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