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 r = sd_device_get_syspath(device, &syspath);
507 path = strjoina(syspath, "/uevent");
509 r = read_full_file(path, &uevent, &uevent_len);
511 /* empty uevent files may be write-only */
514 log_debug("sd-device: failed to read uevent file '%s': %s", path, strerror(-r));
518 for (i = 0; i < uevent_len; i++) {
521 if (!strchr(NEWLINE, uevent[i])) {
529 if (uevent[i] == '=') {
533 } else if (strchr(NEWLINE, uevent[i])) {
535 log_debug("sd-device: ignoring invalid uevent line '%s'", key);
548 if (strchr(NEWLINE, uevent[i])) {
551 r = handle_uevent_line(device, key, value, &major, &minor);
553 log_debug("sd-device: failed to handle uevent entry '%s=%s': %s", key, value, strerror(-r));
560 assert_not_reached("invalid state when parsing uevent file");
565 r = device_set_devnum(device, major, minor);
567 log_debug("sd-device: could not set 'MAJOR=%s' or 'MINOR=%s' from '%s': %s", major, minor, path, strerror(-r));
570 device->uevent_loaded = true;
575 _public_ int sd_device_get_ifindex(sd_device *device, int *ifindex) {
578 assert_return(device, -EINVAL);
579 assert_return(ifindex, -EINVAL);
581 r = device_read_uevent_file(device);
585 *ifindex = device->ifindex;
590 _public_ int sd_device_new_from_device_id(sd_device **ret, const char *id) {
593 assert_return(ret, -EINVAL);
594 assert_return(id, -EINVAL);
603 r = sscanf(id, "%c%i:%i", &type, &maj, &min);
607 return sd_device_new_from_devnum(ret, type, makedev(maj, min));
611 _cleanup_device_unref_ sd_device *device = NULL;
612 _cleanup_close_ int sk = -1;
613 struct ifreq ifr = {};
616 r = safe_atoi(&id[1], &ifr.ifr_ifindex);
619 else if (ifr.ifr_ifindex <= 0)
622 sk = socket(PF_INET, SOCK_DGRAM, 0);
626 r = ioctl(sk, SIOCGIFNAME, &ifr);
630 r = sd_device_new_from_subsystem_sysname(&device, "net", ifr.ifr_name);
634 r = sd_device_get_ifindex(device, &ifindex);
638 /* this is racey, so we might end up with the wrong device */
639 if (ifr.ifr_ifindex != ifindex)
649 char subsys[PATH_MAX];
652 (void)strscpy(subsys, sizeof(subsys), id + 1);
653 sysname = strchr(subsys, ':');
660 return sd_device_new_from_subsystem_sysname(ret, subsys, sysname);
667 _public_ int sd_device_get_syspath(sd_device *device, const char **ret) {
668 assert_return(device, -EINVAL);
669 assert_return(ret, -EINVAL);
671 assert(path_startswith(device->syspath, "/sys/"));
673 *ret = device->syspath;
678 static int device_new_from_child(sd_device **ret, sd_device *child) {
679 _cleanup_free_ char *path = NULL;
680 const char *subdir, *syspath;
686 r = sd_device_get_syspath(child, &syspath);
690 path = strdup(syspath);
693 subdir = path + strlen("/sys");
698 pos = strrchr(subdir, '/');
699 if (!pos || pos < subdir + 2)
704 r = sd_device_new_from_syspath(ret, path);
714 _public_ int sd_device_get_parent(sd_device *child, sd_device **ret) {
716 assert_return(ret, -EINVAL);
717 assert_return(child, -EINVAL);
719 if (!child->parent_set) {
720 child->parent_set = true;
722 (void)device_new_from_child(&child->parent, child);
728 *ret = child->parent;
733 int device_set_subsystem(sd_device *device, const char *_subsystem) {
734 _cleanup_free_ char *subsystem = NULL;
740 subsystem = strdup(_subsystem);
744 r = device_add_property_internal(device, "SUBSYSTEM", subsystem);
748 free(device->subsystem);
749 device->subsystem = subsystem;
752 device->subsystem_set = true;
757 _public_ int sd_device_get_subsystem(sd_device *device, const char **ret) {
758 assert_return(ret, -EINVAL);
759 assert_return(device, -EINVAL);
761 if (!device->subsystem_set) {
762 _cleanup_free_ char *subsystem = NULL;
767 /* read 'subsystem' link */
768 r = sd_device_get_syspath(device, &syspath);
772 path = strjoina(syspath, "/subsystem");
773 r = readlink_value(path, &subsystem);
775 r = device_set_subsystem(device, subsystem);
776 /* use implicit names */
777 else if (path_startswith(device->devpath, "/module/"))
778 r = device_set_subsystem(device, "module");
779 else if (strstr(device->devpath, "/drivers/"))
780 r = device_set_subsystem(device, "drivers");
781 else if (path_startswith(device->devpath, "/subsystem/") ||
782 path_startswith(device->devpath, "/class/") ||
783 path_startswith(device->devpath, "/bus/"))
784 r = device_set_subsystem(device, "subsystem");
786 return log_debug_errno(r, "sd-device: could not set subsystem for %s: %m", device->devpath);
788 device->subsystem_set = true;
791 *ret = device->subsystem;
796 _public_ int sd_device_get_devtype(sd_device *device, const char **devtype) {
802 r = device_read_uevent_file(device);
806 *devtype = device->devtype;
811 _public_ int sd_device_get_parent_with_subsystem_devtype(sd_device *child, const char *subsystem, const char *devtype, sd_device **ret) {
812 sd_device *parent = NULL;
815 assert_return(child, -EINVAL);
816 assert_return(subsystem, -EINVAL);
818 r = sd_device_get_parent(child, &parent);
820 const char *parent_subsystem = NULL;
821 const char *parent_devtype = NULL;
823 (void)sd_device_get_subsystem(parent, &parent_subsystem);
824 if (streq_ptr(parent_subsystem, subsystem)) {
828 (void)sd_device_get_devtype(parent, &parent_devtype);
829 if (streq_ptr(parent_devtype, devtype))
832 r = sd_device_get_parent(parent, &parent);
843 _public_ int sd_device_get_devnum(sd_device *device, dev_t *devnum) {
846 assert_return(device, -EINVAL);
847 assert_return(devnum, -EINVAL);
849 r = device_read_uevent_file(device);
853 *devnum = device->devnum;
858 int device_set_driver(sd_device *device, const char *_driver) {
859 _cleanup_free_ char *driver = NULL;
865 driver = strdup(_driver);
869 r = device_add_property_internal(device, "DRIVER", driver);
873 free(device->driver);
874 device->driver = driver;
877 device->driver_set = true;
882 _public_ int sd_device_get_driver(sd_device *device, const char **ret) {
883 assert_return(device, -EINVAL);
884 assert_return(ret, -EINVAL);
886 if (!device->driver_set) {
887 _cleanup_free_ char *driver = NULL;
892 r = sd_device_get_syspath(device, &syspath);
896 path = strjoina(syspath, "/driver");
897 r = readlink_value(path, &driver);
899 r = device_set_driver(device, driver);
905 *ret = device->driver;
910 _public_ int sd_device_get_devpath(sd_device *device, const char **devpath) {
911 assert_return(device, -EINVAL);
912 assert_return(devpath, -EINVAL);
914 assert(device->devpath);
915 assert(device->devpath[0] == '/');
917 *devpath = device->devpath;
922 _public_ int sd_device_get_devname(sd_device *device, const char **devname) {
925 assert_return(device, -EINVAL);
926 assert_return(devname, -EINVAL);
928 r = device_read_uevent_file(device);
932 if (!device->devname)
935 assert(path_startswith(device->devname, "/dev/"));
937 *devname = device->devname;
942 static int device_set_sysname(sd_device *device) {
943 _cleanup_free_ char *sysname = NULL;
944 const char *sysnum = NULL;
948 pos = strrchr(device->devpath, '/');
953 /* devpath is not a root directory */
954 if (*pos == '\0' || pos <= device->devpath)
957 sysname = strdup(pos);
961 /* some devices have '!' in their name, change that to '/' */
962 while (sysname[len] != '\0') {
963 if (sysname[len] == '!')
969 /* trailing number */
970 while (len > 0 && isdigit(sysname[--len]))
971 sysnum = &sysname[len];
976 free(device->sysname);
977 device->sysname = sysname;
980 device->sysnum = sysnum;
982 device->sysname_set = true;
987 _public_ int sd_device_get_sysname(sd_device *device, const char **ret) {
990 assert_return(device, -EINVAL);
991 assert_return(ret, -EINVAL);
993 if (!device->sysname_set) {
994 r = device_set_sysname(device);
999 *ret = device->sysname;
1004 _public_ int sd_device_get_sysnum(sd_device *device, const char **ret) {
1007 assert_return(device, -EINVAL);
1008 assert_return(ret, -EINVAL);
1010 if (!device->sysname_set) {
1011 r = device_set_sysname(device);
1016 *ret = device->sysnum;
1021 static bool is_valid_tag(const char *tag) {
1024 return !strchr(tag, ':') && !strchr(tag, ' ');
1027 int device_add_tag(sd_device *device, const char *tag) {
1033 if (!is_valid_tag(tag))
1036 r = set_ensure_allocated(&device->tags, &string_hash_ops);
1040 r = set_put_strdup(device->tags, tag);
1044 device->tags_generation ++;
1045 device->property_tags_outdated = true;
1050 int device_add_devlink(sd_device *device, const char *devlink) {
1056 r = set_ensure_allocated(&device->devlinks, &string_hash_ops);
1060 r = set_put_strdup(device->devlinks, devlink);
1064 device->devlinks_generation ++;
1065 device->property_devlinks_outdated = true;
1070 static int device_add_property_internal_from_string(sd_device *device, const char *str) {
1071 _cleanup_free_ char *key = NULL;
1081 value = strchr(key, '=');
1087 if (isempty(++value))
1090 return device_add_property_internal(device, key, value);
1093 int device_set_usec_initialized(sd_device *device, const char *initialized) {
1094 uint64_t usec_initialized;
1098 assert(initialized);
1100 r = safe_atou64(initialized, &usec_initialized);
1104 r = device_add_property_internal(device, "USEC_INITIALIZED", initialized);
1108 device->usec_initialized = usec_initialized;
1113 static int handle_db_line(sd_device *device, char key, const char *value) {
1122 r = device_add_tag(device, value);
1128 path = strjoina("/dev/", value);
1129 r = device_add_devlink(device, path);
1135 r = device_add_property_internal_from_string(device, value);
1141 r = device_set_usec_initialized(device, value);
1147 r = safe_atoi(value, &device->devlink_priority);
1153 r = safe_atoi(value, &device->watch_handle);
1159 log_debug("device db: unknown key '%c'", key);
1165 int device_get_id_filename(sd_device *device, const char **ret) {
1169 if (!device->id_filename) {
1170 _cleanup_free_ char *id = NULL;
1171 const char *subsystem;
1175 r = sd_device_get_subsystem(device, &subsystem);
1179 r = sd_device_get_devnum(device, &devnum);
1183 r = sd_device_get_ifindex(device, &ifindex);
1187 if (major(devnum) > 0) {
1188 /* use dev_t -- b259:131072, c254:0 */
1189 r = asprintf(&id, "%c%u:%u",
1190 streq(subsystem, "block") ? 'b' : 'c',
1191 major(devnum), minor(devnum));
1194 } else if (ifindex > 0) {
1195 /* use netdev ifindex -- n3 */
1196 r = asprintf(&id, "n%u", ifindex);
1200 /* use $subsys:$sysname -- pci:0000:00:1f.2
1201 * sysname() has '!' translated, get it from devpath
1203 const char *sysname;
1205 sysname = basename(device->devpath);
1209 r = asprintf(&id, "+%s:%s", subsystem, sysname);
1214 device->id_filename = id;
1218 *ret = device->id_filename;
1223 int device_read_db_aux(sd_device *device, bool force) {
1224 _cleanup_free_ char *db = NULL;
1226 const char *id, *value;
1240 if (device->db_loaded || (!force && device->sealed))
1243 r = device_get_id_filename(device, &id);
1247 path = strjoina("/run/udev/data/", id);
1249 r = read_full_file(path, &db, &db_len);
1254 log_debug("sd-device: failed to read db '%s': %s", path, strerror(-r));
1259 /* devices with a database entry are initialized */
1260 device->is_initialized = true;;
1262 for (i = 0; i < db_len; i++) {
1265 if (!strchr(NEWLINE, db[i])) {
1274 log_debug("sd-device: ignoring invalid db entry with key '%c'", key);
1276 state = INVALID_LINE;
1291 if (strchr(NEWLINE, db[i]))
1296 if (strchr(NEWLINE, db[i])) {
1298 r = handle_db_line(device, key, value);
1300 log_debug("sd-device: failed to handle db entry '%c:%s': %s", key, value, strerror(-r));
1307 assert_not_reached("invalid state when parsing db");
1311 device->db_loaded = true;
1316 static int device_read_db(sd_device *device) {
1317 return device_read_db_aux(device, false);
1320 _public_ int sd_device_get_is_initialized(sd_device *device, int *initialized) {
1323 assert_return(device, -EINVAL);
1324 assert_return(initialized, -EINVAL);
1326 r = device_read_db(device);
1330 *initialized = device->is_initialized;
1335 _public_ int sd_device_get_usec_since_initialized(sd_device *device, uint64_t *usec) {
1339 assert_return(device, -EINVAL);
1340 assert_return(usec, -EINVAL);
1342 r = device_read_db(device);
1346 if (!device->is_initialized)
1349 if (!device->usec_initialized)
1352 now_ts = now(clock_boottime_or_monotonic());
1354 if (now_ts < device->usec_initialized)
1357 *usec = now_ts - device->usec_initialized;
1362 _public_ const char *sd_device_get_tag_first(sd_device *device) {
1363 assert_return(device, NULL);
1365 (void) device_read_db(device);
1367 device->tags_iterator_generation = device->tags_generation;
1368 device->tags_iterator = ITERATOR_FIRST;
1370 return set_iterate(device->tags, &device->tags_iterator);
1373 _public_ const char *sd_device_get_tag_next(sd_device *device) {
1374 assert_return(device, NULL);
1376 (void) device_read_db(device);
1378 if (device->tags_iterator_generation != device->tags_generation)
1381 return set_iterate(device->tags, &device->tags_iterator);
1384 _public_ const char *sd_device_get_devlink_first(sd_device *device) {
1385 assert_return(device, NULL);
1387 (void) device_read_db(device);
1389 device->devlinks_iterator_generation = device->devlinks_generation;
1390 device->devlinks_iterator = ITERATOR_FIRST;
1392 return set_iterate(device->devlinks, &device->devlinks_iterator);
1395 _public_ const char *sd_device_get_devlink_next(sd_device *device) {
1396 assert_return(device, NULL);
1398 (void) device_read_db(device);
1400 if (device->devlinks_iterator_generation != device->devlinks_generation)
1403 return set_iterate(device->devlinks, &device->devlinks_iterator);
1406 static int device_properties_prepare(sd_device *device) {
1411 r = device_read_uevent_file(device);
1415 r = device_read_db(device);
1419 if (device->property_devlinks_outdated) {
1420 char *devlinks = NULL;
1421 const char *devlink;
1423 devlink = sd_device_get_devlink_first(device);
1425 devlinks = strdupa(devlink);
1427 while ((devlink = sd_device_get_devlink_next(device)))
1428 devlinks = strjoina(devlinks, " ", devlink);
1430 r = device_add_property_internal(device, "DEVLINKS", devlinks);
1434 device->property_devlinks_outdated = false;
1437 if (device->property_tags_outdated) {
1441 tag = sd_device_get_tag_first(device);
1443 tags = strjoina(":", tag);
1445 while ((tag = sd_device_get_tag_next(device)))
1446 tags = strjoina(tags, ":", tag);
1448 tags = strjoina(tags, ":");
1450 r = device_add_property_internal(device, "TAGS", tags);
1454 device->property_tags_outdated = false;
1460 _public_ const char *sd_device_get_property_first(sd_device *device, const char **_value) {
1465 assert_return(device, NULL);
1467 r = device_properties_prepare(device);
1471 device->properties_iterator_generation = device->properties_generation;
1472 device->properties_iterator = ITERATOR_FIRST;
1474 value = ordered_hashmap_iterate(device->properties, &device->properties_iterator, (const void**)&key);
1482 _public_ const char *sd_device_get_property_next(sd_device *device, const char **_value) {
1487 assert_return(device, NULL);
1489 r = device_properties_prepare(device);
1493 if (device->properties_iterator_generation != device->properties_generation)
1496 value = ordered_hashmap_iterate(device->properties, &device->properties_iterator, (const void**)&key);
1504 static int device_sysattrs_read_all(sd_device *device) {
1505 _cleanup_closedir_ DIR *dir = NULL;
1506 const char *syspath;
1507 struct dirent *dent;
1512 if (device->sysattrs_read)
1515 r = sd_device_get_syspath(device, &syspath);
1519 dir = opendir(syspath);
1523 r = set_ensure_allocated(&device->sysattrs, &string_hash_ops);
1527 for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
1529 struct stat statbuf;
1531 /* only handle symlinks and regular files */
1532 if (dent->d_type != DT_LNK && dent->d_type != DT_REG)
1535 path = strjoina(syspath, "/", dent->d_name);
1537 if (lstat(path, &statbuf) != 0)
1540 if (!(statbuf.st_mode & S_IRUSR))
1543 r = set_put_strdup(device->sysattrs, dent->d_name);
1548 device->sysattrs_read = true;
1553 _public_ const char *sd_device_get_sysattr_first(sd_device *device) {
1556 assert_return(device, NULL);
1558 if (!device->sysattrs_read) {
1559 r = device_sysattrs_read_all(device);
1566 device->sysattrs_iterator = ITERATOR_FIRST;
1568 return set_iterate(device->sysattrs, &device->sysattrs_iterator);
1571 _public_ const char *sd_device_get_sysattr_next(sd_device *device) {
1572 assert_return(device, NULL);
1574 if (!device->sysattrs_read)
1577 return set_iterate(device->sysattrs, &device->sysattrs_iterator);
1580 _public_ int sd_device_has_tag(sd_device *device, const char *tag) {
1581 assert_return(device, -EINVAL);
1582 assert_return(tag, -EINVAL);
1584 (void) device_read_db(device);
1586 return !!set_contains(device->tags, tag);
1589 _public_ int sd_device_get_property_value(sd_device *device, const char *key, const char **_value) {
1593 assert_return(device, -EINVAL);
1594 assert_return(key, -EINVAL);
1595 assert_return(_value, -EINVAL);
1597 r = device_properties_prepare(device);
1601 value = ordered_hashmap_get(device->properties, key);
1610 /* replaces the value if it already exists */
1611 static int device_add_sysattr_value(sd_device *device, const char *_key, char *value) {
1612 _cleanup_free_ char *key = NULL;
1613 _cleanup_free_ char *value_old = NULL;
1619 r = hashmap_ensure_allocated(&device->sysattr_values, &string_hash_ops);
1623 value_old = hashmap_remove2(device->sysattr_values, _key, (void **)&key);
1630 r = hashmap_put(device->sysattr_values, key, value);
1639 static int device_get_sysattr_value(sd_device *device, const char *_key, const char **_value) {
1640 const char *key = NULL, *value;
1645 value = hashmap_get2(device->sysattr_values, _key, (void **) &key);
1655 /* We cache all sysattr lookups. If an attribute does not exist, it is stored
1656 * with a NULL value in the cache, otherwise the returned string is stored */
1657 _public_ int sd_device_get_sysattr_value(sd_device *device, const char *sysattr, const char **_value) {
1658 _cleanup_free_ char *value = NULL;
1659 const char *syspath, *cached_value = NULL;
1661 struct stat statbuf;
1664 assert_return(device, -EINVAL);
1665 assert_return(sysattr, -EINVAL);
1667 /* look for possibly already cached result */
1668 r = device_get_sysattr_value(device, sysattr, &cached_value);
1674 /* we looked up the sysattr before and it did not exist */
1678 *_value = cached_value;
1683 r = sd_device_get_syspath(device, &syspath);
1687 path = strjoina(syspath, "/", sysattr);
1688 r = lstat(path, &statbuf);
1690 /* remember that we could not access the sysattr */
1691 r = device_add_sysattr_value(device, sysattr, NULL);
1696 } else if (S_ISLNK(statbuf.st_mode)) {
1697 /* Some core links return only the last element of the target path,
1698 * these are just values, the paths should not be exposed. */
1699 if (STR_IN_SET(sysattr, "driver", "subsystem", "module")) {
1700 r = readlink_value(path, &value);
1705 } else if (S_ISDIR(statbuf.st_mode)) {
1706 /* skip directories */
1708 } else if (!(statbuf.st_mode & S_IRUSR)) {
1709 /* skip non-readable files */
1714 /* read attribute value */
1715 r = read_full_file(path, &value, &size);
1719 /* drop trailing newlines */
1720 while (size > 0 && value[--size] == '\n')
1724 r = device_add_sysattr_value(device, sysattr, value);
1734 static void device_remove_sysattr_value(sd_device *device, const char *_key) {
1735 _cleanup_free_ char *key = NULL;
1736 _cleanup_free_ char *value = NULL;
1741 value = hashmap_remove2(device->sysattr_values, _key, (void **) &key);
1746 /* set the attribute and save it in the cache. If a NULL value is passed the
1747 * attribute is cleared from the cache */
1748 _public_ int sd_device_set_sysattr_value(sd_device *device, const char *sysattr, char *_value) {
1749 _cleanup_close_ int fd = -1;
1750 _cleanup_free_ char *value = NULL;
1751 const char *syspath;
1753 struct stat statbuf;
1754 size_t value_len = 0;
1758 assert_return(device, -EINVAL);
1759 assert_return(sysattr, -EINVAL);
1762 device_remove_sysattr_value(device, sysattr);
1767 r = sd_device_get_syspath(device, &syspath);
1771 path = strjoina(syspath, "/", sysattr);
1772 r = lstat(path, &statbuf);
1778 r = device_add_sysattr_value(device, sysattr, value);
1785 if (S_ISLNK(statbuf.st_mode))
1788 /* skip directories */
1789 if (S_ISDIR(statbuf.st_mode))
1792 /* skip non-readable files */
1793 if ((statbuf.st_mode & S_IRUSR) == 0)
1796 value_len = strlen(_value);
1798 /* drop trailing newlines */
1799 while (value_len > 0 && _value[value_len - 1] == '\n')
1800 _value[--value_len] = '\0';
1802 /* value length is limited to 4k */
1803 if (value_len > 4096)
1806 fd = open(path, O_WRONLY | O_CLOEXEC);
1810 value = strdup(_value);
1814 size = write(fd, value, value_len);
1818 if ((size_t)size != value_len)
1821 r = device_add_sysattr_value(device, sysattr, value);