]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd/sd-device/device-private.c
strv: make iterator in STRV_FOREACH() declaread in the loop
[thirdparty/systemd.git] / src / libsystemd / sd-device / device-private.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>
07630cea 5#include <sys/types.h>
57fa1d09
TG
6
7#include "sd-device.h"
8
b5efdb8a 9#include "alloc-util.h"
57fa1d09
TG
10#include "device-internal.h"
11#include "device-private.h"
07630cea 12#include "device-util.h"
3ffd4af2 13#include "fd-util.h"
07630cea 14#include "fileio.h"
f4f15635 15#include "fs-util.h"
07630cea
LP
16#include "hashmap.h"
17#include "macro.h"
18#include "mkdir.h"
d8b4d14d 19#include "nulstr-util.h"
6bedfcbb 20#include "parse-util.h"
07630cea 21#include "path-util.h"
07630cea 22#include "set.h"
e7f781e4 23#include "stdio-util.h"
8b43440b 24#include "string-table.h"
07630cea
LP
25#include "string-util.h"
26#include "strv.h"
27#include "strxcpyx.h"
e4de7287 28#include "tmpfile-util.h"
ee104e11 29#include "user-util.h"
57fa1d09
TG
30
31int device_add_property(sd_device *device, const char *key, const char *value) {
32 int r;
33
34 assert(device);
35 assert(key);
36
37 r = device_add_property_aux(device, key, value, false);
38 if (r < 0)
39 return r;
40
41 if (key[0] != '.') {
42 r = device_add_property_aux(device, key, value, true);
43 if (r < 0)
44 return r;
45 }
46
47 return 0;
48}
49
57fa1d09
TG
50void device_set_devlink_priority(sd_device *device, int priority) {
51 assert(device);
52
53 device->devlink_priority = priority;
54}
55
56void device_set_is_initialized(sd_device *device) {
57 assert(device);
58
59 device->is_initialized = true;
60}
61
62int device_ensure_usec_initialized(sd_device *device, sd_device *device_old) {
dc5042c0 63 usec_t when;
57fa1d09
TG
64
65 assert(device);
66
67 if (device_old && device_old->usec_initialized > 0)
dc5042c0 68 when = device_old->usec_initialized;
57fa1d09 69 else
dc5042c0 70 when = now(CLOCK_MONOTONIC);
57fa1d09 71
dc5042c0 72 return device_set_usec_initialized(device, when);
57fa1d09
TG
73}
74
57fa1d09
TG
75uint64_t device_get_properties_generation(sd_device *device) {
76 assert(device);
77
78 return device->properties_generation;
79}
80
81uint64_t device_get_tags_generation(sd_device *device) {
82 assert(device);
83
84 return device->tags_generation;
85}
86
87uint64_t device_get_devlinks_generation(sd_device *device) {
88 assert(device);
89
90 return device->devlinks_generation;
91}
92
93int device_get_devnode_mode(sd_device *device, mode_t *mode) {
94 int r;
95
96 assert(device);
57fa1d09
TG
97
98 r = device_read_db(device);
99 if (r < 0)
100 return r;
101
f5fbe71d 102 if (device->devmode == MODE_INVALID)
dcfbde3a
YW
103 return -ENOENT;
104
78ffb476
YW
105 if (mode)
106 *mode = device->devmode;
57fa1d09
TG
107
108 return 0;
109}
110
111int device_get_devnode_uid(sd_device *device, uid_t *uid) {
112 int r;
113
114 assert(device);
57fa1d09
TG
115
116 r = device_read_db(device);
117 if (r < 0)
118 return r;
119
f5fbe71d 120 if (device->devuid == UID_INVALID)
dcfbde3a
YW
121 return -ENOENT;
122
78ffb476
YW
123 if (uid)
124 *uid = device->devuid;
57fa1d09
TG
125
126 return 0;
127}
128
129static int device_set_devuid(sd_device *device, const char *uid) {
130 unsigned u;
131 int r;
132
133 assert(device);
134 assert(uid);
135
136 r = safe_atou(uid, &u);
137 if (r < 0)
138 return r;
139
140 r = device_add_property_internal(device, "DEVUID", uid);
141 if (r < 0)
142 return r;
143
144 device->devuid = u;
145
146 return 0;
147}
148
149int device_get_devnode_gid(sd_device *device, gid_t *gid) {
150 int r;
151
152 assert(device);
57fa1d09
TG
153
154 r = device_read_db(device);
155 if (r < 0)
156 return r;
157
f5fbe71d 158 if (device->devgid == GID_INVALID)
dcfbde3a
YW
159 return -ENOENT;
160
78ffb476
YW
161 if (gid)
162 *gid = device->devgid;
57fa1d09
TG
163
164 return 0;
165}
166
167static int device_set_devgid(sd_device *device, const char *gid) {
168 unsigned g;
169 int r;
170
171 assert(device);
172 assert(gid);
173
174 r = safe_atou(gid, &g);
175 if (r < 0)
176 return r;
177
178 r = device_add_property_internal(device, "DEVGID", gid);
179 if (r < 0)
180 return r;
181
182 device->devgid = g;
183
184 return 0;
185}
186
20798980 187int device_set_action(sd_device *device, sd_device_action_t a) {
5ebd3fc3
YW
188 int r;
189
190 assert(device);
20798980 191 assert(a >= 0 && a < _SD_DEVICE_ACTION_MAX);
5ebd3fc3 192
a1130022 193 r = device_add_property_internal(device, "ACTION", device_action_to_string(a));
5ebd3fc3
YW
194 if (r < 0)
195 return r;
196
197 device->action = a;
198
199 return 0;
200}
201
20798980
YW
202static int device_set_action_from_string(sd_device *device, const char *action) {
203 sd_device_action_t a;
204
205 assert(device);
206 assert(action);
207
208 a = device_action_from_string(action);
209 if (a < 0)
210 return a;
211
212 return device_set_action(device, a);
213}
214
5ebd3fc3
YW
215static int device_set_seqnum(sd_device *device, const char *str) {
216 uint64_t seqnum;
217 int r;
218
219 assert(device);
220 assert(str);
221
222 r = safe_atou64(str, &seqnum);
223 if (r < 0)
224 return r;
225 if (seqnum == 0)
226 return -EINVAL;
227
228 r = device_add_property_internal(device, "SEQNUM", str);
229 if (r < 0)
230 return r;
231
232 device->seqnum = seqnum;
233
234 return 0;
235}
236
122adcb2
LB
237static int device_set_diskseq(sd_device *device, const char *str) {
238 uint64_t diskseq;
239 int r;
240
241 assert(device);
242 assert(str);
243
244 r = safe_atou64(str, &diskseq);
245 if (r < 0)
246 return r;
247 if (diskseq == 0)
248 return -EINVAL;
249
250 r = device_add_property_internal(device, "DISKSEQ", str);
251 if (r < 0)
252 return r;
253
254 device->diskseq = diskseq;
255
256 return 0;
257}
258
401cb614 259static int device_amend(sd_device *device, const char *key, const char *value) {
57fa1d09
TG
260 int r;
261
262 assert(device);
263 assert(key);
264 assert(value);
265
266 if (streq(key, "DEVPATH")) {
267 char *path;
268
269 path = strjoina("/sys", value);
270
271 /* the caller must verify or trust this data (e.g., if it comes from the kernel) */
272 r = device_set_syspath(device, path, false);
273 if (r < 0)
c7d54dae 274 return log_device_debug_errno(device, r, "sd-device: Failed to set syspath to '%s': %m", path);
57fa1d09
TG
275 } else if (streq(key, "SUBSYSTEM")) {
276 r = device_set_subsystem(device, value);
277 if (r < 0)
c7d54dae 278 return log_device_debug_errno(device, r, "sd-device: Failed to set subsystem to '%s': %m", value);
57fa1d09
TG
279 } else if (streq(key, "DEVTYPE")) {
280 r = device_set_devtype(device, value);
281 if (r < 0)
c7d54dae 282 return log_device_debug_errno(device, r, "sd-device: Failed to set devtype to '%s': %m", value);
57fa1d09
TG
283 } else if (streq(key, "DEVNAME")) {
284 r = device_set_devname(device, value);
285 if (r < 0)
c7d54dae 286 return log_device_debug_errno(device, r, "sd-device: Failed to set devname to '%s': %m", value);
57fa1d09 287 } else if (streq(key, "USEC_INITIALIZED")) {
dc5042c0
ZJS
288 usec_t t;
289
290 r = safe_atou64(value, &t);
291 if (r < 0)
292 return log_device_debug_errno(device, r, "sd-device: Failed to parse timestamp '%s': %m", value);
293
294 r = device_set_usec_initialized(device, t);
57fa1d09 295 if (r < 0)
c7d54dae 296 return log_device_debug_errno(device, r, "sd-device: Failed to set usec-initialized to '%s': %m", value);
57fa1d09
TG
297 } else if (streq(key, "DRIVER")) {
298 r = device_set_driver(device, value);
299 if (r < 0)
c7d54dae 300 return log_device_debug_errno(device, r, "sd-device: Failed to set driver to '%s': %m", value);
57fa1d09
TG
301 } else if (streq(key, "IFINDEX")) {
302 r = device_set_ifindex(device, value);
303 if (r < 0)
c7d54dae 304 return log_device_debug_errno(device, r, "sd-device: Failed to set ifindex to '%s': %m", value);
57fa1d09
TG
305 } else if (streq(key, "DEVMODE")) {
306 r = device_set_devmode(device, value);
307 if (r < 0)
c7d54dae 308 return log_device_debug_errno(device, r, "sd-device: Failed to set devmode to '%s': %m", value);
57fa1d09
TG
309 } else if (streq(key, "DEVUID")) {
310 r = device_set_devuid(device, value);
311 if (r < 0)
c7d54dae 312 return log_device_debug_errno(device, r, "sd-device: Failed to set devuid to '%s': %m", value);
57fa1d09
TG
313 } else if (streq(key, "DEVGID")) {
314 r = device_set_devgid(device, value);
315 if (r < 0)
c7d54dae 316 return log_device_debug_errno(device, r, "sd-device: Failed to set devgid to '%s': %m", value);
5ebd3fc3 317 } else if (streq(key, "ACTION")) {
20798980 318 r = device_set_action_from_string(device, value);
5ebd3fc3
YW
319 if (r < 0)
320 return log_device_debug_errno(device, r, "sd-device: Failed to set action to '%s': %m", value);
321 } else if (streq(key, "SEQNUM")) {
322 r = device_set_seqnum(device, value);
323 if (r < 0)
324 return log_device_debug_errno(device, r, "sd-device: Failed to set SEQNUM to '%s': %m", value);
122adcb2
LB
325 } else if (streq(key, "DISKSEQ")) {
326 r = device_set_diskseq(device, value);
327 if (r < 0)
328 return log_device_debug_errno(device, r, "sd-device: Failed to set DISKSEQ to '%s': %m", value);
57fa1d09 329 } else if (streq(key, "DEVLINKS")) {
87a4d416
ZJS
330 for (const char *p = value;;) {
331 _cleanup_free_ char *word = NULL;
57fa1d09 332
31063db0
YW
333 /* udev rules may set escaped strings, and sd-device does not modify the input
334 * strings. So, it is also necessary to keep the strings received through
335 * sd-device-monitor. */
336 r = extract_first_word(&p, &word, NULL, EXTRACT_RETAIN_ESCAPE);
87a4d416
ZJS
337 if (r < 0)
338 return r;
339 if (r == 0)
340 break;
57fa1d09 341
87a4d416 342 r = device_add_devlink(device, word);
57fa1d09 343 if (r < 0)
87a4d416 344 return log_device_debug_errno(device, r, "sd-device: Failed to add devlink '%s': %m", word);
57fa1d09 345 }
e77b146f 346 } else if (STR_IN_SET(key, "TAGS", "CURRENT_TAGS")) {
87a4d416
ZJS
347 for (const char *p = value;;) {
348 _cleanup_free_ char *word = NULL;
57fa1d09 349
87a4d416
ZJS
350 r = extract_first_word(&p, &word, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
351 if (r < 0)
352 return r;
353 if (r == 0)
354 break;
57fa1d09 355
87a4d416 356 r = device_add_tag(device, word, streq(key, "CURRENT_TAGS"));
57fa1d09 357 if (r < 0)
87a4d416 358 return log_device_debug_errno(device, r, "sd-device: Failed to add tag '%s': %m", word);
57fa1d09
TG
359 }
360 } else {
361 r = device_add_property_internal(device, key, value);
362 if (r < 0)
c7d54dae 363 return log_device_debug_errno(device, r, "sd-device: Failed to add property '%s=%s': %m", key, value);
57fa1d09
TG
364 }
365
366 return 0;
367}
368
96fb82aa
LP
369static int device_append(
370 sd_device *device,
371 char *key,
372 const char **_major,
373 const char **_minor) {
374
57fa1d09
TG
375 const char *major = NULL, *minor = NULL;
376 char *value;
377 int r;
378
379 assert(device);
380 assert(key);
381 assert(_major);
382 assert(_minor);
57fa1d09
TG
383
384 value = strchr(key, '=');
9e791238
ZJS
385 if (!value)
386 return log_device_debug_errno(device, SYNTHETIC_ERRNO(EINVAL),
387 "sd-device: Not a key-value pair: '%s'", key);
57fa1d09
TG
388
389 *value = '\0';
390
391 value++;
392
393 if (streq(key, "MAJOR"))
394 major = value;
395 else if (streq(key, "MINOR"))
396 minor = value;
397 else {
401cb614 398 r = device_amend(device, key, value);
57fa1d09
TG
399 if (r < 0)
400 return r;
401 }
402
96fb82aa 403 if (major)
57fa1d09
TG
404 *_major = major;
405
96fb82aa 406 if (minor)
57fa1d09
TG
407 *_minor = minor;
408
57fa1d09
TG
409 return 0;
410}
411
412void device_seal(sd_device *device) {
413 assert(device);
414
415 device->sealed = true;
416}
417
5ebd3fc3 418static int device_verify(sd_device *device) {
e5ca293f
YW
419 int r;
420
57fa1d09
TG
421 assert(device);
422
9e791238
ZJS
423 if (!device->devpath || !device->subsystem || device->action < 0 || device->seqnum == 0)
424 return log_device_debug_errno(device, SYNTHETIC_ERRNO(EINVAL),
425 "sd-device: Device created from strv or nulstr lacks devpath, subsystem, action or seqnum.");
57fa1d09 426
e5ca293f
YW
427 if (streq(device->subsystem, "drivers")) {
428 r = device_set_drivers_subsystem(device);
429 if (r < 0)
430 return r;
431 }
432
57fa1d09
TG
433 device->sealed = true;
434
435 return 0;
436}
437
438int device_new_from_strv(sd_device **ret, char **strv) {
4afd3348 439 _cleanup_(sd_device_unrefp) sd_device *device = NULL;
57fa1d09 440 const char *major = NULL, *minor = NULL;
57fa1d09
TG
441 int r;
442
443 assert(ret);
444 assert(strv);
445
446 r = device_new_aux(&device);
447 if (r < 0)
448 return r;
449
450 STRV_FOREACH(key, strv) {
5ebd3fc3 451 r = device_append(device, *key, &major, &minor);
57fa1d09
TG
452 if (r < 0)
453 return r;
454 }
455
456 if (major) {
457 r = device_set_devnum(device, major, minor);
458 if (r < 0)
c7d54dae 459 return log_device_debug_errno(device, r, "sd-device: Failed to set devnum %s:%s: %m", major, minor);
57fa1d09
TG
460 }
461
5ebd3fc3 462 r = device_verify(device);
57fa1d09
TG
463 if (r < 0)
464 return r;
465
1cc6c93a 466 *ret = TAKE_PTR(device);
57fa1d09
TG
467
468 return 0;
469}
470
471int device_new_from_nulstr(sd_device **ret, uint8_t *nulstr, size_t len) {
4afd3348 472 _cleanup_(sd_device_unrefp) sd_device *device = NULL;
57fa1d09 473 const char *major = NULL, *minor = NULL;
57fa1d09
TG
474 int r;
475
476 assert(ret);
477 assert(nulstr);
478 assert(len);
479
480 r = device_new_aux(&device);
481 if (r < 0)
482 return r;
483
ce634c4a 484 for (size_t i = 0; i < len; ) {
57fa1d09
TG
485 char *key;
486 const char *end;
487
ce634c4a 488 key = (char*) &nulstr[i];
57fa1d09 489 end = memchr(key, '\0', len - i);
9e791238
ZJS
490 if (!end)
491 return log_device_debug_errno(device, SYNTHETIC_ERRNO(EINVAL),
492 "sd-device: Failed to parse nulstr");
493
57fa1d09
TG
494 i += end - key + 1;
495
b9cbb08e
YW
496 /* netlink messages for some devices contain an unwanted newline at the end of value.
497 * Let's drop the newline and remaining characters after the newline. */
498 truncate_nl(key);
499
5ebd3fc3 500 r = device_append(device, key, &major, &minor);
57fa1d09
TG
501 if (r < 0)
502 return r;
503 }
504
505 if (major) {
506 r = device_set_devnum(device, major, minor);
507 if (r < 0)
c7d54dae 508 return log_device_debug_errno(device, r, "sd-device: Failed to set devnum %s:%s: %m", major, minor);
57fa1d09
TG
509 }
510
5ebd3fc3 511 r = device_verify(device);
57fa1d09
TG
512 if (r < 0)
513 return r;
514
1cc6c93a 515 *ret = TAKE_PTR(device);
57fa1d09
TG
516
517 return 0;
518}
519
520static int device_update_properties_bufs(sd_device *device) {
521 const char *val, *prop;
ccc1002a
TG
522 _cleanup_free_ char **buf_strv = NULL;
523 _cleanup_free_ uint8_t *buf_nulstr = NULL;
ccc1002a 524 size_t nulstr_len = 0, num = 0, i = 0;
57fa1d09
TG
525
526 assert(device);
527
aa20f49a
TG
528 if (!device->properties_buf_outdated)
529 return 0;
530
57fa1d09
TG
531 FOREACH_DEVICE_PROPERTY(device, prop, val) {
532 size_t len = 0;
533
534 len = strlen(prop) + 1 + strlen(val);
535
319a4f4b 536 buf_nulstr = GREEDY_REALLOC0(buf_nulstr, nulstr_len + len + 2);
57fa1d09
TG
537 if (!buf_nulstr)
538 return -ENOMEM;
539
57fa1d09
TG
540 strscpyl((char *)buf_nulstr + nulstr_len, len + 1, prop, "=", val, NULL);
541 nulstr_len += len + 1;
d854ba50 542 ++num;
57fa1d09
TG
543 }
544
ccc1002a
TG
545 /* build buf_strv from buf_nulstr */
546 buf_strv = new0(char *, num + 1);
547 if (!buf_strv)
548 return -ENOMEM;
d854ba50 549
d854ba50 550 NULSTR_FOREACH(val, (char*) buf_nulstr) {
ccc1002a 551 buf_strv[i] = (char *) val;
d854ba50
MP
552 assert(i < num);
553 i++;
554 }
57fa1d09 555
f9ecfd3b 556 free_and_replace(device->properties_nulstr, buf_nulstr);
ccc1002a 557 device->properties_nulstr_len = nulstr_len;
f9ecfd3b 558 free_and_replace(device->properties_strv, buf_strv);
ccc1002a 559
57fa1d09
TG
560 device->properties_buf_outdated = false;
561
562 return 0;
563}
564
565int device_get_properties_nulstr(sd_device *device, const uint8_t **nulstr, size_t *len) {
566 int r;
567
568 assert(device);
569 assert(nulstr);
570 assert(len);
571
aa20f49a
TG
572 r = device_update_properties_bufs(device);
573 if (r < 0)
574 return r;
57fa1d09
TG
575
576 *nulstr = device->properties_nulstr;
577 *len = device->properties_nulstr_len;
578
579 return 0;
580}
581
582int device_get_properties_strv(sd_device *device, char ***strv) {
583 int r;
584
585 assert(device);
586 assert(strv);
587
588 r = device_update_properties_bufs(device);
589 if (r < 0)
590 return r;
591
592 *strv = device->properties_strv;
593
594 return 0;
595}
596
597int device_get_devlink_priority(sd_device *device, int *priority) {
598 int r;
599
600 assert(device);
601 assert(priority);
602
603 r = device_read_db(device);
604 if (r < 0)
605 return r;
606
607 *priority = device->devlink_priority;
608
609 return 0;
610}
611
e7f781e4
YW
612int device_get_watch_handle(sd_device *device) {
613 char path_wd[STRLEN("/run/udev/watch/") + DECIMAL_STR_MAX(int)];
614 _cleanup_free_ char *buf = NULL;
615 const char *id, *path_id;
616 int wd, r;
617
618 assert(device);
619
620 if (device->watch_handle >= 0)
621 return device->watch_handle;
622
623 r = device_get_device_id(device, &id);
624 if (r < 0)
625 return r;
626
627 path_id = strjoina("/run/udev/watch/", id);
628 r = readlink_malloc(path_id, &buf);
629 if (r < 0)
630 return r;
631
632 r = safe_atoi(buf, &wd);
633 if (r < 0)
634 return r;
635
636 if (wd < 0)
637 return -EBADF;
638
639 buf = mfree(buf);
640 xsprintf(path_wd, "/run/udev/watch/%d", wd);
641 r = readlink_malloc(path_wd, &buf);
642 if (r < 0)
643 return r;
644
645 if (!streq(buf, id))
646 return -EBADF;
647
648 return device->watch_handle = wd;
649}
650
651static void device_remove_watch_handle(sd_device *device) {
652 const char *id;
653 int wd;
654
655 assert(device);
656
657 /* First, remove the symlink from handle to device id. */
658 wd = device_get_watch_handle(device);
659 if (wd >= 0) {
660 char path_wd[STRLEN("/run/udev/watch/") + DECIMAL_STR_MAX(int)];
661
662 xsprintf(path_wd, "/run/udev/watch/%d", wd);
663 if (unlink(path_wd) < 0 && errno != ENOENT)
664 log_device_debug_errno(device, errno,
665 "sd-device: failed to remove %s, ignoring: %m",
666 path_wd);
667 }
668
669 /* Next, remove the symlink from device id to handle. */
670 if (device_get_device_id(device, &id) >= 0) {
671 const char *path_id;
672
673 path_id = strjoina("/run/udev/watch/", id);
674 if (unlink(path_id) < 0 && errno != ENOENT)
675 log_device_debug_errno(device, errno,
676 "sd-device: failed to remove %s, ignoring: %m",
677 path_id);
678 }
679
680 device->watch_handle = -1;
681}
682
683int device_set_watch_handle(sd_device *device, int wd) {
684 char path_wd[STRLEN("/run/udev/watch/") + DECIMAL_STR_MAX(int)];
685 const char *id, *path_id;
57fa1d09
TG
686 int r;
687
688 assert(device);
57fa1d09 689
20ec7d9e 690 if (wd >= 0 && wd == device_get_watch_handle(device))
e7f781e4
YW
691 return 0;
692
693 device_remove_watch_handle(device);
694
695 if (wd < 0)
696 /* negative wd means that the caller requests to clear saved watch handle. */
697 return 0;
698
699 r = device_get_device_id(device, &id);
57fa1d09
TG
700 if (r < 0)
701 return r;
702
e7f781e4
YW
703 path_id = strjoina("/run/udev/watch/", id);
704 xsprintf(path_wd, "/run/udev/watch/%d", wd);
705
706 r = mkdir_parents(path_wd, 0755);
707 if (r < 0)
708 return r;
709
710 if (symlink(id, path_wd) < 0)
711 return -errno;
dcfbde3a 712
e7f781e4
YW
713 if (symlink(path_wd + STRLEN("/run/udev/watch/"), path_id) < 0) {
714 r = -errno;
715 if (unlink(path_wd) < 0 && errno != ENOENT)
716 log_device_debug_errno(device, errno,
717 "sd-device: failed to remove %s, ignoring: %m",
718 path_wd);
719 return r;
720 }
721
722 device->watch_handle = wd;
57fa1d09
TG
723
724 return 0;
725}
726
e7f781e4
YW
727int device_new_from_watch_handle_at(sd_device **ret, int dirfd, int wd) {
728 char path_wd[STRLEN("/run/udev/watch/") + DECIMAL_STR_MAX(int)];
729 _cleanup_free_ char *id = NULL;
730 int r;
731
732 assert(ret);
733
734 if (wd < 0)
735 return -EBADF;
57fa1d09 736
e7f781e4
YW
737 if (dirfd >= 0) {
738 xsprintf(path_wd, "%d", wd);
739 r = readlinkat_malloc(dirfd, path_wd, &id);
740 } else {
741 xsprintf(path_wd, "/run/udev/watch/%d", wd);
742 r = readlink_malloc(path_wd, &id);
743 }
744 if (r < 0)
745 return r;
746
747 return sd_device_new_from_device_id(ret, id);
57fa1d09
TG
748}
749
750int device_rename(sd_device *device, const char *name) {
751 _cleanup_free_ char *dirname = NULL;
270384b2 752 const char *new_syspath, *interface;
57fa1d09
TG
753 int r;
754
755 assert(device);
756 assert(name);
757
758 dirname = dirname_malloc(device->syspath);
759 if (!dirname)
760 return -ENOMEM;
761
270384b2 762 new_syspath = prefix_roota(dirname, name);
57fa1d09
TG
763
764 /* the user must trust that the new name is correct */
765 r = device_set_syspath(device, new_syspath, false);
766 if (r < 0)
767 return r;
768
769 r = sd_device_get_property_value(device, "INTERFACE", &interface);
770 if (r >= 0) {
f7b1c8d1
EV
771 /* like DEVPATH_OLD, INTERFACE_OLD is not saved to the db, but only stays around for the current event */
772 r = device_add_property_internal(device, "INTERFACE_OLD", interface);
57fa1d09
TG
773 if (r < 0)
774 return r;
775
f7b1c8d1 776 r = device_add_property_internal(device, "INTERFACE", name);
57fa1d09
TG
777 if (r < 0)
778 return r;
779 } else if (r != -ENOENT)
780 return r;
781
782 return 0;
783}
784
785int device_shallow_clone(sd_device *old_device, sd_device **new_device) {
4afd3348 786 _cleanup_(sd_device_unrefp) sd_device *ret = NULL;
381f6d4b 787 const char *val;
57fa1d09
TG
788 int r;
789
790 assert(old_device);
791 assert(new_device);
792
793 r = device_new_aux(&ret);
794 if (r < 0)
795 return r;
796
797 r = device_set_syspath(ret, old_device->syspath, false);
798 if (r < 0)
799 return r;
800
df49a732
ZJS
801 (void) sd_device_get_subsystem(old_device, &val);
802 r = device_set_subsystem(ret, val);
803 if (r < 0)
804 return r;
805 if (streq_ptr(val, "drivers")) {
806 r = free_and_strdup(&ret->driver_subsystem, old_device->driver_subsystem);
2255e8ad
YW
807 if (r < 0)
808 return r;
df49a732 809 }
57fa1d09 810
381f6d4b
YW
811 /* The device may be already removed. Let's copy minimal set of information to make
812 * device_get_device_id() work without uevent file. */
57fa1d09 813
381f6d4b
YW
814 if (sd_device_get_property_value(old_device, "IFINDEX", &val) >= 0) {
815 r = device_set_ifindex(ret, val);
816 if (r < 0)
817 return r;
818 }
819
820 if (sd_device_get_property_value(old_device, "MAJOR", &val) >= 0) {
821 const char *minor = NULL;
57fa1d09 822
381f6d4b
YW
823 (void) sd_device_get_property_value(old_device, "MINOR", &minor);
824 r = device_set_devnum(ret, val, minor);
825 if (r < 0)
826 return r;
827 }
828
829 /* And then read uevent file, but ignore errors, as some devices seem to return a spurious
830 * error on read, e.g. -ENODEV, and even if ifindex or devnum is set in the above,
831 * sd_device_get_ifindex() or sd_device_get_devnum() fails. See. #19788. */
832 (void) device_read_uevent_file(ret);
833
834 *new_device = TAKE_PTR(ret);
57fa1d09
TG
835 return 0;
836}
837
838int device_clone_with_db(sd_device *old_device, sd_device **new_device) {
4afd3348 839 _cleanup_(sd_device_unrefp) sd_device *ret = NULL;
57fa1d09
TG
840 int r;
841
842 assert(old_device);
843 assert(new_device);
844
845 r = device_shallow_clone(old_device, &ret);
846 if (r < 0)
847 return r;
848
849 r = device_read_db(ret);
850 if (r < 0)
851 return r;
852
853 ret->sealed = true;
854
1cc6c93a 855 *new_device = TAKE_PTR(ret);
57fa1d09
TG
856
857 return 0;
858}
859
57fa1d09
TG
860int device_copy_properties(sd_device *device_dst, sd_device *device_src) {
861 const char *property, *value;
862 int r;
863
864 assert(device_dst);
865 assert(device_src);
866
a3ce8136
YW
867 r = device_properties_prepare(device_src);
868 if (r < 0)
869 return r;
870
90e74a66 871 ORDERED_HASHMAP_FOREACH_KEY(value, property, device_src->properties_db) {
a3ce8136
YW
872 r = device_add_property_aux(device_dst, property, value, true);
873 if (r < 0)
874 return r;
875 }
876
90e74a66 877 ORDERED_HASHMAP_FOREACH_KEY(value, property, device_src->properties) {
a3ce8136 878 r = device_add_property_aux(device_dst, property, value, false);
57fa1d09
TG
879 if (r < 0)
880 return r;
881 }
882
883 return 0;
884}
885
886void device_cleanup_tags(sd_device *device) {
887 assert(device);
888
e77b146f
LP
889 device->all_tags = set_free_free(device->all_tags);
890 device->current_tags = set_free_free(device->current_tags);
57fa1d09 891 device->property_tags_outdated = true;
313cefa1 892 device->tags_generation++;
57fa1d09
TG
893}
894
895void device_cleanup_devlinks(sd_device *device) {
896 assert(device);
897
898 set_free_free(device->devlinks);
899 device->devlinks = NULL;
900 device->property_devlinks_outdated = true;
313cefa1 901 device->devlinks_generation++;
57fa1d09
TG
902}
903
904void device_remove_tag(sd_device *device, const char *tag) {
905 assert(device);
906 assert(tag);
907
e77b146f 908 free(set_remove(device->current_tags, tag));
57fa1d09 909 device->property_tags_outdated = true;
313cefa1 910 device->tags_generation++;
57fa1d09
TG
911}
912
913static int device_tag(sd_device *device, const char *tag, bool add) {
914 const char *id;
915 char *path;
916 int r;
917
918 assert(device);
919 assert(tag);
920
fe732381 921 r = device_get_device_id(device, &id);
57fa1d09
TG
922 if (r < 0)
923 return r;
924
925 path = strjoina("/run/udev/tags/", tag, "/", id);
926
927 if (add) {
928 r = touch_file(path, true, USEC_INFINITY, UID_INVALID, GID_INVALID, 0444);
929 if (r < 0)
930 return r;
931 } else {
932 r = unlink(path);
933 if (r < 0 && errno != ENOENT)
934 return -errno;
935 }
936
937 return 0;
938}
939
940int device_tag_index(sd_device *device, sd_device *device_old, bool add) {
941 const char *tag;
942 int r = 0, k;
943
944 if (add && device_old) {
945 /* delete possible left-over tags */
946 FOREACH_DEVICE_TAG(device_old, tag) {
947 if (!sd_device_has_tag(device, tag)) {
948 k = device_tag(device_old, tag, false);
949 if (r >= 0 && k < 0)
950 r = k;
951 }
952 }
953 }
954
955 FOREACH_DEVICE_TAG(device, tag) {
956 k = device_tag(device, tag, add);
957 if (r >= 0 && k < 0)
958 r = k;
959 }
960
961 return r;
962}
963
964static bool device_has_info(sd_device *device) {
965 assert(device);
966
967 if (!set_isempty(device->devlinks))
968 return true;
969
970 if (device->devlink_priority != 0)
971 return true;
972
973 if (!ordered_hashmap_isempty(device->properties_db))
974 return true;
975
e77b146f
LP
976 if (!set_isempty(device->all_tags))
977 return true;
978
979 if (!set_isempty(device->current_tags))
57fa1d09
TG
980 return true;
981
57fa1d09
TG
982 return false;
983}
984
985void device_set_db_persist(sd_device *device) {
986 assert(device);
987
988 device->db_persist = true;
989}
990
991int device_update_db(sd_device *device) {
992 const char *id;
993 char *path;
994 _cleanup_fclose_ FILE *f = NULL;
995 _cleanup_free_ char *path_tmp = NULL;
996 bool has_info;
997 int r;
998
999 assert(device);
1000
1001 has_info = device_has_info(device);
1002
fe732381 1003 r = device_get_device_id(device, &id);
57fa1d09
TG
1004 if (r < 0)
1005 return r;
1006
1007 path = strjoina("/run/udev/data/", id);
1008
1009 /* do not store anything for otherwise empty devices */
1010 if (!has_info && major(device->devnum) == 0 && device->ifindex == 0) {
1011 r = unlink(path);
1012 if (r < 0 && errno != ENOENT)
1013 return -errno;
1014
1015 return 0;
1016 }
1017
1018 /* write a database file */
1019 r = mkdir_parents(path, 0755);
1020 if (r < 0)
1021 return r;
1022
1023 r = fopen_temporary(path, &f, &path_tmp);
1024 if (r < 0)
1025 return r;
1026
1027 /*
1028 * set 'sticky' bit to indicate that we should not clean the
1029 * database when we transition from initramfs to the real root
1030 */
827f8650
YW
1031 if (fchmod(fileno(f), device->db_persist ? 01644 : 0644) < 0) {
1032 r = -errno;
1033 goto fail;
57fa1d09
TG
1034 }
1035
1036 if (has_info) {
1037 const char *property, *value, *tag;
57fa1d09
TG
1038
1039 if (major(device->devnum) > 0) {
1040 const char *devlink;
1041
1042 FOREACH_DEVICE_DEVLINK(device, devlink)
fbd0b64f 1043 fprintf(f, "S:%s\n", devlink + STRLEN("/dev/"));
57fa1d09
TG
1044
1045 if (device->devlink_priority != 0)
1046 fprintf(f, "L:%i\n", device->devlink_priority);
57fa1d09
TG
1047 }
1048
1049 if (device->usec_initialized > 0)
1050 fprintf(f, "I:"USEC_FMT"\n", device->usec_initialized);
1051
90e74a66 1052 ORDERED_HASHMAP_FOREACH_KEY(value, property, device->properties_db)
57fa1d09
TG
1053 fprintf(f, "E:%s=%s\n", property, value);
1054
1055 FOREACH_DEVICE_TAG(device, tag)
e77b146f
LP
1056 fprintf(f, "G:%s\n", tag); /* Any tag */
1057
90e74a66 1058 SET_FOREACH(tag, device->current_tags)
e77b146f 1059 fprintf(f, "Q:%s\n", tag); /* Current tag */
58b30ada
YW
1060
1061 /* Always write the latest database version here, instead of the value stored in
1062 * device->database_version, as which may be 0. */
1063 fputs("V:" STRINGIFY(LATEST_UDEV_DATABASE_VERSION) "\n", f);
57fa1d09
TG
1064 }
1065
1066 r = fflush_and_check(f);
1067 if (r < 0)
1068 goto fail;
1069
827f8650 1070 if (rename(path_tmp, path) < 0) {
57fa1d09
TG
1071 r = -errno;
1072 goto fail;
1073 }
1074
c7d54dae
YW
1075 log_device_debug(device, "sd-device: Created %s file '%s' for '%s'", has_info ? "db" : "empty",
1076 path, device->devpath);
57fa1d09
TG
1077
1078 return 0;
1079
1080fail:
dacd6cee
LP
1081 (void) unlink(path);
1082 (void) unlink(path_tmp);
57fa1d09 1083
c7d54dae 1084 return log_device_debug_errno(device, r, "sd-device: Failed to create %s file '%s' for '%s'", has_info ? "db" : "empty", path, device->devpath);
57fa1d09
TG
1085}
1086
1087int device_delete_db(sd_device *device) {
1088 const char *id;
1089 char *path;
1090 int r;
1091
1092 assert(device);
1093
fe732381 1094 r = device_get_device_id(device, &id);
57fa1d09
TG
1095 if (r < 0)
1096 return r;
1097
1098 path = strjoina("/run/udev/data/", id);
1099
1100 r = unlink(path);
1101 if (r < 0 && errno != ENOENT)
1102 return -errno;
1103
1104 return 0;
1105}
5ebd3fc3 1106
a1130022
LP
1107static const char* const device_action_table[_SD_DEVICE_ACTION_MAX] = {
1108 [SD_DEVICE_ADD] = "add",
1109 [SD_DEVICE_REMOVE] = "remove",
1110 [SD_DEVICE_CHANGE] = "change",
1111 [SD_DEVICE_MOVE] = "move",
1112 [SD_DEVICE_ONLINE] = "online",
1113 [SD_DEVICE_OFFLINE] = "offline",
1114 [SD_DEVICE_BIND] = "bind",
1115 [SD_DEVICE_UNBIND] = "unbind",
5ebd3fc3
YW
1116};
1117
a1130022 1118DEFINE_STRING_TABLE_LOOKUP(device_action, sd_device_action_t);
9e0196b1
YW
1119
1120void dump_device_action_table(void) {
a1130022 1121 DUMP_STRING_TABLE(device_action, sd_device_action_t, _SD_DEVICE_ACTION_MAX);
9e0196b1 1122}