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