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