]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd/sd-device/sd-device.c
systemd-nspawn@.service: start after /var/lib/machines is mounted (#6079)
[thirdparty/systemd.git] / src / libsystemd / sd-device / sd-device.c
CommitLineData
57fa1d09
TG
1/***
2 This file is part of systemd.
3
4 Copyright 2008-2012 Kay Sievers <kay@vrfy.org>
5 Copyright 2014 Tom Gundersen <teg@jklm.no>
6
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.
11
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.
16
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/>.
19***/
20
21#include <ctype.h>
57fa1d09 22#include <net/if.h>
07630cea 23#include <sys/types.h>
57fa1d09 24
07630cea
LP
25#include "sd-device.h"
26
b5efdb8a 27#include "alloc-util.h"
07630cea
LP
28#include "device-internal.h"
29#include "device-private.h"
30#include "device-util.h"
8fb3f009 31#include "dirent-util.h"
3ffd4af2 32#include "fd-util.h"
57fa1d09 33#include "fileio.h"
f4f15635 34#include "fs-util.h"
57fa1d09 35#include "hashmap.h"
07630cea 36#include "macro.h"
6bedfcbb 37#include "parse-util.h"
07630cea 38#include "path-util.h"
57fa1d09 39#include "set.h"
429b4350 40#include "socket-util.h"
8fcde012 41#include "stat-util.h"
07630cea 42#include "string-util.h"
57fa1d09 43#include "strv.h"
07630cea
LP
44#include "strxcpyx.h"
45#include "util.h"
57fa1d09
TG
46
47int device_new_aux(sd_device **ret) {
4afd3348 48 _cleanup_(sd_device_unrefp) sd_device *device = NULL;
57fa1d09
TG
49
50 assert(ret);
51
52 device = new0(sd_device, 1);
53 if (!device)
54 return -ENOMEM;
55
56 device->n_ref = 1;
57 device->watch_handle = -1;
58
59 *ret = device;
60 device = NULL;
61
62 return 0;
63}
64
65_public_ sd_device *sd_device_ref(sd_device *device) {
66 if (device)
67 assert_se(++ device->n_ref >= 2);
68
69 return device;
70}
71
72_public_ sd_device *sd_device_unref(sd_device *device) {
73 if (device && -- device->n_ref == 0) {
74 sd_device_unref(device->parent);
75 free(device->syspath);
76 free(device->sysname);
77 free(device->devtype);
78 free(device->devname);
79 free(device->subsystem);
de7e983e 80 free(device->driver_subsystem);
57fa1d09
TG
81 free(device->driver);
82 free(device->id_filename);
83 free(device->properties_strv);
84 free(device->properties_nulstr);
85
86 ordered_hashmap_free_free_free(device->properties);
87 ordered_hashmap_free_free_free(device->properties_db);
88 hashmap_free_free_free(device->sysattr_values);
89 set_free_free(device->sysattrs);
90 set_free_free(device->tags);
91 set_free_free(device->devlinks);
92
93 free(device);
94 }
95
96 return NULL;
97}
98
99int device_add_property_aux(sd_device *device, const char *_key, const char *_value, bool db) {
100 OrderedHashmap **properties;
101
102 assert(device);
103 assert(_key);
104
105 if (db)
106 properties = &device->properties_db;
107 else
108 properties = &device->properties;
109
110 if (_value) {
111 _cleanup_free_ char *key = NULL, *value = NULL, *old_key = NULL, *old_value = NULL;
112 int r;
113
114 r = ordered_hashmap_ensure_allocated(properties, &string_hash_ops);
115 if (r < 0)
116 return r;
117
118 key = strdup(_key);
119 if (!key)
120 return -ENOMEM;
121
122 value = strdup(_value);
123 if (!value)
124 return -ENOMEM;
125
126 old_value = ordered_hashmap_get2(*properties, key, (void**) &old_key);
127
128 r = ordered_hashmap_replace(*properties, key, value);
129 if (r < 0)
130 return r;
131
132 key = NULL;
133 value = NULL;
134 } else {
135 _cleanup_free_ char *key = NULL;
136 _cleanup_free_ char *value = NULL;
137
138 value = ordered_hashmap_remove2(*properties, _key, (void**) &key);
139 }
140
141 if (!db) {
313cefa1 142 device->properties_generation++;
57fa1d09
TG
143 device->properties_buf_outdated = true;
144 }
145
146 return 0;
147}
148
149int device_add_property_internal(sd_device *device, const char *key, const char *value) {
150 return device_add_property_aux(device, key, value, false);
151}
152
153int device_set_syspath(sd_device *device, const char *_syspath, bool verify) {
154 _cleanup_free_ char *syspath = NULL;
155 const char *devpath;
156 int r;
157
158 assert(device);
159 assert(_syspath);
160
161 /* must be a subdirectory of /sys */
162 if (!path_startswith(_syspath, "/sys/")) {
163 log_debug("sd-device: syspath '%s' is not a subdirectory of /sys", _syspath);
164 return -EINVAL;
165 }
166
167 if (verify) {
e1873695 168 r = readlink_and_canonicalize(_syspath, NULL, &syspath);
08232a02
TG
169 if (r == -ENOENT)
170 /* the device does not exist (any more?) */
171 return -ENODEV;
172 else if (r == -EINVAL) {
57fa1d09
TG
173 /* not a symlink */
174 syspath = canonicalize_file_name(_syspath);
175 if (!syspath) {
08232a02
TG
176 if (errno == ENOENT)
177 /* the device does not exist (any more?) */
178 return -ENODEV;
179
e53fc357 180 return log_debug_errno(errno, "sd-device: could not canonicalize '%s': %m", _syspath);
57fa1d09 181 }
08232a02 182 } else if (r < 0) {
23446f01 183 log_debug_errno(r, "sd-device: could not get target of '%s': %m", _syspath);
57fa1d09
TG
184 return r;
185 }
186
187 if (path_startswith(syspath, "/sys/devices/")) {
188 char *path;
189
190 /* all 'devices' require an 'uevent' file */
191 path = strjoina(syspath, "/uevent");
192 r = access(path, F_OK);
193 if (r < 0) {
52d62901
TG
194 if (errno == ENOENT)
195 /* this is not a valid device */
196 return -ENODEV;
197
25f027c5 198 return log_debug_errno(errno, "sd-device: %s does not have an uevent file: %m", syspath);
57fa1d09
TG
199 }
200 } else {
61233823 201 /* everything else just needs to be a directory */
52d62901
TG
202 if (!is_dir(syspath, false))
203 return -ENODEV;
57fa1d09
TG
204 }
205 } else {
206 syspath = strdup(_syspath);
207 if (!syspath)
208 return -ENOMEM;
209 }
210
211 devpath = syspath + strlen("/sys");
212
213 r = device_add_property_internal(device, "DEVPATH", devpath);
214 if (r < 0)
215 return r;
216
217 free(device->syspath);
218 device->syspath = syspath;
219 syspath = NULL;
220
221 device->devpath = devpath;
222
223 return 0;
224}
225
226_public_ int sd_device_new_from_syspath(sd_device **ret, const char *syspath) {
4afd3348 227 _cleanup_(sd_device_unrefp) sd_device *device = NULL;
57fa1d09
TG
228 int r;
229
230 assert_return(ret, -EINVAL);
231 assert_return(syspath, -EINVAL);
232
233 r = device_new_aux(&device);
234 if (r < 0)
235 return r;
236
237 r = device_set_syspath(device, syspath, true);
238 if (r < 0)
239 return r;
240
241 *ret = device;
242 device = NULL;
243
244 return 0;
245}
246
247_public_ int sd_device_new_from_devnum(sd_device **ret, char type, dev_t devnum) {
248 char *syspath;
249 char id[DECIMAL_STR_MAX(unsigned) * 2 + 1];
250
251 assert_return(ret, -EINVAL);
252 assert_return(type == 'b' || type == 'c', -EINVAL);
253
254 /* use /sys/dev/{block,char}/<maj>:<min> link */
255 snprintf(id, sizeof(id), "%u:%u", major(devnum), minor(devnum));
256
257 syspath = strjoina("/sys/dev/", (type == 'b' ? "block" : "char"), "/", id);
258
259 return sd_device_new_from_syspath(ret, syspath);
260}
261
262_public_ int sd_device_new_from_subsystem_sysname(sd_device **ret, const char *subsystem, const char *sysname) {
21d6220f
TG
263 char *name, *syspath;
264 size_t len = 0;
57fa1d09
TG
265
266 assert_return(ret, -EINVAL);
267 assert_return(subsystem, -EINVAL);
268 assert_return(sysname, -EINVAL);
269
270 if (streq(subsystem, "subsystem")) {
271 syspath = strjoina("/sys/subsystem/", sysname);
272 if (access(syspath, F_OK) >= 0)
273 return sd_device_new_from_syspath(ret, syspath);
274
275 syspath = strjoina("/sys/bus/", sysname);
276 if (access(syspath, F_OK) >= 0)
277 return sd_device_new_from_syspath(ret, syspath);
278
279 syspath = strjoina("/sys/class/", sysname);
280 if (access(syspath, F_OK) >= 0)
281 return sd_device_new_from_syspath(ret, syspath);
282 } else if (streq(subsystem, "module")) {
283 syspath = strjoina("/sys/module/", sysname);
284 if (access(syspath, F_OK) >= 0)
285 return sd_device_new_from_syspath(ret, syspath);
286 } else if (streq(subsystem, "drivers")) {
287 char subsys[PATH_MAX];
288 char *driver;
289
290 strscpy(subsys, sizeof(subsys), sysname);
291 driver = strchr(subsys, ':');
292 if (driver) {
293 driver[0] = '\0';
294 driver++;
295
296 syspath = strjoina("/sys/subsystem/", subsys, "/drivers/", driver);
297 if (access(syspath, F_OK) >= 0)
298 return sd_device_new_from_syspath(ret, syspath);
299
300 syspath = strjoina("/sys/bus/", subsys, "/drivers/", driver);
301 if (access(syspath, F_OK) >= 0)
302 return sd_device_new_from_syspath(ret, syspath);
21d6220f
TG
303 }
304 }
a9ec9f29 305
21d6220f
TG
306 /* translate sysname back to sysfs filename */
307 name = strdupa(sysname);
308 while (name[len] != '\0') {
309 if (name[len] == '/')
310 name[len] = '!';
a9ec9f29 311
21d6220f
TG
312 len++;
313 }
a9ec9f29 314
21d6220f
TG
315 syspath = strjoina("/sys/subsystem/", subsystem, "/devices/", name);
316 if (access(syspath, F_OK) >= 0)
317 return sd_device_new_from_syspath(ret, syspath);
57fa1d09 318
21d6220f
TG
319 syspath = strjoina("/sys/bus/", subsystem, "/devices/", name);
320 if (access(syspath, F_OK) >= 0)
321 return sd_device_new_from_syspath(ret, syspath);
57fa1d09 322
21d6220f
TG
323 syspath = strjoina("/sys/class/", subsystem, "/", name);
324 if (access(syspath, F_OK) >= 0)
325 return sd_device_new_from_syspath(ret, syspath);
57fa1d09 326
08232a02 327 return -ENODEV;
57fa1d09
TG
328}
329
330int device_set_devtype(sd_device *device, const char *_devtype) {
331 _cleanup_free_ char *devtype = NULL;
332 int r;
333
334 assert(device);
335 assert(_devtype);
336
337 devtype = strdup(_devtype);
338 if (!devtype)
339 return -ENOMEM;
340
341 r = device_add_property_internal(device, "DEVTYPE", devtype);
342 if (r < 0)
343 return r;
344
345 free(device->devtype);
346 device->devtype = devtype;
347 devtype = NULL;
348
349 return 0;
350}
351
352int device_set_ifindex(sd_device *device, const char *_ifindex) {
353 int ifindex, r;
354
355 assert(device);
356 assert(_ifindex);
357
6ad623a3 358 r = parse_ifindex(_ifindex, &ifindex);
57fa1d09
TG
359 if (r < 0)
360 return r;
361
57fa1d09
TG
362 r = device_add_property_internal(device, "IFINDEX", _ifindex);
363 if (r < 0)
364 return r;
365
366 device->ifindex = ifindex;
367
368 return 0;
369}
370
371int device_set_devname(sd_device *device, const char *_devname) {
372 _cleanup_free_ char *devname = NULL;
373 int r;
374
375 assert(device);
376 assert(_devname);
377
378 if (_devname[0] != '/') {
379 r = asprintf(&devname, "/dev/%s", _devname);
380 if (r < 0)
381 return -ENOMEM;
382 } else {
383 devname = strdup(_devname);
384 if (!devname)
385 return -ENOMEM;
386 }
387
388 r = device_add_property_internal(device, "DEVNAME", devname);
389 if (r < 0)
390 return r;
391
392 free(device->devname);
393 device->devname = devname;
394 devname = NULL;
395
396 return 0;
397}
398
399int device_set_devmode(sd_device *device, const char *_devmode) {
400 unsigned devmode;
401 int r;
402
403 assert(device);
404 assert(_devmode);
405
406 r = safe_atou(_devmode, &devmode);
407 if (r < 0)
408 return r;
409
410 if (devmode > 07777)
411 return -EINVAL;
412
413 r = device_add_property_internal(device, "DEVMODE", _devmode);
414 if (r < 0)
415 return r;
416
417 device->devmode = devmode;
418
419 return 0;
420}
421
422int device_set_devnum(sd_device *device, const char *major, const char *minor) {
423 unsigned maj = 0, min = 0;
424 int r;
425
426 assert(device);
427 assert(major);
428
429 r = safe_atou(major, &maj);
430 if (r < 0)
431 return r;
432 if (!maj)
433 return 0;
434
435 if (minor) {
436 r = safe_atou(minor, &min);
437 if (r < 0)
438 return r;
439 }
440
441 r = device_add_property_internal(device, "MAJOR", major);
442 if (r < 0)
443 return r;
444
445 if (minor) {
446 r = device_add_property_internal(device, "MINOR", minor);
447 if (r < 0)
448 return r;
449 }
450
451 device->devnum = makedev(maj, min);
452
453 return 0;
454}
455
456static int handle_uevent_line(sd_device *device, const char *key, const char *value, const char **major, const char **minor) {
457 int r;
458
459 assert(device);
460 assert(key);
461 assert(value);
462 assert(major);
463 assert(minor);
464
465 if (streq(key, "DEVTYPE")) {
466 r = device_set_devtype(device, value);
467 if (r < 0)
468 return r;
469 } else if (streq(key, "IFINDEX")) {
470 r = device_set_ifindex(device, value);
471 if (r < 0)
472 return r;
473 } else if (streq(key, "DEVNAME")) {
474 r = device_set_devname(device, value);
475 if (r < 0)
476 return r;
477 } else if (streq(key, "DEVMODE")) {
478 r = device_set_devmode(device, value);
479 if (r < 0)
480 return r;
481 } else if (streq(key, "MAJOR"))
482 *major = value;
483 else if (streq(key, "MINOR"))
484 *minor = value;
485 else {
486 r = device_add_property_internal(device, key, value);
487 if (r < 0)
488 return r;
489 }
490
491 return 0;
492}
493
494int device_read_uevent_file(sd_device *device) {
495 _cleanup_free_ char *uevent = NULL;
97c94b98 496 const char *syspath, *key = NULL, *value = NULL, *major = NULL, *minor = NULL;
57fa1d09
TG
497 char *path;
498 size_t uevent_len;
499 unsigned i;
500 int r;
501
502 enum {
503 PRE_KEY,
504 KEY,
505 PRE_VALUE,
506 VALUE,
507 INVALID_LINE,
508 } state = PRE_KEY;
509
510 assert(device);
511
512 if (device->uevent_loaded || device->sealed)
513 return 0;
514
7141e4f6
TG
515 device->uevent_loaded = true;
516
57fa1d09
TG
517 r = sd_device_get_syspath(device, &syspath);
518 if (r < 0)
519 return r;
520
521 path = strjoina(syspath, "/uevent");
522
523 r = read_full_file(path, &uevent, &uevent_len);
bba06166
TG
524 if (r == -EACCES)
525 /* empty uevent files may be write-only */
526 return 0;
2a213740
TG
527 else if (r == -ENOENT)
528 /* some devices may not have uevent files, see set_syspath() */
529 return 0;
bba06166 530 else if (r < 0) {
e53fc357 531 log_debug_errno(r, "sd-device: failed to read uevent file '%s': %m", path);
57fa1d09
TG
532 return r;
533 }
534
755700bb 535 for (i = 0; i < uevent_len; i++)
57fa1d09
TG
536 switch (state) {
537 case PRE_KEY:
538 if (!strchr(NEWLINE, uevent[i])) {
539 key = &uevent[i];
540
541 state = KEY;
542 }
543
544 break;
545 case KEY:
546 if (uevent[i] == '=') {
547 uevent[i] = '\0';
548
549 state = PRE_VALUE;
550 } else if (strchr(NEWLINE, uevent[i])) {
551 uevent[i] = '\0';
552 log_debug("sd-device: ignoring invalid uevent line '%s'", key);
553
554 state = PRE_KEY;
555 }
556
557 break;
558 case PRE_VALUE:
559 value = &uevent[i];
57fa1d09
TG
560 state = VALUE;
561
ec251fe7 562 /* fall through */ /* to handle empty property */
57fa1d09
TG
563 case VALUE:
564 if (strchr(NEWLINE, uevent[i])) {
565 uevent[i] = '\0';
566
567 r = handle_uevent_line(device, key, value, &major, &minor);
568 if (r < 0)
19c29853 569 log_debug_errno(r, "sd-device: failed to handle uevent entry '%s=%s': %m", key, value);
57fa1d09
TG
570
571 state = PRE_KEY;
572 }
573
574 break;
575 default:
576 assert_not_reached("invalid state when parsing uevent file");
577 }
57fa1d09
TG
578
579 if (major) {
580 r = device_set_devnum(device, major, minor);
581 if (r < 0)
23446f01 582 log_debug_errno(r, "sd-device: could not set 'MAJOR=%s' or 'MINOR=%s' from '%s': %m", major, minor, path);
57fa1d09
TG
583 }
584
57fa1d09
TG
585 return 0;
586}
587
588_public_ int sd_device_get_ifindex(sd_device *device, int *ifindex) {
589 int r;
590
591 assert_return(device, -EINVAL);
592 assert_return(ifindex, -EINVAL);
593
594 r = device_read_uevent_file(device);
595 if (r < 0)
596 return r;
597
598 *ifindex = device->ifindex;
599
600 return 0;
601}
602
603_public_ int sd_device_new_from_device_id(sd_device **ret, const char *id) {
604 int r;
605
606 assert_return(ret, -EINVAL);
607 assert_return(id, -EINVAL);
608
609 switch (id[0]) {
610 case 'b':
611 case 'c':
612 {
613 char type;
614 int maj, min;
615
616 r = sscanf(id, "%c%i:%i", &type, &maj, &min);
617 if (r != 3)
618 return -EINVAL;
619
620 return sd_device_new_from_devnum(ret, type, makedev(maj, min));
621 }
622 case 'n':
623 {
4afd3348 624 _cleanup_(sd_device_unrefp) sd_device *device = NULL;
57fa1d09
TG
625 _cleanup_close_ int sk = -1;
626 struct ifreq ifr = {};
627 int ifindex;
628
6ad623a3 629 r = parse_ifindex(&id[1], &ifr.ifr_ifindex);
57fa1d09
TG
630 if (r < 0)
631 return r;
57fa1d09 632
429b4350 633 sk = socket_ioctl_fd();
57fa1d09 634 if (sk < 0)
429b4350 635 return sk;
57fa1d09
TG
636
637 r = ioctl(sk, SIOCGIFNAME, &ifr);
638 if (r < 0)
639 return -errno;
640
641 r = sd_device_new_from_subsystem_sysname(&device, "net", ifr.ifr_name);
642 if (r < 0)
643 return r;
644
645 r = sd_device_get_ifindex(device, &ifindex);
646 if (r < 0)
647 return r;
648
08232a02 649 /* this is racey, so we might end up with the wrong device */
57fa1d09
TG
650 if (ifr.ifr_ifindex != ifindex)
651 return -ENODEV;
652
653 *ret = device;
654 device = NULL;
655
656 return 0;
657 }
658 case '+':
659 {
660 char subsys[PATH_MAX];
661 char *sysname;
662
663 (void)strscpy(subsys, sizeof(subsys), id + 1);
664 sysname = strchr(subsys, ':');
665 if (!sysname)
666 return -EINVAL;
667
668 sysname[0] = '\0';
313cefa1 669 sysname++;
57fa1d09
TG
670
671 return sd_device_new_from_subsystem_sysname(ret, subsys, sysname);
672 }
673 default:
674 return -EINVAL;
675 }
676}
677
678_public_ int sd_device_get_syspath(sd_device *device, const char **ret) {
679 assert_return(device, -EINVAL);
680 assert_return(ret, -EINVAL);
681
682 assert(path_startswith(device->syspath, "/sys/"));
683
684 *ret = device->syspath;
685
686 return 0;
687}
688
689static int device_new_from_child(sd_device **ret, sd_device *child) {
690 _cleanup_free_ char *path = NULL;
691 const char *subdir, *syspath;
692 int r;
693
694 assert(ret);
695 assert(child);
696
697 r = sd_device_get_syspath(child, &syspath);
698 if (r < 0)
699 return r;
700
701 path = strdup(syspath);
702 if (!path)
703 return -ENOMEM;
704 subdir = path + strlen("/sys");
705
706 for (;;) {
707 char *pos;
708
709 pos = strrchr(subdir, '/');
710 if (!pos || pos < subdir + 2)
711 break;
712
713 *pos = '\0';
714
715 r = sd_device_new_from_syspath(ret, path);
716 if (r < 0)
717 continue;
718
719 return 0;
720 }
721
08232a02 722 return -ENODEV;
57fa1d09
TG
723}
724
725_public_ int sd_device_get_parent(sd_device *child, sd_device **ret) {
726
727 assert_return(ret, -EINVAL);
728 assert_return(child, -EINVAL);
729
730 if (!child->parent_set) {
731 child->parent_set = true;
732
733 (void)device_new_from_child(&child->parent, child);
734 }
735
736 if (!child->parent)
737 return -ENOENT;
738
739 *ret = child->parent;
740
741 return 0;
742}
743
744int device_set_subsystem(sd_device *device, const char *_subsystem) {
745 _cleanup_free_ char *subsystem = NULL;
746 int r;
747
748 assert(device);
749 assert(_subsystem);
750
751 subsystem = strdup(_subsystem);
752 if (!subsystem)
753 return -ENOMEM;
754
755 r = device_add_property_internal(device, "SUBSYSTEM", subsystem);
756 if (r < 0)
757 return r;
758
759 free(device->subsystem);
760 device->subsystem = subsystem;
761 subsystem = NULL;
762
763 device->subsystem_set = true;
764
765 return 0;
766}
767
de7e983e
TG
768static int device_set_drivers_subsystem(sd_device *device, const char *_subsystem) {
769 _cleanup_free_ char *subsystem = NULL;
770 int r;
771
772 assert(device);
773 assert(_subsystem);
774 assert(*_subsystem);
775
776 subsystem = strdup(_subsystem);
777 if (!subsystem)
778 return -ENOMEM;
779
780 r = device_set_subsystem(device, "drivers");
781 if (r < 0)
782 return r;
783
784 free(device->driver_subsystem);
785 device->driver_subsystem = subsystem;
786 subsystem = NULL;
787
788 return 0;
789}
790
57fa1d09 791_public_ int sd_device_get_subsystem(sd_device *device, const char **ret) {
de7e983e
TG
792 const char *syspath, *drivers = NULL;
793 int r;
794
57fa1d09
TG
795 assert_return(ret, -EINVAL);
796 assert_return(device, -EINVAL);
797
de7e983e
TG
798 r = sd_device_get_syspath(device, &syspath);
799 if (r < 0)
800 return r;
801
57fa1d09
TG
802 if (!device->subsystem_set) {
803 _cleanup_free_ char *subsystem = NULL;
57fa1d09 804 char *path;
57fa1d09
TG
805
806 /* read 'subsystem' link */
57fa1d09
TG
807 path = strjoina(syspath, "/subsystem");
808 r = readlink_value(path, &subsystem);
809 if (r >= 0)
810 r = device_set_subsystem(device, subsystem);
811 /* use implicit names */
812 else if (path_startswith(device->devpath, "/module/"))
813 r = device_set_subsystem(device, "module");
de7e983e
TG
814 else if (!(drivers = strstr(syspath, "/drivers/")) &&
815 (path_startswith(device->devpath, "/subsystem/") ||
816 path_startswith(device->devpath, "/class/") ||
817 path_startswith(device->devpath, "/bus/")))
57fa1d09 818 r = device_set_subsystem(device, "subsystem");
4189708a 819 if (r < 0 && r != -ENOENT)
5a917c06 820 return log_debug_errno(r, "sd-device: could not set subsystem for %s: %m", device->devpath);
57fa1d09
TG
821
822 device->subsystem_set = true;
de7e983e
TG
823 } else if (!device->driver_subsystem_set)
824 drivers = strstr(syspath, "/drivers/");
825
826 if (!device->driver_subsystem_set) {
827 if (drivers) {
828 _cleanup_free_ char *subpath = NULL;
829
830 subpath = strndup(syspath, drivers - syspath);
831 if (!subpath)
832 r = -ENOMEM;
833 else {
834 const char *subsys;
835
836 subsys = strrchr(subpath, '/');
837 if (!subsys)
838 r = -EINVAL;
839 else
840 r = device_set_drivers_subsystem(device, subsys + 1);
841 }
842 if (r < 0 && r != -ENOENT)
843 return log_debug_errno(r, "sd-device: could not set subsystem for driver %s: %m", device->devpath);
844 }
845
846 device->driver_subsystem_set = true;
57fa1d09
TG
847 }
848
bf4c113e
DH
849 if (!device->subsystem)
850 return -ENOENT;
851
57fa1d09
TG
852 *ret = device->subsystem;
853
854 return 0;
855}
856
857_public_ int sd_device_get_devtype(sd_device *device, const char **devtype) {
858 int r;
859
860 assert(devtype);
861 assert(device);
862
863 r = device_read_uevent_file(device);
864 if (r < 0)
865 return r;
866
867 *devtype = device->devtype;
868
869 return 0;
870}
871
872_public_ int sd_device_get_parent_with_subsystem_devtype(sd_device *child, const char *subsystem, const char *devtype, sd_device **ret) {
873 sd_device *parent = NULL;
874 int r;
875
876 assert_return(child, -EINVAL);
877 assert_return(subsystem, -EINVAL);
878
879 r = sd_device_get_parent(child, &parent);
880 while (r >= 0) {
881 const char *parent_subsystem = NULL;
882 const char *parent_devtype = NULL;
883
884 (void)sd_device_get_subsystem(parent, &parent_subsystem);
885 if (streq_ptr(parent_subsystem, subsystem)) {
886 if (!devtype)
887 break;
888
889 (void)sd_device_get_devtype(parent, &parent_devtype);
890 if (streq_ptr(parent_devtype, devtype))
891 break;
892 }
893 r = sd_device_get_parent(parent, &parent);
894 }
895
896 if (r < 0)
897 return r;
898
899 *ret = parent;
900
901 return 0;
902}
903
904_public_ int sd_device_get_devnum(sd_device *device, dev_t *devnum) {
905 int r;
906
907 assert_return(device, -EINVAL);
908 assert_return(devnum, -EINVAL);
909
910 r = device_read_uevent_file(device);
911 if (r < 0)
912 return r;
913
914 *devnum = device->devnum;
915
916 return 0;
917}
918
919int device_set_driver(sd_device *device, const char *_driver) {
920 _cleanup_free_ char *driver = NULL;
921 int r;
922
923 assert(device);
924 assert(_driver);
925
926 driver = strdup(_driver);
927 if (!driver)
928 return -ENOMEM;
929
930 r = device_add_property_internal(device, "DRIVER", driver);
931 if (r < 0)
932 return r;
933
934 free(device->driver);
935 device->driver = driver;
936 driver = NULL;
937
938 device->driver_set = true;
939
940 return 0;
941}
942
943_public_ int sd_device_get_driver(sd_device *device, const char **ret) {
944 assert_return(device, -EINVAL);
945 assert_return(ret, -EINVAL);
946
947 if (!device->driver_set) {
948 _cleanup_free_ char *driver = NULL;
949 const char *syspath;
950 char *path;
951 int r;
952
953 r = sd_device_get_syspath(device, &syspath);
954 if (r < 0)
955 return r;
956
957 path = strjoina(syspath, "/driver");
958 r = readlink_value(path, &driver);
959 if (r >= 0) {
960 r = device_set_driver(device, driver);
961 if (r < 0)
7283a80d
TG
962 return log_debug_errno(r, "sd-device: could not set driver for %s: %m", device->devpath);
963 } else if (r == -ENOENT)
964 device->driver_set = true;
965 else
966 return log_debug_errno(r, "sd-device: could not set driver for %s: %m", device->devpath);
57fa1d09
TG
967 }
968
bf4c113e
DH
969 if (!device->driver)
970 return -ENOENT;
971
57fa1d09
TG
972 *ret = device->driver;
973
974 return 0;
975}
976
977_public_ int sd_device_get_devpath(sd_device *device, const char **devpath) {
978 assert_return(device, -EINVAL);
979 assert_return(devpath, -EINVAL);
980
981 assert(device->devpath);
982 assert(device->devpath[0] == '/');
983
984 *devpath = device->devpath;
985
986 return 0;
987}
988
989_public_ int sd_device_get_devname(sd_device *device, const char **devname) {
990 int r;
991
992 assert_return(device, -EINVAL);
993 assert_return(devname, -EINVAL);
994
995 r = device_read_uevent_file(device);
996 if (r < 0)
997 return r;
998
999 if (!device->devname)
1000 return -ENOENT;
1001
1002 assert(path_startswith(device->devname, "/dev/"));
1003
1004 *devname = device->devname;
1005
1006 return 0;
1007}
1008
1009static int device_set_sysname(sd_device *device) {
1010 _cleanup_free_ char *sysname = NULL;
afcac065 1011 const char *sysnum = NULL;
57fa1d09
TG
1012 const char *pos;
1013 size_t len = 0;
1014
1015 pos = strrchr(device->devpath, '/');
1016 if (!pos)
1017 return -EINVAL;
313cefa1 1018 pos++;
57fa1d09
TG
1019
1020 /* devpath is not a root directory */
1021 if (*pos == '\0' || pos <= device->devpath)
1022 return -EINVAL;
1023
1024 sysname = strdup(pos);
1025 if (!sysname)
1026 return -ENOMEM;
1027
1028 /* some devices have '!' in their name, change that to '/' */
1029 while (sysname[len] != '\0') {
1030 if (sysname[len] == '!')
1031 sysname[len] = '/';
1032
313cefa1 1033 len++;
57fa1d09
TG
1034 }
1035
1036 /* trailing number */
1037 while (len > 0 && isdigit(sysname[--len]))
1038 sysnum = &sysname[len];
1039
1040 if (len == 0)
1041 sysnum = NULL;
1042
1043 free(device->sysname);
1044 device->sysname = sysname;
1045 sysname = NULL;
1046
1047 device->sysnum = sysnum;
1048
1049 device->sysname_set = true;
1050
1051 return 0;
1052}
1053
1054_public_ int sd_device_get_sysname(sd_device *device, const char **ret) {
1055 int r;
1056
1057 assert_return(device, -EINVAL);
1058 assert_return(ret, -EINVAL);
1059
1060 if (!device->sysname_set) {
1061 r = device_set_sysname(device);
1062 if (r < 0)
1063 return r;
1064 }
1065
bf4c113e
DH
1066 assert_return(device->sysname, -ENOENT);
1067
57fa1d09
TG
1068 *ret = device->sysname;
1069
1070 return 0;
1071}
1072
1073_public_ int sd_device_get_sysnum(sd_device *device, const char **ret) {
1074 int r;
1075
1076 assert_return(device, -EINVAL);
1077 assert_return(ret, -EINVAL);
1078
1079 if (!device->sysname_set) {
1080 r = device_set_sysname(device);
1081 if (r < 0)
1082 return r;
1083 }
1084
1085 *ret = device->sysnum;
1086
1087 return 0;
1088}
1089
1090static bool is_valid_tag(const char *tag) {
1091 assert(tag);
1092
1093 return !strchr(tag, ':') && !strchr(tag, ' ');
1094}
1095
1096int device_add_tag(sd_device *device, const char *tag) {
1097 int r;
1098
1099 assert(device);
1100 assert(tag);
1101
1102 if (!is_valid_tag(tag))
1103 return -EINVAL;
1104
1105 r = set_ensure_allocated(&device->tags, &string_hash_ops);
1106 if (r < 0)
1107 return r;
1108
1109 r = set_put_strdup(device->tags, tag);
1110 if (r < 0)
1111 return r;
1112
313cefa1 1113 device->tags_generation++;
57fa1d09
TG
1114 device->property_tags_outdated = true;
1115
1116 return 0;
1117}
1118
1119int device_add_devlink(sd_device *device, const char *devlink) {
1120 int r;
1121
1122 assert(device);
1123 assert(devlink);
1124
1125 r = set_ensure_allocated(&device->devlinks, &string_hash_ops);
1126 if (r < 0)
1127 return r;
1128
1129 r = set_put_strdup(device->devlinks, devlink);
1130 if (r < 0)
1131 return r;
1132
313cefa1 1133 device->devlinks_generation++;
57fa1d09
TG
1134 device->property_devlinks_outdated = true;
1135
1136 return 0;
1137}
1138
1139static int device_add_property_internal_from_string(sd_device *device, const char *str) {
1140 _cleanup_free_ char *key = NULL;
1141 char *value;
1142
1143 assert(device);
1144 assert(str);
1145
1146 key = strdup(str);
1147 if (!key)
1148 return -ENOMEM;
1149
1150 value = strchr(key, '=');
1151 if (!value)
1152 return -EINVAL;
1153
1154 *value = '\0';
1155
1156 if (isempty(++value))
1157 value = NULL;
1158
1159 return device_add_property_internal(device, key, value);
1160}
1161
1162int device_set_usec_initialized(sd_device *device, const char *initialized) {
1163 uint64_t usec_initialized;
1164 int r;
1165
1166 assert(device);
1167 assert(initialized);
1168
1169 r = safe_atou64(initialized, &usec_initialized);
1170 if (r < 0)
1171 return r;
1172
1173 r = device_add_property_internal(device, "USEC_INITIALIZED", initialized);
1174 if (r < 0)
1175 return r;
1176
1177 device->usec_initialized = usec_initialized;
1178
1179 return 0;
1180}
1181
1182static int handle_db_line(sd_device *device, char key, const char *value) {
1183 char *path;
1184 int r;
1185
1186 assert(device);
1187 assert(value);
1188
1189 switch (key) {
1190 case 'G':
1191 r = device_add_tag(device, value);
1192 if (r < 0)
1193 return r;
1194
1195 break;
1196 case 'S':
1197 path = strjoina("/dev/", value);
1198 r = device_add_devlink(device, path);
1199 if (r < 0)
1200 return r;
1201
1202 break;
1203 case 'E':
1204 r = device_add_property_internal_from_string(device, value);
1205 if (r < 0)
1206 return r;
1207
1208 break;
1209 case 'I':
1210 r = device_set_usec_initialized(device, value);
1211 if (r < 0)
1212 return r;
1213
1214 break;
1215 case 'L':
1216 r = safe_atoi(value, &device->devlink_priority);
1217 if (r < 0)
1218 return r;
1219
1220 break;
1221 case 'W':
1222 r = safe_atoi(value, &device->watch_handle);
1223 if (r < 0)
1224 return r;
1225
1226 break;
1227 default:
1228 log_debug("device db: unknown key '%c'", key);
1229 }
1230
1231 return 0;
1232}
1233
1234int device_get_id_filename(sd_device *device, const char **ret) {
1235 assert(device);
1236 assert(ret);
1237
1238 if (!device->id_filename) {
1239 _cleanup_free_ char *id = NULL;
1240 const char *subsystem;
1241 dev_t devnum;
1242 int ifindex, r;
1243
1244 r = sd_device_get_subsystem(device, &subsystem);
1245 if (r < 0)
1246 return r;
1247
1248 r = sd_device_get_devnum(device, &devnum);
1249 if (r < 0)
1250 return r;
1251
1252 r = sd_device_get_ifindex(device, &ifindex);
1253 if (r < 0)
1254 return r;
1255
1256 if (major(devnum) > 0) {
4189708a
TG
1257 assert(subsystem);
1258
ccddd104 1259 /* use dev_t — b259:131072, c254:0 */
57fa1d09
TG
1260 r = asprintf(&id, "%c%u:%u",
1261 streq(subsystem, "block") ? 'b' : 'c',
1262 major(devnum), minor(devnum));
1263 if (r < 0)
53fae771 1264 return -ENOMEM;
57fa1d09 1265 } else if (ifindex > 0) {
ccddd104 1266 /* use netdev ifindex — n3 */
57fa1d09
TG
1267 r = asprintf(&id, "n%u", ifindex);
1268 if (r < 0)
53fae771 1269 return -ENOMEM;
57fa1d09 1270 } else {
ccddd104 1271 /* use $subsys:$sysname — pci:0000:00:1f.2
57fa1d09
TG
1272 * sysname() has '!' translated, get it from devpath
1273 */
1274 const char *sysname;
1275
1276 sysname = basename(device->devpath);
1277 if (!sysname)
4189708a
TG
1278 return -EINVAL;
1279
1280 if (!subsystem)
57fa1d09
TG
1281 return -EINVAL;
1282
de7e983e
TG
1283 if (streq(subsystem, "drivers")) {
1284 /* the 'drivers' pseudo-subsystem is special, and needs the real subsystem
1285 * encoded as well */
1286 r = asprintf(&id, "+drivers:%s:%s", device->driver_subsystem, sysname);
1287 if (r < 0)
1288 return -ENOMEM;
1289 } else {
1290 r = asprintf(&id, "+%s:%s", subsystem, sysname);
1291 if (r < 0)
1292 return -ENOMEM;
1293 }
57fa1d09
TG
1294 }
1295
1296 device->id_filename = id;
1297 id = NULL;
1298 }
1299
1300 *ret = device->id_filename;
1301
1302 return 0;
1303}
1304
107f2e25 1305int device_read_db_aux(sd_device *device, bool force) {
57fa1d09
TG
1306 _cleanup_free_ char *db = NULL;
1307 char *path;
1308 const char *id, *value;
1309 char key;
1310 size_t db_len;
1311 unsigned i;
1312 int r;
1313
1314 enum {
1315 PRE_KEY,
1316 KEY,
1317 PRE_VALUE,
1318 VALUE,
1319 INVALID_LINE,
1320 } state = PRE_KEY;
1321
107f2e25 1322 if (device->db_loaded || (!force && device->sealed))
57fa1d09
TG
1323 return 0;
1324
7141e4f6
TG
1325 device->db_loaded = true;
1326
57fa1d09
TG
1327 r = device_get_id_filename(device, &id);
1328 if (r < 0)
1329 return r;
1330
1331 path = strjoina("/run/udev/data/", id);
1332
1333 r = read_full_file(path, &db, &db_len);
1334 if (r < 0) {
1335 if (r == -ENOENT)
1336 return 0;
e53fc357
LP
1337 else
1338 return log_debug_errno(r, "sd-device: failed to read db '%s': %m", path);
57fa1d09
TG
1339 }
1340
1341 /* devices with a database entry are initialized */
7e518afa 1342 device->is_initialized = true;
57fa1d09
TG
1343
1344 for (i = 0; i < db_len; i++) {
1345 switch (state) {
1346 case PRE_KEY:
1347 if (!strchr(NEWLINE, db[i])) {
1348 key = db[i];
1349
1350 state = KEY;
1351 }
1352
1353 break;
1354 case KEY:
1355 if (db[i] != ':') {
1356 log_debug("sd-device: ignoring invalid db entry with key '%c'", key);
1357
1358 state = INVALID_LINE;
1359 } else {
1360 db[i] = '\0';
1361
1362 state = PRE_VALUE;
1363 }
1364
1365 break;
1366 case PRE_VALUE:
1367 value = &db[i];
1368
1369 state = VALUE;
1370
1371 break;
1372 case INVALID_LINE:
1373 if (strchr(NEWLINE, db[i]))
1374 state = PRE_KEY;
1375
1376 break;
1377 case VALUE:
1378 if (strchr(NEWLINE, db[i])) {
1379 db[i] = '\0';
1380 r = handle_db_line(device, key, value);
1381 if (r < 0)
19c29853 1382 log_debug_errno(r, "sd-device: failed to handle db entry '%c:%s': %m", key, value);
57fa1d09
TG
1383
1384 state = PRE_KEY;
1385 }
1386
1387 break;
1388 default:
1389 assert_not_reached("invalid state when parsing db");
1390 }
1391 }
1392
57fa1d09
TG
1393 return 0;
1394}
1395
107f2e25
TG
1396static int device_read_db(sd_device *device) {
1397 return device_read_db_aux(device, false);
1398}
1399
57fa1d09
TG
1400_public_ int sd_device_get_is_initialized(sd_device *device, int *initialized) {
1401 int r;
1402
1403 assert_return(device, -EINVAL);
1404 assert_return(initialized, -EINVAL);
1405
1406 r = device_read_db(device);
1407 if (r < 0)
1408 return r;
1409
1410 *initialized = device->is_initialized;
1411
1412 return 0;
1413}
1414
1415_public_ int sd_device_get_usec_since_initialized(sd_device *device, uint64_t *usec) {
1416 usec_t now_ts;
1417 int r;
1418
1419 assert_return(device, -EINVAL);
1420 assert_return(usec, -EINVAL);
1421
1422 r = device_read_db(device);
1423 if (r < 0)
1424 return r;
1425
1426 if (!device->is_initialized)
1427 return -EBUSY;
1428
1429 if (!device->usec_initialized)
1430 return -ENODATA;
1431
1432 now_ts = now(clock_boottime_or_monotonic());
1433
1434 if (now_ts < device->usec_initialized)
1435 return -EIO;
1436
1437 *usec = now_ts - device->usec_initialized;
1438
1439 return 0;
1440}
1441
1442_public_ const char *sd_device_get_tag_first(sd_device *device) {
8927b1da
DH
1443 void *v;
1444
57fa1d09
TG
1445 assert_return(device, NULL);
1446
1447 (void) device_read_db(device);
1448
1449 device->tags_iterator_generation = device->tags_generation;
1450 device->tags_iterator = ITERATOR_FIRST;
1451
bccfe92e 1452 (void) set_iterate(device->tags, &device->tags_iterator, &v);
8927b1da 1453 return v;
57fa1d09
TG
1454}
1455
1456_public_ const char *sd_device_get_tag_next(sd_device *device) {
8927b1da
DH
1457 void *v;
1458
57fa1d09
TG
1459 assert_return(device, NULL);
1460
1461 (void) device_read_db(device);
1462
1463 if (device->tags_iterator_generation != device->tags_generation)
1464 return NULL;
1465
bccfe92e 1466 (void) set_iterate(device->tags, &device->tags_iterator, &v);
8927b1da 1467 return v;
57fa1d09
TG
1468}
1469
1470_public_ const char *sd_device_get_devlink_first(sd_device *device) {
8927b1da
DH
1471 void *v;
1472
57fa1d09
TG
1473 assert_return(device, NULL);
1474
1475 (void) device_read_db(device);
1476
1477 device->devlinks_iterator_generation = device->devlinks_generation;
1478 device->devlinks_iterator = ITERATOR_FIRST;
1479
bccfe92e 1480 (void) set_iterate(device->devlinks, &device->devlinks_iterator, &v);
8927b1da 1481 return v;
57fa1d09
TG
1482}
1483
1484_public_ const char *sd_device_get_devlink_next(sd_device *device) {
8927b1da
DH
1485 void *v;
1486
57fa1d09
TG
1487 assert_return(device, NULL);
1488
1489 (void) device_read_db(device);
1490
1491 if (device->devlinks_iterator_generation != device->devlinks_generation)
1492 return NULL;
1493
bccfe92e 1494 (void) set_iterate(device->devlinks, &device->devlinks_iterator, &v);
8927b1da 1495 return v;
57fa1d09
TG
1496}
1497
1498static int device_properties_prepare(sd_device *device) {
1499 int r;
1500
1501 assert(device);
1502
1503 r = device_read_uevent_file(device);
1504 if (r < 0)
1505 return r;
1506
1507 r = device_read_db(device);
1508 if (r < 0)
1509 return r;
1510
1511 if (device->property_devlinks_outdated) {
1d88a271
MP
1512 _cleanup_free_ char *devlinks = NULL;
1513 size_t devlinks_allocated = 0, devlinks_len = 0;
57fa1d09
TG
1514 const char *devlink;
1515
1d88a271
MP
1516 for (devlink = sd_device_get_devlink_first(device); devlink; devlink = sd_device_get_devlink_next(device)) {
1517 char *e;
57fa1d09 1518
1d88a271
MP
1519 if (!GREEDY_REALLOC(devlinks, devlinks_allocated, devlinks_len + strlen(devlink) + 2))
1520 return -ENOMEM;
1521 if (devlinks_len > 0)
1522 stpcpy(devlinks + devlinks_len++, " ");
1523 e = stpcpy(devlinks + devlinks_len, devlink);
1524 devlinks_len = e - devlinks;
1525 }
57fa1d09
TG
1526
1527 r = device_add_property_internal(device, "DEVLINKS", devlinks);
1528 if (r < 0)
1529 return r;
1530
1531 device->property_devlinks_outdated = false;
1532 }
1533
1534 if (device->property_tags_outdated) {
1d88a271
MP
1535 _cleanup_free_ char *tags = NULL;
1536 size_t tags_allocated = 0, tags_len = 0;
57fa1d09
TG
1537 const char *tag;
1538
1d88a271
MP
1539 if (!GREEDY_REALLOC(tags, tags_allocated, 2))
1540 return -ENOMEM;
1541 stpcpy(tags, ":");
1542 tags_len++;
57fa1d09 1543
1d88a271
MP
1544 for (tag = sd_device_get_tag_first(device); tag; tag = sd_device_get_tag_next(device)) {
1545 char *e;
57fa1d09 1546
817ec8cc 1547 if (!GREEDY_REALLOC(tags, tags_allocated, tags_len + strlen(tag) + 2))
1d88a271
MP
1548 return -ENOMEM;
1549 e = stpcpy(stpcpy(tags + tags_len, tag), ":");
1550 tags_len = e - tags;
1551 }
57fa1d09
TG
1552
1553 r = device_add_property_internal(device, "TAGS", tags);
1554 if (r < 0)
1555 return r;
1556
1557 device->property_tags_outdated = false;
1558 }
1559
1560 return 0;
1561}
1562
1563_public_ const char *sd_device_get_property_first(sd_device *device, const char **_value) {
1564 const char *key;
1565 const char *value;
1566 int r;
1567
1568 assert_return(device, NULL);
1569
1570 r = device_properties_prepare(device);
1571 if (r < 0)
1572 return NULL;
1573
1574 device->properties_iterator_generation = device->properties_generation;
1575 device->properties_iterator = ITERATOR_FIRST;
1576
8927b1da 1577 ordered_hashmap_iterate(device->properties, &device->properties_iterator, (void**)&value, (const void**)&key);
57fa1d09
TG
1578
1579 if (_value)
1580 *_value = value;
1581
1582 return key;
1583}
1584
1585_public_ const char *sd_device_get_property_next(sd_device *device, const char **_value) {
1586 const char *key;
1587 const char *value;
1588 int r;
1589
1590 assert_return(device, NULL);
1591
1592 r = device_properties_prepare(device);
1593 if (r < 0)
1594 return NULL;
1595
1596 if (device->properties_iterator_generation != device->properties_generation)
1597 return NULL;
1598
8927b1da 1599 ordered_hashmap_iterate(device->properties, &device->properties_iterator, (void**)&value, (const void**)&key);
57fa1d09
TG
1600
1601 if (_value)
1602 *_value = value;
1603
1604 return key;
1605}
1606
1607static int device_sysattrs_read_all(sd_device *device) {
1608 _cleanup_closedir_ DIR *dir = NULL;
1609 const char *syspath;
1610 struct dirent *dent;
1611 int r;
1612
1613 assert(device);
1614
1615 if (device->sysattrs_read)
1616 return 0;
1617
1618 r = sd_device_get_syspath(device, &syspath);
1619 if (r < 0)
1620 return r;
1621
1622 dir = opendir(syspath);
1623 if (!dir)
1624 return -errno;
1625
1626 r = set_ensure_allocated(&device->sysattrs, &string_hash_ops);
1627 if (r < 0)
1628 return r;
1629
8fb3f009 1630 FOREACH_DIRENT_ALL(dent, dir, return -errno) {
57fa1d09
TG
1631 char *path;
1632 struct stat statbuf;
1633
1634 /* only handle symlinks and regular files */
1635 if (dent->d_type != DT_LNK && dent->d_type != DT_REG)
1636 continue;
1637
1638 path = strjoina(syspath, "/", dent->d_name);
1639
1640 if (lstat(path, &statbuf) != 0)
1641 continue;
1642
1643 if (!(statbuf.st_mode & S_IRUSR))
1644 continue;
1645
1646 r = set_put_strdup(device->sysattrs, dent->d_name);
1647 if (r < 0)
1648 return r;
1649 }
1650
1651 device->sysattrs_read = true;
1652
1653 return 0;
1654}
1655
1656_public_ const char *sd_device_get_sysattr_first(sd_device *device) {
8927b1da 1657 void *v;
57fa1d09
TG
1658 int r;
1659
1660 assert_return(device, NULL);
1661
1662 if (!device->sysattrs_read) {
1663 r = device_sysattrs_read_all(device);
1664 if (r < 0) {
1665 errno = -r;
1666 return NULL;
1667 }
1668 }
1669
1670 device->sysattrs_iterator = ITERATOR_FIRST;
1671
bccfe92e 1672 (void) set_iterate(device->sysattrs, &device->sysattrs_iterator, &v);
8927b1da 1673 return v;
57fa1d09
TG
1674}
1675
1676_public_ const char *sd_device_get_sysattr_next(sd_device *device) {
8927b1da
DH
1677 void *v;
1678
57fa1d09
TG
1679 assert_return(device, NULL);
1680
1681 if (!device->sysattrs_read)
1682 return NULL;
1683
bccfe92e 1684 (void) set_iterate(device->sysattrs, &device->sysattrs_iterator, &v);
8927b1da 1685 return v;
57fa1d09
TG
1686}
1687
1688_public_ int sd_device_has_tag(sd_device *device, const char *tag) {
1689 assert_return(device, -EINVAL);
1690 assert_return(tag, -EINVAL);
1691
1692 (void) device_read_db(device);
1693
1694 return !!set_contains(device->tags, tag);
1695}
1696
1697_public_ int sd_device_get_property_value(sd_device *device, const char *key, const char **_value) {
1698 char *value;
1699 int r;
1700
1701 assert_return(device, -EINVAL);
1702 assert_return(key, -EINVAL);
1703 assert_return(_value, -EINVAL);
1704
1705 r = device_properties_prepare(device);
1706 if (r < 0)
1707 return r;
1708
1709 value = ordered_hashmap_get(device->properties, key);
1710 if (!value)
1711 return -ENOENT;
1712
1713 *_value = value;
1714
1715 return 0;
1716}
1717
1718/* replaces the value if it already exists */
2fe29a46 1719static int device_add_sysattr_value(sd_device *device, const char *_key, char *value) {
57fa1d09 1720 _cleanup_free_ char *key = NULL;
2fe29a46 1721 _cleanup_free_ char *value_old = NULL;
57fa1d09
TG
1722 int r;
1723
1724 assert(device);
1725 assert(_key);
1726
1727 r = hashmap_ensure_allocated(&device->sysattr_values, &string_hash_ops);
1728 if (r < 0)
1729 return r;
1730
2fe29a46 1731 value_old = hashmap_remove2(device->sysattr_values, _key, (void **)&key);
57fa1d09
TG
1732 if (!key) {
1733 key = strdup(_key);
1734 if (!key)
1735 return -ENOMEM;
1736 }
1737
57fa1d09
TG
1738 r = hashmap_put(device->sysattr_values, key, value);
1739 if (r < 0)
1740 return r;
1741
1742 key = NULL;
57fa1d09
TG
1743
1744 return 0;
1745}
1746
1747static int device_get_sysattr_value(sd_device *device, const char *_key, const char **_value) {
1748 const char *key = NULL, *value;
1749
1750 assert(device);
1751 assert(_key);
1752
1753 value = hashmap_get2(device->sysattr_values, _key, (void **) &key);
1754 if (!key)
1755 return -ENOENT;
1756
1757 if (_value)
1758 *_value = value;
1759
1760 return 0;
1761}
1762
1763/* We cache all sysattr lookups. If an attribute does not exist, it is stored
1764 * with a NULL value in the cache, otherwise the returned string is stored */
1765_public_ int sd_device_get_sysattr_value(sd_device *device, const char *sysattr, const char **_value) {
1766 _cleanup_free_ char *value = NULL;
1767 const char *syspath, *cached_value = NULL;
1768 char *path;
1769 struct stat statbuf;
1770 int r;
1771
1772 assert_return(device, -EINVAL);
1773 assert_return(sysattr, -EINVAL);
1774
1775 /* look for possibly already cached result */
1776 r = device_get_sysattr_value(device, sysattr, &cached_value);
1777 if (r != -ENOENT) {
1778 if (r < 0)
1779 return r;
1780
1781 if (!cached_value)
1782 /* we looked up the sysattr before and it did not exist */
1783 return -ENOENT;
1784
1785 if (_value)
1786 *_value = cached_value;
1787
1788 return 0;
1789 }
1790
1791 r = sd_device_get_syspath(device, &syspath);
1792 if (r < 0)
1793 return r;
1794
1795 path = strjoina(syspath, "/", sysattr);
1796 r = lstat(path, &statbuf);
1797 if (r < 0) {
1798 /* remember that we could not access the sysattr */
1799 r = device_add_sysattr_value(device, sysattr, NULL);
1800 if (r < 0)
1801 return r;
1802
1803 return -ENOENT;
1804 } else if (S_ISLNK(statbuf.st_mode)) {
1805 /* Some core links return only the last element of the target path,
1806 * these are just values, the paths should not be exposed. */
1807 if (STR_IN_SET(sysattr, "driver", "subsystem", "module")) {
1808 r = readlink_value(path, &value);
1809 if (r < 0)
1810 return r;
1811 } else
1812 return -EINVAL;
1813 } else if (S_ISDIR(statbuf.st_mode)) {
1814 /* skip directories */
1815 return -EINVAL;
1816 } else if (!(statbuf.st_mode & S_IRUSR)) {
1817 /* skip non-readable files */
1818 return -EPERM;
1819 } else {
1820 size_t size;
1821
1822 /* read attribute value */
1823 r = read_full_file(path, &value, &size);
1824 if (r < 0)
1825 return r;
1826
1827 /* drop trailing newlines */
1828 while (size > 0 && value[--size] == '\n')
1829 value[size] = '\0';
1830 }
1831
1832 r = device_add_sysattr_value(device, sysattr, value);
1833 if (r < 0)
1834 return r;
1835
1836 *_value = value;
1837 value = NULL;
1838
1839 return 0;
1840}
1841
1842static void device_remove_sysattr_value(sd_device *device, const char *_key) {
1843 _cleanup_free_ char *key = NULL;
1844 _cleanup_free_ char *value = NULL;
1845
1846 assert(device);
1847 assert(_key);
1848
1849 value = hashmap_remove2(device->sysattr_values, _key, (void **) &key);
1850
1851 return;
1852}
1853
1854/* set the attribute and save it in the cache. If a NULL value is passed the
1855 * attribute is cleared from the cache */
2fe29a46 1856_public_ int sd_device_set_sysattr_value(sd_device *device, const char *sysattr, char *_value) {
57fa1d09 1857 _cleanup_close_ int fd = -1;
2fe29a46 1858 _cleanup_free_ char *value = NULL;
57fa1d09
TG
1859 const char *syspath;
1860 char *path;
2fa4861a 1861 size_t len = 0;
57fa1d09
TG
1862 ssize_t size;
1863 int r;
1864
1865 assert_return(device, -EINVAL);
1866 assert_return(sysattr, -EINVAL);
1867
2fe29a46 1868 if (!_value) {
57fa1d09
TG
1869 device_remove_sysattr_value(device, sysattr);
1870
1871 return 0;
1872 }
1873
1874 r = sd_device_get_syspath(device, &syspath);
1875 if (r < 0)
1876 return r;
1877
1878 path = strjoina(syspath, "/", sysattr);
2fa4861a
ZJS
1879
1880 fd = open(path, O_WRONLY | O_CLOEXEC | O_NOFOLLOW);
1881 if (fd < 0) {
1882 if (errno == ELOOP)
1883 return -EINVAL;
1884 if (errno == EISDIR)
1885 return -EISDIR;
1886
2fe29a46
TG
1887 value = strdup("");
1888 if (!value)
1889 return -ENOMEM;
1890
1891 r = device_add_sysattr_value(device, sysattr, value);
57fa1d09
TG
1892 if (r < 0)
1893 return r;
1894
1895 return -ENXIO;
1896 }
1897
2fa4861a 1898 len = strlen(_value);
57fa1d09
TG
1899
1900 /* drop trailing newlines */
2fa4861a
ZJS
1901 while (len > 0 && _value[len - 1] == '\n')
1902 len --;
57fa1d09
TG
1903
1904 /* value length is limited to 4k */
2fa4861a 1905 if (len > 4096)
57fa1d09
TG
1906 return -EINVAL;
1907
2fa4861a 1908 value = strndup(_value, len);
2fe29a46
TG
1909 if (!value)
1910 return -ENOMEM;
1911
2fa4861a 1912 size = write(fd, value, len);
57fa1d09
TG
1913 if (size < 0)
1914 return -errno;
1915
2fa4861a 1916 if ((size_t)size != len)
57fa1d09
TG
1917 return -EIO;
1918
1919 r = device_add_sysattr_value(device, sysattr, value);
1920 if (r < 0)
1921 return r;
2fe29a46
TG
1922 value = NULL;
1923
57fa1d09
TG
1924 return 0;
1925}