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