X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=libudev%2Flibudev-device.c;h=8698d98e1c6871ee7ea3c2ddf88f95c75fe2fa95;hb=cad40a5fe75d876af22f68b688494b9cd98cc899;hp=a6a1ecb4e90f84651b26ea0c5cb345928bbeb082;hpb=65f099c721fa568350f8ac019e3a99fda1966082;p=elogind.git diff --git a/libudev/libudev-device.c b/libudev/libudev-device.c index a6a1ecb4e..8698d98e1 100644 --- a/libudev/libudev-device.c +++ b/libudev/libudev-device.c @@ -54,6 +54,7 @@ struct udev_device { char *devpath_old; char *sysname_old; char *knodename; + char *id_filename; char **envp; char *monitor_buf; size_t monitor_buf_len; @@ -67,6 +68,7 @@ struct udev_device { int devlink_priority; int refcount; dev_t devnum; + int ifindex; int watch_handle; int maj, min; bool parent_set; @@ -187,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); } @@ -227,68 +231,29 @@ const char *udev_device_get_property_value(struct udev_device *udev_device, cons int udev_device_read_db(struct udev_device *udev_device) { - struct stat stats; + const char *id; char filename[UTIL_PATH_SIZE]; char line[UTIL_LINE_SIZE]; FILE *f; if (udev_device->db_loaded) return 0; + udev_device->db_loaded = true; - 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 (lstat(filename, &stats) != 0) { - dbg(udev_device->udev, "no db file to read %s: %m\n", filename); + id = udev_device_get_id_filename(udev_device); + if (id == NULL) return -1; - } - if ((stats.st_mode & S_IFMT) == S_IFLNK) { - char target[UTIL_PATH_SIZE]; - char devnode[UTIL_PATH_SIZE]; - int target_len; - char *next; - - target_len = readlink(filename, target, sizeof(target)); - 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) { - next[0] = '\0'; - next = &next[1]; - } - util_strscpyl(devnode, sizeof(devnode), udev_get_dev_path(udev_device->udev), "/", target, NULL); - udev_device_set_devnode(udev_device, devnode); - while (next != NULL) { - char devlink[UTIL_PATH_SIZE]; - const char *lnk; - - lnk = next; - next = strchr(next, ' '); - if (next != NULL) { - next[0] = '\0'; - next = &next[1]; - } - util_strscpyl(devlink, sizeof(devlink), udev_get_dev_path(udev_device->udev), "/", lnk, NULL); - udev_device_add_devlink(udev_device, devlink, 0); - } - info(udev_device->udev, "device %p filled with db symlink data '%s'\n", udev_device, udev_device->devnode); - return 0; - } - - f = fopen(filename, "r"); + util_strscpyl(filename, sizeof(filename), udev_get_dev_path(udev_device->udev), "/.udev/db/", id, NULL); + f = fopen(filename, "re"); if (f == NULL) { - dbg(udev_device->udev, "error reading db file %s: %m\n", filename); + info(udev_device->udev, "no db file to read %s: %m\n", filename); return -1; } - udev_device->db_loaded = true; while (fgets(line, sizeof(line), f)) { ssize_t len; const char *val; + struct udev_list_entry *entry; len = strlen(line); if (len < 4) @@ -307,11 +272,9 @@ int udev_device_read_db(struct udev_device *udev_device) case 'L': udev_device_set_devlink_priority(udev_device, atoi(val)); break; - case 'T': - udev_device_set_event_timeout(udev_device, atoi(val)); - break; case 'E': - udev_device_add_property_from_string(udev_device, val); + entry = udev_device_add_property_from_string(udev_device, val); + udev_list_entry_set_flags(entry, 1); break; case 'G': udev_device_add_tag(udev_device, val); @@ -339,7 +302,7 @@ int udev_device_read_uevent_file(struct udev_device *udev_device) 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; @@ -358,6 +321,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]); @@ -510,6 +475,32 @@ struct udev_device *udev_device_new_from_devnum(struct udev *udev, char type, de return udev_device_new_from_syspath(udev, path); } +struct udev_device *udev_device_new_from_id_filename(struct udev *udev, char *id) +{ + char type; + int maj, min; + char subsys[UTIL_PATH_SIZE]; + char *sysname; + + switch(id[0]) { + case 'b': + case 'c': + if (sscanf(id, "%c%i:%i", &type, &maj, &min) != 3) + return NULL; + return udev_device_new_from_devnum(udev, type, makedev(maj, min)); + case '+': + util_strscpy(subsys, sizeof(subsys), &id[1]); + sysname = strchr(subsys, ':'); + if (sysname == NULL) + return NULL; + sysname[0] = '\0'; + sysname = &sysname[1]; + return udev_device_new_from_subsystem_sysname(udev, subsys, sysname); + default: + return NULL; + } +} + /** * udev_device_new_from_subsystem_sysname: * @udev: udev library context @@ -794,6 +785,7 @@ void udev_device_unref(struct udev_device *udev_device) free(udev_device->devpath_old); free(udev_device->sysname_old); free(udev_device->knodename); + 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); @@ -871,8 +863,21 @@ const char *udev_device_get_devnode(struct udev_device *udev_device) { if (udev_device == NULL) return NULL; - if (!udev_device->info_loaded) + 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) { + char filename[UTIL_NAME_SIZE]; + + util_strscpyl(filename, sizeof(filename), udev_get_dev_path(udev_device->udev), "/", + udev_device_get_knodename(udev_device), NULL); + udev_device_set_devnode(udev_device, filename); + return udev_device->devnode; + } + return udev_device->devnode; } @@ -1164,7 +1169,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; @@ -1250,8 +1255,6 @@ int udev_device_set_devnode(struct udev_device *udev_device, const char *devnode { free(udev_device->devnode); udev_device->devnode = strdup(devnode); - if (devnode == NULL) - return 0; if (udev_device->devnode == NULL) return -ENOMEM; udev_device_add_property(udev_device, "DEVNAME", udev_device->devnode); @@ -1271,6 +1274,40 @@ 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) @@ -1287,6 +1324,17 @@ void udev_device_cleanup_tags_list(struct udev_device *udev_device) 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) @@ -1450,7 +1498,9 @@ int udev_device_set_knodename(struct udev_device *udev_device, const char *knode udev_device->knodename = strdup(knodename); if (udev_device->knodename == NULL) return -ENOMEM; - udev_device_add_property(udev_device, "DEVNAME", udev_device->knodename); + /* do not overwrite the udev property with the kernel property */ + if (udev_device->devnode == NULL) + udev_device_add_property(udev_device, "DEVNAME", udev_device->knodename); return 0; } @@ -1473,7 +1523,11 @@ int udev_device_get_event_timeout(struct udev_device *udev_device) 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; } @@ -1525,3 +1579,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; +}