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