2 This file is part of systemd.
4 Copyright 2008-2012 Kay Sievers <kay@vrfy.org>
5 Copyright 2014 Tom Gundersen <teg@jklm.no>
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
22 #include <sys/types.h>
27 #include "path-util.h"
34 #include "sd-device.h"
36 #include "device-util.h"
37 #include "device-private.h"
38 #include "device-internal.h"
40 int device_new_aux(sd_device
**ret
) {
41 _cleanup_device_unref_ sd_device
*device
= NULL
;
45 device
= new0(sd_device
, 1);
50 device
->watch_handle
= -1;
58 _public_ sd_device
*sd_device_ref(sd_device
*device
) {
60 assert_se(++ device
->n_ref
>= 2);
65 _public_ sd_device
*sd_device_unref(sd_device
*device
) {
66 if (device
&& -- device
->n_ref
== 0) {
67 sd_device_unref(device
->parent
);
68 free(device
->syspath
);
69 free(device
->sysname
);
70 free(device
->devtype
);
71 free(device
->devname
);
72 free(device
->subsystem
);
74 free(device
->id_filename
);
75 free(device
->properties_strv
);
76 free(device
->properties_nulstr
);
78 ordered_hashmap_free_free_free(device
->properties
);
79 ordered_hashmap_free_free_free(device
->properties_db
);
80 hashmap_free_free_free(device
->sysattr_values
);
81 set_free_free(device
->sysattrs
);
82 set_free_free(device
->tags
);
83 set_free_free(device
->devlinks
);
91 int device_add_property_aux(sd_device
*device
, const char *_key
, const char *_value
, bool db
) {
92 OrderedHashmap
**properties
;
98 properties
= &device
->properties_db
;
100 properties
= &device
->properties
;
103 _cleanup_free_
char *key
= NULL
, *value
= NULL
, *old_key
= NULL
, *old_value
= NULL
;
106 r
= ordered_hashmap_ensure_allocated(properties
, &string_hash_ops
);
114 value
= strdup(_value
);
118 old_value
= ordered_hashmap_get2(*properties
, key
, (void**) &old_key
);
120 r
= ordered_hashmap_replace(*properties
, key
, value
);
127 _cleanup_free_
char *key
= NULL
;
128 _cleanup_free_
char *value
= NULL
;
130 value
= ordered_hashmap_remove2(*properties
, _key
, (void**) &key
);
134 device
->properties_generation
++;
135 device
->properties_buf_outdated
= true;
141 int device_add_property_internal(sd_device
*device
, const char *key
, const char *value
) {
142 return device_add_property_aux(device
, key
, value
, false);
145 int device_set_syspath(sd_device
*device
, const char *_syspath
, bool verify
) {
146 _cleanup_free_
char *syspath
= NULL
;
153 /* must be a subdirectory of /sys */
154 if (!path_startswith(_syspath
, "/sys/")) {
155 log_debug("sd-device: syspath '%s' is not a subdirectory of /sys", _syspath
);
160 r
= readlink_and_canonicalize(_syspath
, &syspath
);
162 /* the device does not exist (any more?) */
164 else if (r
== -EINVAL
) {
166 syspath
= canonicalize_file_name(_syspath
);
169 /* the device does not exist (any more?) */
172 log_debug("sd-device: could not canonicalize '%s': %m", _syspath
);
176 log_debug("sd-device: could not get target of '%s': %s", _syspath
, strerror(-r
));
180 if (path_startswith(syspath
, "/sys/devices/")) {
183 /* all 'devices' require an 'uevent' file */
184 path
= strjoina(syspath
, "/uevent");
185 r
= access(path
, F_OK
);
188 /* this is not a valid device */
191 log_debug("sd-device: %s does not have an uevent file: %m", syspath
);
195 /* everything else just just needs to be a directory */
196 if (!is_dir(syspath
, false))
200 syspath
= strdup(_syspath
);
205 devpath
= syspath
+ strlen("/sys");
207 r
= device_add_property_internal(device
, "DEVPATH", devpath
);
211 free(device
->syspath
);
212 device
->syspath
= syspath
;
215 device
->devpath
= devpath
;
220 _public_
int sd_device_new_from_syspath(sd_device
**ret
, const char *syspath
) {
221 _cleanup_device_unref_ sd_device
*device
= NULL
;
224 assert_return(ret
, -EINVAL
);
225 assert_return(syspath
, -EINVAL
);
227 r
= device_new_aux(&device
);
231 r
= device_set_syspath(device
, syspath
, true);
241 _public_
int sd_device_new_from_devnum(sd_device
**ret
, char type
, dev_t devnum
) {
243 char id
[DECIMAL_STR_MAX(unsigned) * 2 + 1];
245 assert_return(ret
, -EINVAL
);
246 assert_return(type
== 'b' || type
== 'c', -EINVAL
);
248 /* use /sys/dev/{block,char}/<maj>:<min> link */
249 snprintf(id
, sizeof(id
), "%u:%u", major(devnum
), minor(devnum
));
251 syspath
= strjoina("/sys/dev/", (type
== 'b' ? "block" : "char"), "/", id
);
253 return sd_device_new_from_syspath(ret
, syspath
);
256 _public_
int sd_device_new_from_subsystem_sysname(sd_device
**ret
, const char *subsystem
, const char *sysname
) {
259 assert_return(ret
, -EINVAL
);
260 assert_return(subsystem
, -EINVAL
);
261 assert_return(sysname
, -EINVAL
);
263 if (streq(subsystem
, "subsystem")) {
264 syspath
= strjoina("/sys/subsystem/", sysname
);
265 if (access(syspath
, F_OK
) >= 0)
266 return sd_device_new_from_syspath(ret
, syspath
);
268 syspath
= strjoina("/sys/bus/", sysname
);
269 if (access(syspath
, F_OK
) >= 0)
270 return sd_device_new_from_syspath(ret
, syspath
);
272 syspath
= strjoina("/sys/class/", sysname
);
273 if (access(syspath
, F_OK
) >= 0)
274 return sd_device_new_from_syspath(ret
, syspath
);
275 } else if (streq(subsystem
, "module")) {
276 syspath
= strjoina("/sys/module/", sysname
);
277 if (access(syspath
, F_OK
) >= 0)
278 return sd_device_new_from_syspath(ret
, syspath
);
279 } else if (streq(subsystem
, "drivers")) {
280 char subsys
[PATH_MAX
];
283 strscpy(subsys
, sizeof(subsys
), sysname
);
284 driver
= strchr(subsys
, ':');
289 syspath
= strjoina("/sys/subsystem/", subsys
, "/drivers/", driver
);
290 if (access(syspath
, F_OK
) >= 0)
291 return sd_device_new_from_syspath(ret
, syspath
);
293 syspath
= strjoina("/sys/bus/", subsys
, "/drivers/", driver
);
294 if (access(syspath
, F_OK
) >= 0)
295 return sd_device_new_from_syspath(ret
, syspath
);
299 syspath
= strjoina("/sys/subsystem/", subsystem
, "/devices/", sysname
);
300 if (access(syspath
, F_OK
) >= 0)
301 return sd_device_new_from_syspath(ret
, syspath
);
303 syspath
= strjoina("/sys/bus/", subsystem
, "/devices/", sysname
);
304 if (access(syspath
, F_OK
) >= 0)
305 return sd_device_new_from_syspath(ret
, syspath
);
307 syspath
= strjoina("/sys/class/", subsystem
, "/", sysname
);
308 if (access(syspath
, F_OK
) >= 0)
309 return sd_device_new_from_syspath(ret
, syspath
);
315 int device_set_devtype(sd_device
*device
, const char *_devtype
) {
316 _cleanup_free_
char *devtype
= NULL
;
322 devtype
= strdup(_devtype
);
326 r
= device_add_property_internal(device
, "DEVTYPE", devtype
);
330 free(device
->devtype
);
331 device
->devtype
= devtype
;
337 int device_set_ifindex(sd_device
*device
, const char *_ifindex
) {
343 r
= safe_atoi(_ifindex
, &ifindex
);
350 r
= device_add_property_internal(device
, "IFINDEX", _ifindex
);
354 device
->ifindex
= ifindex
;
359 int device_set_devname(sd_device
*device
, const char *_devname
) {
360 _cleanup_free_
char *devname
= NULL
;
366 if (_devname
[0] != '/') {
367 r
= asprintf(&devname
, "/dev/%s", _devname
);
371 devname
= strdup(_devname
);
376 r
= device_add_property_internal(device
, "DEVNAME", devname
);
380 free(device
->devname
);
381 device
->devname
= devname
;
387 int device_set_devmode(sd_device
*device
, const char *_devmode
) {
394 r
= safe_atou(_devmode
, &devmode
);
401 r
= device_add_property_internal(device
, "DEVMODE", _devmode
);
405 device
->devmode
= devmode
;
410 int device_set_devnum(sd_device
*device
, const char *major
, const char *minor
) {
411 unsigned maj
= 0, min
= 0;
417 r
= safe_atou(major
, &maj
);
424 r
= safe_atou(minor
, &min
);
429 r
= device_add_property_internal(device
, "MAJOR", major
);
434 r
= device_add_property_internal(device
, "MINOR", minor
);
439 device
->devnum
= makedev(maj
, min
);
444 static int handle_uevent_line(sd_device
*device
, const char *key
, const char *value
, const char **major
, const char **minor
) {
453 if (streq(key
, "DEVTYPE")) {
454 r
= device_set_devtype(device
, value
);
457 } else if (streq(key
, "IFINDEX")) {
458 r
= device_set_ifindex(device
, value
);
461 } else if (streq(key
, "DEVNAME")) {
462 r
= device_set_devname(device
, value
);
465 } else if (streq(key
, "DEVMODE")) {
466 r
= device_set_devmode(device
, value
);
469 } else if (streq(key
, "MAJOR"))
471 else if (streq(key
, "MINOR"))
474 r
= device_add_property_internal(device
, key
, value
);
482 int device_read_uevent_file(sd_device
*device
) {
483 _cleanup_free_
char *uevent
= NULL
;
484 const char *syspath
, *key
, *value
, *major
= NULL
, *minor
= NULL
;
500 if (device
->uevent_loaded
|| device
->sealed
)
503 r
= sd_device_get_syspath(device
, &syspath
);
507 path
= strjoina(syspath
, "/uevent");
509 r
= read_full_file(path
, &uevent
, &uevent_len
);
511 /* empty uevent files may be write-only */
514 log_debug("sd-device: failed to read uevent file '%s': %s", path
, strerror(-r
));
518 for (i
= 0; i
< uevent_len
; i
++) {
521 if (!strchr(NEWLINE
, uevent
[i
])) {
529 if (uevent
[i
] == '=') {
533 } else if (strchr(NEWLINE
, uevent
[i
])) {
535 log_debug("sd-device: ignoring invalid uevent line '%s'", key
);
548 if (strchr(NEWLINE
, uevent
[i
])) {
551 r
= handle_uevent_line(device
, key
, value
, &major
, &minor
);
553 log_debug("sd-device: failed to handle uevent entry '%s=%s': %s", key
, value
, strerror(-r
));
560 assert_not_reached("invalid state when parsing uevent file");
565 r
= device_set_devnum(device
, major
, minor
);
567 log_debug("sd-device: could not set 'MAJOR=%s' or 'MINOR=%s' from '%s': %s", major
, minor
, path
, strerror(-r
));
570 device
->uevent_loaded
= true;
575 _public_
int sd_device_get_ifindex(sd_device
*device
, int *ifindex
) {
578 assert_return(device
, -EINVAL
);
579 assert_return(ifindex
, -EINVAL
);
581 r
= device_read_uevent_file(device
);
585 *ifindex
= device
->ifindex
;
590 _public_
int sd_device_new_from_device_id(sd_device
**ret
, const char *id
) {
593 assert_return(ret
, -EINVAL
);
594 assert_return(id
, -EINVAL
);
603 r
= sscanf(id
, "%c%i:%i", &type
, &maj
, &min
);
607 return sd_device_new_from_devnum(ret
, type
, makedev(maj
, min
));
611 _cleanup_device_unref_ sd_device
*device
= NULL
;
612 _cleanup_close_
int sk
= -1;
613 struct ifreq ifr
= {};
616 r
= safe_atoi(&id
[1], &ifr
.ifr_ifindex
);
619 else if (ifr
.ifr_ifindex
<= 0)
622 sk
= socket(PF_INET
, SOCK_DGRAM
, 0);
626 r
= ioctl(sk
, SIOCGIFNAME
, &ifr
);
630 r
= sd_device_new_from_subsystem_sysname(&device
, "net", ifr
.ifr_name
);
634 r
= sd_device_get_ifindex(device
, &ifindex
);
638 /* this is racey, so we might end up with the wrong device */
639 if (ifr
.ifr_ifindex
!= ifindex
)
649 char subsys
[PATH_MAX
];
652 (void)strscpy(subsys
, sizeof(subsys
), id
+ 1);
653 sysname
= strchr(subsys
, ':');
660 return sd_device_new_from_subsystem_sysname(ret
, subsys
, sysname
);
667 _public_
int sd_device_get_syspath(sd_device
*device
, const char **ret
) {
668 assert_return(device
, -EINVAL
);
669 assert_return(ret
, -EINVAL
);
671 assert(path_startswith(device
->syspath
, "/sys/"));
673 *ret
= device
->syspath
;
678 static int device_new_from_child(sd_device
**ret
, sd_device
*child
) {
679 _cleanup_free_
char *path
= NULL
;
680 const char *subdir
, *syspath
;
686 r
= sd_device_get_syspath(child
, &syspath
);
690 path
= strdup(syspath
);
693 subdir
= path
+ strlen("/sys");
698 pos
= strrchr(subdir
, '/');
699 if (!pos
|| pos
< subdir
+ 2)
704 r
= sd_device_new_from_syspath(ret
, path
);
714 _public_
int sd_device_get_parent(sd_device
*child
, sd_device
**ret
) {
716 assert_return(ret
, -EINVAL
);
717 assert_return(child
, -EINVAL
);
719 if (!child
->parent_set
) {
720 child
->parent_set
= true;
722 (void)device_new_from_child(&child
->parent
, child
);
728 *ret
= child
->parent
;
733 int device_set_subsystem(sd_device
*device
, const char *_subsystem
) {
734 _cleanup_free_
char *subsystem
= NULL
;
740 subsystem
= strdup(_subsystem
);
744 r
= device_add_property_internal(device
, "SUBSYSTEM", subsystem
);
748 free(device
->subsystem
);
749 device
->subsystem
= subsystem
;
752 device
->subsystem_set
= true;
757 _public_
int sd_device_get_subsystem(sd_device
*device
, const char **ret
) {
758 assert_return(ret
, -EINVAL
);
759 assert_return(device
, -EINVAL
);
761 if (!device
->subsystem_set
) {
762 _cleanup_free_
char *subsystem
= NULL
;
767 /* read 'subsystem' link */
768 r
= sd_device_get_syspath(device
, &syspath
);
772 path
= strjoina(syspath
, "/subsystem");
773 r
= readlink_value(path
, &subsystem
);
775 r
= device_set_subsystem(device
, subsystem
);
776 /* use implicit names */
777 else if (path_startswith(device
->devpath
, "/module/"))
778 r
= device_set_subsystem(device
, "module");
779 else if (strstr(device
->devpath
, "/drivers/"))
780 r
= device_set_subsystem(device
, "drivers");
781 else if (path_startswith(device
->devpath
, "/subsystem/") ||
782 path_startswith(device
->devpath
, "/class/") ||
783 path_startswith(device
->devpath
, "/bus/"))
784 r
= device_set_subsystem(device
, "subsystem");
786 return log_debug_errno(r
, "sd-device: could not set subsystem for %s: %m", device
->devpath
);
788 device
->subsystem_set
= true;
791 *ret
= device
->subsystem
;
796 _public_
int sd_device_get_devtype(sd_device
*device
, const char **devtype
) {
802 r
= device_read_uevent_file(device
);
806 *devtype
= device
->devtype
;
811 _public_
int sd_device_get_parent_with_subsystem_devtype(sd_device
*child
, const char *subsystem
, const char *devtype
, sd_device
**ret
) {
812 sd_device
*parent
= NULL
;
815 assert_return(child
, -EINVAL
);
816 assert_return(subsystem
, -EINVAL
);
818 r
= sd_device_get_parent(child
, &parent
);
820 const char *parent_subsystem
= NULL
;
821 const char *parent_devtype
= NULL
;
823 (void)sd_device_get_subsystem(parent
, &parent_subsystem
);
824 if (streq_ptr(parent_subsystem
, subsystem
)) {
828 (void)sd_device_get_devtype(parent
, &parent_devtype
);
829 if (streq_ptr(parent_devtype
, devtype
))
832 r
= sd_device_get_parent(parent
, &parent
);
843 _public_
int sd_device_get_devnum(sd_device
*device
, dev_t
*devnum
) {
846 assert_return(device
, -EINVAL
);
847 assert_return(devnum
, -EINVAL
);
849 r
= device_read_uevent_file(device
);
853 *devnum
= device
->devnum
;
858 int device_set_driver(sd_device
*device
, const char *_driver
) {
859 _cleanup_free_
char *driver
= NULL
;
865 driver
= strdup(_driver
);
869 r
= device_add_property_internal(device
, "DRIVER", driver
);
873 free(device
->driver
);
874 device
->driver
= driver
;
877 device
->driver_set
= true;
882 _public_
int sd_device_get_driver(sd_device
*device
, const char **ret
) {
883 assert_return(device
, -EINVAL
);
884 assert_return(ret
, -EINVAL
);
886 if (!device
->driver_set
) {
887 _cleanup_free_
char *driver
= NULL
;
892 r
= sd_device_get_syspath(device
, &syspath
);
896 path
= strjoina(syspath
, "/driver");
897 r
= readlink_value(path
, &driver
);
899 r
= device_set_driver(device
, driver
);
905 *ret
= device
->driver
;
910 _public_
int sd_device_get_devpath(sd_device
*device
, const char **devpath
) {
911 assert_return(device
, -EINVAL
);
912 assert_return(devpath
, -EINVAL
);
914 assert(device
->devpath
);
915 assert(device
->devpath
[0] == '/');
917 *devpath
= device
->devpath
;
922 _public_
int sd_device_get_devname(sd_device
*device
, const char **devname
) {
925 assert_return(device
, -EINVAL
);
926 assert_return(devname
, -EINVAL
);
928 r
= device_read_uevent_file(device
);
932 if (!device
->devname
)
935 assert(path_startswith(device
->devname
, "/dev/"));
937 *devname
= device
->devname
;
942 static int device_set_sysname(sd_device
*device
) {
943 _cleanup_free_
char *sysname
= NULL
;
944 const char *sysnum
= NULL
;
948 pos
= strrchr(device
->devpath
, '/');
953 /* devpath is not a root directory */
954 if (*pos
== '\0' || pos
<= device
->devpath
)
957 sysname
= strdup(pos
);
961 /* some devices have '!' in their name, change that to '/' */
962 while (sysname
[len
] != '\0') {
963 if (sysname
[len
] == '!')
969 /* trailing number */
970 while (len
> 0 && isdigit(sysname
[--len
]))
971 sysnum
= &sysname
[len
];
976 free(device
->sysname
);
977 device
->sysname
= sysname
;
980 device
->sysnum
= sysnum
;
982 device
->sysname_set
= true;
987 _public_
int sd_device_get_sysname(sd_device
*device
, const char **ret
) {
990 assert_return(device
, -EINVAL
);
991 assert_return(ret
, -EINVAL
);
993 if (!device
->sysname_set
) {
994 r
= device_set_sysname(device
);
999 *ret
= device
->sysname
;
1004 _public_
int sd_device_get_sysnum(sd_device
*device
, const char **ret
) {
1007 assert_return(device
, -EINVAL
);
1008 assert_return(ret
, -EINVAL
);
1010 if (!device
->sysname_set
) {
1011 r
= device_set_sysname(device
);
1016 *ret
= device
->sysnum
;
1021 static bool is_valid_tag(const char *tag
) {
1024 return !strchr(tag
, ':') && !strchr(tag
, ' ');
1027 int device_add_tag(sd_device
*device
, const char *tag
) {
1033 if (!is_valid_tag(tag
))
1036 r
= set_ensure_allocated(&device
->tags
, &string_hash_ops
);
1040 r
= set_put_strdup(device
->tags
, tag
);
1044 device
->tags_generation
++;
1045 device
->property_tags_outdated
= true;
1050 int device_add_devlink(sd_device
*device
, const char *devlink
) {
1056 r
= set_ensure_allocated(&device
->devlinks
, &string_hash_ops
);
1060 r
= set_put_strdup(device
->devlinks
, devlink
);
1064 device
->devlinks_generation
++;
1065 device
->property_devlinks_outdated
= true;
1070 static int device_add_property_internal_from_string(sd_device
*device
, const char *str
) {
1071 _cleanup_free_
char *key
= NULL
;
1081 value
= strchr(key
, '=');
1087 if (isempty(++value
))
1090 return device_add_property_internal(device
, key
, value
);
1093 int device_set_usec_initialized(sd_device
*device
, const char *initialized
) {
1094 uint64_t usec_initialized
;
1098 assert(initialized
);
1100 r
= safe_atou64(initialized
, &usec_initialized
);
1104 r
= device_add_property_internal(device
, "USEC_INITIALIZED", initialized
);
1108 device
->usec_initialized
= usec_initialized
;
1113 static int handle_db_line(sd_device
*device
, char key
, const char *value
) {
1122 r
= device_add_tag(device
, value
);
1128 path
= strjoina("/dev/", value
);
1129 r
= device_add_devlink(device
, path
);
1135 r
= device_add_property_internal_from_string(device
, value
);
1141 r
= device_set_usec_initialized(device
, value
);
1147 r
= safe_atoi(value
, &device
->devlink_priority
);
1153 r
= safe_atoi(value
, &device
->watch_handle
);
1159 log_debug("device db: unknown key '%c'", key
);
1165 int device_get_id_filename(sd_device
*device
, const char **ret
) {
1169 if (!device
->id_filename
) {
1170 _cleanup_free_
char *id
= NULL
;
1171 const char *subsystem
;
1175 r
= sd_device_get_subsystem(device
, &subsystem
);
1179 r
= sd_device_get_devnum(device
, &devnum
);
1183 r
= sd_device_get_ifindex(device
, &ifindex
);
1187 if (major(devnum
) > 0) {
1188 /* use dev_t -- b259:131072, c254:0 */
1189 r
= asprintf(&id
, "%c%u:%u",
1190 streq(subsystem
, "block") ? 'b' : 'c',
1191 major(devnum
), minor(devnum
));
1194 } else if (ifindex
> 0) {
1195 /* use netdev ifindex -- n3 */
1196 r
= asprintf(&id
, "n%u", ifindex
);
1200 /* use $subsys:$sysname -- pci:0000:00:1f.2
1201 * sysname() has '!' translated, get it from devpath
1203 const char *sysname
;
1205 sysname
= basename(device
->devpath
);
1209 r
= asprintf(&id
, "+%s:%s", subsystem
, sysname
);
1214 device
->id_filename
= id
;
1218 *ret
= device
->id_filename
;
1223 static int device_read_db(sd_device
*device
) {
1224 _cleanup_free_
char *db
= NULL
;
1226 const char *id
, *value
;
1240 if (device
->db_loaded
|| device
->sealed
)
1243 r
= device_get_id_filename(device
, &id
);
1247 path
= strjoina("/run/udev/data/", id
);
1249 r
= read_full_file(path
, &db
, &db_len
);
1254 log_debug("sd-device: failed to read db '%s': %s", path
, strerror(-r
));
1259 /* devices with a database entry are initialized */
1260 device
->is_initialized
= true;;
1262 for (i
= 0; i
< db_len
; i
++) {
1265 if (!strchr(NEWLINE
, db
[i
])) {
1274 log_debug("sd-device: ignoring invalid db entry with key '%c'", key
);
1276 state
= INVALID_LINE
;
1291 if (strchr(NEWLINE
, db
[i
]))
1296 if (strchr(NEWLINE
, db
[i
])) {
1298 r
= handle_db_line(device
, key
, value
);
1300 log_debug("sd-device: failed to handle db entry '%c:%s': %s", key
, value
, strerror(-r
));
1307 assert_not_reached("invalid state when parsing db");
1311 device
->db_loaded
= true;
1316 _public_
int sd_device_get_is_initialized(sd_device
*device
, int *initialized
) {
1319 assert_return(device
, -EINVAL
);
1320 assert_return(initialized
, -EINVAL
);
1322 r
= device_read_db(device
);
1326 *initialized
= device
->is_initialized
;
1331 _public_
int sd_device_get_usec_since_initialized(sd_device
*device
, uint64_t *usec
) {
1335 assert_return(device
, -EINVAL
);
1336 assert_return(usec
, -EINVAL
);
1338 r
= device_read_db(device
);
1342 if (!device
->is_initialized
)
1345 if (!device
->usec_initialized
)
1348 now_ts
= now(clock_boottime_or_monotonic());
1350 if (now_ts
< device
->usec_initialized
)
1353 *usec
= now_ts
- device
->usec_initialized
;
1358 _public_
const char *sd_device_get_tag_first(sd_device
*device
) {
1359 assert_return(device
, NULL
);
1361 (void) device_read_db(device
);
1363 device
->tags_iterator_generation
= device
->tags_generation
;
1364 device
->tags_iterator
= ITERATOR_FIRST
;
1366 return set_iterate(device
->tags
, &device
->tags_iterator
);
1369 _public_
const char *sd_device_get_tag_next(sd_device
*device
) {
1370 assert_return(device
, NULL
);
1372 (void) device_read_db(device
);
1374 if (device
->tags_iterator_generation
!= device
->tags_generation
)
1377 return set_iterate(device
->tags
, &device
->tags_iterator
);
1380 _public_
const char *sd_device_get_devlink_first(sd_device
*device
) {
1381 assert_return(device
, NULL
);
1383 (void) device_read_db(device
);
1385 device
->devlinks_iterator_generation
= device
->devlinks_generation
;
1386 device
->devlinks_iterator
= ITERATOR_FIRST
;
1388 return set_iterate(device
->devlinks
, &device
->devlinks_iterator
);
1391 _public_
const char *sd_device_get_devlink_next(sd_device
*device
) {
1392 assert_return(device
, NULL
);
1394 (void) device_read_db(device
);
1396 if (device
->devlinks_iterator_generation
!= device
->devlinks_generation
)
1399 return set_iterate(device
->devlinks
, &device
->devlinks_iterator
);
1402 static int device_properties_prepare(sd_device
*device
) {
1407 r
= device_read_uevent_file(device
);
1411 r
= device_read_db(device
);
1415 if (device
->property_devlinks_outdated
) {
1416 char *devlinks
= NULL
;
1417 const char *devlink
;
1419 devlink
= sd_device_get_devlink_first(device
);
1421 devlinks
= strdupa(devlink
);
1423 while ((devlink
= sd_device_get_devlink_next(device
)))
1424 devlinks
= strjoina(devlinks
, " ", devlink
);
1426 r
= device_add_property_internal(device
, "DEVLINKS", devlinks
);
1430 device
->property_devlinks_outdated
= false;
1433 if (device
->property_tags_outdated
) {
1437 tag
= sd_device_get_tag_first(device
);
1439 tags
= strjoina(":", tag
);
1441 while ((tag
= sd_device_get_tag_next(device
)))
1442 tags
= strjoina(tags
, ":", tag
);
1444 tags
= strjoina(tags
, ":");
1446 r
= device_add_property_internal(device
, "TAGS", tags
);
1450 device
->property_tags_outdated
= false;
1456 _public_
const char *sd_device_get_property_first(sd_device
*device
, const char **_value
) {
1461 assert_return(device
, NULL
);
1463 r
= device_properties_prepare(device
);
1467 device
->properties_iterator_generation
= device
->properties_generation
;
1468 device
->properties_iterator
= ITERATOR_FIRST
;
1470 value
= ordered_hashmap_iterate(device
->properties
, &device
->properties_iterator
, (const void**)&key
);
1478 _public_
const char *sd_device_get_property_next(sd_device
*device
, const char **_value
) {
1483 assert_return(device
, NULL
);
1485 r
= device_properties_prepare(device
);
1489 if (device
->properties_iterator_generation
!= device
->properties_generation
)
1492 value
= ordered_hashmap_iterate(device
->properties
, &device
->properties_iterator
, (const void**)&key
);
1500 static int device_sysattrs_read_all(sd_device
*device
) {
1501 _cleanup_closedir_
DIR *dir
= NULL
;
1502 const char *syspath
;
1503 struct dirent
*dent
;
1508 if (device
->sysattrs_read
)
1511 r
= sd_device_get_syspath(device
, &syspath
);
1515 dir
= opendir(syspath
);
1519 r
= set_ensure_allocated(&device
->sysattrs
, &string_hash_ops
);
1523 for (dent
= readdir(dir
); dent
!= NULL
; dent
= readdir(dir
)) {
1525 struct stat statbuf
;
1527 /* only handle symlinks and regular files */
1528 if (dent
->d_type
!= DT_LNK
&& dent
->d_type
!= DT_REG
)
1531 path
= strjoina(syspath
, "/", dent
->d_name
);
1533 if (lstat(path
, &statbuf
) != 0)
1536 if (!(statbuf
.st_mode
& S_IRUSR
))
1539 r
= set_put_strdup(device
->sysattrs
, dent
->d_name
);
1544 device
->sysattrs_read
= true;
1549 _public_
const char *sd_device_get_sysattr_first(sd_device
*device
) {
1552 assert_return(device
, NULL
);
1554 if (!device
->sysattrs_read
) {
1555 r
= device_sysattrs_read_all(device
);
1562 device
->sysattrs_iterator
= ITERATOR_FIRST
;
1564 return set_iterate(device
->sysattrs
, &device
->sysattrs_iterator
);
1567 _public_
const char *sd_device_get_sysattr_next(sd_device
*device
) {
1568 assert_return(device
, NULL
);
1570 if (!device
->sysattrs_read
)
1573 return set_iterate(device
->sysattrs
, &device
->sysattrs_iterator
);
1576 _public_
int sd_device_has_tag(sd_device
*device
, const char *tag
) {
1577 assert_return(device
, -EINVAL
);
1578 assert_return(tag
, -EINVAL
);
1580 (void) device_read_db(device
);
1582 return !!set_contains(device
->tags
, tag
);
1585 _public_
int sd_device_get_property_value(sd_device
*device
, const char *key
, const char **_value
) {
1589 assert_return(device
, -EINVAL
);
1590 assert_return(key
, -EINVAL
);
1591 assert_return(_value
, -EINVAL
);
1593 r
= device_properties_prepare(device
);
1597 value
= ordered_hashmap_get(device
->properties
, key
);
1606 /* replaces the value if it already exists */
1607 static int device_add_sysattr_value(sd_device
*device
, const char *_key
, char *value
) {
1608 _cleanup_free_
char *key
= NULL
;
1609 _cleanup_free_
char *value_old
= NULL
;
1615 r
= hashmap_ensure_allocated(&device
->sysattr_values
, &string_hash_ops
);
1619 value_old
= hashmap_remove2(device
->sysattr_values
, _key
, (void **)&key
);
1626 r
= hashmap_put(device
->sysattr_values
, key
, value
);
1635 static int device_get_sysattr_value(sd_device
*device
, const char *_key
, const char **_value
) {
1636 const char *key
= NULL
, *value
;
1641 value
= hashmap_get2(device
->sysattr_values
, _key
, (void **) &key
);
1651 /* We cache all sysattr lookups. If an attribute does not exist, it is stored
1652 * with a NULL value in the cache, otherwise the returned string is stored */
1653 _public_
int sd_device_get_sysattr_value(sd_device
*device
, const char *sysattr
, const char **_value
) {
1654 _cleanup_free_
char *value
= NULL
;
1655 const char *syspath
, *cached_value
= NULL
;
1657 struct stat statbuf
;
1660 assert_return(device
, -EINVAL
);
1661 assert_return(sysattr
, -EINVAL
);
1663 /* look for possibly already cached result */
1664 r
= device_get_sysattr_value(device
, sysattr
, &cached_value
);
1670 /* we looked up the sysattr before and it did not exist */
1674 *_value
= cached_value
;
1679 r
= sd_device_get_syspath(device
, &syspath
);
1683 path
= strjoina(syspath
, "/", sysattr
);
1684 r
= lstat(path
, &statbuf
);
1686 /* remember that we could not access the sysattr */
1687 r
= device_add_sysattr_value(device
, sysattr
, NULL
);
1692 } else if (S_ISLNK(statbuf
.st_mode
)) {
1693 /* Some core links return only the last element of the target path,
1694 * these are just values, the paths should not be exposed. */
1695 if (STR_IN_SET(sysattr
, "driver", "subsystem", "module")) {
1696 r
= readlink_value(path
, &value
);
1701 } else if (S_ISDIR(statbuf
.st_mode
)) {
1702 /* skip directories */
1704 } else if (!(statbuf
.st_mode
& S_IRUSR
)) {
1705 /* skip non-readable files */
1710 /* read attribute value */
1711 r
= read_full_file(path
, &value
, &size
);
1715 /* drop trailing newlines */
1716 while (size
> 0 && value
[--size
] == '\n')
1720 r
= device_add_sysattr_value(device
, sysattr
, value
);
1730 static void device_remove_sysattr_value(sd_device
*device
, const char *_key
) {
1731 _cleanup_free_
char *key
= NULL
;
1732 _cleanup_free_
char *value
= NULL
;
1737 value
= hashmap_remove2(device
->sysattr_values
, _key
, (void **) &key
);
1742 /* set the attribute and save it in the cache. If a NULL value is passed the
1743 * attribute is cleared from the cache */
1744 _public_
int sd_device_set_sysattr_value(sd_device
*device
, const char *sysattr
, char *_value
) {
1745 _cleanup_close_
int fd
= -1;
1746 _cleanup_free_
char *value
= NULL
;
1747 const char *syspath
;
1749 struct stat statbuf
;
1750 size_t value_len
= 0;
1754 assert_return(device
, -EINVAL
);
1755 assert_return(sysattr
, -EINVAL
);
1758 device_remove_sysattr_value(device
, sysattr
);
1763 r
= sd_device_get_syspath(device
, &syspath
);
1767 path
= strjoina(syspath
, "/", sysattr
);
1768 r
= lstat(path
, &statbuf
);
1774 r
= device_add_sysattr_value(device
, sysattr
, value
);
1781 if (S_ISLNK(statbuf
.st_mode
))
1784 /* skip directories */
1785 if (S_ISDIR(statbuf
.st_mode
))
1788 /* skip non-readable files */
1789 if ((statbuf
.st_mode
& S_IRUSR
) == 0)
1792 value_len
= strlen(_value
);
1794 /* drop trailing newlines */
1795 while (value_len
> 0 && _value
[value_len
- 1] == '\n')
1796 _value
[--value_len
] = '\0';
1798 /* value length is limited to 4k */
1799 if (value_len
> 4096)
1802 fd
= open(path
, O_WRONLY
| O_CLOEXEC
);
1806 value
= strdup(_value
);
1810 size
= write(fd
, value
, value_len
);
1814 if ((size_t)size
!= value_len
)
1817 r
= device_add_sysattr_value(device
, sysattr
, value
);