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