]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd/sd-device/device-private.c
sd-device: ignore bind/unbind events for now
[thirdparty/systemd.git] / src / libsystemd / sd-device / device-private.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
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"
6bedfcbb 19#include "parse-util.h"
07630cea
LP
20#include "path-util.h"
21#include "refcnt.h"
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"
07630cea 29#include "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
57fa1d09
TG
50void device_set_devlink_priority(sd_device *device, int priority) {
51 assert(device);
52
53 device->devlink_priority = priority;
54}
55
56void device_set_is_initialized(sd_device *device) {
57 assert(device);
58
59 device->is_initialized = true;
60}
61
62int device_ensure_usec_initialized(sd_device *device, sd_device *device_old) {
dc5042c0 63 usec_t when;
57fa1d09
TG
64
65 assert(device);
66
67 if (device_old && device_old->usec_initialized > 0)
dc5042c0 68 when = device_old->usec_initialized;
57fa1d09 69 else
dc5042c0 70 when = now(CLOCK_MONOTONIC);
57fa1d09 71
dc5042c0 72 return device_set_usec_initialized(device, when);
57fa1d09
TG
73}
74
57fa1d09
TG
75uint64_t device_get_properties_generation(sd_device *device) {
76 assert(device);
77
78 return device->properties_generation;
79}
80
81uint64_t device_get_tags_generation(sd_device *device) {
82 assert(device);
83
84 return device->tags_generation;
85}
86
87uint64_t device_get_devlinks_generation(sd_device *device) {
88 assert(device);
89
90 return device->devlinks_generation;
91}
92
93int device_get_devnode_mode(sd_device *device, mode_t *mode) {
94 int r;
95
96 assert(device);
57fa1d09
TG
97
98 r = device_read_db(device);
99 if (r < 0)
100 return r;
101
dcfbde3a
YW
102 if (device->devmode == (mode_t) -1)
103 return -ENOENT;
104
78ffb476
YW
105 if (mode)
106 *mode = device->devmode;
57fa1d09
TG
107
108 return 0;
109}
110
111int device_get_devnode_uid(sd_device *device, uid_t *uid) {
112 int r;
113
114 assert(device);
57fa1d09
TG
115
116 r = device_read_db(device);
117 if (r < 0)
118 return r;
119
dcfbde3a
YW
120 if (device->devuid == (uid_t) -1)
121 return -ENOENT;
122
78ffb476
YW
123 if (uid)
124 *uid = device->devuid;
57fa1d09
TG
125
126 return 0;
127}
128
129static int device_set_devuid(sd_device *device, const char *uid) {
130 unsigned u;
131 int r;
132
133 assert(device);
134 assert(uid);
135
136 r = safe_atou(uid, &u);
137 if (r < 0)
138 return r;
139
140 r = device_add_property_internal(device, "DEVUID", uid);
141 if (r < 0)
142 return r;
143
144 device->devuid = u;
145
146 return 0;
147}
148
149int device_get_devnode_gid(sd_device *device, gid_t *gid) {
150 int r;
151
152 assert(device);
57fa1d09
TG
153
154 r = device_read_db(device);
155 if (r < 0)
156 return r;
157
dcfbde3a
YW
158 if (device->devgid == (gid_t) -1)
159 return -ENOENT;
160
78ffb476
YW
161 if (gid)
162 *gid = device->devgid;
57fa1d09
TG
163
164 return 0;
165}
166
167static int device_set_devgid(sd_device *device, const char *gid) {
168 unsigned g;
169 int r;
170
171 assert(device);
172 assert(gid);
173
174 r = safe_atou(gid, &g);
175 if (r < 0)
176 return r;
177
178 r = device_add_property_internal(device, "DEVGID", gid);
179 if (r < 0)
180 return r;
181
182 device->devgid = g;
183
184 return 0;
185}
186
401cb614 187static int device_amend(sd_device *device, const char *key, const char *value) {
57fa1d09
TG
188 int r;
189
190 assert(device);
191 assert(key);
192 assert(value);
193
194 if (streq(key, "DEVPATH")) {
195 char *path;
196
197 path = strjoina("/sys", value);
198
199 /* the caller must verify or trust this data (e.g., if it comes from the kernel) */
200 r = device_set_syspath(device, path, false);
201 if (r < 0)
c7d54dae 202 return log_device_debug_errno(device, r, "sd-device: Failed to set syspath to '%s': %m", path);
57fa1d09
TG
203 } else if (streq(key, "SUBSYSTEM")) {
204 r = device_set_subsystem(device, value);
205 if (r < 0)
c7d54dae 206 return log_device_debug_errno(device, r, "sd-device: Failed to set subsystem to '%s': %m", value);
57fa1d09
TG
207 } else if (streq(key, "DEVTYPE")) {
208 r = device_set_devtype(device, value);
209 if (r < 0)
c7d54dae 210 return log_device_debug_errno(device, r, "sd-device: Failed to set devtype to '%s': %m", value);
57fa1d09
TG
211 } else if (streq(key, "DEVNAME")) {
212 r = device_set_devname(device, value);
213 if (r < 0)
c7d54dae 214 return log_device_debug_errno(device, r, "sd-device: Failed to set devname to '%s': %m", value);
57fa1d09 215 } else if (streq(key, "USEC_INITIALIZED")) {
dc5042c0
ZJS
216 usec_t t;
217
218 r = safe_atou64(value, &t);
219 if (r < 0)
220 return log_device_debug_errno(device, r, "sd-device: Failed to parse timestamp '%s': %m", value);
221
222 r = device_set_usec_initialized(device, t);
57fa1d09 223 if (r < 0)
c7d54dae 224 return log_device_debug_errno(device, r, "sd-device: Failed to set usec-initialized to '%s': %m", value);
57fa1d09
TG
225 } else if (streq(key, "DRIVER")) {
226 r = device_set_driver(device, value);
227 if (r < 0)
c7d54dae 228 return log_device_debug_errno(device, r, "sd-device: Failed to set driver to '%s': %m", value);
57fa1d09
TG
229 } else if (streq(key, "IFINDEX")) {
230 r = device_set_ifindex(device, value);
231 if (r < 0)
c7d54dae 232 return log_device_debug_errno(device, r, "sd-device: Failed to set ifindex to '%s': %m", value);
57fa1d09
TG
233 } else if (streq(key, "DEVMODE")) {
234 r = device_set_devmode(device, value);
235 if (r < 0)
c7d54dae 236 return log_device_debug_errno(device, r, "sd-device: Failed to set devmode to '%s': %m", value);
57fa1d09
TG
237 } else if (streq(key, "DEVUID")) {
238 r = device_set_devuid(device, value);
239 if (r < 0)
c7d54dae 240 return log_device_debug_errno(device, r, "sd-device: Failed to set devuid to '%s': %m", value);
57fa1d09
TG
241 } else if (streq(key, "DEVGID")) {
242 r = device_set_devgid(device, value);
243 if (r < 0)
c7d54dae 244 return log_device_debug_errno(device, r, "sd-device: Failed to set devgid to '%s': %m", value);
57fa1d09 245 } else if (streq(key, "DEVLINKS")) {
4df4fd11
TG
246 const char *word, *state;
247 size_t l;
57fa1d09 248
4df4fd11 249 FOREACH_WORD(word, l, value, state) {
de9b34b6 250 char devlink[l + 1];
57fa1d09 251
de9b34b6
TG
252 strncpy(devlink, word, l);
253 devlink[l] = '\0';
57fa1d09 254
4df4fd11 255 r = device_add_devlink(device, devlink);
57fa1d09 256 if (r < 0)
c7d54dae 257 return log_device_debug_errno(device, r, "sd-device: Failed to add devlink '%s': %m", devlink);
57fa1d09
TG
258 }
259 } else if (streq(key, "TAGS")) {
4df4fd11
TG
260 const char *word, *state;
261 size_t l;
57fa1d09 262
4df4fd11 263 FOREACH_WORD_SEPARATOR(word, l, value, ":", state) {
de9b34b6 264 char tag[l + 1];
57fa1d09 265
db2f8a2e 266 (void) strncpy(tag, word, l);
de9b34b6 267 tag[l] = '\0';
57fa1d09 268
4df4fd11 269 r = device_add_tag(device, tag);
57fa1d09 270 if (r < 0)
c7d54dae 271 return log_device_debug_errno(device, r, "sd-device: Failed to add tag '%s': %m", tag);
57fa1d09
TG
272 }
273 } else {
274 r = device_add_property_internal(device, key, value);
275 if (r < 0)
c7d54dae 276 return log_device_debug_errno(device, r, "sd-device: Failed to add property '%s=%s': %m", key, value);
57fa1d09
TG
277 }
278
279 return 0;
280}
281
282static const char* const device_action_table[_DEVICE_ACTION_MAX] = {
283 [DEVICE_ACTION_ADD] = "add",
284 [DEVICE_ACTION_REMOVE] = "remove",
285 [DEVICE_ACTION_CHANGE] = "change",
286 [DEVICE_ACTION_MOVE] = "move",
287 [DEVICE_ACTION_ONLINE] = "online",
288 [DEVICE_ACTION_OFFLINE] = "offline",
9a39e1ce
LP
289 [DEVICE_ACTION_BIND] = "bind",
290 [DEVICE_ACTION_UNBIND] = "unbind",
57fa1d09
TG
291};
292
293DEFINE_STRING_TABLE_LOOKUP(device_action, DeviceAction);
294
295static int device_append(sd_device *device, char *key, const char **_major, const char **_minor, uint64_t *_seqnum,
296 DeviceAction *_action) {
297 DeviceAction action = _DEVICE_ACTION_INVALID;
298 uint64_t seqnum = 0;
299 const char *major = NULL, *minor = NULL;
300 char *value;
301 int r;
302
303 assert(device);
304 assert(key);
305 assert(_major);
306 assert(_minor);
307 assert(_seqnum);
308 assert(_action);
309
310 value = strchr(key, '=');
311 if (!value) {
c7d54dae 312 log_device_debug(device, "sd-device: Not a key-value pair: '%s'", key);
57fa1d09
TG
313 return -EINVAL;
314 }
315
316 *value = '\0';
317
318 value++;
319
320 if (streq(key, "MAJOR"))
321 major = value;
322 else if (streq(key, "MINOR"))
323 minor = value;
324 else {
325 if (streq(key, "ACTION")) {
326 action = device_action_from_string(value);
327 if (action == _DEVICE_ACTION_INVALID)
328 return -EINVAL;
56c886dc
DT
329 /* FIXME: remove once we no longer flush previuos state for each action */
330 if (action == DEVICE_ACTION_BIND || action == DEVICE_ACTION_UNBIND) {
331 static bool warned;
332 if (!warned) {
333 log_device_debug(device, "sd-device: ignoring actions 'bind' and 'unbind'");
334 warned = true;
335 }
336 return -EINVAL;
337 }
57fa1d09
TG
338 } else if (streq(key, "SEQNUM")) {
339 r = safe_atou64(value, &seqnum);
340 if (r < 0)
341 return r;
342 else if (seqnum == 0)
343 /* kernel only sends seqnum > 0 */
344 return -EINVAL;
345 }
346
401cb614 347 r = device_amend(device, key, value);
57fa1d09
TG
348 if (r < 0)
349 return r;
350 }
351
352 if (major != 0)
353 *_major = major;
354
355 if (minor != 0)
356 *_minor = minor;
357
358 if (action != _DEVICE_ACTION_INVALID)
359 *_action = action;
360
361 if (seqnum > 0)
362 *_seqnum = seqnum;
363
364 return 0;
365}
366
367void device_seal(sd_device *device) {
368 assert(device);
369
370 device->sealed = true;
371}
372
373static int device_verify(sd_device *device, DeviceAction action, uint64_t seqnum) {
374 assert(device);
375
376 if (!device->devpath || !device->subsystem || action == _DEVICE_ACTION_INVALID || seqnum == 0) {
c7d54dae 377 log_device_debug(device, "sd-device: Device created from strv or nulstr lacks devpath, subsystem, action or seqnum.");
57fa1d09
TG
378 return -EINVAL;
379 }
380
381 device->sealed = true;
382
383 return 0;
384}
385
386int device_new_from_strv(sd_device **ret, char **strv) {
4afd3348 387 _cleanup_(sd_device_unrefp) sd_device *device = NULL;
57fa1d09
TG
388 char **key;
389 const char *major = NULL, *minor = NULL;
390 DeviceAction action = _DEVICE_ACTION_INVALID;
8d578a2e 391 uint64_t seqnum = 0;
57fa1d09
TG
392 int r;
393
394 assert(ret);
395 assert(strv);
396
397 r = device_new_aux(&device);
398 if (r < 0)
399 return r;
400
401 STRV_FOREACH(key, strv) {
402 r = device_append(device, *key, &major, &minor, &seqnum, &action);
403 if (r < 0)
404 return r;
405 }
406
407 if (major) {
408 r = device_set_devnum(device, major, minor);
409 if (r < 0)
c7d54dae 410 return log_device_debug_errno(device, r, "sd-device: Failed to set devnum %s:%s: %m", major, minor);
57fa1d09
TG
411 }
412
413 r = device_verify(device, action, seqnum);
414 if (r < 0)
415 return r;
416
1cc6c93a 417 *ret = TAKE_PTR(device);
57fa1d09
TG
418
419 return 0;
420}
421
422int device_new_from_nulstr(sd_device **ret, uint8_t *nulstr, size_t len) {
4afd3348 423 _cleanup_(sd_device_unrefp) sd_device *device = NULL;
57fa1d09
TG
424 const char *major = NULL, *minor = NULL;
425 DeviceAction action = _DEVICE_ACTION_INVALID;
8d578a2e 426 uint64_t seqnum = 0;
57fa1d09
TG
427 unsigned i = 0;
428 int r;
429
430 assert(ret);
431 assert(nulstr);
432 assert(len);
433
434 r = device_new_aux(&device);
435 if (r < 0)
436 return r;
437
438 while (i < len) {
439 char *key;
440 const char *end;
441
442 key = (char*)&nulstr[i];
443 end = memchr(key, '\0', len - i);
444 if (!end) {
c7d54dae 445 log_device_debug(device, "sd-device: Failed to parse nulstr");
57fa1d09
TG
446 return -EINVAL;
447 }
448 i += end - key + 1;
449
450 r = device_append(device, key, &major, &minor, &seqnum, &action);
451 if (r < 0)
452 return r;
453 }
454
455 if (major) {
456 r = device_set_devnum(device, major, minor);
457 if (r < 0)
c7d54dae 458 return log_device_debug_errno(device, r, "sd-device: Failed to set devnum %s:%s: %m", major, minor);
57fa1d09
TG
459 }
460
461 r = device_verify(device, action, seqnum);
462 if (r < 0)
463 return r;
464
1cc6c93a 465 *ret = TAKE_PTR(device);
57fa1d09
TG
466
467 return 0;
468}
469
470static int device_update_properties_bufs(sd_device *device) {
471 const char *val, *prop;
ccc1002a
TG
472 _cleanup_free_ char **buf_strv = NULL;
473 _cleanup_free_ uint8_t *buf_nulstr = NULL;
d854ba50 474 size_t allocated_nulstr = 0;
ccc1002a 475 size_t nulstr_len = 0, num = 0, i = 0;
57fa1d09
TG
476
477 assert(device);
478
aa20f49a
TG
479 if (!device->properties_buf_outdated)
480 return 0;
481
57fa1d09
TG
482 FOREACH_DEVICE_PROPERTY(device, prop, val) {
483 size_t len = 0;
484
485 len = strlen(prop) + 1 + strlen(val);
486
487 buf_nulstr = GREEDY_REALLOC0(buf_nulstr, allocated_nulstr, nulstr_len + len + 2);
488 if (!buf_nulstr)
489 return -ENOMEM;
490
57fa1d09
TG
491 strscpyl((char *)buf_nulstr + nulstr_len, len + 1, prop, "=", val, NULL);
492 nulstr_len += len + 1;
d854ba50 493 ++num;
57fa1d09
TG
494 }
495
ccc1002a
TG
496 /* build buf_strv from buf_nulstr */
497 buf_strv = new0(char *, num + 1);
498 if (!buf_strv)
499 return -ENOMEM;
d854ba50 500
d854ba50 501 NULSTR_FOREACH(val, (char*) buf_nulstr) {
ccc1002a 502 buf_strv[i] = (char *) val;
d854ba50
MP
503 assert(i < num);
504 i++;
505 }
57fa1d09 506
f9ecfd3b 507 free_and_replace(device->properties_nulstr, buf_nulstr);
ccc1002a 508 device->properties_nulstr_len = nulstr_len;
f9ecfd3b 509 free_and_replace(device->properties_strv, buf_strv);
ccc1002a 510
57fa1d09
TG
511 device->properties_buf_outdated = false;
512
513 return 0;
514}
515
516int device_get_properties_nulstr(sd_device *device, const uint8_t **nulstr, size_t *len) {
517 int r;
518
519 assert(device);
520 assert(nulstr);
521 assert(len);
522
aa20f49a
TG
523 r = device_update_properties_bufs(device);
524 if (r < 0)
525 return r;
57fa1d09
TG
526
527 *nulstr = device->properties_nulstr;
528 *len = device->properties_nulstr_len;
529
530 return 0;
531}
532
533int device_get_properties_strv(sd_device *device, char ***strv) {
534 int r;
535
536 assert(device);
537 assert(strv);
538
539 r = device_update_properties_bufs(device);
540 if (r < 0)
541 return r;
542
543 *strv = device->properties_strv;
544
545 return 0;
546}
547
548int device_get_devlink_priority(sd_device *device, int *priority) {
549 int r;
550
551 assert(device);
552 assert(priority);
553
554 r = device_read_db(device);
555 if (r < 0)
556 return r;
557
558 *priority = device->devlink_priority;
559
560 return 0;
561}
562
563int device_get_watch_handle(sd_device *device, int *handle) {
564 int r;
565
566 assert(device);
57fa1d09
TG
567
568 r = device_read_db(device);
569 if (r < 0)
570 return r;
571
dcfbde3a
YW
572 if (device->watch_handle < 0)
573 return -ENOENT;
574
78ffb476
YW
575 if (handle)
576 *handle = device->watch_handle;
57fa1d09
TG
577
578 return 0;
579}
580
581void device_set_watch_handle(sd_device *device, int handle) {
582 assert(device);
583
584 device->watch_handle = handle;
585}
586
587int device_rename(sd_device *device, const char *name) {
588 _cleanup_free_ char *dirname = NULL;
589 char *new_syspath;
590 const char *interface;
591 int r;
592
593 assert(device);
594 assert(name);
595
596 dirname = dirname_malloc(device->syspath);
597 if (!dirname)
598 return -ENOMEM;
599
600 new_syspath = strjoina(dirname, "/", name);
601
602 /* the user must trust that the new name is correct */
603 r = device_set_syspath(device, new_syspath, false);
604 if (r < 0)
605 return r;
606
607 r = sd_device_get_property_value(device, "INTERFACE", &interface);
608 if (r >= 0) {
f7b1c8d1
EV
609 /* like DEVPATH_OLD, INTERFACE_OLD is not saved to the db, but only stays around for the current event */
610 r = device_add_property_internal(device, "INTERFACE_OLD", interface);
57fa1d09
TG
611 if (r < 0)
612 return r;
613
f7b1c8d1 614 r = device_add_property_internal(device, "INTERFACE", name);
57fa1d09
TG
615 if (r < 0)
616 return r;
617 } else if (r != -ENOENT)
618 return r;
619
620 return 0;
621}
622
623int device_shallow_clone(sd_device *old_device, sd_device **new_device) {
4afd3348 624 _cleanup_(sd_device_unrefp) sd_device *ret = NULL;
57fa1d09
TG
625 int r;
626
627 assert(old_device);
628 assert(new_device);
629
630 r = device_new_aux(&ret);
631 if (r < 0)
632 return r;
633
634 r = device_set_syspath(ret, old_device->syspath, false);
635 if (r < 0)
636 return r;
637
638 r = device_set_subsystem(ret, old_device->subsystem);
639 if (r < 0)
640 return r;
641
642 ret->devnum = old_device->devnum;
643
1cc6c93a 644 *new_device = TAKE_PTR(ret);
57fa1d09
TG
645
646 return 0;
647}
648
649int device_clone_with_db(sd_device *old_device, sd_device **new_device) {
4afd3348 650 _cleanup_(sd_device_unrefp) sd_device *ret = NULL;
57fa1d09
TG
651 int r;
652
653 assert(old_device);
654 assert(new_device);
655
656 r = device_shallow_clone(old_device, &ret);
657 if (r < 0)
658 return r;
659
660 r = device_read_db(ret);
661 if (r < 0)
662 return r;
663
664 ret->sealed = true;
665
1cc6c93a 666 *new_device = TAKE_PTR(ret);
57fa1d09
TG
667
668 return 0;
669}
670
671int device_new_from_synthetic_event(sd_device **new_device, const char *syspath, const char *action) {
4afd3348 672 _cleanup_(sd_device_unrefp) sd_device *ret = NULL;
57fa1d09
TG
673 int r;
674
675 assert(new_device);
676 assert(syspath);
677 assert(action);
678
679 r = sd_device_new_from_syspath(&ret, syspath);
680 if (r < 0)
681 return r;
682
683 r = device_read_uevent_file(ret);
684 if (r < 0)
685 return r;
686
687 r = device_add_property_internal(ret, "ACTION", action);
688 if (r < 0)
689 return r;
690
1cc6c93a 691 *new_device = TAKE_PTR(ret);
57fa1d09
TG
692
693 return 0;
694}
695
ad5944d7
YW
696int device_new_from_stat_rdev(sd_device **ret, const struct stat *st) {
697 char type;
698
699 assert(ret);
700 assert(st);
701
702 if (S_ISBLK(st->st_mode))
703 type = 'b';
704 else if (S_ISCHR(st->st_mode))
705 type = 'c';
706 else
707 return -ENOTTY;
708
709 return sd_device_new_from_devnum(ret, type, st->st_rdev);
710}
711
57fa1d09
TG
712int device_copy_properties(sd_device *device_dst, sd_device *device_src) {
713 const char *property, *value;
714 int r;
715
716 assert(device_dst);
717 assert(device_src);
718
719 FOREACH_DEVICE_PROPERTY(device_src, property, value) {
720 r = device_add_property(device_dst, property, value);
721 if (r < 0)
722 return r;
723 }
724
725 return 0;
726}
727
728void device_cleanup_tags(sd_device *device) {
729 assert(device);
730
731 set_free_free(device->tags);
732 device->tags = NULL;
733 device->property_tags_outdated = true;
313cefa1 734 device->tags_generation++;
57fa1d09
TG
735}
736
737void device_cleanup_devlinks(sd_device *device) {
738 assert(device);
739
740 set_free_free(device->devlinks);
741 device->devlinks = NULL;
742 device->property_devlinks_outdated = true;
313cefa1 743 device->devlinks_generation++;
57fa1d09
TG
744}
745
746void device_remove_tag(sd_device *device, const char *tag) {
747 assert(device);
748 assert(tag);
749
750 free(set_remove(device->tags, tag));
751 device->property_tags_outdated = true;
313cefa1 752 device->tags_generation++;
57fa1d09
TG
753}
754
755static int device_tag(sd_device *device, const char *tag, bool add) {
756 const char *id;
757 char *path;
758 int r;
759
760 assert(device);
761 assert(tag);
762
763 r = device_get_id_filename(device, &id);
764 if (r < 0)
765 return r;
766
767 path = strjoina("/run/udev/tags/", tag, "/", id);
768
769 if (add) {
770 r = touch_file(path, true, USEC_INFINITY, UID_INVALID, GID_INVALID, 0444);
771 if (r < 0)
772 return r;
773 } else {
774 r = unlink(path);
775 if (r < 0 && errno != ENOENT)
776 return -errno;
777 }
778
779 return 0;
780}
781
782int device_tag_index(sd_device *device, sd_device *device_old, bool add) {
783 const char *tag;
784 int r = 0, k;
785
786 if (add && device_old) {
787 /* delete possible left-over tags */
788 FOREACH_DEVICE_TAG(device_old, tag) {
789 if (!sd_device_has_tag(device, tag)) {
790 k = device_tag(device_old, tag, false);
791 if (r >= 0 && k < 0)
792 r = k;
793 }
794 }
795 }
796
797 FOREACH_DEVICE_TAG(device, tag) {
798 k = device_tag(device, tag, add);
799 if (r >= 0 && k < 0)
800 r = k;
801 }
802
803 return r;
804}
805
806static bool device_has_info(sd_device *device) {
807 assert(device);
808
809 if (!set_isempty(device->devlinks))
810 return true;
811
812 if (device->devlink_priority != 0)
813 return true;
814
815 if (!ordered_hashmap_isempty(device->properties_db))
816 return true;
817
818 if (!set_isempty(device->tags))
819 return true;
820
821 if (device->watch_handle >= 0)
822 return true;
823
824 return false;
825}
826
827void device_set_db_persist(sd_device *device) {
828 assert(device);
829
830 device->db_persist = true;
831}
832
833int device_update_db(sd_device *device) {
834 const char *id;
835 char *path;
836 _cleanup_fclose_ FILE *f = NULL;
837 _cleanup_free_ char *path_tmp = NULL;
838 bool has_info;
839 int r;
840
841 assert(device);
842
843 has_info = device_has_info(device);
844
845 r = device_get_id_filename(device, &id);
846 if (r < 0)
847 return r;
848
849 path = strjoina("/run/udev/data/", id);
850
851 /* do not store anything for otherwise empty devices */
852 if (!has_info && major(device->devnum) == 0 && device->ifindex == 0) {
853 r = unlink(path);
854 if (r < 0 && errno != ENOENT)
855 return -errno;
856
857 return 0;
858 }
859
860 /* write a database file */
861 r = mkdir_parents(path, 0755);
862 if (r < 0)
863 return r;
864
865 r = fopen_temporary(path, &f, &path_tmp);
866 if (r < 0)
867 return r;
868
869 /*
870 * set 'sticky' bit to indicate that we should not clean the
871 * database when we transition from initramfs to the real root
872 */
873 if (device->db_persist) {
874 r = fchmod(fileno(f), 01644);
875 if (r < 0) {
876 r = -errno;
877 goto fail;
878 }
879 } else {
880 r = fchmod(fileno(f), 0644);
881 if (r < 0) {
882 r = -errno;
883 goto fail;
884 }
885 }
886
887 if (has_info) {
888 const char *property, *value, *tag;
889 Iterator i;
890
891 if (major(device->devnum) > 0) {
892 const char *devlink;
893
894 FOREACH_DEVICE_DEVLINK(device, devlink)
fbd0b64f 895 fprintf(f, "S:%s\n", devlink + STRLEN("/dev/"));
57fa1d09
TG
896
897 if (device->devlink_priority != 0)
898 fprintf(f, "L:%i\n", device->devlink_priority);
899
900 if (device->watch_handle >= 0)
901 fprintf(f, "W:%i\n", device->watch_handle);
902 }
903
904 if (device->usec_initialized > 0)
905 fprintf(f, "I:"USEC_FMT"\n", device->usec_initialized);
906
907 ORDERED_HASHMAP_FOREACH_KEY(value, property, device->properties_db, i)
908 fprintf(f, "E:%s=%s\n", property, value);
909
910 FOREACH_DEVICE_TAG(device, tag)
911 fprintf(f, "G:%s\n", tag);
912 }
913
914 r = fflush_and_check(f);
915 if (r < 0)
916 goto fail;
917
918 r = rename(path_tmp, path);
919 if (r < 0) {
920 r = -errno;
921 goto fail;
922 }
923
c7d54dae
YW
924 log_device_debug(device, "sd-device: Created %s file '%s' for '%s'", has_info ? "db" : "empty",
925 path, device->devpath);
57fa1d09
TG
926
927 return 0;
928
929fail:
dacd6cee
LP
930 (void) unlink(path);
931 (void) unlink(path_tmp);
57fa1d09 932
c7d54dae 933 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
934}
935
936int device_delete_db(sd_device *device) {
937 const char *id;
938 char *path;
939 int r;
940
941 assert(device);
942
943 r = device_get_id_filename(device, &id);
944 if (r < 0)
945 return r;
946
947 path = strjoina("/run/udev/data/", id);
948
949 r = unlink(path);
950 if (r < 0 && errno != ENOENT)
951 return -errno;
952
953 return 0;
954}