summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS6
-rw-r--r--TODO2
-rw-r--r--libudev/libudev-device-private.c7
-rw-r--r--libudev/libudev-device.c11
-rw-r--r--libudev/libudev-private.h2
-rw-r--r--udev/udev-rules.c19
-rw-r--r--udev/udevadm-info.c82
-rw-r--r--udev/udevadm.xml6
8 files changed, 132 insertions, 3 deletions
diff --git a/NEWS b/NEWS
index f45957b62d..6647fd4c24 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 773fe7f380..6906aa89d1 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 6d72d328bd..ee9e297cea 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 ccd4a70677..a141dadf0a 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 f6137b5dc7..c57a89873c 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 221865c9dc..805f449f22 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 9357f67208..87c1c32314 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 04c3d0b963..7860efe967 100644
--- a/udev/udevadm.xml
+++ b/udev/udevadm.xml
@@ -150,6 +150,12 @@
</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>