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