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