========
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.
+ 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
#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);
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))
}
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);
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);
}
char *driver;
char *action;
char *devpath_old;
+ char *sysname_old;
char *knodename;
char **envp;
char *monitor_buf;
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;
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);
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);
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;
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);
/* 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);
/* 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);
{
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:
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));
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
},
{
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 */
#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);
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);
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);
}
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);
}
}
}
/* 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:
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));
}