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