]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd/sd-device/sd-device.c
Merge pull request #12 from systemd-mailing-devs/1433236104-9967-1-git-send-email...
[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 assert_return(device, NULL);
1375
1376 (void) device_read_db(device);
1377
1378 device->tags_iterator_generation = device->tags_generation;
1379 device->tags_iterator = ITERATOR_FIRST;
1380
1381 return set_iterate(device->tags, &device->tags_iterator);
1382 }
1383
1384 _public_ const char *sd_device_get_tag_next(sd_device *device) {
1385 assert_return(device, NULL);
1386
1387 (void) device_read_db(device);
1388
1389 if (device->tags_iterator_generation != device->tags_generation)
1390 return NULL;
1391
1392 return set_iterate(device->tags, &device->tags_iterator);
1393 }
1394
1395 _public_ const char *sd_device_get_devlink_first(sd_device *device) {
1396 assert_return(device, NULL);
1397
1398 (void) device_read_db(device);
1399
1400 device->devlinks_iterator_generation = device->devlinks_generation;
1401 device->devlinks_iterator = ITERATOR_FIRST;
1402
1403 return set_iterate(device->devlinks, &device->devlinks_iterator);
1404 }
1405
1406 _public_ const char *sd_device_get_devlink_next(sd_device *device) {
1407 assert_return(device, NULL);
1408
1409 (void) device_read_db(device);
1410
1411 if (device->devlinks_iterator_generation != device->devlinks_generation)
1412 return NULL;
1413
1414 return set_iterate(device->devlinks, &device->devlinks_iterator);
1415 }
1416
1417 static int device_properties_prepare(sd_device *device) {
1418 int r;
1419
1420 assert(device);
1421
1422 r = device_read_uevent_file(device);
1423 if (r < 0)
1424 return r;
1425
1426 r = device_read_db(device);
1427 if (r < 0)
1428 return r;
1429
1430 if (device->property_devlinks_outdated) {
1431 char *devlinks = NULL;
1432 const char *devlink;
1433
1434 devlink = sd_device_get_devlink_first(device);
1435 if (devlink)
1436 devlinks = strdupa(devlink);
1437
1438 while ((devlink = sd_device_get_devlink_next(device)))
1439 devlinks = strjoina(devlinks, " ", devlink);
1440
1441 r = device_add_property_internal(device, "DEVLINKS", devlinks);
1442 if (r < 0)
1443 return r;
1444
1445 device->property_devlinks_outdated = false;
1446 }
1447
1448 if (device->property_tags_outdated) {
1449 char *tags = NULL;
1450 const char *tag;
1451
1452 tag = sd_device_get_tag_first(device);
1453 if (tag)
1454 tags = strjoina(":", tag);
1455
1456 while ((tag = sd_device_get_tag_next(device)))
1457 tags = strjoina(tags, ":", tag);
1458
1459 tags = strjoina(tags, ":");
1460
1461 r = device_add_property_internal(device, "TAGS", tags);
1462 if (r < 0)
1463 return r;
1464
1465 device->property_tags_outdated = false;
1466 }
1467
1468 return 0;
1469 }
1470
1471 _public_ const char *sd_device_get_property_first(sd_device *device, const char **_value) {
1472 const char *key;
1473 const char *value;
1474 int r;
1475
1476 assert_return(device, NULL);
1477
1478 r = device_properties_prepare(device);
1479 if (r < 0)
1480 return NULL;
1481
1482 device->properties_iterator_generation = device->properties_generation;
1483 device->properties_iterator = ITERATOR_FIRST;
1484
1485 value = ordered_hashmap_iterate(device->properties, &device->properties_iterator, (const void**)&key);
1486
1487 if (_value)
1488 *_value = value;
1489
1490 return key;
1491 }
1492
1493 _public_ const char *sd_device_get_property_next(sd_device *device, const char **_value) {
1494 const char *key;
1495 const char *value;
1496 int r;
1497
1498 assert_return(device, NULL);
1499
1500 r = device_properties_prepare(device);
1501 if (r < 0)
1502 return NULL;
1503
1504 if (device->properties_iterator_generation != device->properties_generation)
1505 return NULL;
1506
1507 value = ordered_hashmap_iterate(device->properties, &device->properties_iterator, (const void**)&key);
1508
1509 if (_value)
1510 *_value = value;
1511
1512 return key;
1513 }
1514
1515 static int device_sysattrs_read_all(sd_device *device) {
1516 _cleanup_closedir_ DIR *dir = NULL;
1517 const char *syspath;
1518 struct dirent *dent;
1519 int r;
1520
1521 assert(device);
1522
1523 if (device->sysattrs_read)
1524 return 0;
1525
1526 r = sd_device_get_syspath(device, &syspath);
1527 if (r < 0)
1528 return r;
1529
1530 dir = opendir(syspath);
1531 if (!dir)
1532 return -errno;
1533
1534 r = set_ensure_allocated(&device->sysattrs, &string_hash_ops);
1535 if (r < 0)
1536 return r;
1537
1538 for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
1539 char *path;
1540 struct stat statbuf;
1541
1542 /* only handle symlinks and regular files */
1543 if (dent->d_type != DT_LNK && dent->d_type != DT_REG)
1544 continue;
1545
1546 path = strjoina(syspath, "/", dent->d_name);
1547
1548 if (lstat(path, &statbuf) != 0)
1549 continue;
1550
1551 if (!(statbuf.st_mode & S_IRUSR))
1552 continue;
1553
1554 r = set_put_strdup(device->sysattrs, dent->d_name);
1555 if (r < 0)
1556 return r;
1557 }
1558
1559 device->sysattrs_read = true;
1560
1561 return 0;
1562 }
1563
1564 _public_ const char *sd_device_get_sysattr_first(sd_device *device) {
1565 int r;
1566
1567 assert_return(device, NULL);
1568
1569 if (!device->sysattrs_read) {
1570 r = device_sysattrs_read_all(device);
1571 if (r < 0) {
1572 errno = -r;
1573 return NULL;
1574 }
1575 }
1576
1577 device->sysattrs_iterator = ITERATOR_FIRST;
1578
1579 return set_iterate(device->sysattrs, &device->sysattrs_iterator);
1580 }
1581
1582 _public_ const char *sd_device_get_sysattr_next(sd_device *device) {
1583 assert_return(device, NULL);
1584
1585 if (!device->sysattrs_read)
1586 return NULL;
1587
1588 return set_iterate(device->sysattrs, &device->sysattrs_iterator);
1589 }
1590
1591 _public_ int sd_device_has_tag(sd_device *device, const char *tag) {
1592 assert_return(device, -EINVAL);
1593 assert_return(tag, -EINVAL);
1594
1595 (void) device_read_db(device);
1596
1597 return !!set_contains(device->tags, tag);
1598 }
1599
1600 _public_ int sd_device_get_property_value(sd_device *device, const char *key, const char **_value) {
1601 char *value;
1602 int r;
1603
1604 assert_return(device, -EINVAL);
1605 assert_return(key, -EINVAL);
1606 assert_return(_value, -EINVAL);
1607
1608 r = device_properties_prepare(device);
1609 if (r < 0)
1610 return r;
1611
1612 value = ordered_hashmap_get(device->properties, key);
1613 if (!value)
1614 return -ENOENT;
1615
1616 *_value = value;
1617
1618 return 0;
1619 }
1620
1621 /* replaces the value if it already exists */
1622 static int device_add_sysattr_value(sd_device *device, const char *_key, char *value) {
1623 _cleanup_free_ char *key = NULL;
1624 _cleanup_free_ char *value_old = NULL;
1625 int r;
1626
1627 assert(device);
1628 assert(_key);
1629
1630 r = hashmap_ensure_allocated(&device->sysattr_values, &string_hash_ops);
1631 if (r < 0)
1632 return r;
1633
1634 value_old = hashmap_remove2(device->sysattr_values, _key, (void **)&key);
1635 if (!key) {
1636 key = strdup(_key);
1637 if (!key)
1638 return -ENOMEM;
1639 }
1640
1641 r = hashmap_put(device->sysattr_values, key, value);
1642 if (r < 0)
1643 return r;
1644
1645 key = NULL;
1646
1647 return 0;
1648 }
1649
1650 static int device_get_sysattr_value(sd_device *device, const char *_key, const char **_value) {
1651 const char *key = NULL, *value;
1652
1653 assert(device);
1654 assert(_key);
1655
1656 value = hashmap_get2(device->sysattr_values, _key, (void **) &key);
1657 if (!key)
1658 return -ENOENT;
1659
1660 if (_value)
1661 *_value = value;
1662
1663 return 0;
1664 }
1665
1666 /* We cache all sysattr lookups. If an attribute does not exist, it is stored
1667 * with a NULL value in the cache, otherwise the returned string is stored */
1668 _public_ int sd_device_get_sysattr_value(sd_device *device, const char *sysattr, const char **_value) {
1669 _cleanup_free_ char *value = NULL;
1670 const char *syspath, *cached_value = NULL;
1671 char *path;
1672 struct stat statbuf;
1673 int r;
1674
1675 assert_return(device, -EINVAL);
1676 assert_return(sysattr, -EINVAL);
1677
1678 /* look for possibly already cached result */
1679 r = device_get_sysattr_value(device, sysattr, &cached_value);
1680 if (r != -ENOENT) {
1681 if (r < 0)
1682 return r;
1683
1684 if (!cached_value)
1685 /* we looked up the sysattr before and it did not exist */
1686 return -ENOENT;
1687
1688 if (_value)
1689 *_value = cached_value;
1690
1691 return 0;
1692 }
1693
1694 r = sd_device_get_syspath(device, &syspath);
1695 if (r < 0)
1696 return r;
1697
1698 path = strjoina(syspath, "/", sysattr);
1699 r = lstat(path, &statbuf);
1700 if (r < 0) {
1701 /* remember that we could not access the sysattr */
1702 r = device_add_sysattr_value(device, sysattr, NULL);
1703 if (r < 0)
1704 return r;
1705
1706 return -ENOENT;
1707 } else if (S_ISLNK(statbuf.st_mode)) {
1708 /* Some core links return only the last element of the target path,
1709 * these are just values, the paths should not be exposed. */
1710 if (STR_IN_SET(sysattr, "driver", "subsystem", "module")) {
1711 r = readlink_value(path, &value);
1712 if (r < 0)
1713 return r;
1714 } else
1715 return -EINVAL;
1716 } else if (S_ISDIR(statbuf.st_mode)) {
1717 /* skip directories */
1718 return -EINVAL;
1719 } else if (!(statbuf.st_mode & S_IRUSR)) {
1720 /* skip non-readable files */
1721 return -EPERM;
1722 } else {
1723 size_t size;
1724
1725 /* read attribute value */
1726 r = read_full_file(path, &value, &size);
1727 if (r < 0)
1728 return r;
1729
1730 /* drop trailing newlines */
1731 while (size > 0 && value[--size] == '\n')
1732 value[size] = '\0';
1733 }
1734
1735 r = device_add_sysattr_value(device, sysattr, value);
1736 if (r < 0)
1737 return r;
1738
1739 *_value = value;
1740 value = NULL;
1741
1742 return 0;
1743 }
1744
1745 static void device_remove_sysattr_value(sd_device *device, const char *_key) {
1746 _cleanup_free_ char *key = NULL;
1747 _cleanup_free_ char *value = NULL;
1748
1749 assert(device);
1750 assert(_key);
1751
1752 value = hashmap_remove2(device->sysattr_values, _key, (void **) &key);
1753
1754 return;
1755 }
1756
1757 /* set the attribute and save it in the cache. If a NULL value is passed the
1758 * attribute is cleared from the cache */
1759 _public_ int sd_device_set_sysattr_value(sd_device *device, const char *sysattr, char *_value) {
1760 _cleanup_close_ int fd = -1;
1761 _cleanup_free_ char *value = NULL;
1762 const char *syspath;
1763 char *path;
1764 struct stat statbuf;
1765 size_t value_len = 0;
1766 ssize_t size;
1767 int r;
1768
1769 assert_return(device, -EINVAL);
1770 assert_return(sysattr, -EINVAL);
1771
1772 if (!_value) {
1773 device_remove_sysattr_value(device, sysattr);
1774
1775 return 0;
1776 }
1777
1778 r = sd_device_get_syspath(device, &syspath);
1779 if (r < 0)
1780 return r;
1781
1782 path = strjoina(syspath, "/", sysattr);
1783 r = lstat(path, &statbuf);
1784 if (r < 0) {
1785 value = strdup("");
1786 if (!value)
1787 return -ENOMEM;
1788
1789 r = device_add_sysattr_value(device, sysattr, value);
1790 if (r < 0)
1791 return r;
1792
1793 return -ENXIO;
1794 }
1795
1796 if (S_ISLNK(statbuf.st_mode))
1797 return -EINVAL;
1798
1799 /* skip directories */
1800 if (S_ISDIR(statbuf.st_mode))
1801 return -EISDIR;
1802
1803 /* skip non-readable files */
1804 if ((statbuf.st_mode & S_IRUSR) == 0)
1805 return -EACCES;
1806
1807 value_len = strlen(_value);
1808
1809 /* drop trailing newlines */
1810 while (value_len > 0 && _value[value_len - 1] == '\n')
1811 _value[--value_len] = '\0';
1812
1813 /* value length is limited to 4k */
1814 if (value_len > 4096)
1815 return -EINVAL;
1816
1817 fd = open(path, O_WRONLY | O_CLOEXEC);
1818 if (fd < 0)
1819 return -errno;
1820
1821 value = strdup(_value);
1822 if (!value)
1823 return -ENOMEM;
1824
1825 size = write(fd, value, value_len);
1826 if (size < 0)
1827 return -errno;
1828
1829 if ((size_t)size != value_len)
1830 return -EIO;
1831
1832 r = device_add_sysattr_value(device, sysattr, value);
1833 if (r < 0)
1834 return r;
1835
1836 value = NULL;
1837
1838 return 0;
1839 }