From 9ead662791b5e59a95b6c5a9351d661cb61d76bb Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Wed, 13 Apr 2011 22:33:01 +0200 Subject: [PATCH 1/1] udevadm: info --cleanup-db Most of the udev database from initramfs should be deleted before starting udev in the real root. udevadm: info --cleanup-db deletes all database entries in /run/udev. Events that processed IMPORT{db}, or mark devices explicitely as persistent, will be excluded. --- NEWS | 6 +++ TODO | 2 - libudev/libudev-device-private.c | 7 +++ libudev/libudev-device.c | 11 +++++ libudev/libudev-private.h | 2 + udev/udev-rules.c | 19 ++++++++ udev/udevadm-info.c | 82 +++++++++++++++++++++++++++++++- udev/udevadm.xml | 6 +++ 8 files changed, 132 insertions(+), 3 deletions(-) diff --git a/NEWS b/NEWS index f45957b62..6647fd4c2 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,12 @@ udev 168 ======== Bugfixes. +warning if /run is not writable. + +udevadm control --exit + +udevadm info --cleanup-db + udev 167 ======== Bugfixes. diff --git a/TODO b/TODO index 773fe7f38..6906aa89d 100644 --- a/TODO +++ b/TODO @@ -1,5 +1,3 @@ - - do not write age/configured in initramfs - - remove deprecated trigger --type=failed logic - remove deprecated BUS=, SYSFS{}=, ID= keys diff --git a/libudev/libudev-device-private.c b/libudev/libudev-device-private.c index 6d72d328b..ee9e297ce 100644 --- a/libudev/libudev-device-private.c +++ b/libudev/libudev-device-private.c @@ -134,6 +134,13 @@ int udev_device_update_db(struct udev_device *udev_device) return -1; } + /* + * set 'sticky' bit to indicate that we should not clean the + * database when we transition from initramfs to the real root + */ + if (udev_device_get_db_persist(udev_device)) + fchmod(fileno(f), 01644); + if (has_info) { size_t devlen = strlen(udev_get_dev_path(udev))+1; struct udev_list_entry *list_entry; diff --git a/libudev/libudev-device.c b/libudev/libudev-device.c index ccd4a7067..a141dadf0 100644 --- a/libudev/libudev-device.c +++ b/libudev/libudev-device.c @@ -89,6 +89,7 @@ struct udev_device { bool uevent_loaded; bool is_initialized; bool sysattr_list_read; + bool db_persist; }; struct udev_list_entry *udev_device_add_property(struct udev_device *udev_device, const char *key, const char *value) @@ -1774,3 +1775,13 @@ int udev_device_set_ifindex(struct udev_device *udev_device, int ifindex) udev_device_add_property(udev_device, "IFINDEX", num); return 0; } + +bool udev_device_get_db_persist(struct udev_device *udev_device) +{ + return udev_device->db_persist; +} + +void udev_device_set_db_persist(struct udev_device *udev_device) +{ + udev_device->db_persist = true; +} diff --git a/libudev/libudev-private.h b/libudev/libudev-private.h index f6137b5dc..c57a89873 100644 --- a/libudev/libudev-private.h +++ b/libudev/libudev-private.h @@ -109,6 +109,8 @@ int udev_device_set_watch_handle(struct udev_device *udev_device, int handle); int udev_device_get_ifindex(struct udev_device *udev_device); int udev_device_set_ifindex(struct udev_device *udev_device, int ifindex); void udev_device_set_info_loaded(struct udev_device *device); +bool udev_device_get_db_persist(struct udev_device *udev_device); +void udev_device_set_db_persist(struct udev_device *udev_device); /* libudev-device-private.c */ int udev_device_update_db(struct udev_device *udev_device); diff --git a/udev/udev-rules.c b/udev/udev-rules.c index 221865c9d..805f449f2 100644 --- a/udev/udev-rules.c +++ b/udev/udev-rules.c @@ -150,6 +150,7 @@ enum token_type { TK_A_STRING_ESCAPE_NONE, TK_A_STRING_ESCAPE_REPLACE, + TK_A_DB_PERSIST, TK_A_INOTIFY_WATCH, /* int */ TK_A_DEVLINK_PRIO, /* int */ TK_A_OWNER, /* val */ @@ -284,6 +285,7 @@ static const char *token_str(enum token_type type) [TK_A_STRING_ESCAPE_NONE] = "A STRING_ESCAPE_NONE", [TK_A_STRING_ESCAPE_REPLACE] = "A STRING_ESCAPE_REPLACE", + [TK_A_DB_PERSIST] = "A DB_PERSIST", [TK_A_INOTIFY_WATCH] = "A INOTIFY_WATCH", [TK_A_DEVLINK_PRIO] = "A DEVLINK_PRIO", [TK_A_OWNER] = "A OWNER", @@ -370,6 +372,7 @@ static void dump_token(struct udev_rules *rules, struct token *token) break; case TK_A_STRING_ESCAPE_NONE: case TK_A_STRING_ESCAPE_REPLACE: + case TK_A_DB_PERSIST: dbg(rules->udev, "%s\n", token_str(type)); break; case TK_M_TEST: @@ -1045,6 +1048,7 @@ static int rule_add_key(struct rule_tmp *rule_tmp, enum token_type type, break; case TK_A_STRING_ESCAPE_NONE: case TK_A_STRING_ESCAPE_REPLACE: + case TK_A_DB_PERSIST: break; case TK_A_RUN: token->key.value_off = add_string(rule_tmp->rules, value); @@ -1572,6 +1576,7 @@ static int add_rule(struct udev_rules *rules, char *line, rule_add_key(&rule_tmp, TK_A_DEVLINK_PRIO, op, NULL, &prio); dbg(rules->udev, "link priority=%i\n", prio); } + pos = strstr(value, "event_timeout="); if (pos != NULL) { int tout = atoi(&pos[strlen("event_timeout=")]); @@ -1579,6 +1584,7 @@ static int add_rule(struct udev_rules *rules, char *line, rule_add_key(&rule_tmp, TK_A_EVENT_TIMEOUT, op, NULL, &tout); dbg(rules->udev, "event timeout=%i\n", tout); } + pos = strstr(value, "string_escape="); if (pos != NULL) { pos = &pos[strlen("string_escape=")]; @@ -1587,6 +1593,11 @@ static int add_rule(struct udev_rules *rules, char *line, else if (strncmp(pos, "replace", strlen("replace")) == 0) rule_add_key(&rule_tmp, TK_A_STRING_ESCAPE_REPLACE, op, NULL, NULL); } + + pos = strstr(value, "db_persist="); + if (pos != NULL) + rule_add_key(&rule_tmp, TK_A_DB_PERSIST, op, NULL, NULL); + pos = strstr(value, "nowatch"); if (pos != NULL) { const int off = 0; @@ -1602,11 +1613,13 @@ static int add_rule(struct udev_rules *rules, char *line, dbg(rules->udev, "inotify watch of device requested\n"); } } + pos = strstr(value, "static_node="); if (pos != NULL) { rule_add_key(&rule_tmp, TK_A_STATIC_NODE, op, &pos[strlen("static_node=")], NULL); rule_tmp.rule.rule.has_static_node = true; } + continue; } err(rules->udev, "unknown key '%s' in %s:%u\n", key, filename, lineno); @@ -2332,6 +2345,9 @@ int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event const char *key = &rules->buf[cur->key.value_off]; const char *value; + /* implicitely mark database as persistent across initramfs transition */ + udev_device_set_db_persist(event->dev); + value = udev_device_get_property_value(event->dev_db, key); if (value != NULL) { struct udev_list_entry *entry; @@ -2407,6 +2423,9 @@ int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event case TK_A_STRING_ESCAPE_REPLACE: esc = ESCAPE_REPLACE; break; + case TK_A_DB_PERSIST: + udev_device_set_db_persist(event->dev); + break; case TK_A_INOTIFY_WATCH: if (event->inotify_watch_final) break; diff --git a/udev/udevadm-info.c b/udev/udevadm-info.c index 9357f6720..87c1c3231 100644 --- a/udev/udevadm-info.c +++ b/udev/udevadm-info.c @@ -200,6 +200,81 @@ static int export_devices(struct udev *udev) return 0; } +static void cleanup_dir(DIR *dir, mode_t mask, int depth) +{ + struct dirent *dent; + + if (depth <= 0) + return; + + for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) { + struct stat stats; + + if (dent->d_name[0] == '.') + continue; + if (fstatat(dirfd(dir), dent->d_name, &stats, AT_SYMLINK_NOFOLLOW) != 0) + continue; + if ((stats.st_mode & mask) != 0) + continue; + if (S_ISDIR(stats.st_mode)) { + DIR *dir2; + + dir2 = fdopendir(openat(dirfd(dir), dent->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC)); + if (dir2 != NULL) { + cleanup_dir(dir2, mask, depth-1); + closedir(dir2); + } + unlinkat(dirfd(dir), dent->d_name, AT_REMOVEDIR); + } else { + unlinkat(dirfd(dir), dent->d_name, 0); + } + } +} + +static void cleanup_db(struct udev *udev) +{ + char filename[UTIL_PATH_SIZE]; + DIR *dir; + + util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev), "/queue.bin", NULL); + unlink(filename); + + util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev), "/data", NULL); + dir = opendir(filename); + if (dir != NULL) { + cleanup_dir(dir, S_ISVTX, 1); + closedir(dir); + } + + util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev), "/links", NULL); + dir = opendir(filename); + if (dir != NULL) { + cleanup_dir(dir, 0, 2); + closedir(dir); + } + + util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev), "/tags", NULL); + dir = opendir(filename); + if (dir != NULL) { + cleanup_dir(dir, 0, 2); + closedir(dir); + } + + util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev), "/watch", NULL); + dir = opendir(filename); + if (dir != NULL) { + cleanup_dir(dir, 0, 1); + closedir(dir); + } + + util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev), "/firmware-missing", NULL); + dir = opendir(filename); + if (dir != NULL) { + cleanup_dir(dir, 0, 1); + closedir(dir); + } +} + int udevadm_info(struct udev *udev, int argc, char *argv[]) { struct udev_device *device = NULL; @@ -216,6 +291,7 @@ int udevadm_info(struct udev *udev, int argc, char *argv[]) { "path", required_argument, NULL, 'p' }, { "query", required_argument, NULL, 'q' }, { "attribute-walk", no_argument, NULL, 'a' }, + { "cleanup-db", no_argument, NULL, 'c' }, { "export-db", no_argument, NULL, 'e' }, { "root", no_argument, NULL, 'r' }, { "run", no_argument, NULL, 'R' }, @@ -248,7 +324,7 @@ int udevadm_info(struct udev *udev, int argc, char *argv[]) int option; struct stat statbuf; - option = getopt_long(argc, argv, "aed:n:p:q:rxP:RVh", options, NULL); + option = getopt_long(argc, argv, "aced:n:p:q:rxP:RVh", options, NULL); if (option == -1) break; @@ -345,6 +421,9 @@ int udevadm_info(struct udev *udev, int argc, char *argv[]) case 'e': export_devices(udev); goto exit; + case 'c': + cleanup_db(udev); + goto exit; case 'x': export = true; break; @@ -371,6 +450,7 @@ int udevadm_info(struct udev *udev, int argc, char *argv[]) " --export export key/value pairs\n" " --export-prefix export the key name with a prefix\n" " --export-db export the content of the udev database\n" + " --cleanup-db cleanup the udev database\n" " --help\n\n"); goto exit; default: diff --git a/udev/udevadm.xml b/udev/udevadm.xml index 04c3d0b96..7860efe96 100644 --- a/udev/udevadm.xml +++ b/udev/udevadm.xml @@ -149,6 +149,12 @@ Export the content of the udev database. + + + + Cleanup the udev database. + + -- 2.30.2