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