change database file names

With very deeply nested devices, We can not use a single file
name to carry an entire DEVPATH. Use <subsystem>:<sysname> as
the database filename, which should also simplify the handling
of devices moving around, as these values will not change but
still be unique.

For the name stack we use the <maj>:<min> now as the filename.

> On Tue, Aug 18, 2009 at 09:59:56AM -0400, Ric Wheeler wrote:
> The first is that udev grumbles during boot about "file name too long"
> like the following:
>
> Aug 17 06:49:58 megadeth udevd-event[20447]: unable to create db file
> '/dev/.udev/db/\x2fdevices\x2fpci0000:00\x2f0000:00:04.0\x2f0000:17:00.0\x2f0000:18:0a.0\x2f0000:1f:00.0\x2fhost11\x2fport-11:0\x2fexpander-11:0\x2fport-11:0:0\x2fexpander-11:1\x2fport-11:1:0\x2fexpander-11:2\x2fport-11:2:17\x2fexpander-11:3\x2fport-11:3:1\x2fend_device-11:3:1\x2fbsg\x2fend_device-11:3:1':
> File name too long
This commit is contained in:
Kay Sievers 2009-08-19 20:49:49 +02:00
parent 24d1fea8bd
commit 2ffc9cc191
9 changed files with 100 additions and 68 deletions

11
NEWS
View file

@ -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.

8
TODO
View file

@ -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

View file

@ -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);
}

View file

@ -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;

View file

@ -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);

View file

@ -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));

View file

@ -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
},
{

View file

@ -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 */

View file

@ -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));
}