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