chiark / gitweb /
udevadm: info --cleanup-db
authorKay Sievers <kay.sievers@vrfy.org>
Wed, 13 Apr 2011 20:33:01 +0000 (22:33 +0200)
committerKay Sievers <kay.sievers@vrfy.org>
Wed, 13 Apr 2011 20:33:01 +0000 (22:33 +0200)
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
TODO
libudev/libudev-device-private.c
libudev/libudev-device.c
libudev/libudev-private.h
udev/udev-rules.c
udev/udevadm-info.c
udev/udevadm.xml

diff --git a/NEWS b/NEWS
index f45957b..6647fd4 100644 (file)
--- 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 773fe7f..6906aa8 100644 (file)
--- 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
index 6d72d32..ee9e297 100644 (file)
@@ -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;
index ccd4a70..a141dad 100644 (file)
@@ -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;
+}
index f6137b5..c57a898 100644 (file)
@@ -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);
index 221865c..805f449 100644 (file)
@@ -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;
index 9357f67..87c1c32 100644 (file)
@@ -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:
index 04c3d0b..7860efe 100644 (file)
           </listitem>
         </varlistentry>
         <varlistentry>
+          <term><option>--cleanup-db</option></term>
+          <listitem>
+            <para>Cleanup the udev database.</para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
           <term><option>--version</option></term>
           <listitem>
             <para>Print version.</para>