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