From: Kay Sievers Date: Tue, 16 Sep 2008 16:53:36 +0000 (-0700) Subject: fix broken symlink resolving X-Git-Tag: 174~1543 X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=commitdiff_plain;h=44589a0c7366c79139bbb7f96b238cb0dcc32d44 fix broken symlink resolving --- diff --git a/udev/udev_sysfs.c b/udev/udev_sysfs.c index 97dcd0311..3e395a280 100644 --- a/udev/udev_sysfs.c +++ b/udev/udev_sysfs.c @@ -40,6 +40,39 @@ struct sysfs_attr { char value_local[UTIL_NAME_SIZE]; }; +static int resolve_sys_link(struct udev *udev, char *path, size_t size) +{ + char link_path[UTIL_PATH_SIZE]; + char link_target[UTIL_PATH_SIZE]; + + int len; + int i; + int back; + + util_strlcpy(link_path, udev_get_sys_path(udev), sizeof(link_path)); + util_strlcat(link_path, path, sizeof(link_path)); + len = readlink(link_path, link_target, sizeof(link_target)); + if (len <= 0) + return -1; + link_target[len] = '\0'; + dbg(udev, "path link '%s' points to '%s'\n", path, link_target); + + for (back = 0; strncmp(&link_target[back * 3], "../", 3) == 0; back++) + ; + dbg(udev, "base '%s', tail '%s', back %i\n", path, &link_target[back * 3], back); + for (i = 0; i <= back; i++) { + char *pos = strrchr(path, '/'); + + if (pos == NULL) + return -1; + pos[0] = '\0'; + } + dbg(udev, "after moving back '%s'\n", path); + util_strlcat(path, "/", size); + util_strlcat(path, &link_target[back * 3], size); + return 0; +} + int sysfs_init(void) { INIT_LIST_HEAD(&dev_list); @@ -144,7 +177,7 @@ struct sysfs_device *sysfs_device_get(struct udev *udev, const char *devpath) return NULL; } if (S_ISLNK(statbuf.st_mode)) { - if (util_resolve_sys_link(udev, devpath_real, sizeof(devpath_real)) != 0) + if (resolve_sys_link(udev, devpath_real, sizeof(devpath_real)) != 0) return NULL; /* now look for device in cache after path translation */ @@ -258,7 +291,7 @@ struct sysfs_device *sysfs_device_get_parent(struct udev *udev, struct sysfs_dev device_link: util_strlcpy(parent_devpath, dev->devpath, sizeof(parent_devpath)); util_strlcat(parent_devpath, "/device", sizeof(parent_devpath)); - if (util_resolve_sys_link(udev, parent_devpath, sizeof(parent_devpath)) != 0) + if (resolve_sys_link(udev, parent_devpath, sizeof(parent_devpath)) != 0) return NULL; /* get parent and remember it */ @@ -460,7 +493,7 @@ out: return 0; found: if (S_ISLNK(statbuf.st_mode)) - util_resolve_sys_link(udev, path, sizeof(path_full) - sysfs_len); + resolve_sys_link(udev, path, sizeof(path_full) - sysfs_len); util_strlcpy(devpath_full, path, len); return 1; } diff --git a/udev/udevadm-trigger.c b/udev/udevadm-trigger.c index f0535f5eb..8a2c12566 100644 --- a/udev/udevadm-trigger.c +++ b/udev/udevadm-trigger.c @@ -65,7 +65,6 @@ static int delay_device(const char *devpath) static int device_list_insert(struct udev *udev, const char *path) { char filename[UTIL_PATH_SIZE]; - char devpath[UTIL_PATH_SIZE]; struct stat statbuf; dbg(udev, "add '%s'\n" , path); @@ -78,16 +77,15 @@ static int device_list_insert(struct udev *udev, const char *path) if (!(statbuf.st_mode & S_IWUSR)) return -1; - util_strlcpy(devpath, &path[strlen(udev_get_sys_path(udev))], sizeof(devpath)); - /* resolve possible link to real target */ - if (lstat(path, &statbuf) < 0) + util_strlcpy(filename, path, sizeof(filename)); + if (lstat(filename, &statbuf) < 0) return -1; if (S_ISLNK(statbuf.st_mode)) - if (util_resolve_sys_link(udev, devpath, sizeof(devpath)) != 0) + if (util_resolve_sys_link(udev, filename, sizeof(filename)) != 0) return -1; - name_list_add(udev, &device_list, devpath, 1); + name_list_add(udev, &device_list, filename, 1); return 0; }