X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=libudev%2Flibudev-device.c;h=d87b0c6c8ac92b87a9ef791dbc588d56577de8c1;hp=b3b6a63114106f973327b5a594762df6c5bdc293;hb=4281da1fa6fda10c15bee984825fc607a8385004;hpb=a89d342dfb45b54e29381af9dbc495bbb2b057af diff --git a/libudev/libudev-device.c b/libudev/libudev-device.c index b3b6a6311..d87b0c6c8 100644 --- a/libudev/libudev-device.c +++ b/libudev/libudev-device.c @@ -54,32 +54,38 @@ struct udev_device { char *devpath_old; char *sysname_old; char *knodename; + char *id_filename; char **envp; char *monitor_buf; size_t monitor_buf_len; struct udev_list_node devlinks_list; struct udev_list_node properties_list; struct udev_list_node sysattr_list; + struct udev_list_node tags_list; unsigned long long int seqnum; int event_timeout; int timeout; int devlink_priority; int refcount; dev_t devnum; + int ifindex; int watch_handle; int maj, min; - unsigned int parent_set:1; - unsigned int subsystem_set:1; - unsigned int devtype_set:1; - unsigned int devlinks_uptodate:1; - unsigned int envp_uptodate:1; - unsigned int driver_set:1; - unsigned int info_loaded:1; + bool parent_set; + bool subsystem_set; + bool devtype_set; + bool devlinks_uptodate; + bool envp_uptodate; + bool tags_uptodate; + bool driver_set; + bool info_loaded; + bool db_loaded; + bool uevent_loaded; }; struct udev_list_entry *udev_device_add_property(struct udev_device *udev_device, const char *key, const char *value) { - udev_device->envp_uptodate = 0; + udev_device->envp_uptodate = false; if (value == NULL) { struct udev_list_entry *list_entry; @@ -149,6 +155,26 @@ void udev_device_add_property_from_string_parse(struct udev_device *udev_device, } if (slink[0] != '\0') udev_device_add_devlink(udev_device, slink, 0); + } else if (strncmp(property, "TAGS=", 5) == 0) { + char tags[UTIL_PATH_SIZE]; + char *next; + + util_strscpy(tags, sizeof(tags), &property[5]); + next = strchr(tags, ':'); + if (next != NULL) { + next++; + while (next[0] != '\0') { + char *tag; + + tag = next; + next = strchr(tag, ':'); + if (next == NULL) + break; + next[0] = '\0'; + next++; + udev_device_add_tag(udev_device, tag); + } + } } else if (strncmp(property, "DRIVER=", 7) == 0) { udev_device_set_driver(udev_device, &property[7]); } else if (strncmp(property, "ACTION=", 7) == 0) { @@ -163,6 +189,8 @@ void udev_device_add_property_from_string_parse(struct udev_device *udev_device, 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 if (strncmp(property, "IFINDEX=", 8) == 0) { + udev_device_set_ifindex(udev_device, strtoull(&property[8], NULL, 10)); } else { udev_device_add_property_from_string(udev_device, property); } @@ -203,13 +231,19 @@ const char *udev_device_get_property_value(struct udev_device *udev_device, cons int udev_device_read_db(struct udev_device *udev_device) { + const char *id; struct stat stats; char filename[UTIL_PATH_SIZE]; char line[UTIL_LINE_SIZE]; FILE *f; - util_strscpyl(filename, sizeof(filename), udev_get_dev_path(udev_device->udev), "/.udev/db/", - udev_device_get_subsystem(udev_device), ":", udev_device_get_sysname(udev_device), NULL); + if (udev_device->db_loaded) + return 0; + + id = udev_device_get_id_filename(udev_device); + if (id == NULL) + return -1; + util_strscpyl(filename, sizeof(filename), udev_get_dev_path(udev_device->udev), "/.udev/db/", id, NULL); if (lstat(filename, &stats) != 0) { dbg(udev_device->udev, "no db file to read %s: %m\n", filename); @@ -222,12 +256,11 @@ int udev_device_read_db(struct udev_device *udev_device) char *next; target_len = readlink(filename, target, sizeof(target)); - if (target_len > 0) - target[target_len] = '\0'; - else { - dbg(udev_device->udev, "error reading db link %s: %m\n", filename); + if (target_len <= 0 || target_len == sizeof(target)) { + info(udev_device->udev, "error reading db link %s: %m\n", filename); return -1; } + target[target_len] = '\0'; next = strchr(target, ' '); if (next != NULL) { @@ -253,11 +286,13 @@ int udev_device_read_db(struct udev_device *udev_device) return 0; } - f = fopen(filename, "r"); + f = fopen(filename, "re"); if (f == NULL) { dbg(udev_device->udev, "error reading db file %s: %m\n", filename); return -1; } + udev_device->db_loaded = true; + while (fgets(line, sizeof(line), f)) { ssize_t len; const char *val; @@ -285,6 +320,9 @@ int udev_device_read_db(struct udev_device *udev_device) case 'E': udev_device_add_property_from_string(udev_device, val); break; + case 'G': + udev_device_add_tag(udev_device, val); + break; case 'W': udev_device_set_watch_handle(udev_device, atoi(val)); break; @@ -304,10 +342,14 @@ int udev_device_read_uevent_file(struct udev_device *udev_device) int maj = 0; int min = 0; + if (udev_device->uevent_loaded) + return 0; + util_strscpyl(filename, sizeof(filename), udev_device->syspath, "/uevent", NULL); - f = fopen(filename, "r"); + f = fopen(filename, "re"); if (f == NULL) return -1; + udev_device->uevent_loaded = true; while (fgets(line, sizeof(line), f)) { char *pos; @@ -323,6 +365,8 @@ int udev_device_read_uevent_file(struct udev_device *udev_device) maj = strtoull(&line[6], NULL, 10); else if (strncmp(line, "MINOR=", 6) == 0) min = strtoull(&line[6], NULL, 10); + else if (strncmp(line, "IFINDEX=", 8) == 0) + udev_device_set_ifindex(udev_device, strtoull(&line[8], NULL, 10)); else if (strncmp(line, "DEVNAME=", 8) == 0) udev_device_set_knodename(udev_device, &line[8]); @@ -330,21 +374,13 @@ int udev_device_read_uevent_file(struct udev_device *udev_device) } udev_device->devnum = makedev(maj, min); - fclose(f); return 0; } -static void device_load_info(struct udev_device *device) -{ - device->info_loaded = 1; - udev_device_read_uevent_file(device); - udev_device_read_db(device); -} - void udev_device_set_info_loaded(struct udev_device *device) { - device->info_loaded = 1; + device->info_loaded = true; } struct udev_device *udev_device_new(struct udev *udev) @@ -363,6 +399,7 @@ struct udev_device *udev_device_new(struct udev *udev) udev_list_init(&udev_device->devlinks_list); udev_list_init(&udev_device->properties_list); udev_list_init(&udev_device->sysattr_list); + udev_list_init(&udev_device->tags_list); udev_device->event_timeout = -1; udev_device->watch_handle = -1; /* copy global properties */ @@ -421,7 +458,7 @@ struct udev_device *udev_device_new_from_syspath(struct udev *udev, const char * util_strscpy(path, sizeof(path), syspath); util_resolve_sys_link(udev, path, sizeof(path)); - if (strncmp(&syspath[len], "/devices/", 9) == 0) { + if (strncmp(&path[len], "/devices/", 9) == 0) { char file[UTIL_PATH_SIZE]; /* all "devices" require a "uevent" file */ @@ -649,7 +686,7 @@ struct udev_device *udev_device_get_parent(struct udev_device *udev_device) if (udev_device == NULL) return NULL; if (!udev_device->parent_set) { - udev_device->parent_set = 1; + udev_device->parent_set = true; udev_device->parent_device = device_new_from_parent(udev_device); } if (udev_device->parent_device != NULL) @@ -759,12 +796,14 @@ void udev_device_unref(struct udev_device *udev_device) free(udev_device->devtype); udev_list_cleanup_entries(udev_device->udev, &udev_device->devlinks_list); udev_list_cleanup_entries(udev_device->udev, &udev_device->properties_list); + udev_list_cleanup_entries(udev_device->udev, &udev_device->sysattr_list); + udev_list_cleanup_entries(udev_device->udev, &udev_device->tags_list); free(udev_device->action); free(udev_device->driver); free(udev_device->devpath_old); free(udev_device->sysname_old); free(udev_device->knodename); - udev_list_cleanup_entries(udev_device->udev, &udev_device->sysattr_list); + free(udev_device->id_filename); free(udev_device->envp); free(udev_device->monitor_buf); dbg(udev_device->udev, "udev_device: %p released\n", udev_device); @@ -842,8 +881,19 @@ const char *udev_device_get_devnode(struct udev_device *udev_device) { if (udev_device == NULL) return NULL; - if (!udev_device->info_loaded) - device_load_info(udev_device); + if (!udev_device->info_loaded) { + udev_device_read_uevent_file(udev_device); + udev_device_read_db(udev_device); + } + + /* we might get called before we handled an event and have a db, use the kernel-provided name */ + if (udev_device->devnode == NULL && udev_device_get_knodename(udev_device) != NULL) { + if (asprintf(&udev_device->devnode, "%s/%s", + udev_get_dev_path(udev_device->udev), udev_device_get_knodename(udev_device)) < 0) + return NULL; + return udev_device->devnode; + } + return udev_device->devnode; } @@ -863,7 +913,7 @@ const char *udev_device_get_subsystem(struct udev_device *udev_device) if (udev_device == NULL) return NULL; if (!udev_device->subsystem_set) { - udev_device->subsystem_set = 1; + udev_device->subsystem_set = true; /* read "subsystem" link */ if (util_get_sys_subsystem(udev_device->udev, udev_device->syspath, subsystem, sizeof(subsystem)) > 0) { udev_device_set_subsystem(udev_device, subsystem); @@ -901,9 +951,8 @@ const char *udev_device_get_devtype(struct udev_device *udev_device) if (udev_device == NULL) return NULL; if (!udev_device->devtype_set) { - udev_device->devtype_set = 1; - if (!udev_device->info_loaded) - udev_device_read_uevent_file(udev_device); + udev_device->devtype_set = true; + udev_device_read_uevent_file(udev_device); } return udev_device->devtype; } @@ -926,13 +975,13 @@ struct udev_list_entry *udev_device_get_devlinks_list_entry(struct udev_device * if (udev_device == NULL) return NULL; if (!udev_device->info_loaded) - device_load_info(udev_device); + udev_device_read_db(udev_device); return udev_list_get_entry(&udev_device->devlinks_list); } void udev_device_cleanup_devlinks_list(struct udev_device *udev_device) { - udev_device->devlinks_uptodate = 0; + udev_device->devlinks_uptodate = false; udev_list_cleanup_entries(udev_device->udev, &udev_device->devlinks_list); } @@ -952,13 +1001,15 @@ struct udev_list_entry *udev_device_get_properties_list_entry(struct udev_device { if (udev_device == NULL) return NULL; - if (!udev_device->info_loaded) - device_load_info(udev_device); + if (!udev_device->info_loaded) { + udev_device_read_uevent_file(udev_device); + udev_device_read_db(udev_device); + } if (!udev_device->devlinks_uptodate) { char symlinks[UTIL_PATH_SIZE]; struct udev_list_entry *list_entry; - udev_device->devlinks_uptodate = 1; + udev_device->devlinks_uptodate = true; list_entry = udev_device_get_devlinks_list_entry(udev_device); if (list_entry != NULL) { char *s; @@ -971,6 +1022,21 @@ struct udev_list_entry *udev_device_get_properties_list_entry(struct udev_device udev_device_add_property(udev_device, "DEVLINKS", symlinks); } } + if (!udev_device->tags_uptodate) { + udev_device->tags_uptodate = true; + if (udev_device_get_tags_list_entry(udev_device) != NULL) { + char tags[UTIL_PATH_SIZE]; + struct udev_list_entry *list_entry; + char *s; + size_t l; + + s = tags; + l = util_strpcpyl(&s, sizeof(tags), ":", NULL); + udev_list_entry_foreach(list_entry, udev_device_get_tags_list_entry(udev_device)) + l = util_strpcpyl(&s, l, udev_list_entry_get_name(list_entry), ":", NULL); + udev_device_add_property(udev_device, "TAGS", tags); + } + } return udev_list_get_entry(&udev_device->properties_list); } @@ -987,7 +1053,7 @@ const char *udev_device_get_driver(struct udev_device *udev_device) if (udev_device == NULL) return NULL; if (!udev_device->driver_set) { - udev_device->driver_set = 1; + udev_device->driver_set = true; if (util_get_sys_driver(udev_device->udev, udev_device->syspath, driver, sizeof(driver)) > 0) udev_device->driver = strdup(driver); } @@ -1005,7 +1071,7 @@ dev_t udev_device_get_devnum(struct udev_device *udev_device) if (udev_device == NULL) return makedev(0, 0); if (!udev_device->info_loaded) - device_load_info(udev_device); + udev_device_read_uevent_file(udev_device); return udev_device->devnum; } @@ -1095,16 +1161,18 @@ const char *udev_device_get_sysattr_value(struct udev_device *udev_device, const goto out; len = readlink(path, target, sizeof(target)); - if (len > 0) { - target[len] = '\0'; - pos = strrchr(target, '/'); - if (pos != NULL) { - pos = &pos[1]; - dbg(udev_device->udev, "cache '%s' with link value '%s'\n", sysattr, pos); - list_entry = udev_list_entry_add(udev_device->udev, &udev_device->sysattr_list, sysattr, pos, 0, 0); - val = udev_list_entry_get_value(list_entry); - } + if (len <= 0 || len == sizeof(target)) + goto out; + target[len] = '\0'; + + pos = strrchr(target, '/'); + if (pos != NULL) { + pos = &pos[1]; + dbg(udev_device->udev, "cache '%s' with link value '%s'\n", sysattr, pos); + list_entry = udev_list_entry_add(udev_device->udev, &udev_device->sysattr_list, sysattr, pos, 0, 0); + val = udev_list_entry_get_value(list_entry); } + goto out; } @@ -1117,7 +1185,7 @@ const char *udev_device_get_sysattr_value(struct udev_device *udev_device, const goto out; /* read attribute value */ - fd = open(path, O_RDONLY); + fd = open(path, O_RDONLY|O_CLOEXEC); if (fd < 0) { dbg(udev_device->udev, "attribute '%s' can not be opened\n", path); goto out; @@ -1183,7 +1251,7 @@ int udev_device_set_subsystem(struct udev_device *udev_device, const char *subsy udev_device->subsystem = strdup(subsystem); if (udev_device->subsystem == NULL) return -ENOMEM; - udev_device->subsystem_set = 1; + udev_device->subsystem_set = true; udev_device_add_property(udev_device, "SUBSYSTEM", udev_device->subsystem); return 0; } @@ -1194,7 +1262,7 @@ int udev_device_set_devtype(struct udev_device *udev_device, const char *devtype udev_device->devtype = strdup(devtype); if (udev_device->devtype == NULL) return -ENOMEM; - udev_device->devtype_set = 1; + udev_device->devtype_set = true; udev_device_add_property(udev_device, "DEVTYPE", udev_device->devtype); return 0; } @@ -1215,7 +1283,7 @@ int udev_device_add_devlink(struct udev_device *udev_device, const char *devlink { struct udev_list_entry *list_entry; - udev_device->devlinks_uptodate = 0; + udev_device->devlinks_uptodate = false; list_entry = udev_list_entry_add(udev_device->udev, &udev_device->devlinks_list, devlink, NULL, 1, 0); if (list_entry == NULL) return -ENOMEM; @@ -1224,6 +1292,87 @@ int udev_device_add_devlink(struct udev_device *udev_device, const char *devlink return 0; } +const char *udev_device_get_id_filename(struct udev_device *udev_device) +{ + if (udev_device->id_filename == NULL) { + if (udev_device_get_subsystem(udev_device) == NULL) + return NULL; + + if (major(udev_device_get_devnum(udev_device)) > 0) { + /* use dev_t -- b259:131072, c254:0 */ + if (asprintf(&udev_device->id_filename, "%c%u:%u", + strcmp(udev_device_get_subsystem(udev_device), "block") == 0 ? 'b' : 'c', + major(udev_device_get_devnum(udev_device)), + minor(udev_device_get_devnum(udev_device))) < 0) + udev_device->id_filename = NULL; + } else if (strcmp(udev_device_get_subsystem(udev_device), "net") == 0) { + /* use netdev ifindex -- n3 */ + if (asprintf(&udev_device->id_filename, "n%u", udev_device_get_ifindex(udev_device)) < 0) + udev_device->id_filename = NULL; + } else { + /* + * use $subsys:$syname -- pci:0000:00:1f.2 + * sysname() has '!' translated, get it from devpath + */ + const char *sysname; + sysname = strrchr(udev_device->devpath, '/'); + if (sysname == NULL) + return NULL; + sysname = &sysname[1]; + if (asprintf(&udev_device->id_filename, "+%s:%s", udev_device_get_subsystem(udev_device), sysname) < 0) + udev_device->id_filename = NULL; + } + } + return udev_device->id_filename; +} + +int udev_device_add_tag(struct udev_device *udev_device, const char *tag) +{ + if (strchr(tag, ':') != NULL || strchr(tag, ' ') != NULL) + return -EINVAL; + udev_device->tags_uptodate = false; + if (udev_list_entry_add(udev_device->udev, &udev_device->tags_list, tag, NULL, 1, 0) != NULL) + return 0; + return -ENOMEM; +} + +void udev_device_cleanup_tags_list(struct udev_device *udev_device) +{ + udev_device->tags_uptodate = false; + udev_list_cleanup_entries(udev_device->udev, &udev_device->tags_list); +} + +/** + * udev_device_get_tags_list_entry: + * @udev_device: udev device + * + * Retrieve the list of tags attached to the udev device. The next + * list entry can be retrieved with udev_list_entry_next(), + * which returns #NULL if no more entries exist. The tag string + * can be retrieved from the list entry by udev_list_get_name(). + * + * Returns: the first entry of the tag list + **/ +struct udev_list_entry *udev_device_get_tags_list_entry(struct udev_device *udev_device) +{ + if (udev_device == NULL) + return NULL; + return udev_list_get_entry(&udev_device->tags_list); +} + +int udev_device_has_tag(struct udev_device *udev_device, const char *tag) +{ + struct udev_list_entry *list_entry; + + if (!udev_device->info_loaded) + udev_device_read_db(udev_device); + list_entry = udev_device_get_tags_list_entry(udev_device); + list_entry = udev_list_entry_get_by_name(list_entry, tag); + if (list_entry != NULL) + return 1; + return 0; +} + #define ENVP_SIZE 128 #define MONITOR_BUF_SIZE 4096 static int update_envp_monitor_buf(struct udev_device *udev_device) @@ -1272,7 +1421,7 @@ static int update_envp_monitor_buf(struct udev_device *udev_device) } udev_device->envp[i] = NULL; udev_device->monitor_buf_len = s - udev_device->monitor_buf; - udev_device->envp_uptodate = 1; + udev_device->envp_uptodate = true; dbg(udev_device->udev, "filled envp/monitor buffer, %u properties, %zu bytes\n", i, udev_device->monitor_buf_len); return 0; @@ -1311,7 +1460,7 @@ int udev_device_set_driver(struct udev_device *udev_device, const char *driver) udev_device->driver = strdup(driver); if (udev_device->driver == NULL) return -ENOMEM; - udev_device->driver_set = 1; + udev_device->driver_set = true; udev_device_add_property(udev_device, "DRIVER", udev_device->driver); return 0; } @@ -1384,13 +1533,17 @@ int udev_device_set_timeout(struct udev_device *udev_device, int timeout) int udev_device_get_event_timeout(struct udev_device *udev_device) { if (!udev_device->info_loaded) - device_load_info(udev_device); + udev_device_read_db(udev_device); return udev_device->event_timeout; } int udev_device_set_event_timeout(struct udev_device *udev_device, int event_timeout) { + char num[32]; + udev_device->event_timeout = event_timeout; + snprintf(num, sizeof(num), "%u", event_timeout); + udev_device_add_property(udev_device, "TIMEOUT", num); return 0; } @@ -1420,7 +1573,7 @@ int udev_device_set_devnum(struct udev_device *udev_device, dev_t devnum) int udev_device_get_devlink_priority(struct udev_device *udev_device) { if (!udev_device->info_loaded) - device_load_info(udev_device); + udev_device_read_db(udev_device); return udev_device->devlink_priority; } @@ -1433,7 +1586,7 @@ int udev_device_set_devlink_priority(struct udev_device *udev_device, int prio) int udev_device_get_watch_handle(struct udev_device *udev_device) { if (!udev_device->info_loaded) - device_load_info(udev_device); + udev_device_read_db(udev_device); return udev_device->watch_handle; } @@ -1442,3 +1595,18 @@ int udev_device_set_watch_handle(struct udev_device *udev_device, int handle) udev_device->watch_handle = handle; return 0; } + +int udev_device_get_ifindex(struct udev_device *udev_device) +{ + return udev_device->ifindex; +} + +int udev_device_set_ifindex(struct udev_device *udev_device, int ifindex) +{ + char num[32]; + + udev_device->ifindex = ifindex; + snprintf(num, sizeof(num), "%u", ifindex); + udev_device_add_property(udev_device, "IFINDEX", num); + return 0; +}