From 1aa1e24848903d11780db1ade355be73ad61a937 Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Mon, 9 Jan 2006 21:18:00 +0100 Subject: 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 --- Makefile | 30 +- RELEASE-NOTES | 8 + docs/udev.xml | 7 - docs/udevtest.xml | 2 +- extras/ata_id/Makefile | 2 +- extras/ata_id/ata_id.c | 4 +- extras/cdrom_id/Makefile | 2 +- extras/cdrom_id/cdrom_id.c | 4 +- extras/dasd_id/Makefile | 2 +- extras/dasd_id/dasd_id.c | 3 +- extras/edd_id/Makefile | 2 +- extras/edd_id/edd_id.c | 4 +- extras/firmware/Makefile | 2 +- extras/firmware/firmware_helper.c | 3 +- extras/floppy/Makefile | 2 +- extras/run_directory/Makefile | 2 +- extras/run_directory/run_directory.c | 4 +- extras/run_directory/udev_run_devd.c | 4 +- extras/run_directory/udev_run_hotplugd.c | 4 +- extras/scsi_id/Makefile | 3 +- extras/scsi_id/scsi_id.c | 436 +++---- extras/scsi_id/scsi_id.h | 14 +- extras/scsi_id/scsi_serial.c | 258 ++-- extras/usb_id/Makefile | 2 +- extras/usb_id/usb_id.c | 226 ++-- extras/volume_id/Makefile | 2 +- extras/volume_id/vol_id.c | 3 +- libsysfs/LGPL | 441 ------- libsysfs/dlist.c | 621 ---------- libsysfs/libsysfs.txt | 1954 ------------------------------ libsysfs/sysfs.h | 64 - libsysfs/sysfs/dlist.h | 207 ---- libsysfs/sysfs/libsysfs.h | 225 ---- libsysfs/sysfs_bus.c | 317 ----- libsysfs/sysfs_class.c | 557 --------- libsysfs/sysfs_device.c | 341 ------ libsysfs/sysfs_dir.c | 491 -------- libsysfs/sysfs_driver.c | 261 ---- libsysfs/sysfs_utils.c | 290 ----- test/simple-build-check.sh | 3 +- test/udev-test.pl | 51 +- udev.c | 53 +- udev.h | 108 +- udev_add.c | 54 +- udev_config.c | 10 +- udev_db.c | 14 +- udev_device.c | 138 ++- udev_event.c | 161 --- udev_libc_wrapper.c | 3 - udev_remove.c | 12 +- udev_rules.c | 353 +++--- udev_rules.h | 12 +- udev_rules_parse.c | 5 +- udev_selinux.c | 1 - udev_sysfs.c | 345 ++++++ udev_utils.c | 4 - udev_utils.h | 65 - udev_utils_file.c | 4 - udev_utils_run.c | 4 - udev_utils_string.c | 4 - udevcontrol.c | 3 - udevd.c | 41 +- udevd.h | 2 +- udevinfo.c | 254 ++-- udevmonitor.c | 2 - udevsend.c | 4 +- udevstart.c | 88 +- udevtest.8 | 4 +- udevtest.c | 85 +- 69 files changed, 1376 insertions(+), 7315 deletions(-) delete mode 100644 libsysfs/LGPL delete mode 100644 libsysfs/dlist.c delete mode 100644 libsysfs/libsysfs.txt delete mode 100644 libsysfs/sysfs.h delete mode 100644 libsysfs/sysfs/dlist.h delete mode 100644 libsysfs/sysfs/libsysfs.h delete mode 100644 libsysfs/sysfs_bus.c delete mode 100644 libsysfs/sysfs_class.c delete mode 100644 libsysfs/sysfs_device.c delete mode 100644 libsysfs/sysfs_dir.c delete mode 100644 libsysfs/sysfs_driver.c delete mode 100644 libsysfs/sysfs_utils.c delete mode 100644 udev_event.c create mode 100644 udev_sysfs.c delete mode 100644 udev_utils.h diff --git a/Makefile b/Makefile index 5edc76f81a..461f5ac012 100644 --- a/Makefile +++ b/Makefile @@ -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 > $@ diff --git a/RELEASE-NOTES b/RELEASE-NOTES index 4e3570205e..623ea0ed60 100644 --- a/RELEASE-NOTES +++ b/RELEASE-NOTES @@ -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. diff --git a/docs/udev.xml b/docs/udev.xml index e87dbab880..7f6a30df52 100644 --- a/docs/udev.xml +++ b/docs/udev.xml @@ -361,13 +361,6 @@ - - , - - The kernel bus id for this device. - - - , diff --git a/docs/udevtest.xml b/docs/udevtest.xml index ceea0413c5..2b39eebab0 100644 --- a/docs/udevtest.xml +++ b/docs/udevtest.xml @@ -37,7 +37,7 @@ - udevtest device-path subsystem + udevtest device-path diff --git a/extras/ata_id/Makefile b/extras/ata_id/Makefile index ebf0f4e9b4..0a881fb194 100644 --- a/extras/ata_id/Makefile +++ b/extras/ata_id/Makefile @@ -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 diff --git a/extras/ata_id/ata_id.c b/extras/ata_id/ata_id.c index a97cc284cc..aedebff711 100644 --- a/extras/ata_id/ata_id.c +++ b/extras/ata_id/ata_id.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -24,8 +25,7 @@ #include #include -#include "../../logging.h" -#include "../../udev_utils.h" +#include "../../udev.h" #ifdef USE_LOG void log_message(int priority, const char *format, ...) diff --git a/extras/cdrom_id/Makefile b/extras/cdrom_id/Makefile index 985eb805a5..9a722d52f9 100644 --- a/extras/cdrom_id/Makefile +++ b/extras/cdrom_id/Makefile @@ -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 diff --git a/extras/cdrom_id/cdrom_id.c b/extras/cdrom_id/cdrom_id.c index ff6f89e163..0d4a8c10f0 100644 --- a/extras/cdrom_id/cdrom_id.c +++ b/extras/cdrom_id/cdrom_id.c @@ -18,14 +18,14 @@ #include #include #include +#include #include #include #include #include #include -#include "../../logging.h" -#include "../../udev_utils.h" +#include "../../udev.h" /* * Taken from the cdrom.h kernel include file. diff --git a/extras/dasd_id/Makefile b/extras/dasd_id/Makefile index 80680f22fe..79f14a49ba 100644 --- a/extras/dasd_id/Makefile +++ b/extras/dasd_id/Makefile @@ -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 diff --git a/extras/dasd_id/dasd_id.c b/extras/dasd_id/dasd_id.c index ca2582cde6..b2496e99f8 100644 --- a/extras/dasd_id/dasd_id.c +++ b/extras/dasd_id/dasd_id.c @@ -24,8 +24,7 @@ #include #include -#include "../../logging.h" -#include "../../udev_utils.h" +#include "../../udev.h" #ifdef USE_LOG void log_message(int priority, const char *format, ...) diff --git a/extras/edd_id/Makefile b/extras/edd_id/Makefile index 5a6cdb65c3..db6afae18c 100644 --- a/extras/edd_id/Makefile +++ b/extras/edd_id/Makefile @@ -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 diff --git a/extras/edd_id/edd_id.c b/extras/edd_id/edd_id.c index f21362b902..8fc690a49c 100644 --- a/extras/edd_id/edd_id.c +++ b/extras/edd_id/edd_id.c @@ -18,12 +18,12 @@ #include #include #include +#include #include #include #include -#include "../../logging.h" -#include "../../udev_utils.h" +#include "../../udev.h" #ifdef USE_LOG void log_message(int priority, const char *format, ...) diff --git a/extras/firmware/Makefile b/extras/firmware/Makefile index 16918867fc..da7fe9d1a8 100644 --- a/extras/firmware/Makefile +++ b/extras/firmware/Makefile @@ -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 diff --git a/extras/firmware/firmware_helper.c b/extras/firmware/firmware_helper.c index 2bc6b50f06..ca1c43814f 100644 --- a/extras/firmware/firmware_helper.c +++ b/extras/firmware/firmware_helper.c @@ -17,8 +17,7 @@ #include #include -#include "../../udev_utils.h" -#include "../../logging.h" +#include "../../udev.h" #define FIRMWARE_PATH "/lib/firmware" #define PATH_SIZE 256 diff --git a/extras/floppy/Makefile b/extras/floppy/Makefile index 240af4ce05..e23191a533 100644 --- a/extras/floppy/Makefile +++ b/extras/floppy/Makefile @@ -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 diff --git a/extras/run_directory/Makefile b/extras/run_directory/Makefile index d138f62c03..37a59597b9 100644 --- a/extras/run_directory/Makefile +++ b/extras/run_directory/Makefile @@ -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 diff --git a/extras/run_directory/run_directory.c b/extras/run_directory/run_directory.c index 69faecc15e..c715ca6bd3 100644 --- a/extras/run_directory/run_directory.c +++ b/extras/run_directory/run_directory.c @@ -22,9 +22,7 @@ #include #include -#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) diff --git a/extras/run_directory/udev_run_devd.c b/extras/run_directory/udev_run_devd.c index e708de8aa4..59ea766ac2 100644 --- a/extras/run_directory/udev_run_devd.c +++ b/extras/run_directory/udev_run_devd.c @@ -22,9 +22,7 @@ #include #include -#include "../../udev_utils.h" -#include "../../list.h" -#include "../../logging.h" +#include "../../udev.h" #include "run_directory.h" diff --git a/extras/run_directory/udev_run_hotplugd.c b/extras/run_directory/udev_run_hotplugd.c index a21835ae4e..bfa82ab917 100644 --- a/extras/run_directory/udev_run_hotplugd.c +++ b/extras/run_directory/udev_run_hotplugd.c @@ -22,9 +22,7 @@ #include #include -#include "../../udev_utils.h" -#include "../../list.h" -#include "../../logging.h" +#include "../../udev.h" #include "run_directory.h" diff --git a/extras/scsi_id/Makefile b/extras/scsi_id/Makefile index 399de76911..057594d5bf 100644 --- a/extras/scsi_id/Makefile +++ b/extras/scsi_id/Makefile @@ -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 diff --git a/extras/scsi_id/scsi_id.c b/extras/scsi_id/scsi_id.c index aa1b16009e..3a4a374d3e 100644 --- a/extras/scsi_id/scsi_id.c +++ b/extras/scsi_id/scsi_id.c @@ -32,37 +32,20 @@ #include #include #include -#include -#include "scsi_id_version.h" -#include "scsi_id.h" -#ifndef SCSI_ID_VERSION -#warning No version -#define SCSI_ID_VERSION "unknown" -#endif +#include "../../udev.h" +#include "scsi_id.h" +#include "scsi_id_version.h" -/* - * 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) - return; + if (udev_log == -1) { + const char *value; - 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); + value = getenv("UDEV_LOG"); + if (value) + udev_log = log_priority(value); + else + udev_log = LOG_ERR; } - va_end (args); - return; + + if (priority > udev_log) + 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); - /* - * 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_type = S_IFBLK; - } else if (has_sysfs_prefix(target_path, "/class")) { - 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; - } - } + dbg("devpath %s\n", devpath); - 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)); + dev = sysfs_device_get(devpath); + if (dev == NULL) { + err("unable to access '%s'", devpath); 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. - */ + if (strcmp(dev->subsystem, "block") == 0) + dev_type = S_IFBLK; + else + dev_type = S_IFCHR; - /* - * 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; } diff --git a/extras/scsi_id/scsi_id.h b/extras/scsi_id/scsi_id.h index 1c9ed969a7..b5312b8988 100644 --- a/extras/scsi_id/scsi_id.h +++ b/extras/scsi_id/scsi_id.h @@ -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. diff --git a/extras/scsi_id/scsi_serial.c b/extras/scsi_id/scsi_serial.c index 14955e676c..bdebe94eb3 100644 --- a/extras/scsi_id/scsi_serial.c +++ b/extras/scsi_id/scsi_serial.c @@ -30,11 +30,12 @@ #include #include #include -#include /* need __user when built via klibc */ #include -#include -#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; } diff --git a/extras/usb_id/Makefile b/extras/usb_id/Makefile index f6d26e1c4c..91b4d57d76 100644 --- a/extras/usb_id/Makefile +++ b/extras/usb_id/Makefile @@ -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 diff --git a/extras/usb_id/usb_id.c b/extras/usb_id/usb_id.c index b7d67958c9..0bcd267f67 100644 --- a/extras/usb_id/usb_id.c +++ b/extras/usb_id/usb_id.c @@ -21,12 +21,10 @@ #include #include -#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)); + dbg("devpath %s\n", devpath); + + dev = sysfs_device_get(devpath); + if (dev == NULL) { + err("unable to access '%s'", devpath); 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); - } - /* - * 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); + /* 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) { - info("%s is not a scsi device", target_path); + /* 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); - /* usb device directory */ - usb_dev = sysfs_get_device_parent(interface_dev); + dev_interface = sysfs_device_get_parent(dev_host); + if (dev_interface == NULL) { + err("unable to access parent device of '%s'", devpath); + return 1; + } - if (strcmp(interface_dev->bus, "usb") != 0) { - info("%s is not an usb device", target_path); + /* usb device directory */ + 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; } diff --git a/extras/volume_id/Makefile b/extras/volume_id/Makefile index 6201044941..edb5d3ac68 100644 --- a/extras/volume_id/Makefile +++ b/extras/volume_id/Makefile @@ -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 diff --git a/extras/volume_id/vol_id.c b/extras/volume_id/vol_id.c index 6f99c52728..a291eda51d 100644 --- a/extras/volume_id/vol_id.c +++ b/extras/volume_id/vol_id.c @@ -29,8 +29,7 @@ #include #include -#include "../../udev_utils.h" -#include "../../logging.h" +#include "../../udev.h" #include "libvolume_id/volume_id.h" #define BLKGETSIZE64 _IOR(0x12,114,size_t) diff --git a/libsysfs/LGPL b/libsysfs/LGPL deleted file mode 100644 index e00a829bb6..0000000000 --- a/libsysfs/LGPL +++ /dev/null @@ -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 - - diff --git a/libsysfs/dlist.c b/libsysfs/dlist.c deleted file mode 100644 index 5579602bbc..0000000000 --- a/libsysfs/dlist.c +++ /dev/null @@ -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((l1counthead)) - { - 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; - -} - diff --git a/libsysfs/libsysfs.txt b/libsysfs/libsysfs.txt deleted file mode 100644 index b877cb8030..0000000000 --- a/libsysfs/libsysfs.txt +++ /dev/null @@ -1,1954 +0,0 @@ - - System Utilities sysfs Library - libsysfs - ========================================= - -Version: 1.2.0 -September 13, 2004 - -Contents --------- -1. Introduction -2. Requirements -3. Definitions -4. Overview -5. Data Structures - 5.1 Directory and Attribute Data Structures - 5.1.1 Attribute Structure - 5.1.2 Link Structure - 5.1.3 Directory Structure - 5.2 Bus Data Structure - 5.3 Class Data Structures - 5.4 Root Device Data Structure - 5.5 Device Data Structure - 5.6 Driver Data Structure -6. Functions - 6.1 Calling Conventions in Libsysfs - 6.2 Utility Functions - 6.3 Filesystem Functions - 6.3.1 Attribute Functions - 6.3.2 Directory Link Functions - 6.3.3 Directory Functions - 6.4 Bus Functions - 6.5 Class Functions - 6.6 Device Functions - 6.7 Driver Functions -7. Dlists - 7.1 Navigating a dlist - 7.2 Custom sorting using dlist_sort_custom() -8. Usage -9. Testsuite -10. Conclusion - - -1. Introduction ---------------- - -Libsysfs' purpose is to provide a consistent and stable interface for -querying system device information exposed through the sysfs filesystem. -The library implements functions for querying filesystem information, -such as reading directories and files. It also contains routines for -working with buses, classes, and the device tree. - - -2. Requirements ---------------- - -The library must satisfy the following requirements: - -- It must provide a stable programming interfaces that applications can - be built upon. - -- It must provide functions to retrieve device Vital Product Data (VPD) - information for Error Log Analysis (ELA) support. ELA will provide - device driver and device bus address information. - -- It must provide access to all system devices and information exposed - by sysfs. - -- It must provide a function to find sysfs' current mount point. - -- It must provide a function for udev to retrieve a device's major and - minor numbers. - - -3. Definitions --------------- - -- sysfs: Sysfs is a virtual filesystem in 2.5+ Linux kernels that - presents a hierarchical representation of all system physical and - virtual devices. It presents system devices by bus, by class, and - by topology. Callbacks to device drivers are exposed as files in - device directories. Sysfs, for all purposes, is our tree of system - devices. For more information, please see: - - http://www.kernel.org/pub/linux/kernel/people/mochel/doc/ - -- udev: Udev is Greg Kroah-Hartman's User Space implementation of devfs. - Udev creates /dev nodes for devices upon Hotplug events. The Hotplug - event provides udev with a sysfs directory location of the device. Udev - must use that directory to grab device's major and minor number, which it - will use to create the /dev node. For more information, please see: - - http://www.kernel.org/pub/linux/utils/kernel/hotplug/ - - Udev provides persistent device naming based on a set of user specified - rules. The rules a device name is based on could one or a combination of a - number of parameters such as the bus the device is on, the serial number - of the device (in case of USB), the vendor name (in case of SCSI) and so - on. Udev uses Libsysfs to retrieve relevent information to appropriately - name devices. - - -4. Overview ------------ - -Libsysfs grew from a common need. There are several applications under -development that need access to sysfs and system devices. Udev, on a -hotplug event, must take a sysfs device path and create a /dev node. Our -diagnostic client needs to list all system devices. Finally, our Error -Log Analysis piece is required to retrieve VPD information for a -failing device. We divided to create a single library interface rather -than having these separate applications create their own accesses to -sysfs involving reading directories and files. - -Libsysfs will also provide stability for applications to be built upon. Sysfs -currently doesn't enforce any standards for callback or file names. File -names change depending on bus or class. Sysfs is also changing, it is -currently being developed. Libsysfs will provide a stable interface to -applications while allowing sysfs to change underneath it. - -Like sysfs, the library will provide devices to applications by bus, by -class, and by topology. The library will function similar to directories -and files that lie underneath it. To query a device on a PCI bus, one would -"open" the bus to scan or read devices and "close" the bus when -completed. Besides supplying functions to retrieve devices, the library -will also provide some utility functions like getting sysfs mount point. - -A paper on Libsysfs was presented at Linux.Conf.Au 2004 (Adelaide, January -2004). The paper is available online at: - -http://oss.software.ibm.com/linux/papers/libsysfs/libsysfs-linuxconfau2004.pdf - - -5. Data Structures ------------------- - -Libsysfs will classify system devices following sysfs' example, dividing -them by bus, class, and devices. The library presents this information -generically. It doesn't, for example, differentiate between PCI and USB -buses. Device attributes are presented with values as they are exposed -by sysfs, the values are not formatted. - -The library will provide standard definitions for working with sysfs -and devices, here's some examples: - -#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_NAME_ATTRIBUTE "name" - -The library uses some definitions to mark maximum size of a sysfs name or -path length: - -#define SYSFS_PATH_MAX 255 -#define SYSFS_NAME_LEN 50 -#define SYSFS_BUS_ID_SIZE 20 - - -NOTE: - a. As of release 0.4.0 of sysfsutils, a number of changes have been - made so that the dlists and "directory" references in all libsysfs's - structures are not populated until such time that it is absolutely - necessary. Hence, these elements may not contain valid data at all - times (as was the case before). - b. As of release 1.0.0 of sysfsutils, all dlists in the library are - sorted in alphabetical order. It is now a requirement that the - "name" and "path" be the first two elements of all libsysfs - structures. - - -5.1 Directory and Attribute Data Structures -------------------------------------------- - -The library implements structures to represent sysfs directories, links, -and files. - - -5.1.1 Attribute Structure -------------------------- - -A file in sysfs represents a device or driver attribute. Attributes can be -read only, write only, or read and write. File data can be ASCII and -binary. The library has the following structure to represent files: - -struct sysfs_attribute { - char name[SYSFS_NAME_LEN]; - char path[SYSFS_PATH_MAX]; - char *value; - unsigned short len; /* value length */ - unsigned short method; /* show and store */ -}; - -Path represents the file/attribute's full path. Value is used when reading -from or writing to an attribute. "len" is the length of data in "value". -Method is a bitmask for defining if the attribute supports show(read) -and/or store(write). - - -5.1.2 Link Structure --------------------- - -Symbolic links are used in sysfs to link bus or class views with -particular devices. - -struct sysfs_link { - char name[SYSFS_NAME_LEN]; - char path[SYSFS_PATH_MAX]; - char target[SYSFS_PATH_MAX]; -}; - -Link's name is stored in "name' and it's target stored in "target". Absolute -path to the link is stored in "path". - - -5.1.3 Directory Structure -------------------------- - -The directory structure represents a sysfs directory: - -struct sysfs_directory { - char name[SYSFS_NAME_LEN]; - char path[SYSFS_PATH_MAX]; - - /* Private: for internal use only */ - struct dlist *subdirs; - struct dlist *links; - struct dlist *attributes; -}; - -The sysfs_directory structure includes the list of subdirectories, links and -attributes. The "name" and absolute "path" are also stored in the structure. -The sysfs_directory structure is intended for use internal to the library. -Applications needing access to attributes and links from the directory -will need to make appropriate calls (described below) to get the same. - - -5.2 Bus Data Structure ----------------------- - -All buses look similar in sysfs including lists of devices and drivers, -therefore we use the following structure to represent all sysfs buses: - -struct sysfs_bus { - char name[SYSFS_NAME_LEN]; - char path[SYSFS_PATH_MAX]; - - /* Private: for internal use only */ - struct dlist *drivers; - struct dlist *devices; - struct sysfs_directory *directory; -}; - -The sysfs_bus structure contains the bus "name", while the "path" to bus -directory is also stored. It also contains lists of devices on the bus -and drivers that are registered on it. The bus' directory is represented -by the sysfs_directory structure and it contains references to all the -subdirectories, links, and attributes. The sysfs_directory structure -is for internal use only. The following functions may be used by -applications to retrieve data from the sysfs_directory structure: - -struct dlist *sysfs_get_bus_attributes(struct sysfs_bus *bus) -struct sysfs_attribute *sysfs_get_bus_attribute(struct sysfs_bus *bus, - char *attrname) - - -5.3 Class Data Structures -------------------------- - -The library uses two data structures to represent classes in sysfs. Sysfs -classes contains a class directory like "net" or "scsi_host" and then -class devices like "eth0", "lo", or "eth1" for the "net" class. - -struct sysfs_class { - char name[SYSFS_NAME_LEN]; - char path[SYSFS_PATH_MAX]; - - /* Private: for internal use only */ - struct dlist *devices; - struct sysfs_directory *directory; -}; - -The sysfs_class represents device classes in sysfs like "net". It contains -the class "name", "path" to the class, a list of class devices and the -directory representation (for internal use only). - -struct sysfs_class_device { - char name[SYSFS_NAME_LEN]; - char path[SYSFS_PATH_MAX]; - char classname[SYSFS_NAME_LEN]; - - /* Private: for internal use only */ - struct sysfs_class_device *parent; - struct sysfs_device *sysdevice; /* NULL if virtual */ - struct sysfs_driver *driver; /* NULL if not implemented */ - struct sysfs_directory *directory; -}; - -A class device isn't the same as a sysfs_device, it's specific to the class in -which it belongs. The class device structure contains the name of the class -the class device belongs to, its sysfs_device reference and that device's -driver reference (if any). It also contains the name of the class device -- like "eth0", its parent point (if present) and its sysfs directory -information including links and attributes (for internal use only). -The following function may be used by applications to retrieve data -from the sysfs_directory structure: - -struct dlist *sysfs_get_classdev_attributes(struct sysfs_class_device *cdev); - - -5.4 Root Device Data Structure ------------------------------- - -Device hierarchies in sysfs are represented under the /sys/devices directory -structure. Sysfs devices typically spawn off from base devices which are -represented by a sysfs_root_device. - -struct sysfs_root_device { - char name[SYSFS_NAME_LEN]; - char path[SYSFS_PATH_MAX]; - - /* Private: for internal use only */ - struct dlist *devices; - struct sysfs_directory *directory; -}; - -The sysfs_root_device structure contains a list of "devices" that spawn off it. -The name of the root device as represented under /sys/devices is read into -"name" and the absolute path into "path" and its sysfs_directory information -intended to be used internal to the library. - - -5.5 Device Data Structure -------------------------- - -The sysfs_device structure represents a system device that's exposed -in sysfs under the /sys/devices directory structure. - -struct sysfs_device { - char name[SYSFS_NAME_LEN]; - char path[SYSFS_PATH_MAX]; - 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; - struct dlist *children; - struct sysfs_directory *directory; -}; - -The sysfs_device structure contains a "parent" pointer, a list of child -devices, if any, device's directory, its bus id - which is the name of -device's directory, the bus name on which this device is registered and -its driver name. The device structure also contains the absolute path -to the device and a directory structure, which contains a list of the -device's attributes (for internal use only). The following functions -may be used to obtain information from sysfs_directory structure: - -struct sysfs_attribute *sysfs_get_device_attribute(struct sysfs_device *dev, - const char *name) -struct dlist *sysfs_get_device_attributes(struct sysfs_device *device) - - -5.6 Driver Data Structure -------------------------- - -The sysfs_driver structure represents a device driver. - -struct sysfs_driver { - char name[SYSFS_NAME_LEN]; - char path[SYSFS_PATH_MAX]; - - /* Private: for internal use only */ - struct dlist *devices; - struct sysfs_directory *directory; -}; - -The sysfs_driver structure contains a list of devices that use this driver, -the name of the driver, its path, and its directory information, which -includes the driver's attributes (for internal use only). The following -function may be used to retrieve driver attribute information from the -sysfs_directory structure: - -struct dlist *sysfs_get_driver_attributes(struct sysfs_driver *driver) - - -6. Functions ------------- - -Libsysfs will provide functions to access system devices by bus, by class, -and by device. Functions will act like accessing directories and files, -using "open" and "close". Open returns a structure and close is used -to clean that structure up. - - -6.1 Calling Conventions in Libsysfs ------------------------------------ - -Libsysfs uses a simple API calling convention. APIs are classified to be -one of "open", "get", "close" types. The convention is as follows: - - a. All "open" APIs have a corresponding "close" API. - b. References obtained using "get" calls should not be closed - explicitly. - c. All "opened" references have to be closed with a call to - their corresponding "close" call. This takes care of - freeing structure references obtained with "get" calls. - - -6.2 Utility Functions ---------------------- - -The library will provide a few utility functions for working with sysfs. - -------------------------------------------------------------------------------- -Name: sysfs_get_mnt_path - -Description: Function finds the mount path for filesystem type "sysfs". - -Arguments: char *mnt_path Mount path buffer - size_t len Size of mount path buffer - -Returns: Zero with success. - -1 with error. Errno will be set with error: - - EINVAL for invalid argument, if buffer is NULL or - if len is zero - -Prototype: sysfs_get_mnt_path(char *mnt_path, size_t len); -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -Name: sysfs_get_name_from_path - -Description: Function returns the last directory or file name from the - included path. - -Arguments: const char *path Path to parse name from - char *name Buffer to put parsed name into - size_t *len Size of name buffer - -Returns: 0 with success. - -1 on Error. Errno will be set with error, returning - - EINVAL for invalid arguments - -Prototype: int sysfs_get_name_from_path(const char *path, - char *name, size_t *len) -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -Name: sysfs_get_link - -Description: Sysfs readlink function, reads the link at supplied path - and returns its target path. - -Arguments: const char *path Link's path - char *target Buffer to place link's target - size_t len Size of target buffer - -Returns: 0 with success - -1 with error. Errno will be set with error, returning - - EINVAL for invalid arguments - -Prototype: int sysfs_get_link(const char *path, char *target, size_t len) -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -Name: sysfs_open_subsystem_list - -Description: Function returns the list of entries for the given subsystem. If - the argument is "bus", this function will return a list of buses - ("pci", "scsi", etc) supported on the system. - - sysfs_close_list() has to be called to free the list obtained - from this call. - -Arguments: char *name Subsystem to open, like "bus".. - -Returns: dlist of entries for the subsystem on success - NULL with error indicating the "name" subsystem is invalid. - -Prototype: struct dlist *sysfs_open_subsystem_list(char *name) -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -Name: sysfs_open_bus_devices_list - -Description: Function returns the list of devices on the given bus. - - sysfs_close_list() has to be called to free the list obtained - from this call. - -Arguments: char *name Bus name to open "pci"/"scsi"/"usb".. - -Returns: dlist of device names for the given bus on success - NULL with error indicating the bus is not supported. - -Prototype: struct dlist *sysfs_open_bus_devices_list(char *name) -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -Name: sysfs_close_list - -Description: Closes a given dlist. This can be used as a generic list close - routine. - -Arguments: struct dlist *list List to be closed - -Prototype: void sysfs_close_list(struct dlist *list) -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -Name: sysfs_path_is_dir - -Description: Utility function to verify if a given path is to a directory. - -Arguments: const char *path Path to verify - -Returns: 0 on success, 1 on error - - EINVAL for invalid arguments - -Prototype: int sysfs_path_is_dir(const char *path) -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -Name: sysfs_path_is_file - -Description: Utility function to verify if a given path is to a file. - -Arguments: const char *path Path to verify - -Returns: 0 on success, 1 on error - - EINVAL for invalid arguments - -Prototype: int sysfs_path_is_file(const char *path) -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -Name: sysfs_path_is_link - -Description: Utility function to verify if a given path is to a link. - -Arguments: const char *path Path to verify - -Returns: 0 on success, 1 on error - - EINVAL for invalid arguments - -Prototype: int sysfs_path_is_link(const char *path) -------------------------------------------------------------------------------- - - -6.3 Filesystem Functions ------------------------- - -Libsysfs provides a set of functions to open, read, and close directories -and attributes/files in sysfs. These functions mirror their filesystem -function counterparts. - - -6.3.1 Attribute Functions -------------------------- - -Along with the usual open, read, and close functions, libsysfs provides -a couple other functions for accessing attribute values. - -------------------------------------------------------------------------------- -Name: sysfs_open_attribute - -Description: Opens up a file in sysfs and creates a sysfs_attribute - structure. File isn't read with this function. - -Arguments: const char *path File/Attribute's path - -Returns: struct sysfs_attribute * with success. - NULL with error. Errno will be set with error, returning - - EINVAL for invalid arguments - -Prototype: struct sysfs_attribute *sysfs_open_attribute(const char *path) -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -Name: sysfs_close_attribute - -Description: Cleans up and closes sysfs_attribute structure. - -Arguments: struct sysfs_attribute *sysattr Attribute to close - -Prototype: void sysfs_close_attribute(struct sysfs_attribute *sysattr) -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -Name: sysfs_read_dir_attributes - -Description: Reads the given sysfs_directory to create a list of attributes. - -Arguments: struct sysfs_directory *sysdir sysfs_directory whose - attributes to read - -Returns: struct dlist * of attributes on success - NULL with error. Errno will be set on error, returning EINVAL - for invalid arguments - -Prototype: struct dlist *sysfs_read_dir_attributes - (struct sysfs_directory *sysdir) -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -Name: sysfs_refresh_dir_attributes - -Description: Given a list sysfs_directory, this function refreshes the list - of attributes for the given directory. - -Arguments: struct sysfs_directory *sysdir sysfs_ directory whose - attributes list to refresh - -Returns: 0 with success. - 1 with error. Errno will be set on error, returning EINVAL - for invalid arguments - -Prototype: int sysfs_refresh_dir_attributes(struct sysfs_directory *sysdir) -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -Name: sysfs_get_dir_attributes - -Description: Returns a list of attributes for the given sysfs_directory. - -Arguments: struct sysfs_directory *sysdir sysfs_directory whose - attributes list to return - -Returns: struct dlist * of attributes with success - NULL with error. Errno will be set on error, returning EINVAL - for invalid arguments - -Prototype: struct dlist *sysfs_read_dir_attributes - (struct sysfs_directory *sysdir) -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -Name: sysfs_read_attribute - -Description: Reads the supplied attribute. Since the maximum transfer - from a sysfs attribute is a pagesize, function reads in - up to a page from the file and stores it in the "value" - field in the attribute. - -Arguments: struct sysfs_attribute *sysattr Attribute to read - -Returns: 0 with success. - -1 with error. Errno will be set with error, returning - - EINVAL for invalid arguments - -Prototype: int sysfs_read_attribute(struct sysfs_attribute *sysattr) -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -Name: sysfs_write_attribute - -Description: Writes to the supplied attribute. Function validates if the - given attribute is writable, and writes the new value to the - attribute. Value to write as well as its length is user - supplied. In case the length written is not equal to the - length requested to be written, the original value is - restored and an error is returned. - -Arguments: struct sysfs_attribute *sysattr Attribute to write to - const char *new_value sysattr's new value - size_t len Length of "new_value" - -Returns: 0 with success. - -1 with error. Errno will be set with error, returning - - EINVAL for invalid arguments - -Prototype: int sysfs_write_attribute(struct sysfs_attribute *sysattr, - const char *new_value, size_t len) -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -Name: sysfs_read_attribute_value - -Description: Given a path to a specific attribute, function reads and - returns its value to the supplied value buffer. - -Arguments: const char *attrpath Attribute path to read - char *value Buffer to read in attribute's value - size_t vsize Size of buffer - -Returns: 0 with success. - -1 with error. Errno will be set with error, returning - - EINVAL for invalid arguments - -Prototype: int sysfs_read_attribute_value(const char *attrpath, - char *value, size_t vsize) -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -Name: sysfs_get_value_from_attributes - -Description: Function takes a single or linked list of sysfs attribute - structures and returns the value of the specified attribute - name. - -Arguments: struct dlist *attr Attribute list to search through - const char *name Name of attribute whose value - to retrieve - -Returns: char * attribute value with success. - NULL with error. Errno will be set with error, returning - - EINVAL for invalid arguments - -Prototype: char *sysfs_get_value_from_attributes - (struct sysfs_attribute *attr, const char *name) -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -Name: sysfs_get_directory_attribute - -Description: Function walks the list of attributes for the given sysfs - directory and returns the sysfs_attribute structure for - the specified attribute name. - -Arguments: struct sysfs_directory *dir Directory in which to search - char *attrname Attribute name to look for - -Returns: struct sysfs_attribute on success. - NULL with error. Errno will be set with error, returning - - EINVAL for invalid arguments - -Prototype: struct sysfs_attribute *sysfs_get_directory_attribute - (struct sysfs_directory *dir, char *attrname) -------------------------------------------------------------------------------- - - -6.3.2 Link Functions --------------------- - -Sysfs contains many symbolic links, like bus links to bus devices. Libsysfs -treats links differently than directories due to processing differences. A -link in the /sys/bus/"busname"/devices/ directory indicates a device in the -/sys/devices directory. Through links we give the functionality to know -what is and what isn't a link and the ability to query the links target. - -------------------------------------------------------------------------------- -Name: sysfs_open_link - -Description: Opens a directory link. - -Arguments: const char *linkpath Path to link - -Returns: struct sysfs_link * with success. - NULL with error. Errno will be set with error, returning - - EINVAL for invalid arguments - -Prototype: struct sysfs_link *sysfs_open_link(const char *linkpath) -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -Name: sysfs_close_link - -Description: Closes a directory link structure. - -Arguments: struct sysfs_link *ln Link to close - -Prototype: void sysfs_close_link(struct sysfs_link *ln) -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -Name: sysfs_read_dir_links - -Description: Reads the given sysfs_directory to create a list of links. - -Arguments: struct sysfs_directory *sysdir sysfs_directory whose - links to read - -Returns: struct dlist * of links with success - NULL with error. Errno will be set on error, returning EINVAL - for invalid arguments - -Prototype: struct dlist *sysfs_read_dir_links - (struct sysfs_directory *sysdir) -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -Name: sysfs_get_dir_links - -Description: Returns a list of links for the given sysfs_directory. - -Arguments: struct sysfs_directory *sysdir sysfs_directory whose - list of links to return - -Returns: struct dlist * of links with success - NULL with error. Errno will be set on error, returning EINVAL - for invalid arguments - -Prototype: struct dlist *sysfs_read_dir_links - (struct sysfs_directory *sysdir) -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -Name: sysfs_get_directory_link - -Description: Function walks the list of links for the given sysfs directory - and returns the sysfs_link structure for the specified link - name. - -Arguments: struct sysfs_directory *dir Directory in which to search - char *linkname Link name to look for - -Returns: struct sysfs_link * with success. - NULL with error. Errno will be set with error, returning - - EINVAL for invalid arguments - -Prototype: struct sysfs_link *sysfs_get_directory_link - (struct sysfs_directory *dir, char *linkname) -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -Name: sysfs_get_subdirectory_link - -Description: Function walks the list of links for the given sysfs directory - and its subdirectories returns the sysfs_link structure for - the specified link name. - -Arguments: struct sysfs_directory *dir Directory in which to search - char *linkname Link name to look for - -Returns: struct sysfs_link * with success. - NULL with error. Errno will be set with error, returning - - EINVAL for invalid arguments - -Prototype: struct sysfs_link *sysfs_get_subdirectory_link - (struct sysfs_directory *dir, char *linkname) -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -Name: sysfs_refresh_dir_links - -Description: Given a list sysfs_directory, this function refreshes the list - of links under the given directory. - -Arguments: struct sysfs_directory *sysdir sysfs_ directory whose - links list to refresh - -Returns: 0 with success. - 1 with error. Errno will be set on error, returning EINVAL - for invalid arguments - -Prototype: int sysfs_refresh_dir_links(struct sysfs_directory *sysdir) -------------------------------------------------------------------------------- - - -6.3.3 Directory Functions -------------------------- - -Sysfs directories can represent every directory under sysfs. The structures -keep track of subdirectories, links, and files. Like opendir, readdir, and -closedir, libsysfs provides open, read, and close functions for working with -sysfs directories. Open creates the sysfs_directory structure. Read reads in -its contents - like subdirectories, links, and files. Close cleans it all -up. - -------------------------------------------------------------------------------- -Name: sysfs_open_directory - -Description: Opens a sysfs directory at a specific path - -Arguments: const char *path Directory path to open - -Returns: struct sysfs_directory * with success. - NULL with error. Errno will be set with error, returning - - EINVAL for invalid arguments - -Prototype: struct sysfs_directory *sysfs_open_directory(const char *path) -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -Name: sysfs_close_directory - -Description: Closes specific directory, its subdirectories, links, and - files. - -Arguments: struct sysfs_directory *sysdir Directory to close - -Prototype: void sysfs_close_directory(struct sysfs_directory *sysdir) -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -Name: sysfs_read_dir_subdirs - -Description: Reads the given sysfs_directory to create a list of subdirs. - -Arguments: struct sysfs_directory *sysdir sysfs_directory whose - subdirs have to be read - -Returns: struct dlist * of links with success - NULL with error. Errno will be set on error, returning EINVAL - for invalid arguments - -Prototype: struct dlist *sysfs_read_dir_subdirs - (struct sysfs_directory *sysdir) -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -Name: sysfs_read_directory - -Description: Read the supplied directory. Reading fills in the directory's - contents like subdirectories, links, and attributes. - -Arguments: struct sysfs_directory *sysdir Directory to read - -Returns: 0 with success. - -1 with error. Errno will be set with error, returning - - EINVAL for invalid arguments - -Prototype: int sysfs_read_directory(struct sysfs_directory *sysdir) -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -Name: sysfs_read_all_subdirs - -Description: Reads all subdirs under a given supplied directory. - -Arguments: struct sysfs_directory *sysdir Directory to read - -Returns: 0 with success. - -1 with error. Errno will be set with error, returning - - EINVAL for invalid arguments - -Prototype: int sysfs_read_all_subdirs(struct sysfs_directory *sysdir) -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -Name: sysfs_get_subdirectory - -Description: Function walks the directory tree for the given directory and - returns a sysfs_directory structure for the specified directory - name. - -Arguments: struct sysfs_directory *dir Directory in which to search - char *subname Name of directory to look for - -Returns: struct sysfs_directory with success. - NULL with error. Errno will be set with error, returning - - EINVAL for invalid arguments - -Prototype: struct sysfs_directory *sysfs_get_subdirectory - (struct sysfs_directory *dir, char *subname) -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -Name: sysfs_get_dir_subdirs - -Description: Returns a list of subdirs for the given sysfs_directory. - -Arguments: struct sysfs_directory *sysdir sysfs_directory whose - subdirectories list to return - -Returns: struct dlist * of directories with success - NULL with error. Errno will be set on error, returning EINVAL - for invalid arguments - -Prototype: struct dlist *sysfs_read_dir_subdirs - (struct sysfs_directory *sysdir) -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -Name: sysfs_refresh_dir_subdirs - -Description: Given a list sysfs_directory, this function refreshes the list - of subdirectories under the given directory. - -Arguments: struct sysfs_directory *sysdir sysfs_ directory whose - subdirs list to refresh - -Returns: 0 with success. - 1 with error. Errno will be set on error, returning EINVAL - for invalid arguments - -Prototype: int sysfs_refresh_dir_subdirs(struct sysfs_directory *sysdir) -------------------------------------------------------------------------------- - - -6.4 Bus Functions ------------------ - -The library provides a functions for viewing buses represented in sysfs. -The sysfs_open_bus opens a bus in the /sys/bus directory, such as "pci", -"usb", or "scsi". The open command returns a sysfs_bus structure that -contains a list of the bus' devices. The sysfs_close_bus function is -used to clean up the bus structure. Given a device or a driver, -functions are provided to determine what bus they are on. - -------------------------------------------------------------------------------- -Name: sysfs_open_bus - -Description: Function opens up one of the buses represented in sysfs in - the /sys/bus directory. It returns a sysfs_bus structure - that includes a list of bus devices and drivers. - -Arguments: const char *name Bus name to open, like "pci"... - -Returns: struct sysfs_bus * with success - NULL with error. Errno will be set with error, returning - - EINVAL for invalid arguments - -Prototype: struct sysfs_bus *sysfs_open_bus(const char *name) -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -Name: sysfs_close_bus - -Description: Function closes up the sysfs_bus structure including its - devices, drivers, and directory. - -Arguments: sysfs_bus *bus Bus structure to close - -Prototype: void sysfs_close_bus(struct sysfs_bus *bus) -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -Name: sysfs_get_bus_devices - -Description: Function returns a list of devices that are registered with - this bus. - -Arguments: struct sysfs_bus *bus Bus whose devices list to return - -Returns: struct dlist * of sysfs_devices on success - NULL with error. Errno will be sent with error, returning - - EINVAL for invalid arguments - -Prototype: struct dlist *sysfs_get_bus_devices(struct sysfs_bus *bus) -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -Name: sysfs_get_bus_drivers - -Description: Function returns a list of drivers that are registered with - this bus. - -Arguments: struct sysfs_bus *bus Bus whose drivers list to return - -Returns: struct dlist * of sysfs_drivers on success - NULL with error. Errno will be sent with error, returning - - EINVAL for invalid arguments - -Prototype: struct dlist *sysfs_get_bus_drivers(struct sysfs_bus *bus) -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -Name: sysfs_get_bus_device - -Description: Function takes a sysfs_bus structure(obtained on a successful - return from a sysfs_open_bus() call) and looks for the given - device on this bus. On success, it returns a sysfs_device - structure corresponding to the device. - -Arguments: struct sysfs_bus *bus Bus structure on which to search - char *id Device to look for - -Returns: struct sysfs_device * with success - NULL with error. Errno will be set with error, returning - - EINVAL for invalid arguments - -Prototype: struct sysfs_device *sysfs_get_bus_device - (struct sysfs_bus *bus, char *id) -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -Name: sysfs_get_bus_driver - -Description: Function takes a sysfs_bus structure (obtained on a successful - return from a sysfs_open_bus() call) and looks for the given - driver on this bus. On success, it returns a sysfs_driver - structure corresponding to the driver. - -Arguments: struct sysfs_bus *bus Bus structure on which to search - char *drvname Driver to look for - -Returns: struct sysfs_driver * with success - NULL with error. Errno will be set with error, returning - - EINVAL for invalid arguments - -Prototype: struct sysfs_device *sysfs_get_bus_driver - (struct sysfs_bus *bus, char *drvname) -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -Name: sysfs_get_bus_attributes - -Description: Function takes a sysfs_bus structure and returns a list of - attributes for the bus. - -Arguments: struct sysfs_bus *bus Bus for which attributes are required - -Returns: struct dlist * of attributes with success - NULL with error. Errno will be set with error, returning - - EINVAL for invalid arguments - -Prototype: struct dlist *sysfs_get_bus_attributes(struct sysfs_bus *bus) -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -Name: sysfs_get_bus_attribute - -Description: Function takes a sysfs_bus structure and looks for the required - attribute on the bus. On success, it returns a sysfs_attribute - structure corresponding to the given attribute. - -Arguments: struct sysfs_bus *bus Bus structure on which to search - char *attrname Attribute to look for - -Returns: struct sysfs_attribute * with success - NULL with error. Errno will be set with error, returning - - EINVAL for invalid arguments - -Prototype: struct sysfs_attribute *sysfs_get_bus_attribute - (struct sysfs_bus *bus, char *attrname) -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -Name: sysfs_refresh_bus_attributes - -Description: Function refreshes the list of attributes for a given sysfs_bus - -Arguments: struct sysfs_bus *bus Bus whose attributes list to refresh - -Returns: struct dlist * of attributes with success - NULL with error. Errno will be set with error, returning - - EINVAL for invalid arguments - -Prototype: struct dlist *sysfs_get_bus_attributes(struct sysfs_bus *bus) -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -Name: sysfs_find_driver_bus - -Description: Given the name of a driver, this function finds the name of the - bus the driver is on - -Arguments: const char *driver Name of the driver to look for - char *busname Buffer to return the bus name - size_t bsize Size of the "busname" buffer - -Returns: 0 with success. - -1 with error. Errno will be set with error, returning - - EINVAL for invalid arguments - -Prototype: int sysfs_find_driver_bus(const char *driver, - char *busname, size_t bsize) -------------------------------------------------------------------------------- - - -6.5 Class Functions -------------------- - -Libsysfs provides functions to open sysfs classes and their class devices. -These functions too operate with open and close, close must be called to -clean up the class structures. Given a class device name, functions are -provided to determine what class they belong to. Once a class device -name and the class it belongs to is known, a function to open the -class device is provided. This method can be used when details of -a single class device is required. - -------------------------------------------------------------------------------- -Name: sysfs_open_class - -Description: Function opens up one of the classes represented in sysfs in - the /sys/class directory. It returns a sysfs_class structure - that includes a list of class devices. - -Arguments: const char *name Class name to open, like "net".. - -Returns: struct sysfs_class * with success - NULL with error. Errno will be set with error, returning - - EINVAL for invalid arguments - -Prototype: struct sysfs_class *sysfs_open_class(const char *name) -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -Name: sysfs_close_class - -Description: Function closes up the sysfs_class structure including its - class devices. - -Arguments: sysfs_class *cls Class structure to close - -Prototype: void sysfs_close_class(struct sysfs_class *cls); -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -Name: sysfs_open_class_device_path - -Description: Function opens up one of the class devices represented in - sysfs in sysfs/class/"class"/ directory. It returns a - sysfs_class_device structure. - -Arguments: const char *path Path to class device - -Returns: struct sysfs_class_device * with success - NULL with error. Errno will be set with error, returning - - EINVAL for invalid arguments - -Prototype: struct sysfs_class_device *sysfs_open_class_device_path - (const char *path) -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -Name: sysfs_close_class_device - -Description: Function closes up the sysfs_class_device structure. - -Arguments: sysfs_class_device *dev Class device structure to close - -Prototype: void sysfs_close_class_device(struct sysfs_class_device *dev) -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -Name: sysfs_get_class_device - -Description: Function takes a sysfs_class structure(obtained on a successful - return from a sysfs_open_class() call) and looks for the given - device in this class. On success, it returns a sysfs_class_device - structure corresponding to the class device. - -Arguments: struct sysfs_class *cls Class on which to search - char *name Class device "name" to look for - -Returns: struct sysfs_class_device * with success - NULL with error. Errno will be set with error, returning - - EINVAL for invalid arguments - -Prototype: struct sysfs_class_device *sysfs_get_class_device - (struct sysfs_class *cls, char *name) -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -Name: sysfs_get_class_devices - -Description: Function returns a list of class devices for the given class. - -Arguments: struct sysfs_class *cls Class whose class device list - is required - -Returns: struct dlist * of sysfs_class_devices on success - NULL with error. Errno will be set with error, returning - - EINVAL for invalid arguments - -Prototype: struct dlist *sysfs_get_class_devices(struct sysfs_class *cls) -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -Name: sysfs_open_class_device - -Description: Given the name of the class on which to look for, this function - locates a given class device and returns a sysfs_class_device - structure corresponding to the requested class device. - - NOTE: - 1. The sysfs_class_device structure obtained upon successful - return from this function has to be closed by calling - sysfs_close_class_device(). - 2. Class this device belongs to must be known prior to calling - this function. - -Arguments: const char *classname Class on which to search - char *name Class device "name" to open - -Returns: struct sysfs_class_device * with success - NULL with error. Errno will be set with error, returning - - EINVAL for invalid arguments - -Prototype: struct sysfs_class_device *sysfs_open_class_device - (const char *classname, char *name) -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -Name: sysfs_get_classdev_device - -Description: Function returns the sysfs_device reference (if present) for the - given class device. - -Arguments: struct sysfs_class_device *clsdev Class device whose - sysfs_device reference - is required - -Returns: struct sysfs_device * on success - NULL with error. Errno will be set with error, returning - - EINVAL for invalid arguments - -Prototype: struct sysfs_device *sysfs_get_classdev_device - (struct sysfs_class_device *clsdev) -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -Name: sysfs_get_classdev_driver - -Description: Function returns the sysfs_driver reference (if present) for - the given class device. - -Arguments: struct sysfs_class_device *clsdev Class device whose - sysfs_driver reference - is required - -Returns: struct sysfs_driver * on success - NULL with error. Errno will be set with error, returning - - EINVAL for invalid arguments - -Prototype: struct sysfs_driver *sysfs_get_classdev_driver - (struct sysfs_class_device *clsdev) -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -Name: sysfs_get_classdev_parent - -Description: Function returns the sysfs_class_device reference for the - parent (if present) of the given class device. - -Arguments: struct sysfs_class_device *clsdev Class device whose - parent reference - is required - -Returns: struct sysfs_class_device * on success - NULL with error. Errno will be set with error, returning - - EINVAL for invalid arguments - -Prototype: struct sysfs_class_device *sysfs_get_classdev_parent - (struct sysfs_class_device *clsdev) -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -Name: sysfs_get_classdev_attributes - -Description: Function takes a sysfs_class_device structure and returns a - list of attributes for the class device. - -Arguments: struct sysfs_class_device *cdev Class device for which - attributes are required - -Returns: struct dlist * of attributes with success - NULL with error. Errno will be set with error, returning - - EINVAL for invalid arguments - -Prototype: struct dlist *sysfs_get_classdev_attributes - (struct sysfs_class_device *cdev) -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -Name: sysfs_get_classdev_attr - -Description: Searches supplied class device's attributes by name and returns - the attribute. - -Arguments: struct sysfs_class_device *clsdev Device to search - const char *name Attribute name to find - -Returns: struct sysfs_attribute * with success - NULL with error. Errno will be set with error, returning - - EINVAL for invalid arguments - -Prototype: struct sysfs_attribute *sysfs_get_classdev_attr - (struct sysfs_class_device *clsdev, const char *name) -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -Name: sysfs_refresh_classdev_attributes - -Description: Function refreshes the list of attributes for a given - sysfs_class_device. - -Arguments: struct sysfs_class_device *cdev Class device whose attributes - list to refresh - -Returns: struct dlist * of attributes with success - NULL with error. Errno will be set with error, returning - - EINVAL for invalid arguments - -Prototype: struct dlist *sysfs_get_classdev_attributes - (struct sysfs_class_device *cdev) -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -Name: sysfs_open_classdev_attr - -Description: Function takes as arguments, a the name of the class, the class - device name and the name of the required attribute. - - NOTE: - 1. The struct sysfs_attribute * obtained upon successful - return from this function has to be closed by making - a call to sysfs_close_attribute() - -Arguments: char *classname Class name on which to search - char *dev Name of the class device - char *attrib Attribute to open - -Returns: struct sysfs_attribute * with success. - NULL with error. Errno will be set with error, returning - - EINVAL for invalid arguments - -Prototype: struct sysfs_attribute *sysfs_write_classdev_attr - (const char *classname, const char *dev, - const char *attrib) -------------------------------------------------------------------------------- - - -6.6 Device Functions --------------------- - -Devices represent everything in sysfs under /sys/devices, which is a -hierarchical view of system devices. Besides the expected open and -close functions, libsysfs provides open and close functions for -root devices. These functions recursively open or close a device -and all of its children. - -------------------------------------------------------------------------------- -Name: sysfs_open_device_path - -Description: Opens up a device at a specific path. It opens the device's - directory, reads the directory, and returns a sysfs_device - structure. - -Arguments: const char *path Path to device - -Returns: struct sysfs_device * with success - NULL with error. Errno will be set with error, returning - - EINVAL for invalid arguments - -Prototype: struct sysfs_device *sysfs_open_device_path(const char *path) -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -Name: sysfs_close_device - -Description: Function closes up the sysfs_device structure. - -Arguments: sysfs_device *dev Device structure to close - -Prototype: void sysfs_close_device(struct sysfs_device *dev) -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -Name: sysfs_open_root_device - -Description: Function opens up one of the root devices represented in sysfs - in the /sys/devices directory. It returns a sysfs_root_device - structure that includes a list of devices in the tree. - -Arguments: const char *name Name of the root device to open - -Returns: struct sysfs_root_device * with success - NULL with error. Errno will be set with error, returning - - EINVAL for invalid arguments - -Prototype: struct sysfs_device *sysfs_open_root_device(const char *name) -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -Name: sysfs_close_root_device - -Description: Function closes up the sysfs_root_device structure including the - devices in the root device tree. - -Arguments: sysfs_device *root Root device structure to close - -Prototype: void sysfs_close_root_device(struct sysfs_root_device *root) -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -Name: sysfs_open_device_tree - -Description: Function opens up the device tree at the specified path. - -Arguments: const char *path Path at which to open the device tree - -Returns: struct sysfs_device * with success - NULL with error, Errno will be set with error, returning - - EINVAL for invalid arguments - -Prototype: struct sysfs_device *sysfs_open_device_tree(const char *path) -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -Name: sysfs_close_device_tree - -Description: Function closes the device tree originating at the given - sysfs_device. - -Arguments: struct sysfs_device *devroot Device from which the device - tree has to be closed - -Prototype: void sysfs_close_device_tree(struct sysfs_device *devroot) -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -Name: sysfs_get_device_parent - -Description: Function returns the sysfs_device reference for the parent - (if present) of the given sysfs_device. - -Arguments: struct sysfs_device *dev sysfs_device whose parent - reference is required - -Returns: struct sysfs_device * on success - NULL with error. Errno will be set with error, returning - - EINVAL for invalid arguments - -Prototype: struct sysfs_device *sysfs_get_device_parent - (struct sysfs_device *dev) -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -Name: sysfs_get_root_devices - -Description: Function returns a list of devices under the given root device. - -Arguments: struct sysfs_root_device *root sysfs_root_device whose devices - list is required - -Returns: struct dlist * of sysfs_devices on success - NULL with error. Errno will be set with error, returning - - EINVAL for invalid arguments - -Prototype: struct dlist *sysfs_get_root_devices - (struct sysfs_root_device *root) -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -Name: sysfs_get_device_attr - -Description: Searches supplied device's attributes by name and returns - the attribute. - -Arguments: struct sysfs_device *dev Device to search - const char *name Attribute name to find - -Returns: struct sysfs_attribute * with success - NULL with error. Errno will be set with error, returning - - EINVAL for invalid arguments - -Prototype: struct sysfs_attribute *sysfs_get_device_attr - (struct sysfs_device *dev, const char *name) -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -Name: sysfs_get_device_attributes - -Description: Function takes a sysfs_device structure and returns a list - of attributes for the device. - -Arguments: struct sysfs_device *device Device for which - attributes are required - -Returns: struct dlist * of attributes with success - NULL with error. Errno will be set with error, returning - - EINVAL for invalid arguments - -Prototype: struct dlist *sysfs_get_device_attributes - (struct sysfs_device *device) -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -Name: sysfs_refresh_device_attributes - -Description: Function refreshes the list of attributes for a given - sysfs_device. - -Arguments: struct sysfs_device *device Device whose attributes list - to refresh - -Returns: struct dlist * of attributes with success - NULL with error. Errno will be set with error, returning - - EINVAL for invalid arguments - -Prototype: struct dlist *sysfs_refresh_device_attributes - (struct sysfs_device *device) -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -Name: sysfs_open_device - -Description: Given the name of the bus on which to look for, this function - locates a given device and returns a sysfs_device structure - corresponding to the requested device. - -Arguments: const char *bus Bus on which to search - const char *bus_id Device to look for - -Returns: struct sysfs_device * with success - NULL with error. Errno will be set with error, returning - - EINVAL for invalid arguments - -Prototype: struct sysfs_device *sysfs_open_device - (const char *bus, const char *bus_id) -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -Name: sysfs_get_device_bus - -Description: Given a sysfs_device, this function fills in the bus this - device is on in the sysfs_device->bus field. - -Arguments: struct sysfs_device *dev Device whose bus name to find - -Returns: 0 with success. - -1 with error. Errno will be set with error, returning - - EINVAL for invalid arguments - -Prototype: int sysfs_get_device_bus(struct sysfs_device *dev) -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -Name: sysfs_open_device_attr - -Description: Function takes as arguments, the bus on which to search for a - device, and an attribute of the device to open. - - NOTE: - 1. The struct sysfs_attribute * obtained upon successful - return from this function has to be closed by making - a call to sysfs_close_attribute() - -Arguments: char *bus Bus on which to search - char *bus_id Device to look for - char *attrib Name of the attribute to open - -Returns: struct sysfs_attribute * with success. - NULL with error. Errno will be set with error, returning - - EINVAL for invalid arguments - -Prototype: struct sysfs_attribute *sysfs_open_device_attr - (const char *bus, const char *bus_id, const char *attrib) -------------------------------------------------------------------------------- - - -6.7 Driver Functions --------------------- - -Drivers are represented in sysfs under the /sys/bus/xxx/drivers (xxx being -the bus type, such as "pci", "usb, and so on). Functions are provided to -open and close drivers. - -------------------------------------------------------------------------------- -Name: sysfs_open_driver_path - -Description: Opens driver at specific path. - -Arguments: const char *path Path to driver - -Returns: struct sysfs_driver * with success - NULL with error. Errno will be set with error, returning - - EINVAL for invalid arguments - -Prototype: struct sysfs_driver *sysfs_open_driver_path(const char *path) -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -Name: sysfs_close_driver - -Description: Closes and cleans up sysfs_driver structure. - -Arguments: sysfs_driver *driver Driver structure to close - -Prototype: void sysfs_close_driver(struct sysfs_driver *driver) -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -Name: sysfs_get_driver_devices - -Description: Function returns a list of devices that use this driver. - -Arguments: struct sysfs_driver *driver Driver whose devices list is - required - -Returns: struct dlist * of sysfs_devices on success - NULL with error. Errno will be set with error, returning - - EINVAL for invalid arguments - -Prototype: struct dlist *sysfs_get_driver_devices - (struct sysfs_driver *driver) -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -Name: sysfs_refresh_driver_devices - -Description: Function refreshes the list of devices that use this driver. - -Arguments: struct sysfs_driver *driver Driver whose devices list is - required to be refreshed - -Returns: struct dlist * of sysfs_devices on success - NULL with error. Errno will be set with error, returning - - EINVAL for invalid arguments - -Prototype: struct dlist *sysfs_refresh_driver_devices - (struct sysfs_driver *driver) -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -Name: sysfs_get_driver_device - -Description: Function returns a sysfs_device reference for the device with - "name" that uses this driver - -Arguments: struct sysfs_driver *driver Driver on which to search - const char *name Name of the device to look for - -Returns: struct sysfs_device * corresponding to "name" on success - NULL with error. Errno will be set with error, returning - - EINVAL for invalid arguments - -Prototype: struct dlist *sysfs_get_driver_device - (struct sysfs_driver *driver, const char *name) -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -Name: sysfs_get_driver_attr - -Description: Searches supplied driver's attributes by name and returns - the attribute. - -Arguments: struct sysfs_driver *drv Driver to search - const char *name Attribute name to find - -Returns: struct sysfs_attribute * with success - NULL with error. Errno will be set with error, returning - - EINVAL for invalid arguments - -Prototype: struct sysfs_attribute *sysfs_get_driver_attr - (struct sysfs_driver *drv, const char *name) -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -Name: sysfs_get_driver_attributes - -Description: Function takes a sysfs_driver structure and returns a list - of attributes for the driver. - -Arguments: struct sysfs_driver *driver Driver for which attributes - are required - -Returns: struct dlist * of attributes with success - NULL with error. Errno will be set with error, returning - - EINVAL for invalid arguments - -Prototype: struct dlist *sysfs_get_driver_attributes - (struct sysfs_driver *driver) -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -Name: sysfs_refresh_driver_attributes - -Description: Function refreshes the list of attributes for a given - sysfs_driver. - -Arguments: struct sysfs_driver *driver Driver whose attributes list - to refresh - -Returns: struct dlist * of attributes with success - NULL with error. Errno will be set with error, returning - - EINVAL for invalid arguments - -Prototype: struct dlist *sysfs_refresh_driver_attributes - (struct sysfs_driver *driver) -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -Name: sysfs_open_driver - -Description: Given the name of the bus on which to look for, this function - locates a given driver and returns a sysfs_driver structure - corresponding to the requested device. - - NOTE: - 1. The sysfs_driver structure obtained upon successful return - from this function has to be closed by calling - sysfs_close_driver_by_name(). - 2. Bus on which to look for this driver should be known prior - to calling this function. Use sysfs_find_driver_bus() - to determine this. - -Arguments: const char *bus_name Bus on which to search - const char *drv_name Driver name to look for - -Returns: struct sysfs_driver * with success - NULL with error. Errno will be set with error, returning - - EINVAL for invalid arguments - -Prototype: struct sysfs_driver *sysfs_open_driver(const char *bus_name, - const char *drv_name) -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -Name: sysfs_get_driver_links - -Description: Function returns a list of links for a given driver - -Arguments: struct sysfs_driver *driver Driver to get links from - -Returns: struct dlist * of links on success - NULL with error - -Prototype: struct dlist *sysfs_get_driver_links - (struct sysfs_driver *driver) -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -Name: sysfs_open_driver_attr - -Description: Function takes as arguments, the bus the driver is registered - on, the driver name and the name of the attribute to open. - - NOTE: - 1. The struct sysfs_attribute * obtained upon successful - return from this function has to be closed by making - a call to sysfs_close_attribute() - -Arguments: char *bus Bus on which driver is present - char *drv Driver to look for - char *attrib Name of the attribute to open - -Returns: struct sysfs_attribute * with success. - NULL with error. Errno will be set with error, returning - - EINVAL for invalid arguments - -Prototype: struct sysfs_attribute *sysfs_open_driver_attr - (const char *bus, const char *drv, const char *attrib) -------------------------------------------------------------------------------- - - -7 Dlists --------- - -Libsysfs uses (yet another) list implementation thanks to Eric J Bohm. - - -7.1 Navigating a dlist ----------------------- - -Some library functions return a dlist of devices/drivers/attributes, etc. -To navigate the list returned the macro "dlist_for_each_data" is to be used. - ------------------------------------------------------------------------------- -Function/Macro name: dlist_for_each_data - -Description: Walk the given list, returning a known data type/ - structure in each iteration. - -Arguments: struct dlist *list List pointer - data_iterator Data type/structure variable - contained in the list - datatype Data type/structure contained - in the list - -Returns: On each iteration, "data_iterator" will contain a list - element of "datatype" - -Usage example: The function sysfs_get_classdev_attributes() returns a - dlist of attributes. To navigate the list: - - struct sysfs_attribute *attr = NULL; - struct dlist *attrlist = NULL; - . - . - . - attrlist = sysfs_get_classdev_attributes - (struct sysfs_class_device *cdev) - if (attrlist != NULL) { - dlist_for_each_data(attrlist, attr, - struct sysfs_attribute) { - . - . - . - } - } -------------------------------------------------------------------------------- - - -7.2 Custom sorting using dlist_sort_custom() --------------------------------------------- - -As of release 1.2.0, libsysfs provides a new interface for custom sorting -of dlists. The API dlist_sort_custom() has been added for this purpose. -Applications that would like to define their own sorter function can now -make use of this API. - -The sorter function must conform to the following prototype: - - int compare(void *a, void*b) - -dlist_sort_custom() expects that the compare function will: - return >0 for a before b - return <0 for b before a - return 0 for a == b - - -8. Usage --------- - -Accessing devices through libsysfs is supposed to mirror accessing devices -in the filesystem it represents. Here's a typical order of operation: - - - get sysfs mount point - - "open" sysfs category, ie. bus, class, or device - - work with category - - "close" sysfs category - - -9. Testsuite ------------- - -Version 1.0.0 of sysfsutils ships with a comprehensive testsuite. The testsuite -shipped as part of the "test" directory of the sysfsutils source package, -results in an executable "testlibsysfs" which will be installed in the -/usr/local/bin directory. Some of the salient features of the testsuite are: - -a. Tests _every_ API exported by the library. -b. Tests are performed for all possible combinations of input parameters. -c. Detailed output is provided for the correct case. -d. Facility to redirect output of the tests to a normal file. -e. Number of iterations of tests can be specified. - -The testsuite comes with its own configuration file "libsysfs.conf" in the -"test" directory. This file is used to generate a header file at the time -the tests are built. - -To use the testsuite: - -a. Modify the variables libsysfs.conf file to appropriate values for your - system. (The libsysfs.conf file contains comments describing what each - variable stands for and, in some cases, how to determine an appropriate - value for the system under test). - -b. Build and install the testsuite. - -c. Run the testsuite: - - testlibsysfs - -The default logfile is stdout. - -NOTE: If the libsysfs.conf file is changed, make sure to run "make clean" in -the test directory and then a "make" for the changes to take effect. - - -10. Conclusion --------------- - -Libsysfs is meant to provide a stable application programming interface to -sysfs. Applications can depend upon the library to access system devices -and functions exposed through sysfs. diff --git a/libsysfs/sysfs.h b/libsysfs/sysfs.h deleted file mode 100644 index 2add8227a4..0000000000 --- a/libsysfs/sysfs.h +++ /dev/null @@ -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 -#include -#include -#include -#include -#include -#include -#include -#include - -#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_ */ diff --git a/libsysfs/sysfs/dlist.h b/libsysfs/sysfs/dlist.h deleted file mode 100644 index 335a490a0a..0000000000 --- a/libsysfs/sysfs/dlist.h +++ /dev/null @@ -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 - -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_ */ diff --git a/libsysfs/sysfs/libsysfs.h b/libsysfs/sysfs/libsysfs.h deleted file mode 100644 index 12e7cc5f99..0000000000 --- a/libsysfs/sysfs/libsysfs.h +++ /dev/null @@ -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 -#include -#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_ */ diff --git a/libsysfs/sysfs_bus.c b/libsysfs/sysfs_bus.c deleted file mode 100644 index 921ef32094..0000000000 --- a/libsysfs/sysfs_bus.c +++ /dev/null @@ -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; -} - diff --git a/libsysfs/sysfs_class.c b/libsysfs/sysfs_class.c deleted file mode 100644 index 102f09f17a..0000000000 --- a/libsysfs/sysfs_class.c +++ /dev/null @@ -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; -} diff --git a/libsysfs/sysfs_device.c b/libsysfs/sysfs_device.c deleted file mode 100644 index e3d70143f9..0000000000 --- a/libsysfs/sysfs_device.c +++ /dev/null @@ -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); -} diff --git a/libsysfs/sysfs_dir.c b/libsysfs/sysfs_dir.c deleted file mode 100644 index 7d98c669c6..0000000000 --- a/libsysfs/sysfs_dir.c +++ /dev/null @@ -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; -} diff --git a/libsysfs/sysfs_driver.c b/libsysfs/sysfs_driver.c deleted file mode 100644 index c2464faa9e..0000000000 --- a/libsysfs/sysfs_driver.c +++ /dev/null @@ -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; -} diff --git a/libsysfs/sysfs_utils.c b/libsysfs/sysfs_utils.c deleted file mode 100644 index c5558a43a1..0000000000 --- a/libsysfs/sysfs_utils.c +++ /dev/null @@ -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; -} diff --git a/test/simple-build-check.sh b/test/simple-build-check.sh index d1c28749fb..faa7c46432 100755 --- a/test/simple-build-check.sh +++ b/test/simple-build-check.sh @@ -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 diff --git a/test/udev-test.pl b/test/udev-test.pl index c33c79b1c0..7ce920092f 100755 --- a/test/udev-test.pl +++ b/test/udev-test.pl @@ -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 => < "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 => < "program result substitution", subsys => "block", devpath => "/block/sda/sda3", - exp_name => "test-0:0:0:0" , + exp_name => "test-3" , rules => < "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 => < "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 => < "test substitution by variable name 3", subsys => "block", devpath => "/block/sda/sda3", - exp_name => "830:0:0:03" , + exp_name => "83sda33" , rules => < "test substitution by variable name 5", subsys => "block", devpath => "/block/sda/sda3", - exp_name => "8330:0:0:0" , + exp_name => "833sda3" , rules => < "program and bus type match", subsys => "block", devpath => "/block/sda", - exp_name => "scsi-0:0:0:0" , + exp_name => "scsi-sda" , rules => < "symlink2-ttyUSB0", exp_target => "ttyUSB0", rules => < "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 => <; + 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; diff --git a/udev.c b/udev.c index f2d6f6653c..4762ab1cef 100644 --- a/udev.c +++ b/udev.c @@ -30,13 +30,8 @@ #include #include -#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; + } + + 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)) { + 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(); diff --git a/udev.h b/udev.h index ca99da512d..c060b8d6ff 100644 --- a/udev.h +++ b/udev.h @@ -24,8 +24,11 @@ #include #include -#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); +/* 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 diff --git a/udev_add.c b/udev_add.c index bf2d59d198..2c66a0ba8d 100644 --- a/udev_add.c +++ b/udev_add.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -29,16 +30,10 @@ #include #include #include -#include #include #include -#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); } } diff --git a/udev_config.c b/udev_config.c index c1af7c12ca..a7e19fe864 100644 --- a/udev_config.c +++ b/udev_config.c @@ -28,15 +28,9 @@ #include #include -#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); diff --git a/udev_db.c b/udev_db.c index 6b9d5e8426..e9ae799132 100644 --- a/udev_db.c +++ b/udev_db.c @@ -30,11 +30,7 @@ #include #include -#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; diff --git a/udev_device.c b/udev_device.c index 7821c91cb4..0325001428 100644 --- a/udev_device.c +++ b/udev_device.c @@ -26,83 +26,99 @@ #include #include #include -#include -#include -#include -#include -#include -#include - -#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)); - - if (action) - strlcpy(udev->action, action, sizeof(udev->action)); - - 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); - } - } + /* set sysfs device to local storage, can be overridden if needed */ + udev->dev = &udev->dev_local; - if (udev->type == DEV_BLOCK || udev->type == DEV_CLASS) { - udev->mode = 0660; - strcpy(udev->owner, "root"); - strcpy(udev->group, "root"); - } + /* default node permissions */ + 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; } diff --git a/udev_event.c b/udev_event.c deleted file mode 100644 index 887537e0e9..0000000000 --- a/udev_event.c +++ /dev/null @@ -1,161 +0,0 @@ -/* - * udev_event.c - udev event process - * - * Copyright (C) 2004, 2005 Kay Sievers - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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; -} diff --git a/udev_libc_wrapper.c b/udev_libc_wrapper.c index fe38993cd7..02a1f8d016 100644 --- a/udev_libc_wrapper.c +++ b/udev_libc_wrapper.c @@ -27,10 +27,7 @@ #include #include -#include "udev_libc_wrapper.h" #include "udev.h" -#include "udev_utils.h" -#include "logging.h" #ifdef __KLIBC__ #define __OWN_USERDB_PARSER__ diff --git a/udev_remove.c b/udev_remove.c index f9592b4c70..945618ce5a 100644 --- a/udev_remove.c +++ b/udev_remove.c @@ -28,11 +28,7 @@ #include #include -#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); diff --git a/udev_rules.c b/udev_rules.c index 492a9b0dfc..8693b71c08 100644 --- a/udev_rules.c +++ b/udev_rules.c @@ -31,13 +31,7 @@ #include #include -#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; - - 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) + } else { + struct sysfs_device *dev_parent; + const char *value; + + 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; - - 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); + { + struct sysfs_device *dev_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) diff --git a/udev_rules.h b/udev_rules.h index 6d9d306ded..125babf1c5 100644 --- a/udev_rules.h +++ b/udev_rules.h @@ -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 diff --git a/udev_rules_parse.c b/udev_rules_parse.c index 7fa21afa8c..4fcd6db08e 100644 --- a/udev_rules_parse.c +++ b/udev_rules_parse.c @@ -28,10 +28,7 @@ #include #include -#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); diff --git a/udev_selinux.c b/udev_selinux.c index 298c75566c..94c213d297 100644 --- a/udev_selinux.c +++ b/udev_selinux.c @@ -32,7 +32,6 @@ #include "udev.h" #include "udev_selinux.h" -#include "logging.h" static security_context_t prev_scontext = NULL; diff --git a/udev_sysfs.c b/udev_sysfs.c new file mode 100644 index 0000000000..19fd614e63 --- /dev/null +++ b/udev_sysfs.c @@ -0,0 +1,345 @@ +/* + * udev_sysfs.c - sysfs access + * + * Copyright (C) 2005 Kay Sievers + * + * 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 +#include +#include +#include +#include +#include +#include + +#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; +} diff --git a/udev_utils.c b/udev_utils.c index 581ba9e80a..a37c4dfe74 100644 --- a/udev_utils.c +++ b/udev_utils.c @@ -30,11 +30,7 @@ #include #include -#include "udev_libc_wrapper.h" #include "udev.h" -#include "logging.h" -#include "udev_utils.h" -#include "list.h" int log_priority(const char *priority) diff --git a/udev_utils.h b/udev_utils.h deleted file mode 100644 index a28ba005ca..0000000000 --- a/udev_utils.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * udev_utils.c - generic stuff used by udev - * - * Copyright (C) 2004-2005 Kay Sievers - * - * 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 diff --git a/udev_utils_file.c b/udev_utils_file.c index cd9c244f0f..acaffdc918 100644 --- a/udev_utils_file.c +++ b/udev_utils_file.c @@ -30,11 +30,7 @@ #include #include -#include "udev_libc_wrapper.h" #include "udev.h" -#include "logging.h" -#include "udev_utils.h" -#include "list.h" int create_path(const char *path) { diff --git a/udev_utils_run.c b/udev_utils_run.c index e1e775ebe6..b6020b0ab6 100644 --- a/udev_utils_run.c +++ b/udev_utils_run.c @@ -31,11 +31,7 @@ #include #include -#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) diff --git a/udev_utils_string.c b/udev_utils_string.c index 37db8dbc85..36ef8bef7e 100644 --- a/udev_utils_string.c +++ b/udev_utils_string.c @@ -30,11 +30,7 @@ #include #include -#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) diff --git a/udevcontrol.c b/udevcontrol.c index bd6563531d..6d91adc1c4 100644 --- a/udevcontrol.c +++ b/udevcontrol.c @@ -32,10 +32,7 @@ #include #include "udev.h" -#include "udev_version.h" #include "udevd.h" -#include "udev_utils.h" -#include "logging.h" /* global variables */ static int sock = -1; diff --git a/udevd.c b/udevd.c index ff61c656c8..f64a4252bb 100644 --- a/udevd.c +++ b/udevd.c @@ -42,16 +42,11 @@ #include #include -#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]); diff --git a/udevd.h b/udevd.h index afbc3a31b1..c0a32e97ed 100644 --- a/udevd.h +++ b/udevd.h @@ -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 diff --git a/udevinfo.c b/udevinfo.c index 8ff09da3d1..f8d0b6125a 100644 --- a/udevinfo.c +++ b/udevinfo.c @@ -21,17 +21,14 @@ #include #include #include +#include #include #include #include +#include #include -#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,125 +45,98 @@ 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; - - 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; - } + char path[PATH_SIZE]; + DIR *dir; + struct dirent *dent; + + strlcpy(path, sysfs_path, sizeof(path)); + strlcat(path, devpath, sizeof(path)); + + 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; + } - /* 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; + 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 void print_record(struct udevice *udev) +static int print_device_chain(const char *devpath) { - struct name_entry *name_loop; + struct sysfs_device *dev; - printf("P: %s\n", udev->devpath); - printf("N: %s\n", udev->name); - list_for_each_entry(name_loop, &udev->symlink_list, node) - printf("S: %s\n", name_loop->name); - list_for_each_entry(name_loop, &udev->env_list, node) - 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" + 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"); - /* 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); + dev = sysfs_device_get(devpath); + if (dev == NULL) + return -1; - 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"); + 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); - sysfs_dev = sysfs_get_device_parent(sysfs_dev); - if (sysfs_dev == NULL) + /* 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); } -exit: - sysfs_close_class_device(class_dev); - return retval; + return 0; +} + +static void print_record(struct udevice *udev) +{ + struct name_entry *name_loop; + + 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); + list_for_each_entry(name_loop, &udev->env_list, node) + printf("E: %s\n", name_loop->name); } 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; } diff --git a/udevmonitor.c b/udevmonitor.c index 7d3f0aa538..80c49753f5 100644 --- a/udevmonitor.c +++ b/udevmonitor.c @@ -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; diff --git a/udevsend.c b/udevsend.c index b67df9720b..1b9860baca 100644 --- a/udevsend.c +++ b/udevsend.c @@ -33,9 +33,7 @@ #include #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); diff --git a/udevstart.c b/udevstart.c index a9959c5d6b..8c414f1acb 100644 --- a/udevstart.c +++ b/udevstart.c @@ -38,14 +38,8 @@ #include #include -#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_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"); + 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_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; } diff --git a/udevtest.8 b/udevtest.8 index e547811a8b..ea0ea59238 100644 --- a/udevtest.8 +++ b/udevtest.8 @@ -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. diff --git a/udevtest.c b/udevtest.c index 1be3fa9515..22fd3735c2 100644 --- a/udevtest.c +++ b/udevtest.c @@ -21,17 +21,15 @@ #include #include #include +#include +#include #include #include #include #include -#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 "); + if (argc != 2) { + info("Usage: udevtest "); 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"); + dev = sysfs_device_get(devpath); + if (dev == NULL) { + info("unable to open '%s'", devpath); + rc = 2; + goto exit; + } - /* 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; + udev = udev_device_init(); + if (udev == NULL) { + info("can't open device"); + rc = 3; + 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); + /* 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); - - return 0; + udev->test_run = 1; + + 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; } -- cgit v1.2.3-54-g00ecf