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