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