From 84b6ad702e64db534f67ce32d4dd2fec00a16784 Mon Sep 17 00:00:00 2001 From: Tom Gundersen Date: Sun, 7 Jul 2013 18:32:34 +0200 Subject: udev: export tags of "dead" device nodes to /run/udev/static_node-tags/ Based on a patch by Kay Sievers. A tag is exported at boot as a symlinks to the device node in the folder /run/udev/static_node-tags//, if the device node exists. These tags are cleaned up by udevadm info --cleanup-db, but are otherwise never removed. --- src/udev/udev-rules.c | 82 +++++++++++++++++++++++++++++++++++++++++-------- src/udev/udev.h | 2 +- src/udev/udevadm-info.c | 6 ++++ src/udev/udevd.c | 4 ++- 4 files changed, 79 insertions(+), 15 deletions(-) (limited to 'src/udev') diff --git a/src/udev/udev-rules.c b/src/udev/udev-rules.c index fe65e2dd85..8ace7050db 100644 --- a/src/udev/udev-rules.c +++ b/src/udev/udev-rules.c @@ -33,6 +33,7 @@ #include "path-util.h" #include "conf-files.h" #include "strbuf.h" +#include "strv.h" #define PREALLOC_TOKEN 2048 @@ -152,9 +153,9 @@ enum token_type { TK_A_OWNER_ID, /* uid_t */ TK_A_GROUP_ID, /* gid_t */ TK_A_MODE_ID, /* mode_t */ + TK_A_TAG, /* val */ TK_A_STATIC_NODE, /* val */ TK_A_ENV, /* val, attr */ - TK_A_TAG, /* val */ TK_A_NAME, /* val */ TK_A_DEVLINK, /* val */ TK_A_ATTR, /* val, attr */ @@ -2496,16 +2497,21 @@ int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event } } -void udev_rules_apply_static_dev_perms(struct udev_rules *rules) +int udev_rules_apply_static_dev_perms(struct udev_rules *rules) { struct token *cur; struct token *rule; uid_t uid = 0; gid_t gid = 0; mode_t mode = 0; + _cleanup_strv_free_ char **tags = NULL; + char **t; + FILE *f = NULL; + _cleanup_free_ char *path = NULL; + int r = 0; if (rules->tokens == NULL) - return; + return 0; cur = &rules->tokens[0]; rule = cur; @@ -2522,6 +2528,8 @@ void udev_rules_apply_static_dev_perms(struct udev_rules *rules) uid = 0; gid = 0; mode = 0; + strv_free(tags); + tags = NULL; break; case TK_A_OWNER_ID: uid = cur->key.uid; @@ -2531,19 +2539,53 @@ void udev_rules_apply_static_dev_perms(struct udev_rules *rules) break; case TK_A_MODE_ID: mode = cur->key.mode; + break; + case TK_A_TAG: + r = strv_extend(&tags, rules_str(rules, cur->key.value_off)); + if (r < 0) + goto finish; + break; case TK_A_STATIC_NODE: { - char filename[UTIL_PATH_SIZE]; + char device_node[UTIL_PATH_SIZE]; + char tags_dir[UTIL_PATH_SIZE]; + char tag_symlink[UTIL_PATH_SIZE]; struct stat stats; /* we assure, that the permissions tokens are sorted before the static token */ - if (mode == 0 && uid == 0 && gid == 0) + if (mode == 0 && uid == 0 && gid == 0 && tags == NULL) goto next; - strscpyl(filename, sizeof(filename), "/dev/", rules_str(rules, cur->key.value_off), NULL); - if (stat(filename, &stats) != 0) + strscpyl(device_node, sizeof(device_node), "/dev/", rules_str(rules, cur->key.value_off), NULL); + if (stat(device_node, &stats) != 0) goto next; if (!S_ISBLK(stats.st_mode) && !S_ISCHR(stats.st_mode)) goto next; + + if (tags) { + /* Export the tags to a directory as symlinks, allowing otherwise dead nodes to be tagged */ + + STRV_FOREACH(t, tags) { + _cleanup_free_ char *unescaped_filename = NULL; + + strscpyl(tags_dir, sizeof(tags_dir), "/run/udev/static_node-tags/", *t, "/", NULL); + r = mkdir_p(tags_dir, 0755); + if (r < 0) { + log_error("failed to create %s: %s\n", tags_dir, strerror(-r)); + return r; + } + + unescaped_filename = xescape(rules_str(rules, cur->key.value_off), "/."); + + strscpyl(tag_symlink, sizeof(tag_symlink), tags_dir, unescaped_filename, NULL); + r = symlink(device_node, tag_symlink); + if (r < 0 && errno != EEXIST) { + log_error("failed to create symlink %s -> %s: %s\n", tag_symlink, device_node, strerror(errno)); + return -errno; + } else + r = 0; + } + } + if (mode == 0) { if (gid > 0) mode = 0660; @@ -2551,20 +2593,20 @@ void udev_rules_apply_static_dev_perms(struct udev_rules *rules) mode = 0600; } if (mode != (stats.st_mode & 01777)) { - chmod(filename, mode); - log_debug("chmod '%s' %#o\n", filename, mode); + chmod(device_node, mode); + log_debug("chmod '%s' %#o\n", device_node, mode); } if ((uid != 0 && uid != stats.st_uid) || (gid != 0 && gid != stats.st_gid)) { - chown(filename, uid, gid); - log_debug("chown '%s' %u %u\n", filename, uid, gid); + chown(device_node, uid, gid); + log_debug("chown '%s' %u %u\n", device_node, uid, gid); } - utimensat(AT_FDCWD, filename, NULL, 0); + utimensat(AT_FDCWD, device_node, NULL, 0); break; } case TK_END: - return; + goto finish; } cur++; @@ -2574,4 +2616,18 @@ next: cur = rule + rule->rule.token_count; continue; } + +finish: + if (f) { + fflush(f); + fchmod(fileno(f), 0644); + if (ferror(f) || rename(path, "/run/udev/static_node-tags") < 0) { + r = -errno; + unlink("/run/udev/static_node-tags"); + unlink(path); + } + fclose(f); + } + + return r; } diff --git a/src/udev/udev.h b/src/udev/udev.h index c9408f2d46..839592680b 100644 --- a/src/udev/udev.h +++ b/src/udev/udev.h @@ -72,7 +72,7 @@ struct udev_rules *udev_rules_new(struct udev *udev, int resolve_names); struct udev_rules *udev_rules_unref(struct udev_rules *rules); bool udev_rules_check_timestamp(struct udev_rules *rules); int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event, const sigset_t *sigmask); -void udev_rules_apply_static_dev_perms(struct udev_rules *rules); +int udev_rules_apply_static_dev_perms(struct udev_rules *rules); /* udev-event.c */ struct udev_event *udev_event_new(struct udev_device *dev); diff --git a/src/udev/udevadm-info.c b/src/udev/udevadm-info.c index 002876594f..2ee59fe075 100644 --- a/src/udev/udevadm-info.c +++ b/src/udev/udevadm-info.c @@ -251,6 +251,12 @@ static void cleanup_db(struct udev *udev) closedir(dir); } + dir = opendir("/run/udev/static_node-tags"); + if (dir != NULL) { + cleanup_dir(dir, 0, 2); + closedir(dir); + } + dir = opendir("/run/udev/watch"); if (dir != NULL) { cleanup_dir(dir, 0, 1); diff --git a/src/udev/udevd.c b/src/udev/udevd.c index c4127cd03b..45ec3d681f 100644 --- a/src/udev/udevd.c +++ b/src/udev/udevd.c @@ -1197,7 +1197,9 @@ int main(int argc, char *argv[]) } log_debug("set children_max to %u\n", children_max); - udev_rules_apply_static_dev_perms(rules); + rc = udev_rules_apply_static_dev_perms(rules); + if (rc < 0) + log_error("failed to apply permissions on static device nodes - %s\n", strerror(-rc)); udev_list_node_init(&event_list); udev_list_node_init(&worker_list); -- cgit v1.2.3-54-g00ecf