]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd/sd-device/device-private.c
udev: make udev_watch_end() noop when device does not have devname
[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
f5fbe71d 101 if (device->devmode == MODE_INVALID)
dcfbde3a
YW
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
f5fbe71d 119 if (device->devuid == UID_INVALID)
dcfbde3a
YW
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
f5fbe71d 157 if (device->devgid == GID_INVALID)
dcfbde3a
YW
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 186static int device_set_action(sd_device *device, const char *action) {
a1130022 187 sd_device_action_t a;
5ebd3fc3
YW
188 int r;
189
190 assert(device);
191 assert(action);
192
193 a = device_action_from_string(action);
194 if (a < 0)
7211c853 195 return a;
5ebd3fc3 196
a1130022 197 r = device_add_property_internal(device, "ACTION", device_action_to_string(a));
5ebd3fc3
YW
198 if (r < 0)
199 return r;
200
201 device->action = a;
202
203 return 0;
204}
205
5ebd3fc3
YW
206static int device_set_seqnum(sd_device *device, const char *str) {
207 uint64_t seqnum;
208 int r;
209
210 assert(device);
211 assert(str);
212
213 r = safe_atou64(str, &seqnum);
214 if (r < 0)
215 return r;
216 if (seqnum == 0)
217 return -EINVAL;
218
219 r = device_add_property_internal(device, "SEQNUM", str);
220 if (r < 0)
221 return r;
222
223 device->seqnum = seqnum;
224
225 return 0;
226}
227
401cb614 228static int device_amend(sd_device *device, const char *key, const char *value) {
57fa1d09
TG
229 int r;
230
231 assert(device);
232 assert(key);
233 assert(value);
234
235 if (streq(key, "DEVPATH")) {
236 char *path;
237
238 path = strjoina("/sys", value);
239
240 /* the caller must verify or trust this data (e.g., if it comes from the kernel) */
241 r = device_set_syspath(device, path, false);
242 if (r < 0)
c7d54dae 243 return log_device_debug_errno(device, r, "sd-device: Failed to set syspath to '%s': %m", path);
57fa1d09
TG
244 } else if (streq(key, "SUBSYSTEM")) {
245 r = device_set_subsystem(device, value);
246 if (r < 0)
c7d54dae 247 return log_device_debug_errno(device, r, "sd-device: Failed to set subsystem to '%s': %m", value);
57fa1d09
TG
248 } else if (streq(key, "DEVTYPE")) {
249 r = device_set_devtype(device, value);
250 if (r < 0)
c7d54dae 251 return log_device_debug_errno(device, r, "sd-device: Failed to set devtype to '%s': %m", value);
57fa1d09
TG
252 } else if (streq(key, "DEVNAME")) {
253 r = device_set_devname(device, value);
254 if (r < 0)
c7d54dae 255 return log_device_debug_errno(device, r, "sd-device: Failed to set devname to '%s': %m", value);
57fa1d09 256 } else if (streq(key, "USEC_INITIALIZED")) {
dc5042c0
ZJS
257 usec_t t;
258
259 r = safe_atou64(value, &t);
260 if (r < 0)
261 return log_device_debug_errno(device, r, "sd-device: Failed to parse timestamp '%s': %m", value);
262
263 r = device_set_usec_initialized(device, t);
57fa1d09 264 if (r < 0)
c7d54dae 265 return log_device_debug_errno(device, r, "sd-device: Failed to set usec-initialized to '%s': %m", value);
57fa1d09
TG
266 } else if (streq(key, "DRIVER")) {
267 r = device_set_driver(device, value);
268 if (r < 0)
c7d54dae 269 return log_device_debug_errno(device, r, "sd-device: Failed to set driver to '%s': %m", value);
57fa1d09
TG
270 } else if (streq(key, "IFINDEX")) {
271 r = device_set_ifindex(device, value);
272 if (r < 0)
c7d54dae 273 return log_device_debug_errno(device, r, "sd-device: Failed to set ifindex to '%s': %m", value);
57fa1d09
TG
274 } else if (streq(key, "DEVMODE")) {
275 r = device_set_devmode(device, value);
276 if (r < 0)
c7d54dae 277 return log_device_debug_errno(device, r, "sd-device: Failed to set devmode to '%s': %m", value);
57fa1d09
TG
278 } else if (streq(key, "DEVUID")) {
279 r = device_set_devuid(device, value);
280 if (r < 0)
c7d54dae 281 return log_device_debug_errno(device, r, "sd-device: Failed to set devuid to '%s': %m", value);
57fa1d09
TG
282 } else if (streq(key, "DEVGID")) {
283 r = device_set_devgid(device, value);
284 if (r < 0)
c7d54dae 285 return log_device_debug_errno(device, r, "sd-device: Failed to set devgid to '%s': %m", value);
5ebd3fc3
YW
286 } else if (streq(key, "ACTION")) {
287 r = device_set_action(device, value);
288 if (r < 0)
289 return log_device_debug_errno(device, r, "sd-device: Failed to set action to '%s': %m", value);
290 } else if (streq(key, "SEQNUM")) {
291 r = device_set_seqnum(device, value);
292 if (r < 0)
293 return log_device_debug_errno(device, r, "sd-device: Failed to set SEQNUM to '%s': %m", value);
57fa1d09 294 } else if (streq(key, "DEVLINKS")) {
87a4d416
ZJS
295 for (const char *p = value;;) {
296 _cleanup_free_ char *word = NULL;
57fa1d09 297
31063db0
YW
298 /* udev rules may set escaped strings, and sd-device does not modify the input
299 * strings. So, it is also necessary to keep the strings received through
300 * sd-device-monitor. */
301 r = extract_first_word(&p, &word, NULL, EXTRACT_RETAIN_ESCAPE);
87a4d416
ZJS
302 if (r < 0)
303 return r;
304 if (r == 0)
305 break;
57fa1d09 306
87a4d416 307 r = device_add_devlink(device, word);
57fa1d09 308 if (r < 0)
87a4d416 309 return log_device_debug_errno(device, r, "sd-device: Failed to add devlink '%s': %m", word);
57fa1d09 310 }
e77b146f 311 } else if (STR_IN_SET(key, "TAGS", "CURRENT_TAGS")) {
87a4d416
ZJS
312 for (const char *p = value;;) {
313 _cleanup_free_ char *word = NULL;
57fa1d09 314
87a4d416
ZJS
315 r = extract_first_word(&p, &word, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
316 if (r < 0)
317 return r;
318 if (r == 0)
319 break;
57fa1d09 320
87a4d416 321 r = device_add_tag(device, word, streq(key, "CURRENT_TAGS"));
57fa1d09 322 if (r < 0)
87a4d416 323 return log_device_debug_errno(device, r, "sd-device: Failed to add tag '%s': %m", word);
57fa1d09
TG
324 }
325 } else {
326 r = device_add_property_internal(device, key, value);
327 if (r < 0)
c7d54dae 328 return log_device_debug_errno(device, r, "sd-device: Failed to add property '%s=%s': %m", key, value);
57fa1d09
TG
329 }
330
331 return 0;
332}
333
96fb82aa
LP
334static int device_append(
335 sd_device *device,
336 char *key,
337 const char **_major,
338 const char **_minor) {
339
57fa1d09
TG
340 const char *major = NULL, *minor = NULL;
341 char *value;
342 int r;
343
344 assert(device);
345 assert(key);
346 assert(_major);
347 assert(_minor);
57fa1d09
TG
348
349 value = strchr(key, '=');
9e791238
ZJS
350 if (!value)
351 return log_device_debug_errno(device, SYNTHETIC_ERRNO(EINVAL),
352 "sd-device: Not a key-value pair: '%s'", key);
57fa1d09
TG
353
354 *value = '\0';
355
356 value++;
357
358 if (streq(key, "MAJOR"))
359 major = value;
360 else if (streq(key, "MINOR"))
361 minor = value;
362 else {
401cb614 363 r = device_amend(device, key, value);
57fa1d09
TG
364 if (r < 0)
365 return r;
366 }
367
96fb82aa 368 if (major)
57fa1d09
TG
369 *_major = major;
370
96fb82aa 371 if (minor)
57fa1d09
TG
372 *_minor = minor;
373
57fa1d09
TG
374 return 0;
375}
376
377void device_seal(sd_device *device) {
378 assert(device);
379
380 device->sealed = true;
381}
382
5ebd3fc3 383static int device_verify(sd_device *device) {
57fa1d09
TG
384 assert(device);
385
9e791238
ZJS
386 if (!device->devpath || !device->subsystem || device->action < 0 || device->seqnum == 0)
387 return log_device_debug_errno(device, SYNTHETIC_ERRNO(EINVAL),
388 "sd-device: Device created from strv or nulstr lacks devpath, subsystem, action or seqnum.");
57fa1d09
TG
389
390 device->sealed = true;
391
392 return 0;
393}
394
395int device_new_from_strv(sd_device **ret, char **strv) {
4afd3348 396 _cleanup_(sd_device_unrefp) sd_device *device = NULL;
57fa1d09
TG
397 char **key;
398 const char *major = NULL, *minor = NULL;
57fa1d09
TG
399 int r;
400
401 assert(ret);
402 assert(strv);
403
404 r = device_new_aux(&device);
405 if (r < 0)
406 return r;
407
408 STRV_FOREACH(key, strv) {
5ebd3fc3 409 r = device_append(device, *key, &major, &minor);
57fa1d09
TG
410 if (r < 0)
411 return r;
412 }
413
414 if (major) {
415 r = device_set_devnum(device, major, minor);
416 if (r < 0)
c7d54dae 417 return log_device_debug_errno(device, r, "sd-device: Failed to set devnum %s:%s: %m", major, minor);
57fa1d09
TG
418 }
419
5ebd3fc3 420 r = device_verify(device);
57fa1d09
TG
421 if (r < 0)
422 return r;
423
1cc6c93a 424 *ret = TAKE_PTR(device);
57fa1d09
TG
425
426 return 0;
427}
428
429int device_new_from_nulstr(sd_device **ret, uint8_t *nulstr, size_t len) {
4afd3348 430 _cleanup_(sd_device_unrefp) sd_device *device = NULL;
57fa1d09 431 const char *major = NULL, *minor = NULL;
57fa1d09
TG
432 int r;
433
434 assert(ret);
435 assert(nulstr);
436 assert(len);
437
438 r = device_new_aux(&device);
439 if (r < 0)
440 return r;
441
ce634c4a 442 for (size_t i = 0; i < len; ) {
57fa1d09
TG
443 char *key;
444 const char *end;
445
ce634c4a 446 key = (char*) &nulstr[i];
57fa1d09 447 end = memchr(key, '\0', len - i);
9e791238
ZJS
448 if (!end)
449 return log_device_debug_errno(device, SYNTHETIC_ERRNO(EINVAL),
450 "sd-device: Failed to parse nulstr");
451
57fa1d09
TG
452 i += end - key + 1;
453
b9cbb08e
YW
454 /* netlink messages for some devices contain an unwanted newline at the end of value.
455 * Let's drop the newline and remaining characters after the newline. */
456 truncate_nl(key);
457
5ebd3fc3 458 r = device_append(device, key, &major, &minor);
57fa1d09
TG
459 if (r < 0)
460 return r;
461 }
462
463 if (major) {
464 r = device_set_devnum(device, major, minor);
465 if (r < 0)
c7d54dae 466 return log_device_debug_errno(device, r, "sd-device: Failed to set devnum %s:%s: %m", major, minor);
57fa1d09
TG
467 }
468
5ebd3fc3 469 r = device_verify(device);
57fa1d09
TG
470 if (r < 0)
471 return r;
472
1cc6c93a 473 *ret = TAKE_PTR(device);
57fa1d09
TG
474
475 return 0;
476}
477
478static int device_update_properties_bufs(sd_device *device) {
479 const char *val, *prop;
ccc1002a
TG
480 _cleanup_free_ char **buf_strv = NULL;
481 _cleanup_free_ uint8_t *buf_nulstr = NULL;
d854ba50 482 size_t allocated_nulstr = 0;
ccc1002a 483 size_t nulstr_len = 0, num = 0, i = 0;
57fa1d09
TG
484
485 assert(device);
486
aa20f49a
TG
487 if (!device->properties_buf_outdated)
488 return 0;
489
57fa1d09
TG
490 FOREACH_DEVICE_PROPERTY(device, prop, val) {
491 size_t len = 0;
492
493 len = strlen(prop) + 1 + strlen(val);
494
495 buf_nulstr = GREEDY_REALLOC0(buf_nulstr, allocated_nulstr, nulstr_len + len + 2);
496 if (!buf_nulstr)
497 return -ENOMEM;
498
57fa1d09
TG
499 strscpyl((char *)buf_nulstr + nulstr_len, len + 1, prop, "=", val, NULL);
500 nulstr_len += len + 1;
d854ba50 501 ++num;
57fa1d09
TG
502 }
503
ccc1002a
TG
504 /* build buf_strv from buf_nulstr */
505 buf_strv = new0(char *, num + 1);
506 if (!buf_strv)
507 return -ENOMEM;
d854ba50 508
d854ba50 509 NULSTR_FOREACH(val, (char*) buf_nulstr) {
ccc1002a 510 buf_strv[i] = (char *) val;
d854ba50
MP
511 assert(i < num);
512 i++;
513 }
57fa1d09 514
f9ecfd3b 515 free_and_replace(device->properties_nulstr, buf_nulstr);
ccc1002a 516 device->properties_nulstr_len = nulstr_len;
f9ecfd3b 517 free_and_replace(device->properties_strv, buf_strv);
ccc1002a 518
57fa1d09
TG
519 device->properties_buf_outdated = false;
520
521 return 0;
522}
523
524int device_get_properties_nulstr(sd_device *device, const uint8_t **nulstr, size_t *len) {
525 int r;
526
527 assert(device);
528 assert(nulstr);
529 assert(len);
530
aa20f49a
TG
531 r = device_update_properties_bufs(device);
532 if (r < 0)
533 return r;
57fa1d09
TG
534
535 *nulstr = device->properties_nulstr;
536 *len = device->properties_nulstr_len;
537
538 return 0;
539}
540
541int device_get_properties_strv(sd_device *device, char ***strv) {
542 int r;
543
544 assert(device);
545 assert(strv);
546
547 r = device_update_properties_bufs(device);
548 if (r < 0)
549 return r;
550
551 *strv = device->properties_strv;
552
553 return 0;
554}
555
556int device_get_devlink_priority(sd_device *device, int *priority) {
557 int r;
558
559 assert(device);
560 assert(priority);
561
562 r = device_read_db(device);
563 if (r < 0)
564 return r;
565
566 *priority = device->devlink_priority;
567
568 return 0;
569}
570
571int device_get_watch_handle(sd_device *device, int *handle) {
572 int r;
573
574 assert(device);
57fa1d09
TG
575
576 r = device_read_db(device);
577 if (r < 0)
578 return r;
579
dcfbde3a
YW
580 if (device->watch_handle < 0)
581 return -ENOENT;
582
78ffb476
YW
583 if (handle)
584 *handle = device->watch_handle;
57fa1d09
TG
585
586 return 0;
587}
588
589void device_set_watch_handle(sd_device *device, int handle) {
590 assert(device);
591
592 device->watch_handle = handle;
593}
594
595int device_rename(sd_device *device, const char *name) {
596 _cleanup_free_ char *dirname = NULL;
270384b2 597 const char *new_syspath, *interface;
57fa1d09
TG
598 int r;
599
600 assert(device);
601 assert(name);
602
603 dirname = dirname_malloc(device->syspath);
604 if (!dirname)
605 return -ENOMEM;
606
270384b2 607 new_syspath = prefix_roota(dirname, name);
57fa1d09
TG
608
609 /* the user must trust that the new name is correct */
610 r = device_set_syspath(device, new_syspath, false);
611 if (r < 0)
612 return r;
613
614 r = sd_device_get_property_value(device, "INTERFACE", &interface);
615 if (r >= 0) {
f7b1c8d1
EV
616 /* like DEVPATH_OLD, INTERFACE_OLD is not saved to the db, but only stays around for the current event */
617 r = device_add_property_internal(device, "INTERFACE_OLD", interface);
57fa1d09
TG
618 if (r < 0)
619 return r;
620
f7b1c8d1 621 r = device_add_property_internal(device, "INTERFACE", name);
57fa1d09
TG
622 if (r < 0)
623 return r;
624 } else if (r != -ENOENT)
625 return r;
626
627 return 0;
628}
629
630int device_shallow_clone(sd_device *old_device, sd_device **new_device) {
4afd3348 631 _cleanup_(sd_device_unrefp) sd_device *ret = NULL;
57fa1d09
TG
632 int r;
633
634 assert(old_device);
635 assert(new_device);
636
637 r = device_new_aux(&ret);
638 if (r < 0)
639 return r;
640
641 r = device_set_syspath(ret, old_device->syspath, false);
642 if (r < 0)
643 return r;
644
645 r = device_set_subsystem(ret, old_device->subsystem);
646 if (r < 0)
647 return r;
648
649 ret->devnum = old_device->devnum;
650
1cc6c93a 651 *new_device = TAKE_PTR(ret);
57fa1d09
TG
652
653 return 0;
654}
655
656int device_clone_with_db(sd_device *old_device, sd_device **new_device) {
4afd3348 657 _cleanup_(sd_device_unrefp) sd_device *ret = NULL;
57fa1d09
TG
658 int r;
659
660 assert(old_device);
661 assert(new_device);
662
663 r = device_shallow_clone(old_device, &ret);
664 if (r < 0)
665 return r;
666
667 r = device_read_db(ret);
668 if (r < 0)
669 return r;
670
671 ret->sealed = true;
672
1cc6c93a 673 *new_device = TAKE_PTR(ret);
57fa1d09
TG
674
675 return 0;
676}
677
678int device_new_from_synthetic_event(sd_device **new_device, const char *syspath, const char *action) {
4afd3348 679 _cleanup_(sd_device_unrefp) sd_device *ret = NULL;
57fa1d09
TG
680 int r;
681
682 assert(new_device);
683 assert(syspath);
684 assert(action);
685
686 r = sd_device_new_from_syspath(&ret, syspath);
687 if (r < 0)
688 return r;
689
690 r = device_read_uevent_file(ret);
691 if (r < 0)
692 return r;
693
5ebd3fc3 694 r = device_set_action(ret, action);
57fa1d09
TG
695 if (r < 0)
696 return r;
697
1cc6c93a 698 *new_device = TAKE_PTR(ret);
57fa1d09
TG
699
700 return 0;
701}
702
703int device_copy_properties(sd_device *device_dst, sd_device *device_src) {
704 const char *property, *value;
705 int r;
706
707 assert(device_dst);
708 assert(device_src);
709
a3ce8136
YW
710 r = device_properties_prepare(device_src);
711 if (r < 0)
712 return r;
713
90e74a66 714 ORDERED_HASHMAP_FOREACH_KEY(value, property, device_src->properties_db) {
a3ce8136
YW
715 r = device_add_property_aux(device_dst, property, value, true);
716 if (r < 0)
717 return r;
718 }
719
90e74a66 720 ORDERED_HASHMAP_FOREACH_KEY(value, property, device_src->properties) {
a3ce8136 721 r = device_add_property_aux(device_dst, property, value, false);
57fa1d09
TG
722 if (r < 0)
723 return r;
724 }
725
726 return 0;
727}
728
729void device_cleanup_tags(sd_device *device) {
730 assert(device);
731
e77b146f
LP
732 device->all_tags = set_free_free(device->all_tags);
733 device->current_tags = set_free_free(device->current_tags);
57fa1d09 734 device->property_tags_outdated = true;
313cefa1 735 device->tags_generation++;
57fa1d09
TG
736}
737
738void device_cleanup_devlinks(sd_device *device) {
739 assert(device);
740
741 set_free_free(device->devlinks);
742 device->devlinks = NULL;
743 device->property_devlinks_outdated = true;
313cefa1 744 device->devlinks_generation++;
57fa1d09
TG
745}
746
747void device_remove_tag(sd_device *device, const char *tag) {
748 assert(device);
749 assert(tag);
750
e77b146f 751 free(set_remove(device->current_tags, tag));
57fa1d09 752 device->property_tags_outdated = true;
313cefa1 753 device->tags_generation++;
57fa1d09
TG
754}
755
756static int device_tag(sd_device *device, const char *tag, bool add) {
757 const char *id;
758 char *path;
759 int r;
760
761 assert(device);
762 assert(tag);
763
fe732381 764 r = device_get_device_id(device, &id);
57fa1d09
TG
765 if (r < 0)
766 return r;
767
768 path = strjoina("/run/udev/tags/", tag, "/", id);
769
770 if (add) {
771 r = touch_file(path, true, USEC_INFINITY, UID_INVALID, GID_INVALID, 0444);
772 if (r < 0)
773 return r;
774 } else {
775 r = unlink(path);
776 if (r < 0 && errno != ENOENT)
777 return -errno;
778 }
779
780 return 0;
781}
782
783int device_tag_index(sd_device *device, sd_device *device_old, bool add) {
784 const char *tag;
785 int r = 0, k;
786
787 if (add && device_old) {
788 /* delete possible left-over tags */
789 FOREACH_DEVICE_TAG(device_old, tag) {
790 if (!sd_device_has_tag(device, tag)) {
791 k = device_tag(device_old, tag, false);
792 if (r >= 0 && k < 0)
793 r = k;
794 }
795 }
796 }
797
798 FOREACH_DEVICE_TAG(device, tag) {
799 k = device_tag(device, tag, add);
800 if (r >= 0 && k < 0)
801 r = k;
802 }
803
804 return r;
805}
806
807static bool device_has_info(sd_device *device) {
808 assert(device);
809
810 if (!set_isempty(device->devlinks))
811 return true;
812
813 if (device->devlink_priority != 0)
814 return true;
815
816 if (!ordered_hashmap_isempty(device->properties_db))
817 return true;
818
e77b146f
LP
819 if (!set_isempty(device->all_tags))
820 return true;
821
822 if (!set_isempty(device->current_tags))
57fa1d09
TG
823 return true;
824
825 if (device->watch_handle >= 0)
826 return true;
827
828 return false;
829}
830
831void device_set_db_persist(sd_device *device) {
832 assert(device);
833
834 device->db_persist = true;
835}
836
837int device_update_db(sd_device *device) {
838 const char *id;
839 char *path;
840 _cleanup_fclose_ FILE *f = NULL;
841 _cleanup_free_ char *path_tmp = NULL;
842 bool has_info;
843 int r;
844
845 assert(device);
846
847 has_info = device_has_info(device);
848
fe732381 849 r = device_get_device_id(device, &id);
57fa1d09
TG
850 if (r < 0)
851 return r;
852
853 path = strjoina("/run/udev/data/", id);
854
855 /* do not store anything for otherwise empty devices */
856 if (!has_info && major(device->devnum) == 0 && device->ifindex == 0) {
857 r = unlink(path);
858 if (r < 0 && errno != ENOENT)
859 return -errno;
860
861 return 0;
862 }
863
864 /* write a database file */
865 r = mkdir_parents(path, 0755);
866 if (r < 0)
867 return r;
868
869 r = fopen_temporary(path, &f, &path_tmp);
870 if (r < 0)
871 return r;
872
873 /*
874 * set 'sticky' bit to indicate that we should not clean the
875 * database when we transition from initramfs to the real root
876 */
877 if (device->db_persist) {
878 r = fchmod(fileno(f), 01644);
879 if (r < 0) {
880 r = -errno;
881 goto fail;
882 }
883 } else {
884 r = fchmod(fileno(f), 0644);
885 if (r < 0) {
886 r = -errno;
887 goto fail;
888 }
889 }
890
891 if (has_info) {
892 const char *property, *value, *tag;
57fa1d09
TG
893
894 if (major(device->devnum) > 0) {
895 const char *devlink;
896
897 FOREACH_DEVICE_DEVLINK(device, devlink)
fbd0b64f 898 fprintf(f, "S:%s\n", devlink + STRLEN("/dev/"));
57fa1d09
TG
899
900 if (device->devlink_priority != 0)
901 fprintf(f, "L:%i\n", device->devlink_priority);
902
903 if (device->watch_handle >= 0)
904 fprintf(f, "W:%i\n", device->watch_handle);
905 }
906
907 if (device->usec_initialized > 0)
908 fprintf(f, "I:"USEC_FMT"\n", device->usec_initialized);
909
90e74a66 910 ORDERED_HASHMAP_FOREACH_KEY(value, property, device->properties_db)
57fa1d09
TG
911 fprintf(f, "E:%s=%s\n", property, value);
912
913 FOREACH_DEVICE_TAG(device, tag)
e77b146f
LP
914 fprintf(f, "G:%s\n", tag); /* Any tag */
915
90e74a66 916 SET_FOREACH(tag, device->current_tags)
e77b146f 917 fprintf(f, "Q:%s\n", tag); /* Current tag */
58b30ada
YW
918
919 /* Always write the latest database version here, instead of the value stored in
920 * device->database_version, as which may be 0. */
921 fputs("V:" STRINGIFY(LATEST_UDEV_DATABASE_VERSION) "\n", f);
57fa1d09
TG
922 }
923
924 r = fflush_and_check(f);
925 if (r < 0)
926 goto fail;
927
928 r = rename(path_tmp, path);
929 if (r < 0) {
930 r = -errno;
931 goto fail;
932 }
933
c7d54dae
YW
934 log_device_debug(device, "sd-device: Created %s file '%s' for '%s'", has_info ? "db" : "empty",
935 path, device->devpath);
57fa1d09
TG
936
937 return 0;
938
939fail:
dacd6cee
LP
940 (void) unlink(path);
941 (void) unlink(path_tmp);
57fa1d09 942
c7d54dae 943 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
944}
945
946int device_delete_db(sd_device *device) {
947 const char *id;
948 char *path;
949 int r;
950
951 assert(device);
952
fe732381 953 r = device_get_device_id(device, &id);
57fa1d09
TG
954 if (r < 0)
955 return r;
956
957 path = strjoina("/run/udev/data/", id);
958
959 r = unlink(path);
960 if (r < 0 && errno != ENOENT)
961 return -errno;
962
963 return 0;
964}
5ebd3fc3 965
a1130022
LP
966static const char* const device_action_table[_SD_DEVICE_ACTION_MAX] = {
967 [SD_DEVICE_ADD] = "add",
968 [SD_DEVICE_REMOVE] = "remove",
969 [SD_DEVICE_CHANGE] = "change",
970 [SD_DEVICE_MOVE] = "move",
971 [SD_DEVICE_ONLINE] = "online",
972 [SD_DEVICE_OFFLINE] = "offline",
973 [SD_DEVICE_BIND] = "bind",
974 [SD_DEVICE_UNBIND] = "unbind",
5ebd3fc3
YW
975};
976
a1130022 977DEFINE_STRING_TABLE_LOOKUP(device_action, sd_device_action_t);
9e0196b1
YW
978
979void dump_device_action_table(void) {
a1130022 980 DUMP_STRING_TABLE(device_action, sd_device_action_t, _SD_DEVICE_ACTION_MAX);
9e0196b1 981}