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/ioctl.h>
6 : : #include <sys/types.h>
7 : :
8 : : #include "sd-device.h"
9 : :
10 : : #include "alloc-util.h"
11 : : #include "device-internal.h"
12 : : #include "device-private.h"
13 : : #include "device-util.h"
14 : : #include "dirent-util.h"
15 : : #include "fd-util.h"
16 : : #include "fileio.h"
17 : : #include "fs-util.h"
18 : : #include "hashmap.h"
19 : : #include "macro.h"
20 : : #include "parse-util.h"
21 : : #include "path-util.h"
22 : : #include "set.h"
23 : : #include "socket-util.h"
24 : : #include "stat-util.h"
25 : : #include "stdio-util.h"
26 : : #include "string-util.h"
27 : : #include "strv.h"
28 : : #include "strxcpyx.h"
29 : : #include "util.h"
30 : :
31 : 31328 : int device_new_aux(sd_device **ret) {
32 : : sd_device *device;
33 : :
34 [ - + ]: 31328 : assert(ret);
35 : :
36 : 31328 : device = new(sd_device, 1);
37 [ - + ]: 31328 : if (!device)
38 : 0 : return -ENOMEM;
39 : :
40 : 31328 : *device = (sd_device) {
41 : : .n_ref = 1,
42 : : .watch_handle = -1,
43 : : .devmode = (mode_t) -1,
44 : : .devuid = (uid_t) -1,
45 : : .devgid = (gid_t) -1,
46 : : .action = _DEVICE_ACTION_INVALID,
47 : : };
48 : :
49 : 31328 : *ret = device;
50 : 31328 : return 0;
51 : : }
52 : :
53 : 31328 : static sd_device *device_free(sd_device *device) {
54 [ - + ]: 31328 : assert(device);
55 : :
56 : 31328 : sd_device_unref(device->parent);
57 : 31328 : free(device->syspath);
58 : 31328 : free(device->sysname);
59 : 31328 : free(device->devtype);
60 : 31328 : free(device->devname);
61 : 31328 : free(device->subsystem);
62 : 31328 : free(device->driver_subsystem);
63 : 31328 : free(device->driver);
64 : 31328 : free(device->id_filename);
65 : 31328 : free(device->properties_strv);
66 : 31328 : free(device->properties_nulstr);
67 : :
68 : 31328 : ordered_hashmap_free_free_free(device->properties);
69 : 31328 : ordered_hashmap_free_free_free(device->properties_db);
70 : 31328 : hashmap_free_free_free(device->sysattr_values);
71 : 31328 : set_free_free(device->sysattrs);
72 : 31328 : set_free_free(device->tags);
73 : 31328 : set_free_free(device->devlinks);
74 : :
75 : 31328 : return mfree(device);
76 : : }
77 : :
78 [ + + - + : 124008 : DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_device, sd_device, device_free);
+ + ]
79 : :
80 : 219540 : int device_add_property_aux(sd_device *device, const char *_key, const char *_value, bool db) {
81 : : OrderedHashmap **properties;
82 : :
83 [ - + ]: 219540 : assert(device);
84 [ - + ]: 219540 : assert(_key);
85 : :
86 [ + + ]: 219540 : if (db)
87 : 49244 : properties = &device->properties_db;
88 : : else
89 : 170296 : properties = &device->properties;
90 : :
91 [ + + ]: 219540 : if (_value) {
92 [ + - + - : 218228 : _cleanup_free_ char *key = NULL, *value = NULL, *old_key = NULL, *old_value = NULL;
+ - + - ]
93 : : int r;
94 : :
95 : 218228 : r = ordered_hashmap_ensure_allocated(properties, &string_hash_ops);
96 [ - + ]: 218228 : if (r < 0)
97 : 0 : return r;
98 : :
99 : 218228 : key = strdup(_key);
100 [ - + ]: 218228 : if (!key)
101 : 0 : return -ENOMEM;
102 : :
103 : 218228 : value = strdup(_value);
104 [ - + ]: 218228 : if (!value)
105 : 0 : return -ENOMEM;
106 : :
107 : 218228 : old_value = ordered_hashmap_get2(*properties, key, (void**) &old_key);
108 : :
109 : 218228 : r = ordered_hashmap_replace(*properties, key, value);
110 [ - + ]: 218228 : if (r < 0)
111 : 0 : return r;
112 : :
113 : 218228 : key = NULL;
114 : 218228 : value = NULL;
115 : : } else {
116 : 1312 : _cleanup_free_ char *key = NULL;
117 : 2624 : _cleanup_free_ char *value = NULL;
118 : :
119 : 1312 : value = ordered_hashmap_remove2(*properties, _key, (void**) &key);
120 : : }
121 : :
122 [ + + ]: 219540 : if (!db) {
123 : 170296 : device->properties_generation++;
124 : 170296 : device->properties_buf_outdated = true;
125 : : }
126 : :
127 : 219540 : return 0;
128 : : }
129 : :
130 : 121052 : int device_add_property_internal(sd_device *device, const char *key, const char *value) {
131 : 121052 : return device_add_property_aux(device, key, value, false);
132 : : }
133 : :
134 : 31328 : int device_set_syspath(sd_device *device, const char *_syspath, bool verify) {
135 : 31328 : _cleanup_free_ char *syspath = NULL;
136 : : const char *devpath;
137 : : int r;
138 : :
139 [ - + ]: 31328 : assert(device);
140 [ - + ]: 31328 : assert(_syspath);
141 : :
142 : : /* must be a subdirectory of /sys */
143 [ - + ]: 31328 : if (!path_startswith(_syspath, "/sys/"))
144 [ # # ]: 0 : return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
145 : : "sd-device: Syspath '%s' is not a subdirectory of /sys",
146 : : _syspath);
147 : :
148 [ + - ]: 31328 : if (verify) {
149 : 31328 : r = chase_symlinks(_syspath, NULL, 0, &syspath);
150 [ - + ]: 31328 : if (r == -ENOENT)
151 : 0 : return -ENODEV; /* the device does not exist (any more?) */
152 [ - + ]: 31328 : if (r < 0)
153 [ # # ]: 0 : return log_debug_errno(r, "sd-device: Failed to get target of '%s': %m", _syspath);
154 : :
155 [ - + ]: 31328 : if (!path_startswith(syspath, "/sys")) {
156 [ # # # # ]: 0 : _cleanup_free_ char *real_sys = NULL, *new_syspath = NULL;
157 : : char *p;
158 : :
159 : : /* /sys is a symlink to somewhere sysfs is mounted on? In that case, we convert the path to real sysfs to "/sys". */
160 : 0 : r = chase_symlinks("/sys", NULL, 0, &real_sys);
161 [ # # ]: 0 : if (r < 0)
162 [ # # ]: 0 : return log_debug_errno(r, "sd-device: Failed to chase symlink /sys: %m");
163 : :
164 : 0 : p = path_startswith(syspath, real_sys);
165 [ # # ]: 0 : if (!p)
166 [ # # ]: 0 : return log_debug_errno(SYNTHETIC_ERRNO(ENODEV),
167 : : "sd-device: Canonicalized path '%s' does not starts with sysfs mount point '%s'",
168 : : syspath, real_sys);
169 : :
170 : 0 : new_syspath = path_join("/sys", p);
171 [ # # ]: 0 : if (!new_syspath)
172 : 0 : return -ENOMEM;
173 : :
174 : 0 : free_and_replace(syspath, new_syspath);
175 : 0 : path_simplify(syspath, false);
176 : : }
177 : :
178 [ + + ]: 31328 : if (path_startswith(syspath, "/sys/devices/")) {
179 : : char *path;
180 : :
181 : : /* all 'devices' require an 'uevent' file */
182 [ + + + - : 132760 : path = strjoina(syspath, "/uevent");
- + - + +
+ + - ]
183 : 26552 : r = access(path, F_OK);
184 [ + + ]: 26552 : if (r < 0) {
185 [ + - ]: 12 : if (errno == ENOENT)
186 : : /* this is not a valid device */
187 : 12 : return -ENODEV;
188 : :
189 [ # # ]: 0 : return log_debug_errno(errno, "sd-device: %s does not have an uevent file: %m", syspath);
190 : : }
191 : : } else {
192 : : /* everything else just needs to be a directory */
193 [ + + ]: 4776 : if (!is_dir(syspath, false))
194 : 44 : return -ENODEV;
195 : : }
196 : : } else {
197 : 0 : syspath = strdup(_syspath);
198 [ # # ]: 0 : if (!syspath)
199 : 0 : return -ENOMEM;
200 : : }
201 : :
202 : 31272 : devpath = syspath + STRLEN("/sys");
203 : :
204 [ - + ]: 31272 : if (devpath[0] == '\0')
205 : : /* '/sys' alone is not a valid device path */
206 : 0 : return -ENODEV;
207 : :
208 : 31272 : r = device_add_property_internal(device, "DEVPATH", devpath);
209 [ - + ]: 31272 : if (r < 0)
210 : 0 : return r;
211 : :
212 : 31272 : free_and_replace(device->syspath, syspath);
213 : 31272 : device->devpath = devpath;
214 : 31272 : return 0;
215 : : }
216 : :
217 : 31328 : _public_ int sd_device_new_from_syspath(sd_device **ret, const char *syspath) {
218 : 31328 : _cleanup_(sd_device_unrefp) sd_device *device = NULL;
219 : : int r;
220 : :
221 [ - + - + ]: 31328 : assert_return(ret, -EINVAL);
222 [ - + - + ]: 31328 : assert_return(syspath, -EINVAL);
223 : :
224 : 31328 : r = device_new_aux(&device);
225 [ - + ]: 31328 : if (r < 0)
226 : 0 : return r;
227 : :
228 : 31328 : r = device_set_syspath(device, syspath, true);
229 [ + + ]: 31328 : if (r < 0)
230 : 56 : return r;
231 : :
232 : 31272 : *ret = TAKE_PTR(device);
233 : 31272 : return 0;
234 : : }
235 : :
236 : 2424 : _public_ int sd_device_new_from_devnum(sd_device **ret, char type, dev_t devnum) {
237 : : char *syspath;
238 : : char id[DECIMAL_STR_MAX(unsigned) * 2 + 1];
239 : :
240 [ - + - + ]: 2424 : assert_return(ret, -EINVAL);
241 [ + - - + : 2424 : assert_return(IN_SET(type, 'b', 'c'), -EINVAL);
- + ]
242 : :
243 : : /* use /sys/dev/{block,char}/<maj>:<min> link */
244 [ - + ]: 2424 : xsprintf(id, "%u:%u", major(devnum), minor(devnum));
245 : :
246 [ + + + + : 21816 : syspath = strjoina("/sys/dev/", (type == 'b' ? "block" : "char"), "/", id);
+ - - + -
+ + + +
- ]
247 : :
248 : 2424 : return sd_device_new_from_syspath(ret, syspath);
249 : : }
250 : :
251 : 652 : _public_ int sd_device_new_from_subsystem_sysname(sd_device **ret, const char *subsystem, const char *sysname) {
252 : : char *name, *syspath;
253 : 652 : size_t len = 0;
254 : :
255 [ - + - + ]: 652 : assert_return(ret, -EINVAL);
256 [ - + - + ]: 652 : assert_return(subsystem, -EINVAL);
257 [ - + - + ]: 652 : assert_return(sysname, -EINVAL);
258 : :
259 [ + + ]: 652 : if (streq(subsystem, "subsystem")) {
260 [ + + + - : 20 : syspath = strjoina("/sys/subsystem/", sysname);
- + - + +
+ + - ]
261 [ - + ]: 4 : if (access(syspath, F_OK) >= 0)
262 : 0 : return sd_device_new_from_syspath(ret, syspath);
263 : :
264 [ + + + - : 20 : syspath = strjoina("/sys/bus/", sysname);
- + - + +
+ + - ]
265 [ + - ]: 4 : if (access(syspath, F_OK) >= 0)
266 : 4 : return sd_device_new_from_syspath(ret, syspath);
267 : :
268 [ # # # # : 0 : syspath = strjoina("/sys/class/", sysname);
# # # # #
# # # ]
269 [ # # ]: 0 : if (access(syspath, F_OK) >= 0)
270 : 0 : return sd_device_new_from_syspath(ret, syspath);
271 [ + + ]: 648 : } else if (streq(subsystem, "module")) {
272 [ + + + - : 460 : syspath = strjoina("/sys/module/", sysname);
- + - + +
+ + - ]
273 [ + - ]: 92 : if (access(syspath, F_OK) >= 0)
274 : 92 : return sd_device_new_from_syspath(ret, syspath);
275 [ + + ]: 556 : } else if (streq(subsystem, "drivers")) {
276 : : char subsys[PATH_MAX];
277 : : char *driver;
278 : :
279 : 4 : strscpy(subsys, sizeof(subsys), sysname);
280 : 4 : driver = strchr(subsys, ':');
281 [ + - ]: 4 : if (driver) {
282 : 4 : driver[0] = '\0';
283 : 4 : driver++;
284 : :
285 [ + + + - : 36 : syspath = strjoina("/sys/subsystem/", subsys, "/drivers/", driver);
- + - + +
+ + - ]
286 [ - + ]: 4 : if (access(syspath, F_OK) >= 0)
287 : 4 : return sd_device_new_from_syspath(ret, syspath);
288 : :
289 [ + + + - : 36 : syspath = strjoina("/sys/bus/", subsys, "/drivers/", driver);
- + - + +
+ + - ]
290 [ + - ]: 4 : if (access(syspath, F_OK) >= 0)
291 : 4 : return sd_device_new_from_syspath(ret, syspath);
292 : : }
293 : : }
294 : :
295 : : /* translate sysname back to sysfs filename */
296 : 552 : name = strdupa(sysname);
297 [ + + ]: 4756 : while (name[len] != '\0') {
298 [ - + ]: 4204 : if (name[len] == '/')
299 : 0 : name[len] = '!';
300 : :
301 : 4204 : len++;
302 : : }
303 : :
304 [ + + + - : 4968 : syspath = strjoina("/sys/subsystem/", subsystem, "/devices/", name);
- + - + +
+ + - ]
305 [ - + ]: 552 : if (access(syspath, F_OK) >= 0)
306 : 0 : return sd_device_new_from_syspath(ret, syspath);
307 : :
308 [ + + + - : 4968 : syspath = strjoina("/sys/bus/", subsystem, "/devices/", name);
- + - + +
+ + - ]
309 [ - + ]: 552 : if (access(syspath, F_OK) >= 0)
310 : 0 : return sd_device_new_from_syspath(ret, syspath);
311 : :
312 [ + + + - : 4968 : syspath = strjoina("/sys/class/", subsystem, "/", name);
- + - + +
+ + - ]
313 [ + + ]: 552 : if (access(syspath, F_OK) >= 0)
314 : 548 : return sd_device_new_from_syspath(ret, syspath);
315 : :
316 [ + + + - : 36 : syspath = strjoina("/sys/firmware/", subsystem, "/", sysname);
- + - + +
+ + - ]
317 [ - + ]: 4 : if (access(syspath, F_OK) >= 0)
318 : 0 : return sd_device_new_from_syspath(ret, syspath);
319 : :
320 : 4 : return -ENODEV;
321 : : }
322 : :
323 : 2828 : int device_set_devtype(sd_device *device, const char *_devtype) {
324 : 2828 : _cleanup_free_ char *devtype = NULL;
325 : : int r;
326 : :
327 [ - + ]: 2828 : assert(device);
328 [ - + ]: 2828 : assert(_devtype);
329 : :
330 : 2828 : devtype = strdup(_devtype);
331 [ - + ]: 2828 : if (!devtype)
332 : 0 : return -ENOMEM;
333 : :
334 : 2828 : r = device_add_property_internal(device, "DEVTYPE", devtype);
335 [ - + ]: 2828 : if (r < 0)
336 : 0 : return r;
337 : :
338 : 2828 : free_and_replace(device->devtype, devtype);
339 : :
340 : 2828 : return 0;
341 : : }
342 : :
343 : 500 : int device_set_ifindex(sd_device *device, const char *_ifindex) {
344 : : int ifindex, r;
345 : :
346 [ - + ]: 500 : assert(device);
347 [ - + ]: 500 : assert(_ifindex);
348 : :
349 : 500 : r = parse_ifindex(_ifindex, &ifindex);
350 [ - + ]: 500 : if (r < 0)
351 : 0 : return r;
352 : :
353 : 500 : r = device_add_property_internal(device, "IFINDEX", _ifindex);
354 [ - + ]: 500 : if (r < 0)
355 : 0 : return r;
356 : :
357 : 500 : device->ifindex = ifindex;
358 : :
359 : 500 : return 0;
360 : : }
361 : :
362 : 8240 : int device_set_devname(sd_device *device, const char *_devname) {
363 : 8240 : _cleanup_free_ char *devname = NULL;
364 : : int r;
365 : :
366 [ - + ]: 8240 : assert(device);
367 [ - + ]: 8240 : assert(_devname);
368 : :
369 [ + - ]: 8240 : if (_devname[0] != '/') {
370 : 8240 : r = asprintf(&devname, "/dev/%s", _devname);
371 [ - + ]: 8240 : if (r < 0)
372 : 0 : return -ENOMEM;
373 : : } else {
374 : 0 : devname = strdup(_devname);
375 [ # # ]: 0 : if (!devname)
376 : 0 : return -ENOMEM;
377 : : }
378 : :
379 : 8240 : r = device_add_property_internal(device, "DEVNAME", devname);
380 [ - + ]: 8240 : if (r < 0)
381 : 0 : return r;
382 : :
383 : 8240 : free_and_replace(device->devname, devname);
384 : :
385 : 8240 : return 0;
386 : : }
387 : :
388 : 252 : int device_set_devmode(sd_device *device, const char *_devmode) {
389 : : unsigned devmode;
390 : : int r;
391 : :
392 [ - + ]: 252 : assert(device);
393 [ - + ]: 252 : assert(_devmode);
394 : :
395 : 252 : r = safe_atou(_devmode, &devmode);
396 [ - + ]: 252 : if (r < 0)
397 : 0 : return r;
398 : :
399 [ - + ]: 252 : if (devmode > 07777)
400 : 0 : return -EINVAL;
401 : :
402 : 252 : r = device_add_property_internal(device, "DEVMODE", _devmode);
403 [ - + ]: 252 : if (r < 0)
404 : 0 : return r;
405 : :
406 : 252 : device->devmode = devmode;
407 : :
408 : 252 : return 0;
409 : : }
410 : :
411 : 8240 : int device_set_devnum(sd_device *device, const char *major, const char *minor) {
412 : 8240 : unsigned maj = 0, min = 0;
413 : : int r;
414 : :
415 [ - + ]: 8240 : assert(device);
416 [ - + ]: 8240 : assert(major);
417 : :
418 : 8240 : r = safe_atou(major, &maj);
419 [ - + ]: 8240 : if (r < 0)
420 : 0 : return r;
421 [ - + ]: 8240 : if (!maj)
422 : 0 : return 0;
423 : :
424 [ + - ]: 8240 : if (minor) {
425 : 8240 : r = safe_atou(minor, &min);
426 [ - + ]: 8240 : if (r < 0)
427 : 0 : return r;
428 : : }
429 : :
430 : 8240 : r = device_add_property_internal(device, "MAJOR", major);
431 [ - + ]: 8240 : if (r < 0)
432 : 0 : return r;
433 : :
434 [ + - ]: 8240 : if (minor) {
435 : 8240 : r = device_add_property_internal(device, "MINOR", minor);
436 [ - + ]: 8240 : if (r < 0)
437 : 0 : return r;
438 : : }
439 : :
440 : 8240 : device->devnum = makedev(maj, min);
441 : :
442 : 8240 : return 0;
443 : : }
444 : :
445 : 44556 : static int handle_uevent_line(sd_device *device, const char *key, const char *value, const char **major, const char **minor) {
446 : : int r;
447 : :
448 [ - + ]: 44556 : assert(device);
449 [ - + ]: 44556 : assert(key);
450 [ - + ]: 44556 : assert(value);
451 [ - + ]: 44556 : assert(major);
452 [ - + ]: 44556 : assert(minor);
453 : :
454 [ + + ]: 44556 : if (streq(key, "DEVTYPE")) {
455 : 2828 : r = device_set_devtype(device, value);
456 [ - + ]: 2828 : if (r < 0)
457 : 0 : return r;
458 [ + + ]: 41728 : } else if (streq(key, "IFINDEX")) {
459 : 500 : r = device_set_ifindex(device, value);
460 [ - + ]: 500 : if (r < 0)
461 : 0 : return r;
462 [ + + ]: 41228 : } else if (streq(key, "DEVNAME")) {
463 : 8240 : r = device_set_devname(device, value);
464 [ - + ]: 8240 : if (r < 0)
465 : 0 : return r;
466 [ + + ]: 32988 : } else if (streq(key, "DEVMODE")) {
467 : 252 : r = device_set_devmode(device, value);
468 [ - + ]: 252 : if (r < 0)
469 : 0 : return r;
470 [ + + ]: 32736 : } else if (streq(key, "MAJOR"))
471 : 8240 : *major = value;
472 [ + + ]: 24496 : else if (streq(key, "MINOR"))
473 : 8240 : *minor = value;
474 : : else {
475 : 16256 : r = device_add_property_internal(device, key, value);
476 [ - + ]: 16256 : if (r < 0)
477 : 0 : return r;
478 : : }
479 : :
480 : 44556 : return 0;
481 : : }
482 : :
483 : 125004 : int device_read_uevent_file(sd_device *device) {
484 : 125004 : _cleanup_free_ char *uevent = NULL;
485 : 125004 : const char *syspath, *key = NULL, *value = NULL, *major = NULL, *minor = NULL;
486 : : char *path;
487 : : size_t uevent_len;
488 : : unsigned i;
489 : : int r;
490 : :
491 : : enum {
492 : : PRE_KEY,
493 : : KEY,
494 : : PRE_VALUE,
495 : : VALUE,
496 : : INVALID_LINE,
497 : 125004 : } state = PRE_KEY;
498 : :
499 [ - + ]: 125004 : assert(device);
500 : :
501 [ + + - + ]: 125004 : if (device->uevent_loaded || device->sealed)
502 : 101312 : return 0;
503 : :
504 : 23692 : r = sd_device_get_syspath(device, &syspath);
505 [ - + ]: 23692 : if (r < 0)
506 : 0 : return r;
507 : :
508 [ + + + - : 118460 : path = strjoina(syspath, "/uevent");
- + - + +
+ + - ]
509 : :
510 : 23692 : r = read_full_file(path, &uevent, &uevent_len);
511 [ + + ]: 23692 : if (r == -EACCES) {
512 : : /* empty uevent files may be write-only */
513 : 3188 : device->uevent_loaded = true;
514 : 3188 : return 0;
515 : : }
516 [ - + ]: 20504 : if (r == -ENOENT)
517 : : /* some devices may not have uevent files, see set_syspath() */
518 : 0 : return 0;
519 [ - + ]: 20504 : if (r < 0)
520 [ # # # # : 0 : return log_device_debug_errno(device, r, "sd-device: Failed to read uevent file '%s': %m", path);
# # ]
521 : :
522 : 20504 : device->uevent_loaded = true;
523 : :
524 [ + + ]: 814012 : for (i = 0; i < uevent_len; i++)
525 [ + + + + : 793508 : switch (state) {
- ]
526 : 44700 : case PRE_KEY:
527 [ + + ]: 44700 : if (!strchr(NEWLINE, uevent[i])) {
528 : 44556 : key = &uevent[i];
529 : :
530 : 44556 : state = KEY;
531 : : }
532 : :
533 : 44700 : break;
534 : 297684 : case KEY:
535 [ + + ]: 297684 : if (uevent[i] == '=') {
536 : 44556 : uevent[i] = '\0';
537 : :
538 : 44556 : state = PRE_VALUE;
539 [ - + ]: 253128 : } else if (strchr(NEWLINE, uevent[i])) {
540 : 0 : uevent[i] = '\0';
541 [ # # # # : 0 : log_device_debug(device, "sd-device: Invalid uevent line '%s', ignoring", key);
# # ]
542 : :
543 : 0 : state = PRE_KEY;
544 : : }
545 : :
546 : 297684 : break;
547 : 44556 : case PRE_VALUE:
548 : 44556 : value = &uevent[i];
549 : 44556 : state = VALUE;
550 : :
551 : : _fallthrough_; /* to handle empty property */
552 : 451124 : case VALUE:
553 [ + + ]: 451124 : if (strchr(NEWLINE, uevent[i])) {
554 : 44556 : uevent[i] = '\0';
555 : :
556 : 44556 : r = handle_uevent_line(device, key, value, &major, &minor);
557 [ - + ]: 44556 : if (r < 0)
558 [ # # # # : 0 : log_device_debug_errno(device, r, "sd-device: Failed to handle uevent entry '%s=%s', ignoring: %m", key, value);
# # ]
559 : :
560 : 44556 : state = PRE_KEY;
561 : : }
562 : :
563 : 451124 : break;
564 : 0 : default:
565 : 0 : assert_not_reached("Invalid state when parsing uevent file");
566 : : }
567 : :
568 [ + + ]: 20504 : if (major) {
569 : 8240 : r = device_set_devnum(device, major, minor);
570 [ - + ]: 8240 : if (r < 0)
571 [ # # # # : 0 : log_device_debug_errno(device, r, "sd-device: Failed to set 'MAJOR=%s' or 'MINOR=%s' from '%s', ignoring: %m", major, minor, path);
# # ]
572 : : }
573 : :
574 : 20504 : return 0;
575 : : }
576 : :
577 : 23012 : _public_ int sd_device_get_ifindex(sd_device *device, int *ifindex) {
578 : : int r;
579 : :
580 [ - + - + ]: 23012 : assert_return(device, -EINVAL);
581 : :
582 : 23012 : r = device_read_uevent_file(device);
583 [ - + ]: 23012 : if (r < 0)
584 : 0 : return r;
585 : :
586 [ + + ]: 23012 : if (device->ifindex <= 0)
587 : 22188 : return -ENOENT;
588 : :
589 [ + - ]: 824 : if (ifindex)
590 : 824 : *ifindex = device->ifindex;
591 : :
592 : 824 : return 0;
593 : : }
594 : :
595 : 2520 : _public_ int sd_device_new_from_device_id(sd_device **ret, const char *id) {
596 : : int r;
597 : :
598 [ - + - + ]: 2520 : assert_return(ret, -EINVAL);
599 [ - + - + ]: 2520 : assert_return(id, -EINVAL);
600 : :
601 [ + + + - ]: 2520 : switch (id[0]) {
602 : 1892 : case 'b':
603 : : case 'c': {
604 : : dev_t devt;
605 : :
606 [ - + ]: 1892 : if (isempty(id))
607 : 0 : return -EINVAL;
608 : :
609 : 1892 : r = parse_dev(id + 1, &devt);
610 [ - + ]: 1892 : if (r < 0)
611 : 0 : return r;
612 : :
613 : 1892 : return sd_device_new_from_devnum(ret, id[0], devt);
614 : : }
615 : :
616 : 320 : case 'n': {
617 : 320 : _cleanup_(sd_device_unrefp) sd_device *device = NULL;
618 : 320 : _cleanup_close_ int sk = -1;
619 : 320 : struct ifreq ifr = {};
620 : : int ifindex;
621 : :
622 : 320 : r = parse_ifindex(&id[1], &ifr.ifr_ifindex);
623 [ - + ]: 320 : if (r < 0)
624 : 0 : return r;
625 : :
626 : 320 : sk = socket_ioctl_fd();
627 [ - + ]: 320 : if (sk < 0)
628 : 0 : return sk;
629 : :
630 : 320 : r = ioctl(sk, SIOCGIFNAME, &ifr);
631 [ + + ]: 320 : if (r < 0)
632 : 28 : return -errno;
633 : :
634 : 292 : r = sd_device_new_from_subsystem_sysname(&device, "net", ifr.ifr_name);
635 [ - + ]: 292 : if (r < 0)
636 : 0 : return r;
637 : :
638 : 292 : r = sd_device_get_ifindex(device, &ifindex);
639 [ - + ]: 292 : if (r < 0)
640 : 0 : return r;
641 : :
642 : : /* this is racey, so we might end up with the wrong device */
643 [ - + ]: 292 : if (ifr.ifr_ifindex != ifindex)
644 : 0 : return -ENODEV;
645 : :
646 : 292 : *ret = TAKE_PTR(device);
647 : 292 : return 0;
648 : : }
649 : :
650 : 308 : case '+': {
651 : : char subsys[PATH_MAX];
652 : : char *sysname;
653 : :
654 : 308 : (void) strscpy(subsys, sizeof(subsys), id + 1);
655 : 308 : sysname = strchr(subsys, ':');
656 [ - + ]: 308 : if (!sysname)
657 : 0 : return -EINVAL;
658 : :
659 : 308 : sysname[0] = '\0';
660 : 308 : sysname++;
661 : :
662 : 308 : return sd_device_new_from_subsystem_sysname(ret, subsys, sysname);
663 : : }
664 : :
665 : 0 : default:
666 : 0 : return -EINVAL;
667 : : }
668 : : }
669 : :
670 : 109224 : _public_ int sd_device_get_syspath(sd_device *device, const char **ret) {
671 [ - + - + ]: 109224 : assert_return(device, -EINVAL);
672 [ - + - + ]: 109224 : assert_return(ret, -EINVAL);
673 : :
674 [ - + ]: 109224 : assert(path_startswith(device->syspath, "/sys/"));
675 : :
676 : 109224 : *ret = device->syspath;
677 : :
678 : 109224 : return 0;
679 : : }
680 : :
681 : 4 : static int device_new_from_child(sd_device **ret, sd_device *child) {
682 : 4 : _cleanup_free_ char *path = NULL;
683 : : const char *subdir, *syspath;
684 : : int r;
685 : :
686 [ - + ]: 4 : assert(ret);
687 [ - + ]: 4 : assert(child);
688 : :
689 : 4 : r = sd_device_get_syspath(child, &syspath);
690 [ - + ]: 4 : if (r < 0)
691 : 0 : return r;
692 : :
693 : 4 : path = strdup(syspath);
694 [ - + ]: 4 : if (!path)
695 : 0 : return -ENOMEM;
696 : 4 : subdir = path + STRLEN("/sys");
697 : :
698 : 12 : for (;;) {
699 : : char *pos;
700 : :
701 : 16 : pos = strrchr(subdir, '/');
702 [ + - + + ]: 16 : if (!pos || pos < subdir + 2)
703 : : break;
704 : :
705 : 12 : *pos = '\0';
706 : :
707 : 12 : r = sd_device_new_from_syspath(ret, path);
708 [ + - ]: 12 : if (r < 0)
709 : 12 : continue;
710 : :
711 : 0 : return 0;
712 : : }
713 : :
714 : 4 : return -ENODEV;
715 : : }
716 : :
717 : 4 : _public_ int sd_device_get_parent(sd_device *child, sd_device **ret) {
718 : :
719 [ - + - + ]: 4 : assert_return(ret, -EINVAL);
720 [ - + - + ]: 4 : assert_return(child, -EINVAL);
721 : :
722 [ + - ]: 4 : if (!child->parent_set) {
723 : 4 : child->parent_set = true;
724 : :
725 : 4 : (void) device_new_from_child(&child->parent, child);
726 : : }
727 : :
728 [ + - ]: 4 : if (!child->parent)
729 : 4 : return -ENOENT;
730 : :
731 : 0 : *ret = child->parent;
732 : 0 : return 0;
733 : : }
734 : :
735 : 30940 : int device_set_subsystem(sd_device *device, const char *_subsystem) {
736 : 30940 : _cleanup_free_ char *subsystem = NULL;
737 : : int r;
738 : :
739 [ - + ]: 30940 : assert(device);
740 [ - + ]: 30940 : assert(_subsystem);
741 : :
742 : 30940 : subsystem = strdup(_subsystem);
743 [ - + ]: 30940 : if (!subsystem)
744 : 0 : return -ENOMEM;
745 : :
746 : 30940 : r = device_add_property_internal(device, "SUBSYSTEM", subsystem);
747 [ - + ]: 30940 : if (r < 0)
748 : 0 : return r;
749 : :
750 : 30940 : device->subsystem_set = true;
751 : 30940 : return free_and_replace(device->subsystem, subsystem);
752 : : }
753 : :
754 : 1648 : static int device_set_drivers_subsystem(sd_device *device, const char *_subsystem) {
755 : 1648 : _cleanup_free_ char *subsystem = NULL;
756 : : int r;
757 : :
758 [ - + ]: 1648 : assert(device);
759 [ - + ]: 1648 : assert(_subsystem);
760 [ - + ]: 1648 : assert(*_subsystem);
761 : :
762 : 1648 : subsystem = strdup(_subsystem);
763 [ - + ]: 1648 : if (!subsystem)
764 : 0 : return -ENOMEM;
765 : :
766 : 1648 : r = device_set_subsystem(device, "drivers");
767 [ - + ]: 1648 : if (r < 0)
768 : 0 : return r;
769 : :
770 : 1648 : return free_and_replace(device->driver_subsystem, subsystem);
771 : : }
772 : :
773 : 40692 : _public_ int sd_device_get_subsystem(sd_device *device, const char **ret) {
774 : 40692 : const char *syspath, *drivers = NULL;
775 : : int r;
776 : :
777 [ - + - + ]: 40692 : assert_return(ret, -EINVAL);
778 [ - + - + ]: 40692 : assert_return(device, -EINVAL);
779 : :
780 : 40692 : r = sd_device_get_syspath(device, &syspath);
781 [ - + ]: 40692 : if (r < 0)
782 : 0 : return r;
783 : :
784 [ + + ]: 40692 : if (!device->subsystem_set) {
785 [ + - ]: 30940 : _cleanup_free_ char *subsystem = NULL;
786 : : char *path;
787 : :
788 : : /* read 'subsystem' link */
789 [ + + + - : 154700 : path = strjoina(syspath, "/subsystem");
- + - + +
+ + - ]
790 : 30940 : r = readlink_value(path, &subsystem);
791 [ + + ]: 30940 : if (r >= 0)
792 : 26208 : r = device_set_subsystem(device, subsystem);
793 : : /* use implicit names */
794 [ + + ]: 4732 : else if (path_startswith(device->devpath, "/module/"))
795 : 2576 : r = device_set_subsystem(device, "module");
796 [ + + + - ]: 2664 : else if (!(drivers = strstr(syspath, "/drivers/")) &&
797 : 508 : PATH_STARTSWITH_SET(device->devpath, "/subsystem/",
798 : : "/class/",
799 : : "/bus/"))
800 : 508 : r = device_set_subsystem(device, "subsystem");
801 [ + + - + ]: 30940 : if (r < 0 && r != -ENOENT)
802 [ # # # # : 0 : return log_device_debug_errno(device, r, "sd-device: Failed to set subsystem for %s: %m", device->devpath);
# # ]
803 : :
804 : 30940 : device->subsystem_set = true;
805 [ - + ]: 9752 : } else if (!device->driver_subsystem_set)
806 : 0 : drivers = strstr(syspath, "/drivers/");
807 : :
808 [ + + ]: 40692 : if (!device->driver_subsystem_set) {
809 [ + + ]: 30940 : if (drivers) {
810 [ + - ]: 1648 : _cleanup_free_ char *subpath = NULL;
811 : :
812 : 1648 : subpath = strndup(syspath, drivers - syspath);
813 [ - + ]: 1648 : if (!subpath)
814 : 0 : r = -ENOMEM;
815 : : else {
816 : : const char *subsys;
817 : :
818 : 1648 : subsys = strrchr(subpath, '/');
819 [ - + ]: 1648 : if (!subsys)
820 : 0 : r = -EINVAL;
821 : : else
822 : 1648 : r = device_set_drivers_subsystem(device, subsys + 1);
823 : : }
824 [ - + # # ]: 1648 : if (r < 0 && r != -ENOENT)
825 [ # # # # : 0 : return log_device_debug_errno(device, r, "sd-device: Failed to set subsystem for driver %s: %m", device->devpath);
# # ]
826 : : }
827 : :
828 : 30940 : device->driver_subsystem_set = true;
829 : : }
830 : :
831 [ - + ]: 40692 : if (!device->subsystem)
832 : 0 : return -ENOENT;
833 : :
834 : 40692 : *ret = device->subsystem;
835 : 40692 : return 0;
836 : : }
837 : :
838 : 4440 : _public_ int sd_device_get_devtype(sd_device *device, const char **devtype) {
839 : : int r;
840 : :
841 [ - + ]: 4440 : assert(devtype);
842 [ - + ]: 4440 : assert(device);
843 : :
844 : 4440 : r = device_read_uevent_file(device);
845 [ - + ]: 4440 : if (r < 0)
846 : 0 : return r;
847 : :
848 [ + + ]: 4440 : if (!device->devtype)
849 : 4144 : return -ENOENT;
850 : :
851 : 296 : *devtype = device->devtype;
852 : :
853 : 296 : return 0;
854 : : }
855 : :
856 : 0 : _public_ int sd_device_get_parent_with_subsystem_devtype(sd_device *child, const char *subsystem, const char *devtype, sd_device **ret) {
857 : 0 : sd_device *parent = NULL;
858 : : int r;
859 : :
860 [ # # # # ]: 0 : assert_return(child, -EINVAL);
861 [ # # # # ]: 0 : assert_return(subsystem, -EINVAL);
862 : :
863 : 0 : r = sd_device_get_parent(child, &parent);
864 [ # # ]: 0 : while (r >= 0) {
865 : 0 : const char *parent_subsystem = NULL;
866 : 0 : const char *parent_devtype = NULL;
867 : :
868 : 0 : (void) sd_device_get_subsystem(parent, &parent_subsystem);
869 [ # # ]: 0 : if (streq_ptr(parent_subsystem, subsystem)) {
870 [ # # ]: 0 : if (!devtype)
871 : 0 : break;
872 : :
873 : 0 : (void) sd_device_get_devtype(parent, &parent_devtype);
874 [ # # ]: 0 : if (streq_ptr(parent_devtype, devtype))
875 : 0 : break;
876 : : }
877 : 0 : r = sd_device_get_parent(parent, &parent);
878 : : }
879 : :
880 [ # # ]: 0 : if (r < 0)
881 : 0 : return r;
882 : :
883 : 0 : *ret = parent;
884 : 0 : return 0;
885 : : }
886 : :
887 : 33056 : _public_ int sd_device_get_devnum(sd_device *device, dev_t *devnum) {
888 : : int r;
889 : :
890 [ - + - + ]: 33056 : assert_return(device, -EINVAL);
891 : :
892 : 33056 : r = device_read_uevent_file(device);
893 [ - + ]: 33056 : if (r < 0)
894 : 0 : return r;
895 : :
896 [ + + ]: 33056 : if (major(device->devnum) <= 0)
897 : 22352 : return -ENOENT;
898 : :
899 [ + - ]: 10704 : if (devnum)
900 : 10704 : *devnum = device->devnum;
901 : :
902 : 10704 : return 0;
903 : : }
904 : :
905 : 348 : int device_set_driver(sd_device *device, const char *_driver) {
906 : 348 : _cleanup_free_ char *driver = NULL;
907 : : int r;
908 : :
909 [ - + ]: 348 : assert(device);
910 [ - + ]: 348 : assert(_driver);
911 : :
912 : 348 : driver = strdup(_driver);
913 [ - + ]: 348 : if (!driver)
914 : 0 : return -ENOMEM;
915 : :
916 : 348 : r = device_add_property_internal(device, "DRIVER", driver);
917 [ - + ]: 348 : if (r < 0)
918 : 0 : return r;
919 : :
920 : 348 : device->driver_set = true;
921 : 348 : return free_and_replace(device->driver, driver);
922 : : }
923 : :
924 : 4432 : _public_ int sd_device_get_driver(sd_device *device, const char **ret) {
925 [ - + - + ]: 4432 : assert_return(device, -EINVAL);
926 [ - + - + ]: 4432 : assert_return(ret, -EINVAL);
927 : :
928 [ + + ]: 4432 : if (!device->driver_set) {
929 [ + - ]: 4428 : _cleanup_free_ char *driver = NULL;
930 : : const char *syspath;
931 : : char *path;
932 : : int r;
933 : :
934 : 4428 : r = sd_device_get_syspath(device, &syspath);
935 [ - + ]: 4428 : if (r < 0)
936 : 0 : return r;
937 : :
938 [ + + + - : 22140 : path = strjoina(syspath, "/driver");
- + - + +
+ + - ]
939 : 4428 : r = readlink_value(path, &driver);
940 [ + + ]: 4428 : if (r >= 0) {
941 : 348 : r = device_set_driver(device, driver);
942 [ - + ]: 348 : if (r < 0)
943 [ # # # # : 0 : return log_device_debug_errno(device, r, "sd-device: Failed to set driver for %s: %m", device->devpath);
# # ]
944 [ + - ]: 4080 : } else if (r == -ENOENT)
945 : 4080 : device->driver_set = true;
946 : : else
947 [ # # # # : 0 : return log_device_debug_errno(device, r, "sd-device: Failed to set driver for %s: %m", device->devpath);
# # ]
948 : : }
949 : :
950 [ + + ]: 4432 : if (!device->driver)
951 : 4084 : return -ENOENT;
952 : :
953 : 348 : *ret = device->driver;
954 : 348 : return 0;
955 : : }
956 : :
957 : 316992 : _public_ int sd_device_get_devpath(sd_device *device, const char **devpath) {
958 [ - + - + ]: 316992 : assert_return(device, -EINVAL);
959 [ - + - + ]: 316992 : assert_return(devpath, -EINVAL);
960 : :
961 [ - + ]: 316992 : assert(device->devpath);
962 [ - + ]: 316992 : assert(device->devpath[0] == '/');
963 : :
964 : 316992 : *devpath = device->devpath;
965 : 316992 : return 0;
966 : : }
967 : :
968 : 7072 : _public_ int sd_device_get_devname(sd_device *device, const char **devname) {
969 : : int r;
970 : :
971 [ - + - + ]: 7072 : assert_return(device, -EINVAL);
972 [ - + - + ]: 7072 : assert_return(devname, -EINVAL);
973 : :
974 : 7072 : r = device_read_uevent_file(device);
975 [ - + ]: 7072 : if (r < 0)
976 : 0 : return r;
977 : :
978 [ + + ]: 7072 : if (!device->devname)
979 : 4036 : return -ENOENT;
980 : :
981 [ - + ]: 3036 : assert(path_startswith(device->devname, "/dev/"));
982 : :
983 : 3036 : *devname = device->devname;
984 : 3036 : return 0;
985 : : }
986 : :
987 : 6892 : static int device_set_sysname(sd_device *device) {
988 : 6892 : _cleanup_free_ char *sysname = NULL;
989 : 6892 : const char *sysnum = NULL;
990 : : const char *pos;
991 : 6892 : size_t len = 0;
992 : :
993 [ - + ]: 6892 : if (!device->devpath)
994 : 0 : return -EINVAL;
995 : :
996 : 6892 : pos = strrchr(device->devpath, '/');
997 [ - + ]: 6892 : if (!pos)
998 : 0 : return -EINVAL;
999 : 6892 : pos++;
1000 : :
1001 : : /* devpath is not a root directory */
1002 [ + - - + ]: 6892 : if (*pos == '\0' || pos <= device->devpath)
1003 : 0 : return -EINVAL;
1004 : :
1005 : 6892 : sysname = strdup(pos);
1006 [ - + ]: 6892 : if (!sysname)
1007 : 0 : return -ENOMEM;
1008 : :
1009 : : /* some devices have '!' in their name, change that to '/' */
1010 [ + + ]: 61708 : while (sysname[len] != '\0') {
1011 [ - + ]: 54816 : if (sysname[len] == '!')
1012 : 0 : sysname[len] = '/';
1013 : :
1014 : 54816 : len++;
1015 : : }
1016 : :
1017 : : /* trailing number */
1018 [ + + + + ]: 14052 : while (len > 0 && isdigit(sysname[--len]))
1019 : 7160 : sysnum = &sysname[len];
1020 : :
1021 [ + + ]: 6892 : if (len == 0)
1022 : 28 : sysnum = NULL;
1023 : :
1024 : 6892 : device->sysname_set = true;
1025 : 6892 : device->sysnum = sysnum;
1026 : 6892 : return free_and_replace(device->sysname, sysname);
1027 : : }
1028 : :
1029 : 6896 : _public_ int sd_device_get_sysname(sd_device *device, const char **ret) {
1030 : : int r;
1031 : :
1032 [ - + - + ]: 6896 : assert_return(device, -EINVAL);
1033 [ - + - + ]: 6896 : assert_return(ret, -EINVAL);
1034 : :
1035 [ + + ]: 6896 : if (!device->sysname_set) {
1036 : 6892 : r = device_set_sysname(device);
1037 [ - + ]: 6892 : if (r < 0)
1038 : 0 : return r;
1039 : : }
1040 : :
1041 [ - + - + ]: 6896 : assert_return(device->sysname, -ENOENT);
1042 : :
1043 : 6896 : *ret = device->sysname;
1044 : 6896 : return 0;
1045 : : }
1046 : :
1047 : 4432 : _public_ int sd_device_get_sysnum(sd_device *device, const char **ret) {
1048 : : int r;
1049 : :
1050 [ - + - + ]: 4432 : assert_return(device, -EINVAL);
1051 [ - + - + ]: 4432 : assert_return(ret, -EINVAL);
1052 : :
1053 [ - + ]: 4432 : if (!device->sysname_set) {
1054 : 0 : r = device_set_sysname(device);
1055 [ # # ]: 0 : if (r < 0)
1056 : 0 : return r;
1057 : : }
1058 : :
1059 [ + + ]: 4432 : if (!device->sysnum)
1060 : 1996 : return -ENOENT;
1061 : :
1062 : 2436 : *ret = device->sysnum;
1063 : 2436 : return 0;
1064 : : }
1065 : :
1066 : 6216 : static bool is_valid_tag(const char *tag) {
1067 [ - + ]: 6216 : assert(tag);
1068 : :
1069 [ + - + - ]: 6216 : return !strchr(tag, ':') && !strchr(tag, ' ');
1070 : : }
1071 : :
1072 : 6216 : int device_add_tag(sd_device *device, const char *tag) {
1073 : : int r;
1074 : :
1075 [ - + ]: 6216 : assert(device);
1076 [ - + ]: 6216 : assert(tag);
1077 : :
1078 [ - + ]: 6216 : if (!is_valid_tag(tag))
1079 : 0 : return -EINVAL;
1080 : :
1081 : 6216 : r = set_ensure_allocated(&device->tags, &string_hash_ops);
1082 [ - + ]: 6216 : if (r < 0)
1083 : 0 : return r;
1084 : :
1085 : 6216 : r = set_put_strdup(device->tags, tag);
1086 [ - + ]: 6216 : if (r < 0)
1087 : 0 : return r;
1088 : :
1089 : 6216 : device->tags_generation++;
1090 : 6216 : device->property_tags_outdated = true;
1091 : :
1092 : 6216 : return 0;
1093 : : }
1094 : :
1095 : 3648 : int device_add_devlink(sd_device *device, const char *devlink) {
1096 : : int r;
1097 : :
1098 [ - + ]: 3648 : assert(device);
1099 [ - + ]: 3648 : assert(devlink);
1100 : :
1101 : 3648 : r = set_ensure_allocated(&device->devlinks, &string_hash_ops);
1102 [ - + ]: 3648 : if (r < 0)
1103 : 0 : return r;
1104 : :
1105 : 3648 : r = set_put_strdup(device->devlinks, devlink);
1106 [ - + ]: 3648 : if (r < 0)
1107 : 0 : return r;
1108 : :
1109 : 3648 : device->devlinks_generation++;
1110 : 3648 : device->property_devlinks_outdated = true;
1111 : :
1112 : 3648 : return 0;
1113 : : }
1114 : :
1115 : 49244 : static int device_add_property_internal_from_string(sd_device *device, const char *str) {
1116 : 49244 : _cleanup_free_ char *key = NULL;
1117 : : char *value;
1118 : : int r;
1119 : :
1120 [ - + ]: 49244 : assert(device);
1121 [ - + ]: 49244 : assert(str);
1122 : :
1123 : 49244 : key = strdup(str);
1124 [ - + ]: 49244 : if (!key)
1125 : 0 : return -ENOMEM;
1126 : :
1127 : 49244 : value = strchr(key, '=');
1128 [ - + ]: 49244 : if (!value)
1129 : 0 : return -EINVAL;
1130 : :
1131 : 49244 : *value = '\0';
1132 : :
1133 [ + + ]: 49244 : if (isempty(++value))
1134 : 656 : value = NULL;
1135 : :
1136 : : /* Add the property to both sd_device::properties and sd_device::properties_db,
1137 : : * as this is called by only handle_db_line(). */
1138 : 49244 : r = device_add_property_aux(device, key, value, false);
1139 [ - + ]: 49244 : if (r < 0)
1140 : 0 : return r;
1141 : :
1142 : 49244 : return device_add_property_aux(device, key, value, true);
1143 : : }
1144 : :
1145 : 9676 : int device_set_usec_initialized(sd_device *device, usec_t when) {
1146 : : char s[DECIMAL_STR_MAX(usec_t)];
1147 : : int r;
1148 : :
1149 [ - + ]: 9676 : assert(device);
1150 : :
1151 [ - + ]: 9676 : xsprintf(s, USEC_FMT, when);
1152 : :
1153 : 9676 : r = device_add_property_internal(device, "USEC_INITIALIZED", s);
1154 [ - + ]: 9676 : if (r < 0)
1155 : 0 : return r;
1156 : :
1157 : 9676 : device->usec_initialized = when;
1158 : 9676 : return 0;
1159 : : }
1160 : :
1161 : 69712 : static int handle_db_line(sd_device *device, char key, const char *value) {
1162 : : char *path;
1163 : : int r;
1164 : :
1165 [ - + ]: 69712 : assert(device);
1166 [ - + ]: 69712 : assert(value);
1167 : :
1168 [ + + + + : 69712 : switch (key) {
+ + - ]
1169 : 6216 : case 'G':
1170 : 6216 : r = device_add_tag(device, value);
1171 [ - + ]: 6216 : if (r < 0)
1172 : 0 : return r;
1173 : :
1174 : 6216 : break;
1175 : 3648 : case 'S':
1176 [ + + + - : 18240 : path = strjoina("/dev/", value);
- + - + +
+ + - ]
1177 : 3648 : r = device_add_devlink(device, path);
1178 [ - + ]: 3648 : if (r < 0)
1179 : 0 : return r;
1180 : :
1181 : 3648 : break;
1182 : 49244 : case 'E':
1183 : 49244 : r = device_add_property_internal_from_string(device, value);
1184 [ - + ]: 49244 : if (r < 0)
1185 : 0 : return r;
1186 : :
1187 : 49244 : break;
1188 : 9676 : case 'I': {
1189 : : usec_t t;
1190 : :
1191 : 9676 : r = safe_atou64(value, &t);
1192 [ - + ]: 9676 : if (r < 0)
1193 : 0 : return r;
1194 : :
1195 : 9676 : r = device_set_usec_initialized(device, t);
1196 [ - + ]: 9676 : if (r < 0)
1197 : 0 : return r;
1198 : :
1199 : 9676 : break;
1200 : : }
1201 : 24 : case 'L':
1202 : 24 : r = safe_atoi(value, &device->devlink_priority);
1203 [ - + ]: 24 : if (r < 0)
1204 : 0 : return r;
1205 : :
1206 : 24 : break;
1207 : 904 : case 'W':
1208 : 904 : r = safe_atoi(value, &device->watch_handle);
1209 [ - + ]: 904 : if (r < 0)
1210 : 0 : return r;
1211 : :
1212 : 904 : break;
1213 : 0 : default:
1214 [ # # # # : 0 : log_device_debug(device, "sd-device: Unknown key '%c' in device db, ignoring", key);
# # ]
1215 : : }
1216 : :
1217 : 69712 : return 0;
1218 : : }
1219 : :
1220 : 34756 : int device_get_id_filename(sd_device *device, const char **ret) {
1221 [ - + ]: 34756 : assert(device);
1222 [ - + ]: 34756 : assert(ret);
1223 : :
1224 [ + + ]: 34756 : if (!device->id_filename) {
1225 [ + - ]: 23428 : _cleanup_free_ char *id = NULL;
1226 : : const char *subsystem;
1227 : : dev_t devnum;
1228 : : int ifindex, r;
1229 : :
1230 : 23428 : r = sd_device_get_subsystem(device, &subsystem);
1231 [ - + ]: 23428 : if (r < 0)
1232 : 0 : return r;
1233 : :
1234 [ + + ]: 23428 : if (sd_device_get_devnum(device, &devnum) >= 0) {
1235 [ - + ]: 7976 : assert(subsystem);
1236 : :
1237 : : /* use dev_t — b259:131072, c254:0 */
1238 : 7976 : r = asprintf(&id, "%c%u:%u",
1239 [ + + ]: 7976 : streq(subsystem, "block") ? 'b' : 'c',
1240 : : major(devnum), minor(devnum));
1241 [ - + ]: 7976 : if (r < 0)
1242 : 0 : return -ENOMEM;
1243 [ + + ]: 15452 : } else if (sd_device_get_ifindex(device, &ifindex) >= 0) {
1244 : : /* use netdev ifindex — n3 */
1245 : 500 : r = asprintf(&id, "n%u", (unsigned) ifindex);
1246 [ - + ]: 500 : if (r < 0)
1247 : 0 : return -ENOMEM;
1248 : : } else {
1249 : : /* use $subsys:$sysname — pci:0000:00:1f.2
1250 : : * sysname() has '!' translated, get it from devpath
1251 : : */
1252 : : const char *sysname;
1253 : :
1254 : 14952 : sysname = basename(device->devpath);
1255 [ - + ]: 14952 : if (!sysname)
1256 : 0 : return -EINVAL;
1257 : :
1258 [ - + ]: 14952 : if (!subsystem)
1259 : 0 : return -EINVAL;
1260 : :
1261 [ + + ]: 14952 : if (streq(subsystem, "drivers")) {
1262 : : /* the 'drivers' pseudo-subsystem is special, and needs the real subsystem
1263 : : * encoded as well */
1264 : 1100 : r = asprintf(&id, "+drivers:%s:%s", device->driver_subsystem, sysname);
1265 [ - + ]: 1100 : if (r < 0)
1266 : 0 : return -ENOMEM;
1267 : : } else {
1268 : 13852 : r = asprintf(&id, "+%s:%s", subsystem, sysname);
1269 [ - + ]: 13852 : if (r < 0)
1270 : 0 : return -ENOMEM;
1271 : : }
1272 : : }
1273 : :
1274 : 23428 : device->id_filename = TAKE_PTR(id);
1275 : : }
1276 : :
1277 : 34756 : *ret = device->id_filename;
1278 : 34756 : return 0;
1279 : : }
1280 : :
1281 : 34756 : int device_read_db_internal_filename(sd_device *device, const char *filename) {
1282 : 34756 : _cleanup_free_ char *db = NULL;
1283 : : const char *value;
1284 : : size_t db_len, i;
1285 : : char key;
1286 : : int r;
1287 : :
1288 : : enum {
1289 : : PRE_KEY,
1290 : : KEY,
1291 : : PRE_VALUE,
1292 : : VALUE,
1293 : : INVALID_LINE,
1294 : 34756 : } state = PRE_KEY;
1295 : :
1296 [ - + ]: 34756 : assert(device);
1297 [ - + ]: 34756 : assert(filename);
1298 : :
1299 : 34756 : r = read_full_file(filename, &db, &db_len);
1300 [ + + ]: 34756 : if (r < 0) {
1301 [ + - ]: 23084 : if (r == -ENOENT)
1302 : 23084 : return 0;
1303 : :
1304 [ # # # # : 0 : return log_device_debug_errno(device, r, "sd-device: Failed to read db '%s': %m", filename);
# # ]
1305 : : }
1306 : :
1307 : : /* devices with a database entry are initialized */
1308 : 11672 : device->is_initialized = true;
1309 : :
1310 : 11672 : device->db_loaded = true;
1311 : :
1312 [ + + ]: 1966524 : for (i = 0; i < db_len; i++) {
1313 [ + + + - : 1954852 : switch (state) {
+ - ]
1314 : 69712 : case PRE_KEY:
1315 [ + - ]: 69712 : if (!strchr(NEWLINE, db[i])) {
1316 : 69712 : key = db[i];
1317 : :
1318 : 69712 : state = KEY;
1319 : : }
1320 : :
1321 : 69712 : break;
1322 : 69712 : case KEY:
1323 [ - + ]: 69712 : if (db[i] != ':') {
1324 [ # # # # : 0 : log_device_debug(device, "sd-device: Invalid db entry with key '%c', ignoring", key);
# # ]
1325 : :
1326 : 0 : state = INVALID_LINE;
1327 : : } else {
1328 : 69712 : db[i] = '\0';
1329 : :
1330 : 69712 : state = PRE_VALUE;
1331 : : }
1332 : :
1333 : 69712 : break;
1334 : 69712 : case PRE_VALUE:
1335 : 69712 : value = &db[i];
1336 : :
1337 : 69712 : state = VALUE;
1338 : :
1339 : 69712 : break;
1340 : 0 : case INVALID_LINE:
1341 [ # # ]: 0 : if (strchr(NEWLINE, db[i]))
1342 : 0 : state = PRE_KEY;
1343 : :
1344 : 0 : break;
1345 : 1745716 : case VALUE:
1346 [ + + ]: 1745716 : if (strchr(NEWLINE, db[i])) {
1347 : 69712 : db[i] = '\0';
1348 : 69712 : r = handle_db_line(device, key, value);
1349 [ - + ]: 69712 : if (r < 0)
1350 [ # # # # : 0 : log_device_debug_errno(device, r, "sd-device: Failed to handle db entry '%c:%s', ignoring: %m", key, value);
# # ]
1351 : :
1352 : 69712 : state = PRE_KEY;
1353 : : }
1354 : :
1355 : 1745716 : break;
1356 : 0 : default:
1357 [ # # # # : 0 : return log_device_debug_errno(device, SYNTHETIC_ERRNO(EINVAL), "sd-device: invalid db syntax.");
# # ]
1358 : : }
1359 : : }
1360 : :
1361 : 11672 : return 0;
1362 : : }
1363 : :
1364 : 98292 : int device_read_db_internal(sd_device *device, bool force) {
1365 : : const char *id, *path;
1366 : : int r;
1367 : :
1368 [ - + ]: 98292 : assert(device);
1369 : :
1370 [ + + + - : 98292 : if (device->db_loaded || (!force && device->sealed))
- + ]
1371 : 63536 : return 0;
1372 : :
1373 : 34756 : r = device_get_id_filename(device, &id);
1374 [ - + ]: 34756 : if (r < 0)
1375 : 0 : return r;
1376 : :
1377 [ + + + - : 173780 : path = strjoina("/run/udev/data/", id);
- + - + +
+ + - ]
1378 : :
1379 : 34756 : return device_read_db_internal_filename(device, path);
1380 : : }
1381 : :
1382 : 25060 : _public_ int sd_device_get_is_initialized(sd_device *device) {
1383 : : int r;
1384 : :
1385 [ - + - + ]: 25060 : assert_return(device, -EINVAL);
1386 : :
1387 : 25060 : r = device_read_db(device);
1388 [ - + ]: 25060 : if (r < 0)
1389 : 0 : return r;
1390 : :
1391 : 25060 : return device->is_initialized;
1392 : : }
1393 : :
1394 : 1452 : _public_ int sd_device_get_usec_since_initialized(sd_device *device, uint64_t *usec) {
1395 : : usec_t now_ts;
1396 : : int r;
1397 : :
1398 [ - + - + ]: 1452 : assert_return(device, -EINVAL);
1399 [ - + - + ]: 1452 : assert_return(usec, -EINVAL);
1400 : :
1401 : 1452 : r = device_read_db(device);
1402 [ - + ]: 1452 : if (r < 0)
1403 : 0 : return r;
1404 : :
1405 [ - + ]: 1452 : if (!device->is_initialized)
1406 : 0 : return -EBUSY;
1407 : :
1408 [ + + ]: 1452 : if (!device->usec_initialized)
1409 : 304 : return -ENODATA;
1410 : :
1411 : 1148 : now_ts = now(clock_boottime_or_monotonic());
1412 : :
1413 [ - + ]: 1148 : if (now_ts < device->usec_initialized)
1414 : 0 : return -EIO;
1415 : :
1416 : 1148 : *usec = now_ts - device->usec_initialized;
1417 : 1148 : return 0;
1418 : : }
1419 : :
1420 : 3628 : _public_ const char *sd_device_get_tag_first(sd_device *device) {
1421 : : void *v;
1422 : :
1423 [ - + - + ]: 3628 : assert_return(device, NULL);
1424 : :
1425 : 3628 : (void) device_read_db(device);
1426 : :
1427 : 3628 : device->tags_iterator_generation = device->tags_generation;
1428 : 3628 : device->tags_iterator = ITERATOR_FIRST;
1429 : :
1430 : 3628 : (void) set_iterate(device->tags, &device->tags_iterator, &v);
1431 : 3628 : return v;
1432 : : }
1433 : :
1434 : 3948 : _public_ const char *sd_device_get_tag_next(sd_device *device) {
1435 : : void *v;
1436 : :
1437 [ - + - + ]: 3948 : assert_return(device, NULL);
1438 : :
1439 : 3948 : (void) device_read_db(device);
1440 : :
1441 [ - + ]: 3948 : if (device->tags_iterator_generation != device->tags_generation)
1442 : 0 : return NULL;
1443 : :
1444 : 3948 : (void) set_iterate(device->tags, &device->tags_iterator, &v);
1445 : 3948 : return v;
1446 : : }
1447 : :
1448 : 2464 : _public_ const char *sd_device_get_devlink_first(sd_device *device) {
1449 : : void *v;
1450 : :
1451 [ - + - + ]: 2464 : assert_return(device, NULL);
1452 : :
1453 : 2464 : (void) device_read_db(device);
1454 : :
1455 : 2464 : device->devlinks_iterator_generation = device->devlinks_generation;
1456 : 2464 : device->devlinks_iterator = ITERATOR_FIRST;
1457 : :
1458 : 2464 : (void) set_iterate(device->devlinks, &device->devlinks_iterator, &v);
1459 : 2464 : return v;
1460 : : }
1461 : :
1462 : 4316 : _public_ const char *sd_device_get_devlink_next(sd_device *device) {
1463 : : void *v;
1464 : :
1465 [ - + - + ]: 4316 : assert_return(device, NULL);
1466 : :
1467 : 4316 : (void) device_read_db(device);
1468 : :
1469 [ - + ]: 4316 : if (device->devlinks_iterator_generation != device->devlinks_generation)
1470 : 0 : return NULL;
1471 : :
1472 : 4316 : (void) set_iterate(device->devlinks, &device->devlinks_iterator, &v);
1473 : 4316 : return v;
1474 : : }
1475 : :
1476 : 57424 : int device_properties_prepare(sd_device *device) {
1477 : : int r;
1478 : :
1479 [ - + ]: 57424 : assert(device);
1480 : :
1481 : 57424 : r = device_read_uevent_file(device);
1482 [ - + ]: 57424 : if (r < 0)
1483 : 0 : return r;
1484 : :
1485 : 57424 : r = device_read_db(device);
1486 [ - + ]: 57424 : if (r < 0)
1487 : 0 : return r;
1488 : :
1489 [ + + ]: 57424 : if (device->property_devlinks_outdated) {
1490 [ + - ]: 632 : _cleanup_free_ char *devlinks = NULL;
1491 : 632 : size_t devlinks_allocated = 0, devlinks_len = 0;
1492 : : const char *devlink;
1493 : :
1494 [ + + ]: 3308 : for (devlink = sd_device_get_devlink_first(device); devlink; devlink = sd_device_get_devlink_next(device)) {
1495 : : char *e;
1496 : :
1497 [ - + ]: 2676 : if (!GREEDY_REALLOC(devlinks, devlinks_allocated, devlinks_len + strlen(devlink) + 2))
1498 : 0 : return -ENOMEM;
1499 [ + + ]: 2676 : if (devlinks_len > 0)
1500 : 2044 : stpcpy(devlinks + devlinks_len++, " ");
1501 : 2676 : e = stpcpy(devlinks + devlinks_len, devlink);
1502 : 2676 : devlinks_len = e - devlinks;
1503 : : }
1504 : :
1505 : 632 : r = device_add_property_internal(device, "DEVLINKS", devlinks);
1506 [ - + ]: 632 : if (r < 0)
1507 : 0 : return r;
1508 : :
1509 : 632 : device->property_devlinks_outdated = false;
1510 : : }
1511 : :
1512 [ + + ]: 57424 : if (device->property_tags_outdated) {
1513 [ + - ]: 3628 : _cleanup_free_ char *tags = NULL;
1514 : 3628 : size_t tags_allocated = 0, tags_len = 0;
1515 : : const char *tag;
1516 : :
1517 [ - + ]: 3628 : if (!GREEDY_REALLOC(tags, tags_allocated, 2))
1518 : 0 : return -ENOMEM;
1519 : 3628 : stpcpy(tags, ":");
1520 : 3628 : tags_len++;
1521 : :
1522 [ + + ]: 7576 : for (tag = sd_device_get_tag_first(device); tag; tag = sd_device_get_tag_next(device)) {
1523 : : char *e;
1524 : :
1525 [ - + ]: 3948 : if (!GREEDY_REALLOC(tags, tags_allocated, tags_len + strlen(tag) + 2))
1526 : 0 : return -ENOMEM;
1527 : 3948 : e = stpcpy(stpcpy(tags + tags_len, tag), ":");
1528 : 3948 : tags_len = e - tags;
1529 : : }
1530 : :
1531 : 3628 : r = device_add_property_internal(device, "TAGS", tags);
1532 [ - + ]: 3628 : if (r < 0)
1533 : 0 : return r;
1534 : :
1535 : 3628 : device->property_tags_outdated = false;
1536 : : }
1537 : :
1538 : 57424 : return 0;
1539 : : }
1540 : :
1541 : 2932 : _public_ const char *sd_device_get_property_first(sd_device *device, const char **_value) {
1542 : : const char *key;
1543 : : int r;
1544 : :
1545 [ - + - + ]: 2932 : assert_return(device, NULL);
1546 : :
1547 : 2932 : r = device_properties_prepare(device);
1548 [ - + ]: 2932 : if (r < 0)
1549 : 0 : return NULL;
1550 : :
1551 : 2932 : device->properties_iterator_generation = device->properties_generation;
1552 : 2932 : device->properties_iterator = ITERATOR_FIRST;
1553 : :
1554 : 2932 : (void) ordered_hashmap_iterate(device->properties, &device->properties_iterator, (void**)_value, (const void**)&key);
1555 : 2932 : return key;
1556 : : }
1557 : :
1558 : 17720 : _public_ const char *sd_device_get_property_next(sd_device *device, const char **_value) {
1559 : : const char *key;
1560 : : int r;
1561 : :
1562 [ - + - + ]: 17720 : assert_return(device, NULL);
1563 : :
1564 : 17720 : r = device_properties_prepare(device);
1565 [ - + ]: 17720 : if (r < 0)
1566 : 0 : return NULL;
1567 : :
1568 [ - + ]: 17720 : if (device->properties_iterator_generation != device->properties_generation)
1569 : 0 : return NULL;
1570 : :
1571 : 17720 : (void) ordered_hashmap_iterate(device->properties, &device->properties_iterator, (void**)_value, (const void**)&key);
1572 : 17720 : return key;
1573 : : }
1574 : :
1575 : 0 : static int device_sysattrs_read_all(sd_device *device) {
1576 : 0 : _cleanup_closedir_ DIR *dir = NULL;
1577 : : const char *syspath;
1578 : : struct dirent *dent;
1579 : : int r;
1580 : :
1581 [ # # ]: 0 : assert(device);
1582 : :
1583 [ # # ]: 0 : if (device->sysattrs_read)
1584 : 0 : return 0;
1585 : :
1586 : 0 : r = sd_device_get_syspath(device, &syspath);
1587 [ # # ]: 0 : if (r < 0)
1588 : 0 : return r;
1589 : :
1590 : 0 : dir = opendir(syspath);
1591 [ # # ]: 0 : if (!dir)
1592 : 0 : return -errno;
1593 : :
1594 : 0 : r = set_ensure_allocated(&device->sysattrs, &string_hash_ops);
1595 [ # # ]: 0 : if (r < 0)
1596 : 0 : return r;
1597 : :
1598 [ # # # # ]: 0 : FOREACH_DIRENT_ALL(dent, dir, return -errno) {
1599 [ # # # ]: 0 : _cleanup_free_ char *path = NULL;
1600 : : struct stat statbuf;
1601 : :
1602 : : /* only handle symlinks and regular files */
1603 [ # # # # ]: 0 : if (!IN_SET(dent->d_type, DT_LNK, DT_REG))
1604 : 0 : continue;
1605 : :
1606 : 0 : path = path_join(syspath, dent->d_name);
1607 [ # # ]: 0 : if (!path)
1608 : 0 : return -ENOMEM;
1609 : :
1610 [ # # ]: 0 : if (lstat(path, &statbuf) != 0)
1611 : 0 : continue;
1612 : :
1613 [ # # ]: 0 : if (!(statbuf.st_mode & S_IRUSR))
1614 : 0 : continue;
1615 : :
1616 : 0 : r = set_put_strdup(device->sysattrs, dent->d_name);
1617 [ # # ]: 0 : if (r < 0)
1618 : 0 : return r;
1619 : : }
1620 : :
1621 : 0 : device->sysattrs_read = true;
1622 : :
1623 : 0 : return 0;
1624 : : }
1625 : :
1626 : 0 : _public_ const char *sd_device_get_sysattr_first(sd_device *device) {
1627 : : void *v;
1628 : : int r;
1629 : :
1630 [ # # # # ]: 0 : assert_return(device, NULL);
1631 : :
1632 [ # # ]: 0 : if (!device->sysattrs_read) {
1633 : 0 : r = device_sysattrs_read_all(device);
1634 [ # # ]: 0 : if (r < 0) {
1635 : 0 : errno = -r;
1636 : 0 : return NULL;
1637 : : }
1638 : : }
1639 : :
1640 : 0 : device->sysattrs_iterator = ITERATOR_FIRST;
1641 : :
1642 : 0 : (void) set_iterate(device->sysattrs, &device->sysattrs_iterator, &v);
1643 : 0 : return v;
1644 : : }
1645 : :
1646 : 0 : _public_ const char *sd_device_get_sysattr_next(sd_device *device) {
1647 : : void *v;
1648 : :
1649 [ # # # # ]: 0 : assert_return(device, NULL);
1650 : :
1651 [ # # ]: 0 : if (!device->sysattrs_read)
1652 : 0 : return NULL;
1653 : :
1654 : 0 : (void) set_iterate(device->sysattrs, &device->sysattrs_iterator, &v);
1655 : 0 : return v;
1656 : : }
1657 : :
1658 : 0 : _public_ int sd_device_has_tag(sd_device *device, const char *tag) {
1659 [ # # # # ]: 0 : assert_return(device, -EINVAL);
1660 [ # # # # ]: 0 : assert_return(tag, -EINVAL);
1661 : :
1662 : 0 : (void) device_read_db(device);
1663 : :
1664 : 0 : return !!set_contains(device->tags, tag);
1665 : : }
1666 : :
1667 : 36772 : _public_ int sd_device_get_property_value(sd_device *device, const char *key, const char **_value) {
1668 : : char *value;
1669 : : int r;
1670 : :
1671 [ - + - + ]: 36772 : assert_return(device, -EINVAL);
1672 [ - + - + ]: 36772 : assert_return(key, -EINVAL);
1673 : :
1674 : 36772 : r = device_properties_prepare(device);
1675 [ - + ]: 36772 : if (r < 0)
1676 : 0 : return r;
1677 : :
1678 : 36772 : value = ordered_hashmap_get(device->properties, key);
1679 [ + + ]: 36772 : if (!value)
1680 : 33956 : return -ENOENT;
1681 : :
1682 [ + - ]: 2816 : if (_value)
1683 : 2816 : *_value = value;
1684 : 2816 : return 0;
1685 : : }
1686 : :
1687 : : /* replaces the value if it already exists */
1688 : 4428 : static int device_add_sysattr_value(sd_device *device, const char *_key, char *value) {
1689 : 4428 : _cleanup_free_ char *key = NULL;
1690 : 4428 : _cleanup_free_ char *value_old = NULL;
1691 : : int r;
1692 : :
1693 [ - + ]: 4428 : assert(device);
1694 [ - + ]: 4428 : assert(_key);
1695 : :
1696 : 4428 : r = hashmap_ensure_allocated(&device->sysattr_values, &string_hash_ops);
1697 [ - + ]: 4428 : if (r < 0)
1698 : 0 : return r;
1699 : :
1700 : 4428 : value_old = hashmap_remove2(device->sysattr_values, _key, (void **)&key);
1701 [ + - ]: 4428 : if (!key) {
1702 : 4428 : key = strdup(_key);
1703 [ - + ]: 4428 : if (!key)
1704 : 0 : return -ENOMEM;
1705 : : }
1706 : :
1707 : 4428 : r = hashmap_put(device->sysattr_values, key, value);
1708 [ - + ]: 4428 : if (r < 0)
1709 : 0 : return r;
1710 : 4428 : TAKE_PTR(key);
1711 : :
1712 : 4428 : return 0;
1713 : : }
1714 : :
1715 : 4448 : static int device_get_sysattr_value(sd_device *device, const char *_key, const char **_value) {
1716 : 4448 : const char *key = NULL, *value;
1717 : :
1718 [ - + ]: 4448 : assert(device);
1719 [ - + ]: 4448 : assert(_key);
1720 : :
1721 : 4448 : value = hashmap_get2(device->sysattr_values, _key, (void **) &key);
1722 [ + + ]: 4448 : if (!key)
1723 : 4444 : return -ENOENT;
1724 : :
1725 [ + - ]: 4 : if (_value)
1726 : 4 : *_value = value;
1727 : 4 : return 0;
1728 : : }
1729 : :
1730 : : /* We cache all sysattr lookups. If an attribute does not exist, it is stored
1731 : : * with a NULL value in the cache, otherwise the returned string is stored */
1732 : 4448 : _public_ int sd_device_get_sysattr_value(sd_device *device, const char *sysattr, const char **_value) {
1733 : 4448 : _cleanup_free_ char *value = NULL;
1734 : 4448 : const char *path, *syspath, *cached_value = NULL;
1735 : : struct stat statbuf;
1736 : : int r;
1737 : :
1738 [ - + - + ]: 4448 : assert_return(device, -EINVAL);
1739 [ - + - + ]: 4448 : assert_return(sysattr, -EINVAL);
1740 : :
1741 : : /* look for possibly already cached result */
1742 : 4448 : r = device_get_sysattr_value(device, sysattr, &cached_value);
1743 [ + + ]: 4448 : if (r != -ENOENT) {
1744 [ - + ]: 4 : if (r < 0)
1745 : 0 : return r;
1746 : :
1747 [ - + ]: 4 : if (!cached_value)
1748 : : /* we looked up the sysattr before and it did not exist */
1749 : 0 : return -ENOENT;
1750 : :
1751 [ + - ]: 4 : if (_value)
1752 : 4 : *_value = cached_value;
1753 : :
1754 : 4 : return 0;
1755 : : }
1756 : :
1757 : 4444 : r = sd_device_get_syspath(device, &syspath);
1758 [ - + ]: 4444 : if (r < 0)
1759 : 0 : return r;
1760 : :
1761 [ - + # # : 4444 : path = prefix_roota(syspath, sysattr);
- + - + -
+ + - - +
+ - ]
1762 : 4444 : r = lstat(path, &statbuf);
1763 [ + + ]: 4444 : if (r < 0) {
1764 : : /* remember that we could not access the sysattr */
1765 : 4392 : r = device_add_sysattr_value(device, sysattr, NULL);
1766 [ - + ]: 4392 : if (r < 0)
1767 : 0 : return r;
1768 : :
1769 : 4392 : return -ENOENT;
1770 [ - + ]: 52 : } else if (S_ISLNK(statbuf.st_mode)) {
1771 : : /* Some core links return only the last element of the target path,
1772 : : * these are just values, the paths should not be exposed. */
1773 [ # # ]: 0 : if (STR_IN_SET(sysattr, "driver", "subsystem", "module")) {
1774 : 0 : r = readlink_value(path, &value);
1775 [ # # ]: 0 : if (r < 0)
1776 : 0 : return r;
1777 : : } else
1778 : 0 : return -EINVAL;
1779 [ - + ]: 52 : } else if (S_ISDIR(statbuf.st_mode)) {
1780 : : /* skip directories */
1781 : 0 : return -EINVAL;
1782 [ - + ]: 52 : } else if (!(statbuf.st_mode & S_IRUSR)) {
1783 : : /* skip non-readable files */
1784 : 0 : return -EPERM;
1785 : : } else {
1786 : : size_t size;
1787 : :
1788 : : /* read attribute value */
1789 : 52 : r = read_full_file(path, &value, &size);
1790 [ + + ]: 52 : if (r < 0)
1791 : 16 : return r;
1792 : :
1793 : : /* drop trailing newlines */
1794 [ + - + + ]: 72 : while (size > 0 && value[--size] == '\n')
1795 : 36 : value[size] = '\0';
1796 : : }
1797 : :
1798 : 36 : r = device_add_sysattr_value(device, sysattr, value);
1799 [ - + ]: 36 : if (r < 0)
1800 : 0 : return r;
1801 : :
1802 : 36 : *_value = TAKE_PTR(value);
1803 : :
1804 : 36 : return 0;
1805 : : }
1806 : :
1807 : 0 : static void device_remove_sysattr_value(sd_device *device, const char *_key) {
1808 : 0 : _cleanup_free_ char *key = NULL;
1809 : :
1810 [ # # ]: 0 : assert(device);
1811 [ # # ]: 0 : assert(_key);
1812 : :
1813 : 0 : free(hashmap_remove2(device->sysattr_values, _key, (void **) &key));
1814 : 0 : }
1815 : :
1816 : : /* set the attribute and save it in the cache. If a NULL value is passed the
1817 : : * attribute is cleared from the cache */
1818 : 0 : _public_ int sd_device_set_sysattr_value(sd_device *device, const char *sysattr, const char *_value) {
1819 : 0 : _cleanup_free_ char *value = NULL;
1820 : : const char *syspath, *path;
1821 : : size_t len;
1822 : : int r;
1823 : :
1824 [ # # # # ]: 0 : assert_return(device, -EINVAL);
1825 [ # # # # ]: 0 : assert_return(sysattr, -EINVAL);
1826 : :
1827 [ # # ]: 0 : if (!_value) {
1828 : 0 : device_remove_sysattr_value(device, sysattr);
1829 : 0 : return 0;
1830 : : }
1831 : :
1832 : 0 : r = sd_device_get_syspath(device, &syspath);
1833 [ # # ]: 0 : if (r < 0)
1834 : 0 : return r;
1835 : :
1836 [ # # # # : 0 : path = prefix_roota(syspath, sysattr);
# # # # #
# # # # #
# # ]
1837 : :
1838 : 0 : len = strlen(_value);
1839 : :
1840 : : /* drop trailing newlines */
1841 [ # # # # ]: 0 : while (len > 0 && _value[len - 1] == '\n')
1842 : 0 : len --;
1843 : :
1844 : : /* value length is limited to 4k */
1845 [ # # ]: 0 : if (len > 4096)
1846 : 0 : return -EINVAL;
1847 : :
1848 : 0 : value = strndup(_value, len);
1849 [ # # ]: 0 : if (!value)
1850 : 0 : return -ENOMEM;
1851 : :
1852 : 0 : r = write_string_file(path, value, WRITE_STRING_FILE_DISABLE_BUFFER | WRITE_STRING_FILE_NOFOLLOW);
1853 [ # # ]: 0 : if (r < 0) {
1854 [ # # ]: 0 : if (r == -ELOOP)
1855 : 0 : return -EINVAL;
1856 [ # # ]: 0 : if (r == -EISDIR)
1857 : 0 : return r;
1858 : :
1859 : 0 : r = free_and_strdup(&value, "");
1860 [ # # ]: 0 : if (r < 0)
1861 : 0 : return r;
1862 : :
1863 : 0 : r = device_add_sysattr_value(device, sysattr, value);
1864 [ # # ]: 0 : if (r < 0)
1865 : 0 : return r;
1866 : 0 : TAKE_PTR(value);
1867 : :
1868 : 0 : return -ENXIO;
1869 : : }
1870 : :
1871 : 0 : r = device_add_sysattr_value(device, sysattr, value);
1872 [ # # ]: 0 : if (r < 0)
1873 : 0 : return r;
1874 : 0 : TAKE_PTR(value);
1875 : :
1876 : 0 : return 0;
1877 : : }
|