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