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