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