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);
163 syspath = canonicalize_file_name(_syspath);
165 log_debug("sd-device: could not canonicalize '%s': %m", _syspath);
168 /* ignore errors due to the link not being a symlink */
169 } else if (r < 0 && r != -EINVAL) {
170 log_debug("sd-device: could not get target of '%s': %s", _syspath, strerror(-r));
174 if (path_startswith(syspath, "/sys/devices/")) {
177 /* all 'devices' require an 'uevent' file */
178 path = strjoina(syspath, "/uevent");
179 r = access(path, F_OK);
181 log_debug("sd-device: %s does not have an uevent file: %m", syspath);
185 /* everything else just just needs to be a directory */
186 if (!is_dir(syspath, false)) {
187 log_debug("sd-device: %s is not a directory", syspath);
192 syspath = strdup(_syspath);
197 devpath = syspath + strlen("/sys");
199 r = device_add_property_internal(device, "DEVPATH", devpath);
203 free(device->syspath);
204 device->syspath = syspath;
207 device->devpath = devpath;
212 _public_ int sd_device_new_from_syspath(sd_device **ret, const char *syspath) {
213 _cleanup_device_unref_ sd_device *device = NULL;
216 assert_return(ret, -EINVAL);
217 assert_return(syspath, -EINVAL);
219 r = device_new_aux(&device);
223 r = device_set_syspath(device, syspath, true);
233 _public_ int sd_device_new_from_devnum(sd_device **ret, char type, dev_t devnum) {
235 char id[DECIMAL_STR_MAX(unsigned) * 2 + 1];
237 assert_return(ret, -EINVAL);
238 assert_return(type == 'b' || type == 'c', -EINVAL);
240 /* use /sys/dev/{block,char}/<maj>:<min> link */
241 snprintf(id, sizeof(id), "%u:%u", major(devnum), minor(devnum));
243 syspath = strjoina("/sys/dev/", (type == 'b' ? "block" : "char"), "/", id);
245 return sd_device_new_from_syspath(ret, syspath);
248 _public_ int sd_device_new_from_subsystem_sysname(sd_device **ret, const char *subsystem, const char *sysname) {
251 assert_return(ret, -EINVAL);
252 assert_return(subsystem, -EINVAL);
253 assert_return(sysname, -EINVAL);
255 if (streq(subsystem, "subsystem")) {
256 syspath = strjoina("/sys/subsystem/", sysname);
257 if (access(syspath, F_OK) >= 0)
258 return sd_device_new_from_syspath(ret, syspath);
260 syspath = strjoina("/sys/bus/", sysname);
261 if (access(syspath, F_OK) >= 0)
262 return sd_device_new_from_syspath(ret, syspath);
264 syspath = strjoina("/sys/class/", sysname);
265 if (access(syspath, F_OK) >= 0)
266 return sd_device_new_from_syspath(ret, syspath);
267 } else if (streq(subsystem, "module")) {
268 syspath = strjoina("/sys/module/", sysname);
269 if (access(syspath, F_OK) >= 0)
270 return sd_device_new_from_syspath(ret, syspath);
271 } else if (streq(subsystem, "drivers")) {
272 char subsys[PATH_MAX];
275 strscpy(subsys, sizeof(subsys), sysname);
276 driver = strchr(subsys, ':');
281 syspath = strjoina("/sys/subsystem/", subsys, "/drivers/", driver);
282 if (access(syspath, F_OK) >= 0)
283 return sd_device_new_from_syspath(ret, syspath);
285 syspath = strjoina("/sys/bus/", subsys, "/drivers/", driver);
286 if (access(syspath, F_OK) >= 0)
287 return sd_device_new_from_syspath(ret, syspath);
291 syspath = strjoina("/sys/subsystem/", subsystem, "/devices/", sysname);
292 if (access(syspath, F_OK) >= 0)
293 return sd_device_new_from_syspath(ret, syspath);
295 syspath = strjoina("/sys/bus/", subsystem, "/devices/", sysname);
296 if (access(syspath, F_OK) >= 0)
297 return sd_device_new_from_syspath(ret, syspath);
299 syspath = strjoina("/sys/class/", subsystem, "/", sysname);
300 if (access(syspath, F_OK) >= 0)
301 return sd_device_new_from_syspath(ret, syspath);
307 int device_set_devtype(sd_device *device, const char *_devtype) {
308 _cleanup_free_ char *devtype = NULL;
314 devtype = strdup(_devtype);
318 r = device_add_property_internal(device, "DEVTYPE", devtype);
322 free(device->devtype);
323 device->devtype = devtype;
329 int device_set_ifindex(sd_device *device, const char *_ifindex) {
335 r = safe_atoi(_ifindex, &ifindex);
342 r = device_add_property_internal(device, "IFINDEX", _ifindex);
346 device->ifindex = ifindex;
351 int device_set_devname(sd_device *device, const char *_devname) {
352 _cleanup_free_ char *devname = NULL;
358 if (_devname[0] != '/') {
359 r = asprintf(&devname, "/dev/%s", _devname);
363 devname = strdup(_devname);
368 r = device_add_property_internal(device, "DEVNAME", devname);
372 free(device->devname);
373 device->devname = devname;
379 int device_set_devmode(sd_device *device, const char *_devmode) {
386 r = safe_atou(_devmode, &devmode);
393 r = device_add_property_internal(device, "DEVMODE", _devmode);
397 device->devmode = devmode;
402 int device_set_devnum(sd_device *device, const char *major, const char *minor) {
403 unsigned maj = 0, min = 0;
409 r = safe_atou(major, &maj);
416 r = safe_atou(minor, &min);
421 r = device_add_property_internal(device, "MAJOR", major);
426 r = device_add_property_internal(device, "MINOR", minor);
431 device->devnum = makedev(maj, min);
436 static int handle_uevent_line(sd_device *device, const char *key, const char *value, const char **major, const char **minor) {
445 if (streq(key, "DEVTYPE")) {
446 r = device_set_devtype(device, value);
449 } else if (streq(key, "IFINDEX")) {
450 r = device_set_ifindex(device, value);
453 } else if (streq(key, "DEVNAME")) {
454 r = device_set_devname(device, value);
457 } else if (streq(key, "DEVMODE")) {
458 r = device_set_devmode(device, value);
461 } else if (streq(key, "MAJOR"))
463 else if (streq(key, "MINOR"))
466 r = device_add_property_internal(device, key, value);
474 int device_read_uevent_file(sd_device *device) {
475 _cleanup_free_ char *uevent = NULL;
476 const char *syspath, *key, *value, *major = NULL, *minor = NULL;
492 if (device->uevent_loaded || device->sealed)
495 r = sd_device_get_syspath(device, &syspath);
499 path = strjoina(syspath, "/uevent");
501 r = read_full_file(path, &uevent, &uevent_len);
503 log_debug("sd-device: failed to read uevent file '%s': %s", path, strerror(-r));
507 for (i = 0; i < uevent_len; i++) {
510 if (!strchr(NEWLINE, uevent[i])) {
518 if (uevent[i] == '=') {
522 } else if (strchr(NEWLINE, uevent[i])) {
524 log_debug("sd-device: ignoring invalid uevent line '%s'", key);
537 if (strchr(NEWLINE, uevent[i])) {
540 r = handle_uevent_line(device, key, value, &major, &minor);
542 log_debug("sd-device: failed to handle uevent entry '%s=%s': %s", key, value, strerror(-r));
549 assert_not_reached("invalid state when parsing uevent file");
554 r = device_set_devnum(device, major, minor);
556 log_debug("sd-device: could not set 'MAJOR=%s' or 'MINOR=%s' from '%s': %s", major, minor, path, strerror(-r));
559 device->uevent_loaded = true;
564 _public_ int sd_device_get_ifindex(sd_device *device, int *ifindex) {
567 assert_return(device, -EINVAL);
568 assert_return(ifindex, -EINVAL);
570 r = device_read_uevent_file(device);
574 *ifindex = device->ifindex;
579 _public_ int sd_device_new_from_device_id(sd_device **ret, const char *id) {
582 assert_return(ret, -EINVAL);
583 assert_return(id, -EINVAL);
592 r = sscanf(id, "%c%i:%i", &type, &maj, &min);
596 return sd_device_new_from_devnum(ret, type, makedev(maj, min));
600 _cleanup_device_unref_ sd_device *device = NULL;
601 _cleanup_close_ int sk = -1;
602 struct ifreq ifr = {};
605 r = safe_atoi(&id[1], &ifr.ifr_ifindex);
608 else if (ifr.ifr_ifindex <= 0)
611 sk = socket(PF_INET, SOCK_DGRAM, 0);
615 r = ioctl(sk, SIOCGIFNAME, &ifr);
619 r = sd_device_new_from_subsystem_sysname(&device, "net", ifr.ifr_name);
623 r = sd_device_get_ifindex(device, &ifindex);
627 /* this si racey, so we might end up with the wrong device */
628 if (ifr.ifr_ifindex != ifindex)
638 char subsys[PATH_MAX];
641 (void)strscpy(subsys, sizeof(subsys), id + 1);
642 sysname = strchr(subsys, ':');
649 return sd_device_new_from_subsystem_sysname(ret, subsys, sysname);
656 _public_ int sd_device_get_syspath(sd_device *device, const char **ret) {
657 assert_return(device, -EINVAL);
658 assert_return(ret, -EINVAL);
660 assert(path_startswith(device->syspath, "/sys/"));
662 *ret = device->syspath;
667 static int device_new_from_child(sd_device **ret, sd_device *child) {
668 _cleanup_free_ char *path = NULL;
669 const char *subdir, *syspath;
675 r = sd_device_get_syspath(child, &syspath);
679 path = strdup(syspath);
682 subdir = path + strlen("/sys");
687 pos = strrchr(subdir, '/');
688 if (!pos || pos < subdir + 2)
693 r = sd_device_new_from_syspath(ret, path);
703 _public_ int sd_device_get_parent(sd_device *child, sd_device **ret) {
705 assert_return(ret, -EINVAL);
706 assert_return(child, -EINVAL);
708 if (!child->parent_set) {
709 child->parent_set = true;
711 (void)device_new_from_child(&child->parent, child);
717 *ret = child->parent;
722 int device_set_subsystem(sd_device *device, const char *_subsystem) {
723 _cleanup_free_ char *subsystem = NULL;
729 subsystem = strdup(_subsystem);
733 r = device_add_property_internal(device, "SUBSYSTEM", subsystem);
737 free(device->subsystem);
738 device->subsystem = subsystem;
741 device->subsystem_set = true;
746 _public_ int sd_device_get_subsystem(sd_device *device, const char **ret) {
747 assert_return(ret, -EINVAL);
748 assert_return(device, -EINVAL);
750 if (!device->subsystem_set) {
751 _cleanup_free_ char *subsystem = NULL;
756 /* read 'subsystem' link */
757 r = sd_device_get_syspath(device, &syspath);
761 path = strjoina(syspath, "/subsystem");
762 r = readlink_value(path, &subsystem);
764 r = device_set_subsystem(device, subsystem);
765 /* use implicit names */
766 else if (path_startswith(device->devpath, "/module/"))
767 r = device_set_subsystem(device, "module");
768 else if (strstr(device->devpath, "/drivers/"))
769 r = device_set_subsystem(device, "drivers");
770 else if (path_startswith(device->devpath, "/subsystem/") ||
771 path_startswith(device->devpath, "/class/") ||
772 path_startswith(device->devpath, "/buss/"))
773 r = device_set_subsystem(device, "subsystem");
777 device->subsystem_set = true;
780 *ret = device->subsystem;
785 _public_ int sd_device_get_devtype(sd_device *device, const char **devtype) {
791 r = device_read_uevent_file(device);
795 *devtype = device->devtype;
800 _public_ int sd_device_get_parent_with_subsystem_devtype(sd_device *child, const char *subsystem, const char *devtype, sd_device **ret) {
801 sd_device *parent = NULL;
804 assert_return(child, -EINVAL);
805 assert_return(subsystem, -EINVAL);
807 r = sd_device_get_parent(child, &parent);
809 const char *parent_subsystem = NULL;
810 const char *parent_devtype = NULL;
812 (void)sd_device_get_subsystem(parent, &parent_subsystem);
813 if (streq_ptr(parent_subsystem, subsystem)) {
817 (void)sd_device_get_devtype(parent, &parent_devtype);
818 if (streq_ptr(parent_devtype, devtype))
821 r = sd_device_get_parent(parent, &parent);
832 _public_ int sd_device_get_devnum(sd_device *device, dev_t *devnum) {
835 assert_return(device, -EINVAL);
836 assert_return(devnum, -EINVAL);
838 r = device_read_uevent_file(device);
842 *devnum = device->devnum;
847 int device_set_driver(sd_device *device, const char *_driver) {
848 _cleanup_free_ char *driver = NULL;
854 driver = strdup(_driver);
858 r = device_add_property_internal(device, "DRIVER", driver);
862 free(device->driver);
863 device->driver = driver;
866 device->driver_set = true;
871 _public_ int sd_device_get_driver(sd_device *device, const char **ret) {
872 assert_return(device, -EINVAL);
873 assert_return(ret, -EINVAL);
875 if (!device->driver_set) {
876 _cleanup_free_ char *driver = NULL;
881 r = sd_device_get_syspath(device, &syspath);
885 path = strjoina(syspath, "/driver");
886 r = readlink_value(path, &driver);
888 r = device_set_driver(device, driver);
894 *ret = device->driver;
899 _public_ int sd_device_get_devpath(sd_device *device, const char **devpath) {
900 assert_return(device, -EINVAL);
901 assert_return(devpath, -EINVAL);
903 assert(device->devpath);
904 assert(device->devpath[0] == '/');
906 *devpath = device->devpath;
911 _public_ int sd_device_get_devname(sd_device *device, const char **devname) {
914 assert_return(device, -EINVAL);
915 assert_return(devname, -EINVAL);
917 r = device_read_uevent_file(device);
921 if (!device->devname)
924 assert(path_startswith(device->devname, "/dev/"));
926 *devname = device->devname;
931 static int device_set_sysname(sd_device *device) {
932 _cleanup_free_ char *sysname = NULL;
933 const char *sysnum = NULL;
937 pos = strrchr(device->devpath, '/');
942 /* devpath is not a root directory */
943 if (*pos == '\0' || pos <= device->devpath)
946 sysname = strdup(pos);
950 /* some devices have '!' in their name, change that to '/' */
951 while (sysname[len] != '\0') {
952 if (sysname[len] == '!')
958 /* trailing number */
959 while (len > 0 && isdigit(sysname[--len]))
960 sysnum = &sysname[len];
965 free(device->sysname);
966 device->sysname = sysname;
969 device->sysnum = sysnum;
971 device->sysname_set = true;
976 _public_ int sd_device_get_sysname(sd_device *device, const char **ret) {
979 assert_return(device, -EINVAL);
980 assert_return(ret, -EINVAL);
982 if (!device->sysname_set) {
983 r = device_set_sysname(device);
988 *ret = device->sysname;
993 _public_ int sd_device_get_sysnum(sd_device *device, const char **ret) {
996 assert_return(device, -EINVAL);
997 assert_return(ret, -EINVAL);
999 if (!device->sysname_set) {
1000 r = device_set_sysname(device);
1005 *ret = device->sysnum;
1010 static bool is_valid_tag(const char *tag) {
1013 return !strchr(tag, ':') && !strchr(tag, ' ');
1016 int device_add_tag(sd_device *device, const char *tag) {
1022 if (!is_valid_tag(tag))
1025 r = set_ensure_allocated(&device->tags, &string_hash_ops);
1029 r = set_put_strdup(device->tags, tag);
1033 device->tags_generation ++;
1034 device->property_tags_outdated = true;
1039 int device_add_devlink(sd_device *device, const char *devlink) {
1045 r = set_ensure_allocated(&device->devlinks, &string_hash_ops);
1049 r = set_put_strdup(device->devlinks, devlink);
1053 device->devlinks_generation ++;
1054 device->property_devlinks_outdated = true;
1059 static int device_add_property_internal_from_string(sd_device *device, const char *str) {
1060 _cleanup_free_ char *key = NULL;
1070 value = strchr(key, '=');
1076 if (isempty(++value))
1079 return device_add_property_internal(device, key, value);
1082 int device_set_usec_initialized(sd_device *device, const char *initialized) {
1083 uint64_t usec_initialized;
1087 assert(initialized);
1089 r = safe_atou64(initialized, &usec_initialized);
1093 r = device_add_property_internal(device, "USEC_INITIALIZED", initialized);
1097 device->usec_initialized = usec_initialized;
1102 static int handle_db_line(sd_device *device, char key, const char *value) {
1111 r = device_add_tag(device, value);
1117 path = strjoina("/dev/", value);
1118 r = device_add_devlink(device, path);
1124 r = device_add_property_internal_from_string(device, value);
1130 r = device_set_usec_initialized(device, value);
1136 r = safe_atoi(value, &device->devlink_priority);
1142 r = safe_atoi(value, &device->watch_handle);
1148 log_debug("device db: unknown key '%c'", key);
1154 int device_get_id_filename(sd_device *device, const char **ret) {
1158 if (!device->id_filename) {
1159 _cleanup_free_ char *id = NULL;
1160 const char *subsystem;
1164 r = sd_device_get_subsystem(device, &subsystem);
1168 r = sd_device_get_devnum(device, &devnum);
1172 r = sd_device_get_ifindex(device, &ifindex);
1176 if (major(devnum) > 0) {
1177 /* use dev_t -- b259:131072, c254:0 */
1178 r = asprintf(&id, "%c%u:%u",
1179 streq(subsystem, "block") ? 'b' : 'c',
1180 major(devnum), minor(devnum));
1183 } else if (ifindex > 0) {
1184 /* use netdev ifindex -- n3 */
1185 r = asprintf(&id, "n%u", ifindex);
1189 /* use $subsys:$sysname -- pci:0000:00:1f.2
1190 * sysname() has '!' translated, get it from devpath
1192 const char *sysname;
1194 sysname = basename(device->devpath);
1198 r = asprintf(&id, "+%s:%s", subsystem, sysname);
1203 device->id_filename = id;
1207 *ret = device->id_filename;
1212 static int device_read_db(sd_device *device) {
1213 _cleanup_free_ char *db = NULL;
1215 const char *id, *value;
1229 if (device->db_loaded || device->sealed)
1232 r = device_get_id_filename(device, &id);
1236 path = strjoina("/run/udev/data/", id);
1238 r = read_full_file(path, &db, &db_len);
1243 log_debug("sd-device: failed to read db '%s': %s", path, strerror(-r));
1248 /* devices with a database entry are initialized */
1249 device->is_initialized = true;;
1251 for (i = 0; i < db_len; i++) {
1254 if (!strchr(NEWLINE, db[i])) {
1263 log_debug("sd-device: ignoring invalid db entry with key '%c'", key);
1265 state = INVALID_LINE;
1280 if (strchr(NEWLINE, db[i]))
1285 if (strchr(NEWLINE, db[i])) {
1287 r = handle_db_line(device, key, value);
1289 log_debug("sd-device: failed to handle db entry '%c:%s': %s", key, value, strerror(-r));
1296 assert_not_reached("invalid state when parsing db");
1300 device->db_loaded = true;
1305 _public_ int sd_device_get_is_initialized(sd_device *device, int *initialized) {
1308 assert_return(device, -EINVAL);
1309 assert_return(initialized, -EINVAL);
1311 r = device_read_db(device);
1315 *initialized = device->is_initialized;
1320 _public_ int sd_device_get_usec_since_initialized(sd_device *device, uint64_t *usec) {
1324 assert_return(device, -EINVAL);
1325 assert_return(usec, -EINVAL);
1327 r = device_read_db(device);
1331 if (!device->is_initialized)
1334 if (!device->usec_initialized)
1337 now_ts = now(clock_boottime_or_monotonic());
1339 if (now_ts < device->usec_initialized)
1342 *usec = now_ts - device->usec_initialized;
1347 _public_ const char *sd_device_get_tag_first(sd_device *device) {
1348 assert_return(device, NULL);
1350 (void) device_read_db(device);
1352 device->tags_iterator_generation = device->tags_generation;
1353 device->tags_iterator = ITERATOR_FIRST;
1355 return set_iterate(device->tags, &device->tags_iterator);
1358 _public_ const char *sd_device_get_tag_next(sd_device *device) {
1359 assert_return(device, NULL);
1361 (void) device_read_db(device);
1363 if (device->tags_iterator_generation != device->tags_generation)
1366 return set_iterate(device->tags, &device->tags_iterator);
1369 _public_ const char *sd_device_get_devlink_first(sd_device *device) {
1370 assert_return(device, NULL);
1372 (void) device_read_db(device);
1374 device->devlinks_iterator_generation = device->devlinks_generation;
1375 device->devlinks_iterator = ITERATOR_FIRST;
1377 return set_iterate(device->devlinks, &device->devlinks_iterator);
1380 _public_ const char *sd_device_get_devlink_next(sd_device *device) {
1381 assert_return(device, NULL);
1383 (void) device_read_db(device);
1385 if (device->devlinks_iterator_generation != device->devlinks_generation)
1388 return set_iterate(device->devlinks, &device->devlinks_iterator);
1391 static int device_properties_prepare(sd_device *device) {
1396 r = device_read_uevent_file(device);
1400 r = device_read_db(device);
1404 if (device->property_devlinks_outdated) {
1405 char *devlinks = NULL;
1406 const char *devlink;
1408 devlink = sd_device_get_devlink_first(device);
1410 devlinks = strdupa(devlink);
1412 while ((devlink = sd_device_get_devlink_next(device)))
1413 devlinks = strjoina(devlinks, " ", devlink);
1415 r = device_add_property_internal(device, "DEVLINKS", devlinks);
1419 device->property_devlinks_outdated = false;
1422 if (device->property_tags_outdated) {
1426 tag = sd_device_get_tag_first(device);
1428 tags = strjoina(":", tag);
1430 while ((tag = sd_device_get_tag_next(device)))
1431 tags = strjoina(tags, ":", tag);
1433 tags = strjoina(tags, ":");
1435 r = device_add_property_internal(device, "TAGS", tags);
1439 device->property_tags_outdated = false;
1445 _public_ const char *sd_device_get_property_first(sd_device *device, const char **_value) {
1450 assert_return(device, NULL);
1452 r = device_properties_prepare(device);
1456 device->properties_iterator_generation = device->properties_generation;
1457 device->properties_iterator = ITERATOR_FIRST;
1459 value = ordered_hashmap_iterate(device->properties, &device->properties_iterator, (const void**)&key);
1467 _public_ const char *sd_device_get_property_next(sd_device *device, const char **_value) {
1472 assert_return(device, NULL);
1474 r = device_properties_prepare(device);
1478 if (device->properties_iterator_generation != device->properties_generation)
1481 value = ordered_hashmap_iterate(device->properties, &device->properties_iterator, (const void**)&key);
1489 static int device_sysattrs_read_all(sd_device *device) {
1490 _cleanup_closedir_ DIR *dir = NULL;
1491 const char *syspath;
1492 struct dirent *dent;
1497 if (device->sysattrs_read)
1500 r = sd_device_get_syspath(device, &syspath);
1504 dir = opendir(syspath);
1508 r = set_ensure_allocated(&device->sysattrs, &string_hash_ops);
1512 for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
1514 struct stat statbuf;
1516 /* only handle symlinks and regular files */
1517 if (dent->d_type != DT_LNK && dent->d_type != DT_REG)
1520 path = strjoina(syspath, "/", dent->d_name);
1522 if (lstat(path, &statbuf) != 0)
1525 if (!(statbuf.st_mode & S_IRUSR))
1528 r = set_put_strdup(device->sysattrs, dent->d_name);
1533 device->sysattrs_read = true;
1538 _public_ const char *sd_device_get_sysattr_first(sd_device *device) {
1541 assert_return(device, NULL);
1543 if (!device->sysattrs_read) {
1544 r = device_sysattrs_read_all(device);
1551 device->sysattrs_iterator = ITERATOR_FIRST;
1553 return set_iterate(device->sysattrs, &device->sysattrs_iterator);
1556 _public_ const char *sd_device_get_sysattr_next(sd_device *device) {
1557 assert_return(device, NULL);
1559 if (!device->sysattrs_read)
1562 return set_iterate(device->sysattrs, &device->sysattrs_iterator);
1565 _public_ int sd_device_has_tag(sd_device *device, const char *tag) {
1566 assert_return(device, -EINVAL);
1567 assert_return(tag, -EINVAL);
1569 (void) device_read_db(device);
1571 return !!set_contains(device->tags, tag);
1574 _public_ int sd_device_get_property_value(sd_device *device, const char *key, const char **_value) {
1578 assert_return(device, -EINVAL);
1579 assert_return(key, -EINVAL);
1580 assert_return(_value, -EINVAL);
1582 r = device_properties_prepare(device);
1586 value = ordered_hashmap_get(device->properties, key);
1595 /* replaces the value if it already exists */
1596 static int device_add_sysattr_value(sd_device *device, const char *_key, char *value) {
1597 _cleanup_free_ char *key = NULL;
1598 _cleanup_free_ char *value_old = NULL;
1604 r = hashmap_ensure_allocated(&device->sysattr_values, &string_hash_ops);
1608 value_old = hashmap_remove2(device->sysattr_values, _key, (void **)&key);
1615 r = hashmap_put(device->sysattr_values, key, value);
1624 static int device_get_sysattr_value(sd_device *device, const char *_key, const char **_value) {
1625 const char *key = NULL, *value;
1630 value = hashmap_get2(device->sysattr_values, _key, (void **) &key);
1640 /* We cache all sysattr lookups. If an attribute does not exist, it is stored
1641 * with a NULL value in the cache, otherwise the returned string is stored */
1642 _public_ int sd_device_get_sysattr_value(sd_device *device, const char *sysattr, const char **_value) {
1643 _cleanup_free_ char *value = NULL;
1644 const char *syspath, *cached_value = NULL;
1646 struct stat statbuf;
1649 assert_return(device, -EINVAL);
1650 assert_return(sysattr, -EINVAL);
1652 /* look for possibly already cached result */
1653 r = device_get_sysattr_value(device, sysattr, &cached_value);
1659 /* we looked up the sysattr before and it did not exist */
1663 *_value = cached_value;
1668 r = sd_device_get_syspath(device, &syspath);
1672 path = strjoina(syspath, "/", sysattr);
1673 r = lstat(path, &statbuf);
1675 /* remember that we could not access the sysattr */
1676 r = device_add_sysattr_value(device, sysattr, NULL);
1681 } else if (S_ISLNK(statbuf.st_mode)) {
1682 /* Some core links return only the last element of the target path,
1683 * these are just values, the paths should not be exposed. */
1684 if (STR_IN_SET(sysattr, "driver", "subsystem", "module")) {
1685 r = readlink_value(path, &value);
1690 } else if (S_ISDIR(statbuf.st_mode)) {
1691 /* skip directories */
1693 } else if (!(statbuf.st_mode & S_IRUSR)) {
1694 /* skip non-readable files */
1699 /* read attribute value */
1700 r = read_full_file(path, &value, &size);
1704 /* drop trailing newlines */
1705 while (size > 0 && value[--size] == '\n')
1709 r = device_add_sysattr_value(device, sysattr, value);
1719 static void device_remove_sysattr_value(sd_device *device, const char *_key) {
1720 _cleanup_free_ char *key = NULL;
1721 _cleanup_free_ char *value = NULL;
1726 value = hashmap_remove2(device->sysattr_values, _key, (void **) &key);
1731 /* set the attribute and save it in the cache. If a NULL value is passed the
1732 * attribute is cleared from the cache */
1733 _public_ int sd_device_set_sysattr_value(sd_device *device, const char *sysattr, char *_value) {
1734 _cleanup_close_ int fd = -1;
1735 _cleanup_free_ char *value = NULL;
1736 const char *syspath;
1738 struct stat statbuf;
1739 size_t value_len = 0;
1743 assert_return(device, -EINVAL);
1744 assert_return(sysattr, -EINVAL);
1747 device_remove_sysattr_value(device, sysattr);
1752 r = sd_device_get_syspath(device, &syspath);
1756 path = strjoina(syspath, "/", sysattr);
1757 r = lstat(path, &statbuf);
1763 r = device_add_sysattr_value(device, sysattr, value);
1770 if (S_ISLNK(statbuf.st_mode))
1773 /* skip directories */
1774 if (S_ISDIR(statbuf.st_mode))
1777 /* skip non-readable files */
1778 if ((statbuf.st_mode & S_IRUSR) == 0)
1781 value_len = strlen(_value);
1783 /* drop trailing newlines */
1784 while (value_len > 0 && _value[value_len - 1] == '\n')
1785 _value[--value_len] = '\0';
1787 /* value length is limited to 4k */
1788 if (value_len > 4096)
1791 fd = open(path, O_WRONLY | O_CLOEXEC);
1795 value = strdup(_value);
1799 size = write(fd, value, value_len);
1803 if ((size_t)size != value_len)
1806 r = device_add_sysattr_value(device, sysattr, value);