1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 Copyright © 2008-2012 Kay Sievers <kay@vrfy.org>
4 Copyright © 2014 Tom Gundersen <teg@jklm.no>
11 #include "sd-device.h"
13 #include "alloc-util.h"
14 #include "device-internal.h"
15 #include "device-private.h"
16 #include "device-util.h"
17 #include "dirent-util.h"
23 #include "parse-util.h"
24 #include "path-util.h"
26 #include "socket-util.h"
27 #include "stat-util.h"
28 #include "string-util.h"
33 int device_new_aux(sd_device
**ret
) {
34 sd_device
*device
= NULL
;
38 device
= new0(sd_device
, 1);
43 device
->watch_handle
= -1;
50 _public_ sd_device
*sd_device_ref(sd_device
*device
) {
52 assert_se(++ device
->n_ref
>= 2);
57 _public_ sd_device
*sd_device_unref(sd_device
*device
) {
58 if (device
&& -- device
->n_ref
== 0) {
59 sd_device_unref(device
->parent
);
60 free(device
->syspath
);
61 free(device
->sysname
);
62 free(device
->devtype
);
63 free(device
->devname
);
64 free(device
->subsystem
);
65 free(device
->driver_subsystem
);
67 free(device
->id_filename
);
68 free(device
->properties_strv
);
69 free(device
->properties_nulstr
);
71 ordered_hashmap_free_free_free(device
->properties
);
72 ordered_hashmap_free_free_free(device
->properties_db
);
73 hashmap_free_free_free(device
->sysattr_values
);
74 set_free_free(device
->sysattrs
);
75 set_free_free(device
->tags
);
76 set_free_free(device
->devlinks
);
84 int device_add_property_aux(sd_device
*device
, const char *_key
, const char *_value
, bool db
) {
85 OrderedHashmap
**properties
;
91 properties
= &device
->properties_db
;
93 properties
= &device
->properties
;
96 _cleanup_free_
char *key
= NULL
, *value
= NULL
, *old_key
= NULL
, *old_value
= NULL
;
99 r
= ordered_hashmap_ensure_allocated(properties
, &string_hash_ops
);
107 value
= strdup(_value
);
111 old_value
= ordered_hashmap_get2(*properties
, key
, (void**) &old_key
);
113 r
= ordered_hashmap_replace(*properties
, key
, value
);
120 _cleanup_free_
char *key
= NULL
;
121 _cleanup_free_
char *value
= NULL
;
123 value
= ordered_hashmap_remove2(*properties
, _key
, (void**) &key
);
127 device
->properties_generation
++;
128 device
->properties_buf_outdated
= true;
134 int device_add_property_internal(sd_device
*device
, const char *key
, const char *value
) {
135 return device_add_property_aux(device
, key
, value
, false);
138 int device_set_syspath(sd_device
*device
, const char *_syspath
, bool verify
) {
139 _cleanup_free_
char *syspath
= NULL
;
146 /* must be a subdirectory of /sys */
147 if (!path_startswith(_syspath
, "/sys/")) {
148 log_debug("sd-device: syspath '%s' is not a subdirectory of /sys", _syspath
);
153 r
= chase_symlinks(_syspath
, NULL
, 0, &syspath
);
155 return -ENODEV
; /* the device does not exist (any more?) */
157 return log_debug_errno(r
, "sd-device: could not get target of '%s': %m", _syspath
);
159 if (!path_startswith(syspath
, "/sys")) {
160 _cleanup_free_
char *real_sys
= NULL
, *new_syspath
= NULL
;
163 /* /sys is a symlink to somewhere sysfs is mounted on? In that case, we convert the path to real sysfs to "/sys". */
164 r
= chase_symlinks("/sys", NULL
, 0, &real_sys
);
166 return log_debug_errno(r
, "sd-device: could not chase symlink /sys: %m");
168 p
= path_startswith(syspath
, real_sys
);
170 log_debug("sd-device: canonicalized path '%s' does not starts with sysfs mount point '%s'", syspath
, real_sys
);
174 new_syspath
= strjoin("/sys/", p
);
178 free_and_replace(syspath
, new_syspath
);
179 path_simplify(syspath
, false);
182 if (path_startswith(syspath
, "/sys/devices/")) {
185 /* all 'devices' require an 'uevent' file */
186 path
= strjoina(syspath
, "/uevent");
187 r
= access(path
, F_OK
);
190 /* this is not a valid device */
193 return log_debug_errno(errno
, "sd-device: %s does not have an uevent file: %m", syspath
);
196 /* everything else just needs to be a directory */
197 if (!is_dir(syspath
, false))
201 syspath
= strdup(_syspath
);
206 devpath
= syspath
+ STRLEN("/sys");
208 r
= device_add_property_internal(device
, "DEVPATH", devpath
);
212 free_and_replace(device
->syspath
, syspath
);
214 device
->devpath
= devpath
;
219 _public_
int sd_device_new_from_syspath(sd_device
**ret
, const char *syspath
) {
220 _cleanup_(sd_device_unrefp
) sd_device
*device
= NULL
;
223 assert_return(ret
, -EINVAL
);
224 assert_return(syspath
, -EINVAL
);
226 r
= device_new_aux(&device
);
230 r
= device_set_syspath(device
, syspath
, true);
234 *ret
= TAKE_PTR(device
);
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(IN_SET(type
, 'b', '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
) {
255 char *name
, *syspath
;
258 assert_return(ret
, -EINVAL
);
259 assert_return(subsystem
, -EINVAL
);
260 assert_return(sysname
, -EINVAL
);
262 if (streq(subsystem
, "subsystem")) {
263 syspath
= strjoina("/sys/subsystem/", sysname
);
264 if (access(syspath
, F_OK
) >= 0)
265 return sd_device_new_from_syspath(ret
, syspath
);
267 syspath
= strjoina("/sys/bus/", sysname
);
268 if (access(syspath
, F_OK
) >= 0)
269 return sd_device_new_from_syspath(ret
, syspath
);
271 syspath
= strjoina("/sys/class/", sysname
);
272 if (access(syspath
, F_OK
) >= 0)
273 return sd_device_new_from_syspath(ret
, syspath
);
274 } else if (streq(subsystem
, "module")) {
275 syspath
= strjoina("/sys/module/", sysname
);
276 if (access(syspath
, F_OK
) >= 0)
277 return sd_device_new_from_syspath(ret
, syspath
);
278 } else if (streq(subsystem
, "drivers")) {
279 char subsys
[PATH_MAX
];
282 strscpy(subsys
, sizeof(subsys
), sysname
);
283 driver
= strchr(subsys
, ':');
288 syspath
= strjoina("/sys/subsystem/", subsys
, "/drivers/", driver
);
289 if (access(syspath
, F_OK
) >= 0)
290 return sd_device_new_from_syspath(ret
, syspath
);
292 syspath
= strjoina("/sys/bus/", subsys
, "/drivers/", driver
);
293 if (access(syspath
, F_OK
) >= 0)
294 return sd_device_new_from_syspath(ret
, syspath
);
298 /* translate sysname back to sysfs filename */
299 name
= strdupa(sysname
);
300 while (name
[len
] != '\0') {
301 if (name
[len
] == '/')
307 syspath
= strjoina("/sys/subsystem/", subsystem
, "/devices/", name
);
308 if (access(syspath
, F_OK
) >= 0)
309 return sd_device_new_from_syspath(ret
, syspath
);
311 syspath
= strjoina("/sys/bus/", subsystem
, "/devices/", name
);
312 if (access(syspath
, F_OK
) >= 0)
313 return sd_device_new_from_syspath(ret
, syspath
);
315 syspath
= strjoina("/sys/class/", subsystem
, "/", name
);
316 if (access(syspath
, F_OK
) >= 0)
317 return sd_device_new_from_syspath(ret
, syspath
);
319 syspath
= strjoina("/sys/firmware/", subsystem
, "/", sysname
);
320 if (access(syspath
, F_OK
) >= 0)
321 return sd_device_new_from_syspath(ret
, syspath
);
326 int device_set_devtype(sd_device
*device
, const char *_devtype
) {
327 _cleanup_free_
char *devtype
= NULL
;
333 devtype
= strdup(_devtype
);
337 r
= device_add_property_internal(device
, "DEVTYPE", devtype
);
341 free_and_replace(device
->devtype
, devtype
);
346 int device_set_ifindex(sd_device
*device
, const char *_ifindex
) {
352 r
= parse_ifindex(_ifindex
, &ifindex
);
356 r
= device_add_property_internal(device
, "IFINDEX", _ifindex
);
360 device
->ifindex
= ifindex
;
365 int device_set_devname(sd_device
*device
, const char *_devname
) {
366 _cleanup_free_
char *devname
= NULL
;
372 if (_devname
[0] != '/') {
373 r
= asprintf(&devname
, "/dev/%s", _devname
);
377 devname
= strdup(_devname
);
382 r
= device_add_property_internal(device
, "DEVNAME", devname
);
386 free_and_replace(device
->devname
, devname
);
391 int device_set_devmode(sd_device
*device
, const char *_devmode
) {
398 r
= safe_atou(_devmode
, &devmode
);
405 r
= device_add_property_internal(device
, "DEVMODE", _devmode
);
409 device
->devmode
= devmode
;
414 int device_set_devnum(sd_device
*device
, const char *major
, const char *minor
) {
415 unsigned maj
= 0, min
= 0;
421 r
= safe_atou(major
, &maj
);
428 r
= safe_atou(minor
, &min
);
433 r
= device_add_property_internal(device
, "MAJOR", major
);
438 r
= device_add_property_internal(device
, "MINOR", minor
);
443 device
->devnum
= makedev(maj
, min
);
448 static int handle_uevent_line(sd_device
*device
, const char *key
, const char *value
, const char **major
, const char **minor
) {
457 if (streq(key
, "DEVTYPE")) {
458 r
= device_set_devtype(device
, value
);
461 } else if (streq(key
, "IFINDEX")) {
462 r
= device_set_ifindex(device
, value
);
465 } else if (streq(key
, "DEVNAME")) {
466 r
= device_set_devname(device
, value
);
469 } else if (streq(key
, "DEVMODE")) {
470 r
= device_set_devmode(device
, value
);
473 } else if (streq(key
, "MAJOR"))
475 else if (streq(key
, "MINOR"))
478 r
= device_add_property_internal(device
, key
, value
);
486 int device_read_uevent_file(sd_device
*device
) {
487 _cleanup_free_
char *uevent
= NULL
;
488 const char *syspath
, *key
= NULL
, *value
= NULL
, *major
= NULL
, *minor
= NULL
;
504 if (device
->uevent_loaded
|| device
->sealed
)
507 device
->uevent_loaded
= true;
509 r
= sd_device_get_syspath(device
, &syspath
);
513 path
= strjoina(syspath
, "/uevent");
515 r
= read_full_file(path
, &uevent
, &uevent_len
);
517 /* empty uevent files may be write-only */
519 else if (r
== -ENOENT
)
520 /* some devices may not have uevent files, see set_syspath() */
523 log_debug_errno(r
, "sd-device: failed to read uevent file '%s': %m", path
);
527 for (i
= 0; i
< uevent_len
; i
++)
530 if (!strchr(NEWLINE
, uevent
[i
])) {
538 if (uevent
[i
] == '=') {
542 } else if (strchr(NEWLINE
, uevent
[i
])) {
544 log_debug("sd-device: ignoring invalid uevent line '%s'", key
);
554 _fallthrough_
; /* to handle empty property */
556 if (strchr(NEWLINE
, uevent
[i
])) {
559 r
= handle_uevent_line(device
, key
, value
, &major
, &minor
);
561 log_debug_errno(r
, "sd-device: failed to handle uevent entry '%s=%s': %m", key
, value
);
568 assert_not_reached("invalid state when parsing uevent file");
572 r
= device_set_devnum(device
, major
, minor
);
574 log_debug_errno(r
, "sd-device: could not set 'MAJOR=%s' or 'MINOR=%s' from '%s': %m", major
, minor
, path
);
580 _public_
int sd_device_get_ifindex(sd_device
*device
, int *ifindex
) {
583 assert_return(device
, -EINVAL
);
584 assert_return(ifindex
, -EINVAL
);
586 r
= device_read_uevent_file(device
);
590 *ifindex
= device
->ifindex
;
595 _public_
int sd_device_new_from_device_id(sd_device
**ret
, const char *id
) {
598 assert_return(ret
, -EINVAL
);
599 assert_return(id
, -EINVAL
);
608 r
= sscanf(id
, "%c%i:%i", &type
, &maj
, &min
);
612 return sd_device_new_from_devnum(ret
, type
, makedev(maj
, min
));
616 _cleanup_(sd_device_unrefp
) sd_device
*device
= NULL
;
617 _cleanup_close_
int sk
= -1;
618 struct ifreq ifr
= {};
621 r
= parse_ifindex(&id
[1], &ifr
.ifr_ifindex
);
625 sk
= socket_ioctl_fd();
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
)
645 *ret
= TAKE_PTR(device
);
651 char subsys
[PATH_MAX
];
654 (void)strscpy(subsys
, sizeof(subsys
), id
+ 1);
655 sysname
= strchr(subsys
, ':');
662 return sd_device_new_from_subsystem_sysname(ret
, subsys
, sysname
);
669 _public_
int sd_device_get_syspath(sd_device
*device
, const char **ret
) {
670 assert_return(device
, -EINVAL
);
671 assert_return(ret
, -EINVAL
);
673 assert(path_startswith(device
->syspath
, "/sys/"));
675 *ret
= device
->syspath
;
680 static int device_new_from_child(sd_device
**ret
, sd_device
*child
) {
681 _cleanup_free_
char *path
= NULL
;
682 const char *subdir
, *syspath
;
688 r
= sd_device_get_syspath(child
, &syspath
);
692 path
= strdup(syspath
);
695 subdir
= path
+ STRLEN("/sys");
700 pos
= strrchr(subdir
, '/');
701 if (!pos
|| pos
< subdir
+ 2)
706 r
= sd_device_new_from_syspath(ret
, path
);
716 _public_
int sd_device_get_parent(sd_device
*child
, sd_device
**ret
) {
718 assert_return(ret
, -EINVAL
);
719 assert_return(child
, -EINVAL
);
721 if (!child
->parent_set
) {
722 child
->parent_set
= true;
724 (void)device_new_from_child(&child
->parent
, child
);
730 *ret
= child
->parent
;
735 int device_set_subsystem(sd_device
*device
, const char *_subsystem
) {
736 _cleanup_free_
char *subsystem
= NULL
;
742 subsystem
= strdup(_subsystem
);
746 r
= device_add_property_internal(device
, "SUBSYSTEM", subsystem
);
750 free_and_replace(device
->subsystem
, subsystem
);
752 device
->subsystem_set
= true;
757 static int device_set_drivers_subsystem(sd_device
*device
, const char *_subsystem
) {
758 _cleanup_free_
char *subsystem
= NULL
;
765 subsystem
= strdup(_subsystem
);
769 r
= device_set_subsystem(device
, "drivers");
773 free_and_replace(device
->driver_subsystem
, subsystem
);
778 _public_
int sd_device_get_subsystem(sd_device
*device
, const char **ret
) {
779 const char *syspath
, *drivers
= NULL
;
782 assert_return(ret
, -EINVAL
);
783 assert_return(device
, -EINVAL
);
785 r
= sd_device_get_syspath(device
, &syspath
);
789 if (!device
->subsystem_set
) {
790 _cleanup_free_
char *subsystem
= NULL
;
793 /* read 'subsystem' link */
794 path
= strjoina(syspath
, "/subsystem");
795 r
= readlink_value(path
, &subsystem
);
797 r
= device_set_subsystem(device
, subsystem
);
798 /* use implicit names */
799 else if (path_startswith(device
->devpath
, "/module/"))
800 r
= device_set_subsystem(device
, "module");
801 else if (!(drivers
= strstr(syspath
, "/drivers/")) &&
802 (path_startswith(device
->devpath
, "/subsystem/") ||
803 path_startswith(device
->devpath
, "/class/") ||
804 path_startswith(device
->devpath
, "/bus/")))
805 r
= device_set_subsystem(device
, "subsystem");
806 if (r
< 0 && r
!= -ENOENT
)
807 return log_debug_errno(r
, "sd-device: could not set subsystem for %s: %m", device
->devpath
);
809 device
->subsystem_set
= true;
810 } else if (!device
->driver_subsystem_set
)
811 drivers
= strstr(syspath
, "/drivers/");
813 if (!device
->driver_subsystem_set
) {
815 _cleanup_free_
char *subpath
= NULL
;
817 subpath
= strndup(syspath
, drivers
- syspath
);
823 subsys
= strrchr(subpath
, '/');
827 r
= device_set_drivers_subsystem(device
, subsys
+ 1);
829 if (r
< 0 && r
!= -ENOENT
)
830 return log_debug_errno(r
, "sd-device: could not set subsystem for driver %s: %m", device
->devpath
);
833 device
->driver_subsystem_set
= true;
836 if (!device
->subsystem
)
839 *ret
= device
->subsystem
;
844 _public_
int sd_device_get_devtype(sd_device
*device
, const char **devtype
) {
850 r
= device_read_uevent_file(device
);
854 *devtype
= device
->devtype
;
859 _public_
int sd_device_get_parent_with_subsystem_devtype(sd_device
*child
, const char *subsystem
, const char *devtype
, sd_device
**ret
) {
860 sd_device
*parent
= NULL
;
863 assert_return(child
, -EINVAL
);
864 assert_return(subsystem
, -EINVAL
);
866 r
= sd_device_get_parent(child
, &parent
);
868 const char *parent_subsystem
= NULL
;
869 const char *parent_devtype
= NULL
;
871 (void)sd_device_get_subsystem(parent
, &parent_subsystem
);
872 if (streq_ptr(parent_subsystem
, subsystem
)) {
876 (void)sd_device_get_devtype(parent
, &parent_devtype
);
877 if (streq_ptr(parent_devtype
, devtype
))
880 r
= sd_device_get_parent(parent
, &parent
);
891 _public_
int sd_device_get_devnum(sd_device
*device
, dev_t
*devnum
) {
894 assert_return(device
, -EINVAL
);
895 assert_return(devnum
, -EINVAL
);
897 r
= device_read_uevent_file(device
);
901 *devnum
= device
->devnum
;
906 int device_set_driver(sd_device
*device
, const char *_driver
) {
907 _cleanup_free_
char *driver
= NULL
;
913 driver
= strdup(_driver
);
917 r
= device_add_property_internal(device
, "DRIVER", driver
);
921 free_and_replace(device
->driver
, driver
);
923 device
->driver_set
= true;
928 _public_
int sd_device_get_driver(sd_device
*device
, const char **ret
) {
929 assert_return(device
, -EINVAL
);
930 assert_return(ret
, -EINVAL
);
932 if (!device
->driver_set
) {
933 _cleanup_free_
char *driver
= NULL
;
938 r
= sd_device_get_syspath(device
, &syspath
);
942 path
= strjoina(syspath
, "/driver");
943 r
= readlink_value(path
, &driver
);
945 r
= device_set_driver(device
, driver
);
947 return log_debug_errno(r
, "sd-device: could not set driver for %s: %m", device
->devpath
);
948 } else if (r
== -ENOENT
)
949 device
->driver_set
= true;
951 return log_debug_errno(r
, "sd-device: could not set driver for %s: %m", device
->devpath
);
957 *ret
= device
->driver
;
962 _public_
int sd_device_get_devpath(sd_device
*device
, const char **devpath
) {
963 assert_return(device
, -EINVAL
);
964 assert_return(devpath
, -EINVAL
);
966 assert(device
->devpath
);
967 assert(device
->devpath
[0] == '/');
969 *devpath
= device
->devpath
;
974 _public_
int sd_device_get_devname(sd_device
*device
, const char **devname
) {
977 assert_return(device
, -EINVAL
);
978 assert_return(devname
, -EINVAL
);
980 r
= device_read_uevent_file(device
);
984 if (!device
->devname
)
987 assert(path_startswith(device
->devname
, "/dev/"));
989 *devname
= device
->devname
;
994 static int device_set_sysname(sd_device
*device
) {
995 _cleanup_free_
char *sysname
= NULL
;
996 const char *sysnum
= NULL
;
1000 pos
= strrchr(device
->devpath
, '/');
1005 /* devpath is not a root directory */
1006 if (*pos
== '\0' || pos
<= device
->devpath
)
1009 sysname
= strdup(pos
);
1013 /* some devices have '!' in their name, change that to '/' */
1014 while (sysname
[len
] != '\0') {
1015 if (sysname
[len
] == '!')
1021 /* trailing number */
1022 while (len
> 0 && isdigit(sysname
[--len
]))
1023 sysnum
= &sysname
[len
];
1028 free_and_replace(device
->sysname
, sysname
);
1030 device
->sysnum
= sysnum
;
1032 device
->sysname_set
= true;
1037 _public_
int sd_device_get_sysname(sd_device
*device
, const char **ret
) {
1040 assert_return(device
, -EINVAL
);
1041 assert_return(ret
, -EINVAL
);
1043 if (!device
->sysname_set
) {
1044 r
= device_set_sysname(device
);
1049 assert_return(device
->sysname
, -ENOENT
);
1051 *ret
= device
->sysname
;
1056 _public_
int sd_device_get_sysnum(sd_device
*device
, const char **ret
) {
1059 assert_return(device
, -EINVAL
);
1060 assert_return(ret
, -EINVAL
);
1062 if (!device
->sysname_set
) {
1063 r
= device_set_sysname(device
);
1068 *ret
= device
->sysnum
;
1073 static bool is_valid_tag(const char *tag
) {
1076 return !strchr(tag
, ':') && !strchr(tag
, ' ');
1079 int device_add_tag(sd_device
*device
, const char *tag
) {
1085 if (!is_valid_tag(tag
))
1088 r
= set_ensure_allocated(&device
->tags
, &string_hash_ops
);
1092 r
= set_put_strdup(device
->tags
, tag
);
1096 device
->tags_generation
++;
1097 device
->property_tags_outdated
= true;
1102 int device_add_devlink(sd_device
*device
, const char *devlink
) {
1108 r
= set_ensure_allocated(&device
->devlinks
, &string_hash_ops
);
1112 r
= set_put_strdup(device
->devlinks
, devlink
);
1116 device
->devlinks_generation
++;
1117 device
->property_devlinks_outdated
= true;
1122 static int device_add_property_internal_from_string(sd_device
*device
, const char *str
) {
1123 _cleanup_free_
char *key
= NULL
;
1133 value
= strchr(key
, '=');
1139 if (isempty(++value
))
1142 return device_add_property_internal(device
, key
, value
);
1145 int device_set_usec_initialized(sd_device
*device
, const char *initialized
) {
1146 uint64_t usec_initialized
;
1150 assert(initialized
);
1152 r
= safe_atou64(initialized
, &usec_initialized
);
1156 r
= device_add_property_internal(device
, "USEC_INITIALIZED", initialized
);
1160 device
->usec_initialized
= usec_initialized
;
1165 static int handle_db_line(sd_device
*device
, char key
, const char *value
) {
1174 r
= device_add_tag(device
, value
);
1180 path
= strjoina("/dev/", value
);
1181 r
= device_add_devlink(device
, path
);
1187 r
= device_add_property_internal_from_string(device
, value
);
1193 r
= device_set_usec_initialized(device
, value
);
1199 r
= safe_atoi(value
, &device
->devlink_priority
);
1205 r
= safe_atoi(value
, &device
->watch_handle
);
1211 log_debug("device db: unknown key '%c'", key
);
1217 int device_get_id_filename(sd_device
*device
, const char **ret
) {
1221 if (!device
->id_filename
) {
1222 _cleanup_free_
char *id
= NULL
;
1223 const char *subsystem
;
1227 r
= sd_device_get_subsystem(device
, &subsystem
);
1231 r
= sd_device_get_devnum(device
, &devnum
);
1235 r
= sd_device_get_ifindex(device
, &ifindex
);
1239 if (major(devnum
) > 0) {
1242 /* use dev_t — b259:131072, c254:0 */
1243 r
= asprintf(&id
, "%c%u:%u",
1244 streq(subsystem
, "block") ? 'b' : 'c',
1245 major(devnum
), minor(devnum
));
1248 } else if (ifindex
> 0) {
1249 /* use netdev ifindex — n3 */
1250 r
= asprintf(&id
, "n%u", ifindex
);
1254 /* use $subsys:$sysname — pci:0000:00:1f.2
1255 * sysname() has '!' translated, get it from devpath
1257 const char *sysname
;
1259 sysname
= basename(device
->devpath
);
1266 if (streq(subsystem
, "drivers")) {
1267 /* the 'drivers' pseudo-subsystem is special, and needs the real subsystem
1268 * encoded as well */
1269 r
= asprintf(&id
, "+drivers:%s:%s", device
->driver_subsystem
, sysname
);
1273 r
= asprintf(&id
, "+%s:%s", subsystem
, sysname
);
1279 device
->id_filename
= TAKE_PTR(id
);
1282 *ret
= device
->id_filename
;
1287 int device_read_db_aux(sd_device
*device
, bool force
) {
1288 _cleanup_free_
char *db
= NULL
;
1290 const char *id
, *value
;
1304 if (device
->db_loaded
|| (!force
&& device
->sealed
))
1307 device
->db_loaded
= true;
1309 r
= device_get_id_filename(device
, &id
);
1313 path
= strjoina("/run/udev/data/", id
);
1315 r
= read_full_file(path
, &db
, &db_len
);
1320 return log_debug_errno(r
, "sd-device: failed to read db '%s': %m", path
);
1323 /* devices with a database entry are initialized */
1324 device
->is_initialized
= true;
1326 for (i
= 0; i
< db_len
; i
++) {
1329 if (!strchr(NEWLINE
, db
[i
])) {
1338 log_debug("sd-device: ignoring invalid db entry with key '%c'", key
);
1340 state
= INVALID_LINE
;
1355 if (strchr(NEWLINE
, db
[i
]))
1360 if (strchr(NEWLINE
, db
[i
])) {
1362 r
= handle_db_line(device
, key
, value
);
1364 log_debug_errno(r
, "sd-device: failed to handle db entry '%c:%s': %m", key
, value
);
1371 assert_not_reached("invalid state when parsing db");
1378 static int device_read_db(sd_device
*device
) {
1379 return device_read_db_aux(device
, false);
1382 _public_
int sd_device_get_is_initialized(sd_device
*device
, int *initialized
) {
1385 assert_return(device
, -EINVAL
);
1386 assert_return(initialized
, -EINVAL
);
1388 r
= device_read_db(device
);
1392 *initialized
= device
->is_initialized
;
1397 _public_
int sd_device_get_usec_since_initialized(sd_device
*device
, uint64_t *usec
) {
1401 assert_return(device
, -EINVAL
);
1402 assert_return(usec
, -EINVAL
);
1404 r
= device_read_db(device
);
1408 if (!device
->is_initialized
)
1411 if (!device
->usec_initialized
)
1414 now_ts
= now(clock_boottime_or_monotonic());
1416 if (now_ts
< device
->usec_initialized
)
1419 *usec
= now_ts
- device
->usec_initialized
;
1424 _public_
const char *sd_device_get_tag_first(sd_device
*device
) {
1427 assert_return(device
, NULL
);
1429 (void) device_read_db(device
);
1431 device
->tags_iterator_generation
= device
->tags_generation
;
1432 device
->tags_iterator
= ITERATOR_FIRST
;
1434 (void) set_iterate(device
->tags
, &device
->tags_iterator
, &v
);
1438 _public_
const char *sd_device_get_tag_next(sd_device
*device
) {
1441 assert_return(device
, NULL
);
1443 (void) device_read_db(device
);
1445 if (device
->tags_iterator_generation
!= device
->tags_generation
)
1448 (void) set_iterate(device
->tags
, &device
->tags_iterator
, &v
);
1452 _public_
const char *sd_device_get_devlink_first(sd_device
*device
) {
1455 assert_return(device
, NULL
);
1457 (void) device_read_db(device
);
1459 device
->devlinks_iterator_generation
= device
->devlinks_generation
;
1460 device
->devlinks_iterator
= ITERATOR_FIRST
;
1462 (void) set_iterate(device
->devlinks
, &device
->devlinks_iterator
, &v
);
1466 _public_
const char *sd_device_get_devlink_next(sd_device
*device
) {
1469 assert_return(device
, NULL
);
1471 (void) device_read_db(device
);
1473 if (device
->devlinks_iterator_generation
!= device
->devlinks_generation
)
1476 (void) set_iterate(device
->devlinks
, &device
->devlinks_iterator
, &v
);
1480 static int device_properties_prepare(sd_device
*device
) {
1485 r
= device_read_uevent_file(device
);
1489 r
= device_read_db(device
);
1493 if (device
->property_devlinks_outdated
) {
1494 _cleanup_free_
char *devlinks
= NULL
;
1495 size_t devlinks_allocated
= 0, devlinks_len
= 0;
1496 const char *devlink
;
1498 for (devlink
= sd_device_get_devlink_first(device
); devlink
; devlink
= sd_device_get_devlink_next(device
)) {
1501 if (!GREEDY_REALLOC(devlinks
, devlinks_allocated
, devlinks_len
+ strlen(devlink
) + 2))
1503 if (devlinks_len
> 0)
1504 stpcpy(devlinks
+ devlinks_len
++, " ");
1505 e
= stpcpy(devlinks
+ devlinks_len
, devlink
);
1506 devlinks_len
= e
- devlinks
;
1509 r
= device_add_property_internal(device
, "DEVLINKS", devlinks
);
1513 device
->property_devlinks_outdated
= false;
1516 if (device
->property_tags_outdated
) {
1517 _cleanup_free_
char *tags
= NULL
;
1518 size_t tags_allocated
= 0, tags_len
= 0;
1521 if (!GREEDY_REALLOC(tags
, tags_allocated
, 2))
1526 for (tag
= sd_device_get_tag_first(device
); tag
; tag
= sd_device_get_tag_next(device
)) {
1529 if (!GREEDY_REALLOC(tags
, tags_allocated
, tags_len
+ strlen(tag
) + 2))
1531 e
= stpcpy(stpcpy(tags
+ tags_len
, tag
), ":");
1532 tags_len
= e
- tags
;
1535 r
= device_add_property_internal(device
, "TAGS", tags
);
1539 device
->property_tags_outdated
= false;
1545 _public_
const char *sd_device_get_property_first(sd_device
*device
, const char **_value
) {
1550 assert_return(device
, NULL
);
1552 r
= device_properties_prepare(device
);
1556 device
->properties_iterator_generation
= device
->properties_generation
;
1557 device
->properties_iterator
= ITERATOR_FIRST
;
1559 ordered_hashmap_iterate(device
->properties
, &device
->properties_iterator
, (void**)&value
, (const void**)&key
);
1567 _public_
const char *sd_device_get_property_next(sd_device
*device
, const char **_value
) {
1572 assert_return(device
, NULL
);
1574 r
= device_properties_prepare(device
);
1578 if (device
->properties_iterator_generation
!= device
->properties_generation
)
1581 ordered_hashmap_iterate(device
->properties
, &device
->properties_iterator
, (void**)&value
, (const void**)&key
);
1589 static int device_sysattrs_read_all(sd_device
*device
) {
1590 _cleanup_closedir_
DIR *dir
= NULL
;
1591 const char *syspath
;
1592 struct dirent
*dent
;
1597 if (device
->sysattrs_read
)
1600 r
= sd_device_get_syspath(device
, &syspath
);
1604 dir
= opendir(syspath
);
1608 r
= set_ensure_allocated(&device
->sysattrs
, &string_hash_ops
);
1612 FOREACH_DIRENT_ALL(dent
, dir
, return -errno
) {
1614 struct stat statbuf
;
1616 /* only handle symlinks and regular files */
1617 if (!IN_SET(dent
->d_type
, DT_LNK
, DT_REG
))
1620 path
= strjoina(syspath
, "/", dent
->d_name
);
1622 if (lstat(path
, &statbuf
) != 0)
1625 if (!(statbuf
.st_mode
& S_IRUSR
))
1628 r
= set_put_strdup(device
->sysattrs
, dent
->d_name
);
1633 device
->sysattrs_read
= true;
1638 _public_
const char *sd_device_get_sysattr_first(sd_device
*device
) {
1642 assert_return(device
, NULL
);
1644 if (!device
->sysattrs_read
) {
1645 r
= device_sysattrs_read_all(device
);
1652 device
->sysattrs_iterator
= ITERATOR_FIRST
;
1654 (void) set_iterate(device
->sysattrs
, &device
->sysattrs_iterator
, &v
);
1658 _public_
const char *sd_device_get_sysattr_next(sd_device
*device
) {
1661 assert_return(device
, NULL
);
1663 if (!device
->sysattrs_read
)
1666 (void) set_iterate(device
->sysattrs
, &device
->sysattrs_iterator
, &v
);
1670 _public_
int sd_device_has_tag(sd_device
*device
, const char *tag
) {
1671 assert_return(device
, -EINVAL
);
1672 assert_return(tag
, -EINVAL
);
1674 (void) device_read_db(device
);
1676 return !!set_contains(device
->tags
, tag
);
1679 _public_
int sd_device_get_property_value(sd_device
*device
, const char *key
, const char **_value
) {
1683 assert_return(device
, -EINVAL
);
1684 assert_return(key
, -EINVAL
);
1685 assert_return(_value
, -EINVAL
);
1687 r
= device_properties_prepare(device
);
1691 value
= ordered_hashmap_get(device
->properties
, key
);
1700 /* replaces the value if it already exists */
1701 static int device_add_sysattr_value(sd_device
*device
, const char *_key
, char *value
) {
1702 _cleanup_free_
char *key
= NULL
;
1703 _cleanup_free_
char *value_old
= NULL
;
1709 r
= hashmap_ensure_allocated(&device
->sysattr_values
, &string_hash_ops
);
1713 value_old
= hashmap_remove2(device
->sysattr_values
, _key
, (void **)&key
);
1720 r
= hashmap_put(device
->sysattr_values
, key
, value
);
1729 static int device_get_sysattr_value(sd_device
*device
, const char *_key
, const char **_value
) {
1730 const char *key
= NULL
, *value
;
1735 value
= hashmap_get2(device
->sysattr_values
, _key
, (void **) &key
);
1745 /* We cache all sysattr lookups. If an attribute does not exist, it is stored
1746 * with a NULL value in the cache, otherwise the returned string is stored */
1747 _public_
int sd_device_get_sysattr_value(sd_device
*device
, const char *sysattr
, const char **_value
) {
1748 _cleanup_free_
char *value
= NULL
;
1749 const char *syspath
, *cached_value
= NULL
;
1751 struct stat statbuf
;
1754 assert_return(device
, -EINVAL
);
1755 assert_return(sysattr
, -EINVAL
);
1757 /* look for possibly already cached result */
1758 r
= device_get_sysattr_value(device
, sysattr
, &cached_value
);
1764 /* we looked up the sysattr before and it did not exist */
1768 *_value
= cached_value
;
1773 r
= sd_device_get_syspath(device
, &syspath
);
1777 path
= strjoina(syspath
, "/", sysattr
);
1778 r
= lstat(path
, &statbuf
);
1780 /* remember that we could not access the sysattr */
1781 r
= device_add_sysattr_value(device
, sysattr
, NULL
);
1786 } else if (S_ISLNK(statbuf
.st_mode
)) {
1787 /* Some core links return only the last element of the target path,
1788 * these are just values, the paths should not be exposed. */
1789 if (STR_IN_SET(sysattr
, "driver", "subsystem", "module")) {
1790 r
= readlink_value(path
, &value
);
1795 } else if (S_ISDIR(statbuf
.st_mode
)) {
1796 /* skip directories */
1798 } else if (!(statbuf
.st_mode
& S_IRUSR
)) {
1799 /* skip non-readable files */
1804 /* read attribute value */
1805 r
= read_full_file(path
, &value
, &size
);
1809 /* drop trailing newlines */
1810 while (size
> 0 && value
[--size
] == '\n')
1814 r
= device_add_sysattr_value(device
, sysattr
, value
);
1818 *_value
= TAKE_PTR(value
);
1823 static void device_remove_sysattr_value(sd_device
*device
, const char *_key
) {
1824 _cleanup_free_
char *key
= NULL
;
1825 _cleanup_free_
char *value
= NULL
;
1830 value
= hashmap_remove2(device
->sysattr_values
, _key
, (void **) &key
);
1835 /* set the attribute and save it in the cache. If a NULL value is passed the
1836 * attribute is cleared from the cache */
1837 _public_
int sd_device_set_sysattr_value(sd_device
*device
, const char *sysattr
, char *_value
) {
1838 _cleanup_close_
int fd
= -1;
1839 _cleanup_free_
char *value
= NULL
;
1840 const char *syspath
;
1846 assert_return(device
, -EINVAL
);
1847 assert_return(sysattr
, -EINVAL
);
1850 device_remove_sysattr_value(device
, sysattr
);
1855 r
= sd_device_get_syspath(device
, &syspath
);
1859 path
= strjoina(syspath
, "/", sysattr
);
1861 fd
= open(path
, O_WRONLY
| O_CLOEXEC
| O_NOFOLLOW
);
1865 if (errno
== EISDIR
)
1872 r
= device_add_sysattr_value(device
, sysattr
, value
);
1880 len
= strlen(_value
);
1882 /* drop trailing newlines */
1883 while (len
> 0 && _value
[len
- 1] == '\n')
1886 /* value length is limited to 4k */
1890 value
= strndup(_value
, len
);
1894 size
= write(fd
, value
, len
);
1898 if ((size_t)size
!= len
)
1901 r
= device_add_sysattr_value(device
, sysattr
, value
);