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 .
2007-08-21 20:26:07 +04:00
* Copyright ( C ) 2004 - 2007 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 ,
* Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
2001-12-05 19:41:52 +03:00
*/
2008-11-03 21:59:59 +03:00
# include "dmlib.h"
2002-11-14 17:44:42 +03:00
# include "libdm-targets.h"
# include "libdm-common.h"
2004-07-01 19:14:29 +04:00
# include "kdev_t.h"
2008-11-01 05:19:19 +03:00
# include "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
# ifdef HAVE_UDEV_QUEUE_GET_UDEV_IS_ACTIVE
2009-09-11 19:57:51 +04:00
# define LIBUDEV_I_KNOW_THE_API_IS_SUBJECT_TO_CHANGE
2009-09-11 19:56:06 +04:00
# include <libudev.h>
# endif
2009-07-31 19:53:11 +04:00
# endif
2007-11-30 19:42:26 +03:00
# ifdef linux
# include <linux / fs.h>
# endif
2004-04-06 22:54:00 +04:00
# ifdef HAVE_SELINUX
# include <selinux / selinux.h>
# endif
2001-12-05 19:41:52 +03:00
# define DEV_DIR " / dev / "
static char _dm_dir [ PATH_MAX ] = DEV_DIR DM_DIR ;
2003-01-22 00:25:11 +03:00
static int _verbose = 0 ;
2009-07-31 19:53:11 +04:00
# ifdef UDEV_SYNC_SUPPORT
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
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
static void _default_log_line ( int level ,
const char * file __attribute ( ( unused ) ) ,
int line __attribute ( ( unused ) ) , int dm_errno ,
const char * f , va_list ap )
2001-12-05 19:41:52 +03:00
{
2007-06-28 21:27:02 +04:00
int use_stderr = level & _LOG_STDERR ;
level & = ~ _LOG_STDERR ;
2001-12-05 19:41:52 +03:00
2003-01-22 00:25:11 +03:00
if ( level > _LOG_WARN & & ! _verbose )
2002-03-14 16:39:33 +03:00
return ;
2003-01-22 00:25:11 +03:00
if ( level < _LOG_WARN )
2002-03-19 02:39:42 +03:00
vfprintf ( stderr , f , ap ) ;
2003-01-22 00:25:11 +03:00
else
2007-06-28 21:27:02 +04:00
vfprintf ( use_stderr ? stderr : stdout , f , ap ) ;
2002-03-14 16:39:33 +03:00
2003-01-22 00:25:11 +03:00
if ( level < _LOG_WARN )
fprintf ( stderr , " \n " ) ;
else
2007-06-28 21:27:02 +04:00
fprintf ( use_stderr ? stderr : stdout , " \n " ) ;
2001-12-05 19:41:52 +03:00
}
2009-07-10 13:59:37 +04:00
static void _default_log_with_errno ( int level ,
const char * file __attribute ( ( unused ) ) ,
int line __attribute ( ( unused ) ) , int dm_errno ,
const char * f , . . . )
{
va_list ap ;
va_start ( ap , f ) ;
_default_log_line ( level , file , line , dm_errno , f , ap ) ;
va_end ( ap ) ;
}
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
void dm_log_init ( dm_log_fn fn )
{
2003-12-21 19:08:20 +03:00
if ( fn )
2006-01-31 17:50:38 +03:00
dm_log = fn ;
2003-12-21 19:08:20 +03:00
else
2006-01-31 17:50:38 +03:00
dm_log = _default_log ;
2009-07-10 13:59:37 +04:00
dm_log_with_errno = _default_log_with_errno ;
}
int dm_log_is_non_default ( void )
{
return ( dm_log = = _default_log ) ? 0 : 1 ;
}
void dm_log_with_errno_init ( dm_log_with_errno_fn fn )
{
if ( fn )
dm_log_with_errno = fn ;
else
dm_log_with_errno = _default_log_with_errno ;
dm_log = _default_log ;
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 ;
}
2002-11-14 22:26:28 +03:00
static void _build_dev_path ( char * buffer , size_t len , const char * dev_name )
2001-12-14 16:30:04 +03:00
{
/* If there's a /, assume caller knows what they're doing */
if ( strchr ( dev_name , ' / ' ) )
snprintf ( buffer , len , " %s " , dev_name ) ;
else
2002-03-19 02:39:42 +03:00
snprintf ( buffer , len , " %s/%s " , _dm_dir , dev_name ) ;
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 )
{
strncpy ( version , DM_LIB_VERSION , size ) ;
return 1 ;
}
2001-12-05 19:41:52 +03:00
struct dm_task * dm_task_create ( int type )
{
2005-10-17 02:57:20 +04:00
struct dm_task * dmt = dm_malloc ( 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 ) ;
2005-01-06 21:22:44 +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
memset ( dmt , 0 , sizeof ( * dmt ) ) ;
2001-12-05 19:41:52 +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 ;
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 .
*/
2009-09-25 22:13:17 +04:00
static char * _find_dm_name_of_device ( dev_t st_rdev )
2009-09-25 22:08:04 +04:00
{
const char * name ;
char path [ PATH_MAX ] ;
struct dirent * dirent ;
DIR * d ;
struct stat buf ;
char * new_name = NULL ;
if ( ! ( d = opendir ( _dm_dir ) ) ) {
log_sys_error ( " opendir " , _dm_dir ) ;
return NULL ;
}
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 ;
}
if ( stat ( path , & buf ) )
continue ;
if ( buf . st_rdev = = st_rdev ) {
2009-09-25 22:19:09 +04:00
if ( ! ( new_name = dm_strdup ( name ) ) )
log_error ( " dm_task_set_name: strdup(%s) failed " ,
name ) ;
2009-09-25 22:08:04 +04:00
break ;
}
}
if ( closedir ( d ) )
log_sys_error ( " closedir " , _dm_dir ) ;
return new_name ;
}
2001-12-05 19:41:52 +03:00
int dm_task_set_name ( struct dm_task * dmt , const char * name )
{
2001-12-14 16:30:04 +03:00
char * pos ;
2009-09-25 22:08:04 +04:00
char * new_name = NULL ;
2001-12-14 16:30:04 +03:00
char path [ PATH_MAX ] ;
struct stat st1 , st2 ;
2002-03-19 02:39:42 +03:00
if ( dmt - > dev_name ) {
2005-10-17 02:57:20 +04:00
dm_free ( dmt - > dev_name ) ;
2002-03-12 01:44:36 +03:00
dmt - > dev_name = NULL ;
}
2001-12-05 19:41:52 +03:00
2009-09-25 22:08:04 +04:00
/*
* Path supplied for existing device ?
2001-12-14 16:30:04 +03:00
*/
if ( ( pos = strrchr ( name , ' / ' ) ) ) {
2009-01-07 15:17:40 +03:00
if ( dmt - > type = = DM_DEVICE_CREATE ) {
log_error ( " Name \" %s \" invalid. It contains \" / \" . " , name ) ;
return 0 ;
}
2009-09-25 22:08:04 +04:00
if ( stat ( name , & st1 ) ) {
log_error ( " Device %s not found " , name ) ;
return 0 ;
}
/*
* If supplied path points to same device as last component
* under / dev / mapper , use that name directly . Otherwise call
2009-09-25 22:13:17 +04:00
* _find_dm_name_of_device ( ) to scan _dm_dir for a match .
2009-09-25 22:08:04 +04:00
*/
2009-09-25 23:06:05 +04:00
if ( dm_snprintf ( path , sizeof ( path ) , " %s/%s " , _dm_dir ,
pos + 1 ) = = - 1 ) {
log_error ( " Couldn't create path for %s " , pos + 1 ) ;
return 0 ;
}
2001-12-14 16:30:04 +03:00
2009-09-25 22:08:04 +04:00
if ( ! stat ( path , & st2 ) & & ( st1 . st_rdev = = st2 . st_rdev ) )
name = pos + 1 ;
2009-09-25 22:13:17 +04:00
else if ( ( new_name = _find_dm_name_of_device ( st1 . st_rdev ) ) )
2009-09-25 22:08:04 +04:00
name = new_name ;
else {
2009-01-07 15:17:40 +03:00
log_error ( " Device %s not found " , name ) ;
2001-12-14 16:30:04 +03:00
return 0 ;
}
}
2009-01-07 15:17:40 +03:00
if ( strlen ( name ) > = DM_NAME_LEN ) {
log_error ( " Name \" %s \" too long " , name ) ;
2009-09-25 22:08:04 +04:00
if ( new_name )
dm_free ( new_name ) ;
2009-01-07 15:17:40 +03:00
return 0 ;
}
2009-09-25 22:08:04 +04:00
if ( new_name )
dmt - > dev_name = new_name ;
else if ( ! ( dmt - > dev_name = dm_strdup ( name ) ) ) {
2002-01-18 22:37:26 +03:00
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
}
2002-03-12 01:44:36 +03:00
int dm_task_set_uuid ( struct dm_task * dmt , const char * uuid )
{
if ( dmt - > uuid ) {
2005-10-17 02:57:20 +04:00
dm_free ( dmt - > uuid ) ;
2002-03-12 01:44:36 +03:00
dmt - > uuid = NULL ;
}
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 ;
}
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 ) ;
2001-12-05 19:41:52 +03:00
2002-03-19 02:39:42 +03:00
if ( ! t )
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
}
2005-10-25 21:30:00 +04:00
int dm_set_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
2004-04-06 22:54:00 +04:00
security_context_t scontext ;
if ( is_selinux_enabled ( ) < = 0 )
2004-07-03 22:14:12 +04:00
return 1 ;
2004-04-06 22:54:00 +04:00
2005-06-13 17:11:48 +04:00
if ( matchpathcon ( path , mode , & scontext ) < 0 ) {
log_error ( " %s: matchpathcon %07o failed: %s " , path , mode ,
strerror ( errno ) ) ;
2004-04-06 22:54:00 +04:00
return 0 ;
}
2005-06-13 17:11:48 +04:00
log_debug ( " 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 ;
}
2005-01-06 01:00:40 +03:00
static int _add_dev_node ( const char * dev_name , uint32_t major , uint32_t minor ,
2009-10-26 17:29:33 +03:00
uid_t uid , gid_t gid , mode_t mode , int check_udev )
2001-12-05 19:41:52 +03:00
{
2002-03-19 02:39:42 +03:00
char path [ PATH_MAX ] ;
struct stat info ;
2003-01-22 00:25:11 +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
2002-03-19 02:39:42 +03:00
_build_dev_path ( path , sizeof ( path ) , dev_name ) ;
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 ;
}
2010-01-11 18:36:24 +03:00
} else if ( dm_udev_get_sync_support ( ) & & dm_udev_get_checking ( ) & &
check_udev )
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
2005-01-06 01:00:40 +03:00
old_mask = umask ( 0 ) ;
if ( mknod ( path , S_IFBLK | mode , dev ) < 0 ) {
2009-09-04 01:51:26 +04:00
umask ( old_mask ) ;
2002-03-19 02:39:42 +03:00
log_error ( " Unable to make device node for '%s' " , dev_name ) ;
return 0 ;
}
2005-01-06 01:00:40 +03:00
umask ( old_mask ) ;
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 ;
}
2007-12-14 22:49:27 +03:00
log_debug ( " Created %s " , path ) ;
2005-10-25 21:30:00 +04:00
if ( ! dm_set_selinux_context ( path , S_IFBLK ) )
2004-04-06 22:54:00 +04:00
return 0 ;
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
}
2009-10-26 17:29:33 +03:00
static int _rm_dev_node ( const char * dev_name , int check_udev )
2009-08-06 19:00:25 +04:00
{
char path [ PATH_MAX ] ;
struct stat info ;
_build_dev_path ( path , sizeof ( path ) , dev_name ) ;
if ( stat ( path , & info ) < 0 )
return 1 ;
2010-01-11 18:36:24 +03:00
else if ( dm_udev_get_sync_support ( ) & & dm_udev_get_checking ( ) & &
check_udev )
2009-08-06 19:00:25 +04:00
log_warn ( " Node %s was not removed by udev. "
" Falling back to direct node removal. " , path ) ;
if ( unlink ( path ) < 0 ) {
log_error ( " Unable to unlink device node for '%s' " , dev_name ) ;
return 0 ;
}
log_debug ( " Removed %s " , path ) ;
return 1 ;
}
2009-10-26 17:29:33 +03:00
static int _rename_dev_node ( const char * old_name , const char * new_name ,
int check_udev )
2002-04-11 16:45:18 +04:00
{
char oldpath [ PATH_MAX ] ;
char newpath [ PATH_MAX ] ;
struct stat info ;
_build_dev_path ( oldpath , sizeof ( oldpath ) , old_name ) ;
_build_dev_path ( newpath , sizeof ( newpath ) , new_name ) ;
2002-04-24 01:47:50 +04:00
if ( stat ( newpath , & info ) = = 0 ) {
2002-04-11 16:45:18 +04:00
if ( ! S_ISBLK ( info . st_mode ) ) {
log_error ( " A non-block device file at '%s' "
" is already present " , newpath ) ;
return 0 ;
}
2010-01-11 18:36:24 +03:00
else if ( dm_udev_get_sync_support ( ) & & dm_udev_get_checking ( ) & &
check_udev ) {
2009-08-06 19:00:25 +04:00
if ( stat ( oldpath , & info ) < 0 & &
errno = = ENOENT )
/* assume udev already deleted this */
return 1 ;
else {
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 ) ;
2009-10-26 17:29:33 +03:00
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 ;
}
}
2010-01-11 18:36:24 +03:00
else if ( dm_udev_get_sync_support ( ) & & dm_udev_get_checking ( ) & &
check_udev )
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
if ( rename ( oldpath , newpath ) < 0 ) {
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 ;
}
2007-12-14 22:49:27 +03:00
log_debug ( " Renamed %s to %s " , oldpath , newpath ) ;
2002-04-11 16:45:18 +04:00
return 1 ;
}
2007-11-30 19:42:26 +03:00
# ifdef linux
static int _open_dev_node ( const char * dev_name )
{
int fd = - 1 ;
char path [ PATH_MAX ] ;
_build_dev_path ( path , sizeof ( path ) , dev_name ) ;
if ( ( fd = open ( path , O_RDONLY , 0 ) ) < 0 )
log_sys_error ( " open " , path ) ;
return fd ;
}
2007-11-30 17:59:57 +03:00
int get_dev_node_read_ahead ( const char * dev_name , uint32_t * read_ahead )
{
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
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 ;
2007-12-05 17:11:26 +03:00
} else {
* read_ahead = ( uint32_t ) read_ahead_long ;
2007-11-30 19:42:26 +03:00
log_debug ( " %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 ) )
2007-11-30 19:42:26 +03:00
stack ;
return r ;
2007-11-30 17:59:57 +03:00
}
static int _set_read_ahead ( const char * dev_name , uint32_t read_ahead )
{
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
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 ;
log_debug ( " %s: Setting read ahead to % " PRIu32 , dev_name , read_ahead ) ;
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 ) )
2007-11-30 19:42:26 +03:00
stack ;
return r ;
2007-11-30 17:59:57 +03:00
}
static int _set_dev_node_read_ahead ( const char * dev_name , uint32_t read_ahead ,
uint32_t read_ahead_flags )
{
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 ) {
if ( ! get_dev_node_read_ahead ( dev_name , & current_read_ahead ) )
return_0 ;
if ( current_read_ahead > read_ahead ) {
2007-12-05 21:57:34 +03:00
log_debug ( " %s: retaining kernel read ahead of % " PRIu32
" (requested % " PRIu32 " ) " ,
2007-11-30 17:59:57 +03:00
dev_name , current_read_ahead , read_ahead ) ;
return 1 ;
}
}
return _set_read_ahead ( dev_name , read_ahead ) ;
}
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 ;
}
static int _set_dev_node_read_ahead ( const char * dev_name , uint32_t read_ahead ,
uint32_t read_ahead_flags )
{
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 ,
NODE_READ_AHEAD
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 ,
2009-10-26 17:29:33 +03:00
uint32_t read_ahead_flags , int check_udev )
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 ,
mode , check_udev ) ;
2003-07-02 01:20:58 +04:00
case NODE_DEL :
2009-10-26 17:29:33 +03:00
return _rm_dev_node ( dev_name , check_udev ) ;
2003-07-02 01:20:58 +04:00
case NODE_RENAME :
2009-10-26 17:29:33 +03:00
return _rename_dev_node ( old_name , dev_name , check_udev ) ;
2007-11-30 17:59:57 +03:00
case NODE_READ_AHEAD :
return _set_dev_node_read_ahead ( dev_name , read_ahead ,
read_ahead_flags ) ;
2003-07-02 01:20:58 +04:00
}
return 1 ;
}
2008-11-04 01:14:30 +03:00
static DM_LIST_INIT ( _node_ops ) ;
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 ;
2009-10-26 17:29:33 +03:00
int check_udev ;
2003-07-02 01:20:58 +04:00
char names [ 0 ] ;
} ;
static void _store_str ( char * * pos , char * * ptr , const char * str )
{
strcpy ( * pos , str ) ;
* ptr = * pos ;
* pos + = strlen ( * ptr ) + 1 ;
}
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 ,
2009-10-26 17:29:33 +03:00
uint32_t read_ahead_flags , int check_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
/*
* Ignore any outstanding operations on the node if deleting it
*/
if ( type = = NODE_DEL ) {
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 ) ) {
2008-11-04 01:14:30 +03:00
dm_list_del ( & nop - > list ) ;
2007-12-14 22:49:27 +03:00
dm_free ( nop ) ;
}
}
}
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 ;
2009-10-26 17:29:33 +03:00
nop - > check_udev = check_udev ;
2003-07-02 01:20:58 +04:00
_store_str ( & pos , & nop - > dev_name , dev_name ) ;
_store_str ( & pos , & nop - > old_name , old_name ) ;
2008-11-04 01:14:30 +03:00
dm_list_add ( & _node_ops , & nop - > list ) ;
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 ) ;
2003-07-02 01:20:58 +04:00
_do_node_op ( nop - > type , nop - > dev_name , nop - > major , nop - > minor ,
2007-11-30 17:59:57 +03:00
nop - > uid , nop - > gid , nop - > mode , nop - > old_name ,
2009-10-26 17:29:33 +03:00
nop - > read_ahead , nop - > read_ahead_flags ,
nop - > check_udev ) ;
2008-11-04 01:14:30 +03:00
dm_list_del ( & nop - > list ) ;
2005-10-17 02:57:20 +04:00
dm_free ( 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 ,
2009-10-26 17:29:33 +03:00
uid_t uid , gid_t gid , mode_t mode , int check_udev )
2003-07-02 01:20:58 +04:00
{
2007-12-14 20:26:09 +03:00
log_debug ( " %s: Stacking NODE_ADD (% " PRIu32 " ,% " PRIu32 " ) %u:%u 0%o " ,
dev_name , major , minor , uid , gid , mode ) ;
2009-10-26 17:29:33 +03:00
return _stack_node_op ( NODE_ADD , dev_name , major , minor , uid ,
gid , mode , " " , 0 , 0 , check_udev ) ;
2003-07-02 01:20:58 +04:00
}
2009-10-26 17:29:33 +03:00
int rename_dev_node ( const char * old_name , const char * new_name , int check_udev )
2003-07-02 01:20:58 +04:00
{
2007-12-14 20:26:09 +03:00
log_debug ( " %s: Stacking NODE_RENAME to %s " , old_name , new_name ) ;
2009-10-26 17:29:33 +03:00
return _stack_node_op ( NODE_RENAME , new_name , 0 , 0 , 0 ,
0 , 0 , old_name , 0 , 0 , check_udev ) ;
2003-07-02 01:20:58 +04:00
}
2009-10-26 17:29:33 +03:00
int rm_dev_node ( const char * dev_name , int check_udev )
2003-07-02 01:20:58 +04:00
{
2007-12-14 22:49:27 +03:00
log_debug ( " %s: Stacking NODE_DEL (replaces other stacked ops) " , dev_name ) ;
2007-12-14 20:26:09 +03:00
2009-10-26 17:29:33 +03:00
return _stack_node_op ( NODE_DEL , dev_name , 0 , 0 , 0 ,
0 , 0 , " " , 0 , 0 , check_udev ) ;
2007-11-30 17:59:57 +03:00
}
int set_dev_node_read_ahead ( const char * dev_name , uint32_t read_ahead ,
uint32_t read_ahead_flags )
{
if ( read_ahead = = DM_READ_AHEAD_AUTO )
return 1 ;
2007-12-14 20:26:09 +03:00
log_debug ( " %s: Stacking NODE_READ_AHEAD % " PRIu32 " (flags=% " PRIu32
" ) " , dev_name , read_ahead , read_ahead_flags ) ;
2009-10-26 17:29:33 +03:00
return _stack_node_op ( NODE_READ_AHEAD , dev_name , 0 , 0 , 0 , 0 ,
0 , " " , read_ahead , read_ahead_flags , 0 ) ;
2003-07-02 01:20:58 +04:00
}
void update_devs ( void )
{
_pop_node_ops ( ) ;
}
2007-10-09 16:14:48 +04:00
int dm_set_dev_dir ( const char * dev_dir )
2001-12-05 19:41:52 +03:00
{
2007-10-09 16:14:48 +04:00
size_t len ;
const char * slash ;
if ( * dev_dir ! = ' / ' ) {
log_debug ( " Invalid dev_dir value, %s: "
" not an absolute name. " , dev_dir ) ;
return 0 ;
}
len = strlen ( dev_dir ) ;
slash = dev_dir [ len - 1 ] = = ' / ' ? " " : " / " ;
if ( snprintf ( _dm_dir , sizeof _dm_dir , " %s%s%s " , dev_dir , slash , DM_DIR )
> = sizeof _dm_dir ) {
log_debug ( " Invalid dev_dir value, %s: name too long. " , dev_dir ) ;
return 0 ;
}
2002-03-19 02:39:42 +03:00
return 1 ;
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
int dm_mknodes ( const char * name )
{
struct dm_task * dmt ;
int r = 0 ;
if ( ! ( dmt = dm_task_create ( DM_DEVICE_MKNODES ) ) )
return 0 ;
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 ) ) )
return 0 ;
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
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
{
2009-11-13 15:43:21 +03:00
if ( dm_cookie_supported ( ) )
dmt - > event_nr = flags < < DM_UDEV_FLAGS_SHIFT ;
2009-07-31 19:53:11 +04:00
* cookie = 0 ;
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 )
{
return 1 ;
}
# else /* UDEV_SYNC_SUPPORT */
2009-09-11 19:56:06 +04:00
static int _check_udev_is_running ( void )
{
2009-09-15 15:41:38 +04:00
# ifndef HAVE_UDEV_QUEUE_GET_UDEV_IS_ACTIVE
2009-09-11 19:56:06 +04:00
log_debug ( " Could not get udev state because libudev library "
" was not found and it was not compiled in. "
" Assuming udev is not running. " ) ;
return 0 ;
2009-09-15 15:41:38 +04:00
# else /* HAVE_UDEV_QUEUE_GET_UDEV_IS_ACTIVE */
2009-09-11 19:56:06 +04:00
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 ) ) )
2009-09-11 19:56:06 +04:00
log_debug ( " Udev is not running. "
" Not using udev synchronisation code. " ) ;
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 ;
2009-09-15 15:41:38 +04:00
# endif /* HAVE_UDEV_QUEUE_GET_UDEV_IS_ACTIVE */
2009-09-11 19:56:06 +04:00
}
2009-07-31 19:53:11 +04:00
void dm_udev_set_sync_support ( int sync_with_udev )
{
2009-09-11 19:56:06 +04:00
if ( _udev_running < 0 )
_udev_running = _check_udev_is_running ( ) ;
2009-07-31 19:53:11 +04:00
_sync_with_udev = sync_with_udev ;
}
int dm_udev_get_sync_support ( void )
{
2009-09-11 19:56:06 +04:00
if ( _udev_running < 0 )
_udev_running = _check_udev_is_running ( ) ;
2009-09-11 20:11:25 +04:00
return 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 ) )
log_debug ( " DM udev checking enabled " ) ;
else
log_debug ( " DM udev checking disabled " ) ;
}
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 } ;
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 ;
}
2009-08-05 23:50:08 +04:00
log_debug ( " Udev cookie 0x% " PRIx32 " (semid %d) incremented " ,
cookie , semid ) ;
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 } ;
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
2009-08-05 23:50:08 +04:00
log_debug ( " Udev cookie 0x% " PRIx32 " (semid %d) decremented " ,
cookie , semid ) ;
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 ;
}
2009-08-05 23:50:08 +04:00
log_debug ( " Udev cookie 0x% " PRIx32 " (semid %d) destroyed " , cookie ,
semid ) ;
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 ;
uint16_t base_cookie ;
uint32_t gen_cookie ;
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 ) ;
2009-08-05 23:50:08 +04:00
log_debug ( " Udev cookie 0x% " PRIx32 " (semid %d) created " ,
gen_cookie , gen_semid ) ;
2009-07-31 19:53:11 +04:00
if ( semctl ( gen_semid , 0 , SETVAL , 1 ) < 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 ;
}
2009-08-05 23:50:08 +04:00
log_debug ( " Udev cookie 0x% " PRIx32 " (semid %d) incremented " ,
gen_cookie , gen_semid ) ;
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 ;
if ( ! dm_udev_get_sync_support ( ) )
return 1 ;
return _udev_notify_sem_create ( cookie , & semid ) ;
}
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 ;
2009-11-13 15:43:21 +03:00
if ( dm_cookie_supported ( ) )
dmt - > event_nr = flags < < DM_UDEV_FLAGS_SHIFT ;
2009-09-11 20:11:25 +04:00
if ( ! dm_udev_get_sync_support ( ) ) {
2009-11-13 15:43:21 +03:00
* cookie = 0 ;
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
2009-10-22 16:55:47 +04:00
log_debug ( " Udev cookie 0x% " PRIx32 " (semid %d) assigned to dm_task "
" with flags 0x% " PRIx16 , * cookie , semid , 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 ;
}
int dm_udev_wait ( uint32_t cookie )
{
int semid ;
struct sembuf sb = { 0 , 0 , 0 } ;
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 ( " 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 ;
}
2009-08-05 23:50:08 +04:00
log_debug ( " Udev cookie 0x% " PRIx32 " (semid %d): Waiting for zero " ,
cookie , semid ) ;
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
}
# endif /* UDEV_SYNC_SUPPORT */