1 /* SPDX-License-Identifier: LGPL-2.1+ */
10 #include "alloc-util.h"
11 #include "device-internal.h"
12 #include "device-private.h"
13 #include "device-util.h"
14 #include "dirent-util.h"
20 #include "parse-util.h"
21 #include "path-util.h"
23 #include "socket-util.h"
24 #include "stat-util.h"
25 #include "string-util.h"
30 int device_new_aux(sd_device
**ret
) {
31 sd_device
*device
= NULL
;
35 device
= new(sd_device
, 1);
39 *device
= (sd_device
) {
42 .devmode
= (mode_t
) -1,
51 static sd_device
*device_free(sd_device
*device
) {
54 sd_device_unref(device
->parent
);
55 free(device
->syspath
);
56 free(device
->sysname
);
57 free(device
->devtype
);
58 free(device
->devname
);
59 free(device
->subsystem
);
60 free(device
->driver_subsystem
);
62 free(device
->id_filename
);
63 free(device
->properties_strv
);
64 free(device
->properties_nulstr
);
66 ordered_hashmap_free_free_free(device
->properties
);
67 ordered_hashmap_free_free_free(device
->properties_db
);
68 hashmap_free_free_free(device
->sysattr_values
);
69 set_free_free(device
->sysattrs
);
70 set_free_free(device
->tags
);
71 set_free_free(device
->devlinks
);
76 DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_device
, sd_device
, device_free
);
78 int device_add_property_aux(sd_device
*device
, const char *_key
, const char *_value
, bool db
) {
79 OrderedHashmap
**properties
;
85 properties
= &device
->properties_db
;
87 properties
= &device
->properties
;
90 _cleanup_free_
char *key
= NULL
, *value
= NULL
, *old_key
= NULL
, *old_value
= NULL
;
93 r
= ordered_hashmap_ensure_allocated(properties
, &string_hash_ops
);
101 value
= strdup(_value
);
105 old_value
= ordered_hashmap_get2(*properties
, key
, (void**) &old_key
);
107 r
= ordered_hashmap_replace(*properties
, key
, value
);
114 _cleanup_free_
char *key
= NULL
;
115 _cleanup_free_
char *value
= NULL
;
117 value
= ordered_hashmap_remove2(*properties
, _key
, (void**) &key
);
121 device
->properties_generation
++;
122 device
->properties_buf_outdated
= true;
128 int device_add_property_internal(sd_device
*device
, const char *key
, const char *value
) {
129 return device_add_property_aux(device
, key
, value
, false);
132 int device_set_syspath(sd_device
*device
, const char *_syspath
, bool verify
) {
133 _cleanup_free_
char *syspath
= NULL
;
140 /* must be a subdirectory of /sys */
141 if (!path_startswith(_syspath
, "/sys/"))
142 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL
),
143 "sd-device: Syspath '%s' is not a subdirectory of /sys",
147 r
= chase_symlinks(_syspath
, NULL
, 0, &syspath
);
149 return -ENODEV
; /* the device does not exist (any more?) */
151 return log_debug_errno(r
, "sd-device: Failed to get target of '%s': %m", _syspath
);
153 if (!path_startswith(syspath
, "/sys")) {
154 _cleanup_free_
char *real_sys
= NULL
, *new_syspath
= NULL
;
157 /* /sys is a symlink to somewhere sysfs is mounted on? In that case, we convert the path to real sysfs to "/sys". */
158 r
= chase_symlinks("/sys", NULL
, 0, &real_sys
);
160 return log_debug_errno(r
, "sd-device: Failed to chase symlink /sys: %m");
162 p
= path_startswith(syspath
, real_sys
);
164 return log_debug_errno(SYNTHETIC_ERRNO(ENODEV
),
165 "sd-device: Canonicalized path '%s' does not starts with sysfs mount point '%s'",
168 new_syspath
= strjoin("/sys/", p
);
172 free_and_replace(syspath
, new_syspath
);
173 path_simplify(syspath
, false);
176 if (path_startswith(syspath
, "/sys/devices/")) {
179 /* all 'devices' require an 'uevent' file */
180 path
= strjoina(syspath
, "/uevent");
181 r
= access(path
, F_OK
);
184 /* this is not a valid device */
187 return log_debug_errno(errno
, "sd-device: %s does not have an uevent file: %m", syspath
);
190 /* everything else just needs to be a directory */
191 if (!is_dir(syspath
, false))
195 syspath
= strdup(_syspath
);
200 devpath
= syspath
+ STRLEN("/sys");
202 r
= device_add_property_internal(device
, "DEVPATH", devpath
);
206 free_and_replace(device
->syspath
, syspath
);
208 device
->devpath
= devpath
;
213 _public_
int sd_device_new_from_syspath(sd_device
**ret
, const char *syspath
) {
214 _cleanup_(sd_device_unrefp
) sd_device
*device
= NULL
;
217 assert_return(ret
, -EINVAL
);
218 assert_return(syspath
, -EINVAL
);
220 r
= device_new_aux(&device
);
224 r
= device_set_syspath(device
, syspath
, true);
228 *ret
= TAKE_PTR(device
);
233 _public_
int sd_device_new_from_devnum(sd_device
**ret
, char type
, dev_t devnum
) {
235 char id
[DECIMAL_STR_MAX(unsigned) * 2 + 1];
237 assert_return(ret
, -EINVAL
);
238 assert_return(IN_SET(type
, 'b', 'c'), -EINVAL
);
240 /* use /sys/dev/{block,char}/<maj>:<min> link */
241 snprintf(id
, sizeof(id
), "%u:%u", major(devnum
), minor(devnum
));
243 syspath
= strjoina("/sys/dev/", (type
== 'b' ? "block" : "char"), "/", id
);
245 return sd_device_new_from_syspath(ret
, syspath
);
248 _public_
int sd_device_new_from_subsystem_sysname(sd_device
**ret
, const char *subsystem
, const char *sysname
) {
249 char *name
, *syspath
;
252 assert_return(ret
, -EINVAL
);
253 assert_return(subsystem
, -EINVAL
);
254 assert_return(sysname
, -EINVAL
);
256 if (streq(subsystem
, "subsystem")) {
257 syspath
= strjoina("/sys/subsystem/", sysname
);
258 if (access(syspath
, F_OK
) >= 0)
259 return sd_device_new_from_syspath(ret
, syspath
);
261 syspath
= strjoina("/sys/bus/", sysname
);
262 if (access(syspath
, F_OK
) >= 0)
263 return sd_device_new_from_syspath(ret
, syspath
);
265 syspath
= strjoina("/sys/class/", sysname
);
266 if (access(syspath
, F_OK
) >= 0)
267 return sd_device_new_from_syspath(ret
, syspath
);
268 } else if (streq(subsystem
, "module")) {
269 syspath
= strjoina("/sys/module/", sysname
);
270 if (access(syspath
, F_OK
) >= 0)
271 return sd_device_new_from_syspath(ret
, syspath
);
272 } else if (streq(subsystem
, "drivers")) {
273 char subsys
[PATH_MAX
];
276 strscpy(subsys
, sizeof(subsys
), sysname
);
277 driver
= strchr(subsys
, ':');
282 syspath
= strjoina("/sys/subsystem/", subsys
, "/drivers/", driver
);
283 if (access(syspath
, F_OK
) >= 0)
284 return sd_device_new_from_syspath(ret
, syspath
);
286 syspath
= strjoina("/sys/bus/", subsys
, "/drivers/", driver
);
287 if (access(syspath
, F_OK
) >= 0)
288 return sd_device_new_from_syspath(ret
, syspath
);
292 /* translate sysname back to sysfs filename */
293 name
= strdupa(sysname
);
294 while (name
[len
] != '\0') {
295 if (name
[len
] == '/')
301 syspath
= strjoina("/sys/subsystem/", subsystem
, "/devices/", name
);
302 if (access(syspath
, F_OK
) >= 0)
303 return sd_device_new_from_syspath(ret
, syspath
);
305 syspath
= strjoina("/sys/bus/", subsystem
, "/devices/", name
);
306 if (access(syspath
, F_OK
) >= 0)
307 return sd_device_new_from_syspath(ret
, syspath
);
309 syspath
= strjoina("/sys/class/", subsystem
, "/", name
);
310 if (access(syspath
, F_OK
) >= 0)
311 return sd_device_new_from_syspath(ret
, syspath
);
313 syspath
= strjoina("/sys/firmware/", subsystem
, "/", sysname
);
314 if (access(syspath
, F_OK
) >= 0)
315 return sd_device_new_from_syspath(ret
, syspath
);
320 int device_set_devtype(sd_device
*device
, const char *_devtype
) {
321 _cleanup_free_
char *devtype
= NULL
;
327 devtype
= strdup(_devtype
);
331 r
= device_add_property_internal(device
, "DEVTYPE", devtype
);
335 free_and_replace(device
->devtype
, devtype
);
340 int device_set_ifindex(sd_device
*device
, const char *_ifindex
) {
346 r
= parse_ifindex(_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_and_replace(device
->devname
, devname
);
385 int device_set_devmode(sd_device
*device
, const char *_devmode
) {
392 r
= safe_atou(_devmode
, &devmode
);
399 r
= device_add_property_internal(device
, "DEVMODE", _devmode
);
403 device
->devmode
= devmode
;
408 int device_set_devnum(sd_device
*device
, const char *major
, const char *minor
) {
409 unsigned maj
= 0, min
= 0;
415 r
= safe_atou(major
, &maj
);
422 r
= safe_atou(minor
, &min
);
427 r
= device_add_property_internal(device
, "MAJOR", major
);
432 r
= device_add_property_internal(device
, "MINOR", minor
);
437 device
->devnum
= makedev(maj
, min
);
442 static int handle_uevent_line(sd_device
*device
, const char *key
, const char *value
, const char **major
, const char **minor
) {
451 if (streq(key
, "DEVTYPE")) {
452 r
= device_set_devtype(device
, value
);
455 } else if (streq(key
, "IFINDEX")) {
456 r
= device_set_ifindex(device
, value
);
459 } else if (streq(key
, "DEVNAME")) {
460 r
= device_set_devname(device
, value
);
463 } else if (streq(key
, "DEVMODE")) {
464 r
= device_set_devmode(device
, value
);
467 } else if (streq(key
, "MAJOR"))
469 else if (streq(key
, "MINOR"))
472 r
= device_add_property_internal(device
, key
, value
);
480 int device_read_uevent_file(sd_device
*device
) {
481 _cleanup_free_
char *uevent
= NULL
;
482 const char *syspath
, *key
= NULL
, *value
= NULL
, *major
= NULL
, *minor
= NULL
;
498 if (device
->uevent_loaded
|| device
->sealed
)
501 device
->uevent_loaded
= true;
503 r
= sd_device_get_syspath(device
, &syspath
);
507 path
= strjoina(syspath
, "/uevent");
509 r
= read_full_file(path
, &uevent
, &uevent_len
);
511 /* empty uevent files may be write-only */
513 else if (r
== -ENOENT
)
514 /* some devices may not have uevent files, see set_syspath() */
517 return log_device_debug_errno(device
, r
, "sd-device: Failed to read uevent file '%s': %m", path
);
519 for (i
= 0; i
< uevent_len
; i
++)
522 if (!strchr(NEWLINE
, uevent
[i
])) {
530 if (uevent
[i
] == '=') {
534 } else if (strchr(NEWLINE
, uevent
[i
])) {
536 log_device_debug(device
, "sd-device: Invalid uevent line '%s', ignoring", key
);
546 _fallthrough_
; /* to handle empty property */
548 if (strchr(NEWLINE
, uevent
[i
])) {
551 r
= handle_uevent_line(device
, key
, value
, &major
, &minor
);
553 log_device_debug_errno(device
, r
, "sd-device: Failed to handle uevent entry '%s=%s', ignoring: %m", key
, value
);
560 assert_not_reached("Invalid state when parsing uevent file");
564 r
= device_set_devnum(device
, major
, minor
);
566 log_device_debug_errno(device
, r
, "sd-device: Failed to set 'MAJOR=%s' or 'MINOR=%s' from '%s', ignoring: %m", major
, minor
, path
);
572 _public_
int sd_device_get_ifindex(sd_device
*device
, int *ifindex
) {
575 assert_return(device
, -EINVAL
);
577 r
= device_read_uevent_file(device
);
581 if (device
->ifindex
<= 0)
585 *ifindex
= device
->ifindex
;
590 _public_
int sd_device_new_from_device_id(sd_device
**ret
, const char *id
) {
593 assert_return(ret
, -EINVAL
);
594 assert_return(id
, -EINVAL
);
604 r
= parse_dev(id
+ 1, &devt
);
608 return sd_device_new_from_devnum(ret
, id
[0], devt
);
612 _cleanup_(sd_device_unrefp
) sd_device
*device
= NULL
;
613 _cleanup_close_
int sk
= -1;
614 struct ifreq ifr
= {};
617 r
= parse_ifindex(&id
[1], &ifr
.ifr_ifindex
);
621 sk
= socket_ioctl_fd();
625 r
= ioctl(sk
, SIOCGIFNAME
, &ifr
);
629 r
= sd_device_new_from_subsystem_sysname(&device
, "net", ifr
.ifr_name
);
633 r
= sd_device_get_ifindex(device
, &ifindex
);
637 /* this is racey, so we might end up with the wrong device */
638 if (ifr
.ifr_ifindex
!= ifindex
)
641 *ret
= TAKE_PTR(device
);
647 char subsys
[PATH_MAX
];
650 (void) strscpy(subsys
, sizeof(subsys
), id
+ 1);
651 sysname
= strchr(subsys
, ':');
658 return sd_device_new_from_subsystem_sysname(ret
, subsys
, sysname
);
665 _public_
int sd_device_get_syspath(sd_device
*device
, const char **ret
) {
666 assert_return(device
, -EINVAL
);
667 assert_return(ret
, -EINVAL
);
669 assert(path_startswith(device
->syspath
, "/sys/"));
671 *ret
= device
->syspath
;
676 static int device_new_from_child(sd_device
**ret
, sd_device
*child
) {
677 _cleanup_free_
char *path
= NULL
;
678 const char *subdir
, *syspath
;
684 r
= sd_device_get_syspath(child
, &syspath
);
688 path
= strdup(syspath
);
691 subdir
= path
+ STRLEN("/sys");
696 pos
= strrchr(subdir
, '/');
697 if (!pos
|| pos
< subdir
+ 2)
702 r
= sd_device_new_from_syspath(ret
, path
);
712 _public_
int sd_device_get_parent(sd_device
*child
, sd_device
**ret
) {
714 assert_return(ret
, -EINVAL
);
715 assert_return(child
, -EINVAL
);
717 if (!child
->parent_set
) {
718 child
->parent_set
= true;
720 (void) device_new_from_child(&child
->parent
, child
);
726 *ret
= child
->parent
;
731 int device_set_subsystem(sd_device
*device
, const char *_subsystem
) {
732 _cleanup_free_
char *subsystem
= NULL
;
738 subsystem
= strdup(_subsystem
);
742 r
= device_add_property_internal(device
, "SUBSYSTEM", subsystem
);
746 free_and_replace(device
->subsystem
, subsystem
);
748 device
->subsystem_set
= true;
753 static int device_set_drivers_subsystem(sd_device
*device
, const char *_subsystem
) {
754 _cleanup_free_
char *subsystem
= NULL
;
761 subsystem
= strdup(_subsystem
);
765 r
= device_set_subsystem(device
, "drivers");
769 free_and_replace(device
->driver_subsystem
, subsystem
);
774 _public_
int sd_device_get_subsystem(sd_device
*device
, const char **ret
) {
775 const char *syspath
, *drivers
= NULL
;
778 assert_return(ret
, -EINVAL
);
779 assert_return(device
, -EINVAL
);
781 r
= sd_device_get_syspath(device
, &syspath
);
785 if (!device
->subsystem_set
) {
786 _cleanup_free_
char *subsystem
= NULL
;
789 /* read 'subsystem' link */
790 path
= strjoina(syspath
, "/subsystem");
791 r
= readlink_value(path
, &subsystem
);
793 r
= device_set_subsystem(device
, subsystem
);
794 /* use implicit names */
795 else if (path_startswith(device
->devpath
, "/module/"))
796 r
= device_set_subsystem(device
, "module");
797 else if (!(drivers
= strstr(syspath
, "/drivers/")) &&
798 PATH_STARTSWITH_SET(device
->devpath
, "/subsystem/",
801 r
= device_set_subsystem(device
, "subsystem");
802 if (r
< 0 && r
!= -ENOENT
)
803 return log_device_debug_errno(device
, r
, "sd-device: Failed to set subsystem for %s: %m", device
->devpath
);
805 device
->subsystem_set
= true;
806 } else if (!device
->driver_subsystem_set
)
807 drivers
= strstr(syspath
, "/drivers/");
809 if (!device
->driver_subsystem_set
) {
811 _cleanup_free_
char *subpath
= NULL
;
813 subpath
= strndup(syspath
, drivers
- syspath
);
819 subsys
= strrchr(subpath
, '/');
823 r
= device_set_drivers_subsystem(device
, subsys
+ 1);
825 if (r
< 0 && r
!= -ENOENT
)
826 return log_device_debug_errno(device
, r
, "sd-device: Failed to set subsystem for driver %s: %m", device
->devpath
);
829 device
->driver_subsystem_set
= true;
832 if (!device
->subsystem
)
835 *ret
= device
->subsystem
;
840 _public_
int sd_device_get_devtype(sd_device
*device
, const char **devtype
) {
846 r
= device_read_uevent_file(device
);
850 if (!device
->devtype
)
853 *devtype
= device
->devtype
;
858 _public_
int sd_device_get_parent_with_subsystem_devtype(sd_device
*child
, const char *subsystem
, const char *devtype
, sd_device
**ret
) {
859 sd_device
*parent
= NULL
;
862 assert_return(child
, -EINVAL
);
863 assert_return(subsystem
, -EINVAL
);
865 r
= sd_device_get_parent(child
, &parent
);
867 const char *parent_subsystem
= NULL
;
868 const char *parent_devtype
= NULL
;
870 (void) sd_device_get_subsystem(parent
, &parent_subsystem
);
871 if (streq_ptr(parent_subsystem
, subsystem
)) {
875 (void) sd_device_get_devtype(parent
, &parent_devtype
);
876 if (streq_ptr(parent_devtype
, devtype
))
879 r
= sd_device_get_parent(parent
, &parent
);
890 _public_
int sd_device_get_devnum(sd_device
*device
, dev_t
*devnum
) {
893 assert_return(device
, -EINVAL
);
895 r
= device_read_uevent_file(device
);
899 if (major(device
->devnum
) <= 0)
903 *devnum
= device
->devnum
;
908 int device_set_driver(sd_device
*device
, const char *_driver
) {
909 _cleanup_free_
char *driver
= NULL
;
915 driver
= strdup(_driver
);
919 r
= device_add_property_internal(device
, "DRIVER", driver
);
923 free_and_replace(device
->driver
, driver
);
925 device
->driver_set
= true;
930 _public_
int sd_device_get_driver(sd_device
*device
, const char **ret
) {
931 assert_return(device
, -EINVAL
);
932 assert_return(ret
, -EINVAL
);
934 if (!device
->driver_set
) {
935 _cleanup_free_
char *driver
= NULL
;
940 r
= sd_device_get_syspath(device
, &syspath
);
944 path
= strjoina(syspath
, "/driver");
945 r
= readlink_value(path
, &driver
);
947 r
= device_set_driver(device
, driver
);
949 return log_device_debug_errno(device
, r
, "sd-device: Failed to set driver for %s: %m", device
->devpath
);
950 } else if (r
== -ENOENT
)
951 device
->driver_set
= true;
953 return log_device_debug_errno(device
, r
, "sd-device: Failed to set driver for %s: %m", device
->devpath
);
959 *ret
= device
->driver
;
964 _public_
int sd_device_get_devpath(sd_device
*device
, const char **devpath
) {
965 assert_return(device
, -EINVAL
);
966 assert_return(devpath
, -EINVAL
);
968 assert(device
->devpath
);
969 assert(device
->devpath
[0] == '/');
971 *devpath
= device
->devpath
;
976 _public_
int sd_device_get_devname(sd_device
*device
, const char **devname
) {
979 assert_return(device
, -EINVAL
);
980 assert_return(devname
, -EINVAL
);
982 r
= device_read_uevent_file(device
);
986 if (!device
->devname
)
989 assert(path_startswith(device
->devname
, "/dev/"));
991 *devname
= device
->devname
;
996 static int device_set_sysname(sd_device
*device
) {
997 _cleanup_free_
char *sysname
= NULL
;
998 const char *sysnum
= NULL
;
1002 pos
= strrchr(device
->devpath
, '/');
1007 /* devpath is not a root directory */
1008 if (*pos
== '\0' || pos
<= device
->devpath
)
1011 sysname
= strdup(pos
);
1015 /* some devices have '!' in their name, change that to '/' */
1016 while (sysname
[len
] != '\0') {
1017 if (sysname
[len
] == '!')
1023 /* trailing number */
1024 while (len
> 0 && isdigit(sysname
[--len
]))
1025 sysnum
= &sysname
[len
];
1030 free_and_replace(device
->sysname
, sysname
);
1032 device
->sysnum
= sysnum
;
1034 device
->sysname_set
= true;
1039 _public_
int sd_device_get_sysname(sd_device
*device
, const char **ret
) {
1042 assert_return(device
, -EINVAL
);
1043 assert_return(ret
, -EINVAL
);
1045 if (!device
->sysname_set
) {
1046 r
= device_set_sysname(device
);
1051 assert_return(device
->sysname
, -ENOENT
);
1053 *ret
= device
->sysname
;
1058 _public_
int sd_device_get_sysnum(sd_device
*device
, const char **ret
) {
1061 assert_return(device
, -EINVAL
);
1062 assert_return(ret
, -EINVAL
);
1064 if (!device
->sysname_set
) {
1065 r
= device_set_sysname(device
);
1070 if (!device
->sysnum
)
1073 *ret
= device
->sysnum
;
1078 static bool is_valid_tag(const char *tag
) {
1081 return !strchr(tag
, ':') && !strchr(tag
, ' ');
1084 int device_add_tag(sd_device
*device
, const char *tag
) {
1090 if (!is_valid_tag(tag
))
1093 r
= set_ensure_allocated(&device
->tags
, &string_hash_ops
);
1097 r
= set_put_strdup(device
->tags
, tag
);
1101 device
->tags_generation
++;
1102 device
->property_tags_outdated
= true;
1107 int device_add_devlink(sd_device
*device
, const char *devlink
) {
1113 r
= set_ensure_allocated(&device
->devlinks
, &string_hash_ops
);
1117 r
= set_put_strdup(device
->devlinks
, devlink
);
1121 device
->devlinks_generation
++;
1122 device
->property_devlinks_outdated
= true;
1127 static int device_add_property_internal_from_string(sd_device
*device
, const char *str
) {
1128 _cleanup_free_
char *key
= NULL
;
1138 value
= strchr(key
, '=');
1144 if (isempty(++value
))
1147 return device_add_property_internal(device
, key
, value
);
1150 int device_set_usec_initialized(sd_device
*device
, const char *initialized
) {
1151 uint64_t usec_initialized
;
1155 assert(initialized
);
1157 r
= safe_atou64(initialized
, &usec_initialized
);
1161 r
= device_add_property_internal(device
, "USEC_INITIALIZED", initialized
);
1165 device
->usec_initialized
= usec_initialized
;
1170 static int handle_db_line(sd_device
*device
, char key
, const char *value
) {
1179 r
= device_add_tag(device
, value
);
1185 path
= strjoina("/dev/", value
);
1186 r
= device_add_devlink(device
, path
);
1192 r
= device_add_property_internal_from_string(device
, value
);
1198 r
= device_set_usec_initialized(device
, value
);
1204 r
= safe_atoi(value
, &device
->devlink_priority
);
1210 r
= safe_atoi(value
, &device
->watch_handle
);
1216 log_device_debug(device
, "sd-device: Unknown key '%c' in device db, ignoring", key
);
1222 int device_get_id_filename(sd_device
*device
, const char **ret
) {
1226 if (!device
->id_filename
) {
1227 _cleanup_free_
char *id
= NULL
;
1228 const char *subsystem
;
1232 r
= sd_device_get_subsystem(device
, &subsystem
);
1236 if (sd_device_get_devnum(device
, &devnum
) >= 0) {
1239 /* use dev_t — b259:131072, c254:0 */
1240 r
= asprintf(&id
, "%c%u:%u",
1241 streq(subsystem
, "block") ? 'b' : 'c',
1242 major(devnum
), minor(devnum
));
1245 } else if (sd_device_get_ifindex(device
, &ifindex
) >= 0) {
1246 /* use netdev ifindex — n3 */
1247 r
= asprintf(&id
, "n%u", (unsigned) ifindex
);
1251 /* use $subsys:$sysname — pci:0000:00:1f.2
1252 * sysname() has '!' translated, get it from devpath
1254 const char *sysname
;
1256 sysname
= basename(device
->devpath
);
1263 if (streq(subsystem
, "drivers")) {
1264 /* the 'drivers' pseudo-subsystem is special, and needs the real subsystem
1265 * encoded as well */
1266 r
= asprintf(&id
, "+drivers:%s:%s", device
->driver_subsystem
, sysname
);
1270 r
= asprintf(&id
, "+%s:%s", subsystem
, sysname
);
1276 device
->id_filename
= TAKE_PTR(id
);
1279 *ret
= device
->id_filename
;
1284 int device_read_db_aux(sd_device
*device
, bool force
) {
1285 _cleanup_free_
char *db
= NULL
;
1287 const char *id
, *value
;
1301 if (device
->db_loaded
|| (!force
&& device
->sealed
))
1304 device
->db_loaded
= true;
1306 r
= device_get_id_filename(device
, &id
);
1310 path
= strjoina("/run/udev/data/", id
);
1312 r
= read_full_file(path
, &db
, &db_len
);
1317 return log_device_debug_errno(device
, r
, "sd-device: Failed to read db '%s': %m", path
);
1320 /* devices with a database entry are initialized */
1321 device
->is_initialized
= true;
1323 for (i
= 0; i
< db_len
; i
++) {
1326 if (!strchr(NEWLINE
, db
[i
])) {
1335 log_device_debug(device
, "sd-device: Invalid db entry with key '%c', ignoring", key
);
1337 state
= INVALID_LINE
;
1352 if (strchr(NEWLINE
, db
[i
]))
1357 if (strchr(NEWLINE
, db
[i
])) {
1359 r
= handle_db_line(device
, key
, value
);
1361 log_device_debug_errno(device
, r
, "sd-device: Failed to handle db entry '%c:%s', ignoring: %m", key
, value
);
1368 assert_not_reached("Invalid state when parsing db");
1375 static int device_read_db(sd_device
*device
) {
1376 return device_read_db_aux(device
, false);
1379 _public_
int sd_device_get_is_initialized(sd_device
*device
) {
1382 assert_return(device
, -EINVAL
);
1384 r
= device_read_db(device
);
1388 return device
->is_initialized
;
1391 _public_
int sd_device_get_usec_since_initialized(sd_device
*device
, uint64_t *usec
) {
1395 assert_return(device
, -EINVAL
);
1396 assert_return(usec
, -EINVAL
);
1398 r
= device_read_db(device
);
1402 if (!device
->is_initialized
)
1405 if (!device
->usec_initialized
)
1408 now_ts
= now(clock_boottime_or_monotonic());
1410 if (now_ts
< device
->usec_initialized
)
1413 *usec
= now_ts
- device
->usec_initialized
;
1418 _public_
const char *sd_device_get_tag_first(sd_device
*device
) {
1421 assert_return(device
, NULL
);
1423 (void) device_read_db(device
);
1425 device
->tags_iterator_generation
= device
->tags_generation
;
1426 device
->tags_iterator
= ITERATOR_FIRST
;
1428 (void) set_iterate(device
->tags
, &device
->tags_iterator
, &v
);
1432 _public_
const char *sd_device_get_tag_next(sd_device
*device
) {
1435 assert_return(device
, NULL
);
1437 (void) device_read_db(device
);
1439 if (device
->tags_iterator_generation
!= device
->tags_generation
)
1442 (void) set_iterate(device
->tags
, &device
->tags_iterator
, &v
);
1446 _public_
const char *sd_device_get_devlink_first(sd_device
*device
) {
1449 assert_return(device
, NULL
);
1451 (void) device_read_db(device
);
1453 device
->devlinks_iterator_generation
= device
->devlinks_generation
;
1454 device
->devlinks_iterator
= ITERATOR_FIRST
;
1456 (void) set_iterate(device
->devlinks
, &device
->devlinks_iterator
, &v
);
1460 _public_
const char *sd_device_get_devlink_next(sd_device
*device
) {
1463 assert_return(device
, NULL
);
1465 (void) device_read_db(device
);
1467 if (device
->devlinks_iterator_generation
!= device
->devlinks_generation
)
1470 (void) set_iterate(device
->devlinks
, &device
->devlinks_iterator
, &v
);
1474 static int device_properties_prepare(sd_device
*device
) {
1479 r
= device_read_uevent_file(device
);
1483 r
= device_read_db(device
);
1487 if (device
->property_devlinks_outdated
) {
1488 _cleanup_free_
char *devlinks
= NULL
;
1489 size_t devlinks_allocated
= 0, devlinks_len
= 0;
1490 const char *devlink
;
1492 for (devlink
= sd_device_get_devlink_first(device
); devlink
; devlink
= sd_device_get_devlink_next(device
)) {
1495 if (!GREEDY_REALLOC(devlinks
, devlinks_allocated
, devlinks_len
+ strlen(devlink
) + 2))
1497 if (devlinks_len
> 0)
1498 stpcpy(devlinks
+ devlinks_len
++, " ");
1499 e
= stpcpy(devlinks
+ devlinks_len
, devlink
);
1500 devlinks_len
= e
- devlinks
;
1503 r
= device_add_property_internal(device
, "DEVLINKS", devlinks
);
1507 device
->property_devlinks_outdated
= false;
1510 if (device
->property_tags_outdated
) {
1511 _cleanup_free_
char *tags
= NULL
;
1512 size_t tags_allocated
= 0, tags_len
= 0;
1515 if (!GREEDY_REALLOC(tags
, tags_allocated
, 2))
1520 for (tag
= sd_device_get_tag_first(device
); tag
; tag
= sd_device_get_tag_next(device
)) {
1523 if (!GREEDY_REALLOC(tags
, tags_allocated
, tags_len
+ strlen(tag
) + 2))
1525 e
= stpcpy(stpcpy(tags
+ tags_len
, tag
), ":");
1526 tags_len
= e
- tags
;
1529 r
= device_add_property_internal(device
, "TAGS", tags
);
1533 device
->property_tags_outdated
= false;
1539 _public_
const char *sd_device_get_property_first(sd_device
*device
, const char **_value
) {
1544 assert_return(device
, NULL
);
1546 r
= device_properties_prepare(device
);
1550 device
->properties_iterator_generation
= device
->properties_generation
;
1551 device
->properties_iterator
= ITERATOR_FIRST
;
1553 ordered_hashmap_iterate(device
->properties
, &device
->properties_iterator
, (void**)&value
, (const void**)&key
);
1561 _public_
const char *sd_device_get_property_next(sd_device
*device
, const char **_value
) {
1566 assert_return(device
, NULL
);
1568 r
= device_properties_prepare(device
);
1572 if (device
->properties_iterator_generation
!= device
->properties_generation
)
1575 ordered_hashmap_iterate(device
->properties
, &device
->properties_iterator
, (void**)&value
, (const void**)&key
);
1583 static int device_sysattrs_read_all(sd_device
*device
) {
1584 _cleanup_closedir_
DIR *dir
= NULL
;
1585 const char *syspath
;
1586 struct dirent
*dent
;
1591 if (device
->sysattrs_read
)
1594 r
= sd_device_get_syspath(device
, &syspath
);
1598 dir
= opendir(syspath
);
1602 r
= set_ensure_allocated(&device
->sysattrs
, &string_hash_ops
);
1606 FOREACH_DIRENT_ALL(dent
, dir
, return -errno
) {
1608 struct stat statbuf
;
1610 /* only handle symlinks and regular files */
1611 if (!IN_SET(dent
->d_type
, DT_LNK
, DT_REG
))
1614 path
= strjoina(syspath
, "/", dent
->d_name
);
1616 if (lstat(path
, &statbuf
) != 0)
1619 if (!(statbuf
.st_mode
& S_IRUSR
))
1622 r
= set_put_strdup(device
->sysattrs
, dent
->d_name
);
1627 device
->sysattrs_read
= true;
1632 _public_
const char *sd_device_get_sysattr_first(sd_device
*device
) {
1636 assert_return(device
, NULL
);
1638 if (!device
->sysattrs_read
) {
1639 r
= device_sysattrs_read_all(device
);
1646 device
->sysattrs_iterator
= ITERATOR_FIRST
;
1648 (void) set_iterate(device
->sysattrs
, &device
->sysattrs_iterator
, &v
);
1652 _public_
const char *sd_device_get_sysattr_next(sd_device
*device
) {
1655 assert_return(device
, NULL
);
1657 if (!device
->sysattrs_read
)
1660 (void) set_iterate(device
->sysattrs
, &device
->sysattrs_iterator
, &v
);
1664 _public_
int sd_device_has_tag(sd_device
*device
, const char *tag
) {
1665 assert_return(device
, -EINVAL
);
1666 assert_return(tag
, -EINVAL
);
1668 (void) device_read_db(device
);
1670 return !!set_contains(device
->tags
, tag
);
1673 _public_
int sd_device_get_property_value(sd_device
*device
, const char *key
, const char **_value
) {
1677 assert_return(device
, -EINVAL
);
1678 assert_return(key
, -EINVAL
);
1680 r
= device_properties_prepare(device
);
1684 value
= ordered_hashmap_get(device
->properties
, key
);
1694 /* replaces the value if it already exists */
1695 static int device_add_sysattr_value(sd_device
*device
, const char *_key
, char *value
) {
1696 _cleanup_free_
char *key
= NULL
;
1697 _cleanup_free_
char *value_old
= NULL
;
1703 r
= hashmap_ensure_allocated(&device
->sysattr_values
, &string_hash_ops
);
1707 value_old
= hashmap_remove2(device
->sysattr_values
, _key
, (void **)&key
);
1714 r
= hashmap_put(device
->sysattr_values
, key
, value
);
1723 static int device_get_sysattr_value(sd_device
*device
, const char *_key
, const char **_value
) {
1724 const char *key
= NULL
, *value
;
1729 value
= hashmap_get2(device
->sysattr_values
, _key
, (void **) &key
);
1739 /* We cache all sysattr lookups. If an attribute does not exist, it is stored
1740 * with a NULL value in the cache, otherwise the returned string is stored */
1741 _public_
int sd_device_get_sysattr_value(sd_device
*device
, const char *sysattr
, const char **_value
) {
1742 _cleanup_free_
char *value
= NULL
;
1743 const char *syspath
, *cached_value
= NULL
;
1745 struct stat statbuf
;
1748 assert_return(device
, -EINVAL
);
1749 assert_return(sysattr
, -EINVAL
);
1751 /* look for possibly already cached result */
1752 r
= device_get_sysattr_value(device
, sysattr
, &cached_value
);
1758 /* we looked up the sysattr before and it did not exist */
1762 *_value
= cached_value
;
1767 r
= sd_device_get_syspath(device
, &syspath
);
1771 path
= strjoina(syspath
, "/", sysattr
);
1772 r
= lstat(path
, &statbuf
);
1774 /* remember that we could not access the sysattr */
1775 r
= device_add_sysattr_value(device
, sysattr
, NULL
);
1780 } else if (S_ISLNK(statbuf
.st_mode
)) {
1781 /* Some core links return only the last element of the target path,
1782 * these are just values, the paths should not be exposed. */
1783 if (STR_IN_SET(sysattr
, "driver", "subsystem", "module")) {
1784 r
= readlink_value(path
, &value
);
1789 } else if (S_ISDIR(statbuf
.st_mode
)) {
1790 /* skip directories */
1792 } else if (!(statbuf
.st_mode
& S_IRUSR
)) {
1793 /* skip non-readable files */
1798 /* read attribute value */
1799 r
= read_full_file(path
, &value
, &size
);
1803 /* drop trailing newlines */
1804 while (size
> 0 && value
[--size
] == '\n')
1808 r
= device_add_sysattr_value(device
, sysattr
, value
);
1812 *_value
= TAKE_PTR(value
);
1817 static void device_remove_sysattr_value(sd_device
*device
, const char *_key
) {
1818 _cleanup_free_
char *key
= NULL
;
1819 _cleanup_free_
char *value
= NULL
;
1824 value
= hashmap_remove2(device
->sysattr_values
, _key
, (void **) &key
);
1829 /* set the attribute and save it in the cache. If a NULL value is passed the
1830 * attribute is cleared from the cache */
1831 _public_
int sd_device_set_sysattr_value(sd_device
*device
, const char *sysattr
, const char *_value
) {
1832 _cleanup_free_
char *value
= NULL
;
1833 const char *syspath
, *path
;
1837 assert_return(device
, -EINVAL
);
1838 assert_return(sysattr
, -EINVAL
);
1841 device_remove_sysattr_value(device
, sysattr
);
1846 r
= sd_device_get_syspath(device
, &syspath
);
1850 path
= strjoina(syspath
, "/", sysattr
);
1852 len
= strlen(_value
);
1854 /* drop trailing newlines */
1855 while (len
> 0 && _value
[len
- 1] == '\n')
1858 /* value length is limited to 4k */
1862 value
= strndup(_value
, len
);
1866 r
= write_string_file(path
, value
, WRITE_STRING_FILE_DISABLE_BUFFER
| WRITE_STRING_FILE_NOFOLLOW
);
1878 r
= device_add_sysattr_value(device
, sysattr
, value
);
1886 r
= device_add_sysattr_value(device
, sysattr
, value
);