2 This file is part of systemd.
4 Copyright 2008-2012 Kay Sievers <kay@vrfy.org>
5 Copyright 2014 Tom Gundersen <teg@jklm.no>
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
22 #include <sys/types.h>
27 #include "path-util.h"
34 #include "sd-device.h"
36 #include "device-util.h"
37 #include "device-private.h"
38 #include "device-internal.h"
40 int device_new_aux(sd_device **ret) {
41 _cleanup_device_unref_ sd_device *device = NULL;
45 device = new0(sd_device, 1);
50 device->watch_handle = -1;
58 _public_ sd_device *sd_device_ref(sd_device *device) {
60 assert_se(++ device->n_ref >= 2);
65 _public_ sd_device *sd_device_unref(sd_device *device) {
66 if (device && -- device->n_ref == 0) {
67 sd_device_unref(device->parent);
68 free(device->syspath);
69 free(device->sysname);
70 free(device->devtype);
71 free(device->devname);
72 free(device->subsystem);
74 free(device->id_filename);
75 free(device->properties_strv);
76 free(device->properties_nulstr);
78 ordered_hashmap_free_free_free(device->properties);
79 ordered_hashmap_free_free_free(device->properties_db);
80 hashmap_free_free_free(device->sysattr_values);
81 set_free_free(device->sysattrs);
82 set_free_free(device->tags);
83 set_free_free(device->devlinks);
91 int device_add_property_aux(sd_device *device, const char *_key, const char *_value, bool db) {
92 OrderedHashmap **properties;
98 properties = &device->properties_db;
100 properties = &device->properties;
103 _cleanup_free_ char *key = NULL, *value = NULL, *old_key = NULL, *old_value = NULL;
106 r = ordered_hashmap_ensure_allocated(properties, &string_hash_ops);
114 value = strdup(_value);
118 old_value = ordered_hashmap_get2(*properties, key, (void**) &old_key);
120 r = ordered_hashmap_replace(*properties, key, value);
127 _cleanup_free_ char *key = NULL;
128 _cleanup_free_ char *value = NULL;
130 value = ordered_hashmap_remove2(*properties, _key, (void**) &key);
134 device->properties_generation ++;
135 device->properties_buf_outdated = true;
141 int device_add_property_internal(sd_device *device, const char *key, const char *value) {
142 return device_add_property_aux(device, key, value, false);
145 int device_set_syspath(sd_device *device, const char *_syspath, bool verify) {
146 _cleanup_free_ char *syspath = NULL;
153 /* must be a subdirectory of /sys */
154 if (!path_startswith(_syspath, "/sys/")) {
155 log_debug("sd-device: syspath '%s' is not a subdirectory of /sys", _syspath);
160 r = readlink_and_canonicalize(_syspath, &syspath);
162 /* the device does not exist (any more?) */
164 else if (r == -EINVAL) {
166 syspath = canonicalize_file_name(_syspath);
169 /* the device does not exist (any more?) */
172 log_debug("sd-device: could not canonicalize '%s': %m", _syspath);
176 log_debug("sd-device: could not get target of '%s': %s", _syspath, strerror(-r));
180 if (path_startswith(syspath, "/sys/devices/")) {
183 /* all 'devices' require an 'uevent' file */
184 path = strjoina(syspath, "/uevent");
185 r = access(path, F_OK);
188 /* this is not a valid device */
191 log_debug("sd-device: %s does not have an uevent file: %m", syspath);
195 /* everything else just just needs to be a directory */
196 if (!is_dir(syspath, false))
200 syspath = strdup(_syspath);
205 devpath = syspath + strlen("/sys");
207 r = device_add_property_internal(device, "DEVPATH", devpath);
211 free(device->syspath);
212 device->syspath = syspath;
215 device->devpath = devpath;
220 _public_ int sd_device_new_from_syspath(sd_device **ret, const char *syspath) {
221 _cleanup_device_unref_ sd_device *device = NULL;
224 assert_return(ret, -EINVAL);
225 assert_return(syspath, -EINVAL);
227 r = device_new_aux(&device);
231 r = device_set_syspath(device, syspath, true);
241 _public_ int sd_device_new_from_devnum(sd_device **ret, char type, dev_t devnum) {
243 char id[DECIMAL_STR_MAX(unsigned) * 2 + 1];
245 assert_return(ret, -EINVAL);
246 assert_return(type == 'b' || type == 'c', -EINVAL);
248 /* use /sys/dev/{block,char}/<maj>:<min> link */
249 snprintf(id, sizeof(id), "%u:%u", major(devnum), minor(devnum));
251 syspath = strjoina("/sys/dev/", (type == 'b' ? "block" : "char"), "/", id);
253 return sd_device_new_from_syspath(ret, syspath);
256 _public_ int sd_device_new_from_subsystem_sysname(sd_device **ret, const char *subsystem, const char *sysname) {
259 assert_return(ret, -EINVAL);
260 assert_return(subsystem, -EINVAL);
261 assert_return(sysname, -EINVAL);
263 if (streq(subsystem, "subsystem")) {
264 syspath = strjoina("/sys/subsystem/", sysname);
265 if (access(syspath, F_OK) >= 0)
266 return sd_device_new_from_syspath(ret, syspath);
268 syspath = strjoina("/sys/bus/", sysname);
269 if (access(syspath, F_OK) >= 0)
270 return sd_device_new_from_syspath(ret, syspath);
272 syspath = strjoina("/sys/class/", sysname);
273 if (access(syspath, F_OK) >= 0)
274 return sd_device_new_from_syspath(ret, syspath);
275 } else if (streq(subsystem, "module")) {
276 syspath = strjoina("/sys/module/", sysname);
277 if (access(syspath, F_OK) >= 0)
278 return sd_device_new_from_syspath(ret, syspath);
279 } else if (streq(subsystem, "drivers")) {
280 char subsys[PATH_MAX];
283 strscpy(subsys, sizeof(subsys), sysname);
284 driver = strchr(subsys, ':');
289 syspath = strjoina("/sys/subsystem/", subsys, "/drivers/", driver);
290 if (access(syspath, F_OK) >= 0)
291 return sd_device_new_from_syspath(ret, syspath);
293 syspath = strjoina("/sys/bus/", subsys, "/drivers/", driver);
294 if (access(syspath, F_OK) >= 0)
295 return sd_device_new_from_syspath(ret, syspath);
299 syspath = strjoina("/sys/subsystem/", subsystem, "/devices/", sysname);
300 if (access(syspath, F_OK) >= 0)
301 return sd_device_new_from_syspath(ret, syspath);
303 syspath = strjoina("/sys/bus/", subsystem, "/devices/", sysname);
304 if (access(syspath, F_OK) >= 0)
305 return sd_device_new_from_syspath(ret, syspath);
307 syspath = strjoina("/sys/class/", subsystem, "/", sysname);
308 if (access(syspath, F_OK) >= 0)
309 return sd_device_new_from_syspath(ret, syspath);
315 int device_set_devtype(sd_device *device, const char *_devtype) {
316 _cleanup_free_ char *devtype = NULL;
322 devtype = strdup(_devtype);
326 r = device_add_property_internal(device, "DEVTYPE", devtype);
330 free(device->devtype);
331 device->devtype = devtype;
337 int device_set_ifindex(sd_device *device, const char *_ifindex) {
343 r = safe_atoi(_ifindex, &ifindex);
350 r = device_add_property_internal(device, "IFINDEX", _ifindex);
354 device->ifindex = ifindex;
359 int device_set_devname(sd_device *device, const char *_devname) {
360 _cleanup_free_ char *devname = NULL;
366 if (_devname[0] != '/') {
367 r = asprintf(&devname, "/dev/%s", _devname);
371 devname = strdup(_devname);
376 r = device_add_property_internal(device, "DEVNAME", devname);
380 free(device->devname);
381 device->devname = devname;
387 int device_set_devmode(sd_device *device, const char *_devmode) {
394 r = safe_atou(_devmode, &devmode);
401 r = device_add_property_internal(device, "DEVMODE", _devmode);
405 device->devmode = devmode;
410 int device_set_devnum(sd_device *device, const char *major, const char *minor) {
411 unsigned maj = 0, min = 0;
417 r = safe_atou(major, &maj);
424 r = safe_atou(minor, &min);
429 r = device_add_property_internal(device, "MAJOR", major);
434 r = device_add_property_internal(device, "MINOR", minor);
439 device->devnum = makedev(maj, min);
444 static int handle_uevent_line(sd_device *device, const char *key, const char *value, const char **major, const char **minor) {
453 if (streq(key, "DEVTYPE")) {
454 r = device_set_devtype(device, value);
457 } else if (streq(key, "IFINDEX")) {
458 r = device_set_ifindex(device, value);
461 } else if (streq(key, "DEVNAME")) {
462 r = device_set_devname(device, value);
465 } else if (streq(key, "DEVMODE")) {
466 r = device_set_devmode(device, value);
469 } else if (streq(key, "MAJOR"))
471 else if (streq(key, "MINOR"))
474 r = device_add_property_internal(device, key, value);
482 int device_read_uevent_file(sd_device *device) {
483 _cleanup_free_ char *uevent = NULL;
484 const char *syspath, *key, *value, *major = NULL, *minor = NULL;
500 if (device->uevent_loaded || device->sealed)
503 device->uevent_loaded = true;
505 r = sd_device_get_syspath(device, &syspath);
509 path = strjoina(syspath, "/uevent");
511 r = read_full_file(path, &uevent, &uevent_len);
513 /* empty uevent files may be write-only */
515 else if (r == -ENOENT)
516 /* some devices may not have uevent files, see set_syspath() */
519 log_debug("sd-device: failed to read uevent file '%s': %s", path, strerror(-r));
523 for (i = 0; i < uevent_len; i++) {
526 if (!strchr(NEWLINE, uevent[i])) {
534 if (uevent[i] == '=') {
538 } else if (strchr(NEWLINE, uevent[i])) {
540 log_debug("sd-device: ignoring invalid uevent line '%s'", key);
553 if (strchr(NEWLINE, uevent[i])) {
556 r = handle_uevent_line(device, key, value, &major, &minor);
558 log_debug("sd-device: failed to handle uevent entry '%s=%s': %s", key, value, strerror(-r));
565 assert_not_reached("invalid state when parsing uevent file");
570 r = device_set_devnum(device, major, minor);
572 log_debug("sd-device: could not set 'MAJOR=%s' or 'MINOR=%s' from '%s': %s", major, minor, path, strerror(-r));
578 _public_ int sd_device_get_ifindex(sd_device *device, int *ifindex) {
581 assert_return(device, -EINVAL);
582 assert_return(ifindex, -EINVAL);
584 r = device_read_uevent_file(device);
588 *ifindex = device->ifindex;
593 _public_ int sd_device_new_from_device_id(sd_device **ret, const char *id) {
596 assert_return(ret, -EINVAL);
597 assert_return(id, -EINVAL);
606 r = sscanf(id, "%c%i:%i", &type, &maj, &min);
610 return sd_device_new_from_devnum(ret, type, makedev(maj, min));
614 _cleanup_device_unref_ sd_device *device = NULL;
615 _cleanup_close_ int sk = -1;
616 struct ifreq ifr = {};
619 r = safe_atoi(&id[1], &ifr.ifr_ifindex);
622 else if (ifr.ifr_ifindex <= 0)
625 sk = socket(PF_INET, SOCK_DGRAM, 0);
629 r = ioctl(sk, SIOCGIFNAME, &ifr);
633 r = sd_device_new_from_subsystem_sysname(&device, "net", ifr.ifr_name);
637 r = sd_device_get_ifindex(device, &ifindex);
641 /* this is racey, so we might end up with the wrong device */
642 if (ifr.ifr_ifindex != ifindex)
652 char subsys[PATH_MAX];
655 (void)strscpy(subsys, sizeof(subsys), id + 1);
656 sysname = strchr(subsys, ':');
663 return sd_device_new_from_subsystem_sysname(ret, subsys, sysname);
670 _public_ int sd_device_get_syspath(sd_device *device, const char **ret) {
671 assert_return(device, -EINVAL);
672 assert_return(ret, -EINVAL);
674 assert(path_startswith(device->syspath, "/sys/"));
676 *ret = device->syspath;
681 static int device_new_from_child(sd_device **ret, sd_device *child) {
682 _cleanup_free_ char *path = NULL;
683 const char *subdir, *syspath;
689 r = sd_device_get_syspath(child, &syspath);
693 path = strdup(syspath);
696 subdir = path + strlen("/sys");
701 pos = strrchr(subdir, '/');
702 if (!pos || pos < subdir + 2)
707 r = sd_device_new_from_syspath(ret, path);
717 _public_ int sd_device_get_parent(sd_device *child, sd_device **ret) {
719 assert_return(ret, -EINVAL);
720 assert_return(child, -EINVAL);
722 if (!child->parent_set) {
723 child->parent_set = true;
725 (void)device_new_from_child(&child->parent, child);
731 *ret = child->parent;
736 int device_set_subsystem(sd_device *device, const char *_subsystem) {
737 _cleanup_free_ char *subsystem = NULL;
743 subsystem = strdup(_subsystem);
747 r = device_add_property_internal(device, "SUBSYSTEM", subsystem);
751 free(device->subsystem);
752 device->subsystem = subsystem;
755 device->subsystem_set = true;
760 _public_ int sd_device_get_subsystem(sd_device *device, const char **ret) {
761 assert_return(ret, -EINVAL);
762 assert_return(device, -EINVAL);
764 if (!device->subsystem_set) {
765 _cleanup_free_ char *subsystem = NULL;
770 /* read 'subsystem' link */
771 r = sd_device_get_syspath(device, &syspath);
775 path = strjoina(syspath, "/subsystem");
776 r = readlink_value(path, &subsystem);
778 r = device_set_subsystem(device, subsystem);
779 /* use implicit names */
780 else if (path_startswith(device->devpath, "/module/"))
781 r = device_set_subsystem(device, "module");
782 else if (strstr(device->devpath, "/drivers/"))
783 r = device_set_subsystem(device, "drivers");
784 else if (path_startswith(device->devpath, "/subsystem/") ||
785 path_startswith(device->devpath, "/class/") ||
786 path_startswith(device->devpath, "/bus/"))
787 r = device_set_subsystem(device, "subsystem");
788 if (r < 0 && r != -ENOENT)
789 return log_debug_errno(r, "sd-device: could not set subsystem for %s: %m", device->devpath);
791 device->subsystem_set = true;
794 if (!device->subsystem)
797 *ret = device->subsystem;
802 _public_ int sd_device_get_devtype(sd_device *device, const char **devtype) {
808 r = device_read_uevent_file(device);
812 *devtype = device->devtype;
817 _public_ int sd_device_get_parent_with_subsystem_devtype(sd_device *child, const char *subsystem, const char *devtype, sd_device **ret) {
818 sd_device *parent = NULL;
821 assert_return(child, -EINVAL);
822 assert_return(subsystem, -EINVAL);
824 r = sd_device_get_parent(child, &parent);
826 const char *parent_subsystem = NULL;
827 const char *parent_devtype = NULL;
829 (void)sd_device_get_subsystem(parent, &parent_subsystem);
830 if (streq_ptr(parent_subsystem, subsystem)) {
834 (void)sd_device_get_devtype(parent, &parent_devtype);
835 if (streq_ptr(parent_devtype, devtype))
838 r = sd_device_get_parent(parent, &parent);
849 _public_ int sd_device_get_devnum(sd_device *device, dev_t *devnum) {
852 assert_return(device, -EINVAL);
853 assert_return(devnum, -EINVAL);
855 r = device_read_uevent_file(device);
859 *devnum = device->devnum;
864 int device_set_driver(sd_device *device, const char *_driver) {
865 _cleanup_free_ char *driver = NULL;
871 driver = strdup(_driver);
875 r = device_add_property_internal(device, "DRIVER", driver);
879 free(device->driver);
880 device->driver = driver;
883 device->driver_set = true;
888 _public_ int sd_device_get_driver(sd_device *device, const char **ret) {
889 assert_return(device, -EINVAL);
890 assert_return(ret, -EINVAL);
892 if (!device->driver_set) {
893 _cleanup_free_ char *driver = NULL;
898 r = sd_device_get_syspath(device, &syspath);
902 path = strjoina(syspath, "/driver");
903 r = readlink_value(path, &driver);
905 r = device_set_driver(device, driver);
907 return log_debug_errno(r, "sd-device: could not set driver for %s: %m", device->devpath);
908 } else if (r == -ENOENT)
909 device->driver_set = true;
911 return log_debug_errno(r, "sd-device: could not set driver for %s: %m", device->devpath);
917 *ret = device->driver;
922 _public_ int sd_device_get_devpath(sd_device *device, const char **devpath) {
923 assert_return(device, -EINVAL);
924 assert_return(devpath, -EINVAL);
926 assert(device->devpath);
927 assert(device->devpath[0] == '/');
929 *devpath = device->devpath;
934 _public_ int sd_device_get_devname(sd_device *device, const char **devname) {
937 assert_return(device, -EINVAL);
938 assert_return(devname, -EINVAL);
940 r = device_read_uevent_file(device);
944 if (!device->devname)
947 assert(path_startswith(device->devname, "/dev/"));
949 *devname = device->devname;
954 static int device_set_sysname(sd_device *device) {
955 _cleanup_free_ char *sysname = NULL;
956 const char *sysnum = NULL;
960 pos = strrchr(device->devpath, '/');
965 /* devpath is not a root directory */
966 if (*pos == '\0' || pos <= device->devpath)
969 sysname = strdup(pos);
973 /* some devices have '!' in their name, change that to '/' */
974 while (sysname[len] != '\0') {
975 if (sysname[len] == '!')
981 /* trailing number */
982 while (len > 0 && isdigit(sysname[--len]))
983 sysnum = &sysname[len];
988 free(device->sysname);
989 device->sysname = sysname;
992 device->sysnum = sysnum;
994 device->sysname_set = true;
999 _public_ int sd_device_get_sysname(sd_device *device, const char **ret) {
1002 assert_return(device, -EINVAL);
1003 assert_return(ret, -EINVAL);
1005 if (!device->sysname_set) {
1006 r = device_set_sysname(device);
1011 assert_return(device->sysname, -ENOENT);
1013 *ret = device->sysname;
1018 _public_ int sd_device_get_sysnum(sd_device *device, const char **ret) {
1021 assert_return(device, -EINVAL);
1022 assert_return(ret, -EINVAL);
1024 if (!device->sysname_set) {
1025 r = device_set_sysname(device);
1030 *ret = device->sysnum;
1035 static bool is_valid_tag(const char *tag) {
1038 return !strchr(tag, ':') && !strchr(tag, ' ');
1041 int device_add_tag(sd_device *device, const char *tag) {
1047 if (!is_valid_tag(tag))
1050 r = set_ensure_allocated(&device->tags, &string_hash_ops);
1054 r = set_put_strdup(device->tags, tag);
1058 device->tags_generation ++;
1059 device->property_tags_outdated = true;
1064 int device_add_devlink(sd_device *device, const char *devlink) {
1070 r = set_ensure_allocated(&device->devlinks, &string_hash_ops);
1074 r = set_put_strdup(device->devlinks, devlink);
1078 device->devlinks_generation ++;
1079 device->property_devlinks_outdated = true;
1084 static int device_add_property_internal_from_string(sd_device *device, const char *str) {
1085 _cleanup_free_ char *key = NULL;
1095 value = strchr(key, '=');
1101 if (isempty(++value))
1104 return device_add_property_internal(device, key, value);
1107 int device_set_usec_initialized(sd_device *device, const char *initialized) {
1108 uint64_t usec_initialized;
1112 assert(initialized);
1114 r = safe_atou64(initialized, &usec_initialized);
1118 r = device_add_property_internal(device, "USEC_INITIALIZED", initialized);
1122 device->usec_initialized = usec_initialized;
1127 static int handle_db_line(sd_device *device, char key, const char *value) {
1136 r = device_add_tag(device, value);
1142 path = strjoina("/dev/", value);
1143 r = device_add_devlink(device, path);
1149 r = device_add_property_internal_from_string(device, value);
1155 r = device_set_usec_initialized(device, value);
1161 r = safe_atoi(value, &device->devlink_priority);
1167 r = safe_atoi(value, &device->watch_handle);
1173 log_debug("device db: unknown key '%c'", key);
1179 int device_get_id_filename(sd_device *device, const char **ret) {
1183 if (!device->id_filename) {
1184 _cleanup_free_ char *id = NULL;
1185 const char *subsystem;
1189 r = sd_device_get_subsystem(device, &subsystem);
1193 r = sd_device_get_devnum(device, &devnum);
1197 r = sd_device_get_ifindex(device, &ifindex);
1201 if (major(devnum) > 0) {
1204 /* use dev_t -- b259:131072, c254:0 */
1205 r = asprintf(&id, "%c%u:%u",
1206 streq(subsystem, "block") ? 'b' : 'c',
1207 major(devnum), minor(devnum));
1210 } else if (ifindex > 0) {
1211 /* use netdev ifindex -- n3 */
1212 r = asprintf(&id, "n%u", ifindex);
1216 /* use $subsys:$sysname -- pci:0000:00:1f.2
1217 * sysname() has '!' translated, get it from devpath
1219 const char *sysname;
1221 sysname = basename(device->devpath);
1228 r = asprintf(&id, "+%s:%s", subsystem, sysname);
1233 device->id_filename = id;
1237 *ret = device->id_filename;
1242 int device_read_db_aux(sd_device *device, bool force) {
1243 _cleanup_free_ char *db = NULL;
1245 const char *id, *value;
1259 if (device->db_loaded || (!force && device->sealed))
1262 device->db_loaded = true;
1264 r = device_get_id_filename(device, &id);
1268 path = strjoina("/run/udev/data/", id);
1270 r = read_full_file(path, &db, &db_len);
1275 log_debug("sd-device: failed to read db '%s': %s", path, strerror(-r));
1280 /* devices with a database entry are initialized */
1281 device->is_initialized = true;
1283 for (i = 0; i < db_len; i++) {
1286 if (!strchr(NEWLINE, db[i])) {
1295 log_debug("sd-device: ignoring invalid db entry with key '%c'", key);
1297 state = INVALID_LINE;
1312 if (strchr(NEWLINE, db[i]))
1317 if (strchr(NEWLINE, db[i])) {
1319 r = handle_db_line(device, key, value);
1321 log_debug("sd-device: failed to handle db entry '%c:%s': %s", key, value, strerror(-r));
1328 assert_not_reached("invalid state when parsing db");
1335 static int device_read_db(sd_device *device) {
1336 return device_read_db_aux(device, false);
1339 _public_ int sd_device_get_is_initialized(sd_device *device, int *initialized) {
1342 assert_return(device, -EINVAL);
1343 assert_return(initialized, -EINVAL);
1345 r = device_read_db(device);
1349 *initialized = device->is_initialized;
1354 _public_ int sd_device_get_usec_since_initialized(sd_device *device, uint64_t *usec) {
1358 assert_return(device, -EINVAL);
1359 assert_return(usec, -EINVAL);
1361 r = device_read_db(device);
1365 if (!device->is_initialized)
1368 if (!device->usec_initialized)
1371 now_ts = now(clock_boottime_or_monotonic());
1373 if (now_ts < device->usec_initialized)
1376 *usec = now_ts - device->usec_initialized;
1381 _public_ const char *sd_device_get_tag_first(sd_device *device) {
1384 assert_return(device, NULL);
1386 (void) device_read_db(device);
1388 device->tags_iterator_generation = device->tags_generation;
1389 device->tags_iterator = ITERATOR_FIRST;
1391 set_iterate(device->tags, &device->tags_iterator, &v);
1395 _public_ const char *sd_device_get_tag_next(sd_device *device) {
1398 assert_return(device, NULL);
1400 (void) device_read_db(device);
1402 if (device->tags_iterator_generation != device->tags_generation)
1405 set_iterate(device->tags, &device->tags_iterator, &v);
1409 _public_ const char *sd_device_get_devlink_first(sd_device *device) {
1412 assert_return(device, NULL);
1414 (void) device_read_db(device);
1416 device->devlinks_iterator_generation = device->devlinks_generation;
1417 device->devlinks_iterator = ITERATOR_FIRST;
1419 set_iterate(device->devlinks, &device->devlinks_iterator, &v);
1423 _public_ const char *sd_device_get_devlink_next(sd_device *device) {
1426 assert_return(device, NULL);
1428 (void) device_read_db(device);
1430 if (device->devlinks_iterator_generation != device->devlinks_generation)
1433 set_iterate(device->devlinks, &device->devlinks_iterator, &v);
1437 static int device_properties_prepare(sd_device *device) {
1442 r = device_read_uevent_file(device);
1446 r = device_read_db(device);
1450 if (device->property_devlinks_outdated) {
1451 char *devlinks = NULL;
1452 const char *devlink;
1454 devlink = sd_device_get_devlink_first(device);
1456 devlinks = strdupa(devlink);
1458 while ((devlink = sd_device_get_devlink_next(device)))
1459 devlinks = strjoina(devlinks, " ", devlink);
1461 r = device_add_property_internal(device, "DEVLINKS", devlinks);
1465 device->property_devlinks_outdated = false;
1468 if (device->property_tags_outdated) {
1472 tag = sd_device_get_tag_first(device);
1474 tags = strjoina(":", tag);
1476 while ((tag = sd_device_get_tag_next(device)))
1477 tags = strjoina(tags, ":", tag);
1479 tags = strjoina(tags, ":");
1481 r = device_add_property_internal(device, "TAGS", tags);
1485 device->property_tags_outdated = false;
1491 _public_ const char *sd_device_get_property_first(sd_device *device, const char **_value) {
1496 assert_return(device, NULL);
1498 r = device_properties_prepare(device);
1502 device->properties_iterator_generation = device->properties_generation;
1503 device->properties_iterator = ITERATOR_FIRST;
1505 ordered_hashmap_iterate(device->properties, &device->properties_iterator, (void**)&value, (const void**)&key);
1513 _public_ const char *sd_device_get_property_next(sd_device *device, const char **_value) {
1518 assert_return(device, NULL);
1520 r = device_properties_prepare(device);
1524 if (device->properties_iterator_generation != device->properties_generation)
1527 ordered_hashmap_iterate(device->properties, &device->properties_iterator, (void**)&value, (const void**)&key);
1535 static int device_sysattrs_read_all(sd_device *device) {
1536 _cleanup_closedir_ DIR *dir = NULL;
1537 const char *syspath;
1538 struct dirent *dent;
1543 if (device->sysattrs_read)
1546 r = sd_device_get_syspath(device, &syspath);
1550 dir = opendir(syspath);
1554 r = set_ensure_allocated(&device->sysattrs, &string_hash_ops);
1558 for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
1560 struct stat statbuf;
1562 /* only handle symlinks and regular files */
1563 if (dent->d_type != DT_LNK && dent->d_type != DT_REG)
1566 path = strjoina(syspath, "/", dent->d_name);
1568 if (lstat(path, &statbuf) != 0)
1571 if (!(statbuf.st_mode & S_IRUSR))
1574 r = set_put_strdup(device->sysattrs, dent->d_name);
1579 device->sysattrs_read = true;
1584 _public_ const char *sd_device_get_sysattr_first(sd_device *device) {
1588 assert_return(device, NULL);
1590 if (!device->sysattrs_read) {
1591 r = device_sysattrs_read_all(device);
1598 device->sysattrs_iterator = ITERATOR_FIRST;
1600 set_iterate(device->sysattrs, &device->sysattrs_iterator, &v);
1604 _public_ const char *sd_device_get_sysattr_next(sd_device *device) {
1607 assert_return(device, NULL);
1609 if (!device->sysattrs_read)
1612 set_iterate(device->sysattrs, &device->sysattrs_iterator, &v);
1616 _public_ int sd_device_has_tag(sd_device *device, const char *tag) {
1617 assert_return(device, -EINVAL);
1618 assert_return(tag, -EINVAL);
1620 (void) device_read_db(device);
1622 return !!set_contains(device->tags, tag);
1625 _public_ int sd_device_get_property_value(sd_device *device, const char *key, const char **_value) {
1629 assert_return(device, -EINVAL);
1630 assert_return(key, -EINVAL);
1631 assert_return(_value, -EINVAL);
1633 r = device_properties_prepare(device);
1637 value = ordered_hashmap_get(device->properties, key);
1646 /* replaces the value if it already exists */
1647 static int device_add_sysattr_value(sd_device *device, const char *_key, char *value) {
1648 _cleanup_free_ char *key = NULL;
1649 _cleanup_free_ char *value_old = NULL;
1655 r = hashmap_ensure_allocated(&device->sysattr_values, &string_hash_ops);
1659 value_old = hashmap_remove2(device->sysattr_values, _key, (void **)&key);
1666 r = hashmap_put(device->sysattr_values, key, value);
1675 static int device_get_sysattr_value(sd_device *device, const char *_key, const char **_value) {
1676 const char *key = NULL, *value;
1681 value = hashmap_get2(device->sysattr_values, _key, (void **) &key);
1691 /* We cache all sysattr lookups. If an attribute does not exist, it is stored
1692 * with a NULL value in the cache, otherwise the returned string is stored */
1693 _public_ int sd_device_get_sysattr_value(sd_device *device, const char *sysattr, const char **_value) {
1694 _cleanup_free_ char *value = NULL;
1695 const char *syspath, *cached_value = NULL;
1697 struct stat statbuf;
1700 assert_return(device, -EINVAL);
1701 assert_return(sysattr, -EINVAL);
1703 /* look for possibly already cached result */
1704 r = device_get_sysattr_value(device, sysattr, &cached_value);
1710 /* we looked up the sysattr before and it did not exist */
1714 *_value = cached_value;
1719 r = sd_device_get_syspath(device, &syspath);
1723 path = strjoina(syspath, "/", sysattr);
1724 r = lstat(path, &statbuf);
1726 /* remember that we could not access the sysattr */
1727 r = device_add_sysattr_value(device, sysattr, NULL);
1732 } else if (S_ISLNK(statbuf.st_mode)) {
1733 /* Some core links return only the last element of the target path,
1734 * these are just values, the paths should not be exposed. */
1735 if (STR_IN_SET(sysattr, "driver", "subsystem", "module")) {
1736 r = readlink_value(path, &value);
1741 } else if (S_ISDIR(statbuf.st_mode)) {
1742 /* skip directories */
1744 } else if (!(statbuf.st_mode & S_IRUSR)) {
1745 /* skip non-readable files */
1750 /* read attribute value */
1751 r = read_full_file(path, &value, &size);
1755 /* drop trailing newlines */
1756 while (size > 0 && value[--size] == '\n')
1760 r = device_add_sysattr_value(device, sysattr, value);
1770 static void device_remove_sysattr_value(sd_device *device, const char *_key) {
1771 _cleanup_free_ char *key = NULL;
1772 _cleanup_free_ char *value = NULL;
1777 value = hashmap_remove2(device->sysattr_values, _key, (void **) &key);
1782 /* set the attribute and save it in the cache. If a NULL value is passed the
1783 * attribute is cleared from the cache */
1784 _public_ int sd_device_set_sysattr_value(sd_device *device, const char *sysattr, char *_value) {
1785 _cleanup_close_ int fd = -1;
1786 _cleanup_free_ char *value = NULL;
1787 const char *syspath;
1789 struct stat statbuf;
1790 size_t value_len = 0;
1794 assert_return(device, -EINVAL);
1795 assert_return(sysattr, -EINVAL);
1798 device_remove_sysattr_value(device, sysattr);
1803 r = sd_device_get_syspath(device, &syspath);
1807 path = strjoina(syspath, "/", sysattr);
1808 r = lstat(path, &statbuf);
1814 r = device_add_sysattr_value(device, sysattr, value);
1821 if (S_ISLNK(statbuf.st_mode))
1824 /* skip directories */
1825 if (S_ISDIR(statbuf.st_mode))
1828 /* skip non-readable files */
1829 if ((statbuf.st_mode & S_IRUSR) == 0)
1832 value_len = strlen(_value);
1834 /* drop trailing newlines */
1835 while (value_len > 0 && _value[value_len - 1] == '\n')
1836 _value[--value_len] = '\0';
1838 /* value length is limited to 4k */
1839 if (value_len > 4096)
1842 fd = open(path, O_WRONLY | O_CLOEXEC);
1846 value = strdup(_value);
1850 size = write(fd, value, value_len);
1854 if ((size_t)size != value_len)
1857 r = device_add_sysattr_value(device, sysattr, value);