replace libsysfs

We never used any of the libsysfs convenience features. Here we replace
it completely with 300 lines of code, which are much simpler and a bit
faster cause udev(d) does not open any syfs file for a simple event which
does not need any parent device information.

Signed-off-by: Kay Sievers <kay.sievers@suse.de>
This commit is contained in:
Kay Sievers
2006-01-09 21:18:00 +01:00
parent 47fbf3c582
commit 1aa1e24848
69 changed files with 1380 additions and 7319 deletions
+4 -26
View File
@@ -58,7 +58,6 @@ PROGRAMS = \
HEADERS = \
udev.h \
udev_utils.h \
udev_rules.h \
logging.h \
udev_libc_wrapper.h \
@@ -66,12 +65,12 @@ HEADERS = \
list.h
UDEV_OBJS = \
udev_event.o \
udev_device.o \
udev_config.o \
udev_add.o \
udev_remove.o \
udev_db.o \
udev_sysfs.o \
udev_rules.o \
udev_rules_parse.o \
udev_utils.o \
@@ -90,15 +89,6 @@ MAN_PAGES = \
udevinfo.8 \
udevstart.8
SYSFS_OBJS = \
libsysfs/sysfs_class.o \
libsysfs/sysfs_device.o \
libsysfs/sysfs_dir.o \
libsysfs/sysfs_driver.o \
libsysfs/sysfs_utils.o \
libsysfs/dlist.o
LIBSYSFS = libsysfs/libsysfs.a
# config files automatically generated
GEN_CONFIGS = \
$(LOCAL_CFG_DIR)/udev.conf
@@ -144,10 +134,6 @@ LDFLAGS = -Wl,-warn-common
OPTFLAGS = -Os
CFLAGS += $(OPTFLAGS)
# include our local copy of libsysfs
CFLAGS += -I$(PWD)/libsysfs/sysfs \
-I$(PWD)/libsysfs
ifeq ($(strip $(USE_LOG)),true)
CFLAGS += -DUSE_LOG
endif
@@ -200,7 +186,6 @@ all: $(PROGRAMS) $(MAN_PAGES)
STRIPCMD="$(STRIPCMD)" \
LIB_OBJS="$(LIB_OBJS)" \
LIBUDEV="$(PWD)/$(LIBUDEV)" \
LIBSYSFS="$(PWD)/$(LIBSYSFS)" \
QUIET="$(QUIET)" \
-C $$target $@ || exit 1; \
done;
@@ -211,28 +196,21 @@ all: $(PROGRAMS) $(MAN_PAGES)
.SUFFIXES:
# build the objects
%.o: %.c $(HOST_PROGS) $(GEN_HEADERS)
%.o: %.c $(HOST_PROGS) $(HEADERS) $(GEN_HEADERS)
$(QUIET) $(CC) -c $(CFLAGS) $< -o $@
# "Static Pattern Rule" to build all programs
$(PROGRAMS): %: $(HOST_PROGS) $(HEADERS) $(GEN_HEADERS) $(LIBSYSFS) $(LIBUDEV) %.o
$(QUIET) $(LD) $(LDFLAGS) $@.o -o $@ $(LIBUDEV) $(LIBSYSFS) $(LIB_OBJS)
$(PROGRAMS): %: $(HOST_PROGS) $(HEADERS) $(GEN_HEADERS) $(LIBUDEV) %.o
$(QUIET) $(LD) $(LDFLAGS) $@.o -o $@ $(LIBUDEV) $(LIB_OBJS)
ifneq ($(STRIPCMD),)
$(QUIET) $(STRIPCMD) $@
endif
$(UDEV_OBJS):
$(LIBUDEV): $(HOST_PROGS) $(HEADERS) $(GEN_HEADERS) $(UDEV_OBJS)
@rm -f $@
$(QUIET) $(AR) cq $@ $(UDEV_OBJS)
$(QUIET) $(RANLIB) $@
$(SYSFS_OBJS):
$(LIBSYSFS): $(HOST_PROGS) $(SYSFS_OBJS)
@rm -f $@
$(QUIET) $(AR) cq $@ $(SYSFS_OBJS)
$(QUIET) $(RANLIB) $@
# generate config files
$(GEN_CONFIGS):
sed -e "s:@udevdir@:$(udevdir):" -e "s:@configdir@:$(configdir):" < $@.in > $@
+8
View File
@@ -1,5 +1,11 @@
udev 080
========
Complete removal of libsysfs, replaced by simple helper functions
which are much simpler and a bit faster. The udev daemon operatesentirely
on event parameters and does not use sysfs for simple rules anymore.
Please report any new bugs/problems, that may be caused by this big
change. They will be fixed immediately.
The enumeration format character '%e' is deprecated and will be
removed sometimes from a future udev version. It never worked correctly
outside of udevstart, so we can't use it with the new parallel
@@ -10,6 +16,8 @@ MODALIAS and $modalias is not needed and will be removed from one of
the next udev versions, replace it in all rules with ENV{MODALIAS} or
the sysfs "modalias" value.
Thanks a lot to Marco for all his help on finding and fixing bugs.
udev 079
========
Let scsi_id request libata drive serial numbers from page 0x80.
-7
View File
@@ -361,13 +361,6 @@
</listitem>
</varlistentry>
<varlistentry>
<term><option>%b</option>, <option>$id</option></term>
<listitem>
<para>The kernel bus id for this device.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>%n</option>, <option>$number</option></term>
<listitem>
+1 -1
View File
@@ -37,7 +37,7 @@
<refsynopsisdiv>
<cmdsynopsis>
<command>udevtest <filename>device-path</filename> <replaceable>subsystem</replaceable></command>
<command>udevtest <filename>device-path</filename></command>
</cmdsynopsis>
</refsynopsisdiv>
+1 -1
View File
@@ -33,7 +33,7 @@ all: $(PROG) $(MAN_PAGES)
$(QUIET) $(CC) -c $(CFLAGS) $< -o $@
$(PROG): %: $(HEADERS) %.o $(OBJS)
$(QUIET) $(LD) $(LDFLAGS) $@.o $(OBJS) -o $@ $(LIBUDEV) $(LIBSYSFS) $(LIB_OBJS)
$(QUIET) $(LD) $(LDFLAGS) $@.o $(OBJS) -o $@ $(LIBUDEV) $(LIB_OBJS)
ifneq ($(STRIPCMD),)
$(QUIET) $(STRIPCMD) $@
endif
+2 -2
View File
@@ -17,6 +17,7 @@
#include <unistd.h>
#include <fcntl.h>
#include <ctype.h>
#include <string.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/types.h>
@@ -24,8 +25,7 @@
#include <linux/types.h>
#include <linux/hdreg.h>
#include "../../logging.h"
#include "../../udev_utils.h"
#include "../../udev.h"
#ifdef USE_LOG
void log_message(int priority, const char *format, ...)
+1 -1
View File
@@ -33,7 +33,7 @@ all: $(PROG) $(MAN_PAGES)
$(QUIET) $(CC) -c $(CFLAGS) $< -o $@
$(PROG): %: $(HEADERS) %.o $(OBJS)
$(QUIET) $(LD) $(LDFLAGS) $@.o $(OBJS) -o $@ $(LIBUDEV) $(LIBSYSFS) $(LIB_OBJS)
$(QUIET) $(LD) $(LDFLAGS) $@.o $(OBJS) -o $@ $(LIBUDEV) $(LIB_OBJS)
ifneq ($(strip $(STRIPCMD)),)
$(QUIET) $(STRIPCMD) $@
endif
+2 -2
View File
@@ -18,14 +18,14 @@
#include <unistd.h>
#include <fcntl.h>
#include <ctype.h>
#include <string.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <linux/types.h>
#include "../../logging.h"
#include "../../udev_utils.h"
#include "../../udev.h"
/*
* Taken from the cdrom.h kernel include file.
+1 -1
View File
@@ -33,7 +33,7 @@ all: $(PROG) $(MAN_PAGES)
$(QUIET) $(CC) -c $(CFLAGS) $< -o $@
$(PROG): %: $(HEADERS) %.o $(OBJS)
$(QUIET) $(LD) $(LDFLAGS) $@.o $(OBJS) -o $@ $(LIBUDEV) $(LIBSYSFS) $(LIB_OBJS)
$(QUIET) $(LD) $(LDFLAGS) $@.o $(OBJS) -o $@ $(LIBUDEV) $(LIB_OBJS)
ifneq ($(strip $(STRIPCMD)),)
$(QUIET) $(STRIPCMD) $@
endif
+1 -2
View File
@@ -24,8 +24,7 @@
#include <errno.h>
#include <sys/ioctl.h>
#include "../../logging.h"
#include "../../udev_utils.h"
#include "../../udev.h"
#ifdef USE_LOG
void log_message(int priority, const char *format, ...)
+1 -1
View File
@@ -33,7 +33,7 @@ all: $(PROG) $(MAN_PAGES)
$(QUIET) $(CC) -c $(CFLAGS) $< -o $@
$(PROG): %: $(HEADERS) %.o $(OBJS)
$(QUIET) $(LD) $(LDFLAGS) $@.o $(OBJS) -o $@ $(LIBUDEV) $(LIBSYSFS) $(LIB_OBJS)
$(QUIET) $(LD) $(LDFLAGS) $@.o $(OBJS) -o $@ $(LIBUDEV) $(LIB_OBJS)
ifneq ($(strip $(STRIPCMD)),)
$(QUIET) $(STRIPCMD) $@
endif
+2 -2
View File
@@ -18,12 +18,12 @@
#include <unistd.h>
#include <fcntl.h>
#include <ctype.h>
#include <string.h>
#include <errno.h>
#include <dirent.h>
#include <stdint.h>
#include "../../logging.h"
#include "../../udev_utils.h"
#include "../../udev.h"
#ifdef USE_LOG
void log_message(int priority, const char *format, ...)
+1 -1
View File
@@ -33,7 +33,7 @@ all: $(PROG) $(MAN_PAGES)
$(QUIET) $(CC) -c $(CFLAGS) $< -o $@
$(PROG): %: $(HEADERS) %.o $(OBJS)
$(QUIET) $(LD) $(LDFLAGS) $@.o $(OBJS) -o $@ $(LIBUDEV) $(LIBSYSFS) $(LIB_OBJS)
$(QUIET) $(LD) $(LDFLAGS) $@.o $(OBJS) -o $@ $(LIBUDEV) $(LIB_OBJS)
ifneq ($(strip $(STRIPCMD)),)
$(QUIET) $(STRIPCMD) $@
endif
+1 -2
View File
@@ -17,8 +17,7 @@
#include <unistd.h>
#include <sys/stat.h>
#include "../../udev_utils.h"
#include "../../logging.h"
#include "../../udev.h"
#define FIRMWARE_PATH "/lib/firmware"
#define PATH_SIZE 256
+1 -1
View File
@@ -33,7 +33,7 @@ all: $(PROG) $(MAN_PAGES)
$(QUIET) $(CC) -c $(CFLAGS) $< -o $@
$(PROG): %: $(HEADERS) %.o $(OBJS)
$(QUIET) $(LD) $(LDFLAGS) $@.o $(OBJS) -o $@ $(LIBUDEV) $(LIBSYSFS) $(LIB_OBJS)
$(QUIET) $(LD) $(LDFLAGS) $@.o $(OBJS) -o $@ $(LIBUDEV) $(LIB_OBJS)
ifneq ($(strip $(STRIPCMD)),)
$(QUIET) $(STRIPCMD) $@
endif
+1 -1
View File
@@ -32,7 +32,7 @@ all: $(PROG) $(MAN_PAGES)
$(QUIET) $(CC) -c $(CFLAGS) $< -o $@
$(PROG): %: $(HEADERS) %.o $(OBJS)
$(QUIET) $(LD) $(LDFLAGS) $@.o $(OBJS) -o $@ $(LIBUDEV) $(LIBSYSFS) $(LIB_OBJS)
$(QUIET) $(LD) $(LDFLAGS) $@.o $(OBJS) -o $@ $(LIBUDEV) $(LIB_OBJS)
ifneq ($(strip $(STRIPCMD)),)
$(QUIET) $(STRIPCMD) $@
endif
+1 -3
View File
@@ -22,9 +22,7 @@
#include <sys/wait.h>
#include <sys/stat.h>
#include "../../udev_utils.h"
#include "../../list.h"
#include "../../logging.h"
#include "../../udev.h"
#include "run_directory.h"
static int exec_program(const char *filename, const char *subsystem)
+1 -3
View File
@@ -22,9 +22,7 @@
#include <sys/wait.h>
#include <sys/stat.h>
#include "../../udev_utils.h"
#include "../../list.h"
#include "../../logging.h"
#include "../../udev.h"
#include "run_directory.h"
+1 -3
View File
@@ -22,9 +22,7 @@
#include <sys/wait.h>
#include <sys/stat.h>
#include "../../udev_utils.h"
#include "../../list.h"
#include "../../logging.h"
#include "../../udev.h"
#include "run_directory.h"
+1 -2
View File
@@ -29,7 +29,6 @@ INSTALL_DATA = ${INSTALL} -m 644
INSTALL_SCRIPT = ${INSTALL_PROGRAM}
# be able to run without udev
LIBSYSFS = -lsysfs
CROSS =
QUIET =
CC = $(CROSS)gcc
@@ -47,7 +46,7 @@ all: $(PROG) $(MAN_PAGES)
$(QUIET) $(CC) -c $(CFLAGS) $< -o $@
$(PROG): %: $(HEADERS) %.o $(OBJS)
$(QUIET) $(LD) $(LDFLAGS) $@.o $(OBJS) -o $@ $(LIBUDEV) $(LIBSYSFS) $(LIB_OBJS)
$(QUIET) $(LD) $(LDFLAGS) $@.o $(OBJS) -o $@ $(LIBUDEV) $(LIB_OBJS)
ifneq ($(strip $(STRIPCMD)),)
$(QUIET) $(STRIPCMD) $@
endif
+146 -292
View File
@@ -32,37 +32,20 @@
#include <stdarg.h>
#include <ctype.h>
#include <sys/stat.h>
#include <sysfs/libsysfs.h>
#include "scsi_id_version.h"
#include "../../udev.h"
#include "scsi_id.h"
#include "scsi_id_version.h"
#ifndef SCSI_ID_VERSION
#warning No version
#define SCSI_ID_VERSION "unknown"
#endif
/* temporary names for mknod */
#define TMP_DIR "/dev"
#define TMP_PREFIX "tmp-scsi"
/*
* temporary names for mknod.
*/
#define TMP_DIR "/dev"
#define TMP_PREFIX "tmp-scsi"
/*
* XXX Note the 'e' (send output to stderr in all cases), and 'c' (callout)
* options are not supported, but other code is still left in place for
* now.
*/
static const char short_options[] = "abd:f:gip:s:uvVx";
/*
* Just duplicate per dev options.
*/
static const char dev_short_options[] = "bgp:";
char sysfs_mnt_path[SYSFS_PATH_MAX];
static int all_good;
static int always_info;
static char *default_callout;
static int dev_specified;
static int sys_specified;
static char config_file[MAX_NAME_LEN] = SCSI_ID_CONFIG_FILE;
@@ -78,28 +61,30 @@ static char model_str[64];
static char revision_str[16];
static char type_str[16];
void log_message (int level, const char *format, ...)
#ifdef USE_LOG
void log_message(int priority, const char *format, ...)
{
va_list args;
va_list args;
static int udev_log = -1;
if (!debug && level == LOG_DEBUG)
if (udev_log == -1) {
const char *value;
value = getenv("UDEV_LOG");
if (value)
udev_log = log_priority(value);
else
udev_log = LOG_ERR;
}
if (priority > udev_log)
return;
va_start (args, format);
if (!hotplug_mode || use_stderr) {
vfprintf(stderr, format, args);
} else {
static int logging_init = 0;
if (!logging_init) {
openlog ("scsi_id", LOG_PID, LOG_DAEMON);
logging_init = 1;
}
vsyslog(level, format, args);
}
va_end (args);
return;
va_start(args, format);
vsyslog(priority, format, args);
va_end(args);
}
#endif
static void set_str(char *to, const char *from, size_t count)
{
@@ -171,68 +156,35 @@ static void set_type(char *to, const char *from, size_t len)
to[len-1] = '\0';
}
static int get_major_minor(struct sysfs_class_device *class_dev, int *maj,
int *min)
static int create_tmp_dev(const char *devpath, char *tmpdev, int dev_type)
{
struct sysfs_attribute *dev_attr;
unsigned int maj, min;
const char *attr;
dev_attr = sysfs_get_classdev_attr(class_dev, "dev");
if (!dev_attr) {
/*
* XXX This happens a lot, since sg has no dev attr.
* And now sysfsutils does not set a meaningful errno
* value. Someday change this back to a LOG_WARNING.
* And if sysfsutils changes, check for ENOENT and handle
* it separately.
*/
log_message(LOG_DEBUG, "%s: could not get dev attribute: %s\n",
class_dev->name, strerror(errno));
dbg("%s", devpath);
attr = sysfs_attr_get_value(devpath, "dev");
if (attr == NULL) {
dbg("%s: could not get dev attribute: %s", devpath, strerror(errno));
return -1;
}
dprintf("dev value %s", dev_attr->value); /* value has a trailing \n */
if (sscanf(dev_attr->value, "%u:%u", maj, min) != 2) {
log_message(LOG_WARNING, "%s: invalid dev major/minor\n",
class_dev->name);
dbg("dev value %s", attr);
if (sscanf(attr, "%u:%u", &maj, &min) != 2) {
err("%s: invalid dev major/minor", devpath);
return -1;
}
return 0;
}
static int create_tmp_dev(struct sysfs_class_device *class_dev, char *tmpdev,
int dev_type)
{
int maj, min;
dprintf("(%s)\n", class_dev->name);
if (get_major_minor(class_dev, &maj, &min))
return -1;
snprintf(tmpdev, MAX_NAME_LEN, "%s/%s-maj%d-min%d-%u",
TMP_DIR, TMP_PREFIX, maj, min, getpid());
dprintf("tmpdev '%s'\n", tmpdev);
dbg("tmpdev '%s'", tmpdev);
if (mknod(tmpdev, 0600 | dev_type, makedev(maj, min))) {
log_message(LOG_WARNING, "mknod failed: %s\n", strerror(errno));
err("mknod failed: %s", strerror(errno));
return -1;
}
return 0;
}
static int has_sysfs_prefix(const char *path, const char *prefix)
{
char match[MAX_NAME_LEN];
strncpy(match, sysfs_mnt_path, MAX_NAME_LEN);
strncat(match, prefix, MAX_NAME_LEN);
if (strncmp(path, match, strlen(match)) == 0)
return 1;
else
return 0;
}
/*
* get_value:
*
@@ -289,8 +241,8 @@ static int argc_count(char *opts)
*
* vendor and model can end in '\n'.
*/
static int get_file_options(char *vendor, char *model, int *argc,
char ***newargv)
static int get_file_options(const char *vendor, const char *model,
int *argc, char ***newargv)
{
char *buffer;
FILE *fd;
@@ -301,15 +253,14 @@ static int get_file_options(char *vendor, char *model, int *argc,
int c;
int retval = 0;
dprintf("vendor='%s'; model='%s'\n", vendor, model);
dbg("vendor='%s'; model='%s'\n", vendor, model);
fd = fopen(config_file, "r");
if (fd == NULL) {
dprintf("can't open %s\n", config_file);
dbg("can't open %s\n", config_file);
if (errno == ENOENT) {
return 1;
} else {
log_message(LOG_WARNING, "can't open %s: %s\n",
config_file, strerror(errno));
err("can't open %s: %s", config_file, strerror(errno));
return -1;
}
}
@@ -321,7 +272,7 @@ static int get_file_options(char *vendor, char *model, int *argc,
*/
buffer = malloc(MAX_BUFFER_LEN);
if (!buffer) {
log_message(LOG_WARNING, "Can't allocate memory.\n");
err("Can't allocate memory.");
return -1;
}
@@ -335,29 +286,22 @@ static int get_file_options(char *vendor, char *model, int *argc,
break;
lineno++;
if (buf[strlen(buffer) - 1] != '\n') {
log_message(LOG_WARNING,
"Config file line %d too long.\n", lineno);
info("Config file line %d too long.\n", lineno);
break;
}
while (isspace(*buf))
buf++;
/* blank or all whitespace line */
if (*buf == '\0')
/*
* blank or all whitespace line
*/
continue;
/* comment line */
if (*buf == '#')
/*
* comment line
*/
continue;
#ifdef LOTS
dprintf("lineno %d: '%s'\n", lineno, buf);
#endif
dbg("lineno %d: '%s'\n", lineno, buf);
str1 = strsep(&buf, "=");
if (str1 && strcasecmp(str1, "VENDOR") == 0) {
str1 = get_value(&buf);
@@ -387,22 +331,20 @@ static int get_file_options(char *vendor, char *model, int *argc,
}
options_in = str1;
}
dprintf("config file line %d:"
dbg("config file line %d:"
" vendor '%s'; model '%s'; options '%s'\n",
lineno, vendor_in, model_in, options_in);
/*
* Only allow: [vendor=foo[,model=bar]]options=stuff
*/
if (!options_in || (!vendor_in && model_in)) {
log_message(LOG_WARNING,
"Error parsing config file line %d '%s'\n",
lineno, buffer);
info("Error parsing config file line %d '%s'", lineno, buffer);
retval = -1;
break;
}
if (vendor == NULL) {
if (vendor_in == NULL) {
dprintf("matched global option\n");
dbg("matched global option\n");
break;
}
} else if ((vendor_in && strncmp(vendor, vendor_in,
@@ -416,10 +358,10 @@ static int get_file_options(char *vendor, char *model, int *argc,
* give a partial match (that is FOO
* matches FOOBAR).
*/
dprintf("matched vendor/model\n");
dbg("matched vendor/model\n");
break;
} else {
dprintf("no match\n");
dbg("no match\n");
}
}
@@ -434,8 +376,7 @@ static int get_file_options(char *vendor, char *model, int *argc,
c = argc_count(buffer) + 2;
*newargv = calloc(c, sizeof(**newargv));
if (!*newargv) {
log_message(LOG_WARNING,
"Can't allocate memory.\n");
err("Can't allocate memory.");
retval = -1;
} else {
*argc = c;
@@ -450,9 +391,7 @@ static int get_file_options(char *vendor, char *model, int *argc,
(*newargv)[c] = strsep(&buffer, " ");
}
} else {
/*
* No matches.
*/
/* No matches */
retval = 1;
}
}
@@ -480,9 +419,9 @@ static int set_options(int argc, char **argv, const char *short_opts,
break;
if (optarg)
dprintf("option '%c' arg '%s'\n", option, optarg);
dbg("option '%c' arg '%s'\n", option, optarg);
else
dprintf("option '%c'\n", option);
dbg("option '%c'\n", option);
switch (option) {
case 'a':
@@ -492,10 +431,6 @@ static int set_options(int argc, char **argv, const char *short_opts,
all_good = 0;
break;
case 'c':
default_callout = optarg;
break;
case 'd':
dev_specified = 1;
strncpy(maj_min_dev, optarg, MAX_NAME_LEN);
@@ -525,16 +460,15 @@ static int set_options(int argc, char **argv, const char *short_opts,
} else if (strcmp(optarg, "pre-spc3-83") == 0) {
default_page_code = PAGE_83_PRE_SPC3;
} else {
log_message(LOG_WARNING,
"Unknown page code '%s'\n", optarg);
info("Unknown page code '%s'", optarg);
return -1;
}
break;
case 's':
sys_specified = 1;
strncpy(target, sysfs_mnt_path, MAX_NAME_LEN);
strncat(target, optarg, MAX_NAME_LEN);
strncpy(target, optarg, MAX_NAME_LEN);
target[MAX_NAME_LEN-1] = '\0';
break;
case 'u':
@@ -550,71 +484,58 @@ static int set_options(int argc, char **argv, const char *short_opts,
break;
case 'V':
log_message(LOG_WARNING, "scsi_id version: %s\n",
SCSI_ID_VERSION);
info("scsi_id version: %s\n", SCSI_ID_VERSION);
exit(0);
break;
default:
log_message(LOG_WARNING,
"Unknown or bad option '%c' (0x%x)\n",
option, option);
info("Unknown or bad option '%c' (0x%x)", option, option);
return -1;
}
}
return 0;
}
static int per_dev_options(struct sysfs_device *scsi_dev, int *good_bad,
int *page_code, char *callout)
static int per_dev_options(struct sysfs_device *dev_scsi, int *good_bad, int *page_code)
{
int retval;
int newargc;
char **newargv = NULL;
struct sysfs_attribute *vendor, *model, *type;
const char *vendor, *model, *type;
int option;
*good_bad = all_good;
*page_code = default_page_code;
if (default_callout && (callout != default_callout))
strncpy(callout, default_callout, MAX_NAME_LEN);
else
callout[0] = '\0';
vendor = sysfs_get_device_attr(scsi_dev, "vendor");
vendor = sysfs_attr_get_value(dev_scsi->devpath, "vendor");
if (!vendor) {
log_message(LOG_WARNING, "%s: cannot get vendor attribute\n",
scsi_dev->name);
info("%s: cannot get vendor attribute", dev_scsi->devpath);
return -1;
}
set_str(vendor_str, vendor->value, sizeof(vendor_str)-1);
set_str(vendor_str, vendor, sizeof(vendor_str)-1);
model = sysfs_get_device_attr(scsi_dev, "model");
model = sysfs_attr_get_value(dev_scsi->devpath, "model");
if (!model) {
log_message(LOG_WARNING, "%s: cannot get model attribute\n",
scsi_dev->name);
info("%s: cannot get model attribute\n", dev_scsi->devpath);
return -1;
}
set_str(model_str, model->value, sizeof(model_str)-1);
set_str(model_str, model, sizeof(model_str)-1);
type = sysfs_get_device_attr(scsi_dev, "type");
type = sysfs_attr_get_value(dev_scsi->devpath, "type");
if (!type) {
log_message(LOG_WARNING, "%s: cannot get type attribute\n",
scsi_dev->name);
info("%s: cannot get type attribute", dev_scsi->devpath);
return -1;
}
set_type(type_str, type->value, sizeof(type_str));
set_type(type_str, type, sizeof(type_str));
type = sysfs_get_device_attr(scsi_dev, "rev");
type = sysfs_attr_get_value(dev_scsi->devpath, "rev");
if (!type) {
log_message(LOG_WARNING, "%s: cannot get type attribute\n",
scsi_dev->name);
info("%s: cannot get type attribute\n", dev_scsi->devpath);
return -1;
}
set_str(revision_str, type->value, sizeof(revision_str)-1);
set_str(revision_str, type, sizeof(revision_str)-1);
retval = get_file_options(vendor->value, model->value, &newargc,
&newargv);
retval = get_file_options(vendor, model, &newargc, &newargv);
optind = 1; /* reset this global extern */
while (retval == 0) {
@@ -623,19 +544,15 @@ static int per_dev_options(struct sysfs_device *scsi_dev, int *good_bad,
break;
if (optarg)
dprintf("option '%c' arg '%s'\n", option, optarg);
dbg("option '%c' arg '%s'\n", option, optarg);
else
dprintf("option '%c'\n", option);
dbg("option '%c'\n", option);
switch (option) {
case 'b':
*good_bad = 0;
break;
case 'c':
strncpy(callout, default_callout, MAX_NAME_LEN);
break;
case 'g':
*good_bad = 1;
break;
@@ -648,16 +565,13 @@ static int per_dev_options(struct sysfs_device *scsi_dev, int *good_bad,
} else if (strcmp(optarg, "pre-spc3-83") == 0) {
*page_code = PAGE_83_PRE_SPC3;
} else {
log_message(LOG_WARNING,
"Unknown page code '%s'\n", optarg);
info("Unknown page code '%s'", optarg);
retval = -1;
}
break;
default:
log_message(LOG_WARNING,
"Unknown or bad option '%c' (0x%x)\n",
option, option);
info("Unknown or bad option '%c' (0x%x)", option, option);
retval = -1;
break;
}
@@ -702,129 +616,62 @@ static void format_serial(char *serial)
* memory etc. return 2, and return 1 for expected cases (like broken
* device found) that do not print an id.
*/
static int scsi_id(const char *target_path, char *maj_min_dev)
static int scsi_id(const char *devpath, char *maj_min_dev)
{
int retval;
int dev_type = 0;
char *serial, *unaligned_buf;
struct sysfs_class_device *class_dev; /* of target_path */
struct sysfs_class_device *class_dev_parent; /* for partitions */
struct sysfs_device *scsi_dev; /* the scsi_device */
struct sysfs_device *dev;
struct sysfs_device *dev_scsi;
int good_dev;
int page_code;
char callout[MAX_NAME_LEN];
dprintf("target_path %s\n", target_path);
dbg("devpath %s\n", devpath);
/*
* Ugly: depend on the sysfs path to tell us whether this is a
* block or char device. This should probably be encoded in the
* "dev" along with the major/minor.
*/
if (has_sysfs_prefix(target_path, "/block")) {
dev = sysfs_device_get(devpath);
if (dev == NULL) {
err("unable to access '%s'", devpath);
return 1;
}
if (strcmp(dev->subsystem, "block") == 0)
dev_type = S_IFBLK;
} else if (has_sysfs_prefix(target_path, "/class")) {
else
dev_type = S_IFCHR;
} else {
if (!hotplug_mode) {
log_message(LOG_WARNING,
"Non block or class device '%s'\n",
target_path);
return 1;
} else {
/*
* Expected in some cases.
*/
dprintf("Non block or class device\n");
return 0;
}
}
class_dev = sysfs_open_class_device_path(target_path);
if (!class_dev) {
log_message(LOG_WARNING, "open class %s failed: %s\n",
target_path, strerror(errno));
return 1;
}
class_dev_parent = sysfs_get_classdev_parent(class_dev);
dprintf("class_dev 0x%p; class_dev_parent 0x%p\n", class_dev,
class_dev_parent);
if (class_dev_parent) {
scsi_dev = sysfs_get_classdev_device(class_dev_parent);
} else {
scsi_dev = sysfs_get_classdev_device(class_dev);
}
/*
* The close of scsi_dev will close class_dev or class_dev_parent.
*/
/*
* We assume we are called after the device is completely ready,
* so we don't have to loop here like udev. (And we are usually
* called via udev.)
*/
if (!scsi_dev) {
/*
* errno is not set if we can't find the device link, so
* don't print it out here.
*/
log_message(LOG_WARNING, "Cannot find sysfs device associated with %s\n",
target_path);
/* get scsi parent device */
dev_scsi = sysfs_device_get_parent(dev);
if (dev_scsi == NULL) {
err("unable to access parent device of '%s'", devpath);
return 1;
}
/*
* Allow only scsi devices.
*
* Other block devices can support SG IO, but only ide-cd does, so
* for now, don't bother with anything else.
*/
if (strcmp(scsi_dev->bus, "scsi") != 0) {
if (hotplug_mode)
/*
* Expected in some cases.
*/
dprintf("%s is not a scsi device\n", target_path);
else
log_message(LOG_WARNING, "%s is not a scsi device\n",
target_path);
/* allow only scsi devices */
if (strcmp(dev_scsi->subsystem, "scsi") != 0) {
info("%s is not a scsi device", devpath);
return 1;
}
/*
* mknod a temp dev to communicate with the device.
*/
if (!dev_specified && create_tmp_dev(class_dev, maj_min_dev,
dev_type)) {
dprintf("create_tmp_dev failed\n");
/* mknod a temp dev to communicate with the device */
if (!dev_specified && create_tmp_dev(dev->devpath, maj_min_dev, dev_type)) {
dbg("create_tmp_dev failed\n");
return 1;
}
/*
* Get any per device (vendor + model) options from the config
* file.
*/
retval = per_dev_options(scsi_dev, &good_dev, &page_code, callout);
dprintf("per dev options: good %d; page code 0x%x; callout '%s'\n",
good_dev, page_code, callout);
/* get per device (vendor + model) options from the config file */
retval = per_dev_options(dev_scsi, &good_dev, &page_code);
dbg("per dev options: good %d; page code 0x%x", good_dev, page_code);
#define ALIGN 512
unaligned_buf = malloc(MAX_SERIAL_LEN + ALIGN);
serial = (char*) (((unsigned long) unaligned_buf + (ALIGN - 1))
& ~(ALIGN - 1));
dprintf("buffer unaligned 0x%p; aligned 0x%p\n", unaligned_buf, serial);
dbg("buffer unaligned 0x%p; aligned 0x%p\n", unaligned_buf, serial);
#undef ALIGN
if (!good_dev) {
retval = 1;
} else if (callout[0] != '\0') {
/*
* XXX Disabled for now ('c' is not in any options[]).
*/
retval = 1;
} else if (scsi_get_serial(scsi_dev, maj_min_dev, page_code,
} else if (scsi_get_serial(dev_scsi, maj_min_dev, page_code,
serial, MAX_SERIAL_LEN)) {
retval = always_info?0:1;
} else {
@@ -844,13 +691,12 @@ static int scsi_id(const char *target_path, char *maj_min_dev)
if (reformat_serial)
format_serial(serial);
if (display_bus_id)
printf("%s: ", scsi_dev->name);
printf("%s: ", dev_scsi->kernel_name);
printf("%s\n", serial);
}
dprintf("%s\n", serial);
dbg("%s\n", serial);
retval = 0;
}
sysfs_close_device(scsi_dev);
if (!dev_specified)
unlink(maj_min_dev);
@@ -860,32 +706,31 @@ static int scsi_id(const char *target_path, char *maj_min_dev)
int main(int argc, char **argv)
{
int retval;
char *devpath;
char target_path[MAX_NAME_LEN];
int retval = 0;
char devpath[MAX_NAME_LEN];
char maj_min_dev[MAX_NAME_LEN];
int newargc;
const char *env;
char **newargv;
if (getenv("DEBUG"))
debug++;
logging_init("scsi_id");
sysfs_init();
dbg("argc is %d\n", argc);
dprintf("argc is %d\n", argc);
if (sysfs_get_mnt_path(sysfs_mnt_path, MAX_NAME_LEN)) {
log_message(LOG_WARNING, "sysfs_get_mnt_path failed: %s\n",
strerror(errno));
exit(1);
}
/* sysfs path can be overridden for testing */
env = getenv("SYSFS_PATH");
if (env) {
strncpy(sysfs_path, env, sizeof(sysfs_path));
sysfs_path[sizeof(sysfs_path)-1] = '\0';
} else
strcpy(sysfs_path, "/sys");
devpath = getenv("DEVPATH");
if (devpath) {
/*
* This implies that we were invoked via udev or hotplug.
*/
env = getenv("DEVPATH");
if (env) {
hotplug_mode = 1;
sys_specified = 1;
strncpy(target_path, sysfs_mnt_path, MAX_NAME_LEN);
strncat(target_path, devpath, MAX_NAME_LEN);
strncpy(devpath, env, MAX_NAME_LEN);
devpath[sizeof(devpath)-1] = '\0';
}
/*
@@ -894,26 +739,35 @@ int main(int argc, char **argv)
newargv = NULL;
retval = get_file_options(NULL, NULL, &newargc, &newargv);
if (retval < 0) {
exit(1);
} else if (newargv && (retval == 0)) {
if (set_options(newargc, newargv, short_options, target_path,
maj_min_dev) < 0)
exit(1);
retval = 1;
goto exit;
}
if (newargv && (retval == 0)) {
if (set_options(newargc, newargv, short_options, devpath,
maj_min_dev) < 0) {
retval = 2;
goto exit;
}
free(newargv);
}
/*
* Get command line options (overriding any config file or DEVPATH
* settings).
*/
if (set_options(argc, argv, short_options, target_path,
maj_min_dev) < 0)
if (set_options(argc, argv, short_options, devpath, maj_min_dev) < 0)
exit(1);
if (!sys_specified) {
log_message(LOG_WARNING, "-s must be specified\n");
exit(1);
info("-s must be specified\n");
retval = 1;
goto exit;
}
retval = scsi_id(target_path, maj_min_dev);
exit(retval);
retval = scsi_id(devpath, maj_min_dev);
exit:
sysfs_cleanup();
logging_close();
return retval;
}
+2 -12
View File
@@ -21,9 +21,6 @@
* USA
*/
#define dprintf(format, arg...) \
log_message(LOG_DEBUG, "%s: " format, __FUNCTION__ , ## arg)
#define MAX_NAME_LEN 72
/*
@@ -44,15 +41,8 @@
*/
#define MAX_BUFFER_LEN 256
extern int scsi_get_serial (struct sysfs_device *scsi_dev, const char
*devname, int page_code, char *serial, int
len);
extern void log_message (int level, const char *format, ...)
__attribute__ ((format (printf, 2, 3)));
#ifndef u8
typedef unsigned char u8;
#endif
extern int scsi_get_serial (struct sysfs_device *dev_scsi, const char *devname,
int page_code, char *serial, int len);
/*
* Page code values.
+111 -147
View File
@@ -30,11 +30,12 @@
#include <stdlib.h>
#include <unistd.h>
#include <syslog.h>
#include <linux/compiler.h> /* need __user when built via klibc */
#include <scsi/sg.h>
#include <sysfs/libsysfs.h>
#include "scsi_id.h"
#include "../../udev.h"
#include "scsi.h"
#include "scsi_id.h"
#include "scsi_id_version.h"
/*
* A priority based list of id, naa, and binary/ascii for the identifier
@@ -75,23 +76,21 @@ static const char hex_str[]="0123456789abcdef";
* 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 DRIVER_TIMEOUT 0x06
#define DRIVER_SENSE 0x08 /* Sense_buffer has been set */
#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 */
/* 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_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_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 */
static int sg_err_category_new(int scsi_status, int msg_status, int
host_status, int driver_status, const
@@ -157,7 +156,7 @@ static int sg_err_category3(struct sg_io_hdr *hp)
hp->sbp, hp->sb_len_wr);
}
static int scsi_dump_sense(struct sysfs_device *scsi_dev, struct sg_io_hdr *io)
static int scsi_dump_sense(struct sysfs_device *dev_scsi, struct sg_io_hdr *io)
{
unsigned char *sense_buffer;
int s;
@@ -184,12 +183,11 @@ static int scsi_dump_sense(struct sysfs_device *scsi_dev, struct sg_io_hdr *io)
* we'll retry the command.
*/
dprintf("got check condition\n");
dbg("got check condition\n");
sb_len = io->sb_len_wr;
if (sb_len < 1) {
log_message(LOG_WARNING, "%s: sense buffer empty\n",
scsi_dev->name);
info("%s: sense buffer empty", dev_scsi->kernel_name);
return -1;
}
@@ -203,10 +201,8 @@ static int scsi_dump_sense(struct sysfs_device *scsi_dev, struct sg_io_hdr *io)
*/
s = sense_buffer[7] + 8;
if (sb_len < s) {
log_message(LOG_WARNING,
"%s: sense buffer too small %d bytes,"
" %d bytes too short\n", scsi_dev->name,
sb_len, s - sb_len);
info("%s: sense buffer too small %d bytes, %d bytes too short",
dev_scsi->kernel_name, sb_len, s - sb_len);
return -1;
}
if ((code == 0x0) || (code == 0x1)) {
@@ -216,9 +212,8 @@ static int scsi_dump_sense(struct sysfs_device *scsi_dev, struct sg_io_hdr *io)
/*
* Possible?
*/
log_message(LOG_WARNING, "%s: sense result too"
" small %d bytes\n",
scsi_dev->name, s);
info("%s: sense result too" " small %d bytes",
dev_scsi->kernel_name, s);
return -1;
}
asc = sense_buffer[12];
@@ -229,72 +224,64 @@ static int scsi_dump_sense(struct sysfs_device *scsi_dev, struct sg_io_hdr *io)
asc = sense_buffer[2];
ascq = sense_buffer[3];
} else {
log_message(LOG_WARNING,
"%s: invalid sense code 0x%x\n",
scsi_dev->name, code);
info("%s: invalid sense code 0x%x",
dev_scsi->kernel_name, code);
return -1;
}
log_message(LOG_WARNING,
"%s: sense key 0x%x ASC 0x%x ASCQ 0x%x\n",
scsi_dev->name, sense_key, asc, ascq);
info("%s: sense key 0x%x ASC 0x%x ASCQ 0x%x",
dev_scsi->kernel_name, sense_key, asc, ascq);
} else {
if (sb_len < 4) {
log_message(LOG_WARNING,
"%s: sense buffer too small %d bytes, %d bytes too short\n",
scsi_dev->name, sb_len, 4 - sb_len);
info("%s: sense buffer too small %d bytes, %d bytes too short",
dev_scsi->kernel_name, sb_len, 4 - sb_len);
return -1;
}
if (sense_buffer[0] < 15)
log_message(LOG_WARNING, "%s: old sense key: 0x%x\n",
scsi_dev->name, sense_buffer[0] & 0x0f);
info("%s: old sense key: 0x%x", dev_scsi->kernel_name, sense_buffer[0] & 0x0f);
else
log_message(LOG_WARNING, "%s: sense = %2x %2x\n",
scsi_dev->name, sense_buffer[0],
sense_buffer[2]);
log_message(LOG_WARNING,
"%s: non-extended sense class %d code 0x%0x\n",
scsi_dev->name, sense_class, code);
info("%s: sense = %2x %2x",
dev_scsi->kernel_name, sense_buffer[0], sense_buffer[2]);
info("%s: non-extended sense class %d code 0x%0x",
dev_scsi->kernel_name, sense_class, code);
}
#ifdef DUMP_SENSE
for (i = 0, j = 0; (i < s) && (j < 254); i++) {
dprintf("i %d, j %d\n", i, j);
dbg("i %d, j %d\n", i, j);
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_message(LOG_WARNING, "%s: sense dump:\n", scsi_dev->name);
log_message(LOG_WARNING, "%s: %s\n", scsi_dev->name, out_buffer);
info("%s: sense dump:", dev_scsi->kernel_name);
info("%s: %s", dev_scsi->kernel_name, out_buffer);
#endif
return -1;
}
static int scsi_dump(struct sysfs_device *scsi_dev, struct sg_io_hdr *io)
static int scsi_dump(struct sysfs_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_message(LOG_WARNING, "%s: called with no error\n",
__FUNCTION__);
info("%s: called with no error", __FUNCTION__);
return -1;
}
log_message(LOG_WARNING, "%s: sg_io failed status 0x%x 0x%x 0x%x 0x%x\n",
scsi_dev->name, io->driver_status, io->host_status,
io->msg_status, io->status);
info("%s: sg_io failed status 0x%x 0x%x 0x%x 0x%x",
dev_scsi->kernel_name, io->driver_status, io->host_status, io->msg_status, io->status);
if (io->status == SCSI_CHECK_CONDITION)
return scsi_dump_sense(scsi_dev, io);
return scsi_dump_sense(dev_scsi, io);
else
return -1;
}
static int scsi_inquiry(struct sysfs_device *scsi_dev, int fd,
static int scsi_inquiry(struct sysfs_device *dev_scsi, int fd,
unsigned char evpd, unsigned char page,
unsigned char *buf, unsigned int buflen)
{
@@ -306,12 +293,12 @@ static int scsi_inquiry(struct sysfs_device *scsi_dev, int fd,
int retry = 3; /* rather random */
if (buflen > SCSI_INQ_BUFF_LEN) {
log_message(LOG_WARNING, "buflen %d too long\n", buflen);
info("buflen %d too long", buflen);
return -1;
}
resend:
dprintf("%s evpd %d, page 0x%x\n", scsi_dev->name, evpd, page);
dbg("%s evpd %d, page 0x%x\n", dev_scsi->kernel_name, evpd, page);
memset(&io_hdr, 0, sizeof(struct sg_io_hdr));
io_hdr.interface_id = 'S';
@@ -325,8 +312,7 @@ resend:
io_hdr.timeout = DEF_TIMEOUT;
if (ioctl(fd, SG_IO, &io_hdr) < 0) {
log_message(LOG_WARNING, "%s: ioctl failed: %s\n",
scsi_dev->name, strerror(errno));
info("%s: ioctl failed: %s", dev_scsi->kernel_name, strerror(errno));
retval = -1;
goto error;
}
@@ -343,14 +329,14 @@ resend:
break;
default:
retval = scsi_dump(scsi_dev, &io_hdr);
retval = scsi_dump(dev_scsi, &io_hdr);
}
if (!retval) {
retval = buflen;
} else if (retval > 0) {
if (--retry > 0) {
dprintf("%s: Retrying ...\n", scsi_dev->name);
dbg("%s: Retrying ...\n", dev_scsi->kernel_name);
goto resend;
}
retval = -1;
@@ -358,33 +344,30 @@ resend:
error:
if (retval < 0)
log_message(LOG_WARNING,
"%s: Unable to get INQUIRY vpd %d page 0x%x.\n",
scsi_dev->name, evpd, page);
info("%s: Unable to get INQUIRY vpd %d page 0x%x.",
dev_scsi->kernel_name, evpd, page);
return retval;
}
/* Get list of supported EVPD pages */
static int do_scsi_page0_inquiry(struct sysfs_device *scsi_dev, int fd,
static int do_scsi_page0_inquiry(struct sysfs_device *dev_scsi, int fd,
unsigned char *buffer, unsigned int len)
{
int retval;
struct sysfs_attribute *vendor;
const char *vendor;
memset(buffer, 0, len);
retval = scsi_inquiry(scsi_dev, fd, 1, 0x0, buffer, len);
retval = scsi_inquiry(dev_scsi, fd, 1, 0x0, buffer, len);
if (retval < 0)
return 1;
if (buffer[1] != 0) {
log_message(LOG_WARNING, "%s: page 0 not available.\n",
scsi_dev->name);
info("%s: page 0 not available.", dev_scsi->kernel_name);
return 1;
}
if (buffer[3] > len) {
log_message(LOG_WARNING, "%s: page 0 buffer too long %d\n",
scsi_dev->name, buffer[3]);
info("%s: page 0 buffer too long %d", dev_scsi->kernel_name, buffer[3]);
return 1;
}
@@ -400,17 +383,13 @@ static int do_scsi_page0_inquiry(struct sysfs_device *scsi_dev, int fd,
* If the vendor id appears in the page assume the page is
* invalid.
*/
vendor = sysfs_get_device_attr(scsi_dev, "vendor");
vendor = sysfs_attr_get_value(dev_scsi->devpath, "vendor");
if (!vendor) {
log_message(LOG_WARNING,
"%s: cannot get model attribute\n",
scsi_dev->name);
info("%s: cannot get model attribute", dev_scsi->kernel_name);
return 1;
}
if (!strncmp((char *)&buffer[VENDOR_LENGTH], vendor->value,
VENDOR_LENGTH)) {
log_message(LOG_WARNING, "%s: invalid page0 data\n",
scsi_dev->name);
if (!strncmp((char *)&buffer[VENDOR_LENGTH], vendor, VENDOR_LENGTH)) {
info("%s: invalid page0 data", dev_scsi->kernel_name);
return 1;
}
}
@@ -421,46 +400,35 @@ static int do_scsi_page0_inquiry(struct sysfs_device *scsi_dev, int fd,
* The caller checks that serial is long enough to include the vendor +
* model.
*/
static int prepend_vendor_model(struct sysfs_device *scsi_dev, char *serial)
static int prepend_vendor_model(struct sysfs_device *dev_scsi, char *serial)
{
struct sysfs_attribute *attr;
const char *attr;
int ind;
attr = sysfs_get_device_attr(scsi_dev, "vendor");
attr = sysfs_attr_get_value(dev_scsi->devpath, "vendor");
if (!attr) {
log_message(LOG_WARNING, "%s: cannot get vendor attribute\n",
scsi_dev->name);
info("%s: cannot get vendor attribute", dev_scsi->kernel_name);
return 1;
}
strncpy(serial, attr->value, VENDOR_LENGTH);
strncpy(serial, attr, VENDOR_LENGTH);
ind = strlen(serial) - 1;
/*
* Remove sysfs added newlines.
*/
if (serial[ind] == '\n')
serial[ind] = '\0';
attr = sysfs_get_device_attr(scsi_dev, "model");
attr = sysfs_attr_get_value(dev_scsi->devpath, "model");
if (!attr) {
log_message(LOG_WARNING, "%s: cannot get model attribute\n",
scsi_dev->name);
info("%s: cannot get model attribute", dev_scsi->kernel_name);
return 1;
}
strncat(serial, attr->value, MODEL_LENGTH);
strncat(serial, attr, MODEL_LENGTH);
ind = strlen(serial) - 1;
if (serial[ind] == '\n')
serial[ind] = '\0';
else
ind++;
ind++;
/*
* 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_message(LOG_WARNING, "%s: expected length %d, got length %d\n",
scsi_dev->name, (VENDOR_LENGTH + MODEL_LENGTH),
ind);
info("%s: expected length %d, got length %d",
dev_scsi->kernel_name, (VENDOR_LENGTH + MODEL_LENGTH), ind);
return 1;
}
return ind;
@@ -470,7 +438,7 @@ static int prepend_vendor_model(struct sysfs_device *scsi_dev, char *serial)
* check_fill_0x83_id - check the page 0x83 id, if OK allocate and fill
* serial number.
**/
static int check_fill_0x83_id(struct sysfs_device *scsi_dev,
static int check_fill_0x83_id(struct sysfs_device *dev_scsi,
unsigned char *page_83,
const struct scsi_id_search_values
*id_search, char *serial, int max_len)
@@ -517,8 +485,8 @@ static int check_fill_0x83_id(struct sysfs_device *scsi_dev,
len += VENDOR_LENGTH + MODEL_LENGTH;
if (max_len < len) {
log_message(LOG_WARNING, "%s: length %d too short - need %d\n",
scsi_dev->name, max_len, len);
info("%s: length %d too short - need %d",
dev_scsi->kernel_name, max_len, len);
return 1;
}
@@ -531,8 +499,8 @@ static int check_fill_0x83_id(struct sysfs_device *scsi_dev,
* included in the identifier.
*/
if (id_search->id_type == SCSI_ID_VENDOR_SPECIFIC)
if (prepend_vendor_model(scsi_dev, &serial[1]) < 0) {
dprintf("prepend failed\n");
if (prepend_vendor_model(dev_scsi, &serial[1]) < 0) {
dbg("prepend failed\n");
return 1;
}
@@ -559,7 +527,7 @@ static int check_fill_0x83_id(struct sysfs_device *scsi_dev,
}
/* Extract the raw binary from VPD 0x83 pre-SPC devices */
static int check_fill_0x83_prespc3(struct sysfs_device *scsi_dev,
static int check_fill_0x83_prespc3(struct sysfs_device *dev_scsi,
unsigned char *page_83,
const struct scsi_id_search_values
*id_search, char *serial, int max_len)
@@ -574,13 +542,13 @@ static int check_fill_0x83_prespc3(struct sysfs_device *scsi_dev,
serial[j++] = hex_str[(page_83[4+i] & 0xf0) >> 4];
serial[j++] = hex_str[ page_83[4+i] & 0x0f];
}
dprintf("using pre-spc3-83 for %s.\n", scsi_dev->name);
dbg("using pre-spc3-83 for %s.\n", dev_scsi->kernel_name);
return 0;
}
/* Get device identification VPD page */
static int do_scsi_page83_inquiry(struct sysfs_device *scsi_dev, int fd,
static int do_scsi_page83_inquiry(struct sysfs_device *dev_scsi, int fd,
char *serial, int len)
{
int retval;
@@ -588,14 +556,13 @@ static int do_scsi_page83_inquiry(struct sysfs_device *scsi_dev, int fd,
unsigned char page_83[SCSI_INQ_BUFF_LEN];
memset(page_83, 0, SCSI_INQ_BUFF_LEN);
retval = scsi_inquiry(scsi_dev, fd, 1, PAGE_83, page_83,
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_message(LOG_WARNING, "%s: Invalid page 0x83\n",
scsi_dev->name);
info("%s: Invalid page 0x83", dev_scsi->kernel_name);
return 1;
}
@@ -629,7 +596,7 @@ static int do_scsi_page83_inquiry(struct sysfs_device *scsi_dev, int fd,
*/
if (page_83[6] != 0)
return check_fill_0x83_prespc3(scsi_dev, page_83,
return check_fill_0x83_prespc3(dev_scsi, page_83,
id_search_list, serial, len);
/*
@@ -643,21 +610,21 @@ static int do_scsi_page83_inquiry(struct sysfs_device *scsi_dev, int fd,
* 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(scsi_dev, &page_83[j],
retval = check_fill_0x83_id(dev_scsi, &page_83[j],
&id_search_list[id_ind],
serial, len);
dprintf("%s id desc %d/%d/%d\n", scsi_dev->name,
dbg("%s id desc %d/%d/%d\n", dev_scsi->kernel_name,
id_search_list[id_ind].id_type,
id_search_list[id_ind].naa_type,
id_search_list[id_ind].code_set);
if (!retval) {
dprintf(" used\n");
dbg(" used\n");
return retval;
} else if (retval < 0) {
dprintf(" failed\n");
dbg(" failed\n");
return retval;
} else {
dprintf(" not used\n");
dbg(" not used\n");
}
}
}
@@ -671,7 +638,7 @@ static int do_scsi_page83_inquiry(struct sysfs_device *scsi_dev, 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 sysfs_device *scsi_dev, int fd,
static int do_scsi_page83_prespc3_inquiry(struct sysfs_device *dev_scsi, int fd,
char *serial, int len)
{
int retval;
@@ -679,12 +646,12 @@ static int do_scsi_page83_prespc3_inquiry(struct sysfs_device *scsi_dev, int fd,
unsigned char page_83[SCSI_INQ_BUFF_LEN];
memset(page_83, 0, SCSI_INQ_BUFF_LEN);
retval = scsi_inquiry(scsi_dev, fd, 1, PAGE_83, 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_message(LOG_WARNING, "%s: Invalid page 0x83\n", scsi_dev->name);
info("%s: Invalid page 0x83", dev_scsi->kernel_name);
return 1;
}
/*
@@ -728,12 +695,12 @@ static int do_scsi_page83_prespc3_inquiry(struct sysfs_device *scsi_dev, int fd,
serial[j++] = hex_str[page_83[i] & 0x0f];
i++;
}
dprintf("using pre-spc3-83 for %s.\n", scsi_dev->name);
dbg("using pre-spc3-83 for %s.\n", dev_scsi->kernel_name);
return 0;
}
/* Get unit serial number VPD page */
static int do_scsi_page80_inquiry(struct sysfs_device *scsi_dev, int fd,
static int do_scsi_page80_inquiry(struct sysfs_device *dev_scsi, int fd,
char *serial, int max_len)
{
int retval;
@@ -743,20 +710,19 @@ static int do_scsi_page80_inquiry(struct sysfs_device *scsi_dev, int fd,
unsigned char buf[SCSI_INQ_BUFF_LEN];
memset(buf, 0, SCSI_INQ_BUFF_LEN);
retval = scsi_inquiry(scsi_dev, fd, 1, PAGE_80, 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_message(LOG_WARNING, "%s: Invalid page 0x80\n",
scsi_dev->name);
info("%s: Invalid page 0x80", dev_scsi->kernel_name);
return 1;
}
len = 1 + VENDOR_LENGTH + MODEL_LENGTH + buf[3];
if (max_len < len) {
log_message(LOG_WARNING, "%s: length %d too short - need %d\n",
scsi_dev->name, max_len, len);
info("%s: length %d too short - need %d",
dev_scsi->kernel_name, max_len, len);
return 1;
}
/*
@@ -764,7 +730,7 @@ static int do_scsi_page80_inquiry(struct sysfs_device *scsi_dev, int fd,
* specific type where we prepend '0' + vendor + model.
*/
serial[0] = 'S';
ser_ind = prepend_vendor_model(scsi_dev, &serial[1]);
ser_ind = prepend_vendor_model(dev_scsi, &serial[1]);
if (ser_ind < 0)
return 1;
len = buf[3];
@@ -773,7 +739,7 @@ static int do_scsi_page80_inquiry(struct sysfs_device *scsi_dev, int fd,
return 0;
}
int scsi_get_serial (struct sysfs_device *scsi_dev, const char *devname,
int scsi_get_serial (struct sysfs_device *dev_scsi, const char *devname,
int page_code, char *serial, int len)
{
unsigned char page0[SCSI_INQ_BUFF_LEN];
@@ -782,16 +748,16 @@ int scsi_get_serial (struct sysfs_device *scsi_dev, const char *devname,
int retval;
memset(serial, 0, len);
dprintf("opening %s\n", devname);
dbg("opening %s\n", devname);
fd = open(devname, O_RDONLY | O_NONBLOCK);
if (fd < 0) {
log_message(LOG_WARNING, "%s: cannot open %s: %s\n",
scsi_dev->name, devname, strerror(errno));
info("%s: cannot open %s: %s",
dev_scsi->kernel_name, devname, strerror(errno));
return 1;
}
if (page_code == PAGE_80) {
if (do_scsi_page80_inquiry(scsi_dev, fd, serial, len)) {
if (do_scsi_page80_inquiry(dev_scsi, fd, serial, len)) {
retval = 1;
goto completed;
} else {
@@ -799,7 +765,7 @@ int scsi_get_serial (struct sysfs_device *scsi_dev, const char *devname,
goto completed;
}
} else if (page_code == PAGE_83) {
if (do_scsi_page83_inquiry(scsi_dev, fd, serial, len)) {
if (do_scsi_page83_inquiry(dev_scsi, fd, serial, len)) {
retval = 1;
goto completed;
} else {
@@ -807,7 +773,7 @@ int scsi_get_serial (struct sysfs_device *scsi_dev, const char *devname,
goto completed;
}
} else if (page_code == PAGE_83_PRE_SPC3) {
retval = do_scsi_page83_prespc3_inquiry(scsi_dev, fd, serial, len);
retval = do_scsi_page83_prespc3_inquiry(dev_scsi, fd, serial, len);
if (retval) {
/*
* Fallback to servicing a SPC-2/3 compliant page 83
@@ -815,7 +781,7 @@ int scsi_get_serial (struct sysfs_device *scsi_dev, const char *devname,
* conform to pre-SPC3 expectations.
*/
if (retval == 2) {
if (do_scsi_page83_inquiry(scsi_dev, fd, serial, len)) {
if (do_scsi_page83_inquiry(dev_scsi, fd, serial, len)) {
retval = 1;
goto completed;
} else {
@@ -832,8 +798,7 @@ int scsi_get_serial (struct sysfs_device *scsi_dev, const char *devname,
goto completed;
}
} else if (page_code != 0x00) {
log_message(LOG_WARNING, "%s: unsupported page code 0x%d\n",
scsi_dev->name, page_code);
info("%s: unsupported page code 0x%d", dev_scsi->kernel_name, page_code);
return 1;
}
@@ -841,7 +806,7 @@ int scsi_get_serial (struct sysfs_device *scsi_dev, const char *devname,
* 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(scsi_dev, fd, page0, SCSI_INQ_BUFF_LEN)) {
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
@@ -851,11 +816,11 @@ int scsi_get_serial (struct sysfs_device *scsi_dev, const char *devname,
goto completed;
}
dprintf("%s: Checking page0\n", scsi_dev->name);
dbg("%s: Checking page0\n", dev_scsi->kernel_name);
for (ind = 4; ind <= page0[3] + 3; ind++)
if (page0[ind] == PAGE_83)
if (!do_scsi_page83_inquiry(scsi_dev, fd, serial,
if (!do_scsi_page83_inquiry(dev_scsi, fd, serial,
len)) {
/*
* Success
@@ -866,7 +831,7 @@ int scsi_get_serial (struct sysfs_device *scsi_dev, const char *devname,
for (ind = 4; ind <= page0[3] + 3; ind++)
if (page0[ind] == PAGE_80)
if (!do_scsi_page80_inquiry(scsi_dev, fd, serial,
if (!do_scsi_page80_inquiry(dev_scsi, fd, serial,
len)) {
/*
* Success
@@ -877,7 +842,6 @@ int scsi_get_serial (struct sysfs_device *scsi_dev, const char *devname,
retval = 1;
completed:
if (close(fd) < 0)
log_message(LOG_WARNING, "%s: close failed: %s\n",
scsi_dev->name, strerror(errno));
info("%s: close failed: %s", dev_scsi->kernel_name, strerror(errno));
return retval;
}
+1 -1
View File
@@ -33,7 +33,7 @@ all: $(PROG) $(MAN_PAGES)
$(QUIET) $(CC) -c $(CFLAGS) $< -o $@
$(PROG): %: $(HEADERS) %.o $(OBJS)
$(QUIET) $(LD) $(LDFLAGS) $@.o $(OBJS) -o $@ $(LIBUDEV) $(LIBSYSFS) $(LIB_OBJS)
$(QUIET) $(LD) $(LDFLAGS) $@.o $(OBJS) -o $@ $(LIBUDEV) $(LIB_OBJS)
ifneq ($(strip $(STRIPCMD)),)
$(QUIET) $(STRIPCMD) $@
endif
+111 -117
View File
@@ -21,12 +21,10 @@
#include <ctype.h>
#include <errno.h>
#include <../../libsysfs/sysfs/libsysfs.h>
#include "../../udev_utils.h"
#include "../../logging.h"
#include "../../udev.h"
#define MAX_NAME_LEN 72
#define MAX_SERIAL_LEN 256
#define MAX_NAME_LEN 72
#define MAX_SERIAL_LEN 256
#define BLKGETSIZE64 _IOR(0x12,114,size_t)
#ifdef USE_LOG
@@ -54,7 +52,6 @@ void log_message(int priority, const char *format, ...)
}
#endif
char sysfs_mnt_path[SYSFS_PATH_MAX];
static char vendor_str[64];
static char model_str[64];
static char serial_str[MAX_SERIAL_LEN];
@@ -245,182 +242,176 @@ static void set_scsi_type(char *to, const char *from, int count)
* 6.) If the device supplies a serial number, this number
* is concatenated with the identification with an underscore '_'.
*/
static int usb_id(const char *target_path)
static int usb_id(const char *devpath)
{
struct sysfs_class_device *class_dev; /* of target_path */
struct sysfs_class_device *class_dev_parent; /* for partitions */
struct sysfs_device *scsi_dev; /* the scsi_device */
struct sysfs_device *target_dev;
struct sysfs_device *host_dev, *interface_dev, *usb_dev;
struct sysfs_attribute *scsi_model, *scsi_vendor, *scsi_type, *scsi_rev;
struct sysfs_attribute *usb_model = NULL, *usb_vendor = NULL, *usb_rev, *usb_serial;
struct sysfs_attribute *if_class, *if_subclass;
struct sysfs_device *dev;
struct sysfs_device *dev_scsi;
struct sysfs_device *dev_target;
struct sysfs_device *dev_host, *dev_interface, *dev_usb;
const char *scsi_model, *scsi_vendor, *scsi_type, *scsi_rev;
const char *usb_model = NULL, *usb_vendor = NULL, *usb_rev, *usb_serial;
const char *if_class, *if_subclass;
int if_class_num;
int protocol = 0;
class_dev = sysfs_open_class_device_path(target_path);
if (!class_dev) {
info("open class %s failed: %s", target_path, strerror(errno));
return 1;
}
class_dev_parent = sysfs_get_classdev_parent(class_dev);
if (class_dev_parent) {
scsi_dev = sysfs_get_classdev_device(class_dev_parent);
} else {
scsi_dev = sysfs_get_classdev_device(class_dev);
}
dbg("devpath %s\n", devpath);
/*
* The close of scsi_dev will close class_dev or class_dev_parent.
*/
/*
* We assume we are called after the device is completely ready,
* so we don't have to loop here like udev. (And we are usually
* called via udev.)
*/
if (!scsi_dev) {
/*
* errno is not set if we can't find the device link, so
* don't print it out here.
*/
info("Cannot find sysfs device associated with %s", target_path);
dev = sysfs_device_get(devpath);
if (dev == NULL) {
err("unable to access '%s'", devpath);
return 1;
}
/*
* Allow only scsi devices.
*
* Other block devices can support SG IO, but only ide-cd does, so
* for now, don't bother with anything else.
*/
if (strcmp(scsi_dev->bus, "scsi") != 0) {
info("%s is not a scsi device", target_path);
/* get scsi parent device */
dev_scsi = sysfs_device_get_parent(dev);
if (dev_scsi == NULL) {
err("unable to access parent device of '%s'", devpath);
return 1;
}
/* allow only scsi devices */
if (strcmp(dev_scsi->subsystem, "scsi") != 0) {
info("%s is not a scsi device", devpath);
return 1;
}
/* target directory */
target_dev = sysfs_get_device_parent(scsi_dev);
dev_target = sysfs_device_get_parent(dev_scsi);
if (dev_target == NULL) {
err("unable to access parent device of '%s'", devpath);
return 1;
}
/* host directory */
host_dev = sysfs_get_device_parent(target_dev);
dev_host = sysfs_device_get_parent(dev_target);
if (dev_host == NULL) {
err("unable to access parent device of '%s'", devpath);
return 1;
}
/* usb interface directory */
interface_dev = sysfs_get_device_parent(host_dev);
dev_interface = sysfs_device_get_parent(dev_host);
if (dev_interface == NULL) {
err("unable to access parent device of '%s'", devpath);
return 1;
}
/* usb device directory */
usb_dev = sysfs_get_device_parent(interface_dev);
if (strcmp(interface_dev->bus, "usb") != 0) {
info("%s is not an usb device", target_path);
dev_usb = sysfs_device_get_parent(dev_interface);
if (dev_usb == NULL) {
err("unable to access parent device of '%s'", devpath);
return 1;
}
if (strcmp(dev_interface->subsystem, "usb") != 0) {
info("%s is not an usb device", devpath);
return 1;
}
if_class = sysfs_get_device_attr(interface_dev, "bInterfaceClass");
if_class = sysfs_attr_get_value(dev_interface->devpath, "bInterfaceClass");
if (!if_class) {
info("%s: cannot get bInterfaceClass attribute", interface_dev->name);
info("%s: cannot get bInterfaceClass attribute", dev_interface->kernel_name);
return 1;
}
if_class_num = strtoul(if_class->value, NULL, 16);
if_class_num = strtoul(if_class, NULL, 16);
if (if_class_num != 8) {
set_usb_iftype(type_str, if_class->value, sizeof(type_str) - 1);
set_usb_iftype(type_str, if_class, sizeof(type_str)-1);
protocol = 0;
} else {
if_subclass = sysfs_get_device_attr(interface_dev,
"bInterfaceSubClass");
protocol = set_usb_ifsubtype(type_str, if_subclass->value,
sizeof(type_str) -1 );
if_subclass = sysfs_attr_get_value(dev_interface->devpath, "bInterfaceSubClass");
protocol = set_usb_ifsubtype(type_str, if_subclass, sizeof(type_str)-1);
}
if (!use_usb_info && protocol == 6) {
/* Generic SPC-2 device */
scsi_vendor = sysfs_get_device_attr(scsi_dev, "vendor");
scsi_vendor = sysfs_attr_get_value(dev_scsi->devpath, "vendor");
if (!scsi_vendor) {
info("%s: cannot get SCSI vendor attribute", scsi_dev->name);
info("%s: cannot get SCSI vendor attribute", dev_scsi->kernel_name);
return 1;
}
set_str(vendor_str, scsi_vendor->value, sizeof(vendor_str)-1);
set_str(vendor_str, scsi_vendor, sizeof(vendor_str)-1);
scsi_model = sysfs_get_device_attr(scsi_dev, "model");
scsi_model = sysfs_attr_get_value(dev_scsi->devpath, "model");
if (!scsi_model) {
info("%s: cannot get SCSI model attribute", scsi_dev->name);
info("%s: cannot get SCSI model attribute", dev_scsi->kernel_name);
return 1;
}
set_str(model_str, scsi_model->value, sizeof(model_str)-1);
set_str(model_str, scsi_model, sizeof(model_str)-1);
scsi_type = sysfs_get_device_attr(scsi_dev, "type");
scsi_type = sysfs_attr_get_value(dev_scsi->devpath, "type");
if (!scsi_type) {
info("%s: cannot get SCSI type attribute", scsi_dev->name);
info("%s: cannot get SCSI type attribute", dev_scsi->kernel_name);
return 1;
}
set_scsi_type(type_str, scsi_type->value, sizeof(type_str)-1);
set_scsi_type(type_str, scsi_type, sizeof(type_str)-1);
scsi_rev = sysfs_get_device_attr(scsi_dev, "rev");
scsi_rev = sysfs_attr_get_value(dev_scsi->devpath, "rev");
if (!scsi_rev) {
info("%s: cannot get SCSI revision attribute", scsi_dev->name);
info("%s: cannot get SCSI revision attribute", dev_scsi->kernel_name);
return 1;
}
set_str(revision_str, scsi_rev->value, sizeof(revision_str)-1);
set_str(revision_str, scsi_rev, sizeof(revision_str)-1);
}
/* Fallback to USB vendor & device */
if (vendor_str[0] == '\0') {
if (!use_num_info)
if (!(usb_vendor = sysfs_get_device_attr(usb_dev, "manufacturer")))
if (!(usb_vendor = sysfs_attr_get_value(dev_usb->devpath, "manufacturer")))
dbg("No USB vendor string found, using idVendor");
if (!usb_vendor) {
if (!(usb_vendor = sysfs_get_device_attr(usb_dev, "idVendor"))) {
if (!(usb_vendor = sysfs_attr_get_value(dev_usb->devpath, "idVendor"))) {
dbg("No USB vendor information available\n");
sprintf(vendor_str,"0000");
}
}
set_str(vendor_str,usb_vendor->value, sizeof(vendor_str) - 1);
set_str(vendor_str,usb_vendor, sizeof(vendor_str) - 1);
}
if (model_str[0] == '\0') {
if (!use_num_info)
if (!(usb_model = sysfs_get_device_attr(usb_dev, "product")))
if (!(usb_model = sysfs_attr_get_value(dev_usb->devpath, "product")))
dbg("No USB model string found, using idProduct");
if (!usb_model) {
if (!(usb_model = sysfs_get_device_attr(usb_dev, "idProduct"))) {
dbg("No USB model information available\n");
sprintf(model_str,"0000");
}
if (!(usb_model = sysfs_attr_get_value(dev_usb->devpath, "idProduct")))
dbg("No USB model information available\n"); sprintf(model_str,"0000");
}
set_str(model_str, usb_model->value, sizeof(model_str) - 1);
set_str(model_str, usb_model, sizeof(model_str) - 1);
}
if (revision_str[0] == '\0') {
usb_rev = sysfs_get_device_attr(usb_dev, "bcdDevice");
if (usb_rev) {
set_str(revision_str, usb_rev->value,
sizeof(revision_str) - 1);
}
usb_rev = sysfs_attr_get_value(dev_usb->devpath, "bcdDevice");
if (usb_rev)
set_str(revision_str, usb_rev, sizeof(revision_str)-1);
}
if (serial_str[0] == '\0') {
usb_serial = sysfs_get_device_attr(usb_dev, "serial");
if (usb_serial) {
set_str(serial_str, usb_serial->value,
sizeof(serial_str) - 1);
}
usb_serial = sysfs_attr_get_value(dev_usb->devpath, "serial");
if (usb_serial)
set_str(serial_str, usb_serial, sizeof(serial_str)-1);
}
return 0;
}
int main(int argc, char **argv)
{
int retval;
char *devpath;
char target_path[MAX_NAME_LEN];
int retval = 0;
const char *env;
char devpath[MAX_NAME_LEN];
int option;
logging_init("usb_id");
sysfs_init();
dbg("argc is %d", argc);
if (sysfs_get_mnt_path(sysfs_mnt_path, MAX_NAME_LEN)) {
info("sysfs_get_mnt_path failed: %s",
strerror(errno));
exit(1);
}
/* sysfs path can be overridden for testing */
env = getenv("SYSFS_PATH");
if (env) {
strlcpy(sysfs_path, env, sizeof(sysfs_path));
remove_trailing_chars(sysfs_path, '/');
} else
strcpy(sysfs_path, "/sys");
while ((option = getopt(argc, argv, "dnux")) != -1 ) {
if (optarg)
@@ -433,14 +424,14 @@ int main(int argc, char **argv)
debug = 1;
break;
case 'n':
use_num_info=1;
use_usb_info=1;
use_num_info = 1;
use_usb_info = 1;
break;
case 'u':
use_usb_info=1;
use_usb_info = 1;
break;
case 'x':
export=1;
export = 1;
break;
default:
info("Unknown or bad option '%c' (0x%x)", option, option);
@@ -449,20 +440,19 @@ int main(int argc, char **argv)
}
}
devpath = getenv("DEVPATH");
if (devpath) {
strncpy(target_path, sysfs_mnt_path, MAX_NAME_LEN);
strncat(target_path, devpath, MAX_NAME_LEN);
} else {
env = getenv("DEVPATH");
if (env != NULL)
strlcpy(devpath, env, sizeof(devpath));
else {
if (optind == argc) {
fprintf(stderr, "No device specified\n");
exit(1);
retval = 1;
goto exit;
}
devpath = argv[optind];
strncpy(target_path, devpath, MAX_NAME_LEN);
strlcpy(devpath, argv[optind], sizeof(devpath));
}
retval = usb_id(target_path);
retval = usb_id(devpath);
if (retval == 0) {
if (export) {
@@ -488,5 +478,9 @@ int main(int argc, char **argv)
}
}
}
exit(retval);
exit:
sysfs_cleanup();
logging_close();
return retval;
}
+1 -1
View File
@@ -35,7 +35,7 @@ $(LIBVOLUME_ID):
$(MAKE) -C libvolume_id
$(PROG): %: $(HEADERS) %.o $(LIBVOLUME_ID)
$(QUIET) $(LD) $(LDFLAGS) $@.o $(LIBVOLUME_ID) -o $@ $(LIBUDEV) $(LIBSYSFS) $(LIB_OBJS)
$(QUIET) $(LD) $(LDFLAGS) $@.o $(LIBVOLUME_ID) -o $@ $(LIBUDEV) $(LIB_OBJS)
ifneq ($(strip $(STRIPCMD)),)
$(QUIET) $(STRIPCMD) $@
endif
+1 -2
View File
@@ -29,8 +29,7 @@
#include <ctype.h>
#include <sys/ioctl.h>
#include "../../udev_utils.h"
#include "../../logging.h"
#include "../../udev.h"
#include "libvolume_id/volume_id.h"
#define BLKGETSIZE64 _IOR(0x12,114,size_t)
-441
View File
@@ -1,441 +0,0 @@
GNU Lesser Public License
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your freedom to
share and change it. By contrast, the GNU General Public Licenses are
intended to guarantee your freedom to share and change free software--to
make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some specially
designated software packages--typically libraries--of the Free Software
Foundation and other authors who decide to use it. You can use it too, but
we suggest you first think carefully about whether this license or the
ordinary General Public License is the better strategy to use in any
particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use, not
price. Our General Public Licenses are designed to make sure that you have
the freedom to distribute copies of free software (and charge for this
service if you wish); that you receive source code or can get it if you
want it; that you can change the software and use pieces of it in new free
programs; and that you are informed that you can do these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for you
if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis or
for a fee, you must give the recipients all the rights that we gave you.
You must make sure that they, too, receive or can get the source code. If
you link other code with the library, you must provide complete object
files to the recipients, so that they can relink them with the library
after making changes to the library and recompiling it. And you must show
them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that there is
no warranty for the free library. Also, if the library is modified by
someone else and passed on, the recipients should know that what they have
is not the original version, so that the original author's reputation will
not be affected by problems that might be introduced by others.
Finally, software patents pose a constant threat to the existence of any
free program. We wish to make sure that a company cannot effectively
restrict the users of a free program by obtaining a restrictive license
from a patent holder. Therefore, we insist that any patent license
obtained for a version of the library must be consistent with the full
freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the ordinary
GNU General Public License. This license, the GNU Lesser General Public
License, applies to certain designated libraries, and is quite different
from the ordinary General Public License. We use this license for certain
libraries in order to permit linking those libraries into non-free
programs.
When a program is linked with a library, whether statically or using a
shared library, the combination of the two is legally speaking a combined
work, a derivative of the original library. The ordinary General Public
License therefore permits such linking only if the entire combination fits
its criteria of freedom. The Lesser General Public License permits more
lax criteria for linking other code with the library.
We call this license the "Lesser" General Public License because it does
Less to protect the user's freedom than the ordinary General Public
License. It also provides other free software developers Less of an
advantage over competing non-free programs. These disadvantages are the
reason we use the ordinary General Public License for many libraries.
However, the Lesser license provides advantages in certain special
circumstances.
For example, on rare occasions, there may be a special need to encourage
the widest possible use of a certain library, so that it becomes a
de-facto standard. To achieve this, non-free programs must be allowed to
use the library. A more frequent case is that a free library does the same
job as widely used non-free libraries. In this case, there is little to
gain by limiting the free library to free software only, so we use the
Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of free
software. For example, permission to use the GNU C Library in non-free
programs enables many more people to use the whole GNU operating system,
as well as its variant, the GNU/Linux operating system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is linked
with the Library has the freedom and the wherewithal to run that program
using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a "work
based on the library" and a "work that uses the library". The former
contains code derived from the library, whereas the latter must be
combined with the library in order to run.
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other program
which contains a notice placed by the copyright holder or other authorized
party saying it may be distributed under the terms of this Lesser General
Public License (also called "this License"). Each licensee is addressed as
"you".
A "library" means a collection of software functions and/or data prepared
so as to be conveniently linked with application programs (which use some
of those functions and data) to form executables.
The "Library", below, refers to any such software library or work which
has been distributed under these terms. A "work based on the Library"
means either the Library or any derivative work under copyright law: that
is to say, a work containing the Library or a portion of it, either
verbatim or with modifications and/or translated straightforwardly into
another language. (Hereinafter, translation is included without limitation
in the term "modification".)
"Source code" for a work means the preferred form of the work for making
modifications to it. For a library, complete source code means all the
source code for all modules it contains, plus any associated interface
definition files, plus the scripts used to control compilation and
installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of running a
program using the Library is not restricted, and output from such a
program is covered only if its contents constitute a work based on the
Library (independent of the use of the Library in a tool for writing it).
Whether that is true depends on what the Library does and what the program
that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's complete
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the notices
that refer to this License and to the absence of any warranty; and
distribute a copy of this License along with the Library.
You may charge a fee for the physical act of transferring a copy, and you
may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Library or any portion of it,
thus forming a work based on the Library, and copy and distribute such
modifications or work under the terms of Section 1 above, provided that
you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices stating
that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no charge to
all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a table
of data to be supplied by an application program that uses the facility,
other than as an argument passed when the facility is invoked, then you
must make a good faith effort to ensure that, in the event an
application does not supply such function or table, the facility still
operates, and performs whatever part of its purpose remains meaningful.
(For example, a function in a library to compute square roots has a
purpose that is entirely well-defined independent of the application.
Therefore, Subsection 2d requires that any application-supplied function
or table used by this function must be optional: if the application does
not supply it, the square root function must still compute square
roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library, and
can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based on
the Library, the distribution of the whole must be on the terms of this
License, whose permissions for other licensees extend to the entire
whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of a
storage or distribution medium does not bring the other work under the
scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so that
they refer to the ordinary GNU General Public License, version 2, instead
of to this License. (If a newer version than version 2 of the ordinary GNU
General Public License has appeared, then you can specify that version
instead if you wish.) Do not make any other change in these notices.
Once this change is made in a given copy, it is irreversible for that
copy, so the ordinary GNU General Public License applies to all subsequent
copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of the
Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or derivative of
it, under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you accompany it with the complete
corresponding machine-readable source code, which must be distributed
under the terms of Sections 1 and 2 above on a medium customarily used for
software interchange.
If distribution of object code is made by offering access to copy from a
designated place, then offering equivalent access to copy the source code
from the same place satisfies the requirement to distribute the source
code, even though third parties are not compelled to copy the source along
with the object code.
5. A program that contains no derivative of any portion of the Library,
but is designed to work with the Library by being compiled or linked with
it, is called a "work that uses the Library". Such a work, in isolation,
is not a derivative work of the Library, and therefore falls outside the
scope of this License.
However, linking a "work that uses the Library" with the Library creates
an executable that is a derivative of the Library (because it contains
portions of the Library), rather than a "work that uses the library". The
executable is therefore covered by this License. Section 6 states terms
for distribution of such executables.
When a "work that uses the Library" uses material from a header file that
is part of the Library, the object code for the work may be a derivative
work of the Library even though the source code is not. Whether this is
true is especially significant if the work can be linked without the
Library, or if the work is itself a library. The threshold for this to be
true is not precisely defined by law.
If such an object file uses only numerical parameters, data structure
layouts and accessors, and small macros and small inline functions (ten
lines or less in length), then the use of the object file is unrestricted,
regardless of whether it is legally a derivative work. (Executables
containing this object code plus portions of the Library will still fall
under Section 6.)
Otherwise, if the work is a derivative of the Library, you may distribute
the object code for the work under the terms of Section 6. Any executables
containing that work also fall under Section 6, whether or not they are
linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or link a
"work that uses the Library" with the Library to produce a work containing
portions of the Library, and distribute that work under terms of your
choice, provided that the terms permit modification of the work for the
customer's own use and reverse engineering for debugging such
modifications.
You must give prominent notice with each copy of the work that the Library
is used in it and that the Library and its use are covered by this
License. You must supply a copy of this License. If the work during
execution displays copyright notices, you must include the copyright
notice for the Library among them, as well as a reference directing the
user to the copy of this License. Also, you must do one of these things:
a) Accompany the work with the complete corresponding machine-readable
source code for the Library including whatever changes were used in the
work (which must be distributed under Sections 1 and 2 above); and, if
the work is an executable linked with the Library, with the complete
machine-readable "work that uses the Library", as object code and/or
source code, so that the user can modify the Library and then relink to
produce a modified executable containing the modified Library. (It is
understood that the user who changes the contents of definitions files
in the Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the Library.
A suitable mechanism is one that (1) uses at run time a copy of the
library already present on the user's computer system, rather than
copying library functions into the executable, and (2) will operate
properly with a modified version of the library, if the user installs
one, as long as the modified version is interface-compatible with the
version that the work was made with.
c) Accompany the work with a written offer, valid for at least three
years, to give the same user the materials specified in Subsection 6a,
above, for a charge no more than the cost of performing this
distribution.
d) If distribution of the work is made by offering access to copy from a
designated place, offer equivalent access to copy the above specified
materials from the same place.
e) Verify that the user has already received a copy of these materials
or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the Library"
must include any data and utility programs needed for reproducing the
executable from it. However, as a special exception, the materials to be
distributed need not include anything that is normally distributed (in
either source or binary form) with the major components (compiler, kernel,
and so on) of the operating system on which the executable runs, unless
that component itself accompanies the executable.
It may happen that this requirement contradicts the license restrictions
of other proprietary libraries that do not normally accompany the
operating system. Such a contradiction means you cannot use both them and
the Library together in an executable that you distribute.
7. You may place library facilities that are a work based on the Library
side-by-side in a single library together with other library facilities
not covered by this License, and distribute such a combined library,
provided that the separate distribution of the work based on the Library
and of the other library facilities is otherwise permitted, and provided
that you do these two things:
a) Accompany the combined library with a copy of the same work based on
the Library, uncombined with any other library facilities. This must be
distributed under the terms of the Sections above.
b) Give prominent notice with the combined library of the fact that part
of it is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute the
Library except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense, link with, or distribute the
Library is void, and will automatically terminate your rights under this
License. However, parties who have received copies, or rights, from you
under this License will not have their licenses terminated so long as such
parties remain in full compliance.
9. You are not required to accept this License, since you have not signed
it. However, nothing else grants you permission to modify or distribute
the Library or its derivative works. These actions are prohibited by law
if you do not accept this License. Therefore, by modifying or distributing
the Library (or any work based on the Library), you indicate your
acceptance of this License to do so, and all its terms and conditions for
copying, distributing or modifying the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the original
licensor to copy, distribute, link with or modify the Library subject to
these terms and conditions. You may not impose any further restrictions on
the recipients' exercise of the rights granted herein. You are not
responsible for enforcing compliance by third parties with this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot distribute
so as to satisfy simultaneously your obligations under this License and
any other pertinent obligations, then as a consequence you may not
distribute the Library at all. For example, if a patent license would not
permit royalty-free redistribution of the Library by all those who receive
copies directly or indirectly through you, then the only way you could
satisfy both it and this License would be to refrain entirely from
distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any such
claims; this section has the sole purpose of protecting the integrity of
the free software distribution system which is implemented by public
license practices. Many people have made generous contributions to the
wide range of software distributed through that system in reliance on
consistent application of that system; it is up to the author/donor to
decide if he or she is willing to distribute software through any other
system and a licensee cannot impose that choice.
This section is intended to make thoroughly clear what is believed to be a
consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in certain
countries either by patents or by copyrighted interfaces, the original
copyright holder who places the Library under this License may add an
explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new versions
of the Lesser General Public License from time to time. Such new versions
will be similar in spirit to the present version, but may differ in detail
to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Library does not specify a license version
number, you may choose any version ever published by the Free Software
Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these, write
to the author to ask for permission. For software which is copyrighted by
the Free Software Foundation, write to the Free Software Foundation; we
sometimes make exceptions for this. Our decision will be guided by the two
goals of preserving the free status of all derivatives of our free
software and of promoting the sharing and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE
LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES
ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT
LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES
SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE
WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN
ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
-621
View File
@@ -1,621 +0,0 @@
/*
* dlist.c
*
* Copyright (C) 2003 Eric J Bohm
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 021110307 USA
*
*/
/* Double linked list implementation.
* You allocate the data and give dlist the pointer.
* If your data is complex set the dlist->del_func to a an appropriate
* delete function. Otherwise dlist will just use free.
*/
#include "stdlib.h"
#include "dlist.h"
/*
* Return pointer to node at marker.
* else null if no nodes.
*/
inline void *dlist_mark(Dlist *list)
{
if(list->marker!=NULL)
return(list->marker->data);
else
return(NULL);
}
/*
* Set marker to start.
*/
inline void dlist_start(Dlist *list)
{
list->marker=list->head;
}
/*
* Set marker to end.
*/
inline void dlist_end(Dlist *list)
{
list->marker=list->head;
}
/* internal use function
* quickie inline to consolidate the marker movement logic
* in one place
*
* when direction true it moves marker after
* when direction false it moves marker before.
* return pointer to data at new marker
* if nowhere to move the marker in desired direction return null
*/
inline void *_dlist_mark_move(Dlist *list,int direction)
{
if(direction)
{
if( list->marker && list->marker->next!=NULL)
list->marker=list->marker->next;
else
return(NULL);
}
else
{
if( list->marker && list->marker->prev!=NULL)
list->marker=list->marker->prev;
else
return(NULL);
}
if(list->marker!=list->head)
return(list->marker->data);
else
return(NULL);
}
/*
* Create new linked list to store nodes of datasize.
* return null if list cannot be created.
*/
Dlist *dlist_new(size_t datasize)
{
Dlist *list=NULL;
if((list=malloc(sizeof(Dlist))))
{
list->marker=NULL;
list->count=0L;
list->data_size=datasize;
list->del_func=free;
list->head=&(list->headnode);
list->head->prev=NULL;
list->head->next=NULL;
list->head->data=NULL;
}
return(list);
}
/*
* Create new linked list to store nodes of datasize set list
* data node delete function to the passed in del_func
* return null if list cannot be created.
*/
Dlist *dlist_new_with_delete(size_t datasize,void (*del_func)(void*))
{
Dlist *list=NULL;
list=dlist_new(datasize);
if(list!=NULL)
list->del_func=del_func;
return(list);
}
/*
* remove marker node from list
* call data_delete function on data if registered.
* otherwise call free.
* when direction true it moves marker after
* when direction false it moves marker before.
* free marker node
* return nothing.
*/
void dlist_delete(Dlist *list,int direction)
{
if((list->marker != list->head)&&(list->marker!=NULL))
{
DL_node *corpse;
corpse=list->marker;
_dlist_mark_move(list,direction);
if(list->head->next==corpse)
list->head->next=corpse->next;
if(list->head->prev==corpse)
list->head->prev=corpse->prev;
if(corpse->prev!=NULL) //should be impossible
corpse->prev->next=corpse->next;
if(corpse->next!=NULL) //should be impossible
corpse->next->prev=corpse->prev;
list->del_func(corpse->data);
list->count--;
free(corpse);
}
}
/*
* Insert node containing data at marker.
* If direction true it inserts after.
* If direction false it inserts before.
* move marker to inserted node
* return pointer to inserted node
*/
void *dlist_insert(Dlist *list,void *data,int direction)
{
DL_node *new_node=NULL;
if(list==NULL || data==NULL)
return(NULL);
if(list->marker==NULL) //in case the marker ends up unset
list->marker=list->head;
if((new_node=malloc(sizeof(DL_node))))
{
new_node->data=data;
new_node->prev=NULL;
new_node->next=NULL;
list->count++;
if(list->head->next==NULL) //no l
{
list->head->next=list->head->prev=new_node;
new_node->prev=list->head;
new_node->next=list->head;
}
else if(direction)
{
new_node->next=list->marker->next;
new_node->prev=list->marker;
list->marker->next->prev=new_node;
list->marker->next=new_node;
}
else
{
new_node->prev=list->marker->prev;
new_node->next=list->marker;
list->marker->prev->next=new_node;
list->marker->prev=new_node;
}
list->marker=new_node;
}
else
{
return(NULL);
}
return(list->marker->data);
}
/* internal use only
* Insert dl_node at marker.
* If direction true it inserts after.
* If direction false it inserts before.
* move marker to inserted node
* return pointer to inserted node
*/
void *_dlist_insert_dlnode(struct dlist *list,struct dl_node *new_node,int direction)
{
if(list==NULL || new_node==NULL)
return(NULL);
if(list->marker==NULL) //in case the marker ends up unset
list->marker=list->head;
list->count++;
if(list->head->next==NULL)
{
list->head->next=list->head->prev=new_node;
new_node->prev=list->head;
new_node->next=list->head;
}
else if(direction)
{
new_node->next=list->marker->next;
new_node->prev=list->marker;
list->marker->next->prev=new_node;
list->marker->next=new_node;
}
else
{
new_node->prev=list->marker->prev;
new_node->next=list->marker;
list->marker->prev->next=new_node;
list->marker->prev=new_node;
}
list->marker=new_node;
return(list->marker);
}
/*
* Remove DL_node from list without deallocating data.
* if marker == killme .
* when direction true it moves marker after
* when direction false it moves marker before.
* to previous if there is no next.
*/
void *_dlist_remove(Dlist *list,DL_node *killme,int direction)
{
if(killme!=NULL)
{
void *killer_data=killme->data;
// take care of head and marker pointers.
if(list->marker==killme)
_dlist_mark_move(list,direction);
if(killme ==list->head->next)
list->head->next=killme->next;
if(killme==list->head->prev)
list->head->prev=killme->prev;
// remove from list
if(killme->prev !=NULL)
killme->prev->next=killme->next;
if(killme->next !=NULL)
killme->next->prev=killme->prev;
list->count--;
free(killme);
return(killer_data);
}
else
return (NULL);
}
/*
* move dl_node from source to dest
* if marker == target .
* when direction true it moves marker after
* when direction false it moves marker before.
* to previous if there is no next.
*/
void dlist_move(struct dlist *source, struct dlist *dest, struct dl_node *target,int direction)
{
if(target!=NULL)
{
if(target==source->head)
{
//not even going to try
}
else
{
// take care of head and marker pointers.
if(source->marker==target)
_dlist_mark_move(source,direction);
if(target ==source->head->next)
source->head->next=target->next;
if(target==source->head->prev)
source->head->prev=target->prev;
// remove from list
if(source->count==1)
{
target->prev=NULL;
target->next=NULL;
source->head->next=NULL;
source->head->prev=NULL;
}
else
{
if(target->prev !=NULL)
target->prev->next=target->next;
if(target->next !=NULL)
target->next->prev=target->prev;
target->prev=NULL;
target->next=NULL;
}
source->count--;
_dlist_insert_dlnode(dest,target,direction);
}
}
}
/*
* Insert node containing data after end.
*/
void dlist_push(Dlist *list,void *data)
{
list->marker=list->head->prev;
dlist_insert(list,data,1);
}
/*
* Insert node containing data at start.
*/
void dlist_unshift(Dlist *list,void *data)
{
list->marker=list->head->next;
dlist_insert(list,data,0);
}
void dlist_unshift_sorted(Dlist *list, void *data,
int (*sorter)(void *new_elem, void *old_elem))
{
if (list->count == 0)
dlist_unshift(list, data);
else {
list->marker=list->head->next;
dlist_insert_sorted(list, data, sorter);
}
}
/*
* Remove end node from list.
* Return pointer to data in removed node.
* Null if no nodes.
*/
void *dlist_pop(Dlist *list)
{
return(_dlist_remove(list,list->head->prev,0));
}
/*
* Remove start node from list.
* Return pointer to data in removed node.
* Null if no nodes.
*/
void *dlist_shift(Dlist *list)
{
return(_dlist_remove(list,list->head->next,1));
}
/*
* destroy the list freeing all memory
*/
void dlist_destroy(Dlist *list)
{
if(list !=NULL)
{
dlist_start(list);
dlist_next(list);
while (dlist_mark(list)) {
dlist_delete(list,1);
}
free(list);
}
}
/**
* Return void pointer to list_data element matching comp function criteria
* else null
* Does not move the marker.
*/
void *dlist_find_custom(struct dlist *list, void *target, int (*comp)(void *, void *))
{
/* test the comp function on each node */
struct dl_node *nodepointer;
dlist_for_each_nomark(list,nodepointer)
if(comp(target,nodepointer->data))
return(nodepointer->data);
return(NULL);
}
/**
* Apply the node_operation function to each data node in the list
*/
void dlist_transform(struct dlist *list, void (*node_operation)(void *))
{
struct dl_node *nodepointer;
dlist_for_each_nomark(list,nodepointer)
node_operation(nodepointer->data);
}
/**
* insert new into list in sorted order
* sorter function in form int sorter(new,ith)
* must return 1 for when new should go before ith
* else 0
* return pointer to inserted node
* NOTE: assumes list is already sorted
*/
void *dlist_insert_sorted(struct dlist *list, void *new, int (*sorter)(void *, void *))
{
for(dlist_start(list),dlist_next(list); \
list->marker!=list->head && !sorter(new,list->marker->data);dlist_next(list));
return(dlist_insert_before(list,new));
}
/*
* NOTE: internal use only
*/
int _dlist_merge(struct dlist *listsource, struct dlist *listdest, unsigned int passcount, int (*compare)(void *, void *))
{
struct dl_node *l1head;
struct dl_node *l2head;
struct dl_node *target;
unsigned int l1count=0;
unsigned int l2count=0;
unsigned int mergecount=0;
while(listsource->count>0)
{
l1head=listsource->head->next;
l2head=l1head;
while((l1count<passcount)&&(l2head!=listsource->head))
{
l2head=l2head->next;
l1count++;
}
// so now we have two lists to merge
if(l2head==listsource->head)
{// l2count
l2count=0;
}
else
{
l2count=passcount;
}
while(l1count>0 || l2count>0)
{
mergecount++;
if((l2count>0)&&(l1count>0))
{
// we have things to merge
int result=compare(l1head->data,l2head->data);
if(result>0)
{
// move from l2
target=l2head;
l2head=l2head->next;
dlist_move(listsource,listdest,target,1);
l2count--;
if(l2head==listsource->head)
l2count=0;
}
else
{
// move from l1
target=l1head;
l1head=l1head->next;
dlist_move(listsource,listdest,target,1);
l1count--;
}
}
else if(l1count>0)
{
// only have l1 to work with
while(l1count>0)
{
target=l1head;
l1head=l1head->next;
dlist_move(listsource,listdest,target,1);
l1count--;
}
}
else if(l2count>0)
{
// only have l2 to work with
while(l2count>0)
{
if(l2head==listsource->head)
{
l2count=0;
}
else
{
target=l2head;
l2head=l2head->next;
dlist_move(listsource,listdest,target,1);
l2count--;
}
}
}
else
{ //nothing left and this should be unreachable
}
}
}
return(mergecount);
}
/**
* mergesort the list based on compare
* compare function in form int sorter(void * a,void * b)
* must return >0 for a after b
* must return <0 for a before b
* else 0
* NOTE: mergesort changes the mark pointer
*/
void dlist_sort_custom(struct dlist *list, int (*compare)(void *, void *))
{
struct dlist *listsource, *listdest, *swap;
struct dlist *templist;
unsigned int passcount = 1;
unsigned int mergecount = 1;
dlist_start(list);
templist = dlist_new(list->data_size);
// do nothing if there isn't anything to sort
listsource = list;
listdest = templist;
if(listsource->count<2)
{ //nothing to do
return;
}
else
{
while(mergecount>0)
{
mergecount=_dlist_merge(listsource, listdest, passcount, compare);
if(mergecount>1)
{
passcount=passcount*2;
//start new pass
swap=listsource;
listsource=listdest;
listdest=swap;
}
}
}
// now put the input list pointers right
// list pointers = newlist pointers
// including the forward and next nodes prev and back pointers
if(list->count==0)
{//copy
list->marker = listdest->marker;
list->count = listdest->count;
list->data_size = listdest->data_size;
list->del_func = listdest->del_func;
list->head->prev = listdest->head->prev;
list->head->next = listdest->head->next;
list->head->data = listdest->head->data;
list->head->next->prev=list->head;
list->head->prev->next=list->head;
templist->head->next=NULL;
templist->head->prev=NULL;
templist->count=0;
}
else
{// no need to copy
}
dlist_destroy(templist);
}
/* internal use function
swaps elements a and b
No sense in juggling node pointers when we can just swap the data pointers
*/
void _dlist_swap(struct dlist *list, struct dl_node *a, struct dl_node *b)
{
void *swap=a->data;
a->data=b->data;
b->data=swap;
}
File diff suppressed because it is too large Load Diff
-64
View File
@@ -1,64 +0,0 @@
/*
* sysfs.h
*
* Internal Header Definitions for libsysfs
*
* Copyright (C) IBM Corp. 2003-2005
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef _SYSFS_H_
#define _SYSFS_H_
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <dirent.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#define safestrcpy(to, from) strncpy(to, from, sizeof(to)-1)
#define safestrcat(to, from) strncat(to, from, sizeof(to) - strlen(to)-1)
#define safestrcpymax(to, from, max) \
do { \
to[max-1] = '\0'; \
strncpy(to, from, max-1); \
} while (0)
#define safestrcatmax(to, from, max) \
do { \
to[max-1] = '\0'; \
strncat(to, from, max - strlen(to)-1); \
} while (0)
extern struct sysfs_attribute *get_attribute(void *dev, const char *name);
extern struct dlist *read_dir_subdirs(const char *path);
extern struct dlist *read_dir_links(const char *path);
extern struct dlist *get_attributes_list(void *dev);
/* Debugging */
#ifdef DEBUG
#include "../logging.h"
#define dprintf(format, arg...) dbg(format, ## arg)
#else
#define dprintf(format, arg...) do { } while (0)
#endif
#endif /* _SYSFS_H_ */
-207
View File
@@ -1,207 +0,0 @@
/*
* dlist.h
*
* Copyright (C) 2003 Eric J Bohm
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef _DLIST_H_
#define _DLIST_H_
/* Double linked list header.
* navigate your list with DLIST_PREV and DLIST_NEXT. These are macros
* so function call overhead is minimized.
* Supports perl style push, pop, shift, unshift list semantics.
* You allocate the data and give dlist the pointer. If your data is
* complex set the dlist->del_func to a an appropriate delete using
* dlist_new_with_delete. Your delete function must match
(void * )(del(void *)
*Otherwise dlist will just use free.
* NOTE: The small amount of pain involved in doing that allows us to
* avoid copy in copy out semantics.
* Dlist uses an internal mark pointer to keep track of where you are
* in the list.
* insert and delete take a directional parameter. Where direction
* corresponds to the direction in which you want the list to go.
* true direction corresponded to progressing forward in the last
* false to regressing in the list.
* so a dlist_insert(yourlist,item,1) will insert it after the mark
* so a dlist_insert(yourlist,item,0) will insert it before the mark
* any insert will move the mark to the new node regardless of the direction.
* Just use the dlist_(insert|delete)_(before|after) macros if you do not want
* to think about it.
*/
#include <stddef.h>
typedef struct dl_node {
struct dl_node *prev;
struct dl_node *next;
void *data;
} DL_node;
typedef struct dlist {
DL_node *marker;
unsigned long count;
size_t data_size;
void (*del_func)(void *);
DL_node headnode;
DL_node *head;
} Dlist;
Dlist *dlist_new(size_t datasize);
Dlist *dlist_new_with_delete(size_t datasize,void (*del_func)(void*));
void *_dlist_mark_move(Dlist *list,int direction);
void *dlist_mark(Dlist *);
void dlist_start(Dlist *);
void dlist_end(Dlist *);
void dlist_move(struct dlist *source, struct dlist *dest, struct dl_node *target,int direction);
void *dlist_insert(Dlist *,void *,int) ;
void *dlist_insert_sorted(struct dlist *list, void *new_elem, int (*sorter)(void *, void *));
void dlist_delete(Dlist *,int);
void dlist_push(Dlist *,void *);
void dlist_unshift(Dlist *,void *);
void dlist_unshift_sorted(Dlist *,void *,int (*sorter)(void *, void *));
void *dlist_pop(Dlist *);
void *dlist_shift(Dlist *);
void dlist_destroy(Dlist *);
int _dlist_merge(struct dlist *listsource, struct dlist *listdest, unsigned int passcount, int (*compare)(void *, void *));
void *dlist_find_custom(struct dlist *list, void *target, int (*comp)(void *, void *));
void dlist_sort_custom(struct dlist *list, int (*compare)(void *, void *));
void _dlist_swap(struct dlist *list, struct dl_node *a, struct dl_node *b);
void dlist_transform(struct dlist *list, void (*node_operation)(void *));
/*
* _dlist_remove is for internal use only
* _dlist_mark_move is for internal use only
*/
void *_dlist_remove(struct dlist *,struct dl_node *,int );
void *_dlist_insert_dlnode(struct dlist *list,struct dl_node *new_node,int direction);
#define dlist_prev(A) _dlist_mark_move((A),0)
#define dlist_next(A) _dlist_mark_move((A),1)
#define dlist_insert_before(A,B) dlist_insert((A),(B),0)
#define dlist_insert_after(A,B) dlist_insert((A),(B),1)
#define dlist_delete_before(A) dlist_delete((A),0)
#define dlist_delete_after(A) dlist_delete((A),1)
/**
* provide for loop header which iterates the mark from start to end
* list: the dlist pointer, use dlist_mark(list) to get iterator
*/
#define dlist_for_each(list) \
for(dlist_start(list),dlist_next(list); \
(list)->marker!=(list)->head;dlist_next(list))
/**
* provide for loop header which iterates the mark from end to start
* list: the dlist pointer, use dlist_mark(list) to get iterator
*/
#define dlist_for_each_rev(list) \
for(dlist_end(list),dlist_prev(list); \
(list)->marker!=(list)->head;dlist_prev(list))
/**
* provide for loop header which iterates through the list without moving mark
* list: the dlist_pointer
* iterator: dl_node pointer to iterate
*/
#define dlist_for_each_nomark(list,iterator) \
for((iterator)=(list)->head->next; (iterator)!=(list)->head; \
(iterator)=(iterator)->next)
/**
* provide for loop header which iterates through the list without moving mark
* in reverse
* list: the dlist_pointer
* iterator: dl_node pointer to iterate
*/
#define dlist_for_each_nomark_rev(list,iterator) \
for((iterator)=(list)->head->prev; (iterator)!=(list)->head; \
(iterator)=(iterator)->prev)
/**
* provide for loop header which iterates through the list providing a
* data iterator
* list: the dlist pointer
* data_iterator: the pointer of type datatype to iterate
* datatype: actual type of the contents in the dl_node->data
*/
#define dlist_for_each_data(list,data_iterator,datatype) \
for(dlist_start(list), (data_iterator)=(datatype *) dlist_next(list); \
(list)->marker!=(list)->head;(data_iterator)=(datatype *) dlist_next(list))
/**
* provide for loop header which iterates through the list providing a
* data iterator in reverse
* list: the dlist pointer
* data_iterator: the pointer of type datatype to iterate
* datatype: actual type of the contents in the dl_node->data
*/
#define dlist_for_each_data_rev(list,data_iterator,datatype) \
for(dlist_end(list), (data_iterator)=(datatype *) dlist_prev(list); \
(list)->marker!=(list)->head;(data_iterator)=(datatype *) dlist_prev(list))
/**
* provide for loop header which iterates through the list providing a
* data iterator without moving the mark
* list: the dlist pointer
* iterator: the dl_node pointer to iterate
* data_iterator: the pointer of type datatype to iterate
* datatype: actual type of the contents in the dl_node->data
*/
#define dlist_for_each_data_nomark(list,iterator,data_iterator,datatype) \
for((iterator)=(list)->head->next, (data_iterator)=(datatype *) (iterator)->data; \
(iterator)!=(list)->head;(iterator)=(iterator)->next,(data_iterator)=(datatype *) (iterator))
/**
* provide for loop header which iterates through the list providing a
* data iterator in reverse without moving the mark
* list: the dlist pointer
* iterator: the dl_node pointer to iterate
* data_iterator: the pointer of type datatype to iterate
* datatype: actual type of the contents in the dl_node->data
*/
#define dlist_for_each_data_nomark_rev(list,iterator, data_iterator,datatype) \
for((iterator)=(list)->head->prev, (data_iterator)=(datatype *) (iterator)->data; \
(iterator)!=(list)->head;(iterator)=(iterator)->prev,(data_iterator)=(datatype *) (iterator))
#endif /* _DLIST_H_ */
-225
View File
@@ -1,225 +0,0 @@
/*
* libsysfs.h
*
* Header Definitions for libsysfs
*
* Copyright (C) IBM Corp. 2004-2005
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef _LIBSYSFS_H_
#define _LIBSYSFS_H_
#include <sys/types.h>
#include <string.h>
#include "dlist.h"
#define SYSFS_FSTYPE_NAME "sysfs"
#define SYSFS_PROC_MNTS "/proc/mounts"
#define SYSFS_BUS_NAME "bus"
#define SYSFS_CLASS_NAME "class"
#define SYSFS_BLOCK_NAME "block"
#define SYSFS_DEVICES_NAME "devices"
#define SYSFS_DRIVERS_NAME "drivers"
#define SYSFS_MODULE_NAME "module"
#define SYSFS_NAME_ATTRIBUTE "name"
#define SYSFS_UNKNOWN "unknown"
#define SYSFS_PATH_ENV "SYSFS_PATH"
#define SYSFS_PATH_MAX 256
#define SYSFS_NAME_LEN 64
#define SYSFS_BUS_ID_SIZE 32
/* mount path for sysfs, can be overridden by exporting SYSFS_PATH */
#define SYSFS_MNT_PATH "/sys"
enum sysfs_attribute_method {
SYSFS_METHOD_SHOW = 0x01, /* attr can be read by user */
SYSFS_METHOD_STORE = 0x02, /* attr can be changed by user */
};
/*
* NOTE:
* 1. We have the statically allocated "name" as the first element of all
* the structures. This feature is used in the "sorter" function for dlists
* 2. As is the case with attrlist
* 3. As is the case with path
*/
struct sysfs_attribute {
char name[SYSFS_NAME_LEN];
char path[SYSFS_PATH_MAX];
char *value;
unsigned short len; /* value length */
enum sysfs_attribute_method method; /* show and store */
};
struct sysfs_driver {
char name[SYSFS_NAME_LEN];
char path[SYSFS_PATH_MAX];
struct dlist *attrlist;
char bus[SYSFS_NAME_LEN];
/* Private: for internal use only */
struct dlist *devices;
};
struct sysfs_device {
char name[SYSFS_NAME_LEN];
char path[SYSFS_PATH_MAX];
struct dlist *attrlist;
char bus_id[SYSFS_NAME_LEN];
char bus[SYSFS_NAME_LEN];
char driver_name[SYSFS_NAME_LEN];
/* Private: for internal use only */
struct sysfs_device *parent;
/* NOTE - we still don't populate this */
struct dlist *children;
};
/* NOTE: not used as of now */
struct sysfs_bus {
char name[SYSFS_NAME_LEN];
char path[SYSFS_PATH_MAX];
struct dlist *attrlist;
/* Private: for internal use only */
struct dlist *drivers;
struct dlist *devices;
};
struct sysfs_class_device {
char name[SYSFS_NAME_LEN];
char path[SYSFS_PATH_MAX];
struct dlist *attrlist;
char classname[SYSFS_NAME_LEN];
/* Private: for internal use only */
struct sysfs_class_device *parent;
struct sysfs_device *sysdevice; /* NULL if virtual */
};
/* NOTE: not used as of now */
struct sysfs_class {
char name[SYSFS_NAME_LEN];
char path[SYSFS_PATH_MAX];
struct dlist *attrlist;
/* Private: for internal use only */
struct dlist *devices;
};
#ifdef __cplusplus
extern "C" {
#endif
/*
* Function Prototypes
*/
extern int sysfs_get_mnt_path(char *mnt_path, size_t len);
extern int sysfs_remove_trailing_slash(char *path);
extern int sysfs_get_name_from_path(const char *path, char *name, size_t len);
extern int sysfs_path_is_dir(const char *path);
extern int sysfs_path_is_link(const char *path);
extern int sysfs_path_is_file(const char *path);
extern int sysfs_get_link(const char *path, char *target, size_t len);
extern struct dlist *sysfs_open_directory_list(const char *path);
extern void sysfs_close_list(struct dlist *list);
/* sysfs directory and file access */
extern void sysfs_close_attribute(struct sysfs_attribute *sysattr);
extern struct sysfs_attribute *sysfs_open_attribute(const char *path);
extern int sysfs_read_attribute(struct sysfs_attribute *sysattr);
extern int sysfs_write_attribute(struct sysfs_attribute *sysattr,
const char *new_value, size_t len);
/* sysfs driver access */
extern void sysfs_close_driver(struct sysfs_driver *driver);
extern struct sysfs_driver *sysfs_open_driver
(const char *bus_name, const char *drv_name);
extern struct sysfs_driver *sysfs_open_driver_path(const char *path);
extern struct sysfs_attribute *sysfs_get_driver_attr
(struct sysfs_driver *drv, const char *name);
extern struct dlist *sysfs_get_driver_attributes(struct sysfs_driver *driver);
extern struct dlist *sysfs_get_driver_devices(struct sysfs_driver *driver);
/* generic sysfs device access */
extern void sysfs_close_device_tree(struct sysfs_device *device);
extern struct sysfs_device *sysfs_open_device_tree(const char *path);
extern void sysfs_close_device(struct sysfs_device *dev);
extern struct sysfs_device *sysfs_open_device
(const char *bus, const char *bus_id);
extern struct sysfs_device *sysfs_get_device_parent(struct sysfs_device *dev);
extern struct sysfs_device *sysfs_open_device_path(const char *path);
extern int sysfs_get_device_bus(struct sysfs_device *dev);
extern struct sysfs_attribute *sysfs_get_device_attr
(struct sysfs_device *dev, const char *name);
extern struct dlist *sysfs_get_device_attributes
(struct sysfs_device *dev);
/* generic sysfs class access */
extern void sysfs_close_class_device(struct sysfs_class_device *dev);
extern struct sysfs_class_device *sysfs_open_class_device_path
(const char *path);
extern struct sysfs_class_device *sysfs_open_class_device
(const char *classname, const char *name);
extern struct sysfs_class_device *sysfs_get_classdev_parent
(struct sysfs_class_device *clsdev);
extern struct sysfs_attribute *sysfs_get_classdev_attr
(struct sysfs_class_device *clsdev, const char *name);
extern struct dlist *sysfs_get_classdev_attributes
(struct sysfs_class_device *clsdev);
extern struct sysfs_device *sysfs_get_classdev_device
(struct sysfs_class_device *clsdev);
extern void sysfs_close_class(struct sysfs_class *cls);
extern struct sysfs_class *sysfs_open_class(const char *name);
extern struct sysfs_class_device *sysfs_get_class_device
(struct sysfs_class *cls, const char *name);
extern struct dlist *sysfs_get_class_devices(struct sysfs_class *cls);
/* generic sysfs bus access */
extern void sysfs_close_bus(struct sysfs_bus *bus);
extern struct sysfs_bus *sysfs_open_bus(const char *name);
extern struct dlist *sysfs_get_bus_devices(struct sysfs_bus *bus);
extern struct dlist *sysfs_get_bus_drivers(struct sysfs_bus *bus);
extern struct sysfs_device *sysfs_get_bus_device
(struct sysfs_bus *bus, const char *id);
extern struct sysfs_driver *sysfs_get_bus_driver
(struct sysfs_bus *bus, const char *drvname);
/**
* sort_list: sorter function to keep list elements sorted in alphabetical
* order. Just does a strncmp as you can see :)
*
* Returns 1 if less than 0 otherwise
*
* NOTE: We take care to have a statically allocated "name" as the first
* lement of all libsysfs structures. Hence, this function will work
* AS IS for _ALL_ the lists that have to be sorted.
*/
static inline int sort_list(void *new_elem, void *old_elem)
{
return ((strncmp(((struct sysfs_attribute *)new_elem)->name,
((struct sysfs_attribute *)old_elem)->name,
strlen(((struct sysfs_attribute *)new_elem)->name))) < 0 ? 1 : 0);
}
#ifdef __cplusplus
}
#endif
#endif /* _LIBSYSFS_H_ */
-317
View File
@@ -1,317 +0,0 @@
/*
* sysfs_bus.c
*
* Generic bus utility functions for libsysfs
*
* Copyright (C) IBM Corp. 2003-2005
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include "libsysfs.h"
#include "sysfs.h"
static void sysfs_close_dev(void *dev)
{
sysfs_close_device((struct sysfs_device *)dev);
}
static void sysfs_close_drv(void *drv)
{
sysfs_close_driver((struct sysfs_driver *)drv);
}
/*
* compares names.
* @a: name looked for
* @b: sysfs_device comparing being compared
* returns 1 if a==b->name or 0 not equal
*/
static int name_equal(void *a, void *b)
{
if (!a || !b)
return 0;
if (strcmp(((char *)a), ((struct sysfs_device *)b)->name) == 0)
return 1;
return 0;
}
/**
* sysfs_close_bus: close single bus
* @bus: bus structure
*/
void sysfs_close_bus(struct sysfs_bus *bus)
{
if (bus) {
if (bus->attrlist)
dlist_destroy(bus->attrlist);
if (bus->devices)
dlist_destroy(bus->devices);
if (bus->drivers)
dlist_destroy(bus->drivers);
free(bus);
}
}
/**
* alloc_bus: mallocs new bus structure
* returns sysfs_bus_bus struct or NULL
*/
static struct sysfs_bus *alloc_bus(void)
{
return (struct sysfs_bus *)calloc(1, sizeof(struct sysfs_bus));
}
/**
* sysfs_get_bus_devices: gets all devices for bus
* @bus: bus to get devices for
* returns dlist of devices with success and NULL with failure
*/
struct dlist *sysfs_get_bus_devices(struct sysfs_bus *bus)
{
struct sysfs_device *dev;
struct dlist *linklist;
char path[SYSFS_PATH_MAX], devpath[SYSFS_PATH_MAX];
char target[SYSFS_PATH_MAX];
char *curlink;
if (!bus) {
errno = EINVAL;
return NULL;
}
memset(path, 0, SYSFS_PATH_MAX);
safestrcpy(path, bus->path);
safestrcat(path, "/");
safestrcat(path, SYSFS_DEVICES_NAME);
linklist = read_dir_links(path);
if (linklist) {
dlist_for_each_data(linklist, curlink, char) {
if (bus->devices) {
dev = (struct sysfs_device *)
dlist_find_custom(bus->devices,
(void *)curlink, name_equal);
if (dev)
continue;
}
safestrcpy(devpath, path);
safestrcat(devpath, "/");
safestrcat(devpath, curlink);
if (sysfs_get_link(devpath, target, SYSFS_PATH_MAX)) {
dprintf("Error getting link - %s\n", devpath);
continue;
}
dev = sysfs_open_device_path(target);
if (!dev) {
dprintf("Error opening device at %s\n",
target);
continue;
}
if (!bus->devices)
bus->devices = dlist_new_with_delete
(sizeof(struct sysfs_device),
sysfs_close_dev);
dlist_unshift_sorted(bus->devices, dev, sort_list);
}
sysfs_close_list(linklist);
}
return (bus->devices);
}
/**
* sysfs_get_bus_drivers: gets all drivers for bus
* @bus: bus to get devices for
* returns dlist of devices with success and NULL with failure
*/
struct dlist *sysfs_get_bus_drivers(struct sysfs_bus *bus)
{
struct sysfs_driver *drv;
struct dlist *dirlist;
char path[SYSFS_PATH_MAX], drvpath[SYSFS_PATH_MAX];
char *curdir;
if (!bus) {
errno = EINVAL;
return NULL;
}
memset(path, 0, SYSFS_PATH_MAX);
safestrcpy(path, bus->path);
safestrcat(path, "/");
safestrcat(path, SYSFS_DRIVERS_NAME);
dirlist = read_dir_subdirs(path);
if (dirlist) {
dlist_for_each_data(dirlist, curdir, char) {
if (bus->drivers) {
drv = (struct sysfs_driver *)
dlist_find_custom(bus->drivers,
(void *)curdir, name_equal);
if (drv)
continue;
}
safestrcpy(drvpath, path);
safestrcat(drvpath, "/");
safestrcat(drvpath, curdir);
drv = sysfs_open_driver_path(drvpath);
if (!drv) {
dprintf("Error opening driver at %s\n",
drvpath);
continue;
}
if (!bus->drivers)
bus->drivers = dlist_new_with_delete
(sizeof(struct sysfs_driver),
sysfs_close_drv);
dlist_unshift_sorted(bus->drivers, drv, sort_list);
}
sysfs_close_list(dirlist);
}
return (bus->drivers);
}
/**
* sysfs_open_bus: opens specific bus and all its devices on system
* returns sysfs_bus structure with success or NULL with error.
*/
struct sysfs_bus *sysfs_open_bus(const char *name)
{
struct sysfs_bus *bus;
char buspath[SYSFS_PATH_MAX];
if (!name) {
errno = EINVAL;
return NULL;
}
memset(buspath, 0, SYSFS_PATH_MAX);
if (sysfs_get_mnt_path(buspath, SYSFS_PATH_MAX)) {
dprintf("Sysfs not supported on this system\n");
return NULL;
}
safestrcat(buspath, "/");
safestrcat(buspath, SYSFS_BUS_NAME);
safestrcat(buspath, "/");
safestrcat(buspath, name);
if (sysfs_path_is_dir(buspath)) {
dprintf("Invalid path to bus: %s\n", buspath);
return NULL;
}
bus = alloc_bus();
if (!bus) {
dprintf("calloc failed\n");
return NULL;
}
safestrcpy(bus->name, name);
safestrcpy(bus->path, buspath);
if (sysfs_remove_trailing_slash(bus->path)) {
dprintf("Incorrect path to bus %s\n", bus->path);
sysfs_close_bus(bus);
return NULL;
}
return bus;
}
/**
* sysfs_get_bus_device: Get specific device on bus using device's id
* @bus: bus to find device on
* @id: bus_id for device
* returns struct sysfs_device reference or NULL if not found.
*/
struct sysfs_device *sysfs_get_bus_device(struct sysfs_bus *bus,
const char *id)
{
struct sysfs_device *dev = NULL;
char devpath[SYSFS_PATH_MAX], target[SYSFS_PATH_MAX];
if (!bus || !id) {
errno = EINVAL;
return NULL;
}
if (bus->devices) {
dev = (struct sysfs_device *)dlist_find_custom
(bus->devices, (void *)id, name_equal);
if (dev)
return dev;
}
safestrcpy(devpath, bus->path);
safestrcat(devpath, "/");
safestrcat(devpath, SYSFS_DEVICES_NAME);
safestrcat(devpath, "/");
safestrcat(devpath, id);
if (sysfs_path_is_link(devpath)) {
dprintf("No such device %s on bus %s?\n", id, bus->name);
return NULL;
}
if (!sysfs_get_link(devpath, target, SYSFS_PATH_MAX)) {
dev = sysfs_open_device_path(target);
if (!dev) {
dprintf("Error opening device at %s\n", target);
return NULL;
}
if (!bus->devices)
bus->devices = dlist_new_with_delete
(sizeof(struct sysfs_device),
sysfs_close_dev);
dlist_unshift_sorted(bus->devices, dev, sort_list);
}
return dev;
}
/**
* sysfs_get_bus_driver: Get specific driver on bus using driver name
* @bus: bus to find driver on
* @drvname: name of driver
* returns struct sysfs_driver reference or NULL if not found.
*/
struct sysfs_driver *sysfs_get_bus_driver(struct sysfs_bus *bus,
const char *drvname)
{
struct sysfs_driver *drv;
char drvpath[SYSFS_PATH_MAX];
if (!bus || !drvname) {
errno = EINVAL;
return NULL;
}
if (bus->drivers) {
drv = (struct sysfs_driver *)dlist_find_custom
(bus->drivers, (void *)drvname, name_equal);
if (drv)
return drv;
}
safestrcpy(drvpath, bus->path);
safestrcat(drvpath, "/");
safestrcat(drvpath, SYSFS_DRIVERS_NAME);
safestrcat(drvpath, "/");
safestrcat(drvpath, drvname);
drv = sysfs_open_driver_path(drvpath);
if (!drv) {
dprintf("Error opening driver at %s\n", drvpath);
return NULL;
}
if (!bus->drivers)
bus->drivers = dlist_new_with_delete
(sizeof(struct sysfs_driver),
sysfs_close_drv);
dlist_unshift_sorted(bus->drivers, drv, sort_list);
return drv;
}
-557
View File
@@ -1,557 +0,0 @@
/*
* sysfs_class.c
*
* Generic class utility functions for libsysfs
*
* Copyright (C) IBM Corp. 2003-2005
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include "libsysfs.h"
#include "sysfs.h"
/**
* sysfs_close_class_device: closes a single class device.
* @dev: class device to close.
*/
void sysfs_close_class_device(struct sysfs_class_device *dev)
{
if (dev) {
if (dev->parent)
sysfs_close_class_device(dev->parent);
if (dev->sysdevice)
sysfs_close_device(dev->sysdevice);
if (dev->attrlist)
dlist_destroy(dev->attrlist);
free(dev);
}
}
static void sysfs_close_cls_dev(void *dev)
{
sysfs_close_class_device((struct sysfs_class_device *)dev);
}
/**
* sysfs_close_class: close the given class
* @cls: sysfs_class to close
*/
void sysfs_close_class(struct sysfs_class *cls)
{
if (cls) {
if (cls->devices)
dlist_destroy(cls->devices);
if (cls->attrlist)
dlist_destroy(cls->attrlist);
free(cls);
}
}
static int cdev_name_equal(void *a, void *b)
{
if (!a || !b)
return 0;
if (strncmp((char *)a, ((struct sysfs_class_device *)b)->name,
strlen((char *)a)) == 0)
return 1;
return 0;
}
static struct sysfs_class *alloc_class(void)
{
return (struct sysfs_class *) calloc(1, sizeof(struct sysfs_class));
}
/**
* alloc_class_device: mallocs and initializes new class device struct.
* returns sysfs_class_device or NULL.
*/
static struct sysfs_class_device *alloc_class_device(void)
{
struct sysfs_class_device *dev;
dev = calloc(1, sizeof(struct sysfs_class_device));
return dev;
}
/**
* set_classdev_classname: Grabs classname from path
* @cdev: class device to set
* Returns nothing
*/
static void set_classdev_classname(struct sysfs_class_device *cdev)
{
char *c, *e;
int count = 0;
c = strstr(cdev->path, SYSFS_CLASS_NAME);
if (c == NULL) {
c = strstr(cdev->path, SYSFS_BLOCK_NAME);
} else {
c = strstr(c, "/");
}
if (c == NULL)
safestrcpy(cdev->classname, SYSFS_UNKNOWN);
else {
if (*c == '/')
c++;
e = c;
while (e != NULL && *e != '/' && *e != '\0') {
e++;
count++;
}
strncpy(cdev->classname, c, count);
}
}
/**
* sysfs_open_class_device_path: Opens and populates class device
* @path: path to class device.
* returns struct sysfs_class_device with success and NULL with error.
*/
struct sysfs_class_device *sysfs_open_class_device_path(const char *path)
{
struct sysfs_class_device *cdev;
char temp_path[SYSFS_PATH_MAX];
if (!path) {
errno = EINVAL;
return NULL;
}
/*
* Post linux-2.6.14 driver model supports nested classes with
* links to the nested hierarchy at /sys/class/xxx/. Check for
* a link to the actual class device if a directory isn't found
*/
if (sysfs_path_is_dir(path)) {
dprintf("%s: Directory not found, checking for a link\n", path);
if (!sysfs_path_is_link(path)) {
if (sysfs_get_link(path, temp_path, SYSFS_PATH_MAX)) {
dprintf("Error retrieving link at %s\n", path);
return NULL;
}
} else {
dprintf("%s is not a valid class device path\n", path);
return NULL;
}
} else
safestrcpy(temp_path, path);
cdev = alloc_class_device();
if (!cdev) {
dprintf("calloc failed\n");
return NULL;
}
if (sysfs_get_name_from_path(temp_path, cdev->name, SYSFS_NAME_LEN)) {
errno = EINVAL;
dprintf("Error getting class device name\n");
sysfs_close_class_device(cdev);
return NULL;
}
safestrcpy(cdev->path, temp_path);
if (sysfs_remove_trailing_slash(cdev->path)) {
dprintf("Invalid path to class device %s\n", cdev->path);
sysfs_close_class_device(cdev);
return NULL;
}
set_classdev_classname(cdev);
return cdev;
}
/**
* get_blockdev_parent: Get the parent class device for a "block" subsystem
* device if present
* @clsdev: block subsystem class device whose parent needs to be found
* Returns 0 on success and 1 on error
*/
static int get_blockdev_parent(struct sysfs_class_device *clsdev)
{
char parent_path[SYSFS_PATH_MAX];
char *c;
safestrcpy(parent_path, clsdev->path);
c = strstr(parent_path, SYSFS_BLOCK_NAME);
if (c == NULL) {
dprintf("Class device %s does not belong to BLOCK subsystem\n",
clsdev->name);
return 1;
}
c += strlen(SYSFS_BLOCK_NAME);
if (*c == '/')
c++;
else
goto errout;
/* validate whether the given class device is a partition or not */
if ((strncmp(c, clsdev->name, strlen(clsdev->name))) == 0) {
dprintf("%s not a partition\n", clsdev->name);
return 1;
}
c = strchr(c, '/');
if (c == NULL)
goto errout;
*c = '\0';
clsdev->parent = sysfs_open_class_device_path(parent_path);
if (!clsdev->parent) {
dprintf("Error opening the parent class device at %s\n",
parent_path);
return 1;
}
return 0;
errout:
dprintf("Invalid path %s\n", clsdev->path);
return 1;
}
/**
* sysfs_get_classdev_parent: Retrieves the parent of a class device.
* eg., when working with hda1, this function can be used to retrieve the
* sysfs_class_device for hda
*
* @clsdev: class device whose parent details are required.
* Returns sysfs_class_device of the parent on success, NULL on failure
*/
struct sysfs_class_device *sysfs_get_classdev_parent
(struct sysfs_class_device *clsdev)
{
if (!clsdev) {
errno = EINVAL;
return NULL;
}
if (clsdev->parent)
return (clsdev->parent);
/*
* As of now, only block devices have a parent child heirarchy in sysfs
* We do not know, if, in the future, more classes will have a similar
* structure. Hence, we now call a specialized function for block and
* later we can add support functions for other subsystems as required.
*/
if (!(strncmp(clsdev->classname, SYSFS_BLOCK_NAME,
sizeof(SYSFS_BLOCK_NAME)))) {
if ((get_blockdev_parent(clsdev)) == 0)
return (clsdev->parent);
}
return NULL;
}
/**
* get_classdev_path: given the class and a device in the class, return the
* absolute path to the device
* @classname: name of the class
* @clsdev: the class device
* @path: buffer to return path
* @psize: size of "path"
* Returns 0 on SUCCESS or -1 on error
*/
static int get_classdev_path(const char *classname, const char *clsdev,
char *path, size_t len)
{
if (!classname || !clsdev || !path) {
errno = EINVAL;
return -1;
}
if (sysfs_get_mnt_path(path, len) != 0) {
dprintf("Error getting sysfs mount path\n");
return -1;
}
if (strncmp(classname, SYSFS_BLOCK_NAME,
sizeof(SYSFS_BLOCK_NAME)) == 0) {
safestrcatmax(path, "/", len);
safestrcatmax(path, SYSFS_BLOCK_NAME, len);
} else {
safestrcatmax(path, "/", len);
safestrcatmax(path, SYSFS_CLASS_NAME, len);
safestrcatmax(path, "/", len);
safestrcatmax(path, classname, len);
}
safestrcatmax(path, "/", len);
safestrcatmax(path, clsdev, len);
return 0;
}
/**
* sysfs_open_class_device: Locates a specific class_device and returns it.
* Class_device must be closed using sysfs_close_class_device
* @classname: Class to search
* @name: name of the class_device
*
* NOTE:
* Call sysfs_close_class_device() to close the class device
*/
struct sysfs_class_device *sysfs_open_class_device
(const char *classname, const char *name)
{
char devpath[SYSFS_PATH_MAX];
struct sysfs_class_device *cdev;
if (!classname || !name) {
errno = EINVAL;
return NULL;
}
memset(devpath, 0, SYSFS_PATH_MAX);
if ((get_classdev_path(classname, name, devpath,
SYSFS_PATH_MAX)) != 0) {
dprintf("Error getting to device %s on class %s\n",
name, classname);
return NULL;
}
cdev = sysfs_open_class_device_path(devpath);
if (!cdev) {
dprintf("Error getting class device %s from class %s\n",
name, classname);
return NULL;
}
return cdev;
}
/**
* sysfs_get_classdev_attr: searches class device's attributes by name
* @clsdev: class device to look through
* @name: attribute name to get
* returns sysfs_attribute reference with success or NULL with error
*/
struct sysfs_attribute *sysfs_get_classdev_attr
(struct sysfs_class_device *clsdev, const char *name)
{
if (!clsdev || !name) {
errno = EINVAL;
return NULL;
}
return get_attribute(clsdev, (char *)name);
}
/**
* sysfs_get_classdev_attributes: gets list of classdev attributes
* @clsdev: class device whose attributes list is needed
* returns dlist of attributes on success or NULL on error
*/
struct dlist *sysfs_get_classdev_attributes(struct sysfs_class_device *clsdev)
{
if (!clsdev) {
errno = EINVAL;
return NULL;
}
return get_attributes_list(clsdev);
}
/**
* sysfs_get_classdev_device: gets the sysfs_device associated with the
* given sysfs_class_device
* @clsdev: class device whose associated sysfs_device is needed
* returns struct sysfs_device * on success or NULL on error
*/
struct sysfs_device *sysfs_get_classdev_device
(struct sysfs_class_device *clsdev)
{
char linkpath[SYSFS_PATH_MAX], devpath[SYSFS_PATH_MAX];
if (!clsdev) {
errno = EINVAL;
return NULL;
}
if (clsdev->sysdevice)
return clsdev->sysdevice;
memset(linkpath, 0, SYSFS_PATH_MAX);
safestrcpy(linkpath, clsdev->path);
safestrcat(linkpath, "/device");
if (!sysfs_path_is_link(linkpath)) {
memset(devpath, 0, SYSFS_PATH_MAX);
if (!sysfs_get_link(linkpath, devpath, SYSFS_PATH_MAX))
clsdev->sysdevice = sysfs_open_device_path(devpath);
}
return clsdev->sysdevice;
}
/**
* sysfs_open_class: opens specific class and all its devices on system
* returns sysfs_class structure with success or NULL with error.
*/
struct sysfs_class *sysfs_open_class(const char *name)
{
struct sysfs_class *cls = NULL;
char classpath[SYSFS_PATH_MAX];
if (!name) {
errno = EINVAL;
return NULL;
}
memset(classpath, 0, SYSFS_PATH_MAX);
if ((sysfs_get_mnt_path(classpath, SYSFS_PATH_MAX)) != 0) {
dprintf("Sysfs not supported on this system\n");
return NULL;
}
/*
* We shall now treat "block" also as a class. Hence, check here
* if "name" is "block" and proceed accordingly
*/
if (strcmp(name, SYSFS_BLOCK_NAME) == 0) {
safestrcat(classpath, "/");
safestrcat(classpath, SYSFS_BLOCK_NAME);
} else {
safestrcat(classpath, "/");
safestrcat(classpath, SYSFS_CLASS_NAME);
safestrcat(classpath, "/");
safestrcat(classpath, name);
}
if (sysfs_path_is_dir(classpath)) {
dprintf("Class %s not found on the system\n", name);
return NULL;
}
cls = alloc_class();
if (cls == NULL) {
dprintf("calloc failed\n");
return NULL;
}
safestrcpy(cls->name, name);
safestrcpy(cls->path, classpath);
if ((sysfs_remove_trailing_slash(cls->path)) != 0) {
dprintf("Invalid path to class device %s\n", cls->path);
sysfs_close_class(cls);
return NULL;
}
return cls;
}
/**
* sysfs_get_class_device: get specific class device using the device's id
* @cls: sysfs_class to find the device on
* @name: name of the class device to look for
*
* Returns sysfs_class_device * on success and NULL on failure
*/
struct sysfs_class_device *sysfs_get_class_device(struct sysfs_class *cls,
const char *name)
{
char path[SYSFS_PATH_MAX];
struct sysfs_class_device *cdev = NULL;
if (!cls || !name) {
errno = EINVAL;
return NULL;
}
if (cls->devices) {
cdev = (struct sysfs_class_device *)dlist_find_custom
(cls->devices, (void *)name, cdev_name_equal);
if (cdev)
return cdev;
}
safestrcpy(path, cls->path);
safestrcat(path, "/");
safestrcat(path, name);
cdev = sysfs_open_class_device_path(path);
if (!cdev) {
dprintf("Error opening class device at %s\n", path);
return NULL;
}
if (!cls->devices)
cls->devices = dlist_new_with_delete
(sizeof(struct sysfs_class_device),
sysfs_close_cls_dev);
dlist_unshift_sorted(cls->devices, cdev, sort_list);
return cdev;
}
/**
* Add class devices to list
*/
static void add_cdevs_to_classlist(struct sysfs_class *cls, struct dlist *list)
{
char path[SYSFS_PATH_MAX], *cdev_name;
struct sysfs_class_device *cdev = NULL;
if (cls == NULL || list == NULL)
return;
dlist_for_each_data(list, cdev_name, char) {
if (cls->devices) {
cdev = (struct sysfs_class_device *)
dlist_find_custom(cls->devices,
(void *)cdev_name, cdev_name_equal);
if (cdev)
continue;
}
safestrcpy(path, cls->path);
safestrcat(path, "/");
safestrcat(path, cdev_name);
cdev = sysfs_open_class_device_path(path);
if (cdev) {
if (!cls->devices)
cls->devices = dlist_new_with_delete
(sizeof(struct sysfs_class_device),
sysfs_close_cls_dev);
dlist_unshift_sorted(cls->devices, cdev,
sort_list);
}
}
}
/**
* sysfs_get_class_devices: get all class devices in the given class
* @cls: sysfs_class whose devices list is needed
*
* Returns a dlist of sysfs_class_device * on success and NULL on failure
*/
struct dlist *sysfs_get_class_devices(struct sysfs_class *cls)
{
char path[SYSFS_PATH_MAX];
struct dlist *dirlist, *linklist;
if (!cls) {
errno = EINVAL;
return NULL;
}
/*
* Post linux-2.6.14, we have nested classes and links under
* /sys/class/xxx/. are also valid class devices
*/
safestrcpy(path, cls->path);
dirlist = read_dir_subdirs(path);
if (dirlist) {
add_cdevs_to_classlist(cls, dirlist);
sysfs_close_list(dirlist);
}
linklist = read_dir_links(path);
if (linklist) {
add_cdevs_to_classlist(cls, linklist);
sysfs_close_list(linklist);
}
return cls->devices;
}
-341
View File
@@ -1,341 +0,0 @@
/*
* sysfs_device.c
*
* Generic device utility functions for libsysfs
*
* Copyright (C) IBM Corp. 2003-2005
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include "libsysfs.h"
#include "sysfs.h"
/**
* get_dev_driver: fills in the dev->driver_name field
* Returns 0 on SUCCESS and -1 on error
*/
static int get_dev_driver(struct sysfs_device *dev)
{
char path[SYSFS_PATH_MAX];
char devpath[SYSFS_PATH_MAX];
if (!dev) {
errno = EINVAL;
return -1;
}
memset(path, 0, SYSFS_PATH_MAX);
memset(devpath, 0, SYSFS_PATH_MAX);
safestrcpymax(path, dev->path, SYSFS_PATH_MAX);
safestrcatmax(path, "/driver", SYSFS_PATH_MAX);
if (!sysfs_path_is_link(path)) {
if (!sysfs_get_link(path, devpath, SYSFS_PATH_MAX)) {
if (sysfs_get_name_from_path(devpath,
dev->driver_name, SYSFS_NAME_LEN))
return -1;
}
return 0;
}
return -1;
}
/**
* sysfs_get_device_bus: retrieves the bus name the device is on, checks path
* to bus' link to make sure it has correct device.
* @dev: device to get busname.
* returns 0 with success and -1 with error.
*/
int sysfs_get_device_bus(struct sysfs_device *dev)
{
char devpath[SYSFS_PATH_MAX];
char path[SYSFS_PATH_MAX];
if (!dev) {
errno = EINVAL;
return -1;
}
memset(path, 0, SYSFS_PATH_MAX);
memset(devpath, 0, SYSFS_PATH_MAX);
safestrcpymax(path, dev->path, SYSFS_PATH_MAX);
safestrcatmax(path, "/bus", SYSFS_PATH_MAX);
if (!sysfs_path_is_link(path)) {
if (!sysfs_get_link(path, devpath, SYSFS_PATH_MAX)) {
if (sysfs_get_name_from_path(devpath,
dev->bus, SYSFS_NAME_LEN))
return -1;
}
return 0;
}
return -1;
}
/**
* sysfs_close_device_tree: closes every device in the supplied tree,
* closing children only.
* @devroot: device root of tree.
*/
void sysfs_close_device_tree(struct sysfs_device *devroot)
{
if (devroot) {
if (devroot->children) {
struct sysfs_device *child = NULL;
dlist_for_each_data(devroot->children, child,
struct sysfs_device) {
sysfs_close_device_tree(child);
}
}
sysfs_close_device(devroot);
}
}
/**
* sysfs_close_device: closes and cleans up a device
* @dev = device to clean up
*/
void sysfs_close_device(struct sysfs_device *dev)
{
if (dev) {
if (dev->parent)
sysfs_close_device(dev->parent);
if (dev->children && dev->children->count)
dlist_destroy(dev->children);
if (dev->attrlist)
dlist_destroy(dev->attrlist);
free(dev);
}
}
/**
* alloc_device: allocates and initializes device structure
* returns struct sysfs_device
*/
static struct sysfs_device *alloc_device(void)
{
return (struct sysfs_device *) calloc(1, sizeof(struct sysfs_device));
}
/**
* sysfs_open_device_path: opens and populates device structure
* @path: path to device, this is the /sys/devices/ path
* returns sysfs_device structure with success or NULL with error
*/
struct sysfs_device *sysfs_open_device_path(const char *path)
{
struct sysfs_device *dev;
if (!path) {
errno = EINVAL;
return NULL;
}
if (sysfs_path_is_dir(path)) {
dprintf("Incorrect path to device: %s\n", path);
return NULL;
}
dev = alloc_device();
if (!dev) {
dprintf("Error allocating device at %s\n", path);
return NULL;
}
if (sysfs_get_name_from_path(path, dev->bus_id, SYSFS_NAME_LEN)) {
errno = EINVAL;
dprintf("Error getting device bus_id\n");
sysfs_close_device(dev);
return NULL;
}
safestrcpy(dev->path, path);
if (sysfs_remove_trailing_slash(dev->path)) {
dprintf("Invalid path to device %s\n", dev->path);
sysfs_close_device(dev);
return NULL;
}
/*
* The "name" attribute no longer exists... return the device's
* sysfs representation instead, in the "dev->name" field, which
* implies that the dev->name and dev->bus_id contain same data.
*/
safestrcpy(dev->name, dev->bus_id);
if (sysfs_get_device_bus(dev))
dprintf("Could not get device bus\n");
if (get_dev_driver(dev)) {
dprintf("Could not get device %s's driver\n", dev->bus_id);
safestrcpy(dev->driver_name, SYSFS_UNKNOWN);
}
return dev;
}
/**
* sysfs_get_device_attr: searches dev's attributes by name
* @dev: device to look through
* @name: attribute name to get
* returns sysfs_attribute reference with success or NULL with error.
*/
struct sysfs_attribute *sysfs_get_device_attr(struct sysfs_device *dev,
const char *name)
{
if (!dev || !name) {
errno = EINVAL;
return NULL;
}
return get_attribute(dev, (char *)name);
}
/**
* sysfs_get_device_attributes: gets list of device attributes
* @dev: device whose attributes list is needed
* returns dlist of attributes on success or NULL on error
*/
struct dlist *sysfs_get_device_attributes(struct sysfs_device *dev)
{
if (!dev) {
errno = EINVAL;
return NULL;
}
return get_attributes_list(dev);
}
/**
* get_device_absolute_path: looks up the bus the device is on, gets
* absolute path to the device
* @device: device for which path is needed
* @path: buffer to store absolute path
* @psize: size of "path"
* Returns 0 on success -1 on failure
*/
static int get_device_absolute_path(const char *device, const char *bus,
char *path, size_t psize)
{
char bus_path[SYSFS_PATH_MAX];
if (!device || !path) {
errno = EINVAL;
return -1;
}
memset(bus_path, 0, SYSFS_PATH_MAX);
if (sysfs_get_mnt_path(bus_path, SYSFS_PATH_MAX)) {
dprintf ("Sysfs not supported on this system\n");
return -1;
}
safestrcat(bus_path, "/");
safestrcat(bus_path, SYSFS_BUS_NAME);
safestrcat(bus_path, "/");
safestrcat(bus_path, bus);
safestrcat(bus_path, "/");
safestrcat(bus_path, SYSFS_DEVICES_NAME);
safestrcat(bus_path, "/");
safestrcat(bus_path, device);
/*
* We now are at /sys/bus/"bus_name"/devices/"device" which is a link.
* Now read this link to reach to the device.
*/
if (sysfs_get_link(bus_path, path, psize)) {
dprintf("Error getting to device %s\n", device);
return -1;
}
return 0;
}
/**
* sysfs_open_device: open a device by id (use the "bus" subsystem)
* @bus: bus the device belongs to
* @bus_id: bus_id of the device to open - has to be the "bus_id" in
* /sys/bus/xxx/devices
* returns struct sysfs_device if found, NULL otherwise
* NOTE:
* 1. Use sysfs_close_device to close the device
* 2. Bus the device is on must be supplied
* Use sysfs_find_device_bus to get the bus name
*/
struct sysfs_device *sysfs_open_device(const char *bus, const char *bus_id)
{
char sysfs_path[SYSFS_PATH_MAX];
struct sysfs_device *device;
if (!bus_id || !bus) {
errno = EINVAL;
return NULL;
}
memset(sysfs_path, 0, SYSFS_PATH_MAX);
if (get_device_absolute_path(bus_id, bus, sysfs_path,
SYSFS_PATH_MAX)) {
dprintf("Error getting to device %s\n", bus_id);
return NULL;
}
device = sysfs_open_device_path(sysfs_path);
if (!device) {
dprintf("Error opening device %s\n", bus_id);
return NULL;
}
return device;
}
/**
* sysfs_get_device_parent: opens up given device's parent and returns a
* reference to its sysfs_device
* @dev: sysfs_device whose parent is requested
* Returns sysfs_device of the parent on success and NULL on failure
*/
struct sysfs_device *sysfs_get_device_parent(struct sysfs_device *dev)
{
char ppath[SYSFS_PATH_MAX], dpath[SYSFS_PATH_MAX], *tmp;
if (!dev) {
errno = EINVAL;
return NULL;
}
if (dev->parent)
return (dev->parent);
memset(ppath, 0, SYSFS_PATH_MAX);
memset(dpath, 0, SYSFS_PATH_MAX);
safestrcpy(ppath, dev->path);
tmp = strrchr(ppath, '/');
if (!tmp) {
dprintf("Invalid path to device %s\n", ppath);
return NULL;
}
if (*(tmp + 1) == '\0') {
*tmp = '\0';
tmp = strrchr(tmp, '/');
if (tmp == NULL) {
dprintf("Invalid path to device %s\n", ppath);
return NULL;
}
}
*tmp = '\0';
/* Make sure we're not at the top of the device tree */
sysfs_get_mnt_path(dpath, SYSFS_PATH_MAX);
safestrcat(dpath, "/" SYSFS_DEVICES_NAME);
if (strcmp(dpath, ppath) == 0) {
dprintf("Device at %s does not have a parent\n", dev->path);
return NULL;
}
dev->parent = sysfs_open_device_path(ppath);
if (!dev->parent) {
dprintf("Error opening device %s's parent at %s\n",
dev->bus_id, ppath);
return NULL;
}
return (dev->parent);
}
-491
View File
@@ -1,491 +0,0 @@
/*
* sysfs_dir.c
*
* Directory utility functions for libsysfs
*
* Copyright (C) IBM Corp. 2003-2005
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include "libsysfs.h"
#include "sysfs.h"
static int sort_char(void *new, void *old)
{
return ((strncmp((char *)new, (char *)old,
strlen((char *)new))) < 0 ? 1 : 0);
}
/**
* sysfs_del_name: free function for sysfs_open_subsystem_list
* @name: memory area to be freed
*/
static void sysfs_del_name(void *name)
{
free(name);
}
/**
* sysfs_del_attribute: routine for dlist integration
*/
static void sysfs_del_attribute(void *attr)
{
sysfs_close_attribute((struct sysfs_attribute *)attr);
}
/**
* attr_name_equal: compares attributes by name
* @a: attribute name for comparison
* @b: sysfs_attribute to be compared.
* returns 1 if a==b->name or 0 if not equal
*/
static int attr_name_equal(void *a, void *b)
{
if (!a || !b)
return 0;
if (strcmp(((char *)a), ((struct sysfs_attribute *)b)->name) == 0)
return 1;
return 0;
}
/**
* sysfs_close_attribute: closes and cleans up attribute
* @sysattr: attribute to close.
*/
void sysfs_close_attribute(struct sysfs_attribute *sysattr)
{
if (sysattr) {
if (sysattr->value)
free(sysattr->value);
free(sysattr);
}
}
/**
* alloc_attribute: allocates and initializes attribute structure
* returns struct sysfs_attribute with success and NULL with error.
*/
static struct sysfs_attribute *alloc_attribute(void)
{
return (struct sysfs_attribute *)
calloc(1, sizeof(struct sysfs_attribute));
}
/**
* sysfs_open_attribute: creates sysfs_attribute structure
* @path: path to attribute.
* returns sysfs_attribute struct with success and NULL with error.
*/
struct sysfs_attribute *sysfs_open_attribute(const char *path)
{
struct sysfs_attribute *sysattr = NULL;
struct stat fileinfo;
if (!path) {
errno = EINVAL;
return NULL;
}
sysattr = alloc_attribute();
if (!sysattr) {
dprintf("Error allocating attribute at %s\n", path);
return NULL;
}
if (sysfs_get_name_from_path(path, sysattr->name,
SYSFS_NAME_LEN) != 0) {
dprintf("Error retrieving attrib name from path: %s\n", path);
sysfs_close_attribute(sysattr);
return NULL;
}
safestrcpy(sysattr->path, path);
if ((stat(sysattr->path, &fileinfo)) != 0) {
dprintf("Stat failed: No such attribute?\n");
sysattr->method = 0;
free(sysattr);
sysattr = NULL;
} else {
if (fileinfo.st_mode & S_IRUSR)
sysattr->method |= SYSFS_METHOD_SHOW;
if (fileinfo.st_mode & S_IWUSR)
sysattr->method |= SYSFS_METHOD_STORE;
}
return sysattr;
}
/**
* sysfs_read_attribute: reads value from attribute
* @sysattr: attribute to read
* returns 0 with success and -1 with error.
*/
int sysfs_read_attribute(struct sysfs_attribute *sysattr)
{
char *fbuf = NULL;
char *vbuf = NULL;
ssize_t length = 0;
long pgsize = 0;
int fd;
if (!sysattr) {
errno = EINVAL;
return -1;
}
if (!(sysattr->method & SYSFS_METHOD_SHOW)) {
dprintf("Show method not supported for attribute %s\n",
sysattr->path);
errno = EACCES;
return -1;
}
pgsize = getpagesize();
fbuf = (char *)calloc(1, pgsize+1);
if (!fbuf) {
dprintf("calloc failed\n");
return -1;
}
if ((fd = open(sysattr->path, O_RDONLY)) < 0) {
dprintf("Error reading attribute %s\n", sysattr->path);
free(fbuf);
return -1;
}
length = read(fd, fbuf, pgsize);
if (length < 0) {
dprintf("Error reading from attribute %s\n", sysattr->path);
close(fd);
free(fbuf);
return -1;
}
if (sysattr->len > 0) {
if ((sysattr->len == length) &&
(!(strncmp(sysattr->value, fbuf, length)))) {
close(fd);
free(fbuf);
return 0;
}
free(sysattr->value);
}
sysattr->len = length;
close(fd);
vbuf = (char *)realloc(fbuf, length+1);
if (!vbuf) {
dprintf("realloc failed\n");
free(fbuf);
return -1;
}
sysattr->value = vbuf;
return 0;
}
/**
* sysfs_write_attribute: write value to the attribute
* @sysattr: attribute to write
* @new_value: value to write
* @len: length of "new_value"
* returns 0 with success and -1 with error.
*/
int sysfs_write_attribute(struct sysfs_attribute *sysattr,
const char *new_value, size_t len)
{
int fd;
int length;
if (!sysattr || !new_value || len == 0) {
errno = EINVAL;
return -1;
}
if (!(sysattr->method & SYSFS_METHOD_STORE)) {
dprintf ("Store method not supported for attribute %s\n",
sysattr->path);
errno = EACCES;
return -1;
}
if (sysattr->method & SYSFS_METHOD_SHOW) {
/*
* read attribute again to see if we can get an updated value
*/
if ((sysfs_read_attribute(sysattr))) {
dprintf("Error reading attribute\n");
return -1;
}
if ((strncmp(sysattr->value, new_value, sysattr->len)) == 0) {
dprintf("Attr %s already has the requested value %s\n",
sysattr->name, new_value);
return 0;
}
}
/*
* open O_WRONLY since some attributes have no "read" but only
* "write" permission
*/
if ((fd = open(sysattr->path, O_WRONLY)) < 0) {
dprintf("Error reading attribute %s\n", sysattr->path);
return -1;
}
length = write(fd, new_value, len);
if (length < 0) {
dprintf("Error writing to the attribute %s - invalid value?\n",
sysattr->name);
close(fd);
return -1;
} else if ((unsigned int)length != len) {
dprintf("Could not write %zd bytes to attribute %s\n",
len, sysattr->name);
/*
* since we could not write user supplied number of bytes,
* restore the old value if one available
*/
if (sysattr->method & SYSFS_METHOD_SHOW) {
length = write(fd, sysattr->value, sysattr->len);
close(fd);
return -1;
}
}
/*
* Validate length that has been copied. Alloc appropriate area
* in sysfs_attribute. Verify first if the attribute supports reading
* (show method). If it does not, do not bother
*/
if (sysattr->method & SYSFS_METHOD_SHOW) {
if (length != sysattr->len) {
sysattr->value = (char *)realloc
(sysattr->value, length);
sysattr->len = length;
safestrcpymax(sysattr->value, new_value, length);
} else {
/*"length" of the new value is same as old one */
safestrcpymax(sysattr->value, new_value, length);
}
}
close(fd);
return 0;
}
/**
* add_attribute: open and add attribute at path to given directory
* @dev: device whose attribute is to be added
* @path: path to attribute
* returns pointer to attr added with success and NULL with error.
*/
static struct sysfs_attribute *add_attribute(void *dev, const char *path)
{
struct sysfs_attribute *attr;
attr = sysfs_open_attribute(path);
if (!attr) {
dprintf("Error opening attribute %s\n", path);
return NULL;
}
if (attr->method & SYSFS_METHOD_SHOW) {
if (sysfs_read_attribute(attr)) {
dprintf("Error reading attribute %s\n", path);
sysfs_close_attribute(attr);
return NULL;
}
}
if (!((struct sysfs_device *)dev)->attrlist) {
((struct sysfs_device *)dev)->attrlist = dlist_new_with_delete
(sizeof(struct sysfs_attribute), sysfs_del_attribute);
}
dlist_unshift_sorted(((struct sysfs_device *)dev)->attrlist,
attr, sort_list);
return attr;
}
/*
* get_attribute - given a sysfs_* struct and a name, return the
* sysfs_attribute corresponding to "name"
* returns sysfs_attribute on success and NULL on error
*/
struct sysfs_attribute *get_attribute(void *dev, const char *name)
{
struct sysfs_attribute *cur = NULL;
char path[SYSFS_PATH_MAX];
if (!dev || !name) {
errno = EINVAL;
return NULL;
}
if (((struct sysfs_device *)dev)->attrlist) {
/* check if attr is already in the list */
cur = (struct sysfs_attribute *)dlist_find_custom
((((struct sysfs_device *)dev)->attrlist),
(void *)name, attr_name_equal);
if (cur)
return cur;
}
safestrcpymax(path, ((struct sysfs_device *)dev)->path,
SYSFS_PATH_MAX);
safestrcatmax(path, "/", SYSFS_PATH_MAX);
safestrcatmax(path, name, SYSFS_PATH_MAX);
if (!sysfs_path_is_file(path))
cur = add_attribute((void *)dev, path);
return cur;
}
/**
* read_dir_links: grabs links in a specific directory
* @sysdir: sysfs directory to read
* returns list of link names with success and NULL with error.
*/
struct dlist *read_dir_links(const char *path)
{
DIR *dir = NULL;
struct dirent *dirent = NULL;
char file_path[SYSFS_PATH_MAX], *linkname;
struct dlist *linklist = NULL;
if (!path) {
errno = EINVAL;
return NULL;
}
dir = opendir(path);
if (!dir) {
dprintf("Error opening directory %s\n", path);
return NULL;
}
while ((dirent = readdir(dir)) != NULL) {
if (0 == strcmp(dirent->d_name, "."))
continue;
if (0 == strcmp(dirent->d_name, ".."))
continue;
memset(file_path, 0, SYSFS_PATH_MAX);
safestrcpy(file_path, path);
safestrcat(file_path, "/");
safestrcat(file_path, dirent->d_name);
if (!sysfs_path_is_link(file_path)) {
if (!linklist) {
linklist = dlist_new_with_delete
(SYSFS_NAME_LEN, sysfs_del_name);
if (!linklist) {
dprintf("Error creating list\n");
return NULL;
}
}
linkname = (char *)calloc(1, SYSFS_NAME_LEN);
safestrcpymax(linkname, dirent->d_name, SYSFS_NAME_LEN);
dlist_unshift_sorted(linklist, linkname, sort_char);
}
}
closedir(dir);
return linklist;
}
/**
* read_dir_subdirs: grabs subdirs in a specific directory
* @sysdir: sysfs directory to read
* returns list of directory names with success and NULL with error.
*/
struct dlist *read_dir_subdirs(const char *path)
{
DIR *dir = NULL;
struct dirent *dirent = NULL;
char file_path[SYSFS_PATH_MAX], *dir_name;
struct dlist *dirlist = NULL;
if (!path) {
errno = EINVAL;
return NULL;
}
dir = opendir(path);
if (!dir) {
dprintf("Error opening directory %s\n", path);
return NULL;
}
while ((dirent = readdir(dir)) != NULL) {
if (0 == strcmp(dirent->d_name, "."))
continue;
if (0 == strcmp(dirent->d_name, ".."))
continue;
memset(file_path, 0, SYSFS_PATH_MAX);
safestrcpy(file_path, path);
safestrcat(file_path, "/");
safestrcat(file_path, dirent->d_name);
if (!sysfs_path_is_dir(file_path)) {
if (!dirlist) {
dirlist = dlist_new_with_delete
(SYSFS_NAME_LEN, sysfs_del_name);
if (!dirlist) {
dprintf("Error creating list\n");
return NULL;
}
}
dir_name = (char *)calloc(1, SYSFS_NAME_LEN);
safestrcpymax(dir_name, dirent->d_name, SYSFS_NAME_LEN);
dlist_unshift_sorted(dirlist, dir_name, sort_char);
}
}
closedir(dir);
return dirlist;
}
/**
* get_attributes_list: build a list of attributes for the given device
* @dev: devices whose attributes list is required
* returns dlist of attributes on success and NULL on failure
*/
struct dlist *get_attributes_list(void *dev)
{
DIR *dir = NULL;
struct dirent *dirent = NULL;
struct sysfs_attribute *attr = NULL;
char file_path[SYSFS_PATH_MAX], path[SYSFS_PATH_MAX];
if (!dev) {
errno = EINVAL;
return NULL;
}
memset(path, 0, SYSFS_PATH_MAX);
safestrcpy(path, ((struct sysfs_device *)dev)->path);
dir = opendir(path);
if (!dir) {
dprintf("Error opening directory %s\n", path);
return NULL;
}
while ((dirent = readdir(dir)) != NULL) {
if (0 == strcmp(dirent->d_name, "."))
continue;
if (0 == strcmp(dirent->d_name, ".."))
continue;
memset(file_path, 0, SYSFS_PATH_MAX);
safestrcpy(file_path, path);
safestrcat(file_path, "/");
safestrcat(file_path, dirent->d_name);
if (!sysfs_path_is_file(file_path)) {
if (((struct sysfs_device *)dev)->attrlist) {
/* check if attr is already in the list */
attr = (struct sysfs_attribute *)
dlist_find_custom
((((struct sysfs_device *)dev)->attrlist),
(void *)dirent->d_name, attr_name_equal);
if (attr)
continue;
else
add_attribute(dev, file_path);
} else
attr = add_attribute(dev, file_path);
}
}
closedir(dir);
return ((struct sysfs_device *)dev)->attrlist;
}
-261
View File
@@ -1,261 +0,0 @@
/*
* sysfs_driver.c
*
* Driver utility functions for libsysfs
*
* Copyright (C) IBM Corp. 2003-2005
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include "libsysfs.h"
#include "sysfs.h"
static void sysfs_close_driver_device(void *device)
{
sysfs_close_device((struct sysfs_device *)device);
}
/**
* sysfs_close_driver: closes driver and deletes device lists too
* @driver: driver to close
*/
void sysfs_close_driver(struct sysfs_driver *driver)
{
if (driver) {
if (driver->devices)
dlist_destroy(driver->devices);
if (driver->attrlist)
dlist_destroy(driver->attrlist);
free(driver);
}
}
/**
* alloc_driver: allocates and initializes driver
* returns struct sysfs_driver with success and NULL with error.
*/
static struct sysfs_driver *alloc_driver(void)
{
return (struct sysfs_driver *)calloc(1, sizeof(struct sysfs_driver));
}
/**
* get_driver_bus: gets bus the driver is on
* Returns 0 on success and 1 on error
*/
static int get_driver_bus(struct sysfs_driver *drv)
{
char drvpath[SYSFS_PATH_MAX], *c = NULL;
if (!drv) {
errno = EINVAL;
return 1;
}
safestrcpy(drvpath, drv->path);
c = strstr(drvpath, SYSFS_DRIVERS_NAME);
if (c == NULL)
return 1;
*--c = '\0';
c = strstr(drvpath, SYSFS_BUS_NAME);
if (c == NULL)
return 1;
c = strstr(c, "/");
if (c == NULL)
return 1;
c++;
safestrcpy(drv->bus, c);
return 0;
}
/**
* sysfs_get_driver_attr: searches drv's attributes by name
* @drv: driver to look through
* @name: attribute name to get
* returns sysfs_attribute reference with success or NULL with error.
*/
struct sysfs_attribute *sysfs_get_driver_attr(struct sysfs_driver *drv,
const char *name)
{
if (!drv || !name) {
errno = EINVAL;
return NULL;
}
return get_attribute(drv, (char *)name);
}
/**
* sysfs_get_driver_attributes: gets list of driver attributes
* @dev: driver whose attributes list is needed
* returns dlist of attributes on success or NULL on error
*/
struct dlist *sysfs_get_driver_attributes(struct sysfs_driver *drv)
{
if (!drv) {
errno = EINVAL;
return NULL;
}
return get_attributes_list(drv);
}
/**
* sysfs_open_driver_path: opens and initializes driver structure
* @path: path to driver directory
* returns struct sysfs_driver with success and NULL with error
*/
struct sysfs_driver *sysfs_open_driver_path(const char *path)
{
struct sysfs_driver *driver = NULL;
if (!path) {
errno = EINVAL;
return NULL;
}
if (sysfs_path_is_dir(path)) {
dprintf("Invalid path to driver: %s\n", path);
return NULL;
}
driver = alloc_driver();
if (!driver) {
dprintf("Error allocating driver at %s\n", path);
return NULL;
}
if (sysfs_get_name_from_path(path, driver->name, SYSFS_NAME_LEN)) {
dprintf("Error getting driver name from path\n");
free(driver);
return NULL;
}
safestrcpy(driver->path, path);
if (sysfs_remove_trailing_slash(driver->path)) {
dprintf("Invalid path to driver %s\n", driver->path);
sysfs_close_driver(driver);
return NULL;
}
if (get_driver_bus(driver)) {
dprintf("Could not get the bus driver is on\n");
sysfs_close_driver(driver);
return NULL;
}
return driver;
}
/**
* get_driver_path: looks up the bus the driver is on and builds path to
* the driver.
* @bus: bus on which to search
* @drv: driver to look for
* @path: buffer to return path to driver
* @psize: size of "path"
* Returns 0 on success and -1 on error
*/
static int get_driver_path(const char *bus, const char *drv,
char *path, size_t psize)
{
if (!bus || !drv || !path || psize == 0) {
errno = EINVAL;
return -1;
}
if (sysfs_get_mnt_path(path, psize)) {
dprintf("Error getting sysfs mount path\n");
return -1;
}
safestrcatmax(path, "/", psize);
safestrcatmax(path, SYSFS_BUS_NAME, psize);
safestrcatmax(path, "/", psize);
safestrcatmax(path, bus, psize);
safestrcatmax(path, "/", psize);
safestrcatmax(path, SYSFS_DRIVERS_NAME, psize);
safestrcatmax(path, "/", psize);
safestrcatmax(path, drv, psize);
return 0;
}
/**
* sysfs_open_driver: open driver by name, given its bus
* @bus_name: Name of the bus
* @drv_name: Name of the driver
* Returns the sysfs_driver reference on success and NULL on failure
*/
struct sysfs_driver *sysfs_open_driver(const char *bus_name,
const char *drv_name)
{
char path[SYSFS_PATH_MAX];
struct sysfs_driver *driver = NULL;
if (!drv_name || !bus_name) {
errno = EINVAL;
return NULL;
}
memset(path, 0, SYSFS_PATH_MAX);
if (get_driver_path(bus_name, drv_name, path, SYSFS_PATH_MAX)) {
dprintf("Error getting to driver %s\n", drv_name);
return NULL;
}
driver = sysfs_open_driver_path(path);
if (!driver) {
dprintf("Error opening driver at %s\n", path);
return NULL;
}
return driver;
}
/**
* sysfs_get_driver_devices: gets list of devices that use the driver
* @drv: sysfs_driver whose device list is needed
* Returns dlist of struct sysfs_device on success and NULL on failure
*/
struct dlist *sysfs_get_driver_devices(struct sysfs_driver *drv)
{
char *ln = NULL;
struct dlist *linklist = NULL;
struct sysfs_device *dev = NULL;
if (!drv) {
errno = EINVAL;
return NULL;
}
linklist = read_dir_links(drv->path);
if (linklist) {
dlist_for_each_data(linklist, ln, char) {
if (!strncmp(ln, SYSFS_MODULE_NAME, strlen(ln)))
continue;
dev = sysfs_open_device(drv->bus, ln);
if (!dev) {
dprintf("Error opening driver's device\n");
sysfs_close_list(linklist);
return NULL;
}
if (!drv->devices) {
drv->devices = dlist_new_with_delete
(sizeof(struct sysfs_device),
sysfs_close_driver_device);
if (!drv->devices) {
dprintf("Error creating device list\n");
sysfs_close_list(linklist);
return NULL;
}
}
dlist_unshift_sorted(drv->devices, dev, sort_list);
}
sysfs_close_list(linklist);
}
return drv->devices;
}
-290
View File
@@ -1,290 +0,0 @@
/*
* sysfs_utils.c
*
* System utility functions for libsysfs
*
* Copyright (C) IBM Corp. 2003-2005
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include "libsysfs.h"
#include "sysfs.h"
/**
* sysfs_remove_trailing_slash: Removes any trailing '/' in the given path
* @path: Path to look for the trailing '/'
* Returns 0 on success 1 on error
*/
int sysfs_remove_trailing_slash(char *path)
{
size_t len;
if (!path) {
errno = EINVAL;
return 1;
}
len = strlen(path);
while (len > 0 && path[len-1] == '/')
path[--len] = '\0';
return 0;
}
/*
* sysfs_get_mnt_path: Gets the sysfs mount point.
* @mnt_path: place to put "sysfs" mount point
* @len: size of mnt_path
* returns 0 with success and -1 with error.
*/
int sysfs_get_mnt_path(char *mnt_path, size_t len)
{
static char sysfs_path[SYSFS_PATH_MAX] = "";
const char *sysfs_path_env;
/* evaluate only at the first call */
if (sysfs_path[0] == '\0') {
/* possible overrride of real mount path */
sysfs_path_env = getenv(SYSFS_PATH_ENV);
if (sysfs_path_env != NULL) {
safestrcpymax(mnt_path, sysfs_path_env, len);
sysfs_remove_trailing_slash(mnt_path);
return 0;
}
safestrcpymax(mnt_path, SYSFS_MNT_PATH, len);
}
return 0;
}
/**
* sysfs_get_name_from_path: returns last name from a "/" delimited path
* @path: path to get name from
* @name: where to put name
* @len: size of name
*/
int sysfs_get_name_from_path(const char *path, char *name, size_t len)
{
char tmp[SYSFS_PATH_MAX];
char *n = NULL;
if (!path || !name || len == 0) {
errno = EINVAL;
return -1;
}
memset(tmp, 0, SYSFS_PATH_MAX);
safestrcpy(tmp, path);
n = strrchr(tmp, '/');
if (n == NULL) {
errno = EINVAL;
return -1;
}
if (*(n+1) == '\0') {
*n = '\0';
n = strrchr(tmp, '/');
if (n == NULL) {
errno = EINVAL;
return -1;
}
}
n++;
safestrcpymax(name, n, len);
return 0;
}
/**
* sysfs_get_link: returns link source
* @path: symbolic link's path
* @target: where to put name
* @len: size of name
*/
int sysfs_get_link(const char *path, char *target, size_t len)
{
char devdir[SYSFS_PATH_MAX];
char linkpath[SYSFS_PATH_MAX];
char temp_path[SYSFS_PATH_MAX];
char *d = NULL, *s = NULL;
int slashes = 0, count = 0;
if (!path || !target || len == 0) {
errno = EINVAL;
return -1;
}
memset(devdir, 0, SYSFS_PATH_MAX);
memset(linkpath, 0, SYSFS_PATH_MAX);
memset(temp_path, 0, SYSFS_PATH_MAX);
safestrcpy(devdir, path);
if ((readlink(path, linkpath, SYSFS_PATH_MAX)) < 0) {
return -1;
}
d = linkpath;
/*
* Three cases here:
* 1. relative path => format ../..
* 2. absolute path => format /abcd/efgh
* 3. relative path _from_ this dir => format abcd/efgh
*/
switch (*d) {
case '.':
/*
* handle the case where link is of type ./abcd/xxx
*/
safestrcpy(temp_path, devdir);
if (*(d+1) == '/')
d += 2;
else if (*(d+1) == '.')
goto parse_path;
s = strrchr(temp_path, '/');
if (s != NULL) {
*(s+1) = '\0';
safestrcat(temp_path, d);
} else {
safestrcpy(temp_path, d);
}
safestrcpymax(target, temp_path, len);
break;
/*
* relative path, getting rid of leading "../.."
*/
parse_path:
while (*d == '/' || *d == '.') {
if (*d == '/')
slashes++;
d++;
}
d--;
s = &devdir[strlen(devdir)-1];
while (s != NULL && count != (slashes+1)) {
s--;
if (*s == '/')
count++;
}
safestrcpymax(s, d, (SYSFS_PATH_MAX-strlen(devdir)));
safestrcpymax(target, devdir, len);
break;
case '/':
/* absolute path - copy as is */
safestrcpymax(target, linkpath, len);
break;
default:
/* relative path from this directory */
safestrcpy(temp_path, devdir);
s = strrchr(temp_path, '/');
if (s != NULL) {
*(s+1) = '\0';
safestrcat(temp_path, linkpath);
} else {
safestrcpy(temp_path, linkpath);
}
safestrcpymax(target, temp_path, len);
}
return 0;
}
/**
* sysfs_close_list: generic list free routine
* @list: dlist to free
* Returns nothing
*/
void sysfs_close_list(struct dlist *list)
{
if (list)
dlist_destroy(list);
}
/**
* sysfs_open_directory_list: gets a list of all directories under "path"
* @path: path to read
* Returns a dlist of supported names or NULL no directories (errno is set
* in case of error
*/
struct dlist *sysfs_open_directory_list(const char *path)
{
if (!path)
return NULL;
return (read_dir_subdirs(path));
}
/**
* sysfs_path_is_dir: Check if the path supplied points to a directory
* @path: path to validate
* Returns 0 if path points to dir, 1 otherwise
*/
int sysfs_path_is_dir(const char *path)
{
struct stat astats;
if (!path) {
errno = EINVAL;
return 1;
}
if ((lstat(path, &astats)) != 0) {
dprintf("stat() failed\n");
return 1;
}
if (S_ISDIR(astats.st_mode))
return 0;
return 1;
}
/**
* sysfs_path_is_link: Check if the path supplied points to a link
* @path: path to validate
* Returns 0 if path points to link, 1 otherwise
*/
int sysfs_path_is_link(const char *path)
{
struct stat astats;
if (!path) {
errno = EINVAL;
return 1;
}
if ((lstat(path, &astats)) != 0) {
dprintf("stat() failed\n");
return 1;
}
if (S_ISLNK(astats.st_mode))
return 0;
return 1;
}
/**
* sysfs_path_is_file: Check if the path supplied points to a file
* @path: path to validate
* Returns 0 if path points to file, 1 otherwise
*/
int sysfs_path_is_file(const char *path)
{
struct stat astats;
if (!path) {
errno = EINVAL;
return 1;
}
if ((lstat(path, &astats)) != 0) {
dprintf("stat() failed\n");
return 1;
}
if (S_ISREG(astats.st_mode))
return 0;
return 1;
}
+1 -2
View File
@@ -23,8 +23,7 @@ make all $MAKEOPTS USE_LOG=false EXTRAS="$EXTRAS" || exit
echo -e "\n\n"
# klibc build
[ -z "$KLCC" ] && KLCC=/usr/bin/klcc
if [ -e "$KLCC" ]; then
if [ -n "$KLCC" -a -e "$KLCC" ]; then
echo KLCC: "$KLCC"
make clean EXTRAS="$EXTRAS" >/dev/null
make all -j4 $MAKEOPTS USE_KLIBC=true DEBUG=true EXTRAS="$EXTRAS" KLCC="$KLCC" || exit
+29 -22
View File
@@ -243,18 +243,18 @@ EOF
desc => "test substitution chars",
subsys => "block",
devpath => "/block/sda/sda3",
exp_name => "Major:8:minor:3:kernelnumber:3:bus:0:0:0:0" ,
exp_name => "Major:8:minor:3:kernelnumber:3" ,
rules => <<EOF
BUS=="scsi", ID=="0:0:0:0", NAME="Major:%M:minor:%m:kernelnumber:%n:bus:%b"
BUS=="scsi", ID=="0:0:0:0", NAME="Major:%M:minor:%m:kernelnumber:%n"
EOF
},
{
desc => "test substitution chars (with length limit)",
subsys => "block",
devpath => "/block/sda/sda3",
exp_name => "M8-m3-n3-b0:0-sIBM" ,
exp_name => "M8-m3-n3-bsd-sIBM" ,
rules => <<EOF
BUS=="scsi", ID=="0:0:0:0", NAME="M%M-m%m-n%n-b%3b-s%3s{vendor}"
BUS=="scsi", ID=="0:0:0:0", NAME="M%M-m%m-n%n-b%2k-s%3s{vendor}"
EOF
},
{
@@ -322,9 +322,9 @@ EOF
desc => "program result substitution",
subsys => "block",
devpath => "/block/sda/sda3",
exp_name => "test-0:0:0:0" ,
exp_name => "test-3" ,
rules => <<EOF
BUS=="scsi", PROGRAM=="/bin/echo -n test-%b", RESULT=="test-0:0*", NAME="%c"
BUS=="scsi", PROGRAM=="/bin/echo -n test-%n", RESULT=="test-3*", NAME="%c"
EOF
},
{
@@ -385,27 +385,27 @@ EOF
desc => "test substitution by variable name",
subsys => "block",
devpath => "/block/sda/sda3",
exp_name => "Major:8-minor:3-kernelnumber:3-bus:0:0:0:0" ,
exp_name => "Major:8-minor:3-kernelnumber:3" ,
rules => <<EOF
BUS=="scsi", ID=="0:0:0:0", NAME="Major:\$major-minor:\$minor-kernelnumber:\$number-bus:\$id"
BUS=="scsi", ID=="0:0:0:0", NAME="Major:\$major-minor:\$minor-kernelnumber:\$number"
EOF
},
{
desc => "test substitution by variable name 2",
subsys => "block",
devpath => "/block/sda/sda3",
exp_name => "Major:8-minor:3-kernelnumber:3-bus:0:0:0:0" ,
exp_name => "Major:8-minor:3-kernelnumber:3-name:sda3" ,
rules => <<EOF
BUS=="scsi", ID=="0:0:0:0", DEVPATH="*/sda/*", NAME="Major:\$major-minor:%m-kernelnumber:\$number-bus:%b"
BUS=="scsi", ID=="0:0:0:0", DEVPATH="*/sda/*", NAME="Major:\$major-minor:%m-kernelnumber:\$number-name:\$kernel"
EOF
},
{
desc => "test substitution by variable name 3",
subsys => "block",
devpath => "/block/sda/sda3",
exp_name => "830:0:0:03" ,
exp_name => "83sda33" ,
rules => <<EOF
BUS=="scsi", ID=="0:0:0:0", DEVPATH="*/sda/*", NAME="%M%m%b%n"
BUS=="scsi", ID=="0:0:0:0", DEVPATH="*/sda/*", NAME="%M%m%k%n"
EOF
},
{
@@ -421,9 +421,9 @@ EOF
desc => "test substitution by variable name 5",
subsys => "block",
devpath => "/block/sda/sda3",
exp_name => "8330:0:0:0" ,
exp_name => "833sda3" ,
rules => <<EOF
BUS=="scsi", ID=="0:0:0:0", DEVPATH="*/sda/*", NAME="\$major%m%n\$id"
BUS=="scsi", ID=="0:0:0:0", DEVPATH="*/sda/*", NAME="\$major%m%n\$kernel"
EOF
},
{
@@ -470,11 +470,11 @@ EOF
desc => "program and bus type match",
subsys => "block",
devpath => "/block/sda",
exp_name => "scsi-0:0:0:0" ,
exp_name => "scsi-sda" ,
rules => <<EOF
BUS=="usb", PROGRAM=="/bin/echo -n usb-%b", NAME="%c"
BUS=="scsi", PROGRAM=="/bin/echo -n scsi-%b", NAME="%c"
BUS=="foo", PROGRAM=="/bin/echo -n foo-%b", NAME="%c"
BUS=="usb", PROGRAM=="/bin/echo -n usb-%k", NAME="%c"
BUS=="scsi", PROGRAM=="/bin/echo -n scsi-%k", NAME="%c"
BUS=="foo", PROGRAM=="/bin/echo -n foo-%k", NAME="%c"
EOF
},
{
@@ -797,7 +797,7 @@ EOF
exp_name => "symlink2-ttyUSB0",
exp_target => "ttyUSB0",
rules => <<EOF
KERNEL=="ttyUSB[0-9]*", NAME="ttyUSB%n", SYMLINK="symlink1-%n symlink2-%k symlink3-%b"
KERNEL=="ttyUSB[0-9]*", NAME="ttyUSB%n", SYMLINK="symlink1-%n symlink2-%k"
EOF
},
{
@@ -918,13 +918,13 @@ KERNEL=="ttyUSB[0-9]*", NAME="ttyUSB%n", SYMLINK+="major-%M:%m"
EOF
},
{
desc => "symlink %b substitution",
desc => "symlink %k substitution",
subsys => "block",
devpath => "/block/sda",
exp_name => "symlink-0:0:0:0",
exp_name => "symlink-sda",
exp_target => "node",
rules => <<EOF
BUS=="scsi", KERNEL=="sda", NAME="node", SYMLINK+="symlink-%b"
BUS=="scsi", KERNEL=="sda", NAME="node", SYMLINK+="symlink-%k"
EOF
},
{
@@ -1564,6 +1564,13 @@ sub udev {
$ENV{DEVPATH} = $devpath;
open my $fd, "$sysfs$devpath/dev";
my $dev = <$fd>;
close $fd;
$dev =~ m/^(.+):(.+)$/;
$ENV{MAJOR} = $1;
$ENV{MINOR} = $2;
# create temporary rules
open CONF, ">$udev_rules" || die "unable to create rules file: $udev_rules";
print CONF $$rules;
+37 -16
View File
@@ -30,13 +30,8 @@
#include <unistd.h>
#include <syslog.h>
#include "libsysfs/sysfs/libsysfs.h"
#include "udev_libc_wrapper.h"
#include "udev.h"
#include "udev_utils.h"
#include "udev_version.h"
#include "udev_rules.h"
#include "logging.h"
#ifdef USE_LOG
void log_message(int priority, const char *format, ...)
@@ -65,7 +60,9 @@ static void asmlinkage sig_handler(int signum)
int main(int argc, char *argv[], char *envp[])
{
struct udevice udev;
struct sysfs_device *dev;
struct udevice *udev;
const char *maj, *min;
struct udev_rules rules;
const char *action;
const char *devpath;
@@ -95,7 +92,7 @@ int main(int argc, char *argv[], char *envp[])
logging_init("udev");
if (devnull < 0)
err("fatal, could not open /dev/null: %s", strerror(errno));
udev_init_config();
udev_config_init();
dbg("version %s", UDEV_VERSION);
/* set signal handlers */
@@ -114,10 +111,10 @@ int main(int argc, char *argv[], char *envp[])
devpath = getenv("DEVPATH");
subsystem = getenv("SUBSYSTEM");
/* older kernels passed the SUBSYSTEM only as argument */
if (!subsystem && argc == 2)
if (subsystem == NULL && argc == 2)
subsystem = argv[1];
if (!action || !subsystem || !devpath) {
if (action == NULL || subsystem == NULL || devpath == NULL) {
err("action, subsystem or devpath missing");
goto exit;
}
@@ -130,25 +127,49 @@ int main(int argc, char *argv[], char *envp[])
setenv("UDEV_LOG", priority, 1);
}
udev_init_device(&udev, devpath, subsystem, action);
sysfs_init();
udev_rules_init(&rules, 0);
retval = udev_process_event(&rules, &udev);
dev = sysfs_device_get(devpath);
if (dev == NULL) {
info("unable to open '%s'", devpath);
goto fail;
}
if (!retval && udev_run && !list_empty(&udev.run_list)) {
udev = udev_device_init();
if (udev == NULL)
goto fail;
/* override built-in sysfs device */
udev->dev = dev;
strlcpy(udev->action, action, sizeof(udev->action));
/* get dev_t from environment, which is needed for "remove" to work, "add" works also from sysfs */
maj = getenv("MAJOR");
min = getenv("MINOR");
if (maj != NULL && min != NULL)
udev->devt = makedev(atoi(maj), atoi(min));
else
udev->devt = udev_device_get_devt(udev);
retval = udev_device_event(&rules, udev);
if (!retval && udev_run && !list_empty(&udev->run_list)) {
struct name_entry *name_loop;
dbg("executing run list");
list_for_each_entry(name_loop, &udev.run_list, node) {
list_for_each_entry(name_loop, &udev->run_list, node) {
if (strncmp(name_loop->name, "socket:", strlen("socket:")) == 0)
pass_env_to_socket(&name_loop->name[strlen("socket:")], devpath, action);
else
run_program(name_loop->name, udev.subsystem, NULL, 0, NULL, (udev_log_priority >= LOG_INFO));
run_program(name_loop->name, udev->dev->subsystem, NULL, 0, NULL, (udev_log_priority >= LOG_INFO));
}
}
udev_rules_close(&rules);
udev_cleanup_device(&udev);
udev_device_cleanup(udev);
fail:
udev_rules_cleanup(&rules);
sysfs_cleanup();
exit:
logging_close();
+81 -29
View File
@@ -24,8 +24,11 @@
#include <sys/types.h>
#include <sys/param.h>
#include "libsysfs/sysfs/libsysfs.h"
#include "list.h"
#include "logging.h"
#include "udev_libc_wrapper.h"
#include "udev_version.h"
#define COMMENT_CHARACTER '#'
#define PATH_TO_NAME_CHAR '@'
@@ -39,24 +42,32 @@
#define DEFAULT_PARTITIONS_COUNT 15
#define UDEV_ALARM_TIMEOUT 180
#define UDEV_MAX(a,b) ((a) > (b) ? (a) : (b))
/* pipes */
#define READ_END 0
#define WRITE_END 1
#define DB_DIR ".udev/db"
struct udev_rules;
enum device_type {
DEV_UNKNOWN,
DEV_CLASS,
DEV_BLOCK,
DEV_NET,
DEV_DEVICE,
struct sysfs_device {
struct list_head node; /* for device cache */
char devpath[PATH_SIZE];
char subsystem[NAME_SIZE]; /* $class/$bus/"drivers */
char kernel_name[NAME_SIZE]; /* device instance name */
char kernel_number[NAME_SIZE];
char driver[NAME_SIZE]; /* device driver name */
};
struct udevice {
char devpath[PATH_SIZE];
char subsystem[NAME_SIZE];
/* device event */
struct sysfs_device *dev;
struct sysfs_device dev_local;
char action[NAME_SIZE];
enum device_type type;
/* node */
char name[PATH_SIZE];
struct list_head symlink_list;
int symlink_final;
@@ -67,42 +78,83 @@ struct udevice {
mode_t mode;
int mode_final;
dev_t devt;
/* event processing */
struct list_head run_list;
int run_final;
struct list_head env_list;
char tmp_node[PATH_SIZE];
int partitions;
int ignore_device;
int ignore_remove;
char bus_id[NAME_SIZE];
char program_result[PATH_SIZE];
char kernel_number[NAME_SIZE];
char kernel_name[NAME_SIZE];
int test_run;
};
extern int udev_init_device(struct udevice *udev, const char* devpath, const char *subsystem, const char *action);
extern void udev_cleanup_device(struct udevice *udev);
extern dev_t get_devt(struct sysfs_class_device *class_dev);
extern int udev_process_event(struct udev_rules *rules, struct udevice *udev);
extern int udev_add_device(struct udevice *udev, struct sysfs_class_device *class_dev);
extern int udev_remove_device(struct udevice *udev);
extern void udev_init_config(void);
extern int udev_start(void);
extern int udev_make_node(struct udevice *udev, const char *file, dev_t devt, mode_t mode, uid_t uid, gid_t gid);
/* udev_config.c */
extern char udev_root[PATH_SIZE];
extern char udev_config_filename[PATH_SIZE];
extern char udev_rules_filename[PATH_SIZE];
extern int udev_log_priority;
extern int udev_run;
extern void udev_config_init(void);
/* udev_device.c */
extern struct udevice *udev_device_init(void);
extern void udev_device_cleanup(struct udevice *udev);
extern int udev_device_event(struct udev_rules *rules, struct udevice *udev);
extern dev_t udev_device_get_devt(struct udevice *udev);
/* udev_sysfs.c */
extern char sysfs_path[PATH_SIZE];
extern int sysfs_init(void);
extern void sysfs_cleanup(void);
extern void sysfs_device_set_values(struct sysfs_device *dev, const char *devpath, const char *subsystem);
extern struct sysfs_device *sysfs_device_get(const char *devpath);
extern struct sysfs_device *sysfs_device_get_parent(struct sysfs_device *dev);
extern char *sysfs_attr_get_value(const char *devpath, const char *attr_name);
/* udev_add.c / udev_remove.c */
extern int udev_add_device(struct udevice *udev);
extern int udev_make_node(struct udevice *udev, const char *file, dev_t devt, mode_t mode, uid_t uid, gid_t gid);
extern int udev_remove_device(struct udevice *udev);
/* udev_db.c */
extern int udev_db_add_device(struct udevice *dev);
extern int udev_db_delete_device(struct udevice *dev);
extern int udev_db_get_device(struct udevice *udev, const char *devpath);
extern int udev_db_lookup_name(const char *name, char *devpath, size_t len);
extern int udev_db_get_all_entries(struct list_head *name_list);
extern char sysfs_path[PATH_SIZE];
extern char udev_root[PATH_SIZE];
extern char udev_config_filename[PATH_SIZE];
extern char udev_rules_filename[PATH_SIZE];
extern int udev_log_priority;
extern int udev_run;
/* udev_utils.c */
struct name_entry {
struct list_head node;
char name[PATH_SIZE];
};
extern int log_priority(const char *priority);
extern int name_list_add(struct list_head *name_list, const char *name, int sort);
extern int name_list_key_add(struct list_head *name_list, const char *key, const char *value);
extern void name_list_cleanup(struct list_head *name_list);
extern int add_matching_files(struct list_head *name_list, const char *dirname, const char *suffix);
/* udev_utils_string.c */
extern int strcmp_pattern(const char *p, const char *s);
extern int string_is_true(const char *str);
extern void remove_trailing_chars(char *path, char c);
extern int utf8_encoded_valid_unichar(const char *str);
extern int replace_untrusted_chars(char *str);
/* udev_utils_file.c */
extern int create_path(const char *path);
extern int delete_path(const char *path);
extern int file_map(const char *filename, char **buf, size_t *bufsize);
extern void file_unmap(void *buf, size_t bufsize);
extern int unlink_secure(const char *filename);
extern size_t buf_get_line(const char *buf, size_t buflen, size_t cur);
/* udev_utils_run.c */
extern int pass_env_to_socket(const char *name, const char *devpath, const char *action);
extern int run_program(const char *command, const char *subsystem,
char *result, size_t ressize, size_t *reslen, int log);
#endif
+21 -33
View File
@@ -22,6 +22,7 @@
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stddef.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
@@ -29,16 +30,10 @@
#include <sys/types.h>
#include <grp.h>
#include <net/if.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <linux/sockios.h>
#include "libsysfs/sysfs/libsysfs.h"
#include "udev_libc_wrapper.h"
#include "udev.h"
#include "udev_utils.h"
#include "udev_version.h"
#include "logging.h"
#include "udev_rules.h"
#include "udev_selinux.h"
@@ -48,25 +43,18 @@ int udev_make_node(struct udevice *udev, const char *file, dev_t devt, mode_t mo
struct stat stats;
int retval = 0;
switch (udev->type) {
case DEV_BLOCK:
if (major(devt) != 0 && strcmp(udev->dev->subsystem, "block") == 0)
mode |= S_IFBLK;
break;
case DEV_CLASS:
else
mode |= S_IFCHR;
break;
default:
dbg("unknown node type %c\n", udev->type);
return -EINVAL;
}
if (stat(file, &stats) != 0)
goto create;
/* preserve node with already correct numbers, to not change the inode number */
/* preserve node with already correct numbers, to prevent changing the inode number */
if ((stats.st_mode & S_IFMT) == (mode & S_IFMT) && (stats.st_rdev == devt)) {
info("preserve file '%s', cause it has correct dev_t", file);
selinux_setfilecon(file, udev->kernel_name, stats.st_mode);
selinux_setfilecon(file, udev->dev->kernel_name, stats.st_mode);
goto perms;
}
@@ -76,7 +64,7 @@ int udev_make_node(struct udevice *udev, const char *file, dev_t devt, mode_t mo
dbg("already present file '%s' unlinked", file);
create:
selinux_setfscreatecon(file, udev->kernel_name, mode);
selinux_setfscreatecon(file, udev->dev->kernel_name, mode);
retval = mknod(file, mode, devt);
selinux_resetfscreatecon();
if (retval != 0) {
@@ -105,7 +93,7 @@ exit:
return retval;
}
static int create_node(struct udevice *udev, struct sysfs_class_device *class_dev)
static int create_node(struct udevice *udev)
{
char filename[PATH_SIZE];
struct name_entry *name_loop;
@@ -161,13 +149,13 @@ static int create_node(struct udevice *udev, struct sysfs_class_device *class_de
/* create all_partitions if requested */
if (udev->partitions) {
char partitionname[PATH_SIZE];
struct sysfs_attribute *attr;
char *attr;
int range;
/* take the maximum registered minor range */
attr = sysfs_get_classdev_attr(class_dev, "range");
attr = sysfs_attr_get_value(udev->dev->devpath, "range");
if (attr) {
range = atoi(attr->value);
range = atoi(attr);
if (range > 1)
udev->partitions = range-1;
}
@@ -247,7 +235,7 @@ static int rename_net_if(struct udevice *udev)
struct ifreq ifr;
int retval;
info("changing net interface name from '%s' to '%s'", udev->kernel_name, udev->name);
info("changing net interface name from '%s' to '%s'", udev->dev->kernel_name, udev->name);
if (udev->test_run)
return 0;
@@ -258,7 +246,7 @@ static int rename_net_if(struct udevice *udev)
}
memset(&ifr, 0x00, sizeof(struct ifreq));
strlcpy(ifr.ifr_name, udev->kernel_name, IFNAMSIZ);
strlcpy(ifr.ifr_name, udev->dev->kernel_name, IFNAMSIZ);
strlcpy(ifr.ifr_newname, udev->name, IFNAMSIZ);
retval = ioctl(sk, SIOCSIFNAME, &ifr);
@@ -269,7 +257,7 @@ static int rename_net_if(struct udevice *udev)
return retval;
}
int udev_add_device(struct udevice *udev, struct sysfs_class_device *class_dev)
int udev_add_device(struct udevice *udev)
{
char *pos;
int retval = 0;
@@ -277,16 +265,16 @@ int udev_add_device(struct udevice *udev, struct sysfs_class_device *class_dev)
dbg("adding name='%s'", udev->name);
selinux_init();
if (udev->type == DEV_BLOCK || udev->type == DEV_CLASS) {
retval = create_node(udev, class_dev);
if (major(udev->devt)) {
retval = create_node(udev);
if (retval != 0)
goto exit;
if (udev_db_add_device(udev) != 0)
dbg("udev_db_add_dev failed, remove might not work for custom names");
} else if (udev->type == DEV_NET) {
} else if (strcmp(udev->dev->subsystem, "net") == 0) {
/* look if we want to change the name of the netif */
if (strcmp(udev->name, udev->kernel_name) != 0) {
if (strcmp(udev->name, udev->dev->kernel_name) != 0) {
retval = rename_net_if(udev);
if (retval != 0)
goto exit;
@@ -296,12 +284,12 @@ int udev_add_device(struct udevice *udev, struct sysfs_class_device *class_dev)
* original kernel name sleeps with the fishes and we don't
* get an event from the kernel with the new name
*/
pos = strrchr(udev->devpath, '/');
pos = strrchr(udev->dev->devpath, '/');
if (pos != NULL) {
pos[1] = '\0';
strlcat(udev->devpath, udev->name, sizeof(udev->devpath));
strlcpy(udev->kernel_name, udev->name, sizeof(udev->kernel_name));
setenv("DEVPATH", udev->devpath, 1);
strlcat(udev->dev->devpath, udev->name, sizeof(udev->dev->devpath));
strlcpy(udev->dev->kernel_name, udev->name, sizeof(udev->dev->kernel_name));
setenv("DEVPATH", udev->dev->devpath, 1);
setenv("INTERFACE", udev->name, 1);
}
}
+1 -9
View File
@@ -28,15 +28,9 @@
#include <ctype.h>
#include <syslog.h>
#include "libsysfs/sysfs/libsysfs.h"
#include "udev_libc_wrapper.h"
#include "udev.h"
#include "udev_utils.h"
#include "udev_version.h"
#include "logging.h"
/* global variables */
char sysfs_path[PATH_SIZE];
char udev_root[PATH_SIZE];
char udev_config_filename[PATH_SIZE];
char udev_rules_filename[PATH_SIZE];
@@ -168,7 +162,7 @@ static int parse_config_file(void)
return retval;
}
void udev_init_config(void)
void udev_config_init(void)
{
const char *env;
@@ -177,7 +171,6 @@ void udev_init_config(void)
strcpy(udev_rules_filename, UDEV_RULES_FILE);
udev_log_priority = LOG_ERR;
udev_run = 1;
sysfs_get_mnt_path(sysfs_path, sizeof(sysfs_path));
/* disable RUN key execution */
env = getenv("UDEV_RUN");
@@ -202,7 +195,6 @@ void udev_init_config(void)
if (env)
udev_log_priority = log_priority(env);
dbg("sysfs_path='%s'", sysfs_path);
dbg("UDEV_CONFIG_FILE='%s'", udev_config_filename);
dbg("udev_root='%s'", udev_root);
dbg("udev_rules='%s'", udev_rules_filename);
+5 -9
View File
@@ -30,11 +30,7 @@
#include <errno.h>
#include <dirent.h>
#include "libsysfs/sysfs/libsysfs.h"
#include "udev_libc_wrapper.h"
#include "udev.h"
#include "udev_utils.h"
#include "logging.h"
static int devpath_to_db_path(const char *devpath, char *filename, size_t len)
@@ -83,21 +79,21 @@ int udev_db_add_device(struct udevice *udev)
/* don't write anything if udev created only the node with the
* kernel name without any interesting data to remember
*/
if (strcmp(udev->name, udev->kernel_name) == 0 &&
if (strcmp(udev->name, udev->dev->kernel_name) == 0 &&
list_empty(&udev->symlink_list) && list_empty(&udev->env_list) &&
!udev->partitions && !udev->ignore_remove) {
dbg("nothing interesting to store in udevdb, skip");
goto exit;
}
devpath_to_db_path(udev->devpath, filename, sizeof(filename));
devpath_to_db_path(udev->dev->devpath, filename, sizeof(filename));
create_path(filename);
f = fopen(filename, "w");
if (f == NULL) {
err("unable to create db file '%s': %s", filename, strerror(errno));
return -1;
}
dbg("storing data for device '%s' in '%s'", udev->devpath, filename);
dbg("storing data for device '%s' in '%s'", udev->dev->devpath, filename);
fprintf(f, "N:%s\n", udev->name);
list_for_each_entry(name_loop, &udev->symlink_list, node)
@@ -132,7 +128,7 @@ int udev_db_get_device(struct udevice *udev, const char *devpath)
return -1;
}
strlcpy(udev->devpath, devpath, sizeof(udev->devpath));
strlcpy(udev->dev->devpath, devpath, sizeof(udev->dev->devpath));
cur = 0;
while (cur < bufsize) {
count = buf_get_line(buf, bufsize, cur);
@@ -196,7 +192,7 @@ int udev_db_delete_device(struct udevice *udev)
{
char filename[PATH_SIZE];
devpath_to_db_path(udev->devpath, filename, sizeof(filename));
devpath_to_db_path(udev->dev->devpath, filename, sizeof(filename));
unlink(filename);
return 0;
+76 -60
View File
@@ -26,83 +26,99 @@
#include <fcntl.h>
#include <errno.h>
#include <ctype.h>
#include <dirent.h>
#include <syslog.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/utsname.h>
#include "udev_libc_wrapper.h"
#include "udev.h"
#include "logging.h"
#include "udev_utils.h"
#include "list.h"
#include "udev_rules.h"
int udev_init_device(struct udevice *udev, const char* devpath, const char *subsystem, const char *action)
struct udevice *udev_device_init(void)
{
char *pos;
struct udevice *udev;
udev = malloc(sizeof(struct udevice));
if (udev == NULL)
return NULL;
memset(udev, 0x00, sizeof(struct udevice));
INIT_LIST_HEAD(&udev->symlink_list);
INIT_LIST_HEAD(&udev->run_list);
INIT_LIST_HEAD(&udev->env_list);
if (subsystem)
strlcpy(udev->subsystem, subsystem, sizeof(udev->subsystem));
/* set sysfs device to local storage, can be overridden if needed */
udev->dev = &udev->dev_local;
if (action)
strlcpy(udev->action, action, sizeof(udev->action));
/* default node permissions */
udev->mode = 0660;
strcpy(udev->owner, "root");
strcpy(udev->group, "root");
if (devpath) {
strlcpy(udev->devpath, devpath, sizeof(udev->devpath));
remove_trailing_chars(udev->devpath, '/');
if (strncmp(udev->devpath, "/block/", 7) == 0)
udev->type = DEV_BLOCK;
else if (strncmp(udev->devpath, "/class/net/", 11) == 0)
udev->type = DEV_NET;
else if (strncmp(udev->devpath, "/class/", 7) == 0)
udev->type = DEV_CLASS;
else if (strncmp(udev->devpath, "/devices/", 9) == 0)
udev->type = DEV_DEVICE;
/* get kernel name */
pos = strrchr(udev->devpath, '/');
if (pos) {
strlcpy(udev->kernel_name, &pos[1], sizeof(udev->kernel_name));
dbg("kernel_name='%s'", udev->kernel_name);
/* Some block devices have '!' in their name, change that to '/' */
pos = udev->kernel_name;
while (pos[0] != '\0') {
if (pos[0] == '!')
pos[0] = '/';
pos++;
}
/* get kernel number */
pos = &udev->kernel_name[strlen(udev->kernel_name)];
while (isdigit(pos[-1]))
pos--;
strlcpy(udev->kernel_number, pos, sizeof(udev->kernel_number));
dbg("kernel_number='%s'", udev->kernel_number);
}
}
if (udev->type == DEV_BLOCK || udev->type == DEV_CLASS) {
udev->mode = 0660;
strcpy(udev->owner, "root");
strcpy(udev->group, "root");
}
return 0;
return udev;
}
void udev_cleanup_device(struct udevice *udev)
void udev_device_cleanup(struct udevice *udev)
{
name_list_cleanup(&udev->symlink_list);
name_list_cleanup(&udev->run_list);
name_list_cleanup(&udev->env_list);
free(udev);
}
dev_t udev_device_get_devt(struct udevice *udev)
{
const char *attr;
unsigned int major, minor;
/* read it from sysfs */
attr = sysfs_attr_get_value(udev->dev->devpath, "dev");
if (attr != NULL) {
if (sscanf(attr, "%u:%u", &major, &minor) == 2)
return makedev(major, minor);
}
return makedev(0, 0);
}
int udev_device_event(struct udev_rules *rules, struct udevice *udev)
{
int retval = 0;
/* device node or netif */
if ((major(udev->devt) != 0 || strcmp(udev->dev->subsystem, "net") == 0) &&
strcmp(udev->action, "add") == 0) {
dbg("device node or netif add '%s'", udev->dev->devpath);
udev_rules_get_name(rules, udev);
if (udev->ignore_device) {
info("device event will be ignored");
return 0;
}
/* create node, store in db */
if (udev->name[0] != '\0')
retval = udev_add_device(udev);
else
info("device node creation supressed");
return 0;
}
if (major(udev->devt) != 0 && strcmp(udev->action, "remove") == 0) {
struct name_entry *name_loop;
udev_rules_get_run(rules, udev);
if (udev->ignore_device) {
info("device event will be ignored");
return 0;
}
/* get data from db, remove db-entry, delete node */
retval = udev_remove_device(udev);
/* restore stored persistent data */
list_for_each_entry(name_loop, &udev->env_list, node)
putenv(name_loop->name);
return 0;
}
/* default devices */
udev_rules_get_run(rules, udev);
if (udev->ignore_device)
info("device event will be ignored");
return retval;
}
-161
View File
@@ -1,161 +0,0 @@
/*
* udev_event.c - udev event process
*
* Copyright (C) 2004, 2005 Kay Sievers <kay.sievers@vrfy.org>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation version 2 of the License.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include <stdlib.h>
#include <stdio.h>
#include <stddef.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <ctype.h>
#include <dirent.h>
#include <syslog.h>
#include <sys/stat.h>
#include "libsysfs/sysfs/libsysfs.h"
#include "udev_libc_wrapper.h"
#include "udev.h"
#include "logging.h"
#include "udev_rules.h"
#include "udev_utils.h"
#include "list.h"
dev_t get_devt(struct sysfs_class_device *class_dev)
{
struct sysfs_attribute *attr = NULL;
unsigned int major, minor;
char *maj, *min;
maj = getenv("MAJOR");
min = getenv("MINOR");
if (maj && min) {
major = atoi(maj);
minor = atoi(min);
} else {
attr = sysfs_get_classdev_attr(class_dev, "dev");
if (attr == NULL)
return 0;
dbg("dev='%s'", attr->value);
if (sscanf(attr->value, "%u:%u", &major, &minor) != 2)
return 0;
}
dbg("found major=%d, minor=%d", major, minor);
return makedev(major, minor);
}
int udev_process_event(struct udev_rules *rules, struct udevice *udev)
{
int retval;
char path[PATH_SIZE];
if (udev->type == DEV_BLOCK || udev->type == DEV_CLASS || udev->type == DEV_NET) {
/* handle device node */
if (strcmp(udev->action, "add") == 0) {
struct sysfs_class_device *class_dev;
dbg("node add");
snprintf(path, sizeof(path), "%s%s", sysfs_path, udev->devpath);
path[sizeof(path)-1] = '\0';
class_dev = sysfs_open_class_device_path(path);
if (class_dev == NULL) {
dbg("open class device failed");
return 0;
}
dbg("opened class_dev->name='%s'", class_dev->name);
/* get major/minor */
if (udev->type == DEV_BLOCK || udev->type == DEV_CLASS)
udev->devt = get_devt(class_dev);
if (udev->type == DEV_NET || udev->devt) {
/* name device */
udev_rules_get_name(rules, udev, class_dev);
if (udev->ignore_device) {
info("device event will be ignored");
sysfs_close_class_device(class_dev);
return 0;
}
if (udev->name[0] != '\0') {
/* create node, store in db */
retval = udev_add_device(udev, class_dev);
} else {
info("device node creation supressed");
}
} else {
dbg("no dev-file found");
udev_rules_get_run(rules, udev, class_dev, NULL);
if (udev->ignore_device) {
info("device event will be ignored");
sysfs_close_class_device(class_dev);
return 0;
}
}
sysfs_close_class_device(class_dev);
} else if (strcmp(udev->action, "remove") == 0) {
struct name_entry *name_loop;
/* get data from db, remove db-entry, delete node */
dbg("node remove");
retval = udev_remove_device(udev);
/* restore stored persistent data */
list_for_each_entry(name_loop, &udev->env_list, node)
putenv(name_loop->name);
udev_rules_get_run(rules, udev, NULL, NULL);
if (udev->ignore_device) {
dbg("device event will be ignored");
return 0;
}
}
} else if (udev->type == DEV_DEVICE && strcmp(udev->action, "add") == 0) {
struct sysfs_device *devices_dev;
dbg("devices add");
snprintf(path, sizeof(path), "%s%s", sysfs_path, udev->devpath);
path[sizeof(path)-1] = '\0';
devices_dev = sysfs_open_device_path(path);
if (!devices_dev) {
dbg("devices device unavailable (probably remove has beaten us)");
return 0;
}
dbg("devices device opened '%s'", path);
udev_rules_get_run(rules, udev, NULL, devices_dev);
sysfs_close_device(devices_dev);
if (udev->ignore_device) {
info("device event will be ignored");
return 0;
}
} else {
dbg("default handling");
udev_rules_get_run(rules, udev, NULL, NULL);
if (udev->ignore_device) {
info("device event will be ignored");
return 0;
}
}
return 0;
}
-3
View File
@@ -27,10 +27,7 @@
#include <fcntl.h>
#include <sys/types.h>
#include "udev_libc_wrapper.h"
#include "udev.h"
#include "udev_utils.h"
#include "logging.h"
#ifdef __KLIBC__
#define __OWN_USERDB_PARSER__
+4 -8
View File
@@ -28,11 +28,7 @@
#include <errno.h>
#include <sys/stat.h>
#include "udev_libc_wrapper.h"
#include "udev.h"
#include "udev_utils.h"
#include "udev_version.h"
#include "logging.h"
static int delete_node(struct udevice *udev)
{
@@ -112,10 +108,10 @@ static int delete_node(struct udevice *udev)
*/
int udev_remove_device(struct udevice *udev)
{
if (udev->type != DEV_BLOCK && udev->type != DEV_CLASS)
if (major(udev->devt) == 0)
return 0;
if (udev_db_get_device(udev, udev->devpath) == 0) {
if (udev_db_get_device(udev, udev->dev->devpath) == 0) {
if (udev->ignore_remove) {
dbg("remove event for '%s' requested to be ignored by rule", udev->name);
return 0;
@@ -123,8 +119,8 @@ int udev_remove_device(struct udevice *udev)
dbg("remove name='%s'", udev->name);
udev_db_delete_device(udev);
} else {
dbg("'%s' not found in database, using kernel name '%s'", udev->devpath, udev->kernel_name);
strlcpy(udev->name, udev->kernel_name, sizeof(udev->name));
dbg("'%s' not found in database, using kernel name '%s'", udev->dev->devpath, udev->dev->kernel_name);
strlcpy(udev->name, udev->dev->kernel_name, sizeof(udev->name));
}
return delete_node(udev);
+138 -211
View File
@@ -31,13 +31,7 @@
#include <sys/wait.h>
#include <sys/stat.h>
#include "libsysfs/sysfs/libsysfs.h"
#include "list.h"
#include "udev_libc_wrapper.h"
#include "udev.h"
#include "udev_utils.h"
#include "udev_version.h"
#include "logging.h"
#include "udev_rules.h"
@@ -221,26 +215,29 @@ static int import_program_into_env(struct udevice *udev, const char *program)
char result[1024];
size_t reslen;
if (run_program(program, udev->subsystem, result, sizeof(result), &reslen, (udev_log_priority >= LOG_INFO)) != 0)
if (run_program(program, udev->dev->subsystem, result, sizeof(result), &reslen, (udev_log_priority >= LOG_INFO)) != 0)
return -1;
return import_keys_into_env(udev, result, reslen);
}
static int import_parent_into_env(struct udevice *udev, struct sysfs_class_device *class_dev, const char *filter)
static int import_parent_into_env(struct udevice *udev, const char *filter)
{
struct sysfs_class_device *parent = sysfs_get_classdev_parent(class_dev);
struct sysfs_device *dev_parent;
int rc = -1;
if (parent != NULL) {
struct udevice udev_parent;
dev_parent = sysfs_device_get_parent(udev->dev);
if (dev_parent != NULL) {
struct udevice *udev_parent;
struct name_entry *name_loop;
dbg("found parent '%s', get the node name", parent->path);
udev_init_device(&udev_parent, NULL, NULL, NULL);
dbg("found parent '%s', get the node name", dev_parent->devpath);
udev_parent = udev_device_init();
if (udev_parent == NULL)
return -1;
/* import the udev_db of the parent */
if (udev_db_get_device(&udev_parent, &parent->path[strlen(sysfs_path)]) == 0) {
dbg("import stored parent env '%s'", udev_parent.name);
list_for_each_entry(name_loop, &udev_parent.env_list, node) {
if (udev_db_get_device(udev_parent, dev_parent->devpath) == 0) {
dbg("import stored parent env '%s'", udev_parent->name);
list_for_each_entry(name_loop, &udev_parent->env_list, node) {
char name[NAME_SIZE];
char *pos;
@@ -260,7 +257,7 @@ static int import_parent_into_env(struct udevice *udev, struct sysfs_class_devic
rc = 0;
} else
dbg("parent not found in database");
udev_cleanup_device(&udev_parent);
udev_device_cleanup(udev_parent);
}
return rc;
@@ -291,22 +288,24 @@ static int find_free_number(const char *base, const char *devpath)
{
char db_devpath[PATH_SIZE];
char filename[PATH_SIZE];
struct udevice udev_db;
struct udevice *udev_db;
int num = 0;
/* check if the device already owns a matching name */
udev_init_device(&udev_db, NULL, NULL, NULL);
if (udev_db_get_device(&udev_db, devpath) == 0) {
udev_db = udev_device_init();
if (udev_db == NULL)
return -1;
if (udev_db_get_device(udev_db, devpath) == 0) {
struct name_entry *name_loop;
int devnum;
devnum = match_name_and_get_number(base, udev_db.name);
devnum = match_name_and_get_number(base, udev_db->name);
if (devnum >= 0) {
num = devnum;
dbg("device '%s', already has the node '%s' with num %u, use it", devpath, base, num);
goto out;
}
list_for_each_entry(name_loop, &udev_db.symlink_list, node) {
list_for_each_entry(name_loop, &udev_db->symlink_list, node) {
devnum = match_name_and_get_number(base, name_loop->name);
if (devnum >= 0) {
num = devnum;
@@ -336,45 +335,10 @@ static int find_free_number(const char *base, const char *devpath)
}
out:
udev_cleanup_device(&udev_db);
udev_device_cleanup(udev_db);
return num;
}
static int find_sysfs_attribute(struct sysfs_class_device *class_dev, struct sysfs_device *sysfs_device,
const char *name, char *value, size_t len)
{
struct sysfs_class_device *class_dev_parent;
struct sysfs_attribute *tmpattr;
dbg("look for device attribute '%s'", name);
if (class_dev) {
dbg("look for class attribute '%s/%s'", class_dev->path, name);
tmpattr = sysfs_get_classdev_attr(class_dev, name);
if (tmpattr)
goto attr_found;
class_dev_parent = sysfs_get_classdev_parent(class_dev);
if (class_dev_parent) {
tmpattr = sysfs_get_classdev_attr(class_dev_parent, name);
if (tmpattr)
goto attr_found;
}
}
if (sysfs_device) {
dbg("look for devices attribute '%s/%s'", sysfs_device->path, name);
tmpattr = sysfs_get_device_attr(sysfs_device, name);
if (tmpattr)
goto attr_found;
}
return -1;
attr_found:
strlcpy(value, tmpattr->value, len);
remove_trailing_chars(value, '\n');
dbg("found attribute '%s'", tmpattr->path);
return 0;
}
#define WAIT_LOOP_PER_SECOND 50
static int wait_for_sysfs(struct udevice *udev, const char *file, int timeout)
{
@@ -382,7 +346,7 @@ static int wait_for_sysfs(struct udevice *udev, const char *file, int timeout)
struct stat stats;
int loop = timeout * WAIT_LOOP_PER_SECOND;
snprintf(filename, sizeof(filename), "%s%s/%s", sysfs_path, udev->devpath, file);
snprintf(filename, sizeof(filename), "%s%s/%s", sysfs_path, udev->dev->devpath, file);
filename[sizeof(filename)-1] = '\0';
dbg("wait %i sec for '%s'", timeout, filename);
@@ -398,8 +362,7 @@ static int wait_for_sysfs(struct udevice *udev, const char *file, int timeout)
return -1;
}
static void apply_format(struct udevice *udev, char *string, size_t maxsize,
struct sysfs_class_device *class_dev, struct sysfs_device *sysfs_device)
static void apply_format(struct udevice *udev, char *string, size_t maxsize)
{
char temp[PATH_SIZE];
char temp2[PATH_SIZE];
@@ -408,11 +371,9 @@ static void apply_format(struct udevice *udev, char *string, size_t maxsize,
int i;
int count;
unsigned int next_free_number;
struct sysfs_class_device *class_dev_parent;
enum subst_type {
SUBST_UNKNOWN,
SUBST_DEVPATH,
SUBST_ID,
SUBST_KERNEL_NUMBER,
SUBST_KERNEL_NAME,
SUBST_MAJOR,
@@ -432,7 +393,6 @@ static void apply_format(struct udevice *udev, char *string, size_t maxsize,
enum subst_type type;
} map[] = {
{ .name = "devpath", .fmt = 'p', .type = SUBST_DEVPATH },
{ .name = "id", .fmt = 'b', .type = SUBST_ID },
{ .name = "number", .fmt = 'n', .type = SUBST_KERNEL_NUMBER },
{ .name = "kernel", .fmt = 'k', .type = SUBST_KERNEL_NAME },
{ .name = "major", .fmt = 'M', .type = SUBST_MAJOR },
@@ -502,25 +462,20 @@ static void apply_format(struct udevice *udev, char *string, size_t maxsize,
found:
attr = get_format_attribute(&tail);
strlcpy(temp, tail, sizeof(temp));
dbg("format=%i, string='%s', tail='%s', class_dev=%p, sysfs_dev=%p",
type ,string, tail, class_dev, sysfs_device);
dbg("format=%i, string='%s', tail='%s'", type ,string, tail);
switch (type) {
case SUBST_DEVPATH:
strlcat(string, udev->devpath, maxsize);
dbg("substitute devpath '%s'", udev->devpath);
break;
case SUBST_ID:
strlcat(string, udev->bus_id, maxsize);
dbg("substitute bus_id '%s'", udev->bus_id);
strlcat(string, udev->dev->devpath, maxsize);
dbg("substitute devpath '%s'", udev->dev->devpath);
break;
case SUBST_KERNEL_NAME:
strlcat(string, udev->kernel_name, maxsize);
dbg("substitute kernel name '%s'", udev->kernel_name);
strlcat(string, udev->dev->kernel_name, maxsize);
dbg("substitute kernel name '%s'", udev->dev->kernel_name);
break;
case SUBST_KERNEL_NUMBER:
strlcat(string, udev->kernel_number, maxsize);
dbg("substitute kernel number '%s'", udev->kernel_number);
strlcat(string, udev->dev->kernel_number, maxsize);
dbg("substitute kernel number '%s'", udev->dev->kernel_number);
break;
case SUBST_MAJOR:
sprintf(temp2, "%d", major(udev->devt));
@@ -570,54 +525,59 @@ found:
if (attr == NULL) {
dbg("missing attribute");
break;
}
if (find_sysfs_attribute(class_dev, sysfs_device, attr, temp2, sizeof(temp2)) != 0) {
struct sysfs_device *parent_device;
} else {
struct sysfs_device *dev_parent;
const char *value;
dbg("sysfs attribute '%s' not found, walk up the physical devices", attr);
parent_device = sysfs_get_device_parent(sysfs_device);
while (parent_device) {
dbg("looking at '%s'", parent_device->path);
if (find_sysfs_attribute(NULL, parent_device, attr, temp2, sizeof(temp2)) == 0)
dev_parent = udev->dev;
do {
dbg("looking at '%s'", dev_parent->devpath);
value = sysfs_attr_get_value(dev_parent->devpath, attr);
if (value != NULL) {
strlcpy(temp2, value, sizeof(temp2));
break;
parent_device = sysfs_get_device_parent(parent_device);
}
if (!parent_device)
break;
}
dev_parent = sysfs_device_get_parent(dev_parent);
} while (dev_parent != NULL);
/* strip trailing whitespace of sysfs value */
i = strlen(temp2);
while (i > 0 && isspace(temp2[i-1]))
temp2[--i] = '\0';
count = replace_untrusted_chars(temp2);
if (count)
info("%i untrusted character(s) replaced" , count);
strlcat(string, temp2, maxsize);
dbg("substitute sysfs value '%s'", temp2);
}
/* strip trailing whitespace of sysfs value */
i = strlen(temp2);
while (i > 0 && isspace(temp2[i-1]))
temp2[--i] = '\0';
count = replace_untrusted_chars(temp2);
if (count)
info("%i untrusted character(s) replaced" , count);
strlcat(string, temp2, maxsize);
dbg("substitute sysfs value '%s'", temp2);
break;
case SUBST_ENUM:
next_free_number = find_free_number(string, udev->devpath);
next_free_number = find_free_number(string, udev->dev->devpath);
if (next_free_number > 0) {
sprintf(temp2, "%d", next_free_number);
strlcat(string, temp2, maxsize);
}
break;
case SUBST_PARENT:
if (!class_dev)
break;
class_dev_parent = sysfs_get_classdev_parent(class_dev);
if (class_dev_parent != NULL) {
struct udevice udev_parent;
{
struct sysfs_device *dev_parent;
dbg("found parent '%s', get the node name", class_dev_parent->path);
udev_init_device(&udev_parent, NULL, NULL, NULL);
/* lookup the name in the udev_db with the DEVPATH of the parent */
if (udev_db_get_device(&udev_parent, &class_dev_parent->path[strlen(sysfs_path)]) == 0) {
strlcat(string, udev_parent.name, maxsize);
dbg("substitute parent node name'%s'", udev_parent.name);
} else
dbg("parent not found in database");
udev_cleanup_device(&udev_parent);
dev_parent = sysfs_device_get_parent(udev->dev);
if (dev_parent != NULL) {
struct udevice *udev_parent;
dbg("found parent '%s', get the node name", dev_parent->devpath);
udev_parent = udev_device_init();
if (udev_parent != NULL) {
/* lookup the name in the udev_db with the DEVPATH of the parent */
if (udev_db_get_device(udev_parent, dev_parent->devpath) == 0) {
strlcat(string, udev_parent->name, maxsize);
dbg("substitute parent node name'%s'", udev_parent->name);
} else
dbg("parent not found in database");
udev_device_cleanup(udev_parent);
}
}
}
break;
case SUBST_TEMP_NODE:
@@ -636,10 +596,15 @@ found:
dbg("substitute udev_root '%s'", udev_root);
break;
case SUBST_MODALIAS:
if (find_sysfs_attribute(NULL, sysfs_device, "modalias", temp2, sizeof(temp2)) != 0)
break;
strlcat(string, temp2, maxsize);
dbg("substitute MODALIAS '%s'", temp2);
{
const char *value;
value = sysfs_attr_get_value(udev->dev->devpath, "modalias");
if (value != NULL) {
strlcat(string, value, maxsize);
dbg("substitute MODALIAS '%s'", temp2);
}
}
break;
case SUBST_ENV:
if (attr == NULL) {
@@ -714,28 +679,28 @@ static int match_key(const char *key_name, struct udev_rule *rule, struct key *k
}
/* match a single rule against a given device and possibly its parent devices */
static int match_rule(struct udevice *udev, struct udev_rule *rule,
struct sysfs_class_device *class_dev, struct sysfs_device *sysfs_device)
static int match_rule(struct udevice *udev, struct udev_rule *rule)
{
struct sysfs_device *parent_device = sysfs_device;
struct sysfs_device *dev_parent;
int i;
if (match_key("ACTION", rule, &rule->action, udev->action))
goto exit;
if (match_key("KERNEL", rule, &rule->kernel_name, udev->kernel_name))
if (match_key("KERNEL", rule, &rule->kernel_name, udev->dev->kernel_name))
goto exit;
if (match_key("SUBSYSTEM", rule, &rule->subsystem, udev->subsystem))
if (match_key("SUBSYSTEM", rule, &rule->subsystem, udev->dev->subsystem))
goto exit;
if (match_key("DEVPATH", rule, &rule->devpath, udev->devpath))
if (match_key("DEVPATH", rule, &rule->devpath, udev->dev->devpath))
goto exit;
if (rule->modalias.operation != KEY_OP_UNSET) {
char value[NAME_SIZE];
const char *value;
if (find_sysfs_attribute(NULL, sysfs_device, "modalias", value, sizeof(value)) != 0) {
value = sysfs_attr_get_value(udev->dev->devpath, "modalias");
if (value == NULL) {
dbg("MODALIAS value not found");
goto exit;
}
@@ -777,34 +742,23 @@ static int match_rule(struct udevice *udev, struct udev_rule *rule,
}
/* walk up the chain of physical devices and find a match */
dev_parent = udev->dev;
while (1) {
/* check for matching driver */
if (rule->driver.operation != KEY_OP_UNSET) {
if (parent_device == NULL) {
dbg("device has no sysfs_device");
goto exit;
}
if (match_key("DRIVER", rule, &rule->driver, parent_device->driver_name))
if (match_key("DRIVER", rule, &rule->driver, dev_parent->driver))
goto try_parent;
}
/* check for matching bus value */
if (rule->bus.operation != KEY_OP_UNSET) {
if (parent_device == NULL) {
dbg("device has no sysfs_device");
goto exit;
}
if (match_key("BUS", rule, &rule->bus, parent_device->bus))
if (match_key("BUS", rule, &rule->bus, dev_parent->subsystem))
goto try_parent;
}
/* check for matching bus id */
if (rule->id.operation != KEY_OP_UNSET) {
if (parent_device == NULL) {
dbg("device has no sysfs_device");
goto exit;
}
if (match_key("ID", rule, &rule->id, parent_device->bus_id))
if (match_key("ID", rule, &rule->id, dev_parent->kernel_name))
goto try_parent;
}
@@ -815,36 +769,39 @@ static int match_rule(struct udevice *udev, struct udev_rule *rule,
struct key_pair *pair = &rule->sysfs.keys[i];
const char *key_name = key_pair_name(rule, pair);
const char *key_value = key_val(rule, &pair->key);
char value[VALUE_SIZE];
const char *value;
char val[VALUE_SIZE];
size_t len;
if (find_sysfs_attribute(class_dev, parent_device, key_name, value, sizeof(value)) != 0)
value = sysfs_attr_get_value(dev_parent->devpath, key_name);
if (value == NULL)
goto try_parent;
strlcpy(val, value, sizeof(val));
/* strip trailing whitespace of value, if not asked to match for it */
len = strlen(key_value);
if (len && !isspace(key_value[len-1])) {
len = strlen(value);
while (len > 0 && isspace(value[len-1]))
value[--len] = '\0';
dbg("removed %zi trailing whitespace chars from '%s'", strlen(value)-len, value);
if (len > 0 && !isspace(key_value[len-1])) {
len = strlen(val);
while (len > 0 && isspace(val[len-1]))
val[--len] = '\0';
dbg("removed %zi trailing whitespace chars from '%s'", strlen(val)-len, val);
}
if (match_key("SYSFS", rule, &pair->key, value))
if (match_key("SYSFS", rule, &pair->key, val))
goto try_parent;
}
dbg("all %i SYSFS keys matched", rule->sysfs.count);
}
/* found matching physical device */
/* found matching device */
break;
try_parent:
dbg("try parent sysfs device");
parent_device = sysfs_get_device_parent(parent_device);
if (parent_device == NULL)
dev_parent = sysfs_device_get_parent(dev_parent);
if (dev_parent == NULL)
goto exit;
dbg("look at sysfs_device->path='%s'", parent_device->path);
dbg("look at sysfs_device->bus_id='%s'", parent_device->bus_id);
dbg("looking at dev_parent->devpath='%s'", dev_parent->devpath);
dbg("looking at dev_parent->bus_kernel_name='%s'", dev_parent->kernel_name);
}
/* execute external program */
@@ -853,8 +810,8 @@ try_parent:
char result[PATH_SIZE];
strlcpy(program, key_val(rule, &rule->program), sizeof(program));
apply_format(udev, program, sizeof(program), class_dev, sysfs_device);
if (run_program(program, udev->subsystem, result, sizeof(result), NULL, (udev_log_priority >= LOG_INFO)) != 0) {
apply_format(udev, program, sizeof(program));
if (run_program(program, udev->dev->subsystem, result, sizeof(result), NULL, (udev_log_priority >= LOG_INFO)) != 0) {
dbg("PROGRAM is false");
udev->program_result[0] = '\0';
if (rule->program.operation != KEY_OP_NOMATCH)
@@ -886,18 +843,18 @@ try_parent:
int rc = -1;
strlcpy(import, key_val(rule, &rule->import), sizeof(import));
apply_format(udev, import, sizeof(import), class_dev, sysfs_device);
apply_format(udev, import, sizeof(import));
dbg("check for IMPORT import='%s'", import);
if (rule->import_type == IMPORT_PROGRAM) {
rc = import_program_into_env(udev, import);
} else if (rule->import_type == IMPORT_FILE) {
dbg("import file import='%s'", import);
rc = import_file_into_env(udev, import);
} else if (rule->import_type == IMPORT_PARENT && class_dev) {
} else if (rule->import_type == IMPORT_PARENT) {
dbg("import parent import='%s'", import);
rc = import_parent_into_env(udev, class_dev, import);
rc = import_parent_into_env(udev, import);
}
if (rc) {
if (rc != 0) {
dbg("IMPORT failed");
if (rule->import.operation != KEY_OP_NOMATCH)
goto exit;
@@ -926,35 +883,13 @@ exit:
return -1;
}
int udev_rules_get_name(struct udev_rules *rules, struct udevice *udev, struct sysfs_class_device *class_dev)
int udev_rules_get_name(struct udev_rules *rules, struct udevice *udev)
{
struct sysfs_class_device *class_dev_parent;
struct sysfs_device *sysfs_device = NULL;
struct udev_rule *rule;
int name_set = 0;
dbg("class_dev->name='%s'", class_dev->name);
/* Figure out where the "device"-symlink is at. For char devices this will
* always be in the class_dev->path. On block devices, only the main block
* device will have the device symlink in it's path. All partition devices
* need to look at the symlink in its parent directory.
*/
class_dev_parent = sysfs_get_classdev_parent(class_dev);
if (class_dev_parent != NULL) {
dbg("given class device has a parent, use this instead");
sysfs_device = sysfs_get_classdev_device(class_dev_parent);
} else {
sysfs_device = sysfs_get_classdev_device(class_dev);
}
if (sysfs_device) {
dbg("found devices device: path='%s', bus_id='%s', bus='%s'",
sysfs_device->path, sysfs_device->bus_id, sysfs_device->bus);
strlcpy(udev->bus_id, sysfs_device->bus_id, sizeof(udev->bus_id));
}
dbg("udev->kernel_name='%s'", udev->kernel_name);
dbg("udev->dev->devpath='%s'", udev->dev->devpath);
dbg("udev->dev->kernel_name='%s'", udev->dev->kernel_name);
/* look for a matching rule to apply */
udev_rules_iter_init(rules);
@@ -969,10 +904,10 @@ int udev_rules_get_name(struct udev_rules *rules, struct udevice *udev, struct s
}
dbg("process rule");
if (match_rule(udev, rule, class_dev, sysfs_device) == 0) {
if (match_rule(udev, rule) == 0) {
/* apply options */
if (rule->ignore_device) {
info("rule applied, '%s' is ignored", udev->kernel_name);
info("rule applied, '%s' is ignored", udev->dev->kernel_name);
udev->ignore_device = 1;
return 0;
}
@@ -981,7 +916,8 @@ int udev_rules_get_name(struct udev_rules *rules, struct udevice *udev, struct s
dbg("remove event should be ignored");
}
/* apply all_partitions option only at a main block device */
if (rule->partitions && udev->type == DEV_BLOCK && udev->kernel_number[0] == '\0') {
if (rule->partitions &&
strcmp(udev->dev->subsystem, "block") == 0 && udev->dev->kernel_number[0] == '\0') {
udev->partitions = rule->partitions;
dbg("creation of partition nodes requested");
}
@@ -991,21 +927,21 @@ int udev_rules_get_name(struct udev_rules *rules, struct udevice *udev, struct s
if (rule->mode_operation == KEY_OP_ASSIGN_FINAL)
udev->mode_final = 1;
udev->mode = rule->mode;
dbg("applied mode=%#o to '%s'", rule->mode, udev->kernel_name);
dbg("applied mode=%#o to '%s'", rule->mode, udev->dev->kernel_name);
}
if (!udev->owner_final && rule->owner.operation != KEY_OP_UNSET) {
if (rule->owner.operation == KEY_OP_ASSIGN_FINAL)
udev->owner_final = 1;
strlcpy(udev->owner, key_val(rule, &rule->owner), sizeof(udev->owner));
apply_format(udev, udev->owner, sizeof(udev->owner), class_dev, sysfs_device);
dbg("applied owner='%s' to '%s'", udev->owner, udev->kernel_name);
apply_format(udev, udev->owner, sizeof(udev->owner));
dbg("applied owner='%s' to '%s'", udev->owner, udev->dev->kernel_name);
}
if (!udev->group_final && rule->group.operation != KEY_OP_UNSET) {
if (rule->group.operation == KEY_OP_ASSIGN_FINAL)
udev->group_final = 1;
strlcpy(udev->group, key_val(rule, &rule->group), sizeof(udev->group));
apply_format(udev, udev->group, sizeof(udev->group), class_dev, sysfs_device);
dbg("applied group='%s' to '%s'", udev->group, udev->kernel_name);
apply_format(udev, udev->group, sizeof(udev->group));
dbg("applied group='%s' to '%s'", udev->group, udev->dev->kernel_name);
}
/* collect symlinks */
@@ -1021,7 +957,7 @@ int udev_rules_get_name(struct udev_rules *rules, struct udevice *udev, struct s
name_list_cleanup(&udev->symlink_list);
}
strlcpy(temp, key_val(rule, &rule->symlink), sizeof(temp));
apply_format(udev, temp, sizeof(temp), class_dev, sysfs_device);
apply_format(udev, temp, sizeof(temp));
count = replace_untrusted_chars(temp);
if (count)
info("%i untrusted character(s) replaced" , count);
@@ -1052,13 +988,13 @@ int udev_rules_get_name(struct udev_rules *rules, struct udevice *udev, struct s
int count;
name_set = 1;
strlcpy(udev->name, key_val(rule, &rule->name), sizeof(udev->name));
apply_format(udev, udev->name, sizeof(udev->name), class_dev, sysfs_device);
apply_format(udev, udev->name, sizeof(udev->name));
count = replace_untrusted_chars(udev->name);
if (count)
info("%i untrusted character(s) replaced", count);
info("rule applied, '%s' becomes '%s'", udev->kernel_name, udev->name);
if (udev->type != DEV_NET)
info("rule applied, '%s' becomes '%s'", udev->dev->kernel_name, udev->name);
if (strcmp(udev->dev->subsystem, "net") != 0)
dbg("name, '%s' is going to have owner='%s', group='%s', mode=%#o partitions=%i",
udev->name, udev->owner, udev->group, udev->mode, udev->partitions);
}
@@ -1073,7 +1009,7 @@ int udev_rules_get_name(struct udev_rules *rules, struct udevice *udev, struct s
name_list_cleanup(&udev->run_list);
}
strlcpy(program, key_val(rule, &rule->run), sizeof(program));
apply_format(udev, program, sizeof(program), class_dev, sysfs_device);
apply_format(udev, program, sizeof(program));
dbg("add run '%s'", program);
name_list_add(&udev->run_list, program, 0);
}
@@ -1091,7 +1027,7 @@ int udev_rules_get_name(struct udev_rules *rules, struct udevice *udev, struct s
}
if (!name_set) {
strlcpy(udev->name, udev->kernel_name, sizeof(udev->name));
strlcpy(udev->name, udev->dev->kernel_name, sizeof(udev->name));
info("no node name set, will use kernel name '%s'", udev->name);
}
@@ -1104,20 +1040,11 @@ int udev_rules_get_name(struct udev_rules *rules, struct udevice *udev, struct s
return 0;
}
int udev_rules_get_run(struct udev_rules *rules, struct udevice *udev,
struct sysfs_class_device *class_dev, struct sysfs_device *sysfs_dev)
int udev_rules_get_run(struct udev_rules *rules, struct udevice *udev)
{
struct udev_rule *rule;
if (class_dev && !sysfs_dev)
sysfs_dev = sysfs_get_classdev_device(class_dev);
if (sysfs_dev) {
dbg("found devices device: path='%s', bus_id='%s', bus='%s'",
sysfs_dev->path, sysfs_dev->bus_id, sysfs_dev->bus);
strlcpy(udev->bus_id, sysfs_dev->bus_id, sizeof(udev->bus_id));
}
dbg("udev->kernel_name='%s'", udev->kernel_name);
dbg("udev->kernel_name='%s'", udev->dev->kernel_name);
/* look for a matching rule to apply */
udev_rules_iter_init(rules);
@@ -1133,9 +1060,9 @@ int udev_rules_get_run(struct udev_rules *rules, struct udevice *udev,
continue;
}
if (match_rule(udev, rule, class_dev, sysfs_dev) == 0) {
if (match_rule(udev, rule) == 0) {
if (rule->ignore_device) {
info("rule applied, '%s' is ignored", udev->kernel_name);
info("rule applied, '%s' is ignored", udev->dev->kernel_name);
udev->ignore_device = 1;
return 0;
}
@@ -1148,7 +1075,7 @@ int udev_rules_get_run(struct udev_rules *rules, struct udevice *udev,
name_list_cleanup(&udev->run_list);
}
strlcpy(program, key_val(rule, &rule->run), sizeof(program));
apply_format(udev, program, sizeof(program), class_dev, sysfs_dev);
apply_format(udev, program, sizeof(program));
dbg("add run '%s'", program);
name_list_add(&udev->run_list, program, 0);
if (rule->run.operation == KEY_OP_ASSIGN_FINAL)
+4 -8
View File
@@ -22,7 +22,6 @@
#ifndef UDEV_RULES_H
#define UDEV_RULES_H
#include "libsysfs/sysfs/libsysfs.h"
#include "udev.h"
#include "list.h"
@@ -104,18 +103,15 @@ struct udev_rules {
};
extern int udev_rules_init(struct udev_rules *rules, int resolve_names);
extern void udev_rules_close(struct udev_rules *rules);
extern void udev_rules_cleanup(struct udev_rules *rules);
extern void udev_apply_format(struct udevice *udev, char *string, size_t maxsize,
struct sysfs_class_device *class_dev, struct sysfs_device *sysfs_device);
extern void udev_apply_format(struct udevice *udev, char *string, size_t maxsize);
extern void udev_rules_iter_init(struct udev_rules *rules);
extern struct udev_rule *udev_rules_iter_next(struct udev_rules *rules);
extern struct udev_rule *udev_rules_iter_label(struct udev_rules *rules, const char *label);
extern int udev_rules_get_name(struct udev_rules *rules, struct udevice *udev,
struct sysfs_class_device *class_dev);
extern int udev_rules_get_run(struct udev_rules *rules, struct udevice *udev,
struct sysfs_class_device *class_dev, struct sysfs_device *sysfs_dev);
extern int udev_rules_get_name(struct udev_rules *rules, struct udevice *udev);
extern int udev_rules_get_run(struct udev_rules *rules, struct udevice *udev);
#endif
+1 -4
View File
@@ -28,10 +28,7 @@
#include <sys/stat.h>
#include <errno.h>
#include "udev_libc_wrapper.h"
#include "udev.h"
#include "udev_utils.h"
#include "logging.h"
#include "udev_rules.h"
@@ -626,7 +623,7 @@ int udev_rules_init(struct udev_rules *rules, int resolve_names)
return retval;
}
void udev_rules_close(struct udev_rules *rules)
void udev_rules_cleanup(struct udev_rules *rules)
{
if (rules->buf) {
free(rules->buf);
-1
View File
@@ -32,7 +32,6 @@
#include "udev.h"
#include "udev_selinux.h"
#include "logging.h"
static security_context_t prev_scontext = NULL;
+345
View File
@@ -0,0 +1,345 @@
/*
* udev_sysfs.c - sysfs access
*
* Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation version 2 of the License.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include <stdlib.h>
#include <stdio.h>
#include <stddef.h>
#include <unistd.h>
#include <fcntl.h>
#include <ctype.h>
#include <errno.h>
#include "udev.h"
char sysfs_path[PATH_SIZE];
/* device cache */
static LIST_HEAD(dev_list);
/* attribute value cache */
static LIST_HEAD(attr_list);
struct sysfs_attr {
struct list_head node;
char path[PATH_SIZE];
char value[NAME_SIZE];
};
int sysfs_init(void)
{
const char *env;
env = getenv("SYSFS_PATH");
if (env) {
strlcpy(sysfs_path, env, sizeof(sysfs_path));
remove_trailing_chars(sysfs_path, '/');
} else
strlcpy(sysfs_path, "/sys", sizeof(sysfs_path));
dbg("sysfs_path='%s'", sysfs_path);
INIT_LIST_HEAD(&dev_list);
INIT_LIST_HEAD(&attr_list);
return 0;
}
void sysfs_cleanup(void)
{
struct sysfs_attr *attr_loop;
struct sysfs_attr *attr_temp;
struct sysfs_device *dev_loop;
struct sysfs_device *dev_temp;
list_for_each_entry_safe(attr_loop, attr_temp, &attr_list, node) {
list_del(&attr_loop->node);
free(attr_loop);
}
list_for_each_entry_safe(dev_loop, dev_temp, &dev_list, node) {
list_del(&dev_loop->node);
free(dev_loop);
}
}
void sysfs_device_set_values(struct sysfs_device *dev, const char *devpath, const char *subsystem)
{
char *pos;
strlcpy(dev->devpath, devpath, sizeof(dev->devpath));
if (subsystem != NULL)
strlcpy(dev->subsystem, subsystem, sizeof(dev->subsystem));
/* set kernel name */
pos = strrchr(dev->devpath, '/');
if (pos == NULL)
return;
strlcpy(dev->kernel_name, &pos[1], sizeof(dev->kernel_name));
dbg("kernel_name='%s'", dev->kernel_name);
/* some devices have '!' in their name, change that to '/' */
pos = dev->kernel_name;
while (pos[0] != '\0') {
if (pos[0] == '!')
pos[0] = '/';
pos++;
}
/* get kernel number */
pos = &dev->kernel_name[strlen(dev->kernel_name)];
while (isdigit(pos[-1]))
pos--;
strlcpy(dev->kernel_number, pos, sizeof(dev->kernel_number));
dbg("kernel_number='%s'", dev->kernel_number);
}
struct sysfs_device *sysfs_device_get(const char *devpath)
{
char path[PATH_SIZE];
char devpath_real[PATH_SIZE];
struct sysfs_device *dev;
struct sysfs_device *dev_loop;
struct stat statbuf;
char link_path[PATH_SIZE];
char link_target[PATH_SIZE];
int len;
char *pos;
dbg("open '%s'", devpath);
strlcpy(devpath_real, devpath, sizeof(devpath_real));
remove_trailing_chars(devpath_real, '/');
strlcpy(path, sysfs_path, sizeof(path));
strlcat(path, devpath_real, sizeof(path));
if (lstat(path, &statbuf) != 0) {
dbg("stat '%s' failed: %s", devpath, strerror(errno));
return NULL;
}
/* if we got a link, resolve it to the real device */
if (S_ISLNK(statbuf.st_mode)) {
int i;
int back;
len = readlink(path, link_target, sizeof(link_target));
if (len <= 0)
return NULL;
link_target[len] = '\0';
dbg("devpath link '%s' points to '%s'", path, link_target);
for (back = 0; strncmp(&link_target[back * 3], "../", 3) == 0; back++)
;
dbg("base '%s', tail '%s', back %i", devpath_real, &link_target[back * 3], back);
for (i = 0; i <= back; i++) {
pos = strrchr(devpath_real, '/');
if (pos == NULL)
return NULL;
pos[0] = '\0';
}
dbg("after moving back '%s'", devpath_real);
strlcat(devpath_real, "/", sizeof(devpath_real));
strlcat(devpath_real, &link_target[back * 3], sizeof(devpath_real));
}
/* look for device in cache */
list_for_each_entry(dev_loop, &dev_list, node) {
if (strcmp(dev_loop->devpath, devpath_real) == 0) {
dbg("found in cache '%s'", dev_loop->devpath);
return dev_loop;
}
}
/* new device */
dbg("'%s'", devpath_real);
dev = malloc(sizeof(struct sysfs_device));
if (dev == NULL)
return NULL;
memset(dev, 0x00, sizeof(struct sysfs_device));
sysfs_device_set_values(dev, devpath_real, NULL);
/* get subsystem */
if (strncmp(dev->devpath, "/class/", 7) == 0) {
strlcpy(dev->subsystem, &dev->devpath[7], sizeof(dev->subsystem));
pos = strchr(dev->subsystem, '/');
if (pos != NULL)
pos[0] = '\0';
else
dev->subsystem[0] = '\0';
} else if (strncmp(devpath, "/block/", 7) == 0) {
strlcpy(dev->subsystem, "block", sizeof(dev->subsystem));
} else if (strncmp(devpath, "/devices/", 9) == 0) {
/* get subsystem from bus name */
strlcpy(link_path, sysfs_path, sizeof(link_path));
strlcat(link_path, dev->devpath, sizeof(link_path));
strlcat(link_path, "/bus", sizeof(link_path));
len = readlink(link_path, link_target, sizeof(link_target));
if (len > 0) {
link_target[len] = '\0';
dbg("bus link '%s' points to '%s'", link_path, link_target);
pos = strrchr(link_target, '/');
if (pos != NULL)
strlcpy(dev->subsystem, &pos[1], sizeof(dev->subsystem));
}
/* get driver name */
strlcpy(link_path, sysfs_path, sizeof(link_path));
strlcat(link_path, dev->devpath, sizeof(link_path));
strlcat(link_path, "/driver", sizeof(link_path));
len = readlink(link_path, link_target, sizeof(link_target));
if (len > 0) {
link_target[len] = '\0';
dbg("driver link '%s' points to '%s'", link_path, link_target);
pos = strrchr(link_target, '/');
if (pos != NULL)
strlcpy(dev->driver, &pos[1], sizeof(dev->driver));
}
} else if (strncmp(devpath, "/bus/", 5) == 0 && strstr(devpath, "/drivers/")) {
strlcpy(dev->subsystem, "drivers", sizeof(dev->subsystem));
} else if (strncmp(devpath, "/module/", 8) == 0) {
strlcpy(dev->subsystem, "module", sizeof(dev->subsystem));
}
dbg("add to cache 'devpath=%s', subsystem='%s', driver='%s'", dev->devpath, dev->subsystem, dev->driver);
list_add(&dev->node, &dev_list);
return dev;
}
struct sysfs_device *sysfs_device_get_parent(struct sysfs_device *dev)
{
char parent_devpath[PATH_SIZE];
char device_link[PATH_SIZE];
char device_link_target[PATH_SIZE];
char *pos;
int i;
int len;
int back;
/* requesting a parent is only valid for devices */
if ((strncmp(dev->devpath, "/devices/", 9) != 0) &&
(strncmp(dev->devpath, "/class/", 7) != 0) &&
(strncmp(dev->devpath, "/block/", 7) != 0))
return NULL;
strlcpy(parent_devpath, dev->devpath, sizeof(parent_devpath));
dbg("'%s'", parent_devpath);
/* strip last element */
pos = strrchr(parent_devpath, '/');
if (pos == NULL || pos == parent_devpath)
return NULL;
pos[0] = '\0';
/* are we at the top level */
if (strcmp(parent_devpath, "/devices") == 0) {
dbg("/devices top level");
return NULL;
}
/* at the top level we may follow the "device" link */
if (strcmp(parent_devpath, "/block") == 0) {
dbg("/block top level, look for device link");
goto device_link;
}
if (strncmp(parent_devpath, "/class", 6) == 0) {
pos = strrchr(parent_devpath, '/');
if (pos == &parent_devpath[6] || pos == parent_devpath) {
dbg("class top level, look for device link");
goto device_link;
}
}
return sysfs_device_get(parent_devpath);
device_link:
strlcpy(device_link, sysfs_path, sizeof(device_link));
strlcat(device_link, dev->devpath, sizeof(device_link));
strlcat(device_link, "/device", sizeof(device_link));
len = readlink(device_link, device_link_target, sizeof(device_link_target));
if (len < 0)
return NULL;
device_link_target[len] = '\0';
dbg("device link '%s' points to '%s'", device_link, device_link_target);
for (back = 0; strncmp(&device_link_target[back * 3], "../", 3) == 0; back++)
;
strlcpy(parent_devpath, dev->devpath, sizeof(parent_devpath));
dbg("base='%s', tail='%s', back=%i", parent_devpath, &device_link_target[back * 3], back);
for (i = 0; i < back; i++) {
pos = strrchr(parent_devpath, '/');
if (pos == NULL)
return NULL;
pos[0] = '\0';
}
dbg("after moving back '%s'", parent_devpath);
strlcat(parent_devpath, "/", sizeof(parent_devpath));
strlcat(parent_devpath, &device_link_target[back * 3], sizeof(parent_devpath));
return sysfs_device_get(parent_devpath);
}
char *sysfs_attr_get_value(const char *devpath, const char *attr_name)
{
char path_full[PATH_SIZE];
const char *path;
char value[NAME_SIZE];
struct sysfs_attr *attr_loop;
struct sysfs_attr *attr;
int fd;
ssize_t size;
size_t sysfs_len;
sysfs_len = strlcpy(path_full, sysfs_path, sizeof(path_full));
path = &path_full[sysfs_len];
strlcat(path_full, devpath, sizeof(path_full));
strlcat(path_full, "/", sizeof(path_full));
strlcat(path_full, attr_name, sizeof(path_full));
/* look for attribute in cache */
list_for_each_entry(attr_loop, &attr_list, node) {
if (strcmp(attr_loop->path, path) == 0) {
dbg("found in cache '%s'", attr_loop->path);
return attr_loop->value;
}
}
/* read attribute value */
fd = open(path_full, O_RDONLY);
if (fd < 0)
return NULL;
size = read(fd, value, sizeof(value));
close(fd);
if (size < 0)
return NULL;
if (size == sizeof(value))
return NULL;
value[size] = '\0';
remove_trailing_chars(value, '\n');
/* store attribute in cache */
attr = malloc(sizeof(struct sysfs_attr));
if (attr == NULL)
return NULL;
strlcpy(attr->path, path, sizeof(attr->path));
strlcpy(attr->value, value, sizeof(attr->value));
dbg("add to cache '%s' '%s'", attr->path, attr->value);
list_add(&attr->node, &attr_list);
return attr->value;
}
-4
View File
@@ -30,11 +30,7 @@
#include <syslog.h>
#include <sys/utsname.h>
#include "udev_libc_wrapper.h"
#include "udev.h"
#include "logging.h"
#include "udev_utils.h"
#include "list.h"
int log_priority(const char *priority)
-65
View File
@@ -1,65 +0,0 @@
/*
* udev_utils.c - generic stuff used by udev
*
* Copyright (C) 2004-2005 Kay Sievers <kay.sievers@vrfy.org>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation version 2 of the License.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#ifndef _UDEV_COMMON_H_
#define _UDEV_COMMON_H_
#include "udev.h"
#include "list.h"
#define UDEV_MAX(a,b) ((a) > (b) ? (a) : (b))
/* pipes */
#define READ_END 0
#define WRITE_END 1
struct name_entry {
struct list_head node;
char name[PATH_SIZE];
};
/* udev_utils.c */
extern int log_priority(const char *priority);
extern int name_list_add(struct list_head *name_list, const char *name, int sort);
extern int name_list_key_add(struct list_head *name_list, const char *key, const char *value);
extern void name_list_cleanup(struct list_head *name_list);
extern int add_matching_files(struct list_head *name_list, const char *dirname, const char *suffix);
/* udev_utils_string.c */
extern int strcmp_pattern(const char *p, const char *s);
extern int string_is_true(const char *str);
extern void remove_trailing_chars(char *path, char c);
extern int utf8_encoded_valid_unichar(const char *str);
extern int replace_untrusted_chars(char *str);
/* udev_utils_file.c */
extern int create_path(const char *path);
extern int delete_path(const char *path);
extern int file_map(const char *filename, char **buf, size_t *bufsize);
extern void file_unmap(void *buf, size_t bufsize);
extern int unlink_secure(const char *filename);
extern size_t buf_get_line(const char *buf, size_t buflen, size_t cur);
/* udev_utils_run.c */
extern int pass_env_to_socket(const char *name, const char *devpath, const char *action);
extern int run_program(const char *command, const char *subsystem,
char *result, size_t ressize, size_t *reslen, int log);
#endif
-4
View File
@@ -30,11 +30,7 @@
#include <sys/stat.h>
#include <sys/mman.h>
#include "udev_libc_wrapper.h"
#include "udev.h"
#include "logging.h"
#include "udev_utils.h"
#include "list.h"
int create_path(const char *path)
{
-4
View File
@@ -31,11 +31,7 @@
#include <sys/wait.h>
#include <sys/select.h>
#include "udev_libc_wrapper.h"
#include "udev.h"
#include "logging.h"
#include "udev_utils.h"
#include "list.h"
int pass_env_to_socket(const char *sockname, const char *devpath, const char *action)
-4
View File
@@ -30,11 +30,7 @@
#include <syslog.h>
#include <sys/utsname.h>
#include "udev_libc_wrapper.h"
#include "udev.h"
#include "logging.h"
#include "udev_utils.h"
#include "list.h"
/* compare string with pattern (like fnmatch(), supports * ? [0-9] [!A-Z]) */
int strcmp_pattern(const char *p, const char *s)
-3
View File
@@ -32,10 +32,7 @@
#include <linux/stddef.h>
#include "udev.h"
#include "udev_version.h"
#include "udevd.h"
#include "udev_utils.h"
#include "logging.h"
/* global variables */
static int sock = -1;
+22 -19
View File
@@ -42,16 +42,11 @@
#include <linux/types.h>
#include <linux/netlink.h>
#include "list.h"
#include "udev_libc_wrapper.h"
#include "udev.h"
#include "udev_version.h"
#include "udev_rules.h"
#include "udev_utils.h"
#include "udevd.h"
#include "logging.h"
struct udev_rules rules;
static struct udev_rules rules;
static int udevd_sock;
static int uevent_netlink_sock;
static int inotify_fd;
@@ -94,8 +89,7 @@ static void asmlinkage udev_event_sig_handler(int signum)
static int udev_event_process(struct uevent_msg *msg)
{
struct sigaction act;
struct udevice udev;
struct name_entry *name_loop;
struct udevice *udev;
int i;
int retval;
@@ -109,27 +103,34 @@ static int udev_event_process(struct uevent_msg *msg)
/* trigger timeout to prevent hanging processes */
alarm(UDEV_ALARM_TIMEOUT);
/* reconstruct env from message */
/* reconstruct event environment from message */
for (i = 0; msg->envp[i]; i++)
putenv(msg->envp[i]);
udev_init_device(&udev, msg->devpath, msg->subsystem, msg->action);
retval = udev_process_event(&rules, &udev);
udev = udev_device_init();
if (udev == NULL)
return -1;
strlcpy(udev->action, msg->action, sizeof(udev->action));
sysfs_device_set_values(udev->dev, msg->devpath, msg->subsystem);
udev->devt = msg->devt;
retval = udev_device_event(&rules, udev);
/* run programs collected by RUN-key*/
if (!retval) {
list_for_each_entry(name_loop, &udev.run_list, node) {
if (retval == 0) {
struct name_entry *name_loop;
list_for_each_entry(name_loop, &udev->run_list, node) {
if (strncmp(name_loop->name, "socket:", strlen("socket:")) == 0)
pass_env_to_socket(&name_loop->name[strlen("socket:")], msg->devpath, msg->action);
else
if (run_program(name_loop->name, udev.subsystem, NULL, 0, NULL,
if (run_program(name_loop->name, udev->dev->subsystem, NULL, 0, NULL,
(udev_log_priority >= LOG_INFO)))
retval = -1;
}
}
udev_cleanup_device(&udev);
udev_device_cleanup(udev);
return retval;
}
@@ -819,7 +820,7 @@ int main(int argc, char *argv[], char *envp[])
if (fd < 0)
err("fatal, could not open /dev/null: %s", strerror(errno));
udev_init_config();
udev_config_init();
dbg("version %s", UDEV_VERSION);
if (getuid() != 0) {
@@ -859,6 +860,7 @@ int main(int argc, char *argv[], char *envp[])
}
/* parse the rules and keep it in memory */
sysfs_init();
udev_rules_init(&rules, 1);
if (daemonize) {
@@ -1020,7 +1022,7 @@ int main(int argc, char *argv[], char *envp[])
/* rules changed, set by inotify or a signal*/
if (reload_config) {
reload_config = 0;
udev_rules_close(&rules);
udev_rules_cleanup(&rules);
udev_rules_init(&rules, 1);
}
@@ -1038,7 +1040,8 @@ int main(int argc, char *argv[], char *envp[])
}
exit:
udev_rules_close(&rules);
udev_rules_cleanup(&rules);
sysfs_cleanup();
if (signal_pipe[READ_END] > 0)
close(signal_pipe[READ_END]);
+1 -1
View File
@@ -32,7 +32,7 @@
#define EVENT_QUEUE_DIR ".udev/queue"
#define EVENT_FAILED_DIR ".udev/failed"
/* maximum limit of runnig childs */
/* maximum limit of forked childs */
#define UDEVD_MAX_CHILDS 64
/* start to throttle forking if maximum number of running childs in our session is reached */
#define UDEVD_MAX_CHILDS_RUNNING 16
+117 -143
View File
@@ -21,17 +21,14 @@
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stddef.h>
#include <ctype.h>
#include <stdarg.h>
#include <unistd.h>
#include <dirent.h>
#include <errno.h>
#include "libsysfs/sysfs/libsysfs.h"
#include "udev_libc_wrapper.h"
#include "udev.h"
#include "udev_utils.h"
#include "udev_version.h"
#include "logging.h"
#ifdef USE_LOG
@@ -48,42 +45,89 @@ void log_message (int priority, const char *format, ...)
}
#endif
static void print_all_attributes(struct dlist *attr_list)
static void print_all_attributes(const char *devpath)
{
struct sysfs_attribute *attr;
char value[VALUE_SIZE];
size_t len;
char path[PATH_SIZE];
DIR *dir;
struct dirent *dent;
dlist_for_each_data(attr_list, attr, struct sysfs_attribute) {
if (attr->value == NULL)
continue;
len = strlcpy(value, attr->value, sizeof(value));
if (len >= sizeof(value)) {
dbg("attribute value of '%s' too long, skip", attr->name);
continue;
}
strlcpy(path, sysfs_path, sizeof(path));
strlcat(path, devpath, sizeof(path));
/* remove trailing newlines */
while (len && value[len-1] == '\n')
value[--len] = '\0';
/* skip nonprintable attributes */
while (len && isprint(value[len-1]))
len--;
if (len) {
dbg("attribute value of '%s' non-printable, skip", attr->name);
continue;
dir = opendir(path);
if (dir != NULL) {
for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
char *attr_value;
char value[NAME_SIZE];
size_t len;
attr_value = sysfs_attr_get_value(devpath, dent->d_name);
if (attr_value == NULL)
continue;
len = strlcpy(value, attr_value, sizeof(value));
dbg("attr '%s'='%s'(%zi)", dent->d_name, value, len);
/* remove trailing newlines */
while (len && value[len-1] == '\n')
value[--len] = '\0';
/* skip nonprintable attributes */
while (len && isprint(value[len-1]))
len--;
if (len) {
dbg("attribute value of '%s' non-printable, skip", dent->d_name);
continue;
}
replace_untrusted_chars(value);
printf(" SYSFS{%s}==\"%s\"\n", dent->d_name, value);
}
replace_untrusted_chars(value);
printf(" SYSFS{%s}==\"%s\"\n", attr->name, value);
}
printf("\n");
}
static int print_device_chain(const char *devpath)
{
struct sysfs_device *dev;
printf("\n"
"udevinfo starts with the device the node belongs to and then walks up the\n"
"device chain, to print for every device found, all possibly useful attributes\n"
"in the udev key format.\n"
"Only attributes within one device section may be used together in one rule,\n"
"to match the device for which the node will be created.\n"
"\n");
dev = sysfs_device_get(devpath);
if (dev == NULL)
return -1;
printf(" looking at device '%s':\n", dev->devpath);
printf(" KERNEL==\"%s\"\n", dev->kernel_name);
printf(" SUBSYSTEM==\"%s\"\n", dev->subsystem);
print_all_attributes(dev->devpath);
/* walk up the chain of devices */
while (1) {
dev = sysfs_device_get_parent(dev);
if (dev == NULL)
break;
printf(" looking at device '%s':\n", dev->devpath);
printf(" ID==\"%s\"\n", dev->kernel_name);
printf(" BUS==\"%s\"\n", dev->subsystem);
printf(" DRIVER==\"%s\"\n", dev->driver);
print_all_attributes(dev->devpath);
}
return 0;
}
static void print_record(struct udevice *udev)
{
struct name_entry *name_loop;
printf("P: %s\n", udev->devpath);
printf("P: %s\n", udev->dev->devpath);
printf("N: %s\n", udev->name);
list_for_each_entry(name_loop, &udev->symlink_list, node)
printf("S: %s\n", name_loop->name);
@@ -91,82 +135,8 @@ static void print_record(struct udevice *udev)
printf("E: %s\n", name_loop->name);
}
static int print_device_chain(const char *path)
{
struct sysfs_class_device *class_dev;
struct sysfs_class_device *class_dev_parent;
struct sysfs_attribute *attr;
struct sysfs_device *sysfs_dev;
struct dlist *attr_list;
int retval = 0;
/* get the class dev */
class_dev = sysfs_open_class_device_path(path);
if (class_dev == NULL) {
fprintf(stderr, "couldn't get the class device\n");
return -1;
}
printf("\nudevinfo starts with the device the node belongs to and then walks up the\n"
"device chain, to print for every device found, all possibly useful attributes\n"
"in the udev key format.\n"
"Only attributes within one device section may be used together in one rule,\n"
"to match the device for which the node will be created.\n"
"\n");
/* look for the 'dev' file */
attr = sysfs_get_classdev_attr(class_dev, "dev");
if (attr != NULL)
printf("device '%s' has major:minor %s", class_dev->path, attr->value);
/* open sysfs class device directory and print all attributes */
printf(" looking at class device '%s':\n", class_dev->path);
printf(" KERNEL==\"%s\"\n", class_dev->name);
printf(" SUBSYSTEM==\"%s\"\n", class_dev->classname);
attr_list = sysfs_get_classdev_attributes(class_dev);
if (attr_list == NULL) {
fprintf(stderr, "couldn't open class device directory\n");
retval = -1;
goto exit;
}
print_all_attributes(attr_list);
/* get the device link (if parent exists look here) */
class_dev_parent = sysfs_get_classdev_parent(class_dev);
if (class_dev_parent != NULL)
sysfs_dev = sysfs_get_classdev_device(class_dev_parent);
else
sysfs_dev = sysfs_get_classdev_device(class_dev);
if (sysfs_dev != NULL)
printf("follow the \"device\"-link to the physical device:\n");
/* look the device chain upwards */
while (sysfs_dev != NULL) {
printf(" looking at the device chain at '%s':\n", sysfs_dev->path);
printf(" BUS==\"%s\"\n", sysfs_dev->bus);
printf(" ID==\"%s\"\n", sysfs_dev->bus_id);
printf(" DRIVER==\"%s\"\n", sysfs_dev->driver_name);
attr_list = sysfs_get_device_attributes(sysfs_dev);
if (attr_list != NULL)
print_all_attributes(attr_list);
else
printf("\n");
sysfs_dev = sysfs_get_device_parent(sysfs_dev);
if (sysfs_dev == NULL)
break;
}
exit:
sysfs_close_class_device(class_dev);
return retval;
}
static void export_name_devpath(struct udevice *udev) {
printf("%s=%s/%s\n", udev->devpath, udev_root, udev->name);
printf("%s=%s/%s\n", udev->dev->devpath, udev_root, udev->name);
}
static void export_record(struct udevice *udev) {
@@ -180,12 +150,14 @@ static void export_db(void fnct(struct udevice *udev)) {
udev_db_get_all_entries(&name_list);
list_for_each_entry(name_loop, &name_list, node) {
struct udevice udev_db;
struct udevice *udev_db;
udev_init_device(&udev_db, NULL, NULL, NULL);
if (udev_db_get_device(&udev_db, name_loop->name) == 0)
fnct(&udev_db);
udev_cleanup_device(&udev_db);
udev_db = udev_device_init();
if (udev_db == NULL)
continue;
if (udev_db_get_device(udev_db, name_loop->name) == 0)
fnct(udev_db);
udev_device_cleanup(udev_db);
}
name_list_cleanup(&name_list);
}
@@ -215,7 +187,7 @@ int main(int argc, char *argv[], char *envp[])
{
static const char short_options[] = "aden:p:q:rVh";
int option;
struct udevice udev;
struct udevice *udev;
int root = 0;
enum action_type {
@@ -239,12 +211,18 @@ int main(int argc, char *argv[], char *envp[])
char temp[PATH_SIZE];
struct name_entry *name_loop;
char *pos;
int retval = 0;
int rc = 0;
logging_init("udevinfo");
udev_init_config();
udev_init_device(&udev, NULL, NULL, NULL);
udev_config_init();
sysfs_init();
udev = udev_device_init();
if (udev == NULL) {
rc = 1;
goto exit;
}
/* get command line options */
while (1) {
@@ -260,7 +238,11 @@ int main(int argc, char *argv[], char *envp[])
break;
case 'p':
dbg("udev path: %s\n", optarg);
strlcpy(path, optarg, sizeof(path));
/* remove sysfs mountpoint if not given */
if (strncmp(optarg, sysfs_path, strlen(sysfs_path)) == 0)
strlcpy(path, &optarg[strlen(sysfs_path)], sizeof(path));
else
strlcpy(path, optarg, sizeof(path));
break;
case 'q':
dbg("udev query: %s\n", optarg);
@@ -286,7 +268,7 @@ int main(int argc, char *argv[], char *envp[])
break;
}
fprintf(stderr, "unknown query type\n");
retval = 2;
rc = 2;
goto exit;
case 'r':
if (action == ACTION_NONE)
@@ -331,10 +313,9 @@ int main(int argc, char *argv[], char *envp[])
pos = path;
}
}
retval = udev_db_get_device(&udev, pos);
if (retval != 0) {
if (udev_db_get_device(udev, pos) != 0) {
fprintf(stderr, "no record for '%s' in database\n", pos);
retval = 3;
rc = 3;
goto exit;
}
} else if (name[0] != '\0') {
@@ -348,46 +329,45 @@ int main(int argc, char *argv[], char *envp[])
} else
pos = name;
retval = udev_db_lookup_name(pos, devpath, sizeof(devpath));
if (retval != 0) {
if (udev_db_lookup_name(pos, devpath, sizeof(devpath)) != 0) {
fprintf(stderr, "no record for '%s' in database\n", pos);
retval = 3;
rc = 3;
goto exit;
}
udev_db_get_device(&udev, devpath);
udev_db_get_device(udev, devpath);
} else {
fprintf(stderr, "query needs device path(-p) or node name(-n) specified\n");
retval = 4;
rc = 4;
goto exit;
}
switch(query) {
case QUERY_NAME:
if (root)
printf("%s/%s\n", udev_root, udev.name);
printf("%s/%s\n", udev_root, udev->name);
else
printf("%s\n", udev.name);
printf("%s\n", udev->name);
break;
case QUERY_SYMLINK:
if (list_empty(&udev.symlink_list))
if (list_empty(&udev->symlink_list))
goto exit;
if (root)
list_for_each_entry(name_loop, &udev.symlink_list, node)
list_for_each_entry(name_loop, &udev->symlink_list, node)
printf("%s/%s ", udev_root, name_loop->name);
else
list_for_each_entry(name_loop, &udev.symlink_list, node)
list_for_each_entry(name_loop, &udev->symlink_list, node)
printf("%s ", name_loop->name);
printf("\n");
break;
case QUERY_PATH:
printf("%s\n", udev.devpath);
printf("%s\n", udev->dev->devpath);
goto exit;
case QUERY_ENV:
list_for_each_entry(name_loop, &udev.env_list, node)
list_for_each_entry(name_loop, &udev->env_list, node)
printf("%s\n", name_loop->name);
break;
case QUERY_ALL:
print_record(&udev);
print_record(udev);
break;
default:
print_help();
@@ -397,29 +377,23 @@ int main(int argc, char *argv[], char *envp[])
case ACTION_ATTRIBUTE_WALK:
if (path[0] == '\0') {
fprintf(stderr, "attribute walk on device chain needs path(-p) specified\n");
retval = 4;
rc = 4;
goto exit;
} else {
if (strncmp(path, sysfs_path, strlen(sysfs_path)) != 0) {
/* prepend sysfs mountpoint if not given */
snprintf(temp, sizeof(temp), "%s%s", sysfs_path, path);
temp[sizeof(temp)-1] = '\0';
strlcpy(path, temp, sizeof(temp));
}
} else
print_device_chain(path);
}
break;
case ACTION_ROOT:
printf("%s\n", udev_root);
break;
default:
print_help();
retval = 1;
rc = 1;
break;
}
exit:
udev_cleanup_device(&udev);
udev_device_cleanup(udev);
sysfs_cleanup();
logging_close();
return retval;
return rc;
}
-2
View File
@@ -34,8 +34,6 @@
#include "udev.h"
#include "udevd.h"
#include "udev_utils.h"
#include "udev_libc_wrapper.h"
static int uevent_netlink_sock;
static int udev_monitor_sock;
+1 -3
View File
@@ -33,9 +33,7 @@
#include <linux/stddef.h>
#include "udev.h"
#include "udev_version.h"
#include "udevd.h"
#include "logging.h"
/* global variables */
static int sock = -1;
@@ -67,7 +65,7 @@ int main(int argc, char *argv[], char *envp[])
logging_init("udevsend");
#ifdef USE_LOG
udev_init_config();
udev_config_init();
#endif
dbg("version %s", UDEV_VERSION);
+44 -46
View File
@@ -38,14 +38,8 @@
#include <sys/stat.h>
#include <sys/types.h>
#include "libsysfs/sysfs/libsysfs.h"
#include "udev_libc_wrapper.h"
#include "udev.h"
#include "udev_version.h"
#include "logging.h"
#include "udev_utils.h"
#include "udev_rules.h"
#include "list.h"
static const char *udev_run_str;
static const char *udev_log_str;
@@ -68,11 +62,10 @@ void log_message(int priority, const char *format, ...)
struct device {
struct list_head node;
char path[PATH_SIZE];
char subsys[NAME_SIZE];
};
/* sort files in lexical order */
static int device_list_insert(const char *path, char *subsystem, struct list_head *device_list)
static int device_list_insert(const char *path, struct list_head *device_list)
{
struct device *loop_device;
struct device *new_device;
@@ -93,9 +86,8 @@ static int device_list_insert(const char *path, char *subsystem, struct list_hea
}
strlcpy(new_device->path, devpath, sizeof(new_device->path));
strlcpy(new_device->subsys, subsystem, sizeof(new_device->subsys));
list_add_tail(&new_device->node, &loop_device->node);
dbg("add '%s' from subsys '%s'", new_device->path, new_device->subsys);
dbg("add '%s'" , new_device->path);
return 0;
}
@@ -112,64 +104,68 @@ static char *first_list[] = {
NULL,
};
static int add_device(const char *devpath, const char *subsystem)
static int add_device(const char *devpath)
{
struct udevice udev;
struct sysfs_class_device *class_dev;
char path[PATH_SIZE];
struct sysfs_device *dev;
struct udevice *udev;
/* clear and set environment for next event */
clearenv();
setenv("ACTION", "add", 1);
setenv("DEVPATH", devpath, 1);
setenv("SUBSYSTEM", subsystem, 1);
setenv("UDEV_START", "1", 1);
if (udev_log_str)
setenv("UDEV_LOG", udev_log_str, 1);
if (udev_run_str)
setenv("UDEV_RUN", udev_run_str, 1);
dbg("add '%s'", devpath);
snprintf(path, sizeof(path), "%s%s", sysfs_path, devpath);
path[sizeof(path)-1] = '\0';
class_dev = sysfs_open_class_device_path(path);
if (class_dev == NULL) {
dbg("sysfs_open_class_device_path failed");
dev = sysfs_device_get(devpath);
if (dev == NULL)
return -1;
udev = udev_device_init();
if (udev == NULL)
return -1;
/* override built-in sysfs device */
udev->dev = dev;
strcpy(udev->action, "add");
udev->devt = udev_device_get_devt(udev);
if (strcmp(udev->dev->subsystem, "net") != 0) {
udev->devt = udev_device_get_devt(udev);
if (major(udev->devt) == 0)
return -1;
}
udev_init_device(&udev, &class_dev->path[strlen(sysfs_path)], subsystem, "add");
udev.devt = get_devt(class_dev);
if (!udev.devt && udev.type != DEV_NET) {
dbg("sysfs_open_class_device_path failed");
return -1;
}
udev_rules_get_name(&rules, &udev, class_dev);
if (udev.ignore_device) {
dbg("add '%s'", udev->dev->devpath);
setenv("DEVPATH", udev->dev->devpath, 1);
setenv("SUBSYSTEM", udev->dev->subsystem, 1);
udev_rules_get_name(&rules, udev);
if (udev->ignore_device) {
dbg("device event will be ignored");
goto exit;
}
if (udev.name[0] == '\0') {
if (udev->name[0] == '\0') {
dbg("device node creation supressed");
goto run;
}
udev_add_device(&udev, class_dev);
udev_add_device(udev);
run:
if (udev_run && !list_empty(&udev.run_list)) {
if (udev_run && !list_empty(&udev->run_list)) {
struct name_entry *name_loop;
dbg("executing run list");
list_for_each_entry(name_loop, &udev.run_list, node) {
list_for_each_entry(name_loop, &udev->run_list, node) {
if (strncmp(name_loop->name, "socket:", strlen("socket:")) == 0)
pass_env_to_socket(&name_loop->name[strlen("socket:")], devpath, "add");
pass_env_to_socket(&name_loop->name[strlen("socket:")], udev->dev->devpath, "add");
else
run_program(name_loop->name, udev.subsystem, NULL, 0, NULL, (udev_log_priority >= LOG_INFO));
run_program(name_loop->name, udev->dev->subsystem, NULL, 0, NULL, (udev_log_priority >= LOG_INFO));
}
}
exit:
sysfs_close_class_device(class_dev);
udev_cleanup_device(&udev);
udev_device_cleanup(udev);
return 0;
}
@@ -184,7 +180,7 @@ static void exec_list(struct list_head *device_list)
list_for_each_entry_safe(loop_device, tmp_device, device_list, node) {
for (i = 0; first_list[i] != NULL; i++) {
if (strncmp(loop_device->path, first_list[i], strlen(first_list[i])) == 0) {
add_device(loop_device->path, loop_device->subsys);
add_device(loop_device->path);
list_del(&loop_device->node);
free(loop_device);
break;
@@ -204,14 +200,14 @@ static void exec_list(struct list_head *device_list)
if (found)
continue;
add_device(loop_device->path, loop_device->subsys);
add_device(loop_device->path);
list_del(&loop_device->node);
free(loop_device);
}
/* handle the rest of the devices left over, if any */
list_for_each_entry_safe(loop_device, tmp_device, device_list, node) {
add_device(loop_device->path, loop_device->subsys);
add_device(loop_device->path);
list_del(&loop_device->node);
free(loop_device);
}
@@ -253,7 +249,7 @@ static void udev_scan_block(struct list_head *device_list)
snprintf(dirname, sizeof(dirname), "%s/%s", base, dent->d_name);
dirname[sizeof(dirname)-1] = '\0';
if (has_devt(dirname))
device_list_insert(dirname, "block", device_list);
device_list_insert(dirname, device_list);
else
continue;
@@ -270,7 +266,7 @@ static void udev_scan_block(struct list_head *device_list)
dirname2[sizeof(dirname2)-1] = '\0';
if (has_devt(dirname2))
device_list_insert(dirname2, "block", device_list);
device_list_insert(dirname2, device_list);
}
closedir(dir2);
}
@@ -313,7 +309,7 @@ static void udev_scan_class(struct list_head *device_list)
dirname2[sizeof(dirname2)-1] = '\0';
if (has_devt(dirname2) || strcmp(dent->d_name, "net") == 0)
device_list_insert(dirname2, dent->d_name, device_list);
device_list_insert(dirname2, device_list);
}
closedir(dir2);
}
@@ -339,7 +335,7 @@ int main(int argc, char *argv[], char *envp[])
struct sigaction act;
logging_init("udevstart");
udev_init_config();
udev_config_init();
dbg("version %s", UDEV_VERSION);
udev_run_str = getenv("UDEV_RUN");
@@ -361,13 +357,15 @@ int main(int argc, char *argv[], char *envp[])
/* trigger timeout to prevent hanging processes */
alarm(UDEV_ALARM_TIMEOUT);
sysfs_init();
udev_rules_init(&rules, 1);
udev_scan_class(&device_list);
udev_scan_block(&device_list);
exec_list(&device_list);
udev_rules_close(&rules);
udev_rules_cleanup(&rules);
sysfs_cleanup();
logging_close();
return 0;
}
+2 -2
View File
@@ -10,8 +10,8 @@
.SH "NAME"
udevtest \- simulate a udev run and print the action to the console
.SH "SYNOPSIS"
.HP 31
\fBudevtest \fR\fB\fIdevice\-path\fR\fR\fB \fR\fB\fIsubsystem\fR\fR
.HP 21
\fBudevtest \fR\fB\fIdevice\-path\fR\fR
.SH "DESCRIPTION"
.PP
udevtest simulates a udev run for the given device and prints out the name of the node udev would have created, or the name of the network interface, that would have been renamend.
+45 -40
View File
@@ -21,17 +21,15 @@
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stddef.h>
#include <unistd.h>
#include <errno.h>
#include <ctype.h>
#include <signal.h>
#include <syslog.h>
#include "libsysfs/sysfs/libsysfs.h"
#include "udev.h"
#include "udev_utils.h"
#include "udev_version.h"
#include "udev_rules.h"
#include "logging.h"
#ifdef USE_LOG
@@ -53,28 +51,28 @@ void log_message (int priority, const char *format, ...)
int main(int argc, char *argv[], char *envp[])
{
struct udev_rules rules;
struct sysfs_class_device *class_dev;
char *devpath;
char path[PATH_SIZE];
char temp[PATH_SIZE];
struct udevice udev;
char *subsystem = NULL;
struct udevice *udev;
struct sysfs_device *dev;
int retval;
int rc = 0;
info("version %s", UDEV_VERSION);
/* initialize our configuration */
udev_init_config();
udev_config_init();
if (udev_log_priority < LOG_INFO)
udev_log_priority = LOG_INFO;
if (argc != 3) {
info("Usage: udevtest <devpath> <subsystem>");
if (argc != 2) {
info("Usage: udevtest <devpath>");
return 1;
}
/* remove sysfs_path if given */
if (strncmp(argv[1], sysfs_path, strlen(sysfs_path)) == 0)
devpath = &argv[1][strlen(sysfs_path)] ;
devpath = &argv[1][strlen(sysfs_path)];
else
if (argv[1][0] != '/') {
/* prepend '/' if missing */
@@ -84,39 +82,46 @@ int main(int argc, char *argv[], char *envp[])
} else
devpath = argv[1];
subsystem = argv[2];
setenv("DEVPATH", devpath, 1);
setenv("SUBSYSTEM", subsystem, 1);
setenv("ACTION", "add", 1);
info("looking at device '%s' from subsystem '%s'", devpath, subsystem);
/* initialize the naming deamon */
sysfs_init();
udev_rules_init(&rules, 0);
/* fill in values and test_run flag*/
udev_init_device(&udev, devpath, subsystem, "add");
/* open the device */
snprintf(path, sizeof(path), "%s%s", sysfs_path, udev.devpath);
path[sizeof(path)-1] = '\0';
class_dev = sysfs_open_class_device_path(path);
if (class_dev == NULL) {
info("sysfs_open_class_device_path failed");
return 1;
dev = sysfs_device_get(devpath);
if (dev == NULL) {
info("unable to open '%s'", devpath);
rc = 2;
goto exit;
}
info("opened class_dev->name='%s'", class_dev->name);
if (udev.type == DEV_BLOCK || udev.type == DEV_CLASS)
udev.devt = get_devt(class_dev);
udev = udev_device_init();
if (udev == NULL) {
info("can't open device");
rc = 3;
goto exit;
}
/* override built-in sysfs device */
udev->dev = dev;
strcpy(udev->action, "add");
udev->devt = udev_device_get_devt(udev);
/* simulate node creation with test flag */
udev.test_run = 1;
if (udev.type == DEV_NET || udev.devt) {
udev_rules_get_name(&rules, &udev, class_dev);
udev_add_device(&udev, class_dev);
} else
info("only char and block devices with a dev-file are supported by this test program");
sysfs_close_class_device(class_dev);
udev->test_run = 1;
return 0;
setenv("DEVPATH", udev->dev->devpath, 1);
setenv("SUBSYSTEM", udev->dev->subsystem, 1);
setenv("ACTION", "add", 1);
info("looking at device '%s' from subsystem '%s'", udev->dev->devpath, udev->dev->subsystem);
retval = udev_device_event(&rules, udev);
if (retval == 0) {
struct name_entry *name_loop;
list_for_each_entry(name_loop, &udev->run_list, node)
info("run: '%s'", name_loop->name);
}
exit:
udev_rules_cleanup(&rules);
sysfs_cleanup();
return rc;
}