]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd/sd-device/device-private.c
Merge pull request #7608 from poettering/more-news-v236
[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
f9ecfd3b 681 free_and_replace(device->properties_nulstr, buf_nulstr);
ccc1002a 682 device->properties_nulstr_len = nulstr_len;
f9ecfd3b 683 free_and_replace(device->properties_strv, buf_strv);
ccc1002a 684
57fa1d09
TG
685 device->properties_buf_outdated = false;
686
687 return 0;
688}
689
690int device_get_properties_nulstr(sd_device *device, const uint8_t **nulstr, size_t *len) {
691 int r;
692
693 assert(device);
694 assert(nulstr);
695 assert(len);
696
aa20f49a
TG
697 r = device_update_properties_bufs(device);
698 if (r < 0)
699 return r;
57fa1d09
TG
700
701 *nulstr = device->properties_nulstr;
702 *len = device->properties_nulstr_len;
703
704 return 0;
705}
706
707int device_get_properties_strv(sd_device *device, char ***strv) {
708 int r;
709
710 assert(device);
711 assert(strv);
712
713 r = device_update_properties_bufs(device);
714 if (r < 0)
715 return r;
716
717 *strv = device->properties_strv;
718
719 return 0;
720}
721
722int device_get_devlink_priority(sd_device *device, int *priority) {
723 int r;
724
725 assert(device);
726 assert(priority);
727
728 r = device_read_db(device);
729 if (r < 0)
730 return r;
731
732 *priority = device->devlink_priority;
733
734 return 0;
735}
736
737int device_get_watch_handle(sd_device *device, int *handle) {
738 int r;
739
740 assert(device);
741 assert(handle);
742
743 r = device_read_db(device);
744 if (r < 0)
745 return r;
746
747 *handle = device->watch_handle;
748
749 return 0;
750}
751
752void device_set_watch_handle(sd_device *device, int handle) {
753 assert(device);
754
755 device->watch_handle = handle;
756}
757
758int device_rename(sd_device *device, const char *name) {
759 _cleanup_free_ char *dirname = NULL;
760 char *new_syspath;
761 const char *interface;
762 int r;
763
764 assert(device);
765 assert(name);
766
767 dirname = dirname_malloc(device->syspath);
768 if (!dirname)
769 return -ENOMEM;
770
771 new_syspath = strjoina(dirname, "/", name);
772
773 /* the user must trust that the new name is correct */
774 r = device_set_syspath(device, new_syspath, false);
775 if (r < 0)
776 return r;
777
778 r = sd_device_get_property_value(device, "INTERFACE", &interface);
779 if (r >= 0) {
f7b1c8d1
EV
780 /* like DEVPATH_OLD, INTERFACE_OLD is not saved to the db, but only stays around for the current event */
781 r = device_add_property_internal(device, "INTERFACE_OLD", interface);
57fa1d09
TG
782 if (r < 0)
783 return r;
784
f7b1c8d1 785 r = device_add_property_internal(device, "INTERFACE", name);
57fa1d09
TG
786 if (r < 0)
787 return r;
788 } else if (r != -ENOENT)
789 return r;
790
791 return 0;
792}
793
794int device_shallow_clone(sd_device *old_device, sd_device **new_device) {
4afd3348 795 _cleanup_(sd_device_unrefp) sd_device *ret = NULL;
57fa1d09
TG
796 int r;
797
798 assert(old_device);
799 assert(new_device);
800
801 r = device_new_aux(&ret);
802 if (r < 0)
803 return r;
804
805 r = device_set_syspath(ret, old_device->syspath, false);
806 if (r < 0)
807 return r;
808
809 r = device_set_subsystem(ret, old_device->subsystem);
810 if (r < 0)
811 return r;
812
813 ret->devnum = old_device->devnum;
814
815 *new_device = ret;
816 ret = NULL;
817
818 return 0;
819}
820
821int device_clone_with_db(sd_device *old_device, sd_device **new_device) {
4afd3348 822 _cleanup_(sd_device_unrefp) sd_device *ret = NULL;
57fa1d09
TG
823 int r;
824
825 assert(old_device);
826 assert(new_device);
827
828 r = device_shallow_clone(old_device, &ret);
829 if (r < 0)
830 return r;
831
832 r = device_read_db(ret);
833 if (r < 0)
834 return r;
835
836 ret->sealed = true;
837
838 *new_device = ret;
839 ret = NULL;
840
841 return 0;
842}
843
844int device_new_from_synthetic_event(sd_device **new_device, const char *syspath, const char *action) {
4afd3348 845 _cleanup_(sd_device_unrefp) sd_device *ret = NULL;
57fa1d09
TG
846 int r;
847
848 assert(new_device);
849 assert(syspath);
850 assert(action);
851
852 r = sd_device_new_from_syspath(&ret, syspath);
853 if (r < 0)
854 return r;
855
856 r = device_read_uevent_file(ret);
857 if (r < 0)
858 return r;
859
860 r = device_add_property_internal(ret, "ACTION", action);
861 if (r < 0)
862 return r;
863
864 *new_device = ret;
865 ret = NULL;
866
867 return 0;
868}
869
870int device_copy_properties(sd_device *device_dst, sd_device *device_src) {
871 const char *property, *value;
872 int r;
873
874 assert(device_dst);
875 assert(device_src);
876
877 FOREACH_DEVICE_PROPERTY(device_src, property, value) {
878 r = device_add_property(device_dst, property, value);
879 if (r < 0)
880 return r;
881 }
882
883 return 0;
884}
885
886void device_cleanup_tags(sd_device *device) {
887 assert(device);
888
889 set_free_free(device->tags);
890 device->tags = NULL;
891 device->property_tags_outdated = true;
313cefa1 892 device->tags_generation++;
57fa1d09
TG
893}
894
895void device_cleanup_devlinks(sd_device *device) {
896 assert(device);
897
898 set_free_free(device->devlinks);
899 device->devlinks = NULL;
900 device->property_devlinks_outdated = true;
313cefa1 901 device->devlinks_generation++;
57fa1d09
TG
902}
903
904void device_remove_tag(sd_device *device, const char *tag) {
905 assert(device);
906 assert(tag);
907
908 free(set_remove(device->tags, tag));
909 device->property_tags_outdated = true;
313cefa1 910 device->tags_generation++;
57fa1d09
TG
911}
912
913static int device_tag(sd_device *device, const char *tag, bool add) {
914 const char *id;
915 char *path;
916 int r;
917
918 assert(device);
919 assert(tag);
920
921 r = device_get_id_filename(device, &id);
922 if (r < 0)
923 return r;
924
925 path = strjoina("/run/udev/tags/", tag, "/", id);
926
927 if (add) {
928 r = touch_file(path, true, USEC_INFINITY, UID_INVALID, GID_INVALID, 0444);
929 if (r < 0)
930 return r;
931 } else {
932 r = unlink(path);
933 if (r < 0 && errno != ENOENT)
934 return -errno;
935 }
936
937 return 0;
938}
939
940int device_tag_index(sd_device *device, sd_device *device_old, bool add) {
941 const char *tag;
942 int r = 0, k;
943
944 if (add && device_old) {
945 /* delete possible left-over tags */
946 FOREACH_DEVICE_TAG(device_old, tag) {
947 if (!sd_device_has_tag(device, tag)) {
948 k = device_tag(device_old, tag, false);
949 if (r >= 0 && k < 0)
950 r = k;
951 }
952 }
953 }
954
955 FOREACH_DEVICE_TAG(device, tag) {
956 k = device_tag(device, tag, add);
957 if (r >= 0 && k < 0)
958 r = k;
959 }
960
961 return r;
962}
963
964static bool device_has_info(sd_device *device) {
965 assert(device);
966
967 if (!set_isempty(device->devlinks))
968 return true;
969
970 if (device->devlink_priority != 0)
971 return true;
972
973 if (!ordered_hashmap_isempty(device->properties_db))
974 return true;
975
976 if (!set_isempty(device->tags))
977 return true;
978
979 if (device->watch_handle >= 0)
980 return true;
981
982 return false;
983}
984
985void device_set_db_persist(sd_device *device) {
986 assert(device);
987
988 device->db_persist = true;
989}
990
991int device_update_db(sd_device *device) {
992 const char *id;
993 char *path;
994 _cleanup_fclose_ FILE *f = NULL;
995 _cleanup_free_ char *path_tmp = NULL;
996 bool has_info;
997 int r;
998
999 assert(device);
1000
1001 has_info = device_has_info(device);
1002
1003 r = device_get_id_filename(device, &id);
1004 if (r < 0)
1005 return r;
1006
1007 path = strjoina("/run/udev/data/", id);
1008
1009 /* do not store anything for otherwise empty devices */
1010 if (!has_info && major(device->devnum) == 0 && device->ifindex == 0) {
1011 r = unlink(path);
1012 if (r < 0 && errno != ENOENT)
1013 return -errno;
1014
1015 return 0;
1016 }
1017
1018 /* write a database file */
1019 r = mkdir_parents(path, 0755);
1020 if (r < 0)
1021 return r;
1022
1023 r = fopen_temporary(path, &f, &path_tmp);
1024 if (r < 0)
1025 return r;
1026
1027 /*
1028 * set 'sticky' bit to indicate that we should not clean the
1029 * database when we transition from initramfs to the real root
1030 */
1031 if (device->db_persist) {
1032 r = fchmod(fileno(f), 01644);
1033 if (r < 0) {
1034 r = -errno;
1035 goto fail;
1036 }
1037 } else {
1038 r = fchmod(fileno(f), 0644);
1039 if (r < 0) {
1040 r = -errno;
1041 goto fail;
1042 }
1043 }
1044
1045 if (has_info) {
1046 const char *property, *value, *tag;
1047 Iterator i;
1048
1049 if (major(device->devnum) > 0) {
1050 const char *devlink;
1051
1052 FOREACH_DEVICE_DEVLINK(device, devlink)
fbd0b64f 1053 fprintf(f, "S:%s\n", devlink + STRLEN("/dev/"));
57fa1d09
TG
1054
1055 if (device->devlink_priority != 0)
1056 fprintf(f, "L:%i\n", device->devlink_priority);
1057
1058 if (device->watch_handle >= 0)
1059 fprintf(f, "W:%i\n", device->watch_handle);
1060 }
1061
1062 if (device->usec_initialized > 0)
1063 fprintf(f, "I:"USEC_FMT"\n", device->usec_initialized);
1064
1065 ORDERED_HASHMAP_FOREACH_KEY(value, property, device->properties_db, i)
1066 fprintf(f, "E:%s=%s\n", property, value);
1067
1068 FOREACH_DEVICE_TAG(device, tag)
1069 fprintf(f, "G:%s\n", tag);
1070 }
1071
1072 r = fflush_and_check(f);
1073 if (r < 0)
1074 goto fail;
1075
1076 r = rename(path_tmp, path);
1077 if (r < 0) {
1078 r = -errno;
1079 goto fail;
1080 }
1081
1082 log_debug("created %s file '%s' for '%s'", has_info ? "db" : "empty",
1083 path, device->devpath);
1084
1085 return 0;
1086
1087fail:
dacd6cee
LP
1088 (void) unlink(path);
1089 (void) unlink(path_tmp);
57fa1d09 1090
dacd6cee 1091 return log_error_errno(r, "failed to create %s file '%s' for '%s'", has_info ? "db" : "empty", path, device->devpath);
57fa1d09
TG
1092}
1093
1094int device_delete_db(sd_device *device) {
1095 const char *id;
1096 char *path;
1097 int r;
1098
1099 assert(device);
1100
1101 r = device_get_id_filename(device, &id);
1102 if (r < 0)
1103 return r;
1104
1105 path = strjoina("/run/udev/data/", id);
1106
1107 r = unlink(path);
1108 if (r < 0 && errno != ENOENT)
1109 return -errno;
1110
1111 return 0;
1112}
107f2e25
TG
1113
1114int device_read_db_force(sd_device *device) {
1115 assert(device);
1116
1117 return device_read_db_aux(device, true);
1118}