mirror of
https://github.com/systemd/systemd.git
synced 2025-01-11 09:18:07 +03:00
udevd: use dev_t or netif ifindex as database key
We need to preserve the database of network interfaces while we rename them. Use the kernel's numbers wherever possible, instead of the device names. Fix wrong database filenames which contain a '/', translated from '!' in the kernel name. Fix segfault for kobject pathes where the subsystem can not be determined from sysfs.
This commit is contained in:
parent
dc1791a9e6
commit
4281da1fa6
@ -35,7 +35,7 @@ DISTCHECK_HOOKS =
|
||||
# libudev
|
||||
# ------------------------------------------------------------------------------
|
||||
LIBUDEV_CURRENT=9
|
||||
LIBUDEV_REVISION=3
|
||||
LIBUDEV_REVISION=4
|
||||
LIBUDEV_AGE=9
|
||||
|
||||
SUBDIRS += libudev/docs
|
||||
|
@ -24,23 +24,18 @@
|
||||
|
||||
static void udev_device_tag(struct udev_device *dev, const char *tag, bool add)
|
||||
{
|
||||
const char *id;
|
||||
struct udev *udev = udev_device_get_udev(dev);
|
||||
char filename[UTIL_PATH_SIZE];
|
||||
|
||||
util_strscpyl(filename, sizeof(filename), udev_get_dev_path(udev), "/.udev/tags/", tag, "/",
|
||||
udev_device_get_subsystem(dev), ":", udev_device_get_sysname(dev), NULL);
|
||||
id = udev_device_get_id_filename(dev);
|
||||
if (id == NULL)
|
||||
return;
|
||||
util_strscpyl(filename, sizeof(filename), udev_get_dev_path(udev), "/.udev/tags/", tag, "/", id, NULL);
|
||||
|
||||
if (add) {
|
||||
util_create_path(udev, filename);
|
||||
symlink(udev_device_get_devpath(dev), filename);
|
||||
/* possibly cleanup old entries after a device renaming */
|
||||
if (udev_device_get_sysname_old(dev) != NULL) {
|
||||
char filename_old[UTIL_PATH_SIZE];
|
||||
|
||||
util_strscpyl(filename_old, sizeof(filename_old), udev_get_dev_path(udev), "/.udev/tags/", tag, "/",
|
||||
udev_device_get_subsystem(dev), ":", udev_device_get_sysname_old(dev), NULL);
|
||||
unlink(filename_old);
|
||||
}
|
||||
} else {
|
||||
unlink(filename);
|
||||
}
|
||||
@ -79,6 +74,7 @@ int udev_device_tag_index(struct udev_device *dev, struct udev_device *dev_old,
|
||||
|
||||
int udev_device_update_db(struct udev_device *udev_device)
|
||||
{
|
||||
const char *id;
|
||||
struct udev *udev = udev_device_get_udev(udev_device);
|
||||
char filename[UTIL_PATH_SIZE];
|
||||
char filename_tmp[UTIL_PATH_SIZE];
|
||||
@ -90,8 +86,10 @@ int udev_device_update_db(struct udev_device *udev_device)
|
||||
struct udev_list_entry *list_entry;
|
||||
int ret;
|
||||
|
||||
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);
|
||||
id = udev_device_get_id_filename(udev_device);
|
||||
if (id == NULL)
|
||||
return -1;
|
||||
util_strscpyl(filename, sizeof(filename), udev_get_dev_path(udev), "/.udev/db/", id, NULL);
|
||||
util_strscpyl(filename_tmp, sizeof(filename_tmp), filename, ".tmp", NULL);
|
||||
|
||||
udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(udev_device))
|
||||
@ -169,11 +167,14 @@ out:
|
||||
|
||||
int udev_device_delete_db(struct udev_device *udev_device)
|
||||
{
|
||||
const char *id;
|
||||
struct udev *udev = udev_device_get_udev(udev_device);
|
||||
char filename[UTIL_PATH_SIZE];
|
||||
|
||||
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);
|
||||
id = udev_device_get_id_filename(udev_device);
|
||||
if (id == NULL)
|
||||
return -1;
|
||||
util_strscpyl(filename, sizeof(filename), udev_get_dev_path(udev), "/.udev/db/", id, NULL);
|
||||
unlink(filename);
|
||||
return 0;
|
||||
}
|
||||
|
@ -54,6 +54,7 @@ struct udev_device {
|
||||
char *devpath_old;
|
||||
char *sysname_old;
|
||||
char *knodename;
|
||||
char *id_filename;
|
||||
char **envp;
|
||||
char *monitor_buf;
|
||||
size_t monitor_buf_len;
|
||||
@ -230,6 +231,7 @@ const char *udev_device_get_property_value(struct udev_device *udev_device, cons
|
||||
|
||||
int udev_device_read_db(struct udev_device *udev_device)
|
||||
{
|
||||
const char *id;
|
||||
struct stat stats;
|
||||
char filename[UTIL_PATH_SIZE];
|
||||
char line[UTIL_LINE_SIZE];
|
||||
@ -238,8 +240,10 @@ int udev_device_read_db(struct udev_device *udev_device)
|
||||
if (udev_device->db_loaded)
|
||||
return 0;
|
||||
|
||||
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);
|
||||
id = udev_device_get_id_filename(udev_device);
|
||||
if (id == NULL)
|
||||
return -1;
|
||||
util_strscpyl(filename, sizeof(filename), udev_get_dev_path(udev_device->udev), "/.udev/db/", id, NULL);
|
||||
|
||||
if (lstat(filename, &stats) != 0) {
|
||||
dbg(udev_device->udev, "no db file to read %s: %m\n", filename);
|
||||
@ -799,6 +803,7 @@ void udev_device_unref(struct udev_device *udev_device)
|
||||
free(udev_device->devpath_old);
|
||||
free(udev_device->sysname_old);
|
||||
free(udev_device->knodename);
|
||||
free(udev_device->id_filename);
|
||||
free(udev_device->envp);
|
||||
free(udev_device->monitor_buf);
|
||||
dbg(udev_device->udev, "udev_device: %p released\n", udev_device);
|
||||
@ -1287,6 +1292,40 @@ int udev_device_add_devlink(struct udev_device *udev_device, const char *devlink
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *udev_device_get_id_filename(struct udev_device *udev_device)
|
||||
{
|
||||
if (udev_device->id_filename == NULL) {
|
||||
if (udev_device_get_subsystem(udev_device) == NULL)
|
||||
return NULL;
|
||||
|
||||
if (major(udev_device_get_devnum(udev_device)) > 0) {
|
||||
/* use dev_t -- b259:131072, c254:0 */
|
||||
if (asprintf(&udev_device->id_filename, "%c%u:%u",
|
||||
strcmp(udev_device_get_subsystem(udev_device), "block") == 0 ? 'b' : 'c',
|
||||
major(udev_device_get_devnum(udev_device)),
|
||||
minor(udev_device_get_devnum(udev_device))) < 0)
|
||||
udev_device->id_filename = NULL;
|
||||
} else if (strcmp(udev_device_get_subsystem(udev_device), "net") == 0) {
|
||||
/* use netdev ifindex -- n3 */
|
||||
if (asprintf(&udev_device->id_filename, "n%u", udev_device_get_ifindex(udev_device)) < 0)
|
||||
udev_device->id_filename = NULL;
|
||||
} else {
|
||||
/*
|
||||
* use $subsys:$syname -- pci:0000:00:1f.2
|
||||
* sysname() has '!' translated, get it from devpath
|
||||
*/
|
||||
const char *sysname;
|
||||
sysname = strrchr(udev_device->devpath, '/');
|
||||
if (sysname == NULL)
|
||||
return NULL;
|
||||
sysname = &sysname[1];
|
||||
if (asprintf(&udev_device->id_filename, "+%s:%s", udev_device_get_subsystem(udev_device), sysname) < 0)
|
||||
udev_device->id_filename = NULL;
|
||||
}
|
||||
}
|
||||
return udev_device->id_filename;
|
||||
}
|
||||
|
||||
int udev_device_add_tag(struct udev_device *udev_device, const char *tag)
|
||||
{
|
||||
if (strchr(tag, ':') != NULL || strchr(tag, ' ') != NULL)
|
||||
@ -1500,7 +1539,11 @@ int udev_device_get_event_timeout(struct udev_device *udev_device)
|
||||
|
||||
int udev_device_set_event_timeout(struct udev_device *udev_device, int event_timeout)
|
||||
{
|
||||
char num[32];
|
||||
|
||||
udev_device->event_timeout = event_timeout;
|
||||
snprintf(num, sizeof(num), "%u", event_timeout);
|
||||
udev_device_add_property(udev_device, "TIMEOUT", num);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1560,6 +1603,10 @@ int udev_device_get_ifindex(struct udev_device *udev_device)
|
||||
|
||||
int udev_device_set_ifindex(struct udev_device *udev_device, int ifindex)
|
||||
{
|
||||
char num[32];
|
||||
|
||||
udev_device->ifindex = ifindex;
|
||||
snprintf(num, sizeof(num), "%u", ifindex);
|
||||
udev_device_add_property(udev_device, "IFINDEX", num);
|
||||
return 0;
|
||||
}
|
||||
|
@ -85,6 +85,7 @@ 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);
|
||||
const char *udev_device_get_id_filename(struct udev_device *udev_device);
|
||||
int udev_device_add_tag(struct udev_device *udev_device, const char *tag);
|
||||
void udev_device_cleanup_tags_list(struct udev_device *udev_device);
|
||||
int udev_device_has_tag(struct udev_device *udev_device, const char *tag);
|
||||
|
@ -535,6 +535,9 @@ 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_subsystem(dev) == NULL)
|
||||
return -1;
|
||||
|
||||
if (strcmp(udev_device_get_action(dev), "remove") == 0) {
|
||||
udev_device_read_db(dev);
|
||||
udev_device_delete_db(dev);
|
||||
|
@ -298,10 +298,8 @@ static void link_update(struct udev_device *dev, const char *slink, bool add)
|
||||
dbg(udev, "update symlink '%s' of '%s'\n", slink, udev_device_get_syspath(dev));
|
||||
|
||||
util_path_encode(&slink[strlen(udev_get_dev_path(udev))+1], name_enc, sizeof(name_enc));
|
||||
snprintf(dirname, sizeof(dirname), "%s/.udev/links/%s", udev_get_dev_path(udev), name_enc);
|
||||
snprintf(filename, sizeof(filename), "%s/%c%u:%u", dirname,
|
||||
strcmp(udev_device_get_subsystem(dev), "block") == 0 ? 'b' : 'c',
|
||||
major(udev_device_get_devnum(dev)), minor(udev_device_get_devnum(dev)));
|
||||
util_strscpyl(dirname, sizeof(dirname), udev_get_dev_path(udev), "/.udev/links/", name_enc, NULL);
|
||||
util_strscpyl(filename, sizeof(filename), dirname, "/", udev_device_get_id_filename(dev), NULL);
|
||||
|
||||
if (!add) {
|
||||
dbg(udev, "removing index: '%s'\n", filename);
|
||||
|
@ -109,7 +109,6 @@ unlink:
|
||||
void udev_watch_begin(struct udev *udev, struct udev_device *dev)
|
||||
{
|
||||
char filename[UTIL_PATH_SIZE];
|
||||
char majmin[UTIL_PATH_SIZE];
|
||||
int wd;
|
||||
|
||||
if (inotify_fd < 0)
|
||||
@ -123,13 +122,10 @@ void udev_watch_begin(struct udev *udev, struct udev_device *dev)
|
||||
return;
|
||||
}
|
||||
|
||||
snprintf(majmin, sizeof(majmin), "%c%i:%i",
|
||||
strcmp(udev_device_get_subsystem(dev), "block") == 0 ? 'b' : 'c',
|
||||
major(udev_device_get_devnum(dev)), minor(udev_device_get_devnum(dev)));
|
||||
snprintf(filename, sizeof(filename), "%s/.udev/watch/%d", udev_get_dev_path(udev), wd);
|
||||
util_create_path(udev, filename);
|
||||
unlink(filename);
|
||||
symlink(majmin, filename);
|
||||
symlink(udev_device_get_id_filename(dev), filename);
|
||||
|
||||
udev_device_set_watch_handle(dev, wd);
|
||||
}
|
||||
|
@ -195,6 +195,60 @@ static int export_devices(struct udev *udev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int convert_db(struct udev *udev)
|
||||
{
|
||||
struct udev_enumerate *udev_enumerate;
|
||||
struct udev_list_entry *list_entry;
|
||||
|
||||
udev_enumerate = udev_enumerate_new(udev);
|
||||
if (udev_enumerate == NULL)
|
||||
return -1;
|
||||
udev_enumerate_scan_devices(udev_enumerate);
|
||||
udev_list_entry_foreach(list_entry, udev_enumerate_get_list_entry(udev_enumerate)) {
|
||||
struct udev_device *device;
|
||||
|
||||
device = udev_device_new_from_syspath(udev, udev_list_entry_get_name(list_entry));
|
||||
if (device != NULL) {
|
||||
const char *id;
|
||||
struct stat statbuf;
|
||||
char to[UTIL_PATH_SIZE];
|
||||
char devpath[UTIL_PATH_SIZE];
|
||||
char from[UTIL_PATH_SIZE];
|
||||
|
||||
id = udev_device_get_id_filename(device);
|
||||
if (id == NULL)
|
||||
goto next;
|
||||
util_strscpyl(to, sizeof(to), udev_get_dev_path(udev), "/.udev/db/", id, NULL);
|
||||
|
||||
/* do not overwrite a new database file */
|
||||
if (lstat(to, &statbuf) == 0)
|
||||
goto next;
|
||||
|
||||
/* find old database with $subsys:$sysname */
|
||||
util_strscpyl(from, sizeof(from), udev_get_dev_path(udev),
|
||||
"/.udev/db/", udev_device_get_subsystem(device), ":",
|
||||
udev_device_get_sysname(device), NULL);
|
||||
if (lstat(from, &statbuf) == 0) {
|
||||
rename(from, to);
|
||||
goto next;
|
||||
}
|
||||
|
||||
/* find old database with the encoded devpath */
|
||||
util_path_encode(udev_device_get_devpath(device), devpath, sizeof(devpath));
|
||||
util_strscpyl(from, sizeof(from), udev_get_dev_path(udev),
|
||||
"/.udev/db/", devpath, NULL);
|
||||
if (lstat(from, &statbuf) == 0) {
|
||||
rename(from, to);
|
||||
goto next;
|
||||
}
|
||||
next:
|
||||
udev_device_unref(device);
|
||||
}
|
||||
}
|
||||
udev_enumerate_unref(udev_enumerate);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int udevadm_info(struct udev *udev, int argc, char *argv[])
|
||||
{
|
||||
struct udev_device *device = NULL;
|
||||
@ -212,6 +266,7 @@ int udevadm_info(struct udev *udev, int argc, char *argv[])
|
||||
{ "query", required_argument, NULL, 'q' },
|
||||
{ "attribute-walk", no_argument, NULL, 'a' },
|
||||
{ "export-db", no_argument, NULL, 'e' },
|
||||
{ "convert-db", no_argument, NULL, 'C' },
|
||||
{ "root", no_argument, NULL, 'r' },
|
||||
{ "device-id-of-file", required_argument, NULL, 'd' },
|
||||
{ "export", no_argument, NULL, 'x' },
|
||||
@ -336,6 +391,9 @@ int udevadm_info(struct udev *udev, int argc, char *argv[])
|
||||
case 'e':
|
||||
export_devices(udev);
|
||||
goto exit;
|
||||
case 'C':
|
||||
convert_db(udev);
|
||||
goto exit;
|
||||
case 'x':
|
||||
export = true;
|
||||
break;
|
||||
@ -359,7 +417,10 @@ int udevadm_info(struct udev *udev, int argc, char *argv[])
|
||||
" --attribute-walk print all key matches while walking along the chain\n"
|
||||
" of parent devices\n"
|
||||
" --device-id-of-file=<file> print major:minor of device containing this file\n"
|
||||
" --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"
|
||||
" --convert-db convert older version of database without a reboot\n"
|
||||
" --help\n\n");
|
||||
goto exit;
|
||||
default:
|
||||
|
@ -143,6 +143,15 @@
|
||||
<para>Export the content of the udev database.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>--convert-db</option></term>
|
||||
<listitem>
|
||||
<para>Convert the database of an earlier udev version to the current format. This
|
||||
is only useful on udev version upgrades, where the content of the old database might
|
||||
be needed for the running system, and it is not sufficient for it, to be re-created
|
||||
with the next bootup.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>--version</option></term>
|
||||
<listitem>
|
||||
|
Loading…
Reference in New Issue
Block a user