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