summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS11
-rw-r--r--TODO8
-rw-r--r--libudev/libudev-device-private.c27
-rw-r--r--libudev/libudev-device.c40
-rw-r--r--libudev/libudev-private.h5
-rw-r--r--libudev/libudev-queue-private.c16
-rwxr-xr-xtest/udev-test.pl4
-rw-r--r--udev/udev-event.c10
-rw-r--r--udev/udev-node.c47
9 files changed, 100 insertions, 68 deletions
diff --git a/NEWS b/NEWS
index 28321c5109..daefed8812 100644
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,17 @@ udev 147
========
Bugfixes.
+To support DEVPATH strings larger than the maximum file name length, the
+private udev database format has changed. If some software still reads the
+private files in /dev/.udev/, which it shouldn't, now it's time to fix it.
+Please do not port anything to the new format again, everything in /dev/.udev
+is and always was private to udev, and may and will change any time without
+prior notice.
+
+NAME="%k" causes a warning now. It's is and always was completely superfluous.
+It will break kernel supplied DEVNAMEs and therefore it needs to be removed
+from all rules.
+
udev 146
========
Bugfixes.
diff --git a/TODO b/TODO
index 6a475365be..5df63fad05 100644
--- a/TODO
+++ b/TODO
@@ -1,4 +1,12 @@
+ o drop support for node names in name stack, support only symlinks
+ With well defined and kernel-supplied node names, we no longer need
+ to support a possible stack of conflicting symlinks and node names.
+ From there on, only symlinks with identical names can be claimed
+ by multiple devices. It will simplify the logic a lot and shrink
+ /dev/.udev/names/ significantly. Also exclude "*/MAJ:MIN" link names
+ from the name stack, they can not conflict.
+ o remove most NAME= rules (they are provided by the 2.6.31 kernel)
o get rid of braindead "scan all devices to find myself" libusb interface
if it can not be fixed, drop libusb entirely
o convert firmware.sh to C
diff --git a/libudev/libudev-device-private.c b/libudev/libudev-device-private.c
index 68dc0a5b98..80a4da4c96 100644
--- a/libudev/libudev-device-private.c
+++ b/libudev/libudev-device-private.c
@@ -21,16 +21,6 @@
#include "libudev.h"
#include "libudev-private.h"
-static size_t devpath_to_db_path(struct udev *udev, const char *devpath, char *filename, size_t len)
-{
- char *s;
- size_t l;
-
- s = filename;
- l = util_strpcpyl(&s, len, udev_get_dev_path(udev), "/.udev/db/", NULL);
- return util_path_encode(devpath, s, l);
-}
-
int udev_device_update_db(struct udev_device *udev_device)
{
struct udev *udev = udev_device_get_udev(udev_device);
@@ -43,8 +33,8 @@ int udev_device_update_db(struct udev_device *udev_device)
struct udev_list_entry *list_entry;
int ret;
- devpath_to_db_path(udev, udev_device_get_devpath(udev_device), filename, sizeof(filename));
- util_create_path(udev, filename);
+ util_strscpyl(filename, sizeof(filename), udev_get_dev_path(udev), "/.udev/db/",
+ udev_device_get_subsystem(udev_device), ":", udev_device_get_sysname(udev_device), NULL);
unlink(filename);
udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(udev_device))
@@ -78,11 +68,13 @@ int udev_device_update_db(struct udev_device *udev_device)
}
info(udev, "create db link (%s)\n", target);
udev_selinux_setfscreatecon(udev, filename, S_IFLNK);
+ util_create_path(udev, filename);
ret = symlink(target, filename);
udev_selinux_resetfscreatecon(udev);
if (ret == 0)
goto out;
file:
+ util_create_path(udev, filename);
f = fopen(filename, "w");
if (f == NULL) {
err(udev, "unable to create db file '%s': %m\n", filename);
@@ -122,18 +114,21 @@ int udev_device_delete_db(struct udev_device *udev_device)
struct udev *udev = udev_device_get_udev(udev_device);
char filename[UTIL_PATH_SIZE];
- devpath_to_db_path(udev, udev_device_get_devpath(udev_device), filename, sizeof(filename));
+ util_strscpyl(filename, sizeof(filename), udev_get_dev_path(udev), "/.udev/db/",
+ udev_device_get_subsystem(udev_device), ":", udev_device_get_sysname(udev_device), NULL);
unlink(filename);
return 0;
}
-int udev_device_rename_db(struct udev_device *udev_device, const char *devpath_old)
+int udev_device_rename_db(struct udev_device *udev_device)
{
struct udev *udev = udev_device_get_udev(udev_device);
char filename_old[UTIL_PATH_SIZE];
char filename[UTIL_PATH_SIZE];
- devpath_to_db_path(udev, devpath_old, filename_old, sizeof(filename_old));
- devpath_to_db_path(udev, udev_device_get_devpath(udev_device), filename, sizeof(filename));
+ util_strscpyl(filename_old, sizeof(filename_old), udev_get_dev_path(udev), "/.udev/db/",
+ udev_device_get_subsystem(udev_device), ":", udev_device_get_sysname_old(udev_device), NULL);
+ util_strscpyl(filename, sizeof(filename), udev_get_dev_path(udev), "/.udev/db/",
+ udev_device_get_subsystem(udev_device), ":", udev_device_get_sysname(udev_device), NULL);
return rename(filename_old, filename);
}
diff --git a/libudev/libudev-device.c b/libudev/libudev-device.c
index eac6bd6041..22d8349275 100644
--- a/libudev/libudev-device.c
+++ b/libudev/libudev-device.c
@@ -51,6 +51,7 @@ struct udev_device {
char *driver;
char *action;
char *devpath_old;
+ char *sysname_old;
char *knodename;
char **envp;
char *monitor_buf;
@@ -76,16 +77,6 @@ struct udev_device {
unsigned int ignore_remove:1;
};
-static size_t devpath_to_db_path(struct udev *udev, const char *devpath, char *filename, size_t len)
-{
- char *s;
- size_t l;
-
- s = filename;
- l = util_strpcpyl(&s, len, udev_get_dev_path(udev), "/.udev/db/", NULL);
- return util_path_encode(devpath, s, l);
-}
-
int udev_device_read_db(struct udev_device *udev_device)
{
struct stat stats;
@@ -93,7 +84,8 @@ int udev_device_read_db(struct udev_device *udev_device)
char line[UTIL_LINE_SIZE];
FILE *f;
- devpath_to_db_path(udev_device->udev, udev_device->devpath, filename, sizeof(filename));
+ util_strscpyl(filename, sizeof(filename), udev_get_dev_path(udev_device->udev), "/.udev/db/",
+ udev_device_get_subsystem(udev_device), ":", udev_device_get_sysname(udev_device), NULL);
if (lstat(filename, &stats) != 0) {
dbg(udev_device->udev, "no db file to read %s: %m\n", filename);
@@ -677,6 +669,7 @@ void udev_device_unref(struct udev_device *udev_device)
free(udev_device->action);
free(udev_device->driver);
free(udev_device->devpath_old);
+ free(udev_device->sysname_old);
free(udev_device->knodename);
udev_list_cleanup_entries(udev_device->udev, &udev_device->sysattr_list);
free(udev_device->envp);
@@ -1282,14 +1275,39 @@ const char *udev_device_get_devpath_old(struct udev_device *udev_device)
int udev_device_set_devpath_old(struct udev_device *udev_device, const char *devpath_old)
{
+ const char *pos;
+ size_t len;
+
free(udev_device->devpath_old);
udev_device->devpath_old = strdup(devpath_old);
if (udev_device->devpath_old == NULL)
return -ENOMEM;
udev_device_add_property(udev_device, "DEVPATH_OLD", udev_device->devpath_old);
+
+ pos = strrchr(udev_device->devpath_old, '/');
+ if (pos == NULL)
+ return -EINVAL;
+ udev_device->sysname_old = strdup(&pos[1]);
+ if (udev_device->sysname_old == NULL)
+ return -ENOMEM;
+
+ /* some devices have '!' in their name, change that to '/' */
+ len = 0;
+ while (udev_device->sysname_old[len] != '\0') {
+ if (udev_device->sysname_old[len] == '!')
+ udev_device->sysname_old[len] = '/';
+ len++;
+ }
return 0;
}
+const char *udev_device_get_sysname_old(struct udev_device *udev_device)
+{
+ if (udev_device == NULL)
+ return NULL;
+ return udev_device->sysname_old;
+}
+
const char *udev_device_get_knodename(struct udev_device *udev_device)
{
return udev_device->knodename;
diff --git a/libudev/libudev-private.h b/libudev/libudev-private.h
index 16f9f2e1c1..b735298c67 100644
--- a/libudev/libudev-private.h
+++ b/libudev/libudev-private.h
@@ -79,6 +79,7 @@ int udev_device_read_uevent_file(struct udev_device *udev_device);
int udev_device_set_action(struct udev_device *udev_device, const char *action);
int udev_device_set_driver(struct udev_device *udev_device, const char *driver);
const char *udev_device_get_devpath_old(struct udev_device *udev_device);
+const char *udev_device_get_sysname_old(struct udev_device *udev_device);
int udev_device_set_devpath_old(struct udev_device *udev_device, const char *devpath_old);
const char *udev_device_get_knodename(struct udev_device *udev_device);
int udev_device_set_knodename(struct udev_device *udev_device, const char *knodename);
@@ -101,7 +102,7 @@ void udev_device_set_info_loaded(struct udev_device *device);
/* libudev-device-private.c */
int udev_device_update_db(struct udev_device *udev_device);
int udev_device_delete_db(struct udev_device *udev_device);
-int udev_device_rename_db(struct udev_device *udev_device, const char *devpath);
+int udev_device_rename_db(struct udev_device *udev_device);
/* libudev-monitor.c - netlink/unix socket communication */
int udev_monitor_disconnect(struct udev_monitor *udev_monitor);
@@ -186,8 +187,8 @@ int udev_queue_export_device_failed(struct udev_queue_export *udev_queue_export,
/* libudev-util.c */
#define UTIL_PATH_SIZE 1024
-#define UTIL_LINE_SIZE 2048
#define UTIL_NAME_SIZE 512
+#define UTIL_LINE_SIZE 2048
#define UDEV_ALLOWED_CHARS_INPUT "/ $%?,"
ssize_t util_get_sys_subsystem(struct udev *udev, const char *syspath, char *subsystem, size_t size);
ssize_t util_get_sys_driver(struct udev *udev, const char *syspath, char *driver, size_t size);
diff --git a/libudev/libudev-queue-private.c b/libudev/libudev-queue-private.c
index 4dea4ad0e7..e0a8738e0e 100644
--- a/libudev/libudev-queue-private.c
+++ b/libudev/libudev-queue-private.c
@@ -396,16 +396,13 @@ static void update_failed(struct udev_queue_export *udev_queue_export,
{
struct udev *udev = udev_device_get_udev(udev_device);
char filename[UTIL_PATH_SIZE];
- char *s;
- size_t l;
if (state != DEVICE_FAILED && udev_queue_export->failed_count == 0)
return;
/* location of failed file */
- s = filename;
- l = util_strpcpyl(&s, sizeof(filename), udev_get_dev_path(udev_queue_export->udev), "/.udev/failed/", NULL);
- util_path_encode(udev_device_get_devpath(udev_device), s, l);
+ util_strscpyl(filename, sizeof(filename), udev_get_dev_path(udev), "/.udev/failed/",
+ udev_device_get_subsystem(udev_device), ":", udev_device_get_sysname(udev_device), NULL);
switch (state) {
case DEVICE_FAILED:
@@ -428,14 +425,13 @@ static void update_failed(struct udev_queue_export *udev_queue_export,
break;
case DEVICE_FINISHED:
- if (udev_device_get_devpath_old(udev_device) != NULL) {
+ if (udev_device_get_sysname_old(udev_device) != NULL &&
+ strcmp(udev_device_get_sysname_old(udev_device), udev_device_get_sysname(udev_device)) != 0) {
/* "move" event - rename failed file to current name, do not delete failed */
char filename_old[UTIL_PATH_SIZE];
- s = filename_old;
- l = util_strpcpyl(&s, sizeof(filename_old), udev_get_dev_path(udev_queue_export->udev), "/.udev/failed/", NULL);
- util_path_encode(udev_device_get_devpath_old(udev_device), s, l);
-
+ util_strscpyl(filename_old, sizeof(filename_old), udev_get_dev_path(udev), "/.udev/failed/",
+ udev_device_get_subsystem(udev_device), ":", udev_device_get_sysname_old(udev_device), NULL);
if (rename(filename_old, filename) == 0)
info(udev, "renamed devpath, moved failed state of '%s' to %s'\n",
udev_device_get_devpath_old(udev_device), udev_device_get_devpath(udev_device));
diff --git a/test/udev-test.pl b/test/udev-test.pl
index 79ed247d46..aaeec24955 100755
--- a/test/udev-test.pl
+++ b/test/udev-test.pl
@@ -819,9 +819,9 @@ EOF
subsys => "tty",
devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
exp_name => "symlink2-ttyACM0",
- exp_target => "ttyACM0",
+ exp_target => "ttyACM-0",
rules => <<EOF
-KERNEL=="ttyACM[0-9]*", NAME="ttyACM%n", SYMLINK="symlink1-%n symlink2-%k symlink3-%b"
+KERNEL=="ttyACM[0-9]*", NAME="ttyACM-%n", SYMLINK="symlink1-%n symlink2-%k symlink3-%b"
EOF
},
{
diff --git a/udev/udev-event.c b/udev/udev-event.c
index f3c2bd2225..3a6c71abe9 100644
--- a/udev/udev-event.c
+++ b/udev/udev-event.c
@@ -531,10 +531,12 @@ int udev_event_execute_rules(struct udev_event *event, struct udev_rules *rules)
struct udev_device *dev = event->dev;
int err = 0;
- if (udev_device_get_devpath_old(dev) != NULL) {
- if (udev_device_rename_db(dev, udev_device_get_devpath(dev)) == 0)
- info(event->udev, "moved database from '%s' to '%s'\n",
- udev_device_get_devpath_old(dev), udev_device_get_devpath(dev));
+ if (udev_device_get_sysname_old(dev) != NULL &&
+ strcmp(udev_device_get_sysname_old(dev), udev_device_get_sysname(dev)) != 0) {
+ udev_device_rename_db(dev);
+ info(event->udev, "moved database from '%s:%s' to '%s:%s'\n",
+ udev_device_get_subsystem(dev), udev_device_get_sysname_old(dev),
+ udev_device_get_subsystem(dev), udev_device_get_sysname(dev));
}
/* add device node */
diff --git a/udev/udev-node.c b/udev/udev-node.c
index 03ab0ea86f..36f6f6d993 100644
--- a/udev/udev-node.c
+++ b/udev/udev-node.c
@@ -32,24 +32,20 @@
#define TMP_FILE_EXT ".udev-tmp"
/* reverse mapping from the device file name to the devpath */
-static int name_index(struct udev *udev, const char *devpath, const char *name, int add)
+static int name_index(struct udev_device *dev, const char *name, int add)
{
- char devpath_enc[UTIL_PATH_SIZE];
+ struct udev *udev = udev_device_get_udev(dev);
char name_enc[UTIL_PATH_SIZE];
char filename[UTIL_PATH_SIZE * 2];
- int fd;
util_path_encode(&name[strlen(udev_get_dev_path(udev))+1], name_enc, sizeof(name_enc));
- util_path_encode(devpath, devpath_enc, sizeof(devpath_enc));
- util_strscpyl(filename, sizeof(filename), udev_get_dev_path(udev),
- "/.udev/names/", name_enc, "/", devpath_enc, NULL);
+ snprintf(filename, sizeof(filename), "%s/.udev/names/%s/%u:%u", udev_get_dev_path(udev), name_enc,
+ major(udev_device_get_devnum(dev)), minor(udev_device_get_devnum(dev)));
if (add) {
dbg(udev, "creating index: '%s'\n", filename);
util_create_path(udev, filename);
- fd = open(filename, O_WRONLY|O_TRUNC|O_CREAT, 0644);
- if (fd > 0)
- close(fd);
+ symlink(udev_device_get_devpath(dev), filename);
} else {
dbg(udev, "removing index: '%s'\n", filename);
unlink(filename);
@@ -247,18 +243,23 @@ static int name_index_get_devices(struct udev *udev, const char *name, struct ud
dbg(udev, "found index directory '%s'\n", dirname);
while (1) {
- struct dirent *ent;
- char device[UTIL_PATH_SIZE];
+ struct dirent *dent;
+ char devpath[UTIL_PATH_SIZE];
+ char syspath[UTIL_PATH_SIZE];
+ int len;
- ent = readdir(dir);
- if (ent == NULL || ent->d_name[0] == '\0')
+ dent = readdir(dir);
+ if (dent == NULL || dent->d_name[0] == '\0')
break;
- if (ent->d_name[0] == '.')
+ if (dent->d_name[0] == '.')
continue;
- util_strscpyl(device, sizeof(device), udev_get_sys_path(udev), ent->d_name, NULL);
- util_path_decode(device);
- udev_list_entry_add(udev, dev_list, device, NULL, 1, 0);
+ len = readlinkat(dirfd(dir), dent->d_name, devpath, sizeof(devpath));
+ if (len < 0 || (size_t)len >= sizeof(devpath))
+ continue;
+ devpath[len] = '\0';
+ util_strscpyl(syspath, sizeof(syspath), udev_get_sys_path(udev), devpath, NULL);
+ udev_list_entry_add(udev, dev_list, syspath, NULL, 1, 0);
count++;
}
closedir(dir);
@@ -384,7 +385,7 @@ void udev_node_update_old_links(struct udev_device *dev, struct udev_device *dev
info(udev, "update old name, '%s' no longer belonging to '%s'\n",
name, udev_device_get_devpath(dev));
- name_index(udev, udev_device_get_devpath(dev), name, 0);
+ name_index(dev, name, 0);
update_link(dev, name);
}
@@ -398,7 +399,7 @@ void udev_node_update_old_links(struct udev_device *dev, struct udev_device *dev
if (devnode != NULL && strcmp(devnode_old, devnode) != 0) {
info(udev, "node has changed from '%s' to '%s'\n", devnode_old, devnode);
- name_index(udev, udev_device_get_devpath(dev), devnode_old, 0);
+ name_index(dev, devnode_old, 0);
update_link(dev, devnode_old);
}
}
@@ -441,11 +442,11 @@ int udev_node_add(struct udev_device *dev, mode_t mode, uid_t uid, gid_t gid)
}
/* add node to name index */
- name_index(udev, udev_device_get_devpath(dev), udev_device_get_devnode(dev), 1);
+ name_index(dev, udev_device_get_devnode(dev), 1);
/* create/update symlinks, add symlinks to name index */
udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(dev)) {
- name_index(udev, udev_device_get_devpath(dev), udev_list_entry_get_name(list_entry), 1);
+ name_index(dev, udev_list_entry_get_name(list_entry), 1);
update_link(dev, udev_list_entry_get_name(list_entry));
}
exit:
@@ -463,11 +464,11 @@ int udev_node_remove(struct udev_device *dev)
int num;
/* remove node from name index */
- name_index(udev, udev_device_get_devpath(dev), udev_device_get_devnode(dev), 0);
+ name_index(dev, udev_device_get_devnode(dev), 0);
/* remove,update symlinks, remove symlinks from name index */
udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(dev)) {
- name_index(udev, udev_device_get_devpath(dev), udev_list_entry_get_name(list_entry), 0);
+ name_index(dev, udev_list_entry_get_name(list_entry), 0);
update_link(dev, udev_list_entry_get_name(list_entry));
}