diff options
author | Anthony G. Basile <blueness@gentoo.org> | 2013-07-30 14:05:40 -0400 |
---|---|---|
committer | Anthony G. Basile <blueness@gentoo.org> | 2013-07-30 14:05:40 -0400 |
commit | 6284c1ca41dca85e968e8d304cdc154c5a46d6d2 (patch) | |
tree | e784cc8f766b9a8ed3fe215752d535aed22db8ef /src | |
parent | 67ba217a190ec3946ae80d99d02648daf32d826d (diff) |
udev: export tags of "dead" device nodes to /run/udev/static_node-tags/
This is upstream 84b6ad702e64db534f67ce32d4dd2fec00a16784
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/<tagname>/, if the device node exists.
These tags are cleaned up by udevadm info --cleanup-db, but are otherwise
never removed.
Signed-off-by: Anthony G. Basile <blueness@gentoo.org>
Diffstat (limited to 'src')
-rw-r--r-- | src/udev/udev-rules.c | 95 | ||||
-rw-r--r-- | src/udev/udev.h | 2 | ||||
-rw-r--r-- | src/udev/udevadm-info.c | 6 | ||||
-rw-r--r-- | src/udev/udevd.c | 4 |
4 files changed, 91 insertions, 16 deletions
diff --git a/src/udev/udev-rules.c b/src/udev/udev-rules.c index 399276c567..f6c2b7943c 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 */ @@ -2508,16 +2509,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; @@ -2534,6 +2540,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; @@ -2544,18 +2552,56 @@ void udev_rules_apply_static_dev_perms(struct udev_rules *rules) 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; + } + } + + /* don't touch the permissions if only the tags were set */ + if (mode == 0 && uid == 0 && gid == 0) + goto next; + if (mode == 0) { if (gid > 0) mode = 0660; @@ -2563,21 +2609,28 @@ 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); + r = chmod(device_node, mode); + if (r < 0) { + log_error("failed to chmod '%s' %#o\n", device_node, mode); + return -errno; + } else + log_debug("chmod '%s' %#o\n", device_node, mode); } if ((uid != 0 && uid != stats.st_uid) || (gid != 0 && gid != stats.st_gid)) { - if (chown(filename, uid, gid) < 0) - log_debug("Following chown failed!"); - log_debug("chown '%s' %u %u\n", filename, uid, gid); + r = chown(device_node, uid, gid); + if (r < 0) { + log_error("failed to chown '%s' %u %u \n", device_node, uid, gid); + return -errno; + } else + 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++; @@ -2587,4 +2640,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 80fdd4c0ec..badbeb229f 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 0eaaea19ae..a5872efbc3 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 a923ce740b..28e626c16a 100644 --- a/src/udev/udevd.c +++ b/src/udev/udevd.c @@ -1225,7 +1225,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); |