1 /* SPDX-License-Identifier: LGPL-2.1+ */
9 #include "alloc-util.h"
10 #include "device-internal.h"
11 #include "device-private.h"
12 #include "device-util.h"
13 #include "dirent-util.h"
19 #include "parse-util.h"
20 #include "path-util.h"
22 #include "socket-util.h"
23 #include "stat-util.h"
24 #include "string-util.h"
29 int device_new_aux(sd_device
**ret
) {
30 sd_device
*device
= NULL
;
34 device
= new(sd_device
, 1);
38 *device
= (sd_device
) {
47 static sd_device
*device_free(sd_device
*device
) {
50 sd_device_unref(device
->parent
);
51 free(device
->syspath
);
52 free(device
->sysname
);
53 free(device
->devtype
);
54 free(device
->devname
);
55 free(device
->subsystem
);
56 free(device
->driver_subsystem
);
58 free(device
->id_filename
);
59 free(device
->properties_strv
);
60 free(device
->properties_nulstr
);
62 ordered_hashmap_free_free_free(device
->properties
);
63 ordered_hashmap_free_free_free(device
->properties_db
);
64 hashmap_free_free_free(device
->sysattr_values
);
65 set_free_free(device
->sysattrs
);
66 set_free_free(device
->tags
);
67 set_free_free(device
->devlinks
);
72 DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_device
, sd_device
, device_free
);
74 int device_add_property_aux(sd_device
*device
, const char *_key
, const char *_value
, bool db
) {
75 OrderedHashmap
**properties
;
81 properties
= &device
->properties_db
;
83 properties
= &device
->properties
;
86 _cleanup_free_
char *key
= NULL
, *value
= NULL
, *old_key
= NULL
, *old_value
= NULL
;
89 r
= ordered_hashmap_ensure_allocated(properties
, &string_hash_ops
);
97 value
= strdup(_value
);
101 old_value
= ordered_hashmap_get2(*properties
, key
, (void**) &old_key
);
103 r
= ordered_hashmap_replace(*properties
, key
, value
);
110 _cleanup_free_
char *key
= NULL
;
111 _cleanup_free_
char *value
= NULL
;
113 value
= ordered_hashmap_remove2(*properties
, _key
, (void**) &key
);
117 device
->properties_generation
++;
118 device
->properties_buf_outdated
= true;
124 int device_add_property_internal(sd_device
*device
, const char *key
, const char *value
) {
125 return device_add_property_aux(device
, key
, value
, false);
128 int device_set_syspath(sd_device
*device
, const char *_syspath
, bool verify
) {
129 _cleanup_free_
char *syspath
= NULL
;
136 /* must be a subdirectory of /sys */
137 if (!path_startswith(_syspath
, "/sys/")) {
138 log_debug("sd-device: syspath '%s' is not a subdirectory of /sys", _syspath
);
143 r
= chase_symlinks(_syspath
, NULL
, 0, &syspath
);
145 return -ENODEV
; /* the device does not exist (any more?) */
147 return log_debug_errno(r
, "sd-device: could not get target of '%s': %m", _syspath
);
149 if (!path_startswith(syspath
, "/sys")) {
150 _cleanup_free_
char *real_sys
= NULL
, *new_syspath
= NULL
;
153 /* /sys is a symlink to somewhere sysfs is mounted on? In that case, we convert the path to real sysfs to "/sys". */
154 r
= chase_symlinks("/sys", NULL
, 0, &real_sys
);
156 return log_debug_errno(r
, "sd-device: could not chase symlink /sys: %m");
158 p
= path_startswith(syspath
, real_sys
);
160 log_debug("sd-device: canonicalized path '%s' does not starts with sysfs mount point '%s'", syspath
, real_sys
);
164 new_syspath
= strjoin("/sys/", p
);
168 free_and_replace(syspath
, new_syspath
);
169 path_simplify(syspath
, false);
172 if (path_startswith(syspath
, "/sys/devices/")) {
175 /* all 'devices' require an 'uevent' file */
176 path
= strjoina(syspath
, "/uevent");
177 r
= access(path
, F_OK
);
180 /* this is not a valid device */
183 return log_debug_errno(errno
, "sd-device: %s does not have an uevent file: %m", syspath
);
186 /* everything else just needs to be a directory */
187 if (!is_dir(syspath
, false))
191 syspath
= strdup(_syspath
);
196 devpath
= syspath
+ STRLEN("/sys");
198 r
= device_add_property_internal(device
, "DEVPATH", devpath
);
202 free_and_replace(device
->syspath
, syspath
);
204 device
->devpath
= devpath
;
209 _public_
int sd_device_new_from_syspath(sd_device
**ret
, const char *syspath
) {
210 _cleanup_(sd_device_unrefp
) sd_device
*device
= NULL
;
213 assert_return(ret
, -EINVAL
);
214 assert_return(syspath
, -EINVAL
);
216 r
= device_new_aux(&device
);
220 r
= device_set_syspath(device
, syspath
, true);
224 *ret
= TAKE_PTR(device
);
229 _public_
int sd_device_new_from_devnum(sd_device
**ret
, char type
, dev_t devnum
) {
231 char id
[DECIMAL_STR_MAX(unsigned) * 2 + 1];
233 assert_return(ret
, -EINVAL
);
234 assert_return(IN_SET(type
, 'b', 'c'), -EINVAL
);
236 /* use /sys/dev/{block,char}/<maj>:<min> link */
237 snprintf(id
, sizeof(id
), "%u:%u", major(devnum
), minor(devnum
));
239 syspath
= strjoina("/sys/dev/", (type
== 'b' ? "block" : "char"), "/", id
);
241 return sd_device_new_from_syspath(ret
, syspath
);
244 _public_
int sd_device_new_from_subsystem_sysname(sd_device
**ret
, const char *subsystem
, const char *sysname
) {
245 char *name
, *syspath
;
248 assert_return(ret
, -EINVAL
);
249 assert_return(subsystem
, -EINVAL
);
250 assert_return(sysname
, -EINVAL
);
252 if (streq(subsystem
, "subsystem")) {
253 syspath
= strjoina("/sys/subsystem/", sysname
);
254 if (access(syspath
, F_OK
) >= 0)
255 return sd_device_new_from_syspath(ret
, syspath
);
257 syspath
= strjoina("/sys/bus/", sysname
);
258 if (access(syspath
, F_OK
) >= 0)
259 return sd_device_new_from_syspath(ret
, syspath
);
261 syspath
= strjoina("/sys/class/", sysname
);
262 if (access(syspath
, F_OK
) >= 0)
263 return sd_device_new_from_syspath(ret
, syspath
);
264 } else if (streq(subsystem
, "module")) {
265 syspath
= strjoina("/sys/module/", sysname
);
266 if (access(syspath
, F_OK
) >= 0)
267 return sd_device_new_from_syspath(ret
, syspath
);
268 } else if (streq(subsystem
, "drivers")) {
269 char subsys
[PATH_MAX
];
272 strscpy(subsys
, sizeof(subsys
), sysname
);
273 driver
= strchr(subsys
, ':');
278 syspath
= strjoina("/sys/subsystem/", subsys
, "/drivers/", driver
);
279 if (access(syspath
, F_OK
) >= 0)
280 return sd_device_new_from_syspath(ret
, syspath
);
282 syspath
= strjoina("/sys/bus/", subsys
, "/drivers/", driver
);
283 if (access(syspath
, F_OK
) >= 0)
284 return sd_device_new_from_syspath(ret
, syspath
);
288 /* translate sysname back to sysfs filename */
289 name
= strdupa(sysname
);
290 while (name
[len
] != '\0') {
291 if (name
[len
] == '/')
297 syspath
= strjoina("/sys/subsystem/", subsystem
, "/devices/", name
);
298 if (access(syspath
, F_OK
) >= 0)
299 return sd_device_new_from_syspath(ret
, syspath
);
301 syspath
= strjoina("/sys/bus/", subsystem
, "/devices/", name
);
302 if (access(syspath
, F_OK
) >= 0)
303 return sd_device_new_from_syspath(ret
, syspath
);
305 syspath
= strjoina("/sys/class/", subsystem
, "/", name
);
306 if (access(syspath
, F_OK
) >= 0)
307 return sd_device_new_from_syspath(ret
, syspath
);
309 syspath
= strjoina("/sys/firmware/", subsystem
, "/", sysname
);
310 if (access(syspath
, F_OK
) >= 0)
311 return sd_device_new_from_syspath(ret
, syspath
);
316 int device_set_devtype(sd_device
*device
, const char *_devtype
) {
317 _cleanup_free_
char *devtype
= NULL
;
323 devtype
= strdup(_devtype
);
327 r
= device_add_property_internal(device
, "DEVTYPE", devtype
);
331 free_and_replace(device
->devtype
, devtype
);
336 int device_set_ifindex(sd_device
*device
, const char *_ifindex
) {
342 r
= parse_ifindex(_ifindex
, &ifindex
);
346 r
= device_add_property_internal(device
, "IFINDEX", _ifindex
);
350 device
->ifindex
= ifindex
;
355 int device_set_devname(sd_device
*device
, const char *_devname
) {
356 _cleanup_free_
char *devname
= NULL
;
362 if (_devname
[0] != '/') {
363 r
= asprintf(&devname
, "/dev/%s", _devname
);
367 devname
= strdup(_devname
);
372 r
= device_add_property_internal(device
, "DEVNAME", devname
);
376 free_and_replace(device
->devname
, devname
);
381 int device_set_devmode(sd_device
*device
, const char *_devmode
) {
388 r
= safe_atou(_devmode
, &devmode
);
395 r
= device_add_property_internal(device
, "DEVMODE", _devmode
);
399 device
->devmode
= devmode
;
404 int device_set_devnum(sd_device
*device
, const char *major
, const char *minor
) {
405 unsigned maj
= 0, min
= 0;
411 r
= safe_atou(major
, &maj
);
418 r
= safe_atou(minor
, &min
);
423 r
= device_add_property_internal(device
, "MAJOR", major
);
428 r
= device_add_property_internal(device
, "MINOR", minor
);
433 device
->devnum
= makedev(maj
, min
);
438 static int handle_uevent_line(sd_device
*device
, const char *key
, const char *value
, const char **major
, const char **minor
) {
447 if (streq(key
, "DEVTYPE")) {
448 r
= device_set_devtype(device
, value
);
451 } else if (streq(key
, "IFINDEX")) {
452 r
= device_set_ifindex(device
, value
);
455 } else if (streq(key
, "DEVNAME")) {
456 r
= device_set_devname(device
, value
);
459 } else if (streq(key
, "DEVMODE")) {
460 r
= device_set_devmode(device
, value
);
463 } else if (streq(key
, "MAJOR"))
465 else if (streq(key
, "MINOR"))
468 r
= device_add_property_internal(device
, key
, value
);
476 int device_read_uevent_file(sd_device
*device
) {
477 _cleanup_free_
char *uevent
= NULL
;
478 const char *syspath
, *key
= NULL
, *value
= NULL
, *major
= NULL
, *minor
= NULL
;
494 if (device
->uevent_loaded
|| device
->sealed
)
497 device
->uevent_loaded
= true;
499 r
= sd_device_get_syspath(device
, &syspath
);
503 path
= strjoina(syspath
, "/uevent");
505 r
= read_full_file(path
, &uevent
, &uevent_len
);
507 /* empty uevent files may be write-only */
509 else if (r
== -ENOENT
)
510 /* some devices may not have uevent files, see set_syspath() */
513 return log_debug_errno(r
, "sd-device: failed to read uevent file '%s': %m", path
);
515 for (i
= 0; i
< uevent_len
; i
++)
518 if (!strchr(NEWLINE
, uevent
[i
])) {
526 if (uevent
[i
] == '=') {
530 } else if (strchr(NEWLINE
, uevent
[i
])) {
532 log_debug("sd-device: ignoring invalid uevent line '%s'", key
);
542 _fallthrough_
; /* to handle empty property */
544 if (strchr(NEWLINE
, uevent
[i
])) {
547 r
= handle_uevent_line(device
, key
, value
, &major
, &minor
);
549 log_debug_errno(r
, "sd-device: failed to handle uevent entry '%s=%s': %m", key
, value
);
556 assert_not_reached("invalid state when parsing uevent file");
560 r
= device_set_devnum(device
, major
, minor
);
562 log_debug_errno(r
, "sd-device: could not set 'MAJOR=%s' or 'MINOR=%s' from '%s': %m", major
, minor
, path
);
568 _public_
int sd_device_get_ifindex(sd_device
*device
, int *ifindex
) {
571 assert_return(device
, -EINVAL
);
572 assert_return(ifindex
, -EINVAL
);
574 r
= device_read_uevent_file(device
);
578 *ifindex
= device
->ifindex
;
583 _public_
int sd_device_new_from_device_id(sd_device
**ret
, const char *id
) {
586 assert_return(ret
, -EINVAL
);
587 assert_return(id
, -EINVAL
);
596 r
= sscanf(id
, "%c%i:%i", &type
, &maj
, &min
);
600 return sd_device_new_from_devnum(ret
, type
, makedev(maj
, min
));
604 _cleanup_(sd_device_unrefp
) sd_device
*device
= NULL
;
605 _cleanup_close_
int sk
= -1;
606 struct ifreq ifr
= {};
609 r
= parse_ifindex(&id
[1], &ifr
.ifr_ifindex
);
613 sk
= socket_ioctl_fd();
617 r
= ioctl(sk
, SIOCGIFNAME
, &ifr
);
621 r
= sd_device_new_from_subsystem_sysname(&device
, "net", ifr
.ifr_name
);
625 r
= sd_device_get_ifindex(device
, &ifindex
);
629 /* this is racey, so we might end up with the wrong device */
630 if (ifr
.ifr_ifindex
!= ifindex
)
633 *ret
= TAKE_PTR(device
);
639 char subsys
[PATH_MAX
];
642 (void) strscpy(subsys
, sizeof(subsys
), id
+ 1);
643 sysname
= strchr(subsys
, ':');
650 return sd_device_new_from_subsystem_sysname(ret
, subsys
, sysname
);
657 _public_
int sd_device_get_syspath(sd_device
*device
, const char **ret
) {
658 assert_return(device
, -EINVAL
);
659 assert_return(ret
, -EINVAL
);
661 assert(path_startswith(device
->syspath
, "/sys/"));
663 *ret
= device
->syspath
;
668 static int device_new_from_child(sd_device
**ret
, sd_device
*child
) {
669 _cleanup_free_
char *path
= NULL
;
670 const char *subdir
, *syspath
;
676 r
= sd_device_get_syspath(child
, &syspath
);
680 path
= strdup(syspath
);
683 subdir
= path
+ STRLEN("/sys");
688 pos
= strrchr(subdir
, '/');
689 if (!pos
|| pos
< subdir
+ 2)
694 r
= sd_device_new_from_syspath(ret
, path
);
704 _public_
int sd_device_get_parent(sd_device
*child
, sd_device
**ret
) {
706 assert_return(ret
, -EINVAL
);
707 assert_return(child
, -EINVAL
);
709 if (!child
->parent_set
) {
710 child
->parent_set
= true;
712 (void) device_new_from_child(&child
->parent
, child
);
718 *ret
= child
->parent
;
723 int device_set_subsystem(sd_device
*device
, const char *_subsystem
) {
724 _cleanup_free_
char *subsystem
= NULL
;
730 subsystem
= strdup(_subsystem
);
734 r
= device_add_property_internal(device
, "SUBSYSTEM", subsystem
);
738 free_and_replace(device
->subsystem
, subsystem
);
740 device
->subsystem_set
= true;
745 static int device_set_drivers_subsystem(sd_device
*device
, const char *_subsystem
) {
746 _cleanup_free_
char *subsystem
= NULL
;
753 subsystem
= strdup(_subsystem
);
757 r
= device_set_subsystem(device
, "drivers");
761 free_and_replace(device
->driver_subsystem
, subsystem
);
766 _public_
int sd_device_get_subsystem(sd_device
*device
, const char **ret
) {
767 const char *syspath
, *drivers
= NULL
;
770 assert_return(ret
, -EINVAL
);
771 assert_return(device
, -EINVAL
);
773 r
= sd_device_get_syspath(device
, &syspath
);
777 if (!device
->subsystem_set
) {
778 _cleanup_free_
char *subsystem
= NULL
;
781 /* read 'subsystem' link */
782 path
= strjoina(syspath
, "/subsystem");
783 r
= readlink_value(path
, &subsystem
);
785 r
= device_set_subsystem(device
, subsystem
);
786 /* use implicit names */
787 else if (path_startswith(device
->devpath
, "/module/"))
788 r
= device_set_subsystem(device
, "module");
789 else if (!(drivers
= strstr(syspath
, "/drivers/")) &&
790 (path_startswith(device
->devpath
, "/subsystem/") ||
791 path_startswith(device
->devpath
, "/class/") ||
792 path_startswith(device
->devpath
, "/bus/")))
793 r
= device_set_subsystem(device
, "subsystem");
794 if (r
< 0 && r
!= -ENOENT
)
795 return log_debug_errno(r
, "sd-device: could not set subsystem for %s: %m", device
->devpath
);
797 device
->subsystem_set
= true;
798 } else if (!device
->driver_subsystem_set
)
799 drivers
= strstr(syspath
, "/drivers/");
801 if (!device
->driver_subsystem_set
) {
803 _cleanup_free_
char *subpath
= NULL
;
805 subpath
= strndup(syspath
, drivers
- syspath
);
811 subsys
= strrchr(subpath
, '/');
815 r
= device_set_drivers_subsystem(device
, subsys
+ 1);
817 if (r
< 0 && r
!= -ENOENT
)
818 return log_debug_errno(r
, "sd-device: could not set subsystem for driver %s: %m", device
->devpath
);
821 device
->driver_subsystem_set
= true;
824 if (!device
->subsystem
)
827 *ret
= device
->subsystem
;
832 _public_
int sd_device_get_devtype(sd_device
*device
, const char **devtype
) {
838 r
= device_read_uevent_file(device
);
842 *devtype
= device
->devtype
;
847 _public_
int sd_device_get_parent_with_subsystem_devtype(sd_device
*child
, const char *subsystem
, const char *devtype
, sd_device
**ret
) {
848 sd_device
*parent
= NULL
;
851 assert_return(child
, -EINVAL
);
852 assert_return(subsystem
, -EINVAL
);
854 r
= sd_device_get_parent(child
, &parent
);
856 const char *parent_subsystem
= NULL
;
857 const char *parent_devtype
= NULL
;
859 (void) sd_device_get_subsystem(parent
, &parent_subsystem
);
860 if (streq_ptr(parent_subsystem
, subsystem
)) {
864 (void) sd_device_get_devtype(parent
, &parent_devtype
);
865 if (streq_ptr(parent_devtype
, devtype
))
868 r
= sd_device_get_parent(parent
, &parent
);
879 _public_
int sd_device_get_devnum(sd_device
*device
, dev_t
*devnum
) {
882 assert_return(device
, -EINVAL
);
883 assert_return(devnum
, -EINVAL
);
885 r
= device_read_uevent_file(device
);
889 *devnum
= device
->devnum
;
894 int device_set_driver(sd_device
*device
, const char *_driver
) {
895 _cleanup_free_
char *driver
= NULL
;
901 driver
= strdup(_driver
);
905 r
= device_add_property_internal(device
, "DRIVER", driver
);
909 free_and_replace(device
->driver
, driver
);
911 device
->driver_set
= true;
916 _public_
int sd_device_get_driver(sd_device
*device
, const char **ret
) {
917 assert_return(device
, -EINVAL
);
918 assert_return(ret
, -EINVAL
);
920 if (!device
->driver_set
) {
921 _cleanup_free_
char *driver
= NULL
;
926 r
= sd_device_get_syspath(device
, &syspath
);
930 path
= strjoina(syspath
, "/driver");
931 r
= readlink_value(path
, &driver
);
933 r
= device_set_driver(device
, driver
);
935 return log_debug_errno(r
, "sd-device: could not set driver for %s: %m", device
->devpath
);
936 } else if (r
== -ENOENT
)
937 device
->driver_set
= true;
939 return log_debug_errno(r
, "sd-device: could not set driver for %s: %m", device
->devpath
);
945 *ret
= device
->driver
;
950 _public_
int sd_device_get_devpath(sd_device
*device
, const char **devpath
) {
951 assert_return(device
, -EINVAL
);
952 assert_return(devpath
, -EINVAL
);
954 assert(device
->devpath
);
955 assert(device
->devpath
[0] == '/');
957 *devpath
= device
->devpath
;
962 _public_
int sd_device_get_devname(sd_device
*device
, const char **devname
) {
965 assert_return(device
, -EINVAL
);
966 assert_return(devname
, -EINVAL
);
968 r
= device_read_uevent_file(device
);
972 if (!device
->devname
)
975 assert(path_startswith(device
->devname
, "/dev/"));
977 *devname
= device
->devname
;
982 static int device_set_sysname(sd_device
*device
) {
983 _cleanup_free_
char *sysname
= NULL
;
984 const char *sysnum
= NULL
;
988 pos
= strrchr(device
->devpath
, '/');
993 /* devpath is not a root directory */
994 if (*pos
== '\0' || pos
<= device
->devpath
)
997 sysname
= strdup(pos
);
1001 /* some devices have '!' in their name, change that to '/' */
1002 while (sysname
[len
] != '\0') {
1003 if (sysname
[len
] == '!')
1009 /* trailing number */
1010 while (len
> 0 && isdigit(sysname
[--len
]))
1011 sysnum
= &sysname
[len
];
1016 free_and_replace(device
->sysname
, sysname
);
1018 device
->sysnum
= sysnum
;
1020 device
->sysname_set
= true;
1025 _public_
int sd_device_get_sysname(sd_device
*device
, const char **ret
) {
1028 assert_return(device
, -EINVAL
);
1029 assert_return(ret
, -EINVAL
);
1031 if (!device
->sysname_set
) {
1032 r
= device_set_sysname(device
);
1037 assert_return(device
->sysname
, -ENOENT
);
1039 *ret
= device
->sysname
;
1044 _public_
int sd_device_get_sysnum(sd_device
*device
, const char **ret
) {
1047 assert_return(device
, -EINVAL
);
1048 assert_return(ret
, -EINVAL
);
1050 if (!device
->sysname_set
) {
1051 r
= device_set_sysname(device
);
1056 *ret
= device
->sysnum
;
1061 static bool is_valid_tag(const char *tag
) {
1064 return !strchr(tag
, ':') && !strchr(tag
, ' ');
1067 int device_add_tag(sd_device
*device
, const char *tag
) {
1073 if (!is_valid_tag(tag
))
1076 r
= set_ensure_allocated(&device
->tags
, &string_hash_ops
);
1080 r
= set_put_strdup(device
->tags
, tag
);
1084 device
->tags_generation
++;
1085 device
->property_tags_outdated
= true;
1090 int device_add_devlink(sd_device
*device
, const char *devlink
) {
1096 r
= set_ensure_allocated(&device
->devlinks
, &string_hash_ops
);
1100 r
= set_put_strdup(device
->devlinks
, devlink
);
1104 device
->devlinks_generation
++;
1105 device
->property_devlinks_outdated
= true;
1110 static int device_add_property_internal_from_string(sd_device
*device
, const char *str
) {
1111 _cleanup_free_
char *key
= NULL
;
1121 value
= strchr(key
, '=');
1127 if (isempty(++value
))
1130 return device_add_property_internal(device
, key
, value
);
1133 int device_set_usec_initialized(sd_device
*device
, const char *initialized
) {
1134 uint64_t usec_initialized
;
1138 assert(initialized
);
1140 r
= safe_atou64(initialized
, &usec_initialized
);
1144 r
= device_add_property_internal(device
, "USEC_INITIALIZED", initialized
);
1148 device
->usec_initialized
= usec_initialized
;
1153 static int handle_db_line(sd_device
*device
, char key
, const char *value
) {
1162 r
= device_add_tag(device
, value
);
1168 path
= strjoina("/dev/", value
);
1169 r
= device_add_devlink(device
, path
);
1175 r
= device_add_property_internal_from_string(device
, value
);
1181 r
= device_set_usec_initialized(device
, value
);
1187 r
= safe_atoi(value
, &device
->devlink_priority
);
1193 r
= safe_atoi(value
, &device
->watch_handle
);
1199 log_debug("device db: unknown key '%c'", key
);
1205 int device_get_id_filename(sd_device
*device
, const char **ret
) {
1209 if (!device
->id_filename
) {
1210 _cleanup_free_
char *id
= NULL
;
1211 const char *subsystem
;
1215 r
= sd_device_get_subsystem(device
, &subsystem
);
1219 r
= sd_device_get_devnum(device
, &devnum
);
1223 r
= sd_device_get_ifindex(device
, &ifindex
);
1227 if (major(devnum
) > 0) {
1230 /* use dev_t — b259:131072, c254:0 */
1231 r
= asprintf(&id
, "%c%u:%u",
1232 streq(subsystem
, "block") ? 'b' : 'c',
1233 major(devnum
), minor(devnum
));
1236 } else if (ifindex
> 0) {
1237 /* use netdev ifindex — n3 */
1238 r
= asprintf(&id
, "n%u", ifindex
);
1242 /* use $subsys:$sysname — pci:0000:00:1f.2
1243 * sysname() has '!' translated, get it from devpath
1245 const char *sysname
;
1247 sysname
= basename(device
->devpath
);
1254 if (streq(subsystem
, "drivers")) {
1255 /* the 'drivers' pseudo-subsystem is special, and needs the real subsystem
1256 * encoded as well */
1257 r
= asprintf(&id
, "+drivers:%s:%s", device
->driver_subsystem
, sysname
);
1261 r
= asprintf(&id
, "+%s:%s", subsystem
, sysname
);
1267 device
->id_filename
= TAKE_PTR(id
);
1270 *ret
= device
->id_filename
;
1275 int device_read_db_aux(sd_device
*device
, bool force
) {
1276 _cleanup_free_
char *db
= NULL
;
1278 const char *id
, *value
;
1292 if (device
->db_loaded
|| (!force
&& device
->sealed
))
1295 device
->db_loaded
= true;
1297 r
= device_get_id_filename(device
, &id
);
1301 path
= strjoina("/run/udev/data/", id
);
1303 r
= read_full_file(path
, &db
, &db_len
);
1308 return log_debug_errno(r
, "sd-device: failed to read db '%s': %m", path
);
1311 /* devices with a database entry are initialized */
1312 device
->is_initialized
= true;
1314 for (i
= 0; i
< db_len
; i
++) {
1317 if (!strchr(NEWLINE
, db
[i
])) {
1326 log_debug("sd-device: ignoring invalid db entry with key '%c'", key
);
1328 state
= INVALID_LINE
;
1343 if (strchr(NEWLINE
, db
[i
]))
1348 if (strchr(NEWLINE
, db
[i
])) {
1350 r
= handle_db_line(device
, key
, value
);
1352 log_debug_errno(r
, "sd-device: failed to handle db entry '%c:%s': %m", key
, value
);
1359 assert_not_reached("invalid state when parsing db");
1366 static int device_read_db(sd_device
*device
) {
1367 return device_read_db_aux(device
, false);
1370 _public_
int sd_device_get_is_initialized(sd_device
*device
, int *initialized
) {
1373 assert_return(device
, -EINVAL
);
1374 assert_return(initialized
, -EINVAL
);
1376 r
= device_read_db(device
);
1380 *initialized
= device
->is_initialized
;
1385 _public_
int sd_device_get_usec_since_initialized(sd_device
*device
, uint64_t *usec
) {
1389 assert_return(device
, -EINVAL
);
1390 assert_return(usec
, -EINVAL
);
1392 r
= device_read_db(device
);
1396 if (!device
->is_initialized
)
1399 if (!device
->usec_initialized
)
1402 now_ts
= now(clock_boottime_or_monotonic());
1404 if (now_ts
< device
->usec_initialized
)
1407 *usec
= now_ts
- device
->usec_initialized
;
1412 _public_
const char *sd_device_get_tag_first(sd_device
*device
) {
1415 assert_return(device
, NULL
);
1417 (void) device_read_db(device
);
1419 device
->tags_iterator_generation
= device
->tags_generation
;
1420 device
->tags_iterator
= ITERATOR_FIRST
;
1422 (void) set_iterate(device
->tags
, &device
->tags_iterator
, &v
);
1426 _public_
const char *sd_device_get_tag_next(sd_device
*device
) {
1429 assert_return(device
, NULL
);
1431 (void) device_read_db(device
);
1433 if (device
->tags_iterator_generation
!= device
->tags_generation
)
1436 (void) set_iterate(device
->tags
, &device
->tags_iterator
, &v
);
1440 _public_
const char *sd_device_get_devlink_first(sd_device
*device
) {
1443 assert_return(device
, NULL
);
1445 (void) device_read_db(device
);
1447 device
->devlinks_iterator_generation
= device
->devlinks_generation
;
1448 device
->devlinks_iterator
= ITERATOR_FIRST
;
1450 (void) set_iterate(device
->devlinks
, &device
->devlinks_iterator
, &v
);
1454 _public_
const char *sd_device_get_devlink_next(sd_device
*device
) {
1457 assert_return(device
, NULL
);
1459 (void) device_read_db(device
);
1461 if (device
->devlinks_iterator_generation
!= device
->devlinks_generation
)
1464 (void) set_iterate(device
->devlinks
, &device
->devlinks_iterator
, &v
);
1468 static int device_properties_prepare(sd_device
*device
) {
1473 r
= device_read_uevent_file(device
);
1477 r
= device_read_db(device
);
1481 if (device
->property_devlinks_outdated
) {
1482 _cleanup_free_
char *devlinks
= NULL
;
1483 size_t devlinks_allocated
= 0, devlinks_len
= 0;
1484 const char *devlink
;
1486 for (devlink
= sd_device_get_devlink_first(device
); devlink
; devlink
= sd_device_get_devlink_next(device
)) {
1489 if (!GREEDY_REALLOC(devlinks
, devlinks_allocated
, devlinks_len
+ strlen(devlink
) + 2))
1491 if (devlinks_len
> 0)
1492 stpcpy(devlinks
+ devlinks_len
++, " ");
1493 e
= stpcpy(devlinks
+ devlinks_len
, devlink
);
1494 devlinks_len
= e
- devlinks
;
1497 r
= device_add_property_internal(device
, "DEVLINKS", devlinks
);
1501 device
->property_devlinks_outdated
= false;
1504 if (device
->property_tags_outdated
) {
1505 _cleanup_free_
char *tags
= NULL
;
1506 size_t tags_allocated
= 0, tags_len
= 0;
1509 if (!GREEDY_REALLOC(tags
, tags_allocated
, 2))
1514 for (tag
= sd_device_get_tag_first(device
); tag
; tag
= sd_device_get_tag_next(device
)) {
1517 if (!GREEDY_REALLOC(tags
, tags_allocated
, tags_len
+ strlen(tag
) + 2))
1519 e
= stpcpy(stpcpy(tags
+ tags_len
, tag
), ":");
1520 tags_len
= e
- tags
;
1523 r
= device_add_property_internal(device
, "TAGS", tags
);
1527 device
->property_tags_outdated
= false;
1533 _public_
const char *sd_device_get_property_first(sd_device
*device
, const char **_value
) {
1538 assert_return(device
, NULL
);
1540 r
= device_properties_prepare(device
);
1544 device
->properties_iterator_generation
= device
->properties_generation
;
1545 device
->properties_iterator
= ITERATOR_FIRST
;
1547 ordered_hashmap_iterate(device
->properties
, &device
->properties_iterator
, (void**)&value
, (const void**)&key
);
1555 _public_
const char *sd_device_get_property_next(sd_device
*device
, const char **_value
) {
1560 assert_return(device
, NULL
);
1562 r
= device_properties_prepare(device
);
1566 if (device
->properties_iterator_generation
!= device
->properties_generation
)
1569 ordered_hashmap_iterate(device
->properties
, &device
->properties_iterator
, (void**)&value
, (const void**)&key
);
1577 static int device_sysattrs_read_all(sd_device
*device
) {
1578 _cleanup_closedir_
DIR *dir
= NULL
;
1579 const char *syspath
;
1580 struct dirent
*dent
;
1585 if (device
->sysattrs_read
)
1588 r
= sd_device_get_syspath(device
, &syspath
);
1592 dir
= opendir(syspath
);
1596 r
= set_ensure_allocated(&device
->sysattrs
, &string_hash_ops
);
1600 FOREACH_DIRENT_ALL(dent
, dir
, return -errno
) {
1602 struct stat statbuf
;
1604 /* only handle symlinks and regular files */
1605 if (!IN_SET(dent
->d_type
, DT_LNK
, DT_REG
))
1608 path
= strjoina(syspath
, "/", dent
->d_name
);
1610 if (lstat(path
, &statbuf
) != 0)
1613 if (!(statbuf
.st_mode
& S_IRUSR
))
1616 r
= set_put_strdup(device
->sysattrs
, dent
->d_name
);
1621 device
->sysattrs_read
= true;
1626 _public_
const char *sd_device_get_sysattr_first(sd_device
*device
) {
1630 assert_return(device
, NULL
);
1632 if (!device
->sysattrs_read
) {
1633 r
= device_sysattrs_read_all(device
);
1640 device
->sysattrs_iterator
= ITERATOR_FIRST
;
1642 (void) set_iterate(device
->sysattrs
, &device
->sysattrs_iterator
, &v
);
1646 _public_
const char *sd_device_get_sysattr_next(sd_device
*device
) {
1649 assert_return(device
, NULL
);
1651 if (!device
->sysattrs_read
)
1654 (void) set_iterate(device
->sysattrs
, &device
->sysattrs_iterator
, &v
);
1658 _public_
int sd_device_has_tag(sd_device
*device
, const char *tag
) {
1659 assert_return(device
, -EINVAL
);
1660 assert_return(tag
, -EINVAL
);
1662 (void) device_read_db(device
);
1664 return !!set_contains(device
->tags
, tag
);
1667 _public_
int sd_device_get_property_value(sd_device
*device
, const char *key
, const char **_value
) {
1671 assert_return(device
, -EINVAL
);
1672 assert_return(key
, -EINVAL
);
1673 assert_return(_value
, -EINVAL
);
1675 r
= device_properties_prepare(device
);
1679 value
= ordered_hashmap_get(device
->properties
, key
);
1688 /* replaces the value if it already exists */
1689 static int device_add_sysattr_value(sd_device
*device
, const char *_key
, char *value
) {
1690 _cleanup_free_
char *key
= NULL
;
1691 _cleanup_free_
char *value_old
= NULL
;
1697 r
= hashmap_ensure_allocated(&device
->sysattr_values
, &string_hash_ops
);
1701 value_old
= hashmap_remove2(device
->sysattr_values
, _key
, (void **)&key
);
1708 r
= hashmap_put(device
->sysattr_values
, key
, value
);
1717 static int device_get_sysattr_value(sd_device
*device
, const char *_key
, const char **_value
) {
1718 const char *key
= NULL
, *value
;
1723 value
= hashmap_get2(device
->sysattr_values
, _key
, (void **) &key
);
1733 /* We cache all sysattr lookups. If an attribute does not exist, it is stored
1734 * with a NULL value in the cache, otherwise the returned string is stored */
1735 _public_
int sd_device_get_sysattr_value(sd_device
*device
, const char *sysattr
, const char **_value
) {
1736 _cleanup_free_
char *value
= NULL
;
1737 const char *syspath
, *cached_value
= NULL
;
1739 struct stat statbuf
;
1742 assert_return(device
, -EINVAL
);
1743 assert_return(sysattr
, -EINVAL
);
1745 /* look for possibly already cached result */
1746 r
= device_get_sysattr_value(device
, sysattr
, &cached_value
);
1752 /* we looked up the sysattr before and it did not exist */
1756 *_value
= cached_value
;
1761 r
= sd_device_get_syspath(device
, &syspath
);
1765 path
= strjoina(syspath
, "/", sysattr
);
1766 r
= lstat(path
, &statbuf
);
1768 /* remember that we could not access the sysattr */
1769 r
= device_add_sysattr_value(device
, sysattr
, NULL
);
1774 } else if (S_ISLNK(statbuf
.st_mode
)) {
1775 /* Some core links return only the last element of the target path,
1776 * these are just values, the paths should not be exposed. */
1777 if (STR_IN_SET(sysattr
, "driver", "subsystem", "module")) {
1778 r
= readlink_value(path
, &value
);
1783 } else if (S_ISDIR(statbuf
.st_mode
)) {
1784 /* skip directories */
1786 } else if (!(statbuf
.st_mode
& S_IRUSR
)) {
1787 /* skip non-readable files */
1792 /* read attribute value */
1793 r
= read_full_file(path
, &value
, &size
);
1797 /* drop trailing newlines */
1798 while (size
> 0 && value
[--size
] == '\n')
1802 r
= device_add_sysattr_value(device
, sysattr
, value
);
1806 *_value
= TAKE_PTR(value
);
1811 static void device_remove_sysattr_value(sd_device
*device
, const char *_key
) {
1812 _cleanup_free_
char *key
= NULL
;
1813 _cleanup_free_
char *value
= NULL
;
1818 value
= hashmap_remove2(device
->sysattr_values
, _key
, (void **) &key
);
1823 /* set the attribute and save it in the cache. If a NULL value is passed the
1824 * attribute is cleared from the cache */
1825 _public_
int sd_device_set_sysattr_value(sd_device
*device
, const char *sysattr
, char *_value
) {
1826 _cleanup_close_
int fd
= -1;
1827 _cleanup_free_
char *value
= NULL
;
1828 const char *syspath
;
1834 assert_return(device
, -EINVAL
);
1835 assert_return(sysattr
, -EINVAL
);
1838 device_remove_sysattr_value(device
, sysattr
);
1843 r
= sd_device_get_syspath(device
, &syspath
);
1847 path
= strjoina(syspath
, "/", sysattr
);
1849 fd
= open(path
, O_WRONLY
| O_CLOEXEC
| O_NOFOLLOW
);
1853 if (errno
== EISDIR
)
1860 r
= device_add_sysattr_value(device
, sysattr
, value
);
1868 len
= strlen(_value
);
1870 /* drop trailing newlines */
1871 while (len
> 0 && _value
[len
- 1] == '\n')
1874 /* value length is limited to 4k */
1878 value
= strndup(_value
, len
);
1882 size
= write(fd
, value
, len
);
1886 if ((size_t)size
!= len
)
1889 r
= device_add_sysattr_value(device
, sysattr
, value
);