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