]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd/sd-device/sd-device.c
Merge pull request #24412 from keszybz/man-similarly
[thirdparty/systemd.git] / src / libsystemd / sd-device / sd-device.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
57fa1d09
TG
2
3#include <ctype.h>
57fa1d09 4#include <net/if.h>
ef118d00 5#include <sys/ioctl.h>
07630cea 6#include <sys/types.h>
57fa1d09 7
07630cea
LP
8#include "sd-device.h"
9
b5efdb8a 10#include "alloc-util.h"
f4351959 11#include "chase-symlinks.h"
07630cea
LP
12#include "device-internal.h"
13#include "device-private.h"
14#include "device-util.h"
7176f06c 15#include "devnum-util.h"
8fb3f009 16#include "dirent-util.h"
a7910612 17#include "env-util.h"
3ffd4af2 18#include "fd-util.h"
57fa1d09 19#include "fileio.h"
bd44a727 20#include "format-util.h"
f4f15635 21#include "fs-util.h"
57fa1d09 22#include "hashmap.h"
b485fd93 23#include "id128-util.h"
07630cea 24#include "macro.h"
a7910612 25#include "missing_magic.h"
bd44a727 26#include "netlink-util.h"
6bedfcbb 27#include "parse-util.h"
07630cea 28#include "path-util.h"
57fa1d09 29#include "set.h"
429b4350 30#include "socket-util.h"
dc5042c0 31#include "stdio-util.h"
07630cea 32#include "string-util.h"
57fa1d09 33#include "strv.h"
07630cea 34#include "strxcpyx.h"
f5fbe71d 35#include "user-util.h"
07630cea 36#include "util.h"
57fa1d09
TG
37
38int device_new_aux(sd_device **ret) {
2cfb1978 39 sd_device *device;
57fa1d09
TG
40
41 assert(ret);
42
6116d2b2 43 device = new(sd_device, 1);
57fa1d09
TG
44 if (!device)
45 return -ENOMEM;
46
6116d2b2
YW
47 *device = (sd_device) {
48 .n_ref = 1,
49 .watch_handle = -1,
f5fbe71d
YW
50 .devmode = MODE_INVALID,
51 .devuid = UID_INVALID,
52 .devgid = GID_INVALID,
a1130022 53 .action = _SD_DEVICE_ACTION_INVALID,
6116d2b2 54 };
57fa1d09
TG
55
56 *ret = device;
57fa1d09
TG
57 return 0;
58}
59
8301aa0b
YW
60static sd_device *device_free(sd_device *device) {
61 assert(device);
57fa1d09 62
8301aa0b
YW
63 sd_device_unref(device->parent);
64 free(device->syspath);
65 free(device->sysname);
66 free(device->devtype);
67 free(device->devname);
68 free(device->subsystem);
69 free(device->driver_subsystem);
70 free(device->driver);
fe732381 71 free(device->device_id);
8301aa0b
YW
72 free(device->properties_strv);
73 free(device->properties_nulstr);
74
dd75bbee
YW
75 ordered_hashmap_free(device->properties);
76 ordered_hashmap_free(device->properties_db);
61c0972d 77 hashmap_free(device->sysattr_values);
be327321 78 set_free(device->sysattrs);
e77b146f
LP
79 set_free(device->all_tags);
80 set_free(device->current_tags);
be327321 81 set_free(device->devlinks);
8301aa0b
YW
82
83 return mfree(device);
57fa1d09
TG
84}
85
8301aa0b 86DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_device, sd_device, device_free);
57fa1d09 87
4f1ef7f9 88int device_add_property_aux(sd_device *device, const char *key, const char *value, bool db) {
57fa1d09
TG
89 OrderedHashmap **properties;
90
91 assert(device);
4f1ef7f9 92 assert(key);
57fa1d09
TG
93
94 if (db)
95 properties = &device->properties_db;
96 else
97 properties = &device->properties;
98
4f1ef7f9 99 if (value) {
d7ac0952
FS
100 _unused_ _cleanup_free_ char *old_value = NULL;
101 _cleanup_free_ char *new_key = NULL, *new_value = NULL, *old_key = NULL;
57fa1d09
TG
102 int r;
103
dd75bbee 104 r = ordered_hashmap_ensure_allocated(properties, &string_hash_ops_free_free);
57fa1d09
TG
105 if (r < 0)
106 return r;
107
4f1ef7f9
YW
108 new_key = strdup(key);
109 if (!new_key)
57fa1d09
TG
110 return -ENOMEM;
111
4f1ef7f9
YW
112 new_value = strdup(value);
113 if (!new_value)
57fa1d09
TG
114 return -ENOMEM;
115
116 old_value = ordered_hashmap_get2(*properties, key, (void**) &old_key);
117
327379f5 118 /* ordered_hashmap_replace() does not fail when the hashmap already has the entry. */
4f1ef7f9 119 r = ordered_hashmap_replace(*properties, new_key, new_value);
57fa1d09
TG
120 if (r < 0)
121 return r;
122
4f1ef7f9
YW
123 TAKE_PTR(new_key);
124 TAKE_PTR(new_value);
57fa1d09 125 } else {
d7ac0952
FS
126 _unused_ _cleanup_free_ char *old_value = NULL;
127 _cleanup_free_ char *old_key = NULL;
57fa1d09 128
4f1ef7f9 129 old_value = ordered_hashmap_remove2(*properties, key, (void**) &old_key);
57fa1d09
TG
130 }
131
132 if (!db) {
313cefa1 133 device->properties_generation++;
57fa1d09
TG
134 device->properties_buf_outdated = true;
135 }
136
137 return 0;
138}
139
57fa1d09
TG
140int device_set_syspath(sd_device *device, const char *_syspath, bool verify) {
141 _cleanup_free_ char *syspath = NULL;
142 const char *devpath;
143 int r;
144
145 assert(device);
146 assert(_syspath);
147
57fa1d09 148 if (verify) {
1793bb61
LP
149 _cleanup_close_ int fd = -1;
150
95c250be
YW
151 /* The input path maybe a symlink located outside of /sys. Let's try to chase the symlink at first.
152 * The primary usecase is that e.g. /proc/device-tree is a symlink to /sys/firmware/devicetree/base.
153 * By chasing symlinks in the path at first, we can call sd_device_new_from_path() with such path. */
1793bb61 154 r = chase_symlinks(_syspath, NULL, 0, &syspath, &fd);
08232a02 155 if (r == -ENOENT)
d7cb60da
YW
156 /* the device does not exist (any more?) */
157 return log_debug_errno(SYNTHETIC_ERRNO(ENODEV),
158 "sd-device: Failed to chase symlinks in \"%s\".", _syspath);
d89e0dc8 159 if (r < 0)
c7d54dae 160 return log_debug_errno(r, "sd-device: Failed to get target of '%s': %m", _syspath);
57fa1d09 161
2e1ec12e
YW
162 if (!path_startswith(syspath, "/sys")) {
163 _cleanup_free_ char *real_sys = NULL, *new_syspath = NULL;
164 char *p;
165
166 /* /sys is a symlink to somewhere sysfs is mounted on? In that case, we convert the path to real sysfs to "/sys". */
a5648b80 167 r = chase_symlinks("/sys", NULL, 0, &real_sys, NULL);
2e1ec12e 168 if (r < 0)
c7d54dae 169 return log_debug_errno(r, "sd-device: Failed to chase symlink /sys: %m");
2e1ec12e
YW
170
171 p = path_startswith(syspath, real_sys);
baaa35ad
ZJS
172 if (!p)
173 return log_debug_errno(SYNTHETIC_ERRNO(ENODEV),
174 "sd-device: Canonicalized path '%s' does not starts with sysfs mount point '%s'",
175 syspath, real_sys);
2e1ec12e 176
657ee2d8 177 new_syspath = path_join("/sys", p);
2e1ec12e 178 if (!new_syspath)
d7cb60da 179 return log_oom_debug();
2e1ec12e
YW
180
181 free_and_replace(syspath, new_syspath);
4ff361cc 182 path_simplify(syspath);
2e1ec12e
YW
183 }
184
1793bb61
LP
185 if (path_startswith(syspath, "/sys/devices/")) {
186 /* For proper devices, stricter rules apply: they must have a 'uevent' file,
187 * otherwise we won't allow them */
57fa1d09 188
1793bb61 189 if (faccessat(fd, "uevent", F_OK, 0) < 0) {
52d62901 190 if (errno == ENOENT)
1793bb61
LP
191 /* This is not a valid device. Note, this condition is quite often
192 * satisfied when enumerating devices or finding a parent device.
29fafedd
YW
193 * Hence, use log_trace_errno() here. */
194 return log_trace_errno(SYNTHETIC_ERRNO(ENODEV),
1793bb61 195 "sd-device: the uevent file \"%s/uevent\" does not exist.", syspath);
5cf0ee31
LP
196 if (errno == ENOTDIR)
197 /* Not actually a directory. */
198 return log_debug_errno(SYNTHETIC_ERRNO(ENODEV),
199 "sd-device: the syspath \"%s\" is not a directory.", syspath);
52d62901 200
1793bb61 201 return log_debug_errno(errno, "sd-device: cannot find uevent file for %s: %m", syspath);
57fa1d09
TG
202 }
203 } else {
1793bb61
LP
204 struct stat st;
205
206 /* For everything else lax rules apply: they just need to be a directory */
207
208 if (fstat(fd, &st) < 0)
209 return log_debug_errno(errno, "sd-device: failed to check if syspath \"%s\" is a directory: %m", syspath);
210 if (!S_ISDIR(st.st_mode))
d7cb60da
YW
211 return log_debug_errno(SYNTHETIC_ERRNO(ENODEV),
212 "sd-device: the syspath \"%s\" is not a directory.", syspath);
57fa1d09 213 }
a7910612
LP
214
215 /* Only operate on sysfs, i.e. refuse going down into /sys/fs/cgroup/ or similar places where
216 * things are not arranged as kobjects in kernel, and hence don't necessarily have
217 * kobject/attribute structure. */
218 r = getenv_bool_secure("SYSTEMD_DEVICE_VERIFY_SYSFS");
219 if (r < 0 && r != -ENXIO)
220 log_debug_errno(r, "Failed to parse $SYSTEMD_DEVICE_VERIFY_SYSFS value: %m");
221 if (r != 0) {
222 r = fd_is_fs_type(fd, SYSFS_MAGIC);
223 if (r < 0)
224 return log_debug_errno(r, "sd-device: failed to check if syspath \"%s\" is backed by sysfs.", syspath);
225 if (r == 0)
226 return log_debug_errno(SYNTHETIC_ERRNO(ENODEV),
227 "sd-device: the syspath \"%s\" is outside of sysfs, refusing.", syspath);
228 }
57fa1d09 229 } else {
95c250be
YW
230 /* must be a subdirectory of /sys */
231 if (!path_startswith(_syspath, "/sys/"))
232 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
233 "sd-device: Syspath '%s' is not a subdirectory of /sys",
234 _syspath);
235
57fa1d09
TG
236 syspath = strdup(_syspath);
237 if (!syspath)
d7cb60da 238 return log_oom_debug();
57fa1d09 239
4d960d0b
LP
240 path_simplify(syspath);
241 }
57fa1d09 242
4d960d0b 243 assert_se(devpath = startswith(syspath, "/sys"));
9dcde103 244 if (devpath[0] != '/')
d7cb60da 245 return log_debug_errno(SYNTHETIC_ERRNO(ENODEV), "sd-device: \"/sys\" alone is not a valid device path.");
c4f885e7 246
57fa1d09
TG
247 r = device_add_property_internal(device, "DEVPATH", devpath);
248 if (r < 0)
d7cb60da 249 return log_debug_errno(r, "sd-device: Failed to add \"DEVPATH\" property for device \"%s\": %m", syspath);
57fa1d09 250
f9ecfd3b 251 free_and_replace(device->syspath, syspath);
57fa1d09 252 device->devpath = devpath;
57fa1d09
TG
253 return 0;
254}
255
95c250be 256static int device_new_from_syspath(sd_device **ret, const char *syspath, bool strict) {
4afd3348 257 _cleanup_(sd_device_unrefp) sd_device *device = NULL;
57fa1d09
TG
258 int r;
259
260 assert_return(ret, -EINVAL);
261 assert_return(syspath, -EINVAL);
262
95c250be
YW
263 if (strict && !path_startswith(syspath, "/sys/"))
264 return -EINVAL;
265
57fa1d09
TG
266 r = device_new_aux(&device);
267 if (r < 0)
268 return r;
269
be247835 270 r = device_set_syspath(device, syspath, /* verify= */ true);
57fa1d09
TG
271 if (r < 0)
272 return r;
273
1cc6c93a 274 *ret = TAKE_PTR(device);
57fa1d09
TG
275 return 0;
276}
277
95c250be
YW
278_public_ int sd_device_new_from_syspath(sd_device **ret, const char *syspath) {
279 return device_new_from_syspath(ret, syspath, /* strict = */ true);
280}
281
a46f9cd0
YW
282static int device_new_from_mode_and_devnum(sd_device **ret, mode_t mode, dev_t devnum) {
283 _cleanup_(sd_device_unrefp) sd_device *dev = NULL;
284 _cleanup_free_ char *syspath = NULL;
285 const char *t, *subsystem;
286 dev_t n;
287 int r;
57fa1d09 288
a46f9cd0
YW
289 assert(ret);
290
291 if (S_ISCHR(mode))
292 t = "char";
293 else if (S_ISBLK(mode))
294 t = "block";
295 else
296 return -ENOTTY;
297
298 if (major(devnum) == 0)
299 return -ENODEV;
300
301 if (asprintf(&syspath, "/sys/dev/%s/%u:%u", t, major(devnum), minor(devnum)) < 0)
302 return -ENOMEM;
57fa1d09 303
a46f9cd0
YW
304 r = sd_device_new_from_syspath(&dev, syspath);
305 if (r < 0)
306 return r;
f1ad2c92 307
a46f9cd0
YW
308 r = sd_device_get_devnum(dev, &n);
309 if (r == -ENOENT)
310 return -ENXIO;
311 if (r < 0)
312 return r;
313 if (n != devnum)
314 return -ENXIO;
57fa1d09 315
a46f9cd0
YW
316 r = sd_device_get_subsystem(dev, &subsystem);
317 if (r < 0 && r != -ENOENT)
318 return r;
319 if (r >= 0 && streq(subsystem, "block") != !!S_ISBLK(mode))
320 return -ENXIO;
57fa1d09 321
a46f9cd0
YW
322 *ret = TAKE_PTR(dev);
323 return 0;
324}
325
326_public_ int sd_device_new_from_devnum(sd_device **ret, char type, dev_t devnum) {
327 assert_return(ret, -EINVAL);
328 assert_return(IN_SET(type, 'b', 'c'), -EINVAL);
329
330 return device_new_from_mode_and_devnum(ret, type == 'b' ? S_IFBLK : S_IFCHR, devnum);
57fa1d09
TG
331}
332
bd44a727
YW
333static int device_new_from_main_ifname(sd_device **ret, const char *ifname) {
334 const char *syspath;
335
336 assert(ret);
337 assert(ifname);
338
339 syspath = strjoina("/sys/class/net/", ifname);
340 return sd_device_new_from_syspath(ret, syspath);
341}
342
343_public_ int sd_device_new_from_ifname(sd_device **ret, const char *ifname) {
344 _cleanup_free_ char *main_name = NULL;
345 int r;
346
347 assert_return(ret, -EINVAL);
348 assert_return(ifname, -EINVAL);
349
350 r = parse_ifindex(ifname);
351 if (r > 0)
352 return sd_device_new_from_ifindex(ret, r);
353
354 if (ifname_valid(ifname)) {
355 r = device_new_from_main_ifname(ret, ifname);
356 if (r >= 0)
357 return r;
358 }
359
360 r = rtnl_resolve_link_alternative_name(NULL, ifname, &main_name);
361 if (r < 0)
362 return r;
363
364 return device_new_from_main_ifname(ret, main_name);
365}
366
367_public_ int sd_device_new_from_ifindex(sd_device **ret, int ifindex) {
a46f9cd0 368 _cleanup_(sd_device_unrefp) sd_device *dev = NULL;
01afd0f7 369 char ifname[IF_NAMESIZE];
a46f9cd0 370 int r, i;
bd44a727
YW
371
372 assert_return(ret, -EINVAL);
373 assert_return(ifindex > 0, -EINVAL);
374
01afd0f7 375 if (format_ifname(ifindex, ifname) < 0)
bd44a727
YW
376 return -ENODEV;
377
a46f9cd0
YW
378 r = device_new_from_main_ifname(&dev, ifname);
379 if (r < 0)
380 return r;
381
382 r = sd_device_get_ifindex(dev, &i);
383 if (r == -ENOENT)
384 return -ENXIO;
385 if (r < 0)
386 return r;
387 if (i != ifindex)
388 return -ENXIO;
389
390 *ret = TAKE_PTR(dev);
391 return 0;
bd44a727
YW
392}
393
f5e77597
LP
394static int device_strjoin_new(
395 const char *a,
396 const char *b,
397 const char *c,
398 const char *d,
399 sd_device **ret) {
400
401 const char *p;
402 int r;
403
404 p = strjoina(a, b, c, d);
405 if (access(p, F_OK) < 0)
406 return IN_SET(errno, ENOENT, ENAMETOOLONG) ? 0 : -errno; /* If this sysfs is too long then it doesn't exist either */
407
408 r = sd_device_new_from_syspath(ret, p);
409 if (r < 0)
410 return r;
411
412 return 1;
413}
414
415_public_ int sd_device_new_from_subsystem_sysname(
416 sd_device **ret,
417 const char *subsystem,
418 const char *sysname) {
419
f5e77597
LP
420 char *name;
421 int r;
57fa1d09
TG
422
423 assert_return(ret, -EINVAL);
f5e77597
LP
424 assert_return(path_is_normalized(subsystem), -EINVAL);
425 assert_return(path_is_normalized(sysname), -EINVAL);
57fa1d09 426
4d38294b
YW
427 /* translate sysname back to sysfs filename */
428 name = strdupa_safe(sysname);
429 string_replace_char(name, '/', '!');
430
57fa1d09 431 if (streq(subsystem, "subsystem")) {
a43129b0 432 FOREACH_STRING(s, "/sys/bus/", "/sys/class/") {
4d38294b 433 r = device_strjoin_new(s, name, NULL, NULL, ret);
f5e77597
LP
434 if (r < 0)
435 return r;
436 if (r > 0)
437 return 0;
438 }
e17c95af 439
4d38294b
YW
440 } else if (streq(subsystem, "module")) {
441 r = device_strjoin_new("/sys/module/", name, NULL, NULL, ret);
f5e77597
LP
442 if (r < 0)
443 return r;
444 if (r > 0)
445 return 0;
e17c95af 446
57fa1d09 447 } else if (streq(subsystem, "drivers")) {
f5e77597 448 const char *sep;
57fa1d09 449
4d38294b 450 sep = strchr(name, ':');
52a89a5f 451 if (sep && sep[1] != '\0') { /* Require ":" and something non-empty after that. */
57fa1d09 452
4d38294b 453 const char *subsys = memdupa_suffix0(name, sep - name);
f5e77597
LP
454 sep++;
455
0b859c97
LP
456 if (streq(sep, "drivers")) /* If the sysname is "drivers", then it's the drivers directory itself that is meant. */
457 r = device_strjoin_new("/sys/bus/", subsys, "/drivers", NULL, ret);
458 else
459 r = device_strjoin_new("/sys/bus/", subsys, "/drivers/", sep, ret);
a43129b0
YW
460 if (r < 0)
461 return r;
462 if (r > 0)
463 return 0;
21d6220f
TG
464 }
465 }
a9ec9f29 466
a43129b0
YW
467 r = device_strjoin_new("/sys/bus/", subsystem, "/devices/", name, ret);
468 if (r < 0)
469 return r;
470 if (r > 0)
471 return 0;
57fa1d09 472
f5e77597
LP
473 r = device_strjoin_new("/sys/class/", subsystem, "/", name, ret);
474 if (r < 0)
475 return r;
476 if (r > 0)
477 return 0;
57fa1d09 478
4d38294b 479 r = device_strjoin_new("/sys/firmware/", subsystem, "/", name, ret);
f5e77597
LP
480 if (r < 0)
481 return r;
482 if (r > 0)
483 return 0;
a918b673 484
08232a02 485 return -ENODEV;
57fa1d09
TG
486}
487
a1130022 488_public_ int sd_device_new_from_stat_rdev(sd_device **ret, const struct stat *st) {
a1130022
LP
489 assert_return(ret, -EINVAL);
490 assert_return(st, -EINVAL);
491
a46f9cd0 492 return device_new_from_mode_and_devnum(ret, st->st_mode, st->st_rdev);
a1130022
LP
493}
494
e418f965
YW
495_public_ int sd_device_new_from_devname(sd_device **ret, const char *devname) {
496 struct stat st;
a46f9cd0
YW
497 dev_t devnum;
498 mode_t mode;
e418f965
YW
499
500 assert_return(ret, -EINVAL);
501 assert_return(devname, -EINVAL);
502
503 /* This function actually accepts both devlinks and devnames, i.e. both symlinks and device
504 * nodes below /dev/. */
505
506 /* Also ignore when the specified path is "/dev". */
507 if (isempty(path_startswith(devname, "/dev")))
508 return -EINVAL;
509
a46f9cd0 510 if (device_path_parse_major_minor(devname, &mode, &devnum) >= 0)
e418f965 511 /* Let's shortcut when "/dev/block/maj:min" or "/dev/char/maj:min" is specified.
a46f9cd0 512 * In that case, we can directly convert the path to syspath, hence it is not necessary
e418f965 513 * that the specified path exists. So, this works fine without udevd being running. */
a46f9cd0 514 return device_new_from_mode_and_devnum(ret, mode, devnum);
e418f965
YW
515
516 if (stat(devname, &st) < 0)
517 return ERRNO_IS_DEVICE_ABSENT(errno) ? -ENODEV : -errno;
518
519 return sd_device_new_from_stat_rdev(ret, &st);
520}
521
522_public_ int sd_device_new_from_path(sd_device **ret, const char *path) {
523 assert_return(ret, -EINVAL);
524 assert_return(path, -EINVAL);
525
526 if (path_startswith(path, "/dev"))
527 return sd_device_new_from_devname(ret, path);
528
95c250be 529 return device_new_from_syspath(ret, path, /* strict = */ false);
e418f965
YW
530}
531
fe20121a
ZJS
532int device_set_devtype(sd_device *device, const char *devtype) {
533 _cleanup_free_ char *t = NULL;
57fa1d09
TG
534 int r;
535
536 assert(device);
fe20121a 537 assert(devtype);
57fa1d09 538
fe20121a
ZJS
539 t = strdup(devtype);
540 if (!t)
57fa1d09
TG
541 return -ENOMEM;
542
fe20121a 543 r = device_add_property_internal(device, "DEVTYPE", t);
57fa1d09
TG
544 if (r < 0)
545 return r;
546
fe20121a 547 return free_and_replace(device->devtype, t);
57fa1d09
TG
548}
549
597da51b
ZJS
550int device_set_ifindex(sd_device *device, const char *name) {
551 int r, ifindex;
57fa1d09
TG
552
553 assert(device);
597da51b 554 assert(name);
57fa1d09 555
597da51b
ZJS
556 ifindex = parse_ifindex(name);
557 if (ifindex < 0)
558 return ifindex;
57fa1d09 559
597da51b 560 r = device_add_property_internal(device, "IFINDEX", name);
57fa1d09
TG
561 if (r < 0)
562 return r;
563
564 device->ifindex = ifindex;
565
566 return 0;
567}
568
fe20121a
ZJS
569int device_set_devname(sd_device *device, const char *devname) {
570 _cleanup_free_ char *t = NULL;
57fa1d09
TG
571 int r;
572
573 assert(device);
fe20121a 574 assert(devname);
57fa1d09 575
fe20121a
ZJS
576 if (devname[0] != '/')
577 t = strjoin("/dev/", devname);
578 else
579 t = strdup(devname);
580 if (!t)
581 return -ENOMEM;
57fa1d09 582
fe20121a 583 r = device_add_property_internal(device, "DEVNAME", t);
57fa1d09
TG
584 if (r < 0)
585 return r;
586
fe20121a 587 return free_and_replace(device->devname, t);
57fa1d09
TG
588}
589
590int device_set_devmode(sd_device *device, const char *_devmode) {
591 unsigned devmode;
592 int r;
593
594 assert(device);
595 assert(_devmode);
596
597 r = safe_atou(_devmode, &devmode);
598 if (r < 0)
599 return r;
600
601 if (devmode > 07777)
602 return -EINVAL;
603
604 r = device_add_property_internal(device, "DEVMODE", _devmode);
605 if (r < 0)
606 return r;
607
608 device->devmode = devmode;
609
610 return 0;
611}
612
613int device_set_devnum(sd_device *device, const char *major, const char *minor) {
49f23693 614 unsigned maj, min = 0;
57fa1d09
TG
615 int r;
616
617 assert(device);
618 assert(major);
619
620 r = safe_atou(major, &maj);
621 if (r < 0)
622 return r;
49f23693 623 if (maj == 0)
57fa1d09 624 return 0;
9d41c62f
LP
625 if (!DEVICE_MAJOR_VALID(maj))
626 return -EINVAL;
57fa1d09
TG
627
628 if (minor) {
629 r = safe_atou(minor, &min);
630 if (r < 0)
631 return r;
9d41c62f
LP
632 if (!DEVICE_MINOR_VALID(min))
633 return -EINVAL;
57fa1d09
TG
634 }
635
636 r = device_add_property_internal(device, "MAJOR", major);
637 if (r < 0)
638 return r;
639
640 if (minor) {
641 r = device_add_property_internal(device, "MINOR", minor);
642 if (r < 0)
643 return r;
644 }
645
646 device->devnum = makedev(maj, min);
647
648 return 0;
649}
650
1ce0d040
LP
651int device_set_diskseq(sd_device *device, const char *str) {
652 uint64_t diskseq;
653 int r;
654
655 assert(device);
656 assert(str);
657
658 r = safe_atou64(str, &diskseq);
659 if (r < 0)
660 return r;
661 if (diskseq == 0)
662 return -EINVAL;
663
664 r = device_add_property_internal(device, "DISKSEQ", str);
665 if (r < 0)
666 return r;
667
668 device->diskseq = diskseq;
669
670 return 0;
671}
672
673static int handle_uevent_line(
674 sd_device *device,
675 const char *key,
676 const char *value,
677 const char **major,
678 const char **minor) {
57fa1d09
TG
679
680 assert(device);
681 assert(key);
682 assert(value);
683 assert(major);
684 assert(minor);
685
08405125
YW
686 if (streq(key, "DEVTYPE"))
687 return device_set_devtype(device, value);
688 if (streq(key, "IFINDEX"))
689 return device_set_ifindex(device, value);
690 if (streq(key, "DEVNAME"))
691 return device_set_devname(device, value);
692 if (streq(key, "DEVMODE"))
693 return device_set_devmode(device, value);
694 if (streq(key, "DISKSEQ"))
695 return device_set_diskseq(device, value);
696 if (streq(key, "MAJOR"))
57fa1d09
TG
697 *major = value;
698 else if (streq(key, "MINOR"))
699 *minor = value;
08405125
YW
700 else
701 return device_add_property_internal(device, key, value);
57fa1d09
TG
702
703 return 0;
704}
705
706int device_read_uevent_file(sd_device *device) {
707 _cleanup_free_ char *uevent = NULL;
97c94b98 708 const char *syspath, *key = NULL, *value = NULL, *major = NULL, *minor = NULL;
57fa1d09
TG
709 char *path;
710 size_t uevent_len;
57fa1d09
TG
711 int r;
712
713 enum {
714 PRE_KEY,
715 KEY,
716 PRE_VALUE,
717 VALUE,
718 INVALID_LINE,
719 } state = PRE_KEY;
720
721 assert(device);
722
723 if (device->uevent_loaded || device->sealed)
724 return 0;
725
726 r = sd_device_get_syspath(device, &syspath);
727 if (r < 0)
728 return r;
729
c7d6ebb1
YW
730 device->uevent_loaded = true;
731
57fa1d09
TG
732 path = strjoina(syspath, "/uevent");
733
627055ce 734 r = read_full_virtual_file(path, &uevent, &uevent_len);
17761fb3
YW
735 if (r < 0) {
736 /* The uevent files may be write-only, the device may be already removed, or the device
737 * may not have the uevent file. */
738 if (r == -EACCES || ERRNO_IS_DEVICE_ABSENT(r))
739 return 0;
740
c7d54dae 741 return log_device_debug_errno(device, r, "sd-device: Failed to read uevent file '%s': %m", path);
17761fb3 742 }
57fa1d09 743
462035d5 744 for (size_t i = 0; i < uevent_len; i++)
57fa1d09
TG
745 switch (state) {
746 case PRE_KEY:
747 if (!strchr(NEWLINE, uevent[i])) {
748 key = &uevent[i];
749
750 state = KEY;
751 }
752
753 break;
754 case KEY:
755 if (uevent[i] == '=') {
756 uevent[i] = '\0';
757
758 state = PRE_VALUE;
759 } else if (strchr(NEWLINE, uevent[i])) {
760 uevent[i] = '\0';
c7d54dae 761 log_device_debug(device, "sd-device: Invalid uevent line '%s', ignoring", key);
57fa1d09
TG
762
763 state = PRE_KEY;
764 }
765
766 break;
767 case PRE_VALUE:
768 value = &uevent[i];
57fa1d09
TG
769 state = VALUE;
770
4831981d 771 _fallthrough_; /* to handle empty property */
57fa1d09
TG
772 case VALUE:
773 if (strchr(NEWLINE, uevent[i])) {
774 uevent[i] = '\0';
775
776 r = handle_uevent_line(device, key, value, &major, &minor);
777 if (r < 0)
c7d54dae 778 log_device_debug_errno(device, r, "sd-device: Failed to handle uevent entry '%s=%s', ignoring: %m", key, value);
57fa1d09
TG
779
780 state = PRE_KEY;
781 }
782
783 break;
784 default:
04499a70 785 assert_not_reached();
57fa1d09 786 }
57fa1d09
TG
787
788 if (major) {
789 r = device_set_devnum(device, major, minor);
790 if (r < 0)
9a81972b 791 log_device_debug_errno(device, r, "sd-device: Failed to set 'MAJOR=%s' or 'MINOR=%s' from '%s', ignoring: %m", major, strna(minor), path);
57fa1d09
TG
792 }
793
57fa1d09
TG
794 return 0;
795}
796
797_public_ int sd_device_get_ifindex(sd_device *device, int *ifindex) {
798 int r;
799
800 assert_return(device, -EINVAL);
57fa1d09
TG
801
802 r = device_read_uevent_file(device);
803 if (r < 0)
804 return r;
805
1dfa9607 806 if (device->ifindex <= 0)
dcfbde3a
YW
807 return -ENOENT;
808
78ffb476
YW
809 if (ifindex)
810 *ifindex = device->ifindex;
57fa1d09
TG
811
812 return 0;
813}
814
815_public_ int sd_device_new_from_device_id(sd_device **ret, const char *id) {
816 int r;
817
818 assert_return(ret, -EINVAL);
819 assert_return(id, -EINVAL);
820
821 switch (id[0]) {
822 case 'b':
3a47c40d
LP
823 case 'c': {
824 dev_t devt;
57fa1d09 825
3a47c40d 826 if (isempty(id))
57fa1d09
TG
827 return -EINVAL;
828
7176f06c 829 r = parse_devnum(id + 1, &devt);
3a47c40d
LP
830 if (r < 0)
831 return r;
832
833 return sd_device_new_from_devnum(ret, id[0], devt);
57fa1d09 834 }
2cfb1978
ZJS
835
836 case 'n': {
57fa1d09
TG
837 int ifindex;
838
bd44a727
YW
839 ifindex = parse_ifindex(id + 1);
840 if (ifindex < 0)
841 return ifindex;
57fa1d09 842
bd44a727 843 return sd_device_new_from_ifindex(ret, ifindex);
57fa1d09 844 }
2cfb1978
ZJS
845
846 case '+': {
3e2d0c6a 847 const char *subsys, *sep;
57fa1d09 848
3e2d0c6a
ZJS
849 sep = strchr(id + 1, ':');
850 if (!sep || sep - id - 1 > NAME_MAX)
57fa1d09
TG
851 return -EINVAL;
852
3e2d0c6a 853 subsys = memdupa_suffix0(id + 1, sep - id - 1);
57fa1d09 854
3e2d0c6a 855 return sd_device_new_from_subsystem_sysname(ret, subsys, sep + 1);
57fa1d09 856 }
2cfb1978 857
57fa1d09
TG
858 default:
859 return -EINVAL;
860 }
861}
862
863_public_ int sd_device_get_syspath(sd_device *device, const char **ret) {
864 assert_return(device, -EINVAL);
57fa1d09
TG
865
866 assert(path_startswith(device->syspath, "/sys/"));
867
45e093a9
YW
868 if (ret)
869 *ret = device->syspath;
57fa1d09
TG
870
871 return 0;
872}
873
68a52f59
YW
874_public_ int sd_device_new_child(sd_device **ret, sd_device *device, const char *suffix) {
875 _cleanup_free_ char *path = NULL;
876 const char *s;
877 int r;
878
879 assert_return(ret, -EINVAL);
880 assert_return(device, -EINVAL);
881 assert_return(suffix, -EINVAL);
882
883 if (!path_is_normalized(suffix))
884 return -EINVAL;
885
886 r = sd_device_get_syspath(device, &s);
887 if (r < 0)
888 return r;
889
890 path = path_join(s, suffix);
891 if (!path)
892 return -ENOMEM;
893
894 return sd_device_new_from_syspath(ret, path);
895}
896
57fa1d09
TG
897static int device_new_from_child(sd_device **ret, sd_device *child) {
898 _cleanup_free_ char *path = NULL;
07c90f02 899 const char *syspath;
57fa1d09
TG
900 int r;
901
902 assert(ret);
903 assert(child);
904
905 r = sd_device_get_syspath(child, &syspath);
906 if (r < 0)
907 return r;
908
57fa1d09 909 for (;;) {
07c90f02 910 _cleanup_free_ char *p = NULL;
57fa1d09 911
07c90f02
YW
912 r = path_extract_directory(path ?: syspath, &p);
913 if (r < 0)
914 return r;
57fa1d09 915
07c90f02
YW
916 if (path_equal(p, "/sys"))
917 return -ENODEV;
57fa1d09 918
07c90f02
YW
919 r = sd_device_new_from_syspath(ret, p);
920 if (r != -ENODEV)
921 return r;
57fa1d09 922
07c90f02 923 free_and_replace(path, p);
57fa1d09 924 }
57fa1d09
TG
925}
926
927_public_ int sd_device_get_parent(sd_device *child, sd_device **ret) {
df88f02b
YW
928 int r;
929
57fa1d09
TG
930 assert_return(child, -EINVAL);
931
932 if (!child->parent_set) {
df88f02b
YW
933 r = device_new_from_child(&child->parent, child);
934 if (r < 0 && r != -ENODEV)
935 return r;
57fa1d09 936
df88f02b 937 child->parent_set = true;
57fa1d09
TG
938 }
939
940 if (!child->parent)
941 return -ENOENT;
942
45e093a9
YW
943 if (ret)
944 *ret = child->parent;
57fa1d09
TG
945 return 0;
946}
947
df49a732
ZJS
948int device_set_subsystem(sd_device *device, const char *subsystem) {
949 _cleanup_free_ char *s = NULL;
57fa1d09
TG
950 int r;
951
952 assert(device);
57fa1d09 953
df49a732
ZJS
954 if (subsystem) {
955 s = strdup(subsystem);
956 if (!s)
957 return -ENOMEM;
958 }
57fa1d09 959
df49a732 960 r = device_add_property_internal(device, "SUBSYSTEM", s);
57fa1d09
TG
961 if (r < 0)
962 return r;
963
57fa1d09 964 device->subsystem_set = true;
df49a732 965 return free_and_replace(device->subsystem, s);
57fa1d09
TG
966}
967
e5ca293f 968int device_set_drivers_subsystem(sd_device *device) {
de7e983e 969 _cleanup_free_ char *subsystem = NULL;
13659527 970 const char *devpath, *drivers, *p;
de7e983e
TG
971 int r;
972
973 assert(device);
de7e983e 974
13659527 975 r = sd_device_get_devpath(device, &devpath);
4956f220
YW
976 if (r < 0)
977 return r;
978
13659527 979 drivers = strstr(devpath, "/drivers/");
0b859c97
LP
980 if (!drivers)
981 drivers = endswith(devpath, "/drivers");
4956f220
YW
982 if (!drivers)
983 return -EINVAL;
984
be247835
LP
985 /* Find the path component immediately before the "/drivers/" string */
986 r = path_find_last_component(devpath, /* accept_dot_dot= */ false, &drivers, &p);
13659527
YW
987 if (r < 0)
988 return r;
989 if (r == 0)
4956f220
YW
990 return -EINVAL;
991
13659527 992 subsystem = strndup(p, r);
de7e983e
TG
993 if (!subsystem)
994 return -ENOMEM;
995
996 r = device_set_subsystem(device, "drivers");
997 if (r < 0)
998 return r;
999
2cfb1978 1000 return free_and_replace(device->driver_subsystem, subsystem);
de7e983e
TG
1001}
1002
57fa1d09 1003_public_ int sd_device_get_subsystem(sd_device *device, const char **ret) {
de7e983e
TG
1004 int r;
1005
57fa1d09
TG
1006 assert_return(device, -EINVAL);
1007
1008 if (!device->subsystem_set) {
1009 _cleanup_free_ char *subsystem = NULL;
4956f220 1010 const char *syspath;
57fa1d09 1011 char *path;
57fa1d09 1012
4956f220
YW
1013 r = sd_device_get_syspath(device, &syspath);
1014 if (r < 0)
1015 return r;
1016
57fa1d09 1017 /* read 'subsystem' link */
57fa1d09
TG
1018 path = strjoina(syspath, "/subsystem");
1019 r = readlink_value(path, &subsystem);
4956f220
YW
1020 if (r < 0 && r != -ENOENT)
1021 return log_device_debug_errno(device, r,
1022 "sd-device: Failed to read subsystem for %s: %m",
1023 device->devpath);
1024
1025 if (subsystem)
57fa1d09
TG
1026 r = device_set_subsystem(device, subsystem);
1027 /* use implicit names */
0b859c97 1028 else if (!isempty(path_startswith(device->devpath, "/module/")))
57fa1d09 1029 r = device_set_subsystem(device, "module");
0b859c97 1030 else if (strstr(syspath, "/drivers/") || endswith(syspath, "/drivers"))
4956f220 1031 r = device_set_drivers_subsystem(device);
0b859c97 1032 else if (!isempty(PATH_STARTSWITH_SET(device->devpath, "/class/", "/bus/")))
57fa1d09 1033 r = device_set_subsystem(device, "subsystem");
4956f220
YW
1034 else {
1035 device->subsystem_set = true;
1036 r = 0;
de7e983e 1037 }
4956f220
YW
1038 if (r < 0)
1039 return log_device_debug_errno(device, r,
1040 "sd-device: Failed to set subsystem for %s: %m",
1041 device->devpath);
57fa1d09
TG
1042 }
1043
bf4c113e
DH
1044 if (!device->subsystem)
1045 return -ENOENT;
1046
45e093a9
YW
1047 if (ret)
1048 *ret = device->subsystem;
57fa1d09
TG
1049 return 0;
1050}
1051
1052_public_ int sd_device_get_devtype(sd_device *device, const char **devtype) {
1053 int r;
1054
730b76bd 1055 assert_return(device, -EINVAL);
57fa1d09
TG
1056
1057 r = device_read_uevent_file(device);
1058 if (r < 0)
1059 return r;
1060
dcfbde3a
YW
1061 if (!device->devtype)
1062 return -ENOENT;
1063
730b76bd
ZJS
1064 if (devtype)
1065 *devtype = device->devtype;
57fa1d09 1066
730b76bd 1067 return !!device->devtype;
57fa1d09
TG
1068}
1069
1070_public_ int sd_device_get_parent_with_subsystem_devtype(sd_device *child, const char *subsystem, const char *devtype, sd_device **ret) {
1071 sd_device *parent = NULL;
1072 int r;
1073
1074 assert_return(child, -EINVAL);
1075 assert_return(subsystem, -EINVAL);
1076
1077 r = sd_device_get_parent(child, &parent);
1078 while (r >= 0) {
1079 const char *parent_subsystem = NULL;
57fa1d09 1080
db2f8a2e 1081 (void) sd_device_get_subsystem(parent, &parent_subsystem);
57fa1d09 1082 if (streq_ptr(parent_subsystem, subsystem)) {
45e093a9
YW
1083 const char *parent_devtype = NULL;
1084
57fa1d09
TG
1085 if (!devtype)
1086 break;
1087
db2f8a2e 1088 (void) sd_device_get_devtype(parent, &parent_devtype);
57fa1d09
TG
1089 if (streq_ptr(parent_devtype, devtype))
1090 break;
1091 }
1092 r = sd_device_get_parent(parent, &parent);
1093 }
1094
1095 if (r < 0)
1096 return r;
1097
45e093a9
YW
1098 if (ret)
1099 *ret = parent;
57fa1d09
TG
1100 return 0;
1101}
1102
1103_public_ int sd_device_get_devnum(sd_device *device, dev_t *devnum) {
1104 int r;
1105
1106 assert_return(device, -EINVAL);
57fa1d09
TG
1107
1108 r = device_read_uevent_file(device);
1109 if (r < 0)
1110 return r;
1111
dcfbde3a
YW
1112 if (major(device->devnum) <= 0)
1113 return -ENOENT;
1114
78ffb476
YW
1115 if (devnum)
1116 *devnum = device->devnum;
57fa1d09
TG
1117
1118 return 0;
1119}
1120
ca0176fa
ZJS
1121int device_set_driver(sd_device *device, const char *driver) {
1122 _cleanup_free_ char *d = NULL;
57fa1d09
TG
1123 int r;
1124
1125 assert(device);
57fa1d09 1126
ca0176fa
ZJS
1127 if (driver) {
1128 d = strdup(driver);
1129 if (!d)
1130 return -ENOMEM;
1131 }
57fa1d09 1132
ca0176fa 1133 r = device_add_property_internal(device, "DRIVER", d);
57fa1d09
TG
1134 if (r < 0)
1135 return r;
1136
57fa1d09 1137 device->driver_set = true;
ca0176fa 1138 return free_and_replace(device->driver, d);
57fa1d09
TG
1139}
1140
1141_public_ int sd_device_get_driver(sd_device *device, const char **ret) {
1142 assert_return(device, -EINVAL);
57fa1d09
TG
1143
1144 if (!device->driver_set) {
1145 _cleanup_free_ char *driver = NULL;
1146 const char *syspath;
1147 char *path;
1148 int r;
1149
1150 r = sd_device_get_syspath(device, &syspath);
1151 if (r < 0)
1152 return r;
1153
1154 path = strjoina(syspath, "/driver");
1155 r = readlink_value(path, &driver);
ca0176fa
ZJS
1156 if (r < 0 && r != -ENOENT)
1157 return log_device_debug_errno(device, r,
1158 "sd-device: readlink(\"%s\") failed: %m", path);
1159
1160 r = device_set_driver(device, driver);
1161 if (r < 0)
1162 return log_device_debug_errno(device, r,
1163 "sd-device: Failed to set driver \"%s\": %m", driver);
57fa1d09
TG
1164 }
1165
bf4c113e
DH
1166 if (!device->driver)
1167 return -ENOENT;
1168
45e093a9
YW
1169 if (ret)
1170 *ret = device->driver;
57fa1d09
TG
1171 return 0;
1172}
1173
d4df6ce2 1174_public_ int sd_device_get_devpath(sd_device *device, const char **ret) {
57fa1d09 1175 assert_return(device, -EINVAL);
57fa1d09
TG
1176
1177 assert(device->devpath);
1178 assert(device->devpath[0] == '/');
1179
d4df6ce2
LP
1180 if (ret)
1181 *ret = device->devpath;
1182
57fa1d09
TG
1183 return 0;
1184}
1185
1186_public_ int sd_device_get_devname(sd_device *device, const char **devname) {
1187 int r;
1188
1189 assert_return(device, -EINVAL);
57fa1d09
TG
1190
1191 r = device_read_uevent_file(device);
1192 if (r < 0)
1193 return r;
1194
1195 if (!device->devname)
1196 return -ENOENT;
1197
1198 assert(path_startswith(device->devname, "/dev/"));
1199
45e093a9
YW
1200 if (devname)
1201 *devname = device->devname;
57fa1d09
TG
1202 return 0;
1203}
1204
6e25642f 1205static int device_set_sysname_and_sysnum(sd_device *device) {
57fa1d09 1206 _cleanup_free_ char *sysname = NULL;
9dbfcaf2 1207 size_t len, n;
5fa9d220 1208 int r;
57fa1d09 1209
c58e0ce6 1210 assert(device);
57fa1d09 1211
c58e0ce6
YW
1212 r = path_extract_filename(device->devpath, &sysname);
1213 if (r < 0)
1214 return r;
e4e1353c
YW
1215 if (r == O_DIRECTORY)
1216 return -EINVAL;
57fa1d09
TG
1217
1218 /* some devices have '!' in their name, change that to '/' */
9dbfcaf2 1219 string_replace_char(sysname, '!', '/');
57fa1d09 1220
9dbfcaf2
YW
1221 n = strspn_from_end(sysname, DIGITS);
1222 len = strlen(sysname);
1223 assert(n <= len);
1224 if (n == len)
1225 n = 0; /* Do not set sysnum for number only sysname. */
57fa1d09 1226
9dbfcaf2 1227 device->sysnum = n > 0 ? sysname + len - n : NULL;
2cfb1978 1228 return free_and_replace(device->sysname, sysname);
57fa1d09
TG
1229}
1230
1231_public_ int sd_device_get_sysname(sd_device *device, const char **ret) {
1232 int r;
1233
1234 assert_return(device, -EINVAL);
57fa1d09 1235
6e25642f
YW
1236 if (!device->sysname) {
1237 r = device_set_sysname_and_sysnum(device);
57fa1d09
TG
1238 if (r < 0)
1239 return r;
1240 }
1241
45e093a9
YW
1242 if (ret)
1243 *ret = device->sysname;
57fa1d09
TG
1244 return 0;
1245}
1246
1247_public_ int sd_device_get_sysnum(sd_device *device, const char **ret) {
1248 int r;
1249
1250 assert_return(device, -EINVAL);
57fa1d09 1251
6e25642f
YW
1252 if (!device->sysname) {
1253 r = device_set_sysname_and_sysnum(device);
57fa1d09
TG
1254 if (r < 0)
1255 return r;
1256 }
1257
dcfbde3a
YW
1258 if (!device->sysnum)
1259 return -ENOENT;
1260
45e093a9
YW
1261 if (ret)
1262 *ret = device->sysnum;
57fa1d09
TG
1263 return 0;
1264}
1265
a1130022
LP
1266_public_ int sd_device_get_action(sd_device *device, sd_device_action_t *ret) {
1267 assert_return(device, -EINVAL);
1268
1269 if (device->action < 0)
1270 return -ENOENT;
1271
1272 if (ret)
1273 *ret = device->action;
1274
1275 return 0;
1276}
1277
1278_public_ int sd_device_get_seqnum(sd_device *device, uint64_t *ret) {
1279 assert_return(device, -EINVAL);
1280
1281 if (device->seqnum == 0)
1282 return -ENOENT;
1283
1284 if (ret)
1285 *ret = device->seqnum;
1286
1287 return 0;
1288}
1289
122adcb2 1290_public_ int sd_device_get_diskseq(sd_device *device, uint64_t *ret) {
becbcca5
YW
1291 int r;
1292
122adcb2
LB
1293 assert_return(device, -EINVAL);
1294
becbcca5
YW
1295 r = device_read_uevent_file(device);
1296 if (r < 0)
1297 return r;
1298
122adcb2
LB
1299 if (device->diskseq == 0)
1300 return -ENOENT;
1301
1302 if (ret)
1303 *ret = device->diskseq;
1304
1305 return 0;
1306}
1307
57fa1d09
TG
1308static bool is_valid_tag(const char *tag) {
1309 assert(tag);
1310
1311 return !strchr(tag, ':') && !strchr(tag, ' ');
1312}
1313
e77b146f
LP
1314int device_add_tag(sd_device *device, const char *tag, bool both) {
1315 int r, added;
57fa1d09
TG
1316
1317 assert(device);
1318 assert(tag);
1319
1320 if (!is_valid_tag(tag))
1321 return -EINVAL;
1322
e77b146f
LP
1323 /* Definitely add to the "all" list of tags (i.e. the sticky list) */
1324 added = set_put_strdup(&device->all_tags, tag);
1325 if (added < 0)
1326 return added;
1327
1328 /* And optionally, also add it to the current list of tags */
1329 if (both) {
1330 r = set_put_strdup(&device->current_tags, tag);
1331 if (r < 0) {
1332 if (added > 0)
1333 (void) set_remove(device->all_tags, tag);
1334
1335 return r;
1336 }
1337 }
57fa1d09 1338
313cefa1 1339 device->tags_generation++;
57fa1d09
TG
1340 device->property_tags_outdated = true;
1341
1342 return 0;
1343}
1344
1345int device_add_devlink(sd_device *device, const char *devlink) {
1346 int r;
1347
1348 assert(device);
1349 assert(devlink);
1350
be327321 1351 r = set_put_strdup(&device->devlinks, devlink);
57fa1d09
TG
1352 if (r < 0)
1353 return r;
1354
313cefa1 1355 device->devlinks_generation++;
57fa1d09
TG
1356 device->property_devlinks_outdated = true;
1357
1358 return 0;
1359}
1360
b881ce16
YW
1361bool device_has_devlink(sd_device *device, const char *devlink) {
1362 assert(device);
1363 assert(devlink);
1364
1365 return set_contains(device->devlinks, devlink);
1366}
1367
57fa1d09
TG
1368static int device_add_property_internal_from_string(sd_device *device, const char *str) {
1369 _cleanup_free_ char *key = NULL;
1370 char *value;
03dd7b7d 1371 int r;
57fa1d09
TG
1372
1373 assert(device);
1374 assert(str);
1375
1376 key = strdup(str);
1377 if (!key)
1378 return -ENOMEM;
1379
1380 value = strchr(key, '=');
1381 if (!value)
1382 return -EINVAL;
1383
1384 *value = '\0';
1385
1386 if (isempty(++value))
1387 value = NULL;
1388
03dd7b7d
YW
1389 /* Add the property to both sd_device::properties and sd_device::properties_db,
1390 * as this is called by only handle_db_line(). */
1391 r = device_add_property_aux(device, key, value, false);
1392 if (r < 0)
1393 return r;
1394
1395 return device_add_property_aux(device, key, value, true);
57fa1d09
TG
1396}
1397
dc5042c0
ZJS
1398int device_set_usec_initialized(sd_device *device, usec_t when) {
1399 char s[DECIMAL_STR_MAX(usec_t)];
57fa1d09
TG
1400 int r;
1401
1402 assert(device);
57fa1d09 1403
dc5042c0 1404 xsprintf(s, USEC_FMT, when);
57fa1d09 1405
dc5042c0 1406 r = device_add_property_internal(device, "USEC_INITIALIZED", s);
57fa1d09
TG
1407 if (r < 0)
1408 return r;
1409
dc5042c0 1410 device->usec_initialized = when;
57fa1d09
TG
1411 return 0;
1412}
1413
1414static int handle_db_line(sd_device *device, char key, const char *value) {
57fa1d09
TG
1415 int r;
1416
1417 assert(device);
1418 assert(value);
1419
1420 switch (key) {
e77b146f
LP
1421 case 'G': /* Any tag */
1422 case 'Q': /* Current tag */
08405125 1423 return device_add_tag(device, value, key == 'Q');
57fa1d09 1424
08405125
YW
1425 case 'S': {
1426 const char *path;
57fa1d09 1427
08405125
YW
1428 path = strjoina("/dev/", value);
1429 return device_add_devlink(device, path);
1430 }
57fa1d09 1431 case 'E':
08405125 1432 return device_add_property_internal_from_string(device, value);
57fa1d09 1433
dc5042c0
ZJS
1434 case 'I': {
1435 usec_t t;
1436
1437 r = safe_atou64(value, &t);
1438 if (r < 0)
1439 return r;
1440
08405125 1441 return device_set_usec_initialized(device, t);
dc5042c0 1442 }
57fa1d09 1443 case 'L':
08405125 1444 return safe_atoi(value, &device->devlink_priority);
57fa1d09 1445
57fa1d09 1446 case 'W':
e7f781e4
YW
1447 /* Deprecated. Previously, watch handle is both saved in database and /run/udev/watch.
1448 * However, the handle saved in database may not be updated when the handle is updated
1449 * or removed. Moreover, it is not necessary to store the handle within the database,
1450 * as its value becomes meaningless when udevd is restarted. */
08405125
YW
1451 return 0;
1452
58b30ada 1453 case 'V':
08405125 1454 return safe_atou(value, &device->database_version);
58b30ada 1455
57fa1d09 1456 default:
c7d54dae 1457 log_device_debug(device, "sd-device: Unknown key '%c' in device db, ignoring", key);
08405125 1458 return 0;
57fa1d09 1459 }
57fa1d09
TG
1460}
1461
fe732381 1462int device_get_device_id(sd_device *device, const char **ret) {
57fa1d09
TG
1463 assert(device);
1464 assert(ret);
1465
fe732381 1466 if (!device->device_id) {
57fa1d09
TG
1467 _cleanup_free_ char *id = NULL;
1468 const char *subsystem;
1469 dev_t devnum;
1470 int ifindex, r;
1471
1472 r = sd_device_get_subsystem(device, &subsystem);
1473 if (r < 0)
1474 return r;
1475
dcfbde3a 1476 if (sd_device_get_devnum(device, &devnum) >= 0) {
ccddd104 1477 /* use dev_t — b259:131072, c254:0 */
ce1d08ba 1478 if (asprintf(&id, "%c%u:%u",
57fa1d09 1479 streq(subsystem, "block") ? 'b' : 'c',
ce1d08ba 1480 major(devnum), minor(devnum)) < 0)
53fae771 1481 return -ENOMEM;
1dfa9607 1482 } else if (sd_device_get_ifindex(device, &ifindex) >= 0) {
ccddd104 1483 /* use netdev ifindex — n3 */
ce1d08ba 1484 if (asprintf(&id, "n%u", (unsigned) ifindex) < 0)
53fae771 1485 return -ENOMEM;
57fa1d09 1486 } else {
ce1d08ba 1487 _cleanup_free_ char *sysname = NULL;
4189708a 1488
ce1d08ba
YW
1489 /* use $subsys:$sysname — pci:0000:00:1f.2
1490 * sd_device_get_sysname() has '!' translated, get it from devpath */
1491 r = path_extract_filename(device->devpath, &sysname);
1492 if (r < 0)
1493 return r;
e4e1353c
YW
1494 if (r == O_DIRECTORY)
1495 return -EINVAL;
57fa1d09 1496
ce1d08ba
YW
1497 if (streq(subsystem, "drivers")) {
1498 /* the 'drivers' pseudo-subsystem is special, and needs the real
1499 * subsystem encoded as well */
1500 assert(device->driver_subsystem);
fe20121a 1501 id = strjoin("+drivers:", device->driver_subsystem, ":", sysname);
ce1d08ba 1502 } else
fe20121a
ZJS
1503 id = strjoin("+", subsystem, ":", sysname);
1504 if (!id)
1505 return -ENOMEM;
57fa1d09
TG
1506 }
1507
db2bad43
YW
1508 if (!filename_is_valid(id))
1509 return -EINVAL;
1510
fe732381 1511 device->device_id = TAKE_PTR(id);
57fa1d09
TG
1512 }
1513
fe732381 1514 *ret = device->device_id;
57fa1d09
TG
1515 return 0;
1516}
1517
b07d0f2a 1518int device_read_db_internal_filename(sd_device *device, const char *filename) {
57fa1d09 1519 _cleanup_free_ char *db = NULL;
b07d0f2a 1520 const char *value;
462035d5 1521 size_t db_len;
376ee2c3 1522 char key = '\0'; /* Unnecessary initialization to appease gcc-12.0.0-0.4.fc36 */
57fa1d09
TG
1523 int r;
1524
1525 enum {
1526 PRE_KEY,
1527 KEY,
1528 PRE_VALUE,
1529 VALUE,
1530 INVALID_LINE,
1531 } state = PRE_KEY;
1532
ebcc52fa 1533 assert(device);
b07d0f2a 1534 assert(filename);
ebcc52fa 1535
b07d0f2a 1536 r = read_full_file(filename, &db, &db_len);
57fa1d09
TG
1537 if (r < 0) {
1538 if (r == -ENOENT)
1539 return 0;
b07d0f2a
YW
1540
1541 return log_device_debug_errno(device, r, "sd-device: Failed to read db '%s': %m", filename);
57fa1d09
TG
1542 }
1543
1544 /* devices with a database entry are initialized */
7e518afa 1545 device->is_initialized = true;
57fa1d09 1546
cd53c8f9
ZJS
1547 device->db_loaded = true;
1548
e47a3af4 1549 for (size_t i = 0; i < db_len; i++)
57fa1d09
TG
1550 switch (state) {
1551 case PRE_KEY:
1552 if (!strchr(NEWLINE, db[i])) {
1553 key = db[i];
1554
1555 state = KEY;
1556 }
1557
1558 break;
1559 case KEY:
1560 if (db[i] != ':') {
c7d54dae 1561 log_device_debug(device, "sd-device: Invalid db entry with key '%c', ignoring", key);
57fa1d09
TG
1562
1563 state = INVALID_LINE;
1564 } else {
1565 db[i] = '\0';
1566
1567 state = PRE_VALUE;
1568 }
1569
1570 break;
1571 case PRE_VALUE:
1572 value = &db[i];
1573
1574 state = VALUE;
1575
1576 break;
1577 case INVALID_LINE:
1578 if (strchr(NEWLINE, db[i]))
1579 state = PRE_KEY;
1580
1581 break;
1582 case VALUE:
1583 if (strchr(NEWLINE, db[i])) {
1584 db[i] = '\0';
1585 r = handle_db_line(device, key, value);
1586 if (r < 0)
462035d5
ZJS
1587 log_device_debug_errno(device, r, "sd-device: Failed to handle db entry '%c:%s', ignoring: %m",
1588 key, value);
57fa1d09
TG
1589
1590 state = PRE_KEY;
1591 }
1592
1593 break;
1594 default:
b07d0f2a 1595 return log_device_debug_errno(device, SYNTHETIC_ERRNO(EINVAL), "sd-device: invalid db syntax.");
57fa1d09 1596 }
57fa1d09 1597
57fa1d09
TG
1598 return 0;
1599}
1600
b07d0f2a
YW
1601int device_read_db_internal(sd_device *device, bool force) {
1602 const char *id, *path;
1603 int r;
1604
1605 assert(device);
1606
1607 if (device->db_loaded || (!force && device->sealed))
1608 return 0;
1609
fe732381 1610 r = device_get_device_id(device, &id);
b07d0f2a
YW
1611 if (r < 0)
1612 return r;
1613
1614 path = strjoina("/run/udev/data/", id);
1615
1616 return device_read_db_internal_filename(device, path);
1617}
1618
5a937ea2 1619_public_ int sd_device_get_is_initialized(sd_device *device) {
57fa1d09
TG
1620 int r;
1621
1622 assert_return(device, -EINVAL);
57fa1d09
TG
1623
1624 r = device_read_db(device);
591c186f
YW
1625 if (r == -ENOENT)
1626 /* The device may be already removed or renamed. */
1627 return false;
57fa1d09
TG
1628 if (r < 0)
1629 return r;
1630
5a937ea2 1631 return device->is_initialized;
57fa1d09
TG
1632}
1633
8626b43b
LP
1634_public_ int sd_device_get_usec_initialized(sd_device *device, uint64_t *ret) {
1635 int r;
1636
1637 assert_return(device, -EINVAL);
1638
4eb5f1db 1639 r = sd_device_get_is_initialized(device);
8626b43b
LP
1640 if (r < 0)
1641 return r;
4eb5f1db 1642 if (r == 0)
8626b43b
LP
1643 return -EBUSY;
1644
1645 if (device->usec_initialized == 0)
1646 return -ENODATA;
1647
1648 if (ret)
1649 *ret = device->usec_initialized;
1650
1651 return 0;
1652}
1653
4eb5f1db
YW
1654_public_ int sd_device_get_usec_since_initialized(sd_device *device, uint64_t *ret) {
1655 usec_t now_ts, ts;
57fa1d09
TG
1656 int r;
1657
1658 assert_return(device, -EINVAL);
57fa1d09 1659
4eb5f1db 1660 r = sd_device_get_usec_initialized(device, &ts);
57fa1d09
TG
1661 if (r < 0)
1662 return r;
1663
02ef01ad 1664 now_ts = now(CLOCK_MONOTONIC);
57fa1d09 1665
4eb5f1db 1666 if (now_ts < ts)
57fa1d09
TG
1667 return -EIO;
1668
4eb5f1db
YW
1669 if (ret)
1670 *ret = usec_sub_unsigned(now_ts, ts);
1671
57fa1d09
TG
1672 return 0;
1673}
1674
1675_public_ const char *sd_device_get_tag_first(sd_device *device) {
8927b1da
DH
1676 void *v;
1677
57fa1d09
TG
1678 assert_return(device, NULL);
1679
1680 (void) device_read_db(device);
1681
e77b146f
LP
1682 device->all_tags_iterator_generation = device->tags_generation;
1683 device->all_tags_iterator = ITERATOR_FIRST;
57fa1d09 1684
e77b146f 1685 (void) set_iterate(device->all_tags, &device->all_tags_iterator, &v);
8927b1da 1686 return v;
57fa1d09
TG
1687}
1688
1689_public_ const char *sd_device_get_tag_next(sd_device *device) {
8927b1da
DH
1690 void *v;
1691
57fa1d09
TG
1692 assert_return(device, NULL);
1693
1694 (void) device_read_db(device);
1695
e77b146f
LP
1696 if (device->all_tags_iterator_generation != device->tags_generation)
1697 return NULL;
1698
1699 (void) set_iterate(device->all_tags, &device->all_tags_iterator, &v);
1700 return v;
1701}
1702
6ece7cd2
YW
1703static bool device_database_supports_current_tags(sd_device *device) {
1704 assert(device);
1705
1706 (void) device_read_db(device);
1707
1708 /* The current tags (saved in Q field) feature is implemented in database version 1.
1709 * If the database version is 0, then the tags (NOT current tags, saved in G field) are not
1710 * sticky. Thus, we can safely bypass the operations for the current tags (Q) to tags (G). */
1711
1712 return device->database_version >= 1;
1713}
1714
e77b146f
LP
1715_public_ const char *sd_device_get_current_tag_first(sd_device *device) {
1716 void *v;
1717
1718 assert_return(device, NULL);
1719
6ece7cd2
YW
1720 if (!device_database_supports_current_tags(device))
1721 return sd_device_get_tag_first(device);
1722
e77b146f
LP
1723 (void) device_read_db(device);
1724
1725 device->current_tags_iterator_generation = device->tags_generation;
1726 device->current_tags_iterator = ITERATOR_FIRST;
1727
1728 (void) set_iterate(device->current_tags, &device->current_tags_iterator, &v);
1729 return v;
1730}
1731
1732_public_ const char *sd_device_get_current_tag_next(sd_device *device) {
1733 void *v;
1734
1735 assert_return(device, NULL);
1736
6ece7cd2
YW
1737 if (!device_database_supports_current_tags(device))
1738 return sd_device_get_tag_next(device);
1739
e77b146f
LP
1740 (void) device_read_db(device);
1741
1742 if (device->current_tags_iterator_generation != device->tags_generation)
57fa1d09
TG
1743 return NULL;
1744
e77b146f 1745 (void) set_iterate(device->current_tags, &device->current_tags_iterator, &v);
8927b1da 1746 return v;
57fa1d09
TG
1747}
1748
1749_public_ const char *sd_device_get_devlink_first(sd_device *device) {
8927b1da
DH
1750 void *v;
1751
57fa1d09
TG
1752 assert_return(device, NULL);
1753
1754 (void) device_read_db(device);
1755
1756 device->devlinks_iterator_generation = device->devlinks_generation;
1757 device->devlinks_iterator = ITERATOR_FIRST;
1758
bccfe92e 1759 (void) set_iterate(device->devlinks, &device->devlinks_iterator, &v);
8927b1da 1760 return v;
57fa1d09
TG
1761}
1762
1763_public_ const char *sd_device_get_devlink_next(sd_device *device) {
8927b1da
DH
1764 void *v;
1765
57fa1d09
TG
1766 assert_return(device, NULL);
1767
1768 (void) device_read_db(device);
1769
1770 if (device->devlinks_iterator_generation != device->devlinks_generation)
1771 return NULL;
1772
bccfe92e 1773 (void) set_iterate(device->devlinks, &device->devlinks_iterator, &v);
8927b1da 1774 return v;
57fa1d09
TG
1775}
1776
a3ce8136 1777int device_properties_prepare(sd_device *device) {
57fa1d09
TG
1778 int r;
1779
1780 assert(device);
1781
1782 r = device_read_uevent_file(device);
1783 if (r < 0)
1784 return r;
1785
1786 r = device_read_db(device);
1787 if (r < 0)
1788 return r;
1789
1790 if (device->property_devlinks_outdated) {
1d88a271 1791 _cleanup_free_ char *devlinks = NULL;
57fa1d09 1792
8d80f275 1793 r = set_strjoin(device->devlinks, " ", false, &devlinks);
57fa1d09
TG
1794 if (r < 0)
1795 return r;
1796
6f3ac0d5
YW
1797 if (!isempty(devlinks)) {
1798 r = device_add_property_internal(device, "DEVLINKS", devlinks);
1799 if (r < 0)
1800 return r;
1801 }
1802
57fa1d09
TG
1803 device->property_devlinks_outdated = false;
1804 }
1805
1806 if (device->property_tags_outdated) {
1d88a271 1807 _cleanup_free_ char *tags = NULL;
57fa1d09 1808
8d80f275 1809 r = set_strjoin(device->all_tags, ":", true, &tags);
6f3ac0d5
YW
1810 if (r < 0)
1811 return r;
57fa1d09 1812
6f3ac0d5 1813 if (!isempty(tags)) {
e77b146f
LP
1814 r = device_add_property_internal(device, "TAGS", tags);
1815 if (r < 0)
1816 return r;
1d88a271 1817 }
57fa1d09 1818
6f3ac0d5 1819 tags = mfree(tags);
8d80f275 1820 r = set_strjoin(device->current_tags, ":", true, &tags);
6f3ac0d5
YW
1821 if (r < 0)
1822 return r;
e77b146f 1823
6f3ac0d5 1824 if (!isempty(tags)) {
e77b146f
LP
1825 r = device_add_property_internal(device, "CURRENT_TAGS", tags);
1826 if (r < 0)
1827 return r;
1828 }
57fa1d09
TG
1829
1830 device->property_tags_outdated = false;
1831 }
1832
1833 return 0;
1834}
1835
1836_public_ const char *sd_device_get_property_first(sd_device *device, const char **_value) {
1837 const char *key;
57fa1d09
TG
1838 int r;
1839
1840 assert_return(device, NULL);
1841
1842 r = device_properties_prepare(device);
1843 if (r < 0)
1844 return NULL;
1845
1846 device->properties_iterator_generation = device->properties_generation;
1847 device->properties_iterator = ITERATOR_FIRST;
1848
7b9103a6 1849 (void) ordered_hashmap_iterate(device->properties, &device->properties_iterator, (void**)_value, (const void**)&key);
57fa1d09
TG
1850 return key;
1851}
1852
1853_public_ const char *sd_device_get_property_next(sd_device *device, const char **_value) {
1854 const char *key;
57fa1d09
TG
1855 int r;
1856
1857 assert_return(device, NULL);
1858
1859 r = device_properties_prepare(device);
1860 if (r < 0)
1861 return NULL;
1862
1863 if (device->properties_iterator_generation != device->properties_generation)
1864 return NULL;
1865
7b9103a6 1866 (void) ordered_hashmap_iterate(device->properties, &device->properties_iterator, (void**)_value, (const void**)&key);
57fa1d09
TG
1867 return key;
1868}
1869
fadcc122
YW
1870static int device_sysattrs_read_all_internal(sd_device *device, const char *subdir) {
1871 _cleanup_free_ char *path_dir = NULL;
57fa1d09 1872 _cleanup_closedir_ DIR *dir = NULL;
fadcc122 1873 const char *syspath;
57fa1d09
TG
1874 int r;
1875
57fa1d09
TG
1876 r = sd_device_get_syspath(device, &syspath);
1877 if (r < 0)
1878 return r;
1879
fadcc122
YW
1880 if (subdir) {
1881 _cleanup_free_ char *p = NULL;
1882
1883 p = path_join(syspath, subdir, "uevent");
1884 if (!p)
1885 return -ENOMEM;
1886
1887 if (access(p, F_OK) >= 0)
1888 /* this is a child device, skipping */
1889 return 0;
21c7fe6d 1890 if (errno != ENOENT) {
43b24a07 1891 log_device_debug_errno(device, errno, "sd-device: Failed to stat %s, ignoring subdir: %m", p);
21c7fe6d
ZJS
1892 return 0;
1893 }
fadcc122
YW
1894
1895 path_dir = path_join(syspath, subdir);
1896 if (!path_dir)
1897 return -ENOMEM;
1898 }
1899
1900 dir = opendir(path_dir ?: syspath);
57fa1d09
TG
1901 if (!dir)
1902 return -errno;
1903
c7f0d9e5 1904 FOREACH_DIRENT_ALL(de, dir, return -errno) {
fadcc122 1905 _cleanup_free_ char *path = NULL, *p = NULL;
57fa1d09
TG
1906 struct stat statbuf;
1907
c7f0d9e5 1908 if (dot_or_dot_dot(de->d_name))
57fa1d09
TG
1909 continue;
1910
fadcc122 1911 /* only handle symlinks, regular files, and directories */
c7f0d9e5 1912 if (!IN_SET(de->d_type, DT_LNK, DT_REG, DT_DIR))
fadcc122
YW
1913 continue;
1914
1915 if (subdir) {
c7f0d9e5 1916 p = path_join(subdir, de->d_name);
fadcc122
YW
1917 if (!p)
1918 return -ENOMEM;
1919 }
1920
c7f0d9e5 1921 if (de->d_type == DT_DIR) {
fadcc122 1922 /* read subdirectory */
c7f0d9e5 1923 r = device_sysattrs_read_all_internal(device, p ?: de->d_name);
fadcc122
YW
1924 if (r < 0)
1925 return r;
1926
1927 continue;
1928 }
1929
c7f0d9e5 1930 path = path_join(syspath, p ?: de->d_name);
6d946490
YW
1931 if (!path)
1932 return -ENOMEM;
57fa1d09
TG
1933
1934 if (lstat(path, &statbuf) != 0)
1935 continue;
1936
ab218d0b 1937 if ((statbuf.st_mode & (S_IRUSR | S_IWUSR)) == 0)
57fa1d09
TG
1938 continue;
1939
c7f0d9e5 1940 r = set_put_strdup(&device->sysattrs, p ?: de->d_name);
57fa1d09
TG
1941 if (r < 0)
1942 return r;
1943 }
1944
fadcc122
YW
1945 return 0;
1946}
1947
1948static int device_sysattrs_read_all(sd_device *device) {
1949 int r;
1950
1951 assert(device);
1952
1953 if (device->sysattrs_read)
1954 return 0;
1955
1956 r = device_sysattrs_read_all_internal(device, NULL);
1957 if (r < 0)
1958 return r;
1959
57fa1d09
TG
1960 device->sysattrs_read = true;
1961
1962 return 0;
1963}
1964
1965_public_ const char *sd_device_get_sysattr_first(sd_device *device) {
8927b1da 1966 void *v;
57fa1d09
TG
1967 int r;
1968
1969 assert_return(device, NULL);
1970
1971 if (!device->sysattrs_read) {
1972 r = device_sysattrs_read_all(device);
1973 if (r < 0) {
1974 errno = -r;
1975 return NULL;
1976 }
1977 }
1978
1979 device->sysattrs_iterator = ITERATOR_FIRST;
1980
bccfe92e 1981 (void) set_iterate(device->sysattrs, &device->sysattrs_iterator, &v);
8927b1da 1982 return v;
57fa1d09
TG
1983}
1984
1985_public_ const char *sd_device_get_sysattr_next(sd_device *device) {
8927b1da
DH
1986 void *v;
1987
57fa1d09
TG
1988 assert_return(device, NULL);
1989
1990 if (!device->sysattrs_read)
1991 return NULL;
1992
bccfe92e 1993 (void) set_iterate(device->sysattrs, &device->sysattrs_iterator, &v);
8927b1da 1994 return v;
57fa1d09
TG
1995}
1996
1997_public_ int sd_device_has_tag(sd_device *device, const char *tag) {
1998 assert_return(device, -EINVAL);
1999 assert_return(tag, -EINVAL);
2000
2001 (void) device_read_db(device);
2002
e77b146f
LP
2003 return set_contains(device->all_tags, tag);
2004}
2005
2006_public_ int sd_device_has_current_tag(sd_device *device, const char *tag) {
2007 assert_return(device, -EINVAL);
2008 assert_return(tag, -EINVAL);
2009
6ece7cd2
YW
2010 if (!device_database_supports_current_tags(device))
2011 return sd_device_has_tag(device, tag);
2012
e77b146f
LP
2013 (void) device_read_db(device);
2014
2015 return set_contains(device->current_tags, tag);
57fa1d09
TG
2016}
2017
45e093a9
YW
2018_public_ int sd_device_get_property_value(sd_device *device, const char *key, const char **ret_value) {
2019 const char *value;
57fa1d09
TG
2020 int r;
2021
2022 assert_return(device, -EINVAL);
2023 assert_return(key, -EINVAL);
57fa1d09
TG
2024
2025 r = device_properties_prepare(device);
2026 if (r < 0)
2027 return r;
2028
2029 value = ordered_hashmap_get(device->properties, key);
2030 if (!value)
2031 return -ENOENT;
2032
45e093a9
YW
2033 if (ret_value)
2034 *ret_value = value;
57fa1d09
TG
2035 return 0;
2036}
2037
15345fc6
YW
2038int device_get_property_bool(sd_device *device, const char *key) {
2039 const char *value;
2040 int r;
2041
2042 assert(device);
2043 assert(key);
2044
2045 r = sd_device_get_property_value(device, key, &value);
2046 if (r < 0)
2047 return r;
2048
2049 return parse_boolean(value);
2050}
2051
b485fd93
LP
2052_public_ int sd_device_get_trigger_uuid(sd_device *device, sd_id128_t *ret) {
2053 const char *s;
2054 sd_id128_t id;
2055 int r;
2056
2057 assert_return(device, -EINVAL);
2058
2059 /* Retrieves the UUID attached to a uevent when triggering it from userspace via
2060 * sd_device_trigger_with_uuid() or an equivalent interface. Returns -ENOENT if the record is not
2061 * caused by a synthetic event and -ENODATA if it was but no UUID was specified */
2062
2063 r = sd_device_get_property_value(device, "SYNTH_UUID", &s);
2064 if (r < 0)
2065 return r;
2066
2067 if (streq(s, "0")) /* SYNTH_UUID=0 is set whenever a device is triggered by userspace without specifying a UUID */
2068 return -ENODATA;
2069
2070 r = sd_id128_from_string(s, &id);
2071 if (r < 0)
2072 return r;
2073
2074 if (ret)
2075 *ret = id;
2076
2077 return 0;
2078}
2079
5eb83e90
YW
2080void device_clear_sysattr_cache(sd_device *device) {
2081 device->sysattr_values = hashmap_free(device->sysattr_values);
2082}
2083
18b11379 2084int device_cache_sysattr_value(sd_device *device, const char *key, char *value) {
d7ac0952
FS
2085 _unused_ _cleanup_free_ char *old_value = NULL;
2086 _cleanup_free_ char *new_key = NULL;
57fa1d09
TG
2087 int r;
2088
2089 assert(device);
61c0972d 2090 assert(key);
57fa1d09 2091
61c0972d
YW
2092 /* This takes the reference of the input value. The input value may be NULL.
2093 * This replaces the value if it already exists. */
57fa1d09 2094
66efcbb1 2095 /* First, remove the old cache entry. So, we do not need to clear cache on error. */
61c0972d
YW
2096 old_value = hashmap_remove2(device->sysattr_values, key, (void **) &new_key);
2097 if (!new_key) {
2098 new_key = strdup(key);
2099 if (!new_key)
57fa1d09
TG
2100 return -ENOMEM;
2101 }
2102
61c0972d 2103 r = hashmap_ensure_put(&device->sysattr_values, &string_hash_ops_free_free, new_key, value);
57fa1d09
TG
2104 if (r < 0)
2105 return r;
61c0972d
YW
2106
2107 TAKE_PTR(new_key);
57fa1d09
TG
2108
2109 return 0;
2110}
2111
18b11379 2112int device_get_cached_sysattr_value(sd_device *device, const char *key, const char **ret_value) {
b63dd5aa 2113 const char *k = NULL, *value;
57fa1d09
TG
2114
2115 assert(device);
b63dd5aa 2116 assert(key);
57fa1d09 2117
b63dd5aa
YW
2118 value = hashmap_get2(device->sysattr_values, key, (void **) &k);
2119 if (!k)
2120 return -ESTALE; /* We have not read the attribute. */
2121 if (!value)
2122 return -ENOENT; /* We have looked up the attribute before and it did not exist. */
2123 if (ret_value)
2124 *ret_value = value;
57fa1d09
TG
2125 return 0;
2126}
2127
2128/* We cache all sysattr lookups. If an attribute does not exist, it is stored
2129 * with a NULL value in the cache, otherwise the returned string is stored */
32a739af 2130_public_ int sd_device_get_sysattr_value(sd_device *device, const char *sysattr, const char **ret_value) {
8e7e4a73
LP
2131 _cleanup_free_ char *value = NULL, *path = NULL;
2132 const char *syspath;
57fa1d09
TG
2133 struct stat statbuf;
2134 int r;
2135
2136 assert_return(device, -EINVAL);
2137 assert_return(sysattr, -EINVAL);
2138
2139 /* look for possibly already cached result */
b63dd5aa
YW
2140 r = device_get_cached_sysattr_value(device, sysattr, ret_value);
2141 if (r != -ESTALE)
2142 return r;
57fa1d09
TG
2143
2144 r = sd_device_get_syspath(device, &syspath);
2145 if (r < 0)
2146 return r;
2147
8e7e4a73
LP
2148 path = path_join(syspath, sysattr);
2149 if (!path)
2150 return -ENOMEM;
2151
e2e40e9a 2152 if (lstat(path, &statbuf) < 0) {
acfc2a1d
YW
2153 int k;
2154
e2e40e9a
LP
2155 r = -errno;
2156
57fa1d09 2157 /* remember that we could not access the sysattr */
acfc2a1d
YW
2158 k = device_cache_sysattr_value(device, sysattr, NULL);
2159 if (k < 0)
2160 log_device_debug_errno(device, k,
2161 "sd-device: failed to cache attribute '%s' with NULL, ignoring: %m",
2162 sysattr);
57fa1d09 2163
acfc2a1d 2164 return r;
57fa1d09
TG
2165 } else if (S_ISLNK(statbuf.st_mode)) {
2166 /* Some core links return only the last element of the target path,
2167 * these are just values, the paths should not be exposed. */
2168 if (STR_IN_SET(sysattr, "driver", "subsystem", "module")) {
2169 r = readlink_value(path, &value);
2170 if (r < 0)
2171 return r;
2172 } else
2173 return -EINVAL;
163e0a88 2174 } else if (S_ISDIR(statbuf.st_mode))
57fa1d09 2175 /* skip directories */
163e0a88
YW
2176 return -EISDIR;
2177 else if (!(statbuf.st_mode & S_IRUSR))
57fa1d09
TG
2178 /* skip non-readable files */
2179 return -EPERM;
163e0a88 2180 else {
70160c6e
YW
2181 size_t size;
2182
2183 /* Read attribute value, Some attributes contain embedded '\0'. So, it is necessary to
2184 * also get the size of the result. See issue #20025. */
2185 r = read_full_virtual_file(path, &value, &size);
57fa1d09
TG
2186 if (r < 0)
2187 return r;
2188
2189 /* drop trailing newlines */
70160c6e
YW
2190 while (size > 0 && strchr(NEWLINE, value[--size]))
2191 value[size] = '\0';
57fa1d09
TG
2192 }
2193
acfc2a1d
YW
2194 /* Unfortunately, we need to return 'const char*' instead of 'char*'. Hence, failure in caching
2195 * sysattr value is critical unlike the other places. */
2a0ebc05 2196 r = device_cache_sysattr_value(device, sysattr, value);
acfc2a1d
YW
2197 if (r < 0) {
2198 log_device_debug_errno(device, r,
2199 "sd-device: failed to cache attribute '%s' with '%s'%s: %m",
2200 sysattr, value, ret_value ? "" : ", ignoring");
2201 if (ret_value)
2202 return r;
2203 } else if (ret_value)
32a739af 2204 *ret_value = TAKE_PTR(value);
57fa1d09
TG
2205
2206 return 0;
2207}
2208
2829fca2
YW
2209int device_get_sysattr_bool(sd_device *device, const char *sysattr) {
2210 const char *value;
2211 int r;
2212
2213 assert(device);
2214 assert(sysattr);
2215
2216 r = sd_device_get_sysattr_value(device, sysattr, &value);
2217 if (r < 0)
2218 return r;
2219
2220 return parse_boolean(value);
2221}
2222
2a0ebc05 2223static void device_remove_cached_sysattr_value(sd_device *device, const char *_key) {
57fa1d09 2224 _cleanup_free_ char *key = NULL;
57fa1d09
TG
2225
2226 assert(device);
2227 assert(_key);
2228
2cfb1978 2229 free(hashmap_remove2(device->sysattr_values, _key, (void **) &key));
57fa1d09
TG
2230}
2231
8aae9a66 2232_public_ int sd_device_set_sysattr_value(sd_device *device, const char *sysattr, const char *_value) {
8e7e4a73
LP
2233 _cleanup_free_ char *value = NULL, *path = NULL;
2234 const char *syspath;
7cadbe09 2235 size_t len;
57fa1d09
TG
2236 int r;
2237
2238 assert_return(device, -EINVAL);
2239 assert_return(sysattr, -EINVAL);
2240
2f7a2e39
YW
2241 /* Set the attribute and save it in the cache. */
2242
2fe29a46 2243 if (!_value) {
2f7a2e39 2244 /* If input value is NULL, then clear cache and not write anything. */
2a0ebc05 2245 device_remove_cached_sysattr_value(device, sysattr);
57fa1d09
TG
2246 return 0;
2247 }
2248
2249 r = sd_device_get_syspath(device, &syspath);
2250 if (r < 0)
2251 return r;
2252
8e7e4a73
LP
2253 path = path_join(syspath, sysattr);
2254 if (!path)
2255 return -ENOMEM;
2fa4861a 2256
2fa4861a 2257 len = strlen(_value);
57fa1d09
TG
2258
2259 /* drop trailing newlines */
2a394d0b 2260 while (len > 0 && strchr(NEWLINE, _value[len - 1]))
2fa4861a 2261 len --;
57fa1d09
TG
2262
2263 /* value length is limited to 4k */
2fa4861a 2264 if (len > 4096)
57fa1d09
TG
2265 return -EINVAL;
2266
2fa4861a 2267 value = strndup(_value, len);
2fe29a46
TG
2268 if (!value)
2269 return -ENOMEM;
2270
7cadbe09
YW
2271 r = write_string_file(path, value, WRITE_STRING_FILE_DISABLE_BUFFER | WRITE_STRING_FILE_NOFOLLOW);
2272 if (r < 0) {
23ff570b
YW
2273 /* On failure, clear cache entry, as we do not know how it fails. */
2274 device_remove_cached_sysattr_value(device, sysattr);
2275 return r;
7cadbe09 2276 }
57fa1d09 2277
297d1370
YW
2278 /* Do not cache action string written into uevent file. */
2279 if (streq(sysattr, "uevent"))
2280 return 0;
2281
2a0ebc05 2282 r = device_cache_sysattr_value(device, sysattr, value);
57fa1d09 2283 if (r < 0)
acfc2a1d
YW
2284 log_device_debug_errno(device, r,
2285 "sd-device: failed to cache attribute '%s' with '%s', ignoring: %m",
2286 sysattr, value);
2287 else
2288 TAKE_PTR(value);
2fe29a46 2289
57fa1d09
TG
2290 return 0;
2291}
ea2bc257
YW
2292
2293_public_ int sd_device_set_sysattr_valuef(sd_device *device, const char *sysattr, const char *format, ...) {
2294 _cleanup_free_ char *value = NULL;
2295 va_list ap;
2296 int r;
2297
2298 assert_return(device, -EINVAL);
2299 assert_return(sysattr, -EINVAL);
2300
2301 if (!format) {
2a0ebc05 2302 device_remove_cached_sysattr_value(device, sysattr);
ea2bc257
YW
2303 return 0;
2304 }
2305
2306 va_start(ap, format);
2307 r = vasprintf(&value, format, ap);
2308 va_end(ap);
2309
2310 if (r < 0)
2311 return -ENOMEM;
2312
2313 return sd_device_set_sysattr_value(device, sysattr, value);
2314}
f4d36efa
YW
2315
2316_public_ int sd_device_trigger(sd_device *device, sd_device_action_t action) {
2317 const char *s;
2318
2319 assert_return(device, -EINVAL);
2320
2321 s = device_action_to_string(action);
2322 if (!s)
2323 return -EINVAL;
2324
b485fd93 2325 /* This uses the simple no-UUID interface of kernel < 4.13 */
f4d36efa
YW
2326 return sd_device_set_sysattr_value(device, "uevent", s);
2327}
b485fd93
LP
2328
2329_public_ int sd_device_trigger_with_uuid(
2330 sd_device *device,
2331 sd_device_action_t action,
2332 sd_id128_t *ret_uuid) {
2333
b485fd93
LP
2334 const char *s, *j;
2335 sd_id128_t u;
2336 int r;
2337
2338 assert_return(device, -EINVAL);
2339
48008c1c 2340 /* If no one wants to know the UUID, use the simple interface from pre-4.13 times */
b485fd93
LP
2341 if (!ret_uuid)
2342 return sd_device_trigger(device, action);
2343
2344 s = device_action_to_string(action);
2345 if (!s)
2346 return -EINVAL;
2347
2348 r = sd_id128_randomize(&u);
2349 if (r < 0)
2350 return r;
2351
b7416360 2352 j = strjoina(s, " ", SD_ID128_TO_UUID_STRING(u));
b485fd93
LP
2353
2354 r = sd_device_set_sysattr_value(device, "uevent", j);
2355 if (r < 0)
2356 return r;
2357
2358 *ret_uuid = u;
2359 return 0;
2360}
f9a726ab
YW
2361
2362_public_ int sd_device_open(sd_device *device, int flags) {
2363 _cleanup_close_ int fd = -1, fd2 = -1;
15345fc6 2364 const char *devname, *subsystem = NULL;
f9a726ab
YW
2365 uint64_t q, diskseq = 0;
2366 struct stat st;
2367 dev_t devnum;
2368 int r;
2369
2370 assert_return(device, -EINVAL);
2371 assert_return(FLAGS_SET(flags, O_PATH) || !FLAGS_SET(flags, O_NOFOLLOW), -EINVAL);
2372
2373 r = sd_device_get_devname(device, &devname);
2374 if (r == -ENOENT)
2375 return -ENOEXEC;
2376 if (r < 0)
2377 return r;
2378
2379 r = sd_device_get_devnum(device, &devnum);
2380 if (r == -ENOENT)
2381 return -ENOEXEC;
2382 if (r < 0)
2383 return r;
2384
2385 r = sd_device_get_subsystem(device, &subsystem);
2386 if (r < 0 && r != -ENOENT)
2387 return r;
2388
f9a726ab
YW
2389 fd = open(devname, FLAGS_SET(flags, O_PATH) ? flags : O_CLOEXEC|O_NOFOLLOW|O_PATH);
2390 if (fd < 0)
2391 return -errno;
2392
2393 if (fstat(fd, &st) < 0)
2394 return -errno;
2395
2396 if (st.st_rdev != devnum)
2397 return -ENXIO;
2398
2399 if (streq_ptr(subsystem, "block") ? !S_ISBLK(st.st_mode) : !S_ISCHR(st.st_mode))
2400 return -ENXIO;
2401
2402 /* If flags has O_PATH, then we cannot check diskseq. Let's return earlier. */
2403 if (FLAGS_SET(flags, O_PATH))
2404 return TAKE_FD(fd);
2405
15345fc6 2406 r = device_get_property_bool(device, "ID_IGNORE_DISKSEQ");
03b894fc
YW
2407 if (r < 0 && r != -ENOENT)
2408 return r;
15345fc6 2409 if (r <= 0) {
03b894fc
YW
2410 r = sd_device_get_diskseq(device, &diskseq);
2411 if (r < 0 && r != -ENOENT)
2412 return r;
2413 }
2414
f9a726ab
YW
2415 fd2 = open(FORMAT_PROC_FD_PATH(fd), flags);
2416 if (fd2 < 0)
2417 return -errno;
2418
2419 if (diskseq == 0)
2420 return TAKE_FD(fd2);
2421
2422 r = fd_get_diskseq(fd2, &q);
2423 if (r < 0)
2424 return r;
2425
2426 if (q != diskseq)
2427 return -ENXIO;
2428
2429 return TAKE_FD(fd2);
2430}