]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd/sd-device/device-private.c
Merge pull request #18007 from fw-strlen/ipv6_masq_and_dnat
[thirdparty/systemd.git] / src / libsystemd / sd-device / device-private.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
57fa1d09
TG
2
3#include <ctype.h>
57fa1d09 4#include <net/if.h>
07630cea 5#include <sys/types.h>
57fa1d09
TG
6
7#include "sd-device.h"
8
b5efdb8a 9#include "alloc-util.h"
57fa1d09
TG
10#include "device-internal.h"
11#include "device-private.h"
07630cea 12#include "device-util.h"
3ffd4af2 13#include "fd-util.h"
07630cea 14#include "fileio.h"
f4f15635 15#include "fs-util.h"
07630cea
LP
16#include "hashmap.h"
17#include "macro.h"
18#include "mkdir.h"
d8b4d14d 19#include "nulstr-util.h"
6bedfcbb 20#include "parse-util.h"
07630cea 21#include "path-util.h"
07630cea 22#include "set.h"
8b43440b 23#include "string-table.h"
07630cea
LP
24#include "string-util.h"
25#include "strv.h"
26#include "strxcpyx.h"
e4de7287 27#include "tmpfile-util.h"
ee104e11 28#include "user-util.h"
57fa1d09
TG
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
57fa1d09
TG
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) {
dc5042c0 62 usec_t when;
57fa1d09
TG
63
64 assert(device);
65
66 if (device_old && device_old->usec_initialized > 0)
dc5042c0 67 when = device_old->usec_initialized;
57fa1d09 68 else
dc5042c0 69 when = now(CLOCK_MONOTONIC);
57fa1d09 70
dc5042c0 71 return device_set_usec_initialized(device, when);
57fa1d09
TG
72}
73
57fa1d09
TG
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);
57fa1d09
TG
96
97 r = device_read_db(device);
98 if (r < 0)
99 return r;
100
dcfbde3a
YW
101 if (device->devmode == (mode_t) -1)
102 return -ENOENT;
103
78ffb476
YW
104 if (mode)
105 *mode = device->devmode;
57fa1d09
TG
106
107 return 0;
108}
109
110int device_get_devnode_uid(sd_device *device, uid_t *uid) {
111 int r;
112
113 assert(device);
57fa1d09
TG
114
115 r = device_read_db(device);
116 if (r < 0)
117 return r;
118
dcfbde3a
YW
119 if (device->devuid == (uid_t) -1)
120 return -ENOENT;
121
78ffb476
YW
122 if (uid)
123 *uid = device->devuid;
57fa1d09
TG
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);
57fa1d09
TG
152
153 r = device_read_db(device);
154 if (r < 0)
155 return r;
156
dcfbde3a
YW
157 if (device->devgid == (gid_t) -1)
158 return -ENOENT;
159
78ffb476
YW
160 if (gid)
161 *gid = device->devgid;
57fa1d09
TG
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
5ebd3fc3
YW
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)
7211c853 207 return a;
5ebd3fc3
YW
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
401cb614 252static int device_amend(sd_device *device, const char *key, const char *value) {
57fa1d09
TG
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)
c7d54dae 267 return log_device_debug_errno(device, r, "sd-device: Failed to set syspath to '%s': %m", path);
57fa1d09
TG
268 } else if (streq(key, "SUBSYSTEM")) {
269 r = device_set_subsystem(device, value);
270 if (r < 0)
c7d54dae 271 return log_device_debug_errno(device, r, "sd-device: Failed to set subsystem to '%s': %m", value);
57fa1d09
TG
272 } else if (streq(key, "DEVTYPE")) {
273 r = device_set_devtype(device, value);
274 if (r < 0)
c7d54dae 275 return log_device_debug_errno(device, r, "sd-device: Failed to set devtype to '%s': %m", value);
57fa1d09
TG
276 } else if (streq(key, "DEVNAME")) {
277 r = device_set_devname(device, value);
278 if (r < 0)
c7d54dae 279 return log_device_debug_errno(device, r, "sd-device: Failed to set devname to '%s': %m", value);
57fa1d09 280 } else if (streq(key, "USEC_INITIALIZED")) {
dc5042c0
ZJS
281 usec_t t;
282
283 r = safe_atou64(value, &t);
284 if (r < 0)
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);
57fa1d09 288 if (r < 0)
c7d54dae 289 return log_device_debug_errno(device, r, "sd-device: Failed to set usec-initialized to '%s': %m", value);
57fa1d09
TG
290 } else if (streq(key, "DRIVER")) {
291 r = device_set_driver(device, value);
292 if (r < 0)
c7d54dae 293 return log_device_debug_errno(device, r, "sd-device: Failed to set driver to '%s': %m", value);
57fa1d09
TG
294 } else if (streq(key, "IFINDEX")) {
295 r = device_set_ifindex(device, value);
296 if (r < 0)
c7d54dae 297 return log_device_debug_errno(device, r, "sd-device: Failed to set ifindex to '%s': %m", value);
57fa1d09
TG
298 } else if (streq(key, "DEVMODE")) {
299 r = device_set_devmode(device, value);
300 if (r < 0)
c7d54dae 301 return log_device_debug_errno(device, r, "sd-device: Failed to set devmode to '%s': %m", value);
57fa1d09
TG
302 } else if (streq(key, "DEVUID")) {
303 r = device_set_devuid(device, value);
304 if (r < 0)
c7d54dae 305 return log_device_debug_errno(device, r, "sd-device: Failed to set devuid to '%s': %m", value);
57fa1d09
TG
306 } else if (streq(key, "DEVGID")) {
307 r = device_set_devgid(device, value);
308 if (r < 0)
c7d54dae 309 return log_device_debug_errno(device, r, "sd-device: Failed to set devgid to '%s': %m", value);
5ebd3fc3
YW
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);
57fa1d09 318 } else if (streq(key, "DEVLINKS")) {
87a4d416
ZJS
319 for (const char *p = value;;) {
320 _cleanup_free_ char *word = NULL;
57fa1d09 321
31063db0
YW
322 /* udev rules may set escaped strings, and sd-device does not modify the input
323 * strings. So, it is also necessary to keep the strings received through
324 * sd-device-monitor. */
325 r = extract_first_word(&p, &word, NULL, EXTRACT_RETAIN_ESCAPE);
87a4d416
ZJS
326 if (r < 0)
327 return r;
328 if (r == 0)
329 break;
57fa1d09 330
87a4d416 331 r = device_add_devlink(device, word);
57fa1d09 332 if (r < 0)
87a4d416 333 return log_device_debug_errno(device, r, "sd-device: Failed to add devlink '%s': %m", word);
57fa1d09 334 }
e77b146f 335 } else if (STR_IN_SET(key, "TAGS", "CURRENT_TAGS")) {
87a4d416
ZJS
336 for (const char *p = value;;) {
337 _cleanup_free_ char *word = NULL;
57fa1d09 338
87a4d416
ZJS
339 r = extract_first_word(&p, &word, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
340 if (r < 0)
341 return r;
342 if (r == 0)
343 break;
57fa1d09 344
87a4d416 345 r = device_add_tag(device, word, streq(key, "CURRENT_TAGS"));
57fa1d09 346 if (r < 0)
87a4d416 347 return log_device_debug_errno(device, r, "sd-device: Failed to add tag '%s': %m", word);
57fa1d09
TG
348 }
349 } else {
350 r = device_add_property_internal(device, key, value);
351 if (r < 0)
c7d54dae 352 return log_device_debug_errno(device, r, "sd-device: Failed to add property '%s=%s': %m", key, value);
57fa1d09
TG
353 }
354
355 return 0;
356}
357
5ebd3fc3 358static int device_append(sd_device *device, char *key, const char **_major, const char **_minor) {
57fa1d09
TG
359 const char *major = NULL, *minor = NULL;
360 char *value;
361 int r;
362
363 assert(device);
364 assert(key);
365 assert(_major);
366 assert(_minor);
57fa1d09
TG
367
368 value = strchr(key, '=');
9e791238
ZJS
369 if (!value)
370 return log_device_debug_errno(device, SYNTHETIC_ERRNO(EINVAL),
371 "sd-device: Not a key-value pair: '%s'", key);
57fa1d09
TG
372
373 *value = '\0';
374
375 value++;
376
377 if (streq(key, "MAJOR"))
378 major = value;
379 else if (streq(key, "MINOR"))
380 minor = value;
381 else {
401cb614 382 r = device_amend(device, key, value);
57fa1d09
TG
383 if (r < 0)
384 return r;
385 }
386
387 if (major != 0)
388 *_major = major;
389
390 if (minor != 0)
391 *_minor = minor;
392
57fa1d09
TG
393 return 0;
394}
395
396void device_seal(sd_device *device) {
397 assert(device);
398
399 device->sealed = true;
400}
401
5ebd3fc3 402static int device_verify(sd_device *device) {
57fa1d09
TG
403 assert(device);
404
9e791238
ZJS
405 if (!device->devpath || !device->subsystem || device->action < 0 || device->seqnum == 0)
406 return log_device_debug_errno(device, SYNTHETIC_ERRNO(EINVAL),
407 "sd-device: Device created from strv or nulstr lacks devpath, subsystem, action or seqnum.");
57fa1d09
TG
408
409 device->sealed = true;
410
411 return 0;
412}
413
414int device_new_from_strv(sd_device **ret, char **strv) {
4afd3348 415 _cleanup_(sd_device_unrefp) sd_device *device = NULL;
57fa1d09
TG
416 char **key;
417 const char *major = NULL, *minor = NULL;
57fa1d09
TG
418 int r;
419
420 assert(ret);
421 assert(strv);
422
423 r = device_new_aux(&device);
424 if (r < 0)
425 return r;
426
427 STRV_FOREACH(key, strv) {
5ebd3fc3 428 r = device_append(device, *key, &major, &minor);
57fa1d09
TG
429 if (r < 0)
430 return r;
431 }
432
433 if (major) {
434 r = device_set_devnum(device, major, minor);
435 if (r < 0)
c7d54dae 436 return log_device_debug_errno(device, r, "sd-device: Failed to set devnum %s:%s: %m", major, minor);
57fa1d09
TG
437 }
438
5ebd3fc3 439 r = device_verify(device);
57fa1d09
TG
440 if (r < 0)
441 return r;
442
1cc6c93a 443 *ret = TAKE_PTR(device);
57fa1d09
TG
444
445 return 0;
446}
447
448int device_new_from_nulstr(sd_device **ret, uint8_t *nulstr, size_t len) {
4afd3348 449 _cleanup_(sd_device_unrefp) sd_device *device = NULL;
57fa1d09 450 const char *major = NULL, *minor = NULL;
57fa1d09
TG
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
ce634c4a 461 for (size_t i = 0; i < len; ) {
57fa1d09
TG
462 char *key;
463 const char *end;
464
ce634c4a 465 key = (char*) &nulstr[i];
57fa1d09 466 end = memchr(key, '\0', len - i);
9e791238
ZJS
467 if (!end)
468 return log_device_debug_errno(device, SYNTHETIC_ERRNO(EINVAL),
469 "sd-device: Failed to parse nulstr");
470
57fa1d09
TG
471 i += end - key + 1;
472
b9cbb08e
YW
473 /* netlink messages for some devices contain an unwanted newline at the end of value.
474 * Let's drop the newline and remaining characters after the newline. */
475 truncate_nl(key);
476
5ebd3fc3 477 r = device_append(device, key, &major, &minor);
57fa1d09
TG
478 if (r < 0)
479 return r;
480 }
481
482 if (major) {
483 r = device_set_devnum(device, major, minor);
484 if (r < 0)
c7d54dae 485 return log_device_debug_errno(device, r, "sd-device: Failed to set devnum %s:%s: %m", major, minor);
57fa1d09
TG
486 }
487
5ebd3fc3 488 r = device_verify(device);
57fa1d09
TG
489 if (r < 0)
490 return r;
491
1cc6c93a 492 *ret = TAKE_PTR(device);
57fa1d09
TG
493
494 return 0;
495}
496
497static int device_update_properties_bufs(sd_device *device) {
498 const char *val, *prop;
ccc1002a
TG
499 _cleanup_free_ char **buf_strv = NULL;
500 _cleanup_free_ uint8_t *buf_nulstr = NULL;
d854ba50 501 size_t allocated_nulstr = 0;
ccc1002a 502 size_t nulstr_len = 0, num = 0, i = 0;
57fa1d09
TG
503
504 assert(device);
505
aa20f49a
TG
506 if (!device->properties_buf_outdated)
507 return 0;
508
57fa1d09
TG
509 FOREACH_DEVICE_PROPERTY(device, prop, val) {
510 size_t len = 0;
511
512 len = strlen(prop) + 1 + strlen(val);
513
514 buf_nulstr = GREEDY_REALLOC0(buf_nulstr, allocated_nulstr, nulstr_len + len + 2);
515 if (!buf_nulstr)
516 return -ENOMEM;
517
57fa1d09
TG
518 strscpyl((char *)buf_nulstr + nulstr_len, len + 1, prop, "=", val, NULL);
519 nulstr_len += len + 1;
d854ba50 520 ++num;
57fa1d09
TG
521 }
522
ccc1002a
TG
523 /* build buf_strv from buf_nulstr */
524 buf_strv = new0(char *, num + 1);
525 if (!buf_strv)
526 return -ENOMEM;
d854ba50 527
d854ba50 528 NULSTR_FOREACH(val, (char*) buf_nulstr) {
ccc1002a 529 buf_strv[i] = (char *) val;
d854ba50
MP
530 assert(i < num);
531 i++;
532 }
57fa1d09 533
f9ecfd3b 534 free_and_replace(device->properties_nulstr, buf_nulstr);
ccc1002a 535 device->properties_nulstr_len = nulstr_len;
f9ecfd3b 536 free_and_replace(device->properties_strv, buf_strv);
ccc1002a 537
57fa1d09
TG
538 device->properties_buf_outdated = false;
539
540 return 0;
541}
542
543int device_get_properties_nulstr(sd_device *device, const uint8_t **nulstr, size_t *len) {
544 int r;
545
546 assert(device);
547 assert(nulstr);
548 assert(len);
549
aa20f49a
TG
550 r = device_update_properties_bufs(device);
551 if (r < 0)
552 return r;
57fa1d09
TG
553
554 *nulstr = device->properties_nulstr;
555 *len = device->properties_nulstr_len;
556
557 return 0;
558}
559
560int device_get_properties_strv(sd_device *device, char ***strv) {
561 int r;
562
563 assert(device);
564 assert(strv);
565
566 r = device_update_properties_bufs(device);
567 if (r < 0)
568 return r;
569
570 *strv = device->properties_strv;
571
572 return 0;
573}
574
575int device_get_devlink_priority(sd_device *device, int *priority) {
576 int r;
577
578 assert(device);
579 assert(priority);
580
581 r = device_read_db(device);
582 if (r < 0)
583 return r;
584
585 *priority = device->devlink_priority;
586
587 return 0;
588}
589
590int device_get_watch_handle(sd_device *device, int *handle) {
591 int r;
592
593 assert(device);
57fa1d09
TG
594
595 r = device_read_db(device);
596 if (r < 0)
597 return r;
598
dcfbde3a
YW
599 if (device->watch_handle < 0)
600 return -ENOENT;
601
78ffb476
YW
602 if (handle)
603 *handle = device->watch_handle;
57fa1d09
TG
604
605 return 0;
606}
607
608void device_set_watch_handle(sd_device *device, int handle) {
609 assert(device);
610
611 device->watch_handle = handle;
612}
613
614int device_rename(sd_device *device, const char *name) {
615 _cleanup_free_ char *dirname = NULL;
270384b2 616 const char *new_syspath, *interface;
57fa1d09
TG
617 int r;
618
619 assert(device);
620 assert(name);
621
622 dirname = dirname_malloc(device->syspath);
623 if (!dirname)
624 return -ENOMEM;
625
270384b2 626 new_syspath = prefix_roota(dirname, name);
57fa1d09
TG
627
628 /* the user must trust that the new name is correct */
629 r = device_set_syspath(device, new_syspath, false);
630 if (r < 0)
631 return r;
632
633 r = sd_device_get_property_value(device, "INTERFACE", &interface);
634 if (r >= 0) {
f7b1c8d1
EV
635 /* like DEVPATH_OLD, INTERFACE_OLD is not saved to the db, but only stays around for the current event */
636 r = device_add_property_internal(device, "INTERFACE_OLD", interface);
57fa1d09
TG
637 if (r < 0)
638 return r;
639
f7b1c8d1 640 r = device_add_property_internal(device, "INTERFACE", name);
57fa1d09
TG
641 if (r < 0)
642 return r;
643 } else if (r != -ENOENT)
644 return r;
645
646 return 0;
647}
648
649int device_shallow_clone(sd_device *old_device, sd_device **new_device) {
4afd3348 650 _cleanup_(sd_device_unrefp) sd_device *ret = NULL;
57fa1d09
TG
651 int r;
652
653 assert(old_device);
654 assert(new_device);
655
656 r = device_new_aux(&ret);
657 if (r < 0)
658 return r;
659
660 r = device_set_syspath(ret, old_device->syspath, false);
661 if (r < 0)
662 return r;
663
664 r = device_set_subsystem(ret, old_device->subsystem);
665 if (r < 0)
666 return r;
667
668 ret->devnum = old_device->devnum;
669
1cc6c93a 670 *new_device = TAKE_PTR(ret);
57fa1d09
TG
671
672 return 0;
673}
674
675int device_clone_with_db(sd_device *old_device, sd_device **new_device) {
4afd3348 676 _cleanup_(sd_device_unrefp) sd_device *ret = NULL;
57fa1d09
TG
677 int r;
678
679 assert(old_device);
680 assert(new_device);
681
682 r = device_shallow_clone(old_device, &ret);
683 if (r < 0)
684 return r;
685
686 r = device_read_db(ret);
687 if (r < 0)
688 return r;
689
690 ret->sealed = true;
691
1cc6c93a 692 *new_device = TAKE_PTR(ret);
57fa1d09
TG
693
694 return 0;
695}
696
697int device_new_from_synthetic_event(sd_device **new_device, const char *syspath, const char *action) {
4afd3348 698 _cleanup_(sd_device_unrefp) sd_device *ret = NULL;
57fa1d09
TG
699 int r;
700
701 assert(new_device);
702 assert(syspath);
703 assert(action);
704
705 r = sd_device_new_from_syspath(&ret, syspath);
706 if (r < 0)
707 return r;
708
709 r = device_read_uevent_file(ret);
710 if (r < 0)
711 return r;
712
5ebd3fc3 713 r = device_set_action(ret, action);
57fa1d09
TG
714 if (r < 0)
715 return r;
716
1cc6c93a 717 *new_device = TAKE_PTR(ret);
57fa1d09
TG
718
719 return 0;
720}
721
ad5944d7
YW
722int device_new_from_stat_rdev(sd_device **ret, const struct stat *st) {
723 char type;
724
725 assert(ret);
726 assert(st);
727
728 if (S_ISBLK(st->st_mode))
729 type = 'b';
730 else if (S_ISCHR(st->st_mode))
731 type = 'c';
732 else
733 return -ENOTTY;
734
735 return sd_device_new_from_devnum(ret, type, st->st_rdev);
736}
737
57fa1d09
TG
738int device_copy_properties(sd_device *device_dst, sd_device *device_src) {
739 const char *property, *value;
740 int r;
741
742 assert(device_dst);
743 assert(device_src);
744
a3ce8136
YW
745 r = device_properties_prepare(device_src);
746 if (r < 0)
747 return r;
748
90e74a66 749 ORDERED_HASHMAP_FOREACH_KEY(value, property, device_src->properties_db) {
a3ce8136
YW
750 r = device_add_property_aux(device_dst, property, value, true);
751 if (r < 0)
752 return r;
753 }
754
90e74a66 755 ORDERED_HASHMAP_FOREACH_KEY(value, property, device_src->properties) {
a3ce8136 756 r = device_add_property_aux(device_dst, property, value, false);
57fa1d09
TG
757 if (r < 0)
758 return r;
759 }
760
761 return 0;
762}
763
764void device_cleanup_tags(sd_device *device) {
765 assert(device);
766
e77b146f
LP
767 device->all_tags = set_free_free(device->all_tags);
768 device->current_tags = set_free_free(device->current_tags);
57fa1d09 769 device->property_tags_outdated = true;
313cefa1 770 device->tags_generation++;
57fa1d09
TG
771}
772
773void device_cleanup_devlinks(sd_device *device) {
774 assert(device);
775
776 set_free_free(device->devlinks);
777 device->devlinks = NULL;
778 device->property_devlinks_outdated = true;
313cefa1 779 device->devlinks_generation++;
57fa1d09
TG
780}
781
782void device_remove_tag(sd_device *device, const char *tag) {
783 assert(device);
784 assert(tag);
785
e77b146f 786 free(set_remove(device->current_tags, tag));
57fa1d09 787 device->property_tags_outdated = true;
313cefa1 788 device->tags_generation++;
57fa1d09
TG
789}
790
791static int device_tag(sd_device *device, const char *tag, bool add) {
792 const char *id;
793 char *path;
794 int r;
795
796 assert(device);
797 assert(tag);
798
799 r = device_get_id_filename(device, &id);
800 if (r < 0)
801 return r;
802
803 path = strjoina("/run/udev/tags/", tag, "/", id);
804
805 if (add) {
806 r = touch_file(path, true, USEC_INFINITY, UID_INVALID, GID_INVALID, 0444);
807 if (r < 0)
808 return r;
809 } else {
810 r = unlink(path);
811 if (r < 0 && errno != ENOENT)
812 return -errno;
813 }
814
815 return 0;
816}
817
818int device_tag_index(sd_device *device, sd_device *device_old, bool add) {
819 const char *tag;
820 int r = 0, k;
821
822 if (add && device_old) {
823 /* delete possible left-over tags */
824 FOREACH_DEVICE_TAG(device_old, tag) {
825 if (!sd_device_has_tag(device, tag)) {
826 k = device_tag(device_old, tag, false);
827 if (r >= 0 && k < 0)
828 r = k;
829 }
830 }
831 }
832
833 FOREACH_DEVICE_TAG(device, tag) {
834 k = device_tag(device, tag, add);
835 if (r >= 0 && k < 0)
836 r = k;
837 }
838
839 return r;
840}
841
842static bool device_has_info(sd_device *device) {
843 assert(device);
844
845 if (!set_isempty(device->devlinks))
846 return true;
847
848 if (device->devlink_priority != 0)
849 return true;
850
851 if (!ordered_hashmap_isempty(device->properties_db))
852 return true;
853
e77b146f
LP
854 if (!set_isempty(device->all_tags))
855 return true;
856
857 if (!set_isempty(device->current_tags))
57fa1d09
TG
858 return true;
859
860 if (device->watch_handle >= 0)
861 return true;
862
863 return false;
864}
865
866void device_set_db_persist(sd_device *device) {
867 assert(device);
868
869 device->db_persist = true;
870}
871
872int device_update_db(sd_device *device) {
873 const char *id;
874 char *path;
875 _cleanup_fclose_ FILE *f = NULL;
876 _cleanup_free_ char *path_tmp = NULL;
877 bool has_info;
878 int r;
879
880 assert(device);
881
882 has_info = device_has_info(device);
883
884 r = device_get_id_filename(device, &id);
885 if (r < 0)
886 return r;
887
888 path = strjoina("/run/udev/data/", id);
889
890 /* do not store anything for otherwise empty devices */
891 if (!has_info && major(device->devnum) == 0 && device->ifindex == 0) {
892 r = unlink(path);
893 if (r < 0 && errno != ENOENT)
894 return -errno;
895
896 return 0;
897 }
898
899 /* write a database file */
900 r = mkdir_parents(path, 0755);
901 if (r < 0)
902 return r;
903
904 r = fopen_temporary(path, &f, &path_tmp);
905 if (r < 0)
906 return r;
907
908 /*
909 * set 'sticky' bit to indicate that we should not clean the
910 * database when we transition from initramfs to the real root
911 */
912 if (device->db_persist) {
913 r = fchmod(fileno(f), 01644);
914 if (r < 0) {
915 r = -errno;
916 goto fail;
917 }
918 } else {
919 r = fchmod(fileno(f), 0644);
920 if (r < 0) {
921 r = -errno;
922 goto fail;
923 }
924 }
925
926 if (has_info) {
927 const char *property, *value, *tag;
57fa1d09
TG
928
929 if (major(device->devnum) > 0) {
930 const char *devlink;
931
932 FOREACH_DEVICE_DEVLINK(device, devlink)
fbd0b64f 933 fprintf(f, "S:%s\n", devlink + STRLEN("/dev/"));
57fa1d09
TG
934
935 if (device->devlink_priority != 0)
936 fprintf(f, "L:%i\n", device->devlink_priority);
937
938 if (device->watch_handle >= 0)
939 fprintf(f, "W:%i\n", device->watch_handle);
940 }
941
942 if (device->usec_initialized > 0)
943 fprintf(f, "I:"USEC_FMT"\n", device->usec_initialized);
944
90e74a66 945 ORDERED_HASHMAP_FOREACH_KEY(value, property, device->properties_db)
57fa1d09
TG
946 fprintf(f, "E:%s=%s\n", property, value);
947
948 FOREACH_DEVICE_TAG(device, tag)
e77b146f
LP
949 fprintf(f, "G:%s\n", tag); /* Any tag */
950
90e74a66 951 SET_FOREACH(tag, device->current_tags)
e77b146f 952 fprintf(f, "Q:%s\n", tag); /* Current tag */
58b30ada
YW
953
954 /* Always write the latest database version here, instead of the value stored in
955 * device->database_version, as which may be 0. */
956 fputs("V:" STRINGIFY(LATEST_UDEV_DATABASE_VERSION) "\n", f);
57fa1d09
TG
957 }
958
959 r = fflush_and_check(f);
960 if (r < 0)
961 goto fail;
962
963 r = rename(path_tmp, path);
964 if (r < 0) {
965 r = -errno;
966 goto fail;
967 }
968
c7d54dae
YW
969 log_device_debug(device, "sd-device: Created %s file '%s' for '%s'", has_info ? "db" : "empty",
970 path, device->devpath);
57fa1d09
TG
971
972 return 0;
973
974fail:
dacd6cee
LP
975 (void) unlink(path);
976 (void) unlink(path_tmp);
57fa1d09 977
c7d54dae 978 return log_device_debug_errno(device, r, "sd-device: Failed to create %s file '%s' for '%s'", has_info ? "db" : "empty", path, device->devpath);
57fa1d09
TG
979}
980
981int device_delete_db(sd_device *device) {
982 const char *id;
983 char *path;
984 int r;
985
986 assert(device);
987
988 r = device_get_id_filename(device, &id);
989 if (r < 0)
990 return r;
991
992 path = strjoina("/run/udev/data/", id);
993
994 r = unlink(path);
995 if (r < 0 && errno != ENOENT)
996 return -errno;
997
998 return 0;
999}
5ebd3fc3
YW
1000
1001static const char* const device_action_table[_DEVICE_ACTION_MAX] = {
1002 [DEVICE_ACTION_ADD] = "add",
1003 [DEVICE_ACTION_REMOVE] = "remove",
1004 [DEVICE_ACTION_CHANGE] = "change",
1005 [DEVICE_ACTION_MOVE] = "move",
1006 [DEVICE_ACTION_ONLINE] = "online",
1007 [DEVICE_ACTION_OFFLINE] = "offline",
1008 [DEVICE_ACTION_BIND] = "bind",
1009 [DEVICE_ACTION_UNBIND] = "unbind",
1010};
1011
1012DEFINE_STRING_TABLE_LOOKUP(device_action, DeviceAction);
9e0196b1
YW
1013
1014void dump_device_action_table(void) {
1015 DUMP_STRING_TABLE(device_action, DeviceAction, _DEVICE_ACTION_MAX);
1016}