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