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