2 This file is part of systemd.
4 Copyright 2008-2012 Kay Sievers <kay@vrfy.org>
5 Copyright 2014 Tom Gundersen <teg@jklm.no>
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
22 #include <sys/types.h>
27 #include "path-util.h"
34 #include "sd-device.h"
36 #include "device-util.h"
37 #include "device-private.h"
38 #include "device-internal.h"
40 int device_new_aux(sd_device **ret) {
41 _cleanup_device_unref_ sd_device *device = NULL;
45 device = new0(sd_device, 1);
50 device->watch_handle = -1;
58 _public_ sd_device *sd_device_ref(sd_device *device) {
60 assert_se(++ device->n_ref >= 2);
65 _public_ sd_device *sd_device_unref(sd_device *device) {
66 if (device && -- device->n_ref == 0) {
67 sd_device_unref(device->parent);
68 free(device->syspath);
69 free(device->sysname);
70 free(device->devtype);
71 free(device->devname);
72 free(device->subsystem);
74 free(device->id_filename);
75 free(device->properties_strv);
76 free(device->properties_nulstr);
78 ordered_hashmap_free_free_free(device->properties);
79 ordered_hashmap_free_free_free(device->properties_db);
80 hashmap_free_free_free(device->sysattr_values);
81 set_free_free(device->sysattrs);
82 set_free_free(device->tags);
83 set_free_free(device->devlinks);
91 int device_add_property_aux(sd_device *device, const char *_key, const char *_value, bool db) {
92 OrderedHashmap **properties;
98 properties = &device->properties_db;
100 properties = &device->properties;
103 _cleanup_free_ char *key = NULL, *value = NULL, *old_key = NULL, *old_value = NULL;
106 r = ordered_hashmap_ensure_allocated(properties, &string_hash_ops);
114 value = strdup(_value);
118 old_value = ordered_hashmap_get2(*properties, key, (void**) &old_key);
120 r = ordered_hashmap_replace(*properties, key, value);
127 _cleanup_free_ char *key = NULL;
128 _cleanup_free_ char *value = NULL;
130 value = ordered_hashmap_remove2(*properties, _key, (void**) &key);
134 device->properties_generation ++;
135 device->properties_buf_outdated = true;
141 int device_add_property_internal(sd_device *device, const char *key, const char *value) {
142 return device_add_property_aux(device, key, value, false);
145 int device_set_syspath(sd_device *device, const char *_syspath, bool verify) {
146 _cleanup_free_ char *syspath = NULL;
153 /* must be a subdirectory of /sys */
154 if (!path_startswith(_syspath, "/sys/")) {
155 log_debug("sd-device: syspath '%s' is not a subdirectory of /sys", _syspath);
160 r = readlink_and_canonicalize(_syspath, &syspath);
162 /* the device does not exist (any more?) */
164 else if (r == -EINVAL) {
166 syspath = canonicalize_file_name(_syspath);
169 /* the device does not exist (any more?) */
172 log_debug("sd-device: could not canonicalize '%s': %m", _syspath);
176 log_debug("sd-device: could not get target of '%s': %s", _syspath, strerror(-r));
180 if (path_startswith(syspath, "/sys/devices/")) {
183 /* all 'devices' require an 'uevent' file */
184 path = strjoina(syspath, "/uevent");
185 r = access(path, F_OK);
188 /* this is not a valid device */
191 log_debug("sd-device: %s does not have an uevent file: %m", syspath);
195 /* everything else just just needs to be a directory */
196 if (!is_dir(syspath, false))
200 syspath = strdup(_syspath);
205 devpath = syspath + strlen("/sys");
207 r = device_add_property_internal(device, "DEVPATH", devpath);
211 free(device->syspath);
212 device->syspath = syspath;
215 device->devpath = devpath;
220 _public_ int sd_device_new_from_syspath(sd_device **ret, const char *syspath) {
221 _cleanup_device_unref_ sd_device *device = NULL;
224 assert_return(ret, -EINVAL);
225 assert_return(syspath, -EINVAL);
227 r = device_new_aux(&device);
231 r = device_set_syspath(device, syspath, true);
241 _public_ int sd_device_new_from_devnum(sd_device **ret, char type, dev_t devnum) {
243 char id[DECIMAL_STR_MAX(unsigned) * 2 + 1];
245 assert_return(ret, -EINVAL);
246 assert_return(type == 'b' || type == 'c', -EINVAL);
248 /* use /sys/dev/{block,char}/<maj>:<min> link */
249 snprintf(id, sizeof(id), "%u:%u", major(devnum), minor(devnum));
251 syspath = strjoina("/sys/dev/", (type == 'b' ? "block" : "char"), "/", id);
253 return sd_device_new_from_syspath(ret, syspath);
256 _public_ int sd_device_new_from_subsystem_sysname(sd_device **ret, const char *subsystem, const char *sysname) {
259 assert_return(ret, -EINVAL);
260 assert_return(subsystem, -EINVAL);
261 assert_return(sysname, -EINVAL);
263 if (streq(subsystem, "subsystem")) {
264 syspath = strjoina("/sys/subsystem/", sysname);
265 if (access(syspath, F_OK) >= 0)
266 return sd_device_new_from_syspath(ret, syspath);
268 syspath = strjoina("/sys/bus/", sysname);
269 if (access(syspath, F_OK) >= 0)
270 return sd_device_new_from_syspath(ret, syspath);
272 syspath = strjoina("/sys/class/", sysname);
273 if (access(syspath, F_OK) >= 0)
274 return sd_device_new_from_syspath(ret, syspath);
275 } else if (streq(subsystem, "module")) {
276 syspath = strjoina("/sys/module/", sysname);
277 if (access(syspath, F_OK) >= 0)
278 return sd_device_new_from_syspath(ret, syspath);
279 } else if (streq(subsystem, "drivers")) {
280 char subsys[PATH_MAX];
283 strscpy(subsys, sizeof(subsys), sysname);
284 driver = strchr(subsys, ':');
289 syspath = strjoina("/sys/subsystem/", subsys, "/drivers/", driver);
290 if (access(syspath, F_OK) >= 0)
291 return sd_device_new_from_syspath(ret, syspath);
293 syspath = strjoina("/sys/bus/", subsys, "/drivers/", driver);
294 if (access(syspath, F_OK) >= 0)
295 return sd_device_new_from_syspath(ret, syspath);
299 syspath = strjoina("/sys/subsystem/", subsystem, "/devices/", sysname);
300 if (access(syspath, F_OK) >= 0)
301 return sd_device_new_from_syspath(ret, syspath);
303 syspath = strjoina("/sys/bus/", subsystem, "/devices/", sysname);
304 if (access(syspath, F_OK) >= 0)
305 return sd_device_new_from_syspath(ret, syspath);
307 syspath = strjoina("/sys/class/", subsystem, "/", sysname);
308 if (access(syspath, F_OK) >= 0)
309 return sd_device_new_from_syspath(ret, syspath);
315 int device_set_devtype(sd_device *device, const char *_devtype) {
316 _cleanup_free_ char *devtype = NULL;
322 devtype = strdup(_devtype);
326 r = device_add_property_internal(device, "DEVTYPE", devtype);
330 free(device->devtype);
331 device->devtype = devtype;
337 int device_set_ifindex(sd_device *device, const char *_ifindex) {
343 r = safe_atoi(_ifindex, &ifindex);
350 r = device_add_property_internal(device, "IFINDEX", _ifindex);
354 device->ifindex = ifindex;
359 int device_set_devname(sd_device *device, const char *_devname) {
360 _cleanup_free_ char *devname = NULL;
366 if (_devname[0] != '/') {
367 r = asprintf(&devname, "/dev/%s", _devname);
371 devname = strdup(_devname);
376 r = device_add_property_internal(device, "DEVNAME", devname);
380 free(device->devname);
381 device->devname = devname;
387 int device_set_devmode(sd_device *device, const char *_devmode) {
394 r = safe_atou(_devmode, &devmode);
401 r = device_add_property_internal(device, "DEVMODE", _devmode);
405 device->devmode = devmode;
410 int device_set_devnum(sd_device *device, const char *major, const char *minor) {
411 unsigned maj = 0, min = 0;
417 r = safe_atou(major, &maj);
424 r = safe_atou(minor, &min);
429 r = device_add_property_internal(device, "MAJOR", major);
434 r = device_add_property_internal(device, "MINOR", minor);
439 device->devnum = makedev(maj, min);
444 static int handle_uevent_line(sd_device *device, const char *key, const char *value, const char **major, const char **minor) {
453 if (streq(key, "DEVTYPE")) {
454 r = device_set_devtype(device, value);
457 } else if (streq(key, "IFINDEX")) {
458 r = device_set_ifindex(device, value);
461 } else if (streq(key, "DEVNAME")) {
462 r = device_set_devname(device, value);
465 } else if (streq(key, "DEVMODE")) {
466 r = device_set_devmode(device, value);
469 } else if (streq(key, "MAJOR"))
471 else if (streq(key, "MINOR"))
474 r = device_add_property_internal(device, key, value);
482 int device_read_uevent_file(sd_device *device) {
483 _cleanup_free_ char *uevent = NULL;
484 const char *syspath, *key, *value, *major = NULL, *minor = NULL;
500 if (device->uevent_loaded || device->sealed)
503 device->uevent_loaded = true;
505 r = sd_device_get_syspath(device, &syspath);
509 path = strjoina(syspath, "/uevent");
511 r = read_full_file(path, &uevent, &uevent_len);
513 /* empty uevent files may be write-only */
515 else if (r == -ENOENT)
516 /* some devices may not have uevent files, see set_syspath() */
519 log_debug("sd-device: failed to read uevent file '%s': %s", path, strerror(-r));
523 for (i = 0; i < uevent_len; i++) {
526 if (!strchr(NEWLINE, uevent[i])) {
534 if (uevent[i] == '=') {
538 } else if (strchr(NEWLINE, uevent[i])) {
540 log_debug("sd-device: ignoring invalid uevent line '%s'", key);
553 if (strchr(NEWLINE, uevent[i])) {
556 r = handle_uevent_line(device, key, value, &major, &minor);
558 log_debug("sd-device: failed to handle uevent entry '%s=%s': %s", key, value, strerror(-r));
565 assert_not_reached("invalid state when parsing uevent file");
570 r = device_set_devnum(device, major, minor);
572 log_debug("sd-device: could not set 'MAJOR=%s' or 'MINOR=%s' from '%s': %s", major, minor, path, strerror(-r));
578 _public_ int sd_device_get_ifindex(sd_device *device, int *ifindex) {
581 assert_return(device, -EINVAL);
582 assert_return(ifindex, -EINVAL);
584 r = device_read_uevent_file(device);
588 *ifindex = device->ifindex;
593 _public_ int sd_device_new_from_device_id(sd_device **ret, const char *id) {
596 assert_return(ret, -EINVAL);
597 assert_return(id, -EINVAL);
606 r = sscanf(id, "%c%i:%i", &type, &maj, &min);
610 return sd_device_new_from_devnum(ret, type, makedev(maj, min));
614 _cleanup_device_unref_ sd_device *device = NULL;
615 _cleanup_close_ int sk = -1;
616 struct ifreq ifr = {};
619 r = safe_atoi(&id[1], &ifr.ifr_ifindex);
622 else if (ifr.ifr_ifindex <= 0)
625 sk = socket(PF_INET, SOCK_DGRAM, 0);
629 r = ioctl(sk, SIOCGIFNAME, &ifr);
633 r = sd_device_new_from_subsystem_sysname(&device, "net", ifr.ifr_name);
637 r = sd_device_get_ifindex(device, &ifindex);
641 /* this is racey, so we might end up with the wrong device */
642 if (ifr.ifr_ifindex != ifindex)
652 char subsys[PATH_MAX];
655 (void)strscpy(subsys, sizeof(subsys), id + 1);
656 sysname = strchr(subsys, ':');
663 return sd_device_new_from_subsystem_sysname(ret, subsys, sysname);
670 _public_ int sd_device_get_syspath(sd_device *device, const char **ret) {
671 assert_return(device, -EINVAL);
672 assert_return(ret, -EINVAL);
674 assert(path_startswith(device->syspath, "/sys/"));
676 *ret = device->syspath;
681 static int device_new_from_child(sd_device **ret, sd_device *child) {
682 _cleanup_free_ char *path = NULL;
683 const char *subdir, *syspath;
689 r = sd_device_get_syspath(child, &syspath);
693 path = strdup(syspath);
696 subdir = path + strlen("/sys");
701 pos = strrchr(subdir, '/');
702 if (!pos || pos < subdir + 2)
707 r = sd_device_new_from_syspath(ret, path);
717 _public_ int sd_device_get_parent(sd_device *child, sd_device **ret) {
719 assert_return(ret, -EINVAL);
720 assert_return(child, -EINVAL);
722 if (!child->parent_set) {
723 child->parent_set = true;
725 (void)device_new_from_child(&child->parent, child);
731 *ret = child->parent;
736 int device_set_subsystem(sd_device *device, const char *_subsystem) {
737 _cleanup_free_ char *subsystem = NULL;
743 subsystem = strdup(_subsystem);
747 r = device_add_property_internal(device, "SUBSYSTEM", subsystem);
751 free(device->subsystem);
752 device->subsystem = subsystem;
755 device->subsystem_set = true;
760 _public_ int sd_device_get_subsystem(sd_device *device, const char **ret) {
761 assert_return(ret, -EINVAL);
762 assert_return(device, -EINVAL);
764 if (!device->subsystem_set) {
765 _cleanup_free_ char *subsystem = NULL;
770 /* read 'subsystem' link */
771 r = sd_device_get_syspath(device, &syspath);
775 path = strjoina(syspath, "/subsystem");
776 r = readlink_value(path, &subsystem);
778 r = device_set_subsystem(device, subsystem);
779 /* use implicit names */
780 else if (path_startswith(device->devpath, "/module/"))
781 r = device_set_subsystem(device, "module");
782 else if (strstr(device->devpath, "/drivers/"))
783 r = device_set_subsystem(device, "drivers");
784 else if (path_startswith(device->devpath, "/subsystem/") ||
785 path_startswith(device->devpath, "/class/") ||
786 path_startswith(device->devpath, "/bus/"))
787 r = device_set_subsystem(device, "subsystem");
789 return log_debug_errno(r, "sd-device: could not set subsystem for %s: %m", device->devpath);
791 device->subsystem_set = true;
794 *ret = device->subsystem;
799 _public_ int sd_device_get_devtype(sd_device *device, const char **devtype) {
805 r = device_read_uevent_file(device);
809 *devtype = device->devtype;
814 _public_ int sd_device_get_parent_with_subsystem_devtype(sd_device *child, const char *subsystem, const char *devtype, sd_device **ret) {
815 sd_device *parent = NULL;
818 assert_return(child, -EINVAL);
819 assert_return(subsystem, -EINVAL);
821 r = sd_device_get_parent(child, &parent);
823 const char *parent_subsystem = NULL;
824 const char *parent_devtype = NULL;
826 (void)sd_device_get_subsystem(parent, &parent_subsystem);
827 if (streq_ptr(parent_subsystem, subsystem)) {
831 (void)sd_device_get_devtype(parent, &parent_devtype);
832 if (streq_ptr(parent_devtype, devtype))
835 r = sd_device_get_parent(parent, &parent);
846 _public_ int sd_device_get_devnum(sd_device *device, dev_t *devnum) {
849 assert_return(device, -EINVAL);
850 assert_return(devnum, -EINVAL);
852 r = device_read_uevent_file(device);
856 *devnum = device->devnum;
861 int device_set_driver(sd_device *device, const char *_driver) {
862 _cleanup_free_ char *driver = NULL;
868 driver = strdup(_driver);
872 r = device_add_property_internal(device, "DRIVER", driver);
876 free(device->driver);
877 device->driver = driver;
880 device->driver_set = true;
885 _public_ int sd_device_get_driver(sd_device *device, const char **ret) {
886 assert_return(device, -EINVAL);
887 assert_return(ret, -EINVAL);
889 if (!device->driver_set) {
890 _cleanup_free_ char *driver = NULL;
895 r = sd_device_get_syspath(device, &syspath);
899 path = strjoina(syspath, "/driver");
900 r = readlink_value(path, &driver);
902 r = device_set_driver(device, driver);
908 *ret = device->driver;
913 _public_ int sd_device_get_devpath(sd_device *device, const char **devpath) {
914 assert_return(device, -EINVAL);
915 assert_return(devpath, -EINVAL);
917 assert(device->devpath);
918 assert(device->devpath[0] == '/');
920 *devpath = device->devpath;
925 _public_ int sd_device_get_devname(sd_device *device, const char **devname) {
928 assert_return(device, -EINVAL);
929 assert_return(devname, -EINVAL);
931 r = device_read_uevent_file(device);
935 if (!device->devname)
938 assert(path_startswith(device->devname, "/dev/"));
940 *devname = device->devname;
945 static int device_set_sysname(sd_device *device) {
946 _cleanup_free_ char *sysname = NULL;
947 const char *sysnum = NULL;
951 pos = strrchr(device->devpath, '/');
956 /* devpath is not a root directory */
957 if (*pos == '\0' || pos <= device->devpath)
960 sysname = strdup(pos);
964 /* some devices have '!' in their name, change that to '/' */
965 while (sysname[len] != '\0') {
966 if (sysname[len] == '!')
972 /* trailing number */
973 while (len > 0 && isdigit(sysname[--len]))
974 sysnum = &sysname[len];
979 free(device->sysname);
980 device->sysname = sysname;
983 device->sysnum = sysnum;
985 device->sysname_set = true;
990 _public_ int sd_device_get_sysname(sd_device *device, const char **ret) {
993 assert_return(device, -EINVAL);
994 assert_return(ret, -EINVAL);
996 if (!device->sysname_set) {
997 r = device_set_sysname(device);
1002 *ret = device->sysname;
1007 _public_ int sd_device_get_sysnum(sd_device *device, const char **ret) {
1010 assert_return(device, -EINVAL);
1011 assert_return(ret, -EINVAL);
1013 if (!device->sysname_set) {
1014 r = device_set_sysname(device);
1019 *ret = device->sysnum;
1024 static bool is_valid_tag(const char *tag) {
1027 return !strchr(tag, ':') && !strchr(tag, ' ');
1030 int device_add_tag(sd_device *device, const char *tag) {
1036 if (!is_valid_tag(tag))
1039 r = set_ensure_allocated(&device->tags, &string_hash_ops);
1043 r = set_put_strdup(device->tags, tag);
1047 device->tags_generation ++;
1048 device->property_tags_outdated = true;
1053 int device_add_devlink(sd_device *device, const char *devlink) {
1059 r = set_ensure_allocated(&device->devlinks, &string_hash_ops);
1063 r = set_put_strdup(device->devlinks, devlink);
1067 device->devlinks_generation ++;
1068 device->property_devlinks_outdated = true;
1073 static int device_add_property_internal_from_string(sd_device *device, const char *str) {
1074 _cleanup_free_ char *key = NULL;
1084 value = strchr(key, '=');
1090 if (isempty(++value))
1093 return device_add_property_internal(device, key, value);
1096 int device_set_usec_initialized(sd_device *device, const char *initialized) {
1097 uint64_t usec_initialized;
1101 assert(initialized);
1103 r = safe_atou64(initialized, &usec_initialized);
1107 r = device_add_property_internal(device, "USEC_INITIALIZED", initialized);
1111 device->usec_initialized = usec_initialized;
1116 static int handle_db_line(sd_device *device, char key, const char *value) {
1125 r = device_add_tag(device, value);
1131 path = strjoina("/dev/", value);
1132 r = device_add_devlink(device, path);
1138 r = device_add_property_internal_from_string(device, value);
1144 r = device_set_usec_initialized(device, value);
1150 r = safe_atoi(value, &device->devlink_priority);
1156 r = safe_atoi(value, &device->watch_handle);
1162 log_debug("device db: unknown key '%c'", key);
1168 int device_get_id_filename(sd_device *device, const char **ret) {
1172 if (!device->id_filename) {
1173 _cleanup_free_ char *id = NULL;
1174 const char *subsystem;
1178 r = sd_device_get_subsystem(device, &subsystem);
1182 r = sd_device_get_devnum(device, &devnum);
1186 r = sd_device_get_ifindex(device, &ifindex);
1190 if (major(devnum) > 0) {
1191 /* use dev_t -- b259:131072, c254:0 */
1192 r = asprintf(&id, "%c%u:%u",
1193 streq(subsystem, "block") ? 'b' : 'c',
1194 major(devnum), minor(devnum));
1197 } else if (ifindex > 0) {
1198 /* use netdev ifindex -- n3 */
1199 r = asprintf(&id, "n%u", ifindex);
1203 /* use $subsys:$sysname -- pci:0000:00:1f.2
1204 * sysname() has '!' translated, get it from devpath
1206 const char *sysname;
1208 sysname = basename(device->devpath);
1212 r = asprintf(&id, "+%s:%s", subsystem, sysname);
1217 device->id_filename = id;
1221 *ret = device->id_filename;
1226 int device_read_db_aux(sd_device *device, bool force) {
1227 _cleanup_free_ char *db = NULL;
1229 const char *id, *value;
1243 if (device->db_loaded || (!force && device->sealed))
1246 device->db_loaded = true;
1248 r = device_get_id_filename(device, &id);
1252 path = strjoina("/run/udev/data/", id);
1254 r = read_full_file(path, &db, &db_len);
1259 log_debug("sd-device: failed to read db '%s': %s", path, strerror(-r));
1264 /* devices with a database entry are initialized */
1265 device->is_initialized = true;;
1267 for (i = 0; i < db_len; i++) {
1270 if (!strchr(NEWLINE, db[i])) {
1279 log_debug("sd-device: ignoring invalid db entry with key '%c'", key);
1281 state = INVALID_LINE;
1296 if (strchr(NEWLINE, db[i]))
1301 if (strchr(NEWLINE, db[i])) {
1303 r = handle_db_line(device, key, value);
1305 log_debug("sd-device: failed to handle db entry '%c:%s': %s", key, value, strerror(-r));
1312 assert_not_reached("invalid state when parsing db");
1319 static int device_read_db(sd_device *device) {
1320 return device_read_db_aux(device, false);
1323 _public_ int sd_device_get_is_initialized(sd_device *device, int *initialized) {
1326 assert_return(device, -EINVAL);
1327 assert_return(initialized, -EINVAL);
1329 r = device_read_db(device);
1333 *initialized = device->is_initialized;
1338 _public_ int sd_device_get_usec_since_initialized(sd_device *device, uint64_t *usec) {
1342 assert_return(device, -EINVAL);
1343 assert_return(usec, -EINVAL);
1345 r = device_read_db(device);
1349 if (!device->is_initialized)
1352 if (!device->usec_initialized)
1355 now_ts = now(clock_boottime_or_monotonic());
1357 if (now_ts < device->usec_initialized)
1360 *usec = now_ts - device->usec_initialized;
1365 _public_ const char *sd_device_get_tag_first(sd_device *device) {
1366 assert_return(device, NULL);
1368 (void) device_read_db(device);
1370 device->tags_iterator_generation = device->tags_generation;
1371 device->tags_iterator = ITERATOR_FIRST;
1373 return set_iterate(device->tags, &device->tags_iterator);
1376 _public_ const char *sd_device_get_tag_next(sd_device *device) {
1377 assert_return(device, NULL);
1379 (void) device_read_db(device);
1381 if (device->tags_iterator_generation != device->tags_generation)
1384 return set_iterate(device->tags, &device->tags_iterator);
1387 _public_ const char *sd_device_get_devlink_first(sd_device *device) {
1388 assert_return(device, NULL);
1390 (void) device_read_db(device);
1392 device->devlinks_iterator_generation = device->devlinks_generation;
1393 device->devlinks_iterator = ITERATOR_FIRST;
1395 return set_iterate(device->devlinks, &device->devlinks_iterator);
1398 _public_ const char *sd_device_get_devlink_next(sd_device *device) {
1399 assert_return(device, NULL);
1401 (void) device_read_db(device);
1403 if (device->devlinks_iterator_generation != device->devlinks_generation)
1406 return set_iterate(device->devlinks, &device->devlinks_iterator);
1409 static int device_properties_prepare(sd_device *device) {
1414 r = device_read_uevent_file(device);
1418 r = device_read_db(device);
1422 if (device->property_devlinks_outdated) {
1423 char *devlinks = NULL;
1424 const char *devlink;
1426 devlink = sd_device_get_devlink_first(device);
1428 devlinks = strdupa(devlink);
1430 while ((devlink = sd_device_get_devlink_next(device)))
1431 devlinks = strjoina(devlinks, " ", devlink);
1433 r = device_add_property_internal(device, "DEVLINKS", devlinks);
1437 device->property_devlinks_outdated = false;
1440 if (device->property_tags_outdated) {
1444 tag = sd_device_get_tag_first(device);
1446 tags = strjoina(":", tag);
1448 while ((tag = sd_device_get_tag_next(device)))
1449 tags = strjoina(tags, ":", tag);
1451 tags = strjoina(tags, ":");
1453 r = device_add_property_internal(device, "TAGS", tags);
1457 device->property_tags_outdated = false;
1463 _public_ const char *sd_device_get_property_first(sd_device *device, const char **_value) {
1468 assert_return(device, NULL);
1470 r = device_properties_prepare(device);
1474 device->properties_iterator_generation = device->properties_generation;
1475 device->properties_iterator = ITERATOR_FIRST;
1477 value = ordered_hashmap_iterate(device->properties, &device->properties_iterator, (const void**)&key);
1485 _public_ const char *sd_device_get_property_next(sd_device *device, const char **_value) {
1490 assert_return(device, NULL);
1492 r = device_properties_prepare(device);
1496 if (device->properties_iterator_generation != device->properties_generation)
1499 value = ordered_hashmap_iterate(device->properties, &device->properties_iterator, (const void**)&key);
1507 static int device_sysattrs_read_all(sd_device *device) {
1508 _cleanup_closedir_ DIR *dir = NULL;
1509 const char *syspath;
1510 struct dirent *dent;
1515 if (device->sysattrs_read)
1518 r = sd_device_get_syspath(device, &syspath);
1522 dir = opendir(syspath);
1526 r = set_ensure_allocated(&device->sysattrs, &string_hash_ops);
1530 for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
1532 struct stat statbuf;
1534 /* only handle symlinks and regular files */
1535 if (dent->d_type != DT_LNK && dent->d_type != DT_REG)
1538 path = strjoina(syspath, "/", dent->d_name);
1540 if (lstat(path, &statbuf) != 0)
1543 if (!(statbuf.st_mode & S_IRUSR))
1546 r = set_put_strdup(device->sysattrs, dent->d_name);
1551 device->sysattrs_read = true;
1556 _public_ const char *sd_device_get_sysattr_first(sd_device *device) {
1559 assert_return(device, NULL);
1561 if (!device->sysattrs_read) {
1562 r = device_sysattrs_read_all(device);
1569 device->sysattrs_iterator = ITERATOR_FIRST;
1571 return set_iterate(device->sysattrs, &device->sysattrs_iterator);
1574 _public_ const char *sd_device_get_sysattr_next(sd_device *device) {
1575 assert_return(device, NULL);
1577 if (!device->sysattrs_read)
1580 return set_iterate(device->sysattrs, &device->sysattrs_iterator);
1583 _public_ int sd_device_has_tag(sd_device *device, const char *tag) {
1584 assert_return(device, -EINVAL);
1585 assert_return(tag, -EINVAL);
1587 (void) device_read_db(device);
1589 return !!set_contains(device->tags, tag);
1592 _public_ int sd_device_get_property_value(sd_device *device, const char *key, const char **_value) {
1596 assert_return(device, -EINVAL);
1597 assert_return(key, -EINVAL);
1598 assert_return(_value, -EINVAL);
1600 r = device_properties_prepare(device);
1604 value = ordered_hashmap_get(device->properties, key);
1613 /* replaces the value if it already exists */
1614 static int device_add_sysattr_value(sd_device *device, const char *_key, char *value) {
1615 _cleanup_free_ char *key = NULL;
1616 _cleanup_free_ char *value_old = NULL;
1622 r = hashmap_ensure_allocated(&device->sysattr_values, &string_hash_ops);
1626 value_old = hashmap_remove2(device->sysattr_values, _key, (void **)&key);
1633 r = hashmap_put(device->sysattr_values, key, value);
1642 static int device_get_sysattr_value(sd_device *device, const char *_key, const char **_value) {
1643 const char *key = NULL, *value;
1648 value = hashmap_get2(device->sysattr_values, _key, (void **) &key);
1658 /* We cache all sysattr lookups. If an attribute does not exist, it is stored
1659 * with a NULL value in the cache, otherwise the returned string is stored */
1660 _public_ int sd_device_get_sysattr_value(sd_device *device, const char *sysattr, const char **_value) {
1661 _cleanup_free_ char *value = NULL;
1662 const char *syspath, *cached_value = NULL;
1664 struct stat statbuf;
1667 assert_return(device, -EINVAL);
1668 assert_return(sysattr, -EINVAL);
1670 /* look for possibly already cached result */
1671 r = device_get_sysattr_value(device, sysattr, &cached_value);
1677 /* we looked up the sysattr before and it did not exist */
1681 *_value = cached_value;
1686 r = sd_device_get_syspath(device, &syspath);
1690 path = strjoina(syspath, "/", sysattr);
1691 r = lstat(path, &statbuf);
1693 /* remember that we could not access the sysattr */
1694 r = device_add_sysattr_value(device, sysattr, NULL);
1699 } else if (S_ISLNK(statbuf.st_mode)) {
1700 /* Some core links return only the last element of the target path,
1701 * these are just values, the paths should not be exposed. */
1702 if (STR_IN_SET(sysattr, "driver", "subsystem", "module")) {
1703 r = readlink_value(path, &value);
1708 } else if (S_ISDIR(statbuf.st_mode)) {
1709 /* skip directories */
1711 } else if (!(statbuf.st_mode & S_IRUSR)) {
1712 /* skip non-readable files */
1717 /* read attribute value */
1718 r = read_full_file(path, &value, &size);
1722 /* drop trailing newlines */
1723 while (size > 0 && value[--size] == '\n')
1727 r = device_add_sysattr_value(device, sysattr, value);
1737 static void device_remove_sysattr_value(sd_device *device, const char *_key) {
1738 _cleanup_free_ char *key = NULL;
1739 _cleanup_free_ char *value = NULL;
1744 value = hashmap_remove2(device->sysattr_values, _key, (void **) &key);
1749 /* set the attribute and save it in the cache. If a NULL value is passed the
1750 * attribute is cleared from the cache */
1751 _public_ int sd_device_set_sysattr_value(sd_device *device, const char *sysattr, char *_value) {
1752 _cleanup_close_ int fd = -1;
1753 _cleanup_free_ char *value = NULL;
1754 const char *syspath;
1756 struct stat statbuf;
1757 size_t value_len = 0;
1761 assert_return(device, -EINVAL);
1762 assert_return(sysattr, -EINVAL);
1765 device_remove_sysattr_value(device, sysattr);
1770 r = sd_device_get_syspath(device, &syspath);
1774 path = strjoina(syspath, "/", sysattr);
1775 r = lstat(path, &statbuf);
1781 r = device_add_sysattr_value(device, sysattr, value);
1788 if (S_ISLNK(statbuf.st_mode))
1791 /* skip directories */
1792 if (S_ISDIR(statbuf.st_mode))
1795 /* skip non-readable files */
1796 if ((statbuf.st_mode & S_IRUSR) == 0)
1799 value_len = strlen(_value);
1801 /* drop trailing newlines */
1802 while (value_len > 0 && _value[value_len - 1] == '\n')
1803 _value[--value_len] = '\0';
1805 /* value length is limited to 4k */
1806 if (value_len > 4096)
1809 fd = open(path, O_WRONLY | O_CLOEXEC);
1813 value = strdup(_value);
1817 size = write(fd, value, value_len);
1821 if ((size_t)size != value_len)
1824 r = device_add_sysattr_value(device, sysattr, value);