From fc8d61c53d6c181dc1e9f5a23c0f805c32a392af Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Wed, 17 Mar 2010 17:42:35 +0100 Subject: [PATCH] libudev: add udev_device_new_from_environment() --- extras/usb_id/usb_id.c | 34 +++-- libudev/docs/libudev-sections.txt | 1 + libudev/exported_symbols | 1 + libudev/libudev-device.c | 214 ++++++++++++++++++++++-------- libudev/libudev-monitor.c | 66 +-------- libudev/libudev-private.h | 3 +- libudev/libudev.h | 1 + 7 files changed, 192 insertions(+), 128 deletions(-) diff --git a/extras/usb_id/usb_id.c b/extras/usb_id/usb_id.c index b412598d..42ccddff 100644 --- a/extras/usb_id/usb_id.c +++ b/extras/usb_id/usb_id.c @@ -456,8 +456,6 @@ int main(int argc, char **argv) }; struct udev *udev; struct udev_device *dev = NULL; - char syspath[UTIL_PATH_SIZE]; - const char *devpath; static int export; int retval = 0; @@ -492,7 +490,7 @@ int main(int argc, char **argv) export = 1; break; case 'h': - printf("Usage: usb_id [--usb-info] [--num-info] [--export] [--help] \n" + printf("Usage: usb_id [--usb-info] [--num-info] [--export] [--help] []\n" " --usb-info use usb strings instead\n" " --num-info use numerical values\n" " --export print values as environment keys\n" @@ -503,18 +501,26 @@ int main(int argc, char **argv) } } - devpath = argv[optind]; - if (devpath == NULL) { - fprintf(stderr, "No device specified\n"); - retval = 1; - goto exit; - } - - util_strscpyl(syspath, sizeof(syspath), udev_get_sys_path(udev), devpath, NULL); - dev = udev_device_new_from_syspath(udev, syspath); + dev = udev_device_new_from_environment(udev); if (dev == NULL) { - err(udev, "unable to access '%s'\n", devpath); - return 1; + char syspath[UTIL_PATH_SIZE]; + const char *devpath; + + devpath = argv[optind]; + if (devpath == NULL) { + fprintf(stderr, "missing device\n"); + retval = 1; + goto exit; + } + + util_strscpyl(syspath, sizeof(syspath), udev_get_sys_path(udev), devpath, NULL); + dev = udev_device_new_from_syspath(udev, syspath); + if (dev == NULL) { + err(udev, "unable to access '%s'\n", devpath); + retval = 1; + goto exit; + return 1; + } } retval = usb_id(dev); diff --git a/libudev/docs/libudev-sections.txt b/libudev/docs/libudev-sections.txt index c11a2735..ca781fff 100644 --- a/libudev/docs/libudev-sections.txt +++ b/libudev/docs/libudev-sections.txt @@ -35,6 +35,7 @@ udev_device_get_udev udev_device_new_from_syspath udev_device_new_from_devnum udev_device_new_from_subsystem_sysname +udev_device_new_from_environment udev_device_get_parent udev_device_get_parent_with_subsystem_devtype udev_device_get_devpath diff --git a/libudev/exported_symbols b/libudev/exported_symbols index f48025a4..61486c6f 100644 --- a/libudev/exported_symbols +++ b/libudev/exported_symbols @@ -15,6 +15,7 @@ udev_list_entry_get_value udev_device_new_from_syspath udev_device_new_from_devnum udev_device_new_from_subsystem_sysname +udev_device_new_from_environment udev_device_get_parent udev_device_get_parent_with_subsystem_devtype udev_device_ref diff --git a/libudev/libudev-device.c b/libudev/libudev-device.c index aec5fb57..fe458801 100644 --- a/libudev/libudev-device.c +++ b/libudev/libudev-device.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -67,6 +68,7 @@ struct udev_device { int refcount; dev_t devnum; int watch_handle; + int maj, min; unsigned int parent_set:1; unsigned int subsystem_set:1; unsigned int devtype_set:1; @@ -77,6 +79,130 @@ struct udev_device { unsigned int ignore_remove:1; }; +struct udev_list_entry *udev_device_add_property(struct udev_device *udev_device, const char *key, const char *value) +{ + udev_device->envp_uptodate = 0; + if (value == NULL) { + struct udev_list_entry *list_entry; + + list_entry = udev_device_get_properties_list_entry(udev_device); + list_entry = udev_list_entry_get_by_name(list_entry, key); + if (list_entry != NULL) + udev_list_entry_delete(list_entry); + return NULL; + } + return udev_list_entry_add(udev_device->udev, &udev_device->properties_list, key, value, 1, 0); +} + +static struct udev_list_entry *udev_device_add_property_from_string(struct udev_device *udev_device, const char *property) +{ + char name[UTIL_LINE_SIZE]; + char *val; + + util_strscpy(name, sizeof(name), property); + val = strchr(name, '='); + if (val == NULL) + return NULL; + val[0] = '\0'; + val = &val[1]; + if (val[0] == '\0') + val = NULL; + return udev_device_add_property(udev_device, name, val); +} + +/* + * parse property string, and if needed, update internal values accordingly + * + * udev_device_add_property_from_string_parse_finish() needs to be + * called after adding properties, and its return value checked + * + * udev_device_set_info_loaded() needs to be set, to avoid trying + * to use a device without a DEVPATH set + */ +void udev_device_add_property_from_string_parse(struct udev_device *udev_device, const char *property) +{ + if (strncmp(property, "DEVPATH=", 8) == 0) { + char path[UTIL_PATH_SIZE]; + + util_strscpyl(path, sizeof(path), udev_get_sys_path(udev_device->udev), &property[8], NULL); + udev_device_set_syspath(udev_device, path); + } else if (strncmp(property, "SUBSYSTEM=", 10) == 0) { + udev_device_set_subsystem(udev_device, &property[10]); + } else if (strncmp(property, "DEVTYPE=", 8) == 0) { + udev_device_set_devtype(udev_device, &property[8]); + } else if (strncmp(property, "DEVNAME=", 8) == 0) { + if (property[8] == '/') + udev_device_set_devnode(udev_device, &property[8]); + else + udev_device_set_knodename(udev_device, &property[8]); + } else if (strncmp(property, "DEVLINKS=", 9) == 0) { + char devlinks[UTIL_PATH_SIZE]; + char *slink; + char *next; + + util_strscpy(devlinks, sizeof(devlinks), &property[9]); + slink = devlinks; + next = strchr(slink, ' '); + while (next != NULL) { + next[0] = '\0'; + udev_device_add_devlink(udev_device, slink, 0); + slink = &next[1]; + next = strchr(slink, ' '); + } + if (slink[0] != '\0') + udev_device_add_devlink(udev_device, slink, 0); + } else if (strncmp(property, "DRIVER=", 7) == 0) { + udev_device_set_driver(udev_device, &property[7]); + } else if (strncmp(property, "ACTION=", 7) == 0) { + udev_device_set_action(udev_device, &property[7]); + } else if (strncmp(property, "MAJOR=", 6) == 0) { + udev_device->maj = strtoull(&property[6], NULL, 10); + } else if (strncmp(property, "MINOR=", 6) == 0) { + udev_device->min = strtoull(&property[6], NULL, 10); + } else if (strncmp(property, "DEVPATH_OLD=", 12) == 0) { + udev_device_set_devpath_old(udev_device, &property[12]); + } else if (strncmp(property, "SEQNUM=", 7) == 0) { + udev_device_set_seqnum(udev_device, strtoull(&property[7], NULL, 10)); + } else if (strncmp(property, "TIMEOUT=", 8) == 0) { + udev_device_set_timeout(udev_device, strtoull(&property[8], NULL, 10)); + } else { + udev_device_add_property_from_string(udev_device, property); + } +} + +int udev_device_add_property_from_string_parse_finish(struct udev_device *udev_device) +{ + if (udev_device->maj > 0) + udev_device_set_devnum(udev_device, makedev(udev_device->maj, udev_device->min)); + udev_device->maj = 0; + udev_device->min = 0; + + if (udev_device->devpath == NULL || udev_device->subsystem == NULL) + return -EINVAL; + return 0; +} + +/** + * udev_device_get_property_value: + * @udev_device: udev device + * @key: property name + * + * Returns: the value of a device property, or #NULL if there is no such property. + **/ +const char *udev_device_get_property_value(struct udev_device *udev_device, const char *key) +{ + struct udev_list_entry *list_entry; + + if (udev_device == NULL) + return NULL; + if (key == NULL) + return NULL; + + list_entry = udev_device_get_properties_list_entry(udev_device); + list_entry = udev_list_entry_get_by_name(list_entry, key); + return udev_list_entry_get_value(list_entry); +} + int udev_device_read_db(struct udev_device *udev_device) { struct stat stats; @@ -451,6 +577,42 @@ found: return udev_device_new_from_syspath(udev, path_full); } +/** + * udev_device_new_from_environment + * @udev: udev library context + * + * Create new udev device, and fill in information from the + * current process environment. This only works reliable if + * the process is called from a udev rule. It is usually used + * for tools executed from IMPORT= rules. + * + * The initial refcount is 1, and needs to be decremented to + * release the resources of the udev device. + * + * Returns: a new udev device, or #NULL, if it does not exist + **/ +struct udev_device *udev_device_new_from_environment(struct udev *udev) +{ + int i; + struct udev_device *udev_device; + + udev_device = udev_device_new(udev); + if (udev_device == NULL) + return NULL; + udev_device_set_info_loaded(udev_device); + + for (i = 0; environ[i] != NULL; i++) + udev_device_add_property_from_string_parse(udev_device, environ[i]); + + if (udev_device_add_property_from_string_parse_finish(udev_device) < 0) { + info(udev, "missing values, invalid device\n"); + udev_device_unref(udev_device); + udev_device = NULL; + } + + return udev_device; +} + static struct udev_device *device_new_from_parent(struct udev_device *udev_device) { struct udev_device *udev_device_parent = NULL; @@ -1072,58 +1234,6 @@ int udev_device_add_devlink(struct udev_device *udev_device, const char *devlink return 0; } -struct udev_list_entry *udev_device_add_property(struct udev_device *udev_device, const char *key, const char *value) -{ - udev_device->envp_uptodate = 0; - if (value == NULL) { - struct udev_list_entry *list_entry; - - list_entry = udev_device_get_properties_list_entry(udev_device); - list_entry = udev_list_entry_get_by_name(list_entry, key); - if (list_entry != NULL) - udev_list_entry_delete(list_entry); - return NULL; - } - return udev_list_entry_add(udev_device->udev, &udev_device->properties_list, key, value, 1, 0); -} - -struct udev_list_entry *udev_device_add_property_from_string(struct udev_device *udev_device, const char *property) -{ - char name[UTIL_LINE_SIZE]; - char *val; - - util_strscpy(name, sizeof(name), property); - val = strchr(name, '='); - if (val == NULL) - return NULL; - val[0] = '\0'; - val = &val[1]; - if (val[0] == '\0') - val = NULL; - return udev_device_add_property(udev_device, name, val); -} - -/** - * udev_device_get_property_value: - * @udev_device: udev device - * @key: property name - * - * Returns: the value of a device property, or #NULL if there is no such property. - **/ -const char *udev_device_get_property_value(struct udev_device *udev_device, const char *key) -{ - struct udev_list_entry *list_entry; - - if (udev_device == NULL) - return NULL; - if (key == NULL) - return NULL; - - list_entry = udev_device_get_properties_list_entry(udev_device); - list_entry = udev_list_entry_get_by_name(list_entry, key); - return udev_list_entry_get_value(list_entry); -} - #define ENVP_SIZE 128 #define MONITOR_BUF_SIZE 4096 static int update_envp_monitor_buf(struct udev_device *udev_device) diff --git a/libudev/libudev-monitor.c b/libudev/libudev-monitor.c index 96c153fb..97e52c42 100644 --- a/libudev/libudev-monitor.c +++ b/libudev/libudev-monitor.c @@ -497,11 +497,6 @@ struct udev_device *udev_monitor_receive_device(struct udev_monitor *udev_monito ssize_t buflen; ssize_t bufpos; struct udev_monitor_netlink_header *nlh; - int devpath_set = 0; - int subsystem_set = 0; - int action_set = 0; - int maj = 0; - int min = 0; retry: if (udev_monitor == NULL) @@ -589,6 +584,7 @@ retry: udev_device = udev_device_new(udev_monitor->udev); if (udev_device == NULL) return NULL; + udev_device_set_info_loaded(udev_device); while (bufpos < buflen) { char *key; @@ -599,60 +595,11 @@ retry: if (keylen == 0) break; bufpos += keylen + 1; - - if (strncmp(key, "DEVPATH=", 8) == 0) { - char path[UTIL_PATH_SIZE]; - - util_strscpyl(path, sizeof(path), udev_get_sys_path(udev_monitor->udev), &key[8], NULL); - udev_device_set_syspath(udev_device, path); - devpath_set = 1; - } else if (strncmp(key, "SUBSYSTEM=", 10) == 0) { - udev_device_set_subsystem(udev_device, &key[10]); - subsystem_set = 1; - } else if (strncmp(key, "DEVTYPE=", 8) == 0) { - udev_device_set_devtype(udev_device, &key[8]); - } else if (strncmp(key, "DEVNAME=", 8) == 0) { - if (key[8] == '/') - udev_device_set_devnode(udev_device, &key[8]); - else - udev_device_set_knodename(udev_device, &key[8]); - } else if (strncmp(key, "DEVLINKS=", 9) == 0) { - char devlinks[UTIL_PATH_SIZE]; - char *slink; - char *next; - - util_strscpy(devlinks, sizeof(devlinks), &key[9]); - slink = devlinks; - next = strchr(slink, ' '); - while (next != NULL) { - next[0] = '\0'; - udev_device_add_devlink(udev_device, slink, 0); - slink = &next[1]; - next = strchr(slink, ' '); - } - if (slink[0] != '\0') - udev_device_add_devlink(udev_device, slink, 0); - } else if (strncmp(key, "DRIVER=", 7) == 0) { - udev_device_set_driver(udev_device, &key[7]); - } else if (strncmp(key, "ACTION=", 7) == 0) { - udev_device_set_action(udev_device, &key[7]); - action_set = 1; - } else if (strncmp(key, "MAJOR=", 6) == 0) { - maj = strtoull(&key[6], NULL, 10); - } else if (strncmp(key, "MINOR=", 6) == 0) { - min = strtoull(&key[6], NULL, 10); - } else if (strncmp(key, "DEVPATH_OLD=", 12) == 0) { - udev_device_set_devpath_old(udev_device, &key[12]); - } else if (strncmp(key, "SEQNUM=", 7) == 0) { - udev_device_set_seqnum(udev_device, strtoull(&key[7], NULL, 10)); - } else if (strncmp(key, "TIMEOUT=", 8) == 0) { - udev_device_set_timeout(udev_device, strtoull(&key[8], NULL, 10)); - } else { - udev_device_add_property_from_string(udev_device, key); - } + udev_device_add_property_from_string_parse(udev_device, key); } - if (!devpath_set || !subsystem_set || !action_set) { - info(udev_monitor->udev, "missing values, skip\n"); + + if (udev_device_add_property_from_string_parse_finish(udev_device) < 0) { + info(udev_monitor->udev, "missing values, invalid device\n"); udev_device_unref(udev_device); return NULL; } @@ -673,9 +620,6 @@ retry: return NULL; } - if (maj > 0) - udev_device_set_devnum(udev_device, makedev(maj, min)); - udev_device_set_info_loaded(udev_device); return udev_device; } diff --git a/libudev/libudev-private.h b/libudev/libudev-private.h index 5ee0c58b..3f2861f5 100644 --- a/libudev/libudev-private.h +++ b/libudev/libudev-private.h @@ -71,7 +71,8 @@ int udev_device_set_devnode(struct udev_device *udev_device, const char *devnode int udev_device_add_devlink(struct udev_device *udev_device, const char *devlink, int unique); void udev_device_cleanup_devlinks_list(struct udev_device *udev_device); struct udev_list_entry *udev_device_add_property(struct udev_device *udev_device, const char *key, const char *value); -struct udev_list_entry *udev_device_add_property_from_string(struct udev_device *udev_device, const char *property); +void udev_device_add_property_from_string_parse(struct udev_device *udev_device, const char *property); +int udev_device_add_property_from_string_parse_finish(struct udev_device *udev_device); char **udev_device_get_properties_envp(struct udev_device *udev_device); ssize_t udev_device_get_properties_monitor_buf(struct udev_device *udev_device, const char **buf); int udev_device_read_db(struct udev_device *udev_device); diff --git a/libudev/libudev.h b/libudev/libudev.h index 9576ad49..750664f4 100644 --- a/libudev/libudev.h +++ b/libudev/libudev.h @@ -75,6 +75,7 @@ struct udev *udev_device_get_udev(struct udev_device *udev_device); struct udev_device *udev_device_new_from_syspath(struct udev *udev, const char *syspath); struct udev_device *udev_device_new_from_devnum(struct udev *udev, char type, dev_t devnum); struct udev_device *udev_device_new_from_subsystem_sysname(struct udev *udev, const char *subsystem, const char *sysname); +struct udev_device *udev_device_new_from_environment(struct udev *udev); /* udev_device_get_parent_*() does not take a reference on the returned device, it is automatically unref'd with the parent */ struct udev_device *udev_device_get_parent(struct udev_device *udev_device); struct udev_device *udev_device_get_parent_with_subsystem_devtype(struct udev_device *udev_device, -- 2.39.5