X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=libudev%2Flibudev-device-private.c;h=ee9e297cea2ef21770841f16ec932587c1917eef;hp=1bcf441237868c34296d3e7b4cf778436a62a650;hb=b466e9ab3951207a3c0c8d2ba6167be1eac1e41a;hpb=fbb31cd6e10fe66d2da781db0ba9a8d671a4c6aa diff --git a/libudev/libudev-device-private.c b/libudev/libudev-device-private.c index 1bcf44123..ee9e297ce 100644 --- a/libudev/libudev-device-private.c +++ b/libudev/libudev-device-private.c @@ -1,7 +1,7 @@ /* * libudev - interface to udev device information * - * Copyright (C) 2008 Kay Sievers + * Copyright (C) 2008-2010 Kay Sievers * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -21,120 +22,168 @@ #include "libudev.h" #include "libudev-private.h" -int udev_device_update_db(struct udev_device *udev_device) +static void udev_device_tag(struct udev_device *dev, const char *tag, bool add) { - struct udev *udev = udev_device_get_udev(udev_device); + const char *id; + struct udev *udev = udev_device_get_udev(dev); char filename[UTIL_PATH_SIZE]; - char filename_tmp[UTIL_PATH_SIZE]; - FILE *f; - char target[232]; /* on 64bit, tmpfs inlines up to 239 bytes */ - size_t devlen = strlen(udev_get_dev_path(udev))+1; - char *s; - size_t l; + + id = udev_device_get_id_filename(dev); + if (id == NULL) + return; + util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev), "/tags/", tag, "/", id, NULL); + + if (add) { + int fd; + + util_create_path(udev, filename); + fd = open(filename, O_WRONLY|O_CREAT|O_CLOEXEC|O_TRUNC|O_NOFOLLOW, 0444); + if (fd >= 0) + close(fd); + } else { + unlink(filename); + } +} + +int udev_device_tag_index(struct udev_device *dev, struct udev_device *dev_old, bool add) +{ struct udev_list_entry *list_entry; - int ret; + bool found; - 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); - util_strscpyl(filename_tmp, sizeof(filename_tmp), filename, ".tmp", NULL); + if (add && dev_old != NULL) { + /* delete possible left-over tags */ + udev_list_entry_foreach(list_entry, udev_device_get_tags_list_entry(dev_old)) { + const char *tag_old = udev_list_entry_get_name(list_entry); + struct udev_list_entry *list_entry_current; + + found = false; + udev_list_entry_foreach(list_entry_current, udev_device_get_tags_list_entry(dev)) { + const char *tag = udev_list_entry_get_name(list_entry_current); + + if (strcmp(tag, tag_old) == 0) { + found = true; + break; + } + } + if (!found) + udev_device_tag(dev_old, tag_old, false); + } + } + udev_list_entry_foreach(list_entry, udev_device_get_tags_list_entry(dev)) + udev_device_tag(dev, udev_list_entry_get_name(list_entry), add); + + return 0; +} + +static bool device_has_info(struct udev_device *udev_device) +{ + struct udev *udev = udev_device_get_udev(udev_device); + struct udev_list_entry *list_entry; + + if (udev_device_get_devlinks_list_entry(udev_device) != NULL) + return true; + if (udev_device_get_devlink_priority(udev_device) != 0) + return true; udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(udev_device)) if (udev_list_entry_get_flags(list_entry)) - goto file; - if (udev_device_get_num_fake_partitions(udev_device) != 0) - goto file; - if (udev_device_get_ignore_remove(udev_device)) - goto file; - if (udev_device_get_devlink_priority(udev_device) != 0) - goto file; - if (udev_device_get_event_timeout(udev_device) >= 0) - goto file; + return true; + if (udev_device_get_tags_list_entry(udev_device) != NULL) + return true; + if (udev_device_get_devnode(udev_device) != NULL && udev_device_get_knodename(udev_device) != NULL) { + size_t devlen = strlen(udev_get_dev_path(udev))+1; + + if (strcmp(&udev_device_get_devnode(udev_device)[devlen], udev_device_get_knodename(udev_device)) != 0) + return true; + } if (udev_device_get_watch_handle(udev_device) >= 0) - goto file; - if (udev_device_get_devnode(udev_device) == NULL) - goto out; + return true; + return false; +} - /* - * if we have only the node and symlinks to store, try not to waste - * tmpfs memory -- store values, if they fit, in a symlink target - */ - s = target; - l = util_strpcpy(&s, sizeof(target), &udev_device_get_devnode(udev_device)[devlen]); - udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(udev_device)) { - l = util_strpcpyl(&s, l, " ", &udev_list_entry_get_name(list_entry)[devlen], NULL); - if (l == 0) { - info(udev, "size of links too large, create file\n"); - goto file; - } +int udev_device_update_db(struct udev_device *udev_device) +{ + bool has_info; + const char *id; + struct udev *udev = udev_device_get_udev(udev_device); + char filename[UTIL_PATH_SIZE]; + char filename_tmp[UTIL_PATH_SIZE]; + FILE *f; + + id = udev_device_get_id_filename(udev_device); + if (id == NULL) + return -1; + + has_info = device_has_info(udev_device); + util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev), "/data/", id, NULL); + + /* do not store anything for otherwise empty devices */ + if (!has_info && + major(udev_device_get_devnum(udev_device)) == 0 && + udev_device_get_ifindex(udev_device) == 0) { + unlink(filename); + return 0; } - udev_selinux_setfscreatecon(udev, filename_tmp, S_IFLNK); - util_create_path(udev, filename_tmp); - ret = symlink(target, filename_tmp); - udev_selinux_resetfscreatecon(udev); - if (ret != 0) - goto file; - ret = rename(filename_tmp, filename); - if (ret != 0) - goto file; - info(udev, "created db link (%s)\n", target); - goto out; -file: + + /* write a database file */ + util_strscpyl(filename_tmp, sizeof(filename_tmp), filename, ".tmp", NULL); util_create_path(udev, filename_tmp); - f = fopen(filename_tmp, "w"); + f = fopen(filename_tmp, "we"); if (f == NULL) { err(udev, "unable to create temporary db file '%s': %m\n", filename_tmp); return -1; - } - - if (udev_device_get_devnode(udev_device) != NULL) { - fprintf(f, "N:%s\n", &udev_device_get_devnode(udev_device)[devlen]); - udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(udev_device)) - fprintf(f, "S:%s\n", &udev_list_entry_get_name(list_entry)[devlen]); } - if (udev_device_get_devlink_priority(udev_device) != 0) - fprintf(f, "L:%i\n", udev_device_get_devlink_priority(udev_device)); - if (udev_device_get_event_timeout(udev_device) >= 0) - fprintf(f, "T:%i\n", udev_device_get_event_timeout(udev_device)); - if (udev_device_get_num_fake_partitions(udev_device) != 0) - fprintf(f, "A:%i\n", udev_device_get_num_fake_partitions(udev_device)); - if (udev_device_get_ignore_remove(udev_device)) - fprintf(f, "R:%i\n", udev_device_get_ignore_remove(udev_device)); - if (udev_device_get_watch_handle(udev_device) >= 0) - fprintf(f, "W:%i\n", udev_device_get_watch_handle(udev_device)); - udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(udev_device)) { - if (!udev_list_entry_get_flags(list_entry)) - continue; - fprintf(f, "E:%s=%s\n", - udev_list_entry_get_name(list_entry), - udev_list_entry_get_value(list_entry)); + + /* + * set 'sticky' bit to indicate that we should not clean the + * database when we transition from initramfs to the real root + */ + if (udev_device_get_db_persist(udev_device)) + fchmod(fileno(f), 01644); + + if (has_info) { + size_t devlen = strlen(udev_get_dev_path(udev))+1; + struct udev_list_entry *list_entry; + + if (udev_device_get_devnode(udev_device) != NULL) { + fprintf(f, "N:%s\n", &udev_device_get_devnode(udev_device)[devlen]); + udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(udev_device)) + fprintf(f, "S:%s\n", &udev_list_entry_get_name(list_entry)[devlen]); + } + if (udev_device_get_devlink_priority(udev_device) != 0) + fprintf(f, "L:%i\n", udev_device_get_devlink_priority(udev_device)); + if (udev_device_get_watch_handle(udev_device) >= 0) + fprintf(f, "W:%i\n", udev_device_get_watch_handle(udev_device)); + if (udev_device_get_usec_initialized(udev_device) > 0) + fprintf(f, "I:%llu\n", udev_device_get_usec_initialized(udev_device)); + udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(udev_device)) { + if (!udev_list_entry_get_flags(list_entry)) + continue; + fprintf(f, "E:%s=%s\n", + udev_list_entry_get_name(list_entry), + udev_list_entry_get_value(list_entry)); + } + udev_list_entry_foreach(list_entry, udev_device_get_tags_list_entry(udev_device)) + fprintf(f, "G:%s\n", udev_list_entry_get_name(list_entry)); } + fclose(f); rename(filename_tmp, filename); - info(udev, "created db file for '%s' in '%s'\n", udev_device_get_devpath(udev_device), filename); -out: + info(udev, "created %s file '%s' for '%s'\n", has_info ? "db" : "empty", + filename, udev_device_get_devpath(udev_device)); return 0; } 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_run_path(udev), "/data/", id, NULL); unlink(filename); return 0; } - -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]; - - 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); -}