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);
187 log_debug("sd-device: %s does not have an uevent file: %m", syspath);
191 /* everything else just just needs to be a directory */
192 if (!is_dir(syspath, false)) {
193 log_debug("sd-device: %s is not a directory", syspath);
198 syspath = strdup(_syspath);
203 devpath = syspath + strlen("/sys");
205 r = device_add_property_internal(device, "DEVPATH", devpath);
209 free(device->syspath);
210 device->syspath = syspath;
213 device->devpath = devpath;
218 _public_ int sd_device_new_from_syspath(sd_device **ret, const char *syspath) {
219 _cleanup_device_unref_ sd_device *device = NULL;
222 assert_return(ret, -EINVAL);
223 assert_return(syspath, -EINVAL);
225 r = device_new_aux(&device);
229 r = device_set_syspath(device, syspath, true);
239 _public_ int sd_device_new_from_devnum(sd_device **ret, char type, dev_t devnum) {
241 char id[DECIMAL_STR_MAX(unsigned) * 2 + 1];
243 assert_return(ret, -EINVAL);
244 assert_return(type == 'b' || type == 'c', -EINVAL);
246 /* use /sys/dev/{block,char}/<maj>:<min> link */
247 snprintf(id, sizeof(id), "%u:%u", major(devnum), minor(devnum));
249 syspath = strjoina("/sys/dev/", (type == 'b' ? "block" : "char"), "/", id);
251 return sd_device_new_from_syspath(ret, syspath);
254 _public_ int sd_device_new_from_subsystem_sysname(sd_device **ret, const char *subsystem, const char *sysname) {
257 assert_return(ret, -EINVAL);
258 assert_return(subsystem, -EINVAL);
259 assert_return(sysname, -EINVAL);
261 if (streq(subsystem, "subsystem")) {
262 syspath = strjoina("/sys/subsystem/", sysname);
263 if (access(syspath, F_OK) >= 0)
264 return sd_device_new_from_syspath(ret, syspath);
266 syspath = strjoina("/sys/bus/", sysname);
267 if (access(syspath, F_OK) >= 0)
268 return sd_device_new_from_syspath(ret, syspath);
270 syspath = strjoina("/sys/class/", sysname);
271 if (access(syspath, F_OK) >= 0)
272 return sd_device_new_from_syspath(ret, syspath);
273 } else if (streq(subsystem, "module")) {
274 syspath = strjoina("/sys/module/", sysname);
275 if (access(syspath, F_OK) >= 0)
276 return sd_device_new_from_syspath(ret, syspath);
277 } else if (streq(subsystem, "drivers")) {
278 char subsys[PATH_MAX];
281 strscpy(subsys, sizeof(subsys), sysname);
282 driver = strchr(subsys, ':');
287 syspath = strjoina("/sys/subsystem/", subsys, "/drivers/", driver);
288 if (access(syspath, F_OK) >= 0)
289 return sd_device_new_from_syspath(ret, syspath);
291 syspath = strjoina("/sys/bus/", subsys, "/drivers/", driver);
292 if (access(syspath, F_OK) >= 0)
293 return sd_device_new_from_syspath(ret, syspath);
297 syspath = strjoina("/sys/subsystem/", subsystem, "/devices/", sysname);
298 if (access(syspath, F_OK) >= 0)
299 return sd_device_new_from_syspath(ret, syspath);
301 syspath = strjoina("/sys/bus/", subsystem, "/devices/", sysname);
302 if (access(syspath, F_OK) >= 0)
303 return sd_device_new_from_syspath(ret, syspath);
305 syspath = strjoina("/sys/class/", subsystem, "/", sysname);
306 if (access(syspath, F_OK) >= 0)
307 return sd_device_new_from_syspath(ret, syspath);
313 int device_set_devtype(sd_device *device, const char *_devtype) {
314 _cleanup_free_ char *devtype = NULL;
320 devtype = strdup(_devtype);
324 r = device_add_property_internal(device, "DEVTYPE", devtype);
328 free(device->devtype);
329 device->devtype = devtype;
335 int device_set_ifindex(sd_device *device, const char *_ifindex) {
341 r = safe_atoi(_ifindex, &ifindex);
348 r = device_add_property_internal(device, "IFINDEX", _ifindex);
352 device->ifindex = ifindex;
357 int device_set_devname(sd_device *device, const char *_devname) {
358 _cleanup_free_ char *devname = NULL;
364 if (_devname[0] != '/') {
365 r = asprintf(&devname, "/dev/%s", _devname);
369 devname = strdup(_devname);
374 r = device_add_property_internal(device, "DEVNAME", devname);
378 free(device->devname);
379 device->devname = devname;
385 int device_set_devmode(sd_device *device, const char *_devmode) {
392 r = safe_atou(_devmode, &devmode);
399 r = device_add_property_internal(device, "DEVMODE", _devmode);
403 device->devmode = devmode;
408 int device_set_devnum(sd_device *device, const char *major, const char *minor) {
409 unsigned maj = 0, min = 0;
415 r = safe_atou(major, &maj);
422 r = safe_atou(minor, &min);
427 r = device_add_property_internal(device, "MAJOR", major);
432 r = device_add_property_internal(device, "MINOR", minor);
437 device->devnum = makedev(maj, min);
442 static int handle_uevent_line(sd_device *device, const char *key, const char *value, const char **major, const char **minor) {
451 if (streq(key, "DEVTYPE")) {
452 r = device_set_devtype(device, value);
455 } else if (streq(key, "IFINDEX")) {
456 r = device_set_ifindex(device, value);
459 } else if (streq(key, "DEVNAME")) {
460 r = device_set_devname(device, value);
463 } else if (streq(key, "DEVMODE")) {
464 r = device_set_devmode(device, value);
467 } else if (streq(key, "MAJOR"))
469 else if (streq(key, "MINOR"))
472 r = device_add_property_internal(device, key, value);
480 int device_read_uevent_file(sd_device *device) {
481 _cleanup_free_ char *uevent = NULL;
482 const char *syspath, *key, *value, *major = NULL, *minor = NULL;
498 if (device->uevent_loaded || device->sealed)
501 r = sd_device_get_syspath(device, &syspath);
505 path = strjoina(syspath, "/uevent");
507 r = read_full_file(path, &uevent, &uevent_len);
509 /* empty uevent files may be write-only */
512 log_debug("sd-device: failed to read uevent file '%s': %s", path, strerror(-r));
516 for (i = 0; i < uevent_len; i++) {
519 if (!strchr(NEWLINE, uevent[i])) {
527 if (uevent[i] == '=') {
531 } else if (strchr(NEWLINE, uevent[i])) {
533 log_debug("sd-device: ignoring invalid uevent line '%s'", key);
546 if (strchr(NEWLINE, uevent[i])) {
549 r = handle_uevent_line(device, key, value, &major, &minor);
551 log_debug("sd-device: failed to handle uevent entry '%s=%s': %s", key, value, strerror(-r));
558 assert_not_reached("invalid state when parsing uevent file");
563 r = device_set_devnum(device, major, minor);
565 log_debug("sd-device: could not set 'MAJOR=%s' or 'MINOR=%s' from '%s': %s", major, minor, path, strerror(-r));
568 device->uevent_loaded = true;
573 _public_ int sd_device_get_ifindex(sd_device *device, int *ifindex) {
576 assert_return(device, -EINVAL);
577 assert_return(ifindex, -EINVAL);
579 r = device_read_uevent_file(device);
583 *ifindex = device->ifindex;
588 _public_ int sd_device_new_from_device_id(sd_device **ret, const char *id) {
591 assert_return(ret, -EINVAL);
592 assert_return(id, -EINVAL);
601 r = sscanf(id, "%c%i:%i", &type, &maj, &min);
605 return sd_device_new_from_devnum(ret, type, makedev(maj, min));
609 _cleanup_device_unref_ sd_device *device = NULL;
610 _cleanup_close_ int sk = -1;
611 struct ifreq ifr = {};
614 r = safe_atoi(&id[1], &ifr.ifr_ifindex);
617 else if (ifr.ifr_ifindex <= 0)
620 sk = socket(PF_INET, SOCK_DGRAM, 0);
624 r = ioctl(sk, SIOCGIFNAME, &ifr);
628 r = sd_device_new_from_subsystem_sysname(&device, "net", ifr.ifr_name);
632 r = sd_device_get_ifindex(device, &ifindex);
636 /* this is racey, so we might end up with the wrong device */
637 if (ifr.ifr_ifindex != ifindex)
647 char subsys[PATH_MAX];
650 (void)strscpy(subsys, sizeof(subsys), id + 1);
651 sysname = strchr(subsys, ':');
658 return sd_device_new_from_subsystem_sysname(ret, subsys, sysname);
665 _public_ int sd_device_get_syspath(sd_device *device, const char **ret) {
666 assert_return(device, -EINVAL);
667 assert_return(ret, -EINVAL);
669 assert(path_startswith(device->syspath, "/sys/"));
671 *ret = device->syspath;
676 static int device_new_from_child(sd_device **ret, sd_device *child) {
677 _cleanup_free_ char *path = NULL;
678 const char *subdir, *syspath;
684 r = sd_device_get_syspath(child, &syspath);
688 path = strdup(syspath);
691 subdir = path + strlen("/sys");
696 pos = strrchr(subdir, '/');
697 if (!pos || pos < subdir + 2)
702 r = sd_device_new_from_syspath(ret, path);
712 _public_ int sd_device_get_parent(sd_device *child, sd_device **ret) {
714 assert_return(ret, -EINVAL);
715 assert_return(child, -EINVAL);
717 if (!child->parent_set) {
718 child->parent_set = true;
720 (void)device_new_from_child(&child->parent, child);
726 *ret = child->parent;
731 int device_set_subsystem(sd_device *device, const char *_subsystem) {
732 _cleanup_free_ char *subsystem = NULL;
738 subsystem = strdup(_subsystem);
742 r = device_add_property_internal(device, "SUBSYSTEM", subsystem);
746 free(device->subsystem);
747 device->subsystem = subsystem;
750 device->subsystem_set = true;
755 _public_ int sd_device_get_subsystem(sd_device *device, const char **ret) {
756 assert_return(ret, -EINVAL);
757 assert_return(device, -EINVAL);
759 if (!device->subsystem_set) {
760 _cleanup_free_ char *subsystem = NULL;
765 /* read 'subsystem' link */
766 r = sd_device_get_syspath(device, &syspath);
770 path = strjoina(syspath, "/subsystem");
771 r = readlink_value(path, &subsystem);
773 r = device_set_subsystem(device, subsystem);
774 /* use implicit names */
775 else if (path_startswith(device->devpath, "/module/"))
776 r = device_set_subsystem(device, "module");
777 else if (strstr(device->devpath, "/drivers/"))
778 r = device_set_subsystem(device, "drivers");
779 else if (path_startswith(device->devpath, "/subsystem/") ||
780 path_startswith(device->devpath, "/class/") ||
781 path_startswith(device->devpath, "/bus/"))
782 r = device_set_subsystem(device, "subsystem");
784 return log_debug_errno(r, "sd-device: could not set subsystem for %s: %m", device->devpath);
786 device->subsystem_set = true;
789 *ret = device->subsystem;
794 _public_ int sd_device_get_devtype(sd_device *device, const char **devtype) {
800 r = device_read_uevent_file(device);
804 *devtype = device->devtype;
809 _public_ int sd_device_get_parent_with_subsystem_devtype(sd_device *child, const char *subsystem, const char *devtype, sd_device **ret) {
810 sd_device *parent = NULL;
813 assert_return(child, -EINVAL);
814 assert_return(subsystem, -EINVAL);
816 r = sd_device_get_parent(child, &parent);
818 const char *parent_subsystem = NULL;
819 const char *parent_devtype = NULL;
821 (void)sd_device_get_subsystem(parent, &parent_subsystem);
822 if (streq_ptr(parent_subsystem, subsystem)) {
826 (void)sd_device_get_devtype(parent, &parent_devtype);
827 if (streq_ptr(parent_devtype, devtype))
830 r = sd_device_get_parent(parent, &parent);
841 _public_ int sd_device_get_devnum(sd_device *device, dev_t *devnum) {
844 assert_return(device, -EINVAL);
845 assert_return(devnum, -EINVAL);
847 r = device_read_uevent_file(device);
851 *devnum = device->devnum;
856 int device_set_driver(sd_device *device, const char *_driver) {
857 _cleanup_free_ char *driver = NULL;
863 driver = strdup(_driver);
867 r = device_add_property_internal(device, "DRIVER", driver);
871 free(device->driver);
872 device->driver = driver;
875 device->driver_set = true;
880 _public_ int sd_device_get_driver(sd_device *device, const char **ret) {
881 assert_return(device, -EINVAL);
882 assert_return(ret, -EINVAL);
884 if (!device->driver_set) {
885 _cleanup_free_ char *driver = NULL;
890 r = sd_device_get_syspath(device, &syspath);
894 path = strjoina(syspath, "/driver");
895 r = readlink_value(path, &driver);
897 r = device_set_driver(device, driver);
903 *ret = device->driver;
908 _public_ int sd_device_get_devpath(sd_device *device, const char **devpath) {
909 assert_return(device, -EINVAL);
910 assert_return(devpath, -EINVAL);
912 assert(device->devpath);
913 assert(device->devpath[0] == '/');
915 *devpath = device->devpath;
920 _public_ int sd_device_get_devname(sd_device *device, const char **devname) {
923 assert_return(device, -EINVAL);
924 assert_return(devname, -EINVAL);
926 r = device_read_uevent_file(device);
930 if (!device->devname)
933 assert(path_startswith(device->devname, "/dev/"));
935 *devname = device->devname;
940 static int device_set_sysname(sd_device *device) {
941 _cleanup_free_ char *sysname = NULL;
942 const char *sysnum = NULL;
946 pos = strrchr(device->devpath, '/');
951 /* devpath is not a root directory */
952 if (*pos == '\0' || pos <= device->devpath)
955 sysname = strdup(pos);
959 /* some devices have '!' in their name, change that to '/' */
960 while (sysname[len] != '\0') {
961 if (sysname[len] == '!')
967 /* trailing number */
968 while (len > 0 && isdigit(sysname[--len]))
969 sysnum = &sysname[len];
974 free(device->sysname);
975 device->sysname = sysname;
978 device->sysnum = sysnum;
980 device->sysname_set = true;
985 _public_ int sd_device_get_sysname(sd_device *device, const char **ret) {
988 assert_return(device, -EINVAL);
989 assert_return(ret, -EINVAL);
991 if (!device->sysname_set) {
992 r = device_set_sysname(device);
997 *ret = device->sysname;
1002 _public_ int sd_device_get_sysnum(sd_device *device, const char **ret) {
1005 assert_return(device, -EINVAL);
1006 assert_return(ret, -EINVAL);
1008 if (!device->sysname_set) {
1009 r = device_set_sysname(device);
1014 *ret = device->sysnum;
1019 static bool is_valid_tag(const char *tag) {
1022 return !strchr(tag, ':') && !strchr(tag, ' ');
1025 int device_add_tag(sd_device *device, const char *tag) {
1031 if (!is_valid_tag(tag))
1034 r = set_ensure_allocated(&device->tags, &string_hash_ops);
1038 r = set_put_strdup(device->tags, tag);
1042 device->tags_generation ++;
1043 device->property_tags_outdated = true;
1048 int device_add_devlink(sd_device *device, const char *devlink) {
1054 r = set_ensure_allocated(&device->devlinks, &string_hash_ops);
1058 r = set_put_strdup(device->devlinks, devlink);
1062 device->devlinks_generation ++;
1063 device->property_devlinks_outdated = true;
1068 static int device_add_property_internal_from_string(sd_device *device, const char *str) {
1069 _cleanup_free_ char *key = NULL;
1079 value = strchr(key, '=');
1085 if (isempty(++value))
1088 return device_add_property_internal(device, key, value);
1091 int device_set_usec_initialized(sd_device *device, const char *initialized) {
1092 uint64_t usec_initialized;
1096 assert(initialized);
1098 r = safe_atou64(initialized, &usec_initialized);
1102 r = device_add_property_internal(device, "USEC_INITIALIZED", initialized);
1106 device->usec_initialized = usec_initialized;
1111 static int handle_db_line(sd_device *device, char key, const char *value) {
1120 r = device_add_tag(device, value);
1126 path = strjoina("/dev/", value);
1127 r = device_add_devlink(device, path);
1133 r = device_add_property_internal_from_string(device, value);
1139 r = device_set_usec_initialized(device, value);
1145 r = safe_atoi(value, &device->devlink_priority);
1151 r = safe_atoi(value, &device->watch_handle);
1157 log_debug("device db: unknown key '%c'", key);
1163 int device_get_id_filename(sd_device *device, const char **ret) {
1167 if (!device->id_filename) {
1168 _cleanup_free_ char *id = NULL;
1169 const char *subsystem;
1173 r = sd_device_get_subsystem(device, &subsystem);
1177 r = sd_device_get_devnum(device, &devnum);
1181 r = sd_device_get_ifindex(device, &ifindex);
1185 if (major(devnum) > 0) {
1186 /* use dev_t -- b259:131072, c254:0 */
1187 r = asprintf(&id, "%c%u:%u",
1188 streq(subsystem, "block") ? 'b' : 'c',
1189 major(devnum), minor(devnum));
1192 } else if (ifindex > 0) {
1193 /* use netdev ifindex -- n3 */
1194 r = asprintf(&id, "n%u", ifindex);
1198 /* use $subsys:$sysname -- pci:0000:00:1f.2
1199 * sysname() has '!' translated, get it from devpath
1201 const char *sysname;
1203 sysname = basename(device->devpath);
1207 r = asprintf(&id, "+%s:%s", subsystem, sysname);
1212 device->id_filename = id;
1216 *ret = device->id_filename;
1221 static int device_read_db(sd_device *device) {
1222 _cleanup_free_ char *db = NULL;
1224 const char *id, *value;
1238 if (device->db_loaded || device->sealed)
1241 r = device_get_id_filename(device, &id);
1245 path = strjoina("/run/udev/data/", id);
1247 r = read_full_file(path, &db, &db_len);
1252 log_debug("sd-device: failed to read db '%s': %s", path, strerror(-r));
1257 /* devices with a database entry are initialized */
1258 device->is_initialized = true;;
1260 for (i = 0; i < db_len; i++) {
1263 if (!strchr(NEWLINE, db[i])) {
1272 log_debug("sd-device: ignoring invalid db entry with key '%c'", key);
1274 state = INVALID_LINE;
1289 if (strchr(NEWLINE, db[i]))
1294 if (strchr(NEWLINE, db[i])) {
1296 r = handle_db_line(device, key, value);
1298 log_debug("sd-device: failed to handle db entry '%c:%s': %s", key, value, strerror(-r));
1305 assert_not_reached("invalid state when parsing db");
1309 device->db_loaded = true;
1314 _public_ int sd_device_get_is_initialized(sd_device *device, int *initialized) {
1317 assert_return(device, -EINVAL);
1318 assert_return(initialized, -EINVAL);
1320 r = device_read_db(device);
1324 *initialized = device->is_initialized;
1329 _public_ int sd_device_get_usec_since_initialized(sd_device *device, uint64_t *usec) {
1333 assert_return(device, -EINVAL);
1334 assert_return(usec, -EINVAL);
1336 r = device_read_db(device);
1340 if (!device->is_initialized)
1343 if (!device->usec_initialized)
1346 now_ts = now(clock_boottime_or_monotonic());
1348 if (now_ts < device->usec_initialized)
1351 *usec = now_ts - device->usec_initialized;
1356 _public_ const char *sd_device_get_tag_first(sd_device *device) {
1357 assert_return(device, NULL);
1359 (void) device_read_db(device);
1361 device->tags_iterator_generation = device->tags_generation;
1362 device->tags_iterator = ITERATOR_FIRST;
1364 return set_iterate(device->tags, &device->tags_iterator);
1367 _public_ const char *sd_device_get_tag_next(sd_device *device) {
1368 assert_return(device, NULL);
1370 (void) device_read_db(device);
1372 if (device->tags_iterator_generation != device->tags_generation)
1375 return set_iterate(device->tags, &device->tags_iterator);
1378 _public_ const char *sd_device_get_devlink_first(sd_device *device) {
1379 assert_return(device, NULL);
1381 (void) device_read_db(device);
1383 device->devlinks_iterator_generation = device->devlinks_generation;
1384 device->devlinks_iterator = ITERATOR_FIRST;
1386 return set_iterate(device->devlinks, &device->devlinks_iterator);
1389 _public_ const char *sd_device_get_devlink_next(sd_device *device) {
1390 assert_return(device, NULL);
1392 (void) device_read_db(device);
1394 if (device->devlinks_iterator_generation != device->devlinks_generation)
1397 return set_iterate(device->devlinks, &device->devlinks_iterator);
1400 static int device_properties_prepare(sd_device *device) {
1405 r = device_read_uevent_file(device);
1409 r = device_read_db(device);
1413 if (device->property_devlinks_outdated) {
1414 char *devlinks = NULL;
1415 const char *devlink;
1417 devlink = sd_device_get_devlink_first(device);
1419 devlinks = strdupa(devlink);
1421 while ((devlink = sd_device_get_devlink_next(device)))
1422 devlinks = strjoina(devlinks, " ", devlink);
1424 r = device_add_property_internal(device, "DEVLINKS", devlinks);
1428 device->property_devlinks_outdated = false;
1431 if (device->property_tags_outdated) {
1435 tag = sd_device_get_tag_first(device);
1437 tags = strjoina(":", tag);
1439 while ((tag = sd_device_get_tag_next(device)))
1440 tags = strjoina(tags, ":", tag);
1442 tags = strjoina(tags, ":");
1444 r = device_add_property_internal(device, "TAGS", tags);
1448 device->property_tags_outdated = false;
1454 _public_ const char *sd_device_get_property_first(sd_device *device, const char **_value) {
1459 assert_return(device, NULL);
1461 r = device_properties_prepare(device);
1465 device->properties_iterator_generation = device->properties_generation;
1466 device->properties_iterator = ITERATOR_FIRST;
1468 value = ordered_hashmap_iterate(device->properties, &device->properties_iterator, (const void**)&key);
1476 _public_ const char *sd_device_get_property_next(sd_device *device, const char **_value) {
1481 assert_return(device, NULL);
1483 r = device_properties_prepare(device);
1487 if (device->properties_iterator_generation != device->properties_generation)
1490 value = ordered_hashmap_iterate(device->properties, &device->properties_iterator, (const void**)&key);
1498 static int device_sysattrs_read_all(sd_device *device) {
1499 _cleanup_closedir_ DIR *dir = NULL;
1500 const char *syspath;
1501 struct dirent *dent;
1506 if (device->sysattrs_read)
1509 r = sd_device_get_syspath(device, &syspath);
1513 dir = opendir(syspath);
1517 r = set_ensure_allocated(&device->sysattrs, &string_hash_ops);
1521 for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
1523 struct stat statbuf;
1525 /* only handle symlinks and regular files */
1526 if (dent->d_type != DT_LNK && dent->d_type != DT_REG)
1529 path = strjoina(syspath, "/", dent->d_name);
1531 if (lstat(path, &statbuf) != 0)
1534 if (!(statbuf.st_mode & S_IRUSR))
1537 r = set_put_strdup(device->sysattrs, dent->d_name);
1542 device->sysattrs_read = true;
1547 _public_ const char *sd_device_get_sysattr_first(sd_device *device) {
1550 assert_return(device, NULL);
1552 if (!device->sysattrs_read) {
1553 r = device_sysattrs_read_all(device);
1560 device->sysattrs_iterator = ITERATOR_FIRST;
1562 return set_iterate(device->sysattrs, &device->sysattrs_iterator);
1565 _public_ const char *sd_device_get_sysattr_next(sd_device *device) {
1566 assert_return(device, NULL);
1568 if (!device->sysattrs_read)
1571 return set_iterate(device->sysattrs, &device->sysattrs_iterator);
1574 _public_ int sd_device_has_tag(sd_device *device, const char *tag) {
1575 assert_return(device, -EINVAL);
1576 assert_return(tag, -EINVAL);
1578 (void) device_read_db(device);
1580 return !!set_contains(device->tags, tag);
1583 _public_ int sd_device_get_property_value(sd_device *device, const char *key, const char **_value) {
1587 assert_return(device, -EINVAL);
1588 assert_return(key, -EINVAL);
1589 assert_return(_value, -EINVAL);
1591 r = device_properties_prepare(device);
1595 value = ordered_hashmap_get(device->properties, key);
1604 /* replaces the value if it already exists */
1605 static int device_add_sysattr_value(sd_device *device, const char *_key, char *value) {
1606 _cleanup_free_ char *key = NULL;
1607 _cleanup_free_ char *value_old = NULL;
1613 r = hashmap_ensure_allocated(&device->sysattr_values, &string_hash_ops);
1617 value_old = hashmap_remove2(device->sysattr_values, _key, (void **)&key);
1624 r = hashmap_put(device->sysattr_values, key, value);
1633 static int device_get_sysattr_value(sd_device *device, const char *_key, const char **_value) {
1634 const char *key = NULL, *value;
1639 value = hashmap_get2(device->sysattr_values, _key, (void **) &key);
1649 /* We cache all sysattr lookups. If an attribute does not exist, it is stored
1650 * with a NULL value in the cache, otherwise the returned string is stored */
1651 _public_ int sd_device_get_sysattr_value(sd_device *device, const char *sysattr, const char **_value) {
1652 _cleanup_free_ char *value = NULL;
1653 const char *syspath, *cached_value = NULL;
1655 struct stat statbuf;
1658 assert_return(device, -EINVAL);
1659 assert_return(sysattr, -EINVAL);
1661 /* look for possibly already cached result */
1662 r = device_get_sysattr_value(device, sysattr, &cached_value);
1668 /* we looked up the sysattr before and it did not exist */
1672 *_value = cached_value;
1677 r = sd_device_get_syspath(device, &syspath);
1681 path = strjoina(syspath, "/", sysattr);
1682 r = lstat(path, &statbuf);
1684 /* remember that we could not access the sysattr */
1685 r = device_add_sysattr_value(device, sysattr, NULL);
1690 } else if (S_ISLNK(statbuf.st_mode)) {
1691 /* Some core links return only the last element of the target path,
1692 * these are just values, the paths should not be exposed. */
1693 if (STR_IN_SET(sysattr, "driver", "subsystem", "module")) {
1694 r = readlink_value(path, &value);
1699 } else if (S_ISDIR(statbuf.st_mode)) {
1700 /* skip directories */
1702 } else if (!(statbuf.st_mode & S_IRUSR)) {
1703 /* skip non-readable files */
1708 /* read attribute value */
1709 r = read_full_file(path, &value, &size);
1713 /* drop trailing newlines */
1714 while (size > 0 && value[--size] == '\n')
1718 r = device_add_sysattr_value(device, sysattr, value);
1728 static void device_remove_sysattr_value(sd_device *device, const char *_key) {
1729 _cleanup_free_ char *key = NULL;
1730 _cleanup_free_ char *value = NULL;
1735 value = hashmap_remove2(device->sysattr_values, _key, (void **) &key);
1740 /* set the attribute and save it in the cache. If a NULL value is passed the
1741 * attribute is cleared from the cache */
1742 _public_ int sd_device_set_sysattr_value(sd_device *device, const char *sysattr, char *_value) {
1743 _cleanup_close_ int fd = -1;
1744 _cleanup_free_ char *value = NULL;
1745 const char *syspath;
1747 struct stat statbuf;
1748 size_t value_len = 0;
1752 assert_return(device, -EINVAL);
1753 assert_return(sysattr, -EINVAL);
1756 device_remove_sysattr_value(device, sysattr);
1761 r = sd_device_get_syspath(device, &syspath);
1765 path = strjoina(syspath, "/", sysattr);
1766 r = lstat(path, &statbuf);
1772 r = device_add_sysattr_value(device, sysattr, value);
1779 if (S_ISLNK(statbuf.st_mode))
1782 /* skip directories */
1783 if (S_ISDIR(statbuf.st_mode))
1786 /* skip non-readable files */
1787 if ((statbuf.st_mode & S_IRUSR) == 0)
1790 value_len = strlen(_value);
1792 /* drop trailing newlines */
1793 while (value_len > 0 && _value[value_len - 1] == '\n')
1794 _value[--value_len] = '\0';
1796 /* value length is limited to 4k */
1797 if (value_len > 4096)
1800 fd = open(path, O_WRONLY | O_CLOEXEC);
1804 value = strdup(_value);
1808 size = write(fd, value, value_len);
1812 if ((size_t)size != value_len)
1815 r = device_add_sysattr_value(device, sysattr, value);