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