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