2001-11-21 15:47:42 +03:00
/*
2004-03-30 23:08:57 +04:00
* Copyright ( C ) 2001 - 2004 Sistina Software , Inc . All rights reserved .
2007-08-21 20:26:07 +04:00
* Copyright ( C ) 2004 - 2007 Red Hat , Inc . All rights reserved .
2001-11-21 15:47:42 +03:00
*
2004-03-30 23:08:57 +04:00
* This file is part of the device - mapper userspace tools .
*
* This copyrighted material is made available to anyone wishing to use ,
* modify , copy , or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License v .2 .1 .
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program ; if not , write to the Free Software Foundation ,
* Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
2001-11-21 15:47:42 +03:00
*/
2008-11-03 21:59:59 +03:00
# include "dmlib.h"
2003-01-22 00:27:36 +03:00
# include "libdm-targets.h"
# include "libdm-common.h"
2003-11-11 00:06:16 +03:00
# ifdef DM_COMPAT
# include "libdm-compat.h"
# endif
2001-11-21 15:47:42 +03:00
# include <fcntl.h>
2003-07-02 01:20:58 +04:00
# include <dirent.h>
2003-11-11 00:06:16 +03:00
# include <sys/ioctl.h>
2009-02-12 23:42:07 +03:00
# include <sys/utsname.h>
2003-07-02 01:20:58 +04:00
# include <limits.h>
2003-11-12 20:30:32 +03:00
# ifdef linux
2004-07-01 19:14:29 +04:00
# include "kdev_t.h"
2003-11-12 20:30:32 +03:00
# include <linux / limits.h>
# else
# define MAJOR(x) major((x))
# define MINOR(x) minor((x))
# define MKDEV(x,y) makedev((x),(y))
# endif
2001-11-21 15:47:42 +03:00
2008-11-01 05:19:19 +03:00
# include "dm-ioctl.h"
2005-01-27 19:16:54 +03:00
2003-01-22 00:27:36 +03:00
/*
* Ensure build compatibility .
* The hard - coded versions here are the highest present
* in the _cmd_data arrays .
*/
# if !((DM_VERSION_MAJOR == 1 && DM_VERSION_MINOR >= 0) || \
2003-04-30 02:52:11 +04:00
( DM_VERSION_MAJOR = = 4 & & DM_VERSION_MINOR > = 0 ) )
2003-01-22 00:27:36 +03:00
# error The version of dm-ioctl.h included is incompatible.
# endif
2005-01-06 21:22:44 +03:00
/* FIXME This should be exported in device-mapper.h */
# define DM_NAME "device-mapper"
# define PROC_MISC " / proc / misc"
# define PROC_DEVICES " / proc / devices"
# define MISC_NAME "misc"
2005-10-16 18:33:22 +04:00
# define NUMBER_OF_MAJORS 4096
2003-01-22 00:27:36 +03:00
/* dm major version no for running kernel */
2006-04-03 19:56:02 +04:00
static unsigned _dm_version = DM_VERSION_MAJOR ;
static unsigned _dm_version_minor = 0 ;
static unsigned _dm_version_patchlevel = 0 ;
2003-01-22 00:27:36 +03:00
static int _log_suppress = 0 ;
2001-11-21 15:47:42 +03:00
2009-02-12 23:42:07 +03:00
/*
* If the kernel dm driver only supports one major number
* we store it in _dm_device_major . Otherwise we indicate
* which major numbers have been claimed by device - mapper
* in _dm_bitset .
*/
static unsigned _dm_multiple_major_support = 1 ;
2005-10-17 02:57:20 +04:00
static dm_bitset_t _dm_bitset = NULL ;
2009-02-12 23:42:07 +03:00
static uint32_t _dm_device_major = 0 ;
2003-07-02 01:20:58 +04:00
static int _control_fd = - 1 ;
static int _version_checked = 0 ;
static int _version_ok = 1 ;
2005-09-20 22:04:28 +04:00
static unsigned _ioctl_buffer_double_factor = 0 ;
2003-07-02 01:20:58 +04:00
2009-02-12 23:42:07 +03:00
2002-06-19 17:07:05 +04:00
/*
2003-01-22 00:27:36 +03:00
* Support both old and new major numbers to ease the transition .
* Clumsy , but only temporary .
2002-06-19 17:07:05 +04:00
*/
2003-04-30 02:52:11 +04:00
# if DM_VERSION_MAJOR == 4 && defined(DM_COMPAT)
2003-01-22 00:27:36 +03:00
const int _dm_compat = 1 ;
# else
const int _dm_compat = 0 ;
2002-06-19 17:07:05 +04:00
# endif
2003-01-22 00:27:36 +03:00
/* *INDENT-OFF* */
2003-04-30 02:52:11 +04:00
static struct cmd_data _cmd_data_v4 [ ] = {
{ " create " , DM_DEV_CREATE , { 4 , 0 , 0 } } ,
2003-07-02 01:20:58 +04:00
{ " reload " , DM_TABLE_LOAD , { 4 , 0 , 0 } } ,
2003-04-30 02:52:11 +04:00
{ " remove " , DM_DEV_REMOVE , { 4 , 0 , 0 } } ,
{ " remove_all " , DM_REMOVE_ALL , { 4 , 0 , 0 } } ,
{ " suspend " , DM_DEV_SUSPEND , { 4 , 0 , 0 } } ,
{ " resume " , DM_DEV_SUSPEND , { 4 , 0 , 0 } } ,
{ " info " , DM_DEV_STATUS , { 4 , 0 , 0 } } ,
2003-07-02 01:20:58 +04:00
{ " deps " , DM_TABLE_DEPS , { 4 , 0 , 0 } } ,
2003-04-30 02:52:11 +04:00
{ " rename " , DM_DEV_RENAME , { 4 , 0 , 0 } } ,
{ " version " , DM_VERSION , { 4 , 0 , 0 } } ,
2003-07-02 01:20:58 +04:00
{ " status " , DM_TABLE_STATUS , { 4 , 0 , 0 } } ,
{ " table " , DM_TABLE_STATUS , { 4 , 0 , 0 } } ,
{ " waitevent " , DM_DEV_WAIT , { 4 , 0 , 0 } } ,
{ " names " , DM_LIST_DEVICES , { 4 , 0 , 0 } } ,
{ " clear " , DM_TABLE_CLEAR , { 4 , 0 , 0 } } ,
2003-11-13 16:14:28 +03:00
{ " mknodes " , DM_DEV_STATUS , { 4 , 0 , 0 } } ,
2004-03-31 22:54:17 +04:00
# ifdef DM_LIST_VERSIONS
2004-01-23 17:37:47 +03:00
{ " versions " , DM_LIST_VERSIONS , { 4 , 1 , 0 } } ,
2004-03-31 22:54:17 +04:00
# endif
2004-06-09 00:34:40 +04:00
# ifdef DM_TARGET_MSG
{ " message " , DM_TARGET_MSG , { 4 , 2 , 0 } } ,
# endif
2006-02-21 02:55:58 +03:00
# ifdef DM_DEV_SET_GEOMETRY
{ " setgeometry " , DM_DEV_SET_GEOMETRY , { 4 , 6 , 0 } } ,
# endif
2002-03-20 17:34:15 +03:00
} ;
2003-01-22 00:27:36 +03:00
/* *INDENT-ON* */
2003-04-09 01:20:31 +04:00
# define ALIGNMENT_V1 sizeof(int)
# define ALIGNMENT 8
2002-03-20 17:34:15 +03:00
2003-04-24 20:08:18 +04:00
/* FIXME Rejig library to record & use errno instead */
# ifndef DM_EXISTS_FLAG
# define DM_EXISTS_FLAG 0x00000004
# endif
2002-05-03 15:55:58 +04:00
static void * _align ( void * ptr , unsigned int a )
{
2003-01-22 00:27:36 +03:00
register unsigned long agn = - - a ;
return ( void * ) ( ( ( unsigned long ) ptr + agn ) & ~ agn ) ;
}
2005-05-16 19:15:34 +04:00
# ifdef DM_IOCTLS
2005-10-16 18:33:22 +04:00
/*
* Set number to NULL to populate _dm_bitset - otherwise first
* match is returned .
*/
2005-01-06 21:22:44 +03:00
static int _get_proc_number ( const char * file , const char * name ,
uint32_t * number )
{
FILE * fl ;
char nm [ 256 ] ;
int c ;
2005-10-16 18:33:22 +04:00
uint32_t num ;
2005-01-06 21:22:44 +03:00
if ( ! ( fl = fopen ( file , " r " ) ) ) {
2007-07-28 14:23:02 +04:00
log_sys_error ( " fopen " , file ) ;
2005-01-06 21:22:44 +03:00
return 0 ;
}
while ( ! feof ( fl ) ) {
2005-10-16 18:33:22 +04:00
if ( fscanf ( fl , " %d %255s \n " , & num , & nm [ 0 ] ) = = 2 ) {
2005-01-06 21:22:44 +03:00
if ( ! strcmp ( name , nm ) ) {
2005-10-16 18:33:22 +04:00
if ( number ) {
* number = num ;
2007-01-25 17:16:20 +03:00
if ( fclose ( fl ) )
2007-07-28 14:23:02 +04:00
log_sys_error ( " fclose " , file ) ;
2005-10-16 18:33:22 +04:00
return 1 ;
}
2005-10-17 02:57:20 +04:00
dm_bit_set ( _dm_bitset , num ) ;
2005-01-06 21:22:44 +03:00
}
2005-01-07 18:39:53 +03:00
} else do {
2005-01-06 21:22:44 +03:00
c = fgetc ( fl ) ;
} while ( c ! = EOF & & c ! = ' \n ' ) ;
}
2007-01-25 17:16:20 +03:00
if ( fclose ( fl ) )
2007-07-28 14:23:02 +04:00
log_sys_error ( " fclose " , file ) ;
2005-01-06 21:22:44 +03:00
2005-10-16 18:33:22 +04:00
if ( number ) {
log_error ( " %s: No entry for %s found " , file , name ) ;
return 0 ;
}
return 1 ;
2005-01-06 21:22:44 +03:00
}
static int _control_device_number ( uint32_t * major , uint32_t * minor )
{
if ( ! _get_proc_number ( PROC_DEVICES , MISC_NAME , major ) | |
! _get_proc_number ( PROC_MISC , DM_NAME , minor ) ) {
* major = 0 ;
return 0 ;
}
return 1 ;
}
/*
* Returns 1 if exists ; 0 if it doesn ' t ; - 1 if it ' s wrong
*/
static int _control_exists ( const char * control , uint32_t major , uint32_t minor )
{
struct stat buf ;
if ( stat ( control , & buf ) < 0 ) {
if ( errno ! = ENOENT )
2007-07-28 14:23:02 +04:00
log_sys_error ( " stat " , control ) ;
2005-01-06 21:22:44 +03:00
return 0 ;
}
if ( ! S_ISCHR ( buf . st_mode ) ) {
log_verbose ( " %s: Wrong inode type " , control ) ;
if ( ! unlink ( control ) )
return 0 ;
2007-07-28 14:23:02 +04:00
log_sys_error ( " unlink " , control ) ;
2005-01-06 21:22:44 +03:00
return - 1 ;
}
if ( major & & buf . st_rdev ! = MKDEV ( major , minor ) ) {
log_verbose ( " %s: Wrong device number: (%u, %u) instead of "
" (%u, %u) " , control ,
MAJOR ( buf . st_mode ) , MINOR ( buf . st_mode ) ,
major , minor ) ;
if ( ! unlink ( control ) )
return 0 ;
2007-07-28 14:23:02 +04:00
log_sys_error ( " unlink " , control ) ;
2005-01-06 21:22:44 +03:00
return - 1 ;
}
return 1 ;
}
static int _create_control ( const char * control , uint32_t major , uint32_t minor )
{
int ret ;
mode_t old_umask ;
if ( ! major )
return 0 ;
2009-09-25 15:58:00 +04:00
old_umask = umask ( DM_DEV_DIR_UMASK ) ;
2007-07-28 14:48:36 +04:00
ret = dm_create_dir ( dm_dir ( ) ) ;
2005-01-06 21:22:44 +03:00
umask ( old_umask ) ;
if ( ! ret )
return 0 ;
log_verbose ( " Creating device %s (%u, %u) " , control , major , minor ) ;
if ( mknod ( control , S_IFCHR | S_IRUSR | S_IWUSR ,
MKDEV ( major , minor ) ) < 0 ) {
2007-07-28 14:23:02 +04:00
log_sys_error ( " mknod " , control ) ;
2005-01-06 21:22:44 +03:00
return 0 ;
}
# ifdef HAVE_SELINUX
2006-04-03 19:56:02 +04:00
if ( ! dm_set_selinux_context ( control , S_IFCHR ) ) {
stack ;
return 0 ;
}
2005-01-06 21:22:44 +03:00
# endif
return 1 ;
}
2005-05-16 19:15:34 +04:00
# endif
2005-01-06 21:22:44 +03:00
2009-02-12 23:42:07 +03:00
/*
* FIXME Update bitset in long - running process if dm claims new major numbers .
*/
2005-10-16 18:33:22 +04:00
static int _create_dm_bitset ( void )
{
# ifdef DM_IOCTLS
2009-02-12 23:42:07 +03:00
struct utsname uts ;
if ( _dm_bitset | | _dm_device_major )
2005-10-16 18:33:22 +04:00
return 1 ;
2009-02-12 23:42:07 +03:00
if ( uname ( & uts ) )
return 0 ;
/*
* 2.6 kernels are limited to one major number .
* Assume 2.4 kernels are patched not to .
* FIXME Check _dm_version and _dm_version_minor if 2.6 changes this .
*/
if ( ! strncmp ( uts . release , " 2.6. " , 4 ) )
_dm_multiple_major_support = 0 ;
if ( ! _dm_multiple_major_support ) {
if ( ! _get_proc_number ( PROC_DEVICES , DM_NAME , & _dm_device_major ) )
return 0 ;
return 1 ;
}
/* Multiple major numbers supported */
2005-10-17 02:57:20 +04:00
if ( ! ( _dm_bitset = dm_bitset_create ( NULL , NUMBER_OF_MAJORS ) ) )
2005-10-16 18:33:22 +04:00
return 0 ;
if ( ! _get_proc_number ( PROC_DEVICES , DM_NAME , NULL ) ) {
2005-10-17 02:57:20 +04:00
dm_bitset_destroy ( _dm_bitset ) ;
2005-10-16 18:33:22 +04:00
_dm_bitset = NULL ;
return 0 ;
}
return 1 ;
# else
return 0 ;
# endif
}
int dm_is_dm_major ( uint32_t major )
{
if ( ! _create_dm_bitset ( ) )
return 0 ;
2009-02-12 23:42:07 +03:00
if ( _dm_multiple_major_support )
return dm_bit ( _dm_bitset , major ) ? 1 : 0 ;
else
return ( major = = _dm_device_major ) ? 1 : 0 ;
2005-10-16 18:33:22 +04:00
}
2003-11-11 00:06:16 +03:00
static int _open_control ( void )
{
2005-01-27 19:16:54 +03:00
# ifdef DM_IOCTLS
2003-11-11 00:06:16 +03:00
char control [ PATH_MAX ] ;
2005-01-06 21:22:44 +03:00
uint32_t major = 0 , minor ;
2003-11-11 00:06:16 +03:00
if ( _control_fd ! = - 1 )
return 1 ;
snprintf ( control , sizeof ( control ) , " %s/control " , dm_dir ( ) ) ;
2005-01-06 21:22:44 +03:00
if ( ! _control_device_number ( & major , & minor ) )
log_error ( " Is device-mapper driver missing from kernel? " ) ;
if ( ! _control_exists ( control , major , minor ) & &
! _create_control ( control , major , minor ) )
goto error ;
2003-11-11 00:06:16 +03:00
if ( ( _control_fd = open ( control , O_RDWR ) ) < 0 ) {
2007-07-28 14:23:02 +04:00
log_sys_error ( " open " , control ) ;
2005-01-06 21:22:44 +03:00
goto error ;
2003-11-11 00:06:16 +03:00
}
2005-10-16 18:33:22 +04:00
if ( ! _create_dm_bitset ( ) ) {
log_error ( " Failed to set up list of device-mapper major numbers " ) ;
return 0 ;
}
2003-11-11 00:06:16 +03:00
return 1 ;
2005-01-06 21:22:44 +03:00
error :
log_error ( " Failure to communicate with kernel device-mapper driver. " ) ;
return 0 ;
2005-01-27 19:16:54 +03:00
# else
return 1 ;
# endif
2003-11-11 00:06:16 +03:00
}
void dm_task_destroy ( struct dm_task * dmt )
{
struct target * t , * n ;
for ( t = dmt - > head ; t ; t = n ) {
n = t - > next ;
2005-10-17 02:57:20 +04:00
dm_free ( t - > params ) ;
dm_free ( t - > type ) ;
dm_free ( t ) ;
2003-11-11 00:06:16 +03:00
}
if ( dmt - > dev_name )
2005-10-17 02:57:20 +04:00
dm_free ( dmt - > dev_name ) ;
2003-11-11 00:06:16 +03:00
if ( dmt - > newname )
2005-10-17 02:57:20 +04:00
dm_free ( dmt - > newname ) ;
2003-11-11 00:06:16 +03:00
2004-06-09 00:34:40 +04:00
if ( dmt - > message )
2005-10-17 02:57:20 +04:00
dm_free ( dmt - > message ) ;
2004-06-09 00:34:40 +04:00
2003-11-11 00:06:16 +03:00
if ( dmt - > dmi . v4 )
2005-10-17 02:57:20 +04:00
dm_free ( dmt - > dmi . v4 ) ;
2003-11-11 00:06:16 +03:00
if ( dmt - > uuid )
2005-10-17 02:57:20 +04:00
dm_free ( dmt - > uuid ) ;
2003-11-11 00:06:16 +03:00
2005-10-17 02:57:20 +04:00
dm_free ( dmt ) ;
2003-11-11 00:06:16 +03:00
}
/*
* Protocol Version 1 compatibility functions .
*/
# ifdef DM_COMPAT
2003-01-22 00:27:36 +03:00
static int _dm_task_get_driver_version_v1 ( struct dm_task * dmt , char * version ,
size_t size )
{
unsigned int * v ;
if ( ! dmt - > dmi . v1 ) {
version [ 0 ] = ' \0 ' ;
return 0 ;
}
v = dmt - > dmi . v1 - > version ;
snprintf ( version , size , " %u.%u.%u " , v [ 0 ] , v [ 1 ] , v [ 2 ] ) ;
return 1 ;
}
/* Unmarshall the target info returned from a status call */
static int _unmarshal_status_v1 ( struct dm_task * dmt , struct dm_ioctl_v1 * dmi )
{
2003-04-09 01:20:31 +04:00
char * outbuf = ( char * ) dmi + dmi - > data_start ;
2003-01-22 00:27:36 +03:00
char * outptr = outbuf ;
2003-03-28 21:58:59 +03:00
int32_t i ;
2003-02-20 16:30:03 +03:00
struct dm_target_spec_v1 * spec ;
2003-01-22 00:27:36 +03:00
for ( i = 0 ; i < dmi - > target_count ; i + + ) {
2003-02-20 16:30:03 +03:00
spec = ( struct dm_target_spec_v1 * ) outptr ;
2003-01-22 00:27:36 +03:00
if ( ! dm_task_add_target ( dmt , spec - > sector_start ,
( uint64_t ) spec - > length ,
2003-02-20 16:30:03 +03:00
spec - > target_type ,
2004-06-09 00:34:40 +04:00
outptr + sizeof ( * spec ) ) ) {
2003-01-22 00:27:36 +03:00
return 0 ;
2004-06-09 00:34:40 +04:00
}
2003-01-22 00:27:36 +03:00
2003-04-09 01:20:31 +04:00
outptr = outbuf + spec - > next ;
2003-01-22 00:27:36 +03:00
}
return 1 ;
}
2003-11-11 00:06:16 +03:00
static int _dm_format_dev_v1 ( char * buf , int bufsize , uint32_t dev_major ,
uint32_t dev_minor )
2003-07-02 01:20:58 +04:00
{
int r ;
if ( bufsize < 8 )
return 0 ;
r = snprintf ( buf , bufsize , " %03x:%03x " , dev_major , dev_minor ) ;
if ( r < 0 | | r > bufsize - 1 )
return 0 ;
return 1 ;
}
2003-01-22 00:27:36 +03:00
static int _dm_task_get_info_v1 ( struct dm_task * dmt , struct dm_info * info )
{
if ( ! dmt - > dmi . v1 )
return 0 ;
memset ( info , 0 , sizeof ( * info ) ) ;
info - > exists = dmt - > dmi . v1 - > flags & DM_EXISTS_FLAG ? 1 : 0 ;
if ( ! info - > exists )
return 1 ;
info - > suspended = dmt - > dmi . v1 - > flags & DM_SUSPEND_FLAG ? 1 : 0 ;
info - > read_only = dmt - > dmi . v1 - > flags & DM_READONLY_FLAG ? 1 : 0 ;
info - > target_count = dmt - > dmi . v1 - > target_count ;
info - > open_count = dmt - > dmi . v1 - > open_count ;
2003-04-29 15:34:23 +04:00
info - > event_nr = 0 ;
2003-01-22 00:27:36 +03:00
info - > major = MAJOR ( dmt - > dmi . v1 - > dev ) ;
info - > minor = MINOR ( dmt - > dmi . v1 - > dev ) ;
2003-07-02 01:20:58 +04:00
info - > live_table = 1 ;
info - > inactive_table = 0 ;
2003-01-22 00:27:36 +03:00
return 1 ;
}
2007-04-27 18:52:41 +04:00
static const char * _dm_task_get_name_v1 ( const struct dm_task * dmt )
2003-07-02 01:20:58 +04:00
{
return ( dmt - > dmi . v1 - > name ) ;
}
2007-04-27 18:52:41 +04:00
static const char * _dm_task_get_uuid_v1 ( const struct dm_task * dmt )
2003-01-22 00:27:36 +03:00
{
return ( dmt - > dmi . v1 - > uuid ) ;
}
static struct dm_deps * _dm_task_get_deps_v1 ( struct dm_task * dmt )
{
2003-03-28 21:58:59 +03:00
log_error ( " deps version 1 no longer supported by libdevmapper " ) ;
return NULL ;
2003-01-22 00:27:36 +03:00
}
2003-07-02 01:20:58 +04:00
static struct dm_names * _dm_task_get_names_v1 ( struct dm_task * dmt )
{
return ( struct dm_names * ) ( ( ( void * ) dmt - > dmi . v1 ) +
dmt - > dmi . v1 - > data_start ) ;
}
2003-01-22 00:27:36 +03:00
static void * _add_target_v1 ( struct target * t , void * out , void * end )
{
void * out_sp = out ;
struct dm_target_spec_v1 sp ;
size_t sp_size = sizeof ( struct dm_target_spec_v1 ) ;
int len ;
const char no_space [ ] = " Ran out of memory building ioctl parameter " ;
out + = sp_size ;
if ( out > = end ) {
log_error ( no_space ) ;
return NULL ;
}
sp . status = 0 ;
sp . sector_start = t - > start ;
sp . length = t - > length ;
strncpy ( sp . target_type , t - > type , sizeof ( sp . target_type ) ) ;
len = strlen ( t - > params ) ;
if ( ( out + len + 1 ) > = end ) {
log_error ( no_space ) ;
log_error ( " t->params= '%s' " , t - > params ) ;
return NULL ;
}
strcpy ( ( char * ) out , t - > params ) ;
out + = len + 1 ;
/* align next block */
2003-04-09 01:20:31 +04:00
out = _align ( out , ALIGNMENT_V1 ) ;
2003-01-22 00:27:36 +03:00
sp . next = out - out_sp ;
memcpy ( out_sp , & sp , sp_size ) ;
return out ;
}
static struct dm_ioctl_v1 * _flatten_v1 ( struct dm_task * dmt )
{
const size_t min_size = 16 * 1024 ;
const int ( * version ) [ 3 ] ;
struct dm_ioctl_v1 * dmi ;
struct target * t ;
size_t len = sizeof ( struct dm_ioctl_v1 ) ;
void * b , * e ;
int count = 0 ;
for ( t = dmt - > head ; t ; t = t - > next ) {
len + = sizeof ( struct dm_target_spec_v1 ) ;
2003-04-09 01:20:31 +04:00
len + = strlen ( t - > params ) + 1 + ALIGNMENT_V1 ;
2003-01-22 00:27:36 +03:00
count + + ;
}
if ( count & & dmt - > newname ) {
log_error ( " targets and newname are incompatible " ) ;
return NULL ;
}
if ( dmt - > newname )
len + = strlen ( dmt - > newname ) + 1 ;
/*
* Give len a minimum size so that we have space to store
* dependencies or status information .
*/
if ( len < min_size )
len = min_size ;
2005-10-17 02:57:20 +04:00
if ( ! ( dmi = dm_malloc ( len ) ) )
2003-01-22 00:27:36 +03:00
return NULL ;
memset ( dmi , 0 , len ) ;
version = & _cmd_data_v1 [ dmt - > type ] . version ;
dmi - > version [ 0 ] = ( * version ) [ 0 ] ;
dmi - > version [ 1 ] = ( * version ) [ 1 ] ;
dmi - > version [ 2 ] = ( * version ) [ 2 ] ;
dmi - > data_size = len ;
dmi - > data_start = sizeof ( struct dm_ioctl_v1 ) ;
if ( dmt - > dev_name )
strncpy ( dmi - > name , dmt - > dev_name , sizeof ( dmi - > name ) ) ;
if ( dmt - > type = = DM_DEVICE_SUSPEND )
dmi - > flags | = DM_SUSPEND_FLAG ;
if ( dmt - > read_only )
dmi - > flags | = DM_READONLY_FLAG ;
if ( dmt - > minor > = 0 ) {
2003-04-09 01:20:31 +04:00
if ( dmt - > major < = 0 ) {
log_error ( " Missing major number for persistent device " ) ;
return NULL ;
}
2003-01-22 00:27:36 +03:00
dmi - > flags | = DM_PERSISTENT_DEV_FLAG ;
2003-04-09 01:20:31 +04:00
dmi - > dev = MKDEV ( dmt - > major , dmt - > minor ) ;
2003-01-22 00:27:36 +03:00
}
if ( dmt - > uuid )
strncpy ( dmi - > uuid , dmt - > uuid , sizeof ( dmi - > uuid ) ) ;
dmi - > target_count = count ;
b = ( void * ) ( dmi + 1 ) ;
e = ( void * ) ( ( char * ) dmi + len ) ;
for ( t = dmt - > head ; t ; t = t - > next )
if ( ! ( b = _add_target_v1 ( t , b , e ) ) )
goto bad ;
if ( dmt - > newname )
strcpy ( b , dmt - > newname ) ;
return dmi ;
bad :
2005-10-17 02:57:20 +04:00
dm_free ( dmi ) ;
2003-01-22 00:27:36 +03:00
return NULL ;
}
2003-07-02 01:20:58 +04:00
static int _dm_names_v1 ( struct dm_ioctl_v1 * dmi )
{
const char * dev_dir = dm_dir ( ) ;
int r = 1 , len ;
const char * name ;
struct dirent * dirent ;
DIR * d ;
struct dm_names * names , * old_names = NULL ;
void * end = ( void * ) dmi + dmi - > data_size ;
struct stat buf ;
char path [ PATH_MAX ] ;
2007-06-28 21:27:02 +04:00
log_warn ( " WARNING: Device list may be incomplete with interface "
2004-01-23 17:37:47 +03:00
" version 1. " ) ;
2007-06-28 21:27:02 +04:00
log_warn ( " Please upgrade your kernel device-mapper driver. " ) ;
2004-01-23 17:37:47 +03:00
2003-07-02 01:20:58 +04:00
if ( ! ( d = opendir ( dev_dir ) ) ) {
2007-07-28 14:23:02 +04:00
log_sys_error ( " opendir " , dev_dir ) ;
2003-07-02 01:20:58 +04:00
return 0 ;
}
names = ( struct dm_names * ) ( ( void * ) dmi + dmi - > data_start ) ;
names - > dev = 0 ; /* Flags no data */
while ( ( dirent = readdir ( d ) ) ) {
name = dirent - > d_name ;
if ( name [ 0 ] = = ' . ' | | ! strcmp ( name , " control " ) )
continue ;
if ( old_names )
old_names - > next = ( uint32_t ) ( ( void * ) names -
( void * ) old_names ) ;
snprintf ( path , sizeof ( path ) , " %s/%s " , dev_dir , name ) ;
if ( stat ( path , & buf ) ) {
2007-07-28 14:23:02 +04:00
log_sys_error ( " stat " , path ) ;
2003-07-02 01:20:58 +04:00
continue ;
}
if ( ! S_ISBLK ( buf . st_mode ) )
continue ;
names - > dev = ( uint64_t ) buf . st_rdev ;
names - > next = 0 ;
len = strlen ( name ) ;
if ( ( ( void * ) ( names + 1 ) + len + 1 ) > = end ) {
log_error ( " Insufficient buffer space for device list " ) ;
r = 0 ;
break ;
}
strcpy ( names - > name , name ) ;
old_names = names ;
names = _align ( ( void * ) + + names + len + 1 , ALIGNMENT ) ;
}
if ( closedir ( d ) )
2007-07-28 14:23:02 +04:00
log_sys_error ( " closedir " , dev_dir ) ;
2003-07-02 01:20:58 +04:00
return r ;
}
2003-01-22 00:27:36 +03:00
static int _dm_task_run_v1 ( struct dm_task * dmt )
{
struct dm_ioctl_v1 * dmi ;
unsigned int command ;
dmi = _flatten_v1 ( dmt ) ;
if ( ! dmi ) {
2005-11-09 01:50:11 +03:00
log_error ( " Couldn't create ioctl argument. " ) ;
2003-01-22 00:27:36 +03:00
return 0 ;
}
2003-07-02 01:20:58 +04:00
if ( ! _open_control ( ) )
return 0 ;
2003-01-22 00:27:36 +03:00
if ( ( unsigned ) dmt - > type > =
( sizeof ( _cmd_data_v1 ) / sizeof ( * _cmd_data_v1 ) ) ) {
log_error ( " Internal error: unknown device-mapper task %d " ,
dmt - > type ) ;
goto bad ;
}
command = _cmd_data_v1 [ dmt - > type ] . cmd ;
if ( dmt - > type = = DM_DEVICE_TABLE )
dmi - > flags | = DM_STATUS_TABLE_FLAG ;
2005-09-20 22:04:28 +04:00
log_debug ( " dm %s %s %s%s%s [%u] " , _cmd_data_v1 [ dmt - > type ] . name ,
dmi - > name , dmi - > uuid , dmt - > newname ? " " : " " ,
dmt - > newname ? dmt - > newname : " " ,
dmi - > data_size ) ;
2003-07-02 01:20:58 +04:00
if ( dmt - > type = = DM_DEVICE_LIST ) {
if ( ! _dm_names_v1 ( dmi ) )
goto bad ;
2005-01-27 19:16:54 +03:00
}
# ifdef DM_IOCTLS
else if ( ioctl ( _control_fd , command , dmi ) < 0 ) {
2003-01-22 00:27:36 +03:00
if ( _log_suppress )
2005-12-02 02:11:41 +03:00
log_verbose ( " device-mapper: %s ioctl failed: %s " ,
_cmd_data_v1 [ dmt - > type ] . name ,
strerror ( errno ) ) ;
2003-01-22 00:27:36 +03:00
else
2005-12-02 02:11:41 +03:00
log_error ( " device-mapper: %s ioctl failed: %s " ,
_cmd_data_v1 [ dmt - > type ] . name ,
strerror ( errno ) ) ;
2003-01-22 00:27:36 +03:00
goto bad ;
}
2005-01-27 19:16:54 +03:00
# else /* Userspace alternative for testing */
# endif
2003-01-22 00:27:36 +03:00
2004-10-01 23:11:37 +04:00
if ( dmi - > flags & DM_BUFFER_FULL_FLAG )
/* FIXME Increase buffer size and retry operation (if query) */
2007-06-28 21:27:02 +04:00
log_error ( " WARNING: libdevmapper buffer too small for data " ) ;
2004-10-01 23:11:37 +04:00
2003-01-22 00:27:36 +03:00
switch ( dmt - > type ) {
case DM_DEVICE_CREATE :
2005-01-06 01:00:40 +03:00
add_dev_node ( dmt - > dev_name , MAJOR ( dmi - > dev ) , MINOR ( dmi - > dev ) ,
dmt - > uid , dmt - > gid , dmt - > mode ) ;
2003-01-22 00:27:36 +03:00
break ;
case DM_DEVICE_REMOVE :
rm_dev_node ( dmt - > dev_name ) ;
break ;
case DM_DEVICE_RENAME :
rename_dev_node ( dmt - > dev_name , dmt - > newname ) ;
break ;
2003-11-13 16:14:28 +03:00
case DM_DEVICE_MKNODES :
if ( dmi - > flags & DM_EXISTS_FLAG )
add_dev_node ( dmt - > dev_name , MAJOR ( dmi - > dev ) ,
2005-01-06 01:00:40 +03:00
MINOR ( dmi - > dev ) ,
dmt - > uid , dmt - > gid , dmt - > mode ) ;
2003-11-13 16:14:28 +03:00
else
rm_dev_node ( dmt - > dev_name ) ;
break ;
2003-01-22 00:27:36 +03:00
case DM_DEVICE_STATUS :
case DM_DEVICE_TABLE :
if ( ! _unmarshal_status_v1 ( dmt , dmi ) )
goto bad ;
break ;
2003-07-06 03:20:43 +04:00
case DM_DEVICE_SUSPEND :
case DM_DEVICE_RESUME :
dmt - > type = DM_DEVICE_INFO ;
if ( ! dm_task_run ( dmt ) )
goto bad ;
2005-10-17 02:57:20 +04:00
dm_free ( dmi ) ; /* We'll use what info returned */
2003-07-06 03:20:43 +04:00
return 1 ;
2003-01-22 00:27:36 +03:00
}
2002-05-03 15:55:58 +04:00
2003-01-22 00:27:36 +03:00
dmt - > dmi . v1 = dmi ;
return 1 ;
bad :
2005-10-17 02:57:20 +04:00
dm_free ( dmi ) ;
2003-01-22 00:27:36 +03:00
return 0 ;
2002-05-03 15:55:58 +04:00
}
2003-11-11 00:06:16 +03:00
# endif
2002-03-12 01:44:36 +03:00
2003-11-11 00:06:16 +03:00
/*
* Protocol Version 4 functions .
*/
2001-11-21 15:47:42 +03:00
2002-03-07 23:56:10 +03:00
int dm_task_get_driver_version ( struct dm_task * dmt , char * version , size_t size )
2002-01-15 18:21:57 +03:00
{
2006-04-03 19:56:02 +04:00
unsigned * v ;
2002-06-17 19:50:17 +04:00
2003-11-11 00:06:16 +03:00
# ifdef DM_COMPAT
2003-01-22 00:27:36 +03:00
if ( _dm_version = = 1 )
return _dm_task_get_driver_version_v1 ( dmt , version , size ) ;
2003-11-11 00:06:16 +03:00
# endif
2003-01-22 00:27:36 +03:00
2003-04-30 02:52:11 +04:00
if ( ! dmt - > dmi . v4 ) {
2003-01-22 00:27:36 +03:00
version [ 0 ] = ' \0 ' ;
2002-01-15 18:21:57 +03:00
return 0 ;
2003-01-22 00:27:36 +03:00
}
2002-01-15 18:21:57 +03:00
2003-04-30 02:52:11 +04:00
v = dmt - > dmi . v4 - > version ;
2002-06-17 19:50:17 +04:00
snprintf ( version , size , " %u.%u.%u " , v [ 0 ] , v [ 1 ] , v [ 2 ] ) ;
2006-04-03 19:56:02 +04:00
_dm_version_minor = v [ 1 ] ;
_dm_version_patchlevel = v [ 2 ] ;
2002-01-15 18:21:57 +03:00
return 1 ;
}
2003-01-22 00:27:36 +03:00
static int _check_version ( char * version , size_t size , int log_suppress )
{
struct dm_task * task ;
int r ;
if ( ! ( task = dm_task_create ( DM_DEVICE_VERSION ) ) ) {
log_error ( " Failed to get device-mapper version " ) ;
version [ 0 ] = ' \0 ' ;
return 0 ;
}
if ( log_suppress )
_log_suppress = 1 ;
r = dm_task_run ( task ) ;
dm_task_get_driver_version ( task , version , size ) ;
dm_task_destroy ( task ) ;
_log_suppress = 0 ;
return r ;
}
/*
* Find out device - mapper ' s major version number the first time
* this is called and whether or not we support it .
*/
int dm_check_version ( void )
{
char libversion [ 64 ] , dmversion [ 64 ] ;
const char * compat = " " ;
2003-07-02 01:20:58 +04:00
if ( _version_checked )
return _version_ok ;
2003-01-22 00:27:36 +03:00
2003-07-02 01:20:58 +04:00
_version_checked = 1 ;
2003-01-22 00:27:36 +03:00
if ( _check_version ( dmversion , sizeof ( dmversion ) , _dm_compat ) )
return 1 ;
if ( ! _dm_compat )
goto bad ;
2006-04-03 19:56:02 +04:00
log_verbose ( " device-mapper ioctl protocol version %u failed. "
2003-01-22 00:27:36 +03:00
" Trying protocol version 1. " , _dm_version ) ;
_dm_version = 1 ;
if ( _check_version ( dmversion , sizeof ( dmversion ) , 0 ) ) {
log_verbose ( " Using device-mapper ioctl protocol version 1 " ) ;
return 1 ;
}
compat = " (compat) " ;
dm_get_library_version ( libversion , sizeof ( libversion ) ) ;
log_error ( " Incompatible libdevmapper %s%s and kernel driver %s " ,
libversion , compat , dmversion ) ;
bad :
2003-07-02 01:20:58 +04:00
_version_ok = 0 ;
2003-01-22 00:27:36 +03:00
return 0 ;
}
2009-07-31 19:53:11 +04:00
int dm_cookie_supported ( void )
{
return ( dm_check_version ( ) & &
_dm_version > = 4 & &
_dm_version_minor > = 15 ) ;
}
2002-05-10 19:25:38 +04:00
void * dm_get_next_target ( struct dm_task * dmt , void * next ,
uint64_t * start , uint64_t * length ,
char * * target_type , char * * params )
2002-05-03 15:55:58 +04:00
{
2002-05-10 19:25:38 +04:00
struct target * t = ( struct target * ) next ;
2002-05-03 15:55:58 +04:00
2002-05-10 19:25:38 +04:00
if ( ! t )
t = dmt - > head ;
2002-05-03 15:55:58 +04:00
2002-05-10 19:25:38 +04:00
if ( ! t )
return NULL ;
2002-05-03 15:55:58 +04:00
* start = t - > start ;
* length = t - > length ;
* target_type = t - > type ;
* params = t - > params ;
2002-05-10 19:25:38 +04:00
2002-05-03 15:55:58 +04:00
return t - > next ;
}
/* Unmarshall the target info returned from a status call */
2002-05-10 19:25:38 +04:00
static int _unmarshal_status ( struct dm_task * dmt , struct dm_ioctl * dmi )
2002-05-03 15:55:58 +04:00
{
2003-04-28 15:55:58 +04:00
char * outbuf = ( char * ) dmi + dmi - > data_start ;
2002-05-03 15:55:58 +04:00
char * outptr = outbuf ;
2003-01-22 00:27:36 +03:00
uint32_t i ;
2003-02-20 16:30:03 +03:00
struct dm_target_spec * spec ;
2002-05-03 15:55:58 +04:00
2002-05-10 19:25:38 +04:00
for ( i = 0 ; i < dmi - > target_count ; i + + ) {
2003-02-20 16:30:03 +03:00
spec = ( struct dm_target_spec * ) outptr ;
2003-01-22 00:27:36 +03:00
if ( ! dm_task_add_target ( dmt , spec - > sector_start ,
spec - > length ,
2003-02-20 16:30:03 +03:00
spec - > target_type ,
2004-06-09 00:34:40 +04:00
outptr + sizeof ( * spec ) ) ) {
2002-05-10 19:25:38 +04:00
return 0 ;
2004-06-09 00:34:40 +04:00
}
2002-05-10 19:25:38 +04:00
2003-04-09 01:20:31 +04:00
outptr = outbuf + spec - > next ;
2002-05-03 15:55:58 +04:00
}
2002-05-10 19:25:38 +04:00
2002-05-03 15:55:58 +04:00
return 1 ;
}
2003-11-11 00:06:16 +03:00
int dm_format_dev ( char * buf , int bufsize , uint32_t dev_major ,
uint32_t dev_minor )
2003-07-02 01:20:58 +04:00
{
int r ;
2003-11-11 00:06:16 +03:00
# ifdef DM_COMPAT
2003-07-02 01:20:58 +04:00
if ( _dm_version = = 1 )
return _dm_format_dev_v1 ( buf , bufsize , dev_major , dev_minor ) ;
2003-11-11 00:06:16 +03:00
# endif
2003-07-02 01:20:58 +04:00
if ( bufsize < 8 )
return 0 ;
2006-01-31 17:50:38 +03:00
r = snprintf ( buf , ( size_t ) bufsize , " %u:%u " , dev_major , dev_minor ) ;
2003-07-02 01:20:58 +04:00
if ( r < 0 | | r > bufsize - 1 )
return 0 ;
return 1 ;
}
2001-11-21 15:47:42 +03:00
int dm_task_get_info ( struct dm_task * dmt , struct dm_info * info )
{
2003-11-11 00:06:16 +03:00
# ifdef DM_COMPAT
2003-01-22 00:27:36 +03:00
if ( _dm_version = = 1 )
return _dm_task_get_info_v1 ( dmt , info ) ;
2003-11-11 00:06:16 +03:00
# endif
2003-01-22 00:27:36 +03:00
2003-04-30 02:52:11 +04:00
if ( ! dmt - > dmi . v4 )
2001-11-21 15:47:42 +03:00
return 0 ;
2002-01-15 02:07:32 +03:00
memset ( info , 0 , sizeof ( * info ) ) ;
2003-04-30 02:52:11 +04:00
info - > exists = dmt - > dmi . v4 - > flags & DM_EXISTS_FLAG ? 1 : 0 ;
2002-01-15 02:07:32 +03:00
if ( ! info - > exists )
return 1 ;
2003-04-30 02:52:11 +04:00
info - > suspended = dmt - > dmi . v4 - > flags & DM_SUSPEND_FLAG ? 1 : 0 ;
info - > read_only = dmt - > dmi . v4 - > flags & DM_READONLY_FLAG ? 1 : 0 ;
2003-07-02 01:20:58 +04:00
info - > live_table = dmt - > dmi . v4 - > flags & DM_ACTIVE_PRESENT_FLAG ? 1 : 0 ;
info - > inactive_table = dmt - > dmi . v4 - > flags & DM_INACTIVE_PRESENT_FLAG ?
1 : 0 ;
2003-04-30 02:52:11 +04:00
info - > target_count = dmt - > dmi . v4 - > target_count ;
info - > open_count = dmt - > dmi . v4 - > open_count ;
info - > event_nr = dmt - > dmi . v4 - > event_nr ;
info - > major = MAJOR ( dmt - > dmi . v4 - > dev ) ;
info - > minor = MINOR ( dmt - > dmi . v4 - > dev ) ;
2002-01-15 02:07:32 +03:00
2001-11-21 15:47:42 +03:00
return 1 ;
}
2007-11-30 17:59:57 +03:00
uint32_t dm_task_get_read_ahead ( const struct dm_task * dmt , uint32_t * read_ahead )
2007-11-27 23:57:05 +03:00
{
2007-12-05 19:24:41 +03:00
const char * dev_name ;
* read_ahead = 0 ;
# ifdef DM_COMPAT
/* Not supporting this */
if ( _dm_version = = 1 )
return 1 ;
# endif
if ( ! dmt - > dmi . v4 | | ! ( dmt - > dmi . v4 - > flags & DM_EXISTS_FLAG ) )
return 0 ;
if ( * dmt - > dmi . v4 - > name )
dev_name = dmt - > dmi . v4 - > name ;
else if ( dmt - > dev_name )
dev_name = dmt - > dev_name ;
else {
log_error ( " Get read ahead request failed: device name unrecorded. " ) ;
return 0 ;
}
return get_dev_node_read_ahead ( dev_name , read_ahead ) ;
2007-11-27 23:57:05 +03:00
}
2007-04-27 18:52:41 +04:00
const char * dm_task_get_name ( const struct dm_task * dmt )
2003-07-02 01:20:58 +04:00
{
2003-11-11 00:06:16 +03:00
# ifdef DM_COMPAT
2003-07-02 01:20:58 +04:00
if ( _dm_version = = 1 )
return _dm_task_get_name_v1 ( dmt ) ;
2003-11-11 00:06:16 +03:00
# endif
2003-07-02 01:20:58 +04:00
return ( dmt - > dmi . v4 - > name ) ;
}
2007-04-27 18:52:41 +04:00
const char * dm_task_get_uuid ( const struct dm_task * dmt )
2002-03-13 19:19:17 +03:00
{
2003-11-11 00:06:16 +03:00
# ifdef DM_COMPAT
2003-01-22 00:27:36 +03:00
if ( _dm_version = = 1 )
return _dm_task_get_uuid_v1 ( dmt ) ;
2003-11-11 00:06:16 +03:00
# endif
2003-01-22 00:27:36 +03:00
2003-04-30 02:52:11 +04:00
return ( dmt - > dmi . v4 - > uuid ) ;
2002-03-13 19:19:17 +03:00
}
2002-03-06 17:38:25 +03:00
struct dm_deps * dm_task_get_deps ( struct dm_task * dmt )
{
2003-11-11 00:06:16 +03:00
# ifdef DM_COMPAT
2003-01-22 00:27:36 +03:00
if ( _dm_version = = 1 )
return _dm_task_get_deps_v1 ( dmt ) ;
2003-11-11 00:06:16 +03:00
# endif
2003-01-22 00:27:36 +03:00
2003-04-30 02:52:11 +04:00
return ( struct dm_deps * ) ( ( ( void * ) dmt - > dmi . v4 ) +
dmt - > dmi . v4 - > data_start ) ;
2002-03-06 17:38:25 +03:00
}
2003-07-02 01:20:58 +04:00
struct dm_names * dm_task_get_names ( struct dm_task * dmt )
{
2003-11-11 00:06:16 +03:00
# ifdef DM_COMPAT
2003-07-02 01:20:58 +04:00
if ( _dm_version = = 1 )
return _dm_task_get_names_v1 ( dmt ) ;
2003-11-11 00:06:16 +03:00
# endif
2003-07-02 01:20:58 +04:00
return ( struct dm_names * ) ( ( ( void * ) dmt - > dmi . v4 ) +
dmt - > dmi . v4 - > data_start ) ;
}
2004-01-23 17:37:47 +03:00
struct dm_versions * dm_task_get_versions ( struct dm_task * dmt )
{
return ( struct dm_versions * ) ( ( ( void * ) dmt - > dmi . v4 ) +
dmt - > dmi . v4 - > data_start ) ;
}
2002-01-03 13:39:21 +03:00
int dm_task_set_ro ( struct dm_task * dmt )
{
dmt - > read_only = 1 ;
return 1 ;
}
2007-11-27 23:57:05 +03:00
int dm_task_set_read_ahead ( struct dm_task * dmt , uint32_t read_ahead ,
uint32_t read_ahead_flags )
{
dmt - > read_ahead = read_ahead ;
dmt - > read_ahead_flags = read_ahead_flags ;
return 1 ;
}
2005-11-22 21:43:12 +03:00
int dm_task_suppress_identical_reload ( struct dm_task * dmt )
{
dmt - > suppress_identical_reload = 1 ;
return 1 ;
}
2002-01-11 02:29:16 +03:00
int dm_task_set_newname ( struct dm_task * dmt , const char * newname )
{
2009-01-07 15:17:40 +03:00
if ( strchr ( newname , ' / ' ) ) {
log_error ( " Name \" %s \" invalid. It contains \" / \" . " , newname ) ;
return 0 ;
}
if ( strlen ( newname ) > = DM_NAME_LEN ) {
log_error ( " Name \" %s \" too long " , newname ) ;
return 0 ;
}
2005-10-17 02:57:20 +04:00
if ( ! ( dmt - > newname = dm_strdup ( newname ) ) ) {
2002-01-18 22:37:26 +03:00
log_error ( " dm_task_set_newname: strdup(%s) failed " , newname ) ;
2002-01-11 02:29:16 +03:00
return 0 ;
}
return 1 ;
}
2004-06-09 00:34:40 +04:00
int dm_task_set_message ( struct dm_task * dmt , const char * message )
{
2005-10-17 02:57:20 +04:00
if ( ! ( dmt - > message = dm_strdup ( message ) ) ) {
2004-06-09 00:34:40 +04:00
log_error ( " dm_task_set_message: strdup(%s) failed " , message ) ;
return 0 ;
}
return 1 ;
}
int dm_task_set_sector ( struct dm_task * dmt , uint64_t sector )
{
dmt - > sector = sector ;
return 1 ;
}
2006-02-21 02:55:58 +03:00
int dm_task_set_geometry ( struct dm_task * dmt , const char * cylinders , const char * heads , const char * sectors , const char * start )
{
size_t len = strlen ( cylinders ) + 1 + strlen ( heads ) + 1 + strlen ( sectors ) + 1 + strlen ( start ) + 1 ;
if ( ! ( dmt - > geometry = dm_malloc ( len ) ) ) {
log_error ( " dm_task_set_geometry: dm_malloc failed " ) ;
return 0 ;
}
if ( sprintf ( dmt - > geometry , " %s %s %s %s " , cylinders , heads , sectors , start ) < 0 ) {
log_error ( " dm_task_set_geometry: sprintf failed " ) ;
return 0 ;
}
2006-04-03 19:56:02 +04:00
return 1 ;
2006-02-21 02:55:58 +03:00
}
2006-10-12 19:42:25 +04:00
int dm_task_no_flush ( struct dm_task * dmt )
{
2006-10-12 21:29:05 +04:00
dmt - > no_flush = 1 ;
2006-10-12 19:42:25 +04:00
return 1 ;
}
2005-01-13 01:10:14 +03:00
int dm_task_no_open_count ( struct dm_task * dmt )
{
dmt - > no_open_count = 1 ;
return 1 ;
}
2005-10-05 00:12:32 +04:00
int dm_task_skip_lockfs ( struct dm_task * dmt )
{
dmt - > skip_lockfs = 1 ;
return 1 ;
}
2003-04-29 15:34:23 +04:00
int dm_task_set_event_nr ( struct dm_task * dmt , uint32_t event_nr )
{
dmt - > event_nr = event_nr ;
return 1 ;
}
2002-05-10 19:25:38 +04:00
struct target * create_target ( uint64_t start , uint64_t len , const char * type ,
const char * params )
2001-11-21 15:47:42 +03:00
{
2005-10-17 02:57:20 +04:00
struct target * t = dm_malloc ( sizeof ( * t ) ) ;
2001-11-21 15:47:42 +03:00
2001-12-05 19:41:52 +03:00
if ( ! t ) {
2006-01-31 17:50:38 +03:00
log_error ( " create_target: malloc(% " PRIsize_t " ) failed " ,
sizeof ( * t ) ) ;
2001-11-21 15:47:42 +03:00
return NULL ;
2001-12-05 19:41:52 +03:00
}
2001-11-21 15:47:42 +03:00
memset ( t , 0 , sizeof ( * t ) ) ;
2005-10-17 02:57:20 +04:00
if ( ! ( t - > params = dm_strdup ( params ) ) ) {
2002-01-18 22:37:26 +03:00
log_error ( " create_target: strdup(params) failed " ) ;
2001-11-21 15:47:42 +03:00
goto bad ;
}
2005-10-17 02:57:20 +04:00
if ( ! ( t - > type = dm_strdup ( type ) ) ) {
2002-01-18 22:37:26 +03:00
log_error ( " create_target: strdup(type) failed " ) ;
2001-11-21 15:47:42 +03:00
goto bad ;
}
t - > start = start ;
t - > length = len ;
return t ;
2002-03-07 23:56:10 +03:00
bad :
2005-10-17 02:57:20 +04:00
dm_free ( t - > params ) ;
dm_free ( t - > type ) ;
dm_free ( t ) ;
2001-11-21 15:47:42 +03:00
return NULL ;
}
static void * _add_target ( struct target * t , void * out , void * end )
{
void * out_sp = out ;
struct dm_target_spec sp ;
2003-01-22 00:27:36 +03:00
size_t sp_size = sizeof ( struct dm_target_spec ) ;
2001-11-21 15:47:42 +03:00
int len ;
const char no_space [ ] = " Ran out of memory building ioctl parameter " ;
2003-01-22 00:27:36 +03:00
out + = sp_size ;
2001-11-21 15:47:42 +03:00
if ( out > = end ) {
2002-01-18 22:37:26 +03:00
log_error ( no_space ) ;
2001-11-21 15:47:42 +03:00
return NULL ;
}
sp . status = 0 ;
sp . sector_start = t - > start ;
sp . length = t - > length ;
strncpy ( sp . target_type , t - > type , sizeof ( sp . target_type ) ) ;
len = strlen ( t - > params ) ;
if ( ( out + len + 1 ) > = end ) {
2002-01-18 22:37:26 +03:00
log_error ( no_space ) ;
2001-11-21 15:47:42 +03:00
2002-01-18 22:37:26 +03:00
log_error ( " t->params= '%s' " , t - > params ) ;
2001-11-21 15:47:42 +03:00
return NULL ;
}
strcpy ( ( char * ) out , t - > params ) ;
out + = len + 1 ;
/* align next block */
out = _align ( out , ALIGNMENT ) ;
sp . next = out - out_sp ;
2003-01-22 00:27:36 +03:00
memcpy ( out_sp , & sp , sp_size ) ;
2001-11-21 15:47:42 +03:00
return out ;
}
2006-04-03 19:56:02 +04:00
static int _lookup_dev_name ( uint64_t dev , char * buf , size_t len )
{
struct dm_names * names ;
unsigned next = 0 ;
struct dm_task * dmt ;
int r = 0 ;
if ( ! ( dmt = dm_task_create ( DM_DEVICE_LIST ) ) )
return 0 ;
if ( ! dm_task_run ( dmt ) )
goto out ;
if ( ! ( names = dm_task_get_names ( dmt ) ) )
goto out ;
if ( ! names - > dev )
goto out ;
do {
names = ( void * ) names + next ;
if ( names - > dev = = dev ) {
strncpy ( buf , names - > name , len ) ;
r = 1 ;
break ;
}
next = names - > next ;
} while ( next ) ;
out :
dm_task_destroy ( dmt ) ;
return r ;
}
2005-09-19 18:29:17 +04:00
static struct dm_ioctl * _flatten ( struct dm_task * dmt , unsigned repeat_count )
2001-11-21 15:47:42 +03:00
{
2002-03-06 17:38:25 +03:00
const size_t min_size = 16 * 1024 ;
2003-01-22 00:27:36 +03:00
const int ( * version ) [ 3 ] ;
2002-03-06 17:38:25 +03:00
2001-11-21 15:47:42 +03:00
struct dm_ioctl * dmi ;
struct target * t ;
2004-06-09 00:34:40 +04:00
struct dm_target_msg * tmsg ;
2001-11-21 15:47:42 +03:00
size_t len = sizeof ( struct dm_ioctl ) ;
void * b , * e ;
int count = 0 ;
for ( t = dmt - > head ; t ; t = t - > next ) {
len + = sizeof ( struct dm_target_spec ) ;
len + = strlen ( t - > params ) + 1 + ALIGNMENT ;
count + + ;
}
2004-06-09 00:34:40 +04:00
if ( count & & ( dmt - > sector | | dmt - > message ) ) {
log_error ( " targets and message are incompatible " ) ;
return NULL ;
}
2002-01-11 02:29:16 +03:00
if ( count & & dmt - > newname ) {
2002-01-18 22:37:26 +03:00
log_error ( " targets and newname are incompatible " ) ;
2002-01-11 02:29:16 +03:00
return NULL ;
}
2006-02-21 02:55:58 +03:00
if ( count & & dmt - > geometry ) {
log_error ( " targets and geometry are incompatible " ) ;
return NULL ;
}
2004-06-09 00:34:40 +04:00
if ( dmt - > newname & & ( dmt - > sector | | dmt - > message ) ) {
log_error ( " message and newname are incompatible " ) ;
return NULL ;
}
2006-02-21 02:55:58 +03:00
if ( dmt - > newname & & dmt - > geometry ) {
log_error ( " geometry and newname are incompatible " ) ;
return NULL ;
}
if ( dmt - > geometry & & ( dmt - > sector | | dmt - > message ) ) {
log_error ( " geometry and message are incompatible " ) ;
return NULL ;
}
2004-06-09 00:34:40 +04:00
if ( dmt - > sector & & ! dmt - > message ) {
log_error ( " message is required with sector " ) ;
return NULL ;
}
2002-01-11 02:29:16 +03:00
if ( dmt - > newname )
len + = strlen ( dmt - > newname ) + 1 ;
2004-06-09 00:34:40 +04:00
if ( dmt - > message )
len + = sizeof ( struct dm_target_msg ) + strlen ( dmt - > message ) + 1 ;
2006-02-21 02:55:58 +03:00
if ( dmt - > geometry )
len + = strlen ( dmt - > geometry ) + 1 ;
2002-03-06 17:38:25 +03:00
/*
* Give len a minimum size so that we have space to store
* dependencies or status information .
*/
if ( len < min_size )
len = min_size ;
2005-09-19 18:29:17 +04:00
/* Increase buffer size if repeating because buffer was too small */
while ( repeat_count - - )
len * = 2 ;
2005-10-17 02:57:20 +04:00
if ( ! ( dmi = dm_malloc ( len ) ) )
2001-11-21 15:47:42 +03:00
return NULL ;
2002-01-08 01:01:50 +03:00
memset ( dmi , 0 , len ) ;
2003-04-30 02:52:11 +04:00
version = & _cmd_data_v4 [ dmt - > type ] . version ;
2003-01-22 00:27:36 +03:00
dmi - > version [ 0 ] = ( * version ) [ 0 ] ;
dmi - > version [ 1 ] = ( * version ) [ 1 ] ;
dmi - > version [ 2 ] = ( * version ) [ 2 ] ;
2001-11-21 15:47:42 +03:00
dmi - > data_size = len ;
2003-04-28 15:55:58 +04:00
dmi - > data_start = sizeof ( struct dm_ioctl ) ;
2002-01-15 18:21:57 +03:00
2002-02-01 20:39:20 +03:00
if ( dmt - > minor > = 0 ) {
2003-04-09 01:20:31 +04:00
if ( dmt - > major < = 0 ) {
2005-11-09 01:50:11 +03:00
log_error ( " Missing major number for persistent device. " ) ;
goto bad ;
2003-04-09 01:20:31 +04:00
}
2009-02-12 23:42:07 +03:00
2009-06-18 00:55:24 +04:00
if ( ! _dm_multiple_major_support & & dmt - > allow_default_major_fallback & &
dmt - > major ! = _dm_device_major ) {
2009-02-12 23:42:07 +03:00
log_verbose ( " Overriding major number of % " PRIu32
" with % " PRIu32 " for persistent device. " ,
dmt - > major , _dm_device_major ) ;
dmt - > major = _dm_device_major ;
}
2002-01-15 18:21:57 +03:00
dmi - > flags | = DM_PERSISTENT_DEV_FLAG ;
2003-04-09 01:20:31 +04:00
dmi - > dev = MKDEV ( dmt - > major , dmt - > minor ) ;
2002-01-15 02:07:32 +03:00
}
2001-11-21 15:47:42 +03:00
2006-04-03 19:56:02 +04:00
/* Does driver support device number referencing? */
if ( _dm_version_minor < 3 & & ! dmt - > dev_name & & ! dmt - > uuid & & dmi - > dev ) {
if ( ! _lookup_dev_name ( dmi - > dev , dmi - > name , sizeof ( dmi - > name ) ) ) {
log_error ( " Unable to find name for device (% " PRIu32
" :% " PRIu32 " ) " , dmt - > major , dmt - > minor ) ;
goto bad ;
}
log_verbose ( " device (% " PRIu32 " :% " PRIu32 " ) is %s "
" for compatibility with old kernel " ,
dmt - > major , dmt - > minor , dmi - > name ) ;
}
2007-12-04 01:48:36 +03:00
/* FIXME Until resume ioctl supplies name, use dev_name for readahead */
if ( dmt - > dev_name & & ( dmt - > type ! = DM_DEVICE_RESUME | | dmt - > minor < 0 | |
dmt - > major < 0 ) )
2006-04-03 19:56:02 +04:00
strncpy ( dmi - > name , dmt - > dev_name , sizeof ( dmi - > name ) ) ;
2002-03-12 01:44:36 +03:00
if ( dmt - > uuid )
strncpy ( dmi - > uuid , dmt - > uuid , sizeof ( dmi - > uuid ) ) ;
2006-04-03 19:56:02 +04:00
if ( dmt - > type = = DM_DEVICE_SUSPEND )
dmi - > flags | = DM_SUSPEND_FLAG ;
2006-10-12 21:29:05 +04:00
if ( dmt - > no_flush )
2006-10-12 19:42:25 +04:00
dmi - > flags | = DM_NOFLUSH_FLAG ;
2006-04-03 19:56:02 +04:00
if ( dmt - > read_only )
dmi - > flags | = DM_READONLY_FLAG ;
if ( dmt - > skip_lockfs )
dmi - > flags | = DM_SKIP_LOCKFS_FLAG ;
2001-11-21 15:47:42 +03:00
dmi - > target_count = count ;
2003-04-29 15:34:23 +04:00
dmi - > event_nr = dmt - > event_nr ;
2001-11-21 15:47:42 +03:00
b = ( void * ) ( dmi + 1 ) ;
e = ( void * ) ( ( char * ) dmi + len ) ;
for ( t = dmt - > head ; t ; t = t - > next )
if ( ! ( b = _add_target ( t , b , e ) ) )
goto bad ;
2002-01-11 02:29:16 +03:00
if ( dmt - > newname )
strcpy ( b , dmt - > newname ) ;
2004-06-09 00:34:40 +04:00
if ( dmt - > message ) {
tmsg = ( struct dm_target_msg * ) b ;
tmsg - > sector = dmt - > sector ;
strcpy ( tmsg - > message , dmt - > message ) ;
}
2006-02-21 02:55:58 +03:00
if ( dmt - > geometry )
strcpy ( b , dmt - > geometry ) ;
2001-11-21 15:47:42 +03:00
return dmi ;
2002-03-07 23:56:10 +03:00
bad :
2005-10-17 02:57:20 +04:00
dm_free ( dmi ) ;
2001-11-21 15:47:42 +03:00
return NULL ;
}
2004-03-30 18:31:58 +04:00
static int _process_mapper_dir ( struct dm_task * dmt )
{
struct dirent * dirent ;
DIR * d ;
const char * dir ;
int r = 1 ;
dir = dm_dir ( ) ;
if ( ! ( d = opendir ( dir ) ) ) {
2007-07-28 14:23:02 +04:00
log_sys_error ( " opendir " , dir ) ;
2004-03-30 18:31:58 +04:00
return 0 ;
}
while ( ( dirent = readdir ( d ) ) ) {
if ( ! strcmp ( dirent - > d_name , " . " ) | |
! strcmp ( dirent - > d_name , " .. " ) | |
! strcmp ( dirent - > d_name , " control " ) )
continue ;
dm_task_set_name ( dmt , dirent - > d_name ) ;
dm_task_run ( dmt ) ;
}
2007-01-25 17:16:20 +03:00
if ( closedir ( d ) )
2007-07-28 14:23:02 +04:00
log_sys_error ( " closedir " , dir ) ;
2004-03-30 18:31:58 +04:00
return r ;
}
static int _process_all_v4 ( struct dm_task * dmt )
{
struct dm_task * task ;
struct dm_names * names ;
unsigned next = 0 ;
int r = 1 ;
if ( ! ( task = dm_task_create ( DM_DEVICE_LIST ) ) )
return 0 ;
if ( ! dm_task_run ( task ) ) {
r = 0 ;
goto out ;
}
if ( ! ( names = dm_task_get_names ( task ) ) ) {
r = 0 ;
goto out ;
}
if ( ! names - > dev )
goto out ;
do {
names = ( void * ) names + next ;
if ( ! dm_task_set_name ( dmt , names - > name ) ) {
r = 0 ;
goto out ;
}
if ( ! dm_task_run ( dmt ) )
r = 0 ;
next = names - > next ;
} while ( next ) ;
out :
dm_task_destroy ( task ) ;
return r ;
}
static int _mknodes_v4 ( struct dm_task * dmt )
{
( void ) _process_mapper_dir ( dmt ) ;
return _process_all_v4 ( dmt ) ;
}
2009-08-06 19:02:01 +04:00
/*
* If an operation that uses a cookie fails , decrement the
* semaphore instead of udev .
*/
static int _udev_complete ( struct dm_task * dmt )
{
if ( dmt - > cookie_set )
return dm_udev_complete ( dmt - > event_nr ) ;
return 1 ;
}
2003-07-02 01:20:58 +04:00
static int _create_and_load_v4 ( struct dm_task * dmt )
2001-11-21 15:47:42 +03:00
{
2003-07-02 01:20:58 +04:00
struct dm_task * task ;
int r ;
2001-11-21 15:47:42 +03:00
2003-07-02 01:20:58 +04:00
/* Use new task struct to create the device */
if ( ! ( task = dm_task_create ( DM_DEVICE_CREATE ) ) ) {
log_error ( " Failed to create device-mapper task struct " ) ;
2009-08-06 19:02:01 +04:00
_udev_complete ( dmt ) ;
2003-07-02 01:20:58 +04:00
return 0 ;
}
2003-01-22 00:27:36 +03:00
2003-07-02 01:20:58 +04:00
/* Copy across relevant fields */
if ( dmt - > dev_name & & ! dm_task_set_name ( task , dmt - > dev_name ) ) {
dm_task_destroy ( task ) ;
2009-08-06 19:02:01 +04:00
_udev_complete ( dmt ) ;
2001-11-21 15:47:42 +03:00
return 0 ;
}
2003-07-02 01:20:58 +04:00
if ( dmt - > uuid & & ! dm_task_set_uuid ( task , dmt - > uuid ) ) {
dm_task_destroy ( task ) ;
2009-08-06 19:02:01 +04:00
_udev_complete ( dmt ) ;
2003-07-02 01:20:58 +04:00
return 0 ;
}
2001-11-21 20:08:37 +03:00
2003-07-02 01:20:58 +04:00
task - > major = dmt - > major ;
task - > minor = dmt - > minor ;
2006-02-03 17:23:22 +03:00
task - > uid = dmt - > uid ;
task - > gid = dmt - > gid ;
task - > mode = dmt - > mode ;
2003-07-02 01:20:58 +04:00
r = dm_task_run ( task ) ;
dm_task_destroy ( task ) ;
2009-08-06 19:02:01 +04:00
if ( ! r ) {
_udev_complete ( dmt ) ;
return 0 ;
}
2003-07-02 01:20:58 +04:00
/* Next load the table */
if ( ! ( task = dm_task_create ( DM_DEVICE_RELOAD ) ) ) {
log_error ( " Failed to create device-mapper task struct " ) ;
2009-08-06 19:02:01 +04:00
_udev_complete ( dmt ) ;
2003-07-02 01:20:58 +04:00
return 0 ;
}
/* Copy across relevant fields */
if ( dmt - > dev_name & & ! dm_task_set_name ( task , dmt - > dev_name ) ) {
dm_task_destroy ( task ) ;
2009-08-06 19:02:01 +04:00
_udev_complete ( dmt ) ;
2003-07-02 01:20:58 +04:00
return 0 ;
2001-11-21 15:47:42 +03:00
}
2003-07-02 01:20:58 +04:00
task - > read_only = dmt - > read_only ;
task - > head = dmt - > head ;
task - > tail = dmt - > tail ;
r = dm_task_run ( task ) ;
task - > head = NULL ;
task - > tail = NULL ;
dm_task_destroy ( task ) ;
2009-08-06 19:02:01 +04:00
if ( ! r ) {
_udev_complete ( dmt ) ;
2006-03-30 19:15:47 +04:00
goto revert ;
2009-08-06 19:02:01 +04:00
}
2003-07-02 01:20:58 +04:00
/* Use the original structure last so the info will be correct */
dmt - > type = DM_DEVICE_RESUME ;
2005-10-17 02:57:20 +04:00
dm_free ( dmt - > uuid ) ;
2004-06-20 17:50:42 +04:00
dmt - > uuid = NULL ;
2003-07-02 01:20:58 +04:00
r = dm_task_run ( dmt ) ;
2006-03-30 19:15:47 +04:00
if ( r )
return r ;
revert :
dmt - > type = DM_DEVICE_REMOVE ;
dm_free ( dmt - > uuid ) ;
dmt - > uuid = NULL ;
2009-08-06 19:02:01 +04:00
dmt - > cookie_set = 0 ;
2006-03-30 19:15:47 +04:00
if ( ! dm_task_run ( dmt ) )
log_error ( " Failed to revert device creation. " ) ;
2003-07-02 01:20:58 +04:00
return r ;
}
2008-09-18 22:34:53 +04:00
uint64_t dm_task_get_existing_table_size ( struct dm_task * dmt )
{
return dmt - > existing_table_size ;
}
2005-11-22 21:43:12 +03:00
static int _reload_with_suppression_v4 ( struct dm_task * dmt )
{
struct dm_task * task ;
struct target * t1 , * t2 ;
int r ;
/* New task to get existing table information */
if ( ! ( task = dm_task_create ( DM_DEVICE_TABLE ) ) ) {
log_error ( " Failed to create device-mapper task struct " ) ;
return 0 ;
}
/* Copy across relevant fields */
if ( dmt - > dev_name & & ! dm_task_set_name ( task , dmt - > dev_name ) ) {
dm_task_destroy ( task ) ;
return 0 ;
}
if ( dmt - > uuid & & ! dm_task_set_uuid ( task , dmt - > uuid ) ) {
dm_task_destroy ( task ) ;
return 0 ;
}
task - > major = dmt - > major ;
task - > minor = dmt - > minor ;
r = dm_task_run ( task ) ;
if ( ! r ) {
dm_task_destroy ( task ) ;
return r ;
}
2008-09-18 22:34:53 +04:00
/* Store existing table size */
t2 = task - > head ;
while ( t2 & & t2 - > next )
t2 = t2 - > next ;
dmt - > existing_table_size = t2 ? t2 - > start + t2 - > length : 0 ;
2006-06-15 02:00:03 +04:00
if ( ( task - > dmi . v4 - > flags & DM_READONLY_FLAG ) ? 1 : 0 ! = dmt - > read_only )
goto no_match ;
2005-11-22 21:43:12 +03:00
t1 = dmt - > head ;
t2 = task - > head ;
while ( t1 & & t2 ) {
2007-01-08 18:18:52 +03:00
while ( t2 - > params [ strlen ( t2 - > params ) - 1 ] = = ' ' )
t2 - > params [ strlen ( t2 - > params ) - 1 ] = ' \0 ' ;
2005-11-22 21:43:12 +03:00
if ( ( t1 - > start ! = t2 - > start ) | |
( t1 - > length ! = t2 - > length ) | |
( strcmp ( t1 - > type , t2 - > type ) ) | |
2006-06-15 02:00:03 +04:00
( strcmp ( t1 - > params , t2 - > params ) ) )
goto no_match ;
2005-11-22 21:43:12 +03:00
t1 = t1 - > next ;
t2 = t2 - > next ;
}
2006-06-15 02:00:03 +04:00
if ( ! t1 & & ! t2 ) {
2005-11-22 21:43:12 +03:00
dmt - > dmi . v4 = task - > dmi . v4 ;
task - > dmi . v4 = NULL ;
dm_task_destroy ( task ) ;
return 1 ;
}
2006-06-15 02:00:03 +04:00
no_match :
2005-11-22 21:43:12 +03:00
dm_task_destroy ( task ) ;
/* Now do the original reload */
dmt - > suppress_identical_reload = 0 ;
r = dm_task_run ( dmt ) ;
return r ;
}
2005-09-20 22:04:28 +04:00
static struct dm_ioctl * _do_dm_ioctl ( struct dm_task * dmt , unsigned command ,
unsigned repeat_count )
2003-07-02 01:20:58 +04:00
{
2005-09-19 18:29:17 +04:00
struct dm_ioctl * dmi ;
2003-07-02 01:20:58 +04:00
2005-09-19 18:29:17 +04:00
dmi = _flatten ( dmt , repeat_count ) ;
2003-07-02 01:20:58 +04:00
if ( ! dmi ) {
2005-11-09 01:50:11 +03:00
log_error ( " Couldn't create ioctl argument. " ) ;
2005-09-19 18:29:17 +04:00
return NULL ;
2003-07-02 01:20:58 +04:00
}
2002-06-19 17:07:05 +04:00
if ( dmt - > type = = DM_DEVICE_TABLE )
dmi - > flags | = DM_STATUS_TABLE_FLAG ;
2003-04-24 20:08:18 +04:00
dmi - > flags | = DM_EXISTS_FLAG ; /* FIXME */
2005-01-13 01:10:14 +03:00
if ( dmt - > no_open_count )
dmi - > flags | = DM_SKIP_BDGET_FLAG ;
2006-02-02 20:23:04 +03:00
log_debug ( " dm %s %s %s%s%s %s%.0d%s%.0d%s "
2007-04-27 18:52:41 +04:00
" %s%c%c%s %.0 " PRIu64 " %s [%u] " ,
2005-09-20 22:04:28 +04:00
_cmd_data_v4 [ dmt - > type ] . name ,
dmi - > name , dmi - > uuid , dmt - > newname ? " " : " " ,
dmt - > newname ? dmt - > newname : " " ,
2005-10-18 17:07:41 +04:00
dmt - > major > 0 ? " ( " : " " ,
2005-10-26 22:32:57 +04:00
dmt - > major > 0 ? dmt - > major : 0 ,
2005-10-18 17:07:41 +04:00
dmt - > major > 0 ? " : " : " " ,
2005-10-26 22:32:57 +04:00
dmt - > minor > 0 ? dmt - > minor : 0 ,
2005-11-09 01:50:11 +03:00
dmt - > major > 0 & & dmt - > minor = = 0 ? " 0 " : " " ,
2005-10-18 17:07:41 +04:00
dmt - > major > 0 ? " ) " : " " ,
2005-01-13 01:10:14 +03:00
dmt - > no_open_count ? ' N ' : ' O ' ,
2006-10-12 21:29:05 +04:00
dmt - > no_flush ? ' N ' : ' F ' ,
2006-08-09 01:22:31 +04:00
dmt - > skip_lockfs ? " S " : " " ,
2005-09-20 22:04:28 +04:00
dmt - > sector , dmt - > message ? dmt - > message : " " ,
dmi - > data_size ) ;
2005-01-27 19:16:54 +03:00
# ifdef DM_IOCTLS
2003-07-02 01:20:58 +04:00
if ( ioctl ( _control_fd , command , dmi ) < 0 ) {
2003-11-13 16:14:28 +03:00
if ( errno = = ENXIO & & ( ( dmt - > type = = DM_DEVICE_INFO ) | |
2005-10-26 22:32:57 +04:00
( dmt - > type = = DM_DEVICE_MKNODES ) | |
( dmt - > type = = DM_DEVICE_STATUS ) ) )
2003-04-24 20:08:18 +04:00
dmi - > flags & = ~ DM_EXISTS_FLAG ; /* FIXME */
2005-01-27 19:16:54 +03:00
else {
if ( _log_suppress )
2005-12-02 02:11:41 +03:00
log_verbose ( " device-mapper: %s ioctl "
" failed: %s " ,
_cmd_data_v4 [ dmt - > type ] . name ,
strerror ( errno ) ) ;
2005-01-27 19:16:54 +03:00
else
2005-12-02 02:11:41 +03:00
log_error ( " device-mapper: %s ioctl "
" failed: %s " ,
_cmd_data_v4 [ dmt - > type ] . name ,
strerror ( errno ) ) ;
2005-10-17 02:57:20 +04:00
dm_free ( dmi ) ;
2005-09-19 18:29:17 +04:00
return NULL ;
2003-04-24 20:08:18 +04:00
}
2001-11-21 15:47:42 +03:00
}
2005-01-27 19:16:54 +03:00
# else /* Userspace alternative for testing */
# endif
2005-09-19 18:29:17 +04:00
return dmi ;
}
2001-11-21 15:47:42 +03:00
2005-12-02 02:11:41 +03:00
void dm_task_update_nodes ( void )
{
update_devs ( ) ;
}
2005-09-19 18:29:17 +04:00
int dm_task_run ( struct dm_task * dmt )
{
struct dm_ioctl * dmi ;
unsigned command ;
# ifdef DM_COMPAT
if ( _dm_version = = 1 )
return _dm_task_run_v1 ( dmt ) ;
# endif
if ( ( unsigned ) dmt - > type > =
( sizeof ( _cmd_data_v4 ) / sizeof ( * _cmd_data_v4 ) ) ) {
log_error ( " Internal error: unknown device-mapper task %d " ,
dmt - > type ) ;
return 0 ;
}
command = _cmd_data_v4 [ dmt - > type ] . cmd ;
/* Old-style creation had a table supplied */
if ( dmt - > type = = DM_DEVICE_CREATE & & dmt - > head )
return _create_and_load_v4 ( dmt ) ;
if ( dmt - > type = = DM_DEVICE_MKNODES & & ! dmt - > dev_name & &
! dmt - > uuid & & dmt - > major < = 0 )
return _mknodes_v4 ( dmt ) ;
2005-11-22 21:43:12 +03:00
if ( ( dmt - > type = = DM_DEVICE_RELOAD ) & & dmt - > suppress_identical_reload )
return _reload_with_suppression_v4 ( dmt ) ;
2009-08-06 19:02:01 +04:00
if ( ! _open_control ( ) ) {
_udev_complete ( dmt ) ;
2005-09-19 18:29:17 +04:00
return 0 ;
2009-08-06 19:02:01 +04:00
}
2005-09-19 18:29:17 +04:00
2009-08-03 22:01:45 +04:00
/* FIXME Detect and warn if cookie set but should not be. */
2005-09-19 18:29:17 +04:00
repeat_ioctl :
2009-08-03 22:01:45 +04:00
if ( ! ( dmi = _do_dm_ioctl ( dmt , command , _ioctl_buffer_double_factor ) ) ) {
2009-08-06 19:02:01 +04:00
_udev_complete ( dmt ) ;
2005-09-19 18:29:17 +04:00
return 0 ;
2009-08-03 22:01:45 +04:00
}
2005-09-19 18:29:17 +04:00
if ( dmi - > flags & DM_BUFFER_FULL_FLAG ) {
switch ( dmt - > type ) {
case DM_DEVICE_LIST_VERSIONS :
case DM_DEVICE_LIST :
case DM_DEVICE_DEPS :
case DM_DEVICE_STATUS :
case DM_DEVICE_TABLE :
case DM_DEVICE_WAITEVENT :
2005-09-20 22:04:28 +04:00
_ioctl_buffer_double_factor + + ;
2005-10-17 02:57:20 +04:00
dm_free ( dmi ) ;
2005-09-19 18:29:17 +04:00
goto repeat_ioctl ;
default :
2007-06-28 21:27:02 +04:00
log_error ( " WARNING: libdevmapper buffer too small for data " ) ;
2005-09-19 18:29:17 +04:00
}
}
2005-08-08 22:40:17 +04:00
2001-11-21 15:47:42 +03:00
switch ( dmt - > type ) {
case DM_DEVICE_CREATE :
2008-05-21 20:14:46 +04:00
if ( dmt - > dev_name & & * dmt - > dev_name )
add_dev_node ( dmt - > dev_name , MAJOR ( dmi - > dev ) ,
MINOR ( dmi - > dev ) , dmt - > uid , dmt - > gid ,
dmt - > mode ) ;
2001-11-21 15:47:42 +03:00
break ;
case DM_DEVICE_REMOVE :
2004-10-01 23:11:37 +04:00
/* FIXME Kernel needs to fill in dmi->name */
if ( dmt - > dev_name )
rm_dev_node ( dmt - > dev_name ) ;
2001-11-21 15:47:42 +03:00
break ;
2002-04-11 16:45:18 +04:00
case DM_DEVICE_RENAME :
2004-10-01 23:11:37 +04:00
/* FIXME Kernel needs to fill in dmi->name */
if ( dmt - > dev_name )
rename_dev_node ( dmt - > dev_name , dmt - > newname ) ;
2002-04-11 16:45:18 +04:00
break ;
2002-05-03 15:55:58 +04:00
2007-11-30 17:59:57 +03:00
case DM_DEVICE_RESUME :
2007-12-04 01:48:36 +03:00
/* FIXME Kernel needs to fill in dmi->name */
set_dev_node_read_ahead ( dmt - > dev_name , dmt - > read_ahead ,
2007-11-30 17:59:57 +03:00
dmt - > read_ahead_flags ) ;
break ;
2003-11-13 16:14:28 +03:00
case DM_DEVICE_MKNODES :
if ( dmi - > flags & DM_EXISTS_FLAG )
2004-10-01 23:11:37 +04:00
add_dev_node ( dmi - > name , MAJOR ( dmi - > dev ) ,
2005-01-06 01:00:40 +03:00
MINOR ( dmi - > dev ) ,
dmt - > uid , dmt - > gid , dmt - > mode ) ;
2004-10-01 23:11:37 +04:00
else if ( dmt - > dev_name )
2003-11-13 16:14:28 +03:00
rm_dev_node ( dmt - > dev_name ) ;
break ;
2002-05-03 15:55:58 +04:00
case DM_DEVICE_STATUS :
case DM_DEVICE_TABLE :
2003-04-28 15:55:58 +04:00
case DM_DEVICE_WAITEVENT :
2002-05-10 19:25:38 +04:00
if ( ! _unmarshal_status ( dmt , dmi ) )
goto bad ;
break ;
2001-11-21 15:47:42 +03:00
}
2006-04-03 19:56:02 +04:00
/* Was structure reused? */
if ( dmt - > dmi . v4 )
dm_free ( dmt - > dmi . v4 ) ;
2003-04-30 02:52:11 +04:00
dmt - > dmi . v4 = dmi ;
2001-11-21 15:47:42 +03:00
return 1 ;
2002-03-07 23:56:10 +03:00
bad :
2005-10-17 02:57:20 +04:00
dm_free ( dmi ) ;
2001-11-21 15:47:42 +03:00
return 0 ;
}
2003-07-02 01:20:58 +04:00
void dm_lib_release ( void )
{
if ( _control_fd ! = - 1 ) {
close ( _control_fd ) ;
_control_fd = - 1 ;
}
update_devs ( ) ;
}
2009-04-10 13:56:58 +04:00
void dm_pools_check_leaks ( void ) ;
2003-07-02 01:20:58 +04:00
void dm_lib_exit ( void )
{
2005-05-16 19:15:34 +04:00
dm_lib_release ( ) ;
2005-10-16 18:33:22 +04:00
if ( _dm_bitset )
2005-10-17 02:57:20 +04:00
dm_bitset_destroy ( _dm_bitset ) ;
2005-10-16 18:33:22 +04:00
_dm_bitset = NULL ;
2009-04-10 13:56:58 +04:00
dm_pools_check_leaks ( ) ;
2005-10-17 02:57:20 +04:00
dm_dump_memory ( ) ;
2003-07-02 01:20:58 +04:00
_version_ok = 1 ;
_version_checked = 0 ;
}