]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd/sd-device/device-private.c
tree-wide: use unlink_and_freep() moreover
[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"
e7f781e4 23#include "stdio-util.h"
8b43440b 24#include "string-table.h"
07630cea
LP
25#include "string-util.h"
26#include "strv.h"
27#include "strxcpyx.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
TG
118
119 r = device_read_db(device);
120 if (r < 0)
121 return r;
122
f5fbe71d 123 if (device->devmode == MODE_INVALID)
dcfbde3a
YW
124 return -ENOENT;
125
d82827a1
YW
126 if (ret)
127 *ret = device->devmode;
57fa1d09
TG
128
129 return 0;
130}
131
d82827a1 132int device_get_devnode_uid(sd_device *device, uid_t *ret) {
57fa1d09
TG
133 int r;
134
135 assert(device);
57fa1d09
TG
136
137 r = device_read_db(device);
138 if (r < 0)
139 return r;
140
f5fbe71d 141 if (device->devuid == UID_INVALID)
dcfbde3a
YW
142 return -ENOENT;
143
d82827a1
YW
144 if (ret)
145 *ret = device->devuid;
57fa1d09
TG
146
147 return 0;
148}
149
150static int device_set_devuid(sd_device *device, const char *uid) {
c77c1cc2 151 uid_t u;
57fa1d09
TG
152 int r;
153
154 assert(device);
155 assert(uid);
156
c77c1cc2 157 r = parse_uid(uid, &u);
57fa1d09
TG
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
d82827a1 170int device_get_devnode_gid(sd_device *device, gid_t *ret) {
57fa1d09
TG
171 int r;
172
173 assert(device);
57fa1d09
TG
174
175 r = device_read_db(device);
176 if (r < 0)
177 return r;
178
f5fbe71d 179 if (device->devgid == GID_INVALID)
dcfbde3a
YW
180 return -ENOENT;
181
d82827a1
YW
182 if (ret)
183 *ret = device->devgid;
57fa1d09
TG
184
185 return 0;
186}
187
188static int device_set_devgid(sd_device *device, const char *gid) {
c77c1cc2 189 gid_t g;
57fa1d09
TG
190 int r;
191
192 assert(device);
193 assert(gid);
194
c77c1cc2 195 r = parse_gid(gid, &g);
57fa1d09
TG
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
20798980 208int device_set_action(sd_device *device, sd_device_action_t a) {
5ebd3fc3
YW
209 int r;
210
211 assert(device);
20798980 212 assert(a >= 0 && a < _SD_DEVICE_ACTION_MAX);
5ebd3fc3 213
a1130022 214 r = device_add_property_internal(device, "ACTION", device_action_to_string(a));
5ebd3fc3
YW
215 if (r < 0)
216 return r;
217
218 device->action = a;
219
220 return 0;
221}
222
20798980
YW
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
5ebd3fc3
YW
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
401cb614 258static int device_amend(sd_device *device, const char *key, const char *value) {
57fa1d09
TG
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)
c7d54dae 273 return log_device_debug_errno(device, r, "sd-device: Failed to set syspath to '%s': %m", path);
57fa1d09
TG
274 } else if (streq(key, "SUBSYSTEM")) {
275 r = device_set_subsystem(device, value);
276 if (r < 0)
c7d54dae 277 return log_device_debug_errno(device, r, "sd-device: Failed to set subsystem to '%s': %m", value);
57fa1d09
TG
278 } else if (streq(key, "DEVTYPE")) {
279 r = device_set_devtype(device, value);
280 if (r < 0)
c7d54dae 281 return log_device_debug_errno(device, r, "sd-device: Failed to set devtype to '%s': %m", value);
57fa1d09
TG
282 } else if (streq(key, "DEVNAME")) {
283 r = device_set_devname(device, value);
284 if (r < 0)
c7d54dae 285 return log_device_debug_errno(device, r, "sd-device: Failed to set devname to '%s': %m", value);
57fa1d09 286 } else if (streq(key, "USEC_INITIALIZED")) {
dc5042c0
ZJS
287 usec_t t;
288
289 r = safe_atou64(value, &t);
290 if (r < 0)
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);
57fa1d09 294 if (r < 0)
c7d54dae 295 return log_device_debug_errno(device, r, "sd-device: Failed to set usec-initialized to '%s': %m", value);
57fa1d09
TG
296 } else if (streq(key, "DRIVER")) {
297 r = device_set_driver(device, value);
298 if (r < 0)
c7d54dae 299 return log_device_debug_errno(device, r, "sd-device: Failed to set driver to '%s': %m", value);
57fa1d09
TG
300 } else if (streq(key, "IFINDEX")) {
301 r = device_set_ifindex(device, value);
302 if (r < 0)
c7d54dae 303 return log_device_debug_errno(device, r, "sd-device: Failed to set ifindex to '%s': %m", value);
57fa1d09
TG
304 } else if (streq(key, "DEVMODE")) {
305 r = device_set_devmode(device, value);
306 if (r < 0)
c7d54dae 307 return log_device_debug_errno(device, r, "sd-device: Failed to set devmode to '%s': %m", value);
57fa1d09
TG
308 } else if (streq(key, "DEVUID")) {
309 r = device_set_devuid(device, value);
310 if (r < 0)
c7d54dae 311 return log_device_debug_errno(device, r, "sd-device: Failed to set devuid to '%s': %m", value);
57fa1d09
TG
312 } else if (streq(key, "DEVGID")) {
313 r = device_set_devgid(device, value);
314 if (r < 0)
c7d54dae 315 return log_device_debug_errno(device, r, "sd-device: Failed to set devgid to '%s': %m", value);
5ebd3fc3 316 } else if (streq(key, "ACTION")) {
20798980 317 r = device_set_action_from_string(device, value);
5ebd3fc3
YW
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);
122adcb2
LB
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);
57fa1d09 328 } else if (streq(key, "DEVLINKS")) {
87a4d416
ZJS
329 for (const char *p = value;;) {
330 _cleanup_free_ char *word = NULL;
57fa1d09 331
31063db0
YW
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);
87a4d416
ZJS
336 if (r < 0)
337 return r;
338 if (r == 0)
339 break;
57fa1d09 340
87a4d416 341 r = device_add_devlink(device, word);
57fa1d09 342 if (r < 0)
87a4d416 343 return log_device_debug_errno(device, r, "sd-device: Failed to add devlink '%s': %m", word);
57fa1d09 344 }
e77b146f 345 } else if (STR_IN_SET(key, "TAGS", "CURRENT_TAGS")) {
87a4d416
ZJS
346 for (const char *p = value;;) {
347 _cleanup_free_ char *word = NULL;
57fa1d09 348
87a4d416
ZJS
349 r = extract_first_word(&p, &word, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
350 if (r < 0)
351 return r;
352 if (r == 0)
353 break;
57fa1d09 354
87a4d416 355 r = device_add_tag(device, word, streq(key, "CURRENT_TAGS"));
57fa1d09 356 if (r < 0)
87a4d416 357 return log_device_debug_errno(device, r, "sd-device: Failed to add tag '%s': %m", word);
57fa1d09 358 }
4bc4040b
YW
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);
57fa1d09
TG
363 } else {
364 r = device_add_property_internal(device, key, value);
365 if (r < 0)
c7d54dae 366 return log_device_debug_errno(device, r, "sd-device: Failed to add property '%s=%s': %m", key, value);
57fa1d09
TG
367 }
368
369 return 0;
370}
371
96fb82aa
LP
372static int device_append(
373 sd_device *device,
374 char *key,
375 const char **_major,
376 const char **_minor) {
377
57fa1d09
TG
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);
57fa1d09
TG
386
387 value = strchr(key, '=');
9e791238
ZJS
388 if (!value)
389 return log_device_debug_errno(device, SYNTHETIC_ERRNO(EINVAL),
390 "sd-device: Not a key-value pair: '%s'", key);
57fa1d09
TG
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 {
401cb614 401 r = device_amend(device, key, value);
57fa1d09
TG
402 if (r < 0)
403 return r;
404 }
405
96fb82aa 406 if (major)
57fa1d09
TG
407 *_major = major;
408
96fb82aa 409 if (minor)
57fa1d09
TG
410 *_minor = minor;
411
57fa1d09
TG
412 return 0;
413}
414
415void device_seal(sd_device *device) {
416 assert(device);
417
418 device->sealed = true;
419}
420
5ebd3fc3 421static int device_verify(sd_device *device) {
e5ca293f
YW
422 int r;
423
57fa1d09
TG
424 assert(device);
425
9e791238
ZJS
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.");
57fa1d09 429
e5ca293f
YW
430 if (streq(device->subsystem, "drivers")) {
431 r = device_set_drivers_subsystem(device);
432 if (r < 0)
433 return r;
434 }
435
57fa1d09
TG
436 device->sealed = true;
437
438 return 0;
439}
440
441int device_new_from_strv(sd_device **ret, char **strv) {
4afd3348 442 _cleanup_(sd_device_unrefp) sd_device *device = NULL;
57fa1d09 443 const char *major = NULL, *minor = NULL;
57fa1d09
TG
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) {
5ebd3fc3 454 r = device_append(device, *key, &major, &minor);
57fa1d09
TG
455 if (r < 0)
456 return r;
457 }
458
459 if (major) {
460 r = device_set_devnum(device, major, minor);
461 if (r < 0)
c7d54dae 462 return log_device_debug_errno(device, r, "sd-device: Failed to set devnum %s:%s: %m", major, minor);
57fa1d09
TG
463 }
464
5ebd3fc3 465 r = device_verify(device);
57fa1d09
TG
466 if (r < 0)
467 return r;
468
1cc6c93a 469 *ret = TAKE_PTR(device);
57fa1d09
TG
470
471 return 0;
472}
473
cff31876 474int device_new_from_nulstr(sd_device **ret, char *nulstr, size_t len) {
4afd3348 475 _cleanup_(sd_device_unrefp) sd_device *device = NULL;
57fa1d09 476 const char *major = NULL, *minor = NULL;
57fa1d09
TG
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
ce634c4a 487 for (size_t i = 0; i < len; ) {
57fa1d09
TG
488 char *key;
489 const char *end;
490
cff31876 491 key = nulstr + i;
57fa1d09 492 end = memchr(key, '\0', len - i);
9e791238
ZJS
493 if (!end)
494 return log_device_debug_errno(device, SYNTHETIC_ERRNO(EINVAL),
495 "sd-device: Failed to parse nulstr");
496
57fa1d09
TG
497 i += end - key + 1;
498
b9cbb08e
YW
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
5ebd3fc3 503 r = device_append(device, key, &major, &minor);
57fa1d09
TG
504 if (r < 0)
505 return r;
506 }
507
508 if (major) {
509 r = device_set_devnum(device, major, minor);
510 if (r < 0)
c7d54dae 511 return log_device_debug_errno(device, r, "sd-device: Failed to set devnum %s:%s: %m", major, minor);
57fa1d09
TG
512 }
513
5ebd3fc3 514 r = device_verify(device);
57fa1d09
TG
515 if (r < 0)
516 return r;
517
1cc6c93a 518 *ret = TAKE_PTR(device);
57fa1d09
TG
519
520 return 0;
521}
522
523static int device_update_properties_bufs(sd_device *device) {
cff31876
YW
524 _cleanup_free_ char **buf_strv = NULL, *buf_nulstr = NULL;
525 size_t nulstr_len = 0, num = 0;
57fa1d09 526 const char *val, *prop;
57fa1d09
TG
527
528 assert(device);
529
aa20f49a
TG
530 if (!device->properties_buf_outdated)
531 return 0;
532
4bc4040b
YW
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
57fa1d09
TG
542 FOREACH_DEVICE_PROPERTY(device, prop, val) {
543 size_t len = 0;
544
545 len = strlen(prop) + 1 + strlen(val);
546
319a4f4b 547 buf_nulstr = GREEDY_REALLOC0(buf_nulstr, nulstr_len + len + 2);
57fa1d09
TG
548 if (!buf_nulstr)
549 return -ENOMEM;
550
cff31876 551 strscpyl(buf_nulstr + nulstr_len, len + 1, prop, "=", val, NULL);
57fa1d09 552 nulstr_len += len + 1;
cff31876 553 num++;
57fa1d09
TG
554 }
555
ccc1002a 556 /* build buf_strv from buf_nulstr */
cff31876 557 buf_strv = new0(char*, num + 1);
ccc1002a
TG
558 if (!buf_strv)
559 return -ENOMEM;
d854ba50 560
cff31876 561 size_t i = 0;
cff31876
YW
562 NULSTR_FOREACH(p, buf_nulstr)
563 buf_strv[i++] = p;
564 assert(i == num);
57fa1d09 565
f9ecfd3b 566 free_and_replace(device->properties_nulstr, buf_nulstr);
ccc1002a 567 device->properties_nulstr_len = nulstr_len;
f9ecfd3b 568 free_and_replace(device->properties_strv, buf_strv);
ccc1002a 569
57fa1d09 570 device->properties_buf_outdated = false;
57fa1d09
TG
571 return 0;
572}
573
793ab3e9 574int device_get_properties_nulstr(sd_device *device, const char **ret_nulstr, size_t *ret_len) {
57fa1d09
TG
575 int r;
576
577 assert(device);
57fa1d09 578
aa20f49a
TG
579 r = device_update_properties_bufs(device);
580 if (r < 0)
581 return r;
57fa1d09 582
793ab3e9
YW
583 if (ret_nulstr)
584 *ret_nulstr = device->properties_nulstr;
585 if (ret_len)
586 *ret_len = device->properties_nulstr_len;
57fa1d09
TG
587
588 return 0;
589}
590
793ab3e9 591int device_get_properties_strv(sd_device *device, char ***ret) {
57fa1d09
TG
592 int r;
593
594 assert(device);
57fa1d09
TG
595
596 r = device_update_properties_bufs(device);
597 if (r < 0)
598 return r;
599
793ab3e9
YW
600 if (ret)
601 *ret = device->properties_strv;
57fa1d09
TG
602
603 return 0;
604}
605
d82827a1 606int device_get_devlink_priority(sd_device *device, int *ret) {
57fa1d09
TG
607 int r;
608
609 assert(device);
57fa1d09
TG
610
611 r = device_read_db(device);
612 if (r < 0)
613 return r;
614
d82827a1
YW
615 if (ret)
616 *ret = device->devlink_priority;
57fa1d09
TG
617
618 return 0;
619}
620
38995498 621static int device_shallow_clone(sd_device *device, sd_device **ret) {
23d20adc 622 _cleanup_(sd_device_unrefp) sd_device *dest = NULL;
9c5d7151 623 const char *val = NULL;
57fa1d09
TG
624 int r;
625
23d20adc
YW
626 assert(device);
627 assert(ret);
57fa1d09 628
23d20adc 629 r = device_new_aux(&dest);
57fa1d09
TG
630 if (r < 0)
631 return r;
632
23d20adc 633 r = device_set_syspath(dest, device->syspath, false);
57fa1d09
TG
634 if (r < 0)
635 return r;
636
23d20adc
YW
637 (void) sd_device_get_subsystem(device, &val);
638 r = device_set_subsystem(dest, val);
df49a732
ZJS
639 if (r < 0)
640 return r;
641 if (streq_ptr(val, "drivers")) {
23d20adc 642 r = free_and_strdup(&dest->driver_subsystem, device->driver_subsystem);
2255e8ad
YW
643 if (r < 0)
644 return r;
df49a732 645 }
57fa1d09 646
381f6d4b
YW
647 /* The device may be already removed. Let's copy minimal set of information to make
648 * device_get_device_id() work without uevent file. */
57fa1d09 649
23d20adc
YW
650 if (sd_device_get_property_value(device, "IFINDEX", &val) >= 0) {
651 r = device_set_ifindex(dest, val);
381f6d4b
YW
652 if (r < 0)
653 return r;
654 }
655
23d20adc 656 if (sd_device_get_property_value(device, "MAJOR", &val) >= 0) {
381f6d4b 657 const char *minor = NULL;
57fa1d09 658
23d20adc
YW
659 (void) sd_device_get_property_value(device, "MINOR", &minor);
660 r = device_set_devnum(dest, val, minor);
381f6d4b
YW
661 if (r < 0)
662 return r;
663 }
664
23d20adc 665 r = device_read_uevent_file(dest);
17761fb3
YW
666 if (r < 0)
667 return r;
381f6d4b 668
23d20adc 669 *ret = TAKE_PTR(dest);
57fa1d09
TG
670 return 0;
671}
672
23d20adc
YW
673int device_clone_with_db(sd_device *device, sd_device **ret) {
674 _cleanup_(sd_device_unrefp) sd_device *dest = NULL;
57fa1d09
TG
675 int r;
676
23d20adc
YW
677 assert(device);
678 assert(ret);
57fa1d09 679
23d20adc 680 r = device_shallow_clone(device, &dest);
57fa1d09
TG
681 if (r < 0)
682 return r;
683
23d20adc 684 r = device_read_db(dest);
57fa1d09
TG
685 if (r < 0)
686 return r;
687
23d20adc 688 dest->sealed = true;
57fa1d09 689
23d20adc 690 *ret = TAKE_PTR(dest);
57fa1d09
TG
691 return 0;
692}
693
57fa1d09
TG
694void device_cleanup_tags(sd_device *device) {
695 assert(device);
696
e77b146f
LP
697 device->all_tags = set_free_free(device->all_tags);
698 device->current_tags = set_free_free(device->current_tags);
57fa1d09 699 device->property_tags_outdated = true;
313cefa1 700 device->tags_generation++;
57fa1d09
TG
701}
702
703void device_cleanup_devlinks(sd_device *device) {
704 assert(device);
705
706 set_free_free(device->devlinks);
707 device->devlinks = NULL;
708 device->property_devlinks_outdated = true;
313cefa1 709 device->devlinks_generation++;
57fa1d09
TG
710}
711
712void device_remove_tag(sd_device *device, const char *tag) {
713 assert(device);
714 assert(tag);
715
e77b146f 716 free(set_remove(device->current_tags, tag));
57fa1d09 717 device->property_tags_outdated = true;
313cefa1 718 device->tags_generation++;
57fa1d09
TG
719}
720
721static int device_tag(sd_device *device, const char *tag, bool add) {
722 const char *id;
723 char *path;
724 int r;
725
726 assert(device);
727 assert(tag);
728
fe732381 729 r = device_get_device_id(device, &id);
57fa1d09
TG
730 if (r < 0)
731 return r;
732
733 path = strjoina("/run/udev/tags/", tag, "/", id);
734
d37c69c1
YW
735 if (add)
736 return touch_file(path, true, USEC_INFINITY, UID_INVALID, GID_INVALID, 0444);
737
738 if (unlink(path) < 0 && errno != ENOENT)
739 return -errno;
57fa1d09
TG
740
741 return 0;
742}
743
744int device_tag_index(sd_device *device, sd_device *device_old, bool add) {
745 const char *tag;
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
787void device_set_db_persist(sd_device *device) {
788 assert(device);
789
790 device->db_persist = true;
791}
792
793int device_update_db(sd_device *device) {
794 const char *id;
795 char *path;
796 _cleanup_fclose_ FILE *f = NULL;
70f1280c 797 _cleanup_(unlink_and_freep) char *path_tmp = NULL;
57fa1d09
TG
798 bool has_info;
799 int r;
800
801 assert(device);
802
803 has_info = device_has_info(device);
804
fe732381 805 r = device_get_device_id(device, &id);
57fa1d09
TG
806 if (r < 0)
807 return r;
808
809 path = strjoina("/run/udev/data/", id);
810
811 /* do not store anything for otherwise empty devices */
812 if (!has_info && major(device->devnum) == 0 && device->ifindex == 0) {
d37c69c1 813 if (unlink(path) < 0 && errno != ENOENT)
57fa1d09
TG
814 return -errno;
815
816 return 0;
817 }
818
819 /* write a database file */
820 r = mkdir_parents(path, 0755);
821 if (r < 0)
822 return r;
823
824 r = fopen_temporary(path, &f, &path_tmp);
825 if (r < 0)
826 return r;
827
32e27670
LP
828 /* set 'sticky' bit to indicate that we should not clean the database when we transition from initrd
829 * to the real root */
827f8650
YW
830 if (fchmod(fileno(f), device->db_persist ? 01644 : 0644) < 0) {
831 r = -errno;
832 goto fail;
57fa1d09
TG
833 }
834
835 if (has_info) {
836 const char *property, *value, *tag;
57fa1d09
TG
837
838 if (major(device->devnum) > 0) {
839 const char *devlink;
840
841 FOREACH_DEVICE_DEVLINK(device, devlink)
fbd0b64f 842 fprintf(f, "S:%s\n", devlink + STRLEN("/dev/"));
57fa1d09
TG
843
844 if (device->devlink_priority != 0)
845 fprintf(f, "L:%i\n", device->devlink_priority);
57fa1d09
TG
846 }
847
848 if (device->usec_initialized > 0)
849 fprintf(f, "I:"USEC_FMT"\n", device->usec_initialized);
850
90e74a66 851 ORDERED_HASHMAP_FOREACH_KEY(value, property, device->properties_db)
57fa1d09
TG
852 fprintf(f, "E:%s=%s\n", property, value);
853
854 FOREACH_DEVICE_TAG(device, tag)
e77b146f
LP
855 fprintf(f, "G:%s\n", tag); /* Any tag */
856
90e74a66 857 SET_FOREACH(tag, device->current_tags)
e77b146f 858 fprintf(f, "Q:%s\n", tag); /* Current tag */
58b30ada
YW
859
860 /* Always write the latest database version here, instead of the value stored in
861 * device->database_version, as which may be 0. */
862 fputs("V:" STRINGIFY(LATEST_UDEV_DATABASE_VERSION) "\n", f);
57fa1d09
TG
863 }
864
865 r = fflush_and_check(f);
866 if (r < 0)
867 goto fail;
868
827f8650 869 if (rename(path_tmp, path) < 0) {
57fa1d09
TG
870 r = -errno;
871 goto fail;
872 }
873
70f1280c
LP
874 path_tmp = mfree(path_tmp);
875
c7d54dae
YW
876 log_device_debug(device, "sd-device: Created %s file '%s' for '%s'", has_info ? "db" : "empty",
877 path, device->devpath);
57fa1d09
TG
878
879 return 0;
880
881fail:
dacd6cee 882 (void) unlink(path);
57fa1d09 883
c7d54dae 884 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
885}
886
887int device_delete_db(sd_device *device) {
888 const char *id;
889 char *path;
890 int r;
891
892 assert(device);
893
fe732381 894 r = device_get_device_id(device, &id);
57fa1d09
TG
895 if (r < 0)
896 return r;
897
898 path = strjoina("/run/udev/data/", id);
899
d37c69c1 900 if (unlink(path) < 0 && errno != ENOENT)
57fa1d09
TG
901 return -errno;
902
903 return 0;
904}
5ebd3fc3 905
a1130022
LP
906static const char* const device_action_table[_SD_DEVICE_ACTION_MAX] = {
907 [SD_DEVICE_ADD] = "add",
908 [SD_DEVICE_REMOVE] = "remove",
909 [SD_DEVICE_CHANGE] = "change",
910 [SD_DEVICE_MOVE] = "move",
911 [SD_DEVICE_ONLINE] = "online",
912 [SD_DEVICE_OFFLINE] = "offline",
913 [SD_DEVICE_BIND] = "bind",
914 [SD_DEVICE_UNBIND] = "unbind",
5ebd3fc3
YW
915};
916
a1130022 917DEFINE_STRING_TABLE_LOOKUP(device_action, sd_device_action_t);
9e0196b1
YW
918
919void dump_device_action_table(void) {
a1130022 920 DUMP_STRING_TABLE(device_action, sd_device_action_t, _SD_DEVICE_ACTION_MAX);
9e0196b1 921}