2 This file is part of systemd.
4 Copyright 2008-2012 Kay Sievers <kay@vrfy.org>
5 Copyright 2014 Tom Gundersen <teg@jklm.no>
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
22 #include <sys/types.h>
27 #include "path-util.h"
34 #include "sd-device.h"
36 #include "device-util.h"
37 #include "device-private.h"
38 #include "device-internal.h"
40 int device_new_aux(sd_device
**ret
) {
41 _cleanup_device_unref_ sd_device
*device
= NULL
;
45 device
= new0(sd_device
, 1);
50 device
->watch_handle
= -1;
58 _public_ sd_device
*sd_device_ref(sd_device
*device
) {
60 assert_se(++ device
->n_ref
>= 2);
65 _public_ sd_device
*sd_device_unref(sd_device
*device
) {
66 if (device
&& -- device
->n_ref
== 0) {
67 sd_device_unref(device
->parent
);
68 free(device
->syspath
);
69 free(device
->sysname
);
70 free(device
->devtype
);
71 free(device
->devname
);
72 free(device
->subsystem
);
74 free(device
->id_filename
);
75 free(device
->properties_strv
);
76 free(device
->properties_nulstr
);
78 ordered_hashmap_free_free_free(device
->properties
);
79 ordered_hashmap_free_free_free(device
->properties_db
);
80 hashmap_free_free_free(device
->sysattr_values
);
81 set_free_free(device
->sysattrs
);
82 set_free_free(device
->tags
);
83 set_free_free(device
->devlinks
);
91 int device_add_property_aux(sd_device
*device
, const char *_key
, const char *_value
, bool db
) {
92 OrderedHashmap
**properties
;
98 properties
= &device
->properties_db
;
100 properties
= &device
->properties
;
103 _cleanup_free_
char *key
= NULL
, *value
= NULL
, *old_key
= NULL
, *old_value
= NULL
;
106 r
= ordered_hashmap_ensure_allocated(properties
, &string_hash_ops
);
114 value
= strdup(_value
);
118 old_value
= ordered_hashmap_get2(*properties
, key
, (void**) &old_key
);
120 r
= ordered_hashmap_replace(*properties
, key
, value
);
127 _cleanup_free_
char *key
= NULL
;
128 _cleanup_free_
char *value
= NULL
;
130 value
= ordered_hashmap_remove2(*properties
, _key
, (void**) &key
);
134 device
->properties_generation
++;
135 device
->properties_buf_outdated
= true;
141 int device_add_property_internal(sd_device
*device
, const char *key
, const char *value
) {
142 return device_add_property_aux(device
, key
, value
, false);
145 int device_set_syspath(sd_device
*device
, const char *_syspath
, bool verify
) {
146 _cleanup_free_
char *syspath
= NULL
;
153 /* must be a subdirectory of /sys */
154 if (!path_startswith(_syspath
, "/sys/")) {
155 log_debug("sd-device: syspath '%s' is not a subdirectory of /sys", _syspath
);
160 r
= readlink_and_canonicalize(_syspath
, &syspath
);
162 /* the device does not exist (any more?) */
164 else if (r
== -EINVAL
) {
166 syspath
= canonicalize_file_name(_syspath
);
169 /* the device does not exist (any more?) */
172 log_debug("sd-device: could not canonicalize '%s': %m", _syspath
);
176 log_debug("sd-device: could not get target of '%s': %s", _syspath
, strerror(-r
));
180 if (path_startswith(syspath
, "/sys/devices/")) {
183 /* all 'devices' require an 'uevent' file */
184 path
= strjoina(syspath
, "/uevent");
185 r
= access(path
, F_OK
);
188 /* this is not a valid device */
191 log_debug("sd-device: %s does not have an uevent file: %m", syspath
);
195 /* everything else just just needs to be a directory */
196 if (!is_dir(syspath
, false))
200 syspath
= strdup(_syspath
);
205 devpath
= syspath
+ strlen("/sys");
207 r
= device_add_property_internal(device
, "DEVPATH", devpath
);
211 free(device
->syspath
);
212 device
->syspath
= syspath
;
215 device
->devpath
= devpath
;
220 _public_
int sd_device_new_from_syspath(sd_device
**ret
, const char *syspath
) {
221 _cleanup_device_unref_ sd_device
*device
= NULL
;
224 assert_return(ret
, -EINVAL
);
225 assert_return(syspath
, -EINVAL
);
227 r
= device_new_aux(&device
);
231 r
= device_set_syspath(device
, syspath
, true);
241 _public_
int sd_device_new_from_devnum(sd_device
**ret
, char type
, dev_t devnum
) {
243 char id
[DECIMAL_STR_MAX(unsigned) * 2 + 1];
245 assert_return(ret
, -EINVAL
);
246 assert_return(type
== 'b' || type
== 'c', -EINVAL
);
248 /* use /sys/dev/{block,char}/<maj>:<min> link */
249 snprintf(id
, sizeof(id
), "%u:%u", major(devnum
), minor(devnum
));
251 syspath
= strjoina("/sys/dev/", (type
== 'b' ? "block" : "char"), "/", id
);
253 return sd_device_new_from_syspath(ret
, syspath
);
256 _public_
int sd_device_new_from_subsystem_sysname(sd_device
**ret
, const char *subsystem
, const char *sysname
) {
259 assert_return(ret
, -EINVAL
);
260 assert_return(subsystem
, -EINVAL
);
261 assert_return(sysname
, -EINVAL
);
263 if (streq(subsystem
, "subsystem")) {
264 syspath
= strjoina("/sys/subsystem/", sysname
);
265 if (access(syspath
, F_OK
) >= 0)
266 return sd_device_new_from_syspath(ret
, syspath
);
268 syspath
= strjoina("/sys/bus/", sysname
);
269 if (access(syspath
, F_OK
) >= 0)
270 return sd_device_new_from_syspath(ret
, syspath
);
272 syspath
= strjoina("/sys/class/", sysname
);
273 if (access(syspath
, F_OK
) >= 0)
274 return sd_device_new_from_syspath(ret
, syspath
);
275 } else if (streq(subsystem
, "module")) {
276 syspath
= strjoina("/sys/module/", sysname
);
277 if (access(syspath
, F_OK
) >= 0)
278 return sd_device_new_from_syspath(ret
, syspath
);
279 } else if (streq(subsystem
, "drivers")) {
280 char subsys
[PATH_MAX
];
283 strscpy(subsys
, sizeof(subsys
), sysname
);
284 driver
= strchr(subsys
, ':');
289 syspath
= strjoina("/sys/subsystem/", subsys
, "/drivers/", driver
);
290 if (access(syspath
, F_OK
) >= 0)
291 return sd_device_new_from_syspath(ret
, syspath
);
293 syspath
= strjoina("/sys/bus/", subsys
, "/drivers/", driver
);
294 if (access(syspath
, F_OK
) >= 0)
295 return sd_device_new_from_syspath(ret
, syspath
);
299 syspath
= strjoina("/sys/subsystem/", subsystem
, "/devices/", sysname
);
300 if (access(syspath
, F_OK
) >= 0)
301 return sd_device_new_from_syspath(ret
, syspath
);
303 syspath
= strjoina("/sys/bus/", subsystem
, "/devices/", sysname
);
304 if (access(syspath
, F_OK
) >= 0)
305 return sd_device_new_from_syspath(ret
, syspath
);
307 syspath
= strjoina("/sys/class/", subsystem
, "/", sysname
);
308 if (access(syspath
, F_OK
) >= 0)
309 return sd_device_new_from_syspath(ret
, syspath
);
315 int device_set_devtype(sd_device
*device
, const char *_devtype
) {
316 _cleanup_free_
char *devtype
= NULL
;
322 devtype
= strdup(_devtype
);
326 r
= device_add_property_internal(device
, "DEVTYPE", devtype
);
330 free(device
->devtype
);
331 device
->devtype
= devtype
;
337 int device_set_ifindex(sd_device
*device
, const char *_ifindex
) {
343 r
= safe_atoi(_ifindex
, &ifindex
);
350 r
= device_add_property_internal(device
, "IFINDEX", _ifindex
);
354 device
->ifindex
= ifindex
;
359 int device_set_devname(sd_device
*device
, const char *_devname
) {
360 _cleanup_free_
char *devname
= NULL
;
366 if (_devname
[0] != '/') {
367 r
= asprintf(&devname
, "/dev/%s", _devname
);
371 devname
= strdup(_devname
);
376 r
= device_add_property_internal(device
, "DEVNAME", devname
);
380 free(device
->devname
);
381 device
->devname
= devname
;
387 int device_set_devmode(sd_device
*device
, const char *_devmode
) {
394 r
= safe_atou(_devmode
, &devmode
);
401 r
= device_add_property_internal(device
, "DEVMODE", _devmode
);
405 device
->devmode
= devmode
;
410 int device_set_devnum(sd_device
*device
, const char *major
, const char *minor
) {
411 unsigned maj
= 0, min
= 0;
417 r
= safe_atou(major
, &maj
);
424 r
= safe_atou(minor
, &min
);
429 r
= device_add_property_internal(device
, "MAJOR", major
);
434 r
= device_add_property_internal(device
, "MINOR", minor
);
439 device
->devnum
= makedev(maj
, min
);
444 static int handle_uevent_line(sd_device
*device
, const char *key
, const char *value
, const char **major
, const char **minor
) {
453 if (streq(key
, "DEVTYPE")) {
454 r
= device_set_devtype(device
, value
);
457 } else if (streq(key
, "IFINDEX")) {
458 r
= device_set_ifindex(device
, value
);
461 } else if (streq(key
, "DEVNAME")) {
462 r
= device_set_devname(device
, value
);
465 } else if (streq(key
, "DEVMODE")) {
466 r
= device_set_devmode(device
, value
);
469 } else if (streq(key
, "MAJOR"))
471 else if (streq(key
, "MINOR"))
474 r
= device_add_property_internal(device
, key
, value
);
482 int device_read_uevent_file(sd_device
*device
) {
483 _cleanup_free_
char *uevent
= NULL
;
484 const char *syspath
, *key
, *value
, *major
= NULL
, *minor
= NULL
;
500 if (device
->uevent_loaded
|| device
->sealed
)
503 device
->uevent_loaded
= true;
505 r
= sd_device_get_syspath(device
, &syspath
);
509 path
= strjoina(syspath
, "/uevent");
511 r
= read_full_file(path
, &uevent
, &uevent_len
);
513 /* empty uevent files may be write-only */
515 else if (r
== -ENOENT
)
516 /* some devices may not have uevent files, see set_syspath() */
519 log_debug("sd-device: failed to read uevent file '%s': %s", path
, strerror(-r
));
523 for (i
= 0; i
< uevent_len
; i
++) {
526 if (!strchr(NEWLINE
, uevent
[i
])) {
534 if (uevent
[i
] == '=') {
538 } else if (strchr(NEWLINE
, uevent
[i
])) {
540 log_debug("sd-device: ignoring invalid uevent line '%s'", key
);
553 if (strchr(NEWLINE
, uevent
[i
])) {
556 r
= handle_uevent_line(device
, key
, value
, &major
, &minor
);
558 log_debug("sd-device: failed to handle uevent entry '%s=%s': %s", key
, value
, strerror(-r
));
565 assert_not_reached("invalid state when parsing uevent file");
570 r
= device_set_devnum(device
, major
, minor
);
572 log_debug("sd-device: could not set 'MAJOR=%s' or 'MINOR=%s' from '%s': %s", major
, minor
, path
, strerror(-r
));
578 _public_
int sd_device_get_ifindex(sd_device
*device
, int *ifindex
) {
581 assert_return(device
, -EINVAL
);
582 assert_return(ifindex
, -EINVAL
);
584 r
= device_read_uevent_file(device
);
588 *ifindex
= device
->ifindex
;
593 _public_
int sd_device_new_from_device_id(sd_device
**ret
, const char *id
) {
596 assert_return(ret
, -EINVAL
);
597 assert_return(id
, -EINVAL
);
606 r
= sscanf(id
, "%c%i:%i", &type
, &maj
, &min
);
610 return sd_device_new_from_devnum(ret
, type
, makedev(maj
, min
));
614 _cleanup_device_unref_ sd_device
*device
= NULL
;
615 _cleanup_close_
int sk
= -1;
616 struct ifreq ifr
= {};
619 r
= safe_atoi(&id
[1], &ifr
.ifr_ifindex
);
622 else if (ifr
.ifr_ifindex
<= 0)
625 sk
= socket(PF_INET
, SOCK_DGRAM
, 0);
629 r
= ioctl(sk
, SIOCGIFNAME
, &ifr
);
633 r
= sd_device_new_from_subsystem_sysname(&device
, "net", ifr
.ifr_name
);
637 r
= sd_device_get_ifindex(device
, &ifindex
);
641 /* this is racey, so we might end up with the wrong device */
642 if (ifr
.ifr_ifindex
!= ifindex
)
652 char subsys
[PATH_MAX
];
655 (void)strscpy(subsys
, sizeof(subsys
), id
+ 1);
656 sysname
= strchr(subsys
, ':');
663 return sd_device_new_from_subsystem_sysname(ret
, subsys
, sysname
);
670 _public_
int sd_device_get_syspath(sd_device
*device
, const char **ret
) {
671 assert_return(device
, -EINVAL
);
672 assert_return(ret
, -EINVAL
);
674 assert(path_startswith(device
->syspath
, "/sys/"));
676 *ret
= device
->syspath
;
681 static int device_new_from_child(sd_device
**ret
, sd_device
*child
) {
682 _cleanup_free_
char *path
= NULL
;
683 const char *subdir
, *syspath
;
689 r
= sd_device_get_syspath(child
, &syspath
);
693 path
= strdup(syspath
);
696 subdir
= path
+ strlen("/sys");
701 pos
= strrchr(subdir
, '/');
702 if (!pos
|| pos
< subdir
+ 2)
707 r
= sd_device_new_from_syspath(ret
, path
);
717 _public_
int sd_device_get_parent(sd_device
*child
, sd_device
**ret
) {
719 assert_return(ret
, -EINVAL
);
720 assert_return(child
, -EINVAL
);
722 if (!child
->parent_set
) {
723 child
->parent_set
= true;
725 (void)device_new_from_child(&child
->parent
, child
);
731 *ret
= child
->parent
;
736 int device_set_subsystem(sd_device
*device
, const char *_subsystem
) {
737 _cleanup_free_
char *subsystem
= NULL
;
743 subsystem
= strdup(_subsystem
);
747 r
= device_add_property_internal(device
, "SUBSYSTEM", subsystem
);
751 free(device
->subsystem
);
752 device
->subsystem
= subsystem
;
755 device
->subsystem_set
= true;
760 _public_
int sd_device_get_subsystem(sd_device
*device
, const char **ret
) {
761 assert_return(ret
, -EINVAL
);
762 assert_return(device
, -EINVAL
);
764 if (!device
->subsystem_set
) {
765 _cleanup_free_
char *subsystem
= NULL
;
770 /* read 'subsystem' link */
771 r
= sd_device_get_syspath(device
, &syspath
);
775 path
= strjoina(syspath
, "/subsystem");
776 r
= readlink_value(path
, &subsystem
);
778 r
= device_set_subsystem(device
, subsystem
);
779 /* use implicit names */
780 else if (path_startswith(device
->devpath
, "/module/"))
781 r
= device_set_subsystem(device
, "module");
782 else if (strstr(device
->devpath
, "/drivers/"))
783 r
= device_set_subsystem(device
, "drivers");
784 else if (path_startswith(device
->devpath
, "/subsystem/") ||
785 path_startswith(device
->devpath
, "/class/") ||
786 path_startswith(device
->devpath
, "/bus/"))
787 r
= device_set_subsystem(device
, "subsystem");
788 if (r
< 0 && r
!= -ENOENT
)
789 return log_debug_errno(r
, "sd-device: could not set subsystem for %s: %m", device
->devpath
);
791 device
->subsystem_set
= true;
794 *ret
= device
->subsystem
;
799 _public_
int sd_device_get_devtype(sd_device
*device
, const char **devtype
) {
805 r
= device_read_uevent_file(device
);
809 *devtype
= device
->devtype
;
814 _public_
int sd_device_get_parent_with_subsystem_devtype(sd_device
*child
, const char *subsystem
, const char *devtype
, sd_device
**ret
) {
815 sd_device
*parent
= NULL
;
818 assert_return(child
, -EINVAL
);
819 assert_return(subsystem
, -EINVAL
);
821 r
= sd_device_get_parent(child
, &parent
);
823 const char *parent_subsystem
= NULL
;
824 const char *parent_devtype
= NULL
;
826 (void)sd_device_get_subsystem(parent
, &parent_subsystem
);
827 if (streq_ptr(parent_subsystem
, subsystem
)) {
831 (void)sd_device_get_devtype(parent
, &parent_devtype
);
832 if (streq_ptr(parent_devtype
, devtype
))
835 r
= sd_device_get_parent(parent
, &parent
);
846 _public_
int sd_device_get_devnum(sd_device
*device
, dev_t
*devnum
) {
849 assert_return(device
, -EINVAL
);
850 assert_return(devnum
, -EINVAL
);
852 r
= device_read_uevent_file(device
);
856 *devnum
= device
->devnum
;
861 int device_set_driver(sd_device
*device
, const char *_driver
) {
862 _cleanup_free_
char *driver
= NULL
;
868 driver
= strdup(_driver
);
872 r
= device_add_property_internal(device
, "DRIVER", driver
);
876 free(device
->driver
);
877 device
->driver
= driver
;
880 device
->driver_set
= true;
885 _public_
int sd_device_get_driver(sd_device
*device
, const char **ret
) {
886 assert_return(device
, -EINVAL
);
887 assert_return(ret
, -EINVAL
);
889 if (!device
->driver_set
) {
890 _cleanup_free_
char *driver
= NULL
;
895 r
= sd_device_get_syspath(device
, &syspath
);
899 path
= strjoina(syspath
, "/driver");
900 r
= readlink_value(path
, &driver
);
902 r
= device_set_driver(device
, driver
);
904 return log_debug_errno(r
, "sd-device: could not set driver for %s: %m", device
->devpath
);
905 } else if (r
== -ENOENT
)
906 device
->driver_set
= true;
908 return log_debug_errno(r
, "sd-device: could not set driver for %s: %m", device
->devpath
);
911 *ret
= device
->driver
;
916 _public_
int sd_device_get_devpath(sd_device
*device
, const char **devpath
) {
917 assert_return(device
, -EINVAL
);
918 assert_return(devpath
, -EINVAL
);
920 assert(device
->devpath
);
921 assert(device
->devpath
[0] == '/');
923 *devpath
= device
->devpath
;
928 _public_
int sd_device_get_devname(sd_device
*device
, const char **devname
) {
931 assert_return(device
, -EINVAL
);
932 assert_return(devname
, -EINVAL
);
934 r
= device_read_uevent_file(device
);
938 if (!device
->devname
)
941 assert(path_startswith(device
->devname
, "/dev/"));
943 *devname
= device
->devname
;
948 static int device_set_sysname(sd_device
*device
) {
949 _cleanup_free_
char *sysname
= NULL
;
950 const char *sysnum
= NULL
;
954 pos
= strrchr(device
->devpath
, '/');
959 /* devpath is not a root directory */
960 if (*pos
== '\0' || pos
<= device
->devpath
)
963 sysname
= strdup(pos
);
967 /* some devices have '!' in their name, change that to '/' */
968 while (sysname
[len
] != '\0') {
969 if (sysname
[len
] == '!')
975 /* trailing number */
976 while (len
> 0 && isdigit(sysname
[--len
]))
977 sysnum
= &sysname
[len
];
982 free(device
->sysname
);
983 device
->sysname
= sysname
;
986 device
->sysnum
= sysnum
;
988 device
->sysname_set
= true;
993 _public_
int sd_device_get_sysname(sd_device
*device
, const char **ret
) {
996 assert_return(device
, -EINVAL
);
997 assert_return(ret
, -EINVAL
);
999 if (!device
->sysname_set
) {
1000 r
= device_set_sysname(device
);
1005 *ret
= device
->sysname
;
1010 _public_
int sd_device_get_sysnum(sd_device
*device
, const char **ret
) {
1013 assert_return(device
, -EINVAL
);
1014 assert_return(ret
, -EINVAL
);
1016 if (!device
->sysname_set
) {
1017 r
= device_set_sysname(device
);
1022 *ret
= device
->sysnum
;
1027 static bool is_valid_tag(const char *tag
) {
1030 return !strchr(tag
, ':') && !strchr(tag
, ' ');
1033 int device_add_tag(sd_device
*device
, const char *tag
) {
1039 if (!is_valid_tag(tag
))
1042 r
= set_ensure_allocated(&device
->tags
, &string_hash_ops
);
1046 r
= set_put_strdup(device
->tags
, tag
);
1050 device
->tags_generation
++;
1051 device
->property_tags_outdated
= true;
1056 int device_add_devlink(sd_device
*device
, const char *devlink
) {
1062 r
= set_ensure_allocated(&device
->devlinks
, &string_hash_ops
);
1066 r
= set_put_strdup(device
->devlinks
, devlink
);
1070 device
->devlinks_generation
++;
1071 device
->property_devlinks_outdated
= true;
1076 static int device_add_property_internal_from_string(sd_device
*device
, const char *str
) {
1077 _cleanup_free_
char *key
= NULL
;
1087 value
= strchr(key
, '=');
1093 if (isempty(++value
))
1096 return device_add_property_internal(device
, key
, value
);
1099 int device_set_usec_initialized(sd_device
*device
, const char *initialized
) {
1100 uint64_t usec_initialized
;
1104 assert(initialized
);
1106 r
= safe_atou64(initialized
, &usec_initialized
);
1110 r
= device_add_property_internal(device
, "USEC_INITIALIZED", initialized
);
1114 device
->usec_initialized
= usec_initialized
;
1119 static int handle_db_line(sd_device
*device
, char key
, const char *value
) {
1128 r
= device_add_tag(device
, value
);
1134 path
= strjoina("/dev/", value
);
1135 r
= device_add_devlink(device
, path
);
1141 r
= device_add_property_internal_from_string(device
, value
);
1147 r
= device_set_usec_initialized(device
, value
);
1153 r
= safe_atoi(value
, &device
->devlink_priority
);
1159 r
= safe_atoi(value
, &device
->watch_handle
);
1165 log_debug("device db: unknown key '%c'", key
);
1171 int device_get_id_filename(sd_device
*device
, const char **ret
) {
1175 if (!device
->id_filename
) {
1176 _cleanup_free_
char *id
= NULL
;
1177 const char *subsystem
;
1181 r
= sd_device_get_subsystem(device
, &subsystem
);
1185 r
= sd_device_get_devnum(device
, &devnum
);
1189 r
= sd_device_get_ifindex(device
, &ifindex
);
1193 if (major(devnum
) > 0) {
1196 /* use dev_t -- b259:131072, c254:0 */
1197 r
= asprintf(&id
, "%c%u:%u",
1198 streq(subsystem
, "block") ? 'b' : 'c',
1199 major(devnum
), minor(devnum
));
1202 } else if (ifindex
> 0) {
1203 /* use netdev ifindex -- n3 */
1204 r
= asprintf(&id
, "n%u", ifindex
);
1208 /* use $subsys:$sysname -- pci:0000:00:1f.2
1209 * sysname() has '!' translated, get it from devpath
1211 const char *sysname
;
1213 sysname
= basename(device
->devpath
);
1220 r
= asprintf(&id
, "+%s:%s", subsystem
, sysname
);
1225 device
->id_filename
= id
;
1229 *ret
= device
->id_filename
;
1234 int device_read_db_aux(sd_device
*device
, bool force
) {
1235 _cleanup_free_
char *db
= NULL
;
1237 const char *id
, *value
;
1251 if (device
->db_loaded
|| (!force
&& device
->sealed
))
1254 device
->db_loaded
= true;
1256 r
= device_get_id_filename(device
, &id
);
1260 path
= strjoina("/run/udev/data/", id
);
1262 r
= read_full_file(path
, &db
, &db_len
);
1267 log_debug("sd-device: failed to read db '%s': %s", path
, strerror(-r
));
1272 /* devices with a database entry are initialized */
1273 device
->is_initialized
= true;;
1275 for (i
= 0; i
< db_len
; i
++) {
1278 if (!strchr(NEWLINE
, db
[i
])) {
1287 log_debug("sd-device: ignoring invalid db entry with key '%c'", key
);
1289 state
= INVALID_LINE
;
1304 if (strchr(NEWLINE
, db
[i
]))
1309 if (strchr(NEWLINE
, db
[i
])) {
1311 r
= handle_db_line(device
, key
, value
);
1313 log_debug("sd-device: failed to handle db entry '%c:%s': %s", key
, value
, strerror(-r
));
1320 assert_not_reached("invalid state when parsing db");
1327 static int device_read_db(sd_device
*device
) {
1328 return device_read_db_aux(device
, false);
1331 _public_
int sd_device_get_is_initialized(sd_device
*device
, int *initialized
) {
1334 assert_return(device
, -EINVAL
);
1335 assert_return(initialized
, -EINVAL
);
1337 r
= device_read_db(device
);
1341 *initialized
= device
->is_initialized
;
1346 _public_
int sd_device_get_usec_since_initialized(sd_device
*device
, uint64_t *usec
) {
1350 assert_return(device
, -EINVAL
);
1351 assert_return(usec
, -EINVAL
);
1353 r
= device_read_db(device
);
1357 if (!device
->is_initialized
)
1360 if (!device
->usec_initialized
)
1363 now_ts
= now(clock_boottime_or_monotonic());
1365 if (now_ts
< device
->usec_initialized
)
1368 *usec
= now_ts
- device
->usec_initialized
;
1373 _public_
const char *sd_device_get_tag_first(sd_device
*device
) {
1374 assert_return(device
, NULL
);
1376 (void) device_read_db(device
);
1378 device
->tags_iterator_generation
= device
->tags_generation
;
1379 device
->tags_iterator
= ITERATOR_FIRST
;
1381 return set_iterate(device
->tags
, &device
->tags_iterator
);
1384 _public_
const char *sd_device_get_tag_next(sd_device
*device
) {
1385 assert_return(device
, NULL
);
1387 (void) device_read_db(device
);
1389 if (device
->tags_iterator_generation
!= device
->tags_generation
)
1392 return set_iterate(device
->tags
, &device
->tags_iterator
);
1395 _public_
const char *sd_device_get_devlink_first(sd_device
*device
) {
1396 assert_return(device
, NULL
);
1398 (void) device_read_db(device
);
1400 device
->devlinks_iterator_generation
= device
->devlinks_generation
;
1401 device
->devlinks_iterator
= ITERATOR_FIRST
;
1403 return set_iterate(device
->devlinks
, &device
->devlinks_iterator
);
1406 _public_
const char *sd_device_get_devlink_next(sd_device
*device
) {
1407 assert_return(device
, NULL
);
1409 (void) device_read_db(device
);
1411 if (device
->devlinks_iterator_generation
!= device
->devlinks_generation
)
1414 return set_iterate(device
->devlinks
, &device
->devlinks_iterator
);
1417 static int device_properties_prepare(sd_device
*device
) {
1422 r
= device_read_uevent_file(device
);
1426 r
= device_read_db(device
);
1430 if (device
->property_devlinks_outdated
) {
1431 char *devlinks
= NULL
;
1432 const char *devlink
;
1434 devlink
= sd_device_get_devlink_first(device
);
1436 devlinks
= strdupa(devlink
);
1438 while ((devlink
= sd_device_get_devlink_next(device
)))
1439 devlinks
= strjoina(devlinks
, " ", devlink
);
1441 r
= device_add_property_internal(device
, "DEVLINKS", devlinks
);
1445 device
->property_devlinks_outdated
= false;
1448 if (device
->property_tags_outdated
) {
1452 tag
= sd_device_get_tag_first(device
);
1454 tags
= strjoina(":", tag
);
1456 while ((tag
= sd_device_get_tag_next(device
)))
1457 tags
= strjoina(tags
, ":", tag
);
1459 tags
= strjoina(tags
, ":");
1461 r
= device_add_property_internal(device
, "TAGS", tags
);
1465 device
->property_tags_outdated
= false;
1471 _public_
const char *sd_device_get_property_first(sd_device
*device
, const char **_value
) {
1476 assert_return(device
, NULL
);
1478 r
= device_properties_prepare(device
);
1482 device
->properties_iterator_generation
= device
->properties_generation
;
1483 device
->properties_iterator
= ITERATOR_FIRST
;
1485 value
= ordered_hashmap_iterate(device
->properties
, &device
->properties_iterator
, (const void**)&key
);
1493 _public_
const char *sd_device_get_property_next(sd_device
*device
, const char **_value
) {
1498 assert_return(device
, NULL
);
1500 r
= device_properties_prepare(device
);
1504 if (device
->properties_iterator_generation
!= device
->properties_generation
)
1507 value
= ordered_hashmap_iterate(device
->properties
, &device
->properties_iterator
, (const void**)&key
);
1515 static int device_sysattrs_read_all(sd_device
*device
) {
1516 _cleanup_closedir_
DIR *dir
= NULL
;
1517 const char *syspath
;
1518 struct dirent
*dent
;
1523 if (device
->sysattrs_read
)
1526 r
= sd_device_get_syspath(device
, &syspath
);
1530 dir
= opendir(syspath
);
1534 r
= set_ensure_allocated(&device
->sysattrs
, &string_hash_ops
);
1538 for (dent
= readdir(dir
); dent
!= NULL
; dent
= readdir(dir
)) {
1540 struct stat statbuf
;
1542 /* only handle symlinks and regular files */
1543 if (dent
->d_type
!= DT_LNK
&& dent
->d_type
!= DT_REG
)
1546 path
= strjoina(syspath
, "/", dent
->d_name
);
1548 if (lstat(path
, &statbuf
) != 0)
1551 if (!(statbuf
.st_mode
& S_IRUSR
))
1554 r
= set_put_strdup(device
->sysattrs
, dent
->d_name
);
1559 device
->sysattrs_read
= true;
1564 _public_
const char *sd_device_get_sysattr_first(sd_device
*device
) {
1567 assert_return(device
, NULL
);
1569 if (!device
->sysattrs_read
) {
1570 r
= device_sysattrs_read_all(device
);
1577 device
->sysattrs_iterator
= ITERATOR_FIRST
;
1579 return set_iterate(device
->sysattrs
, &device
->sysattrs_iterator
);
1582 _public_
const char *sd_device_get_sysattr_next(sd_device
*device
) {
1583 assert_return(device
, NULL
);
1585 if (!device
->sysattrs_read
)
1588 return set_iterate(device
->sysattrs
, &device
->sysattrs_iterator
);
1591 _public_
int sd_device_has_tag(sd_device
*device
, const char *tag
) {
1592 assert_return(device
, -EINVAL
);
1593 assert_return(tag
, -EINVAL
);
1595 (void) device_read_db(device
);
1597 return !!set_contains(device
->tags
, tag
);
1600 _public_
int sd_device_get_property_value(sd_device
*device
, const char *key
, const char **_value
) {
1604 assert_return(device
, -EINVAL
);
1605 assert_return(key
, -EINVAL
);
1606 assert_return(_value
, -EINVAL
);
1608 r
= device_properties_prepare(device
);
1612 value
= ordered_hashmap_get(device
->properties
, key
);
1621 /* replaces the value if it already exists */
1622 static int device_add_sysattr_value(sd_device
*device
, const char *_key
, char *value
) {
1623 _cleanup_free_
char *key
= NULL
;
1624 _cleanup_free_
char *value_old
= NULL
;
1630 r
= hashmap_ensure_allocated(&device
->sysattr_values
, &string_hash_ops
);
1634 value_old
= hashmap_remove2(device
->sysattr_values
, _key
, (void **)&key
);
1641 r
= hashmap_put(device
->sysattr_values
, key
, value
);
1650 static int device_get_sysattr_value(sd_device
*device
, const char *_key
, const char **_value
) {
1651 const char *key
= NULL
, *value
;
1656 value
= hashmap_get2(device
->sysattr_values
, _key
, (void **) &key
);
1666 /* We cache all sysattr lookups. If an attribute does not exist, it is stored
1667 * with a NULL value in the cache, otherwise the returned string is stored */
1668 _public_
int sd_device_get_sysattr_value(sd_device
*device
, const char *sysattr
, const char **_value
) {
1669 _cleanup_free_
char *value
= NULL
;
1670 const char *syspath
, *cached_value
= NULL
;
1672 struct stat statbuf
;
1675 assert_return(device
, -EINVAL
);
1676 assert_return(sysattr
, -EINVAL
);
1678 /* look for possibly already cached result */
1679 r
= device_get_sysattr_value(device
, sysattr
, &cached_value
);
1685 /* we looked up the sysattr before and it did not exist */
1689 *_value
= cached_value
;
1694 r
= sd_device_get_syspath(device
, &syspath
);
1698 path
= strjoina(syspath
, "/", sysattr
);
1699 r
= lstat(path
, &statbuf
);
1701 /* remember that we could not access the sysattr */
1702 r
= device_add_sysattr_value(device
, sysattr
, NULL
);
1707 } else if (S_ISLNK(statbuf
.st_mode
)) {
1708 /* Some core links return only the last element of the target path,
1709 * these are just values, the paths should not be exposed. */
1710 if (STR_IN_SET(sysattr
, "driver", "subsystem", "module")) {
1711 r
= readlink_value(path
, &value
);
1716 } else if (S_ISDIR(statbuf
.st_mode
)) {
1717 /* skip directories */
1719 } else if (!(statbuf
.st_mode
& S_IRUSR
)) {
1720 /* skip non-readable files */
1725 /* read attribute value */
1726 r
= read_full_file(path
, &value
, &size
);
1730 /* drop trailing newlines */
1731 while (size
> 0 && value
[--size
] == '\n')
1735 r
= device_add_sysattr_value(device
, sysattr
, value
);
1745 static void device_remove_sysattr_value(sd_device
*device
, const char *_key
) {
1746 _cleanup_free_
char *key
= NULL
;
1747 _cleanup_free_
char *value
= NULL
;
1752 value
= hashmap_remove2(device
->sysattr_values
, _key
, (void **) &key
);
1757 /* set the attribute and save it in the cache. If a NULL value is passed the
1758 * attribute is cleared from the cache */
1759 _public_
int sd_device_set_sysattr_value(sd_device
*device
, const char *sysattr
, char *_value
) {
1760 _cleanup_close_
int fd
= -1;
1761 _cleanup_free_
char *value
= NULL
;
1762 const char *syspath
;
1764 struct stat statbuf
;
1765 size_t value_len
= 0;
1769 assert_return(device
, -EINVAL
);
1770 assert_return(sysattr
, -EINVAL
);
1773 device_remove_sysattr_value(device
, sysattr
);
1778 r
= sd_device_get_syspath(device
, &syspath
);
1782 path
= strjoina(syspath
, "/", sysattr
);
1783 r
= lstat(path
, &statbuf
);
1789 r
= device_add_sysattr_value(device
, sysattr
, value
);
1796 if (S_ISLNK(statbuf
.st_mode
))
1799 /* skip directories */
1800 if (S_ISDIR(statbuf
.st_mode
))
1803 /* skip non-readable files */
1804 if ((statbuf
.st_mode
& S_IRUSR
) == 0)
1807 value_len
= strlen(_value
);
1809 /* drop trailing newlines */
1810 while (value_len
> 0 && _value
[value_len
- 1] == '\n')
1811 _value
[--value_len
] = '\0';
1813 /* value length is limited to 4k */
1814 if (value_len
> 4096)
1817 fd
= open(path
, O_WRONLY
| O_CLOEXEC
);
1821 value
= strdup(_value
);
1825 size
= write(fd
, value
, value_len
);
1829 if ((size_t)size
!= value_len
)
1832 r
= device_add_sysattr_value(device
, sysattr
, value
);