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