]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd/sd-device/sd-device.c
sd-device: pass timestamp internally as usec_t not char*
[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 pos = strrchr(device->devpath, '/');
1006 if (!pos)
1007 return -EINVAL;
1008 pos++;
1009
1010 /* devpath is not a root directory */
1011 if (*pos == '\0' || pos <= device->devpath)
1012 return -EINVAL;
1013
1014 sysname = strdup(pos);
1015 if (!sysname)
1016 return -ENOMEM;
1017
1018 /* some devices have '!' in their name, change that to '/' */
1019 while (sysname[len] != '\0') {
1020 if (sysname[len] == '!')
1021 sysname[len] = '/';
1022
1023 len++;
1024 }
1025
1026 /* trailing number */
1027 while (len > 0 && isdigit(sysname[--len]))
1028 sysnum = &sysname[len];
1029
1030 if (len == 0)
1031 sysnum = NULL;
1032
1033 free_and_replace(device->sysname, sysname);
1034
1035 device->sysnum = sysnum;
1036
1037 device->sysname_set = true;
1038
1039 return 0;
1040 }
1041
1042 _public_ int sd_device_get_sysname(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 assert_return(device->sysname, -ENOENT);
1055
1056 *ret = device->sysname;
1057
1058 return 0;
1059 }
1060
1061 _public_ int sd_device_get_sysnum(sd_device *device, const char **ret) {
1062 int r;
1063
1064 assert_return(device, -EINVAL);
1065 assert_return(ret, -EINVAL);
1066
1067 if (!device->sysname_set) {
1068 r = device_set_sysname(device);
1069 if (r < 0)
1070 return r;
1071 }
1072
1073 if (!device->sysnum)
1074 return -ENOENT;
1075
1076 *ret = device->sysnum;
1077
1078 return 0;
1079 }
1080
1081 static bool is_valid_tag(const char *tag) {
1082 assert(tag);
1083
1084 return !strchr(tag, ':') && !strchr(tag, ' ');
1085 }
1086
1087 int device_add_tag(sd_device *device, const char *tag) {
1088 int r;
1089
1090 assert(device);
1091 assert(tag);
1092
1093 if (!is_valid_tag(tag))
1094 return -EINVAL;
1095
1096 r = set_ensure_allocated(&device->tags, &string_hash_ops);
1097 if (r < 0)
1098 return r;
1099
1100 r = set_put_strdup(device->tags, tag);
1101 if (r < 0)
1102 return r;
1103
1104 device->tags_generation++;
1105 device->property_tags_outdated = true;
1106
1107 return 0;
1108 }
1109
1110 int device_add_devlink(sd_device *device, const char *devlink) {
1111 int r;
1112
1113 assert(device);
1114 assert(devlink);
1115
1116 r = set_ensure_allocated(&device->devlinks, &string_hash_ops);
1117 if (r < 0)
1118 return r;
1119
1120 r = set_put_strdup(device->devlinks, devlink);
1121 if (r < 0)
1122 return r;
1123
1124 device->devlinks_generation++;
1125 device->property_devlinks_outdated = true;
1126
1127 return 0;
1128 }
1129
1130 static int device_add_property_internal_from_string(sd_device *device, const char *str) {
1131 _cleanup_free_ char *key = NULL;
1132 char *value;
1133
1134 assert(device);
1135 assert(str);
1136
1137 key = strdup(str);
1138 if (!key)
1139 return -ENOMEM;
1140
1141 value = strchr(key, '=');
1142 if (!value)
1143 return -EINVAL;
1144
1145 *value = '\0';
1146
1147 if (isempty(++value))
1148 value = NULL;
1149
1150 return device_add_property_internal(device, key, value);
1151 }
1152
1153 int device_set_usec_initialized(sd_device *device, usec_t when) {
1154 char s[DECIMAL_STR_MAX(usec_t)];
1155 int r;
1156
1157 assert(device);
1158
1159 xsprintf(s, USEC_FMT, when);
1160
1161 r = device_add_property_internal(device, "USEC_INITIALIZED", s);
1162 if (r < 0)
1163 return r;
1164
1165 device->usec_initialized = when;
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 usec_t t;
1198
1199 r = safe_atou64(value, &t);
1200 if (r < 0)
1201 return r;
1202
1203 r = device_set_usec_initialized(device, t);
1204 if (r < 0)
1205 return r;
1206
1207 break;
1208 }
1209 case 'L':
1210 r = safe_atoi(value, &device->devlink_priority);
1211 if (r < 0)
1212 return r;
1213
1214 break;
1215 case 'W':
1216 r = safe_atoi(value, &device->watch_handle);
1217 if (r < 0)
1218 return r;
1219
1220 break;
1221 default:
1222 log_device_debug(device, "sd-device: Unknown key '%c' in device db, ignoring", key);
1223 }
1224
1225 return 0;
1226 }
1227
1228 int device_get_id_filename(sd_device *device, const char **ret) {
1229 assert(device);
1230 assert(ret);
1231
1232 if (!device->id_filename) {
1233 _cleanup_free_ char *id = NULL;
1234 const char *subsystem;
1235 dev_t devnum;
1236 int ifindex, r;
1237
1238 r = sd_device_get_subsystem(device, &subsystem);
1239 if (r < 0)
1240 return r;
1241
1242 if (sd_device_get_devnum(device, &devnum) >= 0) {
1243 assert(subsystem);
1244
1245 /* use dev_t — b259:131072, c254:0 */
1246 r = asprintf(&id, "%c%u:%u",
1247 streq(subsystem, "block") ? 'b' : 'c',
1248 major(devnum), minor(devnum));
1249 if (r < 0)
1250 return -ENOMEM;
1251 } else if (sd_device_get_ifindex(device, &ifindex) >= 0) {
1252 /* use netdev ifindex — n3 */
1253 r = asprintf(&id, "n%u", (unsigned) ifindex);
1254 if (r < 0)
1255 return -ENOMEM;
1256 } else {
1257 /* use $subsys:$sysname — pci:0000:00:1f.2
1258 * sysname() has '!' translated, get it from devpath
1259 */
1260 const char *sysname;
1261
1262 sysname = basename(device->devpath);
1263 if (!sysname)
1264 return -EINVAL;
1265
1266 if (!subsystem)
1267 return -EINVAL;
1268
1269 if (streq(subsystem, "drivers")) {
1270 /* the 'drivers' pseudo-subsystem is special, and needs the real subsystem
1271 * encoded as well */
1272 r = asprintf(&id, "+drivers:%s:%s", device->driver_subsystem, sysname);
1273 if (r < 0)
1274 return -ENOMEM;
1275 } else {
1276 r = asprintf(&id, "+%s:%s", subsystem, sysname);
1277 if (r < 0)
1278 return -ENOMEM;
1279 }
1280 }
1281
1282 device->id_filename = TAKE_PTR(id);
1283 }
1284
1285 *ret = device->id_filename;
1286
1287 return 0;
1288 }
1289
1290 int device_read_db_internal(sd_device *device, bool force) {
1291 _cleanup_free_ char *db = NULL;
1292 char *path;
1293 const char *id, *value;
1294 char key;
1295 size_t db_len;
1296 unsigned i;
1297 int r;
1298
1299 enum {
1300 PRE_KEY,
1301 KEY,
1302 PRE_VALUE,
1303 VALUE,
1304 INVALID_LINE,
1305 } state = PRE_KEY;
1306
1307 assert(device);
1308
1309 if (device->db_loaded || (!force && device->sealed))
1310 return 0;
1311
1312 r = device_get_id_filename(device, &id);
1313 if (r < 0)
1314 return r;
1315
1316 path = strjoina("/run/udev/data/", id);
1317
1318 r = read_full_file(path, &db, &db_len);
1319 if (r < 0) {
1320 if (r == -ENOENT)
1321 return 0;
1322 else
1323 return log_device_debug_errno(device, r, "sd-device: Failed to read db '%s': %m", path);
1324 }
1325
1326 /* devices with a database entry are initialized */
1327 device->is_initialized = true;
1328
1329 device->db_loaded = true;
1330
1331 for (i = 0; i < db_len; i++) {
1332 switch (state) {
1333 case PRE_KEY:
1334 if (!strchr(NEWLINE, db[i])) {
1335 key = db[i];
1336
1337 state = KEY;
1338 }
1339
1340 break;
1341 case KEY:
1342 if (db[i] != ':') {
1343 log_device_debug(device, "sd-device: Invalid db entry with key '%c', ignoring", key);
1344
1345 state = INVALID_LINE;
1346 } else {
1347 db[i] = '\0';
1348
1349 state = PRE_VALUE;
1350 }
1351
1352 break;
1353 case PRE_VALUE:
1354 value = &db[i];
1355
1356 state = VALUE;
1357
1358 break;
1359 case INVALID_LINE:
1360 if (strchr(NEWLINE, db[i]))
1361 state = PRE_KEY;
1362
1363 break;
1364 case VALUE:
1365 if (strchr(NEWLINE, db[i])) {
1366 db[i] = '\0';
1367 r = handle_db_line(device, key, value);
1368 if (r < 0)
1369 log_device_debug_errno(device, r, "sd-device: Failed to handle db entry '%c:%s', ignoring: %m", key, value);
1370
1371 state = PRE_KEY;
1372 }
1373
1374 break;
1375 default:
1376 assert_not_reached("Invalid state when parsing db");
1377 }
1378 }
1379
1380 return 0;
1381 }
1382
1383 _public_ int sd_device_get_is_initialized(sd_device *device) {
1384 int r;
1385
1386 assert_return(device, -EINVAL);
1387
1388 r = device_read_db(device);
1389 if (r < 0)
1390 return r;
1391
1392 return device->is_initialized;
1393 }
1394
1395 _public_ int sd_device_get_usec_since_initialized(sd_device *device, uint64_t *usec) {
1396 usec_t now_ts;
1397 int r;
1398
1399 assert_return(device, -EINVAL);
1400 assert_return(usec, -EINVAL);
1401
1402 r = device_read_db(device);
1403 if (r < 0)
1404 return r;
1405
1406 if (!device->is_initialized)
1407 return -EBUSY;
1408
1409 if (!device->usec_initialized)
1410 return -ENODATA;
1411
1412 now_ts = now(clock_boottime_or_monotonic());
1413
1414 if (now_ts < device->usec_initialized)
1415 return -EIO;
1416
1417 *usec = now_ts - device->usec_initialized;
1418
1419 return 0;
1420 }
1421
1422 _public_ const char *sd_device_get_tag_first(sd_device *device) {
1423 void *v;
1424
1425 assert_return(device, NULL);
1426
1427 (void) device_read_db(device);
1428
1429 device->tags_iterator_generation = device->tags_generation;
1430 device->tags_iterator = ITERATOR_FIRST;
1431
1432 (void) set_iterate(device->tags, &device->tags_iterator, &v);
1433 return v;
1434 }
1435
1436 _public_ const char *sd_device_get_tag_next(sd_device *device) {
1437 void *v;
1438
1439 assert_return(device, NULL);
1440
1441 (void) device_read_db(device);
1442
1443 if (device->tags_iterator_generation != device->tags_generation)
1444 return NULL;
1445
1446 (void) set_iterate(device->tags, &device->tags_iterator, &v);
1447 return v;
1448 }
1449
1450 _public_ const char *sd_device_get_devlink_first(sd_device *device) {
1451 void *v;
1452
1453 assert_return(device, NULL);
1454
1455 (void) device_read_db(device);
1456
1457 device->devlinks_iterator_generation = device->devlinks_generation;
1458 device->devlinks_iterator = ITERATOR_FIRST;
1459
1460 (void) set_iterate(device->devlinks, &device->devlinks_iterator, &v);
1461 return v;
1462 }
1463
1464 _public_ const char *sd_device_get_devlink_next(sd_device *device) {
1465 void *v;
1466
1467 assert_return(device, NULL);
1468
1469 (void) device_read_db(device);
1470
1471 if (device->devlinks_iterator_generation != device->devlinks_generation)
1472 return NULL;
1473
1474 (void) set_iterate(device->devlinks, &device->devlinks_iterator, &v);
1475 return v;
1476 }
1477
1478 static int device_properties_prepare(sd_device *device) {
1479 int r;
1480
1481 assert(device);
1482
1483 r = device_read_uevent_file(device);
1484 if (r < 0)
1485 return r;
1486
1487 r = device_read_db(device);
1488 if (r < 0)
1489 return r;
1490
1491 if (device->property_devlinks_outdated) {
1492 _cleanup_free_ char *devlinks = NULL;
1493 size_t devlinks_allocated = 0, devlinks_len = 0;
1494 const char *devlink;
1495
1496 for (devlink = sd_device_get_devlink_first(device); devlink; devlink = sd_device_get_devlink_next(device)) {
1497 char *e;
1498
1499 if (!GREEDY_REALLOC(devlinks, devlinks_allocated, devlinks_len + strlen(devlink) + 2))
1500 return -ENOMEM;
1501 if (devlinks_len > 0)
1502 stpcpy(devlinks + devlinks_len++, " ");
1503 e = stpcpy(devlinks + devlinks_len, devlink);
1504 devlinks_len = e - devlinks;
1505 }
1506
1507 r = device_add_property_internal(device, "DEVLINKS", devlinks);
1508 if (r < 0)
1509 return r;
1510
1511 device->property_devlinks_outdated = false;
1512 }
1513
1514 if (device->property_tags_outdated) {
1515 _cleanup_free_ char *tags = NULL;
1516 size_t tags_allocated = 0, tags_len = 0;
1517 const char *tag;
1518
1519 if (!GREEDY_REALLOC(tags, tags_allocated, 2))
1520 return -ENOMEM;
1521 stpcpy(tags, ":");
1522 tags_len++;
1523
1524 for (tag = sd_device_get_tag_first(device); tag; tag = sd_device_get_tag_next(device)) {
1525 char *e;
1526
1527 if (!GREEDY_REALLOC(tags, tags_allocated, tags_len + strlen(tag) + 2))
1528 return -ENOMEM;
1529 e = stpcpy(stpcpy(tags + tags_len, tag), ":");
1530 tags_len = e - tags;
1531 }
1532
1533 r = device_add_property_internal(device, "TAGS", tags);
1534 if (r < 0)
1535 return r;
1536
1537 device->property_tags_outdated = false;
1538 }
1539
1540 return 0;
1541 }
1542
1543 _public_ const char *sd_device_get_property_first(sd_device *device, const char **_value) {
1544 const char *key;
1545 const char *value;
1546 int r;
1547
1548 assert_return(device, NULL);
1549
1550 r = device_properties_prepare(device);
1551 if (r < 0)
1552 return NULL;
1553
1554 device->properties_iterator_generation = device->properties_generation;
1555 device->properties_iterator = ITERATOR_FIRST;
1556
1557 ordered_hashmap_iterate(device->properties, &device->properties_iterator, (void**)&value, (const void**)&key);
1558
1559 if (_value)
1560 *_value = value;
1561
1562 return key;
1563 }
1564
1565 _public_ const char *sd_device_get_property_next(sd_device *device, const char **_value) {
1566 const char *key;
1567 const char *value;
1568 int r;
1569
1570 assert_return(device, NULL);
1571
1572 r = device_properties_prepare(device);
1573 if (r < 0)
1574 return NULL;
1575
1576 if (device->properties_iterator_generation != device->properties_generation)
1577 return NULL;
1578
1579 ordered_hashmap_iterate(device->properties, &device->properties_iterator, (void**)&value, (const void**)&key);
1580
1581 if (_value)
1582 *_value = value;
1583
1584 return key;
1585 }
1586
1587 static int device_sysattrs_read_all(sd_device *device) {
1588 _cleanup_closedir_ DIR *dir = NULL;
1589 const char *syspath;
1590 struct dirent *dent;
1591 int r;
1592
1593 assert(device);
1594
1595 if (device->sysattrs_read)
1596 return 0;
1597
1598 r = sd_device_get_syspath(device, &syspath);
1599 if (r < 0)
1600 return r;
1601
1602 dir = opendir(syspath);
1603 if (!dir)
1604 return -errno;
1605
1606 r = set_ensure_allocated(&device->sysattrs, &string_hash_ops);
1607 if (r < 0)
1608 return r;
1609
1610 FOREACH_DIRENT_ALL(dent, dir, return -errno) {
1611 char *path;
1612 struct stat statbuf;
1613
1614 /* only handle symlinks and regular files */
1615 if (!IN_SET(dent->d_type, DT_LNK, DT_REG))
1616 continue;
1617
1618 path = strjoina(syspath, "/", dent->d_name);
1619
1620 if (lstat(path, &statbuf) != 0)
1621 continue;
1622
1623 if (!(statbuf.st_mode & S_IRUSR))
1624 continue;
1625
1626 r = set_put_strdup(device->sysattrs, dent->d_name);
1627 if (r < 0)
1628 return r;
1629 }
1630
1631 device->sysattrs_read = true;
1632
1633 return 0;
1634 }
1635
1636 _public_ const char *sd_device_get_sysattr_first(sd_device *device) {
1637 void *v;
1638 int r;
1639
1640 assert_return(device, NULL);
1641
1642 if (!device->sysattrs_read) {
1643 r = device_sysattrs_read_all(device);
1644 if (r < 0) {
1645 errno = -r;
1646 return NULL;
1647 }
1648 }
1649
1650 device->sysattrs_iterator = ITERATOR_FIRST;
1651
1652 (void) set_iterate(device->sysattrs, &device->sysattrs_iterator, &v);
1653 return v;
1654 }
1655
1656 _public_ const char *sd_device_get_sysattr_next(sd_device *device) {
1657 void *v;
1658
1659 assert_return(device, NULL);
1660
1661 if (!device->sysattrs_read)
1662 return NULL;
1663
1664 (void) set_iterate(device->sysattrs, &device->sysattrs_iterator, &v);
1665 return v;
1666 }
1667
1668 _public_ int sd_device_has_tag(sd_device *device, const char *tag) {
1669 assert_return(device, -EINVAL);
1670 assert_return(tag, -EINVAL);
1671
1672 (void) device_read_db(device);
1673
1674 return !!set_contains(device->tags, tag);
1675 }
1676
1677 _public_ int sd_device_get_property_value(sd_device *device, const char *key, const char **_value) {
1678 char *value;
1679 int r;
1680
1681 assert_return(device, -EINVAL);
1682 assert_return(key, -EINVAL);
1683
1684 r = device_properties_prepare(device);
1685 if (r < 0)
1686 return r;
1687
1688 value = ordered_hashmap_get(device->properties, key);
1689 if (!value)
1690 return -ENOENT;
1691
1692 if (_value)
1693 *_value = value;
1694
1695 return 0;
1696 }
1697
1698 /* replaces the value if it already exists */
1699 static int device_add_sysattr_value(sd_device *device, const char *_key, char *value) {
1700 _cleanup_free_ char *key = NULL;
1701 _cleanup_free_ char *value_old = NULL;
1702 int r;
1703
1704 assert(device);
1705 assert(_key);
1706
1707 r = hashmap_ensure_allocated(&device->sysattr_values, &string_hash_ops);
1708 if (r < 0)
1709 return r;
1710
1711 value_old = hashmap_remove2(device->sysattr_values, _key, (void **)&key);
1712 if (!key) {
1713 key = strdup(_key);
1714 if (!key)
1715 return -ENOMEM;
1716 }
1717
1718 r = hashmap_put(device->sysattr_values, key, value);
1719 if (r < 0)
1720 return r;
1721
1722 key = NULL;
1723
1724 return 0;
1725 }
1726
1727 static int device_get_sysattr_value(sd_device *device, const char *_key, const char **_value) {
1728 const char *key = NULL, *value;
1729
1730 assert(device);
1731 assert(_key);
1732
1733 value = hashmap_get2(device->sysattr_values, _key, (void **) &key);
1734 if (!key)
1735 return -ENOENT;
1736
1737 if (_value)
1738 *_value = value;
1739
1740 return 0;
1741 }
1742
1743 /* We cache all sysattr lookups. If an attribute does not exist, it is stored
1744 * with a NULL value in the cache, otherwise the returned string is stored */
1745 _public_ int sd_device_get_sysattr_value(sd_device *device, const char *sysattr, const char **_value) {
1746 _cleanup_free_ char *value = NULL;
1747 const char *syspath, *cached_value = NULL;
1748 char *path;
1749 struct stat statbuf;
1750 int r;
1751
1752 assert_return(device, -EINVAL);
1753 assert_return(sysattr, -EINVAL);
1754
1755 /* look for possibly already cached result */
1756 r = device_get_sysattr_value(device, sysattr, &cached_value);
1757 if (r != -ENOENT) {
1758 if (r < 0)
1759 return r;
1760
1761 if (!cached_value)
1762 /* we looked up the sysattr before and it did not exist */
1763 return -ENOENT;
1764
1765 if (_value)
1766 *_value = cached_value;
1767
1768 return 0;
1769 }
1770
1771 r = sd_device_get_syspath(device, &syspath);
1772 if (r < 0)
1773 return r;
1774
1775 path = strjoina(syspath, "/", sysattr);
1776 r = lstat(path, &statbuf);
1777 if (r < 0) {
1778 /* remember that we could not access the sysattr */
1779 r = device_add_sysattr_value(device, sysattr, NULL);
1780 if (r < 0)
1781 return r;
1782
1783 return -ENOENT;
1784 } else if (S_ISLNK(statbuf.st_mode)) {
1785 /* Some core links return only the last element of the target path,
1786 * these are just values, the paths should not be exposed. */
1787 if (STR_IN_SET(sysattr, "driver", "subsystem", "module")) {
1788 r = readlink_value(path, &value);
1789 if (r < 0)
1790 return r;
1791 } else
1792 return -EINVAL;
1793 } else if (S_ISDIR(statbuf.st_mode)) {
1794 /* skip directories */
1795 return -EINVAL;
1796 } else if (!(statbuf.st_mode & S_IRUSR)) {
1797 /* skip non-readable files */
1798 return -EPERM;
1799 } else {
1800 size_t size;
1801
1802 /* read attribute value */
1803 r = read_full_file(path, &value, &size);
1804 if (r < 0)
1805 return r;
1806
1807 /* drop trailing newlines */
1808 while (size > 0 && value[--size] == '\n')
1809 value[size] = '\0';
1810 }
1811
1812 r = device_add_sysattr_value(device, sysattr, value);
1813 if (r < 0)
1814 return r;
1815
1816 *_value = TAKE_PTR(value);
1817
1818 return 0;
1819 }
1820
1821 static void device_remove_sysattr_value(sd_device *device, const char *_key) {
1822 _cleanup_free_ char *key = NULL;
1823 _cleanup_free_ char *value = NULL;
1824
1825 assert(device);
1826 assert(_key);
1827
1828 value = hashmap_remove2(device->sysattr_values, _key, (void **) &key);
1829
1830 return;
1831 }
1832
1833 /* set the attribute and save it in the cache. If a NULL value is passed the
1834 * attribute is cleared from the cache */
1835 _public_ int sd_device_set_sysattr_value(sd_device *device, const char *sysattr, const char *_value) {
1836 _cleanup_free_ char *value = NULL;
1837 const char *syspath, *path;
1838 size_t len;
1839 int r;
1840
1841 assert_return(device, -EINVAL);
1842 assert_return(sysattr, -EINVAL);
1843
1844 if (!_value) {
1845 device_remove_sysattr_value(device, sysattr);
1846
1847 return 0;
1848 }
1849
1850 r = sd_device_get_syspath(device, &syspath);
1851 if (r < 0)
1852 return r;
1853
1854 path = strjoina(syspath, "/", sysattr);
1855
1856 len = strlen(_value);
1857
1858 /* drop trailing newlines */
1859 while (len > 0 && _value[len - 1] == '\n')
1860 len --;
1861
1862 /* value length is limited to 4k */
1863 if (len > 4096)
1864 return -EINVAL;
1865
1866 value = strndup(_value, len);
1867 if (!value)
1868 return -ENOMEM;
1869
1870 r = write_string_file(path, value, WRITE_STRING_FILE_DISABLE_BUFFER | WRITE_STRING_FILE_NOFOLLOW);
1871 if (r < 0) {
1872 if (r == -ELOOP)
1873 return -EINVAL;
1874 if (r == -EISDIR)
1875 return r;
1876
1877 free(value);
1878 value = strdup("");
1879 if (!value)
1880 return -ENOMEM;
1881
1882 r = device_add_sysattr_value(device, sysattr, value);
1883 if (r < 0)
1884 return r;
1885
1886 value = NULL;
1887 return -ENXIO;
1888 }
1889
1890 r = device_add_sysattr_value(device, sysattr, value);
1891 if (r < 0)
1892 return r;
1893
1894 value = NULL;
1895 return 0;
1896 }