From 2f2f7a5d28db0ee9bdb9f22166773514da694fe2 Mon Sep 17 00:00:00 2001 From: Peter Gossner Date: Wed, 27 Jul 2016 21:33:29 +0930 Subject: [PATCH 01/13] modified: .gitignore modified: libvdev/config.c modified: libvdev/config.h modified: vdevd/main.c modified: vdevd/vdev.c patches to (re)instate --help for the vdevd daemon. should now exit early when -h or --help is supplied on the command line. hopefully I have understood the project style and intent of various code structures. currently the exit code is 2 make clean make test and compare with build/sbin/vdevd -l mylogfile.log -h echo $? =returns=> 6 build/sbin/vdevd --help echo $? =returns=> 2 which may be a little helpful There are structures and defs for future work --- .gitignore | 4 ++++ libvdev/config.c | 19 +++++++++++++---- libvdev/config.h | 5 ++++- vdevd/main.c | 55 +++++++++++++++++++++++++++++------------------- vdevd/vdev.c | 10 ++++++++- 5 files changed, 65 insertions(+), 28 deletions(-) diff --git a/.gitignore b/.gitignore index a8db8d4..fd26f30 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,11 @@ *~ +*.orig +*.backup *.pyc *.o *.so *.so.* *.swp *.kate-swp +*.patch +*.diff diff --git a/libvdev/config.c b/libvdev/config.c index fa7a84a..3ab38fa 100644 --- a/libvdev/config.c +++ b/libvdev/config.c @@ -487,9 +487,12 @@ Options include:\n\ \n\ -p, --pidfile PATH\n\ Write the PID of the daemon to PATH.\n\ + -h, --help\n\ + prints this help message.\n\ + and exits early.\n\ ", progname ); - return 0; + return 0; } // get the mountpoint option, by taking the last argument that wasn't an optarg @@ -528,6 +531,7 @@ int vdev_config_load_from_args( struct vdev_config* config, int argc, char** arg {"once", no_argument, 0, '1'}, {"coldplug-only", no_argument, 0, 'n'}, {"foreground", no_argument, 0, 'f'}, + {"help", no_argument, 0, 'h'}, {0, 0, 0, 0} }; @@ -536,7 +540,7 @@ int vdev_config_load_from_args( struct vdev_config* config, int argc, char** arg int c = 0; int fuse_optind = 0; - char const* optstr = "c:v:l:o:f1np:ds"; + char const* optstr = "c:v:l:o:hf1np:ds"; if( fuse_argv != NULL ) { fuse_argv[fuse_optind] = argv[0]; @@ -546,8 +550,8 @@ int vdev_config_load_from_args( struct vdev_config* config, int argc, char** arg while(rc == 0 && c != -1) { c = getopt_long(argc, argv, optstr, vdev_options, &opt_index); - - if( c == -1 ) { + // break on -1 missing arguments and -2 help + if( c == -1 || c == -2 ) { break; } @@ -650,6 +654,13 @@ int vdev_config_load_from_args( struct vdev_config* config, int argc, char** arg break; } + + case 'h': { + // command args line help + fprintf(stderr, "Command Line Options Help \n" ); + rc = -2; + break; + } default: { diff --git a/libvdev/config.h b/libvdev/config.h index 0496b03..f35313f 100644 --- a/libvdev/config.h +++ b/libvdev/config.h @@ -42,6 +42,7 @@ #define VDEV_CONFIG_COLDPLUG_ONLY "coldplug_only" #define VDEV_CONFIG_FOREGROUND "foreground" #define VDEV_CONFIG_PRESEED "preseed" +#define VDEV_CONFIG_HELP "help" // simple commandline help #define VDEV_CONFIG_INSTANCE_NONCE_LEN 32 #define VDEV_CONFIG_INSTANCE_NONCE_STRLEN (2*VDEV_CONFIG_INSTANCE_NONCE_LEN + 1) @@ -104,6 +105,9 @@ struct vdev_config { // bitfield of OS-specific quirks uint64_t OS_quirks; + + // help holder + char help; }; C_LINKAGE_BEGIN @@ -112,7 +116,6 @@ int vdev_config_init( struct vdev_config* conf ); int vdev_config_load( char const* path, struct vdev_config* conf ); int vdev_config_load_file( FILE* file, struct vdev_config* conf ); int vdev_config_free( struct vdev_config* conf ); - int vdev_config_usage( char const* progname ); int vdev_config_load_from_args( struct vdev_config* config, int argc, char** argv, int* fuse_argc, char** fuse_argv ); int vdev_config_fullpaths( struct vdev_config* config ); diff --git a/vdevd/main.c b/vdevd/main.c index 84d49ca..72d2d1c 100644 --- a/vdevd/main.c +++ b/vdevd/main.c @@ -32,29 +32,40 @@ void vdev_reload_sighup( int ignored ) { // run! int main( int argc, char** argv ) { - - int rc = 0; - int coldplug_quiesce_pipe[2]; - bool is_child = false; - bool is_parent = false; - ssize_t nr = 0; - int coldplug_finished_fd = -1; // FD to write to once we finish flushing the initial device requests - - memset( &vdev, 0, sizeof(struct vdev_state) ); - - // ignore SIGPIPE from daemonlets - signal( SIGPIPE, SIG_IGN ); - - // set up global vdev state - rc = vdev_init( &vdev, argc, argv ); - if( rc != 0 ) { - - vdev_error("vdev_init rc = %d\n", rc ); - - vdev_shutdown( &vdev, false ); - exit(1); - } + int rc = 0; + int coldplug_quiesce_pipe[2]; + bool is_child = false; + bool is_parent = false; + ssize_t nr = 0; + + int coldplug_finished_fd = -1; // FD to write to once we finish flushing the initial device requests + + memset( &vdev, 0, sizeof(struct vdev_state) ); + + // ignore SIGPIPE from daemonlets + signal( SIGPIPE, SIG_IGN ); + + // set up global vdev state + rc = vdev_init( &vdev, argc, argv ); + // help called from command line -h or --help (-2) + // short circuit with log/debug support + if( vdev.config->help ){ + if( rc == -2 ){ + + vdev_debug("%s", "exiting: help called at command line\n"); + // the shutdown and clean up should be redundant ? + exit(0); + } + } + + if( rc != 0 ) { + + vdev_error("vdev_init rc = %d\n", rc ); + + vdev_shutdown( &vdev, false ); + exit(1); + } // run the preseed command rc = vdev_preseed_run( &vdev ); diff --git a/vdevd/vdev.c b/vdevd/vdev.c index 306d674..a9e94cf 100644 --- a/vdevd/vdev.c +++ b/vdevd/vdev.c @@ -1,5 +1,5 @@ /* - vdev: a virtual device manager for *nix + Vdev: A virtual device manager for *nix Copyright (C) 2014 Jude Nelson This program is dual-licensed: you can redistribute it and/or modify @@ -926,6 +926,14 @@ int vdev_init( struct vdev_state* vdev, int argc, char** argv ) { // parse config options from command-line rc = vdev_config_load_from_args( vdev->config, argc, argv, NULL, NULL ); + // help is not an error + if( rc == -2 ) { + + vdev_config_usage( argv[0] ); + + return 0; + + } if( rc != 0 ) { From cb4da01915ceb41f2d34ac7738958d59af1dda90 Mon Sep 17 00:00:00 2001 From: Peter Gossner Date: Thu, 11 Aug 2016 23:32:06 +0930 Subject: [PATCH 02/13] modified: buildconf.mk set CFLAGS to more recent C version and increase error reporting originals simply commented out ready for production uses. --- buildconf.mk | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/buildconf.mk b/buildconf.mk index 436bc6d..941c5f0 100644 --- a/buildconf.mk +++ b/buildconf.mk @@ -22,7 +22,7 @@ INCLUDEDIR ?= $(INCLUDE_PREFIX)/include ETCDIR ?= $(PREFIX)/etc ETCDIR_VDEV ?= $(ETCDIR)/vdev SHAREDIR ?= $(PREFIX)/share -PKGCONFIG ?= $(INCLUDE_PREFIX)/share/pkgconfig +PKGCONFIG ?= $(INCLUDE_PREFIX)/share/pkgconfig RUNDIR ?= $(PREFIX)/run RUNDIR_VDEV ?= $(RUNDIR)/vdev LOGDIR ?= $(PREFIX)/var/log @@ -68,8 +68,12 @@ BUILD_HWDB := $(BUILD_LIBDIR)/vdev/hwdb BUILD_HWDB_DIRS := $(BUILD_HWDB) INSTALL_HWDB := $(DESTDIR)$(LIBDIR)/vdev/hwdb -# compiler -CFLAGS := -Wall -std=c99 -g -fPIC -fstack-protector -fstack-protector-all -pthread -Wno-unused-variable -Wno-unused-but-set-variable +# compiler original settings +#CFLAGS := -Wall -std=c99 -g -fPIC -fstack-protector -fstack-protector-all -pthread -Wno-unused-variable -Wno-unused-but-set-variable +# compiler : headers also set some C standards though perhaps boiler plate ? +# noiser settings for hair shirted types and deeper testing and analysis. +CFLAGS := -g -fPIC -fstack-protector -fstack-protector-all -pthread\ + -Wall -Wextra -std=c11 #-pedantic-errors LDFLAGS := INC := -I. -I$(ROOT_DIR) -I$(BUILD_INCLUDEDIR) DEFS := -D_THREAD_SAFE -D__STDC_FORMAT_MACROS -D_VDEV_OS_$(OS) -D_XOPEN_SOURCE=700 From 0efdeed96f9a32a478e4180f0a6c7f08b43c5c50 Mon Sep 17 00:00:00 2001 From: Peter Gossner Date: Thu, 11 Aug 2016 23:38:16 +0930 Subject: [PATCH 03/13] modified: example/sysv-initscript.sh Some small tweaks for clarity and consistancy with init time errors. --- example/sysv-initscript.sh | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/example/sysv-initscript.sh b/example/sysv-initscript.sh index 18ffee0..7aaff3b 100755 --- a/example/sysv-initscript.sh +++ b/example/sysv-initscript.sh @@ -3,8 +3,8 @@ # Provides: udev # Required-Start: mountkernfs # Required-Stop: -# Default-Start: S -# Default-Stop: +# Default-Start: S +# Default-Stop: # Short-Description: Start vdevd, populate /dev and load drivers. ### END INIT INFO @@ -33,7 +33,7 @@ source_ini_file() { FILE_PATH=$1 NAMESPACE=$2 - + # convert [ini style header] to "" /bin/cat $FILE_PATH | /bin/sed "s/.*\[.*\].*//g" | \ while read line; do @@ -41,8 +41,7 @@ source_ini_file() { VALUE=$(echo $line | /bin/sed "s/^.*=\(.*\)$/\1/g"); if [ -n "$KEY" ]; then - - echo "${NAMESPACE}${KEY}=${VALUE}" + echo "${NAMESPACE}${KEY}=${VALUE}" fi done } @@ -79,7 +78,7 @@ eval $(source_ini_file $VDEV_CONFIG "vdev_config_") # config sanity check if [ -z "$vdev_config_pidfile" ]; then log_warning_msg "No PID file defined in $VDEV_CONFIG. Please set the pidfile= directive." - log_warning_msg "You will be unable stop or restart vdevd with this script." + log_warning_msg "You will be unable control vdevd with this init script." fi @@ -119,12 +118,13 @@ vdevd_start() { # start vdev if "$VDEV_BIN" -c "$VDEV_CONFIG" $@ "$VDEV_MOUNTPOINT"; then - log_end_msg $? - + log_end_msg $? + else - log_warning_msg $? - log_warning_msg "Waiting 15 seconds and trying to continue anyway" - sleep 15 + log_warning_msg $? + log_warning_msg "Errors when starting \"$VDEV_BIN\" -c \"$VDEV_CONFIG\" " + log_warning_msg "Waiting 15 seconds and trying to continue anyway" + sleep 15 fi return 0 From ed83cfa836bd631e8502170df2298c41aecc1f1c Mon Sep 17 00:00:00 2001 From: Peter Gossner Date: Thu, 11 Aug 2016 23:43:11 +0930 Subject: [PATCH 04/13] modified: example/vdevd.conf No major alterations diff maybe becuase of testing. --- example/vdevd.conf | 1 + 1 file changed, 1 insertion(+) diff --git a/example/vdevd.conf b/example/vdevd.conf index 4f13930..3507bf9 100644 --- a/example/vdevd.conf +++ b/example/vdevd.conf @@ -1,4 +1,5 @@ [vdev-config] + firmware=/lib/firmware acls=./build/etc/vdev/acls actions=./build/etc/vdev/actions From 1d2b4933a9bc1f59ca4f920b4782fe2fdf675c52 Mon Sep 17 00:00:00 2001 From: Peter Gossner Date: Thu, 11 Aug 2016 23:47:33 +0930 Subject: [PATCH 05/13] modified: .gitignore modified: libvdev/config.c modified: libvdev/ini.c modified: libvdev/ini.h modified: libvdev/param.h modified: libvdev/sglib.h modified: libvdev/util.h modified: vdevd/action.c modified: vdevd/vdev.c modified: vdevd/vdev.h Mostly just compiler warning fixits. - attempts to understand some macros and defs. - attempts to understand initramfs inplications. - No functionality alters at all. --- .gitignore | 9 +++ libvdev/config.c | 13 ++-- libvdev/ini.c | 159 ++++++++++++++++++++++++----------------------- libvdev/ini.h | 20 +++--- libvdev/param.h | 4 +- libvdev/sglib.h | 2 +- libvdev/util.h | 36 +++++------ vdevd/action.c | 2 +- vdevd/vdev.c | 3 +- vdevd/vdev.h | 2 +- 10 files changed, 132 insertions(+), 118 deletions(-) diff --git a/.gitignore b/.gitignore index fd26f30..4fe48c3 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,12 @@ *.kate-swp *.patch *.diff + +build +*.log +*.notes +*.petes +*.tux +*.mingus +*.stuff +.gitignore diff --git a/libvdev/config.c b/libvdev/config.c index 3ab38fa..e1368b3 100644 --- a/libvdev/config.c +++ b/libvdev/config.c @@ -135,9 +135,12 @@ static int vdev_config_ini_parser( void* userdata, char const* section, char con conf->error_level = VDEV_LOGLEVEL_ERROR; } else { - - fprintf(stderr, "Unrecognized value '%s' for '%s'\n", value, name ); - return 0; + // warn about unknown option value + // fallover to debug and warn + fprintf(stderr, "Unrecognized value '%s' for '%s'\n", value, name ); + conf->debug_level = VDEV_LOGLEVEL_DEBUG; + conf->error_level = VDEV_LOGLEVEL_WARN; + // return 0; } return 1; @@ -406,8 +409,8 @@ int vdev_config_free( struct vdev_config* conf ) { // return -ENOMEM on OOM // return -ERANGE if cwd is too long int vdev_config_fullpaths( struct vdev_config* conf ) { - - int rc = 0; + // this int does not seem to be used here + // int rc = 0; char** need_fullpath[] = { &conf->config_path, diff --git a/libvdev/ini.c b/libvdev/ini.c index 56426cd..d6e1661 100644 --- a/libvdev/ini.c +++ b/libvdev/ini.c @@ -1,8 +1,7 @@ /* inih -- simple .INI file parser -inih is released under the New BSD license (see LICENSE.txt). Go to the project -home page for more info: - +inih is released under the New BSD license (see LICENSE.txt). +Go to the project home page for more info: http://code.google.com/p/inih/ */ @@ -23,39 +22,41 @@ home page for more info: /* Strip whitespace chars off end of given string, in place. Return s. */ static char* rstrip(char* s) { - char* p = s + strlen(s); - while (p > s && isspace((unsigned char)(*--p))) - *p = '\0'; - return s; + char* p = s + strlen(s); + while (p > s && isspace((unsigned char)(*--p))) + *p = '\0'; + return s; } /* Return pointer to first non-whitespace char in given string. */ static char* lskip(const char* s) { - while (*s && isspace((unsigned char)(*s))) - s++; - return (char*)s; + while (*s && isspace((unsigned char)(*s))) + s++; + return (char*)s; } -/* Return pointer to first char c or ';' comment in given string, or pointer to - null at end of string if neither found. ';' must be prefixed by a whitespace - character to register as a comment. */ +/* +Return pointer to first char c or ';' comment in given string, +or pointer to null at end of string if neither found. +';' must be prefixed by a whitespace character to register as a comment. +*/ static char* find_char_or_comment(const char* s, char c) { - int was_whitespace = 0; - while (*s && *s != c && !(was_whitespace && *s == ';')) { - was_whitespace = isspace((unsigned char)(*s)); - s++; - } - return (char*)s; + int was_whitespace = 0; + while (*s && *s != c && !(was_whitespace && *s == ';')) { + was_whitespace = isspace((unsigned char)(*s)); + s++; + } + return (char*)s; } /* Version of strncpy that ensures dest (size bytes) is null-terminated. */ static char* strncpy0(char* dest, const char* src, size_t size) { - strncpy(dest, src, size); - dest[size - 1] = '\0'; - return dest; + strncpy(dest, src, size); + dest[size - 1] = '\0'; + return dest; } /* See documentation in header file. */ @@ -89,20 +90,20 @@ int ini_parse_file(FILE* file, /* Scan through file line by line */ while (fgets(line, INI_MAX_LINE, file) != NULL) { - lineno++; - - start = line; + lineno++; + + start = line; #if INI_ALLOW_BOM - if (lineno == 1 && (unsigned char)start[0] == 0xEF && - (unsigned char)start[1] == 0xBB && - (unsigned char)start[2] == 0xBF) { - start += 3; - } + if (lineno == 1 && (unsigned char)start[0] == 0xEF && + (unsigned char)start[1] == 0xBB && + (unsigned char)start[2] == 0xBF) { + start += 3; + } #endif start = lskip(rstrip(start)); - + if (*start == ';' || *start == '#') { - /* Per Python ConfigParser, allow '#' comments at start of line */ + /* Per Python ConfigParser, allow '#' comments at start of line */ } #if INI_ALLOW_MULTILINE else if (*prev_name && *start && start > line) { @@ -113,54 +114,54 @@ int ini_parse_file(FILE* file, } #endif else if (*start == '[') { - /* A "[section]" line */ - end = find_char_or_comment(start + 1, ']'); - if (*end == ']') { - *end = '\0'; - strncpy0(section, start + 1, sizeof(section)); - *prev_name = '\0'; - } - else if (!error) { - /* No ']' found on section line */ - error = lineno; - } + /* A "[section]" line */ + end = find_char_or_comment(start + 1, ']'); + if (*end == ']') { + *end = '\0'; + strncpy0(section, start + 1, sizeof(section)); + *prev_name = '\0'; + } + else if (!error) { + /* No ']' found on section line */ + error = lineno; + } } else if (*start && *start != ';') { - /* Not a comment, must be a name[=:]value pair */ - end = find_char_or_comment(start, '='); - if (*end != '=') { - end = find_char_or_comment(start, ':'); - } - if (*end == '=' || *end == ':') { - *end = '\0'; - name = rstrip(start); - value = lskip(end + 1); - end = find_char_or_comment(value, '\0'); - if (*end == ';') - *end = '\0'; - rstrip(value); - - /* Valid name[=:]value pair found, call handler */ - strncpy0(prev_name, name, sizeof(prev_name)); - if (!handler(user, section, name, value) && !error) - error = lineno; - } - else if (!error) { - /* No '=' or ':' found on name[=:]value line */ - error = lineno; - } + /* Not a comment, must be a name[=:]value pair */ + end = find_char_or_comment(start, '='); + if (*end != '=') { + end = find_char_or_comment(start, ':'); + } + if (*end == '=' || *end == ':') { + *end = '\0'; + name = rstrip(start); + value = lskip(end + 1); + end = find_char_or_comment(value, '\0'); + if (*end == ';') + *end = '\0'; + rstrip(value); + + /* Valid name[=:]value pair found, call handler */ + strncpy0(prev_name, name, sizeof(prev_name)); + if (!handler(user, section, name, value) && !error) + error = lineno; + } + else if (!error) { + /* No '=' or ':' found on name[=:]value line */ + error = lineno; + } } - + #if INI_STOP_ON_FIRST_ERROR if (error) - break; + break; #endif } - + #if !INI_USE_STACK free(line); #endif - + return error; } @@ -169,13 +170,13 @@ int ini_parse(const char* filename, int (*handler)(void*, const char*, const char*, const char*), void* user) { - FILE* file; - int error; - - file = fopen(filename, "r"); - if (!file) - return -1; - error = ini_parse_file(file, handler, user); - fclose(file); - return error; + FILE* file; + int error; + + file = fopen(filename, "r"); + if (!file) + return -1; + error = ini_parse_file(file, handler, user); + fclose(file); + return error; } diff --git a/libvdev/ini.h b/libvdev/ini.h index b267da6..92ef145 100644 --- a/libvdev/ini.h +++ b/libvdev/ini.h @@ -1,10 +1,8 @@ /* inih -- simple .INI file parser -inih is released under the New BSD license (see LICENSE.txt). Go to the project -home page for more info: - +inih is released under the New BSD license (see LICENSE.txt). +Go to the project home page for more info: http://code.google.com/p/inih/ - */ #ifndef __INI_H__ @@ -34,17 +32,19 @@ int ini_parse(const char* filename, int (*handler)(void* user, const char* section, const char* name, const char* value), void* user); - + /* Same as ini_parse(), but takes a FILE* instead of filename. This doesn't close the file when it's finished -- the caller must do that. */ -int ini_parse_file(FILE* file, - int (*handler)(void* user, const char* section, - const char* name, const char* value), - void* user); -/* Nonzero to allow multi-line value parsing, in the style of Python's +int ini_parse_file(FILE* file, + int (*handler)(void* user, const char* section, + const char* name, const char* value), + void* user); + + /* Nonzero to allow multi-line value parsing, in the style of Python's ConfigParser. If allowed, ini_parse() will call the handler with the same name for each subsequent line parsed. */ + #ifndef INI_ALLOW_MULTILINE #define INI_ALLOW_MULTILINE 0 #endif diff --git a/libvdev/param.h b/libvdev/param.h index 54b73b0..7938233 100644 --- a/libvdev/param.h +++ b/libvdev/param.h @@ -43,10 +43,10 @@ typedef struct vdev_param_t vdev_params; C_LINKAGE_BEGIN // vdev_param_t -SGLIB_DEFINE_RBTREE_PROTOTYPES(vdev_params, left, right, color, VDEV_PARAM_CMP); +SGLIB_DEFINE_RBTREE_PROTOTYPES(vdev_params, left, right, color, VDEV_PARAM_CMP) int vdev_params_add( vdev_params** params, char const* key, char const* value ); int vdev_params_free( vdev_params* params ); C_LINKAGE_END -#endif \ No newline at end of file +#endif diff --git a/libvdev/sglib.h b/libvdev/sglib.h index 1a2f8af..4ca2aac 100644 --- a/libvdev/sglib.h +++ b/libvdev/sglib.h @@ -1986,7 +1986,7 @@ void sglib___##type##_consistency_check(type *t) {\ \ type sglib_##type##_vector_pop_back( struct sglib_##type##_vector* v ) { \ if( v->len <= 0 ) { \ - fprintf( stderr, "FATAL: pop_back on zero-length vector %p\n", v ); \ + fprintf( stderr, "FATAL: pop_back on zero-length vector\n" ); \ abort(); \ } \ type ret = v->buf[ v->len - 1 ]; \ diff --git a/libvdev/util.h b/libvdev/util.h index 52a05f1..63a715b 100644 --- a/libvdev/util.h +++ b/libvdev/util.h @@ -90,28 +90,28 @@ extern int _VDEV_SYSLOG; #define vdev_debug( format, ... ) \ do { \ - if( _VDEV_DEBUG_MESSAGES ) { \ - if( _VDEV_SYSLOG ) { \ - syslog( LOG_DAEMON | LOG_DEBUG, format, __VA_ARGS__ ); \ - } \ - else { \ - fprintf(stderr, VDEV_WHERESTR "DEBUG: " format, VDEV_WHEREARG, __VA_ARGS__ ); fflush(stderr);\ - } \ - } \ + if( _VDEV_DEBUG_MESSAGES ) { \ + if( _VDEV_SYSLOG ) { \ + syslog( LOG_DAEMON | LOG_DEBUG, format, __VA_ARGS__ ); \ + } \ + else { \ + fprintf(stderr, VDEV_WHERESTR "DEBUG: " format, VDEV_WHEREARG, __VA_ARGS__ ); fflush(stderr); \ + } \ + } \ } while(0) - -#define vdev_info( format, ... ) \ - do { \ + +#define vdev_info( format, ... ) \ + do { \ if( _VDEV_INFO_MESSAGES ) { \ - if( _VDEV_SYSLOG ) { \ - syslog( LOG_DAEMON | LOG_INFO, format, __VA_ARGS__ ); \ - } \ - else { \ - fprintf(stderr, VDEV_WHERESTR "INFO: " format, VDEV_WHEREARG, __VA_ARGS__ ); fflush(stderr);\ + if( _VDEV_SYSLOG ) { \ + syslog( LOG_DAEMON | LOG_INFO, format, __VA_ARGS__ ); \ } \ - } \ - } while(0) + else { \ + fprintf(stderr, VDEV_WHERESTR "INFO: " format, VDEV_WHEREARG, __VA_ARGS__ ); fflush(stderr); \ + } \ + } \ + } while(0) #define vdev_warn( format, ... ) \ diff --git a/vdevd/action.c b/vdevd/action.c index 9d3c845..884b09b 100644 --- a/vdevd/action.c +++ b/vdevd/action.c @@ -1749,7 +1749,7 @@ int vdev_action_run_commands( struct vdev_device_request* vreq, struct vdev_acti // always succeeds int vdev_action_log_benchmarks( struct vdev_action* action ) { - int rc = 0; + // int rc = 0; if( action->num_successful_calls > 0 ) { vdev_debug("Action '%s' (daemon=%d, async=%d): %lu successful calls; %lu millis total; %lf avg.\n", diff --git a/vdevd/vdev.c b/vdevd/vdev.c index a9e94cf..6c98372 100644 --- a/vdevd/vdev.c +++ b/vdevd/vdev.c @@ -23,7 +23,7 @@ #include "action.h" #include "libvdev/config.h" -SGLIB_DEFINE_VECTOR_FUNCTIONS( cstr ); +SGLIB_DEFINE_VECTOR_FUNCTIONS( cstr ) // context for removing unplugged device @@ -211,6 +211,7 @@ int vdev_remove_unplugged_devices( struct vdev_state* state ) { char* devroot = vdev_strdup_or_null( state->config->mountpoint ); char* next_dir = NULL; size_t next_dir_index = 0; + // sb ? struct stat sb; struct vdev_device_unplug_context unplug_ctx; diff --git a/vdevd/vdev.h b/vdevd/vdev.h index 32c1c65..7a02f5f 100644 --- a/vdevd/vdev.h +++ b/vdevd/vdev.h @@ -101,7 +101,7 @@ int vdev_signal_coldplug_finished( struct vdev_state* state, int status ); int vdev_preseed_run( struct vdev_state* state ); int vdev_remove_unplugged_devices( struct vdev_state* state ); -SGLIB_DEFINE_VECTOR_PROTOTYPES( cstr ); +SGLIB_DEFINE_VECTOR_PROTOTYPES( cstr ) C_LINKAGE_END From 1b815e5a1c1a228a78a46c63b3ad6a26aaa61a9a Mon Sep 17 00:00:00 2001 From: Peter Gossner Date: Sun, 14 Aug 2016 04:08:26 +0930 Subject: [PATCH 06/13] indent -linux ./*.c no more than a style tidy up. --- vdevd/action.c | 3204 +++++++++++++++++++++++---------------------- vdevd/device.c | 2246 ++++++++++++++++--------------- vdevd/main.c | 447 +++---- vdevd/vdev.c | 2198 ++++++++++++++++--------------- vdevd/workqueue.c | 489 +++---- 5 files changed, 4408 insertions(+), 4176 deletions(-) diff --git a/vdevd/action.c b/vdevd/action.c index 884b09b..1d4067d 100644 --- a/vdevd/action.c +++ b/vdevd/action.c @@ -31,800 +31,837 @@ // to be passed into the action loader loop struct vdev_action_loader_cls { - struct sglib_vdev_action_vector* acts; - struct vdev_config* config; + struct sglib_vdev_action_vector *acts; + struct vdev_config *config; }; // prototypes -SGLIB_DEFINE_VECTOR_PROTOTYPES( vdev_action ); -SGLIB_DEFINE_VECTOR_FUNCTIONS( vdev_action ); +SGLIB_DEFINE_VECTOR_PROTOTYPES(vdev_action); +SGLIB_DEFINE_VECTOR_FUNCTIONS(vdev_action); -static int vdev_action_daemonlet_stop( struct vdev_action* act ); +static int vdev_action_daemonlet_stop(struct vdev_action *act); // initialize an action // return 0 on success // return -ENOMEM on OOM -int vdev_action_init( struct vdev_action* act, vdev_device_request_t trigger, char* path, char* command, char* helper, bool async ) { - - int rc = 0; - memset( act, 0, sizeof(struct vdev_action) ); - - act->trigger = trigger; - act->path = vdev_strdup_or_null( path ); - act->command = vdev_strdup_or_null( command ); - act->helper = vdev_strdup_or_null( helper ); - act->async = async; - - act->is_daemonlet = false; - act->daemonlet_stdin = -1; - act->daemonlet_stdout = -1; - act->daemonlet_pid = -1; - - if( act->path != NULL ) { - - rc = vdev_match_regex_init( &act->path_regex, path ); - - if( rc != 0 ) { - - vdev_error("vdev_match_regex_init('%s') rc = %d\n", path, rc ); - vdev_action_free( act ); - return rc; - } - } - - return 0; +int vdev_action_init(struct vdev_action *act, vdev_device_request_t trigger, + char *path, char *command, char *helper, bool async) +{ + + int rc = 0; + memset(act, 0, sizeof(struct vdev_action)); + + act->trigger = trigger; + act->path = vdev_strdup_or_null(path); + act->command = vdev_strdup_or_null(command); + act->helper = vdev_strdup_or_null(helper); + act->async = async; + + act->is_daemonlet = false; + act->daemonlet_stdin = -1; + act->daemonlet_stdout = -1; + act->daemonlet_pid = -1; + + if (act->path != NULL) { + + rc = vdev_match_regex_init(&act->path_regex, path); + + if (rc != 0) { + + vdev_error("vdev_match_regex_init('%s') rc = %d\n", + path, rc); + vdev_action_free(act); + return rc; + } + } + + return 0; } // add a device parameter to match on // return 0 on success // return -ENOMEM on OOM // return -EEXIST if name already exists -int vdev_action_add_param( struct vdev_action* act, char const* name, char const* value ) { - return vdev_params_add( &act->dev_params, name, value ); +int vdev_action_add_param(struct vdev_action *act, char const *name, + char const *value) +{ + return vdev_params_add(&act->dev_params, name, value); } - // add an environment variable to send to a helper // return 0 on success // return -ENOMEM on OOM // return -EEXIST if the name already exists -int vdev_action_add_var( struct vdev_action* act, char const* name, char const* value ) { - return vdev_params_add( &act->helper_vars, name, value ); +int vdev_action_add_var(struct vdev_action *act, char const *name, + char const *value) +{ + return vdev_params_add(&act->helper_vars, name, value); } // free an action // always succeeds // NOTE: does NOT touch the daemonlet state. -int vdev_action_free( struct vdev_action* act ) { - - if( act->name != NULL ) { - - free( act->name ); - act->name = NULL; - } - - if( act->command != NULL ) { - - free( act->command ); - act->command = NULL; - } - - if( act->rename_command != NULL ) { - - free( act->rename_command ); - act->rename_command = NULL; - } - - if( act->dev_params != NULL ) { - - vdev_params_free( act->dev_params ); - act->dev_params = NULL; - } - - if( act->helper_vars != NULL ) { - - vdev_params_free( act->helper_vars ); - act->helper_vars = NULL; - } - - if( act->helper != NULL ) { - - free( act->helper ); - act->helper = NULL; - } - - if( act->path != NULL ) { - - free( act->path ); - act->path = NULL; - - - regfree( &act->path_regex ); - } - - if( act->type != NULL ) { - - free( act->type ); - act->type = NULL; - } - - return 0; -} +int vdev_action_free(struct vdev_action *act) +{ + + if (act->name != NULL) { + + free(act->name); + act->name = NULL; + } + + if (act->command != NULL) { + + free(act->command); + act->command = NULL; + } + if (act->rename_command != NULL) { + + free(act->rename_command); + act->rename_command = NULL; + } + + if (act->dev_params != NULL) { + + vdev_params_free(act->dev_params); + act->dev_params = NULL; + } + + if (act->helper_vars != NULL) { + + vdev_params_free(act->helper_vars); + act->helper_vars = NULL; + } + + if (act->helper != NULL) { + + free(act->helper); + act->helper = NULL; + } + + if (act->path != NULL) { + + free(act->path); + act->path = NULL; + + regfree(&act->path_regex); + } + + if (act->type != NULL) { + + free(act->type); + act->type = NULL; + } + + return 0; +} // convert an action into a device request // return the constant associated with the type on success // return VDEV_DEVICE_INVALID if the type is not recognized -vdev_device_request_t vdev_action_parse_trigger( char const* type ) { - - if( strcmp(type, VDEV_ACTION_EVENT_ADD) == 0 ) { - return VDEV_DEVICE_ADD; - } - else if( strcmp(type, VDEV_ACTION_EVENT_REMOVE) == 0 ) { - return VDEV_DEVICE_REMOVE; - } - else if( strcmp(type, VDEV_ACTION_EVENT_CHANGE) == 0 ) { - return VDEV_DEVICE_CHANGE; - } - else if( strcmp(type, VDEV_ACTION_EVENT_ANY) == 0 ) { - return VDEV_DEVICE_ANY; - } - - return VDEV_DEVICE_INVALID; +vdev_device_request_t vdev_action_parse_trigger(char const *type) +{ + + if (strcmp(type, VDEV_ACTION_EVENT_ADD) == 0) { + return VDEV_DEVICE_ADD; + } else if (strcmp(type, VDEV_ACTION_EVENT_REMOVE) == 0) { + return VDEV_DEVICE_REMOVE; + } else if (strcmp(type, VDEV_ACTION_EVENT_CHANGE) == 0) { + return VDEV_DEVICE_CHANGE; + } else if (strcmp(type, VDEV_ACTION_EVENT_ANY) == 0) { + return VDEV_DEVICE_ANY; + } + + return VDEV_DEVICE_INVALID; } // parse an action from an ini file // return 1 for parsed // return 0 for not parsed -static int vdev_action_ini_parser( void* userdata, char const* section, char const* name, char const* value ) { - - struct vdev_action* act = (struct vdev_action*)userdata; - int rc = 0; - - if( strcmp(section, VDEV_ACTION_NAME) == 0 ) { - - if( strcmp(name, VDEV_ACTION_NAME_PATH) == 0 ) { - // path? - if( act->path != NULL ) { - - free( act->path ); - } - - act->path = vdev_strdup_or_null( value ); - - if( act->path == NULL ) { - // EOM - return 0; - } - else { - rc = vdev_match_regex_init( &act->path_regex, act->path ); - - if( rc != 0 ) { - - vdev_error("vdev_match_regex_init('%s') rc = %d\n", act->path, rc ); - return 0; - } - } - return 1; - } - - if( strcmp(name, VDEV_ACTION_NAME_RENAME) == 0 ) { - - // rename command - if( act->rename_command != NULL ) { - - free( act->rename_command ); - } - - act->rename_command = vdev_strdup_or_null( value ); - return 1; - } - - if( strcmp(name, VDEV_ACTION_NAME_EVENT) == 0 ) { - - // event? - act->trigger = vdev_action_parse_trigger( value ); - - if( act->trigger == VDEV_DEVICE_INVALID ) { - - fprintf(stderr, "Invalid event type '%s'\n", value); - return 0; - } - else { - return 1; - } - } - - if( strcmp(name, VDEV_ACTION_NAME_COMMAND) == 0 ) { - - // shell command - if( act->command != NULL ) { - - free( act->command ); - } - - act->command = vdev_strdup_or_null( value ); - return 1; - } - - if( strcmp(name, VDEV_ACTION_NAME_HELPER) == 0 ) { - - // helper in /lib/vdev - if( act->helper != NULL ) { - - free( act->helper ); - } - - act->helper = vdev_strdup_or_null( value ); - return 1; - } - - if( strcmp(name, VDEV_ACTION_NAME_ASYNC) == 0 ) { - - // async? - if( strcasecmp(value, "true") == 0 || strcmp(value, "1") == 0 ) { - - act->async = true; - return 1; - } - else if( strcasecmp(value, "false") == 0 || strcmp(value, "0") == 0 ) { - - act->async = false; - return 1; - } - else { - - fprintf(stderr, "Invalid async value '%s'\n", value); - return 0; - } - } - - if( strcmp(name, VDEV_ACTION_NAME_TYPE) == 0 ) { - - // remember this - act->has_type = true; - act->type = vdev_strdup_or_null( value ); - return 1; - } - - if( strcmp(name, VDEV_ACTION_NAME_IF_EXISTS) == 0 ) { - - // if-exists flag - if( strcmp( value, VDEV_ACTION_IF_EXISTS_ERROR ) == 0 ) { - - act->if_exists = VDEV_IF_EXISTS_ERROR; - return 1; - } - - if( strcmp( value, VDEV_ACTION_IF_EXISTS_MASK ) == 0 ) { - - act->if_exists = VDEV_IF_EXISTS_MASK; - return 1; - } - - if( strcmp( value, VDEV_ACTION_IF_EXISTS_RUN ) == 0 ) { - - act->if_exists = VDEV_IF_EXISTS_RUN; - return 1; - } - - fprintf(stderr, "Invalid '%s' value '%s'\n", name, value ); - return 0; - } - - if( strcmp(name, VDEV_ACTION_DAEMONLET) == 0 ) { - - // this is a daemonlet - if( strcasecmp( value, "true" ) == 0 ) { - - act->is_daemonlet = true; - } - - return 1; - } - - if( strncmp(name, VDEV_ACTION_NAME_OS_PREFIX, strlen(VDEV_ACTION_NAME_OS_PREFIX)) == 0 ) { - - // OS-specific param - rc = vdev_action_add_param( act, name + strlen(VDEV_ACTION_NAME_OS_PREFIX), value ); - - if( rc == 0 ) { - return 1; - } - else { - vdev_error("vdev_action_add_param( '%s', '%s' ) rc = %d\n", name, value, rc ); - return 0; - } - } - - if( strncmp(name, VDEV_ACTION_NAME_VAR_PREFIX, strlen(VDEV_ACTION_NAME_VAR_PREFIX)) == 0 ) { - - // helper-specific variable - rc = vdev_action_add_var( act, name + strlen(VDEV_ACTION_NAME_VAR_PREFIX), value ); - - if( rc == 0 ) { - return 1; - } - else { - vdev_error("vdev_action_add_var( '%s', '%s' ) rc = %d\n", name, value, rc ); - return 0; - } - } - fprintf(stderr, "Unknown field '%s' in section '%s'\n", name, section ); - return 0; - } - - fprintf(stderr, "Unknown section '%s'\n", section); - return 0; +static int vdev_action_ini_parser(void *userdata, char const *section, + char const *name, char const *value) +{ + + struct vdev_action *act = (struct vdev_action *)userdata; + int rc = 0; + + if (strcmp(section, VDEV_ACTION_NAME) == 0) { + + if (strcmp(name, VDEV_ACTION_NAME_PATH) == 0) { + // path? + if (act->path != NULL) { + + free(act->path); + } + + act->path = vdev_strdup_or_null(value); + + if (act->path == NULL) { + // EOM + return 0; + } else { + rc = vdev_match_regex_init(&act->path_regex, + act->path); + + if (rc != 0) { + + vdev_error + ("vdev_match_regex_init('%s') rc = %d\n", + act->path, rc); + return 0; + } + } + return 1; + } + + if (strcmp(name, VDEV_ACTION_NAME_RENAME) == 0) { + + // rename command + if (act->rename_command != NULL) { + + free(act->rename_command); + } + + act->rename_command = vdev_strdup_or_null(value); + return 1; + } + + if (strcmp(name, VDEV_ACTION_NAME_EVENT) == 0) { + + // event? + act->trigger = vdev_action_parse_trigger(value); + + if (act->trigger == VDEV_DEVICE_INVALID) { + + fprintf(stderr, "Invalid event type '%s'\n", + value); + return 0; + } else { + return 1; + } + } + + if (strcmp(name, VDEV_ACTION_NAME_COMMAND) == 0) { + + // shell command + if (act->command != NULL) { + + free(act->command); + } + + act->command = vdev_strdup_or_null(value); + return 1; + } + + if (strcmp(name, VDEV_ACTION_NAME_HELPER) == 0) { + + // helper in /lib/vdev + if (act->helper != NULL) { + + free(act->helper); + } + + act->helper = vdev_strdup_or_null(value); + return 1; + } + + if (strcmp(name, VDEV_ACTION_NAME_ASYNC) == 0) { + + // async? + if (strcasecmp(value, "true") == 0 + || strcmp(value, "1") == 0) { + + act->async = true; + return 1; + } else if (strcasecmp(value, "false") == 0 + || strcmp(value, "0") == 0) { + + act->async = false; + return 1; + } else { + + fprintf(stderr, "Invalid async value '%s'\n", + value); + return 0; + } + } + + if (strcmp(name, VDEV_ACTION_NAME_TYPE) == 0) { + + // remember this + act->has_type = true; + act->type = vdev_strdup_or_null(value); + return 1; + } + + if (strcmp(name, VDEV_ACTION_NAME_IF_EXISTS) == 0) { + + // if-exists flag + if (strcmp(value, VDEV_ACTION_IF_EXISTS_ERROR) == 0) { + + act->if_exists = VDEV_IF_EXISTS_ERROR; + return 1; + } + + if (strcmp(value, VDEV_ACTION_IF_EXISTS_MASK) == 0) { + + act->if_exists = VDEV_IF_EXISTS_MASK; + return 1; + } + + if (strcmp(value, VDEV_ACTION_IF_EXISTS_RUN) == 0) { + + act->if_exists = VDEV_IF_EXISTS_RUN; + return 1; + } + + fprintf(stderr, "Invalid '%s' value '%s'\n", name, + value); + return 0; + } + + if (strcmp(name, VDEV_ACTION_DAEMONLET) == 0) { + + // this is a daemonlet + if (strcasecmp(value, "true") == 0) { + + act->is_daemonlet = true; + } + + return 1; + } + + if (strncmp + (name, VDEV_ACTION_NAME_OS_PREFIX, + strlen(VDEV_ACTION_NAME_OS_PREFIX)) == 0) { + + // OS-specific param + rc = vdev_action_add_param(act, + name + + strlen + (VDEV_ACTION_NAME_OS_PREFIX), + value); + + if (rc == 0) { + return 1; + } else { + vdev_error + ("vdev_action_add_param( '%s', '%s' ) rc = %d\n", + name, value, rc); + return 0; + } + } + + if (strncmp + (name, VDEV_ACTION_NAME_VAR_PREFIX, + strlen(VDEV_ACTION_NAME_VAR_PREFIX)) == 0) { + + // helper-specific variable + rc = vdev_action_add_var(act, + name + + strlen + (VDEV_ACTION_NAME_VAR_PREFIX), + value); + + if (rc == 0) { + return 1; + } else { + vdev_error + ("vdev_action_add_var( '%s', '%s' ) rc = %d\n", + name, value, rc); + return 0; + } + } + fprintf(stderr, "Unknown field '%s' in section '%s'\n", name, + section); + return 0; + } + + fprintf(stderr, "Unknown section '%s'\n", section); + return 0; } // sanity check an action // return 0 on success // return -EINVAL if invalid -int vdev_action_sanity_check( struct vdev_action* act ) { - - int rc = 0; - - if( act->command == NULL && act->rename_command == NULL && act->helper == NULL ) { - - fprintf(stderr, "Action is missing 'command=', 'rename_command=', and 'helper='\n"); - rc = -EINVAL; - } - - if( act->command != NULL && act->helper != NULL ) { - - fprintf(stderr, "Action has both 'command=' and 'helper='\n"); - rc = -EINVAL; - } - - if( act->trigger == VDEV_DEVICE_INVALID ) { - - fprintf(stderr, "Action is missing 'event='\n"); - rc = -EINVAL; - } - - return rc; -} +int vdev_action_sanity_check(struct vdev_action *act) +{ + + int rc = 0; + + if (act->command == NULL && act->rename_command == NULL + && act->helper == NULL) { + fprintf(stderr, + "Action is missing 'command=', 'rename_command=', and 'helper='\n"); + rc = -EINVAL; + } + + if (act->command != NULL && act->helper != NULL) { + + fprintf(stderr, "Action has both 'command=' and 'helper='\n"); + rc = -EINVAL; + } + + if (act->trigger == VDEV_DEVICE_INVALID) { + + fprintf(stderr, "Action is missing 'event='\n"); + rc = -EINVAL; + } + + return rc; +} // perform misc. post-processing on an action: // * if the command is NULL but the helper is not, then set command to be the full path to the helper, and don't use a shell // return 0 on success // return -ENOMEM on OOM -int vdev_action_postprocess( struct vdev_config* config, struct vdev_action* act ) { - - int rc = 0; - - if( act->command == NULL && act->helper != NULL ) { - - act->command = VDEV_CALLOC( char, strlen(config->helpers_dir) + 1 + strlen(act->helper) + 1 ); - if( act->command == NULL ) { - return -ENOMEM; - } - - sprintf( act->command, "%s/%s", config->helpers_dir, act->helper ); - - act->use_shell = false; - } - else { - - // given a shell command string - act->use_shell = true; - } - - return rc; +int vdev_action_postprocess(struct vdev_config *config, struct vdev_action *act) +{ + + int rc = 0; + + if (act->command == NULL && act->helper != NULL) { + + act->command = + VDEV_CALLOC(char, + strlen(config->helpers_dir) + 1 + + strlen(act->helper) + 1); + if (act->command == NULL) { + return -ENOMEM; + } + + sprintf(act->command, "%s/%s", config->helpers_dir, + act->helper); + + act->use_shell = false; + } else { + + // given a shell command string + act->use_shell = true; + } + + return rc; } // load an action from a file // return 0 on success // return -errno on failure to open, read, parse, or close // return -EINVAL if the loaded action fails our sanity tests -int vdev_action_load_file( struct vdev_config* config, char const* path, struct vdev_action* act, FILE* f ) { - - int rc = 0; - - rc = ini_parse_file( f, vdev_action_ini_parser, act ); - if( rc != 0 ) { - vdev_error("ini_parse_file(action) rc = %d\n", rc ); - } - else { - rc = vdev_action_sanity_check( act ); - if( rc != 0 ) { - vdev_error("Invalid action '%s'\n", path ); - } - } - - if( rc == 0 ) { - - // postprocess - rc = vdev_action_postprocess( config, act ); - } - return rc; +int vdev_action_load_file(struct vdev_config *config, char const *path, + struct vdev_action *act, FILE * f) +{ + + int rc = 0; + + rc = ini_parse_file(f, vdev_action_ini_parser, act); + if (rc != 0) { + vdev_error("ini_parse_file(action) rc = %d\n", rc); + } else { + rc = vdev_action_sanity_check(act); + if (rc != 0) { + vdev_error("Invalid action '%s'\n", path); + } + } + + if (rc == 0) { + + // postprocess + rc = vdev_action_postprocess(config, act); + } + return rc; } - // load an action from a path // return -ENOMEM if OOM // return -errno on failure to open or read the file // return -EINVAL if the file could not be parsed -int vdev_action_load( struct vdev_config* config, char const* path, struct vdev_action* act ) { - - int rc = 0; - FILE* f = NULL; - - rc = vdev_action_init( act, VDEV_DEVICE_INVALID, NULL, NULL, NULL, false ); - if( rc != 0 ) { - - vdev_error("vdev_action_init('%s') rc = %d\n", path, rc ); - return rc; - } - - f = fopen( path, "r" ); - if( f == NULL ) { - - vdev_action_free( act ); - rc = -errno; - - return rc; - } - - rc = vdev_action_load_file( config, path, act, f ); - - fclose( f ); - - if( rc == -EINVAL ) { - - vdev_action_free( act ); - vdev_error("Invalid action '%s'\n", path ); - } - else if( rc == 0 ) { - - // store the name - act->name = vdev_strdup_or_null( path ); - if( act->name == NULL ) { - - // OOM - vdev_action_free( act ); - rc = -ENOMEM; - } - } - - return rc; -} +int vdev_action_load(struct vdev_config *config, char const *path, + struct vdev_action *act) +{ + + int rc = 0; + FILE *f = NULL; + + rc = vdev_action_init(act, VDEV_DEVICE_INVALID, NULL, NULL, NULL, + false); + if (rc != 0) { + + vdev_error("vdev_action_init('%s') rc = %d\n", path, rc); + return rc; + } + + f = fopen(path, "r"); + if (f == NULL) { + + vdev_action_free(act); + rc = -errno; + + return rc; + } + rc = vdev_action_load_file(config, path, act, f); + + fclose(f); + + if (rc == -EINVAL) { + + vdev_action_free(act); + vdev_error("Invalid action '%s'\n", path); + } else if (rc == 0) { + + // store the name + act->name = vdev_strdup_or_null(path); + if (act->name == NULL) { + + // OOM + vdev_action_free(act); + rc = -ENOMEM; + } + } + + return rc; +} // free a C-style list of actions (including the list itself) // always succeeds -int vdev_action_free_all( struct vdev_action* act_list, size_t num_acts ) { - - int rc = 0; - - for( unsigned int i = 0; i < num_acts; i++ ) { - - rc = vdev_action_free( &act_list[i] ); - if( rc != 0 ) { - return rc; - } - } - - free( act_list ); - - return rc; -} +int vdev_action_free_all(struct vdev_action *act_list, size_t num_acts) +{ + + int rc = 0; + + for (unsigned int i = 0; i < num_acts; i++) { + + rc = vdev_action_free(&act_list[i]); + if (rc != 0) { + return rc; + } + } + free(act_list); + + return rc; +} // action loader // return 0 on success // return -errno on failure to stat(2) // return -EINVAL if the file is invalid // return -ENOMEM if OOM -int vdev_action_loader( char const* path, void* cls ) { - - int rc = 0; - struct vdev_action act; - struct stat sb; - struct vdev_action_loader_cls* loader_cls = (struct vdev_action_loader_cls*)cls; - - struct sglib_vdev_action_vector* acts = loader_cls->acts; - struct vdev_config* config = loader_cls->config; - - // skip if not a regular file - rc = stat( path, &sb ); - if( rc != 0 ) { - - rc = -errno; - vdev_error("stat(%s) rc = %d\n", path, rc ); - return rc; - } - - if( !S_ISREG( sb.st_mode ) ) { - - return 0; - } - - vdev_debug("Load Action %s\n", path ); - - memset( &act, 0, sizeof(struct vdev_action) ); - - rc = vdev_action_load( config, path, &act ); - if( rc != 0 ) { - - vdev_error("vdev_acl_load(%s) rc = %d\n", path, rc ); - return rc; - } - - // save this action - rc = sglib_vdev_action_vector_push_back( acts, act ); - if( rc != 0 ) { - - // OOM - vdev_action_free( &act ); - return rc; - } - - return 0; +int vdev_action_loader(char const *path, void *cls) +{ + + int rc = 0; + struct vdev_action act; + struct stat sb; + struct vdev_action_loader_cls *loader_cls = + (struct vdev_action_loader_cls *)cls; + + struct sglib_vdev_action_vector *acts = loader_cls->acts; + struct vdev_config *config = loader_cls->config; + + // skip if not a regular file + rc = stat(path, &sb); + if (rc != 0) { + + rc = -errno; + vdev_error("stat(%s) rc = %d\n", path, rc); + return rc; + } + + if (!S_ISREG(sb.st_mode)) { + + return 0; + } + + vdev_debug("Load Action %s\n", path); + + memset(&act, 0, sizeof(struct vdev_action)); + + rc = vdev_action_load(config, path, &act); + if (rc != 0) { + + vdev_error("vdev_acl_load(%s) rc = %d\n", path, rc); + return rc; + } + // save this action + rc = sglib_vdev_action_vector_push_back(acts, act); + if (rc != 0) { + + // OOM + vdev_action_free(&act); + return rc; + } + + return 0; } // free a vector of actions // always succeeds -static int vdev_action_vector_free( struct sglib_vdev_action_vector* acts ) { - - for( unsigned long i = 0; i < sglib_vdev_action_vector_size( acts ); i++ ) { - - struct vdev_action* act = sglib_vdev_action_vector_at_ref( acts, i ); - - vdev_action_free( act ); - } - - sglib_vdev_action_vector_clear( acts ); - return 0; -} +static int vdev_action_vector_free(struct sglib_vdev_action_vector *acts) +{ + + for (unsigned long i = 0; i < sglib_vdev_action_vector_size(acts); i++) { + struct vdev_action *act = + sglib_vdev_action_vector_at_ref(acts, i); + + vdev_action_free(act); + } + + sglib_vdev_action_vector_clear(acts); + return 0; +} // load all actions in a directory // return 0 on success // return -ENOMEM if OOM // return -EINVAL if at least one action file failed to load due to a sanity test failure // return -errno if at least one action file failed to load due to an I/O error -int vdev_action_load_all( struct vdev_config* config, struct vdev_action** ret_acts, size_t* ret_num_acts ) { - - int rc = 0; - struct vdev_action_loader_cls loader_cls; - struct sglib_vdev_action_vector acts; - - sglib_vdev_action_vector_init( &acts ); - - loader_cls.acts = &acts; - loader_cls.config = config; - - rc = vdev_load_all( config->acts_dir, vdev_action_loader, &loader_cls ); - - if( rc != 0 ) { - - vdev_action_vector_free( &acts ); - sglib_vdev_action_vector_free( &acts ); - - return rc; - } - else { - - if( sglib_vdev_action_vector_size( &acts ) == 0 ) { - - // nothing - *ret_acts = NULL; - *ret_num_acts = 0; - } - else { - - // extract values - unsigned long len_acts = 0; - - sglib_vdev_action_vector_yoink( &acts, ret_acts, &len_acts ); - - *ret_num_acts = len_acts; - } - } - - return 0; -} +int vdev_action_load_all(struct vdev_config *config, + struct vdev_action **ret_acts, size_t * ret_num_acts) +{ + + int rc = 0; + struct vdev_action_loader_cls loader_cls; + struct sglib_vdev_action_vector acts; + + sglib_vdev_action_vector_init(&acts); + + loader_cls.acts = &acts; + loader_cls.config = config; + rc = vdev_load_all(config->acts_dir, vdev_action_loader, &loader_cls); + + if (rc != 0) { + + vdev_action_vector_free(&acts); + sglib_vdev_action_vector_free(&acts); + + return rc; + } else { + + if (sglib_vdev_action_vector_size(&acts) == 0) { + + // nothing + *ret_acts = NULL; + *ret_num_acts = 0; + } else { + + // extract values + unsigned long len_acts = 0; + + sglib_vdev_action_vector_yoink(&acts, ret_acts, + &len_acts); + + *ret_num_acts = len_acts; + } + } + + return 0; +} // carry out a command, synchronously, using an environment given by vreq. // stdout will be captured to *output // return the exit status on success (non-negative) // return negative on error -int vdev_action_run_sync( struct vdev_device_request* vreq, char const* command, vdev_params* helper_vars, bool use_shell, char** output, size_t max_output ) { - - int rc = 0; - int exit_status = 0; - char** req_env = NULL; - size_t num_env = 0; - - // convert to environment variables - rc = vdev_device_request_to_env( vreq, helper_vars, &req_env, &num_env, 0 ); - if( rc != 0 ) { - - vdev_error("vdev_device_request_to_env(%s) rc = %d\n", vreq->path, rc ); - return rc; - } - - vdev_debug("run command: '%s'\n", command ); - - for( unsigned int i = 0; i < num_env; i++ ) { - vdev_debug("command env: '%s'\n", req_env[i] ); - } - - rc = vdev_subprocess( command, req_env, output, max_output, vreq->state->error_fd, &exit_status, use_shell ); - - vdev_debug("exit status %d\n", exit_status ); - - if( output != NULL && *output != NULL ) { - - vdev_debug("command output: '%s'\n", *output ); - } - - VDEV_FREE_LIST( req_env ); - - if( rc != 0 ) { - - vdev_error("vdev_subprocess('%s', use_shell=%d) rc = %d\n", command, use_shell, rc ); - - return rc; - } - - if( exit_status != 0 ) { - - vdev_error("vdev_subprocess('%s', use_shell=%d) exit status = %d\n", command, use_shell, exit_status ); - } - - return exit_status; -} +int vdev_action_run_sync(struct vdev_device_request *vreq, char const *command, + vdev_params * helper_vars, bool use_shell, + char **output, size_t max_output) +{ + + int rc = 0; + int exit_status = 0; + char **req_env = NULL; + size_t num_env = 0; + + // convert to environment variables + rc = vdev_device_request_to_env(vreq, helper_vars, &req_env, &num_env, + 0); + if (rc != 0) { + + vdev_error("vdev_device_request_to_env(%s) rc = %d\n", + vreq->path, rc); + return rc; + } + vdev_debug("run command: '%s'\n", command); + + for (unsigned int i = 0; i < num_env; i++) { + vdev_debug("command env: '%s'\n", req_env[i]); + } + + rc = vdev_subprocess(command, req_env, output, max_output, + vreq->state->error_fd, &exit_status, use_shell); + + vdev_debug("exit status %d\n", exit_status); + + if (output != NULL && *output != NULL) { + + vdev_debug("command output: '%s'\n", *output); + } + + VDEV_FREE_LIST(req_env); + + if (rc != 0) { + + vdev_error("vdev_subprocess('%s', use_shell=%d) rc = %d\n", + command, use_shell, rc); + + return rc; + } + + if (exit_status != 0) { + + vdev_error + ("vdev_subprocess('%s', use_shell=%d) exit status = %d\n", + command, use_shell, exit_status); + } + + return exit_status; +} // carry out an action, asynchronously. // fork, setsid, fork, and exec, so the helper gets reparented to init. // return 0 if we were able to fork // return -errno on failure to fork // TODO: configurable interpreter (defaults to /bin/dash) -int vdev_action_run_async( struct vdev_device_request* req, char const* command, vdev_params* helper_vars, bool use_shell ) { - - int rc = 0; - pid_t pid = 0; - pid_t sid = 0; - int max_fd = 0; - - // generate the environment - char** env = NULL; - size_t num_env = 0; - - rc = vdev_device_request_to_env( req, helper_vars, &env, &num_env, 0 ); - if( rc != 0 ) { - - // NOTE: must be async-safe! - vdev_error("vdev_device_request_to_env rc = %d\n", rc); - return rc; - } - - vdev_debug("run command async: '%s'\n", command ); - - for( unsigned int i = 0; i < num_env; i++ ) { - vdev_debug("command async env: '%s'\n", env[i] ); - } - - pid = fork(); - - if( pid == 0 ) { - - // child - // detach from parent - sid = setsid(); - if( sid < 0 ) { - - rc = -errno; - - // NOTE: must be async-safe! - vdev_error_async_safe("setsid failed\n" ); - exit(1); - } - - pid = fork(); - - if( pid == 0 ) { - - // fully detached - max_fd = sysconf(_SC_OPEN_MAX); - if( max_fd < 0 ) { - - // should be big enough... - max_fd = 1024; - } - - // close everything except stderr, which should be directed to our log - for( int i = 0; i < max_fd; i++ ) { - if( i != STDERR_FILENO ) { - close( i ); - } - } - - clearenv(); - - // run the command - if( use_shell ) { - execle( "/bin/dash", "dash", "-c", command, (char*)0, env ); - } - else { - execle( command, command, (char*)0, env ); - } - - // keep gcc happy - exit(0); - } - else if( pid > 0 ) { - - exit(0); - } - else { - - rc = -errno; - vdev_error_async_safe("fork() failed\n"); - exit(-rc); - } - } - else if( pid > 0 ) { - - rc = 0; - - VDEV_FREE_LIST( env ); - - // parent; succeeded - // wait for intermediate process - pid_t child_pid = waitpid( pid, &rc, 0 ); - if( child_pid < 0 ) { - - rc = -errno; - vdev_error("waitpid(%d) rc = %d\n", pid, rc ); - return rc; - } - else if( WIFEXITED( rc ) && WEXITSTATUS( rc ) != 0 ) { - - rc = -WEXITSTATUS( rc ); - vdev_error("fork() rc = %d\n", rc ); - } - - return rc; - } - else { - - // error - rc = -errno; - - VDEV_FREE_LIST( env ); - - vdev_error("fork() rc = %d\n", rc); - - return rc; - } -} +int vdev_action_run_async(struct vdev_device_request *req, char const *command, + vdev_params * helper_vars, bool use_shell) +{ + + int rc = 0; + pid_t pid = 0; + pid_t sid = 0; + int max_fd = 0; + + // generate the environment + char **env = NULL; + size_t num_env = 0; + + rc = vdev_device_request_to_env(req, helper_vars, &env, &num_env, 0); + if (rc != 0) { + + // NOTE: must be async-safe! + vdev_error("vdev_device_request_to_env rc = %d\n", rc); + return rc; + } + + vdev_debug("run command async: '%s'\n", command); + + for (unsigned int i = 0; i < num_env; i++) { + vdev_debug("command async env: '%s'\n", env[i]); + } + + pid = fork(); + + if (pid == 0) { + + // child + // detach from parent + sid = setsid(); + if (sid < 0) { + + rc = -errno; + + // NOTE: must be async-safe! + vdev_error_async_safe("setsid failed\n"); + exit(1); + } + + pid = fork(); + + if (pid == 0) { + // fully detached + max_fd = sysconf(_SC_OPEN_MAX); + if (max_fd < 0) { + + // should be big enough... + max_fd = 1024; + } + // close everything except stderr, which should be directed to our log + for (int i = 0; i < max_fd; i++) { + if (i != STDERR_FILENO) { + close(i); + } + } + + clearenv(); + + // run the command + if (use_shell) { + execle("/bin/dash", "dash", "-c", command, + (char *)0, env); + } else { + execle(command, command, (char *)0, env); + } + + // keep gcc happy + exit(0); + } else if (pid > 0) { + + exit(0); + } else { + + rc = -errno; + vdev_error_async_safe("fork() failed\n"); + exit(-rc); + } + } else if (pid > 0) { + + rc = 0; + + VDEV_FREE_LIST(env); + + // parent; succeeded + // wait for intermediate process + pid_t child_pid = waitpid(pid, &rc, 0); + if (child_pid < 0) { + + rc = -errno; + vdev_error("waitpid(%d) rc = %d\n", pid, rc); + return rc; + } else if (WIFEXITED(rc) && WEXITSTATUS(rc) != 0) { + + rc = -WEXITSTATUS(rc); + vdev_error("fork() rc = %d\n", rc); + } + + return rc; + } else { + + // error + rc = -errno; + + VDEV_FREE_LIST(env); + + vdev_error("fork() rc = %d\n", rc); + + return rc; + } +} // clean up a daemonlet's state in an action // always succeeds -static int vdev_action_daemonlet_clean( struct vdev_action* act ) { - - // dead - act->daemonlet_pid = -1; - - if( act->daemonlet_stdin >= 0 ) { - close( act->daemonlet_stdin ); - act->daemonlet_stdin = -1; - } - - if( act->daemonlet_stdout >= 0 ) { - close( act->daemonlet_stdout ); - act->daemonlet_stdout = -1; - } - - return 0; +static int vdev_action_daemonlet_clean(struct vdev_action *act) +{ + + // dead + act->daemonlet_pid = -1; + + if (act->daemonlet_stdin >= 0) { + close(act->daemonlet_stdin); + act->daemonlet_stdin = -1; + } + + if (act->daemonlet_stdout >= 0) { + close(act->daemonlet_stdout); + act->daemonlet_stdout = -1; + } + + return 0; } // start up a daemonlet, using the daemonlet helper program at $VDEV_HELPERS/daemonlet. @@ -838,314 +875,324 @@ static int vdev_action_daemonlet_clean( struct vdev_action* act ) { // return -errno from fork(2) if we could not fork // return -ECHILD if the daemonlet died before it could signal readiness // NOTE: /dev/null *must* exist already--this should be taken care of by the pre-seed script. -static int vdev_action_daemonlet_start( struct vdev_state* state, struct vdev_action* act ) { - - int rc = 0; - pid_t pid = 0; - int daemonlet_pipe_stdin[2]; - int daemonlet_pipe_stdout[2]; - char daemonlet_runner_path[ PATH_MAX+1 ]; - char vdevd_global_metadata[ PATH_MAX+1 ]; - char null_path[ PATH_MAX+1 ]; - long max_open = sysconf( _SC_OPEN_MAX ); - struct stat sb; - struct vdev_config* config = state->config; - - char* daemonlet_argv[] = { - "vdevd-daemonlet", - act->command, - NULL - }; - - if( max_open <= 0 ) { - max_open = 1024; // a good guess - } - - if( act->daemonlet_pid > 0 ) { - return 0; - } - - memset( daemonlet_runner_path, 0, PATH_MAX+1 ); - memset( vdevd_global_metadata, 0, PATH_MAX+1 ); - - snprintf( daemonlet_runner_path, PATH_MAX, "%s/daemonlet", config->helpers_dir ); - snprintf( vdevd_global_metadata, PATH_MAX, "%s/" VDEV_METADATA_PREFIX, config->mountpoint ); - - // the daemonlet runner must exist - rc = stat( daemonlet_runner_path, &sb ); - if( rc != 0 ) { - - vdev_error("stat('%s') rc = %d\n", daemonlet_runner_path, rc ); - return rc; - } - - // the daemonlet runner must be executable - if( !S_ISREG( sb.st_mode ) || !(((S_IXUSR & sb.st_mode) && sb.st_uid == geteuid()) || ((S_IXGRP & sb.st_mode) && sb.st_gid == getegid()) || (S_IXOTH & sb.st_mode )) ) { - - vdev_error("%s is not a regular file, or is not executable for vdevd\n", daemonlet_runner_path ); - return -EPERM; - } - - rc = pipe( daemonlet_pipe_stdin ); - if( rc < 0 ) { - - rc = -errno; - vdev_error("pipe rc = %d\n", rc ); - return rc; - } - - rc = pipe( daemonlet_pipe_stdout ); - if( rc < 0 ) { - - rc = -errno; - vdev_error("pipe rc = %d\n", rc ); - - close( daemonlet_pipe_stdin[0] ); - close( daemonlet_pipe_stdin[1] ); - return rc; - } - - pid = fork(); - if( pid == 0 ) { - - // child - close( daemonlet_pipe_stdin[1] ); - close( daemonlet_pipe_stdout[0] ); - - // redirect - rc = dup2( daemonlet_pipe_stdin[0], STDIN_FILENO ); - if( rc < 0 ) { - - vdev_error_async_safe("dup2 stdin failed\n"); - exit(1); - } - - rc = dup2( daemonlet_pipe_stdout[1], STDOUT_FILENO ); - if( rc < 0 ) { - - vdev_error_async_safe("dup2 stdout to vdevd failed\n"); - _exit(1); - } - - rc = dup2( state->error_fd, STDERR_FILENO ); - if( rc < 0 ) { - - vdev_error_async_safe("dup2 stderr to null failed\n"); - _exit(1); - } - - // close everything else - // the daemonlet should capture stderr itself - for( int i = 3; i < max_open; i++ ) { - - close( i ); - } - - // set basic environment variables - clearenv(); - setenv( "VDEV_GLOBAL_METADATA", vdevd_global_metadata, 1 ); - setenv( "VDEV_MOUNTPOINT", config->mountpoint, 1 ); - setenv( "VDEV_HELPERS", config->helpers_dir, 1 ); - setenv( "VDEV_LOGFILE", config->logfile_path, 1 ); - setenv( "VDEV_CONFIG_FILE", config->config_path, 1 ); - setenv( "VDEV_INSTANCE", config->instance_str, 1 ); - - // start the daemonlet - execv( daemonlet_runner_path, daemonlet_argv ); - - // keep gcc happy - _exit(0); - } - else if( pid > 0 ) { - - // parent vdevd - close( daemonlet_pipe_stdin[0] ); - close( daemonlet_pipe_stdout[1] ); - - // wait for child to indicate readiness, if running synchronously - if( !act->async ) { - - while( 1 ) { - - char tmp = 0; - rc = vdev_read_uninterrupted( daemonlet_pipe_stdout[0], &tmp, 1 ); - - if( rc <= 0 ) { - - // some fatal error, or process has closed stdout - // not much we can safely do at this point (don't want to risk SIGKILL'ing) - close( daemonlet_pipe_stdin[1] ); - close( daemonlet_pipe_stdout[0] ); - - if( rc == 0 ) { - - // process has closed stdout - vdev_error("vdev_read_uninterrupted(%d PID=%d action='%s') rc = %d\n", daemonlet_pipe_stdout[0], pid, act->name, rc ); - rc = -ECHILD; - } - - return rc; - } - else { - - // got back readiness hint - break; - } - } - } - - // record runtime state - act->is_daemonlet = true; - act->daemonlet_pid = pid; - act->daemonlet_stdin = daemonlet_pipe_stdin[1]; - act->daemonlet_stdout = daemonlet_pipe_stdout[0]; - - // daemonlet started! - return 0; - } - else { - - // fork() error - rc = -errno; - vdev_error("fork() rc = %d\n", rc ); - - close( daemonlet_pipe_stdin[0] ); - close( daemonlet_pipe_stdin[1] ); - close( daemonlet_pipe_stdout[0] ); - close( daemonlet_pipe_stdout[1] ); - - return rc; - } +static int vdev_action_daemonlet_start(struct vdev_state *state, + struct vdev_action *act) +{ + + int rc = 0; + pid_t pid = 0; + int daemonlet_pipe_stdin[2]; + int daemonlet_pipe_stdout[2]; + char daemonlet_runner_path[PATH_MAX + 1]; + char vdevd_global_metadata[PATH_MAX + 1]; + char null_path[PATH_MAX + 1]; + long max_open = sysconf(_SC_OPEN_MAX); + struct stat sb; + struct vdev_config *config = state->config; + + char *daemonlet_argv[] = { + "vdevd-daemonlet", + act->command, + NULL + }; + + if (max_open <= 0) { + max_open = 1024; // a good guess + } + + if (act->daemonlet_pid > 0) { + return 0; + } + + memset(daemonlet_runner_path, 0, PATH_MAX + 1); + memset(vdevd_global_metadata, 0, PATH_MAX + 1); + + snprintf(daemonlet_runner_path, PATH_MAX, "%s/daemonlet", + config->helpers_dir); + snprintf(vdevd_global_metadata, PATH_MAX, "%s/" VDEV_METADATA_PREFIX, + config->mountpoint); + + // the daemonlet runner must exist + rc = stat(daemonlet_runner_path, &sb); + if (rc != 0) { + + vdev_error("stat('%s') rc = %d\n", daemonlet_runner_path, rc); + return rc; + } + // the daemonlet runner must be executable + if (!S_ISREG(sb.st_mode) + || !(((S_IXUSR & sb.st_mode) && sb.st_uid == geteuid()) + || ((S_IXGRP & sb.st_mode) && sb.st_gid == getegid()) + || (S_IXOTH & sb.st_mode))) { + + vdev_error + ("%s is not a regular file, or is not executable for vdevd\n", + daemonlet_runner_path); + return -EPERM; + } + + rc = pipe(daemonlet_pipe_stdin); + if (rc < 0) { + + rc = -errno; + vdev_error("pipe rc = %d\n", rc); + return rc; + } + + rc = pipe(daemonlet_pipe_stdout); + if (rc < 0) { + + rc = -errno; + vdev_error("pipe rc = %d\n", rc); + + close(daemonlet_pipe_stdin[0]); + close(daemonlet_pipe_stdin[1]); + return rc; + } + + pid = fork(); + if (pid == 0) { + + // child + close(daemonlet_pipe_stdin[1]); + close(daemonlet_pipe_stdout[0]); + + // redirect + rc = dup2(daemonlet_pipe_stdin[0], STDIN_FILENO); + if (rc < 0) { + + vdev_error_async_safe("dup2 stdin failed\n"); + exit(1); + } + + rc = dup2(daemonlet_pipe_stdout[1], STDOUT_FILENO); + if (rc < 0) { + + vdev_error_async_safe("dup2 stdout to vdevd failed\n"); + _exit(1); + } + + rc = dup2(state->error_fd, STDERR_FILENO); + if (rc < 0) { + + vdev_error_async_safe("dup2 stderr to null failed\n"); + _exit(1); + } + // close everything else + // the daemonlet should capture stderr itself + for (int i = 3; i < max_open; i++) { + + close(i); + } + + // set basic environment variables + clearenv(); + setenv("VDEV_GLOBAL_METADATA", vdevd_global_metadata, 1); + setenv("VDEV_MOUNTPOINT", config->mountpoint, 1); + setenv("VDEV_HELPERS", config->helpers_dir, 1); + setenv("VDEV_LOGFILE", config->logfile_path, 1); + setenv("VDEV_CONFIG_FILE", config->config_path, 1); + setenv("VDEV_INSTANCE", config->instance_str, 1); + + // start the daemonlet + execv(daemonlet_runner_path, daemonlet_argv); + + // keep gcc happy + _exit(0); + } else if (pid > 0) { + + // parent vdevd + close(daemonlet_pipe_stdin[0]); + close(daemonlet_pipe_stdout[1]); + + // wait for child to indicate readiness, if running synchronously + if (!act->async) { + + while (1) { + + char tmp = 0; + rc = vdev_read_uninterrupted + (daemonlet_pipe_stdout[0], &tmp, 1); + + if (rc <= 0) { + + // some fatal error, or process has closed stdout + // not much we can safely do at this point (don't want to risk SIGKILL'ing) + close(daemonlet_pipe_stdin[1]); + close(daemonlet_pipe_stdout[0]); + + if (rc == 0) { + + // process has closed stdout + vdev_error + ("vdev_read_uninterrupted(%d PID=%d action='%s') rc = %d\n", + daemonlet_pipe_stdout[0], + pid, act->name, rc); + rc = -ECHILD; + } + + return rc; + } else { + + // got back readiness hint + break; + } + } + } + // record runtime state + act->is_daemonlet = true; + act->daemonlet_pid = pid; + act->daemonlet_stdin = daemonlet_pipe_stdin[1]; + act->daemonlet_stdout = daemonlet_pipe_stdout[0]; + + // daemonlet started! + return 0; + } else { + + // fork() error + rc = -errno; + vdev_error("fork() rc = %d\n", rc); + + close(daemonlet_pipe_stdin[0]); + close(daemonlet_pipe_stdin[1]); + close(daemonlet_pipe_stdout[0]); + close(daemonlet_pipe_stdout[1]); + + return rc; + } } - // stop a daemonlet and join with it // first, ask it by writing "exit" to its stdin pipe. // wait 30 seconds before SIGTERM'ing the daemonlet. // return 0 on success, even if the daemonlet is already dead -static int vdev_action_daemonlet_stop( struct vdev_action* act ) { - - int rc = 0; - pid_t child_pid = 0; - struct timespec timeout; - struct timespec stop_deadline; - sigset_t sigchld_sigset; - siginfo_t sigchld_info; - - timeout.tv_sec = 30; - timeout.tv_nsec = 0; - - if( act->daemonlet_pid <= 0 || act->daemonlet_stdin < 0 || act->daemonlet_stdout < 0 ) { - // not running - return 0; - } - - // confirm that it is still running by trying to join with it - child_pid = waitpid( act->daemonlet_pid, &rc, WNOHANG ); - if( child_pid == act->daemonlet_pid || child_pid < 0 ) { - - // joined, or not running - vdev_debug("Daemonlet %d (%s) dead\n", act->daemonlet_pid, act->name ); - vdev_action_daemonlet_clean( act ); - return 0; - } - - // ask it to die: close stdin - rc = close( act->daemonlet_stdin ); - - if( rc < 0 ) { - - vdev_error("close(%d PID=%d name=%s) rc = %d\n", act->daemonlet_stdin, act->daemonlet_pid, act->name, rc ); - act->daemonlet_stdin = -1; - - // no choice but to kill this one - kill( act->daemonlet_pid, SIGTERM ); - vdev_action_daemonlet_clean( act ); - - // join with it... - rc = 0; - } - else { - - // tell daemonlet to die - rc = kill( act->daemonlet_pid, SIGINT ); - if( rc < 0 ) { - - vdev_error("kill(PID=%d name=%s) rc = %d\n", act->daemonlet_pid, act->name, rc ); - } - - // will wait for the child to die - act->daemonlet_stdin = -1; - } - - // join with it. - while( 1 ) { - - // attempt to join - child_pid = waitpid( act->daemonlet_pid, &rc, 0 ); - - if( child_pid < 0 ) { - - rc = -errno; - if( rc == -ECHILD ) { - - // already dead - rc = 0; - vdev_debug("Daemonlet %d (%s) dead\n", act->daemonlet_pid, act->name ); - vdev_action_daemonlet_clean( act ); - break; - } - else if( rc == -EINTR ) { - - // unhandled signal *or* SIGCHLD - child_pid = waitpid( act->daemonlet_pid, &rc, WNOHANG ); - if( child_pid > 0 ) { - - // child died - break; - } - else { - - // try waiting again - continue; - } - } - } - else if( child_pid > 0 ) { - - // joined! - break; - } - } - - // clean this child out (even if we had an error with waitpid) - vdev_debug("Daemonlet %d (%s) dead\n", act->daemonlet_pid, act->name ); - vdev_action_daemonlet_clean( act ); - - return rc; +static int vdev_action_daemonlet_stop(struct vdev_action *act) +{ + + int rc = 0; + pid_t child_pid = 0; + struct timespec timeout; + struct timespec stop_deadline; + sigset_t sigchld_sigset; + siginfo_t sigchld_info; + + timeout.tv_sec = 30; + timeout.tv_nsec = 0; + + if (act->daemonlet_pid <= 0 || act->daemonlet_stdin < 0 + || act->daemonlet_stdout < 0) { + // not running + return 0; + } + // confirm that it is still running by trying to join with it + child_pid = waitpid(act->daemonlet_pid, &rc, WNOHANG); + if (child_pid == act->daemonlet_pid || child_pid < 0) { + + // joined, or not running + vdev_debug("Daemonlet %d (%s) dead\n", act->daemonlet_pid, + act->name); + vdev_action_daemonlet_clean(act); + return 0; + } + // ask it to die: close stdin + rc = close(act->daemonlet_stdin); + + if (rc < 0) { + + vdev_error("close(%d PID=%d name=%s) rc = %d\n", + act->daemonlet_stdin, act->daemonlet_pid, act->name, + rc); + act->daemonlet_stdin = -1; + + // no choice but to kill this one + kill(act->daemonlet_pid, SIGTERM); + vdev_action_daemonlet_clean(act); + + // join with it... + rc = 0; + } else { + + // tell daemonlet to die + rc = kill(act->daemonlet_pid, SIGINT); + if (rc < 0) { + + vdev_error("kill(PID=%d name=%s) rc = %d\n", + act->daemonlet_pid, act->name, rc); + } + // will wait for the child to die + act->daemonlet_stdin = -1; + } + + // join with it. + while (1) { + + // attempt to join + child_pid = waitpid(act->daemonlet_pid, &rc, 0); + + if (child_pid < 0) { + + rc = -errno; + if (rc == -ECHILD) { + + // already dead + rc = 0; + vdev_debug("Daemonlet %d (%s) dead\n", + act->daemonlet_pid, act->name); + vdev_action_daemonlet_clean(act); + break; + } else if (rc == -EINTR) { + + // unhandled signal *or* SIGCHLD + child_pid = + waitpid(act->daemonlet_pid, &rc, WNOHANG); + if (child_pid > 0) { + + // child died + break; + } else { + + // try waiting again + continue; + } + } + } else if (child_pid > 0) { + + // joined! + break; + } + } + + // clean this child out (even if we had an error with waitpid) + vdev_debug("Daemonlet %d (%s) dead\n", act->daemonlet_pid, act->name); + vdev_action_daemonlet_clean(act); + + return rc; } - // stop all daemonlets // always succeeds; mask all stop errors (i.e. only call this on shutdown) -int vdev_action_daemonlet_stop_all( struct vdev_action* actions, size_t num_actions ) { - - int rc = 0; - - for( unsigned int i = 0; i < num_actions; i++ ) { - - if( !actions[i].is_daemonlet ) { - continue; - } - - rc = vdev_action_daemonlet_stop( &actions[i] ); - if( rc < 0 ) { - - vdev_error("vdev_action_daemonlet_stop('%s' PID=%d) rc = %d\n", actions[i].name, actions[i].daemonlet_pid, rc ); - } - } - - return 0; +int vdev_action_daemonlet_stop_all(struct vdev_action *actions, + size_t num_actions) +{ + + int rc = 0; + + for (unsigned int i = 0; i < num_actions; i++) { + + if (!actions[i].is_daemonlet) { + continue; + } + + rc = vdev_action_daemonlet_stop(&actions[i]); + if (rc < 0) { + + vdev_error + ("vdev_action_daemonlet_stop('%s' PID=%d) rc = %d\n", + actions[i].name, actions[i].daemonlet_pid, rc); + } + } + + return 0; } // read a string-ified int64_t from a file descriptor, followed by a newline. @@ -1153,52 +1200,51 @@ int vdev_action_daemonlet_stop_all( struct vdev_action* actions, size_t num_acti // return 0 on success, and set *ret // return -errno on I/O error (such as -EPIPE) // return -EAGAIN if we got EOF -static int vdev_action_daemonlet_read_int64( int fd, int64_t* ret ) { - - int64_t value = 0; - - int cnt = 0; - int c = 0; - int rc = 0; - int s = 1; - - while( 1 ) { - - // next character - rc = vdev_read_uninterrupted( fd, (char*)&c, 1 ); - if( rc < 0 ) { - - return rc; - } - if( rc == 0 ) { - - return -EAGAIN; - } - - if( c == '\n' ) { - break; - } - - if( cnt == 0 && c == '-' ) { - s = -1; - } - else if( c < '0' || c > '9' ) { - - // invalid - rc = -EINVAL; - break; - } - - value *= 10; - value += (c - '0'); - - cnt++; - } - - *ret = value * s; - return 0; -} +static int vdev_action_daemonlet_read_int64(int fd, int64_t * ret) +{ + + int64_t value = 0; + + int cnt = 0; + int c = 0; + int rc = 0; + int s = 1; + + while (1) { + + // next character + rc = vdev_read_uninterrupted(fd, (char *)&c, 1); + if (rc < 0) { + + return rc; + } + if (rc == 0) { + return -EAGAIN; + } + + if (c == '\n') { + break; + } + + if (cnt == 0 && c == '-') { + s = -1; + } else if (c < '0' || c > '9') { + + // invalid + rc = -EINVAL; + break; + } + + value *= 10; + value += (c - '0'); + + cnt++; + } + + *ret = value * s; + return 0; +} // issue a command to a daemonlet, and get back its return code. // the daemonlet should already be running (or thought to be running) before calling this method. @@ -1207,100 +1253,109 @@ static int vdev_action_daemonlet_read_int64( int fd, int64_t* ret ) { // return -ENOMEM on OOM // return -EAGAIN if the daemonlet needs to be restarted and the request retried. // return -EPERM on permanent daemonlet failure -static int vdev_action_daemonlet_send_command( struct vdev_device_request* vreq, struct vdev_action* act, int64_t* daemonlet_rc ) { - - int rc = 0; - char** req_env = NULL; - size_t num_env = 0; - char env_buf[ PATH_MAX+1 ]; - - memset( env_buf, 0, PATH_MAX+1 ); - - // generate the environment... - rc = vdev_device_request_to_env( vreq, act->helper_vars, &req_env, &num_env, 1 ); - if( rc != 0 ) { - - vdev_error("vdev_device_request_to_env(%s) rc = %d\n", vreq->path, rc ); - return rc; - } - - - vdev_debug("run daemonlet (async=%d): '%s'\n", act->async, act->name ); - - for( unsigned int i = 0; i < num_env; i++ ) { - vdev_debug("daemonlet env: '%s'\n", req_env[i] ); - } - - // feed environment variables - for( unsigned int i = 0; i < num_env; i++ ) { - - snprintf( env_buf, PATH_MAX, "%s\n", req_env[i] ); - - rc = vdev_write_uninterrupted( act->daemonlet_stdin, env_buf, strlen(env_buf) ); - if( rc < 0 ) { - - // failed to write! - vdev_error("vdev_write_uninterrupted(%d) to daemonlet '%s' rc = %d\n", act->daemonlet_stdin, act->name, rc ); - break; - } - } - - if( rc > 0 ) { - - // feed end-of-environment flag - rc = vdev_write_uninterrupted( act->daemonlet_stdin, "done\n", strlen("done\n") ); - if( rc < 0 ) { - - vdev_error("vdev_write_uninterrupted(%d) to daemonlet '%s' rc = %d\n", act->daemonlet_stdin, act->name, rc ); - } - } - - VDEV_FREE_LIST( req_env ); - - if( rc < 0 ) { - - // -EPIPE means the daemonlet is dead, and the caller should restart it - if( rc == -EPIPE ) { - return -EAGAIN; - } - else { - return -EPERM; - } - } - - // if we're running asynchronously, then we don't care about getting back the reply (stdout is routed to /dev/null anyway) - if( act->async ) { - *daemonlet_rc = 0; - return 0; - } - - // wait for a status code reply - rc = vdev_action_daemonlet_read_int64( act->daemonlet_stdout, daemonlet_rc ); - if( rc < 0 ) { - - vdev_error("vdev_action_daemonlet_read_int64('%s') rc = %d\n", act->name, rc ); - - // -EPIPE means the daemonlet is dead, and the caller should restart it - if( rc == -EPIPE ) { - return -EAGAIN; - } - else { - return -EPERM; - } - } - - if( *daemonlet_rc < 0 || *daemonlet_rc > 255 ) { - - // invalid daemonlet return code - // caller should consider restarting the daemonlet and trying again - vdev_error("vdev_daemonlet_read_int64('%s', PID=%d) exit status %d\n", act->name, act->daemonlet_pid, (int)*daemonlet_rc ); - return -EAGAIN; - } - - return 0; +static int vdev_action_daemonlet_send_command(struct vdev_device_request *vreq, + struct vdev_action *act, + int64_t * daemonlet_rc) +{ + + int rc = 0; + char **req_env = NULL; + size_t num_env = 0; + char env_buf[PATH_MAX + 1]; + + memset(env_buf, 0, PATH_MAX + 1); + + // generate the environment... + rc = vdev_device_request_to_env(vreq, act->helper_vars, &req_env, + &num_env, 1); + if (rc != 0) { + + vdev_error("vdev_device_request_to_env(%s) rc = %d\n", + vreq->path, rc); + return rc; + } + + vdev_debug("run daemonlet (async=%d): '%s'\n", act->async, act->name); + + for (unsigned int i = 0; i < num_env; i++) { + vdev_debug("daemonlet env: '%s'\n", req_env[i]); + } + + // feed environment variables + for (unsigned int i = 0; i < num_env; i++) { + + snprintf(env_buf, PATH_MAX, "%s\n", req_env[i]); + + rc = vdev_write_uninterrupted(act->daemonlet_stdin, env_buf, + strlen(env_buf)); + if (rc < 0) { + + // failed to write! + vdev_error + ("vdev_write_uninterrupted(%d) to daemonlet '%s' rc = %d\n", + act->daemonlet_stdin, act->name, rc); + break; + } + } + + if (rc > 0) { + + // feed end-of-environment flag + rc = vdev_write_uninterrupted(act->daemonlet_stdin, "done\n", + strlen("done\n")); + if (rc < 0) { + + vdev_error + ("vdev_write_uninterrupted(%d) to daemonlet '%s' rc = %d\n", + act->daemonlet_stdin, act->name, rc); + } + } + + VDEV_FREE_LIST(req_env); + + if (rc < 0) { + + // -EPIPE means the daemonlet is dead, and the caller should restart it + if (rc == -EPIPE) { + return -EAGAIN; + } else { + return -EPERM; + } + } + // if we're running asynchronously, then we don't care about getting back the reply (stdout is routed to /dev/null anyway) + if (act->async) { + *daemonlet_rc = 0; + return 0; + } + // wait for a status code reply + rc = vdev_action_daemonlet_read_int64(act->daemonlet_stdout, + daemonlet_rc); + if (rc < 0) { + + vdev_error("vdev_action_daemonlet_read_int64('%s') rc = %d\n", + act->name, rc); + + // -EPIPE means the daemonlet is dead, and the caller should restart it + if (rc == -EPIPE) { + return -EAGAIN; + } else { + return -EPERM; + } + } + + if (*daemonlet_rc < 0 || *daemonlet_rc > 255) { + + // invalid daemonlet return code + // caller should consider restarting the daemonlet and trying again + vdev_error + ("vdev_daemonlet_read_int64('%s', PID=%d) exit status %d\n", + act->name, act->daemonlet_pid, (int)*daemonlet_rc); + return -EAGAIN; + } + + return 0; } - // carry out a command by sending it to a running daemonlet. // restart the daemonlet if we need to (e.g. if it hasn't been started, or it died since the last device request). // return the daemonlet's exit status on success (will be positive if the daemonlet failed in error). @@ -1311,455 +1366,498 @@ static int vdev_action_daemonlet_send_command( struct vdev_device_request* vreq, // return a positive exit code if the daemonlet failed to process the device request // NOTE: if this method fails to communicate with the daemonlet, it will try to "reset" the daemonlet by stopping it, and allowing a subsequent call to start it. // NOTE: not reload-safe; call while the reload lock is held -int vdev_action_run_daemonlet( struct vdev_device_request* vreq, struct vdev_action* act ) { - - int rc = 0; - int64_t daemonlet_rc = 0; - int num_attempts = 0; - - if( !act->is_daemonlet ) { - return -EINVAL; - } - - // do we need to start it? - if( act->daemonlet_pid <= 0 ) { - - rc = vdev_action_daemonlet_start( vreq->state, act ); - if( rc < 0 ) { - - vdev_error("vdev_action_daemonlet_start('%s') rc = %d\n", act->name, rc ); - return -EPERM; - } - } - - // try twice, in case we need to stop and start it. - while( num_attempts < 2 ) { - - rc = vdev_action_daemonlet_send_command( vreq, act, &daemonlet_rc ); - if( rc != 0 ) { - - vdev_error("vdev_action_daemonlet_send_command('%s') rc = %d\n", act->name, rc ); - - if( rc == -EAGAIN ) { - - // try restarting and re-dispatching the command - rc = vdev_action_daemonlet_stop( act ); - if( rc < 0 ) { - - vdev_error("vdev_action_daemonlet_stop('%s', PID=%d) rc = %d\n", act->name, act->daemonlet_pid, rc ); - rc = -EPERM; - break; - } - else { - - rc = vdev_action_daemonlet_start( vreq->state, act ); - if( rc < 0 ) { - - vdev_error("vdev_action_daemonlet_start('%s') rc = %d\n", act->name, rc ); - rc = -EPERM; - break; - } - else { - - // try again - num_attempts++; - continue; - } - } - } - else { - - // permanent failure - rc = -EPERM; - break; - } - } - else { - - // successfully dispatched the request, and (if not async) received an exit status via daemonlet_rc - break; - } - } - - if( rc == 0 ) { - - vdev_debug("daemonlet '%s' returned %d\n", act->name, (int)daemonlet_rc ); - return (int)daemonlet_rc; - } - else { - - return rc; - } +int vdev_action_run_daemonlet(struct vdev_device_request *vreq, + struct vdev_action *act) +{ + + int rc = 0; + int64_t daemonlet_rc = 0; + int num_attempts = 0; + + if (!act->is_daemonlet) { + return -EINVAL; + } + // do we need to start it? + if (act->daemonlet_pid <= 0) { + + rc = vdev_action_daemonlet_start(vreq->state, act); + if (rc < 0) { + + vdev_error + ("vdev_action_daemonlet_start('%s') rc = %d\n", + act->name, rc); + return -EPERM; + } + } + // try twice, in case we need to stop and start it. + while (num_attempts < 2) { + + rc = vdev_action_daemonlet_send_command(vreq, act, + &daemonlet_rc); + if (rc != 0) { + + vdev_error + ("vdev_action_daemonlet_send_command('%s') rc = %d\n", + act->name, rc); + + if (rc == -EAGAIN) { + + // try restarting and re-dispatching the command + rc = vdev_action_daemonlet_stop(act); + if (rc < 0) { + + vdev_error + ("vdev_action_daemonlet_stop('%s', PID=%d) rc = %d\n", + act->name, act->daemonlet_pid, rc); + rc = -EPERM; + break; + } else { + + rc = vdev_action_daemonlet_start + (vreq->state, act); + if (rc < 0) { + + vdev_error + ("vdev_action_daemonlet_start('%s') rc = %d\n", + act->name, rc); + rc = -EPERM; + break; + } else { + + // try again + num_attempts++; + continue; + } + } + } else { + + // permanent failure + rc = -EPERM; + break; + } + } else { + + // successfully dispatched the request, and (if not async) received an exit status via daemonlet_rc + break; + } + } + + if (rc == 0) { + + vdev_debug("daemonlet '%s' returned %d\n", act->name, + (int)daemonlet_rc); + return (int)daemonlet_rc; + } else { + + return rc; + } } - // match device request against action // return 1 if match // return 0 if not match -int vdev_action_match( struct vdev_device_request* vreq, struct vdev_action* act ) { - - int rc = 0; - - // action match? - if( act->trigger != vreq->type && act->trigger != VDEV_DEVICE_ANY ) { - return 0; - } - - // path match? - if( act->path != NULL ) { - - rc = vdev_match_regex( vreq->path, &act->path_regex ); - if( rc == 0 ) { - - // no match - return 0; - } - if( rc < 0 ) { - - // some error - return rc; - } - } - - // type match? - if( act->has_type ) { - - if( !S_ISBLK( vreq->mode ) && !S_ISCHR( vreq->mode ) ) { - // device has no type - return 0; - } - - if( S_ISBLK( vreq->mode ) && strcasecmp( act->type, "block" ) != 0 ) { - - // not a block device - return 0; - } - if( S_ISCHR( vreq->mode ) && strcasecmp( act->type, "char" ) != 0 ) { - - // not a char device - return 0; - } - } - - // OS parameter match? - if( act->dev_params != NULL ) { - - struct sglib_vdev_params_iterator itr; - struct vdev_param_t* dp = NULL; - - for( dp = sglib_vdev_params_it_init_inorder( &itr, act->dev_params ); dp != NULL; dp = sglib_vdev_params_it_next( &itr ) ) { - - struct vdev_param_t* match = sglib_vdev_params_find_member( vreq->params, dp ); - - if( match != NULL ) { - - // vreq has this parameter - char const* vreq_param_value = match->value; - char const* act_param_value = dp->value; - - // if the action has no value (value of length 0), then it matches any vreq value - if( act_param_value == NULL || strlen( act_param_value ) == 0 ) { - - continue; - } - - // otherwise, compare the values - if( strcmp( vreq_param_value, act_param_value ) != 0 ) { - - // values don't match - return 0; - } - } - else { - - // vreq does not have this parameter, so no match - return 0; - } - } - } - - // match! - return 1; +int vdev_action_match(struct vdev_device_request *vreq, struct vdev_action *act) +{ + + int rc = 0; + + // action match? + if (act->trigger != vreq->type && act->trigger != VDEV_DEVICE_ANY) { + return 0; + } + // path match? + if (act->path != NULL) { + + rc = vdev_match_regex(vreq->path, &act->path_regex); + if (rc == 0) { + + // no match + return 0; + } + if (rc < 0) { + + // some error + return rc; + } + } + // type match? + if (act->has_type) { + + if (!S_ISBLK(vreq->mode) && !S_ISCHR(vreq->mode)) { + // device has no type + return 0; + } + + if (S_ISBLK(vreq->mode) && strcasecmp(act->type, "block") != 0) { + + // not a block device + return 0; + } + if (S_ISCHR(vreq->mode) && strcasecmp(act->type, "char") != 0) { + + // not a char device + return 0; + } + } + // OS parameter match? + if (act->dev_params != NULL) { + + struct sglib_vdev_params_iterator itr; + struct vdev_param_t *dp = NULL; + + for (dp = + sglib_vdev_params_it_init_inorder(&itr, act->dev_params); + dp != NULL; dp = sglib_vdev_params_it_next(&itr)) { + + struct vdev_param_t *match = + sglib_vdev_params_find_member(vreq->params, dp); + + if (match != NULL) { + + // vreq has this parameter + char const *vreq_param_value = match->value; + char const *act_param_value = dp->value; + + // if the action has no value (value of length 0), then it matches any vreq value + if (act_param_value == NULL + || strlen(act_param_value) == 0) { + + continue; + } + // otherwise, compare the values + if (strcmp(vreq_param_value, act_param_value) != + 0) { + + // values don't match + return 0; + } + } else { + + // vreq does not have this parameter, so no match + return 0; + } + } + } + // match! + return 1; } - // find the next action in a list of actions to run, given the path // return the index into acts of the next match, if found // return num_acts if not found // return negative on error -int vdev_action_find_next( struct vdev_device_request* vreq, struct vdev_action* acts, size_t num_acts ) { - - int rc = 0; - int i = 0; - - for( i = 0; (unsigned)i < num_acts; i++ ) { - - rc = vdev_action_match( vreq, &acts[i] ); - - if( rc > 0 ) { - return i; - } - else if( rc < 0 ) { - return rc; - } - } - - return num_acts; -} +int vdev_action_find_next(struct vdev_device_request *vreq, + struct vdev_action *acts, size_t num_acts) +{ + + int rc = 0; + int i = 0; + + for (i = 0; (unsigned)i < num_acts; i++) { + + rc = vdev_action_match(vreq, &acts[i]); + if (rc > 0) { + return i; + } else if (rc < 0) { + return rc; + } + } + + return num_acts; +} // find the path to create for the given device request, but in a fail-fast manner (i.e. return on first error) // *path will be filled in with path to the device node, relative to the mountpoint. *path must be NULL on call. // return 0 on success // return -EINVAL if *path is not NULL, or if we failed to match the vreq against our actions due to a regex error // return -ENODATA if *path has zero-length -int vdev_action_create_path( struct vdev_device_request* vreq, struct vdev_action* acts, size_t num_acts, char** path ) { - - int rc = 0; - int act_offset = 0; - int i = 0; - char* new_path = NULL; - - if( *path != NULL ) { - return -EINVAL; - } - - while( act_offset < (signed)num_acts ) { - - rc = 0; - - // skip this action if there is no rename command - if( acts[act_offset].rename_command == NULL ) { - act_offset++; - continue; - } - - // find the next action that matches this path - rc = vdev_action_find_next( vreq, acts + act_offset, num_acts - act_offset ); - - if( rc == (signed)(num_acts - act_offset) ) { - - // not found - rc = 0; - break; - } - else if( rc < 0 ) { - - // error - vdev_error("vdev_action_find_next(%s, offset = %d) rc = %d\n", vreq->path, act_offset, rc ); - break; - } - else { - - // matched! advance offset to next action - i = act_offset + rc; - act_offset += rc + 1; - rc = 0; - - if( acts[i].rename_command == NULL ) { - continue; - } - - // generate the new name - rc = vdev_action_run_sync( vreq, acts[i].rename_command, acts[i].helper_vars, true, &new_path, PATH_MAX + 1 ); - if( rc < 0 ) { - - vdev_error("vdev_action_run_sync('%s') rc = %d\n", acts[i].rename_command, rc ); - break; - } - else { - - if( *path != NULL ) { - free( *path ); - } - - *path = new_path; - new_path = NULL; - } - } - } - - if( *path != NULL && strlen(*path) == 0 ) { - - // if this is "UNKNOWN", then just reset to "UNKNOWN" - if( strcmp(vreq->path, VDEV_DEVICE_PATH_UNKNOWN) == 0 ) { - - free( *path ); - *path = vdev_strdup_or_null( VDEV_DEVICE_PATH_UNKNOWN ); - } - else { - - vdev_error("Zero-length path generated for '%s'\n", vreq->path ); - - free( *path ); - *path = NULL; - - rc = -ENODATA; - } - } - - return rc; +int vdev_action_create_path(struct vdev_device_request *vreq, + struct vdev_action *acts, size_t num_acts, + char **path) +{ + + int rc = 0; + int act_offset = 0; + int i = 0; + char *new_path = NULL; + + if (*path != NULL) { + return -EINVAL; + } + + while (act_offset < (signed)num_acts) { + + rc = 0; + + // skip this action if there is no rename command + if (acts[act_offset].rename_command == NULL) { + act_offset++; + continue; + } + // find the next action that matches this path + rc = vdev_action_find_next(vreq, acts + act_offset, + num_acts - act_offset); + + if (rc == (signed)(num_acts - act_offset)) { + + // not found + rc = 0; + break; + } else if (rc < 0) { + + // error + vdev_error + ("vdev_action_find_next(%s, offset = %d) rc = %d\n", + vreq->path, act_offset, rc); + break; + } else { + + // matched! advance offset to next action + i = act_offset + rc; + act_offset += rc + 1; + rc = 0; + + if (acts[i].rename_command == NULL) { + continue; + } + // generate the new name + rc = vdev_action_run_sync(vreq, acts[i].rename_command, + acts[i].helper_vars, true, + &new_path, PATH_MAX + 1); + if (rc < 0) { + + vdev_error + ("vdev_action_run_sync('%s') rc = %d\n", + acts[i].rename_command, rc); + break; + } else { + + if (*path != NULL) { + free(*path); + } + + *path = new_path; + new_path = NULL; + } + } + } + + if (*path != NULL && strlen(*path) == 0) { + + // if this is "UNKNOWN", then just reset to "UNKNOWN" + if (strcmp(vreq->path, VDEV_DEVICE_PATH_UNKNOWN) == 0) { + + free(*path); + *path = vdev_strdup_or_null(VDEV_DEVICE_PATH_UNKNOWN); + } else { + + vdev_error("Zero-length path generated for '%s'\n", + vreq->path); + + free(*path); + *path = NULL; + + rc = -ENODATA; + } + } + + return rc; } - // run all actions for a device, sequentially, in lexographic order. // commands are executed optimistically--even if one fails, the other subsequent ones will be attempted, unless // the device already exists and we encounter if_exists=error in one of the matching actions. // if the device already exists (given by the exists flag), then only run commands with if_exists set to "run" // return 0 on success // return negative on failure -int vdev_action_run_commands( struct vdev_device_request* vreq, struct vdev_action* acts, size_t num_acts, bool exists ) { - - int rc = 0; - int act_offset = 0; - int i = 0; - char const* method = NULL; - struct timespec start; - struct timespec end; - - while( act_offset < (signed)num_acts && rc == 0 ) { - - // skip this action if there is no command - if( acts[act_offset].command == NULL ) { - act_offset++; - continue; - } - - // find the next action that matches this path - rc = vdev_action_find_next( vreq, acts + act_offset, num_acts - act_offset ); - - if( rc == (signed)(num_acts - act_offset) ) { - - // not found - rc = 0; - break; - } - else if( rc < 0 ) { - - vdev_error("vdev_action_find_next(%s, offset = %d) rc = %d\n", vreq->path, act_offset, rc ); - break; - } - else { - - // matched! advance offset to next action - i = act_offset + rc; - act_offset += rc + 1; - rc = 0; - - if( acts[i].command == NULL ) { - continue; - } - - if( vreq->type == VDEV_DEVICE_ADD && exists && acts[i].if_exists != VDEV_IF_EXISTS_RUN ) { - - if( acts[i].if_exists == VDEV_IF_EXISTS_ERROR ) { - - vdev_error("Will stop processing %s, since it already exists\n", vreq->path ); - rc = 1; - break; - } - else { - - // device already exists, but this is not considered by the .act file to be an error - continue; - } - } - - // benchmark this... - clock_gettime( CLOCK_MONOTONIC, &start ); - - // what kind of action to take? - if( !acts[i].is_daemonlet ) { - - if( acts[i].async ) { - - // fork a subprocess and handle asynchronously - method = "vdev_action_run_async"; - rc = vdev_action_run_async( vreq, acts[i].command, acts[i].helper_vars, acts[i].use_shell ); - } - else { - - // run as a subprocess, wait, and join with it - method = "vdev_action_run_sync"; - rc = vdev_action_run_sync( vreq, acts[i].command, acts[i].helper_vars, acts[i].use_shell, NULL, 0 ); - } - } - else { - - if( acts[i].async ) { - - // run as a daemonlet, feed it the request, but don't wait for a reply - method = "vdev_action_run_daemonlet_async"; - } - else { - - // run as a daemonlet, feed the request, and wait for a reply - method = "vdev_action_run_daemonlet"; - } - - rc = vdev_action_run_daemonlet( vreq, &acts[i] ); - } - - clock_gettime( CLOCK_MONOTONIC, &end ); - - if( rc != 0 ) { - - vdev_error("%s('%s') rc = %d\n", method, acts[i].command, rc ); - - if( rc < 0 ) { - return rc; - } - else { - - // mask non-zero exit statuses - uint64_t start_millis = 1000L * start.tv_sec + (start.tv_nsec / 1000000L); - uint64_t end_millis = 1000L * end.tv_sec + (end.tv_nsec / 1000000L); - - vdev_debug("Benchmark: action %s failed (exit %d) in %lu millis\n", acts[i].name, rc, (unsigned long)(end_millis - start_millis) ); - rc = 0; - } - } - else { - - // success! update benchmark - acts[i].num_successful_calls++; - - uint64_t start_millis = 1000L * start.tv_sec + (start.tv_nsec / 1000000L); - uint64_t end_millis = 1000L * end.tv_sec + (end.tv_nsec / 1000000L); - - acts[i].cumulative_time_millis += (end_millis - start_millis); - - // log timings directly, for finer granularity... - vdev_debug("Benchmark: action %s succeeded in %lu millis\n", acts[i].name, (unsigned long)(end_millis - start_millis) ); - } - } - } - - if( rc > 0 ) { - - // not an error, but a cause to abort - rc = 0; - } - - return rc; +int vdev_action_run_commands(struct vdev_device_request *vreq, + struct vdev_action *acts, size_t num_acts, + bool exists) +{ + + int rc = 0; + int act_offset = 0; + int i = 0; + char const *method = NULL; + struct timespec start; + struct timespec end; + + while (act_offset < (signed)num_acts && rc == 0) { + + // skip this action if there is no command + if (acts[act_offset].command == NULL) { + act_offset++; + continue; + } + // find the next action that matches this path + rc = vdev_action_find_next(vreq, acts + act_offset, + num_acts - act_offset); + + if (rc == (signed)(num_acts - act_offset)) { + + // not found + rc = 0; + break; + } else if (rc < 0) { + + vdev_error + ("vdev_action_find_next(%s, offset = %d) rc = %d\n", + vreq->path, act_offset, rc); + break; + } else { + + // matched! advance offset to next action + i = act_offset + rc; + act_offset += rc + 1; + rc = 0; + + if (acts[i].command == NULL) { + continue; + } + + if (vreq->type == VDEV_DEVICE_ADD && exists + && acts[i].if_exists != VDEV_IF_EXISTS_RUN) { + + if (acts[i].if_exists == VDEV_IF_EXISTS_ERROR) { + + vdev_error + ("Will stop processing %s, since it already exists\n", + vreq->path); + rc = 1; + break; + } else { + + // device already exists, but this is not considered by the .act file to be an error + continue; + } + } + // benchmark this... + clock_gettime(CLOCK_MONOTONIC, &start); + + // what kind of action to take? + if (!acts[i].is_daemonlet) { + + if (acts[i].async) { + + // fork a subprocess and handle asynchronously + method = "vdev_action_run_async"; + rc = vdev_action_run_async(vreq, + acts + [i].command, + acts + [i].helper_vars, + acts + [i].use_shell); + } else { + + // run as a subprocess, wait, and join with it + method = "vdev_action_run_sync"; + rc = vdev_action_run_sync(vreq, + acts + [i].command, + acts + [i].helper_vars, + acts + [i].use_shell, + NULL, 0); + } + } else { + + if (acts[i].async) { + + // run as a daemonlet, feed it the request, but don't wait for a reply + method = + "vdev_action_run_daemonlet_async"; + } else { + + // run as a daemonlet, feed the request, and wait for a reply + method = "vdev_action_run_daemonlet"; + } + + rc = vdev_action_run_daemonlet(vreq, &acts[i]); + } + + clock_gettime(CLOCK_MONOTONIC, &end); + + if (rc != 0) { + + vdev_error("%s('%s') rc = %d\n", method, + acts[i].command, rc); + + if (rc < 0) { + return rc; + } else { + + // mask non-zero exit statuses + uint64_t start_millis = + 1000L * start.tv_sec + + (start.tv_nsec / 1000000L); + uint64_t end_millis = + 1000L * end.tv_sec + + (end.tv_nsec / 1000000L); + + vdev_debug + ("Benchmark: action %s failed (exit %d) in %lu millis\n", + acts[i].name, rc, + (unsigned long)(end_millis - + start_millis)); + rc = 0; + } + } else { + + // success! update benchmark + acts[i].num_successful_calls++; + + uint64_t start_millis = + 1000L * start.tv_sec + + (start.tv_nsec / 1000000L); + uint64_t end_millis = + 1000L * end.tv_sec + + (end.tv_nsec / 1000000L); + + acts[i].cumulative_time_millis += + (end_millis - start_millis); + + // log timings directly, for finer granularity... + vdev_debug + ("Benchmark: action %s succeeded in %lu millis\n", + acts[i].name, + (unsigned long)(end_millis - + start_millis)); + } + } + } + + if (rc > 0) { + + // not an error, but a cause to abort + rc = 0; + } + + return rc; } - // print out all benchmark information for this action // always succeeds -int vdev_action_log_benchmarks( struct vdev_action* action ) { - - // int rc = 0; - - if( action->num_successful_calls > 0 ) { - vdev_debug("Action '%s' (daemon=%d, async=%d): %lu successful calls; %lu millis total; %lf avg.\n", - action->name, action->is_daemonlet, action->async, action->num_successful_calls, action->cumulative_time_millis, (double)(action->cumulative_time_millis) / (double)(action->num_successful_calls)); - } - else { - vdev_debug("Action '%s' (daemon=%d, async=%d): 0 successful calls\n", action->name, action->is_daemonlet, action->async ); - } - - return 0; +int vdev_action_log_benchmarks(struct vdev_action *action) +{ + + // int rc = 0; + + if (action->num_successful_calls > 0) { + vdev_debug + ("Action '%s' (daemon=%d, async=%d): %lu successful calls; %lu millis total; %lf avg.\n", + action->name, action->is_daemonlet, action->async, + action->num_successful_calls, + action->cumulative_time_millis, + (double)(action->cumulative_time_millis) / + (double)(action->num_successful_calls)); + } else { + vdev_debug + ("Action '%s' (daemon=%d, async=%d): 0 successful calls\n", + action->name, action->is_daemonlet, action->async); + } + + return 0; } - - diff --git a/vdevd/device.c b/vdevd/device.c index 7d0369c..2c92cef 100644 --- a/vdevd/device.c +++ b/vdevd/device.c @@ -28,107 +28,115 @@ // create a request // return 0 on success // return -ENOMEM if we can't allocate device parameters -int vdev_device_request_init( struct vdev_device_request* req, struct vdev_state* state, vdev_device_request_t req_type, char const* path ) { - - memset( req, 0, sizeof(struct vdev_device_request) ); - - if( path != NULL ) { - req->path = vdev_strdup_or_null( path ); - if( req->path == NULL ) { - return -ENOMEM; - } - } - - req->state = state; - req->type = req_type; - - return 0; +int vdev_device_request_init(struct vdev_device_request *req, + struct vdev_state *state, + vdev_device_request_t req_type, char const *path) +{ + + memset(req, 0, sizeof(struct vdev_device_request)); + + if (path != NULL) { + req->path = vdev_strdup_or_null(path); + if (req->path == NULL) { + return -ENOMEM; + } + } + + req->state = state; + req->type = req_type; + + return 0; } // free a request -int vdev_device_request_free( struct vdev_device_request* req ) { - - if( req->params != NULL ) { - - vdev_params_free( req->params ); - req->params = NULL; - } - - if( req->path != NULL ) { - - free( req->path ); - req->path = NULL; - } - - if( req->renamed_path != NULL ) { - - free( req->renamed_path ); - req->renamed_path = NULL; - } - - memset( req, 0, sizeof(struct vdev_device_request) ); - - return 0; +int vdev_device_request_free(struct vdev_device_request *req) +{ + + if (req->params != NULL) { + + vdev_params_free(req->params); + req->params = NULL; + } + + if (req->path != NULL) { + + free(req->path); + req->path = NULL; + } + + if (req->renamed_path != NULL) { + + free(req->renamed_path); + req->renamed_path = NULL; + } + + memset(req, 0, sizeof(struct vdev_device_request)); + + return 0; } // add a device parameter (must be unique) // return 0 on success // return -EEXIST if the parameter exists // return -ENOMEM if OOM -int vdev_device_request_add_param( struct vdev_device_request* req, char const* key, char const* value ) { - - return vdev_params_add( &req->params, key, value ); +int vdev_device_request_add_param(struct vdev_device_request *req, + char const *key, char const *value) +{ + + return vdev_params_add(&req->params, key, value); } // create a KEY=VALUE string -static int vdev_device_request_make_env_str( char const* key, char const* value, char** ret ) { - - char* e = VDEV_CALLOC( char, strlen(key) + 1 + strlen(value) + 1 ); - - if( e == NULL ) { - return -ENOMEM; - } - - sprintf(e, "%s=%s", key, value ); - *ret = e; - - return 0; -} +static int vdev_device_request_make_env_str(char const *key, char const *value, + char **ret) +{ + char *e = VDEV_CALLOC(char, strlen(key) + 1 + strlen(value) + 1); -// action to const string -static char const* vdev_device_request_type_to_string( vdev_device_request_t req ) { - - if( req == VDEV_DEVICE_ADD ) { - return "add"; - } - if( req == VDEV_DEVICE_REMOVE ) { - return "remove"; - } - if( req == VDEV_DEVICE_CHANGE ) { - return "change"; - } - - return "none"; + if (e == NULL) { + return -ENOMEM; + } + + sprintf(e, "%s=%s", key, value); + *ret = e; + + return 0; } +// action to const string +static char const *vdev_device_request_type_to_string(vdev_device_request_t req) +{ + + if (req == VDEV_DEVICE_ADD) { + return "add"; + } + if (req == VDEV_DEVICE_REMOVE) { + return "remove"; + } + if (req == VDEV_DEVICE_CHANGE) { + return "change"; + } + + return "none"; +} // mode to const string -static char const* vdev_device_request_mode_to_string( mode_t mode ) { - - static char const* blk_str = "block"; - static char const* chr_str = "char"; - static char const* none_str = "none"; - - if( S_ISBLK(mode) ) { - return blk_str; - } - - else if( S_ISCHR(mode) ) { - return chr_str; - } - - return none_str; +static char const *vdev_device_request_mode_to_string(mode_t mode) +{ + + static char const *blk_str = "block"; + static char const *chr_str = "char"; + static char const *none_str = "none"; + + if (S_ISBLK(mode)) { + return blk_str; + } + + else if (S_ISCHR(mode)) { + return chr_str; + } + + return none_str; } // convert a device request to a list of null-terminated KEY=VALUE environment variable strings @@ -137,439 +145,482 @@ static char const* vdev_device_request_mode_to_string( mode_t mode ) { // return 0 on success // return negative on error // NOTE: not reload-safe; call while the reload lock is held -int vdev_device_request_to_env( struct vdev_device_request* req, vdev_params* helper_vars, char*** ret_env, size_t* num_env, int is_daemonlet ) { - - // type --> VDEV_ACTION - // path --> VDEV_PATH (if non-null) - // dev --> VDEV_MAJOR, VDEV_MINOR (if given) - // mode --> VDEV_MODE (if given) - // params --> VDEV_OS_* - // helper vars --> VDEV_VAR_* - // mountpoint --> VDEV_MOUNTPOINT - // metadata --> VDEV_METADATA (if path is non-null) - // global metadata --> VDEV_GLOBAL_METADATA - // helpers --> VDEV_HELPERS - // logfile --> VDEV_LOGFILE - // vdev instance nonce --> VDEV_INSTANCE - // config file --> VDEV_CONFIG_FILE - // daemonlet --> VDEV_DAEMONLET (0 by default, 1 if is_daemonlet is non-zero) - - size_t num_vars = 15 + sglib_vdev_params_len( req->params ) + sglib_vdev_params_len( helper_vars ); - int i = 0; - int rc = 0; - char dev_buf[51]; - struct vdev_param_t* dp = NULL; - struct sglib_vdev_params_iterator itr; - char* vdev_path = req->renamed_path; - char metadata_dir[ PATH_MAX + 1 ]; - char global_metadata_dir[ PATH_MAX + 1 ]; - char const* is_daemonlet_str = NULL; - char const* loglevel = NULL; - - if( is_daemonlet != 0 ) { - is_daemonlet_str = "1"; - } - else { - is_daemonlet_str = "0"; - } - - memset( metadata_dir, 0, PATH_MAX+1 ); - memset( global_metadata_dir, 0, PATH_MAX+1 ); - memset( dev_buf, 0, 51 ); - - if( vdev_path == NULL ) { - - vdev_path = req->path; - } - - if( vdev_path != NULL ) { - snprintf( metadata_dir, PATH_MAX, "%s/" VDEV_METADATA_PREFIX "/dev/%s", req->state->mountpoint, vdev_path ); - } - - char** env = VDEV_CALLOC( char*, num_vars + 1 ); - - if( env == NULL ) { - return -ENOMEM; - } - - snprintf( global_metadata_dir, PATH_MAX, "%s/" VDEV_METADATA_PREFIX, req->state->mountpoint ); - - rc = vdev_device_request_make_env_str( "VDEV_MOUNTPOINT", req->state->mountpoint, &env[i] ); - if( rc != 0 ) { - - VDEV_FREE_LIST( env ); - return rc; - } - - i++; - - rc = vdev_device_request_make_env_str( "VDEV_ACTION", vdev_device_request_type_to_string( req->type ), &env[i] ); - if( rc != 0 ) { - - VDEV_FREE_LIST( env ); - return rc; - } - - i++; - - if( vdev_path != NULL ) { - - rc = vdev_device_request_make_env_str( "VDEV_PATH", vdev_path, &env[i] ); - if( rc != 0 ) { - - VDEV_FREE_LIST( env ); - return rc; - } - - i++; - - rc = vdev_device_request_make_env_str( "VDEV_METADATA", metadata_dir, &env[i] ); - if( rc != 0 ) { - - VDEV_FREE_LIST( env ); - return rc; - } - - i++; - } - - rc = vdev_device_request_make_env_str( "VDEV_GLOBAL_METADATA", global_metadata_dir, &env[i] ); - if( rc != 0 ) { - - VDEV_FREE_LIST( env ); - return rc; - } - - i++; - - rc = vdev_device_request_make_env_str( "VDEV_CONFIG_FILE", req->state->config->config_path, &env[i] ); - if( rc != 0 ) { - - VDEV_FREE_LIST( env ); - return rc; - } - - i++; - - if( req->dev != 0 ) { - - snprintf(dev_buf, 50, "%u", major(req->dev) ); - - rc = vdev_device_request_make_env_str( "VDEV_MAJOR", dev_buf, &env[i] ); - if( rc != 0 ) { - - VDEV_FREE_LIST( env ); - return rc; - } - - i++; - - snprintf(dev_buf, 50, "%u", minor(req->dev) ); - - rc = vdev_device_request_make_env_str( "VDEV_MINOR", dev_buf, &env[i] ); - if( rc != 0 ) { - - VDEV_FREE_LIST( env ); - return rc; - } - - i++; - } - - if( (req->mode & (S_IFBLK | S_IFCHR)) != 0 ) { - - rc = vdev_device_request_make_env_str( "VDEV_MODE", vdev_device_request_mode_to_string( req->mode ), &env[i] ); - if( rc != 0 ) { - - VDEV_FREE_LIST( env ); - return rc; - } - - i++; - } - - rc = vdev_device_request_make_env_str( "VDEV_HELPERS", req->state->config->helpers_dir, &env[i] ); - if( rc != 0 ) { - - VDEV_FREE_LIST( env ); - return rc; - } - - i++; - - if( req->state->config->logfile_path != NULL && strcasecmp( req->state->config->logfile_path, "syslog" ) != 0 ) { - - rc = vdev_device_request_make_env_str( "VDEV_LOGFILE", req->state->config->logfile_path, &env[i] ); - if( rc != 0 ) { - - VDEV_FREE_LIST( env ); - return rc; - } - - i++; - } - - rc = vdev_device_request_make_env_str( "VDEV_INSTANCE", req->state->config->instance_str, &env[i] ); - if( rc != 0 ) { - - VDEV_FREE_LIST( env ); - return rc; - } - - i++; - - rc = vdev_device_request_make_env_str( "VDEV_DAEMONLET", is_daemonlet_str, &env[i] ); - if( rc != 0 ) { - - VDEV_FREE_LIST( env ); - return rc; - } - - i++; - - if( vdev_get_debug_level() > 0 ) { - if( vdev_get_debug_level() == 1 ) { - loglevel = "info"; - } - else { - loglevel = "debug"; - } - } - else if( vdev_get_error_level() > 0 ) { - if( vdev_get_error_level() == 1 ) { - loglevel = "error"; - } - else { - loglevel = "warning"; - } - } - - if( loglevel == NULL ) { - loglevel = "warning"; - } - - rc = vdev_device_request_make_env_str( "VDEV_LOGLEVEL", loglevel, &env[i] ); - if( rc != 0 ) { - - VDEV_FREE_LIST( env ); - return rc; - } - - i++; - - // add all OS-specific parameters - for( dp = sglib_vdev_params_it_init_inorder( &itr, req->params ); dp != NULL; dp = sglib_vdev_params_it_next( &itr ) ) { - - char const* param_key = dp->key; - char const* param_value = dp->value; - - // prepend with "VDEV_OS_" - char* varname = VDEV_CALLOC( char, strlen(param_key) + 1 + strlen("VDEV_OS_") ); - - if( varname == NULL ) { - - VDEV_FREE_LIST( env ); - return -ENOMEM; - } - - sprintf( varname, "VDEV_OS_%s", param_key ); - - rc = vdev_device_request_make_env_str( varname, param_value, &env[i] ); - - free( varname ); - - if( rc != 0 ) { - - VDEV_FREE_LIST( env ); - return rc; - } - - i++; - } - - // add all helper-specific variables - for( dp = sglib_vdev_params_it_init_inorder( &itr, helper_vars ); dp != NULL; dp = sglib_vdev_params_it_next( &itr ) ) { - - char const* param_key = dp->key; - char const* param_value = dp->value; - - // prepend with "VDEV_OS_" - char* varname = VDEV_CALLOC( char, strlen(param_key) + 1 + strlen("VDEV_VAR_") ); - - if( varname == NULL ) { - - VDEV_FREE_LIST( env ); - return -ENOMEM; - } - - sprintf( varname, "VDEV_VAR_%s", param_key ); - - rc = vdev_device_request_make_env_str( varname, param_value, &env[i] ); - - free( varname ); - - if( rc != 0 ) { - - VDEV_FREE_LIST( env ); - return rc; - } - - i++; - } - - *ret_env = env; - *num_env = i; - - return 0; -} +int vdev_device_request_to_env(struct vdev_device_request *req, + vdev_params * helper_vars, char ***ret_env, + size_t * num_env, int is_daemonlet) +{ + + // type --> VDEV_ACTION + // path --> VDEV_PATH (if non-null) + // dev --> VDEV_MAJOR, VDEV_MINOR (if given) + // mode --> VDEV_MODE (if given) + // params --> VDEV_OS_* + // helper vars --> VDEV_VAR_* + // mountpoint --> VDEV_MOUNTPOINT + // metadata --> VDEV_METADATA (if path is non-null) + // global metadata --> VDEV_GLOBAL_METADATA + // helpers --> VDEV_HELPERS + // logfile --> VDEV_LOGFILE + // vdev instance nonce --> VDEV_INSTANCE + // config file --> VDEV_CONFIG_FILE + // daemonlet --> VDEV_DAEMONLET (0 by default, 1 if is_daemonlet is non-zero) + + size_t num_vars = + 15 + sglib_vdev_params_len(req->params) + + sglib_vdev_params_len(helper_vars); + int i = 0; + int rc = 0; + char dev_buf[51]; + struct vdev_param_t *dp = NULL; + struct sglib_vdev_params_iterator itr; + char *vdev_path = req->renamed_path; + char metadata_dir[PATH_MAX + 1]; + char global_metadata_dir[PATH_MAX + 1]; + char const *is_daemonlet_str = NULL; + char const *loglevel = NULL; + + if (is_daemonlet != 0) { + is_daemonlet_str = "1"; + } else { + is_daemonlet_str = "0"; + } + + memset(metadata_dir, 0, PATH_MAX + 1); + memset(global_metadata_dir, 0, PATH_MAX + 1); + memset(dev_buf, 0, 51); + + if (vdev_path == NULL) { + + vdev_path = req->path; + } + + if (vdev_path != NULL) { + snprintf(metadata_dir, PATH_MAX, + "%s/" VDEV_METADATA_PREFIX "/dev/%s", + req->state->mountpoint, vdev_path); + } + + char **env = VDEV_CALLOC(char *, num_vars + 1); + + if (env == NULL) { + return -ENOMEM; + } + + snprintf(global_metadata_dir, PATH_MAX, "%s/" VDEV_METADATA_PREFIX, + req->state->mountpoint); + + rc = vdev_device_request_make_env_str("VDEV_MOUNTPOINT", + req->state->mountpoint, &env[i]); + if (rc != 0) { + + VDEV_FREE_LIST(env); + return rc; + } + + i++; + + rc = vdev_device_request_make_env_str("VDEV_ACTION", + vdev_device_request_type_to_string + (req->type), &env[i]); + if (rc != 0) { + + VDEV_FREE_LIST(env); + return rc; + } + + i++; + + if (vdev_path != NULL) { + + rc = vdev_device_request_make_env_str("VDEV_PATH", vdev_path, + &env[i]); + if (rc != 0) { + + VDEV_FREE_LIST(env); + return rc; + } + + i++; + + rc = vdev_device_request_make_env_str("VDEV_METADATA", + metadata_dir, &env[i]); + if (rc != 0) { + + VDEV_FREE_LIST(env); + return rc; + } + + i++; + } + + rc = vdev_device_request_make_env_str("VDEV_GLOBAL_METADATA", + global_metadata_dir, &env[i]); + if (rc != 0) { + + VDEV_FREE_LIST(env); + return rc; + } + + i++; + + rc = vdev_device_request_make_env_str("VDEV_CONFIG_FILE", + req->state->config->config_path, + &env[i]); + if (rc != 0) { + + VDEV_FREE_LIST(env); + return rc; + } + + i++; + + if (req->dev != 0) { + + snprintf(dev_buf, 50, "%u", major(req->dev)); + + rc = vdev_device_request_make_env_str("VDEV_MAJOR", dev_buf, + &env[i]); + if (rc != 0) { + + VDEV_FREE_LIST(env); + return rc; + } + + i++; + + snprintf(dev_buf, 50, "%u", minor(req->dev)); + + rc = vdev_device_request_make_env_str("VDEV_MINOR", dev_buf, + &env[i]); + if (rc != 0) { + + VDEV_FREE_LIST(env); + return rc; + } + + i++; + } + + if ((req->mode & (S_IFBLK | S_IFCHR)) != 0) { + + rc = vdev_device_request_make_env_str("VDEV_MODE", + vdev_device_request_mode_to_string + (req->mode), &env[i]); + if (rc != 0) { + + VDEV_FREE_LIST(env); + return rc; + } + + i++; + } + + rc = vdev_device_request_make_env_str("VDEV_HELPERS", + req->state->config->helpers_dir, + &env[i]); + if (rc != 0) { + + VDEV_FREE_LIST(env); + return rc; + } + + i++; + + if (req->state->config->logfile_path != NULL + && strcasecmp(req->state->config->logfile_path, "syslog") != 0) { + + rc = vdev_device_request_make_env_str("VDEV_LOGFILE", + req->state-> + config->logfile_path, + &env[i]); + if (rc != 0) { + VDEV_FREE_LIST(env); + return rc; + } + + i++; + } + + rc = vdev_device_request_make_env_str("VDEV_INSTANCE", + req->state->config->instance_str, + &env[i]); + if (rc != 0) { + + VDEV_FREE_LIST(env); + return rc; + } + + i++; + + rc = vdev_device_request_make_env_str("VDEV_DAEMONLET", + is_daemonlet_str, &env[i]); + if (rc != 0) { + + VDEV_FREE_LIST(env); + return rc; + } + + i++; + + if (vdev_get_debug_level() > 0) { + if (vdev_get_debug_level() == 1) { + loglevel = "info"; + } else { + loglevel = "debug"; + } + } else if (vdev_get_error_level() > 0) { + if (vdev_get_error_level() == 1) { + loglevel = "error"; + } else { + loglevel = "warning"; + } + } + + if (loglevel == NULL) { + loglevel = "warning"; + } + + rc = vdev_device_request_make_env_str("VDEV_LOGLEVEL", loglevel, + &env[i]); + if (rc != 0) { + + VDEV_FREE_LIST(env); + return rc; + } + + i++; + + // add all OS-specific parameters + for (dp = sglib_vdev_params_it_init_inorder(&itr, req->params); + dp != NULL; dp = sglib_vdev_params_it_next(&itr)) { + + char const *param_key = dp->key; + char const *param_value = dp->value; + + // prepend with "VDEV_OS_" + char *varname = VDEV_CALLOC(char, + strlen(param_key) + 1 + + strlen("VDEV_OS_")); + + if (varname == NULL) { + + VDEV_FREE_LIST(env); + return -ENOMEM; + } + + sprintf(varname, "VDEV_OS_%s", param_key); + + rc = vdev_device_request_make_env_str(varname, param_value, + &env[i]); + + free(varname); + + if (rc != 0) { + + VDEV_FREE_LIST(env); + return rc; + } + + i++; + } + + // add all helper-specific variables + for (dp = sglib_vdev_params_it_init_inorder(&itr, helper_vars); + dp != NULL; dp = sglib_vdev_params_it_next(&itr)) { + + char const *param_key = dp->key; + char const *param_value = dp->value; + + // prepend with "VDEV_OS_" + char *varname = VDEV_CALLOC(char, + strlen(param_key) + 1 + + strlen("VDEV_VAR_")); + + if (varname == NULL) { + + VDEV_FREE_LIST(env); + return -ENOMEM; + } + + sprintf(varname, "VDEV_VAR_%s", param_key); + + rc = vdev_device_request_make_env_str(varname, param_value, + &env[i]); + + free(varname); + + if (rc != 0) { + + VDEV_FREE_LIST(env); + return rc; + } + + i++; + } + + *ret_env = env; + *num_env = i; + + return 0; +} // set the path // return 0 on success // return -ENOMEM on OOM -int vdev_device_request_set_path( struct vdev_device_request* req, char const* path ) { - - if( req->path != NULL ) { - free( req->path ); - } - - req->path = vdev_strdup_or_null( path ); - - if( req->path == NULL && path != NULL ) { - return -ENOMEM; - } - - return 0; +int vdev_device_request_set_path(struct vdev_device_request *req, + char const *path) +{ + + if (req->path != NULL) { + free(req->path); + } + + req->path = vdev_strdup_or_null(path); + + if (req->path == NULL && path != NULL) { + return -ENOMEM; + } + + return 0; } // set the device // always succeeds -int vdev_device_request_set_dev( struct vdev_device_request* req, dev_t dev ) { - - req->dev = dev; - return 0; -} +int vdev_device_request_set_dev(struct vdev_device_request *req, dev_t dev) +{ + req->dev = dev; + return 0; +} // mark this device as already existing // always succeeds -int vdev_device_request_set_exists( struct vdev_device_request* req, bool exists ) { - - req->exists = exists; - return 0; +int vdev_device_request_set_exists(struct vdev_device_request *req, bool exists) +{ + + req->exists = exists; + return 0; } - // device request sanity check // return 0 if valid // return -EINVAL if not valid -int vdev_device_request_sanity_check( struct vdev_device_request* req ) { - - if( req->path == NULL ) { - - vdev_error("request %p missing path\n", req ); - return -EINVAL; - } - - if( req->type == VDEV_DEVICE_INVALID ) { - - vdev_error("request %p has no request type\n", req ); - return -EINVAL; - } - - return 0; -} +int vdev_device_request_sanity_check(struct vdev_device_request *req) +{ + if (req->path == NULL) { -// set the request type -int vdev_device_request_set_type( struct vdev_device_request* req, vdev_device_request_t req_type ) { - - req->type = req_type; - return 0; + vdev_error("request %p missing path\n", req); + return -EINVAL; + } + + if (req->type == VDEV_DEVICE_INVALID) { + + vdev_error("request %p has no request type\n", req); + return -EINVAL; + } + + return 0; } +// set the request type +int vdev_device_request_set_type(struct vdev_device_request *req, + vdev_device_request_t req_type) +{ -// set the request device mode -int vdev_device_request_set_mode( struct vdev_device_request* req, mode_t mode ) { - - req->mode = mode; - return 0; + req->type = req_type; + return 0; } +// set the request device mode +int vdev_device_request_set_mode(struct vdev_device_request *req, mode_t mode) +{ + + req->mode = mode; + return 0; +} // generate a path to a device's metadata // return the malloc'ed path on success // return NULL on error -char* vdev_device_metadata_fullpath( char const* mountpoint, char const* device_path ) { - - char* base_dir = NULL; - char* metadata_dir = VDEV_CALLOC( char, strlen( mountpoint ) + 1 + strlen(VDEV_METADATA_PREFIX) + 2 + strlen(device_path) + 1 ); - if( metadata_dir == NULL ) { - - return NULL; - } - - sprintf( metadata_dir, VDEV_METADATA_PREFIX "/dev/%s", device_path ); - - base_dir = vdev_fullpath( mountpoint, metadata_dir, NULL ); - - free( metadata_dir ); - - if( base_dir == NULL ) { - - return NULL; - } - - return base_dir; -} +char *vdev_device_metadata_fullpath(char const *mountpoint, + char const *device_path) +{ + + char *base_dir = NULL; + char *metadata_dir = VDEV_CALLOC(char, + strlen(mountpoint) + 1 + + strlen(VDEV_METADATA_PREFIX) + 2 + + strlen(device_path) + 1); + if (metadata_dir == NULL) { + + return NULL; + } + sprintf(metadata_dir, VDEV_METADATA_PREFIX "/dev/%s", device_path); + + base_dir = vdev_fullpath(mountpoint, metadata_dir, NULL); + + free(metadata_dir); + + if (base_dir == NULL) { + + return NULL; + } + + return base_dir; +} // create or update an item of metadata to $VDEV_MOUNTPOINT/$VDEV_METADATA_PREFIX/dev/$VDEV_PATH/$PARAM_KEY // return 0 on success // return negative on error -static int vdev_device_put_metadata_item( char* base_dir, char const* param_name, char const* param_value, int flags, mode_t mode ) { - - int rc = 0; - char* param_value_with_newline = NULL; - char* key_value_path = NULL; - - key_value_path = vdev_fullpath( base_dir, param_name, NULL ); - - if( key_value_path == NULL ) { - - rc = -ENOMEM; - return rc; - } - - param_value_with_newline = VDEV_CALLOC( char, strlen(param_value) + 2 ); - if( param_value_with_newline == NULL ) { - - rc = -ENOMEM; - free( key_value_path ); - return rc; - } - - strcpy( param_value_with_newline, param_value ); - strcat( param_value_with_newline, "\n"); - - rc = vdev_write_file( key_value_path, param_value_with_newline, strlen(param_value_with_newline), flags, mode ); - - free( param_value_with_newline ); - - if( rc < 0 ) { - - vdev_error("vdev_write_file('%s', '%s') rc = %d\n", key_value_path, param_value, rc ); - } - else { - - rc = 0; - } - - free( key_value_path ); - - return rc; -} +static int vdev_device_put_metadata_item(char *base_dir, char const *param_name, + char const *param_value, int flags, + mode_t mode) +{ + + int rc = 0; + char *param_value_with_newline = NULL; + char *key_value_path = NULL; + key_value_path = vdev_fullpath(base_dir, param_name, NULL); + + if (key_value_path == NULL) { + + rc = -ENOMEM; + return rc; + } + + param_value_with_newline = VDEV_CALLOC(char, strlen(param_value) + 2); + if (param_value_with_newline == NULL) { + + rc = -ENOMEM; + free(key_value_path); + return rc; + } + + strcpy(param_value_with_newline, param_value); + strcat(param_value_with_newline, "\n"); + + rc = vdev_write_file(key_value_path, param_value_with_newline, + strlen(param_value_with_newline), flags, mode); + + free(param_value_with_newline); + + if (rc < 0) { + + vdev_error("vdev_write_file('%s', '%s') rc = %d\n", + key_value_path, param_value, rc); + } else { + + rc = 0; + } + + free(key_value_path); + + return rc; +} // record extra metadata (i.e. vdev parameters) for a device node // overwrite existing metadata if it already exists for this device. @@ -579,241 +630,245 @@ static int vdev_device_put_metadata_item( char* base_dir, char const* param_name // return negative on I/O error // NOTE: the device metadata directory ($VDEV_MOUNTPOINT/$VDEV_METADATA_PREFIX/dev) must exist // NOTE: not reload-safe; call while the reload lock is held -static int vdev_device_put_metadata( struct vdev_device_request* req ) { - - int rc = 0; - struct sglib_vdev_params_iterator itr; - struct vdev_param_t* dp; - - char* base_dir = NULL; - char* device_path = NULL; - - // only create device metadata if the device path is known. - if( req->renamed_path != NULL ) { - - device_path = req->renamed_path; - } - else if( req->path != NULL ) { - - device_path = req->path; - } - else { - - return -EINVAL; - } - - // unknown? - if( strcmp( device_path, VDEV_DEVICE_PATH_UNKNOWN ) == 0 ) { - - return -EINVAL; - } - - // path to device metadata - base_dir = vdev_device_metadata_fullpath( req->state->mountpoint, req->renamed_path ); - if( base_dir == NULL ) { - - return -ENOMEM; - } - - // all directories must exist - rc = vdev_mkdirs( base_dir, strlen( req->state->mountpoint ), 0755 ); - if( rc != 0 ) { - - vdev_error("vdev_mkdirs('%s') rc = %d\n", base_dir, rc ); - - free( base_dir ); - base_dir = NULL; - - return rc; - } - - // save instance nonce - rc = vdev_device_put_metadata_item( base_dir, VDEV_METADATA_PARAM_INSTANCE, req->state->config->instance_str, O_CREAT | O_WRONLY | O_TRUNC, 0644 ); - if( rc != 0 ) { - - if( rc == -EEXIST ) { - - // try to update instead - rc = vdev_device_put_metadata_item( base_dir, VDEV_METADATA_PARAM_INSTANCE, req->state->config->instance_str, O_WRONLY | O_TRUNC, 0644 ); - } - - if( rc != 0 ) { - vdev_error("vdev_device_put_metadata_item('%s', '%s') rc = %d\n", VDEV_METADATA_PARAM_INSTANCE, req->state->config->instance_str, rc ); - } - } - - free( base_dir ); - - return rc; +static int vdev_device_put_metadata(struct vdev_device_request *req) +{ + + int rc = 0; + struct sglib_vdev_params_iterator itr; + struct vdev_param_t *dp; + + char *base_dir = NULL; + char *device_path = NULL; + + // only create device metadata if the device path is known. + if (req->renamed_path != NULL) { + + device_path = req->renamed_path; + } else if (req->path != NULL) { + + device_path = req->path; + } else { + + return -EINVAL; + } + + // unknown? + if (strcmp(device_path, VDEV_DEVICE_PATH_UNKNOWN) == 0) { + + return -EINVAL; + } + // path to device metadata + base_dir = + vdev_device_metadata_fullpath(req->state->mountpoint, + req->renamed_path); + if (base_dir == NULL) { + + return -ENOMEM; + } + // all directories must exist + rc = vdev_mkdirs(base_dir, strlen(req->state->mountpoint), 0755); + if (rc != 0) { + + vdev_error("vdev_mkdirs('%s') rc = %d\n", base_dir, rc); + + free(base_dir); + base_dir = NULL; + + return rc; + } + // save instance nonce + rc = vdev_device_put_metadata_item(base_dir, + VDEV_METADATA_PARAM_INSTANCE, + req->state->config->instance_str, + O_CREAT | O_WRONLY | O_TRUNC, 0644); + if (rc != 0) { + + if (rc == -EEXIST) { + + // try to update instead + rc = vdev_device_put_metadata_item(base_dir, + VDEV_METADATA_PARAM_INSTANCE, + req->state-> + config->instance_str, + O_WRONLY | O_TRUNC, + 0644); + } + + if (rc != 0) { + vdev_error + ("vdev_device_put_metadata_item('%s', '%s') rc = %d\n", + VDEV_METADATA_PARAM_INSTANCE, + req->state->config->instance_str, rc); + } + } + + free(base_dir); + + return rc; } - // remove helper for vdev_device_remove_metadata // return 0 on success // return -errno for unlink failure -static int vdev_device_remove_metadata_file( char const* fp, void* cls ) { - - int rc = 0; - struct stat sb; - - char name_buf[ VDEV_NAME_MAX + 1 ]; - - vdev_basename( fp, name_buf ); - - if( strcmp(name_buf, ".") == 0 || strcmp(name_buf, "..") == 0 ) { - // skip - return 0; - } - - // is this a directory? - rc = lstat( fp, &sb ); - if( rc != 0 ) { - - rc = -errno; - vdev_warn("stat('%s') rc = %d\n", fp, rc ); - return rc; - } - - if( S_ISDIR( sb.st_mode ) ) { - - // blow away children too - rc = vdev_load_all( fp, vdev_device_remove_metadata_file, NULL ); - if( rc != 0 ) { - - vdev_warn("removing '%s' rc = %d\n", fp, rc ); - return rc; - } - - // blow away dir - rc = rmdir( fp ); - } - else { - - // regular file - rc = unlink( fp ); - } - - if( rc != 0 ) { - - rc = -errno; - vdev_warn("unlink('%s') rc = %d\n", fp, rc ); - return rc; - } - - return rc; +static int vdev_device_remove_metadata_file(char const *fp, void *cls) +{ + + int rc = 0; + struct stat sb; + + char name_buf[VDEV_NAME_MAX + 1]; + + vdev_basename(fp, name_buf); + + if (strcmp(name_buf, ".") == 0 || strcmp(name_buf, "..") == 0) { + // skip + return 0; + } + // is this a directory? + rc = lstat(fp, &sb); + if (rc != 0) { + + rc = -errno; + vdev_warn("stat('%s') rc = %d\n", fp, rc); + return rc; + } + + if (S_ISDIR(sb.st_mode)) { + + // blow away children too + rc = vdev_load_all(fp, vdev_device_remove_metadata_file, NULL); + if (rc != 0) { + + vdev_warn("removing '%s' rc = %d\n", fp, rc); + return rc; + } + // blow away dir + rc = rmdir(fp); + } else { + + // regular file + rc = unlink(fp); + } + + if (rc != 0) { + + rc = -errno; + vdev_warn("unlink('%s') rc = %d\n", fp, rc); + return rc; + } + + return rc; } // remove extra metadata (i.e. vdev and OS parameters) for a deivce node // return 0 on success // return negative on error // NOTE: not reload-safe; call while the reload lock is held -static int vdev_device_remove_metadata( struct vdev_device_request* req ) { - - int rc = 0; - - char* base_dir = NULL; - char metadata_dir[ PATH_MAX + 1 ]; - - // NOTE: req->path is guaranteed to be <= 256 characters - sprintf( metadata_dir, VDEV_METADATA_PREFIX "/dev/%s", req->path ); - - base_dir = vdev_fullpath( req->state->mountpoint, metadata_dir, NULL ); - if( base_dir == NULL ) { - - return -ENOMEM; - } - - // remove everything in this directory - rc = vdev_load_all( base_dir, vdev_device_remove_metadata_file, NULL ); - - if( rc != 0 ) { - - vdev_error("vdev_load_all('%s') rc = %d\n", base_dir, rc ); - } - - // remove the directory itself - rc = rmdir( base_dir ); - if( rc != 0 ) { - - rc = -errno; - vdev_warn("rmdir('%s') rc = %d\n", base_dir, rc ); - } - - free( base_dir ); - return rc; -} +static int vdev_device_remove_metadata(struct vdev_device_request *req) +{ + + int rc = 0; + + char *base_dir = NULL; + char metadata_dir[PATH_MAX + 1]; + + // NOTE: req->path is guaranteed to be <= 256 characters + sprintf(metadata_dir, VDEV_METADATA_PREFIX "/dev/%s", req->path); + + base_dir = vdev_fullpath(req->state->mountpoint, metadata_dir, NULL); + if (base_dir == NULL) { + + return -ENOMEM; + } + // remove everything in this directory + rc = vdev_load_all(base_dir, vdev_device_remove_metadata_file, NULL); + + if (rc != 0) { + vdev_error("vdev_load_all('%s') rc = %d\n", base_dir, rc); + } + // remove the directory itself + rc = rmdir(base_dir); + if (rc != 0) { + + rc = -errno; + vdev_warn("rmdir('%s') rc = %d\n", base_dir, rc); + } + + free(base_dir); + return rc; +} // do we have metadata logged for a device? // return 0 on success // return negative on error // NOTE: not reload-safe; call while the reload lock is held -static int vdev_device_has_metadata( struct vdev_device_request* req ) { - - int rc = 0; - struct stat sb; - char* md_fp = vdev_device_metadata_fullpath( req->state->mountpoint, req->renamed_path ); - if( md_fp == NULL ) { - - rc = -ENOMEM; - } - else { - - rc = stat( md_fp, &sb ); - - if( rc != 0 ) { - rc = -errno; - } - - free( md_fp ); - } - - return rc; -} +static int vdev_device_has_metadata(struct vdev_device_request *req) +{ + + int rc = 0; + struct stat sb; + char *md_fp = vdev_device_metadata_fullpath(req->state->mountpoint, + req->renamed_path); + if (md_fp == NULL) { + + rc = -ENOMEM; + } else { + + rc = stat(md_fp, &sb); + + if (rc != 0) { + rc = -errno; + } + free(md_fp); + } + + return rc; +} // create all directories leading up to a device // return 0 on success // return negative on error // NOTE: not reload-safe; call while the reload lock is held -static int vdev_device_mkdirs( struct vdev_device_request* req, char** dev_fullpath ) { - - int rc = 0; - char* fp = NULL; - char* fp_dir = NULL; - - fp = vdev_fullpath( req->state->mountpoint, req->renamed_path, NULL ); - if( fp == NULL ) { - - rc = -ENOMEM; - return rc; - } - - if( strchr(req->renamed_path, '/') != NULL ) { - - fp_dir = vdev_dirname( fp, NULL ); - if( fp_dir == NULL ) { - - rc = -ENOMEM; - free( fp ); - return rc; - } - - // make sure the directories leading to this path exist - rc = vdev_mkdirs( fp_dir, strlen(req->state->mountpoint), 0755 ); - if( rc != 0 ) { - - vdev_error("vdev_mkdirs('%s') rc = %d\n", fp_dir, rc ); - } - - free( fp_dir ); - } - - *dev_fullpath = fp; - - return rc; -} +static int vdev_device_mkdirs(struct vdev_device_request *req, + char **dev_fullpath) +{ + + int rc = 0; + char *fp = NULL; + char *fp_dir = NULL; + + fp = vdev_fullpath(req->state->mountpoint, req->renamed_path, NULL); + if (fp == NULL) { + + rc = -ENOMEM; + return rc; + } + + if (strchr(req->renamed_path, '/') != NULL) { + + fp_dir = vdev_dirname(fp, NULL); + if (fp_dir == NULL) { + rc = -ENOMEM; + free(fp); + return rc; + } + // make sure the directories leading to this path exist + rc = vdev_mkdirs(fp_dir, strlen(req->state->mountpoint), 0755); + if (rc != 0) { + + vdev_error("vdev_mkdirs('%s') rc = %d\n", fp_dir, rc); + } + + free(fp_dir); + } + + *dev_fullpath = fp; + + return rc; +} // handler to add a device // rename the device, and if it succeeds, mknod the device (if it exists), @@ -821,288 +876,326 @@ static int vdev_device_mkdirs( struct vdev_device_request* req, char** dev_fullp // return -ENOMEM on OOM // return -EACCES if we do not have enough privileges to create the device node // return -EEXIST if the device node already exists -int vdev_device_add( struct vdev_device_request* req ) { - - int rc = 0; - int do_mknod = 1; // if 1, issue mknod. Otherwise, check to see if the device exists by checking for metadata. - int device_exists = 0; // if 1, the device already exists. only run commands with the if_exists directive set to "run" - - // prevent reloads while processing - vdev_reload_lock( req->state ); - - // do the rename, possibly generating it - rc = vdev_action_create_path( req, req->state->acts, req->state->num_acts, &req->renamed_path ); - if( rc != 0 ) { - - vdev_error("vdev_action_create_path('%s') rc = %d\n", req->path, rc); - - // done with this request - vdev_reload_unlock( req->state ); - vdev_device_request_free( req ); - free( req ); - - return rc; - } - - if( req->renamed_path == NULL ) { - - // base path becomes renamed path (trivial rename) - req->renamed_path = vdev_strdup_or_null( req->path ); - if( req->renamed_path == NULL && req->path != NULL ) { - - // done with this request - vdev_reload_unlock( req->state ); - vdev_device_request_free( req ); - free( req ); - - return -ENOMEM; - } - } - - vdev_debug("ADD device: type '%s' at '%s' ('%s' %d:%d)\n", (S_ISBLK(req->mode) ? "block" : S_ISCHR(req->mode) ? "char" : "unknown"), req->renamed_path, req->path, major(req->dev), minor(req->dev) ); - - if( req->renamed_path != NULL ) { - - // device has a name (i.e. something for us to add)? - if( strcmp( req->renamed_path, VDEV_DEVICE_PATH_UNKNOWN ) != 0 ) { - - // device has major/minor/mode? - if( req->dev != 0 && req->mode != 0 ) { - - char* fp = NULL; // full path to the device - - rc = vdev_device_mkdirs( req, &fp ); - if( rc != 0 ) { - - vdev_error("vdev_device_mkdirs('%s/%s') rc = %d\n", req->state->mountpoint, req->renamed_path, rc ); - - // done with this request - vdev_reload_unlock( req->state ); - vdev_device_request_free( req ); - free( req ); - - return rc; - } - - // do we need to make the device? - if( vdev_config_has_OS_quirk( req->state->config->OS_quirks, VDEV_OS_QUIRK_DEVICE_EXISTS ) ) { - - // nope, but did we process it already? - if( vdev_device_has_metadata( req ) ) { - - // this device already exists, insofar as - // we (or some other device manager) - // have already processed it. - device_exists = 1; - } - } - - else { - - if( !req->exists ) { - - // file is not expected to exist - rc = mknod( fp, req->mode | req->state->config->default_mode, req->dev ); - } - else { - - rc = 0; - } - - if( rc != 0 ) { - - rc = -errno; - if( rc == -EEXIST ) { - - // device already exists, insofar as - // we (or some other device manager) - // have already processed it. - device_exists = 1; - rc = 0; - } - } - } - - free( fp ); - } - - // no major/minor/mode - else { - - // not creating a device file, but a device-add event nevertheless. - // creating or updating? - rc = vdev_device_has_metadata( req ); - if( rc != 0 ) { - - if( rc == -ENOENT ) { - - // add metadata, since none exists! - rc = 0; - } - } - else { - - // metadata already present, meaning - // that this device has been processed - rc = 0; - device_exists = 1; - } - } - - if( rc != 0 ) { - - // some mknod or metadata I/O error occurred - vdev_error("Add device '%s/%s', rc = %d\n", req->state->mountpoint, req->renamed_path, rc ); - } - - else { - - // put/update metadata - rc = vdev_device_put_metadata( req ); - - if( rc != 0 ) { - - vdev_error("vdev_device_put_metadata('%s/%s') rc = %d\n", req->state->mountpoint, req->renamed_path, rc ); - } - } - } - - if( rc == 0 ) { - - // no problems yet. call all ADD actions - rc = vdev_action_run_commands( req, req->state->acts, req->state->num_acts, device_exists ); - if( rc != 0 ) { - - vdev_error("vdev_action_run_commands(ADD %s, dev=(%u, %u)) rc = %d\n", req->renamed_path, major(req->dev), minor(req->dev), rc ); - } - } - } - - // done with this request - vdev_reload_unlock( req->state ); - vdev_device_request_free( req ); - free( req ); - - return 0; +int vdev_device_add(struct vdev_device_request *req) +{ + + int rc = 0; + int do_mknod = 1; // if 1, issue mknod. Otherwise, check to see if the device exists by checking for metadata. + int device_exists = 0; // if 1, the device already exists. only run commands with the if_exists directive set to "run" + + // prevent reloads while processing + vdev_reload_lock(req->state); + + // do the rename, possibly generating it + rc = vdev_action_create_path(req, req->state->acts, + req->state->num_acts, &req->renamed_path); + if (rc != 0) { + + vdev_error("vdev_action_create_path('%s') rc = %d\n", req->path, + rc); + + // done with this request + vdev_reload_unlock(req->state); + vdev_device_request_free(req); + free(req); + + return rc; + } + + if (req->renamed_path == NULL) { + + // base path becomes renamed path (trivial rename) + req->renamed_path = vdev_strdup_or_null(req->path); + if (req->renamed_path == NULL && req->path != NULL) { + + // done with this request + vdev_reload_unlock(req->state); + vdev_device_request_free(req); + free(req); + + return -ENOMEM; + } + } + + vdev_debug("ADD device: type '%s' at '%s' ('%s' %d:%d)\n", + (S_ISBLK(req->mode) ? "block" : S_ISCHR(req->mode) ? "char" : + "unknown"), req->renamed_path, req->path, major(req->dev), + minor(req->dev)); + + if (req->renamed_path != NULL) { + + // device has a name (i.e. something for us to add)? + if (strcmp(req->renamed_path, VDEV_DEVICE_PATH_UNKNOWN) != 0) { + + // device has major/minor/mode? + if (req->dev != 0 && req->mode != 0) { + + char *fp = NULL; // full path to the device + + rc = vdev_device_mkdirs(req, &fp); + if (rc != 0) { + + vdev_error + ("vdev_device_mkdirs('%s/%s') rc = %d\n", + req->state->mountpoint, + req->renamed_path, rc); + + // done with this request + vdev_reload_unlock(req->state); + vdev_device_request_free(req); + free(req); + + return rc; + } + // do we need to make the device? + if (vdev_config_has_OS_quirk + (req->state->config->OS_quirks, + VDEV_OS_QUIRK_DEVICE_EXISTS)) { + + // nope, but did we process it already? + if (vdev_device_has_metadata(req)) { + + // this device already exists, insofar as + // we (or some other device manager) + // have already processed it. + device_exists = 1; + } + } + + else { + + if (!req->exists) { + + // file is not expected to exist + rc = mknod(fp, + req-> + mode | req->state-> + config->default_mode, + req->dev); + } else { + + rc = 0; + } + + if (rc != 0) { + + rc = -errno; + if (rc == -EEXIST) { + + // device already exists, insofar as + // we (or some other device manager) + // have already processed it. + device_exists = 1; + rc = 0; + } + } + } + + free(fp); + } + // no major/minor/mode + else { + + // not creating a device file, but a device-add event nevertheless. + // creating or updating? + rc = vdev_device_has_metadata(req); + if (rc != 0) { + + if (rc == -ENOENT) { + + // add metadata, since none exists! + rc = 0; + } + } else { + + // metadata already present, meaning + // that this device has been processed + rc = 0; + device_exists = 1; + } + } + + if (rc != 0) { + + // some mknod or metadata I/O error occurred + vdev_error("Add device '%s/%s', rc = %d\n", + req->state->mountpoint, + req->renamed_path, rc); + } + + else { + + // put/update metadata + rc = vdev_device_put_metadata(req); + + if (rc != 0) { + + vdev_error + ("vdev_device_put_metadata('%s/%s') rc = %d\n", + req->state->mountpoint, + req->renamed_path, rc); + } + } + } + + if (rc == 0) { + + // no problems yet. call all ADD actions + rc = vdev_action_run_commands(req, req->state->acts, + req->state->num_acts, + device_exists); + if (rc != 0) { + + vdev_error + ("vdev_action_run_commands(ADD %s, dev=(%u, %u)) rc = %d\n", + req->renamed_path, major(req->dev), + minor(req->dev), rc); + } + } + } + // done with this request + vdev_reload_unlock(req->state); + vdev_device_request_free(req); + free(req); + + return 0; } // workqueue call to vdev_device_add -static int vdev_device_add_wq( struct vdev_wreq* wreq, void* cls ) { - - struct vdev_device_request* req = (struct vdev_device_request*)cls; - return vdev_device_add( req ); -} +static int vdev_device_add_wq(struct vdev_wreq *wreq, void *cls) +{ + struct vdev_device_request *req = (struct vdev_device_request *)cls; + return vdev_device_add(req); +} // handler to remove a device (unlink) // return 0 on success. This masks failure to unlink or clean up metadata or a failed action. // return -ENOMEM on OOM -int vdev_device_remove( struct vdev_device_request* req ) { - - int rc = 0; - - vdev_reload_lock( req->state ); - - // do the rename, possibly generating it - rc = vdev_action_create_path( req, req->state->acts, req->state->num_acts, &req->renamed_path ); - if( rc != 0 ) { - - vdev_error("vdev_action_create_path('%s') rc = %d\n", req->path, rc); - - // done with this request - vdev_reload_unlock( req->state ); - vdev_device_request_free( req ); - free( req ); - - return rc; - } - - if( req->renamed_path == NULL ) { - - req->renamed_path = vdev_strdup_or_null( req->path ); - if( req->renamed_path == NULL && req->path == NULL ) { - - // done with this request - vdev_reload_unlock( req->state ); - vdev_device_request_free( req ); - free( req ); - - return -ENOMEM; - } - } - - vdev_info("REMOVE device: type '%s' at '%s' ('%s' %d:%d)\n", (S_ISBLK(req->mode) ? "block" : S_ISCHR(req->mode) ? "char" : "unknown"), req->renamed_path, req->path, major(req->dev), minor(req->dev) ); - - if( req->renamed_path != NULL ) { - - // call all REMOVE actions - rc = vdev_action_run_commands( req, req->state->acts, req->state->num_acts, true ); - if( rc != 0 ) { - - vdev_error("vdev_action_run_all(REMOVE %s) rc = %d\n", req->renamed_path, rc ); - rc = 0; - } - - if( strcmp( req->renamed_path, VDEV_DEVICE_PATH_UNKNOWN ) != 0 ) { - - // known path - // only remove files from /dev if this is a device, and we created it - if( req->dev != 0 && req->mode != 0 && !vdev_config_has_OS_quirk( req->state->config->OS_quirks, VDEV_OS_QUIRK_DEVICE_EXISTS ) ) { - - // remove the data itself, if there is data - char* fp = vdev_fullpath( req->state->mountpoint, req->renamed_path, NULL ); - - rc = unlink( fp ); - if( rc != 0 ) { - - rc = -errno; - - if( rc != -ENOENT ) { - vdev_error("unlink(%s) rc = %d\n", fp, rc ); - } - - rc = 0; - } - - // try to clean up directories - rc = vdev_rmdirs( fp ); - if( rc != 0 && rc != -ENOTEMPTY && rc != -ENOENT ) { - - vdev_error("vdev_rmdirs('%s') rc = %d\n", fp, rc ); - rc = 0; - } - - free( fp ); - } - - // remove metadata - rc = vdev_device_remove_metadata( req ); - - if( rc != 0 ) { - - vdev_warn("unable to clean up metadata for %s\n", req->renamed_path ); - rc = 0; - } - } - } - - vdev_reload_unlock( req->state ); - - // done with this request - vdev_device_request_free( req ); - free( req ); - - return rc; -} +int vdev_device_remove(struct vdev_device_request *req) +{ + int rc = 0; + + vdev_reload_lock(req->state); + + // do the rename, possibly generating it + rc = vdev_action_create_path(req, req->state->acts, + req->state->num_acts, &req->renamed_path); + if (rc != 0) { + + vdev_error("vdev_action_create_path('%s') rc = %d\n", req->path, + rc); -// workqueue call to vdev_device_remove -static int vdev_device_remove_wq( struct vdev_wreq* wreq, void* cls ) { - - struct vdev_device_request* req = (struct vdev_device_request*)cls; - return vdev_device_remove( req ); + // done with this request + vdev_reload_unlock(req->state); + vdev_device_request_free(req); + free(req); + + return rc; + } + + if (req->renamed_path == NULL) { + + req->renamed_path = vdev_strdup_or_null(req->path); + if (req->renamed_path == NULL && req->path == NULL) { + + // done with this request + vdev_reload_unlock(req->state); + vdev_device_request_free(req); + free(req); + + return -ENOMEM; + } + } + + vdev_info("REMOVE device: type '%s' at '%s' ('%s' %d:%d)\n", + (S_ISBLK(req->mode) ? "block" : S_ISCHR(req->mode) ? "char" : + "unknown"), req->renamed_path, req->path, major(req->dev), + minor(req->dev)); + + if (req->renamed_path != NULL) { + + // call all REMOVE actions + rc = vdev_action_run_commands(req, req->state->acts, + req->state->num_acts, true); + if (rc != 0) { + + vdev_error("vdev_action_run_all(REMOVE %s) rc = %d\n", + req->renamed_path, rc); + rc = 0; + } + + if (strcmp(req->renamed_path, VDEV_DEVICE_PATH_UNKNOWN) != 0) { + + // known path + // only remove files from /dev if this is a device, and we created it + if (req->dev != 0 && req->mode != 0 + && !vdev_config_has_OS_quirk(req->state-> + config->OS_quirks, + VDEV_OS_QUIRK_DEVICE_EXISTS)) + { + + // remove the data itself, if there is data + char *fp = vdev_fullpath(req->state->mountpoint, + req->renamed_path, + NULL); + + rc = unlink(fp); + if (rc != 0) { + + rc = -errno; + + if (rc != -ENOENT) { + vdev_error + ("unlink(%s) rc = %d\n", fp, + rc); + } + + rc = 0; + } + // try to clean up directories + rc = vdev_rmdirs(fp); + if (rc != 0 && rc != -ENOTEMPTY + && rc != -ENOENT) { + + vdev_error + ("vdev_rmdirs('%s') rc = %d\n", fp, + rc); + rc = 0; + } + + free(fp); + } + // remove metadata + rc = vdev_device_remove_metadata(req); + + if (rc != 0) { + + vdev_warn + ("unable to clean up metadata for %s\n", + req->renamed_path); + rc = 0; + } + } + } + + vdev_reload_unlock(req->state); + + // done with this request + vdev_device_request_free(req); + free(req); + + return rc; } +// workqueue call to vdev_device_remove +static int vdev_device_remove_wq(struct vdev_wreq *wreq, void *cls) +{ + + struct vdev_device_request *req = (struct vdev_device_request *)cls; + return vdev_device_remove(req); +} // handler to change a device // Process any rename commands to get the final path, and then update that path's metadata @@ -1111,123 +1204,134 @@ static int vdev_device_remove_wq( struct vdev_wreq* wreq, void* cls ) { // return -ENOMEM on OOM // return -EACCES if we do not have enough privileges to create the device node // return -EEXIST if the device node already exists -int vdev_device_change( struct vdev_device_request* req ) { - - int rc = 0; - - vdev_reload_lock( req->state ); - - // do the rename, possibly generating it - rc = vdev_action_create_path( req, req->state->acts, req->state->num_acts, &req->renamed_path ); - if( rc != 0 ) { - - vdev_error("vdev_action_create_path('%s') rc = %d\n", req->path, rc); - - // done with this request - vdev_reload_unlock( req->state ); - vdev_device_request_free( req ); - free( req ); - - return rc; - } - - if( req->renamed_path == NULL ) { - - // base path becomes renamed path (trivial rename) - req->renamed_path = vdev_strdup_or_null( req->path ); - if( req->renamed_path == NULL && req->path != NULL ) { - - // done with this request - vdev_reload_unlock( req->state ); - vdev_device_request_free( req ); - free( req ); - return -ENOMEM; - } - } - - vdev_debug("CHANGE device: type '%s' at '%s' ('%s' %d:%d)\n", (S_ISBLK(req->mode) ? "block" : S_ISCHR(req->mode) ? "char" : "unknown"), req->renamed_path, req->path, major(req->dev), minor(req->dev) ); - - if( req->renamed_path != NULL && vdev_device_has_metadata( req ) ) { - - // call all CHANGE actions - rc = vdev_action_run_commands( req, req->state->acts, req->state->num_acts, 1 ); - if( rc != 0 ) { - - vdev_error("vdev_action_run_commands(ADD %s, dev=(%u, %u)) rc = %d\n", req->renamed_path, major(req->dev), minor(req->dev), rc ); - } - } - - vdev_reload_unlock( req->state ); - - // done with this request - vdev_device_request_free( req ); - free( req ); - - return 0; -} +int vdev_device_change(struct vdev_device_request *req) +{ + int rc = 0; -// workqueue call to vdev_device_change -static int vdev_device_change_wq( struct vdev_wreq* wreq, void* cls ) { - - struct vdev_device_request* req = (struct vdev_device_request*)cls; - return vdev_device_change( req ); + vdev_reload_lock(req->state); + + // do the rename, possibly generating it + rc = vdev_action_create_path(req, req->state->acts, + req->state->num_acts, &req->renamed_path); + if (rc != 0) { + + vdev_error("vdev_action_create_path('%s') rc = %d\n", req->path, + rc); + + // done with this request + vdev_reload_unlock(req->state); + vdev_device_request_free(req); + free(req); + + return rc; + } + + if (req->renamed_path == NULL) { + + // base path becomes renamed path (trivial rename) + req->renamed_path = vdev_strdup_or_null(req->path); + if (req->renamed_path == NULL && req->path != NULL) { + + // done with this request + vdev_reload_unlock(req->state); + vdev_device_request_free(req); + free(req); + return -ENOMEM; + } + } + + vdev_debug("CHANGE device: type '%s' at '%s' ('%s' %d:%d)\n", + (S_ISBLK(req->mode) ? "block" : S_ISCHR(req->mode) ? "char" : + "unknown"), req->renamed_path, req->path, major(req->dev), + minor(req->dev)); + + if (req->renamed_path != NULL && vdev_device_has_metadata(req)) { + + // call all CHANGE actions + rc = vdev_action_run_commands(req, req->state->acts, + req->state->num_acts, 1); + if (rc != 0) { + + vdev_error + ("vdev_action_run_commands(ADD %s, dev=(%u, %u)) rc = %d\n", + req->renamed_path, major(req->dev), + minor(req->dev), rc); + } + } + + vdev_reload_unlock(req->state); + + // done with this request + vdev_device_request_free(req); + free(req); + + return 0; } +// workqueue call to vdev_device_change +static int vdev_device_change_wq(struct vdev_wreq *wreq, void *cls) +{ + + struct vdev_device_request *req = (struct vdev_device_request *)cls; + return vdev_device_change(req); +} // enqueue a device request // NOTE: the workqueue takes ownership of the request. The caller should not free it. // return 0 on success // return -EINVAL if the device request is missing required fields // return -ENOMEM on OOM -int vdev_device_request_enqueue( struct vdev_wq* wq, struct vdev_device_request* req ) { - - int rc = 0; - struct vdev_wreq wreq; - - memset( &wreq, 0, sizeof(struct vdev_wreq) ); - - // sanity check - rc = vdev_device_request_sanity_check( req ); - if( rc != 0 ) { - - vdev_error("Invalid device request (type %d)\n", req->type ); - return -EINVAL; - } - - // which handler? - switch( req->type ) { - - case VDEV_DEVICE_ADD: { - - vdev_wreq_init( &wreq, vdev_device_add_wq, req ); - break; - } - - case VDEV_DEVICE_REMOVE: { - - vdev_wreq_init( &wreq, vdev_device_remove_wq, req ); - break; - } - - case VDEV_DEVICE_CHANGE: { - - vdev_wreq_init( &wreq, vdev_device_change_wq, req ); - break; - } - - default: { - - vdev_error("Invalid device request type %d\n", req->type ); - return -EINVAL; - } - } - - rc = vdev_wq_add( wq, &wreq ); - if( rc != 0 ) { - - vdev_error("vdev_wq_add('%s') rc = %d\n", req->path, rc ); - } - - return rc; +int vdev_device_request_enqueue(struct vdev_wq *wq, + struct vdev_device_request *req) +{ + + int rc = 0; + struct vdev_wreq wreq; + + memset(&wreq, 0, sizeof(struct vdev_wreq)); + + // sanity check + rc = vdev_device_request_sanity_check(req); + if (rc != 0) { + + vdev_error("Invalid device request (type %d)\n", req->type); + return -EINVAL; + } + // which handler? + switch (req->type) { + + case VDEV_DEVICE_ADD:{ + + vdev_wreq_init(&wreq, vdev_device_add_wq, req); + break; + } + + case VDEV_DEVICE_REMOVE:{ + + vdev_wreq_init(&wreq, vdev_device_remove_wq, req); + break; + } + + case VDEV_DEVICE_CHANGE:{ + + vdev_wreq_init(&wreq, vdev_device_change_wq, req); + break; + } + + default:{ + + vdev_error("Invalid device request type %d\n", + req->type); + return -EINVAL; + } + } + + rc = vdev_wq_add(wq, &wreq); + if (rc != 0) { + + vdev_error("vdev_wq_add('%s') rc = %d\n", req->path, rc); + } + + return rc; } diff --git a/vdevd/main.c b/vdevd/main.c index 72d2d1c..fe7316a 100644 --- a/vdevd/main.c +++ b/vdevd/main.c @@ -25,229 +25,232 @@ static struct vdev_state vdev; // reload handler -void vdev_reload_sighup( int ignored ) { - - vdev_reload( &vdev ); +void vdev_reload_sighup(int ignored) +{ + + vdev_reload(&vdev); } // run! -int main( int argc, char** argv ) { - - int rc = 0; - int coldplug_quiesce_pipe[2]; - bool is_child = false; - bool is_parent = false; - ssize_t nr = 0; - - int coldplug_finished_fd = -1; // FD to write to once we finish flushing the initial device requests - - memset( &vdev, 0, sizeof(struct vdev_state) ); - - // ignore SIGPIPE from daemonlets - signal( SIGPIPE, SIG_IGN ); - - // set up global vdev state - rc = vdev_init( &vdev, argc, argv ); - // help called from command line -h or --help (-2) - // short circuit with log/debug support - if( vdev.config->help ){ - if( rc == -2 ){ - - vdev_debug("%s", "exiting: help called at command line\n"); - // the shutdown and clean up should be redundant ? - exit(0); - } - } - - if( rc != 0 ) { - - vdev_error("vdev_init rc = %d\n", rc ); - - vdev_shutdown( &vdev, false ); - exit(1); - } - - // run the preseed command - rc = vdev_preseed_run( &vdev ); - if( rc != 0 ) { - - vdev_error("vdev_preseed_run rc = %d\n", rc ); - - vdev_shutdown( &vdev, false ); - exit(1); - } - - // if we're going to daemonize, then redirect logging to the logfile - if( !vdev.config->foreground ) { - - // sanity check - if( vdev.config->logfile_path == NULL ) { - - fprintf(stderr, "No logfile specified\n"); - - vdev_shutdown( &vdev, false ); - exit(2); - } - - // do we need to connect to syslog? - if( strcmp( vdev.config->logfile_path, "syslog" ) == 0 ) { - - vdev_debug("%s", "Switching to syslog for messages\n"); - vdev_enable_syslog(); - } - - else { - - // send to a specific logfile - rc = vdev_log_redirect( vdev.config->logfile_path ); - if( rc != 0 ) { - - vdev_error("vdev_log_redirect('%s') rc = %d\n", vdev.config->logfile_path, rc ); - - vdev_shutdown( &vdev, false ); - exit(2); - } - } - - if( !vdev.config->coldplug_only ) { - - // will become a daemon after handling coldplug. - // set up a pipe between parent and child, so the child can - // signal the parent when it's device queue has been emptied - // (meaning the parent can safely exit). - - rc = pipe( coldplug_quiesce_pipe ); - if( rc != 0 ) { - - vdev_error("pipe rc = %d\n", rc ); - vdev_shutdown( &vdev, false ); - - exit(3); - } - - // become a daemon - rc = vdev_daemonize(); - if( rc < 0 ) { - - vdev_error("vdev_daemonize rc = %d\n", rc ); - vdev_shutdown( &vdev, false ); - - exit(3); - } - - if( rc == 0 ) { - - // child - close( coldplug_quiesce_pipe[0] ); - coldplug_finished_fd = coldplug_quiesce_pipe[1]; - - // write a pidfile - if( vdev.config->pidfile_path != NULL ) { - - rc = vdev_pidfile_write( vdev.config->pidfile_path ); - if( rc != 0 ) { - - vdev_error("vdev_pidfile_write('%s') rc = %d\n", vdev.config->pidfile_path, rc ); - - vdev_shutdown( &vdev, false ); - exit(4); - } - } - - // set reload handler - signal( SIGHUP, vdev_reload_sighup ); - - is_child = true; - } - else { - - // parent - is_parent = true; - close( coldplug_quiesce_pipe[1] ); - } - } - } - - if( !is_parent || vdev.config->foreground || vdev.config->coldplug_only ) { - - // child, or foreground, or coldplug only. start handling (coldplug) device events - rc = vdev_start( &vdev ); - if( rc != 0 ) { - - vdev_error("vdev_backend_init rc = %d\n", rc ); - - vdev_stop( &vdev ); - vdev_shutdown( &vdev, false ); - - // if child, and we're connected to the parent, then tell the parent to exit failure - if( is_child && !vdev.config->foreground && !vdev.config->coldplug_only ) { - - write( coldplug_quiesce_pipe[1], &rc, sizeof(rc) ); - close( coldplug_quiesce_pipe[1] ); - } - - exit(5); - } - - // main loop: get events from the OS and process them. - // wake up the parent once we finish the coldplugged devices - rc = vdev_main( &vdev, coldplug_finished_fd ); - if( rc != 0 ) { - - vdev_error("vdev_main rc = %d\n", rc ); - } - - // if only doing coldplug, find and remove all stale coldplug devices. - // use the metadata directory to figure this out - if( vdev.config->coldplug_only ) { - - rc = vdev_remove_unplugged_devices( &vdev ); - if( rc != 0 ) { - - vdev_error("vdev_remove_unplugged_devices() rc = %d\n", rc ); - } - } - - // quiesce requests - vdev_stop( &vdev ); - - // print benchmarks... - vdev_debug("%s", "Action benchmarks:\n"); - for( unsigned int i = 0; i < vdev.num_acts; i++ ) { - - vdev_action_log_benchmarks( &vdev.acts[i] ); - } - - // clean up - // keep the pidfile unless we're doing coldplug only (in which case don't touch it) - vdev_shutdown( &vdev, !vdev.config->coldplug_only ); - - return rc; - } - else { - - // parent process--wait for the child to finish processing the coldplugged devices, and exit. - nr = read( coldplug_quiesce_pipe[0], &rc, sizeof(rc) ); - - if( nr < 0 || rc != 0 ) { - - if( nr < 0 ) { - - vdev_error("read(%d) rc = %zd\n", coldplug_quiesce_pipe[0], nr ); - } - - vdev_error("device quiesce failure, child rc = %d\n", rc ); - exit(6); - } - - printf("parent: all initial devices processed\n"); - - // clean up, but keep the pidfile - vdev_shutdown( &vdev, false ); - - close( coldplug_quiesce_pipe[0] ); - - return 0; - } -} +int main(int argc, char **argv) +{ + + int rc = 0; + int coldplug_quiesce_pipe[2]; + bool is_child = false; + bool is_parent = false; + ssize_t nr = 0; + + int coldplug_finished_fd = -1; // FD to write to once we finish flushing the initial device requests + + memset(&vdev, 0, sizeof(struct vdev_state)); + + // ignore SIGPIPE from daemonlets + signal(SIGPIPE, SIG_IGN); + + // set up global vdev state + rc = vdev_init(&vdev, argc, argv); + // help called from command line -h or --help (-2) + // short circuit with log/debug support + if (vdev.config->help) { + if (rc == -2) { + + vdev_debug("%s", + "exiting: help called at command line\n"); + // the shutdown and clean up should be redundant ? + exit(0); + } + } + + if (rc != 0) { + + vdev_error("vdev_init rc = %d\n", rc); + + vdev_shutdown(&vdev, false); + exit(1); + } + // run the preseed command + rc = vdev_preseed_run(&vdev); + if (rc != 0) { + + vdev_error("vdev_preseed_run rc = %d\n", rc); + + vdev_shutdown(&vdev, false); + exit(1); + } + // if we're going to daemonize, then redirect logging to the logfile + if (!vdev.config->foreground) { + + // sanity check + if (vdev.config->logfile_path == NULL) { + + fprintf(stderr, "No logfile specified\n"); + + vdev_shutdown(&vdev, false); + exit(2); + } + // do we need to connect to syslog? + if (strcmp(vdev.config->logfile_path, "syslog") == 0) { + + vdev_debug("%s", "Switching to syslog for messages\n"); + vdev_enable_syslog(); + } + + else { + + // send to a specific logfile + rc = vdev_log_redirect(vdev.config->logfile_path); + if (rc != 0) { + + vdev_error("vdev_log_redirect('%s') rc = %d\n", + vdev.config->logfile_path, rc); + + vdev_shutdown(&vdev, false); + exit(2); + } + } + + if (!vdev.config->coldplug_only) { + + // will become a daemon after handling coldplug. + // set up a pipe between parent and child, so the child can + // signal the parent when it's device queue has been emptied + // (meaning the parent can safely exit). + + rc = pipe(coldplug_quiesce_pipe); + if (rc != 0) { + + vdev_error("pipe rc = %d\n", rc); + vdev_shutdown(&vdev, false); + + exit(3); + } + // become a daemon + rc = vdev_daemonize(); + if (rc < 0) { + + vdev_error("vdev_daemonize rc = %d\n", rc); + vdev_shutdown(&vdev, false); + + exit(3); + } + + if (rc == 0) { + + // child + close(coldplug_quiesce_pipe[0]); + coldplug_finished_fd = coldplug_quiesce_pipe[1]; + // write a pidfile + if (vdev.config->pidfile_path != NULL) { + + rc = vdev_pidfile_write(vdev. + config->pidfile_path); + if (rc != 0) { + + vdev_error + ("vdev_pidfile_write('%s') rc = %d\n", + vdev.config->pidfile_path, + rc); + + vdev_shutdown(&vdev, false); + exit(4); + } + } + // set reload handler + signal(SIGHUP, vdev_reload_sighup); + + is_child = true; + } else { + + // parent + is_parent = true; + close(coldplug_quiesce_pipe[1]); + } + } + } + + if (!is_parent || vdev.config->foreground || vdev.config->coldplug_only) { + + // child, or foreground, or coldplug only. start handling (coldplug) device events + rc = vdev_start(&vdev); + if (rc != 0) { + + vdev_error("vdev_backend_init rc = %d\n", rc); + + vdev_stop(&vdev); + vdev_shutdown(&vdev, false); + + // if child, and we're connected to the parent, then tell the parent to exit failure + if (is_child && !vdev.config->foreground + && !vdev.config->coldplug_only) { + + write(coldplug_quiesce_pipe[1], &rc, + sizeof(rc)); + close(coldplug_quiesce_pipe[1]); + } + + exit(5); + } + // main loop: get events from the OS and process them. + // wake up the parent once we finish the coldplugged devices + rc = vdev_main(&vdev, coldplug_finished_fd); + if (rc != 0) { + + vdev_error("vdev_main rc = %d\n", rc); + } + // if only doing coldplug, find and remove all stale coldplug devices. + // use the metadata directory to figure this out + if (vdev.config->coldplug_only) { + + rc = vdev_remove_unplugged_devices(&vdev); + if (rc != 0) { + + vdev_error + ("vdev_remove_unplugged_devices() rc = %d\n", + rc); + } + } + // quiesce requests + vdev_stop(&vdev); + + // print benchmarks... + vdev_debug("%s", "Action benchmarks:\n"); + for (unsigned int i = 0; i < vdev.num_acts; i++) { + + vdev_action_log_benchmarks(&vdev.acts[i]); + } + + // clean up + // keep the pidfile unless we're doing coldplug only (in which case don't touch it) + vdev_shutdown(&vdev, !vdev.config->coldplug_only); + + return rc; + } else { + + // parent process--wait for the child to finish processing the coldplugged devices, and exit. + nr = read(coldplug_quiesce_pipe[0], &rc, sizeof(rc)); + + if (nr < 0 || rc != 0) { + + if (nr < 0) { + + vdev_error("read(%d) rc = %zd\n", + coldplug_quiesce_pipe[0], nr); + } + + vdev_error("device quiesce failure, child rc = %d\n", + rc); + exit(6); + } + + printf("parent: all initial devices processed\n"); + + // clean up, but keep the pidfile + vdev_shutdown(&vdev, false); + + close(coldplug_quiesce_pipe[0]); + + return 0; + } +} diff --git a/vdevd/vdev.c b/vdevd/vdev.c index 6c98372..e0f194c 100644 --- a/vdevd/vdev.c +++ b/vdevd/vdev.c @@ -23,522 +23,533 @@ #include "action.h" #include "libvdev/config.h" -SGLIB_DEFINE_VECTOR_FUNCTIONS( cstr ) - - +SGLIB_DEFINE_VECTOR_FUNCTIONS(cstr) // context for removing unplugged device struct vdev_device_unplug_context { - - struct sglib_cstr_vector* device_paths; // queue of device paths to search - struct vdev_state* state; // vdev state + + struct sglib_cstr_vector *device_paths; // queue of device paths to search + struct vdev_state *state; // vdev state }; // get the instance of the vdevd program that made this device, given its device path // instance_str must be at least VDEV_CONFIG_INSTANCE_NONCE_STRLEN bytes // return 0 on success // return -errno on failure to stat, open, or read -static int vdev_device_read_vdevd_instance( char const* mountpoint, char const* dev_fullpath, char* instance_str ) { - - int rc = 0; - char const* devpath = dev_fullpath + strlen(mountpoint); - - char* instance_attr_relpath = vdev_fullpath( VDEV_METADATA_PREFIX "/dev", devpath, NULL ); - if( instance_attr_relpath == NULL ) { - - return -ENOMEM; - } - - char* instance_attr_path = vdev_fullpath( mountpoint, instance_attr_relpath, NULL ); - - free( instance_attr_relpath ); - instance_attr_relpath = NULL; - - if( instance_attr_path == NULL ) { - - return -ENOMEM; - } - - char* instance_path = vdev_fullpath( instance_attr_path, VDEV_METADATA_PARAM_INSTANCE, NULL ); - - free( instance_attr_path ); - instance_attr_path = NULL; - - if( instance_path == NULL ) { - - return -ENOMEM; - } - - // read the instance string - rc = vdev_read_file( instance_path, instance_str, VDEV_CONFIG_INSTANCE_NONCE_STRLEN - 1 ); - if( rc < 0 ) { - - vdev_error("vdev_read_file('%s') rc = %d\n", instance_path, rc ); - } - - free( instance_path ); - instance_path = NULL; - - return rc; -} +static int vdev_device_read_vdevd_instance(char const *mountpoint, + char const *dev_fullpath, + char *instance_str) +{ + + int rc = 0; + char const *devpath = dev_fullpath + strlen(mountpoint); + + char *instance_attr_relpath = + vdev_fullpath(VDEV_METADATA_PREFIX "/dev", devpath, NULL); + if (instance_attr_relpath == NULL) { + + return -ENOMEM; + } + + char *instance_attr_path = + vdev_fullpath(mountpoint, instance_attr_relpath, NULL); + + free(instance_attr_relpath); + instance_attr_relpath = NULL; + + if (instance_attr_path == NULL) { + + return -ENOMEM; + } + + char *instance_path = + vdev_fullpath(instance_attr_path, VDEV_METADATA_PARAM_INSTANCE, + NULL); + free(instance_attr_path); + instance_attr_path = NULL; + + if (instance_path == NULL) { + + return -ENOMEM; + } + // read the instance string + rc = vdev_read_file(instance_path, instance_str, + VDEV_CONFIG_INSTANCE_NONCE_STRLEN - 1); + if (rc < 0) { + + vdev_error("vdev_read_file('%s') rc = %d\n", instance_path, rc); + } + + free(instance_path); + instance_path = NULL; + + return rc; +} // scan callback for a directory. // queue directories, and unlink device files that are no longer plugged in. // return 0 on success // return -ENOMEM on OOM // NOTE: mask unlink() failures, but log them. -static int vdev_remove_unplugged_device( char const* path, void* cls ) { - - int rc = 0; - struct stat sb; - char instance_str[ VDEV_CONFIG_INSTANCE_NONCE_STRLEN + 1 ]; - char basename[ NAME_MAX+1 ]; - - memset( instance_str, 0, VDEV_CONFIG_INSTANCE_NONCE_STRLEN + 1 ); - - // extract cls - struct vdev_device_unplug_context* ctx = (struct vdev_device_unplug_context*)cls; - - struct sglib_cstr_vector* device_paths = ctx->device_paths; - struct vdev_state* state = ctx->state; - - if( strlen(path) == 0 ) { - - // nothing to do - return 0; - } - - vdev_basename( path, basename ); - - // is this . or ..? - if( strcmp(basename, ".") == 0 || strcmp(basename, "..") == 0 ) { - return 0; - } - - // what is this? - rc = lstat( path, &sb ); - if( rc != 0 ) { - - vdev_error("stat('%s') rc = %d\n", path, rc ); - - // mask - return 0; - } - - // is this a directory? - if( S_ISDIR( sb.st_mode ) ) { - - // skip the metadata dir - if( strcmp( basename, "metadata" ) == 0 ) { - return 0; - } - - // search this later - char* path_dup = vdev_strdup_or_null( path ); - if( path_dup == NULL ) { - - // really can't continue - return -ENOMEM; - } - - sglib_cstr_vector_push_back( device_paths, path_dup ); - - return 0; - } - - // is this a device file? - if( S_ISBLK( sb.st_mode ) || S_ISCHR( sb.st_mode ) ) { - - // what's the instance value? - rc = vdev_device_read_vdevd_instance( state->config->mountpoint, path, instance_str ); - if( rc != 0 ) { - - vdev_error("vdev_device_read_vdevd_instance('%s') rc = %d\n", path, rc ); - - // mask - return 0; - } - - // does it match ours? - if( strcmp( state->config->instance_str, instance_str ) != 0 ) { - - struct vdev_device_request* to_delete = NULL; - char const* device_path = NULL; - - vdev_debug("Remove unplugged device '%s'\n", path ); - - device_path = path + strlen( state->config->mountpoint ); - - to_delete = VDEV_CALLOC( struct vdev_device_request, 1 ); - if( to_delete == NULL ) { - - // OOM - return -ENOMEM; - } - - rc = vdev_device_request_init( to_delete, state, VDEV_DEVICE_REMOVE, device_path ); - if( rc != 0 ) { - - // OOM - return rc; - } - - // populate - vdev_device_request_set_dev( to_delete, sb.st_rdev ); - vdev_device_request_set_mode( to_delete, S_ISBLK( sb.st_mode ) ? S_IFBLK : S_IFCHR ); - - // remove it - rc = vdev_device_remove( to_delete ); - if( rc != 0 ) { - - vdev_warn("vdev_device_remove('%s') rc = %d\n", device_path, rc ); - rc = 0; - } - } - } - - return 0; -} +static int vdev_remove_unplugged_device(char const *path, void *cls) +{ + int rc = 0; + struct stat sb; + char instance_str[VDEV_CONFIG_INSTANCE_NONCE_STRLEN + 1]; + char basename[NAME_MAX + 1]; + + memset(instance_str, 0, VDEV_CONFIG_INSTANCE_NONCE_STRLEN + 1); + + // extract cls + struct vdev_device_unplug_context *ctx = + (struct vdev_device_unplug_context *)cls; + + struct sglib_cstr_vector *device_paths = ctx->device_paths; + struct vdev_state *state = ctx->state; + + if (strlen(path) == 0) { + + // nothing to do + return 0; + } + + vdev_basename(path, basename); + + // is this . or ..? + if (strcmp(basename, ".") == 0 || strcmp(basename, "..") == 0) { + return 0; + } + // what is this? + rc = lstat(path, &sb); + if (rc != 0) { + + vdev_error("stat('%s') rc = %d\n", path, rc); + + // mask + return 0; + } + // is this a directory? + if (S_ISDIR(sb.st_mode)) { + + // skip the metadata dir + if (strcmp(basename, "metadata") == 0) { + return 0; + } + // search this later + char *path_dup = vdev_strdup_or_null(path); + if (path_dup == NULL) { + + // really can't continue + return -ENOMEM; + } + + sglib_cstr_vector_push_back(device_paths, path_dup); + + return 0; + } + // is this a device file? + if (S_ISBLK(sb.st_mode) || S_ISCHR(sb.st_mode)) { + + // what's the instance value? + rc = vdev_device_read_vdevd_instance(state->config->mountpoint, + path, instance_str); + if (rc != 0) { + + vdev_error + ("vdev_device_read_vdevd_instance('%s') rc = %d\n", + path, rc); + + // mask + return 0; + } + // does it match ours? + if (strcmp(state->config->instance_str, instance_str) != 0) { + + struct vdev_device_request *to_delete = NULL; + char const *device_path = NULL; + + vdev_debug("Remove unplugged device '%s'\n", path); + + device_path = path + strlen(state->config->mountpoint); + + to_delete = VDEV_CALLOC(struct vdev_device_request, 1); + if (to_delete == NULL) { + + // OOM + return -ENOMEM; + } + + rc = vdev_device_request_init(to_delete, state, + VDEV_DEVICE_REMOVE, + device_path); + if (rc != 0) { + + // OOM + return rc; + } + // populate + vdev_device_request_set_dev(to_delete, sb.st_rdev); + vdev_device_request_set_mode(to_delete, + S_ISBLK(sb.st_mode) ? + S_IFBLK : S_IFCHR); + + // remove it + rc = vdev_device_remove(to_delete); + if (rc != 0) { + + vdev_warn("vdev_device_remove('%s') rc = %d\n", + device_path, rc); + rc = 0; + } + } + } + + return 0; +} // remove all devices that no longer exist--that is, the contents of the /dev/metadata/$DEVICE_PATH/dev_instance file // does not match this vdev's instance nonce. // this is used when running with --once. -int vdev_remove_unplugged_devices( struct vdev_state* state ) { - - int rc = 0; - struct sglib_cstr_vector device_paths; - char* devroot = vdev_strdup_or_null( state->config->mountpoint ); - char* next_dir = NULL; - size_t next_dir_index = 0; - // sb ? - struct stat sb; - - struct vdev_device_unplug_context unplug_ctx; - - unplug_ctx.state = state; - unplug_ctx.device_paths = &device_paths; - - if( devroot == NULL ) { - return -ENOMEM; - } - - sglib_cstr_vector_init( &device_paths ); - - // walk /dev breadth-first - rc = sglib_cstr_vector_push_back( &device_paths, devroot ); - if( rc != 0 ) { - - sglib_cstr_vector_free( &device_paths ); - free( devroot ); - - return rc; - } - - while( next_dir_index < sglib_cstr_vector_size( &device_paths ) ) { - - // next path - next_dir = sglib_cstr_vector_at( &device_paths, next_dir_index ); - sglib_cstr_vector_set( &device_paths, NULL, next_dir_index ); - - next_dir_index++; - - // scan this directory, and remove unplugged device files and remember the directories to search - rc = vdev_load_all( next_dir, vdev_remove_unplugged_device, &unplug_ctx ); - if( rc != 0 ) { - - vdev_error("vdev_load_all('%s') rc = %d\n", next_dir, rc ); - - free( next_dir ); - break; - } - - free( next_dir ); - } - - // free any unused vector space - while( next_dir_index < sglib_cstr_vector_size( &device_paths ) ) { - - next_dir = sglib_cstr_vector_at( &device_paths, next_dir_index ); - sglib_cstr_vector_set( &device_paths, NULL, next_dir_index ); - - next_dir_index++; - - free( next_dir ); - } - - sglib_cstr_vector_free( &device_paths ); - - return rc; -} +int vdev_remove_unplugged_devices(struct vdev_state *state) +{ + + int rc = 0; + struct sglib_cstr_vector device_paths; + char *devroot = vdev_strdup_or_null(state->config->mountpoint); + char *next_dir = NULL; + size_t next_dir_index = 0; + // sb ? + struct stat sb; + + struct vdev_device_unplug_context unplug_ctx; + unplug_ctx.state = state; + unplug_ctx.device_paths = &device_paths; + + if (devroot == NULL) { + return -ENOMEM; + } + + sglib_cstr_vector_init(&device_paths); + + // walk /dev breadth-first + rc = sglib_cstr_vector_push_back(&device_paths, devroot); + if (rc != 0) { + + sglib_cstr_vector_free(&device_paths); + free(devroot); + + return rc; + } + + while (next_dir_index < sglib_cstr_vector_size(&device_paths)) { + + // next path + next_dir = sglib_cstr_vector_at(&device_paths, next_dir_index); + sglib_cstr_vector_set(&device_paths, NULL, next_dir_index); + + next_dir_index++; + + // scan this directory, and remove unplugged device files and remember the directories to search + rc = vdev_load_all(next_dir, vdev_remove_unplugged_device, + &unplug_ctx); + if (rc != 0) { + + vdev_error("vdev_load_all('%s') rc = %d\n", next_dir, + rc); + + free(next_dir); + break; + } + + free(next_dir); + } + + // free any unused vector space + while (next_dir_index < sglib_cstr_vector_size(&device_paths)) { + + next_dir = sglib_cstr_vector_at(&device_paths, next_dir_index); + sglib_cstr_vector_set(&device_paths, NULL, next_dir_index); + + next_dir_index++; + + free(next_dir); + } + + sglib_cstr_vector_free(&device_paths); + + return rc; +} // create the path to the error FIFO // that helpers use to write error messages. // return 0 on success // return -EPERM on overflow -int vdev_error_fifo_path( char const* mountpoint, char* path, size_t path_len ) { +int vdev_error_fifo_path(char const *mountpoint, char *path, size_t path_len) +{ - int rc = 0; - rc = snprintf( path, path_len, "%s/%s/err.pipe", mountpoint, VDEV_METADATA_PREFIX ); - if( rc >= path_len ) { - return -EPERM; - } + int rc = 0; + rc = snprintf(path, path_len, "%s/%s/err.pipe", mountpoint, + VDEV_METADATA_PREFIX); + if (rc >= path_len) { + return -EPERM; + } - return 0; + return 0; } - // get a handle to the error FIFO, creating the FIFO if it doesn't yet exist. // the handle will be in read/write mode // return 0 on success, and set *fd // return -errno on failure to create the FIFO -int vdev_error_fifo_get_or_create( char const* mountpoint, int* fd ) { - - int rc = 0; - char fifo_path[PATH_MAX+1]; - struct stat sb; - memset( fifo_path, 0, PATH_MAX+1 ); - - rc = vdev_error_fifo_path( mountpoint, fifo_path, PATH_MAX ); - if( rc < 0 ) { - return rc; - } - - rc = stat( fifo_path, &sb ); - if( rc != 0 ) { - - rc = -errno; - if( rc != -ENOENT ) { - - vdev_error("failed to create FIFO '%s': %s\n", fifo_path, strerror( -rc ) ); - return rc; - } - - // create - rc = mkfifo( fifo_path, 0600 ); - if( rc != 0 ) { - - rc = -errno; - vdev_error("mkfifo('%s'): %s\n", fifo_path, strerror( -rc ) ); - return rc; - } - } - - *fd = open( fifo_path, O_RDWR ); - if( *fd < 0 ) { - - rc = -errno; - vdev_error("open('%s'): %s\n", fifo_path, strerror( -rc ) ); - return rc; - } - - return 0; +int vdev_error_fifo_get_or_create(char const *mountpoint, int *fd) +{ + + int rc = 0; + char fifo_path[PATH_MAX + 1]; + struct stat sb; + memset(fifo_path, 0, PATH_MAX + 1); + + rc = vdev_error_fifo_path(mountpoint, fifo_path, PATH_MAX); + if (rc < 0) { + return rc; + } + + rc = stat(fifo_path, &sb); + if (rc != 0) { + + rc = -errno; + if (rc != -ENOENT) { + + vdev_error("failed to create FIFO '%s': %s\n", + fifo_path, strerror(-rc)); + return rc; + } + // create + rc = mkfifo(fifo_path, 0600); + if (rc != 0) { + + rc = -errno; + vdev_error("mkfifo('%s'): %s\n", fifo_path, + strerror(-rc)); + return rc; + } + } + + *fd = open(fifo_path, O_RDWR); + if (*fd < 0) { + + rc = -errno; + vdev_error("open('%s'): %s\n", fifo_path, strerror(-rc)); + return rc; + } + + return 0; } - - // thread for gathering error messages from the helpers and forwarding // them to our logging system. // *arg is an int, which is the error pipe to read from -void* vdev_error_thread_main( void* arg ) { - - int rc = 0; - int fd = *((int*)arg); - char buf[4096]; - ssize_t nr = 0; - int flags = 0; - fd_set read_fds; - - // put into non-blocking mode - flags = fcntl( fd, F_GETFL, 0 ); - if( flags < 0 ) { - rc = -errno; - vdev_error("fcntl(%d, F_GETFL): %s\n", fd, strerror(-rc) ); - return NULL; - } - - rc = fcntl( fd, F_SETFL, flags | O_NONBLOCK ); - if( rc < 0 ) { - rc = -errno; - vdev_error("fctnl(%d, F_SETFL): %s\n", fd, strerror(-rc) ); - return NULL; - } - - while( 1 ) { - - FD_ZERO( &read_fds ); - FD_SET( fd, &read_fds ); - - rc = select( fd + 1, &read_fds, NULL, NULL, NULL ); - if( rc == 0 ) { - - // not ready - continue; - } - - if( rc < 0 ) { - - // pipe closed - break; - } - - nr = read( fd, buf, 4095 ); - if( nr <= 0 ) { - - // closed, invalidated, etc. - break; - } - - // truncate and log - buf[nr] = 0; - - vdev_error( "%s", buf ); - } - - return NULL; +void *vdev_error_thread_main(void *arg) +{ + + int rc = 0; + int fd = *((int *)arg); + char buf[4096]; + ssize_t nr = 0; + int flags = 0; + fd_set read_fds; + + // put into non-blocking mode + flags = fcntl(fd, F_GETFL, 0); + if (flags < 0) { + rc = -errno; + vdev_error("fcntl(%d, F_GETFL): %s\n", fd, strerror(-rc)); + return NULL; + } + + rc = fcntl(fd, F_SETFL, flags | O_NONBLOCK); + if (rc < 0) { + rc = -errno; + vdev_error("fctnl(%d, F_SETFL): %s\n", fd, strerror(-rc)); + return NULL; + } + + while (1) { + + FD_ZERO(&read_fds); + FD_SET(fd, &read_fds); + + rc = select(fd + 1, &read_fds, NULL, NULL, NULL); + if (rc == 0) { + + // not ready + continue; + } + + if (rc < 0) { + + // pipe closed + break; + } + + nr = read(fd, buf, 4095); + if (nr <= 0) { + + // closed, invalidated, etc. + break; + } + // truncate and log + buf[nr] = 0; + + vdev_error("%s", buf); + } + + return NULL; } - // start the error-listining thread // return 0 on success, and set state->error_thread // return -errno on failure -int vdev_error_thread_start( struct vdev_state* vdev ) { +int vdev_error_thread_start(struct vdev_state *vdev) +{ - int rc = 0; - pthread_attr_t attrs; + int rc = 0; + pthread_attr_t attrs; - rc = vdev_error_fifo_get_or_create( vdev->config->mountpoint, &vdev->error_fd ); - if( rc < 0 ) { + rc = vdev_error_fifo_get_or_create(vdev->config->mountpoint, + &vdev->error_fd); + if (rc < 0) { - vdev_error("vdev_error_fifo_get_or_create: %s\n", strerror(-rc) ); - return rc; - } + vdev_error("vdev_error_fifo_get_or_create: %s\n", + strerror(-rc)); + return rc; + } - rc = pthread_attr_init( &attrs ); - if( rc != 0 ) { + rc = pthread_attr_init(&attrs); + if (rc != 0) { - vdev_error("pthread_attr_init: %s\n", strerror(rc) ); - return -rc; - } + vdev_error("pthread_attr_init: %s\n", strerror(rc)); + return -rc; + } - vdev->error_thread_running = true; + vdev->error_thread_running = true; - rc = pthread_create( &vdev->error_thread, &attrs, vdev_error_thread_main, &vdev->error_fd ); - if( rc != 0 ) { + rc = pthread_create(&vdev->error_thread, &attrs, vdev_error_thread_main, + &vdev->error_fd); + if (rc != 0) { - vdev->error_thread_running = false; - vdev_error("pthread_crate: %s\n", strerror(rc) ); - return -rc; - } + vdev->error_thread_running = false; + vdev_error("pthread_crate: %s\n", strerror(rc)); + return -rc; + } - return 0; + return 0; } - // stop the error-listening thread // return 0 on success -int vdev_error_thread_stop( struct vdev_state* vdev ) { +int vdev_error_thread_stop(struct vdev_state *vdev) +{ - int rc = 0; - if( !vdev->error_thread_running ) { - // already stopped - return 0; - } + int rc = 0; + if (!vdev->error_thread_running) { + // already stopped + return 0; + } - if( vdev->error_fd >= 0 ) { - - int fd = vdev->error_fd; - vdev->error_fd = -1; + if (vdev->error_fd >= 0) { - close( fd ); - } + int fd = vdev->error_fd; + vdev->error_fd = -1; - rc = pthread_cancel( vdev->error_thread ); - if( rc != 0 ) { + close(fd); + } - vdev_error("pthread_cancel: %s\n", strerror(rc) ); - } + rc = pthread_cancel(vdev->error_thread); + if (rc != 0) { - rc = pthread_join( vdev->error_thread, NULL ); - if( rc != 0 ) { + vdev_error("pthread_cancel: %s\n", strerror(rc)); + } - vdev_error("pthread_join: %s\n", strerror(rc) ); - } + rc = pthread_join(vdev->error_thread, NULL); + if (rc != 0) { - vdev->error_thread_running = false; + vdev_error("pthread_join: %s\n", strerror(rc)); + } - return 0; -} + vdev->error_thread_running = false; + return 0; +} // start up the back-end // return 0 on success // return -ENOMEM on OOM // return negative if the OS-specific back-end fails to initialize -int vdev_start( struct vdev_state* vdev ) { - - int rc = 0; - - // otherwise, it's already given - vdev->running = true; - - // initialize OS-specific state, and start feeding requests - vdev->os = VDEV_CALLOC( struct vdev_os_context, 1 ); - - if( vdev->os == NULL ) { - - return -ENOMEM; - } - - // set up error capture - rc = vdev_error_thread_start( vdev ); - if( rc != 0 ) { - - vdev_error("vdev_error_thread_start: %s\n", strerror(-rc) ); - free( vdev->os ); - vdev->os = NULL; - return rc; - } - - // start processing requests - rc = vdev_wq_start( &vdev->device_wq ); - if( rc != 0 ) { - - vdev_error("vdev_wq_start: %s\n", strerror(-rc) ); - - int erc = vdev_error_thread_stop( vdev ); - if( erc != 0 ) { - - vdev_error("vdev_error_thread_stop: %s\n", strerror(-erc) ); - } - - free( vdev->os ); - vdev->os = NULL; - return rc; - } - - rc = vdev_os_context_init( vdev->os, vdev ); - - if( rc != 0 ) { - - vdev_error("vdev_os_context_init rc = %d\n", rc ); - - int wqrc = vdev_wq_stop( &vdev->device_wq, false ); - if( wqrc != 0 ) { - - vdev_error("vdev_wq_stop rc = %d\n", wqrc); - } - - vdev_error_thread_stop( vdev ); - free( vdev->os ); - vdev->os = NULL; - return rc; - } - - return 0; -} +int vdev_start(struct vdev_state *vdev) +{ + + int rc = 0; + + // otherwise, it's already given + vdev->running = true; + + // initialize OS-specific state, and start feeding requests + vdev->os = VDEV_CALLOC(struct vdev_os_context, 1); + + if (vdev->os == NULL) { + + return -ENOMEM; + } + // set up error capture + rc = vdev_error_thread_start(vdev); + if (rc != 0) { + + vdev_error("vdev_error_thread_start: %s\n", strerror(-rc)); + free(vdev->os); + vdev->os = NULL; + return rc; + } + // start processing requests + rc = vdev_wq_start(&vdev->device_wq); + if (rc != 0) { + + vdev_error("vdev_wq_start: %s\n", strerror(-rc)); + + int erc = vdev_error_thread_stop(vdev); + if (erc != 0) { + vdev_error("vdev_error_thread_stop: %s\n", + strerror(-erc)); + } + + free(vdev->os); + vdev->os = NULL; + return rc; + } + + rc = vdev_os_context_init(vdev->os, vdev); + + if (rc != 0) { + + vdev_error("vdev_os_context_init rc = %d\n", rc); + + int wqrc = vdev_wq_stop(&vdev->device_wq, false); + if (wqrc != 0) { + + vdev_error("vdev_wq_stop rc = %d\n", wqrc); + } + + vdev_error_thread_stop(vdev); + free(vdev->os); + vdev->os = NULL; + return rc; + } + + return 0; +} // process a single line of text into a device request // @@ -556,166 +567,167 @@ int vdev_start( struct vdev_state* vdev ) { // return -ENOENT if we're missing a parameter // return -EINVAL if the parameter is malformed // return -ENOMEM on OOM -int vdev_parse_device_request( struct vdev_state* state, struct vdev_device_request* vreq, char* line ) { - - int rc = 0; - int stat_rc; - char* tok = NULL; - char* tokstr = line; - char* tok_ctx = NULL; - char* tmp = NULL; - - mode_t mode = 0; - dev_t major = 0; - dev_t minor = 0; - char name[4097]; - char fullpath[ PATH_MAX+1 ]; - char keyvalue_buf[4097]; - char* key = NULL; - char* value = NULL; - - struct stat sb; - - // type - tok = strtok_r( tokstr, " \t", &tok_ctx ); - tokstr = NULL; - - if( tok == NULL ) { - - // no type - fprintf(stderr, "Missing type\n"); - return -ENOENT; - } - - if( strlen(tok) != 1 ) { - - // invalid type - fprintf(stderr, "Unrecognized type '%s'. Expected 'c', 'b', or 'u'\n", tok ); - return -EINVAL; - } - - if( tok[0] != 'c' && tok[0] != 'b' && tok[0] != 'u' ) { - - // invalid type - fprintf(stderr, "Unrecognized type '%s'. Expected 'c', 'b', or 'u'\n", tok ); - return -EINVAL; - } - - if( tok[0] == 'c' ) { - mode = S_IFCHR; - } - else if( tok[0] == 'b' ) { - mode = S_IFBLK; - } - - // name - tok = strtok_r( tokstr, " \t", &tok_ctx ); - if( tok == NULL ) { - - // no name - fprintf(stderr, "Missing name\n"); - return -ENOENT; - } - - strcpy( name, tok ); - - // major - tok = strtok_r( tokstr, " \t", &tok_ctx ); - if( tok == NULL ) { - - // no major - fprintf(stderr, "Missing major device number\n"); - return -ENOENT; - } - - major = (dev_t)strtoul( tok, &tmp, 10 ); - if( tmp == tok || *tmp != '\0' ) { - - // invalid major - fprintf(stderr, "Invalid major device number '%s'\n", tok ); - return -EINVAL; - } - - // minor - tok = strtok_r( tokstr, " \t", &tok_ctx ); - if( tok == NULL ) { - - // no minor - fprintf(stderr, "Missing minor device number\n"); - return -ENOENT; - } - - minor = (dev_t)strtoul( tok, &tmp, 10 ); - if( tmp == tok || *tmp != '\0' ) { - - // invalid minor - fprintf(stderr, "Invalid minor device number '%s'\n", tok ); - return -EINVAL; - } - - // set up the device... - rc = vdev_device_request_init( vreq, state, VDEV_DEVICE_ADD, name ); - if( rc != 0 ) { - - vdev_error("vdev_device_request_init('%s') rc = %d\n", name, rc ); - return rc; - } - - vdev_device_request_set_type( vreq, VDEV_DEVICE_ADD ); - vdev_device_request_set_mode( vreq, mode ); - vdev_device_request_set_dev( vreq, makedev( major, minor ) ); - - // parameters - while( tok != NULL ) { - - tok = strtok_r( tokstr, " \t", &tok_ctx ); - if( tok == NULL ) { - break; - } - - if( strlen(tok) > 4096 ) { - - // too big - fprintf(stderr, "OS parameter too long: '%s'\n", tok ); - vdev_device_request_free( vreq ); - return -EINVAL; - } - - strcpy( keyvalue_buf, tok ); - - rc = vdev_keyvalue_next( keyvalue_buf, &key, &value ); - if( rc < 0 ) { - - // could not parse - fprintf(stderr, "Unparsible OS parameter: '%s'\n", tok ); - vdev_device_request_free( vreq ); - return -EINVAL; - } - - rc = vdev_device_request_add_param( vreq, key, value ); - if( rc != 0 ) { - - vdev_device_request_free( vreq ); - return rc; - } - } - - // finally, does this device exist already? - snprintf( fullpath, PATH_MAX, "%s/%s", state->config->mountpoint, name ); - stat_rc = lstat( fullpath, &sb ); - - if( stat_rc == 0 ) { - - vdev_device_request_set_exists( vreq, true ); - } - else { - - vdev_device_request_set_exists( vreq, false ); - } - - return rc; -} +int vdev_parse_device_request(struct vdev_state *state, + struct vdev_device_request *vreq, char *line) +{ + + int rc = 0; + int stat_rc; + char *tok = NULL; + char *tokstr = line; + char *tok_ctx = NULL; + char *tmp = NULL; + + mode_t mode = 0; + dev_t major = 0; + dev_t minor = 0; + char name[4097]; + char fullpath[PATH_MAX + 1]; + char keyvalue_buf[4097]; + char *key = NULL; + char *value = NULL; + + struct stat sb; + + // type + tok = strtok_r(tokstr, " \t", &tok_ctx); + tokstr = NULL; + + if (tok == NULL) { + + // no type + fprintf(stderr, "Missing type\n"); + return -ENOENT; + } + + if (strlen(tok) != 1) { + + // invalid type + fprintf(stderr, + "Unrecognized type '%s'. Expected 'c', 'b', or 'u'\n", + tok); + return -EINVAL; + } + + if (tok[0] != 'c' && tok[0] != 'b' && tok[0] != 'u') { + + // invalid type + fprintf(stderr, + "Unrecognized type '%s'. Expected 'c', 'b', or 'u'\n", + tok); + return -EINVAL; + } + + if (tok[0] == 'c') { + mode = S_IFCHR; + } else if (tok[0] == 'b') { + mode = S_IFBLK; + } + // name + tok = strtok_r(tokstr, " \t", &tok_ctx); + if (tok == NULL) { + + // no name + fprintf(stderr, "Missing name\n"); + return -ENOENT; + } + + strcpy(name, tok); + + // major + tok = strtok_r(tokstr, " \t", &tok_ctx); + if (tok == NULL) { + + // no major + fprintf(stderr, "Missing major device number\n"); + return -ENOENT; + } + + major = (dev_t) strtoul(tok, &tmp, 10); + if (tmp == tok || *tmp != '\0') { + + // invalid major + fprintf(stderr, "Invalid major device number '%s'\n", tok); + return -EINVAL; + } + // minor + tok = strtok_r(tokstr, " \t", &tok_ctx); + if (tok == NULL) { + + // no minor + fprintf(stderr, "Missing minor device number\n"); + return -ENOENT; + } + + minor = (dev_t) strtoul(tok, &tmp, 10); + if (tmp == tok || *tmp != '\0') { + + // invalid minor + fprintf(stderr, "Invalid minor device number '%s'\n", tok); + return -EINVAL; + } + // set up the device... + rc = vdev_device_request_init(vreq, state, VDEV_DEVICE_ADD, name); + if (rc != 0) { + + vdev_error("vdev_device_request_init('%s') rc = %d\n", name, + rc); + return rc; + } + + vdev_device_request_set_type(vreq, VDEV_DEVICE_ADD); + vdev_device_request_set_mode(vreq, mode); + vdev_device_request_set_dev(vreq, makedev(major, minor)); + + // parameters + while (tok != NULL) { + + tok = strtok_r(tokstr, " \t", &tok_ctx); + if (tok == NULL) { + break; + } + + if (strlen(tok) > 4096) { + + // too big + fprintf(stderr, "OS parameter too long: '%s'\n", tok); + vdev_device_request_free(vreq); + return -EINVAL; + } + + strcpy(keyvalue_buf, tok); + + rc = vdev_keyvalue_next(keyvalue_buf, &key, &value); + if (rc < 0) { + + // could not parse + fprintf(stderr, "Unparsible OS parameter: '%s'\n", tok); + vdev_device_request_free(vreq); + return -EINVAL; + } + + rc = vdev_device_request_add_param(vreq, key, value); + if (rc != 0) { + + vdev_device_request_free(vreq); + return rc; + } + } + + // finally, does this device exist already? + snprintf(fullpath, PATH_MAX, "%s/%s", state->config->mountpoint, name); + stat_rc = lstat(fullpath, &sb); + + if (stat_rc == 0) { + + vdev_device_request_set_exists(vreq, true); + } else { + + vdev_device_request_set_exists(vreq, false); + } + return rc; +} // process a newline-delimited textual list of device events. // @@ -732,531 +744,543 @@ int vdev_parse_device_request( struct vdev_state* state, struct vdev_device_requ // NOTE: currently, we do not tolerate spaces in any of these fields. Sorry. // return 0 on success // return -ERANGE if a line exceeded 4096 characters -int vdev_load_device_requests( struct vdev_state* state, char* text_buf, size_t text_buflen ) { - - int rc = 0; - char* cur_line = NULL; - char* next_line = NULL; - - struct vdev_device_request* vreq = NULL; - - size_t consumed = 0; - size_t line_len = 0; - char line_buf[4097]; - char line_buf_dbg[4097]; // for debugging - - dev_t major = 0; - dev_t minor = 0; - - cur_line = text_buf; - while( consumed < text_buflen && cur_line != NULL ) { - - next_line = strchr( cur_line, '\n' ); - if( next_line == NULL ) { - - line_len = strlen( cur_line ); - - if( line_len == 0 ) { - // done - break; - } - - // last line - if( line_len < 4096 ) { - - strcpy( line_buf, cur_line ); - } - else { - - // too big - return -ERANGE; - } - } - else { - - // copy until '\n' - line_len = (size_t)(next_line - cur_line) / sizeof(char); - memcpy( line_buf, cur_line, line_len ); - - line_buf[ line_len ] = '\0'; - } - - vdev_debug("Preseed device: '%s'\n", line_buf ); - - strcpy( line_buf_dbg, line_buf ); - - vreq = VDEV_CALLOC( struct vdev_device_request, 1 ); - if( vreq == NULL ) { - - // OOM - return -ENOMEM; - } - - // consume the line - rc = vdev_parse_device_request( state, vreq, line_buf ); - if( rc != 0 ) { - - fprintf(stderr, "Could not parse line '%s' (rc = %d)\n", line_buf_dbg, rc ); - vdev_error("vdev_parse_device_request('%s') rc = %d\n", line_buf_dbg, rc ); - - free( vreq ); - return rc; - } - - // enqueue the device! - rc = vdev_device_request_enqueue( &state->device_wq, vreq ); - if( rc != 0 ) { - - vdev_error("vdev_device_request_enqueue('%s') rc = %d\n", line_buf_dbg, rc ); - - free( vreq ); - return rc; - } - - // next line - cur_line = next_line; - consumed += strlen(next_line); - - while( consumed < text_buflen && *cur_line == '\n' ) { - - cur_line++; - consumed++; - } - } - - return rc; -} +int vdev_load_device_requests(struct vdev_state *state, char *text_buf, + size_t text_buflen) +{ + + int rc = 0; + char *cur_line = NULL; + char *next_line = NULL; + + struct vdev_device_request *vreq = NULL; + + size_t consumed = 0; + size_t line_len = 0; + char line_buf[4097]; + char line_buf_dbg[4097]; // for debugging + + dev_t major = 0; + dev_t minor = 0; + + cur_line = text_buf; + while (consumed < text_buflen && cur_line != NULL) { + + next_line = strchr(cur_line, '\n'); + if (next_line == NULL) { + + line_len = strlen(cur_line); + + if (line_len == 0) { + // done + break; + } + // last line + if (line_len < 4096) { + + strcpy(line_buf, cur_line); + } else { + + // too big + return -ERANGE; + } + } else { + + // copy until '\n' + line_len = + (size_t) (next_line - cur_line) / sizeof(char); + memcpy(line_buf, cur_line, line_len); + + line_buf[line_len] = '\0'; + } + + vdev_debug("Preseed device: '%s'\n", line_buf); + + strcpy(line_buf_dbg, line_buf); + + vreq = VDEV_CALLOC(struct vdev_device_request, 1); + if (vreq == NULL) { + + // OOM + return -ENOMEM; + } + // consume the line + rc = vdev_parse_device_request(state, vreq, line_buf); + if (rc != 0) { + + fprintf(stderr, "Could not parse line '%s' (rc = %d)\n", + line_buf_dbg, rc); + vdev_error("vdev_parse_device_request('%s') rc = %d\n", + line_buf_dbg, rc); + + free(vreq); + return rc; + } + // enqueue the device! + rc = vdev_device_request_enqueue(&state->device_wq, vreq); + if (rc != 0) { + + vdev_error + ("vdev_device_request_enqueue('%s') rc = %d\n", + line_buf_dbg, rc); + + free(vreq); + return rc; + } + // next line + cur_line = next_line; + consumed += strlen(next_line); + + while (consumed < text_buflen && *cur_line == '\n') { + cur_line++; + consumed++; + } + } + + return rc; +} // run the pre-seed command, if given // return 0 on success // return -ENOMEM on OOM // return non-zero on non-zero exit status // TODO: "unlimited" output buffer space--like a pipe -int vdev_preseed_run( struct vdev_state* vdev ) { - - int rc = 0; - int exit_status = 0; - char* command = NULL; - - size_t output_len = 1024 * 1024; // 1MB buffer for initial devices, just in case - char* output = NULL; - - if( vdev->config->preseed_path == NULL ) { - // nothing to do - return 0; - } - - output = VDEV_CALLOC( char, output_len ); - if( output == NULL ) { - - // OOM - return -ENOMEM; - } - - command = VDEV_CALLOC( char, strlen( vdev->config->preseed_path ) + 2 + strlen( vdev->config->mountpoint ) + 2 + strlen( vdev->config->config_path ) + 1 ); - if( command == NULL ) { - - // OOM - free( output ); - return -ENOMEM; - } - - sprintf(command, "%s %s %s", vdev->config->preseed_path, vdev->config->mountpoint, vdev->config->config_path ); - - rc = vdev_subprocess( command, NULL, &output, output_len, -1, &exit_status, true ); - if( rc != 0 ) { - - vdev_error("vdev_subprocess('%s') rc = %d\n", command, rc ); - } - else if( exit_status != 0 ) { - - vdev_error("vdev_subprocess('%s') exit status %d\n", command, exit_status ); - rc = exit_status; - } - - free( command ); - command = NULL; - - if( rc != 0 ) { - - free( output ); - return rc; - } - - // process the preseed devices... - rc = vdev_load_device_requests( vdev, output, output_len ); - if( rc != 0 ) { - - vdev_error("vdev_load_device_requests rc = %d\n", rc); - } - - free( output ); - output = NULL; - - return rc; -} +int vdev_preseed_run(struct vdev_state *vdev) +{ + int rc = 0; + int exit_status = 0; + char *command = NULL; -// global vdev initialization -int vdev_init( struct vdev_state* vdev, int argc, char** argv ) { - - int rc = 0; - - // global setup - vdev_setup_global(); - - pthread_mutex_init( &vdev->reload_lock, NULL ); - vdev->error_fd = -1; - vdev->coldplug_finished_fd = -1; - - // config... - vdev->config = VDEV_CALLOC( struct vdev_config, 1 ); - if( vdev->config == NULL ) { - - return -ENOMEM; - } - - // config init - rc = vdev_config_init( vdev->config ); - if( rc != 0 ) { - - vdev_error("vdev_config_init rc = %d\n", rc ); - return rc; - } - - // parse config options from command-line - rc = vdev_config_load_from_args( vdev->config, argc, argv, NULL, NULL ); - // help is not an error - if( rc == -2 ) { - - vdev_config_usage( argv[0] ); - - return 0; - - } - - if( rc != 0 ) { - - vdev_error("vdev_config_load_from_argv rc = %d\n", rc ); - - vdev_config_usage( argv[0] ); - - return rc; - } - - // if we didn't get a config file, use the default one - if( vdev->config->config_path == NULL ) { - - vdev->config->config_path = vdev_strdup_or_null( VDEV_CONFIG_FILE ); - if( vdev->config->config_path == NULL ) { - - // OOM - return -ENOMEM; - } - } - - vdev_set_debug_level( vdev->config->debug_level ); - vdev_set_error_level( vdev->config->error_level ); - - vdev_info("Config file: '%s'\n", vdev->config->config_path ); - vdev_info("Log debug level: '%s'\n", (vdev->config->debug_level == VDEV_LOGLEVEL_DEBUG ? "debug" : (vdev->config->debug_level == VDEV_LOGLEVEL_INFO ? "info" : "none")) ); - vdev_info("Log error level: '%s'\n", (vdev->config->error_level == VDEV_LOGLEVEL_WARN ? "warning" : (vdev->config->error_level == VDEV_LOGLEVEL_ERROR ? "error" : "none")) ); - - // load from file... - rc = vdev_config_load( vdev->config->config_path, vdev->config ); - if( rc != 0 ) { - - vdev_error("vdev_config_load('%s') rc = %d\n", vdev->config->config_path, rc ); - - return rc; - } - - // if no command-line loglevel is given, then take it from the config file (if given) - if( vdev->config->debug_level != VDEV_LOGLEVEL_NONE ) { - - vdev_set_debug_level( vdev->config->debug_level ); - } - - if( vdev->config->error_level != VDEV_LOGLEVEL_NONE ) { - - vdev_set_error_level( vdev->config->error_level ); - } - - vdev_info("vdev actions dir: '%s'\n", vdev->config->acts_dir ); - vdev_info("helpers dir: '%s'\n", vdev->config->helpers_dir ); - vdev_info("logfile path: '%s'\n", vdev->config->logfile_path ); - vdev_info("pidfile path: '%s'\n", vdev->config->pidfile_path ); - vdev_info("default mode: 0%o\n", vdev->config->default_mode ); - vdev_info("preseed script: '%s'\n", vdev->config->preseed_path ); - - vdev->mountpoint = vdev_strdup_or_null( vdev->config->mountpoint ); - vdev->coldplug_only = vdev->config->coldplug_only; - - if( vdev->mountpoint == NULL ) { - - vdev_error("Failed to set mountpoint, config->mountpount = '%s'\n", vdev->config->mountpoint ); - - return -EINVAL; - } - else { - - vdev_info("mountpoint: '%s'\n", vdev->mountpoint ); - } - - vdev->argc = argc; - vdev->argv = argv; - - // load actions - rc = vdev_action_load_all( vdev->config, &vdev->acts, &vdev->num_acts ); - if( rc != 0) { - - vdev_error("vdev_action_load_all('%s') rc = %d\n", vdev->config->acts_dir, rc ); - - return rc; - } - - // initialize request work queue - rc = vdev_wq_init( &vdev->device_wq, vdev ); - if( rc != 0 ) { - - vdev_error("vdev_wq_init rc = %d\n", rc ); - - return rc; - } - - return 0; + size_t output_len = 1024 * 1024; // 1MB buffer for initial devices, just in case + char *output = NULL; + + if (vdev->config->preseed_path == NULL) { + // nothing to do + return 0; + } + + output = VDEV_CALLOC(char, output_len); + if (output == NULL) { + + // OOM + return -ENOMEM; + } + + command = + VDEV_CALLOC(char, + strlen(vdev->config->preseed_path) + 2 + + strlen(vdev->config->mountpoint) + 2 + + strlen(vdev->config->config_path) + 1); + if (command == NULL) { + + // OOM + free(output); + return -ENOMEM; + } + + sprintf(command, "%s %s %s", vdev->config->preseed_path, + vdev->config->mountpoint, vdev->config->config_path); + + rc = vdev_subprocess(command, NULL, &output, output_len, -1, + &exit_status, true); + if (rc != 0) { + + vdev_error("vdev_subprocess('%s') rc = %d\n", command, rc); + } else if (exit_status != 0) { + + vdev_error("vdev_subprocess('%s') exit status %d\n", command, + exit_status); + rc = exit_status; + } + + free(command); + command = NULL; + + if (rc != 0) { + + free(output); + return rc; + } + // process the preseed devices... + rc = vdev_load_device_requests(vdev, output, output_len); + if (rc != 0) { + + vdev_error("vdev_load_device_requests rc = %d\n", rc); + } + + free(output); + output = NULL; + + return rc; } +// global vdev initialization +int vdev_init(struct vdev_state *vdev, int argc, char **argv) +{ + + int rc = 0; + + // global setup + vdev_setup_global(); + + pthread_mutex_init(&vdev->reload_lock, NULL); + vdev->error_fd = -1; + vdev->coldplug_finished_fd = -1; + + // config... + vdev->config = VDEV_CALLOC(struct vdev_config, 1); + if (vdev->config == NULL) { + + return -ENOMEM; + } + // config init + rc = vdev_config_init(vdev->config); + if (rc != 0) { + + vdev_error("vdev_config_init rc = %d\n", rc); + return rc; + } + // parse config options from command-line + rc = vdev_config_load_from_args(vdev->config, argc, argv, NULL, NULL); + // help is not an error + if (rc == -2) { + + vdev_config_usage(argv[0]); + + return 0; + + } + + if (rc != 0) { + + vdev_error("vdev_config_load_from_argv rc = %d\n", rc); + + vdev_config_usage(argv[0]); + + return rc; + } + // if we didn't get a config file, use the default one + if (vdev->config->config_path == NULL) { + + vdev->config->config_path = + vdev_strdup_or_null(VDEV_CONFIG_FILE); + if (vdev->config->config_path == NULL) { + + // OOM + return -ENOMEM; + } + } + + vdev_set_debug_level(vdev->config->debug_level); + vdev_set_error_level(vdev->config->error_level); + + vdev_info("Config file: '%s'\n", vdev->config->config_path); + vdev_info("Log debug level: '%s'\n", + (vdev->config->debug_level == + VDEV_LOGLEVEL_DEBUG ? "debug" : (vdev->config->debug_level == + VDEV_LOGLEVEL_INFO ? "info" + : "none"))); + vdev_info("Log error level: '%s'\n", + (vdev->config->error_level == + VDEV_LOGLEVEL_WARN ? "warning" : (vdev-> + config->error_level == + VDEV_LOGLEVEL_ERROR ? + "error" : "none"))); + + // load from file... + rc = vdev_config_load(vdev->config->config_path, vdev->config); + if (rc != 0) { + + vdev_error("vdev_config_load('%s') rc = %d\n", + vdev->config->config_path, rc); + + return rc; + } + // if no command-line loglevel is given, then take it from the config file (if given) + if (vdev->config->debug_level != VDEV_LOGLEVEL_NONE) { + + vdev_set_debug_level(vdev->config->debug_level); + } + + if (vdev->config->error_level != VDEV_LOGLEVEL_NONE) { + + vdev_set_error_level(vdev->config->error_level); + } + + vdev_info("vdev actions dir: '%s'\n", vdev->config->acts_dir); + vdev_info("helpers dir: '%s'\n", vdev->config->helpers_dir); + vdev_info("logfile path: '%s'\n", vdev->config->logfile_path); + vdev_info("pidfile path: '%s'\n", vdev->config->pidfile_path); + vdev_info("default mode: 0%o\n", vdev->config->default_mode); + vdev_info("preseed script: '%s'\n", vdev->config->preseed_path); + + vdev->mountpoint = vdev_strdup_or_null(vdev->config->mountpoint); + vdev->coldplug_only = vdev->config->coldplug_only; + + if (vdev->mountpoint == NULL) { + + vdev_error + ("Failed to set mountpoint, config->mountpount = '%s'\n", + vdev->config->mountpoint); + + return -EINVAL; + } else { + + vdev_info("mountpoint: '%s'\n", vdev->mountpoint); + } + + vdev->argc = argc; + vdev->argv = argv; + + // load actions + rc = vdev_action_load_all(vdev->config, &vdev->acts, &vdev->num_acts); + if (rc != 0) { + + vdev_error("vdev_action_load_all('%s') rc = %d\n", + vdev->config->acts_dir, rc); + + return rc; + } + // initialize request work queue + rc = vdev_wq_init(&vdev->device_wq, vdev); + if (rc != 0) { + + vdev_error("vdev_wq_init rc = %d\n", rc); + + return rc; + } + + return 0; +} // main loop for the back-end // takes a file descriptor to be written to once coldplug processing has finished. // return 0 on success // return -errno on failure to daemonize, or abnormal OS-specific back-end failure -int vdev_main( struct vdev_state* vdev, int coldplug_finished_fd ) { - - int rc = 0; - - vdev->coldplug_finished_fd = coldplug_finished_fd; - - char* metadata_dir = vdev_device_metadata_fullpath( vdev->mountpoint, "" ); - if( metadata_dir == NULL ) { - - return -ENOMEM; - } - - // create metadata directory - rc = vdev_mkdirs( metadata_dir, 0, 0755 ); - - if( rc != 0 ) { - - vdev_error("vdev_mkdirs('%s') rc = %d\n", metadata_dir, rc ); - - free( metadata_dir ); - return rc; - } - - free( metadata_dir ); - - rc = vdev_os_main( vdev->os ); - - return rc; -} +int vdev_main(struct vdev_state *vdev, int coldplug_finished_fd) +{ + int rc = 0; -// signal that we've processed all coldplug devices -int vdev_signal_coldplug_finished( struct vdev_state* vdev, int status ) { - - if( vdev->coldplug_finished_fd > 0 ) { - write( vdev->coldplug_finished_fd, &status, sizeof(status)); - close( vdev->coldplug_finished_fd ); - vdev->coldplug_finished_fd = -1; - } - - return 0; + vdev->coldplug_finished_fd = coldplug_finished_fd; + + char *metadata_dir = + vdev_device_metadata_fullpath(vdev->mountpoint, ""); + if (metadata_dir == NULL) { + + return -ENOMEM; + } + // create metadata directory + rc = vdev_mkdirs(metadata_dir, 0, 0755); + + if (rc != 0) { + + vdev_error("vdev_mkdirs('%s') rc = %d\n", metadata_dir, rc); + + free(metadata_dir); + return rc; + } + + free(metadata_dir); + + rc = vdev_os_main(vdev->os); + + return rc; } +// signal that we've processed all coldplug devices +int vdev_signal_coldplug_finished(struct vdev_state *vdev, int status) +{ -// prevent reload -int vdev_reload_lock( struct vdev_state* vdev ) { - return pthread_mutex_lock( &vdev->reload_lock ); + if (vdev->coldplug_finished_fd > 0) { + write(vdev->coldplug_finished_fd, &status, sizeof(status)); + close(vdev->coldplug_finished_fd); + vdev->coldplug_finished_fd = -1; + } + + return 0; } +// prevent reload +int vdev_reload_lock(struct vdev_state *vdev) +{ + return pthread_mutex_lock(&vdev->reload_lock); +} // allow reload -int vdev_reload_unlock( struct vdev_state* vdev ) { - return pthread_mutex_unlock( &vdev->reload_lock ); +int vdev_reload_unlock(struct vdev_state *vdev) +{ + return pthread_mutex_unlock(&vdev->reload_lock); } - // do a reload // return 0 on success, and replace the config and actions, atomically // return -errno on failure, and do nothing to vdev -int vdev_reload( struct vdev_state* vdev ) { - - int rc = 0; - struct vdev_config* config = NULL; - struct vdev_action* acts = NULL; - size_t num_acts = 0; - - struct vdev_config* old_config = NULL; - struct vdev_action* old_acts = NULL; - size_t old_num_acts = 0; - - config = VDEV_CALLOC( struct vdev_config, 1 ); - if( config == NULL ) { - return -ENOMEM; - } - - // config init - rc = vdev_config_init( config ); - if( rc != 0 ) { - - vdev_error("vdev_config_init rc = %d\n", rc ); - return rc; - } - - if( config->config_path == NULL ) { - // default - config->config_path = vdev_strdup_or_null( VDEV_CONFIG_FILE ); - if( config->config_path == NULL ) { - - vdev_config_free( config ); - free( config ); - return -ENOMEM; - } - } - - // parse config options from command-line - rc = vdev_config_load_from_args( config, vdev->argc, vdev->argv, NULL, NULL ); - if( rc != 0 ) { - - vdev_error("vdev_config_load_from_argv rc = %d\n", rc ); - return rc; - } - - // load from file... - rc = vdev_config_load( config->config_path, config ); - if( rc != 0 ) { - - vdev_error("vdev_config_load('%s') rc = %d\n", config->config_path, rc ); - - vdev_config_free( config ); - free( config ); - return rc; - } - - // load actions - rc = vdev_action_load_all( config, &acts, &num_acts ); - if( rc != 0) { - - vdev_error("vdev_action_load_all('%s') rc = %d\n", config->acts_dir, rc ); - - vdev_config_free( config ); - free( config ); - return rc; - } - - // install them - vdev_reload_lock( vdev ); - - old_config = vdev->config; - vdev->config = config; - - old_acts = vdev->acts; - old_num_acts = vdev->num_acts; - vdev->acts = acts; - vdev->num_acts = num_acts; - - vdev_reload_unlock( vdev ); - - // free old state - vdev_config_free( old_config ); - free( old_config ); - - vdev_action_free_all( old_acts, old_num_acts ); - - return rc; +int vdev_reload(struct vdev_state *vdev) +{ + + int rc = 0; + struct vdev_config *config = NULL; + struct vdev_action *acts = NULL; + size_t num_acts = 0; + + struct vdev_config *old_config = NULL; + struct vdev_action *old_acts = NULL; + size_t old_num_acts = 0; + + config = VDEV_CALLOC(struct vdev_config, 1); + if (config == NULL) { + return -ENOMEM; + } + // config init + rc = vdev_config_init(config); + if (rc != 0) { + + vdev_error("vdev_config_init rc = %d\n", rc); + return rc; + } + + if (config->config_path == NULL) { + // default + config->config_path = vdev_strdup_or_null(VDEV_CONFIG_FILE); + if (config->config_path == NULL) { + + vdev_config_free(config); + free(config); + return -ENOMEM; + } + } + // parse config options from command-line + rc = vdev_config_load_from_args(config, vdev->argc, vdev->argv, NULL, + NULL); + if (rc != 0) { + + vdev_error("vdev_config_load_from_argv rc = %d\n", rc); + return rc; + } + // load from file... + rc = vdev_config_load(config->config_path, config); + if (rc != 0) { + + vdev_error("vdev_config_load('%s') rc = %d\n", + config->config_path, rc); + + vdev_config_free(config); + free(config); + return rc; + } + // load actions + rc = vdev_action_load_all(config, &acts, &num_acts); + if (rc != 0) { + + vdev_error("vdev_action_load_all('%s') rc = %d\n", + config->acts_dir, rc); + + vdev_config_free(config); + free(config); + return rc; + } + // install them + vdev_reload_lock(vdev); + + old_config = vdev->config; + vdev->config = config; + + old_acts = vdev->acts; + old_num_acts = vdev->num_acts; + vdev->acts = acts; + vdev->num_acts = num_acts; + + vdev_reload_unlock(vdev); + + // free old state + vdev_config_free(old_config); + free(old_config); + + vdev_action_free_all(old_acts, old_num_acts); + + return rc; } // stop vdev // NOTE: if this fails, there's not really a way to recover // return 0 on success // return non-zero if we failed to stop the work queue -int vdev_stop( struct vdev_state* vdev ) { - - int rc = 0; - bool wait_for_empty = false; - - if( !vdev->running ) { - return -EINVAL; - } - - vdev->running = false; - wait_for_empty = vdev->coldplug_only; // wait for the queue to drain if running coldplug only - - // stop processing requests - rc = vdev_wq_stop( &vdev->device_wq, wait_for_empty ); - if( rc != 0 ) { - - vdev_error("vdev_wq_stop: %s\n", strerror(-rc) ); - return rc; - } - - // stop all actions' daemonlets - vdev_action_daemonlet_stop_all( vdev->acts, vdev->num_acts ); - return rc; +int vdev_stop(struct vdev_state *vdev) +{ + + int rc = 0; + bool wait_for_empty = false; + + if (!vdev->running) { + return -EINVAL; + } + + vdev->running = false; + wait_for_empty = vdev->coldplug_only; // wait for the queue to drain if running coldplug only + + // stop processing requests + rc = vdev_wq_stop(&vdev->device_wq, wait_for_empty); + if (rc != 0) { + + vdev_error("vdev_wq_stop: %s\n", strerror(-rc)); + return rc; + } + // stop all actions' daemonlets + vdev_action_daemonlet_stop_all(vdev->acts, vdev->num_acts); + return rc; } // free up vdev. // only call after vdev_stop(). // return 0 on success, and print out benchmarks // return -EINVAL if we're still running. -int vdev_shutdown( struct vdev_state* vdev, bool unlink_pidfile ) { - - if( vdev->running ) { - return -EINVAL; - } - - vdev_debug("%s", "vdev shutdown\n" ); - - // stop error thread--all daemonlets should be dead anyway - int erc = vdev_error_thread_stop( vdev ); - if( erc != 0 ) { - - vdev_error("vdev_error_thread_stop: %s\n", strerror(-erc) ); - } - - // remove the PID file, if we have one - if( vdev->config->pidfile_path != NULL && unlink_pidfile ) { - unlink( vdev->config->pidfile_path ); - } - - vdev_action_free_all( vdev->acts, vdev->num_acts ); - - vdev->acts = NULL; - vdev->num_acts = 0; - - if( vdev->os != NULL ) { - vdev_os_context_free( vdev->os ); - free( vdev->os ); - vdev->os = NULL; - } - - if( vdev->config != NULL ) { - vdev_config_free( vdev->config ); - free( vdev->config ); - vdev->config = NULL; - } - - vdev_wq_free( &vdev->device_wq ); - - if( vdev->mountpoint != NULL ) { - free( vdev->mountpoint ); - vdev->mountpoint = NULL; - } - - pthread_mutex_destroy( &vdev->reload_lock ); - - return 0; +int vdev_shutdown(struct vdev_state *vdev, bool unlink_pidfile) +{ + + if (vdev->running) { + return -EINVAL; + } + + vdev_debug("%s", "vdev shutdown\n"); + + // stop error thread--all daemonlets should be dead anyway + int erc = vdev_error_thread_stop(vdev); + if (erc != 0) { + + vdev_error("vdev_error_thread_stop: %s\n", strerror(-erc)); + } + // remove the PID file, if we have one + if (vdev->config->pidfile_path != NULL && unlink_pidfile) { + unlink(vdev->config->pidfile_path); + } + + vdev_action_free_all(vdev->acts, vdev->num_acts); + + vdev->acts = NULL; + vdev->num_acts = 0; + + if (vdev->os != NULL) { + vdev_os_context_free(vdev->os); + free(vdev->os); + vdev->os = NULL; + } + + if (vdev->config != NULL) { + vdev_config_free(vdev->config); + free(vdev->config); + vdev->config = NULL; + } + + vdev_wq_free(&vdev->device_wq); + + if (vdev->mountpoint != NULL) { + free(vdev->mountpoint); + vdev->mountpoint = NULL; + } + + pthread_mutex_destroy(&vdev->reload_lock); + + return 0; } diff --git a/vdevd/workqueue.c b/vdevd/workqueue.c index e18c365..9254534 100644 --- a/vdevd/workqueue.c +++ b/vdevd/workqueue.c @@ -25,318 +25,321 @@ #include "vdev.h" // wait for the queue to be drained of coldplug events -static void vdev_wq_wait_for_empty( struct vdev_wq* wq ) { - - pthread_mutex_lock( &wq->waiter_lock ); - - wq->num_waiters++; - - pthread_mutex_unlock( &wq->waiter_lock ); - - sem_wait( &wq->end_sem ); -} +static void vdev_wq_wait_for_empty(struct vdev_wq *wq) +{ + pthread_mutex_lock(&wq->waiter_lock); -// signal any waiting threads that the queue has been drained of coldplug events -static void vdev_wq_signal_empty( struct vdev_wq* wq ) { - - volatile int num_waiters = 0; - - pthread_mutex_lock( &wq->waiter_lock ); - - num_waiters = wq->num_waiters; - wq->num_waiters = 0; - - pthread_mutex_unlock( &wq->waiter_lock ); - - for( int i = 0; i < num_waiters; i++ ) { - - sem_post( &wq->end_sem ); - } + wq->num_waiters++; + + pthread_mutex_unlock(&wq->waiter_lock); + + sem_wait(&wq->end_sem); } +// signal any waiting threads that the queue has been drained of coldplug events +static void vdev_wq_signal_empty(struct vdev_wq *wq) +{ + + volatile int num_waiters = 0; + + pthread_mutex_lock(&wq->waiter_lock); + + num_waiters = wq->num_waiters; + wq->num_waiters = 0; + + pthread_mutex_unlock(&wq->waiter_lock); + + for (int i = 0; i < num_waiters; i++) { + + sem_post(&wq->end_sem); + } +} // work queue main method // always succeeds -static void* vdev_wq_main( void* cls ) { - - struct vdev_wq* wq = (struct vdev_wq*)cls; - - struct vdev_wreq* work_itr = NULL; - struct vdev_wreq* next = NULL; - - struct vdev_state* state = wq->state; - - bool coldplug_finished = false; - - int rc = 0; - - while( wq->running ) { - - // is there work? - rc = sem_trywait( &wq->work_sem ); - if( rc != 0 ) { - - rc = -errno; - if( rc == -EAGAIN ) { - - // wait for work - sem_wait( &wq->work_sem ); - } - else { - - // some other fatal error - vdev_error("FATAL: sem_trywait rc = %d\n", rc ); - break; - } - } - - // cancelled? - if( !wq->running ) { - break; - } - - // we have work to do - pthread_mutex_lock( &wq->work_lock ); - - work_itr = wq->work; - wq->work = NULL; - wq->tail = NULL; - - pthread_mutex_unlock( &wq->work_lock ); - - if( !coldplug_finished ) { - coldplug_finished = vdev_os_context_is_coldplug_finished( state->os ); - } - - if( work_itr == NULL ) { - - vdev_wq_signal_empty( wq ); - - if( coldplug_finished ) { - - // coldplug has finished! signal the parent to exit. - vdev_signal_coldplug_finished( state, 0 ); - } - - continue; - } - - // safe to use work buffer (we'll clear it out in the process) - while( work_itr != NULL ) { - - // carry out work - rc = (*work_itr->work)( work_itr, work_itr->work_data ); - - if( rc != 0 ) { - - vdev_warn("work %p rc = %d\n", work_itr->work, rc ); - } - - next = work_itr->next; - - vdev_wreq_free( work_itr ); - free( work_itr ); - - work_itr = next; - } - } - - return NULL; +static void *vdev_wq_main(void *cls) +{ + + struct vdev_wq *wq = (struct vdev_wq *)cls; + + struct vdev_wreq *work_itr = NULL; + struct vdev_wreq *next = NULL; + + struct vdev_state *state = wq->state; + + bool coldplug_finished = false; + + int rc = 0; + + while (wq->running) { + + // is there work? + rc = sem_trywait(&wq->work_sem); + if (rc != 0) { + + rc = -errno; + if (rc == -EAGAIN) { + + // wait for work + sem_wait(&wq->work_sem); + } else { + + // some other fatal error + vdev_error("FATAL: sem_trywait rc = %d\n", rc); + break; + } + } + // cancelled? + if (!wq->running) { + break; + } + // we have work to do + pthread_mutex_lock(&wq->work_lock); + + work_itr = wq->work; + wq->work = NULL; + wq->tail = NULL; + + pthread_mutex_unlock(&wq->work_lock); + + if (!coldplug_finished) { + coldplug_finished = + vdev_os_context_is_coldplug_finished(state->os); + } + + if (work_itr == NULL) { + + vdev_wq_signal_empty(wq); + + if (coldplug_finished) { + + // coldplug has finished! signal the parent to exit. + vdev_signal_coldplug_finished(state, 0); + } + + continue; + } + // safe to use work buffer (we'll clear it out in the process) + while (work_itr != NULL) { + + // carry out work + rc = (*work_itr->work) (work_itr, work_itr->work_data); + + if (rc != 0) { + + vdev_warn("work %p rc = %d\n", work_itr->work, + rc); + } + + next = work_itr->next; + + vdev_wreq_free(work_itr); + free(work_itr); + + work_itr = next; + } + } + + return NULL; } // set up a work queue, but don't start it. // return 0 on success // return negative on failure: // * -ENOMEM if OOM -int vdev_wq_init( struct vdev_wq* wq, struct vdev_state* state ) { - - int rc = 0; - - memset( wq, 0, sizeof(struct vdev_wq) ); - - rc = pthread_mutex_init( &wq->work_lock, NULL ); - if( rc != 0 ) { - - return -abs(rc); - } - - rc = pthread_mutex_init( &wq->waiter_lock, NULL ); - if( rc != 0 ) { - - pthread_mutex_destroy( &wq->work_lock ); - return -abs(rc); - } - - sem_init( &wq->work_sem, 0, 0 ); - sem_init( &wq->end_sem, 0, 0 ); - - wq->state = state; - - return rc; -} +int vdev_wq_init(struct vdev_wq *wq, struct vdev_state *state) +{ + + int rc = 0; + + memset(wq, 0, sizeof(struct vdev_wq)); + + rc = pthread_mutex_init(&wq->work_lock, NULL); + if (rc != 0) { + + return -abs(rc); + } + + rc = pthread_mutex_init(&wq->waiter_lock, NULL); + if (rc != 0) { + pthread_mutex_destroy(&wq->work_lock); + return -abs(rc); + } + + sem_init(&wq->work_sem, 0, 0); + sem_init(&wq->end_sem, 0, 0); + + wq->state = state; + + return rc; +} // start a work queue // return 0 on success // return negative on error: // * -EINVAL if already started // * whatever pthread_create errors on -int vdev_wq_start( struct vdev_wq* wq ) { +int vdev_wq_start(struct vdev_wq *wq) +{ - if( wq->running ) { - return -EINVAL; - } + if (wq->running) { + return -EINVAL; + } - int rc = 0; - pthread_attr_t attrs; + int rc = 0; + pthread_attr_t attrs; - memset( &attrs, 0, sizeof(pthread_attr_t) ); + memset(&attrs, 0, sizeof(pthread_attr_t)); - wq->running = true; + wq->running = true; - rc = pthread_create( &wq->thread, &attrs, vdev_wq_main, wq ); - if( rc != 0 ) { + rc = pthread_create(&wq->thread, &attrs, vdev_wq_main, wq); + if (rc != 0) { - wq->running = false; + wq->running = false; - rc = -errno; - vdev_error("pthread_create errno = %d\n", rc ); + rc = -errno; + vdev_error("pthread_create errno = %d\n", rc); - return rc; - } + return rc; + } - return 0; + return 0; } // stop a work queue // return 0 on success // return negative on error: // * -EINVAL if not running -int vdev_wq_stop( struct vdev_wq* wq, bool wait ) { +int vdev_wq_stop(struct vdev_wq *wq, bool wait) +{ - if( !wq->running ) { - return -EINVAL; - } - - if( wait ) { - - // wait for the queue to be empty - vdev_wq_wait_for_empty( wq ); - } + if (!wq->running) { + return -EINVAL; + } - wq->running = false; + if (wait) { - // wake up the work queue so it cancels - sem_post( &wq->work_sem ); - pthread_cancel( wq->thread ); + // wait for the queue to be empty + vdev_wq_wait_for_empty(wq); + } - pthread_join( wq->thread, NULL ); + wq->running = false; - return 0; -} + // wake up the work queue so it cancels + sem_post(&wq->work_sem); + pthread_cancel(wq->thread); + + pthread_join(wq->thread, NULL); + return 0; +} // free a work request queue // always succeeds -static int vdev_wq_queue_free( struct vdev_wreq* wqueue ) { - - struct vdev_wreq* next = NULL; - - while( wqueue != NULL ) { - - next = wqueue->next; - - vdev_wreq_free( wqueue ); - free( wqueue ); - - wqueue = next; - } - - return 0; +static int vdev_wq_queue_free(struct vdev_wreq *wqueue) +{ + + struct vdev_wreq *next = NULL; + + while (wqueue != NULL) { + + next = wqueue->next; + + vdev_wreq_free(wqueue); + free(wqueue); + + wqueue = next; + } + + return 0; } // free up a work queue // return 0 on success // return negative on error: // * -EINVAL if running -int vdev_wq_free( struct vdev_wq* wq ) { +int vdev_wq_free(struct vdev_wq *wq) +{ + + if (wq->running) { + return -EINVAL; + } + // free all + vdev_wq_queue_free(wq->work); - if( wq->running ) { - return -EINVAL; - } + pthread_mutex_destroy(&wq->work_lock); + pthread_mutex_destroy(&wq->waiter_lock); - // free all - vdev_wq_queue_free( wq->work ); - - pthread_mutex_destroy( &wq->work_lock ); - pthread_mutex_destroy( &wq->waiter_lock ); - - sem_destroy( &wq->work_sem ); - sem_destroy( &wq->end_sem ); + sem_destroy(&wq->work_sem); + sem_destroy(&wq->end_sem); - memset( wq, 0, sizeof(struct vdev_wq) ); + memset(wq, 0, sizeof(struct vdev_wq)); - return 0; + return 0; } // create a work request // always succeeds -int vdev_wreq_init( struct vdev_wreq* wreq, vdev_wq_func_t work, void* work_data ) { +int vdev_wreq_init(struct vdev_wreq *wreq, vdev_wq_func_t work, void *work_data) +{ - memset( wreq, 0, sizeof(struct vdev_wreq) ); + memset(wreq, 0, sizeof(struct vdev_wreq)); - wreq->work = work; - wreq->work_data = work_data; + wreq->work = work; + wreq->work_data = work_data; - return 0; + return 0; } // free a work request // always succeeds -int vdev_wreq_free( struct vdev_wreq* wreq ) { +int vdev_wreq_free(struct vdev_wreq *wreq) +{ - memset( wreq, 0, sizeof(struct vdev_wreq) ); - return 0; + memset(wreq, 0, sizeof(struct vdev_wreq)); + return 0; } // enqueue work // return 0 on success // return -ENOMEM if OOM -int vdev_wq_add( struct vdev_wq* wq, struct vdev_wreq* wreq ) { - - int rc = 0; - struct vdev_wreq* next = NULL; - - // duplicate this work item - next = VDEV_CALLOC( struct vdev_wreq, 1 ); - if( next == NULL ) { - return -ENOMEM; - } - - next->work = wreq->work; - next->work_data = wreq->work_data; - next->next = NULL; - - pthread_mutex_lock( &wq->work_lock ); - - if( wq->work == NULL ) { - // head - wq->work = next; - wq->tail = next; - } - else { - // append - wq->tail->next = next; - wq->tail = next; - } - - pthread_mutex_unlock( &wq->work_lock ); - - if( rc == 0 ) { - // have work - sem_post( &wq->work_sem ); - } - - return rc; +int vdev_wq_add(struct vdev_wq *wq, struct vdev_wreq *wreq) +{ + + int rc = 0; + struct vdev_wreq *next = NULL; + + // duplicate this work item + next = VDEV_CALLOC(struct vdev_wreq, 1); + if (next == NULL) { + return -ENOMEM; + } + + next->work = wreq->work; + next->work_data = wreq->work_data; + next->next = NULL; + + pthread_mutex_lock(&wq->work_lock); + + if (wq->work == NULL) { + // head + wq->work = next; + wq->tail = next; + } else { + // append + wq->tail->next = next; + wq->tail = next; + } + + pthread_mutex_unlock(&wq->work_lock); + + if (rc == 0) { + // have work + sem_post(&wq->work_sem); + } + + return rc; } From fff81a00672ee8c6ea7d864d9e366156dbba72c3 Mon Sep 17 00:00:00 2001 From: Peter Gossner Date: Sun, 14 Aug 2016 04:16:37 +0930 Subject: [PATCH 07/13] indent -linux ./*.h also some hand tweaks all cosmetics only --- vdevd/action.h | 138 ++++++++++++++++++++++++---------------------- vdevd/device.h | 109 +++++++++++++++++++----------------- vdevd/vdev.h | 120 ++++++++++++++++++++-------------------- vdevd/workqueue.h | 81 ++++++++++++++------------- 4 files changed, 229 insertions(+), 219 deletions(-) diff --git a/vdevd/action.h b/vdevd/action.h index 16accb7..66b7419 100644 --- a/vdevd/action.h +++ b/vdevd/action.h @@ -28,7 +28,6 @@ #include "device.h" - // action fields #define VDEV_ACTION_NAME "vdev-action" @@ -55,84 +54,91 @@ #define VDEV_ACTION_DAEMONLET "daemonlet" enum vdev_action_if_exists { - VDEV_IF_EXISTS_ERROR = 1, - VDEV_IF_EXISTS_MASK, - VDEV_IF_EXISTS_RUN + VDEV_IF_EXISTS_ERROR = 1, + VDEV_IF_EXISTS_MASK, + VDEV_IF_EXISTS_RUN }; // vdev action to take on an event struct vdev_action { - - // action name - char* name; - - // what kind of request triggers this? - vdev_device_request_t trigger; - - // device path to match on - char* path; - regex_t path_regex; - - // device type to match on (block, char) - bool has_type; - char* type; - - // command to run to rename the matched path, if needed - char* rename_command; - - // command to run once the device state change is processed. - // can be dynamically generated from helper, below. - char* command; - - // name of a helper to run once the device state change is processed (conflicts with command) - char* helper; - - // whether or not to run this action in the system shell, or directly - bool use_shell; - - // OS-specific fields to match on - vdev_params* dev_params; - - // helper-specific variables to export - vdev_params* helper_vars; - - // synchronous or asynchronous - bool async; - - // how to handle the case where the device already exists - int if_exists; - - // is the action's command implemented as a daemonlet? If so, hold onto its runtime state - bool is_daemonlet; - int daemonlet_stdin; - int daemonlet_stdout; - pid_t daemonlet_pid; - - // action runtime statistics - uint64_t num_successful_calls; - uint64_t cumulative_time_millis; + + // action name + char *name; + + // what kind of request triggers this? + vdev_device_request_t trigger; + + // device path to match on + char *path; + regex_t path_regex; + + // device type to match on (block, char) + bool has_type; + char *type; + + // command to run to rename the matched path, if needed + char *rename_command; + + // command to run once the device state change is processed. + // can be dynamically generated from helper, below. + char *command; + + // name of a helper to run once the device state change is processed (conflicts with command) + char *helper; + + // whether or not to run this action in the system shell, or directly + bool use_shell; + + // OS-specific fields to match on + vdev_params *dev_params; + + // helper-specific variables to export + vdev_params *helper_vars; + + // synchronous or asynchronous + bool async; + + // how to handle the case where the device already exists + int if_exists; + + // is the action's command implemented as a daemonlet? If so, hold onto its runtime state + bool is_daemonlet; + int daemonlet_stdin; + int daemonlet_stdout; + pid_t daemonlet_pid; + + // action runtime statistics + uint64_t num_successful_calls; + uint64_t cumulative_time_millis; }; typedef struct vdev_action vdev_action; C_LINKAGE_BEGIN +int vdev_action_init(struct vdev_action *act, vdev_device_request_t trigger, + char *path, char *command, char *helper, bool async); +int vdev_action_add_param(struct vdev_action *act, char const *name, + char const *value); +int vdev_action_free(struct vdev_action *act); +int vdev_action_free_all(struct vdev_action *act_list, size_t num_acts); -int vdev_action_init( struct vdev_action* act, vdev_device_request_t trigger, char* path, char* command, char* helper, bool async ); -int vdev_action_add_param( struct vdev_action* act, char const* name, char const* value ); -int vdev_action_free( struct vdev_action* act ); -int vdev_action_free_all( struct vdev_action* act_list, size_t num_acts ); +int vdev_action_load(struct vdev_config *config, char const *path, + struct vdev_action *act); -int vdev_action_load( struct vdev_config* config, char const* path, struct vdev_action* act ); +int vdev_action_load_all(struct vdev_config *config, struct vdev_action **acts, + size_t * num_acts); -int vdev_action_load_all( struct vdev_config* config, struct vdev_action** acts, size_t* num_acts ); +int vdev_action_create_path(struct vdev_device_request *vreq, + struct vdev_action *acts, size_t num_acts, + char **path); +int vdev_action_run_commands(struct vdev_device_request *vreq, + struct vdev_action *acts, size_t num_acts, + bool exists); -int vdev_action_create_path( struct vdev_device_request* vreq, struct vdev_action* acts, size_t num_acts, char** path ); -int vdev_action_run_commands( struct vdev_device_request* vreq, struct vdev_action* acts, size_t num_acts, bool exists ); +int vdev_action_daemonlet_stop_all(struct vdev_action *actions, + size_t num_actions); -int vdev_action_daemonlet_stop_all( struct vdev_action* actions, size_t num_actions ); - -int vdev_action_log_benchmarks( struct vdev_action* action ); +int vdev_action_log_benchmarks(struct vdev_action *action); C_LINKAGE_END - -#endif \ No newline at end of file +#endif diff --git a/vdevd/device.h b/vdevd/device.h index d0a6680..7c63c77 100644 --- a/vdevd/device.h +++ b/vdevd/device.h @@ -36,78 +36,85 @@ // device request type typedef enum { - VDEV_DEVICE_INVALID = 0, // invalid request - VDEV_DEVICE_ADD, - VDEV_DEVICE_REMOVE, - VDEV_DEVICE_CHANGE, - VDEV_DEVICE_ANY // only useful for actions + VDEV_DEVICE_INVALID = 0, // invalid request + VDEV_DEVICE_ADD, + VDEV_DEVICE_REMOVE, + VDEV_DEVICE_CHANGE, + VDEV_DEVICE_ANY // only useful for actions } vdev_device_request_t; struct vdev_state; // device request struct vdev_device_request { - - // type of request (always initialized) - vdev_device_request_t type; - - // path to the device node to create (if we're making one at all) - // If we're creating a network interface, this is the interface name. - char* path; - - // renamed path (used internally) - char* renamed_path; - - // device numbers, for mknod - dev_t dev; - - // device mode: character or block device - mode_t mode; - - // OS-specific driver parameters - vdev_params* params; - - // reference to vdev state, so we can call other methods when working - struct vdev_state* state; - - // does this device file already exist? for example, did the preseed script create it? this applies to files like /dev/null, which *need* to exist. - bool exists; - - // reference to the next item, since this structure often gets used for linked lists - struct vdev_device_request* next; -}; + // type of request (always initialized) + vdev_device_request_t type; -C_LINKAGE_BEGIN + // path to the device node to create (if we're making one at all) + // If we're creating a network interface, this is the interface name. + char *path; + + // renamed path (used internally) + char *renamed_path; + + // device numbers, for mknod + dev_t dev; + + // device mode: character or block device + mode_t mode; + + // OS-specific driver parameters + vdev_params *params; + // reference to vdev state, so we can call other methods when working + struct vdev_state *state; + + // does this device file already exist? for example, did the preseed script create it? this applies to files like /dev/null, which *need* to exist. + bool exists; + + // reference to the next item, since this structure often gets used for linked lists + struct vdev_device_request *next; +}; + +C_LINKAGE_BEGIN // memory management -int vdev_device_request_init( struct vdev_device_request* req, struct vdev_state* state, vdev_device_request_t type, char const* path ); -int vdev_device_request_free( struct vdev_device_request* req ); +int vdev_device_request_init(struct vdev_device_request *req, + struct vdev_state *state, + vdev_device_request_t type, char const *path); +int vdev_device_request_free(struct vdev_device_request *req); // setters for device requests (so the OS can build one up) -int vdev_device_request_set_type( struct vdev_device_request* req, vdev_device_request_t req_type ); -int vdev_device_request_set_dev( struct vdev_device_request* req, dev_t dev ); -int vdev_device_request_set_mode( struct vdev_device_request* req, mode_t mode ); -int vdev_device_request_set_path( struct vdev_device_request* req, char const* path ); -int vdev_device_request_add_param( struct vdev_device_request* req, char const* key, char const* value ); -int vdev_device_request_set_exists( struct vdev_device_request* req, bool exists ); +int vdev_device_request_set_type(struct vdev_device_request *req, + vdev_device_request_t req_type); +int vdev_device_request_set_dev(struct vdev_device_request *req, dev_t dev); +int vdev_device_request_set_mode(struct vdev_device_request *req, mode_t mode); +int vdev_device_request_set_path(struct vdev_device_request *req, + char const *path); +int vdev_device_request_add_param(struct vdev_device_request *req, + char const *key, char const *value); +int vdev_device_request_set_exists(struct vdev_device_request *req, + bool exists); // environment variables -int vdev_device_request_to_env( struct vdev_device_request* req, vdev_params* helper_vars, char*** env, size_t* num_env, int is_daemonlet ); +int vdev_device_request_to_env(struct vdev_device_request *req, + vdev_params * helper_vars, char ***env, + size_t * num_env, int is_daemonlet); // add a device request to the work queue -int vdev_device_request_enqueue( struct vdev_wq* wq, struct vdev_device_request* req ); +int vdev_device_request_enqueue(struct vdev_wq *wq, + struct vdev_device_request *req); // sanity check structure -int vdev_device_request_sanity_check( struct vdev_device_request* req ); +int vdev_device_request_sanity_check(struct vdev_device_request *req); // device metadata -char* vdev_device_metadata_fullpath( char const* mountpoint, char const* device_path ); +char *vdev_device_metadata_fullpath(char const *mountpoint, + char const *device_path); // add/remove devices -int vdev_device_add( struct vdev_device_request* req ); -int vdev_device_remove( struct vdev_device_request* req ); +int vdev_device_add(struct vdev_device_request *req); +int vdev_device_remove(struct vdev_device_request *req); C_LINKAGE_END - -#endif \ No newline at end of file +#endif diff --git a/vdevd/vdev.h b/vdevd/vdev.h index 7a02f5f..3fd0f1d 100644 --- a/vdevd/vdev.h +++ b/vdevd/vdev.h @@ -34,75 +34,73 @@ // global vdev state struct vdev_state { - - // configuration (covered by reload_lock) - struct vdev_config* config; - - // arguments - int argc; - char** argv; - - // mountpoint; where /dev is - char* mountpoint; - - // OS context - struct vdev_os_context* os; - - // actions (covered by reload_lock) - struct vdev_action* acts; - size_t num_acts; - - // pending requests - struct vdev_pending_context* pending; - - // device processing workqueue (back-end) - struct vdev_wq device_wq; - - // are we taking events from the OS? (back-end) - bool running; - - // coldplug only? - bool coldplug_only; - - // fd to signal the end of coldplug - int coldplug_finished_fd; - - // error thread that listens to an error FIFO - // that helper processes use to send error - // messages to vdev's log - bool error_thread_running; - pthread_t error_thread; - - // fd to the error pipe, to be passed to subprocesses - // in place of stderr - int error_fd; - - // reload lock--held when reloading the config - pthread_mutex_t reload_lock; + + // configuration (covered by reload_lock) + struct vdev_config *config; + + // arguments + int argc; + char **argv; + + // mountpoint; where /dev is + char *mountpoint; + + // OS context + struct vdev_os_context *os; + + // actions (covered by reload_lock) + struct vdev_action *acts; + size_t num_acts; + + // pending requests + struct vdev_pending_context *pending; + + // device processing workqueue (back-end) + struct vdev_wq device_wq; + + // are we taking events from the OS? (back-end) + bool running; + + // coldplug only? + bool coldplug_only; + + // fd to signal the end of coldplug + int coldplug_finished_fd; + + // error thread that listens to an error FIFO + // that helper processes use to send error + // messages to vdev's log + bool error_thread_running; + pthread_t error_thread; + + // fd to the error pipe, to be passed to subprocesses + // in place of stderr + int error_fd; + + // reload lock--held when reloading the config + pthread_mutex_t reload_lock; }; -typedef char* cstr; +typedef char *cstr; C_LINKAGE_BEGIN +int vdev_init(struct vdev_state *vdev, int argc, char **argv); +int vdev_start(struct vdev_state *vdev); +int vdev_main(struct vdev_state *vdev, int flush_fd); +int vdev_reload(struct vdev_state *vdev); +int vdev_stop(struct vdev_state *vdev); +int vdev_shutdown(struct vdev_state *vdev, bool unlink_pidfile); -int vdev_init( struct vdev_state* vdev, int argc, char** argv ); -int vdev_start( struct vdev_state* vdev ); -int vdev_main( struct vdev_state* vdev, int flush_fd ); -int vdev_reload( struct vdev_state* vdev ); -int vdev_stop( struct vdev_state* vdev ); -int vdev_shutdown( struct vdev_state* vdev, bool unlink_pidfile ); - -int vdev_reload_lock( struct vdev_state* vdev ); -int vdev_reload_unlock( struct vdev_state* vdev ); +int vdev_reload_lock(struct vdev_state *vdev); +int vdev_reload_unlock(struct vdev_state *vdev); -int vdev_error_fifo_path( char const* mountpoint, char* path, size_t path_len ); -int vdev_signal_coldplug_finished( struct vdev_state* state, int status ); +int vdev_error_fifo_path(char const *mountpoint, char *path, size_t path_len); +int vdev_signal_coldplug_finished(struct vdev_state *state, int status); -int vdev_preseed_run( struct vdev_state* state ); -int vdev_remove_unplugged_devices( struct vdev_state* state ); +int vdev_preseed_run(struct vdev_state *state); +int vdev_remove_unplugged_devices(struct vdev_state *state); -SGLIB_DEFINE_VECTOR_PROTOTYPES( cstr ) +SGLIB_DEFINE_VECTOR_PROTOTYPES(cstr) C_LINKAGE_END - #endif diff --git a/vdevd/workqueue.h b/vdevd/workqueue.h index afd3673..bc5e46d 100644 --- a/vdevd/workqueue.h +++ b/vdevd/workqueue.h @@ -28,63 +28,62 @@ struct vdev_wreq; struct vdev_state; // vdev workqueue callback type -typedef int (*vdev_wq_func_t)( struct vdev_wreq* wreq, void* cls ); +typedef int (*vdev_wq_func_t) (struct vdev_wreq * wreq, void *cls); // vdev workqueue request struct vdev_wreq { - // callback to do work - vdev_wq_func_t work; + // callback to do work + vdev_wq_func_t work; - // user-supplied arguments - void* work_data; + // user-supplied arguments + void *work_data; - // next item - struct vdev_wreq* next; + // next item + struct vdev_wreq *next; }; // vdev workqueue struct vdev_wq { - // worker thread - pthread_t thread; - - // is the thread running? - volatile bool running; - - // things to do - struct vdev_wreq* work; - struct vdev_wreq* tail; - - // lock governing access to work - pthread_mutex_t work_lock; - - // semaphore to signal the availability of work - sem_t work_sem; - - // semaphore to signal the end of coldplug processing - sem_t end_sem; - - // pointer to vdev global state - struct vdev_state* state; - - // number of threads waiting for the queue to be empty - volatile int num_waiters; - pthread_mutex_t waiter_lock; + // worker thread + pthread_t thread; + + // is the thread running? + volatile bool running; + + // things to do + struct vdev_wreq *work; + struct vdev_wreq *tail; + + // lock governing access to work + pthread_mutex_t work_lock; + + // semaphore to signal the availability of work + sem_t work_sem; + + // semaphore to signal the end of coldplug processing + sem_t end_sem; + + // pointer to vdev global state + struct vdev_state *state; + + // number of threads waiting for the queue to be empty + volatile int num_waiters; + pthread_mutex_t waiter_lock; }; C_LINKAGE_BEGIN +int vdev_wq_init(struct vdev_wq *wq, struct vdev_state *state); +int vdev_wq_start(struct vdev_wq *wq); +int vdev_wq_stop(struct vdev_wq *wq, bool wait); +int vdev_wq_free(struct vdev_wq *wq); -int vdev_wq_init( struct vdev_wq* wq, struct vdev_state* state ); -int vdev_wq_start( struct vdev_wq* wq ); -int vdev_wq_stop( struct vdev_wq* wq, bool wait ); -int vdev_wq_free( struct vdev_wq* wq ); +int vdev_wreq_init(struct vdev_wreq *wreq, vdev_wq_func_t work, + void *work_data); +int vdev_wreq_free(struct vdev_wreq *wreq); -int vdev_wreq_init( struct vdev_wreq* wreq, vdev_wq_func_t work, void* work_data ); -int vdev_wreq_free( struct vdev_wreq* wreq ); - -int vdev_wq_add( struct vdev_wq* wq, struct vdev_wreq* wreq ); +int vdev_wq_add(struct vdev_wq *wq, struct vdev_wreq *wreq); C_LINKAGE_END - #endif From 8e7e230ac916d08a44ed536cc370c9b85e929850 Mon Sep 17 00:00:00 2001 From: Peter Gossner Date: Mon, 15 Aug 2016 17:29:12 +0930 Subject: [PATCH 08/13] indent -gnu just for the blast --- fs/acl.c | 1838 ++++++------- fs/acl.h | 81 +- fs/fs.c | 2420 ++++++++--------- fs/fs.h | 106 +- fs/main.c | 47 +- libudev-compat/MurmurHash2.c | 73 +- libudev-compat/MurmurHash2.h | 8 +- libudev-compat/device-nodes.c | 81 +- libudev-compat/device-nodes.h | 2 +- libudev-compat/hashmap.c | 2550 +++++++++--------- libudev-compat/hashmap.h | 438 ++-- libudev-compat/hwdb-internal.h | 58 +- libudev-compat/hwdb-util.h | 6 +- libudev-compat/libudev-device-private.c | 310 ++- libudev-compat/libudev-device.c | 2800 ++++++++++---------- libudev-compat/libudev-enumerate.c | 1336 +++++----- libudev-compat/libudev-fs.c | 2387 +++++++++-------- libudev-compat/libudev-fs.h | 16 +- libudev-compat/libudev-hwdb.c | 117 +- libudev-compat/libudev-list.c | 405 +-- libudev-compat/libudev-monitor.c | 1725 ++++++------ libudev-compat/libudev-private.h | 146 +- libudev-compat/libudev-queue.c | 141 +- libudev-compat/libudev-util.c | 461 ++-- libudev-compat/libudev.c | 228 +- libudev-compat/libudev.h | 302 ++- libudev-compat/log.c | 73 +- libudev-compat/log.h | 4 +- libudev-compat/macro.h | 64 +- libudev-compat/mempool.c | 108 +- libudev-compat/mempool.h | 15 +- libudev-compat/mkdir.c | 192 +- libudev-compat/mkdir.h | 15 +- libudev-compat/sd-hwdb.c | 770 +++--- libudev-compat/sd-hwdb.h | 13 +- libudev-compat/set.h | 114 +- libudev-compat/siphash24.c | 142 +- libudev-compat/siphash24.h | 5 +- libudev-compat/sparse-endian.h | 70 +- libudev-compat/strxcpyx.c | 119 +- libudev-compat/strxcpyx.h | 2 +- libudev-compat/utf8.c | 541 ++-- libudev-compat/utf8.h | 21 +- libudev-compat/util.c | 524 ++-- libudev-compat/util.h | 126 +- libvdev/config.c | 1204 ++++----- libvdev/config.h | 132 +- libvdev/ini.c | 334 +-- libvdev/ini.h | 84 +- libvdev/match.c | 232 +- libvdev/match.h | 18 +- libvdev/param.c | 151 +- libvdev/param.h | 20 +- libvdev/sglib.h | 45 +- libvdev/util.c | 1927 +++++++------- libvdev/util.h | 71 +- tools/udev_to_vdev/udev_rule.h | 87 +- vdevd/action.c | 2873 +++++++++++--------- vdevd/action.h | 125 +- vdevd/device.c | 1854 +++++++------ vdevd/device.h | 103 +- vdevd/helpers/LINUX/common.c | 2249 ++++++++-------- vdevd/helpers/LINUX/common.h | 73 +- vdevd/helpers/LINUX/echo_n.c | 19 +- vdevd/helpers/LINUX/event-put.c | 860 +++--- vdevd/helpers/LINUX/stat_ata.c | 1351 +++++----- vdevd/helpers/LINUX/stat_bus.c | 275 +- vdevd/helpers/LINUX/stat_input.c | 754 +++--- vdevd/helpers/LINUX/stat_net.c | 1806 +++++++------ vdevd/helpers/LINUX/stat_optical.c | 143 +- vdevd/helpers/LINUX/stat_path.c | 3207 ++++++++++++----------- vdevd/helpers/LINUX/stat_scsi.c | 2910 ++++++++++---------- vdevd/helpers/LINUX/stat_usb.c | 1655 ++++++------ vdevd/helpers/LINUX/stat_v4l.c | 170 +- vdevd/main.c | 351 +-- vdevd/os/common.c | 254 +- vdevd/os/common.h | 36 +- vdevd/os/linux.c | 2715 +++++++++---------- vdevd/os/linux.h | 47 +- vdevd/os/methods.h | 11 +- vdevd/os/test.h | 31 +- vdevd/vdev.c | 1934 +++++++------- vdevd/vdev.h | 98 +- vdevd/workqueue.c | 395 +-- vdevd/workqueue.h | 72 +- 85 files changed, 26953 insertions(+), 24723 deletions(-) diff --git a/fs/acl.c b/fs/acl.c index 34f6022..ba286a2 100644 --- a/fs/acl.c +++ b/fs/acl.c @@ -21,31 +21,30 @@ #include "acl.h" -#define INI_MAX_LINE 4096 +#define INI_MAX_LINE 4096 #define INI_STOP_ON_FIRST_ERROR 1 #include "libvdev/ini.h" #include "libvdev/match.h" #include "libvdev/config.h" -SGLIB_DEFINE_VECTOR_PROTOTYPES( vdev_acl ); -SGLIB_DEFINE_VECTOR_FUNCTIONS( vdev_acl ); +SGLIB_DEFINE_VECTOR_PROTOTYPES(vdev_acl); +SGLIB_DEFINE_VECTOR_FUNCTIONS(vdev_acl); // parse the ACL mode -static int vdev_acl_parse_mode( mode_t* mode, char const* mode_str ) { - - char* tmp = NULL; - - *mode = ((mode_t)strtol( mode_str, &tmp, 8 )) & 0777; - - if( *tmp != '\0' ) { - return -EINVAL; - } - else { - return 0; - } -} +static int vdev_acl_parse_mode(mode_t * mode, char const *mode_str) +{ + + char *tmp = NULL; + *mode = ((mode_t) strtol(mode_str, &tmp, 8)) & 0777; + + if (*tmp != '\0') { + return -EINVAL; + } else { + return 0; + } +} // get a passwd struct for a user. // on success, fill in pwd and *pwd_buf (the caller must free *pwd_buf, but not pwd). @@ -53,52 +52,51 @@ static int vdev_acl_parse_mode( mode_t* mode, char const* mode_str ) { // return -EINVAL if any argument is NULL // return -ENOMEM on OOM // return -ENOENT if the username cnanot be loaded -int vdev_get_passwd( char const* username, struct passwd* pwd, char** pwd_buf ) { - - struct passwd* result = NULL; - char* buf = NULL; - int buf_len = 0; - int rc = 0; - - if( pwd == NULL || username == NULL || pwd_buf == NULL ) { - return -EINVAL; - } - - memset( pwd, 0, sizeof(struct passwd) ); - - buf_len = sysconf( _SC_GETPW_R_SIZE_MAX ); - if( buf_len <= 0 ) { - buf_len = 65536; - } - - buf = VDEV_CALLOC( char, buf_len ); - if( buf == NULL ) { - return -ENOMEM; - } - - rc = getpwnam_r( username, pwd, buf, buf_len, &result ); - - if( result == NULL ) { - - if( rc == 0 ) { - free( buf ); - return -ENOENT; - } - else { - rc = -errno; - free( buf ); - - vdev_error("getpwnam_r(%s) errno = %d\n", username, rc); - return rc; - } - } - - *pwd_buf = buf; - - // success! - return rc; -} +int vdev_get_passwd(char const *username, struct passwd *pwd, char **pwd_buf) +{ + + struct passwd *result = NULL; + char *buf = NULL; + int buf_len = 0; + int rc = 0; + + if (pwd == NULL || username == NULL || pwd_buf == NULL) { + return -EINVAL; + } + + memset(pwd, 0, sizeof(struct passwd)); + buf_len = sysconf(_SC_GETPW_R_SIZE_MAX); + if (buf_len <= 0) { + buf_len = 65536; + } + + buf = VDEV_CALLOC(char, buf_len); + if (buf == NULL) { + return -ENOMEM; + } + + rc = getpwnam_r(username, pwd, buf, buf_len, &result); + + if (result == NULL) { + + if (rc == 0) { + free(buf); + return -ENOENT; + } else { + rc = -errno; + free(buf); + + vdev_error("getpwnam_r(%s) errno = %d\n", username, rc); + return rc; + } + } + + *pwd_buf = buf; + + // success! + return rc; +} // get a group struct for a group. // on success, fill in grp and *grp_buf (the caller must free *grp_buf, but not grp). @@ -106,181 +104,181 @@ int vdev_get_passwd( char const* username, struct passwd* pwd, char** pwd_buf ) // return -ENOMEM on OOM // return -EINVAL if any argument is NULL // return -ENOENT if the group cannot be found -int vdev_get_group( char const* groupname, struct group* grp, char** grp_buf ) { - - struct group* result = NULL; - char* buf = NULL; - int buf_len = 0; - int rc = 0; - - if( grp == NULL || groupname == NULL || grp_buf == NULL ) { - return -EINVAL; - } - - memset( grp, 0, sizeof(struct group) ); - - buf_len = sysconf( _SC_GETGR_R_SIZE_MAX ); - if( buf_len <= 0 ) { - buf_len = 65536; - } - - buf = VDEV_CALLOC( char, buf_len ); - if( buf == NULL ) { - return -ENOMEM; - } - - rc = getgrnam_r( groupname, grp, buf, buf_len, &result ); - - if( result == NULL ) { - - if( rc == 0 ) { - free( buf ); - return -ENOENT; - } - else { - rc = -errno; - free( buf ); - - vdev_error("getgrnam_r(%s) errno = %d\n", groupname, rc); - return rc; - } - } - - // success! - return rc; -} +int vdev_get_group(char const *groupname, struct group *grp, char **grp_buf) +{ + + struct group *result = NULL; + char *buf = NULL; + int buf_len = 0; + int rc = 0; + + if (grp == NULL || groupname == NULL || grp_buf == NULL) { + return -EINVAL; + } + + memset(grp, 0, sizeof(struct group)); + + buf_len = sysconf(_SC_GETGR_R_SIZE_MAX); + if (buf_len <= 0) { + buf_len = 65536; + } + + buf = VDEV_CALLOC(char, buf_len); + if (buf == NULL) { + return -ENOMEM; + } + + rc = getgrnam_r(groupname, grp, buf, buf_len, &result); + + if (result == NULL) { + if (rc == 0) { + free(buf); + return -ENOENT; + } else { + rc = -errno; + free(buf); + + vdev_error("getgrnam_r(%s) errno = %d\n", groupname, + rc); + return rc; + } + } + // success! + return rc; +} // parse a username or uid from a string. // translate a username into a uid, if needed // return 0 and set *uid on success // return negative if we failed to look up the corresponding user (see vdev_get_passwd) // return negative on error -int vdev_parse_uid( char const* uid_str, uid_t* uid ) { - - bool parsed = false; - int rc = 0; - - if( uid_str == NULL || uid == NULL ) { - return -EINVAL; - } - - *uid = (uid_t)vdev_parse_uint64( uid_str, &parsed ); - - // not a number? - if( !parsed ) { - - // probably a username - char* pwd_buf = NULL; - struct passwd pwd; - - // look up the uid... - rc = vdev_get_passwd( uid_str, &pwd, &pwd_buf ); - if( rc != 0 ) { - - vdev_error("vdev_get_passwd(%s) rc = %d\n", uid_str, rc ); - return rc; - } - - *uid = pwd.pw_uid; - - free( pwd_buf ); - } - - return 0; -} +int vdev_parse_uid(char const *uid_str, uid_t * uid) +{ + + bool parsed = false; + int rc = 0; + + if (uid_str == NULL || uid == NULL) { + return -EINVAL; + } + + *uid = (uid_t) vdev_parse_uint64(uid_str, &parsed); + + // not a number? + if (!parsed) { + + // probably a username + char *pwd_buf = NULL; + struct passwd pwd; + // look up the uid... + rc = vdev_get_passwd(uid_str, &pwd, &pwd_buf); + if (rc != 0) { + + vdev_error("vdev_get_passwd(%s) rc = %d\n", uid_str, + rc); + return rc; + } + + *uid = pwd.pw_uid; + + free(pwd_buf); + } + + return 0; +} // parse a group name or GID from a string // translate a group name into a gid, if needed // return 0 and set gid on success // return negative if we failed to look up the corresponding group (see vdev_get_group) // return negative on error -int vdev_parse_gid( char const* gid_str, gid_t* gid ) { - - bool parsed = false; - int rc = 0; - - if( gid_str == NULL || gid == NULL ) { - return -EINVAL; - } - - *gid = (gid_t)vdev_parse_uint64( gid_str, &parsed ); - - // not a number? - if( !parsed ) { - - // probably a group name - char* grp_buf = NULL; - struct group grp; - - // look up the gid... - rc = vdev_get_group( gid_str, &grp, &grp_buf ); - if( rc != 0 ) { - - vdev_error("vdev_get_group(%s) rc = %d\n", gid_str, rc ); - return rc; - } - - *gid = grp.gr_gid; - - free( grp_buf ); - } - - return 0; -} +int vdev_parse_gid(char const *gid_str, gid_t * gid) +{ + + bool parsed = false; + int rc = 0; + + if (gid_str == NULL || gid == NULL) { + return -EINVAL; + } + *gid = (gid_t) vdev_parse_uint64(gid_str, &parsed); + + // not a number? + if (!parsed) { + + // probably a group name + char *grp_buf = NULL; + struct group grp; + + // look up the gid... + rc = vdev_get_group(gid_str, &grp, &grp_buf); + if (rc != 0) { + + vdev_error("vdev_get_group(%s) rc = %d\n", gid_str, rc); + return rc; + } + + *gid = grp.gr_gid; + + free(grp_buf); + } + + return 0; +} // verify that a UID is valid // return 0 on success // return -ENOMEM on OOM // return -ENOENT on failure to look up the user // return negative on error -int vdev_validate_uid( uid_t uid ) { - - struct passwd* result = NULL; - char* buf = NULL; - int buf_len = 0; - int rc = 0; - struct passwd pwd; - - memset( &pwd, 0, sizeof(struct passwd) ); - - buf_len = sysconf( _SC_GETPW_R_SIZE_MAX ); - if( buf_len <= 0 ) { - buf_len = 65536; - } - - buf = VDEV_CALLOC( char, buf_len ); - if( buf == NULL ) { - return -ENOMEM; - } - - rc = getpwuid_r( uid, &pwd, buf, buf_len, &result ); - - if( result == NULL ) { - - if( rc == 0 ) { - free( buf ); - return -ENOENT; - } - else { - rc = -errno; - free( buf ); - - vdev_error("getpwuid_r(%d) errno = %d\n", uid, rc); - return rc; - } - } - - if( uid != pwd.pw_uid ) { - // should *never* happen - rc = -EINVAL; - } - - free( buf ); - - return rc; +int vdev_validate_uid(uid_t uid) +{ + + struct passwd *result = NULL; + char *buf = NULL; + int buf_len = 0; + int rc = 0; + struct passwd pwd; + + memset(&pwd, 0, sizeof(struct passwd)); + + buf_len = sysconf(_SC_GETPW_R_SIZE_MAX); + if (buf_len <= 0) { + buf_len = 65536; + } + + buf = VDEV_CALLOC(char, buf_len); + if (buf == NULL) { + return -ENOMEM; + } + + rc = getpwuid_r(uid, &pwd, buf, buf_len, &result); + + if (result == NULL) { + + if (rc == 0) { + free(buf); + return -ENOENT; + } else { + rc = -errno; + free(buf); + + vdev_error("getpwuid_r(%d) errno = %d\n", uid, rc); + return rc; + } + } + + if (uid != pwd.pw_uid) { + // should *never* happen + rc = -EINVAL; + } + + free(buf); + + return rc; } // verify that a GID is valid @@ -288,769 +286,791 @@ int vdev_validate_uid( uid_t uid ) { // return -ENOMEM on OOM // return -ENOENT if we couldn't find the corresponding group // return negative on other error -int vdev_validate_gid( gid_t gid ) { - - struct group* result = NULL; - struct group grp; - char* buf = NULL; - int buf_len = 0; - int rc = 0; - - memset( &grp, 0, sizeof(struct group) ); - - buf_len = sysconf( _SC_GETGR_R_SIZE_MAX ); - if( buf_len <= 0 ) { - buf_len = 65536; - } - - buf = VDEV_CALLOC( char, buf_len ); - if( buf == NULL ) { - return -ENOMEM; - } - - rc = getgrgid_r( gid, &grp, buf, buf_len, &result ); - - if( result == NULL ) { - - if( rc == 0 ) { - free( buf ); - return -ENOENT; - } - else { - rc = -errno; - free( buf ); - - vdev_error("getgrgid_r(%d) errno = %d\n", gid, rc); - return rc; - } - } - - if( gid != grp.gr_gid ) { - rc = -EINVAL; - } - - free( buf ); - - return rc; -} +int vdev_validate_gid(gid_t gid) +{ + + struct group *result = NULL; + struct group grp; + char *buf = NULL; + int buf_len = 0; + int rc = 0; + + memset(&grp, 0, sizeof(struct group)); + + buf_len = sysconf(_SC_GETGR_R_SIZE_MAX); + if (buf_len <= 0) { + buf_len = 65536; + } + buf = VDEV_CALLOC(char, buf_len); + if (buf == NULL) { + return -ENOMEM; + } + rc = getgrgid_r(gid, &grp, buf, buf_len, &result); + + if (result == NULL) { + + if (rc == 0) { + free(buf); + return -ENOENT; + } else { + rc = -errno; + free(buf); + + vdev_error("getgrgid_r(%d) errno = %d\n", gid, rc); + return rc; + } + } + + if (gid != grp.gr_gid) { + rc = -EINVAL; + } + + free(buf); + + return rc; +} // callback from inih to parse an acl // return 1 on success // return 0 on failure -static int vdev_acl_ini_parser( void* userdata, char const* section, char const* name, char const* value ) { - - struct vdev_acl* acl = (struct vdev_acl*)userdata; - - // verify this is an acl section - if( strcmp(section, VDEV_ACL_NAME) != 0 ) { - - fprintf(stderr, "Invalid section '%s'\n", section); - return 0; - } - - if( strcmp(name, VDEV_ACL_NAME_UID ) == 0 ) { - - // parse user or UID - uid_t uid = 0; - int rc = vdev_parse_uid( value, &uid ); - - if( rc != 0 ) { - vdev_error("vdev_parse_uid(%s) rc = %d\n", value, rc ); - - fprintf(stderr, "Invalid user/UID '%s'\n", value ); - return 0; - } - - acl->has_uid = true; - acl->uid = uid; - return 1; - } - - if( strcmp(name, VDEV_ACL_NAME_SETUID ) == 0 ) { - - // parse user or UID - uid_t uid = 0; - int rc = vdev_parse_uid( value, &uid ); - - if( rc != 0 ) { - vdev_error("vdev_parse_uid(%s) rc = %d\n", value, rc ); - - fprintf(stderr, "Invalid user/UID '%s'\n", value ); - return 0; - } - - acl->has_setuid = true; - acl->setuid = uid; - return 1; - } - - if( strcmp(name, VDEV_ACL_NAME_GID ) == 0 ) { - - // parse group or GID - gid_t gid = 0; - int rc = vdev_parse_gid( value, &gid ); - - if( rc != 0 ) { - vdev_error("vdev_parse_gid(%s) rc = %d\n", value, rc ); - - fprintf(stderr, "Invalid group/GID '%s'\n", value ); - return 0; - } - - acl->has_gid = true; - acl->gid = gid; - return 1; - } - - if( strcmp(name, VDEV_ACL_NAME_SETGID ) == 0 ) { - - // parse group or GID - gid_t gid = 0; - int rc = vdev_parse_gid( value, &gid ); - - if( rc != 0 ) { - vdev_error("vdev_parse_gid(%s) rc = %d\n", value, rc ); - - fprintf(stderr, "Invalid group/GID '%s'\n", value ); - return 0; - } - - acl->has_setgid = true; - acl->setgid = gid; - return 1; - } - - if( strcmp(name, VDEV_ACL_NAME_SETMODE ) == 0 ) { - - // parse mode - mode_t mode = 0; - int rc = vdev_acl_parse_mode( &mode, value ); - - if( rc != 0 ) { - vdev_error("vdev_acl_parse_mode(%s) rc = %d\n", value, rc ); - - fprintf(stderr, "Invalid mode '%s'\n", value ); - return 0; - } - - acl->has_setmode = true; - acl->setmode = mode; - return 1; - } - - if( strcmp(name, VDEV_ACL_DEVICE_REGEX ) == 0 ) { - - // parse and preserve this value - int rc = vdev_match_regex_append( &acl->paths, &acl->regexes, &acl->num_paths, value ); - - if( rc != 0 ) { - vdev_error("vdev_match_regex_append(%s) rc = %d\n", value, rc ); - - fprintf(stderr, "Invalid regex '%s'\n", value ); - return 0; - } - - return 1; - } - - if( strcmp(name, VDEV_ACL_NAME_PROC_PATH ) == 0 ) { - - // preserve this value - if( acl->proc_path != NULL ) { - - fprintf(stderr, "Duplicate process path '%s'\n", value ); - return 0; - } - - acl->has_proc = true; - acl->proc_path = vdev_strdup_or_null(value); - return 1; - } - - if( strcmp(name, VDEV_ACL_NAME_PROC_PREDICATE ) == 0 ) { - - // preserve this value - if( acl->proc_predicate_cmd != NULL ) { - - fprintf(stderr, "Duplicate predicate '%s'\n", value ); - return 0; - } - - acl->has_proc = true; - acl->proc_predicate_cmd = vdev_strdup_or_null(value); - return 1; - } - - if( strcmp(name, VDEV_ACL_NAME_PROC_INODE ) == 0 ) { - - // preserve this value - ino_t inode = 0; - bool success = false; - - inode = vdev_parse_uint64( value, &success ); - if( !success ) { - - fprintf(stderr, "Failed to parse inode '%s'\n", value ); - return 0; - } - - acl->has_proc = true; - acl->proc_inode = inode; - return 1; - } - - fprintf(stderr, "Unrecognized field '%s'\n", name); - return 0; -} +static int vdev_acl_ini_parser(void *userdata, char const *section, + char const *name, char const *value) +{ + + struct vdev_acl *acl = (struct vdev_acl *)userdata; + + // verify this is an acl section + if (strcmp(section, VDEV_ACL_NAME) != 0) { + + fprintf(stderr, "Invalid section '%s'\n", section); + return 0; + } + + if (strcmp(name, VDEV_ACL_NAME_UID) == 0) { + + // parse user or UID + uid_t uid = 0; + int rc = vdev_parse_uid(value, &uid); + + if (rc != 0) { + vdev_error("vdev_parse_uid(%s) rc = %d\n", value, rc); + + fprintf(stderr, "Invalid user/UID '%s'\n", value); + return 0; + } + + acl->has_uid = true; + acl->uid = uid; + return 1; + } + + if (strcmp(name, VDEV_ACL_NAME_SETUID) == 0) { + + // parse user or UID + uid_t uid = 0; + int rc = vdev_parse_uid(value, &uid); + + if (rc != 0) { + vdev_error("vdev_parse_uid(%s) rc = %d\n", value, rc); + + fprintf(stderr, "Invalid user/UID '%s'\n", value); + return 0; + } + + acl->has_setuid = true; + acl->setuid = uid; + return 1; + } + + if (strcmp(name, VDEV_ACL_NAME_GID) == 0) { + + // parse group or GID + gid_t gid = 0; + int rc = vdev_parse_gid(value, &gid); + + if (rc != 0) { + vdev_error("vdev_parse_gid(%s) rc = %d\n", value, rc); + + fprintf(stderr, "Invalid group/GID '%s'\n", value); + return 0; + } + + acl->has_gid = true; + acl->gid = gid; + return 1; + } + + if (strcmp(name, VDEV_ACL_NAME_SETGID) == 0) { + + // parse group or GID + gid_t gid = 0; + int rc = vdev_parse_gid(value, &gid); + + if (rc != 0) { + vdev_error("vdev_parse_gid(%s) rc = %d\n", value, rc); + + fprintf(stderr, "Invalid group/GID '%s'\n", value); + return 0; + } + + acl->has_setgid = true; + acl->setgid = gid; + return 1; + } + if (strcmp(name, VDEV_ACL_NAME_SETMODE) == 0) { + + // parse mode + mode_t mode = 0; + int rc = vdev_acl_parse_mode(&mode, value); + + if (rc != 0) { + vdev_error("vdev_acl_parse_mode(%s) rc = %d\n", value, + rc); + + fprintf(stderr, "Invalid mode '%s'\n", value); + return 0; + } + + acl->has_setmode = true; + acl->setmode = mode; + return 1; + } + + if (strcmp(name, VDEV_ACL_DEVICE_REGEX) == 0) { + + // parse and preserve this value + int rc = + vdev_match_regex_append(&acl->paths, &acl->regexes, + &acl->num_paths, value); + + if (rc != 0) { + vdev_error("vdev_match_regex_append(%s) rc = %d\n", + value, rc); + + fprintf(stderr, "Invalid regex '%s'\n", value); + return 0; + } + + return 1; + } + + if (strcmp(name, VDEV_ACL_NAME_PROC_PATH) == 0) { + + // preserve this value + if (acl->proc_path != NULL) { + + fprintf(stderr, "Duplicate process path '%s'\n", value); + return 0; + } + + acl->has_proc = true; + acl->proc_path = vdev_strdup_or_null(value); + return 1; + } + + if (strcmp(name, VDEV_ACL_NAME_PROC_PREDICATE) == 0) { + + // preserve this value + if (acl->proc_predicate_cmd != NULL) { + + fprintf(stderr, "Duplicate predicate '%s'\n", value); + return 0; + } + + acl->has_proc = true; + acl->proc_predicate_cmd = vdev_strdup_or_null(value); + return 1; + } + + if (strcmp(name, VDEV_ACL_NAME_PROC_INODE) == 0) { + + // preserve this value + ino_t inode = 0; + bool success = false; + + inode = vdev_parse_uint64(value, &success); + if (!success) { + + fprintf(stderr, "Failed to parse inode '%s'\n", value); + return 0; + } + + acl->has_proc = true; + acl->proc_inode = inode; + return 1; + } + + fprintf(stderr, "Unrecognized field '%s'\n", name); + return 0; +} // acl sanity check -int vdev_acl_sanity_check( struct vdev_acl* acl ) { - - int rc = 0; - - if( acl->has_gid ) { - - rc = vdev_validate_gid( acl->gid ); - if( rc != 0 ) { - - fprintf(stderr, "Invalid GID %d\n", acl->gid ); - return rc; - } - } - - if( acl->has_setgid ) { - - rc = vdev_validate_gid( acl->gid ); - if( rc != 0 ) { - - fprintf(stderr, "Invalid set-GID %d\n", acl->setgid ); - return rc; - } - } - - if( acl->has_uid ) { - - rc = vdev_validate_uid( acl->uid ); - if( rc != 0 ) { - - fprintf(stderr, "Invalid UID %d\n", acl->uid ); - return rc; - } - } - - if( acl->has_setuid ) { - - rc = vdev_validate_uid( acl->uid ); - if( rc != 0 ) { - - fprintf(stderr, "Invalid set-UID %d\n", acl->setuid ); - return rc; - } - } - - return rc; +int vdev_acl_sanity_check(struct vdev_acl *acl) +{ + + int rc = 0; + + if (acl->has_gid) { + + rc = vdev_validate_gid(acl->gid); + if (rc != 0) { + + fprintf(stderr, "Invalid GID %d\n", acl->gid); + return rc; + } + } + + if (acl->has_setgid) { + + rc = vdev_validate_gid(acl->gid); + if (rc != 0) { + + fprintf(stderr, "Invalid set-GID %d\n", acl->setgid); + return rc; + } + } + + if (acl->has_uid) { + + rc = vdev_validate_uid(acl->uid); + if (rc != 0) { + + fprintf(stderr, "Invalid UID %d\n", acl->uid); + return rc; + } + } + + if (acl->has_setuid) { + + rc = vdev_validate_uid(acl->uid); + if (rc != 0) { + + fprintf(stderr, "Invalid set-UID %d\n", acl->setuid); + return rc; + } + } + + return rc; } // initialize an acl -int vdev_acl_init( struct vdev_acl* acl ) { - memset( acl, 0, sizeof(struct vdev_acl) ); - return 0; +int vdev_acl_init(struct vdev_acl *acl) +{ + memset(acl, 0, sizeof(struct vdev_acl)); + return 0; } - // free an acl -int vdev_acl_free( struct vdev_acl* acl ) { - - if( acl->num_paths > 0 ) { - - vdev_match_regexes_free( acl->paths, acl->regexes, acl->num_paths ); - } - - if( acl->proc_path != NULL ) { - free( acl->proc_path ); - acl->proc_path = NULL; - } - - return 0; -} +int vdev_acl_free(struct vdev_acl *acl) +{ + if (acl->num_paths > 0) { -// load an ACL from a file handle -int vdev_acl_load_file( FILE* file, struct vdev_acl* acl ) { - - int rc = 0; - - vdev_acl_init( acl ); - - rc = ini_parse_file( file, vdev_acl_ini_parser, acl ); - if( rc != 0 ) { - vdev_error("ini_parse_file(ACL) rc = %d\n", rc ); - return rc; - } - - // sanity check - rc = vdev_acl_sanity_check( acl ); - if( rc != 0 ) { - - vdev_error("vdev_acl_sanity_check rc = %d\n", rc ); - - vdev_acl_free( acl ); - memset( acl, 0, sizeof(struct vdev_acl) ); - return rc; - } - - return rc; + vdev_match_regexes_free(acl->paths, acl->regexes, + acl->num_paths); + } + + if (acl->proc_path != NULL) { + free(acl->proc_path); + acl->proc_path = NULL; + } + + return 0; } +// load an ACL from a file handle +int vdev_acl_load_file(FILE * file, struct vdev_acl *acl) +{ -// load an ACL from a file, given the path -int vdev_acl_load( char const* path, struct vdev_acl* acl ) { - - int rc = 0; - FILE* f = NULL; - - f = fopen( path, "r" ); - if( f == NULL ) { - - rc = -errno; - vdev_error("fopen(%s) errno = %d\n", path,rc ); - return rc; - } - - rc = vdev_acl_load_file( f, acl ); - - fclose( f ); - - if( rc != 0 ) { - vdev_error("vdev_acl_load_file(%s) rc = %d\n", path, rc ); - } - - return rc; + int rc = 0; + + vdev_acl_init(acl); + + rc = ini_parse_file(file, vdev_acl_ini_parser, acl); + if (rc != 0) { + vdev_error("ini_parse_file(ACL) rc = %d\n", rc); + return rc; + } + // sanity check + rc = vdev_acl_sanity_check(acl); + if (rc != 0) { + + vdev_error("vdev_acl_sanity_check rc = %d\n", rc); + + vdev_acl_free(acl); + memset(acl, 0, sizeof(struct vdev_acl)); + return rc; + } + + return rc; } +// load an ACL from a file, given the path +int vdev_acl_load(char const *path, struct vdev_acl *acl) +{ + + int rc = 0; + FILE *f = NULL; + + f = fopen(path, "r"); + if (f == NULL) { + + rc = -errno; + vdev_error("fopen(%s) errno = %d\n", path, rc); + return rc; + } + + rc = vdev_acl_load_file(f, acl); + + fclose(f); + + if (rc != 0) { + vdev_error("vdev_acl_load_file(%s) rc = %d\n", path, rc); + } + + return rc; +} // free a vector of acls -static void vdev_acl_free_vector( struct sglib_vdev_acl_vector* acls ) { - - for( unsigned long i = 0; i < sglib_vdev_acl_vector_size( acls ); i++ ) { - - struct vdev_acl* acl = sglib_vdev_acl_vector_at_ref( acls, i ); - - vdev_acl_free( acl ); - } - - sglib_vdev_acl_vector_clear( acls ); +static void vdev_acl_free_vector(struct sglib_vdev_acl_vector *acls) +{ + + for (unsigned long i = 0; i < sglib_vdev_acl_vector_size(acls); i++) { + + struct vdev_acl *acl = sglib_vdev_acl_vector_at_ref(acls, i); + + vdev_acl_free(acl); + } + + sglib_vdev_acl_vector_clear(acls); } // free a C-style list of acls (including the list itself) -int vdev_acl_free_all( struct vdev_acl* acl_list, size_t num_acls ) { - - int rc = 0; - - for( unsigned int i = 0; i < num_acls; i++ ) { - - rc = vdev_acl_free( &acl_list[i] ); - if( rc != 0 ) { - - return rc; - } - } - - free( acl_list ); - - return rc; -} +int vdev_acl_free_all(struct vdev_acl *acl_list, size_t num_acls) +{ + + int rc = 0; + + for (unsigned int i = 0; i < num_acls; i++) { + rc = vdev_acl_free(&acl_list[i]); + if (rc != 0) { + + return rc; + } + } + + free(acl_list); + + return rc; +} // loader for an acl -int vdev_acl_loader( char const* fp, void* cls ) { - - struct vdev_acl acl; - int rc = 0; - struct stat sb; - - struct sglib_vdev_acl_vector* acls = (struct sglib_vdev_acl_vector*)cls; - - // skip if not a regular file - rc = stat( fp, &sb ); - if( rc != 0 ) { - - rc = -errno; - vdev_error("stat(%s) rc = %d\n", fp, rc ); - return rc; - } - - if( !S_ISREG( sb.st_mode ) ) { - - return 0; - } - - vdev_debug("Load ACL %s\n", fp ); - - memset( &acl, 0, sizeof(struct vdev_acl) ); - - rc = vdev_acl_load( fp, &acl ); - if( rc != 0 ) { - - vdev_error("vdev_acl_load(%s) rc = %d\n", fp, rc ); - return rc; - } - - // save this acl - rc = sglib_vdev_acl_vector_push_back( acls, acl ); - if( rc != 0 ) { - - // OOM - vdev_acl_free( &acl ); - return rc; - } - - return 0; +int vdev_acl_loader(char const *fp, void *cls) +{ + + struct vdev_acl acl; + int rc = 0; + struct stat sb; + + struct sglib_vdev_acl_vector *acls = + (struct sglib_vdev_acl_vector *)cls; + + // skip if not a regular file + rc = stat(fp, &sb); + if (rc != 0) { + + rc = -errno; + vdev_error("stat(%s) rc = %d\n", fp, rc); + return rc; + } + + if (!S_ISREG(sb.st_mode)) { + + return 0; + } + + vdev_debug("Load ACL %s\n", fp); + + memset(&acl, 0, sizeof(struct vdev_acl)); + + rc = vdev_acl_load(fp, &acl); + if (rc != 0) { + + vdev_error("vdev_acl_load(%s) rc = %d\n", fp, rc); + return rc; + } + // save this acl + rc = sglib_vdev_acl_vector_push_back(acls, acl); + if (rc != 0) { + + // OOM + vdev_acl_free(&acl); + return rc; + } + + return 0; } // load all ACLs from a directory, in lexographic order // return 0 on success, negative on error -int vdev_acl_load_all( char const* dir_path, struct vdev_acl** ret_acls, size_t* ret_num_acls ) { - - int rc = 0; - struct sglib_vdev_acl_vector acls; - - sglib_vdev_acl_vector_init( &acls ); - - rc = vdev_load_all( dir_path, vdev_acl_loader, &acls ); - - if( rc != 0 ) { - - vdev_acl_free_vector( &acls ); - return rc; - } - else { - - if( sglib_vdev_acl_vector_size( &acls ) == 0 ) { - - // nothing - *ret_acls = NULL; - *ret_num_acls = 0; - } - else { - - // extract values - unsigned long len = 0; - - sglib_vdev_acl_vector_yoink( &acls, ret_acls, &len ); - - *ret_num_acls = len; - } - } - - return 0; +int vdev_acl_load_all(char const *dir_path, struct vdev_acl **ret_acls, + size_t * ret_num_acls) +{ + + int rc = 0; + struct sglib_vdev_acl_vector acls; + + sglib_vdev_acl_vector_init(&acls); + + rc = vdev_load_all(dir_path, vdev_acl_loader, &acls); + + if (rc != 0) { + + vdev_acl_free_vector(&acls); + return rc; + } else { + + if (sglib_vdev_acl_vector_size(&acls) == 0) { + + // nothing + *ret_acls = NULL; + *ret_num_acls = 0; + } else { + + // extract values + unsigned long len = 0; + + sglib_vdev_acl_vector_yoink(&acls, ret_acls, &len); + + *ret_num_acls = len; + } + } + + return 0; } // modify a stat buffer to apply a user access control list, if the acl says so -int vdev_acl_do_set_user( struct vdev_acl* acl, uid_t caller_uid, struct stat* sb ) { - - if( acl->has_setuid && acl->has_uid ) { - - // change the UID of this path - if( acl->uid == caller_uid ) { - sb->st_uid = acl->setuid; - } - } - - return 0; +int vdev_acl_do_set_user(struct vdev_acl *acl, uid_t caller_uid, + struct stat *sb) +{ + + if (acl->has_setuid && acl->has_uid) { + + // change the UID of this path + if (acl->uid == caller_uid) { + sb->st_uid = acl->setuid; + } + } + + return 0; } // modify a stat buffer to apply a group access control list -int vdev_acl_do_set_group( struct vdev_acl* acl, gid_t caller_gid, struct stat* sb ) { - - if( acl->has_setgid && acl->has_gid ) { - - // change the GID of this path - if( acl->gid == caller_gid ) { - sb->st_gid = acl->setgid; - } - } - - return 0; +int vdev_acl_do_set_group(struct vdev_acl *acl, gid_t caller_gid, + struct stat *sb) +{ + + if (acl->has_setgid && acl->has_gid) { + + // change the GID of this path + if (acl->gid == caller_gid) { + sb->st_gid = acl->setgid; + } + } + + return 0; } // modify a stat buffer to apply the mode -int vdev_acl_do_set_mode( struct vdev_acl* acl, struct stat* sb ) { - - if( acl->has_setmode ) { - - // clear permission bits - sb->st_mode &= ~(0777); - - // set permission bits - sb->st_mode |= acl->setmode; - } - - return 0; -} +int vdev_acl_do_set_mode(struct vdev_acl *acl, struct stat *sb) +{ + + if (acl->has_setmode) { + // clear permission bits + sb->st_mode &= ~(0777); + + // set permission bits + sb->st_mode |= acl->setmode; + } + + return 0; +} // evaluate a predicate command, with the appropriate environment variables set. // on success, fill in the exit code. // return 0 on success // return negative on error -int vdev_acl_run_predicate( struct vdev_acl* acl, struct pstat* ps, uid_t caller_uid, gid_t caller_gid, int* exit_code ) { - - int exit_status = 0; - char* cmd_buf = NULL; - char env_buf[3][100]; - char* predicate_env[4]; - int rc = 0; - - // build the command with the apporpriate environment variables: - // * VDEV_GID: the gid of the calling process - // * VDEV_UID: the uid of the calling process - // * VDEV_PID: the pid of the calling process - - sprintf(env_buf[0], "VDEV_UID=%u", caller_uid ); - sprintf(env_buf[1], "VDEV_GID=%u", caller_gid ); - sprintf(env_buf[2], "VDEV_PID=%u", pstat_get_pid( ps )); - - predicate_env[0] = env_buf[0]; - predicate_env[1] = env_buf[1]; - predicate_env[2] = env_buf[2]; - predicate_env[3] = NULL; - - rc = vdev_subprocess( cmd_buf, predicate_env, NULL, 0, -1, &exit_status, true ); - - if( rc != 0 ) { - - vdev_error("vdev_subprocess('%s') rc = %d\n", cmd_buf, rc ); - - free( cmd_buf ); - return rc; - } - - *exit_code = exit_status; - - free( cmd_buf ); - - return 0; +int vdev_acl_run_predicate(struct vdev_acl *acl, struct pstat *ps, + uid_t caller_uid, gid_t caller_gid, int *exit_code) +{ + + int exit_status = 0; + char *cmd_buf = NULL; + char env_buf[3][100]; + char *predicate_env[4]; + int rc = 0; + + // build the command with the apporpriate environment variables: + // * VDEV_GID: the gid of the calling process + // * VDEV_UID: the uid of the calling process + // * VDEV_PID: the pid of the calling process + + sprintf(env_buf[0], "VDEV_UID=%u", caller_uid); + sprintf(env_buf[1], "VDEV_GID=%u", caller_gid); + sprintf(env_buf[2], "VDEV_PID=%u", pstat_get_pid(ps)); + + predicate_env[0] = env_buf[0]; + predicate_env[1] = env_buf[1]; + predicate_env[2] = env_buf[2]; + predicate_env[3] = NULL; + + rc = vdev_subprocess(cmd_buf, predicate_env, NULL, 0, -1, &exit_status, + true); + + if (rc != 0) { + + vdev_error("vdev_subprocess('%s') rc = %d\n", cmd_buf, rc); + + free(cmd_buf); + return rc; + } + + *exit_code = exit_status; + + free(cmd_buf); + + return 0; } - // check that the caller PID is matched by the given ACL. // every process match criterion must be satisfied. // return 1 if all ACL criteria match // return 0 if at least one ACL criterion does not match // return negative on error -int vdev_acl_match_process( struct vdev_acl* acl, struct pstat* ps, uid_t caller_uid, gid_t caller_gid ) { - - int rc = 0; - char path[PATH_MAX+1]; - struct stat sb; - - if( !acl->has_proc ) { - // applies to anyone - return 1; - } - - if( acl->proc_path != NULL || acl->has_proc_inode ) { - - if( acl->proc_path != NULL ) { - - pstat_get_path( ps, path ); - if( strcmp( acl->proc_path, path ) != 0 ) { - - // doesn't match - return 0; - } - } - - if( acl->has_proc_inode ) { - - pstat_get_stat( ps, &sb ); - if( acl->proc_inode != sb.st_ino ) { - - // doesn't match - return 0; - } - } - } - - // filter on a given PID list generator? - if( acl->proc_predicate_cmd != NULL ) { - - // run the command and use the exit code to see if - // this ACL applies to the calling process - int exit_status = 0; - - rc = vdev_acl_run_predicate( acl, ps, caller_uid, caller_gid, &exit_status ); - if( rc != 0 ) { - - vdev_error("vdev_acl_run_predicate('%s') rc = %d\n", acl->proc_predicate_cmd, rc ); - return rc; - } - - // exit status follows shell-like semantics: - // 0 indicates "yes, this applies." - // non-zero indicates "no, this does not apply" - - if( exit_status == 0 ) { - return 1; - } - else { - return 0; - } - } - - // all checks match - return 1; -} +int vdev_acl_match_process(struct vdev_acl *acl, struct pstat *ps, + uid_t caller_uid, gid_t caller_gid) +{ + + int rc = 0; + char path[PATH_MAX + 1]; + struct stat sb; + + if (!acl->has_proc) { + // applies to anyone + return 1; + } + + if (acl->proc_path != NULL || acl->has_proc_inode) { + + if (acl->proc_path != NULL) { + + pstat_get_path(ps, path); + if (strcmp(acl->proc_path, path) != 0) { + + // doesn't match + return 0; + } + } + + if (acl->has_proc_inode) { + + pstat_get_stat(ps, &sb); + if (acl->proc_inode != sb.st_ino) { + // doesn't match + return 0; + } + } + } + // filter on a given PID list generator? + if (acl->proc_predicate_cmd != NULL) { + + // run the command and use the exit code to see if + // this ACL applies to the calling process + int exit_status = 0; + + rc = vdev_acl_run_predicate(acl, ps, caller_uid, caller_gid, + &exit_status); + if (rc != 0) { + + vdev_error("vdev_acl_run_predicate('%s') rc = %d\n", + acl->proc_predicate_cmd, rc); + return rc; + } + // exit status follows shell-like semantics: + // 0 indicates "yes, this applies." + // non-zero indicates "no, this does not apply" + + if (exit_status == 0) { + return 1; + } else { + return 0; + } + } + // all checks match + return 1; +} // given a list of access control lists, find the index of the first one that applies to the given caller and path. // return >= 0 with the index // return num_acls if not found // return negative on error -int vdev_acl_find_next( char const* path, struct pstat* caller_proc, uid_t caller_uid, gid_t caller_gid, struct vdev_acl* acls, size_t num_acls ) { - - int rc = 0; - bool found = false; - int idx = 0; - - for( unsigned int i = 0; i < num_acls; i++ ) { - - rc = 0; - - // match UID? - if( acls[i].has_uid && acls[i].uid != caller_uid ) { - // nope - continue; - } - - // match GID? - if( acls[i].has_gid && acls[i].gid != caller_gid ) { - // nope - continue; - } - - // match path? - if( acls[i].num_paths > 0 ) { - - rc = vdev_match_first_regex( path, acls[i].regexes, acls[i].num_paths ); - - if( rc >= (signed)acls[i].num_paths ) { - // no match - continue; - } - } - - if( rc < 0 ) { - - vdev_error("vdev_match_first_regex(%s) rc = %d\n", path, rc ); - break; - } - - // match process? Do this last, since it can be expensive - rc = vdev_acl_match_process( &acls[i], caller_proc, caller_uid, caller_gid ); - if( rc == 0 ) { - // no match - continue; - } - - if( rc < 0 ) { - - // error... - vdev_error("vdev_acl_match_process(%d) rc = %d\n", pstat_get_pid( caller_proc ), rc ); - break; - } - - // success! - found = true; - idx = i; - rc = 0; - break; - } - - if( found ) { - return idx; - } - else { - if( rc >= 0 ) { - return num_acls; - } - else { - return rc; - } - } +int vdev_acl_find_next(char const *path, struct pstat *caller_proc, + uid_t caller_uid, gid_t caller_gid, + struct vdev_acl *acls, size_t num_acls) +{ + + int rc = 0; + bool found = false; + int idx = 0; + + for (unsigned int i = 0; i < num_acls; i++) { + + rc = 0; + + // match UID? + if (acls[i].has_uid && acls[i].uid != caller_uid) { + // nope + continue; + } + // match GID? + if (acls[i].has_gid && acls[i].gid != caller_gid) { + // nope + continue; + } + // match path? + if (acls[i].num_paths > 0) { + + rc = vdev_match_first_regex(path, acls[i].regexes, + acls[i].num_paths); + + if (rc >= (signed)acls[i].num_paths) { + // no match + continue; + } + } + + if (rc < 0) { + + vdev_error("vdev_match_first_regex(%s) rc = %d\n", path, + rc); + break; + } + // match process? Do this last, since it can be expensive + rc = vdev_acl_match_process(&acls[i], caller_proc, caller_uid, + caller_gid); + if (rc == 0) { + // no match + continue; + } + + if (rc < 0) { + + // error... + vdev_error("vdev_acl_match_process(%d) rc = %d\n", + pstat_get_pid(caller_proc), rc); + break; + } + // success! + found = true; + idx = i; + rc = 0; + break; + } + + if (found) { + return idx; + } else { + if (rc >= 0) { + return num_acls; + } else { + return rc; + } + } } // apply the acl to the stat buf, filtering on caller uid, gid, and process information -int vdev_acl_apply( struct vdev_acl* acl, uid_t caller_uid, gid_t caller_gid, struct stat* sb ) { - - // set user, group, mode (if given) - vdev_acl_do_set_user( acl, caller_uid, sb ); - vdev_acl_do_set_group( acl, caller_gid, sb ); - vdev_acl_do_set_mode( acl, sb ); - - return 0; -} +int vdev_acl_apply(struct vdev_acl *acl, uid_t caller_uid, gid_t caller_gid, + struct stat *sb) +{ + + // set user, group, mode (if given) + vdev_acl_do_set_user(acl, caller_uid, sb); + vdev_acl_do_set_group(acl, caller_gid, sb); + vdev_acl_do_set_mode(acl, sb); + return 0; +} // go through the list of acls and apply any modifications to the given stat buffer // return 1 if at least one ACL matches // return 0 if there are no matches (i.e. this device node should be hidden) // return negative on error -int vdev_acl_apply_all( struct vdev_config* config, struct vdev_acl* acls, size_t num_acls, char const* path, struct pstat* caller_proc, uid_t caller_uid, gid_t caller_gid, struct stat* sb ) { - - int rc = 0; - int acl_offset = 0; - int i = 0; - bool found = false; - - // special case: if there are no ACLs, then follow the config default policy - if( num_acls == 0 ) { - return config->default_policy; - } - - while( acl_offset < (signed)num_acls ) { - - // find the next acl - rc = vdev_acl_find_next( path, caller_proc, caller_uid, caller_gid, acls + acl_offset, num_acls - acl_offset ); - - if( rc == (signed)(num_acls - acl_offset) ) { - - // not found - rc = 0; - break; - } - else if( rc < 0 ) { - - vdev_error("vdev_acl_find_next(%s, offset = %d) rc = %d\n", path, acl_offset, rc ); - break; - } - else { - - // matched! advance offset to next acl - i = acl_offset + rc; - acl_offset += rc + 1; - found = true; - - // apply the ACL - rc = vdev_acl_apply( &acls[i], caller_uid, caller_gid, sb ); - if( rc != 0 ) { - - vdev_error("vdev_acl_apply(%s, offset = %d) rc = %d\n", path, acl_offset, rc ); - break; - } - } - } - - if( rc == 0 ) { - // no error reported - if( found ) { - rc = 1; - } - } - - return rc; +int vdev_acl_apply_all(struct vdev_config *config, struct vdev_acl *acls, + size_t num_acls, char const *path, + struct pstat *caller_proc, uid_t caller_uid, + gid_t caller_gid, struct stat *sb) +{ + + int rc = 0; + int acl_offset = 0; + int i = 0; + bool found = false; + + // special case: if there are no ACLs, then follow the config default policy + if (num_acls == 0) { + return config->default_policy; + } + + while (acl_offset < (signed)num_acls) { + + // find the next acl + rc = vdev_acl_find_next(path, caller_proc, caller_uid, + caller_gid, acls + acl_offset, + num_acls - acl_offset); + + if (rc == (signed)(num_acls - acl_offset)) { + + // not found + rc = 0; + break; + } else if (rc < 0) { + + vdev_error + ("vdev_acl_find_next(%s, offset = %d) rc = %d\n", + path, acl_offset, rc); + break; + } else { + + // matched! advance offset to next acl + i = acl_offset + rc; + acl_offset += rc + 1; + found = true; + + // apply the ACL + rc = vdev_acl_apply(&acls[i], caller_uid, caller_gid, + sb); + if (rc != 0) { + + vdev_error + ("vdev_acl_apply(%s, offset = %d) rc = %d\n", + path, acl_offset, rc); + break; + } + } + } + + if (rc == 0) { + // no error reported + if (found) { + rc = 1; + } + } + + return rc; } diff --git a/fs/acl.h b/fs/acl.h index 8a13a08..ca91ae2 100644 --- a/fs/acl.h +++ b/fs/acl.h @@ -47,38 +47,38 @@ // vdev access control list. struct vdev_acl { - - // user to match - bool has_uid; - uid_t uid; - - // group to match - bool has_gid; - gid_t gid; - - // process info to match (set at least one; all must match for the ACL to apply) - bool has_proc; // if true, at least one of the following is filled in (and the ACL will only apply if the request is from one of the indicated processes) - char* proc_path; // path to the allowed process - char* proc_predicate_cmd; // command string to run to see if this ACL applies to the calling process (based on the exit code: 0 indicates 'yes, this applies'; nonzero indicates 'no, does not apply') - bool has_proc_inode; // whether or not the ACL has an inode check - ino_t proc_inode; // process binary's inode - - // UID to set on match - bool has_setuid; - uid_t setuid; - - // GID to set on match - bool has_setgid; - gid_t setgid; - - // mode to set on match - bool has_setmode; - mode_t setmode; - - // device node path regexes over which this ACL applies (NULL-terminated) - char** paths; - regex_t* regexes; - size_t num_paths; + + // user to match + bool has_uid; + uid_t uid; + + // group to match + bool has_gid; + gid_t gid; + + // process info to match (set at least one; all must match for the ACL to apply) + bool has_proc; // if true, at least one of the following is filled in (and the ACL will only apply if the request is from one of the indicated processes) + char *proc_path; // path to the allowed process + char *proc_predicate_cmd; // command string to run to see if this ACL applies to the calling process (based on the exit code: 0 indicates 'yes, this applies'; nonzero indicates 'no, does not apply') + bool has_proc_inode; // whether or not the ACL has an inode check + ino_t proc_inode; // process binary's inode + + // UID to set on match + bool has_setuid; + uid_t setuid; + + // GID to set on match + bool has_setgid; + gid_t setgid; + + // mode to set on match + bool has_setmode; + mode_t setmode; + + // device node path regexes over which this ACL applies (NULL-terminated) + char **paths; + regex_t *regexes; + size_t num_paths; }; typedef struct vdev_acl vdev_acl; @@ -86,15 +86,16 @@ typedef struct vdev_acl vdev_acl; // prototype... struct vdev_config; -C_LINKAGE_BEGIN - -int vdev_acl_init( struct vdev_acl* acl ); -int vdev_acl_load_all( char const* dir_path, struct vdev_acl** ret_acls, size_t* ret_num_acls ); -int vdev_acl_free( struct vdev_acl* acl ); -int vdev_acl_free_all( struct vdev_acl* acl_list, size_t num_acls ); +C_LINKAGE_BEGIN int vdev_acl_init(struct vdev_acl *acl); +int vdev_acl_load_all(char const *dir_path, struct vdev_acl **ret_acls, + size_t * ret_num_acls); +int vdev_acl_free(struct vdev_acl *acl); +int vdev_acl_free_all(struct vdev_acl *acl_list, size_t num_acls); -int vdev_acl_apply_all( struct vdev_config* conf, struct vdev_acl* acls, size_t num_acls, char const* path, struct pstat* caller_proc, uid_t caller_uid, gid_t caller_gid, struct stat* sb ); +int vdev_acl_apply_all(struct vdev_config *conf, struct vdev_acl *acls, + size_t num_acls, char const *path, + struct pstat *caller_proc, uid_t caller_uid, + gid_t caller_gid, struct stat *sb); C_LINKAGE_END - #endif diff --git a/fs/fs.c b/fs/fs.c index 1daa5de..389e8a3 100644 --- a/fs/fs.c +++ b/fs/fs.c @@ -19,1274 +19,1334 @@ . */ - #include "fs.h" #include "acl.h" -static char const* vdev_fuse_odev = "-odev"; -static char const* vdev_fuse_ononempty = "-ononempty"; -static char const* vdev_fuse_allow_other = "-oallow_other"; +static char const *vdev_fuse_odev = "-odev"; +static char const *vdev_fuse_ononempty = "-ononempty"; +static char const *vdev_fuse_allow_other = "-oallow_other"; // scanning context queue entry struct vdevfs_scandirat_queue { - - int fd; - char* path; - - struct vdevfs_scandirat_queue* next; + + int fd; + char *path; + + struct vdevfs_scandirat_queue *next; }; // scanning context, for vdevfs_dev_import struct vdevfs_scandirat_context { - struct fskit_core* core; // fskit core context - struct fskit_entry* parent_dir; // corresponding fskit directory being scanned - char* parent_path; - - struct vdevfs_scandirat_queue* tail; -}; + struct fskit_core *core; // fskit core context + struct fskit_entry *parent_dir; // corresponding fskit directory being scanned + char *parent_path; + struct vdevfs_scandirat_queue *tail; +}; // set up a vdevfs_scandirat_context // always succeeds -static void vdevfs_scandirat_context_init( struct vdevfs_scandirat_context* ctx, struct fskit_core* core, struct fskit_entry* parent_dir, char* parent_path, struct vdevfs_scandirat_queue* tail ) { - - ctx->core = core; - ctx->parent_dir = parent_dir; - ctx->parent_path = parent_path; - ctx->tail = tail; -} +static void vdevfs_scandirat_context_init(struct vdevfs_scandirat_context *ctx, + struct fskit_core *core, + struct fskit_entry *parent_dir, + char *parent_path, + struct vdevfs_scandirat_queue *tail) +{ + ctx->core = core; + ctx->parent_dir = parent_dir; + ctx->parent_path = parent_path; + ctx->tail = tail; +} // callback to be fed int vdev_load_all_at. // builds up the children listing of vdevfs_scandirat_context.parent_dir. // if we find a directory, open it and enqueue its file descriptor to dir_queue. // return 0 on success // return -ENOMEM on OOM -static int vdevfs_scandirat_context_callback( int dirfd, struct dirent* dent, void* cls ) { - - struct vdevfs_scandirat_context* ctx = (struct vdevfs_scandirat_context*)cls; - - int rc = 0; - int fd = 0; - struct stat sb; - struct fskit_entry* child; - char linkbuf[8193]; // for resolving an underlying symlink - char const* method_name; // for logging - char* joined_path = NULL; - struct vdevfs_scandirat_queue* next = NULL; - - // skip . and .. - if( strcmp( dent->d_name, "." ) == 0 || strcmp( dent->d_name, ".." ) == 0 ) { - return 0; - } - - // learn more... - rc = fstatat( dirfd, dent->d_name, &sb, AT_SYMLINK_NOFOLLOW ); - if( rc != 0 ) { - - rc = -errno; - - // mask errors; just log the serious ones - if( rc != -ENOENT && rc != -EACCES ) { - - vdev_error("fstatat(%d, '%s') rc = %d\n", dirfd, dent->d_name, rc ); - } - - return 0; - } - - // directory? get an fd to it if so, so we can keep scanning - if( S_ISDIR( sb.st_mode ) ) { - - // try to get at it - fd = openat( dirfd, dent->d_name, O_RDONLY ); - if( fd < 0 ) { - - rc = -errno; - - // mask errors; just log the serious ones - if( rc != -ENOENT && rc != -EACCES ) { - - vdev_error("openat(%d, '%s') rc = %d\n", dirfd, dent->d_name, rc ); - } - - return 0; - } - - // woo! save it - joined_path = vdev_fullpath( ctx->parent_path, dent->d_name, NULL ); - if( joined_path == NULL ) { - - close( fd ); - return -ENOMEM; - } - - next = VDEV_CALLOC( struct vdevfs_scandirat_queue, 1 ); - if( next == NULL ) { - - close( fd ); - free( joined_path ); - return -ENOMEM; - } - - next->fd = fd; - next->path = joined_path; - next->next = NULL; - - ctx->tail->next = next; - ctx->tail = ctx->tail->next; - } - - // construct an inode for this entry - child = fskit_entry_new(); - if( child == NULL ) { - - return -ENOMEM; - } - - // regular file? - if( S_ISREG( sb.st_mode ) ) { - - method_name = "fskit_entry_init_file"; - rc = fskit_entry_init_file( child, sb.st_ino, sb.st_uid, sb.st_gid, sb.st_mode & 0777 ); - } - - // directory? - else if( S_ISDIR( sb.st_mode ) ) { - - method_name = "fskit_entry_init_dir"; - rc = fskit_entry_init_dir( child, ctx->parent_dir, sb.st_ino, sb.st_uid, sb.st_gid, sb.st_mode & 0777 ); - } - - // named pipe? - else if( S_ISFIFO( sb.st_mode ) ) { - - method_name = "fskit_entry_init_fifo"; - rc = fskit_entry_init_fifo( child, sb.st_ino, sb.st_uid, sb.st_gid, sb.st_mode & 0777 ); - } - - // unix domain socket? - else if( S_ISSOCK( sb.st_mode ) ) { - - method_name = "fskit_entry_init_sock"; - rc = fskit_entry_init_sock( child, sb.st_ino, sb.st_uid, sb.st_gid, sb.st_mode & 0777 ); - } - - // character device? - else if( S_ISCHR( sb.st_mode ) ) { - - method_name = "fskit_entry_init_chr"; - rc = fskit_entry_init_chr( child, sb.st_ino, sb.st_uid, sb.st_gid, sb.st_mode, sb.st_rdev ); - } - - // block device? - else if( S_ISBLK( sb.st_mode ) ) { - - method_name = "fskit_entry_init_blk"; - rc = fskit_entry_init_blk( child, sb.st_ino, sb.st_uid, sb.st_gid, sb.st_mode, sb.st_rdev ); - } - - // symbolic link? - else if( S_ISLNK( sb.st_mode ) ) { - - // read the link first... - memset( linkbuf, 0, 8193 ); - - rc = readlinkat( dirfd, dent->d_name, linkbuf, 8192 ); - if( rc < 0 ) { - - rc = -errno; - - // mask error, but log serious ones. this link will not appear in the listing - if( rc != -ENOENT && rc != -EACCES ) { - - vdev_error("readlinkat(%d, '%s') rc = %d\n", dirfd, dent->d_name, rc ); - } - - free( child ); - child = NULL; - - return 0; - } - - method_name = "fskit_entry_init_symlink"; - rc = fskit_entry_init_symlink( child, sb.st_ino, linkbuf ); - } - - // success? - if( rc != 0 ) { - - vdev_error("%s( on %d, '%s' ) rc = %d\n", method_name, dirfd, dent->d_name, rc ); - - free( child ); - child = NULL; - - return rc; - } - - // insert into parent - rc = fskit_entry_attach_lowlevel( ctx->parent_dir, child, dent->d_name ); - if( rc != 0 ) { - - // OOM - fskit_entry_destroy( ctx->core, child, false ); - - free( child ); - child = NULL; - - return rc; - } - - // success! - return rc; -} +static int vdevfs_scandirat_context_callback(int dirfd, struct dirent *dent, + void *cls) +{ + + struct vdevfs_scandirat_context *ctx = + (struct vdevfs_scandirat_context *)cls; + + int rc = 0; + int fd = 0; + struct stat sb; + struct fskit_entry *child; + char linkbuf[8193]; // for resolving an underlying symlink + char const *method_name; // for logging + char *joined_path = NULL; + struct vdevfs_scandirat_queue *next = NULL; + + // skip . and .. + if (strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0) { + return 0; + } + // learn more... + rc = fstatat(dirfd, dent->d_name, &sb, AT_SYMLINK_NOFOLLOW); + if (rc != 0) { + + rc = -errno; + + // mask errors; just log the serious ones + if (rc != -ENOENT && rc != -EACCES) { + + vdev_error("fstatat(%d, '%s') rc = %d\n", dirfd, + dent->d_name, rc); + } + + return 0; + } + // directory? get an fd to it if so, so we can keep scanning + if (S_ISDIR(sb.st_mode)) { + + // try to get at it + fd = openat(dirfd, dent->d_name, O_RDONLY); + if (fd < 0) { + + rc = -errno; + + // mask errors; just log the serious ones + if (rc != -ENOENT && rc != -EACCES) { + + vdev_error("openat(%d, '%s') rc = %d\n", dirfd, + dent->d_name, rc); + } + + return 0; + } + // woo! save it + joined_path = + vdev_fullpath(ctx->parent_path, dent->d_name, NULL); + if (joined_path == NULL) { + + close(fd); + return -ENOMEM; + } + + next = VDEV_CALLOC(struct vdevfs_scandirat_queue, 1); + if (next == NULL) { + + close(fd); + free(joined_path); + return -ENOMEM; + } + + next->fd = fd; + next->path = joined_path; + next->next = NULL; + + ctx->tail->next = next; + ctx->tail = ctx->tail->next; + } + // construct an inode for this entry + child = fskit_entry_new(); + if (child == NULL) { + + return -ENOMEM; + } + // regular file? + if (S_ISREG(sb.st_mode)) { + + method_name = "fskit_entry_init_file"; + rc = fskit_entry_init_file(child, sb.st_ino, sb.st_uid, + sb.st_gid, sb.st_mode & 0777); + } + // directory? + else if (S_ISDIR(sb.st_mode)) { + + method_name = "fskit_entry_init_dir"; + rc = fskit_entry_init_dir(child, ctx->parent_dir, sb.st_ino, + sb.st_uid, sb.st_gid, + sb.st_mode & 0777); + } + // named pipe? + else if (S_ISFIFO(sb.st_mode)) { + + method_name = "fskit_entry_init_fifo"; + rc = fskit_entry_init_fifo(child, sb.st_ino, sb.st_uid, + sb.st_gid, sb.st_mode & 0777); + } + // unix domain socket? + else if (S_ISSOCK(sb.st_mode)) { + + method_name = "fskit_entry_init_sock"; + rc = fskit_entry_init_sock(child, sb.st_ino, sb.st_uid, + sb.st_gid, sb.st_mode & 0777); + } + // character device? + else if (S_ISCHR(sb.st_mode)) { + + method_name = "fskit_entry_init_chr"; + rc = fskit_entry_init_chr(child, sb.st_ino, sb.st_uid, + sb.st_gid, sb.st_mode, sb.st_rdev); + } + // block device? + else if (S_ISBLK(sb.st_mode)) { + + method_name = "fskit_entry_init_blk"; + rc = fskit_entry_init_blk(child, sb.st_ino, sb.st_uid, + sb.st_gid, sb.st_mode, sb.st_rdev); + } + // symbolic link? + else if (S_ISLNK(sb.st_mode)) { + + // read the link first... + memset(linkbuf, 0, 8193); + + rc = readlinkat(dirfd, dent->d_name, linkbuf, 8192); + if (rc < 0) { + + rc = -errno; + + // mask error, but log serious ones. this link will not appear in the listing + if (rc != -ENOENT && rc != -EACCES) { + + vdev_error("readlinkat(%d, '%s') rc = %d\n", + dirfd, dent->d_name, rc); + } + + free(child); + child = NULL; + + return 0; + } + method_name = "fskit_entry_init_symlink"; + rc = fskit_entry_init_symlink(child, sb.st_ino, linkbuf); + } + // success? + if (rc != 0) { + + vdev_error("%s( on %d, '%s' ) rc = %d\n", method_name, dirfd, + dent->d_name, rc); + + free(child); + child = NULL; + + return rc; + } + // insert into parent + rc = fskit_entry_attach_lowlevel(ctx->parent_dir, child, dent->d_name); + if (rc != 0) { + + // OOM + fskit_entry_destroy(ctx->core, child, false); + + free(child); + child = NULL; + + return rc; + } + // success! + return rc; +} // load the filesystem with metadata from under the mountpoint // return 0 on success // return -ENOMEM on OOM -static int vdevfs_dev_import( struct fskit_fuse_state* fs, void* arg ) { - - struct vdevfs* vdev = (struct vdevfs*)arg; - int rc = 0; - struct vdevfs_scandirat_queue* dir_queue = NULL; - struct vdevfs_scandirat_queue* dir_queue_tail = NULL; - struct vdevfs_scandirat_queue* ptr = NULL; - struct fskit_entry* dir_ent = NULL; - - struct vdevfs_scandirat_context scan_context; - - char* root = vdev_strdup_or_null("/"); - if( root == NULL ) { - return -ENOMEM; - } - - int root_fd = dup( vdev->mountpoint_dirfd ); - if( root_fd < 0 ) { - - vdev_error("dup(%d) rc = %d\n", vdev->mountpoint_dirfd, rc ); - rc = -errno; - free( root ); - return rc; - } - - // start at the mountpoint - dir_queue = VDEV_CALLOC( struct vdevfs_scandirat_queue, 1 ); - if( dir_queue == NULL ) { - - free( root ); - close( root_fd ); - return -ENOMEM; - } - - dir_queue->fd = root_fd; - dir_queue->path = root; - dir_queue->next = NULL; - - dir_queue_tail = dir_queue; - - while( dir_queue != NULL ) { - - int dirfd = dir_queue->fd; - char* dirpath = dir_queue->path; - - // look up this entry - dir_ent = fskit_entry_resolve_path( fskit_fuse_get_core( vdev->fs ), dirpath, 0, 0, true, &rc ); - if( rc != 0 ) { - - // shouldn't happen--we're going breadth-first - vdev_error("fskit_entry_resolve_path('%s') rc = %d\n", dirpath, rc ); - break; - } - - // make a scan context - vdevfs_scandirat_context_init( &scan_context, fskit_fuse_get_core( vdev->fs ), dir_ent, dirpath, dir_queue_tail ); - - // scan this directory - rc = vdev_load_all_at( dirfd, vdevfs_scandirat_context_callback, &scan_context ); - - fskit_entry_unlock( dir_ent ); - - if( rc != 0 ) { - - // failed - vdev_error("vdev_load_all_at(%d, '%s') rc = %d\n", dirfd, dirpath, rc ); - break; - } - - // advance tail pointer - dir_queue_tail = scan_context.tail; - - // advance to next directory - close( dirfd ); - free( dirpath ); - dirpath = NULL; - - ptr = dir_queue; - dir_queue = dir_queue->next; - - memset( ptr, 0, sizeof(struct vdevfs_scandirat_queue) ); - free( ptr ); - } - - // free any remaining directory state - for( struct vdevfs_scandirat_queue* ptr = dir_queue; ptr != NULL; ) { - - int fd = ptr->fd; - char* path = ptr->path; - struct vdevfs_scandirat_queue* old_ptr = ptr; - - close( fd ); - free( path ); - - ptr = ptr->next; - - memset( old_ptr, 0, sizeof(struct vdevfs_scandirat_queue) ); - free( old_ptr ); - } - - return rc; -} +static int vdevfs_dev_import(struct fskit_fuse_state *fs, void *arg) +{ + + struct vdevfs *vdev = (struct vdevfs *)arg; + int rc = 0; + struct vdevfs_scandirat_queue *dir_queue = NULL; + struct vdevfs_scandirat_queue *dir_queue_tail = NULL; + struct vdevfs_scandirat_queue *ptr = NULL; + struct fskit_entry *dir_ent = NULL; + + struct vdevfs_scandirat_context scan_context; + + char *root = vdev_strdup_or_null("/"); + if (root == NULL) { + return -ENOMEM; + } + + int root_fd = dup(vdev->mountpoint_dirfd); + if (root_fd < 0) { + + vdev_error("dup(%d) rc = %d\n", vdev->mountpoint_dirfd, rc); + rc = -errno; + free(root); + return rc; + } + // start at the mountpoint + dir_queue = VDEV_CALLOC(struct vdevfs_scandirat_queue, 1); + if (dir_queue == NULL) { + + free(root); + close(root_fd); + return -ENOMEM; + } + + dir_queue->fd = root_fd; + dir_queue->path = root; + dir_queue->next = NULL; + + dir_queue_tail = dir_queue; + + while (dir_queue != NULL) { + + int dirfd = dir_queue->fd; + char *dirpath = dir_queue->path; + + // look up this entry + dir_ent = + fskit_entry_resolve_path(fskit_fuse_get_core(vdev->fs), + dirpath, 0, 0, true, &rc); + if (rc != 0) { + // shouldn't happen--we're going breadth-first + vdev_error("fskit_entry_resolve_path('%s') rc = %d\n", + dirpath, rc); + break; + } + // make a scan context + vdevfs_scandirat_context_init(&scan_context, + fskit_fuse_get_core(vdev->fs), + dir_ent, dirpath, dir_queue_tail); + + // scan this directory + rc = vdev_load_all_at(dirfd, vdevfs_scandirat_context_callback, + &scan_context); + + fskit_entry_unlock(dir_ent); + + if (rc != 0) { + + // failed + vdev_error("vdev_load_all_at(%d, '%s') rc = %d\n", + dirfd, dirpath, rc); + break; + } + // advance tail pointer + dir_queue_tail = scan_context.tail; + + // advance to next directory + close(dirfd); + free(dirpath); + dirpath = NULL; + + ptr = dir_queue; + dir_queue = dir_queue->next; + + memset(ptr, 0, sizeof(struct vdevfs_scandirat_queue)); + free(ptr); + } + + // free any remaining directory state + for (struct vdevfs_scandirat_queue * ptr = dir_queue; ptr != NULL;) { + + int fd = ptr->fd; + char *path = ptr->path; + struct vdevfs_scandirat_queue *old_ptr = ptr; + + close(fd); + free(path); + + ptr = ptr->next; + + memset(old_ptr, 0, sizeof(struct vdevfs_scandirat_queue)); + free(old_ptr); + } + + return rc; +} // get the mountpoint option, by parsing the FUSE command line -static int vdev_get_mountpoint( int fuse_argc, char** fuse_argv, char** ret_mountpoint ) { - - struct fuse_args fargs = FUSE_ARGS_INIT(fuse_argc, fuse_argv); - char* mountpoint = NULL; - int unused_1; - int unused_2; - int rc = 0; - - // parse command-line... - rc = fuse_parse_cmdline( &fargs, &mountpoint, &unused_1, &unused_2 ); - if( rc < 0 ) { - - vdev_error("fuse_parse_cmdline rc = %d\n", rc ); - fuse_opt_free_args(&fargs); - - return rc; - } - - else { - - if( mountpoint != NULL ) { - - *ret_mountpoint = strdup( mountpoint ); - free( mountpoint ); - - rc = 0; - } - else { - rc = -ENOMEM; - } - - fuse_opt_free_args(&fargs); - } - - return 0; -} +static int vdev_get_mountpoint(int fuse_argc, char **fuse_argv, + char **ret_mountpoint) +{ + + struct fuse_args fargs = FUSE_ARGS_INIT(fuse_argc, fuse_argv); + char *mountpoint = NULL; + int unused_1; + int unused_2; + int rc = 0; + + // parse command-line... + rc = fuse_parse_cmdline(&fargs, &mountpoint, &unused_1, &unused_2); + if (rc < 0) { + + vdev_error("fuse_parse_cmdline rc = %d\n", rc); + fuse_opt_free_args(&fargs); + + return rc; + } + + else { + if (mountpoint != NULL) { + + *ret_mountpoint = strdup(mountpoint); + free(mountpoint); + + rc = 0; + } else { + rc = -ENOMEM; + } + + fuse_opt_free_args(&fargs); + } + + return 0; +} // initialize the filesystem front-end // call after vdev_init // return 0 on success // return -ENOMEM on OOM // return negative on error -int vdevfs_init( struct vdevfs* vdev, int argc, char** argv ) { - - int rc = 0; - int rh = 0; - struct fskit_core* core = NULL; - int fuse_argc = 0; - char** fuse_argv = NULL; - int dirfd = 0; - - // library setup - vdev_setup_global(); - - struct fskit_fuse_state* fs = fskit_fuse_state_new(); - - if( fs == NULL ) { - return -ENOMEM; - } - - fuse_argv = VDEV_CALLOC( char*, argc + 5 ); - - if( fuse_argv == NULL ) { - - free( fs ); - return -ENOMEM; - } - - // load config - vdev->config = VDEV_CALLOC( struct vdev_config, 1 ); - if( vdev->config == NULL ) { - - free( fs ); - free( fuse_argv ); - return -ENOMEM; - } - - // init config - rc = vdev_config_init( vdev->config ); - if( rc != 0 ) { - - vdev_error("vdev_config_init rc = %d\n", rc ); - - vdevfs_shutdown( vdev ); - free( fs ); - free( fuse_argv ); - return rc; - } - - // parse opts - rc = vdev_config_load_from_args( vdev->config, argc, argv, &fuse_argc, fuse_argv ); - if( rc != 0 ) { - - vdev_error("vdev_opts_parse rc = %d\n", rc ); - - vdev_config_usage( argv[0] ); - - free( fs ); - free( fuse_argv ); - vdevfs_shutdown( vdev ); - return rc; - } - - // get the mountpoint, but from FUSE - if( vdev->config->mountpoint != NULL ) { - free( vdev->config->mountpoint ); - } - - rc = vdev_get_mountpoint( fuse_argc, fuse_argv, &vdev->config->mountpoint ); - if( rc != 0 ) { - - vdev_error("vdev_get_mountpoint rc = %d\n", rc ); - - vdev_config_usage( argv[0] ); - - free( fs ); - free( fuse_argv ); - return rc; - } - - vdev_set_debug_level( vdev->config->debug_level ); - vdev_set_error_level( vdev->config->error_level ); - - vdev_debug("Config file: %s\n", vdev->config->config_path ); - - rc = vdev_config_load( vdev->config->config_path, vdev->config ); - if( rc != 0 ) { - - vdev_error("vdev_config_load('%s') rc = %d\n", vdev->config->config_path, rc ); - - vdevfs_shutdown( vdev ); - free( fs ); - free( fuse_argv ); - return rc; - } - - vdev_debug("vdev ACLs dir: %s\n", vdev->config->acls_dir ); - - // force -odev, since we'll create device nodes - fuse_argv[fuse_argc] = (char*)vdev_fuse_odev; - fuse_argc++; - - // force -oallow_other, since we'll want to expose this to everyone - fuse_argv[fuse_argc] = (char*)vdev_fuse_allow_other; - fuse_argc++; - - // force -ononempty, since we'll want to import the underlying filesystem - fuse_argv[fuse_argc] = (char*)vdev_fuse_ononempty; - fuse_argc++; - - vdev->mountpoint = vdev_strdup_or_null( vdev->config->mountpoint ); - - if( vdev->mountpoint == NULL ) { - - vdev_error("Failed to set mountpoint, config.mountpount = '%s'\n", vdev->config->mountpoint ); - - vdevfs_shutdown( vdev ); - free( fuse_argv ); - free( fs ); - return -EINVAL; - } - else { - - vdev_debug("mountpoint: %s\n", vdev->mountpoint ); - } - - vdev->argc = argc; - vdev->argv = argv; - vdev->fuse_argc = fuse_argc; - vdev->fuse_argv = fuse_argv; - - fskit_set_debug_level( vdev->config->debug_level ); - fskit_set_error_level( vdev->config->error_level ); - - // get mountpoint directory - dirfd = open( vdev->mountpoint, O_DIRECTORY ); - if( dirfd < 0 ) { - - rc = -errno; - vdev_error("open('%s') rc = %d\n", vdev->mountpoint, rc ); - - free( fs ); - vdevfs_shutdown( vdev ); - return rc; - } - - vdev->mountpoint_dirfd = dirfd; - - // set up fskit - rc = fskit_fuse_init( fs, vdev ); - if( rc != 0 ) { - - vdev_error("fskit_fuse_init rc = %d\n", rc ); - free( fs ); - vdevfs_shutdown( vdev ); - return rc; - } - - // load ACLs - rc = vdev_acl_load_all( vdev->config->acls_dir, &vdev->acls, &vdev->num_acls ); - if( rc != 0 ) { - - vdev_error("vdev_acl_load_all('%s') rc = %d\n", vdev->config->acls_dir, rc ); - - fskit_fuse_shutdown( fs, NULL ); - free( fs ); - vdevfs_shutdown( vdev ); - return rc; - } - - // make sure the fs can access its methods through the VFS - fskit_fuse_setting_enable( fs, FSKIT_FUSE_SET_FS_ACCESS ); - - core = fskit_fuse_get_core( fs ); - - // add handlers. - rh = fskit_route_readdir( core, FSKIT_ROUTE_ANY, vdevfs_readdir, FSKIT_CONCURRENT ); - if( rh < 0 ) { - - vdev_error("fskit_route_readdir(%s) rc = %d\n", FSKIT_ROUTE_ANY, rh ); - goto vdev_route_fail; - } - - rh = fskit_route_stat( core, FSKIT_ROUTE_ANY, vdevfs_stat, FSKIT_CONCURRENT ); - if( rh < 0 ) { - - vdev_error("fskit_route_stat(%s) rc = %d\n", FSKIT_ROUTE_ANY, rh ); - goto vdev_route_fail; - } - - rh = fskit_route_mknod( core, FSKIT_ROUTE_ANY, vdevfs_mknod, FSKIT_CONCURRENT ); - if( rc < 0 ) { - - vdev_error("fskit_route_mknod(%s) rc = %d\n", FSKIT_ROUTE_ANY, rh ); - goto vdev_route_fail; - } - - rh = fskit_route_mkdir( core, FSKIT_ROUTE_ANY, vdevfs_mkdir, FSKIT_CONCURRENT ); - if( rh < 0 ) { - - vdev_error("fskit_route_mkdir(%s) rc = %d\n", FSKIT_ROUTE_ANY, rh ); - goto vdev_route_fail; - } - - rh = fskit_route_create( core, FSKIT_ROUTE_ANY, vdevfs_create, FSKIT_CONCURRENT ); - if( rh < 0 ) { - - vdev_error("fskit_route_create(%s) rc = %d\n", FSKIT_ROUTE_ANY, rh ); - goto vdev_route_fail; - } - - rh = fskit_route_open( core, FSKIT_ROUTE_ANY, vdevfs_open, FSKIT_CONCURRENT ); - if( rh < 0 ) { - - vdev_error("fskit_route_open(%s) rc = %d\n", FSKIT_ROUTE_ANY, rh ); - goto vdev_route_fail; - } - - rh = fskit_route_read( core, FSKIT_ROUTE_ANY, vdevfs_read, FSKIT_CONCURRENT ); - if( rh < 0 ) { - - vdev_error("fskit_route_read(%s) rc = %d\n", FSKIT_ROUTE_ANY, rh ); - goto vdev_route_fail; - } - - rh = fskit_route_write( core, FSKIT_ROUTE_ANY, vdevfs_write, FSKIT_CONCURRENT ); - if( rh < 0 ) { - - vdev_error("fskit_route_write(%s) rc = %d\n", FSKIT_ROUTE_ANY, rh ); - goto vdev_route_fail; - } - - rh = fskit_route_close( core, FSKIT_ROUTE_ANY, vdevfs_close, FSKIT_CONCURRENT ); - if( rh < 0 ) { - - vdev_error("fskit_route_close(%s) rc = %d\n", FSKIT_ROUTE_ANY, rh ); - goto vdev_route_fail; - } - - rh = fskit_route_sync( core, FSKIT_ROUTE_ANY, vdevfs_sync, FSKIT_CONCURRENT ); - if( rh < 0 ) { - - vdev_error("fskit_route_sync(%s) rc = %d\n", FSKIT_ROUTE_ANY, rh ); - goto vdev_route_fail; - } - - rh = fskit_route_detach( core, FSKIT_ROUTE_ANY, vdevfs_detach, FSKIT_CONCURRENT ); - if( rh < 0 ) { - - vdev_error("fskit_route_detach(%s) rc = %d\n", FSKIT_ROUTE_ANY, rh ); - goto vdev_route_fail; - } - - vdev->fs = fs; - vdev->close_rh = rh; - - // set the root to be owned by the effective UID and GID of user - fskit_chown( core, "/", 0, 0, geteuid(), getegid() ); - - // import the underlying filesystem once we're mounted, but before taking requests. - rc = fskit_fuse_postmount_callback( fs, vdevfs_dev_import, vdev ); - if( rc != 0 ) { - - vdev_error("fskit_fuse_postmount_callback() rc = %d\n", rc ); - - vdev->fs = NULL; - goto vdev_route_fail; - } - - return 0; - -vdev_route_fail: - - fskit_fuse_shutdown( fs, NULL ); - free( fs ); - vdevfs_shutdown( vdev ); - return rh; -} +int vdevfs_init(struct vdevfs *vdev, int argc, char **argv) +{ + int rc = 0; + int rh = 0; + struct fskit_core *core = NULL; + int fuse_argc = 0; + char **fuse_argv = NULL; + int dirfd = 0; -// main loop for vdev frontend -int vdevfs_main( struct vdevfs* vdev, int fuse_argc, char** fuse_argv ) { - - int rc = 0; - - rc = fskit_fuse_main( vdev->fs, fuse_argc, fuse_argv ); - - return rc; + // library setup + vdev_setup_global(); + + struct fskit_fuse_state *fs = fskit_fuse_state_new(); + + if (fs == NULL) { + return -ENOMEM; + } + + fuse_argv = VDEV_CALLOC(char *, argc + 5); + + if (fuse_argv == NULL) { + + free(fs); + return -ENOMEM; + } + // load config + vdev->config = VDEV_CALLOC(struct vdev_config, 1); + if (vdev->config == NULL) { + + free(fs); + free(fuse_argv); + return -ENOMEM; + } + // init config + rc = vdev_config_init(vdev->config); + if (rc != 0) { + + vdev_error("vdev_config_init rc = %d\n", rc); + + vdevfs_shutdown(vdev); + free(fs); + free(fuse_argv); + return rc; + } + // parse opts + rc = vdev_config_load_from_args(vdev->config, argc, argv, &fuse_argc, + fuse_argv); + if (rc != 0) { + + vdev_error("vdev_opts_parse rc = %d\n", rc); + + vdev_config_usage(argv[0]); + + free(fs); + free(fuse_argv); + vdevfs_shutdown(vdev); + return rc; + } + // get the mountpoint, but from FUSE + if (vdev->config->mountpoint != NULL) { + free(vdev->config->mountpoint); + } + + rc = vdev_get_mountpoint(fuse_argc, fuse_argv, + &vdev->config->mountpoint); + if (rc != 0) { + + vdev_error("vdev_get_mountpoint rc = %d\n", rc); + + vdev_config_usage(argv[0]); + + free(fs); + free(fuse_argv); + return rc; + } + + vdev_set_debug_level(vdev->config->debug_level); + vdev_set_error_level(vdev->config->error_level); + + vdev_debug("Config file: %s\n", vdev->config->config_path); + + rc = vdev_config_load(vdev->config->config_path, vdev->config); + if (rc != 0) { + + vdev_error("vdev_config_load('%s') rc = %d\n", + vdev->config->config_path, rc); + + vdevfs_shutdown(vdev); + free(fs); + free(fuse_argv); + return rc; + } + + vdev_debug("vdev ACLs dir: %s\n", vdev->config->acls_dir); + + // force -odev, since we'll create device nodes + fuse_argv[fuse_argc] = (char *)vdev_fuse_odev; + fuse_argc++; + + // force -oallow_other, since we'll want to expose this to everyone + fuse_argv[fuse_argc] = (char *)vdev_fuse_allow_other; + fuse_argc++; + + // force -ononempty, since we'll want to import the underlying filesystem + fuse_argv[fuse_argc] = (char *)vdev_fuse_ononempty; + fuse_argc++; + + vdev->mountpoint = vdev_strdup_or_null(vdev->config->mountpoint); + + if (vdev->mountpoint == NULL) { + + vdev_error + ("Failed to set mountpoint, config.mountpount = '%s'\n", + vdev->config->mountpoint); + + vdevfs_shutdown(vdev); + free(fuse_argv); + free(fs); + return -EINVAL; + } else { + + vdev_debug("mountpoint: %s\n", vdev->mountpoint); + } + + vdev->argc = argc; + vdev->argv = argv; + vdev->fuse_argc = fuse_argc; + vdev->fuse_argv = fuse_argv; + + fskit_set_debug_level(vdev->config->debug_level); + fskit_set_error_level(vdev->config->error_level); + + // get mountpoint directory + dirfd = open(vdev->mountpoint, O_DIRECTORY); + if (dirfd < 0) { + + rc = -errno; + vdev_error("open('%s') rc = %d\n", vdev->mountpoint, rc); + + free(fs); + vdevfs_shutdown(vdev); + return rc; + } + + vdev->mountpoint_dirfd = dirfd; + + // set up fskit + rc = fskit_fuse_init(fs, vdev); + if (rc != 0) { + + vdev_error("fskit_fuse_init rc = %d\n", rc); + free(fs); + vdevfs_shutdown(vdev); + return rc; + } + // load ACLs + rc = vdev_acl_load_all(vdev->config->acls_dir, &vdev->acls, + &vdev->num_acls); + if (rc != 0) { + + vdev_error("vdev_acl_load_all('%s') rc = %d\n", + vdev->config->acls_dir, rc); + + fskit_fuse_shutdown(fs, NULL); + free(fs); + vdevfs_shutdown(vdev); + return rc; + } + // make sure the fs can access its methods through the VFS + fskit_fuse_setting_enable(fs, FSKIT_FUSE_SET_FS_ACCESS); + + core = fskit_fuse_get_core(fs); + + // add handlers. + rh = fskit_route_readdir(core, FSKIT_ROUTE_ANY, vdevfs_readdir, + FSKIT_CONCURRENT); + if (rh < 0) { + + vdev_error("fskit_route_readdir(%s) rc = %d\n", FSKIT_ROUTE_ANY, + rh); + goto vdev_route_fail; + } + + rh = fskit_route_stat(core, FSKIT_ROUTE_ANY, vdevfs_stat, + FSKIT_CONCURRENT); + if (rh < 0) { + + vdev_error("fskit_route_stat(%s) rc = %d\n", FSKIT_ROUTE_ANY, + rh); + goto vdev_route_fail; + } + + rh = fskit_route_mknod(core, FSKIT_ROUTE_ANY, vdevfs_mknod, + FSKIT_CONCURRENT); + if (rc < 0) { + + vdev_error("fskit_route_mknod(%s) rc = %d\n", FSKIT_ROUTE_ANY, + rh); + goto vdev_route_fail; + } + + rh = fskit_route_mkdir(core, FSKIT_ROUTE_ANY, vdevfs_mkdir, + FSKIT_CONCURRENT); + if (rh < 0) { + + vdev_error("fskit_route_mkdir(%s) rc = %d\n", FSKIT_ROUTE_ANY, + rh); + goto vdev_route_fail; + } + + rh = fskit_route_create(core, FSKIT_ROUTE_ANY, vdevfs_create, + FSKIT_CONCURRENT); + if (rh < 0) { + + vdev_error("fskit_route_create(%s) rc = %d\n", FSKIT_ROUTE_ANY, + rh); + goto vdev_route_fail; + } + + rh = fskit_route_open(core, FSKIT_ROUTE_ANY, vdevfs_open, + FSKIT_CONCURRENT); + if (rh < 0) { + + vdev_error("fskit_route_open(%s) rc = %d\n", FSKIT_ROUTE_ANY, + rh); + goto vdev_route_fail; + } + + rh = fskit_route_read(core, FSKIT_ROUTE_ANY, vdevfs_read, + FSKIT_CONCURRENT); + if (rh < 0) { + + vdev_error("fskit_route_read(%s) rc = %d\n", FSKIT_ROUTE_ANY, + rh); + goto vdev_route_fail; + } + + rh = fskit_route_write(core, FSKIT_ROUTE_ANY, vdevfs_write, + FSKIT_CONCURRENT); + if (rh < 0) { + + vdev_error("fskit_route_write(%s) rc = %d\n", FSKIT_ROUTE_ANY, + rh); + goto vdev_route_fail; + } + + rh = fskit_route_close(core, FSKIT_ROUTE_ANY, vdevfs_close, + FSKIT_CONCURRENT); + if (rh < 0) { + + vdev_error("fskit_route_close(%s) rc = %d\n", FSKIT_ROUTE_ANY, + rh); + goto vdev_route_fail; + } + + rh = fskit_route_sync(core, FSKIT_ROUTE_ANY, vdevfs_sync, + FSKIT_CONCURRENT); + if (rh < 0) { + + vdev_error("fskit_route_sync(%s) rc = %d\n", FSKIT_ROUTE_ANY, + rh); + goto vdev_route_fail; + } + + rh = fskit_route_detach(core, FSKIT_ROUTE_ANY, vdevfs_detach, + FSKIT_CONCURRENT); + if (rh < 0) { + + vdev_error("fskit_route_detach(%s) rc = %d\n", FSKIT_ROUTE_ANY, + rh); + goto vdev_route_fail; + } + + vdev->fs = fs; + vdev->close_rh = rh; + + // set the root to be owned by the effective UID and GID of user + fskit_chown(core, "/", 0, 0, geteuid(), getegid()); + + // import the underlying filesystem once we're mounted, but before taking requests. + rc = fskit_fuse_postmount_callback(fs, vdevfs_dev_import, vdev); + if (rc != 0) { + + vdev_error("fskit_fuse_postmount_callback() rc = %d\n", rc); + + vdev->fs = NULL; + goto vdev_route_fail; + } + + return 0; + + vdev_route_fail: + + fskit_fuse_shutdown(fs, NULL); + free(fs); + vdevfs_shutdown(vdev); + return rh; } +// main loop for vdev frontend +int vdevfs_main(struct vdevfs *vdev, int fuse_argc, char **fuse_argv) +{ -// shut down the front-end -int vdevfs_shutdown( struct vdevfs* vdev ) { - - if( vdev->fs != NULL ) { - - // stop processing unlink() requests, since the filesystem itself will unlink all files when it frees itself up. - fskit_unroute_detach( fskit_fuse_get_core( vdev->fs ), vdev->close_rh ); - - fskit_fuse_shutdown( vdev->fs, NULL ); - free( vdev->fs ); - vdev->fs = NULL; - } - - if( vdev->acls != NULL ) { - vdev_acl_free_all( vdev->acls, vdev->num_acls ); - } - - if( vdev->config != NULL ) { - vdev_config_free( vdev->config ); - free( vdev->config ); - vdev->config = NULL; - } - - if( vdev->mountpoint != NULL ) { - - free( vdev->mountpoint ); - vdev->mountpoint = NULL; - } - - if( vdev->fuse_argv != NULL ) { - - free( vdev->fuse_argv ); - vdev->fuse_argc = 0; - vdev->fuse_argv = NULL; - } - - if( vdev->mountpoint_dirfd >= 0 ) { - - close( vdev->mountpoint_dirfd ); - vdev->mountpoint_dirfd = -1; - } - - memset( vdev, 0, sizeof(struct vdevfs) ); - - return 0; + int rc = 0; + + rc = fskit_fuse_main(vdev->fs, fuse_argc, fuse_argv); + + return rc; } +// shut down the front-end +int vdevfs_shutdown(struct vdevfs *vdev) +{ + + if (vdev->fs != NULL) { + + // stop processing unlink() requests, since the filesystem itself will unlink all files when it frees itself up. + fskit_unroute_detach(fskit_fuse_get_core(vdev->fs), + vdev->close_rh); + + fskit_fuse_shutdown(vdev->fs, NULL); + free(vdev->fs); + vdev->fs = NULL; + } + + if (vdev->acls != NULL) { + vdev_acl_free_all(vdev->acls, vdev->num_acls); + } + + if (vdev->config != NULL) { + vdev_config_free(vdev->config); + free(vdev->config); + vdev->config = NULL; + } + + if (vdev->mountpoint != NULL) { + + free(vdev->mountpoint); + vdev->mountpoint = NULL; + } + + if (vdev->fuse_argv != NULL) { + + free(vdev->fuse_argv); + vdev->fuse_argc = 0; + vdev->fuse_argv = NULL; + } + + if (vdev->mountpoint_dirfd >= 0) { + + close(vdev->mountpoint_dirfd); + vdev->mountpoint_dirfd = -1; + } + + memset(vdev, 0, sizeof(struct vdevfs)); + + return 0; +} // for creating, opening, or stating files, verify that the caller is permitted according to our ACLs // return 0 on success // return -EPERM if denied // return other -errno on error -static int vdevfs_access_check( struct vdevfs* vdev, struct fskit_fuse_state* fs_state, char const* method_name, char const* path ) { - - int rc = 0; - pid_t pid = 0; - uid_t uid = 0; - gid_t gid = 0; - struct stat sb; - struct pstat* ps = NULL; - - memset( &sb, 0, sizeof(struct stat) ); - sb.st_mode = 0777; - - // stat the calling process - pid = fskit_fuse_get_pid(); - uid = fskit_fuse_get_uid( fs_state ); - gid = fskit_fuse_get_gid( fs_state ); - - ps = pstat_new(); - if( ps == NULL ) { - return -ENOMEM; - } - - vdev_debug("%s('%s') from user %d group %d task %d\n", method_name, path, uid, gid, pid ); - - // see who's asking - rc = pstat( pid, ps, 0 ); - if( rc != 0 ) { - - vdev_error("pstat(%d) rc = %d\n", pid, rc ); - pstat_free( ps ); - return -EIO; - } - - // apply the ACLs on the stat buffer - rc = vdev_acl_apply_all( vdev->config, vdev->acls, vdev->num_acls, path, ps, uid, gid, &sb ); - pstat_free( ps ); - - if( rc < 0 ) { - - vdev_error("vdev_acl_apply_all(%s, uid=%d, gid=%d, pid=%d) rc = %d\n", path, uid, gid, pid, rc ); - return -EIO; - } - - // omit entirely? - if( rc == 0 || (sb.st_mode & 0777) == 0 ) { - - // filter - vdev_debug("DENY '%s'\n", path ); - return -EPERM; - } - else { - - // accept! - return 0; - } +static int vdevfs_access_check(struct vdevfs *vdev, + struct fskit_fuse_state *fs_state, + char const *method_name, char const *path) +{ + + int rc = 0; + pid_t pid = 0; + uid_t uid = 0; + gid_t gid = 0; + struct stat sb; + struct pstat *ps = NULL; + + memset(&sb, 0, sizeof(struct stat)); + sb.st_mode = 0777; + + // stat the calling process + pid = fskit_fuse_get_pid(); + uid = fskit_fuse_get_uid(fs_state); + gid = fskit_fuse_get_gid(fs_state); + + ps = pstat_new(); + if (ps == NULL) { + return -ENOMEM; + } + + vdev_debug("%s('%s') from user %d group %d task %d\n", method_name, + path, uid, gid, pid); + + // see who's asking + rc = pstat(pid, ps, 0); + if (rc != 0) { + + vdev_error("pstat(%d) rc = %d\n", pid, rc); + pstat_free(ps); + return -EIO; + } + // apply the ACLs on the stat buffer + rc = vdev_acl_apply_all(vdev->config, vdev->acls, vdev->num_acls, path, + ps, uid, gid, &sb); + pstat_free(ps); + + if (rc < 0) { + + vdev_error + ("vdev_acl_apply_all(%s, uid=%d, gid=%d, pid=%d) rc = %d\n", + path, uid, gid, pid, rc); + return -EIO; + } + // omit entirely? + if (rc == 0 || (sb.st_mode & 0777) == 0) { + + // filter + vdev_debug("DENY '%s'\n", path); + return -EPERM; + } else { + + // accept! + return 0; + } } - // mknod: create the device node as normal, but also write to the underlying filesystem as an emergency counter-measure -int vdevfs_mknod( struct fskit_core* core, struct fskit_route_metadata* grp, struct fskit_entry* fent, mode_t mode, dev_t dev, void** inode_cls ) { - - int rc = 0; - struct vdevfs* vdev = (struct vdevfs*)fskit_core_get_user_data( core ); - struct fskit_fuse_state* fs_state = fskit_fuse_get_state(); - char const* path = NULL; - - rc = vdevfs_access_check( vdev, fs_state, "mknod", fskit_route_metadata_get_path( grp ) ); - if( rc < 0 ) { - - // denied! - return -EACCES; - } - - // must be relative path - path = fskit_route_metadata_get_path( grp ); - while( *path == '/' && *path != '\0' ) { - path++; - } - - if( *path == '\0' ) { - path = "."; - } - - rc = mknodat( vdev->mountpoint_dirfd, path, dev, mode ); - - if( rc != 0 ) { - - rc = -errno; - vdev_error("mknodat('%s', '%s') rc = %d\n", vdev->mountpoint, path, rc ); - - return rc; - } - - return 0; -} +int vdevfs_mknod(struct fskit_core *core, struct fskit_route_metadata *grp, + struct fskit_entry *fent, mode_t mode, dev_t dev, + void **inode_cls) +{ + int rc = 0; + struct vdevfs *vdev = (struct vdevfs *)fskit_core_get_user_data(core); + struct fskit_fuse_state *fs_state = fskit_fuse_get_state(); + char const *path = NULL; -// mkdir: create the directory as normal, but also write to the underlying filesystem as an emergency counter-measure -int vdevfs_mkdir( struct fskit_core* core, struct fskit_route_metadata* grp, struct fskit_entry* fent, mode_t mode, void** inode_cls ) { - - int rc = 0; - struct vdevfs* vdev = (struct vdevfs*)fskit_core_get_user_data( core ); - struct fskit_fuse_state* fs_state = fskit_fuse_get_state(); - char const* path = NULL; - - rc = vdevfs_access_check( vdev, fs_state, "mkdir", fskit_route_metadata_get_path( grp ) ); - if( rc < 0 ) { - - // denied! - return -EACCES; - } - - // must be relative path - path = fskit_route_metadata_get_path( grp ); - while( *path == '/' && *path != '\0' ) { - path++; - } - - if( *path == '\0' ) { - path = "."; - } - - rc = mkdirat( vdev->mountpoint_dirfd, path, mode ); - - if( rc != 0 ) { - - rc = -errno; - vdev_error("mkdirat('%s', '%s') rc = %d\n", vdev->mountpoint, path, rc ); - - return rc; - } - - return 0; + rc = vdevfs_access_check(vdev, fs_state, "mknod", + fskit_route_metadata_get_path(grp)); + if (rc < 0) { + + // denied! + return -EACCES; + } + // must be relative path + path = fskit_route_metadata_get_path(grp); + while (*path == '/' && *path != '\0') { + path++; + } + + if (*path == '\0') { + path = "."; + } + + rc = mknodat(vdev->mountpoint_dirfd, path, dev, mode); + + if (rc != 0) { + + rc = -errno; + vdev_error("mknodat('%s', '%s') rc = %d\n", vdev->mountpoint, + path, rc); + + return rc; + } + + return 0; } +// mkdir: create the directory as normal, but also write to the underlying filesystem as an emergency counter-measure +int vdevfs_mkdir(struct fskit_core *core, struct fskit_route_metadata *grp, + struct fskit_entry *fent, mode_t mode, void **inode_cls) +{ + + int rc = 0; + struct vdevfs *vdev = (struct vdevfs *)fskit_core_get_user_data(core); + struct fskit_fuse_state *fs_state = fskit_fuse_get_state(); + char const *path = NULL; + + rc = vdevfs_access_check(vdev, fs_state, "mkdir", + fskit_route_metadata_get_path(grp)); + if (rc < 0) { + + // denied! + return -EACCES; + } + // must be relative path + path = fskit_route_metadata_get_path(grp); + while (*path == '/' && *path != '\0') { + path++; + } + + if (*path == '\0') { + path = "."; + } + + rc = mkdirat(vdev->mountpoint_dirfd, path, mode); + + if (rc != 0) { + + rc = -errno; + vdev_error("mkdirat('%s', '%s') rc = %d\n", vdev->mountpoint, + path, rc); + + return rc; + } + + return 0; +} // creat: create the file as usual, but also write to the underlying filesystem as an emergency counter-measure // NOTE: since this is backed by FUSE, this handler will only be called for regular files -int vdevfs_create( struct fskit_core* core, struct fskit_route_metadata* grp, struct fskit_entry* fent, mode_t mode, void** inode_cls, void** handle_cls ) { - - int fd = 0; - struct vdevfs* vdev = (struct vdevfs*)fskit_core_get_user_data( core ); - struct fskit_fuse_state* fs_state = fskit_fuse_get_state(); - char const* path = NULL; - int rc = 0; - - rc = vdevfs_access_check( vdev, fs_state, "create", fskit_route_metadata_get_path( grp ) ); - if( rc < 0 ) { - - // denied! - return -EACCES; - } - - // must be relative path - path = fskit_route_metadata_get_path( grp ); - while( *path == '/' && *path != '\0' ) { - path++; - } - - if( *path == '\0' ) { - path = "."; - } - - // success! - fd = openat( vdev->mountpoint_dirfd, path, O_CREAT | O_WRONLY | O_TRUNC, mode ); - if( fd < 0 ) { - - fd = -errno; - vdev_error("openat('%s', '%s') rc = %d\n", vdev->mountpoint, path, fd ); - - return fd; - } - - // careful... - void* handle_data = NULL; - memcpy( &handle_data, &fd, 4 ); - - *handle_cls = handle_data; - - return 0; -} +int vdevfs_create(struct fskit_core *core, struct fskit_route_metadata *grp, + struct fskit_entry *fent, mode_t mode, void **inode_cls, + void **handle_cls) +{ + + int fd = 0; + struct vdevfs *vdev = (struct vdevfs *)fskit_core_get_user_data(core); + struct fskit_fuse_state *fs_state = fskit_fuse_get_state(); + char const *path = NULL; + int rc = 0; + + rc = vdevfs_access_check(vdev, fs_state, "create", + fskit_route_metadata_get_path(grp)); + if (rc < 0) { + + // denied! + return -EACCES; + } + // must be relative path + path = fskit_route_metadata_get_path(grp); + while (*path == '/' && *path != '\0') { + path++; + } + + if (*path == '\0') { + path = "."; + } + // success! + fd = openat(vdev->mountpoint_dirfd, path, O_CREAT | O_WRONLY | O_TRUNC, + mode); + if (fd < 0) { + + fd = -errno; + vdev_error("openat('%s', '%s') rc = %d\n", vdev->mountpoint, + path, fd); + + return fd; + } + // careful... + void *handle_data = NULL; + memcpy(&handle_data, &fd, 4); + + *handle_cls = handle_data; + return 0; +} // open: open the file as usual, but from the underlying filesystem // NOTE: since this is backed by FUSE, this handler will only be called for regular files -int vdevfs_open( struct fskit_core* core, struct fskit_route_metadata* grp, struct fskit_entry* fent, int flags, void** handle_cls ) { - - int fd = 0; - struct vdevfs* vdev = (struct vdevfs*)fskit_core_get_user_data( core ); - struct fskit_fuse_state* fs_state = fskit_fuse_get_state(); - char const* path = NULL; - - int rc = 0; - - // dir or file? - char const* method = NULL; - - if( fskit_entry_get_type( fent ) == FSKIT_ENTRY_TYPE_DIR ) { - - rc = vdevfs_access_check( vdev, fs_state, "opendir", fskit_route_metadata_get_path( grp ) ); - } - else { - - rc = vdevfs_access_check( vdev, fs_state, "open", fskit_route_metadata_get_path( grp ) ); - } - - if( rc < 0 ) { - - // denied! - return -ENOENT; - } - - // only care about open() for files - if( fskit_entry_get_type( fent ) == FSKIT_ENTRY_TYPE_DIR ) { - - // done! - return 0; - } - - // must be relative path - path = fskit_route_metadata_get_path( grp ); - while( *path == '/' && *path != '\0' ) { - path++; - } - - if( *path == '\0' ) { - path = "."; - } - - fd = openat( vdev->mountpoint_dirfd, path, flags ); - if( fd < 0 ) { - - fd = -errno; - vdev_error("openat(%d, '%s') rc = %d\n", vdev->mountpoint_dirfd, path, fd ); - - return fd; - } - - // careful... - void* handle_data = NULL; - memcpy( &handle_data, &fd, 4 ); - - *handle_cls = handle_data; - - return 0; -} +int vdevfs_open(struct fskit_core *core, struct fskit_route_metadata *grp, + struct fskit_entry *fent, int flags, void **handle_cls) +{ + + int fd = 0; + struct vdevfs *vdev = (struct vdevfs *)fskit_core_get_user_data(core); + struct fskit_fuse_state *fs_state = fskit_fuse_get_state(); + char const *path = NULL; + + int rc = 0; + + // dir or file? + char const *method = NULL; + + if (fskit_entry_get_type(fent) == FSKIT_ENTRY_TYPE_DIR) { + + rc = vdevfs_access_check(vdev, fs_state, "opendir", + fskit_route_metadata_get_path(grp)); + } else { + + rc = vdevfs_access_check(vdev, fs_state, "open", + fskit_route_metadata_get_path(grp)); + } + + if (rc < 0) { + + // denied! + return -ENOENT; + } + // only care about open() for files + if (fskit_entry_get_type(fent) == FSKIT_ENTRY_TYPE_DIR) { + // done! + return 0; + } + // must be relative path + path = fskit_route_metadata_get_path(grp); + while (*path == '/' && *path != '\0') { + path++; + } + + if (*path == '\0') { + path = "."; + } + + fd = openat(vdev->mountpoint_dirfd, path, flags); + if (fd < 0) { + + fd = -errno; + vdev_error("openat(%d, '%s') rc = %d\n", vdev->mountpoint_dirfd, + path, fd); + + return fd; + } + // careful... + void *handle_data = NULL; + memcpy(&handle_data, &fd, 4); + + *handle_cls = handle_data; + + return 0; +} // read: read as usual, but from the underlying filesystem // NOTE: since this is backed by FUSE, this handler will only be called for regular files -int vdevfs_read( struct fskit_core* core, struct fskit_route_metadata* grp, struct fskit_entry* fent, char* buf, size_t len, off_t offset, void* handle_cls ) { - - // careful... - int fd = 0; - memcpy( &fd, &handle_cls, 4 ); - - int rc = 0; - struct vdevfs* vdev = (struct vdevfs*)fskit_core_get_user_data( core ); - - rc = lseek( fd, offset, SEEK_SET ); - if( rc < 0 ) { - - rc = -errno; - vdev_error("lseek(%d '%s') rc = %d\n", fd, fskit_route_metadata_get_path( grp ), rc ); - - return rc; - } - - rc = read( fd, buf, len ); - if( rc < 0 ) { - - rc = -errno; - vdev_error("read(%d '%s') rc = %d\n", fd, fskit_route_metadata_get_path( grp ), rc ); - - return rc; - } - - return rc; -} +int vdevfs_read(struct fskit_core *core, struct fskit_route_metadata *grp, + struct fskit_entry *fent, char *buf, size_t len, off_t offset, + void *handle_cls) +{ + + // careful... + int fd = 0; + memcpy(&fd, &handle_cls, 4); + int rc = 0; + struct vdevfs *vdev = (struct vdevfs *)fskit_core_get_user_data(core); + + rc = lseek(fd, offset, SEEK_SET); + if (rc < 0) { + + rc = -errno; + vdev_error("lseek(%d '%s') rc = %d\n", fd, + fskit_route_metadata_get_path(grp), rc); + + return rc; + } + + rc = read(fd, buf, len); + if (rc < 0) { + + rc = -errno; + vdev_error("read(%d '%s') rc = %d\n", fd, + fskit_route_metadata_get_path(grp), rc); + + return rc; + } + + return rc; +} // write; write as usual, but to the underlying filesystem // NOTE: since this is backed by FUSE, this handler will only be called for regular files -int vdevfs_write( struct fskit_core* core, struct fskit_route_metadata* grp, struct fskit_entry* fent, char* buf, size_t len, off_t offset, void* handle_cls ) { - - // careful... - int fd = 0; - memcpy( &fd, &handle_cls, 4 ); - - - int rc = 0; - struct vdevfs* vdev = (struct vdevfs*)fskit_core_get_user_data( core ); - - rc = lseek( fd, offset, SEEK_SET ); - if( rc < 0 ) { - - rc = -errno; - vdev_error("lseek(%d '%s') rc = %d\n", fd, fskit_route_metadata_get_path( grp ), rc ); - - return rc; - } - - rc = write( fd, buf, len ); - if( rc < 0 ) { - - rc = -errno; - vdev_error("write(%d '%s') rc = %d\n", fd, fskit_route_metadata_get_path( grp ), rc ); - - return rc; - } - - return rc; -} +int vdevfs_write(struct fskit_core *core, struct fskit_route_metadata *grp, + struct fskit_entry *fent, char *buf, size_t len, off_t offset, + void *handle_cls) +{ + + // careful... + int fd = 0; + memcpy(&fd, &handle_cls, 4); + int rc = 0; + struct vdevfs *vdev = (struct vdevfs *)fskit_core_get_user_data(core); + + rc = lseek(fd, offset, SEEK_SET); + if (rc < 0) { + + rc = -errno; + vdev_error("lseek(%d '%s') rc = %d\n", fd, + fskit_route_metadata_get_path(grp), rc); + + return rc; + } + + rc = write(fd, buf, len); + if (rc < 0) { + + rc = -errno; + vdev_error("write(%d '%s') rc = %d\n", fd, + fskit_route_metadata_get_path(grp), rc); + + return rc; + } + + return rc; +} // close: close as usual // NOTE: since this is backed by FUSE, this handler will only be called for regular files -int vdevfs_close( struct fskit_core* core, struct fskit_route_metadata* grp, struct fskit_entry* fent, void* handle_cls ) { - - // only care about close() for files - if( fskit_entry_get_type( fent ) == FSKIT_ENTRY_TYPE_DIR ) { - - // done! - return 0; - } - - // careful... - int fd = 0; - memcpy( &fd, &handle_cls, 4 ); - - int rc = 0; - - rc = close( fd ); - if( rc < 0 ) { - - rc = -errno; - vdev_error("close(%d '%s') rc = %d\n", fd, fskit_route_metadata_get_path( grp ), rc ); - - return rc; - } - - return rc; -} +int vdevfs_close(struct fskit_core *core, struct fskit_route_metadata *grp, + struct fskit_entry *fent, void *handle_cls) +{ + + // only care about close() for files + if (fskit_entry_get_type(fent) == FSKIT_ENTRY_TYPE_DIR) { + // done! + return 0; + } + // careful... + int fd = 0; + memcpy(&fd, &handle_cls, 4); + + int rc = 0; + + rc = close(fd); + if (rc < 0) { + + rc = -errno; + vdev_error("close(%d '%s') rc = %d\n", fd, + fskit_route_metadata_get_path(grp), rc); + + return rc; + } + + return rc; +} // sync: sync as usual // NOTE: since this is backed by FUSE, this handler will only be called for regular files -int vdevfs_sync( struct fskit_core* core, struct fskit_route_metadata* grp, struct fskit_entry* fent ) { - - void* user_data = fskit_entry_get_user_data( fent ); - - // careful... - int fd = 0; - memcpy( &fd, &user_data, 4 ); - - int rc = 0; - - rc = fsync( fd ); - if( rc < 0 ) { - - rc = -errno; - vdev_error("fsync(%d '%s') rc = %d\n", fd, fskit_route_metadata_get_path( grp ), rc ); - - return rc; - } - - return rc; -} +int vdevfs_sync(struct fskit_core *core, struct fskit_route_metadata *grp, + struct fskit_entry *fent) +{ + void *user_data = fskit_entry_get_user_data(fent); -// unlink/rmdir: remove the file or device node from the underlying filesystem -int vdevfs_detach( struct fskit_core* core, struct fskit_route_metadata* grp, struct fskit_entry* fent, void* inode_cls ) { - - int rc = 0; - struct vdevfs* vdev = (struct vdevfs*)fskit_core_get_user_data( core ); - struct fskit_fuse_state* fs_state = fskit_fuse_get_state(); - char const* method = NULL; - - if( fskit_entry_get_type( fent ) == FSKIT_ENTRY_TYPE_DIR ) { - - method = "rmdir"; - } - else { - - method = "unlink"; - } - - - rc = vdevfs_access_check( vdev, fs_state, method, fskit_route_metadata_get_path( grp ) ); - if( rc < 0 ) { - - // denied! - return -ENOENT; - } - - if( rc != 0 ) { - - rc = -errno; - vdev_error("%s('%s', '%s') rc = %d\n", method, vdev->mountpoint, fskit_route_metadata_get_path( grp ), rc ); - - return rc; - } - - return 0; + // careful... + int fd = 0; + memcpy(&fd, &user_data, 4); + + int rc = 0; + + rc = fsync(fd); + if (rc < 0) { + + rc = -errno; + vdev_error("fsync(%d '%s') rc = %d\n", fd, + fskit_route_metadata_get_path(grp), rc); + + return rc; + } + + return rc; } +// unlink/rmdir: remove the file or device node from the underlying filesystem +int vdevfs_detach(struct fskit_core *core, struct fskit_route_metadata *grp, + struct fskit_entry *fent, void *inode_cls) +{ + + int rc = 0; + struct vdevfs *vdev = (struct vdevfs *)fskit_core_get_user_data(core); + struct fskit_fuse_state *fs_state = fskit_fuse_get_state(); + char const *method = NULL; + + if (fskit_entry_get_type(fent) == FSKIT_ENTRY_TYPE_DIR) { + + method = "rmdir"; + } else { + + method = "unlink"; + } + + rc = vdevfs_access_check(vdev, fs_state, method, + fskit_route_metadata_get_path(grp)); + if (rc < 0) { + + // denied! + return -ENOENT; + } + + if (rc != 0) { + + rc = -errno; + vdev_error("%s('%s', '%s') rc = %d\n", method, vdev->mountpoint, + fskit_route_metadata_get_path(grp), rc); + + return rc; + } + + return 0; +} // stat: equvocate about which devices exist, depending on who's asking // return -ENOENT not only if the file doesn't exist, but also if the file is blocked by the ACL -int vdevfs_stat( struct fskit_core* core, struct fskit_route_metadata* grp, struct fskit_entry* fent, struct stat* sb ) { - - int rc = 0; - struct vdevfs* vdev = (struct vdevfs*)fskit_core_get_user_data( core ); - struct fskit_fuse_state* fs_state = fskit_fuse_get_state(); - - if( fent == NULL ) { - return -ENOENT; - } - - rc = vdevfs_access_check( vdev, fs_state, "stat", fskit_route_metadata_get_path( grp ) ); - if( rc < 0 ) { - - // denied! - return -ENOENT; - } - else { - - return 0; - } +int vdevfs_stat(struct fskit_core *core, struct fskit_route_metadata *grp, + struct fskit_entry *fent, struct stat *sb) +{ + + int rc = 0; + struct vdevfs *vdev = (struct vdevfs *)fskit_core_get_user_data(core); + struct fskit_fuse_state *fs_state = fskit_fuse_get_state(); + + if (fent == NULL) { + return -ENOENT; + } + + rc = vdevfs_access_check(vdev, fs_state, "stat", + fskit_route_metadata_get_path(grp)); + if (rc < 0) { + + // denied! + return -ENOENT; + } else { + + return 0; + } } // readdir: equivocate about which devices exist, depending on who's asking // omit entries if the ACLs forbid them -int vdevfs_readdir( struct fskit_core* core, struct fskit_route_metadata* grp, struct fskit_entry* fent, struct fskit_dir_entry** dirents, size_t num_dirents ) { - - int rc = 0; - struct fskit_entry* child = NULL; - - // entries to omit in the listing - unsigned int omitted_idx = 0; - int* omitted = VDEV_CALLOC( int, num_dirents ); - if( omitted == NULL ) { - return -ENOMEM; - } - - pid_t pid = 0; - uid_t uid = 0; - gid_t gid = 0; - - struct vdevfs* vdev = (struct vdevfs*)fskit_core_get_user_data( core ); - struct fskit_fuse_state* fs_state = fskit_fuse_get_state(); - - struct stat sb; - struct stat fskit_sb; - struct pstat* ps = NULL; - char* child_path = NULL; - - pid = fskit_fuse_get_pid(); - uid = fskit_fuse_get_uid( fs_state ); - gid = fskit_fuse_get_gid( fs_state ); - - vdev_debug("vdevfs_readdir(%s, %zu) from user %d group %d task %d\n", fskit_route_metadata_get_path( grp ), num_dirents, uid, gid, pid ); - - ps = pstat_new(); - if( ps == NULL ) { - free( omitted ); - return -ENOMEM; - } - - // see who's asking - rc = pstat( pid, ps, 0 ); - if( rc != 0 ) { - - vdev_error("pstat(%d) rc = %d\n", pid, rc ); - pstat_free( ps ); - free( omitted ); - return -EIO; - } - - for( unsigned int i = 0; i < num_dirents; i++ ) { - - // skip . and .. - if( strcmp(dirents[i]->name, ".") == 0 || strcmp(dirents[i]->name, "..") == 0 ) { - continue; - } - - // find the associated fskit_entry - child = fskit_dir_find_by_name( fent, dirents[i]->name ); - - if( child == NULL ) { - // strange, shouldn't happen... - continue; - } - - fskit_entry_rlock( child ); - - // construct a stat buffer from what we actually need - memset( &sb, 0, sizeof(struct stat) ); - - fskit_entry_fstat( child, &fskit_sb ); - sb.st_uid = fskit_sb.st_uid; - sb.st_gid = fskit_sb.st_gid; - sb.st_mode = fskit_sb.st_mode; - - child_path = fskit_fullpath( fskit_route_metadata_get_path( grp ), fskit_route_metadata_get_name( grp ), NULL ); - if( child_path == NULL ) { - - // can't continue; OOM - fskit_entry_unlock( child ); - rc = -ENOMEM; - break; - } - - // filter it - rc = vdev_acl_apply_all( vdev->config, vdev->acls, vdev->num_acls, child_path, ps, uid, gid, &sb ); - if( rc < 0 ) { - - vdev_error("vdev_acl_apply_all('%s', uid=%d, gid=%d, pid=%d) rc = %d\n", child_path, uid, gid, pid, rc ); - rc = -EIO; - } - else if( rc == 0 || (sb.st_mode & 0777) == 0 ) { - - // omit this one - vdev_debug("Filter '%s'\n", fskit_route_metadata_get_name( grp ) ); - omitted[ omitted_idx ] = i; - omitted_idx++; - - rc = 0; - } - else { - - // success; matched - rc = 0; - } - - fskit_entry_unlock( child ); - - free( child_path ); - - // error? - if( rc != 0 ) { - break; - } - } - - // skip ACL'ed entries - for( unsigned int i = 0; i < omitted_idx; i++ ) { - - fskit_readdir_omit( dirents, omitted[i] ); - } - - pstat_free( ps ); - free( omitted ); - return rc; +int vdevfs_readdir(struct fskit_core *core, struct fskit_route_metadata *grp, + struct fskit_entry *fent, struct fskit_dir_entry **dirents, + size_t num_dirents) +{ + + int rc = 0; + struct fskit_entry *child = NULL; + + // entries to omit in the listing + unsigned int omitted_idx = 0; + int *omitted = VDEV_CALLOC(int, num_dirents); + if (omitted == NULL) { + return -ENOMEM; + } + + pid_t pid = 0; + uid_t uid = 0; + gid_t gid = 0; + + struct vdevfs *vdev = (struct vdevfs *)fskit_core_get_user_data(core); + struct fskit_fuse_state *fs_state = fskit_fuse_get_state(); + + struct stat sb; + struct stat fskit_sb; + struct pstat *ps = NULL; + char *child_path = NULL; + + pid = fskit_fuse_get_pid(); + uid = fskit_fuse_get_uid(fs_state); + gid = fskit_fuse_get_gid(fs_state); + + vdev_debug("vdevfs_readdir(%s, %zu) from user %d group %d task %d\n", + fskit_route_metadata_get_path(grp), num_dirents, uid, gid, + pid); + + ps = pstat_new(); + if (ps == NULL) { + free(omitted); + return -ENOMEM; + } + // see who's asking + rc = pstat(pid, ps, 0); + if (rc != 0) { + + vdev_error("pstat(%d) rc = %d\n", pid, rc); + pstat_free(ps); + free(omitted); + return -EIO; + } + + for (unsigned int i = 0; i < num_dirents; i++) { + + // skip . and .. + if (strcmp(dirents[i]->name, ".") == 0 + || strcmp(dirents[i]->name, "..") == 0) { + continue; + } + // find the associated fskit_entry + child = fskit_dir_find_by_name(fent, dirents[i]->name); + + if (child == NULL) { + // strange, shouldn't happen... + continue; + } + + fskit_entry_rlock(child); + + // construct a stat buffer from what we actually need + memset(&sb, 0, sizeof(struct stat)); + + fskit_entry_fstat(child, &fskit_sb); + sb.st_uid = fskit_sb.st_uid; + sb.st_gid = fskit_sb.st_gid; + sb.st_mode = fskit_sb.st_mode; + + child_path = + fskit_fullpath(fskit_route_metadata_get_path(grp), + fskit_route_metadata_get_name(grp), NULL); + if (child_path == NULL) { + + // can't continue; OOM + fskit_entry_unlock(child); + rc = -ENOMEM; + break; + } + // filter it + rc = vdev_acl_apply_all(vdev->config, vdev->acls, + vdev->num_acls, child_path, ps, uid, + gid, &sb); + if (rc < 0) { + + vdev_error + ("vdev_acl_apply_all('%s', uid=%d, gid=%d, pid=%d) rc = %d\n", + child_path, uid, gid, pid, rc); + rc = -EIO; + } else if (rc == 0 || (sb.st_mode & 0777) == 0) { + + // omit this one + vdev_debug("Filter '%s'\n", + fskit_route_metadata_get_name(grp)); + omitted[omitted_idx] = i; + omitted_idx++; + + rc = 0; + } else { + + // success; matched + rc = 0; + } + + fskit_entry_unlock(child); + + free(child_path); + + // error? + if (rc != 0) { + break; + } + } + + // skip ACL'ed entries + for (unsigned int i = 0; i < omitted_idx; i++) { + + fskit_readdir_omit(dirents, omitted[i]); + } + + pstat_free(ps); + free(omitted); + return rc; } diff --git a/fs/fs.h b/fs/fs.h index 022aab1..99ec8e1 100644 --- a/fs/fs.h +++ b/fs/fs.h @@ -32,56 +32,68 @@ #include "libvdev/util.h" #include "libvdev/config.h" - struct vdevfs { - - // configuration - struct vdev_config* config; - - // arguments - int argc; - char** argv; - - // FUSE-filtered arguments - int fuse_argc; - char** fuse_argv; - - // mountpoint; where /dev is - char* mountpoint; - - // mountpoint dir handle, underneath /dev - int mountpoint_dirfd; - - // fskit core - struct fskit_fuse_state* fs; - - // acls - struct vdev_acl* acls; - size_t num_acls; - - // close route handler id - int close_rh; -}; + // configuration + struct vdev_config *config; + + // arguments + int argc; + char **argv; + + // FUSE-filtered arguments + int fuse_argc; + char **fuse_argv; + + // mountpoint; where /dev is + char *mountpoint; + + // mountpoint dir handle, underneath /dev + int mountpoint_dirfd; + + // fskit core + struct fskit_fuse_state *fs; + + // acls + struct vdev_acl *acls; + size_t num_acls; + + // close route handler id + int close_rh; +}; C_LINKAGE_BEGIN - -int vdevfs_mkdir( struct fskit_core* core, struct fskit_route_metadata* grp, struct fskit_entry* fent, mode_t mode, void** inode_cls ); -int vdevfs_mknod( struct fskit_core* core, struct fskit_route_metadata* grp, struct fskit_entry* fent, mode_t mode, dev_t dev, void** inode_cls ); -int vdevfs_create( struct fskit_core* core, struct fskit_route_metadata* grp, struct fskit_entry* fent, mode_t mode, void** inode_cls, void** handle_cls ); -int vdevfs_open( struct fskit_core* core, struct fskit_route_metadata* grp, struct fskit_entry* fent, int flags, void** handle_cls ); -int vdevfs_read( struct fskit_core* core, struct fskit_route_metadata* grp, struct fskit_entry* fent, char* buf, size_t len, off_t offset, void* handle_cls ); -int vdevfs_write( struct fskit_core* core, struct fskit_route_metadata* grp, struct fskit_entry* fent, char* buf, size_t len, off_t offset, void* handle_cls ); -int vdevfs_close( struct fskit_core* core, struct fskit_route_metadata* grp, struct fskit_entry* fent, void* handle_cls ); -int vdevfs_sync( struct fskit_core* core, struct fskit_route_metadata* grp, struct fskit_entry* fent ); -int vdevfs_detach( struct fskit_core* core, struct fskit_route_metadata* grp, struct fskit_entry* fent, void* inode_cls ); -int vdevfs_stat( struct fskit_core* core, struct fskit_route_metadata* grp, struct fskit_entry* fent, struct stat* sb ); -int vdevfs_readdir( struct fskit_core* core, struct fskit_route_metadata* grp, struct fskit_entry* fent, struct fskit_dir_entry** dirents, size_t num_dirents ); - -int vdevfs_init( struct vdevfs* vdev, int argc, char** argv ); -int vdevfs_main( struct vdevfs* vdev, int fuse_argc, char** fuse_argv ); -int vdevfs_shutdown( struct vdevfs* vdev ); + int vdevfs_mkdir(struct fskit_core *core, struct fskit_route_metadata *grp, + struct fskit_entry *fent, mode_t mode, void **inode_cls); +int vdevfs_mknod(struct fskit_core *core, struct fskit_route_metadata *grp, + struct fskit_entry *fent, mode_t mode, dev_t dev, + void **inode_cls); +int vdevfs_create(struct fskit_core *core, struct fskit_route_metadata *grp, + struct fskit_entry *fent, mode_t mode, void **inode_cls, + void **handle_cls); +int vdevfs_open(struct fskit_core *core, struct fskit_route_metadata *grp, + struct fskit_entry *fent, int flags, void **handle_cls); +int vdevfs_read(struct fskit_core *core, struct fskit_route_metadata *grp, + struct fskit_entry *fent, char *buf, size_t len, off_t offset, + void *handle_cls); +int vdevfs_write(struct fskit_core *core, struct fskit_route_metadata *grp, + struct fskit_entry *fent, char *buf, size_t len, off_t offset, + void *handle_cls); +int vdevfs_close(struct fskit_core *core, struct fskit_route_metadata *grp, + struct fskit_entry *fent, void *handle_cls); +int vdevfs_sync(struct fskit_core *core, struct fskit_route_metadata *grp, + struct fskit_entry *fent); +int vdevfs_detach(struct fskit_core *core, struct fskit_route_metadata *grp, + struct fskit_entry *fent, void *inode_cls); +int vdevfs_stat(struct fskit_core *core, struct fskit_route_metadata *grp, + struct fskit_entry *fent, struct stat *sb); +int vdevfs_readdir(struct fskit_core *core, struct fskit_route_metadata *grp, + struct fskit_entry *fent, struct fskit_dir_entry **dirents, + size_t num_dirents); -C_LINKAGE_END +int vdevfs_init(struct vdevfs *vdev, int argc, char **argv); +int vdevfs_main(struct vdevfs *vdev, int fuse_argc, char **fuse_argv); +int vdevfs_shutdown(struct vdevfs *vdev); -#endif // _VDEV_FS_H_ +C_LINKAGE_END +#endif // _VDEV_FS_H_ diff --git a/fs/main.c b/fs/main.c index d805556..db0b6b2 100644 --- a/fs/main.c +++ b/fs/main.c @@ -22,28 +22,27 @@ #include "main.h" // run! -int main( int argc, char** argv ) { - - int rc = 0; - pid_t pid = 0; - struct vdevfs vdev; - - memset( &vdev, 0, sizeof(struct vdevfs) ); - - // set up global vdev state - rc = vdevfs_init( &vdev, argc, argv ); - if( rc != 0 ) { - - vdev_error("vdevfs_init rc = %d\n", rc ); - - exit(1); - } - - // run! - rc = vdevfs_main( &vdev, vdev.fuse_argc, vdev.fuse_argv ); - - vdevfs_shutdown( &vdev ); - - return rc; -} +int main(int argc, char **argv) +{ + + int rc = 0; + pid_t pid = 0; + struct vdevfs vdev; + + memset(&vdev, 0, sizeof(struct vdevfs)); + + // set up global vdev state + rc = vdevfs_init(&vdev, argc, argv); + if (rc != 0) { + vdev_error("vdevfs_init rc = %d\n", rc); + + exit(1); + } + // run! + rc = vdevfs_main(&vdev, vdev.fuse_argc, vdev.fuse_argv); + + vdevfs_shutdown(&vdev); + + return rc; +} diff --git a/libudev-compat/MurmurHash2.c b/libudev-compat/MurmurHash2.c index 35f0949..1d1974e 100644 --- a/libudev-compat/MurmurHash2.c +++ b/libudev-compat/MurmurHash2.c @@ -35,61 +35,62 @@ // Other compilers -#else // defined(_MSC_VER) +#else // defined(_MSC_VER) #define BIG_CONSTANT(x) (x##LLU) -#endif // !defined(_MSC_VER) +#endif // !defined(_MSC_VER) //----------------------------------------------------------------------------- -uint32_t MurmurHash2 ( const void * key, int len, uint32_t seed ) +uint32_t MurmurHash2(const void *key, int len, uint32_t seed) { - // 'm' and 'r' are mixing constants generated offline. - // They're not really 'magic', they just happen to work well. + // 'm' and 'r' are mixing constants generated offline. + // They're not really 'magic', they just happen to work well. - const uint32_t m = 0x5bd1e995; - const int r = 24; + const uint32_t m = 0x5bd1e995; + const int r = 24; - // Initialize the hash to a 'random' value + // Initialize the hash to a 'random' value - uint32_t h = seed ^ len; + uint32_t h = seed ^ len; - // Mix 4 bytes at a time into the hash + // Mix 4 bytes at a time into the hash - const unsigned char * data = (const unsigned char *)key; + const unsigned char *data = (const unsigned char *)key; - while(len >= 4) - { - uint32_t k = *(uint32_t*)data; + while (len >= 4) { + uint32_t k = *(uint32_t *) data; - k *= m; - k ^= k >> r; - k *= m; + k *= m; + k ^= k >> r; + k *= m; - h *= m; - h ^= k; + h *= m; + h ^= k; - data += 4; - len -= 4; - } + data += 4; + len -= 4; + } - // Handle the last few bytes of the input array + // Handle the last few bytes of the input array - switch(len) - { - case 3: h ^= data[2] << 16; - case 2: h ^= data[1] << 8; - case 1: h ^= data[0]; - h *= m; - }; + switch (len) { + case 3: + h ^= data[2] << 16; + case 2: + h ^= data[1] << 8; + case 1: + h ^= data[0]; + h *= m; + }; - // Do a few final mixes of the hash to ensure the last few - // bytes are well-incorporated. + // Do a few final mixes of the hash to ensure the last few + // bytes are well-incorporated. - h ^= h >> 13; - h *= m; - h ^= h >> 15; + h ^= h >> 13; + h *= m; + h ^= h >> 15; - return h; + return h; } diff --git a/libudev-compat/MurmurHash2.h b/libudev-compat/MurmurHash2.h index d4f4cf1..fb94f42 100644 --- a/libudev-compat/MurmurHash2.h +++ b/libudev-compat/MurmurHash2.h @@ -27,16 +27,16 @@ typedef unsigned __int64 uint64_t; // Other compilers -#else // defined(_MSC_VER) +#else // defined(_MSC_VER) #include -#endif // !defined(_MSC_VER) +#endif // !defined(_MSC_VER) //----------------------------------------------------------------------------- -uint32_t MurmurHash2 ( const void * key, int len, uint32_t seed ); +uint32_t MurmurHash2(const void *key, int len, uint32_t seed); //----------------------------------------------------------------------------- -#endif // _MURMURHASH2_H_ +#endif // _MURMURHASH2_H_ diff --git a/libudev-compat/device-nodes.c b/libudev-compat/device-nodes.c index ce76c26..611fbbb 100644 --- a/libudev-compat/device-nodes.c +++ b/libudev-compat/device-nodes.c @@ -34,48 +34,51 @@ #include "device-nodes.h" #include "utf8.h" -int whitelisted_char_for_devnode(char c, const char *white) { - if ((c >= '0' && c <= '9') || - (c >= 'A' && c <= 'Z') || - (c >= 'a' && c <= 'z') || - strchr("#+-.:=@_", c) != NULL || - (white != NULL && strchr(white, c) != NULL)) - return 1; - return 0; +int whitelisted_char_for_devnode(char c, const char *white) +{ + if ((c >= '0' && c <= '9') || + (c >= 'A' && c <= 'Z') || + (c >= 'a' && c <= 'z') || + strchr("#+-.:=@_", c) != NULL || + (white != NULL && strchr(white, c) != NULL)) + return 1; + return 0; } -int encode_devnode_name(const char *str, char *str_enc, size_t len) { - size_t i, j; +int encode_devnode_name(const char *str, char *str_enc, size_t len) +{ + size_t i, j; - if (str == NULL || str_enc == NULL) - return -EINVAL; + if (str == NULL || str_enc == NULL) + return -EINVAL; - for (i = 0, j = 0; str[i] != '\0'; i++) { - int seqlen; + for (i = 0, j = 0; str[i] != '\0'; i++) { + int seqlen; - seqlen = utf8_encoded_valid_unichar(&str[i]); - if (seqlen > 1) { - if (len-j < (size_t)seqlen) - goto err; - memcpy(&str_enc[j], &str[i], seqlen); - j += seqlen; - i += (seqlen-1); - } else if (str[i] == '\\' || !whitelisted_char_for_devnode(str[i], NULL)) { - if (len-j < 4) - goto err; - sprintf(&str_enc[j], "\\x%02x", (unsigned char) str[i]); - j += 4; - } else { - if (len-j < 1) - goto err; - str_enc[j] = str[i]; - j++; - } - } - if (len-j < 1) - goto err; - str_enc[j] = '\0'; - return 0; -err: - return -EINVAL; + seqlen = utf8_encoded_valid_unichar(&str[i]); + if (seqlen > 1) { + if (len - j < (size_t) seqlen) + goto err; + memcpy(&str_enc[j], &str[i], seqlen); + j += seqlen; + i += (seqlen - 1); + } else if (str[i] == '\\' + || !whitelisted_char_for_devnode(str[i], NULL)) { + if (len - j < 4) + goto err; + sprintf(&str_enc[j], "\\x%02x", (unsigned char)str[i]); + j += 4; + } else { + if (len - j < 1) + goto err; + str_enc[j] = str[i]; + j++; + } + } + if (len - j < 1) + goto err; + str_enc[j] = '\0'; + return 0; + err: + return -EINVAL; } diff --git a/libudev-compat/device-nodes.h b/libudev-compat/device-nodes.h index 93d4904..0224796 100644 --- a/libudev-compat/device-nodes.h +++ b/libudev-compat/device-nodes.h @@ -32,4 +32,4 @@ int encode_devnode_name(const char *str, char *str_enc, size_t len); int whitelisted_char_for_devnode(char c, const char *additional); -#endif \ No newline at end of file +#endif diff --git a/libudev-compat/hashmap.c b/libudev-compat/hashmap.c index aa782fa..e8a0715 100644 --- a/libudev-compat/hashmap.c +++ b/libudev-compat/hashmap.c @@ -95,27 +95,26 @@ /* Fields common to entries of all hashmap/set types */ struct hashmap_base_entry { - const void *key; + const void *key; }; /* Entry types for specific hashmap/set types * hashmap_base_entry must be at the beginning of each entry struct. */ struct plain_hashmap_entry { - struct hashmap_base_entry b; - void *value; + struct hashmap_base_entry b; + void *value; }; struct ordered_hashmap_entry { - struct plain_hashmap_entry p; - unsigned iterate_next, iterate_previous; + struct plain_hashmap_entry p; + unsigned iterate_next, iterate_previous; }; struct set_entry { - struct hashmap_base_entry b; + struct hashmap_base_entry b; }; - /* In several functions it is advantageous to have the hash table extended * virtually by a couple of additional buckets. We reserve special index values * for these "swap" buckets. */ @@ -125,10 +124,10 @@ struct set_entry { #define _IDX_SWAP_END (_IDX_SWAP_BEGIN + 2) /* special index for freshly initialized iterators */ -#define IDX_FIRST (UINT_MAX - 1) +#define IDX_FIRST (UINT_MAX - 1) /* special index value meaning "none" or "end" */ -#define IDX_NIL UINT_MAX +#define IDX_NIL UINT_MAX assert_cc(IDX_FIRST == _IDX_SWAP_END); assert_cc(IDX_FIRST == _IDX_ITERATOR_FIRST); @@ -136,32 +135,32 @@ assert_cc(IDX_FIRST == _IDX_ITERATOR_FIRST); /* Storage space for the "swap" buckets. * All entry types can fit into a ordered_hashmap_entry. */ struct swap_entries { - struct ordered_hashmap_entry e[_IDX_SWAP_END - _IDX_SWAP_BEGIN]; + struct ordered_hashmap_entry e[_IDX_SWAP_END - _IDX_SWAP_BEGIN]; }; /* Distance from Initial Bucket */ typedef uint8_t dib_raw_t; -#define DIB_RAW_OVERFLOW ((dib_raw_t)0xfdU) /* indicates DIB value is greater than representable */ -#define DIB_RAW_REHASH ((dib_raw_t)0xfeU) /* entry yet to be rehashed during in-place resize */ -#define DIB_RAW_FREE ((dib_raw_t)0xffU) /* a free bucket */ -#define DIB_RAW_INIT ((char)DIB_RAW_FREE) /* a byte to memset a DIB store with when initializing */ +#define DIB_RAW_OVERFLOW ((dib_raw_t)0xfdU) /* indicates DIB value is greater than representable */ +#define DIB_RAW_REHASH ((dib_raw_t)0xfeU) /* entry yet to be rehashed during in-place resize */ +#define DIB_RAW_FREE ((dib_raw_t)0xffU) /* a free bucket */ +#define DIB_RAW_INIT ((char)DIB_RAW_FREE) /* a byte to memset a DIB store with when initializing */ #define DIB_FREE UINT_MAX #ifdef ENABLE_DEBUG_HASHMAP struct hashmap_debug_info { - LIST_FIELDS(struct hashmap_debug_info, debug_list); - unsigned max_entries; /* high watermark of n_entries */ - - /* who allocated this hashmap */ - int line; - const char *file; - const char *func; - - /* fields to detect modification while iterating */ - unsigned put_count; /* counts puts into the hashmap */ - unsigned rem_count; /* counts removals from hashmap */ - unsigned last_rem_idx; /* remembers last removal index */ + LIST_FIELDS(struct hashmap_debug_info, debug_list); + unsigned max_entries; /* high watermark of n_entries */ + + /* who allocated this hashmap */ + int line; + const char *file; + const char *func; + + /* fields to detect modification while iterating */ + unsigned put_count; /* counts puts into the hashmap */ + unsigned rem_count; /* counts removals from hashmap */ + unsigned last_rem_idx; /* remembers last removal index */ }; /* Tracks all existing hashmaps. Get at it from gdb. See sd_dump_hashmaps.py */ @@ -169,36 +168,36 @@ static LIST_HEAD(struct hashmap_debug_info, hashmap_debug_list); #define HASHMAP_DEBUG_FIELDS struct hashmap_debug_info debug; -#else /* !ENABLE_DEBUG_HASHMAP */ +#else /* !ENABLE_DEBUG_HASHMAP */ #define HASHMAP_DEBUG_FIELDS -#endif /* ENABLE_DEBUG_HASHMAP */ +#endif /* ENABLE_DEBUG_HASHMAP */ enum HashmapType { - HASHMAP_TYPE_PLAIN, - HASHMAP_TYPE_ORDERED, - HASHMAP_TYPE_SET, - _HASHMAP_TYPE_MAX + HASHMAP_TYPE_PLAIN, + HASHMAP_TYPE_ORDERED, + HASHMAP_TYPE_SET, + _HASHMAP_TYPE_MAX }; struct _packed_ indirect_storage { - char *storage; /* where buckets and DIBs are stored */ - uint8_t hash_key[HASH_KEY_SIZE]; /* hash key; changes during resize */ + char *storage; /* where buckets and DIBs are stored */ + uint8_t hash_key[HASH_KEY_SIZE]; /* hash key; changes during resize */ - unsigned n_entries; /* number of stored entries */ - unsigned n_buckets; /* number of buckets */ + unsigned n_entries; /* number of stored entries */ + unsigned n_buckets; /* number of buckets */ - unsigned idx_lowest_entry; /* Index below which all buckets are free. - Makes "while(hashmap_steal_first())" loops - O(n) instead of O(n^2) for unordered hashmaps. */ - uint8_t _pad[3]; /* padding for the whole HashmapBase */ - /* The bitfields in HashmapBase complete the alignment of the whole thing. */ + unsigned idx_lowest_entry; /* Index below which all buckets are free. + Makes "while(hashmap_steal_first())" loops + O(n) instead of O(n^2) for unordered hashmaps. */ + uint8_t _pad[3]; /* padding for the whole HashmapBase */ + /* The bitfields in HashmapBase complete the alignment of the whole thing. */ }; struct direct_storage { - /* This gives us 39 bytes on 64bit, or 35 bytes on 32bit. - * That's room for 4 set_entries + 4 DIB bytes + 3 unused bytes on 64bit, - * or 7 set_entries + 7 DIB bytes + 0 unused bytes on 32bit. */ - char storage[sizeof(struct indirect_storage)]; + /* This gives us 39 bytes on 64bit, or 35 bytes on 32bit. + * That's room for 4 set_entries + 4 DIB bytes + 3 unused bytes on 64bit, + * or 7 set_entries + 7 DIB bytes + 0 unused bytes on 32bit. */ + char storage[sizeof(struct indirect_storage)]; }; #define DIRECT_BUCKETS(entry_t) \ @@ -219,554 +218,612 @@ static bool shared_hash_key_initialized; /* Fields that all hashmap/set types must have */ struct HashmapBase { - const struct hash_ops *hash_ops; /* hash and compare ops to use */ - - union _packed_ { - struct indirect_storage indirect; /* if has_indirect */ - struct direct_storage direct; /* if !has_indirect */ - }; - - enum HashmapType type:2; /* HASHMAP_TYPE_* */ - bool has_indirect:1; /* whether indirect storage is used */ - unsigned n_direct_entries:3; /* Number of entries in direct storage. - * Only valid if !has_indirect. */ - bool from_pool:1; /* whether was allocated from mempool */ - HASHMAP_DEBUG_FIELDS /* optional hashmap_debug_info */ + const struct hash_ops *hash_ops; /* hash and compare ops to use */ + + union _packed_ { + struct indirect_storage indirect; /* if has_indirect */ + struct direct_storage direct; /* if !has_indirect */ + }; + + enum HashmapType type:2; /* HASHMAP_TYPE_* */ + bool has_indirect:1; /* whether indirect storage is used */ + unsigned n_direct_entries:3; /* Number of entries in direct storage. + * Only valid if !has_indirect. */ + bool from_pool:1; /* whether was allocated from mempool */ + HASHMAP_DEBUG_FIELDS /* optional hashmap_debug_info */ }; /* Specific hash types * HashmapBase must be at the beginning of each hashmap struct. */ struct Hashmap { - struct HashmapBase b; + struct HashmapBase b; }; struct OrderedHashmap { - struct HashmapBase b; - unsigned iterate_list_head, iterate_list_tail; + struct HashmapBase b; + unsigned iterate_list_head, iterate_list_tail; }; struct Set { - struct HashmapBase b; + struct HashmapBase b; }; -DEFINE_MEMPOOL(hashmap_pool, Hashmap, 8); +DEFINE_MEMPOOL(hashmap_pool, Hashmap, 8); DEFINE_MEMPOOL(ordered_hashmap_pool, OrderedHashmap, 8); /* No need for a separate Set pool */ assert_cc(sizeof(Hashmap) == sizeof(Set)); struct hashmap_type_info { - size_t head_size; - size_t entry_size; - struct mempool *mempool; - unsigned n_direct_buckets; + size_t head_size; + size_t entry_size; + struct mempool *mempool; + unsigned n_direct_buckets; }; static const struct hashmap_type_info hashmap_type_info[_HASHMAP_TYPE_MAX] = { - [HASHMAP_TYPE_PLAIN] = { - .head_size = sizeof(Hashmap), - .entry_size = sizeof(struct plain_hashmap_entry), - .mempool = &hashmap_pool, - .n_direct_buckets = DIRECT_BUCKETS(struct plain_hashmap_entry), - }, - [HASHMAP_TYPE_ORDERED] = { - .head_size = sizeof(OrderedHashmap), - .entry_size = sizeof(struct ordered_hashmap_entry), - .mempool = &ordered_hashmap_pool, - .n_direct_buckets = DIRECT_BUCKETS(struct ordered_hashmap_entry), - }, - [HASHMAP_TYPE_SET] = { - .head_size = sizeof(Set), - .entry_size = sizeof(struct set_entry), - .mempool = &hashmap_pool, - .n_direct_buckets = DIRECT_BUCKETS(struct set_entry), - }, + [HASHMAP_TYPE_PLAIN] = { + .head_size = sizeof(Hashmap), + .entry_size = + sizeof(struct plain_hashmap_entry), + .mempool = &hashmap_pool, + .n_direct_buckets = + DIRECT_BUCKETS(struct plain_hashmap_entry), + }, + [HASHMAP_TYPE_ORDERED] = { + .head_size = sizeof(OrderedHashmap), + .entry_size = + sizeof(struct ordered_hashmap_entry), + .mempool = &ordered_hashmap_pool, + .n_direct_buckets = + DIRECT_BUCKETS(struct ordered_hashmap_entry), + }, + [HASHMAP_TYPE_SET] = { + .head_size = sizeof(Set), + .entry_size = sizeof(struct set_entry), + .mempool = &hashmap_pool, + .n_direct_buckets = + DIRECT_BUCKETS(struct set_entry), + }, }; -unsigned long string_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) { - uint64_t u; - siphash24((uint8_t*) &u, p, strlen(p), hash_key); - return (unsigned long) u; +unsigned long string_hash_func(const void *p, + const uint8_t hash_key[HASH_KEY_SIZE]) +{ + uint64_t u; + siphash24((uint8_t *) & u, p, strlen(p), hash_key); + return (unsigned long)u; } -int string_compare_func(const void *a, const void *b) { - return strcmp(a, b); +int string_compare_func(const void *a, const void *b) +{ + return strcmp(a, b); } const struct hash_ops string_hash_ops = { - .hash = string_hash_func, - .compare = string_compare_func + .hash = string_hash_func, + .compare = string_compare_func }; -unsigned long trivial_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) { - uint64_t u; - siphash24((uint8_t*) &u, &p, sizeof(p), hash_key); - return (unsigned long) u; +unsigned long trivial_hash_func(const void *p, + const uint8_t hash_key[HASH_KEY_SIZE]) +{ + uint64_t u; + siphash24((uint8_t *) & u, &p, sizeof(p), hash_key); + return (unsigned long)u; } -int trivial_compare_func(const void *a, const void *b) { - return a < b ? -1 : (a > b ? 1 : 0); +int trivial_compare_func(const void *a, const void *b) +{ + return a < b ? -1 : (a > b ? 1 : 0); } const struct hash_ops trivial_hash_ops = { - .hash = trivial_hash_func, - .compare = trivial_compare_func + .hash = trivial_hash_func, + .compare = trivial_compare_func }; -unsigned long uint64_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) { - uint64_t u; - siphash24((uint8_t*) &u, p, sizeof(uint64_t), hash_key); - return (unsigned long) u; +unsigned long uint64_hash_func(const void *p, + const uint8_t hash_key[HASH_KEY_SIZE]) +{ + uint64_t u; + siphash24((uint8_t *) & u, p, sizeof(uint64_t), hash_key); + return (unsigned long)u; } -int uint64_compare_func(const void *_a, const void *_b) { - uint64_t a, b; - a = *(const uint64_t*) _a; - b = *(const uint64_t*) _b; - return a < b ? -1 : (a > b ? 1 : 0); +int uint64_compare_func(const void *_a, const void *_b) +{ + uint64_t a, b; + a = *(const uint64_t *)_a; + b = *(const uint64_t *)_b; + return a < b ? -1 : (a > b ? 1 : 0); } const struct hash_ops uint64_hash_ops = { - .hash = uint64_hash_func, - .compare = uint64_compare_func + .hash = uint64_hash_func, + .compare = uint64_compare_func }; #if SIZEOF_DEV_T != 8 -unsigned long devt_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) { - uint64_t u; - siphash24((uint8_t*) &u, p, sizeof(dev_t), hash_key); - return (unsigned long) u; +unsigned long devt_hash_func(const void *p, + const uint8_t hash_key[HASH_KEY_SIZE]) +{ + uint64_t u; + siphash24((uint8_t *) & u, p, sizeof(dev_t), hash_key); + return (unsigned long)u; } -int devt_compare_func(const void *_a, const void *_b) { - dev_t a, b; - a = *(const dev_t*) _a; - b = *(const dev_t*) _b; - return a < b ? -1 : (a > b ? 1 : 0); +int devt_compare_func(const void *_a, const void *_b) +{ + dev_t a, b; + a = *(const dev_t *)_a; + b = *(const dev_t *)_b; + return a < b ? -1 : (a > b ? 1 : 0); } const struct hash_ops devt_hash_ops = { - .hash = devt_hash_func, - .compare = devt_compare_func + .hash = devt_hash_func, + .compare = devt_compare_func }; #endif -static unsigned n_buckets(HashmapBase *h) { - return h->has_indirect ? h->indirect.n_buckets - : hashmap_type_info[h->type].n_direct_buckets; +static unsigned n_buckets(HashmapBase * h) +{ + return h->has_indirect ? h->indirect.n_buckets + : hashmap_type_info[h->type].n_direct_buckets; } -static unsigned n_entries(HashmapBase *h) { - return h->has_indirect ? h->indirect.n_entries - : h->n_direct_entries; +static unsigned n_entries(HashmapBase * h) +{ + return h->has_indirect ? h->indirect.n_entries : h->n_direct_entries; } -static void n_entries_inc(HashmapBase *h) { - if (h->has_indirect) - h->indirect.n_entries++; - else - h->n_direct_entries++; +static void n_entries_inc(HashmapBase * h) +{ + if (h->has_indirect) + h->indirect.n_entries++; + else + h->n_direct_entries++; } -static void n_entries_dec(HashmapBase *h) { - if (h->has_indirect) - h->indirect.n_entries--; - else - h->n_direct_entries--; +static void n_entries_dec(HashmapBase * h) +{ + if (h->has_indirect) + h->indirect.n_entries--; + else + h->n_direct_entries--; } -static char *storage_ptr(HashmapBase *h) { - return h->has_indirect ? h->indirect.storage - : h->direct.storage; +static char *storage_ptr(HashmapBase * h) +{ + return h->has_indirect ? h->indirect.storage : h->direct.storage; } -static uint8_t *hash_key(HashmapBase *h) { - return h->has_indirect ? h->indirect.hash_key - : shared_hash_key; +static uint8_t *hash_key(HashmapBase * h) +{ + return h->has_indirect ? h->indirect.hash_key : shared_hash_key; } -static unsigned base_bucket_hash(HashmapBase *h, const void *p) { - return (unsigned) (h->hash_ops->hash(p, hash_key(h)) % n_buckets(h)); +static unsigned base_bucket_hash(HashmapBase * h, const void *p) +{ + return (unsigned)(h->hash_ops->hash(p, hash_key(h)) % n_buckets(h)); } + #define bucket_hash(h, p) base_bucket_hash(HASHMAP_BASE(h), p) -static void get_hash_key(uint8_t hash_key[HASH_KEY_SIZE], bool reuse_is_ok) { - static uint8_t current[HASH_KEY_SIZE]; - static bool current_initialized = false; +static void get_hash_key(uint8_t hash_key[HASH_KEY_SIZE], bool reuse_is_ok) +{ + static uint8_t current[HASH_KEY_SIZE]; + static bool current_initialized = false; - /* Returns a hash function key to use. In order to keep things - * fast we will not generate a new key each time we allocate a - * new hash table. Instead, we'll just reuse the most recently - * generated one, except if we never generated one or when we - * are rehashing an entire hash table because we reached a - * fill level */ + /* Returns a hash function key to use. In order to keep things + * fast we will not generate a new key each time we allocate a + * new hash table. Instead, we'll just reuse the most recently + * generated one, except if we never generated one or when we + * are rehashing an entire hash table because we reached a + * fill level */ - if (!current_initialized || !reuse_is_ok) { - random_bytes(current, sizeof(current)); - current_initialized = true; - } + if (!current_initialized || !reuse_is_ok) { + random_bytes(current, sizeof(current)); + current_initialized = true; + } - memcpy(hash_key, current, sizeof(current)); + memcpy(hash_key, current, sizeof(current)); } -static struct hashmap_base_entry *bucket_at(HashmapBase *h, unsigned idx) { - return (struct hashmap_base_entry*) - (storage_ptr(h) + idx * hashmap_type_info[h->type].entry_size); +static struct hashmap_base_entry *bucket_at(HashmapBase * h, unsigned idx) +{ + return (struct hashmap_base_entry *) + (storage_ptr(h) + idx * hashmap_type_info[h->type].entry_size); } -static struct plain_hashmap_entry *plain_bucket_at(Hashmap *h, unsigned idx) { - return (struct plain_hashmap_entry*) bucket_at(HASHMAP_BASE(h), idx); +static struct plain_hashmap_entry *plain_bucket_at(Hashmap * h, unsigned idx) +{ + return (struct plain_hashmap_entry *)bucket_at(HASHMAP_BASE(h), idx); } -static struct ordered_hashmap_entry *ordered_bucket_at(OrderedHashmap *h, unsigned idx) { - return (struct ordered_hashmap_entry*) bucket_at(HASHMAP_BASE(h), idx); +static struct ordered_hashmap_entry *ordered_bucket_at(OrderedHashmap * h, + unsigned idx) +{ + return (struct ordered_hashmap_entry *)bucket_at(HASHMAP_BASE(h), idx); } -static struct set_entry *set_bucket_at(Set *h, unsigned idx) { - return (struct set_entry*) bucket_at(HASHMAP_BASE(h), idx); +static struct set_entry *set_bucket_at(Set * h, unsigned idx) +{ + return (struct set_entry *)bucket_at(HASHMAP_BASE(h), idx); } -static struct ordered_hashmap_entry *bucket_at_swap(struct swap_entries *swap, unsigned idx) { - return &swap->e[idx - _IDX_SWAP_BEGIN]; +static struct ordered_hashmap_entry *bucket_at_swap(struct swap_entries *swap, + unsigned idx) +{ + return &swap->e[idx - _IDX_SWAP_BEGIN]; } /* Returns a pointer to the bucket at index idx. * Understands real indexes and swap indexes, hence "_virtual". */ -static struct hashmap_base_entry *bucket_at_virtual(HashmapBase *h, struct swap_entries *swap, - unsigned idx) { - if (idx < _IDX_SWAP_BEGIN) - return bucket_at(h, idx); +static struct hashmap_base_entry *bucket_at_virtual(HashmapBase * h, + struct swap_entries *swap, + unsigned idx) +{ + if (idx < _IDX_SWAP_BEGIN) + return bucket_at(h, idx); - if (idx < _IDX_SWAP_END) - return &bucket_at_swap(swap, idx)->p.b; + if (idx < _IDX_SWAP_END) + return &bucket_at_swap(swap, idx)->p.b; - assert_not_reached("Invalid index"); - return NULL; + assert_not_reached("Invalid index"); + return NULL; } -static dib_raw_t *dib_raw_ptr(HashmapBase *h) { - return (dib_raw_t*) - (storage_ptr(h) + hashmap_type_info[h->type].entry_size * n_buckets(h)); +static dib_raw_t *dib_raw_ptr(HashmapBase * h) +{ + return (dib_raw_t *) + (storage_ptr(h) + + hashmap_type_info[h->type].entry_size * n_buckets(h)); } -static unsigned bucket_distance(HashmapBase *h, unsigned idx, unsigned from) { - return idx >= from ? idx - from - : n_buckets(h) + idx - from; +static unsigned bucket_distance(HashmapBase * h, unsigned idx, unsigned from) +{ + return idx >= from ? idx - from : n_buckets(h) + idx - from; } -static unsigned bucket_calculate_dib(HashmapBase *h, unsigned idx, dib_raw_t raw_dib) { - unsigned initial_bucket; +static unsigned bucket_calculate_dib(HashmapBase * h, unsigned idx, + dib_raw_t raw_dib) +{ + unsigned initial_bucket; - if (raw_dib == DIB_RAW_FREE) - return DIB_FREE; + if (raw_dib == DIB_RAW_FREE) + return DIB_FREE; - if (_likely_(raw_dib < DIB_RAW_OVERFLOW)) - return raw_dib; + if (_likely_(raw_dib < DIB_RAW_OVERFLOW)) + return raw_dib; - /* - * Having an overflow DIB value is very unlikely. The hash function - * would have to be bad. For example, in a table of size 2^24 filled - * to load factor 0.9 the maximum observed DIB is only about 60. - * In theory (assuming I used Maxima correctly), for an infinite size - * hash table with load factor 0.8 the probability of a given entry - * having DIB > 40 is 1.9e-8. - * This returns the correct DIB value by recomputing the hash value in - * the unlikely case. XXX Hitting this case could be a hint to rehash. - */ - initial_bucket = bucket_hash(h, bucket_at(h, idx)->key); - return bucket_distance(h, idx, initial_bucket); + /* + * Having an overflow DIB value is very unlikely. The hash function + * would have to be bad. For example, in a table of size 2^24 filled + * to load factor 0.9 the maximum observed DIB is only about 60. + * In theory (assuming I used Maxima correctly), for an infinite size + * hash table with load factor 0.8 the probability of a given entry + * having DIB > 40 is 1.9e-8. + * This returns the correct DIB value by recomputing the hash value in + * the unlikely case. XXX Hitting this case could be a hint to rehash. + */ + initial_bucket = bucket_hash(h, bucket_at(h, idx)->key); + return bucket_distance(h, idx, initial_bucket); } -static void bucket_set_dib(HashmapBase *h, unsigned idx, unsigned dib) { - dib_raw_ptr(h)[idx] = dib != DIB_FREE ? MIN(dib, DIB_RAW_OVERFLOW) : DIB_RAW_FREE; +static void bucket_set_dib(HashmapBase * h, unsigned idx, unsigned dib) +{ + dib_raw_ptr(h)[idx] = + dib != DIB_FREE ? MIN(dib, DIB_RAW_OVERFLOW) : DIB_RAW_FREE; } -static unsigned skip_free_buckets(HashmapBase *h, unsigned idx) { - dib_raw_t *dibs; +static unsigned skip_free_buckets(HashmapBase * h, unsigned idx) +{ + dib_raw_t *dibs; - dibs = dib_raw_ptr(h); + dibs = dib_raw_ptr(h); - for ( ; idx < n_buckets(h); idx++) - if (dibs[idx] != DIB_RAW_FREE) - return idx; + for (; idx < n_buckets(h); idx++) + if (dibs[idx] != DIB_RAW_FREE) + return idx; - return IDX_NIL; + return IDX_NIL; } -static void bucket_mark_free(HashmapBase *h, unsigned idx) { - memzero(bucket_at(h, idx), hashmap_type_info[h->type].entry_size); - bucket_set_dib(h, idx, DIB_FREE); +static void bucket_mark_free(HashmapBase * h, unsigned idx) +{ + memzero(bucket_at(h, idx), hashmap_type_info[h->type].entry_size); + bucket_set_dib(h, idx, DIB_FREE); } -static void bucket_move_entry(HashmapBase *h, struct swap_entries *swap, - unsigned from, unsigned to) { - struct hashmap_base_entry *e_from, *e_to; +static void bucket_move_entry(HashmapBase * h, struct swap_entries *swap, + unsigned from, unsigned to) +{ + struct hashmap_base_entry *e_from, *e_to; - assert(from != to); + assert(from != to); - e_from = bucket_at_virtual(h, swap, from); - e_to = bucket_at_virtual(h, swap, to); + e_from = bucket_at_virtual(h, swap, from); + e_to = bucket_at_virtual(h, swap, to); - memcpy(e_to, e_from, hashmap_type_info[h->type].entry_size); + memcpy(e_to, e_from, hashmap_type_info[h->type].entry_size); - if (h->type == HASHMAP_TYPE_ORDERED) { - OrderedHashmap *lh = (OrderedHashmap*) h; - struct ordered_hashmap_entry *le, *le_to; + if (h->type == HASHMAP_TYPE_ORDERED) { + OrderedHashmap *lh = (OrderedHashmap *) h; + struct ordered_hashmap_entry *le, *le_to; - le_to = (struct ordered_hashmap_entry*) e_to; + le_to = (struct ordered_hashmap_entry *)e_to; - if (le_to->iterate_next != IDX_NIL) { - le = (struct ordered_hashmap_entry*) - bucket_at_virtual(h, swap, le_to->iterate_next); - le->iterate_previous = to; - } + if (le_to->iterate_next != IDX_NIL) { + le = (struct ordered_hashmap_entry *) + bucket_at_virtual(h, swap, le_to->iterate_next); + le->iterate_previous = to; + } - if (le_to->iterate_previous != IDX_NIL) { - le = (struct ordered_hashmap_entry*) - bucket_at_virtual(h, swap, le_to->iterate_previous); - le->iterate_next = to; - } + if (le_to->iterate_previous != IDX_NIL) { + le = (struct ordered_hashmap_entry *) + bucket_at_virtual(h, swap, le_to->iterate_previous); + le->iterate_next = to; + } - if (lh->iterate_list_head == from) - lh->iterate_list_head = to; - if (lh->iterate_list_tail == from) - lh->iterate_list_tail = to; - } + if (lh->iterate_list_head == from) + lh->iterate_list_head = to; + if (lh->iterate_list_tail == from) + lh->iterate_list_tail = to; + } } -static unsigned next_idx(HashmapBase *h, unsigned idx) { - return (idx + 1U) % n_buckets(h); +static unsigned next_idx(HashmapBase * h, unsigned idx) +{ + return (idx + 1U) % n_buckets(h); } -static unsigned prev_idx(HashmapBase *h, unsigned idx) { - return (n_buckets(h) + idx - 1U) % n_buckets(h); +static unsigned prev_idx(HashmapBase * h, unsigned idx) +{ + return (n_buckets(h) + idx - 1U) % n_buckets(h); } -static void *entry_value(HashmapBase *h, struct hashmap_base_entry *e) { - switch (h->type) { +static void *entry_value(HashmapBase * h, struct hashmap_base_entry *e) +{ + switch (h->type) { - case HASHMAP_TYPE_PLAIN: - case HASHMAP_TYPE_ORDERED: - return ((struct plain_hashmap_entry*)e)->value; + case HASHMAP_TYPE_PLAIN: + case HASHMAP_TYPE_ORDERED: + return ((struct plain_hashmap_entry *)e)->value; - case HASHMAP_TYPE_SET: - return (void*) e->key; + case HASHMAP_TYPE_SET: + return (void *)e->key; - default: - assert_not_reached("Unknown hashmap type"); - return NULL; - } + default: + assert_not_reached("Unknown hashmap type"); + return NULL; + } } -static void base_remove_entry(HashmapBase *h, unsigned idx) { - unsigned left, right, prev, dib; - dib_raw_t raw_dib, *dibs; +static void base_remove_entry(HashmapBase * h, unsigned idx) +{ + unsigned left, right, prev, dib; + dib_raw_t raw_dib, *dibs; - dibs = dib_raw_ptr(h); - assert(dibs[idx] != DIB_RAW_FREE); + dibs = dib_raw_ptr(h); + assert(dibs[idx] != DIB_RAW_FREE); #ifdef ENABLE_DEBUG_HASHMAP - h->debug.rem_count++; - h->debug.last_rem_idx = idx; + h->debug.rem_count++; + h->debug.last_rem_idx = idx; #endif - left = idx; - /* Find the stop bucket ("right"). It is either free or has DIB == 0. */ - for (right = next_idx(h, left); ; right = next_idx(h, right)) { - raw_dib = dibs[right]; - if (raw_dib == 0 || raw_dib == DIB_RAW_FREE) - break; - - /* The buckets are not supposed to be all occupied and with DIB > 0. - * That would mean we could make everyone better off by shifting them - * backward. This scenario is impossible. */ - assert(left != right); - } - - if (h->type == HASHMAP_TYPE_ORDERED) { - OrderedHashmap *lh = (OrderedHashmap*) h; - struct ordered_hashmap_entry *le = ordered_bucket_at(lh, idx); - - if (le->iterate_next != IDX_NIL) - ordered_bucket_at(lh, le->iterate_next)->iterate_previous = le->iterate_previous; - else - lh->iterate_list_tail = le->iterate_previous; - - if (le->iterate_previous != IDX_NIL) - ordered_bucket_at(lh, le->iterate_previous)->iterate_next = le->iterate_next; - else - lh->iterate_list_head = le->iterate_next; - } - - /* Now shift all buckets in the interval (left, right) one step backwards */ - for (prev = left, left = next_idx(h, left); left != right; - prev = left, left = next_idx(h, left)) { - dib = bucket_calculate_dib(h, left, dibs[left]); - assert(dib != 0); - bucket_move_entry(h, NULL, left, prev); - bucket_set_dib(h, prev, dib - 1); - } - - bucket_mark_free(h, prev); - n_entries_dec(h); + left = idx; + /* Find the stop bucket ("right"). It is either free or has DIB == 0. */ + for (right = next_idx(h, left);; right = next_idx(h, right)) { + raw_dib = dibs[right]; + if (raw_dib == 0 || raw_dib == DIB_RAW_FREE) + break; + + /* The buckets are not supposed to be all occupied and with DIB > 0. + * That would mean we could make everyone better off by shifting them + * backward. This scenario is impossible. */ + assert(left != right); + } + + if (h->type == HASHMAP_TYPE_ORDERED) { + OrderedHashmap *lh = (OrderedHashmap *) h; + struct ordered_hashmap_entry *le = ordered_bucket_at(lh, idx); + + if (le->iterate_next != IDX_NIL) + ordered_bucket_at(lh, + le->iterate_next)->iterate_previous = + le->iterate_previous; + else + lh->iterate_list_tail = le->iterate_previous; + + if (le->iterate_previous != IDX_NIL) + ordered_bucket_at(lh, + le->iterate_previous)->iterate_next = + le->iterate_next; + else + lh->iterate_list_head = le->iterate_next; + } + + /* Now shift all buckets in the interval (left, right) one step backwards */ + for (prev = left, left = next_idx(h, left); left != right; + prev = left, left = next_idx(h, left)) { + dib = bucket_calculate_dib(h, left, dibs[left]); + assert(dib != 0); + bucket_move_entry(h, NULL, left, prev); + bucket_set_dib(h, prev, dib - 1); + } + + bucket_mark_free(h, prev); + n_entries_dec(h); } + #define remove_entry(h, idx) base_remove_entry(HASHMAP_BASE(h), idx) -static unsigned hashmap_iterate_in_insertion_order(OrderedHashmap *h, Iterator *i) { - struct ordered_hashmap_entry *e; - unsigned idx; - - assert(h); - assert(i); - - if (i->idx == IDX_NIL) - goto at_end; - - if (i->idx == IDX_FIRST && h->iterate_list_head == IDX_NIL) - goto at_end; - - if (i->idx == IDX_FIRST) { - idx = h->iterate_list_head; - e = ordered_bucket_at(h, idx); - } else { - idx = i->idx; - e = ordered_bucket_at(h, idx); - /* - * We allow removing the current entry while iterating, but removal may cause - * a backward shift. The next entry may thus move one bucket to the left. - * To detect when it happens, we remember the key pointer of the entry we were - * going to iterate next. If it does not match, there was a backward shift. - */ - if (e->p.b.key != i->next_key) { - idx = prev_idx(HASHMAP_BASE(h), idx); - e = ordered_bucket_at(h, idx); - } - assert(e->p.b.key == i->next_key); - } +static unsigned hashmap_iterate_in_insertion_order(OrderedHashmap * h, + Iterator * i) +{ + struct ordered_hashmap_entry *e; + unsigned idx; + + assert(h); + assert(i); + + if (i->idx == IDX_NIL) + goto at_end; + + if (i->idx == IDX_FIRST && h->iterate_list_head == IDX_NIL) + goto at_end; + + if (i->idx == IDX_FIRST) { + idx = h->iterate_list_head; + e = ordered_bucket_at(h, idx); + } else { + idx = i->idx; + e = ordered_bucket_at(h, idx); + /* + * We allow removing the current entry while iterating, but removal may cause + * a backward shift. The next entry may thus move one bucket to the left. + * To detect when it happens, we remember the key pointer of the entry we were + * going to iterate next. If it does not match, there was a backward shift. + */ + if (e->p.b.key != i->next_key) { + idx = prev_idx(HASHMAP_BASE(h), idx); + e = ordered_bucket_at(h, idx); + } + assert(e->p.b.key == i->next_key); + } #ifdef ENABLE_DEBUG_HASHMAP - i->prev_idx = idx; + i->prev_idx = idx; #endif - if (e->iterate_next != IDX_NIL) { - struct ordered_hashmap_entry *n; - i->idx = e->iterate_next; - n = ordered_bucket_at(h, i->idx); - i->next_key = n->p.b.key; - } else - i->idx = IDX_NIL; - - return idx; - -at_end: - i->idx = IDX_NIL; - return IDX_NIL; -} - -static unsigned hashmap_iterate_in_internal_order(HashmapBase *h, Iterator *i) { - unsigned idx; - - assert(h); - assert(i); - - if (i->idx == IDX_NIL) - goto at_end; - - if (i->idx == IDX_FIRST) { - /* fast forward to the first occupied bucket */ - if (h->has_indirect) { - i->idx = skip_free_buckets(h, h->indirect.idx_lowest_entry); - h->indirect.idx_lowest_entry = i->idx; - } else - i->idx = skip_free_buckets(h, 0); - - if (i->idx == IDX_NIL) - goto at_end; - } else { - struct hashmap_base_entry *e; - - assert(i->idx > 0); - - e = bucket_at(h, i->idx); - /* - * We allow removing the current entry while iterating, but removal may cause - * a backward shift. The next entry may thus move one bucket to the left. - * To detect when it happens, we remember the key pointer of the entry we were - * going to iterate next. If it does not match, there was a backward shift. - */ - if (e->key != i->next_key) - e = bucket_at(h, --i->idx); - - assert(e->key == i->next_key); - } - - idx = i->idx; + if (e->iterate_next != IDX_NIL) { + struct ordered_hashmap_entry *n; + i->idx = e->iterate_next; + n = ordered_bucket_at(h, i->idx); + i->next_key = n->p.b.key; + } else + i->idx = IDX_NIL; + + return idx; + + at_end: + i->idx = IDX_NIL; + return IDX_NIL; +} + +static unsigned hashmap_iterate_in_internal_order(HashmapBase * h, Iterator * i) +{ + unsigned idx; + + assert(h); + assert(i); + + if (i->idx == IDX_NIL) + goto at_end; + + if (i->idx == IDX_FIRST) { + /* fast forward to the first occupied bucket */ + if (h->has_indirect) { + i->idx = + skip_free_buckets(h, h->indirect.idx_lowest_entry); + h->indirect.idx_lowest_entry = i->idx; + } else + i->idx = skip_free_buckets(h, 0); + + if (i->idx == IDX_NIL) + goto at_end; + } else { + struct hashmap_base_entry *e; + + assert(i->idx > 0); + + e = bucket_at(h, i->idx); + /* + * We allow removing the current entry while iterating, but removal may cause + * a backward shift. The next entry may thus move one bucket to the left. + * To detect when it happens, we remember the key pointer of the entry we were + * going to iterate next. If it does not match, there was a backward shift. + */ + if (e->key != i->next_key) + e = bucket_at(h, --i->idx); + + assert(e->key == i->next_key); + } + + idx = i->idx; #ifdef ENABLE_DEBUG_HASHMAP - i->prev_idx = idx; + i->prev_idx = idx; #endif - i->idx = skip_free_buckets(h, i->idx + 1); - if (i->idx != IDX_NIL) - i->next_key = bucket_at(h, i->idx)->key; - else - i->idx = IDX_NIL; + i->idx = skip_free_buckets(h, i->idx + 1); + if (i->idx != IDX_NIL) + i->next_key = bucket_at(h, i->idx)->key; + else + i->idx = IDX_NIL; - return idx; + return idx; -at_end: - i->idx = IDX_NIL; - return IDX_NIL; + at_end: + i->idx = IDX_NIL; + return IDX_NIL; } -static unsigned hashmap_iterate_entry(HashmapBase *h, Iterator *i) { - if (!h) { - i->idx = IDX_NIL; - return IDX_NIL; - } - +static unsigned hashmap_iterate_entry(HashmapBase * h, Iterator * i) +{ + if (!h) { + i->idx = IDX_NIL; + return IDX_NIL; + } #ifdef ENABLE_DEBUG_HASHMAP - if (i->idx == IDX_FIRST) { - i->put_count = h->debug.put_count; - i->rem_count = h->debug.rem_count; - } else { - /* While iterating, must not add any new entries */ - assert(i->put_count == h->debug.put_count); - /* ... or remove entries other than the current one */ - assert(i->rem_count == h->debug.rem_count || - (i->rem_count == h->debug.rem_count - 1 && - i->prev_idx == h->debug.last_rem_idx)); - /* Reset our removals counter */ - i->rem_count = h->debug.rem_count; - } + if (i->idx == IDX_FIRST) { + i->put_count = h->debug.put_count; + i->rem_count = h->debug.rem_count; + } else { + /* While iterating, must not add any new entries */ + assert(i->put_count == h->debug.put_count); + /* ... or remove entries other than the current one */ + assert(i->rem_count == h->debug.rem_count || + (i->rem_count == h->debug.rem_count - 1 && + i->prev_idx == h->debug.last_rem_idx)); + /* Reset our removals counter */ + i->rem_count = h->debug.rem_count; + } #endif - return h->type == HASHMAP_TYPE_ORDERED ? hashmap_iterate_in_insertion_order((OrderedHashmap*) h, i) - : hashmap_iterate_in_internal_order(h, i); + return h->type == + HASHMAP_TYPE_ORDERED ? + hashmap_iterate_in_insertion_order((OrderedHashmap *) h, i) + : hashmap_iterate_in_internal_order(h, i); } -void *internal_hashmap_iterate(HashmapBase *h, Iterator *i, const void **key) { - struct hashmap_base_entry *e; - void *data; - unsigned idx; +void *internal_hashmap_iterate(HashmapBase * h, Iterator * i, const void **key) +{ + struct hashmap_base_entry *e; + void *data; + unsigned idx; - idx = hashmap_iterate_entry(h, i); - if (idx == IDX_NIL) { - if (key) - *key = NULL; + idx = hashmap_iterate_entry(h, i); + if (idx == IDX_NIL) { + if (key) + *key = NULL; - return NULL; - } + return NULL; + } - e = bucket_at(h, idx); - data = entry_value(h, e); - if (key) - *key = e->key; + e = bucket_at(h, idx); + data = entry_value(h, e); + if (key) + *key = e->key; - return data; + return data; } -void *set_iterate(Set *s, Iterator *i) { - return internal_hashmap_iterate(HASHMAP_BASE(s), i, NULL); +void *set_iterate(Set * s, Iterator * i) +{ + return internal_hashmap_iterate(HASHMAP_BASE(s), i, NULL); } #define HASHMAP_FOREACH_IDX(idx, h, i) \ @@ -774,191 +831,232 @@ void *set_iterate(Set *s, Iterator *i) { (idx != IDX_NIL); \ (idx) = hashmap_iterate_entry((h), &(i))) -static void reset_direct_storage(HashmapBase *h) { - const struct hashmap_type_info *hi = &hashmap_type_info[h->type]; - void *p; +static void reset_direct_storage(HashmapBase * h) +{ + const struct hashmap_type_info *hi = &hashmap_type_info[h->type]; + void *p; - assert(!h->has_indirect); + assert(!h->has_indirect); - p = mempset(h->direct.storage, 0, hi->entry_size * hi->n_direct_buckets); - memset(p, DIB_RAW_INIT, sizeof(dib_raw_t) * hi->n_direct_buckets); + p = mempset(h->direct.storage, 0, + hi->entry_size * hi->n_direct_buckets); + memset(p, DIB_RAW_INIT, sizeof(dib_raw_t) * hi->n_direct_buckets); } -static struct HashmapBase *hashmap_base_new(const struct hash_ops *hash_ops, enum HashmapType type HASHMAP_DEBUG_PARAMS) { - HashmapBase *h; - const struct hashmap_type_info *hi = &hashmap_type_info[type]; - bool use_pool; - - use_pool = is_main_thread(); +static struct HashmapBase *hashmap_base_new(const struct hash_ops *hash_ops, + enum HashmapType type + HASHMAP_DEBUG_PARAMS) +{ + HashmapBase *h; + const struct hashmap_type_info *hi = &hashmap_type_info[type]; + bool use_pool; - h = use_pool ? mempool_alloc0_tile(hi->mempool) : malloc0(hi->head_size); + use_pool = is_main_thread(); - if (!h) - return NULL; + h = use_pool ? mempool_alloc0_tile(hi->mempool) : malloc0(hi-> + head_size); - h->type = type; - h->from_pool = use_pool; - h->hash_ops = hash_ops ? hash_ops : &trivial_hash_ops; + if (!h) + return NULL; - if (type == HASHMAP_TYPE_ORDERED) { - OrderedHashmap *lh = (OrderedHashmap*)h; - lh->iterate_list_head = lh->iterate_list_tail = IDX_NIL; - } + h->type = type; + h->from_pool = use_pool; + h->hash_ops = hash_ops ? hash_ops : &trivial_hash_ops; - reset_direct_storage(h); + if (type == HASHMAP_TYPE_ORDERED) { + OrderedHashmap *lh = (OrderedHashmap *) h; + lh->iterate_list_head = lh->iterate_list_tail = IDX_NIL; + } - if (!shared_hash_key_initialized) { - random_bytes(shared_hash_key, sizeof(shared_hash_key)); - shared_hash_key_initialized= true; - } + reset_direct_storage(h); + if (!shared_hash_key_initialized) { + random_bytes(shared_hash_key, sizeof(shared_hash_key)); + shared_hash_key_initialized = true; + } #ifdef ENABLE_DEBUG_HASHMAP - LIST_PREPEND(debug_list, hashmap_debug_list, &h->debug); - h->debug.func = func; - h->debug.file = file; - h->debug.line = line; + LIST_PREPEND(debug_list, hashmap_debug_list, &h->debug); + h->debug.func = func; + h->debug.file = file; + h->debug.line = line; #endif - return h; + return h; } -Hashmap *internal_hashmap_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) { - return (Hashmap*) hashmap_base_new(hash_ops, HASHMAP_TYPE_PLAIN HASHMAP_DEBUG_PASS_ARGS); +Hashmap *internal_hashmap_new(const struct hash_ops * + hash_ops HASHMAP_DEBUG_PARAMS) +{ + return (Hashmap *) hashmap_base_new(hash_ops, + HASHMAP_TYPE_PLAIN + HASHMAP_DEBUG_PASS_ARGS); } -OrderedHashmap *internal_ordered_hashmap_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) { - return (OrderedHashmap*) hashmap_base_new(hash_ops, HASHMAP_TYPE_ORDERED HASHMAP_DEBUG_PASS_ARGS); +OrderedHashmap *internal_ordered_hashmap_new(const struct hash_ops * + hash_ops HASHMAP_DEBUG_PARAMS) +{ + return (OrderedHashmap *) hashmap_base_new(hash_ops, + HASHMAP_TYPE_ORDERED + HASHMAP_DEBUG_PASS_ARGS); } -Set *internal_set_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) { - return (Set*) hashmap_base_new(hash_ops, HASHMAP_TYPE_SET HASHMAP_DEBUG_PASS_ARGS); +Set *internal_set_new(const struct hash_ops * hash_ops HASHMAP_DEBUG_PARAMS) +{ + return (Set *) hashmap_base_new(hash_ops, + HASHMAP_TYPE_SET + HASHMAP_DEBUG_PASS_ARGS); } -static int hashmap_base_ensure_allocated(HashmapBase **h, const struct hash_ops *hash_ops, - enum HashmapType type HASHMAP_DEBUG_PARAMS) { - HashmapBase *q; +static int hashmap_base_ensure_allocated(HashmapBase ** h, + const struct hash_ops *hash_ops, + enum HashmapType type + HASHMAP_DEBUG_PARAMS) +{ + HashmapBase *q; - assert(h); + assert(h); - if (*h) - return 0; + if (*h) + return 0; - q = hashmap_base_new(hash_ops, type HASHMAP_DEBUG_PASS_ARGS); - if (!q) - return -ENOMEM; + q = hashmap_base_new(hash_ops, type HASHMAP_DEBUG_PASS_ARGS); + if (!q) + return -ENOMEM; - *h = q; - return 0; + *h = q; + return 0; } -int internal_hashmap_ensure_allocated(Hashmap **h, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) { - return hashmap_base_ensure_allocated((HashmapBase**)h, hash_ops, HASHMAP_TYPE_PLAIN HASHMAP_DEBUG_PASS_ARGS); +int internal_hashmap_ensure_allocated(Hashmap ** h, + const struct hash_ops *hash_ops + HASHMAP_DEBUG_PARAMS) +{ + return hashmap_base_ensure_allocated((HashmapBase **) h, hash_ops, + HASHMAP_TYPE_PLAIN + HASHMAP_DEBUG_PASS_ARGS); } -int internal_ordered_hashmap_ensure_allocated(OrderedHashmap **h, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) { - return hashmap_base_ensure_allocated((HashmapBase**)h, hash_ops, HASHMAP_TYPE_ORDERED HASHMAP_DEBUG_PASS_ARGS); +int internal_ordered_hashmap_ensure_allocated(OrderedHashmap ** h, + const struct hash_ops *hash_ops + HASHMAP_DEBUG_PARAMS) +{ + return hashmap_base_ensure_allocated((HashmapBase **) h, hash_ops, + HASHMAP_TYPE_ORDERED + HASHMAP_DEBUG_PASS_ARGS); } -int internal_set_ensure_allocated(Set **s, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) { - return hashmap_base_ensure_allocated((HashmapBase**)s, hash_ops, HASHMAP_TYPE_SET HASHMAP_DEBUG_PASS_ARGS); +int internal_set_ensure_allocated(Set ** s, + const struct hash_ops *hash_ops + HASHMAP_DEBUG_PARAMS) +{ + return hashmap_base_ensure_allocated((HashmapBase **) s, hash_ops, + HASHMAP_TYPE_SET + HASHMAP_DEBUG_PASS_ARGS); } -static void hashmap_free_no_clear(HashmapBase *h) { - assert(!h->has_indirect); - assert(!h->n_direct_entries); +static void hashmap_free_no_clear(HashmapBase * h) +{ + assert(!h->has_indirect); + assert(!h->n_direct_entries); #ifdef ENABLE_DEBUG_HASHMAP - LIST_REMOVE(debug_list, hashmap_debug_list, &h->debug); + LIST_REMOVE(debug_list, hashmap_debug_list, &h->debug); #endif - if (h->from_pool) - mempool_free_tile(hashmap_type_info[h->type].mempool, h); - else - free(h); + if (h->from_pool) + mempool_free_tile(hashmap_type_info[h->type].mempool, h); + else + free(h); } -void internal_hashmap_free(HashmapBase *h) { +void internal_hashmap_free(HashmapBase * h) +{ - /* Free the hashmap, but nothing in it */ + /* Free the hashmap, but nothing in it */ - if (!h) - return; + if (!h) + return; - internal_hashmap_clear(h); - hashmap_free_no_clear(h); + internal_hashmap_clear(h); + hashmap_free_no_clear(h); } -void internal_hashmap_free_free(HashmapBase *h) { +void internal_hashmap_free_free(HashmapBase * h) +{ - /* Free the hashmap and all data objects in it, but not the - * keys */ + /* Free the hashmap and all data objects in it, but not the + * keys */ - if (!h) - return; + if (!h) + return; - internal_hashmap_clear_free(h); - hashmap_free_no_clear(h); + internal_hashmap_clear_free(h); + hashmap_free_no_clear(h); } -void hashmap_free_free_free(Hashmap *h) { +void hashmap_free_free_free(Hashmap * h) +{ - /* Free the hashmap and all data and key objects in it */ + /* Free the hashmap and all data and key objects in it */ - if (!h) - return; + if (!h) + return; - hashmap_clear_free_free(h); - hashmap_free_no_clear(HASHMAP_BASE(h)); + hashmap_clear_free_free(h); + hashmap_free_no_clear(HASHMAP_BASE(h)); } -void internal_hashmap_clear(HashmapBase *h) { - if (!h) - return; +void internal_hashmap_clear(HashmapBase * h) +{ + if (!h) + return; - if (h->has_indirect) { - free(h->indirect.storage); - h->has_indirect = false; - } + if (h->has_indirect) { + free(h->indirect.storage); + h->has_indirect = false; + } - h->n_direct_entries = 0; - reset_direct_storage(h); + h->n_direct_entries = 0; + reset_direct_storage(h); - if (h->type == HASHMAP_TYPE_ORDERED) { - OrderedHashmap *lh = (OrderedHashmap*) h; - lh->iterate_list_head = lh->iterate_list_tail = IDX_NIL; - } + if (h->type == HASHMAP_TYPE_ORDERED) { + OrderedHashmap *lh = (OrderedHashmap *) h; + lh->iterate_list_head = lh->iterate_list_tail = IDX_NIL; + } } -void internal_hashmap_clear_free(HashmapBase *h) { - unsigned idx; +void internal_hashmap_clear_free(HashmapBase * h) +{ + unsigned idx; - if (!h) - return; + if (!h) + return; - for (idx = skip_free_buckets(h, 0); idx != IDX_NIL; - idx = skip_free_buckets(h, idx + 1)) - free(entry_value(h, bucket_at(h, idx))); + for (idx = skip_free_buckets(h, 0); idx != IDX_NIL; + idx = skip_free_buckets(h, idx + 1)) + free(entry_value(h, bucket_at(h, idx))); - internal_hashmap_clear(h); + internal_hashmap_clear(h); } -void hashmap_clear_free_free(Hashmap *h) { - unsigned idx; +void hashmap_clear_free_free(Hashmap * h) +{ + unsigned idx; - if (!h) - return; + if (!h) + return; - for (idx = skip_free_buckets(HASHMAP_BASE(h), 0); idx != IDX_NIL; - idx = skip_free_buckets(HASHMAP_BASE(h), idx + 1)) { - struct plain_hashmap_entry *e = plain_bucket_at(h, idx); - free((void*)e->b.key); - free(e->value); - } + for (idx = skip_free_buckets(HASHMAP_BASE(h), 0); idx != IDX_NIL; + idx = skip_free_buckets(HASHMAP_BASE(h), idx + 1)) { + struct plain_hashmap_entry *e = plain_bucket_at(h, idx); + free((void *)e->b.key); + free(e->value); + } - internal_hashmap_clear(HASHMAP_BASE(h)); + internal_hashmap_clear(HASHMAP_BASE(h)); } -static int resize_buckets(HashmapBase *h, unsigned entries_add); +static int resize_buckets(HashmapBase * h, unsigned entries_add); /* * Finds an empty bucket to put an entry into, starting the scan at 'idx'. @@ -969,53 +1067,55 @@ static int resize_buckets(HashmapBase *h, unsigned entries_add); * Returns: true if it left a displaced entry to rehash next in IDX_PUT, * false otherwise. */ -static bool hashmap_put_robin_hood(HashmapBase *h, unsigned idx, - struct swap_entries *swap) { - dib_raw_t raw_dib, *dibs; - unsigned dib, distance; +static bool hashmap_put_robin_hood(HashmapBase * h, unsigned idx, + struct swap_entries *swap) +{ + dib_raw_t raw_dib, *dibs; + unsigned dib, distance; #ifdef ENABLE_DEBUG_HASHMAP - h->debug.put_count++; + h->debug.put_count++; #endif - dibs = dib_raw_ptr(h); + dibs = dib_raw_ptr(h); - for (distance = 0; ; distance++) { - raw_dib = dibs[idx]; - if (raw_dib == DIB_RAW_FREE || raw_dib == DIB_RAW_REHASH) { - if (raw_dib == DIB_RAW_REHASH) - bucket_move_entry(h, swap, idx, IDX_TMP); + for (distance = 0;; distance++) { + raw_dib = dibs[idx]; + if (raw_dib == DIB_RAW_FREE || raw_dib == DIB_RAW_REHASH) { + if (raw_dib == DIB_RAW_REHASH) + bucket_move_entry(h, swap, idx, IDX_TMP); - if (h->has_indirect && h->indirect.idx_lowest_entry > idx) - h->indirect.idx_lowest_entry = idx; + if (h->has_indirect + && h->indirect.idx_lowest_entry > idx) + h->indirect.idx_lowest_entry = idx; - bucket_set_dib(h, idx, distance); - bucket_move_entry(h, swap, IDX_PUT, idx); - if (raw_dib == DIB_RAW_REHASH) { - bucket_move_entry(h, swap, IDX_TMP, IDX_PUT); - return true; - } + bucket_set_dib(h, idx, distance); + bucket_move_entry(h, swap, IDX_PUT, idx); + if (raw_dib == DIB_RAW_REHASH) { + bucket_move_entry(h, swap, IDX_TMP, IDX_PUT); + return true; + } - return false; - } + return false; + } - dib = bucket_calculate_dib(h, idx, raw_dib); + dib = bucket_calculate_dib(h, idx, raw_dib); - if (dib < distance) { - /* Found a wealthier entry. Go Robin Hood! */ + if (dib < distance) { + /* Found a wealthier entry. Go Robin Hood! */ - bucket_set_dib(h, idx, distance); + bucket_set_dib(h, idx, distance); - /* swap the entries */ - bucket_move_entry(h, swap, idx, IDX_TMP); - bucket_move_entry(h, swap, IDX_PUT, idx); - bucket_move_entry(h, swap, IDX_TMP, IDX_PUT); + /* swap the entries */ + bucket_move_entry(h, swap, idx, IDX_TMP); + bucket_move_entry(h, swap, IDX_PUT, idx); + bucket_move_entry(h, swap, IDX_TMP, IDX_PUT); - distance = dib; - } + distance = dib; + } - idx = next_idx(h, idx); - } + idx = next_idx(h, idx); + } } /* @@ -1028,52 +1128,54 @@ static bool hashmap_put_robin_hood(HashmapBase *h, unsigned idx, * -ENOMEM if may_resize==true and resize failed with -ENOMEM. * Cannot return -ENOMEM if !may_resize. */ -static int hashmap_base_put_boldly(HashmapBase *h, unsigned idx, - struct swap_entries *swap, bool may_resize) { - struct ordered_hashmap_entry *new_entry; - int r; +static int hashmap_base_put_boldly(HashmapBase * h, unsigned idx, + struct swap_entries *swap, bool may_resize) +{ + struct ordered_hashmap_entry *new_entry; + int r; - assert(idx < n_buckets(h)); + assert(idx < n_buckets(h)); - new_entry = bucket_at_swap(swap, IDX_PUT); + new_entry = bucket_at_swap(swap, IDX_PUT); - if (may_resize) { - r = resize_buckets(h, 1); - if (r < 0) - return r; - if (r > 0) - idx = bucket_hash(h, new_entry->p.b.key); - } - assert(n_entries(h) < n_buckets(h)); + if (may_resize) { + r = resize_buckets(h, 1); + if (r < 0) + return r; + if (r > 0) + idx = bucket_hash(h, new_entry->p.b.key); + } + assert(n_entries(h) < n_buckets(h)); - if (h->type == HASHMAP_TYPE_ORDERED) { - OrderedHashmap *lh = (OrderedHashmap*) h; + if (h->type == HASHMAP_TYPE_ORDERED) { + OrderedHashmap *lh = (OrderedHashmap *) h; - new_entry->iterate_next = IDX_NIL; - new_entry->iterate_previous = lh->iterate_list_tail; + new_entry->iterate_next = IDX_NIL; + new_entry->iterate_previous = lh->iterate_list_tail; - if (lh->iterate_list_tail != IDX_NIL) { - struct ordered_hashmap_entry *old_tail; + if (lh->iterate_list_tail != IDX_NIL) { + struct ordered_hashmap_entry *old_tail; - old_tail = ordered_bucket_at(lh, lh->iterate_list_tail); - assert(old_tail->iterate_next == IDX_NIL); - old_tail->iterate_next = IDX_PUT; - } + old_tail = ordered_bucket_at(lh, lh->iterate_list_tail); + assert(old_tail->iterate_next == IDX_NIL); + old_tail->iterate_next = IDX_PUT; + } - lh->iterate_list_tail = IDX_PUT; - if (lh->iterate_list_head == IDX_NIL) - lh->iterate_list_head = IDX_PUT; - } + lh->iterate_list_tail = IDX_PUT; + if (lh->iterate_list_head == IDX_NIL) + lh->iterate_list_head = IDX_PUT; + } - assert_se(hashmap_put_robin_hood(h, idx, swap) == false); + assert_se(hashmap_put_robin_hood(h, idx, swap) == false); - n_entries_inc(h); + n_entries_inc(h); #ifdef ENABLE_DEBUG_HASHMAP - h->debug.max_entries = MAX(h->debug.max_entries, n_entries(h)); + h->debug.max_entries = MAX(h->debug.max_entries, n_entries(h)); #endif - return 1; + return 1; } + #define hashmap_put_boldly(h, idx, swap, may_resize) \ hashmap_base_put_boldly(HASHMAP_BASE(h), idx, swap, may_resize) @@ -1082,586 +1184,623 @@ static int hashmap_base_put_boldly(HashmapBase *h, unsigned idx, * 1 if successfully resized. * -ENOMEM on allocation failure. */ -static int resize_buckets(HashmapBase *h, unsigned entries_add) { - struct swap_entries swap; - char *new_storage; - dib_raw_t *old_dibs, *new_dibs; - const struct hashmap_type_info *hi; - unsigned idx, optimal_idx; - unsigned old_n_buckets, new_n_buckets, n_rehashed, new_n_entries; - uint8_t new_shift; - bool rehash_next; - - assert(h); - - hi = &hashmap_type_info[h->type]; - new_n_entries = n_entries(h) + entries_add; - - /* overflow? */ - if (_unlikely_(new_n_entries < entries_add)) - return -ENOMEM; - - /* For direct storage we allow 100% load, because it's tiny. */ - if (!h->has_indirect && new_n_entries <= hi->n_direct_buckets) - return 0; - - /* - * Load factor = n/m = 1 - (1/INV_KEEP_FREE). - * From it follows: m = n + n/(INV_KEEP_FREE - 1) - */ - new_n_buckets = new_n_entries + new_n_entries / (INV_KEEP_FREE - 1); - /* overflow? */ - if (_unlikely_(new_n_buckets < new_n_entries)) - return -ENOMEM; - - if (_unlikely_(new_n_buckets > UINT_MAX / (hi->entry_size + sizeof(dib_raw_t)))) - return -ENOMEM; - - old_n_buckets = n_buckets(h); - - if (_likely_(new_n_buckets <= old_n_buckets)) - return 0; - - new_shift = log2u_round_up(MAX( - new_n_buckets * (hi->entry_size + sizeof(dib_raw_t)), - 2 * sizeof(struct direct_storage))); - - /* Realloc storage (buckets and DIB array). */ - new_storage = realloc(h->has_indirect ? h->indirect.storage : NULL, - 1U << new_shift); - if (!new_storage) - return -ENOMEM; - - /* Must upgrade direct to indirect storage. */ - if (!h->has_indirect) { - memcpy(new_storage, h->direct.storage, - old_n_buckets * (hi->entry_size + sizeof(dib_raw_t))); - h->indirect.n_entries = h->n_direct_entries; - h->indirect.idx_lowest_entry = 0; - h->n_direct_entries = 0; - } - - /* Get a new hash key. If we've just upgraded to indirect storage, - * allow reusing a previously generated key. It's still a different key - * from the shared one that we used for direct storage. */ - get_hash_key(h->indirect.hash_key, !h->has_indirect); - - h->has_indirect = true; - h->indirect.storage = new_storage; - h->indirect.n_buckets = (1U << new_shift) / - (hi->entry_size + sizeof(dib_raw_t)); - - old_dibs = (dib_raw_t*)(new_storage + hi->entry_size * old_n_buckets); - new_dibs = dib_raw_ptr(h); - - /* - * Move the DIB array to the new place, replacing valid DIB values with - * DIB_RAW_REHASH to indicate all of the used buckets need rehashing. - * Note: Overlap is not possible, because we have at least doubled the - * number of buckets and dib_raw_t is smaller than any entry type. - */ - for (idx = 0; idx < old_n_buckets; idx++) { - assert(old_dibs[idx] != DIB_RAW_REHASH); - new_dibs[idx] = old_dibs[idx] == DIB_RAW_FREE ? DIB_RAW_FREE - : DIB_RAW_REHASH; - } - - /* Zero the area of newly added entries (including the old DIB area) */ - memzero(bucket_at(h, old_n_buckets), - (n_buckets(h) - old_n_buckets) * hi->entry_size); - - /* The upper half of the new DIB array needs initialization */ - memset(&new_dibs[old_n_buckets], DIB_RAW_INIT, - (n_buckets(h) - old_n_buckets) * sizeof(dib_raw_t)); - - /* Rehash entries that need it */ - n_rehashed = 0; - for (idx = 0; idx < old_n_buckets; idx++) { - if (new_dibs[idx] != DIB_RAW_REHASH) - continue; - - optimal_idx = bucket_hash(h, bucket_at(h, idx)->key); - - /* - * Not much to do if by luck the entry hashes to its current - * location. Just set its DIB. - */ - if (optimal_idx == idx) { - new_dibs[idx] = 0; - n_rehashed++; - continue; - } - - new_dibs[idx] = DIB_RAW_FREE; - bucket_move_entry(h, &swap, idx, IDX_PUT); - /* bucket_move_entry does not clear the source */ - memzero(bucket_at(h, idx), hi->entry_size); - - do { - /* - * Find the new bucket for the current entry. This may make - * another entry homeless and load it into IDX_PUT. - */ - rehash_next = hashmap_put_robin_hood(h, optimal_idx, &swap); - n_rehashed++; - - /* Did the current entry displace another one? */ - if (rehash_next) - optimal_idx = bucket_hash(h, bucket_at_swap(&swap, IDX_PUT)->p.b.key); - } while (rehash_next); - } - - assert(n_rehashed == n_entries(h)); - - return 1; +static int resize_buckets(HashmapBase * h, unsigned entries_add) +{ + struct swap_entries swap; + char *new_storage; + dib_raw_t *old_dibs, *new_dibs; + const struct hashmap_type_info *hi; + unsigned idx, optimal_idx; + unsigned old_n_buckets, new_n_buckets, n_rehashed, new_n_entries; + uint8_t new_shift; + bool rehash_next; + + assert(h); + + hi = &hashmap_type_info[h->type]; + new_n_entries = n_entries(h) + entries_add; + + /* overflow? */ + if (_unlikely_(new_n_entries < entries_add)) + return -ENOMEM; + + /* For direct storage we allow 100% load, because it's tiny. */ + if (!h->has_indirect && new_n_entries <= hi->n_direct_buckets) + return 0; + + /* + * Load factor = n/m = 1 - (1/INV_KEEP_FREE). + * From it follows: m = n + n/(INV_KEEP_FREE - 1) + */ + new_n_buckets = new_n_entries + new_n_entries / (INV_KEEP_FREE - 1); + /* overflow? */ + if (_unlikely_(new_n_buckets < new_n_entries)) + return -ENOMEM; + + if (_unlikely_ + (new_n_buckets > UINT_MAX / (hi->entry_size + sizeof(dib_raw_t)))) + return -ENOMEM; + + old_n_buckets = n_buckets(h); + + if (_likely_(new_n_buckets <= old_n_buckets)) + return 0; + + new_shift = + log2u_round_up(MAX + (new_n_buckets * + (hi->entry_size + sizeof(dib_raw_t)), + 2 * sizeof(struct direct_storage))); + + /* Realloc storage (buckets and DIB array). */ + new_storage = realloc(h->has_indirect ? h->indirect.storage : NULL, + 1U << new_shift); + if (!new_storage) + return -ENOMEM; + + /* Must upgrade direct to indirect storage. */ + if (!h->has_indirect) { + memcpy(new_storage, h->direct.storage, + old_n_buckets * (hi->entry_size + sizeof(dib_raw_t))); + h->indirect.n_entries = h->n_direct_entries; + h->indirect.idx_lowest_entry = 0; + h->n_direct_entries = 0; + } + + /* Get a new hash key. If we've just upgraded to indirect storage, + * allow reusing a previously generated key. It's still a different key + * from the shared one that we used for direct storage. */ + get_hash_key(h->indirect.hash_key, !h->has_indirect); + + h->has_indirect = true; + h->indirect.storage = new_storage; + h->indirect.n_buckets = (1U << new_shift) / + (hi->entry_size + sizeof(dib_raw_t)); + + old_dibs = (dib_raw_t *) (new_storage + hi->entry_size * old_n_buckets); + new_dibs = dib_raw_ptr(h); + + /* + * Move the DIB array to the new place, replacing valid DIB values with + * DIB_RAW_REHASH to indicate all of the used buckets need rehashing. + * Note: Overlap is not possible, because we have at least doubled the + * number of buckets and dib_raw_t is smaller than any entry type. + */ + for (idx = 0; idx < old_n_buckets; idx++) { + assert(old_dibs[idx] != DIB_RAW_REHASH); + new_dibs[idx] = old_dibs[idx] == DIB_RAW_FREE ? DIB_RAW_FREE + : DIB_RAW_REHASH; + } + + /* Zero the area of newly added entries (including the old DIB area) */ + memzero(bucket_at(h, old_n_buckets), + (n_buckets(h) - old_n_buckets) * hi->entry_size); + + /* The upper half of the new DIB array needs initialization */ + memset(&new_dibs[old_n_buckets], DIB_RAW_INIT, + (n_buckets(h) - old_n_buckets) * sizeof(dib_raw_t)); + + /* Rehash entries that need it */ + n_rehashed = 0; + for (idx = 0; idx < old_n_buckets; idx++) { + if (new_dibs[idx] != DIB_RAW_REHASH) + continue; + + optimal_idx = bucket_hash(h, bucket_at(h, idx)->key); + + /* + * Not much to do if by luck the entry hashes to its current + * location. Just set its DIB. + */ + if (optimal_idx == idx) { + new_dibs[idx] = 0; + n_rehashed++; + continue; + } + + new_dibs[idx] = DIB_RAW_FREE; + bucket_move_entry(h, &swap, idx, IDX_PUT); + /* bucket_move_entry does not clear the source */ + memzero(bucket_at(h, idx), hi->entry_size); + + do { + /* + * Find the new bucket for the current entry. This may make + * another entry homeless and load it into IDX_PUT. + */ + rehash_next = + hashmap_put_robin_hood(h, optimal_idx, &swap); + n_rehashed++; + + /* Did the current entry displace another one? */ + if (rehash_next) + optimal_idx = + bucket_hash(h, + bucket_at_swap(&swap, + IDX_PUT)->p.b. + key); + } while (rehash_next); + } + + assert(n_rehashed == n_entries(h)); + + return 1; } /* * Finds an entry with a matching key * Returns: index of the found entry, or IDX_NIL if not found. */ -static unsigned base_bucket_scan(HashmapBase *h, unsigned idx, const void *key) { - struct hashmap_base_entry *e; - unsigned dib, distance; - dib_raw_t *dibs = dib_raw_ptr(h); +static unsigned base_bucket_scan(HashmapBase * h, unsigned idx, const void *key) +{ + struct hashmap_base_entry *e; + unsigned dib, distance; + dib_raw_t *dibs = dib_raw_ptr(h); - assert(idx < n_buckets(h)); + assert(idx < n_buckets(h)); - for (distance = 0; ; distance++) { - if (dibs[idx] == DIB_RAW_FREE) - return IDX_NIL; + for (distance = 0;; distance++) { + if (dibs[idx] == DIB_RAW_FREE) + return IDX_NIL; - dib = bucket_calculate_dib(h, idx, dibs[idx]); + dib = bucket_calculate_dib(h, idx, dibs[idx]); - if (dib < distance) - return IDX_NIL; - if (dib == distance) { - e = bucket_at(h, idx); - if (h->hash_ops->compare(e->key, key) == 0) - return idx; - } + if (dib < distance) + return IDX_NIL; + if (dib == distance) { + e = bucket_at(h, idx); + if (h->hash_ops->compare(e->key, key) == 0) + return idx; + } - idx = next_idx(h, idx); - } + idx = next_idx(h, idx); + } } + #define bucket_scan(h, idx, key) base_bucket_scan(HASHMAP_BASE(h), idx, key) -int hashmap_put(Hashmap *h, const void *key, void *value) { - struct swap_entries swap; - struct plain_hashmap_entry *e; - unsigned hash, idx; +int hashmap_put(Hashmap * h, const void *key, void *value) +{ + struct swap_entries swap; + struct plain_hashmap_entry *e; + unsigned hash, idx; - assert(h); + assert(h); - hash = bucket_hash(h, key); - idx = bucket_scan(h, hash, key); - if (idx != IDX_NIL) { - e = plain_bucket_at(h, idx); - if (e->value == value) - return 0; - return -EEXIST; - } + hash = bucket_hash(h, key); + idx = bucket_scan(h, hash, key); + if (idx != IDX_NIL) { + e = plain_bucket_at(h, idx); + if (e->value == value) + return 0; + return -EEXIST; + } - e = &bucket_at_swap(&swap, IDX_PUT)->p; - e->b.key = key; - e->value = value; - return hashmap_put_boldly(h, hash, &swap, true); + e = &bucket_at_swap(&swap, IDX_PUT)->p; + e->b.key = key; + e->value = value; + return hashmap_put_boldly(h, hash, &swap, true); } -int set_put(Set *s, const void *key) { - struct swap_entries swap; - struct hashmap_base_entry *e; - unsigned hash, idx; +int set_put(Set * s, const void *key) +{ + struct swap_entries swap; + struct hashmap_base_entry *e; + unsigned hash, idx; - assert(s); + assert(s); - hash = bucket_hash(s, key); - idx = bucket_scan(s, hash, key); - if (idx != IDX_NIL) - return 0; + hash = bucket_hash(s, key); + idx = bucket_scan(s, hash, key); + if (idx != IDX_NIL) + return 0; - e = &bucket_at_swap(&swap, IDX_PUT)->p.b; - e->key = key; - return hashmap_put_boldly(s, hash, &swap, true); + e = &bucket_at_swap(&swap, IDX_PUT)->p.b; + e->key = key; + return hashmap_put_boldly(s, hash, &swap, true); } -int hashmap_replace(Hashmap *h, const void *key, void *value) { - struct swap_entries swap; - struct plain_hashmap_entry *e; - unsigned hash, idx; +int hashmap_replace(Hashmap * h, const void *key, void *value) +{ + struct swap_entries swap; + struct plain_hashmap_entry *e; + unsigned hash, idx; - assert(h); + assert(h); - hash = bucket_hash(h, key); - idx = bucket_scan(h, hash, key); - if (idx != IDX_NIL) { - e = plain_bucket_at(h, idx); + hash = bucket_hash(h, key); + idx = bucket_scan(h, hash, key); + if (idx != IDX_NIL) { + e = plain_bucket_at(h, idx); #ifdef ENABLE_DEBUG_HASHMAP - /* Although the key is equal, the key pointer may have changed, - * and this would break our assumption for iterating. So count - * this operation as incompatible with iteration. */ - if (e->b.key != key) { - h->b.debug.put_count++; - h->b.debug.rem_count++; - h->b.debug.last_rem_idx = idx; - } + /* Although the key is equal, the key pointer may have changed, + * and this would break our assumption for iterating. So count + * this operation as incompatible with iteration. */ + if (e->b.key != key) { + h->b.debug.put_count++; + h->b.debug.rem_count++; + h->b.debug.last_rem_idx = idx; + } #endif - e->b.key = key; - e->value = value; - return 0; - } + e->b.key = key; + e->value = value; + return 0; + } - e = &bucket_at_swap(&swap, IDX_PUT)->p; - e->b.key = key; - e->value = value; - return hashmap_put_boldly(h, hash, &swap, true); + e = &bucket_at_swap(&swap, IDX_PUT)->p; + e->b.key = key; + e->value = value; + return hashmap_put_boldly(h, hash, &swap, true); } -int hashmap_update(Hashmap *h, const void *key, void *value) { - struct plain_hashmap_entry *e; - unsigned hash, idx; +int hashmap_update(Hashmap * h, const void *key, void *value) +{ + struct plain_hashmap_entry *e; + unsigned hash, idx; - assert(h); + assert(h); - hash = bucket_hash(h, key); - idx = bucket_scan(h, hash, key); - if (idx == IDX_NIL) - return -ENOENT; + hash = bucket_hash(h, key); + idx = bucket_scan(h, hash, key); + if (idx == IDX_NIL) + return -ENOENT; - e = plain_bucket_at(h, idx); - e->value = value; - return 0; + e = plain_bucket_at(h, idx); + e->value = value; + return 0; } -void *internal_hashmap_get(HashmapBase *h, const void *key) { - struct hashmap_base_entry *e; - unsigned hash, idx; +void *internal_hashmap_get(HashmapBase * h, const void *key) +{ + struct hashmap_base_entry *e; + unsigned hash, idx; - if (!h) - return NULL; + if (!h) + return NULL; - hash = bucket_hash(h, key); - idx = bucket_scan(h, hash, key); - if (idx == IDX_NIL) - return NULL; + hash = bucket_hash(h, key); + idx = bucket_scan(h, hash, key); + if (idx == IDX_NIL) + return NULL; - e = bucket_at(h, idx); - return entry_value(h, e); + e = bucket_at(h, idx); + return entry_value(h, e); } -void *hashmap_get2(Hashmap *h, const void *key, void **key2) { - struct plain_hashmap_entry *e; - unsigned hash, idx; +void *hashmap_get2(Hashmap * h, const void *key, void **key2) +{ + struct plain_hashmap_entry *e; + unsigned hash, idx; - if (!h) - return NULL; + if (!h) + return NULL; - hash = bucket_hash(h, key); - idx = bucket_scan(h, hash, key); - if (idx == IDX_NIL) - return NULL; + hash = bucket_hash(h, key); + idx = bucket_scan(h, hash, key); + if (idx == IDX_NIL) + return NULL; - e = plain_bucket_at(h, idx); - if (key2) - *key2 = (void*) e->b.key; + e = plain_bucket_at(h, idx); + if (key2) + *key2 = (void *)e->b.key; - return e->value; + return e->value; } -bool internal_hashmap_contains(HashmapBase *h, const void *key) { - unsigned hash; +bool internal_hashmap_contains(HashmapBase * h, const void *key) +{ + unsigned hash; - if (!h) - return false; + if (!h) + return false; - hash = bucket_hash(h, key); - return bucket_scan(h, hash, key) != IDX_NIL; + hash = bucket_hash(h, key); + return bucket_scan(h, hash, key) != IDX_NIL; } -void *internal_hashmap_remove(HashmapBase *h, const void *key) { - struct hashmap_base_entry *e; - unsigned hash, idx; - void *data; +void *internal_hashmap_remove(HashmapBase * h, const void *key) +{ + struct hashmap_base_entry *e; + unsigned hash, idx; + void *data; - if (!h) - return NULL; + if (!h) + return NULL; - hash = bucket_hash(h, key); - idx = bucket_scan(h, hash, key); - if (idx == IDX_NIL) - return NULL; + hash = bucket_hash(h, key); + idx = bucket_scan(h, hash, key); + if (idx == IDX_NIL) + return NULL; - e = bucket_at(h, idx); - data = entry_value(h, e); - remove_entry(h, idx); + e = bucket_at(h, idx); + data = entry_value(h, e); + remove_entry(h, idx); - return data; + return data; } -void *hashmap_remove2(Hashmap *h, const void *key, void **rkey) { - struct plain_hashmap_entry *e; - unsigned hash, idx; - void *data; +void *hashmap_remove2(Hashmap * h, const void *key, void **rkey) +{ + struct plain_hashmap_entry *e; + unsigned hash, idx; + void *data; - if (!h) { - if (rkey) - *rkey = NULL; - return NULL; - } + if (!h) { + if (rkey) + *rkey = NULL; + return NULL; + } - hash = bucket_hash(h, key); - idx = bucket_scan(h, hash, key); - if (idx == IDX_NIL) { - if (rkey) - *rkey = NULL; - return NULL; - } + hash = bucket_hash(h, key); + idx = bucket_scan(h, hash, key); + if (idx == IDX_NIL) { + if (rkey) + *rkey = NULL; + return NULL; + } - e = plain_bucket_at(h, idx); - data = e->value; - if (rkey) - *rkey = (void*) e->b.key; + e = plain_bucket_at(h, idx); + data = e->value; + if (rkey) + *rkey = (void *)e->b.key; - remove_entry(h, idx); + remove_entry(h, idx); - return data; + return data; } -int hashmap_remove_and_put(Hashmap *h, const void *old_key, const void *new_key, void *value) { - struct swap_entries swap; - struct plain_hashmap_entry *e; - unsigned old_hash, new_hash, idx; +int hashmap_remove_and_put(Hashmap * h, const void *old_key, + const void *new_key, void *value) +{ + struct swap_entries swap; + struct plain_hashmap_entry *e; + unsigned old_hash, new_hash, idx; - if (!h) - return -ENOENT; + if (!h) + return -ENOENT; - old_hash = bucket_hash(h, old_key); - idx = bucket_scan(h, old_hash, old_key); - if (idx == IDX_NIL) - return -ENOENT; + old_hash = bucket_hash(h, old_key); + idx = bucket_scan(h, old_hash, old_key); + if (idx == IDX_NIL) + return -ENOENT; - new_hash = bucket_hash(h, new_key); - if (bucket_scan(h, new_hash, new_key) != IDX_NIL) - return -EEXIST; + new_hash = bucket_hash(h, new_key); + if (bucket_scan(h, new_hash, new_key) != IDX_NIL) + return -EEXIST; - remove_entry(h, idx); + remove_entry(h, idx); - e = &bucket_at_swap(&swap, IDX_PUT)->p; - e->b.key = new_key; - e->value = value; - assert_se(hashmap_put_boldly(h, new_hash, &swap, false) == 1); + e = &bucket_at_swap(&swap, IDX_PUT)->p; + e->b.key = new_key; + e->value = value; + assert_se(hashmap_put_boldly(h, new_hash, &swap, false) == 1); - return 0; + return 0; } -int set_remove_and_put(Set *s, const void *old_key, const void *new_key) { - struct swap_entries swap; - struct hashmap_base_entry *e; - unsigned old_hash, new_hash, idx; +int set_remove_and_put(Set * s, const void *old_key, const void *new_key) +{ + struct swap_entries swap; + struct hashmap_base_entry *e; + unsigned old_hash, new_hash, idx; - if (!s) - return -ENOENT; + if (!s) + return -ENOENT; - old_hash = bucket_hash(s, old_key); - idx = bucket_scan(s, old_hash, old_key); - if (idx == IDX_NIL) - return -ENOENT; + old_hash = bucket_hash(s, old_key); + idx = bucket_scan(s, old_hash, old_key); + if (idx == IDX_NIL) + return -ENOENT; - new_hash = bucket_hash(s, new_key); - if (bucket_scan(s, new_hash, new_key) != IDX_NIL) - return -EEXIST; + new_hash = bucket_hash(s, new_key); + if (bucket_scan(s, new_hash, new_key) != IDX_NIL) + return -EEXIST; - remove_entry(s, idx); + remove_entry(s, idx); - e = &bucket_at_swap(&swap, IDX_PUT)->p.b; - e->key = new_key; - assert_se(hashmap_put_boldly(s, new_hash, &swap, false) == 1); + e = &bucket_at_swap(&swap, IDX_PUT)->p.b; + e->key = new_key; + assert_se(hashmap_put_boldly(s, new_hash, &swap, false) == 1); - return 0; + return 0; } -int hashmap_remove_and_replace(Hashmap *h, const void *old_key, const void *new_key, void *value) { - struct swap_entries swap; - struct plain_hashmap_entry *e; - unsigned old_hash, new_hash, idx_old, idx_new; +int hashmap_remove_and_replace(Hashmap * h, const void *old_key, + const void *new_key, void *value) +{ + struct swap_entries swap; + struct plain_hashmap_entry *e; + unsigned old_hash, new_hash, idx_old, idx_new; - if (!h) - return -ENOENT; + if (!h) + return -ENOENT; - old_hash = bucket_hash(h, old_key); - idx_old = bucket_scan(h, old_hash, old_key); - if (idx_old == IDX_NIL) - return -ENOENT; + old_hash = bucket_hash(h, old_key); + idx_old = bucket_scan(h, old_hash, old_key); + if (idx_old == IDX_NIL) + return -ENOENT; - old_key = bucket_at(HASHMAP_BASE(h), idx_old)->key; + old_key = bucket_at(HASHMAP_BASE(h), idx_old)->key; - new_hash = bucket_hash(h, new_key); - idx_new = bucket_scan(h, new_hash, new_key); - if (idx_new != IDX_NIL) - if (idx_old != idx_new) { - remove_entry(h, idx_new); - /* Compensate for a possible backward shift. */ - if (old_key != bucket_at(HASHMAP_BASE(h), idx_old)->key) - idx_old = prev_idx(HASHMAP_BASE(h), idx_old); - assert(old_key == bucket_at(HASHMAP_BASE(h), idx_old)->key); - } + new_hash = bucket_hash(h, new_key); + idx_new = bucket_scan(h, new_hash, new_key); + if (idx_new != IDX_NIL) + if (idx_old != idx_new) { + remove_entry(h, idx_new); + /* Compensate for a possible backward shift. */ + if (old_key != bucket_at(HASHMAP_BASE(h), idx_old)->key) + idx_old = prev_idx(HASHMAP_BASE(h), idx_old); + assert(old_key == + bucket_at(HASHMAP_BASE(h), idx_old)->key); + } - remove_entry(h, idx_old); + remove_entry(h, idx_old); - e = &bucket_at_swap(&swap, IDX_PUT)->p; - e->b.key = new_key; - e->value = value; - assert_se(hashmap_put_boldly(h, new_hash, &swap, false) == 1); + e = &bucket_at_swap(&swap, IDX_PUT)->p; + e->b.key = new_key; + e->value = value; + assert_se(hashmap_put_boldly(h, new_hash, &swap, false) == 1); - return 0; + return 0; } -void *hashmap_remove_value(Hashmap *h, const void *key, void *value) { - struct plain_hashmap_entry *e; - unsigned hash, idx; +void *hashmap_remove_value(Hashmap * h, const void *key, void *value) +{ + struct plain_hashmap_entry *e; + unsigned hash, idx; - if (!h) - return NULL; + if (!h) + return NULL; - hash = bucket_hash(h, key); - idx = bucket_scan(h, hash, key); - if (idx == IDX_NIL) - return NULL; + hash = bucket_hash(h, key); + idx = bucket_scan(h, hash, key); + if (idx == IDX_NIL) + return NULL; - e = plain_bucket_at(h, idx); - if (e->value != value) - return NULL; + e = plain_bucket_at(h, idx); + if (e->value != value) + return NULL; - remove_entry(h, idx); + remove_entry(h, idx); - return value; + return value; } -static unsigned find_first_entry(HashmapBase *h) { - Iterator i = ITERATOR_FIRST; +static unsigned find_first_entry(HashmapBase * h) +{ + Iterator i = ITERATOR_FIRST; - if (!h || !n_entries(h)) - return IDX_NIL; + if (!h || !n_entries(h)) + return IDX_NIL; - return hashmap_iterate_entry(h, &i); + return hashmap_iterate_entry(h, &i); } -void *internal_hashmap_first(HashmapBase *h) { - unsigned idx; +void *internal_hashmap_first(HashmapBase * h) +{ + unsigned idx; - idx = find_first_entry(h); - if (idx == IDX_NIL) - return NULL; + idx = find_first_entry(h); + if (idx == IDX_NIL) + return NULL; - return entry_value(h, bucket_at(h, idx)); + return entry_value(h, bucket_at(h, idx)); } -void *internal_hashmap_first_key(HashmapBase *h) { - struct hashmap_base_entry *e; - unsigned idx; +void *internal_hashmap_first_key(HashmapBase * h) +{ + struct hashmap_base_entry *e; + unsigned idx; - idx = find_first_entry(h); - if (idx == IDX_NIL) - return NULL; + idx = find_first_entry(h); + if (idx == IDX_NIL) + return NULL; - e = bucket_at(h, idx); - return (void*) e->key; + e = bucket_at(h, idx); + return (void *)e->key; } -void *internal_hashmap_steal_first(HashmapBase *h) { - struct hashmap_base_entry *e; - void *data; - unsigned idx; +void *internal_hashmap_steal_first(HashmapBase * h) +{ + struct hashmap_base_entry *e; + void *data; + unsigned idx; - idx = find_first_entry(h); - if (idx == IDX_NIL) - return NULL; + idx = find_first_entry(h); + if (idx == IDX_NIL) + return NULL; - e = bucket_at(h, idx); - data = entry_value(h, e); - remove_entry(h, idx); + e = bucket_at(h, idx); + data = entry_value(h, e); + remove_entry(h, idx); - return data; + return data; } -void *internal_hashmap_steal_first_key(HashmapBase *h) { - struct hashmap_base_entry *e; - void *key; - unsigned idx; +void *internal_hashmap_steal_first_key(HashmapBase * h) +{ + struct hashmap_base_entry *e; + void *key; + unsigned idx; - idx = find_first_entry(h); - if (idx == IDX_NIL) - return NULL; + idx = find_first_entry(h); + if (idx == IDX_NIL) + return NULL; - e = bucket_at(h, idx); - key = (void*) e->key; - remove_entry(h, idx); + e = bucket_at(h, idx); + key = (void *)e->key; + remove_entry(h, idx); - return key; + return key; } -unsigned internal_hashmap_size(HashmapBase *h) { +unsigned internal_hashmap_size(HashmapBase * h) +{ - if (!h) - return 0; + if (!h) + return 0; - return n_entries(h); + return n_entries(h); } -unsigned internal_hashmap_buckets(HashmapBase *h) { +unsigned internal_hashmap_buckets(HashmapBase * h) +{ - if (!h) - return 0; + if (!h) + return 0; - return n_buckets(h); + return n_buckets(h); } -int internal_hashmap_merge(Hashmap *h, Hashmap *other) { - Iterator i; - unsigned idx; +int internal_hashmap_merge(Hashmap * h, Hashmap * other) +{ + Iterator i; + unsigned idx; - assert(h); + assert(h); - HASHMAP_FOREACH_IDX(idx, HASHMAP_BASE(other), i) { - struct plain_hashmap_entry *pe = plain_bucket_at(other, idx); - int r; + HASHMAP_FOREACH_IDX(idx, HASHMAP_BASE(other), i) { + struct plain_hashmap_entry *pe = plain_bucket_at(other, idx); + int r; - r = hashmap_put(h, pe->b.key, pe->value); - if (r < 0 && r != -EEXIST) - return r; - } + r = hashmap_put(h, pe->b.key, pe->value); + if (r < 0 && r != -EEXIST) + return r; + } - return 0; + return 0; } -int set_merge(Set *s, Set *other) { - Iterator i; - unsigned idx; +int set_merge(Set * s, Set * other) +{ + Iterator i; + unsigned idx; - assert(s); + assert(s); - HASHMAP_FOREACH_IDX(idx, HASHMAP_BASE(other), i) { - struct set_entry *se = set_bucket_at(other, idx); - int r; + HASHMAP_FOREACH_IDX(idx, HASHMAP_BASE(other), i) { + struct set_entry *se = set_bucket_at(other, idx); + int r; - r = set_put(s, se->b.key); - if (r < 0) - return r; - } + r = set_put(s, se->b.key); + if (r < 0) + return r; + } - return 0; + return 0; } -int internal_hashmap_reserve(HashmapBase *h, unsigned entries_add) { - int r; +int internal_hashmap_reserve(HashmapBase * h, unsigned entries_add) +{ + int r; - assert(h); + assert(h); - r = resize_buckets(h, entries_add); - if (r < 0) - return r; + r = resize_buckets(h, entries_add); + if (r < 0) + return r; - return 0; + return 0; } /* @@ -1670,194 +1809,203 @@ int internal_hashmap_reserve(HashmapBase *h, unsigned entries_add) { * Returns: 0 on success. * -ENOMEM on alloc failure, in which case no move has been done. */ -int internal_hashmap_move(HashmapBase *h, HashmapBase *other) { - struct swap_entries swap; - struct hashmap_base_entry *e, *n; - Iterator i; - unsigned idx; - int r; - - assert(h); - - if (!other) - return 0; - - assert(other->type == h->type); - - /* - * This reserves buckets for the worst case, where none of other's - * entries are yet present in h. This is preferable to risking - * an allocation failure in the middle of the moving and having to - * rollback or return a partial result. - */ - r = resize_buckets(h, n_entries(other)); - if (r < 0) - return r; - - HASHMAP_FOREACH_IDX(idx, other, i) { - unsigned h_hash; - - e = bucket_at(other, idx); - h_hash = bucket_hash(h, e->key); - if (bucket_scan(h, h_hash, e->key) != IDX_NIL) - continue; - - n = &bucket_at_swap(&swap, IDX_PUT)->p.b; - n->key = e->key; - if (h->type != HASHMAP_TYPE_SET) - ((struct plain_hashmap_entry*) n)->value = - ((struct plain_hashmap_entry*) e)->value; - assert_se(hashmap_put_boldly(h, h_hash, &swap, false) == 1); - - remove_entry(other, idx); - } +int internal_hashmap_move(HashmapBase * h, HashmapBase * other) +{ + struct swap_entries swap; + struct hashmap_base_entry *e, *n; + Iterator i; + unsigned idx; + int r; + + assert(h); + + if (!other) + return 0; + + assert(other->type == h->type); + + /* + * This reserves buckets for the worst case, where none of other's + * entries are yet present in h. This is preferable to risking + * an allocation failure in the middle of the moving and having to + * rollback or return a partial result. + */ + r = resize_buckets(h, n_entries(other)); + if (r < 0) + return r; + + HASHMAP_FOREACH_IDX(idx, other, i) { + unsigned h_hash; + + e = bucket_at(other, idx); + h_hash = bucket_hash(h, e->key); + if (bucket_scan(h, h_hash, e->key) != IDX_NIL) + continue; + + n = &bucket_at_swap(&swap, IDX_PUT)->p.b; + n->key = e->key; + if (h->type != HASHMAP_TYPE_SET) + ((struct plain_hashmap_entry *)n)->value = + ((struct plain_hashmap_entry *)e)->value; + assert_se(hashmap_put_boldly(h, h_hash, &swap, false) == 1); + + remove_entry(other, idx); + } - return 0; + return 0; } -int internal_hashmap_move_one(HashmapBase *h, HashmapBase *other, const void *key) { - struct swap_entries swap; - unsigned h_hash, other_hash, idx; - struct hashmap_base_entry *e, *n; - int r; +int internal_hashmap_move_one(HashmapBase * h, HashmapBase * other, + const void *key) +{ + struct swap_entries swap; + unsigned h_hash, other_hash, idx; + struct hashmap_base_entry *e, *n; + int r; - assert(h); + assert(h); - h_hash = bucket_hash(h, key); - if (bucket_scan(h, h_hash, key) != IDX_NIL) - return -EEXIST; + h_hash = bucket_hash(h, key); + if (bucket_scan(h, h_hash, key) != IDX_NIL) + return -EEXIST; - if (!other) - return -ENOENT; + if (!other) + return -ENOENT; - assert(other->type == h->type); + assert(other->type == h->type); - other_hash = bucket_hash(other, key); - idx = bucket_scan(other, other_hash, key); - if (idx == IDX_NIL) - return -ENOENT; + other_hash = bucket_hash(other, key); + idx = bucket_scan(other, other_hash, key); + if (idx == IDX_NIL) + return -ENOENT; - e = bucket_at(other, idx); + e = bucket_at(other, idx); - n = &bucket_at_swap(&swap, IDX_PUT)->p.b; - n->key = e->key; - if (h->type != HASHMAP_TYPE_SET) - ((struct plain_hashmap_entry*) n)->value = - ((struct plain_hashmap_entry*) e)->value; - r = hashmap_put_boldly(h, h_hash, &swap, true); - if (r < 0) - return r; + n = &bucket_at_swap(&swap, IDX_PUT)->p.b; + n->key = e->key; + if (h->type != HASHMAP_TYPE_SET) + ((struct plain_hashmap_entry *)n)->value = + ((struct plain_hashmap_entry *)e)->value; + r = hashmap_put_boldly(h, h_hash, &swap, true); + if (r < 0) + return r; - remove_entry(other, idx); - return 0; + remove_entry(other, idx); + return 0; } -HashmapBase *internal_hashmap_copy(HashmapBase *h) { - HashmapBase *copy; - int r; +HashmapBase *internal_hashmap_copy(HashmapBase * h) +{ + HashmapBase *copy; + int r; - assert(h); + assert(h); - copy = hashmap_base_new(h->hash_ops, h->type HASHMAP_DEBUG_SRC_ARGS); - if (!copy) - return NULL; + copy = hashmap_base_new(h->hash_ops, h->type HASHMAP_DEBUG_SRC_ARGS); + if (!copy) + return NULL; - switch (h->type) { - case HASHMAP_TYPE_PLAIN: - case HASHMAP_TYPE_ORDERED: - r = hashmap_merge((Hashmap*)copy, (Hashmap*)h); - break; - case HASHMAP_TYPE_SET: - r = set_merge((Set*)copy, (Set*)h); - break; - default: - assert_not_reached("Unknown hashmap type"); - } + switch (h->type) { + case HASHMAP_TYPE_PLAIN: + case HASHMAP_TYPE_ORDERED: + r = hashmap_merge((Hashmap *) copy, (Hashmap *) h); + break; + case HASHMAP_TYPE_SET: + r = set_merge((Set *) copy, (Set *) h); + break; + default: + assert_not_reached("Unknown hashmap type"); + } - if (r < 0) { - internal_hashmap_free(copy); - return NULL; - } + if (r < 0) { + internal_hashmap_free(copy); + return NULL; + } - return copy; + return copy; } -char **internal_hashmap_get_strv(HashmapBase *h) { - char **sv; - Iterator i; - unsigned idx, n; +char **internal_hashmap_get_strv(HashmapBase * h) +{ + char **sv; + Iterator i; + unsigned idx, n; - sv = new(char*, n_entries(h)+1); - if (!sv) - return NULL; + sv = new(char *, n_entries(h) + 1); + if (!sv) + return NULL; - n = 0; - HASHMAP_FOREACH_IDX(idx, h, i) - sv[n++] = entry_value(h, bucket_at(h, idx)); - sv[n] = NULL; + n = 0; + HASHMAP_FOREACH_IDX(idx, h, i) + sv[n++] = entry_value(h, bucket_at(h, idx)); + sv[n] = NULL; - return sv; + return sv; } -void *ordered_hashmap_next(OrderedHashmap *h, const void *key) { - struct ordered_hashmap_entry *e; - unsigned hash, idx; +void *ordered_hashmap_next(OrderedHashmap * h, const void *key) +{ + struct ordered_hashmap_entry *e; + unsigned hash, idx; - assert(key); + assert(key); - if (!h) - return NULL; + if (!h) + return NULL; - hash = bucket_hash(h, key); - idx = bucket_scan(h, hash, key); - if (idx == IDX_NIL) - return NULL; + hash = bucket_hash(h, key); + idx = bucket_scan(h, hash, key); + if (idx == IDX_NIL) + return NULL; - e = ordered_bucket_at(h, idx); - if (e->iterate_next == IDX_NIL) - return NULL; - return ordered_bucket_at(h, e->iterate_next)->p.value; + e = ordered_bucket_at(h, idx); + if (e->iterate_next == IDX_NIL) + return NULL; + return ordered_bucket_at(h, e->iterate_next)->p.value; } -int set_consume(Set *s, void *value) { - int r; +int set_consume(Set * s, void *value) +{ + int r; - r = set_put(s, value); - if (r <= 0) - free(value); + r = set_put(s, value); + if (r <= 0) + free(value); - return r; + return r; } -int set_put_strdup(Set *s, const char *p) { - char *c; - int r; +int set_put_strdup(Set * s, const char *p) +{ + char *c; + int r; - assert(s); - assert(p); + assert(s); + assert(p); - c = strdup(p); - if (!c) - return -ENOMEM; + c = strdup(p); + if (!c) + return -ENOMEM; - r = set_consume(s, c); - if (r == -EEXIST) - return 0; + r = set_consume(s, c); + if (r == -EEXIST) + return 0; - return r; + return r; } -int set_put_strdupv(Set *s, char **l) { - int n = 0, r; - char **i; +int set_put_strdupv(Set * s, char **l) +{ + int n = 0, r; + char **i; - STRV_FOREACH(i, l) { - r = set_put_strdup(s, *i); - if (r < 0) - return r; + STRV_FOREACH(i, l) { + r = set_put_strdup(s, *i); + if (r < 0) + return r; - n += r; - } + n += r; + } - return n; + return n; } diff --git a/libudev-compat/hashmap.h b/libudev-compat/hashmap.h index 1587e98..fd060bb 100644 --- a/libudev-compat/hashmap.h +++ b/libudev-compat/hashmap.h @@ -57,60 +57,65 @@ typedef struct HashmapBase HashmapBase; /* Specific hashmap/set types */ -typedef struct Hashmap Hashmap; /* Maps keys to values */ -typedef struct OrderedHashmap OrderedHashmap; /* Like Hashmap, but also remembers entry insertion order */ -typedef struct Set Set; /* Stores just keys */ +typedef struct Hashmap Hashmap; /* Maps keys to values */ +typedef struct OrderedHashmap OrderedHashmap; /* Like Hashmap, but also remembers entry insertion order */ +typedef struct Set Set; /* Stores just keys */ /* Ideally the Iterator would be an opaque struct, but it is instantiated * by hashmap users, so the definition has to be here. Do not use its fields * directly. */ typedef struct { - unsigned idx; /* index of an entry to be iterated next */ - const void *next_key; /* expected value of that entry's key pointer */ + unsigned idx; /* index of an entry to be iterated next */ + const void *next_key; /* expected value of that entry's key pointer */ #ifdef ENABLE_DEBUG_HASHMAP - unsigned put_count; /* hashmap's put_count recorded at start of iteration */ - unsigned rem_count; /* hashmap's rem_count in previous iteration */ - unsigned prev_idx; /* idx in previous iteration */ + unsigned put_count; /* hashmap's put_count recorded at start of iteration */ + unsigned rem_count; /* hashmap's rem_count in previous iteration */ + unsigned prev_idx; /* idx in previous iteration */ #endif } Iterator; #define _IDX_ITERATOR_FIRST (UINT_MAX - 1) #define ITERATOR_FIRST ((Iterator) { .idx = _IDX_ITERATOR_FIRST, .next_key = NULL }) -typedef unsigned long (*hash_func_t)(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]); -typedef int (*compare_func_t)(const void *a, const void *b); +typedef unsigned long (*hash_func_t) (const void *p, + const uint8_t hash_key[HASH_KEY_SIZE]); +typedef int (*compare_func_t) (const void *a, const void *b); struct hash_ops { - hash_func_t hash; - compare_func_t compare; + hash_func_t hash; + compare_func_t compare; }; -unsigned long string_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) _pure_; +unsigned long string_hash_func(const void *p, + const uint8_t hash_key[HASH_KEY_SIZE]) _pure_; int string_compare_func(const void *a, const void *b) _pure_; extern const struct hash_ops string_hash_ops; /* This will compare the passed pointers directly, and will not * dereference them. This is hence not useful for strings or * suchlike. */ -unsigned long trivial_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) _pure_; +unsigned long trivial_hash_func(const void *p, + const uint8_t hash_key[HASH_KEY_SIZE]) _pure_; int trivial_compare_func(const void *a, const void *b) _const_; extern const struct hash_ops trivial_hash_ops; /* 32bit values we can always just embedd in the pointer itself, but * in order to support 32bit archs we need store 64bit values * indirectly, since they don't fit in a pointer. */ -unsigned long uint64_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) _pure_; +unsigned long uint64_hash_func(const void *p, + const uint8_t hash_key[HASH_KEY_SIZE]) _pure_; int uint64_compare_func(const void *a, const void *b) _pure_; extern const struct hash_ops uint64_hash_ops; /* On some archs dev_t is 32bit, and on others 64bit. And sometimes * it's 64bit on 32bit archs, and sometimes 32bit on 64bit archs. Yuck! */ #if SIZEOF_DEV_T != 8 -unsigned long devt_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) _pure_; +unsigned long devt_hash_func(const void *p, + const uint8_t hash_key[HASH_KEY_SIZE]) _pure_; int devt_compare_func(const void *a, const void *b) _pure_; extern const struct hash_ops devt_hash_ops = { - .hash = devt_hash_func, - .compare = devt_compare_func + .hash = devt_hash_func, + .compare = devt_compare_func }; #else #define devt_hash_func uint64_hash_func @@ -140,199 +145,285 @@ extern const struct hash_ops devt_hash_ops = { (void)0) #ifdef ENABLE_DEBUG_HASHMAP -# define HASHMAP_DEBUG_PARAMS , const char *func, const char *file, int line -# define HASHMAP_DEBUG_SRC_ARGS , __func__, __FILE__, __LINE__ -# define HASHMAP_DEBUG_PASS_ARGS , func, file, line +#define HASHMAP_DEBUG_PARAMS , const char *func, const char *file, int line +#define HASHMAP_DEBUG_SRC_ARGS , __func__, __FILE__, __LINE__ +#define HASHMAP_DEBUG_PASS_ARGS , func, file, line #else -# define HASHMAP_DEBUG_PARAMS -# define HASHMAP_DEBUG_SRC_ARGS -# define HASHMAP_DEBUG_PASS_ARGS +#define HASHMAP_DEBUG_PARAMS +#define HASHMAP_DEBUG_SRC_ARGS +#define HASHMAP_DEBUG_PASS_ARGS #endif -Hashmap *internal_hashmap_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS); -OrderedHashmap *internal_ordered_hashmap_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS); +Hashmap *internal_hashmap_new(const struct hash_ops *hash_ops + HASHMAP_DEBUG_PARAMS); +OrderedHashmap *internal_ordered_hashmap_new(const struct hash_ops *hash_ops + HASHMAP_DEBUG_PARAMS); #define hashmap_new(ops) internal_hashmap_new(ops HASHMAP_DEBUG_SRC_ARGS) #define ordered_hashmap_new(ops) internal_ordered_hashmap_new(ops HASHMAP_DEBUG_SRC_ARGS) -void internal_hashmap_free(HashmapBase *h); -static inline void hashmap_free(Hashmap *h) { - internal_hashmap_free(HASHMAP_BASE(h)); +void internal_hashmap_free(HashmapBase * h); +static inline void hashmap_free(Hashmap * h) +{ + internal_hashmap_free(HASHMAP_BASE(h)); } -static inline void ordered_hashmap_free(OrderedHashmap *h) { - internal_hashmap_free(HASHMAP_BASE(h)); + +static inline void ordered_hashmap_free(OrderedHashmap * h) +{ + internal_hashmap_free(HASHMAP_BASE(h)); } -void internal_hashmap_free_free(HashmapBase *h); -static inline void hashmap_free_free(Hashmap *h) { - internal_hashmap_free_free(HASHMAP_BASE(h)); +void internal_hashmap_free_free(HashmapBase * h); +static inline void hashmap_free_free(Hashmap * h) +{ + internal_hashmap_free_free(HASHMAP_BASE(h)); } -static inline void ordered_hashmap_free_free(OrderedHashmap *h) { - internal_hashmap_free_free(HASHMAP_BASE(h)); + +static inline void ordered_hashmap_free_free(OrderedHashmap * h) +{ + internal_hashmap_free_free(HASHMAP_BASE(h)); } -void hashmap_free_free_free(Hashmap *h); -static inline void ordered_hashmap_free_free_free(OrderedHashmap *h) { - hashmap_free_free_free(PLAIN_HASHMAP(h)); +void hashmap_free_free_free(Hashmap * h); +static inline void ordered_hashmap_free_free_free(OrderedHashmap * h) +{ + hashmap_free_free_free(PLAIN_HASHMAP(h)); } -HashmapBase *internal_hashmap_copy(HashmapBase *h); -static inline Hashmap *hashmap_copy(Hashmap *h) { - return (Hashmap*) internal_hashmap_copy(HASHMAP_BASE(h)); +HashmapBase *internal_hashmap_copy(HashmapBase * h); +static inline Hashmap *hashmap_copy(Hashmap * h) +{ + return (Hashmap *) internal_hashmap_copy(HASHMAP_BASE(h)); } -static inline OrderedHashmap *ordered_hashmap_copy(OrderedHashmap *h) { - return (OrderedHashmap*) internal_hashmap_copy(HASHMAP_BASE(h)); + +static inline OrderedHashmap *ordered_hashmap_copy(OrderedHashmap * h) +{ + return (OrderedHashmap *) internal_hashmap_copy(HASHMAP_BASE(h)); } -int internal_hashmap_ensure_allocated(Hashmap **h, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS); -int internal_ordered_hashmap_ensure_allocated(OrderedHashmap **h, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS); +int internal_hashmap_ensure_allocated(Hashmap ** h, + const struct hash_ops *hash_ops + HASHMAP_DEBUG_PARAMS); +int internal_ordered_hashmap_ensure_allocated(OrderedHashmap ** h, + const struct hash_ops *hash_ops + HASHMAP_DEBUG_PARAMS); #define hashmap_ensure_allocated(h, ops) internal_hashmap_ensure_allocated(h, ops HASHMAP_DEBUG_SRC_ARGS) #define ordered_hashmap_ensure_allocated(h, ops) internal_ordered_hashmap_ensure_allocated(h, ops HASHMAP_DEBUG_SRC_ARGS) -int hashmap_put(Hashmap *h, const void *key, void *value); -static inline int ordered_hashmap_put(OrderedHashmap *h, const void *key, void *value) { - return hashmap_put(PLAIN_HASHMAP(h), key, value); +int hashmap_put(Hashmap * h, const void *key, void *value); +static inline int ordered_hashmap_put(OrderedHashmap * h, const void *key, + void *value) +{ + return hashmap_put(PLAIN_HASHMAP(h), key, value); } -int hashmap_update(Hashmap *h, const void *key, void *value); -static inline int ordered_hashmap_update(OrderedHashmap *h, const void *key, void *value) { - return hashmap_update(PLAIN_HASHMAP(h), key, value); +int hashmap_update(Hashmap * h, const void *key, void *value); +static inline int ordered_hashmap_update(OrderedHashmap * h, const void *key, + void *value) +{ + return hashmap_update(PLAIN_HASHMAP(h), key, value); } -int hashmap_replace(Hashmap *h, const void *key, void *value); -static inline int ordered_hashmap_replace(OrderedHashmap *h, const void *key, void *value) { - return hashmap_replace(PLAIN_HASHMAP(h), key, value); +int hashmap_replace(Hashmap * h, const void *key, void *value); +static inline int ordered_hashmap_replace(OrderedHashmap * h, const void *key, + void *value) +{ + return hashmap_replace(PLAIN_HASHMAP(h), key, value); } -void *internal_hashmap_get(HashmapBase *h, const void *key); -static inline void *hashmap_get(Hashmap *h, const void *key) { - return internal_hashmap_get(HASHMAP_BASE(h), key); +void *internal_hashmap_get(HashmapBase * h, const void *key); +static inline void *hashmap_get(Hashmap * h, const void *key) +{ + return internal_hashmap_get(HASHMAP_BASE(h), key); } -static inline void *ordered_hashmap_get(OrderedHashmap *h, const void *key) { - return internal_hashmap_get(HASHMAP_BASE(h), key); + +static inline void *ordered_hashmap_get(OrderedHashmap * h, const void *key) +{ + return internal_hashmap_get(HASHMAP_BASE(h), key); } -void *hashmap_get2(Hashmap *h, const void *key, void **rkey); -static inline void *ordered_hashmap_get2(OrderedHashmap *h, const void *key, void **rkey) { - return hashmap_get2(PLAIN_HASHMAP(h), key, rkey); +void *hashmap_get2(Hashmap * h, const void *key, void **rkey); +static inline void *ordered_hashmap_get2(OrderedHashmap * h, const void *key, + void **rkey) +{ + return hashmap_get2(PLAIN_HASHMAP(h), key, rkey); } -bool internal_hashmap_contains(HashmapBase *h, const void *key); -static inline bool hashmap_contains(Hashmap *h, const void *key) { - return internal_hashmap_contains(HASHMAP_BASE(h), key); +bool internal_hashmap_contains(HashmapBase * h, const void *key); +static inline bool hashmap_contains(Hashmap * h, const void *key) +{ + return internal_hashmap_contains(HASHMAP_BASE(h), key); } -static inline bool ordered_hashmap_contains(OrderedHashmap *h, const void *key) { - return internal_hashmap_contains(HASHMAP_BASE(h), key); + +static inline bool ordered_hashmap_contains(OrderedHashmap * h, const void *key) +{ + return internal_hashmap_contains(HASHMAP_BASE(h), key); } -void *internal_hashmap_remove(HashmapBase *h, const void *key); -static inline void *hashmap_remove(Hashmap *h, const void *key) { - return internal_hashmap_remove(HASHMAP_BASE(h), key); +void *internal_hashmap_remove(HashmapBase * h, const void *key); +static inline void *hashmap_remove(Hashmap * h, const void *key) +{ + return internal_hashmap_remove(HASHMAP_BASE(h), key); } -static inline void *ordered_hashmap_remove(OrderedHashmap *h, const void *key) { - return internal_hashmap_remove(HASHMAP_BASE(h), key); + +static inline void *ordered_hashmap_remove(OrderedHashmap * h, const void *key) +{ + return internal_hashmap_remove(HASHMAP_BASE(h), key); } -void *hashmap_remove2(Hashmap *h, const void *key, void **rkey); -static inline void *ordered_hashmap_remove2(OrderedHashmap *h, const void *key, void **rkey) { - return hashmap_remove2(PLAIN_HASHMAP(h), key, rkey); +void *hashmap_remove2(Hashmap * h, const void *key, void **rkey); +static inline void *ordered_hashmap_remove2(OrderedHashmap * h, const void *key, + void **rkey) +{ + return hashmap_remove2(PLAIN_HASHMAP(h), key, rkey); } -void *hashmap_remove_value(Hashmap *h, const void *key, void *value); -static inline void *ordered_hashmap_remove_value(OrderedHashmap *h, const void *key, void *value) { - return hashmap_remove_value(PLAIN_HASHMAP(h), key, value); +void *hashmap_remove_value(Hashmap * h, const void *key, void *value); +static inline void *ordered_hashmap_remove_value(OrderedHashmap * h, + const void *key, void *value) +{ + return hashmap_remove_value(PLAIN_HASHMAP(h), key, value); } -int hashmap_remove_and_put(Hashmap *h, const void *old_key, const void *new_key, void *value); -static inline int ordered_hashmap_remove_and_put(OrderedHashmap *h, const void *old_key, const void *new_key, void *value) { - return hashmap_remove_and_put(PLAIN_HASHMAP(h), old_key, new_key, value); +int hashmap_remove_and_put(Hashmap * h, const void *old_key, + const void *new_key, void *value); +static inline int ordered_hashmap_remove_and_put(OrderedHashmap * h, + const void *old_key, + const void *new_key, + void *value) +{ + return hashmap_remove_and_put(PLAIN_HASHMAP(h), old_key, new_key, + value); } -int hashmap_remove_and_replace(Hashmap *h, const void *old_key, const void *new_key, void *value); -static inline int ordered_hashmap_remove_and_replace(OrderedHashmap *h, const void *old_key, const void *new_key, void *value) { - return hashmap_remove_and_replace(PLAIN_HASHMAP(h), old_key, new_key, value); +int hashmap_remove_and_replace(Hashmap * h, const void *old_key, + const void *new_key, void *value); +static inline int ordered_hashmap_remove_and_replace(OrderedHashmap * h, + const void *old_key, + const void *new_key, + void *value) +{ + return hashmap_remove_and_replace(PLAIN_HASHMAP(h), old_key, new_key, + value); } /* Since merging data from a OrderedHashmap into a Hashmap or vice-versa * should just work, allow this by having looser type-checking here. */ -int internal_hashmap_merge(Hashmap *h, Hashmap *other); +int internal_hashmap_merge(Hashmap * h, Hashmap * other); #define hashmap_merge(h, other) internal_hashmap_merge(PLAIN_HASHMAP(h), PLAIN_HASHMAP(other)) #define ordered_hashmap_merge(h, other) hashmap_merge(h, other) -int internal_hashmap_reserve(HashmapBase *h, unsigned entries_add); -static inline int hashmap_reserve(Hashmap *h, unsigned entries_add) { - return internal_hashmap_reserve(HASHMAP_BASE(h), entries_add); +int internal_hashmap_reserve(HashmapBase * h, unsigned entries_add); +static inline int hashmap_reserve(Hashmap * h, unsigned entries_add) +{ + return internal_hashmap_reserve(HASHMAP_BASE(h), entries_add); } -static inline int ordered_hashmap_reserve(OrderedHashmap *h, unsigned entries_add) { - return internal_hashmap_reserve(HASHMAP_BASE(h), entries_add); + +static inline int ordered_hashmap_reserve(OrderedHashmap * h, + unsigned entries_add) +{ + return internal_hashmap_reserve(HASHMAP_BASE(h), entries_add); } -int internal_hashmap_move(HashmapBase *h, HashmapBase *other); +int internal_hashmap_move(HashmapBase * h, HashmapBase * other); /* Unlike hashmap_merge, hashmap_move does not allow mixing the types. */ -static inline int hashmap_move(Hashmap *h, Hashmap *other) { - return internal_hashmap_move(HASHMAP_BASE(h), HASHMAP_BASE(other)); +static inline int hashmap_move(Hashmap * h, Hashmap * other) +{ + return internal_hashmap_move(HASHMAP_BASE(h), HASHMAP_BASE(other)); } -static inline int ordered_hashmap_move(OrderedHashmap *h, OrderedHashmap *other) { - return internal_hashmap_move(HASHMAP_BASE(h), HASHMAP_BASE(other)); + +static inline int ordered_hashmap_move(OrderedHashmap * h, + OrderedHashmap * other) +{ + return internal_hashmap_move(HASHMAP_BASE(h), HASHMAP_BASE(other)); } -int internal_hashmap_move_one(HashmapBase *h, HashmapBase *other, const void *key); -static inline int hashmap_move_one(Hashmap *h, Hashmap *other, const void *key) { - return internal_hashmap_move_one(HASHMAP_BASE(h), HASHMAP_BASE(other), key); +int internal_hashmap_move_one(HashmapBase * h, HashmapBase * other, + const void *key); +static inline int hashmap_move_one(Hashmap * h, Hashmap * other, + const void *key) +{ + return internal_hashmap_move_one(HASHMAP_BASE(h), HASHMAP_BASE(other), + key); } -static inline int ordered_hashmap_move_one(OrderedHashmap *h, OrderedHashmap *other, const void *key) { - return internal_hashmap_move_one(HASHMAP_BASE(h), HASHMAP_BASE(other), key); + +static inline int ordered_hashmap_move_one(OrderedHashmap * h, + OrderedHashmap * other, + const void *key) +{ + return internal_hashmap_move_one(HASHMAP_BASE(h), HASHMAP_BASE(other), + key); } -unsigned internal_hashmap_size(HashmapBase *h) _pure_; -static inline unsigned hashmap_size(Hashmap *h) { - return internal_hashmap_size(HASHMAP_BASE(h)); +unsigned internal_hashmap_size(HashmapBase * h) _pure_; +static inline unsigned hashmap_size(Hashmap * h) +{ + return internal_hashmap_size(HASHMAP_BASE(h)); } -static inline unsigned ordered_hashmap_size(OrderedHashmap *h) { - return internal_hashmap_size(HASHMAP_BASE(h)); + +static inline unsigned ordered_hashmap_size(OrderedHashmap * h) +{ + return internal_hashmap_size(HASHMAP_BASE(h)); } -static inline bool hashmap_isempty(Hashmap *h) { - return hashmap_size(h) == 0; +static inline bool hashmap_isempty(Hashmap * h) +{ + return hashmap_size(h) == 0; } -static inline bool ordered_hashmap_isempty(OrderedHashmap *h) { - return ordered_hashmap_size(h) == 0; + +static inline bool ordered_hashmap_isempty(OrderedHashmap * h) +{ + return ordered_hashmap_size(h) == 0; } -unsigned internal_hashmap_buckets(HashmapBase *h) _pure_; -static inline unsigned hashmap_buckets(Hashmap *h) { - return internal_hashmap_buckets(HASHMAP_BASE(h)); +unsigned internal_hashmap_buckets(HashmapBase * h) _pure_; +static inline unsigned hashmap_buckets(Hashmap * h) +{ + return internal_hashmap_buckets(HASHMAP_BASE(h)); } -static inline unsigned ordered_hashmap_buckets(OrderedHashmap *h) { - return internal_hashmap_buckets(HASHMAP_BASE(h)); + +static inline unsigned ordered_hashmap_buckets(OrderedHashmap * h) +{ + return internal_hashmap_buckets(HASHMAP_BASE(h)); } -void *internal_hashmap_iterate(HashmapBase *h, Iterator *i, const void **key); -static inline void *hashmap_iterate(Hashmap *h, Iterator *i, const void **key) { - return internal_hashmap_iterate(HASHMAP_BASE(h), i, key); +void *internal_hashmap_iterate(HashmapBase * h, Iterator * i, const void **key); +static inline void *hashmap_iterate(Hashmap * h, Iterator * i, const void **key) +{ + return internal_hashmap_iterate(HASHMAP_BASE(h), i, key); } -static inline void *ordered_hashmap_iterate(OrderedHashmap *h, Iterator *i, const void **key) { - return internal_hashmap_iterate(HASHMAP_BASE(h), i, key); + +static inline void *ordered_hashmap_iterate(OrderedHashmap * h, Iterator * i, + const void **key) +{ + return internal_hashmap_iterate(HASHMAP_BASE(h), i, key); } -void internal_hashmap_clear(HashmapBase *h); -static inline void hashmap_clear(Hashmap *h) { - internal_hashmap_clear(HASHMAP_BASE(h)); +void internal_hashmap_clear(HashmapBase * h); +static inline void hashmap_clear(Hashmap * h) +{ + internal_hashmap_clear(HASHMAP_BASE(h)); } -static inline void ordered_hashmap_clear(OrderedHashmap *h) { - internal_hashmap_clear(HASHMAP_BASE(h)); + +static inline void ordered_hashmap_clear(OrderedHashmap * h) +{ + internal_hashmap_clear(HASHMAP_BASE(h)); } -void internal_hashmap_clear_free(HashmapBase *h); -static inline void hashmap_clear_free(Hashmap *h) { - internal_hashmap_clear_free(HASHMAP_BASE(h)); +void internal_hashmap_clear_free(HashmapBase * h); +static inline void hashmap_clear_free(Hashmap * h) +{ + internal_hashmap_clear_free(HASHMAP_BASE(h)); } -static inline void ordered_hashmap_clear_free(OrderedHashmap *h) { - internal_hashmap_clear_free(HASHMAP_BASE(h)); + +static inline void ordered_hashmap_clear_free(OrderedHashmap * h) +{ + internal_hashmap_clear_free(HASHMAP_BASE(h)); } -void hashmap_clear_free_free(Hashmap *h); -static inline void ordered_hashmap_clear_free_free(OrderedHashmap *h) { - hashmap_clear_free_free(PLAIN_HASHMAP(h)); +void hashmap_clear_free_free(Hashmap * h); +static inline void ordered_hashmap_clear_free_free(OrderedHashmap * h) +{ + hashmap_clear_free_free(PLAIN_HASHMAP(h)); } /* @@ -346,47 +437,62 @@ static inline void ordered_hashmap_clear_free_free(OrderedHashmap *h) { * the first entry is O(1). */ -void *internal_hashmap_steal_first(HashmapBase *h); -static inline void *hashmap_steal_first(Hashmap *h) { - return internal_hashmap_steal_first(HASHMAP_BASE(h)); +void *internal_hashmap_steal_first(HashmapBase * h); +static inline void *hashmap_steal_first(Hashmap * h) +{ + return internal_hashmap_steal_first(HASHMAP_BASE(h)); } -static inline void *ordered_hashmap_steal_first(OrderedHashmap *h) { - return internal_hashmap_steal_first(HASHMAP_BASE(h)); + +static inline void *ordered_hashmap_steal_first(OrderedHashmap * h) +{ + return internal_hashmap_steal_first(HASHMAP_BASE(h)); } -void *internal_hashmap_steal_first_key(HashmapBase *h); -static inline void *hashmap_steal_first_key(Hashmap *h) { - return internal_hashmap_steal_first_key(HASHMAP_BASE(h)); +void *internal_hashmap_steal_first_key(HashmapBase * h); +static inline void *hashmap_steal_first_key(Hashmap * h) +{ + return internal_hashmap_steal_first_key(HASHMAP_BASE(h)); } -static inline void *ordered_hashmap_steal_first_key(OrderedHashmap *h) { - return internal_hashmap_steal_first_key(HASHMAP_BASE(h)); + +static inline void *ordered_hashmap_steal_first_key(OrderedHashmap * h) +{ + return internal_hashmap_steal_first_key(HASHMAP_BASE(h)); } -void *internal_hashmap_first_key(HashmapBase *h) _pure_; -static inline void *hashmap_first_key(Hashmap *h) { - return internal_hashmap_first_key(HASHMAP_BASE(h)); +void *internal_hashmap_first_key(HashmapBase * h) _pure_; +static inline void *hashmap_first_key(Hashmap * h) +{ + return internal_hashmap_first_key(HASHMAP_BASE(h)); } -static inline void *ordered_hashmap_first_key(OrderedHashmap *h) { - return internal_hashmap_first_key(HASHMAP_BASE(h)); + +static inline void *ordered_hashmap_first_key(OrderedHashmap * h) +{ + return internal_hashmap_first_key(HASHMAP_BASE(h)); } -void *internal_hashmap_first(HashmapBase *h) _pure_; -static inline void *hashmap_first(Hashmap *h) { - return internal_hashmap_first(HASHMAP_BASE(h)); +void *internal_hashmap_first(HashmapBase * h) _pure_; +static inline void *hashmap_first(Hashmap * h) +{ + return internal_hashmap_first(HASHMAP_BASE(h)); } -static inline void *ordered_hashmap_first(OrderedHashmap *h) { - return internal_hashmap_first(HASHMAP_BASE(h)); + +static inline void *ordered_hashmap_first(OrderedHashmap * h) +{ + return internal_hashmap_first(HASHMAP_BASE(h)); } /* no hashmap_next */ -void *ordered_hashmap_next(OrderedHashmap *h, const void *key); +void *ordered_hashmap_next(OrderedHashmap * h, const void *key); -char **internal_hashmap_get_strv(HashmapBase *h); -static inline char **hashmap_get_strv(Hashmap *h) { - return internal_hashmap_get_strv(HASHMAP_BASE(h)); +char **internal_hashmap_get_strv(HashmapBase * h); +static inline char **hashmap_get_strv(Hashmap * h) +{ + return internal_hashmap_get_strv(HASHMAP_BASE(h)); } -static inline char **ordered_hashmap_get_strv(OrderedHashmap *h) { - return internal_hashmap_get_strv(HASHMAP_BASE(h)); + +static inline char **ordered_hashmap_get_strv(OrderedHashmap * h) +{ + return internal_hashmap_get_strv(HASHMAP_BASE(h)); } /* @@ -415,12 +521,12 @@ static inline char **ordered_hashmap_get_strv(OrderedHashmap *h) { (e); \ (e) = ordered_hashmap_iterate((h), &(i), (const void**) &(k))) -DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap*, hashmap_free); -DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap*, hashmap_free_free); -DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap*, hashmap_free_free_free); -DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedHashmap*, ordered_hashmap_free); -DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedHashmap*, ordered_hashmap_free_free); -DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedHashmap*, ordered_hashmap_free_free_free); +DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap *, hashmap_free); +DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap *, hashmap_free_free); +DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap *, hashmap_free_free_free); +DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedHashmap *, ordered_hashmap_free); +DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedHashmap *, ordered_hashmap_free_free); +DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedHashmap *, ordered_hashmap_free_free_free); #define _cleanup_hashmap_free_ _cleanup_(hashmap_freep) #define _cleanup_hashmap_free_free_ _cleanup_(hashmap_free_freep) @@ -429,4 +535,4 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedHashmap*, ordered_hashmap_free_free_free); #define _cleanup_ordered_hashmap_free_free_ _cleanup_(ordered_hashmap_free_freep) #define _cleanup_ordered_hashmap_free_free_free_ _cleanup_(ordered_hashmap_free_free_freep) -#endif \ No newline at end of file +#endif diff --git a/libudev-compat/hwdb-internal.h b/libudev-compat/hwdb-internal.h index 85fed35..e4f061d 100644 --- a/libudev-compat/hwdb-internal.h +++ b/libudev-compat/hwdb-internal.h @@ -35,49 +35,49 @@ /* on-disk trie objects */ struct trie_header_f { - uint8_t signature[8]; + uint8_t signature[8]; - /* version of tool which created the file */ - le64_t tool_version; - le64_t file_size; + /* version of tool which created the file */ + le64_t tool_version; + le64_t file_size; - /* size of structures to allow them to grow */ - le64_t header_size; - le64_t node_size; - le64_t child_entry_size; - le64_t value_entry_size; + /* size of structures to allow them to grow */ + le64_t header_size; + le64_t node_size; + le64_t child_entry_size; + le64_t value_entry_size; - /* offset of the root trie node */ - le64_t nodes_root_off; + /* offset of the root trie node */ + le64_t nodes_root_off; - /* size of the nodes and string section */ - le64_t nodes_len; - le64_t strings_len; + /* size of the nodes and string section */ + le64_t nodes_len; + le64_t strings_len; } _packed_; struct trie_node_f { - /* prefix of lookup string, shared by all children */ - le64_t prefix_off; - /* size of children entry array appended to the node */ - uint8_t children_count; - uint8_t padding[7]; - /* size of value entry array appended to the node */ - le64_t values_count; + /* prefix of lookup string, shared by all children */ + le64_t prefix_off; + /* size of children entry array appended to the node */ + uint8_t children_count; + uint8_t padding[7]; + /* size of value entry array appended to the node */ + le64_t values_count; } _packed_; /* array of child entries, follows directly the node record */ struct trie_child_entry_f { - /* index of the child node */ - uint8_t c; - uint8_t padding[7]; - /* offset of the child node */ - le64_t child_off; + /* index of the child node */ + uint8_t c; + uint8_t padding[7]; + /* offset of the child node */ + le64_t child_off; } _packed_; /* array of value entries, follows directly the node record/child array */ struct trie_value_entry_f { - le64_t key_off; - le64_t value_off; + le64_t key_off; + le64_t value_off; } _packed_; -#endif +#endif diff --git a/libudev-compat/hwdb-util.h b/libudev-compat/hwdb-util.h index bc110d1..01c9328 100644 --- a/libudev-compat/hwdb-util.h +++ b/libudev-compat/hwdb-util.h @@ -34,9 +34,9 @@ #include "sd-hwdb.h" -DEFINE_TRIVIAL_CLEANUP_FUNC(sd_hwdb*, sd_hwdb_unref); +DEFINE_TRIVIAL_CLEANUP_FUNC(sd_hwdb *, sd_hwdb_unref); #define _cleanup_hwdb_unref_ _cleanup_(sd_hwdb_unrefp) -bool hwdb_validate(sd_hwdb *hwdb); +bool hwdb_validate(sd_hwdb * hwdb); -#endif \ No newline at end of file +#endif diff --git a/libudev-compat/libudev-device-private.c b/libudev-compat/libudev-device-private.c index 7b47ba8..c93482f 100644 --- a/libudev-compat/libudev-device-private.c +++ b/libudev-compat/libudev-device-private.c @@ -41,162 +41,190 @@ static void udev_device_tag(struct udev_device *dev, const char *tag, bool add) { - const char *id; - char filename[UTIL_PATH_SIZE]; - - id = udev_device_get_id_filename(dev); - if (id == NULL) - return; - strscpyl(filename, sizeof(filename), "/run/udev/tags/", tag, "/", id, NULL); - - if (add) { - int fd; - - mkdir_parents(filename, 0755); - fd = open(filename, O_WRONLY|O_CREAT|O_CLOEXEC|O_TRUNC|O_NOFOLLOW, 0444); - if (fd >= 0) - close(fd); - } else { - unlink(filename); - } + const char *id; + char filename[UTIL_PATH_SIZE]; + + id = udev_device_get_id_filename(dev); + if (id == NULL) + return; + strscpyl(filename, sizeof(filename), "/run/udev/tags/", tag, "/", id, + NULL); + + if (add) { + int fd; + + mkdir_parents(filename, 0755); + fd = open(filename, + O_WRONLY | O_CREAT | O_CLOEXEC | O_TRUNC | O_NOFOLLOW, + 0444); + if (fd >= 0) + close(fd); + } else { + unlink(filename); + } } -int udev_device_tag_index(struct udev_device *dev, struct udev_device *dev_old, bool add) +int udev_device_tag_index(struct udev_device *dev, struct udev_device *dev_old, + bool add) { - struct udev_list_entry *list_entry; - bool found; - - if (add && dev_old != NULL) { - /* delete possible left-over tags */ - udev_list_entry_foreach(list_entry, udev_device_get_tags_list_entry(dev_old)) { - const char *tag_old = udev_list_entry_get_name(list_entry); - struct udev_list_entry *list_entry_current; - - found = false; - udev_list_entry_foreach(list_entry_current, udev_device_get_tags_list_entry(dev)) { - const char *tag = udev_list_entry_get_name(list_entry_current); - - if (streq(tag, tag_old)) { - found = true; - break; - } - } - if (!found) - udev_device_tag(dev_old, tag_old, false); - } - } - - udev_list_entry_foreach(list_entry, udev_device_get_tags_list_entry(dev)) - udev_device_tag(dev, udev_list_entry_get_name(list_entry), add); - - return 0; + struct udev_list_entry *list_entry; + bool found; + + if (add && dev_old != NULL) { + /* delete possible left-over tags */ + udev_list_entry_foreach(list_entry, + udev_device_get_tags_list_entry + (dev_old)) { + const char *tag_old = + udev_list_entry_get_name(list_entry); + struct udev_list_entry *list_entry_current; + + found = false; + udev_list_entry_foreach(list_entry_current, + udev_device_get_tags_list_entry + (dev)) { + const char *tag = + udev_list_entry_get_name + (list_entry_current); + + if (streq(tag, tag_old)) { + found = true; + break; + } + } + if (!found) + udev_device_tag(dev_old, tag_old, false); + } + } + + udev_list_entry_foreach(list_entry, + udev_device_get_tags_list_entry(dev)) + udev_device_tag(dev, udev_list_entry_get_name(list_entry), add); + + return 0; } static bool device_has_info(struct udev_device *udev_device) { - struct udev_list_entry *list_entry; - - if (udev_device_get_devlinks_list_entry(udev_device) != NULL) - return true; - if (udev_device_get_devlink_priority(udev_device) != 0) - return true; - udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(udev_device)) - if (udev_list_entry_get_num(list_entry)) - return true; - if (udev_device_get_tags_list_entry(udev_device) != NULL) - return true; - if (udev_device_get_watch_handle(udev_device) >= 0) - return true; - return false; + struct udev_list_entry *list_entry; + + if (udev_device_get_devlinks_list_entry(udev_device) != NULL) + return true; + if (udev_device_get_devlink_priority(udev_device) != 0) + return true; + udev_list_entry_foreach(list_entry, + udev_device_get_properties_list_entry + (udev_device)) + if (udev_list_entry_get_num(list_entry)) + return true; + if (udev_device_get_tags_list_entry(udev_device) != NULL) + return true; + if (udev_device_get_watch_handle(udev_device) >= 0) + return true; + return false; } int udev_device_update_db(struct udev_device *udev_device) { - bool has_info; - const char *id; - char filename[UTIL_PATH_SIZE]; - char filename_tmp[UTIL_PATH_SIZE]; - FILE *f; - int r; - - id = udev_device_get_id_filename(udev_device); - if (id == NULL) - return -1; - - has_info = device_has_info(udev_device); - strscpyl(filename, sizeof(filename), "/run/udev/data/", id, NULL); - - /* do not store anything for otherwise empty devices */ - if (!has_info && - major(udev_device_get_devnum(udev_device)) == 0 && - udev_device_get_ifindex(udev_device) == 0) { - unlink(filename); - return 0; - } - - /* write a database file */ - strscpyl(filename_tmp, sizeof(filename_tmp), filename, ".tmp", NULL); - mkdir_parents(filename_tmp, 0755); - f = fopen(filename_tmp, "we"); - if (f == NULL) { - int errsv = errno; - log_debug("unable to create temporary db file '%s': %s", filename_tmp, strerror(errsv)); - return errsv; - } - - /* - * set 'sticky' bit to indicate that we should not clean the - * database when we transition from initramfs to the real root - */ - if (udev_device_get_db_persist(udev_device)) - fchmod(fileno(f), 01644); - - if (has_info) { - struct udev_list_entry *list_entry; - - if (major(udev_device_get_devnum(udev_device)) > 0) { - udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(udev_device)) - fprintf(f, "S:%s\n", udev_list_entry_get_name(list_entry) + strlen("/dev/")); - if (udev_device_get_devlink_priority(udev_device) != 0) - fprintf(f, "L:%i\n", udev_device_get_devlink_priority(udev_device)); - if (udev_device_get_watch_handle(udev_device) >= 0) - fprintf(f, "W:%i\n", udev_device_get_watch_handle(udev_device)); - } - - if (udev_device_get_usec_initialized(udev_device) > 0) - fprintf(f, "I:"USEC_FMT"\n", udev_device_get_usec_initialized(udev_device)); - - udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(udev_device)) { - if (!udev_list_entry_get_num(list_entry)) - continue; - fprintf(f, "E:%s=%s\n", - udev_list_entry_get_name(list_entry), - udev_list_entry_get_value(list_entry)); - } - - udev_list_entry_foreach(list_entry, udev_device_get_tags_list_entry(udev_device)) - fprintf(f, "G:%s\n", udev_list_entry_get_name(list_entry)); - } - - fclose(f); - r = rename(filename_tmp, filename); - if (r < 0) - return -1; - log_debug("created %s file '%s' for '%s'", has_info ? "db" : "empty", - filename, udev_device_get_devpath(udev_device)); - return 0; + bool has_info; + const char *id; + char filename[UTIL_PATH_SIZE]; + char filename_tmp[UTIL_PATH_SIZE]; + FILE *f; + int r; + + id = udev_device_get_id_filename(udev_device); + if (id == NULL) + return -1; + + has_info = device_has_info(udev_device); + strscpyl(filename, sizeof(filename), "/run/udev/data/", id, NULL); + + /* do not store anything for otherwise empty devices */ + if (!has_info && + major(udev_device_get_devnum(udev_device)) == 0 && + udev_device_get_ifindex(udev_device) == 0) { + unlink(filename); + return 0; + } + + /* write a database file */ + strscpyl(filename_tmp, sizeof(filename_tmp), filename, ".tmp", NULL); + mkdir_parents(filename_tmp, 0755); + f = fopen(filename_tmp, "we"); + if (f == NULL) { + int errsv = errno; + log_debug("unable to create temporary db file '%s': %s", + filename_tmp, strerror(errsv)); + return errsv; + } + + /* + * set 'sticky' bit to indicate that we should not clean the + * database when we transition from initramfs to the real root + */ + if (udev_device_get_db_persist(udev_device)) + fchmod(fileno(f), 01644); + + if (has_info) { + struct udev_list_entry *list_entry; + + if (major(udev_device_get_devnum(udev_device)) > 0) { + udev_list_entry_foreach(list_entry, + udev_device_get_devlinks_list_entry + (udev_device)) + fprintf(f, "S:%s\n", + udev_list_entry_get_name(list_entry) + + strlen("/dev/")); + if (udev_device_get_devlink_priority(udev_device) != 0) + fprintf(f, "L:%i\n", + udev_device_get_devlink_priority + (udev_device)); + if (udev_device_get_watch_handle(udev_device) >= 0) + fprintf(f, "W:%i\n", + udev_device_get_watch_handle + (udev_device)); + } + + if (udev_device_get_usec_initialized(udev_device) > 0) + fprintf(f, "I:" USEC_FMT "\n", + udev_device_get_usec_initialized(udev_device)); + + udev_list_entry_foreach(list_entry, + udev_device_get_properties_list_entry + (udev_device)) { + if (!udev_list_entry_get_num(list_entry)) + continue; + fprintf(f, "E:%s=%s\n", + udev_list_entry_get_name(list_entry), + udev_list_entry_get_value(list_entry)); + } + + udev_list_entry_foreach(list_entry, + udev_device_get_tags_list_entry + (udev_device)) + fprintf(f, "G:%s\n", udev_list_entry_get_name(list_entry)); + } + + fclose(f); + r = rename(filename_tmp, filename); + if (r < 0) + return -1; + log_debug("created %s file '%s' for '%s'", has_info ? "db" : "empty", + filename, udev_device_get_devpath(udev_device)); + return 0; } int udev_device_delete_db(struct udev_device *udev_device) { - const char *id; - char filename[UTIL_PATH_SIZE]; + const char *id; + char filename[UTIL_PATH_SIZE]; - id = udev_device_get_id_filename(udev_device); - if (id == NULL) - return -1; - strscpyl(filename, sizeof(filename), "/run/udev/data/", id, NULL); + id = udev_device_get_id_filename(udev_device); + if (id == NULL) + return -1; + strscpyl(filename, sizeof(filename), "/run/udev/data/", id, NULL); - unlink(filename); - return 0; + unlink(filename); + return 0; } diff --git a/libudev-compat/libudev-device.c b/libudev-compat/libudev-device.c index 91f2c8e..2e7f067 100644 --- a/libudev-compat/libudev-device.c +++ b/libudev-compat/libudev-device.c @@ -49,8 +49,15 @@ static int udev_device_read_uevent_file(struct udev_device *udev_device); static int udev_device_read_db(struct udev_device *udev_device); -static int udev_device_set_devnode(struct udev_device *udev_device, const char *devnode); -static struct udev_list_entry *udev_device_add_property_internal(struct udev_device *udev_device, const char *key, const char *value); +static int udev_device_set_devnode(struct udev_device *udev_device, + const char *devnode); +static struct udev_list_entry *udev_device_add_property_internal(struct + udev_device + *udev_device, + const char + *key, + const char + *value); /** * SECTION:libudev-device @@ -68,51 +75,51 @@ static struct udev_list_entry *udev_device_add_property_internal(struct udev_dev * Opaque object representing one kernel sys device. */ struct udev_device { - struct udev *udev; - struct udev_device *parent_device; - char *syspath; - const char *devpath; - char *sysname; - const char *sysnum; - char *devnode; - mode_t devnode_mode; - uid_t devnode_uid; - gid_t devnode_gid; - char *subsystem; - char *devtype; - char *driver; - char *action; - char *devpath_old; - char *id_filename; - char **envp; - char *monitor_buf; - size_t monitor_buf_len; - struct udev_list devlinks_list; - struct udev_list properties_list; - struct udev_list sysattr_value_list; - struct udev_list sysattr_list; - struct udev_list tags_list; - unsigned long long int seqnum; - usec_t usec_initialized; - int devlink_priority; - int refcount; - dev_t devnum; - int ifindex; - int watch_handle; - int maj, min; - bool parent_set; - bool subsystem_set; - bool devtype_set; - bool devlinks_uptodate; - bool envp_uptodate; - bool tags_uptodate; - bool driver_set; - bool info_loaded; - bool db_loaded; - bool uevent_loaded; - bool is_initialized; - bool sysattr_list_read; - bool db_persist; + struct udev *udev; + struct udev_device *parent_device; + char *syspath; + const char *devpath; + char *sysname; + const char *sysnum; + char *devnode; + mode_t devnode_mode; + uid_t devnode_uid; + gid_t devnode_gid; + char *subsystem; + char *devtype; + char *driver; + char *action; + char *devpath_old; + char *id_filename; + char **envp; + char *monitor_buf; + size_t monitor_buf_len; + struct udev_list devlinks_list; + struct udev_list properties_list; + struct udev_list sysattr_value_list; + struct udev_list sysattr_list; + struct udev_list tags_list; + unsigned long long int seqnum; + usec_t usec_initialized; + int devlink_priority; + int refcount; + dev_t devnum; + int ifindex; + int watch_handle; + int maj, min; + bool parent_set; + bool subsystem_set; + bool devtype_set; + bool devlinks_uptodate; + bool envp_uptodate; + bool tags_uptodate; + bool driver_set; + bool info_loaded; + bool db_loaded; + bool uevent_loaded; + bool is_initialized; + bool sysattr_list_read; + bool db_persist; }; /** @@ -126,36 +133,37 @@ struct udev_device { **/ unsigned long long int udev_device_get_seqnum(struct udev_device *udev_device) { - if (udev_device == NULL) - return 0; - return udev_device->seqnum; + if (udev_device == NULL) + return 0; + return udev_device->seqnum; } -static int udev_device_set_seqnum(struct udev_device *udev_device, unsigned long long int seqnum) +static int udev_device_set_seqnum(struct udev_device *udev_device, + unsigned long long int seqnum) { - char num[32]; + char num[32]; - udev_device->seqnum = seqnum; - snprintf(num, sizeof(num), "%llu", seqnum); - udev_device_add_property_internal(udev_device, "SEQNUM", num); - return 0; + udev_device->seqnum = seqnum; + snprintf(num, sizeof(num), "%llu", seqnum); + udev_device_add_property_internal(udev_device, "SEQNUM", num); + return 0; } int udev_device_get_ifindex(struct udev_device *udev_device) { - if (!udev_device->info_loaded) - udev_device_read_uevent_file(udev_device); - return udev_device->ifindex; + if (!udev_device->info_loaded) + udev_device_read_uevent_file(udev_device); + return udev_device->ifindex; } static int udev_device_set_ifindex(struct udev_device *udev_device, int ifindex) { - char num[32]; + char num[32]; - udev_device->ifindex = ifindex; - snprintf(num, sizeof(num), "%d", ifindex); - udev_device_add_property_internal(udev_device, "IFINDEX", num); - return 0; + udev_device->ifindex = ifindex; + snprintf(num, sizeof(num), "%d", ifindex); + udev_device_add_property_internal(udev_device, "IFINDEX", num); + return 0; } /** @@ -166,47 +174,49 @@ static int udev_device_set_ifindex(struct udev_device *udev_device, int ifindex) * * Returns: the dev_t number. **/ -dev_t udev_device_get_devnum(struct udev_device *udev_device) +dev_t udev_device_get_devnum(struct udev_device * udev_device) { - if (udev_device == NULL) - return makedev(0, 0); - if (!udev_device->info_loaded) - udev_device_read_uevent_file(udev_device); - return udev_device->devnum; + if (udev_device == NULL) + return makedev(0, 0); + if (!udev_device->info_loaded) + udev_device_read_uevent_file(udev_device); + return udev_device->devnum; } static int udev_device_set_devnum(struct udev_device *udev_device, dev_t devnum) { - char num[32]; + char num[32]; - udev_device->devnum = devnum; + udev_device->devnum = devnum; - snprintf(num, sizeof(num), "%u", major(devnum)); - udev_device_add_property_internal(udev_device, "MAJOR", num); - snprintf(num, sizeof(num), "%u", minor(devnum)); - udev_device_add_property_internal(udev_device, "MINOR", num); - return 0; + snprintf(num, sizeof(num), "%u", major(devnum)); + udev_device_add_property_internal(udev_device, "MAJOR", num); + snprintf(num, sizeof(num), "%u", minor(devnum)); + udev_device_add_property_internal(udev_device, "MINOR", num); + return 0; } const char *udev_device_get_devpath_old(struct udev_device *udev_device) { - return udev_device->devpath_old; + return udev_device->devpath_old; } -static int udev_device_set_devpath_old(struct udev_device *udev_device, const char *devpath_old) +static int udev_device_set_devpath_old(struct udev_device *udev_device, + const char *devpath_old) { - const char *pos; + const char *pos; - free(udev_device->devpath_old); - udev_device->devpath_old = strdup(devpath_old); - if (udev_device->devpath_old == NULL) - return -ENOMEM; - udev_device_add_property_internal(udev_device, "DEVPATH_OLD", udev_device->devpath_old); + free(udev_device->devpath_old); + udev_device->devpath_old = strdup(devpath_old); + if (udev_device->devpath_old == NULL) + return -ENOMEM; + udev_device_add_property_internal(udev_device, "DEVPATH_OLD", + udev_device->devpath_old); - pos = strrchr(udev_device->devpath_old, '/'); - if (pos == NULL) - return -EINVAL; - return 0; + pos = strrchr(udev_device->devpath_old, '/'); + if (pos == NULL) + return -EINVAL; + return 0; } /** @@ -219,27 +229,31 @@ static int udev_device_set_devpath_old(struct udev_device *udev_device, const ch **/ const char *udev_device_get_driver(struct udev_device *udev_device) { - char driver[UTIL_NAME_SIZE]; + char driver[UTIL_NAME_SIZE]; - if (udev_device == NULL) - return NULL; - if (!udev_device->driver_set) { - udev_device->driver_set = true; - if (util_get_sys_core_link_value(udev_device->udev, "driver", udev_device->syspath, driver, sizeof(driver)) > 0) - udev_device->driver = strdup(driver); - } - return udev_device->driver; + if (udev_device == NULL) + return NULL; + if (!udev_device->driver_set) { + udev_device->driver_set = true; + if (util_get_sys_core_link_value + (udev_device->udev, "driver", udev_device->syspath, driver, + sizeof(driver)) > 0) + udev_device->driver = strdup(driver); + } + return udev_device->driver; } -static int udev_device_set_driver(struct udev_device *udev_device, const char *driver) +static int udev_device_set_driver(struct udev_device *udev_device, + const char *driver) { - free(udev_device->driver); - udev_device->driver = strdup(driver); - if (udev_device->driver == NULL) - return -ENOMEM; - udev_device->driver_set = true; - udev_device_add_property_internal(udev_device, "DRIVER", udev_device->driver); - return 0; + free(udev_device->driver); + udev_device->driver = strdup(driver); + if (udev_device->driver == NULL) + return -ENOMEM; + udev_device->driver_set = true; + udev_device_add_property_internal(udev_device, "DRIVER", + udev_device->driver); + return 0; } /** @@ -252,35 +266,39 @@ static int udev_device_set_driver(struct udev_device *udev_device, const char *d **/ const char *udev_device_get_devtype(struct udev_device *udev_device) { - if (udev_device == NULL) - return NULL; - if (!udev_device->devtype_set) { - udev_device->devtype_set = true; - udev_device_read_uevent_file(udev_device); - } - return udev_device->devtype; + if (udev_device == NULL) + return NULL; + if (!udev_device->devtype_set) { + udev_device->devtype_set = true; + udev_device_read_uevent_file(udev_device); + } + return udev_device->devtype; } -static int udev_device_set_devtype(struct udev_device *udev_device, const char *devtype) +static int udev_device_set_devtype(struct udev_device *udev_device, + const char *devtype) { - free(udev_device->devtype); - udev_device->devtype = strdup(devtype); - if (udev_device->devtype == NULL) - return -ENOMEM; - udev_device->devtype_set = true; - udev_device_add_property_internal(udev_device, "DEVTYPE", udev_device->devtype); - return 0; + free(udev_device->devtype); + udev_device->devtype = strdup(devtype); + if (udev_device->devtype == NULL) + return -ENOMEM; + udev_device->devtype_set = true; + udev_device_add_property_internal(udev_device, "DEVTYPE", + udev_device->devtype); + return 0; } -static int udev_device_set_subsystem(struct udev_device *udev_device, const char *subsystem) +static int udev_device_set_subsystem(struct udev_device *udev_device, + const char *subsystem) { - free(udev_device->subsystem); - udev_device->subsystem = strdup(subsystem); - if (udev_device->subsystem == NULL) - return -ENOMEM; - udev_device->subsystem_set = true; - udev_device_add_property_internal(udev_device, "SUBSYSTEM", udev_device->subsystem); - return 0; + free(udev_device->subsystem); + udev_device->subsystem = strdup(subsystem); + if (udev_device->subsystem == NULL) + return -ENOMEM; + udev_device->subsystem_set = true; + udev_device_add_property_internal(udev_device, "SUBSYSTEM", + udev_device->subsystem); + return 0; } /** @@ -294,195 +312,218 @@ static int udev_device_set_subsystem(struct udev_device *udev_device, const char **/ const char *udev_device_get_subsystem(struct udev_device *udev_device) { - char subsystem[UTIL_NAME_SIZE]; + char subsystem[UTIL_NAME_SIZE]; - if (udev_device == NULL) - return NULL; - if (!udev_device->subsystem_set) { - udev_device->subsystem_set = true; - /* read "subsystem" link */ - if (util_get_sys_core_link_value(udev_device->udev, "subsystem", udev_device->syspath, subsystem, sizeof(subsystem)) > 0) { - udev_device_set_subsystem(udev_device, subsystem); - return udev_device->subsystem; - } - /* implicit names */ - if (startswith(udev_device->devpath, "/module/")) { - udev_device_set_subsystem(udev_device, "module"); - return udev_device->subsystem; - } - if (strstr(udev_device->devpath, "/drivers/") != NULL) { - udev_device_set_subsystem(udev_device, "drivers"); - return udev_device->subsystem; - } - if (startswith(udev_device->devpath, "/subsystem/") || - startswith(udev_device->devpath, "/class/") || - startswith(udev_device->devpath, "/bus/")) { - udev_device_set_subsystem(udev_device, "subsystem"); - return udev_device->subsystem; - } - } - return udev_device->subsystem; + if (udev_device == NULL) + return NULL; + if (!udev_device->subsystem_set) { + udev_device->subsystem_set = true; + /* read "subsystem" link */ + if (util_get_sys_core_link_value + (udev_device->udev, "subsystem", udev_device->syspath, + subsystem, sizeof(subsystem)) > 0) { + udev_device_set_subsystem(udev_device, subsystem); + return udev_device->subsystem; + } + /* implicit names */ + if (startswith(udev_device->devpath, "/module/")) { + udev_device_set_subsystem(udev_device, "module"); + return udev_device->subsystem; + } + if (strstr(udev_device->devpath, "/drivers/") != NULL) { + udev_device_set_subsystem(udev_device, "drivers"); + return udev_device->subsystem; + } + if (startswith(udev_device->devpath, "/subsystem/") || + startswith(udev_device->devpath, "/class/") || + startswith(udev_device->devpath, "/bus/")) { + udev_device_set_subsystem(udev_device, "subsystem"); + return udev_device->subsystem; + } + } + return udev_device->subsystem; } -mode_t udev_device_get_devnode_mode(struct udev_device *udev_device) +mode_t udev_device_get_devnode_mode(struct udev_device * udev_device) { - if (!udev_device->info_loaded) - udev_device_read_uevent_file(udev_device); - return udev_device->devnode_mode; + if (!udev_device->info_loaded) + udev_device_read_uevent_file(udev_device); + return udev_device->devnode_mode; } -static int udev_device_set_devnode_mode(struct udev_device *udev_device, mode_t mode) +static int udev_device_set_devnode_mode(struct udev_device *udev_device, + mode_t mode) { - char num[32]; + char num[32]; - udev_device->devnode_mode = mode; - snprintf(num, sizeof(num), "%#o", mode); - udev_device_add_property_internal(udev_device, "DEVMODE", num); - return 0; + udev_device->devnode_mode = mode; + snprintf(num, sizeof(num), "%#o", mode); + udev_device_add_property_internal(udev_device, "DEVMODE", num); + return 0; } -uid_t udev_device_get_devnode_uid(struct udev_device *udev_device) +uid_t udev_device_get_devnode_uid(struct udev_device * udev_device) { - if (!udev_device->info_loaded) - udev_device_read_uevent_file(udev_device); - return udev_device->devnode_uid; + if (!udev_device->info_loaded) + udev_device_read_uevent_file(udev_device); + return udev_device->devnode_uid; } -static int udev_device_set_devnode_uid(struct udev_device *udev_device, uid_t uid) +static int udev_device_set_devnode_uid(struct udev_device *udev_device, + uid_t uid) { - char num[32]; + char num[32]; - udev_device->devnode_uid = uid; - snprintf(num, sizeof(num), "%u", uid); - udev_device_add_property_internal(udev_device, "DEVUID", num); - return 0; + udev_device->devnode_uid = uid; + snprintf(num, sizeof(num), "%u", uid); + udev_device_add_property_internal(udev_device, "DEVUID", num); + return 0; } -gid_t udev_device_get_devnode_gid(struct udev_device *udev_device) +gid_t udev_device_get_devnode_gid(struct udev_device * udev_device) { - if (!udev_device->info_loaded) - udev_device_read_uevent_file(udev_device); - return udev_device->devnode_gid; + if (!udev_device->info_loaded) + udev_device_read_uevent_file(udev_device); + return udev_device->devnode_gid; } -static int udev_device_set_devnode_gid(struct udev_device *udev_device, gid_t gid) +static int udev_device_set_devnode_gid(struct udev_device *udev_device, + gid_t gid) { - char num[32]; + char num[32]; - udev_device->devnode_gid = gid; - snprintf(num, sizeof(num), "%u", gid); - udev_device_add_property_internal(udev_device, "DEVGID", num); - return 0; + udev_device->devnode_gid = gid; + snprintf(num, sizeof(num), "%u", gid); + udev_device_add_property_internal(udev_device, "DEVGID", num); + return 0; } -static struct udev_list_entry *udev_device_add_property_internal(struct udev_device *udev_device, const char *key, const char *value) +static struct udev_list_entry *udev_device_add_property_internal(struct + udev_device + *udev_device, + const char + *key, + const char + *value) { - udev_device->envp_uptodate = false; - if (value == NULL) { - struct udev_list_entry *list_entry; + udev_device->envp_uptodate = false; + if (value == NULL) { + struct udev_list_entry *list_entry; - list_entry = udev_device_get_properties_list_entry(udev_device); - list_entry = udev_list_entry_get_by_name(list_entry, key); - if (list_entry != NULL) - udev_list_entry_delete(list_entry); - return NULL; - } - return udev_list_entry_add(&udev_device->properties_list, key, value); + list_entry = udev_device_get_properties_list_entry(udev_device); + list_entry = udev_list_entry_get_by_name(list_entry, key); + if (list_entry != NULL) + udev_list_entry_delete(list_entry); + return NULL; + } + return udev_list_entry_add(&udev_device->properties_list, key, value); } - -int udev_device_add_property(struct udev_device *udev_device, const char *key, const char *value) +int udev_device_add_property(struct udev_device *udev_device, const char *key, + const char *value) { - struct udev_list_entry *property; + struct udev_list_entry *property; - property = udev_device_add_property_internal(udev_device, key, value); + property = udev_device_add_property_internal(udev_device, key, value); - /* store in db, skip private keys */ - if (key[0] != '.') - udev_list_entry_set_num(property, true); + /* store in db, skip private keys */ + if (key[0] != '.') + udev_list_entry_set_num(property, true); - return 0; + return 0; } -static struct udev_list_entry *udev_device_add_property_from_string(struct udev_device *udev_device, const char *property) +static struct udev_list_entry *udev_device_add_property_from_string(struct + udev_device + *udev_device, + const char + *property) { - char name[UTIL_LINE_SIZE]; - char *val; + char name[UTIL_LINE_SIZE]; + char *val; - strscpy(name, sizeof(name), property); - val = strchr(name, '='); - if (val == NULL) - return NULL; - val[0] = '\0'; - val = &val[1]; - if (val[0] == '\0') - val = NULL; - return udev_device_add_property_internal(udev_device, name, val); + strscpy(name, sizeof(name), property); + val = strchr(name, '='); + if (val == NULL) + return NULL; + val[0] = '\0'; + val = &val[1]; + if (val[0] == '\0') + val = NULL; + return udev_device_add_property_internal(udev_device, name, val); } -static int udev_device_set_syspath(struct udev_device *udev_device, const char *syspath) +static int udev_device_set_syspath(struct udev_device *udev_device, + const char *syspath) { - const char *pos; - size_t len; + const char *pos; + size_t len; - free(udev_device->syspath); - udev_device->syspath = strdup(syspath); - if (udev_device->syspath == NULL) - return -ENOMEM; - udev_device->devpath = udev_device->syspath + strlen("/sys"); - udev_device_add_property_internal(udev_device, "DEVPATH", udev_device->devpath); + free(udev_device->syspath); + udev_device->syspath = strdup(syspath); + if (udev_device->syspath == NULL) + return -ENOMEM; + udev_device->devpath = udev_device->syspath + strlen("/sys"); + udev_device_add_property_internal(udev_device, "DEVPATH", + udev_device->devpath); - pos = strrchr(udev_device->syspath, '/'); - if (pos == NULL) - return -EINVAL; - udev_device->sysname = strdup(&pos[1]); - if (udev_device->sysname == NULL) - return -ENOMEM; + pos = strrchr(udev_device->syspath, '/'); + if (pos == NULL) + return -EINVAL; + udev_device->sysname = strdup(&pos[1]); + if (udev_device->sysname == NULL) + return -ENOMEM; - /* some devices have '!' in their name, change that to '/' */ - len = 0; - while (udev_device->sysname[len] != '\0') { - if (udev_device->sysname[len] == '!') - udev_device->sysname[len] = '/'; - len++; - } + /* some devices have '!' in their name, change that to '/' */ + len = 0; + while (udev_device->sysname[len] != '\0') { + if (udev_device->sysname[len] == '!') + udev_device->sysname[len] = '/'; + len++; + } - /* trailing number */ - while (len > 0 && isdigit(udev_device->sysname[--len])) - udev_device->sysnum = &udev_device->sysname[len]; + /* trailing number */ + while (len > 0 && isdigit(udev_device->sysname[--len])) + udev_device->sysnum = &udev_device->sysname[len]; - /* sysname is completely numeric */ - if (len == 0) - udev_device->sysnum = NULL; + /* sysname is completely numeric */ + if (len == 0) + udev_device->sysnum = NULL; - return 0; + return 0; } -static void udev_device_set_usec_initialized(struct udev_device *udev_device, usec_t usec_initialized) +static void udev_device_set_usec_initialized(struct udev_device *udev_device, + usec_t usec_initialized) { - char num[DECIMAL_STR_MAX(usec_t)]; + char num[DECIMAL_STR_MAX(usec_t)]; - udev_device->usec_initialized = usec_initialized; - snprintf(num, sizeof(num), USEC_FMT, usec_initialized); - udev_device_add_property_internal(udev_device, "USEC_INITIALIZED", num); + udev_device->usec_initialized = usec_initialized; + snprintf(num, sizeof(num), USEC_FMT, usec_initialized); + udev_device_add_property_internal(udev_device, "USEC_INITIALIZED", num); } -void udev_device_ensure_usec_initialized(struct udev_device *udev_device, struct udev_device *old_device) +void udev_device_ensure_usec_initialized(struct udev_device *udev_device, + struct udev_device *old_device) { - if (old_device && old_device->usec_initialized != 0) - udev_device_set_usec_initialized(udev_device, old_device->usec_initialized); - else - udev_device_set_usec_initialized(udev_device, now(CLOCK_MONOTONIC)); + if (old_device && old_device->usec_initialized != 0) + udev_device_set_usec_initialized(udev_device, + old_device->usec_initialized); + else + udev_device_set_usec_initialized(udev_device, + now(CLOCK_MONOTONIC)); } -static int udev_device_set_action(struct udev_device *udev_device, const char *action) +static int udev_device_set_action(struct udev_device *udev_device, + const char *action) { - free(udev_device->action); - udev_device->action = strdup(action); - if (udev_device->action == NULL) - return -ENOMEM; - udev_device_add_property_internal(udev_device, "ACTION", udev_device->action); - return 0; + free(udev_device->action); + udev_device->action = strdup(action); + if (udev_device->action == NULL) + return -ENOMEM; + udev_device_add_property_internal(udev_device, "ACTION", + udev_device->action); + return 0; } /* @@ -512,92 +553,104 @@ static int udev_device_set_action(struct udev_device *udev_device, const char *a * DEVUID=(device node UID???) * DEVGID=(device node GID???) */ -static void udev_device_add_property_from_string_parse(struct udev_device *udev_device, const char *property) -{ - if (startswith(property, "DEVPATH=")) { - char path[UTIL_PATH_SIZE]; - - strscpyl(path, sizeof(path), "/sys", &property[8], NULL); - udev_device_set_syspath(udev_device, path); - } else if (startswith(property, "SUBSYSTEM=")) { - udev_device_set_subsystem(udev_device, &property[10]); - } else if (startswith(property, "DEVTYPE=")) { - udev_device_set_devtype(udev_device, &property[8]); - } else if (startswith(property, "DEVNAME=")) { - udev_device_set_devnode(udev_device, &property[8]); - } else if (startswith(property, "DEVLINKS=")) { - char devlinks[UTIL_PATH_SIZE]; - char *slink; - char *next; - - strscpy(devlinks, sizeof(devlinks), &property[9]); - slink = devlinks; - next = strchr(slink, ' '); - while (next != NULL) { - next[0] = '\0'; - udev_device_add_devlink(udev_device, slink); - slink = &next[1]; - next = strchr(slink, ' '); - } - if (slink[0] != '\0') - udev_device_add_devlink(udev_device, slink); - } else if (startswith(property, "TAGS=")) { - char tags[UTIL_PATH_SIZE]; - char *next; - - strscpy(tags, sizeof(tags), &property[5]); - next = strchr(tags, ':'); - if (next != NULL) { - next++; - while (next[0] != '\0') { - char *tag; - - tag = next; - next = strchr(tag, ':'); - if (next == NULL) - break; - next[0] = '\0'; - next++; - udev_device_add_tag(udev_device, tag); - } - } - } else if (startswith(property, "USEC_INITIALIZED=")) { - udev_device_set_usec_initialized(udev_device, strtoull(&property[19], NULL, 10)); - } else if (startswith(property, "DRIVER=")) { - udev_device_set_driver(udev_device, &property[7]); - } else if (startswith(property, "ACTION=")) { - udev_device_set_action(udev_device, &property[7]); - } else if (startswith(property, "MAJOR=")) { - udev_device->maj = strtoull(&property[6], NULL, 10); - } else if (startswith(property, "MINOR=")) { - udev_device->min = strtoull(&property[6], NULL, 10); - } else if (startswith(property, "DEVPATH_OLD=")) { - udev_device_set_devpath_old(udev_device, &property[12]); - } else if (startswith(property, "SEQNUM=")) { - udev_device_set_seqnum(udev_device, strtoull(&property[7], NULL, 10)); - } else if (startswith(property, "IFINDEX=")) { - udev_device_set_ifindex(udev_device, strtoull(&property[8], NULL, 10)); - } else if (startswith(property, "DEVMODE=")) { - udev_device_set_devnode_mode(udev_device, strtoul(&property[8], NULL, 8)); - } else if (startswith(property, "DEVUID=")) { - udev_device_set_devnode_uid(udev_device, strtoul(&property[7], NULL, 10)); - } else if (startswith(property, "DEVGID=")) { - udev_device_set_devnode_gid(udev_device, strtoul(&property[7], NULL, 10)); - } else { - udev_device_add_property_from_string(udev_device, property); - } -} - -static int udev_device_add_property_from_string_parse_finish(struct udev_device *udev_device) -{ - if (udev_device->maj > 0) - udev_device_set_devnum(udev_device, makedev(udev_device->maj, udev_device->min)); - udev_device->maj = 0; - udev_device->min = 0; - - if (udev_device->devpath == NULL || udev_device->subsystem == NULL) - return -EINVAL; - return 0; +static void udev_device_add_property_from_string_parse(struct udev_device + *udev_device, + const char *property) +{ + if (startswith(property, "DEVPATH=")) { + char path[UTIL_PATH_SIZE]; + + strscpyl(path, sizeof(path), "/sys", &property[8], NULL); + udev_device_set_syspath(udev_device, path); + } else if (startswith(property, "SUBSYSTEM=")) { + udev_device_set_subsystem(udev_device, &property[10]); + } else if (startswith(property, "DEVTYPE=")) { + udev_device_set_devtype(udev_device, &property[8]); + } else if (startswith(property, "DEVNAME=")) { + udev_device_set_devnode(udev_device, &property[8]); + } else if (startswith(property, "DEVLINKS=")) { + char devlinks[UTIL_PATH_SIZE]; + char *slink; + char *next; + + strscpy(devlinks, sizeof(devlinks), &property[9]); + slink = devlinks; + next = strchr(slink, ' '); + while (next != NULL) { + next[0] = '\0'; + udev_device_add_devlink(udev_device, slink); + slink = &next[1]; + next = strchr(slink, ' '); + } + if (slink[0] != '\0') + udev_device_add_devlink(udev_device, slink); + } else if (startswith(property, "TAGS=")) { + char tags[UTIL_PATH_SIZE]; + char *next; + + strscpy(tags, sizeof(tags), &property[5]); + next = strchr(tags, ':'); + if (next != NULL) { + next++; + while (next[0] != '\0') { + char *tag; + + tag = next; + next = strchr(tag, ':'); + if (next == NULL) + break; + next[0] = '\0'; + next++; + udev_device_add_tag(udev_device, tag); + } + } + } else if (startswith(property, "USEC_INITIALIZED=")) { + udev_device_set_usec_initialized(udev_device, + strtoull(&property[19], NULL, + 10)); + } else if (startswith(property, "DRIVER=")) { + udev_device_set_driver(udev_device, &property[7]); + } else if (startswith(property, "ACTION=")) { + udev_device_set_action(udev_device, &property[7]); + } else if (startswith(property, "MAJOR=")) { + udev_device->maj = strtoull(&property[6], NULL, 10); + } else if (startswith(property, "MINOR=")) { + udev_device->min = strtoull(&property[6], NULL, 10); + } else if (startswith(property, "DEVPATH_OLD=")) { + udev_device_set_devpath_old(udev_device, &property[12]); + } else if (startswith(property, "SEQNUM=")) { + udev_device_set_seqnum(udev_device, + strtoull(&property[7], NULL, 10)); + } else if (startswith(property, "IFINDEX=")) { + udev_device_set_ifindex(udev_device, + strtoull(&property[8], NULL, 10)); + } else if (startswith(property, "DEVMODE=")) { + udev_device_set_devnode_mode(udev_device, + strtoul(&property[8], NULL, 8)); + } else if (startswith(property, "DEVUID=")) { + udev_device_set_devnode_uid(udev_device, + strtoul(&property[7], NULL, 10)); + } else if (startswith(property, "DEVGID=")) { + udev_device_set_devnode_gid(udev_device, + strtoul(&property[7], NULL, 10)); + } else { + udev_device_add_property_from_string(udev_device, property); + } +} + +static int udev_device_add_property_from_string_parse_finish(struct udev_device + *udev_device) +{ + if (udev_device->maj > 0) + udev_device_set_devnum(udev_device, + makedev(udev_device->maj, + udev_device->min)); + udev_device->maj = 0; + udev_device->min = 0; + + if (udev_device->devpath == NULL || udev_device->subsystem == NULL) + return -EINVAL; + return 0; } /** @@ -609,169 +662,179 @@ static int udev_device_add_property_from_string_parse_finish(struct udev_device * * Returns: the property string, or #NULL if there is no such property. **/ -const char *udev_device_get_property_value(struct udev_device *udev_device, const char *key) +const char *udev_device_get_property_value(struct udev_device *udev_device, + const char *key) { - struct udev_list_entry *list_entry; + struct udev_list_entry *list_entry; - if (udev_device == NULL) - return NULL; - if (key == NULL) - return NULL; + if (udev_device == NULL) + return NULL; + if (key == NULL) + return NULL; - list_entry = udev_device_get_properties_list_entry(udev_device); - list_entry = udev_list_entry_get_by_name(list_entry, key); - return udev_list_entry_get_value(list_entry); + list_entry = udev_device_get_properties_list_entry(udev_device); + list_entry = udev_list_entry_get_by_name(list_entry, key); + return udev_list_entry_get_value(list_entry); } static int udev_device_read_db(struct udev_device *udev_device) { - char filename[UTIL_PATH_SIZE]; - char line[UTIL_LINE_SIZE]; - const char *id; - FILE *f; - - if (udev_device->db_loaded) - return 0; - - udev_device->db_loaded = true; - - id = udev_device_get_id_filename(udev_device); - if (id == NULL) - return -1; - - strscpyl(filename, sizeof(filename), "/run/udev/data/", id, NULL); - - f = fopen(filename, "re"); - if (f == NULL) { - int errsv = errno; - log_debug("no db file to read %s: %s", filename, strerror(errsv)); - return errsv; - } - - /* devices with a database entry are initialized */ - udev_device->is_initialized = true; - - while (fgets(line, sizeof(line), f)) { - ssize_t len; - const char *val; - struct udev_list_entry *entry; - - len = strlen(line); - if (len < 4) - break; - line[len-1] = '\0'; - val = &line[2]; - switch(line[0]) { - case 'S': - strscpyl(filename, sizeof(filename), "/dev/", val, NULL); - udev_device_add_devlink(udev_device, filename); - break; - case 'L': - udev_device_set_devlink_priority(udev_device, atoi(val)); - break; - case 'E': - entry = udev_device_add_property_from_string(udev_device, val); - udev_list_entry_set_num(entry, true); - break; - case 'G': - udev_device_add_tag(udev_device, val); - break; - case 'W': - udev_device_set_watch_handle(udev_device, atoi(val)); - break; - case 'I': - udev_device_set_usec_initialized(udev_device, strtoull(val, NULL, 10)); - break; - } - } - fclose(f); - - log_trace("device %p filled with db file data", udev_device); - return 0; + char filename[UTIL_PATH_SIZE]; + char line[UTIL_LINE_SIZE]; + const char *id; + FILE *f; + + if (udev_device->db_loaded) + return 0; + + udev_device->db_loaded = true; + + id = udev_device_get_id_filename(udev_device); + if (id == NULL) + return -1; + + strscpyl(filename, sizeof(filename), "/run/udev/data/", id, NULL); + + f = fopen(filename, "re"); + if (f == NULL) { + int errsv = errno; + log_debug("no db file to read %s: %s", filename, + strerror(errsv)); + return errsv; + } + + /* devices with a database entry are initialized */ + udev_device->is_initialized = true; + + while (fgets(line, sizeof(line), f)) { + ssize_t len; + const char *val; + struct udev_list_entry *entry; + + len = strlen(line); + if (len < 4) + break; + line[len - 1] = '\0'; + val = &line[2]; + switch (line[0]) { + case 'S': + strscpyl(filename, sizeof(filename), "/dev/", val, + NULL); + udev_device_add_devlink(udev_device, filename); + break; + case 'L': + udev_device_set_devlink_priority(udev_device, + atoi(val)); + break; + case 'E': + entry = + udev_device_add_property_from_string(udev_device, + val); + udev_list_entry_set_num(entry, true); + break; + case 'G': + udev_device_add_tag(udev_device, val); + break; + case 'W': + udev_device_set_watch_handle(udev_device, atoi(val)); + break; + case 'I': + udev_device_set_usec_initialized(udev_device, + strtoull(val, NULL, + 10)); + break; + } + } + fclose(f); + + log_trace("device %p filled with db file data", udev_device); + return 0; } static int udev_device_read_uevent_file(struct udev_device *udev_device) { - char filename[UTIL_PATH_SIZE]; - FILE *f; - char line[UTIL_LINE_SIZE]; - int maj = 0; - int min = 0; - - if (udev_device->uevent_loaded) - return 0; - - strscpyl(filename, sizeof(filename), udev_device->syspath, "/uevent", NULL); - f = fopen(filename, "re"); - if (f == NULL) - return -errno; - udev_device->uevent_loaded = true; - - while (fgets(line, sizeof(line), f)) { - char *pos; - - pos = strchr(line, '\n'); - if (pos == NULL) - continue; - pos[0] = '\0'; - - if (startswith(line, "DEVTYPE=")) { - udev_device_set_devtype(udev_device, &line[8]); - continue; - } - if (startswith(line, "IFINDEX=")) { - udev_device_set_ifindex(udev_device, strtoull(&line[8], NULL, 10)); - continue; - } - if (startswith(line, "DEVNAME=")) { - udev_device_set_devnode(udev_device, &line[8]); - continue; - } - - if (startswith(line, "MAJOR=")) - maj = strtoull(&line[6], NULL, 10); - else if (startswith(line, "MINOR=")) - min = strtoull(&line[6], NULL, 10); - else if (startswith(line, "DEVMODE=")) - udev_device->devnode_mode = strtoul(&line[8], NULL, 8); - - udev_device_add_property_from_string(udev_device, line); - } - - udev_device->devnum = makedev(maj, min); - fclose(f); - return 0; + char filename[UTIL_PATH_SIZE]; + FILE *f; + char line[UTIL_LINE_SIZE]; + int maj = 0; + int min = 0; + + if (udev_device->uevent_loaded) + return 0; + + strscpyl(filename, sizeof(filename), udev_device->syspath, "/uevent", + NULL); + f = fopen(filename, "re"); + if (f == NULL) + return -errno; + udev_device->uevent_loaded = true; + + while (fgets(line, sizeof(line), f)) { + char *pos; + + pos = strchr(line, '\n'); + if (pos == NULL) + continue; + pos[0] = '\0'; + + if (startswith(line, "DEVTYPE=")) { + udev_device_set_devtype(udev_device, &line[8]); + continue; + } + if (startswith(line, "IFINDEX=")) { + udev_device_set_ifindex(udev_device, + strtoull(&line[8], NULL, 10)); + continue; + } + if (startswith(line, "DEVNAME=")) { + udev_device_set_devnode(udev_device, &line[8]); + continue; + } + + if (startswith(line, "MAJOR=")) + maj = strtoull(&line[6], NULL, 10); + else if (startswith(line, "MINOR=")) + min = strtoull(&line[6], NULL, 10); + else if (startswith(line, "DEVMODE=")) + udev_device->devnode_mode = strtoul(&line[8], NULL, 8); + + udev_device_add_property_from_string(udev_device, line); + } + + udev_device->devnum = makedev(maj, min); + fclose(f); + return 0; } void udev_device_set_info_loaded(struct udev_device *device) { - device->info_loaded = true; + device->info_loaded = true; } static struct udev_device *udev_device_new(struct udev *udev) { - struct udev_device *udev_device; + struct udev_device *udev_device; - if (udev == NULL) { - errno = EINVAL; - return NULL; - } + if (udev == NULL) { + errno = EINVAL; + return NULL; + } - udev_device = new0(struct udev_device, 1); - if (udev_device == NULL) { - errno = ENOMEM; - return NULL; - } - udev_device->refcount = 1; - udev_device->udev = udev; - udev_list_init(udev, &udev_device->devlinks_list, true); - udev_list_init(udev, &udev_device->properties_list, true); - udev_list_init(udev, &udev_device->sysattr_value_list, true); - udev_list_init(udev, &udev_device->sysattr_list, false); - udev_list_init(udev, &udev_device->tags_list, true); - udev_device->watch_handle = -1; + udev_device = new0(struct udev_device, 1); + if (udev_device == NULL) { + errno = ENOMEM; + return NULL; + } + udev_device->refcount = 1; + udev_device->udev = udev; + udev_list_init(udev, &udev_device->devlinks_list, true); + udev_list_init(udev, &udev_device->properties_list, true); + udev_list_init(udev, &udev_device->sysattr_value_list, true); + udev_list_init(udev, &udev_device->sysattr_list, false); + udev_list_init(udev, &udev_device->tags_list, true); + udev_device->watch_handle = -1; - return udev_device; + return udev_device; } /** @@ -788,69 +851,71 @@ static struct udev_device *udev_device_new(struct udev *udev) * * Returns: a new udev device, or #NULL, if it does not exist **/ -struct udev_device *udev_device_new_from_syspath(struct udev *udev, const char *syspath) -{ - const char *subdir; - char path[UTIL_PATH_SIZE]; - char *pos; - struct stat statbuf; - struct udev_device *udev_device; - - if (udev == NULL) { - errno = EINVAL; - return NULL; - } - - if (syspath == NULL) { - errno = EINVAL; - return NULL; - } - - /* path starts in sys */ - if (!startswith(syspath, "/sys")) { - log_debug("not in sys :%s", syspath); - errno = EINVAL; - return NULL; - } - - /* path is not a root directory */ - subdir = syspath + strlen("/sys"); - pos = strrchr(subdir, '/'); - if (pos == NULL || pos[1] == '\0' || pos < &subdir[2]) { - errno = EINVAL; - return NULL; - } - - /* resolve possible symlink to real path */ - strscpy(path, sizeof(path), syspath); - util_resolve_sys_link(udev, path, sizeof(path)); - - if (startswith(path + strlen("/sys"), "/devices/")) { - char file[UTIL_PATH_SIZE]; - - /* all "devices" require a "uevent" file */ - strscpyl(file, sizeof(file), path, "/uevent", NULL); - if (stat(file, &statbuf) != 0) - return NULL; - } else { - /* everything else just needs to be a directory */ - if (stat(path, &statbuf) != 0) - return NULL; - - if (!S_ISDIR(statbuf.st_mode)) { - errno = EISDIR; - return NULL; - } - } - - udev_device = udev_device_new(udev); - if (udev_device == NULL) - return NULL; - - udev_device_set_syspath(udev_device, path); - log_trace("device %p has devpath '%s'", udev_device, udev_device_get_devpath(udev_device)); - - return udev_device; +struct udev_device *udev_device_new_from_syspath(struct udev *udev, + const char *syspath) +{ + const char *subdir; + char path[UTIL_PATH_SIZE]; + char *pos; + struct stat statbuf; + struct udev_device *udev_device; + + if (udev == NULL) { + errno = EINVAL; + return NULL; + } + + if (syspath == NULL) { + errno = EINVAL; + return NULL; + } + + /* path starts in sys */ + if (!startswith(syspath, "/sys")) { + log_debug("not in sys :%s", syspath); + errno = EINVAL; + return NULL; + } + + /* path is not a root directory */ + subdir = syspath + strlen("/sys"); + pos = strrchr(subdir, '/'); + if (pos == NULL || pos[1] == '\0' || pos < &subdir[2]) { + errno = EINVAL; + return NULL; + } + + /* resolve possible symlink to real path */ + strscpy(path, sizeof(path), syspath); + util_resolve_sys_link(udev, path, sizeof(path)); + + if (startswith(path + strlen("/sys"), "/devices/")) { + char file[UTIL_PATH_SIZE]; + + /* all "devices" require a "uevent" file */ + strscpyl(file, sizeof(file), path, "/uevent", NULL); + if (stat(file, &statbuf) != 0) + return NULL; + } else { + /* everything else just needs to be a directory */ + if (stat(path, &statbuf) != 0) + return NULL; + + if (!S_ISDIR(statbuf.st_mode)) { + errno = EISDIR; + return NULL; + } + } + + udev_device = udev_device_new(udev); + if (udev_device == NULL) + return NULL; + + udev_device_set_syspath(udev_device, path); + log_trace("device %p has devpath '%s'", udev_device, + udev_device_get_devpath(udev_device)); + + return udev_device; } /** @@ -869,24 +934,25 @@ struct udev_device *udev_device_new_from_syspath(struct udev *udev, const char * * * Returns: a new udev device, or #NULL, if it does not exist **/ -struct udev_device *udev_device_new_from_devnum(struct udev *udev, char type, dev_t devnum) +struct udev_device *udev_device_new_from_devnum(struct udev *udev, char type, + dev_t devnum) { - char path[UTIL_PATH_SIZE]; - const char *type_str; + char path[UTIL_PATH_SIZE]; + const char *type_str; - if (type == 'b') - type_str = "block"; - else if (type == 'c') - type_str = "char"; - else { - errno = EINVAL; - return NULL; - } + if (type == 'b') + type_str = "block"; + else if (type == 'c') + type_str = "char"; + else { + errno = EINVAL; + return NULL; + } - /* use /sys/dev/{block,char}/: link */ - snprintf(path, sizeof(path), "/sys/dev/%s/%u:%u", - type_str, major(devnum), minor(devnum)); - return udev_device_new_from_syspath(udev, path); + /* use /sys/dev/{block,char}/: link */ + snprintf(path, sizeof(path), "/sys/dev/%s/%u:%u", + type_str, major(devnum), minor(devnum)); + return udev_device_new_from_syspath(udev, path); } /** @@ -907,67 +973,73 @@ struct udev_device *udev_device_new_from_devnum(struct udev *udev, char type, de * * Returns: a new udev device, or #NULL, if it does not exist **/ -struct udev_device *udev_device_new_from_device_id(struct udev *udev, const char *id) -{ - char type; - int maj, min; - char subsys[UTIL_PATH_SIZE]; - char *sysname; - - switch(id[0]) { - case 'b': - case 'c': - if (sscanf(id, "%c%i:%i", &type, &maj, &min) != 3) - return NULL; - return udev_device_new_from_devnum(udev, type, makedev(maj, min)); - case 'n': { - int sk; - struct ifreq ifr; - struct udev_device *dev; - int ifindex; - - ifindex = strtoul(&id[1], NULL, 10); - if (ifindex <= 0) { - errno = EINVAL; - return NULL; - } - - sk = socket(PF_INET, SOCK_DGRAM, 0); - if (sk < 0) - return NULL; - memzero(&ifr, sizeof(struct ifreq)); - ifr.ifr_ifindex = ifindex; - if (ioctl(sk, SIOCGIFNAME, &ifr) != 0) { - close(sk); - return NULL; - } - close(sk); - - dev = udev_device_new_from_subsystem_sysname(udev, "net", ifr.ifr_name); - if (dev == NULL) - return NULL; - if (udev_device_get_ifindex(dev) == ifindex) - return dev; - - /* this is racy, so we may end up with the wrong device */ - udev_device_unref(dev); - errno = ENODEV; - return NULL; - } - case '+': - strscpy(subsys, sizeof(subsys), &id[1]); - sysname = strchr(subsys, ':'); - if (sysname == NULL) { - errno = EINVAL; - return NULL; - } - sysname[0] = '\0'; - sysname = &sysname[1]; - return udev_device_new_from_subsystem_sysname(udev, subsys, sysname); - default: - errno = EINVAL; - return NULL; - } +struct udev_device *udev_device_new_from_device_id(struct udev *udev, + const char *id) +{ + char type; + int maj, min; + char subsys[UTIL_PATH_SIZE]; + char *sysname; + + switch (id[0]) { + case 'b': + case 'c': + if (sscanf(id, "%c%i:%i", &type, &maj, &min) != 3) + return NULL; + return udev_device_new_from_devnum(udev, type, + makedev(maj, min)); + case 'n':{ + int sk; + struct ifreq ifr; + struct udev_device *dev; + int ifindex; + + ifindex = strtoul(&id[1], NULL, 10); + if (ifindex <= 0) { + errno = EINVAL; + return NULL; + } + + sk = socket(PF_INET, SOCK_DGRAM, 0); + if (sk < 0) + return NULL; + memzero(&ifr, sizeof(struct ifreq)); + ifr.ifr_ifindex = ifindex; + if (ioctl(sk, SIOCGIFNAME, &ifr) != 0) { + close(sk); + return NULL; + } + close(sk); + + dev = + udev_device_new_from_subsystem_sysname(udev, "net", + ifr. + ifr_name); + if (dev == NULL) + return NULL; + if (udev_device_get_ifindex(dev) == ifindex) + return dev; + + /* this is racy, so we may end up with the wrong device */ + udev_device_unref(dev); + errno = ENODEV; + return NULL; + } + case '+': + strscpy(subsys, sizeof(subsys), &id[1]); + sysname = strchr(subsys, ':'); + if (sysname == NULL) { + errno = EINVAL; + return NULL; + } + sysname[0] = '\0'; + sysname = &sysname[1]; + return udev_device_new_from_subsystem_sysname(udev, subsys, + sysname); + default: + errno = EINVAL; + return NULL; + } } /** @@ -985,71 +1057,79 @@ struct udev_device *udev_device_new_from_device_id(struct udev *udev, const char * * Returns: a new udev device, or #NULL, if it does not exist **/ -struct udev_device *udev_device_new_from_subsystem_sysname(struct udev *udev, const char *subsystem, const char *sysname) -{ - char path[UTIL_PATH_SIZE]; - struct stat statbuf; - - if (streq(subsystem, "subsystem")) { - strscpyl(path, sizeof(path), "/sys/subsystem/", sysname, NULL); - if (stat(path, &statbuf) == 0) - goto found; - - strscpyl(path, sizeof(path), "/sys/bus/", sysname, NULL); - if (stat(path, &statbuf) == 0) - goto found; - - strscpyl(path, sizeof(path), "/sys/class/", sysname, NULL); - if (stat(path, &statbuf) == 0) - goto found; - goto out; - } - - if (streq(subsystem, "module")) { - strscpyl(path, sizeof(path), "/sys/module/", sysname, NULL); - if (stat(path, &statbuf) == 0) - goto found; - goto out; - } - - if (streq(subsystem, "drivers")) { - char subsys[UTIL_NAME_SIZE]; - char *driver; - - strscpy(subsys, sizeof(subsys), sysname); - driver = strchr(subsys, ':'); - if (driver != NULL) { - driver[0] = '\0'; - driver = &driver[1]; - - strscpyl(path, sizeof(path), "/sys/subsystem/", subsys, "/drivers/", driver, NULL); - if (stat(path, &statbuf) == 0) - goto found; - - strscpyl(path, sizeof(path), "/sys/bus/", subsys, "/drivers/", driver, NULL); - if (stat(path, &statbuf) == 0) - goto found; - } else - errno = EINVAL; - - goto out; - } - - strscpyl(path, sizeof(path), "/sys/subsystem/", subsystem, "/devices/", sysname, NULL); - if (stat(path, &statbuf) == 0) - goto found; - - strscpyl(path, sizeof(path), "/sys/bus/", subsystem, "/devices/", sysname, NULL); - if (stat(path, &statbuf) == 0) - goto found; - - strscpyl(path, sizeof(path), "/sys/class/", subsystem, "/", sysname, NULL); - if (stat(path, &statbuf) == 0) - goto found; -out: - return NULL; -found: - return udev_device_new_from_syspath(udev, path); +struct udev_device *udev_device_new_from_subsystem_sysname(struct udev *udev, + const char + *subsystem, + const char *sysname) +{ + char path[UTIL_PATH_SIZE]; + struct stat statbuf; + + if (streq(subsystem, "subsystem")) { + strscpyl(path, sizeof(path), "/sys/subsystem/", sysname, NULL); + if (stat(path, &statbuf) == 0) + goto found; + + strscpyl(path, sizeof(path), "/sys/bus/", sysname, NULL); + if (stat(path, &statbuf) == 0) + goto found; + + strscpyl(path, sizeof(path), "/sys/class/", sysname, NULL); + if (stat(path, &statbuf) == 0) + goto found; + goto out; + } + + if (streq(subsystem, "module")) { + strscpyl(path, sizeof(path), "/sys/module/", sysname, NULL); + if (stat(path, &statbuf) == 0) + goto found; + goto out; + } + + if (streq(subsystem, "drivers")) { + char subsys[UTIL_NAME_SIZE]; + char *driver; + + strscpy(subsys, sizeof(subsys), sysname); + driver = strchr(subsys, ':'); + if (driver != NULL) { + driver[0] = '\0'; + driver = &driver[1]; + + strscpyl(path, sizeof(path), "/sys/subsystem/", subsys, + "/drivers/", driver, NULL); + if (stat(path, &statbuf) == 0) + goto found; + + strscpyl(path, sizeof(path), "/sys/bus/", subsys, + "/drivers/", driver, NULL); + if (stat(path, &statbuf) == 0) + goto found; + } else + errno = EINVAL; + + goto out; + } + + strscpyl(path, sizeof(path), "/sys/subsystem/", subsystem, "/devices/", + sysname, NULL); + if (stat(path, &statbuf) == 0) + goto found; + + strscpyl(path, sizeof(path), "/sys/bus/", subsystem, "/devices/", + sysname, NULL); + if (stat(path, &statbuf) == 0) + goto found; + + strscpyl(path, sizeof(path), "/sys/class/", subsystem, "/", sysname, + NULL); + if (stat(path, &statbuf) == 0) + goto found; + out: + return NULL; + found: + return udev_device_new_from_syspath(udev, path); } /** @@ -1068,48 +1148,51 @@ struct udev_device *udev_device_new_from_subsystem_sysname(struct udev *udev, co **/ struct udev_device *udev_device_new_from_environment(struct udev *udev) { - int i; - struct udev_device *udev_device; + int i; + struct udev_device *udev_device; - udev_device = udev_device_new(udev); - if (udev_device == NULL) - return NULL; - udev_device_set_info_loaded(udev_device); + udev_device = udev_device_new(udev); + if (udev_device == NULL) + return NULL; + udev_device_set_info_loaded(udev_device); - for (i = 0; environ[i] != NULL; i++) - udev_device_add_property_from_string_parse(udev_device, environ[i]); + for (i = 0; environ[i] != NULL; i++) + udev_device_add_property_from_string_parse(udev_device, + environ[i]); - if (udev_device_add_property_from_string_parse_finish(udev_device) < 0) { - log_debug("%s", "missing values, invalid device"); - udev_device_unref(udev_device); - udev_device = NULL; - } + if (udev_device_add_property_from_string_parse_finish(udev_device) < 0) { + log_debug("%s", "missing values, invalid device"); + udev_device_unref(udev_device); + udev_device = NULL; + } - return udev_device; + return udev_device; } -static struct udev_device *device_new_from_parent(struct udev_device *udev_device) +static struct udev_device *device_new_from_parent(struct udev_device + *udev_device) { - struct udev_device *udev_device_parent = NULL; - char path[UTIL_PATH_SIZE]; - const char *subdir; + struct udev_device *udev_device_parent = NULL; + char path[UTIL_PATH_SIZE]; + const char *subdir; - strscpy(path, sizeof(path), udev_device->syspath); - subdir = path + strlen("/sys/"); - for (;;) { - char *pos; + strscpy(path, sizeof(path), udev_device->syspath); + subdir = path + strlen("/sys/"); + for (;;) { + char *pos; - pos = strrchr(subdir, '/'); - if (pos == NULL || pos < &subdir[2]) - break; - pos[0] = '\0'; - udev_device_parent = udev_device_new_from_syspath(udev_device->udev, path); - if (udev_device_parent != NULL) - return udev_device_parent; - } + pos = strrchr(subdir, '/'); + if (pos == NULL || pos < &subdir[2]) + break; + pos[0] = '\0'; + udev_device_parent = + udev_device_new_from_syspath(udev_device->udev, path); + if (udev_device_parent != NULL) + return udev_device_parent; + } - errno = ENOENT; - return NULL; + errno = ENOENT; + return NULL; } /** @@ -1132,15 +1215,16 @@ static struct udev_device *device_new_from_parent(struct udev_device *udev_devic **/ struct udev_device *udev_device_get_parent(struct udev_device *udev_device) { - if (udev_device == NULL) { - errno = EINVAL; - return NULL; - } - if (!udev_device->parent_set) { - udev_device->parent_set = true; - udev_device->parent_device = device_new_from_parent(udev_device); - } - return udev_device->parent_device; + if (udev_device == NULL) { + errno = EINVAL; + return NULL; + } + if (!udev_device->parent_set) { + udev_device->parent_set = true; + udev_device->parent_device = + device_new_from_parent(udev_device); + } + return udev_device->parent_device; } /** @@ -1164,35 +1248,43 @@ struct udev_device *udev_device_get_parent(struct udev_device *udev_device) * * Returns: a new udev device, or #NULL if no matching parent exists. **/ -struct udev_device *udev_device_get_parent_with_subsystem_devtype(struct udev_device *udev_device, const char *subsystem, const char *devtype) -{ - struct udev_device *parent; - - if (subsystem == NULL) { - errno = EINVAL; - return NULL; - } - - parent = udev_device_get_parent(udev_device); - while (parent != NULL) { - const char *parent_subsystem; - const char *parent_devtype; - - parent_subsystem = udev_device_get_subsystem(parent); - if (parent_subsystem != NULL && streq(parent_subsystem, subsystem)) { - if (devtype == NULL) - break; - parent_devtype = udev_device_get_devtype(parent); - if (parent_devtype != NULL && streq(parent_devtype, devtype)) - break; - } - parent = udev_device_get_parent(parent); - } - - if (!parent) - errno = ENOENT; - - return parent; +struct udev_device *udev_device_get_parent_with_subsystem_devtype(struct + udev_device + *udev_device, + const char + *subsystem, + const char + *devtype) +{ + struct udev_device *parent; + + if (subsystem == NULL) { + errno = EINVAL; + return NULL; + } + + parent = udev_device_get_parent(udev_device); + while (parent != NULL) { + const char *parent_subsystem; + const char *parent_devtype; + + parent_subsystem = udev_device_get_subsystem(parent); + if (parent_subsystem != NULL + && streq(parent_subsystem, subsystem)) { + if (devtype == NULL) + break; + parent_devtype = udev_device_get_devtype(parent); + if (parent_devtype != NULL + && streq(parent_devtype, devtype)) + break; + } + parent = udev_device_get_parent(parent); + } + + if (!parent) + errno = ENOENT; + + return parent; } /** @@ -1205,9 +1297,9 @@ struct udev_device *udev_device_get_parent_with_subsystem_devtype(struct udev_de **/ struct udev *udev_device_get_udev(struct udev_device *udev_device) { - if (udev_device == NULL) - return NULL; - return udev_device->udev; + if (udev_device == NULL) + return NULL; + return udev_device->udev; } /** @@ -1220,10 +1312,10 @@ struct udev *udev_device_get_udev(struct udev_device *udev_device) **/ struct udev_device *udev_device_ref(struct udev_device *udev_device) { - if (udev_device == NULL) - return NULL; - udev_device->refcount++; - return udev_device; + if (udev_device == NULL) + return NULL; + udev_device->refcount++; + return udev_device; } /** @@ -1237,31 +1329,31 @@ struct udev_device *udev_device_ref(struct udev_device *udev_device) **/ struct udev_device *udev_device_unref(struct udev_device *udev_device) { - if (udev_device == NULL) - return NULL; - udev_device->refcount--; - if (udev_device->refcount > 0) - return NULL; - if (udev_device->parent_device != NULL) - udev_device_unref(udev_device->parent_device); - free(udev_device->syspath); - free(udev_device->sysname); - free(udev_device->devnode); - free(udev_device->subsystem); - free(udev_device->devtype); - udev_list_cleanup(&udev_device->devlinks_list); - udev_list_cleanup(&udev_device->properties_list); - udev_list_cleanup(&udev_device->sysattr_value_list); - udev_list_cleanup(&udev_device->sysattr_list); - udev_list_cleanup(&udev_device->tags_list); - free(udev_device->action); - free(udev_device->driver); - free(udev_device->devpath_old); - free(udev_device->id_filename); - free(udev_device->envp); - free(udev_device->monitor_buf); - free(udev_device); - return NULL; + if (udev_device == NULL) + return NULL; + udev_device->refcount--; + if (udev_device->refcount > 0) + return NULL; + if (udev_device->parent_device != NULL) + udev_device_unref(udev_device->parent_device); + free(udev_device->syspath); + free(udev_device->sysname); + free(udev_device->devnode); + free(udev_device->subsystem); + free(udev_device->devtype); + udev_list_cleanup(&udev_device->devlinks_list); + udev_list_cleanup(&udev_device->properties_list); + udev_list_cleanup(&udev_device->sysattr_value_list); + udev_list_cleanup(&udev_device->sysattr_list); + udev_list_cleanup(&udev_device->tags_list); + free(udev_device->action); + free(udev_device->driver); + free(udev_device->devpath_old); + free(udev_device->id_filename); + free(udev_device->envp); + free(udev_device->monitor_buf); + free(udev_device); + return NULL; } /** @@ -1275,9 +1367,9 @@ struct udev_device *udev_device_unref(struct udev_device *udev_device) **/ const char *udev_device_get_devpath(struct udev_device *udev_device) { - if (udev_device == NULL) - return NULL; - return udev_device->devpath; + if (udev_device == NULL) + return NULL; + return udev_device->devpath; } /** @@ -1291,9 +1383,9 @@ const char *udev_device_get_devpath(struct udev_device *udev_device) **/ const char *udev_device_get_syspath(struct udev_device *udev_device) { - if (udev_device == NULL) - return NULL; - return udev_device->syspath; + if (udev_device == NULL) + return NULL; + return udev_device->syspath; } /** @@ -1306,9 +1398,9 @@ const char *udev_device_get_syspath(struct udev_device *udev_device) **/ const char *udev_device_get_sysname(struct udev_device *udev_device) { - if (udev_device == NULL) - return NULL; - return udev_device->sysname; + if (udev_device == NULL) + return NULL; + return udev_device->sysname; } /** @@ -1321,9 +1413,9 @@ const char *udev_device_get_sysname(struct udev_device *udev_device) **/ const char *udev_device_get_sysnum(struct udev_device *udev_device) { - if (udev_device == NULL) - return NULL; - return udev_device->sysnum; + if (udev_device == NULL) + return NULL; + return udev_device->sysnum; } /** @@ -1337,13 +1429,13 @@ const char *udev_device_get_sysnum(struct udev_device *udev_device) **/ const char *udev_device_get_devnode(struct udev_device *udev_device) { - if (udev_device == NULL) - return NULL; - if (udev_device->devnode != NULL) - return udev_device->devnode; - if (!udev_device->info_loaded) - udev_device_read_uevent_file(udev_device); - return udev_device->devnode; + if (udev_device == NULL) + return NULL; + if (udev_device->devnode != NULL) + return udev_device->devnode; + if (!udev_device->info_loaded) + udev_device_read_uevent_file(udev_device); + return udev_device->devnode; } /** @@ -1359,19 +1451,20 @@ const char *udev_device_get_devnode(struct udev_device *udev_device) * * Returns: the first entry of the device node link list **/ -struct udev_list_entry *udev_device_get_devlinks_list_entry(struct udev_device *udev_device) +struct udev_list_entry *udev_device_get_devlinks_list_entry(struct udev_device + *udev_device) { - if (udev_device == NULL) - return NULL; - if (!udev_device->info_loaded) - udev_device_read_db(udev_device); - return udev_list_get_entry(&udev_device->devlinks_list); + if (udev_device == NULL) + return NULL; + if (!udev_device->info_loaded) + udev_device_read_db(udev_device); + return udev_list_get_entry(&udev_device->devlinks_list); } void udev_device_cleanup_devlinks_list(struct udev_device *udev_device) { - udev_device->devlinks_uptodate = false; - udev_list_cleanup(&udev_device->devlinks_list); + udev_device->devlinks_uptodate = false; + udev_list_cleanup(&udev_device->devlinks_list); } /** @@ -1386,47 +1479,62 @@ void udev_device_cleanup_devlinks_list(struct udev_device *udev_device) * * Returns: the first entry of the property list **/ -struct udev_list_entry *udev_device_get_properties_list_entry(struct udev_device *udev_device) -{ - if (udev_device == NULL) - return NULL; - if (!udev_device->info_loaded) { - udev_device_read_uevent_file(udev_device); - udev_device_read_db(udev_device); - } - if (!udev_device->devlinks_uptodate) { - char symlinks[UTIL_PATH_SIZE]; - struct udev_list_entry *list_entry; - - udev_device->devlinks_uptodate = true; - list_entry = udev_device_get_devlinks_list_entry(udev_device); - if (list_entry != NULL) { - char *s; - size_t l; - - s = symlinks; - l = strpcpyl(&s, sizeof(symlinks), udev_list_entry_get_name(list_entry), NULL); - udev_list_entry_foreach(list_entry, udev_list_entry_get_next(list_entry)) - l = strpcpyl(&s, l, " ", udev_list_entry_get_name(list_entry), NULL); - udev_device_add_property_internal(udev_device, "DEVLINKS", symlinks); - } - } - if (!udev_device->tags_uptodate) { - udev_device->tags_uptodate = true; - if (udev_device_get_tags_list_entry(udev_device) != NULL) { - char tags[UTIL_PATH_SIZE]; - struct udev_list_entry *list_entry; - char *s; - size_t l; - - s = tags; - l = strpcpyl(&s, sizeof(tags), ":", NULL); - udev_list_entry_foreach(list_entry, udev_device_get_tags_list_entry(udev_device)) - l = strpcpyl(&s, l, udev_list_entry_get_name(list_entry), ":", NULL); - udev_device_add_property_internal(udev_device, "TAGS", tags); - } - } - return udev_list_get_entry(&udev_device->properties_list); +struct udev_list_entry *udev_device_get_properties_list_entry(struct udev_device + *udev_device) +{ + if (udev_device == NULL) + return NULL; + if (!udev_device->info_loaded) { + udev_device_read_uevent_file(udev_device); + udev_device_read_db(udev_device); + } + if (!udev_device->devlinks_uptodate) { + char symlinks[UTIL_PATH_SIZE]; + struct udev_list_entry *list_entry; + + udev_device->devlinks_uptodate = true; + list_entry = udev_device_get_devlinks_list_entry(udev_device); + if (list_entry != NULL) { + char *s; + size_t l; + + s = symlinks; + l = strpcpyl(&s, sizeof(symlinks), + udev_list_entry_get_name(list_entry), + NULL); + udev_list_entry_foreach(list_entry, + udev_list_entry_get_next + (list_entry)) + l = + strpcpyl(&s, l, " ", + udev_list_entry_get_name(list_entry), + NULL); + udev_device_add_property_internal(udev_device, + "DEVLINKS", symlinks); + } + } + if (!udev_device->tags_uptodate) { + udev_device->tags_uptodate = true; + if (udev_device_get_tags_list_entry(udev_device) != NULL) { + char tags[UTIL_PATH_SIZE]; + struct udev_list_entry *list_entry; + char *s; + size_t l; + + s = tags; + l = strpcpyl(&s, sizeof(tags), ":", NULL); + udev_list_entry_foreach(list_entry, + udev_device_get_tags_list_entry + (udev_device)) + l = + strpcpyl(&s, l, + udev_list_entry_get_name(list_entry), ":", + NULL); + udev_device_add_property_internal(udev_device, "TAGS", + tags); + } + } + return udev_list_get_entry(&udev_device->properties_list); } /** @@ -1441,9 +1549,9 @@ struct udev_list_entry *udev_device_get_properties_list_entry(struct udev_device **/ const char *udev_device_get_action(struct udev_device *udev_device) { - if (udev_device == NULL) - return NULL; - return udev_device->action; + if (udev_device == NULL) + return NULL; + return udev_device->action; } /** @@ -1458,25 +1566,26 @@ const char *udev_device_get_action(struct udev_device *udev_device) * * Returns: the number of microseconds since the device was first seen. **/ -unsigned long long int udev_device_get_usec_since_initialized(struct udev_device *udev_device) +unsigned long long int udev_device_get_usec_since_initialized(struct udev_device + *udev_device) { - usec_t now_ts; + usec_t now_ts; - if (udev_device == NULL) - return 0; - if (!udev_device->info_loaded) - udev_device_read_db(udev_device); - if (udev_device->usec_initialized == 0) - return 0; - now_ts = now(CLOCK_MONOTONIC); - if (now_ts == 0) - return 0; - return now_ts - udev_device->usec_initialized; + if (udev_device == NULL) + return 0; + if (!udev_device->info_loaded) + udev_device_read_db(udev_device); + if (udev_device->usec_initialized == 0) + return 0; + now_ts = now(CLOCK_MONOTONIC); + if (now_ts == 0) + return 0; + return now_ts - udev_device->usec_initialized; } -usec_t udev_device_get_usec_initialized(struct udev_device *udev_device) +usec_t udev_device_get_usec_initialized(struct udev_device * udev_device) { - return udev_device->usec_initialized; + return udev_device->usec_initialized; } /** @@ -1489,78 +1598,86 @@ usec_t udev_device_get_usec_initialized(struct udev_device *udev_device) * * Returns: the content of a sys attribute file, or #NULL if there is no sys attribute value. **/ -const char *udev_device_get_sysattr_value(struct udev_device *udev_device, const char *sysattr) -{ - struct udev_list_entry *list_entry; - char path[UTIL_PATH_SIZE]; - char value[4096]; - struct stat statbuf; - int fd; - ssize_t size; - const char *val = NULL; - - if (udev_device == NULL) - return NULL; - if (sysattr == NULL) - return NULL; - - /* look for possibly already cached result */ - list_entry = udev_list_get_entry(&udev_device->sysattr_value_list); - list_entry = udev_list_entry_get_by_name(list_entry, sysattr); - if (list_entry != NULL) - return udev_list_entry_get_value(list_entry); - - strscpyl(path, sizeof(path), udev_device_get_syspath(udev_device), "/", sysattr, NULL); - if (lstat(path, &statbuf) != 0) { - udev_list_entry_add(&udev_device->sysattr_value_list, sysattr, NULL); - goto out; - } - - if (S_ISLNK(statbuf.st_mode)) { - /* - * Some core links return only the last element of the target path, - * these are just values, the paths should not be exposed. - */ - if (streq(sysattr, "driver") || - streq(sysattr, "subsystem") || - streq(sysattr, "module")) { - if (util_get_sys_core_link_value(udev_device->udev, sysattr, - udev_device->syspath, value, sizeof(value)) < 0) - return NULL; - list_entry = udev_list_entry_add(&udev_device->sysattr_value_list, sysattr, value); - val = udev_list_entry_get_value(list_entry); - goto out; - } - - goto out; - } - - /* skip directories */ - if (S_ISDIR(statbuf.st_mode)) - goto out; - - /* skip non-readable files */ - if ((statbuf.st_mode & S_IRUSR) == 0) - goto out; - - /* read attribute value */ - fd = open(path, O_RDONLY|O_CLOEXEC); - if (fd < 0) - goto out; - size = read(fd, value, sizeof(value)); - close(fd); - if (size < 0) - goto out; - if (size == sizeof(value)) - goto out; - - /* got a valid value, store it in cache and return it */ - value[size] = '\0'; - util_remove_trailing_chars(value, '\n'); - list_entry = udev_list_entry_add(&udev_device->sysattr_value_list, sysattr, value); - val = udev_list_entry_get_value(list_entry); -out: - return val; +const char *udev_device_get_sysattr_value(struct udev_device *udev_device, + const char *sysattr) +{ + struct udev_list_entry *list_entry; + char path[UTIL_PATH_SIZE]; + char value[4096]; + struct stat statbuf; + int fd; + ssize_t size; + const char *val = NULL; + + if (udev_device == NULL) + return NULL; + if (sysattr == NULL) + return NULL; + + /* look for possibly already cached result */ + list_entry = udev_list_get_entry(&udev_device->sysattr_value_list); + list_entry = udev_list_entry_get_by_name(list_entry, sysattr); + if (list_entry != NULL) + return udev_list_entry_get_value(list_entry); + + strscpyl(path, sizeof(path), udev_device_get_syspath(udev_device), "/", + sysattr, NULL); + if (lstat(path, &statbuf) != 0) { + udev_list_entry_add(&udev_device->sysattr_value_list, sysattr, + NULL); + goto out; + } + + if (S_ISLNK(statbuf.st_mode)) { + /* + * Some core links return only the last element of the target path, + * these are just values, the paths should not be exposed. + */ + if (streq(sysattr, "driver") || + streq(sysattr, "subsystem") || streq(sysattr, "module")) { + if (util_get_sys_core_link_value + (udev_device->udev, sysattr, udev_device->syspath, + value, sizeof(value)) < 0) + return NULL; + list_entry = + udev_list_entry_add(&udev_device-> + sysattr_value_list, sysattr, + value); + val = udev_list_entry_get_value(list_entry); + goto out; + } + + goto out; + } + + /* skip directories */ + if (S_ISDIR(statbuf.st_mode)) + goto out; + + /* skip non-readable files */ + if ((statbuf.st_mode & S_IRUSR) == 0) + goto out; + + /* read attribute value */ + fd = open(path, O_RDONLY | O_CLOEXEC); + if (fd < 0) + goto out; + size = read(fd, value, sizeof(value)); + close(fd); + if (size < 0) + goto out; + if (size == sizeof(value)) + goto out; + + /* got a valid value, store it in cache and return it */ + value[size] = '\0'; + util_remove_trailing_chars(value, '\n'); + list_entry = + udev_list_entry_add(&udev_device->sysattr_value_list, sysattr, + value); + val = udev_list_entry_get_value(list_entry); + out: + return val; } /** @@ -1573,118 +1690,123 @@ const char *udev_device_get_sysattr_value(struct udev_device *udev_device, const * * Returns: Negative error code on failure or 0 on success. **/ -int udev_device_set_sysattr_value(struct udev_device *udev_device, const char *sysattr, char *value) -{ - struct udev_device *dev; - char path[UTIL_PATH_SIZE]; - struct stat statbuf; - int fd; - ssize_t size, value_len; - int ret = 0; - - if (udev_device == NULL) - return -EINVAL; - dev = udev_device; - if (sysattr == NULL) - return -EINVAL; - if (value == NULL) - value_len = 0; - else - value_len = strlen(value); - - strscpyl(path, sizeof(path), udev_device_get_syspath(dev), "/", sysattr, NULL); - if (lstat(path, &statbuf) != 0) { - udev_list_entry_add(&dev->sysattr_value_list, sysattr, NULL); - ret = -ENXIO; - goto out; - } - - if (S_ISLNK(statbuf.st_mode)) { - ret = -EINVAL; - goto out; - } - - /* skip directories */ - if (S_ISDIR(statbuf.st_mode)) { - ret = -EISDIR; - goto out; - } - - /* skip non-readable files */ - if ((statbuf.st_mode & S_IRUSR) == 0) { - ret = -EACCES; - goto out; - } - - /* Value is limited to 4k */ - if (value_len > 4096) { - ret = -EINVAL; - goto out; - } - util_remove_trailing_chars(value, '\n'); - - /* write attribute value */ - fd = open(path, O_WRONLY|O_CLOEXEC); - if (fd < 0) { - ret = -errno; - goto out; - } - size = write(fd, value, value_len); - close(fd); - if (size < 0) { - ret = -errno; - goto out; - } - if (size < value_len) { - ret = -EIO; - goto out; - } - - /* wrote a valid value, store it in cache and return it */ - udev_list_entry_add(&dev->sysattr_value_list, sysattr, value); -out: - if (dev != udev_device) - udev_device_unref(dev); - return ret; +int udev_device_set_sysattr_value(struct udev_device *udev_device, + const char *sysattr, char *value) +{ + struct udev_device *dev; + char path[UTIL_PATH_SIZE]; + struct stat statbuf; + int fd; + ssize_t size, value_len; + int ret = 0; + + if (udev_device == NULL) + return -EINVAL; + dev = udev_device; + if (sysattr == NULL) + return -EINVAL; + if (value == NULL) + value_len = 0; + else + value_len = strlen(value); + + strscpyl(path, sizeof(path), udev_device_get_syspath(dev), "/", sysattr, + NULL); + if (lstat(path, &statbuf) != 0) { + udev_list_entry_add(&dev->sysattr_value_list, sysattr, NULL); + ret = -ENXIO; + goto out; + } + + if (S_ISLNK(statbuf.st_mode)) { + ret = -EINVAL; + goto out; + } + + /* skip directories */ + if (S_ISDIR(statbuf.st_mode)) { + ret = -EISDIR; + goto out; + } + + /* skip non-readable files */ + if ((statbuf.st_mode & S_IRUSR) == 0) { + ret = -EACCES; + goto out; + } + + /* Value is limited to 4k */ + if (value_len > 4096) { + ret = -EINVAL; + goto out; + } + util_remove_trailing_chars(value, '\n'); + + /* write attribute value */ + fd = open(path, O_WRONLY | O_CLOEXEC); + if (fd < 0) { + ret = -errno; + goto out; + } + size = write(fd, value, value_len); + close(fd); + if (size < 0) { + ret = -errno; + goto out; + } + if (size < value_len) { + ret = -EIO; + goto out; + } + + /* wrote a valid value, store it in cache and return it */ + udev_list_entry_add(&dev->sysattr_value_list, sysattr, value); + out: + if (dev != udev_device) + udev_device_unref(dev); + return ret; } static int udev_device_sysattr_list_read(struct udev_device *udev_device) { - struct dirent *dent; - DIR *dir; - int num = 0; + struct dirent *dent; + DIR *dir; + int num = 0; - if (udev_device == NULL) - return -EINVAL; - if (udev_device->sysattr_list_read) - return 0; + if (udev_device == NULL) + return -EINVAL; + if (udev_device->sysattr_list_read) + return 0; - dir = opendir(udev_device_get_syspath(udev_device)); - if (!dir) - return -errno; + dir = opendir(udev_device_get_syspath(udev_device)); + if (!dir) + return -errno; - for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) { - char path[UTIL_PATH_SIZE]; - struct stat statbuf; + for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) { + char path[UTIL_PATH_SIZE]; + struct stat statbuf; - /* only handle symlinks and regular files */ - if (dent->d_type != DT_LNK && dent->d_type != DT_REG) - continue; + /* only handle symlinks and regular files */ + if (dent->d_type != DT_LNK && dent->d_type != DT_REG) + continue; - strscpyl(path, sizeof(path), udev_device_get_syspath(udev_device), "/", dent->d_name, NULL); - if (lstat(path, &statbuf) != 0) - continue; - if ((statbuf.st_mode & S_IRUSR) == 0) - continue; + strscpyl(path, sizeof(path), + udev_device_get_syspath(udev_device), "/", + dent->d_name, NULL); + if (lstat(path, &statbuf) != 0) + continue; + if ((statbuf.st_mode & S_IRUSR) == 0) + continue; - udev_list_entry_add(&udev_device->sysattr_list, dent->d_name, NULL); - num++; - } + udev_list_entry_add(&udev_device->sysattr_list, dent->d_name, + NULL); + num++; + } - closedir(dir); - udev_device->sysattr_list_read = true; + closedir(dir); + udev_device->sysattr_list_read = true; - return num; + return num; } /** @@ -1697,76 +1819,88 @@ static int udev_device_sysattr_list_read(struct udev_device *udev_device) * * Returns: the first entry of the property list **/ -struct udev_list_entry *udev_device_get_sysattr_list_entry(struct udev_device *udev_device) +struct udev_list_entry *udev_device_get_sysattr_list_entry(struct udev_device + *udev_device) { - if (!udev_device->sysattr_list_read) { - int ret; - ret = udev_device_sysattr_list_read(udev_device); - if (0 > ret) - return NULL; - } + if (!udev_device->sysattr_list_read) { + int ret; + ret = udev_device_sysattr_list_read(udev_device); + if (0 > ret) + return NULL; + } - return udev_list_get_entry(&udev_device->sysattr_list); + return udev_list_get_entry(&udev_device->sysattr_list); } -static int udev_device_set_devnode(struct udev_device *udev_device, const char *devnode) +static int udev_device_set_devnode(struct udev_device *udev_device, + const char *devnode) { - free(udev_device->devnode); - if (devnode[0] != '/') { - if (asprintf(&udev_device->devnode, "/dev/%s", devnode) < 0) - udev_device->devnode = NULL; - } else { - udev_device->devnode = strdup(devnode); - } - if (udev_device->devnode == NULL) - return -ENOMEM; - udev_device_add_property_internal(udev_device, "DEVNAME", udev_device->devnode); - return 0; + free(udev_device->devnode); + if (devnode[0] != '/') { + if (asprintf(&udev_device->devnode, "/dev/%s", devnode) < 0) + udev_device->devnode = NULL; + } else { + udev_device->devnode = strdup(devnode); + } + if (udev_device->devnode == NULL) + return -ENOMEM; + udev_device_add_property_internal(udev_device, "DEVNAME", + udev_device->devnode); + return 0; } -int udev_device_add_devlink(struct udev_device *udev_device, const char *devlink) +int udev_device_add_devlink(struct udev_device *udev_device, + const char *devlink) { - struct udev_list_entry *list_entry; + struct udev_list_entry *list_entry; - udev_device->devlinks_uptodate = false; - list_entry = udev_list_entry_add(&udev_device->devlinks_list, devlink, NULL); - if (list_entry == NULL) - return -ENOMEM; - return 0; + udev_device->devlinks_uptodate = false; + list_entry = + udev_list_entry_add(&udev_device->devlinks_list, devlink, NULL); + if (list_entry == NULL) + return -ENOMEM; + return 0; } const char *udev_device_get_id_filename(struct udev_device *udev_device) { - if (udev_device->id_filename == NULL) { - if (udev_device_get_subsystem(udev_device) == NULL) - return NULL; - - if (major(udev_device_get_devnum(udev_device)) > 0) { - /* use dev_t -- b259:131072, c254:0 */ - if (asprintf(&udev_device->id_filename, "%c%u:%u", - streq(udev_device_get_subsystem(udev_device), "block") ? 'b' : 'c', - major(udev_device_get_devnum(udev_device)), - minor(udev_device_get_devnum(udev_device))) < 0) - udev_device->id_filename = NULL; - } else if (udev_device_get_ifindex(udev_device) > 0) { - /* use netdev ifindex -- n3 */ - if (asprintf(&udev_device->id_filename, "n%i", udev_device_get_ifindex(udev_device)) < 0) - udev_device->id_filename = NULL; - } else { - /* - * use $subsys:$syname -- pci:0000:00:1f.2 - * sysname() has '!' translated, get it from devpath - */ - const char *sysname; - sysname = strrchr(udev_device->devpath, '/'); - if (sysname == NULL) - return NULL; - sysname = &sysname[1]; - if (asprintf(&udev_device->id_filename, "+%s:%s", udev_device_get_subsystem(udev_device), sysname) < 0) - udev_device->id_filename = NULL; - } - } - return udev_device->id_filename; + if (udev_device->id_filename == NULL) { + if (udev_device_get_subsystem(udev_device) == NULL) + return NULL; + + if (major(udev_device_get_devnum(udev_device)) > 0) { + /* use dev_t -- b259:131072, c254:0 */ + if (asprintf(&udev_device->id_filename, "%c%u:%u", + streq(udev_device_get_subsystem + (udev_device), "block") ? 'b' : 'c', + major(udev_device_get_devnum(udev_device)), + minor(udev_device_get_devnum(udev_device))) + < 0) + udev_device->id_filename = NULL; + } else if (udev_device_get_ifindex(udev_device) > 0) { + /* use netdev ifindex -- n3 */ + if (asprintf + (&udev_device->id_filename, "n%i", + udev_device_get_ifindex(udev_device)) < 0) + udev_device->id_filename = NULL; + } else { + /* + * use $subsys:$syname -- pci:0000:00:1f.2 + * sysname() has '!' translated, get it from devpath + */ + const char *sysname; + sysname = strrchr(udev_device->devpath, '/'); + if (sysname == NULL) + return NULL; + sysname = &sysname[1]; + if (asprintf + (&udev_device->id_filename, "+%s:%s", + udev_device_get_subsystem(udev_device), + sysname) < 0) + udev_device->id_filename = NULL; + } + } + return udev_device->id_filename; } /** @@ -1784,49 +1918,49 @@ const char *udev_device_get_id_filename(struct udev_device *udev_device) **/ int udev_device_get_is_initialized(struct udev_device *udev_device) { - if (!udev_device->info_loaded) - udev_device_read_db(udev_device); - return udev_device->is_initialized; + if (!udev_device->info_loaded) + udev_device_read_db(udev_device); + return udev_device->is_initialized; } void udev_device_set_is_initialized(struct udev_device *udev_device) { - udev_device->is_initialized = true; + udev_device->is_initialized = true; } static bool is_valid_tag(const char *tag) { - return !strchr(tag, ':') && !strchr(tag, ' '); + return !strchr(tag, ':') && !strchr(tag, ' '); } int udev_device_add_tag(struct udev_device *udev_device, const char *tag) { - if (!is_valid_tag(tag)) - return -EINVAL; - udev_device->tags_uptodate = false; - if (udev_list_entry_add(&udev_device->tags_list, tag, NULL) != NULL) - return 0; - return -ENOMEM; + if (!is_valid_tag(tag)) + return -EINVAL; + udev_device->tags_uptodate = false; + if (udev_list_entry_add(&udev_device->tags_list, tag, NULL) != NULL) + return 0; + return -ENOMEM; } void udev_device_remove_tag(struct udev_device *udev_device, const char *tag) { - struct udev_list_entry *e; + struct udev_list_entry *e; - if (!is_valid_tag(tag)) - return; - e = udev_list_get_entry(&udev_device->tags_list); - e = udev_list_entry_get_by_name(e, tag); - if (e) { - udev_device->tags_uptodate = false; - udev_list_entry_delete(e); - } + if (!is_valid_tag(tag)) + return; + e = udev_list_get_entry(&udev_device->tags_list); + e = udev_list_entry_get_by_name(e, tag); + if (e) { + udev_device->tags_uptodate = false; + udev_list_entry_delete(e); + } } void udev_device_cleanup_tags_list(struct udev_device *udev_device) { - udev_device->tags_uptodate = false; - udev_list_cleanup(&udev_device->tags_list); + udev_device->tags_uptodate = false; + udev_list_cleanup(&udev_device->tags_list); } /** @@ -1840,13 +1974,14 @@ void udev_device_cleanup_tags_list(struct udev_device *udev_device) * * Returns: the first entry of the tag list **/ -struct udev_list_entry *udev_device_get_tags_list_entry(struct udev_device *udev_device) +struct udev_list_entry *udev_device_get_tags_list_entry(struct udev_device + *udev_device) { - if (udev_device == NULL) - return NULL; - if (!udev_device->info_loaded) - udev_device_read_db(udev_device); - return udev_list_get_entry(&udev_device->tags_list); + if (udev_device == NULL) + return NULL; + if (!udev_device->info_loaded) + udev_device_read_db(udev_device); + return udev_list_get_entry(&udev_device->tags_list); } /** @@ -1860,280 +1995,295 @@ struct udev_list_entry *udev_device_get_tags_list_entry(struct udev_device *udev **/ int udev_device_has_tag(struct udev_device *udev_device, const char *tag) { - struct udev_list_entry *list_entry; + struct udev_list_entry *list_entry; - if (udev_device == NULL) - return false; - if (!udev_device->info_loaded) - udev_device_read_db(udev_device); - list_entry = udev_device_get_tags_list_entry(udev_device); - if (udev_list_entry_get_by_name(list_entry, tag) != NULL) - return true; - return false; + if (udev_device == NULL) + return false; + if (!udev_device->info_loaded) + udev_device_read_db(udev_device); + list_entry = udev_device_get_tags_list_entry(udev_device); + if (udev_list_entry_get_by_name(list_entry, tag) != NULL) + return true; + return false; } #define ENVP_SIZE 128 #define MONITOR_BUF_SIZE 4096 static int update_envp_monitor_buf(struct udev_device *udev_device) { - struct udev_list_entry *list_entry; - char *s; - size_t l; - unsigned int i; - - /* monitor buffer of property strings */ - free(udev_device->monitor_buf); - udev_device->monitor_buf_len = 0; - udev_device->monitor_buf = malloc(MONITOR_BUF_SIZE); - if (udev_device->monitor_buf == NULL) - return -ENOMEM; - - /* envp array, strings will point into monitor buffer */ - if (udev_device->envp == NULL) - udev_device->envp = malloc(sizeof(char *) * ENVP_SIZE); - if (udev_device->envp == NULL) - return -ENOMEM; - - i = 0; - s = udev_device->monitor_buf; - l = MONITOR_BUF_SIZE; - udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(udev_device)) { - const char *key; - - key = udev_list_entry_get_name(list_entry); - /* skip private variables */ - if (key[0] == '.') - continue; - - /* add string to envp array */ - udev_device->envp[i++] = s; - if (i+1 >= ENVP_SIZE) - return -EINVAL; - - /* add property string to monitor buffer */ - l = strpcpyl(&s, l, key, "=", udev_list_entry_get_value(list_entry), NULL); - if (l == 0) - return -EINVAL; - /* advance past the trailing '\0' that strpcpyl() guarantees */ - s++; - l--; - } - udev_device->envp[i] = NULL; - udev_device->monitor_buf_len = s - udev_device->monitor_buf; - udev_device->envp_uptodate = true; - return 0; + struct udev_list_entry *list_entry; + char *s; + size_t l; + unsigned int i; + + /* monitor buffer of property strings */ + free(udev_device->monitor_buf); + udev_device->monitor_buf_len = 0; + udev_device->monitor_buf = malloc(MONITOR_BUF_SIZE); + if (udev_device->monitor_buf == NULL) + return -ENOMEM; + + /* envp array, strings will point into monitor buffer */ + if (udev_device->envp == NULL) + udev_device->envp = malloc(sizeof(char *) * ENVP_SIZE); + if (udev_device->envp == NULL) + return -ENOMEM; + + i = 0; + s = udev_device->monitor_buf; + l = MONITOR_BUF_SIZE; + udev_list_entry_foreach(list_entry, + udev_device_get_properties_list_entry + (udev_device)) { + const char *key; + + key = udev_list_entry_get_name(list_entry); + /* skip private variables */ + if (key[0] == '.') + continue; + + /* add string to envp array */ + udev_device->envp[i++] = s; + if (i + 1 >= ENVP_SIZE) + return -EINVAL; + + /* add property string to monitor buffer */ + l = strpcpyl(&s, l, key, "=", + udev_list_entry_get_value(list_entry), NULL); + if (l == 0) + return -EINVAL; + /* advance past the trailing '\0' that strpcpyl() guarantees */ + s++; + l--; + } + udev_device->envp[i] = NULL; + udev_device->monitor_buf_len = s - udev_device->monitor_buf; + udev_device->envp_uptodate = true; + return 0; } char **udev_device_get_properties_envp(struct udev_device *udev_device) { - if (!udev_device->envp_uptodate) - if (update_envp_monitor_buf(udev_device) != 0) - return NULL; - return udev_device->envp; + if (!udev_device->envp_uptodate) + if (update_envp_monitor_buf(udev_device) != 0) + return NULL; + return udev_device->envp; } -ssize_t udev_device_get_properties_monitor_buf(struct udev_device *udev_device, const char **buf) +ssize_t udev_device_get_properties_monitor_buf(struct udev_device * udev_device, + const char **buf) { - if (!udev_device->envp_uptodate) - if (update_envp_monitor_buf(udev_device) != 0) - return -EINVAL; - *buf = udev_device->monitor_buf; - return udev_device->monitor_buf_len; + if (!udev_device->envp_uptodate) + if (update_envp_monitor_buf(udev_device) != 0) + return -EINVAL; + *buf = udev_device->monitor_buf; + return udev_device->monitor_buf_len; } int udev_device_get_devlink_priority(struct udev_device *udev_device) { - if (!udev_device->info_loaded) - udev_device_read_db(udev_device); - return udev_device->devlink_priority; + if (!udev_device->info_loaded) + udev_device_read_db(udev_device); + return udev_device->devlink_priority; } int udev_device_set_devlink_priority(struct udev_device *udev_device, int prio) { - udev_device->devlink_priority = prio; - return 0; + udev_device->devlink_priority = prio; + return 0; } int udev_device_get_watch_handle(struct udev_device *udev_device) { - if (!udev_device->info_loaded) - udev_device_read_db(udev_device); - return udev_device->watch_handle; + if (!udev_device->info_loaded) + udev_device_read_db(udev_device); + return udev_device->watch_handle; } int udev_device_set_watch_handle(struct udev_device *udev_device, int handle) { - udev_device->watch_handle = handle; - return 0; + udev_device->watch_handle = handle; + return 0; } -bool udev_device_get_db_persist(struct udev_device *udev_device) +bool udev_device_get_db_persist(struct udev_device * udev_device) { - return udev_device->db_persist; + return udev_device->db_persist; } void udev_device_set_db_persist(struct udev_device *udev_device) { - udev_device->db_persist = true; + udev_device->db_persist = true; } int udev_device_rename(struct udev_device *udev_device, const char *name) { - char *dirname = NULL; - const char *interface; - char *new_syspath; - int r; + char *dirname = NULL; + const char *interface; + char *new_syspath; + int r; - if (udev_device == NULL || name == NULL) - return -EINVAL; + if (udev_device == NULL || name == NULL) + return -EINVAL; - dirname = dirname_malloc(udev_device->syspath); - if (!dirname) - return -ENOMEM; + dirname = dirname_malloc(udev_device->syspath); + if (!dirname) + return -ENOMEM; - new_syspath = strjoina(dirname, "/", name); + new_syspath = strjoina(dirname, "/", name); - r = udev_device_set_syspath(udev_device, new_syspath); - if (r < 0) { - libudev_safe_free( dirname ); - return r; - } + r = udev_device_set_syspath(udev_device, new_syspath); + if (r < 0) { + libudev_safe_free(dirname); + return r; + } - interface = udev_device_get_property_value(udev_device, "INTERFACE"); - if (interface) { - /* like DEVPATH_OLD, INTERFACE_OLD is not saved to the db, but only stays around for the current event */ - udev_device_add_property_internal(udev_device, "INTERFACE_OLD", interface); - udev_device_add_property_internal(udev_device, "INTERFACE", name); - } + interface = udev_device_get_property_value(udev_device, "INTERFACE"); + if (interface) { + /* like DEVPATH_OLD, INTERFACE_OLD is not saved to the db, but only stays around for the current event */ + udev_device_add_property_internal(udev_device, "INTERFACE_OLD", + interface); + udev_device_add_property_internal(udev_device, "INTERFACE", + name); + } - libudev_safe_free( dirname ); - return 0; + libudev_safe_free(dirname); + return 0; } struct udev_device *udev_device_shallow_clone(struct udev_device *old_device) { - struct udev_device *device; + struct udev_device *device; - if (old_device == NULL) - return NULL; + if (old_device == NULL) + return NULL; - device = udev_device_new(old_device->udev); - if (!device) { - errno = ENOMEM; + device = udev_device_new(old_device->udev); + if (!device) { + errno = ENOMEM; - return NULL; - } + return NULL; + } - udev_device_set_syspath(device, udev_device_get_syspath(old_device)); - udev_device_set_subsystem(device, udev_device_get_subsystem(old_device)); - udev_device_set_devnum(device, udev_device_get_devnum(old_device)); + udev_device_set_syspath(device, udev_device_get_syspath(old_device)); + udev_device_set_subsystem(device, + udev_device_get_subsystem(old_device)); + udev_device_set_devnum(device, udev_device_get_devnum(old_device)); - return device; + return device; } struct udev_device *udev_device_clone_with_db(struct udev_device *old_device) { - struct udev_device *device; + struct udev_device *device; - device = udev_device_shallow_clone(old_device); - if (!device) - return NULL; + device = udev_device_shallow_clone(old_device); + if (!device) + return NULL; - udev_device_read_db(device); - udev_device_set_info_loaded(device); + udev_device_read_db(device); + udev_device_set_info_loaded(device); - return device; + return device; } // NOTE: expects "key=value" pairs separated by exactly one '\0' -struct udev_device *udev_device_new_from_nulstr(struct udev *udev, char *nulstr, ssize_t buflen) { - - struct udev_device *device = NULL; - ssize_t bufpos = 0; +struct udev_device *udev_device_new_from_nulstr(struct udev *udev, char *nulstr, + ssize_t buflen) +{ - if (nulstr == NULL || buflen <= 0) { - - errno = EINVAL; - - return NULL; - } + struct udev_device *device = NULL; + ssize_t bufpos = 0; - device = udev_device_new(udev); - if (!device) { - - errno = ENOMEM; - return NULL; - } + if (nulstr == NULL || buflen <= 0) { - udev_device_set_info_loaded(device); + errno = EINVAL; - while (bufpos < buflen) { - char *key; - size_t keylen; + return NULL; + } - key = nulstr + bufpos; - keylen = strlen(key); - if (keylen == 0) - break; + device = udev_device_new(udev); + if (!device) { - bufpos += keylen + 1; - udev_device_add_property_from_string_parse(device, key); - } + errno = ENOMEM; + return NULL; + } - if (udev_device_add_property_from_string_parse_finish(device) < 0) { - log_debug("%s", "missing values, invalid device"); - - udev_device_unref(device); + udev_device_set_info_loaded(device); - errno = EINVAL; + while (bufpos < buflen) { + char *key; + size_t keylen; - return NULL; - } + key = nulstr + bufpos; + keylen = strlen(key); + if (keylen == 0) + break; - return device; + bufpos += keylen + 1; + udev_device_add_property_from_string_parse(device, key); + } + + if (udev_device_add_property_from_string_parse_finish(device) < 0) { + log_debug("%s", "missing values, invalid device"); + + udev_device_unref(device); + + errno = EINVAL; + + return NULL; + } + + return device; } -struct udev_device *udev_device_new_from_synthetic_event(struct udev *udev, const char *syspath, const char *action) { - struct udev_device *ret; - int r; +struct udev_device *udev_device_new_from_synthetic_event(struct udev *udev, + const char *syspath, + const char *action) +{ + struct udev_device *ret; + int r; - if (!action) { - errno = EINVAL; - return NULL; - } + if (!action) { + errno = EINVAL; + return NULL; + } - ret = udev_device_new_from_syspath(udev, syspath); - if (!ret) - return NULL; + ret = udev_device_new_from_syspath(udev, syspath); + if (!ret) + return NULL; - r = udev_device_read_uevent_file(ret); - if (r < 0) { - udev_device_unref(ret); - errno = -r; - return NULL; - } + r = udev_device_read_uevent_file(ret); + if (r < 0) { + udev_device_unref(ret); + errno = -r; + return NULL; + } - r = udev_device_set_action(ret, action); - if (r < 0) { - udev_device_unref(ret); - errno = -r; - return NULL; - } + r = udev_device_set_action(ret, action); + if (r < 0) { + udev_device_unref(ret); + errno = -r; + return NULL; + } - return ret; + return ret; } -int udev_device_copy_properties(struct udev_device *dst, struct udev_device *src) { - struct udev_list_entry *entry; +int udev_device_copy_properties(struct udev_device *dst, + struct udev_device *src) +{ + struct udev_list_entry *entry; - for ((entry = udev_device_get_properties_list_entry(src)); entry; entry = udev_list_entry_get_next(entry)) { - const char *key, *value; + for ((entry = udev_device_get_properties_list_entry(src)); entry; + entry = udev_list_entry_get_next(entry)) { + const char *key, *value; - key = udev_list_entry_get_name(entry); - value = udev_list_entry_get_value(entry); + key = udev_list_entry_get_name(entry); + value = udev_list_entry_get_value(entry); - udev_device_add_property(dst, key, value); - } + udev_device_add_property(dst, key, value); + } - return 0; + return 0; } diff --git a/libudev-compat/libudev-enumerate.c b/libudev-compat/libudev-enumerate.c index 7046020..c03ff4f 100644 --- a/libudev-compat/libudev-enumerate.c +++ b/libudev-compat/libudev-enumerate.c @@ -48,8 +48,8 @@ */ struct syspath { - char *syspath; - size_t len; + char *syspath; + size_t len; }; /** @@ -58,22 +58,22 @@ struct syspath { * Opaque object representing one device lookup/sort context. */ struct udev_enumerate { - struct udev *udev; - int refcount; - struct udev_list sysattr_match_list; - struct udev_list sysattr_nomatch_list; - struct udev_list subsystem_match_list; - struct udev_list subsystem_nomatch_list; - struct udev_list sysname_match_list; - struct udev_list properties_match_list; - struct udev_list tags_match_list; - struct udev_device *parent_match; - struct udev_list devices_list; - struct syspath *devices; - unsigned int devices_cur; - unsigned int devices_max; - bool devices_uptodate:1; - bool match_is_initialized; + struct udev *udev; + int refcount; + struct udev_list sysattr_match_list; + struct udev_list sysattr_nomatch_list; + struct udev_list subsystem_match_list; + struct udev_list subsystem_nomatch_list; + struct udev_list sysname_match_list; + struct udev_list properties_match_list; + struct udev_list tags_match_list; + struct udev_device *parent_match; + struct udev_list devices_list; + struct syspath *devices; + unsigned int devices_cur; + unsigned int devices_max; + bool devices_uptodate:1; + bool match_is_initialized; }; /** @@ -86,24 +86,24 @@ struct udev_enumerate { **/ struct udev_enumerate *udev_enumerate_new(struct udev *udev) { - struct udev_enumerate *udev_enumerate; - - if (udev == NULL) - return NULL; - udev_enumerate = new0(struct udev_enumerate, 1); - if (udev_enumerate == NULL) - return NULL; - udev_enumerate->refcount = 1; - udev_enumerate->udev = udev; - udev_list_init(udev, &udev_enumerate->sysattr_match_list, false); - udev_list_init(udev, &udev_enumerate->sysattr_nomatch_list, false); - udev_list_init(udev, &udev_enumerate->subsystem_match_list, true); - udev_list_init(udev, &udev_enumerate->subsystem_nomatch_list, true); - udev_list_init(udev, &udev_enumerate->sysname_match_list, true); - udev_list_init(udev, &udev_enumerate->properties_match_list, false); - udev_list_init(udev, &udev_enumerate->tags_match_list, true); - udev_list_init(udev, &udev_enumerate->devices_list, false); - return udev_enumerate; + struct udev_enumerate *udev_enumerate; + + if (udev == NULL) + return NULL; + udev_enumerate = new0(struct udev_enumerate, 1); + if (udev_enumerate == NULL) + return NULL; + udev_enumerate->refcount = 1; + udev_enumerate->udev = udev; + udev_list_init(udev, &udev_enumerate->sysattr_match_list, false); + udev_list_init(udev, &udev_enumerate->sysattr_nomatch_list, false); + udev_list_init(udev, &udev_enumerate->subsystem_match_list, true); + udev_list_init(udev, &udev_enumerate->subsystem_nomatch_list, true); + udev_list_init(udev, &udev_enumerate->sysname_match_list, true); + udev_list_init(udev, &udev_enumerate->properties_match_list, false); + udev_list_init(udev, &udev_enumerate->tags_match_list, true); + udev_list_init(udev, &udev_enumerate->devices_list, false); + return udev_enumerate; } /** @@ -116,10 +116,10 @@ struct udev_enumerate *udev_enumerate_new(struct udev *udev) **/ struct udev_enumerate *udev_enumerate_ref(struct udev_enumerate *udev_enumerate) { - if (udev_enumerate == NULL) - return NULL; - udev_enumerate->refcount++; - return udev_enumerate; + if (udev_enumerate == NULL) + return NULL; + udev_enumerate->refcount++; + return udev_enumerate; } /** @@ -131,29 +131,30 @@ struct udev_enumerate *udev_enumerate_ref(struct udev_enumerate *udev_enumerate) * * Returns: #NULL **/ -struct udev_enumerate *udev_enumerate_unref(struct udev_enumerate *udev_enumerate) -{ - unsigned int i; - - if (udev_enumerate == NULL) - return NULL; - udev_enumerate->refcount--; - if (udev_enumerate->refcount > 0) - return NULL; - udev_list_cleanup(&udev_enumerate->sysattr_match_list); - udev_list_cleanup(&udev_enumerate->sysattr_nomatch_list); - udev_list_cleanup(&udev_enumerate->subsystem_match_list); - udev_list_cleanup(&udev_enumerate->subsystem_nomatch_list); - udev_list_cleanup(&udev_enumerate->sysname_match_list); - udev_list_cleanup(&udev_enumerate->properties_match_list); - udev_list_cleanup(&udev_enumerate->tags_match_list); - udev_device_unref(udev_enumerate->parent_match); - udev_list_cleanup(&udev_enumerate->devices_list); - for (i = 0; i < udev_enumerate->devices_cur; i++) - free(udev_enumerate->devices[i].syspath); - free(udev_enumerate->devices); - free(udev_enumerate); - return NULL; +struct udev_enumerate *udev_enumerate_unref(struct udev_enumerate + *udev_enumerate) +{ + unsigned int i; + + if (udev_enumerate == NULL) + return NULL; + udev_enumerate->refcount--; + if (udev_enumerate->refcount > 0) + return NULL; + udev_list_cleanup(&udev_enumerate->sysattr_match_list); + udev_list_cleanup(&udev_enumerate->sysattr_nomatch_list); + udev_list_cleanup(&udev_enumerate->subsystem_match_list); + udev_list_cleanup(&udev_enumerate->subsystem_nomatch_list); + udev_list_cleanup(&udev_enumerate->sysname_match_list); + udev_list_cleanup(&udev_enumerate->properties_match_list); + udev_list_cleanup(&udev_enumerate->tags_match_list); + udev_device_unref(udev_enumerate->parent_match); + udev_list_cleanup(&udev_enumerate->devices_list); + for (i = 0; i < udev_enumerate->devices_cur; i++) + free(udev_enumerate->devices[i].syspath); + free(udev_enumerate->devices); + free(udev_enumerate); + return NULL; } /** @@ -166,75 +167,80 @@ struct udev_enumerate *udev_enumerate_unref(struct udev_enumerate *udev_enumerat */ struct udev *udev_enumerate_get_udev(struct udev_enumerate *udev_enumerate) { - if (udev_enumerate == NULL) - return NULL; - return udev_enumerate->udev; + if (udev_enumerate == NULL) + return NULL; + return udev_enumerate->udev; } -static int syspath_add(struct udev_enumerate *udev_enumerate, const char *syspath) +static int syspath_add(struct udev_enumerate *udev_enumerate, + const char *syspath) { - char *path; - struct syspath *entry; - - /* double array size if needed */ - if (udev_enumerate->devices_cur >= udev_enumerate->devices_max) { - struct syspath *buf; - unsigned int add; - - add = udev_enumerate->devices_max; - if (add < 1024) - add = 1024; - buf = realloc(udev_enumerate->devices, (udev_enumerate->devices_max + add) * sizeof(struct syspath)); - if (buf == NULL) - return -ENOMEM; - udev_enumerate->devices = buf; - udev_enumerate->devices_max += add; - } - - path = strdup(syspath); - if (path == NULL) - return -ENOMEM; - entry = &udev_enumerate->devices[udev_enumerate->devices_cur]; - entry->syspath = path; - entry->len = strlen(path); - udev_enumerate->devices_cur++; - udev_enumerate->devices_uptodate = false; - return 0; + char *path; + struct syspath *entry; + + /* double array size if needed */ + if (udev_enumerate->devices_cur >= udev_enumerate->devices_max) { + struct syspath *buf; + unsigned int add; + + add = udev_enumerate->devices_max; + if (add < 1024) + add = 1024; + buf = + realloc(udev_enumerate->devices, + (udev_enumerate->devices_max + + add) * sizeof(struct syspath)); + if (buf == NULL) + return -ENOMEM; + udev_enumerate->devices = buf; + udev_enumerate->devices_max += add; + } + + path = strdup(syspath); + if (path == NULL) + return -ENOMEM; + entry = &udev_enumerate->devices[udev_enumerate->devices_cur]; + entry->syspath = path; + entry->len = strlen(path); + udev_enumerate->devices_cur++; + udev_enumerate->devices_uptodate = false; + return 0; } static int syspath_cmp(const void *p1, const void *p2) { - const struct syspath *path1 = p1; - const struct syspath *path2 = p2; - size_t len; - int ret; - - len = MIN(path1->len, path2->len); - ret = memcmp(path1->syspath, path2->syspath, len); - if (ret == 0) { - if (path1->len < path2->len) - ret = -1; - else if (path1->len > path2->len) - ret = 1; - } - return ret; + const struct syspath *path1 = p1; + const struct syspath *path2 = p2; + size_t len; + int ret; + + len = MIN(path1->len, path2->len); + ret = memcmp(path1->syspath, path2->syspath, len); + if (ret == 0) { + if (path1->len < path2->len) + ret = -1; + else if (path1->len > path2->len) + ret = 1; + } + return ret; } /* For devices that should be moved to the absolute end of the list */ static bool devices_delay_end(struct udev *udev, const char *syspath) { - static const char *delay_device_list[] = { - "/block/md", - "/block/dm-", - NULL - }; - int i; - - for (i = 0; delay_device_list[i] != NULL; i++) { - if (strstr(syspath + strlen("/sys"), delay_device_list[i]) != NULL) - return true; - } - return false; + static const char *delay_device_list[] = { + "/block/md", + "/block/dm-", + NULL + }; + int i; + + for (i = 0; delay_device_list[i] != NULL; i++) { + if (strstr(syspath + strlen("/sys"), delay_device_list[i]) != + NULL) + return true; + } + return false; } /* For devices that should just be moved a little bit later, just @@ -242,25 +248,25 @@ static bool devices_delay_end(struct udev *udev, const char *syspath) * number of characters that make up that common prefix */ static size_t devices_delay_later(struct udev *udev, const char *syspath) { - const char *c; + const char *c; - /* For sound cards the control device must be enumerated last - * to make sure it's the final device node that gets ACLs - * applied. Applications rely on this fact and use ACL changes - * on the control node as an indicator that the ACL change of - * the entire sound card completed. The kernel makes this - * guarantee when creating those devices, and hence we should - * too when enumerating them. */ + /* For sound cards the control device must be enumerated last + * to make sure it's the final device node that gets ACLs + * applied. Applications rely on this fact and use ACL changes + * on the control node as an indicator that the ACL change of + * the entire sound card completed. The kernel makes this + * guarantee when creating those devices, and hence we should + * too when enumerating them. */ - if ((c = strstr(syspath, "/sound/card"))) { - c += 11; - c += strcspn(c, "/"); + if ((c = strstr(syspath, "/sound/card"))) { + c += 11; + c += strcspn(c, "/"); - if (startswith(c, "/controlC")) - return c - syspath + 1; - } + if (startswith(c, "/controlC")) + return c - syspath + 1; + } - return 0; + return 0; } /** @@ -271,78 +277,92 @@ static size_t devices_delay_later(struct udev *udev, const char *syspath) * * Returns: a udev_list_entry. */ -struct udev_list_entry *udev_enumerate_get_list_entry(struct udev_enumerate *udev_enumerate) -{ - if (udev_enumerate == NULL) - return NULL; - if (!udev_enumerate->devices_uptodate) { - unsigned int i; - int move_later = -1; - unsigned int max; - struct syspath *prev = NULL; - size_t move_later_prefix = 0; - - udev_list_cleanup(&udev_enumerate->devices_list); - qsort_safe(udev_enumerate->devices, udev_enumerate->devices_cur, sizeof(struct syspath), syspath_cmp); - - max = udev_enumerate->devices_cur; - for (i = 0; i < max; i++) { - struct syspath *entry = &udev_enumerate->devices[i]; - - /* skip duplicated entries */ - if (prev != NULL && - entry->len == prev->len && - memcmp(entry->syspath, prev->syspath, entry->len) == 0) - continue; - prev = entry; - - /* skip to be delayed devices, and add them to the end of the list */ - if (devices_delay_end(udev_enumerate->udev, entry->syspath)) { - syspath_add(udev_enumerate, entry->syspath); - /* need to update prev here for the case realloc() gives a different address */ - prev = &udev_enumerate->devices[i]; - continue; - } - - /* skip to be delayed devices, and move the to - * the point where the prefix changes. We can - * only move one item at a time. */ - if (move_later == -1) { - move_later_prefix = devices_delay_later(udev_enumerate->udev, entry->syspath); - - if (move_later_prefix > 0) { - move_later = i; - continue; - } - } - - if ((move_later >= 0) && - !strneq(entry->syspath, udev_enumerate->devices[move_later].syspath, move_later_prefix)) { - - udev_list_entry_add(&udev_enumerate->devices_list, - udev_enumerate->devices[move_later].syspath, NULL); - move_later = -1; - } - - udev_list_entry_add(&udev_enumerate->devices_list, entry->syspath, NULL); - } - - if (move_later >= 0) - udev_list_entry_add(&udev_enumerate->devices_list, - udev_enumerate->devices[move_later].syspath, NULL); - - /* add and cleanup delayed devices from end of list */ - for (i = max; i < udev_enumerate->devices_cur; i++) { - struct syspath *entry = &udev_enumerate->devices[i]; - - udev_list_entry_add(&udev_enumerate->devices_list, entry->syspath, NULL); - free(entry->syspath); - } - udev_enumerate->devices_cur = max; - - udev_enumerate->devices_uptodate = true; - } - return udev_list_get_entry(&udev_enumerate->devices_list); +struct udev_list_entry *udev_enumerate_get_list_entry(struct udev_enumerate + *udev_enumerate) +{ + if (udev_enumerate == NULL) + return NULL; + if (!udev_enumerate->devices_uptodate) { + unsigned int i; + int move_later = -1; + unsigned int max; + struct syspath *prev = NULL; + size_t move_later_prefix = 0; + + udev_list_cleanup(&udev_enumerate->devices_list); + qsort_safe(udev_enumerate->devices, udev_enumerate->devices_cur, + sizeof(struct syspath), syspath_cmp); + + max = udev_enumerate->devices_cur; + for (i = 0; i < max; i++) { + struct syspath *entry = &udev_enumerate->devices[i]; + + /* skip duplicated entries */ + if (prev != NULL && + entry->len == prev->len && + memcmp(entry->syspath, prev->syspath, + entry->len) == 0) + continue; + prev = entry; + + /* skip to be delayed devices, and add them to the end of the list */ + if (devices_delay_end + (udev_enumerate->udev, entry->syspath)) { + syspath_add(udev_enumerate, entry->syspath); + /* need to update prev here for the case realloc() gives a different address */ + prev = &udev_enumerate->devices[i]; + continue; + } + + /* skip to be delayed devices, and move the to + * the point where the prefix changes. We can + * only move one item at a time. */ + if (move_later == -1) { + move_later_prefix = + devices_delay_later(udev_enumerate->udev, + entry->syspath); + + if (move_later_prefix > 0) { + move_later = i; + continue; + } + } + + if ((move_later >= 0) && + !strneq(entry->syspath, + udev_enumerate->devices[move_later].syspath, + move_later_prefix)) { + + udev_list_entry_add(&udev_enumerate-> + devices_list, + udev_enumerate-> + devices[move_later].syspath, + NULL); + move_later = -1; + } + + udev_list_entry_add(&udev_enumerate->devices_list, + entry->syspath, NULL); + } + + if (move_later >= 0) + udev_list_entry_add(&udev_enumerate->devices_list, + udev_enumerate->devices[move_later]. + syspath, NULL); + + /* add and cleanup delayed devices from end of list */ + for (i = max; i < udev_enumerate->devices_cur; i++) { + struct syspath *entry = &udev_enumerate->devices[i]; + + udev_list_entry_add(&udev_enumerate->devices_list, + entry->syspath, NULL); + free(entry->syspath); + } + udev_enumerate->devices_cur = max; + + udev_enumerate->devices_uptodate = true; + } + return udev_list_get_entry(&udev_enumerate->devices_list); } /** @@ -354,15 +374,17 @@ struct udev_list_entry *udev_enumerate_get_list_entry(struct udev_enumerate *ude * * Returns: 0 on success, otherwise a negative error value. */ -int udev_enumerate_add_match_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem) +int udev_enumerate_add_match_subsystem(struct udev_enumerate *udev_enumerate, + const char *subsystem) { - if (udev_enumerate == NULL) - return -EINVAL; - if (subsystem == NULL) - return 0; - if (udev_list_entry_add(&udev_enumerate->subsystem_match_list, subsystem, NULL) == NULL) - return -ENOMEM; - return 0; + if (udev_enumerate == NULL) + return -EINVAL; + if (subsystem == NULL) + return 0; + if (udev_list_entry_add + (&udev_enumerate->subsystem_match_list, subsystem, NULL) == NULL) + return -ENOMEM; + return 0; } /** @@ -374,15 +396,17 @@ int udev_enumerate_add_match_subsystem(struct udev_enumerate *udev_enumerate, co * * Returns: 0 on success, otherwise a negative error value. */ -int udev_enumerate_add_nomatch_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem) +int udev_enumerate_add_nomatch_subsystem(struct udev_enumerate *udev_enumerate, + const char *subsystem) { - if (udev_enumerate == NULL) - return -EINVAL; - if (subsystem == NULL) - return 0; - if (udev_list_entry_add(&udev_enumerate->subsystem_nomatch_list, subsystem, NULL) == NULL) - return -ENOMEM; - return 0; + if (udev_enumerate == NULL) + return -EINVAL; + if (subsystem == NULL) + return 0; + if (udev_list_entry_add + (&udev_enumerate->subsystem_nomatch_list, subsystem, NULL) == NULL) + return -ENOMEM; + return 0; } /** @@ -395,15 +419,17 @@ int udev_enumerate_add_nomatch_subsystem(struct udev_enumerate *udev_enumerate, * * Returns: 0 on success, otherwise a negative error value. */ -int udev_enumerate_add_match_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value) +int udev_enumerate_add_match_sysattr(struct udev_enumerate *udev_enumerate, + const char *sysattr, const char *value) { - if (udev_enumerate == NULL) - return -EINVAL; - if (sysattr == NULL) - return 0; - if (udev_list_entry_add(&udev_enumerate->sysattr_match_list, sysattr, value) == NULL) - return -ENOMEM; - return 0; + if (udev_enumerate == NULL) + return -EINVAL; + if (sysattr == NULL) + return 0; + if (udev_list_entry_add + (&udev_enumerate->sysattr_match_list, sysattr, value) == NULL) + return -ENOMEM; + return 0; } /** @@ -416,35 +442,38 @@ int udev_enumerate_add_match_sysattr(struct udev_enumerate *udev_enumerate, cons * * Returns: 0 on success, otherwise a negative error value. */ -int udev_enumerate_add_nomatch_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value) +int udev_enumerate_add_nomatch_sysattr(struct udev_enumerate *udev_enumerate, + const char *sysattr, const char *value) { - if (udev_enumerate == NULL) - return -EINVAL; - if (sysattr == NULL) - return 0; - if (udev_list_entry_add(&udev_enumerate->sysattr_nomatch_list, sysattr, value) == NULL) - return -ENOMEM; - return 0; + if (udev_enumerate == NULL) + return -EINVAL; + if (sysattr == NULL) + return 0; + if (udev_list_entry_add + (&udev_enumerate->sysattr_nomatch_list, sysattr, value) == NULL) + return -ENOMEM; + return 0; } -static int match_sysattr_value(struct udev_device *dev, const char *sysattr, const char *match_val) +static int match_sysattr_value(struct udev_device *dev, const char *sysattr, + const char *match_val) { - const char *val = NULL; - bool match = false; - - val = udev_device_get_sysattr_value(dev, sysattr); - if (val == NULL) - goto exit; - if (match_val == NULL) { - match = true; - goto exit; - } - if (fnmatch(match_val, val, 0) == 0) { - match = true; - goto exit; - } -exit: - return match; + const char *val = NULL; + bool match = false; + + val = udev_device_get_sysattr_value(dev, sysattr); + if (val == NULL) + goto exit; + if (match_val == NULL) { + match = true; + goto exit; + } + if (fnmatch(match_val, val, 0) == 0) { + match = true; + goto exit; + } + exit: + return match; } /** @@ -457,15 +486,17 @@ static int match_sysattr_value(struct udev_device *dev, const char *sysattr, con * * Returns: 0 on success, otherwise a negative error value. */ -int udev_enumerate_add_match_property(struct udev_enumerate *udev_enumerate, const char *property, const char *value) +int udev_enumerate_add_match_property(struct udev_enumerate *udev_enumerate, + const char *property, const char *value) { - if (udev_enumerate == NULL) - return -EINVAL; - if (property == NULL) - return 0; - if (udev_list_entry_add(&udev_enumerate->properties_match_list, property, value) == NULL) - return -ENOMEM; - return 0; + if (udev_enumerate == NULL) + return -EINVAL; + if (property == NULL) + return 0; + if (udev_list_entry_add + (&udev_enumerate->properties_match_list, property, value) == NULL) + return -ENOMEM; + return 0; } /** @@ -477,15 +508,17 @@ int udev_enumerate_add_match_property(struct udev_enumerate *udev_enumerate, con * * Returns: 0 on success, otherwise a negative error value. */ -int udev_enumerate_add_match_tag(struct udev_enumerate *udev_enumerate, const char *tag) +int udev_enumerate_add_match_tag(struct udev_enumerate *udev_enumerate, + const char *tag) { - if (udev_enumerate == NULL) - return -EINVAL; - if (tag == NULL) - return 0; - if (udev_list_entry_add(&udev_enumerate->tags_match_list, tag, NULL) == NULL) - return -ENOMEM; - return 0; + if (udev_enumerate == NULL) + return -EINVAL; + if (tag == NULL) + return 0; + if (udev_list_entry_add(&udev_enumerate->tags_match_list, tag, NULL) == + NULL) + return -ENOMEM; + return 0; } /** @@ -501,16 +534,17 @@ int udev_enumerate_add_match_tag(struct udev_enumerate *udev_enumerate, const ch * * Returns: 0 on success, otherwise a negative error value. */ -int udev_enumerate_add_match_parent(struct udev_enumerate *udev_enumerate, struct udev_device *parent) +int udev_enumerate_add_match_parent(struct udev_enumerate *udev_enumerate, + struct udev_device *parent) { - if (udev_enumerate == NULL) - return -EINVAL; - if (parent == NULL) - return 0; - if (udev_enumerate->parent_match != NULL) - udev_device_unref(udev_enumerate->parent_match); - udev_enumerate->parent_match = udev_device_ref(parent); - return 0; + if (udev_enumerate == NULL) + return -EINVAL; + if (parent == NULL) + return 0; + if (udev_enumerate->parent_match != NULL) + udev_device_unref(udev_enumerate->parent_match); + udev_enumerate->parent_match = udev_device_ref(parent); + return 0; } /** @@ -531,12 +565,13 @@ int udev_enumerate_add_match_parent(struct udev_enumerate *udev_enumerate, struc * * Returns: 0 on success, otherwise a negative error value. */ -int udev_enumerate_add_match_is_initialized(struct udev_enumerate *udev_enumerate) +int udev_enumerate_add_match_is_initialized(struct udev_enumerate + *udev_enumerate) { - if (udev_enumerate == NULL) - return -EINVAL; - udev_enumerate->match_is_initialized = true; - return 0; + if (udev_enumerate == NULL) + return -EINVAL; + udev_enumerate->match_is_initialized = true; + return 0; } /** @@ -548,224 +583,268 @@ int udev_enumerate_add_match_is_initialized(struct udev_enumerate *udev_enumerat * * Returns: 0 on success, otherwise a negative error value. */ -int udev_enumerate_add_match_sysname(struct udev_enumerate *udev_enumerate, const char *sysname) +int udev_enumerate_add_match_sysname(struct udev_enumerate *udev_enumerate, + const char *sysname) { - if (udev_enumerate == NULL) - return -EINVAL; - if (sysname == NULL) - return 0; - if (udev_list_entry_add(&udev_enumerate->sysname_match_list, sysname, NULL) == NULL) - return -ENOMEM; - return 0; + if (udev_enumerate == NULL) + return -EINVAL; + if (sysname == NULL) + return 0; + if (udev_list_entry_add + (&udev_enumerate->sysname_match_list, sysname, NULL) == NULL) + return -ENOMEM; + return 0; } -static bool match_sysattr(struct udev_enumerate *udev_enumerate, struct udev_device *dev) +static bool match_sysattr(struct udev_enumerate *udev_enumerate, + struct udev_device *dev) { - struct udev_list_entry *list_entry; - - /* skip list */ - udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->sysattr_nomatch_list)) { - if (match_sysattr_value(dev, udev_list_entry_get_name(list_entry), - udev_list_entry_get_value(list_entry))) - return false; - } - /* include list */ - if (udev_list_get_entry(&udev_enumerate->sysattr_match_list) != NULL) { - udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->sysattr_match_list)) { - /* anything that does not match, will make it FALSE */ - if (!match_sysattr_value(dev, udev_list_entry_get_name(list_entry), - udev_list_entry_get_value(list_entry))) - return false; - } - return true; - } - return true; + struct udev_list_entry *list_entry; + + /* skip list */ + udev_list_entry_foreach(list_entry, + udev_list_get_entry(&udev_enumerate-> + sysattr_nomatch_list)) { + if (match_sysattr_value + (dev, udev_list_entry_get_name(list_entry), + udev_list_entry_get_value(list_entry))) + return false; + } + /* include list */ + if (udev_list_get_entry(&udev_enumerate->sysattr_match_list) != NULL) { + udev_list_entry_foreach(list_entry, + udev_list_get_entry(&udev_enumerate-> + sysattr_match_list)) + { + /* anything that does not match, will make it FALSE */ + if (!match_sysattr_value + (dev, udev_list_entry_get_name(list_entry), + udev_list_entry_get_value(list_entry))) + return false; + } + return true; + } + return true; } -static bool match_property(struct udev_enumerate *udev_enumerate, struct udev_device *dev) +static bool match_property(struct udev_enumerate *udev_enumerate, + struct udev_device *dev) { - struct udev_list_entry *list_entry; - bool match = false; - - /* no match always matches */ - if (udev_list_get_entry(&udev_enumerate->properties_match_list) == NULL) - return true; - - /* loop over matches */ - udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->properties_match_list)) { - const char *match_key = udev_list_entry_get_name(list_entry); - const char *match_value = udev_list_entry_get_value(list_entry); - struct udev_list_entry *property_entry; - - /* loop over device properties */ - udev_list_entry_foreach(property_entry, udev_device_get_properties_list_entry(dev)) { - const char *dev_key = udev_list_entry_get_name(property_entry); - const char *dev_value = udev_list_entry_get_value(property_entry); - - if (fnmatch(match_key, dev_key, 0) != 0) - continue; - if (match_value == NULL && dev_value == NULL) { - match = true; - goto out; - } - if (match_value == NULL || dev_value == NULL) - continue; - if (fnmatch(match_value, dev_value, 0) == 0) { - match = true; - goto out; - } - } - } -out: - return match; + struct udev_list_entry *list_entry; + bool match = false; + + /* no match always matches */ + if (udev_list_get_entry(&udev_enumerate->properties_match_list) == NULL) + return true; + + /* loop over matches */ + udev_list_entry_foreach(list_entry, + udev_list_get_entry(&udev_enumerate-> + properties_match_list)) { + const char *match_key = udev_list_entry_get_name(list_entry); + const char *match_value = udev_list_entry_get_value(list_entry); + struct udev_list_entry *property_entry; + + /* loop over device properties */ + udev_list_entry_foreach(property_entry, + udev_device_get_properties_list_entry + (dev)) { + const char *dev_key = + udev_list_entry_get_name(property_entry); + const char *dev_value = + udev_list_entry_get_value(property_entry); + + if (fnmatch(match_key, dev_key, 0) != 0) + continue; + if (match_value == NULL && dev_value == NULL) { + match = true; + goto out; + } + if (match_value == NULL || dev_value == NULL) + continue; + if (fnmatch(match_value, dev_value, 0) == 0) { + match = true; + goto out; + } + } + } + out: + return match; } -static bool match_tag(struct udev_enumerate *udev_enumerate, struct udev_device *dev) +static bool match_tag(struct udev_enumerate *udev_enumerate, + struct udev_device *dev) { - struct udev_list_entry *list_entry; + struct udev_list_entry *list_entry; - /* no match always matches */ - if (udev_list_get_entry(&udev_enumerate->tags_match_list) == NULL) - return true; + /* no match always matches */ + if (udev_list_get_entry(&udev_enumerate->tags_match_list) == NULL) + return true; - /* loop over matches */ - udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->tags_match_list)) - if (!udev_device_has_tag(dev, udev_list_entry_get_name(list_entry))) - return false; + /* loop over matches */ + udev_list_entry_foreach(list_entry, + udev_list_get_entry(&udev_enumerate-> + tags_match_list)) + if (!udev_device_has_tag(dev, udev_list_entry_get_name(list_entry))) + return false; - return true; + return true; } -static bool match_parent(struct udev_enumerate *udev_enumerate, struct udev_device *dev) +static bool match_parent(struct udev_enumerate *udev_enumerate, + struct udev_device *dev) { - if (udev_enumerate->parent_match == NULL) - return true; + if (udev_enumerate->parent_match == NULL) + return true; - return startswith(udev_device_get_devpath(dev), udev_device_get_devpath(udev_enumerate->parent_match)); + return startswith(udev_device_get_devpath(dev), + udev_device_get_devpath(udev_enumerate-> + parent_match)); } -static bool match_sysname(struct udev_enumerate *udev_enumerate, const char *sysname) +static bool match_sysname(struct udev_enumerate *udev_enumerate, + const char *sysname) { - struct udev_list_entry *list_entry; + struct udev_list_entry *list_entry; + + if (udev_list_get_entry(&udev_enumerate->sysname_match_list) == NULL) + return true; + + udev_list_entry_foreach(list_entry, + udev_list_get_entry(&udev_enumerate-> + sysname_match_list)) { + if (fnmatch(udev_list_entry_get_name(list_entry), sysname, 0) != + 0) + continue; + return true; + } + return false; +} - if (udev_list_get_entry(&udev_enumerate->sysname_match_list) == NULL) - return true; +static int scan_dir_and_add_devices(struct udev_enumerate *udev_enumerate, + const char *basedir, const char *subdir1, + const char *subdir2) +{ + char path[UTIL_PATH_SIZE]; + size_t l; + char *s; + DIR *dir; + struct dirent *dent; + + s = path; + l = strpcpyl(&s, sizeof(path), "/sys/", basedir, NULL); + if (subdir1 != NULL) + l = strpcpyl(&s, l, "/", subdir1, NULL); + if (subdir2 != NULL) + strpcpyl(&s, l, "/", subdir2, NULL); + dir = opendir(path); + if (dir == NULL) + return -ENOENT; + for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) { + char syspath[UTIL_PATH_SIZE]; + struct udev_device *dev; + + if (dent->d_name[0] == '.') + continue; + + if (!match_sysname(udev_enumerate, dent->d_name)) + continue; + + strscpyl(syspath, sizeof(syspath), path, "/", dent->d_name, + NULL); + dev = + udev_device_new_from_syspath(udev_enumerate->udev, syspath); + if (dev == NULL) + continue; + + if (udev_enumerate->match_is_initialized) { + /* + * All devices with a device node or network interfaces + * possibly need udev to adjust the device node permission + * or context, or rename the interface before it can be + * reliably used from other processes. + * + * For now, we can only check these types of devices, we + * might not store a database, and have no way to find out + * for all other types of devices. + */ + if (!udev_device_get_is_initialized(dev) && + (major(udev_device_get_devnum(dev)) > 0 + || udev_device_get_ifindex(dev) > 0)) + goto nomatch; + } + if (!match_parent(udev_enumerate, dev)) + goto nomatch; + if (!match_tag(udev_enumerate, dev)) + goto nomatch; + if (!match_property(udev_enumerate, dev)) + goto nomatch; + if (!match_sysattr(udev_enumerate, dev)) + goto nomatch; + + syspath_add(udev_enumerate, udev_device_get_syspath(dev)); + nomatch: + udev_device_unref(dev); + } + closedir(dir); + return 0; +} - udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->sysname_match_list)) { - if (fnmatch(udev_list_entry_get_name(list_entry), sysname, 0) != 0) - continue; - return true; - } - return false; +static bool match_subsystem(struct udev_enumerate *udev_enumerate, + const char *subsystem) +{ + struct udev_list_entry *list_entry; + + if (!subsystem) + return false; + + udev_list_entry_foreach(list_entry, + udev_list_get_entry(&udev_enumerate-> + subsystem_nomatch_list)) { + if (fnmatch(udev_list_entry_get_name(list_entry), subsystem, 0) + == 0) + return false; + } + + if (udev_list_get_entry(&udev_enumerate->subsystem_match_list) != NULL) { + udev_list_entry_foreach(list_entry, + udev_list_get_entry(&udev_enumerate-> + subsystem_match_list)) + { + if (fnmatch + (udev_list_entry_get_name(list_entry), subsystem, + 0) == 0) + return true; + } + return false; + } + + return true; } -static int scan_dir_and_add_devices(struct udev_enumerate *udev_enumerate, - const char *basedir, const char *subdir1, const char *subdir2) -{ - char path[UTIL_PATH_SIZE]; - size_t l; - char *s; - DIR *dir; - struct dirent *dent; - - s = path; - l = strpcpyl(&s, sizeof(path), "/sys/", basedir, NULL); - if (subdir1 != NULL) - l = strpcpyl(&s, l, "/", subdir1, NULL); - if (subdir2 != NULL) - strpcpyl(&s, l, "/", subdir2, NULL); - dir = opendir(path); - if (dir == NULL) - return -ENOENT; - for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) { - char syspath[UTIL_PATH_SIZE]; - struct udev_device *dev; - - if (dent->d_name[0] == '.') - continue; - - if (!match_sysname(udev_enumerate, dent->d_name)) - continue; - - strscpyl(syspath, sizeof(syspath), path, "/", dent->d_name, NULL); - dev = udev_device_new_from_syspath(udev_enumerate->udev, syspath); - if (dev == NULL) - continue; - - if (udev_enumerate->match_is_initialized) { - /* - * All devices with a device node or network interfaces - * possibly need udev to adjust the device node permission - * or context, or rename the interface before it can be - * reliably used from other processes. - * - * For now, we can only check these types of devices, we - * might not store a database, and have no way to find out - * for all other types of devices. - */ - if (!udev_device_get_is_initialized(dev) && - (major(udev_device_get_devnum(dev)) > 0 || udev_device_get_ifindex(dev) > 0)) - goto nomatch; - } - if (!match_parent(udev_enumerate, dev)) - goto nomatch; - if (!match_tag(udev_enumerate, dev)) - goto nomatch; - if (!match_property(udev_enumerate, dev)) - goto nomatch; - if (!match_sysattr(udev_enumerate, dev)) - goto nomatch; - - syspath_add(udev_enumerate, udev_device_get_syspath(dev)); -nomatch: - udev_device_unref(dev); - } - closedir(dir); - return 0; -} - -static bool match_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem) -{ - struct udev_list_entry *list_entry; - - if (!subsystem) - return false; - - udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->subsystem_nomatch_list)) { - if (fnmatch(udev_list_entry_get_name(list_entry), subsystem, 0) == 0) - return false; - } - - if (udev_list_get_entry(&udev_enumerate->subsystem_match_list) != NULL) { - udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->subsystem_match_list)) { - if (fnmatch(udev_list_entry_get_name(list_entry), subsystem, 0) == 0) - return true; - } - return false; - } - - return true; -} - -static int scan_dir(struct udev_enumerate *udev_enumerate, const char *basedir, const char *subdir, const char *subsystem) -{ - char path[UTIL_PATH_SIZE]; - DIR *dir; - struct dirent *dent; - - strscpyl(path, sizeof(path), "/sys/", basedir, NULL); - dir = opendir(path); - if (dir == NULL) - return -1; - for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) { - if (dent->d_name[0] == '.') - continue; - if (!match_subsystem(udev_enumerate, subsystem != NULL ? subsystem : dent->d_name)) - continue; - scan_dir_and_add_devices(udev_enumerate, basedir, dent->d_name, subdir); - } - closedir(dir); - return 0; +static int scan_dir(struct udev_enumerate *udev_enumerate, const char *basedir, + const char *subdir, const char *subsystem) +{ + char path[UTIL_PATH_SIZE]; + DIR *dir; + struct dirent *dent; + + strscpyl(path, sizeof(path), "/sys/", basedir, NULL); + dir = opendir(path); + if (dir == NULL) + return -1; + for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) { + if (dent->d_name[0] == '.') + continue; + if (!match_subsystem + (udev_enumerate, + subsystem != NULL ? subsystem : dent->d_name)) + continue; + scan_dir_and_add_devices(udev_enumerate, basedir, dent->d_name, + subdir); + } + closedir(dir); + return 0; } /** @@ -777,142 +856,153 @@ static int scan_dir(struct udev_enumerate *udev_enumerate, const char *basedir, * * Returns: 0 on success, otherwise a negative error value. */ -int udev_enumerate_add_syspath(struct udev_enumerate *udev_enumerate, const char *syspath) +int udev_enumerate_add_syspath(struct udev_enumerate *udev_enumerate, + const char *syspath) { - struct udev_device *udev_device; - - if (udev_enumerate == NULL) - return -EINVAL; - if (syspath == NULL) - return 0; - /* resolve to real syspath */ - udev_device = udev_device_new_from_syspath(udev_enumerate->udev, syspath); - if (udev_device == NULL) - return -EINVAL; - syspath_add(udev_enumerate, udev_device_get_syspath(udev_device)); - udev_device_unref(udev_device); - return 0; + struct udev_device *udev_device; + + if (udev_enumerate == NULL) + return -EINVAL; + if (syspath == NULL) + return 0; + /* resolve to real syspath */ + udev_device = + udev_device_new_from_syspath(udev_enumerate->udev, syspath); + if (udev_device == NULL) + return -EINVAL; + syspath_add(udev_enumerate, udev_device_get_syspath(udev_device)); + udev_device_unref(udev_device); + return 0; } static int scan_devices_tags(struct udev_enumerate *udev_enumerate) { - struct udev_list_entry *list_entry; - - /* scan only tagged devices, use tags reverse-index, instead of searching all devices in /sys */ - udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->tags_match_list)) { - DIR *dir; - struct dirent *dent; - char path[UTIL_PATH_SIZE]; - - strscpyl(path, sizeof(path), "/run/udev/tags/", udev_list_entry_get_name(list_entry), NULL); - dir = opendir(path); - if (dir == NULL) - continue; - for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) { - struct udev_device *dev; - - if (dent->d_name[0] == '.') - continue; - - dev = udev_device_new_from_device_id(udev_enumerate->udev, dent->d_name); - if (dev == NULL) - continue; - - if (!match_subsystem(udev_enumerate, udev_device_get_subsystem(dev))) - goto nomatch; - if (!match_sysname(udev_enumerate, udev_device_get_sysname(dev))) - goto nomatch; - if (!match_parent(udev_enumerate, dev)) - goto nomatch; - if (!match_property(udev_enumerate, dev)) - goto nomatch; - if (!match_sysattr(udev_enumerate, dev)) - goto nomatch; - - syspath_add(udev_enumerate, udev_device_get_syspath(dev)); -nomatch: - udev_device_unref(dev); - } - closedir(dir); - } - return 0; + struct udev_list_entry *list_entry; + + /* scan only tagged devices, use tags reverse-index, instead of searching all devices in /sys */ + udev_list_entry_foreach(list_entry, + udev_list_get_entry(&udev_enumerate-> + tags_match_list)) { + DIR *dir; + struct dirent *dent; + char path[UTIL_PATH_SIZE]; + + strscpyl(path, sizeof(path), "/run/udev/tags/", + udev_list_entry_get_name(list_entry), NULL); + dir = opendir(path); + if (dir == NULL) + continue; + for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) { + struct udev_device *dev; + + if (dent->d_name[0] == '.') + continue; + + dev = + udev_device_new_from_device_id(udev_enumerate->udev, + dent->d_name); + if (dev == NULL) + continue; + + if (!match_subsystem + (udev_enumerate, udev_device_get_subsystem(dev))) + goto nomatch; + if (!match_sysname + (udev_enumerate, udev_device_get_sysname(dev))) + goto nomatch; + if (!match_parent(udev_enumerate, dev)) + goto nomatch; + if (!match_property(udev_enumerate, dev)) + goto nomatch; + if (!match_sysattr(udev_enumerate, dev)) + goto nomatch; + + syspath_add(udev_enumerate, + udev_device_get_syspath(dev)); + nomatch: + udev_device_unref(dev); + } + closedir(dir); + } + return 0; } static int parent_add_child(struct udev_enumerate *enumerate, const char *path) { - struct udev_device *dev; - int r = 0; - - dev = udev_device_new_from_syspath(enumerate->udev, path); - if (dev == NULL) - return -ENODEV; - - if (!match_subsystem(enumerate, udev_device_get_subsystem(dev))) - goto nomatch; - if (!match_sysname(enumerate, udev_device_get_sysname(dev))) - goto nomatch; - if (!match_property(enumerate, dev)) - goto nomatch; - if (!match_sysattr(enumerate, dev)) - goto nomatch; - - syspath_add(enumerate, udev_device_get_syspath(dev)); - r = 1; - -nomatch: - udev_device_unref(dev); - return r; + struct udev_device *dev; + int r = 0; + + dev = udev_device_new_from_syspath(enumerate->udev, path); + if (dev == NULL) + return -ENODEV; + + if (!match_subsystem(enumerate, udev_device_get_subsystem(dev))) + goto nomatch; + if (!match_sysname(enumerate, udev_device_get_sysname(dev))) + goto nomatch; + if (!match_property(enumerate, dev)) + goto nomatch; + if (!match_sysattr(enumerate, dev)) + goto nomatch; + + syspath_add(enumerate, udev_device_get_syspath(dev)); + r = 1; + + nomatch: + udev_device_unref(dev); + return r; } -static int parent_crawl_children(struct udev_enumerate *enumerate, const char *path, int maxdepth) +static int parent_crawl_children(struct udev_enumerate *enumerate, + const char *path, int maxdepth) { - DIR *d; - struct dirent *dent; - - d = opendir(path); - if (d == NULL) - return -errno; - - for (dent = readdir(d); dent != NULL; dent = readdir(d)) { - char *child; - - if (dent->d_name[0] == '.') - continue; - if (dent->d_type != DT_DIR) - continue; - if (asprintf(&child, "%s/%s", path, dent->d_name) < 0) - continue; - parent_add_child(enumerate, child); - if (maxdepth > 0) - parent_crawl_children(enumerate, child, maxdepth-1); - free(child); - } - - closedir(d); - return 0; + DIR *d; + struct dirent *dent; + + d = opendir(path); + if (d == NULL) + return -errno; + + for (dent = readdir(d); dent != NULL; dent = readdir(d)) { + char *child; + + if (dent->d_name[0] == '.') + continue; + if (dent->d_type != DT_DIR) + continue; + if (asprintf(&child, "%s/%s", path, dent->d_name) < 0) + continue; + parent_add_child(enumerate, child); + if (maxdepth > 0) + parent_crawl_children(enumerate, child, maxdepth - 1); + free(child); + } + + closedir(d); + return 0; } static int scan_devices_children(struct udev_enumerate *enumerate) { - const char *path; + const char *path; - path = udev_device_get_syspath(enumerate->parent_match); - parent_add_child(enumerate, path); - return parent_crawl_children(enumerate, path, 256); + path = udev_device_get_syspath(enumerate->parent_match); + parent_add_child(enumerate, path); + return parent_crawl_children(enumerate, path, 256); } static int scan_devices_all(struct udev_enumerate *udev_enumerate) { - struct stat statbuf; - - if (stat("/sys/subsystem", &statbuf) == 0) { - /* we have /subsystem/, forget all the old stuff */ - scan_dir(udev_enumerate, "subsystem", "devices", NULL); - } else { - scan_dir(udev_enumerate, "bus", "devices", NULL); - scan_dir(udev_enumerate, "class", NULL, NULL); - } - return 0; + struct stat statbuf; + + if (stat("/sys/subsystem", &statbuf) == 0) { + /* we have /subsystem/, forget all the old stuff */ + scan_dir(udev_enumerate, "subsystem", "devices", NULL); + } else { + scan_dir(udev_enumerate, "bus", "devices", NULL); + scan_dir(udev_enumerate, "class", NULL, NULL); + } + return 0; } /** @@ -926,19 +1016,19 @@ static int scan_devices_all(struct udev_enumerate *udev_enumerate) **/ int udev_enumerate_scan_devices(struct udev_enumerate *udev_enumerate) { - if (udev_enumerate == NULL) - return -EINVAL; + if (udev_enumerate == NULL) + return -EINVAL; - /* efficiently lookup tags only, we maintain a reverse-index */ - if (udev_list_get_entry(&udev_enumerate->tags_match_list) != NULL) - return scan_devices_tags(udev_enumerate); + /* efficiently lookup tags only, we maintain a reverse-index */ + if (udev_list_get_entry(&udev_enumerate->tags_match_list) != NULL) + return scan_devices_tags(udev_enumerate); - /* walk the subtree of one parent device only */ - if (udev_enumerate->parent_match != NULL) - return scan_devices_children(udev_enumerate); + /* walk the subtree of one parent device only */ + if (udev_enumerate->parent_match != NULL) + return scan_devices_children(udev_enumerate); - /* scan devices of all subsystems */ - return scan_devices_all(udev_enumerate); + /* scan devices of all subsystems */ + return scan_devices_all(udev_enumerate); } /** @@ -951,27 +1041,27 @@ int udev_enumerate_scan_devices(struct udev_enumerate *udev_enumerate) **/ int udev_enumerate_scan_subsystems(struct udev_enumerate *udev_enumerate) { - struct stat statbuf; - const char *subsysdir; + struct stat statbuf; + const char *subsysdir; - if (udev_enumerate == NULL) - return -EINVAL; + if (udev_enumerate == NULL) + return -EINVAL; - /* all kernel modules */ - if (match_subsystem(udev_enumerate, "module")) - scan_dir_and_add_devices(udev_enumerate, "module", NULL, NULL); + /* all kernel modules */ + if (match_subsystem(udev_enumerate, "module")) + scan_dir_and_add_devices(udev_enumerate, "module", NULL, NULL); - if (stat("/sys/subsystem", &statbuf) == 0) - subsysdir = "subsystem"; - else - subsysdir = "bus"; + if (stat("/sys/subsystem", &statbuf) == 0) + subsysdir = "subsystem"; + else + subsysdir = "bus"; - /* all subsystems (only buses support coldplug) */ - if (match_subsystem(udev_enumerate, "subsystem")) - scan_dir_and_add_devices(udev_enumerate, subsysdir, NULL, NULL); + /* all subsystems (only buses support coldplug) */ + if (match_subsystem(udev_enumerate, "subsystem")) + scan_dir_and_add_devices(udev_enumerate, subsysdir, NULL, NULL); - /* all subsystem drivers */ - if (match_subsystem(udev_enumerate, "drivers")) - scan_dir(udev_enumerate, subsysdir, "drivers", "drivers"); - return 0; + /* all subsystem drivers */ + if (match_subsystem(udev_enumerate, "drivers")) + scan_dir(udev_enumerate, subsysdir, "drivers", "drivers"); + return 0; } diff --git a/libudev-compat/libudev-fs.c b/libudev-compat/libudev-fs.c index be138dc..bf56793 100644 --- a/libudev-compat/libudev-fs.c +++ b/libudev-compat/libudev-fs.c @@ -23,11 +23,11 @@ #define UDEV_FS_WATCH_DIR_FLAGS (IN_CREATE | IN_ONESHOT) -#ifdef TEST +#ifdef TEST #define UDEV_FS_EVENTS_DIR "/tmp/events" #else #define UDEV_FS_EVENTS_DIR "/dev/metadata/udev/events" -#endif +#endif // how many monitors can there be per process? // this is probably big enough. @@ -36,724 +36,754 @@ #define UDEV_MAX_MONITORS 32768 #endif -static int udev_monitor_fs_events_path( char const* name, char* pathbuf, int nonce ); +static int udev_monitor_fs_events_path(char const *name, char *pathbuf, + int nonce); // We need to make sure that on fork, a udev_monitor listening to the underlying filesystem // will listen to its *own* process's events directory, at all times. To do this, we will // track every monitor that exists, by holding a reference internally. When the process // forks, we'll re-initialize all monitors to point to the new process's events directory. -static struct udev_monitor* g_monitor_table[ UDEV_MAX_MONITORS ]; -static int g_monitor_lock = 0; // primitive mutex that can work across forks -static pid_t g_pid = 0; // tells us when to re-target the monitors - +static struct udev_monitor *g_monitor_table[UDEV_MAX_MONITORS]; +static int g_monitor_lock = 0; // primitive mutex that can work across forks +static pid_t g_pid = 0; // tells us when to re-target the monitors // spin-lock to lock the monitor table -static void g_monitor_table_spinlock() { - - bool locked = false; - while( 1 ) { - - locked = __sync_bool_compare_and_swap( &g_monitor_lock, 0, 1 ); - if( locked ) { - break; - } - } +static void g_monitor_table_spinlock() +{ + + bool locked = false; + while (1) { + + locked = __sync_bool_compare_and_swap(&g_monitor_lock, 0, 1); + if (locked) { + break; + } + } } // unlock the monitor table -static void g_monitor_table_unlock() { - - g_monitor_lock = 0; - - // make sure spinners see it. - __sync_synchronize(); +static void g_monitor_table_unlock() +{ + + g_monitor_lock = 0; + + // make sure spinners see it. + __sync_synchronize(); } // on fork(), create a new events directory for each of this process's monitors // and point them all to them. This way, both the parent and child can continue // to receive device packets. // NOTE: can only call async-safe methods -static void udev_monitor_atfork(void) { - - int errsv = errno; - int rc = 0; - int i = 0; - int cnt = 0; - pid_t pid = getpid(); - struct udev_monitor* monitor = NULL; - int socket_fds[2]; - struct epoll_event ev; - - write( STDERR_FILENO, "forked! begin split\n", strlen("forked! begin split\n") ); - - memset( &ev, 0, sizeof(struct epoll_event) ); - - // reset each monitor's inotify fd to point to a new PID-specific directory instead - g_monitor_table_spinlock(); - - if( g_pid != pid ) { - - // child; do the fork - for( i = 0; i < UDEV_MAX_MONITORS; i++ ) { - - if( g_monitor_table[i] == NULL ) { - continue; - } - - monitor = g_monitor_table[i]; - - if( monitor->type != UDEV_MONITOR_TYPE_UDEV ) { - continue; - } - - if( monitor->inotify_fd < 0 ) { - continue; - } - - if( monitor->epoll_fd < 0 ) { - continue; - } - - if( monitor->events_wd < 0 ) { - continue; - } - - // reset the socket buffer--the parent will be said to have - // received intermittent events before the child was created. - if( monitor->sock >= 0 ) { - - // stop watching this socket--we'll regenerate it later - epoll_ctl( monitor->epoll_fd, EPOLL_CTL_DEL, monitor->sock, NULL ); - close( monitor->sock ); - monitor->sock = -1; - } - - if( monitor->sock_fs >= 0 ) { - close( monitor->sock_fs ); - monitor->sock_fs = -1; - } - - rc = socketpair( AF_LOCAL, SOCK_RAW | SOCK_NONBLOCK | SOCK_CLOEXEC, 0, socket_fds ); - if( rc < 0 ) { - - // not much we can do here, except log an error - write( STDERR_FILENO, "Failed to generate a socketpair\n", strlen( "Failed to generate a socketpair\n" ) ); - - udev_monitor_fs_shutdown( monitor ); - g_monitor_table[i] = NULL; - continue; - } - - // child's copy of the monitor has its own socketpair - monitor->sock = socket_fds[0]; - monitor->sock_fs = socket_fds[1]; - - // reinstall its filter - udev_monitor_filter_update( monitor ); - - // watch the child's socket - ev.events = EPOLLIN; - ev.data.fd = monitor->sock; - rc = epoll_ctl( monitor->epoll_fd, EPOLL_CTL_ADD, monitor->sock, &ev ); - if( rc < 0 ) { - - // not much we can do here, except log an error - write( STDERR_FILENO, "Failed to add monitor socket\n", strlen("Failed to add monitor socket\n") ); - - udev_monitor_fs_shutdown( monitor ); - g_monitor_table[i] = NULL; - continue; - } - - // reset the inotify watch - rc = inotify_rm_watch( monitor->inotify_fd, monitor->events_wd ); - monitor->events_wd = -1; - - if( rc < 0 ) { - - rc = -errno; - if( rc == -EINVAL ) { - - // monitor->events_wd was invalid - rc = 0; - } - else if( rc == -EBADF ) { - - // monitor->inotify_fd is invalid. - // not much we can do here, except log an error - write( STDERR_FILENO, "Invalid inotify handle\n", strlen("Invalid inotify handle")); - - udev_monitor_fs_shutdown( monitor ); - g_monitor_table[i] = NULL; - continue; - } - } - - if( rc == 0 ) { - - udev_monitor_fs_events_path( "", monitor->events_dir, i ); - - // try to create a new directory for this monitor - rc = mkdir( monitor->events_dir, 0700 ); - - if( rc < 0 ) { - // failed, we have. - // child will not get any notifications from this monitor - rc = -errno; - write( STDERR_FILENO, "Failed to mkdir ", strlen("Failed to mkdir ") ); - write( STDERR_FILENO, monitor->events_dir, strlen(monitor->events_dir) ); - write( STDERR_FILENO, "\n", 1 ); - - udev_monitor_fs_shutdown( monitor ); - g_monitor_table[i] = NULL; - return; - } - - // reconnect to the new directory - monitor->events_wd = inotify_add_watch( monitor->inotify_fd, monitor->events_dir, UDEV_FS_WATCH_DIR_FLAGS ); - if( monitor->events_wd < 0 ) { - - // there's not much we can safely do here, besides log an error - write( STDERR_FILENO, "Failed to watch ", strlen( "Failed to watch " ) ); - write( STDERR_FILENO, monitor->events_dir, strlen(monitor->events_dir) ); - write( STDERR_FILENO, "\n", 1 ); - } - } - else { - - // there's not much we can safely do here, besides log an error - rc = -errno; - write( STDERR_FILENO, "Failed to disconnect!\n", strlen("Failed to disconnect!\n") ); - } - } - - g_pid = pid; - } - - g_monitor_table_unlock(); - - write( STDERR_FILENO, "end atfork()\n", strlen("end atfork()\n") ); - - // restore... - errno = errsv; -} +static void udev_monitor_atfork(void) +{ + + int errsv = errno; + int rc = 0; + int i = 0; + int cnt = 0; + pid_t pid = getpid(); + struct udev_monitor *monitor = NULL; + int socket_fds[2]; + struct epoll_event ev; + + write(STDERR_FILENO, "forked! begin split\n", + strlen("forked! begin split\n")); + + memset(&ev, 0, sizeof(struct epoll_event)); + + // reset each monitor's inotify fd to point to a new PID-specific directory instead + g_monitor_table_spinlock(); + + if (g_pid != pid) { + + // child; do the fork + for (i = 0; i < UDEV_MAX_MONITORS; i++) { + + if (g_monitor_table[i] == NULL) { + continue; + } + + monitor = g_monitor_table[i]; + + if (monitor->type != UDEV_MONITOR_TYPE_UDEV) { + continue; + } + + if (monitor->inotify_fd < 0) { + continue; + } + + if (monitor->epoll_fd < 0) { + continue; + } + + if (monitor->events_wd < 0) { + continue; + } + // reset the socket buffer--the parent will be said to have + // received intermittent events before the child was created. + if (monitor->sock >= 0) { + + // stop watching this socket--we'll regenerate it later + epoll_ctl(monitor->epoll_fd, EPOLL_CTL_DEL, + monitor->sock, NULL); + close(monitor->sock); + monitor->sock = -1; + } + + if (monitor->sock_fs >= 0) { + close(monitor->sock_fs); + monitor->sock_fs = -1; + } + + rc = socketpair(AF_LOCAL, + SOCK_RAW | SOCK_NONBLOCK | SOCK_CLOEXEC, + 0, socket_fds); + if (rc < 0) { + + // not much we can do here, except log an error + write(STDERR_FILENO, + "Failed to generate a socketpair\n", + strlen + ("Failed to generate a socketpair\n")); + + udev_monitor_fs_shutdown(monitor); + g_monitor_table[i] = NULL; + continue; + } + // child's copy of the monitor has its own socketpair + monitor->sock = socket_fds[0]; + monitor->sock_fs = socket_fds[1]; + + // reinstall its filter + udev_monitor_filter_update(monitor); + + // watch the child's socket + ev.events = EPOLLIN; + ev.data.fd = monitor->sock; + rc = epoll_ctl(monitor->epoll_fd, EPOLL_CTL_ADD, + monitor->sock, &ev); + if (rc < 0) { + + // not much we can do here, except log an error + write(STDERR_FILENO, + "Failed to add monitor socket\n", + strlen("Failed to add monitor socket\n")); + + udev_monitor_fs_shutdown(monitor); + g_monitor_table[i] = NULL; + continue; + } + // reset the inotify watch + rc = inotify_rm_watch(monitor->inotify_fd, + monitor->events_wd); + monitor->events_wd = -1; + + if (rc < 0) { + + rc = -errno; + if (rc == -EINVAL) { + + // monitor->events_wd was invalid + rc = 0; + } else if (rc == -EBADF) { + + // monitor->inotify_fd is invalid. + // not much we can do here, except log an error + write(STDERR_FILENO, + "Invalid inotify handle\n", + strlen("Invalid inotify handle")); + + udev_monitor_fs_shutdown(monitor); + g_monitor_table[i] = NULL; + continue; + } + } + + if (rc == 0) { + + udev_monitor_fs_events_path("", + monitor->events_dir, + i); + + // try to create a new directory for this monitor + rc = mkdir(monitor->events_dir, 0700); + + if (rc < 0) { + // failed, we have. + // child will not get any notifications from this monitor + rc = -errno; + write(STDERR_FILENO, "Failed to mkdir ", + strlen("Failed to mkdir ")); + write(STDERR_FILENO, + monitor->events_dir, + strlen(monitor->events_dir)); + write(STDERR_FILENO, "\n", 1); + + udev_monitor_fs_shutdown(monitor); + g_monitor_table[i] = NULL; + return; + } + // reconnect to the new directory + monitor->events_wd = + inotify_add_watch(monitor->inotify_fd, + monitor->events_dir, + UDEV_FS_WATCH_DIR_FLAGS); + if (monitor->events_wd < 0) { + // there's not much we can safely do here, besides log an error + write(STDERR_FILENO, "Failed to watch ", + strlen("Failed to watch ")); + write(STDERR_FILENO, + monitor->events_dir, + strlen(monitor->events_dir)); + write(STDERR_FILENO, "\n", 1); + } + } else { + + // there's not much we can safely do here, besides log an error + rc = -errno; + write(STDERR_FILENO, "Failed to disconnect!\n", + strlen("Failed to disconnect!\n")); + } + } + + g_pid = pid; + } + + g_monitor_table_unlock(); + + write(STDERR_FILENO, "end atfork()\n", strlen("end atfork()\n")); + + // restore... + errno = errsv; +} // register a monitor in our list of monitors // return 0 on success // return -ENOSPC if we're out of slots -static int udev_monitor_register( struct udev_monitor* monitor ) { - - g_monitor_table_spinlock(); - - // find a free slot - int i = 0; - int rc = -ENOSPC; - for( i = 0; i < UDEV_MAX_MONITORS; i++ ) { - - if( g_monitor_table[i] == NULL ) { - - g_monitor_table[i] = monitor; - monitor->slot = i; - rc = 0; - break; - } - } - - if( g_pid == 0 ) { - - // first monitor ever. - // register our fork handler. - g_pid = getpid(); - pthread_atfork( NULL, NULL, udev_monitor_atfork ); - } - - g_monitor_table_unlock(); +static int udev_monitor_register(struct udev_monitor *monitor) +{ - return rc; -} + g_monitor_table_spinlock(); + // find a free slot + int i = 0; + int rc = -ENOSPC; + for (i = 0; i < UDEV_MAX_MONITORS; i++) { -// unregister a monitor in our list of monitors -static void udev_monitor_unregister( struct udev_monitor* monitor ) { - - if( monitor->slot < 0 ) { - return; - } - - g_monitor_table_spinlock(); - - g_monitor_table[ monitor->slot ] = NULL; - - g_monitor_table_unlock(); - - monitor->slot = -1; + if (g_monitor_table[i] == NULL) { + + g_monitor_table[i] = monitor; + monitor->slot = i; + rc = 0; + break; + } + } + + if (g_pid == 0) { + + // first monitor ever. + // register our fork handler. + g_pid = getpid(); + pthread_atfork(NULL, NULL, udev_monitor_atfork); + } + + g_monitor_table_unlock(); + + return rc; } +// unregister a monitor in our list of monitors +static void udev_monitor_unregister(struct udev_monitor *monitor) +{ + + if (monitor->slot < 0) { + return; + } + + g_monitor_table_spinlock(); + + g_monitor_table[monitor->slot] = NULL; + + g_monitor_table_unlock(); + + monitor->slot = -1; +} // write, but mask EINTR // return number of bytes written on success // return -errno on I/O error -ssize_t udev_write_uninterrupted( int fd, char const* buf, size_t len ) { - - ssize_t num_written = 0; - - if( buf == NULL ) { - return -EINVAL; - } - - while( (unsigned)num_written < len ) { - ssize_t nw = write( fd, buf + num_written, len - num_written ); - if( nw < 0 ) { - - int errsv = -errno; - if( errsv == -EINTR ) { - continue; - } - - return errsv; - } - if( nw == 0 ) { - break; - } - - num_written += nw; - } - - return num_written; -} +ssize_t udev_write_uninterrupted(int fd, char const *buf, size_t len) +{ + + ssize_t num_written = 0; + + if (buf == NULL) { + return -EINVAL; + } + + while ((unsigned)num_written < len) { + ssize_t nw = write(fd, buf + num_written, len - num_written); + if (nw < 0) { + int errsv = -errno; + if (errsv == -EINTR) { + continue; + } + + return errsv; + } + if (nw == 0) { + break; + } + + num_written += nw; + } + + return num_written; +} // read, but mask EINTR // return number of bytes read on success // return -errno on I/O error // NOTE: must be async-safe! -ssize_t udev_read_uninterrupted( int fd, char* buf, size_t len ) { - - ssize_t num_read = 0; - - if( buf == NULL ) { - return -EINVAL; - } - - while( (unsigned)num_read < len ) { - ssize_t nr = read( fd, buf + num_read, len - num_read ); - if( nr < 0 ) { - - int errsv = -errno; - if( errsv == -EINTR ) { - continue; - } - - return errsv; - } - if( nr == 0 ) { - break; - } - - num_read += nr; - } - - return num_read; -} +ssize_t udev_read_uninterrupted(int fd, char *buf, size_t len) +{ + + ssize_t num_read = 0; + + if (buf == NULL) { + return -EINVAL; + } + + while ((unsigned)num_read < len) { + ssize_t nr = read(fd, buf + num_read, len - num_read); + if (nr < 0) { + int errsv = -errno; + if (errsv == -EINTR) { + continue; + } + + return errsv; + } + if (nr == 0) { + break; + } + + num_read += nr; + } + + return num_read; +} // set up a filesystem monitor // register pthread_atfork() handlers to ensure that its children // get their own filesystem monitor state. // * set up /dev/events/libudev-$PID/ // * start watching /dev/events/libudev-$PID for new files -int udev_monitor_fs_setup( struct udev_monitor* monitor ) { - - int rc = 0; - struct epoll_event ev; - - monitor->inotify_fd = -1; - monitor->epoll_fd = -1; - monitor->sock = -1; - monitor->sock_fs = -1; - monitor->slot = -1; - - int socket_fd[2] = { -1, -1 }; - - memset( &monitor->events_dir, 0, PATH_MAX+1 ); - memset( &ev, 0, sizeof(struct epoll_event) ); - - // make sure this monitor can't disappear on us - udev_monitor_register( monitor ); - - // set up inotify - monitor->inotify_fd = inotify_init1( IN_NONBLOCK | IN_CLOEXEC ); - if( monitor->inotify_fd < 0 ) { - - rc = -errno; - log_error("inotify_init rc = %d", rc ); - - udev_monitor_fs_shutdown( monitor ); - return rc; - } - - // epoll descriptor unifying inotify and event counter - monitor->epoll_fd = epoll_create1( EPOLL_CLOEXEC ); - if( monitor->epoll_fd < 0 ) { - - rc = -errno; - log_error("epoll_create rc = %d", rc ); - - udev_monitor_fs_shutdown( monitor ); - return rc; - } - - // create our monitor directory /dev/events/libudev-$PID - udev_monitor_fs_events_path( "", monitor->events_dir, monitor->slot ); - rc = mkdir( monitor->events_dir, 0700 ); - if( rc != 0 ) { - - rc = -errno; - log_error("mkdir('%s') rc = %d", monitor->events_dir, rc ); - - udev_monitor_fs_destroy( monitor ); - return rc; - } - - // begin watching /dev/events/libudev-$PID - monitor->events_wd = inotify_add_watch( monitor->inotify_fd, monitor->events_dir, UDEV_FS_WATCH_DIR_FLAGS ); - if( monitor->events_wd < 0 ) { - - rc = -errno; - log_error("inotify_add_watch('%s') rc = %d", monitor->events_dir, rc ); - - udev_monitor_fs_destroy( monitor ); - return rc; - } - - // set up local socket pair with the parent process - // needs to be a socket (not a pipe) since we're going to attach a BPF to it. - rc = socketpair( AF_LOCAL, SOCK_RAW | SOCK_NONBLOCK | SOCK_CLOEXEC, 0, socket_fd ); - if( rc < 0 ) { - - rc = -errno; - log_error("socketpair(AF_LOCAL, SOCK_RAW|SOCK_CLOEXEC, 0) rc = %d", rc ); - - udev_monitor_fs_destroy( monitor ); - return rc; - } - - monitor->sock = socket_fd[0]; // receiving end - monitor->sock_fs = socket_fd[1]; // sending end - - // unify inotify and sock behind epoll_fd, set to poll for reading - ev.events = EPOLLIN; - ev.data.fd = monitor->inotify_fd; - rc = epoll_ctl( monitor->epoll_fd, EPOLL_CTL_ADD, monitor->inotify_fd, &ev ); - if( rc != 0 ) { - - rc = -errno; - log_error("epoll_ctl(%d on inotify_fd %d) rc = %d", monitor->epoll_fd, monitor->inotify_fd, rc ); - - udev_monitor_fs_shutdown( monitor ); - return rc; - } - - ev.data.fd = monitor->sock; - rc = epoll_ctl( monitor->epoll_fd, EPOLL_CTL_ADD, monitor->sock, &ev ); - if( rc != 0 ) { - - rc = -errno; - log_error("epoll_ctl(%d on inotify_fd %d) rc = %d", monitor->sock, monitor->sock, rc ); - - udev_monitor_fs_shutdown( monitor ); - return rc; - } - - monitor->pid = getpid(); - - return rc; -} +int udev_monitor_fs_setup(struct udev_monitor *monitor) +{ + + int rc = 0; + struct epoll_event ev; + + monitor->inotify_fd = -1; + monitor->epoll_fd = -1; + monitor->sock = -1; + monitor->sock_fs = -1; + monitor->slot = -1; + + int socket_fd[2] = { -1, -1 }; + + memset(&monitor->events_dir, 0, PATH_MAX + 1); + memset(&ev, 0, sizeof(struct epoll_event)); + + // make sure this monitor can't disappear on us + udev_monitor_register(monitor); + // set up inotify + monitor->inotify_fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC); + if (monitor->inotify_fd < 0) { + + rc = -errno; + log_error("inotify_init rc = %d", rc); + + udev_monitor_fs_shutdown(monitor); + return rc; + } + // epoll descriptor unifying inotify and event counter + monitor->epoll_fd = epoll_create1(EPOLL_CLOEXEC); + if (monitor->epoll_fd < 0) { + + rc = -errno; + log_error("epoll_create rc = %d", rc); + + udev_monitor_fs_shutdown(monitor); + return rc; + } + // create our monitor directory /dev/events/libudev-$PID + udev_monitor_fs_events_path("", monitor->events_dir, monitor->slot); + rc = mkdir(monitor->events_dir, 0700); + if (rc != 0) { + + rc = -errno; + log_error("mkdir('%s') rc = %d", monitor->events_dir, rc); + + udev_monitor_fs_destroy(monitor); + return rc; + } + // begin watching /dev/events/libudev-$PID + monitor->events_wd = + inotify_add_watch(monitor->inotify_fd, monitor->events_dir, + UDEV_FS_WATCH_DIR_FLAGS); + if (monitor->events_wd < 0) { + + rc = -errno; + log_error("inotify_add_watch('%s') rc = %d", + monitor->events_dir, rc); + + udev_monitor_fs_destroy(monitor); + return rc; + } + // set up local socket pair with the parent process + // needs to be a socket (not a pipe) since we're going to attach a BPF to it. + rc = socketpair(AF_LOCAL, SOCK_RAW | SOCK_NONBLOCK | SOCK_CLOEXEC, 0, + socket_fd); + if (rc < 0) { + + rc = -errno; + log_error + ("socketpair(AF_LOCAL, SOCK_RAW|SOCK_CLOEXEC, 0) rc = %d", + rc); + + udev_monitor_fs_destroy(monitor); + return rc; + } + + monitor->sock = socket_fd[0]; // receiving end + monitor->sock_fs = socket_fd[1]; // sending end + + // unify inotify and sock behind epoll_fd, set to poll for reading + ev.events = EPOLLIN; + ev.data.fd = monitor->inotify_fd; + rc = epoll_ctl(monitor->epoll_fd, EPOLL_CTL_ADD, monitor->inotify_fd, + &ev); + if (rc != 0) { + + rc = -errno; + log_error("epoll_ctl(%d on inotify_fd %d) rc = %d", + monitor->epoll_fd, monitor->inotify_fd, rc); + + udev_monitor_fs_shutdown(monitor); + return rc; + } + + ev.data.fd = monitor->sock; + rc = epoll_ctl(monitor->epoll_fd, EPOLL_CTL_ADD, monitor->sock, &ev); + if (rc != 0) { + + rc = -errno; + log_error("epoll_ctl(%d on inotify_fd %d) rc = %d", + monitor->sock, monitor->sock, rc); + + udev_monitor_fs_shutdown(monitor); + return rc; + } + + monitor->pid = getpid(); + + return rc; +} // shut down a monitor's filesystem-specific state // not much we can do if any shutdown step fails, so try them all -int udev_monitor_fs_shutdown( struct udev_monitor* monitor ) { - - int rc = 0; - - // stop tracking this monitor - udev_monitor_unregister( monitor ); - - if( monitor->sock >= 0 ) { - rc = shutdown( monitor->sock, SHUT_RDWR ); - if( rc < 0 ) { - rc = -errno; - log_error("shutdown(socket %d) rc = %d", monitor->sock, rc ); - } - } - - if( monitor->sock_fs >= 0 ) { - rc = shutdown( monitor->sock_fs, SHUT_RDWR ); - if( rc < 0 ) { - rc = -errno; - log_error("shutdown(socket %d) rc = %d", monitor->sock_fs, rc ); - } - } - - if( monitor->sock >= 0 ) { - rc = close( monitor->sock ); - if( rc < 0 ) { - rc = -errno; - log_error("close(socket %d) rc = %d", monitor->sock, rc ); - } - else { - monitor->sock = -1; - } - } - - if( monitor->sock_fs >= 0 ) { - rc = close( monitor->sock_fs ); - if( rc < 0 ) { - rc = -errno; - log_error("close(socket %d) rc = %d", monitor->sock_fs, rc ); - } - else { - monitor->sock_fs = -1; - } - } - - if( monitor->epoll_fd >= 0 ) { - rc = close( monitor->epoll_fd ); - if( rc < 0 ) { - rc = -errno; - log_error("close(epoll_fd %d) rc = %d", monitor->epoll_fd, rc ); - } - else { - monitor->epoll_fd = -1; - } - } - - if( monitor->events_wd >= 0 ) { - - if( monitor->inotify_fd >= 0 ) { - rc = inotify_rm_watch( monitor->inotify_fd, monitor->events_wd ); - if( rc < 0 ) { - rc = -errno; - log_error("close(events_wd %d) rc = %d", monitor->events_wd, rc ); - } - else { - monitor->events_wd = -1; - } - } - } - if( monitor->inotify_fd >= 0 ) { - rc = close( monitor->inotify_fd ); - if( rc < 0 ) { - rc = -errno; - log_error("close(inotify_fd %d) rc = %d", monitor->inotify_fd, rc ); - } - else { - monitor->inotify_fd = -1; - } - } - - return rc; -} +int udev_monitor_fs_shutdown(struct udev_monitor *monitor) +{ + int rc = 0; -// blow away all local filesystem state for a monitor -int udev_monitor_fs_destroy( struct udev_monitor* monitor ) { - - char pathbuf[ PATH_MAX+1 ]; - int dirfd = 0; - int rc = 0; - DIR* dirh = NULL; - struct dirent entry; - struct dirent* result = NULL; - bool can_rmdir = true; - - // stop listening - udev_monitor_fs_shutdown( monitor ); - - // remove events dir contents - dirfd = open( monitor->events_dir, O_DIRECTORY | O_CLOEXEC ); - if( dirfd < 0 ) { - - rc = -errno; - log_error("open('%s') rc = %d", monitor->events_dir, rc ); - return rc; - } - - dirh = fdopendir( dirfd ); - if( dirh == NULL ) { - - // OOM - rc = -errno; - close( dirfd ); - return rc; - } - - do { - - // next entry - rc = readdir_r( dirh, &entry, &result ); - if( rc != 0 ) { - - // I/O error - log_error("readdir_r('%s') rc = %d", monitor->events_dir, rc ); - break; - } - - // skip . and .. - if( strcmp( entry.d_name, "." ) == 0 || strcmp( entry.d_name, ".." ) == 0 ) { - continue; - } - - // generate full path - memset( pathbuf, 0, PATH_MAX+1 ); - - snprintf( pathbuf, PATH_MAX, "%s/%s", monitor->events_dir, entry.d_name ); - - // optimistically remove - if( entry.d_type == DT_DIR ) { - rc = rmdir( pathbuf ); - } - else { - rc = unlink( pathbuf ); - } - - if( rc != 0 ) { - - rc = -errno; - log_error("remove '%s' rc = %d", pathbuf, rc ); - - can_rmdir = false; - rc = 0; - } - - } while( result != NULL ); - - // NOTE: closes dirfd - closedir( dirh ); - - if( can_rmdir ) { - rc = rmdir( monitor->events_dir ); - if( rc != 0 ) { - - rc = -errno; - log_error("rmdir('%s') rc = %d\n", monitor->events_dir, rc); - } - } - else { - // let the caller know... - rc = -ENOTEMPTY; - } - - return rc; + // stop tracking this monitor + udev_monitor_unregister(monitor); + + if (monitor->sock >= 0) { + rc = shutdown(monitor->sock, SHUT_RDWR); + if (rc < 0) { + rc = -errno; + log_error("shutdown(socket %d) rc = %d", monitor->sock, + rc); + } + } + + if (monitor->sock_fs >= 0) { + rc = shutdown(monitor->sock_fs, SHUT_RDWR); + if (rc < 0) { + rc = -errno; + log_error("shutdown(socket %d) rc = %d", + monitor->sock_fs, rc); + } + } + + if (monitor->sock >= 0) { + rc = close(monitor->sock); + if (rc < 0) { + rc = -errno; + log_error("close(socket %d) rc = %d", monitor->sock, + rc); + } else { + monitor->sock = -1; + } + } + + if (monitor->sock_fs >= 0) { + rc = close(monitor->sock_fs); + if (rc < 0) { + rc = -errno; + log_error("close(socket %d) rc = %d", monitor->sock_fs, + rc); + } else { + monitor->sock_fs = -1; + } + } + + if (monitor->epoll_fd >= 0) { + rc = close(monitor->epoll_fd); + if (rc < 0) { + rc = -errno; + log_error("close(epoll_fd %d) rc = %d", + monitor->epoll_fd, rc); + } else { + monitor->epoll_fd = -1; + } + } + + if (monitor->events_wd >= 0) { + + if (monitor->inotify_fd >= 0) { + rc = inotify_rm_watch(monitor->inotify_fd, + monitor->events_wd); + if (rc < 0) { + rc = -errno; + log_error("close(events_wd %d) rc = %d", + monitor->events_wd, rc); + } else { + monitor->events_wd = -1; + } + } + } + if (monitor->inotify_fd >= 0) { + rc = close(monitor->inotify_fd); + if (rc < 0) { + rc = -errno; + log_error("close(inotify_fd %d) rc = %d", + monitor->inotify_fd, rc); + } else { + monitor->inotify_fd = -1; + } + } + + return rc; } +// blow away all local filesystem state for a monitor +int udev_monitor_fs_destroy(struct udev_monitor *monitor) +{ + + char pathbuf[PATH_MAX + 1]; + int dirfd = 0; + int rc = 0; + DIR *dirh = NULL; + struct dirent entry; + struct dirent *result = NULL; + bool can_rmdir = true; + + // stop listening + udev_monitor_fs_shutdown(monitor); + + // remove events dir contents + dirfd = open(monitor->events_dir, O_DIRECTORY | O_CLOEXEC); + if (dirfd < 0) { + + rc = -errno; + log_error("open('%s') rc = %d", monitor->events_dir, rc); + return rc; + } + + dirh = fdopendir(dirfd); + if (dirh == NULL) { + + // OOM + rc = -errno; + close(dirfd); + return rc; + } + + do { + + // next entry + rc = readdir_r(dirh, &entry, &result); + if (rc != 0) { + + // I/O error + log_error("readdir_r('%s') rc = %d", + monitor->events_dir, rc); + break; + } + // skip . and .. + if (strcmp(entry.d_name, ".") == 0 + || strcmp(entry.d_name, "..") == 0) { + continue; + } + // generate full path + memset(pathbuf, 0, PATH_MAX + 1); + + snprintf(pathbuf, PATH_MAX, "%s/%s", monitor->events_dir, + entry.d_name); + + // optimistically remove + if (entry.d_type == DT_DIR) { + rc = rmdir(pathbuf); + } else { + rc = unlink(pathbuf); + } + + if (rc != 0) { + + rc = -errno; + log_error("remove '%s' rc = %d", pathbuf, rc); + + can_rmdir = false; + rc = 0; + } + + } while (result != NULL); + + // NOTE: closes dirfd + closedir(dirh); + + if (can_rmdir) { + rc = rmdir(monitor->events_dir); + if (rc != 0) { + + rc = -errno; + log_error("rmdir('%s') rc = %d\n", monitor->events_dir, + rc); + } + } else { + // let the caller know... + rc = -ENOTEMPTY; + } + + return rc; +} // thread-safe and async-safe int to string for base 10 -void itoa10_safe( int val, char* str ) { - - int rc = 0; - int i = 0; - int len = 0; - int j = 0; - bool neg = false; - - // sign check - if( val < 0 ) { - val = -val; - neg = true; - } - - // consume, lowest-order to highest-order - if( val == 0 ) { - str[i] = '0'; - i++; - } - else { - while( val > 0 ) { - - int r = val % 10; - - str[i] = '0' + r; - i++; - - val /= 10; - } - } - - if( neg ) { - - str[i] = '-'; - i++; - } - - len = i; - i--; - - // reverse order to get the number - while( j < i ) { - - char tmp = *(str + i); - *(str + i) = *(str + j); - *(str + j) = tmp; - - j++; - i--; - } - - str[len] = '\0'; +void itoa10_safe(int val, char *str) +{ + + int rc = 0; + int i = 0; + int len = 0; + int j = 0; + bool neg = false; + + // sign check + if (val < 0) { + val = -val; + neg = true; + } + // consume, lowest-order to highest-order + if (val == 0) { + str[i] = '0'; + i++; + } else { + while (val > 0) { + + int r = val % 10; + + str[i] = '0' + r; + i++; + + val /= 10; + } + } + + if (neg) { + + str[i] = '-'; + i++; + } + + len = i; + i--; + + // reverse order to get the number + while (j < i) { + + char tmp = *(str + i); + *(str + i) = *(str + j); + *(str + j) = tmp; + + j++; + i--; + } + + str[len] = '\0'; } // path to a named event for this process to consume // pathbuf must have at least PATH_MAX bytes // NOTE: must be async-safe, since it's used in a pthread_atfork() callback -static int udev_monitor_fs_events_path( char const* name, char* pathbuf, int nonce ) { - - // do the equivalent of: - // snprintf( pathbuf, PATH_MAX, UDEV_FS_EVENTS_DIR "/libudev-%d-%d/%s", getpid(), nonce, name ); - - char pidbuf[10]; - pidbuf[9] = 0; +static int udev_monitor_fs_events_path(char const *name, char *pathbuf, + int nonce) +{ - char nonce_buf[50]; - nonce_buf[49] = 0; - - pid_t pid = getpid(); - - itoa10_safe( pid, pidbuf ); - itoa10_safe( nonce, nonce_buf ); - - size_t pidbuf_len = strnlen(pidbuf, 10); - size_t nonce_buf_len = strnlen( nonce_buf, 50 ); - size_t prefix_len = strlen( UDEV_FS_EVENTS_DIR ); - size_t dirname_prefix_len = strlen( "/libudev-" ); - int off = 0; - - memcpy( pathbuf, UDEV_FS_EVENTS_DIR, prefix_len ); - off += prefix_len; - - memcpy( pathbuf + off, "/libudev-", dirname_prefix_len ); - off += dirname_prefix_len; - - memcpy( pathbuf + off, pidbuf, pidbuf_len ); - off += pidbuf_len; + // do the equivalent of: + // snprintf( pathbuf, PATH_MAX, UDEV_FS_EVENTS_DIR "/libudev-%d-%d/%s", getpid(), nonce, name ); - memcpy( pathbuf + off, "-", 1 ); - off += 1; + char pidbuf[10]; + pidbuf[9] = 0; - memcpy( pathbuf + off, nonce_buf, nonce_buf_len ); - off += nonce_buf_len; - - pathbuf[off] = '/'; - off++; - - memcpy( pathbuf + off, name, strlen(name) ); - off += strlen(name); - - pathbuf[off] = '\0'; - - return off + strlen(name); + char nonce_buf[50]; + nonce_buf[49] = 0; + + pid_t pid = getpid(); + + itoa10_safe(pid, pidbuf); + itoa10_safe(nonce, nonce_buf); + + size_t pidbuf_len = strnlen(pidbuf, 10); + size_t nonce_buf_len = strnlen(nonce_buf, 50); + size_t prefix_len = strlen(UDEV_FS_EVENTS_DIR); + size_t dirname_prefix_len = strlen("/libudev-"); + int off = 0; + + memcpy(pathbuf, UDEV_FS_EVENTS_DIR, prefix_len); + off += prefix_len; + + memcpy(pathbuf + off, "/libudev-", dirname_prefix_len); + off += dirname_prefix_len; + + memcpy(pathbuf + off, pidbuf, pidbuf_len); + off += pidbuf_len; + + memcpy(pathbuf + off, "-", 1); + off += 1; + + memcpy(pathbuf + off, nonce_buf, nonce_buf_len); + off += nonce_buf_len; + + pathbuf[off] = '/'; + off++; + + memcpy(pathbuf + off, name, strlen(name)); + off += strlen(name); + + pathbuf[off] = '\0'; + + return off + strlen(name); } // send the contents of a file containing a serialized packet to the libudev client: @@ -769,219 +799,223 @@ static int udev_monitor_fs_events_path( char const* name, char* pathbuf, int non // return -EBADMSG if the file is invalid // return -EAGAIN if we'd block on send // TODO: can we use sendfile(2)? -static int udev_monitor_fs_push_event( int fd, struct udev_monitor* monitor ) { - - int rc = 0; - off_t len = 0; - size_t hdrlen = 0; - char buf[8192]; - struct stat sb; - struct msghdr msg; - struct iovec iov; - struct udev_device* dev = NULL; - size_t i = 0; - - memset( &msg, 0, sizeof(struct msghdr) ); - memset( &iov, 0, sizeof(struct iovec) ); - - // first, get the size - rc = fstat( fd, &sb ); - if( rc < 0 ) { - - rc = -errno; - log_error("fstat(%d) rc = %d", fd, rc ); - return rc; - } - - if( sb.st_size >= 8192 ) { - - rc = -EMSGSIZE; - return rc; - } - - rc = udev_read_uninterrupted( fd, buf, sb.st_size ); - if( rc < 0 ) { - - log_error("udev_read_uninterrupted(%d) rc = %d", fd, rc ); - return rc; - } - - // replace all '\n' with '\0', in case the caller wrote - // the file line by line. - for( i = 0; i < sb.st_size; i++ ) { - - if( buf[i] == '\n' ) { - buf[i] = '\0'; - } - } - - // should be a uevent packet, and should start with [add|change|move|remove]@[devpath]\0 - hdrlen = strnlen( buf, sb.st_size ) + 1; - if( hdrlen < sizeof("a@/d") || hdrlen >= sb.st_size ) { - - log_error("invalid message header: length = %zu, message length = %zd", hdrlen, sb.st_size ); - return -EBADMSG; - } - - if( strstr( buf, "@/" ) == NULL ) { - - // invalid header - log_error("%s", "invalid message header: missing '@' directive" ); - return -EBADMSG; - } - - // make a udev device - dev = udev_device_new_from_nulstr( monitor->udev, &buf[hdrlen], sb.st_size - hdrlen ); - if( dev == NULL ) { - - rc = -errno; - log_error("udev_device_new_from_nulstr() rc = %d", rc); - - return rc; - } - - // send it along - // TODO: sendfile(2)? - rc = udev_monitor_send_device( monitor, NULL, dev ); - if( rc < 0 ) { - - log_error("udev_monitor_send_device rc = %d", rc ); - } - else { - - rc = 0; - } - - udev_device_unref( dev ); - return rc; -} +static int udev_monitor_fs_push_event(int fd, struct udev_monitor *monitor) +{ + + int rc = 0; + off_t len = 0; + size_t hdrlen = 0; + char buf[8192]; + struct stat sb; + struct msghdr msg; + struct iovec iov; + struct udev_device *dev = NULL; + size_t i = 0; + + memset(&msg, 0, sizeof(struct msghdr)); + memset(&iov, 0, sizeof(struct iovec)); + + // first, get the size + rc = fstat(fd, &sb); + if (rc < 0) { + + rc = -errno; + log_error("fstat(%d) rc = %d", fd, rc); + return rc; + } + if (sb.st_size >= 8192) { + + rc = -EMSGSIZE; + return rc; + } + + rc = udev_read_uninterrupted(fd, buf, sb.st_size); + if (rc < 0) { + + log_error("udev_read_uninterrupted(%d) rc = %d", fd, rc); + return rc; + } + // replace all '\n' with '\0', in case the caller wrote + // the file line by line. + for (i = 0; i < sb.st_size; i++) { + + if (buf[i] == '\n') { + buf[i] = '\0'; + } + } + + // should be a uevent packet, and should start with [add|change|move|remove]@[devpath]\0 + hdrlen = strnlen(buf, sb.st_size) + 1; + if (hdrlen < sizeof("a@/d") || hdrlen >= sb.st_size) { + + log_error + ("invalid message header: length = %zu, message length = %zd", + hdrlen, sb.st_size); + return -EBADMSG; + } + + if (strstr(buf, "@/") == NULL) { + + // invalid header + log_error("%s", + "invalid message header: missing '@' directive"); + return -EBADMSG; + } + // make a udev device + dev = + udev_device_new_from_nulstr(monitor->udev, &buf[hdrlen], + sb.st_size - hdrlen); + if (dev == NULL) { + + rc = -errno; + log_error("udev_device_new_from_nulstr() rc = %d", rc); + + return rc; + } + // send it along + // TODO: sendfile(2)? + rc = udev_monitor_send_device(monitor, NULL, dev); + if (rc < 0) { + + log_error("udev_monitor_send_device rc = %d", rc); + } else { + + rc = 0; + } + + udev_device_unref(dev); + return rc; +} // reset the oneshot inotify watch, so it will trip on the next create. // consume pending events, if there are any, and re-watch the directory. // if the pid has changed since last time, watch the new directory. // return 0 on success // return negative on error (errno) -static int udev_monitor_fs_watch_reset( struct udev_monitor* monitor ) { - - int rc = 0; - bool inotify_triggerred = false; // was inotify triggerred? - char buf[4096] __attribute__ ((aligned(__alignof__(struct inotify_event)))); // see inotify(7) - struct pollfd pfd[1]; - - pfd[0].fd = monitor->inotify_fd; - pfd[0].events = POLLIN; - - // reset the watch by consuming all its events (should be at most one) - while( 1 ) { - - // do we have data? - rc = poll( pfd, 1, 0 ); - if( rc <= 0 ) { - - // out of data, or error - if( rc < 0 ) { - - rc = -errno; - if( rc == -EINTR ) { - - // shouldn't really happen since the timeout for poll is zero, - // but you never know... - continue; - } - - log_error("poll(%d) rc = %d\n", monitor->inotify_fd, rc ); - rc = 0; - } - - break; - } - - // at least one event remaining - // consume it - rc = read( monitor->inotify_fd, buf, 4096 ); - if( rc == 0 ) { - break; - } - - if( rc < 0 ) { - - rc = -errno; - - if( rc == -EINTR ) { - continue; - } - else if( rc == -EAGAIN || rc == -EWOULDBLOCK ) { - rc = 0; - break; - } - } - - // got one event - inotify_triggerred = true; - } +static int udev_monitor_fs_watch_reset(struct udev_monitor *monitor) +{ - - // has the PID changed? - // need to regenerate events path - if( getpid() != monitor->pid ) { - - log_trace("Switch PID from %d to %d", monitor->pid, getpid()); - - udev_monitor_fs_events_path( "", monitor->events_dir, monitor->slot ); - - rc = mkdir( monitor->events_dir, 0700 ); - if( rc != 0 ) { - - rc = -errno; - if( rc != -EEXIST ) { - - log_error("mkdir('%s') rc = %d\n", monitor->events_dir, rc ); - return rc; - } - else { - rc = 0; - } - } - - monitor->events_wd = inotify_add_watch( monitor->inotify_fd, monitor->events_dir, UDEV_FS_WATCH_DIR_FLAGS ); - if( monitor->events_wd < 0 ) { - - rc = -errno; - - log_error("inotify_add_watch('%s') rc = %d\n", monitor->events_dir, rc ); - return rc; - } - - monitor->pid = getpid(); - - // TODO: what about events that the child was supposed to receive? - // the parent forks, receives one or more events, and the child wakes up, and will miss them - // if we only do the above. - // we need to (try to) consume them here - } - - rc = inotify_add_watch( monitor->inotify_fd, monitor->events_dir, UDEV_FS_WATCH_DIR_FLAGS ); - if( rc < 0 ) { - - rc = -errno; - log_error("inotify_add_watch(%d) rc = %d", monitor->inotify_fd, rc ); - } - - return rc; + int rc = 0; + bool inotify_triggerred = false; // was inotify triggerred? + char buf[4096] __attribute__ ((aligned(__alignof__(struct inotify_event)))); // see inotify(7) + struct pollfd pfd[1]; + + pfd[0].fd = monitor->inotify_fd; + pfd[0].events = POLLIN; + + // reset the watch by consuming all its events (should be at most one) + while (1) { + + // do we have data? + rc = poll(pfd, 1, 0); + if (rc <= 0) { + + // out of data, or error + if (rc < 0) { + + rc = -errno; + if (rc == -EINTR) { + + // shouldn't really happen since the timeout for poll is zero, + // but you never know... + continue; + } + + log_error("poll(%d) rc = %d\n", + monitor->inotify_fd, rc); + rc = 0; + } + + break; + } + // at least one event remaining + // consume it + rc = read(monitor->inotify_fd, buf, 4096); + if (rc == 0) { + break; + } + + if (rc < 0) { + + rc = -errno; + + if (rc == -EINTR) { + continue; + } else if (rc == -EAGAIN || rc == -EWOULDBLOCK) { + rc = 0; + break; + } + } + // got one event + inotify_triggerred = true; + } + + // has the PID changed? + // need to regenerate events path + if (getpid() != monitor->pid) { + + log_trace("Switch PID from %d to %d", monitor->pid, getpid()); + + udev_monitor_fs_events_path("", monitor->events_dir, + monitor->slot); + + rc = mkdir(monitor->events_dir, 0700); + if (rc != 0) { + + rc = -errno; + if (rc != -EEXIST) { + + log_error("mkdir('%s') rc = %d\n", + monitor->events_dir, rc); + return rc; + } else { + rc = 0; + } + } + + monitor->events_wd = + inotify_add_watch(monitor->inotify_fd, monitor->events_dir, + UDEV_FS_WATCH_DIR_FLAGS); + if (monitor->events_wd < 0) { + + rc = -errno; + + log_error("inotify_add_watch('%s') rc = %d\n", + monitor->events_dir, rc); + return rc; + } + + monitor->pid = getpid(); + + // TODO: what about events that the child was supposed to receive? + // the parent forks, receives one or more events, and the child wakes up, and will miss them + // if we only do the above. + // we need to (try to) consume them here + } + + rc = inotify_add_watch(monitor->inotify_fd, monitor->events_dir, + UDEV_FS_WATCH_DIR_FLAGS); + if (rc < 0) { + + rc = -errno; + log_error("inotify_add_watch(%d) rc = %d", monitor->inotify_fd, + rc); + } + + return rc; } // scandir: skip . and .. -static int udev_monitor_fs_scandir_filter( const struct dirent* dent ) { - - if( strcmp( dent->d_name, "." ) == 0 || strcmp( dent->d_name, ".." ) == 0 ) { - return 0; - } - else { - return 1; - } -} +static int udev_monitor_fs_scandir_filter(const struct dirent *dent) +{ + if (strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0) { + return 0; + } else { + return 1; + } +} // push as many available events from our filesystem buffer of events off to the monitor's socketpair. // the order is determined lexicographically (i.e. we assume that whatever is writing events is naming them in @@ -992,307 +1026,346 @@ static int udev_monitor_fs_scandir_filter( const struct dirent* dent ) { // return -errno if we can't re-watch the directory // NOTE: this method should only be used if the underlying filesystem holding the events can't help us preserve the order. // NOTE: not thread-safe -int udev_monitor_fs_push_events( struct udev_monitor* monitor ) { - - char pathbuf[ PATH_MAX+1 ]; - int dirfd = -1; - int fd = -1; - int rc = 0; - int num_events = 0; - int num_valid_events = 0; - int num_sent = 0; - struct dirent** events = NULL; // names of events to buffer - int i = 0; - - // reset the watch on this directory, and ensure we're watching the right one. - rc = udev_monitor_fs_watch_reset( monitor ); - if( rc < 0 ) { - - log_error("Failed to re-watch '%s', rc = %d", monitor->events_dir, rc ); - goto udev_monitor_fs_push_events_cleanup; - } - - // find new events... - dirfd = open( monitor->events_dir, O_DIRECTORY | O_CLOEXEC ); - if( dirfd < 0 ) { - - rc = -errno; - log_error("open('%s') rc = %d", monitor->events_dir, rc ); - goto udev_monitor_fs_push_events_cleanup; - } - - num_events = scandirat( dirfd, ".", &events, udev_monitor_fs_scandir_filter, alphasort ); - - if( num_events < 0 ) { - - rc = -errno; - log_error("scandir('%s') rc = %d", monitor->events_dir, rc ); - goto udev_monitor_fs_push_events_cleanup; - } - - - if( num_events == 0 ) { - - // got nothing - rc = -ENODATA; - goto udev_monitor_fs_push_events_cleanup; - } - - num_valid_events = num_events; - - // send them all off! - for( i = 0; i < num_events; i++ ) { - - snprintf( pathbuf, PATH_MAX, "%s/%s", monitor->events_dir, events[i]->d_name ); - - fd = open( pathbuf, O_RDONLY | O_CLOEXEC ); - if( fd < 0 ) { - - rc = -errno; - log_error("cannot open event: open('%s') rc = %d", pathbuf, rc ); - - // we consider it more important to preserve order and drop events - // than to try to resend later. - unlink( pathbuf ); - } - else { - - // propagate to the monitor's socket - rc = udev_monitor_fs_push_event( fd, monitor ); - - // garbage-collect - close( fd ); - unlink( pathbuf ); - - if( rc == -EBADMSG || rc == -EMSGSIZE ) { - - // invalid message anyway - rc = 0; - num_valid_events--; - continue; - } - - else if( rc < 0 ) { - - if( rc != -EAGAIN ) { - - // socket-level error - log_error("failed to push event '%s', rc = %d", pathbuf, rc ); - break; - } - else { - - // sent as many as we could - rc = 0; - break; - } - } - else if( rc == 0 ) { - - num_sent++; - } - } - } - -udev_monitor_fs_push_events_cleanup: - - if( dirfd >= 0 ) { - close( dirfd ); - } - - if( events != NULL ) { - for( i = 0; i < num_events; i++ ) { - - if( events[i] != NULL ) { - free( events[i] ); - events[i] = NULL; - } - } - - free( events ); - } - - if( num_sent == 0 && num_valid_events > 0 ) { - - // there are pending events, but we couldn't push any. - rc = -EAGAIN; - } - - return rc; -} +int udev_monitor_fs_push_events(struct udev_monitor *monitor) +{ + + char pathbuf[PATH_MAX + 1]; + int dirfd = -1; + int fd = -1; + int rc = 0; + int num_events = 0; + int num_valid_events = 0; + int num_sent = 0; + struct dirent **events = NULL; // names of events to buffer + int i = 0; + + // reset the watch on this directory, and ensure we're watching the right one. + rc = udev_monitor_fs_watch_reset(monitor); + if (rc < 0) { + + log_error("Failed to re-watch '%s', rc = %d", + monitor->events_dir, rc); + goto udev_monitor_fs_push_events_cleanup; + } + // find new events... + dirfd = open(monitor->events_dir, O_DIRECTORY | O_CLOEXEC); + if (dirfd < 0) { + + rc = -errno; + log_error("open('%s') rc = %d", monitor->events_dir, rc); + goto udev_monitor_fs_push_events_cleanup; + } + + num_events = + scandirat(dirfd, ".", &events, udev_monitor_fs_scandir_filter, + alphasort); + + if (num_events < 0) { + + rc = -errno; + log_error("scandir('%s') rc = %d", monitor->events_dir, rc); + goto udev_monitor_fs_push_events_cleanup; + } + + if (num_events == 0) { + + // got nothing + rc = -ENODATA; + goto udev_monitor_fs_push_events_cleanup; + } + + num_valid_events = num_events; + + // send them all off! + for (i = 0; i < num_events; i++) { + + snprintf(pathbuf, PATH_MAX, "%s/%s", monitor->events_dir, + events[i]->d_name); + + fd = open(pathbuf, O_RDONLY | O_CLOEXEC); + if (fd < 0) { + + rc = -errno; + log_error("cannot open event: open('%s') rc = %d", + pathbuf, rc); + // we consider it more important to preserve order and drop events + // than to try to resend later. + unlink(pathbuf); + } else { -#ifdef TEST + // propagate to the monitor's socket + rc = udev_monitor_fs_push_event(fd, monitor); + + // garbage-collect + close(fd); + unlink(pathbuf); + + if (rc == -EBADMSG || rc == -EMSGSIZE) { + + // invalid message anyway + rc = 0; + num_valid_events--; + continue; + } + + else if (rc < 0) { + + if (rc != -EAGAIN) { + + // socket-level error + log_error + ("failed to push event '%s', rc = %d", + pathbuf, rc); + break; + } else { + + // sent as many as we could + rc = 0; + break; + } + } else if (rc == 0) { + + num_sent++; + } + } + } + + udev_monitor_fs_push_events_cleanup: + + if (dirfd >= 0) { + close(dirfd); + } + + if (events != NULL) { + for (i = 0; i < num_events; i++) { + + if (events[i] != NULL) { + free(events[i]); + events[i] = NULL; + } + } + + free(events); + } + + if (num_sent == 0 && num_valid_events > 0) { + + // there are pending events, but we couldn't push any. + rc = -EAGAIN; + } + + return rc; +} + +#ifdef TEST #include "libudev.h" -int main( int argc, char** argv ) { - - int rc = 0; - char pathbuf[PATH_MAX+1]; - struct udev* udev_client = NULL; - struct udev_monitor* monitor = NULL; - int monitor_fd = 0; - struct udev_device* dev = NULL; - struct pollfd pfd[1]; - int num_events = INT_MAX; - int num_forks = 0; - - // usage: $0 [num events to process [num times to fork]] - if( argc > 1 ) { - char* tmp = NULL; - num_events = (int)strtol( argv[1], &tmp, 10 ); - if( tmp == argv[1] || *tmp != '\0' ) { - fprintf(stderr, "Usage: %s [number of events to process [number of times to fork]]\n", argv[0] ); - exit(1); - } - - if( argc > 2 ) { - - num_forks = (int)strtol( argv[2], &tmp, 10 ); - if( tmp == argv[2] || *tmp != '\0' ) { - fprintf(stderr, "Usage: %s [number of events to process [number of times to fork]]\n", argv[0] ); - exit(1); - } - } - } - - // make sure events dir exists - log_trace("events directory '%s'", UDEV_FS_EVENTS_DIR); - - rc = mkdir( UDEV_FS_EVENTS_DIR, 0700 ); - if( rc != 0 ) { - - rc = -errno; - if( rc != -EEXIST ) { - log_error("mkdir('%s') rc = %d", UDEV_FS_EVENTS_DIR, rc ); - exit(1); - } - } - - udev_monitor_fs_events_path( "", pathbuf, 0 ); - - printf("Watching '%s'\n", pathbuf ); - - udev_client = udev_new(); - if( udev_client == NULL ) { - - // OOM - exit(2); - } - - monitor = udev_monitor_new_from_netlink( udev_client, "udev" ); - if( monitor == NULL ) { - - // OOM or error - udev_unref( udev_client ); - exit(2); - } - - printf("Press Ctrl-C to quit\n"); - - monitor_fd = udev_monitor_get_fd( monitor ); - if( monitor_fd < 0 ) { - - rc = -errno; - log_error("udev_monitor_get_fd rc = %d\n", rc ); - exit(3); - } - - pfd[0].fd = monitor_fd; - pfd[0].events = POLLIN; - - while( num_events > 0 ) { - - // wait for the next device - rc = poll( pfd, 1, -1 ); - if( rc < 0 ) { - - log_error("poll(%d) rc = %d\n", monitor_fd, rc ); - break; - } - - // get devices - while( num_events > 0 ) { - - dev = udev_monitor_receive_device( monitor ); - if( dev == NULL ) { - break; - } - - int pid = getpid(); - struct udev_list_entry *list_entry = NULL; - - printf("[%d] [%d] ACTION: '%s'\n", pid, num_events, udev_device_get_action( dev ) ); - printf("[%d] [%d] SEQNUM: %llu\n", pid, num_events, udev_device_get_seqnum( dev ) ); - printf("[%d] [%d] USEC: %llu\n", pid, num_events, udev_device_get_usec_since_initialized( dev ) ); - printf("[%d] [%d] DEVNODE: '%s'\n", pid, num_events, udev_device_get_devnode( dev ) ); - printf("[%d] [%d] DEVPATH: '%s'\n", pid, num_events, udev_device_get_devpath( dev ) ); - printf("[%d] [%d] SYSNAME: '%s'\n", pid, num_events, udev_device_get_sysname( dev ) ); - printf("[%d] [%d] SYSPATH: '%s'\n", pid, num_events, udev_device_get_syspath( dev ) ); - printf("[%d] [%d] SUBSYSTEM: '%s'\n", pid, num_events, udev_device_get_subsystem( dev ) ); - printf("[%d] [%d] DEVTYPE: '%s'\n", pid, num_events, udev_device_get_devtype( dev ) ); - printf("[%d] [%d] SYSNUM: '%s'\n", pid, num_events, udev_device_get_sysnum( dev ) ); - printf("[%d] [%d] DRIVER: '%s'\n", pid, num_events, udev_device_get_driver( dev ) ); - printf("[%d] [%d] DEVNUM: %d:%d\n", pid, num_events, major( udev_device_get_devnum( dev ) ), minor( udev_device_get_devnum( dev ) ) ); - printf("[%d] [%d] IFINDEX: '%s'\n", pid, num_events, udev_device_get_property_value( dev, "IFINDEX" ) ); - printf("[%d] [%d] DEVMODE: '%s'\n", pid, num_events, udev_device_get_property_value( dev, "DEVMODE" ) ); - printf("[%d] [%d] DEVUID: '%s'\n", pid, num_events, udev_device_get_property_value( dev, "DEVUID" ) ); - printf("[%d] [%d] DEVGID: '%s'\n", pid, num_events, udev_device_get_property_value( dev, "DEVGID" ) ); - - list_entry = udev_device_get_devlinks_list_entry( dev ); - udev_list_entry_foreach( list_entry, udev_list_entry_get_next( list_entry )) { - - printf("[%d] [%d] devlink: '%s'\n", pid, num_events, udev_list_entry_get_name( list_entry ) ); - } - - list_entry = udev_device_get_properties_list_entry( dev ); - udev_list_entry_foreach( list_entry, udev_list_entry_get_next( list_entry )) { - - printf("[%d] [%d] property: '%s' = '%s'\n", pid, num_events, udev_list_entry_get_name( list_entry ), udev_list_entry_get_value( list_entry ) ); - } - - list_entry = udev_device_get_tags_list_entry( dev ); - udev_list_entry_foreach( list_entry, udev_list_entry_get_next( list_entry )) { - - printf("[%d] [%d] tag: '%s'\n", pid, num_events, udev_list_entry_get_name( list_entry ) ); - } - - list_entry = udev_device_get_sysattr_list_entry( dev ); - udev_list_entry_foreach( list_entry, udev_list_entry_get_next( list_entry )) { - - printf("[%d] [%d] sysattr: '%s'\n", pid, num_events, udev_list_entry_get_name( list_entry ) ); - } - - printf("\n"); - - udev_device_unref( dev ); - - num_events--; - } - - // do our forks - if( num_forks > 0 ) { - - num_forks--; - - int pid = fork(); - if( pid < 0 ) { - - rc = -errno; - fprintf(stderr, "fork: %s\n", strerror( -rc ) ); - break; - } - else if( pid == 0 ) { - - printf("[%d]\n", getpid() ); - } - } - } - - udev_monitor_fs_destroy( monitor ); - - exit(0); +int main(int argc, char **argv) +{ + + int rc = 0; + char pathbuf[PATH_MAX + 1]; + struct udev *udev_client = NULL; + struct udev_monitor *monitor = NULL; + int monitor_fd = 0; + struct udev_device *dev = NULL; + struct pollfd pfd[1]; + int num_events = INT_MAX; + int num_forks = 0; + + // usage: $0 [num events to process [num times to fork]] + if (argc > 1) { + char *tmp = NULL; + num_events = (int)strtol(argv[1], &tmp, 10); + if (tmp == argv[1] || *tmp != '\0') { + fprintf(stderr, + "Usage: %s [number of events to process [number of times to fork]]\n", + argv[0]); + exit(1); + } + + if (argc > 2) { + + num_forks = (int)strtol(argv[2], &tmp, 10); + if (tmp == argv[2] || *tmp != '\0') { + fprintf(stderr, + "Usage: %s [number of events to process [number of times to fork]]\n", + argv[0]); + exit(1); + } + } + } + // make sure events dir exists + log_trace("events directory '%s'", UDEV_FS_EVENTS_DIR); + + rc = mkdir(UDEV_FS_EVENTS_DIR, 0700); + if (rc != 0) { + + rc = -errno; + if (rc != -EEXIST) { + log_error("mkdir('%s') rc = %d", UDEV_FS_EVENTS_DIR, + rc); + exit(1); + } + } + + udev_monitor_fs_events_path("", pathbuf, 0); + + printf("Watching '%s'\n", pathbuf); + + udev_client = udev_new(); + if (udev_client == NULL) { + + // OOM + exit(2); + } + + monitor = udev_monitor_new_from_netlink(udev_client, "udev"); + if (monitor == NULL) { + + // OOM or error + udev_unref(udev_client); + exit(2); + } + + printf("Press Ctrl-C to quit\n"); + + monitor_fd = udev_monitor_get_fd(monitor); + if (monitor_fd < 0) { + + rc = -errno; + log_error("udev_monitor_get_fd rc = %d\n", rc); + exit(3); + } + + pfd[0].fd = monitor_fd; + pfd[0].events = POLLIN; + + while (num_events > 0) { + + // wait for the next device + rc = poll(pfd, 1, -1); + if (rc < 0) { + + log_error("poll(%d) rc = %d\n", monitor_fd, rc); + break; + } + // get devices + while (num_events > 0) { + + dev = udev_monitor_receive_device(monitor); + if (dev == NULL) { + break; + } + + int pid = getpid(); + struct udev_list_entry *list_entry = NULL; + + printf("[%d] [%d] ACTION: '%s'\n", pid, num_events, + udev_device_get_action(dev)); + printf("[%d] [%d] SEQNUM: %llu\n", pid, num_events, + udev_device_get_seqnum(dev)); + printf("[%d] [%d] USEC: %llu\n", pid, num_events, + udev_device_get_usec_since_initialized(dev)); + printf("[%d] [%d] DEVNODE: '%s'\n", pid, num_events, + udev_device_get_devnode(dev)); + printf("[%d] [%d] DEVPATH: '%s'\n", pid, num_events, + udev_device_get_devpath(dev)); + printf("[%d] [%d] SYSNAME: '%s'\n", pid, num_events, + udev_device_get_sysname(dev)); + printf("[%d] [%d] SYSPATH: '%s'\n", pid, num_events, + udev_device_get_syspath(dev)); + printf("[%d] [%d] SUBSYSTEM: '%s'\n", pid, num_events, + udev_device_get_subsystem(dev)); + printf("[%d] [%d] DEVTYPE: '%s'\n", pid, num_events, + udev_device_get_devtype(dev)); + printf("[%d] [%d] SYSNUM: '%s'\n", pid, num_events, + udev_device_get_sysnum(dev)); + printf("[%d] [%d] DRIVER: '%s'\n", pid, num_events, + udev_device_get_driver(dev)); + printf("[%d] [%d] DEVNUM: %d:%d\n", pid, + num_events, major(udev_device_get_devnum(dev)), + minor(udev_device_get_devnum(dev))); + printf("[%d] [%d] IFINDEX: '%s'\n", pid, num_events, + udev_device_get_property_value(dev, "IFINDEX")); + printf("[%d] [%d] DEVMODE: '%s'\n", pid, num_events, + udev_device_get_property_value(dev, "DEVMODE")); + printf("[%d] [%d] DEVUID: '%s'\n", pid, num_events, + udev_device_get_property_value(dev, "DEVUID")); + printf("[%d] [%d] DEVGID: '%s'\n", pid, num_events, + udev_device_get_property_value(dev, "DEVGID")); + + list_entry = udev_device_get_devlinks_list_entry(dev); + udev_list_entry_foreach(list_entry, + udev_list_entry_get_next + (list_entry)) { + + printf("[%d] [%d] devlink: '%s'\n", pid, + num_events, + udev_list_entry_get_name(list_entry)); + } + + list_entry = udev_device_get_properties_list_entry(dev); + udev_list_entry_foreach(list_entry, + udev_list_entry_get_next + (list_entry)) { + + printf("[%d] [%d] property: '%s' = '%s'\n", + pid, num_events, + udev_list_entry_get_name(list_entry), + udev_list_entry_get_value(list_entry)); + } + + list_entry = udev_device_get_tags_list_entry(dev); + udev_list_entry_foreach(list_entry, + udev_list_entry_get_next + (list_entry)) { + + printf("[%d] [%d] tag: '%s'\n", pid, + num_events, + udev_list_entry_get_name(list_entry)); + } + + list_entry = udev_device_get_sysattr_list_entry(dev); + udev_list_entry_foreach(list_entry, + udev_list_entry_get_next + (list_entry)) { + + printf("[%d] [%d] sysattr: '%s'\n", pid, + num_events, + udev_list_entry_get_name(list_entry)); + } + + printf("\n"); + + udev_device_unref(dev); + + num_events--; + } + + // do our forks + if (num_forks > 0) { + + num_forks--; + + int pid = fork(); + if (pid < 0) { + + rc = -errno; + fprintf(stderr, "fork: %s\n", strerror(-rc)); + break; + } else if (pid == 0) { + + printf("[%d]\n", getpid()); + } + } + } + + udev_monitor_fs_destroy(monitor); + + exit(0); } -#endif +#endif diff --git a/libudev-compat/libudev-fs.h b/libudev-compat/libudev-fs.h index 23b3f59..dbcf2d1 100644 --- a/libudev-compat/libudev-fs.h +++ b/libudev-compat/libudev-fs.h @@ -25,17 +25,17 @@ #ifndef _POSIX_C_SOURCE #define _POSIX_C_SOURCE 200809L -#endif +#endif #ifndef _XOPEN_SOURCE #define _XOPEN_SOURCE 700 -#endif +#endif #ifndef _BSD_SOURCE #define _BSD_SOURCE #endif -#ifndef _GNU_SOURCE +#ifndef _GNU_SOURCE #define _GNU_SOURCE #endif @@ -66,9 +66,9 @@ #include "libudev-private.h" -int udev_monitor_fs_setup( struct udev_monitor* monitor ); -int udev_monitor_fs_destroy( struct udev_monitor* monitor ); -int udev_monitor_fs_shutdown( struct udev_monitor* monitor ); -int udev_monitor_fs_push_events( struct udev_monitor* monitor ); +int udev_monitor_fs_setup(struct udev_monitor *monitor); +int udev_monitor_fs_destroy(struct udev_monitor *monitor); +int udev_monitor_fs_shutdown(struct udev_monitor *monitor); +int udev_monitor_fs_push_events(struct udev_monitor *monitor); -#endif \ No newline at end of file +#endif diff --git a/libudev-compat/libudev-hwdb.c b/libudev-compat/libudev-hwdb.c index fb16b88..53128b0 100644 --- a/libudev-compat/libudev-hwdb.c +++ b/libudev-compat/libudev-hwdb.c @@ -44,12 +44,12 @@ * Opaque object representing the hardware database. */ struct udev_hwdb { - struct udev *udev; - int refcount; + struct udev *udev; + int refcount; - sd_hwdb *hwdb; + sd_hwdb *hwdb; - struct udev_list properties_list; + struct udev_list properties_list; }; /** @@ -60,28 +60,29 @@ struct udev_hwdb { * * Returns: a hwdb context. **/ -_public_ struct udev_hwdb *udev_hwdb_new(struct udev *udev) { - _cleanup_hwdb_unref_ sd_hwdb *hwdb_internal = NULL; - struct udev_hwdb *hwdb; - int r; +_public_ struct udev_hwdb *udev_hwdb_new(struct udev *udev) +{ + _cleanup_hwdb_unref_ sd_hwdb *hwdb_internal = NULL; + struct udev_hwdb *hwdb; + int r; - assert_return(udev, NULL); + assert_return(udev, NULL); - r = sd_hwdb_new(&hwdb_internal); - if (r < 0) - return NULL; + r = sd_hwdb_new(&hwdb_internal); + if (r < 0) + return NULL; - hwdb = new0(struct udev_hwdb, 1); - if (!hwdb) - return NULL; + hwdb = new0(struct udev_hwdb, 1); + if (!hwdb) + return NULL; - hwdb->refcount = 1; - hwdb->hwdb = hwdb_internal; - hwdb_internal = NULL; + hwdb->refcount = 1; + hwdb->hwdb = hwdb_internal; + hwdb_internal = NULL; - udev_list_init(udev, &hwdb->properties_list, true); + udev_list_init(udev, &hwdb->properties_list, true); - return hwdb; + return hwdb; } /** @@ -92,11 +93,12 @@ _public_ struct udev_hwdb *udev_hwdb_new(struct udev *udev) { * * Returns: the passed enumeration context **/ -_public_ struct udev_hwdb *udev_hwdb_ref(struct udev_hwdb *hwdb) { - if (!hwdb) - return NULL; - hwdb->refcount++; - return hwdb; +_public_ struct udev_hwdb *udev_hwdb_ref(struct udev_hwdb *hwdb) +{ + if (!hwdb) + return NULL; + hwdb->refcount++; + return hwdb; } /** @@ -108,16 +110,17 @@ _public_ struct udev_hwdb *udev_hwdb_ref(struct udev_hwdb *hwdb) { * * Returns: #NULL **/ -_public_ struct udev_hwdb *udev_hwdb_unref(struct udev_hwdb *hwdb) { - if (!hwdb) - return NULL; - hwdb->refcount--; - if (hwdb->refcount > 0) - return NULL; - sd_hwdb_unref(hwdb->hwdb); - udev_list_cleanup(&hwdb->properties_list); - free(hwdb); - return NULL; +_public_ struct udev_hwdb *udev_hwdb_unref(struct udev_hwdb *hwdb) +{ + if (!hwdb) + return NULL; + hwdb->refcount--; + if (hwdb->refcount > 0) + return NULL; + sd_hwdb_unref(hwdb->hwdb); + udev_list_cleanup(&hwdb->properties_list); + free(hwdb); + return NULL; } /** @@ -133,22 +136,30 @@ _public_ struct udev_hwdb *udev_hwdb_unref(struct udev_hwdb *hwdb) { * * Returns: a udev_list_entry. */ -_public_ struct udev_list_entry *udev_hwdb_get_properties_list_entry(struct udev_hwdb *hwdb, const char *modalias, unsigned int flags) { - const char *key, *value; - - if (!hwdb || !modalias) { - errno = EINVAL; - return NULL; - } - - udev_list_cleanup(&hwdb->properties_list); - - SD_HWDB_FOREACH_PROPERTY(hwdb->hwdb, modalias, key, value) { - if (udev_list_entry_add(&hwdb->properties_list, key, value) == NULL) { - errno = ENOMEM; - return NULL; - } - } - - return udev_list_get_entry(&hwdb->properties_list); +_public_ struct udev_list_entry *udev_hwdb_get_properties_list_entry(struct + udev_hwdb + *hwdb, + const char + *modalias, + unsigned + int flags) +{ + const char *key, *value; + + if (!hwdb || !modalias) { + errno = EINVAL; + return NULL; + } + + udev_list_cleanup(&hwdb->properties_list); + + SD_HWDB_FOREACH_PROPERTY(hwdb->hwdb, modalias, key, value) { + if (udev_list_entry_add(&hwdb->properties_list, key, value) == + NULL) { + errno = ENOMEM; + return NULL; + } + } + + return udev_list_get_entry(&hwdb->properties_list); } diff --git a/libudev-compat/libudev-list.c b/libudev-compat/libudev-list.c index f1dd4c6..3f25e93 100644 --- a/libudev-compat/libudev-list.c +++ b/libudev-compat/libudev-list.c @@ -47,227 +47,239 @@ * contains a name, and optionally a value. */ struct udev_list_entry { - struct udev_list_node node; - struct udev_list *list; - char *name; - char *value; - int num; + struct udev_list_node node; + struct udev_list *list; + char *name; + char *value; + int num; }; /* the list's head points to itself if empty */ void udev_list_node_init(struct udev_list_node *list) { - list->next = list; - list->prev = list; + list->next = list; + list->prev = list; } int udev_list_node_is_empty(struct udev_list_node *list) { - return list->next == list; + return list->next == list; } static void udev_list_node_insert_between(struct udev_list_node *new, - struct udev_list_node *prev, - struct udev_list_node *next) + struct udev_list_node *prev, + struct udev_list_node *next) { - next->prev = new; - new->next = next; - new->prev = prev; - prev->next = new; + next->prev = new; + new->next = next; + new->prev = prev; + prev->next = new; } -void udev_list_node_append(struct udev_list_node *new, struct udev_list_node *list) +void udev_list_node_append(struct udev_list_node *new, + struct udev_list_node *list) { - udev_list_node_insert_between(new, list->prev, list); + udev_list_node_insert_between(new, list->prev, list); } void udev_list_node_remove(struct udev_list_node *entry) { - struct udev_list_node *prev = entry->prev; - struct udev_list_node *next = entry->next; + struct udev_list_node *prev = entry->prev; + struct udev_list_node *next = entry->next; - next->prev = prev; - prev->next = next; + next->prev = prev; + prev->next = next; - entry->prev = NULL; - entry->next = NULL; + entry->prev = NULL; + entry->next = NULL; } /* return list entry which embeds this node */ -static inline struct udev_list_entry *list_node_to_entry(struct udev_list_node *node) +static inline struct udev_list_entry *list_node_to_entry(struct udev_list_node + *node) { - return container_of(node, struct udev_list_entry, node); + return container_of(node, struct udev_list_entry, node); } void udev_list_init(struct udev *udev, struct udev_list *list, bool unique) { - memzero(list, sizeof(struct udev_list)); - list->udev = udev; - list->unique = unique; - udev_list_node_init(&list->node); + memzero(list, sizeof(struct udev_list)); + list->udev = udev; + list->unique = unique; + udev_list_node_init(&list->node); } /* insert entry into a list as the last element */ -static void udev_list_entry_append(struct udev_list_entry *new, struct udev_list *list) +static void udev_list_entry_append(struct udev_list_entry *new, + struct udev_list *list) { - /* inserting before the list head make the node the last node in the list */ - udev_list_node_insert_between(&new->node, list->node.prev, &list->node); - new->list = list; + /* inserting before the list head make the node the last node in the list */ + udev_list_node_insert_between(&new->node, list->node.prev, &list->node); + new->list = list; } /* insert entry into a list, before a given existing entry */ -static void udev_list_entry_insert_before(struct udev_list_entry *new, struct udev_list_entry *entry) +static void udev_list_entry_insert_before(struct udev_list_entry *new, + struct udev_list_entry *entry) { - udev_list_node_insert_between(&new->node, entry->node.prev, &entry->node); - new->list = entry->list; + udev_list_node_insert_between(&new->node, entry->node.prev, + &entry->node); + new->list = entry->list; } /* binary search in sorted array */ static int list_search(struct udev_list *list, const char *name) { - unsigned int first, last; - - first = 0; - last = list->entries_cur; - while (first < last) { - unsigned int i; - int cmp; - - i = (first + last)/2; - cmp = strcmp(name, list->entries[i]->name); - if (cmp < 0) - last = i; - else if (cmp > 0) - first = i+1; - else - return i; - } - - /* not found, return negative insertion-index+1 */ - return -(first+1); + unsigned int first, last; + + first = 0; + last = list->entries_cur; + while (first < last) { + unsigned int i; + int cmp; + + i = (first + last) / 2; + cmp = strcmp(name, list->entries[i]->name); + if (cmp < 0) + last = i; + else if (cmp > 0) + first = i + 1; + else + return i; + } + + /* not found, return negative insertion-index+1 */ + return -(first + 1); } -struct udev_list_entry *udev_list_entry_add(struct udev_list *list, const char *name, const char *value) +struct udev_list_entry *udev_list_entry_add(struct udev_list *list, + const char *name, const char *value) { - struct udev_list_entry *entry; - int i = 0; - - if (list->unique) { - /* lookup existing name or insertion-index */ - i = list_search(list, name); - if (i >= 0) { - entry = list->entries[i]; - - free(entry->value); - if (value == NULL) { - entry->value = NULL; - return entry; - } - entry->value = strdup(value); - if (entry->value == NULL) - return NULL; - return entry; - } - } - - /* add new name */ - entry = new0(struct udev_list_entry, 1); - if (entry == NULL) - return NULL; - entry->name = strdup(name); - if (entry->name == NULL) { - free(entry); - return NULL; - } - if (value != NULL) { - entry->value = strdup(value); - if (entry->value == NULL) { - free(entry->name); - free(entry); - return NULL; - } - } - - if (list->unique) { - /* allocate or enlarge sorted array if needed */ - if (list->entries_cur >= list->entries_max) { - struct udev_list_entry **entries; - unsigned int add; - - add = list->entries_max; - if (add < 1) - add = 64; - entries = realloc(list->entries, (list->entries_max + add) * sizeof(struct udev_list_entry *)); - if (entries == NULL) { - free(entry->name); - free(entry->value); - free(entry); - return NULL; - } - list->entries = entries; - list->entries_max += add; - } - - /* the negative i returned the insertion index */ - i = (-i)-1; - - /* insert into sorted list */ - if ((unsigned int)i < list->entries_cur) - udev_list_entry_insert_before(entry, list->entries[i]); - else - udev_list_entry_append(entry, list); - - /* insert into sorted array */ - memmove(&list->entries[i+1], &list->entries[i], - (list->entries_cur - i) * sizeof(struct udev_list_entry *)); - list->entries[i] = entry; - list->entries_cur++; - } else { - udev_list_entry_append(entry, list); - } - - return entry; + struct udev_list_entry *entry; + int i = 0; + + if (list->unique) { + /* lookup existing name or insertion-index */ + i = list_search(list, name); + if (i >= 0) { + entry = list->entries[i]; + + free(entry->value); + if (value == NULL) { + entry->value = NULL; + return entry; + } + entry->value = strdup(value); + if (entry->value == NULL) + return NULL; + return entry; + } + } + + /* add new name */ + entry = new0(struct udev_list_entry, 1); + if (entry == NULL) + return NULL; + entry->name = strdup(name); + if (entry->name == NULL) { + free(entry); + return NULL; + } + if (value != NULL) { + entry->value = strdup(value); + if (entry->value == NULL) { + free(entry->name); + free(entry); + return NULL; + } + } + + if (list->unique) { + /* allocate or enlarge sorted array if needed */ + if (list->entries_cur >= list->entries_max) { + struct udev_list_entry **entries; + unsigned int add; + + add = list->entries_max; + if (add < 1) + add = 64; + entries = + realloc(list->entries, + (list->entries_max + + add) * sizeof(struct udev_list_entry *)); + if (entries == NULL) { + free(entry->name); + free(entry->value); + free(entry); + return NULL; + } + list->entries = entries; + list->entries_max += add; + } + + /* the negative i returned the insertion index */ + i = (-i) - 1; + + /* insert into sorted list */ + if ((unsigned int)i < list->entries_cur) + udev_list_entry_insert_before(entry, list->entries[i]); + else + udev_list_entry_append(entry, list); + + /* insert into sorted array */ + memmove(&list->entries[i + 1], &list->entries[i], + (list->entries_cur - + i) * sizeof(struct udev_list_entry *)); + list->entries[i] = entry; + list->entries_cur++; + } else { + udev_list_entry_append(entry, list); + } + + return entry; } void udev_list_entry_delete(struct udev_list_entry *entry) { - if (entry->list->entries != NULL) { - int i; - struct udev_list *list = entry->list; - - /* remove entry from sorted array */ - i = list_search(list, entry->name); - if (i >= 0) { - memmove(&list->entries[i], &list->entries[i+1], - ((list->entries_cur-1) - i) * sizeof(struct udev_list_entry *)); - list->entries_cur--; - } - } - - udev_list_node_remove(&entry->node); - free(entry->name); - free(entry->value); - free(entry); + if (entry->list->entries != NULL) { + int i; + struct udev_list *list = entry->list; + + /* remove entry from sorted array */ + i = list_search(list, entry->name); + if (i >= 0) { + memmove(&list->entries[i], &list->entries[i + 1], + ((list->entries_cur - 1) - + i) * sizeof(struct udev_list_entry *)); + list->entries_cur--; + } + } + + udev_list_node_remove(&entry->node); + free(entry->name); + free(entry->value); + free(entry); } void udev_list_cleanup(struct udev_list *list) { - struct udev_list_entry *entry_loop; - struct udev_list_entry *entry_tmp; - - free(list->entries); - list->entries = NULL; - list->entries_cur = 0; - list->entries_max = 0; - udev_list_entry_foreach_safe(entry_loop, entry_tmp, udev_list_get_entry(list)) - udev_list_entry_delete(entry_loop); + struct udev_list_entry *entry_loop; + struct udev_list_entry *entry_tmp; + + free(list->entries); + list->entries = NULL; + list->entries_cur = 0; + list->entries_max = 0; + udev_list_entry_foreach_safe(entry_loop, entry_tmp, + udev_list_get_entry(list)) + udev_list_entry_delete(entry_loop); } struct udev_list_entry *udev_list_get_entry(struct udev_list *list) { - if (udev_list_node_is_empty(&list->node)) - return NULL; - return list_node_to_entry(list->node.next); + if (udev_list_node_is_empty(&list->node)) + return NULL; + return list_node_to_entry(list->node.next); } /** @@ -278,17 +290,18 @@ struct udev_list_entry *udev_list_get_entry(struct udev_list *list) * * Returns: udev_list_entry, #NULL if no more entries are available. */ -struct udev_list_entry *udev_list_entry_get_next(struct udev_list_entry *list_entry) +struct udev_list_entry *udev_list_entry_get_next(struct udev_list_entry + *list_entry) { - struct udev_list_node *next; - - if (list_entry == NULL) - return NULL; - next = list_entry->node.next; - /* empty list or no more entries */ - if (next == &list_entry->list->node) - return NULL; - return list_node_to_entry(next); + struct udev_list_node *next; + + if (list_entry == NULL) + return NULL; + next = list_entry->node.next; + /* empty list or no more entries */ + if (next == &list_entry->list->node) + return NULL; + return list_node_to_entry(next); } /** @@ -300,20 +313,22 @@ struct udev_list_entry *udev_list_entry_get_next(struct udev_list_entry *list_en * * Returns: udev_list_entry, #NULL if no matching entry is found. */ -struct udev_list_entry *udev_list_entry_get_by_name(struct udev_list_entry *list_entry, const char *name) +struct udev_list_entry *udev_list_entry_get_by_name(struct udev_list_entry + *list_entry, + const char *name) { - int i; + int i; - if (list_entry == NULL) - return NULL; + if (list_entry == NULL) + return NULL; - if (!list_entry->list->unique) - return NULL; + if (!list_entry->list->unique) + return NULL; - i = list_search(list_entry->list, name); - if (i < 0) - return NULL; - return list_entry->list->entries[i]; + i = list_search(list_entry->list, name); + if (i < 0) + return NULL; + return list_entry->list->entries[i]; } /** @@ -326,9 +341,9 @@ struct udev_list_entry *udev_list_entry_get_by_name(struct udev_list_entry *list */ const char *udev_list_entry_get_name(struct udev_list_entry *list_entry) { - if (list_entry == NULL) - return NULL; - return list_entry->name; + if (list_entry == NULL) + return NULL; + return list_entry->name; } /** @@ -341,21 +356,21 @@ const char *udev_list_entry_get_name(struct udev_list_entry *list_entry) */ const char *udev_list_entry_get_value(struct udev_list_entry *list_entry) { - if (list_entry == NULL) - return NULL; - return list_entry->value; + if (list_entry == NULL) + return NULL; + return list_entry->value; } int udev_list_entry_get_num(struct udev_list_entry *list_entry) { - if (list_entry == NULL) - return -EINVAL; - return list_entry->num; + if (list_entry == NULL) + return -EINVAL; + return list_entry->num; } void udev_list_entry_set_num(struct udev_list_entry *list_entry, int num) { - if (list_entry == NULL) - return; - list_entry->num = num; + if (list_entry == NULL) + return; + list_entry->num = num; } diff --git a/libudev-compat/libudev-monitor.c b/libudev-compat/libudev-monitor.c index 77e682c..ae22659 100644 --- a/libudev-compat/libudev-monitor.c +++ b/libudev-compat/libudev-monitor.c @@ -44,96 +44,96 @@ #include "libudev-private.h" #include "libudev-fs.h" - enum udev_monitor_netlink_group { - UDEV_MONITOR_NONE, - UDEV_MONITOR_KERNEL, - UDEV_MONITOR_UDEV, - UDEV_MONITOR_ANY + UDEV_MONITOR_NONE, + UDEV_MONITOR_KERNEL, + UDEV_MONITOR_UDEV, + UDEV_MONITOR_ANY }; #define UDEV_MONITOR_MAGIC 0xfeedcafe struct udev_monitor_netlink_header { - /* "libudev" prefix to distinguish libudev and kernel messages */ - char prefix[8]; - /* - * magic to protect against daemon <-> library message format mismatch - * used in the kernel from socket filter rules; needs to be stored in network order - */ - unsigned int magic; - /* total length of header structure known to the sender */ - unsigned int header_size; - /* properties string buffer */ - unsigned int properties_off; - unsigned int properties_len; - /* - * hashes of primary device properties strings, to let libudev subscribers - * use in-kernel socket filters; values need to be stored in network order - */ - unsigned int filter_subsystem_hash; - unsigned int filter_devtype_hash; - unsigned int filter_tag_bloom_hi; - unsigned int filter_tag_bloom_lo; + /* "libudev" prefix to distinguish libudev and kernel messages */ + char prefix[8]; + /* + * magic to protect against daemon <-> library message format mismatch + * used in the kernel from socket filter rules; needs to be stored in network order + */ + unsigned int magic; + /* total length of header structure known to the sender */ + unsigned int header_size; + /* properties string buffer */ + unsigned int properties_off; + unsigned int properties_len; + /* + * hashes of primary device properties strings, to let libudev subscribers + * use in-kernel socket filters; values need to be stored in network order + */ + unsigned int filter_subsystem_hash; + unsigned int filter_devtype_hash; + unsigned int filter_tag_bloom_hi; + unsigned int filter_tag_bloom_lo; }; static struct udev_monitor *udev_monitor_new(struct udev *udev) { - struct udev_monitor *udev_monitor; - - udev_monitor = new0(struct udev_monitor, 1); - if (udev_monitor == NULL) - return NULL; - - udev_monitor->type = 0; - udev_monitor->refcount = 1; - udev_monitor->udev = udev; - udev_list_init(udev, &udev_monitor->filter_subsystem_list, false); - udev_list_init(udev, &udev_monitor->filter_tag_list, true); - return udev_monitor; + struct udev_monitor *udev_monitor; + + udev_monitor = new0(struct udev_monitor, 1); + if (udev_monitor == NULL) + return NULL; + + udev_monitor->type = 0; + udev_monitor->refcount = 1; + udev_monitor->udev = udev; + udev_list_init(udev, &udev_monitor->filter_subsystem_list, false); + udev_list_init(udev, &udev_monitor->filter_tag_list, true); + return udev_monitor; } -static struct udev_monitor *udev_monitor_new_from_filesystem(struct udev *udev ) { - - // The approach taken here is to have the device manager - // record device events to well-known subdirectories in /dev. - // Then, the device manager in the root context can be instructed to - // record all relevant device events, and the admin can bind-mount - // subdirectory trees into container contexts. In doing so, the - // admin both controls fine-grained device information visibility - // (through permission bits) and aggregate device visibility - // (through bind-mounts) for both root and container contexts, - // all without requiring extra help from the kernel. Moreover, - // this approach is generic enough to not specific to a particular - // kernel or device manager. - // - // The purpose of libudev-compat is to help would-be - // udev listeners find and read the device information in the - // underlying /dev filesystem. - // - // --Jude Nelson - - struct udev_monitor *udev_monitor = NULL; - int rc = 0; - - if (udev == NULL) { - return NULL; - } - - udev_monitor = udev_monitor_new(udev); - if (udev_monitor == NULL) { - return NULL; - } - - rc = udev_monitor_fs_setup( udev_monitor ); - if( rc < 0 ) { - - log_error("udev_monitor_fs_setup() rc = %d\n", rc ); - return NULL; - } - - udev_monitor->type = UDEV_MONITOR_TYPE_UDEV; - - return udev_monitor; +static struct udev_monitor *udev_monitor_new_from_filesystem(struct udev *udev) +{ + + // The approach taken here is to have the device manager + // record device events to well-known subdirectories in /dev. + // Then, the device manager in the root context can be instructed to + // record all relevant device events, and the admin can bind-mount + // subdirectory trees into container contexts. In doing so, the + // admin both controls fine-grained device information visibility + // (through permission bits) and aggregate device visibility + // (through bind-mounts) for both root and container contexts, + // all without requiring extra help from the kernel. Moreover, + // this approach is generic enough to not specific to a particular + // kernel or device manager. + // + // The purpose of libudev-compat is to help would-be + // udev listeners find and read the device information in the + // underlying /dev filesystem. + // + // --Jude Nelson + + struct udev_monitor *udev_monitor = NULL; + int rc = 0; + + if (udev == NULL) { + return NULL; + } + + udev_monitor = udev_monitor_new(udev); + if (udev_monitor == NULL) { + return NULL; + } + + rc = udev_monitor_fs_setup(udev_monitor); + if (rc < 0) { + + log_error("udev_monitor_fs_setup() rc = %d\n", rc); + return NULL; + } + + udev_monitor->type = UDEV_MONITOR_TYPE_UDEV; + + return udev_monitor; } /** @@ -163,111 +163,115 @@ static struct udev_monitor *udev_monitor_new_from_filesystem(struct udev *udev ) * * Returns: a new udev monitor, or #NULL, in case of an error **/ -struct udev_monitor *udev_monitor_new_from_netlink(struct udev *udev, const char *name) +struct udev_monitor *udev_monitor_new_from_netlink(struct udev *udev, + const char *name) { - - if( strcmp( name, "udev" ) == 0 ) { - return udev_monitor_new_from_filesystem(udev); - } - else { - return udev_monitor_new_from_netlink_fd(udev, name, -1); - } + + if (strcmp(name, "udev") == 0) { + return udev_monitor_new_from_filesystem(udev); + } else { + return udev_monitor_new_from_netlink_fd(udev, name, -1); + } } -static void monitor_set_nl_address(struct udev_monitor *udev_monitor) { - union sockaddr_union snl; - socklen_t addrlen; - int r; - - assert(udev_monitor); - - /* get the address the kernel has assigned us - * it is usually, but not necessarily the pid - */ - addrlen = sizeof(struct sockaddr_nl); - r = getsockname(udev_monitor->sock, &snl.sa, &addrlen); - if (r >= 0) { - udev_monitor->snl.nl.nl_pid = snl.nl.nl_pid; - } +static void monitor_set_nl_address(struct udev_monitor *udev_monitor) +{ + union sockaddr_union snl; + socklen_t addrlen; + int r; + + assert(udev_monitor); + + /* get the address the kernel has assigned us + * it is usually, but not necessarily the pid + */ + addrlen = sizeof(struct sockaddr_nl); + r = getsockname(udev_monitor->sock, &snl.sa, &addrlen); + if (r >= 0) { + udev_monitor->snl.nl.nl_pid = snl.nl.nl_pid; + } } // NOTE: this method is here only for compatibility. -struct udev_monitor *udev_monitor_new_from_netlink_fd( struct udev* udev, char const* name, int fd ) { - - struct udev_monitor *udev_monitor; - unsigned int group; - - if (udev == NULL) { - return NULL; - } - - if (name == NULL) { - group = UDEV_MONITOR_NONE; - } - - else if (streq(name, "udev")) { - - // libudev-compat: read from an event buffer on the fs - return udev_monitor_new_from_filesystem( udev ); - - } else if (streq(name, "kernel")) { - group = UDEV_MONITOR_KERNEL; - } - else { - return NULL; - } - - udev_monitor = udev_monitor_new(udev); - if (udev_monitor == NULL) { - return NULL; - } - - if (fd < 0) { - udev_monitor->sock = socket(PF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, NETLINK_KOBJECT_UEVENT); - if (udev_monitor->sock < 0) { - log_debug("error getting socket: %s", strerror(errno)); - free(udev_monitor); - return NULL; - } - } else { - udev_monitor->bound = true; - udev_monitor->sock = fd; - monitor_set_nl_address(udev_monitor); - } - - udev_monitor->snl.nl.nl_family = AF_NETLINK; - udev_monitor->snl.nl.nl_groups = group; - - /* default destination for sending */ - udev_monitor->snl_destination.nl.nl_family = AF_NETLINK; - udev_monitor->snl_destination.nl.nl_groups = UDEV_MONITOR_UDEV; - - udev_monitor->type = UDEV_MONITOR_TYPE_KERNEL; - - return udev_monitor; +struct udev_monitor *udev_monitor_new_from_netlink_fd(struct udev *udev, + char const *name, int fd) +{ + + struct udev_monitor *udev_monitor; + unsigned int group; + + if (udev == NULL) { + return NULL; + } + + if (name == NULL) { + group = UDEV_MONITOR_NONE; + } + + else if (streq(name, "udev")) { + + // libudev-compat: read from an event buffer on the fs + return udev_monitor_new_from_filesystem(udev); + + } else if (streq(name, "kernel")) { + group = UDEV_MONITOR_KERNEL; + } else { + return NULL; + } + + udev_monitor = udev_monitor_new(udev); + if (udev_monitor == NULL) { + return NULL; + } + + if (fd < 0) { + udev_monitor->sock = + socket(PF_NETLINK, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, + NETLINK_KOBJECT_UEVENT); + if (udev_monitor->sock < 0) { + log_debug("error getting socket: %s", strerror(errno)); + free(udev_monitor); + return NULL; + } + } else { + udev_monitor->bound = true; + udev_monitor->sock = fd; + monitor_set_nl_address(udev_monitor); + } + + udev_monitor->snl.nl.nl_family = AF_NETLINK; + udev_monitor->snl.nl.nl_groups = group; + + /* default destination for sending */ + udev_monitor->snl_destination.nl.nl_family = AF_NETLINK; + udev_monitor->snl_destination.nl.nl_groups = UDEV_MONITOR_UDEV; + + udev_monitor->type = UDEV_MONITOR_TYPE_KERNEL; + + return udev_monitor; } static inline void bpf_stmt(struct sock_filter *inss, unsigned int *i, - unsigned short code, unsigned int data) + unsigned short code, unsigned int data) { - struct sock_filter *ins = &inss[*i]; + struct sock_filter *ins = &inss[*i]; - ins->code = code; - ins->k = data; - (*i)++; + ins->code = code; + ins->k = data; + (*i)++; } static inline void bpf_jmp(struct sock_filter *inss, unsigned int *i, - unsigned short code, unsigned int data, - unsigned short jt, unsigned short jf) + unsigned short code, unsigned int data, + unsigned short jt, unsigned short jf) { - struct sock_filter *ins = &inss[*i]; + struct sock_filter *ins = &inss[*i]; - ins->code = code; - ins->jt = jt; - ins->jf = jf; - ins->k = data; - (*i)++; + ins->code = code; + ins->jt = jt; + ins->jf = jf; + ins->k = data; + (*i)++; } /** @@ -281,116 +285,147 @@ static inline void bpf_jmp(struct sock_filter *inss, unsigned int *i, */ int udev_monitor_filter_update(struct udev_monitor *udev_monitor) { - struct sock_filter ins[512]; - struct sock_fprog filter; - unsigned int i; - struct udev_list_entry *list_entry; - int err; - - if (udev_list_get_entry(&udev_monitor->filter_subsystem_list) == NULL && - udev_list_get_entry(&udev_monitor->filter_tag_list) == NULL) - return 0; - - memzero(ins, sizeof(ins)); - i = 0; - - /* load magic in A */ - bpf_stmt(ins, &i, BPF_LD|BPF_W|BPF_ABS, offsetof(struct udev_monitor_netlink_header, magic)); - /* jump if magic matches */ - bpf_jmp(ins, &i, BPF_JMP|BPF_JEQ|BPF_K, UDEV_MONITOR_MAGIC, 1, 0); - /* wrong magic, pass packet */ - bpf_stmt(ins, &i, BPF_RET|BPF_K, 0xffffffff); - - if (udev_list_get_entry(&udev_monitor->filter_tag_list) != NULL) { - int tag_matches; - - /* count tag matches, to calculate end of tag match block */ - tag_matches = 0; - udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_monitor->filter_tag_list)) - tag_matches++; - - /* add all tags matches */ - udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_monitor->filter_tag_list)) { - uint64_t tag_bloom_bits = util_string_bloom64(udev_list_entry_get_name(list_entry)); - uint32_t tag_bloom_hi = tag_bloom_bits >> 32; - uint32_t tag_bloom_lo = tag_bloom_bits & 0xffffffff; - - /* load device bloom bits in A */ - bpf_stmt(ins, &i, BPF_LD|BPF_W|BPF_ABS, offsetof(struct udev_monitor_netlink_header, filter_tag_bloom_hi)); - /* clear bits (tag bits & bloom bits) */ - bpf_stmt(ins, &i, BPF_ALU|BPF_AND|BPF_K, tag_bloom_hi); - /* jump to next tag if it does not match */ - bpf_jmp(ins, &i, BPF_JMP|BPF_JEQ|BPF_K, tag_bloom_hi, 0, 3); - - /* load device bloom bits in A */ - bpf_stmt(ins, &i, BPF_LD|BPF_W|BPF_ABS, offsetof(struct udev_monitor_netlink_header, filter_tag_bloom_lo)); - /* clear bits (tag bits & bloom bits) */ - bpf_stmt(ins, &i, BPF_ALU|BPF_AND|BPF_K, tag_bloom_lo); - /* jump behind end of tag match block if tag matches */ - tag_matches--; - bpf_jmp(ins, &i, BPF_JMP|BPF_JEQ|BPF_K, tag_bloom_lo, 1 + (tag_matches * 6), 0); - } - - /* nothing matched, drop packet */ - bpf_stmt(ins, &i, BPF_RET|BPF_K, 0); - } - - /* add all subsystem matches */ - if (udev_list_get_entry(&udev_monitor->filter_subsystem_list) != NULL) { - udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_monitor->filter_subsystem_list)) { - unsigned int hash = util_string_hash32(udev_list_entry_get_name(list_entry)); - - /* load device subsystem value in A */ - bpf_stmt(ins, &i, BPF_LD|BPF_W|BPF_ABS, offsetof(struct udev_monitor_netlink_header, filter_subsystem_hash)); - if (udev_list_entry_get_value(list_entry) == NULL) { - /* jump if subsystem does not match */ - bpf_jmp(ins, &i, BPF_JMP|BPF_JEQ|BPF_K, hash, 0, 1); - } else { - /* jump if subsystem does not match */ - bpf_jmp(ins, &i, BPF_JMP|BPF_JEQ|BPF_K, hash, 0, 3); - - /* load device devtype value in A */ - bpf_stmt(ins, &i, BPF_LD|BPF_W|BPF_ABS, offsetof(struct udev_monitor_netlink_header, filter_devtype_hash)); - /* jump if value does not match */ - hash = util_string_hash32(udev_list_entry_get_value(list_entry)); - bpf_jmp(ins, &i, BPF_JMP|BPF_JEQ|BPF_K, hash, 0, 1); - } - - /* matched, pass packet */ - bpf_stmt(ins, &i, BPF_RET|BPF_K, 0xffffffff); - - if (i+1 >= ELEMENTSOF(ins)) - return -E2BIG; - } - - /* nothing matched, drop packet */ - bpf_stmt(ins, &i, BPF_RET|BPF_K, 0); - } - - /* matched, pass packet */ - bpf_stmt(ins, &i, BPF_RET|BPF_K, 0xffffffff); - - /* install filter */ - // NOTE: attaches to either netlink or sockpair - memzero(&filter, sizeof(filter)); - filter.len = i; - filter.filter = ins; - err = setsockopt(udev_monitor->sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)); - return err < 0 ? -errno : 0; + struct sock_filter ins[512]; + struct sock_fprog filter; + unsigned int i; + struct udev_list_entry *list_entry; + int err; + + if (udev_list_get_entry(&udev_monitor->filter_subsystem_list) == NULL && + udev_list_get_entry(&udev_monitor->filter_tag_list) == NULL) + return 0; + + memzero(ins, sizeof(ins)); + i = 0; + + /* load magic in A */ + bpf_stmt(ins, &i, BPF_LD | BPF_W | BPF_ABS, + offsetof(struct udev_monitor_netlink_header, magic)); + /* jump if magic matches */ + bpf_jmp(ins, &i, BPF_JMP | BPF_JEQ | BPF_K, UDEV_MONITOR_MAGIC, 1, 0); + /* wrong magic, pass packet */ + bpf_stmt(ins, &i, BPF_RET | BPF_K, 0xffffffff); + + if (udev_list_get_entry(&udev_monitor->filter_tag_list) != NULL) { + int tag_matches; + + /* count tag matches, to calculate end of tag match block */ + tag_matches = 0; + udev_list_entry_foreach(list_entry, + udev_list_get_entry(&udev_monitor-> + filter_tag_list)) + tag_matches++; + + /* add all tags matches */ + udev_list_entry_foreach(list_entry, + udev_list_get_entry(&udev_monitor-> + filter_tag_list)) { + uint64_t tag_bloom_bits = + util_string_bloom64(udev_list_entry_get_name + (list_entry)); + uint32_t tag_bloom_hi = tag_bloom_bits >> 32; + uint32_t tag_bloom_lo = tag_bloom_bits & 0xffffffff; + + /* load device bloom bits in A */ + bpf_stmt(ins, &i, BPF_LD | BPF_W | BPF_ABS, + offsetof(struct udev_monitor_netlink_header, + filter_tag_bloom_hi)); + /* clear bits (tag bits & bloom bits) */ + bpf_stmt(ins, &i, BPF_ALU | BPF_AND | BPF_K, + tag_bloom_hi); + /* jump to next tag if it does not match */ + bpf_jmp(ins, &i, BPF_JMP | BPF_JEQ | BPF_K, + tag_bloom_hi, 0, 3); + + /* load device bloom bits in A */ + bpf_stmt(ins, &i, BPF_LD | BPF_W | BPF_ABS, + offsetof(struct udev_monitor_netlink_header, + filter_tag_bloom_lo)); + /* clear bits (tag bits & bloom bits) */ + bpf_stmt(ins, &i, BPF_ALU | BPF_AND | BPF_K, + tag_bloom_lo); + /* jump behind end of tag match block if tag matches */ + tag_matches--; + bpf_jmp(ins, &i, BPF_JMP | BPF_JEQ | BPF_K, + tag_bloom_lo, 1 + (tag_matches * 6), 0); + } + + /* nothing matched, drop packet */ + bpf_stmt(ins, &i, BPF_RET | BPF_K, 0); + } + + /* add all subsystem matches */ + if (udev_list_get_entry(&udev_monitor->filter_subsystem_list) != NULL) { + udev_list_entry_foreach(list_entry, + udev_list_get_entry(&udev_monitor-> + filter_subsystem_list)) + { + unsigned int hash = + util_string_hash32(udev_list_entry_get_name + (list_entry)); + + /* load device subsystem value in A */ + bpf_stmt(ins, &i, BPF_LD | BPF_W | BPF_ABS, + offsetof(struct udev_monitor_netlink_header, + filter_subsystem_hash)); + if (udev_list_entry_get_value(list_entry) == NULL) { + /* jump if subsystem does not match */ + bpf_jmp(ins, &i, BPF_JMP | BPF_JEQ | BPF_K, + hash, 0, 1); + } else { + /* jump if subsystem does not match */ + bpf_jmp(ins, &i, BPF_JMP | BPF_JEQ | BPF_K, + hash, 0, 3); + + /* load device devtype value in A */ + bpf_stmt(ins, &i, BPF_LD | BPF_W | BPF_ABS, + offsetof(struct + udev_monitor_netlink_header, + filter_devtype_hash)); + /* jump if value does not match */ + hash = + util_string_hash32(udev_list_entry_get_value + (list_entry)); + bpf_jmp(ins, &i, BPF_JMP | BPF_JEQ | BPF_K, + hash, 0, 1); + } + + /* matched, pass packet */ + bpf_stmt(ins, &i, BPF_RET | BPF_K, 0xffffffff); + + if (i + 1 >= ELEMENTSOF(ins)) + return -E2BIG; + } + + /* nothing matched, drop packet */ + bpf_stmt(ins, &i, BPF_RET | BPF_K, 0); + } + + /* matched, pass packet */ + bpf_stmt(ins, &i, BPF_RET | BPF_K, 0xffffffff); + + /* install filter */ + // NOTE: attaches to either netlink or sockpair + memzero(&filter, sizeof(filter)); + filter.len = i; + filter.filter = ins; + err = + setsockopt(udev_monitor->sock, SOL_SOCKET, SO_ATTACH_FILTER, + &filter, sizeof(filter)); + return err < 0 ? -errno : 0; } - -int udev_monitor_allow_unicast_sender(struct udev_monitor *udev_monitor, struct udev_monitor *sender) +int udev_monitor_allow_unicast_sender(struct udev_monitor *udev_monitor, + struct udev_monitor *sender) { - // only for kernel-type links - if( udev_monitor->type != UDEV_MONITOR_TYPE_KERNEL ) { - return -EINVAL; - } - - udev_monitor->snl_trusted_sender.nl.nl_pid = sender->snl.nl.nl_pid; - return 0; -} + // only for kernel-type links + if (udev_monitor->type != UDEV_MONITOR_TYPE_KERNEL) { + return -EINVAL; + } + udev_monitor->snl_trusted_sender.nl.nl_pid = sender->snl.nl.nl_pid; + return 0; +} /** * udev_monitor_enable_receiving: @@ -404,58 +439,61 @@ int udev_monitor_allow_unicast_sender(struct udev_monitor *udev_monitor, struct */ int udev_monitor_enable_receiving(struct udev_monitor *udev_monitor) { - - if( udev_monitor == NULL ) { - return -EINVAL; - } - - // libudev-compat: only for kernel types - // udev-types are already in a receiving state - if( udev_monitor->type != UDEV_MONITOR_TYPE_KERNEL ) { - return 0; - } - - int err = 0; - const int on = 1; - - udev_monitor_filter_update(udev_monitor); - - if (!udev_monitor->bound) { - err = bind(udev_monitor->sock, &udev_monitor->snl.sa, sizeof(struct sockaddr_nl)); - if (err == 0) { - udev_monitor->bound = true; - } - } - - if (err >= 0) { - union sockaddr_union snl; - socklen_t addrlen; - - // get the address the kernel has assigned us - // it is usually, but not necessarily the pid - - addrlen = sizeof(struct sockaddr_nl); - err = getsockname(udev_monitor->sock, &snl.sa, &addrlen); - if (err == 0) { - udev_monitor->snl.nl.nl_pid = snl.nl.nl_pid; - } - } else { - - int errsv = errno; - log_debug("bind failed: %s", strerror(errsv)); - return -errsv; - } - - // enable receiving of sender credentials - err = setsockopt(udev_monitor->sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)); - if (err < 0) { - - int errsv = errno; - log_debug("setting SO_PASSCRED failed: %s", strerror(errsv)); - return -errsv; - } - - return 0; + + if (udev_monitor == NULL) { + return -EINVAL; + } + // libudev-compat: only for kernel types + // udev-types are already in a receiving state + if (udev_monitor->type != UDEV_MONITOR_TYPE_KERNEL) { + return 0; + } + + int err = 0; + const int on = 1; + + udev_monitor_filter_update(udev_monitor); + + if (!udev_monitor->bound) { + err = + bind(udev_monitor->sock, &udev_monitor->snl.sa, + sizeof(struct sockaddr_nl)); + if (err == 0) { + udev_monitor->bound = true; + } + } + + if (err >= 0) { + union sockaddr_union snl; + socklen_t addrlen; + + // get the address the kernel has assigned us + // it is usually, but not necessarily the pid + + addrlen = sizeof(struct sockaddr_nl); + err = getsockname(udev_monitor->sock, &snl.sa, &addrlen); + if (err == 0) { + udev_monitor->snl.nl.nl_pid = snl.nl.nl_pid; + } + } else { + + int errsv = errno; + log_debug("bind failed: %s", strerror(errsv)); + return -errsv; + } + + // enable receiving of sender credentials + err = + setsockopt(udev_monitor->sock, SOL_SOCKET, SO_PASSCRED, &on, + sizeof(on)); + if (err < 0) { + + int errsv = errno; + log_debug("setting SO_PASSCRED failed: %s", strerror(errsv)); + return -errsv; + } + + return 0; } /** @@ -468,27 +506,28 @@ int udev_monitor_enable_receiving(struct udev_monitor *udev_monitor) * * Returns: 0 on success, otherwise -1 on error. */ -int udev_monitor_set_receive_buffer_size(struct udev_monitor *udev_monitor, int size) +int udev_monitor_set_receive_buffer_size(struct udev_monitor *udev_monitor, + int size) { - if (udev_monitor == NULL) { - return -EINVAL; - } - - return setsockopt(udev_monitor->sock, SOL_SOCKET, SO_RCVBUFFORCE, &size, sizeof(size)); + if (udev_monitor == NULL) { + return -EINVAL; + } + + return setsockopt(udev_monitor->sock, SOL_SOCKET, SO_RCVBUFFORCE, &size, + sizeof(size)); } int udev_monitor_disconnect(struct udev_monitor *udev_monitor) { - if( udev_monitor->type == UDEV_MONITOR_TYPE_UDEV ) { - return udev_monitor_fs_shutdown( udev_monitor ); - } - else { - - int err = 0; - err = close(udev_monitor->sock); - udev_monitor->sock = -1; - return err < 0 ? -errno : 0; - } + if (udev_monitor->type == UDEV_MONITOR_TYPE_UDEV) { + return udev_monitor_fs_shutdown(udev_monitor); + } else { + + int err = 0; + err = close(udev_monitor->sock); + udev_monitor->sock = -1; + return err < 0 ? -errno : 0; + } } /** @@ -501,12 +540,12 @@ int udev_monitor_disconnect(struct udev_monitor *udev_monitor) **/ struct udev_monitor *udev_monitor_ref(struct udev_monitor *udev_monitor) { - if (udev_monitor == NULL) { - return NULL; - } - - udev_monitor->refcount++; - return udev_monitor; + if (udev_monitor == NULL) { + return NULL; + } + + udev_monitor->refcount++; + return udev_monitor; } /** @@ -521,30 +560,29 @@ struct udev_monitor *udev_monitor_ref(struct udev_monitor *udev_monitor) **/ struct udev_monitor *udev_monitor_unref(struct udev_monitor *udev_monitor) { - if (udev_monitor == NULL) { - return NULL; - } - - udev_monitor->refcount--; - - if (udev_monitor->refcount > 0) { - return NULL; - } - - udev_list_cleanup(&udev_monitor->filter_subsystem_list); - udev_list_cleanup(&udev_monitor->filter_tag_list); - - if( udev_monitor->type == UDEV_MONITOR_TYPE_UDEV ) { - udev_monitor_fs_destroy( udev_monitor ); - } - else { - if (udev_monitor->sock >= 0) { - close(udev_monitor->sock); - } - } - - free(udev_monitor); - return NULL; + if (udev_monitor == NULL) { + return NULL; + } + + udev_monitor->refcount--; + + if (udev_monitor->refcount > 0) { + return NULL; + } + + udev_list_cleanup(&udev_monitor->filter_subsystem_list); + udev_list_cleanup(&udev_monitor->filter_tag_list); + + if (udev_monitor->type == UDEV_MONITOR_TYPE_UDEV) { + udev_monitor_fs_destroy(udev_monitor); + } else { + if (udev_monitor->sock >= 0) { + close(udev_monitor->sock); + } + } + + free(udev_monitor); + return NULL; } /** @@ -557,10 +595,10 @@ struct udev_monitor *udev_monitor_unref(struct udev_monitor *udev_monitor) **/ struct udev *udev_monitor_get_udev(struct udev_monitor *udev_monitor) { - if (udev_monitor == NULL) { - return NULL; - } - return udev_monitor->udev; + if (udev_monitor == NULL) { + return NULL; + } + return udev_monitor->udev; } /** @@ -579,340 +617,352 @@ struct udev *udev_monitor_get_udev(struct udev_monitor *udev_monitor) **/ int udev_monitor_get_fd(struct udev_monitor *udev_monitor) { - if (udev_monitor == NULL) { - return -EINVAL; - } - - if( udev_monitor->type == UDEV_MONITOR_TYPE_UDEV ) { - return udev_monitor->epoll_fd; - } - else { - return udev_monitor->sock; - } + if (udev_monitor == NULL) { + return -EINVAL; + } + + if (udev_monitor->type == UDEV_MONITOR_TYPE_UDEV) { + return udev_monitor->epoll_fd; + } else { + return udev_monitor->sock; + } } -static int passes_filter(struct udev_monitor *udev_monitor, struct udev_device *udev_device) +static int passes_filter(struct udev_monitor *udev_monitor, + struct udev_device *udev_device) { - struct udev_list_entry *list_entry; - - if (udev_list_get_entry(&udev_monitor->filter_subsystem_list) == NULL) - goto tag; - udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_monitor->filter_subsystem_list)) { - const char *subsys = udev_list_entry_get_name(list_entry); - const char *dsubsys = udev_device_get_subsystem(udev_device); - const char *devtype; - const char *ddevtype; - - if (!streq(dsubsys, subsys)) - continue; - - devtype = udev_list_entry_get_value(list_entry); - if (devtype == NULL) - goto tag; - ddevtype = udev_device_get_devtype(udev_device); - if (ddevtype == NULL) - continue; - if (streq(ddevtype, devtype)) - goto tag; - } - return 0; - -tag: - if (udev_list_get_entry(&udev_monitor->filter_tag_list) == NULL) - return 1; - udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_monitor->filter_tag_list)) { - const char *tag = udev_list_entry_get_name(list_entry); - - if (udev_device_has_tag(udev_device, tag)) - return 1; - } - return 0; + struct udev_list_entry *list_entry; + + if (udev_list_get_entry(&udev_monitor->filter_subsystem_list) == NULL) + goto tag; + udev_list_entry_foreach(list_entry, + udev_list_get_entry(&udev_monitor-> + filter_subsystem_list)) { + const char *subsys = udev_list_entry_get_name(list_entry); + const char *dsubsys = udev_device_get_subsystem(udev_device); + const char *devtype; + const char *ddevtype; + + if (!streq(dsubsys, subsys)) + continue; + + devtype = udev_list_entry_get_value(list_entry); + if (devtype == NULL) + goto tag; + ddevtype = udev_device_get_devtype(udev_device); + if (ddevtype == NULL) + continue; + if (streq(ddevtype, devtype)) + goto tag; + } + return 0; + + tag: + if (udev_list_get_entry(&udev_monitor->filter_tag_list) == NULL) + return 1; + udev_list_entry_foreach(list_entry, + udev_list_get_entry(&udev_monitor-> + filter_tag_list)) { + const char *tag = udev_list_entry_get_name(list_entry); + + if (udev_device_has_tag(udev_device, tag)) + return 1; + } + return 0; } - // receive a device from netlink -static struct udev_device* udev_monitor_receive_device_netlink( struct udev_monitor* udev_monitor ) { - - if( udev_monitor == NULL ) { - return NULL; - } - - if( udev_monitor->type != UDEV_MONITOR_TYPE_KERNEL ) { - - errno = EINVAL; - return NULL; - } - - struct udev_device *udev_device; - struct msghdr smsg; - struct iovec iov; - char cred_msg[CMSG_SPACE(sizeof(struct ucred))]; - struct cmsghdr *cmsg; - union sockaddr_union snl; - struct ucred *cred; - union { - struct udev_monitor_netlink_header nlh; - char raw[8192]; - } buf; - ssize_t buflen; - ssize_t bufpos; - bool is_initialized = false; - -retry: - if (udev_monitor == NULL) - return NULL; - iov.iov_base = &buf; - iov.iov_len = sizeof(buf); - memzero(&smsg, sizeof(struct msghdr)); - smsg.msg_iov = &iov; - smsg.msg_iovlen = 1; - smsg.msg_control = cred_msg; - smsg.msg_controllen = sizeof(cred_msg); - smsg.msg_name = &snl; - smsg.msg_namelen = sizeof(snl); - - buflen = recvmsg(udev_monitor->sock, &smsg, 0); - if (buflen < 0) { - if (errno != EINTR) { - log_debug("%s", "unable to receive message"); - } - return NULL; - } - - if (buflen < 32 || (smsg.msg_flags & MSG_TRUNC)) { - log_debug("%s", "invalid message length"); - return NULL; - } - - if (snl.nl.nl_groups == 0) { - /* unicast message, check if we trust the sender */ - if (udev_monitor->snl_trusted_sender.nl.nl_pid == 0 || - snl.nl.nl_pid != udev_monitor->snl_trusted_sender.nl.nl_pid) { - log_debug("%s", "unicast netlink message ignored"); - return NULL; - } - } else if (snl.nl.nl_groups == UDEV_MONITOR_KERNEL) { - if (snl.nl.nl_pid > 0) { - log_debug("multicast kernel netlink message from PID %"PRIu32" ignored", - snl.nl.nl_pid); - return NULL; - } - } - - cmsg = CMSG_FIRSTHDR(&smsg); - if (cmsg == NULL || cmsg->cmsg_type != SCM_CREDENTIALS) { - log_debug("%s", "no sender credentials received, message ignored"); - return NULL; - } - - cred = (struct ucred *)CMSG_DATA(cmsg); - if (cred->uid != 0) { - log_debug("sender uid="UID_FMT", message ignored", cred->uid); - return NULL; - } - - if (memcmp(buf.raw, "libudev", 8) == 0) { - /* udev message needs proper version magic */ - if (buf.nlh.magic != htonl(UDEV_MONITOR_MAGIC)) { - log_debug("%s", "unrecognized message signature (%x != %x)", - buf.nlh.magic, htonl(UDEV_MONITOR_MAGIC)); - return NULL; - } - if (buf.nlh.properties_off+32 > (size_t)buflen) { - log_debug("%s", "message smaller than expected (%u > %zd)", - buf.nlh.properties_off+32, buflen); - return NULL; - } - - bufpos = buf.nlh.properties_off; - - /* devices received from udev are always initialized */ - is_initialized = true; - } else { - /* kernel message with header */ - bufpos = strlen(buf.raw) + 1; - if ((size_t)bufpos < sizeof("a@/d") || bufpos >= buflen) { - log_debug("%s", "invalid message length"); - return NULL; - } - - /* check message header */ - if (strstr(buf.raw, "@/") == NULL) { - log_debug("%s", "unrecognized message header"); - return NULL; - } - } - - udev_device = udev_device_new_from_nulstr(udev_monitor->udev, &buf.raw[bufpos], buflen - bufpos); - if (!udev_device) { - log_debug("could not create device: %s", strerror(errno)); - return NULL; - } - - if (is_initialized) - udev_device_set_is_initialized(udev_device); - - /* skip device, if it does not pass the current filter */ - if (!passes_filter(udev_monitor, udev_device)) { - struct pollfd pfd[1]; - int rc; - - udev_device_unref(udev_device); - - /* if something is queued, get next device */ - pfd[0].fd = udev_monitor->sock; - pfd[0].events = POLLIN; - rc = poll(pfd, 1, 0); - if (rc > 0) - goto retry; - return NULL; - } - - return udev_device; -} +static struct udev_device *udev_monitor_receive_device_netlink(struct + udev_monitor + *udev_monitor) +{ + if (udev_monitor == NULL) { + return NULL; + } + + if (udev_monitor->type != UDEV_MONITOR_TYPE_KERNEL) { + + errno = EINVAL; + return NULL; + } + + struct udev_device *udev_device; + struct msghdr smsg; + struct iovec iov; + char cred_msg[CMSG_SPACE(sizeof(struct ucred))]; + struct cmsghdr *cmsg; + union sockaddr_union snl; + struct ucred *cred; + union { + struct udev_monitor_netlink_header nlh; + char raw[8192]; + } buf; + ssize_t buflen; + ssize_t bufpos; + bool is_initialized = false; + + retry: + if (udev_monitor == NULL) + return NULL; + iov.iov_base = &buf; + iov.iov_len = sizeof(buf); + memzero(&smsg, sizeof(struct msghdr)); + smsg.msg_iov = &iov; + smsg.msg_iovlen = 1; + smsg.msg_control = cred_msg; + smsg.msg_controllen = sizeof(cred_msg); + smsg.msg_name = &snl; + smsg.msg_namelen = sizeof(snl); + + buflen = recvmsg(udev_monitor->sock, &smsg, 0); + if (buflen < 0) { + if (errno != EINTR) { + log_debug("%s", "unable to receive message"); + } + return NULL; + } + + if (buflen < 32 || (smsg.msg_flags & MSG_TRUNC)) { + log_debug("%s", "invalid message length"); + return NULL; + } + + if (snl.nl.nl_groups == 0) { + /* unicast message, check if we trust the sender */ + if (udev_monitor->snl_trusted_sender.nl.nl_pid == 0 || + snl.nl.nl_pid != + udev_monitor->snl_trusted_sender.nl.nl_pid) { + log_debug("%s", "unicast netlink message ignored"); + return NULL; + } + } else if (snl.nl.nl_groups == UDEV_MONITOR_KERNEL) { + if (snl.nl.nl_pid > 0) { + log_debug("multicast kernel netlink message from PID %" + PRIu32 " ignored", snl.nl.nl_pid); + return NULL; + } + } + + cmsg = CMSG_FIRSTHDR(&smsg); + if (cmsg == NULL || cmsg->cmsg_type != SCM_CREDENTIALS) { + log_debug("%s", + "no sender credentials received, message ignored"); + return NULL; + } + + cred = (struct ucred *)CMSG_DATA(cmsg); + if (cred->uid != 0) { + log_debug("sender uid=" UID_FMT ", message ignored", cred->uid); + return NULL; + } + + if (memcmp(buf.raw, "libudev", 8) == 0) { + /* udev message needs proper version magic */ + if (buf.nlh.magic != htonl(UDEV_MONITOR_MAGIC)) { + log_debug("%s", + "unrecognized message signature (%x != %x)", + buf.nlh.magic, htonl(UDEV_MONITOR_MAGIC)); + return NULL; + } + if (buf.nlh.properties_off + 32 > (size_t) buflen) { + log_debug("%s", + "message smaller than expected (%u > %zd)", + buf.nlh.properties_off + 32, buflen); + return NULL; + } + + bufpos = buf.nlh.properties_off; + + /* devices received from udev are always initialized */ + is_initialized = true; + } else { + /* kernel message with header */ + bufpos = strlen(buf.raw) + 1; + if ((size_t) bufpos < sizeof("a@/d") || bufpos >= buflen) { + log_debug("%s", "invalid message length"); + return NULL; + } + + /* check message header */ + if (strstr(buf.raw, "@/") == NULL) { + log_debug("%s", "unrecognized message header"); + return NULL; + } + } + + udev_device = + udev_device_new_from_nulstr(udev_monitor->udev, &buf.raw[bufpos], + buflen - bufpos); + if (!udev_device) { + log_debug("could not create device: %s", strerror(errno)); + return NULL; + } + + if (is_initialized) + udev_device_set_is_initialized(udev_device); + + /* skip device, if it does not pass the current filter */ + if (!passes_filter(udev_monitor, udev_device)) { + struct pollfd pfd[1]; + int rc; + + udev_device_unref(udev_device); + + /* if something is queued, get next device */ + pfd[0].fd = udev_monitor->sock; + pfd[0].events = POLLIN; + rc = poll(pfd, 1, 0); + if (rc > 0) + goto retry; + return NULL; + } + + return udev_device; +} // receive a device from the filesystem (i.e. for udev-type monitors) -static struct udev_device *udev_monitor_receive_device_fs(struct udev_monitor *udev_monitor) +static struct udev_device *udev_monitor_receive_device_fs(struct udev_monitor + *udev_monitor) { - struct udev_device *udev_device; - struct msghdr smsg; - struct iovec iov; - int rc = 0; - union { - struct udev_monitor_netlink_header nlh; - char raw[8192]; - } buf; - ssize_t buflen; - ssize_t bufpos; - bool is_initialized = false; - bool rescan = false; - - struct pollfd pfd[1]; - -retry: - if (udev_monitor == NULL) { - return NULL; - } - - // are there pending events? - pfd[0].fd = udev_monitor->sock; - pfd[0].events = POLLIN; - - rc = poll( pfd, 1, 0 ); - if( rc < 0 ) { - - rc = -errno; - log_error("poll(%d) rc = %d\n", udev_monitor->sock, rc ); - - return NULL; - } - - if( rc == 0 ) { - - // no events bufferred. - // push as many events as we can into the socketpair - rc = udev_monitor_fs_push_events( udev_monitor ); - if( rc < 0 ) { - - if( rc == -ENODATA ) { - // the socketpair was empty, and there were no bufferred events. - // can only mean that whatever event got created, was unlinked before we could scan it. - // shouldn't happen unless the admin is meddling... - return NULL; - } - - if( rc != -EAGAIN ) { - - log_error("udev_monitor_fs_push_events rc = %d\n", rc ); - return NULL; - } - else { - - // there are pending events, but we couldn't push any at this time. - // this means the socket buffer is too small, or there was some - // socket-level error. - goto retry; - } - } - } - - // prepare to receive - iov.iov_base = &buf; - iov.iov_len = sizeof(buf); - memzero(&smsg, sizeof(struct msghdr)); - smsg.msg_iov = &iov; - smsg.msg_iovlen = 1; - - // get a message we sent to ourselves through the filter - buflen = recvmsg(udev_monitor->sock, &smsg, 0); - if (buflen < 0) { - if (errno != EINTR) { - log_debug("%s", "unable to receive message"); - } - return NULL; - } - - if (buflen < 32 || (smsg.msg_flags & MSG_TRUNC)) { - - log_debug("%s", "invalid message length"); - return NULL; - } - - if (memcmp(buf.raw, "libudev", 8) == 0) { - - /* udev message needs proper version magic */ - if (buf.nlh.magic != htonl(UDEV_MONITOR_MAGIC)) { - log_debug("unrecognized message signature (%x != %x)", - buf.nlh.magic, htonl(UDEV_MONITOR_MAGIC)); - return NULL; - } - if (buf.nlh.properties_off+32 > (size_t)buflen) { - return NULL; - } - - bufpos = buf.nlh.properties_off; - - /* devices received from udev are always initialized */ - is_initialized = true; - - } else { - - // libudev-compat: should never be reached, since we don't listen to netlink - log_error("%s", "Invalid message: missing 'libudev' header"); - return NULL; - } - - udev_device = udev_device_new_from_nulstr(udev_monitor->udev, &buf.raw[bufpos], buflen - bufpos); - if (!udev_device) { - return NULL; - } - - if (is_initialized) { - udev_device_set_is_initialized(udev_device); - } - - /* skip device, if it does not pass the current filter */ - if (!passes_filter(udev_monitor, udev_device)) { - - udev_device_unref(udev_device); - - /* if something is queued, get next device */ - pfd[0].fd = udev_monitor->epoll_fd; - pfd[0].events = POLLIN; - rc = poll(pfd, 1, 0); - - if (rc > 0) { - goto retry; - } - - return NULL; - } - - return udev_device; + struct udev_device *udev_device; + struct msghdr smsg; + struct iovec iov; + int rc = 0; + union { + struct udev_monitor_netlink_header nlh; + char raw[8192]; + } buf; + ssize_t buflen; + ssize_t bufpos; + bool is_initialized = false; + bool rescan = false; + + struct pollfd pfd[1]; + + retry: + if (udev_monitor == NULL) { + return NULL; + } + // are there pending events? + pfd[0].fd = udev_monitor->sock; + pfd[0].events = POLLIN; + + rc = poll(pfd, 1, 0); + if (rc < 0) { + + rc = -errno; + log_error("poll(%d) rc = %d\n", udev_monitor->sock, rc); + + return NULL; + } + + if (rc == 0) { + + // no events bufferred. + // push as many events as we can into the socketpair + rc = udev_monitor_fs_push_events(udev_monitor); + if (rc < 0) { + + if (rc == -ENODATA) { + // the socketpair was empty, and there were no bufferred events. + // can only mean that whatever event got created, was unlinked before we could scan it. + // shouldn't happen unless the admin is meddling... + return NULL; + } + + if (rc != -EAGAIN) { + + log_error + ("udev_monitor_fs_push_events rc = %d\n", + rc); + return NULL; + } else { + + // there are pending events, but we couldn't push any at this time. + // this means the socket buffer is too small, or there was some + // socket-level error. + goto retry; + } + } + } + // prepare to receive + iov.iov_base = &buf; + iov.iov_len = sizeof(buf); + memzero(&smsg, sizeof(struct msghdr)); + smsg.msg_iov = &iov; + smsg.msg_iovlen = 1; + + // get a message we sent to ourselves through the filter + buflen = recvmsg(udev_monitor->sock, &smsg, 0); + if (buflen < 0) { + if (errno != EINTR) { + log_debug("%s", "unable to receive message"); + } + return NULL; + } + + if (buflen < 32 || (smsg.msg_flags & MSG_TRUNC)) { + + log_debug("%s", "invalid message length"); + return NULL; + } + + if (memcmp(buf.raw, "libudev", 8) == 0) { + + /* udev message needs proper version magic */ + if (buf.nlh.magic != htonl(UDEV_MONITOR_MAGIC)) { + log_debug("unrecognized message signature (%x != %x)", + buf.nlh.magic, htonl(UDEV_MONITOR_MAGIC)); + return NULL; + } + if (buf.nlh.properties_off + 32 > (size_t) buflen) { + return NULL; + } + + bufpos = buf.nlh.properties_off; + + /* devices received from udev are always initialized */ + is_initialized = true; + + } else { + + // libudev-compat: should never be reached, since we don't listen to netlink + log_error("%s", "Invalid message: missing 'libudev' header"); + return NULL; + } + + udev_device = + udev_device_new_from_nulstr(udev_monitor->udev, &buf.raw[bufpos], + buflen - bufpos); + if (!udev_device) { + return NULL; + } + + if (is_initialized) { + udev_device_set_is_initialized(udev_device); + } + + /* skip device, if it does not pass the current filter */ + if (!passes_filter(udev_monitor, udev_device)) { + + udev_device_unref(udev_device); + + /* if something is queued, get next device */ + pfd[0].fd = udev_monitor->epoll_fd; + pfd[0].events = POLLIN; + rc = poll(pfd, 1, 0); + + if (rc > 0) { + goto retry; + } + + return NULL; + } + + return udev_device; } - /** * udev_monitor_receive_device: * @udev_monitor: udev monitor @@ -933,123 +983,129 @@ static struct udev_device *udev_monitor_receive_device_fs(struct udev_monitor *u * Returns: a new udev device, or #NULL, in case of an error **/ -struct udev_device *udev_monitor_receive_device(struct udev_monitor *udev_monitor) { - - if( udev_monitor == NULL ) { - return NULL; - } - - if( udev_monitor->type == UDEV_MONITOR_TYPE_KERNEL ) { - - return udev_monitor_receive_device_netlink( udev_monitor ); - } - else if( udev_monitor->type == UDEV_MONITOR_TYPE_UDEV ) { - - return udev_monitor_receive_device_fs( udev_monitor ); - } - else { - - errno = EINVAL; - return NULL; - } -} +struct udev_device *udev_monitor_receive_device(struct udev_monitor + *udev_monitor) +{ + + if (udev_monitor == NULL) { + return NULL; + } + + if (udev_monitor->type == UDEV_MONITOR_TYPE_KERNEL) { + + return udev_monitor_receive_device_netlink(udev_monitor); + } else if (udev_monitor->type == UDEV_MONITOR_TYPE_UDEV) { + return udev_monitor_receive_device_fs(udev_monitor); + } else { -int udev_monitor_send_device(struct udev_monitor *udev_monitor, struct udev_monitor *destination, struct udev_device *udev_device) + errno = EINVAL; + return NULL; + } +} + +int udev_monitor_send_device(struct udev_monitor *udev_monitor, + struct udev_monitor *destination, + struct udev_device *udev_device) { - - if( udev_monitor == NULL ) { - return -EINVAL; - } - - const char *buf, *val; - ssize_t blen, count; - struct msghdr smsg; - int sock = -1; - struct udev_monitor_netlink_header nlh = { - .prefix = "libudev", - .magic = htonl(UDEV_MONITOR_MAGIC), - .header_size = sizeof nlh, - }; - struct iovec iov[2] = { - { .iov_base = &nlh, .iov_len = sizeof nlh }, - }; - - memset( &smsg, 0, sizeof(struct msghdr) ); - - smsg.msg_iov = iov; - smsg.msg_iovlen = 2; - - struct udev_list_entry *list_entry; - uint64_t tag_bloom_bits; - - // serialize the device - blen = udev_device_get_properties_monitor_buf(udev_device, &buf); - if (blen < 32) { - return -EINVAL; - } - - /* fill in versioned header */ - val = udev_device_get_subsystem(udev_device); - nlh.filter_subsystem_hash = htonl(util_string_hash32(val)); - - val = udev_device_get_devtype(udev_device); - if (val != NULL) { - nlh.filter_devtype_hash = htonl(util_string_hash32(val)); - } - - /* add tag bloom filter */ - tag_bloom_bits = 0; - udev_list_entry_foreach(list_entry, udev_device_get_tags_list_entry(udev_device)) - tag_bloom_bits |= util_string_bloom64(udev_list_entry_get_name(list_entry)); - - if (tag_bloom_bits > 0) { - nlh.filter_tag_bloom_hi = htonl(tag_bloom_bits >> 32); - nlh.filter_tag_bloom_lo = htonl(tag_bloom_bits & 0xffffffff); - } - - /* add properties list */ - nlh.properties_off = iov[0].iov_len; - nlh.properties_len = blen; - iov[1].iov_base = (char *)buf; - iov[1].iov_len = blen; - - /* - * Use custom address for target, or the default one. - * - * If we send to a multicast group, we will get - * ECONNREFUSED, which is expected. - */ - - if( udev_monitor->type == UDEV_MONITOR_TYPE_KERNEL ) { - - sock = udev_monitor->sock; - - if (destination) - smsg.msg_name = &destination->snl; - else - smsg.msg_name = &udev_monitor->snl_destination; - - smsg.msg_namelen = sizeof(struct sockaddr_nl); - } - else { - - sock = udev_monitor->sock_fs; - } - - count = sendmsg( sock, &smsg, 0); - if (count < 0) { - - if (!destination) { - log_debug("passed unknown number of bytes to netlink monitor %p", udev_monitor); - return 0; - } else { - return -errno; - } - } - - log_debug("passed %zi bytes to netlink monitor %p", count, udev_monitor); - return count; + + if (udev_monitor == NULL) { + return -EINVAL; + } + + const char *buf, *val; + ssize_t blen, count; + struct msghdr smsg; + int sock = -1; + struct udev_monitor_netlink_header nlh = { + .prefix = "libudev", + .magic = htonl(UDEV_MONITOR_MAGIC), + .header_size = sizeof nlh, + }; + struct iovec iov[2] = { + {.iov_base = &nlh,.iov_len = sizeof nlh} + , + }; + + memset(&smsg, 0, sizeof(struct msghdr)); + + smsg.msg_iov = iov; + smsg.msg_iovlen = 2; + + struct udev_list_entry *list_entry; + uint64_t tag_bloom_bits; + + // serialize the device + blen = udev_device_get_properties_monitor_buf(udev_device, &buf); + if (blen < 32) { + return -EINVAL; + } + + /* fill in versioned header */ + val = udev_device_get_subsystem(udev_device); + nlh.filter_subsystem_hash = htonl(util_string_hash32(val)); + + val = udev_device_get_devtype(udev_device); + if (val != NULL) { + nlh.filter_devtype_hash = htonl(util_string_hash32(val)); + } + + /* add tag bloom filter */ + tag_bloom_bits = 0; + udev_list_entry_foreach(list_entry, + udev_device_get_tags_list_entry(udev_device)) + tag_bloom_bits |= + util_string_bloom64(udev_list_entry_get_name(list_entry)); + + if (tag_bloom_bits > 0) { + nlh.filter_tag_bloom_hi = htonl(tag_bloom_bits >> 32); + nlh.filter_tag_bloom_lo = htonl(tag_bloom_bits & 0xffffffff); + } + + /* add properties list */ + nlh.properties_off = iov[0].iov_len; + nlh.properties_len = blen; + iov[1].iov_base = (char *)buf; + iov[1].iov_len = blen; + + /* + * Use custom address for target, or the default one. + * + * If we send to a multicast group, we will get + * ECONNREFUSED, which is expected. + */ + + if (udev_monitor->type == UDEV_MONITOR_TYPE_KERNEL) { + + sock = udev_monitor->sock; + + if (destination) + smsg.msg_name = &destination->snl; + else + smsg.msg_name = &udev_monitor->snl_destination; + + smsg.msg_namelen = sizeof(struct sockaddr_nl); + } else { + + sock = udev_monitor->sock_fs; + } + + count = sendmsg(sock, &smsg, 0); + if (count < 0) { + + if (!destination) { + log_debug + ("passed unknown number of bytes to netlink monitor %p", + udev_monitor); + return 0; + } else { + return -errno; + } + } + + log_debug("passed %zi bytes to netlink monitor %p", count, + udev_monitor); + return count; } /** @@ -1065,15 +1121,19 @@ int udev_monitor_send_device(struct udev_monitor *udev_monitor, struct udev_moni * * Returns: 0 on success, otherwise a negative error value. */ -int udev_monitor_filter_add_match_subsystem_devtype(struct udev_monitor *udev_monitor, const char *subsystem, const char *devtype) +int udev_monitor_filter_add_match_subsystem_devtype(struct udev_monitor + *udev_monitor, + const char *subsystem, + const char *devtype) { - if (udev_monitor == NULL) - return -EINVAL; - if (subsystem == NULL) - return -EINVAL; - if (udev_list_entry_add(&udev_monitor->filter_subsystem_list, subsystem, devtype) == NULL) - return -ENOMEM; - return 0; + if (udev_monitor == NULL) + return -EINVAL; + if (subsystem == NULL) + return -EINVAL; + if (udev_list_entry_add + (&udev_monitor->filter_subsystem_list, subsystem, devtype) == NULL) + return -ENOMEM; + return 0; } /** @@ -1088,15 +1148,17 @@ int udev_monitor_filter_add_match_subsystem_devtype(struct udev_monitor *udev_mo * * Returns: 0 on success, otherwise a negative error value. */ -int udev_monitor_filter_add_match_tag(struct udev_monitor *udev_monitor, const char *tag) +int udev_monitor_filter_add_match_tag(struct udev_monitor *udev_monitor, + const char *tag) { - if (udev_monitor == NULL) - return -EINVAL; - if (tag == NULL) - return -EINVAL; - if (udev_list_entry_add(&udev_monitor->filter_tag_list, tag, NULL) == NULL) - return -ENOMEM; - return 0; + if (udev_monitor == NULL) + return -EINVAL; + if (tag == NULL) + return -EINVAL; + if (udev_list_entry_add(&udev_monitor->filter_tag_list, tag, NULL) == + NULL) + return -ENOMEM; + return 0; } /** @@ -1109,8 +1171,9 @@ int udev_monitor_filter_add_match_tag(struct udev_monitor *udev_monitor, const c */ int udev_monitor_filter_remove(struct udev_monitor *udev_monitor) { - static struct sock_fprog filter = { 0, NULL }; + static struct sock_fprog filter = { 0, NULL }; - udev_list_cleanup(&udev_monitor->filter_subsystem_list); - return setsockopt(udev_monitor->sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)); + udev_list_cleanup(&udev_monitor->filter_subsystem_list); + return setsockopt(udev_monitor->sock, SOL_SOCKET, SO_ATTACH_FILTER, + &filter, sizeof(filter)); } diff --git a/libudev-compat/libudev-private.h b/libudev-compat/libudev-private.h index 8fc7459..7f60eef 100644 --- a/libudev-compat/libudev-private.h +++ b/libudev-compat/libudev-private.h @@ -48,23 +48,30 @@ #define WRITE_END 1 /* libudev.c */ -int udev_get_rules_path(struct udev *udev, char **path[], usec_t *ts_usec[]); +int udev_get_rules_path(struct udev *udev, char **path[], usec_t * ts_usec[]); /* libudev-device.c */ -struct udev_device *udev_device_new_from_nulstr(struct udev *udev, char *nulstr, ssize_t buflen); -struct udev_device *udev_device_new_from_synthetic_event(struct udev *udev, const char *syspath, const char *action); +struct udev_device *udev_device_new_from_nulstr(struct udev *udev, char *nulstr, + ssize_t buflen); +struct udev_device *udev_device_new_from_synthetic_event(struct udev *udev, + const char *syspath, + const char *action); struct udev_device *udev_device_shallow_clone(struct udev_device *old_device); struct udev_device *udev_device_clone_with_db(struct udev_device *old_device); -int udev_device_copy_properties(struct udev_device *dst, struct udev_device *src); +int udev_device_copy_properties(struct udev_device *dst, + struct udev_device *src); mode_t udev_device_get_devnode_mode(struct udev_device *udev_device); uid_t udev_device_get_devnode_uid(struct udev_device *udev_device); gid_t udev_device_get_devnode_gid(struct udev_device *udev_device); int udev_device_rename(struct udev_device *udev_device, const char *new_name); -int udev_device_add_devlink(struct udev_device *udev_device, const char *devlink); +int udev_device_add_devlink(struct udev_device *udev_device, + const char *devlink); void udev_device_cleanup_devlinks_list(struct udev_device *udev_device); -int udev_device_add_property(struct udev_device *udev_device, const char *key, const char *value); +int udev_device_add_property(struct udev_device *udev_device, const char *key, + const char *value); char **udev_device_get_properties_envp(struct udev_device *udev_device); -ssize_t udev_device_get_properties_monitor_buf(struct udev_device *udev_device, const char **buf); +ssize_t udev_device_get_properties_monitor_buf(struct udev_device *udev_device, + const char **buf); const char *udev_device_get_devpath_old(struct udev_device *udev_device); const char *udev_device_get_id_filename(struct udev_device *udev_device); void udev_device_set_is_initialized(struct udev_device *udev_device); @@ -72,7 +79,8 @@ int udev_device_add_tag(struct udev_device *udev_device, const char *tag); void udev_device_remove_tag(struct udev_device *udev_device, const char *tag); void udev_device_cleanup_tags_list(struct udev_device *udev_device); usec_t udev_device_get_usec_initialized(struct udev_device *udev_device); -void udev_device_ensure_usec_initialized(struct udev_device *udev_device, struct udev_device *old_device); +void udev_device_ensure_usec_initialized(struct udev_device *udev_device, + struct udev_device *old_device); int udev_device_get_devlink_priority(struct udev_device *udev_device); int udev_device_set_devlink_priority(struct udev_device *udev_device, int prio); int udev_device_get_watch_handle(struct udev_device *udev_device); @@ -85,25 +93,26 @@ void udev_device_set_db_persist(struct udev_device *udev_device); /* libudev-device-private.c */ int udev_device_update_db(struct udev_device *udev_device); int udev_device_delete_db(struct udev_device *udev_device); -int udev_device_tag_index(struct udev_device *dev, struct udev_device *dev_old, bool add); - +int udev_device_tag_index(struct udev_device *dev, struct udev_device *dev_old, + bool add); /* libudev-list.c */ struct udev_list_node { - struct udev_list_node *next, *prev; + struct udev_list_node *next, *prev; }; struct udev_list { - struct udev *udev; - struct udev_list_node node; - struct udev_list_entry **entries; - unsigned int entries_cur; - unsigned int entries_max; - bool unique; + struct udev *udev; + struct udev_list_node node; + struct udev_list_entry **entries; + unsigned int entries_cur; + unsigned int entries_max; + bool unique; }; #define UDEV_LIST(list) struct udev_list_node list = { &(list), &(list) } void udev_list_node_init(struct udev_list_node *list); int udev_list_node_is_empty(struct udev_list_node *list); -void udev_list_node_append(struct udev_list_node *new, struct udev_list_node *list); +void udev_list_node_append(struct udev_list_node *new, + struct udev_list_node *list); void udev_list_node_remove(struct udev_list_node *entry); #define udev_list_node_foreach(node, list) \ for (node = (list)->next; \ @@ -116,7 +125,9 @@ void udev_list_node_remove(struct udev_list_node *entry); void udev_list_init(struct udev *udev, struct udev_list *list, bool unique); void udev_list_cleanup(struct udev_list *list); struct udev_list_entry *udev_list_get_entry(struct udev_list *list); -struct udev_list_entry *udev_list_entry_add(struct udev_list *list, const char *name, const char *value); +struct udev_list_entry *udev_list_entry_add(struct udev_list *list, + const char *name, + const char *value); void udev_list_entry_delete(struct udev_list_entry *entry); int udev_list_entry_get_num(struct udev_list_entry *list_entry); void udev_list_entry_set_num(struct udev_list_entry *list_entry, int num); @@ -124,7 +135,7 @@ void udev_list_entry_set_num(struct udev_list_entry *list_entry, int num); for (entry = first, tmp = udev_list_entry_get_next(entry); \ entry != NULL; \ entry = tmp, tmp = udev_list_entry_get_next(tmp)) - + /* libudev-monitor.c - netlink/unix socket communication */ /** @@ -135,46 +146,45 @@ void udev_list_entry_set_num(struct udev_list_entry *list_entry, int num); */ union sockaddr_union { - struct sockaddr sa; - struct sockaddr_in in; - struct sockaddr_in6 in6; - struct sockaddr_un un; - struct sockaddr_nl nl; - struct sockaddr_storage storage; - struct sockaddr_ll ll; + struct sockaddr sa; + struct sockaddr_in in; + struct sockaddr_in6 in6; + struct sockaddr_un un; + struct sockaddr_nl nl; + struct sockaddr_storage storage; + struct sockaddr_ll ll; }; - /** * udev_monitor: * * Opaque object handling an event source. */ struct udev_monitor { - struct udev *udev; - int refcount; - - int type; // libudev-compat: kernel or udev link? - int sock; // libudev-compat: for udev-links, this is a socketpair sink which receives udev devices - // libudev-compat: for kernel-links, this is a netlink socket - union sockaddr_union snl; - union sockaddr_union snl_trusted_sender; - union sockaddr_union snl_destination; - socklen_t addrlen; - struct udev_list filter_subsystem_list; - struct udev_list filter_tag_list; - bool bound; - - // new in libudev-compat - int sock_fs; // socketpair source into which we send udev_devices - int events_wd; // watch descriptor for our events directory - int inotify_fd; // pollable one-shot inotify file descriptor watching the events directory for IN_CREATE. Oneshot because it can overflow. - int epoll_fd; // pollable handle for detecting either the availability of previously-found events (signaled by sock_fs) or new events (inotify_fd) - - pid_t pid; // the PID of the process at the time this monitor was created - char events_dir[PATH_MAX+1]; // path to the directory we watch - - int slot; // monitor slot in our global monitor table + struct udev *udev; + int refcount; + + int type; // libudev-compat: kernel or udev link? + int sock; // libudev-compat: for udev-links, this is a socketpair sink which receives udev devices + // libudev-compat: for kernel-links, this is a netlink socket + union sockaddr_union snl; + union sockaddr_union snl_trusted_sender; + union sockaddr_union snl_destination; + socklen_t addrlen; + struct udev_list filter_subsystem_list; + struct udev_list filter_tag_list; + bool bound; + + // new in libudev-compat + int sock_fs; // socketpair source into which we send udev_devices + int events_wd; // watch descriptor for our events directory + int inotify_fd; // pollable one-shot inotify file descriptor watching the events directory for IN_CREATE. Oneshot because it can overflow. + int epoll_fd; // pollable handle for detecting either the availability of previously-found events (signaled by sock_fs) or new events (inotify_fd) + + pid_t pid; // the PID of the process at the time this monitor was created + char events_dir[PATH_MAX + 1]; // path to the directory we watch + + int slot; // monitor slot in our global monitor table }; // types of monitors @@ -182,31 +192,40 @@ struct udev_monitor { #define UDEV_MONITOR_TYPE_UDEV 2 int udev_monitor_disconnect(struct udev_monitor *udev_monitor); -int udev_monitor_allow_unicast_sender(struct udev_monitor *udev_monitor, struct udev_monitor *sender); +int udev_monitor_allow_unicast_sender(struct udev_monitor *udev_monitor, + struct udev_monitor *sender); int udev_monitor_send_device(struct udev_monitor *udev_monitor, - struct udev_monitor *destination, struct udev_device *udev_device); -struct udev_monitor *udev_monitor_new_from_netlink_fd(struct udev *udev, const char *name, int fd); + struct udev_monitor *destination, + struct udev_device *udev_device); +struct udev_monitor *udev_monitor_new_from_netlink_fd(struct udev *udev, + const char *name, int fd); int udev_monitor_filter_update(struct udev_monitor *udev_monitor); /* libudev-queue.c */ unsigned long long int udev_get_kernel_seqnum(struct udev *udev); -int udev_queue_read_seqnum(FILE *queue_file, unsigned long long int *seqnum); -ssize_t udev_queue_read_devpath(FILE *queue_file, char *devpath, size_t size); -ssize_t udev_queue_skip_devpath(FILE *queue_file); +int udev_queue_read_seqnum(FILE * queue_file, unsigned long long int *seqnum); +ssize_t udev_queue_read_devpath(FILE * queue_file, char *devpath, size_t size); +ssize_t udev_queue_skip_devpath(FILE * queue_file); /* libudev-queue-private.c */ struct udev_queue_export *udev_queue_export_new(struct udev *udev); -struct udev_queue_export *udev_queue_export_unref(struct udev_queue_export *udev_queue_export); +struct udev_queue_export *udev_queue_export_unref(struct udev_queue_export + *udev_queue_export); void udev_queue_export_cleanup(struct udev_queue_export *udev_queue_export); -int udev_queue_export_device_queued(struct udev_queue_export *udev_queue_export, struct udev_device *udev_device); -int udev_queue_export_device_finished(struct udev_queue_export *udev_queue_export, struct udev_device *udev_device); +int udev_queue_export_device_queued(struct udev_queue_export *udev_queue_export, + struct udev_device *udev_device); +int udev_queue_export_device_finished(struct udev_queue_export + *udev_queue_export, + struct udev_device *udev_device); /* libudev-util.c */ #define UTIL_PATH_SIZE 1024 #define UTIL_NAME_SIZE 512 #define UTIL_LINE_SIZE 16384 #define UDEV_ALLOWED_CHARS_INPUT "/ $%?," -ssize_t util_get_sys_core_link_value(struct udev *udev, const char *slink, const char *syspath, char *value, size_t size); +ssize_t util_get_sys_core_link_value(struct udev *udev, const char *slink, + const char *syspath, char *value, + size_t size); int util_resolve_sys_link(struct udev *udev, char *syspath, size_t size); int util_log_priority(const char *priority); size_t util_path_encode(const char *src, char *dest, size_t size); @@ -217,6 +236,7 @@ unsigned int util_string_hash32(const char *key); uint64_t util_string_bloom64(const char *str); /* libudev-util-private.c */ -int util_resolve_subsys_kernel(struct udev *udev, const char *string, char *result, size_t maxsize, int read_value); +int util_resolve_subsys_kernel(struct udev *udev, const char *string, + char *result, size_t maxsize, int read_value); #endif diff --git a/libudev-compat/libudev-queue.c b/libudev-compat/libudev-queue.c index 3f7b364..8d93b4d 100644 --- a/libudev-compat/libudev-queue.c +++ b/libudev-compat/libudev-queue.c @@ -48,9 +48,9 @@ * Opaque object representing the current event queue in the udev daemon. */ struct udev_queue { - struct udev *udev; - int refcount; - int fd; + struct udev *udev; + int refcount; + int fd; }; /** @@ -64,19 +64,19 @@ struct udev_queue { **/ _public_ struct udev_queue *udev_queue_new(struct udev *udev) { - struct udev_queue *udev_queue; + struct udev_queue *udev_queue; - if (udev == NULL) - return NULL; + if (udev == NULL) + return NULL; - udev_queue = new0(struct udev_queue, 1); - if (udev_queue == NULL) - return NULL; + udev_queue = new0(struct udev_queue, 1); + if (udev_queue == NULL) + return NULL; - udev_queue->refcount = 1; - udev_queue->udev = udev; - udev_queue->fd = -1; - return udev_queue; + udev_queue->refcount = 1; + udev_queue->udev = udev; + udev_queue->fd = -1; + return udev_queue; } /** @@ -89,11 +89,11 @@ _public_ struct udev_queue *udev_queue_new(struct udev *udev) **/ _public_ struct udev_queue *udev_queue_ref(struct udev_queue *udev_queue) { - if (udev_queue == NULL) - return NULL; + if (udev_queue == NULL) + return NULL; - udev_queue->refcount++; - return udev_queue; + udev_queue->refcount++; + return udev_queue; } /** @@ -107,17 +107,17 @@ _public_ struct udev_queue *udev_queue_ref(struct udev_queue *udev_queue) **/ _public_ struct udev_queue *udev_queue_unref(struct udev_queue *udev_queue) { - if (udev_queue == NULL) - return NULL; + if (udev_queue == NULL) + return NULL; - udev_queue->refcount--; - if (udev_queue->refcount > 0) - return NULL; + udev_queue->refcount--; + if (udev_queue->refcount > 0) + return NULL; - safe_close(udev_queue->fd); + safe_close(udev_queue->fd); - free(udev_queue); - return NULL; + free(udev_queue); + return NULL; } /** @@ -130,9 +130,9 @@ _public_ struct udev_queue *udev_queue_unref(struct udev_queue *udev_queue) **/ _public_ struct udev *udev_queue_get_udev(struct udev_queue *udev_queue) { - if (udev_queue == NULL) - return NULL; - return udev_queue->udev; + if (udev_queue == NULL) + return NULL; + return udev_queue->udev; } /** @@ -143,9 +143,10 @@ _public_ struct udev *udev_queue_get_udev(struct udev_queue *udev_queue) * * Returns: 0. **/ -_public_ unsigned long long int udev_queue_get_kernel_seqnum(struct udev_queue *udev_queue) +_public_ unsigned long long int udev_queue_get_kernel_seqnum(struct udev_queue + *udev_queue) { - return 0; + return 0; } /** @@ -156,9 +157,10 @@ _public_ unsigned long long int udev_queue_get_kernel_seqnum(struct udev_queue * * * Returns: 0. **/ -_public_ unsigned long long int udev_queue_get_udev_seqnum(struct udev_queue *udev_queue) +_public_ unsigned long long int udev_queue_get_udev_seqnum(struct udev_queue + *udev_queue) { - return 0; + return 0; } /** @@ -171,7 +173,7 @@ _public_ unsigned long long int udev_queue_get_udev_seqnum(struct udev_queue *ud **/ _public_ int udev_queue_get_udev_is_active(struct udev_queue *udev_queue) { - return access("/run/udev/control", F_OK) >= 0; + return access("/run/udev/control", F_OK) >= 0; } /** @@ -184,7 +186,7 @@ _public_ int udev_queue_get_udev_is_active(struct udev_queue *udev_queue) **/ _public_ int udev_queue_get_queue_is_empty(struct udev_queue *udev_queue) { - return access("/run/udev/queue", F_OK) < 0; + return access("/run/udev/queue", F_OK) < 0; } /** @@ -198,10 +200,14 @@ _public_ int udev_queue_get_queue_is_empty(struct udev_queue *udev_queue) * * Returns: a flag indicating if udev is currently handling events. **/ -_public_ int udev_queue_get_seqnum_sequence_is_finished(struct udev_queue *udev_queue, - unsigned long long int start, unsigned long long int end) +_public_ int udev_queue_get_seqnum_sequence_is_finished(struct udev_queue + *udev_queue, + unsigned long long int + start, + unsigned long long int + end) { - return udev_queue_get_queue_is_empty(udev_queue); + return udev_queue_get_queue_is_empty(udev_queue); } /** @@ -214,9 +220,10 @@ _public_ int udev_queue_get_seqnum_sequence_is_finished(struct udev_queue *udev_ * * Returns: a flag indicating if udev is currently handling events. **/ -_public_ int udev_queue_get_seqnum_is_finished(struct udev_queue *udev_queue, unsigned long long int seqnum) +_public_ int udev_queue_get_seqnum_is_finished(struct udev_queue *udev_queue, + unsigned long long int seqnum) { - return udev_queue_get_queue_is_empty(udev_queue); + return udev_queue_get_queue_is_empty(udev_queue); } /** @@ -227,9 +234,11 @@ _public_ int udev_queue_get_seqnum_is_finished(struct udev_queue *udev_queue, un * * Returns: NULL. **/ -_public_ struct udev_list_entry *udev_queue_get_queued_list_entry(struct udev_queue *udev_queue) +_public_ struct udev_list_entry *udev_queue_get_queued_list_entry(struct + udev_queue + *udev_queue) { - return NULL; + return NULL; } /** @@ -238,26 +247,27 @@ _public_ struct udev_list_entry *udev_queue_get_queued_list_entry(struct udev_qu * * Returns: a file descriptor to watch for a queue to become empty. */ -_public_ int udev_queue_get_fd(struct udev_queue *udev_queue) { - int fd; - int r; - - if (udev_queue->fd >= 0) - return udev_queue->fd; - - fd = inotify_init1(IN_CLOEXEC); - if (fd < 0) - return -errno; - - r = inotify_add_watch(fd, "/run/udev" , IN_DELETE); - if (r < 0) { - r = -errno; - close(fd); - return r; - } - - udev_queue->fd = fd; - return fd; +_public_ int udev_queue_get_fd(struct udev_queue *udev_queue) +{ + int fd; + int r; + + if (udev_queue->fd >= 0) + return udev_queue->fd; + + fd = inotify_init1(IN_CLOEXEC); + if (fd < 0) + return -errno; + + r = inotify_add_watch(fd, "/run/udev", IN_DELETE); + if (r < 0) { + r = -errno; + close(fd); + return r; + } + + udev_queue->fd = fd; + return fd; } /** @@ -266,9 +276,10 @@ _public_ int udev_queue_get_fd(struct udev_queue *udev_queue) { * * Returns: the result of clearing the watch for queue changes. */ -_public_ int udev_queue_flush(struct udev_queue *udev_queue) { - if (udev_queue->fd < 0) - return -EINVAL; +_public_ int udev_queue_flush(struct udev_queue *udev_queue) +{ + if (udev_queue->fd < 0) + return -EINVAL; - return flush_fd(udev_queue->fd); + return flush_fd(udev_queue->fd); } diff --git a/libudev-compat/libudev-util.c b/libudev-compat/libudev-util.c index 8af200f..6cfa9d1 100644 --- a/libudev-compat/libudev-util.c +++ b/libudev-compat/libudev-util.c @@ -48,256 +48,257 @@ /* handle "[/]" format */ int util_resolve_subsys_kernel(struct udev *udev, const char *string, - char *result, size_t maxsize, int read_value) + char *result, size_t maxsize, int read_value) { - char temp[UTIL_PATH_SIZE]; - char *subsys; - char *sysname; - struct udev_device *dev; - char *attr; - - if (string[0] != '[') - return -1; - - strscpy(temp, sizeof(temp), string); - - subsys = &temp[1]; - - sysname = strchr(subsys, '/'); - if (sysname == NULL) - return -1; - sysname[0] = '\0'; - sysname = &sysname[1]; - - attr = strchr(sysname, ']'); - if (attr == NULL) - return -1; - attr[0] = '\0'; - attr = &attr[1]; - if (attr[0] == '/') - attr = &attr[1]; - if (attr[0] == '\0') - attr = NULL; - - if (read_value && attr == NULL) - return -1; - - dev = udev_device_new_from_subsystem_sysname(udev, subsys, sysname); - if (dev == NULL) - return -1; - - if (read_value) { - const char *val; - - val = udev_device_get_sysattr_value(dev, attr); - if (val != NULL) - strscpy(result, maxsize, val); - else - result[0] = '\0'; - log_debug("value '[%s/%s]%s' is '%s'", subsys, sysname, attr, result); - } else { - size_t l; - char *s; - - s = result; - l = strpcpyl(&s, maxsize, udev_device_get_syspath(dev), NULL); - if (attr != NULL) - strpcpyl(&s, l, "/", attr, NULL); - log_debug("path '[%s/%s]%s' is '%s'", subsys, sysname, attr, result); - } - udev_device_unref(dev); - return 0; + char temp[UTIL_PATH_SIZE]; + char *subsys; + char *sysname; + struct udev_device *dev; + char *attr; + + if (string[0] != '[') + return -1; + + strscpy(temp, sizeof(temp), string); + + subsys = &temp[1]; + + sysname = strchr(subsys, '/'); + if (sysname == NULL) + return -1; + sysname[0] = '\0'; + sysname = &sysname[1]; + + attr = strchr(sysname, ']'); + if (attr == NULL) + return -1; + attr[0] = '\0'; + attr = &attr[1]; + if (attr[0] == '/') + attr = &attr[1]; + if (attr[0] == '\0') + attr = NULL; + + if (read_value && attr == NULL) + return -1; + + dev = udev_device_new_from_subsystem_sysname(udev, subsys, sysname); + if (dev == NULL) + return -1; + + if (read_value) { + const char *val; + + val = udev_device_get_sysattr_value(dev, attr); + if (val != NULL) + strscpy(result, maxsize, val); + else + result[0] = '\0'; + log_debug("value '[%s/%s]%s' is '%s'", subsys, sysname, attr, + result); + } else { + size_t l; + char *s; + + s = result; + l = strpcpyl(&s, maxsize, udev_device_get_syspath(dev), NULL); + if (attr != NULL) + strpcpyl(&s, l, "/", attr, NULL); + log_debug("path '[%s/%s]%s' is '%s'", subsys, sysname, attr, + result); + } + udev_device_unref(dev); + return 0; } -ssize_t util_get_sys_core_link_value(struct udev *udev, const char *slink, const char *syspath, char *value, size_t size) +ssize_t util_get_sys_core_link_value(struct udev * udev, const char *slink, + const char *syspath, char *value, + size_t size) { - char path[UTIL_PATH_SIZE]; - char target[UTIL_PATH_SIZE]; - ssize_t len; - const char *pos; - - strscpyl(path, sizeof(path), syspath, "/", slink, NULL); - len = readlink(path, target, sizeof(target)); - if (len <= 0 || len == (ssize_t)sizeof(target)) - return -1; - target[len] = '\0'; - pos = strrchr(target, '/'); - if (pos == NULL) - return -1; - pos = &pos[1]; - return strscpy(value, size, pos); + char path[UTIL_PATH_SIZE]; + char target[UTIL_PATH_SIZE]; + ssize_t len; + const char *pos; + + strscpyl(path, sizeof(path), syspath, "/", slink, NULL); + len = readlink(path, target, sizeof(target)); + if (len <= 0 || len == (ssize_t) sizeof(target)) + return -1; + target[len] = '\0'; + pos = strrchr(target, '/'); + if (pos == NULL) + return -1; + pos = &pos[1]; + return strscpy(value, size, pos); } int util_resolve_sys_link(struct udev *udev, char *syspath, size_t size) { - char link_target[UTIL_PATH_SIZE]; - - ssize_t len; - int i; - int back; - char *base = NULL; - - len = readlink(syspath, link_target, sizeof(link_target)); - if (len <= 0 || len == (ssize_t)sizeof(link_target)) - return -1; - link_target[len] = '\0'; - - for (back = 0; startswith(&link_target[back * 3], "../"); back++) - ; - for (i = 0; i <= back; i++) { - base = strrchr(syspath, '/'); - if (base == NULL) - return -EINVAL; - base[0] = '\0'; - } - - strscpyl(base, size - (base - syspath), "/", &link_target[back * 3], NULL); - return 0; + char link_target[UTIL_PATH_SIZE]; + + ssize_t len; + int i; + int back; + char *base = NULL; + + len = readlink(syspath, link_target, sizeof(link_target)); + if (len <= 0 || len == (ssize_t) sizeof(link_target)) + return -1; + link_target[len] = '\0'; + + for (back = 0; startswith(&link_target[back * 3], "../"); back++) ; + for (i = 0; i <= back; i++) { + base = strrchr(syspath, '/'); + if (base == NULL) + return -EINVAL; + base[0] = '\0'; + } + + strscpyl(base, size - (base - syspath), "/", &link_target[back * 3], + NULL); + return 0; } int util_log_priority(const char *priority) { - char *endptr; - int prio; - - prio = strtoul(priority, &endptr, 10); - if (endptr[0] == '\0' || isspace(endptr[0])) { - if (prio >= 0 && prio <= 7) { - return prio; - } - else { - return -ERANGE; - } - } - - // So, I can't find this method anywhere... -Jude - // return log_level_from_string(priority); - - if( strcasecmp( priority, "err" ) == 0 ) { - return LOG_ERR; - } - else if( strcasecmp( priority, "debug" ) == 0 ) { - return LOG_DEBUG; - } - else if( strcasecmp( priority, "info" ) == 0 ) { - return LOG_INFO; - } - - return -EINVAL; + char *endptr; + int prio; + + prio = strtoul(priority, &endptr, 10); + if (endptr[0] == '\0' || isspace(endptr[0])) { + if (prio >= 0 && prio <= 7) { + return prio; + } else { + return -ERANGE; + } + } + // So, I can't find this method anywhere... -Jude + // return log_level_from_string(priority); + + if (strcasecmp(priority, "err") == 0) { + return LOG_ERR; + } else if (strcasecmp(priority, "debug") == 0) { + return LOG_DEBUG; + } else if (strcasecmp(priority, "info") == 0) { + return LOG_INFO; + } + + return -EINVAL; } size_t util_path_encode(const char *src, char *dest, size_t size) { - size_t i, j; - - for (i = 0, j = 0; src[i] != '\0'; i++) { - if (src[i] == '/') { - if (j+4 >= size) { - j = 0; - break; - } - memcpy(&dest[j], "\\x2f", 4); - j += 4; - } else if (src[i] == '\\') { - if (j+4 >= size) { - j = 0; - break; - } - memcpy(&dest[j], "\\x5c", 4); - j += 4; - } else { - if (j+1 >= size) { - j = 0; - break; - } - dest[j] = src[i]; - j++; - } - } - dest[j] = '\0'; - return j; + size_t i, j; + + for (i = 0, j = 0; src[i] != '\0'; i++) { + if (src[i] == '/') { + if (j + 4 >= size) { + j = 0; + break; + } + memcpy(&dest[j], "\\x2f", 4); + j += 4; + } else if (src[i] == '\\') { + if (j + 4 >= size) { + j = 0; + break; + } + memcpy(&dest[j], "\\x5c", 4); + j += 4; + } else { + if (j + 1 >= size) { + j = 0; + break; + } + dest[j] = src[i]; + j++; + } + } + dest[j] = '\0'; + return j; } void util_remove_trailing_chars(char *path, char c) { - size_t len; + size_t len; - if (path == NULL) - return; - len = strlen(path); - while (len > 0 && path[len-1] == c) - path[--len] = '\0'; + if (path == NULL) + return; + len = strlen(path); + while (len > 0 && path[len - 1] == c) + path[--len] = '\0'; } int util_replace_whitespace(const char *str, char *to, size_t len) { - size_t i, j; - - /* strip trailing whitespace */ - len = strnlen(str, len); - while (len && isspace(str[len-1])) - len--; - - /* strip leading whitespace */ - i = 0; - while (isspace(str[i]) && (i < len)) - i++; - - j = 0; - while (i < len) { - /* substitute multiple whitespace with a single '_' */ - if (isspace(str[i])) { - while (isspace(str[i])) - i++; - to[j++] = '_'; - } - to[j++] = str[i++]; - } - to[j] = '\0'; - return 0; + size_t i, j; + + /* strip trailing whitespace */ + len = strnlen(str, len); + while (len && isspace(str[len - 1])) + len--; + + /* strip leading whitespace */ + i = 0; + while (isspace(str[i]) && (i < len)) + i++; + + j = 0; + while (i < len) { + /* substitute multiple whitespace with a single '_' */ + if (isspace(str[i])) { + while (isspace(str[i])) + i++; + to[j++] = '_'; + } + to[j++] = str[i++]; + } + to[j] = '\0'; + return 0; } /* allow chars in whitelist, plain ascii, hex-escaping and valid utf8 */ int util_replace_chars(char *str, const char *white) { - size_t i = 0; - int replaced = 0; - - while (str[i] != '\0') { - int len; - - if (whitelisted_char_for_devnode(str[i], white)) { - i++; - continue; - } - - /* accept hex encoding */ - if (str[i] == '\\' && str[i+1] == 'x') { - i += 2; - continue; - } - - /* accept valid utf8 */ - len = utf8_encoded_valid_unichar(&str[i]); - if (len > 1) { - i += len; - continue; - } - - /* if space is allowed, replace whitespace with ordinary space */ - if (isspace(str[i]) && white != NULL && strchr(white, ' ') != NULL) { - str[i] = ' '; - i++; - replaced++; - continue; - } - - /* everything else is replaced with '_' */ - str[i] = '_'; - i++; - replaced++; - } - return replaced; + size_t i = 0; + int replaced = 0; + + while (str[i] != '\0') { + int len; + + if (whitelisted_char_for_devnode(str[i], white)) { + i++; + continue; + } + + /* accept hex encoding */ + if (str[i] == '\\' && str[i + 1] == 'x') { + i += 2; + continue; + } + + /* accept valid utf8 */ + len = utf8_encoded_valid_unichar(&str[i]); + if (len > 1) { + i += len; + continue; + } + + /* if space is allowed, replace whitespace with ordinary space */ + if (isspace(str[i]) && white != NULL + && strchr(white, ' ') != NULL) { + str[i] = ' '; + i++; + replaced++; + continue; + } + + /* everything else is replaced with '_' */ + str[i] = '_'; + i++; + replaced++; + } + return replaced; } /** @@ -314,23 +315,23 @@ int util_replace_chars(char *str, const char *white) **/ _public_ int udev_util_encode_string(const char *str, char *str_enc, size_t len) { - return encode_devnode_name(str, str_enc, len); + return encode_devnode_name(str, str_enc, len); } unsigned int util_string_hash32(const char *str) { - return MurmurHash2(str, strlen(str), 0); + return MurmurHash2(str, strlen(str), 0); } /* get a bunch of bit numbers out of the hash, and set the bits in our bit field */ uint64_t util_string_bloom64(const char *str) { - uint64_t bits = 0; - unsigned int hash = util_string_hash32(str); - - bits |= 1LLU << (hash & 63); - bits |= 1LLU << ((hash >> 6) & 63); - bits |= 1LLU << ((hash >> 12) & 63); - bits |= 1LLU << ((hash >> 18) & 63); - return bits; + uint64_t bits = 0; + unsigned int hash = util_string_hash32(str); + + bits |= 1LLU << (hash & 63); + bits |= 1LLU << ((hash >> 6) & 63); + bits |= 1LLU << ((hash >> 12) & 63); + bits |= 1LLU << ((hash >> 18) & 63); + return bits; } diff --git a/libudev-compat/libudev.c b/libudev-compat/libudev.c index d65415d..1923db9 100644 --- a/libudev-compat/libudev.c +++ b/libudev-compat/libudev.c @@ -50,11 +50,11 @@ * Opaque object representing the library context. */ struct udev { - int refcount; - void (*log_fn)(struct udev *udev, - int priority, const char *file, int line, const char *fn, - const char *format, va_list args); - void *userdata; + int refcount; + void (*log_fn) (struct udev * udev, + int priority, const char *file, int line, + const char *fn, const char *format, va_list args); + void *userdata; }; /** @@ -66,10 +66,11 @@ struct udev { * * Returns: stored userdata **/ -void *udev_get_userdata(struct udev *udev) { - if (udev == NULL) - return NULL; - return udev->userdata; +void *udev_get_userdata(struct udev *udev) +{ + if (udev == NULL) + return NULL; + return udev->userdata; } /** @@ -79,10 +80,11 @@ void *udev_get_userdata(struct udev *udev) { * * Store custom @userdata in the library context. **/ -void udev_set_userdata(struct udev *udev, void *userdata) { - if (udev == NULL) - return; - udev->userdata = userdata; +void udev_set_userdata(struct udev *udev, void *userdata) +{ + if (udev == NULL) + return; + udev->userdata = userdata; } /** @@ -96,94 +98,100 @@ void udev_set_userdata(struct udev *udev, void *userdata) { * * Returns: a new udev library context **/ -struct udev *udev_new(void) { - struct udev *udev; - _cleanup_fclose_ FILE *f = NULL; +struct udev *udev_new(void) +{ + struct udev *udev; + _cleanup_fclose_ FILE *f = NULL; - udev = new0(struct udev, 1); - if (udev == NULL) - return NULL; - udev->refcount = 1; + udev = new0(struct udev, 1); + if (udev == NULL) + return NULL; + udev->refcount = 1; - f = fopen("/etc/udev/udev.conf", "re"); - if (f != NULL) { - char line[UTIL_LINE_SIZE]; - unsigned line_nr = 0; + f = fopen("/etc/udev/udev.conf", "re"); + if (f != NULL) { + char line[UTIL_LINE_SIZE]; + unsigned line_nr = 0; - while (fgets(line, sizeof(line), f)) { - size_t len; - char *key; - char *val; + while (fgets(line, sizeof(line), f)) { + size_t len; + char *key; + char *val; - line_nr++; + line_nr++; - /* find key */ - key = line; - while (isspace(key[0])) - key++; + /* find key */ + key = line; + while (isspace(key[0])) + key++; - /* comment or empty line */ - if (key[0] == '#' || key[0] == '\0') - continue; + /* comment or empty line */ + if (key[0] == '#' || key[0] == '\0') + continue; - /* split key/value */ - val = strchr(key, '='); - if (val == NULL) { - log_debug("/etc/udev/udev.conf:%u: missing assignment, skipping line.", line_nr); - continue; - } - val[0] = '\0'; - val++; + /* split key/value */ + val = strchr(key, '='); + if (val == NULL) { + log_debug + ("/etc/udev/udev.conf:%u: missing assignment, skipping line.", + line_nr); + continue; + } + val[0] = '\0'; + val++; - /* find value */ - while (isspace(val[0])) - val++; + /* find value */ + while (isspace(val[0])) + val++; - /* terminate key */ - len = strlen(key); - if (len == 0) - continue; - while (isspace(key[len-1])) - len--; - key[len] = '\0'; + /* terminate key */ + len = strlen(key); + if (len == 0) + continue; + while (isspace(key[len - 1])) + len--; + key[len] = '\0'; - /* terminate value */ - len = strlen(val); - if (len == 0) - continue; - while (isspace(val[len-1])) - len--; - val[len] = '\0'; + /* terminate value */ + len = strlen(val); + if (len == 0) + continue; + while (isspace(val[len - 1])) + len--; + val[len] = '\0'; - if (len == 0) - continue; + if (len == 0) + continue; - /* unquote */ - if (val[0] == '"' || val[0] == '\'') { - if (val[len-1] != val[0]) { - log_debug("/etc/udev/udev.conf:%u: inconsistent quoting, skipping line.", line_nr); - continue; - } - val[len-1] = '\0'; - val++; - } + /* unquote */ + if (val[0] == '"' || val[0] == '\'') { + if (val[len - 1] != val[0]) { + log_debug + ("/etc/udev/udev.conf:%u: inconsistent quoting, skipping line.", + line_nr); + continue; + } + val[len - 1] = '\0'; + val++; + } - if (streq(key, "udev_log")) { - int prio; + if (streq(key, "udev_log")) { + int prio; - prio = util_log_priority(val); - if (prio < 0) { - log_debug("/etc/udev/udev.conf:%u: invalid log level '%s', ignoring.", line_nr, val); - } - else { - log_set_max_level(prio); - } - continue; - } - } - } + prio = util_log_priority(val); + if (prio < 0) { + log_debug + ("/etc/udev/udev.conf:%u: invalid log level '%s', ignoring.", + line_nr, val); + } else { + log_set_max_level(prio); + } + continue; + } + } + } - return udev; + return udev; } /** @@ -194,11 +202,12 @@ struct udev *udev_new(void) { * * Returns: the passed udev library context **/ -struct udev *udev_ref(struct udev *udev) { - if (udev == NULL) - return NULL; - udev->refcount++; - return udev; +struct udev *udev_ref(struct udev *udev) +{ + if (udev == NULL) + return NULL; + udev->refcount++; + return udev; } /** @@ -210,14 +219,15 @@ struct udev *udev_ref(struct udev *udev) { * * Returns: the passed udev library context if it has still an active reference, or #NULL otherwise. **/ -struct udev *udev_unref(struct udev *udev) { - if (udev == NULL) - return NULL; - udev->refcount--; - if (udev->refcount > 0) - return udev; - free(udev); - return NULL; +struct udev *udev_unref(struct udev *udev) +{ + if (udev == NULL) + return NULL; + udev->refcount--; + if (udev->refcount > 0) + return udev; + free(udev); + return NULL; } /** @@ -229,10 +239,12 @@ struct udev *udev_unref(struct udev *udev) { * **/ void udev_set_log_fn(struct udev *udev, - void (*log_fn)(struct udev *udev, - int priority, const char *file, int line, const char *fn, - const char *format, va_list args)) { - return; + void (*log_fn) (struct udev * udev, + int priority, const char *file, int line, + const char *fn, const char *format, + va_list args)) +{ + return; } /** @@ -242,8 +254,9 @@ void udev_set_log_fn(struct udev *udev, * This function is deprecated. * **/ -int udev_get_log_priority(struct udev *udev) { - return log_get_max_level(); +int udev_get_log_priority(struct udev *udev) +{ + return log_get_max_level(); } /** @@ -254,6 +267,7 @@ int udev_get_log_priority(struct udev *udev) { * This function is deprecated. * **/ -void udev_set_log_priority(struct udev *udev, int priority) { - log_set_max_level(priority); +void udev_set_log_priority(struct udev *udev, int priority) +{ + log_set_max_level(priority); } diff --git a/libudev-compat/libudev.h b/libudev-compat/libudev.h index b1d3a16..4ffb364 100644 --- a/libudev-compat/libudev.h +++ b/libudev-compat/libudev.h @@ -45,29 +45,36 @@ extern "C" { * allows custom logging */ -struct udev; -struct udev *udev_ref(struct udev *udev); -struct udev *udev_unref(struct udev *udev); -struct udev *udev_new(void); -void udev_set_log_fn(struct udev *udev, - void (*log_fn)(struct udev *udev, - int priority, const char *file, int line, const char *fn, - const char *format, va_list args)); -int udev_get_log_priority(struct udev *udev); -void udev_set_log_priority(struct udev *udev, int priority); -void *udev_get_userdata(struct udev *udev); -void udev_set_userdata(struct udev *udev, void *userdata); + struct udev; + struct udev *udev_ref(struct udev *udev); + struct udev *udev_unref(struct udev *udev); + struct udev *udev_new(void); + void udev_set_log_fn(struct udev *udev, + void (*log_fn) (struct udev * udev, + int priority, const char *file, + int line, const char *fn, + const char *format, va_list args)); + int udev_get_log_priority(struct udev *udev); + void udev_set_log_priority(struct udev *udev, int priority); + void *udev_get_userdata(struct udev *udev); + void udev_set_userdata(struct udev *udev, void *userdata); /* * udev_list * * access to libudev generated lists */ -struct udev_list_entry; -struct udev_list_entry *udev_list_entry_get_next(struct udev_list_entry *list_entry); -struct udev_list_entry *udev_list_entry_get_by_name(struct udev_list_entry *list_entry, const char *name); -const char *udev_list_entry_get_name(struct udev_list_entry *list_entry); -const char *udev_list_entry_get_value(struct udev_list_entry *list_entry); + struct udev_list_entry; + struct udev_list_entry *udev_list_entry_get_next(struct udev_list_entry + *list_entry); + struct udev_list_entry *udev_list_entry_get_by_name(struct + udev_list_entry + *list_entry, + const char *name); + const char *udev_list_entry_get_name(struct udev_list_entry + *list_entry); + const char *udev_list_entry_get_value(struct udev_list_entry + *list_entry); /** * udev_list_entry_foreach: * @list_entry: entry to store the current position @@ -85,134 +92,217 @@ const char *udev_list_entry_get_value(struct udev_list_entry *list_entry); * * access to sysfs/kernel devices */ -struct udev_device; -struct udev_device *udev_device_ref(struct udev_device *udev_device); -struct udev_device *udev_device_unref(struct udev_device *udev_device); -struct udev *udev_device_get_udev(struct udev_device *udev_device); -struct udev_device *udev_device_new_from_syspath(struct udev *udev, const char *syspath); -struct udev_device *udev_device_new_from_devnum(struct udev *udev, char type, dev_t devnum); -struct udev_device *udev_device_new_from_subsystem_sysname(struct udev *udev, const char *subsystem, const char *sysname); -struct udev_device *udev_device_new_from_device_id(struct udev *udev, const char *id); -struct udev_device *udev_device_new_from_environment(struct udev *udev); + struct udev_device; + struct udev_device *udev_device_ref(struct udev_device *udev_device); + struct udev_device *udev_device_unref(struct udev_device *udev_device); + struct udev *udev_device_get_udev(struct udev_device *udev_device); + struct udev_device *udev_device_new_from_syspath(struct udev *udev, + const char *syspath); + struct udev_device *udev_device_new_from_devnum(struct udev *udev, + char type, + dev_t devnum); + struct udev_device *udev_device_new_from_subsystem_sysname(struct udev + *udev, + const char + *subsystem, + const char + *sysname); + struct udev_device *udev_device_new_from_device_id(struct udev *udev, + const char *id); + struct udev_device *udev_device_new_from_environment(struct udev *udev); /* udev_device_get_parent_*() does not take a reference on the returned device, it is automatically unref'd with the parent */ -struct udev_device *udev_device_get_parent(struct udev_device *udev_device); -struct udev_device *udev_device_get_parent_with_subsystem_devtype(struct udev_device *udev_device, - const char *subsystem, const char *devtype); + struct udev_device *udev_device_get_parent(struct udev_device + *udev_device); + struct udev_device *udev_device_get_parent_with_subsystem_devtype(struct + udev_device + *udev_device, + const + char + *subsystem, + const + char + *devtype); /* retrieve device properties */ -const char *udev_device_get_devpath(struct udev_device *udev_device); -const char *udev_device_get_subsystem(struct udev_device *udev_device); -const char *udev_device_get_devtype(struct udev_device *udev_device); -const char *udev_device_get_syspath(struct udev_device *udev_device); -const char *udev_device_get_sysname(struct udev_device *udev_device); -const char *udev_device_get_sysnum(struct udev_device *udev_device); -const char *udev_device_get_devnode(struct udev_device *udev_device); -int udev_device_get_is_initialized(struct udev_device *udev_device); -struct udev_list_entry *udev_device_get_devlinks_list_entry(struct udev_device *udev_device); -struct udev_list_entry *udev_device_get_properties_list_entry(struct udev_device *udev_device); -struct udev_list_entry *udev_device_get_tags_list_entry(struct udev_device *udev_device); -struct udev_list_entry *udev_device_get_sysattr_list_entry(struct udev_device *udev_device); -const char *udev_device_get_property_value(struct udev_device *udev_device, const char *key); -const char *udev_device_get_driver(struct udev_device *udev_device); -dev_t udev_device_get_devnum(struct udev_device *udev_device); -const char *udev_device_get_action(struct udev_device *udev_device); -unsigned long long int udev_device_get_seqnum(struct udev_device *udev_device); -unsigned long long int udev_device_get_usec_since_initialized(struct udev_device *udev_device); -const char *udev_device_get_sysattr_value(struct udev_device *udev_device, const char *sysattr); -int udev_device_set_sysattr_value(struct udev_device *udev_device, const char *sysattr, char *value); -int udev_device_has_tag(struct udev_device *udev_device, const char *tag); + const char *udev_device_get_devpath(struct udev_device *udev_device); + const char *udev_device_get_subsystem(struct udev_device *udev_device); + const char *udev_device_get_devtype(struct udev_device *udev_device); + const char *udev_device_get_syspath(struct udev_device *udev_device); + const char *udev_device_get_sysname(struct udev_device *udev_device); + const char *udev_device_get_sysnum(struct udev_device *udev_device); + const char *udev_device_get_devnode(struct udev_device *udev_device); + int udev_device_get_is_initialized(struct udev_device *udev_device); + struct udev_list_entry *udev_device_get_devlinks_list_entry(struct + udev_device + *udev_device); + struct udev_list_entry *udev_device_get_properties_list_entry(struct + udev_device + *udev_device); + struct udev_list_entry *udev_device_get_tags_list_entry(struct + udev_device + *udev_device); + struct udev_list_entry *udev_device_get_sysattr_list_entry(struct + udev_device + *udev_device); + const char *udev_device_get_property_value(struct udev_device + *udev_device, + const char *key); + const char *udev_device_get_driver(struct udev_device *udev_device); + dev_t udev_device_get_devnum(struct udev_device *udev_device); + const char *udev_device_get_action(struct udev_device *udev_device); + unsigned long long int udev_device_get_seqnum(struct udev_device + *udev_device); + unsigned long long int udev_device_get_usec_since_initialized(struct + udev_device + *udev_device); + const char *udev_device_get_sysattr_value(struct udev_device + *udev_device, + const char *sysattr); + int udev_device_set_sysattr_value(struct udev_device *udev_device, + const char *sysattr, char *value); + int udev_device_has_tag(struct udev_device *udev_device, + const char *tag); /* * udev_monitor * * access to kernel uevents and udev events */ -struct udev_monitor; -struct udev_monitor *udev_monitor_ref(struct udev_monitor *udev_monitor); -struct udev_monitor *udev_monitor_unref(struct udev_monitor *udev_monitor); -struct udev *udev_monitor_get_udev(struct udev_monitor *udev_monitor); + struct udev_monitor; + struct udev_monitor *udev_monitor_ref(struct udev_monitor + *udev_monitor); + struct udev_monitor *udev_monitor_unref(struct udev_monitor + *udev_monitor); + struct udev *udev_monitor_get_udev(struct udev_monitor *udev_monitor); /* kernel and udev generated events over netlink */ -struct udev_monitor *udev_monitor_new_from_netlink(struct udev *udev, const char *name); + struct udev_monitor *udev_monitor_new_from_netlink(struct udev *udev, + const char *name); /* bind socket */ -int udev_monitor_enable_receiving(struct udev_monitor *udev_monitor); -int udev_monitor_set_receive_buffer_size(struct udev_monitor *udev_monitor, int size); -int udev_monitor_get_fd(struct udev_monitor *udev_monitor); -struct udev_device *udev_monitor_receive_device(struct udev_monitor *udev_monitor); + int udev_monitor_enable_receiving(struct udev_monitor *udev_monitor); + int udev_monitor_set_receive_buffer_size(struct udev_monitor + *udev_monitor, int size); + int udev_monitor_get_fd(struct udev_monitor *udev_monitor); + struct udev_device *udev_monitor_receive_device(struct udev_monitor + *udev_monitor); /* in-kernel socket filters to select messages that get delivered to a listener */ -int udev_monitor_filter_add_match_subsystem_devtype(struct udev_monitor *udev_monitor, - const char *subsystem, const char *devtype); -int udev_monitor_filter_add_match_tag(struct udev_monitor *udev_monitor, const char *tag); -int udev_monitor_filter_update(struct udev_monitor *udev_monitor); -int udev_monitor_filter_remove(struct udev_monitor *udev_monitor); + int udev_monitor_filter_add_match_subsystem_devtype(struct udev_monitor + *udev_monitor, + const char + *subsystem, + const char + *devtype); + int udev_monitor_filter_add_match_tag(struct udev_monitor *udev_monitor, + const char *tag); + int udev_monitor_filter_update(struct udev_monitor *udev_monitor); + int udev_monitor_filter_remove(struct udev_monitor *udev_monitor); /* * udev_enumerate * * search sysfs for specific devices and provide a sorted list */ -struct udev_enumerate; -struct udev_enumerate *udev_enumerate_ref(struct udev_enumerate *udev_enumerate); -struct udev_enumerate *udev_enumerate_unref(struct udev_enumerate *udev_enumerate); -struct udev *udev_enumerate_get_udev(struct udev_enumerate *udev_enumerate); -struct udev_enumerate *udev_enumerate_new(struct udev *udev); + struct udev_enumerate; + struct udev_enumerate *udev_enumerate_ref(struct udev_enumerate + *udev_enumerate); + struct udev_enumerate *udev_enumerate_unref(struct udev_enumerate + *udev_enumerate); + struct udev *udev_enumerate_get_udev(struct udev_enumerate + *udev_enumerate); + struct udev_enumerate *udev_enumerate_new(struct udev *udev); /* device properties filter */ -int udev_enumerate_add_match_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem); -int udev_enumerate_add_nomatch_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem); -int udev_enumerate_add_match_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value); -int udev_enumerate_add_nomatch_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value); -int udev_enumerate_add_match_property(struct udev_enumerate *udev_enumerate, const char *property, const char *value); -int udev_enumerate_add_match_sysname(struct udev_enumerate *udev_enumerate, const char *sysname); -int udev_enumerate_add_match_tag(struct udev_enumerate *udev_enumerate, const char *tag); -int udev_enumerate_add_match_parent(struct udev_enumerate *udev_enumerate, struct udev_device *parent); -int udev_enumerate_add_match_is_initialized(struct udev_enumerate *udev_enumerate); -int udev_enumerate_add_syspath(struct udev_enumerate *udev_enumerate, const char *syspath); + int udev_enumerate_add_match_subsystem(struct udev_enumerate + *udev_enumerate, + const char *subsystem); + int udev_enumerate_add_nomatch_subsystem(struct udev_enumerate + *udev_enumerate, + const char *subsystem); + int udev_enumerate_add_match_sysattr(struct udev_enumerate + *udev_enumerate, + const char *sysattr, + const char *value); + int udev_enumerate_add_nomatch_sysattr(struct udev_enumerate + *udev_enumerate, + const char *sysattr, + const char *value); + int udev_enumerate_add_match_property(struct udev_enumerate + *udev_enumerate, + const char *property, + const char *value); + int udev_enumerate_add_match_sysname(struct udev_enumerate + *udev_enumerate, + const char *sysname); + int udev_enumerate_add_match_tag(struct udev_enumerate *udev_enumerate, + const char *tag); + int udev_enumerate_add_match_parent(struct udev_enumerate + *udev_enumerate, + struct udev_device *parent); + int udev_enumerate_add_match_is_initialized(struct udev_enumerate + *udev_enumerate); + int udev_enumerate_add_syspath(struct udev_enumerate *udev_enumerate, + const char *syspath); /* run enumeration with active filters */ -int udev_enumerate_scan_devices(struct udev_enumerate *udev_enumerate); -int udev_enumerate_scan_subsystems(struct udev_enumerate *udev_enumerate); + int udev_enumerate_scan_devices(struct udev_enumerate *udev_enumerate); + int udev_enumerate_scan_subsystems(struct udev_enumerate + *udev_enumerate); /* return device list */ -struct udev_list_entry *udev_enumerate_get_list_entry(struct udev_enumerate *udev_enumerate); + struct udev_list_entry *udev_enumerate_get_list_entry(struct + udev_enumerate + *udev_enumerate); /* * udev_queue * * access to the currently running udev events */ -struct udev_queue; -struct udev_queue *udev_queue_ref(struct udev_queue *udev_queue); -struct udev_queue *udev_queue_unref(struct udev_queue *udev_queue); -struct udev *udev_queue_get_udev(struct udev_queue *udev_queue); -struct udev_queue *udev_queue_new(struct udev *udev); -unsigned long long int udev_queue_get_kernel_seqnum(struct udev_queue *udev_queue); -unsigned long long int udev_queue_get_udev_seqnum(struct udev_queue *udev_queue); -int udev_queue_get_udev_is_active(struct udev_queue *udev_queue); -int udev_queue_get_queue_is_empty(struct udev_queue *udev_queue); -int udev_queue_get_seqnum_is_finished(struct udev_queue *udev_queue, unsigned long long int seqnum); -int udev_queue_get_seqnum_sequence_is_finished(struct udev_queue *udev_queue, - unsigned long long int start, unsigned long long int end); -int udev_queue_get_fd(struct udev_queue *udev_queue); -int udev_queue_flush(struct udev_queue *udev_queue); -struct udev_list_entry *udev_queue_get_queued_list_entry(struct udev_queue *udev_queue); + struct udev_queue; + struct udev_queue *udev_queue_ref(struct udev_queue *udev_queue); + struct udev_queue *udev_queue_unref(struct udev_queue *udev_queue); + struct udev *udev_queue_get_udev(struct udev_queue *udev_queue); + struct udev_queue *udev_queue_new(struct udev *udev); + unsigned long long int udev_queue_get_kernel_seqnum(struct udev_queue + *udev_queue); + unsigned long long int udev_queue_get_udev_seqnum(struct udev_queue + *udev_queue); + int udev_queue_get_udev_is_active(struct udev_queue *udev_queue); + int udev_queue_get_queue_is_empty(struct udev_queue *udev_queue); + int udev_queue_get_seqnum_is_finished(struct udev_queue *udev_queue, + unsigned long long int seqnum); + int udev_queue_get_seqnum_sequence_is_finished(struct udev_queue + *udev_queue, + unsigned long long int + start, + unsigned long long int + end); + int udev_queue_get_fd(struct udev_queue *udev_queue); + int udev_queue_flush(struct udev_queue *udev_queue); + struct udev_list_entry *udev_queue_get_queued_list_entry(struct + udev_queue + *udev_queue); /* * udev_hwdb * * access to the static hardware properties database */ -struct udev_hwdb; -struct udev_hwdb *udev_hwdb_new(struct udev *udev); -struct udev_hwdb *udev_hwdb_ref(struct udev_hwdb *hwdb); -struct udev_hwdb *udev_hwdb_unref(struct udev_hwdb *hwdb); -struct udev_list_entry *udev_hwdb_get_properties_list_entry(struct udev_hwdb *hwdb, const char *modalias, unsigned int flags); + struct udev_hwdb; + struct udev_hwdb *udev_hwdb_new(struct udev *udev); + struct udev_hwdb *udev_hwdb_ref(struct udev_hwdb *hwdb); + struct udev_hwdb *udev_hwdb_unref(struct udev_hwdb *hwdb); + struct udev_list_entry *udev_hwdb_get_properties_list_entry(struct + udev_hwdb + *hwdb, + const char + *modalias, + unsigned int + flags); /* * udev_util * * udev specific utilities */ -int udev_util_encode_string(const char *str, char *str_enc, size_t len); - + int udev_util_encode_string(const char *str, char *str_enc, size_t len); #ifdef __cplusplus -} /* extern "C" */ +} /* extern "C" */ #endif - #endif diff --git a/libudev-compat/log.c b/libudev-compat/log.c index 7ee5b7f..1a4a183 100644 --- a/libudev-compat/log.c +++ b/libudev-compat/log.c @@ -30,45 +30,50 @@ // undefined by default... static int log_max_level = -1; -void log_set_max_level(int level) { - // don't allow invalid log levels (only these methods can do so) - assert((level & LOG_PRIMASK) == level); +void log_set_max_level(int level) +{ + // don't allow invalid log levels (only these methods can do so) + assert((level & LOG_PRIMASK) == level); - log_max_level = level; + log_max_level = level; } -static void log_check_disabled(void) { - - if( log_max_level == -1 ) { - - // undefined default max log level - char* libudev_compat_loglevel_str = secure_getenv( LIBUDEV_COMPAT_DEBUG_ENVAR ); - if( libudev_compat_loglevel_str != NULL && strlen(libudev_compat_loglevel_str) > 0 ) { - - // enable debugging - log_max_level = LIBUDEV_COMPAT_DEBUG; - } - else { - - // disable debugging - log_max_level = LIBUDEV_COMPAT_NO_DEBUG; - } - } +static void log_check_disabled(void) +{ + + if (log_max_level == -1) { + + // undefined default max log level + char *libudev_compat_loglevel_str = + secure_getenv(LIBUDEV_COMPAT_DEBUG_ENVAR); + if (libudev_compat_loglevel_str != NULL + && strlen(libudev_compat_loglevel_str) > 0) { + + // enable debugging + log_max_level = LIBUDEV_COMPAT_DEBUG; + } else { + + // disable debugging + log_max_level = LIBUDEV_COMPAT_NO_DEBUG; + } + } } -int log_get_max_level(void) { - - log_check_disabled(); - return log_max_level; +int log_get_max_level(void) +{ + + log_check_disabled(); + return log_max_level; } -void log_impl( int level, char const* fmt, ... ) { - - log_check_disabled(); - if( level <= log_max_level ) { - va_list args; - va_start( args, fmt ); - vfprintf( stderr, fmt, args ); - va_end( args ); - } +void log_impl(int level, char const *fmt, ...) +{ + + log_check_disabled(); + if (level <= log_max_level) { + va_list args; + va_start(args, fmt); + vfprintf(stderr, fmt, args); + va_end(args); + } } diff --git a/libudev-compat/log.h b/libudev-compat/log.h index 3439690..0bb6641 100644 --- a/libudev-compat/log.h +++ b/libudev-compat/log.h @@ -41,6 +41,6 @@ void log_set_max_level(int level); int log_get_max_level(void); -void log_impl( int level, char const* fmt, ... ); - +void log_impl(int level, char const *fmt, ...); + #endif diff --git a/libudev-compat/macro.h b/libudev-compat/macro.h index 402652a..05ea59d 100644 --- a/libudev-compat/macro.h +++ b/libudev-compat/macro.h @@ -112,23 +112,25 @@ #define ALIGN4_PTR(p) ((void*) ALIGN4((unsigned long) (p))) #define ALIGN8_PTR(p) ((void*) ALIGN8((unsigned long) (p))) -static inline size_t ALIGN_TO(size_t l, size_t ali) { - return ((l + ali - 1) & ~(ali - 1)); +static inline size_t ALIGN_TO(size_t l, size_t ali) +{ + return ((l + ali - 1) & ~(ali - 1)); } #define ALIGN_TO_PTR(p, ali) ((void*) ALIGN_TO((unsigned long) (p), (ali))) /* align to next higher power-of-2 (except for: 0 => 0, overflow => 0) */ -static inline unsigned long ALIGN_POWER2(unsigned long u) { - /* clz(0) is undefined */ - if (u == 1) - return 1; +static inline unsigned long ALIGN_POWER2(unsigned long u) +{ + /* clz(0) is undefined */ + if (u == 1) + return 1; - /* left-shift overflow is undefined */ - if (__builtin_clzl(u - 1UL) < 1) - return 0; + /* left-shift overflow is undefined */ + if (__builtin_clzl(u - 1UL) < 1) + return 0; - return 1UL << (sizeof(u) * 8 - __builtin_clzl(u - 1UL)); + return 1UL << (sizeof(u) * 8 - __builtin_clzl(u - 1UL)); } #define ELEMENTSOF(x) (sizeof(x)/sizeof((x)[0])) @@ -311,32 +313,34 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) { _i->iov_len = strlen(_s); \ } while(false) -static inline size_t IOVEC_TOTAL_SIZE(const struct iovec *i, unsigned n) { - unsigned j; - size_t r = 0; +static inline size_t IOVEC_TOTAL_SIZE(const struct iovec *i, unsigned n) +{ + unsigned j; + size_t r = 0; - for (j = 0; j < n; j++) - r += i[j].iov_len; + for (j = 0; j < n; j++) + r += i[j].iov_len; - return r; + return r; } -static inline size_t IOVEC_INCREMENT(struct iovec *i, unsigned n, size_t k) { - unsigned j; +static inline size_t IOVEC_INCREMENT(struct iovec *i, unsigned n, size_t k) +{ + unsigned j; - for (j = 0; j < n; j++) { - size_t sub; + for (j = 0; j < n; j++) { + size_t sub; - if (_unlikely_(k <= 0)) - break; + if (_unlikely_(k <= 0)) + break; - sub = MIN(i[j].iov_len, k); - i[j].iov_len -= sub; - i[j].iov_base = (uint8_t*) i[j].iov_base + sub; - k -= sub; - } + sub = MIN(i[j].iov_len, k); + i[j].iov_len -= sub; + i[j].iov_base = (uint8_t *) i[j].iov_base + sub; + k -= sub; + } - return k; + return k; } #define VA_FORMAT_ADVANCE(format, ap) \ @@ -387,7 +391,7 @@ do { \ /* Because statfs.t_type can be int on some architectures, we have to cast * the const magic to the type, otherwise the compiler warns about * signed/unsigned comparison, because the magic can be 32 bit unsigned. - */ + */ #define F_TYPE_EQUAL(a, b) (a == (typeof(a)) b) /* Returns the number of chars needed to format variables of the @@ -469,4 +473,4 @@ do { \ #include "log.h" -#endif \ No newline at end of file +#endif diff --git a/libudev-compat/mempool.c b/libudev-compat/mempool.c index 718d768..ca5cfde 100644 --- a/libudev-compat/mempool.c +++ b/libudev-compat/mempool.c @@ -29,79 +29,85 @@ #include "util.h" struct pool { - struct pool *next; - unsigned n_tiles; - unsigned n_used; + struct pool *next; + unsigned n_tiles; + unsigned n_used; }; -void* mempool_alloc_tile(struct mempool *mp) { - unsigned i; +void *mempool_alloc_tile(struct mempool *mp) +{ + unsigned i; - /* When a tile is released we add it to the list and simply - * place the next pointer at its offset 0. */ + /* When a tile is released we add it to the list and simply + * place the next pointer at its offset 0. */ - assert(mp->tile_size >= sizeof(void*)); - assert(mp->at_least > 0); + assert(mp->tile_size >= sizeof(void *)); + assert(mp->at_least > 0); - if (mp->freelist) { - void *r; + if (mp->freelist) { + void *r; - r = mp->freelist; - mp->freelist = * (void**) mp->freelist; - return r; - } + r = mp->freelist; + mp->freelist = *(void **)mp->freelist; + return r; + } - if (_unlikely_(!mp->first_pool) || - _unlikely_(mp->first_pool->n_used >= mp->first_pool->n_tiles)) { - unsigned n; - size_t size; - struct pool *p; + if (_unlikely_(!mp->first_pool) || + _unlikely_(mp->first_pool->n_used >= mp->first_pool->n_tiles)) { + unsigned n; + size_t size; + struct pool *p; - n = mp->first_pool ? mp->first_pool->n_tiles : 0; - n = MAX(mp->at_least, n * 2); - size = PAGE_ALIGN(ALIGN(sizeof(struct pool)) + n*mp->tile_size); - n = (size - ALIGN(sizeof(struct pool))) / mp->tile_size; + n = mp->first_pool ? mp->first_pool->n_tiles : 0; + n = MAX(mp->at_least, n * 2); + size = + PAGE_ALIGN(ALIGN(sizeof(struct pool)) + n * mp->tile_size); + n = (size - ALIGN(sizeof(struct pool))) / mp->tile_size; - p = malloc(size); - if (!p) - return NULL; + p = malloc(size); + if (!p) + return NULL; - p->next = mp->first_pool; - p->n_tiles = n; - p->n_used = 0; + p->next = mp->first_pool; + p->n_tiles = n; + p->n_used = 0; - mp->first_pool = p; - } + mp->first_pool = p; + } - i = mp->first_pool->n_used++; + i = mp->first_pool->n_used++; - return ((uint8_t*) mp->first_pool) + ALIGN(sizeof(struct pool)) + i*mp->tile_size; + return ((uint8_t *) mp->first_pool) + ALIGN(sizeof(struct pool)) + + i * mp->tile_size; } -void* mempool_alloc0_tile(struct mempool *mp) { - void *p; +void *mempool_alloc0_tile(struct mempool *mp) +{ + void *p; - p = mempool_alloc_tile(mp); - if (p) - memzero(p, mp->tile_size); - return p; + p = mempool_alloc_tile(mp); + if (p) + memzero(p, mp->tile_size); + return p; } -void mempool_free_tile(struct mempool *mp, void *p) { - * (void**) p = mp->freelist; - mp->freelist = p; +void mempool_free_tile(struct mempool *mp, void *p) +{ + *(void **)p = mp->freelist; + mp->freelist = p; } #ifdef VALGRIND -void mempool_drop(struct mempool *mp) { - struct pool *p = mp->first_pool; - while (p) { - struct pool *n; - n = p->next; - free(p); - p = n; - } +void mempool_drop(struct mempool *mp) +{ + struct pool *p = mp->first_pool; + while (p) { + struct pool *n; + n = p->next; + free(p); + p = n; + } } #endif diff --git a/libudev-compat/mempool.h b/libudev-compat/mempool.h index 1484ca7..b5f6860 100644 --- a/libudev-compat/mempool.h +++ b/libudev-compat/mempool.h @@ -32,14 +32,14 @@ struct pool; struct mempool { - struct pool *first_pool; - void *freelist; - size_t tile_size; - unsigned at_least; + struct pool *first_pool; + void *freelist; + size_t tile_size; + unsigned at_least; }; -void* mempool_alloc_tile(struct mempool *mp); -void* mempool_alloc0_tile(struct mempool *mp); +void *mempool_alloc_tile(struct mempool *mp); +void *mempool_alloc0_tile(struct mempool *mp); void mempool_free_tile(struct mempool *mp, void *p); #define DEFINE_MEMPOOL(pool_name, tile_type, alloc_at_least) \ @@ -48,9 +48,8 @@ struct mempool pool_name = { \ .at_least = alloc_at_least, \ } - #ifdef VALGRIND void mempool_drop(struct mempool *mp); #endif -#endif \ No newline at end of file +#endif diff --git a/libudev-compat/mkdir.c b/libudev-compat/mkdir.c index 0382274..4aec9cc 100644 --- a/libudev-compat/mkdir.c +++ b/libudev-compat/mkdir.c @@ -29,136 +29,144 @@ #include "util.h" #include "mkdir.h" -char* path_startswith(const char *path, const char *prefix) { - assert(path); - assert(prefix); +char *path_startswith(const char *path, const char *prefix) +{ + assert(path); + assert(prefix); - if ((path[0] == '/') != (prefix[0] == '/')) - return NULL; + if ((path[0] == '/') != (prefix[0] == '/')) + return NULL; - for (;;) { - size_t a, b; + for (;;) { + size_t a, b; - path += strspn(path, "/"); - prefix += strspn(prefix, "/"); + path += strspn(path, "/"); + prefix += strspn(prefix, "/"); - if (*prefix == 0) - return (char*) path; + if (*prefix == 0) + return (char *)path; - if (*path == 0) - return NULL; + if (*path == 0) + return NULL; - a = strcspn(path, "/"); - b = strcspn(prefix, "/"); + a = strcspn(path, "/"); + b = strcspn(prefix, "/"); - if (a != b) - return NULL; + if (a != b) + return NULL; - if (memcmp(path, prefix, a) != 0) - return NULL; + if (memcmp(path, prefix, a) != 0) + return NULL; - path += a; - prefix += b; - } + path += a; + prefix += b; + } } +int mkdir_safe_internal(const char *path, mode_t mode, uid_t uid, gid_t gid, + mkdir_func_t _mkdir) +{ + struct stat st; -int mkdir_safe_internal(const char *path, mode_t mode, uid_t uid, gid_t gid, mkdir_func_t _mkdir) { - struct stat st; + if (_mkdir(path, mode) >= 0) + if (chmod_and_chown(path, mode, uid, gid) < 0) + return -errno; - if (_mkdir(path, mode) >= 0) - if (chmod_and_chown(path, mode, uid, gid) < 0) - return -errno; + if (lstat(path, &st) < 0) + return -errno; - if (lstat(path, &st) < 0) - return -errno; + if ((st.st_mode & 0007) > (mode & 0007) || + (st.st_mode & 0070) > (mode & 0070) || + (st.st_mode & 0700) > (mode & 0700) || + (uid != UID_INVALID && st.st_uid != uid) || + (gid != GID_INVALID && st.st_gid != gid) || !S_ISDIR(st.st_mode)) { + errno = EEXIST; + return -errno; + } - if ((st.st_mode & 0007) > (mode & 0007) || - (st.st_mode & 0070) > (mode & 0070) || - (st.st_mode & 0700) > (mode & 0700) || - (uid != UID_INVALID && st.st_uid != uid) || - (gid != GID_INVALID && st.st_gid != gid) || - !S_ISDIR(st.st_mode)) { - errno = EEXIST; - return -errno; - } - - return 0; + return 0; } -int mkdir_safe(const char *path, mode_t mode, uid_t uid, gid_t gid) { - return mkdir_safe_internal(path, mode, uid, gid, mkdir); +int mkdir_safe(const char *path, mode_t mode, uid_t uid, gid_t gid) +{ + return mkdir_safe_internal(path, mode, uid, gid, mkdir); } -int mkdir_parents_internal(const char *prefix, const char *path, mode_t mode, mkdir_func_t _mkdir) { - const char *p, *e; - int r; +int mkdir_parents_internal(const char *prefix, const char *path, mode_t mode, + mkdir_func_t _mkdir) +{ + const char *p, *e; + int r; - assert(path); + assert(path); - if (prefix && !path_startswith(path, prefix)) - return -ENOTDIR; + if (prefix && !path_startswith(path, prefix)) + return -ENOTDIR; - /* return immediately if directory exists */ - e = strrchr(path, '/'); - if (!e) - return -EINVAL; + /* return immediately if directory exists */ + e = strrchr(path, '/'); + if (!e) + return -EINVAL; - if (e == path) - return 0; + if (e == path) + return 0; - p = strndupa(path, e - path); - r = is_dir(p, true); - if (r > 0) - return 0; - if (r == 0) - return -ENOTDIR; + p = strndupa(path, e - path); + r = is_dir(p, true); + if (r > 0) + return 0; + if (r == 0) + return -ENOTDIR; - /* create every parent directory in the path, except the last component */ - p = path + strspn(path, "/"); - for (;;) { - char t[strlen(path) + 1]; + /* create every parent directory in the path, except the last component */ + p = path + strspn(path, "/"); + for (;;) { + char t[strlen(path) + 1]; - e = p + strcspn(p, "/"); - p = e + strspn(e, "/"); + e = p + strcspn(p, "/"); + p = e + strspn(e, "/"); - /* Is this the last component? If so, then we're - * done */ - if (*p == 0) - return 0; + /* Is this the last component? If so, then we're + * done */ + if (*p == 0) + return 0; - memcpy(t, path, e - path); - t[e-path] = 0; + memcpy(t, path, e - path); + t[e - path] = 0; - if (prefix && path_startswith(prefix, t)) - continue; + if (prefix && path_startswith(prefix, t)) + continue; - r = _mkdir(t, mode); - if (r < 0 && errno != EEXIST) - return -errno; - } + r = _mkdir(t, mode); + if (r < 0 && errno != EEXIST) + return -errno; + } } -int mkdir_parents(const char *path, mode_t mode) { - return mkdir_parents_internal(NULL, path, mode, mkdir); +int mkdir_parents(const char *path, mode_t mode) +{ + return mkdir_parents_internal(NULL, path, mode, mkdir); } -int mkdir_p_internal(const char *prefix, const char *path, mode_t mode, mkdir_func_t _mkdir) { - int r; +int mkdir_p_internal(const char *prefix, const char *path, mode_t mode, + mkdir_func_t _mkdir) +{ + int r; - /* Like mkdir -p */ + /* Like mkdir -p */ - r = mkdir_parents_internal(prefix, path, mode, _mkdir); - if (r < 0) - return r; + r = mkdir_parents_internal(prefix, path, mode, _mkdir); + if (r < 0) + return r; - r = _mkdir(path, mode); - if (r < 0 && (errno != EEXIST || is_dir(path, true) <= 0)) - return -errno; + r = _mkdir(path, mode); + if (r < 0 && (errno != EEXIST || is_dir(path, true) <= 0)) + return -errno; - return 0; + return 0; } -int mkdir_p(const char *path, mode_t mode) { - return mkdir_p_internal(NULL, path, mode, mkdir); +int mkdir_p(const char *path, mode_t mode) +{ + return mkdir_p_internal(NULL, path, mode, mkdir); } diff --git a/libudev-compat/mkdir.h b/libudev-compat/mkdir.h index 0516777..3e14dc4 100644 --- a/libudev-compat/mkdir.h +++ b/libudev-compat/mkdir.h @@ -39,9 +39,12 @@ int mkdir_parents(const char *path, mode_t mode); int mkdir_p(const char *path, mode_t mode); /* internally used */ -typedef int (*mkdir_func_t)(const char *pathname, mode_t mode); -int mkdir_safe_internal(const char *path, mode_t mode, uid_t uid, gid_t gid, mkdir_func_t _mkdir); -int mkdir_parents_internal(const char *prefix, const char *path, mode_t mode, mkdir_func_t _mkdir); -int mkdir_p_internal(const char *prefix, const char *path, mode_t mode, mkdir_func_t _mkdir); - -#endif \ No newline at end of file +typedef int (*mkdir_func_t) (const char *pathname, mode_t mode); +int mkdir_safe_internal(const char *path, mode_t mode, uid_t uid, gid_t gid, + mkdir_func_t _mkdir); +int mkdir_parents_internal(const char *prefix, const char *path, mode_t mode, + mkdir_func_t _mkdir); +int mkdir_p_internal(const char *prefix, const char *path, mode_t mode, + mkdir_func_t _mkdir); + +#endif diff --git a/libudev-compat/sd-hwdb.c b/libudev-compat/sd-hwdb.c index c69a2ac..f2640b5 100644 --- a/libudev-compat/sd-hwdb.c +++ b/libudev-compat/sd-hwdb.c @@ -46,448 +46,518 @@ #include "hwdb-internal.h" struct sd_hwdb { - RefCount n_ref; - int refcount; + RefCount n_ref; + int refcount; - FILE *f; - struct stat st; - union { - struct trie_header_f *head; - const char *map; - }; + FILE *f; + struct stat st; + union { + struct trie_header_f *head; + const char *map; + }; - char *modalias; + char *modalias; - OrderedHashmap *properties; - Iterator properties_iterator; - bool properties_modified; + OrderedHashmap *properties; + Iterator properties_iterator; + bool properties_modified; }; struct linebuf { - char bytes[LINE_MAX]; - size_t size; - size_t len; + char bytes[LINE_MAX]; + size_t size; + size_t len; }; -static void linebuf_init(struct linebuf *buf) { - buf->size = 0; - buf->len = 0; +static void linebuf_init(struct linebuf *buf) +{ + buf->size = 0; + buf->len = 0; } -static const char *linebuf_get(struct linebuf *buf) { - if (buf->len + 1 >= sizeof(buf->bytes)) - return NULL; - buf->bytes[buf->len] = '\0'; - return buf->bytes; +static const char *linebuf_get(struct linebuf *buf) +{ + if (buf->len + 1 >= sizeof(buf->bytes)) + return NULL; + buf->bytes[buf->len] = '\0'; + return buf->bytes; } -static bool linebuf_add(struct linebuf *buf, const char *s, size_t len) { - if (buf->len + len >= sizeof(buf->bytes)) - return false; - memcpy(buf->bytes + buf->len, s, len); - buf->len += len; - return true; +static bool linebuf_add(struct linebuf *buf, const char *s, size_t len) +{ + if (buf->len + len >= sizeof(buf->bytes)) + return false; + memcpy(buf->bytes + buf->len, s, len); + buf->len += len; + return true; } static bool linebuf_add_char(struct linebuf *buf, char c) { - if (buf->len + 1 >= sizeof(buf->bytes)) - return false; - buf->bytes[buf->len++] = c; - return true; + if (buf->len + 1 >= sizeof(buf->bytes)) + return false; + buf->bytes[buf->len++] = c; + return true; } -static void linebuf_rem(struct linebuf *buf, size_t count) { - assert(buf->len >= count); - buf->len -= count; +static void linebuf_rem(struct linebuf *buf, size_t count) +{ + assert(buf->len >= count); + buf->len -= count; } -static void linebuf_rem_char(struct linebuf *buf) { - linebuf_rem(buf, 1); +static void linebuf_rem_char(struct linebuf *buf) +{ + linebuf_rem(buf, 1); } -static const struct trie_child_entry_f *trie_node_children(sd_hwdb *hwdb, const struct trie_node_f *node) { - return (const struct trie_child_entry_f *)((const char *)node + le64toh(hwdb->head->node_size)); +static const struct trie_child_entry_f *trie_node_children(sd_hwdb * hwdb, + const struct + trie_node_f *node) +{ + return (const struct trie_child_entry_f *)((const char *)node + + le64toh(hwdb->head-> + node_size)); } -static const struct trie_value_entry_f *trie_node_values(sd_hwdb *hwdb, const struct trie_node_f *node) { - const char *base = (const char *)node; +static const struct trie_value_entry_f *trie_node_values(sd_hwdb * hwdb, + const struct + trie_node_f *node) +{ + const char *base = (const char *)node; - base += le64toh(hwdb->head->node_size); - base += node->children_count * le64toh(hwdb->head->child_entry_size); - return (const struct trie_value_entry_f *)base; + base += le64toh(hwdb->head->node_size); + base += node->children_count * le64toh(hwdb->head->child_entry_size); + return (const struct trie_value_entry_f *)base; } -static const struct trie_node_f *trie_node_from_off(sd_hwdb *hwdb, le64_t off) { - return (const struct trie_node_f *)(hwdb->map + le64toh(off)); +static const struct trie_node_f *trie_node_from_off(sd_hwdb * hwdb, le64_t off) +{ + return (const struct trie_node_f *)(hwdb->map + le64toh(off)); } -static const char *trie_string(sd_hwdb *hwdb, le64_t off) { - return hwdb->map + le64toh(off); +static const char *trie_string(sd_hwdb * hwdb, le64_t off) +{ + return hwdb->map + le64toh(off); } -static int trie_children_cmp_f(const void *v1, const void *v2) { - const struct trie_child_entry_f *n1 = v1; - const struct trie_child_entry_f *n2 = v2; +static int trie_children_cmp_f(const void *v1, const void *v2) +{ + const struct trie_child_entry_f *n1 = v1; + const struct trie_child_entry_f *n2 = v2; - return n1->c - n2->c; + return n1->c - n2->c; } -static const struct trie_node_f *node_lookup_f(sd_hwdb *hwdb, const struct trie_node_f *node, uint8_t c) { - struct trie_child_entry_f *child; - struct trie_child_entry_f search; - - search.c = c; - child = bsearch(&search, trie_node_children(hwdb, node), node->children_count, - le64toh(hwdb->head->child_entry_size), trie_children_cmp_f); - if (child) - return trie_node_from_off(hwdb, child->child_off); - return NULL; +static const struct trie_node_f *node_lookup_f(sd_hwdb * hwdb, + const struct trie_node_f *node, + uint8_t c) +{ + struct trie_child_entry_f *child; + struct trie_child_entry_f search; + + search.c = c; + child = + bsearch(&search, trie_node_children(hwdb, node), + node->children_count, le64toh(hwdb->head->child_entry_size), + trie_children_cmp_f); + if (child) + return trie_node_from_off(hwdb, child->child_off); + return NULL; } -static int hwdb_add_property(sd_hwdb *hwdb, const char *key, const char *value) { - int r; +static int hwdb_add_property(sd_hwdb * hwdb, const char *key, const char *value) +{ + int r; - assert(hwdb); - assert(key); - assert(value); + assert(hwdb); + assert(key); + assert(value); - /* - * Silently ignore all properties which do not start with a - * space; future extensions might use additional prefixes. - */ - if (key[0] != ' ') - return 0; + /* + * Silently ignore all properties which do not start with a + * space; future extensions might use additional prefixes. + */ + if (key[0] != ' ') + return 0; - key++; + key++; - r = ordered_hashmap_ensure_allocated(&hwdb->properties, &string_hash_ops); - if (r < 0) - return r; + r = ordered_hashmap_ensure_allocated(&hwdb->properties, + &string_hash_ops); + if (r < 0) + return r; - r = ordered_hashmap_replace(hwdb->properties, key, (char*)value); - if (r < 0) - return r; + r = ordered_hashmap_replace(hwdb->properties, key, (char *)value); + if (r < 0) + return r; - hwdb->properties_modified = true; + hwdb->properties_modified = true; - return 0; + return 0; } -static int trie_fnmatch_f(sd_hwdb *hwdb, const struct trie_node_f *node, size_t p, - struct linebuf *buf, const char *search) { - size_t len; - size_t i; - const char *prefix; - int err; - - prefix = trie_string(hwdb, node->prefix_off); - len = strlen(prefix + p); - linebuf_add(buf, prefix + p, len); - - for (i = 0; i < node->children_count; i++) { - const struct trie_child_entry_f *child = &trie_node_children(hwdb, node)[i]; - - linebuf_add_char(buf, child->c); - err = trie_fnmatch_f(hwdb, trie_node_from_off(hwdb, child->child_off), 0, buf, search); - if (err < 0) - return err; - linebuf_rem_char(buf); - } - - if (le64toh(node->values_count) && fnmatch(linebuf_get(buf), search, 0) == 0) - for (i = 0; i < le64toh(node->values_count); i++) { - err = hwdb_add_property(hwdb, trie_string(hwdb, trie_node_values(hwdb, node)[i].key_off), - trie_string(hwdb, trie_node_values(hwdb, node)[i].value_off)); - if (err < 0) - return err; - } - - linebuf_rem(buf, len); - return 0; +static int trie_fnmatch_f(sd_hwdb * hwdb, const struct trie_node_f *node, + size_t p, struct linebuf *buf, const char *search) +{ + size_t len; + size_t i; + const char *prefix; + int err; + + prefix = trie_string(hwdb, node->prefix_off); + len = strlen(prefix + p); + linebuf_add(buf, prefix + p, len); + + for (i = 0; i < node->children_count; i++) { + const struct trie_child_entry_f *child = + &trie_node_children(hwdb, node)[i]; + + linebuf_add_char(buf, child->c); + err = + trie_fnmatch_f(hwdb, + trie_node_from_off(hwdb, child->child_off), + 0, buf, search); + if (err < 0) + return err; + linebuf_rem_char(buf); + } + + if (le64toh(node->values_count) + && fnmatch(linebuf_get(buf), search, 0) == 0) + for (i = 0; i < le64toh(node->values_count); i++) { + err = + hwdb_add_property(hwdb, + trie_string(hwdb, + trie_node_values(hwdb, + node) + [i].key_off), + trie_string(hwdb, + trie_node_values(hwdb, + node) + [i].value_off)); + if (err < 0) + return err; + } + + linebuf_rem(buf, len); + return 0; } -static int trie_search_f(sd_hwdb *hwdb, const char *search) { - struct linebuf buf; - const struct trie_node_f *node; - size_t i = 0; - int err; - - linebuf_init(&buf); - - node = trie_node_from_off(hwdb, hwdb->head->nodes_root_off); - while (node) { - const struct trie_node_f *child; - size_t p = 0; - - if (node->prefix_off) { - uint8_t c; - - for (; (c = trie_string(hwdb, node->prefix_off)[p]); p++) { - if (c == '*' || c == '?' || c == '[') - return trie_fnmatch_f(hwdb, node, p, &buf, search + i + p); - if (c != search[i + p]) - return 0; - } - i += p; - } - - child = node_lookup_f(hwdb, node, '*'); - if (child) { - linebuf_add_char(&buf, '*'); - err = trie_fnmatch_f(hwdb, child, 0, &buf, search + i); - if (err < 0) - return err; - linebuf_rem_char(&buf); - } - - child = node_lookup_f(hwdb, node, '?'); - if (child) { - linebuf_add_char(&buf, '?'); - err = trie_fnmatch_f(hwdb, child, 0, &buf, search + i); - if (err < 0) - return err; - linebuf_rem_char(&buf); - } - - child = node_lookup_f(hwdb, node, '['); - if (child) { - linebuf_add_char(&buf, '['); - err = trie_fnmatch_f(hwdb, child, 0, &buf, search + i); - if (err < 0) - return err; - linebuf_rem_char(&buf); - } - - if (search[i] == '\0') { - size_t n; - - for (n = 0; n < le64toh(node->values_count); n++) { - err = hwdb_add_property(hwdb, trie_string(hwdb, trie_node_values(hwdb, node)[n].key_off), - trie_string(hwdb, trie_node_values(hwdb, node)[n].value_off)); - if (err < 0) - return err; - } - return 0; - } - - child = node_lookup_f(hwdb, node, search[i]); - node = child; - i++; - } - return 0; +static int trie_search_f(sd_hwdb * hwdb, const char *search) +{ + struct linebuf buf; + const struct trie_node_f *node; + size_t i = 0; + int err; + + linebuf_init(&buf); + + node = trie_node_from_off(hwdb, hwdb->head->nodes_root_off); + while (node) { + const struct trie_node_f *child; + size_t p = 0; + + if (node->prefix_off) { + uint8_t c; + + for (; (c = trie_string(hwdb, node->prefix_off)[p]); + p++) { + if (c == '*' || c == '?' || c == '[') + return trie_fnmatch_f(hwdb, node, p, + &buf, + search + i + p); + if (c != search[i + p]) + return 0; + } + i += p; + } + + child = node_lookup_f(hwdb, node, '*'); + if (child) { + linebuf_add_char(&buf, '*'); + err = trie_fnmatch_f(hwdb, child, 0, &buf, search + i); + if (err < 0) + return err; + linebuf_rem_char(&buf); + } + + child = node_lookup_f(hwdb, node, '?'); + if (child) { + linebuf_add_char(&buf, '?'); + err = trie_fnmatch_f(hwdb, child, 0, &buf, search + i); + if (err < 0) + return err; + linebuf_rem_char(&buf); + } + + child = node_lookup_f(hwdb, node, '['); + if (child) { + linebuf_add_char(&buf, '['); + err = trie_fnmatch_f(hwdb, child, 0, &buf, search + i); + if (err < 0) + return err; + linebuf_rem_char(&buf); + } + + if (search[i] == '\0') { + size_t n; + + for (n = 0; n < le64toh(node->values_count); n++) { + err = + hwdb_add_property(hwdb, + trie_string(hwdb, + trie_node_values + (hwdb, + node)[n]. + key_off), + trie_string(hwdb, + trie_node_values + (hwdb, + node)[n]. + value_off)); + if (err < 0) + return err; + } + return 0; + } + + child = node_lookup_f(hwdb, node, search[i]); + node = child; + i++; + } + return 0; } static const char hwdb_bin_paths[] = "/etc/systemd/hwdb/hwdb.bin\0" - "/etc/udev/hwdb.bin\0" - "/usr/lib/systemd/hwdb/hwdb.bin\0" + "/etc/udev/hwdb.bin\0" "/usr/lib/systemd/hwdb/hwdb.bin\0" #ifdef HAVE_SPLIT_USR "/lib/systemd/hwdb/hwdb.bin\0" #endif "/lib/systemd/hwdb.bin\0"; -_public_ int sd_hwdb_new(sd_hwdb **ret) { - _cleanup_hwdb_unref_ sd_hwdb *hwdb = NULL; - const char *hwdb_bin_path; - const char sig[] = HWDB_SIG; - - assert_return(ret, -EINVAL); - - hwdb = new0(sd_hwdb, 1); - if (!hwdb) - return -ENOMEM; - - hwdb->n_ref = REFCNT_INIT; - - /* find hwdb.bin in hwdb_bin_paths */ - NULSTR_FOREACH(hwdb_bin_path, hwdb_bin_paths) { - hwdb->f = fopen(hwdb_bin_path, "re"); - if (hwdb->f) { - break; - } - else if (errno == ENOENT) { - continue; - } - else { - - int errsv = -errno; - log_debug("error reading %s: %s", hwdb_bin_path, strerror(errsv)); - return errsv; - } - } - - if (!hwdb->f) { - log_debug("%s", "hwdb.bin does not exist, please run udevadm hwdb --update"); - return -ENOENT; - } - - if (fstat(fileno(hwdb->f), &hwdb->st) < 0 || - (size_t)hwdb->st.st_size < offsetof(struct trie_header_f, strings_len) + 8) { - - int errsv = errno; - log_debug("error reading %s: %s", hwdb_bin_path, strerror(errsv)); - return errsv; - } - - hwdb->map = mmap(0, hwdb->st.st_size, PROT_READ, MAP_SHARED, fileno(hwdb->f), 0); - if (hwdb->map == MAP_FAILED) { - - int errsv = errno; - log_debug("error mapping %s: %s", hwdb_bin_path, strerror(errsv)); - return errsv; - } - - if (memcmp(hwdb->map, sig, sizeof(hwdb->head->signature)) != 0 || - (size_t)hwdb->st.st_size != le64toh(hwdb->head->file_size)) { - log_debug("error recognizing the format of %s", hwdb_bin_path); - return -EINVAL;; - } - - log_debug("%s\n", "=== trie on-disk ==="); - log_debug("tool version: %"PRIu64, le64toh(hwdb->head->tool_version)); - log_debug("file size: %8"PRIi64" bytes", hwdb->st.st_size); - log_debug("header size %8"PRIu64" bytes", le64toh(hwdb->head->header_size)); - log_debug("strings %8"PRIu64" bytes", le64toh(hwdb->head->strings_len)); - log_debug("nodes %8"PRIu64" bytes", le64toh(hwdb->head->nodes_len)); - - *ret = hwdb; - hwdb = NULL; - - return 0; +_public_ int sd_hwdb_new(sd_hwdb ** ret) +{ + _cleanup_hwdb_unref_ sd_hwdb *hwdb = NULL; + const char *hwdb_bin_path; + const char sig[] = HWDB_SIG; + + assert_return(ret, -EINVAL); + + hwdb = new0(sd_hwdb, 1); + if (!hwdb) + return -ENOMEM; + + hwdb->n_ref = REFCNT_INIT; + + /* find hwdb.bin in hwdb_bin_paths */ + NULSTR_FOREACH(hwdb_bin_path, hwdb_bin_paths) { + hwdb->f = fopen(hwdb_bin_path, "re"); + if (hwdb->f) { + break; + } else if (errno == ENOENT) { + continue; + } else { + + int errsv = -errno; + log_debug("error reading %s: %s", hwdb_bin_path, + strerror(errsv)); + return errsv; + } + } + + if (!hwdb->f) { + log_debug("%s", + "hwdb.bin does not exist, please run udevadm hwdb --update"); + return -ENOENT; + } + + if (fstat(fileno(hwdb->f), &hwdb->st) < 0 || + (size_t) hwdb->st.st_size < offsetof(struct trie_header_f, + strings_len) + 8) { + + int errsv = errno; + log_debug("error reading %s: %s", hwdb_bin_path, + strerror(errsv)); + return errsv; + } + + hwdb->map = + mmap(0, hwdb->st.st_size, PROT_READ, MAP_SHARED, fileno(hwdb->f), + 0); + if (hwdb->map == MAP_FAILED) { + + int errsv = errno; + log_debug("error mapping %s: %s", hwdb_bin_path, + strerror(errsv)); + return errsv; + } + + if (memcmp(hwdb->map, sig, sizeof(hwdb->head->signature)) != 0 || + (size_t) hwdb->st.st_size != le64toh(hwdb->head->file_size)) { + log_debug("error recognizing the format of %s", hwdb_bin_path); + return -EINVAL;; + } + + log_debug("%s\n", "=== trie on-disk ==="); + log_debug("tool version: %" PRIu64, + le64toh(hwdb->head->tool_version)); + log_debug("file size: %8" PRIi64 " bytes", hwdb->st.st_size); + log_debug("header size %8" PRIu64 " bytes", + le64toh(hwdb->head->header_size)); + log_debug("strings %8" PRIu64 " bytes", + le64toh(hwdb->head->strings_len)); + log_debug("nodes %8" PRIu64 " bytes", + le64toh(hwdb->head->nodes_len)); + + *ret = hwdb; + hwdb = NULL; + + return 0; } -_public_ sd_hwdb *sd_hwdb_ref(sd_hwdb *hwdb) { - assert_return(hwdb, NULL); +_public_ sd_hwdb *sd_hwdb_ref(sd_hwdb * hwdb) +{ + assert_return(hwdb, NULL); - assert_se(REFCNT_INC(hwdb->n_ref) >= 2); + assert_se(REFCNT_INC(hwdb->n_ref) >= 2); - return hwdb; + return hwdb; } -_public_ sd_hwdb *sd_hwdb_unref(sd_hwdb *hwdb) { - if (hwdb && REFCNT_DEC(hwdb->n_ref) == 0) { - if (hwdb->map) - munmap((void *)hwdb->map, hwdb->st.st_size); - if (hwdb->f) - fclose(hwdb->f); - free(hwdb->modalias); - ordered_hashmap_free(hwdb->properties); - free(hwdb); - } - - return NULL; +_public_ sd_hwdb *sd_hwdb_unref(sd_hwdb * hwdb) +{ + if (hwdb && REFCNT_DEC(hwdb->n_ref) == 0) { + if (hwdb->map) + munmap((void *)hwdb->map, hwdb->st.st_size); + if (hwdb->f) + fclose(hwdb->f); + free(hwdb->modalias); + ordered_hashmap_free(hwdb->properties); + free(hwdb); + } + + return NULL; } -bool hwdb_validate(sd_hwdb *hwdb) { - bool found = false; - const char* p; - struct stat st; - - if (!hwdb) - return false; - if (!hwdb->f) - return false; - - /* if hwdb.bin doesn't exist anywhere, we need to update */ - NULSTR_FOREACH(p, hwdb_bin_paths) { - if (stat(p, &st) >= 0) { - found = true; - break; - } - } - if (!found) - return true; - - if (timespec_load(&hwdb->st.st_mtim) != timespec_load(&st.st_mtim)) - return true; - return false; +bool hwdb_validate(sd_hwdb * hwdb) +{ + bool found = false; + const char *p; + struct stat st; + + if (!hwdb) + return false; + if (!hwdb->f) + return false; + + /* if hwdb.bin doesn't exist anywhere, we need to update */ + NULSTR_FOREACH(p, hwdb_bin_paths) { + if (stat(p, &st) >= 0) { + found = true; + break; + } + } + if (!found) + return true; + + if (timespec_load(&hwdb->st.st_mtim) != timespec_load(&st.st_mtim)) + return true; + return false; } -static int properties_prepare(sd_hwdb *hwdb, const char *modalias) { - char *mod = NULL; - int r; +static int properties_prepare(sd_hwdb * hwdb, const char *modalias) +{ + char *mod = NULL; + int r; - assert(hwdb); - assert(modalias); + assert(hwdb); + assert(modalias); - if (streq_ptr(modalias, hwdb->modalias)) - return 0; + if (streq_ptr(modalias, hwdb->modalias)) + return 0; - mod = strdup(modalias); - if (!mod) - return -ENOMEM; + mod = strdup(modalias); + if (!mod) + return -ENOMEM; - ordered_hashmap_clear(hwdb->properties); + ordered_hashmap_clear(hwdb->properties); - hwdb->properties_modified = true; + hwdb->properties_modified = true; - r = trie_search_f(hwdb, modalias); - if (r < 0) - return r; + r = trie_search_f(hwdb, modalias); + if (r < 0) + return r; - free(hwdb->modalias); - hwdb->modalias = mod; - mod = NULL; + free(hwdb->modalias); + hwdb->modalias = mod; + mod = NULL; - return 0; + return 0; } -_public_ int sd_hwdb_get(sd_hwdb *hwdb, const char *modalias, const char *key, const char **_value) { - const char *value; - int r; +_public_ int sd_hwdb_get(sd_hwdb * hwdb, const char *modalias, const char *key, + const char **_value) +{ + const char *value; + int r; - assert_return(hwdb, -EINVAL); - assert_return(hwdb->f, -EINVAL); - assert_return(modalias, -EINVAL); - assert_return(_value, -EINVAL); + assert_return(hwdb, -EINVAL); + assert_return(hwdb->f, -EINVAL); + assert_return(modalias, -EINVAL); + assert_return(_value, -EINVAL); - r = properties_prepare(hwdb, modalias); - if (r < 0) - return r; + r = properties_prepare(hwdb, modalias); + if (r < 0) + return r; - value = ordered_hashmap_get(hwdb->properties, key); - if (!value) - return -ENOENT; + value = ordered_hashmap_get(hwdb->properties, key); + if (!value) + return -ENOENT; - *_value = value; + *_value = value; - return 0; + return 0; } -_public_ int sd_hwdb_seek(sd_hwdb *hwdb, const char *modalias) { - int r; +_public_ int sd_hwdb_seek(sd_hwdb * hwdb, const char *modalias) +{ + int r; - assert_return(hwdb, -EINVAL); - assert_return(hwdb->f, -EINVAL); - assert_return(modalias, -EINVAL); + assert_return(hwdb, -EINVAL); + assert_return(hwdb->f, -EINVAL); + assert_return(modalias, -EINVAL); - r = properties_prepare(hwdb, modalias); - if (r < 0) - return r; + r = properties_prepare(hwdb, modalias); + if (r < 0) + return r; - hwdb->properties_modified = false; - hwdb->properties_iterator = ITERATOR_FIRST; + hwdb->properties_modified = false; + hwdb->properties_iterator = ITERATOR_FIRST; - return 0; + return 0; } -_public_ int sd_hwdb_enumerate(sd_hwdb *hwdb, const char **key, const char **value) { - const void *k, *v; +_public_ int sd_hwdb_enumerate(sd_hwdb * hwdb, const char **key, + const char **value) +{ + const void *k, *v; - assert_return(hwdb, -EINVAL); - assert_return(key, -EINVAL); - assert_return(value, -EINVAL); + assert_return(hwdb, -EINVAL); + assert_return(key, -EINVAL); + assert_return(value, -EINVAL); - if (hwdb->properties_modified) - return -EAGAIN; + if (hwdb->properties_modified) + return -EAGAIN; - v = ordered_hashmap_iterate(hwdb->properties, &hwdb->properties_iterator, &k); - if (!k) - return 0; + v = ordered_hashmap_iterate(hwdb->properties, + &hwdb->properties_iterator, &k); + if (!k) + return 0; - *key = k; - *value = v; + *key = k; + *value = v; - return 1; + return 1; } diff --git a/libudev-compat/sd-hwdb.h b/libudev-compat/sd-hwdb.h index 9959fff..8ed1401 100644 --- a/libudev-compat/sd-hwdb.h +++ b/libudev-compat/sd-hwdb.h @@ -34,15 +34,16 @@ typedef struct sd_hwdb sd_hwdb; -sd_hwdb *sd_hwdb_ref(sd_hwdb *hwdb); -sd_hwdb *sd_hwdb_unref(sd_hwdb *hwdb); +sd_hwdb *sd_hwdb_ref(sd_hwdb * hwdb); +sd_hwdb *sd_hwdb_unref(sd_hwdb * hwdb); -int sd_hwdb_new(sd_hwdb **ret); +int sd_hwdb_new(sd_hwdb ** ret); -int sd_hwdb_get(sd_hwdb *hwdb, const char *modalias, const char *key, const char **value); +int sd_hwdb_get(sd_hwdb * hwdb, const char *modalias, const char *key, + const char **value); -int sd_hwdb_seek(sd_hwdb *hwdb, const char *modalias); -int sd_hwdb_enumerate(sd_hwdb *hwdb, const char **key, const char **value); +int sd_hwdb_seek(sd_hwdb * hwdb, const char *modalias); +int sd_hwdb_enumerate(sd_hwdb * hwdb, const char **key, const char **value); /* the inverse condition avoids ambiguity of danling 'else' after the macro */ #define SD_HWDB_FOREACH_PROPERTY(hwdb, modalias, key, value) \ diff --git a/libudev-compat/set.h b/libudev-compat/set.h index 97cf83d..75d0c43 100644 --- a/libudev-compat/set.h +++ b/libudev-compat/set.h @@ -28,113 +28,133 @@ #include "hashmap.h" -Set *internal_set_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS); +Set *internal_set_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS); #define set_new(ops) internal_set_new(ops HASHMAP_DEBUG_SRC_ARGS) - -static inline void set_free(Set *s) { - internal_hashmap_free(HASHMAP_BASE(s)); +static inline void set_free(Set * s) +{ + internal_hashmap_free(HASHMAP_BASE(s)); } -static inline void set_free_free(Set *s) { - internal_hashmap_free_free(HASHMAP_BASE(s)); +static inline void set_free_free(Set * s) +{ + internal_hashmap_free_free(HASHMAP_BASE(s)); } /* no set_free_free_free */ -static inline Set *set_copy(Set *s) { - return (Set*) internal_hashmap_copy(HASHMAP_BASE(s)); +static inline Set *set_copy(Set * s) +{ + return (Set *) internal_hashmap_copy(HASHMAP_BASE(s)); } -int internal_set_ensure_allocated(Set **s, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS); +int internal_set_ensure_allocated(Set ** s, + const struct hash_ops *hash_ops + HASHMAP_DEBUG_PARAMS); #define set_ensure_allocated(h, ops) internal_set_ensure_allocated(h, ops HASHMAP_DEBUG_SRC_ARGS) -int set_put(Set *s, const void *key); +int set_put(Set * s, const void *key); /* no set_update */ /* no set_replace */ -static inline void *set_get(Set *s, void *key) { - return internal_hashmap_get(HASHMAP_BASE(s), key); +static inline void *set_get(Set * s, void *key) +{ + return internal_hashmap_get(HASHMAP_BASE(s), key); } + /* no set_get2 */ -static inline bool set_contains(Set *s, const void *key) { - return internal_hashmap_contains(HASHMAP_BASE(s), key); +static inline bool set_contains(Set * s, const void *key) +{ + return internal_hashmap_contains(HASHMAP_BASE(s), key); } -static inline void *set_remove(Set *s, void *key) { - return internal_hashmap_remove(HASHMAP_BASE(s), key); +static inline void *set_remove(Set * s, void *key) +{ + return internal_hashmap_remove(HASHMAP_BASE(s), key); } /* no set_remove2 */ /* no set_remove_value */ -int set_remove_and_put(Set *s, const void *old_key, const void *new_key); +int set_remove_and_put(Set * s, const void *old_key, const void *new_key); /* no set_remove_and_replace */ -int set_merge(Set *s, Set *other); +int set_merge(Set * s, Set * other); -static inline int set_reserve(Set *h, unsigned entries_add) { - return internal_hashmap_reserve(HASHMAP_BASE(h), entries_add); +static inline int set_reserve(Set * h, unsigned entries_add) +{ + return internal_hashmap_reserve(HASHMAP_BASE(h), entries_add); } -static inline int set_move(Set *s, Set *other) { - return internal_hashmap_move(HASHMAP_BASE(s), HASHMAP_BASE(other)); +static inline int set_move(Set * s, Set * other) +{ + return internal_hashmap_move(HASHMAP_BASE(s), HASHMAP_BASE(other)); } -static inline int set_move_one(Set *s, Set *other, const void *key) { - return internal_hashmap_move_one(HASHMAP_BASE(s), HASHMAP_BASE(other), key); +static inline int set_move_one(Set * s, Set * other, const void *key) +{ + return internal_hashmap_move_one(HASHMAP_BASE(s), HASHMAP_BASE(other), + key); } -static inline unsigned set_size(Set *s) { - return internal_hashmap_size(HASHMAP_BASE(s)); +static inline unsigned set_size(Set * s) +{ + return internal_hashmap_size(HASHMAP_BASE(s)); } -static inline bool set_isempty(Set *s) { - return set_size(s) == 0; +static inline bool set_isempty(Set * s) +{ + return set_size(s) == 0; } -static inline unsigned set_buckets(Set *s) { - return internal_hashmap_buckets(HASHMAP_BASE(s)); +static inline unsigned set_buckets(Set * s) +{ + return internal_hashmap_buckets(HASHMAP_BASE(s)); } -void *set_iterate(Set *s, Iterator *i); +void *set_iterate(Set * s, Iterator * i); -static inline void set_clear(Set *s) { - internal_hashmap_clear(HASHMAP_BASE(s)); +static inline void set_clear(Set * s) +{ + internal_hashmap_clear(HASHMAP_BASE(s)); } -static inline void set_clear_free(Set *s) { - internal_hashmap_clear_free(HASHMAP_BASE(s)); +static inline void set_clear_free(Set * s) +{ + internal_hashmap_clear_free(HASHMAP_BASE(s)); } /* no set_clear_free_free */ -static inline void *set_steal_first(Set *s) { - return internal_hashmap_steal_first(HASHMAP_BASE(s)); +static inline void *set_steal_first(Set * s) +{ + return internal_hashmap_steal_first(HASHMAP_BASE(s)); } /* no set_steal_first_key */ /* no set_first_key */ -static inline void *set_first(Set *s) { - return internal_hashmap_first(HASHMAP_BASE(s)); +static inline void *set_first(Set * s) +{ + return internal_hashmap_first(HASHMAP_BASE(s)); } /* no set_next */ -static inline char **set_get_strv(Set *s) { - return internal_hashmap_get_strv(HASHMAP_BASE(s)); +static inline char **set_get_strv(Set * s) +{ + return internal_hashmap_get_strv(HASHMAP_BASE(s)); } -int set_consume(Set *s, void *value); -int set_put_strdup(Set *s, const char *p); -int set_put_strdupv(Set *s, char **l); +int set_consume(Set * s, void *value); +int set_put_strdup(Set * s, const char *p); +int set_put_strdupv(Set * s, char **l); #define SET_FOREACH(e, s, i) \ for ((i) = ITERATOR_FIRST, (e) = set_iterate((s), &(i)); (e); (e) = set_iterate((s), &(i))) -DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, set_free); -DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, set_free_free); +DEFINE_TRIVIAL_CLEANUP_FUNC(Set *, set_free); +DEFINE_TRIVIAL_CLEANUP_FUNC(Set *, set_free_free); #define _cleanup_set_free_ _cleanup_(set_freep) #define _cleanup_set_free_free_ _cleanup_(set_free_freep) -#endif \ No newline at end of file +#endif diff --git a/libudev-compat/siphash24.c b/libudev-compat/siphash24.c index 51e4b6e..8543c79 100644 --- a/libudev-compat/siphash24.c +++ b/libudev-compat/siphash24.c @@ -58,83 +58,97 @@ typedef uint8_t u8; } while(0) /* SipHash-2-4 */ -void siphash24(uint8_t out[8], const void *_in, size_t inlen, const uint8_t k[16]) +void siphash24(uint8_t out[8], const void *_in, size_t inlen, + const uint8_t k[16]) { - /* "somepseudorandomlygeneratedbytes" */ - u64 v0 = 0x736f6d6570736575ULL; - u64 v1 = 0x646f72616e646f6dULL; - u64 v2 = 0x6c7967656e657261ULL; - u64 v3 = 0x7465646279746573ULL; - u64 b; - u64 k0 = U8TO64_LE( k ); - u64 k1 = U8TO64_LE( k + 8 ); - u64 m; - const u8 *in = _in; - const u8 *end = in + inlen - ( inlen % sizeof( u64 ) ); - const int left = inlen & 7; - b = ( ( u64 )inlen ) << 56; - v3 ^= k1; - v2 ^= k0; - v1 ^= k1; - v0 ^= k0; - - for ( ; in != end; in += 8 ) - { - m = U8TO64_LE( in ); + /* "somepseudorandomlygeneratedbytes" */ + u64 v0 = 0x736f6d6570736575ULL; + u64 v1 = 0x646f72616e646f6dULL; + u64 v2 = 0x6c7967656e657261ULL; + u64 v3 = 0x7465646279746573ULL; + u64 b; + u64 k0 = U8TO64_LE(k); + u64 k1 = U8TO64_LE(k + 8); + u64 m; + const u8 *in = _in; + const u8 *end = in + inlen - (inlen % sizeof(u64)); + const int left = inlen & 7; + b = ((u64) inlen) << 56; + v3 ^= k1; + v2 ^= k0; + v1 ^= k1; + v0 ^= k0; + + for (; in != end; in += 8) { + m = U8TO64_LE(in); #ifdef DEBUG - printf( "(%3d) v0 %08x %08x\n", ( int )inlen, ( u32 )( v0 >> 32 ), ( u32 )v0 ); - printf( "(%3d) v1 %08x %08x\n", ( int )inlen, ( u32 )( v1 >> 32 ), ( u32 )v1 ); - printf( "(%3d) v2 %08x %08x\n", ( int )inlen, ( u32 )( v2 >> 32 ), ( u32 )v2 ); - printf( "(%3d) v3 %08x %08x\n", ( int )inlen, ( u32 )( v3 >> 32 ), ( u32 )v3 ); - printf( "(%3d) compress %08x %08x\n", ( int )inlen, ( u32 )( m >> 32 ), ( u32 )m ); + printf("(%3d) v0 %08x %08x\n", (int)inlen, (u32) (v0 >> 32), + (u32) v0); + printf("(%3d) v1 %08x %08x\n", (int)inlen, (u32) (v1 >> 32), + (u32) v1); + printf("(%3d) v2 %08x %08x\n", (int)inlen, (u32) (v2 >> 32), + (u32) v2); + printf("(%3d) v3 %08x %08x\n", (int)inlen, (u32) (v3 >> 32), + (u32) v3); + printf("(%3d) compress %08x %08x\n", (int)inlen, + (u32) (m >> 32), (u32) m); #endif - v3 ^= m; - SIPROUND; - SIPROUND; - v0 ^= m; - } + v3 ^= m; + SIPROUND; + SIPROUND; + v0 ^= m; + } - switch( left ) - { - case 7: b |= ( ( u64 )in[ 6] ) << 48; + switch (left) { + case 7: + b |= ((u64) in[6]) << 48; - case 6: b |= ( ( u64 )in[ 5] ) << 40; + case 6: + b |= ((u64) in[5]) << 40; - case 5: b |= ( ( u64 )in[ 4] ) << 32; + case 5: + b |= ((u64) in[4]) << 32; - case 4: b |= ( ( u64 )in[ 3] ) << 24; + case 4: + b |= ((u64) in[3]) << 24; - case 3: b |= ( ( u64 )in[ 2] ) << 16; + case 3: + b |= ((u64) in[2]) << 16; - case 2: b |= ( ( u64 )in[ 1] ) << 8; + case 2: + b |= ((u64) in[1]) << 8; - case 1: b |= ( ( u64 )in[ 0] ); break; + case 1: + b |= ((u64) in[0]); + break; - case 0: break; - } + case 0: + break; + } #ifdef DEBUG - printf( "(%3d) v0 %08x %08x\n", ( int )inlen, ( u32 )( v0 >> 32 ), ( u32 )v0 ); - printf( "(%3d) v1 %08x %08x\n", ( int )inlen, ( u32 )( v1 >> 32 ), ( u32 )v1 ); - printf( "(%3d) v2 %08x %08x\n", ( int )inlen, ( u32 )( v2 >> 32 ), ( u32 )v2 ); - printf( "(%3d) v3 %08x %08x\n", ( int )inlen, ( u32 )( v3 >> 32 ), ( u32 )v3 ); - printf( "(%3d) padding %08x %08x\n", ( int )inlen, ( u32 )( b >> 32 ), ( u32 )b ); + printf("(%3d) v0 %08x %08x\n", (int)inlen, (u32) (v0 >> 32), (u32) v0); + printf("(%3d) v1 %08x %08x\n", (int)inlen, (u32) (v1 >> 32), (u32) v1); + printf("(%3d) v2 %08x %08x\n", (int)inlen, (u32) (v2 >> 32), (u32) v2); + printf("(%3d) v3 %08x %08x\n", (int)inlen, (u32) (v3 >> 32), (u32) v3); + printf("(%3d) padding %08x %08x\n", (int)inlen, (u32) (b >> 32), + (u32) b); #endif - v3 ^= b; - SIPROUND; - SIPROUND; - v0 ^= b; + v3 ^= b; + SIPROUND; + SIPROUND; + v0 ^= b; #ifdef DEBUG - printf( "(%3d) v0 %08x %08x\n", ( int )inlen, ( u32 )( v0 >> 32 ), ( u32 )v0 ); - printf( "(%3d) v1 %08x %08x\n", ( int )inlen, ( u32 )( v1 >> 32 ), ( u32 )v1 ); - printf( "(%3d) v2 %08x %08x\n", ( int )inlen, ( u32 )( v2 >> 32 ), ( u32 )v2 ); - printf( "(%3d) v3 %08x %08x\n", ( int )inlen, ( u32 )( v3 >> 32 ), ( u32 )v3 ); + printf("(%3d) v0 %08x %08x\n", (int)inlen, (u32) (v0 >> 32), (u32) v0); + printf("(%3d) v1 %08x %08x\n", (int)inlen, (u32) (v1 >> 32), (u32) v1); + printf("(%3d) v2 %08x %08x\n", (int)inlen, (u32) (v2 >> 32), (u32) v2); + printf("(%3d) v3 %08x %08x\n", (int)inlen, (u32) (v3 >> 32), (u32) v3); #endif - v2 ^= 0xff; - SIPROUND; - SIPROUND; - SIPROUND; - SIPROUND; - b = v0 ^ v1 ^ v2 ^ v3; - U64TO8_LE( out, b ); -} \ No newline at end of file + v2 ^= 0xff; + SIPROUND; + SIPROUND; + SIPROUND; + SIPROUND; + b = v0 ^ v1 ^ v2 ^ v3; + U64TO8_LE(out, b); +} diff --git a/libudev-compat/siphash24.h b/libudev-compat/siphash24.h index 859a852..ea6662e 100644 --- a/libudev-compat/siphash24.h +++ b/libudev-compat/siphash24.h @@ -12,6 +12,7 @@ #include #include -void siphash24(uint8_t out[8], const void *in, size_t inlen, const uint8_t k[16]); +void siphash24(uint8_t out[8], const void *in, size_t inlen, + const uint8_t k[16]); -#endif \ No newline at end of file +#endif diff --git a/libudev-compat/sparse-endian.h b/libudev-compat/sparse-endian.h index 11145ed..7893b9c 100644 --- a/libudev-compat/sparse-endian.h +++ b/libudev-compat/sparse-endian.h @@ -78,20 +78,64 @@ typedef uint64_t __bitwise be64_t; #define bswap_64_on_be(x) __bswap_64(x) #endif -static inline le16_t htole16(uint16_t value) { return (le16_t __force) bswap_16_on_be(value); } -static inline le32_t htole32(uint32_t value) { return (le32_t __force) bswap_32_on_be(value); } -static inline le64_t htole64(uint64_t value) { return (le64_t __force) bswap_64_on_be(value); } +static inline le16_t htole16(uint16_t value) +{ + return (le16_t __force) bswap_16_on_be(value); +} -static inline be16_t htobe16(uint16_t value) { return (be16_t __force) bswap_16_on_le(value); } -static inline be32_t htobe32(uint32_t value) { return (be32_t __force) bswap_32_on_le(value); } -static inline be64_t htobe64(uint64_t value) { return (be64_t __force) bswap_64_on_le(value); } +static inline le32_t htole32(uint32_t value) +{ + return (le32_t __force) bswap_32_on_be(value); +} -static inline uint16_t le16toh(le16_t value) { return bswap_16_on_be((uint16_t __force)value); } -static inline uint32_t le32toh(le32_t value) { return bswap_32_on_be((uint32_t __force)value); } -static inline uint64_t le64toh(le64_t value) { return bswap_64_on_be((uint64_t __force)value); } +static inline le64_t htole64(uint64_t value) +{ + return (le64_t __force) bswap_64_on_be(value); +} -static inline uint16_t be16toh(be16_t value) { return bswap_16_on_le((uint16_t __force)value); } -static inline uint32_t be32toh(be32_t value) { return bswap_32_on_le((uint32_t __force)value); } -static inline uint64_t be64toh(be64_t value) { return bswap_64_on_le((uint64_t __force)value); } +static inline be16_t htobe16(uint16_t value) +{ + return (be16_t __force) bswap_16_on_le(value); +} -#endif /* SPARSE_ENDIAN_H */ +static inline be32_t htobe32(uint32_t value) +{ + return (be32_t __force) bswap_32_on_le(value); +} + +static inline be64_t htobe64(uint64_t value) +{ + return (be64_t __force) bswap_64_on_le(value); +} + +static inline uint16_t le16toh(le16_t value) +{ + return bswap_16_on_be((uint16_t __force) value); +} + +static inline uint32_t le32toh(le32_t value) +{ + return bswap_32_on_be((uint32_t __force) value); +} + +static inline uint64_t le64toh(le64_t value) +{ + return bswap_64_on_be((uint64_t __force) value); +} + +static inline uint16_t be16toh(be16_t value) +{ + return bswap_16_on_le((uint16_t __force) value); +} + +static inline uint32_t be32toh(be32_t value) +{ + return bswap_32_on_le((uint32_t __force) value); +} + +static inline uint64_t be64toh(be64_t value) +{ + return bswap_64_on_le((uint64_t __force) value); +} + +#endif /* SPARSE_ENDIAN_H */ diff --git a/libudev-compat/strxcpyx.c b/libudev-compat/strxcpyx.c index 88a14db..6e62a18 100644 --- a/libudev-compat/strxcpyx.c +++ b/libudev-compat/strxcpyx.c @@ -36,72 +36,77 @@ #include #include "strxcpyx.h" -size_t strpcpy(char **dest, size_t size, const char *src) { - size_t len; - - len = strlen(src); - if (len >= size) { - if (size > 1) - *dest = mempcpy(*dest, src, size-1); - size = 0; - } else { - if (len > 0) { - *dest = mempcpy(*dest, src, len); - size -= len; - } - } - *dest[0] = '\0'; - return size; +size_t strpcpy(char **dest, size_t size, const char *src) +{ + size_t len; + + len = strlen(src); + if (len >= size) { + if (size > 1) + *dest = mempcpy(*dest, src, size - 1); + size = 0; + } else { + if (len > 0) { + *dest = mempcpy(*dest, src, len); + size -= len; + } + } + *dest[0] = '\0'; + return size; } -size_t strpcpyf(char **dest, size_t size, const char *src, ...) { - va_list va; - int i; - - va_start(va, src); - i = vsnprintf(*dest, size, src, va); - if (i < (int)size) { - *dest += i; - size -= i; - } else { - *dest += size; - size = 0; - } - va_end(va); - *dest[0] = '\0'; - return size; +size_t strpcpyf(char **dest, size_t size, const char *src, ...) +{ + va_list va; + int i; + + va_start(va, src); + i = vsnprintf(*dest, size, src, va); + if (i < (int)size) { + *dest += i; + size -= i; + } else { + *dest += size; + size = 0; + } + va_end(va); + *dest[0] = '\0'; + return size; } -size_t strpcpyl(char **dest, size_t size, const char *src, ...) { - va_list va; - - va_start(va, src); - do { - size = strpcpy(dest, size, src); - src = va_arg(va, char *); - } while (src != NULL); - va_end(va); - return size; +size_t strpcpyl(char **dest, size_t size, const char *src, ...) +{ + va_list va; + + va_start(va, src); + do { + size = strpcpy(dest, size, src); + src = va_arg(va, char *); + } while (src != NULL); + va_end(va); + return size; } -size_t strscpy(char *dest, size_t size, const char *src) { - char *s; +size_t strscpy(char *dest, size_t size, const char *src) +{ + char *s; - s = dest; - return strpcpy(&s, size, src); + s = dest; + return strpcpy(&s, size, src); } -size_t strscpyl(char *dest, size_t size, const char *src, ...) { - va_list va; - char *s; +size_t strscpyl(char *dest, size_t size, const char *src, ...) +{ + va_list va; + char *s; - va_start(va, src); - s = dest; - do { - size = strpcpy(&s, size, src); - src = va_arg(va, char *); - } while (src != NULL); - va_end(va); + va_start(va, src); + s = dest; + do { + size = strpcpy(&s, size, src); + src = va_arg(va, char *); + } while (src != NULL); + va_end(va); - return size; + return size; } diff --git a/libudev-compat/strxcpyx.h b/libudev-compat/strxcpyx.h index 7d8276a..fe115ff 100644 --- a/libudev-compat/strxcpyx.h +++ b/libudev-compat/strxcpyx.h @@ -41,4 +41,4 @@ size_t strpcpyl(char **dest, size_t size, const char *src, ...) _sentinel_; size_t strscpy(char *dest, size_t size, const char *src); size_t strscpyl(char *dest, size_t size, const char *src, ...) _sentinel_; -#endif \ No newline at end of file +#endif diff --git a/libudev-compat/utf8.c b/libudev-compat/utf8.c index 4f2bffd..42ef2ae 100644 --- a/libudev-compat/utf8.c +++ b/libudev-compat/utf8.c @@ -59,215 +59,222 @@ #include "utf8.h" #include "util.h" -static inline bool is_unicode_valid(uint32_t ch) { - - if (ch >= 0x110000) /* End of unicode space */ - return false; - if ((ch & 0xFFFFF800) == 0xD800) /* Reserved area for UTF-16 */ - return false; - if ((ch >= 0xFDD0) && (ch <= 0xFDEF)) /* Reserved */ - return false; - if ((ch & 0xFFFE) == 0xFFFE) /* BOM (Byte Order Mark) */ - return false; - - return true; +static inline bool is_unicode_valid(uint32_t ch) +{ + + if (ch >= 0x110000) /* End of unicode space */ + return false; + if ((ch & 0xFFFFF800) == 0xD800) /* Reserved area for UTF-16 */ + return false; + if ((ch >= 0xFDD0) && (ch <= 0xFDEF)) /* Reserved */ + return false; + if ((ch & 0xFFFE) == 0xFFFE) /* BOM (Byte Order Mark) */ + return false; + + return true; } -static bool is_unicode_control(uint32_t ch) { +static bool is_unicode_control(uint32_t ch) +{ - /* - 0 to ' '-1 is the C0 range. - DEL=0x7F, and DEL+1 to 0x9F is C1 range. - '\t' is in C0 range, but more or less harmless and commonly used. - */ + /* + 0 to ' '-1 is the C0 range. + DEL=0x7F, and DEL+1 to 0x9F is C1 range. + '\t' is in C0 range, but more or less harmless and commonly used. + */ - return (ch < ' ' && ch != '\t' && ch != '\n') || - (0x7F <= ch && ch <= 0x9F); + return (ch < ' ' && ch != '\t' && ch != '\n') || + (0x7F <= ch && ch <= 0x9F); } /* count of characters used to encode one unicode char */ -static int utf8_encoded_expected_len(const char *str) { - unsigned char c; - - assert(str); - - c = (unsigned char) str[0]; - if (c < 0x80) - return 1; - if ((c & 0xe0) == 0xc0) - return 2; - if ((c & 0xf0) == 0xe0) - return 3; - if ((c & 0xf8) == 0xf0) - return 4; - if ((c & 0xfc) == 0xf8) - return 5; - if ((c & 0xfe) == 0xfc) - return 6; - - return 0; +static int utf8_encoded_expected_len(const char *str) +{ + unsigned char c; + + assert(str); + + c = (unsigned char)str[0]; + if (c < 0x80) + return 1; + if ((c & 0xe0) == 0xc0) + return 2; + if ((c & 0xf0) == 0xe0) + return 3; + if ((c & 0xf8) == 0xf0) + return 4; + if ((c & 0xfc) == 0xf8) + return 5; + if ((c & 0xfe) == 0xfc) + return 6; + + return 0; } /* decode one unicode char */ -int utf8_encoded_to_unichar(const char *str) { - int unichar, len, i; - - assert(str); - - len = utf8_encoded_expected_len(str); - - switch (len) { - case 1: - return (int)str[0]; - case 2: - unichar = str[0] & 0x1f; - break; - case 3: - unichar = (int)str[0] & 0x0f; - break; - case 4: - unichar = (int)str[0] & 0x07; - break; - case 5: - unichar = (int)str[0] & 0x03; - break; - case 6: - unichar = (int)str[0] & 0x01; - break; - default: - return -EINVAL; - } - - for (i = 1; i < len; i++) { - if (((int)str[i] & 0xc0) != 0x80) - return -EINVAL; - unichar <<= 6; - unichar |= (int)str[i] & 0x3f; - } - - return unichar; +int utf8_encoded_to_unichar(const char *str) +{ + int unichar, len, i; + + assert(str); + + len = utf8_encoded_expected_len(str); + + switch (len) { + case 1: + return (int)str[0]; + case 2: + unichar = str[0] & 0x1f; + break; + case 3: + unichar = (int)str[0] & 0x0f; + break; + case 4: + unichar = (int)str[0] & 0x07; + break; + case 5: + unichar = (int)str[0] & 0x03; + break; + case 6: + unichar = (int)str[0] & 0x01; + break; + default: + return -EINVAL; + } + + for (i = 1; i < len; i++) { + if (((int)str[i] & 0xc0) != 0x80) + return -EINVAL; + unichar <<= 6; + unichar |= (int)str[i] & 0x3f; + } + + return unichar; } -bool utf8_is_printable_newline(const char* str, size_t length, bool newline) { - const char *p; +bool utf8_is_printable_newline(const char *str, size_t length, bool newline) +{ + const char *p; - assert(str); + assert(str); - for (p = str; length;) { - int encoded_len, val; + for (p = str; length;) { + int encoded_len, val; - encoded_len = utf8_encoded_valid_unichar(p); - if (encoded_len < 0 || - (size_t) encoded_len > length) - return false; + encoded_len = utf8_encoded_valid_unichar(p); + if (encoded_len < 0 || (size_t) encoded_len > length) + return false; - val = utf8_encoded_to_unichar(p); - if (val < 0 || - is_unicode_control(val) || - (!newline && val == '\n')) - return false; + val = utf8_encoded_to_unichar(p); + if (val < 0 || + is_unicode_control(val) || (!newline && val == '\n')) + return false; - length -= encoded_len; - p += encoded_len; - } + length -= encoded_len; + p += encoded_len; + } - return true; + return true; } -const char *utf8_is_valid(const char *str) { - const uint8_t *p; +const char *utf8_is_valid(const char *str) +{ + const uint8_t *p; - assert(str); + assert(str); - for (p = (const uint8_t*) str; *p; ) { - int len; + for (p = (const uint8_t *)str; *p;) { + int len; - len = utf8_encoded_valid_unichar((const char *)p); - if (len < 0) - return NULL; + len = utf8_encoded_valid_unichar((const char *)p); + if (len < 0) + return NULL; - p += len; - } + p += len; + } - return str; + return str; } -char *utf8_escape_invalid(const char *str) { - char *p, *s; +char *utf8_escape_invalid(const char *str) +{ + char *p, *s; - assert(str); + assert(str); - p = s = malloc(strlen(str) * 4 + 1); - if (!p) - return NULL; + p = s = malloc(strlen(str) * 4 + 1); + if (!p) + return NULL; - while (*str) { - int len; + while (*str) { + int len; - len = utf8_encoded_valid_unichar(str); - if (len > 0) { - s = mempcpy(s, str, len); - str += len; - } else { - s = stpcpy(s, UTF8_REPLACEMENT_CHARACTER); - str += 1; - } - } + len = utf8_encoded_valid_unichar(str); + if (len > 0) { + s = mempcpy(s, str, len); + str += len; + } else { + s = stpcpy(s, UTF8_REPLACEMENT_CHARACTER); + str += 1; + } + } - *s = '\0'; + *s = '\0'; - return p; + return p; } -char *utf8_escape_non_printable(const char *str) { - char *p, *s; - - assert(str); - - p = s = malloc(strlen(str) * 4 + 1); - if (!p) - return NULL; - - while (*str) { - int len; - - len = utf8_encoded_valid_unichar(str); - if (len > 0) { - if (utf8_is_printable(str, len)) { - s = mempcpy(s, str, len); - str += len; - } else { - while (len > 0) { - *(s++) = '\\'; - *(s++) = 'x'; - *(s++) = hexchar((int) *str >> 4); - *(s++) = hexchar((int) *str); - - str += 1; - len --; - } - } - } else { - s = stpcpy(s, UTF8_REPLACEMENT_CHARACTER); - str += 1; - } - } - - *s = '\0'; - - return p; +char *utf8_escape_non_printable(const char *str) +{ + char *p, *s; + + assert(str); + + p = s = malloc(strlen(str) * 4 + 1); + if (!p) + return NULL; + + while (*str) { + int len; + + len = utf8_encoded_valid_unichar(str); + if (len > 0) { + if (utf8_is_printable(str, len)) { + s = mempcpy(s, str, len); + str += len; + } else { + while (len > 0) { + *(s++) = '\\'; + *(s++) = 'x'; + *(s++) = hexchar((int)*str >> 4); + *(s++) = hexchar((int)*str); + + str += 1; + len--; + } + } + } else { + s = stpcpy(s, UTF8_REPLACEMENT_CHARACTER); + str += 1; + } + } + + *s = '\0'; + + return p; } -char *ascii_is_valid(const char *str) { - const char *p; +char *ascii_is_valid(const char *str) +{ + const char *p; - assert(str); + assert(str); - for (p = str; *p; p++) - if ((unsigned char) *p >= 128) - return NULL; + for (p = str; *p; p++) + if ((unsigned char)*p >= 128) + return NULL; - return (char*) str; + return (char *)str; } /** @@ -282,127 +289,133 @@ char *ascii_is_valid(const char *str) { * Returns: The length in bytes that the UTF-8 representation does or would * occupy. */ -size_t utf8_encode_unichar(char *out_utf8, uint32_t g) { - if (g < (1 << 7)) { - if (out_utf8) - out_utf8[0] = g & 0x7f; - return 1; - } else if (g < (1 << 11)) { - if (out_utf8) { - out_utf8[0] = 0xc0 | ((g >> 6) & 0x1f); - out_utf8[1] = 0x80 | (g & 0x3f); - } - return 2; - } else if (g < (1 << 16)) { - if (out_utf8) { - out_utf8[0] = 0xe0 | ((g >> 12) & 0x0f); - out_utf8[1] = 0x80 | ((g >> 6) & 0x3f); - out_utf8[2] = 0x80 | (g & 0x3f); - } - return 3; - } else if (g < (1 << 21)) { - if (out_utf8) { - out_utf8[0] = 0xf0 | ((g >> 18) & 0x07); - out_utf8[1] = 0x80 | ((g >> 12) & 0x3f); - out_utf8[2] = 0x80 | ((g >> 6) & 0x3f); - out_utf8[3] = 0x80 | (g & 0x3f); - } - return 4; - } else { - return 0; - } +size_t utf8_encode_unichar(char *out_utf8, uint32_t g) +{ + if (g < (1 << 7)) { + if (out_utf8) + out_utf8[0] = g & 0x7f; + return 1; + } else if (g < (1 << 11)) { + if (out_utf8) { + out_utf8[0] = 0xc0 | ((g >> 6) & 0x1f); + out_utf8[1] = 0x80 | (g & 0x3f); + } + return 2; + } else if (g < (1 << 16)) { + if (out_utf8) { + out_utf8[0] = 0xe0 | ((g >> 12) & 0x0f); + out_utf8[1] = 0x80 | ((g >> 6) & 0x3f); + out_utf8[2] = 0x80 | (g & 0x3f); + } + return 3; + } else if (g < (1 << 21)) { + if (out_utf8) { + out_utf8[0] = 0xf0 | ((g >> 18) & 0x07); + out_utf8[1] = 0x80 | ((g >> 12) & 0x3f); + out_utf8[2] = 0x80 | ((g >> 6) & 0x3f); + out_utf8[3] = 0x80 | (g & 0x3f); + } + return 4; + } else { + return 0; + } } -char *utf16_to_utf8(const void *s, size_t length) { - const uint8_t *f; - char *r, *t; +char *utf16_to_utf8(const void *s, size_t length) +{ + const uint8_t *f; + char *r, *t; - r = new(char, (length * 4 + 1) / 2 + 1); - if (!r) - return NULL; + r = new(char, (length * 4 + 1) / 2 + 1); + if (!r) + return NULL; - f = s; - t = r; + f = s; + t = r; - while (f < (const uint8_t*) s + length) { - uint16_t w1, w2; + while (f < (const uint8_t *)s + length) { + uint16_t w1, w2; - /* see RFC 2781 section 2.2 */ + /* see RFC 2781 section 2.2 */ - w1 = f[1] << 8 | f[0]; - f += 2; + w1 = f[1] << 8 | f[0]; + f += 2; - if (!utf16_is_surrogate(w1)) { - t += utf8_encode_unichar(t, w1); + if (!utf16_is_surrogate(w1)) { + t += utf8_encode_unichar(t, w1); - continue; - } + continue; + } - if (utf16_is_trailing_surrogate(w1)) - continue; - else if (f >= (const uint8_t*) s + length) - break; + if (utf16_is_trailing_surrogate(w1)) + continue; + else if (f >= (const uint8_t *)s + length) + break; - w2 = f[1] << 8 | f[0]; - f += 2; + w2 = f[1] << 8 | f[0]; + f += 2; - if (!utf16_is_trailing_surrogate(w2)) { - f -= 2; - continue; - } + if (!utf16_is_trailing_surrogate(w2)) { + f -= 2; + continue; + } - t += utf8_encode_unichar(t, utf16_surrogate_pair_to_unichar(w1, w2)); - } + t += utf8_encode_unichar(t, + utf16_surrogate_pair_to_unichar(w1, + w2)); + } - *t = 0; - return r; + *t = 0; + return r; } /* expected size used to encode one unicode char */ -static int utf8_unichar_to_encoded_len(int unichar) { - - if (unichar < 0x80) - return 1; - if (unichar < 0x800) - return 2; - if (unichar < 0x10000) - return 3; - if (unichar < 0x200000) - return 4; - if (unichar < 0x4000000) - return 5; - - return 6; +static int utf8_unichar_to_encoded_len(int unichar) +{ + + if (unichar < 0x80) + return 1; + if (unichar < 0x800) + return 2; + if (unichar < 0x10000) + return 3; + if (unichar < 0x200000) + return 4; + if (unichar < 0x4000000) + return 5; + + return 6; } /* validate one encoded unicode char and return its length */ -int utf8_encoded_valid_unichar(const char *str) { - int len, unichar, i; +int utf8_encoded_valid_unichar(const char *str) +{ + int len, unichar, i; - assert(str); + assert(str); - len = utf8_encoded_expected_len(str); - if (len == 0) - return -EINVAL; + len = utf8_encoded_expected_len(str); + if (len == 0) + return -EINVAL; - /* ascii is valid */ - if (len == 1) - return 1; + /* ascii is valid */ + if (len == 1) + return 1; - /* check if expected encoded chars are available */ - for (i = 0; i < len; i++) - if ((str[i] & 0x80) != 0x80) - return -EINVAL; + /* check if expected encoded chars are available */ + for (i = 0; i < len; i++) + if ((str[i] & 0x80) != 0x80) + return -EINVAL; - unichar = utf8_encoded_to_unichar(str); + unichar = utf8_encoded_to_unichar(str); - /* check if encoded length matches encoded value */ - if (utf8_unichar_to_encoded_len(unichar) != len) - return -EINVAL; + /* check if encoded length matches encoded value */ + if (utf8_unichar_to_encoded_len(unichar) != len) + return -EINVAL; - /* check if value has valid range */ - if (!is_unicode_valid(unichar)) - return -EINVAL; + /* check if value has valid range */ + if (!is_unicode_valid(unichar)) + return -EINVAL; - return len; + return len; } diff --git a/libudev-compat/utf8.h b/libudev-compat/utf8.h index 0a23888..426f5c5 100644 --- a/libudev-compat/utf8.h +++ b/libudev-compat/utf8.h @@ -39,7 +39,8 @@ const char *utf8_is_valid(const char *s) _pure_; char *ascii_is_valid(const char *s) _pure_; -bool utf8_is_printable_newline(const char* str, size_t length, bool newline) _pure_; +bool utf8_is_printable_newline(const char *str, size_t length, + bool newline) _pure_; #define utf8_is_printable(str, length) utf8_is_printable_newline(str, length, true) char *utf8_escape_invalid(const char *s); @@ -51,16 +52,20 @@ char *utf16_to_utf8(const void *s, size_t length); int utf8_encoded_valid_unichar(const char *str); int utf8_encoded_to_unichar(const char *str); -static inline bool utf16_is_surrogate(uint16_t c) { - return (0xd800 <= c && c <= 0xdfff); +static inline bool utf16_is_surrogate(uint16_t c) +{ + return (0xd800 <= c && c <= 0xdfff); } -static inline bool utf16_is_trailing_surrogate(uint16_t c) { - return (0xdc00 <= c && c <= 0xdfff); +static inline bool utf16_is_trailing_surrogate(uint16_t c) +{ + return (0xdc00 <= c && c <= 0xdfff); } -static inline uint32_t utf16_surrogate_pair_to_unichar(uint16_t lead, uint16_t trail) { - return ((lead - 0xd800) << 10) + (trail - 0xdc00) + 0x10000; +static inline uint32_t utf16_surrogate_pair_to_unichar(uint16_t lead, + uint16_t trail) +{ + return ((lead - 0xd800) << 10) + (trail - 0xdc00) + 0x10000; } -#endif \ No newline at end of file +#endif diff --git a/libudev-compat/util.c b/libudev-compat/util.c index 0fb1f69..3750ce7 100644 --- a/libudev-compat/util.c +++ b/libudev-compat/util.c @@ -79,367 +79,385 @@ #include #undef basename -usec_t now(clockid_t clock_id) { - struct timespec ts; +usec_t now(clockid_t clock_id) +{ + struct timespec ts; - assert_se(clock_gettime(clock_id, &ts) == 0); + assert_se(clock_gettime(clock_id, &ts) == 0); - return timespec_load(&ts); + return timespec_load(&ts); } -struct timespec *timespec_store(struct timespec *ts, usec_t u) { - assert(ts); +struct timespec *timespec_store(struct timespec *ts, usec_t u) +{ + assert(ts); - if (u == USEC_INFINITY) { - ts->tv_sec = (time_t) -1; - ts->tv_nsec = (long) -1; - return ts; - } + if (u == USEC_INFINITY) { + ts->tv_sec = (time_t) - 1; + ts->tv_nsec = (long)-1; + return ts; + } - ts->tv_sec = (time_t) (u / USEC_PER_SEC); - ts->tv_nsec = (long int) ((u % USEC_PER_SEC) * NSEC_PER_USEC); + ts->tv_sec = (time_t) (u / USEC_PER_SEC); + ts->tv_nsec = (long int)((u % USEC_PER_SEC) * NSEC_PER_USEC); - return ts; + return ts; } -usec_t timespec_load(const struct timespec *ts) { - assert(ts); +usec_t timespec_load(const struct timespec * ts) +{ + assert(ts); - if (ts->tv_sec == (time_t) -1 && - ts->tv_nsec == (long) -1) - return USEC_INFINITY; + if (ts->tv_sec == (time_t) - 1 && ts->tv_nsec == (long)-1) + return USEC_INFINITY; - if ((usec_t) ts->tv_sec > (UINT64_MAX - (ts->tv_nsec / NSEC_PER_USEC)) / USEC_PER_SEC) - return USEC_INFINITY; + if ((usec_t) ts->tv_sec > + (UINT64_MAX - (ts->tv_nsec / NSEC_PER_USEC)) / USEC_PER_SEC) + return USEC_INFINITY; - return - (usec_t) ts->tv_sec * USEC_PER_SEC + - (usec_t) ts->tv_nsec / NSEC_PER_USEC; + return + (usec_t) ts->tv_sec * USEC_PER_SEC + + (usec_t) ts->tv_nsec / NSEC_PER_USEC; } -char* dirname_malloc(const char *path) { - char *d, *dir, *dir2; +char *dirname_malloc(const char *path) +{ + char *d, *dir, *dir2; - d = strdup(path); - if (!d) - return NULL; - dir = dirname(d); - assert(dir); + d = strdup(path); + if (!d) + return NULL; + dir = dirname(d); + assert(dir); - if (dir != d) { - dir2 = strdup(dir); - free(d); - return dir2; - } + if (dir != d) { + dir2 = strdup(dir); + free(d); + return dir2; + } - return dir; + return dir; } -char hexchar(int x) { - static const char table[16] = "0123456789abcdef"; +char hexchar(int x) +{ + static const char table[16] = "0123456789abcdef"; - return table[x & 15]; + return table[x & 15]; } -int unhexchar(char c) { +int unhexchar(char c) +{ - if (c >= '0' && c <= '9') - return c - '0'; + if (c >= '0' && c <= '9') + return c - '0'; - if (c >= 'a' && c <= 'f') - return c - 'a' + 10; + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; - if (c >= 'A' && c <= 'F') - return c - 'A' + 10; + if (c >= 'A' && c <= 'F') + return c - 'A' + 10; - return -EINVAL; + return -EINVAL; } -int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid) { - assert(path); +int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid) +{ + assert(path); - /* Under the assumption that we are running privileged we - * first change the access mode and only then hand out - * ownership to avoid a window where access is too open. */ + /* Under the assumption that we are running privileged we + * first change the access mode and only then hand out + * ownership to avoid a window where access is too open. */ - if (mode != MODE_INVALID) - if (chmod(path, mode) < 0) - return -errno; + if (mode != MODE_INVALID) + if (chmod(path, mode) < 0) + return -errno; - if (uid != UID_INVALID || gid != GID_INVALID) - if (chown(path, uid, gid) < 0) - return -errno; + if (uid != UID_INVALID || gid != GID_INVALID) + if (chown(path, uid, gid) < 0) + return -errno; - return 0; + return 0; } -int is_dir(const char* path, bool follow) { - struct stat st; - int r; +int is_dir(const char *path, bool follow) +{ + struct stat st; + int r; - if (follow) - r = stat(path, &st); - else - r = lstat(path, &st); - if (r < 0) - return -errno; + if (follow) + r = stat(path, &st); + else + r = lstat(path, &st); + if (r < 0) + return -errno; - return !!S_ISDIR(st.st_mode); + return ! !S_ISDIR(st.st_mode); } -int close_nointr(int fd) { - assert(fd >= 0); - - if (close(fd) >= 0) - return 0; - - /* - * Just ignore EINTR; a retry loop is the wrong thing to do on - * Linux. - * - * http://lkml.indiana.edu/hypermail/linux/kernel/0509.1/0877.html - * https://bugzilla.gnome.org/show_bug.cgi?id=682819 - * http://utcc.utoronto.ca/~cks/space/blog/unix/CloseEINTR - * https://sites.google.com/site/michaelsafyan/software-engineering/checkforeintrwheninvokingclosethinkagain - */ - if (errno == EINTR) - return 0; - - return -errno; +int close_nointr(int fd) +{ + assert(fd >= 0); + + if (close(fd) >= 0) + return 0; + + /* + * Just ignore EINTR; a retry loop is the wrong thing to do on + * Linux. + * + * http://lkml.indiana.edu/hypermail/linux/kernel/0509.1/0877.html + * https://bugzilla.gnome.org/show_bug.cgi?id=682819 + * http://utcc.utoronto.ca/~cks/space/blog/unix/CloseEINTR + * https://sites.google.com/site/michaelsafyan/software-engineering/checkforeintrwheninvokingclosethinkagain + */ + if (errno == EINTR) + return 0; + + return -errno; } -int flush_fd(int fd) { - struct pollfd pollfd = { - .fd = fd, - .events = POLLIN, - }; +int flush_fd(int fd) +{ + struct pollfd pollfd = { + .fd = fd, + .events = POLLIN, + }; - for (;;) { - char buf[LINE_MAX]; - ssize_t l; - int r; + for (;;) { + char buf[LINE_MAX]; + ssize_t l; + int r; - r = poll(&pollfd, 1, 0); - if (r < 0) { - if (errno == EINTR) - continue; + r = poll(&pollfd, 1, 0); + if (r < 0) { + if (errno == EINTR) + continue; - return -errno; + return -errno; - } else if (r == 0) - return 0; + } else if (r == 0) + return 0; - l = read(fd, buf, sizeof(buf)); - if (l < 0) { + l = read(fd, buf, sizeof(buf)); + if (l < 0) { - if (errno == EINTR) - continue; + if (errno == EINTR) + continue; - if (errno == EAGAIN) - return 0; + if (errno == EAGAIN) + return 0; - return -errno; - } else if (l == 0) - return 0; - } + return -errno; + } else if (l == 0) + return 0; + } } +int safe_close(int fd) +{ -int safe_close(int fd) { + /* + * Like close_nointr() but cannot fail. Guarantees errno is + * unchanged. Is a NOP with negative fds passed, and returns + * -1, so that it can be used in this syntax: + * + * fd = safe_close(fd); + */ - /* - * Like close_nointr() but cannot fail. Guarantees errno is - * unchanged. Is a NOP with negative fds passed, and returns - * -1, so that it can be used in this syntax: - * - * fd = safe_close(fd); - */ + if (fd >= 0) { + int errsv = errno; - if (fd >= 0) { - int errsv = errno; + /* The kernel might return pretty much any error code + * via close(), but the fd will be closed anyway. The + * only condition we want to check for here is whether + * the fd was invalid at all... */ - /* The kernel might return pretty much any error code - * via close(), but the fd will be closed anyway. The - * only condition we want to check for here is whether - * the fd was invalid at all... */ + assert_se(close_nointr(fd) != -EBADF); - assert_se(close_nointr(fd) != -EBADF); - - errno = errsv; - } + errno = errsv; + } - return -1; + return -1; } +int fd_wait_for_event(int fd, int event, usec_t t) +{ -int fd_wait_for_event(int fd, int event, usec_t t) { + struct pollfd pollfd = { + .fd = fd, + .events = event, + }; - struct pollfd pollfd = { - .fd = fd, - .events = event, - }; + struct timespec ts; + int r; - struct timespec ts; - int r; + r = ppoll(&pollfd, 1, + t == USEC_INFINITY ? NULL : timespec_store(&ts, t), NULL); + if (r < 0) + return -errno; - r = ppoll(&pollfd, 1, t == USEC_INFINITY ? NULL : timespec_store(&ts, t), NULL); - if (r < 0) - return -errno; + if (r == 0) + return 0; - if (r == 0) - return 0; - - return pollfd.revents; + return pollfd.revents; } -ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll) { - uint8_t *p = buf; - ssize_t n = 0; +ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll) +{ + uint8_t *p = buf; + ssize_t n = 0; - assert(fd >= 0); - assert(buf); + assert(fd >= 0); + assert(buf); - while (nbytes > 0) { - ssize_t k; + while (nbytes > 0) { + ssize_t k; - k = read(fd, p, nbytes); - if (k < 0) { - if (errno == EINTR) - continue; + k = read(fd, p, nbytes); + if (k < 0) { + if (errno == EINTR) + continue; - if (errno == EAGAIN && do_poll) { + if (errno == EAGAIN && do_poll) { - /* We knowingly ignore any return value here, - * and expect that any error/EOF is reported - * via read() */ + /* We knowingly ignore any return value here, + * and expect that any error/EOF is reported + * via read() */ - fd_wait_for_event(fd, POLLIN, USEC_INFINITY); - continue; - } + fd_wait_for_event(fd, POLLIN, USEC_INFINITY); + continue; + } - return n > 0 ? n : -errno; - } + return n > 0 ? n : -errno; + } - if (k == 0) - return n; + if (k == 0) + return n; - p += k; - nbytes -= k; - n += k; - } + p += k; + nbytes -= k; + n += k; + } - return n; + return n; } -int loop_read_exact(int fd, void *buf, size_t nbytes, bool do_poll) { - ssize_t n; +int loop_read_exact(int fd, void *buf, size_t nbytes, bool do_poll) +{ + ssize_t n; - n = loop_read(fd, buf, nbytes, do_poll); - if (n < 0) - return n; - if ((size_t) n != nbytes) - return -EIO; - return 0; + n = loop_read(fd, buf, nbytes, do_poll); + if (n < 0) + return n; + if ((size_t) n != nbytes) + return -EIO; + return 0; } - // get task ID (no glibc wrapper around this...) -pid_t gettid(void) { - return syscall( __NR_gettid ); +pid_t gettid(void) +{ + return syscall(__NR_gettid); } -int dev_urandom(void *p, size_t n) { - static int have_syscall = -1; - - int fd = -1; - int r; - - /* Gathers some randomness from the kernel. This call will - * never block, and will always return some data from the - * kernel, regardless if the random pool is fully initialized - * or not. It thus makes no guarantee for the quality of the - * returned entropy, but is good enough for or usual usecases - * of seeding the hash functions for hashtable */ - - fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY); - if (fd < 0) { - return errno == ENOENT ? -ENOSYS : -errno; - } - - int rc = loop_read_exact(fd, p, n, true); - close( fd ); - return rc; +int dev_urandom(void *p, size_t n) +{ + static int have_syscall = -1; + + int fd = -1; + int r; + + /* Gathers some randomness from the kernel. This call will + * never block, and will always return some data from the + * kernel, regardless if the random pool is fully initialized + * or not. It thus makes no guarantee for the quality of the + * returned entropy, but is good enough for or usual usecases + * of seeding the hash functions for hashtable */ + + fd = open("/dev/urandom", O_RDONLY | O_CLOEXEC | O_NOCTTY); + if (fd < 0) { + return errno == ENOENT ? -ENOSYS : -errno; + } + + int rc = loop_read_exact(fd, p, n, true); + close(fd); + return rc; } -void initialize_srand(void) { - static bool srand_called = false; - unsigned x; +void initialize_srand(void) +{ + static bool srand_called = false; + unsigned x; #ifdef HAVE_SYS_AUXV_H - void *auxv; + void *auxv; #endif - if (srand_called) - return; + if (srand_called) + return; - x = 0; + x = 0; #ifdef HAVE_SYS_AUXV_H - /* The kernel provides us with a bit of entropy in auxv, so - * let's try to make use of that to seed the pseudo-random - * generator. It's better than nothing... */ + /* The kernel provides us with a bit of entropy in auxv, so + * let's try to make use of that to seed the pseudo-random + * generator. It's better than nothing... */ - auxv = (void*) getauxval(AT_RANDOM); - if (auxv) - x ^= *(unsigned*) auxv; + auxv = (void *)getauxval(AT_RANDOM); + if (auxv) + x ^= *(unsigned *)auxv; #endif - x ^= (unsigned) now(CLOCK_REALTIME); - x ^= (unsigned) gettid(); + x ^= (unsigned)now(CLOCK_REALTIME); + x ^= (unsigned)gettid(); - srand(x); - srand_called = true; + srand(x); + srand_called = true; } -void random_bytes(void *p, size_t n) { - uint8_t *q; - int r; +void random_bytes(void *p, size_t n) +{ + uint8_t *q; + int r; - r = dev_urandom(p, n); - if (r >= 0) - return; + r = dev_urandom(p, n); + if (r >= 0) + return; - /* If some idiot made /dev/urandom unavailable to us, he'll - * get a PRNG instead. */ + /* If some idiot made /dev/urandom unavailable to us, he'll + * get a PRNG instead. */ - initialize_srand(); + initialize_srand(); - for (q = p; q < (uint8_t*) p + n; q ++) - *q = rand(); + for (q = p; q < (uint8_t *) p + n; q++) + *q = rand(); } -bool is_main_thread(void) { - - return (getpid() == gettid()); -} +bool is_main_thread(void) +{ -size_t page_size(void) { - - int r = sysconf(_SC_PAGESIZE); - assert(r > 0); - - return r; + return (getpid() == gettid()); } +size_t page_size(void) +{ + + int r = sysconf(_SC_PAGESIZE); + assert(r > 0); -bool streq_ptr(const char *a, const char *b) { + return r; +} - /* Like streq(), but tries to make sense of NULL pointers */ +bool streq_ptr(const char *a, const char *b) +{ - if (a && b) - return streq(a, b); + /* Like streq(), but tries to make sense of NULL pointers */ - if (!a && !b) - return true; + if (a && b) + return streq(a, b); - return false; -} \ No newline at end of file + if (!a && !b) + return true; + + return false; +} diff --git a/libudev-compat/util.h b/libudev-compat/util.h index 1a3ba1d..f2611a2 100644 --- a/libudev-compat/util.h +++ b/libudev-compat/util.h @@ -56,7 +56,7 @@ #include #include #include -#include // for gettid() +#include // for gettid() #include "log.h" @@ -127,18 +127,17 @@ bool streq_ptr(const char *a, const char *b); #ifndef MAX_HANDLE_SZ #define MAX_HANDLE_SZ 128 -struct file_handle -{ - unsigned int handle_bytes; - int handle_type; - /* File identifier. */ - unsigned char f_handle[0]; +struct file_handle { + unsigned int handle_bytes; + int handle_type; + /* File identifier. */ + unsigned char f_handle[0]; }; #endif union file_handle_union { - struct file_handle handle; - char padding[sizeof(struct file_handle) + MAX_HANDLE_SZ]; + struct file_handle handle; + char padding[sizeof(struct file_handle) + MAX_HANDLE_SZ]; }; #define FILE_HANDLE_INIT { .handle.handle_bytes = MAX_HANDLE_SZ } @@ -150,19 +149,19 @@ union file_handle_union { } \ break; \ } else - -static inline size_t ALIGN_TO(size_t l, size_t ali) { - return ((l + ali - 1) & ~(ali - 1)); +static inline size_t ALIGN_TO(size_t l, size_t ali) +{ + return ((l + ali - 1) & ~(ali - 1)); } -size_t page_size(void) _pure_; +size_t page_size(void)_pure_; #define PAGE_ALIGN(l) ALIGN_TO((l), page_size()) - + ////////// reference counting typedef struct { - volatile unsigned _value; + volatile unsigned _value; } RefCount; #define REFCNT_GET(r) ((r)._value) @@ -195,14 +194,15 @@ struct timespec *timespec_store(struct timespec *ts, usec_t u); ////////// string functions -static inline char *startswith(const char *s, const char *prefix) { - size_t l; +static inline char *startswith(const char *s, const char *prefix) +{ + size_t l; - l = strlen(prefix); - if (strncmp(s, prefix, l) == 0) - return (char*) s + l; + l = strlen(prefix); + if (strncmp(s, prefix, l) == 0) + return (char *)s + l; - return NULL; + return NULL; } #define strjoina(a, ...) \ @@ -230,7 +230,7 @@ static inline char *startswith(const char *s, const char *prefix) { sizeof(type) <= 4 ? 10 : \ sizeof(type) <= 8 ? 20 : sizeof(int[-2*(sizeof(type) > 8)]))) -char* dirname_malloc(const char *path); +char *dirname_malloc(const char *path); char hexchar(int x) _const_; int unhexchar(char c) _const_; @@ -239,8 +239,7 @@ int unhexchar(char c) _const_; #define STRV_FOREACH(s, l) \ for ((s) = (l); (s) && *(s); (s)++) - - + //////////// memory functions #define _cleanup_(x) __attribute__((cleanup(x))) @@ -252,11 +251,10 @@ int unhexchar(char c) _const_; } \ struct __useless_struct_to_allow_trailing_semicolon__ - -DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, fclose); -DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, pclose); -DEFINE_TRIVIAL_CLEANUP_FUNC(DIR*, closedir); -DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, endmntent); +DEFINE_TRIVIAL_CLEANUP_FUNC(FILE *, fclose); +DEFINE_TRIVIAL_CLEANUP_FUNC(FILE *, pclose); +DEFINE_TRIVIAL_CLEANUP_FUNC(DIR *, closedir); +DEFINE_TRIVIAL_CLEANUP_FUNC(FILE *, endmntent); #define _cleanup_free_ _cleanup_(freep) #define _cleanup_close_ _cleanup_(closep) @@ -268,21 +266,24 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, endmntent); #define _cleanup_endmntent_ _cleanup_(endmntentp) #define _cleanup_close_pair_ _cleanup_(close_pairp) -_malloc_ _alloc_(1, 2) static inline void *malloc_multiply(size_t a, size_t b) { - if (_unlikely_(b != 0 && a > ((size_t) -1) / b)) - return NULL; +_malloc_ _alloc_(1, 2) +static inline void *malloc_multiply(size_t a, size_t b) +{ + if (_unlikely_(b != 0 && a > ((size_t) - 1) / b)) + return NULL; - return malloc(a * b); + return malloc(a * b); } -_alloc_(2, 3) static inline void *realloc_multiply(void *p, size_t a, size_t b) { - if (_unlikely_(b != 0 && a > ((size_t) -1) / b)) - return NULL; +_alloc_(2, 3) +static inline void *realloc_multiply(void *p, size_t a, size_t b) +{ + if (_unlikely_(b != 0 && a > ((size_t) - 1) / b)) + return NULL; - return realloc(p, a * b); + return realloc(p, a * b); } - ////////// sanity checks #define assert_return(expr, r) \ @@ -293,21 +294,19 @@ _alloc_(2, 3) static inline void *realloc_multiply(void *p, size_t a, size_t b) } \ } while (false) - #define assert_se(expr) \ do { \ if (_unlikely_(!(expr))) \ log_error("Assertion failure: '%s'", #expr); \ - } while (false) - - + } while (false) + #define DISABLE_WARNING_DECLARATION_AFTER_STATEMENT \ _Pragma("GCC diagnostic push"); \ _Pragma("GCC diagnostic ignored \"-Wdeclaration-after-statement\"") - + #define REENABLE_WARNING \ _Pragma("GCC diagnostic pop") - + #if defined(static_assert) /* static_assert() is sometimes defined in a way that trips up * -Wdeclaration-after-statement, hence let's temporarily turn off @@ -329,7 +328,7 @@ _alloc_(2, 3) static inline void *realloc_multiply(void *p, size_t a, size_t b) do { \ log_error("Not reached: %s", t); \ } while (false) - + ////////// type functions #define MIN( a, b ) ((a) < (b) ? (a) : (b)) @@ -350,37 +349,40 @@ _alloc_(2, 3) static inline void *realloc_multiply(void *p, size_t a, size_t b) ///////// misc inline functions - /** * Normal qsort requires base to be nonnull. Here were require * that only if nmemb > 0. */ static inline void qsort_safe(void *base, size_t nmemb, size_t size, - int (*compar)(const void *, const void *)) { - if (nmemb) { - assert(base); - qsort(base, nmemb, size, compar); - } + int (*compar) (const void *, const void *)) +{ + if (nmemb) { + assert(base); + qsort(base, nmemb, size, compar); + } } -static inline void *mempset(void *s, int c, size_t n) { - memset(s, c, n); - return (uint8_t*)s + n; +static inline void *mempset(void *s, int c, size_t n) +{ + memset(s, c, n); + return (uint8_t *) s + n; } -static inline unsigned log2u(unsigned x) { - assert(x > 0); +static inline unsigned log2u(unsigned x) +{ + assert(x > 0); - return sizeof(unsigned) * 8 - __builtin_clz(x) - 1; + return sizeof(unsigned) * 8 - __builtin_clz(x) - 1; } -static inline unsigned log2u_round_up(unsigned x) { - assert(x > 0); +static inline unsigned log2u_round_up(unsigned x) +{ + assert(x > 0); - if (x == 1) - return 0; + if (x == 1) + return 0; - return log2u(x - 1) + 1; + return log2u(x - 1) + 1; } ///////// misc functions diff --git a/libvdev/config.c b/libvdev/config.c index e1368b3..9aa0766 100644 --- a/libvdev/config.c +++ b/libvdev/config.c @@ -27,444 +27,452 @@ #include "ini.h" // FUSE reserved options -static const char* FUSE_OPT_S = "-s"; -static const char* FUSE_OPT_O = "-o"; -static const char* FUSE_OPT_D = "-d"; -static const char* FUSE_OPT_F = "-f"; +static const char *FUSE_OPT_S = "-s"; +static const char *FUSE_OPT_O = "-o"; +static const char *FUSE_OPT_D = "-d"; +static const char *FUSE_OPT_F = "-f"; // ini parser callback // return 1 on parsed (WARNING: masks OOM) // return 0 on not parsed -static int vdev_config_ini_parser( void* userdata, char const* section, char const* name, char const* value ) { - - struct vdev_config* conf = (struct vdev_config*)userdata; - bool success = false; - int rc = 0; - - if( strcmp( section, VDEV_CONFIG_NAME ) == 0 ) { - - if( strcmp( name, VDEV_CONFIG_ACLS ) == 0 ) { - - if( conf->acls_dir == NULL ) { - // save this - conf->acls_dir = vdev_strdup_or_null( value ); - } - return 1; - } - - if( strcmp( name, VDEV_CONFIG_ACTIONS ) == 0 ) { - - if( conf->acts_dir == NULL ) { - // save this - conf->acts_dir = vdev_strdup_or_null( value ); - } - - return 1; - } - - if( strcmp( name, VDEV_CONFIG_HELPERS ) == 0 ) { - - if( conf->helpers_dir == NULL ) { - // save this - conf->helpers_dir = vdev_strdup_or_null( value ); - } - - return 1; - } - - if( strcmp( name, VDEV_CONFIG_DEFAULT_MODE ) == 0 ) { - - char* tmp = NULL; - conf->default_mode = (mode_t)strtoul( value, &tmp, 8 ); - - if( *tmp != '\0' ) { - - fprintf(stderr, "Invalid value '%s' for '%s'\n", value, name ); - return 0; - } - else { - - return 1; - } - } - - if( strcmp( name, VDEV_CONFIG_DEFAULT_POLICY ) == 0 ) { - - conf->default_policy = strcasecmp( value, "allow" ) ? 1 : 0; - return 1; - } - - if( strcmp( name, VDEV_CONFIG_PIDFILE_PATH ) == 0 ) { - - if( conf->pidfile_path == NULL ) { - conf->pidfile_path = vdev_strdup_or_null( value ); - } - - return 1; - } - - if( strcmp( name, VDEV_CONFIG_LOGFILE_PATH ) == 0 ) { - - if( conf->logfile_path == NULL ) { - conf->logfile_path = vdev_strdup_or_null( value ); - } - - return 1; - } - - if( strcmp( name, VDEV_CONFIG_LOG_LEVEL ) == 0 ) { - - if( strcasecmp( value, "debug" ) == 0 ) { - - conf->debug_level = VDEV_LOGLEVEL_DEBUG; - conf->error_level = VDEV_LOGLEVEL_WARN; - } - else if( strcasecmp( value, "info" ) == 0 ) { - - conf->debug_level = VDEV_LOGLEVEL_INFO; - conf->error_level = VDEV_LOGLEVEL_WARN; - } - else if( strcasecmp( value, "warn" ) == 0 || strcasecmp( value, "warning" ) == 0 ) { - - conf->debug_level = VDEV_LOGLEVEL_NONE; - conf->error_level = VDEV_LOGLEVEL_WARN; - } - else if( strcasecmp( value, "error" ) == 0 || strcasecmp( value, "critical" ) == 0 ) { - - conf->debug_level = VDEV_LOGLEVEL_NONE; - conf->error_level = VDEV_LOGLEVEL_ERROR; - } - else { - // warn about unknown option value - // fallover to debug and warn - fprintf(stderr, "Unrecognized value '%s' for '%s'\n", value, name ); - conf->debug_level = VDEV_LOGLEVEL_DEBUG; - conf->error_level = VDEV_LOGLEVEL_WARN; - // return 0; - } - - return 1; - } - - if( strcmp( name, VDEV_CONFIG_MOUNTPOINT ) == 0 ) { - - if( conf->mountpoint == NULL ) { - conf->mountpoint = vdev_strdup_or_null( value ); - } - - return 1; - } - - if( strcmp( name, VDEV_CONFIG_COLDPLUG_ONLY ) == 0 ) { - - if( strcasecmp( name, "true" ) == 0 ) { - - conf->coldplug_only = true; - } - else if( strcasecmp( name, "false" ) == 0 ) { - - conf->coldplug_only = false; - } - else if( !conf->coldplug_only ) { - - // maybe it's 0 or non-zero? - conf->coldplug_only = (bool)vdev_parse_uint64( value, &success ); - if( !success ) { - - fprintf(stderr, "Invalid value '%s' for '%s'\n", value, name ); - return 0; - } - else { - - return 1; - } - } - } - - if( strcmp( name, VDEV_CONFIG_PRESEED ) == 0 ) { - - if( conf->preseed_path == NULL ) { - - conf->preseed_path = vdev_strdup_or_null( value ); - } - - return 1; - } - - return 1; - } - - if( strcmp( section, VDEV_OS_CONFIG_NAME ) == 0 ) { - - // OS-specific config value - rc = vdev_params_add( &conf->os_config, name, value ); - if( rc != 0 ) { - - return 0; - } - return 1; - } - - fprintf(stderr, "Unrecognized field '%s'\n", name); - return 1; -} +static int vdev_config_ini_parser(void *userdata, char const *section, + char const *name, char const *value) +{ + struct vdev_config *conf = (struct vdev_config *)userdata; + bool success = false; + int rc = 0; -// config sanity check -int vdev_config_sanity_check( struct vdev_config* conf ) { - - int rc = 0; - - if( conf->acls_dir == NULL ) { - - fprintf(stderr, "[ERROR]: missing acls\n"); - rc = -EINVAL; - } - - if( conf->acts_dir == NULL ) { - - fprintf(stderr, "[ERROR]: missing actions\n"); - rc = -EINVAL; - } - - if( conf->mountpoint == NULL ) { - - fprintf(stderr, "[ERROR]: missing mountpoint\n"); - rc = -EINVAL; - } - - return rc; + if (strcmp(section, VDEV_CONFIG_NAME) == 0) { + + if (strcmp(name, VDEV_CONFIG_ACLS) == 0) { + + if (conf->acls_dir == NULL) { + // save this + conf->acls_dir = vdev_strdup_or_null(value); + } + return 1; + } + + if (strcmp(name, VDEV_CONFIG_ACTIONS) == 0) { + + if (conf->acts_dir == NULL) { + // save this + conf->acts_dir = vdev_strdup_or_null(value); + } + + return 1; + } + + if (strcmp(name, VDEV_CONFIG_HELPERS) == 0) { + + if (conf->helpers_dir == NULL) { + // save this + conf->helpers_dir = vdev_strdup_or_null(value); + } + + return 1; + } + + if (strcmp(name, VDEV_CONFIG_DEFAULT_MODE) == 0) { + + char *tmp = NULL; + conf->default_mode = (mode_t) strtoul(value, &tmp, 8); + + if (*tmp != '\0') { + + fprintf(stderr, "Invalid value '%s' for '%s'\n", + value, name); + return 0; + } else { + + return 1; + } + } + + if (strcmp(name, VDEV_CONFIG_DEFAULT_POLICY) == 0) { + + conf->default_policy = + strcasecmp(value, "allow") ? 1 : 0; + return 1; + } + + if (strcmp(name, VDEV_CONFIG_PIDFILE_PATH) == 0) { + + if (conf->pidfile_path == NULL) { + conf->pidfile_path = vdev_strdup_or_null(value); + } + + return 1; + } + + if (strcmp(name, VDEV_CONFIG_LOGFILE_PATH) == 0) { + + if (conf->logfile_path == NULL) { + conf->logfile_path = vdev_strdup_or_null(value); + } + + return 1; + } + + if (strcmp(name, VDEV_CONFIG_LOG_LEVEL) == 0) { + + if (strcasecmp(value, "debug") == 0) { + + conf->debug_level = VDEV_LOGLEVEL_DEBUG; + conf->error_level = VDEV_LOGLEVEL_WARN; + } else if (strcasecmp(value, "info") == 0) { + + conf->debug_level = VDEV_LOGLEVEL_INFO; + conf->error_level = VDEV_LOGLEVEL_WARN; + } else if (strcasecmp(value, "warn") == 0 + || strcasecmp(value, "warning") == 0) { + + conf->debug_level = VDEV_LOGLEVEL_NONE; + conf->error_level = VDEV_LOGLEVEL_WARN; + } else if (strcasecmp(value, "error") == 0 + || strcasecmp(value, "critical") == 0) { + + conf->debug_level = VDEV_LOGLEVEL_NONE; + conf->error_level = VDEV_LOGLEVEL_ERROR; + } else { + // warn about unknown option value + // fallover to debug and warn + fprintf(stderr, + "Unrecognized value '%s' for '%s'\n", + value, name); + conf->debug_level = VDEV_LOGLEVEL_DEBUG; + conf->error_level = VDEV_LOGLEVEL_WARN; + // return 0; + } + + return 1; + } + + if (strcmp(name, VDEV_CONFIG_MOUNTPOINT) == 0) { + + if (conf->mountpoint == NULL) { + conf->mountpoint = vdev_strdup_or_null(value); + } + + return 1; + } + + if (strcmp(name, VDEV_CONFIG_COLDPLUG_ONLY) == 0) { + + if (strcasecmp(name, "true") == 0) { + + conf->coldplug_only = true; + } else if (strcasecmp(name, "false") == 0) { + + conf->coldplug_only = false; + } else if (!conf->coldplug_only) { + + // maybe it's 0 or non-zero? + conf->coldplug_only = + (bool) vdev_parse_uint64(value, &success); + if (!success) { + + fprintf(stderr, + "Invalid value '%s' for '%s'\n", + value, name); + return 0; + } else { + + return 1; + } + } + } + + if (strcmp(name, VDEV_CONFIG_PRESEED) == 0) { + + if (conf->preseed_path == NULL) { + + conf->preseed_path = vdev_strdup_or_null(value); + } + + return 1; + } + + return 1; + } + + if (strcmp(section, VDEV_OS_CONFIG_NAME) == 0) { + + // OS-specific config value + rc = vdev_params_add(&conf->os_config, name, value); + if (rc != 0) { + + return 0; + } + return 1; + } + + fprintf(stderr, "Unrecognized field '%s'\n", name); + return 1; } +// config sanity check +int vdev_config_sanity_check(struct vdev_config *conf) +{ + + int rc = 0; + + if (conf->acls_dir == NULL) { + + fprintf(stderr, "[ERROR]: missing acls\n"); + rc = -EINVAL; + } + + if (conf->acts_dir == NULL) { + + fprintf(stderr, "[ERROR]: missing actions\n"); + rc = -EINVAL; + } + + if (conf->mountpoint == NULL) { + + fprintf(stderr, "[ERROR]: missing mountpoint\n"); + rc = -EINVAL; + } + + return rc; +} // convert a number between 0 and 16 to its hex representation // hex must have at least 2 characters // always succeeds -void vdev_bin_to_hex( unsigned char num, char* hex ) { - - unsigned char upper = num >> 4; - unsigned char lower = num & 0xf; - - if( upper < 10 ) { - hex[0] = upper + '0'; - } - else { - hex[0] = upper + 'A'; - } - - if( lower < 10 ) { - hex[1] = lower + '0'; - } - else { - hex[1] = lower + 'A'; - } +void vdev_bin_to_hex(unsigned char num, char *hex) +{ + + unsigned char upper = num >> 4; + unsigned char lower = num & 0xf; + + if (upper < 10) { + hex[0] = upper + '0'; + } else { + hex[0] = upper + 'A'; + } + + if (lower < 10) { + hex[1] = lower + '0'; + } else { + hex[1] = lower + 'A'; + } } // generate an instance nonce // NOTE: not thread-safe, since it uses mrand48(3) (can't use /dev/urandom, since it doesn't exist yet) // always succeeds -static void vdev_config_make_instance_nonce( struct vdev_config* conf ) { - - char instance[VDEV_CONFIG_INSTANCE_NONCE_LEN]; - - // generate an instance nonce - for( int i = 0; i < VDEV_CONFIG_INSTANCE_NONCE_LEN; i++ ) { - - instance[i] = (char)mrand48(); - } - - memset( conf->instance_str, 0, VDEV_CONFIG_INSTANCE_NONCE_STRLEN ); - - for( int i = 0; i < VDEV_CONFIG_INSTANCE_NONCE_LEN; i++ ) { - - vdev_bin_to_hex( (unsigned char)instance[i], &conf->instance_str[2*i] ); - } +static void vdev_config_make_instance_nonce(struct vdev_config *conf) +{ + + char instance[VDEV_CONFIG_INSTANCE_NONCE_LEN]; + + // generate an instance nonce + for (int i = 0; i < VDEV_CONFIG_INSTANCE_NONCE_LEN; i++) { + + instance[i] = (char)mrand48(); + } + + memset(conf->instance_str, 0, VDEV_CONFIG_INSTANCE_NONCE_STRLEN); + + for (int i = 0; i < VDEV_CONFIG_INSTANCE_NONCE_LEN; i++) { + + vdev_bin_to_hex((unsigned char)instance[i], + &conf->instance_str[2 * i]); + } } - // initialize a config // always succeeds -int vdev_config_init( struct vdev_config* conf ) { - - memset( conf, 0, sizeof(struct vdev_config) ); - return 0; +int vdev_config_init(struct vdev_config *conf) +{ + + memset(conf, 0, sizeof(struct vdev_config)); + return 0; } // load from a file, by path // return on on success // return -errno on failure to open -int vdev_config_load( char const* path, struct vdev_config* conf ) { - - FILE* f = NULL; - int rc = 0; - - f = fopen( path, "r" ); - if( f == NULL ) { - rc = -errno; - return rc; - } - - rc = vdev_config_load_file( f, conf ); - - fclose( f ); - - if( rc == 0 ) { - - vdev_config_make_instance_nonce( conf ); - } - return rc; +int vdev_config_load(char const *path, struct vdev_config *conf) +{ + + FILE *f = NULL; + int rc = 0; + + f = fopen(path, "r"); + if (f == NULL) { + rc = -errno; + return rc; + } + + rc = vdev_config_load_file(f, conf); + + fclose(f); + + if (rc == 0) { + + vdev_config_make_instance_nonce(conf); + } + return rc; } // load from a file // return 0 on success // return -errno on failure to load -int vdev_config_load_file( FILE* file, struct vdev_config* conf ) { - - int rc = 0; - - rc = ini_parse_file( file, vdev_config_ini_parser, conf ); - if( rc != 0 ) { - vdev_error("ini_parse_file(config) rc = %d\n", rc ); - vdev_config_free( conf ); - - return rc; - } - - // convert paths - rc = vdev_config_fullpaths( conf ); - if( rc != 0 ) { - - vdev_error("vdev_config_fullpaths: %s\n", strerror(-rc) ); - vdev_config_free( conf ); - return rc; - } - - return rc; +int vdev_config_load_file(FILE * file, struct vdev_config *conf) +{ + + int rc = 0; + + rc = ini_parse_file(file, vdev_config_ini_parser, conf); + if (rc != 0) { + vdev_error("ini_parse_file(config) rc = %d\n", rc); + vdev_config_free(conf); + + return rc; + } + // convert paths + rc = vdev_config_fullpaths(conf); + if (rc != 0) { + + vdev_error("vdev_config_fullpaths: %s\n", strerror(-rc)); + vdev_config_free(conf); + return rc; + } + + return rc; } // free a config // always succeeds -int vdev_config_free( struct vdev_config* conf ) { - - if( conf->acls_dir != NULL ) { - - free( conf->acls_dir ); - conf->acls_dir = NULL; - } - - if( conf->acts_dir != NULL ) { - - free( conf->acts_dir ); - conf->acts_dir = NULL; - } - - if( conf->os_config != NULL ) { - - vdev_params_free( conf->os_config ); - conf->os_config = NULL; - } - - if( conf->helpers_dir != NULL ) { - - free( conf->helpers_dir ); - conf->helpers_dir = NULL; - } - - if( conf->config_path != NULL ) { - - free( conf->config_path ); - conf->config_path = NULL; - } - - if( conf->mountpoint != NULL ) { - - free( conf->mountpoint ); - conf->mountpoint = NULL; - } - - if( conf->preseed_path != NULL ) { - - free( conf->preseed_path ); - conf->preseed_path = NULL; - } - - if( conf->logfile_path != NULL ) { - - free( conf->logfile_path ); - conf->logfile_path = NULL; - } - - if( conf->pidfile_path != NULL ) { - - free( conf->pidfile_path ); - conf->pidfile_path = NULL; - } - - return 0; -} +int vdev_config_free(struct vdev_config *conf) +{ + + if (conf->acls_dir != NULL) { + + free(conf->acls_dir); + conf->acls_dir = NULL; + } + + if (conf->acts_dir != NULL) { + free(conf->acts_dir); + conf->acts_dir = NULL; + } + + if (conf->os_config != NULL) { + + vdev_params_free(conf->os_config); + conf->os_config = NULL; + } + + if (conf->helpers_dir != NULL) { + + free(conf->helpers_dir); + conf->helpers_dir = NULL; + } + + if (conf->config_path != NULL) { + + free(conf->config_path); + conf->config_path = NULL; + } + + if (conf->mountpoint != NULL) { + + free(conf->mountpoint); + conf->mountpoint = NULL; + } + + if (conf->preseed_path != NULL) { + + free(conf->preseed_path); + conf->preseed_path = NULL; + } + + if (conf->logfile_path != NULL) { + + free(conf->logfile_path); + conf->logfile_path = NULL; + } + + if (conf->pidfile_path != NULL) { + + free(conf->pidfile_path); + conf->pidfile_path = NULL; + } + + return 0; +} // convert all paths in the config to absolute paths // return 0 on success // return -ENOMEM on OOM // return -ERANGE if cwd is too long -int vdev_config_fullpaths( struct vdev_config* conf ) { - // this int does not seem to be used here - // int rc = 0; - - char** need_fullpath[] = { - &conf->config_path, - &conf->acls_dir, - &conf->acts_dir, - &conf->helpers_dir, - &conf->pidfile_path, - &conf->logfile_path, - &conf->preseed_path, - NULL - }; - - char cwd_buf[ PATH_MAX + 1 ]; - memset( cwd_buf, 0, PATH_MAX + 1 ); - - char* tmp = getcwd( cwd_buf, PATH_MAX ); - if( tmp == NULL ) { - - vdev_error("Current working directory exceeds %u bytes\n", PATH_MAX); - return -ERANGE; - } - - for( int i = 0; need_fullpath[i] != NULL; i++ ) { - - if( need_fullpath[i] != NULL && (*need_fullpath[i]) != NULL ) { - - // if special sentinel string "syslog" is found, don't process it - if( need_fullpath[i] == &conf->logfile_path && strncmp((*need_fullpath[i]), "syslog",7) == 0 ) { - continue; - } - - if( *(need_fullpath[i])[0] != '/' ) { - - // relative path - char* new_path = vdev_fullpath( cwd_buf, *(need_fullpath)[i], NULL ); - if( new_path == NULL ) { - - return -ENOMEM; - } - - free( *(need_fullpath[i]) ); - *(need_fullpath[i]) = new_path; - } - } - } - - return 0; +int vdev_config_fullpaths(struct vdev_config *conf) +{ + // this int does not seem to be used here + // int rc = 0; + + char **need_fullpath[] = { + &conf->config_path, + &conf->acls_dir, + &conf->acts_dir, + &conf->helpers_dir, + &conf->pidfile_path, + &conf->logfile_path, + &conf->preseed_path, + NULL + }; + + char cwd_buf[PATH_MAX + 1]; + memset(cwd_buf, 0, PATH_MAX + 1); + + char *tmp = getcwd(cwd_buf, PATH_MAX); + if (tmp == NULL) { + + vdev_error("Current working directory exceeds %u bytes\n", + PATH_MAX); + return -ERANGE; + } + + for (int i = 0; need_fullpath[i] != NULL; i++) { + + if (need_fullpath[i] != NULL && (*need_fullpath[i]) != NULL) { + + // if special sentinel string "syslog" is found, don't process it + if (need_fullpath[i] == &conf->logfile_path + && strncmp((*need_fullpath[i]), "syslog", 7) == 0) { + continue; + } + + if (*(need_fullpath[i])[0] != '/') { + + // relative path + char *new_path = + vdev_fullpath(cwd_buf, *(need_fullpath)[i], + NULL); + if (new_path == NULL) { + + return -ENOMEM; + } + + free(*(need_fullpath[i])); + *(need_fullpath[i]) = new_path; + } + } + } + + return 0; } - - // print usage statement -int vdev_config_usage( char const* progname ) { - fprintf(stderr, "\ +int vdev_config_usage(char const *progname) +{ + fprintf(stderr, "\ \ Usage: %s [options] mountpoint\n\ Options include:\n\ @@ -493,213 +501,223 @@ Options include:\n\ -h, --help\n\ prints this help message.\n\ and exits early.\n\ -", progname ); - - return 0; +", progname); + + return 0; } // get the mountpoint option, by taking the last argument that wasn't an optarg -static int vdev_config_get_mountpoint_from_fuse( int fuse_argc, char** fuse_argv, char** ret_mountpoint ) { - - *ret_mountpoint = realpath( fuse_argv[ fuse_argc - 1 ], NULL ); - - if( *ret_mountpoint == NULL ) { - - int rc = -errno; - printf("No mountpoint, rc = %d\n", rc); - - for( int i = 0; i < fuse_argc; i++ ) { - printf("argv[%d]: '%s'\n", i, fuse_argv[i]); - } - - return -EINVAL; - } - - return 0; -} +static int vdev_config_get_mountpoint_from_fuse(int fuse_argc, char **fuse_argv, + char **ret_mountpoint) +{ + + *ret_mountpoint = realpath(fuse_argv[fuse_argc - 1], NULL); + if (*ret_mountpoint == NULL) { + + int rc = -errno; + printf("No mountpoint, rc = %d\n", rc); + + for (int i = 0; i < fuse_argc; i++) { + printf("argv[%d]: '%s'\n", i, fuse_argv[i]); + } + + return -EINVAL; + } + + return 0; +} // parse command-line options from argv. // fill in fuse_argv with fuse-specific options. // config must be initialized; this method simply augments it // return 0 on success // return -1 on unrecognized option -int vdev_config_load_from_args( struct vdev_config* config, int argc, char** argv, int* fuse_argc, char** fuse_argv ) { - - static struct option vdev_options[] = { - {"config-file", required_argument, 0, 'c'}, - {"verbose-level", required_argument, 0, 'v'}, - {"logfile", required_argument, 0, 'l'}, - {"pidfile", required_argument, 0, 'p'}, - {"once", no_argument, 0, '1'}, - {"coldplug-only", no_argument, 0, 'n'}, - {"foreground", no_argument, 0, 'f'}, - {"help", no_argument, 0, 'h'}, - {0, 0, 0, 0} - }; - - int rc = 0; - int opt_index = 0; - int c = 0; - int fuse_optind = 0; - - char const* optstr = "c:v:l:o:hf1np:ds"; - - if( fuse_argv != NULL ) { - fuse_argv[fuse_optind] = argv[0]; - fuse_optind++; - } - - while(rc == 0 && c != -1) { - - c = getopt_long(argc, argv, optstr, vdev_options, &opt_index); - // break on -1 missing arguments and -2 help - if( c == -1 || c == -2 ) { - break; - } - - switch( c ) { - - case 'c': { - - if( config->config_path != NULL ) { - free( config->config_path ); - } - - config->config_path = vdev_strdup_or_null( optarg ); - break; - } - - case 'l': { - - if( config->logfile_path != NULL ) { - free( config->logfile_path ); - } - - config->logfile_path = vdev_strdup_or_null( optarg ); - break; - } - - case 'p': { - - if( config->pidfile_path != NULL ) { - free( config->pidfile_path ); - } - - config->pidfile_path = vdev_strdup_or_null( optarg ); - break; - } - - case 'v': { - - long debug_level = 0; - char* tmp = NULL; - - debug_level = strtol( optarg, &tmp, 10 ); - - if( *tmp != '\0' ) { - fprintf(stderr, "Invalid argument for -d\n"); - rc = -1; - } - else { - config->debug_level = debug_level; - } - break; - } - - case 'n': - case '1': { - - config->coldplug_only = true; - break; - } - - case 's': { - // FUSE Option - if( fuse_argv != NULL ) { - fuse_argv[fuse_optind] = (char*)FUSE_OPT_S; - fuse_optind++; - } - - break; - } - - case 'd': { - // FUSE option - if( fuse_argv != NULL ) { - fuse_argv[fuse_optind] = (char*)FUSE_OPT_D; - fuse_optind++; - } - - break; - } - - case 'f': { - // FUSE option - if( fuse_argv != NULL ) { - fuse_argv[fuse_optind] = (char*)FUSE_OPT_F; - fuse_optind++; - } - - config->foreground = true; - break; - } - - case 'o': { - // FUSE option - if( fuse_argv != NULL ) { - fuse_argv[fuse_optind] = (char*)FUSE_OPT_O; - fuse_optind++; - - fuse_argv[fuse_optind] = optarg; - fuse_optind++; - } - - break; - } - - case 'h': { - // command args line help - fprintf(stderr, "Command Line Options Help \n" ); - rc = -2; - break; - } - - default: { - - fprintf(stderr, "Unrecognized option -%c\n", c ); - rc = -1; - break; - } - } - } - - if( rc != 0 ) { - return rc; - } - - if( fuse_argv != NULL ) { - // copy over non-option arguments to fuse_argv - for( int i = optind; i < argc; i++ ) { - - fuse_argv[ fuse_optind ] = argv[i]; - fuse_optind++; - } - - *fuse_argc = fuse_optind; - - // parse FUSE args to get the mountpoint - rc = vdev_config_get_mountpoint_from_fuse( *fuse_argc, fuse_argv, &config->mountpoint ); - } - else { - - // extract mountpoint - config->mountpoint = realpath( argv[ optind ], NULL ); - if( config->mountpoint == NULL ) { - rc = -errno; - fprintf(stderr, "Failed to evaluate '%s': %s\n", argv[optind], strerror(-rc) ); - } - } - return rc; +int vdev_config_load_from_args(struct vdev_config *config, int argc, + char **argv, int *fuse_argc, char **fuse_argv) +{ + + static struct option vdev_options[] = { + {"config-file", required_argument, 0, 'c'}, + {"verbose-level", required_argument, 0, 'v'}, + {"logfile", required_argument, 0, 'l'}, + {"pidfile", required_argument, 0, 'p'}, + {"once", no_argument, 0, '1'}, + {"coldplug-only", no_argument, 0, 'n'}, + {"foreground", no_argument, 0, 'f'}, + {"help", no_argument, 0, 'h'}, + {0, 0, 0, 0} + }; + + int rc = 0; + int opt_index = 0; + int c = 0; + int fuse_optind = 0; + + char const *optstr = "c:v:l:o:hf1np:ds"; + + if (fuse_argv != NULL) { + fuse_argv[fuse_optind] = argv[0]; + fuse_optind++; + } + + while (rc == 0 && c != -1) { + + c = getopt_long(argc, argv, optstr, vdev_options, &opt_index); + // break on -1 missing arguments and -2 help + if (c == -1 || c == -2) { + break; + } + + switch (c) { + + case 'c':{ + + if (config->config_path != NULL) { + free(config->config_path); + } + + config->config_path = + vdev_strdup_or_null(optarg); + break; + } + + case 'l':{ + + if (config->logfile_path != NULL) { + free(config->logfile_path); + } + + config->logfile_path = + vdev_strdup_or_null(optarg); + break; + } + + case 'p':{ + + if (config->pidfile_path != NULL) { + free(config->pidfile_path); + } + + config->pidfile_path = + vdev_strdup_or_null(optarg); + break; + } + + case 'v':{ + + long debug_level = 0; + char *tmp = NULL; + + debug_level = strtol(optarg, &tmp, 10); + + if (*tmp != '\0') { + fprintf(stderr, + "Invalid argument for -d\n"); + rc = -1; + } else { + config->debug_level = debug_level; + } + break; + } + + case 'n': + case '1':{ + + config->coldplug_only = true; + break; + } + + case 's':{ + // FUSE Option + if (fuse_argv != NULL) { + fuse_argv[fuse_optind] = + (char *)FUSE_OPT_S; + fuse_optind++; + } + + break; + } + + case 'd':{ + // FUSE option + if (fuse_argv != NULL) { + fuse_argv[fuse_optind] = + (char *)FUSE_OPT_D; + fuse_optind++; + } + + break; + } + + case 'f':{ + // FUSE option + if (fuse_argv != NULL) { + fuse_argv[fuse_optind] = + (char *)FUSE_OPT_F; + fuse_optind++; + } + + config->foreground = true; + break; + } + + case 'o':{ + // FUSE option + if (fuse_argv != NULL) { + fuse_argv[fuse_optind] = + (char *)FUSE_OPT_O; + fuse_optind++; + + fuse_argv[fuse_optind] = optarg; + fuse_optind++; + } + + break; + } + + case 'h':{ + // command args line help + fprintf(stderr, "Command Line Options Help \n"); + rc = -2; + break; + } + + default:{ + + fprintf(stderr, "Unrecognized option -%c\n", c); + rc = -1; + break; + } + } + } + + if (rc != 0) { + return rc; + } + + if (fuse_argv != NULL) { + // copy over non-option arguments to fuse_argv + for (int i = optind; i < argc; i++) { + + fuse_argv[fuse_optind] = argv[i]; + fuse_optind++; + } + + *fuse_argc = fuse_optind; + + // parse FUSE args to get the mountpoint + rc = vdev_config_get_mountpoint_from_fuse(*fuse_argc, fuse_argv, + &config->mountpoint); + } else { + + // extract mountpoint + config->mountpoint = realpath(argv[optind], NULL); + if (config->mountpoint == NULL) { + rc = -errno; + fprintf(stderr, "Failed to evaluate '%s': %s\n", + argv[optind], strerror(-rc)); + } + } + return rc; } - diff --git a/libvdev/config.h b/libvdev/config.h index f35313f..ebf6160 100644 --- a/libvdev/config.h +++ b/libvdev/config.h @@ -34,7 +34,7 @@ #define VDEV_CONFIG_ACTIONS "actions" #define VDEV_CONFIG_HELPERS "helpers" #define VDEV_CONFIG_DEFAULT_MODE "default_permissions" -#define VDEV_CONFIG_DEFAULT_POLICY "default_policy" // ACL allow or deny +#define VDEV_CONFIG_DEFAULT_POLICY "default_policy" // ACL allow or deny #define VDEV_CONFIG_PIDFILE_PATH "pidfile" #define VDEV_CONFIG_LOGFILE_PATH "logfile" #define VDEV_CONFIG_LOG_LEVEL "loglevel" @@ -42,84 +42,82 @@ #define VDEV_CONFIG_COLDPLUG_ONLY "coldplug_only" #define VDEV_CONFIG_FOREGROUND "foreground" #define VDEV_CONFIG_PRESEED "preseed" -#define VDEV_CONFIG_HELP "help" // simple commandline help +#define VDEV_CONFIG_HELP "help" // simple commandline help #define VDEV_CONFIG_INSTANCE_NONCE_LEN 32 #define VDEV_CONFIG_INSTANCE_NONCE_STRLEN (2*VDEV_CONFIG_INSTANCE_NONCE_LEN + 1) -#define VDEV_OS_QUIRK_DEVICE_EXISTS 0x1 // set this bit if the OS already has the device file--i.e. vdevd is not expected to create it +#define VDEV_OS_QUIRK_DEVICE_EXISTS 0x1 // set this bit if the OS already has the device file--i.e. vdevd is not expected to create it #define vdev_config_has_OS_quirk( quirk_field, quirk ) (((quirk_field) & (quirk)) != 0) #define vdev_config_set_OS_quirk( quirk_field, quirk ) quirk_field |= (quirk) // structure for both file configuration and command-line options struct vdev_config { - - // config file path (used by opts) - char* config_path; - - // preseed script - char* preseed_path; - - // ACLs directory - char* acls_dir; - - // actions directory - char* acts_dir; - - // helpers directory - char* helpers_dir; - - // default policy (0 for deny, 1 for allow) - int default_policy; - - // debug level - int debug_level; - - // error level - int error_level; - - // PID file path - char* pidfile_path; - - // logfile path (set to "syslog" to send directly to syslog) - char* logfile_path; - - // path to where /dev lives - char* mountpoint; - - // coldplug only? - bool coldplug_only; - - // run in the foreground - bool foreground; - - // OS-specific configuration (for keys under "OS") - vdev_params* os_config; - - // default permission bits for mknod - mode_t default_mode; - - // printable 256-bit instance nonce--randomly generated and unique per execution - char instance_str[VDEV_CONFIG_INSTANCE_NONCE_STRLEN]; - - // bitfield of OS-specific quirks - uint64_t OS_quirks; - - // help holder - char help; -}; -C_LINKAGE_BEGIN + // config file path (used by opts) + char *config_path; -int vdev_config_init( struct vdev_config* conf ); -int vdev_config_load( char const* path, struct vdev_config* conf ); -int vdev_config_load_file( FILE* file, struct vdev_config* conf ); -int vdev_config_free( struct vdev_config* conf ); -int vdev_config_usage( char const* progname ); -int vdev_config_load_from_args( struct vdev_config* config, int argc, char** argv, int* fuse_argc, char** fuse_argv ); -int vdev_config_fullpaths( struct vdev_config* config ); + // preseed script + char *preseed_path; -C_LINKAGE_END + // ACLs directory + char *acls_dir; + + // actions directory + char *acts_dir; + + // helpers directory + char *helpers_dir; + + // default policy (0 for deny, 1 for allow) + int default_policy; + + // debug level + int debug_level; + + // error level + int error_level; + + // PID file path + char *pidfile_path; + + // logfile path (set to "syslog" to send directly to syslog) + char *logfile_path; + + // path to where /dev lives + char *mountpoint; + // coldplug only? + bool coldplug_only; + + // run in the foreground + bool foreground; + + // OS-specific configuration (for keys under "OS") + vdev_params *os_config; + + // default permission bits for mknod + mode_t default_mode; + + // printable 256-bit instance nonce--randomly generated and unique per execution + char instance_str[VDEV_CONFIG_INSTANCE_NONCE_STRLEN]; + + // bitfield of OS-specific quirks + uint64_t OS_quirks; + + // help holder + char help; +}; + +C_LINKAGE_BEGIN int vdev_config_init(struct vdev_config *conf); +int vdev_config_load(char const *path, struct vdev_config *conf); +int vdev_config_load_file(FILE * file, struct vdev_config *conf); +int vdev_config_free(struct vdev_config *conf); +int vdev_config_usage(char const *progname); +int vdev_config_load_from_args(struct vdev_config *config, int argc, + char **argv, int *fuse_argc, char **fuse_argv); +int vdev_config_fullpaths(struct vdev_config *config); + +C_LINKAGE_END #endif diff --git a/libvdev/ini.c b/libvdev/ini.c index d6e1661..45a9788 100644 --- a/libvdev/ini.c +++ b/libvdev/ini.c @@ -4,179 +4,199 @@ inih is released under the New BSD license (see LICENSE.txt). Go to the project home page for more info: http://code.google.com/p/inih/ -*/ - +*/ + #include #include #include - + #include "ini.h" - + #if !INI_USE_STACK #include -#endif - +#endif /* */ + #define MAX_SECTION 50 #define MAX_NAME 50 - -/* Strip whitespace chars off end of given string, in place. Return s. */ -static char* rstrip(char* s) -{ - char* p = s + strlen(s); - while (p > s && isspace((unsigned char)(*--p))) - *p = '\0'; - return s; -} - -/* Return pointer to first non-whitespace char in given string. */ -static char* lskip(const char* s) -{ - while (*s && isspace((unsigned char)(*s))) - s++; - return (char*)s; -} - + +/* Strip whitespace chars off end of given string, in place. Return s. */ +static char *rstrip(char *s) +{ + char *p = s + strlen(s); + while (p > s && isspace((unsigned char)(*--p))) + *p = '\0'; + return s; + } + + +/* Return pointer to first non-whitespace char in given string. */ +static char *lskip(const char *s) +{ + while (*s && isspace((unsigned char)(*s))) + s++; + return (char *)s; + } + /* Return pointer to first char c or ';' comment in given string, or pointer to null at end of string if neither found. ';' must be prefixed by a whitespace character to register as a comment. -*/ -static char* find_char_or_comment(const char* s, char c) -{ - int was_whitespace = 0; - while (*s && *s != c && !(was_whitespace && *s == ';')) { - was_whitespace = isspace((unsigned char)(*s)); - s++; - } - return (char*)s; -} - -/* Version of strncpy that ensures dest (size bytes) is null-terminated. */ -static char* strncpy0(char* dest, const char* src, size_t size) -{ - strncpy(dest, src, size); - dest[size - 1] = '\0'; - return dest; -} - -/* See documentation in header file. */ -int ini_parse_file(FILE* file, - int (*handler)(void*, const char*, const char*, - const char*), - void* user) -{ - /* Uses a fair bit of stack (use heap instead if you need to) */ +*/ +static char *find_char_or_comment(const char *s, char c) +{ + int was_whitespace = 0; + while (*s && *s != c && !(was_whitespace && *s == ';')) { + was_whitespace = isspace((unsigned char)(*s)); + s++; + } return (char *)s; + } + +/* Version of strncpy that ensures dest (size bytes) is null-terminated. */ +static char *strncpy0(char *dest, const char *src, size_t size) +{ + strncpy(dest, src, size); + dest[size - 1] = '\0'; + return dest; + } + + +/* See documentation in header file. */ +int ini_parse_file(FILE * file, + int (*handler) (void *, const char *, const char *, + const char *), void *user) +{ + + /* Uses a fair bit of stack (use heap instead if you need to) */ #if INI_USE_STACK - char line[INI_MAX_LINE]; -#else - char* line; -#endif - char section[MAX_SECTION] = ""; - char prev_name[MAX_NAME] = ""; - - char* start; - char* end; - char* name; - char* value; - int lineno = 0; - int error = 0; - + char line[INI_MAX_LINE]; + +#else /* */ + char *line; + +#endif /* */ + char section[MAX_SECTION] = ""; + char prev_name[MAX_NAME] = ""; + char *start; + char *end; + char *name; + char *value; + int lineno = 0; + int error = 0; + #if !INI_USE_STACK - line = (char*)malloc(INI_MAX_LINE); - if (!line) { - return -2; - } -#endif - - /* Scan through file line by line */ - while (fgets(line, INI_MAX_LINE, file) != NULL) { - lineno++; - - start = line; -#if INI_ALLOW_BOM - if (lineno == 1 && (unsigned char)start[0] == 0xEF && - (unsigned char)start[1] == 0xBB && - (unsigned char)start[2] == 0xBF) { - start += 3; - } -#endif - start = lskip(rstrip(start)); + line = (char *)malloc(INI_MAX_LINE); + if (!line) { + return -2; + } - if (*start == ';' || *start == '#') { - /* Per Python ConfigParser, allow '#' comments at start of line */ - } -#if INI_ALLOW_MULTILINE - else if (*prev_name && *start && start > line) { - /* Non-black line with leading whitespace, treat as continuation - of previous name's value (as per Python ConfigParser). */ - if (!handler(user, section, prev_name, start) && !error) - error = lineno; - } -#endif - else if (*start == '[') { - /* A "[section]" line */ - end = find_char_or_comment(start + 1, ']'); - if (*end == ']') { - *end = '\0'; - strncpy0(section, start + 1, sizeof(section)); - *prev_name = '\0'; - } - else if (!error) { - /* No ']' found on section line */ - error = lineno; - } - } - else if (*start && *start != ';') { - /* Not a comment, must be a name[=:]value pair */ - end = find_char_or_comment(start, '='); - if (*end != '=') { - end = find_char_or_comment(start, ':'); - } - if (*end == '=' || *end == ':') { - *end = '\0'; - name = rstrip(start); - value = lskip(end + 1); - end = find_char_or_comment(value, '\0'); - if (*end == ';') - *end = '\0'; - rstrip(value); +#endif /* */ - /* Valid name[=:]value pair found, call handler */ - strncpy0(prev_name, name, sizeof(prev_name)); - if (!handler(user, section, name, value) && !error) - error = lineno; - } - else if (!error) { - /* No '=' or ':' found on name[=:]value line */ - error = lineno; - } - } - + /* Scan through file line by line */ + while (fgets(line, INI_MAX_LINE, file) != NULL) { + lineno++; + start = line; + +#if INI_ALLOW_BOM + if (lineno == 1 && (unsigned char)start[0] == 0xEF && + (unsigned char)start[1] == 0xBB && + (unsigned char)start[2] == 0xBF) { + start += 3; + } + +#endif /* */ + start = lskip(rstrip(start)); + if (*start == ';' || *start == '#') { + + /* Per Python ConfigParser, allow '#' comments at start of line */ + } + +#if INI_ALLOW_MULTILINE + else if (*prev_name && *start && start > line) { + + /* Non-black line with leading whitespace, treat as continuation + of previous name's value (as per Python ConfigParser). */ + if (!handler(user, section, prev_name, start) + && !error) + error = lineno; + } + +#endif /* */ + else if (*start == '[') { + + /* A "[section]" line */ + end = find_char_or_comment(start + 1, ']'); + if (*end == ']') { + *end = '\0'; + strncpy0(section, start + 1, sizeof(section)); + *prev_name = '\0'; + } + + else if (!error) { + + /* No ']' found on section line */ + error = lineno; + } + } + + else if (*start && *start != ';') { + + /* Not a comment, must be a name[=:]value pair */ + end = find_char_or_comment(start, '='); + if (*end != '=') { + end = find_char_or_comment(start, ':'); + } + if (*end == '=' || *end == ':') { + *end = '\0'; + name = rstrip(start); + value = lskip(end + 1); + end = find_char_or_comment(value, '\0'); + if (*end == ';') + *end = '\0'; + rstrip(value); + + /* Valid name[=:]value pair found, call handler */ + strncpy0(prev_name, name, + sizeof(prev_name)); + if (!handler(user, section, name, value) + && !error) + error = lineno; + } + + else if (!error) { + + /* No '=' or ':' found on name[=:]value line */ + error = lineno; + } + } + #if INI_STOP_ON_FIRST_ERROR - if (error) - break; -#endif - } - + if (error) + break; + +#endif /* */ + } + #if !INI_USE_STACK - free(line); -#endif - - return error; -} + free(line); + +#endif /* */ + return error; + } + + +/* See documentation in header file. */ +int ini_parse(const char *filename, + int (*handler) (void *, const char *, const char *, + const char *), void *user) +{ + FILE * file; + int error; + file = fopen(filename, "r"); + if (!file) + return -1; + error = ini_parse_file(file, handler, user); + fclose(file); + return error; + } + -/* See documentation in header file. */ -int ini_parse(const char* filename, - int (*handler)(void*, const char*, const char*, const char*), - void* user) -{ - FILE* file; - int error; - - file = fopen(filename, "r"); - if (!file) - return -1; - error = ini_parse_file(file, handler, user); - fclose(file); - return error; -} diff --git a/libvdev/ini.h b/libvdev/ini.h index 92ef145..6c6d1b7 100644 --- a/libvdev/ini.h +++ b/libvdev/ini.h @@ -3,18 +3,19 @@ inih is released under the New BSD license (see LICENSE.txt). Go to the project home page for more info: http://code.google.com/p/inih/ -*/ - +*/ + #ifndef __INI_H__ #define __INI_H__ - -/* Make this header file easier to include in C++ code */ + +/* Make this header file easier to include in C++ code */ #ifdef __cplusplus -extern "C" { -#endif - +extern "C" { + +#endif /* */ + #include - + /* Parse given INI-style file. May have [section]s, name=value pairs (whitespace stripped), and comments starting with ';' (semicolon). Section is "" if name=value pair parsed before any section heading. name:value @@ -27,51 +28,50 @@ extern "C" { Returns 0 on success, line number of first error on parse error (doesn't stop on first error), -1 on file open error, or -2 on memory allocation error (only when INI_USE_STACK is zero). -*/ -int ini_parse(const char* filename, - int (*handler)(void* user, const char* section, - const char* name, const char* value), - void* user); - +*/ + int ini_parse(const char *filename, + int (*handler) (void *user, const char *section, + const char *name, const char *value), + void *user); + /* Same as ini_parse(), but takes a FILE* instead of filename. This doesn't - close the file when it's finished -- the caller must do that. */ - -int ini_parse_file(FILE* file, - int (*handler)(void* user, const char* section, - const char* name, const char* value), - void* user); - - /* Nonzero to allow multi-line value parsing, in the style of Python's - ConfigParser. If allowed, ini_parse() will call the handler with the same - name for each subsequent line parsed. */ - + close the file when it's finished -- the caller must do that. */ + int ini_parse_file(FILE * file, + int (*handler) (void *user, const char *section, + const char *name, + const char *value), void *user); + + /* Nonzero to allow multi-line value parsing, in the style of Python's + ConfigParser. If allowed, ini_parse() will call the handler with the same + name for each subsequent line parsed. */ + #ifndef INI_ALLOW_MULTILINE #define INI_ALLOW_MULTILINE 0 -#endif - +#endif /* */ + /* Nonzero to allow a UTF-8 BOM sequence (0xEF 0xBB 0xBF) at the start of - the file. See http://code.google.com/p/inih/issues/detail?id=21 */ + the file. See http://code.google.com/p/inih/issues/detail?id=21 */ #ifndef INI_ALLOW_BOM #define INI_ALLOW_BOM 1 -#endif - -/* Nonzero to use stack, zero to use heap (malloc/free). */ +#endif /* */ + +/* Nonzero to use stack, zero to use heap (malloc/free). */ #ifndef INI_USE_STACK #define INI_USE_STACK 1 -#endif - -/* Stop parsing on first error (default is to keep parsing). */ +#endif /* */ + +/* Stop parsing on first error (default is to keep parsing). */ #ifndef INI_STOP_ON_FIRST_ERROR #define INI_STOP_ON_FIRST_ERROR 1 -#endif - -/* Maximum line length for any line in INI file. */ +#endif /* */ + +/* Maximum line length for any line in INI file. */ #ifndef INI_MAX_LINE #define INI_MAX_LINE 4096 -#endif - +#endif /* */ + #ifdef __cplusplus -} -#endif +} +#endif /* */ -#endif /* __INI_H__ */ +#endif /* __INI_H__ */ diff --git a/libvdev/match.c b/libvdev/match.c index 585b754..9109804 100644 --- a/libvdev/match.c +++ b/libvdev/match.c @@ -22,137 +22,141 @@ #include "match.h" // parse a regex -int vdev_match_regex_init( regex_t* regex, char const* str ) { - - int rc = 0; - - rc = regcomp( regex, str, REG_EXTENDED | REG_NEWLINE ); - - if( rc != 0 ) { - - return -EINVAL; - } - else { - return 0; - } +int vdev_match_regex_init(regex_t * regex, char const *str) +{ + + int rc = 0; + + rc = regcomp(regex, str, REG_EXTENDED | REG_NEWLINE); + + if (rc != 0) { + + return -EINVAL; + } else { + return 0; + } } // parse a regex and append it to a list of regexes and strings // return 0 on success // return -EINVAL if the regex is invalid // return -ENOMEM if we're out of memory -int vdev_match_regex_append( char*** strings, regex_t** regexes, size_t* len, char const* next ) { - - // verify that this is a valid regex - regex_t reg; - int rc = 0; - - memset( ®, 0, sizeof(regex_t) ); - - rc = regcomp( ®, next, REG_EXTENDED | REG_NEWLINE | REG_NOSUB ); - if( rc != 0 ) { - - vdev_error("regcomp(%s) rc = %d\n", next, rc ); - return -EINVAL; - } - - char** new_strings = (char**)realloc( *strings, sizeof(char**) * (*len + 2) ); - regex_t* new_regexes = (regex_t*)realloc( *regexes, sizeof(regex_t) * (*len + 1) ); - - if( new_strings == NULL || new_regexes == NULL ) { - return -ENOMEM; - } - - new_strings[*len] = vdev_strdup_or_null( next ); - new_strings[*len + 1] = NULL; - - new_regexes[*len] = reg; - - *strings = new_strings; - *regexes = new_regexes; - - *len = *len + 1; - - return 0; -} +int vdev_match_regex_append(char ***strings, regex_t ** regexes, size_t * len, + char const *next) +{ + + // verify that this is a valid regex + regex_t reg; + int rc = 0; + + memset(®, 0, sizeof(regex_t)); + + rc = regcomp(®, next, REG_EXTENDED | REG_NEWLINE | REG_NOSUB); + if (rc != 0) { + + vdev_error("regcomp(%s) rc = %d\n", next, rc); + return -EINVAL; + } + char **new_strings = + (char **)realloc(*strings, sizeof(char **) * (*len + 2)); + regex_t *new_regexes = + (regex_t *) realloc(*regexes, sizeof(regex_t) * (*len + 1)); + + if (new_strings == NULL || new_regexes == NULL) { + return -ENOMEM; + } + + new_strings[*len] = vdev_strdup_or_null(next); + new_strings[*len + 1] = NULL; + + new_regexes[*len] = reg; + + *strings = new_strings; + *regexes = new_regexes; + + *len = *len + 1; + + return 0; +} // free a list of regexes and their associated paths -int vdev_match_regexes_free( char** regex_strs, regex_t* regexes, size_t len ) { - - if( regex_strs != NULL || regexes != NULL ) { - - for( unsigned int i = 0; i < len; i++ ) { - - if( regex_strs != NULL && regex_strs[i] != NULL ) { - - free( regex_strs[i] ); - regex_strs[i] = NULL; - } - - if( regexes != NULL ) { - regfree( ®exes[i] ); - } - } - - if( regex_strs != NULL ) { - - free( regex_strs ); - } - - if( regexes != NULL ) { - - free( regexes ); - } - } - - return 0; +int vdev_match_regexes_free(char **regex_strs, regex_t * regexes, size_t len) +{ + + if (regex_strs != NULL || regexes != NULL) { + + for (unsigned int i = 0; i < len; i++) { + + if (regex_strs != NULL && regex_strs[i] != NULL) { + + free(regex_strs[i]); + regex_strs[i] = NULL; + } + + if (regexes != NULL) { + regfree(®exes[i]); + } + } + + if (regex_strs != NULL) { + + free(regex_strs); + } + + if (regexes != NULL) { + + free(regexes); + } + } + + return 0; } // does a path match a regex? // return 1 if so, 0 if not, negative on error -int vdev_match_regex( char const* path, regex_t* regex ) { - - int rc = 0; - - rc = regexec( regex, path, 0, NULL, 0 ); - - if( rc != 0 ) { - if( rc == REG_NOMATCH ) { - - // no match - return 0; - } - else { - vdev_error("regexec(%s) rc = %d\n", path, rc ); - return -abs(rc); - } - } - - // match! - return 1; -} +int vdev_match_regex(char const *path, regex_t * regex) +{ + int rc = 0; + + rc = regexec(regex, path, 0, NULL, 0); + + if (rc != 0) { + if (rc == REG_NOMATCH) { + + // no match + return 0; + } else { + vdev_error("regexec(%s) rc = %d\n", path, rc); + return -abs(rc); + } + } + // match! + return 1; +} // does a path match any regexes in a list? // return the index of the match if so (>= 0) // return the size if not // return negative on error -int vdev_match_first_regex( char const* path, regex_t* regexes, size_t num_regexes ) { - - int matched = 0; - - for( unsigned int i = 0; i < num_regexes; i++ ) { - - matched = vdev_match_regex( path, ®exes[i] ); - if( matched > 0 ) { - return i; - } - else if( matched < 0 ) { - vdev_error("vdev_acl_regex_match(%s) rc = %d\n", path, matched ); - return matched; - } - } - - return num_regexes; +int vdev_match_first_regex(char const *path, regex_t * regexes, + size_t num_regexes) +{ + + int matched = 0; + + for (unsigned int i = 0; i < num_regexes; i++) { + + matched = vdev_match_regex(path, ®exes[i]); + if (matched > 0) { + return i; + } else if (matched < 0) { + vdev_error("vdev_acl_regex_match(%s) rc = %d\n", path, + matched); + return matched; + } + } + + return num_regexes; } diff --git a/libvdev/match.h b/libvdev/match.h index eb580be..6cd1416 100644 --- a/libvdev/match.h +++ b/libvdev/match.h @@ -26,15 +26,13 @@ #include +C_LINKAGE_BEGIN int vdev_match_regex_init(regex_t * regex, char const *str); +int vdev_match_regex_append(char ***strings, regex_t ** regexes, size_t * len, + char const *next); +int vdev_match_regexes_free(char **regex_strs, regex_t * regexes, size_t len); +int vdev_match_regex(char const *path, regex_t * regex); +int vdev_match_first_regex(char const *path, regex_t * regexes, + size_t num_regexes); -C_LINKAGE_BEGIN - -int vdev_match_regex_init( regex_t* regex, char const* str ); -int vdev_match_regex_append( char*** strings, regex_t** regexes, size_t* len, char const* next ); -int vdev_match_regexes_free( char** regex_strs, regex_t* regexes, size_t len ); -int vdev_match_regex( char const* path, regex_t* regex ); -int vdev_match_first_regex( char const* path, regex_t* regexes, size_t num_regexes ); - C_LINKAGE_END - -#endif \ No newline at end of file +#endif diff --git a/libvdev/param.c b/libvdev/param.c index 0d4b629..5365a3a 100644 --- a/libvdev/param.c +++ b/libvdev/param.c @@ -28,81 +28,84 @@ SGLIB_DEFINE_RBTREE_FUNCTIONS(vdev_params, left, right, color, VDEV_PARAM_CMP); // return 0 on success // return -EEXIST if the parameter exists // return -ENOMEM if OOM -int vdev_params_add( vdev_params** params, char const* key, char const* value ) { - - char* key_dup = NULL; - char* value_dup = NULL; - struct vdev_param_t* new_param = NULL; - - struct vdev_param_t lookup; - - // exists? fill in requisite comparator information and check - memset( &lookup, 0, sizeof(lookup) ); - lookup.key = (char*)key; - - new_param = sglib_vdev_params_find_member( *params, &lookup ); - - if( new_param != NULL ) { - return -EEXIST; - } - - new_param = VDEV_CALLOC( struct vdev_param_t, 1 ); - - if( new_param == NULL ) { - return -ENOMEM; - } - - key_dup = vdev_strdup_or_null( key ); - - if( key_dup == NULL ) { - - free( new_param ); - return -ENOMEM; - } - - value_dup = vdev_strdup_or_null( value ); - - if( value_dup == NULL ) { - - free( new_param ); - free( key_dup ); - return -ENOMEM; - } - - new_param->key = key_dup; - new_param->value = value_dup; - - sglib_vdev_params_add( params, new_param ); - - return 0; +int vdev_params_add(vdev_params ** params, char const *key, char const *value) +{ + + char *key_dup = NULL; + char *value_dup = NULL; + struct vdev_param_t *new_param = NULL; + + struct vdev_param_t lookup; + + // exists? fill in requisite comparator information and check + memset(&lookup, 0, sizeof(lookup)); + lookup.key = (char *)key; + + new_param = sglib_vdev_params_find_member(*params, &lookup); + + if (new_param != NULL) { + return -EEXIST; + } + + new_param = VDEV_CALLOC(struct vdev_param_t, 1); + + if (new_param == NULL) { + return -ENOMEM; + } + + key_dup = vdev_strdup_or_null(key); + + if (key_dup == NULL) { + + free(new_param); + return -ENOMEM; + } + + value_dup = vdev_strdup_or_null(value); + + if (value_dup == NULL) { + + free(new_param); + free(key_dup); + return -ENOMEM; + } + + new_param->key = key_dup; + new_param->value = value_dup; + + sglib_vdev_params_add(params, new_param); + + return 0; } // free params -int vdev_params_free( vdev_params* params ) { - - struct sglib_vdev_params_iterator itr; - struct vdev_param_t* dp = NULL; - - for( dp = sglib_vdev_params_it_init_inorder( &itr, params ); dp != NULL; dp = sglib_vdev_params_it_next( &itr ) ) { - - if( dp->key != NULL ) { - - free( dp->key ); - dp->key = NULL; - } - - if( dp->value != NULL ) { - - free( dp->value ); - dp->value = NULL; - } - } - - for( dp = sglib_vdev_params_it_init( &itr, params ); dp != NULL; dp = sglib_vdev_params_it_next( &itr ) ) { - - free( dp ); - } - - return 0; -} +int vdev_params_free(vdev_params * params) +{ + + struct sglib_vdev_params_iterator itr; + struct vdev_param_t *dp = NULL; + + for (dp = sglib_vdev_params_it_init_inorder(&itr, params); dp != NULL; + dp = sglib_vdev_params_it_next(&itr)) { + + if (dp->key != NULL) { + free(dp->key); + dp->key = NULL; + } + + if (dp->value != NULL) { + + free(dp->value); + dp->value = NULL; + } + } + + for (dp = sglib_vdev_params_it_init(&itr, params); dp != NULL; + dp = sglib_vdev_params_it_next(&itr)) { + + free(dp); + } + + return 0; +} diff --git a/libvdev/param.h b/libvdev/param.h index 7938233..cee7699 100644 --- a/libvdev/param.h +++ b/libvdev/param.h @@ -27,13 +27,13 @@ // red-black tree for (string, string) pairs (i.e. named parameter pairs) struct vdev_param_t { - - char* key; - char* value; - - struct vdev_param_t* left; - struct vdev_param_t* right; - char color; + + char *key; + char *value; + + struct vdev_param_t *left; + struct vdev_param_t *right; + char color; }; typedef struct vdev_param_t vdev_params; @@ -41,12 +41,10 @@ typedef struct vdev_param_t vdev_params; #define VDEV_PARAM_CMP( dp1, dp2 ) (strcmp( (dp1)->key, (dp2)->key )) C_LINKAGE_BEGIN - // vdev_param_t SGLIB_DEFINE_RBTREE_PROTOTYPES(vdev_params, left, right, color, VDEV_PARAM_CMP) -int vdev_params_add( vdev_params** params, char const* key, char const* value ); -int vdev_params_free( vdev_params* params ); +int vdev_params_add(vdev_params ** params, char const *key, char const *value); +int vdev_params_free(vdev_params * params); C_LINKAGE_END - #endif diff --git a/libvdev/sglib.h b/libvdev/sglib.h index 4ca2aac..50da6f6 100644 --- a/libvdev/sglib.h +++ b/libvdev/sglib.h @@ -12,24 +12,20 @@ under any other license conditions, contact the author. - */ - #ifndef _SGLIB__h_ #define _SGLIB__h_ /* the assert is used exclusively to write unexpected error messages */ #include - /* ---------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------------- */ /* - LEVEL - 0 INTERFACE - */ /* ---------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------------- */ - /* ---------------------------------------------------------------------------- */ /* ------------------------------ STATIC ARRAYS ------------------------------- */ /* ---------------------------------------------------------------------------- */ @@ -79,7 +75,6 @@ } while (_m_ != _i_);\ } - /* QUICK - SORT (level 0) */ #define SGLIB_ARRAY_SINGLE_QUICK_SORT(type, a, max, comparator) {\ @@ -242,7 +237,6 @@ SGLIB_HEAP_DELETE_FIRST(type, a, i, dim, comparator, SGLIB_ARRAY_ELEMENTS_EXCHANGER);\ } - /* ----------------- hashed table of pointers (in an array) -------------------- */ /* @@ -322,7 +316,6 @@ }\ } - /* ---------------------------------------------------------------------------- */ /* ------------------------- DYNAMIC DATA STRUCTURES -------------------------- */ /* ---------------------------------------------------------------------------- */ @@ -455,7 +448,6 @@ this property. */ - #define SGLIB_SORTED_LIST_ADD(type, list, elem, comparator, next) {\ type **_e_;\ int _cmpres_;\ @@ -523,7 +515,6 @@ SGLIB_LIST_MAP_ON_ELEMENTS(type, list, iteratedVariable, next, command);\ } - /* ------------------------------- double linked list (level 0) ------------------------- */ /* Lists with back pointer to previous element. Those lists implements deletion @@ -720,10 +711,8 @@ }\ } - /* ------------------------------- binary tree traversal (level 0) -------------------- */ - #define SGLIB___BIN_TREE_MAP_ON_ELEMENTS(type, tree, iteratedVariable, order, left, right, command) {\ /* this is non-recursive implementation of tree traversal */\ /* it maintains the path to the current node in the array '_path_' */\ @@ -799,8 +788,6 @@ /* ---------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------------- */ - - /* ---------------------------------------------------------------------------- */ /* ------------------------------ STATIC ARRAYS ------------------------------- */ /* ---------------------------------------------------------------------------- */ @@ -830,7 +817,6 @@ /* dim is the size of the array afield */ /* !!!!!!! This data structure is NOT documented, do not use it !!!!!!!!!! */ - #define SGLIB_DEFINE_QUEUE_PROTOTYPES(queue_type, elem_type, afield, ifield, jfield, dim) \ extern void sglib_##queue_type##_init(queue_type *q); \ extern int sglib_##queue_type##_is_empty(queue_type *q); \ @@ -842,7 +828,6 @@ extern void sglib_##queue_type##_delete_first(queue_type *q); \ extern void sglib_##queue_type##_delete(queue_type *q); - #define SGLIB_DEFINE_QUEUE_FUNCTIONS(queue_type, elem_type, afield, ifield, jfield, dim) \ void sglib_##queue_type##_init(queue_type *q) {\ SGLIB_QUEUE_INIT(elem_type, q->afield, q->ifield, q->jfield);\ @@ -872,7 +857,6 @@ SGLIB_QUEUE_DELETE_FIRST(elem_type, q->afield, q->ifield, q->jfield, dim);\ } - /* ------------------------ array heap (level 1) ------------------------- */ /* sglib's heap is a priority queue implemented in a fixed sized array */ /* heap_type MUST be a structure containing fields: */ @@ -880,7 +864,6 @@ /* ifield is the index of the first free element after the queue */ /* !!!!!!! This data structure is NOT documented, do not use it !!!!!!!!!! */ - #define SGLIB_DEFINE_HEAP_PROTOTYPES(heap_type, elem_type, afield, ifield, dim, comparator, elem_exchanger) \ extern void sglib_##heap_type##_init(heap_type *q); \ extern int sglib_##heap_type##_is_empty(heap_type *q); \ @@ -921,7 +904,6 @@ SGLIB_HEAP_DELETE_FIRST(elem_type, q->afield, q->ifield, dim, comparator, elem_exchanger);\ } - /* ------------------------ hashed table (level 1) ------------------------- */ /* @@ -1005,7 +987,6 @@ return(NULL);\ } - /* ------------------- hashed container (only for level 1) -------------------- */ /* hashed container is a table of given fixed size containing another @@ -1104,14 +1085,10 @@ return(e);\ } - - /* ---------------------------------------------------------------------------- */ /* ------------------------- DYNAMIC DATA STRUCTURES -------------------------- */ /* ---------------------------------------------------------------------------- */ - - /* ------------------------------------ list (level 1) -------------------------------- */ #define SGLIB_DEFINE_LIST_PROTOTYPES(type, comparator, next) \ @@ -1136,7 +1113,6 @@ extern type *sglib_##type##_it_current(struct sglib_##type##_iterator *it); \ extern type *sglib_##type##_it_next(struct sglib_##type##_iterator *it); - #define SGLIB_DEFINE_LIST_FUNCTIONS(type, comparator, next) \ int sglib_##type##_is_member(type *list, type *elem) {\ int result;\ @@ -1206,7 +1182,6 @@ /* ----------------------------- sorted list (level 1) ----------------------------------- */ - #define SGLIB_DEFINE_SORTED_LIST_PROTOTYPES(type, comparator, next) \ struct sglib_##type##_iterator {\ type *currentelem;\ @@ -1227,7 +1202,6 @@ extern type *sglib_##type##_it_current(struct sglib_##type##_iterator *it); \ extern type *sglib_##type##_it_next(struct sglib_##type##_iterator *it); - #define SGLIB_DEFINE_SORTED_LIST_FUNCTIONS(type, comparator, next) \ int sglib_##type##_is_member(type *list, type *elem) {\ int result;\ @@ -1291,10 +1265,8 @@ return(ce);\ } - /* ----------------------------- double linked list (level 1) ------------------------------ */ - #define SGLIB_DEFINE_DL_LIST_PROTOTYPES(type, comparator, previous, next) \ struct sglib_##type##_iterator {\ type *currentelem;\ @@ -1324,7 +1296,6 @@ extern type *sglib_##type##_it_current(struct sglib_##type##_iterator *it); \ extern type *sglib_##type##_it_next(struct sglib_##type##_iterator *it); - #define SGLIB_DEFINE_DL_LIST_FUNCTIONS(type, comparator, previous, next) \ void sglib_##type##_add(type **list, type *elem) {\ SGLIB_DL_LIST_ADD(type, *list, elem, previous, next);\ @@ -1429,7 +1400,6 @@ return(ce);\ } - /* --------------------------------- red-black trees (level 1) -------------------------------- */ /* @@ -1600,7 +1570,6 @@ fixing rules from: }\ } - #define SGLIB_DEFINE_RBTREE_FUNCTIONS_GENERAL(type, left, right, bits, comparator, RED, BLACK) \ static void sglib___##type##_fix_left_insertion_discrepancy(type **tree) {\ SGLIB___RBTREE_FIX_INSERTION_DISCREPANCY(type, tree, left, right, bits, RED, BLACK);\ @@ -1887,7 +1856,6 @@ void sglib___##type##_consistency_check(type *t) {\ sglib___##type##_consistency_check_recursive(t, &pathDeep, 0);\ } - #define SGLIB_DEFINE_RBTREE_PROTOTYPES(type, left, right, colorbit, comparator) \ struct sglib_##type##_iterator {\ type *currentelem;\ @@ -1918,7 +1886,6 @@ void sglib___##type##_consistency_check(type *t) {\ #define SGLIB_DEFINE_RBTREE_FUNCTIONS(type, left, right, colorbit, comparator) \ SGLIB_DEFINE_RBTREE_FUNCTIONS_GENERAL(type, left, right, colorbit, comparator, 1, 0) - /*********************************** * vector implementation * Copyright (C) 2015 Jude Nelson @@ -1942,7 +1909,6 @@ void sglib___##type##_consistency_check(type *t) {\ extern unsigned long sglib_##type##_vector_size( struct sglib_##type##_vector* v ); \ extern void sglib_##type##_vector_yoink( struct sglib_##type##_vector* v, type** buf, unsigned long* len ); - #define SGLIB_DEFINE_VECTOR_FUNCTIONS( type ) \ \ int sglib___##type##_vector_grow( struct sglib_##type##_vector* v ) { \ @@ -2032,20 +1998,17 @@ void sglib___##type##_consistency_check(type *t) {\ } \ \ - - + /* ---------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------------- */ /* - SUPPLEMENTARY DEFINITIONS - */ /* ---------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------------- */ - #define SGLIB___GET_VALUE(x) (x) #define SGLIB___SET_VALUE(x, value) {(x) = (value);} #define SGLIB_ARRAY_ELEMENTS_EXCHANGER(type, a, i, j) {type _sgl_aee_tmp_; _sgl_aee_tmp_=(a)[(i)]; (a)[(i)]=(a)[(j)]; (a)[(j)]= _sgl_aee_tmp_;} - #define SGLIB_SAFE_NUMERIC_COMPARATOR(x, y) (((x)>(y)?1:((x)<(y)?-1:0))) #define SGLIB_SAFE_REVERSE_NUMERIC_COMPARATOR(x, y) (((x)>(y)?-1:((x)<(y)?1:0))) #define SGLIB_FAST_NUMERIC_COMPARATOR(x, y) ((int)((x) - (y))) @@ -2058,8 +2021,8 @@ void sglib___##type##_consistency_check(type *t) {\ #endif #ifndef SGLIB_HASH_TAB_SHIFT_CONSTANT -#define SGLIB_HASH_TAB_SHIFT_CONSTANT 16381 /* should be a prime */ -/* #define SGLIB_HASH_TAB_SHIFT_CONSTANT 536870912*/ /* for large tables :) */ +#define SGLIB_HASH_TAB_SHIFT_CONSTANT 16381 /* should be a prime */ + /* #define SGLIB_HASH_TAB_SHIFT_CONSTANT 536870912*//* for large tables :) */ #endif -#endif /* _SGLIB__h_ */ +#endif /* _SGLIB__h_ */ diff --git a/libvdev/util.c b/libvdev/util.c index d2c99c9..ecaf40f 100644 --- a/libvdev/util.c +++ b/libvdev/util.c @@ -18,7 +18,7 @@ For the terms of this license, see LICENSE.ISC or . */ - + #include "util.h" int _VDEV_DEBUG_MESSAGES = 0; @@ -27,347 +27,345 @@ int _VDEV_WARN_MESSAGES = 1; int _VDEV_ERROR_MESSAGES = 1; int _VDEV_SYSLOG = 0; - // set debug level, by setting for info and debug messages -void vdev_set_debug_level( int d ) { - - if( d >= 1 ) { - _VDEV_INFO_MESSAGES = 1; - } - if( d >= 2 ) { - _VDEV_DEBUG_MESSAGES = 1; - } +void vdev_set_debug_level(int d) +{ + + if (d >= 1) { + _VDEV_INFO_MESSAGES = 1; + } + if (d >= 2) { + _VDEV_DEBUG_MESSAGES = 1; + } } // set error level, by setting for warning and error messages -void vdev_set_error_level( int e ) { - - if( e >= 1 ) { - _VDEV_ERROR_MESSAGES = 1; - } - if( e >= 2 ) { - _VDEV_WARN_MESSAGES = 1; - } +void vdev_set_error_level(int e) +{ + + if (e >= 1) { + _VDEV_ERROR_MESSAGES = 1; + } + if (e >= 2) { + _VDEV_WARN_MESSAGES = 1; + } } // debug level is the sum of the levels enabled -int vdev_get_debug_level() { - return _VDEV_DEBUG_MESSAGES + _VDEV_INFO_MESSAGES; +int vdev_get_debug_level() +{ + return _VDEV_DEBUG_MESSAGES + _VDEV_INFO_MESSAGES; } // error level is the sum of the errors enable -int vdev_get_error_level() { - return _VDEV_ERROR_MESSAGES + _VDEV_WARN_MESSAGES; +int vdev_get_error_level() +{ + return _VDEV_ERROR_MESSAGES + _VDEV_WARN_MESSAGES; } // turn on syslog logging // always succeeds -int vdev_enable_syslog() { - - _VDEV_SYSLOG = 1; - openlog( VDEV_SYSLOG_IDENT, LOG_CONS | LOG_NDELAY | LOG_PID, LOG_DAEMON ); - - return 0; +int vdev_enable_syslog() +{ + + _VDEV_SYSLOG = 1; + openlog(VDEV_SYSLOG_IDENT, LOG_CONS | LOG_NDELAY | LOG_PID, LOG_DAEMON); + + return 0; } // become a daemon: fork, setsid, fork, umask // return 0 on child // return 1 on parent // return -errno on failure to fork -int vdev_daemonize(void) { - - int rc = 0; - pid_t pid = 0; - - pid = fork(); - if( pid == 0 ) { - - // child--no tty - // become process group leader - rc = setsid(); - if( rc < 0 ) { - - rc = -errno; - vdev_error("setsid() rc = %d\n", rc ); - return rc; - } - - // fork again - // stop us from ever regaining the tty - pid = fork(); - if( pid == 0 ) { - - // child - // switch to / - rc = chdir("/"); - if( rc != 0 ) { - - rc = -errno; - vdev_error("chdir('/') rc = %d\n", rc ); - return rc; - } - - // own everything we create - umask(0); - - // now a daemon! - return 0; - } - else if( pid > 0 ) { - - // parent--die, but don't call userspace clean-up - _exit(0); - } - else { - - // failed to fork - rc = -errno; - vdev_error("fork( parent=%d ) rc = %d\n", getpid(), rc ); - return rc; - } - } - else if( pid > 0 ) { - - // parent--we're done - return 1; - } - else { - - // error - rc = -errno; - vdev_error( "fork( parent=%d ) rc = %d\n", getpid(), rc ); - return rc; - } +int vdev_daemonize(void) +{ + + int rc = 0; + pid_t pid = 0; + + pid = fork(); + if (pid == 0) { + + // child--no tty + // become process group leader + rc = setsid(); + if (rc < 0) { + + rc = -errno; + vdev_error("setsid() rc = %d\n", rc); + return rc; + } + // fork again + // stop us from ever regaining the tty + pid = fork(); + if (pid == 0) { + + // child + // switch to / + rc = chdir("/"); + if (rc != 0) { + + rc = -errno; + vdev_error("chdir('/') rc = %d\n", rc); + return rc; + } + // own everything we create + umask(0); + + // now a daemon! + return 0; + } else if (pid > 0) { + + // parent--die, but don't call userspace clean-up + _exit(0); + } else { + + // failed to fork + rc = -errno; + vdev_error("fork( parent=%d ) rc = %d\n", getpid(), rc); + return rc; + } + } else if (pid > 0) { + + // parent--we're done + return 1; + } else { + + // error + rc = -errno; + vdev_error("fork( parent=%d ) rc = %d\n", getpid(), rc); + return rc; + } } - // redirect stdout and stderr to a logfile // return 0 on success -int vdev_log_redirect( char const* logfile_path ) { - - int logfd = 0; - int rc = 0; - FILE* f = NULL; - - f = fopen( logfile_path, "a" ); - if( f == NULL ) { - - rc = -errno; - vdev_error("fopen('%s') rc = %d\n", logfile_path, rc ); - return rc; - } - - logfd = fileno(f); - - close( STDOUT_FILENO ); - close( STDERR_FILENO ); - - rc = dup2( logfd, STDOUT_FILENO ); - if( rc < 0 ) { - - rc = -errno; - vdev_error("dup2(STDOUT) rc = %d\n", rc ); - return rc; - } - - rc = dup2( logfd, STDERR_FILENO ); - if( rc < 0 ) { - - rc = -errno; - vdev_error("dup2(STDERR) rc = %d\n", rc ); - - return rc; - } - - fclose( f ); - logfd = -1; - - return 0; -} +int vdev_log_redirect(char const *logfile_path) +{ + int logfd = 0; + int rc = 0; + FILE *f = NULL; -// write a pidfile to a path -int vdev_pidfile_write( char const* pidfile_path ) { - - char pidbuf[50]; - FILE* f = NULL; - size_t nw = 0; - int rc = 0; - - f = fopen( pidfile_path, "w+" ); - if( f == NULL ) { - - rc = -errno; - vdev_error("fopen('%s') rc = %d\n", pidfile_path, rc ); - return rc; - } - - memset( pidbuf, 0, 50 ); - sprintf( pidbuf, "%d\n", getpid() ); - - rc = vdev_write_uninterrupted( fileno(f), pidbuf, strlen(pidbuf) + 1 ); - - fclose( f ); - - if( rc < 0 ) { - - vdev_error("vdev_write_uninterrupted('%d') rc = %d\n", getpid(), rc ); - return rc; - } - - return 0; + f = fopen(logfile_path, "a"); + if (f == NULL) { + + rc = -errno; + vdev_error("fopen('%s') rc = %d\n", logfile_path, rc); + return rc; + } + + logfd = fileno(f); + + close(STDOUT_FILENO); + close(STDERR_FILENO); + + rc = dup2(logfd, STDOUT_FILENO); + if (rc < 0) { + + rc = -errno; + vdev_error("dup2(STDOUT) rc = %d\n", rc); + return rc; + } + + rc = dup2(logfd, STDERR_FILENO); + if (rc < 0) { + + rc = -errno; + vdev_error("dup2(STDERR) rc = %d\n", rc); + + return rc; + } + + fclose(f); + logfd = -1; + + return 0; } +// write a pidfile to a path +int vdev_pidfile_write(char const *pidfile_path) +{ + + char pidbuf[50]; + FILE *f = NULL; + size_t nw = 0; + int rc = 0; + + f = fopen(pidfile_path, "w+"); + if (f == NULL) { + + rc = -errno; + vdev_error("fopen('%s') rc = %d\n", pidfile_path, rc); + return rc; + } + + memset(pidbuf, 0, 50); + sprintf(pidbuf, "%d\n", getpid()); + + rc = vdev_write_uninterrupted(fileno(f), pidbuf, strlen(pidbuf) + 1); + + fclose(f); + + if (rc < 0) { + + vdev_error("vdev_write_uninterrupted('%d') rc = %d\n", getpid(), + rc); + return rc; + } + + return 0; +} // join two paths, writing the result to dest if dest is not NULL. // otherwise, allocate and return a buffer containing the joined paths. // return NULL on OOM -char* vdev_fullpath( char const* root, char const* path, char* dest ) { - - char delim = 0; - int path_off = 0; - int len = 0; - - if( root == NULL || path == NULL ) { - return NULL; - } - - len = strlen(path) + strlen(root) + 2; - - if( strlen(root) > 0 ) { - size_t root_delim_off = strlen(root) - 1; - if( root[root_delim_off] != '/' && path[0] != '/' ) { - len++; - delim = '/'; - } - else if( root[root_delim_off] == '/' && path[0] == '/' ) { - path_off = 1; - } - } - - if( dest == NULL ) { - dest = VDEV_CALLOC( char, len ); - if( dest == NULL ) { - return NULL; - } - } - - memset(dest, 0, len); - - strcpy( dest, root ); - if( delim != 0 ) { - dest[strlen(dest)] = '/'; - } - strcat( dest, path + path_off ); - - return dest; +char *vdev_fullpath(char const *root, char const *path, char *dest) +{ + + char delim = 0; + int path_off = 0; + int len = 0; + + if (root == NULL || path == NULL) { + return NULL; + } + + len = strlen(path) + strlen(root) + 2; + + if (strlen(root) > 0) { + size_t root_delim_off = strlen(root) - 1; + if (root[root_delim_off] != '/' && path[0] != '/') { + len++; + delim = '/'; + } else if (root[root_delim_off] == '/' && path[0] == '/') { + path_off = 1; + } + } + + if (dest == NULL) { + dest = VDEV_CALLOC(char, len); + if (dest == NULL) { + return NULL; + } + } + + memset(dest, 0, len); + + strcpy(dest, root); + if (delim != 0) { + dest[strlen(dest)] = '/'; + } + strcat(dest, path + path_off); + + return dest; } - // get the directory name of a path. // put it into dest if dest is not null. // otherwise, allocate a buffer and return it. // return NULL on OOM -char* vdev_dirname( char const* path, char* dest ) { - - if( path == NULL ) { - return NULL; - } - - if( dest == NULL ) { - dest = VDEV_CALLOC( char, strlen(path) + 1 ); - if( dest == NULL ) { - return NULL; - } - } - - // is this root? - if( strlen(path) == 0 || strcmp( path, "/" ) == 0 ) { - strcpy( dest, "/" ); - return dest; - } - - int delim_i = strlen(path); - if( path[delim_i] == '/' ) { - delim_i--; - } - - for( ; delim_i >= 0; delim_i-- ) { - if( path[delim_i] == '/' ) { - break; - } - } - - if( delim_i < 0 ) { - delim_i = 0; - } - - if( delim_i == 0 && path[0] == '/' ) { - delim_i = 1; - } - - strncpy( dest, path, delim_i ); - dest[delim_i+1] = '\0'; - return dest; +char *vdev_dirname(char const *path, char *dest) +{ + + if (path == NULL) { + return NULL; + } + + if (dest == NULL) { + dest = VDEV_CALLOC(char, strlen(path) + 1); + if (dest == NULL) { + return NULL; + } + } + // is this root? + if (strlen(path) == 0 || strcmp(path, "/") == 0) { + strcpy(dest, "/"); + return dest; + } + + int delim_i = strlen(path); + if (path[delim_i] == '/') { + delim_i--; + } + + for (; delim_i >= 0; delim_i--) { + if (path[delim_i] == '/') { + break; + } + } + + if (delim_i < 0) { + delim_i = 0; + } + + if (delim_i == 0 && path[0] == '/') { + delim_i = 1; + } + + strncpy(dest, path, delim_i); + dest[delim_i + 1] = '\0'; + return dest; } // determine how long the basename of a path is // return 0 if the length could not be determined -size_t vdev_basename_len( char const* path ) { - - if( path == NULL ) { - return 0; - } - - int delim_i = strlen(path) - 1; - if( delim_i <= 0 ) { - return 0; - } - if( path[delim_i] == '/' ) { - // this path ends with '/', so skip over it if it isn't / - if( delim_i > 0 ) { - delim_i--; - } - } - for( ; delim_i >= 0; delim_i-- ) { - if( path[delim_i] == '/' ) { - break; - } - } - delim_i++; - - return strlen(path) - delim_i; +size_t vdev_basename_len(char const *path) +{ + + if (path == NULL) { + return 0; + } + + int delim_i = strlen(path) - 1; + if (delim_i <= 0) { + return 0; + } + if (path[delim_i] == '/') { + // this path ends with '/', so skip over it if it isn't / + if (delim_i > 0) { + delim_i--; + } + } + for (; delim_i >= 0; delim_i--) { + if (path[delim_i] == '/') { + break; + } + } + delim_i++; + + return strlen(path) - delim_i; } - // get the basename of a (non-directory) path. // put it into dest, if dest is not null. // otherwise, allocate a buffer with it and return the buffer // return NULL on OOM, or if path is NULL -char* vdev_basename( char const* path, char* dest ) { - - size_t len = 0; - - if( path == NULL ) { - return NULL; - } - - len = vdev_basename_len( path ); - - if( dest == NULL ) { - - dest = VDEV_CALLOC( char, len + 1 ); - if( dest == NULL ) { - - return NULL; - } - } - else { - memset( dest, 0, len + 1 ); - } - - strncpy( dest, path + strlen(path) - len, len ); - return dest; +char *vdev_basename(char const *path, char *dest) +{ + + size_t len = 0; + + if (path == NULL) { + return NULL; + } + + len = vdev_basename_len(path); + + if (dest == NULL) { + + dest = VDEV_CALLOC(char, len + 1); + if (dest == NULL) { + + return NULL; + } + } else { + memset(dest, 0, len + 1); + } + + strncpy(dest, path + strlen(path) - len, len); + return dest; } // run a subprocess, optionally in the system shell. @@ -378,508 +376,509 @@ char* vdev_basename( char const* path, char* dest ) { // return 1 on output truncate // return negative on error // set the subprocess exit status in *exit_status -int vdev_subprocess( char const* cmd, char* const env[], char** output, size_t max_output, int stderr_fd, int* exit_status, bool use_shell ) { - - int p[2]; - int rc = 0; - pid_t pid = 0; - int max_fd = 0; - ssize_t nr = 0; - size_t num_read = 0; - int status = 0; - bool alloced = false; - - if( cmd == NULL ) { - return -EINVAL; - } - - // open the pipe - rc = pipe( p ); - if( rc != 0 ) { - - rc = -errno; - vdev_error("pipe() rc = %d\n", rc ); - return rc; - } - - max_fd = sysconf(_SC_OPEN_MAX); - - // fork the child - pid = fork(); - - if( pid == 0 ) { - - // send stdout to p[1] - close( p[0] ); - rc = dup2( p[1], STDOUT_FILENO ); - - if( rc < 0 ) { - - rc = errno; - close( p[1] ); - exit(rc); - } - - // optionally redirect stderr (or just close it) - if( stderr_fd >= 0 ) { - rc = dup2( stderr_fd, STDERR_FILENO ); - if( rc < 0 ) { - - rc = errno; - close( p[1] ); - exit(rc); - } - } - - // close everything else but stdout and optionally stderr. - for( int i = 0; i < max_fd; i++ ) { - - if( i != STDOUT_FILENO && i != stderr_fd ) { - close( i ); - } - } - - // run the command - if( use_shell ) { - - if( env != NULL ) { - rc = execle( "/bin/sh", "sh", "-c", cmd, (char*)0, env ); - } - else { - - char** noenv = { NULL }; - rc = execle( "/bin/sh", "sh", "-c", cmd, (char*)0, noenv ); - } - } - else { - - if( env != NULL ) { - rc = execle( cmd, cmd, (char*)0, env ); - } - else { - - char** noenv = { NULL }; - rc = execle( cmd, cmd, (char*)0, noenv ); - } - } - - if( rc != 0 ) { - - rc = errno; - exit(rc); - } - else { - - // make gcc happy - exit(0); - } - } - else if( pid > 0 ) { - - // parent - close(p[1]); - - // allocate output - if( output != NULL ) { - if( *output == NULL && max_output > 0 ) { - - *output = VDEV_CALLOC( char, max_output ); - if( *output == NULL ) { - - // out of memory - close( p[0] ); - return -ENOMEM; - } - - alloced = true; - } - } - - // get output - if( output != NULL && *output != NULL && max_output > 0 ) { - - nr = vdev_read_uninterrupted( p[0], (*output) + num_read, max_output - num_read ); - if( nr < 0 ) { - - vdev_error("vdev_read_uninterrupted rc = %zd\n", nr ); - close( p[0] ); - - if( alloced ) { - - free( *output ); - *output = NULL; - } - return nr; - } - - num_read = nr; - } - - // wait for child - rc = waitpid( pid, &status, 0 ); - if( rc < 0 ) { - - rc = -errno; - vdev_error("waitpid(%d) rc = %d\n", pid, rc ); - - close( p[0] ); - - if( alloced ) { - - free( *output ); - *output = NULL; - } - - return rc; - } - - if( WIFEXITED( status ) ) { - - *exit_status = WEXITSTATUS( status ); - } - else if( WIFSIGNALED( status ) ) { - - vdev_error("WARN: command '%s' failed with signal %d\n", cmd, WTERMSIG( status ) ); - *exit_status = status; - } - else { - - // indicate start/stop - *exit_status = -EPERM; - } - - close( p[0] ); - return 0; - } - else { - - rc = -errno; - vdev_error("fork() rc = %d\n", rc ); - return rc; - } -} +int vdev_subprocess(char const *cmd, char *const env[], char **output, + size_t max_output, int stderr_fd, int *exit_status, + bool use_shell) +{ + + int p[2]; + int rc = 0; + pid_t pid = 0; + int max_fd = 0; + ssize_t nr = 0; + size_t num_read = 0; + int status = 0; + bool alloced = false; + + if (cmd == NULL) { + return -EINVAL; + } + // open the pipe + rc = pipe(p); + if (rc != 0) { + + rc = -errno; + vdev_error("pipe() rc = %d\n", rc); + return rc; + } + + max_fd = sysconf(_SC_OPEN_MAX); + + // fork the child + pid = fork(); + + if (pid == 0) { + + // send stdout to p[1] + close(p[0]); + rc = dup2(p[1], STDOUT_FILENO); + + if (rc < 0) { + + rc = errno; + close(p[1]); + exit(rc); + } + // optionally redirect stderr (or just close it) + if (stderr_fd >= 0) { + rc = dup2(stderr_fd, STDERR_FILENO); + if (rc < 0) { + + rc = errno; + close(p[1]); + exit(rc); + } + } + // close everything else but stdout and optionally stderr. + for (int i = 0; i < max_fd; i++) { + + if (i != STDOUT_FILENO && i != stderr_fd) { + close(i); + } + } + + // run the command + if (use_shell) { + + if (env != NULL) { + rc = execle("/bin/sh", "sh", "-c", cmd, + (char *)0, env); + } else { + + char **noenv = { NULL }; + rc = execle("/bin/sh", "sh", "-c", cmd, + (char *)0, noenv); + } + } else { + + if (env != NULL) { + rc = execle(cmd, cmd, (char *)0, env); + } else { + + char **noenv = { NULL }; + rc = execle(cmd, cmd, (char *)0, noenv); + } + } + + if (rc != 0) { + + rc = errno; + exit(rc); + } else { + + // make gcc happy + exit(0); + } + } else if (pid > 0) { + + // parent + close(p[1]); + + // allocate output + if (output != NULL) { + if (*output == NULL && max_output > 0) { + + *output = VDEV_CALLOC(char, max_output); + if (*output == NULL) { + + // out of memory + close(p[0]); + return -ENOMEM; + } + + alloced = true; + } + } + // get output + if (output != NULL && *output != NULL && max_output > 0) { + + nr = vdev_read_uninterrupted(p[0], (*output) + num_read, + max_output - num_read); + if (nr < 0) { + + vdev_error("vdev_read_uninterrupted rc = %zd\n", + nr); + close(p[0]); + + if (alloced) { + free(*output); + *output = NULL; + } + return nr; + } + + num_read = nr; + } + // wait for child + rc = waitpid(pid, &status, 0); + if (rc < 0) { + + rc = -errno; + vdev_error("waitpid(%d) rc = %d\n", pid, rc); + + close(p[0]); + + if (alloced) { + + free(*output); + *output = NULL; + } + + return rc; + } + + if (WIFEXITED(status)) { + + *exit_status = WEXITSTATUS(status); + } else if (WIFSIGNALED(status)) { + + vdev_error("WARN: command '%s' failed with signal %d\n", + cmd, WTERMSIG(status)); + *exit_status = status; + } else { + + // indicate start/stop + *exit_status = -EPERM; + } + + close(p[0]); + return 0; + } else { + + rc = -errno; + vdev_error("fork() rc = %d\n", rc); + return rc; + } +} // write, but mask EINTR // return number of bytes written on success // return -errno on I/O error -ssize_t vdev_write_uninterrupted( int fd, char const* buf, size_t len ) { - - ssize_t num_written = 0; - - if( buf == NULL ) { - return -EINVAL; - } - - while( (unsigned)num_written < len ) { - ssize_t nw = write( fd, buf + num_written, len - num_written ); - if( nw < 0 ) { - - int errsv = -errno; - if( errsv == -EINTR ) { - continue; - } - - return errsv; - } - if( nw == 0 ) { - break; - } - - num_written += nw; - } - - return num_written; -} +ssize_t vdev_write_uninterrupted(int fd, char const *buf, size_t len) +{ + + ssize_t num_written = 0; + + if (buf == NULL) { + return -EINVAL; + } + while ((unsigned)num_written < len) { + ssize_t nw = write(fd, buf + num_written, len - num_written); + if (nw < 0) { + + int errsv = -errno; + if (errsv == -EINTR) { + continue; + } + + return errsv; + } + if (nw == 0) { + break; + } + + num_written += nw; + } + + return num_written; +} // read, but mask EINTR // return number of bytes read on success // return -errno on I/O error -ssize_t vdev_read_uninterrupted( int fd, char* buf, size_t len ) { - - ssize_t num_read = 0; - - if( buf == NULL ) { - return -EINVAL; - } - - while( (unsigned)num_read < len ) { - ssize_t nr = read( fd, buf + num_read, len - num_read ); - if( nr < 0 ) { - - int errsv = -errno; - if( errsv == -EINTR ) { - continue; - } - - return errsv; - } - if( nr == 0 ) { - break; - } - - num_read += nr; - } - - return num_read; -} +ssize_t vdev_read_uninterrupted(int fd, char *buf, size_t len) +{ + + ssize_t num_read = 0; + + if (buf == NULL) { + return -EINVAL; + } + + while ((unsigned)num_read < len) { + ssize_t nr = read(fd, buf + num_read, len - num_read); + if (nr < 0) { + + int errsv = -errno; + if (errsv == -EINTR) { + continue; + } + return errsv; + } + if (nr == 0) { + break; + } + + num_read += nr; + } + + return num_read; +} // read a whole file, masking EINTR // return 0 on success, filling buf with up to len bytes // return -errno on open or read errors -int vdev_read_file( char const* path, char* buf, size_t len ) { - - int fd = 0; - int rc = 0; - - if( path == NULL || buf == NULL ) { - return -EINVAL; - } - - fd = open( path, O_RDONLY ); - if( fd < 0 ) { - - rc = -errno; - vdev_error("open('%s') rc = %d\n", path, rc ); - return rc; - } - - rc = vdev_read_uninterrupted( fd, buf, len ); - if( rc < 0 ) { - - rc = -errno; - vdev_error("vdev_read_uninterrupted('%s') rc = %d\n", path, rc ); - - close( fd ); - return rc; - } - - close( fd ); - return 0; +int vdev_read_file(char const *path, char *buf, size_t len) +{ + + int fd = 0; + int rc = 0; + + if (path == NULL || buf == NULL) { + return -EINVAL; + } + + fd = open(path, O_RDONLY); + if (fd < 0) { + + rc = -errno; + vdev_error("open('%s') rc = %d\n", path, rc); + return rc; + } + + rc = vdev_read_uninterrupted(fd, buf, len); + if (rc < 0) { + + rc = -errno; + vdev_error("vdev_read_uninterrupted('%s') rc = %d\n", path, rc); + + close(fd); + return rc; + } + + close(fd); + return 0; } // write a whole file, masking EINTR // return 0 on success // return -EINVAL if buf or path is null // return -errno on failiure to open or write or fsync -int vdev_write_file( char const* path, char const* buf, size_t len, int flags, mode_t mode ) { - - int fd = 0; - int rc = 0; - - if( path == NULL || buf == NULL ) { - return -EINVAL; - } - - fd = open( path, flags, mode ); - if( fd < 0 ) { - - rc = -errno; - vdev_error("open('%s') rc = %d\n", path, rc ); - return rc; - } - - rc = vdev_write_uninterrupted( fd, buf, len ); - if( rc < 0 ) { - - rc = -errno; - vdev_error("vdev_write_uninterrupted('%s') rc = %d\n", path, rc ); - - close( fd ); - return rc; - } - - // NOTE: not much we can do if close() fails... - close( fd ); - - return rc; -} +int vdev_write_file(char const *path, char const *buf, size_t len, int flags, + mode_t mode) +{ + + int fd = 0; + int rc = 0; + + if (path == NULL || buf == NULL) { + return -EINVAL; + } + + fd = open(path, flags, mode); + if (fd < 0) { + rc = -errno; + vdev_error("open('%s') rc = %d\n", path, rc); + return rc; + } + + rc = vdev_write_uninterrupted(fd, buf, len); + if (rc < 0) { + + rc = -errno; + vdev_error("vdev_write_uninterrupted('%s') rc = %d\n", path, + rc); + + close(fd); + return rc; + } + // NOTE: not much we can do if close() fails... + close(fd); + + return rc; +} // free a list of dirents // always succeeds -static void vdev_dirents_free( struct dirent** dirents, int num_entries ) { - - if( dirents == NULL ) { - return; - } - - for( int i = 0; i < num_entries; i++ ) { - - if( dirents[i] == NULL ) { - continue; - } - - free( dirents[i] ); - dirents[i] = NULL; - } - - free( dirents ); -} +static void vdev_dirents_free(struct dirent **dirents, int num_entries) +{ + if (dirents == NULL) { + return; + } -// portable scandirat() implementation--behaves as close to the Linux scandirat(3) interface as possible. -int vdev_portable_scandirat( int dirfd, char const* dirp, struct dirent ***namelist, int (*filter)( const struct dirent* ), int (*compar)( const struct dirent**, const struct dirent** ) ) { - - int rc = 0; - - DIR* dirh = NULL; - struct dirent next; - struct dirent* result = NULL; - struct dirent* next_dup = NULL; - int dirp_fd = -1; - - struct dirent** namelist_buf = NULL; - struct dirent** namelist_tmp = NULL; - ssize_t num_dirents = 0; - ssize_t num_dirents_capacity = 0; - - dirp_fd = openat( dirfd, dirp, O_DIRECTORY ); - if( dirp_fd < 0 ) { - - rc = -errno; - return rc; - } - - // open the duplicated handle instead - dirh = fdopendir( dirp_fd ); - if( dirh == NULL ) { - - rc = -errno; - - close( dirp_fd ); - return rc; - } - - while( 1 ) { - - // next dirent - rc = readdir_r( dirh, &next, &result ); - - // done? - if( result == NULL ) { - break; - } - - // error? - if( rc != 0 ) { - - rc = -rc; - break; - } - - // filter? - if( filter != NULL ) { - - rc = (*filter)( &next ); - if( rc == 0 ) { - - // skip - continue; - } - } - - // increase (double) space? - if( num_dirents >= num_dirents_capacity ) { - - if( num_dirents_capacity == 0 ) { - num_dirents_capacity = 1; - } - - num_dirents_capacity <<= 1; - - namelist_tmp = (struct dirent**)realloc( namelist_buf, (num_dirents_capacity + 1) * sizeof( struct dirent ) ); - if( namelist_tmp == NULL ) { - - // OOM - rc = -ENOMEM; - break; - } - - namelist_buf = namelist_tmp; - } - - // duplicate - next_dup = VDEV_CALLOC( struct dirent, 1 ); - if( next_dup == NULL ) { - - // OOM - rc = -ENOMEM; - break; - } - - memcpy( next_dup, &next, sizeof( struct dirent ) ); - - // insert - namelist_buf[ num_dirents ] = next_dup; - namelist_buf[ num_dirents+1 ] = NULL; - num_dirents++; - } - - closedir( dirh ); - - if( rc < 0 ) { - - // error--clean up - vdev_dirents_free( namelist_buf, num_dirents ); - return rc; - } - - // sort? - if( compar != NULL ) { - - qsort( (void*)namelist_buf, num_dirents, sizeof(struct dirent*), (int (*)(const void*, const void*))compar ); - } - - // finished! - *namelist = namelist_buf; - return num_dirents; + for (int i = 0; i < num_entries; i++) { + + if (dirents[i] == NULL) { + continue; + } + + free(dirents[i]); + dirents[i] = NULL; + } + + free(dirents); } +// portable scandirat() implementation--behaves as close to the Linux scandirat(3) interface as possible. +int vdev_portable_scandirat(int dirfd, char const *dirp, + struct dirent ***namelist, + int (*filter) (const struct dirent *), + int (*compar) (const struct dirent **, + const struct dirent **)) +{ + + int rc = 0; + + DIR *dirh = NULL; + struct dirent next; + struct dirent *result = NULL; + struct dirent *next_dup = NULL; + int dirp_fd = -1; + + struct dirent **namelist_buf = NULL; + struct dirent **namelist_tmp = NULL; + ssize_t num_dirents = 0; + ssize_t num_dirents_capacity = 0; + + dirp_fd = openat(dirfd, dirp, O_DIRECTORY); + if (dirp_fd < 0) { + + rc = -errno; + return rc; + } + // open the duplicated handle instead + dirh = fdopendir(dirp_fd); + if (dirh == NULL) { + + rc = -errno; + + close(dirp_fd); + return rc; + } + + while (1) { + + // next dirent + rc = readdir_r(dirh, &next, &result); + + // done? + if (result == NULL) { + break; + } + // error? + if (rc != 0) { + + rc = -rc; + break; + } + // filter? + if (filter != NULL) { + + rc = (*filter) (&next); + if (rc == 0) { + + // skip + continue; + } + } + // increase (double) space? + if (num_dirents >= num_dirents_capacity) { + + if (num_dirents_capacity == 0) { + num_dirents_capacity = 1; + } + + num_dirents_capacity <<= 1; + + namelist_tmp = + (struct dirent **)realloc(namelist_buf, + (num_dirents_capacity + + 1) * + sizeof(struct dirent)); + if (namelist_tmp == NULL) { + + // OOM + rc = -ENOMEM; + break; + } + + namelist_buf = namelist_tmp; + } + // duplicate + next_dup = VDEV_CALLOC(struct dirent, 1); + if (next_dup == NULL) { + + // OOM + rc = -ENOMEM; + break; + } + + memcpy(next_dup, &next, sizeof(struct dirent)); + + // insert + namelist_buf[num_dirents] = next_dup; + namelist_buf[num_dirents + 1] = NULL; + num_dirents++; + } + + closedir(dirh); + + if (rc < 0) { + + // error--clean up + vdev_dirents_free(namelist_buf, num_dirents); + return rc; + } + // sort? + if (compar != NULL) { + + qsort((void *)namelist_buf, num_dirents, + sizeof(struct dirent *), + (int (*)(const void *, const void *))compar); + } + // finished! + *namelist = namelist_buf; + return num_dirents; +} // process all files in a directory, given a descriptor to it. Search in alphanumeric order // return 0 on success // return -EINVAL if loader is NULL // return -EBADF if dirfd is invalid // return non-zero of loader_at returns non-zero -int vdev_load_all_at( int dirfd, vdev_dirent_loader_at_t loader_at, void* cls ) { - - struct dirent** dirents = NULL; - int num_entries = 0; - int rc = 0; - - if( loader_at == NULL ) { - return -EINVAL; - } - - num_entries = vdev_portable_scandirat( dirfd, ".", &dirents, NULL, alphasort ); - if( num_entries < 0 ) { - - rc = -errno; - vdev_error("scandirat(%d) rc = %d\n", dirfd, rc ); - return rc; - } - - for( int i = 0; i < num_entries; i++ ) { - - // process this - rc = (*loader_at)( dirfd, dirents[i], cls ); - if( rc != 0 ) { - - vdev_error("loader_at(%d, '%s') rc = %d\n", dirfd, dirents[i]->d_name, rc ); - - vdev_dirents_free( dirents, num_entries ); - return rc; - } - } - - vdev_dirents_free( dirents, num_entries ); - - return rc; -} +int vdev_load_all_at(int dirfd, vdev_dirent_loader_at_t loader_at, void *cls) +{ + + struct dirent **dirents = NULL; + int num_entries = 0; + int rc = 0; + + if (loader_at == NULL) { + return -EINVAL; + } + num_entries = + vdev_portable_scandirat(dirfd, ".", &dirents, NULL, alphasort); + if (num_entries < 0) { + + rc = -errno; + vdev_error("scandirat(%d) rc = %d\n", dirfd, rc); + return rc; + } + + for (int i = 0; i < num_entries; i++) { + + // process this + rc = (*loader_at) (dirfd, dirents[i], cls); + if (rc != 0) { + + vdev_error("loader_at(%d, '%s') rc = %d\n", dirfd, + dirents[i]->d_name, rc); + + vdev_dirents_free(dirents, num_entries); + return rc; + } + } + + vdev_dirents_free(dirents, num_entries); + + return rc; +} // process all files in a directory with a loader, in alphanumeric order // return 0 on success @@ -887,242 +886,240 @@ int vdev_load_all_at( int dirfd, vdev_dirent_loader_at_t loader_at, void* cls ) // return -ENOMEM if OOM // return -errno on I/O error // return non-zero if loader fails -int vdev_load_all( char const* dir_path, vdev_dirent_loader_t loader, void* cls ) { - - struct dirent** dirents = NULL; - int num_entries = 0; - int rc = 0; - - if( dir_path == NULL || loader == NULL ) { - return -EINVAL; - } - - num_entries = scandir( dir_path, &dirents, NULL, alphasort ); - if( num_entries < 0 ) { - - rc = -errno; - vdev_error("scandir('%s') rc = %d\n", dir_path, rc ); - return rc; - } - - for( int i = 0; i < num_entries; i++ ) { - - // full path... - char* fp = vdev_fullpath( dir_path, dirents[i]->d_name, NULL ); - if( fp == NULL ) { - - vdev_dirents_free( dirents, num_entries ); - return -ENOMEM; - } - - // process this - rc = (*loader)( fp, cls ); - if( rc != 0 ) { - - vdev_error("loader('%s') rc = %d\n", fp, rc ); - - free( fp ); - vdev_dirents_free( dirents, num_entries ); - return rc; - } - - free( fp ); - } - - vdev_dirents_free( dirents, num_entries ); - - return 0; -} +int vdev_load_all(char const *dir_path, vdev_dirent_loader_t loader, void *cls) +{ + + struct dirent **dirents = NULL; + int num_entries = 0; + int rc = 0; + if (dir_path == NULL || loader == NULL) { + return -EINVAL; + } + + num_entries = scandir(dir_path, &dirents, NULL, alphasort); + if (num_entries < 0) { + + rc = -errno; + vdev_error("scandir('%s') rc = %d\n", dir_path, rc); + return rc; + } + + for (int i = 0; i < num_entries; i++) { + + // full path... + char *fp = vdev_fullpath(dir_path, dirents[i]->d_name, NULL); + if (fp == NULL) { + + vdev_dirents_free(dirents, num_entries); + return -ENOMEM; + } + // process this + rc = (*loader) (fp, cls); + if (rc != 0) { + + vdev_error("loader('%s') rc = %d\n", fp, rc); + + free(fp); + vdev_dirents_free(dirents, num_entries); + return rc; + } + + free(fp); + } + + vdev_dirents_free(dirents, num_entries); + + return 0; +} // make a string of directories, given the path dirp // return 0 if the directory exists at the end of the call. // return -EINVAL if dirp is NULL // return -ENOMEM if OOM // return negative if the directory could not be created. -int vdev_mkdirs( char const* dirp, int start, mode_t mode ) { - - unsigned int i = start; - char* currdir = NULL; - struct stat statbuf; - int rc = 0; - - if( dirp == NULL ) { - return -EINVAL; - } - - currdir = VDEV_CALLOC( char, strlen(dirp) + 1 ); - if( currdir == NULL ) { - return -ENOMEM; - } - - while( i <= strlen(dirp) ) { - - // next '/' - if( dirp[i] == '/' || i == strlen(dirp) ) { - - strncpy( currdir, dirp, i == 0 ? 1 : i ); - - rc = stat( currdir, &statbuf ); - if( rc == 0 && !S_ISDIR( statbuf.st_mode ) ) { - - // something else exists here - free( currdir ); - return -ENOTDIR; - } - - if( rc != 0 ) { - - // try to make this directory - rc = mkdir( currdir, mode ); - if( rc != 0 ) { - - rc = -errno; - free(currdir); - return rc; - } - } - } - - i++; - } - - free(currdir); - return 0; -} +int vdev_mkdirs(char const *dirp, int start, mode_t mode) +{ + + unsigned int i = start; + char *currdir = NULL; + struct stat statbuf; + int rc = 0; + + if (dirp == NULL) { + return -EINVAL; + } + + currdir = VDEV_CALLOC(char, strlen(dirp) + 1); + if (currdir == NULL) { + return -ENOMEM; + } + + while (i <= strlen(dirp)) { + + // next '/' + if (dirp[i] == '/' || i == strlen(dirp)) { + + strncpy(currdir, dirp, i == 0 ? 1 : i); + + rc = stat(currdir, &statbuf); + if (rc == 0 && !S_ISDIR(statbuf.st_mode)) { + + // something else exists here + free(currdir); + return -ENOTDIR; + } + if (rc != 0) { + + // try to make this directory + rc = mkdir(currdir, mode); + if (rc != 0) { + + rc = -errno; + free(currdir); + return rc; + } + } + } + + i++; + } + + free(currdir); + return 0; +} // try to remove a path of directories // the must all be emtpy // return 0 on success // return negative on error -int vdev_rmdirs( char const* dirp ) { - - char* dirname = NULL; - int rc = 0; - - if( dirp == NULL ) { - return -EINVAL; - } - - dirname = strdup( dirp ); - - while( strlen(dirname) > 0 ) { - - rc = rmdir( dirname ); - - if( rc != 0 ) { - - rc = -errno; - break; - } - else { - - char* tmp = vdev_dirname( dirname, NULL ); - if( tmp == NULL ) { - return -ENOMEM; - } - - free( dirname ); - - dirname = tmp; - } - } - - free( dirname ); - return rc; -} +int vdev_rmdirs(char const *dirp) +{ + + char *dirname = NULL; + int rc = 0; + + if (dirp == NULL) { + return -EINVAL; + } + + dirname = strdup(dirp); + + while (strlen(dirname) > 0) { + rc = rmdir(dirname); + + if (rc != 0) { + + rc = -errno; + break; + } else { + + char *tmp = vdev_dirname(dirname, NULL); + if (tmp == NULL) { + return -ENOMEM; + } + + free(dirname); + + dirname = tmp; + } + } + + free(dirname); + return rc; +} // parse an unsigned 64-bit number // uint64_str must contain *only* the text of the number // return the number, and set *success to true if we succeeded // return -EINVAL if any of hte arguments were NULL // return 0, LLONG_MAX, or LLONG_MIN if we failed -uint64_t vdev_parse_uint64( char const* uint64_str, bool* success ) { - - if( uint64_str == NULL || success == NULL ) { - return -EINVAL; - } - - char* tmp = NULL; - uint64_t uid = (uint64_t)strtoll( uint64_str, &tmp, 10 ); - - if( tmp == uint64_str ) { - *success = false; - } - else { - *success = true; - } - - return uid; -} +uint64_t vdev_parse_uint64(char const *uint64_str, bool * success) +{ + + if (uint64_str == NULL || success == NULL) { + return -EINVAL; + } + + char *tmp = NULL; + uint64_t uid = (uint64_t) strtoll(uint64_str, &tmp, 10); + if (tmp == uint64_str) { + *success = false; + } else { + *success = true; + } + + return uid; +} // given a null-terminated key=value string, chomp it into a null-terminated key and value. // return the original length of the string. // return -EINVAL if any argument is NULL // return negative on error -int vdev_keyvalue_next( char* keyvalue, char** key, char** value ) { - - if( keyvalue == NULL || key == NULL || value == NULL ) { - return -EINVAL; - } - - int ret = strlen(keyvalue); - char* tmp = NULL; - - // find the '=' - tmp = strchr(keyvalue, '='); - if( tmp == NULL ) { - - return -EINVAL; - } - - *key = keyvalue; - *tmp = '\0'; - tmp++; - - *value = tmp; - - return ret; -} +int vdev_keyvalue_next(char *keyvalue, char **key, char **value) +{ + + if (keyvalue == NULL || key == NULL || value == NULL) { + return -EINVAL; + } + + int ret = strlen(keyvalue); + char *tmp = NULL; + // find the '=' + tmp = strchr(keyvalue, '='); + if (tmp == NULL) { + + return -EINVAL; + } + + *key = keyvalue; + *tmp = '\0'; + tmp++; + + *value = tmp; + + return ret; +} // set up the library // always succeeds -void vdev_setup_global(void) { - - // seed random from monotonic clock - struct timespec ts_mono; - struct timespec ts_clock; - int rc = 0; - unsigned short seedv[3]; - int32_t lower_32; - - clock_gettime( CLOCK_MONOTONIC, &ts_mono ); - clock_gettime( CLOCK_REALTIME, &ts_clock ); - - // NOTE: it's okay to use uninitialized memory for the random seed, - // so we don't really care if clock_gettime fails - - lower_32 = ts_mono.tv_nsec + ts_clock.tv_nsec; - memcpy( seedv, &lower_32, 3 ); - - seed48( seedv ); -} +void vdev_setup_global(void) +{ + + // seed random from monotonic clock + struct timespec ts_mono; + struct timespec ts_clock; + int rc = 0; + unsigned short seedv[3]; + int32_t lower_32; + + clock_gettime(CLOCK_MONOTONIC, &ts_mono); + clock_gettime(CLOCK_REALTIME, &ts_clock); + // NOTE: it's okay to use uninitialized memory for the random seed, + // so we don't really care if clock_gettime fails + + lower_32 = ts_mono.tv_nsec + ts_clock.tv_nsec; + memcpy(seedv, &lower_32, 3); + + seed48(seedv); +} // portable cast pthread_t to uint64_t -unsigned long long int vdev_pthread_self(void) { - - union { - pthread_t t; - uint64_t i; - } vdev_pthread; - - vdev_pthread.i = 0; - vdev_pthread.t = pthread_self(); - - return vdev_pthread.i; +unsigned long long int vdev_pthread_self(void) +{ + + union { + pthread_t t; + uint64_t i; + } vdev_pthread; + + vdev_pthread.i = 0; + vdev_pthread.t = pthread_self(); + + return vdev_pthread.i; } diff --git a/libvdev/util.h b/libvdev/util.h index 63a715b..5e3bf95 100644 --- a/libvdev/util.h +++ b/libvdev/util.h @@ -24,11 +24,11 @@ #ifndef _POSIX_C_SOURCE #define _POSIX_C_SOURCE 200809L -#endif +#endif #ifndef _XOPEN_SOURCE #define _XOPEN_SOURCE 700 -#endif +#endif #ifndef _DEFAULT_SOURCE #define _DEFAULT_SOURCE @@ -100,7 +100,6 @@ extern int _VDEV_SYSLOG; } \ } while(0) - #define vdev_info( format, ... ) \ do { \ if( _VDEV_INFO_MESSAGES ) { \ @@ -113,7 +112,6 @@ extern int _VDEV_SYSLOG; } \ } while(0) - #define vdev_warn( format, ... ) \ do { \ if( _VDEV_WARN_MESSAGES ) { \ @@ -124,9 +122,8 @@ extern int _VDEV_SYSLOG; fprintf(stderr, VDEV_WHERESTR "WARN: " format, VDEV_WHEREARG, __VA_ARGS__); fflush(stderr);\ } \ } \ - } while(0) + } while(0) - #define vdev_error( format, ... ) \ do { \ if( _VDEV_ERROR_MESSAGES ) { \ @@ -138,15 +135,14 @@ extern int _VDEV_SYSLOG; } \ } \ } while(0) - - + #define vdev_error_async_safe( msg ) \ do { \ if( _VDEV_ERROR_MESSAGES ) { \ write( STDERR_FILENO, "[vdev error async] " msg, strlen( "[vdev error async] " msg ) ); \ } \ } while(0) - + #define VDEV_CALLOC(type, count) (type*)calloc( sizeof(type) * (count), 1 ) #define VDEV_FREE_LIST(list) do { if( (list) != NULL ) { for(unsigned int __i = 0; (list)[__i] != NULL; ++ __i) { if( (list)[__i] != NULL ) { free( (list)[__i] ); (list)[__i] = NULL; }} free( (list) ); } } while(0) #define VDEV_SIZE_LIST(sz, list) for( *(sz) = 0; (list)[*(sz)] != NULL; ++ *(sz) ); @@ -158,62 +154,63 @@ extern int _VDEV_SYSLOG; #define MAX(x,y) ((x) > (y) ? (x) : (y)) #endif -#ifndef MIN +#ifndef MIN #define MIN(x,y) ((x) < (y) ? (x) : (y)) -#endif +#endif #ifdef __cplusplus #define C_LINKAGE_BEGIN extern "C" { #define C_LINKAGE_END } #else -#define C_LINKAGE_BEGIN +#define C_LINKAGE_BEGIN #define C_LINKAGE_END -#endif +#endif -typedef int (*vdev_dirent_loader_t)( char const*, void* ); -typedef int (*vdev_dirent_loader_at_t)( int, struct dirent* dent, void* ); +typedef int (*vdev_dirent_loader_t) (char const *, void *); +typedef int (*vdev_dirent_loader_at_t) (int, struct dirent * dent, void *); C_LINKAGE_BEGIN - // debug functions -void vdev_set_debug_level( int d ); -void vdev_set_error_level( int e ); +void vdev_set_debug_level(int d); +void vdev_set_error_level(int e); int vdev_get_debug_level(); int vdev_get_error_level(); int vdev_enable_syslog(); // system functions -int vdev_daemonize( void ); -int vdev_subprocess( char const* cmd, char* const env[], char** output, size_t max_output, int stderr_fd, int* exit_status, bool use_shell ); -int vdev_log_redirect( char const* logfile_path ); -int vdev_pidfile_write( char const* pidfile_path ); +int vdev_daemonize(void); +int vdev_subprocess(char const *cmd, char *const env[], char **output, + size_t max_output, int stderr_fd, int *exit_status, + bool use_shell); +int vdev_log_redirect(char const *logfile_path); +int vdev_pidfile_write(char const *pidfile_path); // parser functions -int vdev_keyvalue_next( char* keyvalue, char** key, char** value ); -uint64_t vdev_parse_uint64( char const* uint64_str, bool* success ); +int vdev_keyvalue_next(char *keyvalue, char **key, char **value); +uint64_t vdev_parse_uint64(char const *uint64_str, bool * success); // I/O functions -ssize_t vdev_read_uninterrupted( int fd, char* buf, size_t len ); -ssize_t vdev_write_uninterrupted( int fd, char const* buf, size_t len ); -int vdev_read_file( char const* path, char* buf, size_t len ); -int vdev_write_file( char const* path, char const* buf, size_t len, int flags, mode_t mode ); +ssize_t vdev_read_uninterrupted(int fd, char *buf, size_t len); +ssize_t vdev_write_uninterrupted(int fd, char const *buf, size_t len); +int vdev_read_file(char const *path, char *buf, size_t len); +int vdev_write_file(char const *path, char const *buf, size_t len, int flags, + mode_t mode); // directory I/O -int vdev_load_all( char const* dir_path, vdev_dirent_loader_t loader, void* cls ); -int vdev_load_all_at( int dirfd, vdev_dirent_loader_at_t loader_at, void* cls ); -int vdev_mkdirs( char const* dirp, int start, mode_t mode ); -int vdev_rmdirs( char const* dirp ); +int vdev_load_all(char const *dir_path, vdev_dirent_loader_t loader, void *cls); +int vdev_load_all_at(int dirfd, vdev_dirent_loader_at_t loader_at, void *cls); +int vdev_mkdirs(char const *dirp, int start, mode_t mode); +int vdev_rmdirs(char const *dirp); // misc -char* vdev_fullpath( char const* root, char const* path, char* dest ); -char* vdev_dirname( char const* path, char* dest ); -size_t vdev_basename_len( char const* path ); -char* vdev_basename( char const* path, char* dest ); +char *vdev_fullpath(char const *root, char const *path, char *dest); +char *vdev_dirname(char const *path, char *dest); +size_t vdev_basename_len(char const *path); +char *vdev_basename(char const *path, char *dest); unsigned long long int vdev_pthread_self(void); // setup void vdev_setup_global(void); C_LINKAGE_END - #endif diff --git a/tools/udev_to_vdev/udev_rule.h b/tools/udev_to_vdev/udev_rule.h index b4446a8..a25edd3 100644 --- a/tools/udev_to_vdev/udev_rule.h +++ b/tools/udev_to_vdev/udev_rule.h @@ -14,53 +14,60 @@ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH RE #include #include -template -class lockable : public type -{ -public: - inline lockable(void) : m_locked(false) { } - inline bool is_locked(void) const { return m_locked; } - inline void lock (void) { m_locked = true ; } - inline void unlock(void) { m_locked = false; } -private: - bool m_locked; + template < typename type > class lockable:public type { + public: + inline lockable(void):m_locked(false) { + } + inline bool is_locked(void) const { + return m_locked; + } inline void lock(void) { + m_locked = true; + } + inline void unlock(void) { + m_locked = false; + } + private: + bool m_locked; }; // parser a single field -struct udev_field_t -{ - inline udev_field_t(void) { subname.lock(); } - bool operator << (const char& input) throw(const char*); // returns false when full - void clear(void); - inline bool full(void) const { return value.is_locked(); } - inline bool empty(void) const { return value.empty(); } - - lockable name; - lockable subname; - lockable op; - lockable value; +struct udev_field_t { + inline udev_field_t(void) { + subname.lock(); + } bool operator <<(const char &input) throw(const char *); // returns false when full + void clear(void); + inline bool full(void) const { + return value.is_locked(); + } inline bool empty(void)const { + return value.empty(); + } lockable < std::string > name; + lockable < std::string > subname; + lockable < std::string > op; + lockable < std::string > value; }; // parses all fields in rule -struct udev_rule_t -{ - inline udev_rule_t(void) : line_continues(false) { fields.emplace_back(); comment.lock(); } - bool operator << (const char& input) throw(const char*); // returns false when full - void clear(void); - inline bool full(void) const { return fields.is_locked(); } - inline bool empty(void) const { return fields.back().empty(); } - - lockable> fields; - bool line_continues; - lockable comment; +struct udev_rule_t { + inline udev_rule_t(void):line_continues(false) { + fields.emplace_back(); + comment.lock(); + } bool operator <<(const char &input) throw(const char *); // returns false when full + void clear(void); + inline bool full(void) const { + return fields.is_locked(); + } inline bool empty(void)const { + return fields.back().empty(); + } lockable < std::list < udev_field_t >> fields; + bool line_continues; + lockable < std::string > comment; }; -struct udev_rule_file_t -{ - inline udev_rule_file_t(void) { rules.emplace_back(); } - void operator << (const char& input) throw(const char*); - void clear(void); +struct udev_rule_file_t { + inline udev_rule_file_t(void) { + rules.emplace_back(); + } void operator <<(const char &input) throw(const char *); + void clear(void); - std::list rules; + std::list < udev_rule_t > rules; }; -#endif // UDEV_FIELD_H +#endif // UDEV_FIELD_H diff --git a/vdevd/action.c b/vdevd/action.c index 1d4067d..ab8e1f4 100644 --- a/vdevd/action.c +++ b/vdevd/action.c @@ -29,519 +29,594 @@ #include "libvdev/ini.h" // to be passed into the action loader loop -struct vdev_action_loader_cls { +struct vdev_action_loader_cls +{ - struct sglib_vdev_action_vector *acts; - struct vdev_config *config; + struct sglib_vdev_action_vector *acts; + struct vdev_config *config; }; // prototypes -SGLIB_DEFINE_VECTOR_PROTOTYPES(vdev_action); -SGLIB_DEFINE_VECTOR_FUNCTIONS(vdev_action); +SGLIB_DEFINE_VECTOR_PROTOTYPES (vdev_action); +SGLIB_DEFINE_VECTOR_FUNCTIONS (vdev_action); -static int vdev_action_daemonlet_stop(struct vdev_action *act); +static int vdev_action_daemonlet_stop (struct vdev_action *act); // initialize an action // return 0 on success // return -ENOMEM on OOM -int vdev_action_init(struct vdev_action *act, vdev_device_request_t trigger, - char *path, char *command, char *helper, bool async) +int +vdev_action_init (struct vdev_action *act, vdev_device_request_t trigger, + char *path, char *command, char *helper, bool async) { - int rc = 0; - memset(act, 0, sizeof(struct vdev_action)); + int rc = 0; + memset (act, 0, sizeof (struct vdev_action)); - act->trigger = trigger; - act->path = vdev_strdup_or_null(path); - act->command = vdev_strdup_or_null(command); - act->helper = vdev_strdup_or_null(helper); - act->async = async; + act->trigger = trigger; + act->path = vdev_strdup_or_null (path); + act->command = vdev_strdup_or_null (command); + act->helper = vdev_strdup_or_null (helper); + act->async = async; - act->is_daemonlet = false; - act->daemonlet_stdin = -1; - act->daemonlet_stdout = -1; - act->daemonlet_pid = -1; + act->is_daemonlet = false; + act->daemonlet_stdin = -1; + act->daemonlet_stdout = -1; + act->daemonlet_pid = -1; - if (act->path != NULL) { + if (act->path != NULL) + { - rc = vdev_match_regex_init(&act->path_regex, path); + rc = vdev_match_regex_init (&act->path_regex, path); - if (rc != 0) { + if (rc != 0) + { - vdev_error("vdev_match_regex_init('%s') rc = %d\n", - path, rc); - vdev_action_free(act); - return rc; - } + vdev_error ("vdev_match_regex_init('%s') rc = %d\n", path, rc); + vdev_action_free (act); + return rc; } + } - return 0; + return 0; } // add a device parameter to match on // return 0 on success // return -ENOMEM on OOM // return -EEXIST if name already exists -int vdev_action_add_param(struct vdev_action *act, char const *name, - char const *value) +int +vdev_action_add_param (struct vdev_action *act, char const *name, + char const *value) { - return vdev_params_add(&act->dev_params, name, value); + return vdev_params_add (&act->dev_params, name, value); } // add an environment variable to send to a helper // return 0 on success // return -ENOMEM on OOM // return -EEXIST if the name already exists -int vdev_action_add_var(struct vdev_action *act, char const *name, - char const *value) +int +vdev_action_add_var (struct vdev_action *act, char const *name, + char const *value) { - return vdev_params_add(&act->helper_vars, name, value); + return vdev_params_add (&act->helper_vars, name, value); } // free an action // always succeeds // NOTE: does NOT touch the daemonlet state. -int vdev_action_free(struct vdev_action *act) +int +vdev_action_free (struct vdev_action *act) { - if (act->name != NULL) { + if (act->name != NULL) + { - free(act->name); - act->name = NULL; - } + free (act->name); + act->name = NULL; + } - if (act->command != NULL) { + if (act->command != NULL) + { - free(act->command); - act->command = NULL; - } + free (act->command); + act->command = NULL; + } - if (act->rename_command != NULL) { + if (act->rename_command != NULL) + { - free(act->rename_command); - act->rename_command = NULL; - } + free (act->rename_command); + act->rename_command = NULL; + } - if (act->dev_params != NULL) { + if (act->dev_params != NULL) + { - vdev_params_free(act->dev_params); - act->dev_params = NULL; - } + vdev_params_free (act->dev_params); + act->dev_params = NULL; + } - if (act->helper_vars != NULL) { + if (act->helper_vars != NULL) + { - vdev_params_free(act->helper_vars); - act->helper_vars = NULL; - } + vdev_params_free (act->helper_vars); + act->helper_vars = NULL; + } - if (act->helper != NULL) { + if (act->helper != NULL) + { - free(act->helper); - act->helper = NULL; - } + free (act->helper); + act->helper = NULL; + } - if (act->path != NULL) { + if (act->path != NULL) + { - free(act->path); - act->path = NULL; + free (act->path); + act->path = NULL; - regfree(&act->path_regex); - } + regfree (&act->path_regex); + } - if (act->type != NULL) { + if (act->type != NULL) + { - free(act->type); - act->type = NULL; - } + free (act->type); + act->type = NULL; + } - return 0; + return 0; } // convert an action into a device request // return the constant associated with the type on success // return VDEV_DEVICE_INVALID if the type is not recognized -vdev_device_request_t vdev_action_parse_trigger(char const *type) +vdev_device_request_t +vdev_action_parse_trigger (char const *type) { - if (strcmp(type, VDEV_ACTION_EVENT_ADD) == 0) { - return VDEV_DEVICE_ADD; - } else if (strcmp(type, VDEV_ACTION_EVENT_REMOVE) == 0) { - return VDEV_DEVICE_REMOVE; - } else if (strcmp(type, VDEV_ACTION_EVENT_CHANGE) == 0) { - return VDEV_DEVICE_CHANGE; - } else if (strcmp(type, VDEV_ACTION_EVENT_ANY) == 0) { - return VDEV_DEVICE_ANY; - } - - return VDEV_DEVICE_INVALID; + if (strcmp (type, VDEV_ACTION_EVENT_ADD) == 0) + { + return VDEV_DEVICE_ADD; + } + else if (strcmp (type, VDEV_ACTION_EVENT_REMOVE) == 0) + { + return VDEV_DEVICE_REMOVE; + } + else if (strcmp (type, VDEV_ACTION_EVENT_CHANGE) == 0) + { + return VDEV_DEVICE_CHANGE; + } + else if (strcmp (type, VDEV_ACTION_EVENT_ANY) == 0) + { + return VDEV_DEVICE_ANY; + } + + return VDEV_DEVICE_INVALID; } // parse an action from an ini file // return 1 for parsed // return 0 for not parsed -static int vdev_action_ini_parser(void *userdata, char const *section, - char const *name, char const *value) +static int +vdev_action_ini_parser (void *userdata, char const *section, + char const *name, char const *value) { - struct vdev_action *act = (struct vdev_action *)userdata; - int rc = 0; + struct vdev_action *act = (struct vdev_action *) userdata; + int rc = 0; - if (strcmp(section, VDEV_ACTION_NAME) == 0) { + if (strcmp (section, VDEV_ACTION_NAME) == 0) + { - if (strcmp(name, VDEV_ACTION_NAME_PATH) == 0) { - // path? - if (act->path != NULL) { + if (strcmp (name, VDEV_ACTION_NAME_PATH) == 0) + { + // path? + if (act->path != NULL) + { - free(act->path); - } + free (act->path); + } - act->path = vdev_strdup_or_null(value); + act->path = vdev_strdup_or_null (value); - if (act->path == NULL) { - // EOM - return 0; - } else { - rc = vdev_match_regex_init(&act->path_regex, - act->path); + if (act->path == NULL) + { + // EOM + return 0; + } + else + { + rc = vdev_match_regex_init (&act->path_regex, act->path); - if (rc != 0) { + if (rc != 0) + { - vdev_error - ("vdev_match_regex_init('%s') rc = %d\n", - act->path, rc); - return 0; - } - } - return 1; + vdev_error + ("vdev_match_regex_init('%s') rc = %d\n", act->path, rc); + return 0; } + } + return 1; + } - if (strcmp(name, VDEV_ACTION_NAME_RENAME) == 0) { + if (strcmp (name, VDEV_ACTION_NAME_RENAME) == 0) + { - // rename command - if (act->rename_command != NULL) { + // rename command + if (act->rename_command != NULL) + { - free(act->rename_command); - } + free (act->rename_command); + } - act->rename_command = vdev_strdup_or_null(value); - return 1; - } + act->rename_command = vdev_strdup_or_null (value); + return 1; + } - if (strcmp(name, VDEV_ACTION_NAME_EVENT) == 0) { + if (strcmp (name, VDEV_ACTION_NAME_EVENT) == 0) + { - // event? - act->trigger = vdev_action_parse_trigger(value); + // event? + act->trigger = vdev_action_parse_trigger (value); - if (act->trigger == VDEV_DEVICE_INVALID) { + if (act->trigger == VDEV_DEVICE_INVALID) + { - fprintf(stderr, "Invalid event type '%s'\n", - value); - return 0; - } else { - return 1; - } - } + fprintf (stderr, "Invalid event type '%s'\n", value); + return 0; + } + else + { + return 1; + } + } - if (strcmp(name, VDEV_ACTION_NAME_COMMAND) == 0) { + if (strcmp (name, VDEV_ACTION_NAME_COMMAND) == 0) + { - // shell command - if (act->command != NULL) { + // shell command + if (act->command != NULL) + { - free(act->command); - } + free (act->command); + } - act->command = vdev_strdup_or_null(value); - return 1; - } + act->command = vdev_strdup_or_null (value); + return 1; + } - if (strcmp(name, VDEV_ACTION_NAME_HELPER) == 0) { + if (strcmp (name, VDEV_ACTION_NAME_HELPER) == 0) + { - // helper in /lib/vdev - if (act->helper != NULL) { + // helper in /lib/vdev + if (act->helper != NULL) + { - free(act->helper); - } + free (act->helper); + } - act->helper = vdev_strdup_or_null(value); - return 1; - } + act->helper = vdev_strdup_or_null (value); + return 1; + } - if (strcmp(name, VDEV_ACTION_NAME_ASYNC) == 0) { + if (strcmp (name, VDEV_ACTION_NAME_ASYNC) == 0) + { - // async? - if (strcasecmp(value, "true") == 0 - || strcmp(value, "1") == 0) { + // async? + if (strcasecmp (value, "true") == 0 || strcmp (value, "1") == 0) + { - act->async = true; - return 1; - } else if (strcasecmp(value, "false") == 0 - || strcmp(value, "0") == 0) { + act->async = true; + return 1; + } + else if (strcasecmp (value, "false") == 0 + || strcmp (value, "0") == 0) + { - act->async = false; - return 1; - } else { + act->async = false; + return 1; + } + else + { - fprintf(stderr, "Invalid async value '%s'\n", - value); - return 0; - } - } + fprintf (stderr, "Invalid async value '%s'\n", value); + return 0; + } + } - if (strcmp(name, VDEV_ACTION_NAME_TYPE) == 0) { + if (strcmp (name, VDEV_ACTION_NAME_TYPE) == 0) + { - // remember this - act->has_type = true; - act->type = vdev_strdup_or_null(value); - return 1; - } + // remember this + act->has_type = true; + act->type = vdev_strdup_or_null (value); + return 1; + } - if (strcmp(name, VDEV_ACTION_NAME_IF_EXISTS) == 0) { + if (strcmp (name, VDEV_ACTION_NAME_IF_EXISTS) == 0) + { - // if-exists flag - if (strcmp(value, VDEV_ACTION_IF_EXISTS_ERROR) == 0) { + // if-exists flag + if (strcmp (value, VDEV_ACTION_IF_EXISTS_ERROR) == 0) + { - act->if_exists = VDEV_IF_EXISTS_ERROR; - return 1; - } + act->if_exists = VDEV_IF_EXISTS_ERROR; + return 1; + } - if (strcmp(value, VDEV_ACTION_IF_EXISTS_MASK) == 0) { + if (strcmp (value, VDEV_ACTION_IF_EXISTS_MASK) == 0) + { - act->if_exists = VDEV_IF_EXISTS_MASK; - return 1; - } + act->if_exists = VDEV_IF_EXISTS_MASK; + return 1; + } - if (strcmp(value, VDEV_ACTION_IF_EXISTS_RUN) == 0) { + if (strcmp (value, VDEV_ACTION_IF_EXISTS_RUN) == 0) + { - act->if_exists = VDEV_IF_EXISTS_RUN; - return 1; - } + act->if_exists = VDEV_IF_EXISTS_RUN; + return 1; + } - fprintf(stderr, "Invalid '%s' value '%s'\n", name, - value); - return 0; - } + fprintf (stderr, "Invalid '%s' value '%s'\n", name, value); + return 0; + } - if (strcmp(name, VDEV_ACTION_DAEMONLET) == 0) { + if (strcmp (name, VDEV_ACTION_DAEMONLET) == 0) + { - // this is a daemonlet - if (strcasecmp(value, "true") == 0) { + // this is a daemonlet + if (strcasecmp (value, "true") == 0) + { - act->is_daemonlet = true; - } + act->is_daemonlet = true; + } - return 1; - } + return 1; + } - if (strncmp - (name, VDEV_ACTION_NAME_OS_PREFIX, - strlen(VDEV_ACTION_NAME_OS_PREFIX)) == 0) { - - // OS-specific param - rc = vdev_action_add_param(act, - name + - strlen - (VDEV_ACTION_NAME_OS_PREFIX), - value); - - if (rc == 0) { - return 1; - } else { - vdev_error - ("vdev_action_add_param( '%s', '%s' ) rc = %d\n", - name, value, rc); - return 0; - } - } + if (strncmp + (name, VDEV_ACTION_NAME_OS_PREFIX, + strlen (VDEV_ACTION_NAME_OS_PREFIX)) == 0) + { - if (strncmp - (name, VDEV_ACTION_NAME_VAR_PREFIX, - strlen(VDEV_ACTION_NAME_VAR_PREFIX)) == 0) { - - // helper-specific variable - rc = vdev_action_add_var(act, - name + - strlen - (VDEV_ACTION_NAME_VAR_PREFIX), - value); - - if (rc == 0) { - return 1; - } else { - vdev_error - ("vdev_action_add_var( '%s', '%s' ) rc = %d\n", - name, value, rc); - return 0; - } - } - fprintf(stderr, "Unknown field '%s' in section '%s'\n", name, - section); - return 0; + // OS-specific param + rc = vdev_action_add_param (act, + name + + strlen + (VDEV_ACTION_NAME_OS_PREFIX), value); + + if (rc == 0) + { + return 1; + } + else + { + vdev_error + ("vdev_action_add_param( '%s', '%s' ) rc = %d\n", + name, value, rc); + return 0; + } } - fprintf(stderr, "Unknown section '%s'\n", section); - return 0; + if (strncmp + (name, VDEV_ACTION_NAME_VAR_PREFIX, + strlen (VDEV_ACTION_NAME_VAR_PREFIX)) == 0) + { + + // helper-specific variable + rc = vdev_action_add_var (act, + name + + strlen + (VDEV_ACTION_NAME_VAR_PREFIX), value); + + if (rc == 0) + { + return 1; + } + else + { + vdev_error + ("vdev_action_add_var( '%s', '%s' ) rc = %d\n", + name, value, rc); + return 0; + } + } + fprintf (stderr, "Unknown field '%s' in section '%s'\n", name, section); + return 0; + } + + fprintf (stderr, "Unknown section '%s'\n", section); + return 0; } // sanity check an action // return 0 on success // return -EINVAL if invalid -int vdev_action_sanity_check(struct vdev_action *act) +int +vdev_action_sanity_check (struct vdev_action *act) { - int rc = 0; + int rc = 0; - if (act->command == NULL && act->rename_command == NULL - && act->helper == NULL) { + if (act->command == NULL && act->rename_command == NULL + && act->helper == NULL) + { - fprintf(stderr, - "Action is missing 'command=', 'rename_command=', and 'helper='\n"); - rc = -EINVAL; - } + fprintf (stderr, + "Action is missing 'command=', 'rename_command=', and 'helper='\n"); + rc = -EINVAL; + } - if (act->command != NULL && act->helper != NULL) { + if (act->command != NULL && act->helper != NULL) + { - fprintf(stderr, "Action has both 'command=' and 'helper='\n"); - rc = -EINVAL; - } + fprintf (stderr, "Action has both 'command=' and 'helper='\n"); + rc = -EINVAL; + } - if (act->trigger == VDEV_DEVICE_INVALID) { + if (act->trigger == VDEV_DEVICE_INVALID) + { - fprintf(stderr, "Action is missing 'event='\n"); - rc = -EINVAL; - } + fprintf (stderr, "Action is missing 'event='\n"); + rc = -EINVAL; + } - return rc; + return rc; } // perform misc. post-processing on an action: // * if the command is NULL but the helper is not, then set command to be the full path to the helper, and don't use a shell // return 0 on success // return -ENOMEM on OOM -int vdev_action_postprocess(struct vdev_config *config, struct vdev_action *act) +int +vdev_action_postprocess (struct vdev_config *config, struct vdev_action *act) { - int rc = 0; + int rc = 0; - if (act->command == NULL && act->helper != NULL) { + if (act->command == NULL && act->helper != NULL) + { - act->command = - VDEV_CALLOC(char, - strlen(config->helpers_dir) + 1 + - strlen(act->helper) + 1); - if (act->command == NULL) { - return -ENOMEM; - } + act->command = + VDEV_CALLOC (char, + strlen (config->helpers_dir) + 1 + + strlen (act->helper) + 1); + if (act->command == NULL) + { + return -ENOMEM; + } - sprintf(act->command, "%s/%s", config->helpers_dir, - act->helper); + sprintf (act->command, "%s/%s", config->helpers_dir, act->helper); - act->use_shell = false; - } else { + act->use_shell = false; + } + else + { - // given a shell command string - act->use_shell = true; - } + // given a shell command string + act->use_shell = true; + } - return rc; + return rc; } // load an action from a file // return 0 on success // return -errno on failure to open, read, parse, or close // return -EINVAL if the loaded action fails our sanity tests -int vdev_action_load_file(struct vdev_config *config, char const *path, - struct vdev_action *act, FILE * f) +int +vdev_action_load_file (struct vdev_config *config, char const *path, + struct vdev_action *act, FILE * f) { - int rc = 0; - - rc = ini_parse_file(f, vdev_action_ini_parser, act); - if (rc != 0) { - vdev_error("ini_parse_file(action) rc = %d\n", rc); - } else { - rc = vdev_action_sanity_check(act); - if (rc != 0) { - vdev_error("Invalid action '%s'\n", path); - } - } - - if (rc == 0) { - - // postprocess - rc = vdev_action_postprocess(config, act); - } - return rc; + int rc = 0; + + rc = ini_parse_file (f, vdev_action_ini_parser, act); + if (rc != 0) + { + vdev_error ("ini_parse_file(action) rc = %d\n", rc); + } + else + { + rc = vdev_action_sanity_check (act); + if (rc != 0) + { + vdev_error ("Invalid action '%s'\n", path); + } + } + + if (rc == 0) + { + + // postprocess + rc = vdev_action_postprocess (config, act); + } + return rc; } // load an action from a path // return -ENOMEM if OOM // return -errno on failure to open or read the file // return -EINVAL if the file could not be parsed -int vdev_action_load(struct vdev_config *config, char const *path, - struct vdev_action *act) +int +vdev_action_load (struct vdev_config *config, char const *path, + struct vdev_action *act) { - int rc = 0; - FILE *f = NULL; + int rc = 0; + FILE *f = NULL; - rc = vdev_action_init(act, VDEV_DEVICE_INVALID, NULL, NULL, NULL, - false); - if (rc != 0) { + rc = vdev_action_init (act, VDEV_DEVICE_INVALID, NULL, NULL, NULL, false); + if (rc != 0) + { - vdev_error("vdev_action_init('%s') rc = %d\n", path, rc); - return rc; - } + vdev_error ("vdev_action_init('%s') rc = %d\n", path, rc); + return rc; + } - f = fopen(path, "r"); - if (f == NULL) { + f = fopen (path, "r"); + if (f == NULL) + { - vdev_action_free(act); - rc = -errno; + vdev_action_free (act); + rc = -errno; - return rc; - } + return rc; + } - rc = vdev_action_load_file(config, path, act, f); + rc = vdev_action_load_file (config, path, act, f); - fclose(f); + fclose (f); - if (rc == -EINVAL) { + if (rc == -EINVAL) + { - vdev_action_free(act); - vdev_error("Invalid action '%s'\n", path); - } else if (rc == 0) { + vdev_action_free (act); + vdev_error ("Invalid action '%s'\n", path); + } + else if (rc == 0) + { - // store the name - act->name = vdev_strdup_or_null(path); - if (act->name == NULL) { + // store the name + act->name = vdev_strdup_or_null (path); + if (act->name == NULL) + { - // OOM - vdev_action_free(act); - rc = -ENOMEM; - } + // OOM + vdev_action_free (act); + rc = -ENOMEM; } + } - return rc; + return rc; } // free a C-style list of actions (including the list itself) // always succeeds -int vdev_action_free_all(struct vdev_action *act_list, size_t num_acts) +int +vdev_action_free_all (struct vdev_action *act_list, size_t num_acts) { - int rc = 0; + int rc = 0; - for (unsigned int i = 0; i < num_acts; i++) { + for (unsigned int i = 0; i < num_acts; i++) + { - rc = vdev_action_free(&act_list[i]); - if (rc != 0) { - return rc; - } + rc = vdev_action_free (&act_list[i]); + if (rc != 0) + { + return rc; } + } - free(act_list); + free (act_list); - return rc; + return rc; } // action loader @@ -549,69 +624,75 @@ int vdev_action_free_all(struct vdev_action *act_list, size_t num_acts) // return -errno on failure to stat(2) // return -EINVAL if the file is invalid // return -ENOMEM if OOM -int vdev_action_loader(char const *path, void *cls) +int +vdev_action_loader (char const *path, void *cls) { - int rc = 0; - struct vdev_action act; - struct stat sb; - struct vdev_action_loader_cls *loader_cls = - (struct vdev_action_loader_cls *)cls; + int rc = 0; + struct vdev_action act; + struct stat sb; + struct vdev_action_loader_cls *loader_cls = + (struct vdev_action_loader_cls *) cls; - struct sglib_vdev_action_vector *acts = loader_cls->acts; - struct vdev_config *config = loader_cls->config; + struct sglib_vdev_action_vector *acts = loader_cls->acts; + struct vdev_config *config = loader_cls->config; - // skip if not a regular file - rc = stat(path, &sb); - if (rc != 0) { + // skip if not a regular file + rc = stat (path, &sb); + if (rc != 0) + { - rc = -errno; - vdev_error("stat(%s) rc = %d\n", path, rc); - return rc; - } + rc = -errno; + vdev_error ("stat(%s) rc = %d\n", path, rc); + return rc; + } - if (!S_ISREG(sb.st_mode)) { + if (!S_ISREG (sb.st_mode)) + { - return 0; - } + return 0; + } - vdev_debug("Load Action %s\n", path); + vdev_debug ("Load Action %s\n", path); - memset(&act, 0, sizeof(struct vdev_action)); + memset (&act, 0, sizeof (struct vdev_action)); - rc = vdev_action_load(config, path, &act); - if (rc != 0) { + rc = vdev_action_load (config, path, &act); + if (rc != 0) + { - vdev_error("vdev_acl_load(%s) rc = %d\n", path, rc); - return rc; - } - // save this action - rc = sglib_vdev_action_vector_push_back(acts, act); - if (rc != 0) { + vdev_error ("vdev_acl_load(%s) rc = %d\n", path, rc); + return rc; + } + // save this action + rc = sglib_vdev_action_vector_push_back (acts, act); + if (rc != 0) + { - // OOM - vdev_action_free(&act); - return rc; - } + // OOM + vdev_action_free (&act); + return rc; + } - return 0; + return 0; } // free a vector of actions // always succeeds -static int vdev_action_vector_free(struct sglib_vdev_action_vector *acts) +static int +vdev_action_vector_free (struct sglib_vdev_action_vector *acts) { - for (unsigned long i = 0; i < sglib_vdev_action_vector_size(acts); i++) { + for (unsigned long i = 0; i < sglib_vdev_action_vector_size (acts); i++) + { - struct vdev_action *act = - sglib_vdev_action_vector_at_ref(acts, i); + struct vdev_action *act = sglib_vdev_action_vector_at_ref (acts, i); - vdev_action_free(act); - } + vdev_action_free (act); + } - sglib_vdev_action_vector_clear(acts); - return 0; + sglib_vdev_action_vector_clear (acts); + return 0; } // load all actions in a directory @@ -619,107 +700,117 @@ static int vdev_action_vector_free(struct sglib_vdev_action_vector *acts) // return -ENOMEM if OOM // return -EINVAL if at least one action file failed to load due to a sanity test failure // return -errno if at least one action file failed to load due to an I/O error -int vdev_action_load_all(struct vdev_config *config, - struct vdev_action **ret_acts, size_t * ret_num_acts) +int +vdev_action_load_all (struct vdev_config *config, + struct vdev_action **ret_acts, size_t * ret_num_acts) { - int rc = 0; - struct vdev_action_loader_cls loader_cls; - struct sglib_vdev_action_vector acts; + int rc = 0; + struct vdev_action_loader_cls loader_cls; + struct sglib_vdev_action_vector acts; - sglib_vdev_action_vector_init(&acts); + sglib_vdev_action_vector_init (&acts); - loader_cls.acts = &acts; - loader_cls.config = config; + loader_cls.acts = &acts; + loader_cls.config = config; - rc = vdev_load_all(config->acts_dir, vdev_action_loader, &loader_cls); + rc = vdev_load_all (config->acts_dir, vdev_action_loader, &loader_cls); - if (rc != 0) { + if (rc != 0) + { - vdev_action_vector_free(&acts); - sglib_vdev_action_vector_free(&acts); + vdev_action_vector_free (&acts); + sglib_vdev_action_vector_free (&acts); - return rc; - } else { + return rc; + } + else + { - if (sglib_vdev_action_vector_size(&acts) == 0) { + if (sglib_vdev_action_vector_size (&acts) == 0) + { - // nothing - *ret_acts = NULL; - *ret_num_acts = 0; - } else { + // nothing + *ret_acts = NULL; + *ret_num_acts = 0; + } + else + { - // extract values - unsigned long len_acts = 0; + // extract values + unsigned long len_acts = 0; - sglib_vdev_action_vector_yoink(&acts, ret_acts, - &len_acts); + sglib_vdev_action_vector_yoink (&acts, ret_acts, &len_acts); - *ret_num_acts = len_acts; - } + *ret_num_acts = len_acts; } + } - return 0; + return 0; } // carry out a command, synchronously, using an environment given by vreq. // stdout will be captured to *output // return the exit status on success (non-negative) // return negative on error -int vdev_action_run_sync(struct vdev_device_request *vreq, char const *command, - vdev_params * helper_vars, bool use_shell, - char **output, size_t max_output) +int +vdev_action_run_sync (struct vdev_device_request *vreq, char const *command, + vdev_params * helper_vars, bool use_shell, + char **output, size_t max_output) { - int rc = 0; - int exit_status = 0; - char **req_env = NULL; - size_t num_env = 0; + int rc = 0; + int exit_status = 0; + char **req_env = NULL; + size_t num_env = 0; - // convert to environment variables - rc = vdev_device_request_to_env(vreq, helper_vars, &req_env, &num_env, - 0); - if (rc != 0) { + // convert to environment variables + rc = vdev_device_request_to_env (vreq, helper_vars, &req_env, &num_env, 0); + if (rc != 0) + { - vdev_error("vdev_device_request_to_env(%s) rc = %d\n", - vreq->path, rc); - return rc; - } + vdev_error ("vdev_device_request_to_env(%s) rc = %d\n", vreq->path, rc); + return rc; + } - vdev_debug("run command: '%s'\n", command); + vdev_debug ("run command: '%s'\n", command); - for (unsigned int i = 0; i < num_env; i++) { - vdev_debug("command env: '%s'\n", req_env[i]); - } + for (unsigned int i = 0; i < num_env; i++) + { + vdev_debug ("command env: '%s'\n", req_env[i]); + } - rc = vdev_subprocess(command, req_env, output, max_output, - vreq->state->error_fd, &exit_status, use_shell); + rc = vdev_subprocess (command, req_env, output, max_output, + vreq->state->error_fd, &exit_status, use_shell); - vdev_debug("exit status %d\n", exit_status); + vdev_debug ("exit status %d\n", exit_status); - if (output != NULL && *output != NULL) { + if (output != NULL && *output != NULL) + { - vdev_debug("command output: '%s'\n", *output); - } + vdev_debug ("command output: '%s'\n", *output); + } - VDEV_FREE_LIST(req_env); + VDEV_FREE_LIST (req_env); - if (rc != 0) { + if (rc != 0) + { - vdev_error("vdev_subprocess('%s', use_shell=%d) rc = %d\n", - command, use_shell, rc); + vdev_error ("vdev_subprocess('%s', use_shell=%d) rc = %d\n", + command, use_shell, rc); - return rc; - } + return rc; + } - if (exit_status != 0) { + if (exit_status != 0) + { - vdev_error - ("vdev_subprocess('%s', use_shell=%d) exit status = %d\n", - command, use_shell, exit_status); - } + vdev_error + ("vdev_subprocess('%s', use_shell=%d) exit status = %d\n", + command, use_shell, exit_status); + } - return exit_status; + return exit_status; } // carry out an action, asynchronously. @@ -727,141 +818,166 @@ int vdev_action_run_sync(struct vdev_device_request *vreq, char const *command, // return 0 if we were able to fork // return -errno on failure to fork // TODO: configurable interpreter (defaults to /bin/dash) -int vdev_action_run_async(struct vdev_device_request *req, char const *command, - vdev_params * helper_vars, bool use_shell) +int +vdev_action_run_async (struct vdev_device_request *req, char const *command, + vdev_params * helper_vars, bool use_shell) { - int rc = 0; - pid_t pid = 0; - pid_t sid = 0; - int max_fd = 0; + int rc = 0; + pid_t pid = 0; + pid_t sid = 0; + int max_fd = 0; - // generate the environment - char **env = NULL; - size_t num_env = 0; + // generate the environment + char **env = NULL; + size_t num_env = 0; - rc = vdev_device_request_to_env(req, helper_vars, &env, &num_env, 0); - if (rc != 0) { + rc = vdev_device_request_to_env (req, helper_vars, &env, &num_env, 0); + if (rc != 0) + { - // NOTE: must be async-safe! - vdev_error("vdev_device_request_to_env rc = %d\n", rc); - return rc; - } + // NOTE: must be async-safe! + vdev_error ("vdev_device_request_to_env rc = %d\n", rc); + return rc; + } - vdev_debug("run command async: '%s'\n", command); + vdev_debug ("run command async: '%s'\n", command); - for (unsigned int i = 0; i < num_env; i++) { - vdev_debug("command async env: '%s'\n", env[i]); - } + for (unsigned int i = 0; i < num_env; i++) + { + vdev_debug ("command async env: '%s'\n", env[i]); + } - pid = fork(); + pid = fork (); - if (pid == 0) { + if (pid == 0) + { - // child - // detach from parent - sid = setsid(); - if (sid < 0) { + // child + // detach from parent + sid = setsid (); + if (sid < 0) + { - rc = -errno; + rc = -errno; - // NOTE: must be async-safe! - vdev_error_async_safe("setsid failed\n"); - exit(1); - } + // NOTE: must be async-safe! + vdev_error_async_safe ("setsid failed\n"); + exit (1); + } - pid = fork(); + pid = fork (); - if (pid == 0) { + if (pid == 0) + { - // fully detached - max_fd = sysconf(_SC_OPEN_MAX); - if (max_fd < 0) { + // fully detached + max_fd = sysconf (_SC_OPEN_MAX); + if (max_fd < 0) + { - // should be big enough... - max_fd = 1024; - } - // close everything except stderr, which should be directed to our log - for (int i = 0; i < max_fd; i++) { - if (i != STDERR_FILENO) { - close(i); - } - } + // should be big enough... + max_fd = 1024; + } + // close everything except stderr, which should be directed to our log + for (int i = 0; i < max_fd; i++) + { + if (i != STDERR_FILENO) + { + close (i); + } + } - clearenv(); + clearenv (); - // run the command - if (use_shell) { - execle("/bin/dash", "dash", "-c", command, - (char *)0, env); - } else { - execle(command, command, (char *)0, env); - } + // run the command + if (use_shell) + { + execle ("/bin/dash", "dash", "-c", command, (char *) 0, env); + } + else + { + execle (command, command, (char *) 0, env); + } - // keep gcc happy - exit(0); - } else if (pid > 0) { + // keep gcc happy + exit (0); + } + else if (pid > 0) + { - exit(0); - } else { + exit (0); + } + else + { - rc = -errno; - vdev_error_async_safe("fork() failed\n"); - exit(-rc); - } - } else if (pid > 0) { + rc = -errno; + vdev_error_async_safe ("fork() failed\n"); + exit (-rc); + } + } + else if (pid > 0) + { - rc = 0; + rc = 0; - VDEV_FREE_LIST(env); + VDEV_FREE_LIST (env); - // parent; succeeded - // wait for intermediate process - pid_t child_pid = waitpid(pid, &rc, 0); - if (child_pid < 0) { + // parent; succeeded + // wait for intermediate process + pid_t child_pid = waitpid (pid, &rc, 0); + if (child_pid < 0) + { - rc = -errno; - vdev_error("waitpid(%d) rc = %d\n", pid, rc); - return rc; - } else if (WIFEXITED(rc) && WEXITSTATUS(rc) != 0) { + rc = -errno; + vdev_error ("waitpid(%d) rc = %d\n", pid, rc); + return rc; + } + else if (WIFEXITED (rc) && WEXITSTATUS (rc) != 0) + { - rc = -WEXITSTATUS(rc); - vdev_error("fork() rc = %d\n", rc); - } + rc = -WEXITSTATUS (rc); + vdev_error ("fork() rc = %d\n", rc); + } - return rc; - } else { + return rc; + } + else + { - // error - rc = -errno; + // error + rc = -errno; - VDEV_FREE_LIST(env); + VDEV_FREE_LIST (env); - vdev_error("fork() rc = %d\n", rc); + vdev_error ("fork() rc = %d\n", rc); - return rc; - } + return rc; + } } // clean up a daemonlet's state in an action // always succeeds -static int vdev_action_daemonlet_clean(struct vdev_action *act) +static int +vdev_action_daemonlet_clean (struct vdev_action *act) { - // dead - act->daemonlet_pid = -1; + // dead + act->daemonlet_pid = -1; - if (act->daemonlet_stdin >= 0) { - close(act->daemonlet_stdin); - act->daemonlet_stdin = -1; - } + if (act->daemonlet_stdin >= 0) + { + close (act->daemonlet_stdin); + act->daemonlet_stdin = -1; + } - if (act->daemonlet_stdout >= 0) { - close(act->daemonlet_stdout); - act->daemonlet_stdout = -1; - } + if (act->daemonlet_stdout >= 0) + { + close (act->daemonlet_stdout); + act->daemonlet_stdout = -1; + } - return 0; + return 0; } // start up a daemonlet, using the daemonlet helper program at $VDEV_HELPERS/daemonlet. @@ -875,324 +991,363 @@ static int vdev_action_daemonlet_clean(struct vdev_action *act) // return -errno from fork(2) if we could not fork // return -ECHILD if the daemonlet died before it could signal readiness // NOTE: /dev/null *must* exist already--this should be taken care of by the pre-seed script. -static int vdev_action_daemonlet_start(struct vdev_state *state, - struct vdev_action *act) +static int +vdev_action_daemonlet_start (struct vdev_state *state, + struct vdev_action *act) { - int rc = 0; - pid_t pid = 0; - int daemonlet_pipe_stdin[2]; - int daemonlet_pipe_stdout[2]; - char daemonlet_runner_path[PATH_MAX + 1]; - char vdevd_global_metadata[PATH_MAX + 1]; - char null_path[PATH_MAX + 1]; - long max_open = sysconf(_SC_OPEN_MAX); - struct stat sb; - struct vdev_config *config = state->config; + int rc = 0; + pid_t pid = 0; + int daemonlet_pipe_stdin[2]; + int daemonlet_pipe_stdout[2]; + char daemonlet_runner_path[PATH_MAX + 1]; + char vdevd_global_metadata[PATH_MAX + 1]; + char null_path[PATH_MAX + 1]; + long max_open = sysconf (_SC_OPEN_MAX); + struct stat sb; + struct vdev_config *config = state->config; + + char *daemonlet_argv[] = { + "vdevd-daemonlet", + act->command, + NULL + }; + + if (max_open <= 0) + { + max_open = 1024; // a good guess + } + + if (act->daemonlet_pid > 0) + { + return 0; + } + + memset (daemonlet_runner_path, 0, PATH_MAX + 1); + memset (vdevd_global_metadata, 0, PATH_MAX + 1); + + snprintf (daemonlet_runner_path, PATH_MAX, "%s/daemonlet", + config->helpers_dir); + snprintf (vdevd_global_metadata, PATH_MAX, "%s/" VDEV_METADATA_PREFIX, + config->mountpoint); + + // the daemonlet runner must exist + rc = stat (daemonlet_runner_path, &sb); + if (rc != 0) + { + + vdev_error ("stat('%s') rc = %d\n", daemonlet_runner_path, rc); + return rc; + } + // the daemonlet runner must be executable + if (!S_ISREG (sb.st_mode) + || !(((S_IXUSR & sb.st_mode) && sb.st_uid == geteuid ()) + || ((S_IXGRP & sb.st_mode) && sb.st_gid == getegid ()) + || (S_IXOTH & sb.st_mode))) + { + + vdev_error + ("%s is not a regular file, or is not executable for vdevd\n", + daemonlet_runner_path); + return -EPERM; + } + + rc = pipe (daemonlet_pipe_stdin); + if (rc < 0) + { + + rc = -errno; + vdev_error ("pipe rc = %d\n", rc); + return rc; + } + + rc = pipe (daemonlet_pipe_stdout); + if (rc < 0) + { + + rc = -errno; + vdev_error ("pipe rc = %d\n", rc); + + close (daemonlet_pipe_stdin[0]); + close (daemonlet_pipe_stdin[1]); + return rc; + } + + pid = fork (); + if (pid == 0) + { + + // child + close (daemonlet_pipe_stdin[1]); + close (daemonlet_pipe_stdout[0]); + + // redirect + rc = dup2 (daemonlet_pipe_stdin[0], STDIN_FILENO); + if (rc < 0) + { + + vdev_error_async_safe ("dup2 stdin failed\n"); + exit (1); + } + + rc = dup2 (daemonlet_pipe_stdout[1], STDOUT_FILENO); + if (rc < 0) + { + + vdev_error_async_safe ("dup2 stdout to vdevd failed\n"); + _exit (1); + } + + rc = dup2 (state->error_fd, STDERR_FILENO); + if (rc < 0) + { + + vdev_error_async_safe ("dup2 stderr to null failed\n"); + _exit (1); + } + // close everything else + // the daemonlet should capture stderr itself + for (int i = 3; i < max_open; i++) + { + + close (i); + } + + // set basic environment variables + clearenv (); + setenv ("VDEV_GLOBAL_METADATA", vdevd_global_metadata, 1); + setenv ("VDEV_MOUNTPOINT", config->mountpoint, 1); + setenv ("VDEV_HELPERS", config->helpers_dir, 1); + setenv ("VDEV_LOGFILE", config->logfile_path, 1); + setenv ("VDEV_CONFIG_FILE", config->config_path, 1); + setenv ("VDEV_INSTANCE", config->instance_str, 1); + + // start the daemonlet + execv (daemonlet_runner_path, daemonlet_argv); + + // keep gcc happy + _exit (0); + } + else if (pid > 0) + { - char *daemonlet_argv[] = { - "vdevd-daemonlet", - act->command, - NULL - }; + // parent vdevd + close (daemonlet_pipe_stdin[0]); + close (daemonlet_pipe_stdout[1]); - if (max_open <= 0) { - max_open = 1024; // a good guess - } - - if (act->daemonlet_pid > 0) { - return 0; - } - - memset(daemonlet_runner_path, 0, PATH_MAX + 1); - memset(vdevd_global_metadata, 0, PATH_MAX + 1); - - snprintf(daemonlet_runner_path, PATH_MAX, "%s/daemonlet", - config->helpers_dir); - snprintf(vdevd_global_metadata, PATH_MAX, "%s/" VDEV_METADATA_PREFIX, - config->mountpoint); - - // the daemonlet runner must exist - rc = stat(daemonlet_runner_path, &sb); - if (rc != 0) { - - vdev_error("stat('%s') rc = %d\n", daemonlet_runner_path, rc); - return rc; - } - // the daemonlet runner must be executable - if (!S_ISREG(sb.st_mode) - || !(((S_IXUSR & sb.st_mode) && sb.st_uid == geteuid()) - || ((S_IXGRP & sb.st_mode) && sb.st_gid == getegid()) - || (S_IXOTH & sb.st_mode))) { - - vdev_error - ("%s is not a regular file, or is not executable for vdevd\n", - daemonlet_runner_path); - return -EPERM; - } - - rc = pipe(daemonlet_pipe_stdin); - if (rc < 0) { - - rc = -errno; - vdev_error("pipe rc = %d\n", rc); - return rc; - } + // wait for child to indicate readiness, if running synchronously + if (!act->async) + { - rc = pipe(daemonlet_pipe_stdout); - if (rc < 0) { + while (1) + { - rc = -errno; - vdev_error("pipe rc = %d\n", rc); + char tmp = 0; + rc = vdev_read_uninterrupted + (daemonlet_pipe_stdout[0], &tmp, 1); - close(daemonlet_pipe_stdin[0]); - close(daemonlet_pipe_stdin[1]); - return rc; - } - - pid = fork(); - if (pid == 0) { + if (rc <= 0) + { - // child - close(daemonlet_pipe_stdin[1]); - close(daemonlet_pipe_stdout[0]); + // some fatal error, or process has closed stdout + // not much we can safely do at this point (don't want to risk SIGKILL'ing) + close (daemonlet_pipe_stdin[1]); + close (daemonlet_pipe_stdout[0]); - // redirect - rc = dup2(daemonlet_pipe_stdin[0], STDIN_FILENO); - if (rc < 0) { - - vdev_error_async_safe("dup2 stdin failed\n"); - exit(1); - } - - rc = dup2(daemonlet_pipe_stdout[1], STDOUT_FILENO); - if (rc < 0) { - - vdev_error_async_safe("dup2 stdout to vdevd failed\n"); - _exit(1); - } + if (rc == 0) + { - rc = dup2(state->error_fd, STDERR_FILENO); - if (rc < 0) { + // process has closed stdout + vdev_error + ("vdev_read_uninterrupted(%d PID=%d action='%s') rc = %d\n", + daemonlet_pipe_stdout[0], pid, act->name, rc); + rc = -ECHILD; + } - vdev_error_async_safe("dup2 stderr to null failed\n"); - _exit(1); + return rc; } - // close everything else - // the daemonlet should capture stderr itself - for (int i = 3; i < max_open; i++) { - - close(i); - } - - // set basic environment variables - clearenv(); - setenv("VDEV_GLOBAL_METADATA", vdevd_global_metadata, 1); - setenv("VDEV_MOUNTPOINT", config->mountpoint, 1); - setenv("VDEV_HELPERS", config->helpers_dir, 1); - setenv("VDEV_LOGFILE", config->logfile_path, 1); - setenv("VDEV_CONFIG_FILE", config->config_path, 1); - setenv("VDEV_INSTANCE", config->instance_str, 1); - - // start the daemonlet - execv(daemonlet_runner_path, daemonlet_argv); - - // keep gcc happy - _exit(0); - } else if (pid > 0) { - - // parent vdevd - close(daemonlet_pipe_stdin[0]); - close(daemonlet_pipe_stdout[1]); + else + { - // wait for child to indicate readiness, if running synchronously - if (!act->async) { - - while (1) { - - char tmp = 0; - rc = vdev_read_uninterrupted - (daemonlet_pipe_stdout[0], &tmp, 1); - - if (rc <= 0) { - - // some fatal error, or process has closed stdout - // not much we can safely do at this point (don't want to risk SIGKILL'ing) - close(daemonlet_pipe_stdin[1]); - close(daemonlet_pipe_stdout[0]); - - if (rc == 0) { - - // process has closed stdout - vdev_error - ("vdev_read_uninterrupted(%d PID=%d action='%s') rc = %d\n", - daemonlet_pipe_stdout[0], - pid, act->name, rc); - rc = -ECHILD; - } - - return rc; - } else { - - // got back readiness hint - break; - } - } + // got back readiness hint + break; } - // record runtime state - act->is_daemonlet = true; - act->daemonlet_pid = pid; - act->daemonlet_stdin = daemonlet_pipe_stdin[1]; - act->daemonlet_stdout = daemonlet_pipe_stdout[0]; - - // daemonlet started! - return 0; - } else { - - // fork() error - rc = -errno; - vdev_error("fork() rc = %d\n", rc); - - close(daemonlet_pipe_stdin[0]); - close(daemonlet_pipe_stdin[1]); - close(daemonlet_pipe_stdout[0]); - close(daemonlet_pipe_stdout[1]); - - return rc; - } + } + } + // record runtime state + act->is_daemonlet = true; + act->daemonlet_pid = pid; + act->daemonlet_stdin = daemonlet_pipe_stdin[1]; + act->daemonlet_stdout = daemonlet_pipe_stdout[0]; + + // daemonlet started! + return 0; + } + else + { + + // fork() error + rc = -errno; + vdev_error ("fork() rc = %d\n", rc); + + close (daemonlet_pipe_stdin[0]); + close (daemonlet_pipe_stdin[1]); + close (daemonlet_pipe_stdout[0]); + close (daemonlet_pipe_stdout[1]); + + return rc; + } } // stop a daemonlet and join with it // first, ask it by writing "exit" to its stdin pipe. // wait 30 seconds before SIGTERM'ing the daemonlet. // return 0 on success, even if the daemonlet is already dead -static int vdev_action_daemonlet_stop(struct vdev_action *act) +static int +vdev_action_daemonlet_stop (struct vdev_action *act) { - int rc = 0; - pid_t child_pid = 0; - struct timespec timeout; - struct timespec stop_deadline; - sigset_t sigchld_sigset; - siginfo_t sigchld_info; - - timeout.tv_sec = 30; - timeout.tv_nsec = 0; - - if (act->daemonlet_pid <= 0 || act->daemonlet_stdin < 0 - || act->daemonlet_stdout < 0) { - // not running - return 0; - } - // confirm that it is still running by trying to join with it - child_pid = waitpid(act->daemonlet_pid, &rc, WNOHANG); - if (child_pid == act->daemonlet_pid || child_pid < 0) { - - // joined, or not running - vdev_debug("Daemonlet %d (%s) dead\n", act->daemonlet_pid, - act->name); - vdev_action_daemonlet_clean(act); - return 0; - } - // ask it to die: close stdin - rc = close(act->daemonlet_stdin); - - if (rc < 0) { - - vdev_error("close(%d PID=%d name=%s) rc = %d\n", - act->daemonlet_stdin, act->daemonlet_pid, act->name, - rc); - act->daemonlet_stdin = -1; - - // no choice but to kill this one - kill(act->daemonlet_pid, SIGTERM); - vdev_action_daemonlet_clean(act); - - // join with it... - rc = 0; - } else { - - // tell daemonlet to die - rc = kill(act->daemonlet_pid, SIGINT); - if (rc < 0) { + int rc = 0; + pid_t child_pid = 0; + struct timespec timeout; + struct timespec stop_deadline; + sigset_t sigchld_sigset; + siginfo_t sigchld_info; + + timeout.tv_sec = 30; + timeout.tv_nsec = 0; + + if (act->daemonlet_pid <= 0 || act->daemonlet_stdin < 0 + || act->daemonlet_stdout < 0) + { + // not running + return 0; + } + // confirm that it is still running by trying to join with it + child_pid = waitpid (act->daemonlet_pid, &rc, WNOHANG); + if (child_pid == act->daemonlet_pid || child_pid < 0) + { + + // joined, or not running + vdev_debug ("Daemonlet %d (%s) dead\n", act->daemonlet_pid, act->name); + vdev_action_daemonlet_clean (act); + return 0; + } + // ask it to die: close stdin + rc = close (act->daemonlet_stdin); + + if (rc < 0) + { + + vdev_error ("close(%d PID=%d name=%s) rc = %d\n", + act->daemonlet_stdin, act->daemonlet_pid, act->name, rc); + act->daemonlet_stdin = -1; + + // no choice but to kill this one + kill (act->daemonlet_pid, SIGTERM); + vdev_action_daemonlet_clean (act); + + // join with it... + rc = 0; + } + else + { + + // tell daemonlet to die + rc = kill (act->daemonlet_pid, SIGINT); + if (rc < 0) + { + + vdev_error ("kill(PID=%d name=%s) rc = %d\n", + act->daemonlet_pid, act->name, rc); + } + // will wait for the child to die + act->daemonlet_stdin = -1; + } + + // join with it. + while (1) + { + + // attempt to join + child_pid = waitpid (act->daemonlet_pid, &rc, 0); + + if (child_pid < 0) + { + + rc = -errno; + if (rc == -ECHILD) + { + + // already dead + rc = 0; + vdev_debug ("Daemonlet %d (%s) dead\n", + act->daemonlet_pid, act->name); + vdev_action_daemonlet_clean (act); + break; + } + else if (rc == -EINTR) + { + + // unhandled signal *or* SIGCHLD + child_pid = waitpid (act->daemonlet_pid, &rc, WNOHANG); + if (child_pid > 0) + { + + // child died + break; + } + else + { - vdev_error("kill(PID=%d name=%s) rc = %d\n", - act->daemonlet_pid, act->name, rc); + // try waiting again + continue; } - // will wait for the child to die - act->daemonlet_stdin = -1; + } } + else if (child_pid > 0) + { - // join with it. - while (1) { - - // attempt to join - child_pid = waitpid(act->daemonlet_pid, &rc, 0); - - if (child_pid < 0) { - - rc = -errno; - if (rc == -ECHILD) { - - // already dead - rc = 0; - vdev_debug("Daemonlet %d (%s) dead\n", - act->daemonlet_pid, act->name); - vdev_action_daemonlet_clean(act); - break; - } else if (rc == -EINTR) { - - // unhandled signal *or* SIGCHLD - child_pid = - waitpid(act->daemonlet_pid, &rc, WNOHANG); - if (child_pid > 0) { - - // child died - break; - } else { - - // try waiting again - continue; - } - } - } else if (child_pid > 0) { - - // joined! - break; - } + // joined! + break; } + } - // clean this child out (even if we had an error with waitpid) - vdev_debug("Daemonlet %d (%s) dead\n", act->daemonlet_pid, act->name); - vdev_action_daemonlet_clean(act); + // clean this child out (even if we had an error with waitpid) + vdev_debug ("Daemonlet %d (%s) dead\n", act->daemonlet_pid, act->name); + vdev_action_daemonlet_clean (act); - return rc; + return rc; } // stop all daemonlets // always succeeds; mask all stop errors (i.e. only call this on shutdown) -int vdev_action_daemonlet_stop_all(struct vdev_action *actions, - size_t num_actions) +int +vdev_action_daemonlet_stop_all (struct vdev_action *actions, + size_t num_actions) { - int rc = 0; + int rc = 0; - for (unsigned int i = 0; i < num_actions; i++) { + for (unsigned int i = 0; i < num_actions; i++) + { - if (!actions[i].is_daemonlet) { - continue; - } + if (!actions[i].is_daemonlet) + { + continue; + } - rc = vdev_action_daemonlet_stop(&actions[i]); - if (rc < 0) { + rc = vdev_action_daemonlet_stop (&actions[i]); + if (rc < 0) + { - vdev_error - ("vdev_action_daemonlet_stop('%s' PID=%d) rc = %d\n", - actions[i].name, actions[i].daemonlet_pid, rc); - } + vdev_error + ("vdev_action_daemonlet_stop('%s' PID=%d) rc = %d\n", + actions[i].name, actions[i].daemonlet_pid, rc); } + } - return 0; + return 0; } // read a string-ified int64_t from a file descriptor, followed by a newline. @@ -1200,50 +1355,58 @@ int vdev_action_daemonlet_stop_all(struct vdev_action *actions, // return 0 on success, and set *ret // return -errno on I/O error (such as -EPIPE) // return -EAGAIN if we got EOF -static int vdev_action_daemonlet_read_int64(int fd, int64_t * ret) +static int +vdev_action_daemonlet_read_int64 (int fd, int64_t * ret) { - int64_t value = 0; + int64_t value = 0; - int cnt = 0; - int c = 0; - int rc = 0; - int s = 1; + int cnt = 0; + int c = 0; + int rc = 0; + int s = 1; - while (1) { + while (1) + { - // next character - rc = vdev_read_uninterrupted(fd, (char *)&c, 1); - if (rc < 0) { + // next character + rc = vdev_read_uninterrupted (fd, (char *) &c, 1); + if (rc < 0) + { - return rc; - } - if (rc == 0) { + return rc; + } + if (rc == 0) + { - return -EAGAIN; - } + return -EAGAIN; + } - if (c == '\n') { - break; - } + if (c == '\n') + { + break; + } - if (cnt == 0 && c == '-') { - s = -1; - } else if (c < '0' || c > '9') { + if (cnt == 0 && c == '-') + { + s = -1; + } + else if (c < '0' || c > '9') + { - // invalid - rc = -EINVAL; - break; - } + // invalid + rc = -EINVAL; + break; + } - value *= 10; - value += (c - '0'); + value *= 10; + value += (c - '0'); - cnt++; - } + cnt++; + } - *ret = value * s; - return 0; + *ret = value * s; + return 0; } // issue a command to a daemonlet, and get back its return code. @@ -1253,107 +1416,122 @@ static int vdev_action_daemonlet_read_int64(int fd, int64_t * ret) // return -ENOMEM on OOM // return -EAGAIN if the daemonlet needs to be restarted and the request retried. // return -EPERM on permanent daemonlet failure -static int vdev_action_daemonlet_send_command(struct vdev_device_request *vreq, - struct vdev_action *act, - int64_t * daemonlet_rc) +static int +vdev_action_daemonlet_send_command (struct vdev_device_request *vreq, + struct vdev_action *act, + int64_t * daemonlet_rc) { - int rc = 0; - char **req_env = NULL; - size_t num_env = 0; - char env_buf[PATH_MAX + 1]; + int rc = 0; + char **req_env = NULL; + size_t num_env = 0; + char env_buf[PATH_MAX + 1]; - memset(env_buf, 0, PATH_MAX + 1); + memset (env_buf, 0, PATH_MAX + 1); + + // generate the environment... + rc = vdev_device_request_to_env (vreq, act->helper_vars, &req_env, + &num_env, 1); + if (rc != 0) + { - // generate the environment... - rc = vdev_device_request_to_env(vreq, act->helper_vars, &req_env, - &num_env, 1); - if (rc != 0) { + vdev_error ("vdev_device_request_to_env(%s) rc = %d\n", vreq->path, rc); + return rc; + } - vdev_error("vdev_device_request_to_env(%s) rc = %d\n", - vreq->path, rc); - return rc; - } - - vdev_debug("run daemonlet (async=%d): '%s'\n", act->async, act->name); + vdev_debug ("run daemonlet (async=%d): '%s'\n", act->async, act->name); - for (unsigned int i = 0; i < num_env; i++) { - vdev_debug("daemonlet env: '%s'\n", req_env[i]); - } + for (unsigned int i = 0; i < num_env; i++) + { + vdev_debug ("daemonlet env: '%s'\n", req_env[i]); + } - // feed environment variables - for (unsigned int i = 0; i < num_env; i++) { + // feed environment variables + for (unsigned int i = 0; i < num_env; i++) + { - snprintf(env_buf, PATH_MAX, "%s\n", req_env[i]); + snprintf (env_buf, PATH_MAX, "%s\n", req_env[i]); - rc = vdev_write_uninterrupted(act->daemonlet_stdin, env_buf, - strlen(env_buf)); - if (rc < 0) { + rc = vdev_write_uninterrupted (act->daemonlet_stdin, env_buf, + strlen (env_buf)); + if (rc < 0) + { - // failed to write! - vdev_error - ("vdev_write_uninterrupted(%d) to daemonlet '%s' rc = %d\n", - act->daemonlet_stdin, act->name, rc); - break; - } + // failed to write! + vdev_error + ("vdev_write_uninterrupted(%d) to daemonlet '%s' rc = %d\n", + act->daemonlet_stdin, act->name, rc); + break; } + } - if (rc > 0) { + if (rc > 0) + { - // feed end-of-environment flag - rc = vdev_write_uninterrupted(act->daemonlet_stdin, "done\n", - strlen("done\n")); - if (rc < 0) { + // feed end-of-environment flag + rc = vdev_write_uninterrupted (act->daemonlet_stdin, "done\n", + strlen ("done\n")); + if (rc < 0) + { - vdev_error - ("vdev_write_uninterrupted(%d) to daemonlet '%s' rc = %d\n", - act->daemonlet_stdin, act->name, rc); - } + vdev_error + ("vdev_write_uninterrupted(%d) to daemonlet '%s' rc = %d\n", + act->daemonlet_stdin, act->name, rc); } + } - VDEV_FREE_LIST(req_env); + VDEV_FREE_LIST (req_env); - if (rc < 0) { + if (rc < 0) + { - // -EPIPE means the daemonlet is dead, and the caller should restart it - if (rc == -EPIPE) { - return -EAGAIN; - } else { - return -EPERM; - } + // -EPIPE means the daemonlet is dead, and the caller should restart it + if (rc == -EPIPE) + { + return -EAGAIN; } - // if we're running asynchronously, then we don't care about getting back the reply (stdout is routed to /dev/null anyway) - if (act->async) { - *daemonlet_rc = 0; - return 0; + else + { + return -EPERM; } - // wait for a status code reply - rc = vdev_action_daemonlet_read_int64(act->daemonlet_stdout, - daemonlet_rc); - if (rc < 0) { + } + // if we're running asynchronously, then we don't care about getting back the reply (stdout is routed to /dev/null anyway) + if (act->async) + { + *daemonlet_rc = 0; + return 0; + } + // wait for a status code reply + rc = vdev_action_daemonlet_read_int64 (act->daemonlet_stdout, daemonlet_rc); + if (rc < 0) + { - vdev_error("vdev_action_daemonlet_read_int64('%s') rc = %d\n", - act->name, rc); + vdev_error ("vdev_action_daemonlet_read_int64('%s') rc = %d\n", + act->name, rc); - // -EPIPE means the daemonlet is dead, and the caller should restart it - if (rc == -EPIPE) { - return -EAGAIN; - } else { - return -EPERM; - } + // -EPIPE means the daemonlet is dead, and the caller should restart it + if (rc == -EPIPE) + { + return -EAGAIN; } - - if (*daemonlet_rc < 0 || *daemonlet_rc > 255) { - - // invalid daemonlet return code - // caller should consider restarting the daemonlet and trying again - vdev_error - ("vdev_daemonlet_read_int64('%s', PID=%d) exit status %d\n", - act->name, act->daemonlet_pid, (int)*daemonlet_rc); - return -EAGAIN; + else + { + return -EPERM; } + } - return 0; + if (*daemonlet_rc < 0 || *daemonlet_rc > 255) + { + + // invalid daemonlet return code + // caller should consider restarting the daemonlet and trying again + vdev_error + ("vdev_daemonlet_read_int64('%s', PID=%d) exit status %d\n", + act->name, act->daemonlet_pid, (int) *daemonlet_rc); + return -EAGAIN; + } + + return 0; } // carry out a command by sending it to a running daemonlet. @@ -1366,205 +1544,241 @@ static int vdev_action_daemonlet_send_command(struct vdev_device_request *vreq, // return a positive exit code if the daemonlet failed to process the device request // NOTE: if this method fails to communicate with the daemonlet, it will try to "reset" the daemonlet by stopping it, and allowing a subsequent call to start it. // NOTE: not reload-safe; call while the reload lock is held -int vdev_action_run_daemonlet(struct vdev_device_request *vreq, - struct vdev_action *act) +int +vdev_action_run_daemonlet (struct vdev_device_request *vreq, + struct vdev_action *act) { - int rc = 0; - int64_t daemonlet_rc = 0; - int num_attempts = 0; + int rc = 0; + int64_t daemonlet_rc = 0; + int num_attempts = 0; + + if (!act->is_daemonlet) + { + return -EINVAL; + } + // do we need to start it? + if (act->daemonlet_pid <= 0) + { + + rc = vdev_action_daemonlet_start (vreq->state, act); + if (rc < 0) + { + + vdev_error + ("vdev_action_daemonlet_start('%s') rc = %d\n", act->name, rc); + return -EPERM; + } + } + // try twice, in case we need to stop and start it. + while (num_attempts < 2) + { + + rc = vdev_action_daemonlet_send_command (vreq, act, &daemonlet_rc); + if (rc != 0) + { + + vdev_error + ("vdev_action_daemonlet_send_command('%s') rc = %d\n", + act->name, rc); + + if (rc == -EAGAIN) + { + + // try restarting and re-dispatching the command + rc = vdev_action_daemonlet_stop (act); + if (rc < 0) + { + + vdev_error + ("vdev_action_daemonlet_stop('%s', PID=%d) rc = %d\n", + act->name, act->daemonlet_pid, rc); + rc = -EPERM; + break; + } + else + { + + rc = vdev_action_daemonlet_start (vreq->state, act); + if (rc < 0) + { + + vdev_error + ("vdev_action_daemonlet_start('%s') rc = %d\n", + act->name, rc); + rc = -EPERM; + break; + } + else + { + + // try again + num_attempts++; + continue; + } + } + } + else + { - if (!act->is_daemonlet) { - return -EINVAL; + // permanent failure + rc = -EPERM; + break; + } } - // do we need to start it? - if (act->daemonlet_pid <= 0) { - - rc = vdev_action_daemonlet_start(vreq->state, act); - if (rc < 0) { + else + { - vdev_error - ("vdev_action_daemonlet_start('%s') rc = %d\n", - act->name, rc); - return -EPERM; - } - } - // try twice, in case we need to stop and start it. - while (num_attempts < 2) { - - rc = vdev_action_daemonlet_send_command(vreq, act, - &daemonlet_rc); - if (rc != 0) { - - vdev_error - ("vdev_action_daemonlet_send_command('%s') rc = %d\n", - act->name, rc); - - if (rc == -EAGAIN) { - - // try restarting and re-dispatching the command - rc = vdev_action_daemonlet_stop(act); - if (rc < 0) { - - vdev_error - ("vdev_action_daemonlet_stop('%s', PID=%d) rc = %d\n", - act->name, act->daemonlet_pid, rc); - rc = -EPERM; - break; - } else { - - rc = vdev_action_daemonlet_start - (vreq->state, act); - if (rc < 0) { - - vdev_error - ("vdev_action_daemonlet_start('%s') rc = %d\n", - act->name, rc); - rc = -EPERM; - break; - } else { - - // try again - num_attempts++; - continue; - } - } - } else { - - // permanent failure - rc = -EPERM; - break; - } - } else { - - // successfully dispatched the request, and (if not async) received an exit status via daemonlet_rc - break; - } + // successfully dispatched the request, and (if not async) received an exit status via daemonlet_rc + break; } + } - if (rc == 0) { + if (rc == 0) + { - vdev_debug("daemonlet '%s' returned %d\n", act->name, - (int)daemonlet_rc); - return (int)daemonlet_rc; - } else { + vdev_debug ("daemonlet '%s' returned %d\n", act->name, + (int) daemonlet_rc); + return (int) daemonlet_rc; + } + else + { - return rc; - } + return rc; + } } // match device request against action // return 1 if match // return 0 if not match -int vdev_action_match(struct vdev_device_request *vreq, struct vdev_action *act) +int +vdev_action_match (struct vdev_device_request *vreq, struct vdev_action *act) { - int rc = 0; + int rc = 0; - // action match? - if (act->trigger != vreq->type && act->trigger != VDEV_DEVICE_ANY) { - return 0; - } - // path match? - if (act->path != NULL) { - - rc = vdev_match_regex(vreq->path, &act->path_regex); - if (rc == 0) { + // action match? + if (act->trigger != vreq->type && act->trigger != VDEV_DEVICE_ANY) + { + return 0; + } + // path match? + if (act->path != NULL) + { - // no match - return 0; - } - if (rc < 0) { + rc = vdev_match_regex (vreq->path, &act->path_regex); + if (rc == 0) + { - // some error - return rc; - } + // no match + return 0; } - // type match? - if (act->has_type) { + if (rc < 0) + { - if (!S_ISBLK(vreq->mode) && !S_ISCHR(vreq->mode)) { - // device has no type - return 0; - } + // some error + return rc; + } + } + // type match? + if (act->has_type) + { - if (S_ISBLK(vreq->mode) && strcasecmp(act->type, "block") != 0) { + if (!S_ISBLK (vreq->mode) && !S_ISCHR (vreq->mode)) + { + // device has no type + return 0; + } - // not a block device - return 0; - } - if (S_ISCHR(vreq->mode) && strcasecmp(act->type, "char") != 0) { + if (S_ISBLK (vreq->mode) && strcasecmp (act->type, "block") != 0) + { - // not a char device - return 0; - } + // not a block device + return 0; } - // OS parameter match? - if (act->dev_params != NULL) { + if (S_ISCHR (vreq->mode) && strcasecmp (act->type, "char") != 0) + { - struct sglib_vdev_params_iterator itr; - struct vdev_param_t *dp = NULL; + // not a char device + return 0; + } + } + // OS parameter match? + if (act->dev_params != NULL) + { - for (dp = - sglib_vdev_params_it_init_inorder(&itr, act->dev_params); - dp != NULL; dp = sglib_vdev_params_it_next(&itr)) { + struct sglib_vdev_params_iterator itr; + struct vdev_param_t *dp = NULL; - struct vdev_param_t *match = - sglib_vdev_params_find_member(vreq->params, dp); + for (dp = + sglib_vdev_params_it_init_inorder (&itr, act->dev_params); + dp != NULL; dp = sglib_vdev_params_it_next (&itr)) + { - if (match != NULL) { + struct vdev_param_t *match = + sglib_vdev_params_find_member (vreq->params, dp); - // vreq has this parameter - char const *vreq_param_value = match->value; - char const *act_param_value = dp->value; + if (match != NULL) + { - // if the action has no value (value of length 0), then it matches any vreq value - if (act_param_value == NULL - || strlen(act_param_value) == 0) { + // vreq has this parameter + char const *vreq_param_value = match->value; + char const *act_param_value = dp->value; - continue; - } - // otherwise, compare the values - if (strcmp(vreq_param_value, act_param_value) != - 0) { + // if the action has no value (value of length 0), then it matches any vreq value + if (act_param_value == NULL || strlen (act_param_value) == 0) + { - // values don't match - return 0; - } - } else { + continue; + } + // otherwise, compare the values + if (strcmp (vreq_param_value, act_param_value) != 0) + { - // vreq does not have this parameter, so no match - return 0; - } + // values don't match + return 0; } + } + else + { + + // vreq does not have this parameter, so no match + return 0; + } } - // match! - return 1; + } + // match! + return 1; } // find the next action in a list of actions to run, given the path // return the index into acts of the next match, if found // return num_acts if not found // return negative on error -int vdev_action_find_next(struct vdev_device_request *vreq, - struct vdev_action *acts, size_t num_acts) +int +vdev_action_find_next (struct vdev_device_request *vreq, + struct vdev_action *acts, size_t num_acts) { - int rc = 0; - int i = 0; + int rc = 0; + int i = 0; - for (i = 0; (unsigned)i < num_acts; i++) { + for (i = 0; (unsigned) i < num_acts; i++) + { - rc = vdev_action_match(vreq, &acts[i]); + rc = vdev_action_match (vreq, &acts[i]); - if (rc > 0) { - return i; - } else if (rc < 0) { - return rc; - } + if (rc > 0) + { + return i; } + else if (rc < 0) + { + return rc; + } + } - return num_acts; + return num_acts; } // find the path to create for the given device request, but in a fail-fast manner (i.e. return on first error) @@ -1572,97 +1786,114 @@ int vdev_action_find_next(struct vdev_device_request *vreq, // return 0 on success // return -EINVAL if *path is not NULL, or if we failed to match the vreq against our actions due to a regex error // return -ENODATA if *path has zero-length -int vdev_action_create_path(struct vdev_device_request *vreq, - struct vdev_action *acts, size_t num_acts, - char **path) +int +vdev_action_create_path (struct vdev_device_request *vreq, + struct vdev_action *acts, size_t num_acts, + char **path) { - int rc = 0; - int act_offset = 0; - int i = 0; - char *new_path = NULL; + int rc = 0; + int act_offset = 0; + int i = 0; + char *new_path = NULL; + + if (*path != NULL) + { + return -EINVAL; + } + + while (act_offset < (signed) num_acts) + { + + rc = 0; + + // skip this action if there is no rename command + if (acts[act_offset].rename_command == NULL) + { + act_offset++; + continue; + } + // find the next action that matches this path + rc = vdev_action_find_next (vreq, acts + act_offset, + num_acts - act_offset); + + if (rc == (signed) (num_acts - act_offset)) + { + + // not found + rc = 0; + break; + } + else if (rc < 0) + { + + // error + vdev_error + ("vdev_action_find_next(%s, offset = %d) rc = %d\n", + vreq->path, act_offset, rc); + break; + } + else + { + + // matched! advance offset to next action + i = act_offset + rc; + act_offset += rc + 1; + rc = 0; + + if (acts[i].rename_command == NULL) + { + continue; + } + // generate the new name + rc = vdev_action_run_sync (vreq, acts[i].rename_command, + acts[i].helper_vars, true, + &new_path, PATH_MAX + 1); + if (rc < 0) + { + + vdev_error + ("vdev_action_run_sync('%s') rc = %d\n", + acts[i].rename_command, rc); + break; + } + else + { + + if (*path != NULL) + { + free (*path); + } - if (*path != NULL) { - return -EINVAL; + *path = new_path; + new_path = NULL; + } } + } - while (act_offset < (signed)num_acts) { + if (*path != NULL && strlen (*path) == 0) + { - rc = 0; + // if this is "UNKNOWN", then just reset to "UNKNOWN" + if (strcmp (vreq->path, VDEV_DEVICE_PATH_UNKNOWN) == 0) + { - // skip this action if there is no rename command - if (acts[act_offset].rename_command == NULL) { - act_offset++; - continue; - } - // find the next action that matches this path - rc = vdev_action_find_next(vreq, acts + act_offset, - num_acts - act_offset); - - if (rc == (signed)(num_acts - act_offset)) { - - // not found - rc = 0; - break; - } else if (rc < 0) { - - // error - vdev_error - ("vdev_action_find_next(%s, offset = %d) rc = %d\n", - vreq->path, act_offset, rc); - break; - } else { - - // matched! advance offset to next action - i = act_offset + rc; - act_offset += rc + 1; - rc = 0; - - if (acts[i].rename_command == NULL) { - continue; - } - // generate the new name - rc = vdev_action_run_sync(vreq, acts[i].rename_command, - acts[i].helper_vars, true, - &new_path, PATH_MAX + 1); - if (rc < 0) { - - vdev_error - ("vdev_action_run_sync('%s') rc = %d\n", - acts[i].rename_command, rc); - break; - } else { - - if (*path != NULL) { - free(*path); - } - - *path = new_path; - new_path = NULL; - } - } + free (*path); + *path = vdev_strdup_or_null (VDEV_DEVICE_PATH_UNKNOWN); } + else + { - if (*path != NULL && strlen(*path) == 0) { - - // if this is "UNKNOWN", then just reset to "UNKNOWN" - if (strcmp(vreq->path, VDEV_DEVICE_PATH_UNKNOWN) == 0) { - - free(*path); - *path = vdev_strdup_or_null(VDEV_DEVICE_PATH_UNKNOWN); - } else { - - vdev_error("Zero-length path generated for '%s'\n", - vreq->path); + vdev_error ("Zero-length path generated for '%s'\n", vreq->path); - free(*path); - *path = NULL; + free (*path); + *path = NULL; - rc = -ENODATA; - } + rc = -ENODATA; } + } - return rc; + return rc; } // run all actions for a device, sequentially, in lexographic order. @@ -1671,193 +1902,213 @@ int vdev_action_create_path(struct vdev_device_request *vreq, // if the device already exists (given by the exists flag), then only run commands with if_exists set to "run" // return 0 on success // return negative on failure -int vdev_action_run_commands(struct vdev_device_request *vreq, - struct vdev_action *acts, size_t num_acts, - bool exists) +int +vdev_action_run_commands (struct vdev_device_request *vreq, + struct vdev_action *acts, size_t num_acts, + bool exists) { - int rc = 0; - int act_offset = 0; - int i = 0; - char const *method = NULL; - struct timespec start; - struct timespec end; + int rc = 0; + int act_offset = 0; + int i = 0; + char const *method = NULL; + struct timespec start; + struct timespec end; + + while (act_offset < (signed) num_acts && rc == 0) + { + + // skip this action if there is no command + if (acts[act_offset].command == NULL) + { + act_offset++; + continue; + } + // find the next action that matches this path + rc = vdev_action_find_next (vreq, acts + act_offset, + num_acts - act_offset); + + if (rc == (signed) (num_acts - act_offset)) + { + + // not found + rc = 0; + break; + } + else if (rc < 0) + { + + vdev_error + ("vdev_action_find_next(%s, offset = %d) rc = %d\n", + vreq->path, act_offset, rc); + break; + } + else + { + + // matched! advance offset to next action + i = act_offset + rc; + act_offset += rc + 1; + rc = 0; + + if (acts[i].command == NULL) + { + continue; + } + + if (vreq->type == VDEV_DEVICE_ADD && exists + && acts[i].if_exists != VDEV_IF_EXISTS_RUN) + { + + if (acts[i].if_exists == VDEV_IF_EXISTS_ERROR) + { + + vdev_error + ("Will stop processing %s, since it already exists\n", + vreq->path); + rc = 1; + break; + } + else + { - while (act_offset < (signed)num_acts && rc == 0) { + // device already exists, but this is not considered by the .act file to be an error + continue; + } + } + // benchmark this... + clock_gettime (CLOCK_MONOTONIC, &start); + + // what kind of action to take? + if (!acts[i].is_daemonlet) + { + + if (acts[i].async) + { + + // fork a subprocess and handle asynchronously + method = "vdev_action_run_async"; + rc = vdev_action_run_async (vreq, + acts + [i].command, + acts + [i].helper_vars, + acts[i].use_shell); + } + else + { + + // run as a subprocess, wait, and join with it + method = "vdev_action_run_sync"; + rc = vdev_action_run_sync (vreq, + acts + [i].command, + acts + [i].helper_vars, + acts[i].use_shell, NULL, 0); + } + } + else + { + + if (acts[i].async) + { - // skip this action if there is no command - if (acts[act_offset].command == NULL) { - act_offset++; - continue; + // run as a daemonlet, feed it the request, but don't wait for a reply + method = "vdev_action_run_daemonlet_async"; } - // find the next action that matches this path - rc = vdev_action_find_next(vreq, acts + act_offset, - num_acts - act_offset); - - if (rc == (signed)(num_acts - act_offset)) { - - // not found - rc = 0; - break; - } else if (rc < 0) { - - vdev_error - ("vdev_action_find_next(%s, offset = %d) rc = %d\n", - vreq->path, act_offset, rc); - break; - } else { - - // matched! advance offset to next action - i = act_offset + rc; - act_offset += rc + 1; - rc = 0; - - if (acts[i].command == NULL) { - continue; - } - - if (vreq->type == VDEV_DEVICE_ADD && exists - && acts[i].if_exists != VDEV_IF_EXISTS_RUN) { - - if (acts[i].if_exists == VDEV_IF_EXISTS_ERROR) { - - vdev_error - ("Will stop processing %s, since it already exists\n", - vreq->path); - rc = 1; - break; - } else { - - // device already exists, but this is not considered by the .act file to be an error - continue; - } - } - // benchmark this... - clock_gettime(CLOCK_MONOTONIC, &start); - - // what kind of action to take? - if (!acts[i].is_daemonlet) { - - if (acts[i].async) { - - // fork a subprocess and handle asynchronously - method = "vdev_action_run_async"; - rc = vdev_action_run_async(vreq, - acts - [i].command, - acts - [i].helper_vars, - acts - [i].use_shell); - } else { - - // run as a subprocess, wait, and join with it - method = "vdev_action_run_sync"; - rc = vdev_action_run_sync(vreq, - acts - [i].command, - acts - [i].helper_vars, - acts - [i].use_shell, - NULL, 0); - } - } else { - - if (acts[i].async) { - - // run as a daemonlet, feed it the request, but don't wait for a reply - method = - "vdev_action_run_daemonlet_async"; - } else { - - // run as a daemonlet, feed the request, and wait for a reply - method = "vdev_action_run_daemonlet"; - } - - rc = vdev_action_run_daemonlet(vreq, &acts[i]); - } - - clock_gettime(CLOCK_MONOTONIC, &end); - - if (rc != 0) { - - vdev_error("%s('%s') rc = %d\n", method, - acts[i].command, rc); - - if (rc < 0) { - return rc; - } else { - - // mask non-zero exit statuses - uint64_t start_millis = - 1000L * start.tv_sec + - (start.tv_nsec / 1000000L); - uint64_t end_millis = - 1000L * end.tv_sec + - (end.tv_nsec / 1000000L); - - vdev_debug - ("Benchmark: action %s failed (exit %d) in %lu millis\n", - acts[i].name, rc, - (unsigned long)(end_millis - - start_millis)); - rc = 0; - } - } else { - - // success! update benchmark - acts[i].num_successful_calls++; - - uint64_t start_millis = - 1000L * start.tv_sec + - (start.tv_nsec / 1000000L); - uint64_t end_millis = - 1000L * end.tv_sec + - (end.tv_nsec / 1000000L); - - acts[i].cumulative_time_millis += - (end_millis - start_millis); - - // log timings directly, for finer granularity... - vdev_debug - ("Benchmark: action %s succeeded in %lu millis\n", - acts[i].name, - (unsigned long)(end_millis - - start_millis)); - } + else + { + + // run as a daemonlet, feed the request, and wait for a reply + method = "vdev_action_run_daemonlet"; } - } - if (rc > 0) { + rc = vdev_action_run_daemonlet (vreq, &acts[i]); + } + + clock_gettime (CLOCK_MONOTONIC, &end); - // not an error, but a cause to abort - rc = 0; + if (rc != 0) + { + + vdev_error ("%s('%s') rc = %d\n", method, acts[i].command, rc); + + if (rc < 0) + { + return rc; + } + else + { + + // mask non-zero exit statuses + uint64_t start_millis = + 1000L * start.tv_sec + (start.tv_nsec / 1000000L); + uint64_t end_millis = + 1000L * end.tv_sec + (end.tv_nsec / 1000000L); + + vdev_debug + ("Benchmark: action %s failed (exit %d) in %lu millis\n", + acts[i].name, rc, + (unsigned long) (end_millis - start_millis)); + rc = 0; + } + } + else + { + + // success! update benchmark + acts[i].num_successful_calls++; + + uint64_t start_millis = + 1000L * start.tv_sec + (start.tv_nsec / 1000000L); + uint64_t end_millis = + 1000L * end.tv_sec + (end.tv_nsec / 1000000L); + + acts[i].cumulative_time_millis += (end_millis - start_millis); + + // log timings directly, for finer granularity... + vdev_debug + ("Benchmark: action %s succeeded in %lu millis\n", + acts[i].name, (unsigned long) (end_millis - start_millis)); + } } + } + + if (rc > 0) + { + + // not an error, but a cause to abort + rc = 0; + } - return rc; + return rc; } // print out all benchmark information for this action // always succeeds -int vdev_action_log_benchmarks(struct vdev_action *action) +int +vdev_action_log_benchmarks (struct vdev_action *action) { - // int rc = 0; - - if (action->num_successful_calls > 0) { - vdev_debug - ("Action '%s' (daemon=%d, async=%d): %lu successful calls; %lu millis total; %lf avg.\n", - action->name, action->is_daemonlet, action->async, - action->num_successful_calls, - action->cumulative_time_millis, - (double)(action->cumulative_time_millis) / - (double)(action->num_successful_calls)); - } else { - vdev_debug - ("Action '%s' (daemon=%d, async=%d): 0 successful calls\n", - action->name, action->is_daemonlet, action->async); - } - - return 0; + // int rc = 0; + + if (action->num_successful_calls > 0) + { + vdev_debug + ("Action '%s' (daemon=%d, async=%d): %lu successful calls; %lu millis total; %lf avg.\n", + action->name, action->is_daemonlet, action->async, + action->num_successful_calls, + action->cumulative_time_millis, + (double) (action->cumulative_time_millis) / + (double) (action->num_successful_calls)); + } + else + { + vdev_debug + ("Action '%s' (daemon=%d, async=%d): 0 successful calls\n", + action->name, action->is_daemonlet, action->async); + } + + return 0; } diff --git a/vdevd/action.h b/vdevd/action.h index 66b7419..2f49f3b 100644 --- a/vdevd/action.h +++ b/vdevd/action.h @@ -53,92 +53,95 @@ #define VDEV_ACTION_DAEMONLET "daemonlet" -enum vdev_action_if_exists { - VDEV_IF_EXISTS_ERROR = 1, - VDEV_IF_EXISTS_MASK, - VDEV_IF_EXISTS_RUN +enum vdev_action_if_exists +{ + VDEV_IF_EXISTS_ERROR = 1, + VDEV_IF_EXISTS_MASK, + VDEV_IF_EXISTS_RUN }; // vdev action to take on an event -struct vdev_action { +struct vdev_action +{ - // action name - char *name; + // action name + char *name; - // what kind of request triggers this? - vdev_device_request_t trigger; + // what kind of request triggers this? + vdev_device_request_t trigger; - // device path to match on - char *path; - regex_t path_regex; + // device path to match on + char *path; + regex_t path_regex; - // device type to match on (block, char) - bool has_type; - char *type; + // device type to match on (block, char) + bool has_type; + char *type; - // command to run to rename the matched path, if needed - char *rename_command; + // command to run to rename the matched path, if needed + char *rename_command; - // command to run once the device state change is processed. - // can be dynamically generated from helper, below. - char *command; + // command to run once the device state change is processed. + // can be dynamically generated from helper, below. + char *command; - // name of a helper to run once the device state change is processed (conflicts with command) - char *helper; + // name of a helper to run once the device state change is processed (conflicts with command) + char *helper; - // whether or not to run this action in the system shell, or directly - bool use_shell; + // whether or not to run this action in the system shell, or directly + bool use_shell; - // OS-specific fields to match on - vdev_params *dev_params; + // OS-specific fields to match on + vdev_params *dev_params; - // helper-specific variables to export - vdev_params *helper_vars; + // helper-specific variables to export + vdev_params *helper_vars; - // synchronous or asynchronous - bool async; + // synchronous or asynchronous + bool async; - // how to handle the case where the device already exists - int if_exists; + // how to handle the case where the device already exists + int if_exists; - // is the action's command implemented as a daemonlet? If so, hold onto its runtime state - bool is_daemonlet; - int daemonlet_stdin; - int daemonlet_stdout; - pid_t daemonlet_pid; + // is the action's command implemented as a daemonlet? If so, hold onto its runtime state + bool is_daemonlet; + int daemonlet_stdin; + int daemonlet_stdout; + pid_t daemonlet_pid; - // action runtime statistics - uint64_t num_successful_calls; - uint64_t cumulative_time_millis; + // action runtime statistics + uint64_t num_successful_calls; + uint64_t cumulative_time_millis; }; typedef struct vdev_action vdev_action; C_LINKAGE_BEGIN -int vdev_action_init(struct vdev_action *act, vdev_device_request_t trigger, - char *path, char *command, char *helper, bool async); -int vdev_action_add_param(struct vdev_action *act, char const *name, - char const *value); -int vdev_action_free(struct vdev_action *act); -int vdev_action_free_all(struct vdev_action *act_list, size_t num_acts); - -int vdev_action_load(struct vdev_config *config, char const *path, - struct vdev_action *act); - -int vdev_action_load_all(struct vdev_config *config, struct vdev_action **acts, - size_t * num_acts); - -int vdev_action_create_path(struct vdev_device_request *vreq, - struct vdev_action *acts, size_t num_acts, - char **path); -int vdev_action_run_commands(struct vdev_device_request *vreq, + int vdev_action_init (struct vdev_action *act, + vdev_device_request_t trigger, char *path, + char *command, char *helper, bool async); +int vdev_action_add_param (struct vdev_action *act, char const *name, + char const *value); +int vdev_action_free (struct vdev_action *act); +int vdev_action_free_all (struct vdev_action *act_list, size_t num_acts); + +int vdev_action_load (struct vdev_config *config, char const *path, + struct vdev_action *act); + +int vdev_action_load_all (struct vdev_config *config, + struct vdev_action **acts, size_t * num_acts); + +int vdev_action_create_path (struct vdev_device_request *vreq, struct vdev_action *acts, size_t num_acts, - bool exists); + char **path); +int vdev_action_run_commands (struct vdev_device_request *vreq, + struct vdev_action *acts, size_t num_acts, + bool exists); -int vdev_action_daemonlet_stop_all(struct vdev_action *actions, - size_t num_actions); +int vdev_action_daemonlet_stop_all (struct vdev_action *actions, + size_t num_actions); -int vdev_action_log_benchmarks(struct vdev_action *action); +int vdev_action_log_benchmarks (struct vdev_action *action); C_LINKAGE_END #endif diff --git a/vdevd/device.c b/vdevd/device.c index 2c92cef..2e23970 100644 --- a/vdevd/device.c +++ b/vdevd/device.c @@ -28,115 +28,132 @@ // create a request // return 0 on success // return -ENOMEM if we can't allocate device parameters -int vdev_device_request_init(struct vdev_device_request *req, - struct vdev_state *state, - vdev_device_request_t req_type, char const *path) +int +vdev_device_request_init (struct vdev_device_request *req, + struct vdev_state *state, + vdev_device_request_t req_type, char const *path) { - memset(req, 0, sizeof(struct vdev_device_request)); + memset (req, 0, sizeof (struct vdev_device_request)); - if (path != NULL) { - req->path = vdev_strdup_or_null(path); - if (req->path == NULL) { - return -ENOMEM; - } + if (path != NULL) + { + req->path = vdev_strdup_or_null (path); + if (req->path == NULL) + { + return -ENOMEM; } + } - req->state = state; - req->type = req_type; + req->state = state; + req->type = req_type; - return 0; + return 0; } // free a request -int vdev_device_request_free(struct vdev_device_request *req) +int +vdev_device_request_free (struct vdev_device_request *req) { - if (req->params != NULL) { + if (req->params != NULL) + { - vdev_params_free(req->params); - req->params = NULL; - } + vdev_params_free (req->params); + req->params = NULL; + } - if (req->path != NULL) { + if (req->path != NULL) + { - free(req->path); - req->path = NULL; - } + free (req->path); + req->path = NULL; + } - if (req->renamed_path != NULL) { + if (req->renamed_path != NULL) + { - free(req->renamed_path); - req->renamed_path = NULL; - } + free (req->renamed_path); + req->renamed_path = NULL; + } - memset(req, 0, sizeof(struct vdev_device_request)); + memset (req, 0, sizeof (struct vdev_device_request)); - return 0; + return 0; } // add a device parameter (must be unique) // return 0 on success // return -EEXIST if the parameter exists // return -ENOMEM if OOM -int vdev_device_request_add_param(struct vdev_device_request *req, - char const *key, char const *value) +int +vdev_device_request_add_param (struct vdev_device_request *req, + char const *key, char const *value) { - return vdev_params_add(&req->params, key, value); + return vdev_params_add (&req->params, key, value); } // create a KEY=VALUE string -static int vdev_device_request_make_env_str(char const *key, char const *value, - char **ret) +static int +vdev_device_request_make_env_str (char const *key, char const *value, + char **ret) { - char *e = VDEV_CALLOC(char, strlen(key) + 1 + strlen(value) + 1); + char *e = VDEV_CALLOC (char, strlen (key) + 1 + strlen (value) + 1); - if (e == NULL) { - return -ENOMEM; - } + if (e == NULL) + { + return -ENOMEM; + } - sprintf(e, "%s=%s", key, value); - *ret = e; + sprintf (e, "%s=%s", key, value); + *ret = e; - return 0; + return 0; } // action to const string -static char const *vdev_device_request_type_to_string(vdev_device_request_t req) +static char const * +vdev_device_request_type_to_string (vdev_device_request_t req) { - if (req == VDEV_DEVICE_ADD) { - return "add"; - } - if (req == VDEV_DEVICE_REMOVE) { - return "remove"; - } - if (req == VDEV_DEVICE_CHANGE) { - return "change"; - } - - return "none"; + if (req == VDEV_DEVICE_ADD) + { + return "add"; + } + if (req == VDEV_DEVICE_REMOVE) + { + return "remove"; + } + if (req == VDEV_DEVICE_CHANGE) + { + return "change"; + } + + return "none"; } // mode to const string -static char const *vdev_device_request_mode_to_string(mode_t mode) +static char const * +vdev_device_request_mode_to_string (mode_t mode) { - static char const *blk_str = "block"; - static char const *chr_str = "char"; - static char const *none_str = "none"; + static char const *blk_str = "block"; + static char const *chr_str = "char"; + static char const *none_str = "none"; - if (S_ISBLK(mode)) { - return blk_str; - } + if (S_ISBLK (mode)) + { + return blk_str; + } - else if (S_ISCHR(mode)) { - return chr_str; - } + else if (S_ISCHR (mode)) + { + return chr_str; + } - return none_str; + return none_str; } // convert a device request to a list of null-terminated KEY=VALUE environment variable strings @@ -145,481 +162,534 @@ static char const *vdev_device_request_mode_to_string(mode_t mode) // return 0 on success // return negative on error // NOTE: not reload-safe; call while the reload lock is held -int vdev_device_request_to_env(struct vdev_device_request *req, - vdev_params * helper_vars, char ***ret_env, - size_t * num_env, int is_daemonlet) +int +vdev_device_request_to_env (struct vdev_device_request *req, + vdev_params * helper_vars, char ***ret_env, + size_t * num_env, int is_daemonlet) { - // type --> VDEV_ACTION - // path --> VDEV_PATH (if non-null) - // dev --> VDEV_MAJOR, VDEV_MINOR (if given) - // mode --> VDEV_MODE (if given) - // params --> VDEV_OS_* - // helper vars --> VDEV_VAR_* - // mountpoint --> VDEV_MOUNTPOINT - // metadata --> VDEV_METADATA (if path is non-null) - // global metadata --> VDEV_GLOBAL_METADATA - // helpers --> VDEV_HELPERS - // logfile --> VDEV_LOGFILE - // vdev instance nonce --> VDEV_INSTANCE - // config file --> VDEV_CONFIG_FILE - // daemonlet --> VDEV_DAEMONLET (0 by default, 1 if is_daemonlet is non-zero) - - size_t num_vars = - 15 + sglib_vdev_params_len(req->params) + - sglib_vdev_params_len(helper_vars); - int i = 0; - int rc = 0; - char dev_buf[51]; - struct vdev_param_t *dp = NULL; - struct sglib_vdev_params_iterator itr; - char *vdev_path = req->renamed_path; - char metadata_dir[PATH_MAX + 1]; - char global_metadata_dir[PATH_MAX + 1]; - char const *is_daemonlet_str = NULL; - char const *loglevel = NULL; - - if (is_daemonlet != 0) { - is_daemonlet_str = "1"; - } else { - is_daemonlet_str = "0"; - } + // type --> VDEV_ACTION + // path --> VDEV_PATH (if non-null) + // dev --> VDEV_MAJOR, VDEV_MINOR (if given) + // mode --> VDEV_MODE (if given) + // params --> VDEV_OS_* + // helper vars --> VDEV_VAR_* + // mountpoint --> VDEV_MOUNTPOINT + // metadata --> VDEV_METADATA (if path is non-null) + // global metadata --> VDEV_GLOBAL_METADATA + // helpers --> VDEV_HELPERS + // logfile --> VDEV_LOGFILE + // vdev instance nonce --> VDEV_INSTANCE + // config file --> VDEV_CONFIG_FILE + // daemonlet --> VDEV_DAEMONLET (0 by default, 1 if is_daemonlet is non-zero) + + size_t num_vars = + 15 + sglib_vdev_params_len (req->params) + + sglib_vdev_params_len (helper_vars); + int i = 0; + int rc = 0; + char dev_buf[51]; + struct vdev_param_t *dp = NULL; + struct sglib_vdev_params_iterator itr; + char *vdev_path = req->renamed_path; + char metadata_dir[PATH_MAX + 1]; + char global_metadata_dir[PATH_MAX + 1]; + char const *is_daemonlet_str = NULL; + char const *loglevel = NULL; + + if (is_daemonlet != 0) + { + is_daemonlet_str = "1"; + } + else + { + is_daemonlet_str = "0"; + } + + memset (metadata_dir, 0, PATH_MAX + 1); + memset (global_metadata_dir, 0, PATH_MAX + 1); + memset (dev_buf, 0, 51); + + if (vdev_path == NULL) + { + + vdev_path = req->path; + } + + if (vdev_path != NULL) + { + snprintf (metadata_dir, PATH_MAX, + "%s/" VDEV_METADATA_PREFIX "/dev/%s", + req->state->mountpoint, vdev_path); + } - memset(metadata_dir, 0, PATH_MAX + 1); - memset(global_metadata_dir, 0, PATH_MAX + 1); - memset(dev_buf, 0, 51); + char **env = VDEV_CALLOC (char *, num_vars + 1); - if (vdev_path == NULL) { + if (env == NULL) + { + return -ENOMEM; + } - vdev_path = req->path; - } + snprintf (global_metadata_dir, PATH_MAX, "%s/" VDEV_METADATA_PREFIX, + req->state->mountpoint); - if (vdev_path != NULL) { - snprintf(metadata_dir, PATH_MAX, - "%s/" VDEV_METADATA_PREFIX "/dev/%s", - req->state->mountpoint, vdev_path); - } + rc = vdev_device_request_make_env_str ("VDEV_MOUNTPOINT", + req->state->mountpoint, &env[i]); + if (rc != 0) + { - char **env = VDEV_CALLOC(char *, num_vars + 1); + VDEV_FREE_LIST (env); + return rc; + } - if (env == NULL) { - return -ENOMEM; - } + i++; - snprintf(global_metadata_dir, PATH_MAX, "%s/" VDEV_METADATA_PREFIX, - req->state->mountpoint); + rc = vdev_device_request_make_env_str ("VDEV_ACTION", + vdev_device_request_type_to_string + (req->type), &env[i]); + if (rc != 0) + { - rc = vdev_device_request_make_env_str("VDEV_MOUNTPOINT", - req->state->mountpoint, &env[i]); - if (rc != 0) { + VDEV_FREE_LIST (env); + return rc; + } - VDEV_FREE_LIST(env); - return rc; - } + i++; - i++; + if (vdev_path != NULL) + { - rc = vdev_device_request_make_env_str("VDEV_ACTION", - vdev_device_request_type_to_string - (req->type), &env[i]); - if (rc != 0) { + rc = vdev_device_request_make_env_str ("VDEV_PATH", vdev_path, &env[i]); + if (rc != 0) + { - VDEV_FREE_LIST(env); - return rc; + VDEV_FREE_LIST (env); + return rc; } - i++; - - if (vdev_path != NULL) { + i++; - rc = vdev_device_request_make_env_str("VDEV_PATH", vdev_path, - &env[i]); - if (rc != 0) { + rc = vdev_device_request_make_env_str ("VDEV_METADATA", + metadata_dir, &env[i]); + if (rc != 0) + { - VDEV_FREE_LIST(env); - return rc; - } - - i++; - - rc = vdev_device_request_make_env_str("VDEV_METADATA", - metadata_dir, &env[i]); - if (rc != 0) { - - VDEV_FREE_LIST(env); - return rc; - } - - i++; + VDEV_FREE_LIST (env); + return rc; } - rc = vdev_device_request_make_env_str("VDEV_GLOBAL_METADATA", - global_metadata_dir, &env[i]); - if (rc != 0) { + i++; + } - VDEV_FREE_LIST(env); - return rc; - } + rc = vdev_device_request_make_env_str ("VDEV_GLOBAL_METADATA", + global_metadata_dir, &env[i]); + if (rc != 0) + { - i++; + VDEV_FREE_LIST (env); + return rc; + } - rc = vdev_device_request_make_env_str("VDEV_CONFIG_FILE", - req->state->config->config_path, - &env[i]); - if (rc != 0) { + i++; - VDEV_FREE_LIST(env); - return rc; - } + rc = vdev_device_request_make_env_str ("VDEV_CONFIG_FILE", + req->state->config->config_path, + &env[i]); + if (rc != 0) + { - i++; + VDEV_FREE_LIST (env); + return rc; + } - if (req->dev != 0) { + i++; - snprintf(dev_buf, 50, "%u", major(req->dev)); + if (req->dev != 0) + { - rc = vdev_device_request_make_env_str("VDEV_MAJOR", dev_buf, - &env[i]); - if (rc != 0) { + snprintf (dev_buf, 50, "%u", major (req->dev)); - VDEV_FREE_LIST(env); - return rc; - } + rc = vdev_device_request_make_env_str ("VDEV_MAJOR", dev_buf, &env[i]); + if (rc != 0) + { - i++; + VDEV_FREE_LIST (env); + return rc; + } - snprintf(dev_buf, 50, "%u", minor(req->dev)); + i++; - rc = vdev_device_request_make_env_str("VDEV_MINOR", dev_buf, - &env[i]); - if (rc != 0) { + snprintf (dev_buf, 50, "%u", minor (req->dev)); - VDEV_FREE_LIST(env); - return rc; - } + rc = vdev_device_request_make_env_str ("VDEV_MINOR", dev_buf, &env[i]); + if (rc != 0) + { - i++; + VDEV_FREE_LIST (env); + return rc; } - if ((req->mode & (S_IFBLK | S_IFCHR)) != 0) { + i++; + } - rc = vdev_device_request_make_env_str("VDEV_MODE", - vdev_device_request_mode_to_string - (req->mode), &env[i]); - if (rc != 0) { + if ((req->mode & (S_IFBLK | S_IFCHR)) != 0) + { - VDEV_FREE_LIST(env); - return rc; - } + rc = vdev_device_request_make_env_str ("VDEV_MODE", + vdev_device_request_mode_to_string + (req->mode), &env[i]); + if (rc != 0) + { - i++; + VDEV_FREE_LIST (env); + return rc; } - rc = vdev_device_request_make_env_str("VDEV_HELPERS", - req->state->config->helpers_dir, - &env[i]); - if (rc != 0) { + i++; + } - VDEV_FREE_LIST(env); - return rc; - } + rc = vdev_device_request_make_env_str ("VDEV_HELPERS", + req->state->config->helpers_dir, + &env[i]); + if (rc != 0) + { - i++; + VDEV_FREE_LIST (env); + return rc; + } - if (req->state->config->logfile_path != NULL - && strcasecmp(req->state->config->logfile_path, "syslog") != 0) { + i++; - rc = vdev_device_request_make_env_str("VDEV_LOGFILE", - req->state-> - config->logfile_path, - &env[i]); - if (rc != 0) { + if (req->state->config->logfile_path != NULL + && strcasecmp (req->state->config->logfile_path, "syslog") != 0) + { - VDEV_FREE_LIST(env); - return rc; - } + rc = vdev_device_request_make_env_str ("VDEV_LOGFILE", + req->state->config->logfile_path, + &env[i]); + if (rc != 0) + { - i++; + VDEV_FREE_LIST (env); + return rc; } - rc = vdev_device_request_make_env_str("VDEV_INSTANCE", - req->state->config->instance_str, - &env[i]); - if (rc != 0) { + i++; + } - VDEV_FREE_LIST(env); - return rc; - } + rc = vdev_device_request_make_env_str ("VDEV_INSTANCE", + req->state->config->instance_str, + &env[i]); + if (rc != 0) + { - i++; + VDEV_FREE_LIST (env); + return rc; + } - rc = vdev_device_request_make_env_str("VDEV_DAEMONLET", - is_daemonlet_str, &env[i]); - if (rc != 0) { + i++; - VDEV_FREE_LIST(env); - return rc; - } + rc = vdev_device_request_make_env_str ("VDEV_DAEMONLET", + is_daemonlet_str, &env[i]); + if (rc != 0) + { - i++; + VDEV_FREE_LIST (env); + return rc; + } - if (vdev_get_debug_level() > 0) { - if (vdev_get_debug_level() == 1) { - loglevel = "info"; - } else { - loglevel = "debug"; - } - } else if (vdev_get_error_level() > 0) { - if (vdev_get_error_level() == 1) { - loglevel = "error"; - } else { - loglevel = "warning"; - } - } + i++; - if (loglevel == NULL) { - loglevel = "warning"; + if (vdev_get_debug_level () > 0) + { + if (vdev_get_debug_level () == 1) + { + loglevel = "info"; + } + else + { + loglevel = "debug"; + } + } + else if (vdev_get_error_level () > 0) + { + if (vdev_get_error_level () == 1) + { + loglevel = "error"; + } + else + { + loglevel = "warning"; } + } - rc = vdev_device_request_make_env_str("VDEV_LOGLEVEL", loglevel, - &env[i]); - if (rc != 0) { + if (loglevel == NULL) + { + loglevel = "warning"; + } - VDEV_FREE_LIST(env); - return rc; - } + rc = vdev_device_request_make_env_str ("VDEV_LOGLEVEL", loglevel, &env[i]); + if (rc != 0) + { - i++; + VDEV_FREE_LIST (env); + return rc; + } - // add all OS-specific parameters - for (dp = sglib_vdev_params_it_init_inorder(&itr, req->params); - dp != NULL; dp = sglib_vdev_params_it_next(&itr)) { + i++; - char const *param_key = dp->key; - char const *param_value = dp->value; + // add all OS-specific parameters + for (dp = sglib_vdev_params_it_init_inorder (&itr, req->params); + dp != NULL; dp = sglib_vdev_params_it_next (&itr)) + { - // prepend with "VDEV_OS_" - char *varname = VDEV_CALLOC(char, - strlen(param_key) + 1 + - strlen("VDEV_OS_")); + char const *param_key = dp->key; + char const *param_value = dp->value; - if (varname == NULL) { + // prepend with "VDEV_OS_" + char *varname = VDEV_CALLOC (char, + strlen (param_key) + 1 + + strlen ("VDEV_OS_")); - VDEV_FREE_LIST(env); - return -ENOMEM; - } + if (varname == NULL) + { - sprintf(varname, "VDEV_OS_%s", param_key); + VDEV_FREE_LIST (env); + return -ENOMEM; + } - rc = vdev_device_request_make_env_str(varname, param_value, - &env[i]); + sprintf (varname, "VDEV_OS_%s", param_key); - free(varname); + rc = vdev_device_request_make_env_str (varname, param_value, &env[i]); - if (rc != 0) { + free (varname); - VDEV_FREE_LIST(env); - return rc; - } + if (rc != 0) + { - i++; + VDEV_FREE_LIST (env); + return rc; } - // add all helper-specific variables - for (dp = sglib_vdev_params_it_init_inorder(&itr, helper_vars); - dp != NULL; dp = sglib_vdev_params_it_next(&itr)) { + i++; + } - char const *param_key = dp->key; - char const *param_value = dp->value; + // add all helper-specific variables + for (dp = sglib_vdev_params_it_init_inorder (&itr, helper_vars); + dp != NULL; dp = sglib_vdev_params_it_next (&itr)) + { - // prepend with "VDEV_OS_" - char *varname = VDEV_CALLOC(char, - strlen(param_key) + 1 + - strlen("VDEV_VAR_")); + char const *param_key = dp->key; + char const *param_value = dp->value; - if (varname == NULL) { + // prepend with "VDEV_OS_" + char *varname = VDEV_CALLOC (char, + strlen (param_key) + 1 + + strlen ("VDEV_VAR_")); - VDEV_FREE_LIST(env); - return -ENOMEM; - } + if (varname == NULL) + { - sprintf(varname, "VDEV_VAR_%s", param_key); + VDEV_FREE_LIST (env); + return -ENOMEM; + } - rc = vdev_device_request_make_env_str(varname, param_value, - &env[i]); + sprintf (varname, "VDEV_VAR_%s", param_key); - free(varname); + rc = vdev_device_request_make_env_str (varname, param_value, &env[i]); - if (rc != 0) { + free (varname); - VDEV_FREE_LIST(env); - return rc; - } + if (rc != 0) + { - i++; + VDEV_FREE_LIST (env); + return rc; } - *ret_env = env; - *num_env = i; + i++; + } + + *ret_env = env; + *num_env = i; - return 0; + return 0; } // set the path // return 0 on success // return -ENOMEM on OOM -int vdev_device_request_set_path(struct vdev_device_request *req, - char const *path) +int +vdev_device_request_set_path (struct vdev_device_request *req, + char const *path) { - if (req->path != NULL) { - free(req->path); - } + if (req->path != NULL) + { + free (req->path); + } - req->path = vdev_strdup_or_null(path); + req->path = vdev_strdup_or_null (path); - if (req->path == NULL && path != NULL) { - return -ENOMEM; - } + if (req->path == NULL && path != NULL) + { + return -ENOMEM; + } - return 0; + return 0; } // set the device // always succeeds -int vdev_device_request_set_dev(struct vdev_device_request *req, dev_t dev) +int +vdev_device_request_set_dev (struct vdev_device_request *req, dev_t dev) { - req->dev = dev; - return 0; + req->dev = dev; + return 0; } // mark this device as already existing // always succeeds -int vdev_device_request_set_exists(struct vdev_device_request *req, bool exists) +int +vdev_device_request_set_exists (struct vdev_device_request *req, bool exists) { - req->exists = exists; - return 0; + req->exists = exists; + return 0; } // device request sanity check // return 0 if valid // return -EINVAL if not valid -int vdev_device_request_sanity_check(struct vdev_device_request *req) +int +vdev_device_request_sanity_check (struct vdev_device_request *req) { - if (req->path == NULL) { + if (req->path == NULL) + { - vdev_error("request %p missing path\n", req); - return -EINVAL; - } + vdev_error ("request %p missing path\n", req); + return -EINVAL; + } - if (req->type == VDEV_DEVICE_INVALID) { + if (req->type == VDEV_DEVICE_INVALID) + { - vdev_error("request %p has no request type\n", req); - return -EINVAL; - } + vdev_error ("request %p has no request type\n", req); + return -EINVAL; + } - return 0; + return 0; } // set the request type -int vdev_device_request_set_type(struct vdev_device_request *req, - vdev_device_request_t req_type) +int +vdev_device_request_set_type (struct vdev_device_request *req, + vdev_device_request_t req_type) { - req->type = req_type; - return 0; + req->type = req_type; + return 0; } // set the request device mode -int vdev_device_request_set_mode(struct vdev_device_request *req, mode_t mode) +int +vdev_device_request_set_mode (struct vdev_device_request *req, mode_t mode) { - req->mode = mode; - return 0; + req->mode = mode; + return 0; } // generate a path to a device's metadata // return the malloc'ed path on success // return NULL on error -char *vdev_device_metadata_fullpath(char const *mountpoint, - char const *device_path) +char * +vdev_device_metadata_fullpath (char const *mountpoint, + char const *device_path) { - char *base_dir = NULL; - char *metadata_dir = VDEV_CALLOC(char, - strlen(mountpoint) + 1 + - strlen(VDEV_METADATA_PREFIX) + 2 + - strlen(device_path) + 1); - if (metadata_dir == NULL) { + char *base_dir = NULL; + char *metadata_dir = VDEV_CALLOC (char, + strlen (mountpoint) + 1 + + strlen (VDEV_METADATA_PREFIX) + 2 + + strlen (device_path) + 1); + if (metadata_dir == NULL) + { - return NULL; - } + return NULL; + } - sprintf(metadata_dir, VDEV_METADATA_PREFIX "/dev/%s", device_path); + sprintf (metadata_dir, VDEV_METADATA_PREFIX "/dev/%s", device_path); - base_dir = vdev_fullpath(mountpoint, metadata_dir, NULL); + base_dir = vdev_fullpath (mountpoint, metadata_dir, NULL); - free(metadata_dir); + free (metadata_dir); - if (base_dir == NULL) { + if (base_dir == NULL) + { - return NULL; - } + return NULL; + } - return base_dir; + return base_dir; } // create or update an item of metadata to $VDEV_MOUNTPOINT/$VDEV_METADATA_PREFIX/dev/$VDEV_PATH/$PARAM_KEY // return 0 on success // return negative on error -static int vdev_device_put_metadata_item(char *base_dir, char const *param_name, - char const *param_value, int flags, - mode_t mode) +static int +vdev_device_put_metadata_item (char *base_dir, char const *param_name, + char const *param_value, int flags, + mode_t mode) { - int rc = 0; - char *param_value_with_newline = NULL; - char *key_value_path = NULL; + int rc = 0; + char *param_value_with_newline = NULL; + char *key_value_path = NULL; - key_value_path = vdev_fullpath(base_dir, param_name, NULL); + key_value_path = vdev_fullpath (base_dir, param_name, NULL); - if (key_value_path == NULL) { + if (key_value_path == NULL) + { - rc = -ENOMEM; - return rc; - } + rc = -ENOMEM; + return rc; + } - param_value_with_newline = VDEV_CALLOC(char, strlen(param_value) + 2); - if (param_value_with_newline == NULL) { + param_value_with_newline = VDEV_CALLOC (char, strlen (param_value) + 2); + if (param_value_with_newline == NULL) + { - rc = -ENOMEM; - free(key_value_path); - return rc; - } + rc = -ENOMEM; + free (key_value_path); + return rc; + } - strcpy(param_value_with_newline, param_value); - strcat(param_value_with_newline, "\n"); + strcpy (param_value_with_newline, param_value); + strcat (param_value_with_newline, "\n"); - rc = vdev_write_file(key_value_path, param_value_with_newline, - strlen(param_value_with_newline), flags, mode); + rc = vdev_write_file (key_value_path, param_value_with_newline, + strlen (param_value_with_newline), flags, mode); - free(param_value_with_newline); + free (param_value_with_newline); - if (rc < 0) { + if (rc < 0) + { - vdev_error("vdev_write_file('%s', '%s') rc = %d\n", - key_value_path, param_value, rc); - } else { + vdev_error ("vdev_write_file('%s', '%s') rc = %d\n", + key_value_path, param_value, rc); + } + else + { - rc = 0; - } + rc = 0; + } - free(key_value_path); + free (key_value_path); - return rc; + return rc; } // record extra metadata (i.e. vdev parameters) for a device node @@ -630,244 +700,275 @@ static int vdev_device_put_metadata_item(char *base_dir, char const *param_name, // return negative on I/O error // NOTE: the device metadata directory ($VDEV_MOUNTPOINT/$VDEV_METADATA_PREFIX/dev) must exist // NOTE: not reload-safe; call while the reload lock is held -static int vdev_device_put_metadata(struct vdev_device_request *req) +static int +vdev_device_put_metadata (struct vdev_device_request *req) { - int rc = 0; - struct sglib_vdev_params_iterator itr; - struct vdev_param_t *dp; - - char *base_dir = NULL; - char *device_path = NULL; - - // only create device metadata if the device path is known. - if (req->renamed_path != NULL) { - - device_path = req->renamed_path; - } else if (req->path != NULL) { - - device_path = req->path; - } else { - - return -EINVAL; - } - - // unknown? - if (strcmp(device_path, VDEV_DEVICE_PATH_UNKNOWN) == 0) { - - return -EINVAL; - } - // path to device metadata - base_dir = - vdev_device_metadata_fullpath(req->state->mountpoint, - req->renamed_path); - if (base_dir == NULL) { - - return -ENOMEM; - } - // all directories must exist - rc = vdev_mkdirs(base_dir, strlen(req->state->mountpoint), 0755); - if (rc != 0) { - - vdev_error("vdev_mkdirs('%s') rc = %d\n", base_dir, rc); - - free(base_dir); - base_dir = NULL; - - return rc; - } - // save instance nonce - rc = vdev_device_put_metadata_item(base_dir, - VDEV_METADATA_PARAM_INSTANCE, - req->state->config->instance_str, - O_CREAT | O_WRONLY | O_TRUNC, 0644); - if (rc != 0) { - - if (rc == -EEXIST) { - - // try to update instead - rc = vdev_device_put_metadata_item(base_dir, - VDEV_METADATA_PARAM_INSTANCE, - req->state-> - config->instance_str, - O_WRONLY | O_TRUNC, - 0644); - } - - if (rc != 0) { - vdev_error - ("vdev_device_put_metadata_item('%s', '%s') rc = %d\n", - VDEV_METADATA_PARAM_INSTANCE, - req->state->config->instance_str, rc); - } - } - - free(base_dir); - - return rc; + int rc = 0; + struct sglib_vdev_params_iterator itr; + struct vdev_param_t *dp; + + char *base_dir = NULL; + char *device_path = NULL; + + // only create device metadata if the device path is known. + if (req->renamed_path != NULL) + { + + device_path = req->renamed_path; + } + else if (req->path != NULL) + { + + device_path = req->path; + } + else + { + + return -EINVAL; + } + + // unknown? + if (strcmp (device_path, VDEV_DEVICE_PATH_UNKNOWN) == 0) + { + + return -EINVAL; + } + // path to device metadata + base_dir = + vdev_device_metadata_fullpath (req->state->mountpoint, req->renamed_path); + if (base_dir == NULL) + { + + return -ENOMEM; + } + // all directories must exist + rc = vdev_mkdirs (base_dir, strlen (req->state->mountpoint), 0755); + if (rc != 0) + { + + vdev_error ("vdev_mkdirs('%s') rc = %d\n", base_dir, rc); + + free (base_dir); + base_dir = NULL; + + return rc; + } + // save instance nonce + rc = vdev_device_put_metadata_item (base_dir, + VDEV_METADATA_PARAM_INSTANCE, + req->state->config->instance_str, + O_CREAT | O_WRONLY | O_TRUNC, 0644); + if (rc != 0) + { + + if (rc == -EEXIST) + { + + // try to update instead + rc = vdev_device_put_metadata_item (base_dir, + VDEV_METADATA_PARAM_INSTANCE, + req->state-> + config->instance_str, + O_WRONLY | O_TRUNC, 0644); + } + + if (rc != 0) + { + vdev_error + ("vdev_device_put_metadata_item('%s', '%s') rc = %d\n", + VDEV_METADATA_PARAM_INSTANCE, + req->state->config->instance_str, rc); + } + } + + free (base_dir); + + return rc; } // remove helper for vdev_device_remove_metadata // return 0 on success // return -errno for unlink failure -static int vdev_device_remove_metadata_file(char const *fp, void *cls) +static int +vdev_device_remove_metadata_file (char const *fp, void *cls) { - int rc = 0; - struct stat sb; - - char name_buf[VDEV_NAME_MAX + 1]; + int rc = 0; + struct stat sb; - vdev_basename(fp, name_buf); + char name_buf[VDEV_NAME_MAX + 1]; - if (strcmp(name_buf, ".") == 0 || strcmp(name_buf, "..") == 0) { - // skip - return 0; - } - // is this a directory? - rc = lstat(fp, &sb); - if (rc != 0) { + vdev_basename (fp, name_buf); - rc = -errno; - vdev_warn("stat('%s') rc = %d\n", fp, rc); - return rc; - } + if (strcmp (name_buf, ".") == 0 || strcmp (name_buf, "..") == 0) + { + // skip + return 0; + } + // is this a directory? + rc = lstat (fp, &sb); + if (rc != 0) + { - if (S_ISDIR(sb.st_mode)) { + rc = -errno; + vdev_warn ("stat('%s') rc = %d\n", fp, rc); + return rc; + } - // blow away children too - rc = vdev_load_all(fp, vdev_device_remove_metadata_file, NULL); - if (rc != 0) { + if (S_ISDIR (sb.st_mode)) + { - vdev_warn("removing '%s' rc = %d\n", fp, rc); - return rc; - } - // blow away dir - rc = rmdir(fp); - } else { + // blow away children too + rc = vdev_load_all (fp, vdev_device_remove_metadata_file, NULL); + if (rc != 0) + { - // regular file - rc = unlink(fp); + vdev_warn ("removing '%s' rc = %d\n", fp, rc); + return rc; } + // blow away dir + rc = rmdir (fp); + } + else + { - if (rc != 0) { + // regular file + rc = unlink (fp); + } - rc = -errno; - vdev_warn("unlink('%s') rc = %d\n", fp, rc); - return rc; - } + if (rc != 0) + { - return rc; + rc = -errno; + vdev_warn ("unlink('%s') rc = %d\n", fp, rc); + return rc; + } + + return rc; } // remove extra metadata (i.e. vdev and OS parameters) for a deivce node // return 0 on success // return negative on error // NOTE: not reload-safe; call while the reload lock is held -static int vdev_device_remove_metadata(struct vdev_device_request *req) +static int +vdev_device_remove_metadata (struct vdev_device_request *req) { - int rc = 0; + int rc = 0; - char *base_dir = NULL; - char metadata_dir[PATH_MAX + 1]; + char *base_dir = NULL; + char metadata_dir[PATH_MAX + 1]; - // NOTE: req->path is guaranteed to be <= 256 characters - sprintf(metadata_dir, VDEV_METADATA_PREFIX "/dev/%s", req->path); + // NOTE: req->path is guaranteed to be <= 256 characters + sprintf (metadata_dir, VDEV_METADATA_PREFIX "/dev/%s", req->path); - base_dir = vdev_fullpath(req->state->mountpoint, metadata_dir, NULL); - if (base_dir == NULL) { + base_dir = vdev_fullpath (req->state->mountpoint, metadata_dir, NULL); + if (base_dir == NULL) + { - return -ENOMEM; - } - // remove everything in this directory - rc = vdev_load_all(base_dir, vdev_device_remove_metadata_file, NULL); + return -ENOMEM; + } + // remove everything in this directory + rc = vdev_load_all (base_dir, vdev_device_remove_metadata_file, NULL); - if (rc != 0) { + if (rc != 0) + { - vdev_error("vdev_load_all('%s') rc = %d\n", base_dir, rc); - } - // remove the directory itself - rc = rmdir(base_dir); - if (rc != 0) { + vdev_error ("vdev_load_all('%s') rc = %d\n", base_dir, rc); + } + // remove the directory itself + rc = rmdir (base_dir); + if (rc != 0) + { - rc = -errno; - vdev_warn("rmdir('%s') rc = %d\n", base_dir, rc); - } + rc = -errno; + vdev_warn ("rmdir('%s') rc = %d\n", base_dir, rc); + } - free(base_dir); - return rc; + free (base_dir); + return rc; } // do we have metadata logged for a device? // return 0 on success // return negative on error // NOTE: not reload-safe; call while the reload lock is held -static int vdev_device_has_metadata(struct vdev_device_request *req) +static int +vdev_device_has_metadata (struct vdev_device_request *req) { - int rc = 0; - struct stat sb; - char *md_fp = vdev_device_metadata_fullpath(req->state->mountpoint, - req->renamed_path); - if (md_fp == NULL) { + int rc = 0; + struct stat sb; + char *md_fp = vdev_device_metadata_fullpath (req->state->mountpoint, + req->renamed_path); + if (md_fp == NULL) + { - rc = -ENOMEM; - } else { + rc = -ENOMEM; + } + else + { - rc = stat(md_fp, &sb); - - if (rc != 0) { - rc = -errno; - } + rc = stat (md_fp, &sb); - free(md_fp); + if (rc != 0) + { + rc = -errno; } - return rc; + free (md_fp); + } + + return rc; } // create all directories leading up to a device // return 0 on success // return negative on error // NOTE: not reload-safe; call while the reload lock is held -static int vdev_device_mkdirs(struct vdev_device_request *req, - char **dev_fullpath) +static int +vdev_device_mkdirs (struct vdev_device_request *req, char **dev_fullpath) { - int rc = 0; - char *fp = NULL; - char *fp_dir = NULL; - - fp = vdev_fullpath(req->state->mountpoint, req->renamed_path, NULL); - if (fp == NULL) { + int rc = 0; + char *fp = NULL; + char *fp_dir = NULL; - rc = -ENOMEM; - return rc; - } + fp = vdev_fullpath (req->state->mountpoint, req->renamed_path, NULL); + if (fp == NULL) + { - if (strchr(req->renamed_path, '/') != NULL) { + rc = -ENOMEM; + return rc; + } - fp_dir = vdev_dirname(fp, NULL); - if (fp_dir == NULL) { + if (strchr (req->renamed_path, '/') != NULL) + { - rc = -ENOMEM; - free(fp); - return rc; - } - // make sure the directories leading to this path exist - rc = vdev_mkdirs(fp_dir, strlen(req->state->mountpoint), 0755); - if (rc != 0) { + fp_dir = vdev_dirname (fp, NULL); + if (fp_dir == NULL) + { - vdev_error("vdev_mkdirs('%s') rc = %d\n", fp_dir, rc); - } + rc = -ENOMEM; + free (fp); + return rc; + } + // make sure the directories leading to this path exist + rc = vdev_mkdirs (fp_dir, strlen (req->state->mountpoint), 0755); + if (rc != 0) + { - free(fp_dir); + vdev_error ("vdev_mkdirs('%s') rc = %d\n", fp_dir, rc); } - *dev_fullpath = fp; + free (fp_dir); + } - return rc; + *dev_fullpath = fp; + + return rc; } // handler to add a device @@ -876,325 +977,348 @@ static int vdev_device_mkdirs(struct vdev_device_request *req, // return -ENOMEM on OOM // return -EACCES if we do not have enough privileges to create the device node // return -EEXIST if the device node already exists -int vdev_device_add(struct vdev_device_request *req) +int +vdev_device_add (struct vdev_device_request *req) { - int rc = 0; - int do_mknod = 1; // if 1, issue mknod. Otherwise, check to see if the device exists by checking for metadata. - int device_exists = 0; // if 1, the device already exists. only run commands with the if_exists directive set to "run" + int rc = 0; + int do_mknod = 1; // if 1, issue mknod. Otherwise, check to see if the device exists by checking for metadata. + int device_exists = 0; // if 1, the device already exists. only run commands with the if_exists directive set to "run" - // prevent reloads while processing - vdev_reload_lock(req->state); + // prevent reloads while processing + vdev_reload_lock (req->state); - // do the rename, possibly generating it - rc = vdev_action_create_path(req, req->state->acts, - req->state->num_acts, &req->renamed_path); - if (rc != 0) { + // do the rename, possibly generating it + rc = vdev_action_create_path (req, req->state->acts, + req->state->num_acts, &req->renamed_path); + if (rc != 0) + { - vdev_error("vdev_action_create_path('%s') rc = %d\n", req->path, - rc); + vdev_error ("vdev_action_create_path('%s') rc = %d\n", req->path, rc); - // done with this request - vdev_reload_unlock(req->state); - vdev_device_request_free(req); - free(req); + // done with this request + vdev_reload_unlock (req->state); + vdev_device_request_free (req); + free (req); - return rc; - } + return rc; + } - if (req->renamed_path == NULL) { + if (req->renamed_path == NULL) + { - // base path becomes renamed path (trivial rename) - req->renamed_path = vdev_strdup_or_null(req->path); - if (req->renamed_path == NULL && req->path != NULL) { + // base path becomes renamed path (trivial rename) + req->renamed_path = vdev_strdup_or_null (req->path); + if (req->renamed_path == NULL && req->path != NULL) + { - // done with this request - vdev_reload_unlock(req->state); - vdev_device_request_free(req); - free(req); + // done with this request + vdev_reload_unlock (req->state); + vdev_device_request_free (req); + free (req); - return -ENOMEM; - } + return -ENOMEM; } + } + + vdev_debug ("ADD device: type '%s' at '%s' ('%s' %d:%d)\n", + (S_ISBLK (req->mode) ? "block" : S_ISCHR (req->mode) ? "char" : + "unknown"), req->renamed_path, req->path, major (req->dev), + minor (req->dev)); - vdev_debug("ADD device: type '%s' at '%s' ('%s' %d:%d)\n", - (S_ISBLK(req->mode) ? "block" : S_ISCHR(req->mode) ? "char" : - "unknown"), req->renamed_path, req->path, major(req->dev), - minor(req->dev)); + if (req->renamed_path != NULL) + { - if (req->renamed_path != NULL) { + // device has a name (i.e. something for us to add)? + if (strcmp (req->renamed_path, VDEV_DEVICE_PATH_UNKNOWN) != 0) + { - // device has a name (i.e. something for us to add)? - if (strcmp(req->renamed_path, VDEV_DEVICE_PATH_UNKNOWN) != 0) { + // device has major/minor/mode? + if (req->dev != 0 && req->mode != 0) + { - // device has major/minor/mode? - if (req->dev != 0 && req->mode != 0) { + char *fp = NULL; // full path to the device - char *fp = NULL; // full path to the device + rc = vdev_device_mkdirs (req, &fp); + if (rc != 0) + { - rc = vdev_device_mkdirs(req, &fp); - if (rc != 0) { + vdev_error + ("vdev_device_mkdirs('%s/%s') rc = %d\n", + req->state->mountpoint, req->renamed_path, rc); - vdev_error - ("vdev_device_mkdirs('%s/%s') rc = %d\n", - req->state->mountpoint, - req->renamed_path, rc); + // done with this request + vdev_reload_unlock (req->state); + vdev_device_request_free (req); + free (req); + + return rc; + } + // do we need to make the device? + if (vdev_config_has_OS_quirk + (req->state->config->OS_quirks, + VDEV_OS_QUIRK_DEVICE_EXISTS)) + { + + // nope, but did we process it already? + if (vdev_device_has_metadata (req)) + { + + // this device already exists, insofar as + // we (or some other device manager) + // have already processed it. + device_exists = 1; + } + } - // done with this request - vdev_reload_unlock(req->state); - vdev_device_request_free(req); - free(req); + else + { - return rc; - } - // do we need to make the device? - if (vdev_config_has_OS_quirk - (req->state->config->OS_quirks, - VDEV_OS_QUIRK_DEVICE_EXISTS)) { + if (!req->exists) + { - // nope, but did we process it already? - if (vdev_device_has_metadata(req)) { + // file is not expected to exist + rc = mknod (fp, + req->mode | req->state-> + config->default_mode, req->dev); + } + else + { - // this device already exists, insofar as - // we (or some other device manager) - // have already processed it. - device_exists = 1; - } - } + rc = 0; + } - else { + if (rc != 0) + { - if (!req->exists) { + rc = -errno; + if (rc == -EEXIST) + { - // file is not expected to exist - rc = mknod(fp, - req-> - mode | req->state-> - config->default_mode, - req->dev); - } else { + // device already exists, insofar as + // we (or some other device manager) + // have already processed it. + device_exists = 1; + rc = 0; + } + } + } - rc = 0; - } + free (fp); + } + // no major/minor/mode + else + { - if (rc != 0) { + // not creating a device file, but a device-add event nevertheless. + // creating or updating? + rc = vdev_device_has_metadata (req); + if (rc != 0) + { - rc = -errno; - if (rc == -EEXIST) { + if (rc == -ENOENT) + { - // device already exists, insofar as - // we (or some other device manager) - // have already processed it. - device_exists = 1; - rc = 0; - } - } - } + // add metadata, since none exists! + rc = 0; + } + } + else + { - free(fp); - } - // no major/minor/mode - else { - - // not creating a device file, but a device-add event nevertheless. - // creating or updating? - rc = vdev_device_has_metadata(req); - if (rc != 0) { - - if (rc == -ENOENT) { - - // add metadata, since none exists! - rc = 0; - } - } else { - - // metadata already present, meaning - // that this device has been processed - rc = 0; - device_exists = 1; - } - } + // metadata already present, meaning + // that this device has been processed + rc = 0; + device_exists = 1; + } + } - if (rc != 0) { + if (rc != 0) + { - // some mknod or metadata I/O error occurred - vdev_error("Add device '%s/%s', rc = %d\n", - req->state->mountpoint, - req->renamed_path, rc); - } + // some mknod or metadata I/O error occurred + vdev_error ("Add device '%s/%s', rc = %d\n", + req->state->mountpoint, req->renamed_path, rc); + } - else { + else + { - // put/update metadata - rc = vdev_device_put_metadata(req); + // put/update metadata + rc = vdev_device_put_metadata (req); - if (rc != 0) { + if (rc != 0) + { - vdev_error - ("vdev_device_put_metadata('%s/%s') rc = %d\n", - req->state->mountpoint, - req->renamed_path, rc); - } - } + vdev_error + ("vdev_device_put_metadata('%s/%s') rc = %d\n", + req->state->mountpoint, req->renamed_path, rc); } + } + } - if (rc == 0) { + if (rc == 0) + { - // no problems yet. call all ADD actions - rc = vdev_action_run_commands(req, req->state->acts, - req->state->num_acts, - device_exists); - if (rc != 0) { + // no problems yet. call all ADD actions + rc = vdev_action_run_commands (req, req->state->acts, + req->state->num_acts, device_exists); + if (rc != 0) + { - vdev_error - ("vdev_action_run_commands(ADD %s, dev=(%u, %u)) rc = %d\n", - req->renamed_path, major(req->dev), - minor(req->dev), rc); - } - } + vdev_error + ("vdev_action_run_commands(ADD %s, dev=(%u, %u)) rc = %d\n", + req->renamed_path, major (req->dev), minor (req->dev), rc); + } } - // done with this request - vdev_reload_unlock(req->state); - vdev_device_request_free(req); - free(req); + } + // done with this request + vdev_reload_unlock (req->state); + vdev_device_request_free (req); + free (req); - return 0; + return 0; } // workqueue call to vdev_device_add -static int vdev_device_add_wq(struct vdev_wreq *wreq, void *cls) +static int +vdev_device_add_wq (struct vdev_wreq *wreq, void *cls) { - struct vdev_device_request *req = (struct vdev_device_request *)cls; - return vdev_device_add(req); + struct vdev_device_request *req = (struct vdev_device_request *) cls; + return vdev_device_add (req); } // handler to remove a device (unlink) // return 0 on success. This masks failure to unlink or clean up metadata or a failed action. // return -ENOMEM on OOM -int vdev_device_remove(struct vdev_device_request *req) +int +vdev_device_remove (struct vdev_device_request *req) { - int rc = 0; + int rc = 0; - vdev_reload_lock(req->state); + vdev_reload_lock (req->state); - // do the rename, possibly generating it - rc = vdev_action_create_path(req, req->state->acts, - req->state->num_acts, &req->renamed_path); - if (rc != 0) { + // do the rename, possibly generating it + rc = vdev_action_create_path (req, req->state->acts, + req->state->num_acts, &req->renamed_path); + if (rc != 0) + { - vdev_error("vdev_action_create_path('%s') rc = %d\n", req->path, - rc); + vdev_error ("vdev_action_create_path('%s') rc = %d\n", req->path, rc); - // done with this request - vdev_reload_unlock(req->state); - vdev_device_request_free(req); - free(req); + // done with this request + vdev_reload_unlock (req->state); + vdev_device_request_free (req); + free (req); - return rc; - } + return rc; + } - if (req->renamed_path == NULL) { + if (req->renamed_path == NULL) + { - req->renamed_path = vdev_strdup_or_null(req->path); - if (req->renamed_path == NULL && req->path == NULL) { + req->renamed_path = vdev_strdup_or_null (req->path); + if (req->renamed_path == NULL && req->path == NULL) + { - // done with this request - vdev_reload_unlock(req->state); - vdev_device_request_free(req); - free(req); + // done with this request + vdev_reload_unlock (req->state); + vdev_device_request_free (req); + free (req); - return -ENOMEM; - } + return -ENOMEM; } + } - vdev_info("REMOVE device: type '%s' at '%s' ('%s' %d:%d)\n", - (S_ISBLK(req->mode) ? "block" : S_ISCHR(req->mode) ? "char" : - "unknown"), req->renamed_path, req->path, major(req->dev), - minor(req->dev)); + vdev_info ("REMOVE device: type '%s' at '%s' ('%s' %d:%d)\n", + (S_ISBLK (req->mode) ? "block" : S_ISCHR (req->mode) ? "char" : + "unknown"), req->renamed_path, req->path, major (req->dev), + minor (req->dev)); - if (req->renamed_path != NULL) { + if (req->renamed_path != NULL) + { - // call all REMOVE actions - rc = vdev_action_run_commands(req, req->state->acts, - req->state->num_acts, true); - if (rc != 0) { + // call all REMOVE actions + rc = vdev_action_run_commands (req, req->state->acts, + req->state->num_acts, true); + if (rc != 0) + { - vdev_error("vdev_action_run_all(REMOVE %s) rc = %d\n", - req->renamed_path, rc); - rc = 0; - } + vdev_error ("vdev_action_run_all(REMOVE %s) rc = %d\n", + req->renamed_path, rc); + rc = 0; + } - if (strcmp(req->renamed_path, VDEV_DEVICE_PATH_UNKNOWN) != 0) { + if (strcmp (req->renamed_path, VDEV_DEVICE_PATH_UNKNOWN) != 0) + { - // known path - // only remove files from /dev if this is a device, and we created it - if (req->dev != 0 && req->mode != 0 - && !vdev_config_has_OS_quirk(req->state-> - config->OS_quirks, - VDEV_OS_QUIRK_DEVICE_EXISTS)) - { + // known path + // only remove files from /dev if this is a device, and we created it + if (req->dev != 0 && req->mode != 0 + && !vdev_config_has_OS_quirk (req->state->config->OS_quirks, + VDEV_OS_QUIRK_DEVICE_EXISTS)) + { - // remove the data itself, if there is data - char *fp = vdev_fullpath(req->state->mountpoint, - req->renamed_path, - NULL); + // remove the data itself, if there is data + char *fp = vdev_fullpath (req->state->mountpoint, + req->renamed_path, + NULL); - rc = unlink(fp); - if (rc != 0) { + rc = unlink (fp); + if (rc != 0) + { - rc = -errno; + rc = -errno; - if (rc != -ENOENT) { - vdev_error - ("unlink(%s) rc = %d\n", fp, - rc); - } + if (rc != -ENOENT) + { + vdev_error ("unlink(%s) rc = %d\n", fp, rc); + } - rc = 0; - } - // try to clean up directories - rc = vdev_rmdirs(fp); - if (rc != 0 && rc != -ENOTEMPTY - && rc != -ENOENT) { + rc = 0; + } + // try to clean up directories + rc = vdev_rmdirs (fp); + if (rc != 0 && rc != -ENOTEMPTY && rc != -ENOENT) + { - vdev_error - ("vdev_rmdirs('%s') rc = %d\n", fp, - rc); - rc = 0; - } + vdev_error ("vdev_rmdirs('%s') rc = %d\n", fp, rc); + rc = 0; + } - free(fp); - } - // remove metadata - rc = vdev_device_remove_metadata(req); + free (fp); + } + // remove metadata + rc = vdev_device_remove_metadata (req); - if (rc != 0) { + if (rc != 0) + { - vdev_warn - ("unable to clean up metadata for %s\n", - req->renamed_path); - rc = 0; - } - } + vdev_warn + ("unable to clean up metadata for %s\n", req->renamed_path); + rc = 0; + } } + } - vdev_reload_unlock(req->state); + vdev_reload_unlock (req->state); - // done with this request - vdev_device_request_free(req); - free(req); + // done with this request + vdev_device_request_free (req); + free (req); - return rc; + return rc; } // workqueue call to vdev_device_remove -static int vdev_device_remove_wq(struct vdev_wreq *wreq, void *cls) +static int +vdev_device_remove_wq (struct vdev_wreq *wreq, void *cls) { - struct vdev_device_request *req = (struct vdev_device_request *)cls; - return vdev_device_remove(req); + struct vdev_device_request *req = (struct vdev_device_request *) cls; + return vdev_device_remove (req); } // handler to change a device @@ -1204,77 +1328,82 @@ static int vdev_device_remove_wq(struct vdev_wreq *wreq, void *cls) // return -ENOMEM on OOM // return -EACCES if we do not have enough privileges to create the device node // return -EEXIST if the device node already exists -int vdev_device_change(struct vdev_device_request *req) +int +vdev_device_change (struct vdev_device_request *req) { - int rc = 0; + int rc = 0; - vdev_reload_lock(req->state); + vdev_reload_lock (req->state); - // do the rename, possibly generating it - rc = vdev_action_create_path(req, req->state->acts, - req->state->num_acts, &req->renamed_path); - if (rc != 0) { + // do the rename, possibly generating it + rc = vdev_action_create_path (req, req->state->acts, + req->state->num_acts, &req->renamed_path); + if (rc != 0) + { - vdev_error("vdev_action_create_path('%s') rc = %d\n", req->path, - rc); + vdev_error ("vdev_action_create_path('%s') rc = %d\n", req->path, rc); - // done with this request - vdev_reload_unlock(req->state); - vdev_device_request_free(req); - free(req); + // done with this request + vdev_reload_unlock (req->state); + vdev_device_request_free (req); + free (req); - return rc; - } + return rc; + } - if (req->renamed_path == NULL) { + if (req->renamed_path == NULL) + { - // base path becomes renamed path (trivial rename) - req->renamed_path = vdev_strdup_or_null(req->path); - if (req->renamed_path == NULL && req->path != NULL) { + // base path becomes renamed path (trivial rename) + req->renamed_path = vdev_strdup_or_null (req->path); + if (req->renamed_path == NULL && req->path != NULL) + { - // done with this request - vdev_reload_unlock(req->state); - vdev_device_request_free(req); - free(req); - return -ENOMEM; - } + // done with this request + vdev_reload_unlock (req->state); + vdev_device_request_free (req); + free (req); + return -ENOMEM; } + } - vdev_debug("CHANGE device: type '%s' at '%s' ('%s' %d:%d)\n", - (S_ISBLK(req->mode) ? "block" : S_ISCHR(req->mode) ? "char" : - "unknown"), req->renamed_path, req->path, major(req->dev), - minor(req->dev)); + vdev_debug ("CHANGE device: type '%s' at '%s' ('%s' %d:%d)\n", + (S_ISBLK (req->mode) ? "block" : S_ISCHR (req->mode) ? "char" : + "unknown"), req->renamed_path, req->path, major (req->dev), + minor (req->dev)); - if (req->renamed_path != NULL && vdev_device_has_metadata(req)) { + if (req->renamed_path != NULL && vdev_device_has_metadata (req)) + { - // call all CHANGE actions - rc = vdev_action_run_commands(req, req->state->acts, - req->state->num_acts, 1); - if (rc != 0) { + // call all CHANGE actions + rc = vdev_action_run_commands (req, req->state->acts, + req->state->num_acts, 1); + if (rc != 0) + { - vdev_error - ("vdev_action_run_commands(ADD %s, dev=(%u, %u)) rc = %d\n", - req->renamed_path, major(req->dev), - minor(req->dev), rc); - } + vdev_error + ("vdev_action_run_commands(ADD %s, dev=(%u, %u)) rc = %d\n", + req->renamed_path, major (req->dev), minor (req->dev), rc); } + } - vdev_reload_unlock(req->state); + vdev_reload_unlock (req->state); - // done with this request - vdev_device_request_free(req); - free(req); + // done with this request + vdev_device_request_free (req); + free (req); - return 0; + return 0; } // workqueue call to vdev_device_change -static int vdev_device_change_wq(struct vdev_wreq *wreq, void *cls) +static int +vdev_device_change_wq (struct vdev_wreq *wreq, void *cls) { - struct vdev_device_request *req = (struct vdev_device_request *)cls; - return vdev_device_change(req); + struct vdev_device_request *req = (struct vdev_device_request *) cls; + return vdev_device_change (req); } // enqueue a device request @@ -1282,56 +1411,63 @@ static int vdev_device_change_wq(struct vdev_wreq *wreq, void *cls) // return 0 on success // return -EINVAL if the device request is missing required fields // return -ENOMEM on OOM -int vdev_device_request_enqueue(struct vdev_wq *wq, - struct vdev_device_request *req) +int +vdev_device_request_enqueue (struct vdev_wq *wq, + struct vdev_device_request *req) { - int rc = 0; - struct vdev_wreq wreq; + int rc = 0; + struct vdev_wreq wreq; - memset(&wreq, 0, sizeof(struct vdev_wreq)); + memset (&wreq, 0, sizeof (struct vdev_wreq)); - // sanity check - rc = vdev_device_request_sanity_check(req); - if (rc != 0) { + // sanity check + rc = vdev_device_request_sanity_check (req); + if (rc != 0) + { - vdev_error("Invalid device request (type %d)\n", req->type); - return -EINVAL; - } - // which handler? - switch (req->type) { + vdev_error ("Invalid device request (type %d)\n", req->type); + return -EINVAL; + } + // which handler? + switch (req->type) + { - case VDEV_DEVICE_ADD:{ + case VDEV_DEVICE_ADD: + { - vdev_wreq_init(&wreq, vdev_device_add_wq, req); - break; - } + vdev_wreq_init (&wreq, vdev_device_add_wq, req); + break; + } - case VDEV_DEVICE_REMOVE:{ + case VDEV_DEVICE_REMOVE: + { - vdev_wreq_init(&wreq, vdev_device_remove_wq, req); - break; - } + vdev_wreq_init (&wreq, vdev_device_remove_wq, req); + break; + } - case VDEV_DEVICE_CHANGE:{ + case VDEV_DEVICE_CHANGE: + { - vdev_wreq_init(&wreq, vdev_device_change_wq, req); - break; - } + vdev_wreq_init (&wreq, vdev_device_change_wq, req); + break; + } - default:{ + default: + { - vdev_error("Invalid device request type %d\n", - req->type); - return -EINVAL; - } - } + vdev_error ("Invalid device request type %d\n", req->type); + return -EINVAL; + } + } - rc = vdev_wq_add(wq, &wreq); - if (rc != 0) { + rc = vdev_wq_add (wq, &wreq); + if (rc != 0) + { - vdev_error("vdev_wq_add('%s') rc = %d\n", req->path, rc); - } + vdev_error ("vdev_wq_add('%s') rc = %d\n", req->path, rc); + } - return rc; + return rc; } diff --git a/vdevd/device.h b/vdevd/device.h index 7c63c77..12f7a72 100644 --- a/vdevd/device.h +++ b/vdevd/device.h @@ -35,86 +35,89 @@ #define VDEV_METADATA_PARAM_INSTANCE "vdev_instance" // device request type -typedef enum { - VDEV_DEVICE_INVALID = 0, // invalid request - VDEV_DEVICE_ADD, - VDEV_DEVICE_REMOVE, - VDEV_DEVICE_CHANGE, - VDEV_DEVICE_ANY // only useful for actions +typedef enum +{ + VDEV_DEVICE_INVALID = 0, // invalid request + VDEV_DEVICE_ADD, + VDEV_DEVICE_REMOVE, + VDEV_DEVICE_CHANGE, + VDEV_DEVICE_ANY // only useful for actions } vdev_device_request_t; struct vdev_state; // device request -struct vdev_device_request { +struct vdev_device_request +{ - // type of request (always initialized) - vdev_device_request_t type; + // type of request (always initialized) + vdev_device_request_t type; - // path to the device node to create (if we're making one at all) - // If we're creating a network interface, this is the interface name. - char *path; + // path to the device node to create (if we're making one at all) + // If we're creating a network interface, this is the interface name. + char *path; - // renamed path (used internally) - char *renamed_path; + // renamed path (used internally) + char *renamed_path; - // device numbers, for mknod - dev_t dev; + // device numbers, for mknod + dev_t dev; - // device mode: character or block device - mode_t mode; + // device mode: character or block device + mode_t mode; - // OS-specific driver parameters - vdev_params *params; + // OS-specific driver parameters + vdev_params *params; - // reference to vdev state, so we can call other methods when working - struct vdev_state *state; + // reference to vdev state, so we can call other methods when working + struct vdev_state *state; - // does this device file already exist? for example, did the preseed script create it? this applies to files like /dev/null, which *need* to exist. - bool exists; + // does this device file already exist? for example, did the preseed script create it? this applies to files like /dev/null, which *need* to exist. + bool exists; - // reference to the next item, since this structure often gets used for linked lists - struct vdev_device_request *next; + // reference to the next item, since this structure often gets used for linked lists + struct vdev_device_request *next; }; C_LINKAGE_BEGIN // memory management -int vdev_device_request_init(struct vdev_device_request *req, - struct vdev_state *state, - vdev_device_request_t type, char const *path); -int vdev_device_request_free(struct vdev_device_request *req); +int vdev_device_request_init (struct vdev_device_request *req, + struct vdev_state *state, + vdev_device_request_t type, char const *path); +int vdev_device_request_free (struct vdev_device_request *req); // setters for device requests (so the OS can build one up) -int vdev_device_request_set_type(struct vdev_device_request *req, - vdev_device_request_t req_type); -int vdev_device_request_set_dev(struct vdev_device_request *req, dev_t dev); -int vdev_device_request_set_mode(struct vdev_device_request *req, mode_t mode); -int vdev_device_request_set_path(struct vdev_device_request *req, - char const *path); -int vdev_device_request_add_param(struct vdev_device_request *req, - char const *key, char const *value); -int vdev_device_request_set_exists(struct vdev_device_request *req, - bool exists); +int vdev_device_request_set_type (struct vdev_device_request *req, + vdev_device_request_t req_type); +int vdev_device_request_set_dev (struct vdev_device_request *req, dev_t dev); +int vdev_device_request_set_mode (struct vdev_device_request *req, + mode_t mode); +int vdev_device_request_set_path (struct vdev_device_request *req, + char const *path); +int vdev_device_request_add_param (struct vdev_device_request *req, + char const *key, char const *value); +int vdev_device_request_set_exists (struct vdev_device_request *req, + bool exists); // environment variables -int vdev_device_request_to_env(struct vdev_device_request *req, - vdev_params * helper_vars, char ***env, - size_t * num_env, int is_daemonlet); +int vdev_device_request_to_env (struct vdev_device_request *req, + vdev_params * helper_vars, char ***env, + size_t * num_env, int is_daemonlet); // add a device request to the work queue -int vdev_device_request_enqueue(struct vdev_wq *wq, - struct vdev_device_request *req); +int vdev_device_request_enqueue (struct vdev_wq *wq, + struct vdev_device_request *req); // sanity check structure -int vdev_device_request_sanity_check(struct vdev_device_request *req); +int vdev_device_request_sanity_check (struct vdev_device_request *req); // device metadata -char *vdev_device_metadata_fullpath(char const *mountpoint, - char const *device_path); +char *vdev_device_metadata_fullpath (char const *mountpoint, + char const *device_path); // add/remove devices -int vdev_device_add(struct vdev_device_request *req); -int vdev_device_remove(struct vdev_device_request *req); +int vdev_device_add (struct vdev_device_request *req); +int vdev_device_remove (struct vdev_device_request *req); C_LINKAGE_END #endif diff --git a/vdevd/helpers/LINUX/common.c b/vdevd/helpers/LINUX/common.c index f4fec2b..cd83c28 100644 --- a/vdevd/helpers/LINUX/common.c +++ b/vdevd/helpers/LINUX/common.c @@ -53,240 +53,246 @@ #include "common.h" -int vdev_util_replace_whitespace(const char *str, char *to, size_t len) { - size_t i, j; - - /* strip trailing whitespace */ - len = strnlen(str, len); - while (len && isspace(str[len-1])) { - len--; - } - - /* strip leading whitespace */ - i = 0; - while (isspace(str[i]) && (i < len)) { - i++; - } - - j = 0; - while (i < len) { - /* substitute multiple whitespace with a single '_' */ - if (isspace(str[i])) { - while (isspace(str[i])) { - i++; - } - to[j++] = '_'; - } - to[j++] = str[i++]; - } - to[j] = '\0'; - return 0; +int vdev_util_replace_whitespace(const char *str, char *to, size_t len) +{ + size_t i, j; + + /* strip trailing whitespace */ + len = strnlen(str, len); + while (len && isspace(str[len - 1])) { + len--; + } + + /* strip leading whitespace */ + i = 0; + while (isspace(str[i]) && (i < len)) { + i++; + } + + j = 0; + while (i < len) { + /* substitute multiple whitespace with a single '_' */ + if (isspace(str[i])) { + while (isspace(str[i])) { + i++; + } + to[j++] = '_'; + } + to[j++] = str[i++]; + } + to[j] = '\0'; + return 0; } - -int vdev_whitelisted_char_for_devnode(char c, const char *white) { - if ((c >= '0' && c <= '9') || - (c >= 'A' && c <= 'Z') || - (c >= 'a' && c <= 'z') || - strchr("#+-.:=@_", c) != NULL || - (white != NULL && strchr(white, c) != NULL)) { - return 1; - } - return 0; +int vdev_whitelisted_char_for_devnode(char c, const char *white) +{ + if ((c >= '0' && c <= '9') || + (c >= 'A' && c <= 'Z') || + (c >= 'a' && c <= 'z') || + strchr("#+-.:=@_", c) != NULL || + (white != NULL && strchr(white, c) != NULL)) { + return 1; + } + return 0; } - -static inline bool vdev_is_unicode_valid(uint32_t ch) { - - if (ch >= 0x110000) { - /* End of unicode space */ - return false; - } - - if ((ch & 0xFFFFF800) == 0xD800) { - /* Reserved area for UTF-16 */ - return false; - } - if ((ch >= 0xFDD0) && (ch <= 0xFDEF)) { - /* Reserved */ - return false; - } - - if ((ch & 0xFFFE) == 0xFFFE) { - /* BOM (Byte Order Mark) */ - return false; - } - return true; +static inline bool vdev_is_unicode_valid(uint32_t ch) +{ + + if (ch >= 0x110000) { + /* End of unicode space */ + return false; + } + + if ((ch & 0xFFFFF800) == 0xD800) { + /* Reserved area for UTF-16 */ + return false; + } + if ((ch >= 0xFDD0) && (ch <= 0xFDEF)) { + /* Reserved */ + return false; + } + + if ((ch & 0xFFFE) == 0xFFFE) { + /* BOM (Byte Order Mark) */ + return false; + } + return true; } /* count of characters used to encode one unicode char */ -static int vdev_utf8_encoded_expected_len(const char *str) { - unsigned char c; - - c = (unsigned char) str[0]; - if (c < 0x80) { - return 1; - } - - if ((c & 0xe0) == 0xc0) { - return 2; - } - if ((c & 0xf0) == 0xe0) { - return 3; - } - if ((c & 0xf8) == 0xf0) { - return 4; - } - if ((c & 0xfc) == 0xf8) { - return 5; - } - if ((c & 0xfe) == 0xfc) { - return 6; - } - - return 0; +static int vdev_utf8_encoded_expected_len(const char *str) +{ + unsigned char c; + + c = (unsigned char)str[0]; + if (c < 0x80) { + return 1; + } + + if ((c & 0xe0) == 0xc0) { + return 2; + } + if ((c & 0xf0) == 0xe0) { + return 3; + } + if ((c & 0xf8) == 0xf0) { + return 4; + } + if ((c & 0xfc) == 0xf8) { + return 5; + } + if ((c & 0xfe) == 0xfc) { + return 6; + } + + return 0; } /* decode one unicode char */ -int vdev_utf8_encoded_to_unichar(const char *str) { - int unichar, len, i; - - len = vdev_utf8_encoded_expected_len(str); - - switch (len) { - case 1: - return (int)str[0]; - case 2: - unichar = str[0] & 0x1f; - break; - case 3: - unichar = (int)str[0] & 0x0f; - break; - case 4: - unichar = (int)str[0] & 0x07; - break; - case 5: - unichar = (int)str[0] & 0x03; - break; - case 6: - unichar = (int)str[0] & 0x01; - break; - default: - return -EINVAL; - } - - for (i = 1; i < len; i++) { - if (((int)str[i] & 0xc0) != 0x80) { - return -EINVAL; - } - unichar <<= 6; - unichar |= (int)str[i] & 0x3f; - } - - return unichar; +int vdev_utf8_encoded_to_unichar(const char *str) +{ + int unichar, len, i; + + len = vdev_utf8_encoded_expected_len(str); + + switch (len) { + case 1: + return (int)str[0]; + case 2: + unichar = str[0] & 0x1f; + break; + case 3: + unichar = (int)str[0] & 0x0f; + break; + case 4: + unichar = (int)str[0] & 0x07; + break; + case 5: + unichar = (int)str[0] & 0x03; + break; + case 6: + unichar = (int)str[0] & 0x01; + break; + default: + return -EINVAL; + } + + for (i = 1; i < len; i++) { + if (((int)str[i] & 0xc0) != 0x80) { + return -EINVAL; + } + unichar <<= 6; + unichar |= (int)str[i] & 0x3f; + } + + return unichar; } /* expected size used to encode one unicode char */ -static int vdev_utf8_unichar_to_encoded_len(int unichar) { - - if (unichar < 0x80) { - return 1; - } - if (unichar < 0x800) { - return 2; - } - if (unichar < 0x10000) { - return 3; - } - if (unichar < 0x200000) { - return 4; - } - if (unichar < 0x4000000) { - return 5; - } - - return 6; +static int vdev_utf8_unichar_to_encoded_len(int unichar) +{ + + if (unichar < 0x80) { + return 1; + } + if (unichar < 0x800) { + return 2; + } + if (unichar < 0x10000) { + return 3; + } + if (unichar < 0x200000) { + return 4; + } + if (unichar < 0x4000000) { + return 5; + } + + return 6; } /* validate one encoded unicode char and return its length */ -int vdev_utf8_encoded_valid_unichar(const char *str) { - int len, unichar, i; - - len = vdev_utf8_encoded_expected_len(str); - if (len == 0) { - return -EINVAL; - } - - /* ascii is valid */ - if (len == 1) { - return 1; - } - - /* check if expected encoded chars are available */ - for (i = 0; i < len; i++) { - if ((str[i] & 0x80) != 0x80) { - return -EINVAL; - } - } - - unichar = vdev_utf8_encoded_to_unichar(str); - - /* check if encoded length matches encoded value */ - if (vdev_utf8_unichar_to_encoded_len(unichar) != len) { - return -EINVAL; - } - - /* check if value has valid range */ - if (!vdev_is_unicode_valid(unichar)) { - return -EINVAL; - } - - return len; +int vdev_utf8_encoded_valid_unichar(const char *str) +{ + int len, unichar, i; + + len = vdev_utf8_encoded_expected_len(str); + if (len == 0) { + return -EINVAL; + } + + /* ascii is valid */ + if (len == 1) { + return 1; + } + + /* check if expected encoded chars are available */ + for (i = 0; i < len; i++) { + if ((str[i] & 0x80) != 0x80) { + return -EINVAL; + } + } + + unichar = vdev_utf8_encoded_to_unichar(str); + + /* check if encoded length matches encoded value */ + if (vdev_utf8_unichar_to_encoded_len(unichar) != len) { + return -EINVAL; + } + + /* check if value has valid range */ + if (!vdev_is_unicode_valid(unichar)) { + return -EINVAL; + } + + return len; } /* allow chars in whitelist, plain ascii, hex-escaping and valid utf8 */ -int vdev_util_replace_chars(char *str, const char *white) { - size_t i = 0; - int replaced = 0; - - while (str[i] != '\0') { - int len; - - if (vdev_whitelisted_char_for_devnode(str[i], white)) { - i++; - continue; - } - - /* accept hex encoding */ - if (str[i] == '\\' && str[i+1] == 'x') { - i += 2; - continue; - } - - /* accept valid utf8 */ - len = vdev_utf8_encoded_valid_unichar(&str[i]); - if (len > 1) { - i += len; - continue; - } - - /* if space is allowed, replace whitespace with ordinary space */ - if (isspace(str[i]) && white != NULL && strchr(white, ' ') != NULL) { - str[i] = ' '; - i++; - replaced++; - continue; - } - - /* everything else is replaced with '_' */ - str[i] = '_'; - i++; - replaced++; - } - return replaced; +int vdev_util_replace_chars(char *str, const char *white) +{ + size_t i = 0; + int replaced = 0; + + while (str[i] != '\0') { + int len; + + if (vdev_whitelisted_char_for_devnode(str[i], white)) { + i++; + continue; + } + + /* accept hex encoding */ + if (str[i] == '\\' && str[i + 1] == 'x') { + i += 2; + continue; + } + + /* accept valid utf8 */ + len = vdev_utf8_encoded_valid_unichar(&str[i]); + if (len > 1) { + i += len; + continue; + } + + /* if space is allowed, replace whitespace with ordinary space */ + if (isspace(str[i]) && white != NULL + && strchr(white, ' ') != NULL) { + str[i] = ' '; + i++; + replaced++; + continue; + } + + /* everything else is replaced with '_' */ + str[i] = '_'; + i++; + replaced++; + } + return replaced; } - /** * vdev_util_encode_string: * @str: input string to be encoded @@ -299,738 +305,770 @@ int vdev_util_replace_chars(char *str, const char *white) { * * Returns: 0 if the entire string was copied, non-zero otherwise. **/ -int vdev_util_encode_string(const char *str, char *str_enc, size_t len) { - - size_t i, j; - - if (str == NULL || str_enc == NULL) { - return -EINVAL; - } - - for (i = 0, j = 0; str[i] != '\0'; i++) { - int seqlen; - - seqlen = vdev_utf8_encoded_valid_unichar(&str[i]); - if (seqlen > 1) { - - if (len-j < (size_t)seqlen) { - goto err; - } - memcpy(&str_enc[j], &str[i], seqlen); - j += seqlen; - i += (seqlen-1); - } - else if (str[i] == '\\' || !vdev_whitelisted_char_for_devnode(str[i], NULL)) { - - if (len-j < 4) { - goto err; - } - sprintf(&str_enc[j], "\\x%02x", (unsigned char) str[i]); - j += 4; - } - else { - - if (len-j < 1) { - goto err; - } - - str_enc[j] = str[i]; - j++; - } - } - if (len-j < 1) { - goto err; - } - - str_enc[j] = '\0'; - return 0; -err: - return -EINVAL; +int vdev_util_encode_string(const char *str, char *str_enc, size_t len) +{ + + size_t i, j; + + if (str == NULL || str_enc == NULL) { + return -EINVAL; + } + + for (i = 0, j = 0; str[i] != '\0'; i++) { + int seqlen; + + seqlen = vdev_utf8_encoded_valid_unichar(&str[i]); + if (seqlen > 1) { + + if (len - j < (size_t) seqlen) { + goto err; + } + memcpy(&str_enc[j], &str[i], seqlen); + j += seqlen; + i += (seqlen - 1); + } else if (str[i] == '\\' + || !vdev_whitelisted_char_for_devnode(str[i], + NULL)) { + + if (len - j < 4) { + goto err; + } + sprintf(&str_enc[j], "\\x%02x", (unsigned char)str[i]); + j += 4; + } else { + + if (len - j < 1) { + goto err; + } + + str_enc[j] = str[i]; + j++; + } + } + if (len - j < 1) { + goto err; + } + + str_enc[j] = '\0'; + return 0; + err: + return -EINVAL; } // remove trailing whitespace -int vdev_util_rstrip( char* str ) { - - size_t i = strlen(str); - - if( i == 0 ) { - return 0; - } - - i--; - - while( i >= 0 ) { - - if( isspace(str[i]) ) { - str[i] = 0; - i--; - continue; - } - else { - // not space - break; - } - } - - return 0; +int vdev_util_rstrip(char *str) +{ + + size_t i = strlen(str); + + if (i == 0) { + return 0; + } + + i--; + + while (i >= 0) { + + if (isspace(str[i])) { + str[i] = 0; + i--; + continue; + } else { + // not space + break; + } + } + + return 0; } // global list of properties discovered -static struct vdev_property* vdev_property_head = NULL; -static struct vdev_property* vdev_property_tail = NULL; +static struct vdev_property *vdev_property_head = NULL; +static struct vdev_property *vdev_property_tail = NULL; // append to a linked list of properties discovered // return 0 on success // return -ENOMEM if we run out of memory -int vdev_property_add( char const* name, char const* value ) { - - struct vdev_property* prop = (struct vdev_property*)calloc( sizeof(struct vdev_property), 1 ); - - if( prop == NULL ) { - return -ENOMEM; - } - - prop->name = strdup( name ); - if( prop->name == NULL ) { - - free( prop ); - return -ENOMEM; - } - - prop->value = strdup( value ); - if( prop->value == NULL ) { - - free( prop->name ); - free( prop ); - return -ENOMEM; - } - - prop->next = NULL; - - if( vdev_property_head == NULL ) { - vdev_property_head = prop; - vdev_property_tail = prop; - } - - else { - vdev_property_tail->next = prop; - vdev_property_tail = prop; - } - - return 0; +int vdev_property_add(char const *name, char const *value) +{ + + struct vdev_property *prop = + (struct vdev_property *)calloc(sizeof(struct vdev_property), 1); + + if (prop == NULL) { + return -ENOMEM; + } + + prop->name = strdup(name); + if (prop->name == NULL) { + + free(prop); + return -ENOMEM; + } + + prop->value = strdup(value); + if (prop->value == NULL) { + + free(prop->name); + free(prop); + return -ENOMEM; + } + + prop->next = NULL; + + if (vdev_property_head == NULL) { + vdev_property_head = prop; + vdev_property_tail = prop; + } + + else { + vdev_property_tail->next = prop; + vdev_property_tail = prop; + } + + return 0; } // print all properties as sourceable environmet variables // always succeeds -int vdev_property_print( void ) { - - if( vdev_property_head != NULL ) { - - for( struct vdev_property* itr = vdev_property_head; itr != NULL; itr = itr->next ) { - printf("%s='%s'\n", itr->name, itr->value ); - } - - // print the variable VDEV_PROPERTIES to include all property names - printf("VDEV_PROPERTIES=\""); - for( struct vdev_property* itr = vdev_property_head; itr != NULL; itr = itr->next ) { - printf("%s ", itr->name ); - } - printf("\"\n"); - } - - return 0; +int vdev_property_print(void) +{ + + if (vdev_property_head != NULL) { + + for (struct vdev_property * itr = vdev_property_head; + itr != NULL; itr = itr->next) { + printf("%s='%s'\n", itr->name, itr->value); + } + + // print the variable VDEV_PROPERTIES to include all property names + printf("VDEV_PROPERTIES=\""); + for (struct vdev_property * itr = vdev_property_head; + itr != NULL; itr = itr->next) { + printf("%s ", itr->name); + } + printf("\"\n"); + } + + return 0; } - // free all properties // always succeeds -int vdev_property_free_all( void ) { - - if( vdev_property_head != NULL ) { - - for( struct vdev_property* itr = vdev_property_head; itr != NULL; ) { - - struct vdev_property* itr_next = itr->next; - - free( itr->name ); - free( itr->value ); - free( itr ); - - itr = itr_next; - } - } - - vdev_property_head = NULL; - vdev_property_tail = NULL; - - return 0; -} +int vdev_property_free_all(void) +{ + + if (vdev_property_head != NULL) { + + for (struct vdev_property * itr = vdev_property_head; + itr != NULL;) { + struct vdev_property *itr_next = itr->next; + + free(itr->name); + free(itr->value); + free(itr); + + itr = itr_next; + } + } + + vdev_property_head = NULL; + vdev_property_tail = NULL; + + return 0; +} // read a file, masking EINTR // return the number of bytes read on success // return -errno on failure -ssize_t vdev_read_uninterrupted( int fd, char* buf, size_t len ) { - - ssize_t num_read = 0; - - if( buf == NULL ) { - return -EINVAL; - } - - while( (unsigned)num_read < len ) { - ssize_t nr = read( fd, buf + num_read, len - num_read ); - if( nr < 0 ) { - - int errsv = -errno; - if( errsv == -EINTR ) { - continue; - } - - return errsv; - } - if( nr == 0 ) { - break; - } - - num_read += nr; - } - - return num_read; -} +ssize_t vdev_read_uninterrupted(int fd, char *buf, size_t len) +{ + ssize_t num_read = 0; + if (buf == NULL) { + return -EINVAL; + } -// read a sysfs attribute -int vdev_sysfs_read_attr( char const* sysfs_device_path, char const* attr_name, char** value, size_t* value_len ) { - - int rc = 0; - int fd = 0; - struct stat sb; - char attr_path[4097]; - - sprintf(attr_path, "%s/%s", sysfs_device_path, attr_name ); - - rc = stat( attr_path, &sb ); - if( rc != 0 ) { - - rc = -errno; - return rc; - } - - // regular file? return the contents - if( S_ISREG( sb.st_mode ) ) { - - fd = open( attr_path, O_RDONLY ); - if( fd < 0 ) { - - rc = -errno; - - fprintf(stderr, "[WARN]: open('%s') errno = %d\n", attr_path, rc ); - return rc; - } - - char* ret_value = (char*)calloc( sb.st_size + 1, 1 ); - if( ret_value == NULL ) { - - close( fd ); - return -ENOMEM; - } - - rc = vdev_read_uninterrupted( fd, ret_value, sb.st_size ); - if( rc < 0 ) { - - free( ret_value ); - close( fd ); - return rc; - } - - close( fd ); - - *value = ret_value; - *value_len = sb.st_size; - - return 0; - } - - // symlink? return the actual link - else if( S_ISLNK( sb.st_mode ) ) { - - char* ret_value = (char*)calloc( sb.st_size + 1, 1 ); - if( ret_value == NULL ) { - - return -ENOMEM; - } - - rc = readlink( attr_path, ret_value, sb.st_size ); - if( rc < 0 ) { - - rc = -errno; - fprintf(stderr, "[WARN]: readlink('%s') errno = %d\n", attr_path, rc ); - - free( ret_value ); - return rc; - } - - *value = ret_value; - *value_len = sb.st_size + 1; - - return 0; - } - - // not sure what to do here - else { - - return -EINVAL; - } + while ((unsigned)num_read < len) { + ssize_t nr = read(fd, buf + num_read, len - num_read); + if (nr < 0) { + + int errsv = -errno; + if (errsv == -EINTR) { + continue; + } + + return errsv; + } + if (nr == 0) { + break; + } + + num_read += nr; + } + + return num_read; } +// read a sysfs attribute +int vdev_sysfs_read_attr(char const *sysfs_device_path, char const *attr_name, + char **value, size_t * value_len) +{ + + int rc = 0; + int fd = 0; + struct stat sb; + char attr_path[4097]; + + sprintf(attr_path, "%s/%s", sysfs_device_path, attr_name); + + rc = stat(attr_path, &sb); + if (rc != 0) { + + rc = -errno; + return rc; + } + // regular file? return the contents + if (S_ISREG(sb.st_mode)) { + + fd = open(attr_path, O_RDONLY); + if (fd < 0) { + + rc = -errno; + + fprintf(stderr, "[WARN]: open('%s') errno = %d\n", + attr_path, rc); + return rc; + } + + char *ret_value = (char *)calloc(sb.st_size + 1, 1); + if (ret_value == NULL) { + + close(fd); + return -ENOMEM; + } + + rc = vdev_read_uninterrupted(fd, ret_value, sb.st_size); + if (rc < 0) { + + free(ret_value); + close(fd); + return rc; + } + + close(fd); + + *value = ret_value; + *value_len = sb.st_size; + + return 0; + } + // symlink? return the actual link + else if (S_ISLNK(sb.st_mode)) { + + char *ret_value = (char *)calloc(sb.st_size + 1, 1); + if (ret_value == NULL) { + + return -ENOMEM; + } + + rc = readlink(attr_path, ret_value, sb.st_size); + if (rc < 0) { + + rc = -errno; + fprintf(stderr, "[WARN]: readlink('%s') errno = %d\n", + attr_path, rc); + + free(ret_value); + return rc; + } + + *value = ret_value; + *value_len = sb.st_size + 1; + + return 0; + } + // not sure what to do here + else { + + return -EINVAL; + } +} // find a field value from a uevent // return 0 on success // return -ENOENT if the key is not found // return -ENOMEM if oom. -int vdev_sysfs_uevent_get_key( char const* uevent_buf, size_t uevent_buflen, char const* key, char** value, size_t* value_len ) { - - char* tmp = NULL; - char* tok = NULL; - char* buf_ptr = NULL; - char* delim = NULL; - int rc = 0; - - // NOTE: zero-terminate - char* buf_dup = (char*)calloc( uevent_buflen + 1, 1 ); - if( buf_dup == NULL ) { - return -ENOMEM; - } - - memcpy( buf_dup, uevent_buf, uevent_buflen ); - buf_ptr = buf_dup; - - while( 1 ) { - - // next line - tok = strtok_r( buf_ptr, "\n", &tmp ); - buf_ptr = NULL; - - if( tok == NULL ) { - rc = -ENOENT; - break; - } - - // read key - delim = index( tok, '=' ); - if( delim == NULL ) { - continue; - } - - *delim = '\0'; - - // match key? - if( strcmp( tok, key ) == 0 ) { - - // get value - *value_len = strlen( delim + 1 ); - *value = (char*)calloc( *value_len + 1, 1 ); - - if( *value == NULL ) { - rc = -ENOMEM; - break; - } - - strcpy( *value, delim + 1 ); - break; - } - - *delim = '='; - } - - free( buf_dup ); - return rc; +int vdev_sysfs_uevent_get_key(char const *uevent_buf, size_t uevent_buflen, + char const *key, char **value, size_t * value_len) +{ + + char *tmp = NULL; + char *tok = NULL; + char *buf_ptr = NULL; + char *delim = NULL; + int rc = 0; + + // NOTE: zero-terminate + char *buf_dup = (char *)calloc(uevent_buflen + 1, 1); + if (buf_dup == NULL) { + return -ENOMEM; + } + + memcpy(buf_dup, uevent_buf, uevent_buflen); + buf_ptr = buf_dup; + + while (1) { + + // next line + tok = strtok_r(buf_ptr, "\n", &tmp); + buf_ptr = NULL; + + if (tok == NULL) { + rc = -ENOENT; + break; + } + // read key + delim = index(tok, '='); + if (delim == NULL) { + continue; + } + + *delim = '\0'; + + // match key? + if (strcmp(tok, key) == 0) { + + // get value + *value_len = strlen(delim + 1); + *value = (char *)calloc(*value_len + 1, 1); + + if (*value == NULL) { + rc = -ENOMEM; + break; + } + + strcpy(*value, delim + 1); + break; + } + + *delim = '='; + } + + free(buf_dup); + return rc; } // read a whole file into RAM // return 0 on success, and set *file_buf and *file_buf_len // return negative on error -int vdev_read_file( char const* path, char** file_buf, size_t* file_buf_len ) { - - int fd = 0; - struct stat sb; - char* buf = NULL; - int rc = 0; - - // get size - rc = stat( path, &sb ); - if( rc != 0 ) { - - rc = -errno; - return rc; - } - - // read the uevent file itself - buf = (char*)calloc( sb.st_size, 1 ); - if( buf == NULL ) { - - return -ENOMEM; - } - - fd = open( path, O_RDONLY ); - if( fd < 0 ) { - - rc = -errno; - free( buf ); - return rc; - } - - rc = vdev_read_uninterrupted( fd, buf, sb.st_size ); - if( rc < 0 ) { - - close( fd ); - free( buf ); - return rc; - } - - close( fd ); - - *file_buf = buf; - *file_buf_len = rc; - - return 0; -} +int vdev_read_file(char const *path, char **file_buf, size_t * file_buf_len) +{ + + int fd = 0; + struct stat sb; + char *buf = NULL; + int rc = 0; + + // get size + rc = stat(path, &sb); + if (rc != 0) { + + rc = -errno; + return rc; + } + // read the uevent file itself + buf = (char *)calloc(sb.st_size, 1); + if (buf == NULL) { + + return -ENOMEM; + } + + fd = open(path, O_RDONLY); + if (fd < 0) { + rc = -errno; + free(buf); + return rc; + } + + rc = vdev_read_uninterrupted(fd, buf, sb.st_size); + if (rc < 0) { + + close(fd); + free(buf); + return rc; + } + + close(fd); + + *file_buf = buf; + *file_buf_len = rc; + + return 0; +} // find a field in the uevent buffer, using vdev_read_file and vdev_sysfs_uevent_get_key // return 0 on success, and set *value and *value_len // return negative on error -int vdev_sysfs_uevent_read_key( char const* sysfs_device_path, char const* uevent_key, char** uevent_value, size_t* uevent_value_len ) { - - int rc = 0; - - char* uevent_buf = NULL; - size_t uevent_len = 0; - - char* uevent_path = (char*)calloc( strlen(sysfs_device_path) + strlen("/uevent") + 1, 1 ); - if( uevent_path == NULL ) { - - return -ENOMEM; - } - - sprintf( uevent_path, "%s/uevent", sysfs_device_path ); - - // get uevent - rc = vdev_read_file( uevent_path, &uevent_buf, &uevent_len ); - if( rc < 0 ) { - - if( DEBUG ) { - fprintf(stderr, "[WARN]: vdev_read_file('%s') rc = %d\n", uevent_path, rc ); - } - return rc; - } - - // get devtype - rc = vdev_sysfs_uevent_get_key( uevent_buf, uevent_len, uevent_key, uevent_value, uevent_value_len ); - - free( uevent_buf ); - free( uevent_path ); - - return rc; -} +int vdev_sysfs_uevent_read_key(char const *sysfs_device_path, + char const *uevent_key, char **uevent_value, + size_t * uevent_value_len) +{ + + int rc = 0; + + char *uevent_buf = NULL; + size_t uevent_len = 0; + + char *uevent_path = + (char *)calloc(strlen(sysfs_device_path) + strlen("/uevent") + 1, + 1); + if (uevent_path == NULL) { + + return -ENOMEM; + } + sprintf(uevent_path, "%s/uevent", sysfs_device_path); + + // get uevent + rc = vdev_read_file(uevent_path, &uevent_buf, &uevent_len); + if (rc < 0) { + + if (DEBUG) { + fprintf(stderr, + "[WARN]: vdev_read_file('%s') rc = %d\n", + uevent_path, rc); + } + return rc; + } + // get devtype + rc = vdev_sysfs_uevent_get_key(uevent_buf, uevent_len, uevent_key, + uevent_value, uevent_value_len); + + free(uevent_buf); + free(uevent_path); + + return rc; +} // walk up a sysfs device path to find the ancestor device with the given subsystem and devtype // if devtype_name is NULL, match any devtype (only match the subsystem) // return 0 on success // return -ENOMEM on OOM // return -ENOENT if a subsystem or uevent was not found, when one was expected -int vdev_sysfs_get_parent_with_subsystem_devtype( char const* sysfs_device_path, char const* subsystem_name, char const* devtype_name, char** devpath, size_t* devpath_len ) { - - char cur_dir[4097]; - char subsystem_path[4097]; - char subsystem_link[4097]; - char uevent_path[4097]; - - memset( subsystem_path, 0, 4097 ); - memset( subsystem_link, 0, 4097 ); - - char* tmp = NULL; - int rc = 0; - char* uevent_buf = NULL; - size_t uevent_len = 0; - char* devtype = NULL; - size_t devtype_len = 0; - char* parent_device = NULL; - size_t parent_device_len = 0; - - strcpy( cur_dir, sysfs_device_path ); - - while( 1 ) { - - // get parent device - rc = vdev_sysfs_get_parent_device( cur_dir, &parent_device, &parent_device_len ); - if( rc != 0 ) { - break; - } - - // subsystem? - sprintf( subsystem_path, "%s/subsystem", parent_device ); - - memset( subsystem_link, 0, 4096 ); - - rc = readlink( subsystem_path, subsystem_link, 4096 ); - if( rc < 0 ) { - - rc = -errno; - if( rc != -ENOENT ) { - fprintf(stderr, "[WARN]: readlink('%s') errno = %d\n", subsystem_path, rc ); - } - - free( parent_device ); - parent_device = NULL; - return rc; - } - - // get subsystem name... - tmp = rindex( subsystem_link, '/' ); - - if( tmp != NULL && strcmp( tmp + 1, subsystem_name ) != 0 ) { - - // subsystem does not match - // crawl up to the parent - strcpy( cur_dir, parent_device ); - - free( parent_device ); - parent_device = NULL; - continue; - } - - // subsystem matches... - *tmp = 0; - - if( devtype_name != NULL ) { - - // get uevent - // get DEVTYPE from uevent - // make uevent path - sprintf( uevent_path, "%s/uevent", parent_device ); - - // get uevent - rc = vdev_read_file( uevent_path, &uevent_buf, &uevent_len ); - if( rc < 0 ) { - - fprintf(stderr, "[WARN]: vdev_read_file('%s') rc = %d\n", uevent_path, rc ); - - free( parent_device ); - parent_device = NULL; - return rc; - } - - // get devtype - rc = vdev_sysfs_uevent_get_key( uevent_buf, uevent_len, "DEVTYPE", &devtype, &devtype_len ); - free( uevent_buf ); - - if( rc != 0 ) { - - if( rc == -ENOENT ) { - - // not found - // next parent - strcpy( cur_dir, parent_device ); - - free( parent_device ); - parent_device = NULL; - - continue; - } - else { - - free( parent_device ); - parent_device = NULL; - - return rc; - } - } - - // matches? - if( strcmp( devtype, devtype_name ) == 0 ) { - - free( devtype ); - - // this is the path to the device - *devpath = parent_device; - *devpath_len = strlen( parent_device ); - - // found! - rc = 0; - break; - } - else { - // no match. - // next device - free( devtype ); - - strcpy( cur_dir, parent_device ); - - free( parent_device ); - parent_device = NULL; - continue; - } - } - else { - - // match only on subsystem - *devpath = parent_device; - *devpath_len = strlen(parent_device); - - rc = 0; - break; - } - } - - return rc; +int vdev_sysfs_get_parent_with_subsystem_devtype(char const *sysfs_device_path, + char const *subsystem_name, + char const *devtype_name, + char **devpath, + size_t * devpath_len) +{ + + char cur_dir[4097]; + char subsystem_path[4097]; + char subsystem_link[4097]; + char uevent_path[4097]; + + memset(subsystem_path, 0, 4097); + memset(subsystem_link, 0, 4097); + + char *tmp = NULL; + int rc = 0; + char *uevent_buf = NULL; + size_t uevent_len = 0; + char *devtype = NULL; + size_t devtype_len = 0; + char *parent_device = NULL; + size_t parent_device_len = 0; + + strcpy(cur_dir, sysfs_device_path); + + while (1) { + + // get parent device + rc = vdev_sysfs_get_parent_device(cur_dir, &parent_device, + &parent_device_len); + if (rc != 0) { + break; + } + // subsystem? + sprintf(subsystem_path, "%s/subsystem", parent_device); + + memset(subsystem_link, 0, 4096); + + rc = readlink(subsystem_path, subsystem_link, 4096); + if (rc < 0) { + + rc = -errno; + if (rc != -ENOENT) { + fprintf(stderr, + "[WARN]: readlink('%s') errno = %d\n", + subsystem_path, rc); + } + + free(parent_device); + parent_device = NULL; + return rc; + } + // get subsystem name... + tmp = rindex(subsystem_link, '/'); + + if (tmp != NULL && strcmp(tmp + 1, subsystem_name) != 0) { + + // subsystem does not match + // crawl up to the parent + strcpy(cur_dir, parent_device); + + free(parent_device); + parent_device = NULL; + continue; + } + // subsystem matches... + *tmp = 0; + + if (devtype_name != NULL) { + + // get uevent + // get DEVTYPE from uevent + // make uevent path + sprintf(uevent_path, "%s/uevent", parent_device); + + // get uevent + rc = vdev_read_file(uevent_path, &uevent_buf, + &uevent_len); + if (rc < 0) { + + fprintf(stderr, + "[WARN]: vdev_read_file('%s') rc = %d\n", + uevent_path, rc); + + free(parent_device); + parent_device = NULL; + return rc; + } + // get devtype + rc = vdev_sysfs_uevent_get_key(uevent_buf, uevent_len, + "DEVTYPE", &devtype, + &devtype_len); + free(uevent_buf); + + if (rc != 0) { + + if (rc == -ENOENT) { + + // not found + // next parent + strcpy(cur_dir, parent_device); + + free(parent_device); + parent_device = NULL; + + continue; + } else { + + free(parent_device); + parent_device = NULL; + + return rc; + } + } + // matches? + if (strcmp(devtype, devtype_name) == 0) { + + free(devtype); + + // this is the path to the device + *devpath = parent_device; + *devpath_len = strlen(parent_device); + + // found! + rc = 0; + break; + } else { + // no match. + // next device + free(devtype); + + strcpy(cur_dir, parent_device); + + free(parent_device); + parent_device = NULL; + continue; + } + } else { + + // match only on subsystem + *devpath = parent_device; + *devpath_len = strlen(parent_device); + + rc = 0; + break; + } + } + + return rc; } - // make a device path using the symlink in the contained 'device' entry -int vdev_sysfs_read_device_path( char const* sysfs_dir, char** devpath, size_t* devpath_len ) { - - int rc = 0; - struct stat sb; - - char path_buf[8193]; - - sprintf( path_buf, "%s/device", sysfs_dir ); - - // is there a link here? - rc = stat( path_buf, &sb ); - if( rc != 0 ) { - - rc = -errno; - return rc; - } - - // must be a link - if( !S_ISLNK( sb.st_mode ) ) { - - rc = -EINVAL; - return rc; - } - - // follow that link! - *devpath = realpath( path_buf, NULL ); - if( *devpath == NULL ) { - return -ENOMEM; - } - - *devpath_len = strlen(*devpath); - - return 0; -} +int vdev_sysfs_read_device_path(char const *sysfs_dir, char **devpath, + size_t * devpath_len) +{ + + int rc = 0; + struct stat sb; + + char path_buf[8193]; + + sprintf(path_buf, "%s/device", sysfs_dir); + + // is there a link here? + rc = stat(path_buf, &sb); + if (rc != 0) { + rc = -errno; + return rc; + } + // must be a link + if (!S_ISLNK(sb.st_mode)) { + + rc = -EINVAL; + return rc; + } + // follow that link! + *devpath = realpath(path_buf, NULL); + if (*devpath == NULL) { + return -ENOMEM; + } + + *devpath_len = strlen(*devpath); + + return 0; +} // search sysfs for the device path corresponding to a given subsystem and sysname. // fill in devpath if found. // heavily inspired by udev_device_new_from_subsystem_sysname -int vdev_sysfs_device_path_from_subsystem_sysname( char const* sysfs_mount, char const* subsystem, char const* sysname, char** devpath, size_t* devpath_len ) { - - int rc = 0; - struct stat sb; - char path_buf[8193]; - - memset( path_buf, 0, 8193 ); - - if( strcmp( subsystem, "subsystem" ) == 0 ) { - - sprintf( path_buf, "%s/subsystem/%s/", sysfs_mount, sysname ); - rc = stat( path_buf, &sb ); - - if( rc == 0 ) { - return vdev_sysfs_read_device_path( path_buf, devpath, devpath_len ); - } - - sprintf(path_buf, "%s/bus/%s/", sysfs_mount, sysname ); - rc = stat( path_buf, &sb ); - - if( rc == 0 ) { - return vdev_sysfs_read_device_path( path_buf, devpath, devpath_len ); - } - - sprintf(path_buf, "%s/class/%s/", sysfs_mount, sysname ); - rc = stat( path_buf, &sb ); - - if( rc == 0 ) { - return vdev_sysfs_read_device_path( path_buf, devpath, devpath_len ); - } - } - - if( strcmp( subsystem, "module" ) == 0 ) { - - sprintf( path_buf, "%s/module/%s/", sysfs_mount, sysname ); - rc = stat( path_buf, &sb ); - - if( rc == 0 ) { - return vdev_sysfs_read_device_path( path_buf, devpath, devpath_len ); - } - } - - if( strcmp( subsystem, "drivers" ) == 0 ) { - - char driver_prefix[4096]; - char* driver = NULL; - - sprintf( driver_prefix, sysname ); - driver = strchr( driver_prefix, ':' ); - - if( driver != NULL ) { - - // trim header - *driver = '\0'; - driver++; - - sprintf( path_buf, "%s/subsystem/%s/drivers/%s/", sysfs_mount, driver_prefix, driver ); - rc = stat( path_buf, &sb ); - - if( rc == 0 ) { - return vdev_sysfs_read_device_path( path_buf, devpath, devpath_len ); - } - - sprintf( path_buf, "%s/bus/%s/drivers/%s/", sysfs_mount, driver_prefix, driver ); - rc = stat( path_buf, &sb ); - - if( rc == 0 ) { - return vdev_sysfs_read_device_path( path_buf, devpath, devpath_len ); - } - } - else { - - return -EINVAL; - } - } - - sprintf( path_buf, "%s/subsystem/%s/devices/%s/", sysfs_mount, subsystem, sysname ); - rc = stat( path_buf, &sb ); - - if( rc == 0 ) { - return vdev_sysfs_read_device_path( path_buf, devpath, devpath_len ); - } - - sprintf( path_buf, "%s/bus/%s/devices/%s/", sysfs_mount, subsystem, sysname ); - rc = stat( path_buf, &sb ); - - if( rc == 0 ) { - return vdev_sysfs_read_device_path( path_buf, devpath, devpath_len ); - } - - sprintf( path_buf, "%s/class/%s/%s", sysfs_mount, subsystem, sysname ); - rc = stat( path_buf, &sb ); - - if( rc == 0 ) { - - return vdev_sysfs_read_device_path( path_buf, devpath, devpath_len ); - } - - return -ENOENT; -} +int vdev_sysfs_device_path_from_subsystem_sysname(char const *sysfs_mount, + char const *subsystem, + char const *sysname, + char **devpath, + size_t * devpath_len) +{ + int rc = 0; + struct stat sb; + char path_buf[8193]; + + memset(path_buf, 0, 8193); + + if (strcmp(subsystem, "subsystem") == 0) { + + sprintf(path_buf, "%s/subsystem/%s/", sysfs_mount, sysname); + rc = stat(path_buf, &sb); + + if (rc == 0) { + return vdev_sysfs_read_device_path(path_buf, devpath, + devpath_len); + } + + sprintf(path_buf, "%s/bus/%s/", sysfs_mount, sysname); + rc = stat(path_buf, &sb); + + if (rc == 0) { + return vdev_sysfs_read_device_path(path_buf, devpath, + devpath_len); + } + + sprintf(path_buf, "%s/class/%s/", sysfs_mount, sysname); + rc = stat(path_buf, &sb); + + if (rc == 0) { + return vdev_sysfs_read_device_path(path_buf, devpath, + devpath_len); + } + } + + if (strcmp(subsystem, "module") == 0) { + + sprintf(path_buf, "%s/module/%s/", sysfs_mount, sysname); + rc = stat(path_buf, &sb); + + if (rc == 0) { + return vdev_sysfs_read_device_path(path_buf, devpath, + devpath_len); + } + } + + if (strcmp(subsystem, "drivers") == 0) { + + char driver_prefix[4096]; + char *driver = NULL; + + sprintf(driver_prefix, sysname); + driver = strchr(driver_prefix, ':'); + + if (driver != NULL) { + + // trim header + *driver = '\0'; + driver++; + + sprintf(path_buf, "%s/subsystem/%s/drivers/%s/", + sysfs_mount, driver_prefix, driver); + rc = stat(path_buf, &sb); + + if (rc == 0) { + return vdev_sysfs_read_device_path(path_buf, + devpath, + devpath_len); + } + + sprintf(path_buf, "%s/bus/%s/drivers/%s/", sysfs_mount, + driver_prefix, driver); + rc = stat(path_buf, &sb); + + if (rc == 0) { + return vdev_sysfs_read_device_path(path_buf, + devpath, + devpath_len); + } + } else { + + return -EINVAL; + } + } + + sprintf(path_buf, "%s/subsystem/%s/devices/%s/", sysfs_mount, subsystem, + sysname); + rc = stat(path_buf, &sb); + + if (rc == 0) { + return vdev_sysfs_read_device_path(path_buf, devpath, + devpath_len); + } + + sprintf(path_buf, "%s/bus/%s/devices/%s/", sysfs_mount, subsystem, + sysname); + rc = stat(path_buf, &sb); + + if (rc == 0) { + return vdev_sysfs_read_device_path(path_buf, devpath, + devpath_len); + } + + sprintf(path_buf, "%s/class/%s/%s", sysfs_mount, subsystem, sysname); + rc = stat(path_buf, &sb); + + if (rc == 0) { + + return vdev_sysfs_read_device_path(path_buf, devpath, + devpath_len); + } + + return -ENOENT; +} // get the parent device of a given device, using sysfs. // not all devices have parents; those that do will have a uevent file. @@ -1040,237 +1078,242 @@ int vdev_sysfs_device_path_from_subsystem_sysname( char const* sysfs_mount, char // return -ENOENT if this dev has no parent // return -errno if stat'ing the parent path fails // return -ENOMEM if OOM -int vdev_sysfs_get_parent_device( char const* dev_path, char** ret_parent_device, size_t* ret_parent_device_len ) { - - char* parent_path = NULL; - size_t parent_path_len = 0; - struct stat sb; - int rc = 0; - - char* delim = NULL; - - parent_path = (char*)calloc( strlen(dev_path) + 1 + strlen("/uevent"), 1 ); - if( parent_path == NULL ) { - return -ENOMEM; - } - - strcpy( parent_path, dev_path ); - - while( strlen(parent_path) > 0 ) { - - // lop off the child - delim = rindex( parent_path, '/' ); - if( delim == NULL ) { - - // invalid - free( parent_path ); - return -EINVAL; - } - - if( delim == parent_path ) { - - // reached / - free( parent_path ); - return -ENOENT; - } - - while( *delim == '/' && delim != parent_path ) { - *delim = '\0'; - delim--; - } - - parent_path_len = strlen( parent_path ); - - // verify that this is a device... - strcat( parent_path, "/uevent" ); - - rc = stat( parent_path, &sb ); - if( rc != 0 ) { - - // not a device - // remove /uevent - parent_path[ parent_path_len ] = '\0'; - continue; - } - else { - - // device! - break; - } - } - - // lop off /uevent - parent_path[ parent_path_len ] = '\0'; - - *ret_parent_device = parent_path; - *ret_parent_device_len = parent_path_len; - - return 0; +int vdev_sysfs_get_parent_device(char const *dev_path, char **ret_parent_device, + size_t * ret_parent_device_len) +{ + + char *parent_path = NULL; + size_t parent_path_len = 0; + struct stat sb; + int rc = 0; + + char *delim = NULL; + + parent_path = + (char *)calloc(strlen(dev_path) + 1 + strlen("/uevent"), 1); + if (parent_path == NULL) { + return -ENOMEM; + } + + strcpy(parent_path, dev_path); + + while (strlen(parent_path) > 0) { + + // lop off the child + delim = rindex(parent_path, '/'); + if (delim == NULL) { + + // invalid + free(parent_path); + return -EINVAL; + } + + if (delim == parent_path) { + + // reached / + free(parent_path); + return -ENOENT; + } + + while (*delim == '/' && delim != parent_path) { + *delim = '\0'; + delim--; + } + + parent_path_len = strlen(parent_path); + + // verify that this is a device... + strcat(parent_path, "/uevent"); + + rc = stat(parent_path, &sb); + if (rc != 0) { + + // not a device + // remove /uevent + parent_path[parent_path_len] = '\0'; + continue; + } else { + + // device! + break; + } + } + + // lop off /uevent + parent_path[parent_path_len] = '\0'; + + *ret_parent_device = parent_path; + *ret_parent_device_len = parent_path_len; + + return 0; } // get the subsystem from a device path -int vdev_sysfs_read_subsystem( char const* devpath, char** ret_subsystem, size_t* ret_subsystem_len ) { - - int rc = 0; - char linkpath[ 4097 ]; - size_t linkpath_len = 4097; - char* subsystem_path = NULL; - char* subsystem = NULL; - - subsystem_path = (char*)calloc( strlen(devpath) + 1 + strlen("/subsystem") + 1, 1 ); - if( subsystem_path == NULL ) { - return -ENOMEM; - } - - sprintf( subsystem_path, "%s/subsystem", devpath ); - - memset( linkpath, 0, 4097 ); - - rc = readlink( subsystem_path, linkpath, linkpath_len ); - if( rc < 0 ) { - - rc = -errno; - log_error("readlink('%s') rc = %d\n", subsystem_path, rc ); - free( subsystem_path ); - return rc; - } - - free( subsystem_path ); - - subsystem = rindex( linkpath, '/' ); - if( subsystem == NULL ) { - return -EINVAL; - } - - *ret_subsystem = strdup( subsystem + 1 ); - *ret_subsystem_len = strlen( subsystem + 1 ); - - if( *ret_subsystem == NULL ) { - return -ENOMEM; - } - - return 0; -} +int vdev_sysfs_read_subsystem(char const *devpath, char **ret_subsystem, + size_t * ret_subsystem_len) +{ + int rc = 0; + char linkpath[4097]; + size_t linkpath_len = 4097; + char *subsystem_path = NULL; + char *subsystem = NULL; -// get the sysname from the device path -int vdev_sysfs_get_sysname( char const* devpath, char** ret_sysname, size_t* ret_sysname_len ) { - - char const* delim = NULL; - char* sysname = NULL; - size_t len = 0; - - delim = rindex( devpath, '/' ); - if( delim == NULL ) { - - return -EINVAL; - } - - sysname = strdup( delim + 1 ); - - if( sysname == NULL ) { - return -ENOMEM; - } - - /* some devices have '!' in their name, change that to '/' */ - while( sysname[len] != '\0' ) { - - if( sysname[len] == '!' ) { - sysname[len] = '/'; - } - - len++; - } - - *ret_sysname = sysname; - *ret_sysname_len = len; - - return 0; + subsystem_path = + (char *)calloc(strlen(devpath) + 1 + strlen("/subsystem") + 1, 1); + if (subsystem_path == NULL) { + return -ENOMEM; + } + + sprintf(subsystem_path, "%s/subsystem", devpath); + + memset(linkpath, 0, 4097); + + rc = readlink(subsystem_path, linkpath, linkpath_len); + if (rc < 0) { + + rc = -errno; + log_error("readlink('%s') rc = %d\n", subsystem_path, rc); + free(subsystem_path); + return rc; + } + + free(subsystem_path); + + subsystem = rindex(linkpath, '/'); + if (subsystem == NULL) { + return -EINVAL; + } + + *ret_subsystem = strdup(subsystem + 1); + *ret_subsystem_len = strlen(subsystem + 1); + + if (*ret_subsystem == NULL) { + return -ENOMEM; + } + + return 0; } +// get the sysname from the device path +int vdev_sysfs_get_sysname(char const *devpath, char **ret_sysname, + size_t * ret_sysname_len) +{ -// get the sysnum of a device from the device path -int vdev_sysfs_get_sysnum( char const* devpath, int* sysnum ) { - - int rc = 0; - char* sysname = NULL; - size_t sysname_len = 0; - int i = 0; - - // last digits at the end of the sysname - rc = vdev_sysfs_get_sysname( devpath, &sysname, &sysname_len ); - if( rc != 0 ) { - return rc; - } - - while( isdigit( sysname[ sysname_len - i ] ) ) { - i++; - } - i++; - - *sysnum = strtol( sysname + sysname_len - i, NULL, 10 ); - - free( sysname ); - - return 0; + char const *delim = NULL; + char *sysname = NULL; + size_t len = 0; + + delim = rindex(devpath, '/'); + if (delim == NULL) { + + return -EINVAL; + } + + sysname = strdup(delim + 1); + + if (sysname == NULL) { + return -ENOMEM; + } + + /* some devices have '!' in their name, change that to '/' */ + while (sysname[len] != '\0') { + + if (sysname[len] == '!') { + sysname[len] = '/'; + } + + len++; + } + + *ret_sysname = sysname; + *ret_sysname_len = len; + + return 0; } +// get the sysnum of a device from the device path +int vdev_sysfs_get_sysnum(char const *devpath, int *sysnum) +{ + + int rc = 0; + char *sysname = NULL; + size_t sysname_len = 0; + int i = 0; + + // last digits at the end of the sysname + rc = vdev_sysfs_get_sysname(devpath, &sysname, &sysname_len); + if (rc != 0) { + return rc; + } + + while (isdigit(sysname[sysname_len - i])) { + i++; + } + i++; + + *sysnum = strtol(sysname + sysname_len - i, NULL, 10); + + free(sysname); + + return 0; +} // get the absolute sysfs device path from a major/minor pair and device type // return 0 on success, and set *syspath and *syspath_len // return negative on error -int vdev_sysfs_get_syspath_from_device( char const* sysfs_mountpoint, mode_t mode, unsigned int major, unsigned int minor, char** syspath, size_t* syspath_len ) { - - char* devpath = (char*)calloc( strlen(sysfs_mountpoint) + 4097, 1 ); - char linkbuf[4097]; - - if( devpath == NULL ) { - return -ENOMEM; - } - - int rc = 0; - - memset( linkbuf, 0, 4097 ); - - if( S_ISCHR( mode ) ) { - - // character device - sprintf(devpath, "%s/dev/char/%u:%u", sysfs_mountpoint, major, minor ); - } - else if( S_ISBLK( mode ) ) { - - // block device - sprintf(devpath, "%s/dev/block/%u:%u", sysfs_mountpoint, major, minor ); - } - else { - - free( devpath ); - return -EINVAL; - } - - rc = readlink( devpath, linkbuf, 4097 ); - if( rc < 0 ) { - - rc = -errno; - free( devpath ); - return rc; - } - - // link should start with "../devices" - if( strncmp( linkbuf, "../../devices", strlen("../../devices") ) != 0 ) { - - // sysfs structure changed??? - free( devpath ); - return -EIO; - } - - sprintf( devpath, "%s/%s", sysfs_mountpoint, linkbuf + strlen("../../") ); - - *syspath = devpath; - *syspath_len = strlen(devpath); - - return 0; -} +int vdev_sysfs_get_syspath_from_device(char const *sysfs_mountpoint, + mode_t mode, unsigned int major, + unsigned int minor, char **syspath, + size_t * syspath_len) +{ + + char *devpath = (char *)calloc(strlen(sysfs_mountpoint) + 4097, 1); + char linkbuf[4097]; + if (devpath == NULL) { + return -ENOMEM; + } + int rc = 0; + memset(linkbuf, 0, 4097); + + if (S_ISCHR(mode)) { + + // character device + sprintf(devpath, "%s/dev/char/%u:%u", sysfs_mountpoint, major, + minor); + } else if (S_ISBLK(mode)) { + + // block device + sprintf(devpath, "%s/dev/block/%u:%u", sysfs_mountpoint, major, + minor); + } else { + + free(devpath); + return -EINVAL; + } + + rc = readlink(devpath, linkbuf, 4097); + if (rc < 0) { + + rc = -errno; + free(devpath); + return rc; + } + // link should start with "../devices" + if (strncmp(linkbuf, "../../devices", strlen("../../devices")) != 0) { + + // sysfs structure changed??? + free(devpath); + return -EIO; + } + + sprintf(devpath, "%s/%s", sysfs_mountpoint, linkbuf + strlen("../../")); + + *syspath = devpath; + *syspath_len = strlen(devpath); + + return 0; +} diff --git a/vdevd/helpers/LINUX/common.h b/vdevd/helpers/LINUX/common.h index f1c2f8a..7bb43eb 100644 --- a/vdevd/helpers/LINUX/common.h +++ b/vdevd/helpers/LINUX/common.h @@ -19,7 +19,6 @@ . */ - #ifndef _VDEV_LINUX_HELPERS_COMMON_H_ #define _VDEV_LINUX_HELPERS_COMMON_H_ @@ -66,7 +65,7 @@ // hold-overs from udev -#ifndef memzero +#ifndef memzero #define memzero(b, z) memset( b, 0, z ) #endif @@ -74,7 +73,7 @@ #define streq(a, b) (strcmp(a, b) == 0) #endif -#ifndef strneq +#ifndef strneq #define strneq(a, b, len) (strncmp(a, b, len) == 0) #endif @@ -86,19 +85,17 @@ #define strscpy(dest, destsize, src) strncpy(dest, src, destsize) #endif -#ifndef initialize_srand +#ifndef initialize_srand #define initialize_srand() do { struct timespec ts; clock_gettime( CLOCK_MONOTONIC, &ts ); srand( ts.tv_sec + ts.tv_nsec ); } while(0) #endif - - // expanding list of properties struct vdev_property { - - char* name; - char* value; - - struct vdev_property* next; + + char *name; + char *value; + + struct vdev_property *next; }; // string methods (hold-overs from udev) @@ -108,28 +105,48 @@ int vdev_utf8_encoded_to_unichar(const char *str); int vdev_utf8_encoded_valid_unichar(const char *str); int vdev_util_replace_chars(char *str, const char *white); int vdev_util_encode_string(const char *str, char *str_enc, size_t len); -int vdev_util_rstrip( char* str ); +int vdev_util_rstrip(char *str); // device properties -int vdev_property_add( char const* name, char const* value ); -int vdev_property_print( void ); -int vdev_property_free_all( void ); +int vdev_property_add(char const *name, char const *value); +int vdev_property_print(void); +int vdev_property_free_all(void); // sysfs methods -int vdev_sysfs_read_attr( char const* sysfs_device_path, char const* attr_name, char** value, size_t* value_len ); -int vdev_sysfs_uevent_read_key( char const* sysfs_device_path, char const* uevent_key, char** uevent_value, size_t* uevent_value_len ); -int vdev_sysfs_uevent_get_key( char const* uevent_buf, size_t uevent_buflen, char const* key, char** value, size_t* value_len ); -int vdev_sysfs_get_parent_with_subsystem_devtype( char const* sysfs_device_path, char const* subsystem_name, char const* devtype_name, char** devpath, size_t* devpath_len ); -int vdev_sysfs_read_device_path( char const* sysfs_dir, char** devpath, size_t* devpath_len ); -int vdev_sysfs_device_path_from_subsystem_sysname( char const* sysfs_mount, char const* subsystem, char const* sysname, char** devpath, size_t* devpath_len ); -int vdev_sysfs_get_parent_device( char const* dev_path, char** ret_parent_device, size_t* ret_parent_device_len ); -int vdev_sysfs_read_subsystem( char const* devpath, char** ret_subsystem, size_t* ret_subsystem_len ); -int vdev_sysfs_get_sysname( char const* devpath, char** sysname, size_t* sysname_len ); -int vdev_sysfs_get_sysnum( char const* devpath, int* sysnum ); -int vdev_sysfs_get_syspath_from_device( char const* sysfs_mountpoint, mode_t mode, unsigned int major, unsigned int minor, char** syspath, size_t* syspath_len ); +int vdev_sysfs_read_attr(char const *sysfs_device_path, char const *attr_name, + char **value, size_t * value_len); +int vdev_sysfs_uevent_read_key(char const *sysfs_device_path, + char const *uevent_key, char **uevent_value, + size_t * uevent_value_len); +int vdev_sysfs_uevent_get_key(char const *uevent_buf, size_t uevent_buflen, + char const *key, char **value, + size_t * value_len); +int vdev_sysfs_get_parent_with_subsystem_devtype(char const *sysfs_device_path, + char const *subsystem_name, + char const *devtype_name, + char **devpath, + size_t * devpath_len); +int vdev_sysfs_read_device_path(char const *sysfs_dir, char **devpath, + size_t * devpath_len); +int vdev_sysfs_device_path_from_subsystem_sysname(char const *sysfs_mount, + char const *subsystem, + char const *sysname, + char **devpath, + size_t * devpath_len); +int vdev_sysfs_get_parent_device(char const *dev_path, char **ret_parent_device, + size_t * ret_parent_device_len); +int vdev_sysfs_read_subsystem(char const *devpath, char **ret_subsystem, + size_t * ret_subsystem_len); +int vdev_sysfs_get_sysname(char const *devpath, char **sysname, + size_t * sysname_len); +int vdev_sysfs_get_sysnum(char const *devpath, int *sysnum); +int vdev_sysfs_get_syspath_from_device(char const *sysfs_mountpoint, + mode_t mode, unsigned int major, + unsigned int minor, char **syspath, + size_t * syspath_len); // file operations -ssize_t vdev_read_uninterrupted( int fd, char* buf, size_t len ); -int vdev_read_file( char const* path, char** file_buf, size_t* file_buf_len ); +ssize_t vdev_read_uninterrupted(int fd, char *buf, size_t len); +int vdev_read_file(char const *path, char **file_buf, size_t * file_buf_len); #endif diff --git a/vdevd/helpers/LINUX/echo_n.c b/vdevd/helpers/LINUX/echo_n.c index d1263a9..d9c7e2e 100644 --- a/vdevd/helpers/LINUX/echo_n.c +++ b/vdevd/helpers/LINUX/echo_n.c @@ -1,13 +1,14 @@ #include // echo -n implementation, where -n means "no newline" -int main( int argc, char** argv ) { - if( argc == 1 ) { - return 0; - } - for( int i = 1; i < argc-1; i++ ) { - printf("%s ", argv[i]); - } - printf("%s", argv[argc-1]); - return 0; +int main(int argc, char **argv) +{ + if (argc == 1) { + return 0; + } + for (int i = 1; i < argc - 1; i++) { + printf("%s ", argv[i]); + } + printf("%s", argv[argc - 1]); + return 0; } diff --git a/vdevd/helpers/LINUX/event-put.c b/vdevd/helpers/LINUX/event-put.c index 7f77c57..d5549cf 100644 --- a/vdevd/helpers/LINUX/event-put.c +++ b/vdevd/helpers/LINUX/event-put.c @@ -30,462 +30,482 @@ #define DEFAULT_DEV_EVENTS "/dev/events/global" // path to device events directory (overrideable in command-line) -static char g_dev_events[PATH_MAX+1]; +static char g_dev_events[PATH_MAX + 1]; // make a path to an event in the global queue // event_path must have at least PATH_MAX+1 bytes -int make_event_path( uint64_t seqnum, char* event_path ) { - - memset( event_path, 0, PATH_MAX+1 ); - - return snprintf( event_path, PATH_MAX, "%s/%" PRIu64, g_dev_events, seqnum ); +int make_event_path(uint64_t seqnum, char *event_path) +{ + + memset(event_path, 0, PATH_MAX + 1); + + return snprintf(event_path, PATH_MAX, "%s/%" PRIu64, g_dev_events, + seqnum); } // open the event file, exclusively, for writing. // make sure that only the UID/GID of this process (i.e. root) can access it. -int open_event( char* event_path ) { - - int fd = 0; - - fd = open( event_path, O_WRONLY | O_EXCL | O_CREAT, 0600 ); - if( fd < 0 ) { - - fd = -errno; - log_error("open('%s') rc = %d\n", event_path, fd ); - return fd; - } - - return fd; -} +int open_event(char *event_path) +{ + + int fd = 0; + fd = open(event_path, O_WRONLY | O_EXCL | O_CREAT, 0600); + if (fd < 0) { + + fd = -errno; + log_error("open('%s') rc = %d\n", event_path, fd); + return fd; + } + + return fd; +} // clear an event // return 0 on success // return -errno (from unlink(2)) on failure -int clear_event( char* event_path ) { - - int rc = unlink( event_path ); - if( rc < 0 ) { - - rc = -errno; - log_error("unlink('%s') rc = %d\n", event_path, rc ); - } - - return rc; -} +int clear_event(char *event_path) +{ + + int rc = unlink(event_path); + if (rc < 0) { + + rc = -errno; + log_error("unlink('%s') rc = %d\n", event_path, rc); + } + return rc; +} // link all events to all directories that are siblings to the parent directory of the event path. // try to do so even if we fail to link in some cases // return 0 on success // return -errno if at least one failed -int multicast_event( uint64_t seqnum, char* event_path ) { - - int rc = 0; - DIR* dirh = NULL; - struct dirent entry; - struct dirent* result = NULL; - char pathbuf[ PATH_MAX+1 ]; - - char event_queues_dir[ PATH_MAX+1 ]; - char global_queue_name[ NAME_MAX+1 ]; - - memset( event_queues_dir, 0, PATH_MAX+1 ); - memset( global_queue_name, 0, NAME_MAX+1 ); - - // parent nmae of event_path... - ssize_t i = strlen(event_path) - 1; - if( i < 0 ) { - return -EINVAL; - } - - // shouldn't end in '/', but you never know... - while( i > 0 && event_path[i] == '/' ) { - i--; - } - - // skip event name - while( i > 0 && event_path[i] != '/' ) { - i--; - } - - // skip '/' at the end of the parent name - while( i > 0 && event_path[i] == '/' ) { - i--; - } - - if( i == 0 ) { - - // event_path's parent is / - strcpy( global_queue_name, "." ); - strcpy( event_queues_dir, "/" ); - } - else { - - ssize_t parent_end = i; - - while( i > 0 && event_path[i] != '/' ) { - i--; - } - - strncpy( global_queue_name, &event_path[i+1], parent_end - i ); - strncpy( event_queues_dir, event_path, i+1 ); - } - - dirh = opendir( event_queues_dir ); - if( dirh == NULL ) { - - // OOM - rc = -errno; - return rc; - } - - do { - - // next entry - rc = readdir_r( dirh, &entry, &result ); - if( rc != 0 ) { - - // I/O error - log_error("readdir_r('%s') rc = %d", event_queues_dir, rc ); - break; - } - - // skip . and .. - if( strcmp( entry.d_name, "." ) == 0 || strcmp( entry.d_name, ".." ) == 0 ) { - continue; - } - - // skip non-directories - if( entry.d_type != DT_DIR ) { - continue; - } - - // skip global queue - if( strcmp( global_queue_name, entry.d_name ) == 0 ) { - continue; - } - - // link to this directory - snprintf( pathbuf, PATH_MAX, "%s/%s/%" PRIu64, event_queues_dir, entry.d_name, seqnum ); - - rc = link( event_path, pathbuf ); - if( rc != 0 ) { - - rc = errno; - log_error("link('%s', '%s'): %s", event_path, pathbuf, strerror( -rc ) ); - rc = 0; - } - - } while( result != NULL ); - - closedir( dirh ); - - return rc; -} +int multicast_event(uint64_t seqnum, char *event_path) +{ + int rc = 0; + DIR *dirh = NULL; + struct dirent entry; + struct dirent *result = NULL; + char pathbuf[PATH_MAX + 1]; -// print usage statement -int usage( char const* progname ) { - - int i = 0; - char const* usage_text[] = { - "Usage: ", progname, " [-v] [-n SEQNUM] [-s SOURCE-QUEUE] [-t TARGET-QUEUES]\n", - "Options:\n", - " -n SEQNUM\n", - " Event sequence number. Must be\n", - " unique across all pending events.\n", - "\n", - " -s SOURCE-QUEUE\n", - " Path to the source event queue. An\n", - " event will be added as a child of this\n", - " directory, and linked into all directories\n", - " in TARGET-QUEUES. The default is\n", - " " DEFAULT_DEV_EVENTS, "\n", - "\n", - NULL - }; - - for( i = 0; usage_text[i] != NULL; i++ ) { - fprintf(stderr, usage_text[i] ); - } - - return 0; + char event_queues_dir[PATH_MAX + 1]; + char global_queue_name[NAME_MAX + 1]; + + memset(event_queues_dir, 0, PATH_MAX + 1); + memset(global_queue_name, 0, NAME_MAX + 1); + + // parent nmae of event_path... + ssize_t i = strlen(event_path) - 1; + if (i < 0) { + return -EINVAL; + } + // shouldn't end in '/', but you never know... + while (i > 0 && event_path[i] == '/') { + i--; + } + + // skip event name + while (i > 0 && event_path[i] != '/') { + i--; + } + + // skip '/' at the end of the parent name + while (i > 0 && event_path[i] == '/') { + i--; + } + + if (i == 0) { + + // event_path's parent is / + strcpy(global_queue_name, "."); + strcpy(event_queues_dir, "/"); + } else { + + ssize_t parent_end = i; + + while (i > 0 && event_path[i] != '/') { + i--; + } + + strncpy(global_queue_name, &event_path[i + 1], parent_end - i); + strncpy(event_queues_dir, event_path, i + 1); + } + + dirh = opendir(event_queues_dir); + if (dirh == NULL) { + + // OOM + rc = -errno; + return rc; + } + + do { + + // next entry + rc = readdir_r(dirh, &entry, &result); + if (rc != 0) { + + // I/O error + log_error("readdir_r('%s') rc = %d", event_queues_dir, + rc); + break; + } + // skip . and .. + if (strcmp(entry.d_name, ".") == 0 + || strcmp(entry.d_name, "..") == 0) { + continue; + } + // skip non-directories + if (entry.d_type != DT_DIR) { + continue; + } + // skip global queue + if (strcmp(global_queue_name, entry.d_name) == 0) { + continue; + } + // link to this directory + snprintf(pathbuf, PATH_MAX, "%s/%s/%" PRIu64, event_queues_dir, + entry.d_name, seqnum); + + rc = link(event_path, pathbuf); + if (rc != 0) { + + rc = errno; + log_error("link('%s', '%s'): %s", event_path, pathbuf, + strerror(-rc)); + rc = 0; + } + + } while (result != NULL); + + closedir(dirh); + + return rc; } +// print usage statement +int usage(char const *progname) +{ + + int i = 0; + char const *usage_text[] = { + "Usage: ", progname, + " [-v] [-n SEQNUM] [-s SOURCE-QUEUE] [-t TARGET-QUEUES]\n", + "Options:\n", + " -n SEQNUM\n", + " Event sequence number. Must be\n", + " unique across all pending events.\n", + "\n", + " -s SOURCE-QUEUE\n", + " Path to the source event queue. An\n", + " event will be added as a child of this\n", + " directory, and linked into all directories\n", + " in TARGET-QUEUES. The default is\n", + " " DEFAULT_DEV_EVENTS, "\n", + "\n", + NULL + }; + + for (i = 0; usage_text[i] != NULL; i++) { + fprintf(stderr, usage_text[i]); + } + + return 0; +} // print a verbose help statement -int help( char const* progname ) { - - usage( progname ); - - int i = 0; - char const* help_text[] = { - "This program reads a device event from standard input, such that\n", - "each line takes the form of KEY=VALUE. Valid keys and values are:\n", - "\n", - " DEVPATH=(/devices path) [REQUIRED]\n", - " SUBSYSTEM=(subsystem name) [REQUIRED]\n", - " SEQNUM=(kernel uevent sequence number) [REQUIRED if -n is not given]\n", - " DEVNAME=(/dev node path)\n", - " DEVLINKS=(space-separated list of symlinks)\n", - " TAGS=(colon-separated list of tags)\n", - " USEC_INITIALIZED=(microseconds since device initialization)\n", - " DRIVER=(name of device driver)\n", - " ACTION=(add, remove, change, move, etc.)\n", - " MAJOR=(major device number)\n", - " MINOR=(minor device number)\n", - " DEVPATH_OLD=(old device path (on move)\n", - " IFINDEX=(device interface index, e.g. for USB and network interfaces)\n", - " DEVMODE=(device node permission bits)\n", - " DEVUID=(device node UID)\n", - " DEVGID=(device node GID)\n", - "\n", - "Keys marked with [REQUIRED] must be present.\n", - "NOTE: events are limited to 8192 bytes.\n", - NULL - }; - - for( i = 0; help_text[i] != NULL; i++ ) { - fprintf(stderr, help_text[i] ); - } - - return 0; +int help(char const *progname) +{ + + usage(progname); + + int i = 0; + char const *help_text[] = { + "This program reads a device event from standard input, such that\n", + "each line takes the form of KEY=VALUE. Valid keys and values are:\n", + "\n", + " DEVPATH=(/devices path) [REQUIRED]\n", + " SUBSYSTEM=(subsystem name) [REQUIRED]\n", + " SEQNUM=(kernel uevent sequence number) [REQUIRED if -n is not given]\n", + " DEVNAME=(/dev node path)\n", + " DEVLINKS=(space-separated list of symlinks)\n", + " TAGS=(colon-separated list of tags)\n", + " USEC_INITIALIZED=(microseconds since device initialization)\n", + " DRIVER=(name of device driver)\n", + " ACTION=(add, remove, change, move, etc.)\n", + " MAJOR=(major device number)\n", + " MINOR=(minor device number)\n", + " DEVPATH_OLD=(old device path (on move)\n", + " IFINDEX=(device interface index, e.g. for USB and network interfaces)\n", + " DEVMODE=(device node permission bits)\n", + " DEVUID=(device node UID)\n", + " DEVGID=(device node GID)\n", + "\n", + "Keys marked with [REQUIRED] must be present.\n", + "NOTE: events are limited to 8192 bytes.\n", + NULL + }; + + for (i = 0; help_text[i] != NULL; i++) { + fprintf(stderr, help_text[i]); + } + + return 0; } // read, but mask EINTR // return number of bytes read on success // return -errno on I/O error // NOTE: must be async-safe! -ssize_t read_uninterrupted( int fd, char* buf, size_t len ) { - - ssize_t num_read = 0; - - if( buf == NULL ) { - return -EINVAL; - } - - while( (unsigned)num_read < len ) { - ssize_t nr = read( fd, buf + num_read, len - num_read ); - if( nr < 0 ) { - - int errsv = -errno; - if( errsv == -EINTR ) { - continue; - } - - return errsv; - } - if( nr == 0 ) { - break; - } - - num_read += nr; - } - - return num_read; -} +ssize_t read_uninterrupted(int fd, char *buf, size_t len) +{ + + ssize_t num_read = 0; + if (buf == NULL) { + return -EINVAL; + } + + while ((unsigned)num_read < len) { + ssize_t nr = read(fd, buf + num_read, len - num_read); + if (nr < 0) { + + int errsv = -errno; + if (errsv == -EINTR) { + continue; + } + + return errsv; + } + if (nr == 0) { + break; + } + + num_read += nr; + } + + return num_read; +} // write, but mask EINTR // return number of bytes written on success // return -errno on I/O error -ssize_t write_uninterrupted( int fd, char const* buf, size_t len ) { - - ssize_t num_written = 0; - - if( buf == NULL ) { - return -EINVAL; - } - - while( (unsigned)num_written < len ) { - ssize_t nw = write( fd, buf + num_written, len - num_written ); - if( nw < 0 ) { - - int errsv = -errno; - if( errsv == -EINTR ) { - continue; - } - - return errsv; - } - if( nw == 0 ) { - break; - } - - num_written += nw; - } - - return num_written; -} +ssize_t write_uninterrupted(int fd, char const *buf, size_t len) +{ + + ssize_t num_written = 0; + + if (buf == NULL) { + return -EINVAL; + } + + while ((unsigned)num_written < len) { + ssize_t nw = write(fd, buf + num_written, len - num_written); + if (nw < 0) { + + int errsv = -errno; + if (errsv == -EINTR) { + continue; + } + + return errsv; + } + if (nw == 0) { + break; + } + num_written += nw; + } + + return num_written; +} // entry point -int main( int argc, char** argv ) { - - int rc = 0; - uint64_t seqnum = 0; - int opt_index = 0; - int c = 0; - int fd = 0; - char* tmp = NULL; - char event_buf[8192]; - char event_buf_tmp[8292]; // has to hold event_buf plus an 8-byte sequence number - char event_path[ PATH_MAX+1 ]; - - bool have_seqnum = false; - ssize_t nr = 0; - char const* required_fields[] = { - "\nSUBSYSTEM=", - "\nDEVPATH=", - NULL - }; - - char target_queues[PATH_MAX+1]; - - // default event queue - memset( g_dev_events, 0, PATH_MAX+1 ); - memset( target_queues, 0, PATH_MAX+1 ); - memset( event_path, 0, PATH_MAX+1 ); - - strcpy( g_dev_events, DEFAULT_DEV_EVENTS ); - - static struct option opts[] = { - {"source-queue", required_argument, 0, 's'}, - {"seqnum", required_argument, 0, 'n'}, - {"help", no_argument, 0, 'h'}, - {0, 0, 0, 0} - }; - - char const* optstr = "n:s:h"; - - while( rc == 0 && c != -1 ) { - - c = getopt_long( argc, argv, optstr, opts, &opt_index ); - if( c == -1 ) { - - break; - } - - switch( c ) { - - case 's': { - - memset( g_dev_events, 0, PATH_MAX ); - strncpy( g_dev_events, optarg, PATH_MAX ); - break; - } - - case 'n': { - - seqnum = (uint64_t)strtoull( optarg, &tmp, 10 ); - if( seqnum == 0 && (tmp == optarg || *tmp != '\0') ) { - - usage( argv[0] ); - exit(1); - } - - have_seqnum = true; - break; - } - - case 'h': { - - help( argv[0] ); - exit(0); - } - - default: { - - fprintf(stderr, "[ERROR] %s: Unrecognized option '%c'\n", argv[0], c ); - usage(argv[0]); - exit(1); - } - } - } - - // get the event - memset( event_buf, 0, 8192 ); - nr = read_uninterrupted( STDIN_FILENO, event_buf, 8192 ); - - if( nr <= 0 ) { - - rc = -errno; - fprintf( stderr, "[ERROR] %s: Failed to read event from stdin: %s\n", argv[0], strerror( -rc ) ); - exit(1); - } - - // simple sanity check for requirements - for( int i = 0; required_fields[i] != NULL; i++ ) { - - if( strstr( event_buf, required_fields[i] ) == NULL ) { - - // head of line? with no leading '\n'? - if( strncmp( event_buf, required_fields[i] + 1, strlen(required_fields[i]) - 1 ) != 0 ) { - - fprintf(stderr, "[ERROR] %s: Missing required field '%s'\n", argv[0], required_fields[i] + 1 ); - fprintf(stderr, "[ERROR] %s: Pass -h for a list of required fields\n", argv[0] ); - exit(1); - } - } - } - - // do we have a seqnum? - if( !have_seqnum ) { - - char* seqnum_str = strstr( event_buf, "SEQNUM=" ); - - // go find it in the device event - if( seqnum_str == NULL ) { - - fprintf(stderr, "[ERROR] %s: Missing SEQNUM. Pass -n or include SEQNUM= in the input.\n", argv[0]); - exit(1); - } - - // is it a valid seqnum? - seqnum = (uint64_t)strtoull( seqnum_str + strlen("SEQNUM="), &tmp, 10 ); - if( seqnum == 0 && (tmp == seqnum_str + strlen("SEQNUM=") || *tmp != '\n') ) { - - // invalid seqnum - fprintf(stderr, "[ERROR] %s: Invalid SEQNUM. Pass -n or include a valid SEQNUM in the input.\n", argv[0]); - exit(1); - } - } - - // send it off! - make_event_path( seqnum, event_path ); - - fd = open_event( event_path ); - if( fd < 0 ) { - - fprintf(stderr, "[ERROR] %s: Failed to open '%s': %s\n", argv[0], event_path, strerror( -fd ) ); - exit(1); - } - - rc = write_uninterrupted( fd, event_buf, nr ); - if( rc < 0 ) { - - fprintf(stderr, "[ERROR] %s: Failed to write '%s': %s\n", argv[0], event_path, strerror( -fd ) ); - - clear_event( event_buf ); - close( fd ); - exit(1); - } - - // propagate.... - rc = multicast_event( seqnum, event_path ); - if( rc < 0 ) { - - fprintf(stderr, "[ERROR] %s: Failed to multicast '%s': %s\n", argv[0], event_path, strerror( -rc ) ); - - clear_event( event_buf ); - close( fd ); - exit(1); - } - - // done! - clear_event( event_path ); - close( fd ); - - return 0; +int main(int argc, char **argv) +{ + + int rc = 0; + uint64_t seqnum = 0; + int opt_index = 0; + int c = 0; + int fd = 0; + char *tmp = NULL; + char event_buf[8192]; + char event_buf_tmp[8292]; // has to hold event_buf plus an 8-byte sequence number + char event_path[PATH_MAX + 1]; + + bool have_seqnum = false; + ssize_t nr = 0; + char const *required_fields[] = { + "\nSUBSYSTEM=", + "\nDEVPATH=", + NULL + }; + + char target_queues[PATH_MAX + 1]; + + // default event queue + memset(g_dev_events, 0, PATH_MAX + 1); + memset(target_queues, 0, PATH_MAX + 1); + memset(event_path, 0, PATH_MAX + 1); + + strcpy(g_dev_events, DEFAULT_DEV_EVENTS); + + static struct option opts[] = { + {"source-queue", required_argument, 0, 's'}, + {"seqnum", required_argument, 0, 'n'}, + {"help", no_argument, 0, 'h'}, + {0, 0, 0, 0} + }; + + char const *optstr = "n:s:h"; + + while (rc == 0 && c != -1) { + + c = getopt_long(argc, argv, optstr, opts, &opt_index); + if (c == -1) { + + break; + } + + switch (c) { + + case 's':{ + + memset(g_dev_events, 0, PATH_MAX); + strncpy(g_dev_events, optarg, PATH_MAX); + break; + } + + case 'n':{ + + seqnum = (uint64_t) strtoull(optarg, &tmp, 10); + if (seqnum == 0 + && (tmp == optarg || *tmp != '\0')) { + + usage(argv[0]); + exit(1); + } + + have_seqnum = true; + break; + } + + case 'h':{ + + help(argv[0]); + exit(0); + } + + default:{ + + fprintf(stderr, + "[ERROR] %s: Unrecognized option '%c'\n", + argv[0], c); + usage(argv[0]); + exit(1); + } + } + } + + // get the event + memset(event_buf, 0, 8192); + nr = read_uninterrupted(STDIN_FILENO, event_buf, 8192); + + if (nr <= 0) { + + rc = -errno; + fprintf(stderr, + "[ERROR] %s: Failed to read event from stdin: %s\n", + argv[0], strerror(-rc)); + exit(1); + } + // simple sanity check for requirements + for (int i = 0; required_fields[i] != NULL; i++) { + + if (strstr(event_buf, required_fields[i]) == NULL) { + + // head of line? with no leading '\n'? + if (strncmp + (event_buf, required_fields[i] + 1, + strlen(required_fields[i]) - 1) != 0) { + + fprintf(stderr, + "[ERROR] %s: Missing required field '%s'\n", + argv[0], required_fields[i] + 1); + fprintf(stderr, + "[ERROR] %s: Pass -h for a list of required fields\n", + argv[0]); + exit(1); + } + } + } + + // do we have a seqnum? + if (!have_seqnum) { + + char *seqnum_str = strstr(event_buf, "SEQNUM="); + + // go find it in the device event + if (seqnum_str == NULL) { + + fprintf(stderr, + "[ERROR] %s: Missing SEQNUM. Pass -n or include SEQNUM= in the input.\n", + argv[0]); + exit(1); + } + // is it a valid seqnum? + seqnum = + (uint64_t) strtoull(seqnum_str + strlen("SEQNUM="), &tmp, + 10); + if (seqnum == 0 + && (tmp == seqnum_str + strlen("SEQNUM=") + || *tmp != '\n')) { + + // invalid seqnum + fprintf(stderr, + "[ERROR] %s: Invalid SEQNUM. Pass -n or include a valid SEQNUM in the input.\n", + argv[0]); + exit(1); + } + } + // send it off! + make_event_path(seqnum, event_path); + + fd = open_event(event_path); + if (fd < 0) { + + fprintf(stderr, "[ERROR] %s: Failed to open '%s': %s\n", + argv[0], event_path, strerror(-fd)); + exit(1); + } + + rc = write_uninterrupted(fd, event_buf, nr); + if (rc < 0) { + + fprintf(stderr, "[ERROR] %s: Failed to write '%s': %s\n", + argv[0], event_path, strerror(-fd)); + + clear_event(event_buf); + close(fd); + exit(1); + } + // propagate.... + rc = multicast_event(seqnum, event_path); + if (rc < 0) { + + fprintf(stderr, "[ERROR] %s: Failed to multicast '%s': %s\n", + argv[0], event_path, strerror(-rc)); + + clear_event(event_buf); + close(fd); + exit(1); + } + // done! + clear_event(event_path); + close(fd); + + return 0; } diff --git a/vdevd/helpers/LINUX/stat_ata.c b/vdevd/helpers/LINUX/stat_ata.c index 9500224..f34f585 100644 --- a/vdevd/helpers/LINUX/stat_ata.c +++ b/vdevd/helpers/LINUX/stat_ata.c @@ -72,240 +72,239 @@ #define COMMAND_TIMEOUT_MSEC (30 * 1000) -static int disk_scsi_inquiry_command(int fd, void *buf, size_t buf_len) { - - uint8_t cdb[6]; - uint8_t sense[32]; - struct sg_io_v4 io_v4; - struct sg_io_hdr io_hdr; - int ret = 0; - - memset( sense, 0, 32 * sizeof(uint8_t)); - memset( &io_v4, 0, sizeof(struct sg_io_v4) ); - memset( &io_hdr, 0, sizeof(struct sg_io_hdr) ); - memset( cdb, 0, 6 * sizeof(uint8_t) ); - - /* - * INQUIRY, see SPC-4 section 6.4 - */ - cdb[0] = 0x12; /* OPERATION CODE: INQUIRY */ - cdb[3] = (buf_len >> 8); /* ALLOCATION LENGTH */ - cdb[4] = (buf_len & 0xff); - - io_v4.guard = 'Q', - io_v4.protocol = BSG_PROTOCOL_SCSI; - io_v4.subprotocol = BSG_SUB_PROTOCOL_SCSI_CMD; - io_v4.request_len = sizeof(cdb); - io_v4.request = (uintptr_t) cdb; - io_v4.max_response_len = sizeof(sense); - io_v4.response = (uintptr_t) sense; - io_v4.din_xfer_len = buf_len; - io_v4.din_xferp = (uintptr_t) buf; - io_v4.timeout = COMMAND_TIMEOUT_MSEC; - - ret = ioctl(fd, SG_IO, &io_v4); - if (ret != 0) { - /* could be that the driver doesn't do version 4, try version 3 */ - if (errno == EINVAL) { - - io_hdr.interface_id = 'S'; - io_hdr.cmdp = (unsigned char*) cdb; - io_hdr.cmd_len = sizeof (cdb); - io_hdr.dxferp = buf; - io_hdr.dxfer_len = buf_len; - io_hdr.sbp = sense; - io_hdr.mx_sb_len = sizeof(sense); - io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; - io_hdr.timeout = COMMAND_TIMEOUT_MSEC; - - ret = ioctl(fd, SG_IO, &io_hdr); - if (ret != 0) { - - return ret; - } - - /* even if the ioctl succeeds, we need to check the return value */ - if (!(io_hdr.status == 0 && - io_hdr.host_status == 0 && - io_hdr.driver_status == 0)) { - errno = EIO; - - return -1; - } - } else { - - return ret; - } - } - - /* even if the ioctl succeeds, we need to check the return value */ - if (!(io_v4.device_status == 0 && - io_v4.transport_status == 0 && - io_v4.driver_status == 0)) { - errno = EIO; - - return -1; - } - - return 0; +static int disk_scsi_inquiry_command(int fd, void *buf, size_t buf_len) +{ + + uint8_t cdb[6]; + uint8_t sense[32]; + struct sg_io_v4 io_v4; + struct sg_io_hdr io_hdr; + int ret = 0; + + memset(sense, 0, 32 * sizeof(uint8_t)); + memset(&io_v4, 0, sizeof(struct sg_io_v4)); + memset(&io_hdr, 0, sizeof(struct sg_io_hdr)); + memset(cdb, 0, 6 * sizeof(uint8_t)); + + /* + * INQUIRY, see SPC-4 section 6.4 + */ + cdb[0] = 0x12; /* OPERATION CODE: INQUIRY */ + cdb[3] = (buf_len >> 8); /* ALLOCATION LENGTH */ + cdb[4] = (buf_len & 0xff); + + io_v4.guard = 'Q', io_v4.protocol = BSG_PROTOCOL_SCSI; + io_v4.subprotocol = BSG_SUB_PROTOCOL_SCSI_CMD; + io_v4.request_len = sizeof(cdb); + io_v4.request = (uintptr_t) cdb; + io_v4.max_response_len = sizeof(sense); + io_v4.response = (uintptr_t) sense; + io_v4.din_xfer_len = buf_len; + io_v4.din_xferp = (uintptr_t) buf; + io_v4.timeout = COMMAND_TIMEOUT_MSEC; + + ret = ioctl(fd, SG_IO, &io_v4); + if (ret != 0) { + /* could be that the driver doesn't do version 4, try version 3 */ + if (errno == EINVAL) { + + io_hdr.interface_id = 'S'; + io_hdr.cmdp = (unsigned char *)cdb; + io_hdr.cmd_len = sizeof(cdb); + io_hdr.dxferp = buf; + io_hdr.dxfer_len = buf_len; + io_hdr.sbp = sense; + io_hdr.mx_sb_len = sizeof(sense); + io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; + io_hdr.timeout = COMMAND_TIMEOUT_MSEC; + + ret = ioctl(fd, SG_IO, &io_hdr); + if (ret != 0) { + + return ret; + } + + /* even if the ioctl succeeds, we need to check the return value */ + if (!(io_hdr.status == 0 && + io_hdr.host_status == 0 && + io_hdr.driver_status == 0)) { + errno = EIO; + + return -1; + } + } else { + + return ret; + } + } + + /* even if the ioctl succeeds, we need to check the return value */ + if (!(io_v4.device_status == 0 && + io_v4.transport_status == 0 && io_v4.driver_status == 0)) { + errno = EIO; + + return -1; + } + + return 0; } -static int disk_identify_command(int fd, void *buf, size_t buf_len) { - - uint8_t cdb[12]; - uint8_t sense[32] = {}; - uint8_t *desc = sense + 8; - struct sg_io_v4 io_v4; - struct sg_io_hdr io_hdr; - int ret = 0; - - memset( cdb, 0, sizeof(uint8_t) * 12 ); - memset( &io_v4, 0, sizeof(struct sg_io_v4) ); - memset( &io_hdr, 0, sizeof(struct sg_io_hdr) ); - - /* - * ATA Pass-Through 12 byte command, as described in - * - * T10 04-262r8 ATA Command Pass-Through - * - * from http://www.t10.org/ftp/t10/document.04/04-262r8.pdf - */ - cdb[0] = 0xa1; /* OPERATION CODE: 12 byte pass through */ - cdb[1] = 4 << 1; /* PROTOCOL: PIO Data-in */ - cdb[2] = 0x2e; /* OFF_LINE=0, CK_COND=1, T_DIR=1, BYT_BLOK=1, T_LENGTH=2 */ - cdb[3] = 0; /* FEATURES */ - cdb[4] = 1; /* SECTORS */ - cdb[5] = 0; /* LBA LOW */ - cdb[6] = 0; /* LBA MID */ - cdb[7] = 0; /* LBA HIGH */ - cdb[8] = 0 & 0x4F; /* SELECT */ - cdb[9] = 0xEC; /* Command: ATA IDENTIFY DEVICE */ - - io_v4.guard = 'Q'; - io_v4.protocol = BSG_PROTOCOL_SCSI; - io_v4.subprotocol = BSG_SUB_PROTOCOL_SCSI_CMD; - io_v4.request_len = sizeof(cdb); - io_v4.request = (uintptr_t) cdb; - io_v4.max_response_len = sizeof(sense); - io_v4.response = (uintptr_t) sense; - io_v4.din_xfer_len = buf_len; - io_v4.din_xferp = (uintptr_t) buf; - io_v4.timeout = COMMAND_TIMEOUT_MSEC; - - ret = ioctl(fd, SG_IO, &io_v4); - if (ret != 0) { - /* could be that the driver doesn't do version 4, try version 3 */ - if (errno == EINVAL) { - - io_hdr.interface_id = 'S', - io_hdr.cmdp = (unsigned char*) cdb; - io_hdr.cmd_len = sizeof (cdb); - io_hdr.dxferp = buf; - io_hdr.dxfer_len = buf_len; - io_hdr.sbp = sense; - io_hdr.mx_sb_len = sizeof (sense); - io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; - io_hdr.timeout = COMMAND_TIMEOUT_MSEC; - - ret = ioctl(fd, SG_IO, &io_hdr); - if (ret != 0) { - return ret; - } - } - else { - return ret; - } - } - - if (!(sense[0] == 0x72 && desc[0] == 0x9 && desc[1] == 0x0c)) { - errno = EIO; - return -1; - } - - return 0; +static int disk_identify_command(int fd, void *buf, size_t buf_len) +{ + + uint8_t cdb[12]; + uint8_t sense[32] = { }; + uint8_t *desc = sense + 8; + struct sg_io_v4 io_v4; + struct sg_io_hdr io_hdr; + int ret = 0; + + memset(cdb, 0, sizeof(uint8_t) * 12); + memset(&io_v4, 0, sizeof(struct sg_io_v4)); + memset(&io_hdr, 0, sizeof(struct sg_io_hdr)); + + /* + * ATA Pass-Through 12 byte command, as described in + * + * T10 04-262r8 ATA Command Pass-Through + * + * from http://www.t10.org/ftp/t10/document.04/04-262r8.pdf + */ + cdb[0] = 0xa1; /* OPERATION CODE: 12 byte pass through */ + cdb[1] = 4 << 1; /* PROTOCOL: PIO Data-in */ + cdb[2] = 0x2e; /* OFF_LINE=0, CK_COND=1, T_DIR=1, BYT_BLOK=1, T_LENGTH=2 */ + cdb[3] = 0; /* FEATURES */ + cdb[4] = 1; /* SECTORS */ + cdb[5] = 0; /* LBA LOW */ + cdb[6] = 0; /* LBA MID */ + cdb[7] = 0; /* LBA HIGH */ + cdb[8] = 0 & 0x4F; /* SELECT */ + cdb[9] = 0xEC; /* Command: ATA IDENTIFY DEVICE */ + + io_v4.guard = 'Q'; + io_v4.protocol = BSG_PROTOCOL_SCSI; + io_v4.subprotocol = BSG_SUB_PROTOCOL_SCSI_CMD; + io_v4.request_len = sizeof(cdb); + io_v4.request = (uintptr_t) cdb; + io_v4.max_response_len = sizeof(sense); + io_v4.response = (uintptr_t) sense; + io_v4.din_xfer_len = buf_len; + io_v4.din_xferp = (uintptr_t) buf; + io_v4.timeout = COMMAND_TIMEOUT_MSEC; + + ret = ioctl(fd, SG_IO, &io_v4); + if (ret != 0) { + /* could be that the driver doesn't do version 4, try version 3 */ + if (errno == EINVAL) { + + io_hdr.interface_id = 'S', + io_hdr.cmdp = (unsigned char *)cdb; + io_hdr.cmd_len = sizeof(cdb); + io_hdr.dxferp = buf; + io_hdr.dxfer_len = buf_len; + io_hdr.sbp = sense; + io_hdr.mx_sb_len = sizeof(sense); + io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; + io_hdr.timeout = COMMAND_TIMEOUT_MSEC; + + ret = ioctl(fd, SG_IO, &io_hdr); + if (ret != 0) { + return ret; + } + } else { + return ret; + } + } + + if (!(sense[0] == 0x72 && desc[0] == 0x9 && desc[1] == 0x0c)) { + errno = EIO; + return -1; + } + + return 0; } - -static int disk_identify_packet_device_command(int fd, void *buf, size_t buf_len) { - - uint8_t cdb[16]; - uint8_t sense[32]; - struct sg_io_v4 io_v4; - struct sg_io_hdr io_hdr; - uint8_t *desc = sense + 8; - int ret = 0; - - memset( sense, 0, 32 * sizeof(uint8_t) ); - memset( &io_v4, 0, sizeof(struct sg_io_v4) ); - memset( &io_hdr, 0, sizeof(struct sg_io_hdr) ); - - /* - * ATA Pass-Through 16 byte command, as described in - * - * T10 04-262r8 ATA Command Pass-Through - * - * from http://www.t10.org/ftp/t10/document.04/04-262r8.pdf - */ - cdb[0] = 0x85; /* OPERATION CODE: 16 byte pass through */ - cdb[1] = 4 << 1; /* PROTOCOL: PIO Data-in */ - cdb[2] = 0x2e; /* OFF_LINE=0, CK_COND=1, T_DIR=1, BYT_BLOK=1, T_LENGTH=2 */ - cdb[3] = 0; /* FEATURES */ - cdb[4] = 0; /* FEATURES */ - cdb[5] = 0; /* SECTORS */ - cdb[6] = 1; /* SECTORS */ - cdb[7] = 0; /* LBA LOW */ - cdb[8] = 0; /* LBA LOW */ - cdb[9] = 0; /* LBA MID */ - cdb[10] = 0; /* LBA MID */ - cdb[11] = 0; /* LBA HIGH */ - cdb[12] = 0; /* LBA HIGH */ - cdb[13] = 0; /* DEVICE */ - cdb[14] = 0xA1; /* Command: ATA IDENTIFY PACKET DEVICE */ - cdb[15] = 0; /* CONTROL */ - - io_v4.guard = 'Q'; - io_v4.protocol = BSG_PROTOCOL_SCSI; - io_v4.subprotocol = BSG_SUB_PROTOCOL_SCSI_CMD; - io_v4.request_len = sizeof (cdb); - io_v4.request = (uintptr_t) cdb; - io_v4.max_response_len = sizeof (sense); - io_v4.response = (uintptr_t) sense; - io_v4.din_xfer_len = buf_len; - io_v4.din_xferp = (uintptr_t) buf; - io_v4.timeout = COMMAND_TIMEOUT_MSEC; - - ret = ioctl(fd, SG_IO, &io_v4); - if (ret != 0) { - /* could be that the driver doesn't do version 4, try version 3 */ - if (errno == EINVAL) { - - io_hdr.interface_id = 'S'; - io_hdr.cmdp = (unsigned char*) cdb; - io_hdr.cmd_len = sizeof (cdb); - io_hdr.dxferp = buf; - io_hdr.dxfer_len = buf_len; - io_hdr.sbp = sense; - io_hdr.mx_sb_len = sizeof (sense); - io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; - io_hdr.timeout = COMMAND_TIMEOUT_MSEC; - - ret = ioctl(fd, SG_IO, &io_hdr); - if (ret != 0) { - return ret; - } - - } - else { - return ret; - } - } - - if (!(sense[0] == 0x72 && desc[0] == 0x9 && desc[1] == 0x0c)) { - errno = EIO; - return -1; - } - - return 0; +static int disk_identify_packet_device_command(int fd, void *buf, + size_t buf_len) +{ + + uint8_t cdb[16]; + uint8_t sense[32]; + struct sg_io_v4 io_v4; + struct sg_io_hdr io_hdr; + uint8_t *desc = sense + 8; + int ret = 0; + + memset(sense, 0, 32 * sizeof(uint8_t)); + memset(&io_v4, 0, sizeof(struct sg_io_v4)); + memset(&io_hdr, 0, sizeof(struct sg_io_hdr)); + + /* + * ATA Pass-Through 16 byte command, as described in + * + * T10 04-262r8 ATA Command Pass-Through + * + * from http://www.t10.org/ftp/t10/document.04/04-262r8.pdf + */ + cdb[0] = 0x85; /* OPERATION CODE: 16 byte pass through */ + cdb[1] = 4 << 1; /* PROTOCOL: PIO Data-in */ + cdb[2] = 0x2e; /* OFF_LINE=0, CK_COND=1, T_DIR=1, BYT_BLOK=1, T_LENGTH=2 */ + cdb[3] = 0; /* FEATURES */ + cdb[4] = 0; /* FEATURES */ + cdb[5] = 0; /* SECTORS */ + cdb[6] = 1; /* SECTORS */ + cdb[7] = 0; /* LBA LOW */ + cdb[8] = 0; /* LBA LOW */ + cdb[9] = 0; /* LBA MID */ + cdb[10] = 0; /* LBA MID */ + cdb[11] = 0; /* LBA HIGH */ + cdb[12] = 0; /* LBA HIGH */ + cdb[13] = 0; /* DEVICE */ + cdb[14] = 0xA1; /* Command: ATA IDENTIFY PACKET DEVICE */ + cdb[15] = 0; /* CONTROL */ + + io_v4.guard = 'Q'; + io_v4.protocol = BSG_PROTOCOL_SCSI; + io_v4.subprotocol = BSG_SUB_PROTOCOL_SCSI_CMD; + io_v4.request_len = sizeof(cdb); + io_v4.request = (uintptr_t) cdb; + io_v4.max_response_len = sizeof(sense); + io_v4.response = (uintptr_t) sense; + io_v4.din_xfer_len = buf_len; + io_v4.din_xferp = (uintptr_t) buf; + io_v4.timeout = COMMAND_TIMEOUT_MSEC; + + ret = ioctl(fd, SG_IO, &io_v4); + if (ret != 0) { + /* could be that the driver doesn't do version 4, try version 3 */ + if (errno == EINVAL) { + + io_hdr.interface_id = 'S'; + io_hdr.cmdp = (unsigned char *)cdb; + io_hdr.cmd_len = sizeof(cdb); + io_hdr.dxferp = buf; + io_hdr.dxfer_len = buf_len; + io_hdr.sbp = sense; + io_hdr.mx_sb_len = sizeof(sense); + io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; + io_hdr.timeout = COMMAND_TIMEOUT_MSEC; + + ret = ioctl(fd, SG_IO, &io_hdr); + if (ret != 0) { + return ret; + } + + } else { + return ret; + } + } + + if (!(sense[0] == 0x72 && desc[0] == 0x9 && desc[1] == 0x0c)) { + errno = EIO; + return -1; + } + + return 0; } /** @@ -317,33 +316,41 @@ static int disk_identify_packet_device_command(int fd, void *buf, size_t buf_len * * Copies the ATA string from @identify located at @offset_words into @dest. */ -static void disk_identify_get_string(uint8_t identify[512], unsigned int offset_words, char *dest, size_t dest_len) { - - unsigned int c1; - unsigned int c2; - - while (dest_len > 0) { - c1 = identify[offset_words * 2 + 1]; - c2 = identify[offset_words * 2]; - *dest = c1; - dest++; - *dest = c2; - dest++; - offset_words++; - dest_len -= 2; - } +static void disk_identify_get_string(uint8_t identify[512], + unsigned int offset_words, char *dest, + size_t dest_len) +{ + + unsigned int c1; + unsigned int c2; + + while (dest_len > 0) { + c1 = identify[offset_words * 2 + 1]; + c2 = identify[offset_words * 2]; + *dest = c1; + dest++; + *dest = c2; + dest++; + offset_words++; + dest_len -= 2; + } } -static void disk_identify_fixup_string(uint8_t identify[512], unsigned int offset_words, size_t len) { - - disk_identify_get_string(identify, offset_words, (char *) identify + offset_words * 2, len); +static void disk_identify_fixup_string(uint8_t identify[512], + unsigned int offset_words, size_t len) +{ + + disk_identify_get_string(identify, offset_words, + (char *)identify + offset_words * 2, len); } -static void disk_identify_fixup_uint16 (uint8_t identify[512], unsigned int offset_words) { - uint16_t *p; +static void disk_identify_fixup_uint16(uint8_t identify[512], + unsigned int offset_words) +{ + uint16_t *p; - p = (uint16_t *) identify; - p[offset_words] = le16toh (p[offset_words]); + p = (uint16_t *) identify; + p[offset_words] = le16toh(p[offset_words]); } /** @@ -363,413 +370,441 @@ static void disk_identify_fixup_uint16 (uint8_t identify[512], unsigned int offs * Returns: 0 if the data was successfully obtained, otherwise * non-zero with errno set. */ -static int disk_identify(int fd, uint8_t out_identify[512], int *out_is_packet_device) { - - int ret; - uint8_t inquiry_buf[36]; - int peripheral_device_type = 0; - int all_nul_bytes = 1; - int n = 0; - int is_packet_device = 0; - - /* init results */ - memset(out_identify, 0, 512); - - /* If we were to use ATA PASS_THROUGH (12) on an ATAPI device - * we could accidentally blank media. This is because MMC's BLANK - * command has the same op-code (0x61). - * - * To prevent this from happening we bail out if the device - * isn't a Direct Access Block Device, e.g. SCSI type 0x00 - * (CD/DVD devices are type 0x05). So we send a SCSI INQUIRY - * command first... libata is handling this via its SCSI - * emulation layer. - * - * This also ensures that we're actually dealing with a device - * that understands SCSI commands. - * - * (Yes, it is a bit perverse that we're tunneling the ATA - * command through SCSI and relying on the ATA driver - * emulating SCSI well-enough...) - * - * (See commit 160b069c25690bfb0c785994c7c3710289179107 for - * the original bug-fix and see http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=556635 - * for the original bug-report.) - */ - ret = disk_scsi_inquiry_command (fd, inquiry_buf, sizeof (inquiry_buf)); - if (ret != 0) { - - goto out; - } - - /* SPC-4, section 6.4.2: Standard INQUIRY data */ - peripheral_device_type = inquiry_buf[0] & 0x1f; - if (peripheral_device_type == 0x05) { - - is_packet_device = 1; - ret = disk_identify_packet_device_command(fd, out_identify, 512); - goto check_nul_bytes; - } - if (peripheral_device_type != 0x00) { - ret = -1; - errno = EIO; - - goto out; - } - - /* OK, now issue the IDENTIFY DEVICE command */ - ret = disk_identify_command(fd, out_identify, 512); - if (ret != 0) { - - goto out; - } - -check_nul_bytes: - /* Check if IDENTIFY data is all NUL bytes - if so, bail */ - all_nul_bytes = 1; - for (n = 0; n < 512; n++) { - if (out_identify[n] != '\0') { - all_nul_bytes = 0; - break; - } - } - - if (all_nul_bytes) { - - ret = -1; - errno = EIO; - goto out; - } - -out: - if (out_is_packet_device != NULL) { - *out_is_packet_device = is_packet_device; - } - return ret; +static int disk_identify(int fd, uint8_t out_identify[512], + int *out_is_packet_device) +{ + + int ret; + uint8_t inquiry_buf[36]; + int peripheral_device_type = 0; + int all_nul_bytes = 1; + int n = 0; + int is_packet_device = 0; + + /* init results */ + memset(out_identify, 0, 512); + + /* If we were to use ATA PASS_THROUGH (12) on an ATAPI device + * we could accidentally blank media. This is because MMC's BLANK + * command has the same op-code (0x61). + * + * To prevent this from happening we bail out if the device + * isn't a Direct Access Block Device, e.g. SCSI type 0x00 + * (CD/DVD devices are type 0x05). So we send a SCSI INQUIRY + * command first... libata is handling this via its SCSI + * emulation layer. + * + * This also ensures that we're actually dealing with a device + * that understands SCSI commands. + * + * (Yes, it is a bit perverse that we're tunneling the ATA + * command through SCSI and relying on the ATA driver + * emulating SCSI well-enough...) + * + * (See commit 160b069c25690bfb0c785994c7c3710289179107 for + * the original bug-fix and see http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=556635 + * for the original bug-report.) + */ + ret = disk_scsi_inquiry_command(fd, inquiry_buf, sizeof(inquiry_buf)); + if (ret != 0) { + + goto out; + } + + /* SPC-4, section 6.4.2: Standard INQUIRY data */ + peripheral_device_type = inquiry_buf[0] & 0x1f; + if (peripheral_device_type == 0x05) { + + is_packet_device = 1; + ret = + disk_identify_packet_device_command(fd, out_identify, 512); + goto check_nul_bytes; + } + if (peripheral_device_type != 0x00) { + ret = -1; + errno = EIO; + + goto out; + } + + /* OK, now issue the IDENTIFY DEVICE command */ + ret = disk_identify_command(fd, out_identify, 512); + if (ret != 0) { + + goto out; + } + + check_nul_bytes: + /* Check if IDENTIFY data is all NUL bytes - if so, bail */ + all_nul_bytes = 1; + for (n = 0; n < 512; n++) { + if (out_identify[n] != '\0') { + all_nul_bytes = 0; + break; + } + } + + if (all_nul_bytes) { + + ret = -1; + errno = EIO; + goto out; + } + + out: + if (out_is_packet_device != NULL) { + *out_is_packet_device = is_packet_device; + } + return ret; } - // entry point -int main(int argc, char **argv ) { - - struct hd_driveid id; - union { - uint8_t byte[512]; - uint16_t wyde[256]; - uint64_t octa[64]; - } identify; - - int fd = 0; - char model[41]; - char model_enc[256]; - char serial[21]; - char revision[9]; - const char *node = NULL; - uint16_t word = 0; - int is_packet_device = 0; - int rc = 0; - - // check usage - if( argc != 2 ) { - fprintf(stderr, "[ERROR] %s: Usage: %s /path/to/device/file\n", argv[0], argv[0]); - exit(1); - } - - node = argv[1]; - - fd = open(node, O_RDONLY|O_NONBLOCK|O_CLOEXEC); - if (fd < 0) { - fprintf(stderr, "[ERROR] %s: unable to open '%s'\n", argv[0], node); - exit(1); - } - - rc = disk_identify(fd, identify.byte, &is_packet_device); - if( rc == 0 ) { - /* - * fix up only the fields from the IDENTIFY data that we are going to - * use and copy it into the hd_driveid struct for convenience - */ - disk_identify_fixup_string(identify.byte, 10, 20); /* serial */ - disk_identify_fixup_string(identify.byte, 23, 8); /* fwrev */ - disk_identify_fixup_string(identify.byte, 27, 40); /* model */ - disk_identify_fixup_uint16(identify.byte, 0); /* configuration */ - disk_identify_fixup_uint16(identify.byte, 75); /* queue depth */ - disk_identify_fixup_uint16(identify.byte, 75); /* SATA capabilities */ - disk_identify_fixup_uint16(identify.byte, 82); /* command set supported */ - disk_identify_fixup_uint16(identify.byte, 83); /* command set supported */ - disk_identify_fixup_uint16(identify.byte, 84); /* command set supported */ - disk_identify_fixup_uint16(identify.byte, 85); /* command set supported */ - disk_identify_fixup_uint16(identify.byte, 86); /* command set supported */ - disk_identify_fixup_uint16(identify.byte, 87); /* command set supported */ - disk_identify_fixup_uint16(identify.byte, 89); /* time required for SECURITY ERASE UNIT */ - disk_identify_fixup_uint16(identify.byte, 90); /* time required for enhanced SECURITY ERASE UNIT */ - disk_identify_fixup_uint16(identify.byte, 91); /* current APM values */ - disk_identify_fixup_uint16(identify.byte, 94); /* current AAM value */ - disk_identify_fixup_uint16(identify.byte, 128); /* device lock function */ - disk_identify_fixup_uint16(identify.byte, 217); /* nominal media rotation rate */ - memcpy(&id, identify.byte, sizeof id); - } - else { - - /* If this fails, then try HDIO_GET_IDENTITY */ - if (ioctl(fd, HDIO_GET_IDENTITY, &id) != 0) { - int errsv = -errno; - fprintf( stderr, "[ERROR] %s: HDIO_GET_IDENTITY failed for '%s': errno = %d\n", argv[0], node, errsv); - close(fd); - exit(2); - } - } - - memcpy (model, id.model, 40); - model[40] = '\0'; - - vdev_util_encode_string(model, model_enc, sizeof(model_enc)); - vdev_util_replace_whitespace((char *) id.model, model, 40); - vdev_util_replace_chars(model, NULL); - vdev_util_replace_whitespace((char *) id.serial_no, serial, 20); - vdev_util_replace_chars(serial, NULL); - vdev_util_replace_whitespace((char *) id.fw_rev, revision, 8); - vdev_util_replace_chars(revision, NULL); - - - /* Set this to convey the disk speaks the ATA protocol */ - vdev_property_add( "VDEV_ATA", "1" ); - - if ((id.config >> 8) & 0x80) { - /* This is an ATAPI device */ - switch ((id.config >> 8) & 0x1f) { - case 0: - - vdev_property_add( "VDEV_ATA_TYPE", "cd" ); - break; - - case 1: - - vdev_property_add("VDEV_ATA_TYPE", "tape" ); - break; - - case 5: - - vdev_property_add("VDEV_ATA_TYPE", "cd" ); - break; - - case 7: - - vdev_property_add("VDEV_ATA_TYPE", "optical" ); - break; - - default: - - vdev_property_add("VDEV_ATA_TYPE", "generic" ); - break; - } - } - else { - - vdev_property_add("VDEV_ATA_TYPE", "disk" ); - } - - vdev_property_add("VDEV_ATA_MODEL", model ); - vdev_property_add("VDEV_ATA_MODEL_ENC", model_enc ); - vdev_property_add("VDEV_ATA_REVISION", revision ); - - if (serial[0] != '\0') { - - char serial_buf[100]; - memset( serial_buf, 0, 100 ); - - snprintf( serial_buf, 99, "%s_%s", model, serial ); - - vdev_property_add("VDEV_ATA_SERIAL", serial_buf ); - vdev_property_add("VDEV_ATA_SERIAL_SHORT", serial ); - - } - else { - - vdev_property_add("VDEV_ATA_SERIAL", model ); - } - - if (id.command_set_1 & (1<<5)) { - - vdev_property_add("VDEV_ATA_WRITE_CACHE", "1" ); - vdev_property_add("VDEV_ATA_WRITE_CACHE_ENABLED", (id.cfs_enable_1 & (1<<5)) ? "1" : "0" ); - } - if (id.command_set_1 & (1<<10)) { - - vdev_property_add("VDEV_ATA_FEATURE_SET_HPA", "1" ); - vdev_property_add("VDEV_ATA_FEATURE_SET_HPA_ENABLED", (id.cfs_enable_1 & (1<<10)) ? "1" : "0"); - - /* - * TODO: use the READ NATIVE MAX ADDRESS command to get the native max address - * so it is easy to check whether the protected area is in use. - */ - } - if (id.command_set_1 & (1<<3)) { - - vdev_property_add("VDEV_ATA_FEATURE_SET_PM", "1" ); - vdev_property_add("VDEV_ATA_FEATURE_SET_PM_ENABLED", (id.cfs_enable_1 & (1<<3)) ? "1" : "0"); - } - if (id.command_set_1 & (1<<1)) { - - char buf[100]; - memset( buf, 0, 100 ); - snprintf( buf, 99, "%d", id.trseuc * 2 ); - - vdev_property_add("VDEV_ATA_FEATURE_SET_SECURITY", "1" ); - vdev_property_add("VDEV_ATA_FEATURE_SET_SECURITY_ENABLED", (id.cfs_enable_1 & (1<<1)) ? "1" : "0"); - vdev_property_add("VDEV_ATA_FEATURE_SET_SECURITY_ERASE_UNIT_MIN", buf ); - - if ((id.cfs_enable_1 & (1<<1))) /* enabled */ { - - if (id.dlf & (1<<8)) { - - vdev_property_add( "VDEV_ATA_FEATURE_SET_SECURITY_LEVEL", "maximum" ); - } - else { - - vdev_property_add("VDEV_ATA_FEATURE_SET_SECURITY_LEVEL", "high" ); - } - } - if (id.dlf & (1<<5)) { - - memset( buf, 0, 100 ); - snprintf( buf, 99, "%d", id.trsEuc * 2 ); - - vdev_property_add("VDEV_ATA_FEATURE_SET_SECURITY_ENHANCED_ERASE_UNIT_MIN", buf ); - } - if (id.dlf & (1<<4)) { - - vdev_property_add("VDEV_ATA_FEATURE_SET_SECURITY_EXPIRE", "1" ); - } - if (id.dlf & (1<<3)) { - - vdev_property_add("VDEV_ATA_FEATURE_SET_SECURITY_FROZEN", "1" ); - } - if (id.dlf & (1<<2)) { - - vdev_property_add("VDEV_ATA_FEATURE_SET_SECURITY_LEVEL", "1" ); - } - } - if (id.command_set_1 & (1<<0)) { - - vdev_property_add("VDEV_ATA_FEATURE_SET_SMART", "1" ); - vdev_property_add("VDEV_ATA_FEATURE_SET_SMART_ENABLED", (id.cfs_enable_1 & (1<<0)) ? "1" : "0"); - } - if (id.command_set_2 & (1<<9)) { - - char aam_buf[100]; - char aam_cur_buf[100]; - - memset( aam_buf, 0, 100 ); - memset( aam_cur_buf, 0, 100 ); - - snprintf( aam_buf, 99, "%d", id.acoustic >> 8 ); - snprintf( aam_cur_buf, 99, "%d", id.acoustic & 0xff ); - - vdev_property_add("VDEV_ATA_FEATURE_SET_AAM", "1" ); - vdev_property_add("VDEV_ATA_FEATURE_SET_AAM_ENABLED", (id.cfs_enable_2 & (1<<9)) ? "1" : "0"); - vdev_property_add("VDEV_ATA_FEATURE_SET_AAM_VENDOR_RECOMMENDED_VALUE", aam_buf ); - vdev_property_add("VDEV_ATA_FEATURE_SET_AAM_CURRENT_VALUE", aam_cur_buf ); - } - if (id.command_set_2 & (1<<5)) { - - vdev_property_add("VDEV_ATA_FEATURE_SET_PUIS", "1" ); - vdev_property_add("VDEV_ATA_FEATURE_SET_PUIS_ENABLED", (id.cfs_enable_2 & (1<<5)) ? "1" : "0"); - } - if (id.command_set_2 & (1<<3)) { - - vdev_property_add("VDEV_ATA_FEATURE_SET_APM", "1" ); - vdev_property_add("VDEV_ATA_FEATURE_SET_APM_ENABLED", (id.cfs_enable_2 & (1<<3)) ? "1" : "0"); - - if ((id.cfs_enable_2 & (1<<3))) { - - char apm_cur_buf[100]; - - memset( apm_cur_buf, 0, 100 ); - - snprintf( apm_cur_buf, 99, "%d", id.CurAPMvalues & 0xff ); - - vdev_property_add("VDEV_ATA_FEATURE_SET_APM_CURRENT_VALUE", apm_cur_buf ); - } - } - if (id.command_set_2 & (1<<0)) { - - vdev_property_add("VDEV_ATA_DOWNLOAD_MICROCODE", "1" ); - } - - /* - * Word 76 indicates the capabilities of a SATA device. A PATA device shall set - * word 76 to 0000h or FFFFh. If word 76 is set to 0000h or FFFFh, then - * the device does not claim compliance with the Serial ATA specification and words - * 76 through 79 are not valid and shall be ignored. - */ - - word = identify.wyde[76]; - if (word != 0x0000 && word != 0xffff) { - - vdev_property_add("VDEV_ATA_SATA", "1" ); - /* - * If bit 2 of word 76 is set to one, then the device supports the Gen2 - * signaling rate of 3.0 Gb/s (see SATA 2.6). - * - * If bit 1 of word 76 is set to one, then the device supports the Gen1 - * signaling rate of 1.5 Gb/s (see SATA 2.6). - */ - if (word & (1<<2)) { - - vdev_property_add("VDEV_ATA_SATA_SIGNAL_RATE_GEN2", "1" ); - } - if (word & (1<<1)) { - - vdev_property_add("VDEV_ATA_SATA_SIGNAL_RATE_GEN1", "1" ); - } - } - - /* Word 217 indicates the nominal media rotation rate of the device */ - word = identify.wyde[217]; - if (word == 0x0001) { - - vdev_property_add("VDEV_ATA_ROTATION_RATE_RPM", "0" ); - } - else if (word >= 0x0401 && word <= 0xfffe) { - - char rpm_buf[100]; - - memset( rpm_buf, 0, 100 ); - - snprintf( rpm_buf, 99, "%d", word ); - - vdev_property_add("VDEV_ATA_ROTATION_RATE_RPM", rpm_buf ); - } - - /* - * Words 108-111 contain a mandatory World Wide Name (WWN) in the NAA IEEE Registered identifier - * format. Word 108 bits (15:12) shall contain 5h, indicating that the naming authority is IEEE. - * All other values are reserved. - */ - word = identify.wyde[108]; - if ((word & 0xf000) == 0x5000) { - - char wwn_buf[100]; - - memset( wwn_buf, 0, 100 ); - - snprintf( wwn_buf, 99, "0x%04x%04x%04x%04x", identify.wyde[108], identify.wyde[109], identify.wyde[110], identify.wyde[111]); - - vdev_property_add("VDEV_ATA_WWN", wwn_buf ); - vdev_property_add("VDEV_ATA_WWN_WITH_EXTENSION", wwn_buf ); - } - - /* from Linux's include/linux/ata.h */ - if (identify.wyde[0] == 0x848a || - identify.wyde[0] == 0x844a || - (identify.wyde[83] & 0xc004) == 0x4004) { - - vdev_property_add("VDEV_ATA_CFA", "1" ); - } - - vdev_property_print(); - vdev_property_free_all(); - - return 0; +int main(int argc, char **argv) +{ + + struct hd_driveid id; + union { + uint8_t byte[512]; + uint16_t wyde[256]; + uint64_t octa[64]; + } identify; + + int fd = 0; + char model[41]; + char model_enc[256]; + char serial[21]; + char revision[9]; + const char *node = NULL; + uint16_t word = 0; + int is_packet_device = 0; + int rc = 0; + + // check usage + if (argc != 2) { + fprintf(stderr, "[ERROR] %s: Usage: %s /path/to/device/file\n", + argv[0], argv[0]); + exit(1); + } + + node = argv[1]; + + fd = open(node, O_RDONLY | O_NONBLOCK | O_CLOEXEC); + if (fd < 0) { + fprintf(stderr, "[ERROR] %s: unable to open '%s'\n", argv[0], + node); + exit(1); + } + + rc = disk_identify(fd, identify.byte, &is_packet_device); + if (rc == 0) { + /* + * fix up only the fields from the IDENTIFY data that we are going to + * use and copy it into the hd_driveid struct for convenience + */ + disk_identify_fixup_string(identify.byte, 10, 20); /* serial */ + disk_identify_fixup_string(identify.byte, 23, 8); /* fwrev */ + disk_identify_fixup_string(identify.byte, 27, 40); /* model */ + disk_identify_fixup_uint16(identify.byte, 0); /* configuration */ + disk_identify_fixup_uint16(identify.byte, 75); /* queue depth */ + disk_identify_fixup_uint16(identify.byte, 75); /* SATA capabilities */ + disk_identify_fixup_uint16(identify.byte, 82); /* command set supported */ + disk_identify_fixup_uint16(identify.byte, 83); /* command set supported */ + disk_identify_fixup_uint16(identify.byte, 84); /* command set supported */ + disk_identify_fixup_uint16(identify.byte, 85); /* command set supported */ + disk_identify_fixup_uint16(identify.byte, 86); /* command set supported */ + disk_identify_fixup_uint16(identify.byte, 87); /* command set supported */ + disk_identify_fixup_uint16(identify.byte, 89); /* time required for SECURITY ERASE UNIT */ + disk_identify_fixup_uint16(identify.byte, 90); /* time required for enhanced SECURITY ERASE UNIT */ + disk_identify_fixup_uint16(identify.byte, 91); /* current APM values */ + disk_identify_fixup_uint16(identify.byte, 94); /* current AAM value */ + disk_identify_fixup_uint16(identify.byte, 128); /* device lock function */ + disk_identify_fixup_uint16(identify.byte, 217); /* nominal media rotation rate */ + memcpy(&id, identify.byte, sizeof id); + } else { + + /* If this fails, then try HDIO_GET_IDENTITY */ + if (ioctl(fd, HDIO_GET_IDENTITY, &id) != 0) { + int errsv = -errno; + fprintf(stderr, + "[ERROR] %s: HDIO_GET_IDENTITY failed for '%s': errno = %d\n", + argv[0], node, errsv); + close(fd); + exit(2); + } + } + + memcpy(model, id.model, 40); + model[40] = '\0'; + + vdev_util_encode_string(model, model_enc, sizeof(model_enc)); + vdev_util_replace_whitespace((char *)id.model, model, 40); + vdev_util_replace_chars(model, NULL); + vdev_util_replace_whitespace((char *)id.serial_no, serial, 20); + vdev_util_replace_chars(serial, NULL); + vdev_util_replace_whitespace((char *)id.fw_rev, revision, 8); + vdev_util_replace_chars(revision, NULL); + + /* Set this to convey the disk speaks the ATA protocol */ + vdev_property_add("VDEV_ATA", "1"); + + if ((id.config >> 8) & 0x80) { + /* This is an ATAPI device */ + switch ((id.config >> 8) & 0x1f) { + case 0: + + vdev_property_add("VDEV_ATA_TYPE", "cd"); + break; + + case 1: + + vdev_property_add("VDEV_ATA_TYPE", "tape"); + break; + + case 5: + + vdev_property_add("VDEV_ATA_TYPE", "cd"); + break; + + case 7: + + vdev_property_add("VDEV_ATA_TYPE", "optical"); + break; + + default: + + vdev_property_add("VDEV_ATA_TYPE", "generic"); + break; + } + } else { + + vdev_property_add("VDEV_ATA_TYPE", "disk"); + } + + vdev_property_add("VDEV_ATA_MODEL", model); + vdev_property_add("VDEV_ATA_MODEL_ENC", model_enc); + vdev_property_add("VDEV_ATA_REVISION", revision); + + if (serial[0] != '\0') { + + char serial_buf[100]; + memset(serial_buf, 0, 100); + + snprintf(serial_buf, 99, "%s_%s", model, serial); + + vdev_property_add("VDEV_ATA_SERIAL", serial_buf); + vdev_property_add("VDEV_ATA_SERIAL_SHORT", serial); + + } else { + + vdev_property_add("VDEV_ATA_SERIAL", model); + } + + if (id.command_set_1 & (1 << 5)) { + + vdev_property_add("VDEV_ATA_WRITE_CACHE", "1"); + vdev_property_add("VDEV_ATA_WRITE_CACHE_ENABLED", + (id.cfs_enable_1 & (1 << 5)) ? "1" : "0"); + } + if (id.command_set_1 & (1 << 10)) { + + vdev_property_add("VDEV_ATA_FEATURE_SET_HPA", "1"); + vdev_property_add("VDEV_ATA_FEATURE_SET_HPA_ENABLED", + (id.cfs_enable_1 & (1 << 10)) ? "1" : "0"); + + /* + * TODO: use the READ NATIVE MAX ADDRESS command to get the native max address + * so it is easy to check whether the protected area is in use. + */ + } + if (id.command_set_1 & (1 << 3)) { + + vdev_property_add("VDEV_ATA_FEATURE_SET_PM", "1"); + vdev_property_add("VDEV_ATA_FEATURE_SET_PM_ENABLED", + (id.cfs_enable_1 & (1 << 3)) ? "1" : "0"); + } + if (id.command_set_1 & (1 << 1)) { + + char buf[100]; + memset(buf, 0, 100); + snprintf(buf, 99, "%d", id.trseuc * 2); + + vdev_property_add("VDEV_ATA_FEATURE_SET_SECURITY", "1"); + vdev_property_add("VDEV_ATA_FEATURE_SET_SECURITY_ENABLED", + (id.cfs_enable_1 & (1 << 1)) ? "1" : "0"); + vdev_property_add + ("VDEV_ATA_FEATURE_SET_SECURITY_ERASE_UNIT_MIN", buf); + + if ((id.cfs_enable_1 & (1 << 1))) { /* enabled */ + + if (id.dlf & (1 << 8)) { + + vdev_property_add + ("VDEV_ATA_FEATURE_SET_SECURITY_LEVEL", + "maximum"); + } else { + + vdev_property_add + ("VDEV_ATA_FEATURE_SET_SECURITY_LEVEL", + "high"); + } + } + if (id.dlf & (1 << 5)) { + + memset(buf, 0, 100); + snprintf(buf, 99, "%d", id.trsEuc * 2); + + vdev_property_add + ("VDEV_ATA_FEATURE_SET_SECURITY_ENHANCED_ERASE_UNIT_MIN", + buf); + } + if (id.dlf & (1 << 4)) { + + vdev_property_add + ("VDEV_ATA_FEATURE_SET_SECURITY_EXPIRE", "1"); + } + if (id.dlf & (1 << 3)) { + + vdev_property_add + ("VDEV_ATA_FEATURE_SET_SECURITY_FROZEN", "1"); + } + if (id.dlf & (1 << 2)) { + + vdev_property_add("VDEV_ATA_FEATURE_SET_SECURITY_LEVEL", + "1"); + } + } + if (id.command_set_1 & (1 << 0)) { + + vdev_property_add("VDEV_ATA_FEATURE_SET_SMART", "1"); + vdev_property_add("VDEV_ATA_FEATURE_SET_SMART_ENABLED", + (id.cfs_enable_1 & (1 << 0)) ? "1" : "0"); + } + if (id.command_set_2 & (1 << 9)) { + + char aam_buf[100]; + char aam_cur_buf[100]; + + memset(aam_buf, 0, 100); + memset(aam_cur_buf, 0, 100); + + snprintf(aam_buf, 99, "%d", id.acoustic >> 8); + snprintf(aam_cur_buf, 99, "%d", id.acoustic & 0xff); + + vdev_property_add("VDEV_ATA_FEATURE_SET_AAM", "1"); + vdev_property_add("VDEV_ATA_FEATURE_SET_AAM_ENABLED", + (id.cfs_enable_2 & (1 << 9)) ? "1" : "0"); + vdev_property_add + ("VDEV_ATA_FEATURE_SET_AAM_VENDOR_RECOMMENDED_VALUE", + aam_buf); + vdev_property_add("VDEV_ATA_FEATURE_SET_AAM_CURRENT_VALUE", + aam_cur_buf); + } + if (id.command_set_2 & (1 << 5)) { + + vdev_property_add("VDEV_ATA_FEATURE_SET_PUIS", "1"); + vdev_property_add("VDEV_ATA_FEATURE_SET_PUIS_ENABLED", + (id.cfs_enable_2 & (1 << 5)) ? "1" : "0"); + } + if (id.command_set_2 & (1 << 3)) { + + vdev_property_add("VDEV_ATA_FEATURE_SET_APM", "1"); + vdev_property_add("VDEV_ATA_FEATURE_SET_APM_ENABLED", + (id.cfs_enable_2 & (1 << 3)) ? "1" : "0"); + + if ((id.cfs_enable_2 & (1 << 3))) { + + char apm_cur_buf[100]; + + memset(apm_cur_buf, 0, 100); + + snprintf(apm_cur_buf, 99, "%d", id.CurAPMvalues & 0xff); + + vdev_property_add + ("VDEV_ATA_FEATURE_SET_APM_CURRENT_VALUE", + apm_cur_buf); + } + } + if (id.command_set_2 & (1 << 0)) { + + vdev_property_add("VDEV_ATA_DOWNLOAD_MICROCODE", "1"); + } + + /* + * Word 76 indicates the capabilities of a SATA device. A PATA device shall set + * word 76 to 0000h or FFFFh. If word 76 is set to 0000h or FFFFh, then + * the device does not claim compliance with the Serial ATA specification and words + * 76 through 79 are not valid and shall be ignored. + */ + + word = identify.wyde[76]; + if (word != 0x0000 && word != 0xffff) { + + vdev_property_add("VDEV_ATA_SATA", "1"); + /* + * If bit 2 of word 76 is set to one, then the device supports the Gen2 + * signaling rate of 3.0 Gb/s (see SATA 2.6). + * + * If bit 1 of word 76 is set to one, then the device supports the Gen1 + * signaling rate of 1.5 Gb/s (see SATA 2.6). + */ + if (word & (1 << 2)) { + + vdev_property_add("VDEV_ATA_SATA_SIGNAL_RATE_GEN2", + "1"); + } + if (word & (1 << 1)) { + + vdev_property_add("VDEV_ATA_SATA_SIGNAL_RATE_GEN1", + "1"); + } + } + + /* Word 217 indicates the nominal media rotation rate of the device */ + word = identify.wyde[217]; + if (word == 0x0001) { + + vdev_property_add("VDEV_ATA_ROTATION_RATE_RPM", "0"); + } else if (word >= 0x0401 && word <= 0xfffe) { + + char rpm_buf[100]; + + memset(rpm_buf, 0, 100); + + snprintf(rpm_buf, 99, "%d", word); + + vdev_property_add("VDEV_ATA_ROTATION_RATE_RPM", rpm_buf); + } + + /* + * Words 108-111 contain a mandatory World Wide Name (WWN) in the NAA IEEE Registered identifier + * format. Word 108 bits (15:12) shall contain 5h, indicating that the naming authority is IEEE. + * All other values are reserved. + */ + word = identify.wyde[108]; + if ((word & 0xf000) == 0x5000) { + + char wwn_buf[100]; + + memset(wwn_buf, 0, 100); + + snprintf(wwn_buf, 99, "0x%04x%04x%04x%04x", identify.wyde[108], + identify.wyde[109], identify.wyde[110], + identify.wyde[111]); + + vdev_property_add("VDEV_ATA_WWN", wwn_buf); + vdev_property_add("VDEV_ATA_WWN_WITH_EXTENSION", wwn_buf); + } + + /* from Linux's include/linux/ata.h */ + if (identify.wyde[0] == 0x848a || + identify.wyde[0] == 0x844a || + (identify.wyde[83] & 0xc004) == 0x4004) { + + vdev_property_add("VDEV_ATA_CFA", "1"); + } + + vdev_property_print(); + vdev_property_free_all(); + + return 0; } diff --git a/vdevd/helpers/LINUX/stat_bus.c b/vdevd/helpers/LINUX/stat_bus.c index ca7c12f..984e336 100644 --- a/vdevd/helpers/LINUX/stat_bus.c +++ b/vdevd/helpers/LINUX/stat_bus.c @@ -22,146 +22,149 @@ // determine what kind of busses we're on #include "common.h" -void usage( char const* progname ) { - - fprintf(stderr, "[ERROR] %s: Usage: %s /sysfs/path/to/device\n", progname, progname ); - exit(1); +void usage(char const *progname) +{ + + fprintf(stderr, "[ERROR] %s: Usage: %s /sysfs/path/to/device\n", + progname, progname); + exit(1); } // lop off the child of a directory // return 0 on success // return -ENOENT if there is no child to remove -int remove_child( char* path ) { - - char* delim = NULL; - - delim = strrchr( path, '/' ); - if( delim == NULL || delim == path ) { - return -ENOENT; - } - - while( *delim == '/' && delim != path ) { - *delim = '\0'; - delim--; - } - - return 0; +int remove_child(char *path) +{ + + char *delim = NULL; + + delim = strrchr(path, '/'); + if (delim == NULL || delim == path) { + return -ENOENT; + } + + while (*delim == '/' && delim != path) { + *delim = '\0'; + delim--; + } + + return 0; } - -int main( int argc, char** argv ) { - - if( argc != 2 ) { - usage( argv[0] ); - } - - char* next_bus = NULL; - char subsystem_list[ 4097 ]; - char subsystem_list_uniq[ 4097 ]; - char* delim = NULL; - char* subsystem_buf = (char*)calloc( strlen(argv[1]) + strlen("/subsystem") + 1, 1 ); - char readlink_buf[ 4097 ]; - int rc = 0; - struct stat sb; - - if( subsystem_buf == NULL ) { - exit(1); - } - - next_bus = argv[1]; - memset( subsystem_list, 0, 4097 ); - memset( subsystem_list_uniq, 0, 4097 ); - - // directory must exist - rc = stat( next_bus, &sb ); - if( rc != 0 ) { - exit(1); - } - - while( 1 ) { - - // what's the subsystem here? - sprintf( subsystem_buf, "%s/subsystem", next_bus ); - - rc = lstat( subsystem_buf, &sb ); - if( rc != 0 ) { - - rc = remove_child( next_bus ); - if( rc != 0 ) { - break; - } - else { - continue; - } - } - - if( !S_ISLNK( sb.st_mode ) ) { - - rc = remove_child( next_bus ); - if( rc != 0 ) { - break; - } - else { - continue; - } - } - - memset( readlink_buf, 0, 4097 ); - - rc = readlink( subsystem_buf, readlink_buf, 4096 ); - if( rc < 0 ) { - - rc = remove_child( next_bus ); - if( rc != 0 ) { - break; - } - else { - continue; - } - } - - delim = strrchr( readlink_buf, '/' ); - if( delim == NULL ) { - - rc = remove_child( next_bus ); - if( rc != 0 ) { - break; - } - else { - continue; - } - } - - // delim + 1 is the subsystem name - if( subsystem_list[0] != 0 ) { - strncat( subsystem_list, ",", 4096 - strlen(subsystem_list) - 1 ); - } - strncat( subsystem_list, delim + 1, 4096 - strlen(subsystem_list) - 1 ); - - if( strstr( subsystem_list_uniq, delim + 1 ) == NULL ) { - - // haven't seen this subsystem name before... - if( subsystem_list_uniq[0] != 0 ) { - strncat( subsystem_list_uniq, ",", 4096 - strlen(subsystem_list_uniq) - 1 ); - } - strncat( subsystem_list_uniq, delim + 1, 4096 - strlen(subsystem_list_uniq) - 1 ); - } - - rc = remove_child( next_bus ); - if( rc != 0 ) { - break; - } - else { - continue; - } - } - - free( subsystem_buf ); - - vdev_property_add( "VDEV_BUS_SUBSYSTEMS", subsystem_list ); - vdev_property_add( "VDEV_BUS_SUBSYSTEMS_UNIQ", subsystem_list_uniq ); - - vdev_property_print(); - vdev_property_free_all(); - - exit(0); + +int main(int argc, char **argv) +{ + + if (argc != 2) { + usage(argv[0]); + } + + char *next_bus = NULL; + char subsystem_list[4097]; + char subsystem_list_uniq[4097]; + char *delim = NULL; + char *subsystem_buf = + (char *)calloc(strlen(argv[1]) + strlen("/subsystem") + 1, 1); + char readlink_buf[4097]; + int rc = 0; + struct stat sb; + + if (subsystem_buf == NULL) { + exit(1); + } + + next_bus = argv[1]; + memset(subsystem_list, 0, 4097); + memset(subsystem_list_uniq, 0, 4097); + + // directory must exist + rc = stat(next_bus, &sb); + if (rc != 0) { + exit(1); + } + + while (1) { + + // what's the subsystem here? + sprintf(subsystem_buf, "%s/subsystem", next_bus); + + rc = lstat(subsystem_buf, &sb); + if (rc != 0) { + + rc = remove_child(next_bus); + if (rc != 0) { + break; + } else { + continue; + } + } + + if (!S_ISLNK(sb.st_mode)) { + + rc = remove_child(next_bus); + if (rc != 0) { + break; + } else { + continue; + } + } + + memset(readlink_buf, 0, 4097); + + rc = readlink(subsystem_buf, readlink_buf, 4096); + if (rc < 0) { + + rc = remove_child(next_bus); + if (rc != 0) { + break; + } else { + continue; + } + } + + delim = strrchr(readlink_buf, '/'); + if (delim == NULL) { + + rc = remove_child(next_bus); + if (rc != 0) { + break; + } else { + continue; + } + } + // delim + 1 is the subsystem name + if (subsystem_list[0] != 0) { + strncat(subsystem_list, ",", + 4096 - strlen(subsystem_list) - 1); + } + strncat(subsystem_list, delim + 1, + 4096 - strlen(subsystem_list) - 1); + + if (strstr(subsystem_list_uniq, delim + 1) == NULL) { + + // haven't seen this subsystem name before... + if (subsystem_list_uniq[0] != 0) { + strncat(subsystem_list_uniq, ",", + 4096 - strlen(subsystem_list_uniq) - 1); + } + strncat(subsystem_list_uniq, delim + 1, + 4096 - strlen(subsystem_list_uniq) - 1); + } + + rc = remove_child(next_bus); + if (rc != 0) { + break; + } else { + continue; + } + } + + free(subsystem_buf); + + vdev_property_add("VDEV_BUS_SUBSYSTEMS", subsystem_list); + vdev_property_add("VDEV_BUS_SUBSYSTEMS_UNIQ", subsystem_list_uniq); + + vdev_property_print(); + vdev_property_free_all(); + + exit(0); } diff --git a/vdevd/helpers/LINUX/stat_input.c b/vdevd/helpers/LINUX/stat_input.c index 7b12dab..a10c02c 100644 --- a/vdevd/helpers/LINUX/stat_input.c +++ b/vdevd/helpers/LINUX/stat_input.c @@ -32,7 +32,6 @@ * along with this program. If not, see . */ - #include "common.h" #include #include @@ -51,390 +50,413 @@ int g_input_class = 0; -static inline int abs_size_mm(const struct input_absinfo *absinfo) { - /* Resolution is defined to be in units/mm for ABS_X/Y */ - return (absinfo->maximum - absinfo->minimum) / absinfo->resolution; +static inline int abs_size_mm(const struct input_absinfo *absinfo) +{ + /* Resolution is defined to be in units/mm for ABS_X/Y */ + return (absinfo->maximum - absinfo->minimum) / absinfo->resolution; } -static void extract_input_resolution( const char *devpath ) { - - char width[50], height[50]; - struct input_absinfo xabsinfo = {}, yabsinfo = {}; - - int rc = 0; - int fd = -1; - - fd = open(devpath, O_RDONLY|O_CLOEXEC); - if (fd < 0) { - rc = -errno; - log_debug("failed to open '%s', errno = %d", devpath, rc ); - return; - } - - if (ioctl(fd, EVIOCGABS(ABS_X), &xabsinfo) < 0 || ioctl(fd, EVIOCGABS(ABS_Y), &yabsinfo) < 0) { - - close( fd ); - return; - } - - if (xabsinfo.resolution <= 0 || yabsinfo.resolution <= 0) { - - close( fd ); - return; - } - - snprintf(width, sizeof(width), "%d", abs_size_mm(&xabsinfo)); - snprintf(height, sizeof(height), "%d", abs_size_mm(&yabsinfo)); - - vdev_property_add( "VDEV_INPUT_WIDTH_MM", width ); - vdev_property_add( "VDEV_INPUT_HEIGHT_MM", height ); - - close( fd ); +static void extract_input_resolution(const char *devpath) +{ + + char width[50], height[50]; + struct input_absinfo xabsinfo = { }, yabsinfo = { + }; + + int rc = 0; + int fd = -1; + + fd = open(devpath, O_RDONLY | O_CLOEXEC); + if (fd < 0) { + rc = -errno; + log_debug("failed to open '%s', errno = %d", devpath, rc); + return; + } + + if (ioctl(fd, EVIOCGABS(ABS_X), &xabsinfo) < 0 + || ioctl(fd, EVIOCGABS(ABS_Y), &yabsinfo) < 0) { + + close(fd); + return; + } + + if (xabsinfo.resolution <= 0 || yabsinfo.resolution <= 0) { + + close(fd); + return; + } + + snprintf(width, sizeof(width), "%d", abs_size_mm(&xabsinfo)); + snprintf(height, sizeof(height), "%d", abs_size_mm(&yabsinfo)); + + vdev_property_add("VDEV_INPUT_WIDTH_MM", width); + vdev_property_add("VDEV_INPUT_HEIGHT_MM", height); + + close(fd); } /* * Read a capability attribute and return bitmask. * @param bitmask: Output array which has a length of bitmask_len */ -static void get_cap_mask( char const* sysfs_cap_path, unsigned long *bitmask, size_t bitmask_len) { - - char text[4096]; - unsigned i; - char* word; - unsigned long val; - int rc = 0; - - memset( text, 0, 4096 ); - - int fd = open( sysfs_cap_path, O_RDONLY ); - if( fd < 0 ) { - return; - } - - rc = vdev_read_uninterrupted( fd, text, 4096 ); - close( fd ); - - if( rc < 0 ) { - - log_debug("read('%s') errno = %d\n", sysfs_cap_path, rc ); - return; - } - - memset( bitmask, 0, bitmask_len * sizeof(unsigned long) ); - - i = 0; - - while ((word = strrchr(text, ' ')) != NULL) { - - val = strtoul (word+1, NULL, 16); - if (i < bitmask_len ) { - bitmask[i] = val; - } - else { - log_debug("ignoring %s block %lX which is larger than maximum length %zu", sysfs_cap_path, val, bitmask_len); - } - *word = '\0'; - ++i; - } - val = strtoul (text, NULL, 16); - if (i < bitmask_len) { - bitmask[i] = val; - } - else { - log_debug("ignoring %s block %lX which is larger than maximum length %zu", sysfs_cap_path, val, bitmask_len); - } - - log_debug("Bitmask path: %s, length: %zu, Text: '%s'", sysfs_cap_path, bitmask_len, text ); - for( unsigned int i = 0; i < bitmask_len; i++ ) { - log_debug("Bitmask[%d] = %lX", i, bitmask[i]); - } +static void get_cap_mask(char const *sysfs_cap_path, unsigned long *bitmask, + size_t bitmask_len) +{ + + char text[4096]; + unsigned i; + char *word; + unsigned long val; + int rc = 0; + + memset(text, 0, 4096); + + int fd = open(sysfs_cap_path, O_RDONLY); + if (fd < 0) { + return; + } + + rc = vdev_read_uninterrupted(fd, text, 4096); + close(fd); + + if (rc < 0) { + + log_debug("read('%s') errno = %d\n", sysfs_cap_path, rc); + return; + } + + memset(bitmask, 0, bitmask_len * sizeof(unsigned long)); + + i = 0; + + while ((word = strrchr(text, ' ')) != NULL) { + + val = strtoul(word + 1, NULL, 16); + if (i < bitmask_len) { + bitmask[i] = val; + } else { + log_debug + ("ignoring %s block %lX which is larger than maximum length %zu", + sysfs_cap_path, val, bitmask_len); + } + *word = '\0'; + ++i; + } + val = strtoul(text, NULL, 16); + if (i < bitmask_len) { + bitmask[i] = val; + } else { + log_debug + ("ignoring %s block %lX which is larger than maximum length %zu", + sysfs_cap_path, val, bitmask_len); + } + + log_debug("Bitmask path: %s, length: %zu, Text: '%s'", sysfs_cap_path, + bitmask_len, text); + for (unsigned int i = 0; i < bitmask_len; i++) { + log_debug("Bitmask[%d] = %lX", i, bitmask[i]); + } } /* pointer devices */ -static void test_pointers (const unsigned long* bitmask_ev, - const unsigned long* bitmask_abs, - const unsigned long* bitmask_key, - const unsigned long* bitmask_rel ) { - int is_mouse = 0; - int is_touchpad = 0; - - if (!test_bit (EV_KEY, bitmask_ev)) { - if (test_bit (EV_ABS, bitmask_ev) && - test_bit (ABS_X, bitmask_abs) && - test_bit (ABS_Y, bitmask_abs) && - test_bit (ABS_Z, bitmask_abs)) { - - vdev_property_add( "VDEV_INPUT_ACCELEROMETER", "1" ); - } - return; - } - - if (test_bit (EV_ABS, bitmask_ev) && test_bit (ABS_X, bitmask_abs) && test_bit (ABS_Y, bitmask_abs)) { - - if (test_bit (BTN_STYLUS, bitmask_key) || test_bit (BTN_TOOL_PEN, bitmask_key)) { - - vdev_property_add( "VDEV_INPUT_TABLET", "1" ); - - g_input_class = VDEV_INPUT_CLASS_MOUSE; - } - - else if (test_bit (BTN_TOOL_FINGER, bitmask_key) && !test_bit (BTN_TOOL_PEN, bitmask_key)) { - - is_touchpad = 1; - } - - else if (test_bit (BTN_MOUSE, bitmask_key)) { - /* This path is taken by VMware's USB mouse, which has - * absolute axes, but no touch/pressure button. */ - - is_mouse = 1; - } - - else if (test_bit (BTN_TOUCH, bitmask_key)) { - - vdev_property_add( "VDEV_INPUT_TOUCHSCREEN", "1" ); - - g_input_class = VDEV_INPUT_CLASS_MOUSE; - } - - /* joysticks don't necessarily have to have buttons; e. g. - * rudders/pedals are joystick-like, but buttonless; they have - * other fancy axes */ - else if (test_bit (BTN_TRIGGER, bitmask_key) || - test_bit (BTN_A, bitmask_key) || - test_bit (BTN_1, bitmask_key) || - test_bit (ABS_RX, bitmask_abs) || - test_bit (ABS_RY, bitmask_abs) || - test_bit (ABS_RZ, bitmask_abs) || - test_bit (ABS_THROTTLE, bitmask_abs) || - test_bit (ABS_RUDDER, bitmask_abs) || - test_bit (ABS_WHEEL, bitmask_abs) || - test_bit (ABS_GAS, bitmask_abs) || - test_bit (ABS_BRAKE, bitmask_abs)) { - - vdev_property_add( "VDEV_INPUT_JOYSTICK", "1" ); - - g_input_class = VDEV_INPUT_CLASS_JOYSTICK; - } - } - - if (test_bit (EV_REL, bitmask_ev) && - test_bit (REL_X, bitmask_rel) && test_bit (REL_Y, bitmask_rel) && - test_bit (BTN_MOUSE, bitmask_key)) { - - is_mouse = 1; - } - - if (is_mouse) { - - vdev_property_add( "VDEV_INPUT_MOUSE", "1" ); - - g_input_class = VDEV_INPUT_CLASS_MOUSE; - } - - if( is_touchpad ) { - - vdev_property_add( "VDEV_INPUT_TOUCHPAD", "1" ); - - g_input_class = VDEV_INPUT_CLASS_MOUSE; - } +static void test_pointers(const unsigned long *bitmask_ev, + const unsigned long *bitmask_abs, + const unsigned long *bitmask_key, + const unsigned long *bitmask_rel) +{ + int is_mouse = 0; + int is_touchpad = 0; + + if (!test_bit(EV_KEY, bitmask_ev)) { + if (test_bit(EV_ABS, bitmask_ev) && + test_bit(ABS_X, bitmask_abs) && + test_bit(ABS_Y, bitmask_abs) && + test_bit(ABS_Z, bitmask_abs)) { + + vdev_property_add("VDEV_INPUT_ACCELEROMETER", "1"); + } + return; + } + + if (test_bit(EV_ABS, bitmask_ev) && test_bit(ABS_X, bitmask_abs) + && test_bit(ABS_Y, bitmask_abs)) { + + if (test_bit(BTN_STYLUS, bitmask_key) + || test_bit(BTN_TOOL_PEN, bitmask_key)) { + + vdev_property_add("VDEV_INPUT_TABLET", "1"); + + g_input_class = VDEV_INPUT_CLASS_MOUSE; + } + + else if (test_bit(BTN_TOOL_FINGER, bitmask_key) + && !test_bit(BTN_TOOL_PEN, bitmask_key)) { + + is_touchpad = 1; + } + + else if (test_bit(BTN_MOUSE, bitmask_key)) { + /* This path is taken by VMware's USB mouse, which has + * absolute axes, but no touch/pressure button. */ + + is_mouse = 1; + } + + else if (test_bit(BTN_TOUCH, bitmask_key)) { + + vdev_property_add("VDEV_INPUT_TOUCHSCREEN", "1"); + + g_input_class = VDEV_INPUT_CLASS_MOUSE; + } + + /* joysticks don't necessarily have to have buttons; e. g. + * rudders/pedals are joystick-like, but buttonless; they have + * other fancy axes */ + else if (test_bit(BTN_TRIGGER, bitmask_key) || + test_bit(BTN_A, bitmask_key) || + test_bit(BTN_1, bitmask_key) || + test_bit(ABS_RX, bitmask_abs) || + test_bit(ABS_RY, bitmask_abs) || + test_bit(ABS_RZ, bitmask_abs) || + test_bit(ABS_THROTTLE, bitmask_abs) || + test_bit(ABS_RUDDER, bitmask_abs) || + test_bit(ABS_WHEEL, bitmask_abs) || + test_bit(ABS_GAS, bitmask_abs) || + test_bit(ABS_BRAKE, bitmask_abs)) { + + vdev_property_add("VDEV_INPUT_JOYSTICK", "1"); + + g_input_class = VDEV_INPUT_CLASS_JOYSTICK; + } + } + + if (test_bit(EV_REL, bitmask_ev) && + test_bit(REL_X, bitmask_rel) && test_bit(REL_Y, bitmask_rel) && + test_bit(BTN_MOUSE, bitmask_key)) { + + is_mouse = 1; + } + + if (is_mouse) { + + vdev_property_add("VDEV_INPUT_MOUSE", "1"); + + g_input_class = VDEV_INPUT_CLASS_MOUSE; + } + + if (is_touchpad) { + + vdev_property_add("VDEV_INPUT_TOUCHPAD", "1"); + + g_input_class = VDEV_INPUT_CLASS_MOUSE; + } } /* key like devices */ -static void test_key (const unsigned long* bitmask_ev, - const unsigned long* bitmask_key ) { - unsigned i; - unsigned long found; - unsigned long mask; - - /* do we have any KEY_* capability? */ - if (!test_bit (EV_KEY, bitmask_ev)) { - log_debug("%s", "test_key: no EV_KEY capability"); - return; - } - - /* only consider KEY_* here, not BTN_* */ - found = 0; - for (i = 0; i < BTN_MISC/BITS_PER_LONG; ++i) { - found |= bitmask_key[i]; - log_debug("test_key: checking bit block %lu for any keys; found=%i", (unsigned long)i*BITS_PER_LONG, found > 0); - } - - /* If there are no keys in the lower block, check the higher block */ - if (!found) { - for (i = KEY_OK; i < BTN_TRIGGER_HAPPY; ++i) { - if (test_bit (i, bitmask_key)) { - log_debug("test_key: Found key %x in high block", i); - found = 1; - break; - } - } - } - - if (found > 0) { - - vdev_property_add( "VDEV_INPUT_KEY", "1" ); - } - - /* the first 32 bits are ESC, numbers, and Q to D; if we have all of - * those, consider it a full keyboard; do not test KEY_RESERVED, though */ - mask = 0xFFFFFFFE; - if ((bitmask_key[0] & mask) == mask) { - - vdev_property_add( "VDEV_INPUT_KEYBOARD", "1" ); - - g_input_class = VDEV_INPUT_CLASS_KBD; - } +static void test_key(const unsigned long *bitmask_ev, + const unsigned long *bitmask_key) +{ + unsigned i; + unsigned long found; + unsigned long mask; + + /* do we have any KEY_* capability? */ + if (!test_bit(EV_KEY, bitmask_ev)) { + log_debug("%s", "test_key: no EV_KEY capability"); + return; + } + + /* only consider KEY_* here, not BTN_* */ + found = 0; + for (i = 0; i < BTN_MISC / BITS_PER_LONG; ++i) { + found |= bitmask_key[i]; + log_debug + ("test_key: checking bit block %lu for any keys; found=%i", + (unsigned long)i * BITS_PER_LONG, found > 0); + } + + /* If there are no keys in the lower block, check the higher block */ + if (!found) { + for (i = KEY_OK; i < BTN_TRIGGER_HAPPY; ++i) { + if (test_bit(i, bitmask_key)) { + log_debug + ("test_key: Found key %x in high block", i); + found = 1; + break; + } + } + } + + if (found > 0) { + + vdev_property_add("VDEV_INPUT_KEY", "1"); + } + + /* the first 32 bits are ESC, numbers, and Q to D; if we have all of + * those, consider it a full keyboard; do not test KEY_RESERVED, though */ + mask = 0xFFFFFFFE; + if ((bitmask_key[0] & mask) == mask) { + + vdev_property_add("VDEV_INPUT_KEYBOARD", "1"); + + g_input_class = VDEV_INPUT_CLASS_KBD; + } } +void usage(char const *program_name) +{ + + fprintf(stderr, "[ERROR] %s: Usage: %s /path/to/input/device/file\n", + program_name, program_name); -void usage(char const* program_name ) { - - fprintf(stderr, "[ERROR] %s: Usage: %s /path/to/input/device/file\n", program_name, program_name); - } // entry point // TODO: support using a sysfs device path directly -int main( int argc, char** argv ) { - - // look for the character device with VDEV_MAJOR and VDEV_MINOR - char capabilities_path[4096]; - char full_sysfs_path[4096]; - char subsystem[4096]; - char sysdev_path[4096]; - - unsigned long bitmask_ev[NBITS(EV_MAX)]; - unsigned long bitmask_abs[NBITS(ABS_MAX)]; - unsigned long bitmask_key[NBITS(KEY_MAX)]; - unsigned long bitmask_rel[NBITS(REL_MAX)]; - - struct stat sb; - int rc = 0; - char major[20]; - char minor[20]; - char* basename = NULL; - - if( argc != 2 ) { - usage( argv[0] ); - exit(1); - } - - rc = stat( argv[1], &sb ); - if( rc != 0 ) { - - rc = -errno; - fprintf(stderr, "[ERROR] %s: stat('%s') errno = %d\n", argv[0], argv[1], rc ); - exit(2); - } - - if( !S_ISCHR( sb.st_mode ) ) { - - fprintf(stderr, "[ERROR] %s: '%s' is not a character device file\n", argv[0], argv[1] ); - usage(argv[0]); - exit(2); - } - - sprintf( major, "%u", major(sb.st_rdev) ); - sprintf( minor, "%u", minor(sb.st_rdev) ); - - static char const* caps[] = { - "ev", - "abs", - "key", - "rel", - NULL - }; - - unsigned long *bitmasks[] = { - bitmask_ev, - bitmask_abs, - bitmask_key, - bitmask_rel, - NULL - }; - - size_t bitmask_lens[] = { - NBITS(EV_MAX), - NBITS(ABS_MAX), - NBITS(KEY_MAX), - NBITS(REL_MAX), - 0 - }; - - if( major == NULL || minor == NULL ) { - // nothing to do here - exit(1); - } - - // is this an input device? - memset( sysdev_path, 0, 4096 ); - memset( subsystem, 0, 4096 ); - - snprintf( sysdev_path, 4096, "/sys/dev/char/%s:%s/subsystem", major, minor ); - rc = readlink( sysdev_path, subsystem, 4096 ); - if( rc < 0 ) { - fprintf(stderr, "[ERROR] %s: readlink('%s'): %s\n", argv[0], sysdev_path, strerror( rc ) ); - exit(1); - } - - if( strcmp( subsystem + strlen(subsystem) - 5, "input" ) != 0 ) { - - // not an input device - exit(1); - } - - // replaces ID_INPUT - vdev_property_add( "VDEV_INPUT", "1" ); - - memset( capabilities_path, 0, 4096 ); - - snprintf(capabilities_path, 4095, "/sys/dev/char/%s:%s/device/capabilities", major, minor ); - - // read each capability - for( int i = 0; caps[i] != NULL; i++ ) { - - memset( full_sysfs_path, 0, 4096 ); - snprintf( full_sysfs_path, 4096, "%s/%s", capabilities_path, caps[i] ); - - get_cap_mask( full_sysfs_path, bitmasks[i], bitmask_lens[i] ); - } - - // build up properties - test_pointers( bitmask_ev, bitmask_abs, bitmask_key, bitmask_rel ); - test_key( bitmask_ev, bitmask_key ); - - basename = rindex( argv[1], '/' ) + 1; - - if( strncmp( basename, "event", 5) == 0 ) { - - extract_input_resolution( argv[1] ); - } - - // state the input class too - switch( g_input_class ) { - - case VDEV_INPUT_CLASS_JOYSTICK: { - - vdev_property_add( "VDEV_INPUT_CLASS", "joystick" ); - break; - } - - case VDEV_INPUT_CLASS_MOUSE: { - - vdev_property_add( "VDEV_INPUT_CLASS", "mouse" ); - break; - } - - case VDEV_INPUT_CLASS_KBD: { - - vdev_property_add( "VDEV_INPUT_CLASS", "kbd" ); - break; - } - } - - vdev_property_print(); - vdev_property_free_all(); - - return 0; +int main(int argc, char **argv) +{ + + // look for the character device with VDEV_MAJOR and VDEV_MINOR + char capabilities_path[4096]; + char full_sysfs_path[4096]; + char subsystem[4096]; + char sysdev_path[4096]; + + unsigned long bitmask_ev[NBITS(EV_MAX)]; + unsigned long bitmask_abs[NBITS(ABS_MAX)]; + unsigned long bitmask_key[NBITS(KEY_MAX)]; + unsigned long bitmask_rel[NBITS(REL_MAX)]; + + struct stat sb; + int rc = 0; + char major[20]; + char minor[20]; + char *basename = NULL; + + if (argc != 2) { + usage(argv[0]); + exit(1); + } + + rc = stat(argv[1], &sb); + if (rc != 0) { + + rc = -errno; + fprintf(stderr, "[ERROR] %s: stat('%s') errno = %d\n", argv[0], + argv[1], rc); + exit(2); + } + + if (!S_ISCHR(sb.st_mode)) { + + fprintf(stderr, + "[ERROR] %s: '%s' is not a character device file\n", + argv[0], argv[1]); + usage(argv[0]); + exit(2); + } + + sprintf(major, "%u", major(sb.st_rdev)); + sprintf(minor, "%u", minor(sb.st_rdev)); + + static char const *caps[] = { + "ev", + "abs", + "key", + "rel", + NULL + }; + + unsigned long *bitmasks[] = { + bitmask_ev, + bitmask_abs, + bitmask_key, + bitmask_rel, + NULL + }; + + size_t bitmask_lens[] = { + NBITS(EV_MAX), + NBITS(ABS_MAX), + NBITS(KEY_MAX), + NBITS(REL_MAX), + 0 + }; + + if (major == NULL || minor == NULL) { + // nothing to do here + exit(1); + } + // is this an input device? + memset(sysdev_path, 0, 4096); + memset(subsystem, 0, 4096); + + snprintf(sysdev_path, 4096, "/sys/dev/char/%s:%s/subsystem", major, + minor); + rc = readlink(sysdev_path, subsystem, 4096); + if (rc < 0) { + fprintf(stderr, "[ERROR] %s: readlink('%s'): %s\n", argv[0], + sysdev_path, strerror(rc)); + exit(1); + } + + if (strcmp(subsystem + strlen(subsystem) - 5, "input") != 0) { + + // not an input device + exit(1); + } + // replaces ID_INPUT + vdev_property_add("VDEV_INPUT", "1"); + + memset(capabilities_path, 0, 4096); + + snprintf(capabilities_path, 4095, + "/sys/dev/char/%s:%s/device/capabilities", major, minor); + + // read each capability + for (int i = 0; caps[i] != NULL; i++) { + + memset(full_sysfs_path, 0, 4096); + snprintf(full_sysfs_path, 4096, "%s/%s", capabilities_path, + caps[i]); + + get_cap_mask(full_sysfs_path, bitmasks[i], bitmask_lens[i]); + } + + // build up properties + test_pointers(bitmask_ev, bitmask_abs, bitmask_key, bitmask_rel); + test_key(bitmask_ev, bitmask_key); + + basename = rindex(argv[1], '/') + 1; + + if (strncmp(basename, "event", 5) == 0) { + + extract_input_resolution(argv[1]); + } + // state the input class too + switch (g_input_class) { + + case VDEV_INPUT_CLASS_JOYSTICK:{ + + vdev_property_add("VDEV_INPUT_CLASS", "joystick"); + break; + } + + case VDEV_INPUT_CLASS_MOUSE:{ + + vdev_property_add("VDEV_INPUT_CLASS", "mouse"); + break; + } + + case VDEV_INPUT_CLASS_KBD:{ + + vdev_property_add("VDEV_INPUT_CLASS", "kbd"); + break; + } + } + + vdev_property_print(); + vdev_property_free_all(); + + return 0; } diff --git a/vdevd/helpers/LINUX/stat_net.c b/vdevd/helpers/LINUX/stat_net.c index 21f1ed7..6f813fc 100644 --- a/vdevd/helpers/LINUX/stat_net.c +++ b/vdevd/helpers/LINUX/stat_net.c @@ -102,899 +102,973 @@ #include #include -enum netname_type{ - NET_UNDEF, - NET_PCI, - NET_USB, - NET_BCMA, - NET_VIRTIO, - NET_CCWGROUP, +enum netname_type { + NET_UNDEF, + NET_PCI, + NET_USB, + NET_BCMA, + NET_VIRTIO, + NET_CCWGROUP, }; struct netnames { - enum netname_type type; - - uint8_t mac[6]; - bool mac_valid; - - char* pcidev; // sysfs device path - char pci_slot[IFNAMSIZ+1]; - char pci_path[IFNAMSIZ+1]; - char pci_onboard[IFNAMSIZ+1]; - char *pci_onboard_label; - - char usb_ports[IFNAMSIZ+1]; - char bcma_core[IFNAMSIZ+1]; - char ccw_group[IFNAMSIZ+1]; + enum netname_type type; + + uint8_t mac[6]; + bool mac_valid; + + char *pcidev; // sysfs device path + char pci_slot[IFNAMSIZ + 1]; + char pci_path[IFNAMSIZ + 1]; + char pci_onboard[IFNAMSIZ + 1]; + char *pci_onboard_label; + + char usb_ports[IFNAMSIZ + 1]; + char bcma_core[IFNAMSIZ + 1]; + char ccw_group[IFNAMSIZ + 1]; }; /* retrieve on-board index number and label from firmware */ -static int dev_pci_onboard( struct netnames *names) { - - char *index; - size_t index_len; - - int idx; - int rc = 0; - - /* ACPI _DSM -- device specific method for naming a PCI or PCI Express device */ - rc = vdev_sysfs_read_attr(names->pcidev, "acpi_index", &index, &index_len ); - - /* SMBIOS type 41 -- Onboard Devices Extended Information */ - if ( rc < 0 ) { - rc = vdev_sysfs_read_attr(names->pcidev, "index", &index, &index_len ); - } - - if( rc < 0 ) { - return -ENOENT; - } - - idx = strtoul(index, NULL, 0); - if (idx <= 0) { - - free( index ); - return -EINVAL; - } - - snprintf(names->pci_onboard, sizeof(names->pci_onboard), "o%d", idx); - - vdev_sysfs_read_attr( names->pcidev, "label", &names->pci_onboard_label, &index_len ); - free( index ); - - return 0; +static int dev_pci_onboard(struct netnames *names) +{ + + char *index; + size_t index_len; + + int idx; + int rc = 0; + + /* ACPI _DSM -- device specific method for naming a PCI or PCI Express device */ + rc = vdev_sysfs_read_attr(names->pcidev, "acpi_index", &index, + &index_len); + + /* SMBIOS type 41 -- Onboard Devices Extended Information */ + if (rc < 0) { + rc = vdev_sysfs_read_attr(names->pcidev, "index", &index, + &index_len); + } + + if (rc < 0) { + return -ENOENT; + } + + idx = strtoul(index, NULL, 0); + if (idx <= 0) { + + free(index); + return -EINVAL; + } + + snprintf(names->pci_onboard, sizeof(names->pci_onboard), "o%d", idx); + + vdev_sysfs_read_attr(names->pcidev, "label", &names->pci_onboard_label, + &index_len); + free(index); + + return 0; } /* read the 256 bytes PCI configuration space to check the multi-function bit */ -static bool is_pci_multifunction( char const* sysfs_path ) { - - FILE *f = NULL; - char *filename; - uint8_t config[64]; - - filename = (char*)calloc( strlen(sysfs_path) + 1 + strlen("/config") + 1, 1 ); - if( filename == NULL ) { - return -ENOMEM; - } - - sprintf( filename, "%s/config", sysfs_path ); - - f = fopen(filename, "re"); - if (!f) { - - free( filename ); - return false; - } - - if (fread(&config, sizeof(config), 1, f) != 1) { - - free( filename ); - fclose( f ); - return false; - } - - fclose( f ); - - /* bit 0-6 header type, bit 7 multi/single function device */ - if ((config[PCI_HEADER_TYPE] & 0x80) != 0) { - free( filename ); - return true; - } - - free( filename ); - - return false; -} +static bool is_pci_multifunction(char const *sysfs_path) +{ + FILE *f = NULL; + char *filename; + uint8_t config[64]; -// calculate the pci path and slot of the device -static int dev_pci_slot( char const* dev_path, struct netnames *names) { - - unsigned domain, bus, slot, func, dev_port = 0; - - char *attr; - size_t attr_len; - - char* pci_sysfs_path = NULL; - size_t pci_sysfs_path_len = 0; - - char* slots = NULL; - char* address_path = NULL; - - DIR *dir = NULL; - struct dirent *dent; - int hotplug_slot = 0, err = 0; - char* pcidev_sysname = NULL; - size_t pcidev_sysname_len = 0; - int rc = 0; - - rc = vdev_sysfs_get_sysname( names->pcidev, &pcidev_sysname, &pcidev_sysname_len ); - if( rc != 0 ) { - return rc; - } - - if (sscanf( pcidev_sysname, "%x:%x:%x.%u", &domain, &bus, &slot, &func) != 4) { - - free( pcidev_sysname ); - return -ENOENT; - } - - free( pcidev_sysname ); - - /* kernel provided multi-device index */ - rc = vdev_sysfs_read_attr(dev_path, "dev_port", &attr, &attr_len ); - if ( rc == 0 ) { - dev_port = strtol(attr, NULL, 10); - free( attr ); - } - - /* compose a name based on the raw kernel's PCI bus, slot numbers */ - memset( names->pci_path, 0, IFNAMSIZ+1 ); - - if (domain > 0) { - - sprintf( names->pci_path + strlen(names->pci_path), "P%u", domain ); - } - - sprintf( names->pci_path + strlen(names->pci_path), "p%us%u", bus, slot ); - - if (func > 0 || is_pci_multifunction(names->pcidev)) { - - sprintf( names->pci_path + strlen(names->pci_path), "f%u", func ); - } - - if (dev_port > 0) { - - sprintf( names->pci_path + strlen(names->pci_path), "d%u", dev_port ); - } - - if (strlen(names->pci_path) == 0) { - names->pci_path[0] = '\0'; - } - - /* ACPI _SUN -- slot user number */ - rc = vdev_sysfs_device_path_from_subsystem_sysname("/sys", "subsystem", "pci", &pci_sysfs_path, &pci_sysfs_path_len); - if ( rc != 0 ) { - err = -ENOENT; - goto out; - } - - slots = (char*)calloc( strlen(pci_sysfs_path) + strlen("/slots") + 1, 1 ); - if( slots == NULL ) { - err = -ENOMEM; - - free( pci_sysfs_path ); - goto out; - } - - sprintf( slots, "%s/slots", pci_sysfs_path ); - - free( pci_sysfs_path ); - - dir = opendir(slots); - if (!dir) { - err = -errno; - goto out; - } - - for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) { - int i; - char *rest; - char *address; - size_t address_len = 0; - - if (dent->d_name[0] == '.') { - continue; - } - - i = strtol(dent->d_name, &rest, 10); - - if (rest[0] != '\0') { - continue; - } - - if (i < 1) { - continue; - } - - address_path = (char*)calloc( strlen(slots) + strlen(dent->d_name) + 3 + strlen("address"), 1 ); - if( address_path == NULL ) { - err = -ENOMEM; - goto out; - } - - sprintf( address_path, "%s/%s/address", slots, dent->d_name ); - - rc = vdev_read_file( address_path, &address, &address_len ); - if( rc != 0 ) { - - free( address_path ); - continue; - } - - free( address_path ); - - // take the first line only - if( index( address, '\n' ) != NULL ) { - - *(index(address, '\n')) = '\0'; - } - - /* match slot address with device by stripping the function */ - if (strneq(address, names->pcidev, strlen(address))) { - hotplug_slot = i; - } - - free(address); - - if (hotplug_slot > 0) { - break; - } - } - - closedir( dir ); - - if (hotplug_slot > 0) { - - memset( names->pci_slot, 0, IFNAMSIZ+1 ); - - if (domain > 0) { - - sprintf( names->pci_slot + strlen( names->pci_slot ), "P%d", domain ); - } - - sprintf( names->pci_slot + strlen( names->pci_slot ), "s%d", hotplug_slot ); - - if (func > 0 || is_pci_multifunction(names->pcidev)) { - - sprintf( names->pci_slot + strlen( names->pci_slot ), "f%d", func ); - } - - if (dev_port > 0) { - - sprintf( names->pci_slot + strlen( names->pci_slot ), "d%d", dev_port ); - } - - if (strlen(names->pci_slot) == 0) { - names->pci_slot[0] = '\0'; - } - } -out: - return err; + filename = + (char *)calloc(strlen(sysfs_path) + 1 + strlen("/config") + 1, 1); + if (filename == NULL) { + return -ENOMEM; + } + + sprintf(filename, "%s/config", sysfs_path); + + f = fopen(filename, "re"); + if (!f) { + + free(filename); + return false; + } + + if (fread(&config, sizeof(config), 1, f) != 1) { + + free(filename); + fclose(f); + return false; + } + + fclose(f); + + /* bit 0-6 header type, bit 7 multi/single function device */ + if ((config[PCI_HEADER_TYPE] & 0x80) != 0) { + free(filename); + return true; + } + + free(filename); + + return false; } -static int names_pci( char const* dev_path, struct netnames *names ) { - - char* parent_device_path = NULL; - size_t parent_device_path_len = 0; - - char* parent_device_subsystem = NULL; - size_t parent_device_subsystem_len = 0; - - int rc = 0; - - // get parent device - rc = vdev_sysfs_get_parent_device( dev_path, &parent_device_path, &parent_device_path_len ); - if( rc != 0 ) { - - if( rc != -ENOENT ) { - // some other fatal error - log_error("WARN: vdev_sysfs_get_parent_device('%s') rc = %d\n", dev_path, rc ); - } - - return rc; - } - - // get parent subsystem - rc = vdev_sysfs_read_subsystem( parent_device_path, &parent_device_subsystem, &parent_device_subsystem_len ); - if( rc != 0 ) { - - free( parent_device_path ); - - log_error("WARN: vdev_sysfs_read_subsystem('%s') rc = %d\n", parent_device_path, rc ); - return rc; - } - - /* check if our direct parent is a PCI device with no other bus in-between */ - if ( strcmp("pci", parent_device_subsystem) == 0 ) { - - names->type = NET_PCI; - names->pcidev = strdup( parent_device_path ); - - if( names->pcidev == NULL ) { - free( parent_device_path ); - free( parent_device_subsystem ); - return -ENOMEM; - } - } - else { - - size_t pcidev_len = 0; - rc = vdev_sysfs_get_parent_with_subsystem_devtype( dev_path, "pci", NULL, &names->pcidev, &pcidev_len ); - - if( rc != 0 ) { - - if( rc != -ENOENT ) { - log_error("WARN: vdev_sysfs_get_parent_with_subsystem_devtype('%s', 'pci', NULL) rc = %d\n", dev_path, rc ); - } - - return rc; - } - } - - free( parent_device_subsystem ); - free( parent_device_path ); - - dev_pci_onboard( names ); - dev_pci_slot(dev_path, names); - return 0; +// calculate the pci path and slot of the device +static int dev_pci_slot(char const *dev_path, struct netnames *names) +{ + + unsigned domain, bus, slot, func, dev_port = 0; + + char *attr; + size_t attr_len; + + char *pci_sysfs_path = NULL; + size_t pci_sysfs_path_len = 0; + + char *slots = NULL; + char *address_path = NULL; + + DIR *dir = NULL; + struct dirent *dent; + int hotplug_slot = 0, err = 0; + char *pcidev_sysname = NULL; + size_t pcidev_sysname_len = 0; + int rc = 0; + + rc = vdev_sysfs_get_sysname(names->pcidev, &pcidev_sysname, + &pcidev_sysname_len); + if (rc != 0) { + return rc; + } + + if (sscanf(pcidev_sysname, "%x:%x:%x.%u", &domain, &bus, &slot, &func) + != 4) { + + free(pcidev_sysname); + return -ENOENT; + } + + free(pcidev_sysname); + + /* kernel provided multi-device index */ + rc = vdev_sysfs_read_attr(dev_path, "dev_port", &attr, &attr_len); + if (rc == 0) { + dev_port = strtol(attr, NULL, 10); + free(attr); + } + + /* compose a name based on the raw kernel's PCI bus, slot numbers */ + memset(names->pci_path, 0, IFNAMSIZ + 1); + + if (domain > 0) { + + sprintf(names->pci_path + strlen(names->pci_path), "P%u", + domain); + } + + sprintf(names->pci_path + strlen(names->pci_path), "p%us%u", bus, slot); + + if (func > 0 || is_pci_multifunction(names->pcidev)) { + + sprintf(names->pci_path + strlen(names->pci_path), "f%u", func); + } + + if (dev_port > 0) { + + sprintf(names->pci_path + strlen(names->pci_path), "d%u", + dev_port); + } + + if (strlen(names->pci_path) == 0) { + names->pci_path[0] = '\0'; + } + + /* ACPI _SUN -- slot user number */ + rc = vdev_sysfs_device_path_from_subsystem_sysname("/sys", "subsystem", + "pci", + &pci_sysfs_path, + &pci_sysfs_path_len); + if (rc != 0) { + err = -ENOENT; + goto out; + } + + slots = + (char *)calloc(strlen(pci_sysfs_path) + strlen("/slots") + 1, 1); + if (slots == NULL) { + err = -ENOMEM; + + free(pci_sysfs_path); + goto out; + } + + sprintf(slots, "%s/slots", pci_sysfs_path); + + free(pci_sysfs_path); + + dir = opendir(slots); + if (!dir) { + err = -errno; + goto out; + } + + for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) { + int i; + char *rest; + char *address; + size_t address_len = 0; + + if (dent->d_name[0] == '.') { + continue; + } + + i = strtol(dent->d_name, &rest, 10); + + if (rest[0] != '\0') { + continue; + } + + if (i < 1) { + continue; + } + + address_path = + (char *)calloc(strlen(slots) + strlen(dent->d_name) + 3 + + strlen("address"), 1); + if (address_path == NULL) { + err = -ENOMEM; + goto out; + } + + sprintf(address_path, "%s/%s/address", slots, dent->d_name); + + rc = vdev_read_file(address_path, &address, &address_len); + if (rc != 0) { + + free(address_path); + continue; + } + + free(address_path); + + // take the first line only + if (index(address, '\n') != NULL) { + + *(index(address, '\n')) = '\0'; + } + + /* match slot address with device by stripping the function */ + if (strneq(address, names->pcidev, strlen(address))) { + hotplug_slot = i; + } + + free(address); + + if (hotplug_slot > 0) { + break; + } + } + + closedir(dir); + + if (hotplug_slot > 0) { + + memset(names->pci_slot, 0, IFNAMSIZ + 1); + + if (domain > 0) { + + sprintf(names->pci_slot + strlen(names->pci_slot), + "P%d", domain); + } + + sprintf(names->pci_slot + strlen(names->pci_slot), "s%d", + hotplug_slot); + + if (func > 0 || is_pci_multifunction(names->pcidev)) { + + sprintf(names->pci_slot + strlen(names->pci_slot), + "f%d", func); + } + + if (dev_port > 0) { + + sprintf(names->pci_slot + strlen(names->pci_slot), + "d%d", dev_port); + } + + if (strlen(names->pci_slot) == 0) { + names->pci_slot[0] = '\0'; + } + } + out: + return err; } -static int names_usb( char const* dev_path, struct netnames *names) { - - char *ports; - char *config; - char *interf; - char *s; - char* usbdev_path = NULL; - char* usbdev_sysname = NULL; - size_t usbdev_path_len = 0; - size_t usbdev_sysname_len =0; - int rc = 0; - - rc = vdev_sysfs_get_parent_with_subsystem_devtype( dev_path, "usb", "usb_interface", &usbdev_path, &usbdev_path_len ); - if( rc != 0 ) { - - if( rc != -ENOENT ) { - log_error("WARN: vdev_sysfs_get_parent_with_subsystem_devtype('%s', 'usb', 'usb_interface') rc = %d\n", dev_path, rc ); - } - - return rc; - } - - rc = vdev_sysfs_get_sysname( usbdev_path, &usbdev_sysname, &usbdev_sysname_len ); - if( rc != 0 ) { - - free( usbdev_path ); - return rc; - } - - free( usbdev_path ); - - /* get USB port number chain, configuration, interface */ - s = strchr(usbdev_sysname, '-'); - if (!s) { - - free( usbdev_sysname ); - return -EINVAL; - } - - ports = s+1; - - s = strchr(ports, ':'); - if (!s) { - - free( usbdev_sysname ); - return -EINVAL; - } - - s[0] = '\0'; - config = s+1; - - s = strchr(config, '.'); - if (!s) { - - free( usbdev_sysname ); - return -EINVAL; - } - - s[0] = '\0'; - interf = s+1; - - /* prefix every port number in the chain with "u" */ - s = ports; - while ((s = strchr(s, '.'))) { - s[0] = 'u'; - } - - // set up usb_ports - s = names->usb_ports; - memset( s, 0, IFNAMSIZ+1 ); - - strncat( s, "u", IFNAMSIZ ); - strncat( s, ports, IFNAMSIZ ); - - /* append USB config number, suppress the common config == 1 */ - if( strcmp(config, "1") != 0 ) { - strncat( s, "c", IFNAMSIZ ); - strncat( s, ports, IFNAMSIZ ); - } - - /* append USB interface number, suppress the interface == 0 */ - if( strcmp(interf, "0") != 0 ) { - strncat( s, "i", IFNAMSIZ ); - strncat( s, interf, IFNAMSIZ ); - } - - if( strlen(s) == 0 ) { - - free( usbdev_sysname ); - return -ENAMETOOLONG; - } - - free( usbdev_sysname ); - names->type = NET_USB; - return 0; +static int names_pci(char const *dev_path, struct netnames *names) +{ + + char *parent_device_path = NULL; + size_t parent_device_path_len = 0; + + char *parent_device_subsystem = NULL; + size_t parent_device_subsystem_len = 0; + + int rc = 0; + + // get parent device + rc = vdev_sysfs_get_parent_device(dev_path, &parent_device_path, + &parent_device_path_len); + if (rc != 0) { + + if (rc != -ENOENT) { + // some other fatal error + log_error + ("WARN: vdev_sysfs_get_parent_device('%s') rc = %d\n", + dev_path, rc); + } + + return rc; + } + // get parent subsystem + rc = vdev_sysfs_read_subsystem(parent_device_path, + &parent_device_subsystem, + &parent_device_subsystem_len); + if (rc != 0) { + + free(parent_device_path); + + log_error("WARN: vdev_sysfs_read_subsystem('%s') rc = %d\n", + parent_device_path, rc); + return rc; + } + + /* check if our direct parent is a PCI device with no other bus in-between */ + if (strcmp("pci", parent_device_subsystem) == 0) { + + names->type = NET_PCI; + names->pcidev = strdup(parent_device_path); + + if (names->pcidev == NULL) { + free(parent_device_path); + free(parent_device_subsystem); + return -ENOMEM; + } + } else { + + size_t pcidev_len = 0; + rc = vdev_sysfs_get_parent_with_subsystem_devtype(dev_path, + "pci", NULL, + &names-> + pcidev, + &pcidev_len); + + if (rc != 0) { + + if (rc != -ENOENT) { + log_error + ("WARN: vdev_sysfs_get_parent_with_subsystem_devtype('%s', 'pci', NULL) rc = %d\n", + dev_path, rc); + } + + return rc; + } + } + + free(parent_device_subsystem); + free(parent_device_path); + + dev_pci_onboard(names); + dev_pci_slot(dev_path, names); + return 0; } -static int names_bcma( char const* devpath, struct netnames *names) { - - char* bcmadev_path = NULL; - size_t bcmadev_path_len = 0; - char* bcmadev_sysname = NULL; - size_t bcmadev_sysname_len = 0; - unsigned int core; - int rc = 0; - - rc = vdev_sysfs_get_parent_with_subsystem_devtype( devpath, "bcma", NULL, &bcmadev_path, &bcmadev_path_len ); - if( rc != 0 ) { - - if( rc != -ENOENT ) { - log_error("vdev_sysfs_get_parent_with_subsystem_devtype('%s', 'bcma', NULL) rc = %d\n", devpath, rc ); - } - - return rc; - } - - rc = vdev_sysfs_get_sysname( devpath, &bcmadev_sysname, &bcmadev_sysname_len ); - if( rc != 0 ) { - - free( bcmadev_path ); - return rc; - } - - /* bus num:core num */ - if (sscanf( bcmadev_sysname, "bcma%*u:%u", &core) != 1) { - - free( bcmadev_path ); - free( bcmadev_sysname ); - return -EINVAL; - } - - /* suppress the common core == 0 */ - if (core > 0) { - snprintf(names->bcma_core, sizeof(names->bcma_core), "b%u", core); - } - - names->type = NET_BCMA; - - free( bcmadev_path ); - free( bcmadev_sysname ); - return 0; +static int names_usb(char const *dev_path, struct netnames *names) +{ + + char *ports; + char *config; + char *interf; + char *s; + char *usbdev_path = NULL; + char *usbdev_sysname = NULL; + size_t usbdev_path_len = 0; + size_t usbdev_sysname_len = 0; + int rc = 0; + + rc = vdev_sysfs_get_parent_with_subsystem_devtype(dev_path, "usb", + "usb_interface", + &usbdev_path, + &usbdev_path_len); + if (rc != 0) { + + if (rc != -ENOENT) { + log_error + ("WARN: vdev_sysfs_get_parent_with_subsystem_devtype('%s', 'usb', 'usb_interface') rc = %d\n", + dev_path, rc); + } + + return rc; + } + + rc = vdev_sysfs_get_sysname(usbdev_path, &usbdev_sysname, + &usbdev_sysname_len); + if (rc != 0) { + + free(usbdev_path); + return rc; + } + + free(usbdev_path); + + /* get USB port number chain, configuration, interface */ + s = strchr(usbdev_sysname, '-'); + if (!s) { + + free(usbdev_sysname); + return -EINVAL; + } + + ports = s + 1; + + s = strchr(ports, ':'); + if (!s) { + + free(usbdev_sysname); + return -EINVAL; + } + + s[0] = '\0'; + config = s + 1; + + s = strchr(config, '.'); + if (!s) { + + free(usbdev_sysname); + return -EINVAL; + } + + s[0] = '\0'; + interf = s + 1; + + /* prefix every port number in the chain with "u" */ + s = ports; + while ((s = strchr(s, '.'))) { + s[0] = 'u'; + } + + // set up usb_ports + s = names->usb_ports; + memset(s, 0, IFNAMSIZ + 1); + + strncat(s, "u", IFNAMSIZ); + strncat(s, ports, IFNAMSIZ); + + /* append USB config number, suppress the common config == 1 */ + if (strcmp(config, "1") != 0) { + strncat(s, "c", IFNAMSIZ); + strncat(s, ports, IFNAMSIZ); + } + + /* append USB interface number, suppress the interface == 0 */ + if (strcmp(interf, "0") != 0) { + strncat(s, "i", IFNAMSIZ); + strncat(s, interf, IFNAMSIZ); + } + + if (strlen(s) == 0) { + + free(usbdev_sysname); + return -ENAMETOOLONG; + } + + free(usbdev_sysname); + names->type = NET_USB; + return 0; } +static int names_bcma(char const *devpath, struct netnames *names) +{ + + char *bcmadev_path = NULL; + size_t bcmadev_path_len = 0; + char *bcmadev_sysname = NULL; + size_t bcmadev_sysname_len = 0; + unsigned int core; + int rc = 0; + + rc = vdev_sysfs_get_parent_with_subsystem_devtype(devpath, "bcma", NULL, + &bcmadev_path, + &bcmadev_path_len); + if (rc != 0) { + + if (rc != -ENOENT) { + log_error + ("vdev_sysfs_get_parent_with_subsystem_devtype('%s', 'bcma', NULL) rc = %d\n", + devpath, rc); + } + + return rc; + } + + rc = vdev_sysfs_get_sysname(devpath, &bcmadev_sysname, + &bcmadev_sysname_len); + if (rc != 0) { + + free(bcmadev_path); + return rc; + } + + /* bus num:core num */ + if (sscanf(bcmadev_sysname, "bcma%*u:%u", &core) != 1) { + + free(bcmadev_path); + free(bcmadev_sysname); + return -EINVAL; + } + + /* suppress the common core == 0 */ + if (core > 0) { + snprintf(names->bcma_core, sizeof(names->bcma_core), "b%u", + core); + } + + names->type = NET_BCMA; + + free(bcmadev_path); + free(bcmadev_sysname); + return 0; +} -static int names_ccw( char const* devpath, struct netnames *names) { - - char *bus_id = NULL; - size_t bus_id_len = 0; - int rc; - - char* parent_devpath = NULL; - size_t parent_devpath_len = 0; - - char* parent_subsystem = NULL; - size_t parent_subsystem_len = 0; - - /* Retrieve the associated CCW device */ - rc = vdev_sysfs_get_parent_device( devpath, &parent_devpath, &parent_devpath_len ); - if( rc != 0 ) { - return -ENOENT; - } - - // get parent subsystem - rc = vdev_sysfs_read_subsystem( parent_devpath, &parent_subsystem, &parent_subsystem_len ); - if( rc != 0 ) { - - free( parent_devpath ); - return rc; - } - - /* Network devices are always grouped CCW devices */ - if( strcmp("ccwgroup", parent_subsystem) != 0 ) { - - free( parent_devpath ); - free( parent_subsystem ); - return -ENOENT; - } - - /* Retrieve bus-ID of the grouped CCW device. The bus-ID uniquely - * identifies the network device on the Linux on System z channel - * subsystem. Note that the bus-ID contains lowercase characters. - */ - rc = vdev_sysfs_get_sysname( parent_devpath, &bus_id, &bus_id_len ); - if( rc != 0 ) { - - free( parent_devpath ); - free( parent_subsystem ); - return -ENOENT; - } - - /* Check the length of the bus-ID. Rely on that the kernel provides - * a correct bus-ID; alternatively, improve this check and parse and - * verify each bus-ID part... - */ - if (bus_id_len == 0 || bus_id_len < 8 || bus_id_len > 9) { - - free( parent_devpath ); - free( parent_subsystem ); - free( bus_id ); - - return -EINVAL; - } - - /* Store the CCW bus-ID for use as network device name */ - rc = snprintf(names->ccw_group, sizeof(names->ccw_group), "ccw%s", bus_id); - if (rc >= 0 && rc < (int)sizeof(names->ccw_group)) { - names->type = NET_CCWGROUP; - } - - free( parent_devpath ); - free( parent_subsystem ); - free( bus_id ); - - return 0; +static int names_ccw(char const *devpath, struct netnames *names) +{ + + char *bus_id = NULL; + size_t bus_id_len = 0; + int rc; + + char *parent_devpath = NULL; + size_t parent_devpath_len = 0; + + char *parent_subsystem = NULL; + size_t parent_subsystem_len = 0; + + /* Retrieve the associated CCW device */ + rc = vdev_sysfs_get_parent_device(devpath, &parent_devpath, + &parent_devpath_len); + if (rc != 0) { + return -ENOENT; + } + // get parent subsystem + rc = vdev_sysfs_read_subsystem(parent_devpath, &parent_subsystem, + &parent_subsystem_len); + if (rc != 0) { + + free(parent_devpath); + return rc; + } + + /* Network devices are always grouped CCW devices */ + if (strcmp("ccwgroup", parent_subsystem) != 0) { + + free(parent_devpath); + free(parent_subsystem); + return -ENOENT; + } + + /* Retrieve bus-ID of the grouped CCW device. The bus-ID uniquely + * identifies the network device on the Linux on System z channel + * subsystem. Note that the bus-ID contains lowercase characters. + */ + rc = vdev_sysfs_get_sysname(parent_devpath, &bus_id, &bus_id_len); + if (rc != 0) { + + free(parent_devpath); + free(parent_subsystem); + return -ENOENT; + } + + /* Check the length of the bus-ID. Rely on that the kernel provides + * a correct bus-ID; alternatively, improve this check and parse and + * verify each bus-ID part... + */ + if (bus_id_len == 0 || bus_id_len < 8 || bus_id_len > 9) { + + free(parent_devpath); + free(parent_subsystem); + free(bus_id); + + return -EINVAL; + } + + /* Store the CCW bus-ID for use as network device name */ + rc = snprintf(names->ccw_group, sizeof(names->ccw_group), "ccw%s", + bus_id); + if (rc >= 0 && rc < (int)sizeof(names->ccw_group)) { + names->type = NET_CCWGROUP; + } + + free(parent_devpath); + free(parent_subsystem); + free(bus_id); + + return 0; } -static int names_mac( char const* devpath, struct netnames *names) { - - unsigned int i; - unsigned int a1, a2, a3, a4, a5, a6; - int rc = 0; - - char* addr_assign_type = NULL; - size_t addr_assign_type_len = 0; - - char* address = NULL; - size_t address_len = 0; - - rc = vdev_sysfs_read_attr( devpath, "addr_assign_type", &addr_assign_type, &addr_assign_type_len ); - if( rc != 0 ) { - return rc; - } - - i = strtoul( addr_assign_type, NULL, 0); - if (i != 0) { - - free( addr_assign_type ); - return 0; - } - - rc = vdev_sysfs_read_attr( devpath, "address", &address, &address_len ); - if( rc != 0 ) { - - free( addr_assign_type ); - return rc; - } - - rc = sscanf(address, "%x:%x:%x:%x:%x:%x", &a1, &a2, &a3, &a4, &a5, &a6); - if( rc != 6 ) { - - free( addr_assign_type ); - free( address ); - return -EINVAL; - } - - free( addr_assign_type ); - free( address ); - - /* skip empty MAC addresses */ - if( a1 == 0 && a2 == 0 && a3 == 0 && a4 == 0 && a5 == 0 && a6 == 0 ) { - return -EINVAL; - } - - names->mac[0] = a1; - names->mac[1] = a2; - names->mac[2] = a3; - names->mac[3] = a4; - names->mac[4] = a5; - names->mac[5] = a6; - names->mac_valid = true; - return 0; +static int names_mac(char const *devpath, struct netnames *names) +{ + + unsigned int i; + unsigned int a1, a2, a3, a4, a5, a6; + int rc = 0; + + char *addr_assign_type = NULL; + size_t addr_assign_type_len = 0; + + char *address = NULL; + size_t address_len = 0; + + rc = vdev_sysfs_read_attr(devpath, "addr_assign_type", + &addr_assign_type, &addr_assign_type_len); + if (rc != 0) { + return rc; + } + + i = strtoul(addr_assign_type, NULL, 0); + if (i != 0) { + + free(addr_assign_type); + return 0; + } + + rc = vdev_sysfs_read_attr(devpath, "address", &address, &address_len); + if (rc != 0) { + + free(addr_assign_type); + return rc; + } + + rc = sscanf(address, "%x:%x:%x:%x:%x:%x", &a1, &a2, &a3, &a4, &a5, &a6); + if (rc != 6) { + + free(addr_assign_type); + free(address); + return -EINVAL; + } + + free(addr_assign_type); + free(address); + + /* skip empty MAC addresses */ + if (a1 == 0 && a2 == 0 && a3 == 0 && a4 == 0 && a5 == 0 && a6 == 0) { + return -EINVAL; + } + + names->mac[0] = a1; + names->mac[1] = a2; + names->mac[2] = a3; + names->mac[3] = a4; + names->mac[4] = a5; + names->mac[5] = a6; + names->mac_valid = true; + return 0; } /* IEEE Organizationally Unique Identifier vendor string */ -static int ieee_oui( char const* devpath, struct netnames *names ) { - char str[32]; - - if (!names->mac_valid) { - return -ENOENT; - } - - /* skip commonly misused 00:00:00 (Xerox) prefix */ - if (memcmp(names->mac, "\0\0\0", 3) == 0) { - return -EINVAL; - } - - snprintf(str, sizeof(str), "OUI:%02X%02X%02X%02X%02X%02X", - names->mac[0], names->mac[1], names->mac[2], - names->mac[3], names->mac[4], names->mac[5]); - - // TODO: find out how to replace this - // udev_builtin_hwdb_lookup(dev, NULL, str, NULL, test); - - return 0; -} +static int ieee_oui(char const *devpath, struct netnames *names) +{ + char str[32]; + if (!names->mac_valid) { + return -ENOENT; + } -void usage( char const* progname ) { - fprintf(stderr, "[ERROR] %s: Usage: %s INTERFACE\n", progname, progname ); + /* skip commonly misused 00:00:00 (Xerox) prefix */ + if (memcmp(names->mac, "\0\0\0", 3) == 0) { + return -EINVAL; + } + + snprintf(str, sizeof(str), "OUI:%02X%02X%02X%02X%02X%02X", + names->mac[0], names->mac[1], names->mac[2], + names->mac[3], names->mac[4], names->mac[5]); + + // TODO: find out how to replace this + // udev_builtin_hwdb_lookup(dev, NULL, str, NULL, test); + + return 0; } -int main( int argc, char **argv ) { - - unsigned int i; - const char *prefix = "en"; - struct netnames names; - int err = 0; - int rc = 0; - char* tmp = NULL; // for realpath success check - bool is_net_device = false; - - char devpath_class[4097]; - char devpath[4097]; - char devpath_uevent[4097]; - - char* devtype = NULL; - size_t devtype_len = 0; - - // sysfs attr buf - char* attr = NULL; - char* attr_iflink = NULL; - char* attr_ifindex = NULL; - size_t attr_len = 0; - - char* uevent_buf = NULL; - size_t uevent_buf_len = 0; - - memset( &names, 0, sizeof(struct netnames) ); - - if( argc != 2 ) { - usage( argv[0] ); - } - - // get the device from the interface - sprintf( devpath_class, "/sys/class/net/%s", argv[1] ); - - tmp = realpath( devpath_class, devpath ); - if( tmp == NULL ) { - rc = -errno; - fprintf(stderr, "[ERROR] %s: Failed to locate sysfs entry for %s\n", argv[0], argv[1] ); - exit(1); - } - - // only care about ethernet and SLIP devices - rc = vdev_sysfs_read_attr( devpath, "type", &attr, &attr_len ); - if( rc != 0 ) { - - // not found - fprintf(stderr, "[ERROR] %s: Failed to find interface type for %s (sysfs path '%s'), rc = %d\n", argv[0], argv[1], devpath, rc ); - exit(1); - } - - i = strtoul(attr, NULL, 0); - - free( attr ); - - switch (i) { - case ARPHRD_ETHER: - prefix = "en"; - break; - case ARPHRD_SLIP: - prefix = "sl"; - break; - default: - return 0; - } - - // sanity check (i.e. no stacked devices) - rc = vdev_sysfs_read_attr( devpath, "ifindex", &attr_ifindex, &attr_len ); - if( rc != 0 ) { - - log_error("vdev_sysfs_read_attr('%s', 'ifindex') rc = %d\n", devpath, rc ); - exit(1); - } - - rc = vdev_sysfs_read_attr( devpath, "iflink", &attr_iflink, &attr_len ); - if( rc != 0 ) { - - log_error("vdev_sysfs_read_attr('%s', 'iflink') rc = %d\n", devpath, rc ); - - free( attr_ifindex ); - exit(1); - } - - if( strcmp( attr_ifindex, attr_iflink ) != 0 ) { - exit(0); - } - - free( attr_ifindex ); - free( attr_iflink ); - - // get device type - sprintf( devpath_uevent, "%s/uevent", devpath ); - - rc = vdev_read_file( devpath_uevent, &uevent_buf, &uevent_buf_len ); - if( rc != 0 ) { - - log_error("vdev_read_file('%s') rc = %d\n", devpath_uevent, rc ); - exit(2); - } - - rc = vdev_sysfs_uevent_get_key( uevent_buf, uevent_buf_len, "DEVTYPE", &devtype, &devtype_len ); - if( rc == 0 ) { - - if( strcmp("wlan", devtype) == 0 ) { - prefix = "wl"; - } - else if( strcmp("wwan", devtype) == 0 ) { - prefix = "ww"; - } - } - - free( uevent_buf ); - free( devtype ); - - err = names_mac( devpath, &names); - if (err >= 0 && names.mac_valid) { - - char str[IFNAMSIZ]; - - snprintf(str, sizeof(str), "%sx%02x%02x%02x%02x%02x%02x", prefix, - names.mac[0], names.mac[1], names.mac[2], - names.mac[3], names.mac[4], names.mac[5]); - - vdev_property_add( "VDEV_NET_NAME_MAC", str ); - - is_net_device = true; - ieee_oui(devpath, &names); - } - - /* get path names for Linux on System z network devices */ - err = names_ccw(devpath, &names); - if (err >= 0 && names.type == NET_CCWGROUP) { - - char str[IFNAMSIZ]; - - if (snprintf(str, sizeof(str), "%s%s", prefix, names.ccw_group) < (int)sizeof(str)) { - - vdev_property_add( "VDEV_NET_NAME_PATH", str ); - is_net_device = true; - } - - goto out; - } - - /* get PCI based path names, we compose only PCI based paths */ - err = names_pci(devpath, &names); - if (err < 0) { - goto out; - } - - /* plain PCI device */ - if (names.type == NET_PCI) { - - char str[IFNAMSIZ]; - - if (names.pci_onboard[0]) { - if (snprintf(str, sizeof(str), "%s%s", prefix, names.pci_onboard) < (int)sizeof(str)) { - - vdev_property_add( "VDEV_NET_NAME_ONBOARD", str ); - is_net_device = true; - } - } - - if (names.pci_onboard_label) { - if (snprintf(str, sizeof(str), "%s%s", prefix, names.pci_onboard_label) < (int)sizeof(str)) { - - vdev_property_add( "VDEV_NET_LABEL_ONBOARD", str ); - is_net_device = true; - } - } - - if (names.pci_path[0]) { - if (snprintf(str, sizeof(str), "%s%s", prefix, names.pci_path) < (int)sizeof(str)) { - - vdev_property_add( "VDEV_NET_NAME_PATH", str ); - is_net_device = true; - } - } - - if (names.pci_slot[0]) { - if (snprintf(str, sizeof(str), "%s%s", prefix, names.pci_slot) < (int)sizeof(str)) { - - vdev_property_add( "VDEV_NET_NAME_SLOT", str ); - is_net_device = true; - } - } - goto out; - } - - /* USB device */ - err = names_usb(devpath, &names); - if (err >= 0 && names.type == NET_USB) { - - char str[IFNAMSIZ]; - - if (names.pci_path[0]) { - if (snprintf(str, sizeof(str), "%s%s%s", prefix, names.pci_path, names.usb_ports) < (int)sizeof(str)) { - - vdev_property_add( "VDEV_NET_NAME_PATH", str ); - is_net_device = true; - } - } - - if (names.pci_slot[0]) { - if (snprintf(str, sizeof(str), "%s%s%s", prefix, names.pci_slot, names.usb_ports) < (int)sizeof(str)) { - - vdev_property_add( "VDEV_NET_NAME_SLOT", str ); - is_net_device = true; - } - } - - goto out; - } - - /* Broadcom bus */ - err = names_bcma(devpath, &names); - if (err >= 0 && names.type == NET_BCMA) { - - char str[IFNAMSIZ]; - - if (names.pci_path[0]) { - if (snprintf(str, sizeof(str), "%s%s%s", prefix, names.pci_path, names.bcma_core) < (int)sizeof(str)) { - - vdev_property_add( "VDEV_NET_NAME_PATH", str ); - is_net_device = true; - } - } - - if (names.pci_slot[0]) { - if (snprintf(str, sizeof(str), "%s%s%s", prefix, names.pci_slot, names.bcma_core) < (int)sizeof(str)) { - - vdev_property_add( "VDEV_NET_NAME_SLOT", str ); - is_net_device = true; - } - } - goto out; - } -out: - - if( is_net_device ) { - vdev_property_add( "VDEV_NET", "1" ); - } - - vdev_property_print(); - vdev_property_free_all(); - - return EXIT_SUCCESS; +void usage(char const *progname) +{ + fprintf(stderr, "[ERROR] %s: Usage: %s INTERFACE\n", progname, + progname); +} + +int main(int argc, char **argv) +{ + + unsigned int i; + const char *prefix = "en"; + struct netnames names; + int err = 0; + int rc = 0; + char *tmp = NULL; // for realpath success check + bool is_net_device = false; + + char devpath_class[4097]; + char devpath[4097]; + char devpath_uevent[4097]; + + char *devtype = NULL; + size_t devtype_len = 0; + + // sysfs attr buf + char *attr = NULL; + char *attr_iflink = NULL; + char *attr_ifindex = NULL; + size_t attr_len = 0; + + char *uevent_buf = NULL; + size_t uevent_buf_len = 0; + + memset(&names, 0, sizeof(struct netnames)); + + if (argc != 2) { + usage(argv[0]); + } + // get the device from the interface + sprintf(devpath_class, "/sys/class/net/%s", argv[1]); + + tmp = realpath(devpath_class, devpath); + if (tmp == NULL) { + rc = -errno; + fprintf(stderr, + "[ERROR] %s: Failed to locate sysfs entry for %s\n", + argv[0], argv[1]); + exit(1); + } + // only care about ethernet and SLIP devices + rc = vdev_sysfs_read_attr(devpath, "type", &attr, &attr_len); + if (rc != 0) { + + // not found + fprintf(stderr, + "[ERROR] %s: Failed to find interface type for %s (sysfs path '%s'), rc = %d\n", + argv[0], argv[1], devpath, rc); + exit(1); + } + + i = strtoul(attr, NULL, 0); + + free(attr); + + switch (i) { + case ARPHRD_ETHER: + prefix = "en"; + break; + case ARPHRD_SLIP: + prefix = "sl"; + break; + default: + return 0; + } + + // sanity check (i.e. no stacked devices) + rc = vdev_sysfs_read_attr(devpath, "ifindex", &attr_ifindex, &attr_len); + if (rc != 0) { + + log_error("vdev_sysfs_read_attr('%s', 'ifindex') rc = %d\n", + devpath, rc); + exit(1); + } + + rc = vdev_sysfs_read_attr(devpath, "iflink", &attr_iflink, &attr_len); + if (rc != 0) { + + log_error("vdev_sysfs_read_attr('%s', 'iflink') rc = %d\n", + devpath, rc); + + free(attr_ifindex); + exit(1); + } + + if (strcmp(attr_ifindex, attr_iflink) != 0) { + exit(0); + } + + free(attr_ifindex); + free(attr_iflink); + + // get device type + sprintf(devpath_uevent, "%s/uevent", devpath); + + rc = vdev_read_file(devpath_uevent, &uevent_buf, &uevent_buf_len); + if (rc != 0) { + + log_error("vdev_read_file('%s') rc = %d\n", devpath_uevent, rc); + exit(2); + } + + rc = vdev_sysfs_uevent_get_key(uevent_buf, uevent_buf_len, "DEVTYPE", + &devtype, &devtype_len); + if (rc == 0) { + + if (strcmp("wlan", devtype) == 0) { + prefix = "wl"; + } else if (strcmp("wwan", devtype) == 0) { + prefix = "ww"; + } + } + + free(uevent_buf); + free(devtype); + + err = names_mac(devpath, &names); + if (err >= 0 && names.mac_valid) { + + char str[IFNAMSIZ]; + + snprintf(str, sizeof(str), "%sx%02x%02x%02x%02x%02x%02x", + prefix, names.mac[0], names.mac[1], names.mac[2], + names.mac[3], names.mac[4], names.mac[5]); + + vdev_property_add("VDEV_NET_NAME_MAC", str); + + is_net_device = true; + ieee_oui(devpath, &names); + } + + /* get path names for Linux on System z network devices */ + err = names_ccw(devpath, &names); + if (err >= 0 && names.type == NET_CCWGROUP) { + + char str[IFNAMSIZ]; + + if (snprintf(str, sizeof(str), "%s%s", prefix, names.ccw_group) + < (int)sizeof(str)) { + + vdev_property_add("VDEV_NET_NAME_PATH", str); + is_net_device = true; + } + + goto out; + } + + /* get PCI based path names, we compose only PCI based paths */ + err = names_pci(devpath, &names); + if (err < 0) { + goto out; + } + + /* plain PCI device */ + if (names.type == NET_PCI) { + + char str[IFNAMSIZ]; + + if (names.pci_onboard[0]) { + if (snprintf + (str, sizeof(str), "%s%s", prefix, + names.pci_onboard) < (int)sizeof(str)) { + + vdev_property_add("VDEV_NET_NAME_ONBOARD", str); + is_net_device = true; + } + } + + if (names.pci_onboard_label) { + if (snprintf + (str, sizeof(str), "%s%s", prefix, + names.pci_onboard_label) < (int)sizeof(str)) { + + vdev_property_add("VDEV_NET_LABEL_ONBOARD", + str); + is_net_device = true; + } + } + + if (names.pci_path[0]) { + if (snprintf + (str, sizeof(str), "%s%s", prefix, + names.pci_path) < (int)sizeof(str)) { + + vdev_property_add("VDEV_NET_NAME_PATH", str); + is_net_device = true; + } + } + + if (names.pci_slot[0]) { + if (snprintf + (str, sizeof(str), "%s%s", prefix, + names.pci_slot) < (int)sizeof(str)) { + + vdev_property_add("VDEV_NET_NAME_SLOT", str); + is_net_device = true; + } + } + goto out; + } + + /* USB device */ + err = names_usb(devpath, &names); + if (err >= 0 && names.type == NET_USB) { + + char str[IFNAMSIZ]; + + if (names.pci_path[0]) { + if (snprintf + (str, sizeof(str), "%s%s%s", prefix, names.pci_path, + names.usb_ports) < (int)sizeof(str)) { + + vdev_property_add("VDEV_NET_NAME_PATH", str); + is_net_device = true; + } + } + + if (names.pci_slot[0]) { + if (snprintf + (str, sizeof(str), "%s%s%s", prefix, names.pci_slot, + names.usb_ports) < (int)sizeof(str)) { + + vdev_property_add("VDEV_NET_NAME_SLOT", str); + is_net_device = true; + } + } + + goto out; + } + + /* Broadcom bus */ + err = names_bcma(devpath, &names); + if (err >= 0 && names.type == NET_BCMA) { + + char str[IFNAMSIZ]; + + if (names.pci_path[0]) { + if (snprintf + (str, sizeof(str), "%s%s%s", prefix, names.pci_path, + names.bcma_core) < (int)sizeof(str)) { + + vdev_property_add("VDEV_NET_NAME_PATH", str); + is_net_device = true; + } + } + + if (names.pci_slot[0]) { + if (snprintf + (str, sizeof(str), "%s%s%s", prefix, names.pci_slot, + names.bcma_core) < (int)sizeof(str)) { + + vdev_property_add("VDEV_NET_NAME_SLOT", str); + is_net_device = true; + } + } + goto out; + } + out: + + if (is_net_device) { + vdev_property_add("VDEV_NET", "1"); + } + + vdev_property_print(); + vdev_property_free_all(); + + return EXIT_SUCCESS; } diff --git a/vdevd/helpers/LINUX/stat_optical.c b/vdevd/helpers/LINUX/stat_optical.c index ef66be3..277702f 100644 --- a/vdevd/helpers/LINUX/stat_optical.c +++ b/vdevd/helpers/LINUX/stat_optical.c @@ -41,78 +41,91 @@ // get drive capabilities from an open device node, using the Linux-specific CDROM_GET_CAPABILITY ioctl. // return 0 on success // return negative errno on error -static int stat_optical_get_caps( int fd ) { - - int caps = 0; - int rc = 0; - - // get the cpability - caps = ioctl( fd, CDROM_GET_CAPABILITY, NULL ); - if( caps < 0 ) { - - rc = -errno; - fprintf(stderr, "[ERROR] optical: CDROM_GET_CAPABILITY ioctl failed, rc = %d\n", rc ); - return rc; - } - - return caps; -} +static int stat_optical_get_caps(int fd) +{ + + int caps = 0; + int rc = 0; + + // get the cpability + caps = ioctl(fd, CDROM_GET_CAPABILITY, NULL); + if (caps < 0) { + rc = -errno; + fprintf(stderr, + "[ERROR] optical: CDROM_GET_CAPABILITY ioctl failed, rc = %d\n", + rc); + return rc; + } + + return caps; +} // print out optical capabilities as environment variables -static int stat_optical_print_caps( int capabilities ) { - - vdev_property_add( "VDEV_OPTICAL_CD_R", (capabilities & CDC_CD_R) == 0 ? "0" : "1" ); - vdev_property_add( "VDEV_OPTICAL_CD_RW", (capabilities & CDC_CD_R) == 0 ? "0" : "1" ); - vdev_property_add( "VDEV_OPTICAL_DVD", (capabilities & CDC_DVD) == 0 ? "0" : "1" ); - vdev_property_add( "VDEV_OPTICAL_DVD_R", (capabilities & CDC_DVD_R) == 0 ? "0" : "1" ); - vdev_property_add( "VDEV_OPTICAL_DVD_RAM", (capabilities & CDC_DVD_RAM) == 0 ? "0" : "1" ); - - vdev_property_print(); - vdev_property_free_all(); - - return 0; +static int stat_optical_print_caps(int capabilities) +{ + + vdev_property_add("VDEV_OPTICAL_CD_R", + (capabilities & CDC_CD_R) == 0 ? "0" : "1"); + vdev_property_add("VDEV_OPTICAL_CD_RW", + (capabilities & CDC_CD_R) == 0 ? "0" : "1"); + vdev_property_add("VDEV_OPTICAL_DVD", + (capabilities & CDC_DVD) == 0 ? "0" : "1"); + vdev_property_add("VDEV_OPTICAL_DVD_R", + (capabilities & CDC_DVD_R) == 0 ? "0" : "1"); + vdev_property_add("VDEV_OPTICAL_DVD_RAM", + (capabilities & CDC_DVD_RAM) == 0 ? "0" : "1"); + + vdev_property_print(); + vdev_property_free_all(); + + return 0; } // usage statement -static int usage( char const* prog_name ) { - - fprintf(stderr, "[ERROR] %s: Usage: %s /path/to/optical/device\n", prog_name, prog_name ); - return 0; +static int usage(char const *prog_name) +{ + + fprintf(stderr, "[ERROR] %s: Usage: %s /path/to/optical/device\n", + prog_name, prog_name); + return 0; } // entry point -int main( int argc, char** argv ) { - - int rc = 0; - int fd = 0; - int capabilities = 0; - - if( argc != 2 ) { - - usage( argv[0] ); - exit(1); - } - - // get the device node - fd = open( argv[1], O_RDONLY | O_NONBLOCK ); - if( fd < 0 ) { - - rc = -errno; - fprintf(stderr, "[ERROR] %s: open('%s') rc = %d\n", argv[0], argv[1], rc ); - exit(2); - } - - capabilities = stat_optical_get_caps( fd ); - - close( fd ); - - if( capabilities < 0 ) { - - fprintf(stderr, "[ERROR] %s: stat_optical_get_caps('%s') rc = %d\n", argv[0], argv[1], rc ); - exit(4); - } - - stat_optical_print_caps( capabilities ); - return 0; +int main(int argc, char **argv) +{ + + int rc = 0; + int fd = 0; + int capabilities = 0; + + if (argc != 2) { + + usage(argv[0]); + exit(1); + } + // get the device node + fd = open(argv[1], O_RDONLY | O_NONBLOCK); + if (fd < 0) { + + rc = -errno; + fprintf(stderr, "[ERROR] %s: open('%s') rc = %d\n", argv[0], + argv[1], rc); + exit(2); + } + + capabilities = stat_optical_get_caps(fd); + + close(fd); + + if (capabilities < 0) { + + fprintf(stderr, + "[ERROR] %s: stat_optical_get_caps('%s') rc = %d\n", + argv[0], argv[1], rc); + exit(4); + } + + stat_optical_print_caps(capabilities); + return 0; } diff --git a/vdevd/helpers/LINUX/stat_path.c b/vdevd/helpers/LINUX/stat_path.c index e3b8d57..bc9e434 100644 --- a/vdevd/helpers/LINUX/stat_path.c +++ b/vdevd/helpers/LINUX/stat_path.c @@ -43,681 +43,717 @@ #include #include -static int path_prepend(char **path, const char *fmt, ...) { - va_list va; - char *pre; - int err = 0; - - va_start(va, fmt); - err = vasprintf(&pre, fmt, va); - va_end(va); - if (err < 0) { - goto out; - } - - if (*path != NULL) { - char *new; - - err = asprintf(&new, "%s-%s", pre, *path); - free(pre); - if (err < 0) { - goto out; - } - free(*path); - *path = new; - } else { - *path = pre; - } -out: - return err; +static int path_prepend(char **path, const char *fmt, ...) +{ + va_list va; + char *pre; + int err = 0; + + va_start(va, fmt); + err = vasprintf(&pre, fmt, va); + va_end(va); + if (err < 0) { + goto out; + } + + if (*path != NULL) { + char *new; + + err = asprintf(&new, "%s-%s", pre, *path); + free(pre); + if (err < 0) { + goto out; + } + free(*path); + *path = new; + } else { + *path = pre; + } + out: + return err; } /* ** Linux only supports 32 bit luns. ** See drivers/scsi/scsi_scan.c::scsilun_to_int() for more details. */ -static int format_lun_number( char const* devpath, char **path) { - - int lun = 0; - int rc = vdev_sysfs_get_sysnum( devpath, &lun ); - if( rc != 0 ) { - return rc; - } - - /* address method 0, peripheral device addressing with bus id of zero */ - if (lun < 256) { - return path_prepend(path, "lun-%lu", lun); - } - - /* handle all other lun addressing methods by using a variant of the original lun format */ - return path_prepend(path, "lun-0x%04lx%04lx00000000", lun & 0xffff, (lun >> 16) & 0xffff); -} +static int format_lun_number(char const *devpath, char **path) +{ + int lun = 0; + int rc = vdev_sysfs_get_sysnum(devpath, &lun); + if (rc != 0) { + return rc; + } + + /* address method 0, peripheral device addressing with bus id of zero */ + if (lun < 256) { + return path_prepend(path, "lun-%lu", lun); + } + + /* handle all other lun addressing methods by using a variant of the original lun format */ + return path_prepend(path, "lun-0x%04lx%04lx00000000", lun & 0xffff, + (lun >> 16) & 0xffff); +} // walk up the sysfs path and skip all ancestor devices with the given subsystem. // stop once the parent device has a different subsystem from subsys. // return 0 on success, and set *next to the path to the deepest ancestor device that either does not have a subsystem, or has one that is different from subsys. -static int skip_subsystem( char const* devpath, char const* subsys, char** next ) { - - char* cur_dev = strdup( devpath ); - char* parent = cur_dev; - - size_t parent_len = 0; - int rc = 0; - - while( true ) { - - char* subsystem = NULL; - size_t subsystem_len = 0; - - int rc = 0; - - rc = vdev_sysfs_read_subsystem( parent, &subsystem, &subsystem_len ); - - // break if not matched - if( (rc == -ENOENT || subsystem == NULL) || strcmp( subsystem, subsys ) != 0 ) { - - if( subsystem != NULL ) { - free( subsystem ); - } - break; - } - - log_debug("skip %s", parent ); - - free( subsystem ); - - if( cur_dev != parent ) { - free( cur_dev ); - } - - cur_dev = parent; - - // matched; walk up - rc = vdev_sysfs_get_parent_device( cur_dev, &parent, &parent_len ); - if( rc != 0 ) { - - break; - } - } - - *next = cur_dev; - - if( cur_dev != parent ) { - free( parent ); - } - - log_debug("Skip from '%s' to '%s'\n", devpath, *next ); - - return rc; +static int skip_subsystem(char const *devpath, char const *subsys, char **next) +{ + + char *cur_dev = strdup(devpath); + char *parent = cur_dev; + + size_t parent_len = 0; + int rc = 0; + + while (true) { + + char *subsystem = NULL; + size_t subsystem_len = 0; + + int rc = 0; + + rc = vdev_sysfs_read_subsystem(parent, &subsystem, + &subsystem_len); + + // break if not matched + if ((rc == -ENOENT || subsystem == NULL) + || strcmp(subsystem, subsys) != 0) { + + if (subsystem != NULL) { + free(subsystem); + } + break; + } + + log_debug("skip %s", parent); + + free(subsystem); + + if (cur_dev != parent) { + free(cur_dev); + } + + cur_dev = parent; + + // matched; walk up + rc = vdev_sysfs_get_parent_device(cur_dev, &parent, + &parent_len); + if (rc != 0) { + + break; + } + } + + *next = cur_dev; + + if (cur_dev != parent) { + free(parent); + } + + log_debug("Skip from '%s' to '%s'\n", devpath, *next); + + return rc; } // persistent name for scsi fibre channel (named by parent) // return 0 on success, and set *new_parent to the parent device and update *path // return negative on failure -static int handle_scsi_fibre_channel( char const* parent, char **path, char** new_parent ) { - - char* port = NULL; - size_t port_len = 0; - - char* lun = NULL; - - char* targetdev = NULL; - size_t targetdev_len = 0; - - char* targetdev_sysname = NULL; - size_t targetdev_sysname_len = 0; - - char* fcdev = NULL; - size_t fcdev_len = 0; - - int rc = 0; - - // look up SCSI parent target - rc = vdev_sysfs_get_parent_with_subsystem_devtype( parent, "scsi", "scsi_target", &targetdev, &targetdev_len ); - if( rc != 0 ) { - - return rc; - } - - // get target device name - rc = vdev_sysfs_get_sysname( targetdev, &targetdev_sysname, &targetdev_sysname_len ); - if( rc != 0 ) { - - free( targetdev ); - return rc; - } - - // find the corresponding fibrechannel sysfs path - rc = vdev_sysfs_device_path_from_subsystem_sysname( "/sys", "fc_transport", targetdev_sysname, &fcdev, &fcdev_len ); - if( rc != 0 ) { - - free( targetdev ); - free( targetdev_sysname ); - return rc; - } - - free( targetdev_sysname ); - - // look up the port name - rc = vdev_sysfs_read_attr( fcdev, "port_name", &port, &port_len ); - if( rc != 0 ) { - - free( targetdev ); - return rc; - } - - free( fcdev ); - - // parse port name - rc = format_lun_number( parent, &lun ); - - path_prepend( path, "fc-%s-%s", port, lun ); - - if( lun != NULL ) { - free( lun ); - } - - // parent stays the same - *new_parent = strdup( parent ); - if( *new_parent == NULL ) { - - return -ENOMEM; - } - - return 0; +static int handle_scsi_fibre_channel(char const *parent, char **path, + char **new_parent) +{ + + char *port = NULL; + size_t port_len = 0; + + char *lun = NULL; + + char *targetdev = NULL; + size_t targetdev_len = 0; + + char *targetdev_sysname = NULL; + size_t targetdev_sysname_len = 0; + + char *fcdev = NULL; + size_t fcdev_len = 0; + + int rc = 0; + + // look up SCSI parent target + rc = vdev_sysfs_get_parent_with_subsystem_devtype(parent, "scsi", + "scsi_target", + &targetdev, + &targetdev_len); + if (rc != 0) { + + return rc; + } + // get target device name + rc = vdev_sysfs_get_sysname(targetdev, &targetdev_sysname, + &targetdev_sysname_len); + if (rc != 0) { + + free(targetdev); + return rc; + } + // find the corresponding fibrechannel sysfs path + rc = vdev_sysfs_device_path_from_subsystem_sysname("/sys", + "fc_transport", + targetdev_sysname, + &fcdev, &fcdev_len); + if (rc != 0) { + + free(targetdev); + free(targetdev_sysname); + return rc; + } + + free(targetdev_sysname); + + // look up the port name + rc = vdev_sysfs_read_attr(fcdev, "port_name", &port, &port_len); + if (rc != 0) { + + free(targetdev); + return rc; + } + + free(fcdev); + + // parse port name + rc = format_lun_number(parent, &lun); + + path_prepend(path, "fc-%s-%s", port, lun); + + if (lun != NULL) { + free(lun); + } + // parent stays the same + *new_parent = strdup(parent); + if (*new_parent == NULL) { + + return -ENOMEM; + } + + return 0; } // persistent name for SCSI SAS wide port // return 0 on success, and update *path with the new persistent name information and set *new_parent to the next parent to parse // return negative on error -static int handle_scsi_sas_wide_port( char const *parent, char **path, char** new_parent ) { - - char* targetdev = NULL; - size_t targetdev_len = 0; - - char* targetparent = NULL; - size_t targetparent_len = 0; - - char* targetparent_sysname = NULL; - size_t targetparent_sysname_len = 0; - - char* sasdev = NULL; - size_t sasdev_len = 0; - - char* sas_address = NULL; - size_t sas_address_len = 0; - - char* lun = NULL; - - int rc = 0; - - rc = vdev_sysfs_get_parent_with_subsystem_devtype( parent, "scsi", "scsi_target", &targetdev, &targetdev_len ); - if( rc != 0 ) { - return rc; - } - - rc = vdev_sysfs_get_parent_device( parent, &targetparent, &targetparent_len ); - if( rc != 0 ) { - - free( targetdev ); - return rc; - } - - rc = vdev_sysfs_get_sysname( targetparent, &targetparent_sysname, &targetparent_sysname_len ); - if( rc != 0 ) { - - free( targetdev ); - free( targetparent ); - return rc; - } - - // find the sas device - rc = vdev_sysfs_device_path_from_subsystem_sysname( "/sys", "sas_device", targetparent_sysname, &sasdev, &sasdev_len ); - - free( targetparent ); - free( targetparent_sysname ); - - if( rc != 0 ) { - - free( targetdev ); - return rc; - } - - // find the address - rc = vdev_sysfs_read_attr( sasdev, "sas_address", &sas_address, &sas_address_len ); - if( rc != 0 ) { - - free( targetdev ); - return rc; - } - - format_lun_number( parent, &lun ); - path_prepend( path, "sas-%s-%s", sas_address, lun ); - - if( lun != NULL ) { - free( lun ); - } - - free( targetdev ); - - *new_parent = strdup( parent ); - if( *new_parent == NULL ) { - - return -ENOMEM; - } - - return 0; -} +static int handle_scsi_sas_wide_port(char const *parent, char **path, + char **new_parent) +{ + + char *targetdev = NULL; + size_t targetdev_len = 0; + + char *targetparent = NULL; + size_t targetparent_len = 0; + + char *targetparent_sysname = NULL; + size_t targetparent_sysname_len = 0; + + char *sasdev = NULL; + size_t sasdev_len = 0; + + char *sas_address = NULL; + size_t sas_address_len = 0; + + char *lun = NULL; + + int rc = 0; + + rc = vdev_sysfs_get_parent_with_subsystem_devtype(parent, "scsi", + "scsi_target", + &targetdev, + &targetdev_len); + if (rc != 0) { + return rc; + } + + rc = vdev_sysfs_get_parent_device(parent, &targetparent, + &targetparent_len); + if (rc != 0) { + + free(targetdev); + return rc; + } + + rc = vdev_sysfs_get_sysname(targetparent, &targetparent_sysname, + &targetparent_sysname_len); + if (rc != 0) { + + free(targetdev); + free(targetparent); + return rc; + } + // find the sas device + rc = vdev_sysfs_device_path_from_subsystem_sysname("/sys", "sas_device", + targetparent_sysname, + &sasdev, + &sasdev_len); + free(targetparent); + free(targetparent_sysname); + + if (rc != 0) { + + free(targetdev); + return rc; + } + // find the address + rc = vdev_sysfs_read_attr(sasdev, "sas_address", &sas_address, + &sas_address_len); + if (rc != 0) { + + free(targetdev); + return rc; + } + + format_lun_number(parent, &lun); + path_prepend(path, "sas-%s-%s", sas_address, lun); + + if (lun != NULL) { + free(lun); + } + + free(targetdev); + + *new_parent = strdup(parent); + if (*new_parent == NULL) { + + return -ENOMEM; + } + + return 0; +} // get the persistent path for a SCSI SAS // return 0 on success, and update *path with the persistent path information for this device, and set *parent to the next parent to process // return negative on error -static int handle_scsi_sas( char const* parent, char **path, char** new_parent ) { - - char* targetdev = NULL; - size_t targetdev_len = 0; - - char* target_parent = NULL; - size_t target_parent_len = 0; - - char* target_parent_sysname = NULL; - size_t target_parent_sysname_len = 0; - - char* port = NULL; - size_t port_len = 0; - - char* port_sysname = NULL; - size_t port_sysname_len = 0; - - char* expander = NULL; - size_t expander_len = 0; - - char* expander_sysname = NULL; - size_t expander_sysname_len = 0; - - char* target_sasdev = NULL; - size_t target_sasdev_len = 0; - - char* expander_sasdev = NULL; - size_t expander_sasdev_len = 0; - - char* port_sasdev = NULL; - size_t port_sasdev_len = 0; - - char* sas_address = NULL; - size_t sas_address_len = 0; - - char* phy_id = NULL; - size_t phy_id_len = 0; - - char* phy_count = NULL; - size_t phy_count_len = 0; - - char* lun = NULL; - - int rc = 0; - - // find scsi target parent device - rc = vdev_sysfs_get_parent_with_subsystem_devtype( parent, "scsi", "scsi_target", &targetdev, &targetdev_len ); - if( rc != 0 ) { - - return rc; - } - - // find parent of the scsi target - rc = vdev_sysfs_get_parent_device( targetdev, &target_parent, &target_parent_len ); - - free( targetdev ); - - if( rc != 0 ) { - - return rc; - } - - // get parent sysname - rc = vdev_sysfs_get_sysname( target_parent, &target_parent_sysname, &target_parent_sysname_len ); - if( rc != 0 ) { - - free( target_parent ); - return rc; - } - - // get sas device - rc = vdev_sysfs_device_path_from_subsystem_sysname( "/sys", "sas_device", target_parent_sysname, &target_sasdev, &target_sasdev_len ); - - free( target_parent ); - - if( rc != 0 ) { - - return rc; - } - - // get the sas port (parent of the sas device) - rc = vdev_sysfs_get_parent_device( target_parent, &port, &port_len ); - if( rc != 0 ) { - - free( target_sasdev ); - return rc; - } - - // get sas port sysname - rc = vdev_sysfs_get_sysname( port, &port_sysname, &port_sysname_len ); - if( rc != 0 ) { - - free( target_sasdev ); - free( port ); - return rc; - } - - // get the port device - rc = vdev_sysfs_device_path_from_subsystem_sysname( "/sys", "sas_port", port_sysname, &port_sasdev, &port_sasdev_len ); - - free( port_sysname ); - - if( rc != 0 ) { - - free( target_sasdev ); - free( port ); - return rc; - } - - // get phy count for this sas device - rc = vdev_sysfs_read_attr( port_sasdev, "num_phys", &phy_count, &phy_count_len ); - if( rc != 0 ) { - - free( target_sasdev ); - free( port_sasdev ); - free( port ); - return rc; - } - - // one disk? - if( strncmp( phy_count, "1", 2 ) != 0 ) { - - // wide port - rc = handle_scsi_sas_wide_port( parent, path, new_parent ); - - free( target_sasdev ); - free( port_sasdev ); - - return rc; - } - - free( phy_count ); - - // multiple disks... - // which one is this? - rc = vdev_sysfs_read_attr( target_sasdev, "phy_identifier", &phy_id, &phy_id_len ); - - free( target_sasdev ); - - if( rc != 0 ) { - - free( port ); - return rc; - } - - // parent is either an HBA or expander device... - rc = vdev_sysfs_get_parent_device( port, &expander, &expander_len ); - - free( port ); - - if( rc != 0 ) { - - free( phy_id ); - return rc; - } - - // get the expander sysname - rc = vdev_sysfs_get_sysname( expander, &expander_sysname, &expander_sysname_len ); - if( rc != 0 ) { - - free( phy_id ); - free( expander ); - return rc; - } - - free( expander ); - - // get the expander sas device - rc = vdev_sysfs_device_path_from_subsystem_sysname( "/sys", "sas_device", expander_sysname, &expander_sasdev, &expander_sasdev_len ); - - free( expander_sysname ); - - if( rc == 0 ) { - - // has expander device - // get its address - rc = vdev_sysfs_read_attr( expander_sasdev, "sas_address", &sas_address, &sas_address_len ); - free( expander_sasdev ); - - if( rc != 0 ) { - - free( phy_id ); - return rc; - } - } - - format_lun_number( parent, &lun ); - - if( sas_address != NULL ) { - - path_prepend(path, "sas-exp%s-phy%s-%s", sas_address, phy_id, lun); - free( sas_address ); - } - else { - - path_prepend(path, "sas-phy%s-%s", phy_id, lun); - } - - if( lun != NULL ) { - free( lun ); - } - - free( phy_id ); - - *new_parent = strdup( parent ); - if( *new_parent == NULL ) { - - return -ENOMEM; - } - - return 0; -} +static int handle_scsi_sas(char const *parent, char **path, char **new_parent) +{ + + char *targetdev = NULL; + size_t targetdev_len = 0; + + char *target_parent = NULL; + size_t target_parent_len = 0; + + char *target_parent_sysname = NULL; + size_t target_parent_sysname_len = 0; + + char *port = NULL; + size_t port_len = 0; + + char *port_sysname = NULL; + size_t port_sysname_len = 0; + + char *expander = NULL; + size_t expander_len = 0; + + char *expander_sysname = NULL; + size_t expander_sysname_len = 0; + + char *target_sasdev = NULL; + size_t target_sasdev_len = 0; + + char *expander_sasdev = NULL; + size_t expander_sasdev_len = 0; + + char *port_sasdev = NULL; + size_t port_sasdev_len = 0; + + char *sas_address = NULL; + size_t sas_address_len = 0; + + char *phy_id = NULL; + size_t phy_id_len = 0; + + char *phy_count = NULL; + size_t phy_count_len = 0; + + char *lun = NULL; + + int rc = 0; + + // find scsi target parent device + rc = vdev_sysfs_get_parent_with_subsystem_devtype(parent, "scsi", + "scsi_target", + &targetdev, + &targetdev_len); + if (rc != 0) { + + return rc; + } + // find parent of the scsi target + rc = vdev_sysfs_get_parent_device(targetdev, &target_parent, + &target_parent_len); + + free(targetdev); + + if (rc != 0) { + + return rc; + } + // get parent sysname + rc = vdev_sysfs_get_sysname(target_parent, &target_parent_sysname, + &target_parent_sysname_len); + if (rc != 0) { + + free(target_parent); + return rc; + } + // get sas device + rc = vdev_sysfs_device_path_from_subsystem_sysname("/sys", "sas_device", + target_parent_sysname, + &target_sasdev, + &target_sasdev_len); + + free(target_parent); + + if (rc != 0) { + + return rc; + } + // get the sas port (parent of the sas device) + rc = vdev_sysfs_get_parent_device(target_parent, &port, &port_len); + if (rc != 0) { + + free(target_sasdev); + return rc; + } + // get sas port sysname + rc = vdev_sysfs_get_sysname(port, &port_sysname, &port_sysname_len); + if (rc != 0) { + + free(target_sasdev); + free(port); + return rc; + } + // get the port device + rc = vdev_sysfs_device_path_from_subsystem_sysname("/sys", "sas_port", + port_sysname, + &port_sasdev, + &port_sasdev_len); + + free(port_sysname); + + if (rc != 0) { + + free(target_sasdev); + free(port); + return rc; + } + // get phy count for this sas device + rc = vdev_sysfs_read_attr(port_sasdev, "num_phys", &phy_count, + &phy_count_len); + if (rc != 0) { + + free(target_sasdev); + free(port_sasdev); + free(port); + return rc; + } + // one disk? + if (strncmp(phy_count, "1", 2) != 0) { + + // wide port + rc = handle_scsi_sas_wide_port(parent, path, new_parent); + + free(target_sasdev); + free(port_sasdev); + + return rc; + } + + free(phy_count); + + // multiple disks... + // which one is this? + rc = vdev_sysfs_read_attr(target_sasdev, "phy_identifier", &phy_id, + &phy_id_len); + + free(target_sasdev); + + if (rc != 0) { + + free(port); + return rc; + } + // parent is either an HBA or expander device... + rc = vdev_sysfs_get_parent_device(port, &expander, &expander_len); + + free(port); + + if (rc != 0) { + + free(phy_id); + return rc; + } + // get the expander sysname + rc = vdev_sysfs_get_sysname(expander, &expander_sysname, + &expander_sysname_len); + if (rc != 0) { + + free(phy_id); + free(expander); + return rc; + } + + free(expander); + + // get the expander sas device + rc = vdev_sysfs_device_path_from_subsystem_sysname("/sys", "sas_device", + expander_sysname, + &expander_sasdev, + &expander_sasdev_len); + + free(expander_sysname); + if (rc == 0) { + + // has expander device + // get its address + rc = vdev_sysfs_read_attr(expander_sasdev, "sas_address", + &sas_address, &sas_address_len); + free(expander_sasdev); + + if (rc != 0) { + + free(phy_id); + return rc; + } + } + + format_lun_number(parent, &lun); + + if (sas_address != NULL) { + + path_prepend(path, "sas-exp%s-phy%s-%s", sas_address, phy_id, + lun); + free(sas_address); + } else { + + path_prepend(path, "sas-phy%s-%s", phy_id, lun); + } + + if (lun != NULL) { + free(lun); + } + + free(phy_id); + + *new_parent = strdup(parent); + if (*new_parent == NULL) { + + return -ENOMEM; + } + + return 0; +} // generate persistent path for iscsi devices // return 0 on success, and update *path with this device's persistent path information, and set *parent to the next parent device to explore // return negative on errror -static int handle_scsi_iscsi( char const* parent, char **path, char** new_parent ) { - - char* transportdev = NULL; - - char* transportdev_sysname = NULL; - size_t transportdev_sysname_len = 0; - - char* sessiondev = NULL; - size_t sessiondev_len = 0; - - char* target = NULL; - size_t target_len = 0; - - char* connname = NULL; - - char* conndev = NULL; - size_t conndev_len = 0; - - char* addr = NULL; - size_t addr_len = 0; - - char* port = NULL; - size_t port_len = 0; - - char* lun = NULL; - - int rc = 0; - - // find iscsi session - transportdev = (char*)parent; - - while( 1 ) { - - char* transport_parent = NULL; - size_t transport_parent_len = 0; - - rc = vdev_sysfs_get_parent_device( transportdev, &transport_parent, &transport_parent_len ); - if( rc != 0 ) { - - return rc; - } - - transportdev = transport_parent; - if( strncmp( transportdev, "session", strlen("session") ) == 0 ) { - - break; - } - - free( transportdev ); - } - - // find tranport dev sysname - rc = vdev_sysfs_get_sysname( transportdev, &transportdev_sysname, &transportdev_sysname_len ); - if( rc != 0 ) { - - free( transportdev ); - return rc; - } - - free( transportdev ); - - // find iscsi session device - rc = vdev_sysfs_device_path_from_subsystem_sysname( "/sys", "iscsi_session", transportdev_sysname, &sessiondev, &sessiondev_len ); - if( rc != 0 ) { - - free( transportdev_sysname ); - return rc; - } - - // read the target - rc = vdev_sysfs_read_attr( sessiondev, "targetname", &target, &target_len ); - - free( sessiondev ); - - if( rc != 0 ) { - - free( transportdev_sysname ); - return rc; - } - - rc = asprintf( &connname, "connection%s:0", transportdev_sysname ); - - free( transportdev_sysname ); - - if( rc < 0 ) { - - free( target ); - free( connname ); - return rc; - } - - // find connection device - rc = vdev_sysfs_device_path_from_subsystem_sysname( "/sys", "iscsi_connection", connname, &conndev, &conndev_len ); - - free( connname ); - - if( rc != 0 ) { - - free( target ); - return rc; - } - - // look up address - rc = vdev_sysfs_read_attr( conndev, "persistent_address", &addr, &addr_len ); - if( rc != 0 ) { - - free( target ); - return rc; - } - - // look up port - rc = vdev_sysfs_read_attr( conndev, "persistent_port", &port, &port_len ); - if( rc != 0 ) { - - free( addr ); - free( target ); - return rc; - } - - // make the name! - format_lun_number( parent, &lun ); - path_prepend( path, "ip-%s:%s-iscsi-%s-%s", addr, port, target, lun ); - - if( lun != NULL ) { - - free( lun ); - } - - free( port ); - free( target ); - free( addr ); - - *new_parent = strdup( parent ); - if( *new_parent == NULL ) { - - return -ENOMEM; - } - - return 0; -} +static int handle_scsi_iscsi(char const *parent, char **path, char **new_parent) +{ + + char *transportdev = NULL; + + char *transportdev_sysname = NULL; + size_t transportdev_sysname_len = 0; + + char *sessiondev = NULL; + size_t sessiondev_len = 0; + + char *target = NULL; + size_t target_len = 0; + + char *connname = NULL; + + char *conndev = NULL; + size_t conndev_len = 0; + + char *addr = NULL; + size_t addr_len = 0; + + char *port = NULL; + size_t port_len = 0; + + char *lun = NULL; + + int rc = 0; + + // find iscsi session + transportdev = (char *)parent; + + while (1) { + + char *transport_parent = NULL; + size_t transport_parent_len = 0; + + rc = vdev_sysfs_get_parent_device(transportdev, + &transport_parent, + &transport_parent_len); + if (rc != 0) { + + return rc; + } + transportdev = transport_parent; + if (strncmp(transportdev, "session", strlen("session")) == 0) { + break; + } + + free(transportdev); + } + + // find tranport dev sysname + rc = vdev_sysfs_get_sysname(transportdev, &transportdev_sysname, + &transportdev_sysname_len); + if (rc != 0) { + + free(transportdev); + return rc; + } + + free(transportdev); + + // find iscsi session device + rc = vdev_sysfs_device_path_from_subsystem_sysname("/sys", + "iscsi_session", + transportdev_sysname, + &sessiondev, + &sessiondev_len); + if (rc != 0) { + + free(transportdev_sysname); + return rc; + } + // read the target + rc = vdev_sysfs_read_attr(sessiondev, "targetname", &target, + &target_len); + + free(sessiondev); + + if (rc != 0) { + + free(transportdev_sysname); + return rc; + } + + rc = asprintf(&connname, "connection%s:0", transportdev_sysname); + + free(transportdev_sysname); + + if (rc < 0) { + + free(target); + free(connname); + return rc; + } + // find connection device + rc = vdev_sysfs_device_path_from_subsystem_sysname("/sys", + "iscsi_connection", + connname, &conndev, + &conndev_len); + + free(connname); + + if (rc != 0) { + + free(target); + return rc; + } + // look up address + rc = vdev_sysfs_read_attr(conndev, "persistent_address", &addr, + &addr_len); + if (rc != 0) { + + free(target); + return rc; + } + // look up port + rc = vdev_sysfs_read_attr(conndev, "persistent_port", &port, &port_len); + if (rc != 0) { + + free(addr); + free(target); + return rc; + } + // make the name! + format_lun_number(parent, &lun); + path_prepend(path, "ip-%s:%s-iscsi-%s-%s", addr, port, target, lun); + + if (lun != NULL) { + + free(lun); + } + + free(port); + free(target); + free(addr); + + *new_parent = strdup(parent); + if (*new_parent == NULL) { + + return -ENOMEM; + } + + return 0; +} // get scsi host information // return 0 on success // return negative on failure -static int scsi_read_host_info( char const* parent, char** hostdev, int* host, int* bus, int* target, int* lun ) { - - int rc = 0; - - size_t hostdev_len = 0; - - char* name = NULL; - size_t name_len = 0; - - // find scsi host parent device - rc = vdev_sysfs_device_path_from_subsystem_sysname( parent, "scsi", "scsi_host", hostdev, &hostdev_len ); - if( rc != 0 ) { - - return rc; - } - - // get sysname of scsi host - rc = vdev_sysfs_get_sysname( parent, &name, &name_len ); - if( rc != 0 ) { - - free( *hostdev ); - *hostdev = NULL; - - return rc; - } - - // read host, bus, target, and lun - rc = sscanf( name, "%d:%d:%d:%d", host, bus, target, lun ); - if( rc != 4 ) { - - // invalid name - free( *hostdev ); - *hostdev = NULL; - - free( name ); - return -EINVAL; - } - - free( name ); - - return 0; +static int scsi_read_host_info(char const *parent, char **hostdev, int *host, + int *bus, int *target, int *lun) +{ + + int rc = 0; + + size_t hostdev_len = 0; + + char *name = NULL; + size_t name_len = 0; + + // find scsi host parent device + rc = vdev_sysfs_device_path_from_subsystem_sysname(parent, "scsi", + "scsi_host", hostdev, + &hostdev_len); + if (rc != 0) { + + return rc; + } + // get sysname of scsi host + rc = vdev_sysfs_get_sysname(parent, &name, &name_len); + if (rc != 0) { + + free(*hostdev); + *hostdev = NULL; + + return rc; + } + // read host, bus, target, and lun + rc = sscanf(name, "%d:%d:%d:%d", host, bus, target, lun); + if (rc != 4) { + + // invalid name + free(*hostdev); + *hostdev = NULL; + + free(name); + return -EINVAL; + } + + free(name); + + return 0; } /* @@ -737,989 +773,998 @@ static int scsi_read_host_info( char const* parent, char** hostdev, int* host, i * this. Manual driver unbind/bind, parallel hotplug/unplug will * get into the way of this "I hope it works" logic. */ -static int scsi_host_offset( char const* hostdev_sysname ) { - - DIR* dir = NULL; - struct dirent* dent = NULL; - char* base = NULL; - char* pos = NULL; - int basenum = -1; - int rc = 0; - - base = strdup( hostdev_sysname ); - if( base == NULL ) { - return -ENOMEM; - } - - // sanity check - pos = strrchr(base, '/'); - if (pos == NULL) { - - free( base ); - return -EINVAL; - } - - // make base its dirname - pos[0] = '\0'; - - dir = opendir(base); - - if (dir == NULL) { - - rc = -errno; - free( base ); - return rc; - } - - for( dent = readdir( dir ); dent != NULL; dent = readdir( dir ) ) { - - char* rest = NULL; - int i = 0; - - // skip . and .. - if( dent->d_name[0] == '.' ) { - continue; - } - - // only regular files - if( dent->d_type != DT_DIR && dent->d_type != DT_LNK ) { - continue; - } - - // only files that start with "host" - if( strncmp( dent->d_name, "host", strlen("host") ) != 0 ) { - continue; - } - - // get base number - i = strtoul( &dent->d_name[4], &rest, 10 ); - if( rest[0] != '\0' ) { - continue; - } - - /* - * find the smallest number; the host really needs to export its - * own instance number per parent device; relying on the global host - * enumeration and plainly rebasing the numbers sounds unreliable - */ - if( basenum == -1 || i < basenum ) { - basenum = i; - } - } - - closedir( dir ); - - if( basenum == -1 ) { - - // not found - return -ENOENT; - } - - return basenum; -} +static int scsi_host_offset(char const *hostdev_sysname) +{ + + DIR *dir = NULL; + struct dirent *dent = NULL; + char *base = NULL; + char *pos = NULL; + int basenum = -1; + int rc = 0; + + base = strdup(hostdev_sysname); + if (base == NULL) { + return -ENOMEM; + } + // sanity check + pos = strrchr(base, '/'); + if (pos == NULL) { + + free(base); + return -EINVAL; + } + // make base its dirname + pos[0] = '\0'; + + dir = opendir(base); + + if (dir == NULL) { + rc = -errno; + free(base); + return rc; + } + + for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) { + + char *rest = NULL; + int i = 0; + + // skip . and .. + if (dent->d_name[0] == '.') { + continue; + } + // only regular files + if (dent->d_type != DT_DIR && dent->d_type != DT_LNK) { + continue; + } + // only files that start with "host" + if (strncmp(dent->d_name, "host", strlen("host")) != 0) { + continue; + } + // get base number + i = strtoul(&dent->d_name[4], &rest, 10); + if (rest[0] != '\0') { + continue; + } + + /* + * find the smallest number; the host really needs to export its + * own instance number per parent device; relying on the global host + * enumeration and plainly rebasing the numbers sounds unreliable + */ + if (basenum == -1 || i < basenum) { + basenum = i; + } + } + + closedir(dir); + + if (basenum == -1) { + + // not found + return -ENOENT; + } + + return basenum; +} // persistent default scsi path // return 0 on success, and update *path with the scsi path information, and set *parent to the next parent device to explore // return negative on error. -static int handle_scsi_default( char const* parent, char **path, char** new_parent ) { - - int rc = 0; - int attempts = 5; // arbitrary - - while( 1 ) { - - int host = 0, bus = 0, target = 0, lun = 0; - int host2 = 0, bus2 = 0, target2 = 0, lun2 = 0; - int host_offset = 0; - char* hostdev = NULL; - char* hostdev2 = NULL; - - char* hostdev_sysname = NULL; - size_t hostdev_sysname_len = 0; - - // get host info - rc = scsi_read_host_info( parent, &hostdev, &host, &bus, &target, &lun ); - - if( rc != 0 ) { - - return rc; - } - - // get host sysname - rc = vdev_sysfs_get_sysname( hostdev, &hostdev_sysname, &hostdev_sysname_len ); - if( rc != 0 ) { - - free( hostdev ); - return rc; - } - - // get host offset - host_offset = scsi_host_offset( hostdev_sysname ); - - free( hostdev_sysname ); - - if( host_offset < 0 ) { - - return -ENODATA; - } - - // get the host info, again, and verify that the kernel didn't race us - rc = scsi_read_host_info( parent, &hostdev2, &host2, &bus2, &target2, &lun2 ); - - if( rc != 0 ) { - - free( hostdev ); - return rc; - } - - // verify that nothing changed - if( strcmp(hostdev, hostdev2) != 0 || host != host2 || bus != bus2 || target != target2 || lun != lun2 ) { - - free( hostdev ); - free( hostdev2 ); - - // let the driver settle - sleep(1); - - attempts--; - if( attempts <= 0 ) { - - return -ETIMEDOUT; - } - - continue; - } - - // success - free( hostdev2 ); - - // success! - host -= host_offset; - - path_prepend(path, "scsi-%u:%u:%u:%u", host, bus, target, lun); - - *new_parent = hostdev; - break; - } - - return 0; -} +static int handle_scsi_default(char const *parent, char **path, + char **new_parent) +{ + + int rc = 0; + int attempts = 5; // arbitrary + + while (1) { + + int host = 0, bus = 0, target = 0, lun = 0; + int host2 = 0, bus2 = 0, target2 = 0, lun2 = 0; + int host_offset = 0; + char *hostdev = NULL; + char *hostdev2 = NULL; + + char *hostdev_sysname = NULL; + size_t hostdev_sysname_len = 0; + // get host info + rc = scsi_read_host_info(parent, &hostdev, &host, &bus, &target, + &lun); + if (rc != 0) { + + return rc; + } + // get host sysname + rc = vdev_sysfs_get_sysname(hostdev, &hostdev_sysname, + &hostdev_sysname_len); + if (rc != 0) { + + free(hostdev); + return rc; + } + // get host offset + host_offset = scsi_host_offset(hostdev_sysname); + + free(hostdev_sysname); + + if (host_offset < 0) { + + return -ENODATA; + } + // get the host info, again, and verify that the kernel didn't race us + rc = scsi_read_host_info(parent, &hostdev2, &host2, &bus2, + &target2, &lun2); + + if (rc != 0) { + + free(hostdev); + return rc; + } + // verify that nothing changed + if (strcmp(hostdev, hostdev2) != 0 || host != host2 + || bus != bus2 || target != target2 || lun != lun2) { + + free(hostdev); + free(hostdev2); + + // let the driver settle + sleep(1); + + attempts--; + if (attempts <= 0) { + + return -ETIMEDOUT; + } + + continue; + } + // success + free(hostdev2); + + // success! + host -= host_offset; + + path_prepend(path, "scsi-%u:%u:%u:%u", host, bus, target, lun); + + *new_parent = hostdev; + break; + } + + return 0; +} // create persistent path for a hyperv scsi device // return 0 on success, and append persistent path info to *path and set *new_parent to the next parent device to explore // return negative on error -static int handle_scsi_hyperv( char const* parent, char **path, char** new_parent ) { - - char* hostdev = NULL; - size_t hostdev_len = 0; - - char* vmbusdev = NULL; - size_t vmbusdev_len = 0; - - char* guid_str = NULL; - size_t guid_str_len = 0; - - char* lun = NULL; - - char guid[38]; - memset( guid, 0, 38 ); - - size_t i = 0; - size_t k = 0; - - int rc = 0; - - // get scsi host parent device - rc = vdev_sysfs_get_parent_with_subsystem_devtype( parent, "scsi", "scsi_host", &hostdev, &hostdev_len ); - if( rc != 0 ) { - - return rc; - } - - // get vmbus device--parent of scsi host - rc = vdev_sysfs_get_parent_device( hostdev, &vmbusdev, &vmbusdev_len ); - if( rc != 0 ) { - - free( hostdev ); - return rc; - } - - // get the guid - rc = vdev_sysfs_read_attr( vmbusdev, "device_id", &guid_str, &guid_str_len ); - - free( hostdev ); - free( vmbusdev ); - - if( rc != 0 ) { - - return rc; - } - - // sanity check - if( strlen(guid_str) < 37 || guid_str[0] != '{' || guid_str[36] != '}' ) { - - return -EINVAL; - } - - // remove '-' - for( i = 0, k = 0; i < 36; i++ ) { - - if( guid_str[i] == '-' ) { - continue; - } - - guid[k] = guid_str[i]; - k++; - } - guid[k] = '\0'; - - format_lun_number( parent, &lun ); - path_prepend(path, "vmbus-%s-%s", guid, lun); - - if( lun != NULL ) { - free( lun ); - } - - *new_parent = strdup( parent ); - if( *new_parent == NULL ) { - - return -ENOMEM; - } - - return 0; -} +static int handle_scsi_hyperv(char const *parent, char **path, + char **new_parent) +{ + + char *hostdev = NULL; + size_t hostdev_len = 0; + + char *vmbusdev = NULL; + size_t vmbusdev_len = 0; + + char *guid_str = NULL; + size_t guid_str_len = 0; + + char *lun = NULL; + + char guid[38]; + memset(guid, 0, 38); + + size_t i = 0; + size_t k = 0; + + int rc = 0; + + // get scsi host parent device + rc = vdev_sysfs_get_parent_with_subsystem_devtype(parent, "scsi", + "scsi_host", &hostdev, + &hostdev_len); + if (rc != 0) { + + return rc; + } + // get vmbus device--parent of scsi host + rc = vdev_sysfs_get_parent_device(hostdev, &vmbusdev, &vmbusdev_len); + if (rc != 0) { + + free(hostdev); + return rc; + } + // get the guid + rc = vdev_sysfs_read_attr(vmbusdev, "device_id", &guid_str, + &guid_str_len); + free(hostdev); + free(vmbusdev); + + if (rc != 0) { + + return rc; + } + // sanity check + if (strlen(guid_str) < 37 || guid_str[0] != '{' || guid_str[36] != '}') { + + return -EINVAL; + } + // remove '-' + for (i = 0, k = 0; i < 36; i++) { + + if (guid_str[i] == '-') { + continue; + } + + guid[k] = guid_str[i]; + k++; + } + guid[k] = '\0'; + + format_lun_number(parent, &lun); + path_prepend(path, "vmbus-%s-%s", guid, lun); + + if (lun != NULL) { + free(lun); + } + + *new_parent = strdup(parent); + if (*new_parent == NULL) { + + return -ENOMEM; + } + + return 0; +} // generate persistent device name for a scsi device. dispatch to implementation-specific handlers. // return 0 on success, and prepend *path with the persistent name for this device. Set *new_parent to the next parent to explore, and set // *supported_parent to true if this device has a parent we support for persistent names. // return negative on failure. -static int handle_scsi( char const* parent, char **path, char** new_parent, bool *supported_parent ) { - - char* devtype = NULL; - size_t devtype_len = 0; - - char* id = NULL; - size_t id_len = 0; - - int rc = 0; - - // verify that this is a scsi_device - rc = vdev_sysfs_uevent_read_key( parent, "DEVTYPE", &devtype, &devtype_len ); - if( rc != 0 ) { - - return rc; - } - - if( devtype == NULL || strcmp( devtype, "scsi_device" ) != 0 ) { - - // not a scsi device - *new_parent = strdup( parent ); - if( *new_parent == NULL ) { - - return -ENOMEM; - } - - return 0; - } - - // firewrire? - rc = vdev_sysfs_read_attr( parent, "ieee1394_id", &id, &id_len ); - free( devtype ); - - if( rc == 0 ) { - - // yup! - rc = skip_subsystem( parent, "scsi", new_parent ); - if( rc != 0 ) { - - free( id ); - return rc; - } - - path_prepend(path, "ieee1394-0x%s", id); - - free( id ); - - *supported_parent = true; - return 0; - } - - free( id ); - - if( strstr( parent, "/rport-" ) != NULL ) { - - // fibrechannel - rc = handle_scsi_fibre_channel( parent, path, new_parent ); - if( rc != 0 ) { - - return rc; - } - - *supported_parent = true; - return 0; - } - - if( strstr( parent, "/end_device-" ) != NULL ) { - - // SCSI SAS - rc = handle_scsi_sas( parent, path, new_parent ); - if( rc != 0 ) { - - return rc; - } - - *supported_parent = true; - return 0; - } - - if( strstr( parent, "/session" ) != NULL ) { - - // iSCSI - rc = handle_scsi_iscsi( parent, path, new_parent ); - if( rc != 0 ) { - - return rc; - } - - *supported_parent = true; - return 0; - } - - /* - * We do not support the ATA transport class, it uses global counters - * to name the ata devices which numbers spread across multiple - * controllers. - * - * The real link numbers are not exported. Also, possible chains of ports - * behind port multipliers cannot be composed that way. - * - * Until all that is solved at the kernel level, there are no by-path/ - * links for ATA devices. - */ - - if( strstr( parent, "/ata" ) != NULL ) { - - // not supported - *new_parent = NULL; - - return 0; - } - - if( strstr( parent, "/vmbus_" ) != NULL ) { - - rc = handle_scsi_hyperv( parent, path, new_parent ); - if( rc != 0 ) { - - return rc; - } - - return 0; - } - - // default - rc = handle_scsi_default( parent, path, new_parent ); - - return rc; +static int handle_scsi(char const *parent, char **path, char **new_parent, + bool * supported_parent) +{ + + char *devtype = NULL; + size_t devtype_len = 0; + + char *id = NULL; + size_t id_len = 0; + + int rc = 0; + + // verify that this is a scsi_device + rc = vdev_sysfs_uevent_read_key(parent, "DEVTYPE", &devtype, + &devtype_len); + if (rc != 0) { + + return rc; + } + + if (devtype == NULL || strcmp(devtype, "scsi_device") != 0) { + + // not a scsi device + *new_parent = strdup(parent); + if (*new_parent == NULL) { + + return -ENOMEM; + } + + return 0; + } + // firewrire? + rc = vdev_sysfs_read_attr(parent, "ieee1394_id", &id, &id_len); + free(devtype); + + if (rc == 0) { + + // yup! + rc = skip_subsystem(parent, "scsi", new_parent); + if (rc != 0) { + + free(id); + return rc; + } + + path_prepend(path, "ieee1394-0x%s", id); + + free(id); + + *supported_parent = true; + return 0; + } + + free(id); + + if (strstr(parent, "/rport-") != NULL) { + + // fibrechannel + rc = handle_scsi_fibre_channel(parent, path, new_parent); + if (rc != 0) { + + return rc; + } + + *supported_parent = true; + return 0; + } + + if (strstr(parent, "/end_device-") != NULL) { + + // SCSI SAS + rc = handle_scsi_sas(parent, path, new_parent); + if (rc != 0) { + + return rc; + } + + *supported_parent = true; + return 0; + } + + if (strstr(parent, "/session") != NULL) { + + // iSCSI + rc = handle_scsi_iscsi(parent, path, new_parent); + if (rc != 0) { + + return rc; + } + + *supported_parent = true; + return 0; + } + + /* + * We do not support the ATA transport class, it uses global counters + * to name the ata devices which numbers spread across multiple + * controllers. + * + * The real link numbers are not exported. Also, possible chains of ports + * behind port multipliers cannot be composed that way. + * + * Until all that is solved at the kernel level, there are no by-path/ + * links for ATA devices. + */ + + if (strstr(parent, "/ata") != NULL) { + + // not supported + *new_parent = NULL; + + return 0; + } + + if (strstr(parent, "/vmbus_") != NULL) { + + rc = handle_scsi_hyperv(parent, path, new_parent); + if (rc != 0) { + + return rc; + } + + return 0; + } + // default + rc = handle_scsi_default(parent, path, new_parent); + + return rc; } // add persistent path name information for a cciss device // return 0 on success, update *path, and set *new_parent to the next parent device to explore // return negative on failure -static int handle_cciss( char const* parent, char **path, char** new_parent ) { - - unsigned int controller = 0, disk = 0; - - char* parent_sysname = NULL; - size_t parent_sysname_len = 0; - - int rc = 0; - - rc = vdev_sysfs_get_sysname( parent, &parent_sysname, &parent_sysname_len ); - if( rc != 0 ) { - return rc; - } - - rc = sscanf( parent_sysname, "c%ud%u%*s", &controller, &disk ); - - free( parent_sysname ); - - if( rc != 2 ) { - - return -ENOENT; - } - - path_prepend(path, "cciss-disk%u", disk); - - rc = skip_subsystem( parent, "cciss", new_parent ); - - return rc; -} +static int handle_cciss(char const *parent, char **path, char **new_parent) +{ + + unsigned int controller = 0, disk = 0; + + char *parent_sysname = NULL; + size_t parent_sysname_len = 0; + + int rc = 0; + + rc = vdev_sysfs_get_sysname(parent, &parent_sysname, + &parent_sysname_len); + if (rc != 0) { + return rc; + } + + rc = sscanf(parent_sysname, "c%ud%u%*s", &controller, &disk); + + free(parent_sysname); + + if (rc != 2) { + + return -ENOENT; + } + path_prepend(path, "cciss-disk%u", disk); + + rc = skip_subsystem(parent, "cciss", new_parent); + + return rc; +} // add persistent path name information for a scsi tape device // always succeeds -static void handle_scsi_tape( char const* dev, char **path ) { - - // must be the last device in the syspath - if( *path != NULL ) { - return; - } - - char* sysname = NULL; - size_t sysname_len = 0; - - int rc = 0; - - rc = vdev_sysfs_get_sysname( dev, &sysname, &sysname_len ); - if( rc != 0 ) { - - return; - } - - if( strncmp( sysname, "nst", 3 ) == 0 && strchr( "lma", sysname[3] ) != NULL ) { - - path_prepend( path, "nst%c", sysname[3] ); - } - else if( strncmp( sysname, "st", 2 ) == 0 && strchr( "lma", sysname[2] ) != NULL ) { - - path_prepend( path, "st%c", sysname[2] ); - } - - free( sysname ); - return; -} +static void handle_scsi_tape(char const *dev, char **path) +{ + + // must be the last device in the syspath + if (*path != NULL) { + return; + } + + char *sysname = NULL; + size_t sysname_len = 0; + + int rc = 0; + rc = vdev_sysfs_get_sysname(dev, &sysname, &sysname_len); + if (rc != 0) { + + return; + } + + if (strncmp(sysname, "nst", 3) == 0 + && strchr("lma", sysname[3]) != NULL) { + + path_prepend(path, "nst%c", sysname[3]); + } else if (strncmp(sysname, "st", 2) == 0 + && strchr("lma", sysname[2]) != NULL) { + + path_prepend(path, "st%c", sysname[2]); + } + + free(sysname); + return; +} // add persistent path name information for a usb device // return 0 on success, update *path with the information, and set *new_parent to the next device to explore // return negative on failure -static int handle_usb( char const *parent, char **path, char** new_parent ) { - - int rc = 0; - - char* devtype = NULL; - size_t devtype_len = 0; - - char* sysname = NULL; - size_t sysname_len = 0; - - char* port = NULL; - - rc = vdev_sysfs_uevent_read_key( parent, "DEVTYPE", &devtype, &devtype_len ); - if( rc != 0 ) { - - *new_parent = strdup( parent ); - if( *new_parent == NULL ) { - - return -ENOMEM; - } - - return 0; - } - - if( strcmp( devtype, "usb_interface" ) != 0 && strcmp( devtype, "usb_device" ) != 0 ) { - - free( devtype ); - - *new_parent = strdup( parent ); - if( *new_parent == NULL ) { - - return -ENOMEM; - } - - return 0; - } - - free( devtype ); - - rc = vdev_sysfs_get_sysname( parent, &sysname, &sysname_len ); - if( rc != 0 ) { - - return rc; - } - - port = strchr( sysname, '-' ); - - if( port == NULL ) { - - *new_parent = strdup( parent ); - if( *new_parent == NULL ) { - - return -ENOMEM; - } - - free( sysname ); - - return 0; - } - - port++; - - rc = skip_subsystem( parent, "usb", new_parent ); - if( rc != 0 ) { - - free( sysname ); - - return rc; - } - - path_prepend( path, "usb-0:%s", port ); - - free( sysname ); - - return 0; -} +static int handle_usb(char const *parent, char **path, char **new_parent) +{ + + int rc = 0; + + char *devtype = NULL; + size_t devtype_len = 0; + + char *sysname = NULL; + size_t sysname_len = 0; + + char *port = NULL; + + rc = vdev_sysfs_uevent_read_key(parent, "DEVTYPE", &devtype, + &devtype_len); + if (rc != 0) { + + *new_parent = strdup(parent); + if (*new_parent == NULL) { + + return -ENOMEM; + } + + return 0; + } + + if (strcmp(devtype, "usb_interface") != 0 + && strcmp(devtype, "usb_device") != 0) { + + free(devtype); + + *new_parent = strdup(parent); + if (*new_parent == NULL) { + + return -ENOMEM; + } + + return 0; + } + + free(devtype); -static int handle_bcma( char const* parent, char **path, char** new_parent ) { - - unsigned int core = 0; - int rc = 0; - - char* sysname = NULL; - size_t sysname_len = 0; - - rc = vdev_sysfs_get_sysname( parent, &sysname, &sysname_len ); - if( rc != 0 ) { - - return rc; - } - - rc = sscanf( sysname, "bcma%*u:%u", &core ); - - free( sysname ); - - if( rc != 1 ) { - - return -ENOENT; - } - - path_prepend( path, "bcma-%u", core ); - - *new_parent = strdup( parent ); - if( *new_parent == NULL ) { - return -ENOMEM; - } - - return 0; + rc = vdev_sysfs_get_sysname(parent, &sysname, &sysname_len); + if (rc != 0) { + + return rc; + } + + port = strchr(sysname, '-'); + + if (port == NULL) { + + *new_parent = strdup(parent); + if (*new_parent == NULL) { + + return -ENOMEM; + } + + free(sysname); + + return 0; + } + + port++; + + rc = skip_subsystem(parent, "usb", new_parent); + if (rc != 0) { + + free(sysname); + + return rc; + } + + path_prepend(path, "usb-0:%s", port); + + free(sysname); + + return 0; } +static int handle_bcma(char const *parent, char **path, char **new_parent) +{ -static int handle_ccw( char const* parent, char const* dev, char **path, char** new_parent ) { - - char* scsi_dev = NULL; - size_t scsi_dev_len = 0; - - bool handled = false; - - int rc = 0; - - rc = vdev_sysfs_get_parent_with_subsystem_devtype( dev, "scsi", "scsi_device", &scsi_dev, &scsi_dev_len ); - if( rc == 0 ) { - - char* wwpn = NULL; - size_t wwpn_len = 0; - - char* lun = NULL; - size_t lun_len = 0; - - char* hba_id = NULL; - size_t hba_id_len = 0; - - vdev_sysfs_read_attr( scsi_dev, "hba_id", &hba_id, &hba_id_len ); - vdev_sysfs_read_attr( scsi_dev, "wwpn", &wwpn, &wwpn_len ); - vdev_sysfs_read_attr( scsi_dev, "fcp_lun", &lun, &lun_len ); - - if( hba_id != NULL && lun != NULL && wwpn != NULL ) { - - path_prepend(path, "ccw-%s-zfcp-%s:%s", hba_id, wwpn, lun); - handled = true; - } - - if( hba_id != NULL ) { - free( hba_id ); - } - if( lun != NULL ) { - free( lun ); - } - if( wwpn != NULL ) { - free( wwpn ); - } - } - - if( !handled ) { - - char* sysname = NULL; - size_t sysname_len = 0; - - rc = vdev_sysfs_get_sysname( parent, &sysname, &sysname_len ); - - if( rc != 0 ) { - - free( scsi_dev ); - return rc; - } - - path_prepend( path, "ccw-%s", sysname ); - - free( sysname ); - } - - free( scsi_dev ); - - rc = skip_subsystem( parent, "ccw", new_parent ); - if( rc != 0 ) { - return rc; - } - - return 0; + unsigned int core = 0; + int rc = 0; + + char *sysname = NULL; + size_t sysname_len = 0; + + rc = vdev_sysfs_get_sysname(parent, &sysname, &sysname_len); + if (rc != 0) { + + return rc; + } + + rc = sscanf(sysname, "bcma%*u:%u", &core); + + free(sysname); + + if (rc != 1) { + + return -ENOENT; + } + + path_prepend(path, "bcma-%u", core); + + *new_parent = strdup(parent); + if (*new_parent == NULL) { + return -ENOMEM; + } + + return 0; } +static int handle_ccw(char const *parent, char const *dev, char **path, + char **new_parent) +{ + + char *scsi_dev = NULL; + size_t scsi_dev_len = 0; + + bool handled = false; + + int rc = 0; + + rc = vdev_sysfs_get_parent_with_subsystem_devtype(dev, "scsi", + "scsi_device", + &scsi_dev, + &scsi_dev_len); + if (rc == 0) { -void usage( char const* progname ) { - - fprintf(stderr, "[ERROR] %s: Usage: %s /sysfs/path/to/device | /path/to/device/node\n", progname, progname ); + char *wwpn = NULL; + size_t wwpn_len = 0; + + char *lun = NULL; + size_t lun_len = 0; + + char *hba_id = NULL; + size_t hba_id_len = 0; + + vdev_sysfs_read_attr(scsi_dev, "hba_id", &hba_id, &hba_id_len); + vdev_sysfs_read_attr(scsi_dev, "wwpn", &wwpn, &wwpn_len); + vdev_sysfs_read_attr(scsi_dev, "fcp_lun", &lun, &lun_len); + + if (hba_id != NULL && lun != NULL && wwpn != NULL) { + + path_prepend(path, "ccw-%s-zfcp-%s:%s", hba_id, wwpn, + lun); + handled = true; + } + + if (hba_id != NULL) { + free(hba_id); + } + if (lun != NULL) { + free(lun); + } + if (wwpn != NULL) { + free(wwpn); + } + } + + if (!handled) { + + char *sysname = NULL; + size_t sysname_len = 0; + + rc = vdev_sysfs_get_sysname(parent, &sysname, &sysname_len); + + if (rc != 0) { + + free(scsi_dev); + return rc; + } + + path_prepend(path, "ccw-%s", sysname); + + free(sysname); + } + + free(scsi_dev); + + rc = skip_subsystem(parent, "ccw", new_parent); + if (rc != 0) { + return rc; + } + + return 0; } +void usage(char const *progname) +{ + + fprintf(stderr, + "[ERROR] %s: Usage: %s /sysfs/path/to/device | /path/to/device/node\n", + progname, progname); +} // entry point -int main( int argc, char** argv ) { - - char* parent = NULL; - size_t parent_len = 0; - - char* new_parent = NULL; - - char* sysname = NULL; - size_t sysname_len = 0; - - char* path = NULL; - - char* subsys = NULL; - size_t subsys_len = 0; - - bool supported_transport = false; - bool supported_parent = false; - - struct stat sb; - - int rc = 0; - - if( argc != 2 ) { - usage( argv[0] ); - exit(1); - } - - char* dev = NULL; - - // if this is a character device, then look up the device path - rc = stat( argv[1], &sb ); - if( rc != 0 ) { - - usage( argv[0] ); - exit(1); - } - - if( S_ISCHR( sb.st_mode ) ) { - - size_t dev_len = 0; - rc = vdev_sysfs_get_syspath_from_device( "/sys", sb.st_mode, major( sb.st_rdev ), minor( sb.st_rdev ), &dev, &dev_len ); - if( rc != 0 ) { - - fprintf(stderr, "[ERROR] %s: vdev_sysfs_get_syspath_from_device rc = %d\n", argv[0], rc ); - usage(argv[0]); - exit(1); - } - } - else { - - dev = strdup( argv[1] ); - } - - // s390 ccw bus? - rc = vdev_sysfs_get_parent_with_subsystem_devtype( dev, "ccw", NULL, &parent, &parent_len ); - if( rc == 0 ) { - - rc = handle_ccw( parent, dev, &path, &new_parent ); - if( rc != 0 ) { - exit(2); - } - - goto main_finish; - } - - // walk up the device sysfs path and make the persistent path - parent = strdup( dev ); - if( parent == NULL ) { - - exit(3); - } - - rc = 0; - - while( parent != NULL ) { - - vdev_sysfs_read_subsystem( parent, &subsys, &subsys_len ); - - log_debug("'%s': subsystem '%s'", parent, subsys ); - - if( subsys != NULL ) { - - if( strcmp( subsys, "scsi_tape" ) == 0 ) { - - handle_scsi_tape( parent, &path ); - } - else if( strcmp( subsys, "scsi" ) == 0 ) { - - rc = handle_scsi( parent, &path, &new_parent, &supported_parent ); - supported_transport = true; - } - else if( strcmp( subsys, "cciss" ) == 0 ) { - - rc = handle_cciss( parent, &path, &new_parent ); - supported_transport = true; - } - else if( strcmp( subsys, "usb" ) == 0 ) { - - rc = handle_usb( parent, &path, &new_parent ); - supported_transport = true; - } - else if( strcmp( subsys, "bcma" ) == 0 ) { - - rc = handle_bcma( parent, &path, &new_parent ); - supported_transport = true; - } - else if( strcmp( subsys, "serio" ) == 0 ) { - - int sysnum = 0; - rc = vdev_sysfs_get_sysnum( parent, &sysnum ); - if( rc == 0 ) { - - path_prepend( &path, "serio-%d", sysnum ); - - rc = skip_subsystem( parent, "serio", &new_parent ); - } - } - else if( strcmp( subsys, "pci" ) == 0 ) { - - rc = vdev_sysfs_get_sysname( parent, &sysname, &sysname_len ); - if( rc == 0 ) { - - path_prepend( &path, "pci-%s", sysname ); - free( sysname ); - - rc = skip_subsystem( parent, "pci", &new_parent ); - } - - supported_parent = true; - } - else if( strcmp( subsys, "platform" ) == 0 ) { - - rc = vdev_sysfs_get_sysname( parent, &sysname, &sysname_len ); - if( rc == 0 ) { - - path_prepend( &path, "platform-%s", sysname ); - free( sysname ); - - rc = skip_subsystem( parent, "platform", &new_parent ); - } - - supported_parent = true; - supported_transport = true; - } - else if( strcmp( subsys, "acpi" ) == 0 ) { - - rc = vdev_sysfs_get_sysname( parent, &sysname, &sysname_len ); - if( rc == 0 ) { - - path_prepend( &path, "acpi-%s", sysname ); - free( sysname ); - - rc = skip_subsystem( parent, "acpi", &new_parent ); - } - - supported_parent = true; - } - else if( strcmp( subsys, "xen" ) == 0 ) { - - rc = vdev_sysfs_get_sysname( parent, &sysname, &sysname_len ); - if( rc == 0 ) { - - path_prepend( &path, "xen-%s", sysname ); - free( sysname ); - - rc = skip_subsystem( parent, "xen", &new_parent ); - } - - supported_parent = true; - } - else if( strcmp( subsys, "scm" ) == 0 ) { - - rc = vdev_sysfs_get_sysname( parent, &sysname, &sysname_len ); - if( rc == 0 ) { - - path_prepend( &path, "scm-%s", sysname ); - free( sysname ); - - rc = skip_subsystem( parent, "scm", &new_parent ); - } - - supported_transport = true; - supported_parent = true; - } - } - - if( rc != 0 ) { - - exit(4); - } - - if( new_parent != NULL ) { - - log_debug("new parent is '%s' (original = '%s')", new_parent, parent ); - - free( parent ); - parent = new_parent; - - new_parent = NULL; - } - - char* next = NULL; - size_t next_len = 0; - - // next device - rc = vdev_sysfs_get_parent_device( parent, &next, &next_len ); - if( rc != 0 ) { - - if( rc == -ENOENT ) { - - break; - } - - // terminal error - exit(15); - } - - - log_debug("Parent of '%s' is '%s'\n", parent, next ); - - free( parent ); - parent = next; - - free( subsys ); - subsys = NULL; - } - - /* - * Do not return devices with an unknown parent device type. They - * might produce conflicting IDs if the parent does not provide a - * unique and predictable name. - */ - if( !supported_parent ) { - - log_debug("%s", "Unsupported parent"); - - if( path != NULL ) { - free( path ); - } - path = NULL; - } - - /* - * Do not return block devices without a well-known transport. Some - * devices do not expose their buses and do not provide a unique - * and predictable name that way. - */ - rc = vdev_sysfs_read_subsystem( dev, &subsys, &subsys_len ); - if( rc != 0 ) { - - if( path != NULL ) { - free( path ); - } - - exit(16); - } - - if( strcmp( subsys, "block" ) == 0 && !supported_transport ) { - - log_debug("'%s': Unsupported transport", dev); - - if( path != NULL ) { - free( path ); - } - exit(17); - } - -main_finish: - - free( dev ); - free( subsys ); - - if( path != NULL ) { - - char tag[4097]; - memset( tag, 0, 4097 ); - - size_t i = 0; - char const* p = NULL; - - - /* compose valid udev tag name */ - for (p = path, i = 0; *p != '\0'; p++ ) { - - // alphanumeric? - if ((*p >= '0' && *p <= '9') || - (*p >= 'A' && *p <= 'Z') || - (*p >= 'a' && *p <= 'z') || - *p == '-') { - - tag[i++] = *p; - continue; - } - - // skip leading '_' - if( i == 0 ) { - continue; - } - - // avoid second '_' - if( tag[i-1] == '_' ) { - continue; - } - - tag[i++] = '_'; - } - - /* strip trailing '_' */ - while( i > 0 && tag[i-1] == '_' ) { - i--; - } - - tag[i] = '\0'; - - // replaces ID_PATH and ID_PATH_TAG - vdev_property_add( "VDEV_PERSISTENT_PATH", path ); - vdev_property_add( "VDEV_PERSISTENT_PATH_TAG", tag ); - - free( path ); - - vdev_property_print(); - vdev_property_free_all(); - - exit(0); - } - else { - - // no path - vdev_property_add( "VDEV_PERSISTENT_PATH", "" ); - vdev_property_add( "VDEV_PERSISTENT_PATH_TAG", "" ); - - vdev_property_print(); - vdev_property_free_all(); - - exit(0); - } +int main(int argc, char **argv) +{ + + char *parent = NULL; + size_t parent_len = 0; + + char *new_parent = NULL; + + char *sysname = NULL; + size_t sysname_len = 0; + + char *path = NULL; + + char *subsys = NULL; + size_t subsys_len = 0; + + bool supported_transport = false; + bool supported_parent = false; + + struct stat sb; + + int rc = 0; + + if (argc != 2) { + usage(argv[0]); + exit(1); + } + + char *dev = NULL; + + // if this is a character device, then look up the device path + rc = stat(argv[1], &sb); + if (rc != 0) { + + usage(argv[0]); + exit(1); + } + + if (S_ISCHR(sb.st_mode)) { + + size_t dev_len = 0; + rc = vdev_sysfs_get_syspath_from_device("/sys", sb.st_mode, + major(sb.st_rdev), + minor(sb.st_rdev), &dev, + &dev_len); + if (rc != 0) { + + fprintf(stderr, + "[ERROR] %s: vdev_sysfs_get_syspath_from_device rc = %d\n", + argv[0], rc); + usage(argv[0]); + exit(1); + } + } else { + + dev = strdup(argv[1]); + } + + // s390 ccw bus? + rc = vdev_sysfs_get_parent_with_subsystem_devtype(dev, "ccw", NULL, + &parent, &parent_len); + if (rc == 0) { + + rc = handle_ccw(parent, dev, &path, &new_parent); + if (rc != 0) { + exit(2); + } + + goto main_finish; + } + // walk up the device sysfs path and make the persistent path + parent = strdup(dev); + if (parent == NULL) { + + exit(3); + } + + rc = 0; + + while (parent != NULL) { + + vdev_sysfs_read_subsystem(parent, &subsys, &subsys_len); + + log_debug("'%s': subsystem '%s'", parent, subsys); + + if (subsys != NULL) { + + if (strcmp(subsys, "scsi_tape") == 0) { + + handle_scsi_tape(parent, &path); + } else if (strcmp(subsys, "scsi") == 0) { + + rc = handle_scsi(parent, &path, &new_parent, + &supported_parent); + supported_transport = true; + } else if (strcmp(subsys, "cciss") == 0) { + + rc = handle_cciss(parent, &path, &new_parent); + supported_transport = true; + } else if (strcmp(subsys, "usb") == 0) { + + rc = handle_usb(parent, &path, &new_parent); + supported_transport = true; + } else if (strcmp(subsys, "bcma") == 0) { + + rc = handle_bcma(parent, &path, &new_parent); + supported_transport = true; + } else if (strcmp(subsys, "serio") == 0) { + + int sysnum = 0; + rc = vdev_sysfs_get_sysnum(parent, &sysnum); + if (rc == 0) { + + path_prepend(&path, "serio-%d", sysnum); + + rc = skip_subsystem(parent, "serio", + &new_parent); + } + } else if (strcmp(subsys, "pci") == 0) { + + rc = vdev_sysfs_get_sysname(parent, &sysname, + &sysname_len); + if (rc == 0) { + + path_prepend(&path, "pci-%s", sysname); + free(sysname); + + rc = skip_subsystem(parent, "pci", + &new_parent); + } + + supported_parent = true; + } else if (strcmp(subsys, "platform") == 0) { + + rc = vdev_sysfs_get_sysname(parent, &sysname, + &sysname_len); + if (rc == 0) { + + path_prepend(&path, "platform-%s", + sysname); + free(sysname); + + rc = skip_subsystem(parent, "platform", + &new_parent); + } + + supported_parent = true; + supported_transport = true; + } else if (strcmp(subsys, "acpi") == 0) { + + rc = vdev_sysfs_get_sysname(parent, &sysname, + &sysname_len); + if (rc == 0) { + + path_prepend(&path, "acpi-%s", sysname); + free(sysname); + + rc = skip_subsystem(parent, "acpi", + &new_parent); + } + + supported_parent = true; + } else if (strcmp(subsys, "xen") == 0) { + + rc = vdev_sysfs_get_sysname(parent, &sysname, + &sysname_len); + if (rc == 0) { + + path_prepend(&path, "xen-%s", sysname); + free(sysname); + + rc = skip_subsystem(parent, "xen", + &new_parent); + } + + supported_parent = true; + } else if (strcmp(subsys, "scm") == 0) { + + rc = vdev_sysfs_get_sysname(parent, &sysname, + &sysname_len); + if (rc == 0) { + + path_prepend(&path, "scm-%s", sysname); + free(sysname); + + rc = skip_subsystem(parent, "scm", + &new_parent); + } + + supported_transport = true; + supported_parent = true; + } + } + + if (rc != 0) { + + exit(4); + } + + if (new_parent != NULL) { + + log_debug("new parent is '%s' (original = '%s')", + new_parent, parent); + + free(parent); + parent = new_parent; + + new_parent = NULL; + } + + char *next = NULL; + size_t next_len = 0; + + // next device + rc = vdev_sysfs_get_parent_device(parent, &next, &next_len); + if (rc != 0) { + + if (rc == -ENOENT) { + + break; + } + // terminal error + exit(15); + } + + log_debug("Parent of '%s' is '%s'\n", parent, next); + + free(parent); + parent = next; + + free(subsys); + subsys = NULL; + } + + /* + * Do not return devices with an unknown parent device type. They + * might produce conflicting IDs if the parent does not provide a + * unique and predictable name. + */ + if (!supported_parent) { + + log_debug("%s", "Unsupported parent"); + + if (path != NULL) { + free(path); + } + path = NULL; + } + + /* + * Do not return block devices without a well-known transport. Some + * devices do not expose their buses and do not provide a unique + * and predictable name that way. + */ + rc = vdev_sysfs_read_subsystem(dev, &subsys, &subsys_len); + if (rc != 0) { + + if (path != NULL) { + free(path); + } + + exit(16); + } + + if (strcmp(subsys, "block") == 0 && !supported_transport) { + + log_debug("'%s': Unsupported transport", dev); + + if (path != NULL) { + free(path); + } + exit(17); + } + + main_finish: + + free(dev); + free(subsys); + + if (path != NULL) { + + char tag[4097]; + memset(tag, 0, 4097); + + size_t i = 0; + char const *p = NULL; + + /* compose valid udev tag name */ + for (p = path, i = 0; *p != '\0'; p++) { + + // alphanumeric? + if ((*p >= '0' && *p <= '9') || + (*p >= 'A' && *p <= 'Z') || + (*p >= 'a' && *p <= 'z') || *p == '-') { + + tag[i++] = *p; + continue; + } + // skip leading '_' + if (i == 0) { + continue; + } + // avoid second '_' + if (tag[i - 1] == '_') { + continue; + } + + tag[i++] = '_'; + } + + /* strip trailing '_' */ + while (i > 0 && tag[i - 1] == '_') { + i--; + } + + tag[i] = '\0'; + + // replaces ID_PATH and ID_PATH_TAG + vdev_property_add("VDEV_PERSISTENT_PATH", path); + vdev_property_add("VDEV_PERSISTENT_PATH_TAG", tag); + + free(path); + + vdev_property_print(); + vdev_property_free_all(); + + exit(0); + } else { + + // no path + vdev_property_add("VDEV_PERSISTENT_PATH", ""); + vdev_property_add("VDEV_PERSISTENT_PATH_TAG", ""); + + vdev_property_print(); + vdev_property_free_all(); + + exit(0); + } } diff --git a/vdevd/helpers/LINUX/stat_scsi.c b/vdevd/helpers/LINUX/stat_scsi.c index 74796dd..062914b 100644 --- a/vdevd/helpers/LINUX/stat_scsi.c +++ b/vdevd/helpers/LINUX/stat_scsi.c @@ -41,10 +41,10 @@ #include struct scsi_ioctl_command { - unsigned int inlen; /* excluding scsi command length */ - unsigned int outlen; - unsigned char data[1]; - /* on input, scsi command starts here then opt. data */ + unsigned int inlen; /* excluding scsi command length */ + unsigned int outlen; + unsigned char data[1]; + /* on input, scsi command starts here then opt. data */ }; /* @@ -103,9 +103,9 @@ struct scsi_ioctl_command { #define SCSI_ID_ASCII 2 struct scsi_id_search_values { - u_char id_type; - u_char naa_type; - u_char code_set; + u_char id_type; + u_char naa_type; + u_char code_set; }; /* @@ -145,39 +145,40 @@ struct scsi_id_search_values { #define MAX_BUFFER_LEN 256 struct scsi_id_device { - char vendor[9]; - char model[17]; - char revision[5]; - char type[33]; - char kernel[64]; - char serial[MAX_SERIAL_LEN]; - char serial_short[MAX_SERIAL_LEN]; - int use_sg; - - /* Always from page 0x80 e.g. 'B3G1P8500RWT' - may not be unique */ - char unit_serial_number[MAX_SERIAL_LEN]; - - /* NULs if not set - otherwise hex encoding using lower-case e.g. '50014ee0016eb572' */ - char wwn[17]; - - /* NULs if not set - otherwise hex encoding using lower-case e.g. '0xe00000d80000' */ - char wwn_vendor_extension[17]; - - /* NULs if not set - otherwise decimal number */ - char tgpt_group[8]; + char vendor[9]; + char model[17]; + char revision[5]; + char type[33]; + char kernel[64]; + char serial[MAX_SERIAL_LEN]; + char serial_short[MAX_SERIAL_LEN]; + int use_sg; + + /* Always from page 0x80 e.g. 'B3G1P8500RWT' - may not be unique */ + char unit_serial_number[MAX_SERIAL_LEN]; + + /* NULs if not set - otherwise hex encoding using lower-case e.g. '50014ee0016eb572' */ + char wwn[17]; + + /* NULs if not set - otherwise hex encoding using lower-case e.g. '0xe00000d80000' */ + char wwn_vendor_extension[17]; + + /* NULs if not set - otherwise decimal number */ + char tgpt_group[8]; }; -int scsi_std_inquiry( struct scsi_id_device *dev_scsi, const char *devname); -int scsi_get_serial( struct scsi_id_device *dev_scsi, const char *devname, int page_code, int len); +int scsi_std_inquiry(struct scsi_id_device *dev_scsi, const char *devname); +int scsi_get_serial(struct scsi_id_device *dev_scsi, const char *devname, + int page_code, int len); /* * Page code values. */ enum page_code { - PAGE_83_PRE_SPC3 = -0x83, - PAGE_UNSPECIFIED = 0x00, - PAGE_80 = 0x80, - PAGE_83 = 0x83, + PAGE_83_PRE_SPC3 = -0x83, + PAGE_UNSPECIFIED = 0x00, + PAGE_80 = 0x80, + PAGE_83 = 0x83, }; /* @@ -189,64 +190,63 @@ enum page_code { * is normally one or some small number of descriptors. */ static const struct scsi_id_search_values id_search_list[] = { - { SCSI_ID_TGTGROUP, SCSI_ID_NAA_DONT_CARE, SCSI_ID_BINARY }, - { SCSI_ID_NAA, SCSI_ID_NAA_IEEE_REG_EXTENDED, SCSI_ID_BINARY }, - { SCSI_ID_NAA, SCSI_ID_NAA_IEEE_REG_EXTENDED, SCSI_ID_ASCII }, - { SCSI_ID_NAA, SCSI_ID_NAA_IEEE_REG, SCSI_ID_BINARY }, - { SCSI_ID_NAA, SCSI_ID_NAA_IEEE_REG, SCSI_ID_ASCII }, - /* - * Devices already exist using NAA values that are now marked - * reserved. These should not conflict with other values, or it is - * a bug in the device. As long as we find the IEEE extended one - * first, we really don't care what other ones are used. Using - * don't care here means that a device that returns multiple - * non-IEEE descriptors in a random order will get different - * names. - */ - { SCSI_ID_NAA, SCSI_ID_NAA_DONT_CARE, SCSI_ID_BINARY }, - { SCSI_ID_NAA, SCSI_ID_NAA_DONT_CARE, SCSI_ID_ASCII }, - { SCSI_ID_EUI_64, SCSI_ID_NAA_DONT_CARE, SCSI_ID_BINARY }, - { SCSI_ID_EUI_64, SCSI_ID_NAA_DONT_CARE, SCSI_ID_ASCII }, - { SCSI_ID_T10_VENDOR, SCSI_ID_NAA_DONT_CARE, SCSI_ID_BINARY }, - { SCSI_ID_T10_VENDOR, SCSI_ID_NAA_DONT_CARE, SCSI_ID_ASCII }, - { SCSI_ID_VENDOR_SPECIFIC, SCSI_ID_NAA_DONT_CARE, SCSI_ID_BINARY }, - { SCSI_ID_VENDOR_SPECIFIC, SCSI_ID_NAA_DONT_CARE, SCSI_ID_ASCII }, + {SCSI_ID_TGTGROUP, SCSI_ID_NAA_DONT_CARE, SCSI_ID_BINARY}, + {SCSI_ID_NAA, SCSI_ID_NAA_IEEE_REG_EXTENDED, SCSI_ID_BINARY}, + {SCSI_ID_NAA, SCSI_ID_NAA_IEEE_REG_EXTENDED, SCSI_ID_ASCII}, + {SCSI_ID_NAA, SCSI_ID_NAA_IEEE_REG, SCSI_ID_BINARY}, + {SCSI_ID_NAA, SCSI_ID_NAA_IEEE_REG, SCSI_ID_ASCII}, + /* + * Devices already exist using NAA values that are now marked + * reserved. These should not conflict with other values, or it is + * a bug in the device. As long as we find the IEEE extended one + * first, we really don't care what other ones are used. Using + * don't care here means that a device that returns multiple + * non-IEEE descriptors in a random order will get different + * names. + */ + {SCSI_ID_NAA, SCSI_ID_NAA_DONT_CARE, SCSI_ID_BINARY}, + {SCSI_ID_NAA, SCSI_ID_NAA_DONT_CARE, SCSI_ID_ASCII}, + {SCSI_ID_EUI_64, SCSI_ID_NAA_DONT_CARE, SCSI_ID_BINARY}, + {SCSI_ID_EUI_64, SCSI_ID_NAA_DONT_CARE, SCSI_ID_ASCII}, + {SCSI_ID_T10_VENDOR, SCSI_ID_NAA_DONT_CARE, SCSI_ID_BINARY}, + {SCSI_ID_T10_VENDOR, SCSI_ID_NAA_DONT_CARE, SCSI_ID_ASCII}, + {SCSI_ID_VENDOR_SPECIFIC, SCSI_ID_NAA_DONT_CARE, SCSI_ID_BINARY}, + {SCSI_ID_VENDOR_SPECIFIC, SCSI_ID_NAA_DONT_CARE, SCSI_ID_ASCII}, }; -static const char hex_str[]="0123456789abcdef"; +static const char hex_str[] = "0123456789abcdef"; /* * Values returned in the result/status, only the ones used by the code * are used here. */ -#define DID_NO_CONNECT 0x01 /* Unable to connect before timeout */ -#define DID_BUS_BUSY 0x02 /* Bus remain busy until timeout */ -#define DID_TIME_OUT 0x03 /* Timed out for some other reason */ +#define DID_NO_CONNECT 0x01 /* Unable to connect before timeout */ +#define DID_BUS_BUSY 0x02 /* Bus remain busy until timeout */ +#define DID_TIME_OUT 0x03 /* Timed out for some other reason */ #define DRIVER_TIMEOUT 0x06 -#define DRIVER_SENSE 0x08 /* Sense_buffer has been set */ +#define DRIVER_SENSE 0x08 /* Sense_buffer has been set */ /* The following "category" function returns one of the following */ -#define SG_ERR_CAT_CLEAN 0 /* No errors or other information */ -#define SG_ERR_CAT_MEDIA_CHANGED 1 /* interpreted from sense buffer */ -#define SG_ERR_CAT_RESET 2 /* interpreted from sense buffer */ +#define SG_ERR_CAT_CLEAN 0 /* No errors or other information */ +#define SG_ERR_CAT_MEDIA_CHANGED 1 /* interpreted from sense buffer */ +#define SG_ERR_CAT_RESET 2 /* interpreted from sense buffer */ #define SG_ERR_CAT_TIMEOUT 3 -#define SG_ERR_CAT_RECOVERED 4 /* Successful command after recovered err */ -#define SG_ERR_CAT_NOTSUPPORTED 5 /* Illegal / unsupported command */ -#define SG_ERR_CAT_SENSE 98 /* Something else in the sense buffer */ -#define SG_ERR_CAT_OTHER 99 /* Some other error/warning */ - +#define SG_ERR_CAT_RECOVERED 4 /* Successful command after recovered err */ +#define SG_ERR_CAT_NOTSUPPORTED 5 /* Illegal / unsupported command */ +#define SG_ERR_CAT_SENSE 98 /* Something else in the sense buffer */ +#define SG_ERR_CAT_OTHER 99 /* Some other error/warning */ static const struct option options[] = { - { "device", required_argument, NULL, 'd' }, - { "config", required_argument, NULL, 'f' }, - { "page", required_argument, NULL, 'p' }, - { "replace-whitespace", no_argument, NULL, 'u' }, - { "sg-version", required_argument, NULL, 's' }, - { "verbose", no_argument, NULL, 'v' }, - { "version", no_argument, NULL, 'V' }, /* don't advertise -V */ - { "help", no_argument, NULL, 'h' }, - {} + {"device", required_argument, NULL, 'd'}, + {"config", required_argument, NULL, 'f'}, + {"page", required_argument, NULL, 'p'}, + {"replace-whitespace", no_argument, NULL, 'u'}, + {"sg-version", required_argument, NULL, 's'}, + {"verbose", no_argument, NULL, 'v'}, + {"version", no_argument, NULL, 'V'}, /* don't advertise -V */ + {"help", no_argument, NULL, 'h'}, + {} }; static bool all_good = true; @@ -262,366 +262,405 @@ static char model_enc_str[256]; static char revision_str[16]; static char type_str[16]; -static int do_scsi_page80_inquiry(struct scsi_id_device *dev_scsi, int fd, char *serial, char *serial_short, int max_len); - -static int sg_err_category_new(int scsi_status, int msg_status, int host_status, int driver_status, const unsigned char *sense_buffer, int sb_len) { - - scsi_status &= 0x7e; - - /* - * XXX change to return only two values - failed or OK. - */ - - if (!scsi_status && !host_status && !driver_status) { - return SG_ERR_CAT_CLEAN; - } - - if ((scsi_status == SCSI_CHECK_CONDITION) || - (scsi_status == SCSI_COMMAND_TERMINATED) || - ((driver_status & 0xf) == DRIVER_SENSE)) { - - if (sense_buffer && (sb_len > 2)) { - int sense_key; - unsigned char asc; - - if (sense_buffer[0] & 0x2) { - sense_key = sense_buffer[1] & 0xf; - asc = sense_buffer[2]; - } else { - sense_key = sense_buffer[2] & 0xf; - asc = (sb_len > 12) ? sense_buffer[12] : 0; - } - - if (sense_key == RECOVERED_ERROR) { - return SG_ERR_CAT_RECOVERED; - } - else if (sense_key == UNIT_ATTENTION) { - if (0x28 == asc) { - return SG_ERR_CAT_MEDIA_CHANGED; - } - if (0x29 == asc) { - return SG_ERR_CAT_RESET; - } - } else if (sense_key == ILLEGAL_REQUEST) { - return SG_ERR_CAT_NOTSUPPORTED; - } - } - return SG_ERR_CAT_SENSE; - } - if (host_status) { - if ((host_status == DID_NO_CONNECT) || - (host_status == DID_BUS_BUSY) || - (host_status == DID_TIME_OUT)) { - return SG_ERR_CAT_TIMEOUT; - } - } - if (driver_status) { - if (driver_status == DRIVER_TIMEOUT) { - return SG_ERR_CAT_TIMEOUT; - } - } - return SG_ERR_CAT_OTHER; +static int do_scsi_page80_inquiry(struct scsi_id_device *dev_scsi, int fd, + char *serial, char *serial_short, + int max_len); + +static int sg_err_category_new(int scsi_status, int msg_status, int host_status, + int driver_status, + const unsigned char *sense_buffer, int sb_len) +{ + + scsi_status &= 0x7e; + + /* + * XXX change to return only two values - failed or OK. + */ + + if (!scsi_status && !host_status && !driver_status) { + return SG_ERR_CAT_CLEAN; + } + + if ((scsi_status == SCSI_CHECK_CONDITION) || + (scsi_status == SCSI_COMMAND_TERMINATED) || + ((driver_status & 0xf) == DRIVER_SENSE)) { + + if (sense_buffer && (sb_len > 2)) { + int sense_key; + unsigned char asc; + + if (sense_buffer[0] & 0x2) { + sense_key = sense_buffer[1] & 0xf; + asc = sense_buffer[2]; + } else { + sense_key = sense_buffer[2] & 0xf; + asc = (sb_len > 12) ? sense_buffer[12] : 0; + } + + if (sense_key == RECOVERED_ERROR) { + return SG_ERR_CAT_RECOVERED; + } else if (sense_key == UNIT_ATTENTION) { + if (0x28 == asc) { + return SG_ERR_CAT_MEDIA_CHANGED; + } + if (0x29 == asc) { + return SG_ERR_CAT_RESET; + } + } else if (sense_key == ILLEGAL_REQUEST) { + return SG_ERR_CAT_NOTSUPPORTED; + } + } + return SG_ERR_CAT_SENSE; + } + if (host_status) { + if ((host_status == DID_NO_CONNECT) || + (host_status == DID_BUS_BUSY) || + (host_status == DID_TIME_OUT)) { + return SG_ERR_CAT_TIMEOUT; + } + } + if (driver_status) { + if (driver_status == DRIVER_TIMEOUT) { + return SG_ERR_CAT_TIMEOUT; + } + } + return SG_ERR_CAT_OTHER; } -static int sg_err_category3( struct sg_io_hdr *hp) { - return sg_err_category_new(hp->status, hp->msg_status, hp->host_status, hp->driver_status, hp->sbp, hp->sb_len_wr); +static int sg_err_category3(struct sg_io_hdr *hp) +{ + return sg_err_category_new(hp->status, hp->msg_status, hp->host_status, + hp->driver_status, hp->sbp, hp->sb_len_wr); } -static int sg_err_category4( struct sg_io_v4 *hp) { - return sg_err_category_new( hp->device_status, 0, hp->transport_status, hp->driver_status, (unsigned char *)(uintptr_t)hp->response, hp->response_len); +static int sg_err_category4(struct sg_io_v4 *hp) +{ + return sg_err_category_new(hp->device_status, 0, hp->transport_status, + hp->driver_status, + (unsigned char *)(uintptr_t) hp->response, + hp->response_len); } -static int scsi_dump_sense( struct scsi_id_device *dev_scsi, unsigned char *sense_buffer, int sb_len) { +static int scsi_dump_sense(struct scsi_id_device *dev_scsi, + unsigned char *sense_buffer, int sb_len) +{ - int s; - int code; - int sense_class; - int sense_key; - int asc, ascq; + int s; + int code; + int sense_class; + int sense_key; + int asc, ascq; #ifdef DUMP_SENSE - char out_buffer[256]; - int i, j; + char out_buffer[256]; + int i, j; #endif - /* - * Figure out and print the sense key, asc and ascq. - * - * If you want to suppress these for a particular drive model, add - * a black list entry in the scsi_id config file. - * - * XXX We probably need to: lookup the sense/asc/ascq in a retry - * table, and if found return 1 (after dumping the sense, asc, and - * ascq). So, if/when we get something like a power on/reset, - * we'll retry the command. - */ - - if (sb_len < 1) { - log_debug("%s: sense buffer empty", dev_scsi->kernel); - return -1; - } - - sense_class = (sense_buffer[0] >> 4) & 0x07; - code = sense_buffer[0] & 0xf; - - if (sense_class == 7) { - /* - * extended sense data. - */ - s = sense_buffer[7] + 8; - if (sb_len < s) { - log_debug("%s: sense buffer too small %d bytes, %d bytes too short", dev_scsi->kernel, sb_len, s - sb_len); - return -1; - } - if ((code == 0x0) || (code == 0x1)) { - sense_key = sense_buffer[2] & 0xf; - if (s < 14) { - /* - * Possible? - */ - log_debug("%s: sense result too" " small %d bytes", dev_scsi->kernel, s); - return -1; - } - asc = sense_buffer[12]; - ascq = sense_buffer[13]; - } else if ((code == 0x2) || (code == 0x3)) { - sense_key = sense_buffer[1] & 0xf; - asc = sense_buffer[2]; - ascq = sense_buffer[3]; - } else { - log_debug("%s: invalid sense code 0x%x", dev_scsi->kernel, code); - return -1; - } - log_debug("%s: sense key 0x%x ASC 0x%x ASCQ 0x%x", dev_scsi->kernel, sense_key, asc, ascq); - } - else { - if (sb_len < 4) { - log_debug("%s: sense buffer too small %d bytes, %d bytes too short", dev_scsi->kernel, sb_len, 4 - sb_len); - return -1; - } - - if (sense_buffer[0] < 15) { - log_debug("%s: old sense key: 0x%x", dev_scsi->kernel, sense_buffer[0] & 0x0f); - } - - else { - log_debug("%s: sense = %2x %2x", dev_scsi->kernel, sense_buffer[0], sense_buffer[2]); - } - log_debug("%s: non-extended sense class %d code 0x%0x", dev_scsi->kernel, sense_class, code); - - } + /* + * Figure out and print the sense key, asc and ascq. + * + * If you want to suppress these for a particular drive model, add + * a black list entry in the scsi_id config file. + * + * XXX We probably need to: lookup the sense/asc/ascq in a retry + * table, and if found return 1 (after dumping the sense, asc, and + * ascq). So, if/when we get something like a power on/reset, + * we'll retry the command. + */ + + if (sb_len < 1) { + log_debug("%s: sense buffer empty", dev_scsi->kernel); + return -1; + } + + sense_class = (sense_buffer[0] >> 4) & 0x07; + code = sense_buffer[0] & 0xf; + + if (sense_class == 7) { + /* + * extended sense data. + */ + s = sense_buffer[7] + 8; + if (sb_len < s) { + log_debug + ("%s: sense buffer too small %d bytes, %d bytes too short", + dev_scsi->kernel, sb_len, s - sb_len); + return -1; + } + if ((code == 0x0) || (code == 0x1)) { + sense_key = sense_buffer[2] & 0xf; + if (s < 14) { + /* + * Possible? + */ + log_debug("%s: sense result too" + " small %d bytes", dev_scsi->kernel, + s); + return -1; + } + asc = sense_buffer[12]; + ascq = sense_buffer[13]; + } else if ((code == 0x2) || (code == 0x3)) { + sense_key = sense_buffer[1] & 0xf; + asc = sense_buffer[2]; + ascq = sense_buffer[3]; + } else { + log_debug("%s: invalid sense code 0x%x", + dev_scsi->kernel, code); + return -1; + } + log_debug("%s: sense key 0x%x ASC 0x%x ASCQ 0x%x", + dev_scsi->kernel, sense_key, asc, ascq); + } else { + if (sb_len < 4) { + log_debug + ("%s: sense buffer too small %d bytes, %d bytes too short", + dev_scsi->kernel, sb_len, 4 - sb_len); + return -1; + } + + if (sense_buffer[0] < 15) { + log_debug("%s: old sense key: 0x%x", dev_scsi->kernel, + sense_buffer[0] & 0x0f); + } + + else { + log_debug("%s: sense = %2x %2x", dev_scsi->kernel, + sense_buffer[0], sense_buffer[2]); + } + log_debug("%s: non-extended sense class %d code 0x%0x", + dev_scsi->kernel, sense_class, code); + + } #ifdef DUMP_SENSE - for (i = 0, j = 0; (i < s) && (j < 254); i++) { - out_buffer[j++] = hex_str[(sense_buffer[i] & 0xf0) >> 4]; - out_buffer[j++] = hex_str[sense_buffer[i] & 0x0f]; - out_buffer[j++] = ' '; - } - out_buffer[j] = '\0'; - log_debug("%s: sense dump:", dev_scsi->kernel); - log_debug("%s: %s", dev_scsi->kernel, out_buffer); + for (i = 0, j = 0; (i < s) && (j < 254); i++) { + out_buffer[j++] = hex_str[(sense_buffer[i] & 0xf0) >> 4]; + out_buffer[j++] = hex_str[sense_buffer[i] & 0x0f]; + out_buffer[j++] = ' '; + } + out_buffer[j] = '\0'; + log_debug("%s: sense dump:", dev_scsi->kernel); + log_debug("%s: %s", dev_scsi->kernel, out_buffer); #endif - return -1; + return -1; } -static int scsi_dump( struct scsi_id_device *dev_scsi, struct sg_io_hdr *io) { - - if (!io->status && !io->host_status && !io->msg_status && !io->driver_status) { - /* - * Impossible, should not be called. - */ - log_debug("%s: called with no error", __FUNCTION__); - return -1; - } - - log_debug("%s: sg_io failed status 0x%x 0x%x 0x%x 0x%x", dev_scsi->kernel, io->driver_status, io->host_status, io->msg_status, io->status); - if (io->status == SCSI_CHECK_CONDITION) { - return scsi_dump_sense( dev_scsi, io->sbp, io->sb_len_wr); - } - else { - return -1; - } +static int scsi_dump(struct scsi_id_device *dev_scsi, struct sg_io_hdr *io) +{ + + if (!io->status && !io->host_status && !io->msg_status + && !io->driver_status) { + /* + * Impossible, should not be called. + */ + log_debug("%s: called with no error", __FUNCTION__); + return -1; + } + + log_debug("%s: sg_io failed status 0x%x 0x%x 0x%x 0x%x", + dev_scsi->kernel, io->driver_status, io->host_status, + io->msg_status, io->status); + if (io->status == SCSI_CHECK_CONDITION) { + return scsi_dump_sense(dev_scsi, io->sbp, io->sb_len_wr); + } else { + return -1; + } } -static int scsi_dump_v4( struct scsi_id_device *dev_scsi, struct sg_io_v4 *io) { - - if (!io->device_status && !io->transport_status && !io->driver_status) { - /* - * Impossible, should not be called. - */ - log_debug("%s: called with no error", __FUNCTION__); - return -1; - } - - log_debug("%s: sg_io failed status 0x%x 0x%x 0x%x", dev_scsi->kernel, io->driver_status, io->transport_status, io->device_status); - - if (io->device_status == SCSI_CHECK_CONDITION) { - return scsi_dump_sense( dev_scsi, (unsigned char *)(uintptr_t)io->response, io->response_len); - } - else { - return -1; - } +static int scsi_dump_v4(struct scsi_id_device *dev_scsi, struct sg_io_v4 *io) +{ + + if (!io->device_status && !io->transport_status && !io->driver_status) { + /* + * Impossible, should not be called. + */ + log_debug("%s: called with no error", __FUNCTION__); + return -1; + } + + log_debug("%s: sg_io failed status 0x%x 0x%x 0x%x", dev_scsi->kernel, + io->driver_status, io->transport_status, io->device_status); + + if (io->device_status == SCSI_CHECK_CONDITION) { + return scsi_dump_sense(dev_scsi, + (unsigned char *)(uintptr_t) io-> + response, io->response_len); + } else { + return -1; + } } -static int scsi_inquiry(struct scsi_id_device *dev_scsi, int fd, unsigned char evpd, unsigned char page, unsigned char *buf, unsigned int buflen) { - - unsigned char inq_cmd[INQUIRY_CMDLEN] = { INQUIRY_CMD, evpd, page, 0, buflen, 0 }; - unsigned char sense[SENSE_BUFF_LEN]; - void *io_buf; - struct sg_io_v4 io_v4; - struct sg_io_hdr io_hdr; - int retry = 3; /* rather random */ - int retval; - int rc = 0; - - if (buflen > SCSI_INQ_BUFF_LEN) { - log_debug("buflen %d too long", buflen); - return -1; - } - -resend: - if (dev_scsi->use_sg == 4) { - memzero(&io_v4, sizeof(struct sg_io_v4)); - io_v4.guard = 'Q'; - io_v4.protocol = BSG_PROTOCOL_SCSI; - io_v4.subprotocol = BSG_SUB_PROTOCOL_SCSI_CMD; - io_v4.request_len = sizeof(inq_cmd); - io_v4.request = (uintptr_t)inq_cmd; - io_v4.max_response_len = sizeof(sense); - io_v4.response = (uintptr_t)sense; - io_v4.din_xfer_len = buflen; - io_v4.din_xferp = (uintptr_t)buf; - io_buf = (void *)&io_v4; - } - else { - memzero(&io_hdr, sizeof(struct sg_io_hdr)); - io_hdr.interface_id = 'S'; - io_hdr.cmd_len = sizeof(inq_cmd); - io_hdr.mx_sb_len = sizeof(sense); - io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; - io_hdr.dxfer_len = buflen; - io_hdr.dxferp = buf; - io_hdr.cmdp = inq_cmd; - io_hdr.sbp = sense; - io_hdr.timeout = DEF_TIMEOUT; - io_buf = (void *)&io_hdr; - } - - retval = ioctl(fd, SG_IO, io_buf); - if (retval < 0) { - if ((errno == EINVAL || errno == ENOSYS) && dev_scsi->use_sg == 4) { - dev_scsi->use_sg = 3; - goto resend; - } - - rc = -errno; - log_debug( "%s: ioctl failed: errno = %d", dev_scsi->kernel, rc); - goto error; - } - - if (dev_scsi->use_sg == 4) { - retval = sg_err_category4(io_buf); - } - else { - retval = sg_err_category3(io_buf); - } - - switch (retval) { - case SG_ERR_CAT_NOTSUPPORTED: - buf[1] = 0; - /* Fallthrough */ - case SG_ERR_CAT_CLEAN: - case SG_ERR_CAT_RECOVERED: - retval = 0; - break; - - default: - if (dev_scsi->use_sg == 4) { - retval = scsi_dump_v4(dev_scsi, io_buf); - } - else { - retval = scsi_dump(dev_scsi, io_buf); - } - } - - if (!retval) { - retval = buflen; - } else if (retval > 0) { - if (--retry > 0) { - goto resend; - } - retval = -1; - } - -error: - if (retval < 0) { - log_debug("%s: Unable to get INQUIRY vpd %d page 0x%x.", dev_scsi->kernel, evpd, page); - } - - return retval; +static int scsi_inquiry(struct scsi_id_device *dev_scsi, int fd, + unsigned char evpd, unsigned char page, + unsigned char *buf, unsigned int buflen) +{ + + unsigned char inq_cmd[INQUIRY_CMDLEN] = + { INQUIRY_CMD, evpd, page, 0, buflen, 0 }; + unsigned char sense[SENSE_BUFF_LEN]; + void *io_buf; + struct sg_io_v4 io_v4; + struct sg_io_hdr io_hdr; + int retry = 3; /* rather random */ + int retval; + int rc = 0; + + if (buflen > SCSI_INQ_BUFF_LEN) { + log_debug("buflen %d too long", buflen); + return -1; + } + + resend: + if (dev_scsi->use_sg == 4) { + memzero(&io_v4, sizeof(struct sg_io_v4)); + io_v4.guard = 'Q'; + io_v4.protocol = BSG_PROTOCOL_SCSI; + io_v4.subprotocol = BSG_SUB_PROTOCOL_SCSI_CMD; + io_v4.request_len = sizeof(inq_cmd); + io_v4.request = (uintptr_t) inq_cmd; + io_v4.max_response_len = sizeof(sense); + io_v4.response = (uintptr_t) sense; + io_v4.din_xfer_len = buflen; + io_v4.din_xferp = (uintptr_t) buf; + io_buf = (void *)&io_v4; + } else { + memzero(&io_hdr, sizeof(struct sg_io_hdr)); + io_hdr.interface_id = 'S'; + io_hdr.cmd_len = sizeof(inq_cmd); + io_hdr.mx_sb_len = sizeof(sense); + io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; + io_hdr.dxfer_len = buflen; + io_hdr.dxferp = buf; + io_hdr.cmdp = inq_cmd; + io_hdr.sbp = sense; + io_hdr.timeout = DEF_TIMEOUT; + io_buf = (void *)&io_hdr; + } + + retval = ioctl(fd, SG_IO, io_buf); + if (retval < 0) { + if ((errno == EINVAL || errno == ENOSYS) + && dev_scsi->use_sg == 4) { + dev_scsi->use_sg = 3; + goto resend; + } + + rc = -errno; + log_debug("%s: ioctl failed: errno = %d", dev_scsi->kernel, rc); + goto error; + } + + if (dev_scsi->use_sg == 4) { + retval = sg_err_category4(io_buf); + } else { + retval = sg_err_category3(io_buf); + } + + switch (retval) { + case SG_ERR_CAT_NOTSUPPORTED: + buf[1] = 0; + /* Fallthrough */ + case SG_ERR_CAT_CLEAN: + case SG_ERR_CAT_RECOVERED: + retval = 0; + break; + + default: + if (dev_scsi->use_sg == 4) { + retval = scsi_dump_v4(dev_scsi, io_buf); + } else { + retval = scsi_dump(dev_scsi, io_buf); + } + } + + if (!retval) { + retval = buflen; + } else if (retval > 0) { + if (--retry > 0) { + goto resend; + } + retval = -1; + } + + error: + if (retval < 0) { + log_debug("%s: Unable to get INQUIRY vpd %d page 0x%x.", + dev_scsi->kernel, evpd, page); + } + + return retval; } /* Get list of supported EVPD pages */ -static int do_scsi_page0_inquiry( struct scsi_id_device *dev_scsi, int fd, unsigned char *buffer, unsigned int len) { - - int retval; - - memzero(buffer, len); - retval = scsi_inquiry( dev_scsi, fd, 1, 0x0, buffer, len); - if (retval < 0) { - return 1; - } - - if (buffer[1] != 0) { - log_debug("%s: page 0 not available.", dev_scsi->kernel); - return 1; - } - if (buffer[3] > len) { - log_debug("%s: page 0 buffer too long %d", dev_scsi->kernel, buffer[3]); - return 1; - } - - /* - * Following check is based on code once included in the 2.5.x - * kernel. - * - * Some ill behaved devices return the standard inquiry here - * rather than the evpd data, snoop the data to verify. - */ - if (buffer[3] > MODEL_LENGTH) { - /* - * If the vendor id appears in the page assume the page is - * invalid. - */ - if (strneq((char *)&buffer[VENDOR_LENGTH], dev_scsi->vendor, VENDOR_LENGTH)) { - log_debug("%s: invalid page0 data", dev_scsi->kernel); - return 1; - } - } - return 0; +static int do_scsi_page0_inquiry(struct scsi_id_device *dev_scsi, int fd, + unsigned char *buffer, unsigned int len) +{ + + int retval; + + memzero(buffer, len); + retval = scsi_inquiry(dev_scsi, fd, 1, 0x0, buffer, len); + if (retval < 0) { + return 1; + } + + if (buffer[1] != 0) { + log_debug("%s: page 0 not available.", dev_scsi->kernel); + return 1; + } + if (buffer[3] > len) { + log_debug("%s: page 0 buffer too long %d", dev_scsi->kernel, + buffer[3]); + return 1; + } + + /* + * Following check is based on code once included in the 2.5.x + * kernel. + * + * Some ill behaved devices return the standard inquiry here + * rather than the evpd data, snoop the data to verify. + */ + if (buffer[3] > MODEL_LENGTH) { + /* + * If the vendor id appears in the page assume the page is + * invalid. + */ + if (strneq + ((char *)&buffer[VENDOR_LENGTH], dev_scsi->vendor, + VENDOR_LENGTH)) { + log_debug("%s: invalid page0 data", dev_scsi->kernel); + return 1; + } + } + return 0; } /* * The caller checks that serial is long enough to include the vendor + * model. */ -static int prepend_vendor_model(struct scsi_id_device *dev_scsi, char *serial) { - - int ind; - - strncpy(serial, dev_scsi->vendor, VENDOR_LENGTH); - strncat(serial, dev_scsi->model, MODEL_LENGTH); - ind = strlen(serial); - - /* - * This is not a complete check, since we are using strncat/cpy - * above, ind will never be too large. - */ - if (ind != (VENDOR_LENGTH + MODEL_LENGTH)) { - log_debug("%s: expected length %d, got length %d", dev_scsi->kernel, (VENDOR_LENGTH + MODEL_LENGTH), ind); - return -1; - } - return ind; +static int prepend_vendor_model(struct scsi_id_device *dev_scsi, char *serial) +{ + + int ind; + + strncpy(serial, dev_scsi->vendor, VENDOR_LENGTH); + strncat(serial, dev_scsi->model, MODEL_LENGTH); + ind = strlen(serial); + + /* + * This is not a complete check, since we are using strncat/cpy + * above, ind will never be too large. + */ + if (ind != (VENDOR_LENGTH + MODEL_LENGTH)) { + log_debug("%s: expected length %d, got length %d", + dev_scsi->kernel, (VENDOR_LENGTH + MODEL_LENGTH), + ind); + return -1; + } + return ind; } /* @@ -629,226 +668,236 @@ static int prepend_vendor_model(struct scsi_id_device *dev_scsi, char *serial) { * serial number. */ static int check_fill_0x83_id(struct scsi_id_device *dev_scsi, - unsigned char *page_83, - const struct scsi_id_search_values - *id_search, char *serial, char *serial_short, - int max_len, char *wwn, - char *wwn_vendor_extension, char *tgpt_group) { - - int i, j, s, len; - - /* - * ASSOCIATION must be with the device (value 0) - * or with the target port for SCSI_ID_TGTPORT - */ - if ((page_83[1] & 0x30) == 0x10) { - if (id_search->id_type != SCSI_ID_TGTGROUP) { - return 1; - } - } - else if ((page_83[1] & 0x30) != 0) { - return 1; - } - - if ((page_83[1] & 0x0f) != id_search->id_type) { - return 1; - } - - /* - * Possibly check NAA sub-type. - */ - if ((id_search->naa_type != SCSI_ID_NAA_DONT_CARE) && (id_search->naa_type != (page_83[4] & 0xf0) >> 4)) { - return 1; - } - - /* - * Check for matching code set - ASCII or BINARY. - */ - if ((page_83[0] & 0x0f) != id_search->code_set) { - return 1; - } - - /* - * page_83[3]: identifier length - */ - len = page_83[3]; - if ((page_83[0] & 0x0f) != SCSI_ID_ASCII) { - /* - * If not ASCII, use two bytes for each binary value. - */ - len *= 2; - } - - /* - * Add one byte for the NUL termination, and one for the id_type. - */ - len += 2; - if (id_search->id_type == SCSI_ID_VENDOR_SPECIFIC) { - len += VENDOR_LENGTH + MODEL_LENGTH; - } - - if (max_len < len) { - log_debug("%s: length %d too short - need %d", dev_scsi->kernel, max_len, len); - return 1; - } - - if (id_search->id_type == SCSI_ID_TGTGROUP && tgpt_group != NULL) { - unsigned int group; - - group = ((unsigned int)page_83[6] << 8) | page_83[7]; - sprintf(tgpt_group,"%x", group); - return 1; - } - - serial[0] = hex_str[id_search->id_type]; - - /* - * For SCSI_ID_VENDOR_SPECIFIC prepend the vendor and model before - * the id since it is not unique across all vendors and models, - * this differs from SCSI_ID_T10_VENDOR, where the vendor is - * included in the identifier. - */ - if (id_search->id_type == SCSI_ID_VENDOR_SPECIFIC) { - if (prepend_vendor_model( dev_scsi, &serial[1]) < 0) { - return 1; - } - } - - i = 4; /* offset to the start of the identifier */ - s = j = strlen(serial); - if ((page_83[0] & 0x0f) == SCSI_ID_ASCII) { - /* - * ASCII descriptor. - */ - while (i < (4 + page_83[3])) { - serial[j++] = page_83[i++]; - } - } else { - /* - * Binary descriptor, convert to ASCII, using two bytes of - * ASCII for each byte in the page_83. - */ - while (i < (4 + page_83[3])) { - serial[j++] = hex_str[(page_83[i] & 0xf0) >> 4]; - serial[j++] = hex_str[page_83[i] & 0x0f]; - i++; - } - } - - strcpy(serial_short, &serial[s]); - - if (id_search->id_type == SCSI_ID_NAA && wwn != NULL) { - strncpy(wwn, &serial[s], 16); - if (wwn_vendor_extension != NULL) { - strncpy(wwn_vendor_extension, &serial[s + 16], 16); - } - } - - return 0; + unsigned char *page_83, + const struct scsi_id_search_values + *id_search, char *serial, char *serial_short, + int max_len, char *wwn, + char *wwn_vendor_extension, char *tgpt_group) +{ + + int i, j, s, len; + + /* + * ASSOCIATION must be with the device (value 0) + * or with the target port for SCSI_ID_TGTPORT + */ + if ((page_83[1] & 0x30) == 0x10) { + if (id_search->id_type != SCSI_ID_TGTGROUP) { + return 1; + } + } else if ((page_83[1] & 0x30) != 0) { + return 1; + } + + if ((page_83[1] & 0x0f) != id_search->id_type) { + return 1; + } + + /* + * Possibly check NAA sub-type. + */ + if ((id_search->naa_type != SCSI_ID_NAA_DONT_CARE) + && (id_search->naa_type != (page_83[4] & 0xf0) >> 4)) { + return 1; + } + + /* + * Check for matching code set - ASCII or BINARY. + */ + if ((page_83[0] & 0x0f) != id_search->code_set) { + return 1; + } + + /* + * page_83[3]: identifier length + */ + len = page_83[3]; + if ((page_83[0] & 0x0f) != SCSI_ID_ASCII) { + /* + * If not ASCII, use two bytes for each binary value. + */ + len *= 2; + } + + /* + * Add one byte for the NUL termination, and one for the id_type. + */ + len += 2; + if (id_search->id_type == SCSI_ID_VENDOR_SPECIFIC) { + len += VENDOR_LENGTH + MODEL_LENGTH; + } + + if (max_len < len) { + log_debug("%s: length %d too short - need %d", dev_scsi->kernel, + max_len, len); + return 1; + } + + if (id_search->id_type == SCSI_ID_TGTGROUP && tgpt_group != NULL) { + unsigned int group; + + group = ((unsigned int)page_83[6] << 8) | page_83[7]; + sprintf(tgpt_group, "%x", group); + return 1; + } + + serial[0] = hex_str[id_search->id_type]; + + /* + * For SCSI_ID_VENDOR_SPECIFIC prepend the vendor and model before + * the id since it is not unique across all vendors and models, + * this differs from SCSI_ID_T10_VENDOR, where the vendor is + * included in the identifier. + */ + if (id_search->id_type == SCSI_ID_VENDOR_SPECIFIC) { + if (prepend_vendor_model(dev_scsi, &serial[1]) < 0) { + return 1; + } + } + + i = 4; /* offset to the start of the identifier */ + s = j = strlen(serial); + if ((page_83[0] & 0x0f) == SCSI_ID_ASCII) { + /* + * ASCII descriptor. + */ + while (i < (4 + page_83[3])) { + serial[j++] = page_83[i++]; + } + } else { + /* + * Binary descriptor, convert to ASCII, using two bytes of + * ASCII for each byte in the page_83. + */ + while (i < (4 + page_83[3])) { + serial[j++] = hex_str[(page_83[i] & 0xf0) >> 4]; + serial[j++] = hex_str[page_83[i] & 0x0f]; + i++; + } + } + + strcpy(serial_short, &serial[s]); + + if (id_search->id_type == SCSI_ID_NAA && wwn != NULL) { + strncpy(wwn, &serial[s], 16); + if (wwn_vendor_extension != NULL) { + strncpy(wwn_vendor_extension, &serial[s + 16], 16); + } + } + + return 0; } /* Extract the raw binary from VPD 0x83 pre-SPC devices */ static int check_fill_0x83_prespc3(struct scsi_id_device *dev_scsi, - unsigned char *page_83, - const struct scsi_id_search_values - *id_search, char *serial, char *serial_short, int max_len) { - int i, j; - - serial[0] = hex_str[id_search->id_type]; - /* serial has been memset to zero before */ - j = strlen(serial); /* j = 1; */ - - for (i = 0; (i < page_83[3]) && (j < max_len-3); ++i) { - serial[j++] = hex_str[(page_83[4+i] & 0xf0) >> 4]; - serial[j++] = hex_str[ page_83[4+i] & 0x0f]; - } - serial[max_len-1] = 0; - strncpy(serial_short, serial, max_len-1); - return 0; + unsigned char *page_83, + const struct scsi_id_search_values + *id_search, char *serial, char *serial_short, + int max_len) +{ + int i, j; + + serial[0] = hex_str[id_search->id_type]; + /* serial has been memset to zero before */ + j = strlen(serial); /* j = 1; */ + + for (i = 0; (i < page_83[3]) && (j < max_len - 3); ++i) { + serial[j++] = hex_str[(page_83[4 + i] & 0xf0) >> 4]; + serial[j++] = hex_str[page_83[4 + i] & 0x0f]; + } + serial[max_len - 1] = 0; + strncpy(serial_short, serial, max_len - 1); + return 0; } - /* Get device identification VPD page */ static int do_scsi_page83_inquiry(struct scsi_id_device *dev_scsi, int fd, - char *serial, char *serial_short, int len, - char *unit_serial_number, char *wwn, - char *wwn_vendor_extension, char *tgpt_group) { - int retval; - unsigned int id_ind, j; - unsigned char page_83[SCSI_INQ_BUFF_LEN]; - - /* also pick up the page 80 serial number */ - do_scsi_page80_inquiry( dev_scsi, fd, NULL, unit_serial_number, MAX_SERIAL_LEN); - - memzero(page_83, SCSI_INQ_BUFF_LEN); - retval = scsi_inquiry( dev_scsi, fd, 1, PAGE_83, page_83, SCSI_INQ_BUFF_LEN); - if (retval < 0) { - return 1; - } - - if (page_83[1] != PAGE_83) { - log_debug("%s: Invalid page 0x83", dev_scsi->kernel); - return 1; - } - - /* - * XXX Some devices (IBM 3542) return all spaces for an identifier if - * the LUN is not actually configured. This leads to identifiers of - * the form: "1 ". - */ - - /* - * Model 4, 5, and (some) model 6 EMC Symmetrix devices return - * a page 83 reply according to SCSI-2 format instead of SPC-2/3. - * - * The SCSI-2 page 83 format returns an IEEE WWN in binary - * encoded hexi-decimal in the 16 bytes following the initial - * 4-byte page 83 reply header. - * - * Both the SPC-2 and SPC-3 formats return an IEEE WWN as part - * of an Identification descriptor. The 3rd byte of the first - * Identification descriptor is a reserved (BSZ) byte field. - * - * Reference the 7th byte of the page 83 reply to determine - * whether the reply is compliant with SCSI-2 or SPC-2/3 - * specifications. A zero value in the 7th byte indicates - * an SPC-2/3 conformant reply, (i.e., the reserved field of the - * first Identification descriptor). This byte will be non-zero - * for a SCSI-2 conformant page 83 reply from these EMC - * Symmetrix models since the 7th byte of the reply corresponds - * to the 4th and 5th nibbles of the 6-byte OUI for EMC, that is, - * 0x006048. - */ - - if (page_83[6] != 0) { - return check_fill_0x83_prespc3(dev_scsi, page_83, id_search_list, serial, serial_short, len); - } - - /* - * Search for a match in the prioritized id_search_list - since WWN ids - * come first we can pick up the WWN in check_fill_0x83_id(). - */ - for (id_ind = 0; id_ind < sizeof(id_search_list)/sizeof(id_search_list[0]); id_ind++) { - /* - * Examine each descriptor returned. There is normally only - * one or a small number of descriptors. - */ - for (j = 4; j <= (unsigned int)page_83[3] + 3; j += page_83[j + 3] + 4) { - - retval = check_fill_0x83_id( dev_scsi, &page_83[j], - &id_search_list[id_ind], - serial, serial_short, len, - wwn, wwn_vendor_extension, - tgpt_group); - if (!retval) { - return retval; - } - else if (retval < 0) { - return retval; - } - } - } - return 1; + char *serial, char *serial_short, int len, + char *unit_serial_number, char *wwn, + char *wwn_vendor_extension, char *tgpt_group) +{ + int retval; + unsigned int id_ind, j; + unsigned char page_83[SCSI_INQ_BUFF_LEN]; + + /* also pick up the page 80 serial number */ + do_scsi_page80_inquiry(dev_scsi, fd, NULL, unit_serial_number, + MAX_SERIAL_LEN); + + memzero(page_83, SCSI_INQ_BUFF_LEN); + retval = + scsi_inquiry(dev_scsi, fd, 1, PAGE_83, page_83, SCSI_INQ_BUFF_LEN); + if (retval < 0) { + return 1; + } + + if (page_83[1] != PAGE_83) { + log_debug("%s: Invalid page 0x83", dev_scsi->kernel); + return 1; + } + + /* + * XXX Some devices (IBM 3542) return all spaces for an identifier if + * the LUN is not actually configured. This leads to identifiers of + * the form: "1 ". + */ + + /* + * Model 4, 5, and (some) model 6 EMC Symmetrix devices return + * a page 83 reply according to SCSI-2 format instead of SPC-2/3. + * + * The SCSI-2 page 83 format returns an IEEE WWN in binary + * encoded hexi-decimal in the 16 bytes following the initial + * 4-byte page 83 reply header. + * + * Both the SPC-2 and SPC-3 formats return an IEEE WWN as part + * of an Identification descriptor. The 3rd byte of the first + * Identification descriptor is a reserved (BSZ) byte field. + * + * Reference the 7th byte of the page 83 reply to determine + * whether the reply is compliant with SCSI-2 or SPC-2/3 + * specifications. A zero value in the 7th byte indicates + * an SPC-2/3 conformant reply, (i.e., the reserved field of the + * first Identification descriptor). This byte will be non-zero + * for a SCSI-2 conformant page 83 reply from these EMC + * Symmetrix models since the 7th byte of the reply corresponds + * to the 4th and 5th nibbles of the 6-byte OUI for EMC, that is, + * 0x006048. + */ + + if (page_83[6] != 0) { + return check_fill_0x83_prespc3(dev_scsi, page_83, + id_search_list, serial, + serial_short, len); + } + + /* + * Search for a match in the prioritized id_search_list - since WWN ids + * come first we can pick up the WWN in check_fill_0x83_id(). + */ + for (id_ind = 0; + id_ind < sizeof(id_search_list) / sizeof(id_search_list[0]); + id_ind++) { + /* + * Examine each descriptor returned. There is normally only + * one or a small number of descriptors. + */ + for (j = 4; j <= (unsigned int)page_83[3] + 3; + j += page_83[j + 3] + 4) { + + retval = check_fill_0x83_id(dev_scsi, &page_83[j], + &id_search_list[id_ind], + serial, serial_short, len, + wwn, wwn_vendor_extension, + tgpt_group); + if (!retval) { + return retval; + } else if (retval < 0) { + return retval; + } + } + } + return 1; } /* @@ -858,316 +907,344 @@ static int do_scsi_page83_inquiry(struct scsi_id_device *dev_scsi, int fd, * Return the hard coded error code value 2 if the page 83 reply is not * conformant to the SCSI-2 format. */ -static int do_scsi_page83_prespc3_inquiry(struct scsi_id_device *dev_scsi, int fd, char *serial, char *serial_short, int len) { - int retval; - int i, j; - unsigned char page_83[SCSI_INQ_BUFF_LEN]; - - memzero(page_83, SCSI_INQ_BUFF_LEN); - retval = scsi_inquiry(dev_scsi, fd, 1, PAGE_83, page_83, SCSI_INQ_BUFF_LEN); - if (retval < 0) { - return 1; - } - - if (page_83[1] != PAGE_83) { - log_debug("%s: Invalid page 0x83", dev_scsi->kernel); - return 1; - } - /* - * Model 4, 5, and (some) model 6 EMC Symmetrix devices return - * a page 83 reply according to SCSI-2 format instead of SPC-2/3. - * - * The SCSI-2 page 83 format returns an IEEE WWN in binary - * encoded hexi-decimal in the 16 bytes following the initial - * 4-byte page 83 reply header. - * - * Both the SPC-2 and SPC-3 formats return an IEEE WWN as part - * of an Identification descriptor. The 3rd byte of the first - * Identification descriptor is a reserved (BSZ) byte field. - * - * Reference the 7th byte of the page 83 reply to determine - * whether the reply is compliant with SCSI-2 or SPC-2/3 - * specifications. A zero value in the 7th byte indicates - * an SPC-2/3 conformant reply, (i.e., the reserved field of the - * first Identification descriptor). This byte will be non-zero - * for a SCSI-2 conformant page 83 reply from these EMC - * Symmetrix models since the 7th byte of the reply corresponds - * to the 4th and 5th nibbles of the 6-byte OUI for EMC, that is, - * 0x006048. - */ - if (page_83[6] == 0) { - return 2; - } - - serial[0] = hex_str[id_search_list[0].id_type]; - /* - * The first four bytes contain data, not a descriptor. - */ - i = 4; - j = strlen(serial); - /* - * Binary descriptor, convert to ASCII, - * using two bytes of ASCII for each byte - * in the page_83. - */ - while (i < (page_83[3]+4)) { - serial[j++] = hex_str[(page_83[i] & 0xf0) >> 4]; - serial[j++] = hex_str[page_83[i] & 0x0f]; - i++; - } - return 0; +static int do_scsi_page83_prespc3_inquiry(struct scsi_id_device *dev_scsi, + int fd, char *serial, + char *serial_short, int len) +{ + int retval; + int i, j; + unsigned char page_83[SCSI_INQ_BUFF_LEN]; + + memzero(page_83, SCSI_INQ_BUFF_LEN); + retval = + scsi_inquiry(dev_scsi, fd, 1, PAGE_83, page_83, SCSI_INQ_BUFF_LEN); + if (retval < 0) { + return 1; + } + + if (page_83[1] != PAGE_83) { + log_debug("%s: Invalid page 0x83", dev_scsi->kernel); + return 1; + } + /* + * Model 4, 5, and (some) model 6 EMC Symmetrix devices return + * a page 83 reply according to SCSI-2 format instead of SPC-2/3. + * + * The SCSI-2 page 83 format returns an IEEE WWN in binary + * encoded hexi-decimal in the 16 bytes following the initial + * 4-byte page 83 reply header. + * + * Both the SPC-2 and SPC-3 formats return an IEEE WWN as part + * of an Identification descriptor. The 3rd byte of the first + * Identification descriptor is a reserved (BSZ) byte field. + * + * Reference the 7th byte of the page 83 reply to determine + * whether the reply is compliant with SCSI-2 or SPC-2/3 + * specifications. A zero value in the 7th byte indicates + * an SPC-2/3 conformant reply, (i.e., the reserved field of the + * first Identification descriptor). This byte will be non-zero + * for a SCSI-2 conformant page 83 reply from these EMC + * Symmetrix models since the 7th byte of the reply corresponds + * to the 4th and 5th nibbles of the 6-byte OUI for EMC, that is, + * 0x006048. + */ + if (page_83[6] == 0) { + return 2; + } + + serial[0] = hex_str[id_search_list[0].id_type]; + /* + * The first four bytes contain data, not a descriptor. + */ + i = 4; + j = strlen(serial); + /* + * Binary descriptor, convert to ASCII, + * using two bytes of ASCII for each byte + * in the page_83. + */ + while (i < (page_83[3] + 4)) { + serial[j++] = hex_str[(page_83[i] & 0xf0) >> 4]; + serial[j++] = hex_str[page_83[i] & 0x0f]; + i++; + } + return 0; } /* Get unit serial number VPD page */ static int do_scsi_page80_inquiry(struct scsi_id_device *dev_scsi, int fd, - char *serial, char *serial_short, int max_len) { - - int retval; - int ser_ind; - int i; - int len; - unsigned char buf[SCSI_INQ_BUFF_LEN]; - - memzero(buf, SCSI_INQ_BUFF_LEN); - retval = scsi_inquiry( dev_scsi, fd, 1, PAGE_80, buf, SCSI_INQ_BUFF_LEN); - if (retval < 0) { - return retval; - } - - if (buf[1] != PAGE_80) { - log_debug("%s: Invalid page 0x80", dev_scsi->kernel); - return 1; - } - - len = 1 + VENDOR_LENGTH + MODEL_LENGTH + buf[3]; - if (max_len < len) { - log_debug("%s: length %d too short - need %d", dev_scsi->kernel, max_len, len); - return 1; - } - /* - * Prepend 'S' to avoid unlikely collision with page 0x83 vendor - * specific type where we prepend '0' + vendor + model. - */ - len = buf[3]; - if (serial != NULL) { - serial[0] = 'S'; - ser_ind = prepend_vendor_model( dev_scsi, &serial[1]); - if (ser_ind < 0) { - return 1; - } - ser_ind++; /* for the leading 'S' */ - for (i = 4; i < len + 4; i++, ser_ind++) { - serial[ser_ind] = buf[i]; - } - } - if (serial_short != NULL) { - memcpy(serial_short, &buf[4], len); - serial_short[len] = '\0'; - } - return 0; -} + char *serial, char *serial_short, int max_len) +{ -int scsi_std_inquiry(struct scsi_id_device *dev_scsi, const char *devname) { - - int fd; - unsigned char buf[SCSI_INQ_BUFF_LEN]; - struct stat statbuf; - int err = 0; - - fd = open(devname, O_RDONLY | O_NONBLOCK | O_CLOEXEC); - if (fd < 0) { - err = -errno; - log_debug( "scsi_id: cannot open %s: errno = %d", devname, err); - return 1; - } - - if (fstat(fd, &statbuf) < 0) { - - err = -errno; - log_debug( "scsi_id: cannot stat %s: errno = %d", devname, err); - err = 2; - goto out; - } - - sprintf(dev_scsi->kernel,"%d:%d", major(statbuf.st_rdev), minor(statbuf.st_rdev)); - - memzero(buf, SCSI_INQ_BUFF_LEN); - err = scsi_inquiry( dev_scsi, fd, 0, 0, buf, SCSI_INQ_BUFF_LEN); - if (err < 0) { - goto out; - } - - err = 0; - memcpy(dev_scsi->vendor, buf + 8, 8); - dev_scsi->vendor[8] = '\0'; - memcpy(dev_scsi->model, buf + 16, 16); - dev_scsi->model[16] = '\0'; - memcpy(dev_scsi->revision, buf + 32, 4); - dev_scsi->revision[4] = '\0'; - sprintf(dev_scsi->type,"%x", buf[0] & 0x1f); - -out: - close(fd); - return err; + int retval; + int ser_ind; + int i; + int len; + unsigned char buf[SCSI_INQ_BUFF_LEN]; + + memzero(buf, SCSI_INQ_BUFF_LEN); + retval = scsi_inquiry(dev_scsi, fd, 1, PAGE_80, buf, SCSI_INQ_BUFF_LEN); + if (retval < 0) { + return retval; + } + + if (buf[1] != PAGE_80) { + log_debug("%s: Invalid page 0x80", dev_scsi->kernel); + return 1; + } + + len = 1 + VENDOR_LENGTH + MODEL_LENGTH + buf[3]; + if (max_len < len) { + log_debug("%s: length %d too short - need %d", dev_scsi->kernel, + max_len, len); + return 1; + } + /* + * Prepend 'S' to avoid unlikely collision with page 0x83 vendor + * specific type where we prepend '0' + vendor + model. + */ + len = buf[3]; + if (serial != NULL) { + serial[0] = 'S'; + ser_ind = prepend_vendor_model(dev_scsi, &serial[1]); + if (ser_ind < 0) { + return 1; + } + ser_ind++; /* for the leading 'S' */ + for (i = 4; i < len + 4; i++, ser_ind++) { + serial[ser_ind] = buf[i]; + } + } + if (serial_short != NULL) { + memcpy(serial_short, &buf[4], len); + serial_short[len] = '\0'; + } + return 0; } -int scsi_get_serial(struct scsi_id_device *dev_scsi, const char *devname, int page_code, int len) { - - unsigned char page0[SCSI_INQ_BUFF_LEN]; - int fd = -1; - int cnt; - int ind; - int retval; - - memzero(dev_scsi->serial, len); - initialize_srand(); - - for (cnt = 20; cnt > 0; cnt--) { - struct timespec duration; - - fd = open(devname, O_RDONLY | O_NONBLOCK | O_CLOEXEC); - if (fd >= 0 || errno != EBUSY) { - break; - } - - duration.tv_sec = 0; - duration.tv_nsec = (200 * 1000 * 1000) + (rand() % 100 * 1000 * 1000); - nanosleep(&duration, NULL); - } - if (fd < 0) { - return 1; - } - - if (page_code == PAGE_80) { - if (do_scsi_page80_inquiry( dev_scsi, fd, dev_scsi->serial, dev_scsi->serial_short, len)) { - retval = 1; - goto completed; - } else { - retval = 0; - goto completed; - } - } - else if (page_code == PAGE_83) { - if (do_scsi_page83_inquiry( dev_scsi, fd, dev_scsi->serial, dev_scsi->serial_short, len, dev_scsi->unit_serial_number, dev_scsi->wwn, dev_scsi->wwn_vendor_extension, dev_scsi->tgpt_group)) { - retval = 1; - goto completed; - } else { - retval = 0; - goto completed; - } - } - else if (page_code == PAGE_83_PRE_SPC3) { - retval = do_scsi_page83_prespc3_inquiry( dev_scsi, fd, dev_scsi->serial, dev_scsi->serial_short, len); - if (retval) { - /* - * Fallback to servicing a SPC-2/3 compliant page 83 - * inquiry if the page 83 reply format does not - * conform to pre-SPC3 expectations. - */ - if (retval == 2) { - if (do_scsi_page83_inquiry( dev_scsi, fd, dev_scsi->serial, dev_scsi->serial_short, len, dev_scsi->unit_serial_number, dev_scsi->wwn, dev_scsi->wwn_vendor_extension, dev_scsi->tgpt_group)) { - retval = 1; - goto completed; - } else { - retval = 0; - goto completed; - } - } - else { - retval = 1; - goto completed; - } - } else { - retval = 0; - goto completed; - } - } else if (page_code != 0x00) { - log_debug("%s: unsupported page code 0x%d", dev_scsi->kernel, page_code); - retval = 1; - goto completed; - } - - /* - * Get page 0, the page of the pages. By default, try from best to - * worst of supported pages: 0x83 then 0x80. - */ - if (do_scsi_page0_inquiry( dev_scsi, fd, page0, SCSI_INQ_BUFF_LEN)) { - /* - * Don't try anything else. Black list if a specific page - * should be used for this vendor+model, or maybe have an - * optional fall-back to page 0x80 or page 0x83. - */ - retval = 1; - goto completed; - } - - for (ind = 4; ind <= page0[3] + 3; ind++) { - if (page0[ind] == PAGE_83) { - if (!do_scsi_page83_inquiry( dev_scsi, fd, dev_scsi->serial, dev_scsi->serial_short, len, dev_scsi->unit_serial_number, dev_scsi->wwn, dev_scsi->wwn_vendor_extension, dev_scsi->tgpt_group)) { - /* - * Success - */ - retval = 0; - goto completed; - } - } - } - - for (ind = 4; ind <= page0[3] + 3; ind++) { - if (page0[ind] == PAGE_80) { - if (!do_scsi_page80_inquiry( dev_scsi, fd, dev_scsi->serial, dev_scsi->serial_short, len)) { - /* - * Success - */ - retval = 0; - goto completed; - } - } - } - retval = 1; - -completed: - close(fd); - return retval; +int scsi_std_inquiry(struct scsi_id_device *dev_scsi, const char *devname) +{ + + int fd; + unsigned char buf[SCSI_INQ_BUFF_LEN]; + struct stat statbuf; + int err = 0; + + fd = open(devname, O_RDONLY | O_NONBLOCK | O_CLOEXEC); + if (fd < 0) { + err = -errno; + log_debug("scsi_id: cannot open %s: errno = %d", devname, err); + return 1; + } + + if (fstat(fd, &statbuf) < 0) { + + err = -errno; + log_debug("scsi_id: cannot stat %s: errno = %d", devname, err); + err = 2; + goto out; + } + + sprintf(dev_scsi->kernel, "%d:%d", major(statbuf.st_rdev), + minor(statbuf.st_rdev)); + + memzero(buf, SCSI_INQ_BUFF_LEN); + err = scsi_inquiry(dev_scsi, fd, 0, 0, buf, SCSI_INQ_BUFF_LEN); + if (err < 0) { + goto out; + } + + err = 0; + memcpy(dev_scsi->vendor, buf + 8, 8); + dev_scsi->vendor[8] = '\0'; + memcpy(dev_scsi->model, buf + 16, 16); + dev_scsi->model[16] = '\0'; + memcpy(dev_scsi->revision, buf + 32, 4); + dev_scsi->revision[4] = '\0'; + sprintf(dev_scsi->type, "%x", buf[0] & 0x1f); + + out: + close(fd); + return err; } +int scsi_get_serial(struct scsi_id_device *dev_scsi, const char *devname, + int page_code, int len) +{ + unsigned char page0[SCSI_INQ_BUFF_LEN]; + int fd = -1; + int cnt; + int ind; + int retval; + + memzero(dev_scsi->serial, len); + initialize_srand(); + + for (cnt = 20; cnt > 0; cnt--) { + struct timespec duration; + + fd = open(devname, O_RDONLY | O_NONBLOCK | O_CLOEXEC); + if (fd >= 0 || errno != EBUSY) { + break; + } + + duration.tv_sec = 0; + duration.tv_nsec = + (200 * 1000 * 1000) + (rand() % 100 * 1000 * 1000); + nanosleep(&duration, NULL); + } + if (fd < 0) { + return 1; + } + + if (page_code == PAGE_80) { + if (do_scsi_page80_inquiry + (dev_scsi, fd, dev_scsi->serial, dev_scsi->serial_short, + len)) { + retval = 1; + goto completed; + } else { + retval = 0; + goto completed; + } + } else if (page_code == PAGE_83) { + if (do_scsi_page83_inquiry + (dev_scsi, fd, dev_scsi->serial, dev_scsi->serial_short, + len, dev_scsi->unit_serial_number, dev_scsi->wwn, + dev_scsi->wwn_vendor_extension, dev_scsi->tgpt_group)) { + retval = 1; + goto completed; + } else { + retval = 0; + goto completed; + } + } else if (page_code == PAGE_83_PRE_SPC3) { + retval = + do_scsi_page83_prespc3_inquiry(dev_scsi, fd, + dev_scsi->serial, + dev_scsi->serial_short, len); + if (retval) { + /* + * Fallback to servicing a SPC-2/3 compliant page 83 + * inquiry if the page 83 reply format does not + * conform to pre-SPC3 expectations. + */ + if (retval == 2) { + if (do_scsi_page83_inquiry + (dev_scsi, fd, dev_scsi->serial, + dev_scsi->serial_short, len, + dev_scsi->unit_serial_number, + dev_scsi->wwn, + dev_scsi->wwn_vendor_extension, + dev_scsi->tgpt_group)) { + retval = 1; + goto completed; + } else { + retval = 0; + goto completed; + } + } else { + retval = 1; + goto completed; + } + } else { + retval = 0; + goto completed; + } + } else if (page_code != 0x00) { + log_debug("%s: unsupported page code 0x%d", dev_scsi->kernel, + page_code); + retval = 1; + goto completed; + } + + /* + * Get page 0, the page of the pages. By default, try from best to + * worst of supported pages: 0x83 then 0x80. + */ + if (do_scsi_page0_inquiry(dev_scsi, fd, page0, SCSI_INQ_BUFF_LEN)) { + /* + * Don't try anything else. Black list if a specific page + * should be used for this vendor+model, or maybe have an + * optional fall-back to page 0x80 or page 0x83. + */ + retval = 1; + goto completed; + } + + for (ind = 4; ind <= page0[3] + 3; ind++) { + if (page0[ind] == PAGE_83) { + if (!do_scsi_page83_inquiry + (dev_scsi, fd, dev_scsi->serial, + dev_scsi->serial_short, len, + dev_scsi->unit_serial_number, dev_scsi->wwn, + dev_scsi->wwn_vendor_extension, + dev_scsi->tgpt_group)) { + /* + * Success + */ + retval = 0; + goto completed; + } + } + } + + for (ind = 4; ind <= page0[3] + 3; ind++) { + if (page0[ind] == PAGE_80) { + if (!do_scsi_page80_inquiry + (dev_scsi, fd, dev_scsi->serial, + dev_scsi->serial_short, len)) { + /* + * Success + */ + retval = 0; + goto completed; + } + } + } + retval = 1; + + completed: + close(fd); + return retval; +} static void set_type(const char *from, char *to, size_t len) { - int type_num; - char *eptr; - const char *type = "generic"; - - type_num = strtoul(from, &eptr, 0); - if (eptr != from) { - switch (type_num) { - case 0: - type = "disk"; - break; - case 1: - type = "tape"; - break; - case 4: - type = "optical"; - break; - case 5: - type = "cd"; - break; - case 7: - type = "optical"; - break; - case 0xe: - type = "disk"; - break; - case 0xf: - type = "optical"; - break; - default: - break; - } - } - strscpy(to, len, type); + int type_num; + char *eptr; + const char *type = "generic"; + + type_num = strtoul(from, &eptr, 0); + if (eptr != from) { + switch (type_num) { + case 0: + type = "disk"; + break; + case 1: + type = "tape"; + break; + case 4: + type = "optical"; + break; + case 5: + type = "cd"; + break; + case 7: + type = "optical"; + break; + case 0xe: + type = "disk"; + break; + case 0xf: + type = "optical"; + break; + default: + break; + } + } + strscpy(to, len, type); } /* @@ -1179,45 +1256,47 @@ static void set_type(const char *from, char *to, size_t len) * Return a pointer to the NUL terminated string, returns NULL if no * matches. */ -static char *get_value(char **buffer) { - - static const char *quote_string = "\"\n"; - static const char *comma_string = ",\n"; - char *val; - const char *end; - - if (**buffer == '"') { - /* - * skip leading quote, terminate when quote seen - */ - (*buffer)++; - end = quote_string; - } else { - end = comma_string; - } - val = strsep(buffer, end); - if (val && end == quote_string) { - /* - * skip trailing quote - */ - (*buffer)++; - } - - while (isspace(**buffer)) { - (*buffer)++; - } - return val; +static char *get_value(char **buffer) +{ + + static const char *quote_string = "\"\n"; + static const char *comma_string = ",\n"; + char *val; + const char *end; + + if (**buffer == '"') { + /* + * skip leading quote, terminate when quote seen + */ + (*buffer)++; + end = quote_string; + } else { + end = comma_string; + } + val = strsep(buffer, end); + if (val && end == quote_string) { + /* + * skip trailing quote + */ + (*buffer)++; + } + + while (isspace(**buffer)) { + (*buffer)++; + } + return val; } -static int argc_count(char *opts) { +static int argc_count(char *opts) +{ - int i = 0; - while (*opts != '\0') { - if (*opts++ == ' ') { - i++; - } - } - return i; + int i = 0; + while (*opts != '\0') { + if (*opts++ == ' ') { + i++; + } + } + return i; } /* @@ -1229,472 +1308,501 @@ static int argc_count(char *opts) { * * vendor and model can end in '\n'. */ -static int get_file_options(const char *vendor, const char *model, int *argc, char ***newargv) { - - char *buffer; - FILE *f = NULL; - char *buf; - char *str1; - char *vendor_in, *model_in, *options_in; /* read in from file */ - int lineno; - int c; - int retval = 0; - int rc = 0; - - f = fopen(config_file, "re"); - if (f == NULL) { - if (errno == ENOENT) { - return 1; - } - else { - - rc = -errno; - log_error( "can't open %s: errno = %d", config_file, rc); - return -1; - } - } - - /* - * Allocate a buffer rather than put it on the stack so we can - * keep it around to parse any options (any allocated newargv - * points into this buffer for its strings). - */ - buffer = (char*)malloc(MAX_BUFFER_LEN); - if (!buffer) { - - fclose(f); - return -ENOMEM; - } - - *newargv = NULL; - lineno = 0; - while (1) { - vendor_in = model_in = options_in = NULL; - - buf = fgets(buffer, MAX_BUFFER_LEN, f); - - if (buf == NULL) { - break; - } - - lineno++; - if (buf[strlen(buffer) - 1] != '\n') { - log_error("Config file line %d too long", lineno); - break; - } - - while (isspace(*buf)) { - buf++; - } - - /* blank or all whitespace line */ - if (*buf == '\0') { - continue; - } - - /* comment line */ - if (*buf == '#') { - continue; - } - str1 = strsep(&buf, "="); - if (str1 && strcaseeq(str1, "VENDOR")) { - str1 = get_value(&buf); - if (!str1) { - retval = -ENOMEM; - break; - } - vendor_in = str1; - - str1 = strsep(&buf, "="); - if (str1 && strcaseeq(str1, "MODEL")) { - str1 = get_value(&buf); - if (!str1) { - retval = -ENOMEM; - break; - } - model_in = str1; - str1 = strsep(&buf, "="); - } - } - - if (str1 && strcaseeq(str1, "OPTIONS")) { - str1 = get_value(&buf); - if (!str1) { - retval = -ENOMEM; - break; - } - options_in = str1; - } - - /* - * Only allow: [vendor=foo[,model=bar]]options=stuff - */ - if (!options_in || (!vendor_in && model_in)) { - log_error("Error parsing config file line %d '%s'", lineno, buffer); - retval = -1; - break; - } - if (vendor == NULL) { - if (vendor_in == NULL) { - break; - } - } - else if (vendor_in && strneq(vendor, vendor_in, strlen(vendor_in)) && (!model_in || (strneq(model, model_in, strlen(model_in))))) { - /* - * Matched vendor and optionally model. - * - * Note: a short vendor_in or model_in can - * give a partial match (that is FOO - * matches FOOBAR). - */ - break; - } - } - - fclose( f ); - - if (retval == 0) { - if (vendor_in != NULL || model_in != NULL || options_in != NULL) { - /* - * Something matched. Allocate newargv, and store - * values found in options_in. - */ - strcpy(buffer, options_in); - c = argc_count(buffer) + 2; - *newargv = calloc(c, sizeof(**newargv)); - if (!*newargv) { - - retval = -ENOMEM; - } - else { - *argc = c; - c = 0; - /* - * argv[0] at 0 is skipped by getopt, but - * store the buffer address there for - * later freeing - */ - (*newargv)[c] = buffer; - for (c = 1; c < *argc; c++) { - (*newargv)[c] = strsep(&buffer, " \t"); - } - } - } else { - /* No matches */ - retval = 1; - } - } - if (retval != 0) { - free(buffer); - } - - return retval; -} - -static void help( char const* progname ) { - printf("Usage: %s [OPTION...] /path/to/device/file\n\n" - "SCSI device identification.\n\n" - " -h --help Print this message\n" - " --version Print version of the program\n\n" - " -d --device= Device node for SG_IO commands\n" - " -f --config= Location of config file\n" - " -p --page=0x80|0x83|pre-spc3-83 SCSI page (0x80, 0x83, pre-spc3-83)\n" - " -s --sg-version=3|4 Use SGv3 or SGv4\n" - " -u --replace-whitespace Replace all whitespace by underscores\n" - " -v --verbose Verbose logging\n" - , progname); +static int get_file_options(const char *vendor, const char *model, int *argc, + char ***newargv) +{ + char *buffer; + FILE *f = NULL; + char *buf; + char *str1; + char *vendor_in, *model_in, *options_in; /* read in from file */ + int lineno; + int c; + int retval = 0; + int rc = 0; + + f = fopen(config_file, "re"); + if (f == NULL) { + if (errno == ENOENT) { + return 1; + } else { + + rc = -errno; + log_error("can't open %s: errno = %d", config_file, rc); + return -1; + } + } + + /* + * Allocate a buffer rather than put it on the stack so we can + * keep it around to parse any options (any allocated newargv + * points into this buffer for its strings). + */ + buffer = (char *)malloc(MAX_BUFFER_LEN); + if (!buffer) { + + fclose(f); + return -ENOMEM; + } + + *newargv = NULL; + lineno = 0; + while (1) { + vendor_in = model_in = options_in = NULL; + + buf = fgets(buffer, MAX_BUFFER_LEN, f); + + if (buf == NULL) { + break; + } + + lineno++; + if (buf[strlen(buffer) - 1] != '\n') { + log_error("Config file line %d too long", lineno); + break; + } + + while (isspace(*buf)) { + buf++; + } + + /* blank or all whitespace line */ + if (*buf == '\0') { + continue; + } + + /* comment line */ + if (*buf == '#') { + continue; + } + str1 = strsep(&buf, "="); + if (str1 && strcaseeq(str1, "VENDOR")) { + str1 = get_value(&buf); + if (!str1) { + retval = -ENOMEM; + break; + } + vendor_in = str1; + + str1 = strsep(&buf, "="); + if (str1 && strcaseeq(str1, "MODEL")) { + str1 = get_value(&buf); + if (!str1) { + retval = -ENOMEM; + break; + } + model_in = str1; + str1 = strsep(&buf, "="); + } + } + + if (str1 && strcaseeq(str1, "OPTIONS")) { + str1 = get_value(&buf); + if (!str1) { + retval = -ENOMEM; + break; + } + options_in = str1; + } + + /* + * Only allow: [vendor=foo[,model=bar]]options=stuff + */ + if (!options_in || (!vendor_in && model_in)) { + log_error("Error parsing config file line %d '%s'", + lineno, buffer); + retval = -1; + break; + } + if (vendor == NULL) { + if (vendor_in == NULL) { + break; + } + } else if (vendor_in + && strneq(vendor, vendor_in, strlen(vendor_in)) + && (!model_in + || (strneq(model, model_in, strlen(model_in))))) + { + /* + * Matched vendor and optionally model. + * + * Note: a short vendor_in or model_in can + * give a partial match (that is FOO + * matches FOOBAR). + */ + break; + } + } + + fclose(f); + + if (retval == 0) { + if (vendor_in != NULL || model_in != NULL || options_in != NULL) { + /* + * Something matched. Allocate newargv, and store + * values found in options_in. + */ + strcpy(buffer, options_in); + c = argc_count(buffer) + 2; + *newargv = calloc(c, sizeof(**newargv)); + if (!*newargv) { + + retval = -ENOMEM; + } else { + *argc = c; + c = 0; + /* + * argv[0] at 0 is skipped by getopt, but + * store the buffer address there for + * later freeing + */ + (*newargv)[c] = buffer; + for (c = 1; c < *argc; c++) { + (*newargv)[c] = strsep(&buffer, " \t"); + } + } + } else { + /* No matches */ + retval = 1; + } + } + if (retval != 0) { + free(buffer); + } + + return retval; } -static int set_options( int argc, char **argv, char *maj_min_dev) { - - int option; - - /* - * optind is a global extern used by getopt. Since we can call - * set_options twice (once for command line, and once for config - * file) we have to reset this back to 1. - */ - optind = 1; - while ((option = getopt_long(argc, argv, "d:f:gp:uvVh", options, NULL)) >= 0) - switch (option) { - - case 'd': - dev_specified = true; - strscpy(maj_min_dev, MAX_PATH_LEN, optarg); - break; - - case 'f': - strscpy(config_file, MAX_PATH_LEN, optarg); - break; - - case 'h': - help( argv[0] ); - exit(0); - - case 'p': - if (streq(optarg, "0x80")) - default_page_code = PAGE_80; - else if (streq(optarg, "0x83")) - default_page_code = PAGE_83; - else if (streq(optarg, "pre-spc3-83")) - default_page_code = PAGE_83_PRE_SPC3; - else { - fprintf(stderr, "[ERROR] %s: Unknown page code '%s'\n", argv[0], optarg); - return -1; - } - break; - - case 's': - sg_version = atoi(optarg); - if (sg_version < 3 || sg_version > 4) { - fprintf(stderr, "[ERROR] %s: Unknown SG version '%s'\n", argv[0], optarg); - return -1; - } - break; - - case 'u': - reformat_serial = true; - break; - - case 'v': - break; - - case 'V': - printf("%s\n", "1.0"); - exit(0); - - case '?': - return -1; - - default: - fprintf(stderr, "[ERROR] %s: Unknown option -%c\n", argv[0], option); - return -1; - } - - if (optind < argc && !dev_specified) { - dev_specified = true; - strscpy(maj_min_dev, MAX_PATH_LEN, argv[optind]); - } - - return 0; -} +static void help(char const *progname) +{ + printf("Usage: %s [OPTION...] /path/to/device/file\n\n" + "SCSI device identification.\n\n" + " -h --help Print this message\n" + " --version Print version of the program\n\n" + " -d --device= Device node for SG_IO commands\n" + " -f --config= Location of config file\n" + " -p --page=0x80|0x83|pre-spc3-83 SCSI page (0x80, 0x83, pre-spc3-83)\n" + " -s --sg-version=3|4 Use SGv3 or SGv4\n" + " -u --replace-whitespace Replace all whitespace by underscores\n" + " -v --verbose Verbose logging\n", + progname); -static int per_dev_options(struct scsi_id_device *dev_scsi, int *good_bad, int *page_code) { - - int retval; - int newargc; - char **newargv = NULL; - int option; - - *good_bad = all_good; - *page_code = default_page_code; - - retval = get_file_options( vendor_str, model_str, &newargc, &newargv); - - optind = 1; /* reset this global extern */ - while (retval == 0) { - option = getopt_long(newargc, newargv, "p:", options, NULL); - if (option == -1) - break; - - switch (option) { - - case 'p': - if (streq(optarg, "0x80")) { - *page_code = PAGE_80; - } else if (streq(optarg, "0x83")) { - *page_code = PAGE_83; - } else if (streq(optarg, "pre-spc3-83")) { - *page_code = PAGE_83_PRE_SPC3; - } else { - log_error("Unknown page code '%s'", optarg); - retval = -1; - } - break; - - default: - log_error("Unknown or bad option '%c' (0x%x)", option, option); - retval = -1; - break; - } - } - - if (newargv) { - free(newargv[0]); - free(newargv); - } - return retval; } +static int set_options(int argc, char **argv, char *maj_min_dev) +{ -static int set_inq_values( struct scsi_id_device *dev_scsi, const char *path) { - - int retval; + int option; + + /* + * optind is a global extern used by getopt. Since we can call + * set_options twice (once for command line, and once for config + * file) we have to reset this back to 1. + */ + optind = 1; + while ((option = + getopt_long(argc, argv, "d:f:gp:uvVh", options, NULL)) >= 0) + switch (option) { + + case 'd': + dev_specified = true; + strscpy(maj_min_dev, MAX_PATH_LEN, optarg); + break; + + case 'f': + strscpy(config_file, MAX_PATH_LEN, optarg); + break; + + case 'h': + help(argv[0]); + exit(0); + + case 'p': + if (streq(optarg, "0x80")) + default_page_code = PAGE_80; + else if (streq(optarg, "0x83")) + default_page_code = PAGE_83; + else if (streq(optarg, "pre-spc3-83")) + default_page_code = PAGE_83_PRE_SPC3; + else { + fprintf(stderr, + "[ERROR] %s: Unknown page code '%s'\n", + argv[0], optarg); + return -1; + } + break; + + case 's': + sg_version = atoi(optarg); + if (sg_version < 3 || sg_version > 4) { + fprintf(stderr, + "[ERROR] %s: Unknown SG version '%s'\n", + argv[0], optarg); + return -1; + } + break; + + case 'u': + reformat_serial = true; + break; + + case 'v': + break; + + case 'V': + printf("%s\n", "1.0"); + exit(0); + + case '?': + return -1; + + default: + fprintf(stderr, "[ERROR] %s: Unknown option -%c\n", + argv[0], option); + return -1; + } + + if (optind < argc && !dev_specified) { + dev_specified = true; + strscpy(maj_min_dev, MAX_PATH_LEN, argv[optind]); + } + + return 0; +} - dev_scsi->use_sg = sg_version; +static int per_dev_options(struct scsi_id_device *dev_scsi, int *good_bad, + int *page_code) +{ - retval = scsi_std_inquiry(dev_scsi, path); - if (retval) { - - log_error("scsi_std_inquiry('%s') rc = %d\n", path, retval); - return retval; - } + int retval; + int newargc; + char **newargv = NULL; + int option; + + *good_bad = all_good; + *page_code = default_page_code; + + retval = get_file_options(vendor_str, model_str, &newargc, &newargv); + + optind = 1; /* reset this global extern */ + while (retval == 0) { + option = getopt_long(newargc, newargv, "p:", options, NULL); + if (option == -1) + break; + + switch (option) { + + case 'p': + if (streq(optarg, "0x80")) { + *page_code = PAGE_80; + } else if (streq(optarg, "0x83")) { + *page_code = PAGE_83; + } else if (streq(optarg, "pre-spc3-83")) { + *page_code = PAGE_83_PRE_SPC3; + } else { + log_error("Unknown page code '%s'", optarg); + retval = -1; + } + break; + + default: + log_error("Unknown or bad option '%c' (0x%x)", option, + option); + retval = -1; + break; + } + } + + if (newargv) { + free(newargv[0]); + free(newargv); + } + return retval; +} - vdev_util_encode_string(dev_scsi->vendor, vendor_enc_str, sizeof(vendor_enc_str)); - vdev_util_encode_string(dev_scsi->model, model_enc_str, sizeof(model_enc_str)); +static int set_inq_values(struct scsi_id_device *dev_scsi, const char *path) +{ - vdev_util_replace_whitespace(dev_scsi->vendor, vendor_str, sizeof(vendor_str)); - vdev_util_replace_chars(vendor_str, NULL); - vdev_util_replace_whitespace(dev_scsi->model, model_str, sizeof(model_str)); - vdev_util_replace_chars(model_str, NULL); - set_type(dev_scsi->type, type_str, sizeof(type_str)); - vdev_util_replace_whitespace(dev_scsi->revision, revision_str, sizeof(revision_str)); - vdev_util_replace_chars(revision_str, NULL); - return 0; + int retval; + + dev_scsi->use_sg = sg_version; + + retval = scsi_std_inquiry(dev_scsi, path); + if (retval) { + + log_error("scsi_std_inquiry('%s') rc = %d\n", path, retval); + return retval; + } + + vdev_util_encode_string(dev_scsi->vendor, vendor_enc_str, + sizeof(vendor_enc_str)); + vdev_util_encode_string(dev_scsi->model, model_enc_str, + sizeof(model_enc_str)); + + vdev_util_replace_whitespace(dev_scsi->vendor, vendor_str, + sizeof(vendor_str)); + vdev_util_replace_chars(vendor_str, NULL); + vdev_util_replace_whitespace(dev_scsi->model, model_str, + sizeof(model_str)); + vdev_util_replace_chars(model_str, NULL); + set_type(dev_scsi->type, type_str, sizeof(type_str)); + vdev_util_replace_whitespace(dev_scsi->revision, revision_str, + sizeof(revision_str)); + vdev_util_replace_chars(revision_str, NULL); + return 0; } /* * scsi_id: try to get an id, if one is found, printf it to stdout. * returns a value passed to exit() - 0 if printed an id, else 1. */ -static int scsi_id( char *maj_min_dev) { - - struct scsi_id_device dev_scsi = {}; - int good_dev = 1; - int page_code = 0; - int retval = 0; - - if (set_inq_values( &dev_scsi, maj_min_dev) < 0) { - retval = 1; - return retval; - } - - /* get per device (vendor + model) options from the config file */ - per_dev_options( &dev_scsi, &good_dev, &page_code); - if (!good_dev) { - - log_error("per_dev_options: good_dev = %d", good_dev ); - retval = 1; - return retval; - } - - /* read serial number from mode pages (no values for optical drives) */ - scsi_get_serial( &dev_scsi, maj_min_dev, page_code, MAX_SERIAL_LEN); - - char serial_str[MAX_SERIAL_LEN]; - - vdev_property_add("VDEV_SCSI", "1" ); - vdev_property_add("VDEV_SCSI_VENDOR", vendor_str ); - vdev_property_add("VDEV_SCSI_VENDOR_ENC", vendor_enc_str ); - vdev_property_add("VDEV_SCSI_MODEL", model_str ); - vdev_property_add("VDEV_SCSI_MODEL_ENC", model_enc_str ); - vdev_property_add("VDEV_SCSI_REVISION", revision_str ); - vdev_property_add("VDEV_SCSI_TYPE", type_str ); - - if (dev_scsi.serial[0] != '\0') { - - vdev_util_replace_whitespace(dev_scsi.serial, serial_str, sizeof(serial_str)); - vdev_util_replace_chars(serial_str, NULL); - - vdev_property_add("VDEV_SCSI_SERIAL", serial_str ); - - vdev_util_replace_whitespace(dev_scsi.serial_short, serial_str, sizeof(serial_str)); - vdev_util_replace_chars(serial_str, NULL); - - vdev_property_add("VDEV_SCSI_SERIAL_SHORT", serial_str ); - } - if (dev_scsi.wwn[0] != '\0') { - - char wwn_buf[100]; - char wwn_vendor_buf[100]; - - memset( wwn_buf, 0, 100 ); - memset( wwn_vendor_buf, 0, 100 ); - - vdev_property_add("VDEV_SCSI_WWN", dev_scsi.wwn ); - - if (dev_scsi.wwn_vendor_extension[0] != '\0') { - - snprintf( wwn_buf, 99, "0x%s%s", dev_scsi.wwn, dev_scsi.wwn_vendor_extension ); - snprintf( wwn_vendor_buf, 99, "0x%s", dev_scsi.wwn_vendor_extension ); - - vdev_property_add("VDEV_SCSI_WWN_VENDOR_EXTENSION", wwn_vendor_buf ); - vdev_property_add("VDEV_SCSI_WWN_WITH_EXTENSION", wwn_buf ); - } - - else { - - snprintf( wwn_buf, 99, "0x%s", dev_scsi.wwn ); - - vdev_property_add("VDEV_SCSI_WWN_WITH_EXTENSION", wwn_buf ); - } - } - if (dev_scsi.tgpt_group[0] != '\0') { - - vdev_property_add("VDEV_SCSI_TARGET_PORT", dev_scsi.tgpt_group ); - } - if (dev_scsi.unit_serial_number[0] != '\0') { - - vdev_property_add("VDEV_SCSI_UNIT_SERIAL", dev_scsi.unit_serial_number ); - } - - return retval; -} +static int scsi_id(char *maj_min_dev) +{ + + struct scsi_id_device dev_scsi = { }; + int good_dev = 1; + int page_code = 0; + int retval = 0; + + if (set_inq_values(&dev_scsi, maj_min_dev) < 0) { + retval = 1; + return retval; + } + + /* get per device (vendor + model) options from the config file */ + per_dev_options(&dev_scsi, &good_dev, &page_code); + if (!good_dev) { + + log_error("per_dev_options: good_dev = %d", good_dev); + retval = 1; + return retval; + } + + /* read serial number from mode pages (no values for optical drives) */ + scsi_get_serial(&dev_scsi, maj_min_dev, page_code, MAX_SERIAL_LEN); + + char serial_str[MAX_SERIAL_LEN]; + + vdev_property_add("VDEV_SCSI", "1"); + vdev_property_add("VDEV_SCSI_VENDOR", vendor_str); + vdev_property_add("VDEV_SCSI_VENDOR_ENC", vendor_enc_str); + vdev_property_add("VDEV_SCSI_MODEL", model_str); + vdev_property_add("VDEV_SCSI_MODEL_ENC", model_enc_str); + vdev_property_add("VDEV_SCSI_REVISION", revision_str); + vdev_property_add("VDEV_SCSI_TYPE", type_str); + + if (dev_scsi.serial[0] != '\0') { + + vdev_util_replace_whitespace(dev_scsi.serial, serial_str, + sizeof(serial_str)); + vdev_util_replace_chars(serial_str, NULL); + vdev_property_add("VDEV_SCSI_SERIAL", serial_str); + + vdev_util_replace_whitespace(dev_scsi.serial_short, serial_str, + sizeof(serial_str)); + vdev_util_replace_chars(serial_str, NULL); + + vdev_property_add("VDEV_SCSI_SERIAL_SHORT", serial_str); + } + if (dev_scsi.wwn[0] != '\0') { + + char wwn_buf[100]; + char wwn_vendor_buf[100]; + + memset(wwn_buf, 0, 100); + memset(wwn_vendor_buf, 0, 100); + + vdev_property_add("VDEV_SCSI_WWN", dev_scsi.wwn); + + if (dev_scsi.wwn_vendor_extension[0] != '\0') { + + snprintf(wwn_buf, 99, "0x%s%s", dev_scsi.wwn, + dev_scsi.wwn_vendor_extension); + snprintf(wwn_vendor_buf, 99, "0x%s", + dev_scsi.wwn_vendor_extension); + + vdev_property_add("VDEV_SCSI_WWN_VENDOR_EXTENSION", + wwn_vendor_buf); + vdev_property_add("VDEV_SCSI_WWN_WITH_EXTENSION", + wwn_buf); + } + + else { + + snprintf(wwn_buf, 99, "0x%s", dev_scsi.wwn); + + vdev_property_add("VDEV_SCSI_WWN_WITH_EXTENSION", + wwn_buf); + } + } + if (dev_scsi.tgpt_group[0] != '\0') { + + vdev_property_add("VDEV_SCSI_TARGET_PORT", dev_scsi.tgpt_group); + } + if (dev_scsi.unit_serial_number[0] != '\0') { + + vdev_property_add("VDEV_SCSI_UNIT_SERIAL", + dev_scsi.unit_serial_number); + } + + return retval; +} // entry point -int main(int argc, char **argv) { - - int retval = 0; - char maj_min_dev[MAX_PATH_LEN]; - int newargc; - char **newargv = NULL; - - /* - * Get config file options. - */ - retval = get_file_options( NULL, NULL, &newargc, &newargv); - if (retval < 0) { - retval = 1; - goto exit; - } - if (retval == 0) { - - if( newargv == NULL ) { - retval = 4; - goto exit; - } - - if (set_options( newargc, newargv, maj_min_dev) < 0) { - retval = 2; - goto exit; - } - } - - /* - * Get command line options (overriding any config file settings). - */ - if (set_options( argc, argv, maj_min_dev) < 0) { - exit(1); - } - - if (!dev_specified) { - log_error("%s", "No device specified."); - retval = 1; - goto exit; - } - - retval = scsi_id( maj_min_dev); - -exit: - if (newargv) { - free(newargv[0]); - free(newargv); - } - - vdev_property_print(); - vdev_property_free_all(); - - return retval; +int main(int argc, char **argv) +{ + + int retval = 0; + char maj_min_dev[MAX_PATH_LEN]; + int newargc; + char **newargv = NULL; + + /* + * Get config file options. + */ + retval = get_file_options(NULL, NULL, &newargc, &newargv); + if (retval < 0) { + retval = 1; + goto exit; + } + if (retval == 0) { + + if (newargv == NULL) { + retval = 4; + goto exit; + } + + if (set_options(newargc, newargv, maj_min_dev) < 0) { + retval = 2; + goto exit; + } + } + + /* + * Get command line options (overriding any config file settings). + */ + if (set_options(argc, argv, maj_min_dev) < 0) { + exit(1); + } + + if (!dev_specified) { + log_error("%s", "No device specified."); + retval = 1; + goto exit; + } + + retval = scsi_id(maj_min_dev); + + exit: + if (newargv) { + free(newargv[0]); + free(newargv); + } + + vdev_property_print(); + vdev_property_free_all(); + + return retval; } diff --git a/vdevd/helpers/LINUX/stat_usb.c b/vdevd/helpers/LINUX/stat_usb.c index cc433a0..edc0faf 100644 --- a/vdevd/helpers/LINUX/stat_usb.c +++ b/vdevd/helpers/LINUX/stat_usb.c @@ -47,250 +47,260 @@ #define USB_DT_DEVICE 0x01 #define USB_DT_INTERFACE 0x04 +static void set_usb_iftype(char *to, int if_class_num, size_t len) +{ + const char *type = "generic"; -static void set_usb_iftype(char *to, int if_class_num, size_t len) { - const char *type = "generic"; - - switch (if_class_num) { - case 1: - type = "audio"; - break; - case 2: /* CDC-Control */ - break; - case 3: - type = "hid"; - break; - case 5: /* Physical */ - break; - case 6: - type = "media"; - break; - case 7: - type = "printer"; - break; - case 8: - type = "storage"; - break; - case 9: - type = "hub"; - break; - case 0x0a: /* CDC-Data */ - break; - case 0x0b: /* Chip/Smart Card */ - break; - case 0x0d: /* Content Security */ - break; - case 0x0e: - type = "video"; - break; - case 0xdc: /* Diagnostic Device */ - break; - case 0xe0: /* Wireless Controller */ - break; - case 0xfe: /* Application-specific */ - break; - case 0xff: /* Vendor-specific */ - break; - default: - break; - } - - strncpy(to, type, len); - to[len-1] = '\0'; + switch (if_class_num) { + case 1: + type = "audio"; + break; + case 2: /* CDC-Control */ + break; + case 3: + type = "hid"; + break; + case 5: /* Physical */ + break; + case 6: + type = "media"; + break; + case 7: + type = "printer"; + break; + case 8: + type = "storage"; + break; + case 9: + type = "hub"; + break; + case 0x0a: /* CDC-Data */ + break; + case 0x0b: /* Chip/Smart Card */ + break; + case 0x0d: /* Content Security */ + break; + case 0x0e: + type = "video"; + break; + case 0xdc: /* Diagnostic Device */ + break; + case 0xe0: /* Wireless Controller */ + break; + case 0xfe: /* Application-specific */ + break; + case 0xff: /* Vendor-specific */ + break; + default: + break; + } + + strncpy(to, type, len); + to[len - 1] = '\0'; } -static int set_usb_mass_storage_ifsubtype(char *to, const char *from, size_t len) { - - int type_num = 0; - char *eptr; - const char *type = "generic"; - - type_num = strtoul(from, &eptr, 0); - if (eptr != from) { - switch (type_num) { - case 1: /* RBC devices */ - type = "rbc"; - break; - case 2: - type = "atapi"; - break; - case 3: - type = "tape"; - break; - case 4: /* UFI */ - type = "floppy"; - break; - case 6: /* Transparent SPC-2 devices */ - type = "scsi"; - break; - default: - break; - } - } - - strncpy( to, type, (strlen(type) < len ? strlen(type) : len) ); - - return type_num; +static int set_usb_mass_storage_ifsubtype(char *to, const char *from, + size_t len) +{ + + int type_num = 0; + char *eptr; + const char *type = "generic"; + + type_num = strtoul(from, &eptr, 0); + if (eptr != from) { + switch (type_num) { + case 1: /* RBC devices */ + type = "rbc"; + break; + case 2: + type = "atapi"; + break; + case 3: + type = "tape"; + break; + case 4: /* UFI */ + type = "floppy"; + break; + case 6: /* Transparent SPC-2 devices */ + type = "scsi"; + break; + default: + break; + } + } + + strncpy(to, type, (strlen(type) < len ? strlen(type) : len)); + + return type_num; } -static void set_scsi_type(char *to, const char *from, size_t len) { - - int type_num; - char *eptr; - const char *type = "generic"; - - type_num = strtoul(from, &eptr, 0); - if (eptr != from) { - switch (type_num) { - case 0: - case 0xe: - type = "disk"; - break; - case 1: - type = "tape"; - break; - case 4: - case 7: - case 0xf: - type = "optical"; - break; - case 5: - type = "cd"; - break; - default: - break; - } - } - - strncpy( to, type, (strlen(type) < len ? strlen(type) : len) ); +static void set_scsi_type(char *to, const char *from, size_t len) +{ + + int type_num; + char *eptr; + const char *type = "generic"; + + type_num = strtoul(from, &eptr, 0); + if (eptr != from) { + switch (type_num) { + case 0: + case 0xe: + type = "disk"; + break; + case 1: + type = "tape"; + break; + case 4: + case 7: + case 0xf: + type = "optical"; + break; + case 5: + type = "cd"; + break; + default: + break; + } + } + + strncpy(to, type, (strlen(type) < len ? strlen(type) : len)); } // read packed descriptors information from sysfs -static int dev_if_packed_info( char const* sysfs_path, char *ifs_str, size_t len) { - - char sysfs_descriptors[4096]; - int fd = -1; - ssize_t size; - unsigned char buf[18 + 65535]; - int pos = 0; - unsigned strpos = 0; - int rc = 0; - struct usb_interface_descriptor { - u_int8_t bLength; - u_int8_t bDescriptorType; - u_int8_t bInterfaceNumber; - u_int8_t bAlternateSetting; - u_int8_t bNumEndpoints; - u_int8_t bInterfaceClass; - u_int8_t bInterfaceSubClass; - u_int8_t bInterfaceProtocol; - u_int8_t iInterface; - } __attribute__((packed)); - - memset( sysfs_descriptors, 0, 4096 ); - snprintf( sysfs_descriptors, 4095, "%s/descriptors", sysfs_path ); - - fd = open(sysfs_descriptors, O_RDONLY|O_CLOEXEC); - if (fd < 0) { - - rc = -errno; - log_debug("open('%s') errno = %d\n", sysfs_descriptors, rc ); - - return rc; - } - - size = read(fd, buf, sizeof(buf)); - if (size < 18 || size == sizeof(buf)) { - - rc = -errno; - - close( fd ); - log_debug("read('%s') rc = %zd, errno = %d\n", sysfs_path, size, rc ); - return -EIO; - } - - close( fd ); - - ifs_str[0] = '\0'; - while (pos < size && strpos+7 < len-2) { - - struct usb_interface_descriptor *desc; - char if_str[8]; - - desc = (struct usb_interface_descriptor *) &buf[pos]; - if (desc->bLength < 3) { - break; - } - - pos += desc->bLength; - - if (desc->bDescriptorType != USB_DT_INTERFACE) { - continue; - } - - if (snprintf(if_str, 8, ":%02x%02x%02x", desc->bInterfaceClass, desc->bInterfaceSubClass, desc->bInterfaceProtocol) != 7) { - continue; - } - - if (strstr(ifs_str, if_str) != NULL) { - continue; - } - - memcpy(&ifs_str[strpos], if_str, 8), - strpos += 7; - } - - if (strpos > 0) { - ifs_str[strpos++] = ':'; - ifs_str[strpos++] = '\0'; - } - - return 0; -} +static int dev_if_packed_info(char const *sysfs_path, char *ifs_str, size_t len) +{ + + char sysfs_descriptors[4096]; + int fd = -1; + ssize_t size; + unsigned char buf[18 + 65535]; + int pos = 0; + unsigned strpos = 0; + int rc = 0; + struct usb_interface_descriptor { + u_int8_t bLength; + u_int8_t bDescriptorType; + u_int8_t bInterfaceNumber; + u_int8_t bAlternateSetting; + u_int8_t bNumEndpoints; + u_int8_t bInterfaceClass; + u_int8_t bInterfaceSubClass; + u_int8_t bInterfaceProtocol; + u_int8_t iInterface; + } __attribute__ ((packed)); + + memset(sysfs_descriptors, 0, 4096); + snprintf(sysfs_descriptors, 4095, "%s/descriptors", sysfs_path); + + fd = open(sysfs_descriptors, O_RDONLY | O_CLOEXEC); + if (fd < 0) { + + rc = -errno; + log_debug("open('%s') errno = %d\n", sysfs_descriptors, rc); + + return rc; + } + + size = read(fd, buf, sizeof(buf)); + if (size < 18 || size == sizeof(buf)) { + + rc = -errno; + + close(fd); + log_debug("read('%s') rc = %zd, errno = %d\n", sysfs_path, size, + rc); + return -EIO; + } + + close(fd); + + ifs_str[0] = '\0'; + while (pos < size && strpos + 7 < len - 2) { + + struct usb_interface_descriptor *desc; + char if_str[8]; + + desc = (struct usb_interface_descriptor *)&buf[pos]; + if (desc->bLength < 3) { + break; + } + + pos += desc->bLength; + if (desc->bDescriptorType != USB_DT_INTERFACE) { + continue; + } -void usage(char const* progname) { - fprintf(stderr, "[ERROR] %s: Usage: %s /path/to/sysfs/device/directory\n", progname, progname); - exit(2); + if (snprintf + (if_str, 8, ":%02x%02x%02x", desc->bInterfaceClass, + desc->bInterfaceSubClass, desc->bInterfaceProtocol) != 7) { + continue; + } + + if (strstr(ifs_str, if_str) != NULL) { + continue; + } + + memcpy(&ifs_str[strpos], if_str, 8), strpos += 7; + } + + if (strpos > 0) { + ifs_str[strpos++] = ':'; + ifs_str[strpos++] = '\0'; + } + + return 0; } +void usage(char const *progname) +{ + fprintf(stderr, + "[ERROR] %s: Usage: %s /path/to/sysfs/device/directory\n", + progname, progname); + exit(2); +} // find out what kind of device this is from the sysfs device tree // fill in the caller-supplied pointer with a malloc'ed string that encodes the DEVTYPE -int get_device_type( char const* sysfs_path, char** device_type, size_t* device_type_len ) { - - char uevent_path[4097]; - memset( uevent_path, 0, 4097 ); - - char* uevent_buf = NULL; - size_t uevent_len = 0; - - char* device_type_buf = NULL; - size_t device_type_buf_len = 0; - - int rc = 0; - - snprintf(uevent_path, 4096, "%s/uevent", sysfs_path ); - - rc = vdev_read_file( uevent_path, &uevent_buf, &uevent_len ); - if( rc != 0 ) { - - return rc; - } - - rc = vdev_sysfs_uevent_get_key( uevent_buf, uevent_len, "DEVTYPE", &device_type_buf, &device_type_buf_len ); - if( rc != 0 ) { - - free( uevent_buf ); - return rc; - } - - *device_type = device_type_buf; - *device_type_len = device_type_buf_len; - - free( uevent_buf ); - - return 0; +int get_device_type(char const *sysfs_path, char **device_type, + size_t * device_type_len) +{ + + char uevent_path[4097]; + memset(uevent_path, 0, 4097); + + char *uevent_buf = NULL; + size_t uevent_len = 0; + + char *device_type_buf = NULL; + size_t device_type_buf_len = 0; + + int rc = 0; + + snprintf(uevent_path, 4096, "%s/uevent", sysfs_path); + + rc = vdev_read_file(uevent_path, &uevent_buf, &uevent_len); + if (rc != 0) { + + return rc; + } + + rc = vdev_sysfs_uevent_get_key(uevent_buf, uevent_len, "DEVTYPE", + &device_type_buf, &device_type_buf_len); + if (rc != 0) { + + free(uevent_buf); + return rc; + } + + *device_type = device_type_buf; + *device_type_len = device_type_buf_len; + + free(uevent_buf); + + return 0; } /* @@ -310,558 +320,637 @@ int get_device_type( char const* sysfs_path, char** device_type, size_t* device_ * 6.) If the device supplies a serial number, this number * is concatenated with the identification with an underscore '_'. */ -int main( int argc, char **argv) { - - int rc = 0; - char vendor_str[256]; - char vendor_str_enc[256]; - char vendor_id[256]; - char model_str[256]; - char model_str_enc[256]; - char product_id[256]; - char serial_str[256]; - char packed_if_str[256]; - char revision_str[256]; - char type_str[256]; - char instance_str[256]; - char driver[256]; - char ifnum[256]; - char serial[4096]; - char sysfs_base[8193]; // /sys/devices entry for this device - char path_tmp[8193]; - - bool confirm_usb = false; - - char* attr = NULL; // temporary buffer for pulling attrs out of sysfs - size_t attr_len = 0; - - int if_class_num; - int protocol = 0; - size_t l; - char *s; - char* devtype_str = NULL; - size_t devtype_strlen = 0; - - // interface information - char* if_device_path = NULL; - size_t if_device_path_len= 0; - - char* usb_device_path = NULL; - size_t usb_device_path_len = 0; - - char* ifnum_str = NULL; - size_t ifnum_strlen = 0; - - char* driver_str = NULL; - size_t driver_strlen = 0; - - char* if_class_str = NULL; - size_t if_class_strlen = 0; - - char* if_subclass_str = NULL; - size_t if_subclass_strlen = 0; - - memset( sysfs_base, 0, 8193 ); - memset( path_tmp, 0, 8193 ); - - memset( vendor_str, 0, 256 ); - memset( vendor_str_enc, 0, 256 ); - memset( vendor_id, 0, 256 ); - memset( model_str, 0, 256 ); - memset( model_str_enc, 0, 256 ); - memset( product_id, 0, 256 ); - memset( serial_str, 0, 256 ); - memset( packed_if_str, 0, 256 ); - memset( revision_str, 0, 256 ); - memset( type_str, 0, 256 ); - memset( instance_str, 0, 256 ); - memset( driver, 0, 256 ); - memset( ifnum, 0, 256 ); - memset( serial, 0, 4096 ); - - if( argc != 2 ) { - usage(argv[0] ); - } - - if( strlen(argv[1]) >= 4096 ) { - fprintf(stderr, "[ERROR] %s: Invalid /sys/devices path\n", argv[0]); - exit(3); - } - - strcpy( sysfs_base, argv[1] ); - - // find out what kind of device we are... - get_device_type( sysfs_base, &devtype_str, &devtype_strlen ); - - if( devtype_str != NULL && strcmp(devtype_str, "usb_device") == 0 ) { - - // we're a device, and can get the packed info right now - dev_if_packed_info( sysfs_base, packed_if_str, sizeof(packed_if_str) ); - - usb_device_path = strdup( sysfs_base ); - if( usb_device_path == NULL ) { - exit(4); - } - - usb_device_path_len = strlen(usb_device_path); - - goto fallback; - } - - // find USB parent - rc = vdev_sysfs_get_parent_with_subsystem_devtype( sysfs_base, "usb", "usb_interface", &if_device_path, &if_device_path_len ); - if( rc != 0 ) { - - fprintf(stderr, "[ERROR] %s: unable to access usb_interface device of '%s'\n", argv[0], sysfs_base ); - exit(1); - } - - // search *this* device instead - // get interface information - rc = vdev_sysfs_read_attr( if_device_path, "bInterfaceNumber", &ifnum_str, &ifnum_strlen ); - if( rc == 0 ) { - - vdev_util_rstrip( ifnum_str ); - - strncpy( ifnum, ifnum_str, (sizeof(ifnum) - 1 < ifnum_strlen ? sizeof(ifnum) - 1 : ifnum_strlen) ); - - free( ifnum_str ); - } - - rc = vdev_sysfs_read_attr( if_device_path, "driver", &driver_str, &driver_strlen ); - if( rc == 0 ) { - - vdev_util_rstrip( driver_str ); - - strncpy( driver, driver_str, (sizeof(driver) - 1 < driver_strlen ? sizeof(driver) - 1 : driver_strlen) ); - - free( driver_str ); - } - - rc = vdev_sysfs_read_attr( if_device_path, "bInterfaceClass", &if_class_str, &if_class_strlen ); - if( rc != 0 ) { - - if( devtype_str != NULL ) { - free( devtype_str ); - } - - fprintf(stderr, "[ERROR] %s: vdev_sysfs_read_attr('%s/%s') rc = %d\n", if_device_path, "bInterfaceClass", argv[0], rc ); - exit(1); - } - - // parse fields - if_class_num = strtoul( if_class_str, NULL, 16 ); - - free( if_class_str ); - - if( if_class_num == 8 ) { - // indicates mass storage device. - // check subclass - rc = vdev_sysfs_read_attr( if_device_path, "bInterfaceSubClass", &if_subclass_str, &if_subclass_strlen ); - if( rc == 0 ) { - - // got ourselves a type of storage device - protocol = set_usb_mass_storage_ifsubtype( type_str, if_subclass_str, sizeof(type_str) - 1 ); - } - else { - - // set type from interface instead - set_usb_iftype( type_str, if_class_num, sizeof(type_str) - 1 ); - } - - free( if_subclass_str ); - } - - // find the usb_device that is this interface's parent - rc = vdev_sysfs_get_parent_with_subsystem_devtype( if_device_path, "usb", "usb_device", &usb_device_path, &usb_device_path_len ); - if( rc != 0 ) { - - // couldn't find - if( devtype_str != NULL ) { - free( devtype_str ); - } - - fprintf( stderr, "[ERROR] %s: vdev_sysfs_get_parent_with_subsystem_devtype('%s', 'usb', 'usb_device') rc = %d\n", argv[0], sysfs_base, rc ); - - exit(1); - } - - // got the device path! - // get the device info - dev_if_packed_info( usb_device_path, packed_if_str, sizeof(packed_if_str) ); - - // is this a SCSI or ATAPI device? - if ((protocol == 6 || protocol == 2)) { - - char* dev_scsi_path = NULL; - size_t dev_scsi_path_len = 0; - - char* scsi_vendor_str = NULL; - size_t scsi_vendor_str_len = 0; - - char* scsi_model_str = NULL; - size_t scsi_model_str_len = 0; - - char* scsi_type_str = NULL; - size_t scsi_type_str_len = 0; - - char* scsi_rev_str = NULL; - size_t scsi_rev_str_len = 0; - - char* dev_scsi_sysname = NULL; - size_t dev_scsi_sysname_len = 0; - - int host = 0; - int bus = 0; - int target = 0; - int lun = 0; - - // scsi device? - rc = vdev_sysfs_get_parent_with_subsystem_devtype( sysfs_base, "scsi", "scsi_device", &dev_scsi_path, &dev_scsi_path_len ); - if( rc != 0 ) { - - // nope - log_error( "WARN: unable to find parent 'scsi' of '%s'", sysfs_base ); - goto fallback; - } - - rc = vdev_sysfs_get_sysname( dev_scsi_path, &dev_scsi_sysname, &dev_scsi_sysname_len ); - if( rc != 0 ) { - - // nope - free( dev_scsi_path ); - - log_error("WARN: vdev_sysfs_get_sysname('%s') rc = %d\n", dev_scsi_path, rc ); - goto fallback; - } - - // find host, bus, target, lun - rc = sscanf( dev_scsi_sysname, "%d:%d:%d:%d", &host, &bus, &target, &lun ); - if( rc != 4 ) { - - // nope - log_error( "WARN: unable to read host, bus, target, and/or lun from '%s'", dev_scsi_path ); - free( dev_scsi_path ); - free( dev_scsi_sysname ); - goto fallback; - } - - // see about vendor? - rc = vdev_sysfs_read_attr( dev_scsi_path, "vendor", &scsi_vendor_str, &scsi_vendor_str_len ); - if( rc != 0 ) { - - // nope - log_error("WARN: unable to read vendor string from '%s'", dev_scsi_path ); - free( dev_scsi_path ); - free( dev_scsi_sysname ); - goto fallback; - } - - vdev_util_rstrip( scsi_vendor_str ); - - vdev_util_encode_string( scsi_vendor_str, vendor_str_enc, sizeof(vendor_str_enc) ); - vdev_util_replace_whitespace( scsi_vendor_str, vendor_str, sizeof(vendor_str) - 1 ); - vdev_util_replace_chars( vendor_str, NULL ); - - free( scsi_vendor_str ); - - // see about model? - rc = vdev_sysfs_read_attr( dev_scsi_path, "model", &scsi_model_str, &scsi_model_str_len ); - if( rc != 0 ) { - - // nope - log_error("WARN: unable to read model from '%s'", dev_scsi_path ); - free( dev_scsi_path ); - free( dev_scsi_sysname ); - - goto fallback; - } - - vdev_util_rstrip( scsi_model_str ); - - vdev_util_encode_string( scsi_model_str, model_str_enc, sizeof(model_str_enc) ); - vdev_util_replace_whitespace( scsi_model_str, model_str, sizeof(model_str) - 1 ); - vdev_util_replace_chars( model_str, NULL ); - - free( scsi_model_str ); - - // see about type? - rc = vdev_sysfs_read_attr( dev_scsi_path, "type", &scsi_type_str, &scsi_type_str_len ); - if( rc != 0 ) { - - // nope - log_error("WARN: unable to read type from '%s'", dev_scsi_path ); - free( dev_scsi_path ); - free( dev_scsi_sysname ); - - goto fallback; - } - - set_scsi_type( type_str, scsi_type_str, sizeof(type_str) - 1 ); - - free( scsi_type_str ); - - // see about revision? - rc = vdev_sysfs_read_attr( dev_scsi_path, "rev", &scsi_rev_str, &scsi_rev_str_len ); - if( rc != 0 ) { - - // nope - log_error("WARN: unable to read revision from '%s'", dev_scsi_path ); - free( dev_scsi_path ); - free( dev_scsi_sysname ); - - goto fallback; - } - - vdev_util_replace_whitespace( scsi_rev_str, revision_str, sizeof(revision_str) - 1 ); - vdev_util_replace_chars( revision_str, NULL ); - - free( scsi_rev_str ); - - sprintf(instance_str, "%d:%d", target, lun ); - - free( dev_scsi_path ); - free( dev_scsi_sysname ); - } - -fallback: - - // not a device, and not an interface. - // fall back to querying vendor and model information - rc = vdev_sysfs_read_attr( usb_device_path, "idVendor", &attr, &attr_len ); - if( rc == 0 ) { - - strncpy( vendor_id, attr, (attr_len < sizeof(vendor_id)-1 ? attr_len : sizeof(vendor_id)-1) ); - vdev_util_rstrip( vendor_id ); - - free( attr ); - attr = NULL; - } - - rc = vdev_sysfs_read_attr( usb_device_path, "idProduct", &attr, &attr_len ); - if( rc == 0 ) { - - strncpy( product_id, attr, (attr_len < sizeof(product_id)-1 ? attr_len : sizeof(product_id)-1) ); - vdev_util_rstrip( product_id ); - - free( attr ); - attr = NULL; - } - - if( vendor_str[0] == 0 ) { - - // vendor not known yet. Try manufaturer, and fall back to idVendor if need be - char* manufacturer_str = NULL; - size_t manufacturer_strlen = 0; - - rc = vdev_sysfs_read_attr( usb_device_path, "manufacturer", &manufacturer_str, &manufacturer_strlen ); - if( rc != 0 ) { - - if( rc == -ENOENT ) { - - // fall back to idVendor - vdev_util_encode_string( vendor_id, vendor_str_enc, sizeof(vendor_str_enc) ); - vdev_util_replace_whitespace( vendor_id, vendor_str, sizeof(vendor_str)-1 ); - vdev_util_replace_chars( vendor_str, NULL ); - } - else { - - log_error("FATAL: vdev_sysfs_read_attr('%s/manufacturer') rc = %d\n", usb_device_path, rc ); - exit(1); - } - } - else { - - // success! - vdev_util_rstrip( manufacturer_str ); - - vdev_util_encode_string( manufacturer_str, vendor_str_enc, sizeof(vendor_str_enc) ); - vdev_util_replace_whitespace( manufacturer_str, vendor_str, sizeof(vendor_str)-1 ); - vdev_util_replace_chars( vendor_str, NULL ); - - free( manufacturer_str ); - manufacturer_str = NULL; - } - } - - if( model_str[0] == 0 ) { - - // model not known yet. Try product, and fall back to idProduct if we fail - char* product_str = NULL; - size_t product_strlen = 0; - - rc = vdev_sysfs_read_attr( usb_device_path, "product", &product_str, &product_strlen ); - if( rc != 0 ) { - - if( rc == -ENOENT ) { - - // fall back to idProduct - vdev_util_encode_string( product_id, model_str_enc, sizeof(model_str_enc) ); - vdev_util_replace_whitespace( product_id, vendor_str, sizeof(vendor_str) - 1 ); - vdev_util_replace_chars( vendor_str, NULL ); - } - else { - - log_error("FATAL: vdev_sysfs_read_attr('%s/product') rc = %d\n", usb_device_path, rc ); - exit(1); - } - } - else { - - // success! - vdev_util_rstrip( product_str ); - - vdev_util_encode_string( product_str, model_str_enc, sizeof(model_str_enc) ); - vdev_util_replace_whitespace( product_str, model_str, sizeof(model_str) - 1 ); - vdev_util_replace_chars( model_str, NULL ); - - free( product_str ); - product_str = NULL; - } - } - - if( revision_str[0] == 0 ) { - - // revision not known yet. maybe it's in bcdDevice? - rc = vdev_sysfs_read_attr( usb_device_path, "bcdDevice", &attr, &attr_len ); - if( rc == 0 ) { - - vdev_util_rstrip( attr ); - - vdev_util_replace_whitespace( attr, revision_str, sizeof(revision_str) - 1 ); - vdev_util_replace_chars( revision_str, NULL ); - - free( attr ); - attr = NULL; - } - } - - if( serial_str[0] == 0 ) { - - // serial number not known. Try 'serial' - rc = vdev_sysfs_read_attr( usb_device_path, "serial", &attr, &attr_len ); - if( rc == 0 ) { - - vdev_util_rstrip( attr ); - - const unsigned char *p = NULL; - bool valid = true; - - /* http://msdn.microsoft.com/en-us/library/windows/hardware/gg487321.aspx */ - for (p = (unsigned char *)attr; *p != '\0'; p++) { - if (*p < 0x20 || *p > 0x7f || *p == ',') { - valid = false; - break; - } - } - - if( valid ) { - vdev_util_replace_whitespace( attr, serial_str, sizeof(serial_str) - 1 ); - vdev_util_replace_chars( serial_str, NULL ); - } - - free( attr ); - attr = NULL; - } - } - - // serialize everything - s = serial; - sprintf( s, "%s_%s", vendor_str, model_str ); - l = strlen(s); - - if( serial_str[0] != 0 ) { - sprintf( s + l, "_%s", serial_str ); - l = strlen(s); - } - - if( instance_str[0] != 0 ) { - sprintf( s + l, "-%s", instance_str ); - l = strlen(s); - } - - if( vendor_str[0] != 0 ) { - vdev_property_add( "VDEV_USB_VENDOR", vendor_str ); - confirm_usb = true; - } - - if( vendor_str_enc[0] != 0 ) { - vdev_property_add( "VDEV_USB_VENDOR_ENC", vendor_str_enc ); - confirm_usb = true; - } - - if( vendor_id[0] != 0 ) { - vdev_property_add( "VDEV_USB_VENDOR_ID", vendor_id ); - confirm_usb = true; - } - - if( model_str[0] != 0 ) { - vdev_property_add( "VDEV_USB_MODEL", model_str ); - confirm_usb = true; - } - - if( model_str_enc[0] != 0 ) { - vdev_property_add( "VDEV_USB_MODEL_ENC", model_str_enc ); - confirm_usb = true; - } - - if( product_id[0] != 0 ) { - vdev_property_add( "VDEV_USB_MODEL_ID", product_id ); - confirm_usb = true; - } - - if( revision_str[0] != 0 ) { - vdev_property_add( "VDEV_USB_REVISION", revision_str ); - confirm_usb = true; - } - - if( strcmp(serial, "_") != 0 ) { - - // nonempty serial number - vdev_property_add( "VDEV_USB_SERIAL", serial ); - confirm_usb = true; - } - - if( serial_str[0] != 0 ) { - vdev_property_add( "VDEV_USB_SERIAL_SHORT", serial_str ); - confirm_usb = true; - } - - if( type_str[0] != 0 ) { - vdev_property_add( "VDEV_USB_TYPE", type_str ); - confirm_usb = true; - } - - if( instance_str[0] != 0 ) { - vdev_property_add( "VDEV_USB_INSTANCE", instance_str ); - confirm_usb = true; - } - - if( packed_if_str[0] != 0 ) { - vdev_property_add( "VDEV_USB_INTERFACES", packed_if_str ); - confirm_usb = true; - } - - if( ifnum[0] != 0 ) { - vdev_property_add( "VDEV_USB_INTERFACE_NUM", ifnum ); - confirm_usb = true; - } - - if( driver[0] != 0 ) { - vdev_property_add( "VDEV_USB_DRIVER", driver ); - confirm_usb = true; - } - - if( confirm_usb ) { - vdev_property_add( "VDEV_USB", "1" ); - } - - vdev_property_print(); - vdev_property_free_all(); - - if( devtype_str != NULL ) { - free( devtype_str ); - } - - return 0; +int main(int argc, char **argv) +{ + + int rc = 0; + char vendor_str[256]; + char vendor_str_enc[256]; + char vendor_id[256]; + char model_str[256]; + char model_str_enc[256]; + char product_id[256]; + char serial_str[256]; + char packed_if_str[256]; + char revision_str[256]; + char type_str[256]; + char instance_str[256]; + char driver[256]; + char ifnum[256]; + char serial[4096]; + char sysfs_base[8193]; // /sys/devices entry for this device + char path_tmp[8193]; + + bool confirm_usb = false; + + char *attr = NULL; // temporary buffer for pulling attrs out of sysfs + size_t attr_len = 0; + + int if_class_num; + int protocol = 0; + size_t l; + char *s; + char *devtype_str = NULL; + size_t devtype_strlen = 0; + + // interface information + char *if_device_path = NULL; + size_t if_device_path_len = 0; + + char *usb_device_path = NULL; + size_t usb_device_path_len = 0; + + char *ifnum_str = NULL; + size_t ifnum_strlen = 0; + + char *driver_str = NULL; + size_t driver_strlen = 0; + + char *if_class_str = NULL; + size_t if_class_strlen = 0; + + char *if_subclass_str = NULL; + size_t if_subclass_strlen = 0; + + memset(sysfs_base, 0, 8193); + memset(path_tmp, 0, 8193); + + memset(vendor_str, 0, 256); + memset(vendor_str_enc, 0, 256); + memset(vendor_id, 0, 256); + memset(model_str, 0, 256); + memset(model_str_enc, 0, 256); + memset(product_id, 0, 256); + memset(serial_str, 0, 256); + memset(packed_if_str, 0, 256); + memset(revision_str, 0, 256); + memset(type_str, 0, 256); + memset(instance_str, 0, 256); + memset(driver, 0, 256); + memset(ifnum, 0, 256); + memset(serial, 0, 4096); + + if (argc != 2) { + usage(argv[0]); + } + + if (strlen(argv[1]) >= 4096) { + fprintf(stderr, "[ERROR] %s: Invalid /sys/devices path\n", + argv[0]); + exit(3); + } + + strcpy(sysfs_base, argv[1]); + + // find out what kind of device we are... + get_device_type(sysfs_base, &devtype_str, &devtype_strlen); + + if (devtype_str != NULL && strcmp(devtype_str, "usb_device") == 0) { + + // we're a device, and can get the packed info right now + dev_if_packed_info(sysfs_base, packed_if_str, + sizeof(packed_if_str)); + + usb_device_path = strdup(sysfs_base); + if (usb_device_path == NULL) { + exit(4); + } + + usb_device_path_len = strlen(usb_device_path); + + goto fallback; + } + // find USB parent + rc = vdev_sysfs_get_parent_with_subsystem_devtype(sysfs_base, "usb", + "usb_interface", + &if_device_path, + &if_device_path_len); + if (rc != 0) { + + fprintf(stderr, + "[ERROR] %s: unable to access usb_interface device of '%s'\n", + argv[0], sysfs_base); + exit(1); + } + // search *this* device instead + // get interface information + rc = vdev_sysfs_read_attr(if_device_path, "bInterfaceNumber", + &ifnum_str, &ifnum_strlen); + if (rc == 0) { + + vdev_util_rstrip(ifnum_str); + + strncpy(ifnum, ifnum_str, + (sizeof(ifnum) - 1 < + ifnum_strlen ? sizeof(ifnum) - 1 : ifnum_strlen)); + + free(ifnum_str); + } + + rc = vdev_sysfs_read_attr(if_device_path, "driver", &driver_str, + &driver_strlen); + if (rc == 0) { + + vdev_util_rstrip(driver_str); + + strncpy(driver, driver_str, + (sizeof(driver) - 1 < + driver_strlen ? sizeof(driver) - 1 : driver_strlen)); + + free(driver_str); + } + + rc = vdev_sysfs_read_attr(if_device_path, "bInterfaceClass", + &if_class_str, &if_class_strlen); + if (rc != 0) { + + if (devtype_str != NULL) { + free(devtype_str); + } + + fprintf(stderr, + "[ERROR] %s: vdev_sysfs_read_attr('%s/%s') rc = %d\n", + if_device_path, "bInterfaceClass", argv[0], rc); + exit(1); + } + // parse fields + if_class_num = strtoul(if_class_str, NULL, 16); + + free(if_class_str); + + if (if_class_num == 8) { + // indicates mass storage device. + // check subclass + rc = vdev_sysfs_read_attr(if_device_path, "bInterfaceSubClass", + &if_subclass_str, + &if_subclass_strlen); + if (rc == 0) { + + // got ourselves a type of storage device + protocol = + set_usb_mass_storage_ifsubtype(type_str, + if_subclass_str, + sizeof(type_str) - + 1); + } else { + + // set type from interface instead + set_usb_iftype(type_str, if_class_num, + sizeof(type_str) - 1); + } + + free(if_subclass_str); + } + // find the usb_device that is this interface's parent + rc = vdev_sysfs_get_parent_with_subsystem_devtype(if_device_path, "usb", + "usb_device", + &usb_device_path, + &usb_device_path_len); + if (rc != 0) { + + // couldn't find + if (devtype_str != NULL) { + free(devtype_str); + } + + fprintf(stderr, + "[ERROR] %s: vdev_sysfs_get_parent_with_subsystem_devtype('%s', 'usb', 'usb_device') rc = %d\n", + argv[0], sysfs_base, rc); + + exit(1); + } + // got the device path! + // get the device info + dev_if_packed_info(usb_device_path, packed_if_str, + sizeof(packed_if_str)); + + // is this a SCSI or ATAPI device? + if ((protocol == 6 || protocol == 2)) { + + char *dev_scsi_path = NULL; + size_t dev_scsi_path_len = 0; + + char *scsi_vendor_str = NULL; + size_t scsi_vendor_str_len = 0; + + char *scsi_model_str = NULL; + size_t scsi_model_str_len = 0; + + char *scsi_type_str = NULL; + size_t scsi_type_str_len = 0; + + char *scsi_rev_str = NULL; + size_t scsi_rev_str_len = 0; + + char *dev_scsi_sysname = NULL; + size_t dev_scsi_sysname_len = 0; + + int host = 0; + int bus = 0; + int target = 0; + int lun = 0; + + // scsi device? + rc = vdev_sysfs_get_parent_with_subsystem_devtype(sysfs_base, + "scsi", + "scsi_device", + &dev_scsi_path, + &dev_scsi_path_len); + if (rc != 0) { + + // nope + log_error("WARN: unable to find parent 'scsi' of '%s'", + sysfs_base); + goto fallback; + } + + rc = vdev_sysfs_get_sysname(dev_scsi_path, &dev_scsi_sysname, + &dev_scsi_sysname_len); + if (rc != 0) { + + // nope + free(dev_scsi_path); + + log_error + ("WARN: vdev_sysfs_get_sysname('%s') rc = %d\n", + dev_scsi_path, rc); + goto fallback; + } + // find host, bus, target, lun + rc = sscanf(dev_scsi_sysname, "%d:%d:%d:%d", &host, &bus, + &target, &lun); + if (rc != 4) { + + // nope + log_error + ("WARN: unable to read host, bus, target, and/or lun from '%s'", + dev_scsi_path); + free(dev_scsi_path); + free(dev_scsi_sysname); + goto fallback; + } + // see about vendor? + rc = vdev_sysfs_read_attr(dev_scsi_path, "vendor", + &scsi_vendor_str, + &scsi_vendor_str_len); + if (rc != 0) { + + // nope + log_error + ("WARN: unable to read vendor string from '%s'", + dev_scsi_path); + free(dev_scsi_path); + free(dev_scsi_sysname); + goto fallback; + } + + vdev_util_rstrip(scsi_vendor_str); + + vdev_util_encode_string(scsi_vendor_str, vendor_str_enc, + sizeof(vendor_str_enc)); + vdev_util_replace_whitespace(scsi_vendor_str, vendor_str, + sizeof(vendor_str) - 1); + vdev_util_replace_chars(vendor_str, NULL); + + free(scsi_vendor_str); + + // see about model? + rc = vdev_sysfs_read_attr(dev_scsi_path, "model", + &scsi_model_str, &scsi_model_str_len); + if (rc != 0) { + + // nope + log_error("WARN: unable to read model from '%s'", + dev_scsi_path); + free(dev_scsi_path); + free(dev_scsi_sysname); + + goto fallback; + } + + vdev_util_rstrip(scsi_model_str); + + vdev_util_encode_string(scsi_model_str, model_str_enc, + sizeof(model_str_enc)); + vdev_util_replace_whitespace(scsi_model_str, model_str, + sizeof(model_str) - 1); + vdev_util_replace_chars(model_str, NULL); + + free(scsi_model_str); + + // see about type? + rc = vdev_sysfs_read_attr(dev_scsi_path, "type", &scsi_type_str, + &scsi_type_str_len); + if (rc != 0) { + + // nope + log_error("WARN: unable to read type from '%s'", + dev_scsi_path); + free(dev_scsi_path); + free(dev_scsi_sysname); + + goto fallback; + } + + set_scsi_type(type_str, scsi_type_str, sizeof(type_str) - 1); + + free(scsi_type_str); + + // see about revision? + rc = vdev_sysfs_read_attr(dev_scsi_path, "rev", &scsi_rev_str, + &scsi_rev_str_len); + if (rc != 0) { + + // nope + log_error("WARN: unable to read revision from '%s'", + dev_scsi_path); + free(dev_scsi_path); + free(dev_scsi_sysname); + + goto fallback; + } + + vdev_util_replace_whitespace(scsi_rev_str, revision_str, + sizeof(revision_str) - 1); + vdev_util_replace_chars(revision_str, NULL); + + free(scsi_rev_str); + + sprintf(instance_str, "%d:%d", target, lun); + + free(dev_scsi_path); + free(dev_scsi_sysname); + } + + fallback: + + // not a device, and not an interface. + // fall back to querying vendor and model information + rc = vdev_sysfs_read_attr(usb_device_path, "idVendor", &attr, + &attr_len); + if (rc == 0) { + + strncpy(vendor_id, attr, + (attr_len < + sizeof(vendor_id) - 1 ? attr_len : sizeof(vendor_id) - + 1)); + vdev_util_rstrip(vendor_id); + + free(attr); + attr = NULL; + } + + rc = vdev_sysfs_read_attr(usb_device_path, "idProduct", &attr, + &attr_len); + if (rc == 0) { + + strncpy(product_id, attr, + (attr_len < + sizeof(product_id) - + 1 ? attr_len : sizeof(product_id) - 1)); + vdev_util_rstrip(product_id); + + free(attr); + attr = NULL; + } + + if (vendor_str[0] == 0) { + + // vendor not known yet. Try manufaturer, and fall back to idVendor if need be + char *manufacturer_str = NULL; + size_t manufacturer_strlen = 0; + + rc = vdev_sysfs_read_attr(usb_device_path, "manufacturer", + &manufacturer_str, + &manufacturer_strlen); + if (rc != 0) { + + if (rc == -ENOENT) { + + // fall back to idVendor + vdev_util_encode_string(vendor_id, + vendor_str_enc, + sizeof(vendor_str_enc)); + vdev_util_replace_whitespace(vendor_id, + vendor_str, + sizeof(vendor_str) + - 1); + vdev_util_replace_chars(vendor_str, NULL); + } else { + + log_error + ("FATAL: vdev_sysfs_read_attr('%s/manufacturer') rc = %d\n", + usb_device_path, rc); + exit(1); + } + } else { + + // success! + vdev_util_rstrip(manufacturer_str); + + vdev_util_encode_string(manufacturer_str, + vendor_str_enc, + sizeof(vendor_str_enc)); + vdev_util_replace_whitespace(manufacturer_str, + vendor_str, + sizeof(vendor_str) - 1); + vdev_util_replace_chars(vendor_str, NULL); + + free(manufacturer_str); + manufacturer_str = NULL; + } + } + + if (model_str[0] == 0) { + + // model not known yet. Try product, and fall back to idProduct if we fail + char *product_str = NULL; + size_t product_strlen = 0; + + rc = vdev_sysfs_read_attr(usb_device_path, "product", + &product_str, &product_strlen); + if (rc != 0) { + + if (rc == -ENOENT) { + + // fall back to idProduct + vdev_util_encode_string(product_id, + model_str_enc, + sizeof(model_str_enc)); + vdev_util_replace_whitespace(product_id, + vendor_str, + sizeof(vendor_str) + - 1); + vdev_util_replace_chars(vendor_str, NULL); + } else { + + log_error + ("FATAL: vdev_sysfs_read_attr('%s/product') rc = %d\n", + usb_device_path, rc); + exit(1); + } + } else { + + // success! + vdev_util_rstrip(product_str); + + vdev_util_encode_string(product_str, model_str_enc, + sizeof(model_str_enc)); + vdev_util_replace_whitespace(product_str, model_str, + sizeof(model_str) - 1); + vdev_util_replace_chars(model_str, NULL); + + free(product_str); + product_str = NULL; + } + } + + if (revision_str[0] == 0) { + + // revision not known yet. maybe it's in bcdDevice? + rc = vdev_sysfs_read_attr(usb_device_path, "bcdDevice", &attr, + &attr_len); + if (rc == 0) { + + vdev_util_rstrip(attr); + + vdev_util_replace_whitespace(attr, revision_str, + sizeof(revision_str) - 1); + vdev_util_replace_chars(revision_str, NULL); + + free(attr); + attr = NULL; + } + } + + if (serial_str[0] == 0) { + + // serial number not known. Try 'serial' + rc = vdev_sysfs_read_attr(usb_device_path, "serial", &attr, + &attr_len); + if (rc == 0) { + + vdev_util_rstrip(attr); + + const unsigned char *p = NULL; + bool valid = true; + + /* http://msdn.microsoft.com/en-us/library/windows/hardware/gg487321.aspx */ + for (p = (unsigned char *)attr; *p != '\0'; p++) { + if (*p < 0x20 || *p > 0x7f || *p == ',') { + valid = false; + break; + } + } + + if (valid) { + vdev_util_replace_whitespace(attr, serial_str, + sizeof(serial_str) + - 1); + vdev_util_replace_chars(serial_str, NULL); + } + + free(attr); + attr = NULL; + } + } + // serialize everything + s = serial; + sprintf(s, "%s_%s", vendor_str, model_str); + l = strlen(s); + + if (serial_str[0] != 0) { + sprintf(s + l, "_%s", serial_str); + l = strlen(s); + } + + if (instance_str[0] != 0) { + sprintf(s + l, "-%s", instance_str); + l = strlen(s); + } + + if (vendor_str[0] != 0) { + vdev_property_add("VDEV_USB_VENDOR", vendor_str); + confirm_usb = true; + } + + if (vendor_str_enc[0] != 0) { + vdev_property_add("VDEV_USB_VENDOR_ENC", vendor_str_enc); + confirm_usb = true; + } + + if (vendor_id[0] != 0) { + vdev_property_add("VDEV_USB_VENDOR_ID", vendor_id); + confirm_usb = true; + } + + if (model_str[0] != 0) { + vdev_property_add("VDEV_USB_MODEL", model_str); + confirm_usb = true; + } + + if (model_str_enc[0] != 0) { + vdev_property_add("VDEV_USB_MODEL_ENC", model_str_enc); + confirm_usb = true; + } + + if (product_id[0] != 0) { + vdev_property_add("VDEV_USB_MODEL_ID", product_id); + confirm_usb = true; + } + + if (revision_str[0] != 0) { + vdev_property_add("VDEV_USB_REVISION", revision_str); + confirm_usb = true; + } + + if (strcmp(serial, "_") != 0) { + + // nonempty serial number + vdev_property_add("VDEV_USB_SERIAL", serial); + confirm_usb = true; + } + + if (serial_str[0] != 0) { + vdev_property_add("VDEV_USB_SERIAL_SHORT", serial_str); + confirm_usb = true; + } + + if (type_str[0] != 0) { + vdev_property_add("VDEV_USB_TYPE", type_str); + confirm_usb = true; + } + + if (instance_str[0] != 0) { + vdev_property_add("VDEV_USB_INSTANCE", instance_str); + confirm_usb = true; + } + + if (packed_if_str[0] != 0) { + vdev_property_add("VDEV_USB_INTERFACES", packed_if_str); + confirm_usb = true; + } + + if (ifnum[0] != 0) { + vdev_property_add("VDEV_USB_INTERFACE_NUM", ifnum); + confirm_usb = true; + } + + if (driver[0] != 0) { + vdev_property_add("VDEV_USB_DRIVER", driver); + confirm_usb = true; + } + + if (confirm_usb) { + vdev_property_add("VDEV_USB", "1"); + } + + vdev_property_print(); + vdev_property_free_all(); + + if (devtype_str != NULL) { + free(devtype_str); + } + + return 0; } diff --git a/vdevd/helpers/LINUX/stat_v4l.c b/vdevd/helpers/LINUX/stat_v4l.c index 607c201..23024b5 100644 --- a/vdevd/helpers/LINUX/stat_v4l.c +++ b/vdevd/helpers/LINUX/stat_v4l.c @@ -39,89 +39,89 @@ #include "common.h" -int main(int argc, char *argv[]) { - static const struct option options[] = { - { "help", no_argument, NULL, 'h' }, - {} - }; - - int fd = 0; - char *device; - struct v4l2_capability v2cap; - char cap_str[4097]; - - memset( cap_str, 0, 4097 ); - - for (;;) { - int option; - - option = getopt_long(argc, argv, "h", options, NULL); - if (option == -1) { - break; - } - - switch (option) { - case 'h': - printf("%s [-h,--help] \n\n" - "Video4Linux device identification.\n\n" - " -h Print this message\n" - , argv[0]); - return 0; - default: - return 1; - } - } - - device = argv[optind]; - - if (device == NULL) { - return 2; - } - - fd = open(device, O_RDONLY); - if (fd < 0) { - return 3; - } - - if (ioctl(fd, VIDIOC_QUERYCAP, &v2cap) == 0) { - - vdev_property_add("VDEV_V4L_VERSION", "2"); - vdev_property_add("VDEV_V4L_PRODUCT", (char*)v2cap.card ); - - strcat( cap_str, ":" ); - - if ((v2cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) > 0) { - - strcat( cap_str, "capture:" ); - } - if ((v2cap.capabilities & V4L2_CAP_VIDEO_OUTPUT) > 0) { - - strcat( cap_str, "video_output:" ); - } - if ((v2cap.capabilities & V4L2_CAP_VIDEO_OVERLAY) > 0) { - - strcat( cap_str, "video_overlay:" ); - } - if ((v2cap.capabilities & V4L2_CAP_AUDIO) > 0) { - - strcat( cap_str, "audio:" ); - } - if ((v2cap.capabilities & V4L2_CAP_TUNER) > 0) { - - strcat( cap_str, "tuner:" ); - } - if ((v2cap.capabilities & V4L2_CAP_RADIO) > 0) { - - strcat( cap_str, "radio:" ); - } - - vdev_property_add( "VDEV_V4L_CAPABILITIES", cap_str ); - } - - close( fd ); - - vdev_property_print(); - vdev_property_free_all(); - - return 0; +int main(int argc, char *argv[]) +{ + static const struct option options[] = { + {"help", no_argument, NULL, 'h'}, + {} + }; + + int fd = 0; + char *device; + struct v4l2_capability v2cap; + char cap_str[4097]; + + memset(cap_str, 0, 4097); + + for (;;) { + int option; + + option = getopt_long(argc, argv, "h", options, NULL); + if (option == -1) { + break; + } + + switch (option) { + case 'h': + printf("%s [-h,--help] \n\n" + "Video4Linux device identification.\n\n" + " -h Print this message\n", argv[0]); + return 0; + default: + return 1; + } + } + + device = argv[optind]; + + if (device == NULL) { + return 2; + } + + fd = open(device, O_RDONLY); + if (fd < 0) { + return 3; + } + + if (ioctl(fd, VIDIOC_QUERYCAP, &v2cap) == 0) { + + vdev_property_add("VDEV_V4L_VERSION", "2"); + vdev_property_add("VDEV_V4L_PRODUCT", (char *)v2cap.card); + + strcat(cap_str, ":"); + + if ((v2cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) > 0) { + + strcat(cap_str, "capture:"); + } + if ((v2cap.capabilities & V4L2_CAP_VIDEO_OUTPUT) > 0) { + + strcat(cap_str, "video_output:"); + } + if ((v2cap.capabilities & V4L2_CAP_VIDEO_OVERLAY) > 0) { + + strcat(cap_str, "video_overlay:"); + } + if ((v2cap.capabilities & V4L2_CAP_AUDIO) > 0) { + + strcat(cap_str, "audio:"); + } + if ((v2cap.capabilities & V4L2_CAP_TUNER) > 0) { + + strcat(cap_str, "tuner:"); + } + if ((v2cap.capabilities & V4L2_CAP_RADIO) > 0) { + + strcat(cap_str, "radio:"); + } + + vdev_property_add("VDEV_V4L_CAPABILITIES", cap_str); + } + + close(fd); + + vdev_property_print(); + vdev_property_free_all(); + + return 0; } diff --git a/vdevd/main.c b/vdevd/main.c index fe7316a..3517abd 100644 --- a/vdevd/main.c +++ b/vdevd/main.c @@ -25,232 +25,255 @@ static struct vdev_state vdev; // reload handler -void vdev_reload_sighup(int ignored) +void +vdev_reload_sighup (int ignored) { - vdev_reload(&vdev); + vdev_reload (&vdev); } // run! -int main(int argc, char **argv) +int +main (int argc, char **argv) { - int rc = 0; - int coldplug_quiesce_pipe[2]; - bool is_child = false; - bool is_parent = false; - ssize_t nr = 0; + int rc = 0; + int coldplug_quiesce_pipe[2]; + bool is_child = false; + bool is_parent = false; + ssize_t nr = 0; - int coldplug_finished_fd = -1; // FD to write to once we finish flushing the initial device requests + int coldplug_finished_fd = -1; // FD to write to once we finish flushing the initial device requests - memset(&vdev, 0, sizeof(struct vdev_state)); + memset (&vdev, 0, sizeof (struct vdev_state)); - // ignore SIGPIPE from daemonlets - signal(SIGPIPE, SIG_IGN); + // ignore SIGPIPE from daemonlets + signal (SIGPIPE, SIG_IGN); - // set up global vdev state - rc = vdev_init(&vdev, argc, argv); - // help called from command line -h or --help (-2) - // short circuit with log/debug support - if (vdev.config->help) { - if (rc == -2) { + // set up global vdev state + rc = vdev_init (&vdev, argc, argv); + // help called from command line -h or --help (-2) + // short circuit with log/debug support + if (vdev.config->help) + { + if (rc == -2) + { - vdev_debug("%s", - "exiting: help called at command line\n"); - // the shutdown and clean up should be redundant ? - exit(0); - } + vdev_debug ("%s", "exiting: help called at command line\n"); + // the shutdown and clean up should be redundant ? + exit (0); } + } - if (rc != 0) { - - vdev_error("vdev_init rc = %d\n", rc); + if (rc != 0) + { - vdev_shutdown(&vdev, false); - exit(1); - } - // run the preseed command - rc = vdev_preseed_run(&vdev); - if (rc != 0) { + vdev_error ("vdev_init rc = %d\n", rc); - vdev_error("vdev_preseed_run rc = %d\n", rc); + vdev_shutdown (&vdev, false); + exit (1); + } + // run the preseed command + rc = vdev_preseed_run (&vdev); + if (rc != 0) + { - vdev_shutdown(&vdev, false); - exit(1); - } - // if we're going to daemonize, then redirect logging to the logfile - if (!vdev.config->foreground) { + vdev_error ("vdev_preseed_run rc = %d\n", rc); - // sanity check - if (vdev.config->logfile_path == NULL) { + vdev_shutdown (&vdev, false); + exit (1); + } + // if we're going to daemonize, then redirect logging to the logfile + if (!vdev.config->foreground) + { - fprintf(stderr, "No logfile specified\n"); + // sanity check + if (vdev.config->logfile_path == NULL) + { - vdev_shutdown(&vdev, false); - exit(2); - } - // do we need to connect to syslog? - if (strcmp(vdev.config->logfile_path, "syslog") == 0) { + fprintf (stderr, "No logfile specified\n"); - vdev_debug("%s", "Switching to syslog for messages\n"); - vdev_enable_syslog(); - } + vdev_shutdown (&vdev, false); + exit (2); + } + // do we need to connect to syslog? + if (strcmp (vdev.config->logfile_path, "syslog") == 0) + { - else { + vdev_debug ("%s", "Switching to syslog for messages\n"); + vdev_enable_syslog (); + } - // send to a specific logfile - rc = vdev_log_redirect(vdev.config->logfile_path); - if (rc != 0) { + else + { - vdev_error("vdev_log_redirect('%s') rc = %d\n", - vdev.config->logfile_path, rc); + // send to a specific logfile + rc = vdev_log_redirect (vdev.config->logfile_path); + if (rc != 0) + { - vdev_shutdown(&vdev, false); - exit(2); - } - } + vdev_error ("vdev_log_redirect('%s') rc = %d\n", + vdev.config->logfile_path, rc); - if (!vdev.config->coldplug_only) { - - // will become a daemon after handling coldplug. - // set up a pipe between parent and child, so the child can - // signal the parent when it's device queue has been emptied - // (meaning the parent can safely exit). + vdev_shutdown (&vdev, false); + exit (2); + } + } - rc = pipe(coldplug_quiesce_pipe); - if (rc != 0) { + if (!vdev.config->coldplug_only) + { - vdev_error("pipe rc = %d\n", rc); - vdev_shutdown(&vdev, false); + // will become a daemon after handling coldplug. + // set up a pipe between parent and child, so the child can + // signal the parent when it's device queue has been emptied + // (meaning the parent can safely exit). - exit(3); - } - // become a daemon - rc = vdev_daemonize(); - if (rc < 0) { + rc = pipe (coldplug_quiesce_pipe); + if (rc != 0) + { - vdev_error("vdev_daemonize rc = %d\n", rc); - vdev_shutdown(&vdev, false); + vdev_error ("pipe rc = %d\n", rc); + vdev_shutdown (&vdev, false); - exit(3); - } + exit (3); + } + // become a daemon + rc = vdev_daemonize (); + if (rc < 0) + { - if (rc == 0) { + vdev_error ("vdev_daemonize rc = %d\n", rc); + vdev_shutdown (&vdev, false); - // child - close(coldplug_quiesce_pipe[0]); - coldplug_finished_fd = coldplug_quiesce_pipe[1]; + exit (3); + } - // write a pidfile - if (vdev.config->pidfile_path != NULL) { + if (rc == 0) + { - rc = vdev_pidfile_write(vdev. - config->pidfile_path); - if (rc != 0) { + // child + close (coldplug_quiesce_pipe[0]); + coldplug_finished_fd = coldplug_quiesce_pipe[1]; - vdev_error - ("vdev_pidfile_write('%s') rc = %d\n", - vdev.config->pidfile_path, - rc); + // write a pidfile + if (vdev.config->pidfile_path != NULL) + { - vdev_shutdown(&vdev, false); - exit(4); - } - } - // set reload handler - signal(SIGHUP, vdev_reload_sighup); + rc = vdev_pidfile_write (vdev.config->pidfile_path); + if (rc != 0) + { - is_child = true; - } else { + vdev_error + ("vdev_pidfile_write('%s') rc = %d\n", + vdev.config->pidfile_path, rc); - // parent - is_parent = true; - close(coldplug_quiesce_pipe[1]); - } + vdev_shutdown (&vdev, false); + exit (4); + } } + // set reload handler + signal (SIGHUP, vdev_reload_sighup); + + is_child = true; + } + else + { + + // parent + is_parent = true; + close (coldplug_quiesce_pipe[1]); + } } + } - if (!is_parent || vdev.config->foreground || vdev.config->coldplug_only) { + if (!is_parent || vdev.config->foreground || vdev.config->coldplug_only) + { - // child, or foreground, or coldplug only. start handling (coldplug) device events - rc = vdev_start(&vdev); - if (rc != 0) { + // child, or foreground, or coldplug only. start handling (coldplug) device events + rc = vdev_start (&vdev); + if (rc != 0) + { - vdev_error("vdev_backend_init rc = %d\n", rc); + vdev_error ("vdev_backend_init rc = %d\n", rc); - vdev_stop(&vdev); - vdev_shutdown(&vdev, false); + vdev_stop (&vdev); + vdev_shutdown (&vdev, false); - // if child, and we're connected to the parent, then tell the parent to exit failure - if (is_child && !vdev.config->foreground - && !vdev.config->coldplug_only) { + // if child, and we're connected to the parent, then tell the parent to exit failure + if (is_child && !vdev.config->foreground + && !vdev.config->coldplug_only) + { - write(coldplug_quiesce_pipe[1], &rc, - sizeof(rc)); - close(coldplug_quiesce_pipe[1]); - } + write (coldplug_quiesce_pipe[1], &rc, sizeof (rc)); + close (coldplug_quiesce_pipe[1]); + } - exit(5); - } - // main loop: get events from the OS and process them. - // wake up the parent once we finish the coldplugged devices - rc = vdev_main(&vdev, coldplug_finished_fd); - if (rc != 0) { + exit (5); + } + // main loop: get events from the OS and process them. + // wake up the parent once we finish the coldplugged devices + rc = vdev_main (&vdev, coldplug_finished_fd); + if (rc != 0) + { - vdev_error("vdev_main rc = %d\n", rc); - } - // if only doing coldplug, find and remove all stale coldplug devices. - // use the metadata directory to figure this out - if (vdev.config->coldplug_only) { + vdev_error ("vdev_main rc = %d\n", rc); + } + // if only doing coldplug, find and remove all stale coldplug devices. + // use the metadata directory to figure this out + if (vdev.config->coldplug_only) + { - rc = vdev_remove_unplugged_devices(&vdev); - if (rc != 0) { + rc = vdev_remove_unplugged_devices (&vdev); + if (rc != 0) + { - vdev_error - ("vdev_remove_unplugged_devices() rc = %d\n", - rc); - } - } - // quiesce requests - vdev_stop(&vdev); + vdev_error ("vdev_remove_unplugged_devices() rc = %d\n", rc); + } + } + // quiesce requests + vdev_stop (&vdev); - // print benchmarks... - vdev_debug("%s", "Action benchmarks:\n"); - for (unsigned int i = 0; i < vdev.num_acts; i++) { + // print benchmarks... + vdev_debug ("%s", "Action benchmarks:\n"); + for (unsigned int i = 0; i < vdev.num_acts; i++) + { - vdev_action_log_benchmarks(&vdev.acts[i]); - } + vdev_action_log_benchmarks (&vdev.acts[i]); + } - // clean up - // keep the pidfile unless we're doing coldplug only (in which case don't touch it) - vdev_shutdown(&vdev, !vdev.config->coldplug_only); + // clean up + // keep the pidfile unless we're doing coldplug only (in which case don't touch it) + vdev_shutdown (&vdev, !vdev.config->coldplug_only); - return rc; - } else { + return rc; + } + else + { - // parent process--wait for the child to finish processing the coldplugged devices, and exit. - nr = read(coldplug_quiesce_pipe[0], &rc, sizeof(rc)); + // parent process--wait for the child to finish processing the coldplugged devices, and exit. + nr = read (coldplug_quiesce_pipe[0], &rc, sizeof (rc)); - if (nr < 0 || rc != 0) { + if (nr < 0 || rc != 0) + { - if (nr < 0) { + if (nr < 0) + { - vdev_error("read(%d) rc = %zd\n", - coldplug_quiesce_pipe[0], nr); - } + vdev_error ("read(%d) rc = %zd\n", + coldplug_quiesce_pipe[0], nr); + } - vdev_error("device quiesce failure, child rc = %d\n", - rc); - exit(6); - } + vdev_error ("device quiesce failure, child rc = %d\n", rc); + exit (6); + } - printf("parent: all initial devices processed\n"); + printf ("parent: all initial devices processed\n"); - // clean up, but keep the pidfile - vdev_shutdown(&vdev, false); + // clean up, but keep the pidfile + vdev_shutdown (&vdev, false); - close(coldplug_quiesce_pipe[0]); + close (coldplug_quiesce_pipe[0]); - return 0; - } + return 0; + } } diff --git a/vdevd/os/common.c b/vdevd/os/common.c index 0e19722..9beb753 100644 --- a/vdevd/os/common.c +++ b/vdevd/os/common.c @@ -25,142 +25,146 @@ #include "methods.h" // yield new devices -int vdev_os_main( struct vdev_os_context* vos ) { - - int rc = 0; - - while( vos->running ) { - - // make a device request - struct vdev_device_request* vreq = VDEV_CALLOC( struct vdev_device_request, 1 ); - - if( vreq == NULL ) { - // OOM - break; - } - - // next device request - rc = vdev_device_request_init( vreq, vos->state, VDEV_DEVICE_INVALID, NULL ); - if( rc != 0 ) { - - if( rc == -EAGAIN ) { - continue; - } - - free( vreq ); - - vdev_error("vdev_device_request_init rc = %d\n", rc ); - break; - } - - // yield the next device - rc = vdev_os_next_device( vreq, vos->os_cls ); - if( rc != 0 ) { - - vdev_device_request_free( vreq ); - free( vreq ); - - if( rc < 0 ) { - vdev_error("vdev_os_next_device rc = %d\n", rc ); - - if( rc == -EAGAIN ) { - - // OS backend says try again - continue; - } - else { - - // fatal error - break; - } - } - else { - - // exit on success - rc = 0; - break; - } - } - - vdev_debug("Next device: %p, type=%d path=%s major=%u minor=%u mode=%o\n", vreq, vreq->type, vreq->path, major(vreq->dev), minor(vreq->dev), vreq->mode ); - - /* - struct sglib_vdev_params_iterator itr2; - struct vdev_param_t* dp2 = NULL; - - printf("vreq %p: params:\n", vreq); - for( dp2 = sglib_vdev_params_it_init_inorder( &itr2, vreq->params ); dp2 != NULL; dp2 = sglib_vdev_params_it_next( &itr2 ) ) { - - printf(" '%s' == '%s'\n", dp2->key, dp2->value ); - } - */ - - // post the event to the device work queue - rc = vdev_device_request_enqueue( &vos->state->device_wq, vreq ); - - if( rc != 0 ) { - - vdev_device_request_free( vreq ); - free( vreq ); - - vdev_error("vdev_device_request_add rc = %d\n", rc ); - - continue; - } - } - - return rc; +int vdev_os_main(struct vdev_os_context *vos) +{ + + int rc = 0; + + while (vos->running) { + + // make a device request + struct vdev_device_request *vreq = + VDEV_CALLOC(struct vdev_device_request, 1); + + if (vreq == NULL) { + // OOM + break; + } + // next device request + rc = vdev_device_request_init(vreq, vos->state, + VDEV_DEVICE_INVALID, NULL); + if (rc != 0) { + + if (rc == -EAGAIN) { + continue; + } + + free(vreq); + + vdev_error("vdev_device_request_init rc = %d\n", rc); + break; + } + // yield the next device + rc = vdev_os_next_device(vreq, vos->os_cls); + if (rc != 0) { + + vdev_device_request_free(vreq); + free(vreq); + + if (rc < 0) { + vdev_error("vdev_os_next_device rc = %d\n", rc); + + if (rc == -EAGAIN) { + + // OS backend says try again + continue; + } else { + + // fatal error + break; + } + } else { + + // exit on success + rc = 0; + break; + } + } + + vdev_debug + ("Next device: %p, type=%d path=%s major=%u minor=%u mode=%o\n", + vreq, vreq->type, vreq->path, major(vreq->dev), + minor(vreq->dev), vreq->mode); + + /* + struct sglib_vdev_params_iterator itr2; + struct vdev_param_t* dp2 = NULL; + + printf("vreq %p: params:\n", vreq); + for( dp2 = sglib_vdev_params_it_init_inorder( &itr2, vreq->params ); dp2 != NULL; dp2 = sglib_vdev_params_it_next( &itr2 ) ) { + + printf(" '%s' == '%s'\n", dp2->key, dp2->value ); + } + */ + + // post the event to the device work queue + rc = vdev_device_request_enqueue(&vos->state->device_wq, vreq); + + if (rc != 0) { + + vdev_device_request_free(vreq); + free(vreq); + + vdev_error("vdev_device_request_add rc = %d\n", rc); + + continue; + } + } + + return rc; } // set up a vdev os context // NOTE: not reload-safe -int vdev_os_context_init( struct vdev_os_context* vos, struct vdev_state* state ) { - - int rc = 0; - - memset( vos, 0, sizeof(struct vdev_os_context) ); - - vos->state = state; - vos->coldplug_only = state->coldplug_only; - - // set up OS state - rc = vdev_os_init( vos, &vos->os_cls ); - if( rc != 0 ) { - - vdev_error("vdev_os_init rc = %d\n", rc ); - memset( vos, 0, sizeof(struct vdev_os_context) ); - return rc; - } - - vos->running = true; - - return 0; -} +int vdev_os_context_init(struct vdev_os_context *vos, struct vdev_state *state) +{ + int rc = 0; -// free memory -int vdev_os_context_free( struct vdev_os_context* vos ) { - - if( vos != NULL ) { - vdev_os_shutdown( vos->os_cls ); - vos->os_cls = NULL; - - memset( vos, 0, sizeof(struct vdev_os_context) ); - } - - return 0; + memset(vos, 0, sizeof(struct vdev_os_context)); + + vos->state = state; + vos->coldplug_only = state->coldplug_only; + + // set up OS state + rc = vdev_os_init(vos, &vos->os_cls); + if (rc != 0) { + + vdev_error("vdev_os_init rc = %d\n", rc); + memset(vos, 0, sizeof(struct vdev_os_context)); + return rc; + } + + vos->running = true; + + return 0; } +// free memory +int vdev_os_context_free(struct vdev_os_context *vos) +{ + + if (vos != NULL) { + vdev_os_shutdown(vos->os_cls); + vos->os_cls = NULL; + + memset(vos, 0, sizeof(struct vdev_os_context)); + } + + return 0; +} // backend signal to vdevd that it has processed all coldplugged devices -int vdev_os_context_signal_coldplug_finished( struct vdev_os_context* vos ) { - - vos->coldplug_finished = true; - return 0; +int vdev_os_context_signal_coldplug_finished(struct vdev_os_context *vos) +{ + + vos->coldplug_finished = true; + return 0; } // wait for coldplug to finish -bool vdev_os_context_is_coldplug_finished( struct vdev_os_context* vos ) { - - return vos->coldplug_finished; +bool vdev_os_context_is_coldplug_finished(struct vdev_os_context * vos) +{ + + return vos->coldplug_finished; } diff --git a/vdevd/os/common.h b/vdevd/os/common.h index 59a3587..5e0661a 100644 --- a/vdevd/os/common.h +++ b/vdevd/os/common.h @@ -26,31 +26,29 @@ // connection to the OS's device notification system struct vdev_os_context { - - void* os_cls; // OS-specific data - - bool running; - - bool coldplug_only; - bool coldplug_finished; - - // reference to global state - // ACCESS WITH CAUTION--ENSURE RELOAD SAFETY - struct vdev_state* state; + + void *os_cls; // OS-specific data + + bool running; + + bool coldplug_only; + bool coldplug_finished; + + // reference to global state + // ACCESS WITH CAUTION--ENSURE RELOAD SAFETY + struct vdev_state *state; }; C_LINKAGE_BEGIN - // context management -int vdev_os_context_init( struct vdev_os_context* vos, struct vdev_state* state ); -int vdev_os_context_free( struct vdev_os_context* vos ); +int vdev_os_context_init(struct vdev_os_context *vos, struct vdev_state *state); +int vdev_os_context_free(struct vdev_os_context *vos); // signaling from the back-end to vdevd -int vdev_os_context_signal_coldplug_finished( struct vdev_os_context* vos ); -bool vdev_os_context_is_coldplug_finished( struct vdev_os_context* vos ); +int vdev_os_context_signal_coldplug_finished(struct vdev_os_context *vos); +bool vdev_os_context_is_coldplug_finished(struct vdev_os_context *vos); -int vdev_os_main( struct vdev_os_context* vos ); +int vdev_os_main(struct vdev_os_context *vos); C_LINKAGE_END - -#endif +#endif diff --git a/vdevd/os/linux.c b/vdevd/os/linux.c index 2446e0b..32ed56e 100644 --- a/vdevd/os/linux.c +++ b/vdevd/os/linux.c @@ -26,175 +26,188 @@ #include "libvdev/sglib.h" // parse a uevent action -static vdev_device_request_t vdev_linux_parse_device_request_type( char const* type ) { - - if( strcmp(type, "add") == 0 ) { - return VDEV_DEVICE_ADD; - } - else if( strcmp(type, "remove") == 0 ) { - return VDEV_DEVICE_REMOVE; - } - else if( strcmp(type, "change") == 0 ) { - return VDEV_DEVICE_CHANGE; - } - - return VDEV_DEVICE_INVALID; -} +static vdev_device_request_t vdev_linux_parse_device_request_type(char const + *type) +{ + + if (strcmp(type, "add") == 0) { + return VDEV_DEVICE_ADD; + } else if (strcmp(type, "remove") == 0) { + return VDEV_DEVICE_REMOVE; + } else if (strcmp(type, "change") == 0) { + return VDEV_DEVICE_CHANGE; + } + return VDEV_DEVICE_INVALID; +} // make the full sysfs path from the dev path, plus an additional path // return NULL on OOM -static char* vdev_linux_sysfs_fullpath( char const* sysfs_mountpoint, char const* devpath, char const* attr_path ) { - - char* tmp = NULL; - char* ret = NULL; - - tmp = vdev_fullpath( sysfs_mountpoint, devpath, NULL ); - if( tmp == NULL ) { - return NULL; - } - - ret = vdev_fullpath( tmp, attr_path, NULL ); - free( tmp ); - - return ret; -} +static char *vdev_linux_sysfs_fullpath(char const *sysfs_mountpoint, + char const *devpath, + char const *attr_path) +{ + + char *tmp = NULL; + char *ret = NULL; + + tmp = vdev_fullpath(sysfs_mountpoint, devpath, NULL); + if (tmp == NULL) { + return NULL; + } + ret = vdev_fullpath(tmp, attr_path, NULL); + free(tmp); + + return ret; +} // parse a device number pair // return 0 on success, and set *major and *minor // return -EINVAL if we failed to parse -static int vdev_linux_sysfs_parse_device_nums( char const* devbuf, unsigned int* major, unsigned int* minor ) { - - int rc = 0; - - // parse devpath - rc = sscanf( devbuf, "%u:%u", major, minor ); - - if( rc != 2 ) { - - vdev_error("sscanf('%s') for major:minor rc = %d\n", devbuf, rc ); - rc = -EINVAL; - } - else { - rc = 0; - } - - return rc; +static int vdev_linux_sysfs_parse_device_nums(char const *devbuf, + unsigned int *major, + unsigned int *minor) +{ + + int rc = 0; + + // parse devpath + rc = sscanf(devbuf, "%u:%u", major, minor); + + if (rc != 2) { + + vdev_error("sscanf('%s') for major:minor rc = %d\n", devbuf, + rc); + rc = -EINVAL; + } else { + rc = 0; + } + + return rc; } // read the device major and minor number, using the devpath // return 0 on success, and set *major and *minor // return -ENOMEM on OOM // return -errno on failure to open or read -static int vdev_linux_sysfs_read_dev_nums( struct vdev_linux_context* ctx, char const* devpath, unsigned int* major, unsigned int* minor ) { - - int rc = 0; - int fd = 0; - ssize_t nr = 0; - char devbuf[101]; - - memset( devbuf, 0, 101 ); - - char* full_devpath = vdev_linux_sysfs_fullpath( ctx->sysfs_mountpoint, devpath, "dev" ); - if( full_devpath == NULL ) { - return -ENOMEM; - } - - // open device path - fd = open( full_devpath, O_RDONLY ); - if( fd < 0 ) { - - rc = -errno; - - if( rc != -ENOENT ) { - vdev_error("open('%s') rc = %d\n", full_devpath, rc ); - } - - free( full_devpath ); - return rc; - } - - nr = vdev_read_uninterrupted( fd, devbuf, 100 ); - if( nr < 0 ) { - - rc = nr; - vdev_error("read('%s') rc = %d\n", full_devpath, rc ); - - free( full_devpath ); - close( fd ); - return rc; - } - - close( fd ); - free( full_devpath ); - - rc = vdev_linux_sysfs_parse_device_nums( devbuf, major, minor ); - - if( rc != 0 ) { - - vdev_error("Failed to parse '%s'\n", devbuf ); - rc = -EIO; - } - - return rc; +static int vdev_linux_sysfs_read_dev_nums(struct vdev_linux_context *ctx, + char const *devpath, + unsigned int *major, + unsigned int *minor) +{ + + int rc = 0; + int fd = 0; + ssize_t nr = 0; + char devbuf[101]; + + memset(devbuf, 0, 101); + + char *full_devpath = + vdev_linux_sysfs_fullpath(ctx->sysfs_mountpoint, devpath, "dev"); + if (full_devpath == NULL) { + return -ENOMEM; + } + // open device path + fd = open(full_devpath, O_RDONLY); + if (fd < 0) { + + rc = -errno; + + if (rc != -ENOENT) { + vdev_error("open('%s') rc = %d\n", full_devpath, rc); + } + + free(full_devpath); + return rc; + } + + nr = vdev_read_uninterrupted(fd, devbuf, 100); + if (nr < 0) { + + rc = nr; + vdev_error("read('%s') rc = %d\n", full_devpath, rc); + + free(full_devpath); + close(fd); + return rc; + } + + close(fd); + free(full_devpath); + + rc = vdev_linux_sysfs_parse_device_nums(devbuf, major, minor); + + if (rc != 0) { + + vdev_error("Failed to parse '%s'\n", devbuf); + rc = -EIO; + } + + return rc; } // read the kernel-given device subsystem from sysfs // return 0 on success, and set *subsystem // return -ENOMEM on OOM // return negative on readlink failure -static int vdev_linux_sysfs_read_subsystem( struct vdev_linux_context* ctx, char const* devpath, char** subsystem ) { - - int rc = 0; - char linkpath[PATH_MAX+1]; - size_t linkpath_len = PATH_MAX; - char* subsystem_path = NULL; - - memset( linkpath, 0, PATH_MAX+1 ); - - subsystem_path = vdev_linux_sysfs_fullpath( ctx->sysfs_mountpoint, devpath, "subsystem" ); - if( subsystem_path == NULL ) { - return -ENOMEM; - } - - rc = readlink( subsystem_path, linkpath, linkpath_len ); - if( rc < 0 ) { - - rc = -errno; - vdev_error("readlink('%s') rc = %d\n", subsystem_path, rc ); - free( subsystem_path ); - return rc; - } - - free( subsystem_path ); - - *subsystem = vdev_basename( linkpath, NULL ); - if( *subsystem == NULL ) { - - return -ENOMEM; - } - - return 0; -} +static int vdev_linux_sysfs_read_subsystem(struct vdev_linux_context *ctx, + char const *devpath, + char **subsystem) +{ + + int rc = 0; + char linkpath[PATH_MAX + 1]; + size_t linkpath_len = PATH_MAX; + char *subsystem_path = NULL; + + memset(linkpath, 0, PATH_MAX + 1); + subsystem_path = + vdev_linux_sysfs_fullpath(ctx->sysfs_mountpoint, devpath, + "subsystem"); + if (subsystem_path == NULL) { + return -ENOMEM; + } + + rc = readlink(subsystem_path, linkpath, linkpath_len); + if (rc < 0) { + + rc = -errno; + vdev_error("readlink('%s') rc = %d\n", subsystem_path, rc); + free(subsystem_path); + return rc; + } + + free(subsystem_path); + + *subsystem = vdev_basename(linkpath, NULL); + if (*subsystem == NULL) { + + return -ENOMEM; + } + + return 0; +} // print a uevent, either with debugging or error loglevels -static int vdev_linux_log_uevent( char const* uevent_buf, size_t uevent_buf_len, bool debug ) { - - for( unsigned int i = 0; i < uevent_buf_len; ) { - - if( debug ) { - vdev_debug("uevent '%s'\n", uevent_buf + i ); - } - else { - vdev_error("uevent '%s'\n", uevent_buf + i ); - } - - i += strlen(uevent_buf + i) + 1; - } - - return 0; +static int vdev_linux_log_uevent(char const *uevent_buf, size_t uevent_buf_len, + bool debug) +{ + + for (unsigned int i = 0; i < uevent_buf_len;) { + + if (debug) { + vdev_debug("uevent '%s'\n", uevent_buf + i); + } else { + vdev_error("uevent '%s'\n", uevent_buf + i); + } + + i += strlen(uevent_buf + i) + 1; + } + + return 0; } #define vdev_linux_debug_uevent( uevent_buf, uevent_buf_len ) vdev_linux_log_uevent( uevent_buf, uevent_buf_len, true ) @@ -203,420 +216,419 @@ static int vdev_linux_log_uevent( char const* uevent_buf, size_t uevent_buf_len, // parse a uevent, and use the information to fill in a device request. // nlbuf must be a contiguous concatenation of null-terminated KEY=VALUE strings. // return 0 on success -static int vdev_linux_parse_request( struct vdev_linux_context* ctx, struct vdev_device_request* vreq, char* nlbuf, ssize_t buflen ) { - - char* buf = nlbuf; - char* key = NULL; - char* value = NULL; - int offset = 0; - int rc = 0; - unsigned int major = 0; - unsigned int minor = 0; - bool have_major = false; - bool have_minor = false; - mode_t dev_mode = 0; - int line_count = 0; - bool not_param = false; // if set to true, add as an OS-specific parameter to the vreq - - char* devpath = NULL; // sysfs devpath - char* subsystem = NULL; // sysfs subsystem - char* devname = (char*)VDEV_DEVICE_PATH_UNKNOWN; // DEVNAME from uevent - - vdev_device_request_t reqtype = VDEV_DEVICE_INVALID; - - vdev_debug("%p: uevent buffer\n", vreq ); - vdev_linux_debug_uevent( nlbuf, buflen ); - - // sanity check: if the first line is $action@$devpath, then skip it (since the information - // contained in the uevent will encode the very same bits of information) - if( strchr(buf, '@') != NULL ) { - - // advance to the next line - offset += strlen(buf) + 1; - } - - // get key/value pairs - while( offset < buflen ) { - - line_count++; - not_param = false; - - rc = vdev_keyvalue_next( buf + offset, &key, &value ); - - if( rc < 0 ) { - - vdev_error("Invalid line %d (byte %d): '%s'\n", line_count, offset, buf + offset ); - vdev_linux_error_uevent( nlbuf, buflen ); - - return -EINVAL; - } - - offset += rc + 1; // count the \0 at the end - rc = 0; - - // is this the action to take? - if( strcmp(key, "ACTION") == 0 ) { - - reqtype = vdev_linux_parse_device_request_type( value ); - - if( reqtype == VDEV_DEVICE_INVALID ) { - - vdev_error("Invalid ACTION '%s'\n", value ); - vdev_linux_error_uevent( nlbuf, buflen ); - - return -EINVAL; - } - - vdev_device_request_set_type( vreq, reqtype ); - - not_param = true; - } - - // is this the sysfs device path? - else if( strcmp(key, "DEVPATH") == 0 ) { - - devpath = value; - } - - // is this the devname? - else if( strcmp(key, "DEVNAME") == 0 ) { - - devname = value; - } - - // subsystem given? - else if( strcmp(key, "SUBSYSTEM") == 0 ) { - - subsystem = vdev_strdup_or_null( value ); - } - - // is this the major device number? - else if( strcmp(key, "MAJOR") == 0 && !have_major ) { - - char* tmp = NULL; - major = (int)strtol( value, &tmp, 10 ); - - if( *tmp != '\0' ) { - - vdev_error("Invalid 'MAJOR' value '%s'\n", value); - vdev_linux_error_uevent( nlbuf, buflen ); - - return -EINVAL; - } - - have_major = true; - not_param = true; - } - - // is this the minor device number? - else if( strcmp(key, "MINOR") == 0 && !have_minor ) { - - char* tmp = NULL; - minor = (int)strtol( value, &tmp, 10 ) ; - - if( *tmp != '\0' ) { - - vdev_error("Invalid 'MINOR' value '%s'\n", value ); - vdev_linux_error_uevent( nlbuf, buflen ); - - return -EINVAL; - } - - have_minor = true; - not_param = true; - } - - if( !not_param ) { - - // add to OS params - rc = vdev_device_request_add_param( vreq, key, value ); - if( rc != 0 ) { - - // could be OOM - if( subsystem != NULL ) { - free( subsystem ); - } - - return rc; - } - } - } - - if( reqtype == VDEV_DEVICE_INVALID ) { - - vdev_error("%s", "No ACTION given\n"); - vdev_linux_error_uevent( nlbuf, buflen ); - - if( subsystem != NULL ) { - free( subsystem ); - } - - return -EINVAL; - } - - if( (!have_major && have_minor) || (have_major && !have_minor) ) { - - vdev_error("Missing device information: major=%d, minor=%d\n", have_major, have_minor ); - vdev_linux_error_uevent( nlbuf, buflen ); - - if( subsystem != NULL ) { - free( subsystem ); - } - - return -EINVAL; - } - - if( have_major && have_minor ) { - - // explicit major and minor device numbers given - vdev_device_request_set_dev( vreq, makedev(major, minor) ); - } - - if( devname != NULL ) { - - // use this as the device's path - vdev_device_request_set_path( vreq, devname ); - } - - if( devpath != NULL ) { - - // get any remaining information from sysfs - // check major/minor? - if( !have_major || !have_minor ) { - - // see if we have major/minor device numbers for this device... - rc = vdev_linux_sysfs_read_dev_nums( ctx, devpath, &major, &minor ); - - if( rc == 0 ) { - - // yup! - vdev_device_request_set_dev( vreq, makedev(major, minor) ); - - have_major = true; - have_minor = true; - } - else { - - // it's okay to not have dev numbers - rc = 0; - } - } - - // subsystem? - if( subsystem == NULL ) { - - // see if we have a subsystem - rc = vdev_linux_sysfs_read_subsystem( ctx, devpath, &subsystem ); - - if( rc == 0 ) { - - // yup! - rc = vdev_device_request_add_param( vreq, "SUBSYSTEM", subsystem ); - if( rc != 0 ) { - - // OOM - free( subsystem ); - return rc; - } - } - else if( rc != -ENOMEM ) { - - // this is weird... - vdev_warn("no subsystem found for '%s'\n", devpath ); - rc = 0; - } - } - } - - if( have_major && have_minor ) { - - if( subsystem != NULL && strcasecmp(subsystem, "block") == 0 ) { - - // this is a block - dev_mode = S_IFBLK; - } - - else { - - // this is a character device--we have major/minor numbers - dev_mode = S_IFCHR; - } - - vdev_device_request_set_mode( vreq, dev_mode ); - } - - vdev_debug("subsystem = '%s', have_major=%d, major = %u, have_minor=%d, minor = %u, mode = %o\n", subsystem, have_major, major, have_minor, minor, dev_mode ); - - if( subsystem != NULL ) { - free( subsystem ); - } - - // tell helpers where /sys is mounted - rc = vdev_device_request_add_param( vreq, "SYSFS_MOUNTPOINT", ctx->sysfs_mountpoint ); - if( rc != 0 ) { - - // OOM - return rc; - } - - return rc; -} +static int vdev_linux_parse_request(struct vdev_linux_context *ctx, + struct vdev_device_request *vreq, + char *nlbuf, ssize_t buflen) +{ + + char *buf = nlbuf; + char *key = NULL; + char *value = NULL; + int offset = 0; + int rc = 0; + unsigned int major = 0; + unsigned int minor = 0; + bool have_major = false; + bool have_minor = false; + mode_t dev_mode = 0; + int line_count = 0; + bool not_param = false; // if set to true, add as an OS-specific parameter to the vreq + + char *devpath = NULL; // sysfs devpath + char *subsystem = NULL; // sysfs subsystem + char *devname = (char *)VDEV_DEVICE_PATH_UNKNOWN; // DEVNAME from uevent + + vdev_device_request_t reqtype = VDEV_DEVICE_INVALID; + + vdev_debug("%p: uevent buffer\n", vreq); + vdev_linux_debug_uevent(nlbuf, buflen); + + // sanity check: if the first line is $action@$devpath, then skip it (since the information + // contained in the uevent will encode the very same bits of information) + if (strchr(buf, '@') != NULL) { + + // advance to the next line + offset += strlen(buf) + 1; + } + // get key/value pairs + while (offset < buflen) { + + line_count++; + not_param = false; + + rc = vdev_keyvalue_next(buf + offset, &key, &value); + + if (rc < 0) { + + vdev_error("Invalid line %d (byte %d): '%s'\n", + line_count, offset, buf + offset); + vdev_linux_error_uevent(nlbuf, buflen); + + return -EINVAL; + } + + offset += rc + 1; // count the \0 at the end + rc = 0; + + // is this the action to take? + if (strcmp(key, "ACTION") == 0) { + + reqtype = vdev_linux_parse_device_request_type(value); + + if (reqtype == VDEV_DEVICE_INVALID) { + + vdev_error("Invalid ACTION '%s'\n", value); + vdev_linux_error_uevent(nlbuf, buflen); + + return -EINVAL; + } + + vdev_device_request_set_type(vreq, reqtype); + + not_param = true; + } + // is this the sysfs device path? + else if (strcmp(key, "DEVPATH") == 0) { + + devpath = value; + } + // is this the devname? + else if (strcmp(key, "DEVNAME") == 0) { + + devname = value; + } + // subsystem given? + else if (strcmp(key, "SUBSYSTEM") == 0) { + + subsystem = vdev_strdup_or_null(value); + } + // is this the major device number? + else if (strcmp(key, "MAJOR") == 0 && !have_major) { + + char *tmp = NULL; + major = (int)strtol(value, &tmp, 10); + + if (*tmp != '\0') { + + vdev_error("Invalid 'MAJOR' value '%s'\n", + value); + vdev_linux_error_uevent(nlbuf, buflen); + + return -EINVAL; + } + + have_major = true; + not_param = true; + } + // is this the minor device number? + else if (strcmp(key, "MINOR") == 0 && !have_minor) { + + char *tmp = NULL; + minor = (int)strtol(value, &tmp, 10); + + if (*tmp != '\0') { + + vdev_error("Invalid 'MINOR' value '%s'\n", + value); + vdev_linux_error_uevent(nlbuf, buflen); + + return -EINVAL; + } + + have_minor = true; + not_param = true; + } + + if (!not_param) { + + // add to OS params + rc = vdev_device_request_add_param(vreq, key, value); + if (rc != 0) { + + // could be OOM + if (subsystem != NULL) { + free(subsystem); + } + + return rc; + } + } + } + + if (reqtype == VDEV_DEVICE_INVALID) { + + vdev_error("%s", "No ACTION given\n"); + vdev_linux_error_uevent(nlbuf, buflen); + + if (subsystem != NULL) { + free(subsystem); + } + + return -EINVAL; + } + + if ((!have_major && have_minor) || (have_major && !have_minor)) { + + vdev_error("Missing device information: major=%d, minor=%d\n", + have_major, have_minor); + vdev_linux_error_uevent(nlbuf, buflen); + + if (subsystem != NULL) { + free(subsystem); + } + + return -EINVAL; + } + + if (have_major && have_minor) { + + // explicit major and minor device numbers given + vdev_device_request_set_dev(vreq, makedev(major, minor)); + } + + if (devname != NULL) { + + // use this as the device's path + vdev_device_request_set_path(vreq, devname); + } + + if (devpath != NULL) { + + // get any remaining information from sysfs + // check major/minor? + if (!have_major || !have_minor) { + + // see if we have major/minor device numbers for this device... + rc = vdev_linux_sysfs_read_dev_nums(ctx, devpath, + &major, &minor); + + if (rc == 0) { + // yup! + vdev_device_request_set_dev(vreq, + makedev(major, + minor)); + + have_major = true; + have_minor = true; + } else { + + // it's okay to not have dev numbers + rc = 0; + } + } + // subsystem? + if (subsystem == NULL) { + + // see if we have a subsystem + rc = vdev_linux_sysfs_read_subsystem(ctx, devpath, + &subsystem); + + if (rc == 0) { + + // yup! + rc = vdev_device_request_add_param(vreq, + "SUBSYSTEM", + subsystem); + if (rc != 0) { + + // OOM + free(subsystem); + return rc; + } + } else if (rc != -ENOMEM) { + + // this is weird... + vdev_warn("no subsystem found for '%s'\n", + devpath); + rc = 0; + } + } + } + + if (have_major && have_minor) { + + if (subsystem != NULL && strcasecmp(subsystem, "block") == 0) { + + // this is a block + dev_mode = S_IFBLK; + } + + else { + + // this is a character device--we have major/minor numbers + dev_mode = S_IFCHR; + } + + vdev_device_request_set_mode(vreq, dev_mode); + } + + vdev_debug + ("subsystem = '%s', have_major=%d, major = %u, have_minor=%d, minor = %u, mode = %o\n", + subsystem, have_major, major, have_minor, minor, dev_mode); + + if (subsystem != NULL) { + free(subsystem); + } + // tell helpers where /sys is mounted + rc = vdev_device_request_add_param(vreq, "SYSFS_MOUNTPOINT", + ctx->sysfs_mountpoint); + if (rc != 0) { + + // OOM + return rc; + } + + return rc; +} // yield the next device event // return 0 on success // return 1 if there are no more devices // return -EAGAIN if vdev should try to get this device again // return -errno on failure to poll for devices or read the next device packet. -int vdev_os_next_device( struct vdev_device_request* vreq, void* cls ) { - - int rc = 0; - struct vdev_linux_context* ctx = (struct vdev_linux_context*)cls; - char buf[VDEV_LINUX_NETLINK_BUF_MAX]; - ssize_t len = 0; - - char cbuf[CMSG_SPACE(sizeof(struct ucred))]; - struct cmsghdr *chdr = NULL; - struct ucred *cred = NULL; - struct msghdr hdr; - struct iovec iov; - struct sockaddr_nl cnls; - - pthread_mutex_lock( &ctx->initial_requests_lock ); - - // do we have initial requests? - if( ctx->initial_requests != NULL ) { - - // next request - struct vdev_device_request* req = ctx->initial_requests; - - // consume - ctx->initial_requests = ctx->initial_requests->next; - - memcpy( vreq, req, sizeof(struct vdev_device_request) ); - free( req ); - - pthread_mutex_unlock( &ctx->initial_requests_lock ); - - // was that the last of them? - if( ctx->initial_requests == NULL ) { - - // tell vdevd that we've finished coldplug processing - vdev_os_context_signal_coldplug_finished( ctx->os_ctx ); - } - - return 0; - } - else if( ctx->os_ctx->coldplug_only ) { - - // out of coldplug requests; die - pthread_mutex_unlock( &ctx->initial_requests_lock ); - return 1; - } - else { - - pthread_mutex_unlock( &ctx->initial_requests_lock ); - } - - memset(&hdr, 0, sizeof(struct msghdr)); - - // next event (wait forever) - // NOTE: this is a cancellation point! - rc = poll( &ctx->pfd, 1, -1 ); - - if( rc < 0 ) { - - rc = -errno; - - if( rc == -EINTR ) { - // try again - return -EAGAIN; - } - - vdev_error("FATAL: poll(%d) rc = %d\n", ctx->pfd.fd, rc ); - - return rc; - } - - // get the event - iov.iov_base = buf; - iov.iov_len = VDEV_LINUX_NETLINK_BUF_MAX; - - hdr.msg_iov = &iov; - hdr.msg_iovlen = 1; - - // get control-plane messages - hdr.msg_control = cbuf; - hdr.msg_controllen = sizeof(cbuf); - - hdr.msg_name = &cnls; - hdr.msg_namelen = sizeof(cnls); - - // get the event - len = recvmsg( ctx->pfd.fd, &hdr, 0 ); - if( len < 0 ) { - - rc = -errno; - vdev_error("FATAL: recvmsg(%d) rc = %d\n", ctx->pfd.fd, rc ); - - return rc; - } - - // big enough? - if( len < 32 || len >= VDEV_LINUX_NETLINK_BUF_MAX ) { - - vdev_error("Netlink message is %zd bytes; ignoring...\n", len ); - return -EAGAIN; - } - - // control message, for credentials - chdr = CMSG_FIRSTHDR( &hdr ); - if( chdr == NULL || chdr->cmsg_type != SCM_CREDENTIALS ) { - - vdev_error("%s", "Netlink message has no credentials\n"); - return -EAGAIN; - } - - // get the credentials - cred = (struct ucred *)CMSG_DATA(chdr); - - // if not root, ignore - if( cred->uid != 0 ) { - - vdev_error("Ignoring message from non-root ID %d\n", cred->uid ); - return -EAGAIN; - } - - // if udev, ignore - if( memcmp( buf, VDEV_LINUX_NETLINK_UDEV_HEADER, VDEV_LINUX_NETLINK_UDEV_HEADER_LEN ) == 0 ) { - - // message from udev; ignore - vdev_warn("%s", "Ignoring libudev message\n"); - return -EAGAIN; - } - - // kernel messages don't come from userspace - if( cnls.nl_pid > 0 ) { - - // from userspace??? - vdev_warn("Ignoring message from PID %d\n", (int)cnls.nl_pid ); - return -EAGAIN; - } - - // parse the event buffer - vdev_debug("%p from netlink\n", vreq ); - rc = vdev_linux_parse_request( ctx, vreq, buf, len ); - - if( rc != 0 ) { - - vdev_error("vdev_linux_parse_request rc = %d\n", rc ); - - return -EAGAIN; - } - - return 0; -} +int vdev_os_next_device(struct vdev_device_request *vreq, void *cls) +{ + + int rc = 0; + struct vdev_linux_context *ctx = (struct vdev_linux_context *)cls; + char buf[VDEV_LINUX_NETLINK_BUF_MAX]; + ssize_t len = 0; + + char cbuf[CMSG_SPACE(sizeof(struct ucred))]; + struct cmsghdr *chdr = NULL; + struct ucred *cred = NULL; + struct msghdr hdr; + struct iovec iov; + struct sockaddr_nl cnls; + + pthread_mutex_lock(&ctx->initial_requests_lock); + + // do we have initial requests? + if (ctx->initial_requests != NULL) { + + // next request + struct vdev_device_request *req = ctx->initial_requests; + + // consume + ctx->initial_requests = ctx->initial_requests->next; + + memcpy(vreq, req, sizeof(struct vdev_device_request)); + free(req); + + pthread_mutex_unlock(&ctx->initial_requests_lock); + + // was that the last of them? + if (ctx->initial_requests == NULL) { + + // tell vdevd that we've finished coldplug processing + vdev_os_context_signal_coldplug_finished(ctx->os_ctx); + } + + return 0; + } else if (ctx->os_ctx->coldplug_only) { + + // out of coldplug requests; die + pthread_mutex_unlock(&ctx->initial_requests_lock); + return 1; + } else { + + pthread_mutex_unlock(&ctx->initial_requests_lock); + } + + memset(&hdr, 0, sizeof(struct msghdr)); + + // next event (wait forever) + // NOTE: this is a cancellation point! + rc = poll(&ctx->pfd, 1, -1); + + if (rc < 0) { + + rc = -errno; + + if (rc == -EINTR) { + // try again + return -EAGAIN; + } + + vdev_error("FATAL: poll(%d) rc = %d\n", ctx->pfd.fd, rc); + + return rc; + } + // get the event + iov.iov_base = buf; + iov.iov_len = VDEV_LINUX_NETLINK_BUF_MAX; + + hdr.msg_iov = &iov; + hdr.msg_iovlen = 1; + + // get control-plane messages + hdr.msg_control = cbuf; + hdr.msg_controllen = sizeof(cbuf); + + hdr.msg_name = &cnls; + hdr.msg_namelen = sizeof(cnls); + + // get the event + len = recvmsg(ctx->pfd.fd, &hdr, 0); + if (len < 0) { + + rc = -errno; + vdev_error("FATAL: recvmsg(%d) rc = %d\n", ctx->pfd.fd, rc); + + return rc; + } + // big enough? + if (len < 32 || len >= VDEV_LINUX_NETLINK_BUF_MAX) { + + vdev_error("Netlink message is %zd bytes; ignoring...\n", len); + return -EAGAIN; + } + // control message, for credentials + chdr = CMSG_FIRSTHDR(&hdr); + if (chdr == NULL || chdr->cmsg_type != SCM_CREDENTIALS) { + + vdev_error("%s", "Netlink message has no credentials\n"); + return -EAGAIN; + } + // get the credentials + cred = (struct ucred *)CMSG_DATA(chdr); + // if not root, ignore + if (cred->uid != 0) { + + vdev_error("Ignoring message from non-root ID %d\n", cred->uid); + return -EAGAIN; + } + // if udev, ignore + if (memcmp + (buf, VDEV_LINUX_NETLINK_UDEV_HEADER, + VDEV_LINUX_NETLINK_UDEV_HEADER_LEN) == 0) { + + // message from udev; ignore + vdev_warn("%s", "Ignoring libudev message\n"); + return -EAGAIN; + } + // kernel messages don't come from userspace + if (cnls.nl_pid > 0) { + + // from userspace??? + vdev_warn("Ignoring message from PID %d\n", (int)cnls.nl_pid); + return -EAGAIN; + } + // parse the event buffer + vdev_debug("%p from netlink\n", vreq); + rc = vdev_linux_parse_request(ctx, vreq, buf, len); + + if (rc != 0) { + + vdev_error("vdev_linux_parse_request rc = %d\n", rc); + + return -EAGAIN; + } + + return 0; +} // find sysfs mountpoint in /proc/mounts // this is apparently superfluous (it *should* be mounted at /sys), but you never know. @@ -626,56 +638,60 @@ int vdev_os_next_device( struct vdev_device_request* vreq, void* cls ) { // return -ENOMEM if the buffer isn't big enough // return -EINVAL if somehow we failed to parse a mount entry // return negative for some other errors (like access permission failures, or /proc not mounted) -static int vdev_linux_find_sysfs_mountpoint( char* mountpoint, size_t mountpoint_len ) { - - FILE* f = NULL; - int rc = 0; - - char mntbuf[4096]; - struct mntent ment_buf; - struct mntent* ment_ptr = NULL; - int ent_count = 1; - bool found = false; - - f = fopen( "/proc/mounts", "r" ); - if( f == NULL ) { - - rc = -errno; - fprintf(stderr, "Failed to open /proc/mounts, rc = %d\n", rc ); - return rc; - } - - // scan for sysfs mount type - while( 1 ) { - - ment_ptr = getmntent_r( f, &ment_buf, mntbuf, 4096 ); - if( ment_ptr == NULL ) { - - vdev_error("Failed on processing entry #%d of /proc/mounts\n", ent_count ); - rc = -EINVAL; - break; - } - - if( strcmp( ment_ptr->mnt_type, "sysfs" ) == 0 ) { - - // found! - strncpy( mountpoint, ment_ptr->mnt_dir, mountpoint_len - 1 ); - found = true; - rc = 0; - break; - } - - ent_count++; - } - - fclose( f ); - - if( rc == 0 && !found ) { - fprintf(stderr, "Failed to find mounted sysfs filesystem\n"); - return -ENOSYS; - } - - return rc; +static int vdev_linux_find_sysfs_mountpoint(char *mountpoint, + size_t mountpoint_len) +{ + + FILE *f = NULL; + int rc = 0; + + char mntbuf[4096]; + struct mntent ment_buf; + struct mntent *ment_ptr = NULL; + int ent_count = 1; + bool found = false; + + f = fopen("/proc/mounts", "r"); + if (f == NULL) { + + rc = -errno; + fprintf(stderr, "Failed to open /proc/mounts, rc = %d\n", rc); + return rc; + } + // scan for sysfs mount type + while (1) { + + ment_ptr = getmntent_r(f, &ment_buf, mntbuf, 4096); + if (ment_ptr == NULL) { + + vdev_error + ("Failed on processing entry #%d of /proc/mounts\n", + ent_count); + rc = -EINVAL; + break; + } + + if (strcmp(ment_ptr->mnt_type, "sysfs") == 0) { + + // found! + strncpy(mountpoint, ment_ptr->mnt_dir, + mountpoint_len - 1); + found = true; + rc = 0; + break; + } + + ent_count++; + } + + fclose(f); + + if (rc == 0 && !found) { + fprintf(stderr, "Failed to find mounted sysfs filesystem\n"); + return -ENOSYS; + } + + return rc; } // get a uevent from a uevent file @@ -684,114 +700,121 @@ static int vdev_linux_find_sysfs_mountpoint( char* mountpoint, size_t mountpoint // return 0 on success // return -ENOMEM on OOM // return -errno on failure to stat or read -static int vdev_linux_sysfs_read_uevent( char const* fp_uevent, char** ret_uevent_buf, size_t* ret_uevent_len ) { - - int rc = 0; - struct stat sb; - char* uevent_buf = NULL; - size_t uevent_buf_len = 0; - size_t uevent_len = 0; - - // get uevent size - rc = stat( fp_uevent, &sb ); - if( rc != 0 ) { - - rc = -errno; - - vdev_error("stat('%s') rc = %d\n", fp_uevent, rc ); - - return rc; - } - else { - - uevent_buf_len = sb.st_size; - } - - // read the uevent - if( fp_uevent != NULL ) { - - uevent_buf = VDEV_CALLOC( char, uevent_buf_len ); - if( uevent_buf == NULL ) { - - return -ENOMEM; - } - - rc = vdev_read_file( fp_uevent, uevent_buf, uevent_buf_len ); - if( rc != 0 ) { - - // failed in this - vdev_error("vdev_read_file('%s') rc = %d\n", fp_uevent, rc ); - free( uevent_buf ); - } - else { - - for( unsigned int i = 0; i < uevent_buf_len; i++ ) { - - if( uevent_buf[i] == '\n' ) { - - uevent_buf[i] = '\0'; - } - } - - // NOTE: the stat size is an upper-bound. Find the exact number of bytes. - for( uevent_len = 0; uevent_len < uevent_buf_len; ) { - - if( *(uevent_buf + uevent_len) == '\0' ) { - break; - } - - uevent_len += strlen( uevent_buf + uevent_len ) + 1; - } - - *ret_uevent_buf = uevent_buf; - *ret_uevent_len = uevent_len; - } - } - - return rc; -} +static int vdev_linux_sysfs_read_uevent(char const *fp_uevent, + char **ret_uevent_buf, + size_t * ret_uevent_len) +{ + + int rc = 0; + struct stat sb; + char *uevent_buf = NULL; + size_t uevent_buf_len = 0; + size_t uevent_len = 0; + + // get uevent size + rc = stat(fp_uevent, &sb); + if (rc != 0) { + + rc = -errno; + vdev_error("stat('%s') rc = %d\n", fp_uevent, rc); + + return rc; + } else { + + uevent_buf_len = sb.st_size; + } + + // read the uevent + if (fp_uevent != NULL) { + + uevent_buf = VDEV_CALLOC(char, uevent_buf_len); + if (uevent_buf == NULL) { + + return -ENOMEM; + } + + rc = vdev_read_file(fp_uevent, uevent_buf, uevent_buf_len); + if (rc != 0) { + + // failed in this + vdev_error("vdev_read_file('%s') rc = %d\n", fp_uevent, + rc); + free(uevent_buf); + } else { + + for (unsigned int i = 0; i < uevent_buf_len; i++) { + + if (uevent_buf[i] == '\n') { + + uevent_buf[i] = '\0'; + } + } + + // NOTE: the stat size is an upper-bound. Find the exact number of bytes. + for (uevent_len = 0; uevent_len < uevent_buf_len;) { + + if (*(uevent_buf + uevent_len) == '\0') { + break; + } + + uevent_len += + strlen(uevent_buf + uevent_len) + 1; + } + + *ret_uevent_buf = uevent_buf; + *ret_uevent_len = uevent_len; + } + } + + return rc; +} // append a key/value pair to a uevent buffer // return 0 on success // return -ENOMEM on OOM -static int vdev_linux_uevent_append( char** ret_uevent_buf, size_t* ret_uevent_buf_len, char const* key, char const* value ) { - - char* tmp = NULL; - char* uevent_buf = *ret_uevent_buf; - size_t uevent_buf_len = *ret_uevent_buf_len; - - // add it to the uevent buffer, so we can parse it like a normal uevent - tmp = (char*)realloc( uevent_buf, uevent_buf_len + 1 + strlen(key) + 1 + strlen(value) + 1 ); - if( tmp == NULL ) { - - return -ENOMEM; - } - - uevent_buf = tmp; - - // add key - memcpy( uevent_buf + uevent_buf_len, key, strlen(key) ); - uevent_buf_len += strlen(key); - - // add '=' - *(uevent_buf + uevent_buf_len) = '='; - uevent_buf_len ++; - - // add value - memcpy( uevent_buf + uevent_buf_len, value, strlen(value) ); - uevent_buf_len += strlen(value); - - // NULL-terminate - *(uevent_buf + uevent_buf_len) = '\0'; - uevent_buf_len ++; - - *ret_uevent_buf = uevent_buf; - *ret_uevent_buf_len = uevent_buf_len; - - return 0; -} +static int vdev_linux_uevent_append(char **ret_uevent_buf, + size_t * ret_uevent_buf_len, + char const *key, char const *value) +{ + + char *tmp = NULL; + char *uevent_buf = *ret_uevent_buf; + size_t uevent_buf_len = *ret_uevent_buf_len; + + // add it to the uevent buffer, so we can parse it like a normal uevent + tmp = + (char *)realloc(uevent_buf, + uevent_buf_len + 1 + strlen(key) + 1 + + strlen(value) + 1); + if (tmp == NULL) { + + return -ENOMEM; + } + + uevent_buf = tmp; + + // add key + memcpy(uevent_buf + uevent_buf_len, key, strlen(key)); + uevent_buf_len += strlen(key); + + // add '=' + *(uevent_buf + uevent_buf_len) = '='; + uevent_buf_len++; + // add value + memcpy(uevent_buf + uevent_buf_len, value, strlen(value)); + uevent_buf_len += strlen(value); + + // NULL-terminate + *(uevent_buf + uevent_buf_len) = '\0'; + uevent_buf_len++; + + *ret_uevent_buf = uevent_buf; + *ret_uevent_buf_len = uevent_buf_len; + + return 0; +} // register a device from sysfs, given the path to its uevent file. // that is, read the uevent file, generate a device request, and add it to the initial_requests list in the ctx. @@ -799,682 +822,712 @@ static int vdev_linux_uevent_append( char** ret_uevent_buf, size_t* ret_uevent_b // return 0 on success // return -ENOMEM on OOM // return negative on error. -static int vdev_linux_sysfs_register_device( struct vdev_linux_context* ctx, char const* fp_uevent ) { - - int rc = 0; - struct stat sb; - char* uevent_buf = NULL; - size_t uevent_buf_len = 0; - char* full_devpath = NULL; - char* devpath = NULL; - char* devname = NULL; - char* delim = NULL; - - // extract the devpath from the uevent path - full_devpath = vdev_dirname( fp_uevent, NULL ); - if( full_devpath == NULL ) { - return -ENOMEM; - } - - // get uevent - rc = vdev_linux_sysfs_read_uevent( fp_uevent, &uevent_buf, &uevent_buf_len ); - if( rc != 0 ) { - - vdev_error("vdev_linux_sysfs_read_uevent('%s') rc = %d\n", fp_uevent, rc ); - - free( full_devpath ); - return rc; - } - - if( uevent_buf_len == 0 ) { - - // no messages to be had - vdev_debug("Empty uevent file at '%s'\n", fp_uevent ); - - free( full_devpath ); - free( uevent_buf ); - return 0; - } - - // truncate to /devices - devpath = full_devpath + strlen( ctx->sysfs_mountpoint ); - - // we're adding this, so make ACTION=add - rc = vdev_linux_uevent_append( &uevent_buf, &uevent_buf_len, "ACTION", "add" ); - if( rc != 0 ) { - - vdev_error("vdev_linux_uevent_append('%s=%s') rc = %d\n", "ACTION", "add", rc ); - - free( uevent_buf ); - free( full_devpath ); - - return rc; - } - - - // see if the uevent has a devname. Use that over our devname, if need be - devname = strstr( uevent_buf, "DEVNAME=" ); - if( devname != NULL ) { - - // have a devname! - devname += strlen("DEVNAME=") + 1; - - size_t devname_len = strcspn( devname, "\n\0" ); - if( devname_len > 0 ) { - - char* tmp = VDEV_CALLOC( char, devname_len + 1 ); - if( tmp == NULL ) { - - free( uevent_buf ); - free( full_devpath ); - - return -ENOMEM; - } - - strncpy( tmp, devname, devname_len ); - - devname = tmp; - } - } - - // include the device path - rc = vdev_linux_uevent_append( &uevent_buf, &uevent_buf_len, "DEVPATH", devpath ); - if( rc != 0 ) { - - vdev_error("vdev_linux_uevent_append('%s=%s') rc = %d\n", "DEVPATH", devpath, rc ); - - free( uevent_buf ); - free( full_devpath ); - free( devname ); - return rc; - } - - - // make the device request - struct vdev_device_request* vreq = VDEV_CALLOC( struct vdev_device_request, 1 ); - if( vreq == NULL ) { - - free( full_devpath ); - free( uevent_buf ); - - return -ENOMEM; - } - - // build up the request - vdev_device_request_init( vreq, ctx->os_ctx->state, VDEV_DEVICE_INVALID, devname ); - - // parse from our uevent - rc = vdev_linux_parse_request( ctx, vreq, uevent_buf, uevent_buf_len ); - - free( uevent_buf ); - uevent_buf = NULL; - - if( rc != 0 ) { - - vdev_error("vdev_linux_parse_request('%s') rc = %d\n", fp_uevent, rc ); - - free( full_devpath ); - free( devname ); - - return rc; - } - - free( full_devpath ); - free( devname ); - - pthread_mutex_lock( &ctx->initial_requests_lock ); - - // append - if( ctx->initial_requests == NULL ) { - - ctx->initial_requests = vreq; - ctx->initial_requests_tail = vreq; - } - else { - - ctx->initial_requests_tail->next = vreq; - ctx->initial_requests_tail = vreq; - } - - vreq->next = NULL; - - pthread_mutex_unlock( &ctx->initial_requests_lock ); - - return rc; -} +static int vdev_linux_sysfs_register_device(struct vdev_linux_context *ctx, + char const *fp_uevent) +{ + + int rc = 0; + struct stat sb; + char *uevent_buf = NULL; + size_t uevent_buf_len = 0; + char *full_devpath = NULL; + char *devpath = NULL; + char *devname = NULL; + char *delim = NULL; + + // extract the devpath from the uevent path + full_devpath = vdev_dirname(fp_uevent, NULL); + if (full_devpath == NULL) { + return -ENOMEM; + } + // get uevent + rc = vdev_linux_sysfs_read_uevent(fp_uevent, &uevent_buf, + &uevent_buf_len); + if (rc != 0) { + + vdev_error("vdev_linux_sysfs_read_uevent('%s') rc = %d\n", + fp_uevent, rc); + + free(full_devpath); + return rc; + } + + if (uevent_buf_len == 0) { + + // no messages to be had + vdev_debug("Empty uevent file at '%s'\n", fp_uevent); + + free(full_devpath); + free(uevent_buf); + return 0; + } + // truncate to /devices + devpath = full_devpath + strlen(ctx->sysfs_mountpoint); + + // we're adding this, so make ACTION=add + rc = vdev_linux_uevent_append(&uevent_buf, &uevent_buf_len, "ACTION", + "add"); + if (rc != 0) { + + vdev_error("vdev_linux_uevent_append('%s=%s') rc = %d\n", + "ACTION", "add", rc); + + free(uevent_buf); + free(full_devpath); + + return rc; + } + + // see if the uevent has a devname. Use that over our devname, if need be + devname = strstr(uevent_buf, "DEVNAME="); + if (devname != NULL) { + + // have a devname! + devname += strlen("DEVNAME=") + 1; + + size_t devname_len = strcspn(devname, "\n\0"); + if (devname_len > 0) { + + char *tmp = VDEV_CALLOC(char, devname_len + 1); + if (tmp == NULL) { + + free(uevent_buf); + free(full_devpath); + + return -ENOMEM; + } + + strncpy(tmp, devname, devname_len); + + devname = tmp; + } + } + // include the device path + rc = vdev_linux_uevent_append(&uevent_buf, &uevent_buf_len, "DEVPATH", + devpath); + if (rc != 0) { + vdev_error("vdev_linux_uevent_append('%s=%s') rc = %d\n", + "DEVPATH", devpath, rc); + + free(uevent_buf); + free(full_devpath); + free(devname); + return rc; + } + + // make the device request + struct vdev_device_request *vreq = + VDEV_CALLOC(struct vdev_device_request, 1); + if (vreq == NULL) { + + free(full_devpath); + free(uevent_buf); + + return -ENOMEM; + } + // build up the request + vdev_device_request_init(vreq, ctx->os_ctx->state, VDEV_DEVICE_INVALID, + devname); + + // parse from our uevent + rc = vdev_linux_parse_request(ctx, vreq, uevent_buf, uevent_buf_len); + + free(uevent_buf); + uevent_buf = NULL; + + if (rc != 0) { + + vdev_error("vdev_linux_parse_request('%s') rc = %d\n", + fp_uevent, rc); + + free(full_devpath); + free(devname); + + return rc; + } + + free(full_devpath); + free(devname); + + pthread_mutex_lock(&ctx->initial_requests_lock); + + // append + if (ctx->initial_requests == NULL) { + + ctx->initial_requests = vreq; + ctx->initial_requests_tail = vreq; + } else { + + ctx->initial_requests_tail->next = vreq; + ctx->initial_requests_tail = vreq; + } + + vreq->next = NULL; + + pthread_mutex_unlock(&ctx->initial_requests_lock); + + return rc; +} // scan structure for finding new device directories, and signalling whether or not // the given directory has a uevent. struct vdev_linux_sysfs_scan_context { - - char* uevent_path; - struct sglib_cstr_vector* device_frontier; + + char *uevent_path; + struct sglib_cstr_vector *device_frontier; }; // scan a directory in /sys/devices directory, to find its child directories // return 0 on success // return -ENOMEM on OOM // return -errno on failure to stat -static int vdev_linux_sysfs_scan_device_directory( char const* fp, void* cls ) { - - struct vdev_linux_sysfs_scan_context* scan_ctx = (struct vdev_linux_sysfs_scan_context*)cls; - - struct sglib_cstr_vector* device_frontier = scan_ctx->device_frontier; - - struct stat sb; - int rc = 0; - char* fp_base = NULL; - char* fp_dup = NULL; - - fp_base = rindex( fp, '/' ); - - if( fp_base == NULL ) { - return 0; - } - - // skip . and .. - if( strcmp( fp_base, "/." ) == 0 || strcmp( fp_base, "/.." ) == 0 ) { - return 0; - } - - // add directories - rc = lstat( fp, &sb ); - if( rc != 0 ) { - - rc = -errno; - vdev_error("lstat('%s') rc = %d\n", fp, rc ); - return rc; - } - - if( !S_ISDIR( sb.st_mode ) && strcmp( fp_base, "/uevent" ) != 0 ) { - - // not a directory, and not a uevent - return 0; - } - - fp_dup = vdev_strdup_or_null( fp ); - if( fp_dup == NULL ) { - - return -ENOMEM; - } - - if( S_ISDIR( sb.st_mode ) ) { - - vdev_debug("Search '%s'\n", fp_dup ); - - rc = sglib_cstr_vector_push_back( device_frontier, fp_dup ); - if( rc != 0 ) { - - free( fp_dup ); - return rc; - } - } - else { - - // this is a uevent; this directory is a device - vdev_debug("Uevent '%s'\n", fp_dup ); - scan_ctx->uevent_path = fp_dup; - } - - return 0; -} +static int vdev_linux_sysfs_scan_device_directory(char const *fp, void *cls) +{ + + struct vdev_linux_sysfs_scan_context *scan_ctx = + (struct vdev_linux_sysfs_scan_context *)cls; + + struct sglib_cstr_vector *device_frontier = scan_ctx->device_frontier; + struct stat sb; + int rc = 0; + char *fp_base = NULL; + char *fp_dup = NULL; + + fp_base = rindex(fp, '/'); + + if (fp_base == NULL) { + return 0; + } + // skip . and .. + if (strcmp(fp_base, "/.") == 0 || strcmp(fp_base, "/..") == 0) { + return 0; + } + // add directories + rc = lstat(fp, &sb); + if (rc != 0) { + + rc = -errno; + vdev_error("lstat('%s') rc = %d\n", fp, rc); + return rc; + } + + if (!S_ISDIR(sb.st_mode) && strcmp(fp_base, "/uevent") != 0) { + + // not a directory, and not a uevent + return 0; + } + + fp_dup = vdev_strdup_or_null(fp); + if (fp_dup == NULL) { + + return -ENOMEM; + } + + if (S_ISDIR(sb.st_mode)) { + + vdev_debug("Search '%s'\n", fp_dup); + + rc = sglib_cstr_vector_push_back(device_frontier, fp_dup); + if (rc != 0) { + + free(fp_dup); + return rc; + } + } else { + + // this is a uevent; this directory is a device + vdev_debug("Uevent '%s'\n", fp_dup); + scan_ctx->uevent_path = fp_dup; + } + + return 0; +} // read all devices from sysfs, and put their uevent paths into the given uevent_paths. // scan in breadth-first order, so we find and process parent devices before their child devices. // return 0 on success // return negative on error -static int vdev_linux_sysfs_find_devices( struct vdev_linux_context* ctx, struct sglib_cstr_vector* uevent_paths ) { - - int rc = 0; - - // find all directories that have a 'uevent' file in them - struct sglib_cstr_vector device_frontier; - sglib_cstr_vector_init( &device_frontier ); - - struct vdev_linux_sysfs_scan_context scan_context; - memset( &scan_context, 0, sizeof(struct vdev_linux_sysfs_scan_context) ); - - scan_context.device_frontier = &device_frontier; - - char* device_root = NULL; - - // scan /sys/devices - device_root = vdev_fullpath( ctx->sysfs_mountpoint, "/devices", NULL ); - if( device_root == NULL ) { - - return -ENOMEM; - } - - rc = vdev_load_all( device_root, vdev_linux_sysfs_scan_device_directory, &scan_context ); - if( rc != 0 ) { - - vdev_error("vdev_load_all('%s') rc = %d\n", device_root, rc ); - - free( device_root ); - - sglib_cstr_vector_free( &device_frontier ); - - return rc; - } - - free( device_root ); - - while( 1 ) { - - unsigned long len = sglib_cstr_vector_size( &device_frontier ); - - if( len == 0 ) { - break; - } - - device_root = sglib_cstr_vector_at( &device_frontier, len - 1 ); - sglib_cstr_vector_set( &device_frontier, NULL, len - 1 ); - - sglib_cstr_vector_pop_back( &device_frontier ); - - // scan for more devices - rc = vdev_load_all( device_root, vdev_linux_sysfs_scan_device_directory, &scan_context ); - if( rc != 0 ) { - - vdev_error("vdev_load_all('%s') rc = %d\n", device_root, rc ); - free( device_root ); - break; - } - - // is one of them a uevent? - if( scan_context.uevent_path != NULL ) { - - // yup--remember it - char* uevent_path = vdev_strdup_or_null( scan_context.uevent_path ); - - if( uevent_path == NULL ) { - - free( device_root ); - free( scan_context.uevent_path ); - scan_context.uevent_path = NULL; - - rc = -ENOMEM; - break; - } - - rc = sglib_cstr_vector_push_back( uevent_paths, uevent_path ); - if( rc < 0 ) { - - free( uevent_path ); - free( device_root ); - free( scan_context.uevent_path ); - scan_context.uevent_path = NULL; - - break; - } - - free( scan_context.uevent_path ); - scan_context.uevent_path = NULL; - } - - free( device_root ); - } - - sglib_cstr_vector_free( &device_frontier ); - - return rc; -} +static int vdev_linux_sysfs_find_devices(struct vdev_linux_context *ctx, + struct sglib_cstr_vector *uevent_paths) +{ + + int rc = 0; + + // find all directories that have a 'uevent' file in them + struct sglib_cstr_vector device_frontier; + sglib_cstr_vector_init(&device_frontier); + + struct vdev_linux_sysfs_scan_context scan_context; + memset(&scan_context, 0, sizeof(struct vdev_linux_sysfs_scan_context)); + + scan_context.device_frontier = &device_frontier; + + char *device_root = NULL; + + // scan /sys/devices + device_root = vdev_fullpath(ctx->sysfs_mountpoint, "/devices", NULL); + if (device_root == NULL) { + + return -ENOMEM; + } + + rc = vdev_load_all(device_root, vdev_linux_sysfs_scan_device_directory, + &scan_context); + if (rc != 0) { + + vdev_error("vdev_load_all('%s') rc = %d\n", device_root, rc); + free(device_root); + + sglib_cstr_vector_free(&device_frontier); + + return rc; + } + + free(device_root); + + while (1) { + + unsigned long len = sglib_cstr_vector_size(&device_frontier); + + if (len == 0) { + break; + } + + device_root = sglib_cstr_vector_at(&device_frontier, len - 1); + sglib_cstr_vector_set(&device_frontier, NULL, len - 1); + + sglib_cstr_vector_pop_back(&device_frontier); + + // scan for more devices + rc = vdev_load_all(device_root, + vdev_linux_sysfs_scan_device_directory, + &scan_context); + if (rc != 0) { + + vdev_error("vdev_load_all('%s') rc = %d\n", device_root, + rc); + free(device_root); + break; + } + // is one of them a uevent? + if (scan_context.uevent_path != NULL) { + + // yup--remember it + char *uevent_path = + vdev_strdup_or_null(scan_context.uevent_path); + + if (uevent_path == NULL) { + + free(device_root); + free(scan_context.uevent_path); + scan_context.uevent_path = NULL; + + rc = -ENOMEM; + break; + } + + rc = sglib_cstr_vector_push_back(uevent_paths, + uevent_path); + if (rc < 0) { + + free(uevent_path); + free(device_root); + free(scan_context.uevent_path); + scan_context.uevent_path = NULL; + + break; + } + + free(scan_context.uevent_path); + scan_context.uevent_path = NULL; + } + + free(device_root); + } + + sglib_cstr_vector_free(&device_frontier); + + return rc; +} // free a list of cstr vectors // always succeeds -static int vdev_cstr_vector_free_all( struct sglib_cstr_vector* vec ) { - - // free all strings - for( unsigned long i = 0; i < sglib_cstr_vector_size( vec ); i++ ) { - - if( sglib_cstr_vector_at( vec, i ) != NULL ) { - - free( sglib_cstr_vector_at( vec, i ) ); - sglib_cstr_vector_set( vec, NULL, i ); - } - } - - return 0; +static int vdev_cstr_vector_free_all(struct sglib_cstr_vector *vec) +{ + + // free all strings + for (unsigned long i = 0; i < sglib_cstr_vector_size(vec); i++) { + + if (sglib_cstr_vector_at(vec, i) != NULL) { + + free(sglib_cstr_vector_at(vec, i)); + sglib_cstr_vector_set(vec, NULL, i); + } + } + + return 0; } - + // register all devices, given a vector to their uevent files // return 0 on success // return negative on error -static int vdev_linux_sysfs_register_devices( struct vdev_linux_context* ctx ) { - - int rc = 0; - struct sglib_cstr_vector uevent_paths; - - sglib_cstr_vector_init( &uevent_paths ); - - // scan devices - rc = vdev_linux_sysfs_find_devices( ctx, &uevent_paths ); - if( rc != 0 ) { - - vdev_error("vdev_linux_sysfs_find_devices() rc = %d\n", rc ); - - vdev_cstr_vector_free_all( &uevent_paths ); - sglib_cstr_vector_free( &uevent_paths ); - return rc; - } - - // process all devices - for( unsigned long i = 0; i < sglib_cstr_vector_size( &uevent_paths ); i++ ) { - - char* uevent_path = sglib_cstr_vector_at( &uevent_paths, i ); - - // skip filtered entries - if( uevent_path == NULL ) { - continue; - } - - vdev_debug("Register device '%s'\n", uevent_path ); - rc = vdev_linux_sysfs_register_device( ctx, uevent_path ); - if( rc != 0 ) { - - vdev_error("vdev_linux_sysfs_register_device('%s') rc = %d\n", uevent_path, rc ); - continue; - } - } - - // free all paths - vdev_cstr_vector_free_all( &uevent_paths ); - sglib_cstr_vector_free( &uevent_paths ); - - return rc; +static int vdev_linux_sysfs_register_devices(struct vdev_linux_context *ctx) +{ + + int rc = 0; + struct sglib_cstr_vector uevent_paths; + + sglib_cstr_vector_init(&uevent_paths); + + // scan devices + rc = vdev_linux_sysfs_find_devices(ctx, &uevent_paths); + if (rc != 0) { + + vdev_error("vdev_linux_sysfs_find_devices() rc = %d\n", rc); + + vdev_cstr_vector_free_all(&uevent_paths); + sglib_cstr_vector_free(&uevent_paths); + return rc; + } + // process all devices + for (unsigned long i = 0; i < sglib_cstr_vector_size(&uevent_paths); + i++) { + + char *uevent_path = sglib_cstr_vector_at(&uevent_paths, i); + + // skip filtered entries + if (uevent_path == NULL) { + continue; + } + + vdev_debug("Register device '%s'\n", uevent_path); + rc = vdev_linux_sysfs_register_device(ctx, uevent_path); + if (rc != 0) { + + vdev_error + ("vdev_linux_sysfs_register_device('%s') rc = %d\n", + uevent_path, rc); + continue; + } + } + + // free all paths + vdev_cstr_vector_free_all(&uevent_paths); + sglib_cstr_vector_free(&uevent_paths); + + return rc; } // start listening for kernel events via netlink // only do so if we're *NOT* going to run once (check the config) // return 0 on success // return -errno on error (failure to socket(2), setsockopt(2), bind(2), or walk sysfs) -static int vdev_linux_context_init( struct vdev_os_context* os_ctx, struct vdev_linux_context* ctx ) { - - int rc = 0; - size_t slen = VDEV_LINUX_NETLINK_RECV_BUF_MAX; - int so_passcred_enable = 1; - - memset( ctx, 0, sizeof(struct vdev_linux_context) ); - - ctx->os_ctx = os_ctx; - - // if we're just handling coldplug, don't set up the netlink socket - if( !os_ctx->coldplug_only ) { - - ctx->nl_addr.nl_family = AF_NETLINK; - ctx->nl_addr.nl_pid = getpid(); - ctx->nl_addr.nl_groups = NETLINK_KOBJECT_UEVENT; - - ctx->pfd.fd = socket( PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT ); - if( ctx->pfd.fd < 0 ) { - - rc = -errno; - vdev_error("socket(PF_NETLINK) rc = %d\n", rc); - return rc; - } - - ctx->pfd.events = POLLIN; - - // big receive buffer, if running as root - if( geteuid() == 0 ) { - rc = setsockopt( ctx->pfd.fd, SOL_SOCKET, SO_RCVBUFFORCE, &slen, sizeof(slen) ); - if( rc < 0 ) { - - rc = -errno; - vdev_error("setsockopt(SO_RCVBUFFORCE) rc = %d\n", rc); - - close( ctx->pfd.fd ); - return rc; - } - } - - // check credentials of message--only root should be able talk to us - rc = setsockopt( ctx->pfd.fd, SOL_SOCKET, SO_PASSCRED, &so_passcred_enable, sizeof(so_passcred_enable) ); - if( rc < 0 ) { - - rc = -errno; - vdev_error("setsockopt(SO_PASSCRED) rc = %d\n", rc ); - - close( ctx->pfd.fd ); - return rc; - - } - - // bind to the address - rc = bind( ctx->pfd.fd, (struct sockaddr*)&ctx->nl_addr, sizeof(struct sockaddr_nl) ); - if( rc != 0 ) { - - rc = -errno; - vdev_error("bind(%d) rc = %d\n", ctx->pfd.fd, rc ); - - close( ctx->pfd.fd ); - return rc; - } - } - else { - - ctx->pfd.fd = -1; - } - - // lookup sysfs mountpoint - rc = vdev_linux_find_sysfs_mountpoint( ctx->sysfs_mountpoint, PATH_MAX ); - if( rc != 0 ) { - - vdev_error("vdev_linux_find_sysfs_mountpoint rc = %d\n", rc ); - - close( ctx->pfd.fd ); - return rc; - } - - pthread_mutex_init( &ctx->initial_requests_lock, NULL ); - - // seed devices from sysfs - rc = vdev_linux_sysfs_register_devices( ctx ); - if( rc != 0 ) { - - vdev_error("vdev_linux_sysfs_walk_devs rc = %d\n", rc ); - return rc; - } - - return 0; -} +static int vdev_linux_context_init(struct vdev_os_context *os_ctx, + struct vdev_linux_context *ctx) +{ + int rc = 0; + size_t slen = VDEV_LINUX_NETLINK_RECV_BUF_MAX; + int so_passcred_enable = 1; -// stop listening -static int vdev_linux_context_shutdown( struct vdev_linux_context* ctx ) { - - // shut down - if( ctx != NULL ) { - - if( ctx->pfd.fd >= 0 ) { - close( ctx->pfd.fd ); - ctx->pfd.fd = -1; - } - - if( ctx->initial_requests != NULL ) { - - struct vdev_device_request* itr = ctx->initial_requests; - struct vdev_device_request* next = NULL; - - while( itr != NULL ) { - - next = itr->next; - - vdev_device_request_free( itr ); - free( itr ); - - itr = next; - } - - ctx->initial_requests = NULL; - ctx->initial_requests_tail = NULL; - } - } - - return 0; + memset(ctx, 0, sizeof(struct vdev_linux_context)); + + ctx->os_ctx = os_ctx; + + // if we're just handling coldplug, don't set up the netlink socket + if (!os_ctx->coldplug_only) { + + ctx->nl_addr.nl_family = AF_NETLINK; + ctx->nl_addr.nl_pid = getpid(); + ctx->nl_addr.nl_groups = NETLINK_KOBJECT_UEVENT; + + ctx->pfd.fd = + socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT); + if (ctx->pfd.fd < 0) { + + rc = -errno; + vdev_error("socket(PF_NETLINK) rc = %d\n", rc); + return rc; + } + + ctx->pfd.events = POLLIN; + + // big receive buffer, if running as root + if (geteuid() == 0) { + rc = setsockopt(ctx->pfd.fd, SOL_SOCKET, SO_RCVBUFFORCE, + &slen, sizeof(slen)); + if (rc < 0) { + + rc = -errno; + vdev_error + ("setsockopt(SO_RCVBUFFORCE) rc = %d\n", + rc); + + close(ctx->pfd.fd); + return rc; + } + } + // check credentials of message--only root should be able talk to us + rc = setsockopt(ctx->pfd.fd, SOL_SOCKET, SO_PASSCRED, + &so_passcred_enable, + sizeof(so_passcred_enable)); + if (rc < 0) { + + rc = -errno; + vdev_error("setsockopt(SO_PASSCRED) rc = %d\n", rc); + + close(ctx->pfd.fd); + return rc; + + } + // bind to the address + rc = bind(ctx->pfd.fd, (struct sockaddr *)&ctx->nl_addr, + sizeof(struct sockaddr_nl)); + if (rc != 0) { + + rc = -errno; + vdev_error("bind(%d) rc = %d\n", ctx->pfd.fd, rc); + + close(ctx->pfd.fd); + return rc; + } + } else { + + ctx->pfd.fd = -1; + } + + // lookup sysfs mountpoint + rc = vdev_linux_find_sysfs_mountpoint(ctx->sysfs_mountpoint, PATH_MAX); + if (rc != 0) { + + vdev_error("vdev_linux_find_sysfs_mountpoint rc = %d\n", rc); + + close(ctx->pfd.fd); + return rc; + } + + pthread_mutex_init(&ctx->initial_requests_lock, NULL); + + // seed devices from sysfs + rc = vdev_linux_sysfs_register_devices(ctx); + if (rc != 0) { + + vdev_error("vdev_linux_sysfs_walk_devs rc = %d\n", rc); + return rc; + } + + return 0; } +// stop listening +static int vdev_linux_context_shutdown(struct vdev_linux_context *ctx) +{ + + // shut down + if (ctx != NULL) { + + if (ctx->pfd.fd >= 0) { + close(ctx->pfd.fd); + ctx->pfd.fd = -1; + } + + if (ctx->initial_requests != NULL) { + + struct vdev_device_request *itr = ctx->initial_requests; + struct vdev_device_request *next = NULL; + + while (itr != NULL) { + + next = itr->next; + + vdev_device_request_free(itr); + free(itr); + + itr = next; + } + + ctx->initial_requests = NULL; + ctx->initial_requests_tail = NULL; + } + } + + return 0; +} // are we using devtmpfs on this mountpoint? // return 1 if so // return 0 if not // return negative on error -static int vdev_linux_mountpoint_on_devtmpfs( char const* mountpoint ) { - - // NOTE: You would think that we can just statfs(2) the - // mountpoint and get the underlying filesystem type. - // However, devtmpfs and tmpfs have the same f_type value. - // This makes this strategy a no-go, since vdevd will need - // to behave differently on devtmpfs but not tmpfs. - // So, we have to parse /proc/mounts instead. - - int rc = 0; - - FILE* f = NULL; - int ent_count = 1; - - bool found = false; - char devtmpfs_mountpoint[PATH_MAX+1]; - - char realpath_mountpoint[PATH_MAX+1]; - char devtmpfs_realpath_mountpoint[PATH_MAX+1]; - - size_t devtmpfs_realpath_mountpoint_len = 0; - size_t realpath_mountpoint_len = 0; - - char mntbuf[4096]; - struct mntent ment_buf; - struct mntent* ment_ptr = NULL; - - f = fopen( "/proc/mounts", "r" ); - if( f == NULL ) { - - rc = -errno; - fprintf(stderr, "Failed to open /proc/mounts, rc = %d\n", rc ); - return rc; - } - - // scan for sysfs mount type - while( 1 ) { - - ment_ptr = getmntent_r( f, &ment_buf, mntbuf, 4096 ); - if( ment_ptr == NULL ) { - - break; - } - - if( strcmp( ment_ptr->mnt_type, "devtmpfs" ) == 0 ) { - - // found! - strncpy( devtmpfs_mountpoint, ment_ptr->mnt_dir, PATH_MAX ); - - // is the mountpoint contained in devtmpfs_mountpoint? - char* tmp = NULL; - - memset( realpath_mountpoint, 0, PATH_MAX+1 ); - memset( devtmpfs_realpath_mountpoint, 0, PATH_MAX+1 ); - - tmp = realpath( mountpoint, realpath_mountpoint ); - if( tmp == NULL ) { - - rc = -errno; - fprintf(stderr, "Failed to get the real path of '%s', rc = %d\n", mountpoint, rc ); - break; - } - - tmp = realpath( devtmpfs_mountpoint, devtmpfs_realpath_mountpoint ); - if( tmp == NULL ) { - - rc = -errno; - fprintf(stderr, "Failed to get the real path of '%s', rc = %d\n", devtmpfs_mountpoint, rc ); - break; - } - - vdev_debug("devtmpfs realpath is '%s'\n", devtmpfs_realpath_mountpoint ); - vdev_debug("mountpoint realpath is '%s'\n", realpath_mountpoint ); - - devtmpfs_realpath_mountpoint_len = strlen(devtmpfs_realpath_mountpoint); - realpath_mountpoint_len = strlen(realpath_mountpoint); - - size_t min_len = MIN( devtmpfs_realpath_mountpoint_len, realpath_mountpoint_len ); - - // is our mountpoint within the devtmpfs mountpoint? - if( strncmp( devtmpfs_realpath_mountpoint, realpath_mountpoint, min_len ) == 0 && // devtmpfs mountpoint path is a substring of the mountpoint path and - (strchr( realpath_mountpoint + min_len, '/' ) != NULL || // either the mountpoint path continues at least one directory into devtmpfs path, or - strcmp( devtmpfs_realpath_mountpoint, realpath_mountpoint ) == 0 ) ) { // the devtmpfs mountpoint path *is* the mountpoint path - - // contained! - rc = 1; - found = true; - break; - } - } - - ent_count++; - } - - fclose( f ); - - return rc; +static int vdev_linux_mountpoint_on_devtmpfs(char const *mountpoint) +{ + + // NOTE: You would think that we can just statfs(2) the + // mountpoint and get the underlying filesystem type. + // However, devtmpfs and tmpfs have the same f_type value. + // This makes this strategy a no-go, since vdevd will need + // to behave differently on devtmpfs but not tmpfs. + // So, we have to parse /proc/mounts instead. + + int rc = 0; + + FILE *f = NULL; + int ent_count = 1; + + bool found = false; + char devtmpfs_mountpoint[PATH_MAX + 1]; + + char realpath_mountpoint[PATH_MAX + 1]; + char devtmpfs_realpath_mountpoint[PATH_MAX + 1]; + + size_t devtmpfs_realpath_mountpoint_len = 0; + size_t realpath_mountpoint_len = 0; + + char mntbuf[4096]; + struct mntent ment_buf; + struct mntent *ment_ptr = NULL; + + f = fopen("/proc/mounts", "r"); + if (f == NULL) { + + rc = -errno; + fprintf(stderr, "Failed to open /proc/mounts, rc = %d\n", rc); + return rc; + } + // scan for sysfs mount type + while (1) { + + ment_ptr = getmntent_r(f, &ment_buf, mntbuf, 4096); + if (ment_ptr == NULL) { + + break; + } + + if (strcmp(ment_ptr->mnt_type, "devtmpfs") == 0) { + + // found! + strncpy(devtmpfs_mountpoint, ment_ptr->mnt_dir, + PATH_MAX); + + // is the mountpoint contained in devtmpfs_mountpoint? + char *tmp = NULL; + + memset(realpath_mountpoint, 0, PATH_MAX + 1); + memset(devtmpfs_realpath_mountpoint, 0, PATH_MAX + 1); + + tmp = realpath(mountpoint, realpath_mountpoint); + if (tmp == NULL) { + + rc = -errno; + fprintf(stderr, + "Failed to get the real path of '%s', rc = %d\n", + mountpoint, rc); + break; + } + + tmp = + realpath(devtmpfs_mountpoint, + devtmpfs_realpath_mountpoint); + if (tmp == NULL) { + + rc = -errno; + fprintf(stderr, + "Failed to get the real path of '%s', rc = %d\n", + devtmpfs_mountpoint, rc); + break; + } + + vdev_debug("devtmpfs realpath is '%s'\n", + devtmpfs_realpath_mountpoint); + vdev_debug("mountpoint realpath is '%s'\n", + realpath_mountpoint); + + devtmpfs_realpath_mountpoint_len = + strlen(devtmpfs_realpath_mountpoint); + realpath_mountpoint_len = strlen(realpath_mountpoint); + + size_t min_len = + MIN(devtmpfs_realpath_mountpoint_len, + realpath_mountpoint_len); + + // is our mountpoint within the devtmpfs mountpoint? + if (strncmp(devtmpfs_realpath_mountpoint, realpath_mountpoint, min_len) == 0 && // devtmpfs mountpoint path is a substring of the mountpoint path and + (strchr(realpath_mountpoint + min_len, '/') != NULL || // either the mountpoint path continues at least one directory into devtmpfs path, or + strcmp(devtmpfs_realpath_mountpoint, realpath_mountpoint) == 0)) { // the devtmpfs mountpoint path *is* the mountpoint path + + // contained! + rc = 1; + found = true; + break; + } + } + + ent_count++; + } + + fclose(f); + + return rc; } // set up Linux-specific vdev state. // this is early initialization, so don't start anything yet // NOTE: this should only be called from reload-safe code--i.e. a reload can't occur while this method runs -int vdev_os_init( struct vdev_os_context* os_ctx, void** cls ) { - - int rc = 0; - struct vdev_linux_context* ctx = NULL; - - rc = vdev_linux_mountpoint_on_devtmpfs( os_ctx->state->mountpoint ); - if( rc < 0 ) { - - vdev_error("vdev_linux_mountpoint_on_devtmpfs('%s') rc = %d\n", os_ctx->state->mountpoint, rc ); - return rc; - } - - if( rc > 0 ) { - - // using devtmpfs - vdev_info("'%s' is on devtmpfs\n", os_ctx->state->mountpoint ); - - vdev_config_set_OS_quirk( os_ctx->state->config->OS_quirks, VDEV_OS_QUIRK_DEVICE_EXISTS ); - } - else { - - vdev_info("'%s' is not on devtmpfs\n", os_ctx->state->mountpoint ); - } - - ctx = VDEV_CALLOC( struct vdev_linux_context, 1 ); - if( ctx == NULL ) { - return -ENOMEM; - } - - rc = vdev_linux_context_init( os_ctx, ctx ); - if( rc != 0 ) { - - free( ctx ); - return rc; - } - - *cls = ctx; - return 0; -} +int vdev_os_init(struct vdev_os_context *os_ctx, void **cls) +{ + int rc = 0; + struct vdev_linux_context *ctx = NULL; -// shut down Linux-specific vdev state -int vdev_os_shutdown( void* cls ) { - - struct vdev_linux_context* ctx = (struct vdev_linux_context*)cls; - - vdev_linux_context_shutdown( ctx ); - free( ctx ); - - return 0; + rc = vdev_linux_mountpoint_on_devtmpfs(os_ctx->state->mountpoint); + if (rc < 0) { + + vdev_error("vdev_linux_mountpoint_on_devtmpfs('%s') rc = %d\n", + os_ctx->state->mountpoint, rc); + return rc; + } + + if (rc > 0) { + + // using devtmpfs + vdev_info("'%s' is on devtmpfs\n", os_ctx->state->mountpoint); + + vdev_config_set_OS_quirk(os_ctx->state->config->OS_quirks, + VDEV_OS_QUIRK_DEVICE_EXISTS); + } else { + + vdev_info("'%s' is not on devtmpfs\n", + os_ctx->state->mountpoint); + } + + ctx = VDEV_CALLOC(struct vdev_linux_context, 1); + if (ctx == NULL) { + return -ENOMEM; + } + + rc = vdev_linux_context_init(os_ctx, ctx); + if (rc != 0) { + + free(ctx); + return rc; + } + + *cls = ctx; + return 0; } +// shut down Linux-specific vdev state +int vdev_os_shutdown(void *cls) +{ + + struct vdev_linux_context *ctx = (struct vdev_linux_context *)cls; + + vdev_linux_context_shutdown(ctx); + free(ctx); + + return 0; +} #endif diff --git a/vdevd/os/linux.h b/vdevd/os/linux.h index 68b7ae5..62cefce 100644 --- a/vdevd/os/linux.h +++ b/vdevd/os/linux.h @@ -25,7 +25,7 @@ // build Linux-specific method implementations #ifdef _VDEV_OS_LINUX -#define _GNU_SOURCE +#define _GNU_SOURCE #include "vdev.h" @@ -48,33 +48,30 @@ // connection to the linux kernel for hotplug struct vdev_linux_context { - - // netlink address - struct sockaddr_nl nl_addr; - - // poll on the netlink socket - struct pollfd pfd; - - // path to mounted sysfs - char sysfs_mountpoint[ PATH_MAX+1 ]; - - // ref to OS context - struct vdev_os_context* os_ctx; - - // initial device requests - pthread_mutex_t initial_requests_lock; - struct vdev_device_request* initial_requests; - struct vdev_device_request* initial_requests_tail; -}; -C_LINKAGE_BEGIN + // netlink address + struct sockaddr_nl nl_addr; -int vdev_os_init( struct vdev_os_context* ctx, void** cls ); -int vdev_os_shutdown( void* cls ); + // poll on the netlink socket + struct pollfd pfd; -int vdev_os_next_device( struct vdev_device_request* request, void* cls ); + // path to mounted sysfs + char sysfs_mountpoint[PATH_MAX + 1]; -C_LINKAGE_END + // ref to OS context + struct vdev_os_context *os_ctx; + + // initial device requests + pthread_mutex_t initial_requests_lock; + struct vdev_device_request *initial_requests; + struct vdev_device_request *initial_requests_tail; +}; +C_LINKAGE_BEGIN int vdev_os_init(struct vdev_os_context *ctx, void **cls); +int vdev_os_shutdown(void *cls); + +int vdev_os_next_device(struct vdev_device_request *request, void *cls); + +C_LINKAGE_END +#endif #endif -#endif \ No newline at end of file diff --git a/vdevd/os/methods.h b/vdevd/os/methods.h index 938f594..d336ed2 100644 --- a/vdevd/os/methods.h +++ b/vdevd/os/methods.h @@ -34,18 +34,15 @@ #include "test.h" #endif -C_LINKAGE_BEGIN - -int vdev_os_init( struct vdev_os_context* ctx, void** cls ); -int vdev_os_shutdown( void* cls ); +C_LINKAGE_BEGIN int vdev_os_init(struct vdev_os_context *ctx, void **cls); +int vdev_os_shutdown(void *cls); // yield the next device // return 0 on success // return positive to exit successfully // return -EAGAIN if vdevd should try again // return negative on fatal error (causes vdevd to exit). -int vdev_os_next_device( struct vdev_device_request* request, void* cls ); +int vdev_os_next_device(struct vdev_device_request *request, void *cls); C_LINKAGE_END - -#endif +#endif diff --git a/vdevd/os/test.h b/vdevd/os/test.h index ffbdb78..e90a602 100644 --- a/vdevd/os/test.h +++ b/vdevd/os/test.h @@ -34,30 +34,27 @@ #define VDEV_TEST_NAME_MAJOR "MAJOR" #define VDEV_TEST_NAME_MINOR "MINOR" - -typedef vector vdev_test_device_list_t; +typedef vector < struct vdev_device_request *>vdev_test_device_list_t; struct vdev_test_context { - - vdev_test_device_list_t* devlist; - - pthread_mutex_t devlist_lock; - sem_t devlist_sem; - - char* events_dir; + + vdev_test_device_list_t *devlist; + + pthread_mutex_t devlist_lock; + sem_t devlist_sem; + + char *events_dir; }; extern "C" { -int vdev_os_init( struct vdev_os_context* ctx, void** cls ); -int vdev_os_start( void* cls ); -int vdev_os_stop( void* cls ); -int vdev_os_shutdown( void* cls ); + int vdev_os_init(struct vdev_os_context *ctx, void **cls); + int vdev_os_start(void *cls); + int vdev_os_stop(void *cls); + int vdev_os_shutdown(void *cls); -int vdev_os_next_device( struct vdev_device_request* request, void* cls ); + int vdev_os_next_device(struct vdev_device_request *request, void *cls); } - #endif - -#endif \ No newline at end of file +#endif diff --git a/vdevd/vdev.c b/vdevd/vdev.c index e0f194c..fdb820f 100644 --- a/vdevd/vdev.c +++ b/vdevd/vdev.c @@ -23,67 +23,72 @@ #include "action.h" #include "libvdev/config.h" -SGLIB_DEFINE_VECTOR_FUNCTIONS(cstr) +SGLIB_DEFINE_VECTOR_FUNCTIONS (cstr) // context for removing unplugged device -struct vdev_device_unplug_context { + struct vdev_device_unplug_context + { - struct sglib_cstr_vector *device_paths; // queue of device paths to search - struct vdev_state *state; // vdev state -}; + struct sglib_cstr_vector *device_paths; // queue of device paths to search + struct vdev_state *state; // vdev state + }; // get the instance of the vdevd program that made this device, given its device path // instance_str must be at least VDEV_CONFIG_INSTANCE_NONCE_STRLEN bytes // return 0 on success // return -errno on failure to stat, open, or read -static int vdev_device_read_vdevd_instance(char const *mountpoint, - char const *dev_fullpath, - char *instance_str) + static int vdev_device_read_vdevd_instance (char const *mountpoint, + char const *dev_fullpath, + char *instance_str) { - int rc = 0; - char const *devpath = dev_fullpath + strlen(mountpoint); + int rc = 0; + char const *devpath = dev_fullpath + strlen (mountpoint); - char *instance_attr_relpath = - vdev_fullpath(VDEV_METADATA_PREFIX "/dev", devpath, NULL); - if (instance_attr_relpath == NULL) { + char *instance_attr_relpath = + vdev_fullpath (VDEV_METADATA_PREFIX "/dev", devpath, NULL); + if (instance_attr_relpath == NULL) + { - return -ENOMEM; - } + return -ENOMEM; + } - char *instance_attr_path = - vdev_fullpath(mountpoint, instance_attr_relpath, NULL); + char *instance_attr_path = + vdev_fullpath (mountpoint, instance_attr_relpath, NULL); - free(instance_attr_relpath); - instance_attr_relpath = NULL; + free (instance_attr_relpath); + instance_attr_relpath = NULL; - if (instance_attr_path == NULL) { + if (instance_attr_path == NULL) + { - return -ENOMEM; - } + return -ENOMEM; + } - char *instance_path = - vdev_fullpath(instance_attr_path, VDEV_METADATA_PARAM_INSTANCE, - NULL); + char *instance_path = + vdev_fullpath (instance_attr_path, VDEV_METADATA_PARAM_INSTANCE, + NULL); - free(instance_attr_path); - instance_attr_path = NULL; + free (instance_attr_path); + instance_attr_path = NULL; - if (instance_path == NULL) { + if (instance_path == NULL) + { - return -ENOMEM; - } - // read the instance string - rc = vdev_read_file(instance_path, instance_str, - VDEV_CONFIG_INSTANCE_NONCE_STRLEN - 1); - if (rc < 0) { + return -ENOMEM; + } + // read the instance string + rc = vdev_read_file (instance_path, instance_str, + VDEV_CONFIG_INSTANCE_NONCE_STRLEN - 1); + if (rc < 0) + { - vdev_error("vdev_read_file('%s') rc = %d\n", instance_path, rc); - } + vdev_error ("vdev_read_file('%s') rc = %d\n", instance_path, rc); + } - free(instance_path); - instance_path = NULL; + free (instance_path); + instance_path = NULL; - return rc; + return rc; } // scan callback for a directory. @@ -91,464 +96,508 @@ static int vdev_device_read_vdevd_instance(char const *mountpoint, // return 0 on success // return -ENOMEM on OOM // NOTE: mask unlink() failures, but log them. -static int vdev_remove_unplugged_device(char const *path, void *cls) +static int +vdev_remove_unplugged_device (char const *path, void *cls) { - int rc = 0; - struct stat sb; - char instance_str[VDEV_CONFIG_INSTANCE_NONCE_STRLEN + 1]; - char basename[NAME_MAX + 1]; + int rc = 0; + struct stat sb; + char instance_str[VDEV_CONFIG_INSTANCE_NONCE_STRLEN + 1]; + char basename[NAME_MAX + 1]; - memset(instance_str, 0, VDEV_CONFIG_INSTANCE_NONCE_STRLEN + 1); + memset (instance_str, 0, VDEV_CONFIG_INSTANCE_NONCE_STRLEN + 1); - // extract cls - struct vdev_device_unplug_context *ctx = - (struct vdev_device_unplug_context *)cls; + // extract cls + struct vdev_device_unplug_context *ctx = + (struct vdev_device_unplug_context *) cls; - struct sglib_cstr_vector *device_paths = ctx->device_paths; - struct vdev_state *state = ctx->state; + struct sglib_cstr_vector *device_paths = ctx->device_paths; + struct vdev_state *state = ctx->state; - if (strlen(path) == 0) { + if (strlen (path) == 0) + { - // nothing to do - return 0; - } + // nothing to do + return 0; + } - vdev_basename(path, basename); + vdev_basename (path, basename); - // is this . or ..? - if (strcmp(basename, ".") == 0 || strcmp(basename, "..") == 0) { - return 0; - } - // what is this? - rc = lstat(path, &sb); - if (rc != 0) { + // is this . or ..? + if (strcmp (basename, ".") == 0 || strcmp (basename, "..") == 0) + { + return 0; + } + // what is this? + rc = lstat (path, &sb); + if (rc != 0) + { + + vdev_error ("stat('%s') rc = %d\n", path, rc); - vdev_error("stat('%s') rc = %d\n", path, rc); + // mask + return 0; + } + // is this a directory? + if (S_ISDIR (sb.st_mode)) + { - // mask - return 0; + // skip the metadata dir + if (strcmp (basename, "metadata") == 0) + { + return 0; } - // is this a directory? - if (S_ISDIR(sb.st_mode)) { + // search this later + char *path_dup = vdev_strdup_or_null (path); + if (path_dup == NULL) + { - // skip the metadata dir - if (strcmp(basename, "metadata") == 0) { - return 0; - } - // search this later - char *path_dup = vdev_strdup_or_null(path); - if (path_dup == NULL) { + // really can't continue + return -ENOMEM; + } - // really can't continue - return -ENOMEM; - } + sglib_cstr_vector_push_back (device_paths, path_dup); - sglib_cstr_vector_push_back(device_paths, path_dup); + return 0; + } + // is this a device file? + if (S_ISBLK (sb.st_mode) || S_ISCHR (sb.st_mode)) + { - return 0; - } - // is this a device file? - if (S_ISBLK(sb.st_mode) || S_ISCHR(sb.st_mode)) { - - // what's the instance value? - rc = vdev_device_read_vdevd_instance(state->config->mountpoint, - path, instance_str); - if (rc != 0) { - - vdev_error - ("vdev_device_read_vdevd_instance('%s') rc = %d\n", - path, rc); - - // mask - return 0; - } - // does it match ours? - if (strcmp(state->config->instance_str, instance_str) != 0) { - - struct vdev_device_request *to_delete = NULL; - char const *device_path = NULL; - - vdev_debug("Remove unplugged device '%s'\n", path); - - device_path = path + strlen(state->config->mountpoint); - - to_delete = VDEV_CALLOC(struct vdev_device_request, 1); - if (to_delete == NULL) { - - // OOM - return -ENOMEM; - } - - rc = vdev_device_request_init(to_delete, state, - VDEV_DEVICE_REMOVE, - device_path); - if (rc != 0) { - - // OOM - return rc; - } - // populate - vdev_device_request_set_dev(to_delete, sb.st_rdev); - vdev_device_request_set_mode(to_delete, - S_ISBLK(sb.st_mode) ? - S_IFBLK : S_IFCHR); - - // remove it - rc = vdev_device_remove(to_delete); - if (rc != 0) { - - vdev_warn("vdev_device_remove('%s') rc = %d\n", - device_path, rc); - rc = 0; - } - } + // what's the instance value? + rc = vdev_device_read_vdevd_instance (state->config->mountpoint, + path, instance_str); + if (rc != 0) + { + + vdev_error + ("vdev_device_read_vdevd_instance('%s') rc = %d\n", path, rc); + + // mask + return 0; } + // does it match ours? + if (strcmp (state->config->instance_str, instance_str) != 0) + { + + struct vdev_device_request *to_delete = NULL; + char const *device_path = NULL; + + vdev_debug ("Remove unplugged device '%s'\n", path); + + device_path = path + strlen (state->config->mountpoint); + + to_delete = VDEV_CALLOC (struct vdev_device_request, 1); + if (to_delete == NULL) + { + + // OOM + return -ENOMEM; + } + + rc = vdev_device_request_init (to_delete, state, + VDEV_DEVICE_REMOVE, device_path); + if (rc != 0) + { + + // OOM + return rc; + } + // populate + vdev_device_request_set_dev (to_delete, sb.st_rdev); + vdev_device_request_set_mode (to_delete, + S_ISBLK (sb.st_mode) ? + S_IFBLK : S_IFCHR); + + // remove it + rc = vdev_device_remove (to_delete); + if (rc != 0) + { + + vdev_warn ("vdev_device_remove('%s') rc = %d\n", + device_path, rc); + rc = 0; + } + } + } - return 0; + return 0; } // remove all devices that no longer exist--that is, the contents of the /dev/metadata/$DEVICE_PATH/dev_instance file // does not match this vdev's instance nonce. // this is used when running with --once. -int vdev_remove_unplugged_devices(struct vdev_state *state) +int +vdev_remove_unplugged_devices (struct vdev_state *state) { - int rc = 0; - struct sglib_cstr_vector device_paths; - char *devroot = vdev_strdup_or_null(state->config->mountpoint); - char *next_dir = NULL; - size_t next_dir_index = 0; - // sb ? - struct stat sb; + int rc = 0; + struct sglib_cstr_vector device_paths; + char *devroot = vdev_strdup_or_null (state->config->mountpoint); + char *next_dir = NULL; + size_t next_dir_index = 0; + // sb ? + struct stat sb; - struct vdev_device_unplug_context unplug_ctx; + struct vdev_device_unplug_context unplug_ctx; - unplug_ctx.state = state; - unplug_ctx.device_paths = &device_paths; + unplug_ctx.state = state; + unplug_ctx.device_paths = &device_paths; - if (devroot == NULL) { - return -ENOMEM; - } - - sglib_cstr_vector_init(&device_paths); + if (devroot == NULL) + { + return -ENOMEM; + } - // walk /dev breadth-first - rc = sglib_cstr_vector_push_back(&device_paths, devroot); - if (rc != 0) { + sglib_cstr_vector_init (&device_paths); - sglib_cstr_vector_free(&device_paths); - free(devroot); + // walk /dev breadth-first + rc = sglib_cstr_vector_push_back (&device_paths, devroot); + if (rc != 0) + { - return rc; - } + sglib_cstr_vector_free (&device_paths); + free (devroot); - while (next_dir_index < sglib_cstr_vector_size(&device_paths)) { + return rc; + } - // next path - next_dir = sglib_cstr_vector_at(&device_paths, next_dir_index); - sglib_cstr_vector_set(&device_paths, NULL, next_dir_index); + while (next_dir_index < sglib_cstr_vector_size (&device_paths)) + { - next_dir_index++; + // next path + next_dir = sglib_cstr_vector_at (&device_paths, next_dir_index); + sglib_cstr_vector_set (&device_paths, NULL, next_dir_index); - // scan this directory, and remove unplugged device files and remember the directories to search - rc = vdev_load_all(next_dir, vdev_remove_unplugged_device, - &unplug_ctx); - if (rc != 0) { + next_dir_index++; - vdev_error("vdev_load_all('%s') rc = %d\n", next_dir, - rc); + // scan this directory, and remove unplugged device files and remember the directories to search + rc = vdev_load_all (next_dir, vdev_remove_unplugged_device, + &unplug_ctx); + if (rc != 0) + { - free(next_dir); - break; - } + vdev_error ("vdev_load_all('%s') rc = %d\n", next_dir, rc); - free(next_dir); + free (next_dir); + break; } - // free any unused vector space - while (next_dir_index < sglib_cstr_vector_size(&device_paths)) { + free (next_dir); + } - next_dir = sglib_cstr_vector_at(&device_paths, next_dir_index); - sglib_cstr_vector_set(&device_paths, NULL, next_dir_index); + // free any unused vector space + while (next_dir_index < sglib_cstr_vector_size (&device_paths)) + { - next_dir_index++; + next_dir = sglib_cstr_vector_at (&device_paths, next_dir_index); + sglib_cstr_vector_set (&device_paths, NULL, next_dir_index); - free(next_dir); - } + next_dir_index++; + + free (next_dir); + } - sglib_cstr_vector_free(&device_paths); + sglib_cstr_vector_free (&device_paths); - return rc; + return rc; } // create the path to the error FIFO // that helpers use to write error messages. // return 0 on success // return -EPERM on overflow -int vdev_error_fifo_path(char const *mountpoint, char *path, size_t path_len) +int +vdev_error_fifo_path (char const *mountpoint, char *path, size_t path_len) { - int rc = 0; - rc = snprintf(path, path_len, "%s/%s/err.pipe", mountpoint, - VDEV_METADATA_PREFIX); - if (rc >= path_len) { - return -EPERM; - } + int rc = 0; + rc = snprintf (path, path_len, "%s/%s/err.pipe", mountpoint, + VDEV_METADATA_PREFIX); + if (rc >= path_len) + { + return -EPERM; + } - return 0; + return 0; } // get a handle to the error FIFO, creating the FIFO if it doesn't yet exist. // the handle will be in read/write mode // return 0 on success, and set *fd // return -errno on failure to create the FIFO -int vdev_error_fifo_get_or_create(char const *mountpoint, int *fd) +int +vdev_error_fifo_get_or_create (char const *mountpoint, int *fd) { - int rc = 0; - char fifo_path[PATH_MAX + 1]; - struct stat sb; - memset(fifo_path, 0, PATH_MAX + 1); + int rc = 0; + char fifo_path[PATH_MAX + 1]; + struct stat sb; + memset (fifo_path, 0, PATH_MAX + 1); + + rc = vdev_error_fifo_path (mountpoint, fifo_path, PATH_MAX); + if (rc < 0) + { + return rc; + } + + rc = stat (fifo_path, &sb); + if (rc != 0) + { - rc = vdev_error_fifo_path(mountpoint, fifo_path, PATH_MAX); - if (rc < 0) { - return rc; + rc = -errno; + if (rc != -ENOENT) + { + + vdev_error ("failed to create FIFO '%s': %s\n", + fifo_path, strerror (-rc)); + return rc; } + // create + rc = mkfifo (fifo_path, 0600); + if (rc != 0) + { - rc = stat(fifo_path, &sb); - if (rc != 0) { - - rc = -errno; - if (rc != -ENOENT) { - - vdev_error("failed to create FIFO '%s': %s\n", - fifo_path, strerror(-rc)); - return rc; - } - // create - rc = mkfifo(fifo_path, 0600); - if (rc != 0) { - - rc = -errno; - vdev_error("mkfifo('%s'): %s\n", fifo_path, - strerror(-rc)); - return rc; - } + rc = -errno; + vdev_error ("mkfifo('%s'): %s\n", fifo_path, strerror (-rc)); + return rc; } + } - *fd = open(fifo_path, O_RDWR); - if (*fd < 0) { + *fd = open (fifo_path, O_RDWR); + if (*fd < 0) + { - rc = -errno; - vdev_error("open('%s'): %s\n", fifo_path, strerror(-rc)); - return rc; - } + rc = -errno; + vdev_error ("open('%s'): %s\n", fifo_path, strerror (-rc)); + return rc; + } - return 0; + return 0; } // thread for gathering error messages from the helpers and forwarding // them to our logging system. // *arg is an int, which is the error pipe to read from -void *vdev_error_thread_main(void *arg) +void * +vdev_error_thread_main (void *arg) { - int rc = 0; - int fd = *((int *)arg); - char buf[4096]; - ssize_t nr = 0; - int flags = 0; - fd_set read_fds; - - // put into non-blocking mode - flags = fcntl(fd, F_GETFL, 0); - if (flags < 0) { - rc = -errno; - vdev_error("fcntl(%d, F_GETFL): %s\n", fd, strerror(-rc)); - return NULL; - } + int rc = 0; + int fd = *((int *) arg); + char buf[4096]; + ssize_t nr = 0; + int flags = 0; + fd_set read_fds; - rc = fcntl(fd, F_SETFL, flags | O_NONBLOCK); - if (rc < 0) { - rc = -errno; - vdev_error("fctnl(%d, F_SETFL): %s\n", fd, strerror(-rc)); - return NULL; - } + // put into non-blocking mode + flags = fcntl (fd, F_GETFL, 0); + if (flags < 0) + { + rc = -errno; + vdev_error ("fcntl(%d, F_GETFL): %s\n", fd, strerror (-rc)); + return NULL; + } - while (1) { + rc = fcntl (fd, F_SETFL, flags | O_NONBLOCK); + if (rc < 0) + { + rc = -errno; + vdev_error ("fctnl(%d, F_SETFL): %s\n", fd, strerror (-rc)); + return NULL; + } - FD_ZERO(&read_fds); - FD_SET(fd, &read_fds); + while (1) + { - rc = select(fd + 1, &read_fds, NULL, NULL, NULL); - if (rc == 0) { + FD_ZERO (&read_fds); + FD_SET (fd, &read_fds); - // not ready - continue; - } + rc = select (fd + 1, &read_fds, NULL, NULL, NULL); + if (rc == 0) + { - if (rc < 0) { + // not ready + continue; + } - // pipe closed - break; - } + if (rc < 0) + { - nr = read(fd, buf, 4095); - if (nr <= 0) { + // pipe closed + break; + } - // closed, invalidated, etc. - break; - } - // truncate and log - buf[nr] = 0; + nr = read (fd, buf, 4095); + if (nr <= 0) + { - vdev_error("%s", buf); + // closed, invalidated, etc. + break; } + // truncate and log + buf[nr] = 0; + + vdev_error ("%s", buf); + } - return NULL; + return NULL; } // start the error-listining thread // return 0 on success, and set state->error_thread // return -errno on failure -int vdev_error_thread_start(struct vdev_state *vdev) +int +vdev_error_thread_start (struct vdev_state *vdev) { - int rc = 0; - pthread_attr_t attrs; + int rc = 0; + pthread_attr_t attrs; - rc = vdev_error_fifo_get_or_create(vdev->config->mountpoint, - &vdev->error_fd); - if (rc < 0) { + rc = vdev_error_fifo_get_or_create (vdev->config->mountpoint, + &vdev->error_fd); + if (rc < 0) + { - vdev_error("vdev_error_fifo_get_or_create: %s\n", - strerror(-rc)); - return rc; - } + vdev_error ("vdev_error_fifo_get_or_create: %s\n", strerror (-rc)); + return rc; + } - rc = pthread_attr_init(&attrs); - if (rc != 0) { + rc = pthread_attr_init (&attrs); + if (rc != 0) + { - vdev_error("pthread_attr_init: %s\n", strerror(rc)); - return -rc; - } + vdev_error ("pthread_attr_init: %s\n", strerror (rc)); + return -rc; + } - vdev->error_thread_running = true; + vdev->error_thread_running = true; - rc = pthread_create(&vdev->error_thread, &attrs, vdev_error_thread_main, - &vdev->error_fd); - if (rc != 0) { + rc = pthread_create (&vdev->error_thread, &attrs, vdev_error_thread_main, + &vdev->error_fd); + if (rc != 0) + { - vdev->error_thread_running = false; - vdev_error("pthread_crate: %s\n", strerror(rc)); - return -rc; - } + vdev->error_thread_running = false; + vdev_error ("pthread_crate: %s\n", strerror (rc)); + return -rc; + } - return 0; + return 0; } // stop the error-listening thread // return 0 on success -int vdev_error_thread_stop(struct vdev_state *vdev) +int +vdev_error_thread_stop (struct vdev_state *vdev) { - int rc = 0; - if (!vdev->error_thread_running) { - // already stopped - return 0; - } + int rc = 0; + if (!vdev->error_thread_running) + { + // already stopped + return 0; + } - if (vdev->error_fd >= 0) { + if (vdev->error_fd >= 0) + { - int fd = vdev->error_fd; - vdev->error_fd = -1; + int fd = vdev->error_fd; + vdev->error_fd = -1; - close(fd); - } + close (fd); + } - rc = pthread_cancel(vdev->error_thread); - if (rc != 0) { + rc = pthread_cancel (vdev->error_thread); + if (rc != 0) + { - vdev_error("pthread_cancel: %s\n", strerror(rc)); - } + vdev_error ("pthread_cancel: %s\n", strerror (rc)); + } - rc = pthread_join(vdev->error_thread, NULL); - if (rc != 0) { + rc = pthread_join (vdev->error_thread, NULL); + if (rc != 0) + { - vdev_error("pthread_join: %s\n", strerror(rc)); - } + vdev_error ("pthread_join: %s\n", strerror (rc)); + } - vdev->error_thread_running = false; + vdev->error_thread_running = false; - return 0; + return 0; } // start up the back-end // return 0 on success // return -ENOMEM on OOM // return negative if the OS-specific back-end fails to initialize -int vdev_start(struct vdev_state *vdev) +int +vdev_start (struct vdev_state *vdev) { - int rc = 0; + int rc = 0; - // otherwise, it's already given - vdev->running = true; + // otherwise, it's already given + vdev->running = true; - // initialize OS-specific state, and start feeding requests - vdev->os = VDEV_CALLOC(struct vdev_os_context, 1); + // initialize OS-specific state, and start feeding requests + vdev->os = VDEV_CALLOC (struct vdev_os_context, 1); - if (vdev->os == NULL) { + if (vdev->os == NULL) + { - return -ENOMEM; - } - // set up error capture - rc = vdev_error_thread_start(vdev); - if (rc != 0) { - - vdev_error("vdev_error_thread_start: %s\n", strerror(-rc)); - free(vdev->os); - vdev->os = NULL; - return rc; - } - // start processing requests - rc = vdev_wq_start(&vdev->device_wq); - if (rc != 0) { + return -ENOMEM; + } + // set up error capture + rc = vdev_error_thread_start (vdev); + if (rc != 0) + { - vdev_error("vdev_wq_start: %s\n", strerror(-rc)); + vdev_error ("vdev_error_thread_start: %s\n", strerror (-rc)); + free (vdev->os); + vdev->os = NULL; + return rc; + } + // start processing requests + rc = vdev_wq_start (&vdev->device_wq); + if (rc != 0) + { - int erc = vdev_error_thread_stop(vdev); - if (erc != 0) { + vdev_error ("vdev_wq_start: %s\n", strerror (-rc)); - vdev_error("vdev_error_thread_stop: %s\n", - strerror(-erc)); - } + int erc = vdev_error_thread_stop (vdev); + if (erc != 0) + { - free(vdev->os); - vdev->os = NULL; - return rc; + vdev_error ("vdev_error_thread_stop: %s\n", strerror (-erc)); } - rc = vdev_os_context_init(vdev->os, vdev); + free (vdev->os); + vdev->os = NULL; + return rc; + } - if (rc != 0) { + rc = vdev_os_context_init (vdev->os, vdev); - vdev_error("vdev_os_context_init rc = %d\n", rc); + if (rc != 0) + { - int wqrc = vdev_wq_stop(&vdev->device_wq, false); - if (wqrc != 0) { + vdev_error ("vdev_os_context_init rc = %d\n", rc); - vdev_error("vdev_wq_stop rc = %d\n", wqrc); - } + int wqrc = vdev_wq_stop (&vdev->device_wq, false); + if (wqrc != 0) + { - vdev_error_thread_stop(vdev); - free(vdev->os); - vdev->os = NULL; - return rc; + vdev_error ("vdev_wq_stop rc = %d\n", wqrc); } - return 0; + vdev_error_thread_stop (vdev); + free (vdev->os); + vdev->os = NULL; + return rc; + } + + return 0; } // process a single line of text into a device request @@ -567,166 +616,184 @@ int vdev_start(struct vdev_state *vdev) // return -ENOENT if we're missing a parameter // return -EINVAL if the parameter is malformed // return -ENOMEM on OOM -int vdev_parse_device_request(struct vdev_state *state, - struct vdev_device_request *vreq, char *line) +int +vdev_parse_device_request (struct vdev_state *state, + struct vdev_device_request *vreq, char *line) { - int rc = 0; - int stat_rc; - char *tok = NULL; - char *tokstr = line; - char *tok_ctx = NULL; - char *tmp = NULL; - - mode_t mode = 0; - dev_t major = 0; - dev_t minor = 0; - char name[4097]; - char fullpath[PATH_MAX + 1]; - char keyvalue_buf[4097]; - char *key = NULL; - char *value = NULL; - - struct stat sb; - - // type - tok = strtok_r(tokstr, " \t", &tok_ctx); - tokstr = NULL; - - if (tok == NULL) { - - // no type - fprintf(stderr, "Missing type\n"); - return -ENOENT; - } - - if (strlen(tok) != 1) { - - // invalid type - fprintf(stderr, - "Unrecognized type '%s'. Expected 'c', 'b', or 'u'\n", - tok); - return -EINVAL; - } - - if (tok[0] != 'c' && tok[0] != 'b' && tok[0] != 'u') { - - // invalid type - fprintf(stderr, - "Unrecognized type '%s'. Expected 'c', 'b', or 'u'\n", - tok); - return -EINVAL; - } - - if (tok[0] == 'c') { - mode = S_IFCHR; - } else if (tok[0] == 'b') { - mode = S_IFBLK; - } - // name - tok = strtok_r(tokstr, " \t", &tok_ctx); - if (tok == NULL) { - - // no name - fprintf(stderr, "Missing name\n"); - return -ENOENT; - } - - strcpy(name, tok); - - // major - tok = strtok_r(tokstr, " \t", &tok_ctx); - if (tok == NULL) { - - // no major - fprintf(stderr, "Missing major device number\n"); - return -ENOENT; - } - - major = (dev_t) strtoul(tok, &tmp, 10); - if (tmp == tok || *tmp != '\0') { - - // invalid major - fprintf(stderr, "Invalid major device number '%s'\n", tok); - return -EINVAL; - } - // minor - tok = strtok_r(tokstr, " \t", &tok_ctx); - if (tok == NULL) { - - // no minor - fprintf(stderr, "Missing minor device number\n"); - return -ENOENT; + int rc = 0; + int stat_rc; + char *tok = NULL; + char *tokstr = line; + char *tok_ctx = NULL; + char *tmp = NULL; + + mode_t mode = 0; + dev_t major = 0; + dev_t minor = 0; + char name[4097]; + char fullpath[PATH_MAX + 1]; + char keyvalue_buf[4097]; + char *key = NULL; + char *value = NULL; + + struct stat sb; + + // type + tok = strtok_r (tokstr, " \t", &tok_ctx); + tokstr = NULL; + + if (tok == NULL) + { + + // no type + fprintf (stderr, "Missing type\n"); + return -ENOENT; + } + + if (strlen (tok) != 1) + { + + // invalid type + fprintf (stderr, + "Unrecognized type '%s'. Expected 'c', 'b', or 'u'\n", tok); + return -EINVAL; + } + + if (tok[0] != 'c' && tok[0] != 'b' && tok[0] != 'u') + { + + // invalid type + fprintf (stderr, + "Unrecognized type '%s'. Expected 'c', 'b', or 'u'\n", tok); + return -EINVAL; + } + + if (tok[0] == 'c') + { + mode = S_IFCHR; + } + else if (tok[0] == 'b') + { + mode = S_IFBLK; + } + // name + tok = strtok_r (tokstr, " \t", &tok_ctx); + if (tok == NULL) + { + + // no name + fprintf (stderr, "Missing name\n"); + return -ENOENT; + } + + strcpy (name, tok); + + // major + tok = strtok_r (tokstr, " \t", &tok_ctx); + if (tok == NULL) + { + + // no major + fprintf (stderr, "Missing major device number\n"); + return -ENOENT; + } + + major = (dev_t) strtoul (tok, &tmp, 10); + if (tmp == tok || *tmp != '\0') + { + + // invalid major + fprintf (stderr, "Invalid major device number '%s'\n", tok); + return -EINVAL; + } + // minor + tok = strtok_r (tokstr, " \t", &tok_ctx); + if (tok == NULL) + { + + // no minor + fprintf (stderr, "Missing minor device number\n"); + return -ENOENT; + } + + minor = (dev_t) strtoul (tok, &tmp, 10); + if (tmp == tok || *tmp != '\0') + { + + // invalid minor + fprintf (stderr, "Invalid minor device number '%s'\n", tok); + return -EINVAL; + } + // set up the device... + rc = vdev_device_request_init (vreq, state, VDEV_DEVICE_ADD, name); + if (rc != 0) + { + + vdev_error ("vdev_device_request_init('%s') rc = %d\n", name, rc); + return rc; + } + + vdev_device_request_set_type (vreq, VDEV_DEVICE_ADD); + vdev_device_request_set_mode (vreq, mode); + vdev_device_request_set_dev (vreq, makedev (major, minor)); + + // parameters + while (tok != NULL) + { + + tok = strtok_r (tokstr, " \t", &tok_ctx); + if (tok == NULL) + { + break; + } + + if (strlen (tok) > 4096) + { + + // too big + fprintf (stderr, "OS parameter too long: '%s'\n", tok); + vdev_device_request_free (vreq); + return -EINVAL; + } + + strcpy (keyvalue_buf, tok); + + rc = vdev_keyvalue_next (keyvalue_buf, &key, &value); + if (rc < 0) + { + + // could not parse + fprintf (stderr, "Unparsible OS parameter: '%s'\n", tok); + vdev_device_request_free (vreq); + return -EINVAL; + } + + rc = vdev_device_request_add_param (vreq, key, value); + if (rc != 0) + { + + vdev_device_request_free (vreq); + return rc; } + } - minor = (dev_t) strtoul(tok, &tmp, 10); - if (tmp == tok || *tmp != '\0') { - - // invalid minor - fprintf(stderr, "Invalid minor device number '%s'\n", tok); - return -EINVAL; - } - // set up the device... - rc = vdev_device_request_init(vreq, state, VDEV_DEVICE_ADD, name); - if (rc != 0) { - - vdev_error("vdev_device_request_init('%s') rc = %d\n", name, - rc); - return rc; - } + // finally, does this device exist already? + snprintf (fullpath, PATH_MAX, "%s/%s", state->config->mountpoint, name); + stat_rc = lstat (fullpath, &sb); - vdev_device_request_set_type(vreq, VDEV_DEVICE_ADD); - vdev_device_request_set_mode(vreq, mode); - vdev_device_request_set_dev(vreq, makedev(major, minor)); + if (stat_rc == 0) + { - // parameters - while (tok != NULL) { - - tok = strtok_r(tokstr, " \t", &tok_ctx); - if (tok == NULL) { - break; - } - - if (strlen(tok) > 4096) { - - // too big - fprintf(stderr, "OS parameter too long: '%s'\n", tok); - vdev_device_request_free(vreq); - return -EINVAL; - } - - strcpy(keyvalue_buf, tok); - - rc = vdev_keyvalue_next(keyvalue_buf, &key, &value); - if (rc < 0) { - - // could not parse - fprintf(stderr, "Unparsible OS parameter: '%s'\n", tok); - vdev_device_request_free(vreq); - return -EINVAL; - } - - rc = vdev_device_request_add_param(vreq, key, value); - if (rc != 0) { - - vdev_device_request_free(vreq); - return rc; - } - } + vdev_device_request_set_exists (vreq, true); + } + else + { - // finally, does this device exist already? - snprintf(fullpath, PATH_MAX, "%s/%s", state->config->mountpoint, name); - stat_rc = lstat(fullpath, &sb); + vdev_device_request_set_exists (vreq, false); + } - if (stat_rc == 0) { - - vdev_device_request_set_exists(vreq, true); - } else { - - vdev_device_request_set_exists(vreq, false); - } - - return rc; + return rc; } // process a newline-delimited textual list of device events. @@ -744,100 +811,111 @@ int vdev_parse_device_request(struct vdev_state *state, // NOTE: currently, we do not tolerate spaces in any of these fields. Sorry. // return 0 on success // return -ERANGE if a line exceeded 4096 characters -int vdev_load_device_requests(struct vdev_state *state, char *text_buf, - size_t text_buflen) +int +vdev_load_device_requests (struct vdev_state *state, char *text_buf, + size_t text_buflen) { - int rc = 0; - char *cur_line = NULL; - char *next_line = NULL; + int rc = 0; + char *cur_line = NULL; + char *next_line = NULL; - struct vdev_device_request *vreq = NULL; + struct vdev_device_request *vreq = NULL; - size_t consumed = 0; - size_t line_len = 0; - char line_buf[4097]; - char line_buf_dbg[4097]; // for debugging + size_t consumed = 0; + size_t line_len = 0; + char line_buf[4097]; + char line_buf_dbg[4097]; // for debugging - dev_t major = 0; - dev_t minor = 0; + dev_t major = 0; + dev_t minor = 0; - cur_line = text_buf; - while (consumed < text_buflen && cur_line != NULL) { + cur_line = text_buf; + while (consumed < text_buflen && cur_line != NULL) + { - next_line = strchr(cur_line, '\n'); - if (next_line == NULL) { + next_line = strchr (cur_line, '\n'); + if (next_line == NULL) + { - line_len = strlen(cur_line); + line_len = strlen (cur_line); - if (line_len == 0) { - // done - break; - } - // last line - if (line_len < 4096) { + if (line_len == 0) + { + // done + break; + } + // last line + if (line_len < 4096) + { - strcpy(line_buf, cur_line); - } else { + strcpy (line_buf, cur_line); + } + else + { - // too big - return -ERANGE; - } - } else { + // too big + return -ERANGE; + } + } + else + { - // copy until '\n' - line_len = - (size_t) (next_line - cur_line) / sizeof(char); - memcpy(line_buf, cur_line, line_len); + // copy until '\n' + line_len = (size_t) (next_line - cur_line) / sizeof (char); + memcpy (line_buf, cur_line, line_len); - line_buf[line_len] = '\0'; - } + line_buf[line_len] = '\0'; + } - vdev_debug("Preseed device: '%s'\n", line_buf); + vdev_debug ("Preseed device: '%s'\n", line_buf); - strcpy(line_buf_dbg, line_buf); + strcpy (line_buf_dbg, line_buf); - vreq = VDEV_CALLOC(struct vdev_device_request, 1); - if (vreq == NULL) { + vreq = VDEV_CALLOC (struct vdev_device_request, 1); + if (vreq == NULL) + { - // OOM - return -ENOMEM; - } - // consume the line - rc = vdev_parse_device_request(state, vreq, line_buf); - if (rc != 0) { + // OOM + return -ENOMEM; + } + // consume the line + rc = vdev_parse_device_request (state, vreq, line_buf); + if (rc != 0) + { - fprintf(stderr, "Could not parse line '%s' (rc = %d)\n", - line_buf_dbg, rc); - vdev_error("vdev_parse_device_request('%s') rc = %d\n", - line_buf_dbg, rc); + fprintf (stderr, "Could not parse line '%s' (rc = %d)\n", + line_buf_dbg, rc); + vdev_error ("vdev_parse_device_request('%s') rc = %d\n", + line_buf_dbg, rc); - free(vreq); - return rc; - } - // enqueue the device! - rc = vdev_device_request_enqueue(&state->device_wq, vreq); - if (rc != 0) { + free (vreq); + return rc; + } + // enqueue the device! + rc = vdev_device_request_enqueue (&state->device_wq, vreq); + if (rc != 0) + { - vdev_error - ("vdev_device_request_enqueue('%s') rc = %d\n", - line_buf_dbg, rc); + vdev_error + ("vdev_device_request_enqueue('%s') rc = %d\n", line_buf_dbg, rc); - free(vreq); - return rc; - } - // next line - cur_line = next_line; - consumed += strlen(next_line); + free (vreq); + return rc; + } + // next line + cur_line = next_line; + consumed += strlen (next_line); - while (consumed < text_buflen && *cur_line == '\n') { + while (consumed < text_buflen && *cur_line == '\n') + { - cur_line++; - consumed++; - } + cur_line++; + consumed++; } + } - return rc; + return rc; } // run the pre-seed command, if given @@ -845,442 +923,488 @@ int vdev_load_device_requests(struct vdev_state *state, char *text_buf, // return -ENOMEM on OOM // return non-zero on non-zero exit status // TODO: "unlimited" output buffer space--like a pipe -int vdev_preseed_run(struct vdev_state *vdev) +int +vdev_preseed_run (struct vdev_state *vdev) { - int rc = 0; - int exit_status = 0; - char *command = NULL; - - size_t output_len = 1024 * 1024; // 1MB buffer for initial devices, just in case - char *output = NULL; - - if (vdev->config->preseed_path == NULL) { - // nothing to do - return 0; - } - - output = VDEV_CALLOC(char, output_len); - if (output == NULL) { - - // OOM - return -ENOMEM; - } - - command = - VDEV_CALLOC(char, - strlen(vdev->config->preseed_path) + 2 + - strlen(vdev->config->mountpoint) + 2 + - strlen(vdev->config->config_path) + 1); - if (command == NULL) { - - // OOM - free(output); - return -ENOMEM; - } - - sprintf(command, "%s %s %s", vdev->config->preseed_path, - vdev->config->mountpoint, vdev->config->config_path); - - rc = vdev_subprocess(command, NULL, &output, output_len, -1, - &exit_status, true); - if (rc != 0) { - - vdev_error("vdev_subprocess('%s') rc = %d\n", command, rc); - } else if (exit_status != 0) { - - vdev_error("vdev_subprocess('%s') exit status %d\n", command, - exit_status); - rc = exit_status; - } - - free(command); - command = NULL; - - if (rc != 0) { - - free(output); - return rc; - } - // process the preseed devices... - rc = vdev_load_device_requests(vdev, output, output_len); - if (rc != 0) { - - vdev_error("vdev_load_device_requests rc = %d\n", rc); - } - - free(output); - output = NULL; - - return rc; + int rc = 0; + int exit_status = 0; + char *command = NULL; + + size_t output_len = 1024 * 1024; // 1MB buffer for initial devices, just in case + char *output = NULL; + + if (vdev->config->preseed_path == NULL) + { + // nothing to do + return 0; + } + + output = VDEV_CALLOC (char, output_len); + if (output == NULL) + { + + // OOM + return -ENOMEM; + } + + command = + VDEV_CALLOC (char, + strlen (vdev->config->preseed_path) + 2 + + strlen (vdev->config->mountpoint) + 2 + + strlen (vdev->config->config_path) + 1); + if (command == NULL) + { + + // OOM + free (output); + return -ENOMEM; + } + + sprintf (command, "%s %s %s", vdev->config->preseed_path, + vdev->config->mountpoint, vdev->config->config_path); + + rc = vdev_subprocess (command, NULL, &output, output_len, -1, + &exit_status, true); + if (rc != 0) + { + + vdev_error ("vdev_subprocess('%s') rc = %d\n", command, rc); + } + else if (exit_status != 0) + { + + vdev_error ("vdev_subprocess('%s') exit status %d\n", command, + exit_status); + rc = exit_status; + } + + free (command); + command = NULL; + + if (rc != 0) + { + + free (output); + return rc; + } + // process the preseed devices... + rc = vdev_load_device_requests (vdev, output, output_len); + if (rc != 0) + { + + vdev_error ("vdev_load_device_requests rc = %d\n", rc); + } + + free (output); + output = NULL; + + return rc; } // global vdev initialization -int vdev_init(struct vdev_state *vdev, int argc, char **argv) +int +vdev_init (struct vdev_state *vdev, int argc, char **argv) { - int rc = 0; + int rc = 0; - // global setup - vdev_setup_global(); + // global setup + vdev_setup_global (); - pthread_mutex_init(&vdev->reload_lock, NULL); - vdev->error_fd = -1; - vdev->coldplug_finished_fd = -1; + pthread_mutex_init (&vdev->reload_lock, NULL); + vdev->error_fd = -1; + vdev->coldplug_finished_fd = -1; - // config... - vdev->config = VDEV_CALLOC(struct vdev_config, 1); - if (vdev->config == NULL) { + // config... + vdev->config = VDEV_CALLOC (struct vdev_config, 1); + if (vdev->config == NULL) + { - return -ENOMEM; - } - // config init - rc = vdev_config_init(vdev->config); - if (rc != 0) { + return -ENOMEM; + } + // config init + rc = vdev_config_init (vdev->config); + if (rc != 0) + { - vdev_error("vdev_config_init rc = %d\n", rc); - return rc; - } - // parse config options from command-line - rc = vdev_config_load_from_args(vdev->config, argc, argv, NULL, NULL); - // help is not an error - if (rc == -2) { + vdev_error ("vdev_config_init rc = %d\n", rc); + return rc; + } + // parse config options from command-line + rc = vdev_config_load_from_args (vdev->config, argc, argv, NULL, NULL); + // help is not an error + if (rc == -2) + { - vdev_config_usage(argv[0]); + vdev_config_usage (argv[0]); - return 0; + return 0; - } + } - if (rc != 0) { + if (rc != 0) + { - vdev_error("vdev_config_load_from_argv rc = %d\n", rc); + vdev_error ("vdev_config_load_from_argv rc = %d\n", rc); - vdev_config_usage(argv[0]); + vdev_config_usage (argv[0]); - return rc; - } - // if we didn't get a config file, use the default one - if (vdev->config->config_path == NULL) { + return rc; + } + // if we didn't get a config file, use the default one + if (vdev->config->config_path == NULL) + { - vdev->config->config_path = - vdev_strdup_or_null(VDEV_CONFIG_FILE); - if (vdev->config->config_path == NULL) { + vdev->config->config_path = vdev_strdup_or_null (VDEV_CONFIG_FILE); + if (vdev->config->config_path == NULL) + { - // OOM - return -ENOMEM; - } + // OOM + return -ENOMEM; } + } - vdev_set_debug_level(vdev->config->debug_level); - vdev_set_error_level(vdev->config->error_level); - - vdev_info("Config file: '%s'\n", vdev->config->config_path); - vdev_info("Log debug level: '%s'\n", - (vdev->config->debug_level == - VDEV_LOGLEVEL_DEBUG ? "debug" : (vdev->config->debug_level == - VDEV_LOGLEVEL_INFO ? "info" - : "none"))); - vdev_info("Log error level: '%s'\n", - (vdev->config->error_level == - VDEV_LOGLEVEL_WARN ? "warning" : (vdev-> - config->error_level == - VDEV_LOGLEVEL_ERROR ? - "error" : "none"))); - - // load from file... - rc = vdev_config_load(vdev->config->config_path, vdev->config); - if (rc != 0) { - - vdev_error("vdev_config_load('%s') rc = %d\n", - vdev->config->config_path, rc); - - return rc; - } - // if no command-line loglevel is given, then take it from the config file (if given) - if (vdev->config->debug_level != VDEV_LOGLEVEL_NONE) { + vdev_set_debug_level (vdev->config->debug_level); + vdev_set_error_level (vdev->config->error_level); - vdev_set_debug_level(vdev->config->debug_level); - } + vdev_info ("Config file: '%s'\n", vdev->config->config_path); + vdev_info ("Log debug level: '%s'\n", + (vdev->config->debug_level == + VDEV_LOGLEVEL_DEBUG ? "debug" : (vdev->config->debug_level == + VDEV_LOGLEVEL_INFO ? "info" + : "none"))); + vdev_info ("Log error level: '%s'\n", + (vdev->config->error_level == + VDEV_LOGLEVEL_WARN ? "warning" : (vdev->config->error_level == + VDEV_LOGLEVEL_ERROR ? + "error" : "none"))); - if (vdev->config->error_level != VDEV_LOGLEVEL_NONE) { + // load from file... + rc = vdev_config_load (vdev->config->config_path, vdev->config); + if (rc != 0) + { - vdev_set_error_level(vdev->config->error_level); - } + vdev_error ("vdev_config_load('%s') rc = %d\n", + vdev->config->config_path, rc); - vdev_info("vdev actions dir: '%s'\n", vdev->config->acts_dir); - vdev_info("helpers dir: '%s'\n", vdev->config->helpers_dir); - vdev_info("logfile path: '%s'\n", vdev->config->logfile_path); - vdev_info("pidfile path: '%s'\n", vdev->config->pidfile_path); - vdev_info("default mode: 0%o\n", vdev->config->default_mode); - vdev_info("preseed script: '%s'\n", vdev->config->preseed_path); + return rc; + } + // if no command-line loglevel is given, then take it from the config file (if given) + if (vdev->config->debug_level != VDEV_LOGLEVEL_NONE) + { - vdev->mountpoint = vdev_strdup_or_null(vdev->config->mountpoint); - vdev->coldplug_only = vdev->config->coldplug_only; + vdev_set_debug_level (vdev->config->debug_level); + } - if (vdev->mountpoint == NULL) { + if (vdev->config->error_level != VDEV_LOGLEVEL_NONE) + { - vdev_error - ("Failed to set mountpoint, config->mountpount = '%s'\n", - vdev->config->mountpoint); + vdev_set_error_level (vdev->config->error_level); + } - return -EINVAL; - } else { + vdev_info ("vdev actions dir: '%s'\n", vdev->config->acts_dir); + vdev_info ("helpers dir: '%s'\n", vdev->config->helpers_dir); + vdev_info ("logfile path: '%s'\n", vdev->config->logfile_path); + vdev_info ("pidfile path: '%s'\n", vdev->config->pidfile_path); + vdev_info ("default mode: 0%o\n", vdev->config->default_mode); + vdev_info ("preseed script: '%s'\n", vdev->config->preseed_path); - vdev_info("mountpoint: '%s'\n", vdev->mountpoint); - } + vdev->mountpoint = vdev_strdup_or_null (vdev->config->mountpoint); + vdev->coldplug_only = vdev->config->coldplug_only; + + if (vdev->mountpoint == NULL) + { - vdev->argc = argc; - vdev->argv = argv; + vdev_error + ("Failed to set mountpoint, config->mountpount = '%s'\n", + vdev->config->mountpoint); - // load actions - rc = vdev_action_load_all(vdev->config, &vdev->acts, &vdev->num_acts); - if (rc != 0) { + return -EINVAL; + } + else + { - vdev_error("vdev_action_load_all('%s') rc = %d\n", - vdev->config->acts_dir, rc); + vdev_info ("mountpoint: '%s'\n", vdev->mountpoint); + } - return rc; - } - // initialize request work queue - rc = vdev_wq_init(&vdev->device_wq, vdev); - if (rc != 0) { + vdev->argc = argc; + vdev->argv = argv; - vdev_error("vdev_wq_init rc = %d\n", rc); + // load actions + rc = vdev_action_load_all (vdev->config, &vdev->acts, &vdev->num_acts); + if (rc != 0) + { - return rc; - } + vdev_error ("vdev_action_load_all('%s') rc = %d\n", + vdev->config->acts_dir, rc); + + return rc; + } + // initialize request work queue + rc = vdev_wq_init (&vdev->device_wq, vdev); + if (rc != 0) + { + + vdev_error ("vdev_wq_init rc = %d\n", rc); - return 0; + return rc; + } + + return 0; } // main loop for the back-end // takes a file descriptor to be written to once coldplug processing has finished. // return 0 on success // return -errno on failure to daemonize, or abnormal OS-specific back-end failure -int vdev_main(struct vdev_state *vdev, int coldplug_finished_fd) +int +vdev_main (struct vdev_state *vdev, int coldplug_finished_fd) { - int rc = 0; + int rc = 0; - vdev->coldplug_finished_fd = coldplug_finished_fd; + vdev->coldplug_finished_fd = coldplug_finished_fd; - char *metadata_dir = - vdev_device_metadata_fullpath(vdev->mountpoint, ""); - if (metadata_dir == NULL) { + char *metadata_dir = vdev_device_metadata_fullpath (vdev->mountpoint, ""); + if (metadata_dir == NULL) + { - return -ENOMEM; - } - // create metadata directory - rc = vdev_mkdirs(metadata_dir, 0, 0755); + return -ENOMEM; + } + // create metadata directory + rc = vdev_mkdirs (metadata_dir, 0, 0755); - if (rc != 0) { + if (rc != 0) + { - vdev_error("vdev_mkdirs('%s') rc = %d\n", metadata_dir, rc); + vdev_error ("vdev_mkdirs('%s') rc = %d\n", metadata_dir, rc); - free(metadata_dir); - return rc; - } + free (metadata_dir); + return rc; + } - free(metadata_dir); + free (metadata_dir); - rc = vdev_os_main(vdev->os); + rc = vdev_os_main (vdev->os); - return rc; + return rc; } // signal that we've processed all coldplug devices -int vdev_signal_coldplug_finished(struct vdev_state *vdev, int status) +int +vdev_signal_coldplug_finished (struct vdev_state *vdev, int status) { - if (vdev->coldplug_finished_fd > 0) { - write(vdev->coldplug_finished_fd, &status, sizeof(status)); - close(vdev->coldplug_finished_fd); - vdev->coldplug_finished_fd = -1; - } + if (vdev->coldplug_finished_fd > 0) + { + write (vdev->coldplug_finished_fd, &status, sizeof (status)); + close (vdev->coldplug_finished_fd); + vdev->coldplug_finished_fd = -1; + } - return 0; + return 0; } // prevent reload -int vdev_reload_lock(struct vdev_state *vdev) +int +vdev_reload_lock (struct vdev_state *vdev) { - return pthread_mutex_lock(&vdev->reload_lock); + return pthread_mutex_lock (&vdev->reload_lock); } // allow reload -int vdev_reload_unlock(struct vdev_state *vdev) +int +vdev_reload_unlock (struct vdev_state *vdev) { - return pthread_mutex_unlock(&vdev->reload_lock); + return pthread_mutex_unlock (&vdev->reload_lock); } // do a reload // return 0 on success, and replace the config and actions, atomically // return -errno on failure, and do nothing to vdev -int vdev_reload(struct vdev_state *vdev) +int +vdev_reload (struct vdev_state *vdev) { - int rc = 0; - struct vdev_config *config = NULL; - struct vdev_action *acts = NULL; - size_t num_acts = 0; - - struct vdev_config *old_config = NULL; - struct vdev_action *old_acts = NULL; - size_t old_num_acts = 0; - - config = VDEV_CALLOC(struct vdev_config, 1); - if (config == NULL) { - return -ENOMEM; - } - // config init - rc = vdev_config_init(config); - if (rc != 0) { - - vdev_error("vdev_config_init rc = %d\n", rc); - return rc; - } - - if (config->config_path == NULL) { - // default - config->config_path = vdev_strdup_or_null(VDEV_CONFIG_FILE); - if (config->config_path == NULL) { - - vdev_config_free(config); - free(config); - return -ENOMEM; - } - } - // parse config options from command-line - rc = vdev_config_load_from_args(config, vdev->argc, vdev->argv, NULL, - NULL); - if (rc != 0) { - - vdev_error("vdev_config_load_from_argv rc = %d\n", rc); - return rc; - } - // load from file... - rc = vdev_config_load(config->config_path, config); - if (rc != 0) { - - vdev_error("vdev_config_load('%s') rc = %d\n", - config->config_path, rc); - - vdev_config_free(config); - free(config); - return rc; - } - // load actions - rc = vdev_action_load_all(config, &acts, &num_acts); - if (rc != 0) { - - vdev_error("vdev_action_load_all('%s') rc = %d\n", - config->acts_dir, rc); - - vdev_config_free(config); - free(config); - return rc; - } - // install them - vdev_reload_lock(vdev); - - old_config = vdev->config; - vdev->config = config; - - old_acts = vdev->acts; - old_num_acts = vdev->num_acts; - vdev->acts = acts; - vdev->num_acts = num_acts; - - vdev_reload_unlock(vdev); - - // free old state - vdev_config_free(old_config); - free(old_config); - - vdev_action_free_all(old_acts, old_num_acts); - - return rc; + int rc = 0; + struct vdev_config *config = NULL; + struct vdev_action *acts = NULL; + size_t num_acts = 0; + + struct vdev_config *old_config = NULL; + struct vdev_action *old_acts = NULL; + size_t old_num_acts = 0; + + config = VDEV_CALLOC (struct vdev_config, 1); + if (config == NULL) + { + return -ENOMEM; + } + // config init + rc = vdev_config_init (config); + if (rc != 0) + { + + vdev_error ("vdev_config_init rc = %d\n", rc); + return rc; + } + + if (config->config_path == NULL) + { + // default + config->config_path = vdev_strdup_or_null (VDEV_CONFIG_FILE); + if (config->config_path == NULL) + { + + vdev_config_free (config); + free (config); + return -ENOMEM; + } + } + // parse config options from command-line + rc = vdev_config_load_from_args (config, vdev->argc, vdev->argv, NULL, + NULL); + if (rc != 0) + { + + vdev_error ("vdev_config_load_from_argv rc = %d\n", rc); + return rc; + } + // load from file... + rc = vdev_config_load (config->config_path, config); + if (rc != 0) + { + + vdev_error ("vdev_config_load('%s') rc = %d\n", + config->config_path, rc); + + vdev_config_free (config); + free (config); + return rc; + } + // load actions + rc = vdev_action_load_all (config, &acts, &num_acts); + if (rc != 0) + { + + vdev_error ("vdev_action_load_all('%s') rc = %d\n", + config->acts_dir, rc); + + vdev_config_free (config); + free (config); + return rc; + } + // install them + vdev_reload_lock (vdev); + + old_config = vdev->config; + vdev->config = config; + + old_acts = vdev->acts; + old_num_acts = vdev->num_acts; + vdev->acts = acts; + vdev->num_acts = num_acts; + + vdev_reload_unlock (vdev); + + // free old state + vdev_config_free (old_config); + free (old_config); + + vdev_action_free_all (old_acts, old_num_acts); + + return rc; } // stop vdev // NOTE: if this fails, there's not really a way to recover // return 0 on success // return non-zero if we failed to stop the work queue -int vdev_stop(struct vdev_state *vdev) +int +vdev_stop (struct vdev_state *vdev) { - int rc = 0; - bool wait_for_empty = false; + int rc = 0; + bool wait_for_empty = false; - if (!vdev->running) { - return -EINVAL; - } + if (!vdev->running) + { + return -EINVAL; + } - vdev->running = false; - wait_for_empty = vdev->coldplug_only; // wait for the queue to drain if running coldplug only + vdev->running = false; + wait_for_empty = vdev->coldplug_only; // wait for the queue to drain if running coldplug only - // stop processing requests - rc = vdev_wq_stop(&vdev->device_wq, wait_for_empty); - if (rc != 0) { + // stop processing requests + rc = vdev_wq_stop (&vdev->device_wq, wait_for_empty); + if (rc != 0) + { - vdev_error("vdev_wq_stop: %s\n", strerror(-rc)); - return rc; - } - // stop all actions' daemonlets - vdev_action_daemonlet_stop_all(vdev->acts, vdev->num_acts); - return rc; + vdev_error ("vdev_wq_stop: %s\n", strerror (-rc)); + return rc; + } + // stop all actions' daemonlets + vdev_action_daemonlet_stop_all (vdev->acts, vdev->num_acts); + return rc; } // free up vdev. // only call after vdev_stop(). // return 0 on success, and print out benchmarks // return -EINVAL if we're still running. -int vdev_shutdown(struct vdev_state *vdev, bool unlink_pidfile) +int +vdev_shutdown (struct vdev_state *vdev, bool unlink_pidfile) { - if (vdev->running) { - return -EINVAL; - } + if (vdev->running) + { + return -EINVAL; + } - vdev_debug("%s", "vdev shutdown\n"); + vdev_debug ("%s", "vdev shutdown\n"); - // stop error thread--all daemonlets should be dead anyway - int erc = vdev_error_thread_stop(vdev); - if (erc != 0) { + // stop error thread--all daemonlets should be dead anyway + int erc = vdev_error_thread_stop (vdev); + if (erc != 0) + { - vdev_error("vdev_error_thread_stop: %s\n", strerror(-erc)); - } - // remove the PID file, if we have one - if (vdev->config->pidfile_path != NULL && unlink_pidfile) { - unlink(vdev->config->pidfile_path); - } + vdev_error ("vdev_error_thread_stop: %s\n", strerror (-erc)); + } + // remove the PID file, if we have one + if (vdev->config->pidfile_path != NULL && unlink_pidfile) + { + unlink (vdev->config->pidfile_path); + } - vdev_action_free_all(vdev->acts, vdev->num_acts); + vdev_action_free_all (vdev->acts, vdev->num_acts); - vdev->acts = NULL; - vdev->num_acts = 0; + vdev->acts = NULL; + vdev->num_acts = 0; - if (vdev->os != NULL) { - vdev_os_context_free(vdev->os); - free(vdev->os); - vdev->os = NULL; - } + if (vdev->os != NULL) + { + vdev_os_context_free (vdev->os); + free (vdev->os); + vdev->os = NULL; + } - if (vdev->config != NULL) { - vdev_config_free(vdev->config); - free(vdev->config); - vdev->config = NULL; - } + if (vdev->config != NULL) + { + vdev_config_free (vdev->config); + free (vdev->config); + vdev->config = NULL; + } - vdev_wq_free(&vdev->device_wq); + vdev_wq_free (&vdev->device_wq); - if (vdev->mountpoint != NULL) { - free(vdev->mountpoint); - vdev->mountpoint = NULL; - } + if (vdev->mountpoint != NULL) + { + free (vdev->mountpoint); + vdev->mountpoint = NULL; + } - pthread_mutex_destroy(&vdev->reload_lock); + pthread_mutex_destroy (&vdev->reload_lock); - return 0; + return 0; } diff --git a/vdevd/vdev.h b/vdevd/vdev.h index 3fd0f1d..b7aa73e 100644 --- a/vdevd/vdev.h +++ b/vdevd/vdev.h @@ -33,74 +33,74 @@ #endif // global vdev state -struct vdev_state { +struct vdev_state +{ - // configuration (covered by reload_lock) - struct vdev_config *config; + // configuration (covered by reload_lock) + struct vdev_config *config; - // arguments - int argc; - char **argv; + // arguments + int argc; + char **argv; - // mountpoint; where /dev is - char *mountpoint; + // mountpoint; where /dev is + char *mountpoint; - // OS context - struct vdev_os_context *os; + // OS context + struct vdev_os_context *os; - // actions (covered by reload_lock) - struct vdev_action *acts; - size_t num_acts; + // actions (covered by reload_lock) + struct vdev_action *acts; + size_t num_acts; - // pending requests - struct vdev_pending_context *pending; + // pending requests + struct vdev_pending_context *pending; - // device processing workqueue (back-end) - struct vdev_wq device_wq; + // device processing workqueue (back-end) + struct vdev_wq device_wq; - // are we taking events from the OS? (back-end) - bool running; + // are we taking events from the OS? (back-end) + bool running; - // coldplug only? - bool coldplug_only; + // coldplug only? + bool coldplug_only; - // fd to signal the end of coldplug - int coldplug_finished_fd; + // fd to signal the end of coldplug + int coldplug_finished_fd; - // error thread that listens to an error FIFO - // that helper processes use to send error - // messages to vdev's log - bool error_thread_running; - pthread_t error_thread; + // error thread that listens to an error FIFO + // that helper processes use to send error + // messages to vdev's log + bool error_thread_running; + pthread_t error_thread; - // fd to the error pipe, to be passed to subprocesses - // in place of stderr - int error_fd; + // fd to the error pipe, to be passed to subprocesses + // in place of stderr + int error_fd; - // reload lock--held when reloading the config - pthread_mutex_t reload_lock; + // reload lock--held when reloading the config + pthread_mutex_t reload_lock; }; typedef char *cstr; -C_LINKAGE_BEGIN -int vdev_init(struct vdev_state *vdev, int argc, char **argv); -int vdev_start(struct vdev_state *vdev); -int vdev_main(struct vdev_state *vdev, int flush_fd); -int vdev_reload(struct vdev_state *vdev); -int vdev_stop(struct vdev_state *vdev); -int vdev_shutdown(struct vdev_state *vdev, bool unlink_pidfile); +C_LINKAGE_BEGIN int vdev_init (struct vdev_state *vdev, int argc, + char **argv); +int vdev_start (struct vdev_state *vdev); +int vdev_main (struct vdev_state *vdev, int flush_fd); +int vdev_reload (struct vdev_state *vdev); +int vdev_stop (struct vdev_state *vdev); +int vdev_shutdown (struct vdev_state *vdev, bool unlink_pidfile); -int vdev_reload_lock(struct vdev_state *vdev); -int vdev_reload_unlock(struct vdev_state *vdev); +int vdev_reload_lock (struct vdev_state *vdev); +int vdev_reload_unlock (struct vdev_state *vdev); -int vdev_error_fifo_path(char const *mountpoint, char *path, size_t path_len); -int vdev_signal_coldplug_finished(struct vdev_state *state, int status); +int vdev_error_fifo_path (char const *mountpoint, char *path, + size_t path_len); +int vdev_signal_coldplug_finished (struct vdev_state *state, int status); -int vdev_preseed_run(struct vdev_state *state); -int vdev_remove_unplugged_devices(struct vdev_state *state); +int vdev_preseed_run (struct vdev_state *state); +int vdev_remove_unplugged_devices (struct vdev_state *state); -SGLIB_DEFINE_VECTOR_PROTOTYPES(cstr) - -C_LINKAGE_END +SGLIB_DEFINE_VECTOR_PROTOTYPES (cstr) C_LINKAGE_END #endif diff --git a/vdevd/workqueue.c b/vdevd/workqueue.c index 9254534..0cb2e39 100644 --- a/vdevd/workqueue.c +++ b/vdevd/workqueue.c @@ -25,155 +25,172 @@ #include "vdev.h" // wait for the queue to be drained of coldplug events -static void vdev_wq_wait_for_empty(struct vdev_wq *wq) +static void +vdev_wq_wait_for_empty (struct vdev_wq *wq) { - pthread_mutex_lock(&wq->waiter_lock); + pthread_mutex_lock (&wq->waiter_lock); - wq->num_waiters++; + wq->num_waiters++; - pthread_mutex_unlock(&wq->waiter_lock); + pthread_mutex_unlock (&wq->waiter_lock); - sem_wait(&wq->end_sem); + sem_wait (&wq->end_sem); } // signal any waiting threads that the queue has been drained of coldplug events -static void vdev_wq_signal_empty(struct vdev_wq *wq) +static void +vdev_wq_signal_empty (struct vdev_wq *wq) { - volatile int num_waiters = 0; + volatile int num_waiters = 0; - pthread_mutex_lock(&wq->waiter_lock); + pthread_mutex_lock (&wq->waiter_lock); - num_waiters = wq->num_waiters; - wq->num_waiters = 0; + num_waiters = wq->num_waiters; + wq->num_waiters = 0; - pthread_mutex_unlock(&wq->waiter_lock); + pthread_mutex_unlock (&wq->waiter_lock); - for (int i = 0; i < num_waiters; i++) { + for (int i = 0; i < num_waiters; i++) + { - sem_post(&wq->end_sem); - } + sem_post (&wq->end_sem); + } } // work queue main method // always succeeds -static void *vdev_wq_main(void *cls) +static void * +vdev_wq_main (void *cls) { - struct vdev_wq *wq = (struct vdev_wq *)cls; + struct vdev_wq *wq = (struct vdev_wq *) cls; - struct vdev_wreq *work_itr = NULL; - struct vdev_wreq *next = NULL; + struct vdev_wreq *work_itr = NULL; + struct vdev_wreq *next = NULL; - struct vdev_state *state = wq->state; + struct vdev_state *state = wq->state; - bool coldplug_finished = false; + bool coldplug_finished = false; - int rc = 0; + int rc = 0; - while (wq->running) { + while (wq->running) + { - // is there work? - rc = sem_trywait(&wq->work_sem); - if (rc != 0) { + // is there work? + rc = sem_trywait (&wq->work_sem); + if (rc != 0) + { - rc = -errno; - if (rc == -EAGAIN) { + rc = -errno; + if (rc == -EAGAIN) + { - // wait for work - sem_wait(&wq->work_sem); - } else { + // wait for work + sem_wait (&wq->work_sem); + } + else + { - // some other fatal error - vdev_error("FATAL: sem_trywait rc = %d\n", rc); - break; - } - } - // cancelled? - if (!wq->running) { - break; - } - // we have work to do - pthread_mutex_lock(&wq->work_lock); + // some other fatal error + vdev_error ("FATAL: sem_trywait rc = %d\n", rc); + break; + } + } + // cancelled? + if (!wq->running) + { + break; + } + // we have work to do + pthread_mutex_lock (&wq->work_lock); - work_itr = wq->work; - wq->work = NULL; - wq->tail = NULL; + work_itr = wq->work; + wq->work = NULL; + wq->tail = NULL; - pthread_mutex_unlock(&wq->work_lock); + pthread_mutex_unlock (&wq->work_lock); - if (!coldplug_finished) { - coldplug_finished = - vdev_os_context_is_coldplug_finished(state->os); - } + if (!coldplug_finished) + { + coldplug_finished = + vdev_os_context_is_coldplug_finished (state->os); + } - if (work_itr == NULL) { + if (work_itr == NULL) + { - vdev_wq_signal_empty(wq); + vdev_wq_signal_empty (wq); - if (coldplug_finished) { + if (coldplug_finished) + { - // coldplug has finished! signal the parent to exit. - vdev_signal_coldplug_finished(state, 0); - } + // coldplug has finished! signal the parent to exit. + vdev_signal_coldplug_finished (state, 0); + } - continue; - } - // safe to use work buffer (we'll clear it out in the process) - while (work_itr != NULL) { + continue; + } + // safe to use work buffer (we'll clear it out in the process) + while (work_itr != NULL) + { - // carry out work - rc = (*work_itr->work) (work_itr, work_itr->work_data); + // carry out work + rc = (*work_itr->work) (work_itr, work_itr->work_data); - if (rc != 0) { + if (rc != 0) + { - vdev_warn("work %p rc = %d\n", work_itr->work, - rc); - } + vdev_warn ("work %p rc = %d\n", work_itr->work, rc); + } - next = work_itr->next; + next = work_itr->next; - vdev_wreq_free(work_itr); - free(work_itr); + vdev_wreq_free (work_itr); + free (work_itr); - work_itr = next; - } + work_itr = next; } + } - return NULL; + return NULL; } // set up a work queue, but don't start it. // return 0 on success // return negative on failure: // * -ENOMEM if OOM -int vdev_wq_init(struct vdev_wq *wq, struct vdev_state *state) +int +vdev_wq_init (struct vdev_wq *wq, struct vdev_state *state) { - int rc = 0; + int rc = 0; - memset(wq, 0, sizeof(struct vdev_wq)); + memset (wq, 0, sizeof (struct vdev_wq)); - rc = pthread_mutex_init(&wq->work_lock, NULL); - if (rc != 0) { + rc = pthread_mutex_init (&wq->work_lock, NULL); + if (rc != 0) + { - return -abs(rc); - } + return -abs (rc); + } - rc = pthread_mutex_init(&wq->waiter_lock, NULL); - if (rc != 0) { + rc = pthread_mutex_init (&wq->waiter_lock, NULL); + if (rc != 0) + { - pthread_mutex_destroy(&wq->work_lock); - return -abs(rc); - } + pthread_mutex_destroy (&wq->work_lock); + return -abs (rc); + } - sem_init(&wq->work_sem, 0, 0); - sem_init(&wq->end_sem, 0, 0); + sem_init (&wq->work_sem, 0, 0); + sem_init (&wq->end_sem, 0, 0); - wq->state = state; + wq->state = state; - return rc; + return rc; } // start a work queue @@ -181,165 +198,183 @@ int vdev_wq_init(struct vdev_wq *wq, struct vdev_state *state) // return negative on error: // * -EINVAL if already started // * whatever pthread_create errors on -int vdev_wq_start(struct vdev_wq *wq) +int +vdev_wq_start (struct vdev_wq *wq) { - if (wq->running) { - return -EINVAL; - } + if (wq->running) + { + return -EINVAL; + } - int rc = 0; - pthread_attr_t attrs; + int rc = 0; + pthread_attr_t attrs; - memset(&attrs, 0, sizeof(pthread_attr_t)); + memset (&attrs, 0, sizeof (pthread_attr_t)); - wq->running = true; + wq->running = true; - rc = pthread_create(&wq->thread, &attrs, vdev_wq_main, wq); - if (rc != 0) { + rc = pthread_create (&wq->thread, &attrs, vdev_wq_main, wq); + if (rc != 0) + { - wq->running = false; + wq->running = false; - rc = -errno; - vdev_error("pthread_create errno = %d\n", rc); + rc = -errno; + vdev_error ("pthread_create errno = %d\n", rc); - return rc; - } + return rc; + } - return 0; + return 0; } // stop a work queue // return 0 on success // return negative on error: // * -EINVAL if not running -int vdev_wq_stop(struct vdev_wq *wq, bool wait) +int +vdev_wq_stop (struct vdev_wq *wq, bool wait) { - if (!wq->running) { - return -EINVAL; - } + if (!wq->running) + { + return -EINVAL; + } - if (wait) { + if (wait) + { - // wait for the queue to be empty - vdev_wq_wait_for_empty(wq); - } + // wait for the queue to be empty + vdev_wq_wait_for_empty (wq); + } - wq->running = false; + wq->running = false; - // wake up the work queue so it cancels - sem_post(&wq->work_sem); - pthread_cancel(wq->thread); + // wake up the work queue so it cancels + sem_post (&wq->work_sem); + pthread_cancel (wq->thread); - pthread_join(wq->thread, NULL); + pthread_join (wq->thread, NULL); - return 0; + return 0; } // free a work request queue // always succeeds -static int vdev_wq_queue_free(struct vdev_wreq *wqueue) +static int +vdev_wq_queue_free (struct vdev_wreq *wqueue) { - struct vdev_wreq *next = NULL; + struct vdev_wreq *next = NULL; - while (wqueue != NULL) { + while (wqueue != NULL) + { - next = wqueue->next; + next = wqueue->next; - vdev_wreq_free(wqueue); - free(wqueue); + vdev_wreq_free (wqueue); + free (wqueue); - wqueue = next; - } + wqueue = next; + } - return 0; + return 0; } // free up a work queue // return 0 on success // return negative on error: // * -EINVAL if running -int vdev_wq_free(struct vdev_wq *wq) +int +vdev_wq_free (struct vdev_wq *wq) { - if (wq->running) { - return -EINVAL; - } - // free all - vdev_wq_queue_free(wq->work); + if (wq->running) + { + return -EINVAL; + } + // free all + vdev_wq_queue_free (wq->work); - pthread_mutex_destroy(&wq->work_lock); - pthread_mutex_destroy(&wq->waiter_lock); + pthread_mutex_destroy (&wq->work_lock); + pthread_mutex_destroy (&wq->waiter_lock); - sem_destroy(&wq->work_sem); - sem_destroy(&wq->end_sem); + sem_destroy (&wq->work_sem); + sem_destroy (&wq->end_sem); - memset(wq, 0, sizeof(struct vdev_wq)); + memset (wq, 0, sizeof (struct vdev_wq)); - return 0; + return 0; } // create a work request // always succeeds -int vdev_wreq_init(struct vdev_wreq *wreq, vdev_wq_func_t work, void *work_data) +int +vdev_wreq_init (struct vdev_wreq *wreq, vdev_wq_func_t work, void *work_data) { - memset(wreq, 0, sizeof(struct vdev_wreq)); + memset (wreq, 0, sizeof (struct vdev_wreq)); - wreq->work = work; - wreq->work_data = work_data; + wreq->work = work; + wreq->work_data = work_data; - return 0; + return 0; } // free a work request // always succeeds -int vdev_wreq_free(struct vdev_wreq *wreq) +int +vdev_wreq_free (struct vdev_wreq *wreq) { - memset(wreq, 0, sizeof(struct vdev_wreq)); - return 0; + memset (wreq, 0, sizeof (struct vdev_wreq)); + return 0; } // enqueue work // return 0 on success // return -ENOMEM if OOM -int vdev_wq_add(struct vdev_wq *wq, struct vdev_wreq *wreq) +int +vdev_wq_add (struct vdev_wq *wq, struct vdev_wreq *wreq) { - int rc = 0; - struct vdev_wreq *next = NULL; - - // duplicate this work item - next = VDEV_CALLOC(struct vdev_wreq, 1); - if (next == NULL) { - return -ENOMEM; - } - - next->work = wreq->work; - next->work_data = wreq->work_data; - next->next = NULL; - - pthread_mutex_lock(&wq->work_lock); - - if (wq->work == NULL) { - // head - wq->work = next; - wq->tail = next; - } else { - // append - wq->tail->next = next; - wq->tail = next; - } - - pthread_mutex_unlock(&wq->work_lock); - - if (rc == 0) { - // have work - sem_post(&wq->work_sem); - } - - return rc; + int rc = 0; + struct vdev_wreq *next = NULL; + + // duplicate this work item + next = VDEV_CALLOC (struct vdev_wreq, 1); + if (next == NULL) + { + return -ENOMEM; + } + + next->work = wreq->work; + next->work_data = wreq->work_data; + next->next = NULL; + + pthread_mutex_lock (&wq->work_lock); + + if (wq->work == NULL) + { + // head + wq->work = next; + wq->tail = next; + } + else + { + // append + wq->tail->next = next; + wq->tail = next; + } + + pthread_mutex_unlock (&wq->work_lock); + + if (rc == 0) + { + // have work + sem_post (&wq->work_sem); + } + + return rc; } diff --git a/vdevd/workqueue.h b/vdevd/workqueue.h index bc5e46d..1ada2e3 100644 --- a/vdevd/workqueue.h +++ b/vdevd/workqueue.h @@ -31,59 +31,61 @@ struct vdev_state; typedef int (*vdev_wq_func_t) (struct vdev_wreq * wreq, void *cls); // vdev workqueue request -struct vdev_wreq { +struct vdev_wreq +{ - // callback to do work - vdev_wq_func_t work; + // callback to do work + vdev_wq_func_t work; - // user-supplied arguments - void *work_data; + // user-supplied arguments + void *work_data; - // next item - struct vdev_wreq *next; + // next item + struct vdev_wreq *next; }; // vdev workqueue -struct vdev_wq { +struct vdev_wq +{ - // worker thread - pthread_t thread; + // worker thread + pthread_t thread; - // is the thread running? - volatile bool running; + // is the thread running? + volatile bool running; - // things to do - struct vdev_wreq *work; - struct vdev_wreq *tail; + // things to do + struct vdev_wreq *work; + struct vdev_wreq *tail; - // lock governing access to work - pthread_mutex_t work_lock; + // lock governing access to work + pthread_mutex_t work_lock; - // semaphore to signal the availability of work - sem_t work_sem; + // semaphore to signal the availability of work + sem_t work_sem; - // semaphore to signal the end of coldplug processing - sem_t end_sem; + // semaphore to signal the end of coldplug processing + sem_t end_sem; - // pointer to vdev global state - struct vdev_state *state; + // pointer to vdev global state + struct vdev_state *state; - // number of threads waiting for the queue to be empty - volatile int num_waiters; - pthread_mutex_t waiter_lock; + // number of threads waiting for the queue to be empty + volatile int num_waiters; + pthread_mutex_t waiter_lock; }; -C_LINKAGE_BEGIN -int vdev_wq_init(struct vdev_wq *wq, struct vdev_state *state); -int vdev_wq_start(struct vdev_wq *wq); -int vdev_wq_stop(struct vdev_wq *wq, bool wait); -int vdev_wq_free(struct vdev_wq *wq); +C_LINKAGE_BEGIN int vdev_wq_init (struct vdev_wq *wq, + struct vdev_state *state); +int vdev_wq_start (struct vdev_wq *wq); +int vdev_wq_stop (struct vdev_wq *wq, bool wait); +int vdev_wq_free (struct vdev_wq *wq); -int vdev_wreq_init(struct vdev_wreq *wreq, vdev_wq_func_t work, - void *work_data); -int vdev_wreq_free(struct vdev_wreq *wreq); +int vdev_wreq_init (struct vdev_wreq *wreq, vdev_wq_func_t work, + void *work_data); +int vdev_wreq_free (struct vdev_wreq *wreq); -int vdev_wq_add(struct vdev_wq *wq, struct vdev_wreq *wreq); +int vdev_wq_add (struct vdev_wq *wq, struct vdev_wreq *wreq); C_LINKAGE_END #endif From 89801957f24a7360e0c14248d7613d6375644d91 Mon Sep 17 00:00:00 2001 From: Peter Gossner Date: Mon, 15 Aug 2016 17:50:03 +0930 Subject: [PATCH 09/13] Testing indent really Moving everything to GNU style As a "middle path"... Its probaly appropriate to move LINUX specific code to -linux style... Not a huge issue for me. --- fs/acl.c | 1465 ++++++----- fs/acl.h | 85 +- fs/fs.c | 2274 ++++++++-------- fs/fs.h | 105 +- fs/main.c | 32 +- libudev-compat/MurmurHash2.c | 77 +- libudev-compat/MurmurHash2.h | 8 +- libudev-compat/device-nodes.c | 85 +- libudev-compat/device-nodes.h | 4 +- libudev-compat/hashmap.c | 2654 ++++++++++--------- libudev-compat/hashmap.h | 449 ++-- libudev-compat/hwdb-internal.h | 76 +- libudev-compat/hwdb-util.h | 4 +- libudev-compat/libudev-device-private.c | 344 +-- libudev-compat/libudev-device.c | 3197 ++++++++++++----------- libudev-compat/libudev-enumerate.c | 1472 ++++++----- libudev-compat/libudev-fs.c | 2247 ++++++++-------- libudev-compat/libudev-fs.h | 8 +- libudev-compat/libudev-hwdb.c | 118 +- libudev-compat/libudev-list.c | 465 ++-- libudev-compat/libudev-monitor.c | 1804 +++++++------ libudev-compat/libudev-private.h | 285 +- libudev-compat/libudev-queue.c | 171 +- libudev-compat/libudev-util.c | 505 ++-- libudev-compat/libudev.c | 244 +- libudev-compat/libudev.h | 376 ++- libudev-compat/log.c | 65 +- libudev-compat/log.h | 6 +- libudev-compat/macro.h | 61 +- libudev-compat/mempool.c | 115 +- libudev-compat/mempool.h | 19 +- libudev-compat/mkdir.c | 204 +- libudev-compat/mkdir.h | 18 +- libudev-compat/sd-hwdb.c | 837 +++--- libudev-compat/sd-hwdb.h | 14 +- libudev-compat/set.h | 113 +- libudev-compat/siphash24.c | 156 +- libudev-compat/siphash24.h | 4 +- libudev-compat/sparse-endian.h | 62 +- libudev-compat/strxcpyx.c | 132 +- libudev-compat/strxcpyx.h | 14 +- libudev-compat/utf8.c | 550 ++-- libudev-compat/utf8.h | 37 +- libudev-compat/util.c | 530 ++-- libudev-compat/util.h | 151 +- libvdev/config.c | 1064 ++++---- libvdev/config.h | 92 +- libvdev/ini.c | 314 +-- libvdev/ini.h | 67 +- libvdev/match.c | 177 +- libvdev/match.h | 15 +- libvdev/param.c | 111 +- libvdev/param.h | 21 +- libvdev/sglib.h | 4 +- libvdev/util.c | 1626 ++++++------ libvdev/util.h | 58 +- tools/udev_to_vdev/udev_rule.h | 114 +- vdevd/device.c | 8 +- vdevd/helpers/LINUX/common.c | 1966 +++++++------- vdevd/helpers/LINUX/common.h | 94 +- vdevd/helpers/LINUX/echo_n.c | 21 +- vdevd/helpers/LINUX/event-put.c | 796 +++--- vdevd/helpers/LINUX/stat_ata.c | 1306 ++++----- vdevd/helpers/LINUX/stat_bus.c | 263 +- vdevd/helpers/LINUX/stat_input.c | 702 ++--- vdevd/helpers/LINUX/stat_net.c | 1669 ++++++------ vdevd/helpers/LINUX/stat_optical.c | 126 +- vdevd/helpers/LINUX/stat_path.c | 2637 ++++++++++--------- vdevd/helpers/LINUX/stat_scsi.c | 3073 ++++++++++++---------- vdevd/helpers/LINUX/stat_usb.c | 1632 ++++++------ vdevd/helpers/LINUX/stat_v4l.c | 143 +- vdevd/os/common.c | 195 +- vdevd/os/common.h | 28 +- vdevd/os/linux.c | 2159 ++++++++------- vdevd/os/linux.h | 33 +- vdevd/os/methods.h | 6 +- vdevd/os/test.h | 24 +- 77 files changed, 22423 insertions(+), 19763 deletions(-) diff --git a/fs/acl.c b/fs/acl.c index ba286a2..819d260 100644 --- a/fs/acl.c +++ b/fs/acl.c @@ -28,22 +28,26 @@ #include "libvdev/match.h" #include "libvdev/config.h" -SGLIB_DEFINE_VECTOR_PROTOTYPES(vdev_acl); -SGLIB_DEFINE_VECTOR_FUNCTIONS(vdev_acl); +SGLIB_DEFINE_VECTOR_PROTOTYPES (vdev_acl); +SGLIB_DEFINE_VECTOR_FUNCTIONS (vdev_acl); // parse the ACL mode -static int vdev_acl_parse_mode(mode_t * mode, char const *mode_str) +static int +vdev_acl_parse_mode (mode_t * mode, char const *mode_str) { - char *tmp = NULL; + char *tmp = NULL; - *mode = ((mode_t) strtol(mode_str, &tmp, 8)) & 0777; + *mode = ((mode_t) strtol (mode_str, &tmp, 8)) & 0777; - if (*tmp != '\0') { - return -EINVAL; - } else { - return 0; - } + if (*tmp != '\0') + { + return -EINVAL; + } + else + { + return 0; + } } // get a passwd struct for a user. @@ -52,50 +56,58 @@ static int vdev_acl_parse_mode(mode_t * mode, char const *mode_str) // return -EINVAL if any argument is NULL // return -ENOMEM on OOM // return -ENOENT if the username cnanot be loaded -int vdev_get_passwd(char const *username, struct passwd *pwd, char **pwd_buf) +int +vdev_get_passwd (char const *username, struct passwd *pwd, char **pwd_buf) { - struct passwd *result = NULL; - char *buf = NULL; - int buf_len = 0; - int rc = 0; + struct passwd *result = NULL; + char *buf = NULL; + int buf_len = 0; + int rc = 0; - if (pwd == NULL || username == NULL || pwd_buf == NULL) { - return -EINVAL; - } + if (pwd == NULL || username == NULL || pwd_buf == NULL) + { + return -EINVAL; + } - memset(pwd, 0, sizeof(struct passwd)); + memset (pwd, 0, sizeof (struct passwd)); - buf_len = sysconf(_SC_GETPW_R_SIZE_MAX); - if (buf_len <= 0) { - buf_len = 65536; - } + buf_len = sysconf (_SC_GETPW_R_SIZE_MAX); + if (buf_len <= 0) + { + buf_len = 65536; + } - buf = VDEV_CALLOC(char, buf_len); - if (buf == NULL) { - return -ENOMEM; - } + buf = VDEV_CALLOC (char, buf_len); + if (buf == NULL) + { + return -ENOMEM; + } - rc = getpwnam_r(username, pwd, buf, buf_len, &result); + rc = getpwnam_r (username, pwd, buf, buf_len, &result); - if (result == NULL) { + if (result == NULL) + { - if (rc == 0) { - free(buf); - return -ENOENT; - } else { - rc = -errno; - free(buf); + if (rc == 0) + { + free (buf); + return -ENOENT; + } + else + { + rc = -errno; + free (buf); - vdev_error("getpwnam_r(%s) errno = %d\n", username, rc); - return rc; - } + vdev_error ("getpwnam_r(%s) errno = %d\n", username, rc); + return rc; } + } - *pwd_buf = buf; + *pwd_buf = buf; - // success! - return rc; + // success! + return rc; } // get a group struct for a group. @@ -104,48 +116,55 @@ int vdev_get_passwd(char const *username, struct passwd *pwd, char **pwd_buf) // return -ENOMEM on OOM // return -EINVAL if any argument is NULL // return -ENOENT if the group cannot be found -int vdev_get_group(char const *groupname, struct group *grp, char **grp_buf) +int +vdev_get_group (char const *groupname, struct group *grp, char **grp_buf) { - struct group *result = NULL; - char *buf = NULL; - int buf_len = 0; - int rc = 0; + struct group *result = NULL; + char *buf = NULL; + int buf_len = 0; + int rc = 0; - if (grp == NULL || groupname == NULL || grp_buf == NULL) { - return -EINVAL; - } + if (grp == NULL || groupname == NULL || grp_buf == NULL) + { + return -EINVAL; + } - memset(grp, 0, sizeof(struct group)); + memset (grp, 0, sizeof (struct group)); - buf_len = sysconf(_SC_GETGR_R_SIZE_MAX); - if (buf_len <= 0) { - buf_len = 65536; - } + buf_len = sysconf (_SC_GETGR_R_SIZE_MAX); + if (buf_len <= 0) + { + buf_len = 65536; + } - buf = VDEV_CALLOC(char, buf_len); - if (buf == NULL) { - return -ENOMEM; - } + buf = VDEV_CALLOC (char, buf_len); + if (buf == NULL) + { + return -ENOMEM; + } - rc = getgrnam_r(groupname, grp, buf, buf_len, &result); + rc = getgrnam_r (groupname, grp, buf, buf_len, &result); - if (result == NULL) { + if (result == NULL) + { - if (rc == 0) { - free(buf); - return -ENOENT; - } else { - rc = -errno; - free(buf); + if (rc == 0) + { + free (buf); + return -ENOENT; + } + else + { + rc = -errno; + free (buf); - vdev_error("getgrnam_r(%s) errno = %d\n", groupname, - rc); - return rc; - } + vdev_error ("getgrnam_r(%s) errno = %d\n", groupname, rc); + return rc; } - // success! - return rc; + } + // success! + return rc; } // parse a username or uid from a string. @@ -153,40 +172,43 @@ int vdev_get_group(char const *groupname, struct group *grp, char **grp_buf) // return 0 and set *uid on success // return negative if we failed to look up the corresponding user (see vdev_get_passwd) // return negative on error -int vdev_parse_uid(char const *uid_str, uid_t * uid) +int +vdev_parse_uid (char const *uid_str, uid_t * uid) { - bool parsed = false; - int rc = 0; + bool parsed = false; + int rc = 0; - if (uid_str == NULL || uid == NULL) { - return -EINVAL; - } + if (uid_str == NULL || uid == NULL) + { + return -EINVAL; + } - *uid = (uid_t) vdev_parse_uint64(uid_str, &parsed); + *uid = (uid_t) vdev_parse_uint64 (uid_str, &parsed); - // not a number? - if (!parsed) { + // not a number? + if (!parsed) + { - // probably a username - char *pwd_buf = NULL; - struct passwd pwd; + // probably a username + char *pwd_buf = NULL; + struct passwd pwd; - // look up the uid... - rc = vdev_get_passwd(uid_str, &pwd, &pwd_buf); - if (rc != 0) { + // look up the uid... + rc = vdev_get_passwd (uid_str, &pwd, &pwd_buf); + if (rc != 0) + { - vdev_error("vdev_get_passwd(%s) rc = %d\n", uid_str, - rc); - return rc; - } + vdev_error ("vdev_get_passwd(%s) rc = %d\n", uid_str, rc); + return rc; + } - *uid = pwd.pw_uid; + *uid = pwd.pw_uid; - free(pwd_buf); - } + free (pwd_buf); + } - return 0; + return 0; } // parse a group name or GID from a string @@ -194,39 +216,43 @@ int vdev_parse_uid(char const *uid_str, uid_t * uid) // return 0 and set gid on success // return negative if we failed to look up the corresponding group (see vdev_get_group) // return negative on error -int vdev_parse_gid(char const *gid_str, gid_t * gid) +int +vdev_parse_gid (char const *gid_str, gid_t * gid) { - bool parsed = false; - int rc = 0; + bool parsed = false; + int rc = 0; - if (gid_str == NULL || gid == NULL) { - return -EINVAL; - } + if (gid_str == NULL || gid == NULL) + { + return -EINVAL; + } - *gid = (gid_t) vdev_parse_uint64(gid_str, &parsed); + *gid = (gid_t) vdev_parse_uint64 (gid_str, &parsed); - // not a number? - if (!parsed) { + // not a number? + if (!parsed) + { - // probably a group name - char *grp_buf = NULL; - struct group grp; + // probably a group name + char *grp_buf = NULL; + struct group grp; - // look up the gid... - rc = vdev_get_group(gid_str, &grp, &grp_buf); - if (rc != 0) { + // look up the gid... + rc = vdev_get_group (gid_str, &grp, &grp_buf); + if (rc != 0) + { - vdev_error("vdev_get_group(%s) rc = %d\n", gid_str, rc); - return rc; - } + vdev_error ("vdev_get_group(%s) rc = %d\n", gid_str, rc); + return rc; + } - *gid = grp.gr_gid; + *gid = grp.gr_gid; - free(grp_buf); - } + free (grp_buf); + } - return 0; + return 0; } // verify that a UID is valid @@ -234,51 +260,59 @@ int vdev_parse_gid(char const *gid_str, gid_t * gid) // return -ENOMEM on OOM // return -ENOENT on failure to look up the user // return negative on error -int vdev_validate_uid(uid_t uid) +int +vdev_validate_uid (uid_t uid) { - struct passwd *result = NULL; - char *buf = NULL; - int buf_len = 0; - int rc = 0; - struct passwd pwd; - - memset(&pwd, 0, sizeof(struct passwd)); + struct passwd *result = NULL; + char *buf = NULL; + int buf_len = 0; + int rc = 0; + struct passwd pwd; - buf_len = sysconf(_SC_GETPW_R_SIZE_MAX); - if (buf_len <= 0) { - buf_len = 65536; - } + memset (&pwd, 0, sizeof (struct passwd)); - buf = VDEV_CALLOC(char, buf_len); - if (buf == NULL) { - return -ENOMEM; - } + buf_len = sysconf (_SC_GETPW_R_SIZE_MAX); + if (buf_len <= 0) + { + buf_len = 65536; + } - rc = getpwuid_r(uid, &pwd, buf, buf_len, &result); + buf = VDEV_CALLOC (char, buf_len); + if (buf == NULL) + { + return -ENOMEM; + } - if (result == NULL) { + rc = getpwuid_r (uid, &pwd, buf, buf_len, &result); - if (rc == 0) { - free(buf); - return -ENOENT; - } else { - rc = -errno; - free(buf); + if (result == NULL) + { - vdev_error("getpwuid_r(%d) errno = %d\n", uid, rc); - return rc; - } + if (rc == 0) + { + free (buf); + return -ENOENT; } + else + { + rc = -errno; + free (buf); - if (uid != pwd.pw_uid) { - // should *never* happen - rc = -EINVAL; + vdev_error ("getpwuid_r(%d) errno = %d\n", uid, rc); + return rc; } + } - free(buf); + if (uid != pwd.pw_uid) + { + // should *never* happen + rc = -EINVAL; + } - return rc; + free (buf); + + return rc; } // verify that a GID is valid @@ -286,565 +320,633 @@ int vdev_validate_uid(uid_t uid) // return -ENOMEM on OOM // return -ENOENT if we couldn't find the corresponding group // return negative on other error -int vdev_validate_gid(gid_t gid) +int +vdev_validate_gid (gid_t gid) { - struct group *result = NULL; - struct group grp; - char *buf = NULL; - int buf_len = 0; - int rc = 0; - - memset(&grp, 0, sizeof(struct group)); + struct group *result = NULL; + struct group grp; + char *buf = NULL; + int buf_len = 0; + int rc = 0; - buf_len = sysconf(_SC_GETGR_R_SIZE_MAX); - if (buf_len <= 0) { - buf_len = 65536; - } + memset (&grp, 0, sizeof (struct group)); - buf = VDEV_CALLOC(char, buf_len); - if (buf == NULL) { - return -ENOMEM; - } + buf_len = sysconf (_SC_GETGR_R_SIZE_MAX); + if (buf_len <= 0) + { + buf_len = 65536; + } - rc = getgrgid_r(gid, &grp, buf, buf_len, &result); + buf = VDEV_CALLOC (char, buf_len); + if (buf == NULL) + { + return -ENOMEM; + } - if (result == NULL) { + rc = getgrgid_r (gid, &grp, buf, buf_len, &result); - if (rc == 0) { - free(buf); - return -ENOENT; - } else { - rc = -errno; - free(buf); + if (result == NULL) + { - vdev_error("getgrgid_r(%d) errno = %d\n", gid, rc); - return rc; - } + if (rc == 0) + { + free (buf); + return -ENOENT; } + else + { + rc = -errno; + free (buf); - if (gid != grp.gr_gid) { - rc = -EINVAL; + vdev_error ("getgrgid_r(%d) errno = %d\n", gid, rc); + return rc; } + } - free(buf); + if (gid != grp.gr_gid) + { + rc = -EINVAL; + } - return rc; + free (buf); + + return rc; } // callback from inih to parse an acl // return 1 on success // return 0 on failure -static int vdev_acl_ini_parser(void *userdata, char const *section, - char const *name, char const *value) +static int +vdev_acl_ini_parser (void *userdata, char const *section, + char const *name, char const *value) { - struct vdev_acl *acl = (struct vdev_acl *)userdata; - - // verify this is an acl section - if (strcmp(section, VDEV_ACL_NAME) != 0) { + struct vdev_acl *acl = (struct vdev_acl *) userdata; - fprintf(stderr, "Invalid section '%s'\n", section); - return 0; - } + // verify this is an acl section + if (strcmp (section, VDEV_ACL_NAME) != 0) + { - if (strcmp(name, VDEV_ACL_NAME_UID) == 0) { + fprintf (stderr, "Invalid section '%s'\n", section); + return 0; + } - // parse user or UID - uid_t uid = 0; - int rc = vdev_parse_uid(value, &uid); + if (strcmp (name, VDEV_ACL_NAME_UID) == 0) + { - if (rc != 0) { - vdev_error("vdev_parse_uid(%s) rc = %d\n", value, rc); + // parse user or UID + uid_t uid = 0; + int rc = vdev_parse_uid (value, &uid); - fprintf(stderr, "Invalid user/UID '%s'\n", value); - return 0; - } + if (rc != 0) + { + vdev_error ("vdev_parse_uid(%s) rc = %d\n", value, rc); - acl->has_uid = true; - acl->uid = uid; - return 1; + fprintf (stderr, "Invalid user/UID '%s'\n", value); + return 0; } - if (strcmp(name, VDEV_ACL_NAME_SETUID) == 0) { + acl->has_uid = true; + acl->uid = uid; + return 1; + } - // parse user or UID - uid_t uid = 0; - int rc = vdev_parse_uid(value, &uid); + if (strcmp (name, VDEV_ACL_NAME_SETUID) == 0) + { - if (rc != 0) { - vdev_error("vdev_parse_uid(%s) rc = %d\n", value, rc); + // parse user or UID + uid_t uid = 0; + int rc = vdev_parse_uid (value, &uid); - fprintf(stderr, "Invalid user/UID '%s'\n", value); - return 0; - } + if (rc != 0) + { + vdev_error ("vdev_parse_uid(%s) rc = %d\n", value, rc); - acl->has_setuid = true; - acl->setuid = uid; - return 1; + fprintf (stderr, "Invalid user/UID '%s'\n", value); + return 0; } - if (strcmp(name, VDEV_ACL_NAME_GID) == 0) { + acl->has_setuid = true; + acl->setuid = uid; + return 1; + } - // parse group or GID - gid_t gid = 0; - int rc = vdev_parse_gid(value, &gid); + if (strcmp (name, VDEV_ACL_NAME_GID) == 0) + { - if (rc != 0) { - vdev_error("vdev_parse_gid(%s) rc = %d\n", value, rc); + // parse group or GID + gid_t gid = 0; + int rc = vdev_parse_gid (value, &gid); - fprintf(stderr, "Invalid group/GID '%s'\n", value); - return 0; - } + if (rc != 0) + { + vdev_error ("vdev_parse_gid(%s) rc = %d\n", value, rc); - acl->has_gid = true; - acl->gid = gid; - return 1; + fprintf (stderr, "Invalid group/GID '%s'\n", value); + return 0; } - if (strcmp(name, VDEV_ACL_NAME_SETGID) == 0) { + acl->has_gid = true; + acl->gid = gid; + return 1; + } - // parse group or GID - gid_t gid = 0; - int rc = vdev_parse_gid(value, &gid); + if (strcmp (name, VDEV_ACL_NAME_SETGID) == 0) + { - if (rc != 0) { - vdev_error("vdev_parse_gid(%s) rc = %d\n", value, rc); + // parse group or GID + gid_t gid = 0; + int rc = vdev_parse_gid (value, &gid); - fprintf(stderr, "Invalid group/GID '%s'\n", value); - return 0; - } + if (rc != 0) + { + vdev_error ("vdev_parse_gid(%s) rc = %d\n", value, rc); - acl->has_setgid = true; - acl->setgid = gid; - return 1; + fprintf (stderr, "Invalid group/GID '%s'\n", value); + return 0; } - if (strcmp(name, VDEV_ACL_NAME_SETMODE) == 0) { + acl->has_setgid = true; + acl->setgid = gid; + return 1; + } - // parse mode - mode_t mode = 0; - int rc = vdev_acl_parse_mode(&mode, value); + if (strcmp (name, VDEV_ACL_NAME_SETMODE) == 0) + { - if (rc != 0) { - vdev_error("vdev_acl_parse_mode(%s) rc = %d\n", value, - rc); + // parse mode + mode_t mode = 0; + int rc = vdev_acl_parse_mode (&mode, value); - fprintf(stderr, "Invalid mode '%s'\n", value); - return 0; - } + if (rc != 0) + { + vdev_error ("vdev_acl_parse_mode(%s) rc = %d\n", value, rc); - acl->has_setmode = true; - acl->setmode = mode; - return 1; + fprintf (stderr, "Invalid mode '%s'\n", value); + return 0; } - if (strcmp(name, VDEV_ACL_DEVICE_REGEX) == 0) { + acl->has_setmode = true; + acl->setmode = mode; + return 1; + } - // parse and preserve this value - int rc = - vdev_match_regex_append(&acl->paths, &acl->regexes, - &acl->num_paths, value); + if (strcmp (name, VDEV_ACL_DEVICE_REGEX) == 0) + { - if (rc != 0) { - vdev_error("vdev_match_regex_append(%s) rc = %d\n", - value, rc); + // parse and preserve this value + int rc = vdev_match_regex_append (&acl->paths, &acl->regexes, + &acl->num_paths, value); - fprintf(stderr, "Invalid regex '%s'\n", value); - return 0; - } + if (rc != 0) + { + vdev_error ("vdev_match_regex_append(%s) rc = %d\n", value, rc); - return 1; + fprintf (stderr, "Invalid regex '%s'\n", value); + return 0; } - if (strcmp(name, VDEV_ACL_NAME_PROC_PATH) == 0) { + return 1; + } - // preserve this value - if (acl->proc_path != NULL) { + if (strcmp (name, VDEV_ACL_NAME_PROC_PATH) == 0) + { - fprintf(stderr, "Duplicate process path '%s'\n", value); - return 0; - } + // preserve this value + if (acl->proc_path != NULL) + { - acl->has_proc = true; - acl->proc_path = vdev_strdup_or_null(value); - return 1; + fprintf (stderr, "Duplicate process path '%s'\n", value); + return 0; } - if (strcmp(name, VDEV_ACL_NAME_PROC_PREDICATE) == 0) { + acl->has_proc = true; + acl->proc_path = vdev_strdup_or_null (value); + return 1; + } - // preserve this value - if (acl->proc_predicate_cmd != NULL) { + if (strcmp (name, VDEV_ACL_NAME_PROC_PREDICATE) == 0) + { - fprintf(stderr, "Duplicate predicate '%s'\n", value); - return 0; - } + // preserve this value + if (acl->proc_predicate_cmd != NULL) + { - acl->has_proc = true; - acl->proc_predicate_cmd = vdev_strdup_or_null(value); - return 1; + fprintf (stderr, "Duplicate predicate '%s'\n", value); + return 0; } - if (strcmp(name, VDEV_ACL_NAME_PROC_INODE) == 0) { + acl->has_proc = true; + acl->proc_predicate_cmd = vdev_strdup_or_null (value); + return 1; + } - // preserve this value - ino_t inode = 0; - bool success = false; + if (strcmp (name, VDEV_ACL_NAME_PROC_INODE) == 0) + { - inode = vdev_parse_uint64(value, &success); - if (!success) { + // preserve this value + ino_t inode = 0; + bool success = false; - fprintf(stderr, "Failed to parse inode '%s'\n", value); - return 0; - } + inode = vdev_parse_uint64 (value, &success); + if (!success) + { - acl->has_proc = true; - acl->proc_inode = inode; - return 1; + fprintf (stderr, "Failed to parse inode '%s'\n", value); + return 0; } - fprintf(stderr, "Unrecognized field '%s'\n", name); - return 0; + acl->has_proc = true; + acl->proc_inode = inode; + return 1; + } + + fprintf (stderr, "Unrecognized field '%s'\n", name); + return 0; } // acl sanity check -int vdev_acl_sanity_check(struct vdev_acl *acl) +int +vdev_acl_sanity_check (struct vdev_acl *acl) { - int rc = 0; + int rc = 0; - if (acl->has_gid) { + if (acl->has_gid) + { - rc = vdev_validate_gid(acl->gid); - if (rc != 0) { + rc = vdev_validate_gid (acl->gid); + if (rc != 0) + { - fprintf(stderr, "Invalid GID %d\n", acl->gid); - return rc; - } + fprintf (stderr, "Invalid GID %d\n", acl->gid); + return rc; } + } - if (acl->has_setgid) { + if (acl->has_setgid) + { - rc = vdev_validate_gid(acl->gid); - if (rc != 0) { + rc = vdev_validate_gid (acl->gid); + if (rc != 0) + { - fprintf(stderr, "Invalid set-GID %d\n", acl->setgid); - return rc; - } + fprintf (stderr, "Invalid set-GID %d\n", acl->setgid); + return rc; } + } - if (acl->has_uid) { + if (acl->has_uid) + { - rc = vdev_validate_uid(acl->uid); - if (rc != 0) { + rc = vdev_validate_uid (acl->uid); + if (rc != 0) + { - fprintf(stderr, "Invalid UID %d\n", acl->uid); - return rc; - } + fprintf (stderr, "Invalid UID %d\n", acl->uid); + return rc; } + } - if (acl->has_setuid) { + if (acl->has_setuid) + { - rc = vdev_validate_uid(acl->uid); - if (rc != 0) { + rc = vdev_validate_uid (acl->uid); + if (rc != 0) + { - fprintf(stderr, "Invalid set-UID %d\n", acl->setuid); - return rc; - } + fprintf (stderr, "Invalid set-UID %d\n", acl->setuid); + return rc; } + } - return rc; + return rc; } // initialize an acl -int vdev_acl_init(struct vdev_acl *acl) +int +vdev_acl_init (struct vdev_acl *acl) { - memset(acl, 0, sizeof(struct vdev_acl)); - return 0; + memset (acl, 0, sizeof (struct vdev_acl)); + return 0; } // free an acl -int vdev_acl_free(struct vdev_acl *acl) +int +vdev_acl_free (struct vdev_acl *acl) { - if (acl->num_paths > 0) { + if (acl->num_paths > 0) + { - vdev_match_regexes_free(acl->paths, acl->regexes, - acl->num_paths); - } + vdev_match_regexes_free (acl->paths, acl->regexes, acl->num_paths); + } - if (acl->proc_path != NULL) { - free(acl->proc_path); - acl->proc_path = NULL; - } + if (acl->proc_path != NULL) + { + free (acl->proc_path); + acl->proc_path = NULL; + } - return 0; + return 0; } // load an ACL from a file handle -int vdev_acl_load_file(FILE * file, struct vdev_acl *acl) +int +vdev_acl_load_file (FILE * file, struct vdev_acl *acl) { - int rc = 0; + int rc = 0; - vdev_acl_init(acl); + vdev_acl_init (acl); - rc = ini_parse_file(file, vdev_acl_ini_parser, acl); - if (rc != 0) { - vdev_error("ini_parse_file(ACL) rc = %d\n", rc); - return rc; - } - // sanity check - rc = vdev_acl_sanity_check(acl); - if (rc != 0) { + rc = ini_parse_file (file, vdev_acl_ini_parser, acl); + if (rc != 0) + { + vdev_error ("ini_parse_file(ACL) rc = %d\n", rc); + return rc; + } + // sanity check + rc = vdev_acl_sanity_check (acl); + if (rc != 0) + { - vdev_error("vdev_acl_sanity_check rc = %d\n", rc); + vdev_error ("vdev_acl_sanity_check rc = %d\n", rc); - vdev_acl_free(acl); - memset(acl, 0, sizeof(struct vdev_acl)); - return rc; - } + vdev_acl_free (acl); + memset (acl, 0, sizeof (struct vdev_acl)); + return rc; + } - return rc; + return rc; } // load an ACL from a file, given the path -int vdev_acl_load(char const *path, struct vdev_acl *acl) +int +vdev_acl_load (char const *path, struct vdev_acl *acl) { - int rc = 0; - FILE *f = NULL; + int rc = 0; + FILE *f = NULL; - f = fopen(path, "r"); - if (f == NULL) { + f = fopen (path, "r"); + if (f == NULL) + { - rc = -errno; - vdev_error("fopen(%s) errno = %d\n", path, rc); - return rc; - } + rc = -errno; + vdev_error ("fopen(%s) errno = %d\n", path, rc); + return rc; + } - rc = vdev_acl_load_file(f, acl); + rc = vdev_acl_load_file (f, acl); - fclose(f); + fclose (f); - if (rc != 0) { - vdev_error("vdev_acl_load_file(%s) rc = %d\n", path, rc); - } + if (rc != 0) + { + vdev_error ("vdev_acl_load_file(%s) rc = %d\n", path, rc); + } - return rc; + return rc; } // free a vector of acls -static void vdev_acl_free_vector(struct sglib_vdev_acl_vector *acls) +static void +vdev_acl_free_vector (struct sglib_vdev_acl_vector *acls) { - for (unsigned long i = 0; i < sglib_vdev_acl_vector_size(acls); i++) { + for (unsigned long i = 0; i < sglib_vdev_acl_vector_size (acls); i++) + { - struct vdev_acl *acl = sglib_vdev_acl_vector_at_ref(acls, i); + struct vdev_acl *acl = sglib_vdev_acl_vector_at_ref (acls, i); - vdev_acl_free(acl); - } + vdev_acl_free (acl); + } - sglib_vdev_acl_vector_clear(acls); + sglib_vdev_acl_vector_clear (acls); } // free a C-style list of acls (including the list itself) -int vdev_acl_free_all(struct vdev_acl *acl_list, size_t num_acls) +int +vdev_acl_free_all (struct vdev_acl *acl_list, size_t num_acls) { - int rc = 0; + int rc = 0; - for (unsigned int i = 0; i < num_acls; i++) { + for (unsigned int i = 0; i < num_acls; i++) + { - rc = vdev_acl_free(&acl_list[i]); - if (rc != 0) { + rc = vdev_acl_free (&acl_list[i]); + if (rc != 0) + { - return rc; - } + return rc; } + } - free(acl_list); + free (acl_list); - return rc; + return rc; } // loader for an acl -int vdev_acl_loader(char const *fp, void *cls) +int +vdev_acl_loader (char const *fp, void *cls) { - struct vdev_acl acl; - int rc = 0; - struct stat sb; + struct vdev_acl acl; + int rc = 0; + struct stat sb; - struct sglib_vdev_acl_vector *acls = - (struct sglib_vdev_acl_vector *)cls; + struct sglib_vdev_acl_vector *acls = (struct sglib_vdev_acl_vector *) cls; - // skip if not a regular file - rc = stat(fp, &sb); - if (rc != 0) { + // skip if not a regular file + rc = stat (fp, &sb); + if (rc != 0) + { - rc = -errno; - vdev_error("stat(%s) rc = %d\n", fp, rc); - return rc; - } + rc = -errno; + vdev_error ("stat(%s) rc = %d\n", fp, rc); + return rc; + } - if (!S_ISREG(sb.st_mode)) { + if (!S_ISREG (sb.st_mode)) + { - return 0; - } + return 0; + } - vdev_debug("Load ACL %s\n", fp); + vdev_debug ("Load ACL %s\n", fp); - memset(&acl, 0, sizeof(struct vdev_acl)); + memset (&acl, 0, sizeof (struct vdev_acl)); - rc = vdev_acl_load(fp, &acl); - if (rc != 0) { + rc = vdev_acl_load (fp, &acl); + if (rc != 0) + { - vdev_error("vdev_acl_load(%s) rc = %d\n", fp, rc); - return rc; - } - // save this acl - rc = sglib_vdev_acl_vector_push_back(acls, acl); - if (rc != 0) { + vdev_error ("vdev_acl_load(%s) rc = %d\n", fp, rc); + return rc; + } + // save this acl + rc = sglib_vdev_acl_vector_push_back (acls, acl); + if (rc != 0) + { - // OOM - vdev_acl_free(&acl); - return rc; - } + // OOM + vdev_acl_free (&acl); + return rc; + } - return 0; + return 0; } // load all ACLs from a directory, in lexographic order // return 0 on success, negative on error -int vdev_acl_load_all(char const *dir_path, struct vdev_acl **ret_acls, - size_t * ret_num_acls) +int +vdev_acl_load_all (char const *dir_path, struct vdev_acl **ret_acls, + size_t * ret_num_acls) { - int rc = 0; - struct sglib_vdev_acl_vector acls; + int rc = 0; + struct sglib_vdev_acl_vector acls; - sglib_vdev_acl_vector_init(&acls); + sglib_vdev_acl_vector_init (&acls); - rc = vdev_load_all(dir_path, vdev_acl_loader, &acls); + rc = vdev_load_all (dir_path, vdev_acl_loader, &acls); - if (rc != 0) { + if (rc != 0) + { - vdev_acl_free_vector(&acls); - return rc; - } else { + vdev_acl_free_vector (&acls); + return rc; + } + else + { - if (sglib_vdev_acl_vector_size(&acls) == 0) { + if (sglib_vdev_acl_vector_size (&acls) == 0) + { - // nothing - *ret_acls = NULL; - *ret_num_acls = 0; - } else { + // nothing + *ret_acls = NULL; + *ret_num_acls = 0; + } + else + { - // extract values - unsigned long len = 0; + // extract values + unsigned long len = 0; - sglib_vdev_acl_vector_yoink(&acls, ret_acls, &len); + sglib_vdev_acl_vector_yoink (&acls, ret_acls, &len); - *ret_num_acls = len; - } + *ret_num_acls = len; } + } - return 0; + return 0; } // modify a stat buffer to apply a user access control list, if the acl says so -int vdev_acl_do_set_user(struct vdev_acl *acl, uid_t caller_uid, - struct stat *sb) +int +vdev_acl_do_set_user (struct vdev_acl *acl, uid_t caller_uid, struct stat *sb) { - if (acl->has_setuid && acl->has_uid) { + if (acl->has_setuid && acl->has_uid) + { - // change the UID of this path - if (acl->uid == caller_uid) { - sb->st_uid = acl->setuid; - } + // change the UID of this path + if (acl->uid == caller_uid) + { + sb->st_uid = acl->setuid; } + } - return 0; + return 0; } // modify a stat buffer to apply a group access control list -int vdev_acl_do_set_group(struct vdev_acl *acl, gid_t caller_gid, - struct stat *sb) +int +vdev_acl_do_set_group (struct vdev_acl *acl, gid_t caller_gid, + struct stat *sb) { - if (acl->has_setgid && acl->has_gid) { + if (acl->has_setgid && acl->has_gid) + { - // change the GID of this path - if (acl->gid == caller_gid) { - sb->st_gid = acl->setgid; - } + // change the GID of this path + if (acl->gid == caller_gid) + { + sb->st_gid = acl->setgid; } + } - return 0; + return 0; } // modify a stat buffer to apply the mode -int vdev_acl_do_set_mode(struct vdev_acl *acl, struct stat *sb) +int +vdev_acl_do_set_mode (struct vdev_acl *acl, struct stat *sb) { - if (acl->has_setmode) { + if (acl->has_setmode) + { - // clear permission bits - sb->st_mode &= ~(0777); + // clear permission bits + sb->st_mode &= ~(0777); - // set permission bits - sb->st_mode |= acl->setmode; - } + // set permission bits + sb->st_mode |= acl->setmode; + } - return 0; + return 0; } // evaluate a predicate command, with the appropriate environment variables set. // on success, fill in the exit code. // return 0 on success // return negative on error -int vdev_acl_run_predicate(struct vdev_acl *acl, struct pstat *ps, - uid_t caller_uid, gid_t caller_gid, int *exit_code) +int +vdev_acl_run_predicate (struct vdev_acl *acl, struct pstat *ps, + uid_t caller_uid, gid_t caller_gid, int *exit_code) { - int exit_status = 0; - char *cmd_buf = NULL; - char env_buf[3][100]; - char *predicate_env[4]; - int rc = 0; + int exit_status = 0; + char *cmd_buf = NULL; + char env_buf[3][100]; + char *predicate_env[4]; + int rc = 0; - // build the command with the apporpriate environment variables: - // * VDEV_GID: the gid of the calling process - // * VDEV_UID: the uid of the calling process - // * VDEV_PID: the pid of the calling process + // build the command with the apporpriate environment variables: + // * VDEV_GID: the gid of the calling process + // * VDEV_UID: the uid of the calling process + // * VDEV_PID: the pid of the calling process - sprintf(env_buf[0], "VDEV_UID=%u", caller_uid); - sprintf(env_buf[1], "VDEV_GID=%u", caller_gid); - sprintf(env_buf[2], "VDEV_PID=%u", pstat_get_pid(ps)); + sprintf (env_buf[0], "VDEV_UID=%u", caller_uid); + sprintf (env_buf[1], "VDEV_GID=%u", caller_gid); + sprintf (env_buf[2], "VDEV_PID=%u", pstat_get_pid (ps)); - predicate_env[0] = env_buf[0]; - predicate_env[1] = env_buf[1]; - predicate_env[2] = env_buf[2]; - predicate_env[3] = NULL; + predicate_env[0] = env_buf[0]; + predicate_env[1] = env_buf[1]; + predicate_env[2] = env_buf[2]; + predicate_env[3] = NULL; - rc = vdev_subprocess(cmd_buf, predicate_env, NULL, 0, -1, &exit_status, - true); + rc = vdev_subprocess (cmd_buf, predicate_env, NULL, 0, -1, &exit_status, + true); - if (rc != 0) { + if (rc != 0) + { - vdev_error("vdev_subprocess('%s') rc = %d\n", cmd_buf, rc); + vdev_error ("vdev_subprocess('%s') rc = %d\n", cmd_buf, rc); - free(cmd_buf); - return rc; - } + free (cmd_buf); + return rc; + } - *exit_code = exit_status; + *exit_code = exit_status; - free(cmd_buf); + free (cmd_buf); - return 0; + return 0; } // check that the caller PID is matched by the given ACL. @@ -852,225 +954,262 @@ int vdev_acl_run_predicate(struct vdev_acl *acl, struct pstat *ps, // return 1 if all ACL criteria match // return 0 if at least one ACL criterion does not match // return negative on error -int vdev_acl_match_process(struct vdev_acl *acl, struct pstat *ps, - uid_t caller_uid, gid_t caller_gid) +int +vdev_acl_match_process (struct vdev_acl *acl, struct pstat *ps, + uid_t caller_uid, gid_t caller_gid) { - int rc = 0; - char path[PATH_MAX + 1]; - struct stat sb; + int rc = 0; + char path[PATH_MAX + 1]; + struct stat sb; - if (!acl->has_proc) { - // applies to anyone - return 1; - } + if (!acl->has_proc) + { + // applies to anyone + return 1; + } + + if (acl->proc_path != NULL || acl->has_proc_inode) + { - if (acl->proc_path != NULL || acl->has_proc_inode) { + if (acl->proc_path != NULL) + { - if (acl->proc_path != NULL) { + pstat_get_path (ps, path); + if (strcmp (acl->proc_path, path) != 0) + { - pstat_get_path(ps, path); - if (strcmp(acl->proc_path, path) != 0) { + // doesn't match + return 0; + } + } - // doesn't match - return 0; - } - } + if (acl->has_proc_inode) + { - if (acl->has_proc_inode) { + pstat_get_stat (ps, &sb); + if (acl->proc_inode != sb.st_ino) + { - pstat_get_stat(ps, &sb); - if (acl->proc_inode != sb.st_ino) { + // doesn't match + return 0; + } + } + } + // filter on a given PID list generator? + if (acl->proc_predicate_cmd != NULL) + { + + // run the command and use the exit code to see if + // this ACL applies to the calling process + int exit_status = 0; + + rc = vdev_acl_run_predicate (acl, ps, caller_uid, caller_gid, + &exit_status); + if (rc != 0) + { + + vdev_error ("vdev_acl_run_predicate('%s') rc = %d\n", + acl->proc_predicate_cmd, rc); + return rc; + } + // exit status follows shell-like semantics: + // 0 indicates "yes, this applies." + // non-zero indicates "no, this does not apply" - // doesn't match - return 0; - } - } + if (exit_status == 0) + { + return 1; } - // filter on a given PID list generator? - if (acl->proc_predicate_cmd != NULL) { - - // run the command and use the exit code to see if - // this ACL applies to the calling process - int exit_status = 0; - - rc = vdev_acl_run_predicate(acl, ps, caller_uid, caller_gid, - &exit_status); - if (rc != 0) { - - vdev_error("vdev_acl_run_predicate('%s') rc = %d\n", - acl->proc_predicate_cmd, rc); - return rc; - } - // exit status follows shell-like semantics: - // 0 indicates "yes, this applies." - // non-zero indicates "no, this does not apply" - - if (exit_status == 0) { - return 1; - } else { - return 0; - } + else + { + return 0; } - // all checks match - return 1; + } + // all checks match + return 1; } // given a list of access control lists, find the index of the first one that applies to the given caller and path. // return >= 0 with the index // return num_acls if not found // return negative on error -int vdev_acl_find_next(char const *path, struct pstat *caller_proc, - uid_t caller_uid, gid_t caller_gid, - struct vdev_acl *acls, size_t num_acls) +int +vdev_acl_find_next (char const *path, struct pstat *caller_proc, + uid_t caller_uid, gid_t caller_gid, + struct vdev_acl *acls, size_t num_acls) { - int rc = 0; - bool found = false; - int idx = 0; - - for (unsigned int i = 0; i < num_acls; i++) { - - rc = 0; - - // match UID? - if (acls[i].has_uid && acls[i].uid != caller_uid) { - // nope - continue; - } - // match GID? - if (acls[i].has_gid && acls[i].gid != caller_gid) { - // nope - continue; - } - // match path? - if (acls[i].num_paths > 0) { - - rc = vdev_match_first_regex(path, acls[i].regexes, - acls[i].num_paths); - - if (rc >= (signed)acls[i].num_paths) { - // no match - continue; - } - } - - if (rc < 0) { - - vdev_error("vdev_match_first_regex(%s) rc = %d\n", path, - rc); - break; - } - // match process? Do this last, since it can be expensive - rc = vdev_acl_match_process(&acls[i], caller_proc, caller_uid, - caller_gid); - if (rc == 0) { - // no match - continue; - } - - if (rc < 0) { - - // error... - vdev_error("vdev_acl_match_process(%d) rc = %d\n", - pstat_get_pid(caller_proc), rc); - break; - } - // success! - found = true; - idx = i; - rc = 0; - break; + int rc = 0; + bool found = false; + int idx = 0; + + for (unsigned int i = 0; i < num_acls; i++) + { + + rc = 0; + + // match UID? + if (acls[i].has_uid && acls[i].uid != caller_uid) + { + // nope + continue; + } + // match GID? + if (acls[i].has_gid && acls[i].gid != caller_gid) + { + // nope + continue; + } + // match path? + if (acls[i].num_paths > 0) + { + + rc = vdev_match_first_regex (path, acls[i].regexes, + acls[i].num_paths); + + if (rc >= (signed) acls[i].num_paths) + { + // no match + continue; + } + } + + if (rc < 0) + { + + vdev_error ("vdev_match_first_regex(%s) rc = %d\n", path, rc); + break; + } + // match process? Do this last, since it can be expensive + rc = vdev_acl_match_process (&acls[i], caller_proc, caller_uid, + caller_gid); + if (rc == 0) + { + // no match + continue; } - if (found) { - return idx; - } else { - if (rc >= 0) { - return num_acls; - } else { - return rc; - } + if (rc < 0) + { + + // error... + vdev_error ("vdev_acl_match_process(%d) rc = %d\n", + pstat_get_pid (caller_proc), rc); + break; + } + // success! + found = true; + idx = i; + rc = 0; + break; + } + + if (found) + { + return idx; + } + else + { + if (rc >= 0) + { + return num_acls; } + else + { + return rc; + } + } } // apply the acl to the stat buf, filtering on caller uid, gid, and process information -int vdev_acl_apply(struct vdev_acl *acl, uid_t caller_uid, gid_t caller_gid, - struct stat *sb) +int +vdev_acl_apply (struct vdev_acl *acl, uid_t caller_uid, gid_t caller_gid, + struct stat *sb) { - // set user, group, mode (if given) - vdev_acl_do_set_user(acl, caller_uid, sb); - vdev_acl_do_set_group(acl, caller_gid, sb); - vdev_acl_do_set_mode(acl, sb); + // set user, group, mode (if given) + vdev_acl_do_set_user (acl, caller_uid, sb); + vdev_acl_do_set_group (acl, caller_gid, sb); + vdev_acl_do_set_mode (acl, sb); - return 0; + return 0; } // go through the list of acls and apply any modifications to the given stat buffer // return 1 if at least one ACL matches // return 0 if there are no matches (i.e. this device node should be hidden) // return negative on error -int vdev_acl_apply_all(struct vdev_config *config, struct vdev_acl *acls, - size_t num_acls, char const *path, - struct pstat *caller_proc, uid_t caller_uid, - gid_t caller_gid, struct stat *sb) +int +vdev_acl_apply_all (struct vdev_config *config, struct vdev_acl *acls, + size_t num_acls, char const *path, + struct pstat *caller_proc, uid_t caller_uid, + gid_t caller_gid, struct stat *sb) { - int rc = 0; - int acl_offset = 0; - int i = 0; - bool found = false; + int rc = 0; + int acl_offset = 0; + int i = 0; + bool found = false; - // special case: if there are no ACLs, then follow the config default policy - if (num_acls == 0) { - return config->default_policy; - } + // special case: if there are no ACLs, then follow the config default policy + if (num_acls == 0) + { + return config->default_policy; + } + + while (acl_offset < (signed) num_acls) + { + + // find the next acl + rc = vdev_acl_find_next (path, caller_proc, caller_uid, + caller_gid, acls + acl_offset, + num_acls - acl_offset); - while (acl_offset < (signed)num_acls) { - - // find the next acl - rc = vdev_acl_find_next(path, caller_proc, caller_uid, - caller_gid, acls + acl_offset, - num_acls - acl_offset); - - if (rc == (signed)(num_acls - acl_offset)) { - - // not found - rc = 0; - break; - } else if (rc < 0) { - - vdev_error - ("vdev_acl_find_next(%s, offset = %d) rc = %d\n", - path, acl_offset, rc); - break; - } else { - - // matched! advance offset to next acl - i = acl_offset + rc; - acl_offset += rc + 1; - found = true; - - // apply the ACL - rc = vdev_acl_apply(&acls[i], caller_uid, caller_gid, - sb); - if (rc != 0) { - - vdev_error - ("vdev_acl_apply(%s, offset = %d) rc = %d\n", - path, acl_offset, rc); - break; - } - } + if (rc == (signed) (num_acls - acl_offset)) + { + + // not found + rc = 0; + break; } + else if (rc < 0) + { - if (rc == 0) { - // no error reported - if (found) { - rc = 1; - } + vdev_error + ("vdev_acl_find_next(%s, offset = %d) rc = %d\n", + path, acl_offset, rc); + break; + } + else + { + + // matched! advance offset to next acl + i = acl_offset + rc; + acl_offset += rc + 1; + found = true; + + // apply the ACL + rc = vdev_acl_apply (&acls[i], caller_uid, caller_gid, sb); + if (rc != 0) + { + + vdev_error + ("vdev_acl_apply(%s, offset = %d) rc = %d\n", + path, acl_offset, rc); + break; + } + } + } + + if (rc == 0) + { + // no error reported + if (found) + { + rc = 1; } + } - return rc; + return rc; } diff --git a/fs/acl.h b/fs/acl.h index ca91ae2..2baa6cf 100644 --- a/fs/acl.h +++ b/fs/acl.h @@ -46,39 +46,40 @@ #define VDEV_ACL_PROC_BUFLEN 65536 // vdev access control list. -struct vdev_acl { - - // user to match - bool has_uid; - uid_t uid; - - // group to match - bool has_gid; - gid_t gid; - - // process info to match (set at least one; all must match for the ACL to apply) - bool has_proc; // if true, at least one of the following is filled in (and the ACL will only apply if the request is from one of the indicated processes) - char *proc_path; // path to the allowed process - char *proc_predicate_cmd; // command string to run to see if this ACL applies to the calling process (based on the exit code: 0 indicates 'yes, this applies'; nonzero indicates 'no, does not apply') - bool has_proc_inode; // whether or not the ACL has an inode check - ino_t proc_inode; // process binary's inode - - // UID to set on match - bool has_setuid; - uid_t setuid; - - // GID to set on match - bool has_setgid; - gid_t setgid; - - // mode to set on match - bool has_setmode; - mode_t setmode; - - // device node path regexes over which this ACL applies (NULL-terminated) - char **paths; - regex_t *regexes; - size_t num_paths; +struct vdev_acl +{ + + // user to match + bool has_uid; + uid_t uid; + + // group to match + bool has_gid; + gid_t gid; + + // process info to match (set at least one; all must match for the ACL to apply) + bool has_proc; // if true, at least one of the following is filled in (and the ACL will only apply if the request is from one of the indicated processes) + char *proc_path; // path to the allowed process + char *proc_predicate_cmd; // command string to run to see if this ACL applies to the calling process (based on the exit code: 0 indicates 'yes, this applies'; nonzero indicates 'no, does not apply') + bool has_proc_inode; // whether or not the ACL has an inode check + ino_t proc_inode; // process binary's inode + + // UID to set on match + bool has_setuid; + uid_t setuid; + + // GID to set on match + bool has_setgid; + gid_t setgid; + + // mode to set on match + bool has_setmode; + mode_t setmode; + + // device node path regexes over which this ACL applies (NULL-terminated) + char **paths; + regex_t *regexes; + size_t num_paths; }; typedef struct vdev_acl vdev_acl; @@ -86,16 +87,16 @@ typedef struct vdev_acl vdev_acl; // prototype... struct vdev_config; -C_LINKAGE_BEGIN int vdev_acl_init(struct vdev_acl *acl); -int vdev_acl_load_all(char const *dir_path, struct vdev_acl **ret_acls, - size_t * ret_num_acls); -int vdev_acl_free(struct vdev_acl *acl); -int vdev_acl_free_all(struct vdev_acl *acl_list, size_t num_acls); +C_LINKAGE_BEGIN int vdev_acl_init (struct vdev_acl *acl); +int vdev_acl_load_all (char const *dir_path, struct vdev_acl **ret_acls, + size_t * ret_num_acls); +int vdev_acl_free (struct vdev_acl *acl); +int vdev_acl_free_all (struct vdev_acl *acl_list, size_t num_acls); -int vdev_acl_apply_all(struct vdev_config *conf, struct vdev_acl *acls, - size_t num_acls, char const *path, - struct pstat *caller_proc, uid_t caller_uid, - gid_t caller_gid, struct stat *sb); +int vdev_acl_apply_all (struct vdev_config *conf, struct vdev_acl *acls, + size_t num_acls, char const *path, + struct pstat *caller_proc, uid_t caller_uid, + gid_t caller_gid, struct stat *sb); C_LINKAGE_END #endif diff --git a/fs/fs.c b/fs/fs.c index 389e8a3..578428b 100644 --- a/fs/fs.c +++ b/fs/fs.c @@ -27,37 +27,40 @@ static char const *vdev_fuse_ononempty = "-ononempty"; static char const *vdev_fuse_allow_other = "-oallow_other"; // scanning context queue entry -struct vdevfs_scandirat_queue { +struct vdevfs_scandirat_queue +{ - int fd; - char *path; + int fd; + char *path; - struct vdevfs_scandirat_queue *next; + struct vdevfs_scandirat_queue *next; }; // scanning context, for vdevfs_dev_import -struct vdevfs_scandirat_context { +struct vdevfs_scandirat_context +{ - struct fskit_core *core; // fskit core context - struct fskit_entry *parent_dir; // corresponding fskit directory being scanned - char *parent_path; + struct fskit_core *core; // fskit core context + struct fskit_entry *parent_dir; // corresponding fskit directory being scanned + char *parent_path; - struct vdevfs_scandirat_queue *tail; + struct vdevfs_scandirat_queue *tail; }; // set up a vdevfs_scandirat_context // always succeeds -static void vdevfs_scandirat_context_init(struct vdevfs_scandirat_context *ctx, - struct fskit_core *core, - struct fskit_entry *parent_dir, - char *parent_path, - struct vdevfs_scandirat_queue *tail) +static void +vdevfs_scandirat_context_init (struct vdevfs_scandirat_context *ctx, + struct fskit_core *core, + struct fskit_entry *parent_dir, + char *parent_path, + struct vdevfs_scandirat_queue *tail) { - ctx->core = core; - ctx->parent_dir = parent_dir; - ctx->parent_path = parent_path; - ctx->tail = tail; + ctx->core = core; + ctx->parent_dir = parent_dir; + ctx->parent_path = parent_path; + ctx->tail = tail; } // callback to be fed int vdev_load_all_at. @@ -65,334 +68,364 @@ static void vdevfs_scandirat_context_init(struct vdevfs_scandirat_context *ctx, // if we find a directory, open it and enqueue its file descriptor to dir_queue. // return 0 on success // return -ENOMEM on OOM -static int vdevfs_scandirat_context_callback(int dirfd, struct dirent *dent, - void *cls) +static int +vdevfs_scandirat_context_callback (int dirfd, struct dirent *dent, void *cls) { - struct vdevfs_scandirat_context *ctx = - (struct vdevfs_scandirat_context *)cls; - - int rc = 0; - int fd = 0; - struct stat sb; - struct fskit_entry *child; - char linkbuf[8193]; // for resolving an underlying symlink - char const *method_name; // for logging - char *joined_path = NULL; - struct vdevfs_scandirat_queue *next = NULL; - - // skip . and .. - if (strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0) { - return 0; - } - // learn more... - rc = fstatat(dirfd, dent->d_name, &sb, AT_SYMLINK_NOFOLLOW); - if (rc != 0) { - - rc = -errno; - - // mask errors; just log the serious ones - if (rc != -ENOENT && rc != -EACCES) { - - vdev_error("fstatat(%d, '%s') rc = %d\n", dirfd, - dent->d_name, rc); - } - - return 0; - } - // directory? get an fd to it if so, so we can keep scanning - if (S_ISDIR(sb.st_mode)) { - - // try to get at it - fd = openat(dirfd, dent->d_name, O_RDONLY); - if (fd < 0) { - - rc = -errno; - - // mask errors; just log the serious ones - if (rc != -ENOENT && rc != -EACCES) { - - vdev_error("openat(%d, '%s') rc = %d\n", dirfd, - dent->d_name, rc); - } - - return 0; - } - // woo! save it - joined_path = - vdev_fullpath(ctx->parent_path, dent->d_name, NULL); - if (joined_path == NULL) { - - close(fd); - return -ENOMEM; - } - - next = VDEV_CALLOC(struct vdevfs_scandirat_queue, 1); - if (next == NULL) { - - close(fd); - free(joined_path); - return -ENOMEM; - } - - next->fd = fd; - next->path = joined_path; - next->next = NULL; - - ctx->tail->next = next; - ctx->tail = ctx->tail->next; - } - // construct an inode for this entry - child = fskit_entry_new(); - if (child == NULL) { - - return -ENOMEM; - } - // regular file? - if (S_ISREG(sb.st_mode)) { - - method_name = "fskit_entry_init_file"; - rc = fskit_entry_init_file(child, sb.st_ino, sb.st_uid, - sb.st_gid, sb.st_mode & 0777); - } - // directory? - else if (S_ISDIR(sb.st_mode)) { - - method_name = "fskit_entry_init_dir"; - rc = fskit_entry_init_dir(child, ctx->parent_dir, sb.st_ino, - sb.st_uid, sb.st_gid, - sb.st_mode & 0777); - } - // named pipe? - else if (S_ISFIFO(sb.st_mode)) { - - method_name = "fskit_entry_init_fifo"; - rc = fskit_entry_init_fifo(child, sb.st_ino, sb.st_uid, - sb.st_gid, sb.st_mode & 0777); - } - // unix domain socket? - else if (S_ISSOCK(sb.st_mode)) { - - method_name = "fskit_entry_init_sock"; - rc = fskit_entry_init_sock(child, sb.st_ino, sb.st_uid, - sb.st_gid, sb.st_mode & 0777); - } - // character device? - else if (S_ISCHR(sb.st_mode)) { - - method_name = "fskit_entry_init_chr"; - rc = fskit_entry_init_chr(child, sb.st_ino, sb.st_uid, - sb.st_gid, sb.st_mode, sb.st_rdev); - } - // block device? - else if (S_ISBLK(sb.st_mode)) { - - method_name = "fskit_entry_init_blk"; - rc = fskit_entry_init_blk(child, sb.st_ino, sb.st_uid, - sb.st_gid, sb.st_mode, sb.st_rdev); - } - // symbolic link? - else if (S_ISLNK(sb.st_mode)) { - - // read the link first... - memset(linkbuf, 0, 8193); - - rc = readlinkat(dirfd, dent->d_name, linkbuf, 8192); - if (rc < 0) { - - rc = -errno; - - // mask error, but log serious ones. this link will not appear in the listing - if (rc != -ENOENT && rc != -EACCES) { - - vdev_error("readlinkat(%d, '%s') rc = %d\n", - dirfd, dent->d_name, rc); - } - - free(child); - child = NULL; - - return 0; - } - - method_name = "fskit_entry_init_symlink"; - rc = fskit_entry_init_symlink(child, sb.st_ino, linkbuf); - } - // success? - if (rc != 0) { - - vdev_error("%s( on %d, '%s' ) rc = %d\n", method_name, dirfd, - dent->d_name, rc); - - free(child); - child = NULL; - - return rc; - } - // insert into parent - rc = fskit_entry_attach_lowlevel(ctx->parent_dir, child, dent->d_name); - if (rc != 0) { - - // OOM - fskit_entry_destroy(ctx->core, child, false); - - free(child); - child = NULL; - - return rc; - } - // success! - return rc; + struct vdevfs_scandirat_context *ctx = + (struct vdevfs_scandirat_context *) cls; + + int rc = 0; + int fd = 0; + struct stat sb; + struct fskit_entry *child; + char linkbuf[8193]; // for resolving an underlying symlink + char const *method_name; // for logging + char *joined_path = NULL; + struct vdevfs_scandirat_queue *next = NULL; + + // skip . and .. + if (strcmp (dent->d_name, ".") == 0 || strcmp (dent->d_name, "..") == 0) + { + return 0; + } + // learn more... + rc = fstatat (dirfd, dent->d_name, &sb, AT_SYMLINK_NOFOLLOW); + if (rc != 0) + { + + rc = -errno; + + // mask errors; just log the serious ones + if (rc != -ENOENT && rc != -EACCES) + { + + vdev_error ("fstatat(%d, '%s') rc = %d\n", dirfd, dent->d_name, rc); + } + + return 0; + } + // directory? get an fd to it if so, so we can keep scanning + if (S_ISDIR (sb.st_mode)) + { + + // try to get at it + fd = openat (dirfd, dent->d_name, O_RDONLY); + if (fd < 0) + { + + rc = -errno; + + // mask errors; just log the serious ones + if (rc != -ENOENT && rc != -EACCES) + { + + vdev_error ("openat(%d, '%s') rc = %d\n", dirfd, + dent->d_name, rc); + } + + return 0; + } + // woo! save it + joined_path = vdev_fullpath (ctx->parent_path, dent->d_name, NULL); + if (joined_path == NULL) + { + + close (fd); + return -ENOMEM; + } + + next = VDEV_CALLOC (struct vdevfs_scandirat_queue, 1); + if (next == NULL) + { + + close (fd); + free (joined_path); + return -ENOMEM; + } + + next->fd = fd; + next->path = joined_path; + next->next = NULL; + + ctx->tail->next = next; + ctx->tail = ctx->tail->next; + } + // construct an inode for this entry + child = fskit_entry_new (); + if (child == NULL) + { + + return -ENOMEM; + } + // regular file? + if (S_ISREG (sb.st_mode)) + { + + method_name = "fskit_entry_init_file"; + rc = fskit_entry_init_file (child, sb.st_ino, sb.st_uid, + sb.st_gid, sb.st_mode & 0777); + } + // directory? + else if (S_ISDIR (sb.st_mode)) + { + + method_name = "fskit_entry_init_dir"; + rc = fskit_entry_init_dir (child, ctx->parent_dir, sb.st_ino, + sb.st_uid, sb.st_gid, sb.st_mode & 0777); + } + // named pipe? + else if (S_ISFIFO (sb.st_mode)) + { + + method_name = "fskit_entry_init_fifo"; + rc = fskit_entry_init_fifo (child, sb.st_ino, sb.st_uid, + sb.st_gid, sb.st_mode & 0777); + } + // unix domain socket? + else if (S_ISSOCK (sb.st_mode)) + { + + method_name = "fskit_entry_init_sock"; + rc = fskit_entry_init_sock (child, sb.st_ino, sb.st_uid, + sb.st_gid, sb.st_mode & 0777); + } + // character device? + else if (S_ISCHR (sb.st_mode)) + { + + method_name = "fskit_entry_init_chr"; + rc = fskit_entry_init_chr (child, sb.st_ino, sb.st_uid, + sb.st_gid, sb.st_mode, sb.st_rdev); + } + // block device? + else if (S_ISBLK (sb.st_mode)) + { + + method_name = "fskit_entry_init_blk"; + rc = fskit_entry_init_blk (child, sb.st_ino, sb.st_uid, + sb.st_gid, sb.st_mode, sb.st_rdev); + } + // symbolic link? + else if (S_ISLNK (sb.st_mode)) + { + + // read the link first... + memset (linkbuf, 0, 8193); + + rc = readlinkat (dirfd, dent->d_name, linkbuf, 8192); + if (rc < 0) + { + + rc = -errno; + + // mask error, but log serious ones. this link will not appear in the listing + if (rc != -ENOENT && rc != -EACCES) + { + + vdev_error ("readlinkat(%d, '%s') rc = %d\n", + dirfd, dent->d_name, rc); + } + + free (child); + child = NULL; + + return 0; + } + + method_name = "fskit_entry_init_symlink"; + rc = fskit_entry_init_symlink (child, sb.st_ino, linkbuf); + } + // success? + if (rc != 0) + { + + vdev_error ("%s( on %d, '%s' ) rc = %d\n", method_name, dirfd, + dent->d_name, rc); + + free (child); + child = NULL; + + return rc; + } + // insert into parent + rc = fskit_entry_attach_lowlevel (ctx->parent_dir, child, dent->d_name); + if (rc != 0) + { + + // OOM + fskit_entry_destroy (ctx->core, child, false); + + free (child); + child = NULL; + + return rc; + } + // success! + return rc; } // load the filesystem with metadata from under the mountpoint // return 0 on success // return -ENOMEM on OOM -static int vdevfs_dev_import(struct fskit_fuse_state *fs, void *arg) +static int +vdevfs_dev_import (struct fskit_fuse_state *fs, void *arg) { - struct vdevfs *vdev = (struct vdevfs *)arg; - int rc = 0; - struct vdevfs_scandirat_queue *dir_queue = NULL; - struct vdevfs_scandirat_queue *dir_queue_tail = NULL; - struct vdevfs_scandirat_queue *ptr = NULL; - struct fskit_entry *dir_ent = NULL; - - struct vdevfs_scandirat_context scan_context; - - char *root = vdev_strdup_or_null("/"); - if (root == NULL) { - return -ENOMEM; - } + struct vdevfs *vdev = (struct vdevfs *) arg; + int rc = 0; + struct vdevfs_scandirat_queue *dir_queue = NULL; + struct vdevfs_scandirat_queue *dir_queue_tail = NULL; + struct vdevfs_scandirat_queue *ptr = NULL; + struct fskit_entry *dir_ent = NULL; + + struct vdevfs_scandirat_context scan_context; - int root_fd = dup(vdev->mountpoint_dirfd); - if (root_fd < 0) { + char *root = vdev_strdup_or_null ("/"); + if (root == NULL) + { + return -ENOMEM; + } - vdev_error("dup(%d) rc = %d\n", vdev->mountpoint_dirfd, rc); - rc = -errno; - free(root); - return rc; - } - // start at the mountpoint - dir_queue = VDEV_CALLOC(struct vdevfs_scandirat_queue, 1); - if (dir_queue == NULL) { + int root_fd = dup (vdev->mountpoint_dirfd); + if (root_fd < 0) + { - free(root); - close(root_fd); - return -ENOMEM; - } + vdev_error ("dup(%d) rc = %d\n", vdev->mountpoint_dirfd, rc); + rc = -errno; + free (root); + return rc; + } + // start at the mountpoint + dir_queue = VDEV_CALLOC (struct vdevfs_scandirat_queue, 1); + if (dir_queue == NULL) + { - dir_queue->fd = root_fd; - dir_queue->path = root; - dir_queue->next = NULL; + free (root); + close (root_fd); + return -ENOMEM; + } - dir_queue_tail = dir_queue; + dir_queue->fd = root_fd; + dir_queue->path = root; + dir_queue->next = NULL; - while (dir_queue != NULL) { + dir_queue_tail = dir_queue; - int dirfd = dir_queue->fd; - char *dirpath = dir_queue->path; + while (dir_queue != NULL) + { - // look up this entry - dir_ent = - fskit_entry_resolve_path(fskit_fuse_get_core(vdev->fs), - dirpath, 0, 0, true, &rc); - if (rc != 0) { + int dirfd = dir_queue->fd; + char *dirpath = dir_queue->path; - // shouldn't happen--we're going breadth-first - vdev_error("fskit_entry_resolve_path('%s') rc = %d\n", - dirpath, rc); - break; - } - // make a scan context - vdevfs_scandirat_context_init(&scan_context, - fskit_fuse_get_core(vdev->fs), - dir_ent, dirpath, dir_queue_tail); + // look up this entry + dir_ent = + fskit_entry_resolve_path (fskit_fuse_get_core (vdev->fs), + dirpath, 0, 0, true, &rc); + if (rc != 0) + { - // scan this directory - rc = vdev_load_all_at(dirfd, vdevfs_scandirat_context_callback, - &scan_context); + // shouldn't happen--we're going breadth-first + vdev_error ("fskit_entry_resolve_path('%s') rc = %d\n", + dirpath, rc); + break; + } + // make a scan context + vdevfs_scandirat_context_init (&scan_context, + fskit_fuse_get_core (vdev->fs), + dir_ent, dirpath, dir_queue_tail); - fskit_entry_unlock(dir_ent); + // scan this directory + rc = vdev_load_all_at (dirfd, vdevfs_scandirat_context_callback, + &scan_context); - if (rc != 0) { + fskit_entry_unlock (dir_ent); - // failed - vdev_error("vdev_load_all_at(%d, '%s') rc = %d\n", - dirfd, dirpath, rc); - break; - } - // advance tail pointer - dir_queue_tail = scan_context.tail; + if (rc != 0) + { - // advance to next directory - close(dirfd); - free(dirpath); - dirpath = NULL; + // failed + vdev_error ("vdev_load_all_at(%d, '%s') rc = %d\n", + dirfd, dirpath, rc); + break; + } + // advance tail pointer + dir_queue_tail = scan_context.tail; - ptr = dir_queue; - dir_queue = dir_queue->next; + // advance to next directory + close (dirfd); + free (dirpath); + dirpath = NULL; - memset(ptr, 0, sizeof(struct vdevfs_scandirat_queue)); - free(ptr); - } + ptr = dir_queue; + dir_queue = dir_queue->next; - // free any remaining directory state - for (struct vdevfs_scandirat_queue * ptr = dir_queue; ptr != NULL;) { + memset (ptr, 0, sizeof (struct vdevfs_scandirat_queue)); + free (ptr); + } - int fd = ptr->fd; - char *path = ptr->path; - struct vdevfs_scandirat_queue *old_ptr = ptr; + // free any remaining directory state + for (struct vdevfs_scandirat_queue * ptr = dir_queue; ptr != NULL;) + { - close(fd); - free(path); + int fd = ptr->fd; + char *path = ptr->path; + struct vdevfs_scandirat_queue *old_ptr = ptr; - ptr = ptr->next; + close (fd); + free (path); + + ptr = ptr->next; - memset(old_ptr, 0, sizeof(struct vdevfs_scandirat_queue)); - free(old_ptr); - } + memset (old_ptr, 0, sizeof (struct vdevfs_scandirat_queue)); + free (old_ptr); + } - return rc; + return rc; } // get the mountpoint option, by parsing the FUSE command line -static int vdev_get_mountpoint(int fuse_argc, char **fuse_argv, - char **ret_mountpoint) +static int +vdev_get_mountpoint (int fuse_argc, char **fuse_argv, char **ret_mountpoint) { - struct fuse_args fargs = FUSE_ARGS_INIT(fuse_argc, fuse_argv); - char *mountpoint = NULL; - int unused_1; - int unused_2; - int rc = 0; + struct fuse_args fargs = FUSE_ARGS_INIT (fuse_argc, fuse_argv); + char *mountpoint = NULL; + int unused_1; + int unused_2; + int rc = 0; - // parse command-line... - rc = fuse_parse_cmdline(&fargs, &mountpoint, &unused_1, &unused_2); - if (rc < 0) { + // parse command-line... + rc = fuse_parse_cmdline (&fargs, &mountpoint, &unused_1, &unused_2); + if (rc < 0) + { - vdev_error("fuse_parse_cmdline rc = %d\n", rc); - fuse_opt_free_args(&fargs); + vdev_error ("fuse_parse_cmdline rc = %d\n", rc); + fuse_opt_free_args (&fargs); - return rc; - } - - else { + return rc; + } - if (mountpoint != NULL) { + else + { - *ret_mountpoint = strdup(mountpoint); - free(mountpoint); + if (mountpoint != NULL) + { - rc = 0; - } else { - rc = -ENOMEM; - } + *ret_mountpoint = strdup (mountpoint); + free (mountpoint); - fuse_opt_free_args(&fargs); + rc = 0; } + else + { + rc = -ENOMEM; + } + + fuse_opt_free_args (&fargs); + } - return 0; + return 0; } // initialize the filesystem front-end @@ -400,953 +433,1040 @@ static int vdev_get_mountpoint(int fuse_argc, char **fuse_argv, // return 0 on success // return -ENOMEM on OOM // return negative on error -int vdevfs_init(struct vdevfs *vdev, int argc, char **argv) +int +vdevfs_init (struct vdevfs *vdev, int argc, char **argv) { - int rc = 0; - int rh = 0; - struct fskit_core *core = NULL; - int fuse_argc = 0; - char **fuse_argv = NULL; - int dirfd = 0; - - // library setup - vdev_setup_global(); - - struct fskit_fuse_state *fs = fskit_fuse_state_new(); - - if (fs == NULL) { - return -ENOMEM; - } - - fuse_argv = VDEV_CALLOC(char *, argc + 5); - - if (fuse_argv == NULL) { - - free(fs); - return -ENOMEM; - } - // load config - vdev->config = VDEV_CALLOC(struct vdev_config, 1); - if (vdev->config == NULL) { - - free(fs); - free(fuse_argv); - return -ENOMEM; - } - // init config - rc = vdev_config_init(vdev->config); - if (rc != 0) { - - vdev_error("vdev_config_init rc = %d\n", rc); - - vdevfs_shutdown(vdev); - free(fs); - free(fuse_argv); - return rc; - } - // parse opts - rc = vdev_config_load_from_args(vdev->config, argc, argv, &fuse_argc, - fuse_argv); - if (rc != 0) { - - vdev_error("vdev_opts_parse rc = %d\n", rc); - - vdev_config_usage(argv[0]); - - free(fs); - free(fuse_argv); - vdevfs_shutdown(vdev); - return rc; - } - // get the mountpoint, but from FUSE - if (vdev->config->mountpoint != NULL) { - free(vdev->config->mountpoint); - } - - rc = vdev_get_mountpoint(fuse_argc, fuse_argv, - &vdev->config->mountpoint); - if (rc != 0) { - - vdev_error("vdev_get_mountpoint rc = %d\n", rc); - - vdev_config_usage(argv[0]); - - free(fs); - free(fuse_argv); - return rc; - } - - vdev_set_debug_level(vdev->config->debug_level); - vdev_set_error_level(vdev->config->error_level); - - vdev_debug("Config file: %s\n", vdev->config->config_path); - - rc = vdev_config_load(vdev->config->config_path, vdev->config); - if (rc != 0) { - - vdev_error("vdev_config_load('%s') rc = %d\n", - vdev->config->config_path, rc); - - vdevfs_shutdown(vdev); - free(fs); - free(fuse_argv); - return rc; - } - - vdev_debug("vdev ACLs dir: %s\n", vdev->config->acls_dir); - - // force -odev, since we'll create device nodes - fuse_argv[fuse_argc] = (char *)vdev_fuse_odev; - fuse_argc++; - - // force -oallow_other, since we'll want to expose this to everyone - fuse_argv[fuse_argc] = (char *)vdev_fuse_allow_other; - fuse_argc++; - - // force -ononempty, since we'll want to import the underlying filesystem - fuse_argv[fuse_argc] = (char *)vdev_fuse_ononempty; - fuse_argc++; - - vdev->mountpoint = vdev_strdup_or_null(vdev->config->mountpoint); - - if (vdev->mountpoint == NULL) { - - vdev_error - ("Failed to set mountpoint, config.mountpount = '%s'\n", - vdev->config->mountpoint); - - vdevfs_shutdown(vdev); - free(fuse_argv); - free(fs); - return -EINVAL; - } else { - - vdev_debug("mountpoint: %s\n", vdev->mountpoint); - } - - vdev->argc = argc; - vdev->argv = argv; - vdev->fuse_argc = fuse_argc; - vdev->fuse_argv = fuse_argv; - - fskit_set_debug_level(vdev->config->debug_level); - fskit_set_error_level(vdev->config->error_level); - - // get mountpoint directory - dirfd = open(vdev->mountpoint, O_DIRECTORY); - if (dirfd < 0) { - - rc = -errno; - vdev_error("open('%s') rc = %d\n", vdev->mountpoint, rc); - - free(fs); - vdevfs_shutdown(vdev); - return rc; - } - - vdev->mountpoint_dirfd = dirfd; - - // set up fskit - rc = fskit_fuse_init(fs, vdev); - if (rc != 0) { - - vdev_error("fskit_fuse_init rc = %d\n", rc); - free(fs); - vdevfs_shutdown(vdev); - return rc; - } - // load ACLs - rc = vdev_acl_load_all(vdev->config->acls_dir, &vdev->acls, - &vdev->num_acls); - if (rc != 0) { - - vdev_error("vdev_acl_load_all('%s') rc = %d\n", - vdev->config->acls_dir, rc); - - fskit_fuse_shutdown(fs, NULL); - free(fs); - vdevfs_shutdown(vdev); - return rc; - } - // make sure the fs can access its methods through the VFS - fskit_fuse_setting_enable(fs, FSKIT_FUSE_SET_FS_ACCESS); - - core = fskit_fuse_get_core(fs); - - // add handlers. - rh = fskit_route_readdir(core, FSKIT_ROUTE_ANY, vdevfs_readdir, - FSKIT_CONCURRENT); - if (rh < 0) { - - vdev_error("fskit_route_readdir(%s) rc = %d\n", FSKIT_ROUTE_ANY, - rh); - goto vdev_route_fail; - } - - rh = fskit_route_stat(core, FSKIT_ROUTE_ANY, vdevfs_stat, - FSKIT_CONCURRENT); - if (rh < 0) { + int rc = 0; + int rh = 0; + struct fskit_core *core = NULL; + int fuse_argc = 0; + char **fuse_argv = NULL; + int dirfd = 0; + + // library setup + vdev_setup_global (); + + struct fskit_fuse_state *fs = fskit_fuse_state_new (); + + if (fs == NULL) + { + return -ENOMEM; + } - vdev_error("fskit_route_stat(%s) rc = %d\n", FSKIT_ROUTE_ANY, - rh); - goto vdev_route_fail; - } - - rh = fskit_route_mknod(core, FSKIT_ROUTE_ANY, vdevfs_mknod, - FSKIT_CONCURRENT); - if (rc < 0) { - - vdev_error("fskit_route_mknod(%s) rc = %d\n", FSKIT_ROUTE_ANY, - rh); - goto vdev_route_fail; - } - - rh = fskit_route_mkdir(core, FSKIT_ROUTE_ANY, vdevfs_mkdir, - FSKIT_CONCURRENT); - if (rh < 0) { - - vdev_error("fskit_route_mkdir(%s) rc = %d\n", FSKIT_ROUTE_ANY, - rh); - goto vdev_route_fail; - } - - rh = fskit_route_create(core, FSKIT_ROUTE_ANY, vdevfs_create, - FSKIT_CONCURRENT); - if (rh < 0) { - - vdev_error("fskit_route_create(%s) rc = %d\n", FSKIT_ROUTE_ANY, - rh); - goto vdev_route_fail; - } - - rh = fskit_route_open(core, FSKIT_ROUTE_ANY, vdevfs_open, - FSKIT_CONCURRENT); - if (rh < 0) { - - vdev_error("fskit_route_open(%s) rc = %d\n", FSKIT_ROUTE_ANY, - rh); - goto vdev_route_fail; - } - - rh = fskit_route_read(core, FSKIT_ROUTE_ANY, vdevfs_read, - FSKIT_CONCURRENT); - if (rh < 0) { - - vdev_error("fskit_route_read(%s) rc = %d\n", FSKIT_ROUTE_ANY, - rh); - goto vdev_route_fail; - } - - rh = fskit_route_write(core, FSKIT_ROUTE_ANY, vdevfs_write, - FSKIT_CONCURRENT); - if (rh < 0) { - - vdev_error("fskit_route_write(%s) rc = %d\n", FSKIT_ROUTE_ANY, - rh); - goto vdev_route_fail; - } - - rh = fskit_route_close(core, FSKIT_ROUTE_ANY, vdevfs_close, - FSKIT_CONCURRENT); - if (rh < 0) { - - vdev_error("fskit_route_close(%s) rc = %d\n", FSKIT_ROUTE_ANY, - rh); - goto vdev_route_fail; - } - - rh = fskit_route_sync(core, FSKIT_ROUTE_ANY, vdevfs_sync, - FSKIT_CONCURRENT); - if (rh < 0) { - - vdev_error("fskit_route_sync(%s) rc = %d\n", FSKIT_ROUTE_ANY, - rh); - goto vdev_route_fail; - } - - rh = fskit_route_detach(core, FSKIT_ROUTE_ANY, vdevfs_detach, - FSKIT_CONCURRENT); - if (rh < 0) { - - vdev_error("fskit_route_detach(%s) rc = %d\n", FSKIT_ROUTE_ANY, - rh); - goto vdev_route_fail; - } - - vdev->fs = fs; - vdev->close_rh = rh; - - // set the root to be owned by the effective UID and GID of user - fskit_chown(core, "/", 0, 0, geteuid(), getegid()); + fuse_argv = VDEV_CALLOC (char *, argc + 5); + + if (fuse_argv == NULL) + { - // import the underlying filesystem once we're mounted, but before taking requests. - rc = fskit_fuse_postmount_callback(fs, vdevfs_dev_import, vdev); - if (rc != 0) { + free (fs); + return -ENOMEM; + } + // load config + vdev->config = VDEV_CALLOC (struct vdev_config, 1); + if (vdev->config == NULL) + { + + free (fs); + free (fuse_argv); + return -ENOMEM; + } + // init config + rc = vdev_config_init (vdev->config); + if (rc != 0) + { + + vdev_error ("vdev_config_init rc = %d\n", rc); + + vdevfs_shutdown (vdev); + free (fs); + free (fuse_argv); + return rc; + } + // parse opts + rc = vdev_config_load_from_args (vdev->config, argc, argv, &fuse_argc, + fuse_argv); + if (rc != 0) + { + + vdev_error ("vdev_opts_parse rc = %d\n", rc); + + vdev_config_usage (argv[0]); + + free (fs); + free (fuse_argv); + vdevfs_shutdown (vdev); + return rc; + } + // get the mountpoint, but from FUSE + if (vdev->config->mountpoint != NULL) + { + free (vdev->config->mountpoint); + } + + rc = vdev_get_mountpoint (fuse_argc, fuse_argv, &vdev->config->mountpoint); + if (rc != 0) + { + + vdev_error ("vdev_get_mountpoint rc = %d\n", rc); + + vdev_config_usage (argv[0]); + + free (fs); + free (fuse_argv); + return rc; + } + + vdev_set_debug_level (vdev->config->debug_level); + vdev_set_error_level (vdev->config->error_level); + + vdev_debug ("Config file: %s\n", vdev->config->config_path); + + rc = vdev_config_load (vdev->config->config_path, vdev->config); + if (rc != 0) + { + + vdev_error ("vdev_config_load('%s') rc = %d\n", + vdev->config->config_path, rc); + + vdevfs_shutdown (vdev); + free (fs); + free (fuse_argv); + return rc; + } + + vdev_debug ("vdev ACLs dir: %s\n", vdev->config->acls_dir); + + // force -odev, since we'll create device nodes + fuse_argv[fuse_argc] = (char *) vdev_fuse_odev; + fuse_argc++; + + // force -oallow_other, since we'll want to expose this to everyone + fuse_argv[fuse_argc] = (char *) vdev_fuse_allow_other; + fuse_argc++; + + // force -ononempty, since we'll want to import the underlying filesystem + fuse_argv[fuse_argc] = (char *) vdev_fuse_ononempty; + fuse_argc++; + + vdev->mountpoint = vdev_strdup_or_null (vdev->config->mountpoint); + + if (vdev->mountpoint == NULL) + { + + vdev_error + ("Failed to set mountpoint, config.mountpount = '%s'\n", + vdev->config->mountpoint); + + vdevfs_shutdown (vdev); + free (fuse_argv); + free (fs); + return -EINVAL; + } + else + { + + vdev_debug ("mountpoint: %s\n", vdev->mountpoint); + } + + vdev->argc = argc; + vdev->argv = argv; + vdev->fuse_argc = fuse_argc; + vdev->fuse_argv = fuse_argv; + + fskit_set_debug_level (vdev->config->debug_level); + fskit_set_error_level (vdev->config->error_level); + + // get mountpoint directory + dirfd = open (vdev->mountpoint, O_DIRECTORY); + if (dirfd < 0) + { + + rc = -errno; + vdev_error ("open('%s') rc = %d\n", vdev->mountpoint, rc); + + free (fs); + vdevfs_shutdown (vdev); + return rc; + } + + vdev->mountpoint_dirfd = dirfd; + + // set up fskit + rc = fskit_fuse_init (fs, vdev); + if (rc != 0) + { + + vdev_error ("fskit_fuse_init rc = %d\n", rc); + free (fs); + vdevfs_shutdown (vdev); + return rc; + } + // load ACLs + rc = vdev_acl_load_all (vdev->config->acls_dir, &vdev->acls, + &vdev->num_acls); + if (rc != 0) + { + + vdev_error ("vdev_acl_load_all('%s') rc = %d\n", + vdev->config->acls_dir, rc); + + fskit_fuse_shutdown (fs, NULL); + free (fs); + vdevfs_shutdown (vdev); + return rc; + } + // make sure the fs can access its methods through the VFS + fskit_fuse_setting_enable (fs, FSKIT_FUSE_SET_FS_ACCESS); + + core = fskit_fuse_get_core (fs); + + // add handlers. + rh = fskit_route_readdir (core, FSKIT_ROUTE_ANY, vdevfs_readdir, + FSKIT_CONCURRENT); + if (rh < 0) + { + + vdev_error ("fskit_route_readdir(%s) rc = %d\n", FSKIT_ROUTE_ANY, rh); + goto vdev_route_fail; + } + + rh = fskit_route_stat (core, FSKIT_ROUTE_ANY, vdevfs_stat, + FSKIT_CONCURRENT); + if (rh < 0) + { + + vdev_error ("fskit_route_stat(%s) rc = %d\n", FSKIT_ROUTE_ANY, rh); + goto vdev_route_fail; + } + + rh = fskit_route_mknod (core, FSKIT_ROUTE_ANY, vdevfs_mknod, + FSKIT_CONCURRENT); + if (rc < 0) + { + + vdev_error ("fskit_route_mknod(%s) rc = %d\n", FSKIT_ROUTE_ANY, rh); + goto vdev_route_fail; + } + + rh = fskit_route_mkdir (core, FSKIT_ROUTE_ANY, vdevfs_mkdir, + FSKIT_CONCURRENT); + if (rh < 0) + { + + vdev_error ("fskit_route_mkdir(%s) rc = %d\n", FSKIT_ROUTE_ANY, rh); + goto vdev_route_fail; + } + + rh = fskit_route_create (core, FSKIT_ROUTE_ANY, vdevfs_create, + FSKIT_CONCURRENT); + if (rh < 0) + { + + vdev_error ("fskit_route_create(%s) rc = %d\n", FSKIT_ROUTE_ANY, rh); + goto vdev_route_fail; + } + + rh = fskit_route_open (core, FSKIT_ROUTE_ANY, vdevfs_open, + FSKIT_CONCURRENT); + if (rh < 0) + { + + vdev_error ("fskit_route_open(%s) rc = %d\n", FSKIT_ROUTE_ANY, rh); + goto vdev_route_fail; + } + + rh = fskit_route_read (core, FSKIT_ROUTE_ANY, vdevfs_read, + FSKIT_CONCURRENT); + if (rh < 0) + { + + vdev_error ("fskit_route_read(%s) rc = %d\n", FSKIT_ROUTE_ANY, rh); + goto vdev_route_fail; + } + + rh = fskit_route_write (core, FSKIT_ROUTE_ANY, vdevfs_write, + FSKIT_CONCURRENT); + if (rh < 0) + { + + vdev_error ("fskit_route_write(%s) rc = %d\n", FSKIT_ROUTE_ANY, rh); + goto vdev_route_fail; + } + + rh = fskit_route_close (core, FSKIT_ROUTE_ANY, vdevfs_close, + FSKIT_CONCURRENT); + if (rh < 0) + { + + vdev_error ("fskit_route_close(%s) rc = %d\n", FSKIT_ROUTE_ANY, rh); + goto vdev_route_fail; + } + + rh = fskit_route_sync (core, FSKIT_ROUTE_ANY, vdevfs_sync, + FSKIT_CONCURRENT); + if (rh < 0) + { + + vdev_error ("fskit_route_sync(%s) rc = %d\n", FSKIT_ROUTE_ANY, rh); + goto vdev_route_fail; + } + + rh = fskit_route_detach (core, FSKIT_ROUTE_ANY, vdevfs_detach, + FSKIT_CONCURRENT); + if (rh < 0) + { + + vdev_error ("fskit_route_detach(%s) rc = %d\n", FSKIT_ROUTE_ANY, rh); + goto vdev_route_fail; + } + + vdev->fs = fs; + vdev->close_rh = rh; + + // set the root to be owned by the effective UID and GID of user + fskit_chown (core, "/", 0, 0, geteuid (), getegid ()); + + // import the underlying filesystem once we're mounted, but before taking requests. + rc = fskit_fuse_postmount_callback (fs, vdevfs_dev_import, vdev); + if (rc != 0) + { + + vdev_error ("fskit_fuse_postmount_callback() rc = %d\n", rc); + + vdev->fs = NULL; + goto vdev_route_fail; + } + + return 0; - vdev_error("fskit_fuse_postmount_callback() rc = %d\n", rc); - - vdev->fs = NULL; - goto vdev_route_fail; - } - - return 0; - - vdev_route_fail: - - fskit_fuse_shutdown(fs, NULL); - free(fs); - vdevfs_shutdown(vdev); - return rh; +vdev_route_fail: + + fskit_fuse_shutdown (fs, NULL); + free (fs); + vdevfs_shutdown (vdev); + return rh; } // main loop for vdev frontend -int vdevfs_main(struct vdevfs *vdev, int fuse_argc, char **fuse_argv) +int +vdevfs_main (struct vdevfs *vdev, int fuse_argc, char **fuse_argv) { - int rc = 0; + int rc = 0; - rc = fskit_fuse_main(vdev->fs, fuse_argc, fuse_argv); + rc = fskit_fuse_main (vdev->fs, fuse_argc, fuse_argv); - return rc; + return rc; } // shut down the front-end -int vdevfs_shutdown(struct vdevfs *vdev) +int +vdevfs_shutdown (struct vdevfs *vdev) { - if (vdev->fs != NULL) { + if (vdev->fs != NULL) + { - // stop processing unlink() requests, since the filesystem itself will unlink all files when it frees itself up. - fskit_unroute_detach(fskit_fuse_get_core(vdev->fs), - vdev->close_rh); + // stop processing unlink() requests, since the filesystem itself will unlink all files when it frees itself up. + fskit_unroute_detach (fskit_fuse_get_core (vdev->fs), vdev->close_rh); - fskit_fuse_shutdown(vdev->fs, NULL); - free(vdev->fs); - vdev->fs = NULL; - } + fskit_fuse_shutdown (vdev->fs, NULL); + free (vdev->fs); + vdev->fs = NULL; + } - if (vdev->acls != NULL) { - vdev_acl_free_all(vdev->acls, vdev->num_acls); - } + if (vdev->acls != NULL) + { + vdev_acl_free_all (vdev->acls, vdev->num_acls); + } - if (vdev->config != NULL) { - vdev_config_free(vdev->config); - free(vdev->config); - vdev->config = NULL; - } + if (vdev->config != NULL) + { + vdev_config_free (vdev->config); + free (vdev->config); + vdev->config = NULL; + } - if (vdev->mountpoint != NULL) { + if (vdev->mountpoint != NULL) + { - free(vdev->mountpoint); - vdev->mountpoint = NULL; - } + free (vdev->mountpoint); + vdev->mountpoint = NULL; + } - if (vdev->fuse_argv != NULL) { + if (vdev->fuse_argv != NULL) + { - free(vdev->fuse_argv); - vdev->fuse_argc = 0; - vdev->fuse_argv = NULL; - } + free (vdev->fuse_argv); + vdev->fuse_argc = 0; + vdev->fuse_argv = NULL; + } - if (vdev->mountpoint_dirfd >= 0) { + if (vdev->mountpoint_dirfd >= 0) + { - close(vdev->mountpoint_dirfd); - vdev->mountpoint_dirfd = -1; - } + close (vdev->mountpoint_dirfd); + vdev->mountpoint_dirfd = -1; + } - memset(vdev, 0, sizeof(struct vdevfs)); + memset (vdev, 0, sizeof (struct vdevfs)); - return 0; + return 0; } // for creating, opening, or stating files, verify that the caller is permitted according to our ACLs // return 0 on success // return -EPERM if denied // return other -errno on error -static int vdevfs_access_check(struct vdevfs *vdev, - struct fskit_fuse_state *fs_state, - char const *method_name, char const *path) +static int +vdevfs_access_check (struct vdevfs *vdev, + struct fskit_fuse_state *fs_state, + char const *method_name, char const *path) { - int rc = 0; - pid_t pid = 0; - uid_t uid = 0; - gid_t gid = 0; - struct stat sb; - struct pstat *ps = NULL; - - memset(&sb, 0, sizeof(struct stat)); - sb.st_mode = 0777; - - // stat the calling process - pid = fskit_fuse_get_pid(); - uid = fskit_fuse_get_uid(fs_state); - gid = fskit_fuse_get_gid(fs_state); - - ps = pstat_new(); - if (ps == NULL) { - return -ENOMEM; - } - - vdev_debug("%s('%s') from user %d group %d task %d\n", method_name, - path, uid, gid, pid); - - // see who's asking - rc = pstat(pid, ps, 0); - if (rc != 0) { - - vdev_error("pstat(%d) rc = %d\n", pid, rc); - pstat_free(ps); - return -EIO; - } - // apply the ACLs on the stat buffer - rc = vdev_acl_apply_all(vdev->config, vdev->acls, vdev->num_acls, path, - ps, uid, gid, &sb); - pstat_free(ps); - - if (rc < 0) { - - vdev_error - ("vdev_acl_apply_all(%s, uid=%d, gid=%d, pid=%d) rc = %d\n", - path, uid, gid, pid, rc); - return -EIO; - } - // omit entirely? - if (rc == 0 || (sb.st_mode & 0777) == 0) { - - // filter - vdev_debug("DENY '%s'\n", path); - return -EPERM; - } else { - - // accept! - return 0; - } + int rc = 0; + pid_t pid = 0; + uid_t uid = 0; + gid_t gid = 0; + struct stat sb; + struct pstat *ps = NULL; + + memset (&sb, 0, sizeof (struct stat)); + sb.st_mode = 0777; + + // stat the calling process + pid = fskit_fuse_get_pid (); + uid = fskit_fuse_get_uid (fs_state); + gid = fskit_fuse_get_gid (fs_state); + + ps = pstat_new (); + if (ps == NULL) + { + return -ENOMEM; + } + + vdev_debug ("%s('%s') from user %d group %d task %d\n", method_name, + path, uid, gid, pid); + + // see who's asking + rc = pstat (pid, ps, 0); + if (rc != 0) + { + + vdev_error ("pstat(%d) rc = %d\n", pid, rc); + pstat_free (ps); + return -EIO; + } + // apply the ACLs on the stat buffer + rc = vdev_acl_apply_all (vdev->config, vdev->acls, vdev->num_acls, path, + ps, uid, gid, &sb); + pstat_free (ps); + + if (rc < 0) + { + + vdev_error + ("vdev_acl_apply_all(%s, uid=%d, gid=%d, pid=%d) rc = %d\n", + path, uid, gid, pid, rc); + return -EIO; + } + // omit entirely? + if (rc == 0 || (sb.st_mode & 0777) == 0) + { + + // filter + vdev_debug ("DENY '%s'\n", path); + return -EPERM; + } + else + { + + // accept! + return 0; + } } // mknod: create the device node as normal, but also write to the underlying filesystem as an emergency counter-measure -int vdevfs_mknod(struct fskit_core *core, struct fskit_route_metadata *grp, - struct fskit_entry *fent, mode_t mode, dev_t dev, - void **inode_cls) +int +vdevfs_mknod (struct fskit_core *core, struct fskit_route_metadata *grp, + struct fskit_entry *fent, mode_t mode, dev_t dev, + void **inode_cls) { - int rc = 0; - struct vdevfs *vdev = (struct vdevfs *)fskit_core_get_user_data(core); - struct fskit_fuse_state *fs_state = fskit_fuse_get_state(); - char const *path = NULL; + int rc = 0; + struct vdevfs *vdev = (struct vdevfs *) fskit_core_get_user_data (core); + struct fskit_fuse_state *fs_state = fskit_fuse_get_state (); + char const *path = NULL; - rc = vdevfs_access_check(vdev, fs_state, "mknod", - fskit_route_metadata_get_path(grp)); - if (rc < 0) { + rc = vdevfs_access_check (vdev, fs_state, "mknod", + fskit_route_metadata_get_path (grp)); + if (rc < 0) + { - // denied! - return -EACCES; - } - // must be relative path - path = fskit_route_metadata_get_path(grp); - while (*path == '/' && *path != '\0') { - path++; - } + // denied! + return -EACCES; + } + // must be relative path + path = fskit_route_metadata_get_path (grp); + while (*path == '/' && *path != '\0') + { + path++; + } - if (*path == '\0') { - path = "."; - } + if (*path == '\0') + { + path = "."; + } - rc = mknodat(vdev->mountpoint_dirfd, path, dev, mode); + rc = mknodat (vdev->mountpoint_dirfd, path, dev, mode); - if (rc != 0) { + if (rc != 0) + { - rc = -errno; - vdev_error("mknodat('%s', '%s') rc = %d\n", vdev->mountpoint, - path, rc); + rc = -errno; + vdev_error ("mknodat('%s', '%s') rc = %d\n", vdev->mountpoint, + path, rc); - return rc; - } + return rc; + } - return 0; + return 0; } // mkdir: create the directory as normal, but also write to the underlying filesystem as an emergency counter-measure -int vdevfs_mkdir(struct fskit_core *core, struct fskit_route_metadata *grp, - struct fskit_entry *fent, mode_t mode, void **inode_cls) +int +vdevfs_mkdir (struct fskit_core *core, struct fskit_route_metadata *grp, + struct fskit_entry *fent, mode_t mode, void **inode_cls) { - int rc = 0; - struct vdevfs *vdev = (struct vdevfs *)fskit_core_get_user_data(core); - struct fskit_fuse_state *fs_state = fskit_fuse_get_state(); - char const *path = NULL; + int rc = 0; + struct vdevfs *vdev = (struct vdevfs *) fskit_core_get_user_data (core); + struct fskit_fuse_state *fs_state = fskit_fuse_get_state (); + char const *path = NULL; - rc = vdevfs_access_check(vdev, fs_state, "mkdir", - fskit_route_metadata_get_path(grp)); - if (rc < 0) { + rc = vdevfs_access_check (vdev, fs_state, "mkdir", + fskit_route_metadata_get_path (grp)); + if (rc < 0) + { - // denied! - return -EACCES; - } - // must be relative path - path = fskit_route_metadata_get_path(grp); - while (*path == '/' && *path != '\0') { - path++; - } + // denied! + return -EACCES; + } + // must be relative path + path = fskit_route_metadata_get_path (grp); + while (*path == '/' && *path != '\0') + { + path++; + } - if (*path == '\0') { - path = "."; - } + if (*path == '\0') + { + path = "."; + } - rc = mkdirat(vdev->mountpoint_dirfd, path, mode); + rc = mkdirat (vdev->mountpoint_dirfd, path, mode); - if (rc != 0) { + if (rc != 0) + { - rc = -errno; - vdev_error("mkdirat('%s', '%s') rc = %d\n", vdev->mountpoint, - path, rc); + rc = -errno; + vdev_error ("mkdirat('%s', '%s') rc = %d\n", vdev->mountpoint, + path, rc); - return rc; - } + return rc; + } - return 0; + return 0; } // creat: create the file as usual, but also write to the underlying filesystem as an emergency counter-measure // NOTE: since this is backed by FUSE, this handler will only be called for regular files -int vdevfs_create(struct fskit_core *core, struct fskit_route_metadata *grp, - struct fskit_entry *fent, mode_t mode, void **inode_cls, - void **handle_cls) +int +vdevfs_create (struct fskit_core *core, struct fskit_route_metadata *grp, + struct fskit_entry *fent, mode_t mode, void **inode_cls, + void **handle_cls) { - int fd = 0; - struct vdevfs *vdev = (struct vdevfs *)fskit_core_get_user_data(core); - struct fskit_fuse_state *fs_state = fskit_fuse_get_state(); - char const *path = NULL; - int rc = 0; - - rc = vdevfs_access_check(vdev, fs_state, "create", - fskit_route_metadata_get_path(grp)); - if (rc < 0) { - - // denied! - return -EACCES; - } - // must be relative path - path = fskit_route_metadata_get_path(grp); - while (*path == '/' && *path != '\0') { - path++; - } - - if (*path == '\0') { - path = "."; - } - // success! - fd = openat(vdev->mountpoint_dirfd, path, O_CREAT | O_WRONLY | O_TRUNC, - mode); - if (fd < 0) { - - fd = -errno; - vdev_error("openat('%s', '%s') rc = %d\n", vdev->mountpoint, - path, fd); - - return fd; - } - // careful... - void *handle_data = NULL; - memcpy(&handle_data, &fd, 4); - - *handle_cls = handle_data; - - return 0; + int fd = 0; + struct vdevfs *vdev = (struct vdevfs *) fskit_core_get_user_data (core); + struct fskit_fuse_state *fs_state = fskit_fuse_get_state (); + char const *path = NULL; + int rc = 0; + + rc = vdevfs_access_check (vdev, fs_state, "create", + fskit_route_metadata_get_path (grp)); + if (rc < 0) + { + + // denied! + return -EACCES; + } + // must be relative path + path = fskit_route_metadata_get_path (grp); + while (*path == '/' && *path != '\0') + { + path++; + } + + if (*path == '\0') + { + path = "."; + } + // success! + fd = openat (vdev->mountpoint_dirfd, path, O_CREAT | O_WRONLY | O_TRUNC, + mode); + if (fd < 0) + { + + fd = -errno; + vdev_error ("openat('%s', '%s') rc = %d\n", vdev->mountpoint, path, fd); + + return fd; + } + // careful... + void *handle_data = NULL; + memcpy (&handle_data, &fd, 4); + + *handle_cls = handle_data; + + return 0; } // open: open the file as usual, but from the underlying filesystem // NOTE: since this is backed by FUSE, this handler will only be called for regular files -int vdevfs_open(struct fskit_core *core, struct fskit_route_metadata *grp, - struct fskit_entry *fent, int flags, void **handle_cls) +int +vdevfs_open (struct fskit_core *core, struct fskit_route_metadata *grp, + struct fskit_entry *fent, int flags, void **handle_cls) { - int fd = 0; - struct vdevfs *vdev = (struct vdevfs *)fskit_core_get_user_data(core); - struct fskit_fuse_state *fs_state = fskit_fuse_get_state(); - char const *path = NULL; - - int rc = 0; - - // dir or file? - char const *method = NULL; - - if (fskit_entry_get_type(fent) == FSKIT_ENTRY_TYPE_DIR) { - - rc = vdevfs_access_check(vdev, fs_state, "opendir", - fskit_route_metadata_get_path(grp)); - } else { - - rc = vdevfs_access_check(vdev, fs_state, "open", - fskit_route_metadata_get_path(grp)); - } - - if (rc < 0) { - - // denied! - return -ENOENT; - } - // only care about open() for files - if (fskit_entry_get_type(fent) == FSKIT_ENTRY_TYPE_DIR) { - - // done! - return 0; - } - // must be relative path - path = fskit_route_metadata_get_path(grp); - while (*path == '/' && *path != '\0') { - path++; - } - - if (*path == '\0') { - path = "."; - } - - fd = openat(vdev->mountpoint_dirfd, path, flags); - if (fd < 0) { - - fd = -errno; - vdev_error("openat(%d, '%s') rc = %d\n", vdev->mountpoint_dirfd, - path, fd); - - return fd; - } - // careful... - void *handle_data = NULL; - memcpy(&handle_data, &fd, 4); - - *handle_cls = handle_data; - - return 0; + int fd = 0; + struct vdevfs *vdev = (struct vdevfs *) fskit_core_get_user_data (core); + struct fskit_fuse_state *fs_state = fskit_fuse_get_state (); + char const *path = NULL; + + int rc = 0; + + // dir or file? + char const *method = NULL; + + if (fskit_entry_get_type (fent) == FSKIT_ENTRY_TYPE_DIR) + { + + rc = vdevfs_access_check (vdev, fs_state, "opendir", + fskit_route_metadata_get_path (grp)); + } + else + { + + rc = vdevfs_access_check (vdev, fs_state, "open", + fskit_route_metadata_get_path (grp)); + } + + if (rc < 0) + { + + // denied! + return -ENOENT; + } + // only care about open() for files + if (fskit_entry_get_type (fent) == FSKIT_ENTRY_TYPE_DIR) + { + + // done! + return 0; + } + // must be relative path + path = fskit_route_metadata_get_path (grp); + while (*path == '/' && *path != '\0') + { + path++; + } + + if (*path == '\0') + { + path = "."; + } + + fd = openat (vdev->mountpoint_dirfd, path, flags); + if (fd < 0) + { + + fd = -errno; + vdev_error ("openat(%d, '%s') rc = %d\n", vdev->mountpoint_dirfd, + path, fd); + + return fd; + } + // careful... + void *handle_data = NULL; + memcpy (&handle_data, &fd, 4); + + *handle_cls = handle_data; + + return 0; } // read: read as usual, but from the underlying filesystem // NOTE: since this is backed by FUSE, this handler will only be called for regular files -int vdevfs_read(struct fskit_core *core, struct fskit_route_metadata *grp, - struct fskit_entry *fent, char *buf, size_t len, off_t offset, - void *handle_cls) +int +vdevfs_read (struct fskit_core *core, struct fskit_route_metadata *grp, + struct fskit_entry *fent, char *buf, size_t len, off_t offset, + void *handle_cls) { - // careful... - int fd = 0; - memcpy(&fd, &handle_cls, 4); + // careful... + int fd = 0; + memcpy (&fd, &handle_cls, 4); - int rc = 0; - struct vdevfs *vdev = (struct vdevfs *)fskit_core_get_user_data(core); + int rc = 0; + struct vdevfs *vdev = (struct vdevfs *) fskit_core_get_user_data (core); - rc = lseek(fd, offset, SEEK_SET); - if (rc < 0) { + rc = lseek (fd, offset, SEEK_SET); + if (rc < 0) + { - rc = -errno; - vdev_error("lseek(%d '%s') rc = %d\n", fd, - fskit_route_metadata_get_path(grp), rc); + rc = -errno; + vdev_error ("lseek(%d '%s') rc = %d\n", fd, + fskit_route_metadata_get_path (grp), rc); - return rc; - } + return rc; + } - rc = read(fd, buf, len); - if (rc < 0) { + rc = read (fd, buf, len); + if (rc < 0) + { - rc = -errno; - vdev_error("read(%d '%s') rc = %d\n", fd, - fskit_route_metadata_get_path(grp), rc); + rc = -errno; + vdev_error ("read(%d '%s') rc = %d\n", fd, + fskit_route_metadata_get_path (grp), rc); - return rc; - } + return rc; + } - return rc; + return rc; } // write; write as usual, but to the underlying filesystem // NOTE: since this is backed by FUSE, this handler will only be called for regular files -int vdevfs_write(struct fskit_core *core, struct fskit_route_metadata *grp, - struct fskit_entry *fent, char *buf, size_t len, off_t offset, - void *handle_cls) +int +vdevfs_write (struct fskit_core *core, struct fskit_route_metadata *grp, + struct fskit_entry *fent, char *buf, size_t len, off_t offset, + void *handle_cls) { - // careful... - int fd = 0; - memcpy(&fd, &handle_cls, 4); + // careful... + int fd = 0; + memcpy (&fd, &handle_cls, 4); - int rc = 0; - struct vdevfs *vdev = (struct vdevfs *)fskit_core_get_user_data(core); + int rc = 0; + struct vdevfs *vdev = (struct vdevfs *) fskit_core_get_user_data (core); - rc = lseek(fd, offset, SEEK_SET); - if (rc < 0) { + rc = lseek (fd, offset, SEEK_SET); + if (rc < 0) + { - rc = -errno; - vdev_error("lseek(%d '%s') rc = %d\n", fd, - fskit_route_metadata_get_path(grp), rc); + rc = -errno; + vdev_error ("lseek(%d '%s') rc = %d\n", fd, + fskit_route_metadata_get_path (grp), rc); - return rc; - } + return rc; + } - rc = write(fd, buf, len); - if (rc < 0) { + rc = write (fd, buf, len); + if (rc < 0) + { - rc = -errno; - vdev_error("write(%d '%s') rc = %d\n", fd, - fskit_route_metadata_get_path(grp), rc); + rc = -errno; + vdev_error ("write(%d '%s') rc = %d\n", fd, + fskit_route_metadata_get_path (grp), rc); - return rc; - } + return rc; + } - return rc; + return rc; } // close: close as usual // NOTE: since this is backed by FUSE, this handler will only be called for regular files -int vdevfs_close(struct fskit_core *core, struct fskit_route_metadata *grp, - struct fskit_entry *fent, void *handle_cls) +int +vdevfs_close (struct fskit_core *core, struct fskit_route_metadata *grp, + struct fskit_entry *fent, void *handle_cls) { - // only care about close() for files - if (fskit_entry_get_type(fent) == FSKIT_ENTRY_TYPE_DIR) { + // only care about close() for files + if (fskit_entry_get_type (fent) == FSKIT_ENTRY_TYPE_DIR) + { - // done! - return 0; - } - // careful... - int fd = 0; - memcpy(&fd, &handle_cls, 4); + // done! + return 0; + } + // careful... + int fd = 0; + memcpy (&fd, &handle_cls, 4); - int rc = 0; + int rc = 0; - rc = close(fd); - if (rc < 0) { + rc = close (fd); + if (rc < 0) + { - rc = -errno; - vdev_error("close(%d '%s') rc = %d\n", fd, - fskit_route_metadata_get_path(grp), rc); + rc = -errno; + vdev_error ("close(%d '%s') rc = %d\n", fd, + fskit_route_metadata_get_path (grp), rc); - return rc; - } + return rc; + } - return rc; + return rc; } // sync: sync as usual // NOTE: since this is backed by FUSE, this handler will only be called for regular files -int vdevfs_sync(struct fskit_core *core, struct fskit_route_metadata *grp, - struct fskit_entry *fent) +int +vdevfs_sync (struct fskit_core *core, struct fskit_route_metadata *grp, + struct fskit_entry *fent) { - void *user_data = fskit_entry_get_user_data(fent); + void *user_data = fskit_entry_get_user_data (fent); - // careful... - int fd = 0; - memcpy(&fd, &user_data, 4); + // careful... + int fd = 0; + memcpy (&fd, &user_data, 4); - int rc = 0; + int rc = 0; - rc = fsync(fd); - if (rc < 0) { + rc = fsync (fd); + if (rc < 0) + { - rc = -errno; - vdev_error("fsync(%d '%s') rc = %d\n", fd, - fskit_route_metadata_get_path(grp), rc); + rc = -errno; + vdev_error ("fsync(%d '%s') rc = %d\n", fd, + fskit_route_metadata_get_path (grp), rc); - return rc; - } + return rc; + } - return rc; + return rc; } // unlink/rmdir: remove the file or device node from the underlying filesystem -int vdevfs_detach(struct fskit_core *core, struct fskit_route_metadata *grp, - struct fskit_entry *fent, void *inode_cls) +int +vdevfs_detach (struct fskit_core *core, struct fskit_route_metadata *grp, + struct fskit_entry *fent, void *inode_cls) { - int rc = 0; - struct vdevfs *vdev = (struct vdevfs *)fskit_core_get_user_data(core); - struct fskit_fuse_state *fs_state = fskit_fuse_get_state(); - char const *method = NULL; + int rc = 0; + struct vdevfs *vdev = (struct vdevfs *) fskit_core_get_user_data (core); + struct fskit_fuse_state *fs_state = fskit_fuse_get_state (); + char const *method = NULL; - if (fskit_entry_get_type(fent) == FSKIT_ENTRY_TYPE_DIR) { + if (fskit_entry_get_type (fent) == FSKIT_ENTRY_TYPE_DIR) + { - method = "rmdir"; - } else { + method = "rmdir"; + } + else + { - method = "unlink"; - } + method = "unlink"; + } - rc = vdevfs_access_check(vdev, fs_state, method, - fskit_route_metadata_get_path(grp)); - if (rc < 0) { + rc = vdevfs_access_check (vdev, fs_state, method, + fskit_route_metadata_get_path (grp)); + if (rc < 0) + { - // denied! - return -ENOENT; - } + // denied! + return -ENOENT; + } - if (rc != 0) { + if (rc != 0) + { - rc = -errno; - vdev_error("%s('%s', '%s') rc = %d\n", method, vdev->mountpoint, - fskit_route_metadata_get_path(grp), rc); + rc = -errno; + vdev_error ("%s('%s', '%s') rc = %d\n", method, vdev->mountpoint, + fskit_route_metadata_get_path (grp), rc); - return rc; - } + return rc; + } - return 0; + return 0; } // stat: equvocate about which devices exist, depending on who's asking // return -ENOENT not only if the file doesn't exist, but also if the file is blocked by the ACL -int vdevfs_stat(struct fskit_core *core, struct fskit_route_metadata *grp, - struct fskit_entry *fent, struct stat *sb) +int +vdevfs_stat (struct fskit_core *core, struct fskit_route_metadata *grp, + struct fskit_entry *fent, struct stat *sb) { - int rc = 0; - struct vdevfs *vdev = (struct vdevfs *)fskit_core_get_user_data(core); - struct fskit_fuse_state *fs_state = fskit_fuse_get_state(); + int rc = 0; + struct vdevfs *vdev = (struct vdevfs *) fskit_core_get_user_data (core); + struct fskit_fuse_state *fs_state = fskit_fuse_get_state (); - if (fent == NULL) { - return -ENOENT; - } + if (fent == NULL) + { + return -ENOENT; + } - rc = vdevfs_access_check(vdev, fs_state, "stat", - fskit_route_metadata_get_path(grp)); - if (rc < 0) { + rc = vdevfs_access_check (vdev, fs_state, "stat", + fskit_route_metadata_get_path (grp)); + if (rc < 0) + { - // denied! - return -ENOENT; - } else { + // denied! + return -ENOENT; + } + else + { - return 0; - } + return 0; + } } // readdir: equivocate about which devices exist, depending on who's asking // omit entries if the ACLs forbid them -int vdevfs_readdir(struct fskit_core *core, struct fskit_route_metadata *grp, - struct fskit_entry *fent, struct fskit_dir_entry **dirents, - size_t num_dirents) +int +vdevfs_readdir (struct fskit_core *core, struct fskit_route_metadata *grp, + struct fskit_entry *fent, struct fskit_dir_entry **dirents, + size_t num_dirents) { - int rc = 0; - struct fskit_entry *child = NULL; + int rc = 0; + struct fskit_entry *child = NULL; + + // entries to omit in the listing + unsigned int omitted_idx = 0; + int *omitted = VDEV_CALLOC (int, num_dirents); + if (omitted == NULL) + { + return -ENOMEM; + } + + pid_t pid = 0; + uid_t uid = 0; + gid_t gid = 0; + + struct vdevfs *vdev = (struct vdevfs *) fskit_core_get_user_data (core); + struct fskit_fuse_state *fs_state = fskit_fuse_get_state (); + + struct stat sb; + struct stat fskit_sb; + struct pstat *ps = NULL; + char *child_path = NULL; + + pid = fskit_fuse_get_pid (); + uid = fskit_fuse_get_uid (fs_state); + gid = fskit_fuse_get_gid (fs_state); + + vdev_debug ("vdevfs_readdir(%s, %zu) from user %d group %d task %d\n", + fskit_route_metadata_get_path (grp), num_dirents, uid, gid, + pid); + + ps = pstat_new (); + if (ps == NULL) + { + free (omitted); + return -ENOMEM; + } + // see who's asking + rc = pstat (pid, ps, 0); + if (rc != 0) + { + + vdev_error ("pstat(%d) rc = %d\n", pid, rc); + pstat_free (ps); + free (omitted); + return -EIO; + } + + for (unsigned int i = 0; i < num_dirents; i++) + { - // entries to omit in the listing - unsigned int omitted_idx = 0; - int *omitted = VDEV_CALLOC(int, num_dirents); - if (omitted == NULL) { - return -ENOMEM; + // skip . and .. + if (strcmp (dirents[i]->name, ".") == 0 + || strcmp (dirents[i]->name, "..") == 0) + { + continue; } + // find the associated fskit_entry + child = fskit_dir_find_by_name (fent, dirents[i]->name); - pid_t pid = 0; - uid_t uid = 0; - gid_t gid = 0; + if (child == NULL) + { + // strange, shouldn't happen... + continue; + } + + fskit_entry_rlock (child); - struct vdevfs *vdev = (struct vdevfs *)fskit_core_get_user_data(core); - struct fskit_fuse_state *fs_state = fskit_fuse_get_state(); + // construct a stat buffer from what we actually need + memset (&sb, 0, sizeof (struct stat)); - struct stat sb; - struct stat fskit_sb; - struct pstat *ps = NULL; - char *child_path = NULL; + fskit_entry_fstat (child, &fskit_sb); + sb.st_uid = fskit_sb.st_uid; + sb.st_gid = fskit_sb.st_gid; + sb.st_mode = fskit_sb.st_mode; - pid = fskit_fuse_get_pid(); - uid = fskit_fuse_get_uid(fs_state); - gid = fskit_fuse_get_gid(fs_state); + child_path = + fskit_fullpath (fskit_route_metadata_get_path (grp), + fskit_route_metadata_get_name (grp), NULL); + if (child_path == NULL) + { - vdev_debug("vdevfs_readdir(%s, %zu) from user %d group %d task %d\n", - fskit_route_metadata_get_path(grp), num_dirents, uid, gid, - pid); + // can't continue; OOM + fskit_entry_unlock (child); + rc = -ENOMEM; + break; + } + // filter it + rc = vdev_acl_apply_all (vdev->config, vdev->acls, + vdev->num_acls, child_path, ps, uid, gid, &sb); + if (rc < 0) + { - ps = pstat_new(); - if (ps == NULL) { - free(omitted); - return -ENOMEM; + vdev_error + ("vdev_acl_apply_all('%s', uid=%d, gid=%d, pid=%d) rc = %d\n", + child_path, uid, gid, pid, rc); + rc = -EIO; } - // see who's asking - rc = pstat(pid, ps, 0); - if (rc != 0) { - - vdev_error("pstat(%d) rc = %d\n", pid, rc); - pstat_free(ps); - free(omitted); - return -EIO; + else if (rc == 0 || (sb.st_mode & 0777) == 0) + { + + // omit this one + vdev_debug ("Filter '%s'\n", fskit_route_metadata_get_name (grp)); + omitted[omitted_idx] = i; + omitted_idx++; + + rc = 0; } + else + { - for (unsigned int i = 0; i < num_dirents; i++) { - - // skip . and .. - if (strcmp(dirents[i]->name, ".") == 0 - || strcmp(dirents[i]->name, "..") == 0) { - continue; - } - // find the associated fskit_entry - child = fskit_dir_find_by_name(fent, dirents[i]->name); - - if (child == NULL) { - // strange, shouldn't happen... - continue; - } - - fskit_entry_rlock(child); - - // construct a stat buffer from what we actually need - memset(&sb, 0, sizeof(struct stat)); - - fskit_entry_fstat(child, &fskit_sb); - sb.st_uid = fskit_sb.st_uid; - sb.st_gid = fskit_sb.st_gid; - sb.st_mode = fskit_sb.st_mode; - - child_path = - fskit_fullpath(fskit_route_metadata_get_path(grp), - fskit_route_metadata_get_name(grp), NULL); - if (child_path == NULL) { - - // can't continue; OOM - fskit_entry_unlock(child); - rc = -ENOMEM; - break; - } - // filter it - rc = vdev_acl_apply_all(vdev->config, vdev->acls, - vdev->num_acls, child_path, ps, uid, - gid, &sb); - if (rc < 0) { - - vdev_error - ("vdev_acl_apply_all('%s', uid=%d, gid=%d, pid=%d) rc = %d\n", - child_path, uid, gid, pid, rc); - rc = -EIO; - } else if (rc == 0 || (sb.st_mode & 0777) == 0) { - - // omit this one - vdev_debug("Filter '%s'\n", - fskit_route_metadata_get_name(grp)); - omitted[omitted_idx] = i; - omitted_idx++; - - rc = 0; - } else { - - // success; matched - rc = 0; - } - - fskit_entry_unlock(child); - - free(child_path); - - // error? - if (rc != 0) { - break; - } + // success; matched + rc = 0; } - // skip ACL'ed entries - for (unsigned int i = 0; i < omitted_idx; i++) { + fskit_entry_unlock (child); - fskit_readdir_omit(dirents, omitted[i]); + free (child_path); + + // error? + if (rc != 0) + { + break; } + } + + // skip ACL'ed entries + for (unsigned int i = 0; i < omitted_idx; i++) + { + + fskit_readdir_omit (dirents, omitted[i]); + } - pstat_free(ps); - free(omitted); - return rc; + pstat_free (ps); + free (omitted); + return rc; } diff --git a/fs/fs.h b/fs/fs.h index 99ec8e1..1484852 100644 --- a/fs/fs.h +++ b/fs/fs.h @@ -32,68 +32,69 @@ #include "libvdev/util.h" #include "libvdev/config.h" -struct vdevfs { +struct vdevfs +{ - // configuration - struct vdev_config *config; + // configuration + struct vdev_config *config; - // arguments - int argc; - char **argv; + // arguments + int argc; + char **argv; - // FUSE-filtered arguments - int fuse_argc; - char **fuse_argv; + // FUSE-filtered arguments + int fuse_argc; + char **fuse_argv; - // mountpoint; where /dev is - char *mountpoint; + // mountpoint; where /dev is + char *mountpoint; - // mountpoint dir handle, underneath /dev - int mountpoint_dirfd; + // mountpoint dir handle, underneath /dev + int mountpoint_dirfd; - // fskit core - struct fskit_fuse_state *fs; + // fskit core + struct fskit_fuse_state *fs; - // acls - struct vdev_acl *acls; - size_t num_acls; + // acls + struct vdev_acl *acls; + size_t num_acls; - // close route handler id - int close_rh; + // close route handler id + int close_rh; }; C_LINKAGE_BEGIN - int vdevfs_mkdir(struct fskit_core *core, struct fskit_route_metadata *grp, - struct fskit_entry *fent, mode_t mode, void **inode_cls); -int vdevfs_mknod(struct fskit_core *core, struct fskit_route_metadata *grp, - struct fskit_entry *fent, mode_t mode, dev_t dev, - void **inode_cls); -int vdevfs_create(struct fskit_core *core, struct fskit_route_metadata *grp, - struct fskit_entry *fent, mode_t mode, void **inode_cls, - void **handle_cls); -int vdevfs_open(struct fskit_core *core, struct fskit_route_metadata *grp, - struct fskit_entry *fent, int flags, void **handle_cls); -int vdevfs_read(struct fskit_core *core, struct fskit_route_metadata *grp, - struct fskit_entry *fent, char *buf, size_t len, off_t offset, - void *handle_cls); -int vdevfs_write(struct fskit_core *core, struct fskit_route_metadata *grp, - struct fskit_entry *fent, char *buf, size_t len, off_t offset, - void *handle_cls); -int vdevfs_close(struct fskit_core *core, struct fskit_route_metadata *grp, - struct fskit_entry *fent, void *handle_cls); -int vdevfs_sync(struct fskit_core *core, struct fskit_route_metadata *grp, - struct fskit_entry *fent); -int vdevfs_detach(struct fskit_core *core, struct fskit_route_metadata *grp, - struct fskit_entry *fent, void *inode_cls); -int vdevfs_stat(struct fskit_core *core, struct fskit_route_metadata *grp, - struct fskit_entry *fent, struct stat *sb); -int vdevfs_readdir(struct fskit_core *core, struct fskit_route_metadata *grp, - struct fskit_entry *fent, struct fskit_dir_entry **dirents, - size_t num_dirents); - -int vdevfs_init(struct vdevfs *vdev, int argc, char **argv); -int vdevfs_main(struct vdevfs *vdev, int fuse_argc, char **fuse_argv); -int vdevfs_shutdown(struct vdevfs *vdev); + int vdevfs_mkdir (struct fskit_core *core, struct fskit_route_metadata *grp, + struct fskit_entry *fent, mode_t mode, void **inode_cls); +int vdevfs_mknod (struct fskit_core *core, struct fskit_route_metadata *grp, + struct fskit_entry *fent, mode_t mode, dev_t dev, + void **inode_cls); +int vdevfs_create (struct fskit_core *core, struct fskit_route_metadata *grp, + struct fskit_entry *fent, mode_t mode, void **inode_cls, + void **handle_cls); +int vdevfs_open (struct fskit_core *core, struct fskit_route_metadata *grp, + struct fskit_entry *fent, int flags, void **handle_cls); +int vdevfs_read (struct fskit_core *core, struct fskit_route_metadata *grp, + struct fskit_entry *fent, char *buf, size_t len, + off_t offset, void *handle_cls); +int vdevfs_write (struct fskit_core *core, struct fskit_route_metadata *grp, + struct fskit_entry *fent, char *buf, size_t len, + off_t offset, void *handle_cls); +int vdevfs_close (struct fskit_core *core, struct fskit_route_metadata *grp, + struct fskit_entry *fent, void *handle_cls); +int vdevfs_sync (struct fskit_core *core, struct fskit_route_metadata *grp, + struct fskit_entry *fent); +int vdevfs_detach (struct fskit_core *core, struct fskit_route_metadata *grp, + struct fskit_entry *fent, void *inode_cls); +int vdevfs_stat (struct fskit_core *core, struct fskit_route_metadata *grp, + struct fskit_entry *fent, struct stat *sb); +int vdevfs_readdir (struct fskit_core *core, struct fskit_route_metadata *grp, + struct fskit_entry *fent, + struct fskit_dir_entry **dirents, size_t num_dirents); + +int vdevfs_init (struct vdevfs *vdev, int argc, char **argv); +int vdevfs_main (struct vdevfs *vdev, int fuse_argc, char **fuse_argv); +int vdevfs_shutdown (struct vdevfs *vdev); C_LINKAGE_END -#endif // _VDEV_FS_H_ +#endif // _VDEV_FS_H_ diff --git a/fs/main.c b/fs/main.c index db0b6b2..fdc8c0c 100644 --- a/fs/main.c +++ b/fs/main.c @@ -22,27 +22,29 @@ #include "main.h" // run! -int main(int argc, char **argv) +int +main (int argc, char **argv) { - int rc = 0; - pid_t pid = 0; - struct vdevfs vdev; + int rc = 0; + pid_t pid = 0; + struct vdevfs vdev; - memset(&vdev, 0, sizeof(struct vdevfs)); + memset (&vdev, 0, sizeof (struct vdevfs)); - // set up global vdev state - rc = vdevfs_init(&vdev, argc, argv); - if (rc != 0) { + // set up global vdev state + rc = vdevfs_init (&vdev, argc, argv); + if (rc != 0) + { - vdev_error("vdevfs_init rc = %d\n", rc); + vdev_error ("vdevfs_init rc = %d\n", rc); - exit(1); - } - // run! - rc = vdevfs_main(&vdev, vdev.fuse_argc, vdev.fuse_argv); + exit (1); + } + // run! + rc = vdevfs_main (&vdev, vdev.fuse_argc, vdev.fuse_argv); - vdevfs_shutdown(&vdev); + vdevfs_shutdown (&vdev); - return rc; + return rc; } diff --git a/libudev-compat/MurmurHash2.c b/libudev-compat/MurmurHash2.c index 1d1974e..e379482 100644 --- a/libudev-compat/MurmurHash2.c +++ b/libudev-compat/MurmurHash2.c @@ -35,62 +35,65 @@ // Other compilers -#else // defined(_MSC_VER) +#else // defined(_MSC_VER) #define BIG_CONSTANT(x) (x##LLU) -#endif // !defined(_MSC_VER) +#endif // !defined(_MSC_VER) //----------------------------------------------------------------------------- -uint32_t MurmurHash2(const void *key, int len, uint32_t seed) +uint32_t +MurmurHash2 (const void *key, int len, uint32_t seed) { - // 'm' and 'r' are mixing constants generated offline. - // They're not really 'magic', they just happen to work well. + // 'm' and 'r' are mixing constants generated offline. + // They're not really 'magic', they just happen to work well. - const uint32_t m = 0x5bd1e995; - const int r = 24; + const uint32_t m = 0x5bd1e995; + const int r = 24; - // Initialize the hash to a 'random' value + // Initialize the hash to a 'random' value - uint32_t h = seed ^ len; + uint32_t h = seed ^ len; - // Mix 4 bytes at a time into the hash + // Mix 4 bytes at a time into the hash - const unsigned char *data = (const unsigned char *)key; + const unsigned char *data = (const unsigned char *) key; - while (len >= 4) { - uint32_t k = *(uint32_t *) data; + while (len >= 4) + { + uint32_t k = *(uint32_t *) data; - k *= m; - k ^= k >> r; - k *= m; + k *= m; + k ^= k >> r; + k *= m; - h *= m; - h ^= k; + h *= m; + h ^= k; - data += 4; - len -= 4; - } + data += 4; + len -= 4; + } - // Handle the last few bytes of the input array + // Handle the last few bytes of the input array - switch (len) { - case 3: - h ^= data[2] << 16; - case 2: - h ^= data[1] << 8; - case 1: - h ^= data[0]; - h *= m; - }; + switch (len) + { + case 3: + h ^= data[2] << 16; + case 2: + h ^= data[1] << 8; + case 1: + h ^= data[0]; + h *= m; + }; - // Do a few final mixes of the hash to ensure the last few - // bytes are well-incorporated. + // Do a few final mixes of the hash to ensure the last few + // bytes are well-incorporated. - h ^= h >> 13; - h *= m; - h ^= h >> 15; + h ^= h >> 13; + h *= m; + h ^= h >> 15; - return h; + return h; } diff --git a/libudev-compat/MurmurHash2.h b/libudev-compat/MurmurHash2.h index fb94f42..b1b21b4 100644 --- a/libudev-compat/MurmurHash2.h +++ b/libudev-compat/MurmurHash2.h @@ -27,16 +27,16 @@ typedef unsigned __int64 uint64_t; // Other compilers -#else // defined(_MSC_VER) +#else // defined(_MSC_VER) #include -#endif // !defined(_MSC_VER) +#endif // !defined(_MSC_VER) //----------------------------------------------------------------------------- -uint32_t MurmurHash2(const void *key, int len, uint32_t seed); +uint32_t MurmurHash2 (const void *key, int len, uint32_t seed); //----------------------------------------------------------------------------- -#endif // _MURMURHASH2_H_ +#endif // _MURMURHASH2_H_ diff --git a/libudev-compat/device-nodes.c b/libudev-compat/device-nodes.c index 611fbbb..1130d17 100644 --- a/libudev-compat/device-nodes.c +++ b/libudev-compat/device-nodes.c @@ -34,51 +34,58 @@ #include "device-nodes.h" #include "utf8.h" -int whitelisted_char_for_devnode(char c, const char *white) +int +whitelisted_char_for_devnode (char c, const char *white) { - if ((c >= '0' && c <= '9') || - (c >= 'A' && c <= 'Z') || - (c >= 'a' && c <= 'z') || - strchr("#+-.:=@_", c) != NULL || - (white != NULL && strchr(white, c) != NULL)) - return 1; - return 0; + if ((c >= '0' && c <= '9') || + (c >= 'A' && c <= 'Z') || + (c >= 'a' && c <= 'z') || + strchr ("#+-.:=@_", c) != NULL || + (white != NULL && strchr (white, c) != NULL)) + return 1; + return 0; } -int encode_devnode_name(const char *str, char *str_enc, size_t len) +int +encode_devnode_name (const char *str, char *str_enc, size_t len) { - size_t i, j; + size_t i, j; - if (str == NULL || str_enc == NULL) - return -EINVAL; + if (str == NULL || str_enc == NULL) + return -EINVAL; - for (i = 0, j = 0; str[i] != '\0'; i++) { - int seqlen; + for (i = 0, j = 0; str[i] != '\0'; i++) + { + int seqlen; - seqlen = utf8_encoded_valid_unichar(&str[i]); - if (seqlen > 1) { - if (len - j < (size_t) seqlen) - goto err; - memcpy(&str_enc[j], &str[i], seqlen); - j += seqlen; - i += (seqlen - 1); - } else if (str[i] == '\\' - || !whitelisted_char_for_devnode(str[i], NULL)) { - if (len - j < 4) - goto err; - sprintf(&str_enc[j], "\\x%02x", (unsigned char)str[i]); - j += 4; - } else { - if (len - j < 1) - goto err; - str_enc[j] = str[i]; - j++; - } + seqlen = utf8_encoded_valid_unichar (&str[i]); + if (seqlen > 1) + { + if (len - j < (size_t) seqlen) + goto err; + memcpy (&str_enc[j], &str[i], seqlen); + j += seqlen; + i += (seqlen - 1); } - if (len - j < 1) - goto err; - str_enc[j] = '\0'; - return 0; - err: - return -EINVAL; + else if (str[i] == '\\' || !whitelisted_char_for_devnode (str[i], NULL)) + { + if (len - j < 4) + goto err; + sprintf (&str_enc[j], "\\x%02x", (unsigned char) str[i]); + j += 4; + } + else + { + if (len - j < 1) + goto err; + str_enc[j] = str[i]; + j++; + } + } + if (len - j < 1) + goto err; + str_enc[j] = '\0'; + return 0; +err: + return -EINVAL; } diff --git a/libudev-compat/device-nodes.h b/libudev-compat/device-nodes.h index 0224796..4e81c1b 100644 --- a/libudev-compat/device-nodes.h +++ b/libudev-compat/device-nodes.h @@ -29,7 +29,7 @@ #ifndef _LIBUDEV_COMPAT_DEVICE_NODES_H_ #define _LIBUDEV_COMPAT_DEVICE_NODES_H_ -int encode_devnode_name(const char *str, char *str_enc, size_t len); -int whitelisted_char_for_devnode(char c, const char *additional); +int encode_devnode_name (const char *str, char *str_enc, size_t len); +int whitelisted_char_for_devnode (char c, const char *additional); #endif diff --git a/libudev-compat/hashmap.c b/libudev-compat/hashmap.c index e8a0715..9f85d2e 100644 --- a/libudev-compat/hashmap.c +++ b/libudev-compat/hashmap.c @@ -94,25 +94,29 @@ #define INV_KEEP_FREE 5U /* Fields common to entries of all hashmap/set types */ -struct hashmap_base_entry { - const void *key; +struct hashmap_base_entry +{ + const void *key; }; /* Entry types for specific hashmap/set types * hashmap_base_entry must be at the beginning of each entry struct. */ -struct plain_hashmap_entry { - struct hashmap_base_entry b; - void *value; +struct plain_hashmap_entry +{ + struct hashmap_base_entry b; + void *value; }; -struct ordered_hashmap_entry { - struct plain_hashmap_entry p; - unsigned iterate_next, iterate_previous; +struct ordered_hashmap_entry +{ + struct plain_hashmap_entry p; + unsigned iterate_next, iterate_previous; }; -struct set_entry { - struct hashmap_base_entry b; +struct set_entry +{ + struct hashmap_base_entry b; }; /* In several functions it is advantageous to have the hash table extended @@ -129,13 +133,14 @@ struct set_entry { /* special index value meaning "none" or "end" */ #define IDX_NIL UINT_MAX -assert_cc(IDX_FIRST == _IDX_SWAP_END); -assert_cc(IDX_FIRST == _IDX_ITERATOR_FIRST); +assert_cc (IDX_FIRST == _IDX_SWAP_END); +assert_cc (IDX_FIRST == _IDX_ITERATOR_FIRST); /* Storage space for the "swap" buckets. * All entry types can fit into a ordered_hashmap_entry. */ -struct swap_entries { - struct ordered_hashmap_entry e[_IDX_SWAP_END - _IDX_SWAP_BEGIN]; +struct swap_entries +{ + struct ordered_hashmap_entry e[_IDX_SWAP_END - _IDX_SWAP_BEGIN]; }; /* Distance from Initial Bucket */ @@ -148,66 +153,70 @@ typedef uint8_t dib_raw_t; #define DIB_FREE UINT_MAX #ifdef ENABLE_DEBUG_HASHMAP -struct hashmap_debug_info { - LIST_FIELDS(struct hashmap_debug_info, debug_list); - unsigned max_entries; /* high watermark of n_entries */ - - /* who allocated this hashmap */ - int line; - const char *file; - const char *func; - - /* fields to detect modification while iterating */ - unsigned put_count; /* counts puts into the hashmap */ - unsigned rem_count; /* counts removals from hashmap */ - unsigned last_rem_idx; /* remembers last removal index */ +struct hashmap_debug_info +{ + LIST_FIELDS (struct hashmap_debug_info, debug_list); + unsigned max_entries; /* high watermark of n_entries */ + + /* who allocated this hashmap */ + int line; + const char *file; + const char *func; + + /* fields to detect modification while iterating */ + unsigned put_count; /* counts puts into the hashmap */ + unsigned rem_count; /* counts removals from hashmap */ + unsigned last_rem_idx; /* remembers last removal index */ }; /* Tracks all existing hashmaps. Get at it from gdb. See sd_dump_hashmaps.py */ -static LIST_HEAD(struct hashmap_debug_info, hashmap_debug_list); +static LIST_HEAD (struct hashmap_debug_info, hashmap_debug_list); #define HASHMAP_DEBUG_FIELDS struct hashmap_debug_info debug; -#else /* !ENABLE_DEBUG_HASHMAP */ +#else /* !ENABLE_DEBUG_HASHMAP */ #define HASHMAP_DEBUG_FIELDS -#endif /* ENABLE_DEBUG_HASHMAP */ +#endif /* ENABLE_DEBUG_HASHMAP */ -enum HashmapType { - HASHMAP_TYPE_PLAIN, - HASHMAP_TYPE_ORDERED, - HASHMAP_TYPE_SET, - _HASHMAP_TYPE_MAX +enum HashmapType +{ + HASHMAP_TYPE_PLAIN, + HASHMAP_TYPE_ORDERED, + HASHMAP_TYPE_SET, + _HASHMAP_TYPE_MAX }; -struct _packed_ indirect_storage { - char *storage; /* where buckets and DIBs are stored */ - uint8_t hash_key[HASH_KEY_SIZE]; /* hash key; changes during resize */ +struct _packed_ indirect_storage +{ + char *storage; /* where buckets and DIBs are stored */ + uint8_t hash_key[HASH_KEY_SIZE]; /* hash key; changes during resize */ - unsigned n_entries; /* number of stored entries */ - unsigned n_buckets; /* number of buckets */ + unsigned n_entries; /* number of stored entries */ + unsigned n_buckets; /* number of buckets */ - unsigned idx_lowest_entry; /* Index below which all buckets are free. - Makes "while(hashmap_steal_first())" loops - O(n) instead of O(n^2) for unordered hashmaps. */ - uint8_t _pad[3]; /* padding for the whole HashmapBase */ - /* The bitfields in HashmapBase complete the alignment of the whole thing. */ + unsigned idx_lowest_entry; /* Index below which all buckets are free. + Makes "while(hashmap_steal_first())" loops + O(n) instead of O(n^2) for unordered hashmaps. */ + uint8_t _pad[3]; /* padding for the whole HashmapBase */ + /* The bitfields in HashmapBase complete the alignment of the whole thing. */ }; -struct direct_storage { - /* This gives us 39 bytes on 64bit, or 35 bytes on 32bit. - * That's room for 4 set_entries + 4 DIB bytes + 3 unused bytes on 64bit, - * or 7 set_entries + 7 DIB bytes + 0 unused bytes on 32bit. */ - char storage[sizeof(struct indirect_storage)]; +struct direct_storage +{ + /* This gives us 39 bytes on 64bit, or 35 bytes on 32bit. + * That's room for 4 set_entries + 4 DIB bytes + 3 unused bytes on 64bit, + * or 7 set_entries + 7 DIB bytes + 0 unused bytes on 32bit. */ + char storage[sizeof (struct indirect_storage)]; }; #define DIRECT_BUCKETS(entry_t) \ (sizeof(struct direct_storage) / (sizeof(entry_t) + sizeof(dib_raw_t))) /* We should be able to store at least one entry directly. */ -assert_cc(DIRECT_BUCKETS(struct ordered_hashmap_entry) >= 1); +assert_cc (DIRECT_BUCKETS (struct ordered_hashmap_entry) >= 1); /* We have 3 bits for n_direct_entries. */ -assert_cc(DIRECT_BUCKETS(struct set_entry) < (1 << 3)); +assert_cc (DIRECT_BUCKETS (struct set_entry) < (1 << 3)); /* Hashmaps with directly stored entries all use this shared hash key. * It's no big deal if the key is guessed, because there can be only @@ -217,613 +226,667 @@ static uint8_t shared_hash_key[HASH_KEY_SIZE]; static bool shared_hash_key_initialized; /* Fields that all hashmap/set types must have */ -struct HashmapBase { - const struct hash_ops *hash_ops; /* hash and compare ops to use */ - - union _packed_ { - struct indirect_storage indirect; /* if has_indirect */ - struct direct_storage direct; /* if !has_indirect */ - }; - - enum HashmapType type:2; /* HASHMAP_TYPE_* */ - bool has_indirect:1; /* whether indirect storage is used */ - unsigned n_direct_entries:3; /* Number of entries in direct storage. - * Only valid if !has_indirect. */ - bool from_pool:1; /* whether was allocated from mempool */ - HASHMAP_DEBUG_FIELDS /* optional hashmap_debug_info */ +struct HashmapBase +{ + const struct hash_ops *hash_ops; /* hash and compare ops to use */ + + union _packed_ + { + struct indirect_storage indirect; /* if has_indirect */ + struct direct_storage direct; /* if !has_indirect */ + }; + + enum HashmapType type:2; /* HASHMAP_TYPE_* */ + bool has_indirect:1; /* whether indirect storage is used */ + unsigned n_direct_entries:3; /* Number of entries in direct storage. + * Only valid if !has_indirect. */ + bool from_pool:1; /* whether was allocated from mempool */ + HASHMAP_DEBUG_FIELDS /* optional hashmap_debug_info */ }; /* Specific hash types * HashmapBase must be at the beginning of each hashmap struct. */ -struct Hashmap { - struct HashmapBase b; +struct Hashmap +{ + struct HashmapBase b; }; -struct OrderedHashmap { - struct HashmapBase b; - unsigned iterate_list_head, iterate_list_tail; +struct OrderedHashmap +{ + struct HashmapBase b; + unsigned iterate_list_head, iterate_list_tail; }; -struct Set { - struct HashmapBase b; +struct Set +{ + struct HashmapBase b; }; -DEFINE_MEMPOOL(hashmap_pool, Hashmap, 8); -DEFINE_MEMPOOL(ordered_hashmap_pool, OrderedHashmap, 8); +DEFINE_MEMPOOL (hashmap_pool, Hashmap, 8); +DEFINE_MEMPOOL (ordered_hashmap_pool, OrderedHashmap, 8); /* No need for a separate Set pool */ -assert_cc(sizeof(Hashmap) == sizeof(Set)); +assert_cc (sizeof (Hashmap) == sizeof (Set)); -struct hashmap_type_info { - size_t head_size; - size_t entry_size; - struct mempool *mempool; - unsigned n_direct_buckets; +struct hashmap_type_info +{ + size_t head_size; + size_t entry_size; + struct mempool *mempool; + unsigned n_direct_buckets; }; static const struct hashmap_type_info hashmap_type_info[_HASHMAP_TYPE_MAX] = { - [HASHMAP_TYPE_PLAIN] = { - .head_size = sizeof(Hashmap), - .entry_size = - sizeof(struct plain_hashmap_entry), - .mempool = &hashmap_pool, - .n_direct_buckets = - DIRECT_BUCKETS(struct plain_hashmap_entry), - }, - [HASHMAP_TYPE_ORDERED] = { - .head_size = sizeof(OrderedHashmap), - .entry_size = - sizeof(struct ordered_hashmap_entry), - .mempool = &ordered_hashmap_pool, - .n_direct_buckets = - DIRECT_BUCKETS(struct ordered_hashmap_entry), - }, - [HASHMAP_TYPE_SET] = { - .head_size = sizeof(Set), - .entry_size = sizeof(struct set_entry), - .mempool = &hashmap_pool, - .n_direct_buckets = - DIRECT_BUCKETS(struct set_entry), - }, + [HASHMAP_TYPE_PLAIN] = { + .head_size = sizeof (Hashmap), + .entry_size = sizeof (struct plain_hashmap_entry), + .mempool = &hashmap_pool, + .n_direct_buckets = + DIRECT_BUCKETS (struct plain_hashmap_entry), + }, + [HASHMAP_TYPE_ORDERED] = { + .head_size = sizeof (OrderedHashmap), + .entry_size = + sizeof (struct ordered_hashmap_entry), + .mempool = &ordered_hashmap_pool, + .n_direct_buckets = + DIRECT_BUCKETS (struct ordered_hashmap_entry), + }, + [HASHMAP_TYPE_SET] = { + .head_size = sizeof (Set), + .entry_size = sizeof (struct set_entry), + .mempool = &hashmap_pool, + .n_direct_buckets = DIRECT_BUCKETS (struct set_entry), + }, }; -unsigned long string_hash_func(const void *p, - const uint8_t hash_key[HASH_KEY_SIZE]) +unsigned long +string_hash_func (const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) { - uint64_t u; - siphash24((uint8_t *) & u, p, strlen(p), hash_key); - return (unsigned long)u; + uint64_t u; + siphash24 ((uint8_t *) & u, p, strlen (p), hash_key); + return (unsigned long) u; } -int string_compare_func(const void *a, const void *b) +int +string_compare_func (const void *a, const void *b) { - return strcmp(a, b); + return strcmp (a, b); } const struct hash_ops string_hash_ops = { - .hash = string_hash_func, - .compare = string_compare_func + .hash = string_hash_func, + .compare = string_compare_func }; -unsigned long trivial_hash_func(const void *p, - const uint8_t hash_key[HASH_KEY_SIZE]) +unsigned long +trivial_hash_func (const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) { - uint64_t u; - siphash24((uint8_t *) & u, &p, sizeof(p), hash_key); - return (unsigned long)u; + uint64_t u; + siphash24 ((uint8_t *) & u, &p, sizeof (p), hash_key); + return (unsigned long) u; } -int trivial_compare_func(const void *a, const void *b) +int +trivial_compare_func (const void *a, const void *b) { - return a < b ? -1 : (a > b ? 1 : 0); + return a < b ? -1 : (a > b ? 1 : 0); } const struct hash_ops trivial_hash_ops = { - .hash = trivial_hash_func, - .compare = trivial_compare_func + .hash = trivial_hash_func, + .compare = trivial_compare_func }; -unsigned long uint64_hash_func(const void *p, - const uint8_t hash_key[HASH_KEY_SIZE]) +unsigned long +uint64_hash_func (const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) { - uint64_t u; - siphash24((uint8_t *) & u, p, sizeof(uint64_t), hash_key); - return (unsigned long)u; + uint64_t u; + siphash24 ((uint8_t *) & u, p, sizeof (uint64_t), hash_key); + return (unsigned long) u; } -int uint64_compare_func(const void *_a, const void *_b) +int +uint64_compare_func (const void *_a, const void *_b) { - uint64_t a, b; - a = *(const uint64_t *)_a; - b = *(const uint64_t *)_b; - return a < b ? -1 : (a > b ? 1 : 0); + uint64_t a, b; + a = *(const uint64_t *) _a; + b = *(const uint64_t *) _b; + return a < b ? -1 : (a > b ? 1 : 0); } const struct hash_ops uint64_hash_ops = { - .hash = uint64_hash_func, - .compare = uint64_compare_func + .hash = uint64_hash_func, + .compare = uint64_compare_func }; #if SIZEOF_DEV_T != 8 -unsigned long devt_hash_func(const void *p, - const uint8_t hash_key[HASH_KEY_SIZE]) +unsigned long +devt_hash_func (const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) { - uint64_t u; - siphash24((uint8_t *) & u, p, sizeof(dev_t), hash_key); - return (unsigned long)u; + uint64_t u; + siphash24 ((uint8_t *) & u, p, sizeof (dev_t), hash_key); + return (unsigned long) u; } -int devt_compare_func(const void *_a, const void *_b) +int +devt_compare_func (const void *_a, const void *_b) { - dev_t a, b; - a = *(const dev_t *)_a; - b = *(const dev_t *)_b; - return a < b ? -1 : (a > b ? 1 : 0); + dev_t a, b; + a = *(const dev_t *) _a; + b = *(const dev_t *) _b; + return a < b ? -1 : (a > b ? 1 : 0); } const struct hash_ops devt_hash_ops = { - .hash = devt_hash_func, - .compare = devt_compare_func + .hash = devt_hash_func, + .compare = devt_compare_func }; #endif -static unsigned n_buckets(HashmapBase * h) +static unsigned +n_buckets (HashmapBase * h) { - return h->has_indirect ? h->indirect.n_buckets - : hashmap_type_info[h->type].n_direct_buckets; + return h->has_indirect ? h->indirect.n_buckets + : hashmap_type_info[h->type].n_direct_buckets; } -static unsigned n_entries(HashmapBase * h) +static unsigned +n_entries (HashmapBase * h) { - return h->has_indirect ? h->indirect.n_entries : h->n_direct_entries; + return h->has_indirect ? h->indirect.n_entries : h->n_direct_entries; } -static void n_entries_inc(HashmapBase * h) +static void +n_entries_inc (HashmapBase * h) { - if (h->has_indirect) - h->indirect.n_entries++; - else - h->n_direct_entries++; + if (h->has_indirect) + h->indirect.n_entries++; + else + h->n_direct_entries++; } -static void n_entries_dec(HashmapBase * h) +static void +n_entries_dec (HashmapBase * h) { - if (h->has_indirect) - h->indirect.n_entries--; - else - h->n_direct_entries--; + if (h->has_indirect) + h->indirect.n_entries--; + else + h->n_direct_entries--; } -static char *storage_ptr(HashmapBase * h) +static char * +storage_ptr (HashmapBase * h) { - return h->has_indirect ? h->indirect.storage : h->direct.storage; + return h->has_indirect ? h->indirect.storage : h->direct.storage; } -static uint8_t *hash_key(HashmapBase * h) +static uint8_t * +hash_key (HashmapBase * h) { - return h->has_indirect ? h->indirect.hash_key : shared_hash_key; + return h->has_indirect ? h->indirect.hash_key : shared_hash_key; } -static unsigned base_bucket_hash(HashmapBase * h, const void *p) +static unsigned +base_bucket_hash (HashmapBase * h, const void *p) { - return (unsigned)(h->hash_ops->hash(p, hash_key(h)) % n_buckets(h)); + return (unsigned) (h->hash_ops->hash (p, hash_key (h)) % n_buckets (h)); } #define bucket_hash(h, p) base_bucket_hash(HASHMAP_BASE(h), p) -static void get_hash_key(uint8_t hash_key[HASH_KEY_SIZE], bool reuse_is_ok) +static void +get_hash_key (uint8_t hash_key[HASH_KEY_SIZE], bool reuse_is_ok) { - static uint8_t current[HASH_KEY_SIZE]; - static bool current_initialized = false; + static uint8_t current[HASH_KEY_SIZE]; + static bool current_initialized = false; - /* Returns a hash function key to use. In order to keep things - * fast we will not generate a new key each time we allocate a - * new hash table. Instead, we'll just reuse the most recently - * generated one, except if we never generated one or when we - * are rehashing an entire hash table because we reached a - * fill level */ + /* Returns a hash function key to use. In order to keep things + * fast we will not generate a new key each time we allocate a + * new hash table. Instead, we'll just reuse the most recently + * generated one, except if we never generated one or when we + * are rehashing an entire hash table because we reached a + * fill level */ - if (!current_initialized || !reuse_is_ok) { - random_bytes(current, sizeof(current)); - current_initialized = true; - } + if (!current_initialized || !reuse_is_ok) + { + random_bytes (current, sizeof (current)); + current_initialized = true; + } - memcpy(hash_key, current, sizeof(current)); + memcpy (hash_key, current, sizeof (current)); } -static struct hashmap_base_entry *bucket_at(HashmapBase * h, unsigned idx) +static struct hashmap_base_entry * +bucket_at (HashmapBase * h, unsigned idx) { - return (struct hashmap_base_entry *) - (storage_ptr(h) + idx * hashmap_type_info[h->type].entry_size); + return (struct hashmap_base_entry *) + (storage_ptr (h) + idx * hashmap_type_info[h->type].entry_size); } -static struct plain_hashmap_entry *plain_bucket_at(Hashmap * h, unsigned idx) +static struct plain_hashmap_entry * +plain_bucket_at (Hashmap * h, unsigned idx) { - return (struct plain_hashmap_entry *)bucket_at(HASHMAP_BASE(h), idx); + return (struct plain_hashmap_entry *) bucket_at (HASHMAP_BASE (h), idx); } -static struct ordered_hashmap_entry *ordered_bucket_at(OrderedHashmap * h, - unsigned idx) +static struct ordered_hashmap_entry * +ordered_bucket_at (OrderedHashmap * h, unsigned idx) { - return (struct ordered_hashmap_entry *)bucket_at(HASHMAP_BASE(h), idx); + return (struct ordered_hashmap_entry *) bucket_at (HASHMAP_BASE (h), idx); } -static struct set_entry *set_bucket_at(Set * h, unsigned idx) +static struct set_entry * +set_bucket_at (Set * h, unsigned idx) { - return (struct set_entry *)bucket_at(HASHMAP_BASE(h), idx); + return (struct set_entry *) bucket_at (HASHMAP_BASE (h), idx); } -static struct ordered_hashmap_entry *bucket_at_swap(struct swap_entries *swap, - unsigned idx) +static struct ordered_hashmap_entry * +bucket_at_swap (struct swap_entries *swap, unsigned idx) { - return &swap->e[idx - _IDX_SWAP_BEGIN]; + return &swap->e[idx - _IDX_SWAP_BEGIN]; } /* Returns a pointer to the bucket at index idx. * Understands real indexes and swap indexes, hence "_virtual". */ -static struct hashmap_base_entry *bucket_at_virtual(HashmapBase * h, - struct swap_entries *swap, - unsigned idx) +static struct hashmap_base_entry * +bucket_at_virtual (HashmapBase * h, struct swap_entries *swap, unsigned idx) { - if (idx < _IDX_SWAP_BEGIN) - return bucket_at(h, idx); + if (idx < _IDX_SWAP_BEGIN) + return bucket_at (h, idx); - if (idx < _IDX_SWAP_END) - return &bucket_at_swap(swap, idx)->p.b; + if (idx < _IDX_SWAP_END) + return &bucket_at_swap (swap, idx)->p.b; - assert_not_reached("Invalid index"); - return NULL; + assert_not_reached ("Invalid index"); + return NULL; } -static dib_raw_t *dib_raw_ptr(HashmapBase * h) +static dib_raw_t * +dib_raw_ptr (HashmapBase * h) { - return (dib_raw_t *) - (storage_ptr(h) + - hashmap_type_info[h->type].entry_size * n_buckets(h)); + return (dib_raw_t *) + (storage_ptr (h) + hashmap_type_info[h->type].entry_size * n_buckets (h)); } -static unsigned bucket_distance(HashmapBase * h, unsigned idx, unsigned from) +static unsigned +bucket_distance (HashmapBase * h, unsigned idx, unsigned from) { - return idx >= from ? idx - from : n_buckets(h) + idx - from; + return idx >= from ? idx - from : n_buckets (h) + idx - from; } -static unsigned bucket_calculate_dib(HashmapBase * h, unsigned idx, - dib_raw_t raw_dib) +static unsigned +bucket_calculate_dib (HashmapBase * h, unsigned idx, dib_raw_t raw_dib) { - unsigned initial_bucket; + unsigned initial_bucket; - if (raw_dib == DIB_RAW_FREE) - return DIB_FREE; + if (raw_dib == DIB_RAW_FREE) + return DIB_FREE; - if (_likely_(raw_dib < DIB_RAW_OVERFLOW)) - return raw_dib; + if (_likely_ (raw_dib < DIB_RAW_OVERFLOW)) + return raw_dib; - /* - * Having an overflow DIB value is very unlikely. The hash function - * would have to be bad. For example, in a table of size 2^24 filled - * to load factor 0.9 the maximum observed DIB is only about 60. - * In theory (assuming I used Maxima correctly), for an infinite size - * hash table with load factor 0.8 the probability of a given entry - * having DIB > 40 is 1.9e-8. - * This returns the correct DIB value by recomputing the hash value in - * the unlikely case. XXX Hitting this case could be a hint to rehash. - */ - initial_bucket = bucket_hash(h, bucket_at(h, idx)->key); - return bucket_distance(h, idx, initial_bucket); + /* + * Having an overflow DIB value is very unlikely. The hash function + * would have to be bad. For example, in a table of size 2^24 filled + * to load factor 0.9 the maximum observed DIB is only about 60. + * In theory (assuming I used Maxima correctly), for an infinite size + * hash table with load factor 0.8 the probability of a given entry + * having DIB > 40 is 1.9e-8. + * This returns the correct DIB value by recomputing the hash value in + * the unlikely case. XXX Hitting this case could be a hint to rehash. + */ + initial_bucket = bucket_hash (h, bucket_at (h, idx)->key); + return bucket_distance (h, idx, initial_bucket); } -static void bucket_set_dib(HashmapBase * h, unsigned idx, unsigned dib) +static void +bucket_set_dib (HashmapBase * h, unsigned idx, unsigned dib) { - dib_raw_ptr(h)[idx] = - dib != DIB_FREE ? MIN(dib, DIB_RAW_OVERFLOW) : DIB_RAW_FREE; + dib_raw_ptr (h)[idx] = + dib != DIB_FREE ? MIN (dib, DIB_RAW_OVERFLOW) : DIB_RAW_FREE; } -static unsigned skip_free_buckets(HashmapBase * h, unsigned idx) +static unsigned +skip_free_buckets (HashmapBase * h, unsigned idx) { - dib_raw_t *dibs; + dib_raw_t *dibs; - dibs = dib_raw_ptr(h); + dibs = dib_raw_ptr (h); - for (; idx < n_buckets(h); idx++) - if (dibs[idx] != DIB_RAW_FREE) - return idx; + for (; idx < n_buckets (h); idx++) + if (dibs[idx] != DIB_RAW_FREE) + return idx; - return IDX_NIL; + return IDX_NIL; } -static void bucket_mark_free(HashmapBase * h, unsigned idx) +static void +bucket_mark_free (HashmapBase * h, unsigned idx) { - memzero(bucket_at(h, idx), hashmap_type_info[h->type].entry_size); - bucket_set_dib(h, idx, DIB_FREE); + memzero (bucket_at (h, idx), hashmap_type_info[h->type].entry_size); + bucket_set_dib (h, idx, DIB_FREE); } -static void bucket_move_entry(HashmapBase * h, struct swap_entries *swap, - unsigned from, unsigned to) +static void +bucket_move_entry (HashmapBase * h, struct swap_entries *swap, + unsigned from, unsigned to) { - struct hashmap_base_entry *e_from, *e_to; - - assert(from != to); + struct hashmap_base_entry *e_from, *e_to; - e_from = bucket_at_virtual(h, swap, from); - e_to = bucket_at_virtual(h, swap, to); + assert (from != to); - memcpy(e_to, e_from, hashmap_type_info[h->type].entry_size); + e_from = bucket_at_virtual (h, swap, from); + e_to = bucket_at_virtual (h, swap, to); - if (h->type == HASHMAP_TYPE_ORDERED) { - OrderedHashmap *lh = (OrderedHashmap *) h; - struct ordered_hashmap_entry *le, *le_to; + memcpy (e_to, e_from, hashmap_type_info[h->type].entry_size); - le_to = (struct ordered_hashmap_entry *)e_to; + if (h->type == HASHMAP_TYPE_ORDERED) + { + OrderedHashmap *lh = (OrderedHashmap *) h; + struct ordered_hashmap_entry *le, *le_to; - if (le_to->iterate_next != IDX_NIL) { - le = (struct ordered_hashmap_entry *) - bucket_at_virtual(h, swap, le_to->iterate_next); - le->iterate_previous = to; - } + le_to = (struct ordered_hashmap_entry *) e_to; - if (le_to->iterate_previous != IDX_NIL) { - le = (struct ordered_hashmap_entry *) - bucket_at_virtual(h, swap, le_to->iterate_previous); - le->iterate_next = to; - } + if (le_to->iterate_next != IDX_NIL) + { + le = (struct ordered_hashmap_entry *) + bucket_at_virtual (h, swap, le_to->iterate_next); + le->iterate_previous = to; + } - if (lh->iterate_list_head == from) - lh->iterate_list_head = to; - if (lh->iterate_list_tail == from) - lh->iterate_list_tail = to; + if (le_to->iterate_previous != IDX_NIL) + { + le = (struct ordered_hashmap_entry *) + bucket_at_virtual (h, swap, le_to->iterate_previous); + le->iterate_next = to; } + + if (lh->iterate_list_head == from) + lh->iterate_list_head = to; + if (lh->iterate_list_tail == from) + lh->iterate_list_tail = to; + } } -static unsigned next_idx(HashmapBase * h, unsigned idx) +static unsigned +next_idx (HashmapBase * h, unsigned idx) { - return (idx + 1U) % n_buckets(h); + return (idx + 1U) % n_buckets (h); } -static unsigned prev_idx(HashmapBase * h, unsigned idx) +static unsigned +prev_idx (HashmapBase * h, unsigned idx) { - return (n_buckets(h) + idx - 1U) % n_buckets(h); + return (n_buckets (h) + idx - 1U) % n_buckets (h); } -static void *entry_value(HashmapBase * h, struct hashmap_base_entry *e) +static void * +entry_value (HashmapBase * h, struct hashmap_base_entry *e) { - switch (h->type) { + switch (h->type) + { - case HASHMAP_TYPE_PLAIN: - case HASHMAP_TYPE_ORDERED: - return ((struct plain_hashmap_entry *)e)->value; + case HASHMAP_TYPE_PLAIN: + case HASHMAP_TYPE_ORDERED: + return ((struct plain_hashmap_entry *) e)->value; - case HASHMAP_TYPE_SET: - return (void *)e->key; + case HASHMAP_TYPE_SET: + return (void *) e->key; - default: - assert_not_reached("Unknown hashmap type"); - return NULL; - } + default: + assert_not_reached ("Unknown hashmap type"); + return NULL; + } } -static void base_remove_entry(HashmapBase * h, unsigned idx) +static void +base_remove_entry (HashmapBase * h, unsigned idx) { - unsigned left, right, prev, dib; - dib_raw_t raw_dib, *dibs; + unsigned left, right, prev, dib; + dib_raw_t raw_dib, *dibs; - dibs = dib_raw_ptr(h); - assert(dibs[idx] != DIB_RAW_FREE); + dibs = dib_raw_ptr (h); + assert (dibs[idx] != DIB_RAW_FREE); #ifdef ENABLE_DEBUG_HASHMAP - h->debug.rem_count++; - h->debug.last_rem_idx = idx; + h->debug.rem_count++; + h->debug.last_rem_idx = idx; #endif - left = idx; - /* Find the stop bucket ("right"). It is either free or has DIB == 0. */ - for (right = next_idx(h, left);; right = next_idx(h, right)) { - raw_dib = dibs[right]; - if (raw_dib == 0 || raw_dib == DIB_RAW_FREE) - break; - - /* The buckets are not supposed to be all occupied and with DIB > 0. - * That would mean we could make everyone better off by shifting them - * backward. This scenario is impossible. */ - assert(left != right); - } - - if (h->type == HASHMAP_TYPE_ORDERED) { - OrderedHashmap *lh = (OrderedHashmap *) h; - struct ordered_hashmap_entry *le = ordered_bucket_at(lh, idx); - - if (le->iterate_next != IDX_NIL) - ordered_bucket_at(lh, - le->iterate_next)->iterate_previous = - le->iterate_previous; - else - lh->iterate_list_tail = le->iterate_previous; - - if (le->iterate_previous != IDX_NIL) - ordered_bucket_at(lh, - le->iterate_previous)->iterate_next = - le->iterate_next; - else - lh->iterate_list_head = le->iterate_next; - } - - /* Now shift all buckets in the interval (left, right) one step backwards */ - for (prev = left, left = next_idx(h, left); left != right; - prev = left, left = next_idx(h, left)) { - dib = bucket_calculate_dib(h, left, dibs[left]); - assert(dib != 0); - bucket_move_entry(h, NULL, left, prev); - bucket_set_dib(h, prev, dib - 1); - } - - bucket_mark_free(h, prev); - n_entries_dec(h); + left = idx; + /* Find the stop bucket ("right"). It is either free or has DIB == 0. */ + for (right = next_idx (h, left);; right = next_idx (h, right)) + { + raw_dib = dibs[right]; + if (raw_dib == 0 || raw_dib == DIB_RAW_FREE) + break; + + /* The buckets are not supposed to be all occupied and with DIB > 0. + * That would mean we could make everyone better off by shifting them + * backward. This scenario is impossible. */ + assert (left != right); + } + + if (h->type == HASHMAP_TYPE_ORDERED) + { + OrderedHashmap *lh = (OrderedHashmap *) h; + struct ordered_hashmap_entry *le = ordered_bucket_at (lh, idx); + + if (le->iterate_next != IDX_NIL) + ordered_bucket_at (lh, + le->iterate_next)->iterate_previous = + le->iterate_previous; + else + lh->iterate_list_tail = le->iterate_previous; + + if (le->iterate_previous != IDX_NIL) + ordered_bucket_at (lh, + le->iterate_previous)->iterate_next = + le->iterate_next; + else + lh->iterate_list_head = le->iterate_next; + } + + /* Now shift all buckets in the interval (left, right) one step backwards */ + for (prev = left, left = next_idx (h, left); left != right; + prev = left, left = next_idx (h, left)) + { + dib = bucket_calculate_dib (h, left, dibs[left]); + assert (dib != 0); + bucket_move_entry (h, NULL, left, prev); + bucket_set_dib (h, prev, dib - 1); + } + + bucket_mark_free (h, prev); + n_entries_dec (h); } #define remove_entry(h, idx) base_remove_entry(HASHMAP_BASE(h), idx) -static unsigned hashmap_iterate_in_insertion_order(OrderedHashmap * h, - Iterator * i) -{ - struct ordered_hashmap_entry *e; - unsigned idx; - - assert(h); - assert(i); - - if (i->idx == IDX_NIL) - goto at_end; - - if (i->idx == IDX_FIRST && h->iterate_list_head == IDX_NIL) - goto at_end; - - if (i->idx == IDX_FIRST) { - idx = h->iterate_list_head; - e = ordered_bucket_at(h, idx); - } else { - idx = i->idx; - e = ordered_bucket_at(h, idx); - /* - * We allow removing the current entry while iterating, but removal may cause - * a backward shift. The next entry may thus move one bucket to the left. - * To detect when it happens, we remember the key pointer of the entry we were - * going to iterate next. If it does not match, there was a backward shift. - */ - if (e->p.b.key != i->next_key) { - idx = prev_idx(HASHMAP_BASE(h), idx); - e = ordered_bucket_at(h, idx); - } - assert(e->p.b.key == i->next_key); +static unsigned +hashmap_iterate_in_insertion_order (OrderedHashmap * h, Iterator * i) +{ + struct ordered_hashmap_entry *e; + unsigned idx; + + assert (h); + assert (i); + + if (i->idx == IDX_NIL) + goto at_end; + + if (i->idx == IDX_FIRST && h->iterate_list_head == IDX_NIL) + goto at_end; + + if (i->idx == IDX_FIRST) + { + idx = h->iterate_list_head; + e = ordered_bucket_at (h, idx); + } + else + { + idx = i->idx; + e = ordered_bucket_at (h, idx); + /* + * We allow removing the current entry while iterating, but removal may cause + * a backward shift. The next entry may thus move one bucket to the left. + * To detect when it happens, we remember the key pointer of the entry we were + * going to iterate next. If it does not match, there was a backward shift. + */ + if (e->p.b.key != i->next_key) + { + idx = prev_idx (HASHMAP_BASE (h), idx); + e = ordered_bucket_at (h, idx); } + assert (e->p.b.key == i->next_key); + } #ifdef ENABLE_DEBUG_HASHMAP - i->prev_idx = idx; + i->prev_idx = idx; #endif - if (e->iterate_next != IDX_NIL) { - struct ordered_hashmap_entry *n; - i->idx = e->iterate_next; - n = ordered_bucket_at(h, i->idx); - i->next_key = n->p.b.key; - } else - i->idx = IDX_NIL; + if (e->iterate_next != IDX_NIL) + { + struct ordered_hashmap_entry *n; + i->idx = e->iterate_next; + n = ordered_bucket_at (h, i->idx); + i->next_key = n->p.b.key; + } + else + i->idx = IDX_NIL; - return idx; + return idx; - at_end: - i->idx = IDX_NIL; - return IDX_NIL; +at_end: + i->idx = IDX_NIL; + return IDX_NIL; } -static unsigned hashmap_iterate_in_internal_order(HashmapBase * h, Iterator * i) +static unsigned +hashmap_iterate_in_internal_order (HashmapBase * h, Iterator * i) { - unsigned idx; - - assert(h); - assert(i); - - if (i->idx == IDX_NIL) - goto at_end; + unsigned idx; - if (i->idx == IDX_FIRST) { - /* fast forward to the first occupied bucket */ - if (h->has_indirect) { - i->idx = - skip_free_buckets(h, h->indirect.idx_lowest_entry); - h->indirect.idx_lowest_entry = i->idx; - } else - i->idx = skip_free_buckets(h, 0); + assert (h); + assert (i); - if (i->idx == IDX_NIL) - goto at_end; - } else { - struct hashmap_base_entry *e; + if (i->idx == IDX_NIL) + goto at_end; - assert(i->idx > 0); - - e = bucket_at(h, i->idx); - /* - * We allow removing the current entry while iterating, but removal may cause - * a backward shift. The next entry may thus move one bucket to the left. - * To detect when it happens, we remember the key pointer of the entry we were - * going to iterate next. If it does not match, there was a backward shift. - */ - if (e->key != i->next_key) - e = bucket_at(h, --i->idx); - - assert(e->key == i->next_key); + if (i->idx == IDX_FIRST) + { + /* fast forward to the first occupied bucket */ + if (h->has_indirect) + { + i->idx = skip_free_buckets (h, h->indirect.idx_lowest_entry); + h->indirect.idx_lowest_entry = i->idx; } - - idx = i->idx; + else + i->idx = skip_free_buckets (h, 0); + + if (i->idx == IDX_NIL) + goto at_end; + } + else + { + struct hashmap_base_entry *e; + + assert (i->idx > 0); + + e = bucket_at (h, i->idx); + /* + * We allow removing the current entry while iterating, but removal may cause + * a backward shift. The next entry may thus move one bucket to the left. + * To detect when it happens, we remember the key pointer of the entry we were + * going to iterate next. If it does not match, there was a backward shift. + */ + if (e->key != i->next_key) + e = bucket_at (h, --i->idx); + + assert (e->key == i->next_key); + } + + idx = i->idx; #ifdef ENABLE_DEBUG_HASHMAP - i->prev_idx = idx; + i->prev_idx = idx; #endif - i->idx = skip_free_buckets(h, i->idx + 1); - if (i->idx != IDX_NIL) - i->next_key = bucket_at(h, i->idx)->key; - else - i->idx = IDX_NIL; + i->idx = skip_free_buckets (h, i->idx + 1); + if (i->idx != IDX_NIL) + i->next_key = bucket_at (h, i->idx)->key; + else + i->idx = IDX_NIL; - return idx; + return idx; - at_end: - i->idx = IDX_NIL; - return IDX_NIL; +at_end: + i->idx = IDX_NIL; + return IDX_NIL; } -static unsigned hashmap_iterate_entry(HashmapBase * h, Iterator * i) +static unsigned +hashmap_iterate_entry (HashmapBase * h, Iterator * i) { - if (!h) { - i->idx = IDX_NIL; - return IDX_NIL; - } + if (!h) + { + i->idx = IDX_NIL; + return IDX_NIL; + } #ifdef ENABLE_DEBUG_HASHMAP - if (i->idx == IDX_FIRST) { - i->put_count = h->debug.put_count; - i->rem_count = h->debug.rem_count; - } else { - /* While iterating, must not add any new entries */ - assert(i->put_count == h->debug.put_count); - /* ... or remove entries other than the current one */ - assert(i->rem_count == h->debug.rem_count || - (i->rem_count == h->debug.rem_count - 1 && - i->prev_idx == h->debug.last_rem_idx)); - /* Reset our removals counter */ - i->rem_count = h->debug.rem_count; - } + if (i->idx == IDX_FIRST) + { + i->put_count = h->debug.put_count; + i->rem_count = h->debug.rem_count; + } + else + { + /* While iterating, must not add any new entries */ + assert (i->put_count == h->debug.put_count); + /* ... or remove entries other than the current one */ + assert (i->rem_count == h->debug.rem_count || + (i->rem_count == h->debug.rem_count - 1 && + i->prev_idx == h->debug.last_rem_idx)); + /* Reset our removals counter */ + i->rem_count = h->debug.rem_count; + } #endif - return h->type == - HASHMAP_TYPE_ORDERED ? - hashmap_iterate_in_insertion_order((OrderedHashmap *) h, i) - : hashmap_iterate_in_internal_order(h, i); + return h->type == + HASHMAP_TYPE_ORDERED ? + hashmap_iterate_in_insertion_order ((OrderedHashmap *) h, i) + : hashmap_iterate_in_internal_order (h, i); } -void *internal_hashmap_iterate(HashmapBase * h, Iterator * i, const void **key) +void * +internal_hashmap_iterate (HashmapBase * h, Iterator * i, const void **key) { - struct hashmap_base_entry *e; - void *data; - unsigned idx; + struct hashmap_base_entry *e; + void *data; + unsigned idx; - idx = hashmap_iterate_entry(h, i); - if (idx == IDX_NIL) { - if (key) - *key = NULL; + idx = hashmap_iterate_entry (h, i); + if (idx == IDX_NIL) + { + if (key) + *key = NULL; - return NULL; - } + return NULL; + } - e = bucket_at(h, idx); - data = entry_value(h, e); - if (key) - *key = e->key; + e = bucket_at (h, idx); + data = entry_value (h, e); + if (key) + *key = e->key; - return data; + return data; } -void *set_iterate(Set * s, Iterator * i) +void * +set_iterate (Set * s, Iterator * i) { - return internal_hashmap_iterate(HASHMAP_BASE(s), i, NULL); + return internal_hashmap_iterate (HASHMAP_BASE (s), i, NULL); } #define HASHMAP_FOREACH_IDX(idx, h, i) \ @@ -831,232 +894,247 @@ void *set_iterate(Set * s, Iterator * i) (idx != IDX_NIL); \ (idx) = hashmap_iterate_entry((h), &(i))) -static void reset_direct_storage(HashmapBase * h) +static void +reset_direct_storage (HashmapBase * h) { - const struct hashmap_type_info *hi = &hashmap_type_info[h->type]; - void *p; + const struct hashmap_type_info *hi = &hashmap_type_info[h->type]; + void *p; - assert(!h->has_indirect); + assert (!h->has_indirect); - p = mempset(h->direct.storage, 0, - hi->entry_size * hi->n_direct_buckets); - memset(p, DIB_RAW_INIT, sizeof(dib_raw_t) * hi->n_direct_buckets); + p = mempset (h->direct.storage, 0, hi->entry_size * hi->n_direct_buckets); + memset (p, DIB_RAW_INIT, sizeof (dib_raw_t) * hi->n_direct_buckets); } -static struct HashmapBase *hashmap_base_new(const struct hash_ops *hash_ops, - enum HashmapType type - HASHMAP_DEBUG_PARAMS) +static struct HashmapBase * +hashmap_base_new (const struct hash_ops *hash_ops, + enum HashmapType type HASHMAP_DEBUG_PARAMS) { - HashmapBase *h; - const struct hashmap_type_info *hi = &hashmap_type_info[type]; - bool use_pool; + HashmapBase *h; + const struct hashmap_type_info *hi = &hashmap_type_info[type]; + bool use_pool; - use_pool = is_main_thread(); + use_pool = is_main_thread (); - h = use_pool ? mempool_alloc0_tile(hi->mempool) : malloc0(hi-> - head_size); + h = use_pool ? mempool_alloc0_tile (hi->mempool) : malloc0 (hi->head_size); - if (!h) - return NULL; + if (!h) + return NULL; - h->type = type; - h->from_pool = use_pool; - h->hash_ops = hash_ops ? hash_ops : &trivial_hash_ops; + h->type = type; + h->from_pool = use_pool; + h->hash_ops = hash_ops ? hash_ops : &trivial_hash_ops; - if (type == HASHMAP_TYPE_ORDERED) { - OrderedHashmap *lh = (OrderedHashmap *) h; - lh->iterate_list_head = lh->iterate_list_tail = IDX_NIL; - } + if (type == HASHMAP_TYPE_ORDERED) + { + OrderedHashmap *lh = (OrderedHashmap *) h; + lh->iterate_list_head = lh->iterate_list_tail = IDX_NIL; + } - reset_direct_storage(h); + reset_direct_storage (h); - if (!shared_hash_key_initialized) { - random_bytes(shared_hash_key, sizeof(shared_hash_key)); - shared_hash_key_initialized = true; - } + if (!shared_hash_key_initialized) + { + random_bytes (shared_hash_key, sizeof (shared_hash_key)); + shared_hash_key_initialized = true; + } #ifdef ENABLE_DEBUG_HASHMAP - LIST_PREPEND(debug_list, hashmap_debug_list, &h->debug); - h->debug.func = func; - h->debug.file = file; - h->debug.line = line; + LIST_PREPEND (debug_list, hashmap_debug_list, &h->debug); + h->debug.func = func; + h->debug.file = file; + h->debug.line = line; #endif - return h; + return h; } -Hashmap *internal_hashmap_new(const struct hash_ops * - hash_ops HASHMAP_DEBUG_PARAMS) +Hashmap * +internal_hashmap_new (const struct hash_ops * hash_ops HASHMAP_DEBUG_PARAMS) { - return (Hashmap *) hashmap_base_new(hash_ops, - HASHMAP_TYPE_PLAIN - HASHMAP_DEBUG_PASS_ARGS); + return (Hashmap *) hashmap_base_new (hash_ops, + HASHMAP_TYPE_PLAIN + HASHMAP_DEBUG_PASS_ARGS); } -OrderedHashmap *internal_ordered_hashmap_new(const struct hash_ops * - hash_ops HASHMAP_DEBUG_PARAMS) +OrderedHashmap * +internal_ordered_hashmap_new (const struct hash_ops * + hash_ops HASHMAP_DEBUG_PARAMS) { - return (OrderedHashmap *) hashmap_base_new(hash_ops, - HASHMAP_TYPE_ORDERED - HASHMAP_DEBUG_PASS_ARGS); + return (OrderedHashmap *) hashmap_base_new (hash_ops, + HASHMAP_TYPE_ORDERED + HASHMAP_DEBUG_PASS_ARGS); } -Set *internal_set_new(const struct hash_ops * hash_ops HASHMAP_DEBUG_PARAMS) +Set * +internal_set_new (const struct hash_ops * hash_ops HASHMAP_DEBUG_PARAMS) { - return (Set *) hashmap_base_new(hash_ops, - HASHMAP_TYPE_SET - HASHMAP_DEBUG_PASS_ARGS); + return (Set *) hashmap_base_new (hash_ops, + HASHMAP_TYPE_SET HASHMAP_DEBUG_PASS_ARGS); } -static int hashmap_base_ensure_allocated(HashmapBase ** h, - const struct hash_ops *hash_ops, - enum HashmapType type - HASHMAP_DEBUG_PARAMS) +static int +hashmap_base_ensure_allocated (HashmapBase ** h, + const struct hash_ops *hash_ops, + enum HashmapType type HASHMAP_DEBUG_PARAMS) { - HashmapBase *q; + HashmapBase *q; - assert(h); + assert (h); - if (*h) - return 0; + if (*h) + return 0; - q = hashmap_base_new(hash_ops, type HASHMAP_DEBUG_PASS_ARGS); - if (!q) - return -ENOMEM; + q = hashmap_base_new (hash_ops, type HASHMAP_DEBUG_PASS_ARGS); + if (!q) + return -ENOMEM; - *h = q; - return 0; + *h = q; + return 0; } -int internal_hashmap_ensure_allocated(Hashmap ** h, - const struct hash_ops *hash_ops - HASHMAP_DEBUG_PARAMS) +int +internal_hashmap_ensure_allocated (Hashmap ** h, + const struct hash_ops *hash_ops + HASHMAP_DEBUG_PARAMS) { - return hashmap_base_ensure_allocated((HashmapBase **) h, hash_ops, - HASHMAP_TYPE_PLAIN - HASHMAP_DEBUG_PASS_ARGS); + return hashmap_base_ensure_allocated ((HashmapBase **) h, hash_ops, + HASHMAP_TYPE_PLAIN + HASHMAP_DEBUG_PASS_ARGS); } -int internal_ordered_hashmap_ensure_allocated(OrderedHashmap ** h, - const struct hash_ops *hash_ops - HASHMAP_DEBUG_PARAMS) +int +internal_ordered_hashmap_ensure_allocated (OrderedHashmap ** h, + const struct hash_ops *hash_ops + HASHMAP_DEBUG_PARAMS) { - return hashmap_base_ensure_allocated((HashmapBase **) h, hash_ops, - HASHMAP_TYPE_ORDERED - HASHMAP_DEBUG_PASS_ARGS); + return hashmap_base_ensure_allocated ((HashmapBase **) h, hash_ops, + HASHMAP_TYPE_ORDERED + HASHMAP_DEBUG_PASS_ARGS); } -int internal_set_ensure_allocated(Set ** s, - const struct hash_ops *hash_ops - HASHMAP_DEBUG_PARAMS) +int +internal_set_ensure_allocated (Set ** s, + const struct hash_ops *hash_ops + HASHMAP_DEBUG_PARAMS) { - return hashmap_base_ensure_allocated((HashmapBase **) s, hash_ops, - HASHMAP_TYPE_SET - HASHMAP_DEBUG_PASS_ARGS); + return hashmap_base_ensure_allocated ((HashmapBase **) s, hash_ops, + HASHMAP_TYPE_SET + HASHMAP_DEBUG_PASS_ARGS); } -static void hashmap_free_no_clear(HashmapBase * h) +static void +hashmap_free_no_clear (HashmapBase * h) { - assert(!h->has_indirect); - assert(!h->n_direct_entries); + assert (!h->has_indirect); + assert (!h->n_direct_entries); #ifdef ENABLE_DEBUG_HASHMAP - LIST_REMOVE(debug_list, hashmap_debug_list, &h->debug); + LIST_REMOVE (debug_list, hashmap_debug_list, &h->debug); #endif - if (h->from_pool) - mempool_free_tile(hashmap_type_info[h->type].mempool, h); - else - free(h); + if (h->from_pool) + mempool_free_tile (hashmap_type_info[h->type].mempool, h); + else + free (h); } -void internal_hashmap_free(HashmapBase * h) +void +internal_hashmap_free (HashmapBase * h) { - /* Free the hashmap, but nothing in it */ + /* Free the hashmap, but nothing in it */ - if (!h) - return; + if (!h) + return; - internal_hashmap_clear(h); - hashmap_free_no_clear(h); + internal_hashmap_clear (h); + hashmap_free_no_clear (h); } -void internal_hashmap_free_free(HashmapBase * h) +void +internal_hashmap_free_free (HashmapBase * h) { - /* Free the hashmap and all data objects in it, but not the - * keys */ + /* Free the hashmap and all data objects in it, but not the + * keys */ - if (!h) - return; + if (!h) + return; - internal_hashmap_clear_free(h); - hashmap_free_no_clear(h); + internal_hashmap_clear_free (h); + hashmap_free_no_clear (h); } -void hashmap_free_free_free(Hashmap * h) +void +hashmap_free_free_free (Hashmap * h) { - /* Free the hashmap and all data and key objects in it */ + /* Free the hashmap and all data and key objects in it */ - if (!h) - return; + if (!h) + return; - hashmap_clear_free_free(h); - hashmap_free_no_clear(HASHMAP_BASE(h)); + hashmap_clear_free_free (h); + hashmap_free_no_clear (HASHMAP_BASE (h)); } -void internal_hashmap_clear(HashmapBase * h) +void +internal_hashmap_clear (HashmapBase * h) { - if (!h) - return; + if (!h) + return; - if (h->has_indirect) { - free(h->indirect.storage); - h->has_indirect = false; - } + if (h->has_indirect) + { + free (h->indirect.storage); + h->has_indirect = false; + } - h->n_direct_entries = 0; - reset_direct_storage(h); + h->n_direct_entries = 0; + reset_direct_storage (h); - if (h->type == HASHMAP_TYPE_ORDERED) { - OrderedHashmap *lh = (OrderedHashmap *) h; - lh->iterate_list_head = lh->iterate_list_tail = IDX_NIL; - } + if (h->type == HASHMAP_TYPE_ORDERED) + { + OrderedHashmap *lh = (OrderedHashmap *) h; + lh->iterate_list_head = lh->iterate_list_tail = IDX_NIL; + } } -void internal_hashmap_clear_free(HashmapBase * h) +void +internal_hashmap_clear_free (HashmapBase * h) { - unsigned idx; + unsigned idx; - if (!h) - return; + if (!h) + return; - for (idx = skip_free_buckets(h, 0); idx != IDX_NIL; - idx = skip_free_buckets(h, idx + 1)) - free(entry_value(h, bucket_at(h, idx))); + for (idx = skip_free_buckets (h, 0); idx != IDX_NIL; + idx = skip_free_buckets (h, idx + 1)) + free (entry_value (h, bucket_at (h, idx))); - internal_hashmap_clear(h); + internal_hashmap_clear (h); } -void hashmap_clear_free_free(Hashmap * h) +void +hashmap_clear_free_free (Hashmap * h) { - unsigned idx; + unsigned idx; - if (!h) - return; + if (!h) + return; - for (idx = skip_free_buckets(HASHMAP_BASE(h), 0); idx != IDX_NIL; - idx = skip_free_buckets(HASHMAP_BASE(h), idx + 1)) { - struct plain_hashmap_entry *e = plain_bucket_at(h, idx); - free((void *)e->b.key); - free(e->value); - } + for (idx = skip_free_buckets (HASHMAP_BASE (h), 0); idx != IDX_NIL; + idx = skip_free_buckets (HASHMAP_BASE (h), idx + 1)) + { + struct plain_hashmap_entry *e = plain_bucket_at (h, idx); + free ((void *) e->b.key); + free (e->value); + } - internal_hashmap_clear(HASHMAP_BASE(h)); + internal_hashmap_clear (HASHMAP_BASE (h)); } -static int resize_buckets(HashmapBase * h, unsigned entries_add); +static int resize_buckets (HashmapBase * h, unsigned entries_add); /* * Finds an empty bucket to put an entry into, starting the scan at 'idx'. @@ -1067,55 +1145,59 @@ static int resize_buckets(HashmapBase * h, unsigned entries_add); * Returns: true if it left a displaced entry to rehash next in IDX_PUT, * false otherwise. */ -static bool hashmap_put_robin_hood(HashmapBase * h, unsigned idx, - struct swap_entries *swap) +static bool +hashmap_put_robin_hood (HashmapBase * h, unsigned idx, + struct swap_entries *swap) { - dib_raw_t raw_dib, *dibs; - unsigned dib, distance; + dib_raw_t raw_dib, *dibs; + unsigned dib, distance; #ifdef ENABLE_DEBUG_HASHMAP - h->debug.put_count++; + h->debug.put_count++; #endif - dibs = dib_raw_ptr(h); + dibs = dib_raw_ptr (h); - for (distance = 0;; distance++) { - raw_dib = dibs[idx]; - if (raw_dib == DIB_RAW_FREE || raw_dib == DIB_RAW_REHASH) { - if (raw_dib == DIB_RAW_REHASH) - bucket_move_entry(h, swap, idx, IDX_TMP); + for (distance = 0;; distance++) + { + raw_dib = dibs[idx]; + if (raw_dib == DIB_RAW_FREE || raw_dib == DIB_RAW_REHASH) + { + if (raw_dib == DIB_RAW_REHASH) + bucket_move_entry (h, swap, idx, IDX_TMP); - if (h->has_indirect - && h->indirect.idx_lowest_entry > idx) - h->indirect.idx_lowest_entry = idx; + if (h->has_indirect && h->indirect.idx_lowest_entry > idx) + h->indirect.idx_lowest_entry = idx; - bucket_set_dib(h, idx, distance); - bucket_move_entry(h, swap, IDX_PUT, idx); - if (raw_dib == DIB_RAW_REHASH) { - bucket_move_entry(h, swap, IDX_TMP, IDX_PUT); - return true; - } + bucket_set_dib (h, idx, distance); + bucket_move_entry (h, swap, IDX_PUT, idx); + if (raw_dib == DIB_RAW_REHASH) + { + bucket_move_entry (h, swap, IDX_TMP, IDX_PUT); + return true; + } - return false; - } - - dib = bucket_calculate_dib(h, idx, raw_dib); + return false; + } - if (dib < distance) { - /* Found a wealthier entry. Go Robin Hood! */ + dib = bucket_calculate_dib (h, idx, raw_dib); - bucket_set_dib(h, idx, distance); + if (dib < distance) + { + /* Found a wealthier entry. Go Robin Hood! */ - /* swap the entries */ - bucket_move_entry(h, swap, idx, IDX_TMP); - bucket_move_entry(h, swap, IDX_PUT, idx); - bucket_move_entry(h, swap, IDX_TMP, IDX_PUT); + bucket_set_dib (h, idx, distance); - distance = dib; - } + /* swap the entries */ + bucket_move_entry (h, swap, idx, IDX_TMP); + bucket_move_entry (h, swap, IDX_PUT, idx); + bucket_move_entry (h, swap, IDX_TMP, IDX_PUT); - idx = next_idx(h, idx); + distance = dib; } + + idx = next_idx (h, idx); + } } /* @@ -1128,52 +1210,56 @@ static bool hashmap_put_robin_hood(HashmapBase * h, unsigned idx, * -ENOMEM if may_resize==true and resize failed with -ENOMEM. * Cannot return -ENOMEM if !may_resize. */ -static int hashmap_base_put_boldly(HashmapBase * h, unsigned idx, - struct swap_entries *swap, bool may_resize) +static int +hashmap_base_put_boldly (HashmapBase * h, unsigned idx, + struct swap_entries *swap, bool may_resize) { - struct ordered_hashmap_entry *new_entry; - int r; + struct ordered_hashmap_entry *new_entry; + int r; - assert(idx < n_buckets(h)); + assert (idx < n_buckets (h)); - new_entry = bucket_at_swap(swap, IDX_PUT); + new_entry = bucket_at_swap (swap, IDX_PUT); - if (may_resize) { - r = resize_buckets(h, 1); - if (r < 0) - return r; - if (r > 0) - idx = bucket_hash(h, new_entry->p.b.key); - } - assert(n_entries(h) < n_buckets(h)); - - if (h->type == HASHMAP_TYPE_ORDERED) { - OrderedHashmap *lh = (OrderedHashmap *) h; + if (may_resize) + { + r = resize_buckets (h, 1); + if (r < 0) + return r; + if (r > 0) + idx = bucket_hash (h, new_entry->p.b.key); + } + assert (n_entries (h) < n_buckets (h)); - new_entry->iterate_next = IDX_NIL; - new_entry->iterate_previous = lh->iterate_list_tail; + if (h->type == HASHMAP_TYPE_ORDERED) + { + OrderedHashmap *lh = (OrderedHashmap *) h; - if (lh->iterate_list_tail != IDX_NIL) { - struct ordered_hashmap_entry *old_tail; + new_entry->iterate_next = IDX_NIL; + new_entry->iterate_previous = lh->iterate_list_tail; - old_tail = ordered_bucket_at(lh, lh->iterate_list_tail); - assert(old_tail->iterate_next == IDX_NIL); - old_tail->iterate_next = IDX_PUT; - } + if (lh->iterate_list_tail != IDX_NIL) + { + struct ordered_hashmap_entry *old_tail; - lh->iterate_list_tail = IDX_PUT; - if (lh->iterate_list_head == IDX_NIL) - lh->iterate_list_head = IDX_PUT; + old_tail = ordered_bucket_at (lh, lh->iterate_list_tail); + assert (old_tail->iterate_next == IDX_NIL); + old_tail->iterate_next = IDX_PUT; } - assert_se(hashmap_put_robin_hood(h, idx, swap) == false); + lh->iterate_list_tail = IDX_PUT; + if (lh->iterate_list_head == IDX_NIL) + lh->iterate_list_head = IDX_PUT; + } - n_entries_inc(h); + assert_se (hashmap_put_robin_hood (h, idx, swap) == false); + + n_entries_inc (h); #ifdef ENABLE_DEBUG_HASHMAP - h->debug.max_entries = MAX(h->debug.max_entries, n_entries(h)); + h->debug.max_entries = MAX (h->debug.max_entries, n_entries (h)); #endif - return 1; + return 1; } #define hashmap_put_boldly(h, idx, swap, may_resize) \ @@ -1184,623 +1270,659 @@ static int hashmap_base_put_boldly(HashmapBase * h, unsigned idx, * 1 if successfully resized. * -ENOMEM on allocation failure. */ -static int resize_buckets(HashmapBase * h, unsigned entries_add) -{ - struct swap_entries swap; - char *new_storage; - dib_raw_t *old_dibs, *new_dibs; - const struct hashmap_type_info *hi; - unsigned idx, optimal_idx; - unsigned old_n_buckets, new_n_buckets, n_rehashed, new_n_entries; - uint8_t new_shift; - bool rehash_next; - - assert(h); - - hi = &hashmap_type_info[h->type]; - new_n_entries = n_entries(h) + entries_add; - - /* overflow? */ - if (_unlikely_(new_n_entries < entries_add)) - return -ENOMEM; - - /* For direct storage we allow 100% load, because it's tiny. */ - if (!h->has_indirect && new_n_entries <= hi->n_direct_buckets) - return 0; - - /* - * Load factor = n/m = 1 - (1/INV_KEEP_FREE). - * From it follows: m = n + n/(INV_KEEP_FREE - 1) - */ - new_n_buckets = new_n_entries + new_n_entries / (INV_KEEP_FREE - 1); - /* overflow? */ - if (_unlikely_(new_n_buckets < new_n_entries)) - return -ENOMEM; - - if (_unlikely_ - (new_n_buckets > UINT_MAX / (hi->entry_size + sizeof(dib_raw_t)))) - return -ENOMEM; - - old_n_buckets = n_buckets(h); - - if (_likely_(new_n_buckets <= old_n_buckets)) - return 0; - - new_shift = - log2u_round_up(MAX - (new_n_buckets * - (hi->entry_size + sizeof(dib_raw_t)), - 2 * sizeof(struct direct_storage))); - - /* Realloc storage (buckets and DIB array). */ - new_storage = realloc(h->has_indirect ? h->indirect.storage : NULL, - 1U << new_shift); - if (!new_storage) - return -ENOMEM; - - /* Must upgrade direct to indirect storage. */ - if (!h->has_indirect) { - memcpy(new_storage, h->direct.storage, - old_n_buckets * (hi->entry_size + sizeof(dib_raw_t))); - h->indirect.n_entries = h->n_direct_entries; - h->indirect.idx_lowest_entry = 0; - h->n_direct_entries = 0; - } - - /* Get a new hash key. If we've just upgraded to indirect storage, - * allow reusing a previously generated key. It's still a different key - * from the shared one that we used for direct storage. */ - get_hash_key(h->indirect.hash_key, !h->has_indirect); - - h->has_indirect = true; - h->indirect.storage = new_storage; - h->indirect.n_buckets = (1U << new_shift) / - (hi->entry_size + sizeof(dib_raw_t)); - - old_dibs = (dib_raw_t *) (new_storage + hi->entry_size * old_n_buckets); - new_dibs = dib_raw_ptr(h); - - /* - * Move the DIB array to the new place, replacing valid DIB values with - * DIB_RAW_REHASH to indicate all of the used buckets need rehashing. - * Note: Overlap is not possible, because we have at least doubled the - * number of buckets and dib_raw_t is smaller than any entry type. - */ - for (idx = 0; idx < old_n_buckets; idx++) { - assert(old_dibs[idx] != DIB_RAW_REHASH); - new_dibs[idx] = old_dibs[idx] == DIB_RAW_FREE ? DIB_RAW_FREE - : DIB_RAW_REHASH; +static int +resize_buckets (HashmapBase * h, unsigned entries_add) +{ + struct swap_entries swap; + char *new_storage; + dib_raw_t *old_dibs, *new_dibs; + const struct hashmap_type_info *hi; + unsigned idx, optimal_idx; + unsigned old_n_buckets, new_n_buckets, n_rehashed, new_n_entries; + uint8_t new_shift; + bool rehash_next; + + assert (h); + + hi = &hashmap_type_info[h->type]; + new_n_entries = n_entries (h) + entries_add; + + /* overflow? */ + if (_unlikely_ (new_n_entries < entries_add)) + return -ENOMEM; + + /* For direct storage we allow 100% load, because it's tiny. */ + if (!h->has_indirect && new_n_entries <= hi->n_direct_buckets) + return 0; + + /* + * Load factor = n/m = 1 - (1/INV_KEEP_FREE). + * From it follows: m = n + n/(INV_KEEP_FREE - 1) + */ + new_n_buckets = new_n_entries + new_n_entries / (INV_KEEP_FREE - 1); + /* overflow? */ + if (_unlikely_ (new_n_buckets < new_n_entries)) + return -ENOMEM; + + if (_unlikely_ + (new_n_buckets > UINT_MAX / (hi->entry_size + sizeof (dib_raw_t)))) + return -ENOMEM; + + old_n_buckets = n_buckets (h); + + if (_likely_ (new_n_buckets <= old_n_buckets)) + return 0; + + new_shift = + log2u_round_up (MAX + (new_n_buckets * + (hi->entry_size + sizeof (dib_raw_t)), + 2 * sizeof (struct direct_storage))); + + /* Realloc storage (buckets and DIB array). */ + new_storage = realloc (h->has_indirect ? h->indirect.storage : NULL, + 1U << new_shift); + if (!new_storage) + return -ENOMEM; + + /* Must upgrade direct to indirect storage. */ + if (!h->has_indirect) + { + memcpy (new_storage, h->direct.storage, + old_n_buckets * (hi->entry_size + sizeof (dib_raw_t))); + h->indirect.n_entries = h->n_direct_entries; + h->indirect.idx_lowest_entry = 0; + h->n_direct_entries = 0; + } + + /* Get a new hash key. If we've just upgraded to indirect storage, + * allow reusing a previously generated key. It's still a different key + * from the shared one that we used for direct storage. */ + get_hash_key (h->indirect.hash_key, !h->has_indirect); + + h->has_indirect = true; + h->indirect.storage = new_storage; + h->indirect.n_buckets = (1U << new_shift) / + (hi->entry_size + sizeof (dib_raw_t)); + + old_dibs = (dib_raw_t *) (new_storage + hi->entry_size * old_n_buckets); + new_dibs = dib_raw_ptr (h); + + /* + * Move the DIB array to the new place, replacing valid DIB values with + * DIB_RAW_REHASH to indicate all of the used buckets need rehashing. + * Note: Overlap is not possible, because we have at least doubled the + * number of buckets and dib_raw_t is smaller than any entry type. + */ + for (idx = 0; idx < old_n_buckets; idx++) + { + assert (old_dibs[idx] != DIB_RAW_REHASH); + new_dibs[idx] = old_dibs[idx] == DIB_RAW_FREE ? DIB_RAW_FREE + : DIB_RAW_REHASH; + } + + /* Zero the area of newly added entries (including the old DIB area) */ + memzero (bucket_at (h, old_n_buckets), + (n_buckets (h) - old_n_buckets) * hi->entry_size); + + /* The upper half of the new DIB array needs initialization */ + memset (&new_dibs[old_n_buckets], DIB_RAW_INIT, + (n_buckets (h) - old_n_buckets) * sizeof (dib_raw_t)); + + /* Rehash entries that need it */ + n_rehashed = 0; + for (idx = 0; idx < old_n_buckets; idx++) + { + if (new_dibs[idx] != DIB_RAW_REHASH) + continue; + + optimal_idx = bucket_hash (h, bucket_at (h, idx)->key); + + /* + * Not much to do if by luck the entry hashes to its current + * location. Just set its DIB. + */ + if (optimal_idx == idx) + { + new_dibs[idx] = 0; + n_rehashed++; + continue; } - /* Zero the area of newly added entries (including the old DIB area) */ - memzero(bucket_at(h, old_n_buckets), - (n_buckets(h) - old_n_buckets) * hi->entry_size); - - /* The upper half of the new DIB array needs initialization */ - memset(&new_dibs[old_n_buckets], DIB_RAW_INIT, - (n_buckets(h) - old_n_buckets) * sizeof(dib_raw_t)); - - /* Rehash entries that need it */ - n_rehashed = 0; - for (idx = 0; idx < old_n_buckets; idx++) { - if (new_dibs[idx] != DIB_RAW_REHASH) - continue; - - optimal_idx = bucket_hash(h, bucket_at(h, idx)->key); - - /* - * Not much to do if by luck the entry hashes to its current - * location. Just set its DIB. - */ - if (optimal_idx == idx) { - new_dibs[idx] = 0; - n_rehashed++; - continue; - } - - new_dibs[idx] = DIB_RAW_FREE; - bucket_move_entry(h, &swap, idx, IDX_PUT); - /* bucket_move_entry does not clear the source */ - memzero(bucket_at(h, idx), hi->entry_size); - - do { - /* - * Find the new bucket for the current entry. This may make - * another entry homeless and load it into IDX_PUT. - */ - rehash_next = - hashmap_put_robin_hood(h, optimal_idx, &swap); - n_rehashed++; - - /* Did the current entry displace another one? */ - if (rehash_next) - optimal_idx = - bucket_hash(h, - bucket_at_swap(&swap, - IDX_PUT)->p.b. - key); - } while (rehash_next); + new_dibs[idx] = DIB_RAW_FREE; + bucket_move_entry (h, &swap, idx, IDX_PUT); + /* bucket_move_entry does not clear the source */ + memzero (bucket_at (h, idx), hi->entry_size); + + do + { + /* + * Find the new bucket for the current entry. This may make + * another entry homeless and load it into IDX_PUT. + */ + rehash_next = hashmap_put_robin_hood (h, optimal_idx, &swap); + n_rehashed++; + + /* Did the current entry displace another one? */ + if (rehash_next) + optimal_idx = + bucket_hash (h, bucket_at_swap (&swap, IDX_PUT)->p.b.key); } + while (rehash_next); + } - assert(n_rehashed == n_entries(h)); + assert (n_rehashed == n_entries (h)); - return 1; + return 1; } /* * Finds an entry with a matching key * Returns: index of the found entry, or IDX_NIL if not found. */ -static unsigned base_bucket_scan(HashmapBase * h, unsigned idx, const void *key) +static unsigned +base_bucket_scan (HashmapBase * h, unsigned idx, const void *key) { - struct hashmap_base_entry *e; - unsigned dib, distance; - dib_raw_t *dibs = dib_raw_ptr(h); + struct hashmap_base_entry *e; + unsigned dib, distance; + dib_raw_t *dibs = dib_raw_ptr (h); - assert(idx < n_buckets(h)); + assert (idx < n_buckets (h)); - for (distance = 0;; distance++) { - if (dibs[idx] == DIB_RAW_FREE) - return IDX_NIL; - - dib = bucket_calculate_dib(h, idx, dibs[idx]); + for (distance = 0;; distance++) + { + if (dibs[idx] == DIB_RAW_FREE) + return IDX_NIL; - if (dib < distance) - return IDX_NIL; - if (dib == distance) { - e = bucket_at(h, idx); - if (h->hash_ops->compare(e->key, key) == 0) - return idx; - } + dib = bucket_calculate_dib (h, idx, dibs[idx]); - idx = next_idx(h, idx); + if (dib < distance) + return IDX_NIL; + if (dib == distance) + { + e = bucket_at (h, idx); + if (h->hash_ops->compare (e->key, key) == 0) + return idx; } + + idx = next_idx (h, idx); + } } #define bucket_scan(h, idx, key) base_bucket_scan(HASHMAP_BASE(h), idx, key) -int hashmap_put(Hashmap * h, const void *key, void *value) +int +hashmap_put (Hashmap * h, const void *key, void *value) { - struct swap_entries swap; - struct plain_hashmap_entry *e; - unsigned hash, idx; + struct swap_entries swap; + struct plain_hashmap_entry *e; + unsigned hash, idx; - assert(h); + assert (h); - hash = bucket_hash(h, key); - idx = bucket_scan(h, hash, key); - if (idx != IDX_NIL) { - e = plain_bucket_at(h, idx); - if (e->value == value) - return 0; - return -EEXIST; - } + hash = bucket_hash (h, key); + idx = bucket_scan (h, hash, key); + if (idx != IDX_NIL) + { + e = plain_bucket_at (h, idx); + if (e->value == value) + return 0; + return -EEXIST; + } - e = &bucket_at_swap(&swap, IDX_PUT)->p; - e->b.key = key; - e->value = value; - return hashmap_put_boldly(h, hash, &swap, true); + e = &bucket_at_swap (&swap, IDX_PUT)->p; + e->b.key = key; + e->value = value; + return hashmap_put_boldly (h, hash, &swap, true); } -int set_put(Set * s, const void *key) +int +set_put (Set * s, const void *key) { - struct swap_entries swap; - struct hashmap_base_entry *e; - unsigned hash, idx; + struct swap_entries swap; + struct hashmap_base_entry *e; + unsigned hash, idx; - assert(s); + assert (s); - hash = bucket_hash(s, key); - idx = bucket_scan(s, hash, key); - if (idx != IDX_NIL) - return 0; + hash = bucket_hash (s, key); + idx = bucket_scan (s, hash, key); + if (idx != IDX_NIL) + return 0; - e = &bucket_at_swap(&swap, IDX_PUT)->p.b; - e->key = key; - return hashmap_put_boldly(s, hash, &swap, true); + e = &bucket_at_swap (&swap, IDX_PUT)->p.b; + e->key = key; + return hashmap_put_boldly (s, hash, &swap, true); } -int hashmap_replace(Hashmap * h, const void *key, void *value) +int +hashmap_replace (Hashmap * h, const void *key, void *value) { - struct swap_entries swap; - struct plain_hashmap_entry *e; - unsigned hash, idx; + struct swap_entries swap; + struct plain_hashmap_entry *e; + unsigned hash, idx; - assert(h); + assert (h); - hash = bucket_hash(h, key); - idx = bucket_scan(h, hash, key); - if (idx != IDX_NIL) { - e = plain_bucket_at(h, idx); + hash = bucket_hash (h, key); + idx = bucket_scan (h, hash, key); + if (idx != IDX_NIL) + { + e = plain_bucket_at (h, idx); #ifdef ENABLE_DEBUG_HASHMAP - /* Although the key is equal, the key pointer may have changed, - * and this would break our assumption for iterating. So count - * this operation as incompatible with iteration. */ - if (e->b.key != key) { - h->b.debug.put_count++; - h->b.debug.rem_count++; - h->b.debug.last_rem_idx = idx; - } -#endif - e->b.key = key; - e->value = value; - return 0; + /* Although the key is equal, the key pointer may have changed, + * and this would break our assumption for iterating. So count + * this operation as incompatible with iteration. */ + if (e->b.key != key) + { + h->b.debug.put_count++; + h->b.debug.rem_count++; + h->b.debug.last_rem_idx = idx; } +#endif + e->b.key = key; + e->value = value; + return 0; + } - e = &bucket_at_swap(&swap, IDX_PUT)->p; - e->b.key = key; - e->value = value; - return hashmap_put_boldly(h, hash, &swap, true); + e = &bucket_at_swap (&swap, IDX_PUT)->p; + e->b.key = key; + e->value = value; + return hashmap_put_boldly (h, hash, &swap, true); } -int hashmap_update(Hashmap * h, const void *key, void *value) +int +hashmap_update (Hashmap * h, const void *key, void *value) { - struct plain_hashmap_entry *e; - unsigned hash, idx; + struct plain_hashmap_entry *e; + unsigned hash, idx; - assert(h); + assert (h); - hash = bucket_hash(h, key); - idx = bucket_scan(h, hash, key); - if (idx == IDX_NIL) - return -ENOENT; + hash = bucket_hash (h, key); + idx = bucket_scan (h, hash, key); + if (idx == IDX_NIL) + return -ENOENT; - e = plain_bucket_at(h, idx); - e->value = value; - return 0; + e = plain_bucket_at (h, idx); + e->value = value; + return 0; } -void *internal_hashmap_get(HashmapBase * h, const void *key) +void * +internal_hashmap_get (HashmapBase * h, const void *key) { - struct hashmap_base_entry *e; - unsigned hash, idx; + struct hashmap_base_entry *e; + unsigned hash, idx; - if (!h) - return NULL; + if (!h) + return NULL; - hash = bucket_hash(h, key); - idx = bucket_scan(h, hash, key); - if (idx == IDX_NIL) - return NULL; + hash = bucket_hash (h, key); + idx = bucket_scan (h, hash, key); + if (idx == IDX_NIL) + return NULL; - e = bucket_at(h, idx); - return entry_value(h, e); + e = bucket_at (h, idx); + return entry_value (h, e); } -void *hashmap_get2(Hashmap * h, const void *key, void **key2) +void * +hashmap_get2 (Hashmap * h, const void *key, void **key2) { - struct plain_hashmap_entry *e; - unsigned hash, idx; + struct plain_hashmap_entry *e; + unsigned hash, idx; - if (!h) - return NULL; + if (!h) + return NULL; - hash = bucket_hash(h, key); - idx = bucket_scan(h, hash, key); - if (idx == IDX_NIL) - return NULL; + hash = bucket_hash (h, key); + idx = bucket_scan (h, hash, key); + if (idx == IDX_NIL) + return NULL; - e = plain_bucket_at(h, idx); - if (key2) - *key2 = (void *)e->b.key; + e = plain_bucket_at (h, idx); + if (key2) + *key2 = (void *) e->b.key; - return e->value; + return e->value; } -bool internal_hashmap_contains(HashmapBase * h, const void *key) +bool +internal_hashmap_contains (HashmapBase * h, const void *key) { - unsigned hash; + unsigned hash; - if (!h) - return false; + if (!h) + return false; - hash = bucket_hash(h, key); - return bucket_scan(h, hash, key) != IDX_NIL; + hash = bucket_hash (h, key); + return bucket_scan (h, hash, key) != IDX_NIL; } -void *internal_hashmap_remove(HashmapBase * h, const void *key) +void * +internal_hashmap_remove (HashmapBase * h, const void *key) { - struct hashmap_base_entry *e; - unsigned hash, idx; - void *data; + struct hashmap_base_entry *e; + unsigned hash, idx; + void *data; - if (!h) - return NULL; + if (!h) + return NULL; - hash = bucket_hash(h, key); - idx = bucket_scan(h, hash, key); - if (idx == IDX_NIL) - return NULL; + hash = bucket_hash (h, key); + idx = bucket_scan (h, hash, key); + if (idx == IDX_NIL) + return NULL; - e = bucket_at(h, idx); - data = entry_value(h, e); - remove_entry(h, idx); + e = bucket_at (h, idx); + data = entry_value (h, e); + remove_entry (h, idx); - return data; + return data; } -void *hashmap_remove2(Hashmap * h, const void *key, void **rkey) +void * +hashmap_remove2 (Hashmap * h, const void *key, void **rkey) { - struct plain_hashmap_entry *e; - unsigned hash, idx; - void *data; + struct plain_hashmap_entry *e; + unsigned hash, idx; + void *data; - if (!h) { - if (rkey) - *rkey = NULL; - return NULL; - } + if (!h) + { + if (rkey) + *rkey = NULL; + return NULL; + } - hash = bucket_hash(h, key); - idx = bucket_scan(h, hash, key); - if (idx == IDX_NIL) { - if (rkey) - *rkey = NULL; - return NULL; - } + hash = bucket_hash (h, key); + idx = bucket_scan (h, hash, key); + if (idx == IDX_NIL) + { + if (rkey) + *rkey = NULL; + return NULL; + } - e = plain_bucket_at(h, idx); - data = e->value; - if (rkey) - *rkey = (void *)e->b.key; + e = plain_bucket_at (h, idx); + data = e->value; + if (rkey) + *rkey = (void *) e->b.key; - remove_entry(h, idx); + remove_entry (h, idx); - return data; + return data; } -int hashmap_remove_and_put(Hashmap * h, const void *old_key, - const void *new_key, void *value) +int +hashmap_remove_and_put (Hashmap * h, const void *old_key, + const void *new_key, void *value) { - struct swap_entries swap; - struct plain_hashmap_entry *e; - unsigned old_hash, new_hash, idx; + struct swap_entries swap; + struct plain_hashmap_entry *e; + unsigned old_hash, new_hash, idx; - if (!h) - return -ENOENT; + if (!h) + return -ENOENT; - old_hash = bucket_hash(h, old_key); - idx = bucket_scan(h, old_hash, old_key); - if (idx == IDX_NIL) - return -ENOENT; + old_hash = bucket_hash (h, old_key); + idx = bucket_scan (h, old_hash, old_key); + if (idx == IDX_NIL) + return -ENOENT; - new_hash = bucket_hash(h, new_key); - if (bucket_scan(h, new_hash, new_key) != IDX_NIL) - return -EEXIST; + new_hash = bucket_hash (h, new_key); + if (bucket_scan (h, new_hash, new_key) != IDX_NIL) + return -EEXIST; - remove_entry(h, idx); + remove_entry (h, idx); - e = &bucket_at_swap(&swap, IDX_PUT)->p; - e->b.key = new_key; - e->value = value; - assert_se(hashmap_put_boldly(h, new_hash, &swap, false) == 1); + e = &bucket_at_swap (&swap, IDX_PUT)->p; + e->b.key = new_key; + e->value = value; + assert_se (hashmap_put_boldly (h, new_hash, &swap, false) == 1); - return 0; + return 0; } -int set_remove_and_put(Set * s, const void *old_key, const void *new_key) +int +set_remove_and_put (Set * s, const void *old_key, const void *new_key) { - struct swap_entries swap; - struct hashmap_base_entry *e; - unsigned old_hash, new_hash, idx; + struct swap_entries swap; + struct hashmap_base_entry *e; + unsigned old_hash, new_hash, idx; - if (!s) - return -ENOENT; + if (!s) + return -ENOENT; - old_hash = bucket_hash(s, old_key); - idx = bucket_scan(s, old_hash, old_key); - if (idx == IDX_NIL) - return -ENOENT; + old_hash = bucket_hash (s, old_key); + idx = bucket_scan (s, old_hash, old_key); + if (idx == IDX_NIL) + return -ENOENT; - new_hash = bucket_hash(s, new_key); - if (bucket_scan(s, new_hash, new_key) != IDX_NIL) - return -EEXIST; + new_hash = bucket_hash (s, new_key); + if (bucket_scan (s, new_hash, new_key) != IDX_NIL) + return -EEXIST; - remove_entry(s, idx); + remove_entry (s, idx); - e = &bucket_at_swap(&swap, IDX_PUT)->p.b; - e->key = new_key; - assert_se(hashmap_put_boldly(s, new_hash, &swap, false) == 1); + e = &bucket_at_swap (&swap, IDX_PUT)->p.b; + e->key = new_key; + assert_se (hashmap_put_boldly (s, new_hash, &swap, false) == 1); - return 0; + return 0; } -int hashmap_remove_and_replace(Hashmap * h, const void *old_key, - const void *new_key, void *value) +int +hashmap_remove_and_replace (Hashmap * h, const void *old_key, + const void *new_key, void *value) { - struct swap_entries swap; - struct plain_hashmap_entry *e; - unsigned old_hash, new_hash, idx_old, idx_new; + struct swap_entries swap; + struct plain_hashmap_entry *e; + unsigned old_hash, new_hash, idx_old, idx_new; - if (!h) - return -ENOENT; + if (!h) + return -ENOENT; - old_hash = bucket_hash(h, old_key); - idx_old = bucket_scan(h, old_hash, old_key); - if (idx_old == IDX_NIL) - return -ENOENT; + old_hash = bucket_hash (h, old_key); + idx_old = bucket_scan (h, old_hash, old_key); + if (idx_old == IDX_NIL) + return -ENOENT; - old_key = bucket_at(HASHMAP_BASE(h), idx_old)->key; + old_key = bucket_at (HASHMAP_BASE (h), idx_old)->key; - new_hash = bucket_hash(h, new_key); - idx_new = bucket_scan(h, new_hash, new_key); - if (idx_new != IDX_NIL) - if (idx_old != idx_new) { - remove_entry(h, idx_new); - /* Compensate for a possible backward shift. */ - if (old_key != bucket_at(HASHMAP_BASE(h), idx_old)->key) - idx_old = prev_idx(HASHMAP_BASE(h), idx_old); - assert(old_key == - bucket_at(HASHMAP_BASE(h), idx_old)->key); - } + new_hash = bucket_hash (h, new_key); + idx_new = bucket_scan (h, new_hash, new_key); + if (idx_new != IDX_NIL) + if (idx_old != idx_new) + { + remove_entry (h, idx_new); + /* Compensate for a possible backward shift. */ + if (old_key != bucket_at (HASHMAP_BASE (h), idx_old)->key) + idx_old = prev_idx (HASHMAP_BASE (h), idx_old); + assert (old_key == bucket_at (HASHMAP_BASE (h), idx_old)->key); + } - remove_entry(h, idx_old); + remove_entry (h, idx_old); - e = &bucket_at_swap(&swap, IDX_PUT)->p; - e->b.key = new_key; - e->value = value; - assert_se(hashmap_put_boldly(h, new_hash, &swap, false) == 1); + e = &bucket_at_swap (&swap, IDX_PUT)->p; + e->b.key = new_key; + e->value = value; + assert_se (hashmap_put_boldly (h, new_hash, &swap, false) == 1); - return 0; + return 0; } -void *hashmap_remove_value(Hashmap * h, const void *key, void *value) +void * +hashmap_remove_value (Hashmap * h, const void *key, void *value) { - struct plain_hashmap_entry *e; - unsigned hash, idx; + struct plain_hashmap_entry *e; + unsigned hash, idx; - if (!h) - return NULL; + if (!h) + return NULL; - hash = bucket_hash(h, key); - idx = bucket_scan(h, hash, key); - if (idx == IDX_NIL) - return NULL; + hash = bucket_hash (h, key); + idx = bucket_scan (h, hash, key); + if (idx == IDX_NIL) + return NULL; - e = plain_bucket_at(h, idx); - if (e->value != value) - return NULL; + e = plain_bucket_at (h, idx); + if (e->value != value) + return NULL; - remove_entry(h, idx); + remove_entry (h, idx); - return value; + return value; } -static unsigned find_first_entry(HashmapBase * h) +static unsigned +find_first_entry (HashmapBase * h) { - Iterator i = ITERATOR_FIRST; + Iterator i = ITERATOR_FIRST; - if (!h || !n_entries(h)) - return IDX_NIL; + if (!h || !n_entries (h)) + return IDX_NIL; - return hashmap_iterate_entry(h, &i); + return hashmap_iterate_entry (h, &i); } -void *internal_hashmap_first(HashmapBase * h) +void * +internal_hashmap_first (HashmapBase * h) { - unsigned idx; + unsigned idx; - idx = find_first_entry(h); - if (idx == IDX_NIL) - return NULL; + idx = find_first_entry (h); + if (idx == IDX_NIL) + return NULL; - return entry_value(h, bucket_at(h, idx)); + return entry_value (h, bucket_at (h, idx)); } -void *internal_hashmap_first_key(HashmapBase * h) +void * +internal_hashmap_first_key (HashmapBase * h) { - struct hashmap_base_entry *e; - unsigned idx; + struct hashmap_base_entry *e; + unsigned idx; - idx = find_first_entry(h); - if (idx == IDX_NIL) - return NULL; + idx = find_first_entry (h); + if (idx == IDX_NIL) + return NULL; - e = bucket_at(h, idx); - return (void *)e->key; + e = bucket_at (h, idx); + return (void *) e->key; } -void *internal_hashmap_steal_first(HashmapBase * h) +void * +internal_hashmap_steal_first (HashmapBase * h) { - struct hashmap_base_entry *e; - void *data; - unsigned idx; + struct hashmap_base_entry *e; + void *data; + unsigned idx; - idx = find_first_entry(h); - if (idx == IDX_NIL) - return NULL; + idx = find_first_entry (h); + if (idx == IDX_NIL) + return NULL; - e = bucket_at(h, idx); - data = entry_value(h, e); - remove_entry(h, idx); + e = bucket_at (h, idx); + data = entry_value (h, e); + remove_entry (h, idx); - return data; + return data; } -void *internal_hashmap_steal_first_key(HashmapBase * h) +void * +internal_hashmap_steal_first_key (HashmapBase * h) { - struct hashmap_base_entry *e; - void *key; - unsigned idx; + struct hashmap_base_entry *e; + void *key; + unsigned idx; - idx = find_first_entry(h); - if (idx == IDX_NIL) - return NULL; + idx = find_first_entry (h); + if (idx == IDX_NIL) + return NULL; - e = bucket_at(h, idx); - key = (void *)e->key; - remove_entry(h, idx); + e = bucket_at (h, idx); + key = (void *) e->key; + remove_entry (h, idx); - return key; + return key; } -unsigned internal_hashmap_size(HashmapBase * h) +unsigned +internal_hashmap_size (HashmapBase * h) { - if (!h) - return 0; + if (!h) + return 0; - return n_entries(h); + return n_entries (h); } -unsigned internal_hashmap_buckets(HashmapBase * h) +unsigned +internal_hashmap_buckets (HashmapBase * h) { - if (!h) - return 0; + if (!h) + return 0; - return n_buckets(h); + return n_buckets (h); } -int internal_hashmap_merge(Hashmap * h, Hashmap * other) +int +internal_hashmap_merge (Hashmap * h, Hashmap * other) { - Iterator i; - unsigned idx; + Iterator i; + unsigned idx; - assert(h); + assert (h); - HASHMAP_FOREACH_IDX(idx, HASHMAP_BASE(other), i) { - struct plain_hashmap_entry *pe = plain_bucket_at(other, idx); - int r; + HASHMAP_FOREACH_IDX (idx, HASHMAP_BASE (other), i) + { + struct plain_hashmap_entry *pe = plain_bucket_at (other, idx); + int r; - r = hashmap_put(h, pe->b.key, pe->value); - if (r < 0 && r != -EEXIST) - return r; - } + r = hashmap_put (h, pe->b.key, pe->value); + if (r < 0 && r != -EEXIST) + return r; + } - return 0; + return 0; } -int set_merge(Set * s, Set * other) +int +set_merge (Set * s, Set * other) { - Iterator i; - unsigned idx; + Iterator i; + unsigned idx; - assert(s); + assert (s); - HASHMAP_FOREACH_IDX(idx, HASHMAP_BASE(other), i) { - struct set_entry *se = set_bucket_at(other, idx); - int r; + HASHMAP_FOREACH_IDX (idx, HASHMAP_BASE (other), i) + { + struct set_entry *se = set_bucket_at (other, idx); + int r; - r = set_put(s, se->b.key); - if (r < 0) - return r; - } + r = set_put (s, se->b.key); + if (r < 0) + return r; + } - return 0; + return 0; } -int internal_hashmap_reserve(HashmapBase * h, unsigned entries_add) +int +internal_hashmap_reserve (HashmapBase * h, unsigned entries_add) { - int r; + int r; - assert(h); + assert (h); - r = resize_buckets(h, entries_add); - if (r < 0) - return r; + r = resize_buckets (h, entries_add); + if (r < 0) + return r; - return 0; + return 0; } /* @@ -1809,203 +1931,215 @@ int internal_hashmap_reserve(HashmapBase * h, unsigned entries_add) * Returns: 0 on success. * -ENOMEM on alloc failure, in which case no move has been done. */ -int internal_hashmap_move(HashmapBase * h, HashmapBase * other) -{ - struct swap_entries swap; - struct hashmap_base_entry *e, *n; - Iterator i; - unsigned idx; - int r; - - assert(h); - - if (!other) - return 0; - - assert(other->type == h->type); - - /* - * This reserves buckets for the worst case, where none of other's - * entries are yet present in h. This is preferable to risking - * an allocation failure in the middle of the moving and having to - * rollback or return a partial result. - */ - r = resize_buckets(h, n_entries(other)); - if (r < 0) - return r; - - HASHMAP_FOREACH_IDX(idx, other, i) { - unsigned h_hash; - - e = bucket_at(other, idx); - h_hash = bucket_hash(h, e->key); - if (bucket_scan(h, h_hash, e->key) != IDX_NIL) - continue; - - n = &bucket_at_swap(&swap, IDX_PUT)->p.b; - n->key = e->key; - if (h->type != HASHMAP_TYPE_SET) - ((struct plain_hashmap_entry *)n)->value = - ((struct plain_hashmap_entry *)e)->value; - assert_se(hashmap_put_boldly(h, h_hash, &swap, false) == 1); - - remove_entry(other, idx); - } +int +internal_hashmap_move (HashmapBase * h, HashmapBase * other) +{ + struct swap_entries swap; + struct hashmap_base_entry *e, *n; + Iterator i; + unsigned idx; + int r; - return 0; + assert (h); + + if (!other) + return 0; + + assert (other->type == h->type); + + /* + * This reserves buckets for the worst case, where none of other's + * entries are yet present in h. This is preferable to risking + * an allocation failure in the middle of the moving and having to + * rollback or return a partial result. + */ + r = resize_buckets (h, n_entries (other)); + if (r < 0) + return r; + + HASHMAP_FOREACH_IDX (idx, other, i) + { + unsigned h_hash; + + e = bucket_at (other, idx); + h_hash = bucket_hash (h, e->key); + if (bucket_scan (h, h_hash, e->key) != IDX_NIL) + continue; + + n = &bucket_at_swap (&swap, IDX_PUT)->p.b; + n->key = e->key; + if (h->type != HASHMAP_TYPE_SET) + ((struct plain_hashmap_entry *) n)->value = + ((struct plain_hashmap_entry *) e)->value; + assert_se (hashmap_put_boldly (h, h_hash, &swap, false) == 1); + + remove_entry (other, idx); + } + + return 0; } -int internal_hashmap_move_one(HashmapBase * h, HashmapBase * other, - const void *key) +int +internal_hashmap_move_one (HashmapBase * h, HashmapBase * other, + const void *key) { - struct swap_entries swap; - unsigned h_hash, other_hash, idx; - struct hashmap_base_entry *e, *n; - int r; + struct swap_entries swap; + unsigned h_hash, other_hash, idx; + struct hashmap_base_entry *e, *n; + int r; - assert(h); + assert (h); - h_hash = bucket_hash(h, key); - if (bucket_scan(h, h_hash, key) != IDX_NIL) - return -EEXIST; + h_hash = bucket_hash (h, key); + if (bucket_scan (h, h_hash, key) != IDX_NIL) + return -EEXIST; - if (!other) - return -ENOENT; + if (!other) + return -ENOENT; - assert(other->type == h->type); + assert (other->type == h->type); - other_hash = bucket_hash(other, key); - idx = bucket_scan(other, other_hash, key); - if (idx == IDX_NIL) - return -ENOENT; + other_hash = bucket_hash (other, key); + idx = bucket_scan (other, other_hash, key); + if (idx == IDX_NIL) + return -ENOENT; - e = bucket_at(other, idx); + e = bucket_at (other, idx); - n = &bucket_at_swap(&swap, IDX_PUT)->p.b; - n->key = e->key; - if (h->type != HASHMAP_TYPE_SET) - ((struct plain_hashmap_entry *)n)->value = - ((struct plain_hashmap_entry *)e)->value; - r = hashmap_put_boldly(h, h_hash, &swap, true); - if (r < 0) - return r; + n = &bucket_at_swap (&swap, IDX_PUT)->p.b; + n->key = e->key; + if (h->type != HASHMAP_TYPE_SET) + ((struct plain_hashmap_entry *) n)->value = + ((struct plain_hashmap_entry *) e)->value; + r = hashmap_put_boldly (h, h_hash, &swap, true); + if (r < 0) + return r; - remove_entry(other, idx); - return 0; + remove_entry (other, idx); + return 0; } -HashmapBase *internal_hashmap_copy(HashmapBase * h) +HashmapBase * +internal_hashmap_copy (HashmapBase * h) { - HashmapBase *copy; - int r; + HashmapBase *copy; + int r; - assert(h); + assert (h); - copy = hashmap_base_new(h->hash_ops, h->type HASHMAP_DEBUG_SRC_ARGS); - if (!copy) - return NULL; + copy = hashmap_base_new (h->hash_ops, h->type HASHMAP_DEBUG_SRC_ARGS); + if (!copy) + return NULL; - switch (h->type) { - case HASHMAP_TYPE_PLAIN: - case HASHMAP_TYPE_ORDERED: - r = hashmap_merge((Hashmap *) copy, (Hashmap *) h); - break; - case HASHMAP_TYPE_SET: - r = set_merge((Set *) copy, (Set *) h); - break; - default: - assert_not_reached("Unknown hashmap type"); - } + switch (h->type) + { + case HASHMAP_TYPE_PLAIN: + case HASHMAP_TYPE_ORDERED: + r = hashmap_merge ((Hashmap *) copy, (Hashmap *) h); + break; + case HASHMAP_TYPE_SET: + r = set_merge ((Set *) copy, (Set *) h); + break; + default: + assert_not_reached ("Unknown hashmap type"); + } - if (r < 0) { - internal_hashmap_free(copy); - return NULL; - } + if (r < 0) + { + internal_hashmap_free (copy); + return NULL; + } - return copy; + return copy; } -char **internal_hashmap_get_strv(HashmapBase * h) +char ** +internal_hashmap_get_strv (HashmapBase * h) { - char **sv; - Iterator i; - unsigned idx, n; + char **sv; + Iterator i; + unsigned idx, n; - sv = new(char *, n_entries(h) + 1); - if (!sv) - return NULL; + sv = new (char *, n_entries (h) + 1); + if (!sv) + return NULL; - n = 0; - HASHMAP_FOREACH_IDX(idx, h, i) - sv[n++] = entry_value(h, bucket_at(h, idx)); - sv[n] = NULL; + n = 0; + HASHMAP_FOREACH_IDX (idx, h, i) + sv[n++] = entry_value (h, bucket_at (h, idx)); + sv[n] = NULL; - return sv; + return sv; } -void *ordered_hashmap_next(OrderedHashmap * h, const void *key) +void * +ordered_hashmap_next (OrderedHashmap * h, const void *key) { - struct ordered_hashmap_entry *e; - unsigned hash, idx; + struct ordered_hashmap_entry *e; + unsigned hash, idx; - assert(key); + assert (key); - if (!h) - return NULL; + if (!h) + return NULL; - hash = bucket_hash(h, key); - idx = bucket_scan(h, hash, key); - if (idx == IDX_NIL) - return NULL; + hash = bucket_hash (h, key); + idx = bucket_scan (h, hash, key); + if (idx == IDX_NIL) + return NULL; - e = ordered_bucket_at(h, idx); - if (e->iterate_next == IDX_NIL) - return NULL; - return ordered_bucket_at(h, e->iterate_next)->p.value; + e = ordered_bucket_at (h, idx); + if (e->iterate_next == IDX_NIL) + return NULL; + return ordered_bucket_at (h, e->iterate_next)->p.value; } -int set_consume(Set * s, void *value) +int +set_consume (Set * s, void *value) { - int r; + int r; - r = set_put(s, value); - if (r <= 0) - free(value); + r = set_put (s, value); + if (r <= 0) + free (value); - return r; + return r; } -int set_put_strdup(Set * s, const char *p) +int +set_put_strdup (Set * s, const char *p) { - char *c; - int r; + char *c; + int r; - assert(s); - assert(p); + assert (s); + assert (p); - c = strdup(p); - if (!c) - return -ENOMEM; + c = strdup (p); + if (!c) + return -ENOMEM; - r = set_consume(s, c); - if (r == -EEXIST) - return 0; + r = set_consume (s, c); + if (r == -EEXIST) + return 0; - return r; + return r; } -int set_put_strdupv(Set * s, char **l) +int +set_put_strdupv (Set * s, char **l) { - int n = 0, r; - char **i; + int n = 0, r; + char **i; - STRV_FOREACH(i, l) { - r = set_put_strdup(s, *i); - if (r < 0) - return r; + STRV_FOREACH (i, l) + { + r = set_put_strdup (s, *i); + if (r < 0) + return r; - n += r; - } + n += r; + } - return n; + return n; } diff --git a/libudev-compat/hashmap.h b/libudev-compat/hashmap.h index fd060bb..1941034 100644 --- a/libudev-compat/hashmap.h +++ b/libudev-compat/hashmap.h @@ -64,13 +64,14 @@ typedef struct Set Set; /* Stores just keys */ /* Ideally the Iterator would be an opaque struct, but it is instantiated * by hashmap users, so the definition has to be here. Do not use its fields * directly. */ -typedef struct { - unsigned idx; /* index of an entry to be iterated next */ - const void *next_key; /* expected value of that entry's key pointer */ +typedef struct +{ + unsigned idx; /* index of an entry to be iterated next */ + const void *next_key; /* expected value of that entry's key pointer */ #ifdef ENABLE_DEBUG_HASHMAP - unsigned put_count; /* hashmap's put_count recorded at start of iteration */ - unsigned rem_count; /* hashmap's rem_count in previous iteration */ - unsigned prev_idx; /* idx in previous iteration */ + unsigned put_count; /* hashmap's put_count recorded at start of iteration */ + unsigned rem_count; /* hashmap's rem_count in previous iteration */ + unsigned prev_idx; /* idx in previous iteration */ #endif } Iterator; @@ -81,42 +82,47 @@ typedef unsigned long (*hash_func_t) (const void *p, const uint8_t hash_key[HASH_KEY_SIZE]); typedef int (*compare_func_t) (const void *a, const void *b); -struct hash_ops { - hash_func_t hash; - compare_func_t compare; +struct hash_ops +{ + hash_func_t hash; + compare_func_t compare; }; -unsigned long string_hash_func(const void *p, - const uint8_t hash_key[HASH_KEY_SIZE]) _pure_; -int string_compare_func(const void *a, const void *b) _pure_; -extern const struct hash_ops string_hash_ops; +unsigned long +string_hash_func (const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) + _pure_; + int string_compare_func (const void *a, const void *b) _pure_; + extern const struct hash_ops string_hash_ops; /* This will compare the passed pointers directly, and will not * dereference them. This is hence not useful for strings or * suchlike. */ -unsigned long trivial_hash_func(const void *p, - const uint8_t hash_key[HASH_KEY_SIZE]) _pure_; -int trivial_compare_func(const void *a, const void *b) _const_; -extern const struct hash_ops trivial_hash_ops; + unsigned long trivial_hash_func (const void *p, + const uint8_t hash_key[HASH_KEY_SIZE]) + _pure_; + int trivial_compare_func (const void *a, const void *b) _const_; + extern const struct hash_ops trivial_hash_ops; /* 32bit values we can always just embedd in the pointer itself, but * in order to support 32bit archs we need store 64bit values * indirectly, since they don't fit in a pointer. */ -unsigned long uint64_hash_func(const void *p, - const uint8_t hash_key[HASH_KEY_SIZE]) _pure_; -int uint64_compare_func(const void *a, const void *b) _pure_; -extern const struct hash_ops uint64_hash_ops; + unsigned long uint64_hash_func (const void *p, + const uint8_t hash_key[HASH_KEY_SIZE]) + _pure_; + int uint64_compare_func (const void *a, const void *b) _pure_; + extern const struct hash_ops uint64_hash_ops; /* On some archs dev_t is 32bit, and on others 64bit. And sometimes * it's 64bit on 32bit archs, and sometimes 32bit on 64bit archs. Yuck! */ #if SIZEOF_DEV_T != 8 -unsigned long devt_hash_func(const void *p, - const uint8_t hash_key[HASH_KEY_SIZE]) _pure_; -int devt_compare_func(const void *a, const void *b) _pure_; -extern const struct hash_ops devt_hash_ops = { - .hash = devt_hash_func, - .compare = devt_compare_func -}; + unsigned long devt_hash_func (const void *p, + const uint8_t hash_key[HASH_KEY_SIZE]) + _pure_; + int devt_compare_func (const void *a, const void *b) _pure_; + extern const struct hash_ops devt_hash_ops = { + .hash = devt_hash_func, + .compare = devt_compare_func + }; #else #define devt_hash_func uint64_hash_func #define devt_compare_func uint64_compare_func @@ -154,276 +160,306 @@ extern const struct hash_ops devt_hash_ops = { #define HASHMAP_DEBUG_PASS_ARGS #endif -Hashmap *internal_hashmap_new(const struct hash_ops *hash_ops - HASHMAP_DEBUG_PARAMS); -OrderedHashmap *internal_ordered_hashmap_new(const struct hash_ops *hash_ops - HASHMAP_DEBUG_PARAMS); + Hashmap *internal_hashmap_new (const struct hash_ops *hash_ops + HASHMAP_DEBUG_PARAMS); + OrderedHashmap *internal_ordered_hashmap_new (const struct hash_ops + *hash_ops + HASHMAP_DEBUG_PARAMS); #define hashmap_new(ops) internal_hashmap_new(ops HASHMAP_DEBUG_SRC_ARGS) #define ordered_hashmap_new(ops) internal_ordered_hashmap_new(ops HASHMAP_DEBUG_SRC_ARGS) -void internal_hashmap_free(HashmapBase * h); -static inline void hashmap_free(Hashmap * h) + void internal_hashmap_free (HashmapBase * h); + static inline void hashmap_free (Hashmap * h) { - internal_hashmap_free(HASHMAP_BASE(h)); + internal_hashmap_free (HASHMAP_BASE (h)); } -static inline void ordered_hashmap_free(OrderedHashmap * h) +static inline void +ordered_hashmap_free (OrderedHashmap * h) { - internal_hashmap_free(HASHMAP_BASE(h)); + internal_hashmap_free (HASHMAP_BASE (h)); } -void internal_hashmap_free_free(HashmapBase * h); -static inline void hashmap_free_free(Hashmap * h) +void internal_hashmap_free_free (HashmapBase * h); +static inline void +hashmap_free_free (Hashmap * h) { - internal_hashmap_free_free(HASHMAP_BASE(h)); + internal_hashmap_free_free (HASHMAP_BASE (h)); } -static inline void ordered_hashmap_free_free(OrderedHashmap * h) +static inline void +ordered_hashmap_free_free (OrderedHashmap * h) { - internal_hashmap_free_free(HASHMAP_BASE(h)); + internal_hashmap_free_free (HASHMAP_BASE (h)); } -void hashmap_free_free_free(Hashmap * h); -static inline void ordered_hashmap_free_free_free(OrderedHashmap * h) +void hashmap_free_free_free (Hashmap * h); +static inline void +ordered_hashmap_free_free_free (OrderedHashmap * h) { - hashmap_free_free_free(PLAIN_HASHMAP(h)); + hashmap_free_free_free (PLAIN_HASHMAP (h)); } -HashmapBase *internal_hashmap_copy(HashmapBase * h); -static inline Hashmap *hashmap_copy(Hashmap * h) +HashmapBase *internal_hashmap_copy (HashmapBase * h); +static inline Hashmap * +hashmap_copy (Hashmap * h) { - return (Hashmap *) internal_hashmap_copy(HASHMAP_BASE(h)); + return (Hashmap *) internal_hashmap_copy (HASHMAP_BASE (h)); } -static inline OrderedHashmap *ordered_hashmap_copy(OrderedHashmap * h) +static inline OrderedHashmap * +ordered_hashmap_copy (OrderedHashmap * h) { - return (OrderedHashmap *) internal_hashmap_copy(HASHMAP_BASE(h)); + return (OrderedHashmap *) internal_hashmap_copy (HASHMAP_BASE (h)); } -int internal_hashmap_ensure_allocated(Hashmap ** h, - const struct hash_ops *hash_ops - HASHMAP_DEBUG_PARAMS); -int internal_ordered_hashmap_ensure_allocated(OrderedHashmap ** h, - const struct hash_ops *hash_ops - HASHMAP_DEBUG_PARAMS); +int internal_hashmap_ensure_allocated (Hashmap ** h, + const struct hash_ops *hash_ops + HASHMAP_DEBUG_PARAMS); +int internal_ordered_hashmap_ensure_allocated (OrderedHashmap ** h, + const struct hash_ops *hash_ops + HASHMAP_DEBUG_PARAMS); #define hashmap_ensure_allocated(h, ops) internal_hashmap_ensure_allocated(h, ops HASHMAP_DEBUG_SRC_ARGS) #define ordered_hashmap_ensure_allocated(h, ops) internal_ordered_hashmap_ensure_allocated(h, ops HASHMAP_DEBUG_SRC_ARGS) -int hashmap_put(Hashmap * h, const void *key, void *value); -static inline int ordered_hashmap_put(OrderedHashmap * h, const void *key, - void *value) +int hashmap_put (Hashmap * h, const void *key, void *value); +static inline int +ordered_hashmap_put (OrderedHashmap * h, const void *key, void *value) { - return hashmap_put(PLAIN_HASHMAP(h), key, value); + return hashmap_put (PLAIN_HASHMAP (h), key, value); } -int hashmap_update(Hashmap * h, const void *key, void *value); -static inline int ordered_hashmap_update(OrderedHashmap * h, const void *key, - void *value) +int hashmap_update (Hashmap * h, const void *key, void *value); +static inline int +ordered_hashmap_update (OrderedHashmap * h, const void *key, void *value) { - return hashmap_update(PLAIN_HASHMAP(h), key, value); + return hashmap_update (PLAIN_HASHMAP (h), key, value); } -int hashmap_replace(Hashmap * h, const void *key, void *value); -static inline int ordered_hashmap_replace(OrderedHashmap * h, const void *key, - void *value) +int hashmap_replace (Hashmap * h, const void *key, void *value); +static inline int +ordered_hashmap_replace (OrderedHashmap * h, const void *key, void *value) { - return hashmap_replace(PLAIN_HASHMAP(h), key, value); + return hashmap_replace (PLAIN_HASHMAP (h), key, value); } -void *internal_hashmap_get(HashmapBase * h, const void *key); -static inline void *hashmap_get(Hashmap * h, const void *key) +void *internal_hashmap_get (HashmapBase * h, const void *key); +static inline void * +hashmap_get (Hashmap * h, const void *key) { - return internal_hashmap_get(HASHMAP_BASE(h), key); + return internal_hashmap_get (HASHMAP_BASE (h), key); } -static inline void *ordered_hashmap_get(OrderedHashmap * h, const void *key) +static inline void * +ordered_hashmap_get (OrderedHashmap * h, const void *key) { - return internal_hashmap_get(HASHMAP_BASE(h), key); + return internal_hashmap_get (HASHMAP_BASE (h), key); } -void *hashmap_get2(Hashmap * h, const void *key, void **rkey); -static inline void *ordered_hashmap_get2(OrderedHashmap * h, const void *key, - void **rkey) +void *hashmap_get2 (Hashmap * h, const void *key, void **rkey); +static inline void * +ordered_hashmap_get2 (OrderedHashmap * h, const void *key, void **rkey) { - return hashmap_get2(PLAIN_HASHMAP(h), key, rkey); + return hashmap_get2 (PLAIN_HASHMAP (h), key, rkey); } -bool internal_hashmap_contains(HashmapBase * h, const void *key); -static inline bool hashmap_contains(Hashmap * h, const void *key) +bool internal_hashmap_contains (HashmapBase * h, const void *key); +static inline bool +hashmap_contains (Hashmap * h, const void *key) { - return internal_hashmap_contains(HASHMAP_BASE(h), key); + return internal_hashmap_contains (HASHMAP_BASE (h), key); } -static inline bool ordered_hashmap_contains(OrderedHashmap * h, const void *key) +static inline bool +ordered_hashmap_contains (OrderedHashmap * h, const void *key) { - return internal_hashmap_contains(HASHMAP_BASE(h), key); + return internal_hashmap_contains (HASHMAP_BASE (h), key); } -void *internal_hashmap_remove(HashmapBase * h, const void *key); -static inline void *hashmap_remove(Hashmap * h, const void *key) +void *internal_hashmap_remove (HashmapBase * h, const void *key); +static inline void * +hashmap_remove (Hashmap * h, const void *key) { - return internal_hashmap_remove(HASHMAP_BASE(h), key); + return internal_hashmap_remove (HASHMAP_BASE (h), key); } -static inline void *ordered_hashmap_remove(OrderedHashmap * h, const void *key) +static inline void * +ordered_hashmap_remove (OrderedHashmap * h, const void *key) { - return internal_hashmap_remove(HASHMAP_BASE(h), key); + return internal_hashmap_remove (HASHMAP_BASE (h), key); } -void *hashmap_remove2(Hashmap * h, const void *key, void **rkey); -static inline void *ordered_hashmap_remove2(OrderedHashmap * h, const void *key, - void **rkey) +void *hashmap_remove2 (Hashmap * h, const void *key, void **rkey); +static inline void * +ordered_hashmap_remove2 (OrderedHashmap * h, const void *key, void **rkey) { - return hashmap_remove2(PLAIN_HASHMAP(h), key, rkey); + return hashmap_remove2 (PLAIN_HASHMAP (h), key, rkey); } -void *hashmap_remove_value(Hashmap * h, const void *key, void *value); -static inline void *ordered_hashmap_remove_value(OrderedHashmap * h, - const void *key, void *value) +void *hashmap_remove_value (Hashmap * h, const void *key, void *value); +static inline void * +ordered_hashmap_remove_value (OrderedHashmap * h, + const void *key, void *value) { - return hashmap_remove_value(PLAIN_HASHMAP(h), key, value); + return hashmap_remove_value (PLAIN_HASHMAP (h), key, value); } -int hashmap_remove_and_put(Hashmap * h, const void *old_key, - const void *new_key, void *value); -static inline int ordered_hashmap_remove_and_put(OrderedHashmap * h, - const void *old_key, - const void *new_key, - void *value) +int hashmap_remove_and_put (Hashmap * h, const void *old_key, + const void *new_key, void *value); +static inline int +ordered_hashmap_remove_and_put (OrderedHashmap * h, + const void *old_key, + const void *new_key, void *value) { - return hashmap_remove_and_put(PLAIN_HASHMAP(h), old_key, new_key, - value); + return hashmap_remove_and_put (PLAIN_HASHMAP (h), old_key, new_key, value); } -int hashmap_remove_and_replace(Hashmap * h, const void *old_key, - const void *new_key, void *value); -static inline int ordered_hashmap_remove_and_replace(OrderedHashmap * h, - const void *old_key, - const void *new_key, - void *value) +int hashmap_remove_and_replace (Hashmap * h, const void *old_key, + const void *new_key, void *value); +static inline int +ordered_hashmap_remove_and_replace (OrderedHashmap * h, + const void *old_key, + const void *new_key, void *value) { - return hashmap_remove_and_replace(PLAIN_HASHMAP(h), old_key, new_key, - value); + return hashmap_remove_and_replace (PLAIN_HASHMAP (h), old_key, new_key, + value); } /* Since merging data from a OrderedHashmap into a Hashmap or vice-versa * should just work, allow this by having looser type-checking here. */ -int internal_hashmap_merge(Hashmap * h, Hashmap * other); +int internal_hashmap_merge (Hashmap * h, Hashmap * other); #define hashmap_merge(h, other) internal_hashmap_merge(PLAIN_HASHMAP(h), PLAIN_HASHMAP(other)) #define ordered_hashmap_merge(h, other) hashmap_merge(h, other) -int internal_hashmap_reserve(HashmapBase * h, unsigned entries_add); -static inline int hashmap_reserve(Hashmap * h, unsigned entries_add) +int internal_hashmap_reserve (HashmapBase * h, unsigned entries_add); +static inline int +hashmap_reserve (Hashmap * h, unsigned entries_add) { - return internal_hashmap_reserve(HASHMAP_BASE(h), entries_add); + return internal_hashmap_reserve (HASHMAP_BASE (h), entries_add); } -static inline int ordered_hashmap_reserve(OrderedHashmap * h, - unsigned entries_add) +static inline int +ordered_hashmap_reserve (OrderedHashmap * h, unsigned entries_add) { - return internal_hashmap_reserve(HASHMAP_BASE(h), entries_add); + return internal_hashmap_reserve (HASHMAP_BASE (h), entries_add); } -int internal_hashmap_move(HashmapBase * h, HashmapBase * other); +int internal_hashmap_move (HashmapBase * h, HashmapBase * other); /* Unlike hashmap_merge, hashmap_move does not allow mixing the types. */ -static inline int hashmap_move(Hashmap * h, Hashmap * other) +static inline int +hashmap_move (Hashmap * h, Hashmap * other) { - return internal_hashmap_move(HASHMAP_BASE(h), HASHMAP_BASE(other)); + return internal_hashmap_move (HASHMAP_BASE (h), HASHMAP_BASE (other)); } -static inline int ordered_hashmap_move(OrderedHashmap * h, - OrderedHashmap * other) +static inline int +ordered_hashmap_move (OrderedHashmap * h, OrderedHashmap * other) { - return internal_hashmap_move(HASHMAP_BASE(h), HASHMAP_BASE(other)); + return internal_hashmap_move (HASHMAP_BASE (h), HASHMAP_BASE (other)); } -int internal_hashmap_move_one(HashmapBase * h, HashmapBase * other, - const void *key); -static inline int hashmap_move_one(Hashmap * h, Hashmap * other, - const void *key) +int internal_hashmap_move_one (HashmapBase * h, HashmapBase * other, + const void *key); +static inline int +hashmap_move_one (Hashmap * h, Hashmap * other, const void *key) { - return internal_hashmap_move_one(HASHMAP_BASE(h), HASHMAP_BASE(other), - key); + return internal_hashmap_move_one (HASHMAP_BASE (h), HASHMAP_BASE (other), + key); } -static inline int ordered_hashmap_move_one(OrderedHashmap * h, - OrderedHashmap * other, - const void *key) +static inline int +ordered_hashmap_move_one (OrderedHashmap * h, + OrderedHashmap * other, const void *key) { - return internal_hashmap_move_one(HASHMAP_BASE(h), HASHMAP_BASE(other), - key); + return internal_hashmap_move_one (HASHMAP_BASE (h), HASHMAP_BASE (other), + key); } -unsigned internal_hashmap_size(HashmapBase * h) _pure_; -static inline unsigned hashmap_size(Hashmap * h) +unsigned +internal_hashmap_size (HashmapBase * h) + _pure_; + static inline unsigned hashmap_size (Hashmap * h) { - return internal_hashmap_size(HASHMAP_BASE(h)); + return internal_hashmap_size (HASHMAP_BASE (h)); } -static inline unsigned ordered_hashmap_size(OrderedHashmap * h) +static inline unsigned +ordered_hashmap_size (OrderedHashmap * h) { - return internal_hashmap_size(HASHMAP_BASE(h)); + return internal_hashmap_size (HASHMAP_BASE (h)); } -static inline bool hashmap_isempty(Hashmap * h) +static inline bool +hashmap_isempty (Hashmap * h) { - return hashmap_size(h) == 0; + return hashmap_size (h) == 0; } -static inline bool ordered_hashmap_isempty(OrderedHashmap * h) +static inline bool +ordered_hashmap_isempty (OrderedHashmap * h) { - return ordered_hashmap_size(h) == 0; + return ordered_hashmap_size (h) == 0; } -unsigned internal_hashmap_buckets(HashmapBase * h) _pure_; -static inline unsigned hashmap_buckets(Hashmap * h) +unsigned +internal_hashmap_buckets (HashmapBase * h) + _pure_; + static inline unsigned hashmap_buckets (Hashmap * h) { - return internal_hashmap_buckets(HASHMAP_BASE(h)); + return internal_hashmap_buckets (HASHMAP_BASE (h)); } -static inline unsigned ordered_hashmap_buckets(OrderedHashmap * h) +static inline unsigned +ordered_hashmap_buckets (OrderedHashmap * h) { - return internal_hashmap_buckets(HASHMAP_BASE(h)); + return internal_hashmap_buckets (HASHMAP_BASE (h)); } -void *internal_hashmap_iterate(HashmapBase * h, Iterator * i, const void **key); -static inline void *hashmap_iterate(Hashmap * h, Iterator * i, const void **key) +void *internal_hashmap_iterate (HashmapBase * h, Iterator * i, + const void **key); +static inline void * +hashmap_iterate (Hashmap * h, Iterator * i, const void **key) { - return internal_hashmap_iterate(HASHMAP_BASE(h), i, key); + return internal_hashmap_iterate (HASHMAP_BASE (h), i, key); } -static inline void *ordered_hashmap_iterate(OrderedHashmap * h, Iterator * i, - const void **key) +static inline void * +ordered_hashmap_iterate (OrderedHashmap * h, Iterator * i, const void **key) { - return internal_hashmap_iterate(HASHMAP_BASE(h), i, key); + return internal_hashmap_iterate (HASHMAP_BASE (h), i, key); } -void internal_hashmap_clear(HashmapBase * h); -static inline void hashmap_clear(Hashmap * h) +void internal_hashmap_clear (HashmapBase * h); +static inline void +hashmap_clear (Hashmap * h) { - internal_hashmap_clear(HASHMAP_BASE(h)); + internal_hashmap_clear (HASHMAP_BASE (h)); } -static inline void ordered_hashmap_clear(OrderedHashmap * h) +static inline void +ordered_hashmap_clear (OrderedHashmap * h) { - internal_hashmap_clear(HASHMAP_BASE(h)); + internal_hashmap_clear (HASHMAP_BASE (h)); } -void internal_hashmap_clear_free(HashmapBase * h); -static inline void hashmap_clear_free(Hashmap * h) +void internal_hashmap_clear_free (HashmapBase * h); +static inline void +hashmap_clear_free (Hashmap * h) { - internal_hashmap_clear_free(HASHMAP_BASE(h)); + internal_hashmap_clear_free (HASHMAP_BASE (h)); } -static inline void ordered_hashmap_clear_free(OrderedHashmap * h) +static inline void +ordered_hashmap_clear_free (OrderedHashmap * h) { - internal_hashmap_clear_free(HASHMAP_BASE(h)); + internal_hashmap_clear_free (HASHMAP_BASE (h)); } -void hashmap_clear_free_free(Hashmap * h); -static inline void ordered_hashmap_clear_free_free(OrderedHashmap * h) +void hashmap_clear_free_free (Hashmap * h); +static inline void +ordered_hashmap_clear_free_free (OrderedHashmap * h) { - hashmap_clear_free_free(PLAIN_HASHMAP(h)); + hashmap_clear_free_free (PLAIN_HASHMAP (h)); } /* @@ -437,62 +473,74 @@ static inline void ordered_hashmap_clear_free_free(OrderedHashmap * h) * the first entry is O(1). */ -void *internal_hashmap_steal_first(HashmapBase * h); -static inline void *hashmap_steal_first(Hashmap * h) +void *internal_hashmap_steal_first (HashmapBase * h); +static inline void * +hashmap_steal_first (Hashmap * h) { - return internal_hashmap_steal_first(HASHMAP_BASE(h)); + return internal_hashmap_steal_first (HASHMAP_BASE (h)); } -static inline void *ordered_hashmap_steal_first(OrderedHashmap * h) +static inline void * +ordered_hashmap_steal_first (OrderedHashmap * h) { - return internal_hashmap_steal_first(HASHMAP_BASE(h)); + return internal_hashmap_steal_first (HASHMAP_BASE (h)); } -void *internal_hashmap_steal_first_key(HashmapBase * h); -static inline void *hashmap_steal_first_key(Hashmap * h) +void *internal_hashmap_steal_first_key (HashmapBase * h); +static inline void * +hashmap_steal_first_key (Hashmap * h) { - return internal_hashmap_steal_first_key(HASHMAP_BASE(h)); + return internal_hashmap_steal_first_key (HASHMAP_BASE (h)); } -static inline void *ordered_hashmap_steal_first_key(OrderedHashmap * h) +static inline void * +ordered_hashmap_steal_first_key (OrderedHashmap * h) { - return internal_hashmap_steal_first_key(HASHMAP_BASE(h)); + return internal_hashmap_steal_first_key (HASHMAP_BASE (h)); } -void *internal_hashmap_first_key(HashmapBase * h) _pure_; -static inline void *hashmap_first_key(Hashmap * h) +void * +internal_hashmap_first_key (HashmapBase * h) + _pure_; + static inline void *hashmap_first_key (Hashmap * h) { - return internal_hashmap_first_key(HASHMAP_BASE(h)); + return internal_hashmap_first_key (HASHMAP_BASE (h)); } -static inline void *ordered_hashmap_first_key(OrderedHashmap * h) +static inline void * +ordered_hashmap_first_key (OrderedHashmap * h) { - return internal_hashmap_first_key(HASHMAP_BASE(h)); + return internal_hashmap_first_key (HASHMAP_BASE (h)); } -void *internal_hashmap_first(HashmapBase * h) _pure_; -static inline void *hashmap_first(Hashmap * h) +void * +internal_hashmap_first (HashmapBase * h) + _pure_; + static inline void *hashmap_first (Hashmap * h) { - return internal_hashmap_first(HASHMAP_BASE(h)); + return internal_hashmap_first (HASHMAP_BASE (h)); } -static inline void *ordered_hashmap_first(OrderedHashmap * h) +static inline void * +ordered_hashmap_first (OrderedHashmap * h) { - return internal_hashmap_first(HASHMAP_BASE(h)); + return internal_hashmap_first (HASHMAP_BASE (h)); } /* no hashmap_next */ -void *ordered_hashmap_next(OrderedHashmap * h, const void *key); +void *ordered_hashmap_next (OrderedHashmap * h, const void *key); -char **internal_hashmap_get_strv(HashmapBase * h); -static inline char **hashmap_get_strv(Hashmap * h) +char **internal_hashmap_get_strv (HashmapBase * h); +static inline char ** +hashmap_get_strv (Hashmap * h) { - return internal_hashmap_get_strv(HASHMAP_BASE(h)); + return internal_hashmap_get_strv (HASHMAP_BASE (h)); } -static inline char **ordered_hashmap_get_strv(OrderedHashmap * h) +static inline char ** +ordered_hashmap_get_strv (OrderedHashmap * h) { - return internal_hashmap_get_strv(HASHMAP_BASE(h)); + return internal_hashmap_get_strv (HASHMAP_BASE (h)); } /* @@ -521,12 +569,13 @@ static inline char **ordered_hashmap_get_strv(OrderedHashmap * h) (e); \ (e) = ordered_hashmap_iterate((h), &(i), (const void**) &(k))) -DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap *, hashmap_free); -DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap *, hashmap_free_free); -DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap *, hashmap_free_free_free); -DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedHashmap *, ordered_hashmap_free); -DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedHashmap *, ordered_hashmap_free_free); -DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedHashmap *, ordered_hashmap_free_free_free); +DEFINE_TRIVIAL_CLEANUP_FUNC (Hashmap *, hashmap_free); +DEFINE_TRIVIAL_CLEANUP_FUNC (Hashmap *, hashmap_free_free); +DEFINE_TRIVIAL_CLEANUP_FUNC (Hashmap *, hashmap_free_free_free); +DEFINE_TRIVIAL_CLEANUP_FUNC (OrderedHashmap *, ordered_hashmap_free); +DEFINE_TRIVIAL_CLEANUP_FUNC (OrderedHashmap *, ordered_hashmap_free_free); +DEFINE_TRIVIAL_CLEANUP_FUNC (OrderedHashmap *, + ordered_hashmap_free_free_free); #define _cleanup_hashmap_free_ _cleanup_(hashmap_freep) #define _cleanup_hashmap_free_free_ _cleanup_(hashmap_free_freep) diff --git a/libudev-compat/hwdb-internal.h b/libudev-compat/hwdb-internal.h index e4f061d..333f120 100644 --- a/libudev-compat/hwdb-internal.h +++ b/libudev-compat/hwdb-internal.h @@ -34,50 +34,54 @@ #define HWDB_SIG { 'K', 'S', 'L', 'P', 'H', 'H', 'R', 'H' } /* on-disk trie objects */ -struct trie_header_f { - uint8_t signature[8]; - - /* version of tool which created the file */ - le64_t tool_version; - le64_t file_size; - - /* size of structures to allow them to grow */ - le64_t header_size; - le64_t node_size; - le64_t child_entry_size; - le64_t value_entry_size; - - /* offset of the root trie node */ - le64_t nodes_root_off; - - /* size of the nodes and string section */ - le64_t nodes_len; - le64_t strings_len; +struct trie_header_f +{ + uint8_t signature[8]; + + /* version of tool which created the file */ + le64_t tool_version; + le64_t file_size; + + /* size of structures to allow them to grow */ + le64_t header_size; + le64_t node_size; + le64_t child_entry_size; + le64_t value_entry_size; + + /* offset of the root trie node */ + le64_t nodes_root_off; + + /* size of the nodes and string section */ + le64_t nodes_len; + le64_t strings_len; } _packed_; -struct trie_node_f { - /* prefix of lookup string, shared by all children */ - le64_t prefix_off; - /* size of children entry array appended to the node */ - uint8_t children_count; - uint8_t padding[7]; - /* size of value entry array appended to the node */ - le64_t values_count; +struct trie_node_f +{ + /* prefix of lookup string, shared by all children */ + le64_t prefix_off; + /* size of children entry array appended to the node */ + uint8_t children_count; + uint8_t padding[7]; + /* size of value entry array appended to the node */ + le64_t values_count; } _packed_; /* array of child entries, follows directly the node record */ -struct trie_child_entry_f { - /* index of the child node */ - uint8_t c; - uint8_t padding[7]; - /* offset of the child node */ - le64_t child_off; +struct trie_child_entry_f +{ + /* index of the child node */ + uint8_t c; + uint8_t padding[7]; + /* offset of the child node */ + le64_t child_off; } _packed_; /* array of value entries, follows directly the node record/child array */ -struct trie_value_entry_f { - le64_t key_off; - le64_t value_off; +struct trie_value_entry_f +{ + le64_t key_off; + le64_t value_off; } _packed_; #endif diff --git a/libudev-compat/hwdb-util.h b/libudev-compat/hwdb-util.h index 01c9328..d3de530 100644 --- a/libudev-compat/hwdb-util.h +++ b/libudev-compat/hwdb-util.h @@ -34,9 +34,9 @@ #include "sd-hwdb.h" -DEFINE_TRIVIAL_CLEANUP_FUNC(sd_hwdb *, sd_hwdb_unref); +DEFINE_TRIVIAL_CLEANUP_FUNC (sd_hwdb *, sd_hwdb_unref); #define _cleanup_hwdb_unref_ _cleanup_(sd_hwdb_unrefp) -bool hwdb_validate(sd_hwdb * hwdb); +bool hwdb_validate (sd_hwdb * hwdb); #endif diff --git a/libudev-compat/libudev-device-private.c b/libudev-compat/libudev-device-private.c index c93482f..b4a1793 100644 --- a/libudev-compat/libudev-device-private.c +++ b/libudev-compat/libudev-device-private.c @@ -39,192 +39,200 @@ #include "log.h" #include "util.h" -static void udev_device_tag(struct udev_device *dev, const char *tag, bool add) +static void +udev_device_tag (struct udev_device *dev, const char *tag, bool add) { - const char *id; - char filename[UTIL_PATH_SIZE]; - - id = udev_device_get_id_filename(dev); - if (id == NULL) - return; - strscpyl(filename, sizeof(filename), "/run/udev/tags/", tag, "/", id, - NULL); - - if (add) { - int fd; - - mkdir_parents(filename, 0755); - fd = open(filename, - O_WRONLY | O_CREAT | O_CLOEXEC | O_TRUNC | O_NOFOLLOW, - 0444); - if (fd >= 0) - close(fd); - } else { - unlink(filename); - } + const char *id; + char filename[UTIL_PATH_SIZE]; + + id = udev_device_get_id_filename (dev); + if (id == NULL) + return; + strscpyl (filename, sizeof (filename), "/run/udev/tags/", tag, "/", id, + NULL); + + if (add) + { + int fd; + + mkdir_parents (filename, 0755); + fd = open (filename, + O_WRONLY | O_CREAT | O_CLOEXEC | O_TRUNC | O_NOFOLLOW, 0444); + if (fd >= 0) + close (fd); + } + else + { + unlink (filename); + } } -int udev_device_tag_index(struct udev_device *dev, struct udev_device *dev_old, - bool add) +int +udev_device_tag_index (struct udev_device *dev, struct udev_device *dev_old, + bool add) { - struct udev_list_entry *list_entry; - bool found; - - if (add && dev_old != NULL) { - /* delete possible left-over tags */ - udev_list_entry_foreach(list_entry, - udev_device_get_tags_list_entry - (dev_old)) { - const char *tag_old = - udev_list_entry_get_name(list_entry); - struct udev_list_entry *list_entry_current; - - found = false; - udev_list_entry_foreach(list_entry_current, - udev_device_get_tags_list_entry - (dev)) { - const char *tag = - udev_list_entry_get_name - (list_entry_current); - - if (streq(tag, tag_old)) { - found = true; - break; - } - } - if (!found) - udev_device_tag(dev_old, tag_old, false); - } + struct udev_list_entry *list_entry; + bool found; + + if (add && dev_old != NULL) + { + /* delete possible left-over tags */ + udev_list_entry_foreach (list_entry, + udev_device_get_tags_list_entry (dev_old)) + { + const char *tag_old = udev_list_entry_get_name (list_entry); + struct udev_list_entry *list_entry_current; + + found = false; + udev_list_entry_foreach (list_entry_current, + udev_device_get_tags_list_entry (dev)) + { + const char *tag = udev_list_entry_get_name (list_entry_current); + + if (streq (tag, tag_old)) + { + found = true; + break; + } } + if (!found) + udev_device_tag (dev_old, tag_old, false); + } + } - udev_list_entry_foreach(list_entry, - udev_device_get_tags_list_entry(dev)) - udev_device_tag(dev, udev_list_entry_get_name(list_entry), add); + udev_list_entry_foreach (list_entry, + udev_device_get_tags_list_entry (dev)) + udev_device_tag (dev, udev_list_entry_get_name (list_entry), add); - return 0; + return 0; } -static bool device_has_info(struct udev_device *udev_device) +static bool +device_has_info (struct udev_device *udev_device) { - struct udev_list_entry *list_entry; - - if (udev_device_get_devlinks_list_entry(udev_device) != NULL) - return true; - if (udev_device_get_devlink_priority(udev_device) != 0) - return true; - udev_list_entry_foreach(list_entry, - udev_device_get_properties_list_entry - (udev_device)) - if (udev_list_entry_get_num(list_entry)) - return true; - if (udev_device_get_tags_list_entry(udev_device) != NULL) - return true; - if (udev_device_get_watch_handle(udev_device) >= 0) - return true; - return false; + struct udev_list_entry *list_entry; + + if (udev_device_get_devlinks_list_entry (udev_device) != NULL) + return true; + if (udev_device_get_devlink_priority (udev_device) != 0) + return true; + udev_list_entry_foreach (list_entry, + udev_device_get_properties_list_entry + (udev_device)) + if (udev_list_entry_get_num (list_entry)) + return true; + if (udev_device_get_tags_list_entry (udev_device) != NULL) + return true; + if (udev_device_get_watch_handle (udev_device) >= 0) + return true; + return false; } -int udev_device_update_db(struct udev_device *udev_device) +int +udev_device_update_db (struct udev_device *udev_device) { - bool has_info; - const char *id; - char filename[UTIL_PATH_SIZE]; - char filename_tmp[UTIL_PATH_SIZE]; - FILE *f; - int r; - - id = udev_device_get_id_filename(udev_device); - if (id == NULL) - return -1; - - has_info = device_has_info(udev_device); - strscpyl(filename, sizeof(filename), "/run/udev/data/", id, NULL); - - /* do not store anything for otherwise empty devices */ - if (!has_info && - major(udev_device_get_devnum(udev_device)) == 0 && - udev_device_get_ifindex(udev_device) == 0) { - unlink(filename); - return 0; - } - - /* write a database file */ - strscpyl(filename_tmp, sizeof(filename_tmp), filename, ".tmp", NULL); - mkdir_parents(filename_tmp, 0755); - f = fopen(filename_tmp, "we"); - if (f == NULL) { - int errsv = errno; - log_debug("unable to create temporary db file '%s': %s", - filename_tmp, strerror(errsv)); - return errsv; - } - - /* - * set 'sticky' bit to indicate that we should not clean the - * database when we transition from initramfs to the real root - */ - if (udev_device_get_db_persist(udev_device)) - fchmod(fileno(f), 01644); - - if (has_info) { - struct udev_list_entry *list_entry; - - if (major(udev_device_get_devnum(udev_device)) > 0) { - udev_list_entry_foreach(list_entry, - udev_device_get_devlinks_list_entry - (udev_device)) - fprintf(f, "S:%s\n", - udev_list_entry_get_name(list_entry) + - strlen("/dev/")); - if (udev_device_get_devlink_priority(udev_device) != 0) - fprintf(f, "L:%i\n", - udev_device_get_devlink_priority - (udev_device)); - if (udev_device_get_watch_handle(udev_device) >= 0) - fprintf(f, "W:%i\n", - udev_device_get_watch_handle - (udev_device)); - } - - if (udev_device_get_usec_initialized(udev_device) > 0) - fprintf(f, "I:" USEC_FMT "\n", - udev_device_get_usec_initialized(udev_device)); - - udev_list_entry_foreach(list_entry, - udev_device_get_properties_list_entry - (udev_device)) { - if (!udev_list_entry_get_num(list_entry)) - continue; - fprintf(f, "E:%s=%s\n", - udev_list_entry_get_name(list_entry), - udev_list_entry_get_value(list_entry)); - } - - udev_list_entry_foreach(list_entry, - udev_device_get_tags_list_entry - (udev_device)) - fprintf(f, "G:%s\n", udev_list_entry_get_name(list_entry)); + bool has_info; + const char *id; + char filename[UTIL_PATH_SIZE]; + char filename_tmp[UTIL_PATH_SIZE]; + FILE *f; + int r; + + id = udev_device_get_id_filename (udev_device); + if (id == NULL) + return -1; + + has_info = device_has_info (udev_device); + strscpyl (filename, sizeof (filename), "/run/udev/data/", id, NULL); + + /* do not store anything for otherwise empty devices */ + if (!has_info && + major (udev_device_get_devnum (udev_device)) == 0 && + udev_device_get_ifindex (udev_device) == 0) + { + unlink (filename); + return 0; + } + + /* write a database file */ + strscpyl (filename_tmp, sizeof (filename_tmp), filename, ".tmp", NULL); + mkdir_parents (filename_tmp, 0755); + f = fopen (filename_tmp, "we"); + if (f == NULL) + { + int errsv = errno; + log_debug ("unable to create temporary db file '%s': %s", + filename_tmp, strerror (errsv)); + return errsv; + } + + /* + * set 'sticky' bit to indicate that we should not clean the + * database when we transition from initramfs to the real root + */ + if (udev_device_get_db_persist (udev_device)) + fchmod (fileno (f), 01644); + + if (has_info) + { + struct udev_list_entry *list_entry; + + if (major (udev_device_get_devnum (udev_device)) > 0) + { + udev_list_entry_foreach (list_entry, + udev_device_get_devlinks_list_entry + (udev_device)) + fprintf (f, "S:%s\n", + udev_list_entry_get_name (list_entry) + + strlen ("/dev/")); + if (udev_device_get_devlink_priority (udev_device) != 0) + fprintf (f, "L:%i\n", + udev_device_get_devlink_priority (udev_device)); + if (udev_device_get_watch_handle (udev_device) >= 0) + fprintf (f, "W:%i\n", udev_device_get_watch_handle (udev_device)); } - fclose(f); - r = rename(filename_tmp, filename); - if (r < 0) - return -1; - log_debug("created %s file '%s' for '%s'", has_info ? "db" : "empty", - filename, udev_device_get_devpath(udev_device)); - return 0; + if (udev_device_get_usec_initialized (udev_device) > 0) + fprintf (f, "I:" USEC_FMT "\n", + udev_device_get_usec_initialized (udev_device)); + + udev_list_entry_foreach (list_entry, + udev_device_get_properties_list_entry + (udev_device)) + { + if (!udev_list_entry_get_num (list_entry)) + continue; + fprintf (f, "E:%s=%s\n", + udev_list_entry_get_name (list_entry), + udev_list_entry_get_value (list_entry)); + } + + udev_list_entry_foreach (list_entry, + udev_device_get_tags_list_entry + (udev_device)) + fprintf (f, "G:%s\n", udev_list_entry_get_name (list_entry)); + } + + fclose (f); + r = rename (filename_tmp, filename); + if (r < 0) + return -1; + log_debug ("created %s file '%s' for '%s'", has_info ? "db" : "empty", + filename, udev_device_get_devpath (udev_device)); + return 0; } -int udev_device_delete_db(struct udev_device *udev_device) +int +udev_device_delete_db (struct udev_device *udev_device) { - const char *id; - char filename[UTIL_PATH_SIZE]; + const char *id; + char filename[UTIL_PATH_SIZE]; - id = udev_device_get_id_filename(udev_device); - if (id == NULL) - return -1; - strscpyl(filename, sizeof(filename), "/run/udev/data/", id, NULL); + id = udev_device_get_id_filename (udev_device); + if (id == NULL) + return -1; + strscpyl (filename, sizeof (filename), "/run/udev/data/", id, NULL); - unlink(filename); - return 0; + unlink (filename); + return 0; } diff --git a/libudev-compat/libudev-device.c b/libudev-compat/libudev-device.c index 2e7f067..a848351 100644 --- a/libudev-compat/libudev-device.c +++ b/libudev-compat/libudev-device.c @@ -47,17 +47,17 @@ #include "libudev.h" #include "libudev-private.h" -static int udev_device_read_uevent_file(struct udev_device *udev_device); -static int udev_device_read_db(struct udev_device *udev_device); -static int udev_device_set_devnode(struct udev_device *udev_device, - const char *devnode); -static struct udev_list_entry *udev_device_add_property_internal(struct - udev_device - *udev_device, - const char - *key, - const char - *value); +static int udev_device_read_uevent_file (struct udev_device *udev_device); +static int udev_device_read_db (struct udev_device *udev_device); +static int udev_device_set_devnode (struct udev_device *udev_device, + const char *devnode); +static struct udev_list_entry *udev_device_add_property_internal (struct + udev_device + *udev_device, + const char + *key, + const char + *value); /** * SECTION:libudev-device @@ -74,52 +74,53 @@ static struct udev_list_entry *udev_device_add_property_internal(struct * * Opaque object representing one kernel sys device. */ -struct udev_device { - struct udev *udev; - struct udev_device *parent_device; - char *syspath; - const char *devpath; - char *sysname; - const char *sysnum; - char *devnode; - mode_t devnode_mode; - uid_t devnode_uid; - gid_t devnode_gid; - char *subsystem; - char *devtype; - char *driver; - char *action; - char *devpath_old; - char *id_filename; - char **envp; - char *monitor_buf; - size_t monitor_buf_len; - struct udev_list devlinks_list; - struct udev_list properties_list; - struct udev_list sysattr_value_list; - struct udev_list sysattr_list; - struct udev_list tags_list; - unsigned long long int seqnum; - usec_t usec_initialized; - int devlink_priority; - int refcount; - dev_t devnum; - int ifindex; - int watch_handle; - int maj, min; - bool parent_set; - bool subsystem_set; - bool devtype_set; - bool devlinks_uptodate; - bool envp_uptodate; - bool tags_uptodate; - bool driver_set; - bool info_loaded; - bool db_loaded; - bool uevent_loaded; - bool is_initialized; - bool sysattr_list_read; - bool db_persist; +struct udev_device +{ + struct udev *udev; + struct udev_device *parent_device; + char *syspath; + const char *devpath; + char *sysname; + const char *sysnum; + char *devnode; + mode_t devnode_mode; + uid_t devnode_uid; + gid_t devnode_gid; + char *subsystem; + char *devtype; + char *driver; + char *action; + char *devpath_old; + char *id_filename; + char **envp; + char *monitor_buf; + size_t monitor_buf_len; + struct udev_list devlinks_list; + struct udev_list properties_list; + struct udev_list sysattr_value_list; + struct udev_list sysattr_list; + struct udev_list tags_list; + unsigned long long int seqnum; + usec_t usec_initialized; + int devlink_priority; + int refcount; + dev_t devnum; + int ifindex; + int watch_handle; + int maj, min; + bool parent_set; + bool subsystem_set; + bool devtype_set; + bool devlinks_uptodate; + bool envp_uptodate; + bool tags_uptodate; + bool driver_set; + bool info_loaded; + bool db_loaded; + bool uevent_loaded; + bool is_initialized; + bool sysattr_list_read; + bool db_persist; }; /** @@ -131,39 +132,43 @@ struct udev_device { * * Returns: the kernel event sequence number, or 0 if there is no sequence number available. **/ -unsigned long long int udev_device_get_seqnum(struct udev_device *udev_device) +unsigned long long int +udev_device_get_seqnum (struct udev_device *udev_device) { - if (udev_device == NULL) - return 0; - return udev_device->seqnum; + if (udev_device == NULL) + return 0; + return udev_device->seqnum; } -static int udev_device_set_seqnum(struct udev_device *udev_device, - unsigned long long int seqnum) +static int +udev_device_set_seqnum (struct udev_device *udev_device, + unsigned long long int seqnum) { - char num[32]; + char num[32]; - udev_device->seqnum = seqnum; - snprintf(num, sizeof(num), "%llu", seqnum); - udev_device_add_property_internal(udev_device, "SEQNUM", num); - return 0; + udev_device->seqnum = seqnum; + snprintf (num, sizeof (num), "%llu", seqnum); + udev_device_add_property_internal (udev_device, "SEQNUM", num); + return 0; } -int udev_device_get_ifindex(struct udev_device *udev_device) +int +udev_device_get_ifindex (struct udev_device *udev_device) { - if (!udev_device->info_loaded) - udev_device_read_uevent_file(udev_device); - return udev_device->ifindex; + if (!udev_device->info_loaded) + udev_device_read_uevent_file (udev_device); + return udev_device->ifindex; } -static int udev_device_set_ifindex(struct udev_device *udev_device, int ifindex) +static int +udev_device_set_ifindex (struct udev_device *udev_device, int ifindex) { - char num[32]; + char num[32]; - udev_device->ifindex = ifindex; - snprintf(num, sizeof(num), "%d", ifindex); - udev_device_add_property_internal(udev_device, "IFINDEX", num); - return 0; + udev_device->ifindex = ifindex; + snprintf (num, sizeof (num), "%d", ifindex); + udev_device_add_property_internal (udev_device, "IFINDEX", num); + return 0; } /** @@ -174,49 +179,53 @@ static int udev_device_set_ifindex(struct udev_device *udev_device, int ifindex) * * Returns: the dev_t number. **/ -dev_t udev_device_get_devnum(struct udev_device * udev_device) +dev_t +udev_device_get_devnum (struct udev_device * udev_device) { - if (udev_device == NULL) - return makedev(0, 0); - if (!udev_device->info_loaded) - udev_device_read_uevent_file(udev_device); - return udev_device->devnum; + if (udev_device == NULL) + return makedev (0, 0); + if (!udev_device->info_loaded) + udev_device_read_uevent_file (udev_device); + return udev_device->devnum; } -static int udev_device_set_devnum(struct udev_device *udev_device, dev_t devnum) +static int +udev_device_set_devnum (struct udev_device *udev_device, dev_t devnum) { - char num[32]; + char num[32]; - udev_device->devnum = devnum; + udev_device->devnum = devnum; - snprintf(num, sizeof(num), "%u", major(devnum)); - udev_device_add_property_internal(udev_device, "MAJOR", num); - snprintf(num, sizeof(num), "%u", minor(devnum)); - udev_device_add_property_internal(udev_device, "MINOR", num); - return 0; + snprintf (num, sizeof (num), "%u", major (devnum)); + udev_device_add_property_internal (udev_device, "MAJOR", num); + snprintf (num, sizeof (num), "%u", minor (devnum)); + udev_device_add_property_internal (udev_device, "MINOR", num); + return 0; } -const char *udev_device_get_devpath_old(struct udev_device *udev_device) +const char * +udev_device_get_devpath_old (struct udev_device *udev_device) { - return udev_device->devpath_old; + return udev_device->devpath_old; } -static int udev_device_set_devpath_old(struct udev_device *udev_device, - const char *devpath_old) +static int +udev_device_set_devpath_old (struct udev_device *udev_device, + const char *devpath_old) { - const char *pos; + const char *pos; - free(udev_device->devpath_old); - udev_device->devpath_old = strdup(devpath_old); - if (udev_device->devpath_old == NULL) - return -ENOMEM; - udev_device_add_property_internal(udev_device, "DEVPATH_OLD", - udev_device->devpath_old); + free (udev_device->devpath_old); + udev_device->devpath_old = strdup (devpath_old); + if (udev_device->devpath_old == NULL) + return -ENOMEM; + udev_device_add_property_internal (udev_device, "DEVPATH_OLD", + udev_device->devpath_old); - pos = strrchr(udev_device->devpath_old, '/'); - if (pos == NULL) - return -EINVAL; - return 0; + pos = strrchr (udev_device->devpath_old, '/'); + if (pos == NULL) + return -EINVAL; + return 0; } /** @@ -227,33 +236,35 @@ static int udev_device_set_devpath_old(struct udev_device *udev_device, * * Returns: the driver name string, or #NULL if there is no driver attached. **/ -const char *udev_device_get_driver(struct udev_device *udev_device) -{ - char driver[UTIL_NAME_SIZE]; - - if (udev_device == NULL) - return NULL; - if (!udev_device->driver_set) { - udev_device->driver_set = true; - if (util_get_sys_core_link_value - (udev_device->udev, "driver", udev_device->syspath, driver, - sizeof(driver)) > 0) - udev_device->driver = strdup(driver); - } - return udev_device->driver; +const char * +udev_device_get_driver (struct udev_device *udev_device) +{ + char driver[UTIL_NAME_SIZE]; + + if (udev_device == NULL) + return NULL; + if (!udev_device->driver_set) + { + udev_device->driver_set = true; + if (util_get_sys_core_link_value + (udev_device->udev, "driver", udev_device->syspath, driver, + sizeof (driver)) > 0) + udev_device->driver = strdup (driver); + } + return udev_device->driver; } -static int udev_device_set_driver(struct udev_device *udev_device, - const char *driver) +static int +udev_device_set_driver (struct udev_device *udev_device, const char *driver) { - free(udev_device->driver); - udev_device->driver = strdup(driver); - if (udev_device->driver == NULL) - return -ENOMEM; - udev_device->driver_set = true; - udev_device_add_property_internal(udev_device, "DRIVER", - udev_device->driver); - return 0; + free (udev_device->driver); + udev_device->driver = strdup (driver); + if (udev_device->driver == NULL) + return -ENOMEM; + udev_device->driver_set = true; + udev_device_add_property_internal (udev_device, "DRIVER", + udev_device->driver); + return 0; } /** @@ -264,41 +275,44 @@ static int udev_device_set_driver(struct udev_device *udev_device, * * Returns: the devtype name of the udev device, or #NULL if it can not be determined **/ -const char *udev_device_get_devtype(struct udev_device *udev_device) -{ - if (udev_device == NULL) - return NULL; - if (!udev_device->devtype_set) { - udev_device->devtype_set = true; - udev_device_read_uevent_file(udev_device); - } - return udev_device->devtype; -} - -static int udev_device_set_devtype(struct udev_device *udev_device, - const char *devtype) -{ - free(udev_device->devtype); - udev_device->devtype = strdup(devtype); - if (udev_device->devtype == NULL) - return -ENOMEM; - udev_device->devtype_set = true; - udev_device_add_property_internal(udev_device, "DEVTYPE", - udev_device->devtype); - return 0; -} - -static int udev_device_set_subsystem(struct udev_device *udev_device, - const char *subsystem) -{ - free(udev_device->subsystem); - udev_device->subsystem = strdup(subsystem); - if (udev_device->subsystem == NULL) - return -ENOMEM; - udev_device->subsystem_set = true; - udev_device_add_property_internal(udev_device, "SUBSYSTEM", - udev_device->subsystem); - return 0; +const char * +udev_device_get_devtype (struct udev_device *udev_device) +{ + if (udev_device == NULL) + return NULL; + if (!udev_device->devtype_set) + { + udev_device->devtype_set = true; + udev_device_read_uevent_file (udev_device); + } + return udev_device->devtype; +} + +static int +udev_device_set_devtype (struct udev_device *udev_device, const char *devtype) +{ + free (udev_device->devtype); + udev_device->devtype = strdup (devtype); + if (udev_device->devtype == NULL) + return -ENOMEM; + udev_device->devtype_set = true; + udev_device_add_property_internal (udev_device, "DEVTYPE", + udev_device->devtype); + return 0; +} + +static int +udev_device_set_subsystem (struct udev_device *udev_device, + const char *subsystem) +{ + free (udev_device->subsystem); + udev_device->subsystem = strdup (subsystem); + if (udev_device->subsystem == NULL) + return -ENOMEM; + udev_device->subsystem_set = true; + udev_device_add_property_internal (udev_device, "SUBSYSTEM", + udev_device->subsystem); + return 0; } /** @@ -310,220 +324,230 @@ static int udev_device_set_subsystem(struct udev_device *udev_device, * * Returns: the subsystem name of the udev device, or #NULL if it can not be determined **/ -const char *udev_device_get_subsystem(struct udev_device *udev_device) -{ - char subsystem[UTIL_NAME_SIZE]; - - if (udev_device == NULL) - return NULL; - if (!udev_device->subsystem_set) { - udev_device->subsystem_set = true; - /* read "subsystem" link */ - if (util_get_sys_core_link_value - (udev_device->udev, "subsystem", udev_device->syspath, - subsystem, sizeof(subsystem)) > 0) { - udev_device_set_subsystem(udev_device, subsystem); - return udev_device->subsystem; - } - /* implicit names */ - if (startswith(udev_device->devpath, "/module/")) { - udev_device_set_subsystem(udev_device, "module"); - return udev_device->subsystem; - } - if (strstr(udev_device->devpath, "/drivers/") != NULL) { - udev_device_set_subsystem(udev_device, "drivers"); - return udev_device->subsystem; - } - if (startswith(udev_device->devpath, "/subsystem/") || - startswith(udev_device->devpath, "/class/") || - startswith(udev_device->devpath, "/bus/")) { - udev_device_set_subsystem(udev_device, "subsystem"); - return udev_device->subsystem; - } +const char * +udev_device_get_subsystem (struct udev_device *udev_device) +{ + char subsystem[UTIL_NAME_SIZE]; + + if (udev_device == NULL) + return NULL; + if (!udev_device->subsystem_set) + { + udev_device->subsystem_set = true; + /* read "subsystem" link */ + if (util_get_sys_core_link_value + (udev_device->udev, "subsystem", udev_device->syspath, + subsystem, sizeof (subsystem)) > 0) + { + udev_device_set_subsystem (udev_device, subsystem); + return udev_device->subsystem; + } + /* implicit names */ + if (startswith (udev_device->devpath, "/module/")) + { + udev_device_set_subsystem (udev_device, "module"); + return udev_device->subsystem; } - return udev_device->subsystem; + if (strstr (udev_device->devpath, "/drivers/") != NULL) + { + udev_device_set_subsystem (udev_device, "drivers"); + return udev_device->subsystem; + } + if (startswith (udev_device->devpath, "/subsystem/") || + startswith (udev_device->devpath, "/class/") || + startswith (udev_device->devpath, "/bus/")) + { + udev_device_set_subsystem (udev_device, "subsystem"); + return udev_device->subsystem; + } + } + return udev_device->subsystem; } -mode_t udev_device_get_devnode_mode(struct udev_device * udev_device) +mode_t +udev_device_get_devnode_mode (struct udev_device * udev_device) { - if (!udev_device->info_loaded) - udev_device_read_uevent_file(udev_device); - return udev_device->devnode_mode; + if (!udev_device->info_loaded) + udev_device_read_uevent_file (udev_device); + return udev_device->devnode_mode; } -static int udev_device_set_devnode_mode(struct udev_device *udev_device, - mode_t mode) +static int +udev_device_set_devnode_mode (struct udev_device *udev_device, mode_t mode) { - char num[32]; + char num[32]; - udev_device->devnode_mode = mode; - snprintf(num, sizeof(num), "%#o", mode); - udev_device_add_property_internal(udev_device, "DEVMODE", num); - return 0; + udev_device->devnode_mode = mode; + snprintf (num, sizeof (num), "%#o", mode); + udev_device_add_property_internal (udev_device, "DEVMODE", num); + return 0; } -uid_t udev_device_get_devnode_uid(struct udev_device * udev_device) +uid_t +udev_device_get_devnode_uid (struct udev_device * udev_device) { - if (!udev_device->info_loaded) - udev_device_read_uevent_file(udev_device); - return udev_device->devnode_uid; + if (!udev_device->info_loaded) + udev_device_read_uevent_file (udev_device); + return udev_device->devnode_uid; } -static int udev_device_set_devnode_uid(struct udev_device *udev_device, - uid_t uid) +static int +udev_device_set_devnode_uid (struct udev_device *udev_device, uid_t uid) { - char num[32]; + char num[32]; - udev_device->devnode_uid = uid; - snprintf(num, sizeof(num), "%u", uid); - udev_device_add_property_internal(udev_device, "DEVUID", num); - return 0; + udev_device->devnode_uid = uid; + snprintf (num, sizeof (num), "%u", uid); + udev_device_add_property_internal (udev_device, "DEVUID", num); + return 0; } -gid_t udev_device_get_devnode_gid(struct udev_device * udev_device) +gid_t +udev_device_get_devnode_gid (struct udev_device * udev_device) { - if (!udev_device->info_loaded) - udev_device_read_uevent_file(udev_device); - return udev_device->devnode_gid; + if (!udev_device->info_loaded) + udev_device_read_uevent_file (udev_device); + return udev_device->devnode_gid; } -static int udev_device_set_devnode_gid(struct udev_device *udev_device, - gid_t gid) +static int +udev_device_set_devnode_gid (struct udev_device *udev_device, gid_t gid) { - char num[32]; + char num[32]; - udev_device->devnode_gid = gid; - snprintf(num, sizeof(num), "%u", gid); - udev_device_add_property_internal(udev_device, "DEVGID", num); - return 0; + udev_device->devnode_gid = gid; + snprintf (num, sizeof (num), "%u", gid); + udev_device_add_property_internal (udev_device, "DEVGID", num); + return 0; } -static struct udev_list_entry *udev_device_add_property_internal(struct - udev_device - *udev_device, - const char - *key, - const char - *value) +static struct udev_list_entry * +udev_device_add_property_internal (struct + udev_device + *udev_device, + const char *key, const char *value) { - udev_device->envp_uptodate = false; - if (value == NULL) { - struct udev_list_entry *list_entry; + udev_device->envp_uptodate = false; + if (value == NULL) + { + struct udev_list_entry *list_entry; - list_entry = udev_device_get_properties_list_entry(udev_device); - list_entry = udev_list_entry_get_by_name(list_entry, key); - if (list_entry != NULL) - udev_list_entry_delete(list_entry); - return NULL; - } - return udev_list_entry_add(&udev_device->properties_list, key, value); + list_entry = udev_device_get_properties_list_entry (udev_device); + list_entry = udev_list_entry_get_by_name (list_entry, key); + if (list_entry != NULL) + udev_list_entry_delete (list_entry); + return NULL; + } + return udev_list_entry_add (&udev_device->properties_list, key, value); } -int udev_device_add_property(struct udev_device *udev_device, const char *key, - const char *value) +int +udev_device_add_property (struct udev_device *udev_device, const char *key, + const char *value) { - struct udev_list_entry *property; + struct udev_list_entry *property; - property = udev_device_add_property_internal(udev_device, key, value); + property = udev_device_add_property_internal (udev_device, key, value); - /* store in db, skip private keys */ - if (key[0] != '.') - udev_list_entry_set_num(property, true); + /* store in db, skip private keys */ + if (key[0] != '.') + udev_list_entry_set_num (property, true); - return 0; + return 0; } -static struct udev_list_entry *udev_device_add_property_from_string(struct - udev_device - *udev_device, - const char - *property) +static struct udev_list_entry * +udev_device_add_property_from_string (struct + udev_device + *udev_device, const char *property) { - char name[UTIL_LINE_SIZE]; - char *val; + char name[UTIL_LINE_SIZE]; + char *val; - strscpy(name, sizeof(name), property); - val = strchr(name, '='); - if (val == NULL) - return NULL; - val[0] = '\0'; - val = &val[1]; - if (val[0] == '\0') - val = NULL; - return udev_device_add_property_internal(udev_device, name, val); + strscpy (name, sizeof (name), property); + val = strchr (name, '='); + if (val == NULL) + return NULL; + val[0] = '\0'; + val = &val[1]; + if (val[0] == '\0') + val = NULL; + return udev_device_add_property_internal (udev_device, name, val); } -static int udev_device_set_syspath(struct udev_device *udev_device, - const char *syspath) +static int +udev_device_set_syspath (struct udev_device *udev_device, const char *syspath) { - const char *pos; - size_t len; + const char *pos; + size_t len; - free(udev_device->syspath); - udev_device->syspath = strdup(syspath); - if (udev_device->syspath == NULL) - return -ENOMEM; - udev_device->devpath = udev_device->syspath + strlen("/sys"); - udev_device_add_property_internal(udev_device, "DEVPATH", - udev_device->devpath); + free (udev_device->syspath); + udev_device->syspath = strdup (syspath); + if (udev_device->syspath == NULL) + return -ENOMEM; + udev_device->devpath = udev_device->syspath + strlen ("/sys"); + udev_device_add_property_internal (udev_device, "DEVPATH", + udev_device->devpath); - pos = strrchr(udev_device->syspath, '/'); - if (pos == NULL) - return -EINVAL; - udev_device->sysname = strdup(&pos[1]); - if (udev_device->sysname == NULL) - return -ENOMEM; + pos = strrchr (udev_device->syspath, '/'); + if (pos == NULL) + return -EINVAL; + udev_device->sysname = strdup (&pos[1]); + if (udev_device->sysname == NULL) + return -ENOMEM; - /* some devices have '!' in their name, change that to '/' */ - len = 0; - while (udev_device->sysname[len] != '\0') { - if (udev_device->sysname[len] == '!') - udev_device->sysname[len] = '/'; - len++; - } + /* some devices have '!' in their name, change that to '/' */ + len = 0; + while (udev_device->sysname[len] != '\0') + { + if (udev_device->sysname[len] == '!') + udev_device->sysname[len] = '/'; + len++; + } - /* trailing number */ - while (len > 0 && isdigit(udev_device->sysname[--len])) - udev_device->sysnum = &udev_device->sysname[len]; + /* trailing number */ + while (len > 0 && isdigit (udev_device->sysname[--len])) + udev_device->sysnum = &udev_device->sysname[len]; - /* sysname is completely numeric */ - if (len == 0) - udev_device->sysnum = NULL; + /* sysname is completely numeric */ + if (len == 0) + udev_device->sysnum = NULL; - return 0; + return 0; } -static void udev_device_set_usec_initialized(struct udev_device *udev_device, - usec_t usec_initialized) +static void +udev_device_set_usec_initialized (struct udev_device *udev_device, + usec_t usec_initialized) { - char num[DECIMAL_STR_MAX(usec_t)]; + char num[DECIMAL_STR_MAX (usec_t)]; - udev_device->usec_initialized = usec_initialized; - snprintf(num, sizeof(num), USEC_FMT, usec_initialized); - udev_device_add_property_internal(udev_device, "USEC_INITIALIZED", num); + udev_device->usec_initialized = usec_initialized; + snprintf (num, sizeof (num), USEC_FMT, usec_initialized); + udev_device_add_property_internal (udev_device, "USEC_INITIALIZED", num); } -void udev_device_ensure_usec_initialized(struct udev_device *udev_device, - struct udev_device *old_device) +void +udev_device_ensure_usec_initialized (struct udev_device *udev_device, + struct udev_device *old_device) { - if (old_device && old_device->usec_initialized != 0) - udev_device_set_usec_initialized(udev_device, - old_device->usec_initialized); - else - udev_device_set_usec_initialized(udev_device, - now(CLOCK_MONOTONIC)); + if (old_device && old_device->usec_initialized != 0) + udev_device_set_usec_initialized (udev_device, + old_device->usec_initialized); + else + udev_device_set_usec_initialized (udev_device, now (CLOCK_MONOTONIC)); } -static int udev_device_set_action(struct udev_device *udev_device, - const char *action) +static int +udev_device_set_action (struct udev_device *udev_device, const char *action) { - free(udev_device->action); - udev_device->action = strdup(action); - if (udev_device->action == NULL) - return -ENOMEM; - udev_device_add_property_internal(udev_device, "ACTION", - udev_device->action); - return 0; + free (udev_device->action); + udev_device->action = strdup (action); + if (udev_device->action == NULL) + return -ENOMEM; + udev_device_add_property_internal (udev_device, "ACTION", + udev_device->action); + return 0; } /* @@ -553,104 +577,141 @@ static int udev_device_set_action(struct udev_device *udev_device, * DEVUID=(device node UID???) * DEVGID=(device node GID???) */ -static void udev_device_add_property_from_string_parse(struct udev_device - *udev_device, - const char *property) -{ - if (startswith(property, "DEVPATH=")) { - char path[UTIL_PATH_SIZE]; - - strscpyl(path, sizeof(path), "/sys", &property[8], NULL); - udev_device_set_syspath(udev_device, path); - } else if (startswith(property, "SUBSYSTEM=")) { - udev_device_set_subsystem(udev_device, &property[10]); - } else if (startswith(property, "DEVTYPE=")) { - udev_device_set_devtype(udev_device, &property[8]); - } else if (startswith(property, "DEVNAME=")) { - udev_device_set_devnode(udev_device, &property[8]); - } else if (startswith(property, "DEVLINKS=")) { - char devlinks[UTIL_PATH_SIZE]; - char *slink; - char *next; - - strscpy(devlinks, sizeof(devlinks), &property[9]); - slink = devlinks; - next = strchr(slink, ' '); - while (next != NULL) { - next[0] = '\0'; - udev_device_add_devlink(udev_device, slink); - slink = &next[1]; - next = strchr(slink, ' '); - } - if (slink[0] != '\0') - udev_device_add_devlink(udev_device, slink); - } else if (startswith(property, "TAGS=")) { - char tags[UTIL_PATH_SIZE]; - char *next; - - strscpy(tags, sizeof(tags), &property[5]); - next = strchr(tags, ':'); - if (next != NULL) { - next++; - while (next[0] != '\0') { - char *tag; - - tag = next; - next = strchr(tag, ':'); - if (next == NULL) - break; - next[0] = '\0'; - next++; - udev_device_add_tag(udev_device, tag); - } - } - } else if (startswith(property, "USEC_INITIALIZED=")) { - udev_device_set_usec_initialized(udev_device, - strtoull(&property[19], NULL, - 10)); - } else if (startswith(property, "DRIVER=")) { - udev_device_set_driver(udev_device, &property[7]); - } else if (startswith(property, "ACTION=")) { - udev_device_set_action(udev_device, &property[7]); - } else if (startswith(property, "MAJOR=")) { - udev_device->maj = strtoull(&property[6], NULL, 10); - } else if (startswith(property, "MINOR=")) { - udev_device->min = strtoull(&property[6], NULL, 10); - } else if (startswith(property, "DEVPATH_OLD=")) { - udev_device_set_devpath_old(udev_device, &property[12]); - } else if (startswith(property, "SEQNUM=")) { - udev_device_set_seqnum(udev_device, - strtoull(&property[7], NULL, 10)); - } else if (startswith(property, "IFINDEX=")) { - udev_device_set_ifindex(udev_device, - strtoull(&property[8], NULL, 10)); - } else if (startswith(property, "DEVMODE=")) { - udev_device_set_devnode_mode(udev_device, - strtoul(&property[8], NULL, 8)); - } else if (startswith(property, "DEVUID=")) { - udev_device_set_devnode_uid(udev_device, - strtoul(&property[7], NULL, 10)); - } else if (startswith(property, "DEVGID=")) { - udev_device_set_devnode_gid(udev_device, - strtoul(&property[7], NULL, 10)); - } else { - udev_device_add_property_from_string(udev_device, property); +static void +udev_device_add_property_from_string_parse (struct udev_device + *udev_device, + const char *property) +{ + if (startswith (property, "DEVPATH=")) + { + char path[UTIL_PATH_SIZE]; + + strscpyl (path, sizeof (path), "/sys", &property[8], NULL); + udev_device_set_syspath (udev_device, path); + } + else if (startswith (property, "SUBSYSTEM=")) + { + udev_device_set_subsystem (udev_device, &property[10]); + } + else if (startswith (property, "DEVTYPE=")) + { + udev_device_set_devtype (udev_device, &property[8]); + } + else if (startswith (property, "DEVNAME=")) + { + udev_device_set_devnode (udev_device, &property[8]); + } + else if (startswith (property, "DEVLINKS=")) + { + char devlinks[UTIL_PATH_SIZE]; + char *slink; + char *next; + + strscpy (devlinks, sizeof (devlinks), &property[9]); + slink = devlinks; + next = strchr (slink, ' '); + while (next != NULL) + { + next[0] = '\0'; + udev_device_add_devlink (udev_device, slink); + slink = &next[1]; + next = strchr (slink, ' '); } -} - -static int udev_device_add_property_from_string_parse_finish(struct udev_device - *udev_device) -{ - if (udev_device->maj > 0) - udev_device_set_devnum(udev_device, - makedev(udev_device->maj, - udev_device->min)); - udev_device->maj = 0; - udev_device->min = 0; - - if (udev_device->devpath == NULL || udev_device->subsystem == NULL) - return -EINVAL; - return 0; + if (slink[0] != '\0') + udev_device_add_devlink (udev_device, slink); + } + else if (startswith (property, "TAGS=")) + { + char tags[UTIL_PATH_SIZE]; + char *next; + + strscpy (tags, sizeof (tags), &property[5]); + next = strchr (tags, ':'); + if (next != NULL) + { + next++; + while (next[0] != '\0') + { + char *tag; + + tag = next; + next = strchr (tag, ':'); + if (next == NULL) + break; + next[0] = '\0'; + next++; + udev_device_add_tag (udev_device, tag); + } + } + } + else if (startswith (property, "USEC_INITIALIZED=")) + { + udev_device_set_usec_initialized (udev_device, + strtoull (&property[19], NULL, 10)); + } + else if (startswith (property, "DRIVER=")) + { + udev_device_set_driver (udev_device, &property[7]); + } + else if (startswith (property, "ACTION=")) + { + udev_device_set_action (udev_device, &property[7]); + } + else if (startswith (property, "MAJOR=")) + { + udev_device->maj = strtoull (&property[6], NULL, 10); + } + else if (startswith (property, "MINOR=")) + { + udev_device->min = strtoull (&property[6], NULL, 10); + } + else if (startswith (property, "DEVPATH_OLD=")) + { + udev_device_set_devpath_old (udev_device, &property[12]); + } + else if (startswith (property, "SEQNUM=")) + { + udev_device_set_seqnum (udev_device, strtoull (&property[7], NULL, 10)); + } + else if (startswith (property, "IFINDEX=")) + { + udev_device_set_ifindex (udev_device, + strtoull (&property[8], NULL, 10)); + } + else if (startswith (property, "DEVMODE=")) + { + udev_device_set_devnode_mode (udev_device, + strtoul (&property[8], NULL, 8)); + } + else if (startswith (property, "DEVUID=")) + { + udev_device_set_devnode_uid (udev_device, + strtoul (&property[7], NULL, 10)); + } + else if (startswith (property, "DEVGID=")) + { + udev_device_set_devnode_gid (udev_device, + strtoul (&property[7], NULL, 10)); + } + else + { + udev_device_add_property_from_string (udev_device, property); + } +} + +static int +udev_device_add_property_from_string_parse_finish (struct udev_device + *udev_device) +{ + if (udev_device->maj > 0) + udev_device_set_devnum (udev_device, + makedev (udev_device->maj, udev_device->min)); + udev_device->maj = 0; + udev_device->min = 0; + + if (udev_device->devpath == NULL || udev_device->subsystem == NULL) + return -EINVAL; + return 0; } /** @@ -662,179 +723,187 @@ static int udev_device_add_property_from_string_parse_finish(struct udev_device * * Returns: the property string, or #NULL if there is no such property. **/ -const char *udev_device_get_property_value(struct udev_device *udev_device, - const char *key) -{ - struct udev_list_entry *list_entry; - - if (udev_device == NULL) - return NULL; - if (key == NULL) - return NULL; +const char * +udev_device_get_property_value (struct udev_device *udev_device, + const char *key) +{ + struct udev_list_entry *list_entry; + + if (udev_device == NULL) + return NULL; + if (key == NULL) + return NULL; + + list_entry = udev_device_get_properties_list_entry (udev_device); + list_entry = udev_list_entry_get_by_name (list_entry, key); + return udev_list_entry_get_value (list_entry); +} + +static int +udev_device_read_db (struct udev_device *udev_device) +{ + char filename[UTIL_PATH_SIZE]; + char line[UTIL_LINE_SIZE]; + const char *id; + FILE *f; + + if (udev_device->db_loaded) + return 0; + + udev_device->db_loaded = true; + + id = udev_device_get_id_filename (udev_device); + if (id == NULL) + return -1; + + strscpyl (filename, sizeof (filename), "/run/udev/data/", id, NULL); + + f = fopen (filename, "re"); + if (f == NULL) + { + int errsv = errno; + log_debug ("no db file to read %s: %s", filename, strerror (errsv)); + return errsv; + } + + /* devices with a database entry are initialized */ + udev_device->is_initialized = true; + + while (fgets (line, sizeof (line), f)) + { + ssize_t len; + const char *val; + struct udev_list_entry *entry; + + len = strlen (line); + if (len < 4) + break; + line[len - 1] = '\0'; + val = &line[2]; + switch (line[0]) + { + case 'S': + strscpyl (filename, sizeof (filename), "/dev/", val, NULL); + udev_device_add_devlink (udev_device, filename); + break; + case 'L': + udev_device_set_devlink_priority (udev_device, atoi (val)); + break; + case 'E': + entry = udev_device_add_property_from_string (udev_device, val); + udev_list_entry_set_num (entry, true); + break; + case 'G': + udev_device_add_tag (udev_device, val); + break; + case 'W': + udev_device_set_watch_handle (udev_device, atoi (val)); + break; + case 'I': + udev_device_set_usec_initialized (udev_device, + strtoull (val, NULL, 10)); + break; + } + } + fclose (f); - list_entry = udev_device_get_properties_list_entry(udev_device); - list_entry = udev_list_entry_get_by_name(list_entry, key); - return udev_list_entry_get_value(list_entry); + log_trace ("device %p filled with db file data", udev_device); + return 0; } -static int udev_device_read_db(struct udev_device *udev_device) +static int +udev_device_read_uevent_file (struct udev_device *udev_device) { - char filename[UTIL_PATH_SIZE]; - char line[UTIL_LINE_SIZE]; - const char *id; - FILE *f; + char filename[UTIL_PATH_SIZE]; + FILE *f; + char line[UTIL_LINE_SIZE]; + int maj = 0; + int min = 0; - if (udev_device->db_loaded) - return 0; + if (udev_device->uevent_loaded) + return 0; - udev_device->db_loaded = true; + strscpyl (filename, sizeof (filename), udev_device->syspath, "/uevent", + NULL); + f = fopen (filename, "re"); + if (f == NULL) + return -errno; + udev_device->uevent_loaded = true; - id = udev_device_get_id_filename(udev_device); - if (id == NULL) - return -1; + while (fgets (line, sizeof (line), f)) + { + char *pos; - strscpyl(filename, sizeof(filename), "/run/udev/data/", id, NULL); + pos = strchr (line, '\n'); + if (pos == NULL) + continue; + pos[0] = '\0'; - f = fopen(filename, "re"); - if (f == NULL) { - int errsv = errno; - log_debug("no db file to read %s: %s", filename, - strerror(errsv)); - return errsv; + if (startswith (line, "DEVTYPE=")) + { + udev_device_set_devtype (udev_device, &line[8]); + continue; } - - /* devices with a database entry are initialized */ - udev_device->is_initialized = true; - - while (fgets(line, sizeof(line), f)) { - ssize_t len; - const char *val; - struct udev_list_entry *entry; - - len = strlen(line); - if (len < 4) - break; - line[len - 1] = '\0'; - val = &line[2]; - switch (line[0]) { - case 'S': - strscpyl(filename, sizeof(filename), "/dev/", val, - NULL); - udev_device_add_devlink(udev_device, filename); - break; - case 'L': - udev_device_set_devlink_priority(udev_device, - atoi(val)); - break; - case 'E': - entry = - udev_device_add_property_from_string(udev_device, - val); - udev_list_entry_set_num(entry, true); - break; - case 'G': - udev_device_add_tag(udev_device, val); - break; - case 'W': - udev_device_set_watch_handle(udev_device, atoi(val)); - break; - case 'I': - udev_device_set_usec_initialized(udev_device, - strtoull(val, NULL, - 10)); - break; - } + if (startswith (line, "IFINDEX=")) + { + udev_device_set_ifindex (udev_device, + strtoull (&line[8], NULL, 10)); + continue; } - fclose(f); - - log_trace("device %p filled with db file data", udev_device); - return 0; -} - -static int udev_device_read_uevent_file(struct udev_device *udev_device) -{ - char filename[UTIL_PATH_SIZE]; - FILE *f; - char line[UTIL_LINE_SIZE]; - int maj = 0; - int min = 0; - - if (udev_device->uevent_loaded) - return 0; - - strscpyl(filename, sizeof(filename), udev_device->syspath, "/uevent", - NULL); - f = fopen(filename, "re"); - if (f == NULL) - return -errno; - udev_device->uevent_loaded = true; - - while (fgets(line, sizeof(line), f)) { - char *pos; - - pos = strchr(line, '\n'); - if (pos == NULL) - continue; - pos[0] = '\0'; - - if (startswith(line, "DEVTYPE=")) { - udev_device_set_devtype(udev_device, &line[8]); - continue; - } - if (startswith(line, "IFINDEX=")) { - udev_device_set_ifindex(udev_device, - strtoull(&line[8], NULL, 10)); - continue; - } - if (startswith(line, "DEVNAME=")) { - udev_device_set_devnode(udev_device, &line[8]); - continue; - } - - if (startswith(line, "MAJOR=")) - maj = strtoull(&line[6], NULL, 10); - else if (startswith(line, "MINOR=")) - min = strtoull(&line[6], NULL, 10); - else if (startswith(line, "DEVMODE=")) - udev_device->devnode_mode = strtoul(&line[8], NULL, 8); - - udev_device_add_property_from_string(udev_device, line); + if (startswith (line, "DEVNAME=")) + { + udev_device_set_devnode (udev_device, &line[8]); + continue; } - udev_device->devnum = makedev(maj, min); - fclose(f); - return 0; + if (startswith (line, "MAJOR=")) + maj = strtoull (&line[6], NULL, 10); + else if (startswith (line, "MINOR=")) + min = strtoull (&line[6], NULL, 10); + else if (startswith (line, "DEVMODE=")) + udev_device->devnode_mode = strtoul (&line[8], NULL, 8); + + udev_device_add_property_from_string (udev_device, line); + } + + udev_device->devnum = makedev (maj, min); + fclose (f); + return 0; } -void udev_device_set_info_loaded(struct udev_device *device) +void +udev_device_set_info_loaded (struct udev_device *device) { - device->info_loaded = true; + device->info_loaded = true; } -static struct udev_device *udev_device_new(struct udev *udev) +static struct udev_device * +udev_device_new (struct udev *udev) { - struct udev_device *udev_device; + struct udev_device *udev_device; - if (udev == NULL) { - errno = EINVAL; - return NULL; - } + if (udev == NULL) + { + errno = EINVAL; + return NULL; + } - udev_device = new0(struct udev_device, 1); - if (udev_device == NULL) { - errno = ENOMEM; - return NULL; - } - udev_device->refcount = 1; - udev_device->udev = udev; - udev_list_init(udev, &udev_device->devlinks_list, true); - udev_list_init(udev, &udev_device->properties_list, true); - udev_list_init(udev, &udev_device->sysattr_value_list, true); - udev_list_init(udev, &udev_device->sysattr_list, false); - udev_list_init(udev, &udev_device->tags_list, true); - udev_device->watch_handle = -1; + udev_device = new0 (struct udev_device, 1); + if (udev_device == NULL) + { + errno = ENOMEM; + return NULL; + } + udev_device->refcount = 1; + udev_device->udev = udev; + udev_list_init (udev, &udev_device->devlinks_list, true); + udev_list_init (udev, &udev_device->properties_list, true); + udev_list_init (udev, &udev_device->sysattr_value_list, true); + udev_list_init (udev, &udev_device->sysattr_list, false); + udev_list_init (udev, &udev_device->tags_list, true); + udev_device->watch_handle = -1; - return udev_device; + return udev_device; } /** @@ -851,71 +920,79 @@ static struct udev_device *udev_device_new(struct udev *udev) * * Returns: a new udev device, or #NULL, if it does not exist **/ -struct udev_device *udev_device_new_from_syspath(struct udev *udev, - const char *syspath) -{ - const char *subdir; - char path[UTIL_PATH_SIZE]; - char *pos; - struct stat statbuf; - struct udev_device *udev_device; - - if (udev == NULL) { - errno = EINVAL; - return NULL; - } - - if (syspath == NULL) { - errno = EINVAL; - return NULL; - } - - /* path starts in sys */ - if (!startswith(syspath, "/sys")) { - log_debug("not in sys :%s", syspath); - errno = EINVAL; - return NULL; - } - - /* path is not a root directory */ - subdir = syspath + strlen("/sys"); - pos = strrchr(subdir, '/'); - if (pos == NULL || pos[1] == '\0' || pos < &subdir[2]) { - errno = EINVAL; - return NULL; - } +struct udev_device * +udev_device_new_from_syspath (struct udev *udev, const char *syspath) +{ + const char *subdir; + char path[UTIL_PATH_SIZE]; + char *pos; + struct stat statbuf; + struct udev_device *udev_device; + + if (udev == NULL) + { + errno = EINVAL; + return NULL; + } + + if (syspath == NULL) + { + errno = EINVAL; + return NULL; + } + + /* path starts in sys */ + if (!startswith (syspath, "/sys")) + { + log_debug ("not in sys :%s", syspath); + errno = EINVAL; + return NULL; + } + + /* path is not a root directory */ + subdir = syspath + strlen ("/sys"); + pos = strrchr (subdir, '/'); + if (pos == NULL || pos[1] == '\0' || pos < &subdir[2]) + { + errno = EINVAL; + return NULL; + } + + /* resolve possible symlink to real path */ + strscpy (path, sizeof (path), syspath); + util_resolve_sys_link (udev, path, sizeof (path)); + + if (startswith (path + strlen ("/sys"), "/devices/")) + { + char file[UTIL_PATH_SIZE]; + + /* all "devices" require a "uevent" file */ + strscpyl (file, sizeof (file), path, "/uevent", NULL); + if (stat (file, &statbuf) != 0) + return NULL; + } + else + { + /* everything else just needs to be a directory */ + if (stat (path, &statbuf) != 0) + return NULL; - /* resolve possible symlink to real path */ - strscpy(path, sizeof(path), syspath); - util_resolve_sys_link(udev, path, sizeof(path)); - - if (startswith(path + strlen("/sys"), "/devices/")) { - char file[UTIL_PATH_SIZE]; - - /* all "devices" require a "uevent" file */ - strscpyl(file, sizeof(file), path, "/uevent", NULL); - if (stat(file, &statbuf) != 0) - return NULL; - } else { - /* everything else just needs to be a directory */ - if (stat(path, &statbuf) != 0) - return NULL; - - if (!S_ISDIR(statbuf.st_mode)) { - errno = EISDIR; - return NULL; - } + if (!S_ISDIR (statbuf.st_mode)) + { + errno = EISDIR; + return NULL; } + } - udev_device = udev_device_new(udev); - if (udev_device == NULL) - return NULL; + udev_device = udev_device_new (udev); + if (udev_device == NULL) + return NULL; - udev_device_set_syspath(udev_device, path); - log_trace("device %p has devpath '%s'", udev_device, - udev_device_get_devpath(udev_device)); + udev_device_set_syspath (udev_device, path); + log_trace ("device %p has devpath '%s'", udev_device, + udev_device_get_devpath (udev_device)); - return udev_device; + return udev_device; } /** @@ -934,25 +1011,26 @@ struct udev_device *udev_device_new_from_syspath(struct udev *udev, * * Returns: a new udev device, or #NULL, if it does not exist **/ -struct udev_device *udev_device_new_from_devnum(struct udev *udev, char type, - dev_t devnum) -{ - char path[UTIL_PATH_SIZE]; - const char *type_str; - - if (type == 'b') - type_str = "block"; - else if (type == 'c') - type_str = "char"; - else { - errno = EINVAL; - return NULL; - } +struct udev_device * +udev_device_new_from_devnum (struct udev *udev, char type, dev_t devnum) +{ + char path[UTIL_PATH_SIZE]; + const char *type_str; - /* use /sys/dev/{block,char}/: link */ - snprintf(path, sizeof(path), "/sys/dev/%s/%u:%u", - type_str, major(devnum), minor(devnum)); - return udev_device_new_from_syspath(udev, path); + if (type == 'b') + type_str = "block"; + else if (type == 'c') + type_str = "char"; + else + { + errno = EINVAL; + return NULL; + } + + /* use /sys/dev/{block,char}/: link */ + snprintf (path, sizeof (path), "/sys/dev/%s/%u:%u", + type_str, major (devnum), minor (devnum)); + return udev_device_new_from_syspath (udev, path); } /** @@ -973,73 +1051,74 @@ struct udev_device *udev_device_new_from_devnum(struct udev *udev, char type, * * Returns: a new udev device, or #NULL, if it does not exist **/ -struct udev_device *udev_device_new_from_device_id(struct udev *udev, - const char *id) -{ - char type; - int maj, min; - char subsys[UTIL_PATH_SIZE]; - char *sysname; - - switch (id[0]) { - case 'b': - case 'c': - if (sscanf(id, "%c%i:%i", &type, &maj, &min) != 3) - return NULL; - return udev_device_new_from_devnum(udev, type, - makedev(maj, min)); - case 'n':{ - int sk; - struct ifreq ifr; - struct udev_device *dev; - int ifindex; - - ifindex = strtoul(&id[1], NULL, 10); - if (ifindex <= 0) { - errno = EINVAL; - return NULL; - } - - sk = socket(PF_INET, SOCK_DGRAM, 0); - if (sk < 0) - return NULL; - memzero(&ifr, sizeof(struct ifreq)); - ifr.ifr_ifindex = ifindex; - if (ioctl(sk, SIOCGIFNAME, &ifr) != 0) { - close(sk); - return NULL; - } - close(sk); - - dev = - udev_device_new_from_subsystem_sysname(udev, "net", - ifr. - ifr_name); - if (dev == NULL) - return NULL; - if (udev_device_get_ifindex(dev) == ifindex) - return dev; - - /* this is racy, so we may end up with the wrong device */ - udev_device_unref(dev); - errno = ENODEV; - return NULL; - } - case '+': - strscpy(subsys, sizeof(subsys), &id[1]); - sysname = strchr(subsys, ':'); - if (sysname == NULL) { - errno = EINVAL; - return NULL; - } - sysname[0] = '\0'; - sysname = &sysname[1]; - return udev_device_new_from_subsystem_sysname(udev, subsys, - sysname); - default: - errno = EINVAL; - return NULL; +struct udev_device * +udev_device_new_from_device_id (struct udev *udev, const char *id) +{ + char type; + int maj, min; + char subsys[UTIL_PATH_SIZE]; + char *sysname; + + switch (id[0]) + { + case 'b': + case 'c': + if (sscanf (id, "%c%i:%i", &type, &maj, &min) != 3) + return NULL; + return udev_device_new_from_devnum (udev, type, makedev (maj, min)); + case 'n': + { + int sk; + struct ifreq ifr; + struct udev_device *dev; + int ifindex; + + ifindex = strtoul (&id[1], NULL, 10); + if (ifindex <= 0) + { + errno = EINVAL; + return NULL; + } + + sk = socket (PF_INET, SOCK_DGRAM, 0); + if (sk < 0) + return NULL; + memzero (&ifr, sizeof (struct ifreq)); + ifr.ifr_ifindex = ifindex; + if (ioctl (sk, SIOCGIFNAME, &ifr) != 0) + { + close (sk); + return NULL; + } + close (sk); + + dev = + udev_device_new_from_subsystem_sysname (udev, "net", ifr.ifr_name); + if (dev == NULL) + return NULL; + if (udev_device_get_ifindex (dev) == ifindex) + return dev; + + /* this is racy, so we may end up with the wrong device */ + udev_device_unref (dev); + errno = ENODEV; + return NULL; + } + case '+': + strscpy (subsys, sizeof (subsys), &id[1]); + sysname = strchr (subsys, ':'); + if (sysname == NULL) + { + errno = EINVAL; + return NULL; } + sysname[0] = '\0'; + sysname = &sysname[1]; + return udev_device_new_from_subsystem_sysname (udev, subsys, sysname); + default: + errno = EINVAL; + return NULL; + } } /** @@ -1057,79 +1136,84 @@ struct udev_device *udev_device_new_from_device_id(struct udev *udev, * * Returns: a new udev device, or #NULL, if it does not exist **/ -struct udev_device *udev_device_new_from_subsystem_sysname(struct udev *udev, - const char - *subsystem, - const char *sysname) -{ - char path[UTIL_PATH_SIZE]; - struct stat statbuf; - - if (streq(subsystem, "subsystem")) { - strscpyl(path, sizeof(path), "/sys/subsystem/", sysname, NULL); - if (stat(path, &statbuf) == 0) - goto found; - - strscpyl(path, sizeof(path), "/sys/bus/", sysname, NULL); - if (stat(path, &statbuf) == 0) - goto found; - - strscpyl(path, sizeof(path), "/sys/class/", sysname, NULL); - if (stat(path, &statbuf) == 0) - goto found; - goto out; +struct udev_device * +udev_device_new_from_subsystem_sysname (struct udev *udev, + const char + *subsystem, const char *sysname) +{ + char path[UTIL_PATH_SIZE]; + struct stat statbuf; + + if (streq (subsystem, "subsystem")) + { + strscpyl (path, sizeof (path), "/sys/subsystem/", sysname, NULL); + if (stat (path, &statbuf) == 0) + goto found; + + strscpyl (path, sizeof (path), "/sys/bus/", sysname, NULL); + if (stat (path, &statbuf) == 0) + goto found; + + strscpyl (path, sizeof (path), "/sys/class/", sysname, NULL); + if (stat (path, &statbuf) == 0) + goto found; + goto out; + } + + if (streq (subsystem, "module")) + { + strscpyl (path, sizeof (path), "/sys/module/", sysname, NULL); + if (stat (path, &statbuf) == 0) + goto found; + goto out; + } + + if (streq (subsystem, "drivers")) + { + char subsys[UTIL_NAME_SIZE]; + char *driver; + + strscpy (subsys, sizeof (subsys), sysname); + driver = strchr (subsys, ':'); + if (driver != NULL) + { + driver[0] = '\0'; + driver = &driver[1]; + + strscpyl (path, sizeof (path), "/sys/subsystem/", subsys, + "/drivers/", driver, NULL); + if (stat (path, &statbuf) == 0) + goto found; + + strscpyl (path, sizeof (path), "/sys/bus/", subsys, + "/drivers/", driver, NULL); + if (stat (path, &statbuf) == 0) + goto found; } + else + errno = EINVAL; - if (streq(subsystem, "module")) { - strscpyl(path, sizeof(path), "/sys/module/", sysname, NULL); - if (stat(path, &statbuf) == 0) - goto found; - goto out; - } + goto out; + } - if (streq(subsystem, "drivers")) { - char subsys[UTIL_NAME_SIZE]; - char *driver; - - strscpy(subsys, sizeof(subsys), sysname); - driver = strchr(subsys, ':'); - if (driver != NULL) { - driver[0] = '\0'; - driver = &driver[1]; - - strscpyl(path, sizeof(path), "/sys/subsystem/", subsys, - "/drivers/", driver, NULL); - if (stat(path, &statbuf) == 0) - goto found; - - strscpyl(path, sizeof(path), "/sys/bus/", subsys, - "/drivers/", driver, NULL); - if (stat(path, &statbuf) == 0) - goto found; - } else - errno = EINVAL; - - goto out; - } + strscpyl (path, sizeof (path), "/sys/subsystem/", subsystem, "/devices/", + sysname, NULL); + if (stat (path, &statbuf) == 0) + goto found; - strscpyl(path, sizeof(path), "/sys/subsystem/", subsystem, "/devices/", - sysname, NULL); - if (stat(path, &statbuf) == 0) - goto found; - - strscpyl(path, sizeof(path), "/sys/bus/", subsystem, "/devices/", - sysname, NULL); - if (stat(path, &statbuf) == 0) - goto found; - - strscpyl(path, sizeof(path), "/sys/class/", subsystem, "/", sysname, - NULL); - if (stat(path, &statbuf) == 0) - goto found; - out: - return NULL; - found: - return udev_device_new_from_syspath(udev, path); + strscpyl (path, sizeof (path), "/sys/bus/", subsystem, "/devices/", + sysname, NULL); + if (stat (path, &statbuf) == 0) + goto found; + + strscpyl (path, sizeof (path), "/sys/class/", subsystem, "/", sysname, + NULL); + if (stat (path, &statbuf) == 0) + goto found; +out: + return NULL; +found: + return udev_device_new_from_syspath (udev, path); } /** @@ -1146,53 +1230,55 @@ struct udev_device *udev_device_new_from_subsystem_sysname(struct udev *udev, * * Returns: a new udev device, or #NULL, if it does not exist **/ -struct udev_device *udev_device_new_from_environment(struct udev *udev) +struct udev_device * +udev_device_new_from_environment (struct udev *udev) { - int i; - struct udev_device *udev_device; + int i; + struct udev_device *udev_device; - udev_device = udev_device_new(udev); - if (udev_device == NULL) - return NULL; - udev_device_set_info_loaded(udev_device); + udev_device = udev_device_new (udev); + if (udev_device == NULL) + return NULL; + udev_device_set_info_loaded (udev_device); - for (i = 0; environ[i] != NULL; i++) - udev_device_add_property_from_string_parse(udev_device, - environ[i]); + for (i = 0; environ[i] != NULL; i++) + udev_device_add_property_from_string_parse (udev_device, environ[i]); - if (udev_device_add_property_from_string_parse_finish(udev_device) < 0) { - log_debug("%s", "missing values, invalid device"); - udev_device_unref(udev_device); - udev_device = NULL; - } + if (udev_device_add_property_from_string_parse_finish (udev_device) < 0) + { + log_debug ("%s", "missing values, invalid device"); + udev_device_unref (udev_device); + udev_device = NULL; + } - return udev_device; + return udev_device; } -static struct udev_device *device_new_from_parent(struct udev_device - *udev_device) +static struct udev_device * +device_new_from_parent (struct udev_device *udev_device) { - struct udev_device *udev_device_parent = NULL; - char path[UTIL_PATH_SIZE]; - const char *subdir; + struct udev_device *udev_device_parent = NULL; + char path[UTIL_PATH_SIZE]; + const char *subdir; - strscpy(path, sizeof(path), udev_device->syspath); - subdir = path + strlen("/sys/"); - for (;;) { - char *pos; + strscpy (path, sizeof (path), udev_device->syspath); + subdir = path + strlen ("/sys/"); + for (;;) + { + char *pos; - pos = strrchr(subdir, '/'); - if (pos == NULL || pos < &subdir[2]) - break; - pos[0] = '\0'; - udev_device_parent = - udev_device_new_from_syspath(udev_device->udev, path); - if (udev_device_parent != NULL) - return udev_device_parent; - } + pos = strrchr (subdir, '/'); + if (pos == NULL || pos < &subdir[2]) + break; + pos[0] = '\0'; + udev_device_parent = + udev_device_new_from_syspath (udev_device->udev, path); + if (udev_device_parent != NULL) + return udev_device_parent; + } - errno = ENOENT; - return NULL; + errno = ENOENT; + return NULL; } /** @@ -1213,18 +1299,20 @@ static struct udev_device *device_new_from_parent(struct udev_device * * Returns: a new udev device, or #NULL, if it no parent exist. **/ -struct udev_device *udev_device_get_parent(struct udev_device *udev_device) -{ - if (udev_device == NULL) { - errno = EINVAL; - return NULL; - } - if (!udev_device->parent_set) { - udev_device->parent_set = true; - udev_device->parent_device = - device_new_from_parent(udev_device); - } - return udev_device->parent_device; +struct udev_device * +udev_device_get_parent (struct udev_device *udev_device) +{ + if (udev_device == NULL) + { + errno = EINVAL; + return NULL; + } + if (!udev_device->parent_set) + { + udev_device->parent_set = true; + udev_device->parent_device = device_new_from_parent (udev_device); + } + return udev_device->parent_device; } /** @@ -1248,43 +1336,44 @@ struct udev_device *udev_device_get_parent(struct udev_device *udev_device) * * Returns: a new udev device, or #NULL if no matching parent exists. **/ -struct udev_device *udev_device_get_parent_with_subsystem_devtype(struct - udev_device - *udev_device, - const char - *subsystem, - const char - *devtype) -{ - struct udev_device *parent; - - if (subsystem == NULL) { - errno = EINVAL; - return NULL; +struct udev_device * +udev_device_get_parent_with_subsystem_devtype (struct + udev_device + *udev_device, + const char + *subsystem, + const char *devtype) +{ + struct udev_device *parent; + + if (subsystem == NULL) + { + errno = EINVAL; + return NULL; + } + + parent = udev_device_get_parent (udev_device); + while (parent != NULL) + { + const char *parent_subsystem; + const char *parent_devtype; + + parent_subsystem = udev_device_get_subsystem (parent); + if (parent_subsystem != NULL && streq (parent_subsystem, subsystem)) + { + if (devtype == NULL) + break; + parent_devtype = udev_device_get_devtype (parent); + if (parent_devtype != NULL && streq (parent_devtype, devtype)) + break; } + parent = udev_device_get_parent (parent); + } - parent = udev_device_get_parent(udev_device); - while (parent != NULL) { - const char *parent_subsystem; - const char *parent_devtype; - - parent_subsystem = udev_device_get_subsystem(parent); - if (parent_subsystem != NULL - && streq(parent_subsystem, subsystem)) { - if (devtype == NULL) - break; - parent_devtype = udev_device_get_devtype(parent); - if (parent_devtype != NULL - && streq(parent_devtype, devtype)) - break; - } - parent = udev_device_get_parent(parent); - } - - if (!parent) - errno = ENOENT; + if (!parent) + errno = ENOENT; - return parent; + return parent; } /** @@ -1295,11 +1384,12 @@ struct udev_device *udev_device_get_parent_with_subsystem_devtype(struct * * Returns: the udev library context **/ -struct udev *udev_device_get_udev(struct udev_device *udev_device) +struct udev * +udev_device_get_udev (struct udev_device *udev_device) { - if (udev_device == NULL) - return NULL; - return udev_device->udev; + if (udev_device == NULL) + return NULL; + return udev_device->udev; } /** @@ -1310,12 +1400,13 @@ struct udev *udev_device_get_udev(struct udev_device *udev_device) * * Returns: the passed udev device **/ -struct udev_device *udev_device_ref(struct udev_device *udev_device) +struct udev_device * +udev_device_ref (struct udev_device *udev_device) { - if (udev_device == NULL) - return NULL; - udev_device->refcount++; - return udev_device; + if (udev_device == NULL) + return NULL; + udev_device->refcount++; + return udev_device; } /** @@ -1327,33 +1418,34 @@ struct udev_device *udev_device_ref(struct udev_device *udev_device) * * Returns: #NULL **/ -struct udev_device *udev_device_unref(struct udev_device *udev_device) -{ - if (udev_device == NULL) - return NULL; - udev_device->refcount--; - if (udev_device->refcount > 0) - return NULL; - if (udev_device->parent_device != NULL) - udev_device_unref(udev_device->parent_device); - free(udev_device->syspath); - free(udev_device->sysname); - free(udev_device->devnode); - free(udev_device->subsystem); - free(udev_device->devtype); - udev_list_cleanup(&udev_device->devlinks_list); - udev_list_cleanup(&udev_device->properties_list); - udev_list_cleanup(&udev_device->sysattr_value_list); - udev_list_cleanup(&udev_device->sysattr_list); - udev_list_cleanup(&udev_device->tags_list); - free(udev_device->action); - free(udev_device->driver); - free(udev_device->devpath_old); - free(udev_device->id_filename); - free(udev_device->envp); - free(udev_device->monitor_buf); - free(udev_device); - return NULL; +struct udev_device * +udev_device_unref (struct udev_device *udev_device) +{ + if (udev_device == NULL) + return NULL; + udev_device->refcount--; + if (udev_device->refcount > 0) + return NULL; + if (udev_device->parent_device != NULL) + udev_device_unref (udev_device->parent_device); + free (udev_device->syspath); + free (udev_device->sysname); + free (udev_device->devnode); + free (udev_device->subsystem); + free (udev_device->devtype); + udev_list_cleanup (&udev_device->devlinks_list); + udev_list_cleanup (&udev_device->properties_list); + udev_list_cleanup (&udev_device->sysattr_value_list); + udev_list_cleanup (&udev_device->sysattr_list); + udev_list_cleanup (&udev_device->tags_list); + free (udev_device->action); + free (udev_device->driver); + free (udev_device->devpath_old); + free (udev_device->id_filename); + free (udev_device->envp); + free (udev_device->monitor_buf); + free (udev_device); + return NULL; } /** @@ -1365,11 +1457,12 @@ struct udev_device *udev_device_unref(struct udev_device *udev_device) * * Returns: the devpath of the udev device **/ -const char *udev_device_get_devpath(struct udev_device *udev_device) +const char * +udev_device_get_devpath (struct udev_device *udev_device) { - if (udev_device == NULL) - return NULL; - return udev_device->devpath; + if (udev_device == NULL) + return NULL; + return udev_device->devpath; } /** @@ -1381,11 +1474,12 @@ const char *udev_device_get_devpath(struct udev_device *udev_device) * * Returns: the sys path of the udev device **/ -const char *udev_device_get_syspath(struct udev_device *udev_device) +const char * +udev_device_get_syspath (struct udev_device *udev_device) { - if (udev_device == NULL) - return NULL; - return udev_device->syspath; + if (udev_device == NULL) + return NULL; + return udev_device->syspath; } /** @@ -1396,11 +1490,12 @@ const char *udev_device_get_syspath(struct udev_device *udev_device) * * Returns: the name string of the device device **/ -const char *udev_device_get_sysname(struct udev_device *udev_device) +const char * +udev_device_get_sysname (struct udev_device *udev_device) { - if (udev_device == NULL) - return NULL; - return udev_device->sysname; + if (udev_device == NULL) + return NULL; + return udev_device->sysname; } /** @@ -1411,11 +1506,12 @@ const char *udev_device_get_sysname(struct udev_device *udev_device) * * Returns: the trailing number string of the device name **/ -const char *udev_device_get_sysnum(struct udev_device *udev_device) +const char * +udev_device_get_sysnum (struct udev_device *udev_device) { - if (udev_device == NULL) - return NULL; - return udev_device->sysnum; + if (udev_device == NULL) + return NULL; + return udev_device->sysnum; } /** @@ -1427,15 +1523,16 @@ const char *udev_device_get_sysnum(struct udev_device *udev_device) * * Returns: the device node file name of the udev device, or #NULL if no device node exists **/ -const char *udev_device_get_devnode(struct udev_device *udev_device) +const char * +udev_device_get_devnode (struct udev_device *udev_device) { - if (udev_device == NULL) - return NULL; - if (udev_device->devnode != NULL) - return udev_device->devnode; - if (!udev_device->info_loaded) - udev_device_read_uevent_file(udev_device); - return udev_device->devnode; + if (udev_device == NULL) + return NULL; + if (udev_device->devnode != NULL) + return udev_device->devnode; + if (!udev_device->info_loaded) + udev_device_read_uevent_file (udev_device); + return udev_device->devnode; } /** @@ -1451,20 +1548,21 @@ const char *udev_device_get_devnode(struct udev_device *udev_device) * * Returns: the first entry of the device node link list **/ -struct udev_list_entry *udev_device_get_devlinks_list_entry(struct udev_device - *udev_device) +struct udev_list_entry * +udev_device_get_devlinks_list_entry (struct udev_device *udev_device) { - if (udev_device == NULL) - return NULL; - if (!udev_device->info_loaded) - udev_device_read_db(udev_device); - return udev_list_get_entry(&udev_device->devlinks_list); + if (udev_device == NULL) + return NULL; + if (!udev_device->info_loaded) + udev_device_read_db (udev_device); + return udev_list_get_entry (&udev_device->devlinks_list); } -void udev_device_cleanup_devlinks_list(struct udev_device *udev_device) +void +udev_device_cleanup_devlinks_list (struct udev_device *udev_device) { - udev_device->devlinks_uptodate = false; - udev_list_cleanup(&udev_device->devlinks_list); + udev_device->devlinks_uptodate = false; + udev_list_cleanup (&udev_device->devlinks_list); } /** @@ -1479,62 +1577,63 @@ void udev_device_cleanup_devlinks_list(struct udev_device *udev_device) * * Returns: the first entry of the property list **/ -struct udev_list_entry *udev_device_get_properties_list_entry(struct udev_device - *udev_device) -{ - if (udev_device == NULL) - return NULL; - if (!udev_device->info_loaded) { - udev_device_read_uevent_file(udev_device); - udev_device_read_db(udev_device); +struct udev_list_entry * +udev_device_get_properties_list_entry (struct udev_device *udev_device) +{ + if (udev_device == NULL) + return NULL; + if (!udev_device->info_loaded) + { + udev_device_read_uevent_file (udev_device); + udev_device_read_db (udev_device); + } + if (!udev_device->devlinks_uptodate) + { + char symlinks[UTIL_PATH_SIZE]; + struct udev_list_entry *list_entry; + + udev_device->devlinks_uptodate = true; + list_entry = udev_device_get_devlinks_list_entry (udev_device); + if (list_entry != NULL) + { + char *s; + size_t l; + + s = symlinks; + l = strpcpyl (&s, sizeof (symlinks), + udev_list_entry_get_name (list_entry), NULL); + udev_list_entry_foreach (list_entry, + udev_list_entry_get_next + (list_entry)) + l = + strpcpyl (&s, l, " ", + udev_list_entry_get_name (list_entry), NULL); + udev_device_add_property_internal (udev_device, + "DEVLINKS", symlinks); } - if (!udev_device->devlinks_uptodate) { - char symlinks[UTIL_PATH_SIZE]; - struct udev_list_entry *list_entry; - - udev_device->devlinks_uptodate = true; - list_entry = udev_device_get_devlinks_list_entry(udev_device); - if (list_entry != NULL) { - char *s; - size_t l; - - s = symlinks; - l = strpcpyl(&s, sizeof(symlinks), - udev_list_entry_get_name(list_entry), - NULL); - udev_list_entry_foreach(list_entry, - udev_list_entry_get_next - (list_entry)) - l = - strpcpyl(&s, l, " ", - udev_list_entry_get_name(list_entry), - NULL); - udev_device_add_property_internal(udev_device, - "DEVLINKS", symlinks); - } + } + if (!udev_device->tags_uptodate) + { + udev_device->tags_uptodate = true; + if (udev_device_get_tags_list_entry (udev_device) != NULL) + { + char tags[UTIL_PATH_SIZE]; + struct udev_list_entry *list_entry; + char *s; + size_t l; + + s = tags; + l = strpcpyl (&s, sizeof (tags), ":", NULL); + udev_list_entry_foreach (list_entry, + udev_device_get_tags_list_entry + (udev_device)) + l = + strpcpyl (&s, l, + udev_list_entry_get_name (list_entry), ":", NULL); + udev_device_add_property_internal (udev_device, "TAGS", tags); } - if (!udev_device->tags_uptodate) { - udev_device->tags_uptodate = true; - if (udev_device_get_tags_list_entry(udev_device) != NULL) { - char tags[UTIL_PATH_SIZE]; - struct udev_list_entry *list_entry; - char *s; - size_t l; - - s = tags; - l = strpcpyl(&s, sizeof(tags), ":", NULL); - udev_list_entry_foreach(list_entry, - udev_device_get_tags_list_entry - (udev_device)) - l = - strpcpyl(&s, l, - udev_list_entry_get_name(list_entry), ":", - NULL); - udev_device_add_property_internal(udev_device, "TAGS", - tags); - } - } - return udev_list_get_entry(&udev_device->properties_list); + } + return udev_list_get_entry (&udev_device->properties_list); } /** @@ -1547,11 +1646,12 @@ struct udev_list_entry *udev_device_get_properties_list_entry(struct udev_device * * Returns: the kernel action value, or #NULL if there is no action value available. **/ -const char *udev_device_get_action(struct udev_device *udev_device) +const char * +udev_device_get_action (struct udev_device *udev_device) { - if (udev_device == NULL) - return NULL; - return udev_device->action; + if (udev_device == NULL) + return NULL; + return udev_device->action; } /** @@ -1566,26 +1666,27 @@ const char *udev_device_get_action(struct udev_device *udev_device) * * Returns: the number of microseconds since the device was first seen. **/ -unsigned long long int udev_device_get_usec_since_initialized(struct udev_device - *udev_device) +unsigned long long int +udev_device_get_usec_since_initialized (struct udev_device *udev_device) { - usec_t now_ts; + usec_t now_ts; - if (udev_device == NULL) - return 0; - if (!udev_device->info_loaded) - udev_device_read_db(udev_device); - if (udev_device->usec_initialized == 0) - return 0; - now_ts = now(CLOCK_MONOTONIC); - if (now_ts == 0) - return 0; - return now_ts - udev_device->usec_initialized; + if (udev_device == NULL) + return 0; + if (!udev_device->info_loaded) + udev_device_read_db (udev_device); + if (udev_device->usec_initialized == 0) + return 0; + now_ts = now (CLOCK_MONOTONIC); + if (now_ts == 0) + return 0; + return now_ts - udev_device->usec_initialized; } -usec_t udev_device_get_usec_initialized(struct udev_device * udev_device) +usec_t +udev_device_get_usec_initialized (struct udev_device * udev_device) { - return udev_device->usec_initialized; + return udev_device->usec_initialized; } /** @@ -1598,86 +1699,87 @@ usec_t udev_device_get_usec_initialized(struct udev_device * udev_device) * * Returns: the content of a sys attribute file, or #NULL if there is no sys attribute value. **/ -const char *udev_device_get_sysattr_value(struct udev_device *udev_device, - const char *sysattr) -{ - struct udev_list_entry *list_entry; - char path[UTIL_PATH_SIZE]; - char value[4096]; - struct stat statbuf; - int fd; - ssize_t size; - const char *val = NULL; - - if (udev_device == NULL) - return NULL; - if (sysattr == NULL) - return NULL; - - /* look for possibly already cached result */ - list_entry = udev_list_get_entry(&udev_device->sysattr_value_list); - list_entry = udev_list_entry_get_by_name(list_entry, sysattr); - if (list_entry != NULL) - return udev_list_entry_get_value(list_entry); - - strscpyl(path, sizeof(path), udev_device_get_syspath(udev_device), "/", - sysattr, NULL); - if (lstat(path, &statbuf) != 0) { - udev_list_entry_add(&udev_device->sysattr_value_list, sysattr, - NULL); - goto out; +const char * +udev_device_get_sysattr_value (struct udev_device *udev_device, + const char *sysattr) +{ + struct udev_list_entry *list_entry; + char path[UTIL_PATH_SIZE]; + char value[4096]; + struct stat statbuf; + int fd; + ssize_t size; + const char *val = NULL; + + if (udev_device == NULL) + return NULL; + if (sysattr == NULL) + return NULL; + + /* look for possibly already cached result */ + list_entry = udev_list_get_entry (&udev_device->sysattr_value_list); + list_entry = udev_list_entry_get_by_name (list_entry, sysattr); + if (list_entry != NULL) + return udev_list_entry_get_value (list_entry); + + strscpyl (path, sizeof (path), udev_device_get_syspath (udev_device), "/", + sysattr, NULL); + if (lstat (path, &statbuf) != 0) + { + udev_list_entry_add (&udev_device->sysattr_value_list, sysattr, NULL); + goto out; + } + + if (S_ISLNK (statbuf.st_mode)) + { + /* + * Some core links return only the last element of the target path, + * these are just values, the paths should not be exposed. + */ + if (streq (sysattr, "driver") || + streq (sysattr, "subsystem") || streq (sysattr, "module")) + { + if (util_get_sys_core_link_value + (udev_device->udev, sysattr, udev_device->syspath, + value, sizeof (value)) < 0) + return NULL; + list_entry = + udev_list_entry_add (&udev_device->sysattr_value_list, sysattr, + value); + val = udev_list_entry_get_value (list_entry); + goto out; } - if (S_ISLNK(statbuf.st_mode)) { - /* - * Some core links return only the last element of the target path, - * these are just values, the paths should not be exposed. - */ - if (streq(sysattr, "driver") || - streq(sysattr, "subsystem") || streq(sysattr, "module")) { - if (util_get_sys_core_link_value - (udev_device->udev, sysattr, udev_device->syspath, - value, sizeof(value)) < 0) - return NULL; - list_entry = - udev_list_entry_add(&udev_device-> - sysattr_value_list, sysattr, - value); - val = udev_list_entry_get_value(list_entry); - goto out; - } - - goto out; - } - - /* skip directories */ - if (S_ISDIR(statbuf.st_mode)) - goto out; - - /* skip non-readable files */ - if ((statbuf.st_mode & S_IRUSR) == 0) - goto out; - - /* read attribute value */ - fd = open(path, O_RDONLY | O_CLOEXEC); - if (fd < 0) - goto out; - size = read(fd, value, sizeof(value)); - close(fd); - if (size < 0) - goto out; - if (size == sizeof(value)) - goto out; - - /* got a valid value, store it in cache and return it */ - value[size] = '\0'; - util_remove_trailing_chars(value, '\n'); - list_entry = - udev_list_entry_add(&udev_device->sysattr_value_list, sysattr, - value); - val = udev_list_entry_get_value(list_entry); - out: - return val; + goto out; + } + + /* skip directories */ + if (S_ISDIR (statbuf.st_mode)) + goto out; + + /* skip non-readable files */ + if ((statbuf.st_mode & S_IRUSR) == 0) + goto out; + + /* read attribute value */ + fd = open (path, O_RDONLY | O_CLOEXEC); + if (fd < 0) + goto out; + size = read (fd, value, sizeof (value)); + close (fd); + if (size < 0) + goto out; + if (size == sizeof (value)) + goto out; + + /* got a valid value, store it in cache and return it */ + value[size] = '\0'; + util_remove_trailing_chars (value, '\n'); + list_entry = + udev_list_entry_add (&udev_device->sysattr_value_list, sysattr, value); + val = udev_list_entry_get_value (list_entry); +out: + return val; } /** @@ -1690,123 +1792,133 @@ const char *udev_device_get_sysattr_value(struct udev_device *udev_device, * * Returns: Negative error code on failure or 0 on success. **/ -int udev_device_set_sysattr_value(struct udev_device *udev_device, - const char *sysattr, char *value) -{ - struct udev_device *dev; - char path[UTIL_PATH_SIZE]; - struct stat statbuf; - int fd; - ssize_t size, value_len; - int ret = 0; - - if (udev_device == NULL) - return -EINVAL; - dev = udev_device; - if (sysattr == NULL) - return -EINVAL; - if (value == NULL) - value_len = 0; - else - value_len = strlen(value); - - strscpyl(path, sizeof(path), udev_device_get_syspath(dev), "/", sysattr, - NULL); - if (lstat(path, &statbuf) != 0) { - udev_list_entry_add(&dev->sysattr_value_list, sysattr, NULL); - ret = -ENXIO; - goto out; - } - - if (S_ISLNK(statbuf.st_mode)) { - ret = -EINVAL; - goto out; - } - - /* skip directories */ - if (S_ISDIR(statbuf.st_mode)) { - ret = -EISDIR; - goto out; - } - - /* skip non-readable files */ - if ((statbuf.st_mode & S_IRUSR) == 0) { - ret = -EACCES; - goto out; - } - - /* Value is limited to 4k */ - if (value_len > 4096) { - ret = -EINVAL; - goto out; - } - util_remove_trailing_chars(value, '\n'); - - /* write attribute value */ - fd = open(path, O_WRONLY | O_CLOEXEC); - if (fd < 0) { - ret = -errno; - goto out; - } - size = write(fd, value, value_len); - close(fd); - if (size < 0) { - ret = -errno; - goto out; - } - if (size < value_len) { - ret = -EIO; - goto out; - } - - /* wrote a valid value, store it in cache and return it */ - udev_list_entry_add(&dev->sysattr_value_list, sysattr, value); - out: - if (dev != udev_device) - udev_device_unref(dev); - return ret; -} - -static int udev_device_sysattr_list_read(struct udev_device *udev_device) -{ - struct dirent *dent; - DIR *dir; - int num = 0; - - if (udev_device == NULL) - return -EINVAL; - if (udev_device->sysattr_list_read) - return 0; - - dir = opendir(udev_device_get_syspath(udev_device)); - if (!dir) - return -errno; - - for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) { - char path[UTIL_PATH_SIZE]; - struct stat statbuf; - - /* only handle symlinks and regular files */ - if (dent->d_type != DT_LNK && dent->d_type != DT_REG) - continue; - - strscpyl(path, sizeof(path), - udev_device_get_syspath(udev_device), "/", - dent->d_name, NULL); - if (lstat(path, &statbuf) != 0) - continue; - if ((statbuf.st_mode & S_IRUSR) == 0) - continue; - - udev_list_entry_add(&udev_device->sysattr_list, dent->d_name, - NULL); - num++; - } - - closedir(dir); - udev_device->sysattr_list_read = true; - - return num; +int +udev_device_set_sysattr_value (struct udev_device *udev_device, + const char *sysattr, char *value) +{ + struct udev_device *dev; + char path[UTIL_PATH_SIZE]; + struct stat statbuf; + int fd; + ssize_t size, value_len; + int ret = 0; + + if (udev_device == NULL) + return -EINVAL; + dev = udev_device; + if (sysattr == NULL) + return -EINVAL; + if (value == NULL) + value_len = 0; + else + value_len = strlen (value); + + strscpyl (path, sizeof (path), udev_device_get_syspath (dev), "/", sysattr, + NULL); + if (lstat (path, &statbuf) != 0) + { + udev_list_entry_add (&dev->sysattr_value_list, sysattr, NULL); + ret = -ENXIO; + goto out; + } + + if (S_ISLNK (statbuf.st_mode)) + { + ret = -EINVAL; + goto out; + } + + /* skip directories */ + if (S_ISDIR (statbuf.st_mode)) + { + ret = -EISDIR; + goto out; + } + + /* skip non-readable files */ + if ((statbuf.st_mode & S_IRUSR) == 0) + { + ret = -EACCES; + goto out; + } + + /* Value is limited to 4k */ + if (value_len > 4096) + { + ret = -EINVAL; + goto out; + } + util_remove_trailing_chars (value, '\n'); + + /* write attribute value */ + fd = open (path, O_WRONLY | O_CLOEXEC); + if (fd < 0) + { + ret = -errno; + goto out; + } + size = write (fd, value, value_len); + close (fd); + if (size < 0) + { + ret = -errno; + goto out; + } + if (size < value_len) + { + ret = -EIO; + goto out; + } + + /* wrote a valid value, store it in cache and return it */ + udev_list_entry_add (&dev->sysattr_value_list, sysattr, value); +out: + if (dev != udev_device) + udev_device_unref (dev); + return ret; +} + +static int +udev_device_sysattr_list_read (struct udev_device *udev_device) +{ + struct dirent *dent; + DIR *dir; + int num = 0; + + if (udev_device == NULL) + return -EINVAL; + if (udev_device->sysattr_list_read) + return 0; + + dir = opendir (udev_device_get_syspath (udev_device)); + if (!dir) + return -errno; + + for (dent = readdir (dir); dent != NULL; dent = readdir (dir)) + { + char path[UTIL_PATH_SIZE]; + struct stat statbuf; + + /* only handle symlinks and regular files */ + if (dent->d_type != DT_LNK && dent->d_type != DT_REG) + continue; + + strscpyl (path, sizeof (path), + udev_device_get_syspath (udev_device), "/", + dent->d_name, NULL); + if (lstat (path, &statbuf) != 0) + continue; + if ((statbuf.st_mode & S_IRUSR) == 0) + continue; + + udev_list_entry_add (&udev_device->sysattr_list, dent->d_name, NULL); + num++; + } + + closedir (dir); + udev_device->sysattr_list_read = true; + + return num; } /** @@ -1819,88 +1931,97 @@ static int udev_device_sysattr_list_read(struct udev_device *udev_device) * * Returns: the first entry of the property list **/ -struct udev_list_entry *udev_device_get_sysattr_list_entry(struct udev_device - *udev_device) -{ - if (!udev_device->sysattr_list_read) { - int ret; - ret = udev_device_sysattr_list_read(udev_device); - if (0 > ret) - return NULL; - } +struct udev_list_entry * +udev_device_get_sysattr_list_entry (struct udev_device *udev_device) +{ + if (!udev_device->sysattr_list_read) + { + int ret; + ret = udev_device_sysattr_list_read (udev_device); + if (0 > ret) + return NULL; + } - return udev_list_get_entry(&udev_device->sysattr_list); + return udev_list_get_entry (&udev_device->sysattr_list); } -static int udev_device_set_devnode(struct udev_device *udev_device, - const char *devnode) +static int +udev_device_set_devnode (struct udev_device *udev_device, const char *devnode) { - free(udev_device->devnode); - if (devnode[0] != '/') { - if (asprintf(&udev_device->devnode, "/dev/%s", devnode) < 0) - udev_device->devnode = NULL; - } else { - udev_device->devnode = strdup(devnode); + free (udev_device->devnode); + if (devnode[0] != '/') + { + if (asprintf (&udev_device->devnode, "/dev/%s", devnode) < 0) + udev_device->devnode = NULL; + } + else + { + udev_device->devnode = strdup (devnode); + } + if (udev_device->devnode == NULL) + return -ENOMEM; + udev_device_add_property_internal (udev_device, "DEVNAME", + udev_device->devnode); + return 0; +} + +int +udev_device_add_devlink (struct udev_device *udev_device, const char *devlink) +{ + struct udev_list_entry *list_entry; + + udev_device->devlinks_uptodate = false; + list_entry = + udev_list_entry_add (&udev_device->devlinks_list, devlink, NULL); + if (list_entry == NULL) + return -ENOMEM; + return 0; +} + +const char * +udev_device_get_id_filename (struct udev_device *udev_device) +{ + if (udev_device->id_filename == NULL) + { + if (udev_device_get_subsystem (udev_device) == NULL) + return NULL; + + if (major (udev_device_get_devnum (udev_device)) > 0) + { + /* use dev_t -- b259:131072, c254:0 */ + if (asprintf (&udev_device->id_filename, "%c%u:%u", + streq (udev_device_get_subsystem + (udev_device), "block") ? 'b' : 'c', + major (udev_device_get_devnum (udev_device)), + minor (udev_device_get_devnum (udev_device))) < 0) + udev_device->id_filename = NULL; + } + else if (udev_device_get_ifindex (udev_device) > 0) + { + /* use netdev ifindex -- n3 */ + if (asprintf + (&udev_device->id_filename, "n%i", + udev_device_get_ifindex (udev_device)) < 0) + udev_device->id_filename = NULL; } - if (udev_device->devnode == NULL) - return -ENOMEM; - udev_device_add_property_internal(udev_device, "DEVNAME", - udev_device->devnode); - return 0; -} - -int udev_device_add_devlink(struct udev_device *udev_device, - const char *devlink) -{ - struct udev_list_entry *list_entry; - - udev_device->devlinks_uptodate = false; - list_entry = - udev_list_entry_add(&udev_device->devlinks_list, devlink, NULL); - if (list_entry == NULL) - return -ENOMEM; - return 0; -} - -const char *udev_device_get_id_filename(struct udev_device *udev_device) -{ - if (udev_device->id_filename == NULL) { - if (udev_device_get_subsystem(udev_device) == NULL) - return NULL; - - if (major(udev_device_get_devnum(udev_device)) > 0) { - /* use dev_t -- b259:131072, c254:0 */ - if (asprintf(&udev_device->id_filename, "%c%u:%u", - streq(udev_device_get_subsystem - (udev_device), "block") ? 'b' : 'c', - major(udev_device_get_devnum(udev_device)), - minor(udev_device_get_devnum(udev_device))) - < 0) - udev_device->id_filename = NULL; - } else if (udev_device_get_ifindex(udev_device) > 0) { - /* use netdev ifindex -- n3 */ - if (asprintf - (&udev_device->id_filename, "n%i", - udev_device_get_ifindex(udev_device)) < 0) - udev_device->id_filename = NULL; - } else { - /* - * use $subsys:$syname -- pci:0000:00:1f.2 - * sysname() has '!' translated, get it from devpath - */ - const char *sysname; - sysname = strrchr(udev_device->devpath, '/'); - if (sysname == NULL) - return NULL; - sysname = &sysname[1]; - if (asprintf - (&udev_device->id_filename, "+%s:%s", - udev_device_get_subsystem(udev_device), - sysname) < 0) - udev_device->id_filename = NULL; - } + else + { + /* + * use $subsys:$syname -- pci:0000:00:1f.2 + * sysname() has '!' translated, get it from devpath + */ + const char *sysname; + sysname = strrchr (udev_device->devpath, '/'); + if (sysname == NULL) + return NULL; + sysname = &sysname[1]; + if (asprintf + (&udev_device->id_filename, "+%s:%s", + udev_device_get_subsystem (udev_device), sysname) < 0) + udev_device->id_filename = NULL; } - return udev_device->id_filename; + } + return udev_device->id_filename; } /** @@ -1916,51 +2037,58 @@ const char *udev_device_get_id_filename(struct udev_device *udev_device) * * Returns: 1 if the device is set up. 0 otherwise. **/ -int udev_device_get_is_initialized(struct udev_device *udev_device) +int +udev_device_get_is_initialized (struct udev_device *udev_device) { - if (!udev_device->info_loaded) - udev_device_read_db(udev_device); - return udev_device->is_initialized; + if (!udev_device->info_loaded) + udev_device_read_db (udev_device); + return udev_device->is_initialized; } -void udev_device_set_is_initialized(struct udev_device *udev_device) +void +udev_device_set_is_initialized (struct udev_device *udev_device) { - udev_device->is_initialized = true; + udev_device->is_initialized = true; } -static bool is_valid_tag(const char *tag) +static bool +is_valid_tag (const char *tag) { - return !strchr(tag, ':') && !strchr(tag, ' '); + return !strchr (tag, ':') && !strchr (tag, ' '); } -int udev_device_add_tag(struct udev_device *udev_device, const char *tag) +int +udev_device_add_tag (struct udev_device *udev_device, const char *tag) { - if (!is_valid_tag(tag)) - return -EINVAL; - udev_device->tags_uptodate = false; - if (udev_list_entry_add(&udev_device->tags_list, tag, NULL) != NULL) - return 0; - return -ENOMEM; + if (!is_valid_tag (tag)) + return -EINVAL; + udev_device->tags_uptodate = false; + if (udev_list_entry_add (&udev_device->tags_list, tag, NULL) != NULL) + return 0; + return -ENOMEM; } -void udev_device_remove_tag(struct udev_device *udev_device, const char *tag) +void +udev_device_remove_tag (struct udev_device *udev_device, const char *tag) { - struct udev_list_entry *e; + struct udev_list_entry *e; - if (!is_valid_tag(tag)) - return; - e = udev_list_get_entry(&udev_device->tags_list); - e = udev_list_entry_get_by_name(e, tag); - if (e) { - udev_device->tags_uptodate = false; - udev_list_entry_delete(e); - } + if (!is_valid_tag (tag)) + return; + e = udev_list_get_entry (&udev_device->tags_list); + e = udev_list_entry_get_by_name (e, tag); + if (e) + { + udev_device->tags_uptodate = false; + udev_list_entry_delete (e); + } } -void udev_device_cleanup_tags_list(struct udev_device *udev_device) +void +udev_device_cleanup_tags_list (struct udev_device *udev_device) { - udev_device->tags_uptodate = false; - udev_list_cleanup(&udev_device->tags_list); + udev_device->tags_uptodate = false; + udev_list_cleanup (&udev_device->tags_list); } /** @@ -1974,14 +2102,14 @@ void udev_device_cleanup_tags_list(struct udev_device *udev_device) * * Returns: the first entry of the tag list **/ -struct udev_list_entry *udev_device_get_tags_list_entry(struct udev_device - *udev_device) +struct udev_list_entry * +udev_device_get_tags_list_entry (struct udev_device *udev_device) { - if (udev_device == NULL) - return NULL; - if (!udev_device->info_loaded) - udev_device_read_db(udev_device); - return udev_list_get_entry(&udev_device->tags_list); + if (udev_device == NULL) + return NULL; + if (!udev_device->info_loaded) + udev_device_read_db (udev_device); + return udev_list_get_entry (&udev_device->tags_list); } /** @@ -1993,297 +2121,320 @@ struct udev_list_entry *udev_device_get_tags_list_entry(struct udev_device * * Returns: 1 if the tag is found. 0 otherwise. **/ -int udev_device_has_tag(struct udev_device *udev_device, const char *tag) +int +udev_device_has_tag (struct udev_device *udev_device, const char *tag) { - struct udev_list_entry *list_entry; + struct udev_list_entry *list_entry; - if (udev_device == NULL) - return false; - if (!udev_device->info_loaded) - udev_device_read_db(udev_device); - list_entry = udev_device_get_tags_list_entry(udev_device); - if (udev_list_entry_get_by_name(list_entry, tag) != NULL) - return true; - return false; + if (udev_device == NULL) + return false; + if (!udev_device->info_loaded) + udev_device_read_db (udev_device); + list_entry = udev_device_get_tags_list_entry (udev_device); + if (udev_list_entry_get_by_name (list_entry, tag) != NULL) + return true; + return false; } #define ENVP_SIZE 128 #define MONITOR_BUF_SIZE 4096 -static int update_envp_monitor_buf(struct udev_device *udev_device) -{ - struct udev_list_entry *list_entry; - char *s; - size_t l; - unsigned int i; - - /* monitor buffer of property strings */ - free(udev_device->monitor_buf); - udev_device->monitor_buf_len = 0; - udev_device->monitor_buf = malloc(MONITOR_BUF_SIZE); - if (udev_device->monitor_buf == NULL) - return -ENOMEM; - - /* envp array, strings will point into monitor buffer */ - if (udev_device->envp == NULL) - udev_device->envp = malloc(sizeof(char *) * ENVP_SIZE); - if (udev_device->envp == NULL) - return -ENOMEM; - - i = 0; - s = udev_device->monitor_buf; - l = MONITOR_BUF_SIZE; - udev_list_entry_foreach(list_entry, - udev_device_get_properties_list_entry - (udev_device)) { - const char *key; - - key = udev_list_entry_get_name(list_entry); - /* skip private variables */ - if (key[0] == '.') - continue; - - /* add string to envp array */ - udev_device->envp[i++] = s; - if (i + 1 >= ENVP_SIZE) - return -EINVAL; - - /* add property string to monitor buffer */ - l = strpcpyl(&s, l, key, "=", - udev_list_entry_get_value(list_entry), NULL); - if (l == 0) - return -EINVAL; - /* advance past the trailing '\0' that strpcpyl() guarantees */ - s++; - l--; - } - udev_device->envp[i] = NULL; - udev_device->monitor_buf_len = s - udev_device->monitor_buf; - udev_device->envp_uptodate = true; - return 0; +static int +update_envp_monitor_buf (struct udev_device *udev_device) +{ + struct udev_list_entry *list_entry; + char *s; + size_t l; + unsigned int i; + + /* monitor buffer of property strings */ + free (udev_device->monitor_buf); + udev_device->monitor_buf_len = 0; + udev_device->monitor_buf = malloc (MONITOR_BUF_SIZE); + if (udev_device->monitor_buf == NULL) + return -ENOMEM; + + /* envp array, strings will point into monitor buffer */ + if (udev_device->envp == NULL) + udev_device->envp = malloc (sizeof (char *) * ENVP_SIZE); + if (udev_device->envp == NULL) + return -ENOMEM; + + i = 0; + s = udev_device->monitor_buf; + l = MONITOR_BUF_SIZE; + udev_list_entry_foreach (list_entry, + udev_device_get_properties_list_entry + (udev_device)) + { + const char *key; + + key = udev_list_entry_get_name (list_entry); + /* skip private variables */ + if (key[0] == '.') + continue; + + /* add string to envp array */ + udev_device->envp[i++] = s; + if (i + 1 >= ENVP_SIZE) + return -EINVAL; + + /* add property string to monitor buffer */ + l = strpcpyl (&s, l, key, "=", + udev_list_entry_get_value (list_entry), NULL); + if (l == 0) + return -EINVAL; + /* advance past the trailing '\0' that strpcpyl() guarantees */ + s++; + l--; + } + udev_device->envp[i] = NULL; + udev_device->monitor_buf_len = s - udev_device->monitor_buf; + udev_device->envp_uptodate = true; + return 0; } -char **udev_device_get_properties_envp(struct udev_device *udev_device) +char ** +udev_device_get_properties_envp (struct udev_device *udev_device) { - if (!udev_device->envp_uptodate) - if (update_envp_monitor_buf(udev_device) != 0) - return NULL; - return udev_device->envp; + if (!udev_device->envp_uptodate) + if (update_envp_monitor_buf (udev_device) != 0) + return NULL; + return udev_device->envp; } -ssize_t udev_device_get_properties_monitor_buf(struct udev_device * udev_device, - const char **buf) +ssize_t +udev_device_get_properties_monitor_buf (struct udev_device * udev_device, + const char **buf) { - if (!udev_device->envp_uptodate) - if (update_envp_monitor_buf(udev_device) != 0) - return -EINVAL; - *buf = udev_device->monitor_buf; - return udev_device->monitor_buf_len; + if (!udev_device->envp_uptodate) + if (update_envp_monitor_buf (udev_device) != 0) + return -EINVAL; + *buf = udev_device->monitor_buf; + return udev_device->monitor_buf_len; } -int udev_device_get_devlink_priority(struct udev_device *udev_device) +int +udev_device_get_devlink_priority (struct udev_device *udev_device) { - if (!udev_device->info_loaded) - udev_device_read_db(udev_device); - return udev_device->devlink_priority; + if (!udev_device->info_loaded) + udev_device_read_db (udev_device); + return udev_device->devlink_priority; } -int udev_device_set_devlink_priority(struct udev_device *udev_device, int prio) +int +udev_device_set_devlink_priority (struct udev_device *udev_device, int prio) { - udev_device->devlink_priority = prio; - return 0; + udev_device->devlink_priority = prio; + return 0; } -int udev_device_get_watch_handle(struct udev_device *udev_device) +int +udev_device_get_watch_handle (struct udev_device *udev_device) { - if (!udev_device->info_loaded) - udev_device_read_db(udev_device); - return udev_device->watch_handle; + if (!udev_device->info_loaded) + udev_device_read_db (udev_device); + return udev_device->watch_handle; } -int udev_device_set_watch_handle(struct udev_device *udev_device, int handle) +int +udev_device_set_watch_handle (struct udev_device *udev_device, int handle) { - udev_device->watch_handle = handle; - return 0; + udev_device->watch_handle = handle; + return 0; } -bool udev_device_get_db_persist(struct udev_device * udev_device) +bool +udev_device_get_db_persist (struct udev_device * udev_device) { - return udev_device->db_persist; + return udev_device->db_persist; } -void udev_device_set_db_persist(struct udev_device *udev_device) +void +udev_device_set_db_persist (struct udev_device *udev_device) { - udev_device->db_persist = true; + udev_device->db_persist = true; } -int udev_device_rename(struct udev_device *udev_device, const char *name) +int +udev_device_rename (struct udev_device *udev_device, const char *name) { - char *dirname = NULL; - const char *interface; - char *new_syspath; - int r; + char *dirname = NULL; + const char *interface; + char *new_syspath; + int r; - if (udev_device == NULL || name == NULL) - return -EINVAL; + if (udev_device == NULL || name == NULL) + return -EINVAL; - dirname = dirname_malloc(udev_device->syspath); - if (!dirname) - return -ENOMEM; + dirname = dirname_malloc (udev_device->syspath); + if (!dirname) + return -ENOMEM; - new_syspath = strjoina(dirname, "/", name); + new_syspath = strjoina (dirname, "/", name); - r = udev_device_set_syspath(udev_device, new_syspath); - if (r < 0) { - libudev_safe_free(dirname); - return r; - } + r = udev_device_set_syspath (udev_device, new_syspath); + if (r < 0) + { + libudev_safe_free (dirname); + return r; + } - interface = udev_device_get_property_value(udev_device, "INTERFACE"); - if (interface) { - /* like DEVPATH_OLD, INTERFACE_OLD is not saved to the db, but only stays around for the current event */ - udev_device_add_property_internal(udev_device, "INTERFACE_OLD", - interface); - udev_device_add_property_internal(udev_device, "INTERFACE", - name); - } + interface = udev_device_get_property_value (udev_device, "INTERFACE"); + if (interface) + { + /* like DEVPATH_OLD, INTERFACE_OLD is not saved to the db, but only stays around for the current event */ + udev_device_add_property_internal (udev_device, "INTERFACE_OLD", + interface); + udev_device_add_property_internal (udev_device, "INTERFACE", name); + } - libudev_safe_free(dirname); - return 0; + libudev_safe_free (dirname); + return 0; } -struct udev_device *udev_device_shallow_clone(struct udev_device *old_device) +struct udev_device * +udev_device_shallow_clone (struct udev_device *old_device) { - struct udev_device *device; + struct udev_device *device; - if (old_device == NULL) - return NULL; + if (old_device == NULL) + return NULL; - device = udev_device_new(old_device->udev); - if (!device) { - errno = ENOMEM; + device = udev_device_new (old_device->udev); + if (!device) + { + errno = ENOMEM; - return NULL; - } + return NULL; + } - udev_device_set_syspath(device, udev_device_get_syspath(old_device)); - udev_device_set_subsystem(device, - udev_device_get_subsystem(old_device)); - udev_device_set_devnum(device, udev_device_get_devnum(old_device)); + udev_device_set_syspath (device, udev_device_get_syspath (old_device)); + udev_device_set_subsystem (device, udev_device_get_subsystem (old_device)); + udev_device_set_devnum (device, udev_device_get_devnum (old_device)); - return device; + return device; } -struct udev_device *udev_device_clone_with_db(struct udev_device *old_device) +struct udev_device * +udev_device_clone_with_db (struct udev_device *old_device) { - struct udev_device *device; + struct udev_device *device; - device = udev_device_shallow_clone(old_device); - if (!device) - return NULL; + device = udev_device_shallow_clone (old_device); + if (!device) + return NULL; - udev_device_read_db(device); - udev_device_set_info_loaded(device); + udev_device_read_db (device); + udev_device_set_info_loaded (device); - return device; + return device; } // NOTE: expects "key=value" pairs separated by exactly one '\0' -struct udev_device *udev_device_new_from_nulstr(struct udev *udev, char *nulstr, - ssize_t buflen) +struct udev_device * +udev_device_new_from_nulstr (struct udev *udev, char *nulstr, ssize_t buflen) { - struct udev_device *device = NULL; - ssize_t bufpos = 0; + struct udev_device *device = NULL; + ssize_t bufpos = 0; - if (nulstr == NULL || buflen <= 0) { + if (nulstr == NULL || buflen <= 0) + { - errno = EINVAL; + errno = EINVAL; - return NULL; - } + return NULL; + } - device = udev_device_new(udev); - if (!device) { + device = udev_device_new (udev); + if (!device) + { - errno = ENOMEM; - return NULL; - } + errno = ENOMEM; + return NULL; + } - udev_device_set_info_loaded(device); + udev_device_set_info_loaded (device); - while (bufpos < buflen) { - char *key; - size_t keylen; + while (bufpos < buflen) + { + char *key; + size_t keylen; - key = nulstr + bufpos; - keylen = strlen(key); - if (keylen == 0) - break; + key = nulstr + bufpos; + keylen = strlen (key); + if (keylen == 0) + break; - bufpos += keylen + 1; - udev_device_add_property_from_string_parse(device, key); - } + bufpos += keylen + 1; + udev_device_add_property_from_string_parse (device, key); + } - if (udev_device_add_property_from_string_parse_finish(device) < 0) { - log_debug("%s", "missing values, invalid device"); + if (udev_device_add_property_from_string_parse_finish (device) < 0) + { + log_debug ("%s", "missing values, invalid device"); - udev_device_unref(device); + udev_device_unref (device); - errno = EINVAL; + errno = EINVAL; - return NULL; - } + return NULL; + } - return device; + return device; } -struct udev_device *udev_device_new_from_synthetic_event(struct udev *udev, - const char *syspath, - const char *action) +struct udev_device * +udev_device_new_from_synthetic_event (struct udev *udev, + const char *syspath, const char *action) { - struct udev_device *ret; - int r; + struct udev_device *ret; + int r; - if (!action) { - errno = EINVAL; - return NULL; - } + if (!action) + { + errno = EINVAL; + return NULL; + } - ret = udev_device_new_from_syspath(udev, syspath); - if (!ret) - return NULL; + ret = udev_device_new_from_syspath (udev, syspath); + if (!ret) + return NULL; - r = udev_device_read_uevent_file(ret); - if (r < 0) { - udev_device_unref(ret); - errno = -r; - return NULL; - } + r = udev_device_read_uevent_file (ret); + if (r < 0) + { + udev_device_unref (ret); + errno = -r; + return NULL; + } - r = udev_device_set_action(ret, action); - if (r < 0) { - udev_device_unref(ret); - errno = -r; - return NULL; - } + r = udev_device_set_action (ret, action); + if (r < 0) + { + udev_device_unref (ret); + errno = -r; + return NULL; + } - return ret; + return ret; } -int udev_device_copy_properties(struct udev_device *dst, - struct udev_device *src) +int +udev_device_copy_properties (struct udev_device *dst, struct udev_device *src) { - struct udev_list_entry *entry; + struct udev_list_entry *entry; - for ((entry = udev_device_get_properties_list_entry(src)); entry; - entry = udev_list_entry_get_next(entry)) { - const char *key, *value; + for ((entry = udev_device_get_properties_list_entry (src)); entry; + entry = udev_list_entry_get_next (entry)) + { + const char *key, *value; - key = udev_list_entry_get_name(entry); - value = udev_list_entry_get_value(entry); + key = udev_list_entry_get_name (entry); + value = udev_list_entry_get_value (entry); - udev_device_add_property(dst, key, value); - } + udev_device_add_property (dst, key, value); + } - return 0; + return 0; } diff --git a/libudev-compat/libudev-enumerate.c b/libudev-compat/libudev-enumerate.c index c03ff4f..79ccc38 100644 --- a/libudev-compat/libudev-enumerate.c +++ b/libudev-compat/libudev-enumerate.c @@ -47,9 +47,10 @@ * and return a sorted list of devices. */ -struct syspath { - char *syspath; - size_t len; +struct syspath +{ + char *syspath; + size_t len; }; /** @@ -57,23 +58,24 @@ struct syspath { * * Opaque object representing one device lookup/sort context. */ -struct udev_enumerate { - struct udev *udev; - int refcount; - struct udev_list sysattr_match_list; - struct udev_list sysattr_nomatch_list; - struct udev_list subsystem_match_list; - struct udev_list subsystem_nomatch_list; - struct udev_list sysname_match_list; - struct udev_list properties_match_list; - struct udev_list tags_match_list; - struct udev_device *parent_match; - struct udev_list devices_list; - struct syspath *devices; - unsigned int devices_cur; - unsigned int devices_max; - bool devices_uptodate:1; - bool match_is_initialized; +struct udev_enumerate +{ + struct udev *udev; + int refcount; + struct udev_list sysattr_match_list; + struct udev_list sysattr_nomatch_list; + struct udev_list subsystem_match_list; + struct udev_list subsystem_nomatch_list; + struct udev_list sysname_match_list; + struct udev_list properties_match_list; + struct udev_list tags_match_list; + struct udev_device *parent_match; + struct udev_list devices_list; + struct syspath *devices; + unsigned int devices_cur; + unsigned int devices_max; + bool devices_uptodate:1; + bool match_is_initialized; }; /** @@ -84,26 +86,27 @@ struct udev_enumerate { * * Returns: an enumeration context. **/ -struct udev_enumerate *udev_enumerate_new(struct udev *udev) +struct udev_enumerate * +udev_enumerate_new (struct udev *udev) { - struct udev_enumerate *udev_enumerate; - - if (udev == NULL) - return NULL; - udev_enumerate = new0(struct udev_enumerate, 1); - if (udev_enumerate == NULL) - return NULL; - udev_enumerate->refcount = 1; - udev_enumerate->udev = udev; - udev_list_init(udev, &udev_enumerate->sysattr_match_list, false); - udev_list_init(udev, &udev_enumerate->sysattr_nomatch_list, false); - udev_list_init(udev, &udev_enumerate->subsystem_match_list, true); - udev_list_init(udev, &udev_enumerate->subsystem_nomatch_list, true); - udev_list_init(udev, &udev_enumerate->sysname_match_list, true); - udev_list_init(udev, &udev_enumerate->properties_match_list, false); - udev_list_init(udev, &udev_enumerate->tags_match_list, true); - udev_list_init(udev, &udev_enumerate->devices_list, false); - return udev_enumerate; + struct udev_enumerate *udev_enumerate; + + if (udev == NULL) + return NULL; + udev_enumerate = new0 (struct udev_enumerate, 1); + if (udev_enumerate == NULL) + return NULL; + udev_enumerate->refcount = 1; + udev_enumerate->udev = udev; + udev_list_init (udev, &udev_enumerate->sysattr_match_list, false); + udev_list_init (udev, &udev_enumerate->sysattr_nomatch_list, false); + udev_list_init (udev, &udev_enumerate->subsystem_match_list, true); + udev_list_init (udev, &udev_enumerate->subsystem_nomatch_list, true); + udev_list_init (udev, &udev_enumerate->sysname_match_list, true); + udev_list_init (udev, &udev_enumerate->properties_match_list, false); + udev_list_init (udev, &udev_enumerate->tags_match_list, true); + udev_list_init (udev, &udev_enumerate->devices_list, false); + return udev_enumerate; } /** @@ -114,12 +117,13 @@ struct udev_enumerate *udev_enumerate_new(struct udev *udev) * * Returns: the passed enumeration context **/ -struct udev_enumerate *udev_enumerate_ref(struct udev_enumerate *udev_enumerate) +struct udev_enumerate * +udev_enumerate_ref (struct udev_enumerate *udev_enumerate) { - if (udev_enumerate == NULL) - return NULL; - udev_enumerate->refcount++; - return udev_enumerate; + if (udev_enumerate == NULL) + return NULL; + udev_enumerate->refcount++; + return udev_enumerate; } /** @@ -131,30 +135,30 @@ struct udev_enumerate *udev_enumerate_ref(struct udev_enumerate *udev_enumerate) * * Returns: #NULL **/ -struct udev_enumerate *udev_enumerate_unref(struct udev_enumerate - *udev_enumerate) +struct udev_enumerate * +udev_enumerate_unref (struct udev_enumerate *udev_enumerate) { - unsigned int i; - - if (udev_enumerate == NULL) - return NULL; - udev_enumerate->refcount--; - if (udev_enumerate->refcount > 0) - return NULL; - udev_list_cleanup(&udev_enumerate->sysattr_match_list); - udev_list_cleanup(&udev_enumerate->sysattr_nomatch_list); - udev_list_cleanup(&udev_enumerate->subsystem_match_list); - udev_list_cleanup(&udev_enumerate->subsystem_nomatch_list); - udev_list_cleanup(&udev_enumerate->sysname_match_list); - udev_list_cleanup(&udev_enumerate->properties_match_list); - udev_list_cleanup(&udev_enumerate->tags_match_list); - udev_device_unref(udev_enumerate->parent_match); - udev_list_cleanup(&udev_enumerate->devices_list); - for (i = 0; i < udev_enumerate->devices_cur; i++) - free(udev_enumerate->devices[i].syspath); - free(udev_enumerate->devices); - free(udev_enumerate); - return NULL; + unsigned int i; + + if (udev_enumerate == NULL) + return NULL; + udev_enumerate->refcount--; + if (udev_enumerate->refcount > 0) + return NULL; + udev_list_cleanup (&udev_enumerate->sysattr_match_list); + udev_list_cleanup (&udev_enumerate->sysattr_nomatch_list); + udev_list_cleanup (&udev_enumerate->subsystem_match_list); + udev_list_cleanup (&udev_enumerate->subsystem_nomatch_list); + udev_list_cleanup (&udev_enumerate->sysname_match_list); + udev_list_cleanup (&udev_enumerate->properties_match_list); + udev_list_cleanup (&udev_enumerate->tags_match_list); + udev_device_unref (udev_enumerate->parent_match); + udev_list_cleanup (&udev_enumerate->devices_list); + for (i = 0; i < udev_enumerate->devices_cur; i++) + free (udev_enumerate->devices[i].syspath); + free (udev_enumerate->devices); + free (udev_enumerate); + return NULL; } /** @@ -165,108 +169,115 @@ struct udev_enumerate *udev_enumerate_unref(struct udev_enumerate * * Returns: a pointer to the context. */ -struct udev *udev_enumerate_get_udev(struct udev_enumerate *udev_enumerate) +struct udev * +udev_enumerate_get_udev (struct udev_enumerate *udev_enumerate) { - if (udev_enumerate == NULL) - return NULL; - return udev_enumerate->udev; + if (udev_enumerate == NULL) + return NULL; + return udev_enumerate->udev; } -static int syspath_add(struct udev_enumerate *udev_enumerate, - const char *syspath) +static int +syspath_add (struct udev_enumerate *udev_enumerate, const char *syspath) { - char *path; - struct syspath *entry; - - /* double array size if needed */ - if (udev_enumerate->devices_cur >= udev_enumerate->devices_max) { - struct syspath *buf; - unsigned int add; - - add = udev_enumerate->devices_max; - if (add < 1024) - add = 1024; - buf = - realloc(udev_enumerate->devices, - (udev_enumerate->devices_max + - add) * sizeof(struct syspath)); - if (buf == NULL) - return -ENOMEM; - udev_enumerate->devices = buf; - udev_enumerate->devices_max += add; - } - - path = strdup(syspath); - if (path == NULL) - return -ENOMEM; - entry = &udev_enumerate->devices[udev_enumerate->devices_cur]; - entry->syspath = path; - entry->len = strlen(path); - udev_enumerate->devices_cur++; - udev_enumerate->devices_uptodate = false; - return 0; + char *path; + struct syspath *entry; + + /* double array size if needed */ + if (udev_enumerate->devices_cur >= udev_enumerate->devices_max) + { + struct syspath *buf; + unsigned int add; + + add = udev_enumerate->devices_max; + if (add < 1024) + add = 1024; + buf = + realloc (udev_enumerate->devices, + (udev_enumerate->devices_max + + add) * sizeof (struct syspath)); + if (buf == NULL) + return -ENOMEM; + udev_enumerate->devices = buf; + udev_enumerate->devices_max += add; + } + + path = strdup (syspath); + if (path == NULL) + return -ENOMEM; + entry = &udev_enumerate->devices[udev_enumerate->devices_cur]; + entry->syspath = path; + entry->len = strlen (path); + udev_enumerate->devices_cur++; + udev_enumerate->devices_uptodate = false; + return 0; } -static int syspath_cmp(const void *p1, const void *p2) +static int +syspath_cmp (const void *p1, const void *p2) { - const struct syspath *path1 = p1; - const struct syspath *path2 = p2; - size_t len; - int ret; - - len = MIN(path1->len, path2->len); - ret = memcmp(path1->syspath, path2->syspath, len); - if (ret == 0) { - if (path1->len < path2->len) - ret = -1; - else if (path1->len > path2->len) - ret = 1; - } - return ret; + const struct syspath *path1 = p1; + const struct syspath *path2 = p2; + size_t len; + int ret; + + len = MIN (path1->len, path2->len); + ret = memcmp (path1->syspath, path2->syspath, len); + if (ret == 0) + { + if (path1->len < path2->len) + ret = -1; + else if (path1->len > path2->len) + ret = 1; + } + return ret; } /* For devices that should be moved to the absolute end of the list */ -static bool devices_delay_end(struct udev *udev, const char *syspath) +static bool +devices_delay_end (struct udev *udev, const char *syspath) { - static const char *delay_device_list[] = { - "/block/md", - "/block/dm-", - NULL - }; - int i; - - for (i = 0; delay_device_list[i] != NULL; i++) { - if (strstr(syspath + strlen("/sys"), delay_device_list[i]) != - NULL) - return true; - } - return false; + static const char *delay_device_list[] = { + "/block/md", + "/block/dm-", + NULL + }; + int i; + + for (i = 0; delay_device_list[i] != NULL; i++) + { + if (strstr (syspath + strlen ("/sys"), delay_device_list[i]) != NULL) + return true; + } + return false; } /* For devices that should just be moved a little bit later, just * before the point where some common path prefix changes. Returns the * number of characters that make up that common prefix */ -static size_t devices_delay_later(struct udev *udev, const char *syspath) +static size_t +devices_delay_later (struct udev *udev, const char *syspath) { - const char *c; - - /* For sound cards the control device must be enumerated last - * to make sure it's the final device node that gets ACLs - * applied. Applications rely on this fact and use ACL changes - * on the control node as an indicator that the ACL change of - * the entire sound card completed. The kernel makes this - * guarantee when creating those devices, and hence we should - * too when enumerating them. */ - - if ((c = strstr(syspath, "/sound/card"))) { - c += 11; - c += strcspn(c, "/"); - - if (startswith(c, "/controlC")) - return c - syspath + 1; - } - - return 0; + const char *c; + + /* For sound cards the control device must be enumerated last + * to make sure it's the final device node that gets ACLs + * applied. Applications rely on this fact and use ACL changes + * on the control node as an indicator that the ACL change of + * the entire sound card completed. The kernel makes this + * guarantee when creating those devices, and hence we should + * too when enumerating them. */ + + if ((c = strstr (syspath, "/sound/card"))) + { + c += 11; + c += strcspn (c, "/"); + + if (startswith (c, "/controlC")) + return c - syspath + 1; + } + + return 0; } /** @@ -277,92 +288,94 @@ static size_t devices_delay_later(struct udev *udev, const char *syspath) * * Returns: a udev_list_entry. */ -struct udev_list_entry *udev_enumerate_get_list_entry(struct udev_enumerate - *udev_enumerate) +struct udev_list_entry * +udev_enumerate_get_list_entry (struct udev_enumerate *udev_enumerate) { - if (udev_enumerate == NULL) - return NULL; - if (!udev_enumerate->devices_uptodate) { - unsigned int i; - int move_later = -1; - unsigned int max; - struct syspath *prev = NULL; - size_t move_later_prefix = 0; - - udev_list_cleanup(&udev_enumerate->devices_list); - qsort_safe(udev_enumerate->devices, udev_enumerate->devices_cur, - sizeof(struct syspath), syspath_cmp); - - max = udev_enumerate->devices_cur; - for (i = 0; i < max; i++) { - struct syspath *entry = &udev_enumerate->devices[i]; - - /* skip duplicated entries */ - if (prev != NULL && - entry->len == prev->len && - memcmp(entry->syspath, prev->syspath, - entry->len) == 0) - continue; - prev = entry; - - /* skip to be delayed devices, and add them to the end of the list */ - if (devices_delay_end - (udev_enumerate->udev, entry->syspath)) { - syspath_add(udev_enumerate, entry->syspath); - /* need to update prev here for the case realloc() gives a different address */ - prev = &udev_enumerate->devices[i]; - continue; - } - - /* skip to be delayed devices, and move the to - * the point where the prefix changes. We can - * only move one item at a time. */ - if (move_later == -1) { - move_later_prefix = - devices_delay_later(udev_enumerate->udev, - entry->syspath); - - if (move_later_prefix > 0) { - move_later = i; - continue; - } - } - - if ((move_later >= 0) && - !strneq(entry->syspath, - udev_enumerate->devices[move_later].syspath, - move_later_prefix)) { - - udev_list_entry_add(&udev_enumerate-> - devices_list, - udev_enumerate-> - devices[move_later].syspath, - NULL); - move_later = -1; - } - - udev_list_entry_add(&udev_enumerate->devices_list, - entry->syspath, NULL); + if (udev_enumerate == NULL) + return NULL; + if (!udev_enumerate->devices_uptodate) + { + unsigned int i; + int move_later = -1; + unsigned int max; + struct syspath *prev = NULL; + size_t move_later_prefix = 0; + + udev_list_cleanup (&udev_enumerate->devices_list); + qsort_safe (udev_enumerate->devices, udev_enumerate->devices_cur, + sizeof (struct syspath), syspath_cmp); + + max = udev_enumerate->devices_cur; + for (i = 0; i < max; i++) + { + struct syspath *entry = &udev_enumerate->devices[i]; + + /* skip duplicated entries */ + if (prev != NULL && + entry->len == prev->len && + memcmp (entry->syspath, prev->syspath, entry->len) == 0) + continue; + prev = entry; + + /* skip to be delayed devices, and add them to the end of the list */ + if (devices_delay_end (udev_enumerate->udev, entry->syspath)) + { + syspath_add (udev_enumerate, entry->syspath); + /* need to update prev here for the case realloc() gives a different address */ + prev = &udev_enumerate->devices[i]; + continue; + } + + /* skip to be delayed devices, and move the to + * the point where the prefix changes. We can + * only move one item at a time. */ + if (move_later == -1) + { + move_later_prefix = + devices_delay_later (udev_enumerate->udev, entry->syspath); + + if (move_later_prefix > 0) + { + move_later = i; + continue; } + } + + if ((move_later >= 0) && + !strneq (entry->syspath, + udev_enumerate->devices[move_later].syspath, + move_later_prefix)) + { + + udev_list_entry_add (&udev_enumerate->devices_list, + udev_enumerate->devices[move_later]. + syspath, NULL); + move_later = -1; + } + + udev_list_entry_add (&udev_enumerate->devices_list, + entry->syspath, NULL); + } - if (move_later >= 0) - udev_list_entry_add(&udev_enumerate->devices_list, - udev_enumerate->devices[move_later]. - syspath, NULL); + if (move_later >= 0) + udev_list_entry_add (&udev_enumerate->devices_list, + udev_enumerate->devices[move_later].syspath, + NULL); - /* add and cleanup delayed devices from end of list */ - for (i = max; i < udev_enumerate->devices_cur; i++) { - struct syspath *entry = &udev_enumerate->devices[i]; + /* add and cleanup delayed devices from end of list */ + for (i = max; i < udev_enumerate->devices_cur; i++) + { + struct syspath *entry = &udev_enumerate->devices[i]; - udev_list_entry_add(&udev_enumerate->devices_list, - entry->syspath, NULL); - free(entry->syspath); - } - udev_enumerate->devices_cur = max; - - udev_enumerate->devices_uptodate = true; + udev_list_entry_add (&udev_enumerate->devices_list, + entry->syspath, NULL); + free (entry->syspath); } - return udev_list_get_entry(&udev_enumerate->devices_list); + udev_enumerate->devices_cur = max; + + udev_enumerate->devices_uptodate = true; + } + return udev_list_get_entry (&udev_enumerate->devices_list); } /** @@ -374,17 +387,18 @@ struct udev_list_entry *udev_enumerate_get_list_entry(struct udev_enumerate * * Returns: 0 on success, otherwise a negative error value. */ -int udev_enumerate_add_match_subsystem(struct udev_enumerate *udev_enumerate, - const char *subsystem) +int +udev_enumerate_add_match_subsystem (struct udev_enumerate *udev_enumerate, + const char *subsystem) { - if (udev_enumerate == NULL) - return -EINVAL; - if (subsystem == NULL) - return 0; - if (udev_list_entry_add - (&udev_enumerate->subsystem_match_list, subsystem, NULL) == NULL) - return -ENOMEM; - return 0; + if (udev_enumerate == NULL) + return -EINVAL; + if (subsystem == NULL) + return 0; + if (udev_list_entry_add + (&udev_enumerate->subsystem_match_list, subsystem, NULL) == NULL) + return -ENOMEM; + return 0; } /** @@ -396,17 +410,18 @@ int udev_enumerate_add_match_subsystem(struct udev_enumerate *udev_enumerate, * * Returns: 0 on success, otherwise a negative error value. */ -int udev_enumerate_add_nomatch_subsystem(struct udev_enumerate *udev_enumerate, - const char *subsystem) +int +udev_enumerate_add_nomatch_subsystem (struct udev_enumerate *udev_enumerate, + const char *subsystem) { - if (udev_enumerate == NULL) - return -EINVAL; - if (subsystem == NULL) - return 0; - if (udev_list_entry_add - (&udev_enumerate->subsystem_nomatch_list, subsystem, NULL) == NULL) - return -ENOMEM; - return 0; + if (udev_enumerate == NULL) + return -EINVAL; + if (subsystem == NULL) + return 0; + if (udev_list_entry_add + (&udev_enumerate->subsystem_nomatch_list, subsystem, NULL) == NULL) + return -ENOMEM; + return 0; } /** @@ -419,17 +434,18 @@ int udev_enumerate_add_nomatch_subsystem(struct udev_enumerate *udev_enumerate, * * Returns: 0 on success, otherwise a negative error value. */ -int udev_enumerate_add_match_sysattr(struct udev_enumerate *udev_enumerate, - const char *sysattr, const char *value) +int +udev_enumerate_add_match_sysattr (struct udev_enumerate *udev_enumerate, + const char *sysattr, const char *value) { - if (udev_enumerate == NULL) - return -EINVAL; - if (sysattr == NULL) - return 0; - if (udev_list_entry_add - (&udev_enumerate->sysattr_match_list, sysattr, value) == NULL) - return -ENOMEM; - return 0; + if (udev_enumerate == NULL) + return -EINVAL; + if (sysattr == NULL) + return 0; + if (udev_list_entry_add + (&udev_enumerate->sysattr_match_list, sysattr, value) == NULL) + return -ENOMEM; + return 0; } /** @@ -442,38 +458,42 @@ int udev_enumerate_add_match_sysattr(struct udev_enumerate *udev_enumerate, * * Returns: 0 on success, otherwise a negative error value. */ -int udev_enumerate_add_nomatch_sysattr(struct udev_enumerate *udev_enumerate, - const char *sysattr, const char *value) +int +udev_enumerate_add_nomatch_sysattr (struct udev_enumerate *udev_enumerate, + const char *sysattr, const char *value) { - if (udev_enumerate == NULL) - return -EINVAL; - if (sysattr == NULL) - return 0; - if (udev_list_entry_add - (&udev_enumerate->sysattr_nomatch_list, sysattr, value) == NULL) - return -ENOMEM; - return 0; + if (udev_enumerate == NULL) + return -EINVAL; + if (sysattr == NULL) + return 0; + if (udev_list_entry_add + (&udev_enumerate->sysattr_nomatch_list, sysattr, value) == NULL) + return -ENOMEM; + return 0; } -static int match_sysattr_value(struct udev_device *dev, const char *sysattr, - const char *match_val) +static int +match_sysattr_value (struct udev_device *dev, const char *sysattr, + const char *match_val) { - const char *val = NULL; - bool match = false; - - val = udev_device_get_sysattr_value(dev, sysattr); - if (val == NULL) - goto exit; - if (match_val == NULL) { - match = true; - goto exit; - } - if (fnmatch(match_val, val, 0) == 0) { - match = true; - goto exit; - } - exit: - return match; + const char *val = NULL; + bool match = false; + + val = udev_device_get_sysattr_value (dev, sysattr); + if (val == NULL) + goto exit; + if (match_val == NULL) + { + match = true; + goto exit; + } + if (fnmatch (match_val, val, 0) == 0) + { + match = true; + goto exit; + } +exit: + return match; } /** @@ -486,17 +506,18 @@ static int match_sysattr_value(struct udev_device *dev, const char *sysattr, * * Returns: 0 on success, otherwise a negative error value. */ -int udev_enumerate_add_match_property(struct udev_enumerate *udev_enumerate, - const char *property, const char *value) +int +udev_enumerate_add_match_property (struct udev_enumerate *udev_enumerate, + const char *property, const char *value) { - if (udev_enumerate == NULL) - return -EINVAL; - if (property == NULL) - return 0; - if (udev_list_entry_add - (&udev_enumerate->properties_match_list, property, value) == NULL) - return -ENOMEM; - return 0; + if (udev_enumerate == NULL) + return -EINVAL; + if (property == NULL) + return 0; + if (udev_list_entry_add + (&udev_enumerate->properties_match_list, property, value) == NULL) + return -ENOMEM; + return 0; } /** @@ -508,17 +529,18 @@ int udev_enumerate_add_match_property(struct udev_enumerate *udev_enumerate, * * Returns: 0 on success, otherwise a negative error value. */ -int udev_enumerate_add_match_tag(struct udev_enumerate *udev_enumerate, - const char *tag) +int +udev_enumerate_add_match_tag (struct udev_enumerate *udev_enumerate, + const char *tag) { - if (udev_enumerate == NULL) - return -EINVAL; - if (tag == NULL) - return 0; - if (udev_list_entry_add(&udev_enumerate->tags_match_list, tag, NULL) == - NULL) - return -ENOMEM; - return 0; + if (udev_enumerate == NULL) + return -EINVAL; + if (tag == NULL) + return 0; + if (udev_list_entry_add (&udev_enumerate->tags_match_list, tag, NULL) == + NULL) + return -ENOMEM; + return 0; } /** @@ -534,17 +556,18 @@ int udev_enumerate_add_match_tag(struct udev_enumerate *udev_enumerate, * * Returns: 0 on success, otherwise a negative error value. */ -int udev_enumerate_add_match_parent(struct udev_enumerate *udev_enumerate, - struct udev_device *parent) +int +udev_enumerate_add_match_parent (struct udev_enumerate *udev_enumerate, + struct udev_device *parent) { - if (udev_enumerate == NULL) - return -EINVAL; - if (parent == NULL) - return 0; - if (udev_enumerate->parent_match != NULL) - udev_device_unref(udev_enumerate->parent_match); - udev_enumerate->parent_match = udev_device_ref(parent); - return 0; + if (udev_enumerate == NULL) + return -EINVAL; + if (parent == NULL) + return 0; + if (udev_enumerate->parent_match != NULL) + udev_device_unref (udev_enumerate->parent_match); + udev_enumerate->parent_match = udev_device_ref (parent); + return 0; } /** @@ -565,13 +588,14 @@ int udev_enumerate_add_match_parent(struct udev_enumerate *udev_enumerate, * * Returns: 0 on success, otherwise a negative error value. */ -int udev_enumerate_add_match_is_initialized(struct udev_enumerate - *udev_enumerate) +int +udev_enumerate_add_match_is_initialized (struct udev_enumerate + *udev_enumerate) { - if (udev_enumerate == NULL) - return -EINVAL; - udev_enumerate->match_is_initialized = true; - return 0; + if (udev_enumerate == NULL) + return -EINVAL; + udev_enumerate->match_is_initialized = true; + return 0; } /** @@ -583,268 +607,274 @@ int udev_enumerate_add_match_is_initialized(struct udev_enumerate * * Returns: 0 on success, otherwise a negative error value. */ -int udev_enumerate_add_match_sysname(struct udev_enumerate *udev_enumerate, - const char *sysname) +int +udev_enumerate_add_match_sysname (struct udev_enumerate *udev_enumerate, + const char *sysname) { - if (udev_enumerate == NULL) - return -EINVAL; - if (sysname == NULL) - return 0; - if (udev_list_entry_add - (&udev_enumerate->sysname_match_list, sysname, NULL) == NULL) - return -ENOMEM; - return 0; + if (udev_enumerate == NULL) + return -EINVAL; + if (sysname == NULL) + return 0; + if (udev_list_entry_add + (&udev_enumerate->sysname_match_list, sysname, NULL) == NULL) + return -ENOMEM; + return 0; } -static bool match_sysattr(struct udev_enumerate *udev_enumerate, - struct udev_device *dev) +static bool +match_sysattr (struct udev_enumerate *udev_enumerate, struct udev_device *dev) { - struct udev_list_entry *list_entry; - - /* skip list */ - udev_list_entry_foreach(list_entry, - udev_list_get_entry(&udev_enumerate-> - sysattr_nomatch_list)) { - if (match_sysattr_value - (dev, udev_list_entry_get_name(list_entry), - udev_list_entry_get_value(list_entry))) - return false; - } - /* include list */ - if (udev_list_get_entry(&udev_enumerate->sysattr_match_list) != NULL) { - udev_list_entry_foreach(list_entry, - udev_list_get_entry(&udev_enumerate-> - sysattr_match_list)) - { - /* anything that does not match, will make it FALSE */ - if (!match_sysattr_value - (dev, udev_list_entry_get_name(list_entry), - udev_list_entry_get_value(list_entry))) - return false; - } - return true; - } - return true; + struct udev_list_entry *list_entry; + + /* skip list */ + udev_list_entry_foreach (list_entry, + udev_list_get_entry + (&udev_enumerate->sysattr_nomatch_list)) + { + if (match_sysattr_value + (dev, udev_list_entry_get_name (list_entry), + udev_list_entry_get_value (list_entry))) + return false; + } + /* include list */ + if (udev_list_get_entry (&udev_enumerate->sysattr_match_list) != NULL) + { + udev_list_entry_foreach (list_entry, + udev_list_get_entry + (&udev_enumerate->sysattr_match_list)) + { + /* anything that does not match, will make it FALSE */ + if (!match_sysattr_value + (dev, udev_list_entry_get_name (list_entry), + udev_list_entry_get_value (list_entry))) + return false; + } + return true; + } + return true; } -static bool match_property(struct udev_enumerate *udev_enumerate, - struct udev_device *dev) +static bool +match_property (struct udev_enumerate *udev_enumerate, + struct udev_device *dev) { - struct udev_list_entry *list_entry; - bool match = false; - - /* no match always matches */ - if (udev_list_get_entry(&udev_enumerate->properties_match_list) == NULL) - return true; - - /* loop over matches */ - udev_list_entry_foreach(list_entry, - udev_list_get_entry(&udev_enumerate-> - properties_match_list)) { - const char *match_key = udev_list_entry_get_name(list_entry); - const char *match_value = udev_list_entry_get_value(list_entry); - struct udev_list_entry *property_entry; - - /* loop over device properties */ - udev_list_entry_foreach(property_entry, - udev_device_get_properties_list_entry - (dev)) { - const char *dev_key = - udev_list_entry_get_name(property_entry); - const char *dev_value = - udev_list_entry_get_value(property_entry); - - if (fnmatch(match_key, dev_key, 0) != 0) - continue; - if (match_value == NULL && dev_value == NULL) { - match = true; - goto out; - } - if (match_value == NULL || dev_value == NULL) - continue; - if (fnmatch(match_value, dev_value, 0) == 0) { - match = true; - goto out; - } - } + struct udev_list_entry *list_entry; + bool match = false; + + /* no match always matches */ + if (udev_list_get_entry (&udev_enumerate->properties_match_list) == NULL) + return true; + + /* loop over matches */ + udev_list_entry_foreach (list_entry, + udev_list_get_entry + (&udev_enumerate->properties_match_list)) + { + const char *match_key = udev_list_entry_get_name (list_entry); + const char *match_value = udev_list_entry_get_value (list_entry); + struct udev_list_entry *property_entry; + + /* loop over device properties */ + udev_list_entry_foreach (property_entry, + udev_device_get_properties_list_entry (dev)) + { + const char *dev_key = udev_list_entry_get_name (property_entry); + const char *dev_value = udev_list_entry_get_value (property_entry); + + if (fnmatch (match_key, dev_key, 0) != 0) + continue; + if (match_value == NULL && dev_value == NULL) + { + match = true; + goto out; + } + if (match_value == NULL || dev_value == NULL) + continue; + if (fnmatch (match_value, dev_value, 0) == 0) + { + match = true; + goto out; } - out: - return match; + } + } +out: + return match; } -static bool match_tag(struct udev_enumerate *udev_enumerate, - struct udev_device *dev) +static bool +match_tag (struct udev_enumerate *udev_enumerate, struct udev_device *dev) { - struct udev_list_entry *list_entry; + struct udev_list_entry *list_entry; - /* no match always matches */ - if (udev_list_get_entry(&udev_enumerate->tags_match_list) == NULL) - return true; + /* no match always matches */ + if (udev_list_get_entry (&udev_enumerate->tags_match_list) == NULL) + return true; - /* loop over matches */ - udev_list_entry_foreach(list_entry, - udev_list_get_entry(&udev_enumerate-> - tags_match_list)) - if (!udev_device_has_tag(dev, udev_list_entry_get_name(list_entry))) - return false; + /* loop over matches */ + udev_list_entry_foreach (list_entry, + udev_list_get_entry + (&udev_enumerate->tags_match_list)) + if (!udev_device_has_tag (dev, udev_list_entry_get_name (list_entry))) + return false; - return true; + return true; } -static bool match_parent(struct udev_enumerate *udev_enumerate, - struct udev_device *dev) +static bool +match_parent (struct udev_enumerate *udev_enumerate, struct udev_device *dev) { - if (udev_enumerate->parent_match == NULL) - return true; + if (udev_enumerate->parent_match == NULL) + return true; - return startswith(udev_device_get_devpath(dev), - udev_device_get_devpath(udev_enumerate-> - parent_match)); + return startswith (udev_device_get_devpath (dev), + udev_device_get_devpath (udev_enumerate->parent_match)); } -static bool match_sysname(struct udev_enumerate *udev_enumerate, - const char *sysname) +static bool +match_sysname (struct udev_enumerate *udev_enumerate, const char *sysname) { - struct udev_list_entry *list_entry; - - if (udev_list_get_entry(&udev_enumerate->sysname_match_list) == NULL) - return true; - - udev_list_entry_foreach(list_entry, - udev_list_get_entry(&udev_enumerate-> - sysname_match_list)) { - if (fnmatch(udev_list_entry_get_name(list_entry), sysname, 0) != - 0) - continue; - return true; - } - return false; + struct udev_list_entry *list_entry; + + if (udev_list_get_entry (&udev_enumerate->sysname_match_list) == NULL) + return true; + + udev_list_entry_foreach (list_entry, + udev_list_get_entry + (&udev_enumerate->sysname_match_list)) + { + if (fnmatch (udev_list_entry_get_name (list_entry), sysname, 0) != 0) + continue; + return true; + } + return false; } -static int scan_dir_and_add_devices(struct udev_enumerate *udev_enumerate, - const char *basedir, const char *subdir1, - const char *subdir2) +static int +scan_dir_and_add_devices (struct udev_enumerate *udev_enumerate, + const char *basedir, const char *subdir1, + const char *subdir2) { - char path[UTIL_PATH_SIZE]; - size_t l; - char *s; - DIR *dir; - struct dirent *dent; - - s = path; - l = strpcpyl(&s, sizeof(path), "/sys/", basedir, NULL); - if (subdir1 != NULL) - l = strpcpyl(&s, l, "/", subdir1, NULL); - if (subdir2 != NULL) - strpcpyl(&s, l, "/", subdir2, NULL); - dir = opendir(path); - if (dir == NULL) - return -ENOENT; - for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) { - char syspath[UTIL_PATH_SIZE]; - struct udev_device *dev; - - if (dent->d_name[0] == '.') - continue; - - if (!match_sysname(udev_enumerate, dent->d_name)) - continue; - - strscpyl(syspath, sizeof(syspath), path, "/", dent->d_name, - NULL); - dev = - udev_device_new_from_syspath(udev_enumerate->udev, syspath); - if (dev == NULL) - continue; - - if (udev_enumerate->match_is_initialized) { - /* - * All devices with a device node or network interfaces - * possibly need udev to adjust the device node permission - * or context, or rename the interface before it can be - * reliably used from other processes. - * - * For now, we can only check these types of devices, we - * might not store a database, and have no way to find out - * for all other types of devices. - */ - if (!udev_device_get_is_initialized(dev) && - (major(udev_device_get_devnum(dev)) > 0 - || udev_device_get_ifindex(dev) > 0)) - goto nomatch; - } - if (!match_parent(udev_enumerate, dev)) - goto nomatch; - if (!match_tag(udev_enumerate, dev)) - goto nomatch; - if (!match_property(udev_enumerate, dev)) - goto nomatch; - if (!match_sysattr(udev_enumerate, dev)) - goto nomatch; - - syspath_add(udev_enumerate, udev_device_get_syspath(dev)); - nomatch: - udev_device_unref(dev); + char path[UTIL_PATH_SIZE]; + size_t l; + char *s; + DIR *dir; + struct dirent *dent; + + s = path; + l = strpcpyl (&s, sizeof (path), "/sys/", basedir, NULL); + if (subdir1 != NULL) + l = strpcpyl (&s, l, "/", subdir1, NULL); + if (subdir2 != NULL) + strpcpyl (&s, l, "/", subdir2, NULL); + dir = opendir (path); + if (dir == NULL) + return -ENOENT; + for (dent = readdir (dir); dent != NULL; dent = readdir (dir)) + { + char syspath[UTIL_PATH_SIZE]; + struct udev_device *dev; + + if (dent->d_name[0] == '.') + continue; + + if (!match_sysname (udev_enumerate, dent->d_name)) + continue; + + strscpyl (syspath, sizeof (syspath), path, "/", dent->d_name, NULL); + dev = udev_device_new_from_syspath (udev_enumerate->udev, syspath); + if (dev == NULL) + continue; + + if (udev_enumerate->match_is_initialized) + { + /* + * All devices with a device node or network interfaces + * possibly need udev to adjust the device node permission + * or context, or rename the interface before it can be + * reliably used from other processes. + * + * For now, we can only check these types of devices, we + * might not store a database, and have no way to find out + * for all other types of devices. + */ + if (!udev_device_get_is_initialized (dev) && + (major (udev_device_get_devnum (dev)) > 0 + || udev_device_get_ifindex (dev) > 0)) + goto nomatch; } - closedir(dir); - return 0; + if (!match_parent (udev_enumerate, dev)) + goto nomatch; + if (!match_tag (udev_enumerate, dev)) + goto nomatch; + if (!match_property (udev_enumerate, dev)) + goto nomatch; + if (!match_sysattr (udev_enumerate, dev)) + goto nomatch; + + syspath_add (udev_enumerate, udev_device_get_syspath (dev)); + nomatch: + udev_device_unref (dev); + } + closedir (dir); + return 0; } -static bool match_subsystem(struct udev_enumerate *udev_enumerate, - const char *subsystem) +static bool +match_subsystem (struct udev_enumerate *udev_enumerate, const char *subsystem) { - struct udev_list_entry *list_entry; - - if (!subsystem) - return false; - - udev_list_entry_foreach(list_entry, - udev_list_get_entry(&udev_enumerate-> - subsystem_nomatch_list)) { - if (fnmatch(udev_list_entry_get_name(list_entry), subsystem, 0) - == 0) - return false; - } - - if (udev_list_get_entry(&udev_enumerate->subsystem_match_list) != NULL) { - udev_list_entry_foreach(list_entry, - udev_list_get_entry(&udev_enumerate-> - subsystem_match_list)) - { - if (fnmatch - (udev_list_entry_get_name(list_entry), subsystem, - 0) == 0) - return true; - } - return false; - } - - return true; + struct udev_list_entry *list_entry; + + if (!subsystem) + return false; + + udev_list_entry_foreach (list_entry, + udev_list_get_entry + (&udev_enumerate->subsystem_nomatch_list)) + { + if (fnmatch (udev_list_entry_get_name (list_entry), subsystem, 0) == 0) + return false; + } + + if (udev_list_get_entry (&udev_enumerate->subsystem_match_list) != NULL) + { + udev_list_entry_foreach (list_entry, + udev_list_get_entry + (&udev_enumerate->subsystem_match_list)) + { + if (fnmatch + (udev_list_entry_get_name (list_entry), subsystem, 0) == 0) + return true; + } + return false; + } + + return true; } -static int scan_dir(struct udev_enumerate *udev_enumerate, const char *basedir, - const char *subdir, const char *subsystem) +static int +scan_dir (struct udev_enumerate *udev_enumerate, const char *basedir, + const char *subdir, const char *subsystem) { - char path[UTIL_PATH_SIZE]; - DIR *dir; - struct dirent *dent; - - strscpyl(path, sizeof(path), "/sys/", basedir, NULL); - dir = opendir(path); - if (dir == NULL) - return -1; - for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) { - if (dent->d_name[0] == '.') - continue; - if (!match_subsystem - (udev_enumerate, - subsystem != NULL ? subsystem : dent->d_name)) - continue; - scan_dir_and_add_devices(udev_enumerate, basedir, dent->d_name, - subdir); - } - closedir(dir); - return 0; + char path[UTIL_PATH_SIZE]; + DIR *dir; + struct dirent *dent; + + strscpyl (path, sizeof (path), "/sys/", basedir, NULL); + dir = opendir (path); + if (dir == NULL) + return -1; + for (dent = readdir (dir); dent != NULL; dent = readdir (dir)) + { + if (dent->d_name[0] == '.') + continue; + if (!match_subsystem + (udev_enumerate, subsystem != NULL ? subsystem : dent->d_name)) + continue; + scan_dir_and_add_devices (udev_enumerate, basedir, dent->d_name, + subdir); + } + closedir (dir); + return 0; } /** @@ -856,153 +886,161 @@ static int scan_dir(struct udev_enumerate *udev_enumerate, const char *basedir, * * Returns: 0 on success, otherwise a negative error value. */ -int udev_enumerate_add_syspath(struct udev_enumerate *udev_enumerate, - const char *syspath) -{ - struct udev_device *udev_device; - - if (udev_enumerate == NULL) - return -EINVAL; - if (syspath == NULL) - return 0; - /* resolve to real syspath */ - udev_device = - udev_device_new_from_syspath(udev_enumerate->udev, syspath); - if (udev_device == NULL) - return -EINVAL; - syspath_add(udev_enumerate, udev_device_get_syspath(udev_device)); - udev_device_unref(udev_device); - return 0; -} - -static int scan_devices_tags(struct udev_enumerate *udev_enumerate) +int +udev_enumerate_add_syspath (struct udev_enumerate *udev_enumerate, + const char *syspath) { - struct udev_list_entry *list_entry; - - /* scan only tagged devices, use tags reverse-index, instead of searching all devices in /sys */ - udev_list_entry_foreach(list_entry, - udev_list_get_entry(&udev_enumerate-> - tags_match_list)) { - DIR *dir; - struct dirent *dent; - char path[UTIL_PATH_SIZE]; - - strscpyl(path, sizeof(path), "/run/udev/tags/", - udev_list_entry_get_name(list_entry), NULL); - dir = opendir(path); - if (dir == NULL) - continue; - for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) { - struct udev_device *dev; - - if (dent->d_name[0] == '.') - continue; - - dev = - udev_device_new_from_device_id(udev_enumerate->udev, - dent->d_name); - if (dev == NULL) - continue; - - if (!match_subsystem - (udev_enumerate, udev_device_get_subsystem(dev))) - goto nomatch; - if (!match_sysname - (udev_enumerate, udev_device_get_sysname(dev))) - goto nomatch; - if (!match_parent(udev_enumerate, dev)) - goto nomatch; - if (!match_property(udev_enumerate, dev)) - goto nomatch; - if (!match_sysattr(udev_enumerate, dev)) - goto nomatch; - - syspath_add(udev_enumerate, - udev_device_get_syspath(dev)); - nomatch: - udev_device_unref(dev); - } - closedir(dir); - } - return 0; + struct udev_device *udev_device; + + if (udev_enumerate == NULL) + return -EINVAL; + if (syspath == NULL) + return 0; + /* resolve to real syspath */ + udev_device = udev_device_new_from_syspath (udev_enumerate->udev, syspath); + if (udev_device == NULL) + return -EINVAL; + syspath_add (udev_enumerate, udev_device_get_syspath (udev_device)); + udev_device_unref (udev_device); + return 0; } -static int parent_add_child(struct udev_enumerate *enumerate, const char *path) +static int +scan_devices_tags (struct udev_enumerate *udev_enumerate) { + struct udev_list_entry *list_entry; + + /* scan only tagged devices, use tags reverse-index, instead of searching all devices in /sys */ + udev_list_entry_foreach (list_entry, + udev_list_get_entry + (&udev_enumerate->tags_match_list)) + { + DIR *dir; + struct dirent *dent; + char path[UTIL_PATH_SIZE]; + + strscpyl (path, sizeof (path), "/run/udev/tags/", + udev_list_entry_get_name (list_entry), NULL); + dir = opendir (path); + if (dir == NULL) + continue; + for (dent = readdir (dir); dent != NULL; dent = readdir (dir)) + { struct udev_device *dev; - int r = 0; - dev = udev_device_new_from_syspath(enumerate->udev, path); + if (dent->d_name[0] == '.') + continue; + + dev = + udev_device_new_from_device_id (udev_enumerate->udev, dent->d_name); if (dev == NULL) - return -ENODEV; - - if (!match_subsystem(enumerate, udev_device_get_subsystem(dev))) - goto nomatch; - if (!match_sysname(enumerate, udev_device_get_sysname(dev))) - goto nomatch; - if (!match_property(enumerate, dev)) - goto nomatch; - if (!match_sysattr(enumerate, dev)) - goto nomatch; - - syspath_add(enumerate, udev_device_get_syspath(dev)); - r = 1; - - nomatch: - udev_device_unref(dev); - return r; + continue; + + if (!match_subsystem + (udev_enumerate, udev_device_get_subsystem (dev))) + goto nomatch; + if (!match_sysname (udev_enumerate, udev_device_get_sysname (dev))) + goto nomatch; + if (!match_parent (udev_enumerate, dev)) + goto nomatch; + if (!match_property (udev_enumerate, dev)) + goto nomatch; + if (!match_sysattr (udev_enumerate, dev)) + goto nomatch; + + syspath_add (udev_enumerate, udev_device_get_syspath (dev)); + nomatch: + udev_device_unref (dev); + } + closedir (dir); + } + return 0; } -static int parent_crawl_children(struct udev_enumerate *enumerate, - const char *path, int maxdepth) +static int +parent_add_child (struct udev_enumerate *enumerate, const char *path) { - DIR *d; - struct dirent *dent; - - d = opendir(path); - if (d == NULL) - return -errno; - - for (dent = readdir(d); dent != NULL; dent = readdir(d)) { - char *child; - - if (dent->d_name[0] == '.') - continue; - if (dent->d_type != DT_DIR) - continue; - if (asprintf(&child, "%s/%s", path, dent->d_name) < 0) - continue; - parent_add_child(enumerate, child); - if (maxdepth > 0) - parent_crawl_children(enumerate, child, maxdepth - 1); - free(child); - } + struct udev_device *dev; + int r = 0; + + dev = udev_device_new_from_syspath (enumerate->udev, path); + if (dev == NULL) + return -ENODEV; + + if (!match_subsystem (enumerate, udev_device_get_subsystem (dev))) + goto nomatch; + if (!match_sysname (enumerate, udev_device_get_sysname (dev))) + goto nomatch; + if (!match_property (enumerate, dev)) + goto nomatch; + if (!match_sysattr (enumerate, dev)) + goto nomatch; + + syspath_add (enumerate, udev_device_get_syspath (dev)); + r = 1; + +nomatch: + udev_device_unref (dev); + return r; +} - closedir(d); - return 0; +static int +parent_crawl_children (struct udev_enumerate *enumerate, + const char *path, int maxdepth) +{ + DIR *d; + struct dirent *dent; + + d = opendir (path); + if (d == NULL) + return -errno; + + for (dent = readdir (d); dent != NULL; dent = readdir (d)) + { + char *child; + + if (dent->d_name[0] == '.') + continue; + if (dent->d_type != DT_DIR) + continue; + if (asprintf (&child, "%s/%s", path, dent->d_name) < 0) + continue; + parent_add_child (enumerate, child); + if (maxdepth > 0) + parent_crawl_children (enumerate, child, maxdepth - 1); + free (child); + } + + closedir (d); + return 0; } -static int scan_devices_children(struct udev_enumerate *enumerate) +static int +scan_devices_children (struct udev_enumerate *enumerate) { - const char *path; + const char *path; - path = udev_device_get_syspath(enumerate->parent_match); - parent_add_child(enumerate, path); - return parent_crawl_children(enumerate, path, 256); + path = udev_device_get_syspath (enumerate->parent_match); + parent_add_child (enumerate, path); + return parent_crawl_children (enumerate, path, 256); } -static int scan_devices_all(struct udev_enumerate *udev_enumerate) +static int +scan_devices_all (struct udev_enumerate *udev_enumerate) { - struct stat statbuf; - - if (stat("/sys/subsystem", &statbuf) == 0) { - /* we have /subsystem/, forget all the old stuff */ - scan_dir(udev_enumerate, "subsystem", "devices", NULL); - } else { - scan_dir(udev_enumerate, "bus", "devices", NULL); - scan_dir(udev_enumerate, "class", NULL, NULL); - } - return 0; + struct stat statbuf; + + if (stat ("/sys/subsystem", &statbuf) == 0) + { + /* we have /subsystem/, forget all the old stuff */ + scan_dir (udev_enumerate, "subsystem", "devices", NULL); + } + else + { + scan_dir (udev_enumerate, "bus", "devices", NULL); + scan_dir (udev_enumerate, "class", NULL, NULL); + } + return 0; } /** @@ -1014,21 +1052,22 @@ static int scan_devices_all(struct udev_enumerate *udev_enumerate) * * Returns: 0 on success, otherwise a negative error value. **/ -int udev_enumerate_scan_devices(struct udev_enumerate *udev_enumerate) +int +udev_enumerate_scan_devices (struct udev_enumerate *udev_enumerate) { - if (udev_enumerate == NULL) - return -EINVAL; + if (udev_enumerate == NULL) + return -EINVAL; - /* efficiently lookup tags only, we maintain a reverse-index */ - if (udev_list_get_entry(&udev_enumerate->tags_match_list) != NULL) - return scan_devices_tags(udev_enumerate); + /* efficiently lookup tags only, we maintain a reverse-index */ + if (udev_list_get_entry (&udev_enumerate->tags_match_list) != NULL) + return scan_devices_tags (udev_enumerate); - /* walk the subtree of one parent device only */ - if (udev_enumerate->parent_match != NULL) - return scan_devices_children(udev_enumerate); + /* walk the subtree of one parent device only */ + if (udev_enumerate->parent_match != NULL) + return scan_devices_children (udev_enumerate); - /* scan devices of all subsystems */ - return scan_devices_all(udev_enumerate); + /* scan devices of all subsystems */ + return scan_devices_all (udev_enumerate); } /** @@ -1039,29 +1078,30 @@ int udev_enumerate_scan_devices(struct udev_enumerate *udev_enumerate) * * Returns: 0 on success, otherwise a negative error value. **/ -int udev_enumerate_scan_subsystems(struct udev_enumerate *udev_enumerate) +int +udev_enumerate_scan_subsystems (struct udev_enumerate *udev_enumerate) { - struct stat statbuf; - const char *subsysdir; + struct stat statbuf; + const char *subsysdir; - if (udev_enumerate == NULL) - return -EINVAL; + if (udev_enumerate == NULL) + return -EINVAL; - /* all kernel modules */ - if (match_subsystem(udev_enumerate, "module")) - scan_dir_and_add_devices(udev_enumerate, "module", NULL, NULL); + /* all kernel modules */ + if (match_subsystem (udev_enumerate, "module")) + scan_dir_and_add_devices (udev_enumerate, "module", NULL, NULL); - if (stat("/sys/subsystem", &statbuf) == 0) - subsysdir = "subsystem"; - else - subsysdir = "bus"; + if (stat ("/sys/subsystem", &statbuf) == 0) + subsysdir = "subsystem"; + else + subsysdir = "bus"; - /* all subsystems (only buses support coldplug) */ - if (match_subsystem(udev_enumerate, "subsystem")) - scan_dir_and_add_devices(udev_enumerate, subsysdir, NULL, NULL); + /* all subsystems (only buses support coldplug) */ + if (match_subsystem (udev_enumerate, "subsystem")) + scan_dir_and_add_devices (udev_enumerate, subsysdir, NULL, NULL); - /* all subsystem drivers */ - if (match_subsystem(udev_enumerate, "drivers")) - scan_dir(udev_enumerate, subsysdir, "drivers", "drivers"); - return 0; + /* all subsystem drivers */ + if (match_subsystem (udev_enumerate, "drivers")) + scan_dir (udev_enumerate, subsysdir, "drivers", "drivers"); + return 0; } diff --git a/libudev-compat/libudev-fs.c b/libudev-compat/libudev-fs.c index bf56793..9e69929 100644 --- a/libudev-compat/libudev-fs.c +++ b/libudev-compat/libudev-fs.c @@ -36,8 +36,8 @@ #define UDEV_MAX_MONITORS 32768 #endif -static int udev_monitor_fs_events_path(char const *name, char *pathbuf, - int nonce); +static int udev_monitor_fs_events_path (char const *name, char *pathbuf, + int nonce); // We need to make sure that on fork, a udev_monitor listening to the underlying filesystem // will listen to its *own* process's events directory, at all times. To do this, we will @@ -48,335 +48,372 @@ static int g_monitor_lock = 0; // primitive mutex that can work across forks static pid_t g_pid = 0; // tells us when to re-target the monitors // spin-lock to lock the monitor table -static void g_monitor_table_spinlock() +static void +g_monitor_table_spinlock () { - bool locked = false; - while (1) { + bool locked = false; + while (1) + { - locked = __sync_bool_compare_and_swap(&g_monitor_lock, 0, 1); - if (locked) { - break; - } + locked = __sync_bool_compare_and_swap (&g_monitor_lock, 0, 1); + if (locked) + { + break; } + } } // unlock the monitor table -static void g_monitor_table_unlock() +static void +g_monitor_table_unlock () { - g_monitor_lock = 0; + g_monitor_lock = 0; - // make sure spinners see it. - __sync_synchronize(); + // make sure spinners see it. + __sync_synchronize (); } // on fork(), create a new events directory for each of this process's monitors // and point them all to them. This way, both the parent and child can continue // to receive device packets. // NOTE: can only call async-safe methods -static void udev_monitor_atfork(void) +static void +udev_monitor_atfork (void) { - int errsv = errno; - int rc = 0; - int i = 0; - int cnt = 0; - pid_t pid = getpid(); - struct udev_monitor *monitor = NULL; - int socket_fds[2]; - struct epoll_event ev; - - write(STDERR_FILENO, "forked! begin split\n", - strlen("forked! begin split\n")); - - memset(&ev, 0, sizeof(struct epoll_event)); - - // reset each monitor's inotify fd to point to a new PID-specific directory instead - g_monitor_table_spinlock(); - - if (g_pid != pid) { - - // child; do the fork - for (i = 0; i < UDEV_MAX_MONITORS; i++) { - - if (g_monitor_table[i] == NULL) { - continue; - } - - monitor = g_monitor_table[i]; - - if (monitor->type != UDEV_MONITOR_TYPE_UDEV) { - continue; - } - - if (monitor->inotify_fd < 0) { - continue; - } - - if (monitor->epoll_fd < 0) { - continue; - } - - if (monitor->events_wd < 0) { - continue; - } - // reset the socket buffer--the parent will be said to have - // received intermittent events before the child was created. - if (monitor->sock >= 0) { - - // stop watching this socket--we'll regenerate it later - epoll_ctl(monitor->epoll_fd, EPOLL_CTL_DEL, - monitor->sock, NULL); - close(monitor->sock); - monitor->sock = -1; - } - - if (monitor->sock_fs >= 0) { - close(monitor->sock_fs); - monitor->sock_fs = -1; - } - - rc = socketpair(AF_LOCAL, - SOCK_RAW | SOCK_NONBLOCK | SOCK_CLOEXEC, - 0, socket_fds); - if (rc < 0) { - - // not much we can do here, except log an error - write(STDERR_FILENO, - "Failed to generate a socketpair\n", - strlen - ("Failed to generate a socketpair\n")); - - udev_monitor_fs_shutdown(monitor); - g_monitor_table[i] = NULL; - continue; - } - // child's copy of the monitor has its own socketpair - monitor->sock = socket_fds[0]; - monitor->sock_fs = socket_fds[1]; - - // reinstall its filter - udev_monitor_filter_update(monitor); - - // watch the child's socket - ev.events = EPOLLIN; - ev.data.fd = monitor->sock; - rc = epoll_ctl(monitor->epoll_fd, EPOLL_CTL_ADD, - monitor->sock, &ev); - if (rc < 0) { - - // not much we can do here, except log an error - write(STDERR_FILENO, - "Failed to add monitor socket\n", - strlen("Failed to add monitor socket\n")); - - udev_monitor_fs_shutdown(monitor); - g_monitor_table[i] = NULL; - continue; - } - // reset the inotify watch - rc = inotify_rm_watch(monitor->inotify_fd, - monitor->events_wd); - monitor->events_wd = -1; - - if (rc < 0) { - - rc = -errno; - if (rc == -EINVAL) { - - // monitor->events_wd was invalid - rc = 0; - } else if (rc == -EBADF) { - - // monitor->inotify_fd is invalid. - // not much we can do here, except log an error - write(STDERR_FILENO, - "Invalid inotify handle\n", - strlen("Invalid inotify handle")); - - udev_monitor_fs_shutdown(monitor); - g_monitor_table[i] = NULL; - continue; - } - } - - if (rc == 0) { - - udev_monitor_fs_events_path("", - monitor->events_dir, - i); - - // try to create a new directory for this monitor - rc = mkdir(monitor->events_dir, 0700); - - if (rc < 0) { - // failed, we have. - // child will not get any notifications from this monitor - rc = -errno; - write(STDERR_FILENO, "Failed to mkdir ", - strlen("Failed to mkdir ")); - write(STDERR_FILENO, - monitor->events_dir, - strlen(monitor->events_dir)); - write(STDERR_FILENO, "\n", 1); - - udev_monitor_fs_shutdown(monitor); - g_monitor_table[i] = NULL; - return; - } - // reconnect to the new directory - monitor->events_wd = - inotify_add_watch(monitor->inotify_fd, - monitor->events_dir, - UDEV_FS_WATCH_DIR_FLAGS); - if (monitor->events_wd < 0) { - - // there's not much we can safely do here, besides log an error - write(STDERR_FILENO, "Failed to watch ", - strlen("Failed to watch ")); - write(STDERR_FILENO, - monitor->events_dir, - strlen(monitor->events_dir)); - write(STDERR_FILENO, "\n", 1); - } - } else { - - // there's not much we can safely do here, besides log an error - rc = -errno; - write(STDERR_FILENO, "Failed to disconnect!\n", - strlen("Failed to disconnect!\n")); - } + int errsv = errno; + int rc = 0; + int i = 0; + int cnt = 0; + pid_t pid = getpid (); + struct udev_monitor *monitor = NULL; + int socket_fds[2]; + struct epoll_event ev; + + write (STDERR_FILENO, "forked! begin split\n", + strlen ("forked! begin split\n")); + + memset (&ev, 0, sizeof (struct epoll_event)); + + // reset each monitor's inotify fd to point to a new PID-specific directory instead + g_monitor_table_spinlock (); + + if (g_pid != pid) + { + + // child; do the fork + for (i = 0; i < UDEV_MAX_MONITORS; i++) + { + + if (g_monitor_table[i] == NULL) + { + continue; + } + + monitor = g_monitor_table[i]; + + if (monitor->type != UDEV_MONITOR_TYPE_UDEV) + { + continue; + } + + if (monitor->inotify_fd < 0) + { + continue; + } + + if (monitor->epoll_fd < 0) + { + continue; + } + + if (monitor->events_wd < 0) + { + continue; + } + // reset the socket buffer--the parent will be said to have + // received intermittent events before the child was created. + if (monitor->sock >= 0) + { + + // stop watching this socket--we'll regenerate it later + epoll_ctl (monitor->epoll_fd, EPOLL_CTL_DEL, + monitor->sock, NULL); + close (monitor->sock); + monitor->sock = -1; + } + + if (monitor->sock_fs >= 0) + { + close (monitor->sock_fs); + monitor->sock_fs = -1; + } + + rc = socketpair (AF_LOCAL, + SOCK_RAW | SOCK_NONBLOCK | SOCK_CLOEXEC, + 0, socket_fds); + if (rc < 0) + { + + // not much we can do here, except log an error + write (STDERR_FILENO, + "Failed to generate a socketpair\n", + strlen ("Failed to generate a socketpair\n")); + + udev_monitor_fs_shutdown (monitor); + g_monitor_table[i] = NULL; + continue; + } + // child's copy of the monitor has its own socketpair + monitor->sock = socket_fds[0]; + monitor->sock_fs = socket_fds[1]; + + // reinstall its filter + udev_monitor_filter_update (monitor); + + // watch the child's socket + ev.events = EPOLLIN; + ev.data.fd = monitor->sock; + rc = epoll_ctl (monitor->epoll_fd, EPOLL_CTL_ADD, + monitor->sock, &ev); + if (rc < 0) + { + + // not much we can do here, except log an error + write (STDERR_FILENO, + "Failed to add monitor socket\n", + strlen ("Failed to add monitor socket\n")); + + udev_monitor_fs_shutdown (monitor); + g_monitor_table[i] = NULL; + continue; + } + // reset the inotify watch + rc = inotify_rm_watch (monitor->inotify_fd, monitor->events_wd); + monitor->events_wd = -1; + + if (rc < 0) + { + + rc = -errno; + if (rc == -EINVAL) + { + + // monitor->events_wd was invalid + rc = 0; } - - g_pid = pid; + else if (rc == -EBADF) + { + + // monitor->inotify_fd is invalid. + // not much we can do here, except log an error + write (STDERR_FILENO, + "Invalid inotify handle\n", + strlen ("Invalid inotify handle")); + + udev_monitor_fs_shutdown (monitor); + g_monitor_table[i] = NULL; + continue; + } + } + + if (rc == 0) + { + + udev_monitor_fs_events_path ("", monitor->events_dir, i); + + // try to create a new directory for this monitor + rc = mkdir (monitor->events_dir, 0700); + + if (rc < 0) + { + // failed, we have. + // child will not get any notifications from this monitor + rc = -errno; + write (STDERR_FILENO, "Failed to mkdir ", + strlen ("Failed to mkdir ")); + write (STDERR_FILENO, + monitor->events_dir, strlen (monitor->events_dir)); + write (STDERR_FILENO, "\n", 1); + + udev_monitor_fs_shutdown (monitor); + g_monitor_table[i] = NULL; + return; + } + // reconnect to the new directory + monitor->events_wd = + inotify_add_watch (monitor->inotify_fd, + monitor->events_dir, + UDEV_FS_WATCH_DIR_FLAGS); + if (monitor->events_wd < 0) + { + + // there's not much we can safely do here, besides log an error + write (STDERR_FILENO, "Failed to watch ", + strlen ("Failed to watch ")); + write (STDERR_FILENO, + monitor->events_dir, strlen (monitor->events_dir)); + write (STDERR_FILENO, "\n", 1); + } + } + else + { + + // there's not much we can safely do here, besides log an error + rc = -errno; + write (STDERR_FILENO, "Failed to disconnect!\n", + strlen ("Failed to disconnect!\n")); + } } - g_monitor_table_unlock(); + g_pid = pid; + } + + g_monitor_table_unlock (); - write(STDERR_FILENO, "end atfork()\n", strlen("end atfork()\n")); + write (STDERR_FILENO, "end atfork()\n", strlen ("end atfork()\n")); - // restore... - errno = errsv; + // restore... + errno = errsv; } // register a monitor in our list of monitors // return 0 on success // return -ENOSPC if we're out of slots -static int udev_monitor_register(struct udev_monitor *monitor) +static int +udev_monitor_register (struct udev_monitor *monitor) { - g_monitor_table_spinlock(); + g_monitor_table_spinlock (); - // find a free slot - int i = 0; - int rc = -ENOSPC; - for (i = 0; i < UDEV_MAX_MONITORS; i++) { + // find a free slot + int i = 0; + int rc = -ENOSPC; + for (i = 0; i < UDEV_MAX_MONITORS; i++) + { - if (g_monitor_table[i] == NULL) { + if (g_monitor_table[i] == NULL) + { - g_monitor_table[i] = monitor; - monitor->slot = i; - rc = 0; - break; - } + g_monitor_table[i] = monitor; + monitor->slot = i; + rc = 0; + break; } + } - if (g_pid == 0) { + if (g_pid == 0) + { - // first monitor ever. - // register our fork handler. - g_pid = getpid(); - pthread_atfork(NULL, NULL, udev_monitor_atfork); - } + // first monitor ever. + // register our fork handler. + g_pid = getpid (); + pthread_atfork (NULL, NULL, udev_monitor_atfork); + } - g_monitor_table_unlock(); + g_monitor_table_unlock (); - return rc; + return rc; } // unregister a monitor in our list of monitors -static void udev_monitor_unregister(struct udev_monitor *monitor) +static void +udev_monitor_unregister (struct udev_monitor *monitor) { - if (monitor->slot < 0) { - return; - } + if (monitor->slot < 0) + { + return; + } - g_monitor_table_spinlock(); + g_monitor_table_spinlock (); - g_monitor_table[monitor->slot] = NULL; + g_monitor_table[monitor->slot] = NULL; - g_monitor_table_unlock(); + g_monitor_table_unlock (); - monitor->slot = -1; + monitor->slot = -1; } // write, but mask EINTR // return number of bytes written on success // return -errno on I/O error -ssize_t udev_write_uninterrupted(int fd, char const *buf, size_t len) +ssize_t +udev_write_uninterrupted (int fd, char const *buf, size_t len) { - ssize_t num_written = 0; + ssize_t num_written = 0; - if (buf == NULL) { - return -EINVAL; - } + if (buf == NULL) + { + return -EINVAL; + } - while ((unsigned)num_written < len) { - ssize_t nw = write(fd, buf + num_written, len - num_written); - if (nw < 0) { + while ((unsigned) num_written < len) + { + ssize_t nw = write (fd, buf + num_written, len - num_written); + if (nw < 0) + { - int errsv = -errno; - if (errsv == -EINTR) { - continue; - } + int errsv = -errno; + if (errsv == -EINTR) + { + continue; + } - return errsv; - } - if (nw == 0) { - break; - } - - num_written += nw; + return errsv; + } + if (nw == 0) + { + break; } - return num_written; + num_written += nw; + } + + return num_written; } // read, but mask EINTR // return number of bytes read on success // return -errno on I/O error // NOTE: must be async-safe! -ssize_t udev_read_uninterrupted(int fd, char *buf, size_t len) +ssize_t +udev_read_uninterrupted (int fd, char *buf, size_t len) { - ssize_t num_read = 0; - - if (buf == NULL) { - return -EINVAL; - } + ssize_t num_read = 0; - while ((unsigned)num_read < len) { - ssize_t nr = read(fd, buf + num_read, len - num_read); - if (nr < 0) { + if (buf == NULL) + { + return -EINVAL; + } - int errsv = -errno; - if (errsv == -EINTR) { - continue; - } + while ((unsigned) num_read < len) + { + ssize_t nr = read (fd, buf + num_read, len - num_read); + if (nr < 0) + { - return errsv; - } - if (nr == 0) { - break; - } + int errsv = -errno; + if (errsv == -EINTR) + { + continue; + } - num_read += nr; + return errsv; } + if (nr == 0) + { + break; + } + + num_read += nr; + } - return num_read; + return num_read; } // set up a filesystem monitor @@ -384,406 +421,450 @@ ssize_t udev_read_uninterrupted(int fd, char *buf, size_t len) // get their own filesystem monitor state. // * set up /dev/events/libudev-$PID/ // * start watching /dev/events/libudev-$PID for new files -int udev_monitor_fs_setup(struct udev_monitor *monitor) +int +udev_monitor_fs_setup (struct udev_monitor *monitor) { - int rc = 0; - struct epoll_event ev; - - monitor->inotify_fd = -1; - monitor->epoll_fd = -1; - monitor->sock = -1; - monitor->sock_fs = -1; - monitor->slot = -1; - - int socket_fd[2] = { -1, -1 }; - - memset(&monitor->events_dir, 0, PATH_MAX + 1); - memset(&ev, 0, sizeof(struct epoll_event)); - - // make sure this monitor can't disappear on us - udev_monitor_register(monitor); - - // set up inotify - monitor->inotify_fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC); - if (monitor->inotify_fd < 0) { - - rc = -errno; - log_error("inotify_init rc = %d", rc); - - udev_monitor_fs_shutdown(monitor); - return rc; - } - // epoll descriptor unifying inotify and event counter - monitor->epoll_fd = epoll_create1(EPOLL_CLOEXEC); - if (monitor->epoll_fd < 0) { - - rc = -errno; - log_error("epoll_create rc = %d", rc); - - udev_monitor_fs_shutdown(monitor); - return rc; - } - // create our monitor directory /dev/events/libudev-$PID - udev_monitor_fs_events_path("", monitor->events_dir, monitor->slot); - rc = mkdir(monitor->events_dir, 0700); - if (rc != 0) { - - rc = -errno; - log_error("mkdir('%s') rc = %d", monitor->events_dir, rc); - - udev_monitor_fs_destroy(monitor); - return rc; - } - // begin watching /dev/events/libudev-$PID - monitor->events_wd = - inotify_add_watch(monitor->inotify_fd, monitor->events_dir, - UDEV_FS_WATCH_DIR_FLAGS); - if (monitor->events_wd < 0) { - - rc = -errno; - log_error("inotify_add_watch('%s') rc = %d", - monitor->events_dir, rc); - - udev_monitor_fs_destroy(monitor); - return rc; - } - // set up local socket pair with the parent process - // needs to be a socket (not a pipe) since we're going to attach a BPF to it. - rc = socketpair(AF_LOCAL, SOCK_RAW | SOCK_NONBLOCK | SOCK_CLOEXEC, 0, - socket_fd); - if (rc < 0) { - - rc = -errno; - log_error - ("socketpair(AF_LOCAL, SOCK_RAW|SOCK_CLOEXEC, 0) rc = %d", - rc); - - udev_monitor_fs_destroy(monitor); - return rc; - } - - monitor->sock = socket_fd[0]; // receiving end - monitor->sock_fs = socket_fd[1]; // sending end - - // unify inotify and sock behind epoll_fd, set to poll for reading - ev.events = EPOLLIN; - ev.data.fd = monitor->inotify_fd; - rc = epoll_ctl(monitor->epoll_fd, EPOLL_CTL_ADD, monitor->inotify_fd, - &ev); - if (rc != 0) { - - rc = -errno; - log_error("epoll_ctl(%d on inotify_fd %d) rc = %d", - monitor->epoll_fd, monitor->inotify_fd, rc); - - udev_monitor_fs_shutdown(monitor); - return rc; - } - - ev.data.fd = monitor->sock; - rc = epoll_ctl(monitor->epoll_fd, EPOLL_CTL_ADD, monitor->sock, &ev); - if (rc != 0) { - - rc = -errno; - log_error("epoll_ctl(%d on inotify_fd %d) rc = %d", - monitor->sock, monitor->sock, rc); - - udev_monitor_fs_shutdown(monitor); - return rc; - } - - monitor->pid = getpid(); - - return rc; + int rc = 0; + struct epoll_event ev; + + monitor->inotify_fd = -1; + monitor->epoll_fd = -1; + monitor->sock = -1; + monitor->sock_fs = -1; + monitor->slot = -1; + + int socket_fd[2] = { -1, -1 }; + + memset (&monitor->events_dir, 0, PATH_MAX + 1); + memset (&ev, 0, sizeof (struct epoll_event)); + + // make sure this monitor can't disappear on us + udev_monitor_register (monitor); + + // set up inotify + monitor->inotify_fd = inotify_init1 (IN_NONBLOCK | IN_CLOEXEC); + if (monitor->inotify_fd < 0) + { + + rc = -errno; + log_error ("inotify_init rc = %d", rc); + + udev_monitor_fs_shutdown (monitor); + return rc; + } + // epoll descriptor unifying inotify and event counter + monitor->epoll_fd = epoll_create1 (EPOLL_CLOEXEC); + if (monitor->epoll_fd < 0) + { + + rc = -errno; + log_error ("epoll_create rc = %d", rc); + + udev_monitor_fs_shutdown (monitor); + return rc; + } + // create our monitor directory /dev/events/libudev-$PID + udev_monitor_fs_events_path ("", monitor->events_dir, monitor->slot); + rc = mkdir (monitor->events_dir, 0700); + if (rc != 0) + { + + rc = -errno; + log_error ("mkdir('%s') rc = %d", monitor->events_dir, rc); + + udev_monitor_fs_destroy (monitor); + return rc; + } + // begin watching /dev/events/libudev-$PID + monitor->events_wd = + inotify_add_watch (monitor->inotify_fd, monitor->events_dir, + UDEV_FS_WATCH_DIR_FLAGS); + if (monitor->events_wd < 0) + { + + rc = -errno; + log_error ("inotify_add_watch('%s') rc = %d", monitor->events_dir, rc); + + udev_monitor_fs_destroy (monitor); + return rc; + } + // set up local socket pair with the parent process + // needs to be a socket (not a pipe) since we're going to attach a BPF to it. + rc = socketpair (AF_LOCAL, SOCK_RAW | SOCK_NONBLOCK | SOCK_CLOEXEC, 0, + socket_fd); + if (rc < 0) + { + + rc = -errno; + log_error + ("socketpair(AF_LOCAL, SOCK_RAW|SOCK_CLOEXEC, 0) rc = %d", rc); + + udev_monitor_fs_destroy (monitor); + return rc; + } + + monitor->sock = socket_fd[0]; // receiving end + monitor->sock_fs = socket_fd[1]; // sending end + + // unify inotify and sock behind epoll_fd, set to poll for reading + ev.events = EPOLLIN; + ev.data.fd = monitor->inotify_fd; + rc = epoll_ctl (monitor->epoll_fd, EPOLL_CTL_ADD, monitor->inotify_fd, &ev); + if (rc != 0) + { + + rc = -errno; + log_error ("epoll_ctl(%d on inotify_fd %d) rc = %d", + monitor->epoll_fd, monitor->inotify_fd, rc); + + udev_monitor_fs_shutdown (monitor); + return rc; + } + + ev.data.fd = monitor->sock; + rc = epoll_ctl (monitor->epoll_fd, EPOLL_CTL_ADD, monitor->sock, &ev); + if (rc != 0) + { + + rc = -errno; + log_error ("epoll_ctl(%d on inotify_fd %d) rc = %d", + monitor->sock, monitor->sock, rc); + + udev_monitor_fs_shutdown (monitor); + return rc; + } + + monitor->pid = getpid (); + + return rc; } // shut down a monitor's filesystem-specific state // not much we can do if any shutdown step fails, so try them all -int udev_monitor_fs_shutdown(struct udev_monitor *monitor) +int +udev_monitor_fs_shutdown (struct udev_monitor *monitor) { - int rc = 0; + int rc = 0; - // stop tracking this monitor - udev_monitor_unregister(monitor); + // stop tracking this monitor + udev_monitor_unregister (monitor); - if (monitor->sock >= 0) { - rc = shutdown(monitor->sock, SHUT_RDWR); - if (rc < 0) { - rc = -errno; - log_error("shutdown(socket %d) rc = %d", monitor->sock, - rc); - } + if (monitor->sock >= 0) + { + rc = shutdown (monitor->sock, SHUT_RDWR); + if (rc < 0) + { + rc = -errno; + log_error ("shutdown(socket %d) rc = %d", monitor->sock, rc); } - - if (monitor->sock_fs >= 0) { - rc = shutdown(monitor->sock_fs, SHUT_RDWR); - if (rc < 0) { - rc = -errno; - log_error("shutdown(socket %d) rc = %d", - monitor->sock_fs, rc); - } + } + + if (monitor->sock_fs >= 0) + { + rc = shutdown (monitor->sock_fs, SHUT_RDWR); + if (rc < 0) + { + rc = -errno; + log_error ("shutdown(socket %d) rc = %d", monitor->sock_fs, rc); } - - if (monitor->sock >= 0) { - rc = close(monitor->sock); - if (rc < 0) { - rc = -errno; - log_error("close(socket %d) rc = %d", monitor->sock, - rc); - } else { - monitor->sock = -1; - } + } + + if (monitor->sock >= 0) + { + rc = close (monitor->sock); + if (rc < 0) + { + rc = -errno; + log_error ("close(socket %d) rc = %d", monitor->sock, rc); } - - if (monitor->sock_fs >= 0) { - rc = close(monitor->sock_fs); - if (rc < 0) { - rc = -errno; - log_error("close(socket %d) rc = %d", monitor->sock_fs, - rc); - } else { - monitor->sock_fs = -1; - } + else + { + monitor->sock = -1; } - - if (monitor->epoll_fd >= 0) { - rc = close(monitor->epoll_fd); - if (rc < 0) { - rc = -errno; - log_error("close(epoll_fd %d) rc = %d", - monitor->epoll_fd, rc); - } else { - monitor->epoll_fd = -1; - } + } + + if (monitor->sock_fs >= 0) + { + rc = close (monitor->sock_fs); + if (rc < 0) + { + rc = -errno; + log_error ("close(socket %d) rc = %d", monitor->sock_fs, rc); } - - if (monitor->events_wd >= 0) { - - if (monitor->inotify_fd >= 0) { - rc = inotify_rm_watch(monitor->inotify_fd, - monitor->events_wd); - if (rc < 0) { - rc = -errno; - log_error("close(events_wd %d) rc = %d", - monitor->events_wd, rc); - } else { - monitor->events_wd = -1; - } - } + else + { + monitor->sock_fs = -1; } - if (monitor->inotify_fd >= 0) { - rc = close(monitor->inotify_fd); - if (rc < 0) { - rc = -errno; - log_error("close(inotify_fd %d) rc = %d", - monitor->inotify_fd, rc); - } else { - monitor->inotify_fd = -1; - } + } + + if (monitor->epoll_fd >= 0) + { + rc = close (monitor->epoll_fd); + if (rc < 0) + { + rc = -errno; + log_error ("close(epoll_fd %d) rc = %d", monitor->epoll_fd, rc); + } + else + { + monitor->epoll_fd = -1; + } + } + + if (monitor->events_wd >= 0) + { + + if (monitor->inotify_fd >= 0) + { + rc = inotify_rm_watch (monitor->inotify_fd, monitor->events_wd); + if (rc < 0) + { + rc = -errno; + log_error ("close(events_wd %d) rc = %d", + monitor->events_wd, rc); + } + else + { + monitor->events_wd = -1; + } + } + } + if (monitor->inotify_fd >= 0) + { + rc = close (monitor->inotify_fd); + if (rc < 0) + { + rc = -errno; + log_error ("close(inotify_fd %d) rc = %d", monitor->inotify_fd, rc); } + else + { + monitor->inotify_fd = -1; + } + } - return rc; + return rc; } // blow away all local filesystem state for a monitor -int udev_monitor_fs_destroy(struct udev_monitor *monitor) +int +udev_monitor_fs_destroy (struct udev_monitor *monitor) { - char pathbuf[PATH_MAX + 1]; - int dirfd = 0; - int rc = 0; - DIR *dirh = NULL; - struct dirent entry; - struct dirent *result = NULL; - bool can_rmdir = true; - - // stop listening - udev_monitor_fs_shutdown(monitor); - - // remove events dir contents - dirfd = open(monitor->events_dir, O_DIRECTORY | O_CLOEXEC); - if (dirfd < 0) { - - rc = -errno; - log_error("open('%s') rc = %d", monitor->events_dir, rc); - return rc; + char pathbuf[PATH_MAX + 1]; + int dirfd = 0; + int rc = 0; + DIR *dirh = NULL; + struct dirent entry; + struct dirent *result = NULL; + bool can_rmdir = true; + + // stop listening + udev_monitor_fs_shutdown (monitor); + + // remove events dir contents + dirfd = open (monitor->events_dir, O_DIRECTORY | O_CLOEXEC); + if (dirfd < 0) + { + + rc = -errno; + log_error ("open('%s') rc = %d", monitor->events_dir, rc); + return rc; + } + + dirh = fdopendir (dirfd); + if (dirh == NULL) + { + + // OOM + rc = -errno; + close (dirfd); + return rc; + } + + do + { + + // next entry + rc = readdir_r (dirh, &entry, &result); + if (rc != 0) + { + + // I/O error + log_error ("readdir_r('%s') rc = %d", monitor->events_dir, rc); + break; } - - dirh = fdopendir(dirfd); - if (dirh == NULL) { - - // OOM - rc = -errno; - close(dirfd); - return rc; + // skip . and .. + if (strcmp (entry.d_name, ".") == 0 || strcmp (entry.d_name, "..") == 0) + { + continue; } + // generate full path + memset (pathbuf, 0, PATH_MAX + 1); - do { - - // next entry - rc = readdir_r(dirh, &entry, &result); - if (rc != 0) { - - // I/O error - log_error("readdir_r('%s') rc = %d", - monitor->events_dir, rc); - break; - } - // skip . and .. - if (strcmp(entry.d_name, ".") == 0 - || strcmp(entry.d_name, "..") == 0) { - continue; - } - // generate full path - memset(pathbuf, 0, PATH_MAX + 1); - - snprintf(pathbuf, PATH_MAX, "%s/%s", monitor->events_dir, - entry.d_name); + snprintf (pathbuf, PATH_MAX, "%s/%s", monitor->events_dir, + entry.d_name); - // optimistically remove - if (entry.d_type == DT_DIR) { - rc = rmdir(pathbuf); - } else { - rc = unlink(pathbuf); - } + // optimistically remove + if (entry.d_type == DT_DIR) + { + rc = rmdir (pathbuf); + } + else + { + rc = unlink (pathbuf); + } - if (rc != 0) { + if (rc != 0) + { - rc = -errno; - log_error("remove '%s' rc = %d", pathbuf, rc); + rc = -errno; + log_error ("remove '%s' rc = %d", pathbuf, rc); - can_rmdir = false; - rc = 0; - } + can_rmdir = false; + rc = 0; + } - } while (result != NULL); + } + while (result != NULL); - // NOTE: closes dirfd - closedir(dirh); + // NOTE: closes dirfd + closedir (dirh); - if (can_rmdir) { - rc = rmdir(monitor->events_dir); - if (rc != 0) { + if (can_rmdir) + { + rc = rmdir (monitor->events_dir); + if (rc != 0) + { - rc = -errno; - log_error("rmdir('%s') rc = %d\n", monitor->events_dir, - rc); - } - } else { - // let the caller know... - rc = -ENOTEMPTY; + rc = -errno; + log_error ("rmdir('%s') rc = %d\n", monitor->events_dir, rc); } - - return rc; + } + else + { + // let the caller know... + rc = -ENOTEMPTY; + } + + return rc; } // thread-safe and async-safe int to string for base 10 -void itoa10_safe(int val, char *str) +void +itoa10_safe (int val, char *str) { - int rc = 0; - int i = 0; - int len = 0; - int j = 0; - bool neg = false; - - // sign check - if (val < 0) { - val = -val; - neg = true; - } - // consume, lowest-order to highest-order - if (val == 0) { - str[i] = '0'; - i++; - } else { - while (val > 0) { - - int r = val % 10; - - str[i] = '0' + r; - i++; - - val /= 10; - } + int rc = 0; + int i = 0; + int len = 0; + int j = 0; + bool neg = false; + + // sign check + if (val < 0) + { + val = -val; + neg = true; + } + // consume, lowest-order to highest-order + if (val == 0) + { + str[i] = '0'; + i++; + } + else + { + while (val > 0) + { + + int r = val % 10; + + str[i] = '0' + r; + i++; + + val /= 10; } + } - if (neg) { + if (neg) + { - str[i] = '-'; - i++; - } + str[i] = '-'; + i++; + } - len = i; - i--; + len = i; + i--; - // reverse order to get the number - while (j < i) { + // reverse order to get the number + while (j < i) + { - char tmp = *(str + i); - *(str + i) = *(str + j); - *(str + j) = tmp; + char tmp = *(str + i); + *(str + i) = *(str + j); + *(str + j) = tmp; - j++; - i--; - } + j++; + i--; + } - str[len] = '\0'; + str[len] = '\0'; } // path to a named event for this process to consume // pathbuf must have at least PATH_MAX bytes // NOTE: must be async-safe, since it's used in a pthread_atfork() callback -static int udev_monitor_fs_events_path(char const *name, char *pathbuf, - int nonce) +static int +udev_monitor_fs_events_path (char const *name, char *pathbuf, int nonce) { - // do the equivalent of: - // snprintf( pathbuf, PATH_MAX, UDEV_FS_EVENTS_DIR "/libudev-%d-%d/%s", getpid(), nonce, name ); + // do the equivalent of: + // snprintf( pathbuf, PATH_MAX, UDEV_FS_EVENTS_DIR "/libudev-%d-%d/%s", getpid(), nonce, name ); - char pidbuf[10]; - pidbuf[9] = 0; + char pidbuf[10]; + pidbuf[9] = 0; - char nonce_buf[50]; - nonce_buf[49] = 0; + char nonce_buf[50]; + nonce_buf[49] = 0; - pid_t pid = getpid(); + pid_t pid = getpid (); - itoa10_safe(pid, pidbuf); - itoa10_safe(nonce, nonce_buf); + itoa10_safe (pid, pidbuf); + itoa10_safe (nonce, nonce_buf); - size_t pidbuf_len = strnlen(pidbuf, 10); - size_t nonce_buf_len = strnlen(nonce_buf, 50); - size_t prefix_len = strlen(UDEV_FS_EVENTS_DIR); - size_t dirname_prefix_len = strlen("/libudev-"); - int off = 0; + size_t pidbuf_len = strnlen (pidbuf, 10); + size_t nonce_buf_len = strnlen (nonce_buf, 50); + size_t prefix_len = strlen (UDEV_FS_EVENTS_DIR); + size_t dirname_prefix_len = strlen ("/libudev-"); + int off = 0; - memcpy(pathbuf, UDEV_FS_EVENTS_DIR, prefix_len); - off += prefix_len; + memcpy (pathbuf, UDEV_FS_EVENTS_DIR, prefix_len); + off += prefix_len; - memcpy(pathbuf + off, "/libudev-", dirname_prefix_len); - off += dirname_prefix_len; + memcpy (pathbuf + off, "/libudev-", dirname_prefix_len); + off += dirname_prefix_len; - memcpy(pathbuf + off, pidbuf, pidbuf_len); - off += pidbuf_len; + memcpy (pathbuf + off, pidbuf, pidbuf_len); + off += pidbuf_len; - memcpy(pathbuf + off, "-", 1); - off += 1; + memcpy (pathbuf + off, "-", 1); + off += 1; - memcpy(pathbuf + off, nonce_buf, nonce_buf_len); - off += nonce_buf_len; + memcpy (pathbuf + off, nonce_buf, nonce_buf_len); + off += nonce_buf_len; - pathbuf[off] = '/'; - off++; + pathbuf[off] = '/'; + off++; - memcpy(pathbuf + off, name, strlen(name)); - off += strlen(name); + memcpy (pathbuf + off, name, strlen (name)); + off += strlen (name); - pathbuf[off] = '\0'; + pathbuf[off] = '\0'; - return off + strlen(name); + return off + strlen (name); } // send the contents of a file containing a serialized packet to the libudev client: @@ -799,93 +880,104 @@ static int udev_monitor_fs_events_path(char const *name, char *pathbuf, // return -EBADMSG if the file is invalid // return -EAGAIN if we'd block on send // TODO: can we use sendfile(2)? -static int udev_monitor_fs_push_event(int fd, struct udev_monitor *monitor) +static int +udev_monitor_fs_push_event (int fd, struct udev_monitor *monitor) { - int rc = 0; - off_t len = 0; - size_t hdrlen = 0; - char buf[8192]; - struct stat sb; - struct msghdr msg; - struct iovec iov; - struct udev_device *dev = NULL; - size_t i = 0; - - memset(&msg, 0, sizeof(struct msghdr)); - memset(&iov, 0, sizeof(struct iovec)); - - // first, get the size - rc = fstat(fd, &sb); - if (rc < 0) { - - rc = -errno; - log_error("fstat(%d) rc = %d", fd, rc); - return rc; - } - - if (sb.st_size >= 8192) { - - rc = -EMSGSIZE; - return rc; - } - - rc = udev_read_uninterrupted(fd, buf, sb.st_size); - if (rc < 0) { - - log_error("udev_read_uninterrupted(%d) rc = %d", fd, rc); - return rc; - } - // replace all '\n' with '\0', in case the caller wrote - // the file line by line. - for (i = 0; i < sb.st_size; i++) { - - if (buf[i] == '\n') { - buf[i] = '\0'; - } - } - - // should be a uevent packet, and should start with [add|change|move|remove]@[devpath]\0 - hdrlen = strnlen(buf, sb.st_size) + 1; - if (hdrlen < sizeof("a@/d") || hdrlen >= sb.st_size) { - - log_error - ("invalid message header: length = %zu, message length = %zd", - hdrlen, sb.st_size); - return -EBADMSG; - } - - if (strstr(buf, "@/") == NULL) { - - // invalid header - log_error("%s", - "invalid message header: missing '@' directive"); - return -EBADMSG; + int rc = 0; + off_t len = 0; + size_t hdrlen = 0; + char buf[8192]; + struct stat sb; + struct msghdr msg; + struct iovec iov; + struct udev_device *dev = NULL; + size_t i = 0; + + memset (&msg, 0, sizeof (struct msghdr)); + memset (&iov, 0, sizeof (struct iovec)); + + // first, get the size + rc = fstat (fd, &sb); + if (rc < 0) + { + + rc = -errno; + log_error ("fstat(%d) rc = %d", fd, rc); + return rc; + } + + if (sb.st_size >= 8192) + { + + rc = -EMSGSIZE; + return rc; + } + + rc = udev_read_uninterrupted (fd, buf, sb.st_size); + if (rc < 0) + { + + log_error ("udev_read_uninterrupted(%d) rc = %d", fd, rc); + return rc; + } + // replace all '\n' with '\0', in case the caller wrote + // the file line by line. + for (i = 0; i < sb.st_size; i++) + { + + if (buf[i] == '\n') + { + buf[i] = '\0'; } - // make a udev device - dev = - udev_device_new_from_nulstr(monitor->udev, &buf[hdrlen], - sb.st_size - hdrlen); - if (dev == NULL) { - - rc = -errno; - log_error("udev_device_new_from_nulstr() rc = %d", rc); - - return rc; - } - // send it along - // TODO: sendfile(2)? - rc = udev_monitor_send_device(monitor, NULL, dev); - if (rc < 0) { - - log_error("udev_monitor_send_device rc = %d", rc); - } else { - - rc = 0; - } - - udev_device_unref(dev); - return rc; + } + + // should be a uevent packet, and should start with [add|change|move|remove]@[devpath]\0 + hdrlen = strnlen (buf, sb.st_size) + 1; + if (hdrlen < sizeof ("a@/d") || hdrlen >= sb.st_size) + { + + log_error + ("invalid message header: length = %zu, message length = %zd", + hdrlen, sb.st_size); + return -EBADMSG; + } + + if (strstr (buf, "@/") == NULL) + { + + // invalid header + log_error ("%s", "invalid message header: missing '@' directive"); + return -EBADMSG; + } + // make a udev device + dev = + udev_device_new_from_nulstr (monitor->udev, &buf[hdrlen], + sb.st_size - hdrlen); + if (dev == NULL) + { + + rc = -errno; + log_error ("udev_device_new_from_nulstr() rc = %d", rc); + + return rc; + } + // send it along + // TODO: sendfile(2)? + rc = udev_monitor_send_device (monitor, NULL, dev); + if (rc < 0) + { + + log_error ("udev_monitor_send_device rc = %d", rc); + } + else + { + + rc = 0; + } + + udev_device_unref (dev); + return rc; } // reset the oneshot inotify watch, so it will trip on the next create. @@ -893,128 +985,145 @@ static int udev_monitor_fs_push_event(int fd, struct udev_monitor *monitor) // if the pid has changed since last time, watch the new directory. // return 0 on success // return negative on error (errno) -static int udev_monitor_fs_watch_reset(struct udev_monitor *monitor) +static int +udev_monitor_fs_watch_reset (struct udev_monitor *monitor) { - int rc = 0; - bool inotify_triggerred = false; // was inotify triggerred? - char buf[4096] __attribute__ ((aligned(__alignof__(struct inotify_event)))); // see inotify(7) - struct pollfd pfd[1]; - - pfd[0].fd = monitor->inotify_fd; - pfd[0].events = POLLIN; - - // reset the watch by consuming all its events (should be at most one) - while (1) { + int rc = 0; + bool inotify_triggerred = false; // was inotify triggerred? + char buf[4096] __attribute__ ((aligned (__alignof__ (struct inotify_event)))); // see inotify(7) + struct pollfd pfd[1]; - // do we have data? - rc = poll(pfd, 1, 0); - if (rc <= 0) { + pfd[0].fd = monitor->inotify_fd; + pfd[0].events = POLLIN; - // out of data, or error - if (rc < 0) { + // reset the watch by consuming all its events (should be at most one) + while (1) + { - rc = -errno; - if (rc == -EINTR) { + // do we have data? + rc = poll (pfd, 1, 0); + if (rc <= 0) + { - // shouldn't really happen since the timeout for poll is zero, - // but you never know... - continue; - } + // out of data, or error + if (rc < 0) + { - log_error("poll(%d) rc = %d\n", - monitor->inotify_fd, rc); - rc = 0; - } + rc = -errno; + if (rc == -EINTR) + { - break; + // shouldn't really happen since the timeout for poll is zero, + // but you never know... + continue; } - // at least one event remaining - // consume it - rc = read(monitor->inotify_fd, buf, 4096); - if (rc == 0) { - break; - } - - if (rc < 0) { - rc = -errno; + log_error ("poll(%d) rc = %d\n", monitor->inotify_fd, rc); + rc = 0; + } - if (rc == -EINTR) { - continue; - } else if (rc == -EAGAIN || rc == -EWOULDBLOCK) { - rc = 0; - break; - } - } - // got one event - inotify_triggerred = true; + break; + } + // at least one event remaining + // consume it + rc = read (monitor->inotify_fd, buf, 4096); + if (rc == 0) + { + break; } - // has the PID changed? - // need to regenerate events path - if (getpid() != monitor->pid) { - - log_trace("Switch PID from %d to %d", monitor->pid, getpid()); - - udev_monitor_fs_events_path("", monitor->events_dir, - monitor->slot); + if (rc < 0) + { - rc = mkdir(monitor->events_dir, 0700); - if (rc != 0) { + rc = -errno; - rc = -errno; - if (rc != -EEXIST) { + if (rc == -EINTR) + { + continue; + } + else if (rc == -EAGAIN || rc == -EWOULDBLOCK) + { + rc = 0; + break; + } + } + // got one event + inotify_triggerred = true; + } + + // has the PID changed? + // need to regenerate events path + if (getpid () != monitor->pid) + { + + log_trace ("Switch PID from %d to %d", monitor->pid, getpid ()); + + udev_monitor_fs_events_path ("", monitor->events_dir, monitor->slot); + + rc = mkdir (monitor->events_dir, 0700); + if (rc != 0) + { + + rc = -errno; + if (rc != -EEXIST) + { + + log_error ("mkdir('%s') rc = %d\n", monitor->events_dir, rc); + return rc; + } + else + { + rc = 0; + } + } - log_error("mkdir('%s') rc = %d\n", - monitor->events_dir, rc); - return rc; - } else { - rc = 0; - } - } + monitor->events_wd = + inotify_add_watch (monitor->inotify_fd, monitor->events_dir, + UDEV_FS_WATCH_DIR_FLAGS); + if (monitor->events_wd < 0) + { - monitor->events_wd = - inotify_add_watch(monitor->inotify_fd, monitor->events_dir, - UDEV_FS_WATCH_DIR_FLAGS); - if (monitor->events_wd < 0) { + rc = -errno; - rc = -errno; + log_error ("inotify_add_watch('%s') rc = %d\n", + monitor->events_dir, rc); + return rc; + } - log_error("inotify_add_watch('%s') rc = %d\n", - monitor->events_dir, rc); - return rc; - } + monitor->pid = getpid (); - monitor->pid = getpid(); + // TODO: what about events that the child was supposed to receive? + // the parent forks, receives one or more events, and the child wakes up, and will miss them + // if we only do the above. + // we need to (try to) consume them here + } - // TODO: what about events that the child was supposed to receive? - // the parent forks, receives one or more events, and the child wakes up, and will miss them - // if we only do the above. - // we need to (try to) consume them here - } + rc = inotify_add_watch (monitor->inotify_fd, monitor->events_dir, + UDEV_FS_WATCH_DIR_FLAGS); + if (rc < 0) + { - rc = inotify_add_watch(monitor->inotify_fd, monitor->events_dir, - UDEV_FS_WATCH_DIR_FLAGS); - if (rc < 0) { + rc = -errno; + log_error ("inotify_add_watch(%d) rc = %d", monitor->inotify_fd, rc); + } - rc = -errno; - log_error("inotify_add_watch(%d) rc = %d", monitor->inotify_fd, - rc); - } - - return rc; + return rc; } // scandir: skip . and .. -static int udev_monitor_fs_scandir_filter(const struct dirent *dent) +static int +udev_monitor_fs_scandir_filter (const struct dirent *dent) { - if (strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0) { - return 0; - } else { - return 1; - } + if (strcmp (dent->d_name, ".") == 0 || strcmp (dent->d_name, "..") == 0) + { + return 0; + } + else + { + return 1; + } } // push as many available events from our filesystem buffer of events off to the monitor's socketpair. @@ -1026,346 +1135,378 @@ static int udev_monitor_fs_scandir_filter(const struct dirent *dent) // return -errno if we can't re-watch the directory // NOTE: this method should only be used if the underlying filesystem holding the events can't help us preserve the order. // NOTE: not thread-safe -int udev_monitor_fs_push_events(struct udev_monitor *monitor) +int +udev_monitor_fs_push_events (struct udev_monitor *monitor) { - char pathbuf[PATH_MAX + 1]; - int dirfd = -1; - int fd = -1; - int rc = 0; - int num_events = 0; - int num_valid_events = 0; - int num_sent = 0; - struct dirent **events = NULL; // names of events to buffer - int i = 0; - - // reset the watch on this directory, and ensure we're watching the right one. - rc = udev_monitor_fs_watch_reset(monitor); - if (rc < 0) { - - log_error("Failed to re-watch '%s', rc = %d", - monitor->events_dir, rc); - goto udev_monitor_fs_push_events_cleanup; + char pathbuf[PATH_MAX + 1]; + int dirfd = -1; + int fd = -1; + int rc = 0; + int num_events = 0; + int num_valid_events = 0; + int num_sent = 0; + struct dirent **events = NULL; // names of events to buffer + int i = 0; + + // reset the watch on this directory, and ensure we're watching the right one. + rc = udev_monitor_fs_watch_reset (monitor); + if (rc < 0) + { + + log_error ("Failed to re-watch '%s', rc = %d", monitor->events_dir, rc); + goto udev_monitor_fs_push_events_cleanup; + } + // find new events... + dirfd = open (monitor->events_dir, O_DIRECTORY | O_CLOEXEC); + if (dirfd < 0) + { + + rc = -errno; + log_error ("open('%s') rc = %d", monitor->events_dir, rc); + goto udev_monitor_fs_push_events_cleanup; + } + + num_events = + scandirat (dirfd, ".", &events, udev_monitor_fs_scandir_filter, + alphasort); + + if (num_events < 0) + { + + rc = -errno; + log_error ("scandir('%s') rc = %d", monitor->events_dir, rc); + goto udev_monitor_fs_push_events_cleanup; + } + + if (num_events == 0) + { + + // got nothing + rc = -ENODATA; + goto udev_monitor_fs_push_events_cleanup; + } + + num_valid_events = num_events; + + // send them all off! + for (i = 0; i < num_events; i++) + { + + snprintf (pathbuf, PATH_MAX, "%s/%s", monitor->events_dir, + events[i]->d_name); + + fd = open (pathbuf, O_RDONLY | O_CLOEXEC); + if (fd < 0) + { + + rc = -errno; + log_error ("cannot open event: open('%s') rc = %d", pathbuf, rc); + + // we consider it more important to preserve order and drop events + // than to try to resend later. + unlink (pathbuf); } - // find new events... - dirfd = open(monitor->events_dir, O_DIRECTORY | O_CLOEXEC); - if (dirfd < 0) { - - rc = -errno; - log_error("open('%s') rc = %d", monitor->events_dir, rc); - goto udev_monitor_fs_push_events_cleanup; - } - - num_events = - scandirat(dirfd, ".", &events, udev_monitor_fs_scandir_filter, - alphasort); + else + { - if (num_events < 0) { - - rc = -errno; - log_error("scandir('%s') rc = %d", monitor->events_dir, rc); - goto udev_monitor_fs_push_events_cleanup; - } - - if (num_events == 0) { - - // got nothing - rc = -ENODATA; - goto udev_monitor_fs_push_events_cleanup; - } + // propagate to the monitor's socket + rc = udev_monitor_fs_push_event (fd, monitor); - num_valid_events = num_events; + // garbage-collect + close (fd); + unlink (pathbuf); - // send them all off! - for (i = 0; i < num_events; i++) { + if (rc == -EBADMSG || rc == -EMSGSIZE) + { - snprintf(pathbuf, PATH_MAX, "%s/%s", monitor->events_dir, - events[i]->d_name); + // invalid message anyway + rc = 0; + num_valid_events--; + continue; + } - fd = open(pathbuf, O_RDONLY | O_CLOEXEC); - if (fd < 0) { + else if (rc < 0) + { - rc = -errno; - log_error("cannot open event: open('%s') rc = %d", - pathbuf, rc); + if (rc != -EAGAIN) + { - // we consider it more important to preserve order and drop events - // than to try to resend later. - unlink(pathbuf); - } else { - - // propagate to the monitor's socket - rc = udev_monitor_fs_push_event(fd, monitor); - - // garbage-collect - close(fd); - unlink(pathbuf); - - if (rc == -EBADMSG || rc == -EMSGSIZE) { - - // invalid message anyway - rc = 0; - num_valid_events--; - continue; - } - - else if (rc < 0) { - - if (rc != -EAGAIN) { - - // socket-level error - log_error - ("failed to push event '%s', rc = %d", - pathbuf, rc); - break; - } else { - - // sent as many as we could - rc = 0; - break; - } - } else if (rc == 0) { - - num_sent++; - } + // socket-level error + log_error + ("failed to push event '%s', rc = %d", pathbuf, rc); + break; } - } + else + { - udev_monitor_fs_push_events_cleanup: + // sent as many as we could + rc = 0; + break; + } + } + else if (rc == 0) + { - if (dirfd >= 0) { - close(dirfd); + num_sent++; + } } + } - if (events != NULL) { - for (i = 0; i < num_events; i++) { +udev_monitor_fs_push_events_cleanup: - if (events[i] != NULL) { - free(events[i]); - events[i] = NULL; - } - } + if (dirfd >= 0) + { + close (dirfd); + } + + if (events != NULL) + { + for (i = 0; i < num_events; i++) + { - free(events); + if (events[i] != NULL) + { + free (events[i]); + events[i] = NULL; + } } - if (num_sent == 0 && num_valid_events > 0) { + free (events); + } - // there are pending events, but we couldn't push any. - rc = -EAGAIN; - } + if (num_sent == 0 && num_valid_events > 0) + { + + // there are pending events, but we couldn't push any. + rc = -EAGAIN; + } - return rc; + return rc; } #ifdef TEST #include "libudev.h" -int main(int argc, char **argv) +int +main (int argc, char **argv) { - int rc = 0; - char pathbuf[PATH_MAX + 1]; - struct udev *udev_client = NULL; - struct udev_monitor *monitor = NULL; - int monitor_fd = 0; - struct udev_device *dev = NULL; - struct pollfd pfd[1]; - int num_events = INT_MAX; - int num_forks = 0; - - // usage: $0 [num events to process [num times to fork]] - if (argc > 1) { - char *tmp = NULL; - num_events = (int)strtol(argv[1], &tmp, 10); - if (tmp == argv[1] || *tmp != '\0') { - fprintf(stderr, - "Usage: %s [number of events to process [number of times to fork]]\n", - argv[0]); - exit(1); - } - - if (argc > 2) { - - num_forks = (int)strtol(argv[2], &tmp, 10); - if (tmp == argv[2] || *tmp != '\0') { - fprintf(stderr, - "Usage: %s [number of events to process [number of times to fork]]\n", - argv[0]); - exit(1); - } - } + int rc = 0; + char pathbuf[PATH_MAX + 1]; + struct udev *udev_client = NULL; + struct udev_monitor *monitor = NULL; + int monitor_fd = 0; + struct udev_device *dev = NULL; + struct pollfd pfd[1]; + int num_events = INT_MAX; + int num_forks = 0; + + // usage: $0 [num events to process [num times to fork]] + if (argc > 1) + { + char *tmp = NULL; + num_events = (int) strtol (argv[1], &tmp, 10); + if (tmp == argv[1] || *tmp != '\0') + { + fprintf (stderr, + "Usage: %s [number of events to process [number of times to fork]]\n", + argv[0]); + exit (1); } - // make sure events dir exists - log_trace("events directory '%s'", UDEV_FS_EVENTS_DIR); - - rc = mkdir(UDEV_FS_EVENTS_DIR, 0700); - if (rc != 0) { - rc = -errno; - if (rc != -EEXIST) { - log_error("mkdir('%s') rc = %d", UDEV_FS_EVENTS_DIR, - rc); - exit(1); - } + if (argc > 2) + { + + num_forks = (int) strtol (argv[2], &tmp, 10); + if (tmp == argv[2] || *tmp != '\0') + { + fprintf (stderr, + "Usage: %s [number of events to process [number of times to fork]]\n", + argv[0]); + exit (1); + } + } + } + // make sure events dir exists + log_trace ("events directory '%s'", UDEV_FS_EVENTS_DIR); + + rc = mkdir (UDEV_FS_EVENTS_DIR, 0700); + if (rc != 0) + { + + rc = -errno; + if (rc != -EEXIST) + { + log_error ("mkdir('%s') rc = %d", UDEV_FS_EVENTS_DIR, rc); + exit (1); } + } - udev_monitor_fs_events_path("", pathbuf, 0); + udev_monitor_fs_events_path ("", pathbuf, 0); - printf("Watching '%s'\n", pathbuf); + printf ("Watching '%s'\n", pathbuf); - udev_client = udev_new(); - if (udev_client == NULL) { + udev_client = udev_new (); + if (udev_client == NULL) + { - // OOM - exit(2); - } + // OOM + exit (2); + } - monitor = udev_monitor_new_from_netlink(udev_client, "udev"); - if (monitor == NULL) { + monitor = udev_monitor_new_from_netlink (udev_client, "udev"); + if (monitor == NULL) + { - // OOM or error - udev_unref(udev_client); - exit(2); - } + // OOM or error + udev_unref (udev_client); + exit (2); + } - printf("Press Ctrl-C to quit\n"); + printf ("Press Ctrl-C to quit\n"); - monitor_fd = udev_monitor_get_fd(monitor); - if (monitor_fd < 0) { + monitor_fd = udev_monitor_get_fd (monitor); + if (monitor_fd < 0) + { - rc = -errno; - log_error("udev_monitor_get_fd rc = %d\n", rc); - exit(3); - } + rc = -errno; + log_error ("udev_monitor_get_fd rc = %d\n", rc); + exit (3); + } - pfd[0].fd = monitor_fd; - pfd[0].events = POLLIN; + pfd[0].fd = monitor_fd; + pfd[0].events = POLLIN; - while (num_events > 0) { + while (num_events > 0) + { - // wait for the next device - rc = poll(pfd, 1, -1); - if (rc < 0) { + // wait for the next device + rc = poll (pfd, 1, -1); + if (rc < 0) + { - log_error("poll(%d) rc = %d\n", monitor_fd, rc); - break; - } - // get devices - while (num_events > 0) { - - dev = udev_monitor_receive_device(monitor); - if (dev == NULL) { - break; - } - - int pid = getpid(); - struct udev_list_entry *list_entry = NULL; - - printf("[%d] [%d] ACTION: '%s'\n", pid, num_events, - udev_device_get_action(dev)); - printf("[%d] [%d] SEQNUM: %llu\n", pid, num_events, - udev_device_get_seqnum(dev)); - printf("[%d] [%d] USEC: %llu\n", pid, num_events, - udev_device_get_usec_since_initialized(dev)); - printf("[%d] [%d] DEVNODE: '%s'\n", pid, num_events, - udev_device_get_devnode(dev)); - printf("[%d] [%d] DEVPATH: '%s'\n", pid, num_events, - udev_device_get_devpath(dev)); - printf("[%d] [%d] SYSNAME: '%s'\n", pid, num_events, - udev_device_get_sysname(dev)); - printf("[%d] [%d] SYSPATH: '%s'\n", pid, num_events, - udev_device_get_syspath(dev)); - printf("[%d] [%d] SUBSYSTEM: '%s'\n", pid, num_events, - udev_device_get_subsystem(dev)); - printf("[%d] [%d] DEVTYPE: '%s'\n", pid, num_events, - udev_device_get_devtype(dev)); - printf("[%d] [%d] SYSNUM: '%s'\n", pid, num_events, - udev_device_get_sysnum(dev)); - printf("[%d] [%d] DRIVER: '%s'\n", pid, num_events, - udev_device_get_driver(dev)); - printf("[%d] [%d] DEVNUM: %d:%d\n", pid, - num_events, major(udev_device_get_devnum(dev)), - minor(udev_device_get_devnum(dev))); - printf("[%d] [%d] IFINDEX: '%s'\n", pid, num_events, - udev_device_get_property_value(dev, "IFINDEX")); - printf("[%d] [%d] DEVMODE: '%s'\n", pid, num_events, - udev_device_get_property_value(dev, "DEVMODE")); - printf("[%d] [%d] DEVUID: '%s'\n", pid, num_events, - udev_device_get_property_value(dev, "DEVUID")); - printf("[%d] [%d] DEVGID: '%s'\n", pid, num_events, - udev_device_get_property_value(dev, "DEVGID")); - - list_entry = udev_device_get_devlinks_list_entry(dev); - udev_list_entry_foreach(list_entry, - udev_list_entry_get_next - (list_entry)) { - - printf("[%d] [%d] devlink: '%s'\n", pid, - num_events, - udev_list_entry_get_name(list_entry)); - } - - list_entry = udev_device_get_properties_list_entry(dev); - udev_list_entry_foreach(list_entry, - udev_list_entry_get_next - (list_entry)) { - - printf("[%d] [%d] property: '%s' = '%s'\n", - pid, num_events, - udev_list_entry_get_name(list_entry), - udev_list_entry_get_value(list_entry)); - } - - list_entry = udev_device_get_tags_list_entry(dev); - udev_list_entry_foreach(list_entry, - udev_list_entry_get_next - (list_entry)) { - - printf("[%d] [%d] tag: '%s'\n", pid, - num_events, - udev_list_entry_get_name(list_entry)); - } - - list_entry = udev_device_get_sysattr_list_entry(dev); - udev_list_entry_foreach(list_entry, - udev_list_entry_get_next - (list_entry)) { - - printf("[%d] [%d] sysattr: '%s'\n", pid, - num_events, - udev_list_entry_get_name(list_entry)); - } - - printf("\n"); - - udev_device_unref(dev); - - num_events--; - } + log_error ("poll(%d) rc = %d\n", monitor_fd, rc); + break; + } + // get devices + while (num_events > 0) + { + + dev = udev_monitor_receive_device (monitor); + if (dev == NULL) + { + break; + } + + int pid = getpid (); + struct udev_list_entry *list_entry = NULL; + + printf ("[%d] [%d] ACTION: '%s'\n", pid, num_events, + udev_device_get_action (dev)); + printf ("[%d] [%d] SEQNUM: %llu\n", pid, num_events, + udev_device_get_seqnum (dev)); + printf ("[%d] [%d] USEC: %llu\n", pid, num_events, + udev_device_get_usec_since_initialized (dev)); + printf ("[%d] [%d] DEVNODE: '%s'\n", pid, num_events, + udev_device_get_devnode (dev)); + printf ("[%d] [%d] DEVPATH: '%s'\n", pid, num_events, + udev_device_get_devpath (dev)); + printf ("[%d] [%d] SYSNAME: '%s'\n", pid, num_events, + udev_device_get_sysname (dev)); + printf ("[%d] [%d] SYSPATH: '%s'\n", pid, num_events, + udev_device_get_syspath (dev)); + printf ("[%d] [%d] SUBSYSTEM: '%s'\n", pid, num_events, + udev_device_get_subsystem (dev)); + printf ("[%d] [%d] DEVTYPE: '%s'\n", pid, num_events, + udev_device_get_devtype (dev)); + printf ("[%d] [%d] SYSNUM: '%s'\n", pid, num_events, + udev_device_get_sysnum (dev)); + printf ("[%d] [%d] DRIVER: '%s'\n", pid, num_events, + udev_device_get_driver (dev)); + printf ("[%d] [%d] DEVNUM: %d:%d\n", pid, + num_events, major (udev_device_get_devnum (dev)), + minor (udev_device_get_devnum (dev))); + printf ("[%d] [%d] IFINDEX: '%s'\n", pid, num_events, + udev_device_get_property_value (dev, "IFINDEX")); + printf ("[%d] [%d] DEVMODE: '%s'\n", pid, num_events, + udev_device_get_property_value (dev, "DEVMODE")); + printf ("[%d] [%d] DEVUID: '%s'\n", pid, num_events, + udev_device_get_property_value (dev, "DEVUID")); + printf ("[%d] [%d] DEVGID: '%s'\n", pid, num_events, + udev_device_get_property_value (dev, "DEVGID")); + + list_entry = udev_device_get_devlinks_list_entry (dev); + udev_list_entry_foreach (list_entry, + udev_list_entry_get_next (list_entry)) + { + + printf ("[%d] [%d] devlink: '%s'\n", pid, + num_events, udev_list_entry_get_name (list_entry)); + } + + list_entry = udev_device_get_properties_list_entry (dev); + udev_list_entry_foreach (list_entry, + udev_list_entry_get_next (list_entry)) + { + + printf ("[%d] [%d] property: '%s' = '%s'\n", + pid, num_events, + udev_list_entry_get_name (list_entry), + udev_list_entry_get_value (list_entry)); + } + + list_entry = udev_device_get_tags_list_entry (dev); + udev_list_entry_foreach (list_entry, + udev_list_entry_get_next (list_entry)) + { + + printf ("[%d] [%d] tag: '%s'\n", pid, + num_events, udev_list_entry_get_name (list_entry)); + } + + list_entry = udev_device_get_sysattr_list_entry (dev); + udev_list_entry_foreach (list_entry, + udev_list_entry_get_next (list_entry)) + { + + printf ("[%d] [%d] sysattr: '%s'\n", pid, + num_events, udev_list_entry_get_name (list_entry)); + } + + printf ("\n"); + + udev_device_unref (dev); + + num_events--; + } - // do our forks - if (num_forks > 0) { + // do our forks + if (num_forks > 0) + { - num_forks--; + num_forks--; - int pid = fork(); - if (pid < 0) { + int pid = fork (); + if (pid < 0) + { - rc = -errno; - fprintf(stderr, "fork: %s\n", strerror(-rc)); - break; - } else if (pid == 0) { + rc = -errno; + fprintf (stderr, "fork: %s\n", strerror (-rc)); + break; + } + else if (pid == 0) + { - printf("[%d]\n", getpid()); - } - } + printf ("[%d]\n", getpid ()); + } } + } - udev_monitor_fs_destroy(monitor); + udev_monitor_fs_destroy (monitor); - exit(0); + exit (0); } #endif diff --git a/libudev-compat/libudev-fs.h b/libudev-compat/libudev-fs.h index dbcf2d1..e5b1c51 100644 --- a/libudev-compat/libudev-fs.h +++ b/libudev-compat/libudev-fs.h @@ -66,9 +66,9 @@ #include "libudev-private.h" -int udev_monitor_fs_setup(struct udev_monitor *monitor); -int udev_monitor_fs_destroy(struct udev_monitor *monitor); -int udev_monitor_fs_shutdown(struct udev_monitor *monitor); -int udev_monitor_fs_push_events(struct udev_monitor *monitor); +int udev_monitor_fs_setup (struct udev_monitor *monitor); +int udev_monitor_fs_destroy (struct udev_monitor *monitor); +int udev_monitor_fs_shutdown (struct udev_monitor *monitor); +int udev_monitor_fs_push_events (struct udev_monitor *monitor); #endif diff --git a/libudev-compat/libudev-hwdb.c b/libudev-compat/libudev-hwdb.c index 53128b0..b04a437 100644 --- a/libudev-compat/libudev-hwdb.c +++ b/libudev-compat/libudev-hwdb.c @@ -43,13 +43,14 @@ * * Opaque object representing the hardware database. */ -struct udev_hwdb { - struct udev *udev; - int refcount; +struct udev_hwdb +{ + struct udev *udev; + int refcount; - sd_hwdb *hwdb; + sd_hwdb *hwdb; - struct udev_list properties_list; + struct udev_list properties_list; }; /** @@ -60,29 +61,30 @@ struct udev_hwdb { * * Returns: a hwdb context. **/ -_public_ struct udev_hwdb *udev_hwdb_new(struct udev *udev) +_public_ struct udev_hwdb * +udev_hwdb_new (struct udev *udev) { - _cleanup_hwdb_unref_ sd_hwdb *hwdb_internal = NULL; - struct udev_hwdb *hwdb; - int r; + _cleanup_hwdb_unref_ sd_hwdb *hwdb_internal = NULL; + struct udev_hwdb *hwdb; + int r; - assert_return(udev, NULL); + assert_return (udev, NULL); - r = sd_hwdb_new(&hwdb_internal); - if (r < 0) - return NULL; + r = sd_hwdb_new (&hwdb_internal); + if (r < 0) + return NULL; - hwdb = new0(struct udev_hwdb, 1); - if (!hwdb) - return NULL; + hwdb = new0 (struct udev_hwdb, 1); + if (!hwdb) + return NULL; - hwdb->refcount = 1; - hwdb->hwdb = hwdb_internal; - hwdb_internal = NULL; + hwdb->refcount = 1; + hwdb->hwdb = hwdb_internal; + hwdb_internal = NULL; - udev_list_init(udev, &hwdb->properties_list, true); + udev_list_init (udev, &hwdb->properties_list, true); - return hwdb; + return hwdb; } /** @@ -93,12 +95,13 @@ _public_ struct udev_hwdb *udev_hwdb_new(struct udev *udev) * * Returns: the passed enumeration context **/ -_public_ struct udev_hwdb *udev_hwdb_ref(struct udev_hwdb *hwdb) +_public_ struct udev_hwdb * +udev_hwdb_ref (struct udev_hwdb *hwdb) { - if (!hwdb) - return NULL; - hwdb->refcount++; - return hwdb; + if (!hwdb) + return NULL; + hwdb->refcount++; + return hwdb; } /** @@ -110,17 +113,18 @@ _public_ struct udev_hwdb *udev_hwdb_ref(struct udev_hwdb *hwdb) * * Returns: #NULL **/ -_public_ struct udev_hwdb *udev_hwdb_unref(struct udev_hwdb *hwdb) +_public_ struct udev_hwdb * +udev_hwdb_unref (struct udev_hwdb *hwdb) { - if (!hwdb) - return NULL; - hwdb->refcount--; - if (hwdb->refcount > 0) - return NULL; - sd_hwdb_unref(hwdb->hwdb); - udev_list_cleanup(&hwdb->properties_list); - free(hwdb); - return NULL; + if (!hwdb) + return NULL; + hwdb->refcount--; + if (hwdb->refcount > 0) + return NULL; + sd_hwdb_unref (hwdb->hwdb); + udev_list_cleanup (&hwdb->properties_list); + free (hwdb); + return NULL; } /** @@ -136,30 +140,30 @@ _public_ struct udev_hwdb *udev_hwdb_unref(struct udev_hwdb *hwdb) * * Returns: a udev_list_entry. */ -_public_ struct udev_list_entry *udev_hwdb_get_properties_list_entry(struct - udev_hwdb - *hwdb, - const char - *modalias, - unsigned - int flags) +_public_ struct udev_list_entry * +udev_hwdb_get_properties_list_entry (struct + udev_hwdb + *hwdb, + const char *modalias, unsigned int flags) { - const char *key, *value; + const char *key, *value; - if (!hwdb || !modalias) { - errno = EINVAL; - return NULL; - } + if (!hwdb || !modalias) + { + errno = EINVAL; + return NULL; + } - udev_list_cleanup(&hwdb->properties_list); + udev_list_cleanup (&hwdb->properties_list); - SD_HWDB_FOREACH_PROPERTY(hwdb->hwdb, modalias, key, value) { - if (udev_list_entry_add(&hwdb->properties_list, key, value) == - NULL) { - errno = ENOMEM; - return NULL; - } - } + SD_HWDB_FOREACH_PROPERTY (hwdb->hwdb, modalias, key, value) + { + if (udev_list_entry_add (&hwdb->properties_list, key, value) == NULL) + { + errno = ENOMEM; + return NULL; + } + } - return udev_list_get_entry(&hwdb->properties_list); + return udev_list_get_entry (&hwdb->properties_list); } diff --git a/libudev-compat/libudev-list.c b/libudev-compat/libudev-list.c index 3f25e93..e32025d 100644 --- a/libudev-compat/libudev-list.c +++ b/libudev-compat/libudev-list.c @@ -46,240 +46,265 @@ * Opaque object representing one entry in a list. An entry contains * contains a name, and optionally a value. */ -struct udev_list_entry { - struct udev_list_node node; - struct udev_list *list; - char *name; - char *value; - int num; +struct udev_list_entry +{ + struct udev_list_node node; + struct udev_list *list; + char *name; + char *value; + int num; }; /* the list's head points to itself if empty */ -void udev_list_node_init(struct udev_list_node *list) +void +udev_list_node_init (struct udev_list_node *list) { - list->next = list; - list->prev = list; + list->next = list; + list->prev = list; } -int udev_list_node_is_empty(struct udev_list_node *list) +int +udev_list_node_is_empty (struct udev_list_node *list) { - return list->next == list; + return list->next == list; } -static void udev_list_node_insert_between(struct udev_list_node *new, - struct udev_list_node *prev, - struct udev_list_node *next) +static void +udev_list_node_insert_between (struct udev_list_node *new, + struct udev_list_node *prev, + struct udev_list_node *next) { - next->prev = new; - new->next = next; - new->prev = prev; - prev->next = new; + next->prev = new; + new->next = next; + new->prev = prev; + prev->next = new; } -void udev_list_node_append(struct udev_list_node *new, - struct udev_list_node *list) +void +udev_list_node_append (struct udev_list_node *new, + struct udev_list_node *list) { - udev_list_node_insert_between(new, list->prev, list); + udev_list_node_insert_between (new, list->prev, list); } -void udev_list_node_remove(struct udev_list_node *entry) +void +udev_list_node_remove (struct udev_list_node *entry) { - struct udev_list_node *prev = entry->prev; - struct udev_list_node *next = entry->next; + struct udev_list_node *prev = entry->prev; + struct udev_list_node *next = entry->next; - next->prev = prev; - prev->next = next; + next->prev = prev; + prev->next = next; - entry->prev = NULL; - entry->next = NULL; + entry->prev = NULL; + entry->next = NULL; } /* return list entry which embeds this node */ -static inline struct udev_list_entry *list_node_to_entry(struct udev_list_node - *node) +static inline struct udev_list_entry * +list_node_to_entry (struct udev_list_node *node) { - return container_of(node, struct udev_list_entry, node); + return container_of (node, struct udev_list_entry, node); } -void udev_list_init(struct udev *udev, struct udev_list *list, bool unique) +void +udev_list_init (struct udev *udev, struct udev_list *list, bool unique) { - memzero(list, sizeof(struct udev_list)); - list->udev = udev; - list->unique = unique; - udev_list_node_init(&list->node); + memzero (list, sizeof (struct udev_list)); + list->udev = udev; + list->unique = unique; + udev_list_node_init (&list->node); } /* insert entry into a list as the last element */ -static void udev_list_entry_append(struct udev_list_entry *new, - struct udev_list *list) +static void +udev_list_entry_append (struct udev_list_entry *new, struct udev_list *list) { - /* inserting before the list head make the node the last node in the list */ - udev_list_node_insert_between(&new->node, list->node.prev, &list->node); - new->list = list; + /* inserting before the list head make the node the last node in the list */ + udev_list_node_insert_between (&new->node, list->node.prev, &list->node); + new->list = list; } /* insert entry into a list, before a given existing entry */ -static void udev_list_entry_insert_before(struct udev_list_entry *new, - struct udev_list_entry *entry) +static void +udev_list_entry_insert_before (struct udev_list_entry *new, + struct udev_list_entry *entry) { - udev_list_node_insert_between(&new->node, entry->node.prev, - &entry->node); - new->list = entry->list; + udev_list_node_insert_between (&new->node, entry->node.prev, &entry->node); + new->list = entry->list; } /* binary search in sorted array */ -static int list_search(struct udev_list *list, const char *name) +static int +list_search (struct udev_list *list, const char *name) { - unsigned int first, last; - - first = 0; - last = list->entries_cur; - while (first < last) { - unsigned int i; - int cmp; - - i = (first + last) / 2; - cmp = strcmp(name, list->entries[i]->name); - if (cmp < 0) - last = i; - else if (cmp > 0) - first = i + 1; - else - return i; - } - - /* not found, return negative insertion-index+1 */ - return -(first + 1); + unsigned int first, last; + + first = 0; + last = list->entries_cur; + while (first < last) + { + unsigned int i; + int cmp; + + i = (first + last) / 2; + cmp = strcmp (name, list->entries[i]->name); + if (cmp < 0) + last = i; + else if (cmp > 0) + first = i + 1; + else + return i; + } + + /* not found, return negative insertion-index+1 */ + return -(first + 1); } -struct udev_list_entry *udev_list_entry_add(struct udev_list *list, - const char *name, const char *value) +struct udev_list_entry * +udev_list_entry_add (struct udev_list *list, + const char *name, const char *value) { - struct udev_list_entry *entry; - int i = 0; - - if (list->unique) { - /* lookup existing name or insertion-index */ - i = list_search(list, name); - if (i >= 0) { - entry = list->entries[i]; - - free(entry->value); - if (value == NULL) { - entry->value = NULL; - return entry; - } - entry->value = strdup(value); - if (entry->value == NULL) - return NULL; - return entry; - } + struct udev_list_entry *entry; + int i = 0; + + if (list->unique) + { + /* lookup existing name or insertion-index */ + i = list_search (list, name); + if (i >= 0) + { + entry = list->entries[i]; + + free (entry->value); + if (value == NULL) + { + entry->value = NULL; + return entry; + } + entry->value = strdup (value); + if (entry->value == NULL) + return NULL; + return entry; } - - /* add new name */ - entry = new0(struct udev_list_entry, 1); - if (entry == NULL) - return NULL; - entry->name = strdup(name); - if (entry->name == NULL) { - free(entry); - return NULL; - } - if (value != NULL) { - entry->value = strdup(value); - if (entry->value == NULL) { - free(entry->name); - free(entry); - return NULL; - } + } + + /* add new name */ + entry = new0 (struct udev_list_entry, 1); + if (entry == NULL) + return NULL; + entry->name = strdup (name); + if (entry->name == NULL) + { + free (entry); + return NULL; + } + if (value != NULL) + { + entry->value = strdup (value); + if (entry->value == NULL) + { + free (entry->name); + free (entry); + return NULL; } - - if (list->unique) { - /* allocate or enlarge sorted array if needed */ - if (list->entries_cur >= list->entries_max) { - struct udev_list_entry **entries; - unsigned int add; - - add = list->entries_max; - if (add < 1) - add = 64; - entries = - realloc(list->entries, - (list->entries_max + - add) * sizeof(struct udev_list_entry *)); - if (entries == NULL) { - free(entry->name); - free(entry->value); - free(entry); - return NULL; - } - list->entries = entries; - list->entries_max += add; - } - - /* the negative i returned the insertion index */ - i = (-i) - 1; - - /* insert into sorted list */ - if ((unsigned int)i < list->entries_cur) - udev_list_entry_insert_before(entry, list->entries[i]); - else - udev_list_entry_append(entry, list); - - /* insert into sorted array */ - memmove(&list->entries[i + 1], &list->entries[i], - (list->entries_cur - - i) * sizeof(struct udev_list_entry *)); - list->entries[i] = entry; - list->entries_cur++; - } else { - udev_list_entry_append(entry, list); + } + + if (list->unique) + { + /* allocate or enlarge sorted array if needed */ + if (list->entries_cur >= list->entries_max) + { + struct udev_list_entry **entries; + unsigned int add; + + add = list->entries_max; + if (add < 1) + add = 64; + entries = + realloc (list->entries, + (list->entries_max + + add) * sizeof (struct udev_list_entry *)); + if (entries == NULL) + { + free (entry->name); + free (entry->value); + free (entry); + return NULL; + } + list->entries = entries; + list->entries_max += add; } - return entry; + /* the negative i returned the insertion index */ + i = (-i) - 1; + + /* insert into sorted list */ + if ((unsigned int) i < list->entries_cur) + udev_list_entry_insert_before (entry, list->entries[i]); + else + udev_list_entry_append (entry, list); + + /* insert into sorted array */ + memmove (&list->entries[i + 1], &list->entries[i], + (list->entries_cur - i) * sizeof (struct udev_list_entry *)); + list->entries[i] = entry; + list->entries_cur++; + } + else + { + udev_list_entry_append (entry, list); + } + + return entry; } -void udev_list_entry_delete(struct udev_list_entry *entry) +void +udev_list_entry_delete (struct udev_list_entry *entry) { - if (entry->list->entries != NULL) { - int i; - struct udev_list *list = entry->list; - - /* remove entry from sorted array */ - i = list_search(list, entry->name); - if (i >= 0) { - memmove(&list->entries[i], &list->entries[i + 1], - ((list->entries_cur - 1) - - i) * sizeof(struct udev_list_entry *)); - list->entries_cur--; - } + if (entry->list->entries != NULL) + { + int i; + struct udev_list *list = entry->list; + + /* remove entry from sorted array */ + i = list_search (list, entry->name); + if (i >= 0) + { + memmove (&list->entries[i], &list->entries[i + 1], + ((list->entries_cur - 1) - + i) * sizeof (struct udev_list_entry *)); + list->entries_cur--; } + } - udev_list_node_remove(&entry->node); - free(entry->name); - free(entry->value); - free(entry); + udev_list_node_remove (&entry->node); + free (entry->name); + free (entry->value); + free (entry); } -void udev_list_cleanup(struct udev_list *list) +void +udev_list_cleanup (struct udev_list *list) { - struct udev_list_entry *entry_loop; - struct udev_list_entry *entry_tmp; - - free(list->entries); - list->entries = NULL; - list->entries_cur = 0; - list->entries_max = 0; - udev_list_entry_foreach_safe(entry_loop, entry_tmp, - udev_list_get_entry(list)) - udev_list_entry_delete(entry_loop); + struct udev_list_entry *entry_loop; + struct udev_list_entry *entry_tmp; + + free (list->entries); + list->entries = NULL; + list->entries_cur = 0; + list->entries_max = 0; + udev_list_entry_foreach_safe (entry_loop, entry_tmp, + udev_list_get_entry (list)) + udev_list_entry_delete (entry_loop); } -struct udev_list_entry *udev_list_get_entry(struct udev_list *list) +struct udev_list_entry * +udev_list_get_entry (struct udev_list *list) { - if (udev_list_node_is_empty(&list->node)) - return NULL; - return list_node_to_entry(list->node.next); + if (udev_list_node_is_empty (&list->node)) + return NULL; + return list_node_to_entry (list->node.next); } /** @@ -290,18 +315,18 @@ struct udev_list_entry *udev_list_get_entry(struct udev_list *list) * * Returns: udev_list_entry, #NULL if no more entries are available. */ -struct udev_list_entry *udev_list_entry_get_next(struct udev_list_entry - *list_entry) +struct udev_list_entry * +udev_list_entry_get_next (struct udev_list_entry *list_entry) { - struct udev_list_node *next; - - if (list_entry == NULL) - return NULL; - next = list_entry->node.next; - /* empty list or no more entries */ - if (next == &list_entry->list->node) - return NULL; - return list_node_to_entry(next); + struct udev_list_node *next; + + if (list_entry == NULL) + return NULL; + next = list_entry->node.next; + /* empty list or no more entries */ + if (next == &list_entry->list->node) + return NULL; + return list_node_to_entry (next); } /** @@ -313,22 +338,22 @@ struct udev_list_entry *udev_list_entry_get_next(struct udev_list_entry * * Returns: udev_list_entry, #NULL if no matching entry is found. */ -struct udev_list_entry *udev_list_entry_get_by_name(struct udev_list_entry - *list_entry, - const char *name) +struct udev_list_entry * +udev_list_entry_get_by_name (struct udev_list_entry + *list_entry, const char *name) { - int i; + int i; - if (list_entry == NULL) - return NULL; + if (list_entry == NULL) + return NULL; - if (!list_entry->list->unique) - return NULL; + if (!list_entry->list->unique) + return NULL; - i = list_search(list_entry->list, name); - if (i < 0) - return NULL; - return list_entry->list->entries[i]; + i = list_search (list_entry->list, name); + if (i < 0) + return NULL; + return list_entry->list->entries[i]; } /** @@ -339,11 +364,12 @@ struct udev_list_entry *udev_list_entry_get_by_name(struct udev_list_entry * * Returns: the name string of this entry. */ -const char *udev_list_entry_get_name(struct udev_list_entry *list_entry) +const char * +udev_list_entry_get_name (struct udev_list_entry *list_entry) { - if (list_entry == NULL) - return NULL; - return list_entry->name; + if (list_entry == NULL) + return NULL; + return list_entry->name; } /** @@ -354,23 +380,26 @@ const char *udev_list_entry_get_name(struct udev_list_entry *list_entry) * * Returns: the value string of this entry. */ -const char *udev_list_entry_get_value(struct udev_list_entry *list_entry) +const char * +udev_list_entry_get_value (struct udev_list_entry *list_entry) { - if (list_entry == NULL) - return NULL; - return list_entry->value; + if (list_entry == NULL) + return NULL; + return list_entry->value; } -int udev_list_entry_get_num(struct udev_list_entry *list_entry) +int +udev_list_entry_get_num (struct udev_list_entry *list_entry) { - if (list_entry == NULL) - return -EINVAL; - return list_entry->num; + if (list_entry == NULL) + return -EINVAL; + return list_entry->num; } -void udev_list_entry_set_num(struct udev_list_entry *list_entry, int num) +void +udev_list_entry_set_num (struct udev_list_entry *list_entry, int num) { - if (list_entry == NULL) - return; - list_entry->num = num; + if (list_entry == NULL) + return; + list_entry->num = num; } diff --git a/libudev-compat/libudev-monitor.c b/libudev-compat/libudev-monitor.c index ae22659..9aae7b6 100644 --- a/libudev-compat/libudev-monitor.c +++ b/libudev-compat/libudev-monitor.c @@ -44,96 +44,103 @@ #include "libudev-private.h" #include "libudev-fs.h" -enum udev_monitor_netlink_group { - UDEV_MONITOR_NONE, - UDEV_MONITOR_KERNEL, - UDEV_MONITOR_UDEV, - UDEV_MONITOR_ANY +enum udev_monitor_netlink_group +{ + UDEV_MONITOR_NONE, + UDEV_MONITOR_KERNEL, + UDEV_MONITOR_UDEV, + UDEV_MONITOR_ANY }; #define UDEV_MONITOR_MAGIC 0xfeedcafe -struct udev_monitor_netlink_header { - /* "libudev" prefix to distinguish libudev and kernel messages */ - char prefix[8]; - /* - * magic to protect against daemon <-> library message format mismatch - * used in the kernel from socket filter rules; needs to be stored in network order - */ - unsigned int magic; - /* total length of header structure known to the sender */ - unsigned int header_size; - /* properties string buffer */ - unsigned int properties_off; - unsigned int properties_len; - /* - * hashes of primary device properties strings, to let libudev subscribers - * use in-kernel socket filters; values need to be stored in network order - */ - unsigned int filter_subsystem_hash; - unsigned int filter_devtype_hash; - unsigned int filter_tag_bloom_hi; - unsigned int filter_tag_bloom_lo; +struct udev_monitor_netlink_header +{ + /* "libudev" prefix to distinguish libudev and kernel messages */ + char prefix[8]; + /* + * magic to protect against daemon <-> library message format mismatch + * used in the kernel from socket filter rules; needs to be stored in network order + */ + unsigned int magic; + /* total length of header structure known to the sender */ + unsigned int header_size; + /* properties string buffer */ + unsigned int properties_off; + unsigned int properties_len; + /* + * hashes of primary device properties strings, to let libudev subscribers + * use in-kernel socket filters; values need to be stored in network order + */ + unsigned int filter_subsystem_hash; + unsigned int filter_devtype_hash; + unsigned int filter_tag_bloom_hi; + unsigned int filter_tag_bloom_lo; }; -static struct udev_monitor *udev_monitor_new(struct udev *udev) +static struct udev_monitor * +udev_monitor_new (struct udev *udev) { - struct udev_monitor *udev_monitor; - - udev_monitor = new0(struct udev_monitor, 1); - if (udev_monitor == NULL) - return NULL; - - udev_monitor->type = 0; - udev_monitor->refcount = 1; - udev_monitor->udev = udev; - udev_list_init(udev, &udev_monitor->filter_subsystem_list, false); - udev_list_init(udev, &udev_monitor->filter_tag_list, true); - return udev_monitor; + struct udev_monitor *udev_monitor; + + udev_monitor = new0 (struct udev_monitor, 1); + if (udev_monitor == NULL) + return NULL; + + udev_monitor->type = 0; + udev_monitor->refcount = 1; + udev_monitor->udev = udev; + udev_list_init (udev, &udev_monitor->filter_subsystem_list, false); + udev_list_init (udev, &udev_monitor->filter_tag_list, true); + return udev_monitor; } -static struct udev_monitor *udev_monitor_new_from_filesystem(struct udev *udev) +static struct udev_monitor * +udev_monitor_new_from_filesystem (struct udev *udev) { - // The approach taken here is to have the device manager - // record device events to well-known subdirectories in /dev. - // Then, the device manager in the root context can be instructed to - // record all relevant device events, and the admin can bind-mount - // subdirectory trees into container contexts. In doing so, the - // admin both controls fine-grained device information visibility - // (through permission bits) and aggregate device visibility - // (through bind-mounts) for both root and container contexts, - // all without requiring extra help from the kernel. Moreover, - // this approach is generic enough to not specific to a particular - // kernel or device manager. - // - // The purpose of libudev-compat is to help would-be - // udev listeners find and read the device information in the - // underlying /dev filesystem. - // - // --Jude Nelson - - struct udev_monitor *udev_monitor = NULL; - int rc = 0; - - if (udev == NULL) { - return NULL; - } - - udev_monitor = udev_monitor_new(udev); - if (udev_monitor == NULL) { - return NULL; - } - - rc = udev_monitor_fs_setup(udev_monitor); - if (rc < 0) { - - log_error("udev_monitor_fs_setup() rc = %d\n", rc); - return NULL; - } - - udev_monitor->type = UDEV_MONITOR_TYPE_UDEV; - - return udev_monitor; + // The approach taken here is to have the device manager + // record device events to well-known subdirectories in /dev. + // Then, the device manager in the root context can be instructed to + // record all relevant device events, and the admin can bind-mount + // subdirectory trees into container contexts. In doing so, the + // admin both controls fine-grained device information visibility + // (through permission bits) and aggregate device visibility + // (through bind-mounts) for both root and container contexts, + // all without requiring extra help from the kernel. Moreover, + // this approach is generic enough to not specific to a particular + // kernel or device manager. + // + // The purpose of libudev-compat is to help would-be + // udev listeners find and read the device information in the + // underlying /dev filesystem. + // + // --Jude Nelson + + struct udev_monitor *udev_monitor = NULL; + int rc = 0; + + if (udev == NULL) + { + return NULL; + } + + udev_monitor = udev_monitor_new (udev); + if (udev_monitor == NULL) + { + return NULL; + } + + rc = udev_monitor_fs_setup (udev_monitor); + if (rc < 0) + { + + log_error ("udev_monitor_fs_setup() rc = %d\n", rc); + return NULL; + } + + udev_monitor->type = UDEV_MONITOR_TYPE_UDEV; + + return udev_monitor; } /** @@ -163,115 +170,134 @@ static struct udev_monitor *udev_monitor_new_from_filesystem(struct udev *udev) * * Returns: a new udev monitor, or #NULL, in case of an error **/ -struct udev_monitor *udev_monitor_new_from_netlink(struct udev *udev, - const char *name) +struct udev_monitor * +udev_monitor_new_from_netlink (struct udev *udev, const char *name) { - if (strcmp(name, "udev") == 0) { - return udev_monitor_new_from_filesystem(udev); - } else { - return udev_monitor_new_from_netlink_fd(udev, name, -1); - } + if (strcmp (name, "udev") == 0) + { + return udev_monitor_new_from_filesystem (udev); + } + else + { + return udev_monitor_new_from_netlink_fd (udev, name, -1); + } } -static void monitor_set_nl_address(struct udev_monitor *udev_monitor) +static void +monitor_set_nl_address (struct udev_monitor *udev_monitor) { - union sockaddr_union snl; - socklen_t addrlen; - int r; - - assert(udev_monitor); - - /* get the address the kernel has assigned us - * it is usually, but not necessarily the pid - */ - addrlen = sizeof(struct sockaddr_nl); - r = getsockname(udev_monitor->sock, &snl.sa, &addrlen); - if (r >= 0) { - udev_monitor->snl.nl.nl_pid = snl.nl.nl_pid; - } + union sockaddr_union snl; + socklen_t addrlen; + int r; + + assert (udev_monitor); + + /* get the address the kernel has assigned us + * it is usually, but not necessarily the pid + */ + addrlen = sizeof (struct sockaddr_nl); + r = getsockname (udev_monitor->sock, &snl.sa, &addrlen); + if (r >= 0) + { + udev_monitor->snl.nl.nl_pid = snl.nl.nl_pid; + } } // NOTE: this method is here only for compatibility. -struct udev_monitor *udev_monitor_new_from_netlink_fd(struct udev *udev, - char const *name, int fd) +struct udev_monitor * +udev_monitor_new_from_netlink_fd (struct udev *udev, char const *name, int fd) { - struct udev_monitor *udev_monitor; - unsigned int group; - - if (udev == NULL) { - return NULL; + struct udev_monitor *udev_monitor; + unsigned int group; + + if (udev == NULL) + { + return NULL; + } + + if (name == NULL) + { + group = UDEV_MONITOR_NONE; + } + + else if (streq (name, "udev")) + { + + // libudev-compat: read from an event buffer on the fs + return udev_monitor_new_from_filesystem (udev); + + } + else if (streq (name, "kernel")) + { + group = UDEV_MONITOR_KERNEL; + } + else + { + return NULL; + } + + udev_monitor = udev_monitor_new (udev); + if (udev_monitor == NULL) + { + return NULL; + } + + if (fd < 0) + { + udev_monitor->sock = + socket (PF_NETLINK, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, + NETLINK_KOBJECT_UEVENT); + if (udev_monitor->sock < 0) + { + log_debug ("error getting socket: %s", strerror (errno)); + free (udev_monitor); + return NULL; } + } + else + { + udev_monitor->bound = true; + udev_monitor->sock = fd; + monitor_set_nl_address (udev_monitor); + } - if (name == NULL) { - group = UDEV_MONITOR_NONE; - } - - else if (streq(name, "udev")) { - - // libudev-compat: read from an event buffer on the fs - return udev_monitor_new_from_filesystem(udev); - - } else if (streq(name, "kernel")) { - group = UDEV_MONITOR_KERNEL; - } else { - return NULL; - } - - udev_monitor = udev_monitor_new(udev); - if (udev_monitor == NULL) { - return NULL; - } - - if (fd < 0) { - udev_monitor->sock = - socket(PF_NETLINK, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, - NETLINK_KOBJECT_UEVENT); - if (udev_monitor->sock < 0) { - log_debug("error getting socket: %s", strerror(errno)); - free(udev_monitor); - return NULL; - } - } else { - udev_monitor->bound = true; - udev_monitor->sock = fd; - monitor_set_nl_address(udev_monitor); - } + udev_monitor->snl.nl.nl_family = AF_NETLINK; + udev_monitor->snl.nl.nl_groups = group; - udev_monitor->snl.nl.nl_family = AF_NETLINK; - udev_monitor->snl.nl.nl_groups = group; + /* default destination for sending */ + udev_monitor->snl_destination.nl.nl_family = AF_NETLINK; + udev_monitor->snl_destination.nl.nl_groups = UDEV_MONITOR_UDEV; - /* default destination for sending */ - udev_monitor->snl_destination.nl.nl_family = AF_NETLINK; - udev_monitor->snl_destination.nl.nl_groups = UDEV_MONITOR_UDEV; + udev_monitor->type = UDEV_MONITOR_TYPE_KERNEL; - udev_monitor->type = UDEV_MONITOR_TYPE_KERNEL; - - return udev_monitor; + return udev_monitor; } -static inline void bpf_stmt(struct sock_filter *inss, unsigned int *i, - unsigned short code, unsigned int data) +static inline void +bpf_stmt (struct sock_filter *inss, unsigned int *i, + unsigned short code, unsigned int data) { - struct sock_filter *ins = &inss[*i]; + struct sock_filter *ins = &inss[*i]; - ins->code = code; - ins->k = data; - (*i)++; + ins->code = code; + ins->k = data; + (*i)++; } -static inline void bpf_jmp(struct sock_filter *inss, unsigned int *i, - unsigned short code, unsigned int data, - unsigned short jt, unsigned short jf) +static inline void +bpf_jmp (struct sock_filter *inss, unsigned int *i, + unsigned short code, unsigned int data, + unsigned short jt, unsigned short jf) { - struct sock_filter *ins = &inss[*i]; + struct sock_filter *ins = &inss[*i]; - ins->code = code; - ins->jt = jt; - ins->jf = jf; - ins->k = data; - (*i)++; + ins->code = code; + ins->jt = jt; + ins->jf = jf; + ins->k = data; + (*i)++; } /** @@ -283,148 +309,148 @@ static inline void bpf_jmp(struct sock_filter *inss, unsigned int *i, * * Returns: 0 on success, otherwise a negative error value. */ -int udev_monitor_filter_update(struct udev_monitor *udev_monitor) +int +udev_monitor_filter_update (struct udev_monitor *udev_monitor) { - struct sock_filter ins[512]; - struct sock_fprog filter; - unsigned int i; - struct udev_list_entry *list_entry; - int err; - - if (udev_list_get_entry(&udev_monitor->filter_subsystem_list) == NULL && - udev_list_get_entry(&udev_monitor->filter_tag_list) == NULL) - return 0; - - memzero(ins, sizeof(ins)); - i = 0; - - /* load magic in A */ - bpf_stmt(ins, &i, BPF_LD | BPF_W | BPF_ABS, - offsetof(struct udev_monitor_netlink_header, magic)); - /* jump if magic matches */ - bpf_jmp(ins, &i, BPF_JMP | BPF_JEQ | BPF_K, UDEV_MONITOR_MAGIC, 1, 0); - /* wrong magic, pass packet */ - bpf_stmt(ins, &i, BPF_RET | BPF_K, 0xffffffff); - - if (udev_list_get_entry(&udev_monitor->filter_tag_list) != NULL) { - int tag_matches; - - /* count tag matches, to calculate end of tag match block */ - tag_matches = 0; - udev_list_entry_foreach(list_entry, - udev_list_get_entry(&udev_monitor-> - filter_tag_list)) - tag_matches++; - - /* add all tags matches */ - udev_list_entry_foreach(list_entry, - udev_list_get_entry(&udev_monitor-> - filter_tag_list)) { - uint64_t tag_bloom_bits = - util_string_bloom64(udev_list_entry_get_name - (list_entry)); - uint32_t tag_bloom_hi = tag_bloom_bits >> 32; - uint32_t tag_bloom_lo = tag_bloom_bits & 0xffffffff; - - /* load device bloom bits in A */ - bpf_stmt(ins, &i, BPF_LD | BPF_W | BPF_ABS, - offsetof(struct udev_monitor_netlink_header, - filter_tag_bloom_hi)); - /* clear bits (tag bits & bloom bits) */ - bpf_stmt(ins, &i, BPF_ALU | BPF_AND | BPF_K, - tag_bloom_hi); - /* jump to next tag if it does not match */ - bpf_jmp(ins, &i, BPF_JMP | BPF_JEQ | BPF_K, - tag_bloom_hi, 0, 3); - - /* load device bloom bits in A */ - bpf_stmt(ins, &i, BPF_LD | BPF_W | BPF_ABS, - offsetof(struct udev_monitor_netlink_header, - filter_tag_bloom_lo)); - /* clear bits (tag bits & bloom bits) */ - bpf_stmt(ins, &i, BPF_ALU | BPF_AND | BPF_K, - tag_bloom_lo); - /* jump behind end of tag match block if tag matches */ - tag_matches--; - bpf_jmp(ins, &i, BPF_JMP | BPF_JEQ | BPF_K, - tag_bloom_lo, 1 + (tag_matches * 6), 0); - } - - /* nothing matched, drop packet */ - bpf_stmt(ins, &i, BPF_RET | BPF_K, 0); - } - - /* add all subsystem matches */ - if (udev_list_get_entry(&udev_monitor->filter_subsystem_list) != NULL) { - udev_list_entry_foreach(list_entry, - udev_list_get_entry(&udev_monitor-> - filter_subsystem_list)) - { - unsigned int hash = - util_string_hash32(udev_list_entry_get_name - (list_entry)); - - /* load device subsystem value in A */ - bpf_stmt(ins, &i, BPF_LD | BPF_W | BPF_ABS, - offsetof(struct udev_monitor_netlink_header, - filter_subsystem_hash)); - if (udev_list_entry_get_value(list_entry) == NULL) { - /* jump if subsystem does not match */ - bpf_jmp(ins, &i, BPF_JMP | BPF_JEQ | BPF_K, - hash, 0, 1); - } else { - /* jump if subsystem does not match */ - bpf_jmp(ins, &i, BPF_JMP | BPF_JEQ | BPF_K, - hash, 0, 3); - - /* load device devtype value in A */ - bpf_stmt(ins, &i, BPF_LD | BPF_W | BPF_ABS, - offsetof(struct - udev_monitor_netlink_header, - filter_devtype_hash)); - /* jump if value does not match */ - hash = - util_string_hash32(udev_list_entry_get_value - (list_entry)); - bpf_jmp(ins, &i, BPF_JMP | BPF_JEQ | BPF_K, - hash, 0, 1); - } - - /* matched, pass packet */ - bpf_stmt(ins, &i, BPF_RET | BPF_K, 0xffffffff); - - if (i + 1 >= ELEMENTSOF(ins)) - return -E2BIG; - } - - /* nothing matched, drop packet */ - bpf_stmt(ins, &i, BPF_RET | BPF_K, 0); - } + struct sock_filter ins[512]; + struct sock_fprog filter; + unsigned int i; + struct udev_list_entry *list_entry; + int err; + + if (udev_list_get_entry (&udev_monitor->filter_subsystem_list) == NULL && + udev_list_get_entry (&udev_monitor->filter_tag_list) == NULL) + return 0; + + memzero (ins, sizeof (ins)); + i = 0; + + /* load magic in A */ + bpf_stmt (ins, &i, BPF_LD | BPF_W | BPF_ABS, + offsetof (struct udev_monitor_netlink_header, magic)); + /* jump if magic matches */ + bpf_jmp (ins, &i, BPF_JMP | BPF_JEQ | BPF_K, UDEV_MONITOR_MAGIC, 1, 0); + /* wrong magic, pass packet */ + bpf_stmt (ins, &i, BPF_RET | BPF_K, 0xffffffff); + + if (udev_list_get_entry (&udev_monitor->filter_tag_list) != NULL) + { + int tag_matches; + + /* count tag matches, to calculate end of tag match block */ + tag_matches = 0; + udev_list_entry_foreach (list_entry, + udev_list_get_entry + (&udev_monitor->filter_tag_list)) + tag_matches++; + + /* add all tags matches */ + udev_list_entry_foreach (list_entry, + udev_list_get_entry + (&udev_monitor->filter_tag_list)) + { + uint64_t tag_bloom_bits = + util_string_bloom64 (udev_list_entry_get_name (list_entry)); + uint32_t tag_bloom_hi = tag_bloom_bits >> 32; + uint32_t tag_bloom_lo = tag_bloom_bits & 0xffffffff; + + /* load device bloom bits in A */ + bpf_stmt (ins, &i, BPF_LD | BPF_W | BPF_ABS, + offsetof (struct udev_monitor_netlink_header, + filter_tag_bloom_hi)); + /* clear bits (tag bits & bloom bits) */ + bpf_stmt (ins, &i, BPF_ALU | BPF_AND | BPF_K, tag_bloom_hi); + /* jump to next tag if it does not match */ + bpf_jmp (ins, &i, BPF_JMP | BPF_JEQ | BPF_K, tag_bloom_hi, 0, 3); + + /* load device bloom bits in A */ + bpf_stmt (ins, &i, BPF_LD | BPF_W | BPF_ABS, + offsetof (struct udev_monitor_netlink_header, + filter_tag_bloom_lo)); + /* clear bits (tag bits & bloom bits) */ + bpf_stmt (ins, &i, BPF_ALU | BPF_AND | BPF_K, tag_bloom_lo); + /* jump behind end of tag match block if tag matches */ + tag_matches--; + bpf_jmp (ins, &i, BPF_JMP | BPF_JEQ | BPF_K, + tag_bloom_lo, 1 + (tag_matches * 6), 0); + } + + /* nothing matched, drop packet */ + bpf_stmt (ins, &i, BPF_RET | BPF_K, 0); + } + + /* add all subsystem matches */ + if (udev_list_get_entry (&udev_monitor->filter_subsystem_list) != NULL) + { + udev_list_entry_foreach (list_entry, + udev_list_get_entry + (&udev_monitor->filter_subsystem_list)) + { + unsigned int hash = + util_string_hash32 (udev_list_entry_get_name (list_entry)); + + /* load device subsystem value in A */ + bpf_stmt (ins, &i, BPF_LD | BPF_W | BPF_ABS, + offsetof (struct udev_monitor_netlink_header, + filter_subsystem_hash)); + if (udev_list_entry_get_value (list_entry) == NULL) + { + /* jump if subsystem does not match */ + bpf_jmp (ins, &i, BPF_JMP | BPF_JEQ | BPF_K, hash, 0, 1); + } + else + { + /* jump if subsystem does not match */ + bpf_jmp (ins, &i, BPF_JMP | BPF_JEQ | BPF_K, hash, 0, 3); + + /* load device devtype value in A */ + bpf_stmt (ins, &i, BPF_LD | BPF_W | BPF_ABS, + offsetof (struct + udev_monitor_netlink_header, + filter_devtype_hash)); + /* jump if value does not match */ + hash = + util_string_hash32 (udev_list_entry_get_value (list_entry)); + bpf_jmp (ins, &i, BPF_JMP | BPF_JEQ | BPF_K, hash, 0, 1); + } /* matched, pass packet */ - bpf_stmt(ins, &i, BPF_RET | BPF_K, 0xffffffff); - - /* install filter */ - // NOTE: attaches to either netlink or sockpair - memzero(&filter, sizeof(filter)); - filter.len = i; - filter.filter = ins; - err = - setsockopt(udev_monitor->sock, SOL_SOCKET, SO_ATTACH_FILTER, - &filter, sizeof(filter)); - return err < 0 ? -errno : 0; + bpf_stmt (ins, &i, BPF_RET | BPF_K, 0xffffffff); + + if (i + 1 >= ELEMENTSOF (ins)) + return -E2BIG; + } + + /* nothing matched, drop packet */ + bpf_stmt (ins, &i, BPF_RET | BPF_K, 0); + } + + /* matched, pass packet */ + bpf_stmt (ins, &i, BPF_RET | BPF_K, 0xffffffff); + + /* install filter */ + // NOTE: attaches to either netlink or sockpair + memzero (&filter, sizeof (filter)); + filter.len = i; + filter.filter = ins; + err = + setsockopt (udev_monitor->sock, SOL_SOCKET, SO_ATTACH_FILTER, + &filter, sizeof (filter)); + return err < 0 ? -errno : 0; } -int udev_monitor_allow_unicast_sender(struct udev_monitor *udev_monitor, - struct udev_monitor *sender) +int +udev_monitor_allow_unicast_sender (struct udev_monitor *udev_monitor, + struct udev_monitor *sender) { - // only for kernel-type links - if (udev_monitor->type != UDEV_MONITOR_TYPE_KERNEL) { - return -EINVAL; - } - - udev_monitor->snl_trusted_sender.nl.nl_pid = sender->snl.nl.nl_pid; - return 0; + // only for kernel-type links + if (udev_monitor->type != UDEV_MONITOR_TYPE_KERNEL) + { + return -EINVAL; + } + + udev_monitor->snl_trusted_sender.nl.nl_pid = sender->snl.nl.nl_pid; + return 0; } /** @@ -437,63 +463,73 @@ int udev_monitor_allow_unicast_sender(struct udev_monitor *udev_monitor, * * NOTE: in libudev-compat, this only works for "kernel" udev monitors. */ -int udev_monitor_enable_receiving(struct udev_monitor *udev_monitor) +int +udev_monitor_enable_receiving (struct udev_monitor *udev_monitor) { - if (udev_monitor == NULL) { - return -EINVAL; - } - // libudev-compat: only for kernel types - // udev-types are already in a receiving state - if (udev_monitor->type != UDEV_MONITOR_TYPE_KERNEL) { - return 0; - } - - int err = 0; - const int on = 1; - - udev_monitor_filter_update(udev_monitor); - - if (!udev_monitor->bound) { - err = - bind(udev_monitor->sock, &udev_monitor->snl.sa, - sizeof(struct sockaddr_nl)); - if (err == 0) { - udev_monitor->bound = true; - } + if (udev_monitor == NULL) + { + return -EINVAL; + } + // libudev-compat: only for kernel types + // udev-types are already in a receiving state + if (udev_monitor->type != UDEV_MONITOR_TYPE_KERNEL) + { + return 0; + } + + int err = 0; + const int on = 1; + + udev_monitor_filter_update (udev_monitor); + + if (!udev_monitor->bound) + { + err = + bind (udev_monitor->sock, &udev_monitor->snl.sa, + sizeof (struct sockaddr_nl)); + if (err == 0) + { + udev_monitor->bound = true; } + } - if (err >= 0) { - union sockaddr_union snl; - socklen_t addrlen; - - // get the address the kernel has assigned us - // it is usually, but not necessarily the pid - - addrlen = sizeof(struct sockaddr_nl); - err = getsockname(udev_monitor->sock, &snl.sa, &addrlen); - if (err == 0) { - udev_monitor->snl.nl.nl_pid = snl.nl.nl_pid; - } - } else { - - int errsv = errno; - log_debug("bind failed: %s", strerror(errsv)); - return -errsv; - } + if (err >= 0) + { + union sockaddr_union snl; + socklen_t addrlen; - // enable receiving of sender credentials - err = - setsockopt(udev_monitor->sock, SOL_SOCKET, SO_PASSCRED, &on, - sizeof(on)); - if (err < 0) { + // get the address the kernel has assigned us + // it is usually, but not necessarily the pid - int errsv = errno; - log_debug("setting SO_PASSCRED failed: %s", strerror(errsv)); - return -errsv; + addrlen = sizeof (struct sockaddr_nl); + err = getsockname (udev_monitor->sock, &snl.sa, &addrlen); + if (err == 0) + { + udev_monitor->snl.nl.nl_pid = snl.nl.nl_pid; } - - return 0; + } + else + { + + int errsv = errno; + log_debug ("bind failed: %s", strerror (errsv)); + return -errsv; + } + + // enable receiving of sender credentials + err = + setsockopt (udev_monitor->sock, SOL_SOCKET, SO_PASSCRED, &on, + sizeof (on)); + if (err < 0) + { + + int errsv = errno; + log_debug ("setting SO_PASSCRED failed: %s", strerror (errsv)); + return -errsv; + } + + return 0; } /** @@ -506,28 +542,34 @@ int udev_monitor_enable_receiving(struct udev_monitor *udev_monitor) * * Returns: 0 on success, otherwise -1 on error. */ -int udev_monitor_set_receive_buffer_size(struct udev_monitor *udev_monitor, - int size) +int +udev_monitor_set_receive_buffer_size (struct udev_monitor *udev_monitor, + int size) { - if (udev_monitor == NULL) { - return -EINVAL; - } + if (udev_monitor == NULL) + { + return -EINVAL; + } - return setsockopt(udev_monitor->sock, SOL_SOCKET, SO_RCVBUFFORCE, &size, - sizeof(size)); + return setsockopt (udev_monitor->sock, SOL_SOCKET, SO_RCVBUFFORCE, &size, + sizeof (size)); } -int udev_monitor_disconnect(struct udev_monitor *udev_monitor) +int +udev_monitor_disconnect (struct udev_monitor *udev_monitor) { - if (udev_monitor->type == UDEV_MONITOR_TYPE_UDEV) { - return udev_monitor_fs_shutdown(udev_monitor); - } else { - - int err = 0; - err = close(udev_monitor->sock); - udev_monitor->sock = -1; - return err < 0 ? -errno : 0; - } + if (udev_monitor->type == UDEV_MONITOR_TYPE_UDEV) + { + return udev_monitor_fs_shutdown (udev_monitor); + } + else + { + + int err = 0; + err = close (udev_monitor->sock); + udev_monitor->sock = -1; + return err < 0 ? -errno : 0; + } } /** @@ -538,14 +580,16 @@ int udev_monitor_disconnect(struct udev_monitor *udev_monitor) * * Returns: the passed udev monitor **/ -struct udev_monitor *udev_monitor_ref(struct udev_monitor *udev_monitor) +struct udev_monitor * +udev_monitor_ref (struct udev_monitor *udev_monitor) { - if (udev_monitor == NULL) { - return NULL; - } + if (udev_monitor == NULL) + { + return NULL; + } - udev_monitor->refcount++; - return udev_monitor; + udev_monitor->refcount++; + return udev_monitor; } /** @@ -558,31 +602,38 @@ struct udev_monitor *udev_monitor_ref(struct udev_monitor *udev_monitor) * * Returns: #NULL **/ -struct udev_monitor *udev_monitor_unref(struct udev_monitor *udev_monitor) +struct udev_monitor * +udev_monitor_unref (struct udev_monitor *udev_monitor) { - if (udev_monitor == NULL) { - return NULL; - } - - udev_monitor->refcount--; - - if (udev_monitor->refcount > 0) { - return NULL; - } - - udev_list_cleanup(&udev_monitor->filter_subsystem_list); - udev_list_cleanup(&udev_monitor->filter_tag_list); - - if (udev_monitor->type == UDEV_MONITOR_TYPE_UDEV) { - udev_monitor_fs_destroy(udev_monitor); - } else { - if (udev_monitor->sock >= 0) { - close(udev_monitor->sock); - } + if (udev_monitor == NULL) + { + return NULL; + } + + udev_monitor->refcount--; + + if (udev_monitor->refcount > 0) + { + return NULL; + } + + udev_list_cleanup (&udev_monitor->filter_subsystem_list); + udev_list_cleanup (&udev_monitor->filter_tag_list); + + if (udev_monitor->type == UDEV_MONITOR_TYPE_UDEV) + { + udev_monitor_fs_destroy (udev_monitor); + } + else + { + if (udev_monitor->sock >= 0) + { + close (udev_monitor->sock); } + } - free(udev_monitor); - return NULL; + free (udev_monitor); + return NULL; } /** @@ -593,12 +644,14 @@ struct udev_monitor *udev_monitor_unref(struct udev_monitor *udev_monitor) * * Returns: the udev library context **/ -struct udev *udev_monitor_get_udev(struct udev_monitor *udev_monitor) +struct udev * +udev_monitor_get_udev (struct udev_monitor *udev_monitor) { - if (udev_monitor == NULL) { - return NULL; - } - return udev_monitor->udev; + if (udev_monitor == NULL) + { + return NULL; + } + return udev_monitor->udev; } /** @@ -615,352 +668,398 @@ struct udev *udev_monitor_get_udev(struct udev_monitor *udev_monitor) * for udev-type monitors, or a netlink socket for kernel-type * monitors. **/ -int udev_monitor_get_fd(struct udev_monitor *udev_monitor) +int +udev_monitor_get_fd (struct udev_monitor *udev_monitor) { - if (udev_monitor == NULL) { - return -EINVAL; - } - - if (udev_monitor->type == UDEV_MONITOR_TYPE_UDEV) { - return udev_monitor->epoll_fd; - } else { - return udev_monitor->sock; - } + if (udev_monitor == NULL) + { + return -EINVAL; + } + + if (udev_monitor->type == UDEV_MONITOR_TYPE_UDEV) + { + return udev_monitor->epoll_fd; + } + else + { + return udev_monitor->sock; + } } -static int passes_filter(struct udev_monitor *udev_monitor, - struct udev_device *udev_device) +static int +passes_filter (struct udev_monitor *udev_monitor, + struct udev_device *udev_device) { - struct udev_list_entry *list_entry; - - if (udev_list_get_entry(&udev_monitor->filter_subsystem_list) == NULL) - goto tag; - udev_list_entry_foreach(list_entry, - udev_list_get_entry(&udev_monitor-> - filter_subsystem_list)) { - const char *subsys = udev_list_entry_get_name(list_entry); - const char *dsubsys = udev_device_get_subsystem(udev_device); - const char *devtype; - const char *ddevtype; - - if (!streq(dsubsys, subsys)) - continue; - - devtype = udev_list_entry_get_value(list_entry); - if (devtype == NULL) - goto tag; - ddevtype = udev_device_get_devtype(udev_device); - if (ddevtype == NULL) - continue; - if (streq(ddevtype, devtype)) - goto tag; - } - return 0; - - tag: - if (udev_list_get_entry(&udev_monitor->filter_tag_list) == NULL) - return 1; - udev_list_entry_foreach(list_entry, - udev_list_get_entry(&udev_monitor-> - filter_tag_list)) { - const char *tag = udev_list_entry_get_name(list_entry); - - if (udev_device_has_tag(udev_device, tag)) - return 1; - } - return 0; + struct udev_list_entry *list_entry; + + if (udev_list_get_entry (&udev_monitor->filter_subsystem_list) == NULL) + goto tag; + udev_list_entry_foreach (list_entry, + udev_list_get_entry + (&udev_monitor->filter_subsystem_list)) + { + const char *subsys = udev_list_entry_get_name (list_entry); + const char *dsubsys = udev_device_get_subsystem (udev_device); + const char *devtype; + const char *ddevtype; + + if (!streq (dsubsys, subsys)) + continue; + + devtype = udev_list_entry_get_value (list_entry); + if (devtype == NULL) + goto tag; + ddevtype = udev_device_get_devtype (udev_device); + if (ddevtype == NULL) + continue; + if (streq (ddevtype, devtype)) + goto tag; + } + return 0; + +tag: + if (udev_list_get_entry (&udev_monitor->filter_tag_list) == NULL) + return 1; + udev_list_entry_foreach (list_entry, + udev_list_get_entry + (&udev_monitor->filter_tag_list)) + { + const char *tag = udev_list_entry_get_name (list_entry); + + if (udev_device_has_tag (udev_device, tag)) + return 1; + } + return 0; } // receive a device from netlink -static struct udev_device *udev_monitor_receive_device_netlink(struct - udev_monitor - *udev_monitor) +static struct udev_device * +udev_monitor_receive_device_netlink (struct udev_monitor *udev_monitor) { - if (udev_monitor == NULL) { - return NULL; - } - - if (udev_monitor->type != UDEV_MONITOR_TYPE_KERNEL) { - - errno = EINVAL; - return NULL; - } - - struct udev_device *udev_device; - struct msghdr smsg; - struct iovec iov; - char cred_msg[CMSG_SPACE(sizeof(struct ucred))]; - struct cmsghdr *cmsg; - union sockaddr_union snl; - struct ucred *cred; - union { - struct udev_monitor_netlink_header nlh; - char raw[8192]; - } buf; - ssize_t buflen; - ssize_t bufpos; - bool is_initialized = false; - - retry: - if (udev_monitor == NULL) - return NULL; - iov.iov_base = &buf; - iov.iov_len = sizeof(buf); - memzero(&smsg, sizeof(struct msghdr)); - smsg.msg_iov = &iov; - smsg.msg_iovlen = 1; - smsg.msg_control = cred_msg; - smsg.msg_controllen = sizeof(cred_msg); - smsg.msg_name = &snl; - smsg.msg_namelen = sizeof(snl); - - buflen = recvmsg(udev_monitor->sock, &smsg, 0); - if (buflen < 0) { - if (errno != EINTR) { - log_debug("%s", "unable to receive message"); - } - return NULL; + if (udev_monitor == NULL) + { + return NULL; + } + + if (udev_monitor->type != UDEV_MONITOR_TYPE_KERNEL) + { + + errno = EINVAL; + return NULL; + } + + struct udev_device *udev_device; + struct msghdr smsg; + struct iovec iov; + char cred_msg[CMSG_SPACE (sizeof (struct ucred))]; + struct cmsghdr *cmsg; + union sockaddr_union snl; + struct ucred *cred; + union + { + struct udev_monitor_netlink_header nlh; + char raw[8192]; + } buf; + ssize_t buflen; + ssize_t bufpos; + bool is_initialized = false; + +retry: + if (udev_monitor == NULL) + return NULL; + iov.iov_base = &buf; + iov.iov_len = sizeof (buf); + memzero (&smsg, sizeof (struct msghdr)); + smsg.msg_iov = &iov; + smsg.msg_iovlen = 1; + smsg.msg_control = cred_msg; + smsg.msg_controllen = sizeof (cred_msg); + smsg.msg_name = &snl; + smsg.msg_namelen = sizeof (snl); + + buflen = recvmsg (udev_monitor->sock, &smsg, 0); + if (buflen < 0) + { + if (errno != EINTR) + { + log_debug ("%s", "unable to receive message"); } - - if (buflen < 32 || (smsg.msg_flags & MSG_TRUNC)) { - log_debug("%s", "invalid message length"); - return NULL; - } - - if (snl.nl.nl_groups == 0) { - /* unicast message, check if we trust the sender */ - if (udev_monitor->snl_trusted_sender.nl.nl_pid == 0 || - snl.nl.nl_pid != - udev_monitor->snl_trusted_sender.nl.nl_pid) { - log_debug("%s", "unicast netlink message ignored"); - return NULL; - } - } else if (snl.nl.nl_groups == UDEV_MONITOR_KERNEL) { - if (snl.nl.nl_pid > 0) { - log_debug("multicast kernel netlink message from PID %" - PRIu32 " ignored", snl.nl.nl_pid); - return NULL; - } + return NULL; + } + + if (buflen < 32 || (smsg.msg_flags & MSG_TRUNC)) + { + log_debug ("%s", "invalid message length"); + return NULL; + } + + if (snl.nl.nl_groups == 0) + { + /* unicast message, check if we trust the sender */ + if (udev_monitor->snl_trusted_sender.nl.nl_pid == 0 || + snl.nl.nl_pid != udev_monitor->snl_trusted_sender.nl.nl_pid) + { + log_debug ("%s", "unicast netlink message ignored"); + return NULL; } - - cmsg = CMSG_FIRSTHDR(&smsg); - if (cmsg == NULL || cmsg->cmsg_type != SCM_CREDENTIALS) { - log_debug("%s", - "no sender credentials received, message ignored"); - return NULL; + } + else if (snl.nl.nl_groups == UDEV_MONITOR_KERNEL) + { + if (snl.nl.nl_pid > 0) + { + log_debug ("multicast kernel netlink message from PID %" + PRIu32 " ignored", snl.nl.nl_pid); + return NULL; } - - cred = (struct ucred *)CMSG_DATA(cmsg); - if (cred->uid != 0) { - log_debug("sender uid=" UID_FMT ", message ignored", cred->uid); - return NULL; + } + + cmsg = CMSG_FIRSTHDR (&smsg); + if (cmsg == NULL || cmsg->cmsg_type != SCM_CREDENTIALS) + { + log_debug ("%s", "no sender credentials received, message ignored"); + return NULL; + } + + cred = (struct ucred *) CMSG_DATA (cmsg); + if (cred->uid != 0) + { + log_debug ("sender uid=" UID_FMT ", message ignored", cred->uid); + return NULL; + } + + if (memcmp (buf.raw, "libudev", 8) == 0) + { + /* udev message needs proper version magic */ + if (buf.nlh.magic != htonl (UDEV_MONITOR_MAGIC)) + { + log_debug ("%s", + "unrecognized message signature (%x != %x)", + buf.nlh.magic, htonl (UDEV_MONITOR_MAGIC)); + return NULL; } - - if (memcmp(buf.raw, "libudev", 8) == 0) { - /* udev message needs proper version magic */ - if (buf.nlh.magic != htonl(UDEV_MONITOR_MAGIC)) { - log_debug("%s", - "unrecognized message signature (%x != %x)", - buf.nlh.magic, htonl(UDEV_MONITOR_MAGIC)); - return NULL; - } - if (buf.nlh.properties_off + 32 > (size_t) buflen) { - log_debug("%s", - "message smaller than expected (%u > %zd)", - buf.nlh.properties_off + 32, buflen); - return NULL; - } - - bufpos = buf.nlh.properties_off; - - /* devices received from udev are always initialized */ - is_initialized = true; - } else { - /* kernel message with header */ - bufpos = strlen(buf.raw) + 1; - if ((size_t) bufpos < sizeof("a@/d") || bufpos >= buflen) { - log_debug("%s", "invalid message length"); - return NULL; - } - - /* check message header */ - if (strstr(buf.raw, "@/") == NULL) { - log_debug("%s", "unrecognized message header"); - return NULL; - } + if (buf.nlh.properties_off + 32 > (size_t) buflen) + { + log_debug ("%s", + "message smaller than expected (%u > %zd)", + buf.nlh.properties_off + 32, buflen); + return NULL; } - udev_device = - udev_device_new_from_nulstr(udev_monitor->udev, &buf.raw[bufpos], - buflen - bufpos); - if (!udev_device) { - log_debug("could not create device: %s", strerror(errno)); - return NULL; + bufpos = buf.nlh.properties_off; + + /* devices received from udev are always initialized */ + is_initialized = true; + } + else + { + /* kernel message with header */ + bufpos = strlen (buf.raw) + 1; + if ((size_t) bufpos < sizeof ("a@/d") || bufpos >= buflen) + { + log_debug ("%s", "invalid message length"); + return NULL; } - if (is_initialized) - udev_device_set_is_initialized(udev_device); - - /* skip device, if it does not pass the current filter */ - if (!passes_filter(udev_monitor, udev_device)) { - struct pollfd pfd[1]; - int rc; - - udev_device_unref(udev_device); - - /* if something is queued, get next device */ - pfd[0].fd = udev_monitor->sock; - pfd[0].events = POLLIN; - rc = poll(pfd, 1, 0); - if (rc > 0) - goto retry; - return NULL; + /* check message header */ + if (strstr (buf.raw, "@/") == NULL) + { + log_debug ("%s", "unrecognized message header"); + return NULL; } - - return udev_device; + } + + udev_device = + udev_device_new_from_nulstr (udev_monitor->udev, &buf.raw[bufpos], + buflen - bufpos); + if (!udev_device) + { + log_debug ("could not create device: %s", strerror (errno)); + return NULL; + } + + if (is_initialized) + udev_device_set_is_initialized (udev_device); + + /* skip device, if it does not pass the current filter */ + if (!passes_filter (udev_monitor, udev_device)) + { + struct pollfd pfd[1]; + int rc; + + udev_device_unref (udev_device); + + /* if something is queued, get next device */ + pfd[0].fd = udev_monitor->sock; + pfd[0].events = POLLIN; + rc = poll (pfd, 1, 0); + if (rc > 0) + goto retry; + return NULL; + } + + return udev_device; } // receive a device from the filesystem (i.e. for udev-type monitors) -static struct udev_device *udev_monitor_receive_device_fs(struct udev_monitor - *udev_monitor) +static struct udev_device * +udev_monitor_receive_device_fs (struct udev_monitor *udev_monitor) { - struct udev_device *udev_device; - struct msghdr smsg; - struct iovec iov; - int rc = 0; - union { - struct udev_monitor_netlink_header nlh; - char raw[8192]; - } buf; - ssize_t buflen; - ssize_t bufpos; - bool is_initialized = false; - bool rescan = false; - - struct pollfd pfd[1]; - - retry: - if (udev_monitor == NULL) { - return NULL; + struct udev_device *udev_device; + struct msghdr smsg; + struct iovec iov; + int rc = 0; + union + { + struct udev_monitor_netlink_header nlh; + char raw[8192]; + } buf; + ssize_t buflen; + ssize_t bufpos; + bool is_initialized = false; + bool rescan = false; + + struct pollfd pfd[1]; + +retry: + if (udev_monitor == NULL) + { + return NULL; + } + // are there pending events? + pfd[0].fd = udev_monitor->sock; + pfd[0].events = POLLIN; + + rc = poll (pfd, 1, 0); + if (rc < 0) + { + + rc = -errno; + log_error ("poll(%d) rc = %d\n", udev_monitor->sock, rc); + + return NULL; + } + + if (rc == 0) + { + + // no events bufferred. + // push as many events as we can into the socketpair + rc = udev_monitor_fs_push_events (udev_monitor); + if (rc < 0) + { + + if (rc == -ENODATA) + { + // the socketpair was empty, and there were no bufferred events. + // can only mean that whatever event got created, was unlinked before we could scan it. + // shouldn't happen unless the admin is meddling... + return NULL; + } + + if (rc != -EAGAIN) + { + + log_error ("udev_monitor_fs_push_events rc = %d\n", rc); + return NULL; + } + else + { + + // there are pending events, but we couldn't push any at this time. + // this means the socket buffer is too small, or there was some + // socket-level error. + goto retry; + } + } + } + // prepare to receive + iov.iov_base = &buf; + iov.iov_len = sizeof (buf); + memzero (&smsg, sizeof (struct msghdr)); + smsg.msg_iov = &iov; + smsg.msg_iovlen = 1; + + // get a message we sent to ourselves through the filter + buflen = recvmsg (udev_monitor->sock, &smsg, 0); + if (buflen < 0) + { + if (errno != EINTR) + { + log_debug ("%s", "unable to receive message"); } - // are there pending events? - pfd[0].fd = udev_monitor->sock; - pfd[0].events = POLLIN; + return NULL; + } - rc = poll(pfd, 1, 0); - if (rc < 0) { + if (buflen < 32 || (smsg.msg_flags & MSG_TRUNC)) + { - rc = -errno; - log_error("poll(%d) rc = %d\n", udev_monitor->sock, rc); + log_debug ("%s", "invalid message length"); + return NULL; + } - return NULL; - } + if (memcmp (buf.raw, "libudev", 8) == 0) + { - if (rc == 0) { - - // no events bufferred. - // push as many events as we can into the socketpair - rc = udev_monitor_fs_push_events(udev_monitor); - if (rc < 0) { - - if (rc == -ENODATA) { - // the socketpair was empty, and there were no bufferred events. - // can only mean that whatever event got created, was unlinked before we could scan it. - // shouldn't happen unless the admin is meddling... - return NULL; - } - - if (rc != -EAGAIN) { - - log_error - ("udev_monitor_fs_push_events rc = %d\n", - rc); - return NULL; - } else { - - // there are pending events, but we couldn't push any at this time. - // this means the socket buffer is too small, or there was some - // socket-level error. - goto retry; - } - } + /* udev message needs proper version magic */ + if (buf.nlh.magic != htonl (UDEV_MONITOR_MAGIC)) + { + log_debug ("unrecognized message signature (%x != %x)", + buf.nlh.magic, htonl (UDEV_MONITOR_MAGIC)); + return NULL; } - // prepare to receive - iov.iov_base = &buf; - iov.iov_len = sizeof(buf); - memzero(&smsg, sizeof(struct msghdr)); - smsg.msg_iov = &iov; - smsg.msg_iovlen = 1; - - // get a message we sent to ourselves through the filter - buflen = recvmsg(udev_monitor->sock, &smsg, 0); - if (buflen < 0) { - if (errno != EINTR) { - log_debug("%s", "unable to receive message"); - } - return NULL; + if (buf.nlh.properties_off + 32 > (size_t) buflen) + { + return NULL; } - if (buflen < 32 || (smsg.msg_flags & MSG_TRUNC)) { + bufpos = buf.nlh.properties_off; - log_debug("%s", "invalid message length"); - return NULL; - } + /* devices received from udev are always initialized */ + is_initialized = true; - if (memcmp(buf.raw, "libudev", 8) == 0) { + } + else + { - /* udev message needs proper version magic */ - if (buf.nlh.magic != htonl(UDEV_MONITOR_MAGIC)) { - log_debug("unrecognized message signature (%x != %x)", - buf.nlh.magic, htonl(UDEV_MONITOR_MAGIC)); - return NULL; - } - if (buf.nlh.properties_off + 32 > (size_t) buflen) { - return NULL; - } + // libudev-compat: should never be reached, since we don't listen to netlink + log_error ("%s", "Invalid message: missing 'libudev' header"); + return NULL; + } - bufpos = buf.nlh.properties_off; + udev_device = + udev_device_new_from_nulstr (udev_monitor->udev, &buf.raw[bufpos], + buflen - bufpos); + if (!udev_device) + { + return NULL; + } - /* devices received from udev are always initialized */ - is_initialized = true; + if (is_initialized) + { + udev_device_set_is_initialized (udev_device); + } - } else { + /* skip device, if it does not pass the current filter */ + if (!passes_filter (udev_monitor, udev_device)) + { - // libudev-compat: should never be reached, since we don't listen to netlink - log_error("%s", "Invalid message: missing 'libudev' header"); - return NULL; - } + udev_device_unref (udev_device); - udev_device = - udev_device_new_from_nulstr(udev_monitor->udev, &buf.raw[bufpos], - buflen - bufpos); - if (!udev_device) { - return NULL; - } + /* if something is queued, get next device */ + pfd[0].fd = udev_monitor->epoll_fd; + pfd[0].events = POLLIN; + rc = poll (pfd, 1, 0); - if (is_initialized) { - udev_device_set_is_initialized(udev_device); + if (rc > 0) + { + goto retry; } - /* skip device, if it does not pass the current filter */ - if (!passes_filter(udev_monitor, udev_device)) { + return NULL; + } - udev_device_unref(udev_device); - - /* if something is queued, get next device */ - pfd[0].fd = udev_monitor->epoll_fd; - pfd[0].events = POLLIN; - rc = poll(pfd, 1, 0); - - if (rc > 0) { - goto retry; - } - - return NULL; - } - - return udev_device; + return udev_device; } /** @@ -983,129 +1082,146 @@ static struct udev_device *udev_monitor_receive_device_fs(struct udev_monitor * Returns: a new udev device, or #NULL, in case of an error **/ -struct udev_device *udev_monitor_receive_device(struct udev_monitor - *udev_monitor) +struct udev_device * +udev_monitor_receive_device (struct udev_monitor *udev_monitor) { - if (udev_monitor == NULL) { - return NULL; - } + if (udev_monitor == NULL) + { + return NULL; + } - if (udev_monitor->type == UDEV_MONITOR_TYPE_KERNEL) { + if (udev_monitor->type == UDEV_MONITOR_TYPE_KERNEL) + { - return udev_monitor_receive_device_netlink(udev_monitor); - } else if (udev_monitor->type == UDEV_MONITOR_TYPE_UDEV) { + return udev_monitor_receive_device_netlink (udev_monitor); + } + else if (udev_monitor->type == UDEV_MONITOR_TYPE_UDEV) + { - return udev_monitor_receive_device_fs(udev_monitor); - } else { + return udev_monitor_receive_device_fs (udev_monitor); + } + else + { - errno = EINVAL; - return NULL; - } + errno = EINVAL; + return NULL; + } } -int udev_monitor_send_device(struct udev_monitor *udev_monitor, - struct udev_monitor *destination, - struct udev_device *udev_device) +int +udev_monitor_send_device (struct udev_monitor *udev_monitor, + struct udev_monitor *destination, + struct udev_device *udev_device) { - if (udev_monitor == NULL) { - return -EINVAL; - } - - const char *buf, *val; - ssize_t blen, count; - struct msghdr smsg; - int sock = -1; - struct udev_monitor_netlink_header nlh = { - .prefix = "libudev", - .magic = htonl(UDEV_MONITOR_MAGIC), - .header_size = sizeof nlh, - }; - struct iovec iov[2] = { - {.iov_base = &nlh,.iov_len = sizeof nlh} - , - }; - - memset(&smsg, 0, sizeof(struct msghdr)); - - smsg.msg_iov = iov; - smsg.msg_iovlen = 2; - - struct udev_list_entry *list_entry; - uint64_t tag_bloom_bits; - - // serialize the device - blen = udev_device_get_properties_monitor_buf(udev_device, &buf); - if (blen < 32) { - return -EINVAL; - } - - /* fill in versioned header */ - val = udev_device_get_subsystem(udev_device); - nlh.filter_subsystem_hash = htonl(util_string_hash32(val)); - - val = udev_device_get_devtype(udev_device); - if (val != NULL) { - nlh.filter_devtype_hash = htonl(util_string_hash32(val)); + if (udev_monitor == NULL) + { + return -EINVAL; + } + + const char *buf, *val; + ssize_t blen, count; + struct msghdr smsg; + int sock = -1; + struct udev_monitor_netlink_header nlh = { + .prefix = "libudev", + .magic = htonl (UDEV_MONITOR_MAGIC), + .header_size = sizeof nlh, + }; + struct iovec iov[2] = { + {.iov_base = &nlh,.iov_len = sizeof nlh} + , + }; + + memset (&smsg, 0, sizeof (struct msghdr)); + + smsg.msg_iov = iov; + smsg.msg_iovlen = 2; + + struct udev_list_entry *list_entry; + uint64_t tag_bloom_bits; + + // serialize the device + blen = udev_device_get_properties_monitor_buf (udev_device, &buf); + if (blen < 32) + { + return -EINVAL; + } + + /* fill in versioned header */ + val = udev_device_get_subsystem (udev_device); + nlh.filter_subsystem_hash = htonl (util_string_hash32 (val)); + + val = udev_device_get_devtype (udev_device); + if (val != NULL) + { + nlh.filter_devtype_hash = htonl (util_string_hash32 (val)); + } + + /* add tag bloom filter */ + tag_bloom_bits = 0; + udev_list_entry_foreach (list_entry, + udev_device_get_tags_list_entry (udev_device)) + tag_bloom_bits |= + util_string_bloom64 (udev_list_entry_get_name (list_entry)); + + if (tag_bloom_bits > 0) + { + nlh.filter_tag_bloom_hi = htonl (tag_bloom_bits >> 32); + nlh.filter_tag_bloom_lo = htonl (tag_bloom_bits & 0xffffffff); + } + + /* add properties list */ + nlh.properties_off = iov[0].iov_len; + nlh.properties_len = blen; + iov[1].iov_base = (char *) buf; + iov[1].iov_len = blen; + + /* + * Use custom address for target, or the default one. + * + * If we send to a multicast group, we will get + * ECONNREFUSED, which is expected. + */ + + if (udev_monitor->type == UDEV_MONITOR_TYPE_KERNEL) + { + + sock = udev_monitor->sock; + + if (destination) + smsg.msg_name = &destination->snl; + else + smsg.msg_name = &udev_monitor->snl_destination; + + smsg.msg_namelen = sizeof (struct sockaddr_nl); + } + else + { + + sock = udev_monitor->sock_fs; + } + + count = sendmsg (sock, &smsg, 0); + if (count < 0) + { + + if (!destination) + { + log_debug + ("passed unknown number of bytes to netlink monitor %p", + udev_monitor); + return 0; } - - /* add tag bloom filter */ - tag_bloom_bits = 0; - udev_list_entry_foreach(list_entry, - udev_device_get_tags_list_entry(udev_device)) - tag_bloom_bits |= - util_string_bloom64(udev_list_entry_get_name(list_entry)); - - if (tag_bloom_bits > 0) { - nlh.filter_tag_bloom_hi = htonl(tag_bloom_bits >> 32); - nlh.filter_tag_bloom_lo = htonl(tag_bloom_bits & 0xffffffff); - } - - /* add properties list */ - nlh.properties_off = iov[0].iov_len; - nlh.properties_len = blen; - iov[1].iov_base = (char *)buf; - iov[1].iov_len = blen; - - /* - * Use custom address for target, or the default one. - * - * If we send to a multicast group, we will get - * ECONNREFUSED, which is expected. - */ - - if (udev_monitor->type == UDEV_MONITOR_TYPE_KERNEL) { - - sock = udev_monitor->sock; - - if (destination) - smsg.msg_name = &destination->snl; - else - smsg.msg_name = &udev_monitor->snl_destination; - - smsg.msg_namelen = sizeof(struct sockaddr_nl); - } else { - - sock = udev_monitor->sock_fs; - } - - count = sendmsg(sock, &smsg, 0); - if (count < 0) { - - if (!destination) { - log_debug - ("passed unknown number of bytes to netlink monitor %p", - udev_monitor); - return 0; - } else { - return -errno; - } + else + { + return -errno; } + } - log_debug("passed %zi bytes to netlink monitor %p", count, - udev_monitor); - return count; + log_debug ("passed %zi bytes to netlink monitor %p", count, udev_monitor); + return count; } /** @@ -1121,19 +1237,20 @@ int udev_monitor_send_device(struct udev_monitor *udev_monitor, * * Returns: 0 on success, otherwise a negative error value. */ -int udev_monitor_filter_add_match_subsystem_devtype(struct udev_monitor - *udev_monitor, - const char *subsystem, - const char *devtype) +int +udev_monitor_filter_add_match_subsystem_devtype (struct udev_monitor + *udev_monitor, + const char *subsystem, + const char *devtype) { - if (udev_monitor == NULL) - return -EINVAL; - if (subsystem == NULL) - return -EINVAL; - if (udev_list_entry_add - (&udev_monitor->filter_subsystem_list, subsystem, devtype) == NULL) - return -ENOMEM; - return 0; + if (udev_monitor == NULL) + return -EINVAL; + if (subsystem == NULL) + return -EINVAL; + if (udev_list_entry_add + (&udev_monitor->filter_subsystem_list, subsystem, devtype) == NULL) + return -ENOMEM; + return 0; } /** @@ -1148,17 +1265,17 @@ int udev_monitor_filter_add_match_subsystem_devtype(struct udev_monitor * * Returns: 0 on success, otherwise a negative error value. */ -int udev_monitor_filter_add_match_tag(struct udev_monitor *udev_monitor, - const char *tag) +int +udev_monitor_filter_add_match_tag (struct udev_monitor *udev_monitor, + const char *tag) { - if (udev_monitor == NULL) - return -EINVAL; - if (tag == NULL) - return -EINVAL; - if (udev_list_entry_add(&udev_monitor->filter_tag_list, tag, NULL) == - NULL) - return -ENOMEM; - return 0; + if (udev_monitor == NULL) + return -EINVAL; + if (tag == NULL) + return -EINVAL; + if (udev_list_entry_add (&udev_monitor->filter_tag_list, tag, NULL) == NULL) + return -ENOMEM; + return 0; } /** @@ -1169,11 +1286,12 @@ int udev_monitor_filter_add_match_tag(struct udev_monitor *udev_monitor, * * Returns: 0 on success, otherwise a negative error value. */ -int udev_monitor_filter_remove(struct udev_monitor *udev_monitor) +int +udev_monitor_filter_remove (struct udev_monitor *udev_monitor) { - static struct sock_fprog filter = { 0, NULL }; + static struct sock_fprog filter = { 0, NULL }; - udev_list_cleanup(&udev_monitor->filter_subsystem_list); - return setsockopt(udev_monitor->sock, SOL_SOCKET, SO_ATTACH_FILTER, - &filter, sizeof(filter)); + udev_list_cleanup (&udev_monitor->filter_subsystem_list); + return setsockopt (udev_monitor->sock, SOL_SOCKET, SO_ATTACH_FILTER, + &filter, sizeof (filter)); } diff --git a/libudev-compat/libudev-private.h b/libudev-compat/libudev-private.h index 7f60eef..366b443 100644 --- a/libudev-compat/libudev-private.h +++ b/libudev-compat/libudev-private.h @@ -48,72 +48,83 @@ #define WRITE_END 1 /* libudev.c */ -int udev_get_rules_path(struct udev *udev, char **path[], usec_t * ts_usec[]); +int udev_get_rules_path (struct udev *udev, char **path[], + usec_t * ts_usec[]); /* libudev-device.c */ -struct udev_device *udev_device_new_from_nulstr(struct udev *udev, char *nulstr, - ssize_t buflen); -struct udev_device *udev_device_new_from_synthetic_event(struct udev *udev, - const char *syspath, - const char *action); -struct udev_device *udev_device_shallow_clone(struct udev_device *old_device); -struct udev_device *udev_device_clone_with_db(struct udev_device *old_device); -int udev_device_copy_properties(struct udev_device *dst, - struct udev_device *src); -mode_t udev_device_get_devnode_mode(struct udev_device *udev_device); -uid_t udev_device_get_devnode_uid(struct udev_device *udev_device); -gid_t udev_device_get_devnode_gid(struct udev_device *udev_device); -int udev_device_rename(struct udev_device *udev_device, const char *new_name); -int udev_device_add_devlink(struct udev_device *udev_device, - const char *devlink); -void udev_device_cleanup_devlinks_list(struct udev_device *udev_device); -int udev_device_add_property(struct udev_device *udev_device, const char *key, - const char *value); -char **udev_device_get_properties_envp(struct udev_device *udev_device); -ssize_t udev_device_get_properties_monitor_buf(struct udev_device *udev_device, - const char **buf); -const char *udev_device_get_devpath_old(struct udev_device *udev_device); -const char *udev_device_get_id_filename(struct udev_device *udev_device); -void udev_device_set_is_initialized(struct udev_device *udev_device); -int udev_device_add_tag(struct udev_device *udev_device, const char *tag); -void udev_device_remove_tag(struct udev_device *udev_device, const char *tag); -void udev_device_cleanup_tags_list(struct udev_device *udev_device); -usec_t udev_device_get_usec_initialized(struct udev_device *udev_device); -void udev_device_ensure_usec_initialized(struct udev_device *udev_device, - struct udev_device *old_device); -int udev_device_get_devlink_priority(struct udev_device *udev_device); -int udev_device_set_devlink_priority(struct udev_device *udev_device, int prio); -int udev_device_get_watch_handle(struct udev_device *udev_device); -int udev_device_set_watch_handle(struct udev_device *udev_device, int handle); -int udev_device_get_ifindex(struct udev_device *udev_device); -void udev_device_set_info_loaded(struct udev_device *device); -bool udev_device_get_db_persist(struct udev_device *udev_device); -void udev_device_set_db_persist(struct udev_device *udev_device); +struct udev_device *udev_device_new_from_nulstr (struct udev *udev, + char *nulstr, + ssize_t buflen); +struct udev_device *udev_device_new_from_synthetic_event (struct udev *udev, + const char *syspath, + const char *action); +struct udev_device *udev_device_shallow_clone (struct udev_device + *old_device); +struct udev_device *udev_device_clone_with_db (struct udev_device + *old_device); +int udev_device_copy_properties (struct udev_device *dst, + struct udev_device *src); +mode_t udev_device_get_devnode_mode (struct udev_device *udev_device); +uid_t udev_device_get_devnode_uid (struct udev_device *udev_device); +gid_t udev_device_get_devnode_gid (struct udev_device *udev_device); +int udev_device_rename (struct udev_device *udev_device, + const char *new_name); +int udev_device_add_devlink (struct udev_device *udev_device, + const char *devlink); +void udev_device_cleanup_devlinks_list (struct udev_device *udev_device); +int udev_device_add_property (struct udev_device *udev_device, + const char *key, const char *value); +char **udev_device_get_properties_envp (struct udev_device *udev_device); +ssize_t udev_device_get_properties_monitor_buf (struct udev_device + *udev_device, + const char **buf); +const char *udev_device_get_devpath_old (struct udev_device *udev_device); +const char *udev_device_get_id_filename (struct udev_device *udev_device); +void udev_device_set_is_initialized (struct udev_device *udev_device); +int udev_device_add_tag (struct udev_device *udev_device, const char *tag); +void udev_device_remove_tag (struct udev_device *udev_device, + const char *tag); +void udev_device_cleanup_tags_list (struct udev_device *udev_device); +usec_t udev_device_get_usec_initialized (struct udev_device *udev_device); +void udev_device_ensure_usec_initialized (struct udev_device *udev_device, + struct udev_device *old_device); +int udev_device_get_devlink_priority (struct udev_device *udev_device); +int udev_device_set_devlink_priority (struct udev_device *udev_device, + int prio); +int udev_device_get_watch_handle (struct udev_device *udev_device); +int udev_device_set_watch_handle (struct udev_device *udev_device, + int handle); +int udev_device_get_ifindex (struct udev_device *udev_device); +void udev_device_set_info_loaded (struct udev_device *device); +bool udev_device_get_db_persist (struct udev_device *udev_device); +void udev_device_set_db_persist (struct udev_device *udev_device); /* libudev-device-private.c */ -int udev_device_update_db(struct udev_device *udev_device); -int udev_device_delete_db(struct udev_device *udev_device); -int udev_device_tag_index(struct udev_device *dev, struct udev_device *dev_old, - bool add); +int udev_device_update_db (struct udev_device *udev_device); +int udev_device_delete_db (struct udev_device *udev_device); +int udev_device_tag_index (struct udev_device *dev, + struct udev_device *dev_old, bool add); /* libudev-list.c */ -struct udev_list_node { - struct udev_list_node *next, *prev; +struct udev_list_node +{ + struct udev_list_node *next, *prev; }; -struct udev_list { - struct udev *udev; - struct udev_list_node node; - struct udev_list_entry **entries; - unsigned int entries_cur; - unsigned int entries_max; - bool unique; +struct udev_list +{ + struct udev *udev; + struct udev_list_node node; + struct udev_list_entry **entries; + unsigned int entries_cur; + unsigned int entries_max; + bool unique; }; #define UDEV_LIST(list) struct udev_list_node list = { &(list), &(list) } -void udev_list_node_init(struct udev_list_node *list); -int udev_list_node_is_empty(struct udev_list_node *list); -void udev_list_node_append(struct udev_list_node *new, - struct udev_list_node *list); -void udev_list_node_remove(struct udev_list_node *entry); +void udev_list_node_init (struct udev_list_node *list); +int udev_list_node_is_empty (struct udev_list_node *list); +void udev_list_node_append (struct udev_list_node *new, + struct udev_list_node *list); +void udev_list_node_remove (struct udev_list_node *entry); #define udev_list_node_foreach(node, list) \ for (node = (list)->next; \ node != list; \ @@ -122,15 +133,15 @@ void udev_list_node_remove(struct udev_list_node *entry); for (node = (list)->next, tmp = (node)->next; \ node != list; \ node = tmp, tmp = (tmp)->next) -void udev_list_init(struct udev *udev, struct udev_list *list, bool unique); -void udev_list_cleanup(struct udev_list *list); -struct udev_list_entry *udev_list_get_entry(struct udev_list *list); -struct udev_list_entry *udev_list_entry_add(struct udev_list *list, - const char *name, - const char *value); -void udev_list_entry_delete(struct udev_list_entry *entry); -int udev_list_entry_get_num(struct udev_list_entry *list_entry); -void udev_list_entry_set_num(struct udev_list_entry *list_entry, int num); +void udev_list_init (struct udev *udev, struct udev_list *list, bool unique); +void udev_list_cleanup (struct udev_list *list); +struct udev_list_entry *udev_list_get_entry (struct udev_list *list); +struct udev_list_entry *udev_list_entry_add (struct udev_list *list, + const char *name, + const char *value); +void udev_list_entry_delete (struct udev_list_entry *entry); +int udev_list_entry_get_num (struct udev_list_entry *list_entry); +void udev_list_entry_set_num (struct udev_list_entry *list_entry, int num); #define udev_list_entry_foreach_safe(entry, tmp, first) \ for (entry = first, tmp = udev_list_entry_get_next(entry); \ entry != NULL; \ @@ -145,14 +156,15 @@ void udev_list_entry_set_num(struct udev_list_entry *list_entry, int num); * Connects to a device event source. */ -union sockaddr_union { - struct sockaddr sa; - struct sockaddr_in in; - struct sockaddr_in6 in6; - struct sockaddr_un un; - struct sockaddr_nl nl; - struct sockaddr_storage storage; - struct sockaddr_ll ll; +union sockaddr_union +{ + struct sockaddr sa; + struct sockaddr_in in; + struct sockaddr_in6 in6; + struct sockaddr_un un; + struct sockaddr_nl nl; + struct sockaddr_storage storage; + struct sockaddr_ll ll; }; /** @@ -160,83 +172,88 @@ union sockaddr_union { * * Opaque object handling an event source. */ -struct udev_monitor { - struct udev *udev; - int refcount; - - int type; // libudev-compat: kernel or udev link? - int sock; // libudev-compat: for udev-links, this is a socketpair sink which receives udev devices - // libudev-compat: for kernel-links, this is a netlink socket - union sockaddr_union snl; - union sockaddr_union snl_trusted_sender; - union sockaddr_union snl_destination; - socklen_t addrlen; - struct udev_list filter_subsystem_list; - struct udev_list filter_tag_list; - bool bound; - - // new in libudev-compat - int sock_fs; // socketpair source into which we send udev_devices - int events_wd; // watch descriptor for our events directory - int inotify_fd; // pollable one-shot inotify file descriptor watching the events directory for IN_CREATE. Oneshot because it can overflow. - int epoll_fd; // pollable handle for detecting either the availability of previously-found events (signaled by sock_fs) or new events (inotify_fd) - - pid_t pid; // the PID of the process at the time this monitor was created - char events_dir[PATH_MAX + 1]; // path to the directory we watch - - int slot; // monitor slot in our global monitor table +struct udev_monitor +{ + struct udev *udev; + int refcount; + + int type; // libudev-compat: kernel or udev link? + int sock; // libudev-compat: for udev-links, this is a socketpair sink which receives udev devices + // libudev-compat: for kernel-links, this is a netlink socket + union sockaddr_union snl; + union sockaddr_union snl_trusted_sender; + union sockaddr_union snl_destination; + socklen_t addrlen; + struct udev_list filter_subsystem_list; + struct udev_list filter_tag_list; + bool bound; + + // new in libudev-compat + int sock_fs; // socketpair source into which we send udev_devices + int events_wd; // watch descriptor for our events directory + int inotify_fd; // pollable one-shot inotify file descriptor watching the events directory for IN_CREATE. Oneshot because it can overflow. + int epoll_fd; // pollable handle for detecting either the availability of previously-found events (signaled by sock_fs) or new events (inotify_fd) + + pid_t pid; // the PID of the process at the time this monitor was created + char events_dir[PATH_MAX + 1]; // path to the directory we watch + + int slot; // monitor slot in our global monitor table }; // types of monitors #define UDEV_MONITOR_TYPE_KERNEL 1 #define UDEV_MONITOR_TYPE_UDEV 2 -int udev_monitor_disconnect(struct udev_monitor *udev_monitor); -int udev_monitor_allow_unicast_sender(struct udev_monitor *udev_monitor, - struct udev_monitor *sender); -int udev_monitor_send_device(struct udev_monitor *udev_monitor, - struct udev_monitor *destination, - struct udev_device *udev_device); -struct udev_monitor *udev_monitor_new_from_netlink_fd(struct udev *udev, - const char *name, int fd); -int udev_monitor_filter_update(struct udev_monitor *udev_monitor); +int udev_monitor_disconnect (struct udev_monitor *udev_monitor); +int udev_monitor_allow_unicast_sender (struct udev_monitor *udev_monitor, + struct udev_monitor *sender); +int udev_monitor_send_device (struct udev_monitor *udev_monitor, + struct udev_monitor *destination, + struct udev_device *udev_device); +struct udev_monitor *udev_monitor_new_from_netlink_fd (struct udev *udev, + const char *name, + int fd); +int udev_monitor_filter_update (struct udev_monitor *udev_monitor); /* libudev-queue.c */ -unsigned long long int udev_get_kernel_seqnum(struct udev *udev); -int udev_queue_read_seqnum(FILE * queue_file, unsigned long long int *seqnum); -ssize_t udev_queue_read_devpath(FILE * queue_file, char *devpath, size_t size); -ssize_t udev_queue_skip_devpath(FILE * queue_file); +unsigned long long int udev_get_kernel_seqnum (struct udev *udev); +int udev_queue_read_seqnum (FILE * queue_file, + unsigned long long int *seqnum); +ssize_t udev_queue_read_devpath (FILE * queue_file, char *devpath, + size_t size); +ssize_t udev_queue_skip_devpath (FILE * queue_file); /* libudev-queue-private.c */ -struct udev_queue_export *udev_queue_export_new(struct udev *udev); -struct udev_queue_export *udev_queue_export_unref(struct udev_queue_export - *udev_queue_export); -void udev_queue_export_cleanup(struct udev_queue_export *udev_queue_export); -int udev_queue_export_device_queued(struct udev_queue_export *udev_queue_export, - struct udev_device *udev_device); -int udev_queue_export_device_finished(struct udev_queue_export - *udev_queue_export, - struct udev_device *udev_device); +struct udev_queue_export *udev_queue_export_new (struct udev *udev); +struct udev_queue_export *udev_queue_export_unref (struct udev_queue_export + *udev_queue_export); +void udev_queue_export_cleanup (struct udev_queue_export *udev_queue_export); +int udev_queue_export_device_queued (struct udev_queue_export + *udev_queue_export, + struct udev_device *udev_device); +int udev_queue_export_device_finished (struct udev_queue_export + *udev_queue_export, + struct udev_device *udev_device); /* libudev-util.c */ #define UTIL_PATH_SIZE 1024 #define UTIL_NAME_SIZE 512 #define UTIL_LINE_SIZE 16384 #define UDEV_ALLOWED_CHARS_INPUT "/ $%?," -ssize_t util_get_sys_core_link_value(struct udev *udev, const char *slink, - const char *syspath, char *value, - size_t size); -int util_resolve_sys_link(struct udev *udev, char *syspath, size_t size); -int util_log_priority(const char *priority); -size_t util_path_encode(const char *src, char *dest, size_t size); -void util_remove_trailing_chars(char *path, char c); -int util_replace_whitespace(const char *str, char *to, size_t len); -int util_replace_chars(char *str, const char *white); -unsigned int util_string_hash32(const char *key); -uint64_t util_string_bloom64(const char *str); +ssize_t util_get_sys_core_link_value (struct udev *udev, const char *slink, + const char *syspath, char *value, + size_t size); +int util_resolve_sys_link (struct udev *udev, char *syspath, size_t size); +int util_log_priority (const char *priority); +size_t util_path_encode (const char *src, char *dest, size_t size); +void util_remove_trailing_chars (char *path, char c); +int util_replace_whitespace (const char *str, char *to, size_t len); +int util_replace_chars (char *str, const char *white); +unsigned int util_string_hash32 (const char *key); +uint64_t util_string_bloom64 (const char *str); /* libudev-util-private.c */ -int util_resolve_subsys_kernel(struct udev *udev, const char *string, - char *result, size_t maxsize, int read_value); +int util_resolve_subsys_kernel (struct udev *udev, const char *string, + char *result, size_t maxsize, int read_value); #endif diff --git a/libudev-compat/libudev-queue.c b/libudev-compat/libudev-queue.c index 8d93b4d..b57a48b 100644 --- a/libudev-compat/libudev-queue.c +++ b/libudev-compat/libudev-queue.c @@ -47,10 +47,11 @@ * * Opaque object representing the current event queue in the udev daemon. */ -struct udev_queue { - struct udev *udev; - int refcount; - int fd; +struct udev_queue +{ + struct udev *udev; + int refcount; + int fd; }; /** @@ -62,21 +63,22 @@ struct udev_queue { * * Returns: the udev queue context, or #NULL on error. **/ -_public_ struct udev_queue *udev_queue_new(struct udev *udev) +_public_ struct udev_queue * +udev_queue_new (struct udev *udev) { - struct udev_queue *udev_queue; + struct udev_queue *udev_queue; - if (udev == NULL) - return NULL; + if (udev == NULL) + return NULL; - udev_queue = new0(struct udev_queue, 1); - if (udev_queue == NULL) - return NULL; + udev_queue = new0 (struct udev_queue, 1); + if (udev_queue == NULL) + return NULL; - udev_queue->refcount = 1; - udev_queue->udev = udev; - udev_queue->fd = -1; - return udev_queue; + udev_queue->refcount = 1; + udev_queue->udev = udev; + udev_queue->fd = -1; + return udev_queue; } /** @@ -87,13 +89,14 @@ _public_ struct udev_queue *udev_queue_new(struct udev *udev) * * Returns: the same udev queue context. **/ -_public_ struct udev_queue *udev_queue_ref(struct udev_queue *udev_queue) +_public_ struct udev_queue * +udev_queue_ref (struct udev_queue *udev_queue) { - if (udev_queue == NULL) - return NULL; + if (udev_queue == NULL) + return NULL; - udev_queue->refcount++; - return udev_queue; + udev_queue->refcount++; + return udev_queue; } /** @@ -105,19 +108,20 @@ _public_ struct udev_queue *udev_queue_ref(struct udev_queue *udev_queue) * * Returns: #NULL **/ -_public_ struct udev_queue *udev_queue_unref(struct udev_queue *udev_queue) +_public_ struct udev_queue * +udev_queue_unref (struct udev_queue *udev_queue) { - if (udev_queue == NULL) - return NULL; + if (udev_queue == NULL) + return NULL; - udev_queue->refcount--; - if (udev_queue->refcount > 0) - return NULL; + udev_queue->refcount--; + if (udev_queue->refcount > 0) + return NULL; - safe_close(udev_queue->fd); + safe_close (udev_queue->fd); - free(udev_queue); - return NULL; + free (udev_queue); + return NULL; } /** @@ -128,11 +132,12 @@ _public_ struct udev_queue *udev_queue_unref(struct udev_queue *udev_queue) * * Returns: the udev library context. **/ -_public_ struct udev *udev_queue_get_udev(struct udev_queue *udev_queue) +_public_ struct udev * +udev_queue_get_udev (struct udev_queue *udev_queue) { - if (udev_queue == NULL) - return NULL; - return udev_queue->udev; + if (udev_queue == NULL) + return NULL; + return udev_queue->udev; } /** @@ -143,10 +148,10 @@ _public_ struct udev *udev_queue_get_udev(struct udev_queue *udev_queue) * * Returns: 0. **/ -_public_ unsigned long long int udev_queue_get_kernel_seqnum(struct udev_queue - *udev_queue) +_public_ unsigned long long int +udev_queue_get_kernel_seqnum (struct udev_queue *udev_queue) { - return 0; + return 0; } /** @@ -157,10 +162,10 @@ _public_ unsigned long long int udev_queue_get_kernel_seqnum(struct udev_queue * * Returns: 0. **/ -_public_ unsigned long long int udev_queue_get_udev_seqnum(struct udev_queue - *udev_queue) +_public_ unsigned long long int +udev_queue_get_udev_seqnum (struct udev_queue *udev_queue) { - return 0; + return 0; } /** @@ -171,9 +176,10 @@ _public_ unsigned long long int udev_queue_get_udev_seqnum(struct udev_queue * * Returns: a flag indicating if udev is active. **/ -_public_ int udev_queue_get_udev_is_active(struct udev_queue *udev_queue) +_public_ int +udev_queue_get_udev_is_active (struct udev_queue *udev_queue) { - return access("/run/udev/control", F_OK) >= 0; + return access ("/run/udev/control", F_OK) >= 0; } /** @@ -184,9 +190,10 @@ _public_ int udev_queue_get_udev_is_active(struct udev_queue *udev_queue) * * Returns: a flag indicating if udev is currently handling events. **/ -_public_ int udev_queue_get_queue_is_empty(struct udev_queue *udev_queue) +_public_ int +udev_queue_get_queue_is_empty (struct udev_queue *udev_queue) { - return access("/run/udev/queue", F_OK) < 0; + return access ("/run/udev/queue", F_OK) < 0; } /** @@ -200,14 +207,13 @@ _public_ int udev_queue_get_queue_is_empty(struct udev_queue *udev_queue) * * Returns: a flag indicating if udev is currently handling events. **/ -_public_ int udev_queue_get_seqnum_sequence_is_finished(struct udev_queue - *udev_queue, - unsigned long long int - start, - unsigned long long int - end) +_public_ int +udev_queue_get_seqnum_sequence_is_finished (struct udev_queue + *udev_queue, + unsigned long long int + start, unsigned long long int end) { - return udev_queue_get_queue_is_empty(udev_queue); + return udev_queue_get_queue_is_empty (udev_queue); } /** @@ -220,10 +226,11 @@ _public_ int udev_queue_get_seqnum_sequence_is_finished(struct udev_queue * * Returns: a flag indicating if udev is currently handling events. **/ -_public_ int udev_queue_get_seqnum_is_finished(struct udev_queue *udev_queue, - unsigned long long int seqnum) +_public_ int +udev_queue_get_seqnum_is_finished (struct udev_queue *udev_queue, + unsigned long long int seqnum) { - return udev_queue_get_queue_is_empty(udev_queue); + return udev_queue_get_queue_is_empty (udev_queue); } /** @@ -234,11 +241,10 @@ _public_ int udev_queue_get_seqnum_is_finished(struct udev_queue *udev_queue, * * Returns: NULL. **/ -_public_ struct udev_list_entry *udev_queue_get_queued_list_entry(struct - udev_queue - *udev_queue) +_public_ struct udev_list_entry * +udev_queue_get_queued_list_entry (struct udev_queue *udev_queue) { - return NULL; + return NULL; } /** @@ -247,27 +253,29 @@ _public_ struct udev_list_entry *udev_queue_get_queued_list_entry(struct * * Returns: a file descriptor to watch for a queue to become empty. */ -_public_ int udev_queue_get_fd(struct udev_queue *udev_queue) +_public_ int +udev_queue_get_fd (struct udev_queue *udev_queue) { - int fd; - int r; - - if (udev_queue->fd >= 0) - return udev_queue->fd; - - fd = inotify_init1(IN_CLOEXEC); - if (fd < 0) - return -errno; - - r = inotify_add_watch(fd, "/run/udev", IN_DELETE); - if (r < 0) { - r = -errno; - close(fd); - return r; - } - - udev_queue->fd = fd; - return fd; + int fd; + int r; + + if (udev_queue->fd >= 0) + return udev_queue->fd; + + fd = inotify_init1 (IN_CLOEXEC); + if (fd < 0) + return -errno; + + r = inotify_add_watch (fd, "/run/udev", IN_DELETE); + if (r < 0) + { + r = -errno; + close (fd); + return r; + } + + udev_queue->fd = fd; + return fd; } /** @@ -276,10 +284,11 @@ _public_ int udev_queue_get_fd(struct udev_queue *udev_queue) * * Returns: the result of clearing the watch for queue changes. */ -_public_ int udev_queue_flush(struct udev_queue *udev_queue) +_public_ int +udev_queue_flush (struct udev_queue *udev_queue) { - if (udev_queue->fd < 0) - return -EINVAL; + if (udev_queue->fd < 0) + return -EINVAL; - return flush_fd(udev_queue->fd); + return flush_fd (udev_queue->fd); } diff --git a/libudev-compat/libudev-util.c b/libudev-compat/libudev-util.c index 6cfa9d1..c8ff9af 100644 --- a/libudev-compat/libudev-util.c +++ b/libudev-compat/libudev-util.c @@ -47,258 +47,290 @@ */ /* handle "[/]" format */ -int util_resolve_subsys_kernel(struct udev *udev, const char *string, - char *result, size_t maxsize, int read_value) +int +util_resolve_subsys_kernel (struct udev *udev, const char *string, + char *result, size_t maxsize, int read_value) { - char temp[UTIL_PATH_SIZE]; - char *subsys; - char *sysname; - struct udev_device *dev; - char *attr; - - if (string[0] != '[') - return -1; - - strscpy(temp, sizeof(temp), string); - - subsys = &temp[1]; - - sysname = strchr(subsys, '/'); - if (sysname == NULL) - return -1; - sysname[0] = '\0'; - sysname = &sysname[1]; - - attr = strchr(sysname, ']'); - if (attr == NULL) - return -1; - attr[0] = '\0'; - attr = &attr[1]; - if (attr[0] == '/') - attr = &attr[1]; - if (attr[0] == '\0') - attr = NULL; - - if (read_value && attr == NULL) - return -1; - - dev = udev_device_new_from_subsystem_sysname(udev, subsys, sysname); - if (dev == NULL) - return -1; - - if (read_value) { - const char *val; - - val = udev_device_get_sysattr_value(dev, attr); - if (val != NULL) - strscpy(result, maxsize, val); - else - result[0] = '\0'; - log_debug("value '[%s/%s]%s' is '%s'", subsys, sysname, attr, - result); - } else { - size_t l; - char *s; - - s = result; - l = strpcpyl(&s, maxsize, udev_device_get_syspath(dev), NULL); - if (attr != NULL) - strpcpyl(&s, l, "/", attr, NULL); - log_debug("path '[%s/%s]%s' is '%s'", subsys, sysname, attr, - result); - } - udev_device_unref(dev); - return 0; + char temp[UTIL_PATH_SIZE]; + char *subsys; + char *sysname; + struct udev_device *dev; + char *attr; + + if (string[0] != '[') + return -1; + + strscpy (temp, sizeof (temp), string); + + subsys = &temp[1]; + + sysname = strchr (subsys, '/'); + if (sysname == NULL) + return -1; + sysname[0] = '\0'; + sysname = &sysname[1]; + + attr = strchr (sysname, ']'); + if (attr == NULL) + return -1; + attr[0] = '\0'; + attr = &attr[1]; + if (attr[0] == '/') + attr = &attr[1]; + if (attr[0] == '\0') + attr = NULL; + + if (read_value && attr == NULL) + return -1; + + dev = udev_device_new_from_subsystem_sysname (udev, subsys, sysname); + if (dev == NULL) + return -1; + + if (read_value) + { + const char *val; + + val = udev_device_get_sysattr_value (dev, attr); + if (val != NULL) + strscpy (result, maxsize, val); + else + result[0] = '\0'; + log_debug ("value '[%s/%s]%s' is '%s'", subsys, sysname, attr, result); + } + else + { + size_t l; + char *s; + + s = result; + l = strpcpyl (&s, maxsize, udev_device_get_syspath (dev), NULL); + if (attr != NULL) + strpcpyl (&s, l, "/", attr, NULL); + log_debug ("path '[%s/%s]%s' is '%s'", subsys, sysname, attr, result); + } + udev_device_unref (dev); + return 0; } -ssize_t util_get_sys_core_link_value(struct udev * udev, const char *slink, - const char *syspath, char *value, - size_t size) +ssize_t +util_get_sys_core_link_value (struct udev * udev, const char *slink, + const char *syspath, char *value, size_t size) { - char path[UTIL_PATH_SIZE]; - char target[UTIL_PATH_SIZE]; - ssize_t len; - const char *pos; - - strscpyl(path, sizeof(path), syspath, "/", slink, NULL); - len = readlink(path, target, sizeof(target)); - if (len <= 0 || len == (ssize_t) sizeof(target)) - return -1; - target[len] = '\0'; - pos = strrchr(target, '/'); - if (pos == NULL) - return -1; - pos = &pos[1]; - return strscpy(value, size, pos); + char path[UTIL_PATH_SIZE]; + char target[UTIL_PATH_SIZE]; + ssize_t len; + const char *pos; + + strscpyl (path, sizeof (path), syspath, "/", slink, NULL); + len = readlink (path, target, sizeof (target)); + if (len <= 0 || len == (ssize_t) sizeof (target)) + return -1; + target[len] = '\0'; + pos = strrchr (target, '/'); + if (pos == NULL) + return -1; + pos = &pos[1]; + return strscpy (value, size, pos); } -int util_resolve_sys_link(struct udev *udev, char *syspath, size_t size) +int +util_resolve_sys_link (struct udev *udev, char *syspath, size_t size) { - char link_target[UTIL_PATH_SIZE]; - - ssize_t len; - int i; - int back; - char *base = NULL; - - len = readlink(syspath, link_target, sizeof(link_target)); - if (len <= 0 || len == (ssize_t) sizeof(link_target)) - return -1; - link_target[len] = '\0'; - - for (back = 0; startswith(&link_target[back * 3], "../"); back++) ; - for (i = 0; i <= back; i++) { - base = strrchr(syspath, '/'); - if (base == NULL) - return -EINVAL; - base[0] = '\0'; - } + char link_target[UTIL_PATH_SIZE]; + + ssize_t len; + int i; + int back; + char *base = NULL; + + len = readlink (syspath, link_target, sizeof (link_target)); + if (len <= 0 || len == (ssize_t) sizeof (link_target)) + return -1; + link_target[len] = '\0'; + + for (back = 0; startswith (&link_target[back * 3], "../"); back++); + for (i = 0; i <= back; i++) + { + base = strrchr (syspath, '/'); + if (base == NULL) + return -EINVAL; + base[0] = '\0'; + } - strscpyl(base, size - (base - syspath), "/", &link_target[back * 3], - NULL); - return 0; + strscpyl (base, size - (base - syspath), "/", &link_target[back * 3], NULL); + return 0; } -int util_log_priority(const char *priority) +int +util_log_priority (const char *priority) { - char *endptr; - int prio; - - prio = strtoul(priority, &endptr, 10); - if (endptr[0] == '\0' || isspace(endptr[0])) { - if (prio >= 0 && prio <= 7) { - return prio; - } else { - return -ERANGE; - } + char *endptr; + int prio; + + prio = strtoul (priority, &endptr, 10); + if (endptr[0] == '\0' || isspace (endptr[0])) + { + if (prio >= 0 && prio <= 7) + { + return prio; } - // So, I can't find this method anywhere... -Jude - // return log_level_from_string(priority); - - if (strcasecmp(priority, "err") == 0) { - return LOG_ERR; - } else if (strcasecmp(priority, "debug") == 0) { - return LOG_DEBUG; - } else if (strcasecmp(priority, "info") == 0) { - return LOG_INFO; + else + { + return -ERANGE; } - - return -EINVAL; + } + // So, I can't find this method anywhere... -Jude + // return log_level_from_string(priority); + + if (strcasecmp (priority, "err") == 0) + { + return LOG_ERR; + } + else if (strcasecmp (priority, "debug") == 0) + { + return LOG_DEBUG; + } + else if (strcasecmp (priority, "info") == 0) + { + return LOG_INFO; + } + + return -EINVAL; } -size_t util_path_encode(const char *src, char *dest, size_t size) +size_t +util_path_encode (const char *src, char *dest, size_t size) { - size_t i, j; - - for (i = 0, j = 0; src[i] != '\0'; i++) { - if (src[i] == '/') { - if (j + 4 >= size) { - j = 0; - break; - } - memcpy(&dest[j], "\\x2f", 4); - j += 4; - } else if (src[i] == '\\') { - if (j + 4 >= size) { - j = 0; - break; - } - memcpy(&dest[j], "\\x5c", 4); - j += 4; - } else { - if (j + 1 >= size) { - j = 0; - break; - } - dest[j] = src[i]; - j++; - } + size_t i, j; + + for (i = 0, j = 0; src[i] != '\0'; i++) + { + if (src[i] == '/') + { + if (j + 4 >= size) + { + j = 0; + break; + } + memcpy (&dest[j], "\\x2f", 4); + j += 4; + } + else if (src[i] == '\\') + { + if (j + 4 >= size) + { + j = 0; + break; + } + memcpy (&dest[j], "\\x5c", 4); + j += 4; } - dest[j] = '\0'; - return j; + else + { + if (j + 1 >= size) + { + j = 0; + break; + } + dest[j] = src[i]; + j++; + } + } + dest[j] = '\0'; + return j; } -void util_remove_trailing_chars(char *path, char c) +void +util_remove_trailing_chars (char *path, char c) { - size_t len; + size_t len; - if (path == NULL) - return; - len = strlen(path); - while (len > 0 && path[len - 1] == c) - path[--len] = '\0'; + if (path == NULL) + return; + len = strlen (path); + while (len > 0 && path[len - 1] == c) + path[--len] = '\0'; } -int util_replace_whitespace(const char *str, char *to, size_t len) +int +util_replace_whitespace (const char *str, char *to, size_t len) { - size_t i, j; - - /* strip trailing whitespace */ - len = strnlen(str, len); - while (len && isspace(str[len - 1])) - len--; - - /* strip leading whitespace */ - i = 0; - while (isspace(str[i]) && (i < len)) - i++; - - j = 0; - while (i < len) { - /* substitute multiple whitespace with a single '_' */ - if (isspace(str[i])) { - while (isspace(str[i])) - i++; - to[j++] = '_'; - } - to[j++] = str[i++]; + size_t i, j; + + /* strip trailing whitespace */ + len = strnlen (str, len); + while (len && isspace (str[len - 1])) + len--; + + /* strip leading whitespace */ + i = 0; + while (isspace (str[i]) && (i < len)) + i++; + + j = 0; + while (i < len) + { + /* substitute multiple whitespace with a single '_' */ + if (isspace (str[i])) + { + while (isspace (str[i])) + i++; + to[j++] = '_'; } - to[j] = '\0'; - return 0; + to[j++] = str[i++]; + } + to[j] = '\0'; + return 0; } /* allow chars in whitelist, plain ascii, hex-escaping and valid utf8 */ -int util_replace_chars(char *str, const char *white) +int +util_replace_chars (char *str, const char *white) { - size_t i = 0; - int replaced = 0; - - while (str[i] != '\0') { - int len; - - if (whitelisted_char_for_devnode(str[i], white)) { - i++; - continue; - } - - /* accept hex encoding */ - if (str[i] == '\\' && str[i + 1] == 'x') { - i += 2; - continue; - } - - /* accept valid utf8 */ - len = utf8_encoded_valid_unichar(&str[i]); - if (len > 1) { - i += len; - continue; - } - - /* if space is allowed, replace whitespace with ordinary space */ - if (isspace(str[i]) && white != NULL - && strchr(white, ' ') != NULL) { - str[i] = ' '; - i++; - replaced++; - continue; - } - - /* everything else is replaced with '_' */ - str[i] = '_'; - i++; - replaced++; + size_t i = 0; + int replaced = 0; + + while (str[i] != '\0') + { + int len; + + if (whitelisted_char_for_devnode (str[i], white)) + { + i++; + continue; + } + + /* accept hex encoding */ + if (str[i] == '\\' && str[i + 1] == 'x') + { + i += 2; + continue; + } + + /* accept valid utf8 */ + len = utf8_encoded_valid_unichar (&str[i]); + if (len > 1) + { + i += len; + continue; + } + + /* if space is allowed, replace whitespace with ordinary space */ + if (isspace (str[i]) && white != NULL && strchr (white, ' ') != NULL) + { + str[i] = ' '; + i++; + replaced++; + continue; } - return replaced; + + /* everything else is replaced with '_' */ + str[i] = '_'; + i++; + replaced++; + } + return replaced; } /** @@ -313,25 +345,28 @@ int util_replace_chars(char *str, const char *white) * * Returns: 0 if the entire string was copied, non-zero otherwise. **/ -_public_ int udev_util_encode_string(const char *str, char *str_enc, size_t len) +_public_ int +udev_util_encode_string (const char *str, char *str_enc, size_t len) { - return encode_devnode_name(str, str_enc, len); + return encode_devnode_name (str, str_enc, len); } -unsigned int util_string_hash32(const char *str) +unsigned int +util_string_hash32 (const char *str) { - return MurmurHash2(str, strlen(str), 0); + return MurmurHash2 (str, strlen (str), 0); } /* get a bunch of bit numbers out of the hash, and set the bits in our bit field */ -uint64_t util_string_bloom64(const char *str) +uint64_t +util_string_bloom64 (const char *str) { - uint64_t bits = 0; - unsigned int hash = util_string_hash32(str); - - bits |= 1LLU << (hash & 63); - bits |= 1LLU << ((hash >> 6) & 63); - bits |= 1LLU << ((hash >> 12) & 63); - bits |= 1LLU << ((hash >> 18) & 63); - return bits; + uint64_t bits = 0; + unsigned int hash = util_string_hash32 (str); + + bits |= 1LLU << (hash & 63); + bits |= 1LLU << ((hash >> 6) & 63); + bits |= 1LLU << ((hash >> 12) & 63); + bits |= 1LLU << ((hash >> 18) & 63); + return bits; } diff --git a/libudev-compat/libudev.c b/libudev-compat/libudev.c index 1923db9..47a14af 100644 --- a/libudev-compat/libudev.c +++ b/libudev-compat/libudev.c @@ -49,12 +49,13 @@ * * Opaque object representing the library context. */ -struct udev { - int refcount; - void (*log_fn) (struct udev * udev, - int priority, const char *file, int line, - const char *fn, const char *format, va_list args); - void *userdata; +struct udev +{ + int refcount; + void (*log_fn) (struct udev * udev, + int priority, const char *file, int line, + const char *fn, const char *format, va_list args); + void *userdata; }; /** @@ -66,11 +67,12 @@ struct udev { * * Returns: stored userdata **/ -void *udev_get_userdata(struct udev *udev) +void * +udev_get_userdata (struct udev *udev) { - if (udev == NULL) - return NULL; - return udev->userdata; + if (udev == NULL) + return NULL; + return udev->userdata; } /** @@ -80,11 +82,12 @@ void *udev_get_userdata(struct udev *udev) * * Store custom @userdata in the library context. **/ -void udev_set_userdata(struct udev *udev, void *userdata) +void +udev_set_userdata (struct udev *udev, void *userdata) { - if (udev == NULL) - return; - udev->userdata = userdata; + if (udev == NULL) + return; + udev->userdata = userdata; } /** @@ -98,100 +101,110 @@ void udev_set_userdata(struct udev *udev, void *userdata) * * Returns: a new udev library context **/ -struct udev *udev_new(void) +struct udev * +udev_new (void) { - struct udev *udev; - _cleanup_fclose_ FILE *f = NULL; + struct udev *udev; + _cleanup_fclose_ FILE *f = NULL; - udev = new0(struct udev, 1); - if (udev == NULL) - return NULL; - udev->refcount = 1; + udev = new0 (struct udev, 1); + if (udev == NULL) + return NULL; + udev->refcount = 1; - f = fopen("/etc/udev/udev.conf", "re"); - if (f != NULL) { - char line[UTIL_LINE_SIZE]; - unsigned line_nr = 0; + f = fopen ("/etc/udev/udev.conf", "re"); + if (f != NULL) + { + char line[UTIL_LINE_SIZE]; + unsigned line_nr = 0; - while (fgets(line, sizeof(line), f)) { - size_t len; - char *key; - char *val; + while (fgets (line, sizeof (line), f)) + { + size_t len; + char *key; + char *val; - line_nr++; + line_nr++; - /* find key */ - key = line; - while (isspace(key[0])) - key++; + /* find key */ + key = line; + while (isspace (key[0])) + key++; - /* comment or empty line */ - if (key[0] == '#' || key[0] == '\0') - continue; + /* comment or empty line */ + if (key[0] == '#' || key[0] == '\0') + continue; - /* split key/value */ - val = strchr(key, '='); - if (val == NULL) { - log_debug - ("/etc/udev/udev.conf:%u: missing assignment, skipping line.", - line_nr); - continue; - } - val[0] = '\0'; - val++; + /* split key/value */ + val = strchr (key, '='); + if (val == NULL) + { + log_debug + ("/etc/udev/udev.conf:%u: missing assignment, skipping line.", + line_nr); + continue; + } + val[0] = '\0'; + val++; - /* find value */ - while (isspace(val[0])) - val++; + /* find value */ + while (isspace (val[0])) + val++; - /* terminate key */ - len = strlen(key); - if (len == 0) - continue; - while (isspace(key[len - 1])) - len--; - key[len] = '\0'; + /* terminate key */ + len = strlen (key); + if (len == 0) + continue; + while (isspace (key[len - 1])) + len--; + key[len] = '\0'; - /* terminate value */ - len = strlen(val); - if (len == 0) - continue; - while (isspace(val[len - 1])) - len--; - val[len] = '\0'; + /* terminate value */ + len = strlen (val); + if (len == 0) + continue; + while (isspace (val[len - 1])) + len--; + val[len] = '\0'; - if (len == 0) - continue; + if (len == 0) + continue; - /* unquote */ - if (val[0] == '"' || val[0] == '\'') { - if (val[len - 1] != val[0]) { - log_debug - ("/etc/udev/udev.conf:%u: inconsistent quoting, skipping line.", - line_nr); - continue; - } - val[len - 1] = '\0'; - val++; - } + /* unquote */ + if (val[0] == '"' || val[0] == '\'') + { + if (val[len - 1] != val[0]) + { + log_debug + ("/etc/udev/udev.conf:%u: inconsistent quoting, skipping line.", + line_nr); + continue; + } + val[len - 1] = '\0'; + val++; + } - if (streq(key, "udev_log")) { - int prio; + if (streq (key, "udev_log")) + { + int prio; - prio = util_log_priority(val); - if (prio < 0) { - log_debug - ("/etc/udev/udev.conf:%u: invalid log level '%s', ignoring.", - line_nr, val); - } else { - log_set_max_level(prio); - } - continue; - } + prio = util_log_priority (val); + if (prio < 0) + { + log_debug + ("/etc/udev/udev.conf:%u: invalid log level '%s', ignoring.", + line_nr, val); + } + else + { + log_set_max_level (prio); } + continue; + } } + } - return udev; + return udev; } /** @@ -202,12 +215,13 @@ struct udev *udev_new(void) * * Returns: the passed udev library context **/ -struct udev *udev_ref(struct udev *udev) +struct udev * +udev_ref (struct udev *udev) { - if (udev == NULL) - return NULL; - udev->refcount++; - return udev; + if (udev == NULL) + return NULL; + udev->refcount++; + return udev; } /** @@ -219,15 +233,16 @@ struct udev *udev_ref(struct udev *udev) * * Returns: the passed udev library context if it has still an active reference, or #NULL otherwise. **/ -struct udev *udev_unref(struct udev *udev) +struct udev * +udev_unref (struct udev *udev) { - if (udev == NULL) - return NULL; - udev->refcount--; - if (udev->refcount > 0) - return udev; - free(udev); - return NULL; + if (udev == NULL) + return NULL; + udev->refcount--; + if (udev->refcount > 0) + return udev; + free (udev); + return NULL; } /** @@ -238,13 +253,14 @@ struct udev *udev_unref(struct udev *udev) * This function is deprecated. * **/ -void udev_set_log_fn(struct udev *udev, - void (*log_fn) (struct udev * udev, - int priority, const char *file, int line, - const char *fn, const char *format, - va_list args)) +void +udev_set_log_fn (struct udev *udev, + void (*log_fn) (struct udev * udev, + int priority, const char *file, int line, + const char *fn, const char *format, + va_list args)) { - return; + return; } /** @@ -254,9 +270,10 @@ void udev_set_log_fn(struct udev *udev, * This function is deprecated. * **/ -int udev_get_log_priority(struct udev *udev) +int +udev_get_log_priority (struct udev *udev) { - return log_get_max_level(); + return log_get_max_level (); } /** @@ -267,7 +284,8 @@ int udev_get_log_priority(struct udev *udev) * This function is deprecated. * **/ -void udev_set_log_priority(struct udev *udev, int priority) +void +udev_set_log_priority (struct udev *udev, int priority) { - log_set_max_level(priority); + log_set_max_level (priority); } diff --git a/libudev-compat/libudev.h b/libudev-compat/libudev.h index 4ffb364..69d9a75 100644 --- a/libudev-compat/libudev.h +++ b/libudev-compat/libudev.h @@ -35,7 +35,8 @@ #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif /* @@ -45,36 +46,34 @@ extern "C" { * allows custom logging */ - struct udev; - struct udev *udev_ref(struct udev *udev); - struct udev *udev_unref(struct udev *udev); - struct udev *udev_new(void); - void udev_set_log_fn(struct udev *udev, - void (*log_fn) (struct udev * udev, - int priority, const char *file, - int line, const char *fn, - const char *format, va_list args)); - int udev_get_log_priority(struct udev *udev); - void udev_set_log_priority(struct udev *udev, int priority); - void *udev_get_userdata(struct udev *udev); - void udev_set_userdata(struct udev *udev, void *userdata); + struct udev; + struct udev *udev_ref (struct udev *udev); + struct udev *udev_unref (struct udev *udev); + struct udev *udev_new (void); + void udev_set_log_fn (struct udev *udev, + void (*log_fn) (struct udev * udev, + int priority, const char *file, + int line, const char *fn, + const char *format, va_list args)); + int udev_get_log_priority (struct udev *udev); + void udev_set_log_priority (struct udev *udev, int priority); + void *udev_get_userdata (struct udev *udev); + void udev_set_userdata (struct udev *udev, void *userdata); /* * udev_list * * access to libudev generated lists */ - struct udev_list_entry; - struct udev_list_entry *udev_list_entry_get_next(struct udev_list_entry - *list_entry); - struct udev_list_entry *udev_list_entry_get_by_name(struct - udev_list_entry - *list_entry, - const char *name); - const char *udev_list_entry_get_name(struct udev_list_entry - *list_entry); - const char *udev_list_entry_get_value(struct udev_list_entry - *list_entry); + struct udev_list_entry; + struct udev_list_entry *udev_list_entry_get_next (struct udev_list_entry + *list_entry); + struct udev_list_entry *udev_list_entry_get_by_name (struct + udev_list_entry + *list_entry, + const char *name); + const char *udev_list_entry_get_name (struct udev_list_entry *list_entry); + const char *udev_list_entry_get_value (struct udev_list_entry *list_entry); /** * udev_list_entry_foreach: * @list_entry: entry to store the current position @@ -92,215 +91,206 @@ extern "C" { * * access to sysfs/kernel devices */ - struct udev_device; - struct udev_device *udev_device_ref(struct udev_device *udev_device); - struct udev_device *udev_device_unref(struct udev_device *udev_device); - struct udev *udev_device_get_udev(struct udev_device *udev_device); - struct udev_device *udev_device_new_from_syspath(struct udev *udev, - const char *syspath); - struct udev_device *udev_device_new_from_devnum(struct udev *udev, - char type, - dev_t devnum); - struct udev_device *udev_device_new_from_subsystem_sysname(struct udev - *udev, - const char - *subsystem, - const char - *sysname); - struct udev_device *udev_device_new_from_device_id(struct udev *udev, - const char *id); - struct udev_device *udev_device_new_from_environment(struct udev *udev); + struct udev_device; + struct udev_device *udev_device_ref (struct udev_device *udev_device); + struct udev_device *udev_device_unref (struct udev_device *udev_device); + struct udev *udev_device_get_udev (struct udev_device *udev_device); + struct udev_device *udev_device_new_from_syspath (struct udev *udev, + const char *syspath); + struct udev_device *udev_device_new_from_devnum (struct udev *udev, + char type, dev_t devnum); + struct udev_device *udev_device_new_from_subsystem_sysname (struct udev + *udev, + const char + *subsystem, + const char + *sysname); + struct udev_device *udev_device_new_from_device_id (struct udev *udev, + const char *id); + struct udev_device *udev_device_new_from_environment (struct udev *udev); /* udev_device_get_parent_*() does not take a reference on the returned device, it is automatically unref'd with the parent */ - struct udev_device *udev_device_get_parent(struct udev_device - *udev_device); - struct udev_device *udev_device_get_parent_with_subsystem_devtype(struct - udev_device - *udev_device, - const - char - *subsystem, - const - char - *devtype); + struct udev_device *udev_device_get_parent (struct udev_device + *udev_device); + struct udev_device *udev_device_get_parent_with_subsystem_devtype (struct + udev_device + *udev_device, + const + char + *subsystem, + const + char + *devtype); /* retrieve device properties */ - const char *udev_device_get_devpath(struct udev_device *udev_device); - const char *udev_device_get_subsystem(struct udev_device *udev_device); - const char *udev_device_get_devtype(struct udev_device *udev_device); - const char *udev_device_get_syspath(struct udev_device *udev_device); - const char *udev_device_get_sysname(struct udev_device *udev_device); - const char *udev_device_get_sysnum(struct udev_device *udev_device); - const char *udev_device_get_devnode(struct udev_device *udev_device); - int udev_device_get_is_initialized(struct udev_device *udev_device); - struct udev_list_entry *udev_device_get_devlinks_list_entry(struct - udev_device - *udev_device); - struct udev_list_entry *udev_device_get_properties_list_entry(struct - udev_device - *udev_device); - struct udev_list_entry *udev_device_get_tags_list_entry(struct - udev_device - *udev_device); - struct udev_list_entry *udev_device_get_sysattr_list_entry(struct - udev_device - *udev_device); - const char *udev_device_get_property_value(struct udev_device - *udev_device, - const char *key); - const char *udev_device_get_driver(struct udev_device *udev_device); - dev_t udev_device_get_devnum(struct udev_device *udev_device); - const char *udev_device_get_action(struct udev_device *udev_device); - unsigned long long int udev_device_get_seqnum(struct udev_device - *udev_device); - unsigned long long int udev_device_get_usec_since_initialized(struct - udev_device - *udev_device); - const char *udev_device_get_sysattr_value(struct udev_device - *udev_device, - const char *sysattr); - int udev_device_set_sysattr_value(struct udev_device *udev_device, - const char *sysattr, char *value); - int udev_device_has_tag(struct udev_device *udev_device, - const char *tag); + const char *udev_device_get_devpath (struct udev_device *udev_device); + const char *udev_device_get_subsystem (struct udev_device *udev_device); + const char *udev_device_get_devtype (struct udev_device *udev_device); + const char *udev_device_get_syspath (struct udev_device *udev_device); + const char *udev_device_get_sysname (struct udev_device *udev_device); + const char *udev_device_get_sysnum (struct udev_device *udev_device); + const char *udev_device_get_devnode (struct udev_device *udev_device); + int udev_device_get_is_initialized (struct udev_device *udev_device); + struct udev_list_entry *udev_device_get_devlinks_list_entry (struct + udev_device + *udev_device); + struct udev_list_entry *udev_device_get_properties_list_entry (struct + udev_device + *udev_device); + struct udev_list_entry *udev_device_get_tags_list_entry (struct + udev_device + *udev_device); + struct udev_list_entry *udev_device_get_sysattr_list_entry (struct + udev_device + *udev_device); + const char *udev_device_get_property_value (struct udev_device + *udev_device, const char *key); + const char *udev_device_get_driver (struct udev_device *udev_device); + dev_t udev_device_get_devnum (struct udev_device *udev_device); + const char *udev_device_get_action (struct udev_device *udev_device); + unsigned long long int udev_device_get_seqnum (struct udev_device + *udev_device); + unsigned long long int udev_device_get_usec_since_initialized (struct + udev_device + *udev_device); + const char *udev_device_get_sysattr_value (struct udev_device + *udev_device, + const char *sysattr); + int udev_device_set_sysattr_value (struct udev_device *udev_device, + const char *sysattr, char *value); + int udev_device_has_tag (struct udev_device *udev_device, const char *tag); /* * udev_monitor * * access to kernel uevents and udev events */ - struct udev_monitor; - struct udev_monitor *udev_monitor_ref(struct udev_monitor - *udev_monitor); - struct udev_monitor *udev_monitor_unref(struct udev_monitor - *udev_monitor); - struct udev *udev_monitor_get_udev(struct udev_monitor *udev_monitor); + struct udev_monitor; + struct udev_monitor *udev_monitor_ref (struct udev_monitor *udev_monitor); + struct udev_monitor *udev_monitor_unref (struct udev_monitor *udev_monitor); + struct udev *udev_monitor_get_udev (struct udev_monitor *udev_monitor); /* kernel and udev generated events over netlink */ - struct udev_monitor *udev_monitor_new_from_netlink(struct udev *udev, - const char *name); + struct udev_monitor *udev_monitor_new_from_netlink (struct udev *udev, + const char *name); /* bind socket */ - int udev_monitor_enable_receiving(struct udev_monitor *udev_monitor); - int udev_monitor_set_receive_buffer_size(struct udev_monitor - *udev_monitor, int size); - int udev_monitor_get_fd(struct udev_monitor *udev_monitor); - struct udev_device *udev_monitor_receive_device(struct udev_monitor - *udev_monitor); + int udev_monitor_enable_receiving (struct udev_monitor *udev_monitor); + int udev_monitor_set_receive_buffer_size (struct udev_monitor + *udev_monitor, int size); + int udev_monitor_get_fd (struct udev_monitor *udev_monitor); + struct udev_device *udev_monitor_receive_device (struct udev_monitor + *udev_monitor); /* in-kernel socket filters to select messages that get delivered to a listener */ - int udev_monitor_filter_add_match_subsystem_devtype(struct udev_monitor - *udev_monitor, - const char - *subsystem, - const char - *devtype); - int udev_monitor_filter_add_match_tag(struct udev_monitor *udev_monitor, - const char *tag); - int udev_monitor_filter_update(struct udev_monitor *udev_monitor); - int udev_monitor_filter_remove(struct udev_monitor *udev_monitor); + int udev_monitor_filter_add_match_subsystem_devtype (struct udev_monitor + *udev_monitor, + const char + *subsystem, + const char *devtype); + int udev_monitor_filter_add_match_tag (struct udev_monitor *udev_monitor, + const char *tag); + int udev_monitor_filter_update (struct udev_monitor *udev_monitor); + int udev_monitor_filter_remove (struct udev_monitor *udev_monitor); /* * udev_enumerate * * search sysfs for specific devices and provide a sorted list */ - struct udev_enumerate; - struct udev_enumerate *udev_enumerate_ref(struct udev_enumerate - *udev_enumerate); - struct udev_enumerate *udev_enumerate_unref(struct udev_enumerate - *udev_enumerate); - struct udev *udev_enumerate_get_udev(struct udev_enumerate + struct udev_enumerate; + struct udev_enumerate *udev_enumerate_ref (struct udev_enumerate *udev_enumerate); - struct udev_enumerate *udev_enumerate_new(struct udev *udev); + struct udev_enumerate *udev_enumerate_unref (struct udev_enumerate + *udev_enumerate); + struct udev *udev_enumerate_get_udev (struct udev_enumerate + *udev_enumerate); + struct udev_enumerate *udev_enumerate_new (struct udev *udev); /* device properties filter */ - int udev_enumerate_add_match_subsystem(struct udev_enumerate - *udev_enumerate, - const char *subsystem); - int udev_enumerate_add_nomatch_subsystem(struct udev_enumerate - *udev_enumerate, - const char *subsystem); - int udev_enumerate_add_match_sysattr(struct udev_enumerate - *udev_enumerate, - const char *sysattr, - const char *value); - int udev_enumerate_add_nomatch_sysattr(struct udev_enumerate - *udev_enumerate, - const char *sysattr, - const char *value); - int udev_enumerate_add_match_property(struct udev_enumerate - *udev_enumerate, - const char *property, - const char *value); - int udev_enumerate_add_match_sysname(struct udev_enumerate - *udev_enumerate, - const char *sysname); - int udev_enumerate_add_match_tag(struct udev_enumerate *udev_enumerate, - const char *tag); - int udev_enumerate_add_match_parent(struct udev_enumerate + int udev_enumerate_add_match_subsystem (struct udev_enumerate + *udev_enumerate, + const char *subsystem); + int udev_enumerate_add_nomatch_subsystem (struct udev_enumerate *udev_enumerate, - struct udev_device *parent); - int udev_enumerate_add_match_is_initialized(struct udev_enumerate - *udev_enumerate); - int udev_enumerate_add_syspath(struct udev_enumerate *udev_enumerate, - const char *syspath); + const char *subsystem); + int udev_enumerate_add_match_sysattr (struct udev_enumerate + *udev_enumerate, + const char *sysattr, + const char *value); + int udev_enumerate_add_nomatch_sysattr (struct udev_enumerate + *udev_enumerate, + const char *sysattr, + const char *value); + int udev_enumerate_add_match_property (struct udev_enumerate + *udev_enumerate, + const char *property, + const char *value); + int udev_enumerate_add_match_sysname (struct udev_enumerate + *udev_enumerate, const char *sysname); + int udev_enumerate_add_match_tag (struct udev_enumerate *udev_enumerate, + const char *tag); + int udev_enumerate_add_match_parent (struct udev_enumerate + *udev_enumerate, + struct udev_device *parent); + int udev_enumerate_add_match_is_initialized (struct udev_enumerate + *udev_enumerate); + int udev_enumerate_add_syspath (struct udev_enumerate *udev_enumerate, + const char *syspath); /* run enumeration with active filters */ - int udev_enumerate_scan_devices(struct udev_enumerate *udev_enumerate); - int udev_enumerate_scan_subsystems(struct udev_enumerate - *udev_enumerate); + int udev_enumerate_scan_devices (struct udev_enumerate *udev_enumerate); + int udev_enumerate_scan_subsystems (struct udev_enumerate *udev_enumerate); /* return device list */ - struct udev_list_entry *udev_enumerate_get_list_entry(struct - udev_enumerate - *udev_enumerate); + struct udev_list_entry *udev_enumerate_get_list_entry (struct + udev_enumerate + *udev_enumerate); /* * udev_queue * * access to the currently running udev events */ - struct udev_queue; - struct udev_queue *udev_queue_ref(struct udev_queue *udev_queue); - struct udev_queue *udev_queue_unref(struct udev_queue *udev_queue); - struct udev *udev_queue_get_udev(struct udev_queue *udev_queue); - struct udev_queue *udev_queue_new(struct udev *udev); - unsigned long long int udev_queue_get_kernel_seqnum(struct udev_queue + struct udev_queue; + struct udev_queue *udev_queue_ref (struct udev_queue *udev_queue); + struct udev_queue *udev_queue_unref (struct udev_queue *udev_queue); + struct udev *udev_queue_get_udev (struct udev_queue *udev_queue); + struct udev_queue *udev_queue_new (struct udev *udev); + unsigned long long int udev_queue_get_kernel_seqnum (struct udev_queue + *udev_queue); + unsigned long long int udev_queue_get_udev_seqnum (struct udev_queue + *udev_queue); + int udev_queue_get_udev_is_active (struct udev_queue *udev_queue); + int udev_queue_get_queue_is_empty (struct udev_queue *udev_queue); + int udev_queue_get_seqnum_is_finished (struct udev_queue *udev_queue, + unsigned long long int seqnum); + int udev_queue_get_seqnum_sequence_is_finished (struct udev_queue + *udev_queue, + unsigned long long int + start, + unsigned long long int end); + int udev_queue_get_fd (struct udev_queue *udev_queue); + int udev_queue_flush (struct udev_queue *udev_queue); + struct udev_list_entry *udev_queue_get_queued_list_entry (struct + udev_queue *udev_queue); - unsigned long long int udev_queue_get_udev_seqnum(struct udev_queue - *udev_queue); - int udev_queue_get_udev_is_active(struct udev_queue *udev_queue); - int udev_queue_get_queue_is_empty(struct udev_queue *udev_queue); - int udev_queue_get_seqnum_is_finished(struct udev_queue *udev_queue, - unsigned long long int seqnum); - int udev_queue_get_seqnum_sequence_is_finished(struct udev_queue - *udev_queue, - unsigned long long int - start, - unsigned long long int - end); - int udev_queue_get_fd(struct udev_queue *udev_queue); - int udev_queue_flush(struct udev_queue *udev_queue); - struct udev_list_entry *udev_queue_get_queued_list_entry(struct - udev_queue - *udev_queue); /* * udev_hwdb * * access to the static hardware properties database */ - struct udev_hwdb; - struct udev_hwdb *udev_hwdb_new(struct udev *udev); - struct udev_hwdb *udev_hwdb_ref(struct udev_hwdb *hwdb); - struct udev_hwdb *udev_hwdb_unref(struct udev_hwdb *hwdb); - struct udev_list_entry *udev_hwdb_get_properties_list_entry(struct - udev_hwdb - *hwdb, - const char - *modalias, - unsigned int - flags); + struct udev_hwdb; + struct udev_hwdb *udev_hwdb_new (struct udev *udev); + struct udev_hwdb *udev_hwdb_ref (struct udev_hwdb *hwdb); + struct udev_hwdb *udev_hwdb_unref (struct udev_hwdb *hwdb); + struct udev_list_entry *udev_hwdb_get_properties_list_entry (struct + udev_hwdb + *hwdb, + const char + *modalias, + unsigned int + flags); /* * udev_util * * udev specific utilities */ - int udev_util_encode_string(const char *str, char *str_enc, size_t len); + int udev_util_encode_string (const char *str, char *str_enc, size_t len); #ifdef __cplusplus } /* extern "C" */ diff --git a/libudev-compat/log.c b/libudev-compat/log.c index 1a4a183..312af6c 100644 --- a/libudev-compat/log.c +++ b/libudev-compat/log.c @@ -30,50 +30,59 @@ // undefined by default... static int log_max_level = -1; -void log_set_max_level(int level) +void +log_set_max_level (int level) { - // don't allow invalid log levels (only these methods can do so) - assert((level & LOG_PRIMASK) == level); + // don't allow invalid log levels (only these methods can do so) + assert ((level & LOG_PRIMASK) == level); - log_max_level = level; + log_max_level = level; } -static void log_check_disabled(void) +static void +log_check_disabled (void) { - if (log_max_level == -1) { + if (log_max_level == -1) + { - // undefined default max log level - char *libudev_compat_loglevel_str = - secure_getenv(LIBUDEV_COMPAT_DEBUG_ENVAR); - if (libudev_compat_loglevel_str != NULL - && strlen(libudev_compat_loglevel_str) > 0) { + // undefined default max log level + char *libudev_compat_loglevel_str = + secure_getenv (LIBUDEV_COMPAT_DEBUG_ENVAR); + if (libudev_compat_loglevel_str != NULL + && strlen (libudev_compat_loglevel_str) > 0) + { - // enable debugging - log_max_level = LIBUDEV_COMPAT_DEBUG; - } else { + // enable debugging + log_max_level = LIBUDEV_COMPAT_DEBUG; + } + else + { - // disable debugging - log_max_level = LIBUDEV_COMPAT_NO_DEBUG; - } + // disable debugging + log_max_level = LIBUDEV_COMPAT_NO_DEBUG; } + } } -int log_get_max_level(void) +int +log_get_max_level (void) { - log_check_disabled(); - return log_max_level; + log_check_disabled (); + return log_max_level; } -void log_impl(int level, char const *fmt, ...) +void +log_impl (int level, char const *fmt, ...) { - log_check_disabled(); - if (level <= log_max_level) { - va_list args; - va_start(args, fmt); - vfprintf(stderr, fmt, args); - va_end(args); - } + log_check_disabled (); + if (level <= log_max_level) + { + va_list args; + va_start (args, fmt); + vfprintf (stderr, fmt, args); + va_end (args); + } } diff --git a/libudev-compat/log.h b/libudev-compat/log.h index 0bb6641..63a39b9 100644 --- a/libudev-compat/log.h +++ b/libudev-compat/log.h @@ -38,9 +38,9 @@ #define log_debug( fmt, ... ) log_impl( LOG_DEBUG, LIBUDEV_COMPAT_WHERESTR fmt "\n", (int)getpid(), __FILE__, __LINE__, __func__, __VA_ARGS__ ) #define log_error( fmt, ... ) log_impl( LOG_ERR, LIBUDEV_COMPAT_WHERESTR fmt "\n", (int)getpid(), __FILE__, __LINE__, __func__, __VA_ARGS__ ) -void log_set_max_level(int level); -int log_get_max_level(void); +void log_set_max_level (int level); +int log_get_max_level (void); -void log_impl(int level, char const *fmt, ...); +void log_impl (int level, char const *fmt, ...); #endif diff --git a/libudev-compat/macro.h b/libudev-compat/macro.h index 05ea59d..fea2edf 100644 --- a/libudev-compat/macro.h +++ b/libudev-compat/macro.h @@ -112,25 +112,27 @@ #define ALIGN4_PTR(p) ((void*) ALIGN4((unsigned long) (p))) #define ALIGN8_PTR(p) ((void*) ALIGN8((unsigned long) (p))) -static inline size_t ALIGN_TO(size_t l, size_t ali) +static inline size_t +ALIGN_TO (size_t l, size_t ali) { - return ((l + ali - 1) & ~(ali - 1)); + return ((l + ali - 1) & ~(ali - 1)); } #define ALIGN_TO_PTR(p, ali) ((void*) ALIGN_TO((unsigned long) (p), (ali))) /* align to next higher power-of-2 (except for: 0 => 0, overflow => 0) */ -static inline unsigned long ALIGN_POWER2(unsigned long u) +static inline unsigned long +ALIGN_POWER2 (unsigned long u) { - /* clz(0) is undefined */ - if (u == 1) - return 1; + /* clz(0) is undefined */ + if (u == 1) + return 1; - /* left-shift overflow is undefined */ - if (__builtin_clzl(u - 1UL) < 1) - return 0; + /* left-shift overflow is undefined */ + if (__builtin_clzl (u - 1UL) < 1) + return 0; - return 1UL << (sizeof(u) * 8 - __builtin_clzl(u - 1UL)); + return 1UL << (sizeof (u) * 8 - __builtin_clzl (u - 1UL)); } #define ELEMENTSOF(x) (sizeof(x)/sizeof((x)[0])) @@ -313,34 +315,37 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) _i->iov_len = strlen(_s); \ } while(false) -static inline size_t IOVEC_TOTAL_SIZE(const struct iovec *i, unsigned n) +static inline size_t +IOVEC_TOTAL_SIZE (const struct iovec *i, unsigned n) { - unsigned j; - size_t r = 0; + unsigned j; + size_t r = 0; - for (j = 0; j < n; j++) - r += i[j].iov_len; + for (j = 0; j < n; j++) + r += i[j].iov_len; - return r; + return r; } -static inline size_t IOVEC_INCREMENT(struct iovec *i, unsigned n, size_t k) +static inline size_t +IOVEC_INCREMENT (struct iovec *i, unsigned n, size_t k) { - unsigned j; + unsigned j; - for (j = 0; j < n; j++) { - size_t sub; + for (j = 0; j < n; j++) + { + size_t sub; - if (_unlikely_(k <= 0)) - break; + if (_unlikely_ (k <= 0)) + break; - sub = MIN(i[j].iov_len, k); - i[j].iov_len -= sub; - i[j].iov_base = (uint8_t *) i[j].iov_base + sub; - k -= sub; - } + sub = MIN (i[j].iov_len, k); + i[j].iov_len -= sub; + i[j].iov_base = (uint8_t *) i[j].iov_base + sub; + k -= sub; + } - return k; + return k; } #define VA_FORMAT_ADVANCE(format, ap) \ diff --git a/libudev-compat/mempool.c b/libudev-compat/mempool.c index ca5cfde..fb6fe4d 100644 --- a/libudev-compat/mempool.c +++ b/libudev-compat/mempool.c @@ -28,86 +28,93 @@ // #include "macro.h" #include "util.h" -struct pool { - struct pool *next; - unsigned n_tiles; - unsigned n_used; +struct pool +{ + struct pool *next; + unsigned n_tiles; + unsigned n_used; }; -void *mempool_alloc_tile(struct mempool *mp) +void * +mempool_alloc_tile (struct mempool *mp) { - unsigned i; + unsigned i; - /* When a tile is released we add it to the list and simply - * place the next pointer at its offset 0. */ + /* When a tile is released we add it to the list and simply + * place the next pointer at its offset 0. */ - assert(mp->tile_size >= sizeof(void *)); - assert(mp->at_least > 0); + assert (mp->tile_size >= sizeof (void *)); + assert (mp->at_least > 0); - if (mp->freelist) { - void *r; + if (mp->freelist) + { + void *r; - r = mp->freelist; - mp->freelist = *(void **)mp->freelist; - return r; - } + r = mp->freelist; + mp->freelist = *(void **) mp->freelist; + return r; + } - if (_unlikely_(!mp->first_pool) || - _unlikely_(mp->first_pool->n_used >= mp->first_pool->n_tiles)) { - unsigned n; - size_t size; - struct pool *p; + if (_unlikely_ (!mp->first_pool) || + _unlikely_ (mp->first_pool->n_used >= mp->first_pool->n_tiles)) + { + unsigned n; + size_t size; + struct pool *p; - n = mp->first_pool ? mp->first_pool->n_tiles : 0; - n = MAX(mp->at_least, n * 2); - size = - PAGE_ALIGN(ALIGN(sizeof(struct pool)) + n * mp->tile_size); - n = (size - ALIGN(sizeof(struct pool))) / mp->tile_size; + n = mp->first_pool ? mp->first_pool->n_tiles : 0; + n = MAX (mp->at_least, n * 2); + size = PAGE_ALIGN (ALIGN (sizeof (struct pool)) + n * mp->tile_size); + n = (size - ALIGN (sizeof (struct pool))) / mp->tile_size; - p = malloc(size); - if (!p) - return NULL; + p = malloc (size); + if (!p) + return NULL; - p->next = mp->first_pool; - p->n_tiles = n; - p->n_used = 0; + p->next = mp->first_pool; + p->n_tiles = n; + p->n_used = 0; - mp->first_pool = p; - } + mp->first_pool = p; + } - i = mp->first_pool->n_used++; + i = mp->first_pool->n_used++; - return ((uint8_t *) mp->first_pool) + ALIGN(sizeof(struct pool)) + - i * mp->tile_size; + return ((uint8_t *) mp->first_pool) + ALIGN (sizeof (struct pool)) + + i * mp->tile_size; } -void *mempool_alloc0_tile(struct mempool *mp) +void * +mempool_alloc0_tile (struct mempool *mp) { - void *p; + void *p; - p = mempool_alloc_tile(mp); - if (p) - memzero(p, mp->tile_size); - return p; + p = mempool_alloc_tile (mp); + if (p) + memzero (p, mp->tile_size); + return p; } -void mempool_free_tile(struct mempool *mp, void *p) +void +mempool_free_tile (struct mempool *mp, void *p) { - *(void **)p = mp->freelist; - mp->freelist = p; + *(void **) p = mp->freelist; + mp->freelist = p; } #ifdef VALGRIND -void mempool_drop(struct mempool *mp) +void +mempool_drop (struct mempool *mp) { - struct pool *p = mp->first_pool; - while (p) { - struct pool *n; - n = p->next; - free(p); - p = n; - } + struct pool *p = mp->first_pool; + while (p) + { + struct pool *n; + n = p->next; + free (p); + p = n; + } } #endif diff --git a/libudev-compat/mempool.h b/libudev-compat/mempool.h index b5f6860..5a96316 100644 --- a/libudev-compat/mempool.h +++ b/libudev-compat/mempool.h @@ -31,16 +31,17 @@ struct pool; -struct mempool { - struct pool *first_pool; - void *freelist; - size_t tile_size; - unsigned at_least; +struct mempool +{ + struct pool *first_pool; + void *freelist; + size_t tile_size; + unsigned at_least; }; -void *mempool_alloc_tile(struct mempool *mp); -void *mempool_alloc0_tile(struct mempool *mp); -void mempool_free_tile(struct mempool *mp, void *p); +void *mempool_alloc_tile (struct mempool *mp); +void *mempool_alloc0_tile (struct mempool *mp); +void mempool_free_tile (struct mempool *mp, void *p); #define DEFINE_MEMPOOL(pool_name, tile_type, alloc_at_least) \ struct mempool pool_name = { \ @@ -49,7 +50,7 @@ struct mempool pool_name = { \ } #ifdef VALGRIND -void mempool_drop(struct mempool *mp); +void mempool_drop (struct mempool *mp); #endif #endif diff --git a/libudev-compat/mkdir.c b/libudev-compat/mkdir.c index 4aec9cc..7eaeb82 100644 --- a/libudev-compat/mkdir.c +++ b/libudev-compat/mkdir.c @@ -29,144 +29,154 @@ #include "util.h" #include "mkdir.h" -char *path_startswith(const char *path, const char *prefix) +char * +path_startswith (const char *path, const char *prefix) { - assert(path); - assert(prefix); + assert (path); + assert (prefix); - if ((path[0] == '/') != (prefix[0] == '/')) - return NULL; + if ((path[0] == '/') != (prefix[0] == '/')) + return NULL; - for (;;) { - size_t a, b; + for (;;) + { + size_t a, b; - path += strspn(path, "/"); - prefix += strspn(prefix, "/"); + path += strspn (path, "/"); + prefix += strspn (prefix, "/"); - if (*prefix == 0) - return (char *)path; + if (*prefix == 0) + return (char *) path; - if (*path == 0) - return NULL; + if (*path == 0) + return NULL; - a = strcspn(path, "/"); - b = strcspn(prefix, "/"); + a = strcspn (path, "/"); + b = strcspn (prefix, "/"); - if (a != b) - return NULL; + if (a != b) + return NULL; - if (memcmp(path, prefix, a) != 0) - return NULL; + if (memcmp (path, prefix, a) != 0) + return NULL; - path += a; - prefix += b; - } + path += a; + prefix += b; + } } -int mkdir_safe_internal(const char *path, mode_t mode, uid_t uid, gid_t gid, - mkdir_func_t _mkdir) +int +mkdir_safe_internal (const char *path, mode_t mode, uid_t uid, gid_t gid, + mkdir_func_t _mkdir) { - struct stat st; - - if (_mkdir(path, mode) >= 0) - if (chmod_and_chown(path, mode, uid, gid) < 0) - return -errno; - - if (lstat(path, &st) < 0) - return -errno; - - if ((st.st_mode & 0007) > (mode & 0007) || - (st.st_mode & 0070) > (mode & 0070) || - (st.st_mode & 0700) > (mode & 0700) || - (uid != UID_INVALID && st.st_uid != uid) || - (gid != GID_INVALID && st.st_gid != gid) || !S_ISDIR(st.st_mode)) { - errno = EEXIST; - return -errno; - } - - return 0; + struct stat st; + + if (_mkdir (path, mode) >= 0) + if (chmod_and_chown (path, mode, uid, gid) < 0) + return -errno; + + if (lstat (path, &st) < 0) + return -errno; + + if ((st.st_mode & 0007) > (mode & 0007) || + (st.st_mode & 0070) > (mode & 0070) || + (st.st_mode & 0700) > (mode & 0700) || + (uid != UID_INVALID && st.st_uid != uid) || + (gid != GID_INVALID && st.st_gid != gid) || !S_ISDIR (st.st_mode)) + { + errno = EEXIST; + return -errno; + } + + return 0; } -int mkdir_safe(const char *path, mode_t mode, uid_t uid, gid_t gid) +int +mkdir_safe (const char *path, mode_t mode, uid_t uid, gid_t gid) { - return mkdir_safe_internal(path, mode, uid, gid, mkdir); + return mkdir_safe_internal (path, mode, uid, gid, mkdir); } -int mkdir_parents_internal(const char *prefix, const char *path, mode_t mode, - mkdir_func_t _mkdir) +int +mkdir_parents_internal (const char *prefix, const char *path, mode_t mode, + mkdir_func_t _mkdir) { - const char *p, *e; - int r; + const char *p, *e; + int r; - assert(path); + assert (path); - if (prefix && !path_startswith(path, prefix)) - return -ENOTDIR; + if (prefix && !path_startswith (path, prefix)) + return -ENOTDIR; - /* return immediately if directory exists */ - e = strrchr(path, '/'); - if (!e) - return -EINVAL; + /* return immediately if directory exists */ + e = strrchr (path, '/'); + if (!e) + return -EINVAL; - if (e == path) - return 0; + if (e == path) + return 0; - p = strndupa(path, e - path); - r = is_dir(p, true); - if (r > 0) - return 0; - if (r == 0) - return -ENOTDIR; + p = strndupa (path, e - path); + r = is_dir (p, true); + if (r > 0) + return 0; + if (r == 0) + return -ENOTDIR; - /* create every parent directory in the path, except the last component */ - p = path + strspn(path, "/"); - for (;;) { - char t[strlen(path) + 1]; + /* create every parent directory in the path, except the last component */ + p = path + strspn (path, "/"); + for (;;) + { + char t[strlen (path) + 1]; - e = p + strcspn(p, "/"); - p = e + strspn(e, "/"); + e = p + strcspn (p, "/"); + p = e + strspn (e, "/"); - /* Is this the last component? If so, then we're - * done */ - if (*p == 0) - return 0; + /* Is this the last component? If so, then we're + * done */ + if (*p == 0) + return 0; - memcpy(t, path, e - path); - t[e - path] = 0; + memcpy (t, path, e - path); + t[e - path] = 0; - if (prefix && path_startswith(prefix, t)) - continue; + if (prefix && path_startswith (prefix, t)) + continue; - r = _mkdir(t, mode); - if (r < 0 && errno != EEXIST) - return -errno; - } + r = _mkdir (t, mode); + if (r < 0 && errno != EEXIST) + return -errno; + } } -int mkdir_parents(const char *path, mode_t mode) +int +mkdir_parents (const char *path, mode_t mode) { - return mkdir_parents_internal(NULL, path, mode, mkdir); + return mkdir_parents_internal (NULL, path, mode, mkdir); } -int mkdir_p_internal(const char *prefix, const char *path, mode_t mode, - mkdir_func_t _mkdir) +int +mkdir_p_internal (const char *prefix, const char *path, mode_t mode, + mkdir_func_t _mkdir) { - int r; + int r; - /* Like mkdir -p */ + /* Like mkdir -p */ - r = mkdir_parents_internal(prefix, path, mode, _mkdir); - if (r < 0) - return r; + r = mkdir_parents_internal (prefix, path, mode, _mkdir); + if (r < 0) + return r; - r = _mkdir(path, mode); - if (r < 0 && (errno != EEXIST || is_dir(path, true) <= 0)) - return -errno; + r = _mkdir (path, mode); + if (r < 0 && (errno != EEXIST || is_dir (path, true) <= 0)) + return -errno; - return 0; + return 0; } -int mkdir_p(const char *path, mode_t mode) +int +mkdir_p (const char *path, mode_t mode) { - return mkdir_p_internal(NULL, path, mode, mkdir); + return mkdir_p_internal (NULL, path, mode, mkdir); } diff --git a/libudev-compat/mkdir.h b/libudev-compat/mkdir.h index 3e14dc4..1a2dcee 100644 --- a/libudev-compat/mkdir.h +++ b/libudev-compat/mkdir.h @@ -34,17 +34,17 @@ #include #include -int mkdir_safe(const char *path, mode_t mode, uid_t uid, gid_t gid); -int mkdir_parents(const char *path, mode_t mode); -int mkdir_p(const char *path, mode_t mode); +int mkdir_safe (const char *path, mode_t mode, uid_t uid, gid_t gid); +int mkdir_parents (const char *path, mode_t mode); +int mkdir_p (const char *path, mode_t mode); /* internally used */ typedef int (*mkdir_func_t) (const char *pathname, mode_t mode); -int mkdir_safe_internal(const char *path, mode_t mode, uid_t uid, gid_t gid, - mkdir_func_t _mkdir); -int mkdir_parents_internal(const char *prefix, const char *path, mode_t mode, - mkdir_func_t _mkdir); -int mkdir_p_internal(const char *prefix, const char *path, mode_t mode, - mkdir_func_t _mkdir); +int mkdir_safe_internal (const char *path, mode_t mode, uid_t uid, gid_t gid, + mkdir_func_t _mkdir); +int mkdir_parents_internal (const char *prefix, const char *path, mode_t mode, + mkdir_func_t _mkdir); +int mkdir_p_internal (const char *prefix, const char *path, mode_t mode, + mkdir_func_t _mkdir); #endif diff --git a/libudev-compat/sd-hwdb.c b/libudev-compat/sd-hwdb.c index f2640b5..4bb63f6 100644 --- a/libudev-compat/sd-hwdb.c +++ b/libudev-compat/sd-hwdb.c @@ -45,519 +45,550 @@ #include "hwdb-util.h" #include "hwdb-internal.h" -struct sd_hwdb { - RefCount n_ref; - int refcount; - - FILE *f; - struct stat st; - union { - struct trie_header_f *head; - const char *map; - }; - - char *modalias; - - OrderedHashmap *properties; - Iterator properties_iterator; - bool properties_modified; +struct sd_hwdb +{ + RefCount n_ref; + int refcount; + + FILE *f; + struct stat st; + union + { + struct trie_header_f *head; + const char *map; + }; + + char *modalias; + + OrderedHashmap *properties; + Iterator properties_iterator; + bool properties_modified; }; -struct linebuf { - char bytes[LINE_MAX]; - size_t size; - size_t len; +struct linebuf +{ + char bytes[LINE_MAX]; + size_t size; + size_t len; }; -static void linebuf_init(struct linebuf *buf) +static void +linebuf_init (struct linebuf *buf) { - buf->size = 0; - buf->len = 0; + buf->size = 0; + buf->len = 0; } -static const char *linebuf_get(struct linebuf *buf) +static const char * +linebuf_get (struct linebuf *buf) { - if (buf->len + 1 >= sizeof(buf->bytes)) - return NULL; - buf->bytes[buf->len] = '\0'; - return buf->bytes; + if (buf->len + 1 >= sizeof (buf->bytes)) + return NULL; + buf->bytes[buf->len] = '\0'; + return buf->bytes; } -static bool linebuf_add(struct linebuf *buf, const char *s, size_t len) +static bool +linebuf_add (struct linebuf *buf, const char *s, size_t len) { - if (buf->len + len >= sizeof(buf->bytes)) - return false; - memcpy(buf->bytes + buf->len, s, len); - buf->len += len; - return true; + if (buf->len + len >= sizeof (buf->bytes)) + return false; + memcpy (buf->bytes + buf->len, s, len); + buf->len += len; + return true; } -static bool linebuf_add_char(struct linebuf *buf, char c) +static bool +linebuf_add_char (struct linebuf *buf, char c) { - if (buf->len + 1 >= sizeof(buf->bytes)) - return false; - buf->bytes[buf->len++] = c; - return true; + if (buf->len + 1 >= sizeof (buf->bytes)) + return false; + buf->bytes[buf->len++] = c; + return true; } -static void linebuf_rem(struct linebuf *buf, size_t count) +static void +linebuf_rem (struct linebuf *buf, size_t count) { - assert(buf->len >= count); - buf->len -= count; + assert (buf->len >= count); + buf->len -= count; } -static void linebuf_rem_char(struct linebuf *buf) +static void +linebuf_rem_char (struct linebuf *buf) { - linebuf_rem(buf, 1); + linebuf_rem (buf, 1); } -static const struct trie_child_entry_f *trie_node_children(sd_hwdb * hwdb, - const struct - trie_node_f *node) +static const struct trie_child_entry_f * +trie_node_children (sd_hwdb * hwdb, const struct trie_node_f *node) { - return (const struct trie_child_entry_f *)((const char *)node + - le64toh(hwdb->head-> - node_size)); + return (const struct trie_child_entry_f *) ((const char *) node + + le64toh (hwdb-> + head->node_size)); } -static const struct trie_value_entry_f *trie_node_values(sd_hwdb * hwdb, - const struct - trie_node_f *node) +static const struct trie_value_entry_f * +trie_node_values (sd_hwdb * hwdb, const struct trie_node_f *node) { - const char *base = (const char *)node; + const char *base = (const char *) node; - base += le64toh(hwdb->head->node_size); - base += node->children_count * le64toh(hwdb->head->child_entry_size); - return (const struct trie_value_entry_f *)base; + base += le64toh (hwdb->head->node_size); + base += node->children_count * le64toh (hwdb->head->child_entry_size); + return (const struct trie_value_entry_f *) base; } -static const struct trie_node_f *trie_node_from_off(sd_hwdb * hwdb, le64_t off) +static const struct trie_node_f * +trie_node_from_off (sd_hwdb * hwdb, le64_t off) { - return (const struct trie_node_f *)(hwdb->map + le64toh(off)); + return (const struct trie_node_f *) (hwdb->map + le64toh (off)); } -static const char *trie_string(sd_hwdb * hwdb, le64_t off) +static const char * +trie_string (sd_hwdb * hwdb, le64_t off) { - return hwdb->map + le64toh(off); + return hwdb->map + le64toh (off); } -static int trie_children_cmp_f(const void *v1, const void *v2) +static int +trie_children_cmp_f (const void *v1, const void *v2) { - const struct trie_child_entry_f *n1 = v1; - const struct trie_child_entry_f *n2 = v2; + const struct trie_child_entry_f *n1 = v1; + const struct trie_child_entry_f *n2 = v2; - return n1->c - n2->c; + return n1->c - n2->c; } -static const struct trie_node_f *node_lookup_f(sd_hwdb * hwdb, - const struct trie_node_f *node, - uint8_t c) +static const struct trie_node_f * +node_lookup_f (sd_hwdb * hwdb, const struct trie_node_f *node, uint8_t c) { - struct trie_child_entry_f *child; - struct trie_child_entry_f search; - - search.c = c; - child = - bsearch(&search, trie_node_children(hwdb, node), - node->children_count, le64toh(hwdb->head->child_entry_size), - trie_children_cmp_f); - if (child) - return trie_node_from_off(hwdb, child->child_off); - return NULL; + struct trie_child_entry_f *child; + struct trie_child_entry_f search; + + search.c = c; + child = + bsearch (&search, trie_node_children (hwdb, node), + node->children_count, le64toh (hwdb->head->child_entry_size), + trie_children_cmp_f); + if (child) + return trie_node_from_off (hwdb, child->child_off); + return NULL; } -static int hwdb_add_property(sd_hwdb * hwdb, const char *key, const char *value) +static int +hwdb_add_property (sd_hwdb * hwdb, const char *key, const char *value) { - int r; + int r; - assert(hwdb); - assert(key); - assert(value); + assert (hwdb); + assert (key); + assert (value); - /* - * Silently ignore all properties which do not start with a - * space; future extensions might use additional prefixes. - */ - if (key[0] != ' ') - return 0; + /* + * Silently ignore all properties which do not start with a + * space; future extensions might use additional prefixes. + */ + if (key[0] != ' ') + return 0; - key++; + key++; - r = ordered_hashmap_ensure_allocated(&hwdb->properties, - &string_hash_ops); - if (r < 0) - return r; + r = ordered_hashmap_ensure_allocated (&hwdb->properties, &string_hash_ops); + if (r < 0) + return r; - r = ordered_hashmap_replace(hwdb->properties, key, (char *)value); - if (r < 0) - return r; + r = ordered_hashmap_replace (hwdb->properties, key, (char *) value); + if (r < 0) + return r; - hwdb->properties_modified = true; + hwdb->properties_modified = true; - return 0; + return 0; } -static int trie_fnmatch_f(sd_hwdb * hwdb, const struct trie_node_f *node, - size_t p, struct linebuf *buf, const char *search) +static int +trie_fnmatch_f (sd_hwdb * hwdb, const struct trie_node_f *node, + size_t p, struct linebuf *buf, const char *search) { - size_t len; - size_t i; - const char *prefix; - int err; - - prefix = trie_string(hwdb, node->prefix_off); - len = strlen(prefix + p); - linebuf_add(buf, prefix + p, len); - - for (i = 0; i < node->children_count; i++) { - const struct trie_child_entry_f *child = - &trie_node_children(hwdb, node)[i]; - - linebuf_add_char(buf, child->c); - err = - trie_fnmatch_f(hwdb, - trie_node_from_off(hwdb, child->child_off), - 0, buf, search); - if (err < 0) - return err; - linebuf_rem_char(buf); - } - - if (le64toh(node->values_count) - && fnmatch(linebuf_get(buf), search, 0) == 0) - for (i = 0; i < le64toh(node->values_count); i++) { - err = - hwdb_add_property(hwdb, - trie_string(hwdb, - trie_node_values(hwdb, - node) - [i].key_off), - trie_string(hwdb, - trie_node_values(hwdb, - node) - [i].value_off)); - if (err < 0) - return err; - } - - linebuf_rem(buf, len); - return 0; + size_t len; + size_t i; + const char *prefix; + int err; + + prefix = trie_string (hwdb, node->prefix_off); + len = strlen (prefix + p); + linebuf_add (buf, prefix + p, len); + + for (i = 0; i < node->children_count; i++) + { + const struct trie_child_entry_f *child = + &trie_node_children (hwdb, node)[i]; + + linebuf_add_char (buf, child->c); + err = + trie_fnmatch_f (hwdb, + trie_node_from_off (hwdb, child->child_off), + 0, buf, search); + if (err < 0) + return err; + linebuf_rem_char (buf); + } + + if (le64toh (node->values_count) + && fnmatch (linebuf_get (buf), search, 0) == 0) + for (i = 0; i < le64toh (node->values_count); i++) + { + err = + hwdb_add_property (hwdb, + trie_string (hwdb, + trie_node_values (hwdb, + node) + [i].key_off), + trie_string (hwdb, + trie_node_values (hwdb, + node) + [i].value_off)); + if (err < 0) + return err; + } + + linebuf_rem (buf, len); + return 0; } -static int trie_search_f(sd_hwdb * hwdb, const char *search) +static int +trie_search_f (sd_hwdb * hwdb, const char *search) { - struct linebuf buf; - const struct trie_node_f *node; - size_t i = 0; - int err; - - linebuf_init(&buf); - - node = trie_node_from_off(hwdb, hwdb->head->nodes_root_off); - while (node) { - const struct trie_node_f *child; - size_t p = 0; - - if (node->prefix_off) { - uint8_t c; - - for (; (c = trie_string(hwdb, node->prefix_off)[p]); - p++) { - if (c == '*' || c == '?' || c == '[') - return trie_fnmatch_f(hwdb, node, p, - &buf, - search + i + p); - if (c != search[i + p]) - return 0; - } - i += p; - } - - child = node_lookup_f(hwdb, node, '*'); - if (child) { - linebuf_add_char(&buf, '*'); - err = trie_fnmatch_f(hwdb, child, 0, &buf, search + i); - if (err < 0) - return err; - linebuf_rem_char(&buf); - } - - child = node_lookup_f(hwdb, node, '?'); - if (child) { - linebuf_add_char(&buf, '?'); - err = trie_fnmatch_f(hwdb, child, 0, &buf, search + i); - if (err < 0) - return err; - linebuf_rem_char(&buf); - } - - child = node_lookup_f(hwdb, node, '['); - if (child) { - linebuf_add_char(&buf, '['); - err = trie_fnmatch_f(hwdb, child, 0, &buf, search + i); - if (err < 0) - return err; - linebuf_rem_char(&buf); - } - - if (search[i] == '\0') { - size_t n; - - for (n = 0; n < le64toh(node->values_count); n++) { - err = - hwdb_add_property(hwdb, - trie_string(hwdb, - trie_node_values - (hwdb, - node)[n]. - key_off), - trie_string(hwdb, - trie_node_values - (hwdb, - node)[n]. - value_off)); - if (err < 0) - return err; - } - return 0; - } - - child = node_lookup_f(hwdb, node, search[i]); - node = child; - i++; + struct linebuf buf; + const struct trie_node_f *node; + size_t i = 0; + int err; + + linebuf_init (&buf); + + node = trie_node_from_off (hwdb, hwdb->head->nodes_root_off); + while (node) + { + const struct trie_node_f *child; + size_t p = 0; + + if (node->prefix_off) + { + uint8_t c; + + for (; (c = trie_string (hwdb, node->prefix_off)[p]); p++) + { + if (c == '*' || c == '?' || c == '[') + return trie_fnmatch_f (hwdb, node, p, &buf, search + i + p); + if (c != search[i + p]) + return 0; + } + i += p; } - return 0; -} -static const char hwdb_bin_paths[] = - "/etc/systemd/hwdb/hwdb.bin\0" - "/etc/udev/hwdb.bin\0" "/usr/lib/systemd/hwdb/hwdb.bin\0" -#ifdef HAVE_SPLIT_USR - "/lib/systemd/hwdb/hwdb.bin\0" -#endif - "/lib/systemd/hwdb.bin\0"; - -_public_ int sd_hwdb_new(sd_hwdb ** ret) -{ - _cleanup_hwdb_unref_ sd_hwdb *hwdb = NULL; - const char *hwdb_bin_path; - const char sig[] = HWDB_SIG; - - assert_return(ret, -EINVAL); - - hwdb = new0(sd_hwdb, 1); - if (!hwdb) - return -ENOMEM; - - hwdb->n_ref = REFCNT_INIT; - - /* find hwdb.bin in hwdb_bin_paths */ - NULSTR_FOREACH(hwdb_bin_path, hwdb_bin_paths) { - hwdb->f = fopen(hwdb_bin_path, "re"); - if (hwdb->f) { - break; - } else if (errno == ENOENT) { - continue; - } else { - - int errsv = -errno; - log_debug("error reading %s: %s", hwdb_bin_path, - strerror(errsv)); - return errsv; - } + child = node_lookup_f (hwdb, node, '*'); + if (child) + { + linebuf_add_char (&buf, '*'); + err = trie_fnmatch_f (hwdb, child, 0, &buf, search + i); + if (err < 0) + return err; + linebuf_rem_char (&buf); } - if (!hwdb->f) { - log_debug("%s", - "hwdb.bin does not exist, please run udevadm hwdb --update"); - return -ENOENT; + child = node_lookup_f (hwdb, node, '?'); + if (child) + { + linebuf_add_char (&buf, '?'); + err = trie_fnmatch_f (hwdb, child, 0, &buf, search + i); + if (err < 0) + return err; + linebuf_rem_char (&buf); } - if (fstat(fileno(hwdb->f), &hwdb->st) < 0 || - (size_t) hwdb->st.st_size < offsetof(struct trie_header_f, - strings_len) + 8) { - - int errsv = errno; - log_debug("error reading %s: %s", hwdb_bin_path, - strerror(errsv)); - return errsv; + child = node_lookup_f (hwdb, node, '['); + if (child) + { + linebuf_add_char (&buf, '['); + err = trie_fnmatch_f (hwdb, child, 0, &buf, search + i); + if (err < 0) + return err; + linebuf_rem_char (&buf); } - hwdb->map = - mmap(0, hwdb->st.st_size, PROT_READ, MAP_SHARED, fileno(hwdb->f), - 0); - if (hwdb->map == MAP_FAILED) { - - int errsv = errno; - log_debug("error mapping %s: %s", hwdb_bin_path, - strerror(errsv)); - return errsv; + if (search[i] == '\0') + { + size_t n; + + for (n = 0; n < le64toh (node->values_count); n++) + { + err = + hwdb_add_property (hwdb, + trie_string (hwdb, + trie_node_values + (hwdb, + node)[n].key_off), + trie_string (hwdb, + trie_node_values + (hwdb, node)[n].value_off)); + if (err < 0) + return err; + } + return 0; } - if (memcmp(hwdb->map, sig, sizeof(hwdb->head->signature)) != 0 || - (size_t) hwdb->st.st_size != le64toh(hwdb->head->file_size)) { - log_debug("error recognizing the format of %s", hwdb_bin_path); - return -EINVAL;; - } + child = node_lookup_f (hwdb, node, search[i]); + node = child; + i++; + } + return 0; +} - log_debug("%s\n", "=== trie on-disk ==="); - log_debug("tool version: %" PRIu64, - le64toh(hwdb->head->tool_version)); - log_debug("file size: %8" PRIi64 " bytes", hwdb->st.st_size); - log_debug("header size %8" PRIu64 " bytes", - le64toh(hwdb->head->header_size)); - log_debug("strings %8" PRIu64 " bytes", - le64toh(hwdb->head->strings_len)); - log_debug("nodes %8" PRIu64 " bytes", - le64toh(hwdb->head->nodes_len)); - - *ret = hwdb; - hwdb = NULL; - - return 0; +static const char hwdb_bin_paths[] = + "/etc/systemd/hwdb/hwdb.bin\0" + "/etc/udev/hwdb.bin\0" "/usr/lib/systemd/hwdb/hwdb.bin\0" +#ifdef HAVE_SPLIT_USR + "/lib/systemd/hwdb/hwdb.bin\0" +#endif + "/lib/systemd/hwdb.bin\0"; + +_public_ int +sd_hwdb_new (sd_hwdb ** ret) +{ + _cleanup_hwdb_unref_ sd_hwdb *hwdb = NULL; + const char *hwdb_bin_path; + const char sig[] = HWDB_SIG; + + assert_return (ret, -EINVAL); + + hwdb = new0 (sd_hwdb, 1); + if (!hwdb) + return -ENOMEM; + + hwdb->n_ref = REFCNT_INIT; + + /* find hwdb.bin in hwdb_bin_paths */ + NULSTR_FOREACH (hwdb_bin_path, hwdb_bin_paths) + { + hwdb->f = fopen (hwdb_bin_path, "re"); + if (hwdb->f) + { + break; + } + else if (errno == ENOENT) + { + continue; + } + else + { + + int errsv = -errno; + log_debug ("error reading %s: %s", hwdb_bin_path, strerror (errsv)); + return errsv; + } + } + + if (!hwdb->f) + { + log_debug ("%s", + "hwdb.bin does not exist, please run udevadm hwdb --update"); + return -ENOENT; + } + + if (fstat (fileno (hwdb->f), &hwdb->st) < 0 || + (size_t) hwdb->st.st_size < offsetof (struct trie_header_f, + strings_len) + 8) + { + + int errsv = errno; + log_debug ("error reading %s: %s", hwdb_bin_path, strerror (errsv)); + return errsv; + } + + hwdb->map = + mmap (0, hwdb->st.st_size, PROT_READ, MAP_SHARED, fileno (hwdb->f), 0); + if (hwdb->map == MAP_FAILED) + { + + int errsv = errno; + log_debug ("error mapping %s: %s", hwdb_bin_path, strerror (errsv)); + return errsv; + } + + if (memcmp (hwdb->map, sig, sizeof (hwdb->head->signature)) != 0 || + (size_t) hwdb->st.st_size != le64toh (hwdb->head->file_size)) + { + log_debug ("error recognizing the format of %s", hwdb_bin_path); + return -EINVAL;; + } + + log_debug ("%s\n", "=== trie on-disk ==="); + log_debug ("tool version: %" PRIu64, + le64toh (hwdb->head->tool_version)); + log_debug ("file size: %8" PRIi64 " bytes", hwdb->st.st_size); + log_debug ("header size %8" PRIu64 " bytes", + le64toh (hwdb->head->header_size)); + log_debug ("strings %8" PRIu64 " bytes", + le64toh (hwdb->head->strings_len)); + log_debug ("nodes %8" PRIu64 " bytes", + le64toh (hwdb->head->nodes_len)); + + *ret = hwdb; + hwdb = NULL; + + return 0; } -_public_ sd_hwdb *sd_hwdb_ref(sd_hwdb * hwdb) +_public_ sd_hwdb * +sd_hwdb_ref (sd_hwdb * hwdb) { - assert_return(hwdb, NULL); + assert_return (hwdb, NULL); - assert_se(REFCNT_INC(hwdb->n_ref) >= 2); + assert_se (REFCNT_INC (hwdb->n_ref) >= 2); - return hwdb; + return hwdb; } -_public_ sd_hwdb *sd_hwdb_unref(sd_hwdb * hwdb) +_public_ sd_hwdb * +sd_hwdb_unref (sd_hwdb * hwdb) { - if (hwdb && REFCNT_DEC(hwdb->n_ref) == 0) { - if (hwdb->map) - munmap((void *)hwdb->map, hwdb->st.st_size); - if (hwdb->f) - fclose(hwdb->f); - free(hwdb->modalias); - ordered_hashmap_free(hwdb->properties); - free(hwdb); - } - - return NULL; + if (hwdb && REFCNT_DEC (hwdb->n_ref) == 0) + { + if (hwdb->map) + munmap ((void *) hwdb->map, hwdb->st.st_size); + if (hwdb->f) + fclose (hwdb->f); + free (hwdb->modalias); + ordered_hashmap_free (hwdb->properties); + free (hwdb); + } + + return NULL; } -bool hwdb_validate(sd_hwdb * hwdb) +bool +hwdb_validate (sd_hwdb * hwdb) { - bool found = false; - const char *p; - struct stat st; - - if (!hwdb) - return false; - if (!hwdb->f) - return false; - - /* if hwdb.bin doesn't exist anywhere, we need to update */ - NULSTR_FOREACH(p, hwdb_bin_paths) { - if (stat(p, &st) >= 0) { - found = true; - break; - } - } - if (!found) - return true; - - if (timespec_load(&hwdb->st.st_mtim) != timespec_load(&st.st_mtim)) - return true; - return false; + bool found = false; + const char *p; + struct stat st; + + if (!hwdb) + return false; + if (!hwdb->f) + return false; + + /* if hwdb.bin doesn't exist anywhere, we need to update */ + NULSTR_FOREACH (p, hwdb_bin_paths) + { + if (stat (p, &st) >= 0) + { + found = true; + break; + } + } + if (!found) + return true; + + if (timespec_load (&hwdb->st.st_mtim) != timespec_load (&st.st_mtim)) + return true; + return false; } -static int properties_prepare(sd_hwdb * hwdb, const char *modalias) +static int +properties_prepare (sd_hwdb * hwdb, const char *modalias) { - char *mod = NULL; - int r; + char *mod = NULL; + int r; - assert(hwdb); - assert(modalias); + assert (hwdb); + assert (modalias); - if (streq_ptr(modalias, hwdb->modalias)) - return 0; + if (streq_ptr (modalias, hwdb->modalias)) + return 0; - mod = strdup(modalias); - if (!mod) - return -ENOMEM; + mod = strdup (modalias); + if (!mod) + return -ENOMEM; - ordered_hashmap_clear(hwdb->properties); + ordered_hashmap_clear (hwdb->properties); - hwdb->properties_modified = true; + hwdb->properties_modified = true; - r = trie_search_f(hwdb, modalias); - if (r < 0) - return r; + r = trie_search_f (hwdb, modalias); + if (r < 0) + return r; - free(hwdb->modalias); - hwdb->modalias = mod; - mod = NULL; + free (hwdb->modalias); + hwdb->modalias = mod; + mod = NULL; - return 0; + return 0; } -_public_ int sd_hwdb_get(sd_hwdb * hwdb, const char *modalias, const char *key, - const char **_value) +_public_ int +sd_hwdb_get (sd_hwdb * hwdb, const char *modalias, const char *key, + const char **_value) { - const char *value; - int r; + const char *value; + int r; - assert_return(hwdb, -EINVAL); - assert_return(hwdb->f, -EINVAL); - assert_return(modalias, -EINVAL); - assert_return(_value, -EINVAL); + assert_return (hwdb, -EINVAL); + assert_return (hwdb->f, -EINVAL); + assert_return (modalias, -EINVAL); + assert_return (_value, -EINVAL); - r = properties_prepare(hwdb, modalias); - if (r < 0) - return r; + r = properties_prepare (hwdb, modalias); + if (r < 0) + return r; - value = ordered_hashmap_get(hwdb->properties, key); - if (!value) - return -ENOENT; + value = ordered_hashmap_get (hwdb->properties, key); + if (!value) + return -ENOENT; - *_value = value; + *_value = value; - return 0; + return 0; } -_public_ int sd_hwdb_seek(sd_hwdb * hwdb, const char *modalias) +_public_ int +sd_hwdb_seek (sd_hwdb * hwdb, const char *modalias) { - int r; + int r; - assert_return(hwdb, -EINVAL); - assert_return(hwdb->f, -EINVAL); - assert_return(modalias, -EINVAL); + assert_return (hwdb, -EINVAL); + assert_return (hwdb->f, -EINVAL); + assert_return (modalias, -EINVAL); - r = properties_prepare(hwdb, modalias); - if (r < 0) - return r; + r = properties_prepare (hwdb, modalias); + if (r < 0) + return r; - hwdb->properties_modified = false; - hwdb->properties_iterator = ITERATOR_FIRST; + hwdb->properties_modified = false; + hwdb->properties_iterator = ITERATOR_FIRST; - return 0; + return 0; } -_public_ int sd_hwdb_enumerate(sd_hwdb * hwdb, const char **key, - const char **value) +_public_ int +sd_hwdb_enumerate (sd_hwdb * hwdb, const char **key, const char **value) { - const void *k, *v; + const void *k, *v; - assert_return(hwdb, -EINVAL); - assert_return(key, -EINVAL); - assert_return(value, -EINVAL); + assert_return (hwdb, -EINVAL); + assert_return (key, -EINVAL); + assert_return (value, -EINVAL); - if (hwdb->properties_modified) - return -EAGAIN; + if (hwdb->properties_modified) + return -EAGAIN; - v = ordered_hashmap_iterate(hwdb->properties, - &hwdb->properties_iterator, &k); - if (!k) - return 0; + v = ordered_hashmap_iterate (hwdb->properties, + &hwdb->properties_iterator, &k); + if (!k) + return 0; - *key = k; - *value = v; + *key = k; + *value = v; - return 1; + return 1; } diff --git a/libudev-compat/sd-hwdb.h b/libudev-compat/sd-hwdb.h index 8ed1401..a967f0e 100644 --- a/libudev-compat/sd-hwdb.h +++ b/libudev-compat/sd-hwdb.h @@ -34,16 +34,16 @@ typedef struct sd_hwdb sd_hwdb; -sd_hwdb *sd_hwdb_ref(sd_hwdb * hwdb); -sd_hwdb *sd_hwdb_unref(sd_hwdb * hwdb); +sd_hwdb *sd_hwdb_ref (sd_hwdb * hwdb); +sd_hwdb *sd_hwdb_unref (sd_hwdb * hwdb); -int sd_hwdb_new(sd_hwdb ** ret); +int sd_hwdb_new (sd_hwdb ** ret); -int sd_hwdb_get(sd_hwdb * hwdb, const char *modalias, const char *key, - const char **value); +int sd_hwdb_get (sd_hwdb * hwdb, const char *modalias, const char *key, + const char **value); -int sd_hwdb_seek(sd_hwdb * hwdb, const char *modalias); -int sd_hwdb_enumerate(sd_hwdb * hwdb, const char **key, const char **value); +int sd_hwdb_seek (sd_hwdb * hwdb, const char *modalias); +int sd_hwdb_enumerate (sd_hwdb * hwdb, const char **key, const char **value); /* the inverse condition avoids ambiguity of danling 'else' after the macro */ #define SD_HWDB_FOREACH_PROPERTY(hwdb, modalias, key, value) \ diff --git a/libudev-compat/set.h b/libudev-compat/set.h index 75d0c43..9c70bd2 100644 --- a/libudev-compat/set.h +++ b/libudev-compat/set.h @@ -28,131 +28,148 @@ #include "hashmap.h" -Set *internal_set_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS); +Set *internal_set_new (const struct hash_ops * hash_ops HASHMAP_DEBUG_PARAMS); #define set_new(ops) internal_set_new(ops HASHMAP_DEBUG_SRC_ARGS) -static inline void set_free(Set * s) +static inline void +set_free (Set * s) { - internal_hashmap_free(HASHMAP_BASE(s)); + internal_hashmap_free (HASHMAP_BASE (s)); } -static inline void set_free_free(Set * s) +static inline void +set_free_free (Set * s) { - internal_hashmap_free_free(HASHMAP_BASE(s)); + internal_hashmap_free_free (HASHMAP_BASE (s)); } /* no set_free_free_free */ -static inline Set *set_copy(Set * s) +static inline Set * +set_copy (Set * s) { - return (Set *) internal_hashmap_copy(HASHMAP_BASE(s)); + return (Set *) internal_hashmap_copy (HASHMAP_BASE (s)); } -int internal_set_ensure_allocated(Set ** s, - const struct hash_ops *hash_ops - HASHMAP_DEBUG_PARAMS); +int internal_set_ensure_allocated (Set ** s, + const struct hash_ops *hash_ops + HASHMAP_DEBUG_PARAMS); #define set_ensure_allocated(h, ops) internal_set_ensure_allocated(h, ops HASHMAP_DEBUG_SRC_ARGS) -int set_put(Set * s, const void *key); +int set_put (Set * s, const void *key); /* no set_update */ /* no set_replace */ -static inline void *set_get(Set * s, void *key) +static inline void * +set_get (Set * s, void *key) { - return internal_hashmap_get(HASHMAP_BASE(s), key); + return internal_hashmap_get (HASHMAP_BASE (s), key); } /* no set_get2 */ -static inline bool set_contains(Set * s, const void *key) +static inline bool +set_contains (Set * s, const void *key) { - return internal_hashmap_contains(HASHMAP_BASE(s), key); + return internal_hashmap_contains (HASHMAP_BASE (s), key); } -static inline void *set_remove(Set * s, void *key) +static inline void * +set_remove (Set * s, void *key) { - return internal_hashmap_remove(HASHMAP_BASE(s), key); + return internal_hashmap_remove (HASHMAP_BASE (s), key); } /* no set_remove2 */ /* no set_remove_value */ -int set_remove_and_put(Set * s, const void *old_key, const void *new_key); +int set_remove_and_put (Set * s, const void *old_key, const void *new_key); /* no set_remove_and_replace */ -int set_merge(Set * s, Set * other); +int set_merge (Set * s, Set * other); -static inline int set_reserve(Set * h, unsigned entries_add) +static inline int +set_reserve (Set * h, unsigned entries_add) { - return internal_hashmap_reserve(HASHMAP_BASE(h), entries_add); + return internal_hashmap_reserve (HASHMAP_BASE (h), entries_add); } -static inline int set_move(Set * s, Set * other) +static inline int +set_move (Set * s, Set * other) { - return internal_hashmap_move(HASHMAP_BASE(s), HASHMAP_BASE(other)); + return internal_hashmap_move (HASHMAP_BASE (s), HASHMAP_BASE (other)); } -static inline int set_move_one(Set * s, Set * other, const void *key) +static inline int +set_move_one (Set * s, Set * other, const void *key) { - return internal_hashmap_move_one(HASHMAP_BASE(s), HASHMAP_BASE(other), - key); + return internal_hashmap_move_one (HASHMAP_BASE (s), HASHMAP_BASE (other), + key); } -static inline unsigned set_size(Set * s) +static inline unsigned +set_size (Set * s) { - return internal_hashmap_size(HASHMAP_BASE(s)); + return internal_hashmap_size (HASHMAP_BASE (s)); } -static inline bool set_isempty(Set * s) +static inline bool +set_isempty (Set * s) { - return set_size(s) == 0; + return set_size (s) == 0; } -static inline unsigned set_buckets(Set * s) +static inline unsigned +set_buckets (Set * s) { - return internal_hashmap_buckets(HASHMAP_BASE(s)); + return internal_hashmap_buckets (HASHMAP_BASE (s)); } -void *set_iterate(Set * s, Iterator * i); +void *set_iterate (Set * s, Iterator * i); -static inline void set_clear(Set * s) +static inline void +set_clear (Set * s) { - internal_hashmap_clear(HASHMAP_BASE(s)); + internal_hashmap_clear (HASHMAP_BASE (s)); } -static inline void set_clear_free(Set * s) +static inline void +set_clear_free (Set * s) { - internal_hashmap_clear_free(HASHMAP_BASE(s)); + internal_hashmap_clear_free (HASHMAP_BASE (s)); } /* no set_clear_free_free */ -static inline void *set_steal_first(Set * s) +static inline void * +set_steal_first (Set * s) { - return internal_hashmap_steal_first(HASHMAP_BASE(s)); + return internal_hashmap_steal_first (HASHMAP_BASE (s)); } /* no set_steal_first_key */ /* no set_first_key */ -static inline void *set_first(Set * s) +static inline void * +set_first (Set * s) { - return internal_hashmap_first(HASHMAP_BASE(s)); + return internal_hashmap_first (HASHMAP_BASE (s)); } /* no set_next */ -static inline char **set_get_strv(Set * s) +static inline char ** +set_get_strv (Set * s) { - return internal_hashmap_get_strv(HASHMAP_BASE(s)); + return internal_hashmap_get_strv (HASHMAP_BASE (s)); } -int set_consume(Set * s, void *value); -int set_put_strdup(Set * s, const char *p); -int set_put_strdupv(Set * s, char **l); +int set_consume (Set * s, void *value); +int set_put_strdup (Set * s, const char *p); +int set_put_strdupv (Set * s, char **l); #define SET_FOREACH(e, s, i) \ for ((i) = ITERATOR_FIRST, (e) = set_iterate((s), &(i)); (e); (e) = set_iterate((s), &(i))) -DEFINE_TRIVIAL_CLEANUP_FUNC(Set *, set_free); -DEFINE_TRIVIAL_CLEANUP_FUNC(Set *, set_free_free); +DEFINE_TRIVIAL_CLEANUP_FUNC (Set *, set_free); +DEFINE_TRIVIAL_CLEANUP_FUNC (Set *, set_free_free); #define _cleanup_set_free_ _cleanup_(set_freep) #define _cleanup_set_free_free_ _cleanup_(set_free_freep) diff --git a/libudev-compat/siphash24.c b/libudev-compat/siphash24.c index 8543c79..29bf033 100644 --- a/libudev-compat/siphash24.c +++ b/libudev-compat/siphash24.c @@ -58,97 +58,99 @@ typedef uint8_t u8; } while(0) /* SipHash-2-4 */ -void siphash24(uint8_t out[8], const void *_in, size_t inlen, - const uint8_t k[16]) +void +siphash24 (uint8_t out[8], const void *_in, size_t inlen, const uint8_t k[16]) { - /* "somepseudorandomlygeneratedbytes" */ - u64 v0 = 0x736f6d6570736575ULL; - u64 v1 = 0x646f72616e646f6dULL; - u64 v2 = 0x6c7967656e657261ULL; - u64 v3 = 0x7465646279746573ULL; - u64 b; - u64 k0 = U8TO64_LE(k); - u64 k1 = U8TO64_LE(k + 8); - u64 m; - const u8 *in = _in; - const u8 *end = in + inlen - (inlen % sizeof(u64)); - const int left = inlen & 7; - b = ((u64) inlen) << 56; - v3 ^= k1; - v2 ^= k0; - v1 ^= k1; - v0 ^= k0; - - for (; in != end; in += 8) { - m = U8TO64_LE(in); + /* "somepseudorandomlygeneratedbytes" */ + u64 v0 = 0x736f6d6570736575ULL; + u64 v1 = 0x646f72616e646f6dULL; + u64 v2 = 0x6c7967656e657261ULL; + u64 v3 = 0x7465646279746573ULL; + u64 b; + u64 k0 = U8TO64_LE (k); + u64 k1 = U8TO64_LE (k + 8); + u64 m; + const u8 *in = _in; + const u8 *end = in + inlen - (inlen % sizeof (u64)); + const int left = inlen & 7; + b = ((u64) inlen) << 56; + v3 ^= k1; + v2 ^= k0; + v1 ^= k1; + v0 ^= k0; + + for (; in != end; in += 8) + { + m = U8TO64_LE (in); #ifdef DEBUG - printf("(%3d) v0 %08x %08x\n", (int)inlen, (u32) (v0 >> 32), - (u32) v0); - printf("(%3d) v1 %08x %08x\n", (int)inlen, (u32) (v1 >> 32), - (u32) v1); - printf("(%3d) v2 %08x %08x\n", (int)inlen, (u32) (v2 >> 32), - (u32) v2); - printf("(%3d) v3 %08x %08x\n", (int)inlen, (u32) (v3 >> 32), - (u32) v3); - printf("(%3d) compress %08x %08x\n", (int)inlen, - (u32) (m >> 32), (u32) m); + printf ("(%3d) v0 %08x %08x\n", (int) inlen, (u32) (v0 >> 32), + (u32) v0); + printf ("(%3d) v1 %08x %08x\n", (int) inlen, (u32) (v1 >> 32), + (u32) v1); + printf ("(%3d) v2 %08x %08x\n", (int) inlen, (u32) (v2 >> 32), + (u32) v2); + printf ("(%3d) v3 %08x %08x\n", (int) inlen, (u32) (v3 >> 32), + (u32) v3); + printf ("(%3d) compress %08x %08x\n", (int) inlen, + (u32) (m >> 32), (u32) m); #endif - v3 ^= m; - SIPROUND; - SIPROUND; - v0 ^= m; - } + v3 ^= m; + SIPROUND; + SIPROUND; + v0 ^= m; + } - switch (left) { - case 7: - b |= ((u64) in[6]) << 48; + switch (left) + { + case 7: + b |= ((u64) in[6]) << 48; - case 6: - b |= ((u64) in[5]) << 40; + case 6: + b |= ((u64) in[5]) << 40; - case 5: - b |= ((u64) in[4]) << 32; + case 5: + b |= ((u64) in[4]) << 32; - case 4: - b |= ((u64) in[3]) << 24; + case 4: + b |= ((u64) in[3]) << 24; - case 3: - b |= ((u64) in[2]) << 16; + case 3: + b |= ((u64) in[2]) << 16; - case 2: - b |= ((u64) in[1]) << 8; + case 2: + b |= ((u64) in[1]) << 8; - case 1: - b |= ((u64) in[0]); - break; + case 1: + b |= ((u64) in[0]); + break; - case 0: - break; - } + case 0: + break; + } #ifdef DEBUG - printf("(%3d) v0 %08x %08x\n", (int)inlen, (u32) (v0 >> 32), (u32) v0); - printf("(%3d) v1 %08x %08x\n", (int)inlen, (u32) (v1 >> 32), (u32) v1); - printf("(%3d) v2 %08x %08x\n", (int)inlen, (u32) (v2 >> 32), (u32) v2); - printf("(%3d) v3 %08x %08x\n", (int)inlen, (u32) (v3 >> 32), (u32) v3); - printf("(%3d) padding %08x %08x\n", (int)inlen, (u32) (b >> 32), - (u32) b); + printf ("(%3d) v0 %08x %08x\n", (int) inlen, (u32) (v0 >> 32), (u32) v0); + printf ("(%3d) v1 %08x %08x\n", (int) inlen, (u32) (v1 >> 32), (u32) v1); + printf ("(%3d) v2 %08x %08x\n", (int) inlen, (u32) (v2 >> 32), (u32) v2); + printf ("(%3d) v3 %08x %08x\n", (int) inlen, (u32) (v3 >> 32), (u32) v3); + printf ("(%3d) padding %08x %08x\n", (int) inlen, (u32) (b >> 32), + (u32) b); #endif - v3 ^= b; - SIPROUND; - SIPROUND; - v0 ^= b; + v3 ^= b; + SIPROUND; + SIPROUND; + v0 ^= b; #ifdef DEBUG - printf("(%3d) v0 %08x %08x\n", (int)inlen, (u32) (v0 >> 32), (u32) v0); - printf("(%3d) v1 %08x %08x\n", (int)inlen, (u32) (v1 >> 32), (u32) v1); - printf("(%3d) v2 %08x %08x\n", (int)inlen, (u32) (v2 >> 32), (u32) v2); - printf("(%3d) v3 %08x %08x\n", (int)inlen, (u32) (v3 >> 32), (u32) v3); + printf ("(%3d) v0 %08x %08x\n", (int) inlen, (u32) (v0 >> 32), (u32) v0); + printf ("(%3d) v1 %08x %08x\n", (int) inlen, (u32) (v1 >> 32), (u32) v1); + printf ("(%3d) v2 %08x %08x\n", (int) inlen, (u32) (v2 >> 32), (u32) v2); + printf ("(%3d) v3 %08x %08x\n", (int) inlen, (u32) (v3 >> 32), (u32) v3); #endif - v2 ^= 0xff; - SIPROUND; - SIPROUND; - SIPROUND; - SIPROUND; - b = v0 ^ v1 ^ v2 ^ v3; - U64TO8_LE(out, b); + v2 ^= 0xff; + SIPROUND; + SIPROUND; + SIPROUND; + SIPROUND; + b = v0 ^ v1 ^ v2 ^ v3; + U64TO8_LE (out, b); } diff --git a/libudev-compat/siphash24.h b/libudev-compat/siphash24.h index ea6662e..888cded 100644 --- a/libudev-compat/siphash24.h +++ b/libudev-compat/siphash24.h @@ -12,7 +12,7 @@ #include #include -void siphash24(uint8_t out[8], const void *in, size_t inlen, - const uint8_t k[16]); +void siphash24 (uint8_t out[8], const void *in, size_t inlen, + const uint8_t k[16]); #endif diff --git a/libudev-compat/sparse-endian.h b/libudev-compat/sparse-endian.h index 7893b9c..8ace142 100644 --- a/libudev-compat/sparse-endian.h +++ b/libudev-compat/sparse-endian.h @@ -78,64 +78,76 @@ typedef uint64_t __bitwise be64_t; #define bswap_64_on_be(x) __bswap_64(x) #endif -static inline le16_t htole16(uint16_t value) +static inline le16_t +htole16 (uint16_t value) { - return (le16_t __force) bswap_16_on_be(value); + return (le16_t __force) bswap_16_on_be (value); } -static inline le32_t htole32(uint32_t value) +static inline le32_t +htole32 (uint32_t value) { - return (le32_t __force) bswap_32_on_be(value); + return (le32_t __force) bswap_32_on_be (value); } -static inline le64_t htole64(uint64_t value) +static inline le64_t +htole64 (uint64_t value) { - return (le64_t __force) bswap_64_on_be(value); + return (le64_t __force) bswap_64_on_be (value); } -static inline be16_t htobe16(uint16_t value) +static inline be16_t +htobe16 (uint16_t value) { - return (be16_t __force) bswap_16_on_le(value); + return (be16_t __force) bswap_16_on_le (value); } -static inline be32_t htobe32(uint32_t value) +static inline be32_t +htobe32 (uint32_t value) { - return (be32_t __force) bswap_32_on_le(value); + return (be32_t __force) bswap_32_on_le (value); } -static inline be64_t htobe64(uint64_t value) +static inline be64_t +htobe64 (uint64_t value) { - return (be64_t __force) bswap_64_on_le(value); + return (be64_t __force) bswap_64_on_le (value); } -static inline uint16_t le16toh(le16_t value) +static inline uint16_t +le16toh (le16_t value) { - return bswap_16_on_be((uint16_t __force) value); + return bswap_16_on_be ((uint16_t __force) value); } -static inline uint32_t le32toh(le32_t value) +static inline uint32_t +le32toh (le32_t value) { - return bswap_32_on_be((uint32_t __force) value); + return bswap_32_on_be ((uint32_t __force) value); } -static inline uint64_t le64toh(le64_t value) +static inline uint64_t +le64toh (le64_t value) { - return bswap_64_on_be((uint64_t __force) value); + return bswap_64_on_be ((uint64_t __force) value); } -static inline uint16_t be16toh(be16_t value) +static inline uint16_t +be16toh (be16_t value) { - return bswap_16_on_le((uint16_t __force) value); + return bswap_16_on_le ((uint16_t __force) value); } -static inline uint32_t be32toh(be32_t value) +static inline uint32_t +be32toh (be32_t value) { - return bswap_32_on_le((uint32_t __force) value); + return bswap_32_on_le ((uint32_t __force) value); } -static inline uint64_t be64toh(be64_t value) +static inline uint64_t +be64toh (be64_t value) { - return bswap_64_on_le((uint64_t __force) value); + return bswap_64_on_le ((uint64_t __force) value); } -#endif /* SPARSE_ENDIAN_H */ +#endif /* SPARSE_ENDIAN_H */ diff --git a/libudev-compat/strxcpyx.c b/libudev-compat/strxcpyx.c index 6e62a18..9fee918 100644 --- a/libudev-compat/strxcpyx.c +++ b/libudev-compat/strxcpyx.c @@ -36,77 +36,93 @@ #include #include "strxcpyx.h" -size_t strpcpy(char **dest, size_t size, const char *src) +size_t +strpcpy (char **dest, size_t size, const char *src) { - size_t len; - - len = strlen(src); - if (len >= size) { - if (size > 1) - *dest = mempcpy(*dest, src, size - 1); - size = 0; - } else { - if (len > 0) { - *dest = mempcpy(*dest, src, len); - size -= len; - } + size_t len; + + len = strlen (src); + if (len >= size) + { + if (size > 1) + *dest = mempcpy (*dest, src, size - 1); + size = 0; + } + else + { + if (len > 0) + { + *dest = mempcpy (*dest, src, len); + size -= len; } - *dest[0] = '\0'; - return size; + } + *dest[0] = '\0'; + return size; } -size_t strpcpyf(char **dest, size_t size, const char *src, ...) +size_t +strpcpyf (char **dest, size_t size, const char *src, ...) { - va_list va; - int i; - - va_start(va, src); - i = vsnprintf(*dest, size, src, va); - if (i < (int)size) { - *dest += i; - size -= i; - } else { - *dest += size; - size = 0; - } - va_end(va); - *dest[0] = '\0'; - return size; + va_list va; + int i; + + va_start (va, src); + i = vsnprintf (*dest, size, src, va); + if (i < (int) size) + { + *dest += i; + size -= i; + } + else + { + *dest += size; + size = 0; + } + va_end (va); + *dest[0] = '\0'; + return size; } -size_t strpcpyl(char **dest, size_t size, const char *src, ...) +size_t +strpcpyl (char **dest, size_t size, const char *src, ...) { - va_list va; - - va_start(va, src); - do { - size = strpcpy(dest, size, src); - src = va_arg(va, char *); - } while (src != NULL); - va_end(va); - return size; + va_list va; + + va_start (va, src); + do + { + size = strpcpy (dest, size, src); + src = va_arg (va, char *); + } + while (src != NULL); + va_end (va); + return size; } -size_t strscpy(char *dest, size_t size, const char *src) +size_t +strscpy (char *dest, size_t size, const char *src) { - char *s; + char *s; - s = dest; - return strpcpy(&s, size, src); + s = dest; + return strpcpy (&s, size, src); } -size_t strscpyl(char *dest, size_t size, const char *src, ...) +size_t +strscpyl (char *dest, size_t size, const char *src, ...) { - va_list va; - char *s; - - va_start(va, src); - s = dest; - do { - size = strpcpy(&s, size, src); - src = va_arg(va, char *); - } while (src != NULL); - va_end(va); - - return size; + va_list va; + char *s; + + va_start (va, src); + s = dest; + do + { + size = strpcpy (&s, size, src); + src = va_arg (va, char *); + } + while (src != NULL); + va_end (va); + + return size; } diff --git a/libudev-compat/strxcpyx.h b/libudev-compat/strxcpyx.h index fe115ff..db496e4 100644 --- a/libudev-compat/strxcpyx.h +++ b/libudev-compat/strxcpyx.h @@ -35,10 +35,14 @@ // #include "macro.h" #include "util.h" -size_t strpcpy(char **dest, size_t size, const char *src); -size_t strpcpyf(char **dest, size_t size, const char *src, ...) _printf_(3, 4); -size_t strpcpyl(char **dest, size_t size, const char *src, ...) _sentinel_; -size_t strscpy(char *dest, size_t size, const char *src); -size_t strscpyl(char *dest, size_t size, const char *src, ...) _sentinel_; +size_t strpcpy (char **dest, size_t size, const char *src); +size_t +strpcpyf (char **dest, size_t size, const char *src, ...) +_printf_ (3, 4); + size_t strpcpyl (char **dest, size_t size, const char *src, + ...) _sentinel_; + size_t strscpy (char *dest, size_t size, const char *src); + size_t strscpyl (char *dest, size_t size, const char *src, + ...) _sentinel_; #endif diff --git a/libudev-compat/utf8.c b/libudev-compat/utf8.c index 42ef2ae..3d4df40 100644 --- a/libudev-compat/utf8.c +++ b/libudev-compat/utf8.c @@ -59,222 +59,245 @@ #include "utf8.h" #include "util.h" -static inline bool is_unicode_valid(uint32_t ch) +static inline bool +is_unicode_valid (uint32_t ch) { - if (ch >= 0x110000) /* End of unicode space */ - return false; - if ((ch & 0xFFFFF800) == 0xD800) /* Reserved area for UTF-16 */ - return false; - if ((ch >= 0xFDD0) && (ch <= 0xFDEF)) /* Reserved */ - return false; - if ((ch & 0xFFFE) == 0xFFFE) /* BOM (Byte Order Mark) */ - return false; + if (ch >= 0x110000) /* End of unicode space */ + return false; + if ((ch & 0xFFFFF800) == 0xD800) /* Reserved area for UTF-16 */ + return false; + if ((ch >= 0xFDD0) && (ch <= 0xFDEF)) /* Reserved */ + return false; + if ((ch & 0xFFFE) == 0xFFFE) /* BOM (Byte Order Mark) */ + return false; - return true; + return true; } -static bool is_unicode_control(uint32_t ch) +static bool +is_unicode_control (uint32_t ch) { - /* - 0 to ' '-1 is the C0 range. - DEL=0x7F, and DEL+1 to 0x9F is C1 range. - '\t' is in C0 range, but more or less harmless and commonly used. - */ + /* + 0 to ' '-1 is the C0 range. + DEL=0x7F, and DEL+1 to 0x9F is C1 range. + '\t' is in C0 range, but more or less harmless and commonly used. + */ - return (ch < ' ' && ch != '\t' && ch != '\n') || - (0x7F <= ch && ch <= 0x9F); + return (ch < ' ' && ch != '\t' && ch != '\n') || (0x7F <= ch && ch <= 0x9F); } /* count of characters used to encode one unicode char */ -static int utf8_encoded_expected_len(const char *str) +static int +utf8_encoded_expected_len (const char *str) { - unsigned char c; - - assert(str); - - c = (unsigned char)str[0]; - if (c < 0x80) - return 1; - if ((c & 0xe0) == 0xc0) - return 2; - if ((c & 0xf0) == 0xe0) - return 3; - if ((c & 0xf8) == 0xf0) - return 4; - if ((c & 0xfc) == 0xf8) - return 5; - if ((c & 0xfe) == 0xfc) - return 6; - - return 0; + unsigned char c; + + assert (str); + + c = (unsigned char) str[0]; + if (c < 0x80) + return 1; + if ((c & 0xe0) == 0xc0) + return 2; + if ((c & 0xf0) == 0xe0) + return 3; + if ((c & 0xf8) == 0xf0) + return 4; + if ((c & 0xfc) == 0xf8) + return 5; + if ((c & 0xfe) == 0xfc) + return 6; + + return 0; } /* decode one unicode char */ -int utf8_encoded_to_unichar(const char *str) +int +utf8_encoded_to_unichar (const char *str) { - int unichar, len, i; - - assert(str); - - len = utf8_encoded_expected_len(str); - - switch (len) { - case 1: - return (int)str[0]; - case 2: - unichar = str[0] & 0x1f; - break; - case 3: - unichar = (int)str[0] & 0x0f; - break; - case 4: - unichar = (int)str[0] & 0x07; - break; - case 5: - unichar = (int)str[0] & 0x03; - break; - case 6: - unichar = (int)str[0] & 0x01; - break; - default: - return -EINVAL; - } - - for (i = 1; i < len; i++) { - if (((int)str[i] & 0xc0) != 0x80) - return -EINVAL; - unichar <<= 6; - unichar |= (int)str[i] & 0x3f; - } - - return unichar; + int unichar, len, i; + + assert (str); + + len = utf8_encoded_expected_len (str); + + switch (len) + { + case 1: + return (int) str[0]; + case 2: + unichar = str[0] & 0x1f; + break; + case 3: + unichar = (int) str[0] & 0x0f; + break; + case 4: + unichar = (int) str[0] & 0x07; + break; + case 5: + unichar = (int) str[0] & 0x03; + break; + case 6: + unichar = (int) str[0] & 0x01; + break; + default: + return -EINVAL; + } + + for (i = 1; i < len; i++) + { + if (((int) str[i] & 0xc0) != 0x80) + return -EINVAL; + unichar <<= 6; + unichar |= (int) str[i] & 0x3f; + } + + return unichar; } -bool utf8_is_printable_newline(const char *str, size_t length, bool newline) +bool +utf8_is_printable_newline (const char *str, size_t length, bool newline) { - const char *p; + const char *p; - assert(str); + assert (str); - for (p = str; length;) { - int encoded_len, val; + for (p = str; length;) + { + int encoded_len, val; - encoded_len = utf8_encoded_valid_unichar(p); - if (encoded_len < 0 || (size_t) encoded_len > length) - return false; + encoded_len = utf8_encoded_valid_unichar (p); + if (encoded_len < 0 || (size_t) encoded_len > length) + return false; - val = utf8_encoded_to_unichar(p); - if (val < 0 || - is_unicode_control(val) || (!newline && val == '\n')) - return false; + val = utf8_encoded_to_unichar (p); + if (val < 0 || is_unicode_control (val) || (!newline && val == '\n')) + return false; - length -= encoded_len; - p += encoded_len; - } + length -= encoded_len; + p += encoded_len; + } - return true; + return true; } -const char *utf8_is_valid(const char *str) +const char * +utf8_is_valid (const char *str) { - const uint8_t *p; + const uint8_t *p; - assert(str); + assert (str); - for (p = (const uint8_t *)str; *p;) { - int len; + for (p = (const uint8_t *) str; *p;) + { + int len; - len = utf8_encoded_valid_unichar((const char *)p); - if (len < 0) - return NULL; + len = utf8_encoded_valid_unichar ((const char *) p); + if (len < 0) + return NULL; - p += len; - } + p += len; + } - return str; + return str; } -char *utf8_escape_invalid(const char *str) +char * +utf8_escape_invalid (const char *str) { - char *p, *s; + char *p, *s; - assert(str); + assert (str); - p = s = malloc(strlen(str) * 4 + 1); - if (!p) - return NULL; + p = s = malloc (strlen (str) * 4 + 1); + if (!p) + return NULL; - while (*str) { - int len; + while (*str) + { + int len; - len = utf8_encoded_valid_unichar(str); - if (len > 0) { - s = mempcpy(s, str, len); - str += len; - } else { - s = stpcpy(s, UTF8_REPLACEMENT_CHARACTER); - str += 1; - } + len = utf8_encoded_valid_unichar (str); + if (len > 0) + { + s = mempcpy (s, str, len); + str += len; + } + else + { + s = stpcpy (s, UTF8_REPLACEMENT_CHARACTER); + str += 1; } + } - *s = '\0'; + *s = '\0'; - return p; + return p; } -char *utf8_escape_non_printable(const char *str) +char * +utf8_escape_non_printable (const char *str) { - char *p, *s; - - assert(str); - - p = s = malloc(strlen(str) * 4 + 1); - if (!p) - return NULL; - - while (*str) { - int len; - - len = utf8_encoded_valid_unichar(str); - if (len > 0) { - if (utf8_is_printable(str, len)) { - s = mempcpy(s, str, len); - str += len; - } else { - while (len > 0) { - *(s++) = '\\'; - *(s++) = 'x'; - *(s++) = hexchar((int)*str >> 4); - *(s++) = hexchar((int)*str); - - str += 1; - len--; - } - } - } else { - s = stpcpy(s, UTF8_REPLACEMENT_CHARACTER); - str += 1; + char *p, *s; + + assert (str); + + p = s = malloc (strlen (str) * 4 + 1); + if (!p) + return NULL; + + while (*str) + { + int len; + + len = utf8_encoded_valid_unichar (str); + if (len > 0) + { + if (utf8_is_printable (str, len)) + { + s = mempcpy (s, str, len); + str += len; + } + else + { + while (len > 0) + { + *(s++) = '\\'; + *(s++) = 'x'; + *(s++) = hexchar ((int) *str >> 4); + *(s++) = hexchar ((int) *str); + + str += 1; + len--; } + } } + else + { + s = stpcpy (s, UTF8_REPLACEMENT_CHARACTER); + str += 1; + } + } - *s = '\0'; + *s = '\0'; - return p; + return p; } -char *ascii_is_valid(const char *str) +char * +ascii_is_valid (const char *str) { - const char *p; + const char *p; - assert(str); + assert (str); - for (p = str; *p; p++) - if ((unsigned char)*p >= 128) - return NULL; + for (p = str; *p; p++) + if ((unsigned char) *p >= 128) + return NULL; - return (char *)str; + return (char *) str; } /** @@ -289,133 +312,150 @@ char *ascii_is_valid(const char *str) * Returns: The length in bytes that the UTF-8 representation does or would * occupy. */ -size_t utf8_encode_unichar(char *out_utf8, uint32_t g) +size_t +utf8_encode_unichar (char *out_utf8, uint32_t g) { - if (g < (1 << 7)) { - if (out_utf8) - out_utf8[0] = g & 0x7f; - return 1; - } else if (g < (1 << 11)) { - if (out_utf8) { - out_utf8[0] = 0xc0 | ((g >> 6) & 0x1f); - out_utf8[1] = 0x80 | (g & 0x3f); - } - return 2; - } else if (g < (1 << 16)) { - if (out_utf8) { - out_utf8[0] = 0xe0 | ((g >> 12) & 0x0f); - out_utf8[1] = 0x80 | ((g >> 6) & 0x3f); - out_utf8[2] = 0x80 | (g & 0x3f); - } - return 3; - } else if (g < (1 << 21)) { - if (out_utf8) { - out_utf8[0] = 0xf0 | ((g >> 18) & 0x07); - out_utf8[1] = 0x80 | ((g >> 12) & 0x3f); - out_utf8[2] = 0x80 | ((g >> 6) & 0x3f); - out_utf8[3] = 0x80 | (g & 0x3f); - } - return 4; - } else { - return 0; + if (g < (1 << 7)) + { + if (out_utf8) + out_utf8[0] = g & 0x7f; + return 1; + } + else if (g < (1 << 11)) + { + if (out_utf8) + { + out_utf8[0] = 0xc0 | ((g >> 6) & 0x1f); + out_utf8[1] = 0x80 | (g & 0x3f); + } + return 2; + } + else if (g < (1 << 16)) + { + if (out_utf8) + { + out_utf8[0] = 0xe0 | ((g >> 12) & 0x0f); + out_utf8[1] = 0x80 | ((g >> 6) & 0x3f); + out_utf8[2] = 0x80 | (g & 0x3f); } + return 3; + } + else if (g < (1 << 21)) + { + if (out_utf8) + { + out_utf8[0] = 0xf0 | ((g >> 18) & 0x07); + out_utf8[1] = 0x80 | ((g >> 12) & 0x3f); + out_utf8[2] = 0x80 | ((g >> 6) & 0x3f); + out_utf8[3] = 0x80 | (g & 0x3f); + } + return 4; + } + else + { + return 0; + } } -char *utf16_to_utf8(const void *s, size_t length) +char * +utf16_to_utf8 (const void *s, size_t length) { - const uint8_t *f; - char *r, *t; + const uint8_t *f; + char *r, *t; - r = new(char, (length * 4 + 1) / 2 + 1); - if (!r) - return NULL; + r = new (char, (length * 4 + 1) / 2 + 1); + if (!r) + return NULL; - f = s; - t = r; + f = s; + t = r; - while (f < (const uint8_t *)s + length) { - uint16_t w1, w2; + while (f < (const uint8_t *) s + length) + { + uint16_t w1, w2; - /* see RFC 2781 section 2.2 */ + /* see RFC 2781 section 2.2 */ - w1 = f[1] << 8 | f[0]; - f += 2; + w1 = f[1] << 8 | f[0]; + f += 2; - if (!utf16_is_surrogate(w1)) { - t += utf8_encode_unichar(t, w1); + if (!utf16_is_surrogate (w1)) + { + t += utf8_encode_unichar (t, w1); - continue; - } - - if (utf16_is_trailing_surrogate(w1)) - continue; - else if (f >= (const uint8_t *)s + length) - break; + continue; + } - w2 = f[1] << 8 | f[0]; - f += 2; + if (utf16_is_trailing_surrogate (w1)) + continue; + else if (f >= (const uint8_t *) s + length) + break; - if (!utf16_is_trailing_surrogate(w2)) { - f -= 2; - continue; - } + w2 = f[1] << 8 | f[0]; + f += 2; - t += utf8_encode_unichar(t, - utf16_surrogate_pair_to_unichar(w1, - w2)); + if (!utf16_is_trailing_surrogate (w2)) + { + f -= 2; + continue; } - *t = 0; - return r; + t += utf8_encode_unichar (t, utf16_surrogate_pair_to_unichar (w1, w2)); + } + + *t = 0; + return r; } /* expected size used to encode one unicode char */ -static int utf8_unichar_to_encoded_len(int unichar) +static int +utf8_unichar_to_encoded_len (int unichar) { - if (unichar < 0x80) - return 1; - if (unichar < 0x800) - return 2; - if (unichar < 0x10000) - return 3; - if (unichar < 0x200000) - return 4; - if (unichar < 0x4000000) - return 5; - - return 6; + if (unichar < 0x80) + return 1; + if (unichar < 0x800) + return 2; + if (unichar < 0x10000) + return 3; + if (unichar < 0x200000) + return 4; + if (unichar < 0x4000000) + return 5; + + return 6; } /* validate one encoded unicode char and return its length */ -int utf8_encoded_valid_unichar(const char *str) +int +utf8_encoded_valid_unichar (const char *str) { - int len, unichar, i; + int len, unichar, i; - assert(str); + assert (str); - len = utf8_encoded_expected_len(str); - if (len == 0) - return -EINVAL; + len = utf8_encoded_expected_len (str); + if (len == 0) + return -EINVAL; - /* ascii is valid */ - if (len == 1) - return 1; + /* ascii is valid */ + if (len == 1) + return 1; - /* check if expected encoded chars are available */ - for (i = 0; i < len; i++) - if ((str[i] & 0x80) != 0x80) - return -EINVAL; + /* check if expected encoded chars are available */ + for (i = 0; i < len; i++) + if ((str[i] & 0x80) != 0x80) + return -EINVAL; - unichar = utf8_encoded_to_unichar(str); + unichar = utf8_encoded_to_unichar (str); - /* check if encoded length matches encoded value */ - if (utf8_unichar_to_encoded_len(unichar) != len) - return -EINVAL; + /* check if encoded length matches encoded value */ + if (utf8_unichar_to_encoded_len (unichar) != len) + return -EINVAL; - /* check if value has valid range */ - if (!is_unicode_valid(unichar)) - return -EINVAL; + /* check if value has valid range */ + if (!is_unicode_valid (unichar)) + return -EINVAL; - return len; + return len; } diff --git a/libudev-compat/utf8.h b/libudev-compat/utf8.h index 426f5c5..58211b8 100644 --- a/libudev-compat/utf8.h +++ b/libudev-compat/utf8.h @@ -36,36 +36,39 @@ #define UTF8_REPLACEMENT_CHARACTER "\xef\xbf\xbd" -const char *utf8_is_valid(const char *s) _pure_; -char *ascii_is_valid(const char *s) _pure_; +const char * +utf8_is_valid (const char *s) + _pure_; + char *ascii_is_valid (const char *s) _pure_; -bool utf8_is_printable_newline(const char *str, size_t length, - bool newline) _pure_; + bool utf8_is_printable_newline (const char *str, size_t length, + bool newline) _pure_; #define utf8_is_printable(str, length) utf8_is_printable_newline(str, length, true) -char *utf8_escape_invalid(const char *s); -char *utf8_escape_non_printable(const char *str); + char *utf8_escape_invalid (const char *s); + char *utf8_escape_non_printable (const char *str); -size_t utf8_encode_unichar(char *out_utf8, uint32_t g); -char *utf16_to_utf8(const void *s, size_t length); + size_t utf8_encode_unichar (char *out_utf8, uint32_t g); + char *utf16_to_utf8 (const void *s, size_t length); -int utf8_encoded_valid_unichar(const char *str); -int utf8_encoded_to_unichar(const char *str); + int utf8_encoded_valid_unichar (const char *str); + int utf8_encoded_to_unichar (const char *str); -static inline bool utf16_is_surrogate(uint16_t c) + static inline bool utf16_is_surrogate (uint16_t c) { - return (0xd800 <= c && c <= 0xdfff); + return (0xd800 <= c && c <= 0xdfff); } -static inline bool utf16_is_trailing_surrogate(uint16_t c) +static inline bool +utf16_is_trailing_surrogate (uint16_t c) { - return (0xdc00 <= c && c <= 0xdfff); + return (0xdc00 <= c && c <= 0xdfff); } -static inline uint32_t utf16_surrogate_pair_to_unichar(uint16_t lead, - uint16_t trail) +static inline uint32_t +utf16_surrogate_pair_to_unichar (uint16_t lead, uint16_t trail) { - return ((lead - 0xd800) << 10) + (trail - 0xdc00) + 0x10000; + return ((lead - 0xd800) << 10) + (trail - 0xdc00) + 0x10000; } #endif diff --git a/libudev-compat/util.c b/libudev-compat/util.c index 3750ce7..ce69ff7 100644 --- a/libudev-compat/util.c +++ b/libudev-compat/util.c @@ -79,385 +79,417 @@ #include #undef basename -usec_t now(clockid_t clock_id) +usec_t +now (clockid_t clock_id) { - struct timespec ts; + struct timespec ts; - assert_se(clock_gettime(clock_id, &ts) == 0); + assert_se (clock_gettime (clock_id, &ts) == 0); - return timespec_load(&ts); + return timespec_load (&ts); } -struct timespec *timespec_store(struct timespec *ts, usec_t u) +struct timespec * +timespec_store (struct timespec *ts, usec_t u) { - assert(ts); + assert (ts); - if (u == USEC_INFINITY) { - ts->tv_sec = (time_t) - 1; - ts->tv_nsec = (long)-1; - return ts; - } + if (u == USEC_INFINITY) + { + ts->tv_sec = (time_t) - 1; + ts->tv_nsec = (long) -1; + return ts; + } - ts->tv_sec = (time_t) (u / USEC_PER_SEC); - ts->tv_nsec = (long int)((u % USEC_PER_SEC) * NSEC_PER_USEC); + ts->tv_sec = (time_t) (u / USEC_PER_SEC); + ts->tv_nsec = (long int) ((u % USEC_PER_SEC) * NSEC_PER_USEC); - return ts; + return ts; } -usec_t timespec_load(const struct timespec * ts) +usec_t +timespec_load (const struct timespec * ts) { - assert(ts); + assert (ts); - if (ts->tv_sec == (time_t) - 1 && ts->tv_nsec == (long)-1) - return USEC_INFINITY; + if (ts->tv_sec == (time_t) - 1 && ts->tv_nsec == (long) -1) + return USEC_INFINITY; - if ((usec_t) ts->tv_sec > - (UINT64_MAX - (ts->tv_nsec / NSEC_PER_USEC)) / USEC_PER_SEC) - return USEC_INFINITY; + if ((usec_t) ts->tv_sec > + (UINT64_MAX - (ts->tv_nsec / NSEC_PER_USEC)) / USEC_PER_SEC) + return USEC_INFINITY; - return - (usec_t) ts->tv_sec * USEC_PER_SEC + - (usec_t) ts->tv_nsec / NSEC_PER_USEC; + return + (usec_t) ts->tv_sec * USEC_PER_SEC + (usec_t) ts->tv_nsec / NSEC_PER_USEC; } -char *dirname_malloc(const char *path) +char * +dirname_malloc (const char *path) { - char *d, *dir, *dir2; - - d = strdup(path); - if (!d) - return NULL; - dir = dirname(d); - assert(dir); - - if (dir != d) { - dir2 = strdup(dir); - free(d); - return dir2; - } - - return dir; + char *d, *dir, *dir2; + + d = strdup (path); + if (!d) + return NULL; + dir = dirname (d); + assert (dir); + + if (dir != d) + { + dir2 = strdup (dir); + free (d); + return dir2; + } + + return dir; } -char hexchar(int x) +char +hexchar (int x) { - static const char table[16] = "0123456789abcdef"; + static const char table[16] = "0123456789abcdef"; - return table[x & 15]; + return table[x & 15]; } -int unhexchar(char c) +int +unhexchar (char c) { - if (c >= '0' && c <= '9') - return c - '0'; + if (c >= '0' && c <= '9') + return c - '0'; - if (c >= 'a' && c <= 'f') - return c - 'a' + 10; + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; - if (c >= 'A' && c <= 'F') - return c - 'A' + 10; + if (c >= 'A' && c <= 'F') + return c - 'A' + 10; - return -EINVAL; + return -EINVAL; } -int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid) +int +chmod_and_chown (const char *path, mode_t mode, uid_t uid, gid_t gid) { - assert(path); + assert (path); - /* Under the assumption that we are running privileged we - * first change the access mode and only then hand out - * ownership to avoid a window where access is too open. */ + /* Under the assumption that we are running privileged we + * first change the access mode and only then hand out + * ownership to avoid a window where access is too open. */ - if (mode != MODE_INVALID) - if (chmod(path, mode) < 0) - return -errno; + if (mode != MODE_INVALID) + if (chmod (path, mode) < 0) + return -errno; - if (uid != UID_INVALID || gid != GID_INVALID) - if (chown(path, uid, gid) < 0) - return -errno; + if (uid != UID_INVALID || gid != GID_INVALID) + if (chown (path, uid, gid) < 0) + return -errno; - return 0; + return 0; } -int is_dir(const char *path, bool follow) +int +is_dir (const char *path, bool follow) { - struct stat st; - int r; + struct stat st; + int r; - if (follow) - r = stat(path, &st); - else - r = lstat(path, &st); - if (r < 0) - return -errno; + if (follow) + r = stat (path, &st); + else + r = lstat (path, &st); + if (r < 0) + return -errno; - return ! !S_ISDIR(st.st_mode); + return ! !S_ISDIR (st.st_mode); } -int close_nointr(int fd) +int +close_nointr (int fd) { - assert(fd >= 0); - - if (close(fd) >= 0) - return 0; - - /* - * Just ignore EINTR; a retry loop is the wrong thing to do on - * Linux. - * - * http://lkml.indiana.edu/hypermail/linux/kernel/0509.1/0877.html - * https://bugzilla.gnome.org/show_bug.cgi?id=682819 - * http://utcc.utoronto.ca/~cks/space/blog/unix/CloseEINTR - * https://sites.google.com/site/michaelsafyan/software-engineering/checkforeintrwheninvokingclosethinkagain - */ - if (errno == EINTR) - return 0; - - return -errno; + assert (fd >= 0); + + if (close (fd) >= 0) + return 0; + + /* + * Just ignore EINTR; a retry loop is the wrong thing to do on + * Linux. + * + * http://lkml.indiana.edu/hypermail/linux/kernel/0509.1/0877.html + * https://bugzilla.gnome.org/show_bug.cgi?id=682819 + * http://utcc.utoronto.ca/~cks/space/blog/unix/CloseEINTR + * https://sites.google.com/site/michaelsafyan/software-engineering/checkforeintrwheninvokingclosethinkagain + */ + if (errno == EINTR) + return 0; + + return -errno; } -int flush_fd(int fd) +int +flush_fd (int fd) { - struct pollfd pollfd = { - .fd = fd, - .events = POLLIN, - }; + struct pollfd pollfd = { + .fd = fd, + .events = POLLIN, + }; - for (;;) { - char buf[LINE_MAX]; - ssize_t l; - int r; + for (;;) + { + char buf[LINE_MAX]; + ssize_t l; + int r; - r = poll(&pollfd, 1, 0); - if (r < 0) { - if (errno == EINTR) - continue; + r = poll (&pollfd, 1, 0); + if (r < 0) + { + if (errno == EINTR) + continue; - return -errno; + return -errno; - } else if (r == 0) - return 0; + } + else if (r == 0) + return 0; - l = read(fd, buf, sizeof(buf)); - if (l < 0) { + l = read (fd, buf, sizeof (buf)); + if (l < 0) + { - if (errno == EINTR) - continue; + if (errno == EINTR) + continue; - if (errno == EAGAIN) - return 0; + if (errno == EAGAIN) + return 0; - return -errno; - } else if (l == 0) - return 0; + return -errno; } + else if (l == 0) + return 0; + } } -int safe_close(int fd) +int +safe_close (int fd) { - /* - * Like close_nointr() but cannot fail. Guarantees errno is - * unchanged. Is a NOP with negative fds passed, and returns - * -1, so that it can be used in this syntax: - * - * fd = safe_close(fd); - */ + /* + * Like close_nointr() but cannot fail. Guarantees errno is + * unchanged. Is a NOP with negative fds passed, and returns + * -1, so that it can be used in this syntax: + * + * fd = safe_close(fd); + */ - if (fd >= 0) { - int errsv = errno; + if (fd >= 0) + { + int errsv = errno; - /* The kernel might return pretty much any error code - * via close(), but the fd will be closed anyway. The - * only condition we want to check for here is whether - * the fd was invalid at all... */ + /* The kernel might return pretty much any error code + * via close(), but the fd will be closed anyway. The + * only condition we want to check for here is whether + * the fd was invalid at all... */ - assert_se(close_nointr(fd) != -EBADF); + assert_se (close_nointr (fd) != -EBADF); - errno = errsv; - } + errno = errsv; + } - return -1; + return -1; } -int fd_wait_for_event(int fd, int event, usec_t t) +int +fd_wait_for_event (int fd, int event, usec_t t) { - struct pollfd pollfd = { - .fd = fd, - .events = event, - }; + struct pollfd pollfd = { + .fd = fd, + .events = event, + }; - struct timespec ts; - int r; + struct timespec ts; + int r; - r = ppoll(&pollfd, 1, - t == USEC_INFINITY ? NULL : timespec_store(&ts, t), NULL); - if (r < 0) - return -errno; + r = ppoll (&pollfd, 1, + t == USEC_INFINITY ? NULL : timespec_store (&ts, t), NULL); + if (r < 0) + return -errno; - if (r == 0) - return 0; + if (r == 0) + return 0; - return pollfd.revents; + return pollfd.revents; } -ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll) +ssize_t +loop_read (int fd, void *buf, size_t nbytes, bool do_poll) { - uint8_t *p = buf; - ssize_t n = 0; - - assert(fd >= 0); - assert(buf); - - while (nbytes > 0) { - ssize_t k; + uint8_t *p = buf; + ssize_t n = 0; - k = read(fd, p, nbytes); - if (k < 0) { - if (errno == EINTR) - continue; + assert (fd >= 0); + assert (buf); - if (errno == EAGAIN && do_poll) { + while (nbytes > 0) + { + ssize_t k; - /* We knowingly ignore any return value here, - * and expect that any error/EOF is reported - * via read() */ + k = read (fd, p, nbytes); + if (k < 0) + { + if (errno == EINTR) + continue; - fd_wait_for_event(fd, POLLIN, USEC_INFINITY); - continue; - } + if (errno == EAGAIN && do_poll) + { - return n > 0 ? n : -errno; - } + /* We knowingly ignore any return value here, + * and expect that any error/EOF is reported + * via read() */ - if (k == 0) - return n; + fd_wait_for_event (fd, POLLIN, USEC_INFINITY); + continue; + } - p += k; - nbytes -= k; - n += k; + return n > 0 ? n : -errno; } + if (k == 0) return n; + + p += k; + nbytes -= k; + n += k; + } + + return n; } -int loop_read_exact(int fd, void *buf, size_t nbytes, bool do_poll) +int +loop_read_exact (int fd, void *buf, size_t nbytes, bool do_poll) { - ssize_t n; - - n = loop_read(fd, buf, nbytes, do_poll); - if (n < 0) - return n; - if ((size_t) n != nbytes) - return -EIO; - return 0; + ssize_t n; + + n = loop_read (fd, buf, nbytes, do_poll); + if (n < 0) + return n; + if ((size_t) n != nbytes) + return -EIO; + return 0; } // get task ID (no glibc wrapper around this...) -pid_t gettid(void) +pid_t +gettid (void) { - return syscall(__NR_gettid); + return syscall (__NR_gettid); } -int dev_urandom(void *p, size_t n) +int +dev_urandom (void *p, size_t n) { - static int have_syscall = -1; - - int fd = -1; - int r; - - /* Gathers some randomness from the kernel. This call will - * never block, and will always return some data from the - * kernel, regardless if the random pool is fully initialized - * or not. It thus makes no guarantee for the quality of the - * returned entropy, but is good enough for or usual usecases - * of seeding the hash functions for hashtable */ - - fd = open("/dev/urandom", O_RDONLY | O_CLOEXEC | O_NOCTTY); - if (fd < 0) { - return errno == ENOENT ? -ENOSYS : -errno; - } - - int rc = loop_read_exact(fd, p, n, true); - close(fd); - return rc; + static int have_syscall = -1; + + int fd = -1; + int r; + + /* Gathers some randomness from the kernel. This call will + * never block, and will always return some data from the + * kernel, regardless if the random pool is fully initialized + * or not. It thus makes no guarantee for the quality of the + * returned entropy, but is good enough for or usual usecases + * of seeding the hash functions for hashtable */ + + fd = open ("/dev/urandom", O_RDONLY | O_CLOEXEC | O_NOCTTY); + if (fd < 0) + { + return errno == ENOENT ? -ENOSYS : -errno; + } + + int rc = loop_read_exact (fd, p, n, true); + close (fd); + return rc; } -void initialize_srand(void) +void +initialize_srand (void) { - static bool srand_called = false; - unsigned x; + static bool srand_called = false; + unsigned x; #ifdef HAVE_SYS_AUXV_H - void *auxv; + void *auxv; #endif - if (srand_called) - return; + if (srand_called) + return; - x = 0; + x = 0; #ifdef HAVE_SYS_AUXV_H - /* The kernel provides us with a bit of entropy in auxv, so - * let's try to make use of that to seed the pseudo-random - * generator. It's better than nothing... */ + /* The kernel provides us with a bit of entropy in auxv, so + * let's try to make use of that to seed the pseudo-random + * generator. It's better than nothing... */ - auxv = (void *)getauxval(AT_RANDOM); - if (auxv) - x ^= *(unsigned *)auxv; + auxv = (void *) getauxval (AT_RANDOM); + if (auxv) + x ^= *(unsigned *) auxv; #endif - x ^= (unsigned)now(CLOCK_REALTIME); - x ^= (unsigned)gettid(); + x ^= (unsigned) now (CLOCK_REALTIME); + x ^= (unsigned) gettid (); - srand(x); - srand_called = true; + srand (x); + srand_called = true; } -void random_bytes(void *p, size_t n) +void +random_bytes (void *p, size_t n) { - uint8_t *q; - int r; + uint8_t *q; + int r; - r = dev_urandom(p, n); - if (r >= 0) - return; + r = dev_urandom (p, n); + if (r >= 0) + return; - /* If some idiot made /dev/urandom unavailable to us, he'll - * get a PRNG instead. */ + /* If some idiot made /dev/urandom unavailable to us, he'll + * get a PRNG instead. */ - initialize_srand(); + initialize_srand (); - for (q = p; q < (uint8_t *) p + n; q++) - *q = rand(); + for (q = p; q < (uint8_t *) p + n; q++) + *q = rand (); } -bool is_main_thread(void) +bool +is_main_thread (void) { - return (getpid() == gettid()); + return (getpid () == gettid ()); } -size_t page_size(void) +size_t +page_size (void) { - int r = sysconf(_SC_PAGESIZE); - assert(r > 0); + int r = sysconf (_SC_PAGESIZE); + assert (r > 0); - return r; + return r; } -bool streq_ptr(const char *a, const char *b) +bool +streq_ptr (const char *a, const char *b) { - /* Like streq(), but tries to make sense of NULL pointers */ + /* Like streq(), but tries to make sense of NULL pointers */ - if (a && b) - return streq(a, b); + if (a && b) + return streq (a, b); - if (!a && !b) - return true; + if (!a && !b) + return true; - return false; + return false; } diff --git a/libudev-compat/util.h b/libudev-compat/util.h index f2611a2..1208306 100644 --- a/libudev-compat/util.h +++ b/libudev-compat/util.h @@ -83,7 +83,7 @@ #define streq(a,b) (strcmp((a),(b)) == 0) -bool streq_ptr(const char *a, const char *b); +bool streq_ptr (const char *a, const char *b); #define strneq(a, b, n) (strncmp((a), (b), (n)) == 0) @@ -127,17 +127,19 @@ bool streq_ptr(const char *a, const char *b); #ifndef MAX_HANDLE_SZ #define MAX_HANDLE_SZ 128 -struct file_handle { - unsigned int handle_bytes; - int handle_type; - /* File identifier. */ - unsigned char f_handle[0]; +struct file_handle +{ + unsigned int handle_bytes; + int handle_type; + /* File identifier. */ + unsigned char f_handle[0]; }; #endif -union file_handle_union { - struct file_handle handle; - char padding[sizeof(struct file_handle) + MAX_HANDLE_SZ]; +union file_handle_union +{ + struct file_handle handle; + char padding[sizeof (struct file_handle) + MAX_HANDLE_SZ]; }; #define FILE_HANDLE_INIT { .handle.handle_bytes = MAX_HANDLE_SZ } @@ -150,19 +152,23 @@ union file_handle_union { break; \ } else -static inline size_t ALIGN_TO(size_t l, size_t ali) +static inline size_t +ALIGN_TO (size_t l, size_t ali) { - return ((l + ali - 1) & ~(ali - 1)); + return ((l + ali - 1) & ~(ali - 1)); } -size_t page_size(void)_pure_; +size_t +page_size (void) + _pure_; #define PAGE_ALIGN(l) ALIGN_TO((l), page_size()) ////////// reference counting -typedef struct { - volatile unsigned _value; -} RefCount; + typedef struct + { + volatile unsigned _value; + } RefCount; #define REFCNT_GET(r) ((r)._value) #define REFCNT_INC(r) (__sync_add_and_fetch(&(r)._value, 1)) @@ -172,8 +178,8 @@ typedef struct { ////////// time functions -typedef uint64_t usec_t; -typedef uint64_t nsec_t; + typedef uint64_t usec_t; + typedef uint64_t nsec_t; #define NSEC_FMT "%" PRIu64 #define USEC_FMT "%" PRIu64 @@ -188,21 +194,21 @@ typedef uint64_t nsec_t; #define NSEC_PER_MSEC ((nsec_t) 1000000ULL) #define NSEC_PER_USEC ((nsec_t) 1000ULL) -usec_t now(clockid_t clock); -usec_t timespec_load(const struct timespec *ts); -struct timespec *timespec_store(struct timespec *ts, usec_t u); + usec_t now (clockid_t clock); + usec_t timespec_load (const struct timespec *ts); + struct timespec *timespec_store (struct timespec *ts, usec_t u); ////////// string functions -static inline char *startswith(const char *s, const char *prefix) + static inline char *startswith (const char *s, const char *prefix) { - size_t l; + size_t l; - l = strlen(prefix); - if (strncmp(s, prefix, l) == 0) - return (char *)s + l; + l = strlen (prefix); + if (strncmp (s, prefix, l) == 0) + return (char *) s + l; - return NULL; + return NULL; } #define strjoina(a, ...) \ @@ -230,9 +236,11 @@ static inline char *startswith(const char *s, const char *prefix) sizeof(type) <= 4 ? 10 : \ sizeof(type) <= 8 ? 20 : sizeof(int[-2*(sizeof(type) > 8)]))) -char *dirname_malloc(const char *path); -char hexchar(int x) _const_; -int unhexchar(char c) _const_; +char *dirname_malloc (const char *path); +char +hexchar (int x) + _const_; + int unhexchar (char c) _const_; #define NULSTR_FOREACH(i, l) \ for ((i) = (l); (i) && *(i); (i) = strchr((i), 0)+1) @@ -251,10 +259,10 @@ int unhexchar(char c) _const_; } \ struct __useless_struct_to_allow_trailing_semicolon__ -DEFINE_TRIVIAL_CLEANUP_FUNC(FILE *, fclose); -DEFINE_TRIVIAL_CLEANUP_FUNC(FILE *, pclose); -DEFINE_TRIVIAL_CLEANUP_FUNC(DIR *, closedir); -DEFINE_TRIVIAL_CLEANUP_FUNC(FILE *, endmntent); +DEFINE_TRIVIAL_CLEANUP_FUNC (FILE *, fclose); +DEFINE_TRIVIAL_CLEANUP_FUNC (FILE *, pclose); +DEFINE_TRIVIAL_CLEANUP_FUNC (DIR *, closedir); +DEFINE_TRIVIAL_CLEANUP_FUNC (FILE *, endmntent); #define _cleanup_free_ _cleanup_(freep) #define _cleanup_close_ _cleanup_(closep) @@ -266,22 +274,22 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(FILE *, endmntent); #define _cleanup_endmntent_ _cleanup_(endmntentp) #define _cleanup_close_pair_ _cleanup_(close_pairp) -_malloc_ _alloc_(1, 2) -static inline void *malloc_multiply(size_t a, size_t b) + _malloc_ _alloc_ (1, 2) + static inline void *malloc_multiply (size_t a, size_t b) { - if (_unlikely_(b != 0 && a > ((size_t) - 1) / b)) - return NULL; + if (_unlikely_ (b != 0 && a > ((size_t) - 1) / b)) + return NULL; - return malloc(a * b); + return malloc (a * b); } -_alloc_(2, 3) -static inline void *realloc_multiply(void *p, size_t a, size_t b) +_alloc_ (2, 3) + static inline void *realloc_multiply (void *p, size_t a, size_t b) { - if (_unlikely_(b != 0 && a > ((size_t) - 1) / b)) - return NULL; + if (_unlikely_ (b != 0 && a > ((size_t) - 1) / b)) + return NULL; - return realloc(p, a * b); + return realloc (p, a * b); } ////////// sanity checks @@ -353,49 +361,54 @@ static inline void *realloc_multiply(void *p, size_t a, size_t b) * Normal qsort requires base to be nonnull. Here were require * that only if nmemb > 0. */ -static inline void qsort_safe(void *base, size_t nmemb, size_t size, - int (*compar) (const void *, const void *)) +static inline void +qsort_safe (void *base, size_t nmemb, size_t size, + int (*compar) (const void *, const void *)) { - if (nmemb) { - assert(base); - qsort(base, nmemb, size, compar); - } + if (nmemb) + { + assert (base); + qsort (base, nmemb, size, compar); + } } -static inline void *mempset(void *s, int c, size_t n) +static inline void * +mempset (void *s, int c, size_t n) { - memset(s, c, n); - return (uint8_t *) s + n; + memset (s, c, n); + return (uint8_t *) s + n; } -static inline unsigned log2u(unsigned x) +static inline unsigned +log2u (unsigned x) { - assert(x > 0); + assert (x > 0); - return sizeof(unsigned) * 8 - __builtin_clz(x) - 1; + return sizeof (unsigned) * 8 - __builtin_clz (x) - 1; } -static inline unsigned log2u_round_up(unsigned x) +static inline unsigned +log2u_round_up (unsigned x) { - assert(x > 0); + assert (x > 0); - if (x == 1) - return 0; + if (x == 1) + return 0; - return log2u(x - 1) + 1; + return log2u (x - 1) + 1; } ///////// misc functions -int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid); -int is_dir(const char *path, bool follow); -int close_nointr(int fd); -int flush_fd(int fd); -int safe_close(int fd); +int chmod_and_chown (const char *path, mode_t mode, uid_t uid, gid_t gid); +int is_dir (const char *path, bool follow); +int close_nointr (int fd); +int flush_fd (int fd); +int safe_close (int fd); -int dev_urandom(void *p, size_t n); -void initialize_srand(void); -void random_bytes(void *p, size_t n); +int dev_urandom (void *p, size_t n); +void initialize_srand (void); +void random_bytes (void *p, size_t n); -bool is_main_thread(void); +bool is_main_thread (void); #endif diff --git a/libvdev/config.c b/libvdev/config.c index 9aa0766..c1fb7f9 100644 --- a/libvdev/config.c +++ b/libvdev/config.c @@ -35,444 +35,519 @@ static const char *FUSE_OPT_F = "-f"; // ini parser callback // return 1 on parsed (WARNING: masks OOM) // return 0 on not parsed -static int vdev_config_ini_parser(void *userdata, char const *section, - char const *name, char const *value) +static int +vdev_config_ini_parser (void *userdata, char const *section, + char const *name, char const *value) { - struct vdev_config *conf = (struct vdev_config *)userdata; - bool success = false; - int rc = 0; + struct vdev_config *conf = (struct vdev_config *) userdata; + bool success = false; + int rc = 0; - if (strcmp(section, VDEV_CONFIG_NAME) == 0) { + if (strcmp (section, VDEV_CONFIG_NAME) == 0) + { - if (strcmp(name, VDEV_CONFIG_ACLS) == 0) { + if (strcmp (name, VDEV_CONFIG_ACLS) == 0) + { - if (conf->acls_dir == NULL) { - // save this - conf->acls_dir = vdev_strdup_or_null(value); - } - return 1; - } + if (conf->acls_dir == NULL) + { + // save this + conf->acls_dir = vdev_strdup_or_null (value); + } + return 1; + } - if (strcmp(name, VDEV_CONFIG_ACTIONS) == 0) { + if (strcmp (name, VDEV_CONFIG_ACTIONS) == 0) + { - if (conf->acts_dir == NULL) { - // save this - conf->acts_dir = vdev_strdup_or_null(value); - } + if (conf->acts_dir == NULL) + { + // save this + conf->acts_dir = vdev_strdup_or_null (value); + } - return 1; - } - - if (strcmp(name, VDEV_CONFIG_HELPERS) == 0) { + return 1; + } - if (conf->helpers_dir == NULL) { - // save this - conf->helpers_dir = vdev_strdup_or_null(value); - } + if (strcmp (name, VDEV_CONFIG_HELPERS) == 0) + { - return 1; - } + if (conf->helpers_dir == NULL) + { + // save this + conf->helpers_dir = vdev_strdup_or_null (value); + } - if (strcmp(name, VDEV_CONFIG_DEFAULT_MODE) == 0) { + return 1; + } - char *tmp = NULL; - conf->default_mode = (mode_t) strtoul(value, &tmp, 8); + if (strcmp (name, VDEV_CONFIG_DEFAULT_MODE) == 0) + { - if (*tmp != '\0') { + char *tmp = NULL; + conf->default_mode = (mode_t) strtoul (value, &tmp, 8); - fprintf(stderr, "Invalid value '%s' for '%s'\n", - value, name); - return 0; - } else { + if (*tmp != '\0') + { - return 1; - } - } + fprintf (stderr, "Invalid value '%s' for '%s'\n", value, name); + return 0; + } + else + { - if (strcmp(name, VDEV_CONFIG_DEFAULT_POLICY) == 0) { + return 1; + } + } - conf->default_policy = - strcasecmp(value, "allow") ? 1 : 0; - return 1; - } + if (strcmp (name, VDEV_CONFIG_DEFAULT_POLICY) == 0) + { - if (strcmp(name, VDEV_CONFIG_PIDFILE_PATH) == 0) { + conf->default_policy = strcasecmp (value, "allow") ? 1 : 0; + return 1; + } - if (conf->pidfile_path == NULL) { - conf->pidfile_path = vdev_strdup_or_null(value); - } + if (strcmp (name, VDEV_CONFIG_PIDFILE_PATH) == 0) + { - return 1; - } + if (conf->pidfile_path == NULL) + { + conf->pidfile_path = vdev_strdup_or_null (value); + } - if (strcmp(name, VDEV_CONFIG_LOGFILE_PATH) == 0) { + return 1; + } - if (conf->logfile_path == NULL) { - conf->logfile_path = vdev_strdup_or_null(value); - } + if (strcmp (name, VDEV_CONFIG_LOGFILE_PATH) == 0) + { - return 1; - } + if (conf->logfile_path == NULL) + { + conf->logfile_path = vdev_strdup_or_null (value); + } - if (strcmp(name, VDEV_CONFIG_LOG_LEVEL) == 0) { - - if (strcasecmp(value, "debug") == 0) { - - conf->debug_level = VDEV_LOGLEVEL_DEBUG; - conf->error_level = VDEV_LOGLEVEL_WARN; - } else if (strcasecmp(value, "info") == 0) { - - conf->debug_level = VDEV_LOGLEVEL_INFO; - conf->error_level = VDEV_LOGLEVEL_WARN; - } else if (strcasecmp(value, "warn") == 0 - || strcasecmp(value, "warning") == 0) { - - conf->debug_level = VDEV_LOGLEVEL_NONE; - conf->error_level = VDEV_LOGLEVEL_WARN; - } else if (strcasecmp(value, "error") == 0 - || strcasecmp(value, "critical") == 0) { - - conf->debug_level = VDEV_LOGLEVEL_NONE; - conf->error_level = VDEV_LOGLEVEL_ERROR; - } else { - // warn about unknown option value - // fallover to debug and warn - fprintf(stderr, - "Unrecognized value '%s' for '%s'\n", - value, name); - conf->debug_level = VDEV_LOGLEVEL_DEBUG; - conf->error_level = VDEV_LOGLEVEL_WARN; - // return 0; - } - - return 1; - } + return 1; + } - if (strcmp(name, VDEV_CONFIG_MOUNTPOINT) == 0) { + if (strcmp (name, VDEV_CONFIG_LOG_LEVEL) == 0) + { + + if (strcasecmp (value, "debug") == 0) + { + + conf->debug_level = VDEV_LOGLEVEL_DEBUG; + conf->error_level = VDEV_LOGLEVEL_WARN; + } + else if (strcasecmp (value, "info") == 0) + { + + conf->debug_level = VDEV_LOGLEVEL_INFO; + conf->error_level = VDEV_LOGLEVEL_WARN; + } + else if (strcasecmp (value, "warn") == 0 + || strcasecmp (value, "warning") == 0) + { + + conf->debug_level = VDEV_LOGLEVEL_NONE; + conf->error_level = VDEV_LOGLEVEL_WARN; + } + else if (strcasecmp (value, "error") == 0 + || strcasecmp (value, "critical") == 0) + { + + conf->debug_level = VDEV_LOGLEVEL_NONE; + conf->error_level = VDEV_LOGLEVEL_ERROR; + } + else + { + // warn about unknown option value + // fallover to debug and warn + fprintf (stderr, + "Unrecognized value '%s' for '%s'\n", value, name); + conf->debug_level = VDEV_LOGLEVEL_DEBUG; + conf->error_level = VDEV_LOGLEVEL_WARN; + // return 0; + } + + return 1; + } - if (conf->mountpoint == NULL) { - conf->mountpoint = vdev_strdup_or_null(value); - } + if (strcmp (name, VDEV_CONFIG_MOUNTPOINT) == 0) + { - return 1; - } + if (conf->mountpoint == NULL) + { + conf->mountpoint = vdev_strdup_or_null (value); + } - if (strcmp(name, VDEV_CONFIG_COLDPLUG_ONLY) == 0) { + return 1; + } - if (strcasecmp(name, "true") == 0) { + if (strcmp (name, VDEV_CONFIG_COLDPLUG_ONLY) == 0) + { - conf->coldplug_only = true; - } else if (strcasecmp(name, "false") == 0) { + if (strcasecmp (name, "true") == 0) + { - conf->coldplug_only = false; - } else if (!conf->coldplug_only) { + conf->coldplug_only = true; + } + else if (strcasecmp (name, "false") == 0) + { - // maybe it's 0 or non-zero? - conf->coldplug_only = - (bool) vdev_parse_uint64(value, &success); - if (!success) { + conf->coldplug_only = false; + } + else if (!conf->coldplug_only) + { - fprintf(stderr, - "Invalid value '%s' for '%s'\n", - value, name); - return 0; - } else { + // maybe it's 0 or non-zero? + conf->coldplug_only = + (bool) vdev_parse_uint64 (value, &success); + if (!success) + { - return 1; - } - } + fprintf (stderr, + "Invalid value '%s' for '%s'\n", value, name); + return 0; } + else + { - if (strcmp(name, VDEV_CONFIG_PRESEED) == 0) { + return 1; + } + } + } - if (conf->preseed_path == NULL) { + if (strcmp (name, VDEV_CONFIG_PRESEED) == 0) + { - conf->preseed_path = vdev_strdup_or_null(value); - } + if (conf->preseed_path == NULL) + { - return 1; - } + conf->preseed_path = vdev_strdup_or_null (value); + } - return 1; + return 1; } - if (strcmp(section, VDEV_OS_CONFIG_NAME) == 0) { + return 1; + } - // OS-specific config value - rc = vdev_params_add(&conf->os_config, name, value); - if (rc != 0) { + if (strcmp (section, VDEV_OS_CONFIG_NAME) == 0) + { - return 0; - } - return 1; + // OS-specific config value + rc = vdev_params_add (&conf->os_config, name, value); + if (rc != 0) + { + + return 0; } + return 1; + } - fprintf(stderr, "Unrecognized field '%s'\n", name); - return 1; + fprintf (stderr, "Unrecognized field '%s'\n", name); + return 1; } // config sanity check -int vdev_config_sanity_check(struct vdev_config *conf) +int +vdev_config_sanity_check (struct vdev_config *conf) { - int rc = 0; + int rc = 0; - if (conf->acls_dir == NULL) { + if (conf->acls_dir == NULL) + { - fprintf(stderr, "[ERROR]: missing acls\n"); - rc = -EINVAL; - } + fprintf (stderr, "[ERROR]: missing acls\n"); + rc = -EINVAL; + } - if (conf->acts_dir == NULL) { + if (conf->acts_dir == NULL) + { - fprintf(stderr, "[ERROR]: missing actions\n"); - rc = -EINVAL; - } + fprintf (stderr, "[ERROR]: missing actions\n"); + rc = -EINVAL; + } - if (conf->mountpoint == NULL) { + if (conf->mountpoint == NULL) + { - fprintf(stderr, "[ERROR]: missing mountpoint\n"); - rc = -EINVAL; - } + fprintf (stderr, "[ERROR]: missing mountpoint\n"); + rc = -EINVAL; + } - return rc; + return rc; } // convert a number between 0 and 16 to its hex representation // hex must have at least 2 characters // always succeeds -void vdev_bin_to_hex(unsigned char num, char *hex) +void +vdev_bin_to_hex (unsigned char num, char *hex) { - unsigned char upper = num >> 4; - unsigned char lower = num & 0xf; - - if (upper < 10) { - hex[0] = upper + '0'; - } else { - hex[0] = upper + 'A'; - } - - if (lower < 10) { - hex[1] = lower + '0'; - } else { - hex[1] = lower + 'A'; - } + unsigned char upper = num >> 4; + unsigned char lower = num & 0xf; + + if (upper < 10) + { + hex[0] = upper + '0'; + } + else + { + hex[0] = upper + 'A'; + } + + if (lower < 10) + { + hex[1] = lower + '0'; + } + else + { + hex[1] = lower + 'A'; + } } // generate an instance nonce // NOTE: not thread-safe, since it uses mrand48(3) (can't use /dev/urandom, since it doesn't exist yet) // always succeeds -static void vdev_config_make_instance_nonce(struct vdev_config *conf) +static void +vdev_config_make_instance_nonce (struct vdev_config *conf) { - char instance[VDEV_CONFIG_INSTANCE_NONCE_LEN]; + char instance[VDEV_CONFIG_INSTANCE_NONCE_LEN]; - // generate an instance nonce - for (int i = 0; i < VDEV_CONFIG_INSTANCE_NONCE_LEN; i++) { + // generate an instance nonce + for (int i = 0; i < VDEV_CONFIG_INSTANCE_NONCE_LEN; i++) + { - instance[i] = (char)mrand48(); - } + instance[i] = (char) mrand48 (); + } - memset(conf->instance_str, 0, VDEV_CONFIG_INSTANCE_NONCE_STRLEN); + memset (conf->instance_str, 0, VDEV_CONFIG_INSTANCE_NONCE_STRLEN); - for (int i = 0; i < VDEV_CONFIG_INSTANCE_NONCE_LEN; i++) { + for (int i = 0; i < VDEV_CONFIG_INSTANCE_NONCE_LEN; i++) + { - vdev_bin_to_hex((unsigned char)instance[i], - &conf->instance_str[2 * i]); - } + vdev_bin_to_hex ((unsigned char) instance[i], + &conf->instance_str[2 * i]); + } } // initialize a config // always succeeds -int vdev_config_init(struct vdev_config *conf) +int +vdev_config_init (struct vdev_config *conf) { - memset(conf, 0, sizeof(struct vdev_config)); - return 0; + memset (conf, 0, sizeof (struct vdev_config)); + return 0; } // load from a file, by path // return on on success // return -errno on failure to open -int vdev_config_load(char const *path, struct vdev_config *conf) +int +vdev_config_load (char const *path, struct vdev_config *conf) { - FILE *f = NULL; - int rc = 0; + FILE *f = NULL; + int rc = 0; - f = fopen(path, "r"); - if (f == NULL) { - rc = -errno; - return rc; - } + f = fopen (path, "r"); + if (f == NULL) + { + rc = -errno; + return rc; + } - rc = vdev_config_load_file(f, conf); + rc = vdev_config_load_file (f, conf); - fclose(f); + fclose (f); - if (rc == 0) { + if (rc == 0) + { - vdev_config_make_instance_nonce(conf); - } - return rc; + vdev_config_make_instance_nonce (conf); + } + return rc; } // load from a file // return 0 on success // return -errno on failure to load -int vdev_config_load_file(FILE * file, struct vdev_config *conf) +int +vdev_config_load_file (FILE * file, struct vdev_config *conf) { - int rc = 0; + int rc = 0; - rc = ini_parse_file(file, vdev_config_ini_parser, conf); - if (rc != 0) { - vdev_error("ini_parse_file(config) rc = %d\n", rc); - vdev_config_free(conf); + rc = ini_parse_file (file, vdev_config_ini_parser, conf); + if (rc != 0) + { + vdev_error ("ini_parse_file(config) rc = %d\n", rc); + vdev_config_free (conf); - return rc; - } - // convert paths - rc = vdev_config_fullpaths(conf); - if (rc != 0) { + return rc; + } + // convert paths + rc = vdev_config_fullpaths (conf); + if (rc != 0) + { - vdev_error("vdev_config_fullpaths: %s\n", strerror(-rc)); - vdev_config_free(conf); - return rc; - } + vdev_error ("vdev_config_fullpaths: %s\n", strerror (-rc)); + vdev_config_free (conf); + return rc; + } - return rc; + return rc; } // free a config // always succeeds -int vdev_config_free(struct vdev_config *conf) +int +vdev_config_free (struct vdev_config *conf) { - if (conf->acls_dir != NULL) { + if (conf->acls_dir != NULL) + { - free(conf->acls_dir); - conf->acls_dir = NULL; - } + free (conf->acls_dir); + conf->acls_dir = NULL; + } - if (conf->acts_dir != NULL) { + if (conf->acts_dir != NULL) + { - free(conf->acts_dir); - conf->acts_dir = NULL; - } + free (conf->acts_dir); + conf->acts_dir = NULL; + } - if (conf->os_config != NULL) { + if (conf->os_config != NULL) + { - vdev_params_free(conf->os_config); - conf->os_config = NULL; - } + vdev_params_free (conf->os_config); + conf->os_config = NULL; + } - if (conf->helpers_dir != NULL) { + if (conf->helpers_dir != NULL) + { - free(conf->helpers_dir); - conf->helpers_dir = NULL; - } + free (conf->helpers_dir); + conf->helpers_dir = NULL; + } - if (conf->config_path != NULL) { + if (conf->config_path != NULL) + { - free(conf->config_path); - conf->config_path = NULL; - } + free (conf->config_path); + conf->config_path = NULL; + } - if (conf->mountpoint != NULL) { + if (conf->mountpoint != NULL) + { - free(conf->mountpoint); - conf->mountpoint = NULL; - } + free (conf->mountpoint); + conf->mountpoint = NULL; + } - if (conf->preseed_path != NULL) { + if (conf->preseed_path != NULL) + { - free(conf->preseed_path); - conf->preseed_path = NULL; - } + free (conf->preseed_path); + conf->preseed_path = NULL; + } - if (conf->logfile_path != NULL) { + if (conf->logfile_path != NULL) + { - free(conf->logfile_path); - conf->logfile_path = NULL; - } + free (conf->logfile_path); + conf->logfile_path = NULL; + } - if (conf->pidfile_path != NULL) { + if (conf->pidfile_path != NULL) + { - free(conf->pidfile_path); - conf->pidfile_path = NULL; - } + free (conf->pidfile_path); + conf->pidfile_path = NULL; + } - return 0; + return 0; } // convert all paths in the config to absolute paths // return 0 on success // return -ENOMEM on OOM // return -ERANGE if cwd is too long -int vdev_config_fullpaths(struct vdev_config *conf) +int +vdev_config_fullpaths (struct vdev_config *conf) { - // this int does not seem to be used here - // int rc = 0; - - char **need_fullpath[] = { - &conf->config_path, - &conf->acls_dir, - &conf->acts_dir, - &conf->helpers_dir, - &conf->pidfile_path, - &conf->logfile_path, - &conf->preseed_path, - NULL - }; - - char cwd_buf[PATH_MAX + 1]; - memset(cwd_buf, 0, PATH_MAX + 1); - - char *tmp = getcwd(cwd_buf, PATH_MAX); - if (tmp == NULL) { - - vdev_error("Current working directory exceeds %u bytes\n", - PATH_MAX); - return -ERANGE; - } - - for (int i = 0; need_fullpath[i] != NULL; i++) { - - if (need_fullpath[i] != NULL && (*need_fullpath[i]) != NULL) { - - // if special sentinel string "syslog" is found, don't process it - if (need_fullpath[i] == &conf->logfile_path - && strncmp((*need_fullpath[i]), "syslog", 7) == 0) { - continue; - } - - if (*(need_fullpath[i])[0] != '/') { - - // relative path - char *new_path = - vdev_fullpath(cwd_buf, *(need_fullpath)[i], - NULL); - if (new_path == NULL) { - - return -ENOMEM; - } - - free(*(need_fullpath[i])); - *(need_fullpath[i]) = new_path; - } + // this int does not seem to be used here + // int rc = 0; + + char **need_fullpath[] = { + &conf->config_path, + &conf->acls_dir, + &conf->acts_dir, + &conf->helpers_dir, + &conf->pidfile_path, + &conf->logfile_path, + &conf->preseed_path, + NULL + }; + + char cwd_buf[PATH_MAX + 1]; + memset (cwd_buf, 0, PATH_MAX + 1); + + char *tmp = getcwd (cwd_buf, PATH_MAX); + if (tmp == NULL) + { + + vdev_error ("Current working directory exceeds %u bytes\n", PATH_MAX); + return -ERANGE; + } + + for (int i = 0; need_fullpath[i] != NULL; i++) + { + + if (need_fullpath[i] != NULL && (*need_fullpath[i]) != NULL) + { + + // if special sentinel string "syslog" is found, don't process it + if (need_fullpath[i] == &conf->logfile_path + && strncmp ((*need_fullpath[i]), "syslog", 7) == 0) + { + continue; + } + + if (*(need_fullpath[i])[0] != '/') + { + + // relative path + char *new_path = vdev_fullpath (cwd_buf, *(need_fullpath)[i], + NULL); + if (new_path == NULL) + { + + return -ENOMEM; } + + free (*(need_fullpath[i])); + *(need_fullpath[i]) = new_path; + } } + } - return 0; + return 0; } // print usage statement -int vdev_config_usage(char const *progname) +int +vdev_config_usage (char const *progname) { - fprintf(stderr, "\ + fprintf (stderr, "\ \ Usage: %s [options] mountpoint\n\ Options include:\n\ @@ -503,29 +578,32 @@ Options include:\n\ and exits early.\n\ ", progname); - return 0; + return 0; } // get the mountpoint option, by taking the last argument that wasn't an optarg -static int vdev_config_get_mountpoint_from_fuse(int fuse_argc, char **fuse_argv, - char **ret_mountpoint) +static int +vdev_config_get_mountpoint_from_fuse (int fuse_argc, char **fuse_argv, + char **ret_mountpoint) { - *ret_mountpoint = realpath(fuse_argv[fuse_argc - 1], NULL); + *ret_mountpoint = realpath (fuse_argv[fuse_argc - 1], NULL); - if (*ret_mountpoint == NULL) { + if (*ret_mountpoint == NULL) + { - int rc = -errno; - printf("No mountpoint, rc = %d\n", rc); + int rc = -errno; + printf ("No mountpoint, rc = %d\n", rc); - for (int i = 0; i < fuse_argc; i++) { - printf("argv[%d]: '%s'\n", i, fuse_argv[i]); - } - - return -EINVAL; + for (int i = 0; i < fuse_argc; i++) + { + printf ("argv[%d]: '%s'\n", i, fuse_argv[i]); } - return 0; + return -EINVAL; + } + + return 0; } // parse command-line options from argv. @@ -533,191 +611,215 @@ static int vdev_config_get_mountpoint_from_fuse(int fuse_argc, char **fuse_argv, // config must be initialized; this method simply augments it // return 0 on success // return -1 on unrecognized option -int vdev_config_load_from_args(struct vdev_config *config, int argc, - char **argv, int *fuse_argc, char **fuse_argv) +int +vdev_config_load_from_args (struct vdev_config *config, int argc, + char **argv, int *fuse_argc, char **fuse_argv) { - static struct option vdev_options[] = { - {"config-file", required_argument, 0, 'c'}, - {"verbose-level", required_argument, 0, 'v'}, - {"logfile", required_argument, 0, 'l'}, - {"pidfile", required_argument, 0, 'p'}, - {"once", no_argument, 0, '1'}, - {"coldplug-only", no_argument, 0, 'n'}, - {"foreground", no_argument, 0, 'f'}, - {"help", no_argument, 0, 'h'}, - {0, 0, 0, 0} - }; - - int rc = 0; - int opt_index = 0; - int c = 0; - int fuse_optind = 0; - - char const *optstr = "c:v:l:o:hf1np:ds"; - - if (fuse_argv != NULL) { - fuse_argv[fuse_optind] = argv[0]; - fuse_optind++; + static struct option vdev_options[] = { + {"config-file", required_argument, 0, 'c'}, + {"verbose-level", required_argument, 0, 'v'}, + {"logfile", required_argument, 0, 'l'}, + {"pidfile", required_argument, 0, 'p'}, + {"once", no_argument, 0, '1'}, + {"coldplug-only", no_argument, 0, 'n'}, + {"foreground", no_argument, 0, 'f'}, + {"help", no_argument, 0, 'h'}, + {0, 0, 0, 0} + }; + + int rc = 0; + int opt_index = 0; + int c = 0; + int fuse_optind = 0; + + char const *optstr = "c:v:l:o:hf1np:ds"; + + if (fuse_argv != NULL) + { + fuse_argv[fuse_optind] = argv[0]; + fuse_optind++; + } + + while (rc == 0 && c != -1) + { + + c = getopt_long (argc, argv, optstr, vdev_options, &opt_index); + // break on -1 missing arguments and -2 help + if (c == -1 || c == -2) + { + break; } - while (rc == 0 && c != -1) { + switch (c) + { + + case 'c': + { + + if (config->config_path != NULL) + { + free (config->config_path); + } + + config->config_path = vdev_strdup_or_null (optarg); + break; + } + + case 'l': + { + + if (config->logfile_path != NULL) + { + free (config->logfile_path); + } + + config->logfile_path = vdev_strdup_or_null (optarg); + break; + } + + case 'p': + { + + if (config->pidfile_path != NULL) + { + free (config->pidfile_path); + } + + config->pidfile_path = vdev_strdup_or_null (optarg); + break; + } + + case 'v': + { + + long debug_level = 0; + char *tmp = NULL; + + debug_level = strtol (optarg, &tmp, 10); + + if (*tmp != '\0') + { + fprintf (stderr, "Invalid argument for -d\n"); + rc = -1; + } + else + { + config->debug_level = debug_level; + } + break; + } + + case 'n': + case '1': + { + + config->coldplug_only = true; + break; + } + + case 's': + { + // FUSE Option + if (fuse_argv != NULL) + { + fuse_argv[fuse_optind] = (char *) FUSE_OPT_S; + fuse_optind++; + } - c = getopt_long(argc, argv, optstr, vdev_options, &opt_index); - // break on -1 missing arguments and -2 help - if (c == -1 || c == -2) { - break; - } + break; + } - switch (c) { - - case 'c':{ - - if (config->config_path != NULL) { - free(config->config_path); - } - - config->config_path = - vdev_strdup_or_null(optarg); - break; - } - - case 'l':{ - - if (config->logfile_path != NULL) { - free(config->logfile_path); - } - - config->logfile_path = - vdev_strdup_or_null(optarg); - break; - } - - case 'p':{ - - if (config->pidfile_path != NULL) { - free(config->pidfile_path); - } - - config->pidfile_path = - vdev_strdup_or_null(optarg); - break; - } - - case 'v':{ - - long debug_level = 0; - char *tmp = NULL; - - debug_level = strtol(optarg, &tmp, 10); - - if (*tmp != '\0') { - fprintf(stderr, - "Invalid argument for -d\n"); - rc = -1; - } else { - config->debug_level = debug_level; - } - break; - } - - case 'n': - case '1':{ - - config->coldplug_only = true; - break; - } - - case 's':{ - // FUSE Option - if (fuse_argv != NULL) { - fuse_argv[fuse_optind] = - (char *)FUSE_OPT_S; - fuse_optind++; - } - - break; - } - - case 'd':{ - // FUSE option - if (fuse_argv != NULL) { - fuse_argv[fuse_optind] = - (char *)FUSE_OPT_D; - fuse_optind++; - } - - break; - } - - case 'f':{ - // FUSE option - if (fuse_argv != NULL) { - fuse_argv[fuse_optind] = - (char *)FUSE_OPT_F; - fuse_optind++; - } - - config->foreground = true; - break; - } - - case 'o':{ - // FUSE option - if (fuse_argv != NULL) { - fuse_argv[fuse_optind] = - (char *)FUSE_OPT_O; - fuse_optind++; - - fuse_argv[fuse_optind] = optarg; - fuse_optind++; - } - - break; - } - - case 'h':{ - // command args line help - fprintf(stderr, "Command Line Options Help \n"); - rc = -2; - break; - } - - default:{ - - fprintf(stderr, "Unrecognized option -%c\n", c); - rc = -1; - break; - } - } - } + case 'd': + { + // FUSE option + if (fuse_argv != NULL) + { + fuse_argv[fuse_optind] = (char *) FUSE_OPT_D; + fuse_optind++; + } - if (rc != 0) { - return rc; - } + break; + } - if (fuse_argv != NULL) { - // copy over non-option arguments to fuse_argv - for (int i = optind; i < argc; i++) { + case 'f': + { + // FUSE option + if (fuse_argv != NULL) + { + fuse_argv[fuse_optind] = (char *) FUSE_OPT_F; + fuse_optind++; + } + + config->foreground = true; + break; + } + + case 'o': + { + // FUSE option + if (fuse_argv != NULL) + { + fuse_argv[fuse_optind] = (char *) FUSE_OPT_O; + fuse_optind++; - fuse_argv[fuse_optind] = argv[i]; - fuse_optind++; - } + fuse_argv[fuse_optind] = optarg; + fuse_optind++; + } + + break; + } + + case 'h': + { + // command args line help + fprintf (stderr, "Command Line Options Help \n"); + rc = -2; + break; + } + + default: + { + + fprintf (stderr, "Unrecognized option -%c\n", c); + rc = -1; + break; + } + } + } - *fuse_argc = fuse_optind; + if (rc != 0) + { + return rc; + } - // parse FUSE args to get the mountpoint - rc = vdev_config_get_mountpoint_from_fuse(*fuse_argc, fuse_argv, - &config->mountpoint); - } else { + if (fuse_argv != NULL) + { + // copy over non-option arguments to fuse_argv + for (int i = optind; i < argc; i++) + { - // extract mountpoint - config->mountpoint = realpath(argv[optind], NULL); - if (config->mountpoint == NULL) { - rc = -errno; - fprintf(stderr, "Failed to evaluate '%s': %s\n", - argv[optind], strerror(-rc)); - } + fuse_argv[fuse_optind] = argv[i]; + fuse_optind++; + } + + *fuse_argc = fuse_optind; + + // parse FUSE args to get the mountpoint + rc = vdev_config_get_mountpoint_from_fuse (*fuse_argc, fuse_argv, + &config->mountpoint); + } + else + { + + // extract mountpoint + config->mountpoint = realpath (argv[optind], NULL); + if (config->mountpoint == NULL) + { + rc = -errno; + fprintf (stderr, "Failed to evaluate '%s': %s\n", + argv[optind], strerror (-rc)); } - return rc; + } + return rc; } diff --git a/libvdev/config.h b/libvdev/config.h index ebf6160..ac3336c 100644 --- a/libvdev/config.h +++ b/libvdev/config.h @@ -53,71 +53,73 @@ #define vdev_config_set_OS_quirk( quirk_field, quirk ) quirk_field |= (quirk) // structure for both file configuration and command-line options -struct vdev_config { +struct vdev_config +{ - // config file path (used by opts) - char *config_path; + // config file path (used by opts) + char *config_path; - // preseed script - char *preseed_path; + // preseed script + char *preseed_path; - // ACLs directory - char *acls_dir; + // ACLs directory + char *acls_dir; - // actions directory - char *acts_dir; + // actions directory + char *acts_dir; - // helpers directory - char *helpers_dir; + // helpers directory + char *helpers_dir; - // default policy (0 for deny, 1 for allow) - int default_policy; + // default policy (0 for deny, 1 for allow) + int default_policy; - // debug level - int debug_level; + // debug level + int debug_level; - // error level - int error_level; + // error level + int error_level; - // PID file path - char *pidfile_path; + // PID file path + char *pidfile_path; - // logfile path (set to "syslog" to send directly to syslog) - char *logfile_path; + // logfile path (set to "syslog" to send directly to syslog) + char *logfile_path; - // path to where /dev lives - char *mountpoint; + // path to where /dev lives + char *mountpoint; - // coldplug only? - bool coldplug_only; + // coldplug only? + bool coldplug_only; - // run in the foreground - bool foreground; + // run in the foreground + bool foreground; - // OS-specific configuration (for keys under "OS") - vdev_params *os_config; + // OS-specific configuration (for keys under "OS") + vdev_params *os_config; - // default permission bits for mknod - mode_t default_mode; + // default permission bits for mknod + mode_t default_mode; - // printable 256-bit instance nonce--randomly generated and unique per execution - char instance_str[VDEV_CONFIG_INSTANCE_NONCE_STRLEN]; + // printable 256-bit instance nonce--randomly generated and unique per execution + char instance_str[VDEV_CONFIG_INSTANCE_NONCE_STRLEN]; - // bitfield of OS-specific quirks - uint64_t OS_quirks; + // bitfield of OS-specific quirks + uint64_t OS_quirks; - // help holder - char help; + // help holder + char help; }; -C_LINKAGE_BEGIN int vdev_config_init(struct vdev_config *conf); -int vdev_config_load(char const *path, struct vdev_config *conf); -int vdev_config_load_file(FILE * file, struct vdev_config *conf); -int vdev_config_free(struct vdev_config *conf); -int vdev_config_usage(char const *progname); -int vdev_config_load_from_args(struct vdev_config *config, int argc, - char **argv, int *fuse_argc, char **fuse_argv); -int vdev_config_fullpaths(struct vdev_config *config); +C_LINKAGE_BEGIN int vdev_config_init (struct vdev_config *conf); +int vdev_config_load (char const *path, struct vdev_config *conf); +int vdev_config_load_file (FILE * file, struct vdev_config *conf); +int vdev_config_free (struct vdev_config *conf); +int vdev_config_usage (char const *progname); +int vdev_config_load_from_args (struct vdev_config *config, int argc, + char **argv, int *fuse_argc, + char **fuse_argv); +int vdev_config_fullpaths (struct vdev_config *config); C_LINKAGE_END #endif diff --git a/libvdev/ini.c b/libvdev/ini.c index 45a9788..df66584 100644 --- a/libvdev/ini.c +++ b/libvdev/ini.c @@ -5,36 +5,38 @@ Go to the project home page for more info: http://code.google.com/p/inih/ */ - + #include #include #include - + #include "ini.h" - + #if !INI_USE_STACK #include -#endif /* */ - +#endif /* */ + #define MAX_SECTION 50 #define MAX_NAME 50 - + /* Strip whitespace chars off end of given string, in place. Return s. */ -static char *rstrip(char *s) +static char * +rstrip (char *s) { - char *p = s + strlen(s); - while (p > s && isspace((unsigned char)(*--p))) - *p = '\0'; - return s; + char *p = s + strlen (s); + while (p > s && isspace ((unsigned char) (*--p))) + *p = '\0'; + return s; } /* Return pointer to first non-whitespace char in given string. */ -static char *lskip(const char *s) +static char * +lskip (const char *s) { - while (*s && isspace((unsigned char)(*s))) - s++; - return (char *)s; + while (*s && isspace ((unsigned char) (*s))) + s++; + return (char *) s; } /* @@ -42,161 +44,175 @@ Return pointer to first char c or ';' comment in given string, or pointer to null at end of string if neither found. ';' must be prefixed by a whitespace character to register as a comment. */ -static char *find_char_or_comment(const char *s, char c) +static char * +find_char_or_comment (const char *s, char c) { - int was_whitespace = 0; - while (*s && *s != c && !(was_whitespace && *s == ';')) { - was_whitespace = isspace((unsigned char)(*s)); - s++; - } return (char *)s; + int was_whitespace = 0; + while (*s && *s != c && !(was_whitespace && *s == ';')) + { + was_whitespace = isspace ((unsigned char) (*s)); + s++; + } return (char *) s; } /* Version of strncpy that ensures dest (size bytes) is null-terminated. */ -static char *strncpy0(char *dest, const char *src, size_t size) +static char * +strncpy0 (char *dest, const char *src, size_t size) { - strncpy(dest, src, size); - dest[size - 1] = '\0'; - return dest; + strncpy (dest, src, size); + dest[size - 1] = '\0'; + return dest; } /* See documentation in header file. */ -int ini_parse_file(FILE * file, - int (*handler) (void *, const char *, const char *, - const char *), void *user) + int +ini_parse_file (FILE * file, + int (*handler) (void *, const char *, const char *, + const char *), void *user) { - - /* Uses a fair bit of stack (use heap instead if you need to) */ + + /* Uses a fair bit of stack (use heap instead if you need to) */ #if INI_USE_STACK - char line[INI_MAX_LINE]; - -#else /* */ - char *line; - -#endif /* */ - char section[MAX_SECTION] = ""; - char prev_name[MAX_NAME] = ""; - char *start; - char *end; - char *name; - char *value; - int lineno = 0; - int error = 0; - + char line[INI_MAX_LINE]; + +#else /* */ + char *line; + +#endif /* */ + char section[MAX_SECTION] = ""; + char prev_name[MAX_NAME] = ""; + char *start; + char *end; + char *name; + char *value; + int lineno = 0; + int error = 0; + #if !INI_USE_STACK - line = (char *)malloc(INI_MAX_LINE); - if (!line) { - return -2; - } - -#endif /* */ - - /* Scan through file line by line */ - while (fgets(line, INI_MAX_LINE, file) != NULL) { - lineno++; - start = line; - + line = (char *) malloc (INI_MAX_LINE); + if (!line) + { + return -2; + } + +#endif /* */ + + /* Scan through file line by line */ + while (fgets (line, INI_MAX_LINE, file) != NULL) + { + lineno++; + start = line; + #if INI_ALLOW_BOM - if (lineno == 1 && (unsigned char)start[0] == 0xEF && - (unsigned char)start[1] == 0xBB && - (unsigned char)start[2] == 0xBF) { - start += 3; - } - -#endif /* */ - start = lskip(rstrip(start)); - if (*start == ';' || *start == '#') { - - /* Per Python ConfigParser, allow '#' comments at start of line */ - } - + if (lineno == 1 && (unsigned char) start[0] == 0xEF && + (unsigned char) start[1] == 0xBB && + (unsigned char) start[2] == 0xBF) + { + start += 3; + } + +#endif /* */ + start = lskip (rstrip (start)); + if (*start == ';' || *start == '#') + { + + /* Per Python ConfigParser, allow '#' comments at start of line */ + } + #if INI_ALLOW_MULTILINE - else if (*prev_name && *start && start > line) { - - /* Non-black line with leading whitespace, treat as continuation - of previous name's value (as per Python ConfigParser). */ - if (!handler(user, section, prev_name, start) - && !error) - error = lineno; - } - -#endif /* */ - else if (*start == '[') { - - /* A "[section]" line */ - end = find_char_or_comment(start + 1, ']'); - if (*end == ']') { - *end = '\0'; - strncpy0(section, start + 1, sizeof(section)); - *prev_name = '\0'; - } - - else if (!error) { - - /* No ']' found on section line */ - error = lineno; - } - } - - else if (*start && *start != ';') { - - /* Not a comment, must be a name[=:]value pair */ - end = find_char_or_comment(start, '='); - if (*end != '=') { - end = find_char_or_comment(start, ':'); - } - if (*end == '=' || *end == ':') { - *end = '\0'; - name = rstrip(start); - value = lskip(end + 1); - end = find_char_or_comment(value, '\0'); - if (*end == ';') - *end = '\0'; - rstrip(value); - - /* Valid name[=:]value pair found, call handler */ - strncpy0(prev_name, name, - sizeof(prev_name)); - if (!handler(user, section, name, value) - && !error) - error = lineno; - } - - else if (!error) { - - /* No '=' or ':' found on name[=:]value line */ - error = lineno; - } - } - + else if (*prev_name && *start && start > line) + { + + /* Non-black line with leading whitespace, treat as continuation + of previous name's value (as per Python ConfigParser). */ + if (!handler (user, section, prev_name, start) && !error) + error = lineno; + } + +#endif /* */ + else if (*start == '[') + { + + /* A "[section]" line */ + end = find_char_or_comment (start + 1, ']'); + if (*end == ']') + { + *end = '\0'; + strncpy0 (section, start + 1, sizeof (section)); + *prev_name = '\0'; + } + + else if (!error) + { + + /* No ']' found on section line */ + error = lineno; + } + } + + else if (*start && *start != ';') + { + + /* Not a comment, must be a name[=:]value pair */ + end = find_char_or_comment (start, '='); + if (*end != '=') + { + end = find_char_or_comment (start, ':'); + } + if (*end == '=' || *end == ':') + { + *end = '\0'; + name = rstrip (start); + value = lskip (end + 1); + end = find_char_or_comment (value, '\0'); + if (*end == ';') + *end = '\0'; + rstrip (value); + + /* Valid name[=:]value pair found, call handler */ + strncpy0 (prev_name, name, sizeof (prev_name)); + if (!handler (user, section, name, value) && !error) + error = lineno; + } + + else if (!error) + { + + /* No '=' or ':' found on name[=:]value line */ + error = lineno; + } + } + #if INI_STOP_ON_FIRST_ERROR - if (error) - break; - -#endif /* */ - } - + if (error) + break; + +#endif /* */ + } + #if !INI_USE_STACK - free(line); - -#endif /* */ - return error; + free (line); + +#endif /* */ + return error; } /* See documentation in header file. */ -int ini_parse(const char *filename, - int (*handler) (void *, const char *, const char *, - const char *), void *user) + int +ini_parse (const char *filename, + int (*handler) (void *, const char *, const char *, + const char *), void *user) { - FILE * file; - int error; - file = fopen(filename, "r"); - if (!file) - return -1; - error = ini_parse_file(file, handler, user); - fclose(file); - return error; + FILE * file; + int error; + file = fopen (filename, "r"); + if (!file) + return -1; + error = ini_parse_file (file, handler, user); + fclose (file); + return error; } diff --git a/libvdev/ini.h b/libvdev/ini.h index 6c6d1b7..6cbd784 100644 --- a/libvdev/ini.h +++ b/libvdev/ini.h @@ -4,18 +4,19 @@ inih is released under the New BSD license (see LICENSE.txt). Go to the project home page for more info: http://code.google.com/p/inih/ */ - + #ifndef __INI_H__ #define __INI_H__ - + /* Make this header file easier to include in C++ code */ #ifdef __cplusplus -extern "C" { - -#endif /* */ - +extern "C" +{ + +#endif /* */ + #include - + /* Parse given INI-style file. May have [section]s, name=value pairs (whitespace stripped), and comments starting with ';' (semicolon). Section is "" if name=value pair parsed before any section heading. name:value @@ -29,49 +30,49 @@ extern "C" { stop on first error), -1 on file open error, or -2 on memory allocation error (only when INI_USE_STACK is zero). */ - int ini_parse(const char *filename, - int (*handler) (void *user, const char *section, - const char *name, const char *value), - void *user); - + int ini_parse (const char *filename, + int (*handler) (void *user, const char *section, + const char *name, const char *value), + void *user); + /* Same as ini_parse(), but takes a FILE* instead of filename. This doesn't close the file when it's finished -- the caller must do that. */ - int ini_parse_file(FILE * file, - int (*handler) (void *user, const char *section, - const char *name, - const char *value), void *user); - - /* Nonzero to allow multi-line value parsing, in the style of Python's - ConfigParser. If allowed, ini_parse() will call the handler with the same - name for each subsequent line parsed. */ - + int ini_parse_file (FILE * file, + int (*handler) (void *user, const char *section, + const char *name, + const char *value), void *user); + + /* Nonzero to allow multi-line value parsing, in the style of Python's + ConfigParser. If allowed, ini_parse() will call the handler with the same + name for each subsequent line parsed. */ + #ifndef INI_ALLOW_MULTILINE #define INI_ALLOW_MULTILINE 0 -#endif /* */ - +#endif /* */ + /* Nonzero to allow a UTF-8 BOM sequence (0xEF 0xBB 0xBF) at the start of the file. See http://code.google.com/p/inih/issues/detail?id=21 */ #ifndef INI_ALLOW_BOM #define INI_ALLOW_BOM 1 -#endif /* */ - +#endif /* */ + /* Nonzero to use stack, zero to use heap (malloc/free). */ #ifndef INI_USE_STACK #define INI_USE_STACK 1 -#endif /* */ - +#endif /* */ + /* Stop parsing on first error (default is to keep parsing). */ #ifndef INI_STOP_ON_FIRST_ERROR #define INI_STOP_ON_FIRST_ERROR 1 -#endif /* */ - +#endif /* */ + /* Maximum line length for any line in INI file. */ #ifndef INI_MAX_LINE #define INI_MAX_LINE 4096 -#endif /* */ - +#endif /* */ + #ifdef __cplusplus } -#endif /* */ - +#endif /* */ + #endif /* __INI_H__ */ diff --git a/libvdev/match.c b/libvdev/match.c index 9109804..f5c2e49 100644 --- a/libvdev/match.c +++ b/libvdev/match.c @@ -22,141 +22,164 @@ #include "match.h" // parse a regex -int vdev_match_regex_init(regex_t * regex, char const *str) +int +vdev_match_regex_init (regex_t * regex, char const *str) { - int rc = 0; + int rc = 0; - rc = regcomp(regex, str, REG_EXTENDED | REG_NEWLINE); + rc = regcomp (regex, str, REG_EXTENDED | REG_NEWLINE); - if (rc != 0) { + if (rc != 0) + { - return -EINVAL; - } else { - return 0; - } + return -EINVAL; + } + else + { + return 0; + } } // parse a regex and append it to a list of regexes and strings // return 0 on success // return -EINVAL if the regex is invalid // return -ENOMEM if we're out of memory -int vdev_match_regex_append(char ***strings, regex_t ** regexes, size_t * len, - char const *next) +int +vdev_match_regex_append (char ***strings, regex_t ** regexes, size_t * len, + char const *next) { - // verify that this is a valid regex - regex_t reg; - int rc = 0; + // verify that this is a valid regex + regex_t reg; + int rc = 0; - memset(®, 0, sizeof(regex_t)); + memset (®, 0, sizeof (regex_t)); - rc = regcomp(®, next, REG_EXTENDED | REG_NEWLINE | REG_NOSUB); - if (rc != 0) { + rc = regcomp (®, next, REG_EXTENDED | REG_NEWLINE | REG_NOSUB); + if (rc != 0) + { - vdev_error("regcomp(%s) rc = %d\n", next, rc); - return -EINVAL; - } + vdev_error ("regcomp(%s) rc = %d\n", next, rc); + return -EINVAL; + } - char **new_strings = - (char **)realloc(*strings, sizeof(char **) * (*len + 2)); - regex_t *new_regexes = - (regex_t *) realloc(*regexes, sizeof(regex_t) * (*len + 1)); + char **new_strings = + (char **) realloc (*strings, sizeof (char **) * (*len + 2)); + regex_t *new_regexes = + (regex_t *) realloc (*regexes, sizeof (regex_t) * (*len + 1)); - if (new_strings == NULL || new_regexes == NULL) { - return -ENOMEM; - } + if (new_strings == NULL || new_regexes == NULL) + { + return -ENOMEM; + } - new_strings[*len] = vdev_strdup_or_null(next); - new_strings[*len + 1] = NULL; + new_strings[*len] = vdev_strdup_or_null (next); + new_strings[*len + 1] = NULL; - new_regexes[*len] = reg; + new_regexes[*len] = reg; - *strings = new_strings; - *regexes = new_regexes; + *strings = new_strings; + *regexes = new_regexes; - *len = *len + 1; + *len = *len + 1; - return 0; + return 0; } // free a list of regexes and their associated paths -int vdev_match_regexes_free(char **regex_strs, regex_t * regexes, size_t len) +int +vdev_match_regexes_free (char **regex_strs, regex_t * regexes, size_t len) { - if (regex_strs != NULL || regexes != NULL) { + if (regex_strs != NULL || regexes != NULL) + { - for (unsigned int i = 0; i < len; i++) { + for (unsigned int i = 0; i < len; i++) + { - if (regex_strs != NULL && regex_strs[i] != NULL) { + if (regex_strs != NULL && regex_strs[i] != NULL) + { - free(regex_strs[i]); - regex_strs[i] = NULL; - } + free (regex_strs[i]); + regex_strs[i] = NULL; + } - if (regexes != NULL) { - regfree(®exes[i]); - } - } + if (regexes != NULL) + { + regfree (®exes[i]); + } + } - if (regex_strs != NULL) { + if (regex_strs != NULL) + { - free(regex_strs); - } + free (regex_strs); + } - if (regexes != NULL) { + if (regexes != NULL) + { - free(regexes); - } + free (regexes); } + } - return 0; + return 0; } // does a path match a regex? // return 1 if so, 0 if not, negative on error -int vdev_match_regex(char const *path, regex_t * regex) +int +vdev_match_regex (char const *path, regex_t * regex) { - int rc = 0; + int rc = 0; - rc = regexec(regex, path, 0, NULL, 0); + rc = regexec (regex, path, 0, NULL, 0); - if (rc != 0) { - if (rc == REG_NOMATCH) { + if (rc != 0) + { + if (rc == REG_NOMATCH) + { - // no match - return 0; - } else { - vdev_error("regexec(%s) rc = %d\n", path, rc); - return -abs(rc); - } + // no match + return 0; + } + else + { + vdev_error ("regexec(%s) rc = %d\n", path, rc); + return -abs (rc); } - // match! - return 1; + } + // match! + return 1; } // does a path match any regexes in a list? // return the index of the match if so (>= 0) // return the size if not // return negative on error -int vdev_match_first_regex(char const *path, regex_t * regexes, - size_t num_regexes) +int +vdev_match_first_regex (char const *path, regex_t * regexes, + size_t num_regexes) { - int matched = 0; + int matched = 0; - for (unsigned int i = 0; i < num_regexes; i++) { + for (unsigned int i = 0; i < num_regexes; i++) + { - matched = vdev_match_regex(path, ®exes[i]); - if (matched > 0) { - return i; - } else if (matched < 0) { - vdev_error("vdev_acl_regex_match(%s) rc = %d\n", path, - matched); - return matched; - } + matched = vdev_match_regex (path, ®exes[i]); + if (matched > 0) + { + return i; + } + else if (matched < 0) + { + vdev_error ("vdev_acl_regex_match(%s) rc = %d\n", path, matched); + return matched; } + } - return num_regexes; + return num_regexes; } diff --git a/libvdev/match.h b/libvdev/match.h index 6cd1416..e61062c 100644 --- a/libvdev/match.h +++ b/libvdev/match.h @@ -26,13 +26,14 @@ #include -C_LINKAGE_BEGIN int vdev_match_regex_init(regex_t * regex, char const *str); -int vdev_match_regex_append(char ***strings, regex_t ** regexes, size_t * len, - char const *next); -int vdev_match_regexes_free(char **regex_strs, regex_t * regexes, size_t len); -int vdev_match_regex(char const *path, regex_t * regex); -int vdev_match_first_regex(char const *path, regex_t * regexes, - size_t num_regexes); +C_LINKAGE_BEGIN int vdev_match_regex_init (regex_t * regex, char const *str); +int vdev_match_regex_append (char ***strings, regex_t ** regexes, + size_t * len, char const *next); +int vdev_match_regexes_free (char **regex_strs, regex_t * regexes, + size_t len); +int vdev_match_regex (char const *path, regex_t * regex); +int vdev_match_first_regex (char const *path, regex_t * regexes, + size_t num_regexes); C_LINKAGE_END #endif diff --git a/libvdev/param.c b/libvdev/param.c index 5365a3a..86ec31d 100644 --- a/libvdev/param.c +++ b/libvdev/param.c @@ -22,90 +22,101 @@ #include "param.h" // sglib methods -SGLIB_DEFINE_RBTREE_FUNCTIONS(vdev_params, left, right, color, VDEV_PARAM_CMP); +SGLIB_DEFINE_RBTREE_FUNCTIONS (vdev_params, left, right, color, + VDEV_PARAM_CMP); // add a parameter to a params set // return 0 on success // return -EEXIST if the parameter exists // return -ENOMEM if OOM -int vdev_params_add(vdev_params ** params, char const *key, char const *value) +int +vdev_params_add (vdev_params ** params, char const *key, char const *value) { - char *key_dup = NULL; - char *value_dup = NULL; - struct vdev_param_t *new_param = NULL; + char *key_dup = NULL; + char *value_dup = NULL; + struct vdev_param_t *new_param = NULL; - struct vdev_param_t lookup; + struct vdev_param_t lookup; - // exists? fill in requisite comparator information and check - memset(&lookup, 0, sizeof(lookup)); - lookup.key = (char *)key; + // exists? fill in requisite comparator information and check + memset (&lookup, 0, sizeof (lookup)); + lookup.key = (char *) key; - new_param = sglib_vdev_params_find_member(*params, &lookup); + new_param = sglib_vdev_params_find_member (*params, &lookup); - if (new_param != NULL) { - return -EEXIST; - } + if (new_param != NULL) + { + return -EEXIST; + } - new_param = VDEV_CALLOC(struct vdev_param_t, 1); + new_param = VDEV_CALLOC (struct vdev_param_t, 1); - if (new_param == NULL) { - return -ENOMEM; - } + if (new_param == NULL) + { + return -ENOMEM; + } - key_dup = vdev_strdup_or_null(key); + key_dup = vdev_strdup_or_null (key); - if (key_dup == NULL) { + if (key_dup == NULL) + { - free(new_param); - return -ENOMEM; - } + free (new_param); + return -ENOMEM; + } - value_dup = vdev_strdup_or_null(value); + value_dup = vdev_strdup_or_null (value); - if (value_dup == NULL) { + if (value_dup == NULL) + { - free(new_param); - free(key_dup); - return -ENOMEM; - } + free (new_param); + free (key_dup); + return -ENOMEM; + } - new_param->key = key_dup; - new_param->value = value_dup; + new_param->key = key_dup; + new_param->value = value_dup; - sglib_vdev_params_add(params, new_param); + sglib_vdev_params_add (params, new_param); - return 0; + return 0; } // free params -int vdev_params_free(vdev_params * params) +int +vdev_params_free (vdev_params * params) { - struct sglib_vdev_params_iterator itr; - struct vdev_param_t *dp = NULL; + struct sglib_vdev_params_iterator itr; + struct vdev_param_t *dp = NULL; - for (dp = sglib_vdev_params_it_init_inorder(&itr, params); dp != NULL; - dp = sglib_vdev_params_it_next(&itr)) { + for (dp = sglib_vdev_params_it_init_inorder (&itr, params); dp != NULL; + dp = sglib_vdev_params_it_next (&itr)) + { - if (dp->key != NULL) { + if (dp->key != NULL) + { - free(dp->key); - dp->key = NULL; - } + free (dp->key); + dp->key = NULL; + } - if (dp->value != NULL) { + if (dp->value != NULL) + { - free(dp->value); - dp->value = NULL; - } + free (dp->value); + dp->value = NULL; } + } - for (dp = sglib_vdev_params_it_init(&itr, params); dp != NULL; - dp = sglib_vdev_params_it_next(&itr)) { + for (dp = sglib_vdev_params_it_init (&itr, params); dp != NULL; + dp = sglib_vdev_params_it_next (&itr)) + { - free(dp); - } + free (dp); + } - return 0; + return 0; } diff --git a/libvdev/param.h b/libvdev/param.h index cee7699..532403d 100644 --- a/libvdev/param.h +++ b/libvdev/param.h @@ -26,14 +26,15 @@ #include "sglib.h" // red-black tree for (string, string) pairs (i.e. named parameter pairs) -struct vdev_param_t { +struct vdev_param_t +{ - char *key; - char *value; + char *key; + char *value; - struct vdev_param_t *left; - struct vdev_param_t *right; - char color; + struct vdev_param_t *left; + struct vdev_param_t *right; + char color; }; typedef struct vdev_param_t vdev_params; @@ -42,9 +43,11 @@ typedef struct vdev_param_t vdev_params; C_LINKAGE_BEGIN // vdev_param_t -SGLIB_DEFINE_RBTREE_PROTOTYPES(vdev_params, left, right, color, VDEV_PARAM_CMP) -int vdev_params_add(vdev_params ** params, char const *key, char const *value); -int vdev_params_free(vdev_params * params); +SGLIB_DEFINE_RBTREE_PROTOTYPES (vdev_params, left, right, color, + VDEV_PARAM_CMP) + int vdev_params_add (vdev_params ** params, char const *key, + char const *value); + int vdev_params_free (vdev_params * params); C_LINKAGE_END #endif diff --git a/libvdev/sglib.h b/libvdev/sglib.h index 50da6f6..0e91da0 100644 --- a/libvdev/sglib.h +++ b/libvdev/sglib.h @@ -2022,7 +2022,7 @@ void sglib___##type##_consistency_check(type *t) {\ #ifndef SGLIB_HASH_TAB_SHIFT_CONSTANT #define SGLIB_HASH_TAB_SHIFT_CONSTANT 16381 /* should be a prime */ - /* #define SGLIB_HASH_TAB_SHIFT_CONSTANT 536870912*//* for large tables :) */ + /* #define SGLIB_HASH_TAB_SHIFT_CONSTANT 536870912 *//* for large tables :) */ #endif -#endif /* _SGLIB__h_ */ +#endif /* _SGLIB__h_ */ diff --git a/libvdev/util.c b/libvdev/util.c index ecaf40f..41720be 100644 --- a/libvdev/util.c +++ b/libvdev/util.c @@ -28,344 +28,404 @@ int _VDEV_ERROR_MESSAGES = 1; int _VDEV_SYSLOG = 0; // set debug level, by setting for info and debug messages -void vdev_set_debug_level(int d) +void +vdev_set_debug_level (int d) { - if (d >= 1) { - _VDEV_INFO_MESSAGES = 1; - } - if (d >= 2) { - _VDEV_DEBUG_MESSAGES = 1; - } + if (d >= 1) + { + _VDEV_INFO_MESSAGES = 1; + } + if (d >= 2) + { + _VDEV_DEBUG_MESSAGES = 1; + } } // set error level, by setting for warning and error messages -void vdev_set_error_level(int e) +void +vdev_set_error_level (int e) { - if (e >= 1) { - _VDEV_ERROR_MESSAGES = 1; - } - if (e >= 2) { - _VDEV_WARN_MESSAGES = 1; - } + if (e >= 1) + { + _VDEV_ERROR_MESSAGES = 1; + } + if (e >= 2) + { + _VDEV_WARN_MESSAGES = 1; + } } // debug level is the sum of the levels enabled -int vdev_get_debug_level() +int +vdev_get_debug_level () { - return _VDEV_DEBUG_MESSAGES + _VDEV_INFO_MESSAGES; + return _VDEV_DEBUG_MESSAGES + _VDEV_INFO_MESSAGES; } // error level is the sum of the errors enable -int vdev_get_error_level() +int +vdev_get_error_level () { - return _VDEV_ERROR_MESSAGES + _VDEV_WARN_MESSAGES; + return _VDEV_ERROR_MESSAGES + _VDEV_WARN_MESSAGES; } // turn on syslog logging // always succeeds -int vdev_enable_syslog() +int +vdev_enable_syslog () { - _VDEV_SYSLOG = 1; - openlog(VDEV_SYSLOG_IDENT, LOG_CONS | LOG_NDELAY | LOG_PID, LOG_DAEMON); + _VDEV_SYSLOG = 1; + openlog (VDEV_SYSLOG_IDENT, LOG_CONS | LOG_NDELAY | LOG_PID, LOG_DAEMON); - return 0; + return 0; } // become a daemon: fork, setsid, fork, umask // return 0 on child // return 1 on parent // return -errno on failure to fork -int vdev_daemonize(void) +int +vdev_daemonize (void) { - int rc = 0; - pid_t pid = 0; + int rc = 0; + pid_t pid = 0; - pid = fork(); - if (pid == 0) { + pid = fork (); + if (pid == 0) + { - // child--no tty - // become process group leader - rc = setsid(); - if (rc < 0) { + // child--no tty + // become process group leader + rc = setsid (); + if (rc < 0) + { - rc = -errno; - vdev_error("setsid() rc = %d\n", rc); - return rc; - } - // fork again - // stop us from ever regaining the tty - pid = fork(); - if (pid == 0) { - - // child - // switch to / - rc = chdir("/"); - if (rc != 0) { - - rc = -errno; - vdev_error("chdir('/') rc = %d\n", rc); - return rc; - } - // own everything we create - umask(0); - - // now a daemon! - return 0; - } else if (pid > 0) { - - // parent--die, but don't call userspace clean-up - _exit(0); - } else { - - // failed to fork - rc = -errno; - vdev_error("fork( parent=%d ) rc = %d\n", getpid(), rc); - return rc; - } - } else if (pid > 0) { + rc = -errno; + vdev_error ("setsid() rc = %d\n", rc); + return rc; + } + // fork again + // stop us from ever regaining the tty + pid = fork (); + if (pid == 0) + { + + // child + // switch to / + rc = chdir ("/"); + if (rc != 0) + { + + rc = -errno; + vdev_error ("chdir('/') rc = %d\n", rc); + return rc; + } + // own everything we create + umask (0); + + // now a daemon! + return 0; + } + else if (pid > 0) + { - // parent--we're done - return 1; - } else { + // parent--die, but don't call userspace clean-up + _exit (0); + } + else + { - // error - rc = -errno; - vdev_error("fork( parent=%d ) rc = %d\n", getpid(), rc); - return rc; + // failed to fork + rc = -errno; + vdev_error ("fork( parent=%d ) rc = %d\n", getpid (), rc); + return rc; } + } + else if (pid > 0) + { + + // parent--we're done + return 1; + } + else + { + + // error + rc = -errno; + vdev_error ("fork( parent=%d ) rc = %d\n", getpid (), rc); + return rc; + } } // redirect stdout and stderr to a logfile // return 0 on success -int vdev_log_redirect(char const *logfile_path) +int +vdev_log_redirect (char const *logfile_path) { - int logfd = 0; - int rc = 0; - FILE *f = NULL; + int logfd = 0; + int rc = 0; + FILE *f = NULL; - f = fopen(logfile_path, "a"); - if (f == NULL) { + f = fopen (logfile_path, "a"); + if (f == NULL) + { - rc = -errno; - vdev_error("fopen('%s') rc = %d\n", logfile_path, rc); - return rc; - } + rc = -errno; + vdev_error ("fopen('%s') rc = %d\n", logfile_path, rc); + return rc; + } - logfd = fileno(f); + logfd = fileno (f); - close(STDOUT_FILENO); - close(STDERR_FILENO); + close (STDOUT_FILENO); + close (STDERR_FILENO); - rc = dup2(logfd, STDOUT_FILENO); - if (rc < 0) { + rc = dup2 (logfd, STDOUT_FILENO); + if (rc < 0) + { - rc = -errno; - vdev_error("dup2(STDOUT) rc = %d\n", rc); - return rc; - } + rc = -errno; + vdev_error ("dup2(STDOUT) rc = %d\n", rc); + return rc; + } - rc = dup2(logfd, STDERR_FILENO); - if (rc < 0) { + rc = dup2 (logfd, STDERR_FILENO); + if (rc < 0) + { - rc = -errno; - vdev_error("dup2(STDERR) rc = %d\n", rc); + rc = -errno; + vdev_error ("dup2(STDERR) rc = %d\n", rc); - return rc; - } + return rc; + } - fclose(f); - logfd = -1; + fclose (f); + logfd = -1; - return 0; + return 0; } // write a pidfile to a path -int vdev_pidfile_write(char const *pidfile_path) +int +vdev_pidfile_write (char const *pidfile_path) { - char pidbuf[50]; - FILE *f = NULL; - size_t nw = 0; - int rc = 0; + char pidbuf[50]; + FILE *f = NULL; + size_t nw = 0; + int rc = 0; - f = fopen(pidfile_path, "w+"); - if (f == NULL) { + f = fopen (pidfile_path, "w+"); + if (f == NULL) + { - rc = -errno; - vdev_error("fopen('%s') rc = %d\n", pidfile_path, rc); - return rc; - } + rc = -errno; + vdev_error ("fopen('%s') rc = %d\n", pidfile_path, rc); + return rc; + } - memset(pidbuf, 0, 50); - sprintf(pidbuf, "%d\n", getpid()); + memset (pidbuf, 0, 50); + sprintf (pidbuf, "%d\n", getpid ()); - rc = vdev_write_uninterrupted(fileno(f), pidbuf, strlen(pidbuf) + 1); + rc = vdev_write_uninterrupted (fileno (f), pidbuf, strlen (pidbuf) + 1); - fclose(f); + fclose (f); - if (rc < 0) { + if (rc < 0) + { - vdev_error("vdev_write_uninterrupted('%d') rc = %d\n", getpid(), - rc); - return rc; - } + vdev_error ("vdev_write_uninterrupted('%d') rc = %d\n", getpid (), rc); + return rc; + } - return 0; + return 0; } // join two paths, writing the result to dest if dest is not NULL. // otherwise, allocate and return a buffer containing the joined paths. // return NULL on OOM -char *vdev_fullpath(char const *root, char const *path, char *dest) +char * +vdev_fullpath (char const *root, char const *path, char *dest) { - char delim = 0; - int path_off = 0; - int len = 0; + char delim = 0; + int path_off = 0; + int len = 0; - if (root == NULL || path == NULL) { - return NULL; - } + if (root == NULL || path == NULL) + { + return NULL; + } - len = strlen(path) + strlen(root) + 2; + len = strlen (path) + strlen (root) + 2; - if (strlen(root) > 0) { - size_t root_delim_off = strlen(root) - 1; - if (root[root_delim_off] != '/' && path[0] != '/') { - len++; - delim = '/'; - } else if (root[root_delim_off] == '/' && path[0] == '/') { - path_off = 1; - } + if (strlen (root) > 0) + { + size_t root_delim_off = strlen (root) - 1; + if (root[root_delim_off] != '/' && path[0] != '/') + { + len++; + delim = '/'; } - - if (dest == NULL) { - dest = VDEV_CALLOC(char, len); - if (dest == NULL) { - return NULL; - } + else if (root[root_delim_off] == '/' && path[0] == '/') + { + path_off = 1; + } + } + + if (dest == NULL) + { + dest = VDEV_CALLOC (char, len); + if (dest == NULL) + { + return NULL; } + } - memset(dest, 0, len); + memset (dest, 0, len); - strcpy(dest, root); - if (delim != 0) { - dest[strlen(dest)] = '/'; - } - strcat(dest, path + path_off); + strcpy (dest, root); + if (delim != 0) + { + dest[strlen (dest)] = '/'; + } + strcat (dest, path + path_off); - return dest; + return dest; } // get the directory name of a path. // put it into dest if dest is not null. // otherwise, allocate a buffer and return it. // return NULL on OOM -char *vdev_dirname(char const *path, char *dest) +char * +vdev_dirname (char const *path, char *dest) { - if (path == NULL) { - return NULL; + if (path == NULL) + { + return NULL; + } + + if (dest == NULL) + { + dest = VDEV_CALLOC (char, strlen (path) + 1); + if (dest == NULL) + { + return NULL; } - - if (dest == NULL) { - dest = VDEV_CALLOC(char, strlen(path) + 1); - if (dest == NULL) { - return NULL; - } - } - // is this root? - if (strlen(path) == 0 || strcmp(path, "/") == 0) { - strcpy(dest, "/"); - return dest; + } + // is this root? + if (strlen (path) == 0 || strcmp (path, "/") == 0) + { + strcpy (dest, "/"); + return dest; + } + + int delim_i = strlen (path); + if (path[delim_i] == '/') + { + delim_i--; + } + + for (; delim_i >= 0; delim_i--) + { + if (path[delim_i] == '/') + { + break; } + } - int delim_i = strlen(path); - if (path[delim_i] == '/') { - delim_i--; - } + if (delim_i < 0) + { + delim_i = 0; + } - for (; delim_i >= 0; delim_i--) { - if (path[delim_i] == '/') { - break; - } - } + if (delim_i == 0 && path[0] == '/') + { + delim_i = 1; + } - if (delim_i < 0) { - delim_i = 0; - } - - if (delim_i == 0 && path[0] == '/') { - delim_i = 1; - } - - strncpy(dest, path, delim_i); - dest[delim_i + 1] = '\0'; - return dest; + strncpy (dest, path, delim_i); + dest[delim_i + 1] = '\0'; + return dest; } // determine how long the basename of a path is // return 0 if the length could not be determined -size_t vdev_basename_len(char const *path) +size_t +vdev_basename_len (char const *path) { - if (path == NULL) { - return 0; - } - - int delim_i = strlen(path) - 1; - if (delim_i <= 0) { - return 0; - } - if (path[delim_i] == '/') { - // this path ends with '/', so skip over it if it isn't / - if (delim_i > 0) { - delim_i--; - } + if (path == NULL) + { + return 0; + } + + int delim_i = strlen (path) - 1; + if (delim_i <= 0) + { + return 0; + } + if (path[delim_i] == '/') + { + // this path ends with '/', so skip over it if it isn't / + if (delim_i > 0) + { + delim_i--; } - for (; delim_i >= 0; delim_i--) { - if (path[delim_i] == '/') { - break; - } + } + for (; delim_i >= 0; delim_i--) + { + if (path[delim_i] == '/') + { + break; } - delim_i++; + } + delim_i++; - return strlen(path) - delim_i; + return strlen (path) - delim_i; } // get the basename of a (non-directory) path. // put it into dest, if dest is not null. // otherwise, allocate a buffer with it and return the buffer // return NULL on OOM, or if path is NULL -char *vdev_basename(char const *path, char *dest) +char * +vdev_basename (char const *path, char *dest) { - size_t len = 0; + size_t len = 0; - if (path == NULL) { - return NULL; - } + if (path == NULL) + { + return NULL; + } - len = vdev_basename_len(path); + len = vdev_basename_len (path); - if (dest == NULL) { + if (dest == NULL) + { - dest = VDEV_CALLOC(char, len + 1); - if (dest == NULL) { + dest = VDEV_CALLOC (char, len + 1); + if (dest == NULL) + { - return NULL; - } - } else { - memset(dest, 0, len + 1); + return NULL; } - - strncpy(dest, path + strlen(path) - len, len); - return dest; + } + else + { + memset (dest, 0, len + 1); + } + + strncpy (dest, path + strlen (path) - len, len); + return dest; } // run a subprocess, optionally in the system shell. @@ -376,464 +436,535 @@ char *vdev_basename(char const *path, char *dest) // return 1 on output truncate // return negative on error // set the subprocess exit status in *exit_status -int vdev_subprocess(char const *cmd, char *const env[], char **output, - size_t max_output, int stderr_fd, int *exit_status, - bool use_shell) +int +vdev_subprocess (char const *cmd, char *const env[], char **output, + size_t max_output, int stderr_fd, int *exit_status, + bool use_shell) { - int p[2]; - int rc = 0; - pid_t pid = 0; - int max_fd = 0; - ssize_t nr = 0; - size_t num_read = 0; - int status = 0; - bool alloced = false; - - if (cmd == NULL) { - return -EINVAL; + int p[2]; + int rc = 0; + pid_t pid = 0; + int max_fd = 0; + ssize_t nr = 0; + size_t num_read = 0; + int status = 0; + bool alloced = false; + + if (cmd == NULL) + { + return -EINVAL; + } + // open the pipe + rc = pipe (p); + if (rc != 0) + { + + rc = -errno; + vdev_error ("pipe() rc = %d\n", rc); + return rc; + } + + max_fd = sysconf (_SC_OPEN_MAX); + + // fork the child + pid = fork (); + + if (pid == 0) + { + + // send stdout to p[1] + close (p[0]); + rc = dup2 (p[1], STDOUT_FILENO); + + if (rc < 0) + { + + rc = errno; + close (p[1]); + exit (rc); } - // open the pipe - rc = pipe(p); - if (rc != 0) { - - rc = -errno; - vdev_error("pipe() rc = %d\n", rc); - return rc; + // optionally redirect stderr (or just close it) + if (stderr_fd >= 0) + { + rc = dup2 (stderr_fd, STDERR_FILENO); + if (rc < 0) + { + + rc = errno; + close (p[1]); + exit (rc); + } + } + // close everything else but stdout and optionally stderr. + for (int i = 0; i < max_fd; i++) + { + + if (i != STDOUT_FILENO && i != stderr_fd) + { + close (i); + } } - max_fd = sysconf(_SC_OPEN_MAX); - - // fork the child - pid = fork(); - - if (pid == 0) { - - // send stdout to p[1] - close(p[0]); - rc = dup2(p[1], STDOUT_FILENO); - - if (rc < 0) { - - rc = errno; - close(p[1]); - exit(rc); - } - // optionally redirect stderr (or just close it) - if (stderr_fd >= 0) { - rc = dup2(stderr_fd, STDERR_FILENO); - if (rc < 0) { - - rc = errno; - close(p[1]); - exit(rc); - } - } - // close everything else but stdout and optionally stderr. - for (int i = 0; i < max_fd; i++) { - - if (i != STDOUT_FILENO && i != stderr_fd) { - close(i); - } - } - - // run the command - if (use_shell) { - - if (env != NULL) { - rc = execle("/bin/sh", "sh", "-c", cmd, - (char *)0, env); - } else { - - char **noenv = { NULL }; - rc = execle("/bin/sh", "sh", "-c", cmd, - (char *)0, noenv); - } - } else { + // run the command + if (use_shell) + { - if (env != NULL) { - rc = execle(cmd, cmd, (char *)0, env); - } else { + if (env != NULL) + { + rc = execle ("/bin/sh", "sh", "-c", cmd, (char *) 0, env); + } + else + { - char **noenv = { NULL }; - rc = execle(cmd, cmd, (char *)0, noenv); - } - } + char **noenv = { NULL }; + rc = execle ("/bin/sh", "sh", "-c", cmd, (char *) 0, noenv); + } + } + else + { + + if (env != NULL) + { + rc = execle (cmd, cmd, (char *) 0, env); + } + else + { + + char **noenv = { NULL }; + rc = execle (cmd, cmd, (char *) 0, noenv); + } + } - if (rc != 0) { + if (rc != 0) + { - rc = errno; - exit(rc); - } else { + rc = errno; + exit (rc); + } + else + { - // make gcc happy - exit(0); + // make gcc happy + exit (0); + } + } + else if (pid > 0) + { + + // parent + close (p[1]); + + // allocate output + if (output != NULL) + { + if (*output == NULL && max_output > 0) + { + + *output = VDEV_CALLOC (char, max_output); + if (*output == NULL) + { + + // out of memory + close (p[0]); + return -ENOMEM; } - } else if (pid > 0) { - // parent - close(p[1]); + alloced = true; + } + } + // get output + if (output != NULL && *output != NULL && max_output > 0) + { - // allocate output - if (output != NULL) { - if (*output == NULL && max_output > 0) { + nr = vdev_read_uninterrupted (p[0], (*output) + num_read, + max_output - num_read); + if (nr < 0) + { - *output = VDEV_CALLOC(char, max_output); - if (*output == NULL) { + vdev_error ("vdev_read_uninterrupted rc = %zd\n", nr); + close (p[0]); - // out of memory - close(p[0]); - return -ENOMEM; - } + if (alloced) + { - alloced = true; - } + free (*output); + *output = NULL; } - // get output - if (output != NULL && *output != NULL && max_output > 0) { - - nr = vdev_read_uninterrupted(p[0], (*output) + num_read, - max_output - num_read); - if (nr < 0) { - - vdev_error("vdev_read_uninterrupted rc = %zd\n", - nr); - close(p[0]); + return nr; + } - if (alloced) { - - free(*output); - *output = NULL; - } - return nr; - } - - num_read = nr; - } - // wait for child - rc = waitpid(pid, &status, 0); - if (rc < 0) { + num_read = nr; + } + // wait for child + rc = waitpid (pid, &status, 0); + if (rc < 0) + { - rc = -errno; - vdev_error("waitpid(%d) rc = %d\n", pid, rc); + rc = -errno; + vdev_error ("waitpid(%d) rc = %d\n", pid, rc); - close(p[0]); + close (p[0]); - if (alloced) { + if (alloced) + { - free(*output); - *output = NULL; - } + free (*output); + *output = NULL; + } - return rc; - } + return rc; + } - if (WIFEXITED(status)) { + if (WIFEXITED (status)) + { - *exit_status = WEXITSTATUS(status); - } else if (WIFSIGNALED(status)) { + *exit_status = WEXITSTATUS (status); + } + else if (WIFSIGNALED (status)) + { - vdev_error("WARN: command '%s' failed with signal %d\n", - cmd, WTERMSIG(status)); - *exit_status = status; - } else { + vdev_error ("WARN: command '%s' failed with signal %d\n", + cmd, WTERMSIG (status)); + *exit_status = status; + } + else + { - // indicate start/stop - *exit_status = -EPERM; - } + // indicate start/stop + *exit_status = -EPERM; + } - close(p[0]); - return 0; - } else { + close (p[0]); + return 0; + } + else + { - rc = -errno; - vdev_error("fork() rc = %d\n", rc); - return rc; - } + rc = -errno; + vdev_error ("fork() rc = %d\n", rc); + return rc; + } } // write, but mask EINTR // return number of bytes written on success // return -errno on I/O error -ssize_t vdev_write_uninterrupted(int fd, char const *buf, size_t len) +ssize_t +vdev_write_uninterrupted (int fd, char const *buf, size_t len) { - ssize_t num_written = 0; + ssize_t num_written = 0; - if (buf == NULL) { - return -EINVAL; - } + if (buf == NULL) + { + return -EINVAL; + } - while ((unsigned)num_written < len) { - ssize_t nw = write(fd, buf + num_written, len - num_written); - if (nw < 0) { + while ((unsigned) num_written < len) + { + ssize_t nw = write (fd, buf + num_written, len - num_written); + if (nw < 0) + { - int errsv = -errno; - if (errsv == -EINTR) { - continue; - } + int errsv = -errno; + if (errsv == -EINTR) + { + continue; + } - return errsv; - } - if (nw == 0) { - break; - } - - num_written += nw; + return errsv; } + if (nw == 0) + { + break; + } + + num_written += nw; + } - return num_written; + return num_written; } // read, but mask EINTR // return number of bytes read on success // return -errno on I/O error -ssize_t vdev_read_uninterrupted(int fd, char *buf, size_t len) +ssize_t +vdev_read_uninterrupted (int fd, char *buf, size_t len) { - ssize_t num_read = 0; + ssize_t num_read = 0; - if (buf == NULL) { - return -EINVAL; - } - - while ((unsigned)num_read < len) { - ssize_t nr = read(fd, buf + num_read, len - num_read); - if (nr < 0) { + if (buf == NULL) + { + return -EINVAL; + } - int errsv = -errno; - if (errsv == -EINTR) { - continue; - } + while ((unsigned) num_read < len) + { + ssize_t nr = read (fd, buf + num_read, len - num_read); + if (nr < 0) + { - return errsv; - } - if (nr == 0) { - break; - } + int errsv = -errno; + if (errsv == -EINTR) + { + continue; + } - num_read += nr; + return errsv; } + if (nr == 0) + { + break; + } + + num_read += nr; + } - return num_read; + return num_read; } // read a whole file, masking EINTR // return 0 on success, filling buf with up to len bytes // return -errno on open or read errors -int vdev_read_file(char const *path, char *buf, size_t len) +int +vdev_read_file (char const *path, char *buf, size_t len) { - int fd = 0; - int rc = 0; + int fd = 0; + int rc = 0; - if (path == NULL || buf == NULL) { - return -EINVAL; - } + if (path == NULL || buf == NULL) + { + return -EINVAL; + } - fd = open(path, O_RDONLY); - if (fd < 0) { + fd = open (path, O_RDONLY); + if (fd < 0) + { - rc = -errno; - vdev_error("open('%s') rc = %d\n", path, rc); - return rc; - } + rc = -errno; + vdev_error ("open('%s') rc = %d\n", path, rc); + return rc; + } - rc = vdev_read_uninterrupted(fd, buf, len); - if (rc < 0) { + rc = vdev_read_uninterrupted (fd, buf, len); + if (rc < 0) + { - rc = -errno; - vdev_error("vdev_read_uninterrupted('%s') rc = %d\n", path, rc); + rc = -errno; + vdev_error ("vdev_read_uninterrupted('%s') rc = %d\n", path, rc); - close(fd); - return rc; - } + close (fd); + return rc; + } - close(fd); - return 0; + close (fd); + return 0; } // write a whole file, masking EINTR // return 0 on success // return -EINVAL if buf or path is null // return -errno on failiure to open or write or fsync -int vdev_write_file(char const *path, char const *buf, size_t len, int flags, - mode_t mode) +int +vdev_write_file (char const *path, char const *buf, size_t len, int flags, + mode_t mode) { - int fd = 0; - int rc = 0; + int fd = 0; + int rc = 0; - if (path == NULL || buf == NULL) { - return -EINVAL; - } + if (path == NULL || buf == NULL) + { + return -EINVAL; + } - fd = open(path, flags, mode); - if (fd < 0) { + fd = open (path, flags, mode); + if (fd < 0) + { - rc = -errno; - vdev_error("open('%s') rc = %d\n", path, rc); - return rc; - } + rc = -errno; + vdev_error ("open('%s') rc = %d\n", path, rc); + return rc; + } - rc = vdev_write_uninterrupted(fd, buf, len); - if (rc < 0) { + rc = vdev_write_uninterrupted (fd, buf, len); + if (rc < 0) + { - rc = -errno; - vdev_error("vdev_write_uninterrupted('%s') rc = %d\n", path, - rc); + rc = -errno; + vdev_error ("vdev_write_uninterrupted('%s') rc = %d\n", path, rc); - close(fd); - return rc; - } - // NOTE: not much we can do if close() fails... - close(fd); + close (fd); + return rc; + } + // NOTE: not much we can do if close() fails... + close (fd); - return rc; + return rc; } // free a list of dirents // always succeeds -static void vdev_dirents_free(struct dirent **dirents, int num_entries) +static void +vdev_dirents_free (struct dirent **dirents, int num_entries) { - if (dirents == NULL) { - return; - } + if (dirents == NULL) + { + return; + } - for (int i = 0; i < num_entries; i++) { + for (int i = 0; i < num_entries; i++) + { - if (dirents[i] == NULL) { - continue; - } - - free(dirents[i]); - dirents[i] = NULL; + if (dirents[i] == NULL) + { + continue; } - free(dirents); + free (dirents[i]); + dirents[i] = NULL; + } + + free (dirents); } // portable scandirat() implementation--behaves as close to the Linux scandirat(3) interface as possible. -int vdev_portable_scandirat(int dirfd, char const *dirp, - struct dirent ***namelist, - int (*filter) (const struct dirent *), - int (*compar) (const struct dirent **, - const struct dirent **)) +int +vdev_portable_scandirat (int dirfd, char const *dirp, + struct dirent ***namelist, + int (*filter) (const struct dirent *), + int (*compar) (const struct dirent **, + const struct dirent **)) { - int rc = 0; - - DIR *dirh = NULL; - struct dirent next; - struct dirent *result = NULL; - struct dirent *next_dup = NULL; - int dirp_fd = -1; - - struct dirent **namelist_buf = NULL; - struct dirent **namelist_tmp = NULL; - ssize_t num_dirents = 0; - ssize_t num_dirents_capacity = 0; - - dirp_fd = openat(dirfd, dirp, O_DIRECTORY); - if (dirp_fd < 0) { - - rc = -errno; - return rc; - } - // open the duplicated handle instead - dirh = fdopendir(dirp_fd); - if (dirh == NULL) { - - rc = -errno; - - close(dirp_fd); - return rc; - } - - while (1) { + int rc = 0; - // next dirent - rc = readdir_r(dirh, &next, &result); + DIR *dirh = NULL; + struct dirent next; + struct dirent *result = NULL; + struct dirent *next_dup = NULL; + int dirp_fd = -1; - // done? - if (result == NULL) { - break; - } - // error? - if (rc != 0) { - - rc = -rc; - break; - } - // filter? - if (filter != NULL) { + struct dirent **namelist_buf = NULL; + struct dirent **namelist_tmp = NULL; + ssize_t num_dirents = 0; + ssize_t num_dirents_capacity = 0; - rc = (*filter) (&next); - if (rc == 0) { - - // skip - continue; - } - } - // increase (double) space? - if (num_dirents >= num_dirents_capacity) { + dirp_fd = openat (dirfd, dirp, O_DIRECTORY); + if (dirp_fd < 0) + { - if (num_dirents_capacity == 0) { - num_dirents_capacity = 1; - } + rc = -errno; + return rc; + } + // open the duplicated handle instead + dirh = fdopendir (dirp_fd); + if (dirh == NULL) + { - num_dirents_capacity <<= 1; + rc = -errno; - namelist_tmp = - (struct dirent **)realloc(namelist_buf, - (num_dirents_capacity + - 1) * - sizeof(struct dirent)); - if (namelist_tmp == NULL) { + close (dirp_fd); + return rc; + } - // OOM - rc = -ENOMEM; - break; - } - - namelist_buf = namelist_tmp; - } - // duplicate - next_dup = VDEV_CALLOC(struct dirent, 1); - if (next_dup == NULL) { - - // OOM - rc = -ENOMEM; - break; - } + while (1) + { - memcpy(next_dup, &next, sizeof(struct dirent)); + // next dirent + rc = readdir_r (dirh, &next, &result); - // insert - namelist_buf[num_dirents] = next_dup; - namelist_buf[num_dirents + 1] = NULL; - num_dirents++; + // done? + if (result == NULL) + { + break; } + // error? + if (rc != 0) + { - closedir(dirh); + rc = -rc; + break; + } + // filter? + if (filter != NULL) + { - if (rc < 0) { + rc = (*filter) (&next); + if (rc == 0) + { - // error--clean up - vdev_dirents_free(namelist_buf, num_dirents); - return rc; + // skip + continue; + } } - // sort? - if (compar != NULL) { - - qsort((void *)namelist_buf, num_dirents, - sizeof(struct dirent *), - (int (*)(const void *, const void *))compar); + // increase (double) space? + if (num_dirents >= num_dirents_capacity) + { + + if (num_dirents_capacity == 0) + { + num_dirents_capacity = 1; + } + + num_dirents_capacity <<= 1; + + namelist_tmp = + (struct dirent **) realloc (namelist_buf, + (num_dirents_capacity + + 1) * sizeof (struct dirent)); + if (namelist_tmp == NULL) + { + + // OOM + rc = -ENOMEM; + break; + } + + namelist_buf = namelist_tmp; } - // finished! - *namelist = namelist_buf; - return num_dirents; + // duplicate + next_dup = VDEV_CALLOC (struct dirent, 1); + if (next_dup == NULL) + { + + // OOM + rc = -ENOMEM; + break; + } + + memcpy (next_dup, &next, sizeof (struct dirent)); + + // insert + namelist_buf[num_dirents] = next_dup; + namelist_buf[num_dirents + 1] = NULL; + num_dirents++; + } + + closedir (dirh); + + if (rc < 0) + { + + // error--clean up + vdev_dirents_free (namelist_buf, num_dirents); + return rc; + } + // sort? + if (compar != NULL) + { + + qsort ((void *) namelist_buf, num_dirents, + sizeof (struct dirent *), + (int (*)(const void *, const void *)) compar); + } + // finished! + *namelist = namelist_buf; + return num_dirents; } // process all files in a directory, given a descriptor to it. Search in alphanumeric order @@ -841,43 +972,48 @@ int vdev_portable_scandirat(int dirfd, char const *dirp, // return -EINVAL if loader is NULL // return -EBADF if dirfd is invalid // return non-zero of loader_at returns non-zero -int vdev_load_all_at(int dirfd, vdev_dirent_loader_at_t loader_at, void *cls) +int +vdev_load_all_at (int dirfd, vdev_dirent_loader_at_t loader_at, void *cls) { - struct dirent **dirents = NULL; - int num_entries = 0; - int rc = 0; + struct dirent **dirents = NULL; + int num_entries = 0; + int rc = 0; - if (loader_at == NULL) { - return -EINVAL; - } + if (loader_at == NULL) + { + return -EINVAL; + } - num_entries = - vdev_portable_scandirat(dirfd, ".", &dirents, NULL, alphasort); - if (num_entries < 0) { + num_entries = + vdev_portable_scandirat (dirfd, ".", &dirents, NULL, alphasort); + if (num_entries < 0) + { - rc = -errno; - vdev_error("scandirat(%d) rc = %d\n", dirfd, rc); - return rc; - } + rc = -errno; + vdev_error ("scandirat(%d) rc = %d\n", dirfd, rc); + return rc; + } - for (int i = 0; i < num_entries; i++) { + for (int i = 0; i < num_entries; i++) + { - // process this - rc = (*loader_at) (dirfd, dirents[i], cls); - if (rc != 0) { + // process this + rc = (*loader_at) (dirfd, dirents[i], cls); + if (rc != 0) + { - vdev_error("loader_at(%d, '%s') rc = %d\n", dirfd, - dirents[i]->d_name, rc); + vdev_error ("loader_at(%d, '%s') rc = %d\n", dirfd, + dirents[i]->d_name, rc); - vdev_dirents_free(dirents, num_entries); - return rc; - } + vdev_dirents_free (dirents, num_entries); + return rc; } + } - vdev_dirents_free(dirents, num_entries); + vdev_dirents_free (dirents, num_entries); - return rc; + return rc; } // process all files in a directory with a loader, in alphanumeric order @@ -886,51 +1022,57 @@ int vdev_load_all_at(int dirfd, vdev_dirent_loader_at_t loader_at, void *cls) // return -ENOMEM if OOM // return -errno on I/O error // return non-zero if loader fails -int vdev_load_all(char const *dir_path, vdev_dirent_loader_t loader, void *cls) +int +vdev_load_all (char const *dir_path, vdev_dirent_loader_t loader, void *cls) { - struct dirent **dirents = NULL; - int num_entries = 0; - int rc = 0; - - if (dir_path == NULL || loader == NULL) { - return -EINVAL; - } + struct dirent **dirents = NULL; + int num_entries = 0; + int rc = 0; - num_entries = scandir(dir_path, &dirents, NULL, alphasort); - if (num_entries < 0) { + if (dir_path == NULL || loader == NULL) + { + return -EINVAL; + } - rc = -errno; - vdev_error("scandir('%s') rc = %d\n", dir_path, rc); - return rc; - } + num_entries = scandir (dir_path, &dirents, NULL, alphasort); + if (num_entries < 0) + { - for (int i = 0; i < num_entries; i++) { + rc = -errno; + vdev_error ("scandir('%s') rc = %d\n", dir_path, rc); + return rc; + } - // full path... - char *fp = vdev_fullpath(dir_path, dirents[i]->d_name, NULL); - if (fp == NULL) { + for (int i = 0; i < num_entries; i++) + { - vdev_dirents_free(dirents, num_entries); - return -ENOMEM; - } - // process this - rc = (*loader) (fp, cls); - if (rc != 0) { + // full path... + char *fp = vdev_fullpath (dir_path, dirents[i]->d_name, NULL); + if (fp == NULL) + { - vdev_error("loader('%s') rc = %d\n", fp, rc); + vdev_dirents_free (dirents, num_entries); + return -ENOMEM; + } + // process this + rc = (*loader) (fp, cls); + if (rc != 0) + { - free(fp); - vdev_dirents_free(dirents, num_entries); - return rc; - } + vdev_error ("loader('%s') rc = %d\n", fp, rc); - free(fp); + free (fp); + vdev_dirents_free (dirents, num_entries); + return rc; } - vdev_dirents_free(dirents, num_entries); + free (fp); + } - return 0; + vdev_dirents_free (dirents, num_entries); + + return 0; } // make a string of directories, given the path dirp @@ -938,97 +1080,112 @@ int vdev_load_all(char const *dir_path, vdev_dirent_loader_t loader, void *cls) // return -EINVAL if dirp is NULL // return -ENOMEM if OOM // return negative if the directory could not be created. -int vdev_mkdirs(char const *dirp, int start, mode_t mode) +int +vdev_mkdirs (char const *dirp, int start, mode_t mode) { - unsigned int i = start; - char *currdir = NULL; - struct stat statbuf; - int rc = 0; + unsigned int i = start; + char *currdir = NULL; + struct stat statbuf; + int rc = 0; - if (dirp == NULL) { - return -EINVAL; - } + if (dirp == NULL) + { + return -EINVAL; + } - currdir = VDEV_CALLOC(char, strlen(dirp) + 1); - if (currdir == NULL) { - return -ENOMEM; - } + currdir = VDEV_CALLOC (char, strlen (dirp) + 1); + if (currdir == NULL) + { + return -ENOMEM; + } - while (i <= strlen(dirp)) { + while (i <= strlen (dirp)) + { - // next '/' - if (dirp[i] == '/' || i == strlen(dirp)) { + // next '/' + if (dirp[i] == '/' || i == strlen (dirp)) + { - strncpy(currdir, dirp, i == 0 ? 1 : i); + strncpy (currdir, dirp, i == 0 ? 1 : i); - rc = stat(currdir, &statbuf); - if (rc == 0 && !S_ISDIR(statbuf.st_mode)) { + rc = stat (currdir, &statbuf); + if (rc == 0 && !S_ISDIR (statbuf.st_mode)) + { - // something else exists here - free(currdir); - return -ENOTDIR; - } + // something else exists here + free (currdir); + return -ENOTDIR; + } - if (rc != 0) { + if (rc != 0) + { - // try to make this directory - rc = mkdir(currdir, mode); - if (rc != 0) { + // try to make this directory + rc = mkdir (currdir, mode); + if (rc != 0) + { - rc = -errno; - free(currdir); - return rc; - } - } + rc = -errno; + free (currdir); + return rc; } - - i++; + } } - free(currdir); - return 0; + i++; + } + + free (currdir); + return 0; } // try to remove a path of directories // the must all be emtpy // return 0 on success // return negative on error -int vdev_rmdirs(char const *dirp) +int +vdev_rmdirs (char const *dirp) { - char *dirname = NULL; - int rc = 0; + char *dirname = NULL; + int rc = 0; - if (dirp == NULL) { - return -EINVAL; - } + if (dirp == NULL) + { + return -EINVAL; + } - dirname = strdup(dirp); + dirname = strdup (dirp); - while (strlen(dirname) > 0) { + while (strlen (dirname) > 0) + { - rc = rmdir(dirname); + rc = rmdir (dirname); - if (rc != 0) { + if (rc != 0) + { - rc = -errno; - break; - } else { + rc = -errno; + break; + } + else + { - char *tmp = vdev_dirname(dirname, NULL); - if (tmp == NULL) { - return -ENOMEM; - } + char *tmp = vdev_dirname (dirname, NULL); + if (tmp == NULL) + { + return -ENOMEM; + } - free(dirname); + free (dirname); - dirname = tmp; - } + dirname = tmp; } + } - free(dirname); - return rc; + free (dirname); + return rc; } // parse an unsigned 64-bit number @@ -1036,90 +1193,101 @@ int vdev_rmdirs(char const *dirp) // return the number, and set *success to true if we succeeded // return -EINVAL if any of hte arguments were NULL // return 0, LLONG_MAX, or LLONG_MIN if we failed -uint64_t vdev_parse_uint64(char const *uint64_str, bool * success) +uint64_t +vdev_parse_uint64 (char const *uint64_str, bool * success) { - if (uint64_str == NULL || success == NULL) { - return -EINVAL; - } + if (uint64_str == NULL || success == NULL) + { + return -EINVAL; + } - char *tmp = NULL; - uint64_t uid = (uint64_t) strtoll(uint64_str, &tmp, 10); + char *tmp = NULL; + uint64_t uid = (uint64_t) strtoll (uint64_str, &tmp, 10); - if (tmp == uint64_str) { - *success = false; - } else { - *success = true; - } + if (tmp == uint64_str) + { + *success = false; + } + else + { + *success = true; + } - return uid; + return uid; } // given a null-terminated key=value string, chomp it into a null-terminated key and value. // return the original length of the string. // return -EINVAL if any argument is NULL // return negative on error -int vdev_keyvalue_next(char *keyvalue, char **key, char **value) +int +vdev_keyvalue_next (char *keyvalue, char **key, char **value) { - if (keyvalue == NULL || key == NULL || value == NULL) { - return -EINVAL; - } + if (keyvalue == NULL || key == NULL || value == NULL) + { + return -EINVAL; + } - int ret = strlen(keyvalue); - char *tmp = NULL; + int ret = strlen (keyvalue); + char *tmp = NULL; - // find the '=' - tmp = strchr(keyvalue, '='); - if (tmp == NULL) { + // find the '=' + tmp = strchr (keyvalue, '='); + if (tmp == NULL) + { - return -EINVAL; - } + return -EINVAL; + } - *key = keyvalue; - *tmp = '\0'; - tmp++; + *key = keyvalue; + *tmp = '\0'; + tmp++; - *value = tmp; + *value = tmp; - return ret; + return ret; } // set up the library // always succeeds -void vdev_setup_global(void) +void +vdev_setup_global (void) { - // seed random from monotonic clock - struct timespec ts_mono; - struct timespec ts_clock; - int rc = 0; - unsigned short seedv[3]; - int32_t lower_32; + // seed random from monotonic clock + struct timespec ts_mono; + struct timespec ts_clock; + int rc = 0; + unsigned short seedv[3]; + int32_t lower_32; - clock_gettime(CLOCK_MONOTONIC, &ts_mono); - clock_gettime(CLOCK_REALTIME, &ts_clock); + clock_gettime (CLOCK_MONOTONIC, &ts_mono); + clock_gettime (CLOCK_REALTIME, &ts_clock); - // NOTE: it's okay to use uninitialized memory for the random seed, - // so we don't really care if clock_gettime fails + // NOTE: it's okay to use uninitialized memory for the random seed, + // so we don't really care if clock_gettime fails - lower_32 = ts_mono.tv_nsec + ts_clock.tv_nsec; - memcpy(seedv, &lower_32, 3); + lower_32 = ts_mono.tv_nsec + ts_clock.tv_nsec; + memcpy (seedv, &lower_32, 3); - seed48(seedv); + seed48 (seedv); } // portable cast pthread_t to uint64_t -unsigned long long int vdev_pthread_self(void) +unsigned long long int +vdev_pthread_self (void) { - union { - pthread_t t; - uint64_t i; - } vdev_pthread; + union + { + pthread_t t; + uint64_t i; + } vdev_pthread; - vdev_pthread.i = 0; - vdev_pthread.t = pthread_self(); + vdev_pthread.i = 0; + vdev_pthread.t = pthread_self (); - return vdev_pthread.i; + return vdev_pthread.i; } diff --git a/libvdev/util.h b/libvdev/util.h index 5e3bf95..2c45d50 100644 --- a/libvdev/util.h +++ b/libvdev/util.h @@ -171,46 +171,48 @@ typedef int (*vdev_dirent_loader_at_t) (int, struct dirent * dent, void *); C_LINKAGE_BEGIN // debug functions -void vdev_set_debug_level(int d); -void vdev_set_error_level(int e); -int vdev_get_debug_level(); -int vdev_get_error_level(); -int vdev_enable_syslog(); +void vdev_set_debug_level (int d); +void vdev_set_error_level (int e); +int vdev_get_debug_level (); +int vdev_get_error_level (); +int vdev_enable_syslog (); // system functions -int vdev_daemonize(void); -int vdev_subprocess(char const *cmd, char *const env[], char **output, - size_t max_output, int stderr_fd, int *exit_status, - bool use_shell); -int vdev_log_redirect(char const *logfile_path); -int vdev_pidfile_write(char const *pidfile_path); +int vdev_daemonize (void); +int vdev_subprocess (char const *cmd, char *const env[], char **output, + size_t max_output, int stderr_fd, int *exit_status, + bool use_shell); +int vdev_log_redirect (char const *logfile_path); +int vdev_pidfile_write (char const *pidfile_path); // parser functions -int vdev_keyvalue_next(char *keyvalue, char **key, char **value); -uint64_t vdev_parse_uint64(char const *uint64_str, bool * success); +int vdev_keyvalue_next (char *keyvalue, char **key, char **value); +uint64_t vdev_parse_uint64 (char const *uint64_str, bool * success); // I/O functions -ssize_t vdev_read_uninterrupted(int fd, char *buf, size_t len); -ssize_t vdev_write_uninterrupted(int fd, char const *buf, size_t len); -int vdev_read_file(char const *path, char *buf, size_t len); -int vdev_write_file(char const *path, char const *buf, size_t len, int flags, - mode_t mode); +ssize_t vdev_read_uninterrupted (int fd, char *buf, size_t len); +ssize_t vdev_write_uninterrupted (int fd, char const *buf, size_t len); +int vdev_read_file (char const *path, char *buf, size_t len); +int vdev_write_file (char const *path, char const *buf, size_t len, int flags, + mode_t mode); // directory I/O -int vdev_load_all(char const *dir_path, vdev_dirent_loader_t loader, void *cls); -int vdev_load_all_at(int dirfd, vdev_dirent_loader_at_t loader_at, void *cls); -int vdev_mkdirs(char const *dirp, int start, mode_t mode); -int vdev_rmdirs(char const *dirp); +int vdev_load_all (char const *dir_path, vdev_dirent_loader_t loader, + void *cls); +int vdev_load_all_at (int dirfd, vdev_dirent_loader_at_t loader_at, + void *cls); +int vdev_mkdirs (char const *dirp, int start, mode_t mode); +int vdev_rmdirs (char const *dirp); // misc -char *vdev_fullpath(char const *root, char const *path, char *dest); -char *vdev_dirname(char const *path, char *dest); -size_t vdev_basename_len(char const *path); -char *vdev_basename(char const *path, char *dest); -unsigned long long int vdev_pthread_self(void); +char *vdev_fullpath (char const *root, char const *path, char *dest); +char *vdev_dirname (char const *path, char *dest); +size_t vdev_basename_len (char const *path); +char *vdev_basename (char const *path, char *dest); +unsigned long long int vdev_pthread_self (void); // setup -void vdev_setup_global(void); +void vdev_setup_global (void); C_LINKAGE_END #endif diff --git a/tools/udev_to_vdev/udev_rule.h b/tools/udev_to_vdev/udev_rule.h index a25edd3..c9a46e6 100644 --- a/tools/udev_to_vdev/udev_rule.h +++ b/tools/udev_to_vdev/udev_rule.h @@ -14,60 +14,80 @@ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH RE #include #include - template < typename type > class lockable:public type { - public: - inline lockable(void):m_locked(false) { - } - inline bool is_locked(void) const { - return m_locked; - } inline void lock(void) { - m_locked = true; - } - inline void unlock(void) { - m_locked = false; - } - private: - bool m_locked; +template < typename type > class lockable:public type +{ +public: + inline lockable (void):m_locked (false) + { + } + inline bool is_locked (void) const + { + return m_locked; + } + inline void lock (void) + { + m_locked = true; + } + inline void unlock (void) + { + m_locked = false; + } +private: + bool m_locked; }; // parser a single field -struct udev_field_t { - inline udev_field_t(void) { - subname.lock(); - } bool operator <<(const char &input) throw(const char *); // returns false when full - void clear(void); - inline bool full(void) const { - return value.is_locked(); - } inline bool empty(void)const { - return value.empty(); - } lockable < std::string > name; - lockable < std::string > subname; - lockable < std::string > op; - lockable < std::string > value; +struct udev_field_t +{ + inline udev_field_t (void) + { + subname.lock (); + } bool operator << (const char &input) throw (const char *); // returns false when full + void clear (void); + inline bool full (void) const + { + return value.is_locked (); + } + inline bool empty (void) const + { + return value.empty (); + } + lockable < std::string > name; + lockable < std::string > subname; + lockable < std::string > op; + lockable < std::string > value; }; // parses all fields in rule -struct udev_rule_t { - inline udev_rule_t(void):line_continues(false) { - fields.emplace_back(); - comment.lock(); - } bool operator <<(const char &input) throw(const char *); // returns false when full - void clear(void); - inline bool full(void) const { - return fields.is_locked(); - } inline bool empty(void)const { - return fields.back().empty(); - } lockable < std::list < udev_field_t >> fields; - bool line_continues; - lockable < std::string > comment; +struct udev_rule_t +{ + inline udev_rule_t (void):line_continues (false) + { + fields.emplace_back (); + comment.lock (); + } bool operator << (const char &input) throw (const char *); // returns false when full + void clear (void); + inline bool full (void) const + { + return fields.is_locked (); + } + inline bool empty (void) const + { + return fields.back ().empty (); + } + lockable < std::list < udev_field_t >> fields; + bool line_continues; + lockable < std::string > comment; }; -struct udev_rule_file_t { - inline udev_rule_file_t(void) { - rules.emplace_back(); - } void operator <<(const char &input) throw(const char *); - void clear(void); +struct udev_rule_file_t +{ + inline udev_rule_file_t (void) + { + rules.emplace_back (); + } void operator << (const char &input) throw (const char *); + void clear (void); - std::list < udev_rule_t > rules; + std::list < udev_rule_t > rules; }; -#endif // UDEV_FIELD_H +#endif // UDEV_FIELD_H diff --git a/vdevd/device.c b/vdevd/device.c index 2e23970..715c838 100644 --- a/vdevd/device.c +++ b/vdevd/device.c @@ -768,8 +768,8 @@ vdev_device_put_metadata (struct vdev_device_request *req) // try to update instead rc = vdev_device_put_metadata_item (base_dir, VDEV_METADATA_PARAM_INSTANCE, - req->state-> - config->instance_str, + req->state->config-> + instance_str, O_WRONLY | O_TRUNC, 0644); } @@ -1079,8 +1079,8 @@ vdev_device_add (struct vdev_device_request *req) // file is not expected to exist rc = mknod (fp, - req->mode | req->state-> - config->default_mode, req->dev); + req->mode | req->state->config-> + default_mode, req->dev); } else { diff --git a/vdevd/helpers/LINUX/common.c b/vdevd/helpers/LINUX/common.c index cd83c28..5491ad6 100644 --- a/vdevd/helpers/LINUX/common.c +++ b/vdevd/helpers/LINUX/common.c @@ -53,244 +53,286 @@ #include "common.h" -int vdev_util_replace_whitespace(const char *str, char *to, size_t len) +int +vdev_util_replace_whitespace (const char *str, char *to, size_t len) { - size_t i, j; - - /* strip trailing whitespace */ - len = strnlen(str, len); - while (len && isspace(str[len - 1])) { - len--; - } - - /* strip leading whitespace */ - i = 0; - while (isspace(str[i]) && (i < len)) { - i++; - } - - j = 0; - while (i < len) { - /* substitute multiple whitespace with a single '_' */ - if (isspace(str[i])) { - while (isspace(str[i])) { - i++; - } - to[j++] = '_'; - } - to[j++] = str[i++]; - } - to[j] = '\0'; - return 0; + size_t i, j; + + /* strip trailing whitespace */ + len = strnlen (str, len); + while (len && isspace (str[len - 1])) + { + len--; + } + + /* strip leading whitespace */ + i = 0; + while (isspace (str[i]) && (i < len)) + { + i++; + } + + j = 0; + while (i < len) + { + /* substitute multiple whitespace with a single '_' */ + if (isspace (str[i])) + { + while (isspace (str[i])) + { + i++; + } + to[j++] = '_'; + } + to[j++] = str[i++]; + } + to[j] = '\0'; + return 0; } -int vdev_whitelisted_char_for_devnode(char c, const char *white) +int +vdev_whitelisted_char_for_devnode (char c, const char *white) { - if ((c >= '0' && c <= '9') || - (c >= 'A' && c <= 'Z') || - (c >= 'a' && c <= 'z') || - strchr("#+-.:=@_", c) != NULL || - (white != NULL && strchr(white, c) != NULL)) { - return 1; - } - return 0; + if ((c >= '0' && c <= '9') || + (c >= 'A' && c <= 'Z') || + (c >= 'a' && c <= 'z') || + strchr ("#+-.:=@_", c) != NULL || + (white != NULL && strchr (white, c) != NULL)) + { + return 1; + } + return 0; } -static inline bool vdev_is_unicode_valid(uint32_t ch) +static inline bool +vdev_is_unicode_valid (uint32_t ch) { - if (ch >= 0x110000) { - /* End of unicode space */ - return false; - } - - if ((ch & 0xFFFFF800) == 0xD800) { - /* Reserved area for UTF-16 */ - return false; - } - if ((ch >= 0xFDD0) && (ch <= 0xFDEF)) { - /* Reserved */ - return false; - } - - if ((ch & 0xFFFE) == 0xFFFE) { - /* BOM (Byte Order Mark) */ - return false; - } - return true; + if (ch >= 0x110000) + { + /* End of unicode space */ + return false; + } + + if ((ch & 0xFFFFF800) == 0xD800) + { + /* Reserved area for UTF-16 */ + return false; + } + if ((ch >= 0xFDD0) && (ch <= 0xFDEF)) + { + /* Reserved */ + return false; + } + + if ((ch & 0xFFFE) == 0xFFFE) + { + /* BOM (Byte Order Mark) */ + return false; + } + return true; } /* count of characters used to encode one unicode char */ -static int vdev_utf8_encoded_expected_len(const char *str) +static int +vdev_utf8_encoded_expected_len (const char *str) { - unsigned char c; - - c = (unsigned char)str[0]; - if (c < 0x80) { - return 1; - } - - if ((c & 0xe0) == 0xc0) { - return 2; - } - if ((c & 0xf0) == 0xe0) { - return 3; - } - if ((c & 0xf8) == 0xf0) { - return 4; - } - if ((c & 0xfc) == 0xf8) { - return 5; - } - if ((c & 0xfe) == 0xfc) { - return 6; - } - - return 0; + unsigned char c; + + c = (unsigned char) str[0]; + if (c < 0x80) + { + return 1; + } + + if ((c & 0xe0) == 0xc0) + { + return 2; + } + if ((c & 0xf0) == 0xe0) + { + return 3; + } + if ((c & 0xf8) == 0xf0) + { + return 4; + } + if ((c & 0xfc) == 0xf8) + { + return 5; + } + if ((c & 0xfe) == 0xfc) + { + return 6; + } + + return 0; } /* decode one unicode char */ -int vdev_utf8_encoded_to_unichar(const char *str) +int +vdev_utf8_encoded_to_unichar (const char *str) { - int unichar, len, i; - - len = vdev_utf8_encoded_expected_len(str); - - switch (len) { - case 1: - return (int)str[0]; - case 2: - unichar = str[0] & 0x1f; - break; - case 3: - unichar = (int)str[0] & 0x0f; - break; - case 4: - unichar = (int)str[0] & 0x07; - break; - case 5: - unichar = (int)str[0] & 0x03; - break; - case 6: - unichar = (int)str[0] & 0x01; - break; - default: - return -EINVAL; - } - - for (i = 1; i < len; i++) { - if (((int)str[i] & 0xc0) != 0x80) { - return -EINVAL; - } - unichar <<= 6; - unichar |= (int)str[i] & 0x3f; - } - - return unichar; + int unichar, len, i; + + len = vdev_utf8_encoded_expected_len (str); + + switch (len) + { + case 1: + return (int) str[0]; + case 2: + unichar = str[0] & 0x1f; + break; + case 3: + unichar = (int) str[0] & 0x0f; + break; + case 4: + unichar = (int) str[0] & 0x07; + break; + case 5: + unichar = (int) str[0] & 0x03; + break; + case 6: + unichar = (int) str[0] & 0x01; + break; + default: + return -EINVAL; + } + + for (i = 1; i < len; i++) + { + if (((int) str[i] & 0xc0) != 0x80) + { + return -EINVAL; + } + unichar <<= 6; + unichar |= (int) str[i] & 0x3f; + } + + return unichar; } /* expected size used to encode one unicode char */ -static int vdev_utf8_unichar_to_encoded_len(int unichar) +static int +vdev_utf8_unichar_to_encoded_len (int unichar) { - if (unichar < 0x80) { - return 1; - } - if (unichar < 0x800) { - return 2; - } - if (unichar < 0x10000) { - return 3; - } - if (unichar < 0x200000) { - return 4; - } - if (unichar < 0x4000000) { - return 5; - } - - return 6; + if (unichar < 0x80) + { + return 1; + } + if (unichar < 0x800) + { + return 2; + } + if (unichar < 0x10000) + { + return 3; + } + if (unichar < 0x200000) + { + return 4; + } + if (unichar < 0x4000000) + { + return 5; + } + + return 6; } /* validate one encoded unicode char and return its length */ -int vdev_utf8_encoded_valid_unichar(const char *str) +int +vdev_utf8_encoded_valid_unichar (const char *str) { - int len, unichar, i; - - len = vdev_utf8_encoded_expected_len(str); - if (len == 0) { - return -EINVAL; - } - - /* ascii is valid */ - if (len == 1) { - return 1; - } - - /* check if expected encoded chars are available */ - for (i = 0; i < len; i++) { - if ((str[i] & 0x80) != 0x80) { - return -EINVAL; - } - } - - unichar = vdev_utf8_encoded_to_unichar(str); - - /* check if encoded length matches encoded value */ - if (vdev_utf8_unichar_to_encoded_len(unichar) != len) { - return -EINVAL; - } - - /* check if value has valid range */ - if (!vdev_is_unicode_valid(unichar)) { - return -EINVAL; - } - - return len; + int len, unichar, i; + + len = vdev_utf8_encoded_expected_len (str); + if (len == 0) + { + return -EINVAL; + } + + /* ascii is valid */ + if (len == 1) + { + return 1; + } + + /* check if expected encoded chars are available */ + for (i = 0; i < len; i++) + { + if ((str[i] & 0x80) != 0x80) + { + return -EINVAL; + } + } + + unichar = vdev_utf8_encoded_to_unichar (str); + + /* check if encoded length matches encoded value */ + if (vdev_utf8_unichar_to_encoded_len (unichar) != len) + { + return -EINVAL; + } + + /* check if value has valid range */ + if (!vdev_is_unicode_valid (unichar)) + { + return -EINVAL; + } + + return len; } /* allow chars in whitelist, plain ascii, hex-escaping and valid utf8 */ -int vdev_util_replace_chars(char *str, const char *white) +int +vdev_util_replace_chars (char *str, const char *white) { - size_t i = 0; - int replaced = 0; + size_t i = 0; + int replaced = 0; - while (str[i] != '\0') { - int len; - - if (vdev_whitelisted_char_for_devnode(str[i], white)) { - i++; - continue; - } + while (str[i] != '\0') + { + int len; - /* accept hex encoding */ - if (str[i] == '\\' && str[i + 1] == 'x') { - i += 2; - continue; - } + if (vdev_whitelisted_char_for_devnode (str[i], white)) + { + i++; + continue; + } - /* accept valid utf8 */ - len = vdev_utf8_encoded_valid_unichar(&str[i]); - if (len > 1) { - i += len; - continue; - } + /* accept hex encoding */ + if (str[i] == '\\' && str[i + 1] == 'x') + { + i += 2; + continue; + } - /* if space is allowed, replace whitespace with ordinary space */ - if (isspace(str[i]) && white != NULL - && strchr(white, ' ') != NULL) { - str[i] = ' '; - i++; - replaced++; - continue; - } + /* accept valid utf8 */ + len = vdev_utf8_encoded_valid_unichar (&str[i]); + if (len > 1) + { + i += len; + continue; + } - /* everything else is replaced with '_' */ - str[i] = '_'; - i++; - replaced++; + /* if space is allowed, replace whitespace with ordinary space */ + if (isspace (str[i]) && white != NULL && strchr (white, ' ') != NULL) + { + str[i] = ' '; + i++; + replaced++; + continue; } - return replaced; + + /* everything else is replaced with '_' */ + str[i] = '_'; + i++; + replaced++; + } + return replaced; } /** @@ -305,81 +347,98 @@ int vdev_util_replace_chars(char *str, const char *white) * * Returns: 0 if the entire string was copied, non-zero otherwise. **/ -int vdev_util_encode_string(const char *str, char *str_enc, size_t len) +int +vdev_util_encode_string (const char *str, char *str_enc, size_t len) { - size_t i, j; - - if (str == NULL || str_enc == NULL) { - return -EINVAL; - } - - for (i = 0, j = 0; str[i] != '\0'; i++) { - int seqlen; - - seqlen = vdev_utf8_encoded_valid_unichar(&str[i]); - if (seqlen > 1) { - - if (len - j < (size_t) seqlen) { - goto err; - } - memcpy(&str_enc[j], &str[i], seqlen); - j += seqlen; - i += (seqlen - 1); - } else if (str[i] == '\\' - || !vdev_whitelisted_char_for_devnode(str[i], - NULL)) { - - if (len - j < 4) { - goto err; - } - sprintf(&str_enc[j], "\\x%02x", (unsigned char)str[i]); - j += 4; - } else { - - if (len - j < 1) { - goto err; - } - - str_enc[j] = str[i]; - j++; - } - } - if (len - j < 1) { - goto err; - } - - str_enc[j] = '\0'; - return 0; - err: - return -EINVAL; + size_t i, j; + + if (str == NULL || str_enc == NULL) + { + return -EINVAL; + } + + for (i = 0, j = 0; str[i] != '\0'; i++) + { + int seqlen; + + seqlen = vdev_utf8_encoded_valid_unichar (&str[i]); + if (seqlen > 1) + { + + if (len - j < (size_t) seqlen) + { + goto err; + } + memcpy (&str_enc[j], &str[i], seqlen); + j += seqlen; + i += (seqlen - 1); + } + else if (str[i] == '\\' + || !vdev_whitelisted_char_for_devnode (str[i], NULL)) + { + + if (len - j < 4) + { + goto err; + } + sprintf (&str_enc[j], "\\x%02x", (unsigned char) str[i]); + j += 4; + } + else + { + + if (len - j < 1) + { + goto err; + } + + str_enc[j] = str[i]; + j++; + } + } + if (len - j < 1) + { + goto err; + } + + str_enc[j] = '\0'; + return 0; +err: + return -EINVAL; } // remove trailing whitespace -int vdev_util_rstrip(char *str) +int +vdev_util_rstrip (char *str) { - size_t i = strlen(str); + size_t i = strlen (str); - if (i == 0) { - return 0; - } + if (i == 0) + { + return 0; + } - i--; + i--; - while (i >= 0) { + while (i >= 0) + { - if (isspace(str[i])) { - str[i] = 0; - i--; - continue; - } else { - // not space - break; - } + if (isspace (str[i])) + { + str[i] = 0; + i--; + continue; + } + else + { + // not space + break; } + } - return 0; + return 0; } // global list of properties discovered @@ -389,369 +448,411 @@ static struct vdev_property *vdev_property_tail = NULL; // append to a linked list of properties discovered // return 0 on success // return -ENOMEM if we run out of memory -int vdev_property_add(char const *name, char const *value) +int +vdev_property_add (char const *name, char const *value) { - struct vdev_property *prop = - (struct vdev_property *)calloc(sizeof(struct vdev_property), 1); + struct vdev_property *prop = + (struct vdev_property *) calloc (sizeof (struct vdev_property), 1); - if (prop == NULL) { - return -ENOMEM; - } + if (prop == NULL) + { + return -ENOMEM; + } - prop->name = strdup(name); - if (prop->name == NULL) { + prop->name = strdup (name); + if (prop->name == NULL) + { - free(prop); - return -ENOMEM; - } + free (prop); + return -ENOMEM; + } - prop->value = strdup(value); - if (prop->value == NULL) { + prop->value = strdup (value); + if (prop->value == NULL) + { - free(prop->name); - free(prop); - return -ENOMEM; - } + free (prop->name); + free (prop); + return -ENOMEM; + } - prop->next = NULL; + prop->next = NULL; - if (vdev_property_head == NULL) { - vdev_property_head = prop; - vdev_property_tail = prop; - } + if (vdev_property_head == NULL) + { + vdev_property_head = prop; + vdev_property_tail = prop; + } - else { - vdev_property_tail->next = prop; - vdev_property_tail = prop; - } + else + { + vdev_property_tail->next = prop; + vdev_property_tail = prop; + } - return 0; + return 0; } // print all properties as sourceable environmet variables // always succeeds -int vdev_property_print(void) +int +vdev_property_print (void) { - if (vdev_property_head != NULL) { + if (vdev_property_head != NULL) + { - for (struct vdev_property * itr = vdev_property_head; - itr != NULL; itr = itr->next) { - printf("%s='%s'\n", itr->name, itr->value); - } + for (struct vdev_property * itr = vdev_property_head; + itr != NULL; itr = itr->next) + { + printf ("%s='%s'\n", itr->name, itr->value); + } - // print the variable VDEV_PROPERTIES to include all property names - printf("VDEV_PROPERTIES=\""); - for (struct vdev_property * itr = vdev_property_head; - itr != NULL; itr = itr->next) { - printf("%s ", itr->name); - } - printf("\"\n"); + // print the variable VDEV_PROPERTIES to include all property names + printf ("VDEV_PROPERTIES=\""); + for (struct vdev_property * itr = vdev_property_head; + itr != NULL; itr = itr->next) + { + printf ("%s ", itr->name); } + printf ("\"\n"); + } - return 0; + return 0; } // free all properties // always succeeds -int vdev_property_free_all(void) +int +vdev_property_free_all (void) { - if (vdev_property_head != NULL) { + if (vdev_property_head != NULL) + { - for (struct vdev_property * itr = vdev_property_head; - itr != NULL;) { + for (struct vdev_property * itr = vdev_property_head; itr != NULL;) + { - struct vdev_property *itr_next = itr->next; + struct vdev_property *itr_next = itr->next; - free(itr->name); - free(itr->value); - free(itr); + free (itr->name); + free (itr->value); + free (itr); - itr = itr_next; - } + itr = itr_next; } + } - vdev_property_head = NULL; - vdev_property_tail = NULL; + vdev_property_head = NULL; + vdev_property_tail = NULL; - return 0; + return 0; } // read a file, masking EINTR // return the number of bytes read on success // return -errno on failure -ssize_t vdev_read_uninterrupted(int fd, char *buf, size_t len) +ssize_t +vdev_read_uninterrupted (int fd, char *buf, size_t len) { - ssize_t num_read = 0; + ssize_t num_read = 0; - if (buf == NULL) { - return -EINVAL; - } + if (buf == NULL) + { + return -EINVAL; + } - while ((unsigned)num_read < len) { - ssize_t nr = read(fd, buf + num_read, len - num_read); - if (nr < 0) { + while ((unsigned) num_read < len) + { + ssize_t nr = read (fd, buf + num_read, len - num_read); + if (nr < 0) + { - int errsv = -errno; - if (errsv == -EINTR) { - continue; - } + int errsv = -errno; + if (errsv == -EINTR) + { + continue; + } - return errsv; - } - if (nr == 0) { - break; - } - - num_read += nr; + return errsv; + } + if (nr == 0) + { + break; } - return num_read; + num_read += nr; + } + + return num_read; } // read a sysfs attribute -int vdev_sysfs_read_attr(char const *sysfs_device_path, char const *attr_name, - char **value, size_t * value_len) +int +vdev_sysfs_read_attr (char const *sysfs_device_path, char const *attr_name, + char **value, size_t * value_len) { - int rc = 0; - int fd = 0; - struct stat sb; - char attr_path[4097]; + int rc = 0; + int fd = 0; + struct stat sb; + char attr_path[4097]; - sprintf(attr_path, "%s/%s", sysfs_device_path, attr_name); + sprintf (attr_path, "%s/%s", sysfs_device_path, attr_name); - rc = stat(attr_path, &sb); - if (rc != 0) { + rc = stat (attr_path, &sb); + if (rc != 0) + { - rc = -errno; - return rc; - } - // regular file? return the contents - if (S_ISREG(sb.st_mode)) { + rc = -errno; + return rc; + } + // regular file? return the contents + if (S_ISREG (sb.st_mode)) + { - fd = open(attr_path, O_RDONLY); - if (fd < 0) { + fd = open (attr_path, O_RDONLY); + if (fd < 0) + { - rc = -errno; + rc = -errno; - fprintf(stderr, "[WARN]: open('%s') errno = %d\n", - attr_path, rc); - return rc; - } + fprintf (stderr, "[WARN]: open('%s') errno = %d\n", attr_path, rc); + return rc; + } - char *ret_value = (char *)calloc(sb.st_size + 1, 1); - if (ret_value == NULL) { + char *ret_value = (char *) calloc (sb.st_size + 1, 1); + if (ret_value == NULL) + { - close(fd); - return -ENOMEM; - } + close (fd); + return -ENOMEM; + } - rc = vdev_read_uninterrupted(fd, ret_value, sb.st_size); - if (rc < 0) { + rc = vdev_read_uninterrupted (fd, ret_value, sb.st_size); + if (rc < 0) + { - free(ret_value); - close(fd); - return rc; - } + free (ret_value); + close (fd); + return rc; + } - close(fd); + close (fd); - *value = ret_value; - *value_len = sb.st_size; + *value = ret_value; + *value_len = sb.st_size; - return 0; - } - // symlink? return the actual link - else if (S_ISLNK(sb.st_mode)) { + return 0; + } + // symlink? return the actual link + else if (S_ISLNK (sb.st_mode)) + { - char *ret_value = (char *)calloc(sb.st_size + 1, 1); - if (ret_value == NULL) { + char *ret_value = (char *) calloc (sb.st_size + 1, 1); + if (ret_value == NULL) + { - return -ENOMEM; - } + return -ENOMEM; + } - rc = readlink(attr_path, ret_value, sb.st_size); - if (rc < 0) { + rc = readlink (attr_path, ret_value, sb.st_size); + if (rc < 0) + { - rc = -errno; - fprintf(stderr, "[WARN]: readlink('%s') errno = %d\n", - attr_path, rc); + rc = -errno; + fprintf (stderr, "[WARN]: readlink('%s') errno = %d\n", + attr_path, rc); - free(ret_value); - return rc; - } + free (ret_value); + return rc; + } - *value = ret_value; - *value_len = sb.st_size + 1; + *value = ret_value; + *value_len = sb.st_size + 1; - return 0; - } - // not sure what to do here - else { + return 0; + } + // not sure what to do here + else + { - return -EINVAL; - } + return -EINVAL; + } } // find a field value from a uevent // return 0 on success // return -ENOENT if the key is not found // return -ENOMEM if oom. -int vdev_sysfs_uevent_get_key(char const *uevent_buf, size_t uevent_buflen, - char const *key, char **value, size_t * value_len) +int +vdev_sysfs_uevent_get_key (char const *uevent_buf, size_t uevent_buflen, + char const *key, char **value, size_t * value_len) { - char *tmp = NULL; - char *tok = NULL; - char *buf_ptr = NULL; - char *delim = NULL; - int rc = 0; + char *tmp = NULL; + char *tok = NULL; + char *buf_ptr = NULL; + char *delim = NULL; + int rc = 0; - // NOTE: zero-terminate - char *buf_dup = (char *)calloc(uevent_buflen + 1, 1); - if (buf_dup == NULL) { - return -ENOMEM; - } + // NOTE: zero-terminate + char *buf_dup = (char *) calloc (uevent_buflen + 1, 1); + if (buf_dup == NULL) + { + return -ENOMEM; + } - memcpy(buf_dup, uevent_buf, uevent_buflen); - buf_ptr = buf_dup; + memcpy (buf_dup, uevent_buf, uevent_buflen); + buf_ptr = buf_dup; - while (1) { + while (1) + { - // next line - tok = strtok_r(buf_ptr, "\n", &tmp); - buf_ptr = NULL; + // next line + tok = strtok_r (buf_ptr, "\n", &tmp); + buf_ptr = NULL; - if (tok == NULL) { - rc = -ENOENT; - break; - } - // read key - delim = index(tok, '='); - if (delim == NULL) { - continue; - } + if (tok == NULL) + { + rc = -ENOENT; + break; + } + // read key + delim = index (tok, '='); + if (delim == NULL) + { + continue; + } - *delim = '\0'; + *delim = '\0'; - // match key? - if (strcmp(tok, key) == 0) { + // match key? + if (strcmp (tok, key) == 0) + { - // get value - *value_len = strlen(delim + 1); - *value = (char *)calloc(*value_len + 1, 1); + // get value + *value_len = strlen (delim + 1); + *value = (char *) calloc (*value_len + 1, 1); - if (*value == NULL) { - rc = -ENOMEM; - break; - } + if (*value == NULL) + { + rc = -ENOMEM; + break; + } - strcpy(*value, delim + 1); - break; - } - - *delim = '='; + strcpy (*value, delim + 1); + break; } - free(buf_dup); - return rc; + *delim = '='; + } + + free (buf_dup); + return rc; } // read a whole file into RAM // return 0 on success, and set *file_buf and *file_buf_len // return negative on error -int vdev_read_file(char const *path, char **file_buf, size_t * file_buf_len) +int +vdev_read_file (char const *path, char **file_buf, size_t * file_buf_len) { - int fd = 0; - struct stat sb; - char *buf = NULL; - int rc = 0; + int fd = 0; + struct stat sb; + char *buf = NULL; + int rc = 0; - // get size - rc = stat(path, &sb); - if (rc != 0) { + // get size + rc = stat (path, &sb); + if (rc != 0) + { - rc = -errno; - return rc; - } - // read the uevent file itself - buf = (char *)calloc(sb.st_size, 1); - if (buf == NULL) { + rc = -errno; + return rc; + } + // read the uevent file itself + buf = (char *) calloc (sb.st_size, 1); + if (buf == NULL) + { - return -ENOMEM; - } + return -ENOMEM; + } - fd = open(path, O_RDONLY); - if (fd < 0) { + fd = open (path, O_RDONLY); + if (fd < 0) + { - rc = -errno; - free(buf); - return rc; - } + rc = -errno; + free (buf); + return rc; + } - rc = vdev_read_uninterrupted(fd, buf, sb.st_size); - if (rc < 0) { + rc = vdev_read_uninterrupted (fd, buf, sb.st_size); + if (rc < 0) + { - close(fd); - free(buf); - return rc; - } + close (fd); + free (buf); + return rc; + } - close(fd); + close (fd); - *file_buf = buf; - *file_buf_len = rc; + *file_buf = buf; + *file_buf_len = rc; - return 0; + return 0; } // find a field in the uevent buffer, using vdev_read_file and vdev_sysfs_uevent_get_key // return 0 on success, and set *value and *value_len // return negative on error -int vdev_sysfs_uevent_read_key(char const *sysfs_device_path, - char const *uevent_key, char **uevent_value, - size_t * uevent_value_len) +int +vdev_sysfs_uevent_read_key (char const *sysfs_device_path, + char const *uevent_key, char **uevent_value, + size_t * uevent_value_len) { - int rc = 0; + int rc = 0; - char *uevent_buf = NULL; - size_t uevent_len = 0; + char *uevent_buf = NULL; + size_t uevent_len = 0; - char *uevent_path = - (char *)calloc(strlen(sysfs_device_path) + strlen("/uevent") + 1, - 1); - if (uevent_path == NULL) { + char *uevent_path = + (char *) calloc (strlen (sysfs_device_path) + strlen ("/uevent") + 1, + 1); + if (uevent_path == NULL) + { - return -ENOMEM; - } + return -ENOMEM; + } - sprintf(uevent_path, "%s/uevent", sysfs_device_path); + sprintf (uevent_path, "%s/uevent", sysfs_device_path); - // get uevent - rc = vdev_read_file(uevent_path, &uevent_buf, &uevent_len); - if (rc < 0) { + // get uevent + rc = vdev_read_file (uevent_path, &uevent_buf, &uevent_len); + if (rc < 0) + { - if (DEBUG) { - fprintf(stderr, - "[WARN]: vdev_read_file('%s') rc = %d\n", - uevent_path, rc); - } - return rc; + if (DEBUG) + { + fprintf (stderr, + "[WARN]: vdev_read_file('%s') rc = %d\n", uevent_path, rc); } - // get devtype - rc = vdev_sysfs_uevent_get_key(uevent_buf, uevent_len, uevent_key, - uevent_value, uevent_value_len); + return rc; + } + // get devtype + rc = vdev_sysfs_uevent_get_key (uevent_buf, uevent_len, uevent_key, + uevent_value, uevent_value_len); - free(uevent_buf); - free(uevent_path); + free (uevent_buf); + free (uevent_path); - return rc; + return rc; } // walk up a sysfs device path to find the ancestor device with the given subsystem and devtype @@ -759,315 +860,341 @@ int vdev_sysfs_uevent_read_key(char const *sysfs_device_path, // return 0 on success // return -ENOMEM on OOM // return -ENOENT if a subsystem or uevent was not found, when one was expected -int vdev_sysfs_get_parent_with_subsystem_devtype(char const *sysfs_device_path, - char const *subsystem_name, - char const *devtype_name, - char **devpath, - size_t * devpath_len) +int +vdev_sysfs_get_parent_with_subsystem_devtype (char const *sysfs_device_path, + char const *subsystem_name, + char const *devtype_name, + char **devpath, + size_t * devpath_len) { - char cur_dir[4097]; - char subsystem_path[4097]; - char subsystem_link[4097]; - char uevent_path[4097]; - - memset(subsystem_path, 0, 4097); - memset(subsystem_link, 0, 4097); - - char *tmp = NULL; - int rc = 0; - char *uevent_buf = NULL; - size_t uevent_len = 0; - char *devtype = NULL; - size_t devtype_len = 0; - char *parent_device = NULL; - size_t parent_device_len = 0; - - strcpy(cur_dir, sysfs_device_path); + char cur_dir[4097]; + char subsystem_path[4097]; + char subsystem_link[4097]; + char uevent_path[4097]; + + memset (subsystem_path, 0, 4097); + memset (subsystem_link, 0, 4097); + + char *tmp = NULL; + int rc = 0; + char *uevent_buf = NULL; + size_t uevent_len = 0; + char *devtype = NULL; + size_t devtype_len = 0; + char *parent_device = NULL; + size_t parent_device_len = 0; + + strcpy (cur_dir, sysfs_device_path); + + while (1) + { + + // get parent device + rc = vdev_sysfs_get_parent_device (cur_dir, &parent_device, + &parent_device_len); + if (rc != 0) + { + break; + } + // subsystem? + sprintf (subsystem_path, "%s/subsystem", parent_device); + + memset (subsystem_link, 0, 4096); + + rc = readlink (subsystem_path, subsystem_link, 4096); + if (rc < 0) + { + + rc = -errno; + if (rc != -ENOENT) + { + fprintf (stderr, + "[WARN]: readlink('%s') errno = %d\n", + subsystem_path, rc); + } + + free (parent_device); + parent_device = NULL; + return rc; + } + // get subsystem name... + tmp = rindex (subsystem_link, '/'); + + if (tmp != NULL && strcmp (tmp + 1, subsystem_name) != 0) + { + + // subsystem does not match + // crawl up to the parent + strcpy (cur_dir, parent_device); + + free (parent_device); + parent_device = NULL; + continue; + } + // subsystem matches... + *tmp = 0; + + if (devtype_name != NULL) + { + + // get uevent + // get DEVTYPE from uevent + // make uevent path + sprintf (uevent_path, "%s/uevent", parent_device); + + // get uevent + rc = vdev_read_file (uevent_path, &uevent_buf, &uevent_len); + if (rc < 0) + { + + fprintf (stderr, + "[WARN]: vdev_read_file('%s') rc = %d\n", + uevent_path, rc); + + free (parent_device); + parent_device = NULL; + return rc; + } + // get devtype + rc = vdev_sysfs_uevent_get_key (uevent_buf, uevent_len, + "DEVTYPE", &devtype, &devtype_len); + free (uevent_buf); + + if (rc != 0) + { + + if (rc == -ENOENT) + { + + // not found + // next parent + strcpy (cur_dir, parent_device); + + free (parent_device); + parent_device = NULL; + + continue; + } + else + { - while (1) { + free (parent_device); + parent_device = NULL; - // get parent device - rc = vdev_sysfs_get_parent_device(cur_dir, &parent_device, - &parent_device_len); - if (rc != 0) { - break; + return rc; } - // subsystem? - sprintf(subsystem_path, "%s/subsystem", parent_device); + } + // matches? + if (strcmp (devtype, devtype_name) == 0) + { - memset(subsystem_link, 0, 4096); + free (devtype); - rc = readlink(subsystem_path, subsystem_link, 4096); - if (rc < 0) { + // this is the path to the device + *devpath = parent_device; + *devpath_len = strlen (parent_device); - rc = -errno; - if (rc != -ENOENT) { - fprintf(stderr, - "[WARN]: readlink('%s') errno = %d\n", - subsystem_path, rc); - } + // found! + rc = 0; + break; + } + else + { + // no match. + // next device + free (devtype); - free(parent_device); - parent_device = NULL; - return rc; - } - // get subsystem name... - tmp = rindex(subsystem_link, '/'); + strcpy (cur_dir, parent_device); - if (tmp != NULL && strcmp(tmp + 1, subsystem_name) != 0) { + free (parent_device); + parent_device = NULL; + continue; + } + } + else + { - // subsystem does not match - // crawl up to the parent - strcpy(cur_dir, parent_device); + // match only on subsystem + *devpath = parent_device; + *devpath_len = strlen (parent_device); - free(parent_device); - parent_device = NULL; - continue; - } - // subsystem matches... - *tmp = 0; - - if (devtype_name != NULL) { - - // get uevent - // get DEVTYPE from uevent - // make uevent path - sprintf(uevent_path, "%s/uevent", parent_device); - - // get uevent - rc = vdev_read_file(uevent_path, &uevent_buf, - &uevent_len); - if (rc < 0) { - - fprintf(stderr, - "[WARN]: vdev_read_file('%s') rc = %d\n", - uevent_path, rc); - - free(parent_device); - parent_device = NULL; - return rc; - } - // get devtype - rc = vdev_sysfs_uevent_get_key(uevent_buf, uevent_len, - "DEVTYPE", &devtype, - &devtype_len); - free(uevent_buf); - - if (rc != 0) { - - if (rc == -ENOENT) { - - // not found - // next parent - strcpy(cur_dir, parent_device); - - free(parent_device); - parent_device = NULL; - - continue; - } else { - - free(parent_device); - parent_device = NULL; - - return rc; - } - } - // matches? - if (strcmp(devtype, devtype_name) == 0) { - - free(devtype); - - // this is the path to the device - *devpath = parent_device; - *devpath_len = strlen(parent_device); - - // found! - rc = 0; - break; - } else { - // no match. - // next device - free(devtype); - - strcpy(cur_dir, parent_device); - - free(parent_device); - parent_device = NULL; - continue; - } - } else { - - // match only on subsystem - *devpath = parent_device; - *devpath_len = strlen(parent_device); - - rc = 0; - break; - } + rc = 0; + break; } + } - return rc; + return rc; } // make a device path using the symlink in the contained 'device' entry -int vdev_sysfs_read_device_path(char const *sysfs_dir, char **devpath, - size_t * devpath_len) +int +vdev_sysfs_read_device_path (char const *sysfs_dir, char **devpath, + size_t * devpath_len) { - int rc = 0; - struct stat sb; + int rc = 0; + struct stat sb; - char path_buf[8193]; + char path_buf[8193]; - sprintf(path_buf, "%s/device", sysfs_dir); + sprintf (path_buf, "%s/device", sysfs_dir); - // is there a link here? - rc = stat(path_buf, &sb); - if (rc != 0) { + // is there a link here? + rc = stat (path_buf, &sb); + if (rc != 0) + { - rc = -errno; - return rc; - } - // must be a link - if (!S_ISLNK(sb.st_mode)) { + rc = -errno; + return rc; + } + // must be a link + if (!S_ISLNK (sb.st_mode)) + { - rc = -EINVAL; - return rc; - } - // follow that link! - *devpath = realpath(path_buf, NULL); - if (*devpath == NULL) { - return -ENOMEM; - } + rc = -EINVAL; + return rc; + } + // follow that link! + *devpath = realpath (path_buf, NULL); + if (*devpath == NULL) + { + return -ENOMEM; + } - *devpath_len = strlen(*devpath); + *devpath_len = strlen (*devpath); - return 0; + return 0; } // search sysfs for the device path corresponding to a given subsystem and sysname. // fill in devpath if found. // heavily inspired by udev_device_new_from_subsystem_sysname -int vdev_sysfs_device_path_from_subsystem_sysname(char const *sysfs_mount, - char const *subsystem, - char const *sysname, - char **devpath, - size_t * devpath_len) +int +vdev_sysfs_device_path_from_subsystem_sysname (char const *sysfs_mount, + char const *subsystem, + char const *sysname, + char **devpath, + size_t * devpath_len) { - int rc = 0; - struct stat sb; - char path_buf[8193]; + int rc = 0; + struct stat sb; + char path_buf[8193]; - memset(path_buf, 0, 8193); + memset (path_buf, 0, 8193); - if (strcmp(subsystem, "subsystem") == 0) { + if (strcmp (subsystem, "subsystem") == 0) + { - sprintf(path_buf, "%s/subsystem/%s/", sysfs_mount, sysname); - rc = stat(path_buf, &sb); + sprintf (path_buf, "%s/subsystem/%s/", sysfs_mount, sysname); + rc = stat (path_buf, &sb); - if (rc == 0) { - return vdev_sysfs_read_device_path(path_buf, devpath, - devpath_len); - } + if (rc == 0) + { + return vdev_sysfs_read_device_path (path_buf, devpath, devpath_len); + } - sprintf(path_buf, "%s/bus/%s/", sysfs_mount, sysname); - rc = stat(path_buf, &sb); + sprintf (path_buf, "%s/bus/%s/", sysfs_mount, sysname); + rc = stat (path_buf, &sb); - if (rc == 0) { - return vdev_sysfs_read_device_path(path_buf, devpath, - devpath_len); - } + if (rc == 0) + { + return vdev_sysfs_read_device_path (path_buf, devpath, devpath_len); + } - sprintf(path_buf, "%s/class/%s/", sysfs_mount, sysname); - rc = stat(path_buf, &sb); + sprintf (path_buf, "%s/class/%s/", sysfs_mount, sysname); + rc = stat (path_buf, &sb); - if (rc == 0) { - return vdev_sysfs_read_device_path(path_buf, devpath, - devpath_len); - } + if (rc == 0) + { + return vdev_sysfs_read_device_path (path_buf, devpath, devpath_len); } + } - if (strcmp(subsystem, "module") == 0) { + if (strcmp (subsystem, "module") == 0) + { - sprintf(path_buf, "%s/module/%s/", sysfs_mount, sysname); - rc = stat(path_buf, &sb); + sprintf (path_buf, "%s/module/%s/", sysfs_mount, sysname); + rc = stat (path_buf, &sb); - if (rc == 0) { - return vdev_sysfs_read_device_path(path_buf, devpath, - devpath_len); - } + if (rc == 0) + { + return vdev_sysfs_read_device_path (path_buf, devpath, devpath_len); } + } - if (strcmp(subsystem, "drivers") == 0) { + if (strcmp (subsystem, "drivers") == 0) + { - char driver_prefix[4096]; - char *driver = NULL; + char driver_prefix[4096]; + char *driver = NULL; - sprintf(driver_prefix, sysname); - driver = strchr(driver_prefix, ':'); + sprintf (driver_prefix, sysname); + driver = strchr (driver_prefix, ':'); - if (driver != NULL) { + if (driver != NULL) + { - // trim header - *driver = '\0'; - driver++; + // trim header + *driver = '\0'; + driver++; - sprintf(path_buf, "%s/subsystem/%s/drivers/%s/", - sysfs_mount, driver_prefix, driver); - rc = stat(path_buf, &sb); + sprintf (path_buf, "%s/subsystem/%s/drivers/%s/", + sysfs_mount, driver_prefix, driver); + rc = stat (path_buf, &sb); - if (rc == 0) { - return vdev_sysfs_read_device_path(path_buf, - devpath, - devpath_len); - } + if (rc == 0) + { + return vdev_sysfs_read_device_path (path_buf, + devpath, devpath_len); + } - sprintf(path_buf, "%s/bus/%s/drivers/%s/", sysfs_mount, - driver_prefix, driver); - rc = stat(path_buf, &sb); + sprintf (path_buf, "%s/bus/%s/drivers/%s/", sysfs_mount, + driver_prefix, driver); + rc = stat (path_buf, &sb); - if (rc == 0) { - return vdev_sysfs_read_device_path(path_buf, - devpath, - devpath_len); - } - } else { + if (rc == 0) + { + return vdev_sysfs_read_device_path (path_buf, + devpath, devpath_len); + } + } + else + { - return -EINVAL; - } + return -EINVAL; } + } - sprintf(path_buf, "%s/subsystem/%s/devices/%s/", sysfs_mount, subsystem, - sysname); - rc = stat(path_buf, &sb); + sprintf (path_buf, "%s/subsystem/%s/devices/%s/", sysfs_mount, subsystem, + sysname); + rc = stat (path_buf, &sb); - if (rc == 0) { - return vdev_sysfs_read_device_path(path_buf, devpath, - devpath_len); - } + if (rc == 0) + { + return vdev_sysfs_read_device_path (path_buf, devpath, devpath_len); + } - sprintf(path_buf, "%s/bus/%s/devices/%s/", sysfs_mount, subsystem, - sysname); - rc = stat(path_buf, &sb); + sprintf (path_buf, "%s/bus/%s/devices/%s/", sysfs_mount, subsystem, + sysname); + rc = stat (path_buf, &sb); - if (rc == 0) { - return vdev_sysfs_read_device_path(path_buf, devpath, - devpath_len); - } + if (rc == 0) + { + return vdev_sysfs_read_device_path (path_buf, devpath, devpath_len); + } - sprintf(path_buf, "%s/class/%s/%s", sysfs_mount, subsystem, sysname); - rc = stat(path_buf, &sb); + sprintf (path_buf, "%s/class/%s/%s", sysfs_mount, subsystem, sysname); + rc = stat (path_buf, &sb); - if (rc == 0) { + if (rc == 0) + { - return vdev_sysfs_read_device_path(path_buf, devpath, - devpath_len); - } + return vdev_sysfs_read_device_path (path_buf, devpath, devpath_len); + } - return -ENOENT; + return -ENOENT; } // get the parent device of a given device, using sysfs. @@ -1078,242 +1205,271 @@ int vdev_sysfs_device_path_from_subsystem_sysname(char const *sysfs_mount, // return -ENOENT if this dev has no parent // return -errno if stat'ing the parent path fails // return -ENOMEM if OOM -int vdev_sysfs_get_parent_device(char const *dev_path, char **ret_parent_device, - size_t * ret_parent_device_len) +int +vdev_sysfs_get_parent_device (char const *dev_path, char **ret_parent_device, + size_t * ret_parent_device_len) { - char *parent_path = NULL; - size_t parent_path_len = 0; - struct stat sb; - int rc = 0; + char *parent_path = NULL; + size_t parent_path_len = 0; + struct stat sb; + int rc = 0; - char *delim = NULL; + char *delim = NULL; - parent_path = - (char *)calloc(strlen(dev_path) + 1 + strlen("/uevent"), 1); - if (parent_path == NULL) { - return -ENOMEM; - } + parent_path = + (char *) calloc (strlen (dev_path) + 1 + strlen ("/uevent"), 1); + if (parent_path == NULL) + { + return -ENOMEM; + } - strcpy(parent_path, dev_path); + strcpy (parent_path, dev_path); - while (strlen(parent_path) > 0) { + while (strlen (parent_path) > 0) + { - // lop off the child - delim = rindex(parent_path, '/'); - if (delim == NULL) { + // lop off the child + delim = rindex (parent_path, '/'); + if (delim == NULL) + { - // invalid - free(parent_path); - return -EINVAL; - } + // invalid + free (parent_path); + return -EINVAL; + } - if (delim == parent_path) { + if (delim == parent_path) + { - // reached / - free(parent_path); - return -ENOENT; - } + // reached / + free (parent_path); + return -ENOENT; + } - while (*delim == '/' && delim != parent_path) { - *delim = '\0'; - delim--; - } + while (*delim == '/' && delim != parent_path) + { + *delim = '\0'; + delim--; + } - parent_path_len = strlen(parent_path); + parent_path_len = strlen (parent_path); - // verify that this is a device... - strcat(parent_path, "/uevent"); + // verify that this is a device... + strcat (parent_path, "/uevent"); - rc = stat(parent_path, &sb); - if (rc != 0) { + rc = stat (parent_path, &sb); + if (rc != 0) + { - // not a device - // remove /uevent - parent_path[parent_path_len] = '\0'; - continue; - } else { + // not a device + // remove /uevent + parent_path[parent_path_len] = '\0'; + continue; + } + else + { - // device! - break; - } + // device! + break; } + } - // lop off /uevent - parent_path[parent_path_len] = '\0'; + // lop off /uevent + parent_path[parent_path_len] = '\0'; - *ret_parent_device = parent_path; - *ret_parent_device_len = parent_path_len; + *ret_parent_device = parent_path; + *ret_parent_device_len = parent_path_len; - return 0; + return 0; } // get the subsystem from a device path -int vdev_sysfs_read_subsystem(char const *devpath, char **ret_subsystem, - size_t * ret_subsystem_len) +int +vdev_sysfs_read_subsystem (char const *devpath, char **ret_subsystem, + size_t * ret_subsystem_len) { - int rc = 0; - char linkpath[4097]; - size_t linkpath_len = 4097; - char *subsystem_path = NULL; - char *subsystem = NULL; + int rc = 0; + char linkpath[4097]; + size_t linkpath_len = 4097; + char *subsystem_path = NULL; + char *subsystem = NULL; - subsystem_path = - (char *)calloc(strlen(devpath) + 1 + strlen("/subsystem") + 1, 1); - if (subsystem_path == NULL) { - return -ENOMEM; - } + subsystem_path = + (char *) calloc (strlen (devpath) + 1 + strlen ("/subsystem") + 1, 1); + if (subsystem_path == NULL) + { + return -ENOMEM; + } - sprintf(subsystem_path, "%s/subsystem", devpath); + sprintf (subsystem_path, "%s/subsystem", devpath); - memset(linkpath, 0, 4097); + memset (linkpath, 0, 4097); - rc = readlink(subsystem_path, linkpath, linkpath_len); - if (rc < 0) { + rc = readlink (subsystem_path, linkpath, linkpath_len); + if (rc < 0) + { - rc = -errno; - log_error("readlink('%s') rc = %d\n", subsystem_path, rc); - free(subsystem_path); - return rc; - } + rc = -errno; + log_error ("readlink('%s') rc = %d\n", subsystem_path, rc); + free (subsystem_path); + return rc; + } - free(subsystem_path); + free (subsystem_path); - subsystem = rindex(linkpath, '/'); - if (subsystem == NULL) { - return -EINVAL; - } + subsystem = rindex (linkpath, '/'); + if (subsystem == NULL) + { + return -EINVAL; + } - *ret_subsystem = strdup(subsystem + 1); - *ret_subsystem_len = strlen(subsystem + 1); + *ret_subsystem = strdup (subsystem + 1); + *ret_subsystem_len = strlen (subsystem + 1); - if (*ret_subsystem == NULL) { - return -ENOMEM; - } + if (*ret_subsystem == NULL) + { + return -ENOMEM; + } - return 0; + return 0; } // get the sysname from the device path -int vdev_sysfs_get_sysname(char const *devpath, char **ret_sysname, - size_t * ret_sysname_len) +int +vdev_sysfs_get_sysname (char const *devpath, char **ret_sysname, + size_t * ret_sysname_len) { - char const *delim = NULL; - char *sysname = NULL; - size_t len = 0; + char const *delim = NULL; + char *sysname = NULL; + size_t len = 0; - delim = rindex(devpath, '/'); - if (delim == NULL) { + delim = rindex (devpath, '/'); + if (delim == NULL) + { - return -EINVAL; - } + return -EINVAL; + } - sysname = strdup(delim + 1); + sysname = strdup (delim + 1); - if (sysname == NULL) { - return -ENOMEM; - } + if (sysname == NULL) + { + return -ENOMEM; + } - /* some devices have '!' in their name, change that to '/' */ - while (sysname[len] != '\0') { + /* some devices have '!' in their name, change that to '/' */ + while (sysname[len] != '\0') + { - if (sysname[len] == '!') { - sysname[len] = '/'; - } - - len++; + if (sysname[len] == '!') + { + sysname[len] = '/'; } - *ret_sysname = sysname; - *ret_sysname_len = len; + len++; + } + + *ret_sysname = sysname; + *ret_sysname_len = len; - return 0; + return 0; } // get the sysnum of a device from the device path -int vdev_sysfs_get_sysnum(char const *devpath, int *sysnum) +int +vdev_sysfs_get_sysnum (char const *devpath, int *sysnum) { - int rc = 0; - char *sysname = NULL; - size_t sysname_len = 0; - int i = 0; + int rc = 0; + char *sysname = NULL; + size_t sysname_len = 0; + int i = 0; - // last digits at the end of the sysname - rc = vdev_sysfs_get_sysname(devpath, &sysname, &sysname_len); - if (rc != 0) { - return rc; - } + // last digits at the end of the sysname + rc = vdev_sysfs_get_sysname (devpath, &sysname, &sysname_len); + if (rc != 0) + { + return rc; + } - while (isdigit(sysname[sysname_len - i])) { - i++; - } - i++; + while (isdigit (sysname[sysname_len - i])) + { + i++; + } + i++; - *sysnum = strtol(sysname + sysname_len - i, NULL, 10); + *sysnum = strtol (sysname + sysname_len - i, NULL, 10); - free(sysname); + free (sysname); - return 0; + return 0; } // get the absolute sysfs device path from a major/minor pair and device type // return 0 on success, and set *syspath and *syspath_len // return negative on error -int vdev_sysfs_get_syspath_from_device(char const *sysfs_mountpoint, - mode_t mode, unsigned int major, - unsigned int minor, char **syspath, - size_t * syspath_len) +int +vdev_sysfs_get_syspath_from_device (char const *sysfs_mountpoint, + mode_t mode, unsigned int major, + unsigned int minor, char **syspath, + size_t * syspath_len) { - char *devpath = (char *)calloc(strlen(sysfs_mountpoint) + 4097, 1); - char linkbuf[4097]; + char *devpath = (char *) calloc (strlen (sysfs_mountpoint) + 4097, 1); + char linkbuf[4097]; - if (devpath == NULL) { - return -ENOMEM; - } + if (devpath == NULL) + { + return -ENOMEM; + } - int rc = 0; + int rc = 0; - memset(linkbuf, 0, 4097); + memset (linkbuf, 0, 4097); - if (S_ISCHR(mode)) { + if (S_ISCHR (mode)) + { - // character device - sprintf(devpath, "%s/dev/char/%u:%u", sysfs_mountpoint, major, - minor); - } else if (S_ISBLK(mode)) { + // character device + sprintf (devpath, "%s/dev/char/%u:%u", sysfs_mountpoint, major, minor); + } + else if (S_ISBLK (mode)) + { - // block device - sprintf(devpath, "%s/dev/block/%u:%u", sysfs_mountpoint, major, - minor); - } else { + // block device + sprintf (devpath, "%s/dev/block/%u:%u", sysfs_mountpoint, major, minor); + } + else + { - free(devpath); - return -EINVAL; - } + free (devpath); + return -EINVAL; + } - rc = readlink(devpath, linkbuf, 4097); - if (rc < 0) { + rc = readlink (devpath, linkbuf, 4097); + if (rc < 0) + { - rc = -errno; - free(devpath); - return rc; - } - // link should start with "../devices" - if (strncmp(linkbuf, "../../devices", strlen("../../devices")) != 0) { + rc = -errno; + free (devpath); + return rc; + } + // link should start with "../devices" + if (strncmp (linkbuf, "../../devices", strlen ("../../devices")) != 0) + { - // sysfs structure changed??? - free(devpath); - return -EIO; - } + // sysfs structure changed??? + free (devpath); + return -EIO; + } - sprintf(devpath, "%s/%s", sysfs_mountpoint, linkbuf + strlen("../../")); + sprintf (devpath, "%s/%s", sysfs_mountpoint, linkbuf + strlen ("../../")); - *syspath = devpath; - *syspath_len = strlen(devpath); + *syspath = devpath; + *syspath_len = strlen (devpath); - return 0; + return 0; } diff --git a/vdevd/helpers/LINUX/common.h b/vdevd/helpers/LINUX/common.h index 7bb43eb..bcc0763 100644 --- a/vdevd/helpers/LINUX/common.h +++ b/vdevd/helpers/LINUX/common.h @@ -90,63 +90,67 @@ #endif // expanding list of properties -struct vdev_property { +struct vdev_property +{ - char *name; - char *value; + char *name; + char *value; - struct vdev_property *next; + struct vdev_property *next; }; // string methods (hold-overs from udev) -int vdev_util_replace_whitespace(const char *str, char *to, size_t len); -int vdev_whitelisted_char_for_devnode(char c, const char *white); -int vdev_utf8_encoded_to_unichar(const char *str); -int vdev_utf8_encoded_valid_unichar(const char *str); -int vdev_util_replace_chars(char *str, const char *white); -int vdev_util_encode_string(const char *str, char *str_enc, size_t len); -int vdev_util_rstrip(char *str); +int vdev_util_replace_whitespace (const char *str, char *to, size_t len); +int vdev_whitelisted_char_for_devnode (char c, const char *white); +int vdev_utf8_encoded_to_unichar (const char *str); +int vdev_utf8_encoded_valid_unichar (const char *str); +int vdev_util_replace_chars (char *str, const char *white); +int vdev_util_encode_string (const char *str, char *str_enc, size_t len); +int vdev_util_rstrip (char *str); // device properties -int vdev_property_add(char const *name, char const *value); -int vdev_property_print(void); -int vdev_property_free_all(void); +int vdev_property_add (char const *name, char const *value); +int vdev_property_print (void); +int vdev_property_free_all (void); // sysfs methods -int vdev_sysfs_read_attr(char const *sysfs_device_path, char const *attr_name, - char **value, size_t * value_len); -int vdev_sysfs_uevent_read_key(char const *sysfs_device_path, - char const *uevent_key, char **uevent_value, - size_t * uevent_value_len); -int vdev_sysfs_uevent_get_key(char const *uevent_buf, size_t uevent_buflen, - char const *key, char **value, - size_t * value_len); -int vdev_sysfs_get_parent_with_subsystem_devtype(char const *sysfs_device_path, - char const *subsystem_name, - char const *devtype_name, - char **devpath, - size_t * devpath_len); -int vdev_sysfs_read_device_path(char const *sysfs_dir, char **devpath, - size_t * devpath_len); -int vdev_sysfs_device_path_from_subsystem_sysname(char const *sysfs_mount, - char const *subsystem, - char const *sysname, +int vdev_sysfs_read_attr (char const *sysfs_device_path, + char const *attr_name, char **value, + size_t * value_len); +int vdev_sysfs_uevent_read_key (char const *sysfs_device_path, + char const *uevent_key, char **uevent_value, + size_t * uevent_value_len); +int vdev_sysfs_uevent_get_key (char const *uevent_buf, size_t uevent_buflen, + char const *key, char **value, + size_t * value_len); +int vdev_sysfs_get_parent_with_subsystem_devtype (char const + *sysfs_device_path, + char const *subsystem_name, + char const *devtype_name, char **devpath, size_t * devpath_len); -int vdev_sysfs_get_parent_device(char const *dev_path, char **ret_parent_device, - size_t * ret_parent_device_len); -int vdev_sysfs_read_subsystem(char const *devpath, char **ret_subsystem, - size_t * ret_subsystem_len); -int vdev_sysfs_get_sysname(char const *devpath, char **sysname, - size_t * sysname_len); -int vdev_sysfs_get_sysnum(char const *devpath, int *sysnum); -int vdev_sysfs_get_syspath_from_device(char const *sysfs_mountpoint, - mode_t mode, unsigned int major, - unsigned int minor, char **syspath, - size_t * syspath_len); +int vdev_sysfs_read_device_path (char const *sysfs_dir, char **devpath, + size_t * devpath_len); +int vdev_sysfs_device_path_from_subsystem_sysname (char const *sysfs_mount, + char const *subsystem, + char const *sysname, + char **devpath, + size_t * devpath_len); +int vdev_sysfs_get_parent_device (char const *dev_path, + char **ret_parent_device, + size_t * ret_parent_device_len); +int vdev_sysfs_read_subsystem (char const *devpath, char **ret_subsystem, + size_t * ret_subsystem_len); +int vdev_sysfs_get_sysname (char const *devpath, char **sysname, + size_t * sysname_len); +int vdev_sysfs_get_sysnum (char const *devpath, int *sysnum); +int vdev_sysfs_get_syspath_from_device (char const *sysfs_mountpoint, + mode_t mode, unsigned int major, + unsigned int minor, char **syspath, + size_t * syspath_len); // file operations -ssize_t vdev_read_uninterrupted(int fd, char *buf, size_t len); -int vdev_read_file(char const *path, char **file_buf, size_t * file_buf_len); +ssize_t vdev_read_uninterrupted (int fd, char *buf, size_t len); +int vdev_read_file (char const *path, char **file_buf, size_t * file_buf_len); #endif diff --git a/vdevd/helpers/LINUX/echo_n.c b/vdevd/helpers/LINUX/echo_n.c index d9c7e2e..f8deca9 100644 --- a/vdevd/helpers/LINUX/echo_n.c +++ b/vdevd/helpers/LINUX/echo_n.c @@ -1,14 +1,17 @@ #include // echo -n implementation, where -n means "no newline" -int main(int argc, char **argv) +int +main (int argc, char **argv) { - if (argc == 1) { - return 0; - } - for (int i = 1; i < argc - 1; i++) { - printf("%s ", argv[i]); - } - printf("%s", argv[argc - 1]); - return 0; + if (argc == 1) + { + return 0; + } + for (int i = 1; i < argc - 1; i++) + { + printf ("%s ", argv[i]); + } + printf ("%s", argv[argc - 1]); + return 0; } diff --git a/vdevd/helpers/LINUX/event-put.c b/vdevd/helpers/LINUX/event-put.c index d5549cf..0253bca 100644 --- a/vdevd/helpers/LINUX/event-put.c +++ b/vdevd/helpers/LINUX/event-put.c @@ -34,478 +34,528 @@ static char g_dev_events[PATH_MAX + 1]; // make a path to an event in the global queue // event_path must have at least PATH_MAX+1 bytes -int make_event_path(uint64_t seqnum, char *event_path) +int +make_event_path (uint64_t seqnum, char *event_path) { - memset(event_path, 0, PATH_MAX + 1); + memset (event_path, 0, PATH_MAX + 1); - return snprintf(event_path, PATH_MAX, "%s/%" PRIu64, g_dev_events, - seqnum); + return snprintf (event_path, PATH_MAX, "%s/%" PRIu64, g_dev_events, seqnum); } // open the event file, exclusively, for writing. // make sure that only the UID/GID of this process (i.e. root) can access it. -int open_event(char *event_path) +int +open_event (char *event_path) { - int fd = 0; + int fd = 0; - fd = open(event_path, O_WRONLY | O_EXCL | O_CREAT, 0600); - if (fd < 0) { + fd = open (event_path, O_WRONLY | O_EXCL | O_CREAT, 0600); + if (fd < 0) + { - fd = -errno; - log_error("open('%s') rc = %d\n", event_path, fd); - return fd; - } + fd = -errno; + log_error ("open('%s') rc = %d\n", event_path, fd); + return fd; + } - return fd; + return fd; } // clear an event // return 0 on success // return -errno (from unlink(2)) on failure -int clear_event(char *event_path) +int +clear_event (char *event_path) { - int rc = unlink(event_path); - if (rc < 0) { + int rc = unlink (event_path); + if (rc < 0) + { - rc = -errno; - log_error("unlink('%s') rc = %d\n", event_path, rc); - } + rc = -errno; + log_error ("unlink('%s') rc = %d\n", event_path, rc); + } - return rc; + return rc; } // link all events to all directories that are siblings to the parent directory of the event path. // try to do so even if we fail to link in some cases // return 0 on success // return -errno if at least one failed -int multicast_event(uint64_t seqnum, char *event_path) +int +multicast_event (uint64_t seqnum, char *event_path) { - int rc = 0; - DIR *dirh = NULL; - struct dirent entry; - struct dirent *result = NULL; - char pathbuf[PATH_MAX + 1]; - - char event_queues_dir[PATH_MAX + 1]; - char global_queue_name[NAME_MAX + 1]; - - memset(event_queues_dir, 0, PATH_MAX + 1); - memset(global_queue_name, 0, NAME_MAX + 1); - - // parent nmae of event_path... - ssize_t i = strlen(event_path) - 1; - if (i < 0) { - return -EINVAL; - } - // shouldn't end in '/', but you never know... - while (i > 0 && event_path[i] == '/') { - i--; - } - - // skip event name - while (i > 0 && event_path[i] != '/') { - i--; + int rc = 0; + DIR *dirh = NULL; + struct dirent entry; + struct dirent *result = NULL; + char pathbuf[PATH_MAX + 1]; + + char event_queues_dir[PATH_MAX + 1]; + char global_queue_name[NAME_MAX + 1]; + + memset (event_queues_dir, 0, PATH_MAX + 1); + memset (global_queue_name, 0, NAME_MAX + 1); + + // parent nmae of event_path... + ssize_t i = strlen (event_path) - 1; + if (i < 0) + { + return -EINVAL; + } + // shouldn't end in '/', but you never know... + while (i > 0 && event_path[i] == '/') + { + i--; + } + + // skip event name + while (i > 0 && event_path[i] != '/') + { + i--; + } + + // skip '/' at the end of the parent name + while (i > 0 && event_path[i] == '/') + { + i--; + } + + if (i == 0) + { + + // event_path's parent is / + strcpy (global_queue_name, "."); + strcpy (event_queues_dir, "/"); + } + else + { + + ssize_t parent_end = i; + + while (i > 0 && event_path[i] != '/') + { + i--; } - // skip '/' at the end of the parent name - while (i > 0 && event_path[i] == '/') { - i--; - } + strncpy (global_queue_name, &event_path[i + 1], parent_end - i); + strncpy (event_queues_dir, event_path, i + 1); + } - if (i == 0) { + dirh = opendir (event_queues_dir); + if (dirh == NULL) + { - // event_path's parent is / - strcpy(global_queue_name, "."); - strcpy(event_queues_dir, "/"); - } else { + // OOM + rc = -errno; + return rc; + } - ssize_t parent_end = i; + do + { - while (i > 0 && event_path[i] != '/') { - i--; - } + // next entry + rc = readdir_r (dirh, &entry, &result); + if (rc != 0) + { - strncpy(global_queue_name, &event_path[i + 1], parent_end - i); - strncpy(event_queues_dir, event_path, i + 1); + // I/O error + log_error ("readdir_r('%s') rc = %d", event_queues_dir, rc); + break; + } + // skip . and .. + if (strcmp (entry.d_name, ".") == 0 || strcmp (entry.d_name, "..") == 0) + { + continue; + } + // skip non-directories + if (entry.d_type != DT_DIR) + { + continue; + } + // skip global queue + if (strcmp (global_queue_name, entry.d_name) == 0) + { + continue; + } + // link to this directory + snprintf (pathbuf, PATH_MAX, "%s/%s/%" PRIu64, event_queues_dir, + entry.d_name, seqnum); + + rc = link (event_path, pathbuf); + if (rc != 0) + { + + rc = errno; + log_error ("link('%s', '%s'): %s", event_path, pathbuf, + strerror (-rc)); + rc = 0; } - dirh = opendir(event_queues_dir); - if (dirh == NULL) { + } + while (result != NULL); - // OOM - rc = -errno; - return rc; - } + closedir (dirh); - do { - - // next entry - rc = readdir_r(dirh, &entry, &result); - if (rc != 0) { - - // I/O error - log_error("readdir_r('%s') rc = %d", event_queues_dir, - rc); - break; - } - // skip . and .. - if (strcmp(entry.d_name, ".") == 0 - || strcmp(entry.d_name, "..") == 0) { - continue; - } - // skip non-directories - if (entry.d_type != DT_DIR) { - continue; - } - // skip global queue - if (strcmp(global_queue_name, entry.d_name) == 0) { - continue; - } - // link to this directory - snprintf(pathbuf, PATH_MAX, "%s/%s/%" PRIu64, event_queues_dir, - entry.d_name, seqnum); - - rc = link(event_path, pathbuf); - if (rc != 0) { - - rc = errno; - log_error("link('%s', '%s'): %s", event_path, pathbuf, - strerror(-rc)); - rc = 0; - } - - } while (result != NULL); - - closedir(dirh); - - return rc; + return rc; } // print usage statement -int usage(char const *progname) +int +usage (char const *progname) { - int i = 0; - char const *usage_text[] = { - "Usage: ", progname, - " [-v] [-n SEQNUM] [-s SOURCE-QUEUE] [-t TARGET-QUEUES]\n", - "Options:\n", - " -n SEQNUM\n", - " Event sequence number. Must be\n", - " unique across all pending events.\n", - "\n", - " -s SOURCE-QUEUE\n", - " Path to the source event queue. An\n", - " event will be added as a child of this\n", - " directory, and linked into all directories\n", - " in TARGET-QUEUES. The default is\n", - " " DEFAULT_DEV_EVENTS, "\n", - "\n", - NULL - }; - - for (i = 0; usage_text[i] != NULL; i++) { - fprintf(stderr, usage_text[i]); - } - - return 0; + int i = 0; + char const *usage_text[] = { + "Usage: ", progname, + " [-v] [-n SEQNUM] [-s SOURCE-QUEUE] [-t TARGET-QUEUES]\n", + "Options:\n", + " -n SEQNUM\n", + " Event sequence number. Must be\n", + " unique across all pending events.\n", + "\n", + " -s SOURCE-QUEUE\n", + " Path to the source event queue. An\n", + " event will be added as a child of this\n", + " directory, and linked into all directories\n", + " in TARGET-QUEUES. The default is\n", + " " DEFAULT_DEV_EVENTS, "\n", + "\n", + NULL + }; + + for (i = 0; usage_text[i] != NULL; i++) + { + fprintf (stderr, usage_text[i]); + } + + return 0; } // print a verbose help statement -int help(char const *progname) +int +help (char const *progname) { - usage(progname); - - int i = 0; - char const *help_text[] = { - "This program reads a device event from standard input, such that\n", - "each line takes the form of KEY=VALUE. Valid keys and values are:\n", - "\n", - " DEVPATH=(/devices path) [REQUIRED]\n", - " SUBSYSTEM=(subsystem name) [REQUIRED]\n", - " SEQNUM=(kernel uevent sequence number) [REQUIRED if -n is not given]\n", - " DEVNAME=(/dev node path)\n", - " DEVLINKS=(space-separated list of symlinks)\n", - " TAGS=(colon-separated list of tags)\n", - " USEC_INITIALIZED=(microseconds since device initialization)\n", - " DRIVER=(name of device driver)\n", - " ACTION=(add, remove, change, move, etc.)\n", - " MAJOR=(major device number)\n", - " MINOR=(minor device number)\n", - " DEVPATH_OLD=(old device path (on move)\n", - " IFINDEX=(device interface index, e.g. for USB and network interfaces)\n", - " DEVMODE=(device node permission bits)\n", - " DEVUID=(device node UID)\n", - " DEVGID=(device node GID)\n", - "\n", - "Keys marked with [REQUIRED] must be present.\n", - "NOTE: events are limited to 8192 bytes.\n", - NULL - }; - - for (i = 0; help_text[i] != NULL; i++) { - fprintf(stderr, help_text[i]); - } - - return 0; + usage (progname); + + int i = 0; + char const *help_text[] = { + "This program reads a device event from standard input, such that\n", + "each line takes the form of KEY=VALUE. Valid keys and values are:\n", + "\n", + " DEVPATH=(/devices path) [REQUIRED]\n", + " SUBSYSTEM=(subsystem name) [REQUIRED]\n", + " SEQNUM=(kernel uevent sequence number) [REQUIRED if -n is not given]\n", + " DEVNAME=(/dev node path)\n", + " DEVLINKS=(space-separated list of symlinks)\n", + " TAGS=(colon-separated list of tags)\n", + " USEC_INITIALIZED=(microseconds since device initialization)\n", + " DRIVER=(name of device driver)\n", + " ACTION=(add, remove, change, move, etc.)\n", + " MAJOR=(major device number)\n", + " MINOR=(minor device number)\n", + " DEVPATH_OLD=(old device path (on move)\n", + " IFINDEX=(device interface index, e.g. for USB and network interfaces)\n", + " DEVMODE=(device node permission bits)\n", + " DEVUID=(device node UID)\n", + " DEVGID=(device node GID)\n", + "\n", + "Keys marked with [REQUIRED] must be present.\n", + "NOTE: events are limited to 8192 bytes.\n", + NULL + }; + + for (i = 0; help_text[i] != NULL; i++) + { + fprintf (stderr, help_text[i]); + } + + return 0; } // read, but mask EINTR // return number of bytes read on success // return -errno on I/O error // NOTE: must be async-safe! -ssize_t read_uninterrupted(int fd, char *buf, size_t len) +ssize_t +read_uninterrupted (int fd, char *buf, size_t len) { - ssize_t num_read = 0; + ssize_t num_read = 0; - if (buf == NULL) { - return -EINVAL; - } - - while ((unsigned)num_read < len) { - ssize_t nr = read(fd, buf + num_read, len - num_read); - if (nr < 0) { + if (buf == NULL) + { + return -EINVAL; + } - int errsv = -errno; - if (errsv == -EINTR) { - continue; - } + while ((unsigned) num_read < len) + { + ssize_t nr = read (fd, buf + num_read, len - num_read); + if (nr < 0) + { - return errsv; - } - if (nr == 0) { - break; - } + int errsv = -errno; + if (errsv == -EINTR) + { + continue; + } - num_read += nr; + return errsv; + } + if (nr == 0) + { + break; } - return num_read; + num_read += nr; + } + + return num_read; } // write, but mask EINTR // return number of bytes written on success // return -errno on I/O error -ssize_t write_uninterrupted(int fd, char const *buf, size_t len) +ssize_t +write_uninterrupted (int fd, char const *buf, size_t len) { - ssize_t num_written = 0; - - if (buf == NULL) { - return -EINVAL; - } + ssize_t num_written = 0; - while ((unsigned)num_written < len) { - ssize_t nw = write(fd, buf + num_written, len - num_written); - if (nw < 0) { + if (buf == NULL) + { + return -EINVAL; + } - int errsv = -errno; - if (errsv == -EINTR) { - continue; - } + while ((unsigned) num_written < len) + { + ssize_t nw = write (fd, buf + num_written, len - num_written); + if (nw < 0) + { - return errsv; - } - if (nw == 0) { - break; - } + int errsv = -errno; + if (errsv == -EINTR) + { + continue; + } - num_written += nw; + return errsv; } + if (nw == 0) + { + break; + } + + num_written += nw; + } - return num_written; + return num_written; } // entry point -int main(int argc, char **argv) +int +main (int argc, char **argv) { - int rc = 0; - uint64_t seqnum = 0; - int opt_index = 0; - int c = 0; - int fd = 0; - char *tmp = NULL; - char event_buf[8192]; - char event_buf_tmp[8292]; // has to hold event_buf plus an 8-byte sequence number - char event_path[PATH_MAX + 1]; - - bool have_seqnum = false; - ssize_t nr = 0; - char const *required_fields[] = { - "\nSUBSYSTEM=", - "\nDEVPATH=", - NULL - }; - - char target_queues[PATH_MAX + 1]; - - // default event queue - memset(g_dev_events, 0, PATH_MAX + 1); - memset(target_queues, 0, PATH_MAX + 1); - memset(event_path, 0, PATH_MAX + 1); - - strcpy(g_dev_events, DEFAULT_DEV_EVENTS); - - static struct option opts[] = { - {"source-queue", required_argument, 0, 's'}, - {"seqnum", required_argument, 0, 'n'}, - {"help", no_argument, 0, 'h'}, - {0, 0, 0, 0} - }; - - char const *optstr = "n:s:h"; - - while (rc == 0 && c != -1) { - - c = getopt_long(argc, argv, optstr, opts, &opt_index); - if (c == -1) { - - break; - } - - switch (c) { - - case 's':{ - - memset(g_dev_events, 0, PATH_MAX); - strncpy(g_dev_events, optarg, PATH_MAX); - break; - } + int rc = 0; + uint64_t seqnum = 0; + int opt_index = 0; + int c = 0; + int fd = 0; + char *tmp = NULL; + char event_buf[8192]; + char event_buf_tmp[8292]; // has to hold event_buf plus an 8-byte sequence number + char event_path[PATH_MAX + 1]; + + bool have_seqnum = false; + ssize_t nr = 0; + char const *required_fields[] = { + "\nSUBSYSTEM=", + "\nDEVPATH=", + NULL + }; + + char target_queues[PATH_MAX + 1]; + + // default event queue + memset (g_dev_events, 0, PATH_MAX + 1); + memset (target_queues, 0, PATH_MAX + 1); + memset (event_path, 0, PATH_MAX + 1); + + strcpy (g_dev_events, DEFAULT_DEV_EVENTS); + + static struct option opts[] = { + {"source-queue", required_argument, 0, 's'}, + {"seqnum", required_argument, 0, 'n'}, + {"help", no_argument, 0, 'h'}, + {0, 0, 0, 0} + }; + + char const *optstr = "n:s:h"; + + while (rc == 0 && c != -1) + { + + c = getopt_long (argc, argv, optstr, opts, &opt_index); + if (c == -1) + { + + break; + } - case 'n':{ + switch (c) + { - seqnum = (uint64_t) strtoull(optarg, &tmp, 10); - if (seqnum == 0 - && (tmp == optarg || *tmp != '\0')) { + case 's': + { - usage(argv[0]); - exit(1); - } + memset (g_dev_events, 0, PATH_MAX); + strncpy (g_dev_events, optarg, PATH_MAX); + break; + } - have_seqnum = true; - break; - } + case 'n': + { - case 'h':{ + seqnum = (uint64_t) strtoull (optarg, &tmp, 10); + if (seqnum == 0 && (tmp == optarg || *tmp != '\0')) + { - help(argv[0]); - exit(0); - } + usage (argv[0]); + exit (1); + } - default:{ + have_seqnum = true; + break; + } - fprintf(stderr, - "[ERROR] %s: Unrecognized option '%c'\n", - argv[0], c); - usage(argv[0]); - exit(1); - } - } - } + case 'h': + { - // get the event - memset(event_buf, 0, 8192); - nr = read_uninterrupted(STDIN_FILENO, event_buf, 8192); + help (argv[0]); + exit (0); + } - if (nr <= 0) { + default: + { - rc = -errno; - fprintf(stderr, - "[ERROR] %s: Failed to read event from stdin: %s\n", - argv[0], strerror(-rc)); - exit(1); + fprintf (stderr, + "[ERROR] %s: Unrecognized option '%c'\n", argv[0], c); + usage (argv[0]); + exit (1); + } } - // simple sanity check for requirements - for (int i = 0; required_fields[i] != NULL; i++) { - - if (strstr(event_buf, required_fields[i]) == NULL) { - - // head of line? with no leading '\n'? - if (strncmp - (event_buf, required_fields[i] + 1, - strlen(required_fields[i]) - 1) != 0) { - - fprintf(stderr, - "[ERROR] %s: Missing required field '%s'\n", - argv[0], required_fields[i] + 1); - fprintf(stderr, - "[ERROR] %s: Pass -h for a list of required fields\n", - argv[0]); - exit(1); - } - } + } + + // get the event + memset (event_buf, 0, 8192); + nr = read_uninterrupted (STDIN_FILENO, event_buf, 8192); + + if (nr <= 0) + { + + rc = -errno; + fprintf (stderr, + "[ERROR] %s: Failed to read event from stdin: %s\n", + argv[0], strerror (-rc)); + exit (1); + } + // simple sanity check for requirements + for (int i = 0; required_fields[i] != NULL; i++) + { + + if (strstr (event_buf, required_fields[i]) == NULL) + { + + // head of line? with no leading '\n'? + if (strncmp + (event_buf, required_fields[i] + 1, + strlen (required_fields[i]) - 1) != 0) + { + + fprintf (stderr, + "[ERROR] %s: Missing required field '%s'\n", + argv[0], required_fields[i] + 1); + fprintf (stderr, + "[ERROR] %s: Pass -h for a list of required fields\n", + argv[0]); + exit (1); + } } + } - // do we have a seqnum? - if (!have_seqnum) { - - char *seqnum_str = strstr(event_buf, "SEQNUM="); - - // go find it in the device event - if (seqnum_str == NULL) { - - fprintf(stderr, - "[ERROR] %s: Missing SEQNUM. Pass -n or include SEQNUM= in the input.\n", - argv[0]); - exit(1); - } - // is it a valid seqnum? - seqnum = - (uint64_t) strtoull(seqnum_str + strlen("SEQNUM="), &tmp, - 10); - if (seqnum == 0 - && (tmp == seqnum_str + strlen("SEQNUM=") - || *tmp != '\n')) { - - // invalid seqnum - fprintf(stderr, - "[ERROR] %s: Invalid SEQNUM. Pass -n or include a valid SEQNUM in the input.\n", - argv[0]); - exit(1); - } - } - // send it off! - make_event_path(seqnum, event_path); + // do we have a seqnum? + if (!have_seqnum) + { - fd = open_event(event_path); - if (fd < 0) { + char *seqnum_str = strstr (event_buf, "SEQNUM="); - fprintf(stderr, "[ERROR] %s: Failed to open '%s': %s\n", - argv[0], event_path, strerror(-fd)); - exit(1); - } + // go find it in the device event + if (seqnum_str == NULL) + { - rc = write_uninterrupted(fd, event_buf, nr); - if (rc < 0) { - - fprintf(stderr, "[ERROR] %s: Failed to write '%s': %s\n", - argv[0], event_path, strerror(-fd)); - - clear_event(event_buf); - close(fd); - exit(1); + fprintf (stderr, + "[ERROR] %s: Missing SEQNUM. Pass -n or include SEQNUM= in the input.\n", + argv[0]); + exit (1); } - // propagate.... - rc = multicast_event(seqnum, event_path); - if (rc < 0) { - - fprintf(stderr, "[ERROR] %s: Failed to multicast '%s': %s\n", - argv[0], event_path, strerror(-rc)); - - clear_event(event_buf); - close(fd); - exit(1); + // is it a valid seqnum? + seqnum = + (uint64_t) strtoull (seqnum_str + strlen ("SEQNUM="), &tmp, 10); + if (seqnum == 0 + && (tmp == seqnum_str + strlen ("SEQNUM=") || *tmp != '\n')) + { + + // invalid seqnum + fprintf (stderr, + "[ERROR] %s: Invalid SEQNUM. Pass -n or include a valid SEQNUM in the input.\n", + argv[0]); + exit (1); } - // done! - clear_event(event_path); - close(fd); - - return 0; + } + // send it off! + make_event_path (seqnum, event_path); + + fd = open_event (event_path); + if (fd < 0) + { + + fprintf (stderr, "[ERROR] %s: Failed to open '%s': %s\n", + argv[0], event_path, strerror (-fd)); + exit (1); + } + + rc = write_uninterrupted (fd, event_buf, nr); + if (rc < 0) + { + + fprintf (stderr, "[ERROR] %s: Failed to write '%s': %s\n", + argv[0], event_path, strerror (-fd)); + + clear_event (event_buf); + close (fd); + exit (1); + } + // propagate.... + rc = multicast_event (seqnum, event_path); + if (rc < 0) + { + + fprintf (stderr, "[ERROR] %s: Failed to multicast '%s': %s\n", + argv[0], event_path, strerror (-rc)); + + clear_event (event_buf); + close (fd); + exit (1); + } + // done! + clear_event (event_path); + close (fd); + + return 0; } diff --git a/vdevd/helpers/LINUX/stat_ata.c b/vdevd/helpers/LINUX/stat_ata.c index f34f585..5797ff8 100644 --- a/vdevd/helpers/LINUX/stat_ata.c +++ b/vdevd/helpers/LINUX/stat_ata.c @@ -72,239 +72,258 @@ #define COMMAND_TIMEOUT_MSEC (30 * 1000) -static int disk_scsi_inquiry_command(int fd, void *buf, size_t buf_len) +static int +disk_scsi_inquiry_command (int fd, void *buf, size_t buf_len) { - uint8_t cdb[6]; - uint8_t sense[32]; - struct sg_io_v4 io_v4; - struct sg_io_hdr io_hdr; - int ret = 0; - - memset(sense, 0, 32 * sizeof(uint8_t)); - memset(&io_v4, 0, sizeof(struct sg_io_v4)); - memset(&io_hdr, 0, sizeof(struct sg_io_hdr)); - memset(cdb, 0, 6 * sizeof(uint8_t)); - - /* - * INQUIRY, see SPC-4 section 6.4 - */ - cdb[0] = 0x12; /* OPERATION CODE: INQUIRY */ - cdb[3] = (buf_len >> 8); /* ALLOCATION LENGTH */ - cdb[4] = (buf_len & 0xff); - - io_v4.guard = 'Q', io_v4.protocol = BSG_PROTOCOL_SCSI; - io_v4.subprotocol = BSG_SUB_PROTOCOL_SCSI_CMD; - io_v4.request_len = sizeof(cdb); - io_v4.request = (uintptr_t) cdb; - io_v4.max_response_len = sizeof(sense); - io_v4.response = (uintptr_t) sense; - io_v4.din_xfer_len = buf_len; - io_v4.din_xferp = (uintptr_t) buf; - io_v4.timeout = COMMAND_TIMEOUT_MSEC; - - ret = ioctl(fd, SG_IO, &io_v4); - if (ret != 0) { - /* could be that the driver doesn't do version 4, try version 3 */ - if (errno == EINVAL) { - - io_hdr.interface_id = 'S'; - io_hdr.cmdp = (unsigned char *)cdb; - io_hdr.cmd_len = sizeof(cdb); - io_hdr.dxferp = buf; - io_hdr.dxfer_len = buf_len; - io_hdr.sbp = sense; - io_hdr.mx_sb_len = sizeof(sense); - io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; - io_hdr.timeout = COMMAND_TIMEOUT_MSEC; - - ret = ioctl(fd, SG_IO, &io_hdr); - if (ret != 0) { - - return ret; - } - - /* even if the ioctl succeeds, we need to check the return value */ - if (!(io_hdr.status == 0 && - io_hdr.host_status == 0 && - io_hdr.driver_status == 0)) { - errno = EIO; - - return -1; - } - } else { - - return ret; - } - } - - /* even if the ioctl succeeds, we need to check the return value */ - if (!(io_v4.device_status == 0 && - io_v4.transport_status == 0 && io_v4.driver_status == 0)) { - errno = EIO; - - return -1; - } - - return 0; + uint8_t cdb[6]; + uint8_t sense[32]; + struct sg_io_v4 io_v4; + struct sg_io_hdr io_hdr; + int ret = 0; + + memset (sense, 0, 32 * sizeof (uint8_t)); + memset (&io_v4, 0, sizeof (struct sg_io_v4)); + memset (&io_hdr, 0, sizeof (struct sg_io_hdr)); + memset (cdb, 0, 6 * sizeof (uint8_t)); + + /* + * INQUIRY, see SPC-4 section 6.4 + */ + cdb[0] = 0x12; /* OPERATION CODE: INQUIRY */ + cdb[3] = (buf_len >> 8); /* ALLOCATION LENGTH */ + cdb[4] = (buf_len & 0xff); + + io_v4.guard = 'Q', io_v4.protocol = BSG_PROTOCOL_SCSI; + io_v4.subprotocol = BSG_SUB_PROTOCOL_SCSI_CMD; + io_v4.request_len = sizeof (cdb); + io_v4.request = (uintptr_t) cdb; + io_v4.max_response_len = sizeof (sense); + io_v4.response = (uintptr_t) sense; + io_v4.din_xfer_len = buf_len; + io_v4.din_xferp = (uintptr_t) buf; + io_v4.timeout = COMMAND_TIMEOUT_MSEC; + + ret = ioctl (fd, SG_IO, &io_v4); + if (ret != 0) + { + /* could be that the driver doesn't do version 4, try version 3 */ + if (errno == EINVAL) + { + + io_hdr.interface_id = 'S'; + io_hdr.cmdp = (unsigned char *) cdb; + io_hdr.cmd_len = sizeof (cdb); + io_hdr.dxferp = buf; + io_hdr.dxfer_len = buf_len; + io_hdr.sbp = sense; + io_hdr.mx_sb_len = sizeof (sense); + io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; + io_hdr.timeout = COMMAND_TIMEOUT_MSEC; + + ret = ioctl (fd, SG_IO, &io_hdr); + if (ret != 0) + { + + return ret; + } + + /* even if the ioctl succeeds, we need to check the return value */ + if (!(io_hdr.status == 0 && + io_hdr.host_status == 0 && io_hdr.driver_status == 0)) + { + errno = EIO; + + return -1; + } + } + else + { + + return ret; + } + } + + /* even if the ioctl succeeds, we need to check the return value */ + if (!(io_v4.device_status == 0 && + io_v4.transport_status == 0 && io_v4.driver_status == 0)) + { + errno = EIO; + + return -1; + } + + return 0; } -static int disk_identify_command(int fd, void *buf, size_t buf_len) +static int +disk_identify_command (int fd, void *buf, size_t buf_len) { - uint8_t cdb[12]; - uint8_t sense[32] = { }; - uint8_t *desc = sense + 8; - struct sg_io_v4 io_v4; - struct sg_io_hdr io_hdr; - int ret = 0; - - memset(cdb, 0, sizeof(uint8_t) * 12); - memset(&io_v4, 0, sizeof(struct sg_io_v4)); - memset(&io_hdr, 0, sizeof(struct sg_io_hdr)); - - /* - * ATA Pass-Through 12 byte command, as described in - * - * T10 04-262r8 ATA Command Pass-Through - * - * from http://www.t10.org/ftp/t10/document.04/04-262r8.pdf - */ - cdb[0] = 0xa1; /* OPERATION CODE: 12 byte pass through */ - cdb[1] = 4 << 1; /* PROTOCOL: PIO Data-in */ - cdb[2] = 0x2e; /* OFF_LINE=0, CK_COND=1, T_DIR=1, BYT_BLOK=1, T_LENGTH=2 */ - cdb[3] = 0; /* FEATURES */ - cdb[4] = 1; /* SECTORS */ - cdb[5] = 0; /* LBA LOW */ - cdb[6] = 0; /* LBA MID */ - cdb[7] = 0; /* LBA HIGH */ - cdb[8] = 0 & 0x4F; /* SELECT */ - cdb[9] = 0xEC; /* Command: ATA IDENTIFY DEVICE */ - - io_v4.guard = 'Q'; - io_v4.protocol = BSG_PROTOCOL_SCSI; - io_v4.subprotocol = BSG_SUB_PROTOCOL_SCSI_CMD; - io_v4.request_len = sizeof(cdb); - io_v4.request = (uintptr_t) cdb; - io_v4.max_response_len = sizeof(sense); - io_v4.response = (uintptr_t) sense; - io_v4.din_xfer_len = buf_len; - io_v4.din_xferp = (uintptr_t) buf; - io_v4.timeout = COMMAND_TIMEOUT_MSEC; - - ret = ioctl(fd, SG_IO, &io_v4); - if (ret != 0) { - /* could be that the driver doesn't do version 4, try version 3 */ - if (errno == EINVAL) { - - io_hdr.interface_id = 'S', - io_hdr.cmdp = (unsigned char *)cdb; - io_hdr.cmd_len = sizeof(cdb); - io_hdr.dxferp = buf; - io_hdr.dxfer_len = buf_len; - io_hdr.sbp = sense; - io_hdr.mx_sb_len = sizeof(sense); - io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; - io_hdr.timeout = COMMAND_TIMEOUT_MSEC; - - ret = ioctl(fd, SG_IO, &io_hdr); - if (ret != 0) { - return ret; - } - } else { - return ret; - } - } - - if (!(sense[0] == 0x72 && desc[0] == 0x9 && desc[1] == 0x0c)) { - errno = EIO; - return -1; - } - - return 0; + uint8_t cdb[12]; + uint8_t sense[32] = { }; + uint8_t *desc = sense + 8; + struct sg_io_v4 io_v4; + struct sg_io_hdr io_hdr; + int ret = 0; + + memset (cdb, 0, sizeof (uint8_t) * 12); + memset (&io_v4, 0, sizeof (struct sg_io_v4)); + memset (&io_hdr, 0, sizeof (struct sg_io_hdr)); + + /* + * ATA Pass-Through 12 byte command, as described in + * + * T10 04-262r8 ATA Command Pass-Through + * + * from http://www.t10.org/ftp/t10/document.04/04-262r8.pdf + */ + cdb[0] = 0xa1; /* OPERATION CODE: 12 byte pass through */ + cdb[1] = 4 << 1; /* PROTOCOL: PIO Data-in */ + cdb[2] = 0x2e; /* OFF_LINE=0, CK_COND=1, T_DIR=1, BYT_BLOK=1, T_LENGTH=2 */ + cdb[3] = 0; /* FEATURES */ + cdb[4] = 1; /* SECTORS */ + cdb[5] = 0; /* LBA LOW */ + cdb[6] = 0; /* LBA MID */ + cdb[7] = 0; /* LBA HIGH */ + cdb[8] = 0 & 0x4F; /* SELECT */ + cdb[9] = 0xEC; /* Command: ATA IDENTIFY DEVICE */ + + io_v4.guard = 'Q'; + io_v4.protocol = BSG_PROTOCOL_SCSI; + io_v4.subprotocol = BSG_SUB_PROTOCOL_SCSI_CMD; + io_v4.request_len = sizeof (cdb); + io_v4.request = (uintptr_t) cdb; + io_v4.max_response_len = sizeof (sense); + io_v4.response = (uintptr_t) sense; + io_v4.din_xfer_len = buf_len; + io_v4.din_xferp = (uintptr_t) buf; + io_v4.timeout = COMMAND_TIMEOUT_MSEC; + + ret = ioctl (fd, SG_IO, &io_v4); + if (ret != 0) + { + /* could be that the driver doesn't do version 4, try version 3 */ + if (errno == EINVAL) + { + + io_hdr.interface_id = 'S', io_hdr.cmdp = (unsigned char *) cdb; + io_hdr.cmd_len = sizeof (cdb); + io_hdr.dxferp = buf; + io_hdr.dxfer_len = buf_len; + io_hdr.sbp = sense; + io_hdr.mx_sb_len = sizeof (sense); + io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; + io_hdr.timeout = COMMAND_TIMEOUT_MSEC; + + ret = ioctl (fd, SG_IO, &io_hdr); + if (ret != 0) + { + return ret; + } + } + else + { + return ret; + } + } + + if (!(sense[0] == 0x72 && desc[0] == 0x9 && desc[1] == 0x0c)) + { + errno = EIO; + return -1; + } + + return 0; } -static int disk_identify_packet_device_command(int fd, void *buf, - size_t buf_len) +static int +disk_identify_packet_device_command (int fd, void *buf, size_t buf_len) { - uint8_t cdb[16]; - uint8_t sense[32]; - struct sg_io_v4 io_v4; - struct sg_io_hdr io_hdr; - uint8_t *desc = sense + 8; - int ret = 0; - - memset(sense, 0, 32 * sizeof(uint8_t)); - memset(&io_v4, 0, sizeof(struct sg_io_v4)); - memset(&io_hdr, 0, sizeof(struct sg_io_hdr)); - - /* - * ATA Pass-Through 16 byte command, as described in - * - * T10 04-262r8 ATA Command Pass-Through - * - * from http://www.t10.org/ftp/t10/document.04/04-262r8.pdf - */ - cdb[0] = 0x85; /* OPERATION CODE: 16 byte pass through */ - cdb[1] = 4 << 1; /* PROTOCOL: PIO Data-in */ - cdb[2] = 0x2e; /* OFF_LINE=0, CK_COND=1, T_DIR=1, BYT_BLOK=1, T_LENGTH=2 */ - cdb[3] = 0; /* FEATURES */ - cdb[4] = 0; /* FEATURES */ - cdb[5] = 0; /* SECTORS */ - cdb[6] = 1; /* SECTORS */ - cdb[7] = 0; /* LBA LOW */ - cdb[8] = 0; /* LBA LOW */ - cdb[9] = 0; /* LBA MID */ - cdb[10] = 0; /* LBA MID */ - cdb[11] = 0; /* LBA HIGH */ - cdb[12] = 0; /* LBA HIGH */ - cdb[13] = 0; /* DEVICE */ - cdb[14] = 0xA1; /* Command: ATA IDENTIFY PACKET DEVICE */ - cdb[15] = 0; /* CONTROL */ - - io_v4.guard = 'Q'; - io_v4.protocol = BSG_PROTOCOL_SCSI; - io_v4.subprotocol = BSG_SUB_PROTOCOL_SCSI_CMD; - io_v4.request_len = sizeof(cdb); - io_v4.request = (uintptr_t) cdb; - io_v4.max_response_len = sizeof(sense); - io_v4.response = (uintptr_t) sense; - io_v4.din_xfer_len = buf_len; - io_v4.din_xferp = (uintptr_t) buf; - io_v4.timeout = COMMAND_TIMEOUT_MSEC; - - ret = ioctl(fd, SG_IO, &io_v4); - if (ret != 0) { - /* could be that the driver doesn't do version 4, try version 3 */ - if (errno == EINVAL) { - - io_hdr.interface_id = 'S'; - io_hdr.cmdp = (unsigned char *)cdb; - io_hdr.cmd_len = sizeof(cdb); - io_hdr.dxferp = buf; - io_hdr.dxfer_len = buf_len; - io_hdr.sbp = sense; - io_hdr.mx_sb_len = sizeof(sense); - io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; - io_hdr.timeout = COMMAND_TIMEOUT_MSEC; - - ret = ioctl(fd, SG_IO, &io_hdr); - if (ret != 0) { - return ret; - } - - } else { - return ret; - } - } - - if (!(sense[0] == 0x72 && desc[0] == 0x9 && desc[1] == 0x0c)) { - errno = EIO; - return -1; - } - - return 0; + uint8_t cdb[16]; + uint8_t sense[32]; + struct sg_io_v4 io_v4; + struct sg_io_hdr io_hdr; + uint8_t *desc = sense + 8; + int ret = 0; + + memset (sense, 0, 32 * sizeof (uint8_t)); + memset (&io_v4, 0, sizeof (struct sg_io_v4)); + memset (&io_hdr, 0, sizeof (struct sg_io_hdr)); + + /* + * ATA Pass-Through 16 byte command, as described in + * + * T10 04-262r8 ATA Command Pass-Through + * + * from http://www.t10.org/ftp/t10/document.04/04-262r8.pdf + */ + cdb[0] = 0x85; /* OPERATION CODE: 16 byte pass through */ + cdb[1] = 4 << 1; /* PROTOCOL: PIO Data-in */ + cdb[2] = 0x2e; /* OFF_LINE=0, CK_COND=1, T_DIR=1, BYT_BLOK=1, T_LENGTH=2 */ + cdb[3] = 0; /* FEATURES */ + cdb[4] = 0; /* FEATURES */ + cdb[5] = 0; /* SECTORS */ + cdb[6] = 1; /* SECTORS */ + cdb[7] = 0; /* LBA LOW */ + cdb[8] = 0; /* LBA LOW */ + cdb[9] = 0; /* LBA MID */ + cdb[10] = 0; /* LBA MID */ + cdb[11] = 0; /* LBA HIGH */ + cdb[12] = 0; /* LBA HIGH */ + cdb[13] = 0; /* DEVICE */ + cdb[14] = 0xA1; /* Command: ATA IDENTIFY PACKET DEVICE */ + cdb[15] = 0; /* CONTROL */ + + io_v4.guard = 'Q'; + io_v4.protocol = BSG_PROTOCOL_SCSI; + io_v4.subprotocol = BSG_SUB_PROTOCOL_SCSI_CMD; + io_v4.request_len = sizeof (cdb); + io_v4.request = (uintptr_t) cdb; + io_v4.max_response_len = sizeof (sense); + io_v4.response = (uintptr_t) sense; + io_v4.din_xfer_len = buf_len; + io_v4.din_xferp = (uintptr_t) buf; + io_v4.timeout = COMMAND_TIMEOUT_MSEC; + + ret = ioctl (fd, SG_IO, &io_v4); + if (ret != 0) + { + /* could be that the driver doesn't do version 4, try version 3 */ + if (errno == EINVAL) + { + + io_hdr.interface_id = 'S'; + io_hdr.cmdp = (unsigned char *) cdb; + io_hdr.cmd_len = sizeof (cdb); + io_hdr.dxferp = buf; + io_hdr.dxfer_len = buf_len; + io_hdr.sbp = sense; + io_hdr.mx_sb_len = sizeof (sense); + io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; + io_hdr.timeout = COMMAND_TIMEOUT_MSEC; + + ret = ioctl (fd, SG_IO, &io_hdr); + if (ret != 0) + { + return ret; + } + + } + else + { + return ret; + } + } + + if (!(sense[0] == 0x72 && desc[0] == 0x9 && desc[1] == 0x0c)) + { + errno = EIO; + return -1; + } + + return 0; } /** @@ -316,41 +335,44 @@ static int disk_identify_packet_device_command(int fd, void *buf, * * Copies the ATA string from @identify located at @offset_words into @dest. */ -static void disk_identify_get_string(uint8_t identify[512], - unsigned int offset_words, char *dest, - size_t dest_len) +static void +disk_identify_get_string (uint8_t identify[512], + unsigned int offset_words, char *dest, + size_t dest_len) { - unsigned int c1; - unsigned int c2; - - while (dest_len > 0) { - c1 = identify[offset_words * 2 + 1]; - c2 = identify[offset_words * 2]; - *dest = c1; - dest++; - *dest = c2; - dest++; - offset_words++; - dest_len -= 2; - } + unsigned int c1; + unsigned int c2; + + while (dest_len > 0) + { + c1 = identify[offset_words * 2 + 1]; + c2 = identify[offset_words * 2]; + *dest = c1; + dest++; + *dest = c2; + dest++; + offset_words++; + dest_len -= 2; + } } -static void disk_identify_fixup_string(uint8_t identify[512], - unsigned int offset_words, size_t len) +static void +disk_identify_fixup_string (uint8_t identify[512], + unsigned int offset_words, size_t len) { - disk_identify_get_string(identify, offset_words, - (char *)identify + offset_words * 2, len); + disk_identify_get_string (identify, offset_words, + (char *) identify + offset_words * 2, len); } -static void disk_identify_fixup_uint16(uint8_t identify[512], - unsigned int offset_words) +static void +disk_identify_fixup_uint16 (uint8_t identify[512], unsigned int offset_words) { - uint16_t *p; + uint16_t *p; - p = (uint16_t *) identify; - p[offset_words] = le16toh(p[offset_words]); + p = (uint16_t *) identify; + p[offset_words] = le16toh (p[offset_words]); } /** @@ -370,441 +392,475 @@ static void disk_identify_fixup_uint16(uint8_t identify[512], * Returns: 0 if the data was successfully obtained, otherwise * non-zero with errno set. */ -static int disk_identify(int fd, uint8_t out_identify[512], - int *out_is_packet_device) +static int +disk_identify (int fd, uint8_t out_identify[512], int *out_is_packet_device) { - int ret; - uint8_t inquiry_buf[36]; - int peripheral_device_type = 0; - int all_nul_bytes = 1; - int n = 0; - int is_packet_device = 0; - - /* init results */ - memset(out_identify, 0, 512); - - /* If we were to use ATA PASS_THROUGH (12) on an ATAPI device - * we could accidentally blank media. This is because MMC's BLANK - * command has the same op-code (0x61). - * - * To prevent this from happening we bail out if the device - * isn't a Direct Access Block Device, e.g. SCSI type 0x00 - * (CD/DVD devices are type 0x05). So we send a SCSI INQUIRY - * command first... libata is handling this via its SCSI - * emulation layer. - * - * This also ensures that we're actually dealing with a device - * that understands SCSI commands. - * - * (Yes, it is a bit perverse that we're tunneling the ATA - * command through SCSI and relying on the ATA driver - * emulating SCSI well-enough...) - * - * (See commit 160b069c25690bfb0c785994c7c3710289179107 for - * the original bug-fix and see http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=556635 - * for the original bug-report.) - */ - ret = disk_scsi_inquiry_command(fd, inquiry_buf, sizeof(inquiry_buf)); - if (ret != 0) { - - goto out; - } - - /* SPC-4, section 6.4.2: Standard INQUIRY data */ - peripheral_device_type = inquiry_buf[0] & 0x1f; - if (peripheral_device_type == 0x05) { - - is_packet_device = 1; - ret = - disk_identify_packet_device_command(fd, out_identify, 512); - goto check_nul_bytes; - } - if (peripheral_device_type != 0x00) { - ret = -1; - errno = EIO; - - goto out; - } - - /* OK, now issue the IDENTIFY DEVICE command */ - ret = disk_identify_command(fd, out_identify, 512); - if (ret != 0) { - - goto out; - } - - check_nul_bytes: - /* Check if IDENTIFY data is all NUL bytes - if so, bail */ - all_nul_bytes = 1; - for (n = 0; n < 512; n++) { - if (out_identify[n] != '\0') { - all_nul_bytes = 0; - break; - } - } - - if (all_nul_bytes) { - - ret = -1; - errno = EIO; - goto out; - } - - out: - if (out_is_packet_device != NULL) { - *out_is_packet_device = is_packet_device; - } - return ret; + int ret; + uint8_t inquiry_buf[36]; + int peripheral_device_type = 0; + int all_nul_bytes = 1; + int n = 0; + int is_packet_device = 0; + + /* init results */ + memset (out_identify, 0, 512); + + /* If we were to use ATA PASS_THROUGH (12) on an ATAPI device + * we could accidentally blank media. This is because MMC's BLANK + * command has the same op-code (0x61). + * + * To prevent this from happening we bail out if the device + * isn't a Direct Access Block Device, e.g. SCSI type 0x00 + * (CD/DVD devices are type 0x05). So we send a SCSI INQUIRY + * command first... libata is handling this via its SCSI + * emulation layer. + * + * This also ensures that we're actually dealing with a device + * that understands SCSI commands. + * + * (Yes, it is a bit perverse that we're tunneling the ATA + * command through SCSI and relying on the ATA driver + * emulating SCSI well-enough...) + * + * (See commit 160b069c25690bfb0c785994c7c3710289179107 for + * the original bug-fix and see http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=556635 + * for the original bug-report.) + */ + ret = disk_scsi_inquiry_command (fd, inquiry_buf, sizeof (inquiry_buf)); + if (ret != 0) + { + + goto out; + } + + /* SPC-4, section 6.4.2: Standard INQUIRY data */ + peripheral_device_type = inquiry_buf[0] & 0x1f; + if (peripheral_device_type == 0x05) + { + + is_packet_device = 1; + ret = disk_identify_packet_device_command (fd, out_identify, 512); + goto check_nul_bytes; + } + if (peripheral_device_type != 0x00) + { + ret = -1; + errno = EIO; + + goto out; + } + + /* OK, now issue the IDENTIFY DEVICE command */ + ret = disk_identify_command (fd, out_identify, 512); + if (ret != 0) + { + + goto out; + } + +check_nul_bytes: + /* Check if IDENTIFY data is all NUL bytes - if so, bail */ + all_nul_bytes = 1; + for (n = 0; n < 512; n++) + { + if (out_identify[n] != '\0') + { + all_nul_bytes = 0; + break; + } + } + + if (all_nul_bytes) + { + + ret = -1; + errno = EIO; + goto out; + } + +out: + if (out_is_packet_device != NULL) + { + *out_is_packet_device = is_packet_device; + } + return ret; } // entry point -int main(int argc, char **argv) +int +main (int argc, char **argv) { - struct hd_driveid id; - union { - uint8_t byte[512]; - uint16_t wyde[256]; - uint64_t octa[64]; - } identify; - - int fd = 0; - char model[41]; - char model_enc[256]; - char serial[21]; - char revision[9]; - const char *node = NULL; - uint16_t word = 0; - int is_packet_device = 0; - int rc = 0; - - // check usage - if (argc != 2) { - fprintf(stderr, "[ERROR] %s: Usage: %s /path/to/device/file\n", - argv[0], argv[0]); - exit(1); - } - - node = argv[1]; - - fd = open(node, O_RDONLY | O_NONBLOCK | O_CLOEXEC); - if (fd < 0) { - fprintf(stderr, "[ERROR] %s: unable to open '%s'\n", argv[0], - node); - exit(1); - } - - rc = disk_identify(fd, identify.byte, &is_packet_device); - if (rc == 0) { - /* - * fix up only the fields from the IDENTIFY data that we are going to - * use and copy it into the hd_driveid struct for convenience - */ - disk_identify_fixup_string(identify.byte, 10, 20); /* serial */ - disk_identify_fixup_string(identify.byte, 23, 8); /* fwrev */ - disk_identify_fixup_string(identify.byte, 27, 40); /* model */ - disk_identify_fixup_uint16(identify.byte, 0); /* configuration */ - disk_identify_fixup_uint16(identify.byte, 75); /* queue depth */ - disk_identify_fixup_uint16(identify.byte, 75); /* SATA capabilities */ - disk_identify_fixup_uint16(identify.byte, 82); /* command set supported */ - disk_identify_fixup_uint16(identify.byte, 83); /* command set supported */ - disk_identify_fixup_uint16(identify.byte, 84); /* command set supported */ - disk_identify_fixup_uint16(identify.byte, 85); /* command set supported */ - disk_identify_fixup_uint16(identify.byte, 86); /* command set supported */ - disk_identify_fixup_uint16(identify.byte, 87); /* command set supported */ - disk_identify_fixup_uint16(identify.byte, 89); /* time required for SECURITY ERASE UNIT */ - disk_identify_fixup_uint16(identify.byte, 90); /* time required for enhanced SECURITY ERASE UNIT */ - disk_identify_fixup_uint16(identify.byte, 91); /* current APM values */ - disk_identify_fixup_uint16(identify.byte, 94); /* current AAM value */ - disk_identify_fixup_uint16(identify.byte, 128); /* device lock function */ - disk_identify_fixup_uint16(identify.byte, 217); /* nominal media rotation rate */ - memcpy(&id, identify.byte, sizeof id); - } else { - - /* If this fails, then try HDIO_GET_IDENTITY */ - if (ioctl(fd, HDIO_GET_IDENTITY, &id) != 0) { - int errsv = -errno; - fprintf(stderr, - "[ERROR] %s: HDIO_GET_IDENTITY failed for '%s': errno = %d\n", - argv[0], node, errsv); - close(fd); - exit(2); - } - } - - memcpy(model, id.model, 40); - model[40] = '\0'; - - vdev_util_encode_string(model, model_enc, sizeof(model_enc)); - vdev_util_replace_whitespace((char *)id.model, model, 40); - vdev_util_replace_chars(model, NULL); - vdev_util_replace_whitespace((char *)id.serial_no, serial, 20); - vdev_util_replace_chars(serial, NULL); - vdev_util_replace_whitespace((char *)id.fw_rev, revision, 8); - vdev_util_replace_chars(revision, NULL); + struct hd_driveid id; + union + { + uint8_t byte[512]; + uint16_t wyde[256]; + uint64_t octa[64]; + } identify; + + int fd = 0; + char model[41]; + char model_enc[256]; + char serial[21]; + char revision[9]; + const char *node = NULL; + uint16_t word = 0; + int is_packet_device = 0; + int rc = 0; + + // check usage + if (argc != 2) + { + fprintf (stderr, "[ERROR] %s: Usage: %s /path/to/device/file\n", + argv[0], argv[0]); + exit (1); + } + + node = argv[1]; + + fd = open (node, O_RDONLY | O_NONBLOCK | O_CLOEXEC); + if (fd < 0) + { + fprintf (stderr, "[ERROR] %s: unable to open '%s'\n", argv[0], node); + exit (1); + } + + rc = disk_identify (fd, identify.byte, &is_packet_device); + if (rc == 0) + { + /* + * fix up only the fields from the IDENTIFY data that we are going to + * use and copy it into the hd_driveid struct for convenience + */ + disk_identify_fixup_string (identify.byte, 10, 20); /* serial */ + disk_identify_fixup_string (identify.byte, 23, 8); /* fwrev */ + disk_identify_fixup_string (identify.byte, 27, 40); /* model */ + disk_identify_fixup_uint16 (identify.byte, 0); /* configuration */ + disk_identify_fixup_uint16 (identify.byte, 75); /* queue depth */ + disk_identify_fixup_uint16 (identify.byte, 75); /* SATA capabilities */ + disk_identify_fixup_uint16 (identify.byte, 82); /* command set supported */ + disk_identify_fixup_uint16 (identify.byte, 83); /* command set supported */ + disk_identify_fixup_uint16 (identify.byte, 84); /* command set supported */ + disk_identify_fixup_uint16 (identify.byte, 85); /* command set supported */ + disk_identify_fixup_uint16 (identify.byte, 86); /* command set supported */ + disk_identify_fixup_uint16 (identify.byte, 87); /* command set supported */ + disk_identify_fixup_uint16 (identify.byte, 89); /* time required for SECURITY ERASE UNIT */ + disk_identify_fixup_uint16 (identify.byte, 90); /* time required for enhanced SECURITY ERASE UNIT */ + disk_identify_fixup_uint16 (identify.byte, 91); /* current APM values */ + disk_identify_fixup_uint16 (identify.byte, 94); /* current AAM value */ + disk_identify_fixup_uint16 (identify.byte, 128); /* device lock function */ + disk_identify_fixup_uint16 (identify.byte, 217); /* nominal media rotation rate */ + memcpy (&id, identify.byte, sizeof id); + } + else + { + + /* If this fails, then try HDIO_GET_IDENTITY */ + if (ioctl (fd, HDIO_GET_IDENTITY, &id) != 0) + { + int errsv = -errno; + fprintf (stderr, + "[ERROR] %s: HDIO_GET_IDENTITY failed for '%s': errno = %d\n", + argv[0], node, errsv); + close (fd); + exit (2); + } + } + + memcpy (model, id.model, 40); + model[40] = '\0'; + + vdev_util_encode_string (model, model_enc, sizeof (model_enc)); + vdev_util_replace_whitespace ((char *) id.model, model, 40); + vdev_util_replace_chars (model, NULL); + vdev_util_replace_whitespace ((char *) id.serial_no, serial, 20); + vdev_util_replace_chars (serial, NULL); + vdev_util_replace_whitespace ((char *) id.fw_rev, revision, 8); + vdev_util_replace_chars (revision, NULL); + + /* Set this to convey the disk speaks the ATA protocol */ + vdev_property_add ("VDEV_ATA", "1"); + + if ((id.config >> 8) & 0x80) + { + /* This is an ATAPI device */ + switch ((id.config >> 8) & 0x1f) + { + case 0: + + vdev_property_add ("VDEV_ATA_TYPE", "cd"); + break; + + case 1: + + vdev_property_add ("VDEV_ATA_TYPE", "tape"); + break; + + case 5: + + vdev_property_add ("VDEV_ATA_TYPE", "cd"); + break; + + case 7: + + vdev_property_add ("VDEV_ATA_TYPE", "optical"); + break; + + default: + + vdev_property_add ("VDEV_ATA_TYPE", "generic"); + break; + } + } + else + { + + vdev_property_add ("VDEV_ATA_TYPE", "disk"); + } + + vdev_property_add ("VDEV_ATA_MODEL", model); + vdev_property_add ("VDEV_ATA_MODEL_ENC", model_enc); + vdev_property_add ("VDEV_ATA_REVISION", revision); + + if (serial[0] != '\0') + { + + char serial_buf[100]; + memset (serial_buf, 0, 100); + + snprintf (serial_buf, 99, "%s_%s", model, serial); + + vdev_property_add ("VDEV_ATA_SERIAL", serial_buf); + vdev_property_add ("VDEV_ATA_SERIAL_SHORT", serial); + + } + else + { + + vdev_property_add ("VDEV_ATA_SERIAL", model); + } - /* Set this to convey the disk speaks the ATA protocol */ - vdev_property_add("VDEV_ATA", "1"); + if (id.command_set_1 & (1 << 5)) + { - if ((id.config >> 8) & 0x80) { - /* This is an ATAPI device */ - switch ((id.config >> 8) & 0x1f) { - case 0: + vdev_property_add ("VDEV_ATA_WRITE_CACHE", "1"); + vdev_property_add ("VDEV_ATA_WRITE_CACHE_ENABLED", + (id.cfs_enable_1 & (1 << 5)) ? "1" : "0"); + } + if (id.command_set_1 & (1 << 10)) + { - vdev_property_add("VDEV_ATA_TYPE", "cd"); - break; + vdev_property_add ("VDEV_ATA_FEATURE_SET_HPA", "1"); + vdev_property_add ("VDEV_ATA_FEATURE_SET_HPA_ENABLED", + (id.cfs_enable_1 & (1 << 10)) ? "1" : "0"); - case 1: + /* + * TODO: use the READ NATIVE MAX ADDRESS command to get the native max address + * so it is easy to check whether the protected area is in use. + */ + } + if (id.command_set_1 & (1 << 3)) + { - vdev_property_add("VDEV_ATA_TYPE", "tape"); - break; + vdev_property_add ("VDEV_ATA_FEATURE_SET_PM", "1"); + vdev_property_add ("VDEV_ATA_FEATURE_SET_PM_ENABLED", + (id.cfs_enable_1 & (1 << 3)) ? "1" : "0"); + } + if (id.command_set_1 & (1 << 1)) + { - case 5: + char buf[100]; + memset (buf, 0, 100); + snprintf (buf, 99, "%d", id.trseuc * 2); - vdev_property_add("VDEV_ATA_TYPE", "cd"); - break; + vdev_property_add ("VDEV_ATA_FEATURE_SET_SECURITY", "1"); + vdev_property_add ("VDEV_ATA_FEATURE_SET_SECURITY_ENABLED", + (id.cfs_enable_1 & (1 << 1)) ? "1" : "0"); + vdev_property_add ("VDEV_ATA_FEATURE_SET_SECURITY_ERASE_UNIT_MIN", buf); - case 7: + if ((id.cfs_enable_1 & (1 << 1))) + { /* enabled */ - vdev_property_add("VDEV_ATA_TYPE", "optical"); - break; + if (id.dlf & (1 << 8)) + { - default: + vdev_property_add + ("VDEV_ATA_FEATURE_SET_SECURITY_LEVEL", "maximum"); + } + else + { - vdev_property_add("VDEV_ATA_TYPE", "generic"); - break; - } - } else { - - vdev_property_add("VDEV_ATA_TYPE", "disk"); + vdev_property_add + ("VDEV_ATA_FEATURE_SET_SECURITY_LEVEL", "high"); + } } + if (id.dlf & (1 << 5)) + { - vdev_property_add("VDEV_ATA_MODEL", model); - vdev_property_add("VDEV_ATA_MODEL_ENC", model_enc); - vdev_property_add("VDEV_ATA_REVISION", revision); - - if (serial[0] != '\0') { - - char serial_buf[100]; - memset(serial_buf, 0, 100); - - snprintf(serial_buf, 99, "%s_%s", model, serial); - - vdev_property_add("VDEV_ATA_SERIAL", serial_buf); - vdev_property_add("VDEV_ATA_SERIAL_SHORT", serial); + memset (buf, 0, 100); + snprintf (buf, 99, "%d", id.trsEuc * 2); - } else { - - vdev_property_add("VDEV_ATA_SERIAL", model); + vdev_property_add + ("VDEV_ATA_FEATURE_SET_SECURITY_ENHANCED_ERASE_UNIT_MIN", buf); } + if (id.dlf & (1 << 4)) + { - if (id.command_set_1 & (1 << 5)) { - - vdev_property_add("VDEV_ATA_WRITE_CACHE", "1"); - vdev_property_add("VDEV_ATA_WRITE_CACHE_ENABLED", - (id.cfs_enable_1 & (1 << 5)) ? "1" : "0"); + vdev_property_add ("VDEV_ATA_FEATURE_SET_SECURITY_EXPIRE", "1"); } - if (id.command_set_1 & (1 << 10)) { + if (id.dlf & (1 << 3)) + { - vdev_property_add("VDEV_ATA_FEATURE_SET_HPA", "1"); - vdev_property_add("VDEV_ATA_FEATURE_SET_HPA_ENABLED", - (id.cfs_enable_1 & (1 << 10)) ? "1" : "0"); - - /* - * TODO: use the READ NATIVE MAX ADDRESS command to get the native max address - * so it is easy to check whether the protected area is in use. - */ + vdev_property_add ("VDEV_ATA_FEATURE_SET_SECURITY_FROZEN", "1"); } - if (id.command_set_1 & (1 << 3)) { + if (id.dlf & (1 << 2)) + { - vdev_property_add("VDEV_ATA_FEATURE_SET_PM", "1"); - vdev_property_add("VDEV_ATA_FEATURE_SET_PM_ENABLED", - (id.cfs_enable_1 & (1 << 3)) ? "1" : "0"); - } - if (id.command_set_1 & (1 << 1)) { - - char buf[100]; - memset(buf, 0, 100); - snprintf(buf, 99, "%d", id.trseuc * 2); - - vdev_property_add("VDEV_ATA_FEATURE_SET_SECURITY", "1"); - vdev_property_add("VDEV_ATA_FEATURE_SET_SECURITY_ENABLED", - (id.cfs_enable_1 & (1 << 1)) ? "1" : "0"); - vdev_property_add - ("VDEV_ATA_FEATURE_SET_SECURITY_ERASE_UNIT_MIN", buf); - - if ((id.cfs_enable_1 & (1 << 1))) { /* enabled */ - - if (id.dlf & (1 << 8)) { - - vdev_property_add - ("VDEV_ATA_FEATURE_SET_SECURITY_LEVEL", - "maximum"); - } else { - - vdev_property_add - ("VDEV_ATA_FEATURE_SET_SECURITY_LEVEL", - "high"); - } - } - if (id.dlf & (1 << 5)) { - - memset(buf, 0, 100); - snprintf(buf, 99, "%d", id.trsEuc * 2); - - vdev_property_add - ("VDEV_ATA_FEATURE_SET_SECURITY_ENHANCED_ERASE_UNIT_MIN", - buf); - } - if (id.dlf & (1 << 4)) { - - vdev_property_add - ("VDEV_ATA_FEATURE_SET_SECURITY_EXPIRE", "1"); - } - if (id.dlf & (1 << 3)) { - - vdev_property_add - ("VDEV_ATA_FEATURE_SET_SECURITY_FROZEN", "1"); - } - if (id.dlf & (1 << 2)) { - - vdev_property_add("VDEV_ATA_FEATURE_SET_SECURITY_LEVEL", - "1"); - } + vdev_property_add ("VDEV_ATA_FEATURE_SET_SECURITY_LEVEL", "1"); } - if (id.command_set_1 & (1 << 0)) { + } + if (id.command_set_1 & (1 << 0)) + { - vdev_property_add("VDEV_ATA_FEATURE_SET_SMART", "1"); - vdev_property_add("VDEV_ATA_FEATURE_SET_SMART_ENABLED", - (id.cfs_enable_1 & (1 << 0)) ? "1" : "0"); - } - if (id.command_set_2 & (1 << 9)) { + vdev_property_add ("VDEV_ATA_FEATURE_SET_SMART", "1"); + vdev_property_add ("VDEV_ATA_FEATURE_SET_SMART_ENABLED", + (id.cfs_enable_1 & (1 << 0)) ? "1" : "0"); + } + if (id.command_set_2 & (1 << 9)) + { - char aam_buf[100]; - char aam_cur_buf[100]; + char aam_buf[100]; + char aam_cur_buf[100]; - memset(aam_buf, 0, 100); - memset(aam_cur_buf, 0, 100); + memset (aam_buf, 0, 100); + memset (aam_cur_buf, 0, 100); - snprintf(aam_buf, 99, "%d", id.acoustic >> 8); - snprintf(aam_cur_buf, 99, "%d", id.acoustic & 0xff); + snprintf (aam_buf, 99, "%d", id.acoustic >> 8); + snprintf (aam_cur_buf, 99, "%d", id.acoustic & 0xff); - vdev_property_add("VDEV_ATA_FEATURE_SET_AAM", "1"); - vdev_property_add("VDEV_ATA_FEATURE_SET_AAM_ENABLED", - (id.cfs_enable_2 & (1 << 9)) ? "1" : "0"); - vdev_property_add - ("VDEV_ATA_FEATURE_SET_AAM_VENDOR_RECOMMENDED_VALUE", - aam_buf); - vdev_property_add("VDEV_ATA_FEATURE_SET_AAM_CURRENT_VALUE", - aam_cur_buf); - } - if (id.command_set_2 & (1 << 5)) { + vdev_property_add ("VDEV_ATA_FEATURE_SET_AAM", "1"); + vdev_property_add ("VDEV_ATA_FEATURE_SET_AAM_ENABLED", + (id.cfs_enable_2 & (1 << 9)) ? "1" : "0"); + vdev_property_add + ("VDEV_ATA_FEATURE_SET_AAM_VENDOR_RECOMMENDED_VALUE", aam_buf); + vdev_property_add ("VDEV_ATA_FEATURE_SET_AAM_CURRENT_VALUE", + aam_cur_buf); + } + if (id.command_set_2 & (1 << 5)) + { - vdev_property_add("VDEV_ATA_FEATURE_SET_PUIS", "1"); - vdev_property_add("VDEV_ATA_FEATURE_SET_PUIS_ENABLED", - (id.cfs_enable_2 & (1 << 5)) ? "1" : "0"); - } - if (id.command_set_2 & (1 << 3)) { + vdev_property_add ("VDEV_ATA_FEATURE_SET_PUIS", "1"); + vdev_property_add ("VDEV_ATA_FEATURE_SET_PUIS_ENABLED", + (id.cfs_enable_2 & (1 << 5)) ? "1" : "0"); + } + if (id.command_set_2 & (1 << 3)) + { - vdev_property_add("VDEV_ATA_FEATURE_SET_APM", "1"); - vdev_property_add("VDEV_ATA_FEATURE_SET_APM_ENABLED", - (id.cfs_enable_2 & (1 << 3)) ? "1" : "0"); + vdev_property_add ("VDEV_ATA_FEATURE_SET_APM", "1"); + vdev_property_add ("VDEV_ATA_FEATURE_SET_APM_ENABLED", + (id.cfs_enable_2 & (1 << 3)) ? "1" : "0"); - if ((id.cfs_enable_2 & (1 << 3))) { + if ((id.cfs_enable_2 & (1 << 3))) + { - char apm_cur_buf[100]; + char apm_cur_buf[100]; - memset(apm_cur_buf, 0, 100); + memset (apm_cur_buf, 0, 100); - snprintf(apm_cur_buf, 99, "%d", id.CurAPMvalues & 0xff); + snprintf (apm_cur_buf, 99, "%d", id.CurAPMvalues & 0xff); - vdev_property_add - ("VDEV_ATA_FEATURE_SET_APM_CURRENT_VALUE", - apm_cur_buf); - } + vdev_property_add + ("VDEV_ATA_FEATURE_SET_APM_CURRENT_VALUE", apm_cur_buf); } - if (id.command_set_2 & (1 << 0)) { + } + if (id.command_set_2 & (1 << 0)) + { - vdev_property_add("VDEV_ATA_DOWNLOAD_MICROCODE", "1"); + vdev_property_add ("VDEV_ATA_DOWNLOAD_MICROCODE", "1"); + } + + /* + * Word 76 indicates the capabilities of a SATA device. A PATA device shall set + * word 76 to 0000h or FFFFh. If word 76 is set to 0000h or FFFFh, then + * the device does not claim compliance with the Serial ATA specification and words + * 76 through 79 are not valid and shall be ignored. + */ + + word = identify.wyde[76]; + if (word != 0x0000 && word != 0xffff) + { + + vdev_property_add ("VDEV_ATA_SATA", "1"); + /* + * If bit 2 of word 76 is set to one, then the device supports the Gen2 + * signaling rate of 3.0 Gb/s (see SATA 2.6). + * + * If bit 1 of word 76 is set to one, then the device supports the Gen1 + * signaling rate of 1.5 Gb/s (see SATA 2.6). + */ + if (word & (1 << 2)) + { + + vdev_property_add ("VDEV_ATA_SATA_SIGNAL_RATE_GEN2", "1"); } + if (word & (1 << 1)) + { - /* - * Word 76 indicates the capabilities of a SATA device. A PATA device shall set - * word 76 to 0000h or FFFFh. If word 76 is set to 0000h or FFFFh, then - * the device does not claim compliance with the Serial ATA specification and words - * 76 through 79 are not valid and shall be ignored. - */ - - word = identify.wyde[76]; - if (word != 0x0000 && word != 0xffff) { - - vdev_property_add("VDEV_ATA_SATA", "1"); - /* - * If bit 2 of word 76 is set to one, then the device supports the Gen2 - * signaling rate of 3.0 Gb/s (see SATA 2.6). - * - * If bit 1 of word 76 is set to one, then the device supports the Gen1 - * signaling rate of 1.5 Gb/s (see SATA 2.6). - */ - if (word & (1 << 2)) { - - vdev_property_add("VDEV_ATA_SATA_SIGNAL_RATE_GEN2", - "1"); - } - if (word & (1 << 1)) { - - vdev_property_add("VDEV_ATA_SATA_SIGNAL_RATE_GEN1", - "1"); - } + vdev_property_add ("VDEV_ATA_SATA_SIGNAL_RATE_GEN1", "1"); } + } - /* Word 217 indicates the nominal media rotation rate of the device */ - word = identify.wyde[217]; - if (word == 0x0001) { + /* Word 217 indicates the nominal media rotation rate of the device */ + word = identify.wyde[217]; + if (word == 0x0001) + { - vdev_property_add("VDEV_ATA_ROTATION_RATE_RPM", "0"); - } else if (word >= 0x0401 && word <= 0xfffe) { + vdev_property_add ("VDEV_ATA_ROTATION_RATE_RPM", "0"); + } + else if (word >= 0x0401 && word <= 0xfffe) + { - char rpm_buf[100]; + char rpm_buf[100]; - memset(rpm_buf, 0, 100); + memset (rpm_buf, 0, 100); - snprintf(rpm_buf, 99, "%d", word); + snprintf (rpm_buf, 99, "%d", word); - vdev_property_add("VDEV_ATA_ROTATION_RATE_RPM", rpm_buf); - } + vdev_property_add ("VDEV_ATA_ROTATION_RATE_RPM", rpm_buf); + } - /* - * Words 108-111 contain a mandatory World Wide Name (WWN) in the NAA IEEE Registered identifier - * format. Word 108 bits (15:12) shall contain 5h, indicating that the naming authority is IEEE. - * All other values are reserved. - */ - word = identify.wyde[108]; - if ((word & 0xf000) == 0x5000) { + /* + * Words 108-111 contain a mandatory World Wide Name (WWN) in the NAA IEEE Registered identifier + * format. Word 108 bits (15:12) shall contain 5h, indicating that the naming authority is IEEE. + * All other values are reserved. + */ + word = identify.wyde[108]; + if ((word & 0xf000) == 0x5000) + { - char wwn_buf[100]; + char wwn_buf[100]; - memset(wwn_buf, 0, 100); + memset (wwn_buf, 0, 100); - snprintf(wwn_buf, 99, "0x%04x%04x%04x%04x", identify.wyde[108], - identify.wyde[109], identify.wyde[110], - identify.wyde[111]); + snprintf (wwn_buf, 99, "0x%04x%04x%04x%04x", identify.wyde[108], + identify.wyde[109], identify.wyde[110], identify.wyde[111]); - vdev_property_add("VDEV_ATA_WWN", wwn_buf); - vdev_property_add("VDEV_ATA_WWN_WITH_EXTENSION", wwn_buf); - } + vdev_property_add ("VDEV_ATA_WWN", wwn_buf); + vdev_property_add ("VDEV_ATA_WWN_WITH_EXTENSION", wwn_buf); + } - /* from Linux's include/linux/ata.h */ - if (identify.wyde[0] == 0x848a || - identify.wyde[0] == 0x844a || - (identify.wyde[83] & 0xc004) == 0x4004) { + /* from Linux's include/linux/ata.h */ + if (identify.wyde[0] == 0x848a || + identify.wyde[0] == 0x844a || (identify.wyde[83] & 0xc004) == 0x4004) + { - vdev_property_add("VDEV_ATA_CFA", "1"); - } + vdev_property_add ("VDEV_ATA_CFA", "1"); + } - vdev_property_print(); - vdev_property_free_all(); + vdev_property_print (); + vdev_property_free_all (); - return 0; + return 0; } diff --git a/vdevd/helpers/LINUX/stat_bus.c b/vdevd/helpers/LINUX/stat_bus.c index 984e336..f4d7429 100644 --- a/vdevd/helpers/LINUX/stat_bus.c +++ b/vdevd/helpers/LINUX/stat_bus.c @@ -22,149 +22,178 @@ // determine what kind of busses we're on #include "common.h" -void usage(char const *progname) +void +usage (char const *progname) { - fprintf(stderr, "[ERROR] %s: Usage: %s /sysfs/path/to/device\n", - progname, progname); - exit(1); + fprintf (stderr, "[ERROR] %s: Usage: %s /sysfs/path/to/device\n", + progname, progname); + exit (1); } // lop off the child of a directory // return 0 on success // return -ENOENT if there is no child to remove -int remove_child(char *path) +int +remove_child (char *path) { - char *delim = NULL; + char *delim = NULL; - delim = strrchr(path, '/'); - if (delim == NULL || delim == path) { - return -ENOENT; - } + delim = strrchr (path, '/'); + if (delim == NULL || delim == path) + { + return -ENOENT; + } - while (*delim == '/' && delim != path) { - *delim = '\0'; - delim--; - } + while (*delim == '/' && delim != path) + { + *delim = '\0'; + delim--; + } - return 0; + return 0; } -int main(int argc, char **argv) +int +main (int argc, char **argv) { - if (argc != 2) { - usage(argv[0]); + if (argc != 2) + { + usage (argv[0]); + } + + char *next_bus = NULL; + char subsystem_list[4097]; + char subsystem_list_uniq[4097]; + char *delim = NULL; + char *subsystem_buf = + (char *) calloc (strlen (argv[1]) + strlen ("/subsystem") + 1, 1); + char readlink_buf[4097]; + int rc = 0; + struct stat sb; + + if (subsystem_buf == NULL) + { + exit (1); + } + + next_bus = argv[1]; + memset (subsystem_list, 0, 4097); + memset (subsystem_list_uniq, 0, 4097); + + // directory must exist + rc = stat (next_bus, &sb); + if (rc != 0) + { + exit (1); + } + + while (1) + { + + // what's the subsystem here? + sprintf (subsystem_buf, "%s/subsystem", next_bus); + + rc = lstat (subsystem_buf, &sb); + if (rc != 0) + { + + rc = remove_child (next_bus); + if (rc != 0) + { + break; + } + else + { + continue; + } } - char *next_bus = NULL; - char subsystem_list[4097]; - char subsystem_list_uniq[4097]; - char *delim = NULL; - char *subsystem_buf = - (char *)calloc(strlen(argv[1]) + strlen("/subsystem") + 1, 1); - char readlink_buf[4097]; - int rc = 0; - struct stat sb; - - if (subsystem_buf == NULL) { - exit(1); + if (!S_ISLNK (sb.st_mode)) + { + + rc = remove_child (next_bus); + if (rc != 0) + { + break; + } + else + { + continue; + } } - next_bus = argv[1]; - memset(subsystem_list, 0, 4097); - memset(subsystem_list_uniq, 0, 4097); + memset (readlink_buf, 0, 4097); + + rc = readlink (subsystem_buf, readlink_buf, 4096); + if (rc < 0) + { + + rc = remove_child (next_bus); + if (rc != 0) + { + break; + } + else + { + continue; + } + } - // directory must exist - rc = stat(next_bus, &sb); - if (rc != 0) { - exit(1); + delim = strrchr (readlink_buf, '/'); + if (delim == NULL) + { + + rc = remove_child (next_bus); + if (rc != 0) + { + break; + } + else + { + continue; + } + } + // delim + 1 is the subsystem name + if (subsystem_list[0] != 0) + { + strncat (subsystem_list, ",", 4096 - strlen (subsystem_list) - 1); + } + strncat (subsystem_list, delim + 1, 4096 - strlen (subsystem_list) - 1); + + if (strstr (subsystem_list_uniq, delim + 1) == NULL) + { + + // haven't seen this subsystem name before... + if (subsystem_list_uniq[0] != 0) + { + strncat (subsystem_list_uniq, ",", + 4096 - strlen (subsystem_list_uniq) - 1); + } + strncat (subsystem_list_uniq, delim + 1, + 4096 - strlen (subsystem_list_uniq) - 1); } - while (1) { - - // what's the subsystem here? - sprintf(subsystem_buf, "%s/subsystem", next_bus); - - rc = lstat(subsystem_buf, &sb); - if (rc != 0) { - - rc = remove_child(next_bus); - if (rc != 0) { - break; - } else { - continue; - } - } - - if (!S_ISLNK(sb.st_mode)) { - - rc = remove_child(next_bus); - if (rc != 0) { - break; - } else { - continue; - } - } - - memset(readlink_buf, 0, 4097); - - rc = readlink(subsystem_buf, readlink_buf, 4096); - if (rc < 0) { - - rc = remove_child(next_bus); - if (rc != 0) { - break; - } else { - continue; - } - } - - delim = strrchr(readlink_buf, '/'); - if (delim == NULL) { - - rc = remove_child(next_bus); - if (rc != 0) { - break; - } else { - continue; - } - } - // delim + 1 is the subsystem name - if (subsystem_list[0] != 0) { - strncat(subsystem_list, ",", - 4096 - strlen(subsystem_list) - 1); - } - strncat(subsystem_list, delim + 1, - 4096 - strlen(subsystem_list) - 1); - - if (strstr(subsystem_list_uniq, delim + 1) == NULL) { - - // haven't seen this subsystem name before... - if (subsystem_list_uniq[0] != 0) { - strncat(subsystem_list_uniq, ",", - 4096 - strlen(subsystem_list_uniq) - 1); - } - strncat(subsystem_list_uniq, delim + 1, - 4096 - strlen(subsystem_list_uniq) - 1); - } - - rc = remove_child(next_bus); - if (rc != 0) { - break; - } else { - continue; - } + rc = remove_child (next_bus); + if (rc != 0) + { + break; + } + else + { + continue; } + } - free(subsystem_buf); + free (subsystem_buf); - vdev_property_add("VDEV_BUS_SUBSYSTEMS", subsystem_list); - vdev_property_add("VDEV_BUS_SUBSYSTEMS_UNIQ", subsystem_list_uniq); + vdev_property_add ("VDEV_BUS_SUBSYSTEMS", subsystem_list); + vdev_property_add ("VDEV_BUS_SUBSYSTEMS_UNIQ", subsystem_list_uniq); - vdev_property_print(); - vdev_property_free_all(); + vdev_property_print (); + vdev_property_free_all (); - exit(0); + exit (0); } diff --git a/vdevd/helpers/LINUX/stat_input.c b/vdevd/helpers/LINUX/stat_input.c index a10c02c..4c63e7f 100644 --- a/vdevd/helpers/LINUX/stat_input.c +++ b/vdevd/helpers/LINUX/stat_input.c @@ -50,413 +50,459 @@ int g_input_class = 0; -static inline int abs_size_mm(const struct input_absinfo *absinfo) +static inline int +abs_size_mm (const struct input_absinfo *absinfo) { - /* Resolution is defined to be in units/mm for ABS_X/Y */ - return (absinfo->maximum - absinfo->minimum) / absinfo->resolution; + /* Resolution is defined to be in units/mm for ABS_X/Y */ + return (absinfo->maximum - absinfo->minimum) / absinfo->resolution; } -static void extract_input_resolution(const char *devpath) +static void +extract_input_resolution (const char *devpath) { - char width[50], height[50]; - struct input_absinfo xabsinfo = { }, yabsinfo = { - }; + char width[50], height[50]; + struct input_absinfo xabsinfo = { }, yabsinfo = + { + }; - int rc = 0; - int fd = -1; + int rc = 0; + int fd = -1; - fd = open(devpath, O_RDONLY | O_CLOEXEC); - if (fd < 0) { - rc = -errno; - log_debug("failed to open '%s', errno = %d", devpath, rc); - return; - } + fd = open (devpath, O_RDONLY | O_CLOEXEC); + if (fd < 0) + { + rc = -errno; + log_debug ("failed to open '%s', errno = %d", devpath, rc); + return; + } - if (ioctl(fd, EVIOCGABS(ABS_X), &xabsinfo) < 0 - || ioctl(fd, EVIOCGABS(ABS_Y), &yabsinfo) < 0) { + if (ioctl (fd, EVIOCGABS (ABS_X), &xabsinfo) < 0 + || ioctl (fd, EVIOCGABS (ABS_Y), &yabsinfo) < 0) + { - close(fd); - return; - } + close (fd); + return; + } - if (xabsinfo.resolution <= 0 || yabsinfo.resolution <= 0) { + if (xabsinfo.resolution <= 0 || yabsinfo.resolution <= 0) + { - close(fd); - return; - } + close (fd); + return; + } - snprintf(width, sizeof(width), "%d", abs_size_mm(&xabsinfo)); - snprintf(height, sizeof(height), "%d", abs_size_mm(&yabsinfo)); + snprintf (width, sizeof (width), "%d", abs_size_mm (&xabsinfo)); + snprintf (height, sizeof (height), "%d", abs_size_mm (&yabsinfo)); - vdev_property_add("VDEV_INPUT_WIDTH_MM", width); - vdev_property_add("VDEV_INPUT_HEIGHT_MM", height); + vdev_property_add ("VDEV_INPUT_WIDTH_MM", width); + vdev_property_add ("VDEV_INPUT_HEIGHT_MM", height); - close(fd); + close (fd); } /* * Read a capability attribute and return bitmask. * @param bitmask: Output array which has a length of bitmask_len */ -static void get_cap_mask(char const *sysfs_cap_path, unsigned long *bitmask, - size_t bitmask_len) +static void +get_cap_mask (char const *sysfs_cap_path, unsigned long *bitmask, + size_t bitmask_len) { - char text[4096]; - unsigned i; - char *word; - unsigned long val; - int rc = 0; + char text[4096]; + unsigned i; + char *word; + unsigned long val; + int rc = 0; - memset(text, 0, 4096); + memset (text, 0, 4096); - int fd = open(sysfs_cap_path, O_RDONLY); - if (fd < 0) { - return; - } + int fd = open (sysfs_cap_path, O_RDONLY); + if (fd < 0) + { + return; + } - rc = vdev_read_uninterrupted(fd, text, 4096); - close(fd); + rc = vdev_read_uninterrupted (fd, text, 4096); + close (fd); - if (rc < 0) { + if (rc < 0) + { - log_debug("read('%s') errno = %d\n", sysfs_cap_path, rc); - return; - } + log_debug ("read('%s') errno = %d\n", sysfs_cap_path, rc); + return; + } - memset(bitmask, 0, bitmask_len * sizeof(unsigned long)); + memset (bitmask, 0, bitmask_len * sizeof (unsigned long)); - i = 0; + i = 0; - while ((word = strrchr(text, ' ')) != NULL) { + while ((word = strrchr (text, ' ')) != NULL) + { - val = strtoul(word + 1, NULL, 16); - if (i < bitmask_len) { - bitmask[i] = val; - } else { - log_debug - ("ignoring %s block %lX which is larger than maximum length %zu", - sysfs_cap_path, val, bitmask_len); - } - *word = '\0'; - ++i; - } - val = strtoul(text, NULL, 16); - if (i < bitmask_len) { - bitmask[i] = val; - } else { - log_debug - ("ignoring %s block %lX which is larger than maximum length %zu", - sysfs_cap_path, val, bitmask_len); + val = strtoul (word + 1, NULL, 16); + if (i < bitmask_len) + { + bitmask[i] = val; } - - log_debug("Bitmask path: %s, length: %zu, Text: '%s'", sysfs_cap_path, - bitmask_len, text); - for (unsigned int i = 0; i < bitmask_len; i++) { - log_debug("Bitmask[%d] = %lX", i, bitmask[i]); + else + { + log_debug + ("ignoring %s block %lX which is larger than maximum length %zu", + sysfs_cap_path, val, bitmask_len); } + *word = '\0'; + ++i; + } + val = strtoul (text, NULL, 16); + if (i < bitmask_len) + { + bitmask[i] = val; + } + else + { + log_debug + ("ignoring %s block %lX which is larger than maximum length %zu", + sysfs_cap_path, val, bitmask_len); + } + + log_debug ("Bitmask path: %s, length: %zu, Text: '%s'", sysfs_cap_path, + bitmask_len, text); + for (unsigned int i = 0; i < bitmask_len; i++) + { + log_debug ("Bitmask[%d] = %lX", i, bitmask[i]); + } } /* pointer devices */ -static void test_pointers(const unsigned long *bitmask_ev, - const unsigned long *bitmask_abs, - const unsigned long *bitmask_key, - const unsigned long *bitmask_rel) +static void +test_pointers (const unsigned long *bitmask_ev, + const unsigned long *bitmask_abs, + const unsigned long *bitmask_key, + const unsigned long *bitmask_rel) { - int is_mouse = 0; - int is_touchpad = 0; - - if (!test_bit(EV_KEY, bitmask_ev)) { - if (test_bit(EV_ABS, bitmask_ev) && - test_bit(ABS_X, bitmask_abs) && - test_bit(ABS_Y, bitmask_abs) && - test_bit(ABS_Z, bitmask_abs)) { - - vdev_property_add("VDEV_INPUT_ACCELEROMETER", "1"); - } - return; - } + int is_mouse = 0; + int is_touchpad = 0; - if (test_bit(EV_ABS, bitmask_ev) && test_bit(ABS_X, bitmask_abs) - && test_bit(ABS_Y, bitmask_abs)) { + if (!test_bit (EV_KEY, bitmask_ev)) + { + if (test_bit (EV_ABS, bitmask_ev) && + test_bit (ABS_X, bitmask_abs) && + test_bit (ABS_Y, bitmask_abs) && test_bit (ABS_Z, bitmask_abs)) + { - if (test_bit(BTN_STYLUS, bitmask_key) - || test_bit(BTN_TOOL_PEN, bitmask_key)) { + vdev_property_add ("VDEV_INPUT_ACCELEROMETER", "1"); + } + return; + } - vdev_property_add("VDEV_INPUT_TABLET", "1"); + if (test_bit (EV_ABS, bitmask_ev) && test_bit (ABS_X, bitmask_abs) + && test_bit (ABS_Y, bitmask_abs)) + { - g_input_class = VDEV_INPUT_CLASS_MOUSE; - } + if (test_bit (BTN_STYLUS, bitmask_key) + || test_bit (BTN_TOOL_PEN, bitmask_key)) + { - else if (test_bit(BTN_TOOL_FINGER, bitmask_key) - && !test_bit(BTN_TOOL_PEN, bitmask_key)) { + vdev_property_add ("VDEV_INPUT_TABLET", "1"); - is_touchpad = 1; - } + g_input_class = VDEV_INPUT_CLASS_MOUSE; + } - else if (test_bit(BTN_MOUSE, bitmask_key)) { - /* This path is taken by VMware's USB mouse, which has - * absolute axes, but no touch/pressure button. */ + else if (test_bit (BTN_TOOL_FINGER, bitmask_key) + && !test_bit (BTN_TOOL_PEN, bitmask_key)) + { - is_mouse = 1; - } + is_touchpad = 1; + } - else if (test_bit(BTN_TOUCH, bitmask_key)) { + else if (test_bit (BTN_MOUSE, bitmask_key)) + { + /* This path is taken by VMware's USB mouse, which has + * absolute axes, but no touch/pressure button. */ - vdev_property_add("VDEV_INPUT_TOUCHSCREEN", "1"); + is_mouse = 1; + } - g_input_class = VDEV_INPUT_CLASS_MOUSE; - } + else if (test_bit (BTN_TOUCH, bitmask_key)) + { - /* joysticks don't necessarily have to have buttons; e. g. - * rudders/pedals are joystick-like, but buttonless; they have - * other fancy axes */ - else if (test_bit(BTN_TRIGGER, bitmask_key) || - test_bit(BTN_A, bitmask_key) || - test_bit(BTN_1, bitmask_key) || - test_bit(ABS_RX, bitmask_abs) || - test_bit(ABS_RY, bitmask_abs) || - test_bit(ABS_RZ, bitmask_abs) || - test_bit(ABS_THROTTLE, bitmask_abs) || - test_bit(ABS_RUDDER, bitmask_abs) || - test_bit(ABS_WHEEL, bitmask_abs) || - test_bit(ABS_GAS, bitmask_abs) || - test_bit(ABS_BRAKE, bitmask_abs)) { + vdev_property_add ("VDEV_INPUT_TOUCHSCREEN", "1"); - vdev_property_add("VDEV_INPUT_JOYSTICK", "1"); + g_input_class = VDEV_INPUT_CLASS_MOUSE; + } - g_input_class = VDEV_INPUT_CLASS_JOYSTICK; - } + /* joysticks don't necessarily have to have buttons; e. g. + * rudders/pedals are joystick-like, but buttonless; they have + * other fancy axes */ + else if (test_bit (BTN_TRIGGER, bitmask_key) || + test_bit (BTN_A, bitmask_key) || + test_bit (BTN_1, bitmask_key) || + test_bit (ABS_RX, bitmask_abs) || + test_bit (ABS_RY, bitmask_abs) || + test_bit (ABS_RZ, bitmask_abs) || + test_bit (ABS_THROTTLE, bitmask_abs) || + test_bit (ABS_RUDDER, bitmask_abs) || + test_bit (ABS_WHEEL, bitmask_abs) || + test_bit (ABS_GAS, bitmask_abs) || + test_bit (ABS_BRAKE, bitmask_abs)) + { + + vdev_property_add ("VDEV_INPUT_JOYSTICK", "1"); + + g_input_class = VDEV_INPUT_CLASS_JOYSTICK; } + } - if (test_bit(EV_REL, bitmask_ev) && - test_bit(REL_X, bitmask_rel) && test_bit(REL_Y, bitmask_rel) && - test_bit(BTN_MOUSE, bitmask_key)) { + if (test_bit (EV_REL, bitmask_ev) && + test_bit (REL_X, bitmask_rel) && test_bit (REL_Y, bitmask_rel) && + test_bit (BTN_MOUSE, bitmask_key)) + { - is_mouse = 1; - } + is_mouse = 1; + } - if (is_mouse) { + if (is_mouse) + { - vdev_property_add("VDEV_INPUT_MOUSE", "1"); + vdev_property_add ("VDEV_INPUT_MOUSE", "1"); - g_input_class = VDEV_INPUT_CLASS_MOUSE; - } + g_input_class = VDEV_INPUT_CLASS_MOUSE; + } - if (is_touchpad) { + if (is_touchpad) + { - vdev_property_add("VDEV_INPUT_TOUCHPAD", "1"); + vdev_property_add ("VDEV_INPUT_TOUCHPAD", "1"); - g_input_class = VDEV_INPUT_CLASS_MOUSE; - } + g_input_class = VDEV_INPUT_CLASS_MOUSE; + } } /* key like devices */ -static void test_key(const unsigned long *bitmask_ev, - const unsigned long *bitmask_key) +static void +test_key (const unsigned long *bitmask_ev, const unsigned long *bitmask_key) { - unsigned i; - unsigned long found; - unsigned long mask; - - /* do we have any KEY_* capability? */ - if (!test_bit(EV_KEY, bitmask_ev)) { - log_debug("%s", "test_key: no EV_KEY capability"); - return; + unsigned i; + unsigned long found; + unsigned long mask; + + /* do we have any KEY_* capability? */ + if (!test_bit (EV_KEY, bitmask_ev)) + { + log_debug ("%s", "test_key: no EV_KEY capability"); + return; + } + + /* only consider KEY_* here, not BTN_* */ + found = 0; + for (i = 0; i < BTN_MISC / BITS_PER_LONG; ++i) + { + found |= bitmask_key[i]; + log_debug + ("test_key: checking bit block %lu for any keys; found=%i", + (unsigned long) i * BITS_PER_LONG, found > 0); + } + + /* If there are no keys in the lower block, check the higher block */ + if (!found) + { + for (i = KEY_OK; i < BTN_TRIGGER_HAPPY; ++i) + { + if (test_bit (i, bitmask_key)) + { + log_debug ("test_key: Found key %x in high block", i); + found = 1; + break; + } } + } - /* only consider KEY_* here, not BTN_* */ - found = 0; - for (i = 0; i < BTN_MISC / BITS_PER_LONG; ++i) { - found |= bitmask_key[i]; - log_debug - ("test_key: checking bit block %lu for any keys; found=%i", - (unsigned long)i * BITS_PER_LONG, found > 0); - } + if (found > 0) + { - /* If there are no keys in the lower block, check the higher block */ - if (!found) { - for (i = KEY_OK; i < BTN_TRIGGER_HAPPY; ++i) { - if (test_bit(i, bitmask_key)) { - log_debug - ("test_key: Found key %x in high block", i); - found = 1; - break; - } - } - } - - if (found > 0) { - - vdev_property_add("VDEV_INPUT_KEY", "1"); - } + vdev_property_add ("VDEV_INPUT_KEY", "1"); + } - /* the first 32 bits are ESC, numbers, and Q to D; if we have all of - * those, consider it a full keyboard; do not test KEY_RESERVED, though */ - mask = 0xFFFFFFFE; - if ((bitmask_key[0] & mask) == mask) { + /* the first 32 bits are ESC, numbers, and Q to D; if we have all of + * those, consider it a full keyboard; do not test KEY_RESERVED, though */ + mask = 0xFFFFFFFE; + if ((bitmask_key[0] & mask) == mask) + { - vdev_property_add("VDEV_INPUT_KEYBOARD", "1"); + vdev_property_add ("VDEV_INPUT_KEYBOARD", "1"); - g_input_class = VDEV_INPUT_CLASS_KBD; - } + g_input_class = VDEV_INPUT_CLASS_KBD; + } } -void usage(char const *program_name) +void +usage (char const *program_name) { - fprintf(stderr, "[ERROR] %s: Usage: %s /path/to/input/device/file\n", - program_name, program_name); + fprintf (stderr, "[ERROR] %s: Usage: %s /path/to/input/device/file\n", + program_name, program_name); } // entry point // TODO: support using a sysfs device path directly -int main(int argc, char **argv) +int +main (int argc, char **argv) { - // look for the character device with VDEV_MAJOR and VDEV_MINOR - char capabilities_path[4096]; - char full_sysfs_path[4096]; - char subsystem[4096]; - char sysdev_path[4096]; - - unsigned long bitmask_ev[NBITS(EV_MAX)]; - unsigned long bitmask_abs[NBITS(ABS_MAX)]; - unsigned long bitmask_key[NBITS(KEY_MAX)]; - unsigned long bitmask_rel[NBITS(REL_MAX)]; - - struct stat sb; - int rc = 0; - char major[20]; - char minor[20]; - char *basename = NULL; - - if (argc != 2) { - usage(argv[0]); - exit(1); - } - - rc = stat(argv[1], &sb); - if (rc != 0) { - - rc = -errno; - fprintf(stderr, "[ERROR] %s: stat('%s') errno = %d\n", argv[0], - argv[1], rc); - exit(2); - } - - if (!S_ISCHR(sb.st_mode)) { - - fprintf(stderr, - "[ERROR] %s: '%s' is not a character device file\n", - argv[0], argv[1]); - usage(argv[0]); - exit(2); - } - - sprintf(major, "%u", major(sb.st_rdev)); - sprintf(minor, "%u", minor(sb.st_rdev)); - - static char const *caps[] = { - "ev", - "abs", - "key", - "rel", - NULL - }; - - unsigned long *bitmasks[] = { - bitmask_ev, - bitmask_abs, - bitmask_key, - bitmask_rel, - NULL - }; - - size_t bitmask_lens[] = { - NBITS(EV_MAX), - NBITS(ABS_MAX), - NBITS(KEY_MAX), - NBITS(REL_MAX), - 0 - }; - - if (major == NULL || minor == NULL) { - // nothing to do here - exit(1); - } - // is this an input device? - memset(sysdev_path, 0, 4096); - memset(subsystem, 0, 4096); - - snprintf(sysdev_path, 4096, "/sys/dev/char/%s:%s/subsystem", major, - minor); - rc = readlink(sysdev_path, subsystem, 4096); - if (rc < 0) { - fprintf(stderr, "[ERROR] %s: readlink('%s'): %s\n", argv[0], - sysdev_path, strerror(rc)); - exit(1); - } - - if (strcmp(subsystem + strlen(subsystem) - 5, "input") != 0) { - - // not an input device - exit(1); - } - // replaces ID_INPUT - vdev_property_add("VDEV_INPUT", "1"); - - memset(capabilities_path, 0, 4096); - - snprintf(capabilities_path, 4095, - "/sys/dev/char/%s:%s/device/capabilities", major, minor); - - // read each capability - for (int i = 0; caps[i] != NULL; i++) { - - memset(full_sysfs_path, 0, 4096); - snprintf(full_sysfs_path, 4096, "%s/%s", capabilities_path, - caps[i]); - - get_cap_mask(full_sysfs_path, bitmasks[i], bitmask_lens[i]); - } - - // build up properties - test_pointers(bitmask_ev, bitmask_abs, bitmask_key, bitmask_rel); - test_key(bitmask_ev, bitmask_key); - - basename = rindex(argv[1], '/') + 1; - - if (strncmp(basename, "event", 5) == 0) { - - extract_input_resolution(argv[1]); - } - // state the input class too - switch (g_input_class) { - - case VDEV_INPUT_CLASS_JOYSTICK:{ - - vdev_property_add("VDEV_INPUT_CLASS", "joystick"); - break; - } - - case VDEV_INPUT_CLASS_MOUSE:{ - - vdev_property_add("VDEV_INPUT_CLASS", "mouse"); - break; - } - - case VDEV_INPUT_CLASS_KBD:{ - - vdev_property_add("VDEV_INPUT_CLASS", "kbd"); - break; - } - } - - vdev_property_print(); - vdev_property_free_all(); - - return 0; + // look for the character device with VDEV_MAJOR and VDEV_MINOR + char capabilities_path[4096]; + char full_sysfs_path[4096]; + char subsystem[4096]; + char sysdev_path[4096]; + + unsigned long bitmask_ev[NBITS (EV_MAX)]; + unsigned long bitmask_abs[NBITS (ABS_MAX)]; + unsigned long bitmask_key[NBITS (KEY_MAX)]; + unsigned long bitmask_rel[NBITS (REL_MAX)]; + + struct stat sb; + int rc = 0; + char major[20]; + char minor[20]; + char *basename = NULL; + + if (argc != 2) + { + usage (argv[0]); + exit (1); + } + + rc = stat (argv[1], &sb); + if (rc != 0) + { + + rc = -errno; + fprintf (stderr, "[ERROR] %s: stat('%s') errno = %d\n", argv[0], + argv[1], rc); + exit (2); + } + + if (!S_ISCHR (sb.st_mode)) + { + + fprintf (stderr, + "[ERROR] %s: '%s' is not a character device file\n", + argv[0], argv[1]); + usage (argv[0]); + exit (2); + } + + sprintf (major, "%u", major (sb.st_rdev)); + sprintf (minor, "%u", minor (sb.st_rdev)); + + static char const *caps[] = { + "ev", + "abs", + "key", + "rel", + NULL + }; + + unsigned long *bitmasks[] = { + bitmask_ev, + bitmask_abs, + bitmask_key, + bitmask_rel, + NULL + }; + + size_t bitmask_lens[] = { + NBITS (EV_MAX), + NBITS (ABS_MAX), + NBITS (KEY_MAX), + NBITS (REL_MAX), + 0 + }; + + if (major == NULL || minor == NULL) + { + // nothing to do here + exit (1); + } + // is this an input device? + memset (sysdev_path, 0, 4096); + memset (subsystem, 0, 4096); + + snprintf (sysdev_path, 4096, "/sys/dev/char/%s:%s/subsystem", major, minor); + rc = readlink (sysdev_path, subsystem, 4096); + if (rc < 0) + { + fprintf (stderr, "[ERROR] %s: readlink('%s'): %s\n", argv[0], + sysdev_path, strerror (rc)); + exit (1); + } + + if (strcmp (subsystem + strlen (subsystem) - 5, "input") != 0) + { + + // not an input device + exit (1); + } + // replaces ID_INPUT + vdev_property_add ("VDEV_INPUT", "1"); + + memset (capabilities_path, 0, 4096); + + snprintf (capabilities_path, 4095, + "/sys/dev/char/%s:%s/device/capabilities", major, minor); + + // read each capability + for (int i = 0; caps[i] != NULL; i++) + { + + memset (full_sysfs_path, 0, 4096); + snprintf (full_sysfs_path, 4096, "%s/%s", capabilities_path, caps[i]); + + get_cap_mask (full_sysfs_path, bitmasks[i], bitmask_lens[i]); + } + + // build up properties + test_pointers (bitmask_ev, bitmask_abs, bitmask_key, bitmask_rel); + test_key (bitmask_ev, bitmask_key); + + basename = rindex (argv[1], '/') + 1; + + if (strncmp (basename, "event", 5) == 0) + { + + extract_input_resolution (argv[1]); + } + // state the input class too + switch (g_input_class) + { + + case VDEV_INPUT_CLASS_JOYSTICK: + { + + vdev_property_add ("VDEV_INPUT_CLASS", "joystick"); + break; + } + + case VDEV_INPUT_CLASS_MOUSE: + { + + vdev_property_add ("VDEV_INPUT_CLASS", "mouse"); + break; + } + + case VDEV_INPUT_CLASS_KBD: + { + + vdev_property_add ("VDEV_INPUT_CLASS", "kbd"); + break; + } + } + + vdev_property_print (); + vdev_property_free_all (); + + return 0; } diff --git a/vdevd/helpers/LINUX/stat_net.c b/vdevd/helpers/LINUX/stat_net.c index 6f813fc..1c43f4d 100644 --- a/vdevd/helpers/LINUX/stat_net.c +++ b/vdevd/helpers/LINUX/stat_net.c @@ -102,973 +102,1080 @@ #include #include -enum netname_type { - NET_UNDEF, - NET_PCI, - NET_USB, - NET_BCMA, - NET_VIRTIO, - NET_CCWGROUP, +enum netname_type +{ + NET_UNDEF, + NET_PCI, + NET_USB, + NET_BCMA, + NET_VIRTIO, + NET_CCWGROUP, }; -struct netnames { - enum netname_type type; +struct netnames +{ + enum netname_type type; - uint8_t mac[6]; - bool mac_valid; + uint8_t mac[6]; + bool mac_valid; - char *pcidev; // sysfs device path - char pci_slot[IFNAMSIZ + 1]; - char pci_path[IFNAMSIZ + 1]; - char pci_onboard[IFNAMSIZ + 1]; - char *pci_onboard_label; + char *pcidev; // sysfs device path + char pci_slot[IFNAMSIZ + 1]; + char pci_path[IFNAMSIZ + 1]; + char pci_onboard[IFNAMSIZ + 1]; + char *pci_onboard_label; - char usb_ports[IFNAMSIZ + 1]; - char bcma_core[IFNAMSIZ + 1]; - char ccw_group[IFNAMSIZ + 1]; + char usb_ports[IFNAMSIZ + 1]; + char bcma_core[IFNAMSIZ + 1]; + char ccw_group[IFNAMSIZ + 1]; }; /* retrieve on-board index number and label from firmware */ -static int dev_pci_onboard(struct netnames *names) +static int +dev_pci_onboard (struct netnames *names) { - char *index; - size_t index_len; + char *index; + size_t index_len; - int idx; - int rc = 0; + int idx; + int rc = 0; - /* ACPI _DSM -- device specific method for naming a PCI or PCI Express device */ - rc = vdev_sysfs_read_attr(names->pcidev, "acpi_index", &index, - &index_len); + /* ACPI _DSM -- device specific method for naming a PCI or PCI Express device */ + rc = vdev_sysfs_read_attr (names->pcidev, "acpi_index", &index, &index_len); - /* SMBIOS type 41 -- Onboard Devices Extended Information */ - if (rc < 0) { - rc = vdev_sysfs_read_attr(names->pcidev, "index", &index, - &index_len); - } + /* SMBIOS type 41 -- Onboard Devices Extended Information */ + if (rc < 0) + { + rc = vdev_sysfs_read_attr (names->pcidev, "index", &index, &index_len); + } - if (rc < 0) { - return -ENOENT; - } + if (rc < 0) + { + return -ENOENT; + } - idx = strtoul(index, NULL, 0); - if (idx <= 0) { + idx = strtoul (index, NULL, 0); + if (idx <= 0) + { - free(index); - return -EINVAL; - } + free (index); + return -EINVAL; + } - snprintf(names->pci_onboard, sizeof(names->pci_onboard), "o%d", idx); + snprintf (names->pci_onboard, sizeof (names->pci_onboard), "o%d", idx); - vdev_sysfs_read_attr(names->pcidev, "label", &names->pci_onboard_label, - &index_len); - free(index); + vdev_sysfs_read_attr (names->pcidev, "label", &names->pci_onboard_label, + &index_len); + free (index); - return 0; + return 0; } /* read the 256 bytes PCI configuration space to check the multi-function bit */ -static bool is_pci_multifunction(char const *sysfs_path) +static bool +is_pci_multifunction (char const *sysfs_path) { - FILE *f = NULL; - char *filename; - uint8_t config[64]; + FILE *f = NULL; + char *filename; + uint8_t config[64]; - filename = - (char *)calloc(strlen(sysfs_path) + 1 + strlen("/config") + 1, 1); - if (filename == NULL) { - return -ENOMEM; - } + filename = + (char *) calloc (strlen (sysfs_path) + 1 + strlen ("/config") + 1, 1); + if (filename == NULL) + { + return -ENOMEM; + } - sprintf(filename, "%s/config", sysfs_path); + sprintf (filename, "%s/config", sysfs_path); - f = fopen(filename, "re"); - if (!f) { + f = fopen (filename, "re"); + if (!f) + { - free(filename); - return false; - } + free (filename); + return false; + } - if (fread(&config, sizeof(config), 1, f) != 1) { + if (fread (&config, sizeof (config), 1, f) != 1) + { - free(filename); - fclose(f); - return false; - } + free (filename); + fclose (f); + return false; + } - fclose(f); + fclose (f); - /* bit 0-6 header type, bit 7 multi/single function device */ - if ((config[PCI_HEADER_TYPE] & 0x80) != 0) { - free(filename); - return true; - } + /* bit 0-6 header type, bit 7 multi/single function device */ + if ((config[PCI_HEADER_TYPE] & 0x80) != 0) + { + free (filename); + return true; + } - free(filename); + free (filename); - return false; + return false; } // calculate the pci path and slot of the device -static int dev_pci_slot(char const *dev_path, struct netnames *names) +static int +dev_pci_slot (char const *dev_path, struct netnames *names) { - unsigned domain, bus, slot, func, dev_port = 0; + unsigned domain, bus, slot, func, dev_port = 0; - char *attr; - size_t attr_len; + char *attr; + size_t attr_len; - char *pci_sysfs_path = NULL; - size_t pci_sysfs_path_len = 0; + char *pci_sysfs_path = NULL; + size_t pci_sysfs_path_len = 0; + + char *slots = NULL; + char *address_path = NULL; + + DIR *dir = NULL; + struct dirent *dent; + int hotplug_slot = 0, err = 0; + char *pcidev_sysname = NULL; + size_t pcidev_sysname_len = 0; + int rc = 0; - char *slots = NULL; - char *address_path = NULL; + rc = vdev_sysfs_get_sysname (names->pcidev, &pcidev_sysname, + &pcidev_sysname_len); + if (rc != 0) + { + return rc; + } - DIR *dir = NULL; - struct dirent *dent; - int hotplug_slot = 0, err = 0; - char *pcidev_sysname = NULL; - size_t pcidev_sysname_len = 0; - int rc = 0; + if (sscanf (pcidev_sysname, "%x:%x:%x.%u", &domain, &bus, &slot, &func) + != 4) + { - rc = vdev_sysfs_get_sysname(names->pcidev, &pcidev_sysname, - &pcidev_sysname_len); - if (rc != 0) { - return rc; - } + free (pcidev_sysname); + return -ENOENT; + } - if (sscanf(pcidev_sysname, "%x:%x:%x.%u", &domain, &bus, &slot, &func) - != 4) { + free (pcidev_sysname); - free(pcidev_sysname); - return -ENOENT; - } + /* kernel provided multi-device index */ + rc = vdev_sysfs_read_attr (dev_path, "dev_port", &attr, &attr_len); + if (rc == 0) + { + dev_port = strtol (attr, NULL, 10); + free (attr); + } - free(pcidev_sysname); + /* compose a name based on the raw kernel's PCI bus, slot numbers */ + memset (names->pci_path, 0, IFNAMSIZ + 1); - /* kernel provided multi-device index */ - rc = vdev_sysfs_read_attr(dev_path, "dev_port", &attr, &attr_len); - if (rc == 0) { - dev_port = strtol(attr, NULL, 10); - free(attr); - } + if (domain > 0) + { - /* compose a name based on the raw kernel's PCI bus, slot numbers */ - memset(names->pci_path, 0, IFNAMSIZ + 1); + sprintf (names->pci_path + strlen (names->pci_path), "P%u", domain); + } - if (domain > 0) { + sprintf (names->pci_path + strlen (names->pci_path), "p%us%u", bus, slot); - sprintf(names->pci_path + strlen(names->pci_path), "P%u", - domain); - } + if (func > 0 || is_pci_multifunction (names->pcidev)) + { - sprintf(names->pci_path + strlen(names->pci_path), "p%us%u", bus, slot); + sprintf (names->pci_path + strlen (names->pci_path), "f%u", func); + } - if (func > 0 || is_pci_multifunction(names->pcidev)) { + if (dev_port > 0) + { - sprintf(names->pci_path + strlen(names->pci_path), "f%u", func); - } + sprintf (names->pci_path + strlen (names->pci_path), "d%u", dev_port); + } - if (dev_port > 0) { + if (strlen (names->pci_path) == 0) + { + names->pci_path[0] = '\0'; + } - sprintf(names->pci_path + strlen(names->pci_path), "d%u", - dev_port); - } + /* ACPI _SUN -- slot user number */ + rc = vdev_sysfs_device_path_from_subsystem_sysname ("/sys", "subsystem", + "pci", + &pci_sysfs_path, + &pci_sysfs_path_len); + if (rc != 0) + { + err = -ENOENT; + goto out; + } - if (strlen(names->pci_path) == 0) { - names->pci_path[0] = '\0'; - } + slots = + (char *) calloc (strlen (pci_sysfs_path) + strlen ("/slots") + 1, 1); + if (slots == NULL) + { + err = -ENOMEM; - /* ACPI _SUN -- slot user number */ - rc = vdev_sysfs_device_path_from_subsystem_sysname("/sys", "subsystem", - "pci", - &pci_sysfs_path, - &pci_sysfs_path_len); - if (rc != 0) { - err = -ENOENT; - goto out; - } + free (pci_sysfs_path); + goto out; + } - slots = - (char *)calloc(strlen(pci_sysfs_path) + strlen("/slots") + 1, 1); - if (slots == NULL) { - err = -ENOMEM; + sprintf (slots, "%s/slots", pci_sysfs_path); - free(pci_sysfs_path); - goto out; - } + free (pci_sysfs_path); - sprintf(slots, "%s/slots", pci_sysfs_path); + dir = opendir (slots); + if (!dir) + { + err = -errno; + goto out; + } - free(pci_sysfs_path); + for (dent = readdir (dir); dent != NULL; dent = readdir (dir)) + { + int i; + char *rest; + char *address; + size_t address_len = 0; - dir = opendir(slots); - if (!dir) { - err = -errno; - goto out; + if (dent->d_name[0] == '.') + { + continue; } - for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) { - int i; - char *rest; - char *address; - size_t address_len = 0; - - if (dent->d_name[0] == '.') { - continue; - } - - i = strtol(dent->d_name, &rest, 10); - - if (rest[0] != '\0') { - continue; - } - - if (i < 1) { - continue; - } - - address_path = - (char *)calloc(strlen(slots) + strlen(dent->d_name) + 3 + - strlen("address"), 1); - if (address_path == NULL) { - err = -ENOMEM; - goto out; - } - - sprintf(address_path, "%s/%s/address", slots, dent->d_name); - - rc = vdev_read_file(address_path, &address, &address_len); - if (rc != 0) { + i = strtol (dent->d_name, &rest, 10); - free(address_path); - continue; - } - - free(address_path); - - // take the first line only - if (index(address, '\n') != NULL) { - - *(index(address, '\n')) = '\0'; - } - - /* match slot address with device by stripping the function */ - if (strneq(address, names->pcidev, strlen(address))) { - hotplug_slot = i; - } - - free(address); - - if (hotplug_slot > 0) { - break; - } + if (rest[0] != '\0') + { + continue; } - closedir(dir); - - if (hotplug_slot > 0) { - - memset(names->pci_slot, 0, IFNAMSIZ + 1); - - if (domain > 0) { - - sprintf(names->pci_slot + strlen(names->pci_slot), - "P%d", domain); - } - - sprintf(names->pci_slot + strlen(names->pci_slot), "s%d", - hotplug_slot); - - if (func > 0 || is_pci_multifunction(names->pcidev)) { - - sprintf(names->pci_slot + strlen(names->pci_slot), - "f%d", func); - } - - if (dev_port > 0) { - - sprintf(names->pci_slot + strlen(names->pci_slot), - "d%d", dev_port); - } - - if (strlen(names->pci_slot) == 0) { - names->pci_slot[0] = '\0'; - } - } - out: - return err; -} - -static int names_pci(char const *dev_path, struct netnames *names) -{ - - char *parent_device_path = NULL; - size_t parent_device_path_len = 0; - - char *parent_device_subsystem = NULL; - size_t parent_device_subsystem_len = 0; - - int rc = 0; - - // get parent device - rc = vdev_sysfs_get_parent_device(dev_path, &parent_device_path, - &parent_device_path_len); - if (rc != 0) { - - if (rc != -ENOENT) { - // some other fatal error - log_error - ("WARN: vdev_sysfs_get_parent_device('%s') rc = %d\n", - dev_path, rc); - } - - return rc; + if (i < 1) + { + continue; } - // get parent subsystem - rc = vdev_sysfs_read_subsystem(parent_device_path, - &parent_device_subsystem, - &parent_device_subsystem_len); - if (rc != 0) { - free(parent_device_path); - - log_error("WARN: vdev_sysfs_read_subsystem('%s') rc = %d\n", - parent_device_path, rc); - return rc; + address_path = + (char *) calloc (strlen (slots) + strlen (dent->d_name) + 3 + + strlen ("address"), 1); + if (address_path == NULL) + { + err = -ENOMEM; + goto out; } - /* check if our direct parent is a PCI device with no other bus in-between */ - if (strcmp("pci", parent_device_subsystem) == 0) { - - names->type = NET_PCI; - names->pcidev = strdup(parent_device_path); + sprintf (address_path, "%s/%s/address", slots, dent->d_name); - if (names->pcidev == NULL) { - free(parent_device_path); - free(parent_device_subsystem); - return -ENOMEM; - } - } else { + rc = vdev_read_file (address_path, &address, &address_len); + if (rc != 0) + { - size_t pcidev_len = 0; - rc = vdev_sysfs_get_parent_with_subsystem_devtype(dev_path, - "pci", NULL, - &names-> - pcidev, - &pcidev_len); - - if (rc != 0) { - - if (rc != -ENOENT) { - log_error - ("WARN: vdev_sysfs_get_parent_with_subsystem_devtype('%s', 'pci', NULL) rc = %d\n", - dev_path, rc); - } - - return rc; - } + free (address_path); + continue; } - free(parent_device_subsystem); - free(parent_device_path); - - dev_pci_onboard(names); - dev_pci_slot(dev_path, names); - return 0; -} + free (address_path); -static int names_usb(char const *dev_path, struct netnames *names) -{ + // take the first line only + if (index (address, '\n') != NULL) + { - char *ports; - char *config; - char *interf; - char *s; - char *usbdev_path = NULL; - char *usbdev_sysname = NULL; - size_t usbdev_path_len = 0; - size_t usbdev_sysname_len = 0; - int rc = 0; - - rc = vdev_sysfs_get_parent_with_subsystem_devtype(dev_path, "usb", - "usb_interface", - &usbdev_path, - &usbdev_path_len); - if (rc != 0) { - - if (rc != -ENOENT) { - log_error - ("WARN: vdev_sysfs_get_parent_with_subsystem_devtype('%s', 'usb', 'usb_interface') rc = %d\n", - dev_path, rc); - } - - return rc; + *(index (address, '\n')) = '\0'; } - rc = vdev_sysfs_get_sysname(usbdev_path, &usbdev_sysname, - &usbdev_sysname_len); - if (rc != 0) { - - free(usbdev_path); - return rc; + /* match slot address with device by stripping the function */ + if (strneq (address, names->pcidev, strlen (address))) + { + hotplug_slot = i; } - free(usbdev_path); - - /* get USB port number chain, configuration, interface */ - s = strchr(usbdev_sysname, '-'); - if (!s) { + free (address); - free(usbdev_sysname); - return -EINVAL; + if (hotplug_slot > 0) + { + break; } + } - ports = s + 1; + closedir (dir); - s = strchr(ports, ':'); - if (!s) { + if (hotplug_slot > 0) + { - free(usbdev_sysname); - return -EINVAL; - } - - s[0] = '\0'; - config = s + 1; + memset (names->pci_slot, 0, IFNAMSIZ + 1); - s = strchr(config, '.'); - if (!s) { + if (domain > 0) + { - free(usbdev_sysname); - return -EINVAL; + sprintf (names->pci_slot + strlen (names->pci_slot), "P%d", domain); } - s[0] = '\0'; - interf = s + 1; - - /* prefix every port number in the chain with "u" */ - s = ports; - while ((s = strchr(s, '.'))) { - s[0] = 'u'; - } + sprintf (names->pci_slot + strlen (names->pci_slot), "s%d", + hotplug_slot); - // set up usb_ports - s = names->usb_ports; - memset(s, 0, IFNAMSIZ + 1); + if (func > 0 || is_pci_multifunction (names->pcidev)) + { - strncat(s, "u", IFNAMSIZ); - strncat(s, ports, IFNAMSIZ); - - /* append USB config number, suppress the common config == 1 */ - if (strcmp(config, "1") != 0) { - strncat(s, "c", IFNAMSIZ); - strncat(s, ports, IFNAMSIZ); - } - - /* append USB interface number, suppress the interface == 0 */ - if (strcmp(interf, "0") != 0) { - strncat(s, "i", IFNAMSIZ); - strncat(s, interf, IFNAMSIZ); + sprintf (names->pci_slot + strlen (names->pci_slot), "f%d", func); } - if (strlen(s) == 0) { + if (dev_port > 0) + { - free(usbdev_sysname); - return -ENAMETOOLONG; + sprintf (names->pci_slot + strlen (names->pci_slot), + "d%d", dev_port); } - free(usbdev_sysname); - names->type = NET_USB; - return 0; + if (strlen (names->pci_slot) == 0) + { + names->pci_slot[0] = '\0'; + } + } +out: + return err; } -static int names_bcma(char const *devpath, struct netnames *names) +static int +names_pci (char const *dev_path, struct netnames *names) { - char *bcmadev_path = NULL; - size_t bcmadev_path_len = 0; - char *bcmadev_sysname = NULL; - size_t bcmadev_sysname_len = 0; - unsigned int core; - int rc = 0; - - rc = vdev_sysfs_get_parent_with_subsystem_devtype(devpath, "bcma", NULL, - &bcmadev_path, - &bcmadev_path_len); - if (rc != 0) { - - if (rc != -ENOENT) { - log_error - ("vdev_sysfs_get_parent_with_subsystem_devtype('%s', 'bcma', NULL) rc = %d\n", - devpath, rc); - } - - return rc; - } - - rc = vdev_sysfs_get_sysname(devpath, &bcmadev_sysname, - &bcmadev_sysname_len); - if (rc != 0) { + char *parent_device_path = NULL; + size_t parent_device_path_len = 0; - free(bcmadev_path); - return rc; - } + char *parent_device_subsystem = NULL; + size_t parent_device_subsystem_len = 0; - /* bus num:core num */ - if (sscanf(bcmadev_sysname, "bcma%*u:%u", &core) != 1) { + int rc = 0; - free(bcmadev_path); - free(bcmadev_sysname); - return -EINVAL; - } + // get parent device + rc = vdev_sysfs_get_parent_device (dev_path, &parent_device_path, + &parent_device_path_len); + if (rc != 0) + { - /* suppress the common core == 0 */ - if (core > 0) { - snprintf(names->bcma_core, sizeof(names->bcma_core), "b%u", - core); + if (rc != -ENOENT) + { + // some other fatal error + log_error + ("WARN: vdev_sysfs_get_parent_device('%s') rc = %d\n", + dev_path, rc); } - names->type = NET_BCMA; - - free(bcmadev_path); - free(bcmadev_sysname); - return 0; -} - -static int names_ccw(char const *devpath, struct netnames *names) -{ - - char *bus_id = NULL; - size_t bus_id_len = 0; - int rc; - - char *parent_devpath = NULL; - size_t parent_devpath_len = 0; - - char *parent_subsystem = NULL; - size_t parent_subsystem_len = 0; - - /* Retrieve the associated CCW device */ - rc = vdev_sysfs_get_parent_device(devpath, &parent_devpath, - &parent_devpath_len); - if (rc != 0) { - return -ENOENT; - } - // get parent subsystem - rc = vdev_sysfs_read_subsystem(parent_devpath, &parent_subsystem, - &parent_subsystem_len); - if (rc != 0) { + return rc; + } + // get parent subsystem + rc = vdev_sysfs_read_subsystem (parent_device_path, + &parent_device_subsystem, + &parent_device_subsystem_len); + if (rc != 0) + { - free(parent_devpath); - return rc; - } + free (parent_device_path); - /* Network devices are always grouped CCW devices */ - if (strcmp("ccwgroup", parent_subsystem) != 0) { + log_error ("WARN: vdev_sysfs_read_subsystem('%s') rc = %d\n", + parent_device_path, rc); + return rc; + } - free(parent_devpath); - free(parent_subsystem); - return -ENOENT; - } + /* check if our direct parent is a PCI device with no other bus in-between */ + if (strcmp ("pci", parent_device_subsystem) == 0) + { - /* Retrieve bus-ID of the grouped CCW device. The bus-ID uniquely - * identifies the network device on the Linux on System z channel - * subsystem. Note that the bus-ID contains lowercase characters. - */ - rc = vdev_sysfs_get_sysname(parent_devpath, &bus_id, &bus_id_len); - if (rc != 0) { + names->type = NET_PCI; + names->pcidev = strdup (parent_device_path); - free(parent_devpath); - free(parent_subsystem); - return -ENOENT; + if (names->pcidev == NULL) + { + free (parent_device_path); + free (parent_device_subsystem); + return -ENOMEM; } + } + else + { - /* Check the length of the bus-ID. Rely on that the kernel provides - * a correct bus-ID; alternatively, improve this check and parse and - * verify each bus-ID part... - */ - if (bus_id_len == 0 || bus_id_len < 8 || bus_id_len > 9) { + size_t pcidev_len = 0; + rc = vdev_sysfs_get_parent_with_subsystem_devtype (dev_path, + "pci", NULL, + &names->pcidev, + &pcidev_len); - free(parent_devpath); - free(parent_subsystem); - free(bus_id); + if (rc != 0) + { - return -EINVAL; - } + if (rc != -ENOENT) + { + log_error + ("WARN: vdev_sysfs_get_parent_with_subsystem_devtype('%s', 'pci', NULL) rc = %d\n", + dev_path, rc); + } - /* Store the CCW bus-ID for use as network device name */ - rc = snprintf(names->ccw_group, sizeof(names->ccw_group), "ccw%s", - bus_id); - if (rc >= 0 && rc < (int)sizeof(names->ccw_group)) { - names->type = NET_CCWGROUP; + return rc; } + } - free(parent_devpath); - free(parent_subsystem); - free(bus_id); + free (parent_device_subsystem); + free (parent_device_path); - return 0; + dev_pci_onboard (names); + dev_pci_slot (dev_path, names); + return 0; } -static int names_mac(char const *devpath, struct netnames *names) +static int +names_usb (char const *dev_path, struct netnames *names) { - unsigned int i; - unsigned int a1, a2, a3, a4, a5, a6; - int rc = 0; - - char *addr_assign_type = NULL; - size_t addr_assign_type_len = 0; - - char *address = NULL; - size_t address_len = 0; - - rc = vdev_sysfs_read_attr(devpath, "addr_assign_type", - &addr_assign_type, &addr_assign_type_len); - if (rc != 0) { - return rc; - } - - i = strtoul(addr_assign_type, NULL, 0); - if (i != 0) { - - free(addr_assign_type); - return 0; - } - - rc = vdev_sysfs_read_attr(devpath, "address", &address, &address_len); - if (rc != 0) { + char *ports; + char *config; + char *interf; + char *s; + char *usbdev_path = NULL; + char *usbdev_sysname = NULL; + size_t usbdev_path_len = 0; + size_t usbdev_sysname_len = 0; + int rc = 0; + + rc = vdev_sysfs_get_parent_with_subsystem_devtype (dev_path, "usb", + "usb_interface", + &usbdev_path, + &usbdev_path_len); + if (rc != 0) + { + + if (rc != -ENOENT) + { + log_error + ("WARN: vdev_sysfs_get_parent_with_subsystem_devtype('%s', 'usb', 'usb_interface') rc = %d\n", + dev_path, rc); + } + + return rc; + } + + rc = vdev_sysfs_get_sysname (usbdev_path, &usbdev_sysname, + &usbdev_sysname_len); + if (rc != 0) + { + + free (usbdev_path); + return rc; + } + + free (usbdev_path); + + /* get USB port number chain, configuration, interface */ + s = strchr (usbdev_sysname, '-'); + if (!s) + { + + free (usbdev_sysname); + return -EINVAL; + } + + ports = s + 1; + + s = strchr (ports, ':'); + if (!s) + { + + free (usbdev_sysname); + return -EINVAL; + } + + s[0] = '\0'; + config = s + 1; + + s = strchr (config, '.'); + if (!s) + { + + free (usbdev_sysname); + return -EINVAL; + } + + s[0] = '\0'; + interf = s + 1; + + /* prefix every port number in the chain with "u" */ + s = ports; + while ((s = strchr (s, '.'))) + { + s[0] = 'u'; + } + + // set up usb_ports + s = names->usb_ports; + memset (s, 0, IFNAMSIZ + 1); + + strncat (s, "u", IFNAMSIZ); + strncat (s, ports, IFNAMSIZ); + + /* append USB config number, suppress the common config == 1 */ + if (strcmp (config, "1") != 0) + { + strncat (s, "c", IFNAMSIZ); + strncat (s, ports, IFNAMSIZ); + } + + /* append USB interface number, suppress the interface == 0 */ + if (strcmp (interf, "0") != 0) + { + strncat (s, "i", IFNAMSIZ); + strncat (s, interf, IFNAMSIZ); + } + + if (strlen (s) == 0) + { + + free (usbdev_sysname); + return -ENAMETOOLONG; + } + + free (usbdev_sysname); + names->type = NET_USB; + return 0; +} - free(addr_assign_type); - return rc; - } +static int +names_bcma (char const *devpath, struct netnames *names) +{ - rc = sscanf(address, "%x:%x:%x:%x:%x:%x", &a1, &a2, &a3, &a4, &a5, &a6); - if (rc != 6) { + char *bcmadev_path = NULL; + size_t bcmadev_path_len = 0; + char *bcmadev_sysname = NULL; + size_t bcmadev_sysname_len = 0; + unsigned int core; + int rc = 0; + + rc = vdev_sysfs_get_parent_with_subsystem_devtype (devpath, "bcma", NULL, + &bcmadev_path, + &bcmadev_path_len); + if (rc != 0) + { + + if (rc != -ENOENT) + { + log_error + ("vdev_sysfs_get_parent_with_subsystem_devtype('%s', 'bcma', NULL) rc = %d\n", + devpath, rc); + } + + return rc; + } + + rc = vdev_sysfs_get_sysname (devpath, &bcmadev_sysname, + &bcmadev_sysname_len); + if (rc != 0) + { + + free (bcmadev_path); + return rc; + } + + /* bus num:core num */ + if (sscanf (bcmadev_sysname, "bcma%*u:%u", &core) != 1) + { + + free (bcmadev_path); + free (bcmadev_sysname); + return -EINVAL; + } + + /* suppress the common core == 0 */ + if (core > 0) + { + snprintf (names->bcma_core, sizeof (names->bcma_core), "b%u", core); + } + + names->type = NET_BCMA; + + free (bcmadev_path); + free (bcmadev_sysname); + return 0; +} - free(addr_assign_type); - free(address); - return -EINVAL; - } +static int +names_ccw (char const *devpath, struct netnames *names) +{ - free(addr_assign_type); - free(address); + char *bus_id = NULL; + size_t bus_id_len = 0; + int rc; + + char *parent_devpath = NULL; + size_t parent_devpath_len = 0; + + char *parent_subsystem = NULL; + size_t parent_subsystem_len = 0; + + /* Retrieve the associated CCW device */ + rc = vdev_sysfs_get_parent_device (devpath, &parent_devpath, + &parent_devpath_len); + if (rc != 0) + { + return -ENOENT; + } + // get parent subsystem + rc = vdev_sysfs_read_subsystem (parent_devpath, &parent_subsystem, + &parent_subsystem_len); + if (rc != 0) + { + + free (parent_devpath); + return rc; + } + + /* Network devices are always grouped CCW devices */ + if (strcmp ("ccwgroup", parent_subsystem) != 0) + { + + free (parent_devpath); + free (parent_subsystem); + return -ENOENT; + } + + /* Retrieve bus-ID of the grouped CCW device. The bus-ID uniquely + * identifies the network device on the Linux on System z channel + * subsystem. Note that the bus-ID contains lowercase characters. + */ + rc = vdev_sysfs_get_sysname (parent_devpath, &bus_id, &bus_id_len); + if (rc != 0) + { + + free (parent_devpath); + free (parent_subsystem); + return -ENOENT; + } + + /* Check the length of the bus-ID. Rely on that the kernel provides + * a correct bus-ID; alternatively, improve this check and parse and + * verify each bus-ID part... + */ + if (bus_id_len == 0 || bus_id_len < 8 || bus_id_len > 9) + { + + free (parent_devpath); + free (parent_subsystem); + free (bus_id); + + return -EINVAL; + } + + /* Store the CCW bus-ID for use as network device name */ + rc = snprintf (names->ccw_group, sizeof (names->ccw_group), "ccw%s", + bus_id); + if (rc >= 0 && rc < (int) sizeof (names->ccw_group)) + { + names->type = NET_CCWGROUP; + } + + free (parent_devpath); + free (parent_subsystem); + free (bus_id); + + return 0; +} - /* skip empty MAC addresses */ - if (a1 == 0 && a2 == 0 && a3 == 0 && a4 == 0 && a5 == 0 && a6 == 0) { - return -EINVAL; - } +static int +names_mac (char const *devpath, struct netnames *names) +{ - names->mac[0] = a1; - names->mac[1] = a2; - names->mac[2] = a3; - names->mac[3] = a4; - names->mac[4] = a5; - names->mac[5] = a6; - names->mac_valid = true; - return 0; + unsigned int i; + unsigned int a1, a2, a3, a4, a5, a6; + int rc = 0; + + char *addr_assign_type = NULL; + size_t addr_assign_type_len = 0; + + char *address = NULL; + size_t address_len = 0; + + rc = vdev_sysfs_read_attr (devpath, "addr_assign_type", + &addr_assign_type, &addr_assign_type_len); + if (rc != 0) + { + return rc; + } + + i = strtoul (addr_assign_type, NULL, 0); + if (i != 0) + { + + free (addr_assign_type); + return 0; + } + + rc = vdev_sysfs_read_attr (devpath, "address", &address, &address_len); + if (rc != 0) + { + + free (addr_assign_type); + return rc; + } + + rc = sscanf (address, "%x:%x:%x:%x:%x:%x", &a1, &a2, &a3, &a4, &a5, &a6); + if (rc != 6) + { + + free (addr_assign_type); + free (address); + return -EINVAL; + } + + free (addr_assign_type); + free (address); + + /* skip empty MAC addresses */ + if (a1 == 0 && a2 == 0 && a3 == 0 && a4 == 0 && a5 == 0 && a6 == 0) + { + return -EINVAL; + } + + names->mac[0] = a1; + names->mac[1] = a2; + names->mac[2] = a3; + names->mac[3] = a4; + names->mac[4] = a5; + names->mac[5] = a6; + names->mac_valid = true; + return 0; } /* IEEE Organizationally Unique Identifier vendor string */ -static int ieee_oui(char const *devpath, struct netnames *names) +static int +ieee_oui (char const *devpath, struct netnames *names) { - char str[32]; + char str[32]; - if (!names->mac_valid) { - return -ENOENT; - } + if (!names->mac_valid) + { + return -ENOENT; + } - /* skip commonly misused 00:00:00 (Xerox) prefix */ - if (memcmp(names->mac, "\0\0\0", 3) == 0) { - return -EINVAL; - } + /* skip commonly misused 00:00:00 (Xerox) prefix */ + if (memcmp (names->mac, "\0\0\0", 3) == 0) + { + return -EINVAL; + } - snprintf(str, sizeof(str), "OUI:%02X%02X%02X%02X%02X%02X", - names->mac[0], names->mac[1], names->mac[2], - names->mac[3], names->mac[4], names->mac[5]); + snprintf (str, sizeof (str), "OUI:%02X%02X%02X%02X%02X%02X", + names->mac[0], names->mac[1], names->mac[2], + names->mac[3], names->mac[4], names->mac[5]); - // TODO: find out how to replace this - // udev_builtin_hwdb_lookup(dev, NULL, str, NULL, test); + // TODO: find out how to replace this + // udev_builtin_hwdb_lookup(dev, NULL, str, NULL, test); - return 0; + return 0; } -void usage(char const *progname) +void +usage (char const *progname) { - fprintf(stderr, "[ERROR] %s: Usage: %s INTERFACE\n", progname, - progname); + fprintf (stderr, "[ERROR] %s: Usage: %s INTERFACE\n", progname, progname); } -int main(int argc, char **argv) +int +main (int argc, char **argv) { - unsigned int i; - const char *prefix = "en"; - struct netnames names; - int err = 0; - int rc = 0; - char *tmp = NULL; // for realpath success check - bool is_net_device = false; - - char devpath_class[4097]; - char devpath[4097]; - char devpath_uevent[4097]; + unsigned int i; + const char *prefix = "en"; + struct netnames names; + int err = 0; + int rc = 0; + char *tmp = NULL; // for realpath success check + bool is_net_device = false; + + char devpath_class[4097]; + char devpath[4097]; + char devpath_uevent[4097]; + + char *devtype = NULL; + size_t devtype_len = 0; + + // sysfs attr buf + char *attr = NULL; + char *attr_iflink = NULL; + char *attr_ifindex = NULL; + size_t attr_len = 0; + + char *uevent_buf = NULL; + size_t uevent_buf_len = 0; + + memset (&names, 0, sizeof (struct netnames)); + + if (argc != 2) + { + usage (argv[0]); + } + // get the device from the interface + sprintf (devpath_class, "/sys/class/net/%s", argv[1]); + + tmp = realpath (devpath_class, devpath); + if (tmp == NULL) + { + rc = -errno; + fprintf (stderr, + "[ERROR] %s: Failed to locate sysfs entry for %s\n", + argv[0], argv[1]); + exit (1); + } + // only care about ethernet and SLIP devices + rc = vdev_sysfs_read_attr (devpath, "type", &attr, &attr_len); + if (rc != 0) + { + + // not found + fprintf (stderr, + "[ERROR] %s: Failed to find interface type for %s (sysfs path '%s'), rc = %d\n", + argv[0], argv[1], devpath, rc); + exit (1); + } + + i = strtoul (attr, NULL, 0); + + free (attr); + + switch (i) + { + case ARPHRD_ETHER: + prefix = "en"; + break; + case ARPHRD_SLIP: + prefix = "sl"; + break; + default: + return 0; + } + + // sanity check (i.e. no stacked devices) + rc = vdev_sysfs_read_attr (devpath, "ifindex", &attr_ifindex, &attr_len); + if (rc != 0) + { + + log_error ("vdev_sysfs_read_attr('%s', 'ifindex') rc = %d\n", + devpath, rc); + exit (1); + } + + rc = vdev_sysfs_read_attr (devpath, "iflink", &attr_iflink, &attr_len); + if (rc != 0) + { + + log_error ("vdev_sysfs_read_attr('%s', 'iflink') rc = %d\n", + devpath, rc); + + free (attr_ifindex); + exit (1); + } + + if (strcmp (attr_ifindex, attr_iflink) != 0) + { + exit (0); + } + + free (attr_ifindex); + free (attr_iflink); + + // get device type + sprintf (devpath_uevent, "%s/uevent", devpath); + + rc = vdev_read_file (devpath_uevent, &uevent_buf, &uevent_buf_len); + if (rc != 0) + { + + log_error ("vdev_read_file('%s') rc = %d\n", devpath_uevent, rc); + exit (2); + } + + rc = vdev_sysfs_uevent_get_key (uevent_buf, uevent_buf_len, "DEVTYPE", + &devtype, &devtype_len); + if (rc == 0) + { + + if (strcmp ("wlan", devtype) == 0) + { + prefix = "wl"; + } + else if (strcmp ("wwan", devtype) == 0) + { + prefix = "ww"; + } + } + + free (uevent_buf); + free (devtype); + + err = names_mac (devpath, &names); + if (err >= 0 && names.mac_valid) + { + + char str[IFNAMSIZ]; + + snprintf (str, sizeof (str), "%sx%02x%02x%02x%02x%02x%02x", + prefix, names.mac[0], names.mac[1], names.mac[2], + names.mac[3], names.mac[4], names.mac[5]); + + vdev_property_add ("VDEV_NET_NAME_MAC", str); + + is_net_device = true; + ieee_oui (devpath, &names); + } - char *devtype = NULL; - size_t devtype_len = 0; + /* get path names for Linux on System z network devices */ + err = names_ccw (devpath, &names); + if (err >= 0 && names.type == NET_CCWGROUP) + { - // sysfs attr buf - char *attr = NULL; - char *attr_iflink = NULL; - char *attr_ifindex = NULL; - size_t attr_len = 0; + char str[IFNAMSIZ]; - char *uevent_buf = NULL; - size_t uevent_buf_len = 0; + if (snprintf (str, sizeof (str), "%s%s", prefix, names.ccw_group) + < (int) sizeof (str)) + { - memset(&names, 0, sizeof(struct netnames)); - - if (argc != 2) { - usage(argv[0]); - } - // get the device from the interface - sprintf(devpath_class, "/sys/class/net/%s", argv[1]); - - tmp = realpath(devpath_class, devpath); - if (tmp == NULL) { - rc = -errno; - fprintf(stderr, - "[ERROR] %s: Failed to locate sysfs entry for %s\n", - argv[0], argv[1]); - exit(1); - } - // only care about ethernet and SLIP devices - rc = vdev_sysfs_read_attr(devpath, "type", &attr, &attr_len); - if (rc != 0) { - - // not found - fprintf(stderr, - "[ERROR] %s: Failed to find interface type for %s (sysfs path '%s'), rc = %d\n", - argv[0], argv[1], devpath, rc); - exit(1); - } - - i = strtoul(attr, NULL, 0); - - free(attr); - - switch (i) { - case ARPHRD_ETHER: - prefix = "en"; - break; - case ARPHRD_SLIP: - prefix = "sl"; - break; - default: - return 0; + vdev_property_add ("VDEV_NET_NAME_PATH", str); + is_net_device = true; } - // sanity check (i.e. no stacked devices) - rc = vdev_sysfs_read_attr(devpath, "ifindex", &attr_ifindex, &attr_len); - if (rc != 0) { + goto out; + } - log_error("vdev_sysfs_read_attr('%s', 'ifindex') rc = %d\n", - devpath, rc); - exit(1); - } + /* get PCI based path names, we compose only PCI based paths */ + err = names_pci (devpath, &names); + if (err < 0) + { + goto out; + } - rc = vdev_sysfs_read_attr(devpath, "iflink", &attr_iflink, &attr_len); - if (rc != 0) { + /* plain PCI device */ + if (names.type == NET_PCI) + { - log_error("vdev_sysfs_read_attr('%s', 'iflink') rc = %d\n", - devpath, rc); + char str[IFNAMSIZ]; - free(attr_ifindex); - exit(1); - } + if (names.pci_onboard[0]) + { + if (snprintf + (str, sizeof (str), "%s%s", prefix, + names.pci_onboard) < (int) sizeof (str)) + { - if (strcmp(attr_ifindex, attr_iflink) != 0) { - exit(0); + vdev_property_add ("VDEV_NET_NAME_ONBOARD", str); + is_net_device = true; + } } - free(attr_ifindex); - free(attr_iflink); - - // get device type - sprintf(devpath_uevent, "%s/uevent", devpath); + if (names.pci_onboard_label) + { + if (snprintf + (str, sizeof (str), "%s%s", prefix, + names.pci_onboard_label) < (int) sizeof (str)) + { - rc = vdev_read_file(devpath_uevent, &uevent_buf, &uevent_buf_len); - if (rc != 0) { - - log_error("vdev_read_file('%s') rc = %d\n", devpath_uevent, rc); - exit(2); + vdev_property_add ("VDEV_NET_LABEL_ONBOARD", str); + is_net_device = true; + } } - rc = vdev_sysfs_uevent_get_key(uevent_buf, uevent_buf_len, "DEVTYPE", - &devtype, &devtype_len); - if (rc == 0) { + if (names.pci_path[0]) + { + if (snprintf + (str, sizeof (str), "%s%s", prefix, + names.pci_path) < (int) sizeof (str)) + { - if (strcmp("wlan", devtype) == 0) { - prefix = "wl"; - } else if (strcmp("wwan", devtype) == 0) { - prefix = "ww"; - } + vdev_property_add ("VDEV_NET_NAME_PATH", str); + is_net_device = true; + } } - free(uevent_buf); - free(devtype); - - err = names_mac(devpath, &names); - if (err >= 0 && names.mac_valid) { + if (names.pci_slot[0]) + { + if (snprintf + (str, sizeof (str), "%s%s", prefix, + names.pci_slot) < (int) sizeof (str)) + { - char str[IFNAMSIZ]; - - snprintf(str, sizeof(str), "%sx%02x%02x%02x%02x%02x%02x", - prefix, names.mac[0], names.mac[1], names.mac[2], - names.mac[3], names.mac[4], names.mac[5]); - - vdev_property_add("VDEV_NET_NAME_MAC", str); - - is_net_device = true; - ieee_oui(devpath, &names); + vdev_property_add ("VDEV_NET_NAME_SLOT", str); + is_net_device = true; + } } + goto out; + } - /* get path names for Linux on System z network devices */ - err = names_ccw(devpath, &names); - if (err >= 0 && names.type == NET_CCWGROUP) { - - char str[IFNAMSIZ]; + /* USB device */ + err = names_usb (devpath, &names); + if (err >= 0 && names.type == NET_USB) + { - if (snprintf(str, sizeof(str), "%s%s", prefix, names.ccw_group) - < (int)sizeof(str)) { + char str[IFNAMSIZ]; - vdev_property_add("VDEV_NET_NAME_PATH", str); - is_net_device = true; - } + if (names.pci_path[0]) + { + if (snprintf + (str, sizeof (str), "%s%s%s", prefix, names.pci_path, + names.usb_ports) < (int) sizeof (str)) + { - goto out; + vdev_property_add ("VDEV_NET_NAME_PATH", str); + is_net_device = true; + } } - /* get PCI based path names, we compose only PCI based paths */ - err = names_pci(devpath, &names); - if (err < 0) { - goto out; - } + if (names.pci_slot[0]) + { + if (snprintf + (str, sizeof (str), "%s%s%s", prefix, names.pci_slot, + names.usb_ports) < (int) sizeof (str)) + { - /* plain PCI device */ - if (names.type == NET_PCI) { - - char str[IFNAMSIZ]; - - if (names.pci_onboard[0]) { - if (snprintf - (str, sizeof(str), "%s%s", prefix, - names.pci_onboard) < (int)sizeof(str)) { - - vdev_property_add("VDEV_NET_NAME_ONBOARD", str); - is_net_device = true; - } - } - - if (names.pci_onboard_label) { - if (snprintf - (str, sizeof(str), "%s%s", prefix, - names.pci_onboard_label) < (int)sizeof(str)) { - - vdev_property_add("VDEV_NET_LABEL_ONBOARD", - str); - is_net_device = true; - } - } - - if (names.pci_path[0]) { - if (snprintf - (str, sizeof(str), "%s%s", prefix, - names.pci_path) < (int)sizeof(str)) { - - vdev_property_add("VDEV_NET_NAME_PATH", str); - is_net_device = true; - } - } - - if (names.pci_slot[0]) { - if (snprintf - (str, sizeof(str), "%s%s", prefix, - names.pci_slot) < (int)sizeof(str)) { - - vdev_property_add("VDEV_NET_NAME_SLOT", str); - is_net_device = true; - } - } - goto out; + vdev_property_add ("VDEV_NET_NAME_SLOT", str); + is_net_device = true; + } } - /* USB device */ - err = names_usb(devpath, &names); - if (err >= 0 && names.type == NET_USB) { - - char str[IFNAMSIZ]; + goto out; + } - if (names.pci_path[0]) { - if (snprintf - (str, sizeof(str), "%s%s%s", prefix, names.pci_path, - names.usb_ports) < (int)sizeof(str)) { + /* Broadcom bus */ + err = names_bcma (devpath, &names); + if (err >= 0 && names.type == NET_BCMA) + { - vdev_property_add("VDEV_NET_NAME_PATH", str); - is_net_device = true; - } - } + char str[IFNAMSIZ]; - if (names.pci_slot[0]) { - if (snprintf - (str, sizeof(str), "%s%s%s", prefix, names.pci_slot, - names.usb_ports) < (int)sizeof(str)) { + if (names.pci_path[0]) + { + if (snprintf + (str, sizeof (str), "%s%s%s", prefix, names.pci_path, + names.bcma_core) < (int) sizeof (str)) + { - vdev_property_add("VDEV_NET_NAME_SLOT", str); - is_net_device = true; - } - } - - goto out; + vdev_property_add ("VDEV_NET_NAME_PATH", str); + is_net_device = true; + } } - /* Broadcom bus */ - err = names_bcma(devpath, &names); - if (err >= 0 && names.type == NET_BCMA) { - - char str[IFNAMSIZ]; + if (names.pci_slot[0]) + { + if (snprintf + (str, sizeof (str), "%s%s%s", prefix, names.pci_slot, + names.bcma_core) < (int) sizeof (str)) + { - if (names.pci_path[0]) { - if (snprintf - (str, sizeof(str), "%s%s%s", prefix, names.pci_path, - names.bcma_core) < (int)sizeof(str)) { - - vdev_property_add("VDEV_NET_NAME_PATH", str); - is_net_device = true; - } - } - - if (names.pci_slot[0]) { - if (snprintf - (str, sizeof(str), "%s%s%s", prefix, names.pci_slot, - names.bcma_core) < (int)sizeof(str)) { - - vdev_property_add("VDEV_NET_NAME_SLOT", str); - is_net_device = true; - } - } - goto out; + vdev_property_add ("VDEV_NET_NAME_SLOT", str); + is_net_device = true; + } } - out: + goto out; + } +out: - if (is_net_device) { - vdev_property_add("VDEV_NET", "1"); - } + if (is_net_device) + { + vdev_property_add ("VDEV_NET", "1"); + } - vdev_property_print(); - vdev_property_free_all(); + vdev_property_print (); + vdev_property_free_all (); - return EXIT_SUCCESS; + return EXIT_SUCCESS; } diff --git a/vdevd/helpers/LINUX/stat_optical.c b/vdevd/helpers/LINUX/stat_optical.c index 277702f..0790e45 100644 --- a/vdevd/helpers/LINUX/stat_optical.c +++ b/vdevd/helpers/LINUX/stat_optical.c @@ -41,91 +41,99 @@ // get drive capabilities from an open device node, using the Linux-specific CDROM_GET_CAPABILITY ioctl. // return 0 on success // return negative errno on error -static int stat_optical_get_caps(int fd) +static int +stat_optical_get_caps (int fd) { - int caps = 0; - int rc = 0; + int caps = 0; + int rc = 0; - // get the cpability - caps = ioctl(fd, CDROM_GET_CAPABILITY, NULL); - if (caps < 0) { + // get the cpability + caps = ioctl (fd, CDROM_GET_CAPABILITY, NULL); + if (caps < 0) + { - rc = -errno; - fprintf(stderr, - "[ERROR] optical: CDROM_GET_CAPABILITY ioctl failed, rc = %d\n", - rc); - return rc; - } + rc = -errno; + fprintf (stderr, + "[ERROR] optical: CDROM_GET_CAPABILITY ioctl failed, rc = %d\n", + rc); + return rc; + } - return caps; + return caps; } // print out optical capabilities as environment variables -static int stat_optical_print_caps(int capabilities) +static int +stat_optical_print_caps (int capabilities) { - vdev_property_add("VDEV_OPTICAL_CD_R", - (capabilities & CDC_CD_R) == 0 ? "0" : "1"); - vdev_property_add("VDEV_OPTICAL_CD_RW", - (capabilities & CDC_CD_R) == 0 ? "0" : "1"); - vdev_property_add("VDEV_OPTICAL_DVD", - (capabilities & CDC_DVD) == 0 ? "0" : "1"); - vdev_property_add("VDEV_OPTICAL_DVD_R", - (capabilities & CDC_DVD_R) == 0 ? "0" : "1"); - vdev_property_add("VDEV_OPTICAL_DVD_RAM", - (capabilities & CDC_DVD_RAM) == 0 ? "0" : "1"); - - vdev_property_print(); - vdev_property_free_all(); - - return 0; + vdev_property_add ("VDEV_OPTICAL_CD_R", + (capabilities & CDC_CD_R) == 0 ? "0" : "1"); + vdev_property_add ("VDEV_OPTICAL_CD_RW", + (capabilities & CDC_CD_R) == 0 ? "0" : "1"); + vdev_property_add ("VDEV_OPTICAL_DVD", + (capabilities & CDC_DVD) == 0 ? "0" : "1"); + vdev_property_add ("VDEV_OPTICAL_DVD_R", + (capabilities & CDC_DVD_R) == 0 ? "0" : "1"); + vdev_property_add ("VDEV_OPTICAL_DVD_RAM", + (capabilities & CDC_DVD_RAM) == 0 ? "0" : "1"); + + vdev_property_print (); + vdev_property_free_all (); + + return 0; } // usage statement -static int usage(char const *prog_name) +static int +usage (char const *prog_name) { - fprintf(stderr, "[ERROR] %s: Usage: %s /path/to/optical/device\n", - prog_name, prog_name); - return 0; + fprintf (stderr, "[ERROR] %s: Usage: %s /path/to/optical/device\n", + prog_name, prog_name); + return 0; } // entry point -int main(int argc, char **argv) +int +main (int argc, char **argv) { - int rc = 0; - int fd = 0; - int capabilities = 0; + int rc = 0; + int fd = 0; + int capabilities = 0; - if (argc != 2) { + if (argc != 2) + { - usage(argv[0]); - exit(1); - } - // get the device node - fd = open(argv[1], O_RDONLY | O_NONBLOCK); - if (fd < 0) { + usage (argv[0]); + exit (1); + } + // get the device node + fd = open (argv[1], O_RDONLY | O_NONBLOCK); + if (fd < 0) + { - rc = -errno; - fprintf(stderr, "[ERROR] %s: open('%s') rc = %d\n", argv[0], - argv[1], rc); - exit(2); - } + rc = -errno; + fprintf (stderr, "[ERROR] %s: open('%s') rc = %d\n", argv[0], + argv[1], rc); + exit (2); + } - capabilities = stat_optical_get_caps(fd); + capabilities = stat_optical_get_caps (fd); - close(fd); + close (fd); - if (capabilities < 0) { + if (capabilities < 0) + { - fprintf(stderr, - "[ERROR] %s: stat_optical_get_caps('%s') rc = %d\n", - argv[0], argv[1], rc); - exit(4); - } + fprintf (stderr, + "[ERROR] %s: stat_optical_get_caps('%s') rc = %d\n", + argv[0], argv[1], rc); + exit (4); + } - stat_optical_print_caps(capabilities); - return 0; + stat_optical_print_caps (capabilities); + return 0; } diff --git a/vdevd/helpers/LINUX/stat_path.c b/vdevd/helpers/LINUX/stat_path.c index bc9e434..f6ae6b7 100644 --- a/vdevd/helpers/LINUX/stat_path.c +++ b/vdevd/helpers/LINUX/stat_path.c @@ -43,717 +43,777 @@ #include #include -static int path_prepend(char **path, const char *fmt, ...) +static int +path_prepend (char **path, const char *fmt, ...) { - va_list va; - char *pre; - int err = 0; - - va_start(va, fmt); - err = vasprintf(&pre, fmt, va); - va_end(va); - if (err < 0) { - goto out; - } - - if (*path != NULL) { - char *new; - - err = asprintf(&new, "%s-%s", pre, *path); - free(pre); - if (err < 0) { - goto out; - } - free(*path); - *path = new; - } else { - *path = pre; - } - out: - return err; + va_list va; + char *pre; + int err = 0; + + va_start (va, fmt); + err = vasprintf (&pre, fmt, va); + va_end (va); + if (err < 0) + { + goto out; + } + + if (*path != NULL) + { + char *new; + + err = asprintf (&new, "%s-%s", pre, *path); + free (pre); + if (err < 0) + { + goto out; + } + free (*path); + *path = new; + } + else + { + *path = pre; + } +out: + return err; } /* ** Linux only supports 32 bit luns. ** See drivers/scsi/scsi_scan.c::scsilun_to_int() for more details. */ -static int format_lun_number(char const *devpath, char **path) +static int +format_lun_number (char const *devpath, char **path) { - int lun = 0; - int rc = vdev_sysfs_get_sysnum(devpath, &lun); - if (rc != 0) { - return rc; - } - - /* address method 0, peripheral device addressing with bus id of zero */ - if (lun < 256) { - return path_prepend(path, "lun-%lu", lun); - } - - /* handle all other lun addressing methods by using a variant of the original lun format */ - return path_prepend(path, "lun-0x%04lx%04lx00000000", lun & 0xffff, - (lun >> 16) & 0xffff); + int lun = 0; + int rc = vdev_sysfs_get_sysnum (devpath, &lun); + if (rc != 0) + { + return rc; + } + + /* address method 0, peripheral device addressing with bus id of zero */ + if (lun < 256) + { + return path_prepend (path, "lun-%lu", lun); + } + + /* handle all other lun addressing methods by using a variant of the original lun format */ + return path_prepend (path, "lun-0x%04lx%04lx00000000", lun & 0xffff, + (lun >> 16) & 0xffff); } // walk up the sysfs path and skip all ancestor devices with the given subsystem. // stop once the parent device has a different subsystem from subsys. // return 0 on success, and set *next to the path to the deepest ancestor device that either does not have a subsystem, or has one that is different from subsys. -static int skip_subsystem(char const *devpath, char const *subsys, char **next) +static int +skip_subsystem (char const *devpath, char const *subsys, char **next) { - char *cur_dev = strdup(devpath); - char *parent = cur_dev; + char *cur_dev = strdup (devpath); + char *parent = cur_dev; - size_t parent_len = 0; - int rc = 0; + size_t parent_len = 0; + int rc = 0; - while (true) { + while (true) + { - char *subsystem = NULL; - size_t subsystem_len = 0; + char *subsystem = NULL; + size_t subsystem_len = 0; - int rc = 0; + int rc = 0; - rc = vdev_sysfs_read_subsystem(parent, &subsystem, - &subsystem_len); + rc = vdev_sysfs_read_subsystem (parent, &subsystem, &subsystem_len); - // break if not matched - if ((rc == -ENOENT || subsystem == NULL) - || strcmp(subsystem, subsys) != 0) { + // break if not matched + if ((rc == -ENOENT || subsystem == NULL) + || strcmp (subsystem, subsys) != 0) + { - if (subsystem != NULL) { - free(subsystem); - } - break; - } + if (subsystem != NULL) + { + free (subsystem); + } + break; + } - log_debug("skip %s", parent); + log_debug ("skip %s", parent); - free(subsystem); + free (subsystem); - if (cur_dev != parent) { - free(cur_dev); - } + if (cur_dev != parent) + { + free (cur_dev); + } - cur_dev = parent; + cur_dev = parent; - // matched; walk up - rc = vdev_sysfs_get_parent_device(cur_dev, &parent, - &parent_len); - if (rc != 0) { + // matched; walk up + rc = vdev_sysfs_get_parent_device (cur_dev, &parent, &parent_len); + if (rc != 0) + { - break; - } + break; } + } - *next = cur_dev; + *next = cur_dev; - if (cur_dev != parent) { - free(parent); - } + if (cur_dev != parent) + { + free (parent); + } - log_debug("Skip from '%s' to '%s'\n", devpath, *next); + log_debug ("Skip from '%s' to '%s'\n", devpath, *next); - return rc; + return rc; } // persistent name for scsi fibre channel (named by parent) // return 0 on success, and set *new_parent to the parent device and update *path // return negative on failure -static int handle_scsi_fibre_channel(char const *parent, char **path, - char **new_parent) +static int +handle_scsi_fibre_channel (char const *parent, char **path, char **new_parent) { - char *port = NULL; - size_t port_len = 0; - - char *lun = NULL; - - char *targetdev = NULL; - size_t targetdev_len = 0; - - char *targetdev_sysname = NULL; - size_t targetdev_sysname_len = 0; - - char *fcdev = NULL; - size_t fcdev_len = 0; - - int rc = 0; - - // look up SCSI parent target - rc = vdev_sysfs_get_parent_with_subsystem_devtype(parent, "scsi", - "scsi_target", - &targetdev, - &targetdev_len); - if (rc != 0) { - - return rc; - } - // get target device name - rc = vdev_sysfs_get_sysname(targetdev, &targetdev_sysname, - &targetdev_sysname_len); - if (rc != 0) { - - free(targetdev); - return rc; - } - // find the corresponding fibrechannel sysfs path - rc = vdev_sysfs_device_path_from_subsystem_sysname("/sys", - "fc_transport", - targetdev_sysname, - &fcdev, &fcdev_len); - if (rc != 0) { - - free(targetdev); - free(targetdev_sysname); - return rc; - } - - free(targetdev_sysname); - - // look up the port name - rc = vdev_sysfs_read_attr(fcdev, "port_name", &port, &port_len); - if (rc != 0) { - - free(targetdev); - return rc; - } - - free(fcdev); - - // parse port name - rc = format_lun_number(parent, &lun); - - path_prepend(path, "fc-%s-%s", port, lun); - - if (lun != NULL) { - free(lun); - } - // parent stays the same - *new_parent = strdup(parent); - if (*new_parent == NULL) { - - return -ENOMEM; - } - - return 0; + char *port = NULL; + size_t port_len = 0; + + char *lun = NULL; + + char *targetdev = NULL; + size_t targetdev_len = 0; + + char *targetdev_sysname = NULL; + size_t targetdev_sysname_len = 0; + + char *fcdev = NULL; + size_t fcdev_len = 0; + + int rc = 0; + + // look up SCSI parent target + rc = vdev_sysfs_get_parent_with_subsystem_devtype (parent, "scsi", + "scsi_target", + &targetdev, + &targetdev_len); + if (rc != 0) + { + + return rc; + } + // get target device name + rc = vdev_sysfs_get_sysname (targetdev, &targetdev_sysname, + &targetdev_sysname_len); + if (rc != 0) + { + + free (targetdev); + return rc; + } + // find the corresponding fibrechannel sysfs path + rc = vdev_sysfs_device_path_from_subsystem_sysname ("/sys", + "fc_transport", + targetdev_sysname, + &fcdev, &fcdev_len); + if (rc != 0) + { + + free (targetdev); + free (targetdev_sysname); + return rc; + } + + free (targetdev_sysname); + + // look up the port name + rc = vdev_sysfs_read_attr (fcdev, "port_name", &port, &port_len); + if (rc != 0) + { + + free (targetdev); + return rc; + } + + free (fcdev); + + // parse port name + rc = format_lun_number (parent, &lun); + + path_prepend (path, "fc-%s-%s", port, lun); + + if (lun != NULL) + { + free (lun); + } + // parent stays the same + *new_parent = strdup (parent); + if (*new_parent == NULL) + { + + return -ENOMEM; + } + + return 0; } // persistent name for SCSI SAS wide port // return 0 on success, and update *path with the new persistent name information and set *new_parent to the next parent to parse // return negative on error -static int handle_scsi_sas_wide_port(char const *parent, char **path, - char **new_parent) +static int +handle_scsi_sas_wide_port (char const *parent, char **path, char **new_parent) { - char *targetdev = NULL; - size_t targetdev_len = 0; + char *targetdev = NULL; + size_t targetdev_len = 0; - char *targetparent = NULL; - size_t targetparent_len = 0; + char *targetparent = NULL; + size_t targetparent_len = 0; - char *targetparent_sysname = NULL; - size_t targetparent_sysname_len = 0; + char *targetparent_sysname = NULL; + size_t targetparent_sysname_len = 0; - char *sasdev = NULL; - size_t sasdev_len = 0; + char *sasdev = NULL; + size_t sasdev_len = 0; - char *sas_address = NULL; - size_t sas_address_len = 0; + char *sas_address = NULL; + size_t sas_address_len = 0; - char *lun = NULL; + char *lun = NULL; - int rc = 0; + int rc = 0; - rc = vdev_sysfs_get_parent_with_subsystem_devtype(parent, "scsi", - "scsi_target", - &targetdev, - &targetdev_len); - if (rc != 0) { - return rc; - } + rc = vdev_sysfs_get_parent_with_subsystem_devtype (parent, "scsi", + "scsi_target", + &targetdev, + &targetdev_len); + if (rc != 0) + { + return rc; + } - rc = vdev_sysfs_get_parent_device(parent, &targetparent, - &targetparent_len); - if (rc != 0) { + rc = vdev_sysfs_get_parent_device (parent, &targetparent, + &targetparent_len); + if (rc != 0) + { - free(targetdev); - return rc; - } + free (targetdev); + return rc; + } - rc = vdev_sysfs_get_sysname(targetparent, &targetparent_sysname, - &targetparent_sysname_len); - if (rc != 0) { + rc = vdev_sysfs_get_sysname (targetparent, &targetparent_sysname, + &targetparent_sysname_len); + if (rc != 0) + { - free(targetdev); - free(targetparent); - return rc; - } - // find the sas device - rc = vdev_sysfs_device_path_from_subsystem_sysname("/sys", "sas_device", - targetparent_sysname, - &sasdev, - &sasdev_len); + free (targetdev); + free (targetparent); + return rc; + } + // find the sas device + rc = vdev_sysfs_device_path_from_subsystem_sysname ("/sys", "sas_device", + targetparent_sysname, + &sasdev, &sasdev_len); - free(targetparent); - free(targetparent_sysname); + free (targetparent); + free (targetparent_sysname); - if (rc != 0) { + if (rc != 0) + { - free(targetdev); - return rc; - } - // find the address - rc = vdev_sysfs_read_attr(sasdev, "sas_address", &sas_address, - &sas_address_len); - if (rc != 0) { + free (targetdev); + return rc; + } + // find the address + rc = vdev_sysfs_read_attr (sasdev, "sas_address", &sas_address, + &sas_address_len); + if (rc != 0) + { - free(targetdev); - return rc; - } + free (targetdev); + return rc; + } - format_lun_number(parent, &lun); - path_prepend(path, "sas-%s-%s", sas_address, lun); + format_lun_number (parent, &lun); + path_prepend (path, "sas-%s-%s", sas_address, lun); - if (lun != NULL) { - free(lun); - } + if (lun != NULL) + { + free (lun); + } - free(targetdev); + free (targetdev); - *new_parent = strdup(parent); - if (*new_parent == NULL) { + *new_parent = strdup (parent); + if (*new_parent == NULL) + { - return -ENOMEM; - } + return -ENOMEM; + } - return 0; + return 0; } // get the persistent path for a SCSI SAS // return 0 on success, and update *path with the persistent path information for this device, and set *parent to the next parent to process // return negative on error -static int handle_scsi_sas(char const *parent, char **path, char **new_parent) +static int +handle_scsi_sas (char const *parent, char **path, char **new_parent) { - char *targetdev = NULL; - size_t targetdev_len = 0; - - char *target_parent = NULL; - size_t target_parent_len = 0; - - char *target_parent_sysname = NULL; - size_t target_parent_sysname_len = 0; - - char *port = NULL; - size_t port_len = 0; - - char *port_sysname = NULL; - size_t port_sysname_len = 0; - - char *expander = NULL; - size_t expander_len = 0; - - char *expander_sysname = NULL; - size_t expander_sysname_len = 0; + char *targetdev = NULL; + size_t targetdev_len = 0; - char *target_sasdev = NULL; - size_t target_sasdev_len = 0; + char *target_parent = NULL; + size_t target_parent_len = 0; - char *expander_sasdev = NULL; - size_t expander_sasdev_len = 0; + char *target_parent_sysname = NULL; + size_t target_parent_sysname_len = 0; - char *port_sasdev = NULL; - size_t port_sasdev_len = 0; + char *port = NULL; + size_t port_len = 0; - char *sas_address = NULL; - size_t sas_address_len = 0; + char *port_sysname = NULL; + size_t port_sysname_len = 0; - char *phy_id = NULL; - size_t phy_id_len = 0; + char *expander = NULL; + size_t expander_len = 0; - char *phy_count = NULL; - size_t phy_count_len = 0; + char *expander_sysname = NULL; + size_t expander_sysname_len = 0; + + char *target_sasdev = NULL; + size_t target_sasdev_len = 0; + + char *expander_sasdev = NULL; + size_t expander_sasdev_len = 0; + + char *port_sasdev = NULL; + size_t port_sasdev_len = 0; + + char *sas_address = NULL; + size_t sas_address_len = 0; + + char *phy_id = NULL; + size_t phy_id_len = 0; + + char *phy_count = NULL; + size_t phy_count_len = 0; + + char *lun = NULL; + + int rc = 0; + + // find scsi target parent device + rc = vdev_sysfs_get_parent_with_subsystem_devtype (parent, "scsi", + "scsi_target", + &targetdev, + &targetdev_len); + if (rc != 0) + { + + return rc; + } + // find parent of the scsi target + rc = vdev_sysfs_get_parent_device (targetdev, &target_parent, + &target_parent_len); + + free (targetdev); + + if (rc != 0) + { - char *lun = NULL; + return rc; + } + // get parent sysname + rc = vdev_sysfs_get_sysname (target_parent, &target_parent_sysname, + &target_parent_sysname_len); + if (rc != 0) + { + + free (target_parent); + return rc; + } + // get sas device + rc = vdev_sysfs_device_path_from_subsystem_sysname ("/sys", "sas_device", + target_parent_sysname, + &target_sasdev, + &target_sasdev_len); + + free (target_parent); + + if (rc != 0) + { + + return rc; + } + // get the sas port (parent of the sas device) + rc = vdev_sysfs_get_parent_device (target_parent, &port, &port_len); + if (rc != 0) + { + + free (target_sasdev); + return rc; + } + // get sas port sysname + rc = vdev_sysfs_get_sysname (port, &port_sysname, &port_sysname_len); + if (rc != 0) + { + + free (target_sasdev); + free (port); + return rc; + } + // get the port device + rc = vdev_sysfs_device_path_from_subsystem_sysname ("/sys", "sas_port", + port_sysname, + &port_sasdev, + &port_sasdev_len); + + free (port_sysname); + + if (rc != 0) + { + + free (target_sasdev); + free (port); + return rc; + } + // get phy count for this sas device + rc = vdev_sysfs_read_attr (port_sasdev, "num_phys", &phy_count, + &phy_count_len); + if (rc != 0) + { + + free (target_sasdev); + free (port_sasdev); + free (port); + return rc; + } + // one disk? + if (strncmp (phy_count, "1", 2) != 0) + { + + // wide port + rc = handle_scsi_sas_wide_port (parent, path, new_parent); + + free (target_sasdev); + free (port_sasdev); + + return rc; + } + + free (phy_count); + + // multiple disks... + // which one is this? + rc = vdev_sysfs_read_attr (target_sasdev, "phy_identifier", &phy_id, + &phy_id_len); + + free (target_sasdev); + + if (rc != 0) + { + + free (port); + return rc; + } + // parent is either an HBA or expander device... + rc = vdev_sysfs_get_parent_device (port, &expander, &expander_len); + + free (port); + + if (rc != 0) + { + + free (phy_id); + return rc; + } + // get the expander sysname + rc = vdev_sysfs_get_sysname (expander, &expander_sysname, + &expander_sysname_len); + if (rc != 0) + { + + free (phy_id); + free (expander); + return rc; + } + + free (expander); + + // get the expander sas device + rc = vdev_sysfs_device_path_from_subsystem_sysname ("/sys", "sas_device", + expander_sysname, + &expander_sasdev, + &expander_sasdev_len); + + free (expander_sysname); + + if (rc == 0) + { + + // has expander device + // get its address + rc = vdev_sysfs_read_attr (expander_sasdev, "sas_address", + &sas_address, &sas_address_len); + free (expander_sasdev); - int rc = 0; + if (rc != 0) + { - // find scsi target parent device - rc = vdev_sysfs_get_parent_with_subsystem_devtype(parent, "scsi", - "scsi_target", - &targetdev, - &targetdev_len); - if (rc != 0) { - - return rc; + free (phy_id); + return rc; } - // find parent of the scsi target - rc = vdev_sysfs_get_parent_device(targetdev, &target_parent, - &target_parent_len); + } - free(targetdev); + format_lun_number (parent, &lun); - if (rc != 0) { + if (sas_address != NULL) + { - return rc; - } - // get parent sysname - rc = vdev_sysfs_get_sysname(target_parent, &target_parent_sysname, - &target_parent_sysname_len); - if (rc != 0) { + path_prepend (path, "sas-exp%s-phy%s-%s", sas_address, phy_id, lun); + free (sas_address); + } + else + { - free(target_parent); - return rc; - } - // get sas device - rc = vdev_sysfs_device_path_from_subsystem_sysname("/sys", "sas_device", - target_parent_sysname, - &target_sasdev, - &target_sasdev_len); + path_prepend (path, "sas-phy%s-%s", phy_id, lun); + } - free(target_parent); + if (lun != NULL) + { + free (lun); + } - if (rc != 0) { + free (phy_id); - return rc; - } - // get the sas port (parent of the sas device) - rc = vdev_sysfs_get_parent_device(target_parent, &port, &port_len); - if (rc != 0) { + *new_parent = strdup (parent); + if (*new_parent == NULL) + { - free(target_sasdev); - return rc; - } - // get sas port sysname - rc = vdev_sysfs_get_sysname(port, &port_sysname, &port_sysname_len); - if (rc != 0) { - - free(target_sasdev); - free(port); - return rc; - } - // get the port device - rc = vdev_sysfs_device_path_from_subsystem_sysname("/sys", "sas_port", - port_sysname, - &port_sasdev, - &port_sasdev_len); + return -ENOMEM; + } - free(port_sysname); - - if (rc != 0) { - - free(target_sasdev); - free(port); - return rc; - } - // get phy count for this sas device - rc = vdev_sysfs_read_attr(port_sasdev, "num_phys", &phy_count, - &phy_count_len); - if (rc != 0) { - - free(target_sasdev); - free(port_sasdev); - free(port); - return rc; - } - // one disk? - if (strncmp(phy_count, "1", 2) != 0) { - - // wide port - rc = handle_scsi_sas_wide_port(parent, path, new_parent); - - free(target_sasdev); - free(port_sasdev); - - return rc; - } - - free(phy_count); - - // multiple disks... - // which one is this? - rc = vdev_sysfs_read_attr(target_sasdev, "phy_identifier", &phy_id, - &phy_id_len); - - free(target_sasdev); - - if (rc != 0) { - - free(port); - return rc; - } - // parent is either an HBA or expander device... - rc = vdev_sysfs_get_parent_device(port, &expander, &expander_len); - - free(port); - - if (rc != 0) { - - free(phy_id); - return rc; - } - // get the expander sysname - rc = vdev_sysfs_get_sysname(expander, &expander_sysname, - &expander_sysname_len); - if (rc != 0) { - - free(phy_id); - free(expander); - return rc; - } - - free(expander); - - // get the expander sas device - rc = vdev_sysfs_device_path_from_subsystem_sysname("/sys", "sas_device", - expander_sysname, - &expander_sasdev, - &expander_sasdev_len); - - free(expander_sysname); - - if (rc == 0) { - - // has expander device - // get its address - rc = vdev_sysfs_read_attr(expander_sasdev, "sas_address", - &sas_address, &sas_address_len); - free(expander_sasdev); - - if (rc != 0) { - - free(phy_id); - return rc; - } - } - - format_lun_number(parent, &lun); - - if (sas_address != NULL) { - - path_prepend(path, "sas-exp%s-phy%s-%s", sas_address, phy_id, - lun); - free(sas_address); - } else { - - path_prepend(path, "sas-phy%s-%s", phy_id, lun); - } - - if (lun != NULL) { - free(lun); - } - - free(phy_id); - - *new_parent = strdup(parent); - if (*new_parent == NULL) { - - return -ENOMEM; - } - - return 0; + return 0; } // generate persistent path for iscsi devices // return 0 on success, and update *path with this device's persistent path information, and set *parent to the next parent device to explore // return negative on errror -static int handle_scsi_iscsi(char const *parent, char **path, char **new_parent) +static int +handle_scsi_iscsi (char const *parent, char **path, char **new_parent) { - char *transportdev = NULL; - - char *transportdev_sysname = NULL; - size_t transportdev_sysname_len = 0; - - char *sessiondev = NULL; - size_t sessiondev_len = 0; - - char *target = NULL; - size_t target_len = 0; + char *transportdev = NULL; - char *connname = NULL; + char *transportdev_sysname = NULL; + size_t transportdev_sysname_len = 0; - char *conndev = NULL; - size_t conndev_len = 0; + char *sessiondev = NULL; + size_t sessiondev_len = 0; - char *addr = NULL; - size_t addr_len = 0; + char *target = NULL; + size_t target_len = 0; - char *port = NULL; - size_t port_len = 0; + char *connname = NULL; - char *lun = NULL; + char *conndev = NULL; + size_t conndev_len = 0; - int rc = 0; + char *addr = NULL; + size_t addr_len = 0; - // find iscsi session - transportdev = (char *)parent; + char *port = NULL; + size_t port_len = 0; - while (1) { + char *lun = NULL; - char *transport_parent = NULL; - size_t transport_parent_len = 0; + int rc = 0; - rc = vdev_sysfs_get_parent_device(transportdev, - &transport_parent, - &transport_parent_len); - if (rc != 0) { + // find iscsi session + transportdev = (char *) parent; - return rc; - } + while (1) + { - transportdev = transport_parent; - if (strncmp(transportdev, "session", strlen("session")) == 0) { + char *transport_parent = NULL; + size_t transport_parent_len = 0; - break; - } + rc = vdev_sysfs_get_parent_device (transportdev, + &transport_parent, + &transport_parent_len); + if (rc != 0) + { - free(transportdev); + return rc; } - // find tranport dev sysname - rc = vdev_sysfs_get_sysname(transportdev, &transportdev_sysname, - &transportdev_sysname_len); - if (rc != 0) { + transportdev = transport_parent; + if (strncmp (transportdev, "session", strlen ("session")) == 0) + { - free(transportdev); - return rc; + break; } - free(transportdev); + free (transportdev); + } - // find iscsi session device - rc = vdev_sysfs_device_path_from_subsystem_sysname("/sys", - "iscsi_session", - transportdev_sysname, - &sessiondev, - &sessiondev_len); - if (rc != 0) { + // find tranport dev sysname + rc = vdev_sysfs_get_sysname (transportdev, &transportdev_sysname, + &transportdev_sysname_len); + if (rc != 0) + { - free(transportdev_sysname); - return rc; - } - // read the target - rc = vdev_sysfs_read_attr(sessiondev, "targetname", &target, - &target_len); + free (transportdev); + return rc; + } - free(sessiondev); + free (transportdev); - if (rc != 0) { + // find iscsi session device + rc = vdev_sysfs_device_path_from_subsystem_sysname ("/sys", + "iscsi_session", + transportdev_sysname, + &sessiondev, + &sessiondev_len); + if (rc != 0) + { - free(transportdev_sysname); - return rc; - } + free (transportdev_sysname); + return rc; + } + // read the target + rc = vdev_sysfs_read_attr (sessiondev, "targetname", &target, &target_len); - rc = asprintf(&connname, "connection%s:0", transportdev_sysname); + free (sessiondev); - free(transportdev_sysname); + if (rc != 0) + { - if (rc < 0) { + free (transportdev_sysname); + return rc; + } - free(target); - free(connname); - return rc; - } - // find connection device - rc = vdev_sysfs_device_path_from_subsystem_sysname("/sys", - "iscsi_connection", - connname, &conndev, - &conndev_len); + rc = asprintf (&connname, "connection%s:0", transportdev_sysname); - free(connname); + free (transportdev_sysname); - if (rc != 0) { + if (rc < 0) + { - free(target); - return rc; - } - // look up address - rc = vdev_sysfs_read_attr(conndev, "persistent_address", &addr, - &addr_len); - if (rc != 0) { + free (target); + free (connname); + return rc; + } + // find connection device + rc = vdev_sysfs_device_path_from_subsystem_sysname ("/sys", + "iscsi_connection", + connname, &conndev, + &conndev_len); - free(target); - return rc; - } - // look up port - rc = vdev_sysfs_read_attr(conndev, "persistent_port", &port, &port_len); - if (rc != 0) { + free (connname); - free(addr); - free(target); - return rc; - } - // make the name! - format_lun_number(parent, &lun); - path_prepend(path, "ip-%s:%s-iscsi-%s-%s", addr, port, target, lun); + if (rc != 0) + { - if (lun != NULL) { + free (target); + return rc; + } + // look up address + rc = vdev_sysfs_read_attr (conndev, "persistent_address", &addr, &addr_len); + if (rc != 0) + { - free(lun); - } + free (target); + return rc; + } + // look up port + rc = vdev_sysfs_read_attr (conndev, "persistent_port", &port, &port_len); + if (rc != 0) + { - free(port); - free(target); - free(addr); + free (addr); + free (target); + return rc; + } + // make the name! + format_lun_number (parent, &lun); + path_prepend (path, "ip-%s:%s-iscsi-%s-%s", addr, port, target, lun); - *new_parent = strdup(parent); - if (*new_parent == NULL) { + if (lun != NULL) + { - return -ENOMEM; - } + free (lun); + } - return 0; + free (port); + free (target); + free (addr); + + *new_parent = strdup (parent); + if (*new_parent == NULL) + { + + return -ENOMEM; + } + + return 0; } // get scsi host information // return 0 on success // return negative on failure -static int scsi_read_host_info(char const *parent, char **hostdev, int *host, - int *bus, int *target, int *lun) +static int +scsi_read_host_info (char const *parent, char **hostdev, int *host, + int *bus, int *target, int *lun) { - int rc = 0; + int rc = 0; - size_t hostdev_len = 0; + size_t hostdev_len = 0; - char *name = NULL; - size_t name_len = 0; + char *name = NULL; + size_t name_len = 0; - // find scsi host parent device - rc = vdev_sysfs_device_path_from_subsystem_sysname(parent, "scsi", - "scsi_host", hostdev, - &hostdev_len); - if (rc != 0) { + // find scsi host parent device + rc = vdev_sysfs_device_path_from_subsystem_sysname (parent, "scsi", + "scsi_host", hostdev, + &hostdev_len); + if (rc != 0) + { - return rc; - } - // get sysname of scsi host - rc = vdev_sysfs_get_sysname(parent, &name, &name_len); - if (rc != 0) { + return rc; + } + // get sysname of scsi host + rc = vdev_sysfs_get_sysname (parent, &name, &name_len); + if (rc != 0) + { - free(*hostdev); - *hostdev = NULL; + free (*hostdev); + *hostdev = NULL; - return rc; - } - // read host, bus, target, and lun - rc = sscanf(name, "%d:%d:%d:%d", host, bus, target, lun); - if (rc != 4) { + return rc; + } + // read host, bus, target, and lun + rc = sscanf (name, "%d:%d:%d:%d", host, bus, target, lun); + if (rc != 4) + { - // invalid name - free(*hostdev); - *hostdev = NULL; + // invalid name + free (*hostdev); + *hostdev = NULL; - free(name); - return -EINVAL; - } + free (name); + return -EINVAL; + } - free(name); + free (name); - return 0; + return 0; } /* @@ -773,998 +833,1109 @@ static int scsi_read_host_info(char const *parent, char **hostdev, int *host, * this. Manual driver unbind/bind, parallel hotplug/unplug will * get into the way of this "I hope it works" logic. */ -static int scsi_host_offset(char const *hostdev_sysname) +static int +scsi_host_offset (char const *hostdev_sysname) { - DIR *dir = NULL; - struct dirent *dent = NULL; - char *base = NULL; - char *pos = NULL; - int basenum = -1; - int rc = 0; - - base = strdup(hostdev_sysname); - if (base == NULL) { - return -ENOMEM; - } - // sanity check - pos = strrchr(base, '/'); - if (pos == NULL) { - - free(base); - return -EINVAL; - } - // make base its dirname - pos[0] = '\0'; - - dir = opendir(base); - - if (dir == NULL) { - - rc = -errno; - free(base); - return rc; - } - - for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) { - - char *rest = NULL; - int i = 0; - - // skip . and .. - if (dent->d_name[0] == '.') { - continue; - } - // only regular files - if (dent->d_type != DT_DIR && dent->d_type != DT_LNK) { - continue; - } - // only files that start with "host" - if (strncmp(dent->d_name, "host", strlen("host")) != 0) { - continue; - } - // get base number - i = strtoul(&dent->d_name[4], &rest, 10); - if (rest[0] != '\0') { - continue; - } - - /* - * find the smallest number; the host really needs to export its - * own instance number per parent device; relying on the global host - * enumeration and plainly rebasing the numbers sounds unreliable - */ - if (basenum == -1 || i < basenum) { - basenum = i; - } - } - - closedir(dir); - - if (basenum == -1) { - - // not found - return -ENOENT; - } - - return basenum; + DIR *dir = NULL; + struct dirent *dent = NULL; + char *base = NULL; + char *pos = NULL; + int basenum = -1; + int rc = 0; + + base = strdup (hostdev_sysname); + if (base == NULL) + { + return -ENOMEM; + } + // sanity check + pos = strrchr (base, '/'); + if (pos == NULL) + { + + free (base); + return -EINVAL; + } + // make base its dirname + pos[0] = '\0'; + + dir = opendir (base); + + if (dir == NULL) + { + + rc = -errno; + free (base); + return rc; + } + + for (dent = readdir (dir); dent != NULL; dent = readdir (dir)) + { + + char *rest = NULL; + int i = 0; + + // skip . and .. + if (dent->d_name[0] == '.') + { + continue; + } + // only regular files + if (dent->d_type != DT_DIR && dent->d_type != DT_LNK) + { + continue; + } + // only files that start with "host" + if (strncmp (dent->d_name, "host", strlen ("host")) != 0) + { + continue; + } + // get base number + i = strtoul (&dent->d_name[4], &rest, 10); + if (rest[0] != '\0') + { + continue; + } + + /* + * find the smallest number; the host really needs to export its + * own instance number per parent device; relying on the global host + * enumeration and plainly rebasing the numbers sounds unreliable + */ + if (basenum == -1 || i < basenum) + { + basenum = i; + } + } + + closedir (dir); + + if (basenum == -1) + { + + // not found + return -ENOENT; + } + + return basenum; } // persistent default scsi path // return 0 on success, and update *path with the scsi path information, and set *parent to the next parent device to explore // return negative on error. -static int handle_scsi_default(char const *parent, char **path, - char **new_parent) +static int +handle_scsi_default (char const *parent, char **path, char **new_parent) { - int rc = 0; - int attempts = 5; // arbitrary + int rc = 0; + int attempts = 5; // arbitrary - while (1) { + while (1) + { - int host = 0, bus = 0, target = 0, lun = 0; - int host2 = 0, bus2 = 0, target2 = 0, lun2 = 0; - int host_offset = 0; - char *hostdev = NULL; - char *hostdev2 = NULL; + int host = 0, bus = 0, target = 0, lun = 0; + int host2 = 0, bus2 = 0, target2 = 0, lun2 = 0; + int host_offset = 0; + char *hostdev = NULL; + char *hostdev2 = NULL; - char *hostdev_sysname = NULL; - size_t hostdev_sysname_len = 0; + char *hostdev_sysname = NULL; + size_t hostdev_sysname_len = 0; - // get host info - rc = scsi_read_host_info(parent, &hostdev, &host, &bus, &target, - &lun); + // get host info + rc = scsi_read_host_info (parent, &hostdev, &host, &bus, &target, &lun); - if (rc != 0) { + if (rc != 0) + { - return rc; - } - // get host sysname - rc = vdev_sysfs_get_sysname(hostdev, &hostdev_sysname, - &hostdev_sysname_len); - if (rc != 0) { + return rc; + } + // get host sysname + rc = vdev_sysfs_get_sysname (hostdev, &hostdev_sysname, + &hostdev_sysname_len); + if (rc != 0) + { - free(hostdev); - return rc; - } - // get host offset - host_offset = scsi_host_offset(hostdev_sysname); + free (hostdev); + return rc; + } + // get host offset + host_offset = scsi_host_offset (hostdev_sysname); - free(hostdev_sysname); + free (hostdev_sysname); - if (host_offset < 0) { + if (host_offset < 0) + { - return -ENODATA; - } - // get the host info, again, and verify that the kernel didn't race us - rc = scsi_read_host_info(parent, &hostdev2, &host2, &bus2, - &target2, &lun2); + return -ENODATA; + } + // get the host info, again, and verify that the kernel didn't race us + rc = scsi_read_host_info (parent, &hostdev2, &host2, &bus2, + &target2, &lun2); - if (rc != 0) { + if (rc != 0) + { - free(hostdev); - return rc; - } - // verify that nothing changed - if (strcmp(hostdev, hostdev2) != 0 || host != host2 - || bus != bus2 || target != target2 || lun != lun2) { + free (hostdev); + return rc; + } + // verify that nothing changed + if (strcmp (hostdev, hostdev2) != 0 || host != host2 + || bus != bus2 || target != target2 || lun != lun2) + { - free(hostdev); - free(hostdev2); + free (hostdev); + free (hostdev2); - // let the driver settle - sleep(1); + // let the driver settle + sleep (1); - attempts--; - if (attempts <= 0) { + attempts--; + if (attempts <= 0) + { - return -ETIMEDOUT; - } + return -ETIMEDOUT; + } - continue; - } - // success - free(hostdev2); + continue; + } + // success + free (hostdev2); - // success! - host -= host_offset; + // success! + host -= host_offset; - path_prepend(path, "scsi-%u:%u:%u:%u", host, bus, target, lun); + path_prepend (path, "scsi-%u:%u:%u:%u", host, bus, target, lun); - *new_parent = hostdev; - break; - } + *new_parent = hostdev; + break; + } - return 0; + return 0; } // create persistent path for a hyperv scsi device // return 0 on success, and append persistent path info to *path and set *new_parent to the next parent device to explore // return negative on error -static int handle_scsi_hyperv(char const *parent, char **path, - char **new_parent) +static int +handle_scsi_hyperv (char const *parent, char **path, char **new_parent) { - char *hostdev = NULL; - size_t hostdev_len = 0; + char *hostdev = NULL; + size_t hostdev_len = 0; - char *vmbusdev = NULL; - size_t vmbusdev_len = 0; + char *vmbusdev = NULL; + size_t vmbusdev_len = 0; - char *guid_str = NULL; - size_t guid_str_len = 0; + char *guid_str = NULL; + size_t guid_str_len = 0; - char *lun = NULL; + char *lun = NULL; - char guid[38]; - memset(guid, 0, 38); + char guid[38]; + memset (guid, 0, 38); - size_t i = 0; - size_t k = 0; + size_t i = 0; + size_t k = 0; - int rc = 0; + int rc = 0; - // get scsi host parent device - rc = vdev_sysfs_get_parent_with_subsystem_devtype(parent, "scsi", - "scsi_host", &hostdev, - &hostdev_len); - if (rc != 0) { + // get scsi host parent device + rc = vdev_sysfs_get_parent_with_subsystem_devtype (parent, "scsi", + "scsi_host", &hostdev, + &hostdev_len); + if (rc != 0) + { - return rc; - } - // get vmbus device--parent of scsi host - rc = vdev_sysfs_get_parent_device(hostdev, &vmbusdev, &vmbusdev_len); - if (rc != 0) { - - free(hostdev); - return rc; - } - // get the guid - rc = vdev_sysfs_read_attr(vmbusdev, "device_id", &guid_str, - &guid_str_len); + return rc; + } + // get vmbus device--parent of scsi host + rc = vdev_sysfs_get_parent_device (hostdev, &vmbusdev, &vmbusdev_len); + if (rc != 0) + { - free(hostdev); - free(vmbusdev); + free (hostdev); + return rc; + } + // get the guid + rc = vdev_sysfs_read_attr (vmbusdev, "device_id", &guid_str, &guid_str_len); - if (rc != 0) { + free (hostdev); + free (vmbusdev); - return rc; - } - // sanity check - if (strlen(guid_str) < 37 || guid_str[0] != '{' || guid_str[36] != '}') { + if (rc != 0) + { - return -EINVAL; - } - // remove '-' - for (i = 0, k = 0; i < 36; i++) { + return rc; + } + // sanity check + if (strlen (guid_str) < 37 || guid_str[0] != '{' || guid_str[36] != '}') + { - if (guid_str[i] == '-') { - continue; - } + return -EINVAL; + } + // remove '-' + for (i = 0, k = 0; i < 36; i++) + { - guid[k] = guid_str[i]; - k++; + if (guid_str[i] == '-') + { + continue; } - guid[k] = '\0'; - format_lun_number(parent, &lun); - path_prepend(path, "vmbus-%s-%s", guid, lun); + guid[k] = guid_str[i]; + k++; + } + guid[k] = '\0'; - if (lun != NULL) { - free(lun); - } + format_lun_number (parent, &lun); + path_prepend (path, "vmbus-%s-%s", guid, lun); - *new_parent = strdup(parent); - if (*new_parent == NULL) { + if (lun != NULL) + { + free (lun); + } - return -ENOMEM; - } + *new_parent = strdup (parent); + if (*new_parent == NULL) + { + + return -ENOMEM; + } - return 0; + return 0; } // generate persistent device name for a scsi device. dispatch to implementation-specific handlers. // return 0 on success, and prepend *path with the persistent name for this device. Set *new_parent to the next parent to explore, and set // *supported_parent to true if this device has a parent we support for persistent names. // return negative on failure. -static int handle_scsi(char const *parent, char **path, char **new_parent, - bool * supported_parent) +static int +handle_scsi (char const *parent, char **path, char **new_parent, + bool * supported_parent) { - char *devtype = NULL; - size_t devtype_len = 0; - - char *id = NULL; - size_t id_len = 0; + char *devtype = NULL; + size_t devtype_len = 0; - int rc = 0; + char *id = NULL; + size_t id_len = 0; - // verify that this is a scsi_device - rc = vdev_sysfs_uevent_read_key(parent, "DEVTYPE", &devtype, - &devtype_len); - if (rc != 0) { + int rc = 0; - return rc; - } + // verify that this is a scsi_device + rc = vdev_sysfs_uevent_read_key (parent, "DEVTYPE", &devtype, &devtype_len); + if (rc != 0) + { - if (devtype == NULL || strcmp(devtype, "scsi_device") != 0) { + return rc; + } - // not a scsi device - *new_parent = strdup(parent); - if (*new_parent == NULL) { + if (devtype == NULL || strcmp (devtype, "scsi_device") != 0) + { - return -ENOMEM; - } + // not a scsi device + *new_parent = strdup (parent); + if (*new_parent == NULL) + { - return 0; + return -ENOMEM; } - // firewrire? - rc = vdev_sysfs_read_attr(parent, "ieee1394_id", &id, &id_len); - free(devtype); - if (rc == 0) { + return 0; + } + // firewrire? + rc = vdev_sysfs_read_attr (parent, "ieee1394_id", &id, &id_len); + free (devtype); - // yup! - rc = skip_subsystem(parent, "scsi", new_parent); - if (rc != 0) { + if (rc == 0) + { - free(id); - return rc; - } + // yup! + rc = skip_subsystem (parent, "scsi", new_parent); + if (rc != 0) + { - path_prepend(path, "ieee1394-0x%s", id); + free (id); + return rc; + } - free(id); + path_prepend (path, "ieee1394-0x%s", id); - *supported_parent = true; - return 0; - } + free (id); - free(id); + *supported_parent = true; + return 0; + } - if (strstr(parent, "/rport-") != NULL) { + free (id); - // fibrechannel - rc = handle_scsi_fibre_channel(parent, path, new_parent); - if (rc != 0) { + if (strstr (parent, "/rport-") != NULL) + { - return rc; - } + // fibrechannel + rc = handle_scsi_fibre_channel (parent, path, new_parent); + if (rc != 0) + { - *supported_parent = true; - return 0; + return rc; } - if (strstr(parent, "/end_device-") != NULL) { + *supported_parent = true; + return 0; + } - // SCSI SAS - rc = handle_scsi_sas(parent, path, new_parent); - if (rc != 0) { + if (strstr (parent, "/end_device-") != NULL) + { - return rc; - } + // SCSI SAS + rc = handle_scsi_sas (parent, path, new_parent); + if (rc != 0) + { - *supported_parent = true; - return 0; + return rc; } - if (strstr(parent, "/session") != NULL) { + *supported_parent = true; + return 0; + } - // iSCSI - rc = handle_scsi_iscsi(parent, path, new_parent); - if (rc != 0) { + if (strstr (parent, "/session") != NULL) + { - return rc; - } + // iSCSI + rc = handle_scsi_iscsi (parent, path, new_parent); + if (rc != 0) + { - *supported_parent = true; - return 0; + return rc; } - /* - * We do not support the ATA transport class, it uses global counters - * to name the ata devices which numbers spread across multiple - * controllers. - * - * The real link numbers are not exported. Also, possible chains of ports - * behind port multipliers cannot be composed that way. - * - * Until all that is solved at the kernel level, there are no by-path/ - * links for ATA devices. - */ + *supported_parent = true; + return 0; + } - if (strstr(parent, "/ata") != NULL) { + /* + * We do not support the ATA transport class, it uses global counters + * to name the ata devices which numbers spread across multiple + * controllers. + * + * The real link numbers are not exported. Also, possible chains of ports + * behind port multipliers cannot be composed that way. + * + * Until all that is solved at the kernel level, there are no by-path/ + * links for ATA devices. + */ - // not supported - *new_parent = NULL; + if (strstr (parent, "/ata") != NULL) + { - return 0; - } + // not supported + *new_parent = NULL; - if (strstr(parent, "/vmbus_") != NULL) { + return 0; + } - rc = handle_scsi_hyperv(parent, path, new_parent); - if (rc != 0) { + if (strstr (parent, "/vmbus_") != NULL) + { - return rc; - } + rc = handle_scsi_hyperv (parent, path, new_parent); + if (rc != 0) + { - return 0; + return rc; } - // default - rc = handle_scsi_default(parent, path, new_parent); - return rc; + return 0; + } + // default + rc = handle_scsi_default (parent, path, new_parent); + + return rc; } // add persistent path name information for a cciss device // return 0 on success, update *path, and set *new_parent to the next parent device to explore // return negative on failure -static int handle_cciss(char const *parent, char **path, char **new_parent) +static int +handle_cciss (char const *parent, char **path, char **new_parent) { - unsigned int controller = 0, disk = 0; + unsigned int controller = 0, disk = 0; - char *parent_sysname = NULL; - size_t parent_sysname_len = 0; + char *parent_sysname = NULL; + size_t parent_sysname_len = 0; - int rc = 0; + int rc = 0; - rc = vdev_sysfs_get_sysname(parent, &parent_sysname, - &parent_sysname_len); - if (rc != 0) { - return rc; - } + rc = vdev_sysfs_get_sysname (parent, &parent_sysname, &parent_sysname_len); + if (rc != 0) + { + return rc; + } - rc = sscanf(parent_sysname, "c%ud%u%*s", &controller, &disk); + rc = sscanf (parent_sysname, "c%ud%u%*s", &controller, &disk); - free(parent_sysname); + free (parent_sysname); - if (rc != 2) { + if (rc != 2) + { - return -ENOENT; - } + return -ENOENT; + } - path_prepend(path, "cciss-disk%u", disk); + path_prepend (path, "cciss-disk%u", disk); - rc = skip_subsystem(parent, "cciss", new_parent); + rc = skip_subsystem (parent, "cciss", new_parent); - return rc; + return rc; } // add persistent path name information for a scsi tape device // always succeeds -static void handle_scsi_tape(char const *dev, char **path) +static void +handle_scsi_tape (char const *dev, char **path) { - // must be the last device in the syspath - if (*path != NULL) { - return; - } + // must be the last device in the syspath + if (*path != NULL) + { + return; + } - char *sysname = NULL; - size_t sysname_len = 0; + char *sysname = NULL; + size_t sysname_len = 0; - int rc = 0; + int rc = 0; - rc = vdev_sysfs_get_sysname(dev, &sysname, &sysname_len); - if (rc != 0) { + rc = vdev_sysfs_get_sysname (dev, &sysname, &sysname_len); + if (rc != 0) + { - return; - } + return; + } - if (strncmp(sysname, "nst", 3) == 0 - && strchr("lma", sysname[3]) != NULL) { + if (strncmp (sysname, "nst", 3) == 0 && strchr ("lma", sysname[3]) != NULL) + { - path_prepend(path, "nst%c", sysname[3]); - } else if (strncmp(sysname, "st", 2) == 0 - && strchr("lma", sysname[2]) != NULL) { + path_prepend (path, "nst%c", sysname[3]); + } + else if (strncmp (sysname, "st", 2) == 0 + && strchr ("lma", sysname[2]) != NULL) + { - path_prepend(path, "st%c", sysname[2]); - } + path_prepend (path, "st%c", sysname[2]); + } - free(sysname); - return; + free (sysname); + return; } // add persistent path name information for a usb device // return 0 on success, update *path with the information, and set *new_parent to the next device to explore // return negative on failure -static int handle_usb(char const *parent, char **path, char **new_parent) +static int +handle_usb (char const *parent, char **path, char **new_parent) { - int rc = 0; + int rc = 0; - char *devtype = NULL; - size_t devtype_len = 0; + char *devtype = NULL; + size_t devtype_len = 0; - char *sysname = NULL; - size_t sysname_len = 0; + char *sysname = NULL; + size_t sysname_len = 0; - char *port = NULL; + char *port = NULL; - rc = vdev_sysfs_uevent_read_key(parent, "DEVTYPE", &devtype, - &devtype_len); - if (rc != 0) { + rc = vdev_sysfs_uevent_read_key (parent, "DEVTYPE", &devtype, &devtype_len); + if (rc != 0) + { - *new_parent = strdup(parent); - if (*new_parent == NULL) { - - return -ENOMEM; - } + *new_parent = strdup (parent); + if (*new_parent == NULL) + { - return 0; + return -ENOMEM; } - if (strcmp(devtype, "usb_interface") != 0 - && strcmp(devtype, "usb_device") != 0) { + return 0; + } - free(devtype); + if (strcmp (devtype, "usb_interface") != 0 + && strcmp (devtype, "usb_device") != 0) + { - *new_parent = strdup(parent); - if (*new_parent == NULL) { + free (devtype); - return -ENOMEM; - } + *new_parent = strdup (parent); + if (*new_parent == NULL) + { - return 0; + return -ENOMEM; } - free(devtype); - - rc = vdev_sysfs_get_sysname(parent, &sysname, &sysname_len); - if (rc != 0) { + return 0; + } - return rc; - } + free (devtype); - port = strchr(sysname, '-'); + rc = vdev_sysfs_get_sysname (parent, &sysname, &sysname_len); + if (rc != 0) + { - if (port == NULL) { + return rc; + } - *new_parent = strdup(parent); - if (*new_parent == NULL) { + port = strchr (sysname, '-'); - return -ENOMEM; - } + if (port == NULL) + { - free(sysname); + *new_parent = strdup (parent); + if (*new_parent == NULL) + { - return 0; + return -ENOMEM; } - port++; + free (sysname); - rc = skip_subsystem(parent, "usb", new_parent); - if (rc != 0) { + return 0; + } - free(sysname); + port++; - return rc; - } + rc = skip_subsystem (parent, "usb", new_parent); + if (rc != 0) + { + + free (sysname); - path_prepend(path, "usb-0:%s", port); + return rc; + } - free(sysname); + path_prepend (path, "usb-0:%s", port); - return 0; + free (sysname); + + return 0; } -static int handle_bcma(char const *parent, char **path, char **new_parent) +static int +handle_bcma (char const *parent, char **path, char **new_parent) { - unsigned int core = 0; - int rc = 0; + unsigned int core = 0; + int rc = 0; - char *sysname = NULL; - size_t sysname_len = 0; + char *sysname = NULL; + size_t sysname_len = 0; - rc = vdev_sysfs_get_sysname(parent, &sysname, &sysname_len); - if (rc != 0) { + rc = vdev_sysfs_get_sysname (parent, &sysname, &sysname_len); + if (rc != 0) + { - return rc; - } + return rc; + } - rc = sscanf(sysname, "bcma%*u:%u", &core); + rc = sscanf (sysname, "bcma%*u:%u", &core); - free(sysname); + free (sysname); - if (rc != 1) { + if (rc != 1) + { - return -ENOENT; - } + return -ENOENT; + } - path_prepend(path, "bcma-%u", core); + path_prepend (path, "bcma-%u", core); - *new_parent = strdup(parent); - if (*new_parent == NULL) { - return -ENOMEM; - } + *new_parent = strdup (parent); + if (*new_parent == NULL) + { + return -ENOMEM; + } - return 0; + return 0; } -static int handle_ccw(char const *parent, char const *dev, char **path, - char **new_parent) +static int +handle_ccw (char const *parent, char const *dev, char **path, + char **new_parent) { - char *scsi_dev = NULL; - size_t scsi_dev_len = 0; + char *scsi_dev = NULL; + size_t scsi_dev_len = 0; - bool handled = false; + bool handled = false; - int rc = 0; + int rc = 0; - rc = vdev_sysfs_get_parent_with_subsystem_devtype(dev, "scsi", - "scsi_device", - &scsi_dev, - &scsi_dev_len); - if (rc == 0) { + rc = vdev_sysfs_get_parent_with_subsystem_devtype (dev, "scsi", + "scsi_device", + &scsi_dev, + &scsi_dev_len); + if (rc == 0) + { - char *wwpn = NULL; - size_t wwpn_len = 0; + char *wwpn = NULL; + size_t wwpn_len = 0; - char *lun = NULL; - size_t lun_len = 0; + char *lun = NULL; + size_t lun_len = 0; - char *hba_id = NULL; - size_t hba_id_len = 0; + char *hba_id = NULL; + size_t hba_id_len = 0; - vdev_sysfs_read_attr(scsi_dev, "hba_id", &hba_id, &hba_id_len); - vdev_sysfs_read_attr(scsi_dev, "wwpn", &wwpn, &wwpn_len); - vdev_sysfs_read_attr(scsi_dev, "fcp_lun", &lun, &lun_len); + vdev_sysfs_read_attr (scsi_dev, "hba_id", &hba_id, &hba_id_len); + vdev_sysfs_read_attr (scsi_dev, "wwpn", &wwpn, &wwpn_len); + vdev_sysfs_read_attr (scsi_dev, "fcp_lun", &lun, &lun_len); - if (hba_id != NULL && lun != NULL && wwpn != NULL) { + if (hba_id != NULL && lun != NULL && wwpn != NULL) + { - path_prepend(path, "ccw-%s-zfcp-%s:%s", hba_id, wwpn, - lun); - handled = true; - } + path_prepend (path, "ccw-%s-zfcp-%s:%s", hba_id, wwpn, lun); + handled = true; + } - if (hba_id != NULL) { - free(hba_id); - } - if (lun != NULL) { - free(lun); - } - if (wwpn != NULL) { - free(wwpn); - } + if (hba_id != NULL) + { + free (hba_id); } + if (lun != NULL) + { + free (lun); + } + if (wwpn != NULL) + { + free (wwpn); + } + } - if (!handled) { + if (!handled) + { - char *sysname = NULL; - size_t sysname_len = 0; + char *sysname = NULL; + size_t sysname_len = 0; - rc = vdev_sysfs_get_sysname(parent, &sysname, &sysname_len); + rc = vdev_sysfs_get_sysname (parent, &sysname, &sysname_len); - if (rc != 0) { + if (rc != 0) + { - free(scsi_dev); - return rc; - } + free (scsi_dev); + return rc; + } - path_prepend(path, "ccw-%s", sysname); + path_prepend (path, "ccw-%s", sysname); - free(sysname); - } + free (sysname); + } - free(scsi_dev); + free (scsi_dev); - rc = skip_subsystem(parent, "ccw", new_parent); - if (rc != 0) { - return rc; - } + rc = skip_subsystem (parent, "ccw", new_parent); + if (rc != 0) + { + return rc; + } - return 0; + return 0; } -void usage(char const *progname) +void +usage (char const *progname) { - fprintf(stderr, - "[ERROR] %s: Usage: %s /sysfs/path/to/device | /path/to/device/node\n", - progname, progname); + fprintf (stderr, + "[ERROR] %s: Usage: %s /sysfs/path/to/device | /path/to/device/node\n", + progname, progname); } // entry point -int main(int argc, char **argv) +int +main (int argc, char **argv) { - char *parent = NULL; - size_t parent_len = 0; + char *parent = NULL; + size_t parent_len = 0; - char *new_parent = NULL; + char *new_parent = NULL; - char *sysname = NULL; - size_t sysname_len = 0; + char *sysname = NULL; + size_t sysname_len = 0; - char *path = NULL; + char *path = NULL; - char *subsys = NULL; - size_t subsys_len = 0; + char *subsys = NULL; + size_t subsys_len = 0; - bool supported_transport = false; - bool supported_parent = false; + bool supported_transport = false; + bool supported_parent = false; - struct stat sb; + struct stat sb; - int rc = 0; + int rc = 0; - if (argc != 2) { - usage(argv[0]); - exit(1); - } + if (argc != 2) + { + usage (argv[0]); + exit (1); + } - char *dev = NULL; + char *dev = NULL; - // if this is a character device, then look up the device path - rc = stat(argv[1], &sb); - if (rc != 0) { + // if this is a character device, then look up the device path + rc = stat (argv[1], &sb); + if (rc != 0) + { - usage(argv[0]); - exit(1); - } - - if (S_ISCHR(sb.st_mode)) { + usage (argv[0]); + exit (1); + } - size_t dev_len = 0; - rc = vdev_sysfs_get_syspath_from_device("/sys", sb.st_mode, - major(sb.st_rdev), - minor(sb.st_rdev), &dev, - &dev_len); - if (rc != 0) { + if (S_ISCHR (sb.st_mode)) + { - fprintf(stderr, - "[ERROR] %s: vdev_sysfs_get_syspath_from_device rc = %d\n", - argv[0], rc); - usage(argv[0]); - exit(1); - } - } else { + size_t dev_len = 0; + rc = vdev_sysfs_get_syspath_from_device ("/sys", sb.st_mode, + major (sb.st_rdev), + minor (sb.st_rdev), &dev, + &dev_len); + if (rc != 0) + { - dev = strdup(argv[1]); + fprintf (stderr, + "[ERROR] %s: vdev_sysfs_get_syspath_from_device rc = %d\n", + argv[0], rc); + usage (argv[0]); + exit (1); } + } + else + { - // s390 ccw bus? - rc = vdev_sysfs_get_parent_with_subsystem_devtype(dev, "ccw", NULL, - &parent, &parent_len); - if (rc == 0) { + dev = strdup (argv[1]); + } - rc = handle_ccw(parent, dev, &path, &new_parent); - if (rc != 0) { - exit(2); - } + // s390 ccw bus? + rc = vdev_sysfs_get_parent_with_subsystem_devtype (dev, "ccw", NULL, + &parent, &parent_len); + if (rc == 0) + { - goto main_finish; + rc = handle_ccw (parent, dev, &path, &new_parent); + if (rc != 0) + { + exit (2); } - // walk up the device sysfs path and make the persistent path - parent = strdup(dev); - if (parent == NULL) { - exit(3); - } + goto main_finish; + } + // walk up the device sysfs path and make the persistent path + parent = strdup (dev); + if (parent == NULL) + { - rc = 0; + exit (3); + } - while (parent != NULL) { + rc = 0; - vdev_sysfs_read_subsystem(parent, &subsys, &subsys_len); + while (parent != NULL) + { - log_debug("'%s': subsystem '%s'", parent, subsys); + vdev_sysfs_read_subsystem (parent, &subsys, &subsys_len); - if (subsys != NULL) { + log_debug ("'%s': subsystem '%s'", parent, subsys); - if (strcmp(subsys, "scsi_tape") == 0) { + if (subsys != NULL) + { - handle_scsi_tape(parent, &path); - } else if (strcmp(subsys, "scsi") == 0) { + if (strcmp (subsys, "scsi_tape") == 0) + { - rc = handle_scsi(parent, &path, &new_parent, - &supported_parent); - supported_transport = true; - } else if (strcmp(subsys, "cciss") == 0) { + handle_scsi_tape (parent, &path); + } + else if (strcmp (subsys, "scsi") == 0) + { - rc = handle_cciss(parent, &path, &new_parent); - supported_transport = true; - } else if (strcmp(subsys, "usb") == 0) { + rc = handle_scsi (parent, &path, &new_parent, + &supported_parent); + supported_transport = true; + } + else if (strcmp (subsys, "cciss") == 0) + { - rc = handle_usb(parent, &path, &new_parent); - supported_transport = true; - } else if (strcmp(subsys, "bcma") == 0) { + rc = handle_cciss (parent, &path, &new_parent); + supported_transport = true; + } + else if (strcmp (subsys, "usb") == 0) + { - rc = handle_bcma(parent, &path, &new_parent); - supported_transport = true; - } else if (strcmp(subsys, "serio") == 0) { + rc = handle_usb (parent, &path, &new_parent); + supported_transport = true; + } + else if (strcmp (subsys, "bcma") == 0) + { + + rc = handle_bcma (parent, &path, &new_parent); + supported_transport = true; + } + else if (strcmp (subsys, "serio") == 0) + { + + int sysnum = 0; + rc = vdev_sysfs_get_sysnum (parent, &sysnum); + if (rc == 0) + { + + path_prepend (&path, "serio-%d", sysnum); + + rc = skip_subsystem (parent, "serio", &new_parent); + } + } + else if (strcmp (subsys, "pci") == 0) + { - int sysnum = 0; - rc = vdev_sysfs_get_sysnum(parent, &sysnum); - if (rc == 0) { + rc = vdev_sysfs_get_sysname (parent, &sysname, &sysname_len); + if (rc == 0) + { - path_prepend(&path, "serio-%d", sysnum); + path_prepend (&path, "pci-%s", sysname); + free (sysname); - rc = skip_subsystem(parent, "serio", - &new_parent); - } - } else if (strcmp(subsys, "pci") == 0) { + rc = skip_subsystem (parent, "pci", &new_parent); + } - rc = vdev_sysfs_get_sysname(parent, &sysname, - &sysname_len); - if (rc == 0) { + supported_parent = true; + } + else if (strcmp (subsys, "platform") == 0) + { - path_prepend(&path, "pci-%s", sysname); - free(sysname); + rc = vdev_sysfs_get_sysname (parent, &sysname, &sysname_len); + if (rc == 0) + { - rc = skip_subsystem(parent, "pci", - &new_parent); - } + path_prepend (&path, "platform-%s", sysname); + free (sysname); - supported_parent = true; - } else if (strcmp(subsys, "platform") == 0) { + rc = skip_subsystem (parent, "platform", &new_parent); + } - rc = vdev_sysfs_get_sysname(parent, &sysname, - &sysname_len); - if (rc == 0) { + supported_parent = true; + supported_transport = true; + } + else if (strcmp (subsys, "acpi") == 0) + { - path_prepend(&path, "platform-%s", - sysname); - free(sysname); + rc = vdev_sysfs_get_sysname (parent, &sysname, &sysname_len); + if (rc == 0) + { - rc = skip_subsystem(parent, "platform", - &new_parent); - } + path_prepend (&path, "acpi-%s", sysname); + free (sysname); - supported_parent = true; - supported_transport = true; - } else if (strcmp(subsys, "acpi") == 0) { + rc = skip_subsystem (parent, "acpi", &new_parent); + } - rc = vdev_sysfs_get_sysname(parent, &sysname, - &sysname_len); - if (rc == 0) { + supported_parent = true; + } + else if (strcmp (subsys, "xen") == 0) + { - path_prepend(&path, "acpi-%s", sysname); - free(sysname); + rc = vdev_sysfs_get_sysname (parent, &sysname, &sysname_len); + if (rc == 0) + { - rc = skip_subsystem(parent, "acpi", - &new_parent); - } + path_prepend (&path, "xen-%s", sysname); + free (sysname); - supported_parent = true; - } else if (strcmp(subsys, "xen") == 0) { + rc = skip_subsystem (parent, "xen", &new_parent); + } - rc = vdev_sysfs_get_sysname(parent, &sysname, - &sysname_len); - if (rc == 0) { + supported_parent = true; + } + else if (strcmp (subsys, "scm") == 0) + { - path_prepend(&path, "xen-%s", sysname); - free(sysname); + rc = vdev_sysfs_get_sysname (parent, &sysname, &sysname_len); + if (rc == 0) + { - rc = skip_subsystem(parent, "xen", - &new_parent); - } + path_prepend (&path, "scm-%s", sysname); + free (sysname); - supported_parent = true; - } else if (strcmp(subsys, "scm") == 0) { + rc = skip_subsystem (parent, "scm", &new_parent); + } - rc = vdev_sysfs_get_sysname(parent, &sysname, - &sysname_len); - if (rc == 0) { + supported_transport = true; + supported_parent = true; + } + } - path_prepend(&path, "scm-%s", sysname); - free(sysname); + if (rc != 0) + { - rc = skip_subsystem(parent, "scm", - &new_parent); - } + exit (4); + } - supported_transport = true; - supported_parent = true; - } - } + if (new_parent != NULL) + { - if (rc != 0) { + log_debug ("new parent is '%s' (original = '%s')", + new_parent, parent); - exit(4); - } + free (parent); + parent = new_parent; - if (new_parent != NULL) { + new_parent = NULL; + } - log_debug("new parent is '%s' (original = '%s')", - new_parent, parent); + char *next = NULL; + size_t next_len = 0; - free(parent); - parent = new_parent; + // next device + rc = vdev_sysfs_get_parent_device (parent, &next, &next_len); + if (rc != 0) + { - new_parent = NULL; - } + if (rc == -ENOENT) + { - char *next = NULL; - size_t next_len = 0; + break; + } + // terminal error + exit (15); + } - // next device - rc = vdev_sysfs_get_parent_device(parent, &next, &next_len); - if (rc != 0) { + log_debug ("Parent of '%s' is '%s'\n", parent, next); - if (rc == -ENOENT) { + free (parent); + parent = next; - break; - } - // terminal error - exit(15); - } + free (subsys); + subsys = NULL; + } - log_debug("Parent of '%s' is '%s'\n", parent, next); + /* + * Do not return devices with an unknown parent device type. They + * might produce conflicting IDs if the parent does not provide a + * unique and predictable name. + */ + if (!supported_parent) + { - free(parent); - parent = next; + log_debug ("%s", "Unsupported parent"); - free(subsys); - subsys = NULL; + if (path != NULL) + { + free (path); } + path = NULL; + } - /* - * Do not return devices with an unknown parent device type. They - * might produce conflicting IDs if the parent does not provide a - * unique and predictable name. - */ - if (!supported_parent) { + /* + * Do not return block devices without a well-known transport. Some + * devices do not expose their buses and do not provide a unique + * and predictable name that way. + */ + rc = vdev_sysfs_read_subsystem (dev, &subsys, &subsys_len); + if (rc != 0) + { - log_debug("%s", "Unsupported parent"); - - if (path != NULL) { - free(path); - } - path = NULL; + if (path != NULL) + { + free (path); } - /* - * Do not return block devices without a well-known transport. Some - * devices do not expose their buses and do not provide a unique - * and predictable name that way. - */ - rc = vdev_sysfs_read_subsystem(dev, &subsys, &subsys_len); - if (rc != 0) { - - if (path != NULL) { - free(path); - } - - exit(16); - } + exit (16); + } - if (strcmp(subsys, "block") == 0 && !supported_transport) { + if (strcmp (subsys, "block") == 0 && !supported_transport) + { - log_debug("'%s': Unsupported transport", dev); + log_debug ("'%s': Unsupported transport", dev); - if (path != NULL) { - free(path); - } - exit(17); + if (path != NULL) + { + free (path); } + exit (17); + } - main_finish: +main_finish: - free(dev); - free(subsys); + free (dev); + free (subsys); - if (path != NULL) { + if (path != NULL) + { - char tag[4097]; - memset(tag, 0, 4097); + char tag[4097]; + memset (tag, 0, 4097); - size_t i = 0; - char const *p = NULL; + size_t i = 0; + char const *p = NULL; - /* compose valid udev tag name */ - for (p = path, i = 0; *p != '\0'; p++) { + /* compose valid udev tag name */ + for (p = path, i = 0; *p != '\0'; p++) + { - // alphanumeric? - if ((*p >= '0' && *p <= '9') || - (*p >= 'A' && *p <= 'Z') || - (*p >= 'a' && *p <= 'z') || *p == '-') { + // alphanumeric? + if ((*p >= '0' && *p <= '9') || + (*p >= 'A' && *p <= 'Z') || + (*p >= 'a' && *p <= 'z') || *p == '-') + { - tag[i++] = *p; - continue; - } - // skip leading '_' - if (i == 0) { - continue; - } - // avoid second '_' - if (tag[i - 1] == '_') { - continue; - } + tag[i++] = *p; + continue; + } + // skip leading '_' + if (i == 0) + { + continue; + } + // avoid second '_' + if (tag[i - 1] == '_') + { + continue; + } - tag[i++] = '_'; - } + tag[i++] = '_'; + } - /* strip trailing '_' */ - while (i > 0 && tag[i - 1] == '_') { - i--; - } + /* strip trailing '_' */ + while (i > 0 && tag[i - 1] == '_') + { + i--; + } - tag[i] = '\0'; + tag[i] = '\0'; - // replaces ID_PATH and ID_PATH_TAG - vdev_property_add("VDEV_PERSISTENT_PATH", path); - vdev_property_add("VDEV_PERSISTENT_PATH_TAG", tag); + // replaces ID_PATH and ID_PATH_TAG + vdev_property_add ("VDEV_PERSISTENT_PATH", path); + vdev_property_add ("VDEV_PERSISTENT_PATH_TAG", tag); - free(path); + free (path); - vdev_property_print(); - vdev_property_free_all(); + vdev_property_print (); + vdev_property_free_all (); - exit(0); - } else { + exit (0); + } + else + { - // no path - vdev_property_add("VDEV_PERSISTENT_PATH", ""); - vdev_property_add("VDEV_PERSISTENT_PATH_TAG", ""); + // no path + vdev_property_add ("VDEV_PERSISTENT_PATH", ""); + vdev_property_add ("VDEV_PERSISTENT_PATH_TAG", ""); - vdev_property_print(); - vdev_property_free_all(); + vdev_property_print (); + vdev_property_free_all (); - exit(0); - } + exit (0); + } } diff --git a/vdevd/helpers/LINUX/stat_scsi.c b/vdevd/helpers/LINUX/stat_scsi.c index 062914b..086a643 100644 --- a/vdevd/helpers/LINUX/stat_scsi.c +++ b/vdevd/helpers/LINUX/stat_scsi.c @@ -40,11 +40,12 @@ #include -struct scsi_ioctl_command { - unsigned int inlen; /* excluding scsi command length */ - unsigned int outlen; - unsigned char data[1]; - /* on input, scsi command starts here then opt. data */ +struct scsi_ioctl_command +{ + unsigned int inlen; /* excluding scsi command length */ + unsigned int outlen; + unsigned char data[1]; + /* on input, scsi command starts here then opt. data */ }; /* @@ -102,10 +103,11 @@ struct scsi_ioctl_command { #define SCSI_ID_BINARY 1 #define SCSI_ID_ASCII 2 -struct scsi_id_search_values { - u_char id_type; - u_char naa_type; - u_char code_set; +struct scsi_id_search_values +{ + u_char id_type; + u_char naa_type; + u_char code_set; }; /* @@ -144,41 +146,43 @@ struct scsi_id_search_values { */ #define MAX_BUFFER_LEN 256 -struct scsi_id_device { - char vendor[9]; - char model[17]; - char revision[5]; - char type[33]; - char kernel[64]; - char serial[MAX_SERIAL_LEN]; - char serial_short[MAX_SERIAL_LEN]; - int use_sg; - - /* Always from page 0x80 e.g. 'B3G1P8500RWT' - may not be unique */ - char unit_serial_number[MAX_SERIAL_LEN]; - - /* NULs if not set - otherwise hex encoding using lower-case e.g. '50014ee0016eb572' */ - char wwn[17]; - - /* NULs if not set - otherwise hex encoding using lower-case e.g. '0xe00000d80000' */ - char wwn_vendor_extension[17]; - - /* NULs if not set - otherwise decimal number */ - char tgpt_group[8]; +struct scsi_id_device +{ + char vendor[9]; + char model[17]; + char revision[5]; + char type[33]; + char kernel[64]; + char serial[MAX_SERIAL_LEN]; + char serial_short[MAX_SERIAL_LEN]; + int use_sg; + + /* Always from page 0x80 e.g. 'B3G1P8500RWT' - may not be unique */ + char unit_serial_number[MAX_SERIAL_LEN]; + + /* NULs if not set - otherwise hex encoding using lower-case e.g. '50014ee0016eb572' */ + char wwn[17]; + + /* NULs if not set - otherwise hex encoding using lower-case e.g. '0xe00000d80000' */ + char wwn_vendor_extension[17]; + + /* NULs if not set - otherwise decimal number */ + char tgpt_group[8]; }; -int scsi_std_inquiry(struct scsi_id_device *dev_scsi, const char *devname); -int scsi_get_serial(struct scsi_id_device *dev_scsi, const char *devname, - int page_code, int len); +int scsi_std_inquiry (struct scsi_id_device *dev_scsi, const char *devname); +int scsi_get_serial (struct scsi_id_device *dev_scsi, const char *devname, + int page_code, int len); /* * Page code values. */ -enum page_code { - PAGE_83_PRE_SPC3 = -0x83, - PAGE_UNSPECIFIED = 0x00, - PAGE_80 = 0x80, - PAGE_83 = 0x83, +enum page_code +{ + PAGE_83_PRE_SPC3 = -0x83, + PAGE_UNSPECIFIED = 0x00, + PAGE_80 = 0x80, + PAGE_83 = 0x83, }; /* @@ -190,28 +194,28 @@ enum page_code { * is normally one or some small number of descriptors. */ static const struct scsi_id_search_values id_search_list[] = { - {SCSI_ID_TGTGROUP, SCSI_ID_NAA_DONT_CARE, SCSI_ID_BINARY}, - {SCSI_ID_NAA, SCSI_ID_NAA_IEEE_REG_EXTENDED, SCSI_ID_BINARY}, - {SCSI_ID_NAA, SCSI_ID_NAA_IEEE_REG_EXTENDED, SCSI_ID_ASCII}, - {SCSI_ID_NAA, SCSI_ID_NAA_IEEE_REG, SCSI_ID_BINARY}, - {SCSI_ID_NAA, SCSI_ID_NAA_IEEE_REG, SCSI_ID_ASCII}, - /* - * Devices already exist using NAA values that are now marked - * reserved. These should not conflict with other values, or it is - * a bug in the device. As long as we find the IEEE extended one - * first, we really don't care what other ones are used. Using - * don't care here means that a device that returns multiple - * non-IEEE descriptors in a random order will get different - * names. - */ - {SCSI_ID_NAA, SCSI_ID_NAA_DONT_CARE, SCSI_ID_BINARY}, - {SCSI_ID_NAA, SCSI_ID_NAA_DONT_CARE, SCSI_ID_ASCII}, - {SCSI_ID_EUI_64, SCSI_ID_NAA_DONT_CARE, SCSI_ID_BINARY}, - {SCSI_ID_EUI_64, SCSI_ID_NAA_DONT_CARE, SCSI_ID_ASCII}, - {SCSI_ID_T10_VENDOR, SCSI_ID_NAA_DONT_CARE, SCSI_ID_BINARY}, - {SCSI_ID_T10_VENDOR, SCSI_ID_NAA_DONT_CARE, SCSI_ID_ASCII}, - {SCSI_ID_VENDOR_SPECIFIC, SCSI_ID_NAA_DONT_CARE, SCSI_ID_BINARY}, - {SCSI_ID_VENDOR_SPECIFIC, SCSI_ID_NAA_DONT_CARE, SCSI_ID_ASCII}, + {SCSI_ID_TGTGROUP, SCSI_ID_NAA_DONT_CARE, SCSI_ID_BINARY}, + {SCSI_ID_NAA, SCSI_ID_NAA_IEEE_REG_EXTENDED, SCSI_ID_BINARY}, + {SCSI_ID_NAA, SCSI_ID_NAA_IEEE_REG_EXTENDED, SCSI_ID_ASCII}, + {SCSI_ID_NAA, SCSI_ID_NAA_IEEE_REG, SCSI_ID_BINARY}, + {SCSI_ID_NAA, SCSI_ID_NAA_IEEE_REG, SCSI_ID_ASCII}, + /* + * Devices already exist using NAA values that are now marked + * reserved. These should not conflict with other values, or it is + * a bug in the device. As long as we find the IEEE extended one + * first, we really don't care what other ones are used. Using + * don't care here means that a device that returns multiple + * non-IEEE descriptors in a random order will get different + * names. + */ + {SCSI_ID_NAA, SCSI_ID_NAA_DONT_CARE, SCSI_ID_BINARY}, + {SCSI_ID_NAA, SCSI_ID_NAA_DONT_CARE, SCSI_ID_ASCII}, + {SCSI_ID_EUI_64, SCSI_ID_NAA_DONT_CARE, SCSI_ID_BINARY}, + {SCSI_ID_EUI_64, SCSI_ID_NAA_DONT_CARE, SCSI_ID_ASCII}, + {SCSI_ID_T10_VENDOR, SCSI_ID_NAA_DONT_CARE, SCSI_ID_BINARY}, + {SCSI_ID_T10_VENDOR, SCSI_ID_NAA_DONT_CARE, SCSI_ID_ASCII}, + {SCSI_ID_VENDOR_SPECIFIC, SCSI_ID_NAA_DONT_CARE, SCSI_ID_BINARY}, + {SCSI_ID_VENDOR_SPECIFIC, SCSI_ID_NAA_DONT_CARE, SCSI_ID_ASCII}, }; static const char hex_str[] = "0123456789abcdef"; @@ -238,15 +242,15 @@ static const char hex_str[] = "0123456789abcdef"; #define SG_ERR_CAT_OTHER 99 /* Some other error/warning */ static const struct option options[] = { - {"device", required_argument, NULL, 'd'}, - {"config", required_argument, NULL, 'f'}, - {"page", required_argument, NULL, 'p'}, - {"replace-whitespace", no_argument, NULL, 'u'}, - {"sg-version", required_argument, NULL, 's'}, - {"verbose", no_argument, NULL, 'v'}, - {"version", no_argument, NULL, 'V'}, /* don't advertise -V */ - {"help", no_argument, NULL, 'h'}, - {} + {"device", required_argument, NULL, 'd'}, + {"config", required_argument, NULL, 'f'}, + {"page", required_argument, NULL, 'p'}, + {"replace-whitespace", no_argument, NULL, 'u'}, + {"sg-version", required_argument, NULL, 's'}, + {"verbose", no_argument, NULL, 'v'}, + {"version", no_argument, NULL, 'V'}, /* don't advertise -V */ + {"help", no_argument, NULL, 'h'}, + {} }; static bool all_good = true; @@ -262,642 +266,739 @@ static char model_enc_str[256]; static char revision_str[16]; static char type_str[16]; -static int do_scsi_page80_inquiry(struct scsi_id_device *dev_scsi, int fd, - char *serial, char *serial_short, - int max_len); +static int do_scsi_page80_inquiry (struct scsi_id_device *dev_scsi, int fd, + char *serial, char *serial_short, + int max_len); -static int sg_err_category_new(int scsi_status, int msg_status, int host_status, - int driver_status, - const unsigned char *sense_buffer, int sb_len) +static int +sg_err_category_new (int scsi_status, int msg_status, int host_status, + int driver_status, + const unsigned char *sense_buffer, int sb_len) { - scsi_status &= 0x7e; - - /* - * XXX change to return only two values - failed or OK. - */ - - if (!scsi_status && !host_status && !driver_status) { - return SG_ERR_CAT_CLEAN; - } - - if ((scsi_status == SCSI_CHECK_CONDITION) || - (scsi_status == SCSI_COMMAND_TERMINATED) || - ((driver_status & 0xf) == DRIVER_SENSE)) { - - if (sense_buffer && (sb_len > 2)) { - int sense_key; - unsigned char asc; - - if (sense_buffer[0] & 0x2) { - sense_key = sense_buffer[1] & 0xf; - asc = sense_buffer[2]; - } else { - sense_key = sense_buffer[2] & 0xf; - asc = (sb_len > 12) ? sense_buffer[12] : 0; - } - - if (sense_key == RECOVERED_ERROR) { - return SG_ERR_CAT_RECOVERED; - } else if (sense_key == UNIT_ATTENTION) { - if (0x28 == asc) { - return SG_ERR_CAT_MEDIA_CHANGED; - } - if (0x29 == asc) { - return SG_ERR_CAT_RESET; - } - } else if (sense_key == ILLEGAL_REQUEST) { - return SG_ERR_CAT_NOTSUPPORTED; - } - } - return SG_ERR_CAT_SENSE; - } - if (host_status) { - if ((host_status == DID_NO_CONNECT) || - (host_status == DID_BUS_BUSY) || - (host_status == DID_TIME_OUT)) { - return SG_ERR_CAT_TIMEOUT; + scsi_status &= 0x7e; + + /* + * XXX change to return only two values - failed or OK. + */ + + if (!scsi_status && !host_status && !driver_status) + { + return SG_ERR_CAT_CLEAN; + } + + if ((scsi_status == SCSI_CHECK_CONDITION) || + (scsi_status == SCSI_COMMAND_TERMINATED) || + ((driver_status & 0xf) == DRIVER_SENSE)) + { + + if (sense_buffer && (sb_len > 2)) + { + int sense_key; + unsigned char asc; + + if (sense_buffer[0] & 0x2) + { + sense_key = sense_buffer[1] & 0xf; + asc = sense_buffer[2]; + } + else + { + sense_key = sense_buffer[2] & 0xf; + asc = (sb_len > 12) ? sense_buffer[12] : 0; + } + + if (sense_key == RECOVERED_ERROR) + { + return SG_ERR_CAT_RECOVERED; + } + else if (sense_key == UNIT_ATTENTION) + { + if (0x28 == asc) + { + return SG_ERR_CAT_MEDIA_CHANGED; } - } - if (driver_status) { - if (driver_status == DRIVER_TIMEOUT) { - return SG_ERR_CAT_TIMEOUT; + if (0x29 == asc) + { + return SG_ERR_CAT_RESET; } - } - return SG_ERR_CAT_OTHER; + } + else if (sense_key == ILLEGAL_REQUEST) + { + return SG_ERR_CAT_NOTSUPPORTED; + } + } + return SG_ERR_CAT_SENSE; + } + if (host_status) + { + if ((host_status == DID_NO_CONNECT) || + (host_status == DID_BUS_BUSY) || (host_status == DID_TIME_OUT)) + { + return SG_ERR_CAT_TIMEOUT; + } + } + if (driver_status) + { + if (driver_status == DRIVER_TIMEOUT) + { + return SG_ERR_CAT_TIMEOUT; + } + } + return SG_ERR_CAT_OTHER; } -static int sg_err_category3(struct sg_io_hdr *hp) +static int +sg_err_category3 (struct sg_io_hdr *hp) { - return sg_err_category_new(hp->status, hp->msg_status, hp->host_status, - hp->driver_status, hp->sbp, hp->sb_len_wr); + return sg_err_category_new (hp->status, hp->msg_status, hp->host_status, + hp->driver_status, hp->sbp, hp->sb_len_wr); } -static int sg_err_category4(struct sg_io_v4 *hp) +static int +sg_err_category4 (struct sg_io_v4 *hp) { - return sg_err_category_new(hp->device_status, 0, hp->transport_status, - hp->driver_status, - (unsigned char *)(uintptr_t) hp->response, - hp->response_len); + return sg_err_category_new (hp->device_status, 0, hp->transport_status, + hp->driver_status, + (unsigned char *) (uintptr_t) hp->response, + hp->response_len); } -static int scsi_dump_sense(struct scsi_id_device *dev_scsi, - unsigned char *sense_buffer, int sb_len) +static int +scsi_dump_sense (struct scsi_id_device *dev_scsi, + unsigned char *sense_buffer, int sb_len) { - int s; - int code; - int sense_class; - int sense_key; - int asc, ascq; + int s; + int code; + int sense_class; + int sense_key; + int asc, ascq; #ifdef DUMP_SENSE - char out_buffer[256]; - int i, j; + char out_buffer[256]; + int i, j; #endif - /* - * Figure out and print the sense key, asc and ascq. - * - * If you want to suppress these for a particular drive model, add - * a black list entry in the scsi_id config file. - * - * XXX We probably need to: lookup the sense/asc/ascq in a retry - * table, and if found return 1 (after dumping the sense, asc, and - * ascq). So, if/when we get something like a power on/reset, - * we'll retry the command. - */ - - if (sb_len < 1) { - log_debug("%s: sense buffer empty", dev_scsi->kernel); - return -1; - } - - sense_class = (sense_buffer[0] >> 4) & 0x07; - code = sense_buffer[0] & 0xf; - - if (sense_class == 7) { - /* - * extended sense data. - */ - s = sense_buffer[7] + 8; - if (sb_len < s) { - log_debug - ("%s: sense buffer too small %d bytes, %d bytes too short", - dev_scsi->kernel, sb_len, s - sb_len); - return -1; - } - if ((code == 0x0) || (code == 0x1)) { - sense_key = sense_buffer[2] & 0xf; - if (s < 14) { - /* - * Possible? - */ - log_debug("%s: sense result too" - " small %d bytes", dev_scsi->kernel, - s); - return -1; - } - asc = sense_buffer[12]; - ascq = sense_buffer[13]; - } else if ((code == 0x2) || (code == 0x3)) { - sense_key = sense_buffer[1] & 0xf; - asc = sense_buffer[2]; - ascq = sense_buffer[3]; - } else { - log_debug("%s: invalid sense code 0x%x", - dev_scsi->kernel, code); - return -1; - } - log_debug("%s: sense key 0x%x ASC 0x%x ASCQ 0x%x", - dev_scsi->kernel, sense_key, asc, ascq); - } else { - if (sb_len < 4) { - log_debug - ("%s: sense buffer too small %d bytes, %d bytes too short", - dev_scsi->kernel, sb_len, 4 - sb_len); - return -1; - } - - if (sense_buffer[0] < 15) { - log_debug("%s: old sense key: 0x%x", dev_scsi->kernel, - sense_buffer[0] & 0x0f); - } - - else { - log_debug("%s: sense = %2x %2x", dev_scsi->kernel, - sense_buffer[0], sense_buffer[2]); - } - log_debug("%s: non-extended sense class %d code 0x%0x", - dev_scsi->kernel, sense_class, code); - - } + /* + * Figure out and print the sense key, asc and ascq. + * + * If you want to suppress these for a particular drive model, add + * a black list entry in the scsi_id config file. + * + * XXX We probably need to: lookup the sense/asc/ascq in a retry + * table, and if found return 1 (after dumping the sense, asc, and + * ascq). So, if/when we get something like a power on/reset, + * we'll retry the command. + */ + + if (sb_len < 1) + { + log_debug ("%s: sense buffer empty", dev_scsi->kernel); + return -1; + } + + sense_class = (sense_buffer[0] >> 4) & 0x07; + code = sense_buffer[0] & 0xf; + + if (sense_class == 7) + { + /* + * extended sense data. + */ + s = sense_buffer[7] + 8; + if (sb_len < s) + { + log_debug + ("%s: sense buffer too small %d bytes, %d bytes too short", + dev_scsi->kernel, sb_len, s - sb_len); + return -1; + } + if ((code == 0x0) || (code == 0x1)) + { + sense_key = sense_buffer[2] & 0xf; + if (s < 14) + { + /* + * Possible? + */ + log_debug ("%s: sense result too" + " small %d bytes", dev_scsi->kernel, s); + return -1; + } + asc = sense_buffer[12]; + ascq = sense_buffer[13]; + } + else if ((code == 0x2) || (code == 0x3)) + { + sense_key = sense_buffer[1] & 0xf; + asc = sense_buffer[2]; + ascq = sense_buffer[3]; + } + else + { + log_debug ("%s: invalid sense code 0x%x", dev_scsi->kernel, code); + return -1; + } + log_debug ("%s: sense key 0x%x ASC 0x%x ASCQ 0x%x", + dev_scsi->kernel, sense_key, asc, ascq); + } + else + { + if (sb_len < 4) + { + log_debug + ("%s: sense buffer too small %d bytes, %d bytes too short", + dev_scsi->kernel, sb_len, 4 - sb_len); + return -1; + } + + if (sense_buffer[0] < 15) + { + log_debug ("%s: old sense key: 0x%x", dev_scsi->kernel, + sense_buffer[0] & 0x0f); + } + + else + { + log_debug ("%s: sense = %2x %2x", dev_scsi->kernel, + sense_buffer[0], sense_buffer[2]); + } + log_debug ("%s: non-extended sense class %d code 0x%0x", + dev_scsi->kernel, sense_class, code); + + } #ifdef DUMP_SENSE - for (i = 0, j = 0; (i < s) && (j < 254); i++) { - out_buffer[j++] = hex_str[(sense_buffer[i] & 0xf0) >> 4]; - out_buffer[j++] = hex_str[sense_buffer[i] & 0x0f]; - out_buffer[j++] = ' '; - } - out_buffer[j] = '\0'; - log_debug("%s: sense dump:", dev_scsi->kernel); - log_debug("%s: %s", dev_scsi->kernel, out_buffer); + for (i = 0, j = 0; (i < s) && (j < 254); i++) + { + out_buffer[j++] = hex_str[(sense_buffer[i] & 0xf0) >> 4]; + out_buffer[j++] = hex_str[sense_buffer[i] & 0x0f]; + out_buffer[j++] = ' '; + } + out_buffer[j] = '\0'; + log_debug ("%s: sense dump:", dev_scsi->kernel); + log_debug ("%s: %s", dev_scsi->kernel, out_buffer); #endif - return -1; + return -1; } -static int scsi_dump(struct scsi_id_device *dev_scsi, struct sg_io_hdr *io) +static int +scsi_dump (struct scsi_id_device *dev_scsi, struct sg_io_hdr *io) { - if (!io->status && !io->host_status && !io->msg_status - && !io->driver_status) { - /* - * Impossible, should not be called. - */ - log_debug("%s: called with no error", __FUNCTION__); - return -1; - } - - log_debug("%s: sg_io failed status 0x%x 0x%x 0x%x 0x%x", - dev_scsi->kernel, io->driver_status, io->host_status, - io->msg_status, io->status); - if (io->status == SCSI_CHECK_CONDITION) { - return scsi_dump_sense(dev_scsi, io->sbp, io->sb_len_wr); - } else { - return -1; - } + if (!io->status && !io->host_status && !io->msg_status + && !io->driver_status) + { + /* + * Impossible, should not be called. + */ + log_debug ("%s: called with no error", __FUNCTION__); + return -1; + } + + log_debug ("%s: sg_io failed status 0x%x 0x%x 0x%x 0x%x", + dev_scsi->kernel, io->driver_status, io->host_status, + io->msg_status, io->status); + if (io->status == SCSI_CHECK_CONDITION) + { + return scsi_dump_sense (dev_scsi, io->sbp, io->sb_len_wr); + } + else + { + return -1; + } } -static int scsi_dump_v4(struct scsi_id_device *dev_scsi, struct sg_io_v4 *io) +static int +scsi_dump_v4 (struct scsi_id_device *dev_scsi, struct sg_io_v4 *io) { - if (!io->device_status && !io->transport_status && !io->driver_status) { - /* - * Impossible, should not be called. - */ - log_debug("%s: called with no error", __FUNCTION__); - return -1; - } - - log_debug("%s: sg_io failed status 0x%x 0x%x 0x%x", dev_scsi->kernel, - io->driver_status, io->transport_status, io->device_status); - - if (io->device_status == SCSI_CHECK_CONDITION) { - return scsi_dump_sense(dev_scsi, - (unsigned char *)(uintptr_t) io-> - response, io->response_len); - } else { - return -1; - } + if (!io->device_status && !io->transport_status && !io->driver_status) + { + /* + * Impossible, should not be called. + */ + log_debug ("%s: called with no error", __FUNCTION__); + return -1; + } + + log_debug ("%s: sg_io failed status 0x%x 0x%x 0x%x", dev_scsi->kernel, + io->driver_status, io->transport_status, io->device_status); + + if (io->device_status == SCSI_CHECK_CONDITION) + { + return scsi_dump_sense (dev_scsi, + (unsigned char *) (uintptr_t) io->response, + io->response_len); + } + else + { + return -1; + } } -static int scsi_inquiry(struct scsi_id_device *dev_scsi, int fd, - unsigned char evpd, unsigned char page, - unsigned char *buf, unsigned int buflen) +static int +scsi_inquiry (struct scsi_id_device *dev_scsi, int fd, + unsigned char evpd, unsigned char page, + unsigned char *buf, unsigned int buflen) { - unsigned char inq_cmd[INQUIRY_CMDLEN] = - { INQUIRY_CMD, evpd, page, 0, buflen, 0 }; - unsigned char sense[SENSE_BUFF_LEN]; - void *io_buf; - struct sg_io_v4 io_v4; - struct sg_io_hdr io_hdr; - int retry = 3; /* rather random */ - int retval; - int rc = 0; - - if (buflen > SCSI_INQ_BUFF_LEN) { - log_debug("buflen %d too long", buflen); - return -1; - } - - resend: - if (dev_scsi->use_sg == 4) { - memzero(&io_v4, sizeof(struct sg_io_v4)); - io_v4.guard = 'Q'; - io_v4.protocol = BSG_PROTOCOL_SCSI; - io_v4.subprotocol = BSG_SUB_PROTOCOL_SCSI_CMD; - io_v4.request_len = sizeof(inq_cmd); - io_v4.request = (uintptr_t) inq_cmd; - io_v4.max_response_len = sizeof(sense); - io_v4.response = (uintptr_t) sense; - io_v4.din_xfer_len = buflen; - io_v4.din_xferp = (uintptr_t) buf; - io_buf = (void *)&io_v4; - } else { - memzero(&io_hdr, sizeof(struct sg_io_hdr)); - io_hdr.interface_id = 'S'; - io_hdr.cmd_len = sizeof(inq_cmd); - io_hdr.mx_sb_len = sizeof(sense); - io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; - io_hdr.dxfer_len = buflen; - io_hdr.dxferp = buf; - io_hdr.cmdp = inq_cmd; - io_hdr.sbp = sense; - io_hdr.timeout = DEF_TIMEOUT; - io_buf = (void *)&io_hdr; - } - - retval = ioctl(fd, SG_IO, io_buf); - if (retval < 0) { - if ((errno == EINVAL || errno == ENOSYS) - && dev_scsi->use_sg == 4) { - dev_scsi->use_sg = 3; - goto resend; - } - - rc = -errno; - log_debug("%s: ioctl failed: errno = %d", dev_scsi->kernel, rc); - goto error; - } - - if (dev_scsi->use_sg == 4) { - retval = sg_err_category4(io_buf); - } else { - retval = sg_err_category3(io_buf); - } - - switch (retval) { - case SG_ERR_CAT_NOTSUPPORTED: - buf[1] = 0; - /* Fallthrough */ - case SG_ERR_CAT_CLEAN: - case SG_ERR_CAT_RECOVERED: - retval = 0; - break; - - default: - if (dev_scsi->use_sg == 4) { - retval = scsi_dump_v4(dev_scsi, io_buf); - } else { - retval = scsi_dump(dev_scsi, io_buf); - } - } - - if (!retval) { - retval = buflen; - } else if (retval > 0) { - if (--retry > 0) { - goto resend; - } - retval = -1; - } - - error: - if (retval < 0) { - log_debug("%s: Unable to get INQUIRY vpd %d page 0x%x.", - dev_scsi->kernel, evpd, page); - } - - return retval; + unsigned char inq_cmd[INQUIRY_CMDLEN] = + { INQUIRY_CMD, evpd, page, 0, buflen, 0 }; + unsigned char sense[SENSE_BUFF_LEN]; + void *io_buf; + struct sg_io_v4 io_v4; + struct sg_io_hdr io_hdr; + int retry = 3; /* rather random */ + int retval; + int rc = 0; + + if (buflen > SCSI_INQ_BUFF_LEN) + { + log_debug ("buflen %d too long", buflen); + return -1; + } + +resend: + if (dev_scsi->use_sg == 4) + { + memzero (&io_v4, sizeof (struct sg_io_v4)); + io_v4.guard = 'Q'; + io_v4.protocol = BSG_PROTOCOL_SCSI; + io_v4.subprotocol = BSG_SUB_PROTOCOL_SCSI_CMD; + io_v4.request_len = sizeof (inq_cmd); + io_v4.request = (uintptr_t) inq_cmd; + io_v4.max_response_len = sizeof (sense); + io_v4.response = (uintptr_t) sense; + io_v4.din_xfer_len = buflen; + io_v4.din_xferp = (uintptr_t) buf; + io_buf = (void *) &io_v4; + } + else + { + memzero (&io_hdr, sizeof (struct sg_io_hdr)); + io_hdr.interface_id = 'S'; + io_hdr.cmd_len = sizeof (inq_cmd); + io_hdr.mx_sb_len = sizeof (sense); + io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; + io_hdr.dxfer_len = buflen; + io_hdr.dxferp = buf; + io_hdr.cmdp = inq_cmd; + io_hdr.sbp = sense; + io_hdr.timeout = DEF_TIMEOUT; + io_buf = (void *) &io_hdr; + } + + retval = ioctl (fd, SG_IO, io_buf); + if (retval < 0) + { + if ((errno == EINVAL || errno == ENOSYS) && dev_scsi->use_sg == 4) + { + dev_scsi->use_sg = 3; + goto resend; + } + + rc = -errno; + log_debug ("%s: ioctl failed: errno = %d", dev_scsi->kernel, rc); + goto error; + } + + if (dev_scsi->use_sg == 4) + { + retval = sg_err_category4 (io_buf); + } + else + { + retval = sg_err_category3 (io_buf); + } + + switch (retval) + { + case SG_ERR_CAT_NOTSUPPORTED: + buf[1] = 0; + /* Fallthrough */ + case SG_ERR_CAT_CLEAN: + case SG_ERR_CAT_RECOVERED: + retval = 0; + break; + + default: + if (dev_scsi->use_sg == 4) + { + retval = scsi_dump_v4 (dev_scsi, io_buf); + } + else + { + retval = scsi_dump (dev_scsi, io_buf); + } + } + + if (!retval) + { + retval = buflen; + } + else if (retval > 0) + { + if (--retry > 0) + { + goto resend; + } + retval = -1; + } + +error: + if (retval < 0) + { + log_debug ("%s: Unable to get INQUIRY vpd %d page 0x%x.", + dev_scsi->kernel, evpd, page); + } + + return retval; } /* Get list of supported EVPD pages */ -static int do_scsi_page0_inquiry(struct scsi_id_device *dev_scsi, int fd, - unsigned char *buffer, unsigned int len) +static int +do_scsi_page0_inquiry (struct scsi_id_device *dev_scsi, int fd, + unsigned char *buffer, unsigned int len) { - int retval; - - memzero(buffer, len); - retval = scsi_inquiry(dev_scsi, fd, 1, 0x0, buffer, len); - if (retval < 0) { - return 1; - } - - if (buffer[1] != 0) { - log_debug("%s: page 0 not available.", dev_scsi->kernel); - return 1; - } - if (buffer[3] > len) { - log_debug("%s: page 0 buffer too long %d", dev_scsi->kernel, - buffer[3]); - return 1; - } - - /* - * Following check is based on code once included in the 2.5.x - * kernel. - * - * Some ill behaved devices return the standard inquiry here - * rather than the evpd data, snoop the data to verify. - */ - if (buffer[3] > MODEL_LENGTH) { - /* - * If the vendor id appears in the page assume the page is - * invalid. - */ - if (strneq - ((char *)&buffer[VENDOR_LENGTH], dev_scsi->vendor, - VENDOR_LENGTH)) { - log_debug("%s: invalid page0 data", dev_scsi->kernel); - return 1; - } - } - return 0; + int retval; + + memzero (buffer, len); + retval = scsi_inquiry (dev_scsi, fd, 1, 0x0, buffer, len); + if (retval < 0) + { + return 1; + } + + if (buffer[1] != 0) + { + log_debug ("%s: page 0 not available.", dev_scsi->kernel); + return 1; + } + if (buffer[3] > len) + { + log_debug ("%s: page 0 buffer too long %d", dev_scsi->kernel, + buffer[3]); + return 1; + } + + /* + * Following check is based on code once included in the 2.5.x + * kernel. + * + * Some ill behaved devices return the standard inquiry here + * rather than the evpd data, snoop the data to verify. + */ + if (buffer[3] > MODEL_LENGTH) + { + /* + * If the vendor id appears in the page assume the page is + * invalid. + */ + if (strneq + ((char *) &buffer[VENDOR_LENGTH], dev_scsi->vendor, VENDOR_LENGTH)) + { + log_debug ("%s: invalid page0 data", dev_scsi->kernel); + return 1; + } + } + return 0; } /* * The caller checks that serial is long enough to include the vendor + * model. */ -static int prepend_vendor_model(struct scsi_id_device *dev_scsi, char *serial) +static int +prepend_vendor_model (struct scsi_id_device *dev_scsi, char *serial) { - int ind; - - strncpy(serial, dev_scsi->vendor, VENDOR_LENGTH); - strncat(serial, dev_scsi->model, MODEL_LENGTH); - ind = strlen(serial); - - /* - * This is not a complete check, since we are using strncat/cpy - * above, ind will never be too large. - */ - if (ind != (VENDOR_LENGTH + MODEL_LENGTH)) { - log_debug("%s: expected length %d, got length %d", - dev_scsi->kernel, (VENDOR_LENGTH + MODEL_LENGTH), - ind); - return -1; - } - return ind; + int ind; + + strncpy (serial, dev_scsi->vendor, VENDOR_LENGTH); + strncat (serial, dev_scsi->model, MODEL_LENGTH); + ind = strlen (serial); + + /* + * This is not a complete check, since we are using strncat/cpy + * above, ind will never be too large. + */ + if (ind != (VENDOR_LENGTH + MODEL_LENGTH)) + { + log_debug ("%s: expected length %d, got length %d", + dev_scsi->kernel, (VENDOR_LENGTH + MODEL_LENGTH), ind); + return -1; + } + return ind; } /* * check_fill_0x83_id - check the page 0x83 id, if OK allocate and fill * serial number. */ -static int check_fill_0x83_id(struct scsi_id_device *dev_scsi, - unsigned char *page_83, - const struct scsi_id_search_values - *id_search, char *serial, char *serial_short, - int max_len, char *wwn, - char *wwn_vendor_extension, char *tgpt_group) +static int +check_fill_0x83_id (struct scsi_id_device *dev_scsi, + unsigned char *page_83, + const struct scsi_id_search_values + *id_search, char *serial, char *serial_short, + int max_len, char *wwn, + char *wwn_vendor_extension, char *tgpt_group) { - int i, j, s, len; - - /* - * ASSOCIATION must be with the device (value 0) - * or with the target port for SCSI_ID_TGTPORT - */ - if ((page_83[1] & 0x30) == 0x10) { - if (id_search->id_type != SCSI_ID_TGTGROUP) { - return 1; - } - } else if ((page_83[1] & 0x30) != 0) { - return 1; - } - - if ((page_83[1] & 0x0f) != id_search->id_type) { - return 1; - } - - /* - * Possibly check NAA sub-type. - */ - if ((id_search->naa_type != SCSI_ID_NAA_DONT_CARE) - && (id_search->naa_type != (page_83[4] & 0xf0) >> 4)) { - return 1; - } - - /* - * Check for matching code set - ASCII or BINARY. - */ - if ((page_83[0] & 0x0f) != id_search->code_set) { - return 1; - } - - /* - * page_83[3]: identifier length - */ - len = page_83[3]; - if ((page_83[0] & 0x0f) != SCSI_ID_ASCII) { - /* - * If not ASCII, use two bytes for each binary value. - */ - len *= 2; - } - - /* - * Add one byte for the NUL termination, and one for the id_type. - */ - len += 2; - if (id_search->id_type == SCSI_ID_VENDOR_SPECIFIC) { - len += VENDOR_LENGTH + MODEL_LENGTH; - } - - if (max_len < len) { - log_debug("%s: length %d too short - need %d", dev_scsi->kernel, - max_len, len); - return 1; - } - - if (id_search->id_type == SCSI_ID_TGTGROUP && tgpt_group != NULL) { - unsigned int group; - - group = ((unsigned int)page_83[6] << 8) | page_83[7]; - sprintf(tgpt_group, "%x", group); - return 1; - } - - serial[0] = hex_str[id_search->id_type]; - - /* - * For SCSI_ID_VENDOR_SPECIFIC prepend the vendor and model before - * the id since it is not unique across all vendors and models, - * this differs from SCSI_ID_T10_VENDOR, where the vendor is - * included in the identifier. - */ - if (id_search->id_type == SCSI_ID_VENDOR_SPECIFIC) { - if (prepend_vendor_model(dev_scsi, &serial[1]) < 0) { - return 1; - } - } - - i = 4; /* offset to the start of the identifier */ - s = j = strlen(serial); - if ((page_83[0] & 0x0f) == SCSI_ID_ASCII) { - /* - * ASCII descriptor. - */ - while (i < (4 + page_83[3])) { - serial[j++] = page_83[i++]; - } - } else { - /* - * Binary descriptor, convert to ASCII, using two bytes of - * ASCII for each byte in the page_83. - */ - while (i < (4 + page_83[3])) { - serial[j++] = hex_str[(page_83[i] & 0xf0) >> 4]; - serial[j++] = hex_str[page_83[i] & 0x0f]; - i++; - } - } - - strcpy(serial_short, &serial[s]); - - if (id_search->id_type == SCSI_ID_NAA && wwn != NULL) { - strncpy(wwn, &serial[s], 16); - if (wwn_vendor_extension != NULL) { - strncpy(wwn_vendor_extension, &serial[s + 16], 16); - } - } - - return 0; + int i, j, s, len; + + /* + * ASSOCIATION must be with the device (value 0) + * or with the target port for SCSI_ID_TGTPORT + */ + if ((page_83[1] & 0x30) == 0x10) + { + if (id_search->id_type != SCSI_ID_TGTGROUP) + { + return 1; + } + } + else if ((page_83[1] & 0x30) != 0) + { + return 1; + } + + if ((page_83[1] & 0x0f) != id_search->id_type) + { + return 1; + } + + /* + * Possibly check NAA sub-type. + */ + if ((id_search->naa_type != SCSI_ID_NAA_DONT_CARE) + && (id_search->naa_type != (page_83[4] & 0xf0) >> 4)) + { + return 1; + } + + /* + * Check for matching code set - ASCII or BINARY. + */ + if ((page_83[0] & 0x0f) != id_search->code_set) + { + return 1; + } + + /* + * page_83[3]: identifier length + */ + len = page_83[3]; + if ((page_83[0] & 0x0f) != SCSI_ID_ASCII) + { + /* + * If not ASCII, use two bytes for each binary value. + */ + len *= 2; + } + + /* + * Add one byte for the NUL termination, and one for the id_type. + */ + len += 2; + if (id_search->id_type == SCSI_ID_VENDOR_SPECIFIC) + { + len += VENDOR_LENGTH + MODEL_LENGTH; + } + + if (max_len < len) + { + log_debug ("%s: length %d too short - need %d", dev_scsi->kernel, + max_len, len); + return 1; + } + + if (id_search->id_type == SCSI_ID_TGTGROUP && tgpt_group != NULL) + { + unsigned int group; + + group = ((unsigned int) page_83[6] << 8) | page_83[7]; + sprintf (tgpt_group, "%x", group); + return 1; + } + + serial[0] = hex_str[id_search->id_type]; + + /* + * For SCSI_ID_VENDOR_SPECIFIC prepend the vendor and model before + * the id since it is not unique across all vendors and models, + * this differs from SCSI_ID_T10_VENDOR, where the vendor is + * included in the identifier. + */ + if (id_search->id_type == SCSI_ID_VENDOR_SPECIFIC) + { + if (prepend_vendor_model (dev_scsi, &serial[1]) < 0) + { + return 1; + } + } + + i = 4; /* offset to the start of the identifier */ + s = j = strlen (serial); + if ((page_83[0] & 0x0f) == SCSI_ID_ASCII) + { + /* + * ASCII descriptor. + */ + while (i < (4 + page_83[3])) + { + serial[j++] = page_83[i++]; + } + } + else + { + /* + * Binary descriptor, convert to ASCII, using two bytes of + * ASCII for each byte in the page_83. + */ + while (i < (4 + page_83[3])) + { + serial[j++] = hex_str[(page_83[i] & 0xf0) >> 4]; + serial[j++] = hex_str[page_83[i] & 0x0f]; + i++; + } + } + + strcpy (serial_short, &serial[s]); + + if (id_search->id_type == SCSI_ID_NAA && wwn != NULL) + { + strncpy (wwn, &serial[s], 16); + if (wwn_vendor_extension != NULL) + { + strncpy (wwn_vendor_extension, &serial[s + 16], 16); + } + } + + return 0; } /* Extract the raw binary from VPD 0x83 pre-SPC devices */ -static int check_fill_0x83_prespc3(struct scsi_id_device *dev_scsi, - unsigned char *page_83, - const struct scsi_id_search_values - *id_search, char *serial, char *serial_short, - int max_len) +static int +check_fill_0x83_prespc3 (struct scsi_id_device *dev_scsi, + unsigned char *page_83, + const struct scsi_id_search_values + *id_search, char *serial, char *serial_short, + int max_len) { - int i, j; - - serial[0] = hex_str[id_search->id_type]; - /* serial has been memset to zero before */ - j = strlen(serial); /* j = 1; */ - - for (i = 0; (i < page_83[3]) && (j < max_len - 3); ++i) { - serial[j++] = hex_str[(page_83[4 + i] & 0xf0) >> 4]; - serial[j++] = hex_str[page_83[4 + i] & 0x0f]; - } - serial[max_len - 1] = 0; - strncpy(serial_short, serial, max_len - 1); - return 0; + int i, j; + + serial[0] = hex_str[id_search->id_type]; + /* serial has been memset to zero before */ + j = strlen (serial); /* j = 1; */ + + for (i = 0; (i < page_83[3]) && (j < max_len - 3); ++i) + { + serial[j++] = hex_str[(page_83[4 + i] & 0xf0) >> 4]; + serial[j++] = hex_str[page_83[4 + i] & 0x0f]; + } + serial[max_len - 1] = 0; + strncpy (serial_short, serial, max_len - 1); + return 0; } /* Get device identification VPD page */ -static int do_scsi_page83_inquiry(struct scsi_id_device *dev_scsi, int fd, - char *serial, char *serial_short, int len, - char *unit_serial_number, char *wwn, - char *wwn_vendor_extension, char *tgpt_group) +static int +do_scsi_page83_inquiry (struct scsi_id_device *dev_scsi, int fd, + char *serial, char *serial_short, int len, + char *unit_serial_number, char *wwn, + char *wwn_vendor_extension, char *tgpt_group) { - int retval; - unsigned int id_ind, j; - unsigned char page_83[SCSI_INQ_BUFF_LEN]; - - /* also pick up the page 80 serial number */ - do_scsi_page80_inquiry(dev_scsi, fd, NULL, unit_serial_number, - MAX_SERIAL_LEN); - - memzero(page_83, SCSI_INQ_BUFF_LEN); - retval = - scsi_inquiry(dev_scsi, fd, 1, PAGE_83, page_83, SCSI_INQ_BUFF_LEN); - if (retval < 0) { - return 1; - } - - if (page_83[1] != PAGE_83) { - log_debug("%s: Invalid page 0x83", dev_scsi->kernel); - return 1; - } - - /* - * XXX Some devices (IBM 3542) return all spaces for an identifier if - * the LUN is not actually configured. This leads to identifiers of - * the form: "1 ". - */ - - /* - * Model 4, 5, and (some) model 6 EMC Symmetrix devices return - * a page 83 reply according to SCSI-2 format instead of SPC-2/3. - * - * The SCSI-2 page 83 format returns an IEEE WWN in binary - * encoded hexi-decimal in the 16 bytes following the initial - * 4-byte page 83 reply header. - * - * Both the SPC-2 and SPC-3 formats return an IEEE WWN as part - * of an Identification descriptor. The 3rd byte of the first - * Identification descriptor is a reserved (BSZ) byte field. - * - * Reference the 7th byte of the page 83 reply to determine - * whether the reply is compliant with SCSI-2 or SPC-2/3 - * specifications. A zero value in the 7th byte indicates - * an SPC-2/3 conformant reply, (i.e., the reserved field of the - * first Identification descriptor). This byte will be non-zero - * for a SCSI-2 conformant page 83 reply from these EMC - * Symmetrix models since the 7th byte of the reply corresponds - * to the 4th and 5th nibbles of the 6-byte OUI for EMC, that is, - * 0x006048. - */ - - if (page_83[6] != 0) { - return check_fill_0x83_prespc3(dev_scsi, page_83, - id_search_list, serial, - serial_short, len); - } - - /* - * Search for a match in the prioritized id_search_list - since WWN ids - * come first we can pick up the WWN in check_fill_0x83_id(). - */ - for (id_ind = 0; - id_ind < sizeof(id_search_list) / sizeof(id_search_list[0]); - id_ind++) { - /* - * Examine each descriptor returned. There is normally only - * one or a small number of descriptors. - */ - for (j = 4; j <= (unsigned int)page_83[3] + 3; - j += page_83[j + 3] + 4) { - - retval = check_fill_0x83_id(dev_scsi, &page_83[j], - &id_search_list[id_ind], - serial, serial_short, len, - wwn, wwn_vendor_extension, - tgpt_group); - if (!retval) { - return retval; - } else if (retval < 0) { - return retval; - } - } - } - return 1; + int retval; + unsigned int id_ind, j; + unsigned char page_83[SCSI_INQ_BUFF_LEN]; + + /* also pick up the page 80 serial number */ + do_scsi_page80_inquiry (dev_scsi, fd, NULL, unit_serial_number, + MAX_SERIAL_LEN); + + memzero (page_83, SCSI_INQ_BUFF_LEN); + retval = + scsi_inquiry (dev_scsi, fd, 1, PAGE_83, page_83, SCSI_INQ_BUFF_LEN); + if (retval < 0) + { + return 1; + } + + if (page_83[1] != PAGE_83) + { + log_debug ("%s: Invalid page 0x83", dev_scsi->kernel); + return 1; + } + + /* + * XXX Some devices (IBM 3542) return all spaces for an identifier if + * the LUN is not actually configured. This leads to identifiers of + * the form: "1 ". + */ + + /* + * Model 4, 5, and (some) model 6 EMC Symmetrix devices return + * a page 83 reply according to SCSI-2 format instead of SPC-2/3. + * + * The SCSI-2 page 83 format returns an IEEE WWN in binary + * encoded hexi-decimal in the 16 bytes following the initial + * 4-byte page 83 reply header. + * + * Both the SPC-2 and SPC-3 formats return an IEEE WWN as part + * of an Identification descriptor. The 3rd byte of the first + * Identification descriptor is a reserved (BSZ) byte field. + * + * Reference the 7th byte of the page 83 reply to determine + * whether the reply is compliant with SCSI-2 or SPC-2/3 + * specifications. A zero value in the 7th byte indicates + * an SPC-2/3 conformant reply, (i.e., the reserved field of the + * first Identification descriptor). This byte will be non-zero + * for a SCSI-2 conformant page 83 reply from these EMC + * Symmetrix models since the 7th byte of the reply corresponds + * to the 4th and 5th nibbles of the 6-byte OUI for EMC, that is, + * 0x006048. + */ + + if (page_83[6] != 0) + { + return check_fill_0x83_prespc3 (dev_scsi, page_83, + id_search_list, serial, + serial_short, len); + } + + /* + * Search for a match in the prioritized id_search_list - since WWN ids + * come first we can pick up the WWN in check_fill_0x83_id(). + */ + for (id_ind = 0; + id_ind < sizeof (id_search_list) / sizeof (id_search_list[0]); + id_ind++) + { + /* + * Examine each descriptor returned. There is normally only + * one or a small number of descriptors. + */ + for (j = 4; j <= (unsigned int) page_83[3] + 3; j += page_83[j + 3] + 4) + { + + retval = check_fill_0x83_id (dev_scsi, &page_83[j], + &id_search_list[id_ind], + serial, serial_short, len, + wwn, wwn_vendor_extension, tgpt_group); + if (!retval) + { + return retval; + } + else if (retval < 0) + { + return retval; + } + } + } + return 1; } /* @@ -907,344 +1008,392 @@ static int do_scsi_page83_inquiry(struct scsi_id_device *dev_scsi, int fd, * Return the hard coded error code value 2 if the page 83 reply is not * conformant to the SCSI-2 format. */ -static int do_scsi_page83_prespc3_inquiry(struct scsi_id_device *dev_scsi, - int fd, char *serial, - char *serial_short, int len) +static int +do_scsi_page83_prespc3_inquiry (struct scsi_id_device *dev_scsi, + int fd, char *serial, + char *serial_short, int len) { - int retval; - int i, j; - unsigned char page_83[SCSI_INQ_BUFF_LEN]; - - memzero(page_83, SCSI_INQ_BUFF_LEN); - retval = - scsi_inquiry(dev_scsi, fd, 1, PAGE_83, page_83, SCSI_INQ_BUFF_LEN); - if (retval < 0) { - return 1; - } - - if (page_83[1] != PAGE_83) { - log_debug("%s: Invalid page 0x83", dev_scsi->kernel); - return 1; - } - /* - * Model 4, 5, and (some) model 6 EMC Symmetrix devices return - * a page 83 reply according to SCSI-2 format instead of SPC-2/3. - * - * The SCSI-2 page 83 format returns an IEEE WWN in binary - * encoded hexi-decimal in the 16 bytes following the initial - * 4-byte page 83 reply header. - * - * Both the SPC-2 and SPC-3 formats return an IEEE WWN as part - * of an Identification descriptor. The 3rd byte of the first - * Identification descriptor is a reserved (BSZ) byte field. - * - * Reference the 7th byte of the page 83 reply to determine - * whether the reply is compliant with SCSI-2 or SPC-2/3 - * specifications. A zero value in the 7th byte indicates - * an SPC-2/3 conformant reply, (i.e., the reserved field of the - * first Identification descriptor). This byte will be non-zero - * for a SCSI-2 conformant page 83 reply from these EMC - * Symmetrix models since the 7th byte of the reply corresponds - * to the 4th and 5th nibbles of the 6-byte OUI for EMC, that is, - * 0x006048. - */ - if (page_83[6] == 0) { - return 2; - } - - serial[0] = hex_str[id_search_list[0].id_type]; - /* - * The first four bytes contain data, not a descriptor. - */ - i = 4; - j = strlen(serial); - /* - * Binary descriptor, convert to ASCII, - * using two bytes of ASCII for each byte - * in the page_83. - */ - while (i < (page_83[3] + 4)) { - serial[j++] = hex_str[(page_83[i] & 0xf0) >> 4]; - serial[j++] = hex_str[page_83[i] & 0x0f]; - i++; - } - return 0; + int retval; + int i, j; + unsigned char page_83[SCSI_INQ_BUFF_LEN]; + + memzero (page_83, SCSI_INQ_BUFF_LEN); + retval = + scsi_inquiry (dev_scsi, fd, 1, PAGE_83, page_83, SCSI_INQ_BUFF_LEN); + if (retval < 0) + { + return 1; + } + + if (page_83[1] != PAGE_83) + { + log_debug ("%s: Invalid page 0x83", dev_scsi->kernel); + return 1; + } + /* + * Model 4, 5, and (some) model 6 EMC Symmetrix devices return + * a page 83 reply according to SCSI-2 format instead of SPC-2/3. + * + * The SCSI-2 page 83 format returns an IEEE WWN in binary + * encoded hexi-decimal in the 16 bytes following the initial + * 4-byte page 83 reply header. + * + * Both the SPC-2 and SPC-3 formats return an IEEE WWN as part + * of an Identification descriptor. The 3rd byte of the first + * Identification descriptor is a reserved (BSZ) byte field. + * + * Reference the 7th byte of the page 83 reply to determine + * whether the reply is compliant with SCSI-2 or SPC-2/3 + * specifications. A zero value in the 7th byte indicates + * an SPC-2/3 conformant reply, (i.e., the reserved field of the + * first Identification descriptor). This byte will be non-zero + * for a SCSI-2 conformant page 83 reply from these EMC + * Symmetrix models since the 7th byte of the reply corresponds + * to the 4th and 5th nibbles of the 6-byte OUI for EMC, that is, + * 0x006048. + */ + if (page_83[6] == 0) + { + return 2; + } + + serial[0] = hex_str[id_search_list[0].id_type]; + /* + * The first four bytes contain data, not a descriptor. + */ + i = 4; + j = strlen (serial); + /* + * Binary descriptor, convert to ASCII, + * using two bytes of ASCII for each byte + * in the page_83. + */ + while (i < (page_83[3] + 4)) + { + serial[j++] = hex_str[(page_83[i] & 0xf0) >> 4]; + serial[j++] = hex_str[page_83[i] & 0x0f]; + i++; + } + return 0; } /* Get unit serial number VPD page */ -static int do_scsi_page80_inquiry(struct scsi_id_device *dev_scsi, int fd, - char *serial, char *serial_short, int max_len) +static int +do_scsi_page80_inquiry (struct scsi_id_device *dev_scsi, int fd, + char *serial, char *serial_short, int max_len) { - int retval; - int ser_ind; - int i; - int len; - unsigned char buf[SCSI_INQ_BUFF_LEN]; - - memzero(buf, SCSI_INQ_BUFF_LEN); - retval = scsi_inquiry(dev_scsi, fd, 1, PAGE_80, buf, SCSI_INQ_BUFF_LEN); - if (retval < 0) { - return retval; - } - - if (buf[1] != PAGE_80) { - log_debug("%s: Invalid page 0x80", dev_scsi->kernel); - return 1; - } - - len = 1 + VENDOR_LENGTH + MODEL_LENGTH + buf[3]; - if (max_len < len) { - log_debug("%s: length %d too short - need %d", dev_scsi->kernel, - max_len, len); - return 1; - } - /* - * Prepend 'S' to avoid unlikely collision with page 0x83 vendor - * specific type where we prepend '0' + vendor + model. - */ - len = buf[3]; - if (serial != NULL) { - serial[0] = 'S'; - ser_ind = prepend_vendor_model(dev_scsi, &serial[1]); - if (ser_ind < 0) { - return 1; - } - ser_ind++; /* for the leading 'S' */ - for (i = 4; i < len + 4; i++, ser_ind++) { - serial[ser_ind] = buf[i]; - } - } - if (serial_short != NULL) { - memcpy(serial_short, &buf[4], len); - serial_short[len] = '\0'; - } - return 0; + int retval; + int ser_ind; + int i; + int len; + unsigned char buf[SCSI_INQ_BUFF_LEN]; + + memzero (buf, SCSI_INQ_BUFF_LEN); + retval = scsi_inquiry (dev_scsi, fd, 1, PAGE_80, buf, SCSI_INQ_BUFF_LEN); + if (retval < 0) + { + return retval; + } + + if (buf[1] != PAGE_80) + { + log_debug ("%s: Invalid page 0x80", dev_scsi->kernel); + return 1; + } + + len = 1 + VENDOR_LENGTH + MODEL_LENGTH + buf[3]; + if (max_len < len) + { + log_debug ("%s: length %d too short - need %d", dev_scsi->kernel, + max_len, len); + return 1; + } + /* + * Prepend 'S' to avoid unlikely collision with page 0x83 vendor + * specific type where we prepend '0' + vendor + model. + */ + len = buf[3]; + if (serial != NULL) + { + serial[0] = 'S'; + ser_ind = prepend_vendor_model (dev_scsi, &serial[1]); + if (ser_ind < 0) + { + return 1; + } + ser_ind++; /* for the leading 'S' */ + for (i = 4; i < len + 4; i++, ser_ind++) + { + serial[ser_ind] = buf[i]; + } + } + if (serial_short != NULL) + { + memcpy (serial_short, &buf[4], len); + serial_short[len] = '\0'; + } + return 0; } -int scsi_std_inquiry(struct scsi_id_device *dev_scsi, const char *devname) +int +scsi_std_inquiry (struct scsi_id_device *dev_scsi, const char *devname) { - int fd; - unsigned char buf[SCSI_INQ_BUFF_LEN]; - struct stat statbuf; - int err = 0; - - fd = open(devname, O_RDONLY | O_NONBLOCK | O_CLOEXEC); - if (fd < 0) { - err = -errno; - log_debug("scsi_id: cannot open %s: errno = %d", devname, err); - return 1; - } - - if (fstat(fd, &statbuf) < 0) { - - err = -errno; - log_debug("scsi_id: cannot stat %s: errno = %d", devname, err); - err = 2; - goto out; - } - - sprintf(dev_scsi->kernel, "%d:%d", major(statbuf.st_rdev), - minor(statbuf.st_rdev)); - - memzero(buf, SCSI_INQ_BUFF_LEN); - err = scsi_inquiry(dev_scsi, fd, 0, 0, buf, SCSI_INQ_BUFF_LEN); - if (err < 0) { - goto out; - } - - err = 0; - memcpy(dev_scsi->vendor, buf + 8, 8); - dev_scsi->vendor[8] = '\0'; - memcpy(dev_scsi->model, buf + 16, 16); - dev_scsi->model[16] = '\0'; - memcpy(dev_scsi->revision, buf + 32, 4); - dev_scsi->revision[4] = '\0'; - sprintf(dev_scsi->type, "%x", buf[0] & 0x1f); - - out: - close(fd); - return err; + int fd; + unsigned char buf[SCSI_INQ_BUFF_LEN]; + struct stat statbuf; + int err = 0; + + fd = open (devname, O_RDONLY | O_NONBLOCK | O_CLOEXEC); + if (fd < 0) + { + err = -errno; + log_debug ("scsi_id: cannot open %s: errno = %d", devname, err); + return 1; + } + + if (fstat (fd, &statbuf) < 0) + { + + err = -errno; + log_debug ("scsi_id: cannot stat %s: errno = %d", devname, err); + err = 2; + goto out; + } + + sprintf (dev_scsi->kernel, "%d:%d", major (statbuf.st_rdev), + minor (statbuf.st_rdev)); + + memzero (buf, SCSI_INQ_BUFF_LEN); + err = scsi_inquiry (dev_scsi, fd, 0, 0, buf, SCSI_INQ_BUFF_LEN); + if (err < 0) + { + goto out; + } + + err = 0; + memcpy (dev_scsi->vendor, buf + 8, 8); + dev_scsi->vendor[8] = '\0'; + memcpy (dev_scsi->model, buf + 16, 16); + dev_scsi->model[16] = '\0'; + memcpy (dev_scsi->revision, buf + 32, 4); + dev_scsi->revision[4] = '\0'; + sprintf (dev_scsi->type, "%x", buf[0] & 0x1f); + +out: + close (fd); + return err; } -int scsi_get_serial(struct scsi_id_device *dev_scsi, const char *devname, - int page_code, int len) +int +scsi_get_serial (struct scsi_id_device *dev_scsi, const char *devname, + int page_code, int len) { - unsigned char page0[SCSI_INQ_BUFF_LEN]; - int fd = -1; - int cnt; - int ind; - int retval; - - memzero(dev_scsi->serial, len); - initialize_srand(); - - for (cnt = 20; cnt > 0; cnt--) { - struct timespec duration; - - fd = open(devname, O_RDONLY | O_NONBLOCK | O_CLOEXEC); - if (fd >= 0 || errno != EBUSY) { - break; - } - - duration.tv_sec = 0; - duration.tv_nsec = - (200 * 1000 * 1000) + (rand() % 100 * 1000 * 1000); - nanosleep(&duration, NULL); - } - if (fd < 0) { - return 1; - } - - if (page_code == PAGE_80) { - if (do_scsi_page80_inquiry - (dev_scsi, fd, dev_scsi->serial, dev_scsi->serial_short, - len)) { - retval = 1; - goto completed; - } else { - retval = 0; - goto completed; - } - } else if (page_code == PAGE_83) { - if (do_scsi_page83_inquiry - (dev_scsi, fd, dev_scsi->serial, dev_scsi->serial_short, - len, dev_scsi->unit_serial_number, dev_scsi->wwn, - dev_scsi->wwn_vendor_extension, dev_scsi->tgpt_group)) { - retval = 1; - goto completed; - } else { - retval = 0; - goto completed; - } - } else if (page_code == PAGE_83_PRE_SPC3) { - retval = - do_scsi_page83_prespc3_inquiry(dev_scsi, fd, - dev_scsi->serial, - dev_scsi->serial_short, len); - if (retval) { - /* - * Fallback to servicing a SPC-2/3 compliant page 83 - * inquiry if the page 83 reply format does not - * conform to pre-SPC3 expectations. - */ - if (retval == 2) { - if (do_scsi_page83_inquiry - (dev_scsi, fd, dev_scsi->serial, - dev_scsi->serial_short, len, - dev_scsi->unit_serial_number, - dev_scsi->wwn, - dev_scsi->wwn_vendor_extension, - dev_scsi->tgpt_group)) { - retval = 1; - goto completed; - } else { - retval = 0; - goto completed; - } - } else { - retval = 1; - goto completed; - } - } else { - retval = 0; - goto completed; - } - } else if (page_code != 0x00) { - log_debug("%s: unsupported page code 0x%d", dev_scsi->kernel, - page_code); - retval = 1; - goto completed; - } - - /* - * Get page 0, the page of the pages. By default, try from best to - * worst of supported pages: 0x83 then 0x80. - */ - if (do_scsi_page0_inquiry(dev_scsi, fd, page0, SCSI_INQ_BUFF_LEN)) { - /* - * Don't try anything else. Black list if a specific page - * should be used for this vendor+model, or maybe have an - * optional fall-back to page 0x80 or page 0x83. - */ - retval = 1; - goto completed; - } - - for (ind = 4; ind <= page0[3] + 3; ind++) { - if (page0[ind] == PAGE_83) { - if (!do_scsi_page83_inquiry - (dev_scsi, fd, dev_scsi->serial, - dev_scsi->serial_short, len, - dev_scsi->unit_serial_number, dev_scsi->wwn, - dev_scsi->wwn_vendor_extension, - dev_scsi->tgpt_group)) { - /* - * Success - */ - retval = 0; - goto completed; - } + unsigned char page0[SCSI_INQ_BUFF_LEN]; + int fd = -1; + int cnt; + int ind; + int retval; + + memzero (dev_scsi->serial, len); + initialize_srand (); + + for (cnt = 20; cnt > 0; cnt--) + { + struct timespec duration; + + fd = open (devname, O_RDONLY | O_NONBLOCK | O_CLOEXEC); + if (fd >= 0 || errno != EBUSY) + { + break; + } + + duration.tv_sec = 0; + duration.tv_nsec = (200 * 1000 * 1000) + (rand () % 100 * 1000 * 1000); + nanosleep (&duration, NULL); + } + if (fd < 0) + { + return 1; + } + + if (page_code == PAGE_80) + { + if (do_scsi_page80_inquiry + (dev_scsi, fd, dev_scsi->serial, dev_scsi->serial_short, len)) + { + retval = 1; + goto completed; + } + else + { + retval = 0; + goto completed; + } + } + else if (page_code == PAGE_83) + { + if (do_scsi_page83_inquiry + (dev_scsi, fd, dev_scsi->serial, dev_scsi->serial_short, + len, dev_scsi->unit_serial_number, dev_scsi->wwn, + dev_scsi->wwn_vendor_extension, dev_scsi->tgpt_group)) + { + retval = 1; + goto completed; + } + else + { + retval = 0; + goto completed; + } + } + else if (page_code == PAGE_83_PRE_SPC3) + { + retval = + do_scsi_page83_prespc3_inquiry (dev_scsi, fd, + dev_scsi->serial, + dev_scsi->serial_short, len); + if (retval) + { + /* + * Fallback to servicing a SPC-2/3 compliant page 83 + * inquiry if the page 83 reply format does not + * conform to pre-SPC3 expectations. + */ + if (retval == 2) + { + if (do_scsi_page83_inquiry + (dev_scsi, fd, dev_scsi->serial, + dev_scsi->serial_short, len, + dev_scsi->unit_serial_number, + dev_scsi->wwn, + dev_scsi->wwn_vendor_extension, dev_scsi->tgpt_group)) + { + retval = 1; + goto completed; } - } - - for (ind = 4; ind <= page0[3] + 3; ind++) { - if (page0[ind] == PAGE_80) { - if (!do_scsi_page80_inquiry - (dev_scsi, fd, dev_scsi->serial, - dev_scsi->serial_short, len)) { - /* - * Success - */ - retval = 0; - goto completed; - } + else + { + retval = 0; + goto completed; } - } - retval = 1; - - completed: - close(fd); - return retval; + } + else + { + retval = 1; + goto completed; + } + } + else + { + retval = 0; + goto completed; + } + } + else if (page_code != 0x00) + { + log_debug ("%s: unsupported page code 0x%d", dev_scsi->kernel, + page_code); + retval = 1; + goto completed; + } + + /* + * Get page 0, the page of the pages. By default, try from best to + * worst of supported pages: 0x83 then 0x80. + */ + if (do_scsi_page0_inquiry (dev_scsi, fd, page0, SCSI_INQ_BUFF_LEN)) + { + /* + * Don't try anything else. Black list if a specific page + * should be used for this vendor+model, or maybe have an + * optional fall-back to page 0x80 or page 0x83. + */ + retval = 1; + goto completed; + } + + for (ind = 4; ind <= page0[3] + 3; ind++) + { + if (page0[ind] == PAGE_83) + { + if (!do_scsi_page83_inquiry + (dev_scsi, fd, dev_scsi->serial, + dev_scsi->serial_short, len, + dev_scsi->unit_serial_number, dev_scsi->wwn, + dev_scsi->wwn_vendor_extension, dev_scsi->tgpt_group)) + { + /* + * Success + */ + retval = 0; + goto completed; + } + } + } + + for (ind = 4; ind <= page0[3] + 3; ind++) + { + if (page0[ind] == PAGE_80) + { + if (!do_scsi_page80_inquiry + (dev_scsi, fd, dev_scsi->serial, dev_scsi->serial_short, len)) + { + /* + * Success + */ + retval = 0; + goto completed; + } + } + } + retval = 1; + +completed: + close (fd); + return retval; } -static void set_type(const char *from, char *to, size_t len) +static void +set_type (const char *from, char *to, size_t len) { - int type_num; - char *eptr; - const char *type = "generic"; - - type_num = strtoul(from, &eptr, 0); - if (eptr != from) { - switch (type_num) { - case 0: - type = "disk"; - break; - case 1: - type = "tape"; - break; - case 4: - type = "optical"; - break; - case 5: - type = "cd"; - break; - case 7: - type = "optical"; - break; - case 0xe: - type = "disk"; - break; - case 0xf: - type = "optical"; - break; - default: - break; - } + int type_num; + char *eptr; + const char *type = "generic"; + + type_num = strtoul (from, &eptr, 0); + if (eptr != from) + { + switch (type_num) + { + case 0: + type = "disk"; + break; + case 1: + type = "tape"; + break; + case 4: + type = "optical"; + break; + case 5: + type = "cd"; + break; + case 7: + type = "optical"; + break; + case 0xe: + type = "disk"; + break; + case 0xf: + type = "optical"; + break; + default: + break; } - strscpy(to, len, type); + } + strscpy (to, len, type); } /* @@ -1256,47 +1405,56 @@ static void set_type(const char *from, char *to, size_t len) * Return a pointer to the NUL terminated string, returns NULL if no * matches. */ -static char *get_value(char **buffer) +static char * +get_value (char **buffer) { - static const char *quote_string = "\"\n"; - static const char *comma_string = ",\n"; - char *val; - const char *end; - - if (**buffer == '"') { - /* - * skip leading quote, terminate when quote seen - */ - (*buffer)++; - end = quote_string; - } else { - end = comma_string; - } - val = strsep(buffer, end); - if (val && end == quote_string) { - /* - * skip trailing quote - */ - (*buffer)++; - } - - while (isspace(**buffer)) { - (*buffer)++; - } - return val; + static const char *quote_string = "\"\n"; + static const char *comma_string = ",\n"; + char *val; + const char *end; + + if (**buffer == '"') + { + /* + * skip leading quote, terminate when quote seen + */ + (*buffer)++; + end = quote_string; + } + else + { + end = comma_string; + } + val = strsep (buffer, end); + if (val && end == quote_string) + { + /* + * skip trailing quote + */ + (*buffer)++; + } + + while (isspace (**buffer)) + { + (*buffer)++; + } + return val; } -static int argc_count(char *opts) +static int +argc_count (char *opts) { - int i = 0; - while (*opts != '\0') { - if (*opts++ == ' ') { - i++; - } + int i = 0; + while (*opts != '\0') + { + if (*opts++ == ' ') + { + i++; } - return i; + } + return i; } /* @@ -1308,501 +1466,562 @@ static int argc_count(char *opts) * * vendor and model can end in '\n'. */ -static int get_file_options(const char *vendor, const char *model, int *argc, - char ***newargv) +static int +get_file_options (const char *vendor, const char *model, int *argc, + char ***newargv) { - char *buffer; - FILE *f = NULL; - char *buf; - char *str1; - char *vendor_in, *model_in, *options_in; /* read in from file */ - int lineno; - int c; - int retval = 0; - int rc = 0; - - f = fopen(config_file, "re"); - if (f == NULL) { - if (errno == ENOENT) { - return 1; - } else { - - rc = -errno; - log_error("can't open %s: errno = %d", config_file, rc); - return -1; - } - } - - /* - * Allocate a buffer rather than put it on the stack so we can - * keep it around to parse any options (any allocated newargv - * points into this buffer for its strings). - */ - buffer = (char *)malloc(MAX_BUFFER_LEN); - if (!buffer) { - - fclose(f); - return -ENOMEM; - } - - *newargv = NULL; - lineno = 0; - while (1) { - vendor_in = model_in = options_in = NULL; - - buf = fgets(buffer, MAX_BUFFER_LEN, f); - - if (buf == NULL) { - break; - } - - lineno++; - if (buf[strlen(buffer) - 1] != '\n') { - log_error("Config file line %d too long", lineno); - break; - } - - while (isspace(*buf)) { - buf++; - } - - /* blank or all whitespace line */ - if (*buf == '\0') { - continue; - } - - /* comment line */ - if (*buf == '#') { - continue; - } - str1 = strsep(&buf, "="); - if (str1 && strcaseeq(str1, "VENDOR")) { - str1 = get_value(&buf); - if (!str1) { - retval = -ENOMEM; - break; - } - vendor_in = str1; - - str1 = strsep(&buf, "="); - if (str1 && strcaseeq(str1, "MODEL")) { - str1 = get_value(&buf); - if (!str1) { - retval = -ENOMEM; - break; - } - model_in = str1; - str1 = strsep(&buf, "="); - } - } - - if (str1 && strcaseeq(str1, "OPTIONS")) { - str1 = get_value(&buf); - if (!str1) { - retval = -ENOMEM; - break; - } - options_in = str1; - } - - /* - * Only allow: [vendor=foo[,model=bar]]options=stuff - */ - if (!options_in || (!vendor_in && model_in)) { - log_error("Error parsing config file line %d '%s'", - lineno, buffer); - retval = -1; - break; - } - if (vendor == NULL) { - if (vendor_in == NULL) { - break; - } - } else if (vendor_in - && strneq(vendor, vendor_in, strlen(vendor_in)) - && (!model_in - || (strneq(model, model_in, strlen(model_in))))) + char *buffer; + FILE *f = NULL; + char *buf; + char *str1; + char *vendor_in, *model_in, *options_in; /* read in from file */ + int lineno; + int c; + int retval = 0; + int rc = 0; + + f = fopen (config_file, "re"); + if (f == NULL) + { + if (errno == ENOENT) + { + return 1; + } + else + { + + rc = -errno; + log_error ("can't open %s: errno = %d", config_file, rc); + return -1; + } + } + + /* + * Allocate a buffer rather than put it on the stack so we can + * keep it around to parse any options (any allocated newargv + * points into this buffer for its strings). + */ + buffer = (char *) malloc (MAX_BUFFER_LEN); + if (!buffer) + { + + fclose (f); + return -ENOMEM; + } + + *newargv = NULL; + lineno = 0; + while (1) + { + vendor_in = model_in = options_in = NULL; + + buf = fgets (buffer, MAX_BUFFER_LEN, f); + + if (buf == NULL) + { + break; + } + + lineno++; + if (buf[strlen (buffer) - 1] != '\n') + { + log_error ("Config file line %d too long", lineno); + break; + } + + while (isspace (*buf)) + { + buf++; + } + + /* blank or all whitespace line */ + if (*buf == '\0') + { + continue; + } + + /* comment line */ + if (*buf == '#') + { + continue; + } + str1 = strsep (&buf, "="); + if (str1 && strcaseeq (str1, "VENDOR")) + { + str1 = get_value (&buf); + if (!str1) + { + retval = -ENOMEM; + break; + } + vendor_in = str1; + + str1 = strsep (&buf, "="); + if (str1 && strcaseeq (str1, "MODEL")) + { + str1 = get_value (&buf); + if (!str1) { - /* - * Matched vendor and optionally model. - * - * Note: a short vendor_in or model_in can - * give a partial match (that is FOO - * matches FOOBAR). - */ - break; + retval = -ENOMEM; + break; } - } - - fclose(f); - - if (retval == 0) { - if (vendor_in != NULL || model_in != NULL || options_in != NULL) { - /* - * Something matched. Allocate newargv, and store - * values found in options_in. - */ - strcpy(buffer, options_in); - c = argc_count(buffer) + 2; - *newargv = calloc(c, sizeof(**newargv)); - if (!*newargv) { - - retval = -ENOMEM; - } else { - *argc = c; - c = 0; - /* - * argv[0] at 0 is skipped by getopt, but - * store the buffer address there for - * later freeing - */ - (*newargv)[c] = buffer; - for (c = 1; c < *argc; c++) { - (*newargv)[c] = strsep(&buffer, " \t"); - } - } - } else { - /* No matches */ - retval = 1; + model_in = str1; + str1 = strsep (&buf, "="); + } + } + + if (str1 && strcaseeq (str1, "OPTIONS")) + { + str1 = get_value (&buf); + if (!str1) + { + retval = -ENOMEM; + break; + } + options_in = str1; + } + + /* + * Only allow: [vendor=foo[,model=bar]]options=stuff + */ + if (!options_in || (!vendor_in && model_in)) + { + log_error ("Error parsing config file line %d '%s'", + lineno, buffer); + retval = -1; + break; + } + if (vendor == NULL) + { + if (vendor_in == NULL) + { + break; + } + } + else if (vendor_in + && strneq (vendor, vendor_in, strlen (vendor_in)) + && (!model_in + || (strneq (model, model_in, strlen (model_in))))) + { + /* + * Matched vendor and optionally model. + * + * Note: a short vendor_in or model_in can + * give a partial match (that is FOO + * matches FOOBAR). + */ + break; + } + } + + fclose (f); + + if (retval == 0) + { + if (vendor_in != NULL || model_in != NULL || options_in != NULL) + { + /* + * Something matched. Allocate newargv, and store + * values found in options_in. + */ + strcpy (buffer, options_in); + c = argc_count (buffer) + 2; + *newargv = calloc (c, sizeof (**newargv)); + if (!*newargv) + { + + retval = -ENOMEM; + } + else + { + *argc = c; + c = 0; + /* + * argv[0] at 0 is skipped by getopt, but + * store the buffer address there for + * later freeing + */ + (*newargv)[c] = buffer; + for (c = 1; c < *argc; c++) + { + (*newargv)[c] = strsep (&buffer, " \t"); } + } } - if (retval != 0) { - free(buffer); + else + { + /* No matches */ + retval = 1; } + } + if (retval != 0) + { + free (buffer); + } - return retval; + return retval; } -static void help(char const *progname) +static void +help (char const *progname) { - printf("Usage: %s [OPTION...] /path/to/device/file\n\n" - "SCSI device identification.\n\n" - " -h --help Print this message\n" - " --version Print version of the program\n\n" - " -d --device= Device node for SG_IO commands\n" - " -f --config= Location of config file\n" - " -p --page=0x80|0x83|pre-spc3-83 SCSI page (0x80, 0x83, pre-spc3-83)\n" - " -s --sg-version=3|4 Use SGv3 or SGv4\n" - " -u --replace-whitespace Replace all whitespace by underscores\n" - " -v --verbose Verbose logging\n", - progname); + printf ("Usage: %s [OPTION...] /path/to/device/file\n\n" + "SCSI device identification.\n\n" + " -h --help Print this message\n" + " --version Print version of the program\n\n" + " -d --device= Device node for SG_IO commands\n" + " -f --config= Location of config file\n" + " -p --page=0x80|0x83|pre-spc3-83 SCSI page (0x80, 0x83, pre-spc3-83)\n" + " -s --sg-version=3|4 Use SGv3 or SGv4\n" + " -u --replace-whitespace Replace all whitespace by underscores\n" + " -v --verbose Verbose logging\n", progname); } -static int set_options(int argc, char **argv, char *maj_min_dev) +static int +set_options (int argc, char **argv, char *maj_min_dev) { - int option; - - /* - * optind is a global extern used by getopt. Since we can call - * set_options twice (once for command line, and once for config - * file) we have to reset this back to 1. - */ - optind = 1; - while ((option = - getopt_long(argc, argv, "d:f:gp:uvVh", options, NULL)) >= 0) - switch (option) { - - case 'd': - dev_specified = true; - strscpy(maj_min_dev, MAX_PATH_LEN, optarg); - break; - - case 'f': - strscpy(config_file, MAX_PATH_LEN, optarg); - break; - - case 'h': - help(argv[0]); - exit(0); - - case 'p': - if (streq(optarg, "0x80")) - default_page_code = PAGE_80; - else if (streq(optarg, "0x83")) - default_page_code = PAGE_83; - else if (streq(optarg, "pre-spc3-83")) - default_page_code = PAGE_83_PRE_SPC3; - else { - fprintf(stderr, - "[ERROR] %s: Unknown page code '%s'\n", - argv[0], optarg); - return -1; - } - break; - - case 's': - sg_version = atoi(optarg); - if (sg_version < 3 || sg_version > 4) { - fprintf(stderr, - "[ERROR] %s: Unknown SG version '%s'\n", - argv[0], optarg); - return -1; - } - break; - - case 'u': - reformat_serial = true; - break; - - case 'v': - break; - - case 'V': - printf("%s\n", "1.0"); - exit(0); - - case '?': - return -1; - - default: - fprintf(stderr, "[ERROR] %s: Unknown option -%c\n", - argv[0], option); - return -1; - } + int option; + + /* + * optind is a global extern used by getopt. Since we can call + * set_options twice (once for command line, and once for config + * file) we have to reset this back to 1. + */ + optind = 1; + while ((option = + getopt_long (argc, argv, "d:f:gp:uvVh", options, NULL)) >= 0) + switch (option) + { + + case 'd': + dev_specified = true; + strscpy (maj_min_dev, MAX_PATH_LEN, optarg); + break; + + case 'f': + strscpy (config_file, MAX_PATH_LEN, optarg); + break; + + case 'h': + help (argv[0]); + exit (0); + + case 'p': + if (streq (optarg, "0x80")) + default_page_code = PAGE_80; + else if (streq (optarg, "0x83")) + default_page_code = PAGE_83; + else if (streq (optarg, "pre-spc3-83")) + default_page_code = PAGE_83_PRE_SPC3; + else + { + fprintf (stderr, + "[ERROR] %s: Unknown page code '%s'\n", argv[0], optarg); + return -1; + } + break; + + case 's': + sg_version = atoi (optarg); + if (sg_version < 3 || sg_version > 4) + { + fprintf (stderr, + "[ERROR] %s: Unknown SG version '%s'\n", + argv[0], optarg); + return -1; + } + break; + + case 'u': + reformat_serial = true; + break; + + case 'v': + break; + + case 'V': + printf ("%s\n", "1.0"); + exit (0); + + case '?': + return -1; - if (optind < argc && !dev_specified) { - dev_specified = true; - strscpy(maj_min_dev, MAX_PATH_LEN, argv[optind]); - } + default: + fprintf (stderr, "[ERROR] %s: Unknown option -%c\n", argv[0], option); + return -1; + } + + if (optind < argc && !dev_specified) + { + dev_specified = true; + strscpy (maj_min_dev, MAX_PATH_LEN, argv[optind]); + } - return 0; + return 0; } -static int per_dev_options(struct scsi_id_device *dev_scsi, int *good_bad, - int *page_code) +static int +per_dev_options (struct scsi_id_device *dev_scsi, int *good_bad, + int *page_code) { - int retval; - int newargc; - char **newargv = NULL; - int option; - - *good_bad = all_good; - *page_code = default_page_code; - - retval = get_file_options(vendor_str, model_str, &newargc, &newargv); - - optind = 1; /* reset this global extern */ - while (retval == 0) { - option = getopt_long(newargc, newargv, "p:", options, NULL); - if (option == -1) - break; - - switch (option) { - - case 'p': - if (streq(optarg, "0x80")) { - *page_code = PAGE_80; - } else if (streq(optarg, "0x83")) { - *page_code = PAGE_83; - } else if (streq(optarg, "pre-spc3-83")) { - *page_code = PAGE_83_PRE_SPC3; - } else { - log_error("Unknown page code '%s'", optarg); - retval = -1; - } - break; - - default: - log_error("Unknown or bad option '%c' (0x%x)", option, - option); - retval = -1; - break; - } - } + int retval; + int newargc; + char **newargv = NULL; + int option; + + *good_bad = all_good; + *page_code = default_page_code; + + retval = get_file_options (vendor_str, model_str, &newargc, &newargv); + + optind = 1; /* reset this global extern */ + while (retval == 0) + { + option = getopt_long (newargc, newargv, "p:", options, NULL); + if (option == -1) + break; + + switch (option) + { + + case 'p': + if (streq (optarg, "0x80")) + { + *page_code = PAGE_80; + } + else if (streq (optarg, "0x83")) + { + *page_code = PAGE_83; + } + else if (streq (optarg, "pre-spc3-83")) + { + *page_code = PAGE_83_PRE_SPC3; + } + else + { + log_error ("Unknown page code '%s'", optarg); + retval = -1; + } + break; - if (newargv) { - free(newargv[0]); - free(newargv); - } - return retval; + default: + log_error ("Unknown or bad option '%c' (0x%x)", option, option); + retval = -1; + break; + } + } + + if (newargv) + { + free (newargv[0]); + free (newargv); + } + return retval; } -static int set_inq_values(struct scsi_id_device *dev_scsi, const char *path) +static int +set_inq_values (struct scsi_id_device *dev_scsi, const char *path) { - int retval; - - dev_scsi->use_sg = sg_version; - - retval = scsi_std_inquiry(dev_scsi, path); - if (retval) { - - log_error("scsi_std_inquiry('%s') rc = %d\n", path, retval); - return retval; - } - - vdev_util_encode_string(dev_scsi->vendor, vendor_enc_str, - sizeof(vendor_enc_str)); - vdev_util_encode_string(dev_scsi->model, model_enc_str, - sizeof(model_enc_str)); - - vdev_util_replace_whitespace(dev_scsi->vendor, vendor_str, - sizeof(vendor_str)); - vdev_util_replace_chars(vendor_str, NULL); - vdev_util_replace_whitespace(dev_scsi->model, model_str, - sizeof(model_str)); - vdev_util_replace_chars(model_str, NULL); - set_type(dev_scsi->type, type_str, sizeof(type_str)); - vdev_util_replace_whitespace(dev_scsi->revision, revision_str, - sizeof(revision_str)); - vdev_util_replace_chars(revision_str, NULL); - return 0; + int retval; + + dev_scsi->use_sg = sg_version; + + retval = scsi_std_inquiry (dev_scsi, path); + if (retval) + { + + log_error ("scsi_std_inquiry('%s') rc = %d\n", path, retval); + return retval; + } + + vdev_util_encode_string (dev_scsi->vendor, vendor_enc_str, + sizeof (vendor_enc_str)); + vdev_util_encode_string (dev_scsi->model, model_enc_str, + sizeof (model_enc_str)); + + vdev_util_replace_whitespace (dev_scsi->vendor, vendor_str, + sizeof (vendor_str)); + vdev_util_replace_chars (vendor_str, NULL); + vdev_util_replace_whitespace (dev_scsi->model, model_str, + sizeof (model_str)); + vdev_util_replace_chars (model_str, NULL); + set_type (dev_scsi->type, type_str, sizeof (type_str)); + vdev_util_replace_whitespace (dev_scsi->revision, revision_str, + sizeof (revision_str)); + vdev_util_replace_chars (revision_str, NULL); + return 0; } /* * scsi_id: try to get an id, if one is found, printf it to stdout. * returns a value passed to exit() - 0 if printed an id, else 1. */ -static int scsi_id(char *maj_min_dev) +static int +scsi_id (char *maj_min_dev) { - struct scsi_id_device dev_scsi = { }; - int good_dev = 1; - int page_code = 0; - int retval = 0; + struct scsi_id_device dev_scsi = { }; + int good_dev = 1; + int page_code = 0; + int retval = 0; - if (set_inq_values(&dev_scsi, maj_min_dev) < 0) { - retval = 1; - return retval; - } + if (set_inq_values (&dev_scsi, maj_min_dev) < 0) + { + retval = 1; + return retval; + } - /* get per device (vendor + model) options from the config file */ - per_dev_options(&dev_scsi, &good_dev, &page_code); - if (!good_dev) { + /* get per device (vendor + model) options from the config file */ + per_dev_options (&dev_scsi, &good_dev, &page_code); + if (!good_dev) + { - log_error("per_dev_options: good_dev = %d", good_dev); - retval = 1; - return retval; - } + log_error ("per_dev_options: good_dev = %d", good_dev); + retval = 1; + return retval; + } - /* read serial number from mode pages (no values for optical drives) */ - scsi_get_serial(&dev_scsi, maj_min_dev, page_code, MAX_SERIAL_LEN); + /* read serial number from mode pages (no values for optical drives) */ + scsi_get_serial (&dev_scsi, maj_min_dev, page_code, MAX_SERIAL_LEN); - char serial_str[MAX_SERIAL_LEN]; + char serial_str[MAX_SERIAL_LEN]; - vdev_property_add("VDEV_SCSI", "1"); - vdev_property_add("VDEV_SCSI_VENDOR", vendor_str); - vdev_property_add("VDEV_SCSI_VENDOR_ENC", vendor_enc_str); - vdev_property_add("VDEV_SCSI_MODEL", model_str); - vdev_property_add("VDEV_SCSI_MODEL_ENC", model_enc_str); - vdev_property_add("VDEV_SCSI_REVISION", revision_str); - vdev_property_add("VDEV_SCSI_TYPE", type_str); + vdev_property_add ("VDEV_SCSI", "1"); + vdev_property_add ("VDEV_SCSI_VENDOR", vendor_str); + vdev_property_add ("VDEV_SCSI_VENDOR_ENC", vendor_enc_str); + vdev_property_add ("VDEV_SCSI_MODEL", model_str); + vdev_property_add ("VDEV_SCSI_MODEL_ENC", model_enc_str); + vdev_property_add ("VDEV_SCSI_REVISION", revision_str); + vdev_property_add ("VDEV_SCSI_TYPE", type_str); - if (dev_scsi.serial[0] != '\0') { + if (dev_scsi.serial[0] != '\0') + { - vdev_util_replace_whitespace(dev_scsi.serial, serial_str, - sizeof(serial_str)); - vdev_util_replace_chars(serial_str, NULL); + vdev_util_replace_whitespace (dev_scsi.serial, serial_str, + sizeof (serial_str)); + vdev_util_replace_chars (serial_str, NULL); - vdev_property_add("VDEV_SCSI_SERIAL", serial_str); + vdev_property_add ("VDEV_SCSI_SERIAL", serial_str); - vdev_util_replace_whitespace(dev_scsi.serial_short, serial_str, - sizeof(serial_str)); - vdev_util_replace_chars(serial_str, NULL); + vdev_util_replace_whitespace (dev_scsi.serial_short, serial_str, + sizeof (serial_str)); + vdev_util_replace_chars (serial_str, NULL); - vdev_property_add("VDEV_SCSI_SERIAL_SHORT", serial_str); - } - if (dev_scsi.wwn[0] != '\0') { + vdev_property_add ("VDEV_SCSI_SERIAL_SHORT", serial_str); + } + if (dev_scsi.wwn[0] != '\0') + { - char wwn_buf[100]; - char wwn_vendor_buf[100]; + char wwn_buf[100]; + char wwn_vendor_buf[100]; - memset(wwn_buf, 0, 100); - memset(wwn_vendor_buf, 0, 100); + memset (wwn_buf, 0, 100); + memset (wwn_vendor_buf, 0, 100); - vdev_property_add("VDEV_SCSI_WWN", dev_scsi.wwn); + vdev_property_add ("VDEV_SCSI_WWN", dev_scsi.wwn); - if (dev_scsi.wwn_vendor_extension[0] != '\0') { + if (dev_scsi.wwn_vendor_extension[0] != '\0') + { - snprintf(wwn_buf, 99, "0x%s%s", dev_scsi.wwn, - dev_scsi.wwn_vendor_extension); - snprintf(wwn_vendor_buf, 99, "0x%s", - dev_scsi.wwn_vendor_extension); + snprintf (wwn_buf, 99, "0x%s%s", dev_scsi.wwn, + dev_scsi.wwn_vendor_extension); + snprintf (wwn_vendor_buf, 99, "0x%s", + dev_scsi.wwn_vendor_extension); - vdev_property_add("VDEV_SCSI_WWN_VENDOR_EXTENSION", - wwn_vendor_buf); - vdev_property_add("VDEV_SCSI_WWN_WITH_EXTENSION", - wwn_buf); - } + vdev_property_add ("VDEV_SCSI_WWN_VENDOR_EXTENSION", + wwn_vendor_buf); + vdev_property_add ("VDEV_SCSI_WWN_WITH_EXTENSION", wwn_buf); + } - else { + else + { - snprintf(wwn_buf, 99, "0x%s", dev_scsi.wwn); + snprintf (wwn_buf, 99, "0x%s", dev_scsi.wwn); - vdev_property_add("VDEV_SCSI_WWN_WITH_EXTENSION", - wwn_buf); - } + vdev_property_add ("VDEV_SCSI_WWN_WITH_EXTENSION", wwn_buf); } - if (dev_scsi.tgpt_group[0] != '\0') { + } + if (dev_scsi.tgpt_group[0] != '\0') + { - vdev_property_add("VDEV_SCSI_TARGET_PORT", dev_scsi.tgpt_group); - } - if (dev_scsi.unit_serial_number[0] != '\0') { + vdev_property_add ("VDEV_SCSI_TARGET_PORT", dev_scsi.tgpt_group); + } + if (dev_scsi.unit_serial_number[0] != '\0') + { - vdev_property_add("VDEV_SCSI_UNIT_SERIAL", - dev_scsi.unit_serial_number); - } + vdev_property_add ("VDEV_SCSI_UNIT_SERIAL", + dev_scsi.unit_serial_number); + } - return retval; + return retval; } // entry point -int main(int argc, char **argv) +int +main (int argc, char **argv) { - int retval = 0; - char maj_min_dev[MAX_PATH_LEN]; - int newargc; - char **newargv = NULL; - - /* - * Get config file options. - */ - retval = get_file_options(NULL, NULL, &newargc, &newargv); - if (retval < 0) { - retval = 1; - goto exit; - } - if (retval == 0) { - - if (newargv == NULL) { - retval = 4; - goto exit; - } - - if (set_options(newargc, newargv, maj_min_dev) < 0) { - retval = 2; - goto exit; - } - } - - /* - * Get command line options (overriding any config file settings). - */ - if (set_options(argc, argv, maj_min_dev) < 0) { - exit(1); - } - - if (!dev_specified) { - log_error("%s", "No device specified."); - retval = 1; - goto exit; - } - - retval = scsi_id(maj_min_dev); - - exit: - if (newargv) { - free(newargv[0]); - free(newargv); - } - - vdev_property_print(); - vdev_property_free_all(); - - return retval; + int retval = 0; + char maj_min_dev[MAX_PATH_LEN]; + int newargc; + char **newargv = NULL; + + /* + * Get config file options. + */ + retval = get_file_options (NULL, NULL, &newargc, &newargv); + if (retval < 0) + { + retval = 1; + goto exit; + } + if (retval == 0) + { + + if (newargv == NULL) + { + retval = 4; + goto exit; + } + + if (set_options (newargc, newargv, maj_min_dev) < 0) + { + retval = 2; + goto exit; + } + } + + /* + * Get command line options (overriding any config file settings). + */ + if (set_options (argc, argv, maj_min_dev) < 0) + { + exit (1); + } + + if (!dev_specified) + { + log_error ("%s", "No device specified."); + retval = 1; + goto exit; + } + + retval = scsi_id (maj_min_dev); + +exit: + if (newargv) + { + free (newargv[0]); + free (newargv); + } + + vdev_property_print (); + vdev_property_free_all (); + + return retval; } diff --git a/vdevd/helpers/LINUX/stat_usb.c b/vdevd/helpers/LINUX/stat_usb.c index edc0faf..9eaaa83 100644 --- a/vdevd/helpers/LINUX/stat_usb.c +++ b/vdevd/helpers/LINUX/stat_usb.c @@ -47,260 +47,280 @@ #define USB_DT_DEVICE 0x01 #define USB_DT_INTERFACE 0x04 -static void set_usb_iftype(char *to, int if_class_num, size_t len) +static void +set_usb_iftype (char *to, int if_class_num, size_t len) { - const char *type = "generic"; - - switch (if_class_num) { - case 1: - type = "audio"; - break; - case 2: /* CDC-Control */ - break; - case 3: - type = "hid"; - break; - case 5: /* Physical */ - break; - case 6: - type = "media"; - break; - case 7: - type = "printer"; - break; - case 8: - type = "storage"; - break; - case 9: - type = "hub"; - break; - case 0x0a: /* CDC-Data */ - break; - case 0x0b: /* Chip/Smart Card */ - break; - case 0x0d: /* Content Security */ - break; - case 0x0e: - type = "video"; - break; - case 0xdc: /* Diagnostic Device */ - break; - case 0xe0: /* Wireless Controller */ - break; - case 0xfe: /* Application-specific */ - break; - case 0xff: /* Vendor-specific */ - break; - default: - break; - } - - strncpy(to, type, len); - to[len - 1] = '\0'; + const char *type = "generic"; + + switch (if_class_num) + { + case 1: + type = "audio"; + break; + case 2: /* CDC-Control */ + break; + case 3: + type = "hid"; + break; + case 5: /* Physical */ + break; + case 6: + type = "media"; + break; + case 7: + type = "printer"; + break; + case 8: + type = "storage"; + break; + case 9: + type = "hub"; + break; + case 0x0a: /* CDC-Data */ + break; + case 0x0b: /* Chip/Smart Card */ + break; + case 0x0d: /* Content Security */ + break; + case 0x0e: + type = "video"; + break; + case 0xdc: /* Diagnostic Device */ + break; + case 0xe0: /* Wireless Controller */ + break; + case 0xfe: /* Application-specific */ + break; + case 0xff: /* Vendor-specific */ + break; + default: + break; + } + + strncpy (to, type, len); + to[len - 1] = '\0'; } -static int set_usb_mass_storage_ifsubtype(char *to, const char *from, - size_t len) +static int +set_usb_mass_storage_ifsubtype (char *to, const char *from, size_t len) { - int type_num = 0; - char *eptr; - const char *type = "generic"; - - type_num = strtoul(from, &eptr, 0); - if (eptr != from) { - switch (type_num) { - case 1: /* RBC devices */ - type = "rbc"; - break; - case 2: - type = "atapi"; - break; - case 3: - type = "tape"; - break; - case 4: /* UFI */ - type = "floppy"; - break; - case 6: /* Transparent SPC-2 devices */ - type = "scsi"; - break; - default: - break; - } + int type_num = 0; + char *eptr; + const char *type = "generic"; + + type_num = strtoul (from, &eptr, 0); + if (eptr != from) + { + switch (type_num) + { + case 1: /* RBC devices */ + type = "rbc"; + break; + case 2: + type = "atapi"; + break; + case 3: + type = "tape"; + break; + case 4: /* UFI */ + type = "floppy"; + break; + case 6: /* Transparent SPC-2 devices */ + type = "scsi"; + break; + default: + break; } + } - strncpy(to, type, (strlen(type) < len ? strlen(type) : len)); + strncpy (to, type, (strlen (type) < len ? strlen (type) : len)); - return type_num; + return type_num; } -static void set_scsi_type(char *to, const char *from, size_t len) +static void +set_scsi_type (char *to, const char *from, size_t len) { - int type_num; - char *eptr; - const char *type = "generic"; - - type_num = strtoul(from, &eptr, 0); - if (eptr != from) { - switch (type_num) { - case 0: - case 0xe: - type = "disk"; - break; - case 1: - type = "tape"; - break; - case 4: - case 7: - case 0xf: - type = "optical"; - break; - case 5: - type = "cd"; - break; - default: - break; - } + int type_num; + char *eptr; + const char *type = "generic"; + + type_num = strtoul (from, &eptr, 0); + if (eptr != from) + { + switch (type_num) + { + case 0: + case 0xe: + type = "disk"; + break; + case 1: + type = "tape"; + break; + case 4: + case 7: + case 0xf: + type = "optical"; + break; + case 5: + type = "cd"; + break; + default: + break; } + } - strncpy(to, type, (strlen(type) < len ? strlen(type) : len)); + strncpy (to, type, (strlen (type) < len ? strlen (type) : len)); } // read packed descriptors information from sysfs -static int dev_if_packed_info(char const *sysfs_path, char *ifs_str, size_t len) +static int +dev_if_packed_info (char const *sysfs_path, char *ifs_str, size_t len) { - char sysfs_descriptors[4096]; - int fd = -1; - ssize_t size; - unsigned char buf[18 + 65535]; - int pos = 0; - unsigned strpos = 0; - int rc = 0; - struct usb_interface_descriptor { - u_int8_t bLength; - u_int8_t bDescriptorType; - u_int8_t bInterfaceNumber; - u_int8_t bAlternateSetting; - u_int8_t bNumEndpoints; - u_int8_t bInterfaceClass; - u_int8_t bInterfaceSubClass; - u_int8_t bInterfaceProtocol; - u_int8_t iInterface; - } __attribute__ ((packed)); - - memset(sysfs_descriptors, 0, 4096); - snprintf(sysfs_descriptors, 4095, "%s/descriptors", sysfs_path); - - fd = open(sysfs_descriptors, O_RDONLY | O_CLOEXEC); - if (fd < 0) { - - rc = -errno; - log_debug("open('%s') errno = %d\n", sysfs_descriptors, rc); - - return rc; - } + char sysfs_descriptors[4096]; + int fd = -1; + ssize_t size; + unsigned char buf[18 + 65535]; + int pos = 0; + unsigned strpos = 0; + int rc = 0; + struct usb_interface_descriptor + { + u_int8_t bLength; + u_int8_t bDescriptorType; + u_int8_t bInterfaceNumber; + u_int8_t bAlternateSetting; + u_int8_t bNumEndpoints; + u_int8_t bInterfaceClass; + u_int8_t bInterfaceSubClass; + u_int8_t bInterfaceProtocol; + u_int8_t iInterface; + } __attribute__ ((packed)); - size = read(fd, buf, sizeof(buf)); - if (size < 18 || size == sizeof(buf)) { + memset (sysfs_descriptors, 0, 4096); + snprintf (sysfs_descriptors, 4095, "%s/descriptors", sysfs_path); - rc = -errno; + fd = open (sysfs_descriptors, O_RDONLY | O_CLOEXEC); + if (fd < 0) + { - close(fd); - log_debug("read('%s') rc = %zd, errno = %d\n", sysfs_path, size, - rc); - return -EIO; - } + rc = -errno; + log_debug ("open('%s') errno = %d\n", sysfs_descriptors, rc); - close(fd); + return rc; + } - ifs_str[0] = '\0'; - while (pos < size && strpos + 7 < len - 2) { + size = read (fd, buf, sizeof (buf)); + if (size < 18 || size == sizeof (buf)) + { - struct usb_interface_descriptor *desc; - char if_str[8]; + rc = -errno; - desc = (struct usb_interface_descriptor *)&buf[pos]; - if (desc->bLength < 3) { - break; - } + close (fd); + log_debug ("read('%s') rc = %zd, errno = %d\n", sysfs_path, size, rc); + return -EIO; + } - pos += desc->bLength; + close (fd); - if (desc->bDescriptorType != USB_DT_INTERFACE) { - continue; - } + ifs_str[0] = '\0'; + while (pos < size && strpos + 7 < len - 2) + { - if (snprintf - (if_str, 8, ":%02x%02x%02x", desc->bInterfaceClass, - desc->bInterfaceSubClass, desc->bInterfaceProtocol) != 7) { - continue; - } + struct usb_interface_descriptor *desc; + char if_str[8]; - if (strstr(ifs_str, if_str) != NULL) { - continue; - } + desc = (struct usb_interface_descriptor *) &buf[pos]; + if (desc->bLength < 3) + { + break; + } + + pos += desc->bLength; + + if (desc->bDescriptorType != USB_DT_INTERFACE) + { + continue; + } - memcpy(&ifs_str[strpos], if_str, 8), strpos += 7; + if (snprintf + (if_str, 8, ":%02x%02x%02x", desc->bInterfaceClass, + desc->bInterfaceSubClass, desc->bInterfaceProtocol) != 7) + { + continue; } - if (strpos > 0) { - ifs_str[strpos++] = ':'; - ifs_str[strpos++] = '\0'; + if (strstr (ifs_str, if_str) != NULL) + { + continue; } - return 0; + memcpy (&ifs_str[strpos], if_str, 8), strpos += 7; + } + + if (strpos > 0) + { + ifs_str[strpos++] = ':'; + ifs_str[strpos++] = '\0'; + } + + return 0; } -void usage(char const *progname) +void +usage (char const *progname) { - fprintf(stderr, - "[ERROR] %s: Usage: %s /path/to/sysfs/device/directory\n", - progname, progname); - exit(2); + fprintf (stderr, + "[ERROR] %s: Usage: %s /path/to/sysfs/device/directory\n", + progname, progname); + exit (2); } // find out what kind of device this is from the sysfs device tree // fill in the caller-supplied pointer with a malloc'ed string that encodes the DEVTYPE -int get_device_type(char const *sysfs_path, char **device_type, - size_t * device_type_len) +int +get_device_type (char const *sysfs_path, char **device_type, + size_t * device_type_len) { - char uevent_path[4097]; - memset(uevent_path, 0, 4097); + char uevent_path[4097]; + memset (uevent_path, 0, 4097); - char *uevent_buf = NULL; - size_t uevent_len = 0; + char *uevent_buf = NULL; + size_t uevent_len = 0; - char *device_type_buf = NULL; - size_t device_type_buf_len = 0; + char *device_type_buf = NULL; + size_t device_type_buf_len = 0; - int rc = 0; + int rc = 0; - snprintf(uevent_path, 4096, "%s/uevent", sysfs_path); + snprintf (uevent_path, 4096, "%s/uevent", sysfs_path); - rc = vdev_read_file(uevent_path, &uevent_buf, &uevent_len); - if (rc != 0) { + rc = vdev_read_file (uevent_path, &uevent_buf, &uevent_len); + if (rc != 0) + { - return rc; - } + return rc; + } - rc = vdev_sysfs_uevent_get_key(uevent_buf, uevent_len, "DEVTYPE", - &device_type_buf, &device_type_buf_len); - if (rc != 0) { + rc = vdev_sysfs_uevent_get_key (uevent_buf, uevent_len, "DEVTYPE", + &device_type_buf, &device_type_buf_len); + if (rc != 0) + { - free(uevent_buf); - return rc; - } + free (uevent_buf); + return rc; + } - *device_type = device_type_buf; - *device_type_len = device_type_buf_len; + *device_type = device_type_buf; + *device_type_len = device_type_buf_len; - free(uevent_buf); + free (uevent_buf); - return 0; + return 0; } /* @@ -320,637 +340,681 @@ int get_device_type(char const *sysfs_path, char **device_type, * 6.) If the device supplies a serial number, this number * is concatenated with the identification with an underscore '_'. */ -int main(int argc, char **argv) +int +main (int argc, char **argv) { - int rc = 0; - char vendor_str[256]; - char vendor_str_enc[256]; - char vendor_id[256]; - char model_str[256]; - char model_str_enc[256]; - char product_id[256]; - char serial_str[256]; - char packed_if_str[256]; - char revision_str[256]; - char type_str[256]; - char instance_str[256]; - char driver[256]; - char ifnum[256]; - char serial[4096]; - char sysfs_base[8193]; // /sys/devices entry for this device - char path_tmp[8193]; - - bool confirm_usb = false; - - char *attr = NULL; // temporary buffer for pulling attrs out of sysfs - size_t attr_len = 0; - - int if_class_num; - int protocol = 0; - size_t l; - char *s; - char *devtype_str = NULL; - size_t devtype_strlen = 0; - - // interface information - char *if_device_path = NULL; - size_t if_device_path_len = 0; - - char *usb_device_path = NULL; - size_t usb_device_path_len = 0; - - char *ifnum_str = NULL; - size_t ifnum_strlen = 0; - - char *driver_str = NULL; - size_t driver_strlen = 0; - - char *if_class_str = NULL; - size_t if_class_strlen = 0; - - char *if_subclass_str = NULL; - size_t if_subclass_strlen = 0; - - memset(sysfs_base, 0, 8193); - memset(path_tmp, 0, 8193); - - memset(vendor_str, 0, 256); - memset(vendor_str_enc, 0, 256); - memset(vendor_id, 0, 256); - memset(model_str, 0, 256); - memset(model_str_enc, 0, 256); - memset(product_id, 0, 256); - memset(serial_str, 0, 256); - memset(packed_if_str, 0, 256); - memset(revision_str, 0, 256); - memset(type_str, 0, 256); - memset(instance_str, 0, 256); - memset(driver, 0, 256); - memset(ifnum, 0, 256); - memset(serial, 0, 4096); - - if (argc != 2) { - usage(argv[0]); - } - - if (strlen(argv[1]) >= 4096) { - fprintf(stderr, "[ERROR] %s: Invalid /sys/devices path\n", - argv[0]); - exit(3); - } - - strcpy(sysfs_base, argv[1]); + int rc = 0; + char vendor_str[256]; + char vendor_str_enc[256]; + char vendor_id[256]; + char model_str[256]; + char model_str_enc[256]; + char product_id[256]; + char serial_str[256]; + char packed_if_str[256]; + char revision_str[256]; + char type_str[256]; + char instance_str[256]; + char driver[256]; + char ifnum[256]; + char serial[4096]; + char sysfs_base[8193]; // /sys/devices entry for this device + char path_tmp[8193]; + + bool confirm_usb = false; + + char *attr = NULL; // temporary buffer for pulling attrs out of sysfs + size_t attr_len = 0; + + int if_class_num; + int protocol = 0; + size_t l; + char *s; + char *devtype_str = NULL; + size_t devtype_strlen = 0; + + // interface information + char *if_device_path = NULL; + size_t if_device_path_len = 0; + + char *usb_device_path = NULL; + size_t usb_device_path_len = 0; + + char *ifnum_str = NULL; + size_t ifnum_strlen = 0; + + char *driver_str = NULL; + size_t driver_strlen = 0; + + char *if_class_str = NULL; + size_t if_class_strlen = 0; + + char *if_subclass_str = NULL; + size_t if_subclass_strlen = 0; + + memset (sysfs_base, 0, 8193); + memset (path_tmp, 0, 8193); + + memset (vendor_str, 0, 256); + memset (vendor_str_enc, 0, 256); + memset (vendor_id, 0, 256); + memset (model_str, 0, 256); + memset (model_str_enc, 0, 256); + memset (product_id, 0, 256); + memset (serial_str, 0, 256); + memset (packed_if_str, 0, 256); + memset (revision_str, 0, 256); + memset (type_str, 0, 256); + memset (instance_str, 0, 256); + memset (driver, 0, 256); + memset (ifnum, 0, 256); + memset (serial, 0, 4096); + + if (argc != 2) + { + usage (argv[0]); + } + + if (strlen (argv[1]) >= 4096) + { + fprintf (stderr, "[ERROR] %s: Invalid /sys/devices path\n", argv[0]); + exit (3); + } + + strcpy (sysfs_base, argv[1]); + + // find out what kind of device we are... + get_device_type (sysfs_base, &devtype_str, &devtype_strlen); + + if (devtype_str != NULL && strcmp (devtype_str, "usb_device") == 0) + { + + // we're a device, and can get the packed info right now + dev_if_packed_info (sysfs_base, packed_if_str, sizeof (packed_if_str)); + + usb_device_path = strdup (sysfs_base); + if (usb_device_path == NULL) + { + exit (4); + } + + usb_device_path_len = strlen (usb_device_path); + + goto fallback; + } + // find USB parent + rc = vdev_sysfs_get_parent_with_subsystem_devtype (sysfs_base, "usb", + "usb_interface", + &if_device_path, + &if_device_path_len); + if (rc != 0) + { + + fprintf (stderr, + "[ERROR] %s: unable to access usb_interface device of '%s'\n", + argv[0], sysfs_base); + exit (1); + } + // search *this* device instead + // get interface information + rc = vdev_sysfs_read_attr (if_device_path, "bInterfaceNumber", + &ifnum_str, &ifnum_strlen); + if (rc == 0) + { + + vdev_util_rstrip (ifnum_str); + + strncpy (ifnum, ifnum_str, + (sizeof (ifnum) - 1 < + ifnum_strlen ? sizeof (ifnum) - 1 : ifnum_strlen)); + + free (ifnum_str); + } + + rc = vdev_sysfs_read_attr (if_device_path, "driver", &driver_str, + &driver_strlen); + if (rc == 0) + { + + vdev_util_rstrip (driver_str); + + strncpy (driver, driver_str, + (sizeof (driver) - 1 < + driver_strlen ? sizeof (driver) - 1 : driver_strlen)); + + free (driver_str); + } + + rc = vdev_sysfs_read_attr (if_device_path, "bInterfaceClass", + &if_class_str, &if_class_strlen); + if (rc != 0) + { + + if (devtype_str != NULL) + { + free (devtype_str); + } + + fprintf (stderr, + "[ERROR] %s: vdev_sysfs_read_attr('%s/%s') rc = %d\n", + if_device_path, "bInterfaceClass", argv[0], rc); + exit (1); + } + // parse fields + if_class_num = strtoul (if_class_str, NULL, 16); + + free (if_class_str); + + if (if_class_num == 8) + { + // indicates mass storage device. + // check subclass + rc = vdev_sysfs_read_attr (if_device_path, "bInterfaceSubClass", + &if_subclass_str, &if_subclass_strlen); + if (rc == 0) + { + + // got ourselves a type of storage device + protocol = + set_usb_mass_storage_ifsubtype (type_str, + if_subclass_str, + sizeof (type_str) - 1); + } + else + { + + // set type from interface instead + set_usb_iftype (type_str, if_class_num, sizeof (type_str) - 1); + } + + free (if_subclass_str); + } + // find the usb_device that is this interface's parent + rc = vdev_sysfs_get_parent_with_subsystem_devtype (if_device_path, "usb", + "usb_device", + &usb_device_path, + &usb_device_path_len); + if (rc != 0) + { + + // couldn't find + if (devtype_str != NULL) + { + free (devtype_str); + } + + fprintf (stderr, + "[ERROR] %s: vdev_sysfs_get_parent_with_subsystem_devtype('%s', 'usb', 'usb_device') rc = %d\n", + argv[0], sysfs_base, rc); + + exit (1); + } + // got the device path! + // get the device info + dev_if_packed_info (usb_device_path, packed_if_str, sizeof (packed_if_str)); + + // is this a SCSI or ATAPI device? + if ((protocol == 6 || protocol == 2)) + { + + char *dev_scsi_path = NULL; + size_t dev_scsi_path_len = 0; + + char *scsi_vendor_str = NULL; + size_t scsi_vendor_str_len = 0; + + char *scsi_model_str = NULL; + size_t scsi_model_str_len = 0; + + char *scsi_type_str = NULL; + size_t scsi_type_str_len = 0; + + char *scsi_rev_str = NULL; + size_t scsi_rev_str_len = 0; + + char *dev_scsi_sysname = NULL; + size_t dev_scsi_sysname_len = 0; + + int host = 0; + int bus = 0; + int target = 0; + int lun = 0; + + // scsi device? + rc = vdev_sysfs_get_parent_with_subsystem_devtype (sysfs_base, + "scsi", + "scsi_device", + &dev_scsi_path, + &dev_scsi_path_len); + if (rc != 0) + { - // find out what kind of device we are... - get_device_type(sysfs_base, &devtype_str, &devtype_strlen); - - if (devtype_str != NULL && strcmp(devtype_str, "usb_device") == 0) { - - // we're a device, and can get the packed info right now - dev_if_packed_info(sysfs_base, packed_if_str, - sizeof(packed_if_str)); - - usb_device_path = strdup(sysfs_base); - if (usb_device_path == NULL) { - exit(4); - } - - usb_device_path_len = strlen(usb_device_path); - - goto fallback; - } - // find USB parent - rc = vdev_sysfs_get_parent_with_subsystem_devtype(sysfs_base, "usb", - "usb_interface", - &if_device_path, - &if_device_path_len); - if (rc != 0) { - - fprintf(stderr, - "[ERROR] %s: unable to access usb_interface device of '%s'\n", - argv[0], sysfs_base); - exit(1); - } - // search *this* device instead - // get interface information - rc = vdev_sysfs_read_attr(if_device_path, "bInterfaceNumber", - &ifnum_str, &ifnum_strlen); - if (rc == 0) { - - vdev_util_rstrip(ifnum_str); - - strncpy(ifnum, ifnum_str, - (sizeof(ifnum) - 1 < - ifnum_strlen ? sizeof(ifnum) - 1 : ifnum_strlen)); - - free(ifnum_str); - } - - rc = vdev_sysfs_read_attr(if_device_path, "driver", &driver_str, - &driver_strlen); - if (rc == 0) { - - vdev_util_rstrip(driver_str); - - strncpy(driver, driver_str, - (sizeof(driver) - 1 < - driver_strlen ? sizeof(driver) - 1 : driver_strlen)); - - free(driver_str); + // nope + log_error ("WARN: unable to find parent 'scsi' of '%s'", + sysfs_base); + goto fallback; } - rc = vdev_sysfs_read_attr(if_device_path, "bInterfaceClass", - &if_class_str, &if_class_strlen); - if (rc != 0) { - - if (devtype_str != NULL) { - free(devtype_str); - } - - fprintf(stderr, - "[ERROR] %s: vdev_sysfs_read_attr('%s/%s') rc = %d\n", - if_device_path, "bInterfaceClass", argv[0], rc); - exit(1); - } - // parse fields - if_class_num = strtoul(if_class_str, NULL, 16); - - free(if_class_str); - - if (if_class_num == 8) { - // indicates mass storage device. - // check subclass - rc = vdev_sysfs_read_attr(if_device_path, "bInterfaceSubClass", - &if_subclass_str, - &if_subclass_strlen); - if (rc == 0) { - - // got ourselves a type of storage device - protocol = - set_usb_mass_storage_ifsubtype(type_str, - if_subclass_str, - sizeof(type_str) - - 1); - } else { - - // set type from interface instead - set_usb_iftype(type_str, if_class_num, - sizeof(type_str) - 1); - } - - free(if_subclass_str); + rc = vdev_sysfs_get_sysname (dev_scsi_path, &dev_scsi_sysname, + &dev_scsi_sysname_len); + if (rc != 0) + { + + // nope + free (dev_scsi_path); + + log_error + ("WARN: vdev_sysfs_get_sysname('%s') rc = %d\n", + dev_scsi_path, rc); + goto fallback; } - // find the usb_device that is this interface's parent - rc = vdev_sysfs_get_parent_with_subsystem_devtype(if_device_path, "usb", - "usb_device", - &usb_device_path, - &usb_device_path_len); - if (rc != 0) { - - // couldn't find - if (devtype_str != NULL) { - free(devtype_str); - } - - fprintf(stderr, - "[ERROR] %s: vdev_sysfs_get_parent_with_subsystem_devtype('%s', 'usb', 'usb_device') rc = %d\n", - argv[0], sysfs_base, rc); + // find host, bus, target, lun + rc = sscanf (dev_scsi_sysname, "%d:%d:%d:%d", &host, &bus, + &target, &lun); + if (rc != 4) + { - exit(1); + // nope + log_error + ("WARN: unable to read host, bus, target, and/or lun from '%s'", + dev_scsi_path); + free (dev_scsi_path); + free (dev_scsi_sysname); + goto fallback; } - // got the device path! - // get the device info - dev_if_packed_info(usb_device_path, packed_if_str, - sizeof(packed_if_str)); - - // is this a SCSI or ATAPI device? - if ((protocol == 6 || protocol == 2)) { - - char *dev_scsi_path = NULL; - size_t dev_scsi_path_len = 0; - - char *scsi_vendor_str = NULL; - size_t scsi_vendor_str_len = 0; - - char *scsi_model_str = NULL; - size_t scsi_model_str_len = 0; - - char *scsi_type_str = NULL; - size_t scsi_type_str_len = 0; - - char *scsi_rev_str = NULL; - size_t scsi_rev_str_len = 0; - - char *dev_scsi_sysname = NULL; - size_t dev_scsi_sysname_len = 0; - - int host = 0; - int bus = 0; - int target = 0; - int lun = 0; + // see about vendor? + rc = vdev_sysfs_read_attr (dev_scsi_path, "vendor", + &scsi_vendor_str, &scsi_vendor_str_len); + if (rc != 0) + { - // scsi device? - rc = vdev_sysfs_get_parent_with_subsystem_devtype(sysfs_base, - "scsi", - "scsi_device", - &dev_scsi_path, - &dev_scsi_path_len); - if (rc != 0) { - - // nope - log_error("WARN: unable to find parent 'scsi' of '%s'", - sysfs_base); - goto fallback; - } - - rc = vdev_sysfs_get_sysname(dev_scsi_path, &dev_scsi_sysname, - &dev_scsi_sysname_len); - if (rc != 0) { - - // nope - free(dev_scsi_path); - - log_error - ("WARN: vdev_sysfs_get_sysname('%s') rc = %d\n", - dev_scsi_path, rc); - goto fallback; - } - // find host, bus, target, lun - rc = sscanf(dev_scsi_sysname, "%d:%d:%d:%d", &host, &bus, - &target, &lun); - if (rc != 4) { - - // nope - log_error - ("WARN: unable to read host, bus, target, and/or lun from '%s'", - dev_scsi_path); - free(dev_scsi_path); - free(dev_scsi_sysname); - goto fallback; - } - // see about vendor? - rc = vdev_sysfs_read_attr(dev_scsi_path, "vendor", - &scsi_vendor_str, - &scsi_vendor_str_len); - if (rc != 0) { - - // nope - log_error - ("WARN: unable to read vendor string from '%s'", - dev_scsi_path); - free(dev_scsi_path); - free(dev_scsi_sysname); - goto fallback; - } - - vdev_util_rstrip(scsi_vendor_str); - - vdev_util_encode_string(scsi_vendor_str, vendor_str_enc, - sizeof(vendor_str_enc)); - vdev_util_replace_whitespace(scsi_vendor_str, vendor_str, - sizeof(vendor_str) - 1); - vdev_util_replace_chars(vendor_str, NULL); - - free(scsi_vendor_str); - - // see about model? - rc = vdev_sysfs_read_attr(dev_scsi_path, "model", - &scsi_model_str, &scsi_model_str_len); - if (rc != 0) { - - // nope - log_error("WARN: unable to read model from '%s'", - dev_scsi_path); - free(dev_scsi_path); - free(dev_scsi_sysname); - - goto fallback; - } - - vdev_util_rstrip(scsi_model_str); - - vdev_util_encode_string(scsi_model_str, model_str_enc, - sizeof(model_str_enc)); - vdev_util_replace_whitespace(scsi_model_str, model_str, - sizeof(model_str) - 1); - vdev_util_replace_chars(model_str, NULL); - - free(scsi_model_str); - - // see about type? - rc = vdev_sysfs_read_attr(dev_scsi_path, "type", &scsi_type_str, - &scsi_type_str_len); - if (rc != 0) { - - // nope - log_error("WARN: unable to read type from '%s'", - dev_scsi_path); - free(dev_scsi_path); - free(dev_scsi_sysname); - - goto fallback; - } - - set_scsi_type(type_str, scsi_type_str, sizeof(type_str) - 1); - - free(scsi_type_str); - - // see about revision? - rc = vdev_sysfs_read_attr(dev_scsi_path, "rev", &scsi_rev_str, - &scsi_rev_str_len); - if (rc != 0) { - - // nope - log_error("WARN: unable to read revision from '%s'", - dev_scsi_path); - free(dev_scsi_path); - free(dev_scsi_sysname); - - goto fallback; - } - - vdev_util_replace_whitespace(scsi_rev_str, revision_str, - sizeof(revision_str) - 1); - vdev_util_replace_chars(revision_str, NULL); - - free(scsi_rev_str); - - sprintf(instance_str, "%d:%d", target, lun); - - free(dev_scsi_path); - free(dev_scsi_sysname); + // nope + log_error + ("WARN: unable to read vendor string from '%s'", dev_scsi_path); + free (dev_scsi_path); + free (dev_scsi_sysname); + goto fallback; } - fallback: + vdev_util_rstrip (scsi_vendor_str); - // not a device, and not an interface. - // fall back to querying vendor and model information - rc = vdev_sysfs_read_attr(usb_device_path, "idVendor", &attr, - &attr_len); - if (rc == 0) { + vdev_util_encode_string (scsi_vendor_str, vendor_str_enc, + sizeof (vendor_str_enc)); + vdev_util_replace_whitespace (scsi_vendor_str, vendor_str, + sizeof (vendor_str) - 1); + vdev_util_replace_chars (vendor_str, NULL); - strncpy(vendor_id, attr, - (attr_len < - sizeof(vendor_id) - 1 ? attr_len : sizeof(vendor_id) - - 1)); - vdev_util_rstrip(vendor_id); + free (scsi_vendor_str); - free(attr); - attr = NULL; - } - - rc = vdev_sysfs_read_attr(usb_device_path, "idProduct", &attr, - &attr_len); - if (rc == 0) { + // see about model? + rc = vdev_sysfs_read_attr (dev_scsi_path, "model", + &scsi_model_str, &scsi_model_str_len); + if (rc != 0) + { - strncpy(product_id, attr, - (attr_len < - sizeof(product_id) - - 1 ? attr_len : sizeof(product_id) - 1)); - vdev_util_rstrip(product_id); + // nope + log_error ("WARN: unable to read model from '%s'", dev_scsi_path); + free (dev_scsi_path); + free (dev_scsi_sysname); - free(attr); - attr = NULL; + goto fallback; } - if (vendor_str[0] == 0) { - - // vendor not known yet. Try manufaturer, and fall back to idVendor if need be - char *manufacturer_str = NULL; - size_t manufacturer_strlen = 0; - - rc = vdev_sysfs_read_attr(usb_device_path, "manufacturer", - &manufacturer_str, - &manufacturer_strlen); - if (rc != 0) { - - if (rc == -ENOENT) { - - // fall back to idVendor - vdev_util_encode_string(vendor_id, - vendor_str_enc, - sizeof(vendor_str_enc)); - vdev_util_replace_whitespace(vendor_id, - vendor_str, - sizeof(vendor_str) - - 1); - vdev_util_replace_chars(vendor_str, NULL); - } else { - - log_error - ("FATAL: vdev_sysfs_read_attr('%s/manufacturer') rc = %d\n", - usb_device_path, rc); - exit(1); - } - } else { - - // success! - vdev_util_rstrip(manufacturer_str); - - vdev_util_encode_string(manufacturer_str, - vendor_str_enc, - sizeof(vendor_str_enc)); - vdev_util_replace_whitespace(manufacturer_str, - vendor_str, - sizeof(vendor_str) - 1); - vdev_util_replace_chars(vendor_str, NULL); - - free(manufacturer_str); - manufacturer_str = NULL; - } - } + vdev_util_rstrip (scsi_model_str); - if (model_str[0] == 0) { - - // model not known yet. Try product, and fall back to idProduct if we fail - char *product_str = NULL; - size_t product_strlen = 0; - - rc = vdev_sysfs_read_attr(usb_device_path, "product", - &product_str, &product_strlen); - if (rc != 0) { - - if (rc == -ENOENT) { - - // fall back to idProduct - vdev_util_encode_string(product_id, - model_str_enc, - sizeof(model_str_enc)); - vdev_util_replace_whitespace(product_id, - vendor_str, - sizeof(vendor_str) - - 1); - vdev_util_replace_chars(vendor_str, NULL); - } else { - - log_error - ("FATAL: vdev_sysfs_read_attr('%s/product') rc = %d\n", - usb_device_path, rc); - exit(1); - } - } else { - - // success! - vdev_util_rstrip(product_str); - - vdev_util_encode_string(product_str, model_str_enc, - sizeof(model_str_enc)); - vdev_util_replace_whitespace(product_str, model_str, - sizeof(model_str) - 1); - vdev_util_replace_chars(model_str, NULL); - - free(product_str); - product_str = NULL; - } - } + vdev_util_encode_string (scsi_model_str, model_str_enc, + sizeof (model_str_enc)); + vdev_util_replace_whitespace (scsi_model_str, model_str, + sizeof (model_str) - 1); + vdev_util_replace_chars (model_str, NULL); - if (revision_str[0] == 0) { + free (scsi_model_str); + + // see about type? + rc = vdev_sysfs_read_attr (dev_scsi_path, "type", &scsi_type_str, + &scsi_type_str_len); + if (rc != 0) + { + + // nope + log_error ("WARN: unable to read type from '%s'", dev_scsi_path); + free (dev_scsi_path); + free (dev_scsi_sysname); + + goto fallback; + } + + set_scsi_type (type_str, scsi_type_str, sizeof (type_str) - 1); - // revision not known yet. maybe it's in bcdDevice? - rc = vdev_sysfs_read_attr(usb_device_path, "bcdDevice", &attr, - &attr_len); - if (rc == 0) { + free (scsi_type_str); - vdev_util_rstrip(attr); + // see about revision? + rc = vdev_sysfs_read_attr (dev_scsi_path, "rev", &scsi_rev_str, + &scsi_rev_str_len); + if (rc != 0) + { - vdev_util_replace_whitespace(attr, revision_str, - sizeof(revision_str) - 1); - vdev_util_replace_chars(revision_str, NULL); + // nope + log_error ("WARN: unable to read revision from '%s'", + dev_scsi_path); + free (dev_scsi_path); + free (dev_scsi_sysname); - free(attr); - attr = NULL; - } + goto fallback; } - if (serial_str[0] == 0) { - - // serial number not known. Try 'serial' - rc = vdev_sysfs_read_attr(usb_device_path, "serial", &attr, - &attr_len); - if (rc == 0) { + vdev_util_replace_whitespace (scsi_rev_str, revision_str, + sizeof (revision_str) - 1); + vdev_util_replace_chars (revision_str, NULL); - vdev_util_rstrip(attr); + free (scsi_rev_str); - const unsigned char *p = NULL; - bool valid = true; - - /* http://msdn.microsoft.com/en-us/library/windows/hardware/gg487321.aspx */ - for (p = (unsigned char *)attr; *p != '\0'; p++) { - if (*p < 0x20 || *p > 0x7f || *p == ',') { - valid = false; - break; - } - } - - if (valid) { - vdev_util_replace_whitespace(attr, serial_str, - sizeof(serial_str) - - 1); - vdev_util_replace_chars(serial_str, NULL); - } - - free(attr); - attr = NULL; - } - } - // serialize everything - s = serial; - sprintf(s, "%s_%s", vendor_str, model_str); - l = strlen(s); - - if (serial_str[0] != 0) { - sprintf(s + l, "_%s", serial_str); - l = strlen(s); - } - - if (instance_str[0] != 0) { - sprintf(s + l, "-%s", instance_str); - l = strlen(s); - } + sprintf (instance_str, "%d:%d", target, lun); - if (vendor_str[0] != 0) { - vdev_property_add("VDEV_USB_VENDOR", vendor_str); - confirm_usb = true; - } + free (dev_scsi_path); + free (dev_scsi_sysname); + } - if (vendor_str_enc[0] != 0) { - vdev_property_add("VDEV_USB_VENDOR_ENC", vendor_str_enc); - confirm_usb = true; - } +fallback: - if (vendor_id[0] != 0) { - vdev_property_add("VDEV_USB_VENDOR_ID", vendor_id); - confirm_usb = true; - } + // not a device, and not an interface. + // fall back to querying vendor and model information + rc = vdev_sysfs_read_attr (usb_device_path, "idVendor", &attr, &attr_len); + if (rc == 0) + { - if (model_str[0] != 0) { - vdev_property_add("VDEV_USB_MODEL", model_str); - confirm_usb = true; - } + strncpy (vendor_id, attr, + (attr_len < + sizeof (vendor_id) - 1 ? attr_len : sizeof (vendor_id) - 1)); + vdev_util_rstrip (vendor_id); - if (model_str_enc[0] != 0) { - vdev_property_add("VDEV_USB_MODEL_ENC", model_str_enc); - confirm_usb = true; - } + free (attr); + attr = NULL; + } - if (product_id[0] != 0) { - vdev_property_add("VDEV_USB_MODEL_ID", product_id); - confirm_usb = true; - } + rc = vdev_sysfs_read_attr (usb_device_path, "idProduct", &attr, &attr_len); + if (rc == 0) + { - if (revision_str[0] != 0) { - vdev_property_add("VDEV_USB_REVISION", revision_str); - confirm_usb = true; - } + strncpy (product_id, attr, + (attr_len < + sizeof (product_id) - + 1 ? attr_len : sizeof (product_id) - 1)); + vdev_util_rstrip (product_id); - if (strcmp(serial, "_") != 0) { + free (attr); + attr = NULL; + } - // nonempty serial number - vdev_property_add("VDEV_USB_SERIAL", serial); - confirm_usb = true; - } + if (vendor_str[0] == 0) + { - if (serial_str[0] != 0) { - vdev_property_add("VDEV_USB_SERIAL_SHORT", serial_str); - confirm_usb = true; - } + // vendor not known yet. Try manufaturer, and fall back to idVendor if need be + char *manufacturer_str = NULL; + size_t manufacturer_strlen = 0; - if (type_str[0] != 0) { - vdev_property_add("VDEV_USB_TYPE", type_str); - confirm_usb = true; - } + rc = vdev_sysfs_read_attr (usb_device_path, "manufacturer", + &manufacturer_str, &manufacturer_strlen); + if (rc != 0) + { - if (instance_str[0] != 0) { - vdev_property_add("VDEV_USB_INSTANCE", instance_str); - confirm_usb = true; - } + if (rc == -ENOENT) + { - if (packed_if_str[0] != 0) { - vdev_property_add("VDEV_USB_INTERFACES", packed_if_str); - confirm_usb = true; - } + // fall back to idVendor + vdev_util_encode_string (vendor_id, + vendor_str_enc, + sizeof (vendor_str_enc)); + vdev_util_replace_whitespace (vendor_id, + vendor_str, + sizeof (vendor_str) - 1); + vdev_util_replace_chars (vendor_str, NULL); + } + else + { - if (ifnum[0] != 0) { - vdev_property_add("VDEV_USB_INTERFACE_NUM", ifnum); - confirm_usb = true; + log_error + ("FATAL: vdev_sysfs_read_attr('%s/manufacturer') rc = %d\n", + usb_device_path, rc); + exit (1); + } } + else + { - if (driver[0] != 0) { - vdev_property_add("VDEV_USB_DRIVER", driver); - confirm_usb = true; - } + // success! + vdev_util_rstrip (manufacturer_str); + + vdev_util_encode_string (manufacturer_str, + vendor_str_enc, sizeof (vendor_str_enc)); + vdev_util_replace_whitespace (manufacturer_str, + vendor_str, sizeof (vendor_str) - 1); + vdev_util_replace_chars (vendor_str, NULL); + + free (manufacturer_str); + manufacturer_str = NULL; + } + } + + if (model_str[0] == 0) + { - if (confirm_usb) { - vdev_property_add("VDEV_USB", "1"); - } + // model not known yet. Try product, and fall back to idProduct if we fail + char *product_str = NULL; + size_t product_strlen = 0; + + rc = vdev_sysfs_read_attr (usb_device_path, "product", + &product_str, &product_strlen); + if (rc != 0) + { + + if (rc == -ENOENT) + { + + // fall back to idProduct + vdev_util_encode_string (product_id, + model_str_enc, sizeof (model_str_enc)); + vdev_util_replace_whitespace (product_id, + vendor_str, + sizeof (vendor_str) - 1); + vdev_util_replace_chars (vendor_str, NULL); + } + else + { + + log_error + ("FATAL: vdev_sysfs_read_attr('%s/product') rc = %d\n", + usb_device_path, rc); + exit (1); + } + } + else + { + + // success! + vdev_util_rstrip (product_str); + + vdev_util_encode_string (product_str, model_str_enc, + sizeof (model_str_enc)); + vdev_util_replace_whitespace (product_str, model_str, + sizeof (model_str) - 1); + vdev_util_replace_chars (model_str, NULL); + + free (product_str); + product_str = NULL; + } + } + + if (revision_str[0] == 0) + { + + // revision not known yet. maybe it's in bcdDevice? + rc = vdev_sysfs_read_attr (usb_device_path, "bcdDevice", &attr, + &attr_len); + if (rc == 0) + { + + vdev_util_rstrip (attr); + + vdev_util_replace_whitespace (attr, revision_str, + sizeof (revision_str) - 1); + vdev_util_replace_chars (revision_str, NULL); + + free (attr); + attr = NULL; + } + } + + if (serial_str[0] == 0) + { + + // serial number not known. Try 'serial' + rc = vdev_sysfs_read_attr (usb_device_path, "serial", &attr, &attr_len); + if (rc == 0) + { - vdev_property_print(); - vdev_property_free_all(); + vdev_util_rstrip (attr); - if (devtype_str != NULL) { - free(devtype_str); - } + const unsigned char *p = NULL; + bool valid = true; - return 0; + /* http://msdn.microsoft.com/en-us/library/windows/hardware/gg487321.aspx */ + for (p = (unsigned char *) attr; *p != '\0'; p++) + { + if (*p < 0x20 || *p > 0x7f || *p == ',') + { + valid = false; + break; + } + } + + if (valid) + { + vdev_util_replace_whitespace (attr, serial_str, + sizeof (serial_str) - 1); + vdev_util_replace_chars (serial_str, NULL); + } + + free (attr); + attr = NULL; + } + } + // serialize everything + s = serial; + sprintf (s, "%s_%s", vendor_str, model_str); + l = strlen (s); + + if (serial_str[0] != 0) + { + sprintf (s + l, "_%s", serial_str); + l = strlen (s); + } + + if (instance_str[0] != 0) + { + sprintf (s + l, "-%s", instance_str); + l = strlen (s); + } + + if (vendor_str[0] != 0) + { + vdev_property_add ("VDEV_USB_VENDOR", vendor_str); + confirm_usb = true; + } + + if (vendor_str_enc[0] != 0) + { + vdev_property_add ("VDEV_USB_VENDOR_ENC", vendor_str_enc); + confirm_usb = true; + } + + if (vendor_id[0] != 0) + { + vdev_property_add ("VDEV_USB_VENDOR_ID", vendor_id); + confirm_usb = true; + } + + if (model_str[0] != 0) + { + vdev_property_add ("VDEV_USB_MODEL", model_str); + confirm_usb = true; + } + + if (model_str_enc[0] != 0) + { + vdev_property_add ("VDEV_USB_MODEL_ENC", model_str_enc); + confirm_usb = true; + } + + if (product_id[0] != 0) + { + vdev_property_add ("VDEV_USB_MODEL_ID", product_id); + confirm_usb = true; + } + + if (revision_str[0] != 0) + { + vdev_property_add ("VDEV_USB_REVISION", revision_str); + confirm_usb = true; + } + + if (strcmp (serial, "_") != 0) + { + + // nonempty serial number + vdev_property_add ("VDEV_USB_SERIAL", serial); + confirm_usb = true; + } + + if (serial_str[0] != 0) + { + vdev_property_add ("VDEV_USB_SERIAL_SHORT", serial_str); + confirm_usb = true; + } + + if (type_str[0] != 0) + { + vdev_property_add ("VDEV_USB_TYPE", type_str); + confirm_usb = true; + } + + if (instance_str[0] != 0) + { + vdev_property_add ("VDEV_USB_INSTANCE", instance_str); + confirm_usb = true; + } + + if (packed_if_str[0] != 0) + { + vdev_property_add ("VDEV_USB_INTERFACES", packed_if_str); + confirm_usb = true; + } + + if (ifnum[0] != 0) + { + vdev_property_add ("VDEV_USB_INTERFACE_NUM", ifnum); + confirm_usb = true; + } + + if (driver[0] != 0) + { + vdev_property_add ("VDEV_USB_DRIVER", driver); + confirm_usb = true; + } + + if (confirm_usb) + { + vdev_property_add ("VDEV_USB", "1"); + } + + vdev_property_print (); + vdev_property_free_all (); + + if (devtype_str != NULL) + { + free (devtype_str); + } + + return 0; } diff --git a/vdevd/helpers/LINUX/stat_v4l.c b/vdevd/helpers/LINUX/stat_v4l.c index 23024b5..b4c0afc 100644 --- a/vdevd/helpers/LINUX/stat_v4l.c +++ b/vdevd/helpers/LINUX/stat_v4l.c @@ -39,89 +39,102 @@ #include "common.h" -int main(int argc, char *argv[]) +int +main (int argc, char *argv[]) { - static const struct option options[] = { - {"help", no_argument, NULL, 'h'}, - {} - }; - - int fd = 0; - char *device; - struct v4l2_capability v2cap; - char cap_str[4097]; - - memset(cap_str, 0, 4097); - - for (;;) { - int option; - - option = getopt_long(argc, argv, "h", options, NULL); - if (option == -1) { - break; - } - - switch (option) { - case 'h': - printf("%s [-h,--help] \n\n" - "Video4Linux device identification.\n\n" - " -h Print this message\n", argv[0]); - return 0; - default: - return 1; - } + static const struct option options[] = { + {"help", no_argument, NULL, 'h'}, + {} + }; + + int fd = 0; + char *device; + struct v4l2_capability v2cap; + char cap_str[4097]; + + memset (cap_str, 0, 4097); + + for (;;) + { + int option; + + option = getopt_long (argc, argv, "h", options, NULL); + if (option == -1) + { + break; } - device = argv[optind]; - - if (device == NULL) { - return 2; + switch (option) + { + case 'h': + printf ("%s [-h,--help] \n\n" + "Video4Linux device identification.\n\n" + " -h Print this message\n", argv[0]); + return 0; + default: + return 1; } + } - fd = open(device, O_RDONLY); - if (fd < 0) { - return 3; - } + device = argv[optind]; - if (ioctl(fd, VIDIOC_QUERYCAP, &v2cap) == 0) { + if (device == NULL) + { + return 2; + } - vdev_property_add("VDEV_V4L_VERSION", "2"); - vdev_property_add("VDEV_V4L_PRODUCT", (char *)v2cap.card); + fd = open (device, O_RDONLY); + if (fd < 0) + { + return 3; + } - strcat(cap_str, ":"); + if (ioctl (fd, VIDIOC_QUERYCAP, &v2cap) == 0) + { - if ((v2cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) > 0) { + vdev_property_add ("VDEV_V4L_VERSION", "2"); + vdev_property_add ("VDEV_V4L_PRODUCT", (char *) v2cap.card); - strcat(cap_str, "capture:"); - } - if ((v2cap.capabilities & V4L2_CAP_VIDEO_OUTPUT) > 0) { + strcat (cap_str, ":"); - strcat(cap_str, "video_output:"); - } - if ((v2cap.capabilities & V4L2_CAP_VIDEO_OVERLAY) > 0) { + if ((v2cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) > 0) + { - strcat(cap_str, "video_overlay:"); - } - if ((v2cap.capabilities & V4L2_CAP_AUDIO) > 0) { + strcat (cap_str, "capture:"); + } + if ((v2cap.capabilities & V4L2_CAP_VIDEO_OUTPUT) > 0) + { - strcat(cap_str, "audio:"); - } - if ((v2cap.capabilities & V4L2_CAP_TUNER) > 0) { + strcat (cap_str, "video_output:"); + } + if ((v2cap.capabilities & V4L2_CAP_VIDEO_OVERLAY) > 0) + { - strcat(cap_str, "tuner:"); - } - if ((v2cap.capabilities & V4L2_CAP_RADIO) > 0) { + strcat (cap_str, "video_overlay:"); + } + if ((v2cap.capabilities & V4L2_CAP_AUDIO) > 0) + { - strcat(cap_str, "radio:"); - } + strcat (cap_str, "audio:"); + } + if ((v2cap.capabilities & V4L2_CAP_TUNER) > 0) + { + + strcat (cap_str, "tuner:"); + } + if ((v2cap.capabilities & V4L2_CAP_RADIO) > 0) + { - vdev_property_add("VDEV_V4L_CAPABILITIES", cap_str); + strcat (cap_str, "radio:"); } - close(fd); + vdev_property_add ("VDEV_V4L_CAPABILITIES", cap_str); + } + + close (fd); - vdev_property_print(); - vdev_property_free_all(); + vdev_property_print (); + vdev_property_free_all (); - return 0; + return 0; } diff --git a/vdevd/os/common.c b/vdevd/os/common.c index 9beb753..901b8c6 100644 --- a/vdevd/os/common.c +++ b/vdevd/os/common.c @@ -25,146 +25,165 @@ #include "methods.h" // yield new devices -int vdev_os_main(struct vdev_os_context *vos) +int +vdev_os_main (struct vdev_os_context *vos) { - int rc = 0; + int rc = 0; - while (vos->running) { + while (vos->running) + { - // make a device request - struct vdev_device_request *vreq = - VDEV_CALLOC(struct vdev_device_request, 1); + // make a device request + struct vdev_device_request *vreq = + VDEV_CALLOC (struct vdev_device_request, 1); - if (vreq == NULL) { - // OOM - break; - } - // next device request - rc = vdev_device_request_init(vreq, vos->state, - VDEV_DEVICE_INVALID, NULL); - if (rc != 0) { + if (vreq == NULL) + { + // OOM + break; + } + // next device request + rc = vdev_device_request_init (vreq, vos->state, + VDEV_DEVICE_INVALID, NULL); + if (rc != 0) + { - if (rc == -EAGAIN) { - continue; - } + if (rc == -EAGAIN) + { + continue; + } - free(vreq); + free (vreq); - vdev_error("vdev_device_request_init rc = %d\n", rc); - break; - } - // yield the next device - rc = vdev_os_next_device(vreq, vos->os_cls); - if (rc != 0) { - - vdev_device_request_free(vreq); - free(vreq); + vdev_error ("vdev_device_request_init rc = %d\n", rc); + break; + } + // yield the next device + rc = vdev_os_next_device (vreq, vos->os_cls); + if (rc != 0) + { - if (rc < 0) { - vdev_error("vdev_os_next_device rc = %d\n", rc); + vdev_device_request_free (vreq); + free (vreq); - if (rc == -EAGAIN) { + if (rc < 0) + { + vdev_error ("vdev_os_next_device rc = %d\n", rc); - // OS backend says try again - continue; - } else { + if (rc == -EAGAIN) + { - // fatal error - break; - } - } else { + // OS backend says try again + continue; + } + else + { - // exit on success - rc = 0; - break; - } + // fatal error + break; } + } + else + { + + // exit on success + rc = 0; + break; + } + } - vdev_debug - ("Next device: %p, type=%d path=%s major=%u minor=%u mode=%o\n", - vreq, vreq->type, vreq->path, major(vreq->dev), - minor(vreq->dev), vreq->mode); + vdev_debug + ("Next device: %p, type=%d path=%s major=%u minor=%u mode=%o\n", + vreq, vreq->type, vreq->path, major (vreq->dev), + minor (vreq->dev), vreq->mode); - /* - struct sglib_vdev_params_iterator itr2; - struct vdev_param_t* dp2 = NULL; + /* + struct sglib_vdev_params_iterator itr2; + struct vdev_param_t* dp2 = NULL; - printf("vreq %p: params:\n", vreq); - for( dp2 = sglib_vdev_params_it_init_inorder( &itr2, vreq->params ); dp2 != NULL; dp2 = sglib_vdev_params_it_next( &itr2 ) ) { + printf("vreq %p: params:\n", vreq); + for( dp2 = sglib_vdev_params_it_init_inorder( &itr2, vreq->params ); dp2 != NULL; dp2 = sglib_vdev_params_it_next( &itr2 ) ) { - printf(" '%s' == '%s'\n", dp2->key, dp2->value ); - } - */ + printf(" '%s' == '%s'\n", dp2->key, dp2->value ); + } + */ - // post the event to the device work queue - rc = vdev_device_request_enqueue(&vos->state->device_wq, vreq); + // post the event to the device work queue + rc = vdev_device_request_enqueue (&vos->state->device_wq, vreq); - if (rc != 0) { + if (rc != 0) + { - vdev_device_request_free(vreq); - free(vreq); + vdev_device_request_free (vreq); + free (vreq); - vdev_error("vdev_device_request_add rc = %d\n", rc); + vdev_error ("vdev_device_request_add rc = %d\n", rc); - continue; - } + continue; } + } - return rc; + return rc; } // set up a vdev os context // NOTE: not reload-safe -int vdev_os_context_init(struct vdev_os_context *vos, struct vdev_state *state) +int +vdev_os_context_init (struct vdev_os_context *vos, struct vdev_state *state) { - int rc = 0; + int rc = 0; - memset(vos, 0, sizeof(struct vdev_os_context)); + memset (vos, 0, sizeof (struct vdev_os_context)); - vos->state = state; - vos->coldplug_only = state->coldplug_only; + vos->state = state; + vos->coldplug_only = state->coldplug_only; - // set up OS state - rc = vdev_os_init(vos, &vos->os_cls); - if (rc != 0) { + // set up OS state + rc = vdev_os_init (vos, &vos->os_cls); + if (rc != 0) + { - vdev_error("vdev_os_init rc = %d\n", rc); - memset(vos, 0, sizeof(struct vdev_os_context)); - return rc; - } + vdev_error ("vdev_os_init rc = %d\n", rc); + memset (vos, 0, sizeof (struct vdev_os_context)); + return rc; + } - vos->running = true; + vos->running = true; - return 0; + return 0; } // free memory -int vdev_os_context_free(struct vdev_os_context *vos) +int +vdev_os_context_free (struct vdev_os_context *vos) { - if (vos != NULL) { - vdev_os_shutdown(vos->os_cls); - vos->os_cls = NULL; + if (vos != NULL) + { + vdev_os_shutdown (vos->os_cls); + vos->os_cls = NULL; - memset(vos, 0, sizeof(struct vdev_os_context)); - } + memset (vos, 0, sizeof (struct vdev_os_context)); + } - return 0; + return 0; } // backend signal to vdevd that it has processed all coldplugged devices -int vdev_os_context_signal_coldplug_finished(struct vdev_os_context *vos) +int +vdev_os_context_signal_coldplug_finished (struct vdev_os_context *vos) { - vos->coldplug_finished = true; - return 0; + vos->coldplug_finished = true; + return 0; } // wait for coldplug to finish -bool vdev_os_context_is_coldplug_finished(struct vdev_os_context * vos) +bool +vdev_os_context_is_coldplug_finished (struct vdev_os_context * vos) { - return vos->coldplug_finished; + return vos->coldplug_finished; } diff --git a/vdevd/os/common.h b/vdevd/os/common.h index 5e0661a..88d2998 100644 --- a/vdevd/os/common.h +++ b/vdevd/os/common.h @@ -25,30 +25,32 @@ #include "libvdev/util.h" // connection to the OS's device notification system -struct vdev_os_context { +struct vdev_os_context +{ - void *os_cls; // OS-specific data + void *os_cls; // OS-specific data - bool running; + bool running; - bool coldplug_only; - bool coldplug_finished; + bool coldplug_only; + bool coldplug_finished; - // reference to global state - // ACCESS WITH CAUTION--ENSURE RELOAD SAFETY - struct vdev_state *state; + // reference to global state + // ACCESS WITH CAUTION--ENSURE RELOAD SAFETY + struct vdev_state *state; }; C_LINKAGE_BEGIN // context management -int vdev_os_context_init(struct vdev_os_context *vos, struct vdev_state *state); -int vdev_os_context_free(struct vdev_os_context *vos); +int vdev_os_context_init (struct vdev_os_context *vos, + struct vdev_state *state); +int vdev_os_context_free (struct vdev_os_context *vos); // signaling from the back-end to vdevd -int vdev_os_context_signal_coldplug_finished(struct vdev_os_context *vos); -bool vdev_os_context_is_coldplug_finished(struct vdev_os_context *vos); +int vdev_os_context_signal_coldplug_finished (struct vdev_os_context *vos); +bool vdev_os_context_is_coldplug_finished (struct vdev_os_context *vos); -int vdev_os_main(struct vdev_os_context *vos); +int vdev_os_main (struct vdev_os_context *vos); C_LINKAGE_END #endif diff --git a/vdevd/os/linux.c b/vdevd/os/linux.c index 32ed56e..dc4a216 100644 --- a/vdevd/os/linux.c +++ b/vdevd/os/linux.c @@ -26,188 +26,208 @@ #include "libvdev/sglib.h" // parse a uevent action -static vdev_device_request_t vdev_linux_parse_device_request_type(char const - *type) +static vdev_device_request_t +vdev_linux_parse_device_request_type (char const *type) { - if (strcmp(type, "add") == 0) { - return VDEV_DEVICE_ADD; - } else if (strcmp(type, "remove") == 0) { - return VDEV_DEVICE_REMOVE; - } else if (strcmp(type, "change") == 0) { - return VDEV_DEVICE_CHANGE; - } - - return VDEV_DEVICE_INVALID; + if (strcmp (type, "add") == 0) + { + return VDEV_DEVICE_ADD; + } + else if (strcmp (type, "remove") == 0) + { + return VDEV_DEVICE_REMOVE; + } + else if (strcmp (type, "change") == 0) + { + return VDEV_DEVICE_CHANGE; + } + + return VDEV_DEVICE_INVALID; } // make the full sysfs path from the dev path, plus an additional path // return NULL on OOM -static char *vdev_linux_sysfs_fullpath(char const *sysfs_mountpoint, - char const *devpath, - char const *attr_path) +static char * +vdev_linux_sysfs_fullpath (char const *sysfs_mountpoint, + char const *devpath, char const *attr_path) { - char *tmp = NULL; - char *ret = NULL; + char *tmp = NULL; + char *ret = NULL; - tmp = vdev_fullpath(sysfs_mountpoint, devpath, NULL); - if (tmp == NULL) { - return NULL; - } + tmp = vdev_fullpath (sysfs_mountpoint, devpath, NULL); + if (tmp == NULL) + { + return NULL; + } - ret = vdev_fullpath(tmp, attr_path, NULL); - free(tmp); + ret = vdev_fullpath (tmp, attr_path, NULL); + free (tmp); - return ret; + return ret; } // parse a device number pair // return 0 on success, and set *major and *minor // return -EINVAL if we failed to parse -static int vdev_linux_sysfs_parse_device_nums(char const *devbuf, - unsigned int *major, - unsigned int *minor) +static int +vdev_linux_sysfs_parse_device_nums (char const *devbuf, + unsigned int *major, unsigned int *minor) { - int rc = 0; + int rc = 0; - // parse devpath - rc = sscanf(devbuf, "%u:%u", major, minor); + // parse devpath + rc = sscanf (devbuf, "%u:%u", major, minor); - if (rc != 2) { + if (rc != 2) + { - vdev_error("sscanf('%s') for major:minor rc = %d\n", devbuf, - rc); - rc = -EINVAL; - } else { - rc = 0; - } + vdev_error ("sscanf('%s') for major:minor rc = %d\n", devbuf, rc); + rc = -EINVAL; + } + else + { + rc = 0; + } - return rc; + return rc; } // read the device major and minor number, using the devpath // return 0 on success, and set *major and *minor // return -ENOMEM on OOM // return -errno on failure to open or read -static int vdev_linux_sysfs_read_dev_nums(struct vdev_linux_context *ctx, - char const *devpath, - unsigned int *major, - unsigned int *minor) +static int +vdev_linux_sysfs_read_dev_nums (struct vdev_linux_context *ctx, + char const *devpath, + unsigned int *major, unsigned int *minor) { - int rc = 0; - int fd = 0; - ssize_t nr = 0; - char devbuf[101]; + int rc = 0; + int fd = 0; + ssize_t nr = 0; + char devbuf[101]; - memset(devbuf, 0, 101); + memset (devbuf, 0, 101); - char *full_devpath = - vdev_linux_sysfs_fullpath(ctx->sysfs_mountpoint, devpath, "dev"); - if (full_devpath == NULL) { - return -ENOMEM; - } - // open device path - fd = open(full_devpath, O_RDONLY); - if (fd < 0) { + char *full_devpath = + vdev_linux_sysfs_fullpath (ctx->sysfs_mountpoint, devpath, "dev"); + if (full_devpath == NULL) + { + return -ENOMEM; + } + // open device path + fd = open (full_devpath, O_RDONLY); + if (fd < 0) + { - rc = -errno; + rc = -errno; - if (rc != -ENOENT) { - vdev_error("open('%s') rc = %d\n", full_devpath, rc); - } - - free(full_devpath); - return rc; + if (rc != -ENOENT) + { + vdev_error ("open('%s') rc = %d\n", full_devpath, rc); } - nr = vdev_read_uninterrupted(fd, devbuf, 100); - if (nr < 0) { + free (full_devpath); + return rc; + } - rc = nr; - vdev_error("read('%s') rc = %d\n", full_devpath, rc); + nr = vdev_read_uninterrupted (fd, devbuf, 100); + if (nr < 0) + { - free(full_devpath); - close(fd); - return rc; - } + rc = nr; + vdev_error ("read('%s') rc = %d\n", full_devpath, rc); - close(fd); - free(full_devpath); + free (full_devpath); + close (fd); + return rc; + } - rc = vdev_linux_sysfs_parse_device_nums(devbuf, major, minor); + close (fd); + free (full_devpath); - if (rc != 0) { + rc = vdev_linux_sysfs_parse_device_nums (devbuf, major, minor); - vdev_error("Failed to parse '%s'\n", devbuf); - rc = -EIO; - } + if (rc != 0) + { - return rc; + vdev_error ("Failed to parse '%s'\n", devbuf); + rc = -EIO; + } + + return rc; } // read the kernel-given device subsystem from sysfs // return 0 on success, and set *subsystem // return -ENOMEM on OOM // return negative on readlink failure -static int vdev_linux_sysfs_read_subsystem(struct vdev_linux_context *ctx, - char const *devpath, - char **subsystem) +static int +vdev_linux_sysfs_read_subsystem (struct vdev_linux_context *ctx, + char const *devpath, char **subsystem) { - int rc = 0; - char linkpath[PATH_MAX + 1]; - size_t linkpath_len = PATH_MAX; - char *subsystem_path = NULL; + int rc = 0; + char linkpath[PATH_MAX + 1]; + size_t linkpath_len = PATH_MAX; + char *subsystem_path = NULL; - memset(linkpath, 0, PATH_MAX + 1); + memset (linkpath, 0, PATH_MAX + 1); - subsystem_path = - vdev_linux_sysfs_fullpath(ctx->sysfs_mountpoint, devpath, - "subsystem"); - if (subsystem_path == NULL) { - return -ENOMEM; - } + subsystem_path = + vdev_linux_sysfs_fullpath (ctx->sysfs_mountpoint, devpath, "subsystem"); + if (subsystem_path == NULL) + { + return -ENOMEM; + } - rc = readlink(subsystem_path, linkpath, linkpath_len); - if (rc < 0) { + rc = readlink (subsystem_path, linkpath, linkpath_len); + if (rc < 0) + { - rc = -errno; - vdev_error("readlink('%s') rc = %d\n", subsystem_path, rc); - free(subsystem_path); - return rc; - } + rc = -errno; + vdev_error ("readlink('%s') rc = %d\n", subsystem_path, rc); + free (subsystem_path); + return rc; + } - free(subsystem_path); + free (subsystem_path); - *subsystem = vdev_basename(linkpath, NULL); - if (*subsystem == NULL) { + *subsystem = vdev_basename (linkpath, NULL); + if (*subsystem == NULL) + { - return -ENOMEM; - } + return -ENOMEM; + } - return 0; + return 0; } // print a uevent, either with debugging or error loglevels -static int vdev_linux_log_uevent(char const *uevent_buf, size_t uevent_buf_len, - bool debug) +static int +vdev_linux_log_uevent (char const *uevent_buf, size_t uevent_buf_len, + bool debug) { - for (unsigned int i = 0; i < uevent_buf_len;) { + for (unsigned int i = 0; i < uevent_buf_len;) + { - if (debug) { - vdev_debug("uevent '%s'\n", uevent_buf + i); - } else { - vdev_error("uevent '%s'\n", uevent_buf + i); - } - - i += strlen(uevent_buf + i) + 1; + if (debug) + { + vdev_debug ("uevent '%s'\n", uevent_buf + i); + } + else + { + vdev_error ("uevent '%s'\n", uevent_buf + i); } - return 0; + i += strlen (uevent_buf + i) + 1; + } + + return 0; } #define vdev_linux_debug_uevent( uevent_buf, uevent_buf_len ) vdev_linux_log_uevent( uevent_buf, uevent_buf_len, true ) @@ -216,270 +236,299 @@ static int vdev_linux_log_uevent(char const *uevent_buf, size_t uevent_buf_len, // parse a uevent, and use the information to fill in a device request. // nlbuf must be a contiguous concatenation of null-terminated KEY=VALUE strings. // return 0 on success -static int vdev_linux_parse_request(struct vdev_linux_context *ctx, - struct vdev_device_request *vreq, - char *nlbuf, ssize_t buflen) +static int +vdev_linux_parse_request (struct vdev_linux_context *ctx, + struct vdev_device_request *vreq, + char *nlbuf, ssize_t buflen) { - char *buf = nlbuf; - char *key = NULL; - char *value = NULL; - int offset = 0; - int rc = 0; - unsigned int major = 0; - unsigned int minor = 0; - bool have_major = false; - bool have_minor = false; - mode_t dev_mode = 0; - int line_count = 0; - bool not_param = false; // if set to true, add as an OS-specific parameter to the vreq - - char *devpath = NULL; // sysfs devpath - char *subsystem = NULL; // sysfs subsystem - char *devname = (char *)VDEV_DEVICE_PATH_UNKNOWN; // DEVNAME from uevent - - vdev_device_request_t reqtype = VDEV_DEVICE_INVALID; - - vdev_debug("%p: uevent buffer\n", vreq); - vdev_linux_debug_uevent(nlbuf, buflen); - - // sanity check: if the first line is $action@$devpath, then skip it (since the information - // contained in the uevent will encode the very same bits of information) - if (strchr(buf, '@') != NULL) { - - // advance to the next line - offset += strlen(buf) + 1; - } - // get key/value pairs - while (offset < buflen) { + char *buf = nlbuf; + char *key = NULL; + char *value = NULL; + int offset = 0; + int rc = 0; + unsigned int major = 0; + unsigned int minor = 0; + bool have_major = false; + bool have_minor = false; + mode_t dev_mode = 0; + int line_count = 0; + bool not_param = false; // if set to true, add as an OS-specific parameter to the vreq - line_count++; - not_param = false; + char *devpath = NULL; // sysfs devpath + char *subsystem = NULL; // sysfs subsystem + char *devname = (char *) VDEV_DEVICE_PATH_UNKNOWN; // DEVNAME from uevent - rc = vdev_keyvalue_next(buf + offset, &key, &value); + vdev_device_request_t reqtype = VDEV_DEVICE_INVALID; - if (rc < 0) { + vdev_debug ("%p: uevent buffer\n", vreq); + vdev_linux_debug_uevent (nlbuf, buflen); - vdev_error("Invalid line %d (byte %d): '%s'\n", - line_count, offset, buf + offset); - vdev_linux_error_uevent(nlbuf, buflen); + // sanity check: if the first line is $action@$devpath, then skip it (since the information + // contained in the uevent will encode the very same bits of information) + if (strchr (buf, '@') != NULL) + { - return -EINVAL; - } + // advance to the next line + offset += strlen (buf) + 1; + } + // get key/value pairs + while (offset < buflen) + { - offset += rc + 1; // count the \0 at the end - rc = 0; + line_count++; + not_param = false; - // is this the action to take? - if (strcmp(key, "ACTION") == 0) { + rc = vdev_keyvalue_next (buf + offset, &key, &value); - reqtype = vdev_linux_parse_device_request_type(value); + if (rc < 0) + { - if (reqtype == VDEV_DEVICE_INVALID) { + vdev_error ("Invalid line %d (byte %d): '%s'\n", + line_count, offset, buf + offset); + vdev_linux_error_uevent (nlbuf, buflen); - vdev_error("Invalid ACTION '%s'\n", value); - vdev_linux_error_uevent(nlbuf, buflen); + return -EINVAL; + } - return -EINVAL; - } + offset += rc + 1; // count the \0 at the end + rc = 0; - vdev_device_request_set_type(vreq, reqtype); + // is this the action to take? + if (strcmp (key, "ACTION") == 0) + { - not_param = true; - } - // is this the sysfs device path? - else if (strcmp(key, "DEVPATH") == 0) { + reqtype = vdev_linux_parse_device_request_type (value); - devpath = value; - } - // is this the devname? - else if (strcmp(key, "DEVNAME") == 0) { + if (reqtype == VDEV_DEVICE_INVALID) + { - devname = value; - } - // subsystem given? - else if (strcmp(key, "SUBSYSTEM") == 0) { + vdev_error ("Invalid ACTION '%s'\n", value); + vdev_linux_error_uevent (nlbuf, buflen); - subsystem = vdev_strdup_or_null(value); - } - // is this the major device number? - else if (strcmp(key, "MAJOR") == 0 && !have_major) { + return -EINVAL; + } + + vdev_device_request_set_type (vreq, reqtype); - char *tmp = NULL; - major = (int)strtol(value, &tmp, 10); + not_param = true; + } + // is this the sysfs device path? + else if (strcmp (key, "DEVPATH") == 0) + { - if (*tmp != '\0') { + devpath = value; + } + // is this the devname? + else if (strcmp (key, "DEVNAME") == 0) + { - vdev_error("Invalid 'MAJOR' value '%s'\n", - value); - vdev_linux_error_uevent(nlbuf, buflen); + devname = value; + } + // subsystem given? + else if (strcmp (key, "SUBSYSTEM") == 0) + { - return -EINVAL; - } + subsystem = vdev_strdup_or_null (value); + } + // is this the major device number? + else if (strcmp (key, "MAJOR") == 0 && !have_major) + { - have_major = true; - not_param = true; - } - // is this the minor device number? - else if (strcmp(key, "MINOR") == 0 && !have_minor) { + char *tmp = NULL; + major = (int) strtol (value, &tmp, 10); - char *tmp = NULL; - minor = (int)strtol(value, &tmp, 10); + if (*tmp != '\0') + { - if (*tmp != '\0') { + vdev_error ("Invalid 'MAJOR' value '%s'\n", value); + vdev_linux_error_uevent (nlbuf, buflen); - vdev_error("Invalid 'MINOR' value '%s'\n", - value); - vdev_linux_error_uevent(nlbuf, buflen); + return -EINVAL; + } - return -EINVAL; - } + have_major = true; + not_param = true; + } + // is this the minor device number? + else if (strcmp (key, "MINOR") == 0 && !have_minor) + { - have_minor = true; - not_param = true; - } + char *tmp = NULL; + minor = (int) strtol (value, &tmp, 10); - if (!not_param) { + if (*tmp != '\0') + { - // add to OS params - rc = vdev_device_request_add_param(vreq, key, value); - if (rc != 0) { + vdev_error ("Invalid 'MINOR' value '%s'\n", value); + vdev_linux_error_uevent (nlbuf, buflen); - // could be OOM - if (subsystem != NULL) { - free(subsystem); - } + return -EINVAL; + } - return rc; - } - } + have_minor = true; + not_param = true; } - if (reqtype == VDEV_DEVICE_INVALID) { + if (!not_param) + { - vdev_error("%s", "No ACTION given\n"); - vdev_linux_error_uevent(nlbuf, buflen); + // add to OS params + rc = vdev_device_request_add_param (vreq, key, value); + if (rc != 0) + { - if (subsystem != NULL) { - free(subsystem); + // could be OOM + if (subsystem != NULL) + { + free (subsystem); } - return -EINVAL; + return rc; + } } + } - if ((!have_major && have_minor) || (have_major && !have_minor)) { - - vdev_error("Missing device information: major=%d, minor=%d\n", - have_major, have_minor); - vdev_linux_error_uevent(nlbuf, buflen); + if (reqtype == VDEV_DEVICE_INVALID) + { - if (subsystem != NULL) { - free(subsystem); - } + vdev_error ("%s", "No ACTION given\n"); + vdev_linux_error_uevent (nlbuf, buflen); - return -EINVAL; + if (subsystem != NULL) + { + free (subsystem); } - if (have_major && have_minor) { + return -EINVAL; + } - // explicit major and minor device numbers given - vdev_device_request_set_dev(vreq, makedev(major, minor)); - } + if ((!have_major && have_minor) || (have_major && !have_minor)) + { - if (devname != NULL) { + vdev_error ("Missing device information: major=%d, minor=%d\n", + have_major, have_minor); + vdev_linux_error_uevent (nlbuf, buflen); - // use this as the device's path - vdev_device_request_set_path(vreq, devname); + if (subsystem != NULL) + { + free (subsystem); } - if (devpath != NULL) { + return -EINVAL; + } - // get any remaining information from sysfs - // check major/minor? - if (!have_major || !have_minor) { + if (have_major && have_minor) + { - // see if we have major/minor device numbers for this device... - rc = vdev_linux_sysfs_read_dev_nums(ctx, devpath, - &major, &minor); + // explicit major and minor device numbers given + vdev_device_request_set_dev (vreq, makedev (major, minor)); + } - if (rc == 0) { + if (devname != NULL) + { - // yup! - vdev_device_request_set_dev(vreq, - makedev(major, - minor)); + // use this as the device's path + vdev_device_request_set_path (vreq, devname); + } - have_major = true; - have_minor = true; - } else { + if (devpath != NULL) + { - // it's okay to not have dev numbers - rc = 0; - } - } - // subsystem? - if (subsystem == NULL) { - - // see if we have a subsystem - rc = vdev_linux_sysfs_read_subsystem(ctx, devpath, - &subsystem); - - if (rc == 0) { - - // yup! - rc = vdev_device_request_add_param(vreq, - "SUBSYSTEM", - subsystem); - if (rc != 0) { - - // OOM - free(subsystem); - return rc; - } - } else if (rc != -ENOMEM) { - - // this is weird... - vdev_warn("no subsystem found for '%s'\n", - devpath); - rc = 0; - } - } - } + // get any remaining information from sysfs + // check major/minor? + if (!have_major || !have_minor) + { - if (have_major && have_minor) { + // see if we have major/minor device numbers for this device... + rc = vdev_linux_sysfs_read_dev_nums (ctx, devpath, &major, &minor); - if (subsystem != NULL && strcasecmp(subsystem, "block") == 0) { + if (rc == 0) + { - // this is a block - dev_mode = S_IFBLK; - } + // yup! + vdev_device_request_set_dev (vreq, makedev (major, minor)); + + have_major = true; + have_minor = true; + } + else + { + + // it's okay to not have dev numbers + rc = 0; + } + } + // subsystem? + if (subsystem == NULL) + { + + // see if we have a subsystem + rc = vdev_linux_sysfs_read_subsystem (ctx, devpath, &subsystem); + + if (rc == 0) + { - else { + // yup! + rc = vdev_device_request_add_param (vreq, + "SUBSYSTEM", subsystem); + if (rc != 0) + { - // this is a character device--we have major/minor numbers - dev_mode = S_IFCHR; + // OOM + free (subsystem); + return rc; } + } + else if (rc != -ENOMEM) + { - vdev_device_request_set_mode(vreq, dev_mode); + // this is weird... + vdev_warn ("no subsystem found for '%s'\n", devpath); + rc = 0; + } } + } - vdev_debug - ("subsystem = '%s', have_major=%d, major = %u, have_minor=%d, minor = %u, mode = %o\n", - subsystem, have_major, major, have_minor, minor, dev_mode); + if (have_major && have_minor) + { - if (subsystem != NULL) { - free(subsystem); + if (subsystem != NULL && strcasecmp (subsystem, "block") == 0) + { + + // this is a block + dev_mode = S_IFBLK; } - // tell helpers where /sys is mounted - rc = vdev_device_request_add_param(vreq, "SYSFS_MOUNTPOINT", - ctx->sysfs_mountpoint); - if (rc != 0) { - // OOM - return rc; + else + { + + // this is a character device--we have major/minor numbers + dev_mode = S_IFCHR; } - return rc; + vdev_device_request_set_mode (vreq, dev_mode); + } + + vdev_debug + ("subsystem = '%s', have_major=%d, major = %u, have_minor=%d, minor = %u, mode = %o\n", + subsystem, have_major, major, have_minor, minor, dev_mode); + + if (subsystem != NULL) + { + free (subsystem); + } + // tell helpers where /sys is mounted + rc = vdev_device_request_add_param (vreq, "SYSFS_MOUNTPOINT", + ctx->sysfs_mountpoint); + if (rc != 0) + { + + // OOM + return rc; + } + + return rc; } // yield the next device event @@ -487,147 +536,163 @@ static int vdev_linux_parse_request(struct vdev_linux_context *ctx, // return 1 if there are no more devices // return -EAGAIN if vdev should try to get this device again // return -errno on failure to poll for devices or read the next device packet. -int vdev_os_next_device(struct vdev_device_request *vreq, void *cls) +int +vdev_os_next_device (struct vdev_device_request *vreq, void *cls) { - int rc = 0; - struct vdev_linux_context *ctx = (struct vdev_linux_context *)cls; - char buf[VDEV_LINUX_NETLINK_BUF_MAX]; - ssize_t len = 0; - - char cbuf[CMSG_SPACE(sizeof(struct ucred))]; - struct cmsghdr *chdr = NULL; - struct ucred *cred = NULL; - struct msghdr hdr; - struct iovec iov; - struct sockaddr_nl cnls; + int rc = 0; + struct vdev_linux_context *ctx = (struct vdev_linux_context *) cls; + char buf[VDEV_LINUX_NETLINK_BUF_MAX]; + ssize_t len = 0; - pthread_mutex_lock(&ctx->initial_requests_lock); + char cbuf[CMSG_SPACE (sizeof (struct ucred))]; + struct cmsghdr *chdr = NULL; + struct ucred *cred = NULL; + struct msghdr hdr; + struct iovec iov; + struct sockaddr_nl cnls; - // do we have initial requests? - if (ctx->initial_requests != NULL) { + pthread_mutex_lock (&ctx->initial_requests_lock); - // next request - struct vdev_device_request *req = ctx->initial_requests; + // do we have initial requests? + if (ctx->initial_requests != NULL) + { - // consume - ctx->initial_requests = ctx->initial_requests->next; + // next request + struct vdev_device_request *req = ctx->initial_requests; - memcpy(vreq, req, sizeof(struct vdev_device_request)); - free(req); + // consume + ctx->initial_requests = ctx->initial_requests->next; - pthread_mutex_unlock(&ctx->initial_requests_lock); + memcpy (vreq, req, sizeof (struct vdev_device_request)); + free (req); - // was that the last of them? - if (ctx->initial_requests == NULL) { - - // tell vdevd that we've finished coldplug processing - vdev_os_context_signal_coldplug_finished(ctx->os_ctx); - } + pthread_mutex_unlock (&ctx->initial_requests_lock); - return 0; - } else if (ctx->os_ctx->coldplug_only) { + // was that the last of them? + if (ctx->initial_requests == NULL) + { - // out of coldplug requests; die - pthread_mutex_unlock(&ctx->initial_requests_lock); - return 1; - } else { - - pthread_mutex_unlock(&ctx->initial_requests_lock); + // tell vdevd that we've finished coldplug processing + vdev_os_context_signal_coldplug_finished (ctx->os_ctx); } - memset(&hdr, 0, sizeof(struct msghdr)); + return 0; + } + else if (ctx->os_ctx->coldplug_only) + { + + // out of coldplug requests; die + pthread_mutex_unlock (&ctx->initial_requests_lock); + return 1; + } + else + { - // next event (wait forever) - // NOTE: this is a cancellation point! - rc = poll(&ctx->pfd, 1, -1); + pthread_mutex_unlock (&ctx->initial_requests_lock); + } - if (rc < 0) { + memset (&hdr, 0, sizeof (struct msghdr)); - rc = -errno; + // next event (wait forever) + // NOTE: this is a cancellation point! + rc = poll (&ctx->pfd, 1, -1); - if (rc == -EINTR) { - // try again - return -EAGAIN; - } + if (rc < 0) + { - vdev_error("FATAL: poll(%d) rc = %d\n", ctx->pfd.fd, rc); + rc = -errno; - return rc; + if (rc == -EINTR) + { + // try again + return -EAGAIN; } - // get the event - iov.iov_base = buf; - iov.iov_len = VDEV_LINUX_NETLINK_BUF_MAX; - hdr.msg_iov = &iov; - hdr.msg_iovlen = 1; + vdev_error ("FATAL: poll(%d) rc = %d\n", ctx->pfd.fd, rc); - // get control-plane messages - hdr.msg_control = cbuf; - hdr.msg_controllen = sizeof(cbuf); + return rc; + } + // get the event + iov.iov_base = buf; + iov.iov_len = VDEV_LINUX_NETLINK_BUF_MAX; - hdr.msg_name = &cnls; - hdr.msg_namelen = sizeof(cnls); + hdr.msg_iov = &iov; + hdr.msg_iovlen = 1; - // get the event - len = recvmsg(ctx->pfd.fd, &hdr, 0); - if (len < 0) { + // get control-plane messages + hdr.msg_control = cbuf; + hdr.msg_controllen = sizeof (cbuf); - rc = -errno; - vdev_error("FATAL: recvmsg(%d) rc = %d\n", ctx->pfd.fd, rc); + hdr.msg_name = &cnls; + hdr.msg_namelen = sizeof (cnls); - return rc; - } - // big enough? - if (len < 32 || len >= VDEV_LINUX_NETLINK_BUF_MAX) { + // get the event + len = recvmsg (ctx->pfd.fd, &hdr, 0); + if (len < 0) + { - vdev_error("Netlink message is %zd bytes; ignoring...\n", len); - return -EAGAIN; - } - // control message, for credentials - chdr = CMSG_FIRSTHDR(&hdr); - if (chdr == NULL || chdr->cmsg_type != SCM_CREDENTIALS) { + rc = -errno; + vdev_error ("FATAL: recvmsg(%d) rc = %d\n", ctx->pfd.fd, rc); - vdev_error("%s", "Netlink message has no credentials\n"); - return -EAGAIN; - } - // get the credentials - cred = (struct ucred *)CMSG_DATA(chdr); + return rc; + } + // big enough? + if (len < 32 || len >= VDEV_LINUX_NETLINK_BUF_MAX) + { + + vdev_error ("Netlink message is %zd bytes; ignoring...\n", len); + return -EAGAIN; + } + // control message, for credentials + chdr = CMSG_FIRSTHDR (&hdr); + if (chdr == NULL || chdr->cmsg_type != SCM_CREDENTIALS) + { - // if not root, ignore - if (cred->uid != 0) { + vdev_error ("%s", "Netlink message has no credentials\n"); + return -EAGAIN; + } + // get the credentials + cred = (struct ucred *) CMSG_DATA (chdr); - vdev_error("Ignoring message from non-root ID %d\n", cred->uid); - return -EAGAIN; - } - // if udev, ignore - if (memcmp - (buf, VDEV_LINUX_NETLINK_UDEV_HEADER, - VDEV_LINUX_NETLINK_UDEV_HEADER_LEN) == 0) { - - // message from udev; ignore - vdev_warn("%s", "Ignoring libudev message\n"); - return -EAGAIN; - } - // kernel messages don't come from userspace - if (cnls.nl_pid > 0) { - - // from userspace??? - vdev_warn("Ignoring message from PID %d\n", (int)cnls.nl_pid); - return -EAGAIN; - } - // parse the event buffer - vdev_debug("%p from netlink\n", vreq); - rc = vdev_linux_parse_request(ctx, vreq, buf, len); + // if not root, ignore + if (cred->uid != 0) + { - if (rc != 0) { - - vdev_error("vdev_linux_parse_request rc = %d\n", rc); - - return -EAGAIN; - } - - return 0; + vdev_error ("Ignoring message from non-root ID %d\n", cred->uid); + return -EAGAIN; + } + // if udev, ignore + if (memcmp + (buf, VDEV_LINUX_NETLINK_UDEV_HEADER, + VDEV_LINUX_NETLINK_UDEV_HEADER_LEN) == 0) + { + + // message from udev; ignore + vdev_warn ("%s", "Ignoring libudev message\n"); + return -EAGAIN; + } + // kernel messages don't come from userspace + if (cnls.nl_pid > 0) + { + + // from userspace??? + vdev_warn ("Ignoring message from PID %d\n", (int) cnls.nl_pid); + return -EAGAIN; + } + // parse the event buffer + vdev_debug ("%p from netlink\n", vreq); + rc = vdev_linux_parse_request (ctx, vreq, buf, len); + + if (rc != 0) + { + + vdev_error ("vdev_linux_parse_request rc = %d\n", rc); + + return -EAGAIN; + } + + return 0; } // find sysfs mountpoint in /proc/mounts @@ -638,60 +703,63 @@ int vdev_os_next_device(struct vdev_device_request *vreq, void *cls) // return -ENOMEM if the buffer isn't big enough // return -EINVAL if somehow we failed to parse a mount entry // return negative for some other errors (like access permission failures, or /proc not mounted) -static int vdev_linux_find_sysfs_mountpoint(char *mountpoint, - size_t mountpoint_len) +static int +vdev_linux_find_sysfs_mountpoint (char *mountpoint, size_t mountpoint_len) { - FILE *f = NULL; - int rc = 0; + FILE *f = NULL; + int rc = 0; - char mntbuf[4096]; - struct mntent ment_buf; - struct mntent *ment_ptr = NULL; - int ent_count = 1; - bool found = false; + char mntbuf[4096]; + struct mntent ment_buf; + struct mntent *ment_ptr = NULL; + int ent_count = 1; + bool found = false; - f = fopen("/proc/mounts", "r"); - if (f == NULL) { + f = fopen ("/proc/mounts", "r"); + if (f == NULL) + { - rc = -errno; - fprintf(stderr, "Failed to open /proc/mounts, rc = %d\n", rc); - return rc; - } - // scan for sysfs mount type - while (1) { + rc = -errno; + fprintf (stderr, "Failed to open /proc/mounts, rc = %d\n", rc); + return rc; + } + // scan for sysfs mount type + while (1) + { - ment_ptr = getmntent_r(f, &ment_buf, mntbuf, 4096); - if (ment_ptr == NULL) { + ment_ptr = getmntent_r (f, &ment_buf, mntbuf, 4096); + if (ment_ptr == NULL) + { - vdev_error - ("Failed on processing entry #%d of /proc/mounts\n", - ent_count); - rc = -EINVAL; - break; - } + vdev_error + ("Failed on processing entry #%d of /proc/mounts\n", ent_count); + rc = -EINVAL; + break; + } - if (strcmp(ment_ptr->mnt_type, "sysfs") == 0) { + if (strcmp (ment_ptr->mnt_type, "sysfs") == 0) + { - // found! - strncpy(mountpoint, ment_ptr->mnt_dir, - mountpoint_len - 1); - found = true; - rc = 0; - break; - } - - ent_count++; + // found! + strncpy (mountpoint, ment_ptr->mnt_dir, mountpoint_len - 1); + found = true; + rc = 0; + break; } - fclose(f); + ent_count++; + } - if (rc == 0 && !found) { - fprintf(stderr, "Failed to find mounted sysfs filesystem\n"); - return -ENOSYS; - } + fclose (f); + + if (rc == 0 && !found) + { + fprintf (stderr, "Failed to find mounted sysfs filesystem\n"); + return -ENOSYS; + } - return rc; + return rc; } // get a uevent from a uevent file @@ -700,120 +768,132 @@ static int vdev_linux_find_sysfs_mountpoint(char *mountpoint, // return 0 on success // return -ENOMEM on OOM // return -errno on failure to stat or read -static int vdev_linux_sysfs_read_uevent(char const *fp_uevent, - char **ret_uevent_buf, - size_t * ret_uevent_len) +static int +vdev_linux_sysfs_read_uevent (char const *fp_uevent, + char **ret_uevent_buf, size_t * ret_uevent_len) { - int rc = 0; - struct stat sb; - char *uevent_buf = NULL; - size_t uevent_buf_len = 0; - size_t uevent_len = 0; + int rc = 0; + struct stat sb; + char *uevent_buf = NULL; + size_t uevent_buf_len = 0; + size_t uevent_len = 0; - // get uevent size - rc = stat(fp_uevent, &sb); - if (rc != 0) { + // get uevent size + rc = stat (fp_uevent, &sb); + if (rc != 0) + { - rc = -errno; + rc = -errno; - vdev_error("stat('%s') rc = %d\n", fp_uevent, rc); + vdev_error ("stat('%s') rc = %d\n", fp_uevent, rc); - return rc; - } else { + return rc; + } + else + { - uevent_buf_len = sb.st_size; - } + uevent_buf_len = sb.st_size; + } - // read the uevent - if (fp_uevent != NULL) { + // read the uevent + if (fp_uevent != NULL) + { - uevent_buf = VDEV_CALLOC(char, uevent_buf_len); - if (uevent_buf == NULL) { + uevent_buf = VDEV_CALLOC (char, uevent_buf_len); + if (uevent_buf == NULL) + { - return -ENOMEM; - } + return -ENOMEM; + } - rc = vdev_read_file(fp_uevent, uevent_buf, uevent_buf_len); - if (rc != 0) { + rc = vdev_read_file (fp_uevent, uevent_buf, uevent_buf_len); + if (rc != 0) + { - // failed in this - vdev_error("vdev_read_file('%s') rc = %d\n", fp_uevent, - rc); - free(uevent_buf); - } else { + // failed in this + vdev_error ("vdev_read_file('%s') rc = %d\n", fp_uevent, rc); + free (uevent_buf); + } + else + { - for (unsigned int i = 0; i < uevent_buf_len; i++) { + for (unsigned int i = 0; i < uevent_buf_len; i++) + { - if (uevent_buf[i] == '\n') { + if (uevent_buf[i] == '\n') + { - uevent_buf[i] = '\0'; - } - } + uevent_buf[i] = '\0'; + } + } - // NOTE: the stat size is an upper-bound. Find the exact number of bytes. - for (uevent_len = 0; uevent_len < uevent_buf_len;) { + // NOTE: the stat size is an upper-bound. Find the exact number of bytes. + for (uevent_len = 0; uevent_len < uevent_buf_len;) + { - if (*(uevent_buf + uevent_len) == '\0') { - break; - } + if (*(uevent_buf + uevent_len) == '\0') + { + break; + } - uevent_len += - strlen(uevent_buf + uevent_len) + 1; - } + uevent_len += strlen (uevent_buf + uevent_len) + 1; + } - *ret_uevent_buf = uevent_buf; - *ret_uevent_len = uevent_len; - } + *ret_uevent_buf = uevent_buf; + *ret_uevent_len = uevent_len; } + } - return rc; + return rc; } // append a key/value pair to a uevent buffer // return 0 on success // return -ENOMEM on OOM -static int vdev_linux_uevent_append(char **ret_uevent_buf, - size_t * ret_uevent_buf_len, - char const *key, char const *value) +static int +vdev_linux_uevent_append (char **ret_uevent_buf, + size_t * ret_uevent_buf_len, + char const *key, char const *value) { - char *tmp = NULL; - char *uevent_buf = *ret_uevent_buf; - size_t uevent_buf_len = *ret_uevent_buf_len; + char *tmp = NULL; + char *uevent_buf = *ret_uevent_buf; + size_t uevent_buf_len = *ret_uevent_buf_len; - // add it to the uevent buffer, so we can parse it like a normal uevent - tmp = - (char *)realloc(uevent_buf, - uevent_buf_len + 1 + strlen(key) + 1 + - strlen(value) + 1); - if (tmp == NULL) { + // add it to the uevent buffer, so we can parse it like a normal uevent + tmp = + (char *) realloc (uevent_buf, + uevent_buf_len + 1 + strlen (key) + 1 + + strlen (value) + 1); + if (tmp == NULL) + { - return -ENOMEM; - } + return -ENOMEM; + } - uevent_buf = tmp; + uevent_buf = tmp; - // add key - memcpy(uevent_buf + uevent_buf_len, key, strlen(key)); - uevent_buf_len += strlen(key); + // add key + memcpy (uevent_buf + uevent_buf_len, key, strlen (key)); + uevent_buf_len += strlen (key); - // add '=' - *(uevent_buf + uevent_buf_len) = '='; - uevent_buf_len++; + // add '=' + *(uevent_buf + uevent_buf_len) = '='; + uevent_buf_len++; - // add value - memcpy(uevent_buf + uevent_buf_len, value, strlen(value)); - uevent_buf_len += strlen(value); + // add value + memcpy (uevent_buf + uevent_buf_len, value, strlen (value)); + uevent_buf_len += strlen (value); - // NULL-terminate - *(uevent_buf + uevent_buf_len) = '\0'; - uevent_buf_len++; + // NULL-terminate + *(uevent_buf + uevent_buf_len) = '\0'; + uevent_buf_len++; - *ret_uevent_buf = uevent_buf; - *ret_uevent_buf_len = uevent_buf_len; + *ret_uevent_buf = uevent_buf; + *ret_uevent_buf_len = uevent_buf_len; - return 0; + return 0; } // register a device from sysfs, given the path to its uevent file. @@ -822,712 +902,771 @@ static int vdev_linux_uevent_append(char **ret_uevent_buf, // return 0 on success // return -ENOMEM on OOM // return negative on error. -static int vdev_linux_sysfs_register_device(struct vdev_linux_context *ctx, - char const *fp_uevent) +static int +vdev_linux_sysfs_register_device (struct vdev_linux_context *ctx, + char const *fp_uevent) { - int rc = 0; - struct stat sb; - char *uevent_buf = NULL; - size_t uevent_buf_len = 0; - char *full_devpath = NULL; - char *devpath = NULL; - char *devname = NULL; - char *delim = NULL; - - // extract the devpath from the uevent path - full_devpath = vdev_dirname(fp_uevent, NULL); - if (full_devpath == NULL) { - return -ENOMEM; - } - // get uevent - rc = vdev_linux_sysfs_read_uevent(fp_uevent, &uevent_buf, - &uevent_buf_len); - if (rc != 0) { + int rc = 0; + struct stat sb; + char *uevent_buf = NULL; + size_t uevent_buf_len = 0; + char *full_devpath = NULL; + char *devpath = NULL; + char *devname = NULL; + char *delim = NULL; + + // extract the devpath from the uevent path + full_devpath = vdev_dirname (fp_uevent, NULL); + if (full_devpath == NULL) + { + return -ENOMEM; + } + // get uevent + rc = vdev_linux_sysfs_read_uevent (fp_uevent, &uevent_buf, &uevent_buf_len); + if (rc != 0) + { + + vdev_error ("vdev_linux_sysfs_read_uevent('%s') rc = %d\n", + fp_uevent, rc); + + free (full_devpath); + return rc; + } + + if (uevent_buf_len == 0) + { - vdev_error("vdev_linux_sysfs_read_uevent('%s') rc = %d\n", - fp_uevent, rc); + // no messages to be had + vdev_debug ("Empty uevent file at '%s'\n", fp_uevent); - free(full_devpath); - return rc; - } + free (full_devpath); + free (uevent_buf); + return 0; + } + // truncate to /devices + devpath = full_devpath + strlen (ctx->sysfs_mountpoint); - if (uevent_buf_len == 0) { + // we're adding this, so make ACTION=add + rc = vdev_linux_uevent_append (&uevent_buf, &uevent_buf_len, "ACTION", + "add"); + if (rc != 0) + { - // no messages to be had - vdev_debug("Empty uevent file at '%s'\n", fp_uevent); + vdev_error ("vdev_linux_uevent_append('%s=%s') rc = %d\n", + "ACTION", "add", rc); - free(full_devpath); - free(uevent_buf); - return 0; - } - // truncate to /devices - devpath = full_devpath + strlen(ctx->sysfs_mountpoint); + free (uevent_buf); + free (full_devpath); - // we're adding this, so make ACTION=add - rc = vdev_linux_uevent_append(&uevent_buf, &uevent_buf_len, "ACTION", - "add"); - if (rc != 0) { + return rc; + } - vdev_error("vdev_linux_uevent_append('%s=%s') rc = %d\n", - "ACTION", "add", rc); + // see if the uevent has a devname. Use that over our devname, if need be + devname = strstr (uevent_buf, "DEVNAME="); + if (devname != NULL) + { - free(uevent_buf); - free(full_devpath); + // have a devname! + devname += strlen ("DEVNAME=") + 1; - return rc; - } + size_t devname_len = strcspn (devname, "\n\0"); + if (devname_len > 0) + { - // see if the uevent has a devname. Use that over our devname, if need be - devname = strstr(uevent_buf, "DEVNAME="); - if (devname != NULL) { + char *tmp = VDEV_CALLOC (char, devname_len + 1); + if (tmp == NULL) + { - // have a devname! - devname += strlen("DEVNAME=") + 1; + free (uevent_buf); + free (full_devpath); - size_t devname_len = strcspn(devname, "\n\0"); - if (devname_len > 0) { + return -ENOMEM; + } - char *tmp = VDEV_CALLOC(char, devname_len + 1); - if (tmp == NULL) { + strncpy (tmp, devname, devname_len); - free(uevent_buf); - free(full_devpath); + devname = tmp; + } + } + // include the device path + rc = vdev_linux_uevent_append (&uevent_buf, &uevent_buf_len, "DEVPATH", + devpath); + if (rc != 0) + { - return -ENOMEM; - } + vdev_error ("vdev_linux_uevent_append('%s=%s') rc = %d\n", + "DEVPATH", devpath, rc); - strncpy(tmp, devname, devname_len); + free (uevent_buf); + free (full_devpath); + free (devname); + return rc; + } - devname = tmp; - } - } - // include the device path - rc = vdev_linux_uevent_append(&uevent_buf, &uevent_buf_len, "DEVPATH", - devpath); - if (rc != 0) { - - vdev_error("vdev_linux_uevent_append('%s=%s') rc = %d\n", - "DEVPATH", devpath, rc); - - free(uevent_buf); - free(full_devpath); - free(devname); - return rc; - } + // make the device request + struct vdev_device_request *vreq = + VDEV_CALLOC (struct vdev_device_request, 1); + if (vreq == NULL) + { - // make the device request - struct vdev_device_request *vreq = - VDEV_CALLOC(struct vdev_device_request, 1); - if (vreq == NULL) { + free (full_devpath); + free (uevent_buf); - free(full_devpath); - free(uevent_buf); + return -ENOMEM; + } + // build up the request + vdev_device_request_init (vreq, ctx->os_ctx->state, VDEV_DEVICE_INVALID, + devname); - return -ENOMEM; - } - // build up the request - vdev_device_request_init(vreq, ctx->os_ctx->state, VDEV_DEVICE_INVALID, - devname); + // parse from our uevent + rc = vdev_linux_parse_request (ctx, vreq, uevent_buf, uevent_buf_len); - // parse from our uevent - rc = vdev_linux_parse_request(ctx, vreq, uevent_buf, uevent_buf_len); + free (uevent_buf); + uevent_buf = NULL; - free(uevent_buf); - uevent_buf = NULL; + if (rc != 0) + { - if (rc != 0) { + vdev_error ("vdev_linux_parse_request('%s') rc = %d\n", fp_uevent, rc); - vdev_error("vdev_linux_parse_request('%s') rc = %d\n", - fp_uevent, rc); + free (full_devpath); + free (devname); - free(full_devpath); - free(devname); + return rc; + } - return rc; - } + free (full_devpath); + free (devname); - free(full_devpath); - free(devname); + pthread_mutex_lock (&ctx->initial_requests_lock); - pthread_mutex_lock(&ctx->initial_requests_lock); + // append + if (ctx->initial_requests == NULL) + { - // append - if (ctx->initial_requests == NULL) { + ctx->initial_requests = vreq; + ctx->initial_requests_tail = vreq; + } + else + { - ctx->initial_requests = vreq; - ctx->initial_requests_tail = vreq; - } else { - - ctx->initial_requests_tail->next = vreq; - ctx->initial_requests_tail = vreq; - } + ctx->initial_requests_tail->next = vreq; + ctx->initial_requests_tail = vreq; + } - vreq->next = NULL; + vreq->next = NULL; - pthread_mutex_unlock(&ctx->initial_requests_lock); + pthread_mutex_unlock (&ctx->initial_requests_lock); - return rc; + return rc; } // scan structure for finding new device directories, and signalling whether or not // the given directory has a uevent. -struct vdev_linux_sysfs_scan_context { +struct vdev_linux_sysfs_scan_context +{ - char *uevent_path; - struct sglib_cstr_vector *device_frontier; + char *uevent_path; + struct sglib_cstr_vector *device_frontier; }; // scan a directory in /sys/devices directory, to find its child directories // return 0 on success // return -ENOMEM on OOM // return -errno on failure to stat -static int vdev_linux_sysfs_scan_device_directory(char const *fp, void *cls) +static int +vdev_linux_sysfs_scan_device_directory (char const *fp, void *cls) { - struct vdev_linux_sysfs_scan_context *scan_ctx = - (struct vdev_linux_sysfs_scan_context *)cls; + struct vdev_linux_sysfs_scan_context *scan_ctx = + (struct vdev_linux_sysfs_scan_context *) cls; - struct sglib_cstr_vector *device_frontier = scan_ctx->device_frontier; + struct sglib_cstr_vector *device_frontier = scan_ctx->device_frontier; - struct stat sb; - int rc = 0; - char *fp_base = NULL; - char *fp_dup = NULL; + struct stat sb; + int rc = 0; + char *fp_base = NULL; + char *fp_dup = NULL; - fp_base = rindex(fp, '/'); + fp_base = rindex (fp, '/'); - if (fp_base == NULL) { - return 0; - } - // skip . and .. - if (strcmp(fp_base, "/.") == 0 || strcmp(fp_base, "/..") == 0) { - return 0; - } - // add directories - rc = lstat(fp, &sb); - if (rc != 0) { + if (fp_base == NULL) + { + return 0; + } + // skip . and .. + if (strcmp (fp_base, "/.") == 0 || strcmp (fp_base, "/..") == 0) + { + return 0; + } + // add directories + rc = lstat (fp, &sb); + if (rc != 0) + { - rc = -errno; - vdev_error("lstat('%s') rc = %d\n", fp, rc); - return rc; - } + rc = -errno; + vdev_error ("lstat('%s') rc = %d\n", fp, rc); + return rc; + } - if (!S_ISDIR(sb.st_mode) && strcmp(fp_base, "/uevent") != 0) { + if (!S_ISDIR (sb.st_mode) && strcmp (fp_base, "/uevent") != 0) + { - // not a directory, and not a uevent - return 0; - } - - fp_dup = vdev_strdup_or_null(fp); - if (fp_dup == NULL) { + // not a directory, and not a uevent + return 0; + } - return -ENOMEM; - } + fp_dup = vdev_strdup_or_null (fp); + if (fp_dup == NULL) + { - if (S_ISDIR(sb.st_mode)) { + return -ENOMEM; + } - vdev_debug("Search '%s'\n", fp_dup); + if (S_ISDIR (sb.st_mode)) + { - rc = sglib_cstr_vector_push_back(device_frontier, fp_dup); - if (rc != 0) { + vdev_debug ("Search '%s'\n", fp_dup); - free(fp_dup); - return rc; - } - } else { + rc = sglib_cstr_vector_push_back (device_frontier, fp_dup); + if (rc != 0) + { - // this is a uevent; this directory is a device - vdev_debug("Uevent '%s'\n", fp_dup); - scan_ctx->uevent_path = fp_dup; + free (fp_dup); + return rc; } + } + else + { - return 0; + // this is a uevent; this directory is a device + vdev_debug ("Uevent '%s'\n", fp_dup); + scan_ctx->uevent_path = fp_dup; + } + + return 0; } // read all devices from sysfs, and put their uevent paths into the given uevent_paths. // scan in breadth-first order, so we find and process parent devices before their child devices. // return 0 on success // return negative on error -static int vdev_linux_sysfs_find_devices(struct vdev_linux_context *ctx, - struct sglib_cstr_vector *uevent_paths) +static int +vdev_linux_sysfs_find_devices (struct vdev_linux_context *ctx, + struct sglib_cstr_vector *uevent_paths) { - int rc = 0; - - // find all directories that have a 'uevent' file in them - struct sglib_cstr_vector device_frontier; - sglib_cstr_vector_init(&device_frontier); + int rc = 0; - struct vdev_linux_sysfs_scan_context scan_context; - memset(&scan_context, 0, sizeof(struct vdev_linux_sysfs_scan_context)); + // find all directories that have a 'uevent' file in them + struct sglib_cstr_vector device_frontier; + sglib_cstr_vector_init (&device_frontier); - scan_context.device_frontier = &device_frontier; + struct vdev_linux_sysfs_scan_context scan_context; + memset (&scan_context, 0, sizeof (struct vdev_linux_sysfs_scan_context)); - char *device_root = NULL; + scan_context.device_frontier = &device_frontier; - // scan /sys/devices - device_root = vdev_fullpath(ctx->sysfs_mountpoint, "/devices", NULL); - if (device_root == NULL) { + char *device_root = NULL; - return -ENOMEM; - } + // scan /sys/devices + device_root = vdev_fullpath (ctx->sysfs_mountpoint, "/devices", NULL); + if (device_root == NULL) + { - rc = vdev_load_all(device_root, vdev_linux_sysfs_scan_device_directory, - &scan_context); - if (rc != 0) { + return -ENOMEM; + } - vdev_error("vdev_load_all('%s') rc = %d\n", device_root, rc); + rc = vdev_load_all (device_root, vdev_linux_sysfs_scan_device_directory, + &scan_context); + if (rc != 0) + { - free(device_root); + vdev_error ("vdev_load_all('%s') rc = %d\n", device_root, rc); - sglib_cstr_vector_free(&device_frontier); + free (device_root); - return rc; - } + sglib_cstr_vector_free (&device_frontier); - free(device_root); + return rc; + } - while (1) { + free (device_root); - unsigned long len = sglib_cstr_vector_size(&device_frontier); + while (1) + { - if (len == 0) { - break; - } + unsigned long len = sglib_cstr_vector_size (&device_frontier); - device_root = sglib_cstr_vector_at(&device_frontier, len - 1); - sglib_cstr_vector_set(&device_frontier, NULL, len - 1); + if (len == 0) + { + break; + } - sglib_cstr_vector_pop_back(&device_frontier); + device_root = sglib_cstr_vector_at (&device_frontier, len - 1); + sglib_cstr_vector_set (&device_frontier, NULL, len - 1); - // scan for more devices - rc = vdev_load_all(device_root, - vdev_linux_sysfs_scan_device_directory, - &scan_context); - if (rc != 0) { + sglib_cstr_vector_pop_back (&device_frontier); - vdev_error("vdev_load_all('%s') rc = %d\n", device_root, - rc); - free(device_root); - break; - } - // is one of them a uevent? - if (scan_context.uevent_path != NULL) { + // scan for more devices + rc = vdev_load_all (device_root, + vdev_linux_sysfs_scan_device_directory, + &scan_context); + if (rc != 0) + { - // yup--remember it - char *uevent_path = - vdev_strdup_or_null(scan_context.uevent_path); + vdev_error ("vdev_load_all('%s') rc = %d\n", device_root, rc); + free (device_root); + break; + } + // is one of them a uevent? + if (scan_context.uevent_path != NULL) + { - if (uevent_path == NULL) { + // yup--remember it + char *uevent_path = vdev_strdup_or_null (scan_context.uevent_path); - free(device_root); - free(scan_context.uevent_path); - scan_context.uevent_path = NULL; + if (uevent_path == NULL) + { - rc = -ENOMEM; - break; - } + free (device_root); + free (scan_context.uevent_path); + scan_context.uevent_path = NULL; - rc = sglib_cstr_vector_push_back(uevent_paths, - uevent_path); - if (rc < 0) { + rc = -ENOMEM; + break; + } - free(uevent_path); - free(device_root); - free(scan_context.uevent_path); - scan_context.uevent_path = NULL; + rc = sglib_cstr_vector_push_back (uevent_paths, uevent_path); + if (rc < 0) + { - break; - } + free (uevent_path); + free (device_root); + free (scan_context.uevent_path); + scan_context.uevent_path = NULL; - free(scan_context.uevent_path); - scan_context.uevent_path = NULL; - } + break; + } - free(device_root); + free (scan_context.uevent_path); + scan_context.uevent_path = NULL; } - sglib_cstr_vector_free(&device_frontier); + free (device_root); + } - return rc; + sglib_cstr_vector_free (&device_frontier); + + return rc; } // free a list of cstr vectors // always succeeds -static int vdev_cstr_vector_free_all(struct sglib_cstr_vector *vec) +static int +vdev_cstr_vector_free_all (struct sglib_cstr_vector *vec) { - // free all strings - for (unsigned long i = 0; i < sglib_cstr_vector_size(vec); i++) { + // free all strings + for (unsigned long i = 0; i < sglib_cstr_vector_size (vec); i++) + { - if (sglib_cstr_vector_at(vec, i) != NULL) { + if (sglib_cstr_vector_at (vec, i) != NULL) + { - free(sglib_cstr_vector_at(vec, i)); - sglib_cstr_vector_set(vec, NULL, i); - } + free (sglib_cstr_vector_at (vec, i)); + sglib_cstr_vector_set (vec, NULL, i); } + } - return 0; + return 0; } // register all devices, given a vector to their uevent files // return 0 on success // return negative on error -static int vdev_linux_sysfs_register_devices(struct vdev_linux_context *ctx) +static int +vdev_linux_sysfs_register_devices (struct vdev_linux_context *ctx) { - int rc = 0; - struct sglib_cstr_vector uevent_paths; + int rc = 0; + struct sglib_cstr_vector uevent_paths; - sglib_cstr_vector_init(&uevent_paths); + sglib_cstr_vector_init (&uevent_paths); - // scan devices - rc = vdev_linux_sysfs_find_devices(ctx, &uevent_paths); - if (rc != 0) { + // scan devices + rc = vdev_linux_sysfs_find_devices (ctx, &uevent_paths); + if (rc != 0) + { - vdev_error("vdev_linux_sysfs_find_devices() rc = %d\n", rc); + vdev_error ("vdev_linux_sysfs_find_devices() rc = %d\n", rc); - vdev_cstr_vector_free_all(&uevent_paths); - sglib_cstr_vector_free(&uevent_paths); - return rc; - } - // process all devices - for (unsigned long i = 0; i < sglib_cstr_vector_size(&uevent_paths); - i++) { + vdev_cstr_vector_free_all (&uevent_paths); + sglib_cstr_vector_free (&uevent_paths); + return rc; + } + // process all devices + for (unsigned long i = 0; i < sglib_cstr_vector_size (&uevent_paths); i++) + { - char *uevent_path = sglib_cstr_vector_at(&uevent_paths, i); + char *uevent_path = sglib_cstr_vector_at (&uevent_paths, i); - // skip filtered entries - if (uevent_path == NULL) { - continue; - } + // skip filtered entries + if (uevent_path == NULL) + { + continue; + } - vdev_debug("Register device '%s'\n", uevent_path); - rc = vdev_linux_sysfs_register_device(ctx, uevent_path); - if (rc != 0) { + vdev_debug ("Register device '%s'\n", uevent_path); + rc = vdev_linux_sysfs_register_device (ctx, uevent_path); + if (rc != 0) + { - vdev_error - ("vdev_linux_sysfs_register_device('%s') rc = %d\n", - uevent_path, rc); - continue; - } + vdev_error + ("vdev_linux_sysfs_register_device('%s') rc = %d\n", + uevent_path, rc); + continue; } + } - // free all paths - vdev_cstr_vector_free_all(&uevent_paths); - sglib_cstr_vector_free(&uevent_paths); + // free all paths + vdev_cstr_vector_free_all (&uevent_paths); + sglib_cstr_vector_free (&uevent_paths); - return rc; + return rc; } // start listening for kernel events via netlink // only do so if we're *NOT* going to run once (check the config) // return 0 on success // return -errno on error (failure to socket(2), setsockopt(2), bind(2), or walk sysfs) -static int vdev_linux_context_init(struct vdev_os_context *os_ctx, - struct vdev_linux_context *ctx) +static int +vdev_linux_context_init (struct vdev_os_context *os_ctx, + struct vdev_linux_context *ctx) { - int rc = 0; - size_t slen = VDEV_LINUX_NETLINK_RECV_BUF_MAX; - int so_passcred_enable = 1; + int rc = 0; + size_t slen = VDEV_LINUX_NETLINK_RECV_BUF_MAX; + int so_passcred_enable = 1; - memset(ctx, 0, sizeof(struct vdev_linux_context)); + memset (ctx, 0, sizeof (struct vdev_linux_context)); - ctx->os_ctx = os_ctx; + ctx->os_ctx = os_ctx; - // if we're just handling coldplug, don't set up the netlink socket - if (!os_ctx->coldplug_only) { + // if we're just handling coldplug, don't set up the netlink socket + if (!os_ctx->coldplug_only) + { - ctx->nl_addr.nl_family = AF_NETLINK; - ctx->nl_addr.nl_pid = getpid(); - ctx->nl_addr.nl_groups = NETLINK_KOBJECT_UEVENT; + ctx->nl_addr.nl_family = AF_NETLINK; + ctx->nl_addr.nl_pid = getpid (); + ctx->nl_addr.nl_groups = NETLINK_KOBJECT_UEVENT; - ctx->pfd.fd = - socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT); - if (ctx->pfd.fd < 0) { + ctx->pfd.fd = socket (PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT); + if (ctx->pfd.fd < 0) + { - rc = -errno; - vdev_error("socket(PF_NETLINK) rc = %d\n", rc); - return rc; - } + rc = -errno; + vdev_error ("socket(PF_NETLINK) rc = %d\n", rc); + return rc; + } - ctx->pfd.events = POLLIN; + ctx->pfd.events = POLLIN; - // big receive buffer, if running as root - if (geteuid() == 0) { - rc = setsockopt(ctx->pfd.fd, SOL_SOCKET, SO_RCVBUFFORCE, - &slen, sizeof(slen)); - if (rc < 0) { + // big receive buffer, if running as root + if (geteuid () == 0) + { + rc = setsockopt (ctx->pfd.fd, SOL_SOCKET, SO_RCVBUFFORCE, + &slen, sizeof (slen)); + if (rc < 0) + { - rc = -errno; - vdev_error - ("setsockopt(SO_RCVBUFFORCE) rc = %d\n", - rc); + rc = -errno; + vdev_error ("setsockopt(SO_RCVBUFFORCE) rc = %d\n", rc); - close(ctx->pfd.fd); - return rc; - } - } - // check credentials of message--only root should be able talk to us - rc = setsockopt(ctx->pfd.fd, SOL_SOCKET, SO_PASSCRED, - &so_passcred_enable, - sizeof(so_passcred_enable)); - if (rc < 0) { + close (ctx->pfd.fd); + return rc; + } + } + // check credentials of message--only root should be able talk to us + rc = setsockopt (ctx->pfd.fd, SOL_SOCKET, SO_PASSCRED, + &so_passcred_enable, sizeof (so_passcred_enable)); + if (rc < 0) + { - rc = -errno; - vdev_error("setsockopt(SO_PASSCRED) rc = %d\n", rc); + rc = -errno; + vdev_error ("setsockopt(SO_PASSCRED) rc = %d\n", rc); - close(ctx->pfd.fd); - return rc; + close (ctx->pfd.fd); + return rc; - } - // bind to the address - rc = bind(ctx->pfd.fd, (struct sockaddr *)&ctx->nl_addr, - sizeof(struct sockaddr_nl)); - if (rc != 0) { + } + // bind to the address + rc = bind (ctx->pfd.fd, (struct sockaddr *) &ctx->nl_addr, + sizeof (struct sockaddr_nl)); + if (rc != 0) + { - rc = -errno; - vdev_error("bind(%d) rc = %d\n", ctx->pfd.fd, rc); + rc = -errno; + vdev_error ("bind(%d) rc = %d\n", ctx->pfd.fd, rc); - close(ctx->pfd.fd); - return rc; - } - } else { - - ctx->pfd.fd = -1; + close (ctx->pfd.fd); + return rc; } + } + else + { - // lookup sysfs mountpoint - rc = vdev_linux_find_sysfs_mountpoint(ctx->sysfs_mountpoint, PATH_MAX); - if (rc != 0) { + ctx->pfd.fd = -1; + } - vdev_error("vdev_linux_find_sysfs_mountpoint rc = %d\n", rc); + // lookup sysfs mountpoint + rc = vdev_linux_find_sysfs_mountpoint (ctx->sysfs_mountpoint, PATH_MAX); + if (rc != 0) + { - close(ctx->pfd.fd); - return rc; - } + vdev_error ("vdev_linux_find_sysfs_mountpoint rc = %d\n", rc); - pthread_mutex_init(&ctx->initial_requests_lock, NULL); + close (ctx->pfd.fd); + return rc; + } - // seed devices from sysfs - rc = vdev_linux_sysfs_register_devices(ctx); - if (rc != 0) { + pthread_mutex_init (&ctx->initial_requests_lock, NULL); - vdev_error("vdev_linux_sysfs_walk_devs rc = %d\n", rc); - return rc; - } + // seed devices from sysfs + rc = vdev_linux_sysfs_register_devices (ctx); + if (rc != 0) + { - return 0; + vdev_error ("vdev_linux_sysfs_walk_devs rc = %d\n", rc); + return rc; + } + + return 0; } // stop listening -static int vdev_linux_context_shutdown(struct vdev_linux_context *ctx) +static int +vdev_linux_context_shutdown (struct vdev_linux_context *ctx) { - // shut down - if (ctx != NULL) { + // shut down + if (ctx != NULL) + { - if (ctx->pfd.fd >= 0) { - close(ctx->pfd.fd); - ctx->pfd.fd = -1; - } + if (ctx->pfd.fd >= 0) + { + close (ctx->pfd.fd); + ctx->pfd.fd = -1; + } - if (ctx->initial_requests != NULL) { + if (ctx->initial_requests != NULL) + { - struct vdev_device_request *itr = ctx->initial_requests; - struct vdev_device_request *next = NULL; + struct vdev_device_request *itr = ctx->initial_requests; + struct vdev_device_request *next = NULL; - while (itr != NULL) { + while (itr != NULL) + { - next = itr->next; + next = itr->next; - vdev_device_request_free(itr); - free(itr); + vdev_device_request_free (itr); + free (itr); - itr = next; - } + itr = next; + } - ctx->initial_requests = NULL; - ctx->initial_requests_tail = NULL; - } + ctx->initial_requests = NULL; + ctx->initial_requests_tail = NULL; } + } - return 0; + return 0; } // are we using devtmpfs on this mountpoint? // return 1 if so // return 0 if not // return negative on error -static int vdev_linux_mountpoint_on_devtmpfs(char const *mountpoint) +static int +vdev_linux_mountpoint_on_devtmpfs (char const *mountpoint) { - // NOTE: You would think that we can just statfs(2) the - // mountpoint and get the underlying filesystem type. - // However, devtmpfs and tmpfs have the same f_type value. - // This makes this strategy a no-go, since vdevd will need - // to behave differently on devtmpfs but not tmpfs. - // So, we have to parse /proc/mounts instead. + // NOTE: You would think that we can just statfs(2) the + // mountpoint and get the underlying filesystem type. + // However, devtmpfs and tmpfs have the same f_type value. + // This makes this strategy a no-go, since vdevd will need + // to behave differently on devtmpfs but not tmpfs. + // So, we have to parse /proc/mounts instead. - int rc = 0; + int rc = 0; - FILE *f = NULL; - int ent_count = 1; + FILE *f = NULL; + int ent_count = 1; - bool found = false; - char devtmpfs_mountpoint[PATH_MAX + 1]; + bool found = false; + char devtmpfs_mountpoint[PATH_MAX + 1]; - char realpath_mountpoint[PATH_MAX + 1]; - char devtmpfs_realpath_mountpoint[PATH_MAX + 1]; + char realpath_mountpoint[PATH_MAX + 1]; + char devtmpfs_realpath_mountpoint[PATH_MAX + 1]; - size_t devtmpfs_realpath_mountpoint_len = 0; - size_t realpath_mountpoint_len = 0; + size_t devtmpfs_realpath_mountpoint_len = 0; + size_t realpath_mountpoint_len = 0; - char mntbuf[4096]; - struct mntent ment_buf; - struct mntent *ment_ptr = NULL; + char mntbuf[4096]; + struct mntent ment_buf; + struct mntent *ment_ptr = NULL; - f = fopen("/proc/mounts", "r"); - if (f == NULL) { + f = fopen ("/proc/mounts", "r"); + if (f == NULL) + { - rc = -errno; - fprintf(stderr, "Failed to open /proc/mounts, rc = %d\n", rc); - return rc; - } - // scan for sysfs mount type - while (1) { + rc = -errno; + fprintf (stderr, "Failed to open /proc/mounts, rc = %d\n", rc); + return rc; + } + // scan for sysfs mount type + while (1) + { - ment_ptr = getmntent_r(f, &ment_buf, mntbuf, 4096); - if (ment_ptr == NULL) { + ment_ptr = getmntent_r (f, &ment_buf, mntbuf, 4096); + if (ment_ptr == NULL) + { - break; - } + break; + } - if (strcmp(ment_ptr->mnt_type, "devtmpfs") == 0) { + if (strcmp (ment_ptr->mnt_type, "devtmpfs") == 0) + { - // found! - strncpy(devtmpfs_mountpoint, ment_ptr->mnt_dir, - PATH_MAX); + // found! + strncpy (devtmpfs_mountpoint, ment_ptr->mnt_dir, PATH_MAX); - // is the mountpoint contained in devtmpfs_mountpoint? - char *tmp = NULL; + // is the mountpoint contained in devtmpfs_mountpoint? + char *tmp = NULL; - memset(realpath_mountpoint, 0, PATH_MAX + 1); - memset(devtmpfs_realpath_mountpoint, 0, PATH_MAX + 1); + memset (realpath_mountpoint, 0, PATH_MAX + 1); + memset (devtmpfs_realpath_mountpoint, 0, PATH_MAX + 1); - tmp = realpath(mountpoint, realpath_mountpoint); - if (tmp == NULL) { + tmp = realpath (mountpoint, realpath_mountpoint); + if (tmp == NULL) + { - rc = -errno; - fprintf(stderr, - "Failed to get the real path of '%s', rc = %d\n", - mountpoint, rc); - break; - } + rc = -errno; + fprintf (stderr, + "Failed to get the real path of '%s', rc = %d\n", + mountpoint, rc); + break; + } - tmp = - realpath(devtmpfs_mountpoint, - devtmpfs_realpath_mountpoint); - if (tmp == NULL) { + tmp = realpath (devtmpfs_mountpoint, devtmpfs_realpath_mountpoint); + if (tmp == NULL) + { - rc = -errno; - fprintf(stderr, - "Failed to get the real path of '%s', rc = %d\n", - devtmpfs_mountpoint, rc); - break; - } + rc = -errno; + fprintf (stderr, + "Failed to get the real path of '%s', rc = %d\n", + devtmpfs_mountpoint, rc); + break; + } - vdev_debug("devtmpfs realpath is '%s'\n", - devtmpfs_realpath_mountpoint); - vdev_debug("mountpoint realpath is '%s'\n", - realpath_mountpoint); + vdev_debug ("devtmpfs realpath is '%s'\n", + devtmpfs_realpath_mountpoint); + vdev_debug ("mountpoint realpath is '%s'\n", realpath_mountpoint); - devtmpfs_realpath_mountpoint_len = - strlen(devtmpfs_realpath_mountpoint); - realpath_mountpoint_len = strlen(realpath_mountpoint); + devtmpfs_realpath_mountpoint_len = + strlen (devtmpfs_realpath_mountpoint); + realpath_mountpoint_len = strlen (realpath_mountpoint); - size_t min_len = - MIN(devtmpfs_realpath_mountpoint_len, + size_t min_len = MIN (devtmpfs_realpath_mountpoint_len, realpath_mountpoint_len); - // is our mountpoint within the devtmpfs mountpoint? - if (strncmp(devtmpfs_realpath_mountpoint, realpath_mountpoint, min_len) == 0 && // devtmpfs mountpoint path is a substring of the mountpoint path and - (strchr(realpath_mountpoint + min_len, '/') != NULL || // either the mountpoint path continues at least one directory into devtmpfs path, or - strcmp(devtmpfs_realpath_mountpoint, realpath_mountpoint) == 0)) { // the devtmpfs mountpoint path *is* the mountpoint path - - // contained! - rc = 1; - found = true; - break; - } - } + // is our mountpoint within the devtmpfs mountpoint? + if (strncmp (devtmpfs_realpath_mountpoint, realpath_mountpoint, min_len) == 0 && // devtmpfs mountpoint path is a substring of the mountpoint path and + (strchr (realpath_mountpoint + min_len, '/') != NULL || // either the mountpoint path continues at least one directory into devtmpfs path, or + strcmp (devtmpfs_realpath_mountpoint, + realpath_mountpoint) == 0)) + { // the devtmpfs mountpoint path *is* the mountpoint path - ent_count++; + // contained! + rc = 1; + found = true; + break; + } } - fclose(f); + ent_count++; + } + + fclose (f); - return rc; + return rc; } // set up Linux-specific vdev state. // this is early initialization, so don't start anything yet // NOTE: this should only be called from reload-safe code--i.e. a reload can't occur while this method runs -int vdev_os_init(struct vdev_os_context *os_ctx, void **cls) +int +vdev_os_init (struct vdev_os_context *os_ctx, void **cls) { - int rc = 0; - struct vdev_linux_context *ctx = NULL; + int rc = 0; + struct vdev_linux_context *ctx = NULL; - rc = vdev_linux_mountpoint_on_devtmpfs(os_ctx->state->mountpoint); - if (rc < 0) { + rc = vdev_linux_mountpoint_on_devtmpfs (os_ctx->state->mountpoint); + if (rc < 0) + { - vdev_error("vdev_linux_mountpoint_on_devtmpfs('%s') rc = %d\n", - os_ctx->state->mountpoint, rc); - return rc; - } + vdev_error ("vdev_linux_mountpoint_on_devtmpfs('%s') rc = %d\n", + os_ctx->state->mountpoint, rc); + return rc; + } - if (rc > 0) { + if (rc > 0) + { - // using devtmpfs - vdev_info("'%s' is on devtmpfs\n", os_ctx->state->mountpoint); + // using devtmpfs + vdev_info ("'%s' is on devtmpfs\n", os_ctx->state->mountpoint); - vdev_config_set_OS_quirk(os_ctx->state->config->OS_quirks, - VDEV_OS_QUIRK_DEVICE_EXISTS); - } else { + vdev_config_set_OS_quirk (os_ctx->state->config->OS_quirks, + VDEV_OS_QUIRK_DEVICE_EXISTS); + } + else + { - vdev_info("'%s' is not on devtmpfs\n", - os_ctx->state->mountpoint); - } + vdev_info ("'%s' is not on devtmpfs\n", os_ctx->state->mountpoint); + } - ctx = VDEV_CALLOC(struct vdev_linux_context, 1); - if (ctx == NULL) { - return -ENOMEM; - } + ctx = VDEV_CALLOC (struct vdev_linux_context, 1); + if (ctx == NULL) + { + return -ENOMEM; + } - rc = vdev_linux_context_init(os_ctx, ctx); - if (rc != 0) { + rc = vdev_linux_context_init (os_ctx, ctx); + if (rc != 0) + { - free(ctx); - return rc; - } + free (ctx); + return rc; + } - *cls = ctx; - return 0; + *cls = ctx; + return 0; } // shut down Linux-specific vdev state -int vdev_os_shutdown(void *cls) +int +vdev_os_shutdown (void *cls) { - struct vdev_linux_context *ctx = (struct vdev_linux_context *)cls; + struct vdev_linux_context *ctx = (struct vdev_linux_context *) cls; - vdev_linux_context_shutdown(ctx); - free(ctx); + vdev_linux_context_shutdown (ctx); + free (ctx); - return 0; + return 0; } #endif diff --git a/vdevd/os/linux.h b/vdevd/os/linux.h index 62cefce..a43e825 100644 --- a/vdevd/os/linux.h +++ b/vdevd/os/linux.h @@ -47,30 +47,31 @@ #define VDEV_LINUX_NETLINK_UDEV_HEADER_LEN 8 // connection to the linux kernel for hotplug -struct vdev_linux_context { +struct vdev_linux_context +{ - // netlink address - struct sockaddr_nl nl_addr; + // netlink address + struct sockaddr_nl nl_addr; - // poll on the netlink socket - struct pollfd pfd; + // poll on the netlink socket + struct pollfd pfd; - // path to mounted sysfs - char sysfs_mountpoint[PATH_MAX + 1]; + // path to mounted sysfs + char sysfs_mountpoint[PATH_MAX + 1]; - // ref to OS context - struct vdev_os_context *os_ctx; + // ref to OS context + struct vdev_os_context *os_ctx; - // initial device requests - pthread_mutex_t initial_requests_lock; - struct vdev_device_request *initial_requests; - struct vdev_device_request *initial_requests_tail; + // initial device requests + pthread_mutex_t initial_requests_lock; + struct vdev_device_request *initial_requests; + struct vdev_device_request *initial_requests_tail; }; -C_LINKAGE_BEGIN int vdev_os_init(struct vdev_os_context *ctx, void **cls); -int vdev_os_shutdown(void *cls); +C_LINKAGE_BEGIN int vdev_os_init (struct vdev_os_context *ctx, void **cls); +int vdev_os_shutdown (void *cls); -int vdev_os_next_device(struct vdev_device_request *request, void *cls); +int vdev_os_next_device (struct vdev_device_request *request, void *cls); C_LINKAGE_END #endif diff --git a/vdevd/os/methods.h b/vdevd/os/methods.h index d336ed2..537c699 100644 --- a/vdevd/os/methods.h +++ b/vdevd/os/methods.h @@ -34,15 +34,15 @@ #include "test.h" #endif -C_LINKAGE_BEGIN int vdev_os_init(struct vdev_os_context *ctx, void **cls); -int vdev_os_shutdown(void *cls); +C_LINKAGE_BEGIN int vdev_os_init (struct vdev_os_context *ctx, void **cls); +int vdev_os_shutdown (void *cls); // yield the next device // return 0 on success // return positive to exit successfully // return -EAGAIN if vdevd should try again // return negative on fatal error (causes vdevd to exit). -int vdev_os_next_device(struct vdev_device_request *request, void *cls); +int vdev_os_next_device (struct vdev_device_request *request, void *cls); C_LINKAGE_END #endif diff --git a/vdevd/os/test.h b/vdevd/os/test.h index e90a602..fbd781f 100644 --- a/vdevd/os/test.h +++ b/vdevd/os/test.h @@ -36,24 +36,26 @@ typedef vector < struct vdev_device_request *>vdev_test_device_list_t; -struct vdev_test_context { +struct vdev_test_context +{ - vdev_test_device_list_t *devlist; + vdev_test_device_list_t *devlist; - pthread_mutex_t devlist_lock; - sem_t devlist_sem; + pthread_mutex_t devlist_lock; + sem_t devlist_sem; - char *events_dir; + char *events_dir; }; -extern "C" { +extern "C" +{ - int vdev_os_init(struct vdev_os_context *ctx, void **cls); - int vdev_os_start(void *cls); - int vdev_os_stop(void *cls); - int vdev_os_shutdown(void *cls); + int vdev_os_init (struct vdev_os_context *ctx, void **cls); + int vdev_os_start (void *cls); + int vdev_os_stop (void *cls); + int vdev_os_shutdown (void *cls); - int vdev_os_next_device(struct vdev_device_request *request, void *cls); + int vdev_os_next_device (struct vdev_device_request *request, void *cls); } #endif From 37e6d59b27237ab7bb7fdee33d155a1e9d036a0e Mon Sep 17 00:00:00 2001 From: Peter Gossner Date: Fri, 26 Aug 2016 02:59:22 +0930 Subject: [PATCH 10/13] archive, capture, merge ralphs work on packaging ralph.ronnquist@gmail.com --- debian.mk | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 debian.mk diff --git a/debian.mk b/debian.mk new file mode 100644 index 0000000..d1a0436 --- /dev/null +++ b/debian.mk @@ -0,0 +1,31 @@ + +LIC=gpl3 +#EMAIL=ralph.ronnquist@gmail.com +EMAIL=pete.gossner@gmail.com +VERSION=1.0alpha-petes +ARCH=$(shell uname -r) +HOMEPAGE="github.com/PeteGozz/vdev" + +DEBS += vdevd_$(VERSION)_$(ARCH).deb +DEBS += libudev1-compat_$(VERSION)_$(ARCH).deb +DEBS += vdev_$(VERSION)_$(ARCH).deb + +all: $(DEBS) + +vdevd_$(VERSION)_$(ARCH).deb: + $(MAKE) -C vdevd -f ../debian.mk deb PACKAGE=vdevd + +libudev1-compat_$(VERSION)_$(ARCH).deb: + $(MAKE) -C libudev-compat -f ../debian.mk deb PACKAGE=libudev1-compat + +vdev_$(VERSION)_$(ARCH).deb: + $(MAKE) -C example -f ../debian.mk deb PACKAGE=vdev + +vdevfs_$(VERSION)_$(ARCH).deb: + $(MAKE) -C fs -f ../debian.mk deb PACKAGE=vdevfs + +.PHONY: deb +deb: + dh_make -a -s -n -y -e "$(EMAIL)" -p $(PACKAGE)_$(VERSION) -c $(LIC) + PREFIX= INCLUDE_PREFIX=/usr dpkg-buildpackage -b -uc + From 8723067acdb1ce8350a85857b2379a820f9c27a8 Mon Sep 17 00:00:00 2001 From: Peter Gossner Date: Fri, 26 Aug 2016 03:53:57 +0930 Subject: [PATCH 11/13] Attempts to succeed on older equipment and or i386 C libs only. --- example/initramfs/hooks/vdev | 93 +++++++++++++++++++++++++++--------- 1 file changed, 70 insertions(+), 23 deletions(-) diff --git a/example/initramfs/hooks/vdev b/example/initramfs/hooks/vdev index 61b3fa1..abe6a79 100755 --- a/example/initramfs/hooks/vdev +++ b/example/initramfs/hooks/vdev @@ -1,5 +1,7 @@ #!/bin/sh -e +## set -x + PREREQS="" prereqs() { echo "$PREREQS"; } @@ -11,28 +13,36 @@ case "$1" in ;; esac -. /usr/share/initramfs-tools/hook-functions +. /usr/share/initramfs-tools/hook-functions + +# Needed for keyboard + +force_load evdev || echo "eventfs (mod evdev ?) not preloaded" && sleep 2 # helper programs -mkdir -p $DESTDIR/lib/vdev + +mkdir -vp $DESTDIR/lib/vdev + for prog in /lib/vdev/*; do # shell script or library? if [ -z "${prog#*.sh}" ]; then - cp -a $prog $DESTDIR/lib/vdev/ else - # binary? if [ -f $prog -a -x $prog ]; then - copy_exec $prog /lib/vdev fi fi done +# libudev-compat +if [ -f /lib/libudev.so.1 ] ; then + copy_exec /lib/libudev.so.1 +fi + # config -mkdir -p $DESTDIR/etc/vdev +mkdir -pv $DESTDIR/etc/vdev cp -a /etc/vdev/* $DESTDIR/etc/vdev/ # the daemon itself @@ -63,19 +73,28 @@ if [ -f /sbin/lvm ]; then else echo "WARN: could not find lvm in /sbin/lvm. Logical volume symlinks will not be created." fi - +# # network tools (needed by vdevd's helpers) +# busy box may provide alternatives +# for human uses. (?) +# +if ! [ -f /sbin/ip ] && ! [ -f /bin/ip ]; then + echo "WARN: could not find iproute2 in /bin/ip or /sbin/ip." + echo "Network interfaces will not be configured." +fi + if [ -f /bin/ip ]; then copy_exec /bin/ip fi if [ -f /sbin/ip ]; then copy_exec /sbin/ip +else [ -f /sbin/ifconfig ]; then +# try the classical tool + copy_exec /sbin/ifconfig + echo "installing /sbin/ifconfig as networking tool" fi -if ! [ -f /sbin/ip ] && ! [ -f /bin/ip ]; then - echo "WARN: could not find iproute2 in /bin/ip or /sbin/ip. Network interfaces will not be configured." -fi # SELinux tools if [ -f /sbin/restorecon ]; then @@ -84,7 +103,10 @@ fi # device tools if [ -f /sbin/MAKEDEV ]; then - copy_exec /sbin/MAKEDEV || true + copy_exec /sbin/MAKEDEV +else + echo "WARNING: No MAKEDEV found to install" + echo "vdev --once may be your best alterenative" fi # device mapper tools @@ -96,10 +118,12 @@ fi # hardware database if [ -f /lib/vdev/hwdb/hwdb.squashfs ]; then + copy_exec /sbin/losetup mkdir -p $DESTDIR/lib/vdev/hwdb cp -a /lib/vdev/hwdb/hwdb.squashfs $DESTDIR/lib/vdev/hwdb else - echo "WARN: could not find hardware database in /lib/vdev/hwdb. Some hardware metadata may not be generated." + echo "WARN: could not find hardware database in /lib/vdev/hwdb. Some hardware metadata may not be generated." + sleep 2 fi # GNU tools (not the busybox equivalents) @@ -112,19 +136,42 @@ copy_exec /bin/egrep copy_exec /bin/kmod # users and groups databases -cp -a /etc/passwd $DESTDIR/etc/passwd -cp -a /etc/group $DESTDIR/etc/group - -# extra libc goodies -copy_exec /lib/x86_64-linux-gnu/libc.so.6 -copy_exec /lib/x86_64-linux-gnu/libnss_compat.so.2 -copy_exec /lib/x86_64-linux-gnu/libnsl.so.1 -copy_exec /lib/x86_64-linux-gnu/libnss_nis.so.2 -copy_exec /lib/x86_64-linux-gnu/libnss_files.so.2 +cp -va /etc/passwd $DESTDIR/etc/passwd +cp -va /etc/group $DESTDIR/etc/group + +# +# extra libc goodies +# Falling to i386 if i686 is the uname machine type +# and the i686 libc version is not found. +# +# +if [ -d /lib/$(arch)-linux-gnu ]; then + LIBC=/lib/$(arch)-linux-gnu +elif [ -d /lib/i386-linux-gnu ]; then + LIBC=/lib/i386-linux-gnu +else + # make noise and trigger -e if set + echo "Unable to find libc shared object files for $(arch)" + sleep 1 + echo "Please check dependancies or package install order" + sleep 2 + /bin/false +fi -# since vdevd is multi-threaded, libpthread will dynamically load libgcc_s +copy_exec $LIBC/libc.so.6 || echo "$LIBC/libc.so.6 (still) not found" +copy_exec $LIBC/libnss_compat.so.2 +copy_exec $LIBC/libnsl.so.1 +copy_exec $LIBC/libnss_nis.so.2 +copy_exec $LIBC/libnss_files.so.2 +# +# since vdevd is multi-threaded, +# libpthread will need to dynamically load libgcc_s # (and copy_exec won't detect this) -copy_exec /lib/`gcc -print-multiarch`/libgcc_s.so.1 +# +copy_exec $LIBC/libgcc_s.so.1 || echo "libpthread needs libgcc_s" # until we're confident that the scripts work with busybox's sh, use dash copy_exec /bin/dash + +# be polite +exit From 5f91a6515eb25473e8459243e1391fd47b00ee4b Mon Sep 17 00:00:00 2001 From: Peter Gossner Date: Fri, 26 Aug 2016 22:24:16 +0930 Subject: [PATCH 12/13] new file: MAKEDEV.sh capturing a snapshot for dev and emergency uses This version has been slightly extended to warn about possible accidental creations. --- tools/MAKEDEV.sh | 2298 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 2298 insertions(+) create mode 100755 tools/MAKEDEV.sh diff --git a/tools/MAKEDEV.sh b/tools/MAKEDEV.sh new file mode 100755 index 0000000..afdd663 --- /dev/null +++ b/tools/MAKEDEV.sh @@ -0,0 +1,2298 @@ +#! /bin/sh - + +# snap shot from debian i386 source August 2016 + +#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---# +# Customisation: +# The devices fall into various classes. This section contains the mapping +# from a class name into a group name and permission. +# You will almost certainly need to edit the group name to match your +# system, and you may change the permissions to suit your preference. These +# lines _must_ be of the format "user group perm". +#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---# + +public=" root root 0666" +private=" root root 0600" +system=" root root 0660" +kmem=" root kmem 0640" +tty=" root tty 0666" +cons=" root tty 0600" +dialout=" root dialout 0660" +dip=" root dip 0660" +mouse=" root root 0660" +printer=" root lp 0660" +floppy=" root floppy 0660" +disk=" root disk 0660" +scsi=" root root 0600" +cdrom=" root cdrom 0660" +tape=" root tape 0660" +audio=" root audio 0660" +video=" root video 0660" +ibcs2=" root root 0666" +scanner=" root root 0666" +coda=" root root 0600" +ipsec=" root root 0200" +readable=" root root 0444" +lirc=" root video 0640" + +MAXVT=63 + +# defaults for $major_* +major_ide0=3 +major_ide1=22 +major_sd=8 +major_lp=6 + +# Remark: OSS/Linux becomes major_OSSLinux +# NON default #---#---#---#---#---#---#---#---#---#---#---#---#---#---#---# + +# for exploration and testing +testdir="test_devices" +RUNAT=$(pwd) + +warning(){ + # function to warn about spontaneous device creation. + # the intent here is as for the warning text and no more. + # This is not a manual page + + cat < here + clear + export noloops=seen + ;; + No | n | N | no | nup | stop | halt | bail) + echo "Avoiding a potential mess" + echo "Probably a wise move" + exit 0 + ;; + *) + clear + echo "$AFFIRM is an unforseen response" + sleep 2 + echo "Leaving you to think about \"$AFFIRM\"." + exit 1 + ;; +esac + +return 0 +} + + +if [ $@ ]; then + # this script calls itself possibly many times + # this test avoids ever hitting + # the warning guff when called with purpose + echo "$0 attempting $@" + : #true pass +elif [ $noloops ]; then + # echo "seen this before" + export noloops=seen + : #true pass +elif [ "${RUNAT}" != "/dev" ] || [ "$(basename ${RUNAT})" != "$testdir" ] ; then + warning +else + noloops=seenandset +fi + +#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---# +# try to do the right things if udev is running +#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---# +if [ "$WRITE_ON_UDEV" ]; then + : +elif [ -d /dev/.static/dev/ ] && [ "`pwd`" = /dev ] && [ -e /proc/mounts ] \ + && grep -qE '^[^ ]+ /dev/\.static/dev' /proc/mounts; then + echo "udev active, devices will be created in /dev/.static/dev/" + cd /dev/.static/dev/ +elif [ -d /.dev/ ] && [ "`pwd`" = /dev ] && [ -e /proc/mounts ] \ + && grep -qE '^[^ ]+ /\.dev' /proc/mounts; then + echo "udev active, devices will be created in /.dev/" + cd /.dev/ +elif [ -d /run/udev -o -d .udevdb/ -o -d .udev/ ] && [ "`pwd`" = /dev ]; then + echo "/run/udev or .udevdb or .udev presence implies active udev. Aborting MAKEDEV invocation." + # use exit 0, not 1, so postinst scripts don't fail on this + exit 0 +fi + +#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---# +# don't stomp on devfs users +#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---# +if [ -c .devfsd ] +then + echo ".devfsd presence implies active DevFS. Aborting MAKEDEV invocation." + # use exit 0, not 1, so postinst scripts don't fail on this + exit 0 +fi + +#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---# +# don't stomp on non-Linux users +#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---# +if [ "$(uname -s)" != "Linux" ] +then + echo "Results undefined on non-Linux systems, aborting MAKEDEV invocation." + # use exit 0, not 1, so postinst scripts don't fail on this + exit 0 +fi + +#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---# + +procfs=/proc + +opt_v= +opt_d= +opt_n= + +while [ $# -ge 1 ] +do + case $1 in + --) shift; break ;; + -v) shift; opt_v=1 ;; + -d) shift; opt_d=1 ;; + -n) shift; opt_n=1; opt_v=1 ;; + -V) shift; opt_V=1 ;; + -*) echo "$0: unknown flag \"$1\"" >&2; exit 1 ;; + *) break ;; + esac +done + +if [ "$opt_V" ] +then + echo "This was Devuan | Debian MAKEDEV." + echo "For version info, try 'dpkg --list makedev'" + echo "See /usr/share/doc/makedev/ for more information on Devuan MAKEDEV." + exit 0 +fi + +opts="${opt_n:+-n} ${opt_v:+-v} ${opt_d:+-d}" + +#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---# +#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---# + +devicename () { # translate device names to something safe + # A-Z is not full alphabet in all locales (e.g. in et_EE) + echo "$*" | LC_ALL=C sed -e 's/[^A-Za-z0-9_]/_/g' +} + +makedev () { # usage: makedev name [bcu] major minor owner group mode + if [ "$opt_v" ] + then if [ "$opt_d" ] + then echo "delete $1" + else echo "create $1 $2 $3 $4 $5:$6 $7" + fi + fi + # missing parameters are a bug - bail - should we do an exit 1 here? + case :$1:$2:$3:$4:$5:$6:$7: in + *::*) echo "Warning: MAKEDEV $@ is missing parameter(s)." >&2;; + esac + if [ ! "$opt_n" ] + then + if [ "$opt_d" ] + then + rm -f $1 + else + rm -f $1- + if mknod $1- $2 $3 $4 && + chown $5:$6 $1- && + chmod $7 $1- && + mv $1- $1 + then + : # it worked + else + # Didn't work, clean up any mess... + echo "makedev $@: failed" + rm -f $1- + fi + fi + fi +} +makefifo () { # usage: makefifo name owner group mode + if [ "$opt_v" ] + then if [ "$opt_d" ] + then echo "delete $1" + else echo "create $1 $2:$3 $4" + fi + fi + # missing parameters are a bug - bail - should we do an exit 1 here? + case :$1:$2:$3:$4: in + *::*) echo "Warning: MAKEFIFO $@ is missing parameter(s)." >&2;; + esac + if [ ! "$opt_n" ] + then + if [ "$opt_d" ] + then + rm -f $1 + else + rm -f $1- + if mknod $1- p && + chown $2:$3 $1- && + chmod $4 $1- && + mv $1- $1 + then + : # it worked + else + # Didn't work, clean up any mess... + echo "makefifo $@: failed" + rm -f $1- + fi + fi + fi +} +symlink () { # usage: symlink name target + if [ "$opt_v" ] + then if [ "$opt_d" ] + then echo "delete $1" + else echo "create $1 -> $2" + fi + fi + [ ! "$opt_n" ] && rm -f $1 && + [ ! "$opt_d" ] && ln -s $2 $1 +} + +#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---# + +# Debian allows us to assume /bin/sh is a POSIX compliant shell, so go for it! + +math () { + eval echo "\$(($*))" +} +index () { # index string c + eval "I=\${1%$2*}" + eval echo "\${#I}" +} +suffix () { + eval echo "\${1#$2}" +} +strip () { + eval echo "\${1% $2 *} \${1#* $2 }" +} +first () { + echo "${1%%?}" +} +second () { + echo "${1##?}" +} +substr () { + echo $1 | dd bs=1 count=1 skip=$(( $2 - 1 )) 2> /dev/null +} + +#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---# + +devices= +if [ ! -f $procfs/devices ] +then + echo "$0: warning: can't read $procfs/devices" >&2 +else + exec 3<$procfs/devices + while read major device extra <&3 + do + device=`echo $device | sed 's#/.*##'` + case "$major" in + Character|Block|'') + ;; + *) + safedevname=`devicename $device` + eval "major_$safedevname=$major" + devices="$devices $device" + ;; + esac + done + exec 3<&- +fi + +Major () { + device=$2 + devname=`devicename $1` + if [ "$opt_d" ] + then + echo -1 # don't care + else + eval echo \${major_$devname:-\${device:?\"unknown major number for $1\"}} + fi +} + +cvt () { + while [ $# -ne 0 ] + do + case "$1" in + mem|tty|ttyp|cua|cub|cui) ;; + hd) (for d in a b c d e f g h i j k l m n o p ; do + echo -n hd$d " " + done) ; echo + ;; + ide0) echo hda hdb ;; + ide1) echo hdc hdd ;; + ide2) echo hde hdf ;; + ide3) echo hdg hdh ;; + ide4) echo hdi hdj ;; + ide5) echo hdk hdl ;; + ide6) echo hdm hdn ;; + ide7) echo hdo hdp ;; + ide8) echo hdq hdr ;; + ide9) echo hds hdt ;; + sd) (for d in a b c d e f g h i j k l m n o p ; do + echo -n sd$d " " + done) ; echo + ;; + dasd) (for d in a b c d e f g h i j k l m \ + n o p q r s t u v w x y z ; do + echo -n dasd$d " " + done) ; echo + ;; + raw) echo raw ;; + sg) echo sg ;; + sr) echo scd ;; + st) echo st0 ;; + xd) echo xda xdb ;; + ad) echo ada adb ;; + lp) echo lp ;; + mt) echo ftape ;; + qft) echo ftape ;; + loop) echo loop ;; + md) echo md ;; + ibcs2) echo ibcs2 ;; + tpqic02) echo qic ;; + sound) echo audio ;; + logiscan) echo logiscan ;; + ac4096) echo ac4096 ;; + hw) echo helloworld ;; # cute + sbpcd | sbpcd[123]) echo $1 ;; + joystick) echo js ;; + input) echo input ;; + apm_bios) echo apm ;; + dcf) echo dcf ;; + aztcd) echo aztcd ;; + cm206cd) echo cm206cd ;; + gscd) echo gscd ;; + pcmcia) ;; # taken care of by its own driver + ttyC) echo cyclades ;; + isdn) echo isdnmodem isdnbri dcbri ;; + vcs) ;; # ummm ? + pty) echo pty ;; + misc) echo misc ;; + 3dfx) echo 3dfx ;; + agpgart) echo agpgart ;; + microcode) echo microcode ;; + ipmi|ipmikcs) echo ipmi ;; + fb) echo fb ;; + nb|drbd) echo nb0 nb1 nb2 nb3 nb4 nb5 nb6 nb7;; + netlink) echo netlink ;; + tap) echo netlink ;; + hamradio) echo hamradio ;; + snd) ;; + ptm) ;; + pts) ;; + ttyB) (for l in 0 1 2 3 4 5 6 7 ; do + echo -n ttyB$l " " + done) ; echo + ;; + ttyS) echo ttyS0 ttyS1 ttyS2 ttyS3 ttyS4 ;; + ttyI) echo ttyI0 ttyI1 ttyI2 ttyI3 ;; + ircomm|irlpt) irda ;; + ppp) echo ppp ;; + usb) echo usb ;; + dpt_i2o) echo dpti ;; + bluetooth) echo bluetooth ;; + lvm) ;; # taken care of by LVM userspace tools + ramdisk) echo ram ;; + null) echo std ;; + zero) echo std ;; + *) echo $1 + esac + shift + done +} + +for arg in `cvt $*` +do + # this is to make the case patterns work as expected in all locales + LC_ALL=C + case $arg in + generic) + # pick the right generic- using dpkg's knowledge + case `dpkg --print-architecture` in + alpha) + $0 $opts generic-alpha + ;; + arm|armeb|armel) + $0 $opts generic-arm + ;; + hppa) + $0 $opts generic-hppa + ;; + i386|lpia) + $0 $opts generic-i386 + ;; + amd64) + $0 $opts generic-i386 + ;; + ia64) + $0 $opts generic-ia64 + ;; + m68k) + $0 $opts generic-m68k + ;; + mips) + $0 $opts generic-mips + ;; + mipsel) + $0 $opts generic-mipsel + ;; + powerpc) + $0 $opts generic-powerpc + ;; + ppc64) + $0 $opts generic-powerpc + ;; + s390) + $0 $opts generic-s390 + ;; + sh*) + $0 $opts generic-sh + ;; + sparc) + $0 $opts generic-sparc + ;; + *) + echo "$0: no support for generic on this arch" >&2 + exit 1 + ;; + esac + ;; + generic-alpha) + $0 $opts std + $0 $opts fd + $0 $opts fd0 fd1 + $0 $opts hd sd + $0 $opts xda xdb + $0 $opts scd0 scd1 + $0 $opts st0 st1 + $0 $opts sg + $0 $opts pty + $0 $opts console + $0 $opts ttyS0 ttyS1 ttyS2 ttyS3 ttyS4 + $0 $opts busmice + $0 $opts lp + $0 $opts par + $0 $opts audio + $0 $opts fb + $0 $opts dac960 + ;; + generic-arm) + $0 $opts std + $0 $opts fd + $0 $opts fd0 fd1 + $0 $opts hd sd + $0 $opts xda xdb + $0 $opts scd0 scd1 + $0 $opts st0 st1 + $0 $opts sg + $0 $opts pty + $0 $opts console + $0 $opts ttyS0 ttyS1 ttyS2 ttyS3 ttyS4 + $0 $opts busmice + makedev sunmouse c 10 6 $mouse + $0 $opts lp + $0 $opts par + $0 $opts audio + $0 $opts fb + ;; + generic-hppa) + $0 $opts std + $0 $opts fd + $0 $opts fd0 fd1 + $0 $opts hd sd + $0 $opts scd0 scd1 + $0 $opts st0 st1 + $0 $opts sg + $0 $opts pty + $0 $opts console + $0 $opts ttyS0 ttyS1 ttyS2 ttyS3 ttyS4 + $0 $opts ttyB0 ttyB1 ttyB2 ttyB3 ttyB4 ttyB5 ttyB6 ttyB7 + $0 $opts busmice + $0 $opts lp + $0 $opts par + $0 $opts audio + $0 $opts fb + $0 $opts rtc + ;; + generic-i386 | generic-i686) + $0 $opts std + $0 $opts fd + $0 $opts fd0 fd1 + $0 $opts hd sd + $0 $opts xda xdb + $0 $opts scd0 scd1 + $0 $opts st0 st1 + $0 $opts sg + $0 $opts pty + $0 $opts console + $0 $opts ttyS0 ttyS1 ttyS2 ttyS3 ttyS4 + $0 $opts busmice + $0 $opts input + $0 $opts lp + $0 $opts par + $0 $opts audio + $0 $opts fb + $0 $opts isdn-io eda edb sonycd mcd mcdx cdu535 + $0 $opts optcd sjcd cm206cd gscd + $0 $opts lmscd sbpcd aztcd bpcd dac960 dpti ida ataraid cciss + $0 $opts i2o.hda i2o.hdb i2o.hdc i2o.hdd + ;; + generic-ia64) + $0 $opts std + $0 $opts fd + $0 $opts fd0 fd1 + $0 $opts hd sd + $0 $opts scd0 scd1 + $0 $opts st0 st1 + $0 $opts sg + $0 $opts pty + $0 $opts console + $0 $opts ttyS0 ttyS1 ttyS2 ttyS3 ttyS4 ttyS5 + $0 $opts busmice + $0 $opts input + $0 $opts lp + $0 $opts par + $0 $opts audio + $0 $opts fb + $0 $opts efirtc + ;; + generic-m68k) + $0 $opts std + $0 $opts fd + $0 $opts fd0 fd1 + $0 $opts hd sd + $0 $opts scd0 scd1 + $0 $opts sg + $0 $opts ada adb adc add ade adf + $0 $opts pty + $0 $opts console + $0 $opts ttyS0 ttyS1 ttyS2 ttyS3 ttyS4 ttyS5 + $0 $opts m68k-mice + $0 $opts lp + $0 $opts par + $0 $opts nvram + $0 $opts audio + $0 $opts fb + ;; + generic-mips) + $0 $opts std + $0 $opts fd + $0 $opts fd0 fd1 + $0 $opts hd sd + $0 $opts scd0 scd1 + $0 $opts st0 st1 + $0 $opts sg + $0 $opts pty + $0 $opts console + $0 $opts ttyS0 ttyS1 ttyS2 ttyS3 ttyS4 + $0 $opts lp + $0 $opts par + $0 $opts audio + $0 $opts fb + $0 $opts busmice + ;; + generic-mipsel) + $0 $opts std + $0 $opts fd + $0 $opts fd0 fd1 + $0 $opts hd sd + $0 $opts scd0 scd1 + $0 $opts st0 st1 + $0 $opts sg + $0 $opts pty + $0 $opts console + $0 $opts ttyS0 ttyS1 ttyS2 ttyS3 ttyS4 + $0 $opts lp + $0 $opts par + $0 $opts audio + $0 $opts fb + $0 $opts rtc + ;; + generic-powerpc) + $0 $opts std + $0 $opts fd + $0 $opts fd0 fd1 + $0 $opts hd sd + $0 $opts scd0 scd1 + $0 $opts st0 st1 + $0 $opts sg + $0 $opts pty + $0 $opts console + $0 $opts ttyS0 ttyS1 ttyS2 ttyS3 ttyS4 + $0 $opts busmice + $0 $opts m68k-mice + $0 $opts input + $0 $opts lp + $0 $opts par + $0 $opts nvram + $0 $opts audio + $0 $opts adb + $0 $opts fb + $0 $opts rtc + $0 $opts isdn-io + ;; + generic-s390) + $0 $opts std + $0 $opts fd + $0 $opts dasda dasdb dasdc dasdd dasde dasdf dasdg dasdh \ + dasdi dasdj dasdk dasdl dasdm dasdn dasdo dasdp \ + dasdq dasdr dasds dasdt dasdu dasdv dasdw dasdx \ + dasdy dasdz + $0 $opts pty + $0 $opts consoleonly + $0 $opts rtc + ;; + generic-sh) + $0 $opts std + $0 $opts fd + $0 $opts fd0 fd1 + $0 $opts hd sd + $0 $opts scd0 scd1 + $0 $opts st0 st1 + $0 $opts sg + $0 $opts pty + $0 $opts console + $0 $opts ttyS0 ttyS1 ttyS2 ttyS3 ttyS4 + $0 $opts ttySC0 ttySC1 ttySC2 ttySC3 + $0 $opts lp + $0 $opts par + $0 $opts audio + $0 $opts fb + $0 $opts rtc + ;; + generic-sparc) + $0 $opts std + $0 $opts fd + $0 $opts fd0 fd1 + $0 $opts hd sd + $0 $opts scd0 scd1 + $0 $opts st0 st1 + $0 $opts sg + $0 $opts pty + $0 $opts console + $0 $opts ttyS0 ttyS1 ttyS2 ttyS3 ttyS4 + $0 $opts busmice + $0 $opts fb + $0 $opts rtc + makedev kbd c 11 0 $cons + makedev sunmouse c 10 6 $mouse + symlink mouse sunmouse + makedev openprom c 10 139 root root 0664 + ;; + local) + $0.local $opts + ;; + std) + makedev mem c 1 1 $kmem + makedev kmem c 1 2 $kmem + makedev null c 1 3 $public + makedev port c 1 4 $kmem + makedev zero c 1 5 $public + symlink core $procfs/kcore + makedev full c 1 7 $public + makedev random c 1 8 $public + makedev urandom c 1 9 $public + makedev tty c 5 0 $tty + $0 $opts ram + $0 $opts loop + ;; + hamradio) + $0 $opts scc + $0 $opts bc + ;; + scc) + for unit in 0 1 2 3 4 5 6 7 + do + makedev scc$unit c 34 $unit $system + done + ;; + mtd) + for unit in 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + do + makedev mtd$unit c 90 `math $unit \* 2` $system + done + ;; + bc) + for unit in 0 1 2 3 + do + makedev bc$unit c 51 $unit $system + done + ;; + random) + makedev random c 1 8 $public + ;; + urandom) + makedev urandom c 1 9 $readable + ;; + ram) + for i in 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ; do + makedev ram$i b 1 $i $disk + done + symlink ram ram1 + ;; + ram[0-9]|ram1[0-6]) + unit=`suffix $arg ram` + makedev ram$unit b 1 $unit $disk + ;; + initrd) + makedev initrd b 1 250 $disk + ;; + raw) + makedev rawctl c 162 0 $disk + mkdir -p raw + for i in 1 2 3 4 5 6 7 8; do + makedev raw/raw$i c 162 $i $disk + done + ;; + consoleonly) + makedev tty0 c 4 0 $cons + # new kernels need a device, old ones a symlink... sigh + kern_rev1=`uname -r | sed -e 's@^\([^.]*\)\..*@\1@'` + kern_rev2=`uname -r | sed -e 's@^[^.]*\.\([^.]*\)\..*@\1@'` + if [ $kern_rev1 -gt 2 ] + then + makedev console c 5 1 $cons + else + if [ $kern_rev1 -eq 2 ] && [ $kern_rev2 -ge 1 ] + then + makedev console c 5 1 $cons + else + symlink console tty0 + fi + fi + ;; + console) + $0 $opts consoleonly + major=`Major vcs 7` # not fatal + [ "$major" ] && makedev vcs0 c $major 0 $cons + symlink vcs vcs0 + [ "$major" ] && makedev vcsa0 c $major 128 $cons + symlink vcsa vcsa0 + # individual vts + line=1 + while [ $line -le $MAXVT ] && [ $line -le 63 ] + do + makedev tty$line c 4 $line $cons + [ "$major" ] && makedev vcs$line c $major $line $cons + [ "$major" ] && makedev vcsa$line c $major `math $line + 128` $cons + line=`math $line + 1` + done + ;; + adb) + # pick the right arch device using dpkg's knowledge + case `dpkg --print-architecture` in + powerpc) + # ADB bus devices (char) + makedev adb c 56 0 $mouse + makedev adbmouse c 10 10 $mouse + ;; + m68k) + # ACSI disk 2, whole device (block) + makedev adb b 28 16 $disk + for part in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + do + minor=$(( 16 + $part )) + makedev adb$part b 28 $minor $disk + done + ;; + *) + echo "no support for adb on this arch" >&2 + exit 1 + ;; + esac + ;; + raw1394) + makedev raw1394 c 171 0 $disk + ;; + video1394) + rm -f video1394 + mkdir -p video1394 + for i in `seq 0 15` + do + makedev video1394/$i c 171 `math 16 + $i` $video + done + ;; + alsa) + echo "You requested 'alsa' devices. Please install the alsa-base package instead," + echo "which creates and maintains device information for ALSA." + ;; + nvram) + makedev nvram c 10 144 $mouse + ;; + tty[1-9]|tty[1-5][0-9]|tty[6][0-3]) + line=`suffix $arg tty` + makedev tty$line c 4 $line $cons + ;; + ttyS[0-9]|ttyS[1-5][0-9]|ttyS[6][0-3]) + line=`suffix $arg ttyS` + minor=`math 64 + $line` + makedev ttyS$line c 4 $minor $dialout + ;; + ttySC[0-3]) + line=`suffix $arg ttySC` + minor=`math 8 + $line` + makedev ttySC$line c 204 $minor $dialout + ;; + ttyB[0-7]) + minor=`suffix $arg ttyB` + makedev ttyB$minor c 11 $minor $dialout + ;; + pty[a-ep-z]) + bank=`suffix $arg pty` + base=`index pqrstuvwxyzabcde $bank` + base=`math $base \* 16` + for i in 0 1 2 3 4 5 6 7 8 9 a b c d e f + do + j=`index 0123456789abcdef $i` + makedev pty$bank$i c 2 `math $base + $j` $tty + makedev tty$bank$i c 3 `math $base + $j` $tty + done + ;; + pty) + ptysufs="" + for i in p q r s t u v w x y z a b c d e + do + ptysufs="$ptysufs pty$i" + done + $0 $opts $ptysufs ptmx + ;; + ptmx) + # master pty multiplexer for 2.1 kernels + makedev ptmx c 5 2 $tty + ;; + cyclades|ttyC) + major1=`Major ttyC 19` || continue + #major2=`Major cub 20` || continue + for i in 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 \ + 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 + do + makedev ttyC$i c $major1 $i $dialout + #makedev cub$i c $major2 $i $dialout + done + ;; + stallion|ttyE) + major1=`Major ttyE 24` || continue + #major2=`Major cue 25` || continue + majorc=28 + minor=0 + until [ $minor -gt 256 ] + do + makedev ttyE$minor c $major1 $minor $dialout + #makedev cue$minor c $major2 $minor $dialout + minor=`math $minor + 1` + done + for i in 0 1 2 3 + do + makedev staliomem$i c $majorc $i $private + done + ;; + chase|ttyH) + major1=`Major ttyH 17` || continue + #major2=`Major cuh 18` || continue + minor=0 + until [ $minor -gt 16 ] # tell me if 16 is wrong + do + makedev ttyH$minor c $major1 $minor $dialout + #makedev cuh$minor c $major2 $minor $dialout + minor=`math $minor + 1` + done + ;; + rocketport|ttyR) + major1=`Major ttyR 46` || continue + #major2=`Major cur 47` || continue + minor=0 + until [ $minor -gt 64 ] # tell me if 64 is wrong + do + makedev ttyR$minor c $major1 $minor $dialout + #makedev cur$minor c $major2 $minor $dialout + minor=`math $minor + 1` + done + ;; + ttyV) + major1=`Major ttyV 105` || continue + #major2=`Major cuv 106` || continue + minor=0 + until [ $minor -gt 16 ] # tell me if 16 is wrong + do + makedev ttyV$minor c $major1 $minor $dialout + #makedev cuv$minor c $major2 $minor $dialout + minor=`math $minor + 1` + done + ;; + digi|ttyD) + major1=`Major ttyD 22` || continue + #major2=`Major cud 23` || continue + minor=0 + until [ $minor -gt 16 ] # tell me if 16 is wrong + do + makedev ttyD$minor c $major1 $minor $dialout + #makedev cud$minor c $major2 $minor $dialout + minor=`math $minor + 1` + done + ;; + specialix|ttyX) + major1=`Major ttyX 32` || continue + #major2=`Major cux 33` || continue + minor=0 + until [ $minor -gt 16 ] # tell me if 16 is wrong + do + makedev ttyX$minor c $major1 $minor $dialout + #makedev cux$minor c $major2 $minor $dialout + minor=`math $minor + 1` + done + ;; + specialixIO8|ttyW) + major1=`Major ttyW 75` || continue + #major2=`Major cuw 76` || continue + minor=0 + until [ $minor -gt 16 ] # tell me if 16 is wrong + do + makedev ttyW$minor c $major1 $minor $dialout + #makedev cuw$minor c $major2 $minor $dialout + minor=`math $minor + 1` + done + ;; + PAM|ttyM) + major1=`Major ttyM 79` || continue + #major2=`Major cum 80` || continue + minor=0 + until [ $minor -gt 16 ] # tell me if 16 is wrong + do + makedev ttyM$minor c $major1 $minor $dialout + #makedev cum$minor c $major2 $minor $dialout + minor=`math $minor + 1` + done + ;; + riscom|ttyL) + major=`Major ttyL 48` || continue + minor=0 + until [ $minor -gt 16 ] # tell me if 16 is wrong + do + makedev ttyL$minor c $major $minor $dialout + minor=`math $minor + 1` + done + ;; + computone|ttyF) + major=`Major ttyF 71` || continue + #major2=`Major cuf 72` || continue + minor=0 + until [ $minor -gt 255 ] + do + makedev ttyF$minor c $major $minor $dialout + #makedev cuf$minor c $major2 $minor $dialout + minor=`math $minor + 1` + done + major=73 + for i in 0 4 8 12 + do + makedev ip2ipl$i c $major $i $private + makedev ip2stat$i c $major `math $i + 1` $private + done + ;; + ESP|ttyP) + major=`Major ttyP 57` || continue + #major2=`Major cup 58` || continue + minor=0 + until [ $minor -gt 4 ] # tell me if 4 is wrong + do + makedev ttyP$minor c $major $minor $dialout + #makedev cup$minor c $major2 $minor $dialout + minor=`math $minor + 1` + done + ;; + COMX|comx) + major=`Major comx 88` || continue + minor=0 + until [ $minor -gt 4 ] # tell me if 4 is wrong + do + makedev comx$minor c $major $minor $private + minor=`math $minor + 1` + done + ;; + isdnmodem|ttyI) + major1=`Major ttyI 43` || continue + #major2=`Major cui 44` || continue + minor=0 + until [ $minor -gt 63 ] + do + makedev ttyI$minor c $major1 $minor $dialout + #makedev cui$minor c $major2 $minor $dialout + minor=`math $minor + 1` + done + ;; + isdnbri) + major=45 + minor=0 + until [ $minor -gt 63 ] + do + makedev isdn$minor c $major $minor $dialout + makedev isdnctrl$minor c $major `math $minor + 64` $dialout + makedev ippp$minor c $major `math $minor + 128` $dialout + minor=`math $minor + 1` + done + makedev isdninfo c $major 255 $private + ;; + dcbri) + major=52 + for i in 0 1 2 3 + do + makedev dcbri$i c $major $i $dialout + done + ;; + capi) + major=68 + makedev capi20 c $major 0 $dialout + for i in 0 1 2 3 4 5 6 7 8 9 + do + makedev capi20.0$i c $major `math $i + 1` $dialout + done + for i in 10 11 12 13 14 15 16 17 18 19 + do + makedev capi20.$i c $major `math $i + 1` $dialout + done + ;; + ubd) + major=98 + for devicenum in 0 1 2 3 4 5 6 7 + do + device=ubd`substr abcdefgh $(($devicenum + 1))` + baseminor=`math $devicenum \* 16` + makedev $device b $major $baseminor $disk + for partition in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + do + minor=`math $baseminor + $partition` + makedev $device$partition b $major $minor $disk + done + done + ;; + fb) + for i in 0 1 2 3 4 5 6 7 + do + makedev fb$i c 29 $i $video + done + ;; + fb[0-7]) + dev=`suffix $arg fb` + makedev fb$dev c 29 $dev $video + ;; + netlink|tap|tap[0-9]|tap1[0-5]) + makedev route c 36 0 $coda + makedev skip c 36 1 $coda + makedev fwmonitor c 36 3 $coda + for i in 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + do + makedev tap$i c 36 `math $i + 16` $coda + done + ;; + tun) + mkdir -p net + makedev net/tun c 10 200 $system + ;; + lp) + major=`Major lp 6` || continue + makedev ${arg}0 c $major 0 $printer + makedev ${arg}1 c $major 1 $printer + makedev ${arg}2 c $major 2 $printer + ;; + par) + major=`Major lp 6` || continue + makedev ${arg}0 c $major 0 $printer + makedev ${arg}1 c $major 1 $printer + makedev ${arg}2 c $major 2 $printer + ;; + parport) + major=`Major parport 99` || continue + makedev ${arg}0 c $major 0 $printer + makedev ${arg}1 c $major 1 $printer + makedev ${arg}2 c $major 2 $printer + ;; + slm) + major=`Major slm 28` || continue + for i in 0 1 2 3 + do + makedev slm c $major $i $printer + done + ;; + input) + major=`Major pcsp 13` || continue + mkdir -p input + for i in 0 1 2 3 + do + makedev input/js$i c $major $i $mouse + makedev input/mouse$i c $major `math $i + 32` $mouse + makedev input/event$i c $major `math $i + 64` $mouse + done + makedev input/mice c $major 63 $mouse + ;; + busmice) + major=`Major mouse 10` || continue + makedev logibm c $major 0 $mouse + makedev psaux c $major 1 $mouse + makedev inportbm c $major 2 $mouse + makedev atibm c $major 3 $mouse + makedev jbm c $major 4 $mouse + ;; + m68k-mice) + major=`Major mouse 10` || continue + makedev amigamouse c $major 4 $mouse + makedev atarimouse c $major 5 $mouse + makedev amigamouse1 c $major 7 $mouse + makedev adbmouse c $major 10 $mouse + ;; + 3dfx) + major=`Major $arg 107` || continue + makedev $arg c $major 0 $video + ;; + agpgart) + major=`Major $arg 10` || continue + makedev $arg c $major 175 $video + ;; + hwrng) + major=`Major $arg 10` || continue + makedev $arg c $major 183 $private + ;; + mcelog) + major=`Major $arg 10` || continue + makedev $arg c $major 227 $private + ;; + cpu|microcode) + mkdir -p cpu + makedev cpu/microcode c 10 184 $private + for i in 0 1 2 3 + do + mkdir -p cpu/$i + makedev cpu/$i/msr c 202 $i $private + makedev cpu/$i/cpuid c 203 $i $private + done + ;; + ipmi|ipmikcs) + major=`Major ipmikcs 10` || continue + makedev ipmikcs c $major 173 $private + ;; + irda) + for i in 0 1 + do + makedev ircomm$i c 161 $i $dialout + makedev irlpt$i c 161 `math $i + 16` $printer + done + ;; + irnet) + makedev irnet c 10 187 $system + ;; + cbm) + makedev cbm c 10 177 $floppy + ;; + misc) + major=`Major mouse 10` || continue + makedev logibm c $major 0 $mouse + makedev psaux c $major 1 $mouse + makedev inportbm c $major 2 $mouse + makedev atibm c $major 3 $mouse + makedev jbm c $major 4 $mouse + makedev amigamouse c $major 4 $mouse + makedev atarimouse c $major 5 $mouse + makedev sunmouse c $major 6 $mouse + makedev amigamouse1 c $major 7 $mouse + makedev smouse c $major 8 $mouse + makedev pc110pad c $major 9 $mouse + makedev adbmouse c $major 10 $mouse + makedev beep c $major 128 $mouse + makedev modreq c $major 129 $mouse + makedev watchdog c $major 130 $mouse + makedev temperature c $major 131 $mouse + makedev hwtrap c $major 132 $mouse + makedev exttrp c $major 133 $mouse + makedev apm_bios c $major 134 $mouse + makedev rtc c $major 135 $mouse + makedev openprom c $major 139 root root 0664 + makedev relay8 c $major 140 $mouse + makedev relay16 c $major 141 $mouse + makedev msr c $major 142 $mouse + makedev pciconf c $major 143 $mouse + makedev nvram c $major 144 $mouse + makedev hfmodem c $major 145 $mouse + makedev led c $major 151 $mouse + makedev mergemem c $major 153 $mouse + makedev pmu c $major 154 $mouse + ;; + fuse) + makedev fuse c 10 229 $system + ;; + pmu) + major=`Major mouse 10` || continue + makedev pmu c $major 154 $mouse + ;; + thinkpad) + major=`Major mouse 10` || continue + mkdir -p thinkpad + makedev thinkpad/thinkpad c $major 170 $mouse + ;; + rtc) + major=`Major mouse 10` || continue + makedev rtc c $major 135 $mouse + ;; + efirtc) + major=`Major mouse 10` || continue + makedev efirtc c $major 136 $mouse + ;; + mwave) + makedev mwave c 10 219 $mouse + ;; + systrace) + makedev systrace c 10 226 $private + ;; + uinput) + mkdir -p input + makedev input/uinput c 10 223 $mouse + ;; + js) + major=`Major Joystick 13` || continue + for unit in 0 1 2 3 + do + makedev js$unit c $major $unit $readable + makedev djs$unit c $major `math $unit + 128` $readable + done + ;; + fd[0-7]) + major=`Major fd 2` || continue + base=`suffix $arg fd` + if [ $base -ge 4 ] + then + base=`math $base + 124` + fi + makedev ${arg} b $major $base $floppy + makedev ${arg}d360 b $major `math $base + 4` $floppy + makedev ${arg}h1200 b $major `math $base + 8` $floppy + makedev ${arg}u360 b $major `math $base + 12` $floppy + makedev ${arg}u720 b $major `math $base + 16` $floppy + makedev ${arg}h360 b $major `math $base + 20` $floppy + makedev ${arg}h720 b $major `math $base + 24` $floppy + makedev ${arg}u1440 b $major `math $base + 28` $floppy + makedev ${arg}u2880 b $major `math $base + 32` $floppy + makedev ${arg}CompaQ b $major `math $base + 36` $floppy + + makedev ${arg}h1440 b $major `math $base + 40` $floppy + makedev ${arg}u1680 b $major `math $base + 44` $floppy + makedev ${arg}h410 b $major `math $base + 48` $floppy + makedev ${arg}u820 b $major `math $base + 52` $floppy + makedev ${arg}h1476 b $major `math $base + 56` $floppy + makedev ${arg}u1722 b $major `math $base + 60` $floppy + makedev ${arg}h420 b $major `math $base + 64` $floppy + makedev ${arg}u830 b $major `math $base + 68` $floppy + makedev ${arg}h1494 b $major `math $base + 72` $floppy + makedev ${arg}u1743 b $major `math $base + 76` $floppy + makedev ${arg}h880 b $major `math $base + 80` $floppy + makedev ${arg}u1040 b $major `math $base + 84` $floppy + makedev ${arg}u1120 b $major `math $base + 88` $floppy + makedev ${arg}h1600 b $major `math $base + 92` $floppy + makedev ${arg}u1760 b $major `math $base + 96` $floppy + makedev ${arg}u1920 b $major `math $base + 100` $floppy + makedev ${arg}u3200 b $major `math $base + 104` $floppy + makedev ${arg}u3520 b $major `math $base + 108` $floppy + makedev ${arg}u3840 b $major `math $base + 112` $floppy + makedev ${arg}u1840 b $major `math $base + 116` $floppy + makedev ${arg}u800 b $major `math $base + 120` $floppy + makedev ${arg}u1600 b $major `math $base + 124` $floppy + ;; + ed[a-b]) + major=`Major ed 36` || continue + unit=`suffix $arg ed` + base=`index ab $unit` + base=`math $base \* 64` + makedev ed$unit b $major $base $disk + for part in 1 2 3 4 5 6 7 8 # 9 10 11 12 13 14 15 16 17 18 19 20 + do + makedev ed$unit$part b $major `math $base + $part` $disk + done + ;; + hd[a-b]) + major=`Major ide0` || major=`Major hd 3` || continue + unit=`suffix $arg hd` + base=`index ab $unit` + base=`math $base \* 64` + makedev hd$unit b $major $base $disk + for part in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 + do + makedev hd$unit$part b $major `math $base + $part` $disk + done + ;; + hd[c-d]) + major=`Major ide1 22` || continue + unit=`suffix $arg hd` + base=`index cd $unit` + base=`math $base \* 64` + makedev hd$unit b $major $base $disk + for part in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 + do + makedev hd$unit$part b $major $(( $base + $part )) $disk + done + ;; + hd[e-f]) + major=`Major ide2 33` || continue + unit=`suffix $arg hd` + base=`index ef $unit` + base=`math $base \* 64` + makedev hd$unit b $major $base $disk + for part in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 + do + makedev hd$unit$part b $major $(( $base + $part )) $disk + done + ;; + hd[g-h]) + major=`Major ide3 34` || continue + unit=`suffix $arg hd` + base=`index gh $unit` + base=`math $base \* 64` + makedev hd$unit b $major $base $disk + for part in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 + do + makedev hd$unit$part b $major $(( $base + $part )) $disk + done + ;; + hd[i-j]) + major=`Major ide4 56` || continue + unit=`suffix $arg hd` + base=`index ij $unit` + base=`math $base \* 64` + makedev hd$unit b $major $base $disk + for part in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 + do + makedev hd$unit$part b $major $(( $base + $part )) $disk + done + ;; + hd[k-l]) + major=`Major ide5 57` || continue + unit=`suffix $arg hd` + base=`index kl $unit` + base=`math $base \* 64` + makedev hd$unit b $major $base $disk + for part in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 + do + makedev hd$unit$part b $major $(( $base + $part )) $disk + done + ;; + hd[m-n]) + major=`Major ide6 88` || continue + unit=`suffix $arg hd` + base=`index mn $unit` + base=`math $base \* 64` + makedev hd$unit b $major $base $disk + for part in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 + do + makedev hd$unit$part b $major $(( $base + $part )) $disk + done + ;; + hd[o-p]) + major=`Major ide7 89` || continue + unit=`suffix $arg hd` + base=`index op $unit` + base=`math $base \* 64` + makedev hd$unit b $major $base $disk + for part in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 + do + makedev hd$unit$part b $major $(( $base + $part )) $disk + done + ;; + hd[q-r]) + major=`Major ide8 90` || continue + unit=`suffix $arg hd` + base=`index qr $unit` + base=`math $base \* 64` + makedev hd$unit b $major $base $disk + for part in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 + do + makedev hd$unit$part b $major $(( $base + $part )) $disk + done + ;; + hd[s-t]) + major=`Major ide9 91` || continue + unit=`suffix $arg hd` + base=`index st $unit` + base=`math $base \* 64` + makedev hd$unit b $major $base $disk + for part in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 + do + makedev hd$unit$part b $major $(( $base + $part )) $disk + done + ;; + ub|uba) + major=180 + makedev uba b $major 0 $disk + for part in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + do + makedev uba$part b $major $part $disk + done + ;; + ht0) + major=`Major ht0 37` || continue + # Only one IDE tape drive is currently supported; ht0. + makedev ht0 c $major 0 $tape + makedev nht0 c $major 128 $tape + ;; + pt) + major=`Major pt 96` || continue + for i in 0 1 2 3 + do + makedev pt$i c $major $i $tape + makedev npt$i c $major `math $i + 128` $tape + done + ;; + xd[a-d]) + major=`Major xd 13` || continue + unit=`suffix $arg xd` + base=`index abcd $unit` + base=`math $base \* 64` + makedev xd$unit b $major $base $disk + for part in 1 2 3 4 5 6 7 8 # 9 10 11 12 13 14 15 16 17 18 19 20 + do + makedev xd$unit$part b $major $(( $base + $part )) $disk + done + ;; + sd[a-z]) + major=`Major sd 8` || continue + unit=`suffix $arg sd` + base=`index abcdefghijklmnopqrstuvwxyz $unit` + base=$(( $base * 16 )) + if [ $base -lt 256 ]; then + major=8 + else + major=65 + base=$(( $base - 256 )) + fi + makedev sd$unit b $major $base $disk + for part in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + do + minor=$(( $base + $part )) + makedev sd$unit$part b $major $minor $disk + done + ;; + sd[a-d][a-z]) + unit=`suffix $arg sd` + unitmaj=`first $unit` + unitmin=`second $unit` + basemaj=`index Xabcd $unitmaj` + basemin=`index abcdefghijklmnopqrstuvwxyz $unitmin` + basemaj=`math $basemaj \* 416` + basemin=`math $basemin \* 16` + base=`math $basemaj + $basemin` + basemaj=`math $base / 256` + base=`math $base % 256` + major=`math basemaj \+ 64` + if [ $major -gt 71 ]; then + echo "$0: don't know how to make device \"$arg\"" >&2 + exit 0 + fi + makedev sd$unit b $major $base $disk + for part in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + do + minor=$(( $base + $part )) + makedev sd$unit$part b $major $minor $disk + done + ;; + i2o.hd[a-z]) + [ -d i2o ] || { + mkdir i2o + chown root:root i2o + chmod 755 i2o + [ -e i2o/ctl ] || makedev i2o/ctl c 10 166 $disk + } + unit=`suffix $arg i2o.hd` + base=`index abcdefghijklmnopqrstuvwxyz $unit` + base=$(( $base * 16 )) + if [ $base -lt 256 ]; then + major=80 + else + major=81 + base=$(( $base - 256 )) + fi + makedev i2o/hd$unit b $major $base $disk + for part in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + do + minor=$(( $base + $part )) + makedev i2o/hd$unit$part b $major $minor $disk + done + ;; + i2o.hd[a-d][a-z]) + [ -d i2o ] || { + mkdir i2o + chown root:root i2o + chmod 755 i2o + [ -e i2o/ctl ] || makedev i2o/ctl c 10 166 $disk + } + unit=`suffix $arg i2o.hd` + unitmaj=`first $unit` + unitmin=`second $unit` + basemaj=`index Xabcd $unitmaj` + basemin=`index abcdefghijklmnopqrstuvwxyz $unitmin` + basemaj=`math $basemaj \* 416` + basemin=`math $basemin \* 16` + base=`math $basemaj + $basemin` + basemaj=`math $base / 256` + base=`math $base % 256` + major=`math basemaj \+ 80` + if [ $major -gt 87 ]; then + echo "$0: don't know how to make device \"$arg\"" >&2 + exit 0 + fi + makedev i2o/hd$unit b $major $base $disk + for part in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + do + minor=$(( $base + $part )) + makedev i2o/hd$unit$part b $major $minor $disk + done + ;; + dasd[a-z]) + major=`Major dasd 94` || continue + unit=`suffix $arg dasd` + base=`index abcdefghijklmnopqrstuvwxyz $unit` + base=$(( $base * 4 )) + if [ $base -lt 256 ]; then + major=94 + else + major=65 + base=$(( $base - 256 )) + fi + makedev dasd$unit b $major $base $disk + for part in 1 2 3 + do + minor=$(( $base + $part )) + makedev dasd$unit$part b $major $minor $disk + done + ;; + ad[a-p]) + major=`Major ad 28` || continue + unit=`suffix $arg ad` + base=`index abcdefghijklmnop $unit` + base=`math $base \* 16` + makedev ad$unit b $major $base $disk + for part in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + do + minor=$(( $base + $part )) + makedev ad$unit$part b $major $minor $disk + done + ;; + dac960) + for ctr in 0 1 2 3 4 5 6 7 + do + $0 $opts dac960.$ctr + done + makedev dac960_gam c 10 252 $disk + ;; + dac960.[0-7]) + [ -d rd ] || { + mkdir rd + chown root:root rd + chmod 755 rd + } + unit=`suffix $arg dac960.` + major=`math 48 + $unit` + minor=0 + for ld in 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 \ + 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 + do + makedev rd/c${unit}d${ld} b $major $minor $disk + minor=`math $minor + 1` + for part in 1 2 3 4 5 6 7 + do + makedev rd/c${unit}d${ld}p$part b $major $minor $disk + minor=`math $minor + 1` + done + done + ;; + dpti) + major=151 + for ld in 1 2 3 4 5 6 7 + do + minor=`math $ld -1` + makedev dpti${ld} c $major $minor $disk + done + ;; + ataraid) + for ctr in 0 1 2 # 3 4 5 6 7 + do + $0 $opts ataraid.$ctr + done + ;; + ataraid.[0-7]) + [ -d ataraid ] || { + mkdir ataraid + chown root:root ataraid + chmod 755 ataraid + } + unit=`suffix $arg ataraid.` + major=114 + minor=`math $unit \* 16` + makedev ataraid/d${unit} b $major $minor $disk + for part in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + do + minor=`math $minor + 1` + makedev ataraid/d${unit}p$part b $major $minor $disk + done + ;; + ida) + for ctr in 0 1 2 # 3 4 5 6 7 + do + $0 $opts ida.$ctr + done + ;; + ida.[0-7]) + [ -d ida ] || { + mkdir ida + chown root:root ida + chmod 755 ida + } + unit=`suffix $arg ida.` + major=`math 72 + $unit` + minor=0 + for ld in 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + do + makedev ida/c${unit}d${ld} b $major $minor $disk + minor=`math $minor + 1` + for part in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + do + makedev ida/c${unit}d${ld}p$part b $major $minor $disk + minor=`math $minor + 1` + done + done + ;; + cciss) + for ctr in 0 1 2 # 3 4 5 6 7 + do + $0 $opts cciss.$ctr + done + ;; + cciss.[0-7]) + [ -d cciss ] || { + mkdir cciss + chown root:root cciss + chmod 755 cciss + } + unit=`suffix $arg cciss.` + major=`math 104 + $unit` + minor=0 + for ld in 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + do + makedev cciss/c${unit}d${ld} b $major $minor $disk + minor=`math $minor + 1` + for part in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + do + makedev cciss/c${unit}d${ld}p$part b $major $minor $disk + minor=`math $minor + 1` + done + done + ;; + rom) + major=`Major rom 31` + for i in 0 1 2 3 4 5 6 7 + do + makedev rom$i b $major $i $disk + makedev rrom$i b $major `math $i +8` $disk + makedev flash$i b $major `math $i +16` $disk + makedev rflash$i b $major `math $i +24` $disk + done + ;; + nb[0-7]) + major=`Major nbd 43` || continue + minor=`suffix $arg nb` + makedev nb$minor b $major $minor $disk + ;; + loop) + for part in 0 1 2 3 4 5 6 7 + do + makedev loop$part b 7 $part $disk + done + ;; + loop[0-9]|loop[1-9][0-9]|loop1[0-9][0-9]|loop2[0-4][0-9]|loop25[0-5]) + minor=`suffix $arg loop` + makedev loop$minor b 7 $minor $disk + ;; + md) + major=`Major md 9` || continue + for part in 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 \ + 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 + do + makedev md$part b $major $part $disk + done + ;; + st[0-7]) + major=`Major st 9` + unit=`suffix $arg st` + makedev st${unit} c $major $unit $tape + makedev nst${unit} c $major `math 128 + $unit` $tape + + makedev st${unit}l c $major `math 32 + $unit` $tape + makedev nst${unit}l c $major `math 160 + $unit` $tape + + makedev st${unit}m c $major `math 64 + $unit` $tape + makedev nst${unit}m c $major `math 192 + $unit` $tape + + makedev st${unit}a c $major `math 96 + $unit` $tape + makedev nst${unit}a c $major `math 224 + $unit` $tape + ;; + qic) + major=`Major tpqic02 12` + makedev ntpqic11 c $major 2 $tape + makedev tpqic11 c $major 3 $tape + makedev ntpqic24 c $major 4 $tape + makedev tpqic24 c $major 5 $tape + makedev ntpqic120 c $major 6 $tape + makedev tpqic120 c $major 7 $tape + makedev ntpqic150 c $major 8 $tape + makedev tpqic150 c $major 9 $tape + makedev rmt8 c $major 6 $tape + makedev rmt16 c $major 8 $tape + makedev tape-d c $major 136 $tape + makedev tape-reset c $major 255 $tape + $0 $opts qft + ;; + ftape) + major=`Major qft 27` || continue + for unit in 0 1 2 3 + do + makedev qft$unit c $major $unit $tape + makedev nqft$unit c $major `math $unit + 4` $tape + makedev zqft$unit c $major `math $unit + 16` $tape + makedev nzqft$unit c $major `math $unit + 20` $tape + makedev rawqft$unit c $major `math $unit + 32` $tape + makedev nrawqft$unit c $major `math $unit + 36` $tape + done + symlink ftape qft0 + symlink nftape nqft0 + ;; + sr|scd|scd-all) + major=`Major sr 11` || continue + for unit in 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 + do + makedev scd$unit b $major $unit $cdrom + symlink sr$unit scd$unit + done + ;; + pktcdvd) + echo "pktcdvd major number is now dynamic, taking no action" + # major=97 + # for unit in 0 1 2 3 + # do + # makedev pktcdvd$unit b $major $unit $cdrom + # done + ;; + cfs0) + makedev cfs0 c 67 0 $coda + ;; + scd[0-9]|scd[0-1][0-9]) + major=`Major sr 11` || continue + unit=`suffix $arg scd` + makedev scd$unit b $major $unit $cdrom + symlink sr$unit scd$unit + ;; + ttyI[0-9]|ttyI[1-5][0-9]|ttyI[6][0-3]) + major=43 + unit=`suffix $arg ttyI` + makedev ttyI$unit c $major $unit $dialout + ;; + ppp) + major=108 + makedev ppp c $major 0 $dip + ;; + ippp[0-9]|ippp[1-5][0-9]|ippp[6][0-3]) + major=45 + unit=`suffix $arg ippp` + minor=`math $unit + 128` + makedev ippp$unit c $major $minor $dialout + ;; + isdn[0-9]|isdn[1-5][0-9]|isdn[6][0-3]) + major=45 + unit=`suffix $arg isdn` + minor=`math $unit + 0` + makedev isdn$unit c $major $minor $dialout + ;; + isdnctrl[0-9]|isdnctrl[1-5][0-9]|isdnctrl[6][0-3]) + major=45 + unit=`suffix $arg isdnctrl` + minor=`math $unit + 64` + makedev isdnctrl$unit c $major $minor $dialout + ;; + isdninfo) + makedev isdninfo c 45 255 $private + ;; + isdn-tty) + major=43 + for unit in 0 1 2 3 4 5 6 7 + do + makedev ttyI$unit c $major $unit $dialout + done + ;; + isdn-ippp) + major=45 + for unit in 0 1 2 3 4 5 6 7 + do + makedev ippp$unit c $major `math $unit + 128` $dialout + done + ;; + isdn-io) + for unit in 0 1 2 3 4 5 6 7 + do + makedev isdn$unit c 45 $unit $dialout + makedev isdnctrl$unit c 45 `math $unit + 64` $dialout + makedev ippp$unit c 45 `math $unit + 128` $dialout + done + makedev isdninfo c 45 255 $dialout + ;; + sonycd) + major=`Major sonycd 15` || continue + makedev $arg b $major 0 $cdrom + ;; + mcd) + major=`Major mcd 23` || continue + makedev $arg b $major 0 $cdrom + ;; + mcdx|mcdx[0-4]) + major=`Major $arg 20` || continue + for unit in 0 1 2 3 4 + do + makedev mcdx$unit b $major $unit $cdrom + done + test -r mcdx || symlink mcdx mcdx0 + ;; + cdu535) + makedev $arg b 24 0 $cdrom + ;; + lmscd) + makedev $arg b 24 0 $cdrom + ;; + sbpcd|sbpcd[123]) + major=`Major $arg 25` || continue + base=`suffix ${arg}0 sbpcd` + for minor in 0 1 2 3 + do + # XXX + unit=$(substr 0123456789abcdef $(( $base * 4 + $minor + 1 )) ) + makedev sbpcd$unit b $major $minor $cdrom + done + [ $arg = sbpcd ] && symlink $arg ${arg}0 + ;; + aztcd) + major=`Major $arg 29` || continue + makedev ${arg}0 b $major 0 $cdrom + ;; + cm206cd) + major=`Major $arg 30` || continue + makedev ${arg}0 b $major 0 $cdrom + ;; + gscd) + major=`Major $arg 16` || continue + makedev ${arg}0 b $major 0 $cdrom + ;; + pcd) + for unit in 0 1 2 3 + do + makedev pcd$unit b 46 $unit $cdrom + done + ;; + bpcd) + makedev $arg b 41 0 $cdrom + ;; + optcd) + makedev $arg b 17 0 $cdrom + ;; + sjcd) + makedev $arg b 18 0 $cdrom + ;; + cfs|coda) + makedev cfs0 c 67 0 $private + ;; + xfs|nnpfs|arla) + makedev xfs0 c 103 0 $private + makedev nnpfs0 c 103 0 $private + ;; + logiscan) + major=`Major logiscan` || continue + makedev $arg c $major 0 $scanner + ;; + toshiba) + major=`Major $arg 10` || continue + makedev $arg c $major 181 root root 0666 + ;; + m105scan) + major=`Major m105` || continue + makedev $arg c $major 0 $scanner + ;; + ac4096) + major=`Major ac4096` || continue + makedev $arg c $major 0 $scanner + ;; + audio) + major=`Major sound 14` + makedev mixer c $major 0 $audio + makedev mixer1 c $major 16 $audio + makedev mixer2 c $major 32 $audio + makedev mixer3 c $major 48 $audio + makedev sequencer c $major 1 $audio + makedev midi00 c $major 2 $audio + makedev midi01 c $major 18 $audio + makedev midi02 c $major 34 $audio + makedev midi03 c $major 50 $audio + makedev dsp c $major 3 $audio + makedev dsp1 c $major 19 $audio + makedev dsp2 c $major 35 $audio + makedev dsp3 c $major 51 $audio + makedev audio c $major 4 $audio + makedev audio1 c $major 20 $audio + makedev audio2 c $major 36 $audio + makedev audio3 c $major 52 $audio + makedev sndstat c $major 6 $audio + makedev audioctl c $major 7 $audio + major=31 + makedev mpu401data c $major 0 $audio + makedev mpu401stat c $major 1 $audio + major=35 + for i in 0 1 2 3 + do + makedev midi$i c $major $i $audio + makedev rmidi$i c $major `math $i + 64` $audio + makedev smpte$i c $major `math $i + 128` $audio + done + ;; + pcaudio) + major=`Major pcsp 13` || continue + makedev pcmixer c $major 0 $audio + makedev pcsp c $major 3 $audio + makedev pcaudio c $major 4 $audio + ;; + video|video4linux|v4l|radio) + # video4linux api includes radio, teletext, etc. + major=`Major video 81` || continue + minor=0 + until [ $minor -gt 63 ] + do + makedev video$minor c $major $minor $video + makedev radio$minor c $major `math $minor + 64` $video + minor=`math $minor + 1` + done + symlink radio radio0 + minor=0 + until [ $minor -gt 31 ] + do + makedev vtx$minor c $major `math $minor + 192` $video + makedev vbi$minor c $major `math $minor + 224` $video + minor=`math $minor + 1` + done + symlink video video0 + symlink vbi vbi0 + major=82 + minor=0 + until [ $minor -gt 1 ] + do + makedev winradio$minor c $major $minor $video + minor=`math $minor + 1` + done + major=83 + makedev vtx c $major 0 $video + makedev vttuner c $major 16 $video + ;; + i2c) + # making it possible to create an arbitrary number of i2c + # devices might be good, but 8 should suffice for now + major=`Major i2c 89` || continue + minor=0 + until [ $minor -gt 7 ] + do + makedev i2c-$minor c $major $minor $private + minor=`math $minor + 1` + done + ;; + tlk) + major=102 + minor=0 + until [ $minor -gt 3 ] # tell me if 3 is wrong... + do + makedev tlk$minor c $major $minor $video + minor=`math $minor + 1` + done + ;; + srnd) + makedev srnd0 c 110 0 $video + makedev srnd1 c 110 1 $video + ;; + fgrab) + makedev mmetfgrab c 40 0 $video + makedev wvisfgrab c 26 0 $video + for i in 0 1 # more? + do + makedev iscc$i c 93 $i $video + makedev isccctl$i c 93 `math $i + 128` $video + done + for i in 0 1 # more? + do + makedev dcxx$i c 94 $i $video + done + ;; + sg|sg-all) + major=`Major sg 21` + for unit in 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 + do + makedev sg$unit c $major $unit $scsi + done + ;; + pg) + major=`Major pg 97` + for unit in 0 1 2 3 + do + makedev pg$unit c $major $unit $scsi + done + ;; + fd) + # not really devices, we use the /proc filesystem + symlink fd $procfs/self/fd + symlink stdin fd/0 + symlink stdout fd/1 + symlink stderr fd/2 + ;; + ibcs2) + major=`Major ibcs2 30` || continue + makedev socksys c $major 0 $ibcs2 + symlink nfsd socksys + makedev spx c $major 1 $ibcs2 + symlink X0R null + ;; + netlink) + major=36 + makedev route c $major 0 $private + makedev skip c $major 1 $private + ;; + enskip) + major=64 + makedev enskip c $major 0 $private + ;; + ipfilt*) + major=95 + makedev ipl c $major 0 $private + makedev ipnat c $major 1 $private + makedev ipstate c $major 2 $private + makedev ipauth c $major 3 $private + ;; + qng) + makedev qng c 77 0 $private + ;; + apm) + major=`Major mouse 10` || continue + makedev apm_bios c $major 134 $mouse + ;; + dcf) + major=`Major dcf` || continue + makedev $arg c $major 0 $system + ;; + helloworld) + major=`Major hw` || continue + makedev helloworld c $major 0 $public + ;; + ipsec) + # For the Free S/WAN (http://www.xs4all.nl/~freeswan/) + # implementation of IPSEC + makedev ipsec c 36 10 $ipsec + ;; + comedi) + major=98 + for minor in 0 1 2 3 + do + makedev comedi$minor c $major $minor $public + done + ;; + tilp) + for i in `seq 0 7` + do + makedev tipar$i c 115 $i $printer + makedev tiser$i c 115 `math 8 + $i` $dialout + done + for i in `seq 0 31` + do + makedev tiusb$i c 115 `math 16 + $i` $dialout + done + ;; + dvb) + # check if kernel-version is >= 2.6.8, if yes, create dvb-devices with + # major-number 212, in the other case 250 + + kern_rev1=`uname -r | sed -e 's@^\([^.]*\)\..*@\1@'` + kern_rev2=`uname -r | sed -e 's@^[^.]*\.\([^.]*\)\..*@\1@'` + kern_rev3=`uname -r | sed -e 's@^[^.]*\.[^.]*\.\([^.][0-9]*\).*@\1@'` + + dvb_major=250 + + if [ $kern_rev1 -gt 2 ] || ([ $kern_rev1 -eq 2 ] && [ $kern_rev2 -gt 6 ]) \ + || ([ $kern_rev1 -eq 2 ] && [ $kern_rev2 -eq 6 ] && [ $kern_rev3 -ge 8 ]) + then + dvb_major=212 + fi + + mkdir -p dvb + for i in 0 1 2 3 + do + mkdir -p dvb/adapter$i + makedev dvb/adapter$i/video0 c $dvb_major `math 64 \* $i + 0` $video + makedev dvb/adapter$i/audio0 c $dvb_major `math 64 \* $i + 1` $video + makedev dvb/adapter$i/frontend0 c $dvb_major `math 64 \* $i + 3` $video + makedev dvb/adapter$i/demux0 c $dvb_major `math 64 \* $i + 4` $video + makedev dvb/adapter$i/dvr0 c $dvb_major `math 64 \* $i + 5` $video + makedev dvb/adapter$i/ca0 c $dvb_major `math 64 \* $i + 6` $video + makedev dvb/adapter$i/net0 c $dvb_major `math 64 \* $i + 7` $video + makedev dvb/adapter$i/osd0 c $dvb_major `math 64 \* $i + 8` $video + done + ;; + usb) + mkdir -p usb + major=180 + for i in 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + do + makedev usb/lp$i c $major $i $printer + makedev usb/mouse$i c $major `math $i + 16` $mouse + makedev usb/ez$i c $major `math $i + 32` $system + makedev usb/scanner$i c $major `math $i + 48` $scanner + makedev usb/hiddev$i c $major `math $i + 96` $system + makedev ttyACM$i c 166 $i $dialout + makedev ttyUSB$i c 188 $i $dialout + done + makedev usb/rio500 c $major 64 $audio + makedev usb/usblcd c $major 65 $audio + makedev usb/cpad0 c $major 66 $audio + ;; + bluetooth) + major=216 + for i in 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 \ + 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 + do + makedev rfcomm$i c $major $i $dialout + done + makedev vhci c 10 250 $dialout + for i in 0 1 2 3; do + makedev ttyUB$i c 216 $i $dialout + makedev ccub$i c 217 $i $dialout + done + ;; + paride) + major=45 + for unit in a b c d + do + base=`index abcd $unit` + base=`math $base \* 16` + makedev pd$unit b $major $base $disk + for part in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + do + makedev pd$unit$part b $major $(( $base + $part )) $disk + done + done + for i in 0 1 2 3 + do + makedev pcd$i b 46 $i $cdrom + makedev pf$i b 47 $i $floppy + done + ;; + lirc) + makedev lirc c 61 0 $lirc + for i in d m; do + makefifo lirc${i} $lirc + done + ;; + update) + devices= + if [ ! -f $procfs/devices ] + then + echo "$0: warning: can't read $procfs/devices" >&2 + else + exec 3<$procfs/devices + while read major device extra <&3 + do + device=`echo $device | sed 's#/.*##'` + case "$major" in + Character|Block|'') + ;; + *) + eval "major_$device=$major" + devices="$devices $device" + ;; + esac + done + exec 3<&- + fi + + if [ ! "$devices" ] + then + echo "$0: don't appear to have any devices" >&2 + continue + fi + if [ "$opt_d" ] + then + echo "$0: can't delete an update" >&2 + continue + fi + create= + delete= + devs="$devices" + if [ -f DEVICES ] + then + exec 3 DEVICES + ;; + *) + echo "$0: don't know how to make device \"$arg\"" >&2 + exit 1 + ;; + esac +done + +exit 0 From 21a0c597831e8f74fd7c99ac9af884aa63d772e3 Mon Sep 17 00:00:00 2001 From: Peter Gossner Date: Fri, 26 Aug 2016 22:46:08 +0930 Subject: [PATCH 13/13] modified: example/initramfs/hooks/vdev Some tidy ups and gentle extensions Most important change is to ensure i386 build of initramfs (libc naming conventions ?) --- example/initramfs/hooks/vdev | 42 ++++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/example/initramfs/hooks/vdev b/example/initramfs/hooks/vdev index abe6a79..664c345 100755 --- a/example/initramfs/hooks/vdev +++ b/example/initramfs/hooks/vdev @@ -1,6 +1,6 @@ #!/bin/sh -e - -## set -x +# posix shell or maybe dash only +#debug# set -x PREREQS="" @@ -15,16 +15,20 @@ esac . /usr/share/initramfs-tools/hook-functions -# Needed for keyboard +# Needed for keyboard or most mice +# see: /dev/input/* -force_load evdev || echo "eventfs (mod evdev ?) not preloaded" && sleep 2 +force_load evdev +if [ $? != 0 ]; then + echo "WARNING:[Xorg] eventfs _may_ not present X with keyboard or mouse devices" + sleep 2; +fi # helper programs mkdir -vp $DESTDIR/lib/vdev for prog in /lib/vdev/*; do - # shell script or library? if [ -z "${prog#*.sh}" ]; then cp -a $prog $DESTDIR/lib/vdev/ @@ -43,7 +47,7 @@ fi # config mkdir -pv $DESTDIR/etc/vdev -cp -a /etc/vdev/* $DESTDIR/etc/vdev/ +cp -avf /etc/vdev/* $DESTDIR/etc/vdev/ # the daemon itself copy_exec /sbin/vdevd @@ -52,26 +56,30 @@ copy_exec /sbin/vdevd if [ -f /sbin/blkid ]; then copy_exec /sbin/blkid else - echo "WARN: could not find blkid in /sbin/blkid. /dev/disk symlinks will not be created." + echo "WARN: could not find blkid in /sbin/blkid." + echo " /dev/disk symlinks will not be created." fi # lvm tools (needed by vdevd's helpers) if [ -f /sbin/lvs ]; then copy_exec /sbin/lvs else - echo "WARN: could not find lvs in /sbin/lvs. Logical volume symlinks will not be created." + echo "WARN: could not find lvs in /sbin/lvs." + echo " Logical volume symlinks will not be created." fi if [ -f /sbin/pvs ]; then copy_exec /sbin/pvs else - echo "WARN: could not find pvs in /sbin/pvs. Physical volume symlinks will not be created." + echo "WARN: could not find pvs in /sbin/pvs." + echo " Physical volume symlinks will not be created." fi if [ -f /sbin/lvm ]; then copy_exec /sbin/lvm else - echo "WARN: could not find lvm in /sbin/lvm. Logical volume symlinks will not be created." + echo "WARN: could not find lvm in /sbin/lvm." + echo " Logical volume symlinks will not be created." fi # # network tools (needed by vdevd's helpers) @@ -80,7 +88,7 @@ fi # if ! [ -f /sbin/ip ] && ! [ -f /bin/ip ]; then echo "WARN: could not find iproute2 in /bin/ip or /sbin/ip." - echo "Network interfaces will not be configured." + echo " Networking may not be available" fi if [ -f /bin/ip ]; then @@ -92,28 +100,29 @@ if [ -f /sbin/ip ]; then else [ -f /sbin/ifconfig ]; then # try the classical tool copy_exec /sbin/ifconfig - echo "installing /sbin/ifconfig as networking tool" + echo "NOTE: installing /sbin/ifconfig as networking tool" fi - # SELinux tools if [ -f /sbin/restorecon ]; then copy_exec /sbin/restorecon || true fi # device tools +# prefer most current if [ -f /sbin/MAKEDEV ]; then copy_exec /sbin/MAKEDEV else echo "WARNING: No MAKEDEV found to install" - echo "vdev --once may be your best alterenative" + echo "vdev --once may be your best alternative" fi # device mapper tools if [ -f /sbin/dmsetup ]; then copy_exec /sbin/dmsetup else - echo "WARN: could not find dmsetup in /sbin/dmsetup. Device mapper symlinks will not be created." + echo "WARN: could not find dmsetup in /sbin/dmsetup." + echo " Device mapper symlinks will not be created." fi # hardware database @@ -122,7 +131,8 @@ if [ -f /lib/vdev/hwdb/hwdb.squashfs ]; then mkdir -p $DESTDIR/lib/vdev/hwdb cp -a /lib/vdev/hwdb/hwdb.squashfs $DESTDIR/lib/vdev/hwdb else - echo "WARN: could not find hardware database in /lib/vdev/hwdb. Some hardware metadata may not be generated." + echo "WARN: could not find hardware database in /lib/vdev/hwdb." + echo "Some hardware metadata may not be generated." sleep 2 fi