]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd/sd-device/sd-device.c
Merge pull request #7740 from yuwata/fix-7676
[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 = id;
1301 id = NULL;
1302 }
1303
1304 *ret = device->id_filename;
1305
1306 return 0;
1307 }
1308
1309 int device_read_db_aux(sd_device *device, bool force) {
1310 _cleanup_free_ char *db = NULL;
1311 char *path;
1312 const char *id, *value;
1313 char key;
1314 size_t db_len;
1315 unsigned i;
1316 int r;
1317
1318 enum {
1319 PRE_KEY,
1320 KEY,
1321 PRE_VALUE,
1322 VALUE,
1323 INVALID_LINE,
1324 } state = PRE_KEY;
1325
1326 if (device->db_loaded || (!force && device->sealed))
1327 return 0;
1328
1329 device->db_loaded = true;
1330
1331 r = device_get_id_filename(device, &id);
1332 if (r < 0)
1333 return r;
1334
1335 path = strjoina("/run/udev/data/", id);
1336
1337 r = read_full_file(path, &db, &db_len);
1338 if (r < 0) {
1339 if (r == -ENOENT)
1340 return 0;
1341 else
1342 return log_debug_errno(r, "sd-device: failed to read db '%s': %m", path);
1343 }
1344
1345 /* devices with a database entry are initialized */
1346 device->is_initialized = true;
1347
1348 for (i = 0; i < db_len; i++) {
1349 switch (state) {
1350 case PRE_KEY:
1351 if (!strchr(NEWLINE, db[i])) {
1352 key = db[i];
1353
1354 state = KEY;
1355 }
1356
1357 break;
1358 case KEY:
1359 if (db[i] != ':') {
1360 log_debug("sd-device: ignoring invalid db entry with key '%c'", key);
1361
1362 state = INVALID_LINE;
1363 } else {
1364 db[i] = '\0';
1365
1366 state = PRE_VALUE;
1367 }
1368
1369 break;
1370 case PRE_VALUE:
1371 value = &db[i];
1372
1373 state = VALUE;
1374
1375 break;
1376 case INVALID_LINE:
1377 if (strchr(NEWLINE, db[i]))
1378 state = PRE_KEY;
1379
1380 break;
1381 case VALUE:
1382 if (strchr(NEWLINE, db[i])) {
1383 db[i] = '\0';
1384 r = handle_db_line(device, key, value);
1385 if (r < 0)
1386 log_debug_errno(r, "sd-device: failed to handle db entry '%c:%s': %m", key, value);
1387
1388 state = PRE_KEY;
1389 }
1390
1391 break;
1392 default:
1393 assert_not_reached("invalid state when parsing db");
1394 }
1395 }
1396
1397 return 0;
1398 }
1399
1400 static int device_read_db(sd_device *device) {
1401 return device_read_db_aux(device, false);
1402 }
1403
1404 _public_ int sd_device_get_is_initialized(sd_device *device, int *initialized) {
1405 int r;
1406
1407 assert_return(device, -EINVAL);
1408 assert_return(initialized, -EINVAL);
1409
1410 r = device_read_db(device);
1411 if (r < 0)
1412 return r;
1413
1414 *initialized = device->is_initialized;
1415
1416 return 0;
1417 }
1418
1419 _public_ int sd_device_get_usec_since_initialized(sd_device *device, uint64_t *usec) {
1420 usec_t now_ts;
1421 int r;
1422
1423 assert_return(device, -EINVAL);
1424 assert_return(usec, -EINVAL);
1425
1426 r = device_read_db(device);
1427 if (r < 0)
1428 return r;
1429
1430 if (!device->is_initialized)
1431 return -EBUSY;
1432
1433 if (!device->usec_initialized)
1434 return -ENODATA;
1435
1436 now_ts = now(clock_boottime_or_monotonic());
1437
1438 if (now_ts < device->usec_initialized)
1439 return -EIO;
1440
1441 *usec = now_ts - device->usec_initialized;
1442
1443 return 0;
1444 }
1445
1446 _public_ const char *sd_device_get_tag_first(sd_device *device) {
1447 void *v;
1448
1449 assert_return(device, NULL);
1450
1451 (void) device_read_db(device);
1452
1453 device->tags_iterator_generation = device->tags_generation;
1454 device->tags_iterator = ITERATOR_FIRST;
1455
1456 (void) set_iterate(device->tags, &device->tags_iterator, &v);
1457 return v;
1458 }
1459
1460 _public_ const char *sd_device_get_tag_next(sd_device *device) {
1461 void *v;
1462
1463 assert_return(device, NULL);
1464
1465 (void) device_read_db(device);
1466
1467 if (device->tags_iterator_generation != device->tags_generation)
1468 return NULL;
1469
1470 (void) set_iterate(device->tags, &device->tags_iterator, &v);
1471 return v;
1472 }
1473
1474 _public_ const char *sd_device_get_devlink_first(sd_device *device) {
1475 void *v;
1476
1477 assert_return(device, NULL);
1478
1479 (void) device_read_db(device);
1480
1481 device->devlinks_iterator_generation = device->devlinks_generation;
1482 device->devlinks_iterator = ITERATOR_FIRST;
1483
1484 (void) set_iterate(device->devlinks, &device->devlinks_iterator, &v);
1485 return v;
1486 }
1487
1488 _public_ const char *sd_device_get_devlink_next(sd_device *device) {
1489 void *v;
1490
1491 assert_return(device, NULL);
1492
1493 (void) device_read_db(device);
1494
1495 if (device->devlinks_iterator_generation != device->devlinks_generation)
1496 return NULL;
1497
1498 (void) set_iterate(device->devlinks, &device->devlinks_iterator, &v);
1499 return v;
1500 }
1501
1502 static int device_properties_prepare(sd_device *device) {
1503 int r;
1504
1505 assert(device);
1506
1507 r = device_read_uevent_file(device);
1508 if (r < 0)
1509 return r;
1510
1511 r = device_read_db(device);
1512 if (r < 0)
1513 return r;
1514
1515 if (device->property_devlinks_outdated) {
1516 _cleanup_free_ char *devlinks = NULL;
1517 size_t devlinks_allocated = 0, devlinks_len = 0;
1518 const char *devlink;
1519
1520 for (devlink = sd_device_get_devlink_first(device); devlink; devlink = sd_device_get_devlink_next(device)) {
1521 char *e;
1522
1523 if (!GREEDY_REALLOC(devlinks, devlinks_allocated, devlinks_len + strlen(devlink) + 2))
1524 return -ENOMEM;
1525 if (devlinks_len > 0)
1526 stpcpy(devlinks + devlinks_len++, " ");
1527 e = stpcpy(devlinks + devlinks_len, devlink);
1528 devlinks_len = e - devlinks;
1529 }
1530
1531 r = device_add_property_internal(device, "DEVLINKS", devlinks);
1532 if (r < 0)
1533 return r;
1534
1535 device->property_devlinks_outdated = false;
1536 }
1537
1538 if (device->property_tags_outdated) {
1539 _cleanup_free_ char *tags = NULL;
1540 size_t tags_allocated = 0, tags_len = 0;
1541 const char *tag;
1542
1543 if (!GREEDY_REALLOC(tags, tags_allocated, 2))
1544 return -ENOMEM;
1545 stpcpy(tags, ":");
1546 tags_len++;
1547
1548 for (tag = sd_device_get_tag_first(device); tag; tag = sd_device_get_tag_next(device)) {
1549 char *e;
1550
1551 if (!GREEDY_REALLOC(tags, tags_allocated, tags_len + strlen(tag) + 2))
1552 return -ENOMEM;
1553 e = stpcpy(stpcpy(tags + tags_len, tag), ":");
1554 tags_len = e - tags;
1555 }
1556
1557 r = device_add_property_internal(device, "TAGS", tags);
1558 if (r < 0)
1559 return r;
1560
1561 device->property_tags_outdated = false;
1562 }
1563
1564 return 0;
1565 }
1566
1567 _public_ const char *sd_device_get_property_first(sd_device *device, const char **_value) {
1568 const char *key;
1569 const char *value;
1570 int r;
1571
1572 assert_return(device, NULL);
1573
1574 r = device_properties_prepare(device);
1575 if (r < 0)
1576 return NULL;
1577
1578 device->properties_iterator_generation = device->properties_generation;
1579 device->properties_iterator = ITERATOR_FIRST;
1580
1581 ordered_hashmap_iterate(device->properties, &device->properties_iterator, (void**)&value, (const void**)&key);
1582
1583 if (_value)
1584 *_value = value;
1585
1586 return key;
1587 }
1588
1589 _public_ const char *sd_device_get_property_next(sd_device *device, const char **_value) {
1590 const char *key;
1591 const char *value;
1592 int r;
1593
1594 assert_return(device, NULL);
1595
1596 r = device_properties_prepare(device);
1597 if (r < 0)
1598 return NULL;
1599
1600 if (device->properties_iterator_generation != device->properties_generation)
1601 return NULL;
1602
1603 ordered_hashmap_iterate(device->properties, &device->properties_iterator, (void**)&value, (const void**)&key);
1604
1605 if (_value)
1606 *_value = value;
1607
1608 return key;
1609 }
1610
1611 static int device_sysattrs_read_all(sd_device *device) {
1612 _cleanup_closedir_ DIR *dir = NULL;
1613 const char *syspath;
1614 struct dirent *dent;
1615 int r;
1616
1617 assert(device);
1618
1619 if (device->sysattrs_read)
1620 return 0;
1621
1622 r = sd_device_get_syspath(device, &syspath);
1623 if (r < 0)
1624 return r;
1625
1626 dir = opendir(syspath);
1627 if (!dir)
1628 return -errno;
1629
1630 r = set_ensure_allocated(&device->sysattrs, &string_hash_ops);
1631 if (r < 0)
1632 return r;
1633
1634 FOREACH_DIRENT_ALL(dent, dir, return -errno) {
1635 char *path;
1636 struct stat statbuf;
1637
1638 /* only handle symlinks and regular files */
1639 if (!IN_SET(dent->d_type, DT_LNK, DT_REG))
1640 continue;
1641
1642 path = strjoina(syspath, "/", dent->d_name);
1643
1644 if (lstat(path, &statbuf) != 0)
1645 continue;
1646
1647 if (!(statbuf.st_mode & S_IRUSR))
1648 continue;
1649
1650 r = set_put_strdup(device->sysattrs, dent->d_name);
1651 if (r < 0)
1652 return r;
1653 }
1654
1655 device->sysattrs_read = true;
1656
1657 return 0;
1658 }
1659
1660 _public_ const char *sd_device_get_sysattr_first(sd_device *device) {
1661 void *v;
1662 int r;
1663
1664 assert_return(device, NULL);
1665
1666 if (!device->sysattrs_read) {
1667 r = device_sysattrs_read_all(device);
1668 if (r < 0) {
1669 errno = -r;
1670 return NULL;
1671 }
1672 }
1673
1674 device->sysattrs_iterator = ITERATOR_FIRST;
1675
1676 (void) set_iterate(device->sysattrs, &device->sysattrs_iterator, &v);
1677 return v;
1678 }
1679
1680 _public_ const char *sd_device_get_sysattr_next(sd_device *device) {
1681 void *v;
1682
1683 assert_return(device, NULL);
1684
1685 if (!device->sysattrs_read)
1686 return NULL;
1687
1688 (void) set_iterate(device->sysattrs, &device->sysattrs_iterator, &v);
1689 return v;
1690 }
1691
1692 _public_ int sd_device_has_tag(sd_device *device, const char *tag) {
1693 assert_return(device, -EINVAL);
1694 assert_return(tag, -EINVAL);
1695
1696 (void) device_read_db(device);
1697
1698 return !!set_contains(device->tags, tag);
1699 }
1700
1701 _public_ int sd_device_get_property_value(sd_device *device, const char *key, const char **_value) {
1702 char *value;
1703 int r;
1704
1705 assert_return(device, -EINVAL);
1706 assert_return(key, -EINVAL);
1707 assert_return(_value, -EINVAL);
1708
1709 r = device_properties_prepare(device);
1710 if (r < 0)
1711 return r;
1712
1713 value = ordered_hashmap_get(device->properties, key);
1714 if (!value)
1715 return -ENOENT;
1716
1717 *_value = value;
1718
1719 return 0;
1720 }
1721
1722 /* replaces the value if it already exists */
1723 static int device_add_sysattr_value(sd_device *device, const char *_key, char *value) {
1724 _cleanup_free_ char *key = NULL;
1725 _cleanup_free_ char *value_old = NULL;
1726 int r;
1727
1728 assert(device);
1729 assert(_key);
1730
1731 r = hashmap_ensure_allocated(&device->sysattr_values, &string_hash_ops);
1732 if (r < 0)
1733 return r;
1734
1735 value_old = hashmap_remove2(device->sysattr_values, _key, (void **)&key);
1736 if (!key) {
1737 key = strdup(_key);
1738 if (!key)
1739 return -ENOMEM;
1740 }
1741
1742 r = hashmap_put(device->sysattr_values, key, value);
1743 if (r < 0)
1744 return r;
1745
1746 key = NULL;
1747
1748 return 0;
1749 }
1750
1751 static int device_get_sysattr_value(sd_device *device, const char *_key, const char **_value) {
1752 const char *key = NULL, *value;
1753
1754 assert(device);
1755 assert(_key);
1756
1757 value = hashmap_get2(device->sysattr_values, _key, (void **) &key);
1758 if (!key)
1759 return -ENOENT;
1760
1761 if (_value)
1762 *_value = value;
1763
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 *syspath, *cached_value = NULL;
1772 char *path;
1773 struct stat statbuf;
1774 int r;
1775
1776 assert_return(device, -EINVAL);
1777 assert_return(sysattr, -EINVAL);
1778
1779 /* look for possibly already cached result */
1780 r = device_get_sysattr_value(device, sysattr, &cached_value);
1781 if (r != -ENOENT) {
1782 if (r < 0)
1783 return r;
1784
1785 if (!cached_value)
1786 /* we looked up the sysattr before and it did not exist */
1787 return -ENOENT;
1788
1789 if (_value)
1790 *_value = cached_value;
1791
1792 return 0;
1793 }
1794
1795 r = sd_device_get_syspath(device, &syspath);
1796 if (r < 0)
1797 return r;
1798
1799 path = strjoina(syspath, "/", sysattr);
1800 r = lstat(path, &statbuf);
1801 if (r < 0) {
1802 /* remember that we could not access the sysattr */
1803 r = device_add_sysattr_value(device, sysattr, NULL);
1804 if (r < 0)
1805 return r;
1806
1807 return -ENOENT;
1808 } else if (S_ISLNK(statbuf.st_mode)) {
1809 /* Some core links return only the last element of the target path,
1810 * these are just values, the paths should not be exposed. */
1811 if (STR_IN_SET(sysattr, "driver", "subsystem", "module")) {
1812 r = readlink_value(path, &value);
1813 if (r < 0)
1814 return r;
1815 } else
1816 return -EINVAL;
1817 } else if (S_ISDIR(statbuf.st_mode)) {
1818 /* skip directories */
1819 return -EINVAL;
1820 } else if (!(statbuf.st_mode & S_IRUSR)) {
1821 /* skip non-readable files */
1822 return -EPERM;
1823 } else {
1824 size_t size;
1825
1826 /* read attribute value */
1827 r = read_full_file(path, &value, &size);
1828 if (r < 0)
1829 return r;
1830
1831 /* drop trailing newlines */
1832 while (size > 0 && value[--size] == '\n')
1833 value[size] = '\0';
1834 }
1835
1836 r = device_add_sysattr_value(device, sysattr, value);
1837 if (r < 0)
1838 return r;
1839
1840 *_value = value;
1841 value = NULL;
1842
1843 return 0;
1844 }
1845
1846 static void device_remove_sysattr_value(sd_device *device, const char *_key) {
1847 _cleanup_free_ char *key = NULL;
1848 _cleanup_free_ char *value = NULL;
1849
1850 assert(device);
1851 assert(_key);
1852
1853 value = hashmap_remove2(device->sysattr_values, _key, (void **) &key);
1854
1855 return;
1856 }
1857
1858 /* set the attribute and save it in the cache. If a NULL value is passed the
1859 * attribute is cleared from the cache */
1860 _public_ int sd_device_set_sysattr_value(sd_device *device, const char *sysattr, char *_value) {
1861 _cleanup_close_ int fd = -1;
1862 _cleanup_free_ char *value = NULL;
1863 const char *syspath;
1864 char *path;
1865 size_t len = 0;
1866 ssize_t size;
1867 int r;
1868
1869 assert_return(device, -EINVAL);
1870 assert_return(sysattr, -EINVAL);
1871
1872 if (!_value) {
1873 device_remove_sysattr_value(device, sysattr);
1874
1875 return 0;
1876 }
1877
1878 r = sd_device_get_syspath(device, &syspath);
1879 if (r < 0)
1880 return r;
1881
1882 path = strjoina(syspath, "/", sysattr);
1883
1884 fd = open(path, O_WRONLY | O_CLOEXEC | O_NOFOLLOW);
1885 if (fd < 0) {
1886 if (errno == ELOOP)
1887 return -EINVAL;
1888 if (errno == EISDIR)
1889 return -EISDIR;
1890
1891 value = strdup("");
1892 if (!value)
1893 return -ENOMEM;
1894
1895 r = device_add_sysattr_value(device, sysattr, value);
1896 if (r < 0)
1897 return r;
1898 value = NULL;
1899
1900 return -ENXIO;
1901 }
1902
1903 len = strlen(_value);
1904
1905 /* drop trailing newlines */
1906 while (len > 0 && _value[len - 1] == '\n')
1907 len --;
1908
1909 /* value length is limited to 4k */
1910 if (len > 4096)
1911 return -EINVAL;
1912
1913 value = strndup(_value, len);
1914 if (!value)
1915 return -ENOMEM;
1916
1917 size = write(fd, value, len);
1918 if (size < 0)
1919 return -errno;
1920
1921 if ((size_t)size != len)
1922 return -EIO;
1923
1924 r = device_add_sysattr_value(device, sysattr, value);
1925 if (r < 0)
1926 return r;
1927 value = NULL;
1928
1929 return 0;
1930 }