# libudev
# ------------------------------------------------------------------------------
LIBUDEV_CURRENT=9
-LIBUDEV_REVISION=3
+LIBUDEV_REVISION=4
LIBUDEV_AGE=9
SUBDIRS += libudev/docs
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);
}
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];
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))
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;
}
char *devpath_old;
char *sysname_old;
char *knodename;
+ char *id_filename;
char **envp;
char *monitor_buf;
size_t monitor_buf_len;
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];
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);
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);
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)
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;
}
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;
}
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);
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);
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);
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)
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);
}
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;
{ "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' },
case 'e':
export_devices(udev);
goto exit;
+ case 'C':
+ convert_db(udev);
+ goto exit;
case 'x':
export = true;
break;
" --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:
<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>