]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd/sd-device/sd-device.c
Merge pull request #10158 from keszybz/seccomp-log-tightening
[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 .ifindex = -1,
42 .devmode = (mode_t) -1,
43 .devuid = (uid_t) -1,
44 .devgid = (gid_t) -1,
45 };
46
47 *ret = device;
48 return 0;
49 }
50
51 static sd_device *device_free(sd_device *device) {
52 assert(device);
53
54 sd_device_unref(device->parent);
55 free(device->syspath);
56 free(device->sysname);
57 free(device->devtype);
58 free(device->devname);
59 free(device->subsystem);
60 free(device->driver_subsystem);
61 free(device->driver);
62 free(device->id_filename);
63 free(device->properties_strv);
64 free(device->properties_nulstr);
65
66 ordered_hashmap_free_free_free(device->properties);
67 ordered_hashmap_free_free_free(device->properties_db);
68 hashmap_free_free_free(device->sysattr_values);
69 set_free_free(device->sysattrs);
70 set_free_free(device->tags);
71 set_free_free(device->devlinks);
72
73 return mfree(device);
74 }
75
76 DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_device, sd_device, device_free);
77
78 int device_add_property_aux(sd_device *device, const char *_key, const char *_value, bool db) {
79 OrderedHashmap **properties;
80
81 assert(device);
82 assert(_key);
83
84 if (db)
85 properties = &device->properties_db;
86 else
87 properties = &device->properties;
88
89 if (_value) {
90 _cleanup_free_ char *key = NULL, *value = NULL, *old_key = NULL, *old_value = NULL;
91 int r;
92
93 r = ordered_hashmap_ensure_allocated(properties, &string_hash_ops);
94 if (r < 0)
95 return r;
96
97 key = strdup(_key);
98 if (!key)
99 return -ENOMEM;
100
101 value = strdup(_value);
102 if (!value)
103 return -ENOMEM;
104
105 old_value = ordered_hashmap_get2(*properties, key, (void**) &old_key);
106
107 r = ordered_hashmap_replace(*properties, key, value);
108 if (r < 0)
109 return r;
110
111 key = NULL;
112 value = NULL;
113 } else {
114 _cleanup_free_ char *key = NULL;
115 _cleanup_free_ char *value = NULL;
116
117 value = ordered_hashmap_remove2(*properties, _key, (void**) &key);
118 }
119
120 if (!db) {
121 device->properties_generation++;
122 device->properties_buf_outdated = true;
123 }
124
125 return 0;
126 }
127
128 int device_add_property_internal(sd_device *device, const char *key, const char *value) {
129 return device_add_property_aux(device, key, value, false);
130 }
131
132 int device_set_syspath(sd_device *device, const char *_syspath, bool verify) {
133 _cleanup_free_ char *syspath = NULL;
134 const char *devpath;
135 int r;
136
137 assert(device);
138 assert(_syspath);
139
140 /* must be a subdirectory of /sys */
141 if (!path_startswith(_syspath, "/sys/")) {
142 log_debug("sd-device: syspath '%s' is not a subdirectory of /sys", _syspath);
143 return -EINVAL;
144 }
145
146 if (verify) {
147 r = chase_symlinks(_syspath, NULL, 0, &syspath);
148 if (r == -ENOENT)
149 return -ENODEV; /* the device does not exist (any more?) */
150 if (r < 0)
151 return log_debug_errno(r, "sd-device: could not get target of '%s': %m", _syspath);
152
153 if (!path_startswith(syspath, "/sys")) {
154 _cleanup_free_ char *real_sys = NULL, *new_syspath = NULL;
155 char *p;
156
157 /* /sys is a symlink to somewhere sysfs is mounted on? In that case, we convert the path to real sysfs to "/sys". */
158 r = chase_symlinks("/sys", NULL, 0, &real_sys);
159 if (r < 0)
160 return log_debug_errno(r, "sd-device: could not chase symlink /sys: %m");
161
162 p = path_startswith(syspath, real_sys);
163 if (!p) {
164 log_debug("sd-device: canonicalized path '%s' does not starts with sysfs mount point '%s'", syspath, real_sys);
165 return -ENODEV;
166 }
167
168 new_syspath = strjoin("/sys/", p);
169 if (!new_syspath)
170 return log_oom();
171
172 free_and_replace(syspath, new_syspath);
173 path_simplify(syspath, false);
174 }
175
176 if (path_startswith(syspath, "/sys/devices/")) {
177 char *path;
178
179 /* all 'devices' require an 'uevent' file */
180 path = strjoina(syspath, "/uevent");
181 r = access(path, F_OK);
182 if (r < 0) {
183 if (errno == ENOENT)
184 /* this is not a valid device */
185 return -ENODEV;
186
187 return log_debug_errno(errno, "sd-device: %s does not have an uevent file: %m", syspath);
188 }
189 } else {
190 /* everything else just needs to be a directory */
191 if (!is_dir(syspath, false))
192 return -ENODEV;
193 }
194 } else {
195 syspath = strdup(_syspath);
196 if (!syspath)
197 return -ENOMEM;
198 }
199
200 devpath = syspath + STRLEN("/sys");
201
202 r = device_add_property_internal(device, "DEVPATH", devpath);
203 if (r < 0)
204 return r;
205
206 free_and_replace(device->syspath, syspath);
207
208 device->devpath = devpath;
209
210 return 0;
211 }
212
213 _public_ int sd_device_new_from_syspath(sd_device **ret, const char *syspath) {
214 _cleanup_(sd_device_unrefp) sd_device *device = NULL;
215 int r;
216
217 assert_return(ret, -EINVAL);
218 assert_return(syspath, -EINVAL);
219
220 r = device_new_aux(&device);
221 if (r < 0)
222 return r;
223
224 r = device_set_syspath(device, syspath, true);
225 if (r < 0)
226 return r;
227
228 *ret = TAKE_PTR(device);
229
230 return 0;
231 }
232
233 _public_ int sd_device_new_from_devnum(sd_device **ret, char type, dev_t devnum) {
234 char *syspath;
235 char id[DECIMAL_STR_MAX(unsigned) * 2 + 1];
236
237 assert_return(ret, -EINVAL);
238 assert_return(IN_SET(type, 'b', 'c'), -EINVAL);
239
240 /* use /sys/dev/{block,char}/<maj>:<min> link */
241 snprintf(id, sizeof(id), "%u:%u", major(devnum), minor(devnum));
242
243 syspath = strjoina("/sys/dev/", (type == 'b' ? "block" : "char"), "/", id);
244
245 return sd_device_new_from_syspath(ret, syspath);
246 }
247
248 _public_ int sd_device_new_from_subsystem_sysname(sd_device **ret, const char *subsystem, const char *sysname) {
249 char *name, *syspath;
250 size_t len = 0;
251
252 assert_return(ret, -EINVAL);
253 assert_return(subsystem, -EINVAL);
254 assert_return(sysname, -EINVAL);
255
256 if (streq(subsystem, "subsystem")) {
257 syspath = strjoina("/sys/subsystem/", sysname);
258 if (access(syspath, F_OK) >= 0)
259 return sd_device_new_from_syspath(ret, syspath);
260
261 syspath = strjoina("/sys/bus/", sysname);
262 if (access(syspath, F_OK) >= 0)
263 return sd_device_new_from_syspath(ret, syspath);
264
265 syspath = strjoina("/sys/class/", sysname);
266 if (access(syspath, F_OK) >= 0)
267 return sd_device_new_from_syspath(ret, syspath);
268 } else if (streq(subsystem, "module")) {
269 syspath = strjoina("/sys/module/", sysname);
270 if (access(syspath, F_OK) >= 0)
271 return sd_device_new_from_syspath(ret, syspath);
272 } else if (streq(subsystem, "drivers")) {
273 char subsys[PATH_MAX];
274 char *driver;
275
276 strscpy(subsys, sizeof(subsys), sysname);
277 driver = strchr(subsys, ':');
278 if (driver) {
279 driver[0] = '\0';
280 driver++;
281
282 syspath = strjoina("/sys/subsystem/", subsys, "/drivers/", driver);
283 if (access(syspath, F_OK) >= 0)
284 return sd_device_new_from_syspath(ret, syspath);
285
286 syspath = strjoina("/sys/bus/", subsys, "/drivers/", driver);
287 if (access(syspath, F_OK) >= 0)
288 return sd_device_new_from_syspath(ret, syspath);
289 }
290 }
291
292 /* translate sysname back to sysfs filename */
293 name = strdupa(sysname);
294 while (name[len] != '\0') {
295 if (name[len] == '/')
296 name[len] = '!';
297
298 len++;
299 }
300
301 syspath = strjoina("/sys/subsystem/", subsystem, "/devices/", name);
302 if (access(syspath, F_OK) >= 0)
303 return sd_device_new_from_syspath(ret, syspath);
304
305 syspath = strjoina("/sys/bus/", subsystem, "/devices/", name);
306 if (access(syspath, F_OK) >= 0)
307 return sd_device_new_from_syspath(ret, syspath);
308
309 syspath = strjoina("/sys/class/", subsystem, "/", name);
310 if (access(syspath, F_OK) >= 0)
311 return sd_device_new_from_syspath(ret, syspath);
312
313 syspath = strjoina("/sys/firmware/", subsystem, "/", sysname);
314 if (access(syspath, F_OK) >= 0)
315 return sd_device_new_from_syspath(ret, syspath);
316
317 return -ENODEV;
318 }
319
320 int device_set_devtype(sd_device *device, const char *_devtype) {
321 _cleanup_free_ char *devtype = NULL;
322 int r;
323
324 assert(device);
325 assert(_devtype);
326
327 devtype = strdup(_devtype);
328 if (!devtype)
329 return -ENOMEM;
330
331 r = device_add_property_internal(device, "DEVTYPE", devtype);
332 if (r < 0)
333 return r;
334
335 free_and_replace(device->devtype, devtype);
336
337 return 0;
338 }
339
340 int device_set_ifindex(sd_device *device, const char *_ifindex) {
341 int ifindex, r;
342
343 assert(device);
344 assert(_ifindex);
345
346 r = parse_ifindex(_ifindex, &ifindex);
347 if (r < 0)
348 return r;
349
350 r = device_add_property_internal(device, "IFINDEX", _ifindex);
351 if (r < 0)
352 return r;
353
354 device->ifindex = ifindex;
355
356 return 0;
357 }
358
359 int device_set_devname(sd_device *device, const char *_devname) {
360 _cleanup_free_ char *devname = NULL;
361 int r;
362
363 assert(device);
364 assert(_devname);
365
366 if (_devname[0] != '/') {
367 r = asprintf(&devname, "/dev/%s", _devname);
368 if (r < 0)
369 return -ENOMEM;
370 } else {
371 devname = strdup(_devname);
372 if (!devname)
373 return -ENOMEM;
374 }
375
376 r = device_add_property_internal(device, "DEVNAME", devname);
377 if (r < 0)
378 return r;
379
380 free_and_replace(device->devname, devname);
381
382 return 0;
383 }
384
385 int device_set_devmode(sd_device *device, const char *_devmode) {
386 unsigned devmode;
387 int r;
388
389 assert(device);
390 assert(_devmode);
391
392 r = safe_atou(_devmode, &devmode);
393 if (r < 0)
394 return r;
395
396 if (devmode > 07777)
397 return -EINVAL;
398
399 r = device_add_property_internal(device, "DEVMODE", _devmode);
400 if (r < 0)
401 return r;
402
403 device->devmode = devmode;
404
405 return 0;
406 }
407
408 int device_set_devnum(sd_device *device, const char *major, const char *minor) {
409 unsigned maj = 0, min = 0;
410 int r;
411
412 assert(device);
413 assert(major);
414
415 r = safe_atou(major, &maj);
416 if (r < 0)
417 return r;
418 if (!maj)
419 return 0;
420
421 if (minor) {
422 r = safe_atou(minor, &min);
423 if (r < 0)
424 return r;
425 }
426
427 r = device_add_property_internal(device, "MAJOR", major);
428 if (r < 0)
429 return r;
430
431 if (minor) {
432 r = device_add_property_internal(device, "MINOR", minor);
433 if (r < 0)
434 return r;
435 }
436
437 device->devnum = makedev(maj, min);
438
439 return 0;
440 }
441
442 static int handle_uevent_line(sd_device *device, const char *key, const char *value, const char **major, const char **minor) {
443 int r;
444
445 assert(device);
446 assert(key);
447 assert(value);
448 assert(major);
449 assert(minor);
450
451 if (streq(key, "DEVTYPE")) {
452 r = device_set_devtype(device, value);
453 if (r < 0)
454 return r;
455 } else if (streq(key, "IFINDEX")) {
456 r = device_set_ifindex(device, value);
457 if (r < 0)
458 return r;
459 } else if (streq(key, "DEVNAME")) {
460 r = device_set_devname(device, value);
461 if (r < 0)
462 return r;
463 } else if (streq(key, "DEVMODE")) {
464 r = device_set_devmode(device, value);
465 if (r < 0)
466 return r;
467 } else if (streq(key, "MAJOR"))
468 *major = value;
469 else if (streq(key, "MINOR"))
470 *minor = value;
471 else {
472 r = device_add_property_internal(device, key, value);
473 if (r < 0)
474 return r;
475 }
476
477 return 0;
478 }
479
480 int device_read_uevent_file(sd_device *device) {
481 _cleanup_free_ char *uevent = NULL;
482 const char *syspath, *key = NULL, *value = NULL, *major = NULL, *minor = NULL;
483 char *path;
484 size_t uevent_len;
485 unsigned i;
486 int r;
487
488 enum {
489 PRE_KEY,
490 KEY,
491 PRE_VALUE,
492 VALUE,
493 INVALID_LINE,
494 } state = PRE_KEY;
495
496 assert(device);
497
498 if (device->uevent_loaded || device->sealed)
499 return 0;
500
501 device->uevent_loaded = true;
502
503 r = sd_device_get_syspath(device, &syspath);
504 if (r < 0)
505 return r;
506
507 path = strjoina(syspath, "/uevent");
508
509 r = read_full_file(path, &uevent, &uevent_len);
510 if (r == -EACCES)
511 /* empty uevent files may be write-only */
512 return 0;
513 else if (r == -ENOENT)
514 /* some devices may not have uevent files, see set_syspath() */
515 return 0;
516 else if (r < 0)
517 return log_debug_errno(r, "sd-device: failed to read uevent file '%s': %m", path);
518
519 for (i = 0; i < uevent_len; i++)
520 switch (state) {
521 case PRE_KEY:
522 if (!strchr(NEWLINE, uevent[i])) {
523 key = &uevent[i];
524
525 state = KEY;
526 }
527
528 break;
529 case KEY:
530 if (uevent[i] == '=') {
531 uevent[i] = '\0';
532
533 state = PRE_VALUE;
534 } else if (strchr(NEWLINE, uevent[i])) {
535 uevent[i] = '\0';
536 log_debug("sd-device: ignoring invalid uevent line '%s'", key);
537
538 state = PRE_KEY;
539 }
540
541 break;
542 case PRE_VALUE:
543 value = &uevent[i];
544 state = VALUE;
545
546 _fallthrough_; /* to handle empty property */
547 case VALUE:
548 if (strchr(NEWLINE, uevent[i])) {
549 uevent[i] = '\0';
550
551 r = handle_uevent_line(device, key, value, &major, &minor);
552 if (r < 0)
553 log_debug_errno(r, "sd-device: failed to handle uevent entry '%s=%s': %m", key, value);
554
555 state = PRE_KEY;
556 }
557
558 break;
559 default:
560 assert_not_reached("invalid state when parsing uevent file");
561 }
562
563 if (major) {
564 r = device_set_devnum(device, major, minor);
565 if (r < 0)
566 log_debug_errno(r, "sd-device: could not set 'MAJOR=%s' or 'MINOR=%s' from '%s': %m", major, minor, path);
567 }
568
569 return 0;
570 }
571
572 _public_ int sd_device_get_ifindex(sd_device *device, int *ifindex) {
573 int r;
574
575 assert_return(device, -EINVAL);
576 assert_return(ifindex, -EINVAL);
577
578 r = device_read_uevent_file(device);
579 if (r < 0)
580 return r;
581
582 if (device->ifindex < 0)
583 return -ENOENT;
584
585 *ifindex = device->ifindex;
586
587 return 0;
588 }
589
590 _public_ int sd_device_new_from_device_id(sd_device **ret, const char *id) {
591 int r;
592
593 assert_return(ret, -EINVAL);
594 assert_return(id, -EINVAL);
595
596 switch (id[0]) {
597 case 'b':
598 case 'c':
599 {
600 char type;
601 int maj, min;
602
603 r = sscanf(id, "%c%i:%i", &type, &maj, &min);
604 if (r != 3)
605 return -EINVAL;
606
607 return sd_device_new_from_devnum(ret, type, makedev(maj, min));
608 }
609 case 'n':
610 {
611 _cleanup_(sd_device_unrefp) sd_device *device = NULL;
612 _cleanup_close_ int sk = -1;
613 struct ifreq ifr = {};
614 int ifindex;
615
616 r = parse_ifindex(&id[1], &ifr.ifr_ifindex);
617 if (r < 0)
618 return r;
619
620 sk = socket_ioctl_fd();
621 if (sk < 0)
622 return sk;
623
624 r = ioctl(sk, SIOCGIFNAME, &ifr);
625 if (r < 0)
626 return -errno;
627
628 r = sd_device_new_from_subsystem_sysname(&device, "net", ifr.ifr_name);
629 if (r < 0)
630 return r;
631
632 r = sd_device_get_ifindex(device, &ifindex);
633 if (r < 0)
634 return r;
635
636 /* this is racey, so we might end up with the wrong device */
637 if (ifr.ifr_ifindex != ifindex)
638 return -ENODEV;
639
640 *ret = TAKE_PTR(device);
641
642 return 0;
643 }
644 case '+':
645 {
646 char subsys[PATH_MAX];
647 char *sysname;
648
649 (void) strscpy(subsys, sizeof(subsys), id + 1);
650 sysname = strchr(subsys, ':');
651 if (!sysname)
652 return -EINVAL;
653
654 sysname[0] = '\0';
655 sysname++;
656
657 return sd_device_new_from_subsystem_sysname(ret, subsys, sysname);
658 }
659 default:
660 return -EINVAL;
661 }
662 }
663
664 _public_ int sd_device_get_syspath(sd_device *device, const char **ret) {
665 assert_return(device, -EINVAL);
666 assert_return(ret, -EINVAL);
667
668 assert(path_startswith(device->syspath, "/sys/"));
669
670 *ret = device->syspath;
671
672 return 0;
673 }
674
675 static int device_new_from_child(sd_device **ret, sd_device *child) {
676 _cleanup_free_ char *path = NULL;
677 const char *subdir, *syspath;
678 int r;
679
680 assert(ret);
681 assert(child);
682
683 r = sd_device_get_syspath(child, &syspath);
684 if (r < 0)
685 return r;
686
687 path = strdup(syspath);
688 if (!path)
689 return -ENOMEM;
690 subdir = path + STRLEN("/sys");
691
692 for (;;) {
693 char *pos;
694
695 pos = strrchr(subdir, '/');
696 if (!pos || pos < subdir + 2)
697 break;
698
699 *pos = '\0';
700
701 r = sd_device_new_from_syspath(ret, path);
702 if (r < 0)
703 continue;
704
705 return 0;
706 }
707
708 return -ENODEV;
709 }
710
711 _public_ int sd_device_get_parent(sd_device *child, sd_device **ret) {
712
713 assert_return(ret, -EINVAL);
714 assert_return(child, -EINVAL);
715
716 if (!child->parent_set) {
717 child->parent_set = true;
718
719 (void) device_new_from_child(&child->parent, child);
720 }
721
722 if (!child->parent)
723 return -ENOENT;
724
725 *ret = child->parent;
726
727 return 0;
728 }
729
730 int device_set_subsystem(sd_device *device, const char *_subsystem) {
731 _cleanup_free_ char *subsystem = NULL;
732 int r;
733
734 assert(device);
735 assert(_subsystem);
736
737 subsystem = strdup(_subsystem);
738 if (!subsystem)
739 return -ENOMEM;
740
741 r = device_add_property_internal(device, "SUBSYSTEM", subsystem);
742 if (r < 0)
743 return r;
744
745 free_and_replace(device->subsystem, subsystem);
746
747 device->subsystem_set = true;
748
749 return 0;
750 }
751
752 static int device_set_drivers_subsystem(sd_device *device, const char *_subsystem) {
753 _cleanup_free_ char *subsystem = NULL;
754 int r;
755
756 assert(device);
757 assert(_subsystem);
758 assert(*_subsystem);
759
760 subsystem = strdup(_subsystem);
761 if (!subsystem)
762 return -ENOMEM;
763
764 r = device_set_subsystem(device, "drivers");
765 if (r < 0)
766 return r;
767
768 free_and_replace(device->driver_subsystem, subsystem);
769
770 return 0;
771 }
772
773 _public_ int sd_device_get_subsystem(sd_device *device, const char **ret) {
774 const char *syspath, *drivers = NULL;
775 int r;
776
777 assert_return(ret, -EINVAL);
778 assert_return(device, -EINVAL);
779
780 r = sd_device_get_syspath(device, &syspath);
781 if (r < 0)
782 return r;
783
784 if (!device->subsystem_set) {
785 _cleanup_free_ char *subsystem = NULL;
786 char *path;
787
788 /* read 'subsystem' link */
789 path = strjoina(syspath, "/subsystem");
790 r = readlink_value(path, &subsystem);
791 if (r >= 0)
792 r = device_set_subsystem(device, subsystem);
793 /* use implicit names */
794 else if (path_startswith(device->devpath, "/module/"))
795 r = device_set_subsystem(device, "module");
796 else if (!(drivers = strstr(syspath, "/drivers/")) &&
797 (path_startswith(device->devpath, "/subsystem/") ||
798 path_startswith(device->devpath, "/class/") ||
799 path_startswith(device->devpath, "/bus/")))
800 r = device_set_subsystem(device, "subsystem");
801 if (r < 0 && r != -ENOENT)
802 return log_debug_errno(r, "sd-device: could not set subsystem for %s: %m", device->devpath);
803
804 device->subsystem_set = true;
805 } else if (!device->driver_subsystem_set)
806 drivers = strstr(syspath, "/drivers/");
807
808 if (!device->driver_subsystem_set) {
809 if (drivers) {
810 _cleanup_free_ char *subpath = NULL;
811
812 subpath = strndup(syspath, drivers - syspath);
813 if (!subpath)
814 r = -ENOMEM;
815 else {
816 const char *subsys;
817
818 subsys = strrchr(subpath, '/');
819 if (!subsys)
820 r = -EINVAL;
821 else
822 r = device_set_drivers_subsystem(device, subsys + 1);
823 }
824 if (r < 0 && r != -ENOENT)
825 return log_debug_errno(r, "sd-device: could not set subsystem for driver %s: %m", device->devpath);
826 }
827
828 device->driver_subsystem_set = true;
829 }
830
831 if (!device->subsystem)
832 return -ENOENT;
833
834 *ret = device->subsystem;
835
836 return 0;
837 }
838
839 _public_ int sd_device_get_devtype(sd_device *device, const char **devtype) {
840 int r;
841
842 assert(devtype);
843 assert(device);
844
845 r = device_read_uevent_file(device);
846 if (r < 0)
847 return r;
848
849 if (!device->devtype)
850 return -ENOENT;
851
852 *devtype = device->devtype;
853
854 return 0;
855 }
856
857 _public_ int sd_device_get_parent_with_subsystem_devtype(sd_device *child, const char *subsystem, const char *devtype, sd_device **ret) {
858 sd_device *parent = NULL;
859 int r;
860
861 assert_return(child, -EINVAL);
862 assert_return(subsystem, -EINVAL);
863
864 r = sd_device_get_parent(child, &parent);
865 while (r >= 0) {
866 const char *parent_subsystem = NULL;
867 const char *parent_devtype = NULL;
868
869 (void) sd_device_get_subsystem(parent, &parent_subsystem);
870 if (streq_ptr(parent_subsystem, subsystem)) {
871 if (!devtype)
872 break;
873
874 (void) sd_device_get_devtype(parent, &parent_devtype);
875 if (streq_ptr(parent_devtype, devtype))
876 break;
877 }
878 r = sd_device_get_parent(parent, &parent);
879 }
880
881 if (r < 0)
882 return r;
883
884 *ret = parent;
885
886 return 0;
887 }
888
889 _public_ int sd_device_get_devnum(sd_device *device, dev_t *devnum) {
890 int r;
891
892 assert_return(device, -EINVAL);
893 assert_return(devnum, -EINVAL);
894
895 r = device_read_uevent_file(device);
896 if (r < 0)
897 return r;
898
899 if (major(device->devnum) <= 0)
900 return -ENOENT;
901
902 *devnum = device->devnum;
903
904 return 0;
905 }
906
907 int device_set_driver(sd_device *device, const char *_driver) {
908 _cleanup_free_ char *driver = NULL;
909 int r;
910
911 assert(device);
912 assert(_driver);
913
914 driver = strdup(_driver);
915 if (!driver)
916 return -ENOMEM;
917
918 r = device_add_property_internal(device, "DRIVER", driver);
919 if (r < 0)
920 return r;
921
922 free_and_replace(device->driver, driver);
923
924 device->driver_set = true;
925
926 return 0;
927 }
928
929 _public_ int sd_device_get_driver(sd_device *device, const char **ret) {
930 assert_return(device, -EINVAL);
931 assert_return(ret, -EINVAL);
932
933 if (!device->driver_set) {
934 _cleanup_free_ char *driver = NULL;
935 const char *syspath;
936 char *path;
937 int r;
938
939 r = sd_device_get_syspath(device, &syspath);
940 if (r < 0)
941 return r;
942
943 path = strjoina(syspath, "/driver");
944 r = readlink_value(path, &driver);
945 if (r >= 0) {
946 r = device_set_driver(device, driver);
947 if (r < 0)
948 return log_debug_errno(r, "sd-device: could not set driver for %s: %m", device->devpath);
949 } else if (r == -ENOENT)
950 device->driver_set = true;
951 else
952 return log_debug_errno(r, "sd-device: could not set driver for %s: %m", device->devpath);
953 }
954
955 if (!device->driver)
956 return -ENOENT;
957
958 *ret = device->driver;
959
960 return 0;
961 }
962
963 _public_ int sd_device_get_devpath(sd_device *device, const char **devpath) {
964 assert_return(device, -EINVAL);
965 assert_return(devpath, -EINVAL);
966
967 assert(device->devpath);
968 assert(device->devpath[0] == '/');
969
970 *devpath = device->devpath;
971
972 return 0;
973 }
974
975 _public_ int sd_device_get_devname(sd_device *device, const char **devname) {
976 int r;
977
978 assert_return(device, -EINVAL);
979 assert_return(devname, -EINVAL);
980
981 r = device_read_uevent_file(device);
982 if (r < 0)
983 return r;
984
985 if (!device->devname)
986 return -ENOENT;
987
988 assert(path_startswith(device->devname, "/dev/"));
989
990 *devname = device->devname;
991
992 return 0;
993 }
994
995 static int device_set_sysname(sd_device *device) {
996 _cleanup_free_ char *sysname = NULL;
997 const char *sysnum = NULL;
998 const char *pos;
999 size_t len = 0;
1000
1001 pos = strrchr(device->devpath, '/');
1002 if (!pos)
1003 return -EINVAL;
1004 pos++;
1005
1006 /* devpath is not a root directory */
1007 if (*pos == '\0' || pos <= device->devpath)
1008 return -EINVAL;
1009
1010 sysname = strdup(pos);
1011 if (!sysname)
1012 return -ENOMEM;
1013
1014 /* some devices have '!' in their name, change that to '/' */
1015 while (sysname[len] != '\0') {
1016 if (sysname[len] == '!')
1017 sysname[len] = '/';
1018
1019 len++;
1020 }
1021
1022 /* trailing number */
1023 while (len > 0 && isdigit(sysname[--len]))
1024 sysnum = &sysname[len];
1025
1026 if (len == 0)
1027 sysnum = NULL;
1028
1029 free_and_replace(device->sysname, sysname);
1030
1031 device->sysnum = sysnum;
1032
1033 device->sysname_set = true;
1034
1035 return 0;
1036 }
1037
1038 _public_ int sd_device_get_sysname(sd_device *device, const char **ret) {
1039 int r;
1040
1041 assert_return(device, -EINVAL);
1042 assert_return(ret, -EINVAL);
1043
1044 if (!device->sysname_set) {
1045 r = device_set_sysname(device);
1046 if (r < 0)
1047 return r;
1048 }
1049
1050 assert_return(device->sysname, -ENOENT);
1051
1052 *ret = device->sysname;
1053
1054 return 0;
1055 }
1056
1057 _public_ int sd_device_get_sysnum(sd_device *device, const char **ret) {
1058 int r;
1059
1060 assert_return(device, -EINVAL);
1061 assert_return(ret, -EINVAL);
1062
1063 if (!device->sysname_set) {
1064 r = device_set_sysname(device);
1065 if (r < 0)
1066 return r;
1067 }
1068
1069 if (!device->sysnum)
1070 return -ENOENT;
1071
1072 *ret = device->sysnum;
1073
1074 return 0;
1075 }
1076
1077 static bool is_valid_tag(const char *tag) {
1078 assert(tag);
1079
1080 return !strchr(tag, ':') && !strchr(tag, ' ');
1081 }
1082
1083 int device_add_tag(sd_device *device, const char *tag) {
1084 int r;
1085
1086 assert(device);
1087 assert(tag);
1088
1089 if (!is_valid_tag(tag))
1090 return -EINVAL;
1091
1092 r = set_ensure_allocated(&device->tags, &string_hash_ops);
1093 if (r < 0)
1094 return r;
1095
1096 r = set_put_strdup(device->tags, tag);
1097 if (r < 0)
1098 return r;
1099
1100 device->tags_generation++;
1101 device->property_tags_outdated = true;
1102
1103 return 0;
1104 }
1105
1106 int device_add_devlink(sd_device *device, const char *devlink) {
1107 int r;
1108
1109 assert(device);
1110 assert(devlink);
1111
1112 r = set_ensure_allocated(&device->devlinks, &string_hash_ops);
1113 if (r < 0)
1114 return r;
1115
1116 r = set_put_strdup(device->devlinks, devlink);
1117 if (r < 0)
1118 return r;
1119
1120 device->devlinks_generation++;
1121 device->property_devlinks_outdated = true;
1122
1123 return 0;
1124 }
1125
1126 static int device_add_property_internal_from_string(sd_device *device, const char *str) {
1127 _cleanup_free_ char *key = NULL;
1128 char *value;
1129
1130 assert(device);
1131 assert(str);
1132
1133 key = strdup(str);
1134 if (!key)
1135 return -ENOMEM;
1136
1137 value = strchr(key, '=');
1138 if (!value)
1139 return -EINVAL;
1140
1141 *value = '\0';
1142
1143 if (isempty(++value))
1144 value = NULL;
1145
1146 return device_add_property_internal(device, key, value);
1147 }
1148
1149 int device_set_usec_initialized(sd_device *device, const char *initialized) {
1150 uint64_t usec_initialized;
1151 int r;
1152
1153 assert(device);
1154 assert(initialized);
1155
1156 r = safe_atou64(initialized, &usec_initialized);
1157 if (r < 0)
1158 return r;
1159
1160 r = device_add_property_internal(device, "USEC_INITIALIZED", initialized);
1161 if (r < 0)
1162 return r;
1163
1164 device->usec_initialized = usec_initialized;
1165
1166 return 0;
1167 }
1168
1169 static int handle_db_line(sd_device *device, char key, const char *value) {
1170 char *path;
1171 int r;
1172
1173 assert(device);
1174 assert(value);
1175
1176 switch (key) {
1177 case 'G':
1178 r = device_add_tag(device, value);
1179 if (r < 0)
1180 return r;
1181
1182 break;
1183 case 'S':
1184 path = strjoina("/dev/", value);
1185 r = device_add_devlink(device, path);
1186 if (r < 0)
1187 return r;
1188
1189 break;
1190 case 'E':
1191 r = device_add_property_internal_from_string(device, value);
1192 if (r < 0)
1193 return r;
1194
1195 break;
1196 case 'I':
1197 r = device_set_usec_initialized(device, value);
1198 if (r < 0)
1199 return r;
1200
1201 break;
1202 case 'L':
1203 r = safe_atoi(value, &device->devlink_priority);
1204 if (r < 0)
1205 return r;
1206
1207 break;
1208 case 'W':
1209 r = safe_atoi(value, &device->watch_handle);
1210 if (r < 0)
1211 return r;
1212
1213 break;
1214 default:
1215 log_debug("device db: unknown key '%c'", key);
1216 }
1217
1218 return 0;
1219 }
1220
1221 int device_get_id_filename(sd_device *device, const char **ret) {
1222 assert(device);
1223 assert(ret);
1224
1225 if (!device->id_filename) {
1226 _cleanup_free_ char *id = NULL;
1227 const char *subsystem;
1228 dev_t devnum;
1229 int ifindex, r;
1230
1231 r = sd_device_get_subsystem(device, &subsystem);
1232 if (r < 0)
1233 return r;
1234
1235 if (sd_device_get_devnum(device, &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 (sd_device_get_ifindex(device, &ifindex) >= 0 && 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, const 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 }