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