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