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 /* empty uevent files may be write-only */
506 log_debug("sd-device: failed to read uevent file '%s': %s", path, strerror(-r));
510 for (i = 0; i < uevent_len; i++) {
513 if (!strchr(NEWLINE, uevent[i])) {
521 if (uevent[i] == '=') {
525 } else if (strchr(NEWLINE, uevent[i])) {
527 log_debug("sd-device: ignoring invalid uevent line '%s'", key);
540 if (strchr(NEWLINE, uevent[i])) {
543 r = handle_uevent_line(device, key, value, &major, &minor);
545 log_debug("sd-device: failed to handle uevent entry '%s=%s': %s", key, value, strerror(-r));
552 assert_not_reached("invalid state when parsing uevent file");
557 r = device_set_devnum(device, major, minor);
559 log_debug("sd-device: could not set 'MAJOR=%s' or 'MINOR=%s' from '%s': %s", major, minor, path, strerror(-r));
562 device->uevent_loaded = true;
567 _public_ int sd_device_get_ifindex(sd_device *device, int *ifindex) {
570 assert_return(device, -EINVAL);
571 assert_return(ifindex, -EINVAL);
573 r = device_read_uevent_file(device);
577 *ifindex = device->ifindex;
582 _public_ int sd_device_new_from_device_id(sd_device **ret, const char *id) {
585 assert_return(ret, -EINVAL);
586 assert_return(id, -EINVAL);
595 r = sscanf(id, "%c%i:%i", &type, &maj, &min);
599 return sd_device_new_from_devnum(ret, type, makedev(maj, min));
603 _cleanup_device_unref_ sd_device *device = NULL;
604 _cleanup_close_ int sk = -1;
605 struct ifreq ifr = {};
608 r = safe_atoi(&id[1], &ifr.ifr_ifindex);
611 else if (ifr.ifr_ifindex <= 0)
614 sk = socket(PF_INET, SOCK_DGRAM, 0);
618 r = ioctl(sk, SIOCGIFNAME, &ifr);
622 r = sd_device_new_from_subsystem_sysname(&device, "net", ifr.ifr_name);
626 r = sd_device_get_ifindex(device, &ifindex);
630 /* this si racey, so we might end up with the wrong device */
631 if (ifr.ifr_ifindex != ifindex)
641 char subsys[PATH_MAX];
644 (void)strscpy(subsys, sizeof(subsys), id + 1);
645 sysname = strchr(subsys, ':');
652 return sd_device_new_from_subsystem_sysname(ret, subsys, sysname);
659 _public_ int sd_device_get_syspath(sd_device *device, const char **ret) {
660 assert_return(device, -EINVAL);
661 assert_return(ret, -EINVAL);
663 assert(path_startswith(device->syspath, "/sys/"));
665 *ret = device->syspath;
670 static int device_new_from_child(sd_device **ret, sd_device *child) {
671 _cleanup_free_ char *path = NULL;
672 const char *subdir, *syspath;
678 r = sd_device_get_syspath(child, &syspath);
682 path = strdup(syspath);
685 subdir = path + strlen("/sys");
690 pos = strrchr(subdir, '/');
691 if (!pos || pos < subdir + 2)
696 r = sd_device_new_from_syspath(ret, path);
706 _public_ int sd_device_get_parent(sd_device *child, sd_device **ret) {
708 assert_return(ret, -EINVAL);
709 assert_return(child, -EINVAL);
711 if (!child->parent_set) {
712 child->parent_set = true;
714 (void)device_new_from_child(&child->parent, child);
720 *ret = child->parent;
725 int device_set_subsystem(sd_device *device, const char *_subsystem) {
726 _cleanup_free_ char *subsystem = NULL;
732 subsystem = strdup(_subsystem);
736 r = device_add_property_internal(device, "SUBSYSTEM", subsystem);
740 free(device->subsystem);
741 device->subsystem = subsystem;
744 device->subsystem_set = true;
749 _public_ int sd_device_get_subsystem(sd_device *device, const char **ret) {
750 assert_return(ret, -EINVAL);
751 assert_return(device, -EINVAL);
753 if (!device->subsystem_set) {
754 _cleanup_free_ char *subsystem = NULL;
759 /* read 'subsystem' link */
760 r = sd_device_get_syspath(device, &syspath);
764 path = strjoina(syspath, "/subsystem");
765 r = readlink_value(path, &subsystem);
767 r = device_set_subsystem(device, subsystem);
768 /* use implicit names */
769 else if (path_startswith(device->devpath, "/module/"))
770 r = device_set_subsystem(device, "module");
771 else if (strstr(device->devpath, "/drivers/"))
772 r = device_set_subsystem(device, "drivers");
773 else if (path_startswith(device->devpath, "/subsystem/") ||
774 path_startswith(device->devpath, "/class/") ||
775 path_startswith(device->devpath, "/bus/"))
776 r = device_set_subsystem(device, "subsystem");
778 return log_debug_errno(r, "sd-devcie: could not set subsystem for %s: %m", device->devpath);
780 device->subsystem_set = true;
783 *ret = device->subsystem;
788 _public_ int sd_device_get_devtype(sd_device *device, const char **devtype) {
794 r = device_read_uevent_file(device);
798 *devtype = device->devtype;
803 _public_ int sd_device_get_parent_with_subsystem_devtype(sd_device *child, const char *subsystem, const char *devtype, sd_device **ret) {
804 sd_device *parent = NULL;
807 assert_return(child, -EINVAL);
808 assert_return(subsystem, -EINVAL);
810 r = sd_device_get_parent(child, &parent);
812 const char *parent_subsystem = NULL;
813 const char *parent_devtype = NULL;
815 (void)sd_device_get_subsystem(parent, &parent_subsystem);
816 if (streq_ptr(parent_subsystem, subsystem)) {
820 (void)sd_device_get_devtype(parent, &parent_devtype);
821 if (streq_ptr(parent_devtype, devtype))
824 r = sd_device_get_parent(parent, &parent);
835 _public_ int sd_device_get_devnum(sd_device *device, dev_t *devnum) {
838 assert_return(device, -EINVAL);
839 assert_return(devnum, -EINVAL);
841 r = device_read_uevent_file(device);
845 *devnum = device->devnum;
850 int device_set_driver(sd_device *device, const char *_driver) {
851 _cleanup_free_ char *driver = NULL;
857 driver = strdup(_driver);
861 r = device_add_property_internal(device, "DRIVER", driver);
865 free(device->driver);
866 device->driver = driver;
869 device->driver_set = true;
874 _public_ int sd_device_get_driver(sd_device *device, const char **ret) {
875 assert_return(device, -EINVAL);
876 assert_return(ret, -EINVAL);
878 if (!device->driver_set) {
879 _cleanup_free_ char *driver = NULL;
884 r = sd_device_get_syspath(device, &syspath);
888 path = strjoina(syspath, "/driver");
889 r = readlink_value(path, &driver);
891 r = device_set_driver(device, driver);
897 *ret = device->driver;
902 _public_ int sd_device_get_devpath(sd_device *device, const char **devpath) {
903 assert_return(device, -EINVAL);
904 assert_return(devpath, -EINVAL);
906 assert(device->devpath);
907 assert(device->devpath[0] == '/');
909 *devpath = device->devpath;
914 _public_ int sd_device_get_devname(sd_device *device, const char **devname) {
917 assert_return(device, -EINVAL);
918 assert_return(devname, -EINVAL);
920 r = device_read_uevent_file(device);
924 if (!device->devname)
927 assert(path_startswith(device->devname, "/dev/"));
929 *devname = device->devname;
934 static int device_set_sysname(sd_device *device) {
935 _cleanup_free_ char *sysname = NULL;
936 const char *sysnum = NULL;
940 pos = strrchr(device->devpath, '/');
945 /* devpath is not a root directory */
946 if (*pos == '\0' || pos <= device->devpath)
949 sysname = strdup(pos);
953 /* some devices have '!' in their name, change that to '/' */
954 while (sysname[len] != '\0') {
955 if (sysname[len] == '!')
961 /* trailing number */
962 while (len > 0 && isdigit(sysname[--len]))
963 sysnum = &sysname[len];
968 free(device->sysname);
969 device->sysname = sysname;
972 device->sysnum = sysnum;
974 device->sysname_set = true;
979 _public_ int sd_device_get_sysname(sd_device *device, const char **ret) {
982 assert_return(device, -EINVAL);
983 assert_return(ret, -EINVAL);
985 if (!device->sysname_set) {
986 r = device_set_sysname(device);
991 *ret = device->sysname;
996 _public_ int sd_device_get_sysnum(sd_device *device, const char **ret) {
999 assert_return(device, -EINVAL);
1000 assert_return(ret, -EINVAL);
1002 if (!device->sysname_set) {
1003 r = device_set_sysname(device);
1008 *ret = device->sysnum;
1013 static bool is_valid_tag(const char *tag) {
1016 return !strchr(tag, ':') && !strchr(tag, ' ');
1019 int device_add_tag(sd_device *device, const char *tag) {
1025 if (!is_valid_tag(tag))
1028 r = set_ensure_allocated(&device->tags, &string_hash_ops);
1032 r = set_put_strdup(device->tags, tag);
1036 device->tags_generation ++;
1037 device->property_tags_outdated = true;
1042 int device_add_devlink(sd_device *device, const char *devlink) {
1048 r = set_ensure_allocated(&device->devlinks, &string_hash_ops);
1052 r = set_put_strdup(device->devlinks, devlink);
1056 device->devlinks_generation ++;
1057 device->property_devlinks_outdated = true;
1062 static int device_add_property_internal_from_string(sd_device *device, const char *str) {
1063 _cleanup_free_ char *key = NULL;
1073 value = strchr(key, '=');
1079 if (isempty(++value))
1082 return device_add_property_internal(device, key, value);
1085 int device_set_usec_initialized(sd_device *device, const char *initialized) {
1086 uint64_t usec_initialized;
1090 assert(initialized);
1092 r = safe_atou64(initialized, &usec_initialized);
1096 r = device_add_property_internal(device, "USEC_INITIALIZED", initialized);
1100 device->usec_initialized = usec_initialized;
1105 static int handle_db_line(sd_device *device, char key, const char *value) {
1114 r = device_add_tag(device, value);
1120 path = strjoina("/dev/", value);
1121 r = device_add_devlink(device, path);
1127 r = device_add_property_internal_from_string(device, value);
1133 r = device_set_usec_initialized(device, value);
1139 r = safe_atoi(value, &device->devlink_priority);
1145 r = safe_atoi(value, &device->watch_handle);
1151 log_debug("device db: unknown key '%c'", key);
1157 int device_get_id_filename(sd_device *device, const char **ret) {
1161 if (!device->id_filename) {
1162 _cleanup_free_ char *id = NULL;
1163 const char *subsystem;
1167 r = sd_device_get_subsystem(device, &subsystem);
1171 r = sd_device_get_devnum(device, &devnum);
1175 r = sd_device_get_ifindex(device, &ifindex);
1179 if (major(devnum) > 0) {
1180 /* use dev_t -- b259:131072, c254:0 */
1181 r = asprintf(&id, "%c%u:%u",
1182 streq(subsystem, "block") ? 'b' : 'c',
1183 major(devnum), minor(devnum));
1186 } else if (ifindex > 0) {
1187 /* use netdev ifindex -- n3 */
1188 r = asprintf(&id, "n%u", ifindex);
1192 /* use $subsys:$sysname -- pci:0000:00:1f.2
1193 * sysname() has '!' translated, get it from devpath
1195 const char *sysname;
1197 sysname = basename(device->devpath);
1201 r = asprintf(&id, "+%s:%s", subsystem, sysname);
1206 device->id_filename = id;
1210 *ret = device->id_filename;
1215 static int device_read_db(sd_device *device) {
1216 _cleanup_free_ char *db = NULL;
1218 const char *id, *value;
1232 if (device->db_loaded || device->sealed)
1235 r = device_get_id_filename(device, &id);
1239 path = strjoina("/run/udev/data/", id);
1241 r = read_full_file(path, &db, &db_len);
1246 log_debug("sd-device: failed to read db '%s': %s", path, strerror(-r));
1251 /* devices with a database entry are initialized */
1252 device->is_initialized = true;;
1254 for (i = 0; i < db_len; i++) {
1257 if (!strchr(NEWLINE, db[i])) {
1266 log_debug("sd-device: ignoring invalid db entry with key '%c'", key);
1268 state = INVALID_LINE;
1283 if (strchr(NEWLINE, db[i]))
1288 if (strchr(NEWLINE, db[i])) {
1290 r = handle_db_line(device, key, value);
1292 log_debug("sd-device: failed to handle db entry '%c:%s': %s", key, value, strerror(-r));
1299 assert_not_reached("invalid state when parsing db");
1303 device->db_loaded = true;
1308 _public_ int sd_device_get_is_initialized(sd_device *device, int *initialized) {
1311 assert_return(device, -EINVAL);
1312 assert_return(initialized, -EINVAL);
1314 r = device_read_db(device);
1318 *initialized = device->is_initialized;
1323 _public_ int sd_device_get_usec_since_initialized(sd_device *device, uint64_t *usec) {
1327 assert_return(device, -EINVAL);
1328 assert_return(usec, -EINVAL);
1330 r = device_read_db(device);
1334 if (!device->is_initialized)
1337 if (!device->usec_initialized)
1340 now_ts = now(clock_boottime_or_monotonic());
1342 if (now_ts < device->usec_initialized)
1345 *usec = now_ts - device->usec_initialized;
1350 _public_ const char *sd_device_get_tag_first(sd_device *device) {
1351 assert_return(device, NULL);
1353 (void) device_read_db(device);
1355 device->tags_iterator_generation = device->tags_generation;
1356 device->tags_iterator = ITERATOR_FIRST;
1358 return set_iterate(device->tags, &device->tags_iterator);
1361 _public_ const char *sd_device_get_tag_next(sd_device *device) {
1362 assert_return(device, NULL);
1364 (void) device_read_db(device);
1366 if (device->tags_iterator_generation != device->tags_generation)
1369 return set_iterate(device->tags, &device->tags_iterator);
1372 _public_ const char *sd_device_get_devlink_first(sd_device *device) {
1373 assert_return(device, NULL);
1375 (void) device_read_db(device);
1377 device->devlinks_iterator_generation = device->devlinks_generation;
1378 device->devlinks_iterator = ITERATOR_FIRST;
1380 return set_iterate(device->devlinks, &device->devlinks_iterator);
1383 _public_ const char *sd_device_get_devlink_next(sd_device *device) {
1384 assert_return(device, NULL);
1386 (void) device_read_db(device);
1388 if (device->devlinks_iterator_generation != device->devlinks_generation)
1391 return set_iterate(device->devlinks, &device->devlinks_iterator);
1394 static int device_properties_prepare(sd_device *device) {
1399 r = device_read_uevent_file(device);
1403 r = device_read_db(device);
1407 if (device->property_devlinks_outdated) {
1408 char *devlinks = NULL;
1409 const char *devlink;
1411 devlink = sd_device_get_devlink_first(device);
1413 devlinks = strdupa(devlink);
1415 while ((devlink = sd_device_get_devlink_next(device)))
1416 devlinks = strjoina(devlinks, " ", devlink);
1418 r = device_add_property_internal(device, "DEVLINKS", devlinks);
1422 device->property_devlinks_outdated = false;
1425 if (device->property_tags_outdated) {
1429 tag = sd_device_get_tag_first(device);
1431 tags = strjoina(":", tag);
1433 while ((tag = sd_device_get_tag_next(device)))
1434 tags = strjoina(tags, ":", tag);
1436 tags = strjoina(tags, ":");
1438 r = device_add_property_internal(device, "TAGS", tags);
1442 device->property_tags_outdated = false;
1448 _public_ const char *sd_device_get_property_first(sd_device *device, const char **_value) {
1453 assert_return(device, NULL);
1455 r = device_properties_prepare(device);
1459 device->properties_iterator_generation = device->properties_generation;
1460 device->properties_iterator = ITERATOR_FIRST;
1462 value = ordered_hashmap_iterate(device->properties, &device->properties_iterator, (const void**)&key);
1470 _public_ const char *sd_device_get_property_next(sd_device *device, const char **_value) {
1475 assert_return(device, NULL);
1477 r = device_properties_prepare(device);
1481 if (device->properties_iterator_generation != device->properties_generation)
1484 value = ordered_hashmap_iterate(device->properties, &device->properties_iterator, (const void**)&key);
1492 static int device_sysattrs_read_all(sd_device *device) {
1493 _cleanup_closedir_ DIR *dir = NULL;
1494 const char *syspath;
1495 struct dirent *dent;
1500 if (device->sysattrs_read)
1503 r = sd_device_get_syspath(device, &syspath);
1507 dir = opendir(syspath);
1511 r = set_ensure_allocated(&device->sysattrs, &string_hash_ops);
1515 for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
1517 struct stat statbuf;
1519 /* only handle symlinks and regular files */
1520 if (dent->d_type != DT_LNK && dent->d_type != DT_REG)
1523 path = strjoina(syspath, "/", dent->d_name);
1525 if (lstat(path, &statbuf) != 0)
1528 if (!(statbuf.st_mode & S_IRUSR))
1531 r = set_put_strdup(device->sysattrs, dent->d_name);
1536 device->sysattrs_read = true;
1541 _public_ const char *sd_device_get_sysattr_first(sd_device *device) {
1544 assert_return(device, NULL);
1546 if (!device->sysattrs_read) {
1547 r = device_sysattrs_read_all(device);
1554 device->sysattrs_iterator = ITERATOR_FIRST;
1556 return set_iterate(device->sysattrs, &device->sysattrs_iterator);
1559 _public_ const char *sd_device_get_sysattr_next(sd_device *device) {
1560 assert_return(device, NULL);
1562 if (!device->sysattrs_read)
1565 return set_iterate(device->sysattrs, &device->sysattrs_iterator);
1568 _public_ int sd_device_has_tag(sd_device *device, const char *tag) {
1569 assert_return(device, -EINVAL);
1570 assert_return(tag, -EINVAL);
1572 (void) device_read_db(device);
1574 return !!set_contains(device->tags, tag);
1577 _public_ int sd_device_get_property_value(sd_device *device, const char *key, const char **_value) {
1581 assert_return(device, -EINVAL);
1582 assert_return(key, -EINVAL);
1583 assert_return(_value, -EINVAL);
1585 r = device_properties_prepare(device);
1589 value = ordered_hashmap_get(device->properties, key);
1598 /* replaces the value if it already exists */
1599 static int device_add_sysattr_value(sd_device *device, const char *_key, char *value) {
1600 _cleanup_free_ char *key = NULL;
1601 _cleanup_free_ char *value_old = NULL;
1607 r = hashmap_ensure_allocated(&device->sysattr_values, &string_hash_ops);
1611 value_old = hashmap_remove2(device->sysattr_values, _key, (void **)&key);
1618 r = hashmap_put(device->sysattr_values, key, value);
1627 static int device_get_sysattr_value(sd_device *device, const char *_key, const char **_value) {
1628 const char *key = NULL, *value;
1633 value = hashmap_get2(device->sysattr_values, _key, (void **) &key);
1643 /* We cache all sysattr lookups. If an attribute does not exist, it is stored
1644 * with a NULL value in the cache, otherwise the returned string is stored */
1645 _public_ int sd_device_get_sysattr_value(sd_device *device, const char *sysattr, const char **_value) {
1646 _cleanup_free_ char *value = NULL;
1647 const char *syspath, *cached_value = NULL;
1649 struct stat statbuf;
1652 assert_return(device, -EINVAL);
1653 assert_return(sysattr, -EINVAL);
1655 /* look for possibly already cached result */
1656 r = device_get_sysattr_value(device, sysattr, &cached_value);
1662 /* we looked up the sysattr before and it did not exist */
1666 *_value = cached_value;
1671 r = sd_device_get_syspath(device, &syspath);
1675 path = strjoina(syspath, "/", sysattr);
1676 r = lstat(path, &statbuf);
1678 /* remember that we could not access the sysattr */
1679 r = device_add_sysattr_value(device, sysattr, NULL);
1684 } else if (S_ISLNK(statbuf.st_mode)) {
1685 /* Some core links return only the last element of the target path,
1686 * these are just values, the paths should not be exposed. */
1687 if (STR_IN_SET(sysattr, "driver", "subsystem", "module")) {
1688 r = readlink_value(path, &value);
1693 } else if (S_ISDIR(statbuf.st_mode)) {
1694 /* skip directories */
1696 } else if (!(statbuf.st_mode & S_IRUSR)) {
1697 /* skip non-readable files */
1702 /* read attribute value */
1703 r = read_full_file(path, &value, &size);
1707 /* drop trailing newlines */
1708 while (size > 0 && value[--size] == '\n')
1712 r = device_add_sysattr_value(device, sysattr, value);
1722 static void device_remove_sysattr_value(sd_device *device, const char *_key) {
1723 _cleanup_free_ char *key = NULL;
1724 _cleanup_free_ char *value = NULL;
1729 value = hashmap_remove2(device->sysattr_values, _key, (void **) &key);
1734 /* set the attribute and save it in the cache. If a NULL value is passed the
1735 * attribute is cleared from the cache */
1736 _public_ int sd_device_set_sysattr_value(sd_device *device, const char *sysattr, char *_value) {
1737 _cleanup_close_ int fd = -1;
1738 _cleanup_free_ char *value = NULL;
1739 const char *syspath;
1741 struct stat statbuf;
1742 size_t value_len = 0;
1746 assert_return(device, -EINVAL);
1747 assert_return(sysattr, -EINVAL);
1750 device_remove_sysattr_value(device, sysattr);
1755 r = sd_device_get_syspath(device, &syspath);
1759 path = strjoina(syspath, "/", sysattr);
1760 r = lstat(path, &statbuf);
1766 r = device_add_sysattr_value(device, sysattr, value);
1773 if (S_ISLNK(statbuf.st_mode))
1776 /* skip directories */
1777 if (S_ISDIR(statbuf.st_mode))
1780 /* skip non-readable files */
1781 if ((statbuf.st_mode & S_IRUSR) == 0)
1784 value_len = strlen(_value);
1786 /* drop trailing newlines */
1787 while (value_len > 0 && _value[value_len - 1] == '\n')
1788 _value[--value_len] = '\0';
1790 /* value length is limited to 4k */
1791 if (value_len > 4096)
1794 fd = open(path, O_WRONLY | O_CLOEXEC);
1798 value = strdup(_value);
1802 size = write(fd, value, value_len);
1806 if ((size_t)size != value_len)
1809 r = device_add_sysattr_value(device, sysattr, value);