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