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