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