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