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