Branch data 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 : 68 : uint64_t device_get_properties_generation(sd_device *device) {
75 [ - + ]: 68 : assert(device);
76 : :
77 : 68 : 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 : 60 : uint64_t device_get_devlinks_generation(sd_device *device) {
87 [ - + ]: 60 : assert(device);
88 : :
89 : 60 : 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 : 32 : int device_get_action(sd_device *device, DeviceAction *action) {
187 [ - + ]: 32 : assert(device);
188 : :
189 [ + - ]: 32 : if (device->action < 0)
190 : 32 : 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 : 528 : int device_new_from_stat_rdev(sd_device **ret, const struct stat *st) {
719 : : char type;
720 : :
721 [ - + ]: 528 : assert(ret);
722 [ - + ]: 528 : assert(st);
723 : :
724 [ + + ]: 528 : if (S_ISBLK(st->st_mode))
725 : 484 : type = 'b';
726 [ + - ]: 44 : else if (S_ISCHR(st->st_mode))
727 : 44 : type = 'c';
728 : : else
729 : 0 : return -ENOTTY;
730 : :
731 : 528 : 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 [ + + + + ]: 80 : 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 : }
|