]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd/sd-device/device-private.c
ci: enable arm64 runner for build/unit jobs
[thirdparty/systemd.git] / src / libsystemd / sd-device / device-private.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
57fa1d09 2
5cdf13c7
DDM
3#include <sys/stat.h>
4#include <sys/sysmacros.h>
5#include <unistd.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"
5cdf13c7 13#include "extract-word.h"
3ffd4af2 14#include "fd-util.h"
07630cea 15#include "fileio.h"
f4f15635 16#include "fs-util.h"
07630cea 17#include "hashmap.h"
07630cea 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"
5cdf13c7 27#include "time-util.h"
e4de7287 28#include "tmpfile-util.h"
ee104e11 29#include "user-util.h"
57fa1d09
TG
30
31int device_add_property(sd_device *device, const char *key, const char *value) {
32 int r;
33
34 assert(device);
35 assert(key);
36
37 r = device_add_property_aux(device, key, value, false);
38 if (r < 0)
39 return r;
40
41 if (key[0] != '.') {
42 r = device_add_property_aux(device, key, value, true);
43 if (r < 0)
44 return r;
45 }
46
47 return 0;
48}
49
71978a79
YW
50int device_add_propertyf(sd_device *device, const char *key, const char *format, ...) {
51 _cleanup_free_ char *value = NULL;
52 va_list ap;
53 int r;
54
55 assert(device);
56 assert(key);
57
58 if (!format)
59 return device_add_property(device, key, NULL);
60
61 va_start(ap, format);
62 r = vasprintf(&value, format, ap);
63 va_end(ap);
64
65 if (r < 0)
66 return -ENOMEM;
67
68 return device_add_property(device, key, value);
69}
70
57fa1d09
TG
71void device_set_devlink_priority(sd_device *device, int priority) {
72 assert(device);
73
74 device->devlink_priority = priority;
75}
76
77void device_set_is_initialized(sd_device *device) {
78 assert(device);
79
80 device->is_initialized = true;
81}
82
83int device_ensure_usec_initialized(sd_device *device, sd_device *device_old) {
dc5042c0 84 usec_t when;
57fa1d09
TG
85
86 assert(device);
87
88 if (device_old && device_old->usec_initialized > 0)
dc5042c0 89 when = device_old->usec_initialized;
57fa1d09 90 else
dc5042c0 91 when = now(CLOCK_MONOTONIC);
57fa1d09 92
dc5042c0 93 return device_set_usec_initialized(device, when);
57fa1d09
TG
94}
95
57fa1d09
TG
96uint64_t device_get_properties_generation(sd_device *device) {
97 assert(device);
98
99 return device->properties_generation;
100}
101
102uint64_t device_get_tags_generation(sd_device *device) {
103 assert(device);
104
105 return device->tags_generation;
106}
107
108uint64_t device_get_devlinks_generation(sd_device *device) {
109 assert(device);
110
111 return device->devlinks_generation;
112}
113
d82827a1 114int device_get_devnode_mode(sd_device *device, mode_t *ret) {
57fa1d09
TG
115 int r;
116
117 assert(device);
57fa1d09 118
640f8e9c
YW
119 r = device_read_uevent_file(device);
120 if (r < 0)
121 return r;
122
57fa1d09
TG
123 r = device_read_db(device);
124 if (r < 0)
125 return r;
126
f5fbe71d 127 if (device->devmode == MODE_INVALID)
dcfbde3a
YW
128 return -ENOENT;
129
d82827a1
YW
130 if (ret)
131 *ret = device->devmode;
57fa1d09
TG
132
133 return 0;
134}
135
d82827a1 136int device_get_devnode_uid(sd_device *device, uid_t *ret) {
57fa1d09
TG
137 int r;
138
139 assert(device);
57fa1d09 140
640f8e9c
YW
141 r = device_read_uevent_file(device);
142 if (r < 0)
143 return r;
144
57fa1d09
TG
145 r = device_read_db(device);
146 if (r < 0)
147 return r;
148
f5fbe71d 149 if (device->devuid == UID_INVALID)
dcfbde3a
YW
150 return -ENOENT;
151
d82827a1
YW
152 if (ret)
153 *ret = device->devuid;
57fa1d09
TG
154
155 return 0;
156}
157
640f8e9c 158int device_set_devuid(sd_device *device, const char *uid) {
c77c1cc2 159 uid_t u;
57fa1d09
TG
160 int r;
161
162 assert(device);
163 assert(uid);
164
c77c1cc2 165 r = parse_uid(uid, &u);
57fa1d09
TG
166 if (r < 0)
167 return r;
168
169 r = device_add_property_internal(device, "DEVUID", uid);
170 if (r < 0)
171 return r;
172
173 device->devuid = u;
174
175 return 0;
176}
177
d82827a1 178int device_get_devnode_gid(sd_device *device, gid_t *ret) {
57fa1d09
TG
179 int r;
180
181 assert(device);
57fa1d09 182
640f8e9c
YW
183 r = device_read_uevent_file(device);
184 if (r < 0)
185 return r;
186
57fa1d09
TG
187 r = device_read_db(device);
188 if (r < 0)
189 return r;
190
f5fbe71d 191 if (device->devgid == GID_INVALID)
dcfbde3a
YW
192 return -ENOENT;
193
d82827a1
YW
194 if (ret)
195 *ret = device->devgid;
57fa1d09
TG
196
197 return 0;
198}
199
640f8e9c 200int device_set_devgid(sd_device *device, const char *gid) {
c77c1cc2 201 gid_t g;
57fa1d09
TG
202 int r;
203
204 assert(device);
205 assert(gid);
206
c77c1cc2 207 r = parse_gid(gid, &g);
57fa1d09
TG
208 if (r < 0)
209 return r;
210
211 r = device_add_property_internal(device, "DEVGID", gid);
212 if (r < 0)
213 return r;
214
215 device->devgid = g;
216
217 return 0;
218}
219
20798980 220int device_set_action(sd_device *device, sd_device_action_t a) {
5ebd3fc3
YW
221 int r;
222
223 assert(device);
20798980 224 assert(a >= 0 && a < _SD_DEVICE_ACTION_MAX);
5ebd3fc3 225
a1130022 226 r = device_add_property_internal(device, "ACTION", device_action_to_string(a));
5ebd3fc3
YW
227 if (r < 0)
228 return r;
229
230 device->action = a;
231
232 return 0;
233}
234
20798980
YW
235static int device_set_action_from_string(sd_device *device, const char *action) {
236 sd_device_action_t a;
237
238 assert(device);
239 assert(action);
240
241 a = device_action_from_string(action);
242 if (a < 0)
243 return a;
244
245 return device_set_action(device, a);
246}
247
5ebd3fc3
YW
248static int device_set_seqnum(sd_device *device, const char *str) {
249 uint64_t seqnum;
250 int r;
251
252 assert(device);
253 assert(str);
254
255 r = safe_atou64(str, &seqnum);
256 if (r < 0)
257 return r;
258 if (seqnum == 0)
259 return -EINVAL;
260
261 r = device_add_property_internal(device, "SEQNUM", str);
262 if (r < 0)
263 return r;
264
265 device->seqnum = seqnum;
266
267 return 0;
268}
269
401cb614 270static int device_amend(sd_device *device, const char *key, const char *value) {
57fa1d09
TG
271 int r;
272
273 assert(device);
274 assert(key);
275 assert(value);
276
277 if (streq(key, "DEVPATH")) {
278 char *path;
279
280 path = strjoina("/sys", value);
281
282 /* the caller must verify or trust this data (e.g., if it comes from the kernel) */
283 r = device_set_syspath(device, path, false);
284 if (r < 0)
c7d54dae 285 return log_device_debug_errno(device, r, "sd-device: Failed to set syspath to '%s': %m", path);
57fa1d09
TG
286 } else if (streq(key, "SUBSYSTEM")) {
287 r = device_set_subsystem(device, value);
288 if (r < 0)
c7d54dae 289 return log_device_debug_errno(device, r, "sd-device: Failed to set subsystem to '%s': %m", value);
57fa1d09
TG
290 } else if (streq(key, "DEVTYPE")) {
291 r = device_set_devtype(device, value);
292 if (r < 0)
c7d54dae 293 return log_device_debug_errno(device, r, "sd-device: Failed to set devtype to '%s': %m", value);
57fa1d09
TG
294 } else if (streq(key, "DEVNAME")) {
295 r = device_set_devname(device, value);
296 if (r < 0)
c7d54dae 297 return log_device_debug_errno(device, r, "sd-device: Failed to set devname to '%s': %m", value);
57fa1d09 298 } else if (streq(key, "USEC_INITIALIZED")) {
dc5042c0
ZJS
299 usec_t t;
300
301 r = safe_atou64(value, &t);
302 if (r < 0)
303 return log_device_debug_errno(device, r, "sd-device: Failed to parse timestamp '%s': %m", value);
304
305 r = device_set_usec_initialized(device, t);
57fa1d09 306 if (r < 0)
c7d54dae 307 return log_device_debug_errno(device, r, "sd-device: Failed to set usec-initialized to '%s': %m", value);
57fa1d09
TG
308 } else if (streq(key, "DRIVER")) {
309 r = device_set_driver(device, value);
310 if (r < 0)
c7d54dae 311 return log_device_debug_errno(device, r, "sd-device: Failed to set driver to '%s': %m", value);
57fa1d09
TG
312 } else if (streq(key, "IFINDEX")) {
313 r = device_set_ifindex(device, value);
314 if (r < 0)
c7d54dae 315 return log_device_debug_errno(device, r, "sd-device: Failed to set ifindex to '%s': %m", value);
57fa1d09
TG
316 } else if (streq(key, "DEVMODE")) {
317 r = device_set_devmode(device, value);
318 if (r < 0)
c7d54dae 319 return log_device_debug_errno(device, r, "sd-device: Failed to set devmode to '%s': %m", value);
57fa1d09
TG
320 } else if (streq(key, "DEVUID")) {
321 r = device_set_devuid(device, value);
322 if (r < 0)
c7d54dae 323 return log_device_debug_errno(device, r, "sd-device: Failed to set devuid to '%s': %m", value);
57fa1d09
TG
324 } else if (streq(key, "DEVGID")) {
325 r = device_set_devgid(device, value);
326 if (r < 0)
c7d54dae 327 return log_device_debug_errno(device, r, "sd-device: Failed to set devgid to '%s': %m", value);
5ebd3fc3 328 } else if (streq(key, "ACTION")) {
20798980 329 r = device_set_action_from_string(device, value);
5ebd3fc3
YW
330 if (r < 0)
331 return log_device_debug_errno(device, r, "sd-device: Failed to set action to '%s': %m", value);
332 } else if (streq(key, "SEQNUM")) {
333 r = device_set_seqnum(device, value);
334 if (r < 0)
335 return log_device_debug_errno(device, r, "sd-device: Failed to set SEQNUM to '%s': %m", value);
122adcb2
LB
336 } else if (streq(key, "DISKSEQ")) {
337 r = device_set_diskseq(device, value);
338 if (r < 0)
339 return log_device_debug_errno(device, r, "sd-device: Failed to set DISKSEQ to '%s': %m", value);
57fa1d09 340 } else if (streq(key, "DEVLINKS")) {
87a4d416
ZJS
341 for (const char *p = value;;) {
342 _cleanup_free_ char *word = NULL;
57fa1d09 343
31063db0
YW
344 /* udev rules may set escaped strings, and sd-device does not modify the input
345 * strings. So, it is also necessary to keep the strings received through
346 * sd-device-monitor. */
347 r = extract_first_word(&p, &word, NULL, EXTRACT_RETAIN_ESCAPE);
87a4d416
ZJS
348 if (r < 0)
349 return r;
350 if (r == 0)
351 break;
57fa1d09 352
87a4d416 353 r = device_add_devlink(device, word);
57fa1d09 354 if (r < 0)
87a4d416 355 return log_device_debug_errno(device, r, "sd-device: Failed to add devlink '%s': %m", word);
57fa1d09 356 }
e77b146f 357 } else if (STR_IN_SET(key, "TAGS", "CURRENT_TAGS")) {
87a4d416
ZJS
358 for (const char *p = value;;) {
359 _cleanup_free_ char *word = NULL;
57fa1d09 360
87a4d416
ZJS
361 r = extract_first_word(&p, &word, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
362 if (r < 0)
363 return r;
364 if (r == 0)
365 break;
0b4c70b4
YW
366 if (isempty(word))
367 continue;
57fa1d09 368
87a4d416 369 r = device_add_tag(device, word, streq(key, "CURRENT_TAGS"));
57fa1d09 370 if (r < 0)
87a4d416 371 return log_device_debug_errno(device, r, "sd-device: Failed to add tag '%s': %m", word);
57fa1d09 372 }
4bc4040b
YW
373 } else if (streq(key, "UDEV_DATABASE_VERSION")) {
374 r = safe_atou(value, &device->database_version);
375 if (r < 0)
376 return log_device_debug_errno(device, r, "sd-device: Failed to parse udev database version '%s': %m", value);
57fa1d09
TG
377 } else {
378 r = device_add_property_internal(device, key, value);
379 if (r < 0)
c7d54dae 380 return log_device_debug_errno(device, r, "sd-device: Failed to add property '%s=%s': %m", key, value);
57fa1d09
TG
381 }
382
383 return 0;
384}
385
96fb82aa
LP
386static int device_append(
387 sd_device *device,
388 char *key,
389 const char **_major,
390 const char **_minor) {
391
57fa1d09
TG
392 const char *major = NULL, *minor = NULL;
393 char *value;
394 int r;
395
396 assert(device);
397 assert(key);
398 assert(_major);
399 assert(_minor);
57fa1d09
TG
400
401 value = strchr(key, '=');
9e791238
ZJS
402 if (!value)
403 return log_device_debug_errno(device, SYNTHETIC_ERRNO(EINVAL),
404 "sd-device: Not a key-value pair: '%s'", key);
57fa1d09
TG
405
406 *value = '\0';
407
408 value++;
409
410 if (streq(key, "MAJOR"))
411 major = value;
412 else if (streq(key, "MINOR"))
413 minor = value;
414 else {
401cb614 415 r = device_amend(device, key, value);
57fa1d09
TG
416 if (r < 0)
417 return r;
418 }
419
96fb82aa 420 if (major)
57fa1d09
TG
421 *_major = major;
422
96fb82aa 423 if (minor)
57fa1d09
TG
424 *_minor = minor;
425
57fa1d09
TG
426 return 0;
427}
428
429void device_seal(sd_device *device) {
430 assert(device);
431
432 device->sealed = true;
433}
434
5ebd3fc3 435static int device_verify(sd_device *device) {
e5ca293f
YW
436 int r;
437
57fa1d09
TG
438 assert(device);
439
9e791238
ZJS
440 if (!device->devpath || !device->subsystem || device->action < 0 || device->seqnum == 0)
441 return log_device_debug_errno(device, SYNTHETIC_ERRNO(EINVAL),
442 "sd-device: Device created from strv or nulstr lacks devpath, subsystem, action or seqnum.");
57fa1d09 443
ab1bd9da
YW
444 r = device_in_subsystem(device, "drivers");
445 if (r < 0)
446 return log_device_debug_errno(device, r, "sd-device: Failed to check if the device is a driver: %m");
447 if (r > 0) {
e5ca293f
YW
448 r = device_set_drivers_subsystem(device);
449 if (r < 0)
1fe5b063
YW
450 return log_device_debug_errno(device, r,
451 "sd-device: Failed to set driver subsystem: %m");
e5ca293f
YW
452 }
453
57fa1d09
TG
454 device->sealed = true;
455
456 return 0;
457}
458
459int device_new_from_strv(sd_device **ret, char **strv) {
4afd3348 460 _cleanup_(sd_device_unrefp) sd_device *device = NULL;
57fa1d09 461 const char *major = NULL, *minor = NULL;
57fa1d09
TG
462 int r;
463
464 assert(ret);
465 assert(strv);
466
467 r = device_new_aux(&device);
468 if (r < 0)
469 return r;
470
471 STRV_FOREACH(key, strv) {
5ebd3fc3 472 r = device_append(device, *key, &major, &minor);
57fa1d09
TG
473 if (r < 0)
474 return r;
475 }
476
477 if (major) {
478 r = device_set_devnum(device, major, minor);
479 if (r < 0)
c7d54dae 480 return log_device_debug_errno(device, r, "sd-device: Failed to set devnum %s:%s: %m", major, minor);
57fa1d09
TG
481 }
482
5ebd3fc3 483 r = device_verify(device);
57fa1d09
TG
484 if (r < 0)
485 return r;
486
1cc6c93a 487 *ret = TAKE_PTR(device);
57fa1d09
TG
488
489 return 0;
490}
491
cff31876 492int device_new_from_nulstr(sd_device **ret, char *nulstr, size_t len) {
4afd3348 493 _cleanup_(sd_device_unrefp) sd_device *device = NULL;
57fa1d09 494 const char *major = NULL, *minor = NULL;
57fa1d09
TG
495 int r;
496
497 assert(ret);
498 assert(nulstr);
499 assert(len);
500
501 r = device_new_aux(&device);
502 if (r < 0)
503 return r;
504
ce634c4a 505 for (size_t i = 0; i < len; ) {
57fa1d09
TG
506 char *key;
507 const char *end;
508
cff31876 509 key = nulstr + i;
57fa1d09 510 end = memchr(key, '\0', len - i);
9e791238
ZJS
511 if (!end)
512 return log_device_debug_errno(device, SYNTHETIC_ERRNO(EINVAL),
513 "sd-device: Failed to parse nulstr");
514
57fa1d09
TG
515 i += end - key + 1;
516
b9cbb08e
YW
517 /* netlink messages for some devices contain an unwanted newline at the end of value.
518 * Let's drop the newline and remaining characters after the newline. */
519 truncate_nl(key);
520
5ebd3fc3 521 r = device_append(device, key, &major, &minor);
57fa1d09
TG
522 if (r < 0)
523 return r;
524 }
525
526 if (major) {
527 r = device_set_devnum(device, major, minor);
528 if (r < 0)
c7d54dae 529 return log_device_debug_errno(device, r, "sd-device: Failed to set devnum %s:%s: %m", major, minor);
57fa1d09
TG
530 }
531
5ebd3fc3 532 r = device_verify(device);
57fa1d09
TG
533 if (r < 0)
534 return r;
535
1cc6c93a 536 *ret = TAKE_PTR(device);
57fa1d09
TG
537
538 return 0;
539}
540
541static int device_update_properties_bufs(sd_device *device) {
cff31876
YW
542 _cleanup_free_ char **buf_strv = NULL, *buf_nulstr = NULL;
543 size_t nulstr_len = 0, num = 0;
57fa1d09
TG
544
545 assert(device);
546
aa20f49a
TG
547 if (!device->properties_buf_outdated)
548 return 0;
549
4bc4040b
YW
550 /* append udev database version */
551 buf_nulstr = newdup(char, "UDEV_DATABASE_VERSION=" STRINGIFY(LATEST_UDEV_DATABASE_VERSION) "\0",
552 STRLEN("UDEV_DATABASE_VERSION=" STRINGIFY(LATEST_UDEV_DATABASE_VERSION)) + 2);
553 if (!buf_nulstr)
554 return -ENOMEM;
555
556 nulstr_len += STRLEN("UDEV_DATABASE_VERSION=" STRINGIFY(LATEST_UDEV_DATABASE_VERSION)) + 1;
557 num++;
558
57fa1d09
TG
559 FOREACH_DEVICE_PROPERTY(device, prop, val) {
560 size_t len = 0;
561
562 len = strlen(prop) + 1 + strlen(val);
563
319a4f4b 564 buf_nulstr = GREEDY_REALLOC0(buf_nulstr, nulstr_len + len + 2);
57fa1d09
TG
565 if (!buf_nulstr)
566 return -ENOMEM;
567
cff31876 568 strscpyl(buf_nulstr + nulstr_len, len + 1, prop, "=", val, NULL);
57fa1d09 569 nulstr_len += len + 1;
cff31876 570 num++;
57fa1d09
TG
571 }
572
ccc1002a 573 /* build buf_strv from buf_nulstr */
cff31876 574 buf_strv = new0(char*, num + 1);
ccc1002a
TG
575 if (!buf_strv)
576 return -ENOMEM;
d854ba50 577
cff31876 578 size_t i = 0;
cff31876
YW
579 NULSTR_FOREACH(p, buf_nulstr)
580 buf_strv[i++] = p;
581 assert(i == num);
57fa1d09 582
f9ecfd3b 583 free_and_replace(device->properties_nulstr, buf_nulstr);
ccc1002a 584 device->properties_nulstr_len = nulstr_len;
f9ecfd3b 585 free_and_replace(device->properties_strv, buf_strv);
ccc1002a 586
57fa1d09 587 device->properties_buf_outdated = false;
57fa1d09
TG
588 return 0;
589}
590
793ab3e9 591int device_get_properties_nulstr(sd_device *device, const char **ret_nulstr, size_t *ret_len) {
57fa1d09
TG
592 int r;
593
594 assert(device);
57fa1d09 595
aa20f49a
TG
596 r = device_update_properties_bufs(device);
597 if (r < 0)
598 return r;
57fa1d09 599
793ab3e9
YW
600 if (ret_nulstr)
601 *ret_nulstr = device->properties_nulstr;
602 if (ret_len)
603 *ret_len = device->properties_nulstr_len;
57fa1d09
TG
604
605 return 0;
606}
607
793ab3e9 608int device_get_properties_strv(sd_device *device, char ***ret) {
57fa1d09
TG
609 int r;
610
611 assert(device);
57fa1d09
TG
612
613 r = device_update_properties_bufs(device);
614 if (r < 0)
615 return r;
616
793ab3e9
YW
617 if (ret)
618 *ret = device->properties_strv;
57fa1d09
TG
619
620 return 0;
621}
622
d82827a1 623int device_get_devlink_priority(sd_device *device, int *ret) {
57fa1d09
TG
624 int r;
625
626 assert(device);
57fa1d09
TG
627
628 r = device_read_db(device);
629 if (r < 0)
630 return r;
631
d82827a1
YW
632 if (ret)
633 *ret = device->devlink_priority;
57fa1d09
TG
634
635 return 0;
636}
637
35e49f28 638int device_clone_with_db(sd_device *device, sd_device **ret) {
23d20adc 639 _cleanup_(sd_device_unrefp) sd_device *dest = NULL;
35e49f28 640 const char *key, *val;
57fa1d09
TG
641 int r;
642
23d20adc
YW
643 assert(device);
644 assert(ret);
57fa1d09 645
35e49f28
YW
646 /* The device may be already removed. Let's copy minimal set of information that was obtained through
647 * netlink socket. */
648
23d20adc 649 r = device_new_aux(&dest);
57fa1d09
TG
650 if (r < 0)
651 return r;
652
35e49f28
YW
653 /* Seal device to prevent reading the uevent file, as the device may have been already removed. */
654 dest->sealed = true;
655
656 /* Copy syspath, then also devname, sysname or sysnum can be obtained. */
23d20adc 657 r = device_set_syspath(dest, device->syspath, false);
57fa1d09
TG
658 if (r < 0)
659 return r;
660
35e49f28
YW
661 /* Copy other information stored in database. Here, do not use FOREACH_DEVICE_PROPERTY() and
662 * sd_device_get_property_value(), as they calls device_properties_prepare() ->
663 * device_read_uevent_file(), but as commented in the above, the device may be already removed and
664 * reading uevent file may fail. */
665 ORDERED_HASHMAP_FOREACH_KEY(val, key, device->properties) {
666 if (streq(key, "MINOR"))
667 continue;
668
669 if (streq(key, "MAJOR")) {
670 const char *minor = NULL;
671
672 minor = ordered_hashmap_get(device->properties, "MINOR");
673 r = device_set_devnum(dest, val, minor);
674 } else
675 r = device_amend(dest, key, val);
2255e8ad
YW
676 if (r < 0)
677 return r;
57fa1d09 678
35e49f28
YW
679 if (streq(key, "SUBSYSTEM") && streq(val, "drivers")) {
680 r = free_and_strdup(&dest->driver_subsystem, device->driver_subsystem);
681 if (r < 0)
682 return r;
683 }
381f6d4b
YW
684 }
685
35e49f28
YW
686 /* Finally, read the udev database. */
687 r = device_read_db_internal(dest, /* force = */ true);
17761fb3
YW
688 if (r < 0)
689 return r;
381f6d4b 690
23d20adc 691 *ret = TAKE_PTR(dest);
57fa1d09
TG
692 return 0;
693}
694
57fa1d09
TG
695void device_cleanup_tags(sd_device *device) {
696 assert(device);
697
f92fac7e
YW
698 device->all_tags = set_free(device->all_tags);
699 device->current_tags = set_free(device->current_tags);
57fa1d09 700 device->property_tags_outdated = true;
313cefa1 701 device->tags_generation++;
57fa1d09
TG
702}
703
704void device_cleanup_devlinks(sd_device *device) {
705 assert(device);
706
f92fac7e 707 set_free(device->devlinks);
57fa1d09
TG
708 device->devlinks = NULL;
709 device->property_devlinks_outdated = true;
313cefa1 710 device->devlinks_generation++;
57fa1d09
TG
711}
712
713void device_remove_tag(sd_device *device, const char *tag) {
714 assert(device);
715 assert(tag);
716
e77b146f 717 free(set_remove(device->current_tags, tag));
57fa1d09 718 device->property_tags_outdated = true;
313cefa1 719 device->tags_generation++;
57fa1d09
TG
720}
721
722static int device_tag(sd_device *device, const char *tag, bool add) {
723 const char *id;
724 char *path;
725 int r;
726
727 assert(device);
728 assert(tag);
729
1ff0164b 730 r = sd_device_get_device_id(device, &id);
57fa1d09
TG
731 if (r < 0)
732 return r;
733
734 path = strjoina("/run/udev/tags/", tag, "/", id);
735
d37c69c1
YW
736 if (add)
737 return touch_file(path, true, USEC_INFINITY, UID_INVALID, GID_INVALID, 0444);
738
739 if (unlink(path) < 0 && errno != ENOENT)
740 return -errno;
57fa1d09
TG
741
742 return 0;
743}
744
745int device_tag_index(sd_device *device, sd_device *device_old, bool add) {
57fa1d09
TG
746 int r = 0, k;
747
d37c69c1 748 if (add && device_old)
57fa1d09 749 /* delete possible left-over tags */
d37c69c1 750 FOREACH_DEVICE_TAG(device_old, tag)
57fa1d09
TG
751 if (!sd_device_has_tag(device, tag)) {
752 k = device_tag(device_old, tag, false);
753 if (r >= 0 && k < 0)
754 r = k;
755 }
57fa1d09
TG
756
757 FOREACH_DEVICE_TAG(device, tag) {
758 k = device_tag(device, tag, add);
759 if (r >= 0 && k < 0)
760 r = k;
761 }
762
763 return r;
764}
765
766static bool device_has_info(sd_device *device) {
767 assert(device);
768
769 if (!set_isempty(device->devlinks))
770 return true;
771
772 if (device->devlink_priority != 0)
773 return true;
774
775 if (!ordered_hashmap_isempty(device->properties_db))
776 return true;
777
e77b146f
LP
778 if (!set_isempty(device->all_tags))
779 return true;
780
781 if (!set_isempty(device->current_tags))
57fa1d09
TG
782 return true;
783
57fa1d09
TG
784 return false;
785}
786
91fd5e6b
YW
787bool device_should_have_db(sd_device *device) {
788 assert(device);
789
790 if (device_has_info(device))
791 return true;
792
793 if (major(device->devnum) != 0)
794 return true;
795
796 if (device->ifindex != 0)
797 return true;
798
799 return false;
800}
801
57fa1d09
TG
802void device_set_db_persist(sd_device *device) {
803 assert(device);
804
805 device->db_persist = true;
806}
807
91fd5e6b 808static int device_get_db_path(sd_device *device, char **ret) {
57fa1d09
TG
809 const char *id;
810 char *path;
57fa1d09
TG
811 int r;
812
813 assert(device);
91fd5e6b 814 assert(ret);
57fa1d09 815
1ff0164b 816 r = sd_device_get_device_id(device, &id);
57fa1d09
TG
817 if (r < 0)
818 return r;
819
91fd5e6b
YW
820 path = path_join("/run/udev/data/", id);
821 if (!path)
822 return -ENOMEM;
823
824 *ret = path;
825 return 0;
826}
827
6e574ebd
YW
828int device_has_db(sd_device *device) {
829 _cleanup_free_ char *path = NULL;
830 int r;
831
832 assert(device);
833
834 r = device_get_db_path(device, &path);
835 if (r < 0)
836 return r;
837
838 return access(path, F_OK) >= 0;
839}
840
91fd5e6b
YW
841int device_update_db(sd_device *device) {
842 _cleanup_(unlink_and_freep) char *path = NULL, *path_tmp = NULL;
843 _cleanup_fclose_ FILE *f = NULL;
844 int r;
845
846 assert(device);
57fa1d09
TG
847
848 /* do not store anything for otherwise empty devices */
91fd5e6b
YW
849 if (!device_should_have_db(device))
850 return device_delete_db(device);
57fa1d09 851
91fd5e6b
YW
852 r = device_get_db_path(device, &path);
853 if (r < 0)
854 return r;
57fa1d09
TG
855
856 /* write a database file */
857 r = mkdir_parents(path, 0755);
858 if (r < 0)
91fd5e6b
YW
859 return log_device_debug_errno(device, r,
860 "sd-device: Failed to create parent directories of '%s': %m",
861 path);
57fa1d09
TG
862
863 r = fopen_temporary(path, &f, &path_tmp);
864 if (r < 0)
91fd5e6b
YW
865 return log_device_debug_errno(device, r,
866 "sd-device: Failed to create temporary file for database file '%s': %m",
867 path);
57fa1d09 868
32e27670
LP
869 /* set 'sticky' bit to indicate that we should not clean the database when we transition from initrd
870 * to the real root */
91fd5e6b
YW
871 if (fchmod(fileno(f), device->db_persist ? 01644 : 0644) < 0)
872 return log_device_debug_errno(device, errno,
873 "sd-device: Failed to chmod temporary database file '%s': %m",
874 path_tmp);
57fa1d09 875
91fd5e6b 876 if (device_has_info(device)) {
a1af8372 877 const char *property, *value, *ct;
57fa1d09
TG
878
879 if (major(device->devnum) > 0) {
57fa1d09 880 FOREACH_DEVICE_DEVLINK(device, devlink)
fbd0b64f 881 fprintf(f, "S:%s\n", devlink + STRLEN("/dev/"));
57fa1d09
TG
882
883 if (device->devlink_priority != 0)
884 fprintf(f, "L:%i\n", device->devlink_priority);
57fa1d09
TG
885 }
886
887 if (device->usec_initialized > 0)
888 fprintf(f, "I:"USEC_FMT"\n", device->usec_initialized);
889
90e74a66 890 ORDERED_HASHMAP_FOREACH_KEY(value, property, device->properties_db)
57fa1d09
TG
891 fprintf(f, "E:%s=%s\n", property, value);
892
893 FOREACH_DEVICE_TAG(device, tag)
e77b146f
LP
894 fprintf(f, "G:%s\n", tag); /* Any tag */
895
a1af8372
DDM
896 SET_FOREACH(ct, device->current_tags)
897 fprintf(f, "Q:%s\n", ct); /* Current tag */
58b30ada
YW
898
899 /* Always write the latest database version here, instead of the value stored in
900 * device->database_version, as which may be 0. */
901 fputs("V:" STRINGIFY(LATEST_UDEV_DATABASE_VERSION) "\n", f);
57fa1d09
TG
902 }
903
904 r = fflush_and_check(f);
905 if (r < 0)
91fd5e6b
YW
906 return log_device_debug_errno(device, r,
907 "sd-device: Failed to flush temporary database file '%s': %m",
908 path_tmp);
57fa1d09 909
91fd5e6b
YW
910 if (rename(path_tmp, path) < 0)
911 return log_device_debug_errno(device, errno,
912 "sd-device: Failed to rename temporary database file '%s' to '%s': %m",
913 path_tmp, path);
57fa1d09 914
91fd5e6b 915 log_device_debug(device, "sd-device: Created database file '%s' for '%s'.", path, device->devpath);
70f1280c 916
91fd5e6b
YW
917 path_tmp = mfree(path_tmp);
918 path = mfree(path);
57fa1d09
TG
919
920 return 0;
57fa1d09
TG
921}
922
923int device_delete_db(sd_device *device) {
91fd5e6b 924 _cleanup_free_ char *path = NULL;
57fa1d09
TG
925 int r;
926
927 assert(device);
928
91fd5e6b 929 r = device_get_db_path(device, &path);
57fa1d09
TG
930 if (r < 0)
931 return r;
932
d37c69c1 933 if (unlink(path) < 0 && errno != ENOENT)
57fa1d09
TG
934 return -errno;
935
936 return 0;
937}
5ebd3fc3 938
91fd5e6b
YW
939int device_read_db_internal(sd_device *device, bool force) {
940 _cleanup_free_ char *path = NULL;
941 int r;
942
943 assert(device);
944
945 if (device->db_loaded || (!force && device->sealed))
946 return 0;
947
948 r = device_get_db_path(device, &path);
949 if (r < 0)
950 return r;
951
952 return device_read_db_internal_filename(device, path);
953}
954
a1130022
LP
955static const char* const device_action_table[_SD_DEVICE_ACTION_MAX] = {
956 [SD_DEVICE_ADD] = "add",
957 [SD_DEVICE_REMOVE] = "remove",
958 [SD_DEVICE_CHANGE] = "change",
959 [SD_DEVICE_MOVE] = "move",
960 [SD_DEVICE_ONLINE] = "online",
961 [SD_DEVICE_OFFLINE] = "offline",
962 [SD_DEVICE_BIND] = "bind",
963 [SD_DEVICE_UNBIND] = "unbind",
5ebd3fc3
YW
964};
965
a1130022 966DEFINE_STRING_TABLE_LOOKUP(device_action, sd_device_action_t);