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