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 ;
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 ' ) {
if ( ! sscanf ( & str [ i + 2 ] , " %2x%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 ( ) ) ;
}
const char * dm_task_get_name ( const struct dm_task * dmt )
{
return ( dmt - > dmi . v4 - > name ) ;
}
2012-10-10 18:59:47 +04:00
static char * _task_get_string_mangled ( const char * str , const char * str_name ,
char * buf , size_t buf_size ,
dm_string_mangling_t mode )
{
char * rs ;
int r ;
if ( ( r = mangle_string ( str , str_name , strlen ( str ) , buf , buf_size , mode ) ) < 0 )
return NULL ;
if ( ! ( rs = r ? dm_strdup ( buf ) : dm_strdup ( str ) ) )
log_error ( " _task_get_string_mangled: dm_strdup failed " ) ;
return rs ;
}
static char * _task_get_string_unmangled ( const char * str , const char * str_name ,
char * buf , size_t buf_size ,
dm_string_mangling_t mode )
{
char * rs ;
int r = 0 ;
/*
* Unless the mode used is ' none ' , the string
* is * already * unmangled on ioctl return !
*/
if ( mode = = DM_STRING_MANGLING_NONE & &
( r = unmangle_string ( str , str_name , strlen ( str ) , buf , buf_size , mode ) ) < 0 )
return NULL ;
if ( ! ( rs = r ? dm_strdup ( buf ) : dm_strdup ( str ) ) )
log_error ( " _task_get_string_unmangled: dm_strdup failed " ) ;
return rs ;
}
2012-02-15 15:39:38 +04:00
char * dm_task_get_name_mangled ( const struct dm_task * dmt )
{
const char * s = dm_task_get_name ( dmt ) ;
char buf [ DM_NAME_LEN ] ;
2012-10-10 18:59:47 +04:00
char * rs ;
2012-02-15 15:39:38 +04:00
2012-10-10 18:59:47 +04:00
if ( ! ( rs = _task_get_string_mangled ( s , " name " , buf , sizeof ( buf ) , dm_get_name_mangling_mode ( ) ) ) )
2012-02-15 15:39:38 +04:00
log_error ( " Failed to mangle device name \" %s \" . " , s ) ;
return rs ;
}
char * dm_task_get_name_unmangled ( const struct dm_task * dmt )
{
const char * s = dm_task_get_name ( dmt ) ;
char buf [ DM_NAME_LEN ] ;
2012-10-10 18:59:47 +04:00
char * rs ;
2012-02-15 15:39:38 +04:00
2012-10-10 18:59:47 +04:00
if ( ! ( rs = _task_get_string_unmangled ( s , " name " , buf , sizeof ( buf ) , dm_get_name_mangling_mode ( ) ) ) )
2012-02-15 15:39:38 +04:00
log_error ( " Failed to unmangle device name \" %s \" . " , s ) ;
2012-10-10 18:59:47 +04:00
return rs ;
}
const char * dm_task_get_uuid ( const struct dm_task * dmt )
{
return ( dmt - > dmi . v4 - > uuid ) ;
}
char * dm_task_get_uuid_mangled ( const struct dm_task * dmt )
{
const char * s = dm_task_get_uuid ( dmt ) ;
char buf [ DM_UUID_LEN ] ;
char * rs ;
if ( ! ( rs = _task_get_string_mangled ( s , " UUID " , buf , sizeof ( buf ) , dm_get_name_mangling_mode ( ) ) ) )
log_error ( " Failed to mangle device uuid \" %s \" . " , s ) ;
return rs ;
}
char * dm_task_get_uuid_unmangled ( const struct dm_task * dmt )
{
const char * s = dm_task_get_uuid ( dmt ) ;
char buf [ DM_UUID_LEN ] ;
char * rs ;
if ( ! ( rs = _task_get_string_unmangled ( s , " UUID " , buf , sizeof ( buf ) , dm_get_name_mangling_mode ( ) ) ) )
log_error ( " Failed to unmangle device uuid \" %s \" . " , s ) ;
2012-02-15 15:39:38 +04:00
return rs ;
}
2012-01-17 18:36:58 +04:00
int dm_task_set_newname ( struct dm_task * dmt , const char * newname )
{
2012-02-15 15:27:01 +04:00
dm_string_mangling_t mangling_mode = dm_get_name_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
2012-01-17 18:36:58 +04: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 ;
}
2013-08-30 16:46:34 +04:00
if ( ! * newname ) {
log_error ( " Non empty new name is required. " ) ;
return 0 ;
}
2012-10-10 18:59:11 +04:00
if ( ! check_multiple_mangled_string_allowed ( newname , " new 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 ( newname , " new name " , strlen ( newname ) , mangled_name ,
sizeof ( mangled_name ) , mangling_mode ) ) < 0 ) {
2012-02-15 15:27:01 +04:00
log_error ( " Failed to mangle new device name \" %s \" " , newname ) ;
return 0 ;
}
if ( r ) {
2013-01-08 02:30:29 +04:00
log_debug_activation ( " New device name mangled [%s]: %s --> %s " ,
mangling_mode = = DM_STRING_MANGLING_AUTO ? " auto " : " hex " ,
newname , mangled_name ) ;
2012-02-15 15:27:01 +04:00
newname = mangled_name ;
}
2013-09-18 04:13:06 +04:00
dm_free ( dmt - > newname ) ;
2012-01-17 18:36:58 +04:00
if ( ! ( dmt - > newname = dm_strdup ( newname ) ) ) {
log_error ( " dm_task_set_newname: strdup(%s) failed " , newname ) ;
return 0 ;
}
2012-02-15 15:27:01 +04:00
2012-01-17 18:36:58 +04:00
dmt - > new_uuid = 0 ;
return 1 ;
}
2002-03-12 01:44:36 +03:00
int dm_task_set_uuid ( struct dm_task * dmt , const char * uuid )
{
2012-10-10 19:00:41 +04:00
char mangled_uuid [ DM_UUID_LEN ] ;
dm_string_mangling_t mangling_mode = dm_get_name_mangling_mode ( ) ;
int r = 0 ;
2010-11-29 13:11:50 +03:00
dm_free ( dmt - > uuid ) ;
2012-10-10 19:00:41 +04:00
dmt - > uuid = NULL ;
dm_free ( dmt - > mangled_uuid ) ;
dmt - > mangled_uuid = NULL ;
if ( ! check_multiple_mangled_string_allowed ( uuid , " UUID " , mangling_mode ) )
return_0 ;
if ( mangling_mode ! = DM_STRING_MANGLING_NONE & &
( r = mangle_string ( uuid , " UUID " , strlen ( uuid ) , mangled_uuid ,
sizeof ( mangled_uuid ) , mangling_mode ) ) < 0 ) {
log_error ( " Failed to mangle device uuid \" %s \" . " , uuid ) ;
return 0 ;
}
if ( r ) {
2013-01-08 02:30:29 +04:00
log_debug_activation ( " Device uuid mangled [%s]: %s --> %s " ,
mangling_mode = = DM_STRING_MANGLING_AUTO ? " auto " : " hex " ,
uuid , mangled_uuid ) ;
2012-10-10 19:00:41 +04:00
if ( ! ( dmt - > mangled_uuid = dm_strdup ( mangled_uuid ) ) ) {
log_error ( " dm_task_set_uuid: dm_strdup(%s) failed " , mangled_uuid ) ;
return 0 ;
}
}
2002-03-12 01:44:36 +03:00
2005-10-17 02:57:20 +04:00
if ( ! ( dmt - > uuid = dm_strdup ( uuid ) ) ) {
2002-03-12 01:44:36 +03:00
log_error ( " dm_task_set_uuid: strdup(%s) failed " , uuid ) ;
return 0 ;
}
return 1 ;
}
2003-04-02 23:03:00 +04:00
int dm_task_set_major ( struct dm_task * dmt , int major )
{
dmt - > major = major ;
2009-06-18 00:55:24 +04:00
dmt - > allow_default_major_fallback = 0 ;
2003-04-02 23:03:00 +04:00
return 1 ;
}
2002-01-11 15:12:46 +03:00
int dm_task_set_minor ( struct dm_task * dmt , int minor )
{
2002-03-19 02:39:42 +03:00
dmt - > minor = minor ;
2002-01-11 15:12:46 +03:00
2002-03-19 02:39:42 +03:00
return 1 ;
}
2002-01-11 15:12:46 +03:00
2009-06-18 00:55:24 +04:00
int dm_task_set_major_minor ( struct dm_task * dmt , int major , int minor ,
int allow_default_major_fallback )
{
dmt - > major = major ;
dmt - > minor = minor ;
dmt - > allow_default_major_fallback = allow_default_major_fallback ;
return 1 ;
}
2006-02-03 17:23:22 +03:00
int dm_task_set_uid ( struct dm_task * dmt , uid_t uid )
{
dmt - > uid = uid ;
return 1 ;
}
int dm_task_set_gid ( struct dm_task * dmt , gid_t gid )
{
dmt - > gid = gid ;
return 1 ;
}
int dm_task_set_mode ( struct dm_task * dmt , mode_t mode )
{
dmt - > mode = mode ;
return 1 ;
}
2011-07-01 18:09:19 +04:00
int dm_task_enable_checks ( struct dm_task * dmt )
{
dmt - > enable_checks = 1 ;
return 1 ;
}
2002-03-19 02:39:42 +03:00
int dm_task_add_target ( struct dm_task * dmt , uint64_t start , uint64_t size ,
const char * ttype , const char * params )
2001-12-05 19:41:52 +03:00
{
2002-03-19 02:39:42 +03:00
struct target * t = create_target ( start , size , ttype , params ) ;
if ( ! t )
2011-11-18 23:34:02 +04:00
return_0 ;
2001-12-05 19:41:52 +03:00
2002-03-19 02:39:42 +03:00
if ( ! dmt - > head )
dmt - > head = dmt - > tail = t ;
else {
dmt - > tail - > next = t ;
dmt - > tail = t ;
}
2001-12-05 19:41:52 +03:00
2002-03-19 02:39:42 +03:00
return 1 ;
2001-12-05 19:41:52 +03:00
}
2010-12-13 15:44:09 +03:00
# ifdef HAVE_SELINUX
2010-12-13 13:43:56 +03:00
static int _selabel_lookup ( const char * path , mode_t mode ,
security_context_t * scontext )
{
# ifdef HAVE_SELINUX_LABEL_H
if ( ! _selabel_handle & &
! ( _selabel_handle = selabel_open ( SELABEL_CTX_FILE , NULL , 0 ) ) ) {
log_error ( " selabel_open failed: %s " , strerror ( errno ) ) ;
return 0 ;
}
if ( selabel_lookup ( _selabel_handle , scontext , path , mode ) ) {
2013-01-08 02:30:29 +04:00
log_debug_activation ( " selabel_lookup failed for %s: %s " ,
path , strerror ( errno ) ) ;
2010-12-13 13:43:56 +03:00
return 0 ;
}
2010-12-13 15:30:04 +03:00
# else
2010-12-13 13:43:56 +03:00
if ( matchpathcon ( path , mode , scontext ) ) {
2013-01-08 02:30:29 +04:00
log_debug_activation ( " matchpathcon failed for %s: %s " ,
path , strerror ( errno ) ) ;
2010-12-13 13:43:56 +03:00
return 0 ;
}
# endif
return 1 ;
}
2010-12-13 15:44:09 +03:00
# endif
2010-12-13 13:43:56 +03:00
2014-02-20 20:09:55 +04:00
# ifdef HAVE_SELINUX
static int _is_selinux_enabled ( void )
{
static int _tested = 0 ;
static int _enabled ;
if ( ! _tested ) {
_tested = 1 ;
_enabled = is_selinux_enabled ( ) ;
}
return _enabled ;
}
# endif
2010-12-13 13:43:56 +03:00
int dm_prepare_selinux_context ( const char * path , mode_t mode )
2004-04-06 22:54:00 +04:00
{
2009-10-12 08:06:42 +04:00
# ifdef HAVE_SELINUX
2010-12-13 13:43:56 +03:00
security_context_t scontext = NULL ;
2004-04-06 22:54:00 +04:00
2014-02-20 20:09:55 +04:00
if ( _is_selinux_enabled ( ) < = 0 )
2004-07-03 22:14:12 +04:00
return 1 ;
2004-04-06 22:54:00 +04:00
2010-12-13 13:43:56 +03:00
if ( path ) {
if ( ! _selabel_lookup ( path , mode , & scontext ) )
return_0 ;
2013-01-08 02:30:29 +04:00
log_debug_activation ( " Preparing SELinux context for %s to %s. " , path , scontext ) ;
2010-12-13 13:43:56 +03:00
}
else
2013-01-08 02:30:29 +04:00
log_debug_activation ( " Resetting SELinux context to default value. " ) ;
2010-12-13 13:43:56 +03:00
if ( setfscreatecon ( scontext ) < 0 ) {
2013-08-15 14:40:47 +04:00
log_sys_error ( " setfscreatecon " , ( path ? : " SELinux context reset " ) ) ;
2010-12-13 13:43:56 +03:00
freecon ( scontext ) ;
2004-04-06 22:54:00 +04:00
return 0 ;
}
2010-12-13 13:43:56 +03:00
freecon ( scontext ) ;
# endif
return 1 ;
}
int dm_set_selinux_context ( const char * path , mode_t mode )
{
# ifdef HAVE_SELINUX
2013-09-24 16:47:32 +04:00
security_context_t scontext = NULL ;
2010-12-13 13:43:56 +03:00
2014-02-20 20:09:55 +04:00
if ( _is_selinux_enabled ( ) < = 0 )
2010-12-13 13:43:56 +03:00
return 1 ;
if ( ! _selabel_lookup ( path , mode , & scontext ) )
return_0 ;
2013-01-08 02:30:29 +04:00
log_debug_activation ( " Setting SELinux context for %s to %s. " , path , scontext ) ;
2005-06-11 01:30:21 +04:00
2004-04-16 16:24:46 +04:00
if ( ( lsetfilecon ( path , scontext ) < 0 ) & & ( errno ! = ENOTSUP ) ) {
2007-07-28 14:23:02 +04:00
log_sys_error ( " lsetfilecon " , path ) ;
2005-06-13 17:11:48 +04:00
freecon ( scontext ) ;
2004-04-06 22:54:00 +04:00
return 0 ;
}
2005-06-13 17:11:48 +04:00
freecon ( scontext ) ;
2009-10-12 08:06:42 +04:00
# endif
2004-04-06 22:54:00 +04:00
return 1 ;
}
2010-12-13 13:43:56 +03:00
void selinux_release ( void )
{
# ifdef HAVE_SELINUX_LABEL_H
if ( _selabel_handle )
selabel_close ( _selabel_handle ) ;
_selabel_handle = NULL ;
# endif
}
2011-06-28 01:43:58 +04:00
static int _warn_if_op_needed ( int warn_if_udev_failed )
{
return warn_if_udev_failed & & dm_udev_get_sync_support ( ) & & dm_udev_get_checking ( ) ;
}
2005-01-06 01:00:40 +03:00
static int _add_dev_node ( const char * dev_name , uint32_t major , uint32_t minor ,
2011-06-28 01:43:58 +04:00
uid_t uid , gid_t gid , mode_t mode , int warn_if_udev_failed )
2001-12-05 19:41:52 +03:00
{
2002-03-19 02:39:42 +03:00
char path [ PATH_MAX ] ;
struct stat info ;
2018-11-03 19:13:10 +03:00
dev_t dev = MKDEV ( major , minor ) ;
2005-01-06 01:00:40 +03:00
mode_t old_mask ;
2001-12-05 19:41:52 +03:00
2014-04-04 23:47:54 +04:00
if ( ! _build_dev_path ( path , sizeof ( path ) , dev_name ) )
return_0 ;
2001-12-05 19:41:52 +03:00
2002-03-19 02:39:42 +03:00
if ( stat ( path , & info ) > = 0 ) {
if ( ! S_ISBLK ( info . st_mode ) ) {
log_error ( " A non-block device file at '%s' "
" is already present " , path ) ;
return 0 ;
}
2001-12-05 19:41:52 +03:00
2005-01-06 01:00:40 +03:00
/* If right inode already exists we don't touch uid etc. */
2002-03-19 02:39:42 +03:00
if ( info . st_rdev = = dev )
return 1 ;
2001-12-05 19:41:52 +03:00
2002-03-19 02:39:42 +03:00
if ( unlink ( path ) < 0 ) {
log_error ( " Unable to unlink device node for '%s' " ,
dev_name ) ;
return 0 ;
}
2011-06-28 01:43:58 +04:00
} else if ( _warn_if_op_needed ( warn_if_udev_failed ) )
2009-08-03 22:33:08 +04:00
log_warn ( " %s not set up by udev: Falling back to direct "
" node creation. " , path ) ;
2001-12-05 19:41:52 +03:00
2010-12-13 13:43:56 +03:00
( void ) dm_prepare_selinux_context ( path , S_IFBLK ) ;
2005-01-06 01:00:40 +03:00
old_mask = umask ( 0 ) ;
2013-09-16 23:23:54 +04:00
/* The node may already have been created by udev. So ignore EEXIST. */
if ( mknod ( path , S_IFBLK | mode , dev ) < 0 & & errno ! = EEXIST ) {
2011-01-12 23:42:50 +03:00
log_error ( " %s: mknod for %s failed: %s " , path , dev_name , strerror ( errno ) ) ;
2010-12-13 13:43:56 +03:00
umask ( old_mask ) ;
( void ) dm_prepare_selinux_context ( NULL , 0 ) ;
2002-03-19 02:39:42 +03:00
return 0 ;
}
2005-01-06 01:00:40 +03:00
umask ( old_mask ) ;
2010-12-13 13:43:56 +03:00
( void ) dm_prepare_selinux_context ( NULL , 0 ) ;
2005-01-06 01:00:40 +03:00
if ( chown ( path , uid , gid ) < 0 ) {
2007-07-28 14:23:02 +04:00
log_sys_error ( " chown " , path ) ;
2005-01-06 01:00:40 +03:00
return 0 ;
}
2013-01-08 02:30:29 +04:00
log_debug_activation ( " Created %s " , path ) ;
2007-12-14 22:49:27 +03:00
2002-03-19 02:39:42 +03:00
return 1 ;
2001-12-05 19:41:52 +03:00
}
2011-06-28 01:43:58 +04:00
static int _rm_dev_node ( const char * dev_name , int warn_if_udev_failed )
2009-08-06 19:00:25 +04:00
{
char path [ PATH_MAX ] ;
struct stat info ;
2014-04-04 23:47:54 +04:00
if ( ! _build_dev_path ( path , sizeof ( path ) , dev_name ) )
return_0 ;
2015-09-17 14:31:34 +03:00
if ( lstat ( path , & info ) < 0 )
2009-08-06 19:00:25 +04:00
return 1 ;
2011-06-28 01:43:58 +04:00
else if ( _warn_if_op_needed ( warn_if_udev_failed ) )
2009-08-06 19:00:25 +04:00
log_warn ( " Node %s was not removed by udev. "
" Falling back to direct node removal. " , path ) ;
2013-09-16 23:23:54 +04:00
/* udev may already have deleted the node. Ignore ENOENT. */
if ( unlink ( path ) < 0 & & errno ! = ENOENT ) {
2009-08-06 19:00:25 +04:00
log_error ( " Unable to unlink device node for '%s' " , dev_name ) ;
return 0 ;
}
2013-01-08 02:30:29 +04:00
log_debug_activation ( " Removed %s " , path ) ;
2009-08-06 19:00:25 +04:00
return 1 ;
}
2009-10-26 17:29:33 +03:00
static int _rename_dev_node ( const char * old_name , const char * new_name ,
2011-06-28 01:43:58 +04:00
int warn_if_udev_failed )
2002-04-11 16:45:18 +04:00
{
char oldpath [ PATH_MAX ] ;
char newpath [ PATH_MAX ] ;
2015-09-17 14:31:34 +03:00
struct stat info , info2 ;
struct stat * info_block_dev ;
2002-04-11 16:45:18 +04:00
2014-04-04 23:47:54 +04:00
if ( ! _build_dev_path ( oldpath , sizeof ( oldpath ) , old_name ) | |
! _build_dev_path ( newpath , sizeof ( newpath ) , new_name ) )
return_0 ;
2002-04-11 16:45:18 +04:00
2015-09-17 14:31:34 +03:00
if ( lstat ( newpath , & info ) = = 0 ) {
if ( S_ISLNK ( info . st_mode ) ) {
if ( stat ( newpath , & info2 ) = = 0 )
info_block_dev = & info2 ;
else {
log_sys_error ( " stat " , newpath ) ;
return 0 ;
}
} else
info_block_dev = & info ;
if ( ! S_ISBLK ( info_block_dev - > st_mode ) ) {
2002-04-11 16:45:18 +04:00
log_error ( " A non-block device file at '%s' "
" is already present " , newpath ) ;
return 0 ;
}
2011-06-28 01:43:58 +04:00
else if ( _warn_if_op_needed ( warn_if_udev_failed ) ) {
2015-09-17 14:31:34 +03:00
if ( lstat ( oldpath , & info ) < 0 & &
2009-08-06 19:00:25 +04:00
errno = = ENOENT )
/* assume udev already deleted this */
return 1 ;
2017-07-19 17:16:12 +03:00
log_warn ( " The node %s should have been renamed to %s "
" by udev but old node is still present. "
" Falling back to direct old node removal. " ,
oldpath , newpath ) ;
return _rm_dev_node ( old_name , 0 ) ;
2009-08-06 19:00:25 +04:00
}
2002-04-11 16:45:18 +04:00
if ( unlink ( newpath ) < 0 ) {
2003-01-22 00:25:11 +03:00
if ( errno = = EPERM ) {
2002-04-24 01:47:50 +04:00
/* devfs, entry has already been renamed */
return 1 ;
2002-04-11 16:45:18 +04:00
}
log_error ( " Unable to unlink device node for '%s' " ,
new_name ) ;
return 0 ;
}
}
2011-06-28 01:43:58 +04:00
else if ( _warn_if_op_needed ( warn_if_udev_failed ) )
2009-08-06 19:00:25 +04:00
log_warn ( " The node %s should have been renamed to %s "
" by udev but new node is not present. "
" Falling back to direct node rename. " ,
oldpath , newpath ) ;
2002-04-11 16:45:18 +04:00
2013-09-16 23:23:54 +04:00
/* udev may already have renamed the node. Ignore ENOENT. */
2014-03-17 14:51:30 +04:00
/* FIXME: when renaming to target mangling mode "none" with udev
* while there are some blacklisted characters in the node name ,
* udev will remove the old_node , but fails to properly rename
* to new_node . The libdevmapper code tries to call
* rename ( old_node , new_node ) , but that won ' t do anything
* since the old node is already removed by udev .
* For example renaming ' a \ x20b ' to ' a b ' :
* - udev removes ' a \ x20b '
* - udev creates ' a ' and ' b ' ( since it considers the ' ' as a delimiter
* - libdevmapper checks udev has done the rename properly
* - libdevmapper calls stat ( new_node ) and it does not see it
* - libdevmapper calls rename ( old_node , new_node )
* - the rename is a NOP since the old_node does not exist anymore
*
* However , this situation is very rare - why would anyone need
* to rename to an unsupported mode ? ? ? So a fix for this would be
* just for completeness .
*/
2013-09-16 23:23:54 +04:00
if ( rename ( oldpath , newpath ) < 0 & & errno ! = ENOENT ) {
2002-04-24 01:47:50 +04:00
log_error ( " Unable to rename device node from '%s' to '%s' " ,
old_name , new_name ) ;
2002-04-11 16:45:18 +04:00
return 0 ;
}
2013-01-08 02:30:29 +04:00
log_debug_activation ( " Renamed %s to %s " , oldpath , newpath ) ;
2007-12-14 22:49:27 +03:00
2002-04-11 16:45:18 +04:00
return 1 ;
}
2013-11-13 17:56:29 +04:00
# ifdef __linux__
2007-11-30 19:42:26 +03:00
static int _open_dev_node ( const char * dev_name )
{
int fd = - 1 ;
char path [ PATH_MAX ] ;
2014-04-04 23:47:54 +04:00
if ( ! _build_dev_path ( path , sizeof ( path ) , dev_name ) )
return fd ;
2007-11-30 19:42:26 +03:00
if ( ( fd = open ( path , O_RDONLY , 0 ) ) < 0 )
log_sys_error ( " open " , path ) ;
return fd ;
}
2012-01-09 16:26:14 +04:00
int get_dev_node_read_ahead ( const char * dev_name , uint32_t major , uint32_t minor ,
uint32_t * read_ahead )
2007-11-30 17:59:57 +03:00
{
2012-01-09 16:26:14 +04:00
char buf [ 24 ] ;
int len ;
2007-11-30 19:42:26 +03:00
int r = 1 ;
int fd ;
2007-12-05 17:11:26 +03:00
long read_ahead_long ;
2007-11-30 19:42:26 +03:00
2012-01-09 16:26:14 +04:00
/*
* If we know the device number , use sysfs if we can .
* Otherwise use BLKRAGET ioctl .
*/
if ( * _sysfs_dir & & major ! = 0 ) {
if ( dm_snprintf ( _path0 , sizeof ( _path0 ) , " %sdev/block/% " PRIu32
" :% " PRIu32 " /bdi/read_ahead_kb " , _sysfs_dir ,
major , minor ) < 0 ) {
log_error ( " Failed to build sysfs_path. " ) ;
return 0 ;
}
if ( ( fd = open ( _path0 , O_RDONLY , 0 ) ) ! = - 1 ) {
/* Reading from sysfs, expecting number\n */
2012-02-08 15:05:04 +04:00
if ( ( len = read ( fd , buf , sizeof ( buf ) - 1 ) ) < 1 ) {
2012-01-09 16:26:14 +04:00
log_sys_error ( " read " , _path0 ) ;
r = 0 ;
} else {
buf [ len ] = 0 ; /* kill \n and ensure \0 */
* read_ahead = atoi ( buf ) * 2 ;
2013-01-08 02:30:29 +04:00
log_debug_activation ( " %s (%d:%d): read ahead is % " PRIu32 ,
dev_name , major , minor , * read_ahead ) ;
2012-01-09 16:26:14 +04:00
}
if ( close ( fd ) )
log_sys_debug ( " close " , _path0 ) ;
return r ;
}
log_sys_debug ( " open " , _path0 ) ;
/* Fall back to use dev_name */
}
/*
* Open / close dev_name may block the process
* ( i . e . overfilled thin pool volume )
*/
2007-12-13 05:25:45 +03:00
if ( ! * dev_name ) {
log_error ( " Empty device name passed to BLKRAGET " ) ;
return 0 ;
}
2007-11-30 19:42:26 +03:00
if ( ( fd = _open_dev_node ( dev_name ) ) < 0 )
2007-11-30 19:44:42 +03:00
return_0 ;
2007-11-30 19:42:26 +03:00
2007-12-05 17:11:26 +03:00
if ( ioctl ( fd , BLKRAGET , & read_ahead_long ) ) {
2007-11-30 19:42:26 +03:00
log_sys_error ( " BLKRAGET " , dev_name ) ;
2007-12-05 17:11:26 +03:00
* read_ahead = 0 ;
2007-11-30 19:42:26 +03:00
r = 0 ;
2012-01-09 16:26:14 +04:00
} else {
2007-12-05 17:11:26 +03:00
* read_ahead = ( uint32_t ) read_ahead_long ;
2013-01-08 02:30:29 +04:00
log_debug_activation ( " %s: read ahead is % " PRIu32 , dev_name , * read_ahead ) ;
2007-12-05 17:11:26 +03:00
}
2007-11-30 19:42:26 +03:00
2007-12-04 01:48:36 +03:00
if ( close ( fd ) )
2012-01-09 16:26:14 +04:00
log_sys_debug ( " close " , dev_name ) ;
2007-11-30 19:42:26 +03:00
return r ;
2007-11-30 17:59:57 +03:00
}
2012-01-09 16:26:14 +04:00
static int _set_read_ahead ( const char * dev_name , uint32_t major , uint32_t minor ,
uint32_t read_ahead )
2007-11-30 17:59:57 +03:00
{
2012-01-09 16:26:14 +04:00
char buf [ 24 ] ;
int len ;
2007-11-30 19:42:26 +03:00
int r = 1 ;
int fd ;
2007-12-05 17:11:26 +03:00
long read_ahead_long = ( long ) read_ahead ;
2007-11-30 19:42:26 +03:00
2013-01-08 02:30:29 +04:00
log_debug_activation ( " %s (%d:%d): Setting read ahead to % " PRIu32 , dev_name ,
major , minor , read_ahead ) ;
2012-01-09 16:26:14 +04:00
/*
* If we know the device number , use sysfs if we can .
* Otherwise use BLKRASET ioctl . RA is set after resume .
*/
if ( * _sysfs_dir & & major ! = 0 ) {
if ( dm_snprintf ( _path0 , sizeof ( _path0 ) , " %sdev/block/% " PRIu32
" :% " PRIu32 " /bdi/read_ahead_kb " ,
_sysfs_dir , major , minor ) < 0 ) {
log_error ( " Failed to build sysfs_path. " ) ;
return 0 ;
}
/* Sysfs is kB based, round up to kB */
2015-07-06 17:09:17 +03:00
if ( ( len = dm_snprintf ( buf , sizeof ( buf ) , FMTu32 ,
2012-01-09 16:26:14 +04:00
( read_ahead + 1 ) / 2 ) ) < 0 ) {
log_error ( " Failed to build size in kB. " ) ;
return 0 ;
}
if ( ( fd = open ( _path0 , O_WRONLY , 0 ) ) ! = - 1 ) {
if ( write ( fd , buf , len ) < len ) {
log_sys_error ( " write " , _path0 ) ;
r = 0 ;
}
if ( close ( fd ) )
log_sys_debug ( " close " , _path0 ) ;
return r ;
}
log_sys_debug ( " open " , _path0 ) ;
/* Fall back to use dev_name */
}
2007-12-13 05:25:45 +03:00
if ( ! * dev_name ) {
log_error ( " Empty device name passed to BLKRAGET " ) ;
return 0 ;
}
2007-11-30 19:42:26 +03:00
if ( ( fd = _open_dev_node ( dev_name ) ) < 0 )
return_0 ;
2007-12-05 17:11:26 +03:00
if ( ioctl ( fd , BLKRASET , read_ahead_long ) ) {
2007-11-30 19:42:26 +03:00
log_sys_error ( " BLKRASET " , dev_name ) ;
r = 0 ;
}
2007-12-04 01:48:36 +03:00
if ( close ( fd ) )
2012-01-09 16:26:14 +04:00
log_sys_debug ( " close " , dev_name ) ;
2007-11-30 19:42:26 +03:00
return r ;
2007-11-30 17:59:57 +03:00
}
2012-01-09 16:26:14 +04:00
static int _set_dev_node_read_ahead ( const char * dev_name ,
uint32_t major , uint32_t minor ,
uint32_t read_ahead , uint32_t read_ahead_flags )
2007-11-30 17:59:57 +03:00
{
uint32_t current_read_ahead ;
if ( read_ahead = = DM_READ_AHEAD_AUTO )
return 1 ;
if ( read_ahead = = DM_READ_AHEAD_NONE )
read_ahead = 0 ;
if ( read_ahead_flags & DM_READ_AHEAD_MINIMUM_FLAG ) {
2012-01-09 16:26:14 +04:00
if ( ! get_dev_node_read_ahead ( dev_name , major , minor , & current_read_ahead ) )
2007-11-30 17:59:57 +03:00
return_0 ;
2013-07-15 13:41:07 +04:00
if ( current_read_ahead > = read_ahead ) {
2013-01-08 02:30:29 +04:00
log_debug_activation ( " %s: retaining kernel read ahead of % " PRIu32
2007-12-05 21:57:34 +03:00
" (requested % " PRIu32 " ) " ,
2007-11-30 17:59:57 +03:00
dev_name , current_read_ahead , read_ahead ) ;
return 1 ;
}
}
2012-01-09 16:26:14 +04:00
return _set_read_ahead ( dev_name , major , minor , read_ahead ) ;
2007-11-30 17:59:57 +03:00
}
2007-11-30 19:42:26 +03:00
# else
int get_dev_node_read_ahead ( const char * dev_name , uint32_t * read_ahead )
{
* read_ahead = 0 ;
return 1 ;
}
2012-01-09 16:26:14 +04:00
static int _set_dev_node_read_ahead ( const char * dev_name ,
uint32_t major , uint32_t minor ,
uint32_t read_ahead , uint32_t read_ahead_flags )
2007-11-30 19:42:26 +03:00
{
return 1 ;
}
# endif
2003-07-02 01:20:58 +04:00
typedef enum {
NODE_ADD ,
NODE_DEL ,
2007-11-30 17:59:57 +03:00
NODE_RENAME ,
2011-02-04 22:14:39 +03:00
NODE_READ_AHEAD ,
NUM_NODES
2003-07-02 01:20:58 +04:00
} node_op_t ;
static int _do_node_op ( node_op_t type , const char * dev_name , uint32_t major ,
2005-01-06 01:00:40 +03:00
uint32_t minor , uid_t uid , gid_t gid , mode_t mode ,
2007-11-30 17:59:57 +03:00
const char * old_name , uint32_t read_ahead ,
2011-06-28 01:43:58 +04:00
uint32_t read_ahead_flags , int warn_if_udev_failed )
2003-07-02 01:20:58 +04:00
{
switch ( type ) {
case NODE_ADD :
2009-10-26 17:29:33 +03:00
return _add_dev_node ( dev_name , major , minor , uid , gid ,
2011-06-28 01:43:58 +04:00
mode , warn_if_udev_failed ) ;
2003-07-02 01:20:58 +04:00
case NODE_DEL :
2011-06-28 01:43:58 +04:00
return _rm_dev_node ( dev_name , warn_if_udev_failed ) ;
2003-07-02 01:20:58 +04:00
case NODE_RENAME :
2011-06-28 01:43:58 +04:00
return _rename_dev_node ( old_name , dev_name , warn_if_udev_failed ) ;
2007-11-30 17:59:57 +03:00
case NODE_READ_AHEAD :
2012-01-09 16:26:14 +04:00
return _set_dev_node_read_ahead ( dev_name , major , minor ,
read_ahead , read_ahead_flags ) ;
2011-02-05 01:07:43 +03:00
default :
; /* NOTREACHED */
2003-07-02 01:20:58 +04:00
}
return 1 ;
}
2008-11-04 01:14:30 +03:00
static DM_LIST_INIT ( _node_ops ) ;
2011-02-04 22:14:39 +03:00
static int _count_node_ops [ NUM_NODES ] ;
2003-07-02 01:20:58 +04:00
struct node_op_parms {
2008-11-04 01:14:30 +03:00
struct dm_list list ;
2003-07-02 01:20:58 +04:00
node_op_t type ;
char * dev_name ;
uint32_t major ;
uint32_t minor ;
2005-01-06 01:00:40 +03:00
uid_t uid ;
gid_t gid ;
mode_t mode ;
2007-11-30 17:59:57 +03:00
uint32_t read_ahead ;
uint32_t read_ahead_flags ;
2003-07-02 01:20:58 +04:00
char * old_name ;
2011-06-28 01:43:58 +04:00
int warn_if_udev_failed ;
unsigned rely_on_udev ;
2020-08-20 19:05:04 +03:00
char names [ ] ;
2003-07-02 01:20:58 +04:00
} ;
static void _store_str ( char * * pos , char * * ptr , const char * str )
{
strcpy ( * pos , str ) ;
* ptr = * pos ;
* pos + = strlen ( * ptr ) + 1 ;
}
2011-02-04 22:14:39 +03:00
static void _del_node_op ( struct node_op_parms * nop )
{
_count_node_ops [ nop - > type ] - - ;
dm_list_del ( & nop - > list ) ;
dm_free ( nop ) ;
}
/* Check if there is other the type of node operation stacked */
static int _other_node_ops ( node_op_t type )
{
2011-03-30 16:14:36 +04:00
unsigned i ;
2011-02-04 22:14:39 +03:00
for ( i = 0 ; i < NUM_NODES ; i + + )
if ( type ! = i & & _count_node_ops [ i ] )
return 1 ;
return 0 ;
}
2011-06-28 01:43:58 +04:00
static void _log_node_op ( const char * action_str , struct node_op_parms * nop )
2011-02-04 22:14:39 +03:00
{
2011-06-28 02:38:53 +04:00
const char * rely = nop - > rely_on_udev ? " [trust_udev] " : " " ;
const char * verify = nop - > warn_if_udev_failed ? " [verify_udev] " : " " ;
2011-06-28 01:43:58 +04:00
switch ( nop - > type ) {
case NODE_ADD :
2013-01-08 02:30:29 +04:00
log_debug_activation ( " %s: %s NODE_ADD (% " PRIu32 " ,% " PRIu32 " ) %u:%u 0%o%s%s " ,
nop - > dev_name , action_str , nop - > major , nop - > minor , nop - > uid , nop - > gid , nop - > mode ,
rely , verify ) ;
2011-06-28 01:43:58 +04:00
break ;
case NODE_DEL :
2013-01-08 02:30:29 +04:00
log_debug_activation ( " %s: %s NODE_DEL%s%s " , nop - > dev_name , action_str , rely , verify ) ;
2011-06-28 01:43:58 +04:00
break ;
case NODE_RENAME :
2013-01-08 02:30:29 +04:00
log_debug_activation ( " %s: %s NODE_RENAME to %s%s%s " , nop - > old_name , action_str , nop - > dev_name , rely , verify ) ;
2011-06-28 01:43:58 +04:00
break ;
case NODE_READ_AHEAD :
2013-01-08 02:30:29 +04:00
log_debug_activation ( " %s: %s NODE_READ_AHEAD % " PRIu32 " (flags=% " PRIu32 " )%s%s " ,
nop - > dev_name , action_str , nop - > read_ahead , nop - > read_ahead_flags , rely , verify ) ;
2011-06-28 01:43:58 +04:00
break ;
default :
; /* NOTREACHED */
}
2011-02-04 22:14:39 +03:00
}
2003-07-02 01:20:58 +04:00
static int _stack_node_op ( node_op_t type , const char * dev_name , uint32_t major ,
2005-01-06 01:00:40 +03:00
uint32_t minor , uid_t uid , gid_t gid , mode_t mode ,
2007-11-30 17:59:57 +03:00
const char * old_name , uint32_t read_ahead ,
2011-06-28 01:43:58 +04:00
uint32_t read_ahead_flags , int warn_if_udev_failed ,
unsigned rely_on_udev )
2003-07-02 01:20:58 +04:00
{
struct node_op_parms * nop ;
2008-11-04 01:14:30 +03:00
struct dm_list * noph , * nopht ;
2003-07-02 01:20:58 +04:00
size_t len = strlen ( dev_name ) + strlen ( old_name ) + 2 ;
char * pos ;
2007-12-14 22:49:27 +03:00
/*
2011-06-28 01:43:58 +04:00
* Note : warn_if_udev_failed must have valid content
2007-12-14 22:49:27 +03:00
*/
2011-02-04 22:14:39 +03:00
if ( ( type = = NODE_DEL ) & & _other_node_ops ( type ) )
/*
* Ignore any outstanding operations on the node if deleting it .
*/
2008-11-04 01:14:30 +03:00
dm_list_iterate_safe ( noph , nopht , & _node_ops ) {
nop = dm_list_item ( noph , struct node_op_parms ) ;
2007-12-14 22:49:27 +03:00
if ( ! strcmp ( dev_name , nop - > dev_name ) ) {
2011-06-28 01:43:58 +04:00
_log_node_op ( " Unstacking " , nop ) ;
2011-02-04 22:14:39 +03:00
_del_node_op ( nop ) ;
if ( ! _other_node_ops ( type ) )
break ; /* no other non DEL ops */
2007-12-14 22:49:27 +03:00
}
}
2011-06-28 01:43:58 +04:00
else if ( ( type = = NODE_ADD ) & & _count_node_ops [ NODE_DEL ] )
2011-02-04 22:14:39 +03:00
/*
2011-06-28 01:43:58 +04:00
* Ignore previous DEL operation on added node .
2011-02-05 01:07:43 +03:00
* ( No other operations for this device then DEL could be stacked here ) .
2011-02-04 22:14:39 +03:00
*/
dm_list_iterate_safe ( noph , nopht , & _node_ops ) {
nop = dm_list_item ( noph , struct node_op_parms ) ;
if ( ( nop - > type = = NODE_DEL ) & &
! strcmp ( dev_name , nop - > dev_name ) ) {
2011-06-28 01:43:58 +04:00
_log_node_op ( " Unstacking " , nop ) ;
2011-02-04 22:14:39 +03:00
_del_node_op ( nop ) ;
break ; /* no other DEL ops */
}
}
2011-12-19 01:56:03 +04:00
else if ( type = = NODE_RENAME )
2011-02-04 22:14:39 +03:00
/*
2011-06-28 01:43:58 +04:00
* Ignore any outstanding operations if renaming it .
2011-02-04 22:14:39 +03:00
*
* Currently RENAME operation happens through ' suspend - > resume ' .
* On ' resume ' device is added with read_ahead settings , so it is
* safe to remove any stacked ADD , RENAME , READ_AHEAD operation
* There cannot be any DEL operation on the renamed device .
*/
dm_list_iterate_safe ( noph , nopht , & _node_ops ) {
nop = dm_list_item ( noph , struct node_op_parms ) ;
2011-06-28 13:24:13 +04:00
if ( ! strcmp ( old_name , nop - > dev_name ) ) {
2011-06-28 01:43:58 +04:00
_log_node_op ( " Unstacking " , nop ) ;
2011-02-04 22:14:39 +03:00
_del_node_op ( nop ) ;
2011-06-28 13:24:13 +04:00
}
2011-02-04 22:14:39 +03:00
}
2011-06-28 13:24:13 +04:00
else if ( type = = NODE_READ_AHEAD ) {
/* udev doesn't process readahead */
rely_on_udev = 0 ;
warn_if_udev_failed = 0 ;
}
2007-12-14 22:49:27 +03:00
2005-10-17 02:57:20 +04:00
if ( ! ( nop = dm_malloc ( sizeof ( * nop ) + len ) ) ) {
2003-07-02 01:20:58 +04:00
log_error ( " Insufficient memory to stack mknod operation " ) ;
return 0 ;
}
pos = nop - > names ;
nop - > type = type ;
nop - > major = major ;
nop - > minor = minor ;
2005-01-06 01:00:40 +03:00
nop - > uid = uid ;
nop - > gid = gid ;
nop - > mode = mode ;
2007-11-30 17:59:57 +03:00
nop - > read_ahead = read_ahead ;
nop - > read_ahead_flags = read_ahead_flags ;
2011-06-28 01:43:58 +04:00
nop - > rely_on_udev = rely_on_udev ;
2003-07-02 01:20:58 +04:00
2011-06-28 13:24:13 +04:00
/*
* Clear warn_if_udev_failed if rely_on_udev is set . It doesn ' t get
* checked in this case - this just removes the flag from log messages .
*/
nop - > warn_if_udev_failed = rely_on_udev ? 0 : warn_if_udev_failed ;
2003-07-02 01:20:58 +04:00
_store_str ( & pos , & nop - > dev_name , dev_name ) ;
_store_str ( & pos , & nop - > old_name , old_name ) ;
2011-02-04 22:14:39 +03:00
_count_node_ops [ type ] + + ;
2008-11-04 01:14:30 +03:00
dm_list_add ( & _node_ops , & nop - > list ) ;
2003-07-02 01:20:58 +04:00
2011-06-28 01:43:58 +04:00
_log_node_op ( " Stacking " , nop ) ;
2003-07-02 01:20:58 +04:00
return 1 ;
}
static void _pop_node_ops ( void )
{
2008-11-04 01:14:30 +03:00
struct dm_list * noph , * nopht ;
2003-07-02 01:20:58 +04:00
struct node_op_parms * nop ;
2008-11-04 01:14:30 +03:00
dm_list_iterate_safe ( noph , nopht , & _node_ops ) {
nop = dm_list_item ( noph , struct node_op_parms ) ;
2011-06-28 01:43:58 +04:00
if ( ! nop - > rely_on_udev ) {
_log_node_op ( " Processing " , nop ) ;
_do_node_op ( nop - > type , nop - > dev_name , nop - > major , nop - > minor ,
nop - > uid , nop - > gid , nop - > mode , nop - > old_name ,
nop - > read_ahead , nop - > read_ahead_flags ,
nop - > warn_if_udev_failed ) ;
} else
2011-06-28 02:38:53 +04:00
_log_node_op ( " Skipping " , nop ) ;
2011-02-04 22:14:39 +03:00
_del_node_op ( nop ) ;
2003-07-02 01:20:58 +04:00
}
}
2005-01-06 01:00:40 +03:00
int add_dev_node ( const char * dev_name , uint32_t major , uint32_t minor ,
2011-06-28 01:43:58 +04:00
uid_t uid , gid_t gid , mode_t mode , int check_udev , unsigned rely_on_udev )
2003-07-02 01:20:58 +04:00
{
2009-10-26 17:29:33 +03:00
return _stack_node_op ( NODE_ADD , dev_name , major , minor , uid ,
2011-06-28 01:43:58 +04:00
gid , mode , " " , 0 , 0 , check_udev , rely_on_udev ) ;
2003-07-02 01:20:58 +04:00
}
2011-06-28 01:43:58 +04:00
int rename_dev_node ( const char * old_name , const char * new_name , int check_udev , unsigned rely_on_udev )
2003-07-02 01:20:58 +04:00
{
2009-10-26 17:29:33 +03:00
return _stack_node_op ( NODE_RENAME , new_name , 0 , 0 , 0 ,
2011-06-28 01:43:58 +04:00
0 , 0 , old_name , 0 , 0 , check_udev , rely_on_udev ) ;
2003-07-02 01:20:58 +04:00
}
2011-06-28 01:43:58 +04:00
int rm_dev_node ( const char * dev_name , int check_udev , unsigned rely_on_udev )
2003-07-02 01:20:58 +04:00
{
2009-10-26 17:29:33 +03:00
return _stack_node_op ( NODE_DEL , dev_name , 0 , 0 , 0 ,
2011-06-28 01:43:58 +04:00
0 , 0 , " " , 0 , 0 , check_udev , rely_on_udev ) ;
2007-11-30 17:59:57 +03:00
}
2012-01-09 16:26:14 +04:00
int set_dev_node_read_ahead ( const char * dev_name ,
uint32_t major , uint32_t minor ,
uint32_t read_ahead , uint32_t read_ahead_flags )
2007-11-30 17:59:57 +03:00
{
if ( read_ahead = = DM_READ_AHEAD_AUTO )
return 1 ;
2012-01-09 16:26:14 +04:00
return _stack_node_op ( NODE_READ_AHEAD , dev_name , major , minor , 0 , 0 ,
2011-06-28 01:43:58 +04:00
0 , " " , read_ahead , read_ahead_flags , 0 , 0 ) ;
2003-07-02 01:20:58 +04:00
}
void update_devs ( void )
{
_pop_node_ops ( ) ;
}
2011-09-22 21:17:07 +04:00
static int _canonicalize_and_set_dir ( const char * src , const char * suffix , size_t max_len , char * dir )
2001-12-05 19:41:52 +03:00
{
2007-10-09 16:14:48 +04:00
size_t len ;
const char * slash ;
2011-09-22 21:17:07 +04:00
if ( * src ! = ' / ' ) {
2013-01-08 02:30:29 +04:00
log_debug_activation ( " Invalid directory value, %s: "
" not an absolute name. " , src ) ;
2007-10-09 16:14:48 +04:00
return 0 ;
}
2011-09-22 21:17:07 +04:00
len = strlen ( src ) ;
slash = src [ len - 1 ] = = ' / ' ? " " : " / " ;
2007-10-09 16:14:48 +04:00
2011-09-22 21:17:07 +04:00
if ( dm_snprintf ( dir , max_len , " %s%s%s " , src , slash , suffix ? suffix : " " ) < 0 ) {
2013-01-08 02:30:29 +04:00
log_debug_activation ( " Invalid directory value, %s: name too long. " , src ) ;
2007-10-09 16:14:48 +04:00
return 0 ;
}
2002-03-19 02:39:42 +03:00
return 1 ;
2001-12-05 19:41:52 +03:00
}
2011-09-22 21:17:07 +04:00
int dm_set_dev_dir ( const char * dev_dir )
{
return _canonicalize_and_set_dir ( dev_dir , DM_DIR , sizeof _dm_dir , _dm_dir ) ;
}
2001-12-05 19:41:52 +03:00
const char * dm_dir ( void )
{
2002-03-19 02:39:42 +03:00
return _dm_dir ;
2001-12-05 19:41:52 +03:00
}
2005-10-17 02:57:20 +04:00
2011-09-22 21:17:07 +04:00
int dm_set_sysfs_dir ( const char * sysfs_dir )
{
if ( ! sysfs_dir | | ! * sysfs_dir ) {
_sysfs_dir [ 0 ] = ' \0 ' ;
return 1 ;
}
2014-04-04 23:45:37 +04:00
return _canonicalize_and_set_dir ( sysfs_dir , NULL , sizeof _sysfs_dir , _sysfs_dir ) ;
2011-09-22 21:17:07 +04:00
}
const char * dm_sysfs_dir ( void )
{
return _sysfs_dir ;
}
2012-01-10 06:03:31 +04:00
/*
* Replace existing uuid_prefix provided it isn ' t too long .
*/
int dm_set_uuid_prefix ( const char * uuid_prefix )
{
if ( ! uuid_prefix )
return_0 ;
if ( strlen ( uuid_prefix ) > DM_MAX_UUID_PREFIX_LEN ) {
log_error ( " New uuid prefix %s too long. " , uuid_prefix ) ;
return 0 ;
}
strcpy ( _default_uuid_prefix , uuid_prefix ) ;
return 1 ;
}
const char * dm_uuid_prefix ( void )
{
return _default_uuid_prefix ;
}
2013-05-16 13:34:26 +04:00
static int _is_octal ( int a )
{
return ( ( ( a ) & ~ 7 ) = = ' 0 ' ) ;
}
/* Convert mangled mountinfo into normal ASCII string */
static void _unmangle_mountinfo_string ( const char * src , char * buf )
{
while ( * src ) {
if ( ( * src = = ' \\ ' ) & &
_is_octal ( src [ 1 ] ) & & _is_octal ( src [ 2 ] ) & & _is_octal ( src [ 3 ] ) ) {
* buf + + = 64 * ( src [ 1 ] & 7 ) + 8 * ( src [ 2 ] & 7 ) + ( src [ 3 ] & 7 ) ;
src + = 4 ;
} else
* buf + + = * src + + ;
}
* buf = ' \0 ' ;
}
/* Parse one line of mountinfo and unmangled target line */
static int _mountinfo_parse_line ( const char * line , unsigned * maj , unsigned * min , char * buf )
{
2014-08-29 13:52:45 +04:00
char root [ PATH_MAX + 1 ] ; /* sscanf needs extra '\0' */
char target [ PATH_MAX + 1 ] ;
2018-03-20 13:13:22 +03:00
char * devmapper ;
struct dm_task * dmt ;
struct dm_info info ;
unsigned i ;
2013-05-16 13:34:26 +04:00
/* TODO: maybe detect availability of %ms glib support ? */
2013-05-29 14:46:21 +04:00
if ( sscanf ( line , " %*u %*u %u:%u % " DM_TO_STRING ( PATH_MAX )
" s % " DM_TO_STRING ( PATH_MAX ) " s " ,
2013-05-16 13:34:26 +04:00
maj , min , root , target ) < 4 ) {
log_error ( " Failed to parse mountinfo line. " ) ;
return 0 ;
}
2018-03-20 13:13:22 +03:00
/* btrfs fakes device numbers, but there is still /dev/mapper name
* placed in mountinfo , so try to detect proper major : minor via this */
if ( * maj = = 0 & & ( devmapper = strstr ( line , " /dev/mapper/ " ) ) ) {
if ( ! ( dmt = dm_task_create ( DM_DEVICE_INFO ) ) ) {
log_error ( " Mount info task creation failed. " ) ;
return 0 ;
}
devmapper + = 12 ; /* skip fixed prefix */
2018-06-21 11:20:09 +03:00
for ( i = 0 ; devmapper [ i ] & & devmapper [ i ] ! = ' ' & & i < sizeof ( root ) - 1 ; + + i )
2018-03-20 13:13:22 +03:00
root [ i ] = devmapper [ i ] ;
root [ i ] = 0 ;
_unmangle_mountinfo_string ( root , buf ) ;
buf [ DM_NAME_LEN ] = 0 ; /* cut away */
if ( dm_task_set_name ( dmt , buf ) & &
dm_task_no_open_count ( dmt ) & &
dm_task_run ( dmt ) & &
dm_task_get_info ( dmt , & info ) ) {
log_debug ( " Replacing mountinfo device (%u:%u) with matching DM device %s (%u:%u). " ,
* maj , * min , buf , info . major , info . minor ) ;
* maj = info . major ;
* min = info . minor ;
}
dm_task_destroy ( dmt ) ;
}
2013-05-16 13:34:26 +04:00
_unmangle_mountinfo_string ( target , buf ) ;
return 1 ;
}
/*
* Function to operate on individal mountinfo line ,
* minor , major and mount target are parsed and unmangled
*/
int dm_mountinfo_read ( dm_mountinfo_line_callback_fn read_fn , void * cb_data )
{
FILE * minfo ;
char buffer [ 2 * PATH_MAX ] ;
char target [ PATH_MAX ] ;
unsigned maj , min ;
int r = 1 ;
if ( ! ( minfo = fopen ( _mountinfo , " r " ) ) ) {
if ( errno ! = ENOENT )
log_sys_error ( " fopen " , _mountinfo ) ;
else
log_sys_debug ( " fopen " , _mountinfo ) ;
return 0 ;
}
while ( ! feof ( minfo ) & & fgets ( buffer , sizeof ( buffer ) , minfo ) )
if ( ! _mountinfo_parse_line ( buffer , & maj , & min , target ) | |
! read_fn ( buffer , maj , min , target , cb_data ) ) {
stack ;
r = 0 ;
break ;
}
if ( fclose ( minfo ) )
log_sys_error ( " fclose " , _mountinfo ) ;
return r ;
}
2012-01-11 16:34:44 +04:00
static int _sysfs_get_dm_name ( uint32_t major , uint32_t minor , char * buf , size_t buf_size )
{
2012-02-13 18:39:24 +04:00
char * sysfs_path , * temp_buf = NULL ;
2012-01-26 01:47:18 +04:00
FILE * fp = NULL ;
int r = 0 ;
2012-02-13 14:49:28 +04:00
size_t len ;
2012-01-11 16:34:44 +04:00
if ( ! ( sysfs_path = dm_malloc ( PATH_MAX ) ) | |
! ( temp_buf = dm_malloc ( PATH_MAX ) ) ) {
log_error ( " _sysfs_get_dm_name: failed to allocate temporary buffers " ) ;
2012-02-13 14:49:28 +04:00
goto bad ;
2012-01-11 16:34:44 +04:00
}
if ( dm_snprintf ( sysfs_path , PATH_MAX , " %sdev/block/% " PRIu32 " :% " PRIu32
" /dm/name " , _sysfs_dir , major , minor ) < 0 ) {
log_error ( " _sysfs_get_dm_name: dm_snprintf failed " ) ;
2012-02-13 14:49:28 +04:00
goto bad ;
2012-01-11 16:34:44 +04:00
}
if ( ! ( fp = fopen ( sysfs_path , " r " ) ) ) {
if ( errno ! = ENOENT )
log_sys_error ( " fopen " , sysfs_path ) ;
else
log_sys_debug ( " fopen " , sysfs_path ) ;
2012-02-13 14:49:28 +04:00
goto bad ;
2012-01-11 16:34:44 +04:00
}
if ( ! fgets ( temp_buf , PATH_MAX , fp ) ) {
log_sys_error ( " fgets " , sysfs_path ) ;
2012-02-13 14:49:28 +04:00
goto bad ;
2012-01-11 16:34:44 +04:00
}
2012-02-13 14:49:28 +04:00
len = strlen ( temp_buf ) ;
if ( len > buf_size ) {
2012-01-11 16:34:44 +04:00
log_error ( " _sysfs_get_dm_name: supplied buffer too small " ) ;
2012-02-13 14:49:28 +04:00
goto bad ;
2012-01-11 16:34:44 +04:00
}
2012-02-13 14:49:28 +04:00
temp_buf [ len ? len - 1 : 0 ] = ' \0 ' ; /* \n */
strcpy ( buf , temp_buf ) ;
2012-01-26 01:47:18 +04:00
r = 1 ;
2012-02-13 14:49:28 +04:00
bad :
2012-01-26 01:47:18 +04:00
if ( fp & & fclose ( fp ) )
log_sys_error ( " fclose " , sysfs_path ) ;
2012-01-11 16:34:44 +04:00
dm_free ( temp_buf ) ;
2012-02-13 18:39:24 +04:00
dm_free ( sysfs_path ) ;
2012-01-26 01:47:18 +04:00
return r ;
2012-01-11 16:34:44 +04:00
}
2019-07-06 02:21:39 +03:00
static int _sysfs_get_dev_major_minor ( const char * path , uint32_t major , uint32_t minor )
{
FILE * fp ;
uint32_t ma , mi ;
int r ;
if ( ! ( fp = fopen ( path , " r " ) ) )
return 0 ;
r = ( fscanf ( fp , " % " PRIu32 " :% " PRIu32 , & ma , & mi ) = = 2 ) & &
( ma = = major ) & & ( mi = = minor ) ;
// log_debug("Checking %s %u:%u -> %d", path, ma, mi, r);
if ( fclose ( fp ) )
log_sys_error ( " fclose " , path ) ;
return r ;
}
static int _sysfs_find_kernel_name ( uint32_t major , uint32_t minor , char * buf , size_t buf_size )
{
const char * name , * name_dev ;
char path [ PATH_MAX ] ;
struct dirent * dirent , * dirent_dev ;
DIR * d , * d_dev ;
struct stat st ;
int r = 0 , sz ;
if ( ! * _sysfs_dir | |
dm_snprintf ( path , sizeof ( path ) , " %s/block/ " , _sysfs_dir ) < 0 ) {
log_error ( " Failed to build sysfs_path. " ) ;
return 0 ;
}
if ( ! ( d = opendir ( path ) ) ) {
log_sys_error ( " opendir " , path ) ;
return 0 ;
}
while ( ! r & & ( dirent = readdir ( d ) ) ) {
name = dirent - > d_name ;
if ( ! strcmp ( name , " . " ) | | ! strcmp ( name , " .. " ) )
continue ;
if ( ( sz = dm_snprintf ( path , sizeof ( path ) , " %sblock/%s/dev " ,
_sysfs_dir , name ) ) = = - 1 ) {
log_warn ( " Couldn't create path for %s. " , name ) ;
continue ;
}
if ( _sysfs_get_dev_major_minor ( path , major , minor ) ) {
r = dm_strncpy ( buf , name , buf_size ) ;
break ; /* found */
}
path [ sz - 4 ] = 0 ; /* strip /dev from end of path string */
if ( stat ( path , & st ) )
continue ;
if ( S_ISDIR ( st . st_mode ) ) {
/* let's assume there is no tree-complex device in past systems */
if ( ! ( d_dev = opendir ( path ) ) ) {
log_sys_debug ( " opendir " , path ) ;
continue ;
}
while ( ( dirent_dev = readdir ( d_dev ) ) ) {
name_dev = dirent_dev - > d_name ;
/* skip known ignorable paths */
if ( ! strcmp ( name_dev , " . " ) | | ! strcmp ( name_dev , " .. " ) | |
! strcmp ( name_dev , " bdi " ) | |
! strcmp ( name_dev , " dev " ) | |
! strcmp ( name_dev , " device " ) | |
! strcmp ( name_dev , " holders " ) | |
! strcmp ( name_dev , " integrity " ) | |
! strcmp ( name_dev , " loop " ) | |
! strcmp ( name_dev , " queueu " ) | |
! strcmp ( name_dev , " md " ) | |
! strcmp ( name_dev , " mq " ) | |
! strcmp ( name_dev , " power " ) | |
! strcmp ( name_dev , " removable " ) | |
! strcmp ( name_dev , " slave " ) | |
! strcmp ( name_dev , " slaves " ) | |
! strcmp ( name_dev , " subsystem " ) | |
! strcmp ( name_dev , " trace " ) | |
! strcmp ( name_dev , " uevent " ) )
continue ;
if ( dm_snprintf ( path , sizeof ( path ) , " %sblock/%s/%s/dev " ,
_sysfs_dir , name , name_dev ) = = - 1 ) {
log_warn ( " Couldn't create path for %s/%s. " , name , name_dev ) ;
continue ;
}
if ( _sysfs_get_dev_major_minor ( path , major , minor ) ) {
r = dm_strncpy ( buf , name_dev , buf_size ) ;
break ; /* found */
}
}
if ( closedir ( d_dev ) )
log_sys_debug ( " closedir " , name ) ;
}
}
if ( closedir ( d ) )
log_sys_debug ( " closedir " , path ) ;
return r ;
}
2012-01-11 16:34:44 +04:00
static int _sysfs_get_kernel_name ( uint32_t major , uint32_t minor , char * buf , size_t buf_size )
{
2012-02-13 18:39:24 +04:00
char * name , * sysfs_path , * temp_buf = NULL ;
2012-01-11 16:34:44 +04:00
ssize_t size ;
2012-02-13 14:49:28 +04:00
size_t len ;
int r = 0 ;
2012-01-11 16:34:44 +04:00
if ( ! ( sysfs_path = dm_malloc ( PATH_MAX ) ) | |
! ( temp_buf = dm_malloc ( PATH_MAX ) ) ) {
log_error ( " _sysfs_get_kernel_name: failed to allocate temporary buffers " ) ;
2012-02-13 14:49:28 +04:00
goto bad ;
2012-01-11 16:34:44 +04:00
}
if ( dm_snprintf ( sysfs_path , PATH_MAX , " %sdev/block/% " PRIu32 " :% " PRIu32 ,
_sysfs_dir , major , minor ) < 0 ) {
log_error ( " _sysfs_get_kernel_name: dm_snprintf failed " ) ;
2012-02-13 14:49:28 +04:00
goto bad ;
2012-01-11 16:34:44 +04:00
}
2012-02-08 15:05:04 +04:00
if ( ( size = readlink ( sysfs_path , temp_buf , PATH_MAX - 1 ) ) < 0 ) {
2012-01-11 16:34:44 +04:00
if ( errno ! = ENOENT )
log_sys_error ( " readlink " , sysfs_path ) ;
2019-07-06 02:21:39 +03:00
else {
2012-01-11 16:34:44 +04:00
log_sys_debug ( " readlink " , sysfs_path ) ;
2019-08-28 11:45:04 +03:00
r = _sysfs_find_kernel_name ( major , minor , buf , buf_size ) ;
goto out ;
2019-07-06 02:21:39 +03:00
}
2012-02-13 14:49:28 +04:00
goto bad ;
2012-01-11 16:34:44 +04:00
}
temp_buf [ size ] = ' \0 ' ;
if ( ! ( name = strrchr ( temp_buf , ' / ' ) ) ) {
log_error ( " Could not locate device kernel name in sysfs path %s " , temp_buf ) ;
2012-02-13 14:49:28 +04:00
goto bad ;
2012-01-11 16:34:44 +04:00
}
name + = 1 ;
2012-02-13 14:49:28 +04:00
len = size - ( name - temp_buf ) + 1 ;
2012-01-11 16:34:44 +04:00
2012-02-13 14:49:28 +04:00
if ( len > buf_size ) {
2012-01-11 16:34:44 +04:00
log_error ( " _sysfs_get_kernel_name: output buffer too small " ) ;
2012-02-13 14:49:28 +04:00
goto bad ;
2012-01-11 16:34:44 +04:00
}
2012-02-13 14:49:28 +04:00
strcpy ( buf , name ) ;
r = 1 ;
bad :
2019-08-28 11:45:04 +03:00
out :
2012-01-11 16:34:44 +04:00
dm_free ( temp_buf ) ;
2012-02-13 18:39:24 +04:00
dm_free ( sysfs_path ) ;
2012-01-11 16:34:44 +04:00
2012-02-13 14:49:28 +04:00
return r ;
2012-01-11 16:34:44 +04:00
}
int dm_device_get_name ( uint32_t major , uint32_t minor , int prefer_kernel_name ,
char * buf , size_t buf_size )
{
if ( ! * _sysfs_dir )
return 0 ;
/*
* device - mapper devices and prefer_kernel_name = 0
* get dm name by reading / sys / dev / block / major : minor / dm / name ,
* fallback to _sysfs_get_kernel_name if not successful
*/
if ( dm_is_dm_major ( major ) & & ! prefer_kernel_name ) {
if ( _sysfs_get_dm_name ( major , minor , buf , buf_size ) )
return 1 ;
else
stack ;
}
/*
* non - device - mapper devices or prefer_kernel_name = 1
* get kernel name using readlink / sys / dev / block / major : minor - > . . . / dm - X
*/
return _sysfs_get_kernel_name ( major , minor , buf , buf_size ) ;
}
2011-09-22 21:23:35 +04:00
int dm_device_has_holders ( uint32_t major , uint32_t minor )
{
char sysfs_path [ PATH_MAX ] ;
struct stat st ;
if ( ! * _sysfs_dir )
return 0 ;
if ( dm_snprintf ( sysfs_path , PATH_MAX , " %sdev/block/% " PRIu32
" :% " PRIu32 " /holders " , _sysfs_dir , major , minor ) < 0 ) {
2017-12-07 12:42:30 +03:00
log_warn ( " WARNING: sysfs_path dm_snprintf failed. " ) ;
2011-09-22 21:23:35 +04:00
return 0 ;
}
if ( stat ( sysfs_path , & st ) ) {
2013-10-17 13:12:02 +04:00
if ( errno ! = ENOENT )
2017-12-07 12:42:30 +03:00
log_sys_debug ( " stat " , sysfs_path ) ;
2011-09-22 21:23:35 +04:00
return 0 ;
}
return ! dm_is_empty_dir ( sysfs_path ) ;
}
static int _mounted_fs_on_device ( const char * kernel_dev_name )
{
char sysfs_path [ PATH_MAX ] ;
struct dirent * dirent ;
DIR * d ;
struct stat st ;
int r = 0 ;
if ( dm_snprintf ( sysfs_path , PATH_MAX , " %sfs " , _sysfs_dir ) < 0 ) {
2017-12-07 12:42:30 +03:00
log_warn ( " WARNING: sysfs_path dm_snprintf failed. " ) ;
2011-09-22 21:23:35 +04:00
return 0 ;
}
if ( ! ( d = opendir ( sysfs_path ) ) ) {
if ( errno ! = ENOENT )
2017-12-07 12:42:30 +03:00
log_sys_debug ( " opendir " , sysfs_path ) ;
2011-09-22 21:23:35 +04:00
return 0 ;
}
while ( ( dirent = readdir ( d ) ) ) {
if ( ! strcmp ( dirent - > d_name , " . " ) | | ! strcmp ( dirent - > d_name , " .. " ) )
continue ;
if ( dm_snprintf ( sysfs_path , PATH_MAX , " %sfs/%s/%s " ,
_sysfs_dir , dirent - > d_name , kernel_dev_name ) < 0 ) {
2017-12-07 12:42:30 +03:00
log_warn ( " WARNING: sysfs_path dm_snprintf failed. " ) ;
2011-09-22 21:23:35 +04:00
break ;
}
if ( ! stat ( sysfs_path , & st ) ) {
/* found! */
r = 1 ;
break ;
}
else if ( errno ! = ENOENT ) {
2017-12-07 12:42:30 +03:00
log_sys_debug ( " stat " , sysfs_path ) ;
2011-09-22 21:23:35 +04:00
break ;
}
}
if ( closedir ( d ) )
2017-12-07 12:42:30 +03:00
log_sys_debug ( " closedir " , kernel_dev_name ) ;
2011-09-22 21:23:35 +04:00
return r ;
}
2013-05-16 13:55:51 +04:00
struct mountinfo_s {
unsigned maj ;
unsigned min ;
int mounted ;
} ;
static int _device_has_mounted_fs ( char * buffer , unsigned major , unsigned minor ,
char * target , void * cb_data )
{
struct mountinfo_s * data = cb_data ;
char kernel_dev_name [ PATH_MAX ] ;
if ( ( major = = data - > maj ) & & ( minor = = data - > min ) ) {
2014-05-07 13:44:33 +04:00
if ( ! dm_device_get_name ( major , minor , 1 , kernel_dev_name ,
sizeof ( kernel_dev_name ) ) ) {
2013-05-16 13:55:51 +04:00
stack ;
* kernel_dev_name = ' \0 ' ;
}
log_verbose ( " Device %s (%u:%u) appears to be mounted on %s. " ,
kernel_dev_name , major , minor , target ) ;
data - > mounted = 1 ;
}
return 1 ;
}
2011-09-22 21:23:35 +04:00
int dm_device_has_mounted_fs ( uint32_t major , uint32_t minor )
{
2012-01-11 16:34:44 +04:00
char kernel_dev_name [ PATH_MAX ] ;
2013-05-16 13:55:51 +04:00
struct mountinfo_s data = {
. maj = major ,
. min = minor ,
} ;
2011-09-22 21:23:35 +04:00
2013-05-16 13:55:51 +04:00
if ( ! dm_mountinfo_read ( _device_has_mounted_fs , & data ) )
stack ;
if ( data . mounted )
return 1 ;
/*
* TODO : Verify dm_mountinfo_read ( ) is superset
* and remove sysfs check ( namespaces )
*/
2011-09-22 21:23:35 +04:00
/* Get kernel device name first */
2012-01-11 16:34:44 +04:00
if ( ! dm_device_get_name ( major , minor , 1 , kernel_dev_name , PATH_MAX ) )
2011-09-22 21:23:35 +04:00
return 0 ;
/* Check /sys/fs/<fs_name>/<kernel_dev_name> presence */
return _mounted_fs_on_device ( kernel_dev_name ) ;
}
2005-10-17 02:57:20 +04:00
int dm_mknodes ( const char * name )
{
struct dm_task * dmt ;
int r = 0 ;
if ( ! ( dmt = dm_task_create ( DM_DEVICE_MKNODES ) ) )
2017-12-04 15:31:40 +03:00
return_0 ;
2005-10-17 02:57:20 +04:00
if ( name & & ! dm_task_set_name ( dmt , name ) )
goto out ;
if ( ! dm_task_no_open_count ( dmt ) )
goto out ;
r = dm_task_run ( dmt ) ;
out :
dm_task_destroy ( dmt ) ;
return r ;
}
2005-10-17 22:05:39 +04:00
int dm_driver_version ( char * version , size_t size )
{
struct dm_task * dmt ;
int r = 0 ;
if ( ! ( dmt = dm_task_create ( DM_DEVICE_VERSION ) ) )
2017-12-04 15:31:40 +03:00
return_0 ;
2005-10-17 22:05:39 +04:00
if ( ! dm_task_run ( dmt ) )
log_error ( " Failed to get driver version " ) ;
if ( ! dm_task_get_driver_version ( dmt , version , size ) )
goto out ;
r = 1 ;
out :
dm_task_destroy ( dmt ) ;
return r ;
}
2006-02-21 02:55:58 +03:00
2012-11-29 17:03:48 +04:00
static void _set_cookie_flags ( struct dm_task * dmt , uint16_t flags )
{
if ( ! dm_cookie_supported ( ) )
return ;
if ( _udev_disabled ) {
/*
* If udev is disabled , hardcode this functionality :
* - we want libdm to create the nodes
* - we don ' t want the / dev / mapper and any subsystem
* related content to be created by udev if udev
* rules are installed
*/
flags & = ~ DM_UDEV_DISABLE_LIBRARY_FALLBACK ;
flags | = DM_UDEV_DISABLE_DM_RULES_FLAG | DM_UDEV_DISABLE_SUBSYSTEM_RULES_FLAG ;
}
dmt - > event_nr = flags < < DM_UDEV_FLAGS_SHIFT ;
}
2009-07-31 19:53:11 +04:00
# ifndef UDEV_SYNC_SUPPORT
void dm_udev_set_sync_support ( int sync_with_udev )
{
}
int dm_udev_get_sync_support ( void )
{
return 0 ;
}
2010-01-11 18:36:24 +03:00
void dm_udev_set_checking ( int checking )
{
}
int dm_udev_get_checking ( void )
{
return 0 ;
}
2009-10-22 16:55:47 +04:00
int dm_task_set_cookie ( struct dm_task * dmt , uint32_t * cookie , uint16_t flags )
2009-07-31 19:53:11 +04:00
{
2012-11-29 17:03:48 +04:00
_set_cookie_flags ( dmt , flags ) ;
2009-07-31 19:53:11 +04:00
* cookie = 0 ;
2012-10-23 13:40:53 +04:00
dmt - > cookie_set = 1 ;
2009-07-31 19:53:11 +04:00
return 1 ;
}
2009-07-31 21:51:45 +04:00
int dm_udev_complete ( uint32_t cookie )
2009-07-31 19:53:11 +04:00
{
return 1 ;
}
int dm_udev_wait ( uint32_t cookie )
{
2011-03-02 03:29:57 +03:00
update_devs ( ) ;
2009-07-31 19:53:11 +04:00
return 1 ;
}
2016-04-28 02:54:27 +03:00
int dm_udev_wait_immediate ( uint32_t cookie , int * ready )
{
update_devs ( ) ;
* ready = 1 ;
return 1 ;
}
2009-07-31 19:53:11 +04:00
# else /* UDEV_SYNC_SUPPORT */
2010-08-03 17:06:35 +04:00
static int _check_semaphore_is_supported ( void )
2010-08-03 11:56:03 +04:00
{
int maxid ;
union semun arg ;
struct seminfo seminfo ;
arg . __buf = & seminfo ;
maxid = semctl ( 0 , 0 , SEM_INFO , arg ) ;
if ( maxid < 0 ) {
log_warn ( " Kernel not configured for semaphores (System V IPC). "
" Not using udev synchronisation code. " ) ;
return 0 ;
}
return 1 ;
}
2009-09-11 19:56:06 +04:00
static int _check_udev_is_running ( void )
{
struct udev * udev ;
struct udev_queue * udev_queue ;
int r ;
if ( ! ( udev = udev_new ( ) ) )
2009-09-15 15:41:38 +04:00
goto_bad ;
2009-09-11 19:56:06 +04:00
if ( ! ( udev_queue = udev_queue_new ( udev ) ) ) {
udev_unref ( udev ) ;
2009-09-15 15:41:38 +04:00
goto_bad ;
2009-09-11 19:56:06 +04:00
}
2009-09-15 15:41:38 +04:00
if ( ! ( r = udev_queue_get_udev_is_active ( udev_queue ) ) )
2013-01-08 02:30:29 +04:00
log_debug_activation ( " Udev is not running. "
" Not using udev synchronisation code. " ) ;
2009-09-11 19:56:06 +04:00
udev_queue_unref ( udev_queue ) ;
udev_unref ( udev ) ;
return r ;
2009-09-15 15:41:38 +04:00
bad :
log_error ( " Could not get udev state. Assuming udev is not running. " ) ;
2009-09-11 19:56:06 +04:00
return 0 ;
}
2010-08-03 17:06:35 +04:00
static void _check_udev_sync_requirements_once ( void )
2009-07-31 19:53:11 +04:00
{
2010-08-03 11:56:03 +04:00
if ( _semaphore_supported < 0 )
_semaphore_supported = _check_semaphore_is_supported ( ) ;
2012-11-29 18:50:52 +04:00
if ( _udev_running < 0 ) {
2009-09-11 19:56:06 +04:00
_udev_running = _check_udev_is_running ( ) ;
2012-11-29 18:50:52 +04:00
if ( _udev_disabled & & _udev_running )
log_warn ( " Udev is running and DM_DISABLE_UDEV environment variable is set. "
" Bypassing udev, device-mapper library will manage device "
" nodes in device directory. " ) ;
}
2010-08-03 11:56:03 +04:00
}
2009-09-11 19:56:06 +04:00
2010-08-03 11:56:03 +04:00
void dm_udev_set_sync_support ( int sync_with_udev )
{
_check_udev_sync_requirements_once ( ) ;
2009-07-31 19:53:11 +04:00
_sync_with_udev = sync_with_udev ;
}
int dm_udev_get_sync_support ( void )
{
2010-08-03 11:56:03 +04:00
_check_udev_sync_requirements_once ( ) ;
2009-09-11 19:56:06 +04:00
2012-11-29 18:50:52 +04:00
return ! _udev_disabled & & _semaphore_supported & &
dm_cookie_supported ( ) & & _udev_running & & _sync_with_udev ;
2009-07-31 19:53:11 +04:00
}
2010-01-11 18:36:24 +03:00
void dm_udev_set_checking ( int checking )
{
if ( ( _udev_checking = checking ) )
2013-01-08 02:30:29 +04:00
log_debug_activation ( " DM udev checking enabled " ) ;
2010-01-11 18:36:24 +03:00
else
2013-01-08 02:30:29 +04:00
log_debug_activation ( " DM udev checking disabled " ) ;
2010-01-11 18:36:24 +03:00
}
int dm_udev_get_checking ( void )
{
return _udev_checking ;
}
2009-07-31 19:53:11 +04:00
static int _get_cookie_sem ( uint32_t cookie , int * semid )
{
2009-08-06 19:04:30 +04:00
if ( cookie > > 16 ! = DM_COOKIE_MAGIC ) {
2009-08-03 15:01:26 +04:00
log_error ( " Could not continue to access notification "
" semaphore identified by cookie value % "
2009-08-03 22:01:45 +04:00
PRIu32 " (0x%x). Incorrect cookie prefix. " ,
cookie , cookie ) ;
2009-08-03 15:01:26 +04:00
return 0 ;
}
2009-07-31 19:53:11 +04:00
if ( ( * semid = semget ( ( key_t ) cookie , 1 , 0 ) ) > = 0 )
return 1 ;
switch ( errno ) {
case ENOENT :
log_error ( " Could not find notification "
" semaphore identified by cookie "
" value % " PRIu32 " (0x%x) " ,
cookie , cookie ) ;
break ;
case EACCES :
log_error ( " No permission to access "
" notificaton semaphore identified "
" by cookie value % " PRIu32 " (0x%x) " ,
cookie , cookie ) ;
break ;
default :
log_error ( " Failed to access notification "
" semaphore identified by cookie "
2009-08-03 15:01:26 +04:00
" value % " PRIu32 " (0x%x): %s " ,
cookie , cookie , strerror ( errno ) ) ;
2009-07-31 19:53:11 +04:00
break ;
}
return 0 ;
}
2009-08-05 23:50:08 +04:00
static int _udev_notify_sem_inc ( uint32_t cookie , int semid )
2009-07-31 19:53:11 +04:00
{
struct sembuf sb = { 0 , 1 , 0 } ;
2011-07-08 19:34:47 +04:00
int val ;
2009-07-31 19:53:11 +04:00
2009-08-03 15:01:26 +04:00
if ( semop ( semid , & sb , 1 ) < 0 ) {
2009-08-05 23:50:08 +04:00
log_error ( " semid %d: semop failed for cookie 0x% " PRIx32 " : %s " ,
semid , cookie , strerror ( errno ) ) ;
2009-08-03 15:01:26 +04:00
return 0 ;
}
2011-07-08 19:34:47 +04:00
if ( ( val = semctl ( semid , 0 , GETVAL ) ) < 0 ) {
log_error ( " semid %d: sem_ctl GETVAL failed for "
" cookie 0x% " PRIx32 " : %s " ,
semid , cookie , strerror ( errno ) ) ;
return 0 ;
}
2013-01-08 02:30:29 +04:00
log_debug_activation ( " Udev cookie 0x% " PRIx32 " (semid %d) incremented to %d " ,
2011-07-08 19:34:47 +04:00
cookie , semid , val ) ;
2009-08-05 23:50:08 +04:00
2009-08-03 15:01:26 +04:00
return 1 ;
2009-07-31 19:53:11 +04:00
}
2009-08-05 23:50:08 +04:00
static int _udev_notify_sem_dec ( uint32_t cookie , int semid )
2009-07-31 19:53:11 +04:00
{
2009-08-03 15:01:26 +04:00
struct sembuf sb = { 0 , - 1 , IPC_NOWAIT } ;
2011-07-08 19:34:47 +04:00
int val ;
if ( ( val = semctl ( semid , 0 , GETVAL ) ) < 0 ) {
log_error ( " semid %d: sem_ctl GETVAL failed for "
" cookie 0x% " PRIx32 " : %s " ,
semid , cookie , strerror ( errno ) ) ;
return 0 ;
}
2009-08-03 15:01:26 +04:00
if ( semop ( semid , & sb , 1 ) < 0 ) {
switch ( errno ) {
case EAGAIN :
2009-08-05 23:50:08 +04:00
log_error ( " semid %d: semop failed for cookie "
" 0x% " PRIx32 " : "
2009-08-03 15:01:26 +04:00
" incorrect semaphore state " ,
2009-08-05 23:50:08 +04:00
semid , cookie ) ;
2009-08-03 15:01:26 +04:00
break ;
default :
2009-08-05 23:50:08 +04:00
log_error ( " semid %d: semop failed for cookie "
" 0x% " PRIx32 " : %s " ,
semid , cookie , strerror ( errno ) ) ;
2009-08-03 15:01:26 +04:00
break ;
}
return 0 ;
}
2009-07-31 19:53:11 +04:00
2013-01-08 02:30:29 +04:00
log_debug_activation ( " Udev cookie 0x% " PRIx32 " (semid %d) decremented to %d " ,
cookie , semid , val - 1 ) ;
2009-08-05 23:50:08 +04:00
2009-08-03 15:01:26 +04:00
return 1 ;
2009-07-31 19:53:11 +04:00
}
2009-08-05 23:50:08 +04:00
static int _udev_notify_sem_destroy ( uint32_t cookie , int semid )
2009-07-31 19:53:11 +04:00
{
if ( semctl ( semid , 0 , IPC_RMID , 0 ) < 0 ) {
log_error ( " Could not cleanup notification semaphore "
2009-08-03 15:01:26 +04:00
" identified by cookie value % " PRIu32 " (0x%x): %s " ,
cookie , cookie , strerror ( errno ) ) ;
2009-07-31 19:53:11 +04:00
return 0 ;
}
2013-01-08 02:30:29 +04:00
log_debug_activation ( " Udev cookie 0x% " PRIx32 " (semid %d) destroyed " , cookie ,
semid ) ;
2009-08-05 23:50:08 +04:00
2009-07-31 19:53:11 +04:00
return 1 ;
}
static int _udev_notify_sem_create ( uint32_t * cookie , int * semid )
{
int fd ;
int gen_semid ;
2011-07-08 19:34:47 +04:00
int val ;
2009-07-31 19:53:11 +04:00
uint16_t base_cookie ;
uint32_t gen_cookie ;
2010-05-27 19:02:56 +04:00
union semun sem_arg ;
2009-07-31 19:53:11 +04:00
if ( ( fd = open ( " /dev/urandom " , O_RDONLY ) ) < 0 ) {
log_error ( " Failed to open /dev/urandom "
" to create random cookie value " ) ;
* cookie = 0 ;
return 0 ;
}
/* Generate random cookie value. Be sure it is unique and non-zero. */
do {
/* FIXME Handle non-error returns from read(). Move _io() into libdm? */
if ( read ( fd , & base_cookie , sizeof ( base_cookie ) ) ! = sizeof ( base_cookie ) ) {
log_error ( " Failed to initialize notification cookie " ) ;
goto bad ;
}
2009-08-06 19:04:30 +04:00
gen_cookie = DM_COOKIE_MAGIC < < 16 | base_cookie ;
2009-07-31 19:53:11 +04:00
if ( base_cookie & & ( gen_semid = semget ( ( key_t ) gen_cookie ,
1 , 0600 | IPC_CREAT | IPC_EXCL ) ) < 0 ) {
switch ( errno ) {
case EEXIST :
/* if the semaphore key exists, we
* simply generate another random one */
base_cookie = 0 ;
break ;
case ENOMEM :
log_error ( " Not enough memory to create "
" notification semaphore " ) ;
goto bad ;
case ENOSPC :
log_error ( " Limit for the maximum number "
2009-08-03 15:01:26 +04:00
" of semaphores reached. You can "
" check and set the limits in "
" /proc/sys/kernel/sem. " ) ;
2009-07-31 19:53:11 +04:00
goto bad ;
default :
2009-08-03 15:01:26 +04:00
log_error ( " Failed to create notification "
" semaphore: %s " , strerror ( errno ) ) ;
2009-07-31 19:53:11 +04:00
goto bad ;
}
}
} while ( ! base_cookie ) ;
2013-01-08 02:30:29 +04:00
log_debug_activation ( " Udev cookie 0x% " PRIx32 " (semid %d) created " ,
gen_cookie , gen_semid ) ;
2009-08-05 23:50:08 +04:00
2010-05-27 19:02:56 +04:00
sem_arg . val = 1 ;
if ( semctl ( gen_semid , 0 , SETVAL , sem_arg ) < 0 ) {
2009-08-03 15:01:26 +04:00
log_error ( " semid %d: semctl failed: %s " , gen_semid , strerror ( errno ) ) ;
2009-07-31 19:53:11 +04:00
/* We have to destroy just created semaphore
* so it won ' t stay in the system . */
2009-08-05 23:50:08 +04:00
( void ) _udev_notify_sem_destroy ( gen_cookie , gen_semid ) ;
2009-07-31 19:53:11 +04:00
goto bad ;
}
2011-07-08 19:34:47 +04:00
if ( ( val = semctl ( gen_semid , 0 , GETVAL ) ) < 0 ) {
log_error ( " semid %d: sem_ctl GETVAL failed for "
" cookie 0x% " PRIx32 " : %s " ,
gen_semid , gen_cookie , strerror ( errno ) ) ;
2012-02-08 15:07:17 +04:00
goto bad ;
2011-07-08 19:34:47 +04:00
}
2013-01-08 02:30:29 +04:00
log_debug_activation ( " Udev cookie 0x% " PRIx32 " (semid %d) incremented to %d " ,
gen_cookie , gen_semid , val ) ;
2009-08-05 23:50:08 +04:00
2009-07-31 19:53:11 +04:00
if ( close ( fd ) )
stack ;
* semid = gen_semid ;
* cookie = gen_cookie ;
return 1 ;
bad :
if ( close ( fd ) )
stack ;
* cookie = 0 ;
return 0 ;
}
2010-02-15 19:21:33 +03:00
int dm_udev_create_cookie ( uint32_t * cookie )
{
int semid ;
2010-03-23 17:43:18 +03:00
if ( ! dm_udev_get_sync_support ( ) ) {
* cookie = 0 ;
2010-02-15 19:21:33 +03:00
return 1 ;
2010-03-23 17:43:18 +03:00
}
2010-02-15 19:21:33 +03:00
return _udev_notify_sem_create ( cookie , & semid ) ;
}
2011-07-05 20:17:14 +04:00
static const char * _task_type_disp ( int type )
{
switch ( type ) {
case DM_DEVICE_CREATE :
return " CREATE " ;
case DM_DEVICE_RELOAD :
return " RELOAD " ;
case DM_DEVICE_REMOVE :
return " REMOVE " ;
case DM_DEVICE_REMOVE_ALL :
return " REMOVE_ALL " ;
case DM_DEVICE_SUSPEND :
return " SUSPEND " ;
case DM_DEVICE_RESUME :
return " RESUME " ;
case DM_DEVICE_INFO :
return " INFO " ;
case DM_DEVICE_DEPS :
return " DEPS " ;
case DM_DEVICE_RENAME :
return " RENAME " ;
case DM_DEVICE_VERSION :
return " VERSION " ;
case DM_DEVICE_STATUS :
return " STATUS " ;
case DM_DEVICE_TABLE :
return " TABLE " ;
case DM_DEVICE_WAITEVENT :
return " WAITEVENT " ;
case DM_DEVICE_LIST :
return " LIST " ;
case DM_DEVICE_CLEAR :
return " CLEAR " ;
case DM_DEVICE_MKNODES :
return " MKNODES " ;
case DM_DEVICE_LIST_VERSIONS :
return " LIST_VERSIONS " ;
case DM_DEVICE_TARGET_MSG :
return " TARGET_MSG " ;
case DM_DEVICE_SET_GEOMETRY :
return " SET_GEOMETRY " ;
}
return " unknown " ;
}
2009-10-22 16:55:47 +04:00
int dm_task_set_cookie ( struct dm_task * dmt , uint32_t * cookie , uint16_t flags )
2009-07-31 19:53:11 +04:00
{
int semid ;
2012-11-29 17:03:48 +04:00
_set_cookie_flags ( dmt , flags ) ;
2009-11-13 15:43:21 +03:00
2009-09-11 20:11:25 +04:00
if ( ! dm_udev_get_sync_support ( ) ) {
2009-11-13 15:43:21 +03:00
* cookie = 0 ;
2012-10-23 13:40:53 +04:00
dmt - > cookie_set = 1 ;
2009-07-31 19:53:11 +04:00
return 1 ;
}
if ( * cookie ) {
if ( ! _get_cookie_sem ( * cookie , & semid ) )
goto_bad ;
} else if ( ! _udev_notify_sem_create ( cookie , & semid ) )
goto_bad ;
2009-08-05 23:50:08 +04:00
if ( ! _udev_notify_sem_inc ( * cookie , semid ) ) {
2009-07-31 19:53:11 +04:00
log_error ( " Could not set notification semaphore "
" identified by cookie value % " PRIu32 " (0x%x) " ,
* cookie , * cookie ) ;
goto bad ;
}
2009-11-13 15:43:21 +03:00
dmt - > event_nr | = ~ DM_UDEV_FLAGS_MASK & * cookie ;
2009-08-03 22:01:45 +04:00
dmt - > cookie_set = 1 ;
2009-08-05 23:50:08 +04:00
2013-01-08 02:30:29 +04:00
log_debug_activation ( " Udev cookie 0x% " PRIx32 " (semid %d) assigned to "
2014-05-27 16:44:11 +04:00
" %s task(%d) with flags%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s (0x% " PRIx16 " ) " ,
* cookie , semid , _task_type_disp ( dmt - > type ) , dmt - > type ,
2013-01-08 02:30:29 +04:00
( flags & DM_UDEV_DISABLE_DM_RULES_FLAG ) ? " DISABLE_DM_RULES " : " " ,
( flags & DM_UDEV_DISABLE_SUBSYSTEM_RULES_FLAG ) ? " DISABLE_SUBSYSTEM_RULES " : " " ,
( flags & DM_UDEV_DISABLE_DISK_RULES_FLAG ) ? " DISABLE_DISK_RULES " : " " ,
( flags & DM_UDEV_DISABLE_OTHER_RULES_FLAG ) ? " DISABLE_OTHER_RULES " : " " ,
( flags & DM_UDEV_LOW_PRIORITY_FLAG ) ? " LOW_PRIORITY " : " " ,
( flags & DM_UDEV_DISABLE_LIBRARY_FALLBACK ) ? " DISABLE_LIBRARY_FALLBACK " : " " ,
( flags & DM_UDEV_PRIMARY_SOURCE_FLAG ) ? " PRIMARY_SOURCE " : " " ,
2014-05-27 16:44:11 +04:00
( flags & DM_SUBSYSTEM_UDEV_FLAG0 ) ? " SUBSYSTEM_0 " : " " ,
( flags & DM_SUBSYSTEM_UDEV_FLAG1 ) ? " SUBSYSTEM_1 " : " " ,
( flags & DM_SUBSYSTEM_UDEV_FLAG2 ) ? " SUBSYSTEM_2 " : " " ,
( flags & DM_SUBSYSTEM_UDEV_FLAG3 ) ? " SUBSYSTEM_3 " : " " ,
( flags & DM_SUBSYSTEM_UDEV_FLAG4 ) ? " SUBSYSTEM_4 " : " " ,
( flags & DM_SUBSYSTEM_UDEV_FLAG5 ) ? " SUBSYSTEM_5 " : " " ,
( flags & DM_SUBSYSTEM_UDEV_FLAG6 ) ? " SUBSYSTEM_6 " : " " ,
( flags & DM_SUBSYSTEM_UDEV_FLAG7 ) ? " SUBSYSTEM_7 " : " " ,
2013-01-08 02:30:29 +04:00
flags ) ;
2009-08-05 23:50:08 +04:00
2009-07-31 19:53:11 +04:00
return 1 ;
bad :
dmt - > event_nr = 0 ;
return 0 ;
}
2009-07-31 21:51:45 +04:00
int dm_udev_complete ( uint32_t cookie )
2009-07-31 19:53:11 +04:00
{
int semid ;
2009-09-11 20:11:25 +04:00
if ( ! cookie | | ! dm_udev_get_sync_support ( ) )
2009-07-31 19:53:11 +04:00
return 1 ;
if ( ! _get_cookie_sem ( cookie , & semid ) )
return_0 ;
2009-08-05 23:50:08 +04:00
if ( ! _udev_notify_sem_dec ( cookie , semid ) ) {
2009-07-31 19:53:11 +04:00
log_error ( " Could not signal waiting process using notification "
" semaphore identified by cookie value % " PRIu32 " (0x%x) " ,
cookie , cookie ) ;
return 0 ;
}
return 1 ;
}
2016-04-28 02:54:27 +03:00
/*
* If * nowait is set , return immediately leaving it set if the semaphore
* is not ready to be decremented to 0. * nowait is cleared if the wait
* succeeds .
*/
static int _udev_wait ( uint32_t cookie , int * nowait )
2009-07-31 19:53:11 +04:00
{
int semid ;
struct sembuf sb = { 0 , 0 , 0 } ;
2016-04-28 02:54:27 +03:00
int val ;
2009-07-31 19:53:11 +04:00
2009-09-11 20:11:25 +04:00
if ( ! cookie | | ! dm_udev_get_sync_support ( ) )
2009-07-31 19:53:11 +04:00
return 1 ;
if ( ! _get_cookie_sem ( cookie , & semid ) )
return_0 ;
2016-04-28 02:54:27 +03:00
/* Return immediately if the semaphore value exceeds 1? */
if ( * nowait ) {
if ( ( val = semctl ( semid , 0 , GETVAL ) ) < 0 ) {
log_error ( " semid %d: sem_ctl GETVAL failed for "
" cookie 0x% " PRIx32 " : %s " ,
semid , cookie , strerror ( errno ) ) ;
return 0 ;
}
if ( val > 1 )
return 1 ;
* nowait = 0 ;
}
2009-08-05 23:50:08 +04:00
if ( ! _udev_notify_sem_dec ( cookie , semid ) ) {
2009-07-31 19:53:11 +04:00
log_error ( " Failed to set a proper state for notification "
" semaphore identified by cookie value % " PRIu32 " (0x%x) "
" to initialize waiting for incoming notifications. " ,
cookie , cookie ) ;
2009-08-05 23:50:08 +04:00
( void ) _udev_notify_sem_destroy ( cookie , semid ) ;
2009-07-31 19:53:11 +04:00
return 0 ;
}
2013-01-08 02:30:29 +04:00
log_debug_activation ( " Udev cookie 0x% " PRIx32 " (semid %d) waiting for zero " ,
cookie , semid ) ;
2009-08-05 23:50:08 +04:00
2009-07-31 19:53:11 +04:00
repeat_wait :
if ( semop ( semid , & sb , 1 ) < 0 ) {
if ( errno = = EINTR )
goto repeat_wait ;
2009-08-06 19:04:30 +04:00
else if ( errno = = EIDRM )
return 1 ;
2009-07-31 19:53:11 +04:00
log_error ( " Could not set wait state for notification semaphore "
2009-08-03 15:01:26 +04:00
" identified by cookie value % " PRIu32 " (0x%x): %s " ,
cookie , cookie , strerror ( errno ) ) ;
2009-08-05 23:50:08 +04:00
( void ) _udev_notify_sem_destroy ( cookie , semid ) ;
2009-07-31 19:53:11 +04:00
return 0 ;
}
2009-08-05 23:50:08 +04:00
return _udev_notify_sem_destroy ( cookie , semid ) ;
2009-07-31 19:53:11 +04:00
}
2011-03-02 03:29:57 +03:00
int dm_udev_wait ( uint32_t cookie )
{
2016-04-28 02:54:27 +03:00
int nowait = 0 ;
int r = _udev_wait ( cookie , & nowait ) ;
2011-03-02 03:29:57 +03:00
update_devs ( ) ;
2011-03-02 11:40:28 +03:00
return r ;
2011-03-02 03:29:57 +03:00
}
2016-04-28 02:54:27 +03:00
int dm_udev_wait_immediate ( uint32_t cookie , int * ready )
{
int nowait = 1 ;
int r = _udev_wait ( cookie , & nowait ) ;
if ( r & & nowait ) {
* ready = 0 ;
return 1 ;
}
update_devs ( ) ;
* ready = 1 ;
return r ;
}
2009-07-31 19:53:11 +04:00
# endif /* UDEV_SYNC_SUPPORT */