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