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