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