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