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