2001-12-05 19:41:52 +03:00
/*
2004-03-30 23:08:57 +04:00
* Copyright ( C ) 2001 - 2004 Sistina Software , Inc . All rights reserved .
2012-01-09 16:26:14 +04:00
* Copyright ( C ) 2004 - 2012 Red Hat , Inc . All rights reserved .
2001-12-05 19:41:52 +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 ,
2016-01-21 13:49:46 +03:00
* Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA
2001-12-05 19:41:52 +03:00
*/
2018-05-14 12:30:20 +03:00
# include "libdm/misc/dmlib.h"
2002-11-14 17:44:42 +03:00
# include "libdm-targets.h"
# include "libdm-common.h"
2018-05-14 12:30:20 +03:00
# include "libdm/misc/kdev_t.h"
# include "libdm/misc/dm-ioctl.h"
2001-12-05 19:41:52 +03:00
# include <stdarg.h>
# include <sys/param.h>
2007-12-03 20:56:36 +03:00
# include <sys/ioctl.h>
2007-11-30 19:42:26 +03:00
# include <fcntl.h>
2009-09-25 22:08:04 +04:00
# include <dirent.h>
2005-01-27 19:16:54 +03:00
2009-07-31 19:53:11 +04:00
# ifdef UDEV_SYNC_SUPPORT
# include <sys / types.h>
# include <sys / ipc.h>
# include <sys / sem.h>
2009-09-11 19:56:06 +04:00
# include <libudev.h>
# endif
2009-07-31 19:53:11 +04:00
2013-11-13 17:56:29 +04:00
# ifdef __linux__
2007-11-30 19:42:26 +03:00
# include <linux / fs.h>
# endif
2004-04-06 22:54:00 +04:00
# ifdef HAVE_SELINUX
# include <selinux / selinux.h>
# endif
2010-12-13 13:43:56 +03:00
# ifdef HAVE_SELINUX_LABEL_H
# include <selinux / label.h>
# endif
2004-04-06 22:54:00 +04:00
2012-02-15 16:23:15 +04:00
# define DM_DEFAULT_NAME_MANGLING_MODE_ENV_VAR_NAME "DM_DEFAULT_NAME_MANGLING_MODE"
2001-12-05 19:41:52 +03:00
# define DEV_DIR " / dev / "
2010-05-27 19:02:56 +04:00
# ifdef UDEV_SYNC_SUPPORT
# ifdef _SEM_SEMUN_UNDEFINED
union semun
{
int val ; /* value for SETVAL */
struct semid_ds * buf ; /* buffer for IPC_STAT & IPC_SET */
unsigned short int * array ; /* array for GETALL & SETALL */
struct seminfo * __buf ; /* buffer for IPC_INFO */
} ;
# endif
# endif
2001-12-05 19:41:52 +03:00
static char _dm_dir [ PATH_MAX ] = DEV_DIR DM_DIR ;
2011-09-22 21:17:07 +04:00
static char _sysfs_dir [ PATH_MAX ] = " /sys/ " ;
2012-01-09 16:26:14 +04:00
static char _path0 [ PATH_MAX ] ; /* path buffer, safe 4kB on stack */
2013-05-16 13:34:26 +04:00
static const char _mountinfo [ ] = " /proc/self/mountinfo " ;
2001-12-05 19:41:52 +03:00
2012-01-10 06:03:31 +04:00
# define DM_MAX_UUID_PREFIX_LEN 15
static char _default_uuid_prefix [ DM_MAX_UUID_PREFIX_LEN + 1 ] = " LVM- " ;
2003-01-22 00:25:11 +03:00
static int _verbose = 0 ;
2011-06-13 07:32:45 +04:00
static int _suspended_dev_counter = 0 ;
2012-02-28 18:24:57 +04:00
static dm_string_mangling_t _name_mangling_mode = DEFAULT_DM_NAME_MANGLING ;
2003-01-22 00:25:11 +03:00
2010-12-13 13:43:56 +03:00
# ifdef HAVE_SELINUX_LABEL_H
static struct selabel_handle * _selabel_handle = NULL ;
# endif
2012-11-29 17:03:48 +04:00
static int _udev_disabled = 0 ;
2012-11-29 17:40:12 +04:00
# ifdef UDEV_SYNC_SUPPORT
2010-08-03 11:56:03 +04:00
static int _semaphore_supported = - 1 ;
2009-09-11 19:56:06 +04:00
static int _udev_running = - 1 ;
2009-07-31 19:53:11 +04:00
static int _sync_with_udev = 1 ;
2010-01-11 18:36:24 +03:00
static int _udev_checking = 1 ;
2009-07-31 19:53:11 +04:00
# endif
2012-02-15 16:23:15 +04:00
void dm_lib_init ( void )
{
const char * env ;
2012-12-14 17:18:46 +04:00
if ( getenv ( " DM_DISABLE_UDEV " ) )
2012-11-29 17:03:48 +04:00
_udev_disabled = 1 ;
2014-04-04 23:24:41 +04:00
_name_mangling_mode = DEFAULT_DM_NAME_MANGLING ;
if ( ( env = getenv ( DM_DEFAULT_NAME_MANGLING_MODE_ENV_VAR_NAME ) ) ) {
2012-02-15 16:23:15 +04:00
if ( ! strcasecmp ( env , " none " ) )
_name_mangling_mode = DM_STRING_MANGLING_NONE ;
else if ( ! strcasecmp ( env , " auto " ) )
_name_mangling_mode = DM_STRING_MANGLING_AUTO ;
else if ( ! strcasecmp ( env , " hex " ) )
_name_mangling_mode = DM_STRING_MANGLING_HEX ;
2014-04-04 23:24:41 +04:00
}
2012-02-15 16:23:15 +04:00
}
2002-01-03 13:39:21 +03:00
/*
2001-12-05 19:41:52 +03:00
* Library users can provide their own logging
* function .
*/
2009-07-10 13:59:37 +04:00
2011-03-30 01:53:46 +04:00
__attribute__ ( ( format ( printf , 5 , 0 ) ) )
2018-03-14 20:08:16 +03:00
static void _default_log_line ( int level , const char * file ,
int line , int dm_errno_or_class ,
const char * f , va_list ap )
2001-12-05 19:41:52 +03:00
{
2013-07-25 16:32:09 +04:00
static int _abort_on_internal_errors = - 1 ;
2018-03-14 20:08:16 +03:00
static int _debug_with_line_numbers = - 1 ;
2016-11-02 16:39:13 +03:00
FILE * out = log_stderr ( level ) ? stderr : stdout ;
2007-06-28 21:27:02 +04:00
2016-11-02 16:39:13 +03:00
level = log_level ( level ) ;
2001-12-05 19:41:52 +03:00
2013-07-25 16:32:09 +04:00
if ( level < = _LOG_WARN | | _verbose ) {
if ( level < _LOG_WARN )
out = stderr ;
2018-03-14 20:08:16 +03:00
if ( _debug_with_line_numbers < 0 )
/* Set when env DM_DEBUG_WITH_LINE_NUMBERS is not "0" */
_debug_with_line_numbers =
strcmp ( getenv ( " DM_DEBUG_WITH_LINE_NUMBERS " ) ? : " 0 " , " 0 " ) ;
if ( _debug_with_line_numbers )
fprintf ( out , " %s:%d " , file , line ) ;
2013-07-25 16:32:09 +04:00
vfprintf ( out , f , ap ) ;
fputc ( ' \n ' , out ) ;
}
if ( _abort_on_internal_errors < 0 )
2013-08-06 17:22:26 +04:00
/* Set when env DM_ABORT_ON_INTERNAL_ERRORS is not "0" */
2013-07-25 16:32:09 +04:00
_abort_on_internal_errors =
2013-08-06 17:22:26 +04:00
strcmp ( getenv ( " DM_ABORT_ON_INTERNAL_ERRORS " ) ? : " 0 " , " 0 " ) ;
2013-07-25 16:32:09 +04:00
if ( _abort_on_internal_errors & &
! strncmp ( f , INTERNAL_ERROR , sizeof ( INTERNAL_ERROR ) - 1 ) )
abort ( ) ;
2001-12-05 19:41:52 +03:00
}
2011-03-30 01:53:46 +04:00
__attribute__ ( ( format ( printf , 5 , 6 ) ) )
2009-07-10 13:59:37 +04:00
static void _default_log_with_errno ( int level ,
2016-11-02 12:55:19 +03:00
const char * file , int line , int dm_errno_or_class ,
2009-07-10 13:59:37 +04:00
const char * f , . . . )
{
va_list ap ;
va_start ( ap , f ) ;
2013-01-08 02:25:19 +04:00
_default_log_line ( level , file , line , dm_errno_or_class , f , ap ) ;
2009-07-10 13:59:37 +04:00
va_end ( ap ) ;
}
2011-03-30 01:53:46 +04:00
__attribute__ ( ( format ( printf , 4 , 5 ) ) )
2009-07-10 13:59:37 +04:00
static void _default_log ( int level , const char * file ,
int line , const char * f , . . . )
{
va_list ap ;
va_start ( ap , f ) ;
_default_log_line ( level , file , line , 0 , f , ap ) ;
va_end ( ap ) ;
}
2006-01-31 17:50:38 +03:00
dm_log_fn dm_log = _default_log ;
2009-07-10 13:59:37 +04:00
dm_log_with_errno_fn dm_log_with_errno = _default_log_with_errno ;
2001-12-05 19:41:52 +03:00
2016-11-03 19:15:07 +03:00
/*
* Wrapper function to reformat new messages to and
* old style logging which had not used errno parameter
*
* As we cannot simply pass ' . . . ' to old function we
* need to process arg list locally and just pass ' % s ' + buffer
*/
__attribute__ ( ( format ( printf , 5 , 6 ) ) )
static void _log_to_default_log ( int level ,
const char * file , int line , int dm_errno_or_class ,
const char * f , . . . )
{
2016-12-10 00:54:08 +03:00
int n ;
2016-11-03 19:15:07 +03:00
va_list ap ;
char buf [ 2 * PATH_MAX + 256 ] ; /* big enough for most messages */
va_start ( ap , f ) ;
2016-12-10 00:54:08 +03:00
n = vsnprintf ( buf , sizeof ( buf ) , f , ap ) ;
2016-11-03 19:15:07 +03:00
va_end ( ap ) ;
2016-12-10 00:54:08 +03:00
if ( n > 0 ) /* Could be truncated */
dm_log ( level , file , line , " %s " , buf ) ;
2016-11-03 19:15:07 +03:00
}
/*
* Wrapper function take ' old ' style message without errno
* and log it via new logging function with errno arg
*
* This minor case may happen if new libdm is used with old
* recompiled tool that would decided to use new logging ,
* but still would like to use old binary plugins .
*/
__attribute__ ( ( format ( printf , 4 , 5 ) ) )
static void _log_to_default_log_with_errno ( int level ,
const char * file , int line , const char * f , . . . )
{
2016-12-10 00:54:08 +03:00
int n ;
2016-11-03 19:15:07 +03:00
va_list ap ;
char buf [ 2 * PATH_MAX + 256 ] ; /* big enough for most messages */
va_start ( ap , f ) ;
2016-12-10 00:54:08 +03:00
n = vsnprintf ( buf , sizeof ( buf ) , f , ap ) ;
2016-11-03 19:15:07 +03:00
va_end ( ap ) ;
2016-12-10 00:54:08 +03:00
if ( n > 0 ) /* Could be truncated */
dm_log_with_errno ( level , file , line , 0 , " %s " , buf ) ;
2016-11-03 19:15:07 +03:00
}
2001-12-05 19:41:52 +03:00
void dm_log_init ( dm_log_fn fn )
{
2016-11-03 19:15:07 +03:00
if ( fn ) {
2006-01-31 17:50:38 +03:00
dm_log = fn ;
2016-11-03 19:15:07 +03:00
dm_log_with_errno = _log_to_default_log ;
} else {
2006-01-31 17:50:38 +03:00
dm_log = _default_log ;
2016-11-03 19:15:07 +03:00
dm_log_with_errno = _default_log_with_errno ;
}
2009-07-10 13:59:37 +04:00
}
int dm_log_is_non_default ( void )
{
2016-11-03 14:07:27 +03:00
return ( dm_log = = _default_log & & dm_log_with_errno = = _default_log_with_errno ) ? 0 : 1 ;
2009-07-10 13:59:37 +04:00
}
void dm_log_with_errno_init ( dm_log_with_errno_fn fn )
{
2016-11-03 19:15:07 +03:00
if ( fn ) {
dm_log = _log_to_default_log_with_errno ;
2009-07-10 13:59:37 +04:00
dm_log_with_errno = fn ;
2016-11-03 19:15:07 +03:00
} else {
dm_log = _default_log ;
2009-07-10 13:59:37 +04:00
dm_log_with_errno = _default_log_with_errno ;
2016-11-03 19:15:07 +03:00
}
2001-12-05 19:41:52 +03:00
}
2003-01-22 00:25:11 +03:00
void dm_log_init_verbose ( int level )
{
_verbose = level ;
}
2014-04-04 23:47:54 +04:00
static int _build_dev_path ( char * buffer , size_t len , const char * dev_name )
2001-12-14 16:30:04 +03:00
{
2014-04-04 23:47:54 +04:00
int r ;
2001-12-14 16:30:04 +03:00
/* If there's a /, assume caller knows what they're doing */
if ( strchr ( dev_name , ' / ' ) )
2014-04-04 23:47:54 +04:00
r = dm_strncpy ( buffer , dev_name , len ) ;
2001-12-14 16:30:04 +03:00
else
2014-04-04 23:47:54 +04:00
r = ( dm_snprintf ( buffer , len , " %s/%s " ,
_dm_dir , dev_name ) < 0 ) ? 0 : 1 ;
if ( ! r )
log_error ( " Failed to build dev path for \" %s \" . " , dev_name ) ;
return r ;
2001-12-14 16:30:04 +03:00
}
2002-01-17 17:13:25 +03:00
int dm_get_library_version ( char * version , size_t size )
{
2014-04-04 23:43:57 +04:00
return dm_strncpy ( version , DM_LIB_VERSION , size ) ;
2002-01-17 17:13:25 +03:00
}
2011-06-13 07:32:45 +04:00
void inc_suspended ( void )
{
_suspended_dev_counter + + ;
2013-01-08 02:30:29 +04:00
log_debug_activation ( " Suspended device counter increased to %d " , _suspended_dev_counter ) ;
2011-06-13 07:32:45 +04:00
}
void dec_suspended ( void )
{
if ( ! _suspended_dev_counter ) {
log_error ( " Attempted to decrement suspended device counter below zero. " ) ;
return ;
}
_suspended_dev_counter - - ;
2013-01-08 02:30:29 +04:00
log_debug_activation ( " Suspended device counter reduced to %d " , _suspended_dev_counter ) ;
2011-06-13 07:32:45 +04:00
}
int dm_get_suspended_counter ( void )
{
return _suspended_dev_counter ;
}
2012-02-15 15:27:01 +04:00
int dm_set_name_mangling_mode ( dm_string_mangling_t name_mangling_mode )
{
_name_mangling_mode = name_mangling_mode ;
return 1 ;
}
dm_string_mangling_t dm_get_name_mangling_mode ( void )
{
return _name_mangling_mode ;
}
2001-12-05 19:41:52 +03:00
struct dm_task * dm_task_create ( int type )
{
2010-10-01 01:06:50 +04:00
struct dm_task * dmt = dm_zalloc ( sizeof ( * dmt ) ) ;
2001-12-05 19:41:52 +03:00
2002-03-19 02:39:42 +03:00
if ( ! dmt ) {
2006-01-31 17:50:38 +03:00
log_error ( " dm_task_create: malloc(% " PRIsize_t " ) failed " ,
sizeof ( * dmt ) ) ;
2002-03-19 02:39:42 +03:00
return NULL ;
}
2001-12-05 19:41:52 +03:00
2006-05-10 20:23:41 +04:00
if ( ! dm_check_version ( ) ) {
dm_free ( dmt ) ;
2011-03-18 16:21:02 +03:00
return_NULL ;
2006-05-10 20:23:41 +04:00
}
2005-01-06 21:22:44 +03:00
2002-03-19 02:39:42 +03:00
dmt - > type = type ;
2002-01-11 15:12:46 +03:00
dmt - > minor = - 1 ;
2003-04-02 23:03:00 +04:00
dmt - > major = - 1 ;
2009-06-18 00:55:24 +04:00
dmt - > allow_default_major_fallback = 1 ;
2008-06-07 00:44:35 +04:00
dmt - > uid = DM_DEVICE_UID ;
dmt - > gid = DM_DEVICE_GID ;
dmt - > mode = DM_DEVICE_MODE ;
2005-09-20 20:39:12 +04:00
dmt - > no_open_count = 0 ;
2007-11-27 23:57:05 +03:00
dmt - > read_ahead = DM_READ_AHEAD_AUTO ;
dmt - > read_ahead_flags = 0 ;
2009-10-26 17:29:33 +03:00
dmt - > event_nr = 0 ;
2009-08-03 22:01:45 +04:00
dmt - > cookie_set = 0 ;
2009-11-06 03:43:08 +03:00
dmt - > query_inactive_table = 0 ;
2010-10-15 05:10:27 +04:00
dmt - > new_uuid = 0 ;
2011-02-04 19:08:11 +03:00
dmt - > secure_data = 0 ;
2015-08-05 10:28:35 +03:00
dmt - > record_timestamp = 0 ;
2021-07-13 04:06:04 +03:00
dmt - > ima_measurement = 0 ;
2003-01-22 00:25:11 +03:00
2002-03-19 02:39:42 +03:00
return dmt ;
2001-12-05 19:41:52 +03:00
}
2009-09-25 22:08:04 +04:00
/*
* Find the name associated with a given device number by scanning _dm_dir .
*/
2012-02-15 15:27:01 +04:00
static int _find_dm_name_of_device ( dev_t st_rdev , char * buf , size_t buf_len )
2009-09-25 22:08:04 +04:00
{
const char * name ;
char path [ PATH_MAX ] ;
struct dirent * dirent ;
DIR * d ;
2012-02-15 15:27:01 +04:00
struct stat st ;
int r = 0 ;
2009-09-25 22:08:04 +04:00
if ( ! ( d = opendir ( _dm_dir ) ) ) {
log_sys_error ( " opendir " , _dm_dir ) ;
2012-02-15 15:27:01 +04:00
return 0 ;
2009-09-25 22:08:04 +04:00
}
while ( ( dirent = readdir ( d ) ) ) {
name = dirent - > d_name ;
if ( ! strcmp ( name , " . " ) | | ! strcmp ( name , " .. " ) )
continue ;
if ( dm_snprintf ( path , sizeof ( path ) , " %s/%s " , _dm_dir ,
name ) = = - 1 ) {
log_error ( " Couldn't create path for %s " , name ) ;
continue ;
}
2012-02-15 15:27:01 +04:00
if ( stat ( path , & st ) )
2009-09-25 22:08:04 +04:00
continue ;
2012-02-15 15:27:01 +04:00
if ( st . st_rdev = = st_rdev ) {
strncpy ( buf , name , buf_len ) ;
r = 1 ;
2009-09-25 22:08:04 +04:00
break ;
}
}
if ( closedir ( d ) )
2021-03-09 13:08:47 +03:00
log_sys_debug ( " closedir " , _dm_dir ) ;
2009-09-25 22:08:04 +04:00
2012-02-15 15:27:01 +04:00
return r ;
2009-09-25 22:08:04 +04:00
}
2012-02-15 15:27:01 +04:00
static int _is_whitelisted_char ( char c )
2001-12-05 19:41:52 +03:00
{
2009-09-25 22:08:04 +04:00
/*
2012-02-15 15:27:01 +04:00
* Actually , DM supports any character in a device name .
* This whitelist is just for proper integration with udev .
2001-12-14 16:30:04 +03:00
*/
2012-02-15 15:27:01 +04:00
if ( ( c > = ' 0 ' & & c < = ' 9 ' ) | |
( c > = ' A ' & & c < = ' Z ' ) | |
( c > = ' a ' & & c < = ' z ' ) | |
strchr ( " #+-.:=@_ " , c ) ! = NULL )
return 1 ;
2009-01-07 15:17:40 +03:00
2012-02-15 15:27:01 +04:00
return 0 ;
}
2009-09-25 22:08:04 +04:00
2012-10-10 18:59:11 +04:00
int check_multiple_mangled_string_allowed ( const char * str , const char * str_name ,
dm_string_mangling_t mode )
2012-03-05 16:48:12 +04:00
{
2012-10-10 18:59:11 +04:00
if ( mode = = DM_STRING_MANGLING_AUTO & & strstr ( str , " \\ x5cx " ) ) {
log_error ( " The %s \" %s \" seems to be mangled more than once. "
" This is not allowed in auto mode. " , str_name , str ) ;
2012-03-05 16:48:12 +04:00
return 0 ;
}
return 1 ;
}
2012-02-15 15:27:01 +04:00
/*
* Mangle all characters in the input string which are not on a whitelist
* with ' \ xNN ' format where NN is the hex value of the character .
*/
2012-10-10 18:59:11 +04:00
int mangle_string ( const char * str , const char * str_name , size_t len ,
char * buf , size_t buf_len , dm_string_mangling_t mode )
2012-02-15 15:27:01 +04:00
{
int need_mangling = - 1 ; /* -1 don't know yet, 0 no, 1 yes */
size_t i , j ;
if ( ! str | | ! buf )
return - 1 ;
/* Is there anything to do at all? */
2012-03-05 16:40:34 +04:00
if ( ! * str | | ! len )
2012-02-15 15:27:01 +04:00
return 0 ;
if ( buf_len < DM_NAME_LEN ) {
2012-10-10 18:59:11 +04:00
log_error ( INTERNAL_ERROR " mangle_string: supplied buffer too small " ) ;
2012-02-15 15:27:01 +04:00
return - 1 ;
}
2012-03-05 16:40:34 +04:00
if ( mode = = DM_STRING_MANGLING_NONE )
mode = DM_STRING_MANGLING_AUTO ;
2012-02-15 15:27:01 +04:00
for ( i = 0 , j = 0 ; str [ i ] ; i + + ) {
if ( mode = = DM_STRING_MANGLING_AUTO ) {
/*
* Detect already mangled part of the string and keep it .
* Return error on mixture of mangled / not mangled !
*/
if ( str [ i ] = = ' \\ ' & & str [ i + 1 ] = = ' x ' ) {
if ( ( len - i < 4 ) | | ( need_mangling = = 1 ) )
goto bad1 ;
if ( buf_len - j < 4 )
goto bad2 ;
memcpy ( & buf [ j ] , & str [ i ] , 4 ) ;
i + = 3 ; j + = 4 ;
need_mangling = 0 ;
continue ;
}
2009-09-25 23:06:05 +04:00
}
2001-12-14 16:30:04 +03:00
2012-02-15 15:27:01 +04:00
if ( _is_whitelisted_char ( str [ i ] ) ) {
/* whitelisted, keep it. */
if ( buf_len - j < 1 )
goto bad2 ;
buf [ j ] = str [ i ] ;
j + + ;
} else {
/*
* Not on a whitelist , mangle it .
* Return error on mixture of mangled / not mangled
* unless a DM_STRING_MANGLING_HEX is used ! .
*/
if ( ( mode ! = DM_STRING_MANGLING_HEX ) & & ( need_mangling = = 0 ) )
goto bad1 ;
if ( buf_len - j < 4 )
goto bad2 ;
sprintf ( & buf [ j ] , " \\ x%02x " , ( unsigned char ) str [ i ] ) ;
j + = 4 ;
need_mangling = 1 ;
2001-12-14 16:30:04 +03:00
}
}
2012-02-15 15:27:01 +04:00
if ( buf_len - j < 1 )
goto bad2 ;
buf [ j ] = ' \0 ' ;
/* All chars in the string whitelisted? */
if ( need_mangling = = - 1 )
need_mangling = 0 ;
return need_mangling ;
bad1 :
2012-10-10 18:59:11 +04:00
log_error ( " The %s \" %s \" contains mixed mangled and unmangled "
" characters or it's already mangled improperly. " , str_name , str ) ;
2012-02-15 15:27:01 +04:00
return - 1 ;
bad2 :
2012-10-10 18:59:11 +04:00
log_error ( " Mangled form of the %s too long for \" %s \" . " , str_name , str ) ;
2012-02-15 15:27:01 +04:00
return - 1 ;
}
2012-02-15 15:39:38 +04:00
/*
* Try to unmangle supplied string .
* Return value : - 1 on error , 0 when no unmangling needed , 1 when unmangling applied
*/
2012-10-10 18:59:11 +04:00
int unmangle_string ( const char * str , const char * str_name , size_t len ,
char * buf , size_t buf_len , dm_string_mangling_t mode )
2012-02-15 15:39:38 +04:00
{
2012-03-05 16:43:03 +04:00
int strict = mode ! = DM_STRING_MANGLING_NONE ;
2012-02-15 15:39:38 +04:00
char str_rest [ DM_NAME_LEN ] ;
size_t i , j ;
2020-08-28 20:35:25 +03:00
unsigned int code ;
2012-02-15 15:39:38 +04:00
int r = 0 ;
if ( ! str | | ! buf )
return - 1 ;
/* Is there anything to do at all? */
2012-03-05 16:40:34 +04:00
if ( ! * str | | ! len )
2012-02-15 15:39:38 +04:00
return 0 ;
if ( buf_len < DM_NAME_LEN ) {
2012-10-10 18:59:11 +04:00
log_error ( INTERNAL_ERROR " unmangle_string: supplied buffer too small " ) ;
2012-02-15 15:39:38 +04:00
return - 1 ;
}
for ( i = 0 , j = 0 ; str [ i ] ; i + + , j + + ) {
2012-03-05 16:43:03 +04:00
if ( strict & & ! ( _is_whitelisted_char ( str [ i ] ) | | str [ i ] = = ' \\ ' ) ) {
2012-10-10 18:59:11 +04:00
log_error ( " The %s \" %s \" should be mangled but "
" it contains blacklisted characters. " , str_name , str ) ;
2012-03-05 16:43:03 +04:00
j = 0 ; r = - 1 ;
goto out ;
}
2012-02-15 15:39:38 +04:00
if ( str [ i ] = = ' \\ ' & & str [ i + 1 ] = = ' x ' ) {
2024-05-04 22:14:41 +03:00
if ( ! sscanf ( & str [ i + 2 ] , " %2x% " DM_TO_STRING ( DM_NAME_LEN ) " s " ,
& code , str_rest ) ) {
2013-01-08 02:30:29 +04:00
log_debug_activation ( " Hex encoding mismatch detected in %s \" %s \" "
" while trying to unmangle it. " , str_name , str ) ;
2012-02-15 15:39:38 +04:00
goto out ;
}
buf [ j ] = ( unsigned char ) code ;
/* skip the encoded part we've just decoded! */
i + = 3 ;
/* unmangling applied */
r = 1 ;
} else
buf [ j ] = str [ i ] ;
}
out :
buf [ j ] = ' \0 ' ;
return r ;
}
2012-02-15 15:27:01 +04:00
static int _dm_task_set_name ( struct dm_task * dmt , const char * name ,
dm_string_mangling_t mangling_mode )
{
char mangled_name [ DM_NAME_LEN ] ;
2012-03-05 16:40:34 +04:00
int r = 0 ;
2012-02-15 15:27:01 +04:00
dm_free ( dmt - > dev_name ) ;
dmt - > dev_name = NULL ;
dm_free ( dmt - > mangled_dev_name ) ;
dmt - > mangled_dev_name = NULL ;
2009-01-07 15:17:40 +03:00
if ( strlen ( name ) > = DM_NAME_LEN ) {
2012-02-15 15:27:01 +04:00
log_error ( " Name \" %s \" too long. " , name ) ;
2009-01-07 15:17:40 +03:00
return 0 ;
}
2012-10-10 18:59:11 +04:00
if ( ! check_multiple_mangled_string_allowed ( name , " name " , mangling_mode ) )
2012-03-05 16:48:12 +04:00
return_0 ;
2012-03-05 16:40:34 +04:00
if ( mangling_mode ! = DM_STRING_MANGLING_NONE & &
2012-10-10 18:59:11 +04:00
( r = mangle_string ( name , " name " , strlen ( name ) , mangled_name ,
sizeof ( mangled_name ) , mangling_mode ) ) < 0 ) {
2012-02-15 15:27:01 +04:00
log_error ( " Failed to mangle device name \" %s \" . " , name ) ;
return 0 ;
}
/* Store mangled_dev_name only if it differs from dev_name! */
if ( r ) {
2013-01-08 02:30:29 +04:00
log_debug_activation ( " Device name mangled [%s]: %s --> %s " ,
mangling_mode = = DM_STRING_MANGLING_AUTO ? " auto " : " hex " ,
name , mangled_name ) ;
2012-02-15 15:27:01 +04:00
if ( ! ( dmt - > mangled_dev_name = dm_strdup ( mangled_name ) ) ) {
log_error ( " _dm_task_set_name: dm_strdup(%s) failed " , mangled_name ) ;
return 0 ;
}
}
if ( ! ( dmt - > dev_name = dm_strdup ( name ) ) ) {
log_error ( " _dm_task_set_name: strdup(%s) failed " , name ) ;
2001-12-14 16:30:04 +03:00
return 0 ;
}
2002-03-19 02:39:42 +03:00
return 1 ;
2001-12-05 19:41:52 +03:00
}
2012-02-15 15:27:01 +04:00
static int _dm_task_set_name_from_path ( struct dm_task * dmt , const char * path ,
const char * name )
{
char buf [ PATH_MAX ] ;
struct stat st1 , st2 ;
2015-07-29 14:24:36 +03:00
const char * final_name = NULL ;
size_t len ;
2012-02-15 15:27:01 +04:00
if ( dmt - > type = = DM_DEVICE_CREATE ) {
log_error ( " Name \" %s \" invalid. It contains \" / \" . " , path ) ;
return 0 ;
}
2015-07-29 14:24:36 +03:00
if ( ! stat ( path , & st1 ) ) {
/*
* Found directly .
* If supplied path points to same device as last component
* under / dev / mapper , use that name directly .
*/
if ( dm_snprintf ( buf , sizeof ( buf ) , " %s/%s " , _dm_dir , name ) = = - 1 ) {
log_error ( " Couldn't create path for %s " , name ) ;
return 0 ;
}
if ( ! stat ( buf , & st2 ) & & ( st1 . st_rdev = = st2 . st_rdev ) )
final_name = name ;
} else {
/* Not found. */
/* If there is exactly one '/' try a prefix of /dev */
if ( ( len = strlen ( path ) ) < 3 | | path [ 0 ] = = ' / ' | |
dm_count_chars ( path , len , ' / ' ) ! = 1 ) {
log_error ( " Device %s not found " , path ) ;
return 0 ;
}
if ( dm_snprintf ( buf , sizeof ( buf ) , " %s/../%s " , _dm_dir , path ) = = - 1 ) {
log_error ( " Couldn't create /dev path for %s " , path ) ;
return 0 ;
}
if ( stat ( buf , & st1 ) ) {
log_error ( " Device %s not found " , path ) ;
return 0 ;
}
/* Found */
2012-02-15 15:27:01 +04:00
}
/*
2015-07-29 14:24:36 +03:00
* If we don ' t have the dm name yet , Call _find_dm_name_of_device ( ) to
* scan _dm_dir for a match .
2012-02-15 15:27:01 +04:00
*/
2015-07-29 14:24:36 +03:00
if ( ! final_name ) {
if ( _find_dm_name_of_device ( st1 . st_rdev , buf , sizeof ( buf ) ) )
final_name = buf ;
else {
log_error ( " Device %s not found " , name ) ;
return 0 ;
}
2012-02-15 15:27:01 +04:00
}
/* This is an already existing path - do not mangle! */
return _dm_task_set_name ( dmt , final_name , DM_STRING_MANGLING_NONE ) ;
}
int dm_task_set_name ( struct dm_task * dmt , const char * name )
{
char * pos ;
/* Path supplied for existing device? */
if ( ( pos = strrchr ( name , ' / ' ) ) )
return _dm_task_set_name_from_path ( dmt , name , pos + 1 ) ;
return _dm_task_set_name ( dmt , name , dm_get_name_mangling_mode ( ) ) ;