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