]> git.proxmox.com Git - systemd.git/blob - src/libsystemd/sd-device/sd-device.c
Imported Upstream version 231
[systemd.git] / src / libsystemd / sd-device / sd-device.c
1 /***
2 This file is part of systemd.
3
4 Copyright 2008-2012 Kay Sievers <kay@vrfy.org>
5 Copyright 2014 Tom Gundersen <teg@jklm.no>
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19 ***/
20
21 #include <ctype.h>
22 #include <net/if.h>
23 #include <sys/types.h>
24
25 #include "sd-device.h"
26
27 #include "alloc-util.h"
28 #include "device-internal.h"
29 #include "device-private.h"
30 #include "device-util.h"
31 #include "fd-util.h"
32 #include "fileio.h"
33 #include "fs-util.h"
34 #include "hashmap.h"
35 #include "macro.h"
36 #include "parse-util.h"
37 #include "path-util.h"
38 #include "set.h"
39 #include "stat-util.h"
40 #include "string-util.h"
41 #include "strv.h"
42 #include "strxcpyx.h"
43 #include "util.h"
44
45 int device_new_aux(sd_device **ret) {
46 _cleanup_(sd_device_unrefp) sd_device *device = NULL;
47
48 assert(ret);
49
50 device = new0(sd_device, 1);
51 if (!device)
52 return -ENOMEM;
53
54 device->n_ref = 1;
55 device->watch_handle = -1;
56
57 *ret = device;
58 device = NULL;
59
60 return 0;
61 }
62
63 _public_ sd_device *sd_device_ref(sd_device *device) {
64 if (device)
65 assert_se(++ device->n_ref >= 2);
66
67 return device;
68 }
69
70 _public_ sd_device *sd_device_unref(sd_device *device) {
71 if (device && -- device->n_ref == 0) {
72 sd_device_unref(device->parent);
73 free(device->syspath);
74 free(device->sysname);
75 free(device->devtype);
76 free(device->devname);
77 free(device->subsystem);
78 free(device->driver_subsystem);
79 free(device->driver);
80 free(device->id_filename);
81 free(device->properties_strv);
82 free(device->properties_nulstr);
83
84 ordered_hashmap_free_free_free(device->properties);
85 ordered_hashmap_free_free_free(device->properties_db);
86 hashmap_free_free_free(device->sysattr_values);
87 set_free_free(device->sysattrs);
88 set_free_free(device->tags);
89 set_free_free(device->devlinks);
90
91 free(device);
92 }
93
94 return NULL;
95 }
96
97 int device_add_property_aux(sd_device *device, const char *_key, const char *_value, bool db) {
98 OrderedHashmap **properties;
99
100 assert(device);
101 assert(_key);
102
103 if (db)
104 properties = &device->properties_db;
105 else
106 properties = &device->properties;
107
108 if (_value) {
109 _cleanup_free_ char *key = NULL, *value = NULL, *old_key = NULL, *old_value = NULL;
110 int r;
111
112 r = ordered_hashmap_ensure_allocated(properties, &string_hash_ops);
113 if (r < 0)
114 return r;
115
116 key = strdup(_key);
117 if (!key)
118 return -ENOMEM;
119
120 value = strdup(_value);
121 if (!value)
122 return -ENOMEM;
123
124 old_value = ordered_hashmap_get2(*properties, key, (void**) &old_key);
125
126 r = ordered_hashmap_replace(*properties, key, value);
127 if (r < 0)
128 return r;
129
130 key = NULL;
131 value = NULL;
132 } else {
133 _cleanup_free_ char *key = NULL;
134 _cleanup_free_ char *value = NULL;
135
136 value = ordered_hashmap_remove2(*properties, _key, (void**) &key);
137 }
138
139 if (!db) {
140 device->properties_generation++;
141 device->properties_buf_outdated = true;
142 }
143
144 return 0;
145 }
146
147 int device_add_property_internal(sd_device *device, const char *key, const char *value) {
148 return device_add_property_aux(device, key, value, false);
149 }
150
151 int device_set_syspath(sd_device *device, const char *_syspath, bool verify) {
152 _cleanup_free_ char *syspath = NULL;
153 const char *devpath;
154 int r;
155
156 assert(device);
157 assert(_syspath);
158
159 /* must be a subdirectory of /sys */
160 if (!path_startswith(_syspath, "/sys/")) {
161 log_debug("sd-device: syspath '%s' is not a subdirectory of /sys", _syspath);
162 return -EINVAL;
163 }
164
165 if (verify) {
166 r = readlink_and_canonicalize(_syspath, &syspath);
167 if (r == -ENOENT)
168 /* the device does not exist (any more?) */
169 return -ENODEV;
170 else if (r == -EINVAL) {
171 /* not a symlink */
172 syspath = canonicalize_file_name(_syspath);
173 if (!syspath) {
174 if (errno == ENOENT)
175 /* the device does not exist (any more?) */
176 return -ENODEV;
177
178 return log_debug_errno(errno, "sd-device: could not canonicalize '%s': %m", _syspath);
179 }
180 } else if (r < 0) {
181 log_debug_errno(r, "sd-device: could not get target of '%s': %m", _syspath);
182 return r;
183 }
184
185 if (path_startswith(syspath, "/sys/devices/")) {
186 char *path;
187
188 /* all 'devices' require an 'uevent' file */
189 path = strjoina(syspath, "/uevent");
190 r = access(path, F_OK);
191 if (r < 0) {
192 if (errno == ENOENT)
193 /* this is not a valid device */
194 return -ENODEV;
195
196 log_debug("sd-device: %s does not have an uevent file: %m", syspath);
197 return -errno;
198 }
199 } else {
200 /* everything else just needs to be a directory */
201 if (!is_dir(syspath, false))
202 return -ENODEV;
203 }
204 } else {
205 syspath = strdup(_syspath);
206 if (!syspath)
207 return -ENOMEM;
208 }
209
210 devpath = syspath + strlen("/sys");
211
212 r = device_add_property_internal(device, "DEVPATH", devpath);
213 if (r < 0)
214 return r;
215
216 free(device->syspath);
217 device->syspath = syspath;
218 syspath = NULL;
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(type == 'b' || type == '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 return -ENODEV;
327 }
328
329 int device_set_devtype(sd_device *device, const char *_devtype) {
330 _cleanup_free_ char *devtype = NULL;
331 int r;
332
333 assert(device);
334 assert(_devtype);
335
336 devtype = strdup(_devtype);
337 if (!devtype)
338 return -ENOMEM;
339
340 r = device_add_property_internal(device, "DEVTYPE", devtype);
341 if (r < 0)
342 return r;
343
344 free(device->devtype);
345 device->devtype = devtype;
346 devtype = NULL;
347
348 return 0;
349 }
350
351 int device_set_ifindex(sd_device *device, const char *_ifindex) {
352 int ifindex, r;
353
354 assert(device);
355 assert(_ifindex);
356
357 r = parse_ifindex(_ifindex, &ifindex);
358 if (r < 0)
359 return r;
360
361 r = device_add_property_internal(device, "IFINDEX", _ifindex);
362 if (r < 0)
363 return r;
364
365 device->ifindex = ifindex;
366
367 return 0;
368 }
369
370 int device_set_devname(sd_device *device, const char *_devname) {
371 _cleanup_free_ char *devname = NULL;
372 int r;
373
374 assert(device);
375 assert(_devname);
376
377 if (_devname[0] != '/') {
378 r = asprintf(&devname, "/dev/%s", _devname);
379 if (r < 0)
380 return -ENOMEM;
381 } else {
382 devname = strdup(_devname);
383 if (!devname)
384 return -ENOMEM;
385 }
386
387 r = device_add_property_internal(device, "DEVNAME", devname);
388 if (r < 0)
389 return r;
390
391 free(device->devname);
392 device->devname = devname;
393 devname = NULL;
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 /* fall through 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(PF_INET, SOCK_DGRAM, 0);
633 if (sk < 0)
634 return -errno;
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(device->subsystem);
759 device->subsystem = subsystem;
760 subsystem = NULL;
761
762 device->subsystem_set = true;
763
764 return 0;
765 }
766
767 static int device_set_drivers_subsystem(sd_device *device, const char *_subsystem) {
768 _cleanup_free_ char *subsystem = NULL;
769 int r;
770
771 assert(device);
772 assert(_subsystem);
773 assert(*_subsystem);
774
775 subsystem = strdup(_subsystem);
776 if (!subsystem)
777 return -ENOMEM;
778
779 r = device_set_subsystem(device, "drivers");
780 if (r < 0)
781 return r;
782
783 free(device->driver_subsystem);
784 device->driver_subsystem = subsystem;
785 subsystem = NULL;
786
787 return 0;
788 }
789
790 _public_ int sd_device_get_subsystem(sd_device *device, const char **ret) {
791 const char *syspath, *drivers = NULL;
792 int r;
793
794 assert_return(ret, -EINVAL);
795 assert_return(device, -EINVAL);
796
797 r = sd_device_get_syspath(device, &syspath);
798 if (r < 0)
799 return r;
800
801 if (!device->subsystem_set) {
802 _cleanup_free_ char *subsystem = NULL;
803 char *path;
804
805 /* read 'subsystem' link */
806 path = strjoina(syspath, "/subsystem");
807 r = readlink_value(path, &subsystem);
808 if (r >= 0)
809 r = device_set_subsystem(device, subsystem);
810 /* use implicit names */
811 else if (path_startswith(device->devpath, "/module/"))
812 r = device_set_subsystem(device, "module");
813 else if (!(drivers = strstr(syspath, "/drivers/")) &&
814 (path_startswith(device->devpath, "/subsystem/") ||
815 path_startswith(device->devpath, "/class/") ||
816 path_startswith(device->devpath, "/bus/")))
817 r = device_set_subsystem(device, "subsystem");
818 if (r < 0 && r != -ENOENT)
819 return log_debug_errno(r, "sd-device: could not set subsystem for %s: %m", device->devpath);
820
821 device->subsystem_set = true;
822 } else if (!device->driver_subsystem_set)
823 drivers = strstr(syspath, "/drivers/");
824
825 if (!device->driver_subsystem_set) {
826 if (drivers) {
827 _cleanup_free_ char *subpath = NULL;
828
829 subpath = strndup(syspath, drivers - syspath);
830 if (!subpath)
831 r = -ENOMEM;
832 else {
833 const char *subsys;
834
835 subsys = strrchr(subpath, '/');
836 if (!subsys)
837 r = -EINVAL;
838 else
839 r = device_set_drivers_subsystem(device, subsys + 1);
840 }
841 if (r < 0 && r != -ENOENT)
842 return log_debug_errno(r, "sd-device: could not set subsystem for driver %s: %m", device->devpath);
843 }
844
845 device->driver_subsystem_set = true;
846 }
847
848 if (!device->subsystem)
849 return -ENOENT;
850
851 *ret = device->subsystem;
852
853 return 0;
854 }
855
856 _public_ int sd_device_get_devtype(sd_device *device, const char **devtype) {
857 int r;
858
859 assert(devtype);
860 assert(device);
861
862 r = device_read_uevent_file(device);
863 if (r < 0)
864 return r;
865
866 *devtype = device->devtype;
867
868 return 0;
869 }
870
871 _public_ int sd_device_get_parent_with_subsystem_devtype(sd_device *child, const char *subsystem, const char *devtype, sd_device **ret) {
872 sd_device *parent = NULL;
873 int r;
874
875 assert_return(child, -EINVAL);
876 assert_return(subsystem, -EINVAL);
877
878 r = sd_device_get_parent(child, &parent);
879 while (r >= 0) {
880 const char *parent_subsystem = NULL;
881 const char *parent_devtype = NULL;
882
883 (void)sd_device_get_subsystem(parent, &parent_subsystem);
884 if (streq_ptr(parent_subsystem, subsystem)) {
885 if (!devtype)
886 break;
887
888 (void)sd_device_get_devtype(parent, &parent_devtype);
889 if (streq_ptr(parent_devtype, devtype))
890 break;
891 }
892 r = sd_device_get_parent(parent, &parent);
893 }
894
895 if (r < 0)
896 return r;
897
898 *ret = parent;
899
900 return 0;
901 }
902
903 _public_ int sd_device_get_devnum(sd_device *device, dev_t *devnum) {
904 int r;
905
906 assert_return(device, -EINVAL);
907 assert_return(devnum, -EINVAL);
908
909 r = device_read_uevent_file(device);
910 if (r < 0)
911 return r;
912
913 *devnum = device->devnum;
914
915 return 0;
916 }
917
918 int device_set_driver(sd_device *device, const char *_driver) {
919 _cleanup_free_ char *driver = NULL;
920 int r;
921
922 assert(device);
923 assert(_driver);
924
925 driver = strdup(_driver);
926 if (!driver)
927 return -ENOMEM;
928
929 r = device_add_property_internal(device, "DRIVER", driver);
930 if (r < 0)
931 return r;
932
933 free(device->driver);
934 device->driver = driver;
935 driver = NULL;
936
937 device->driver_set = true;
938
939 return 0;
940 }
941
942 _public_ int sd_device_get_driver(sd_device *device, const char **ret) {
943 assert_return(device, -EINVAL);
944 assert_return(ret, -EINVAL);
945
946 if (!device->driver_set) {
947 _cleanup_free_ char *driver = NULL;
948 const char *syspath;
949 char *path;
950 int r;
951
952 r = sd_device_get_syspath(device, &syspath);
953 if (r < 0)
954 return r;
955
956 path = strjoina(syspath, "/driver");
957 r = readlink_value(path, &driver);
958 if (r >= 0) {
959 r = device_set_driver(device, driver);
960 if (r < 0)
961 return log_debug_errno(r, "sd-device: could not set driver for %s: %m", device->devpath);
962 } else if (r == -ENOENT)
963 device->driver_set = true;
964 else
965 return log_debug_errno(r, "sd-device: could not set driver for %s: %m", device->devpath);
966 }
967
968 if (!device->driver)
969 return -ENOENT;
970
971 *ret = device->driver;
972
973 return 0;
974 }
975
976 _public_ int sd_device_get_devpath(sd_device *device, const char **devpath) {
977 assert_return(device, -EINVAL);
978 assert_return(devpath, -EINVAL);
979
980 assert(device->devpath);
981 assert(device->devpath[0] == '/');
982
983 *devpath = device->devpath;
984
985 return 0;
986 }
987
988 _public_ int sd_device_get_devname(sd_device *device, const char **devname) {
989 int r;
990
991 assert_return(device, -EINVAL);
992 assert_return(devname, -EINVAL);
993
994 r = device_read_uevent_file(device);
995 if (r < 0)
996 return r;
997
998 if (!device->devname)
999 return -ENOENT;
1000
1001 assert(path_startswith(device->devname, "/dev/"));
1002
1003 *devname = device->devname;
1004
1005 return 0;
1006 }
1007
1008 static int device_set_sysname(sd_device *device) {
1009 _cleanup_free_ char *sysname = NULL;
1010 const char *sysnum = NULL;
1011 const char *pos;
1012 size_t len = 0;
1013
1014 pos = strrchr(device->devpath, '/');
1015 if (!pos)
1016 return -EINVAL;
1017 pos++;
1018
1019 /* devpath is not a root directory */
1020 if (*pos == '\0' || pos <= device->devpath)
1021 return -EINVAL;
1022
1023 sysname = strdup(pos);
1024 if (!sysname)
1025 return -ENOMEM;
1026
1027 /* some devices have '!' in their name, change that to '/' */
1028 while (sysname[len] != '\0') {
1029 if (sysname[len] == '!')
1030 sysname[len] = '/';
1031
1032 len++;
1033 }
1034
1035 /* trailing number */
1036 while (len > 0 && isdigit(sysname[--len]))
1037 sysnum = &sysname[len];
1038
1039 if (len == 0)
1040 sysnum = NULL;
1041
1042 free(device->sysname);
1043 device->sysname = sysname;
1044 sysname = NULL;
1045
1046 device->sysnum = sysnum;
1047
1048 device->sysname_set = true;
1049
1050 return 0;
1051 }
1052
1053 _public_ int sd_device_get_sysname(sd_device *device, const char **ret) {
1054 int r;
1055
1056 assert_return(device, -EINVAL);
1057 assert_return(ret, -EINVAL);
1058
1059 if (!device->sysname_set) {
1060 r = device_set_sysname(device);
1061 if (r < 0)
1062 return r;
1063 }
1064
1065 assert_return(device->sysname, -ENOENT);
1066
1067 *ret = device->sysname;
1068
1069 return 0;
1070 }
1071
1072 _public_ int sd_device_get_sysnum(sd_device *device, const char **ret) {
1073 int r;
1074
1075 assert_return(device, -EINVAL);
1076 assert_return(ret, -EINVAL);
1077
1078 if (!device->sysname_set) {
1079 r = device_set_sysname(device);
1080 if (r < 0)
1081 return r;
1082 }
1083
1084 *ret = device->sysnum;
1085
1086 return 0;
1087 }
1088
1089 static bool is_valid_tag(const char *tag) {
1090 assert(tag);
1091
1092 return !strchr(tag, ':') && !strchr(tag, ' ');
1093 }
1094
1095 int device_add_tag(sd_device *device, const char *tag) {
1096 int r;
1097
1098 assert(device);
1099 assert(tag);
1100
1101 if (!is_valid_tag(tag))
1102 return -EINVAL;
1103
1104 r = set_ensure_allocated(&device->tags, &string_hash_ops);
1105 if (r < 0)
1106 return r;
1107
1108 r = set_put_strdup(device->tags, tag);
1109 if (r < 0)
1110 return r;
1111
1112 device->tags_generation++;
1113 device->property_tags_outdated = true;
1114
1115 return 0;
1116 }
1117
1118 int device_add_devlink(sd_device *device, const char *devlink) {
1119 int r;
1120
1121 assert(device);
1122 assert(devlink);
1123
1124 r = set_ensure_allocated(&device->devlinks, &string_hash_ops);
1125 if (r < 0)
1126 return r;
1127
1128 r = set_put_strdup(device->devlinks, devlink);
1129 if (r < 0)
1130 return r;
1131
1132 device->devlinks_generation++;
1133 device->property_devlinks_outdated = true;
1134
1135 return 0;
1136 }
1137
1138 static int device_add_property_internal_from_string(sd_device *device, const char *str) {
1139 _cleanup_free_ char *key = NULL;
1140 char *value;
1141
1142 assert(device);
1143 assert(str);
1144
1145 key = strdup(str);
1146 if (!key)
1147 return -ENOMEM;
1148
1149 value = strchr(key, '=');
1150 if (!value)
1151 return -EINVAL;
1152
1153 *value = '\0';
1154
1155 if (isempty(++value))
1156 value = NULL;
1157
1158 return device_add_property_internal(device, key, value);
1159 }
1160
1161 int device_set_usec_initialized(sd_device *device, const char *initialized) {
1162 uint64_t usec_initialized;
1163 int r;
1164
1165 assert(device);
1166 assert(initialized);
1167
1168 r = safe_atou64(initialized, &usec_initialized);
1169 if (r < 0)
1170 return r;
1171
1172 r = device_add_property_internal(device, "USEC_INITIALIZED", initialized);
1173 if (r < 0)
1174 return r;
1175
1176 device->usec_initialized = usec_initialized;
1177
1178 return 0;
1179 }
1180
1181 static int handle_db_line(sd_device *device, char key, const char *value) {
1182 char *path;
1183 int r;
1184
1185 assert(device);
1186 assert(value);
1187
1188 switch (key) {
1189 case 'G':
1190 r = device_add_tag(device, value);
1191 if (r < 0)
1192 return r;
1193
1194 break;
1195 case 'S':
1196 path = strjoina("/dev/", value);
1197 r = device_add_devlink(device, path);
1198 if (r < 0)
1199 return r;
1200
1201 break;
1202 case 'E':
1203 r = device_add_property_internal_from_string(device, value);
1204 if (r < 0)
1205 return r;
1206
1207 break;
1208 case 'I':
1209 r = device_set_usec_initialized(device, value);
1210 if (r < 0)
1211 return r;
1212
1213 break;
1214 case 'L':
1215 r = safe_atoi(value, &device->devlink_priority);
1216 if (r < 0)
1217 return r;
1218
1219 break;
1220 case 'W':
1221 r = safe_atoi(value, &device->watch_handle);
1222 if (r < 0)
1223 return r;
1224
1225 break;
1226 default:
1227 log_debug("device db: unknown key '%c'", key);
1228 }
1229
1230 return 0;
1231 }
1232
1233 int device_get_id_filename(sd_device *device, const char **ret) {
1234 assert(device);
1235 assert(ret);
1236
1237 if (!device->id_filename) {
1238 _cleanup_free_ char *id = NULL;
1239 const char *subsystem;
1240 dev_t devnum;
1241 int ifindex, r;
1242
1243 r = sd_device_get_subsystem(device, &subsystem);
1244 if (r < 0)
1245 return r;
1246
1247 r = sd_device_get_devnum(device, &devnum);
1248 if (r < 0)
1249 return r;
1250
1251 r = sd_device_get_ifindex(device, &ifindex);
1252 if (r < 0)
1253 return r;
1254
1255 if (major(devnum) > 0) {
1256 assert(subsystem);
1257
1258 /* use dev_t — b259:131072, c254:0 */
1259 r = asprintf(&id, "%c%u:%u",
1260 streq(subsystem, "block") ? 'b' : 'c',
1261 major(devnum), minor(devnum));
1262 if (r < 0)
1263 return -ENOMEM;
1264 } else if (ifindex > 0) {
1265 /* use netdev ifindex — n3 */
1266 r = asprintf(&id, "n%u", ifindex);
1267 if (r < 0)
1268 return -ENOMEM;
1269 } else {
1270 /* use $subsys:$sysname — pci:0000:00:1f.2
1271 * sysname() has '!' translated, get it from devpath
1272 */
1273 const char *sysname;
1274
1275 sysname = basename(device->devpath);
1276 if (!sysname)
1277 return -EINVAL;
1278
1279 if (!subsystem)
1280 return -EINVAL;
1281
1282 if (streq(subsystem, "drivers")) {
1283 /* the 'drivers' pseudo-subsystem is special, and needs the real subsystem
1284 * encoded as well */
1285 r = asprintf(&id, "+drivers:%s:%s", device->driver_subsystem, sysname);
1286 if (r < 0)
1287 return -ENOMEM;
1288 } else {
1289 r = asprintf(&id, "+%s:%s", subsystem, sysname);
1290 if (r < 0)
1291 return -ENOMEM;
1292 }
1293 }
1294
1295 device->id_filename = id;
1296 id = NULL;
1297 }
1298
1299 *ret = device->id_filename;
1300
1301 return 0;
1302 }
1303
1304 int device_read_db_aux(sd_device *device, bool force) {
1305 _cleanup_free_ char *db = NULL;
1306 char *path;
1307 const char *id, *value;
1308 char key;
1309 size_t db_len;
1310 unsigned i;
1311 int r;
1312
1313 enum {
1314 PRE_KEY,
1315 KEY,
1316 PRE_VALUE,
1317 VALUE,
1318 INVALID_LINE,
1319 } state = PRE_KEY;
1320
1321 if (device->db_loaded || (!force && device->sealed))
1322 return 0;
1323
1324 device->db_loaded = true;
1325
1326 r = device_get_id_filename(device, &id);
1327 if (r < 0)
1328 return r;
1329
1330 path = strjoina("/run/udev/data/", id);
1331
1332 r = read_full_file(path, &db, &db_len);
1333 if (r < 0) {
1334 if (r == -ENOENT)
1335 return 0;
1336 else
1337 return log_debug_errno(r, "sd-device: failed to read db '%s': %m", path);
1338 }
1339
1340 /* devices with a database entry are initialized */
1341 device->is_initialized = true;
1342
1343 for (i = 0; i < db_len; i++) {
1344 switch (state) {
1345 case PRE_KEY:
1346 if (!strchr(NEWLINE, db[i])) {
1347 key = db[i];
1348
1349 state = KEY;
1350 }
1351
1352 break;
1353 case KEY:
1354 if (db[i] != ':') {
1355 log_debug("sd-device: ignoring invalid db entry with key '%c'", key);
1356
1357 state = INVALID_LINE;
1358 } else {
1359 db[i] = '\0';
1360
1361 state = PRE_VALUE;
1362 }
1363
1364 break;
1365 case PRE_VALUE:
1366 value = &db[i];
1367
1368 state = VALUE;
1369
1370 break;
1371 case INVALID_LINE:
1372 if (strchr(NEWLINE, db[i]))
1373 state = PRE_KEY;
1374
1375 break;
1376 case VALUE:
1377 if (strchr(NEWLINE, db[i])) {
1378 db[i] = '\0';
1379 r = handle_db_line(device, key, value);
1380 if (r < 0)
1381 log_debug_errno(r, "sd-device: failed to handle db entry '%c:%s': %m", key, value);
1382
1383 state = PRE_KEY;
1384 }
1385
1386 break;
1387 default:
1388 assert_not_reached("invalid state when parsing db");
1389 }
1390 }
1391
1392 return 0;
1393 }
1394
1395 static int device_read_db(sd_device *device) {
1396 return device_read_db_aux(device, false);
1397 }
1398
1399 _public_ int sd_device_get_is_initialized(sd_device *device, int *initialized) {
1400 int r;
1401
1402 assert_return(device, -EINVAL);
1403 assert_return(initialized, -EINVAL);
1404
1405 r = device_read_db(device);
1406 if (r < 0)
1407 return r;
1408
1409 *initialized = device->is_initialized;
1410
1411 return 0;
1412 }
1413
1414 _public_ int sd_device_get_usec_since_initialized(sd_device *device, uint64_t *usec) {
1415 usec_t now_ts;
1416 int r;
1417
1418 assert_return(device, -EINVAL);
1419 assert_return(usec, -EINVAL);
1420
1421 r = device_read_db(device);
1422 if (r < 0)
1423 return r;
1424
1425 if (!device->is_initialized)
1426 return -EBUSY;
1427
1428 if (!device->usec_initialized)
1429 return -ENODATA;
1430
1431 now_ts = now(clock_boottime_or_monotonic());
1432
1433 if (now_ts < device->usec_initialized)
1434 return -EIO;
1435
1436 *usec = now_ts - device->usec_initialized;
1437
1438 return 0;
1439 }
1440
1441 _public_ const char *sd_device_get_tag_first(sd_device *device) {
1442 void *v;
1443
1444 assert_return(device, NULL);
1445
1446 (void) device_read_db(device);
1447
1448 device->tags_iterator_generation = device->tags_generation;
1449 device->tags_iterator = ITERATOR_FIRST;
1450
1451 (void) set_iterate(device->tags, &device->tags_iterator, &v);
1452 return v;
1453 }
1454
1455 _public_ const char *sd_device_get_tag_next(sd_device *device) {
1456 void *v;
1457
1458 assert_return(device, NULL);
1459
1460 (void) device_read_db(device);
1461
1462 if (device->tags_iterator_generation != device->tags_generation)
1463 return NULL;
1464
1465 (void) set_iterate(device->tags, &device->tags_iterator, &v);
1466 return v;
1467 }
1468
1469 _public_ const char *sd_device_get_devlink_first(sd_device *device) {
1470 void *v;
1471
1472 assert_return(device, NULL);
1473
1474 (void) device_read_db(device);
1475
1476 device->devlinks_iterator_generation = device->devlinks_generation;
1477 device->devlinks_iterator = ITERATOR_FIRST;
1478
1479 (void) set_iterate(device->devlinks, &device->devlinks_iterator, &v);
1480 return v;
1481 }
1482
1483 _public_ const char *sd_device_get_devlink_next(sd_device *device) {
1484 void *v;
1485
1486 assert_return(device, NULL);
1487
1488 (void) device_read_db(device);
1489
1490 if (device->devlinks_iterator_generation != device->devlinks_generation)
1491 return NULL;
1492
1493 (void) set_iterate(device->devlinks, &device->devlinks_iterator, &v);
1494 return v;
1495 }
1496
1497 static int device_properties_prepare(sd_device *device) {
1498 int r;
1499
1500 assert(device);
1501
1502 r = device_read_uevent_file(device);
1503 if (r < 0)
1504 return r;
1505
1506 r = device_read_db(device);
1507 if (r < 0)
1508 return r;
1509
1510 if (device->property_devlinks_outdated) {
1511 _cleanup_free_ char *devlinks = NULL;
1512 size_t devlinks_allocated = 0, devlinks_len = 0;
1513 const char *devlink;
1514
1515 for (devlink = sd_device_get_devlink_first(device); devlink; devlink = sd_device_get_devlink_next(device)) {
1516 char *e;
1517
1518 if (!GREEDY_REALLOC(devlinks, devlinks_allocated, devlinks_len + strlen(devlink) + 2))
1519 return -ENOMEM;
1520 if (devlinks_len > 0)
1521 stpcpy(devlinks + devlinks_len++, " ");
1522 e = stpcpy(devlinks + devlinks_len, devlink);
1523 devlinks_len = e - devlinks;
1524 }
1525
1526 r = device_add_property_internal(device, "DEVLINKS", devlinks);
1527 if (r < 0)
1528 return r;
1529
1530 device->property_devlinks_outdated = false;
1531 }
1532
1533 if (device->property_tags_outdated) {
1534 _cleanup_free_ char *tags = NULL;
1535 size_t tags_allocated = 0, tags_len = 0;
1536 const char *tag;
1537
1538 if (!GREEDY_REALLOC(tags, tags_allocated, 2))
1539 return -ENOMEM;
1540 stpcpy(tags, ":");
1541 tags_len++;
1542
1543 for (tag = sd_device_get_tag_first(device); tag; tag = sd_device_get_tag_next(device)) {
1544 char *e;
1545
1546 if (!GREEDY_REALLOC(tags, tags_allocated, tags_len + strlen(tag) + 2))
1547 return -ENOMEM;
1548 e = stpcpy(stpcpy(tags + tags_len, tag), ":");
1549 tags_len = e - tags;
1550 }
1551
1552 r = device_add_property_internal(device, "TAGS", tags);
1553 if (r < 0)
1554 return r;
1555
1556 device->property_tags_outdated = false;
1557 }
1558
1559 return 0;
1560 }
1561
1562 _public_ const char *sd_device_get_property_first(sd_device *device, const char **_value) {
1563 const char *key;
1564 const char *value;
1565 int r;
1566
1567 assert_return(device, NULL);
1568
1569 r = device_properties_prepare(device);
1570 if (r < 0)
1571 return NULL;
1572
1573 device->properties_iterator_generation = device->properties_generation;
1574 device->properties_iterator = ITERATOR_FIRST;
1575
1576 ordered_hashmap_iterate(device->properties, &device->properties_iterator, (void**)&value, (const void**)&key);
1577
1578 if (_value)
1579 *_value = value;
1580
1581 return key;
1582 }
1583
1584 _public_ const char *sd_device_get_property_next(sd_device *device, const char **_value) {
1585 const char *key;
1586 const char *value;
1587 int r;
1588
1589 assert_return(device, NULL);
1590
1591 r = device_properties_prepare(device);
1592 if (r < 0)
1593 return NULL;
1594
1595 if (device->properties_iterator_generation != device->properties_generation)
1596 return NULL;
1597
1598 ordered_hashmap_iterate(device->properties, &device->properties_iterator, (void**)&value, (const void**)&key);
1599
1600 if (_value)
1601 *_value = value;
1602
1603 return key;
1604 }
1605
1606 static int device_sysattrs_read_all(sd_device *device) {
1607 _cleanup_closedir_ DIR *dir = NULL;
1608 const char *syspath;
1609 struct dirent *dent;
1610 int r;
1611
1612 assert(device);
1613
1614 if (device->sysattrs_read)
1615 return 0;
1616
1617 r = sd_device_get_syspath(device, &syspath);
1618 if (r < 0)
1619 return r;
1620
1621 dir = opendir(syspath);
1622 if (!dir)
1623 return -errno;
1624
1625 r = set_ensure_allocated(&device->sysattrs, &string_hash_ops);
1626 if (r < 0)
1627 return r;
1628
1629 for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
1630 char *path;
1631 struct stat statbuf;
1632
1633 /* only handle symlinks and regular files */
1634 if (dent->d_type != DT_LNK && dent->d_type != DT_REG)
1635 continue;
1636
1637 path = strjoina(syspath, "/", dent->d_name);
1638
1639 if (lstat(path, &statbuf) != 0)
1640 continue;
1641
1642 if (!(statbuf.st_mode & S_IRUSR))
1643 continue;
1644
1645 r = set_put_strdup(device->sysattrs, dent->d_name);
1646 if (r < 0)
1647 return r;
1648 }
1649
1650 device->sysattrs_read = true;
1651
1652 return 0;
1653 }
1654
1655 _public_ const char *sd_device_get_sysattr_first(sd_device *device) {
1656 void *v;
1657 int r;
1658
1659 assert_return(device, NULL);
1660
1661 if (!device->sysattrs_read) {
1662 r = device_sysattrs_read_all(device);
1663 if (r < 0) {
1664 errno = -r;
1665 return NULL;
1666 }
1667 }
1668
1669 device->sysattrs_iterator = ITERATOR_FIRST;
1670
1671 (void) set_iterate(device->sysattrs, &device->sysattrs_iterator, &v);
1672 return v;
1673 }
1674
1675 _public_ const char *sd_device_get_sysattr_next(sd_device *device) {
1676 void *v;
1677
1678 assert_return(device, NULL);
1679
1680 if (!device->sysattrs_read)
1681 return NULL;
1682
1683 (void) set_iterate(device->sysattrs, &device->sysattrs_iterator, &v);
1684 return v;
1685 }
1686
1687 _public_ int sd_device_has_tag(sd_device *device, const char *tag) {
1688 assert_return(device, -EINVAL);
1689 assert_return(tag, -EINVAL);
1690
1691 (void) device_read_db(device);
1692
1693 return !!set_contains(device->tags, tag);
1694 }
1695
1696 _public_ int sd_device_get_property_value(sd_device *device, const char *key, const char **_value) {
1697 char *value;
1698 int r;
1699
1700 assert_return(device, -EINVAL);
1701 assert_return(key, -EINVAL);
1702 assert_return(_value, -EINVAL);
1703
1704 r = device_properties_prepare(device);
1705 if (r < 0)
1706 return r;
1707
1708 value = ordered_hashmap_get(device->properties, key);
1709 if (!value)
1710 return -ENOENT;
1711
1712 *_value = value;
1713
1714 return 0;
1715 }
1716
1717 /* replaces the value if it already exists */
1718 static int device_add_sysattr_value(sd_device *device, const char *_key, char *value) {
1719 _cleanup_free_ char *key = NULL;
1720 _cleanup_free_ char *value_old = NULL;
1721 int r;
1722
1723 assert(device);
1724 assert(_key);
1725
1726 r = hashmap_ensure_allocated(&device->sysattr_values, &string_hash_ops);
1727 if (r < 0)
1728 return r;
1729
1730 value_old = hashmap_remove2(device->sysattr_values, _key, (void **)&key);
1731 if (!key) {
1732 key = strdup(_key);
1733 if (!key)
1734 return -ENOMEM;
1735 }
1736
1737 r = hashmap_put(device->sysattr_values, key, value);
1738 if (r < 0)
1739 return r;
1740
1741 key = NULL;
1742
1743 return 0;
1744 }
1745
1746 static int device_get_sysattr_value(sd_device *device, const char *_key, const char **_value) {
1747 const char *key = NULL, *value;
1748
1749 assert(device);
1750 assert(_key);
1751
1752 value = hashmap_get2(device->sysattr_values, _key, (void **) &key);
1753 if (!key)
1754 return -ENOENT;
1755
1756 if (_value)
1757 *_value = value;
1758
1759 return 0;
1760 }
1761
1762 /* We cache all sysattr lookups. If an attribute does not exist, it is stored
1763 * with a NULL value in the cache, otherwise the returned string is stored */
1764 _public_ int sd_device_get_sysattr_value(sd_device *device, const char *sysattr, const char **_value) {
1765 _cleanup_free_ char *value = NULL;
1766 const char *syspath, *cached_value = NULL;
1767 char *path;
1768 struct stat statbuf;
1769 int r;
1770
1771 assert_return(device, -EINVAL);
1772 assert_return(sysattr, -EINVAL);
1773
1774 /* look for possibly already cached result */
1775 r = device_get_sysattr_value(device, sysattr, &cached_value);
1776 if (r != -ENOENT) {
1777 if (r < 0)
1778 return r;
1779
1780 if (!cached_value)
1781 /* we looked up the sysattr before and it did not exist */
1782 return -ENOENT;
1783
1784 if (_value)
1785 *_value = cached_value;
1786
1787 return 0;
1788 }
1789
1790 r = sd_device_get_syspath(device, &syspath);
1791 if (r < 0)
1792 return r;
1793
1794 path = strjoina(syspath, "/", sysattr);
1795 r = lstat(path, &statbuf);
1796 if (r < 0) {
1797 /* remember that we could not access the sysattr */
1798 r = device_add_sysattr_value(device, sysattr, NULL);
1799 if (r < 0)
1800 return r;
1801
1802 return -ENOENT;
1803 } else if (S_ISLNK(statbuf.st_mode)) {
1804 /* Some core links return only the last element of the target path,
1805 * these are just values, the paths should not be exposed. */
1806 if (STR_IN_SET(sysattr, "driver", "subsystem", "module")) {
1807 r = readlink_value(path, &value);
1808 if (r < 0)
1809 return r;
1810 } else
1811 return -EINVAL;
1812 } else if (S_ISDIR(statbuf.st_mode)) {
1813 /* skip directories */
1814 return -EINVAL;
1815 } else if (!(statbuf.st_mode & S_IRUSR)) {
1816 /* skip non-readable files */
1817 return -EPERM;
1818 } else {
1819 size_t size;
1820
1821 /* read attribute value */
1822 r = read_full_file(path, &value, &size);
1823 if (r < 0)
1824 return r;
1825
1826 /* drop trailing newlines */
1827 while (size > 0 && value[--size] == '\n')
1828 value[size] = '\0';
1829 }
1830
1831 r = device_add_sysattr_value(device, sysattr, value);
1832 if (r < 0)
1833 return r;
1834
1835 *_value = value;
1836 value = NULL;
1837
1838 return 0;
1839 }
1840
1841 static void device_remove_sysattr_value(sd_device *device, const char *_key) {
1842 _cleanup_free_ char *key = NULL;
1843 _cleanup_free_ char *value = NULL;
1844
1845 assert(device);
1846 assert(_key);
1847
1848 value = hashmap_remove2(device->sysattr_values, _key, (void **) &key);
1849
1850 return;
1851 }
1852
1853 /* set the attribute and save it in the cache. If a NULL value is passed the
1854 * attribute is cleared from the cache */
1855 _public_ int sd_device_set_sysattr_value(sd_device *device, const char *sysattr, char *_value) {
1856 _cleanup_close_ int fd = -1;
1857 _cleanup_free_ char *value = NULL;
1858 const char *syspath;
1859 char *path;
1860 struct stat statbuf;
1861 size_t value_len = 0;
1862 ssize_t size;
1863 int r;
1864
1865 assert_return(device, -EINVAL);
1866 assert_return(sysattr, -EINVAL);
1867
1868 if (!_value) {
1869 device_remove_sysattr_value(device, sysattr);
1870
1871 return 0;
1872 }
1873
1874 r = sd_device_get_syspath(device, &syspath);
1875 if (r < 0)
1876 return r;
1877
1878 path = strjoina(syspath, "/", sysattr);
1879 r = lstat(path, &statbuf);
1880 if (r < 0) {
1881 value = strdup("");
1882 if (!value)
1883 return -ENOMEM;
1884
1885 r = device_add_sysattr_value(device, sysattr, value);
1886 if (r < 0)
1887 return r;
1888
1889 return -ENXIO;
1890 }
1891
1892 if (S_ISLNK(statbuf.st_mode))
1893 return -EINVAL;
1894
1895 /* skip directories */
1896 if (S_ISDIR(statbuf.st_mode))
1897 return -EISDIR;
1898
1899 /* skip non-readable files */
1900 if ((statbuf.st_mode & S_IRUSR) == 0)
1901 return -EACCES;
1902
1903 value_len = strlen(_value);
1904
1905 /* drop trailing newlines */
1906 while (value_len > 0 && _value[value_len - 1] == '\n')
1907 _value[--value_len] = '\0';
1908
1909 /* value length is limited to 4k */
1910 if (value_len > 4096)
1911 return -EINVAL;
1912
1913 fd = open(path, O_WRONLY | O_CLOEXEC);
1914 if (fd < 0)
1915 return -errno;
1916
1917 value = strdup(_value);
1918 if (!value)
1919 return -ENOMEM;
1920
1921 size = write(fd, value, value_len);
1922 if (size < 0)
1923 return -errno;
1924
1925 if ((size_t)size != value_len)
1926 return -EIO;
1927
1928 r = device_add_sysattr_value(device, sysattr, value);
1929 if (r < 0)
1930 return r;
1931
1932 value = NULL;
1933
1934 return 0;
1935 }