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