chiark / gitweb /
sd-device: never return NULL+0
[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         if (!device->subsystem)
795                 return -ENOENT;
796
797         *ret = device->subsystem;
798
799         return 0;
800 }
801
802 _public_ int sd_device_get_devtype(sd_device *device, const char **devtype) {
803         int r;
804
805         assert(devtype);
806         assert(device);
807
808         r = device_read_uevent_file(device);
809         if (r < 0)
810                 return r;
811
812         *devtype = device->devtype;
813
814         return 0;
815 }
816
817 _public_ int sd_device_get_parent_with_subsystem_devtype(sd_device *child, const char *subsystem, const char *devtype, sd_device **ret) {
818         sd_device *parent = NULL;
819         int r;
820
821         assert_return(child, -EINVAL);
822         assert_return(subsystem, -EINVAL);
823
824         r = sd_device_get_parent(child, &parent);
825         while (r >= 0) {
826                 const char *parent_subsystem = NULL;
827                 const char *parent_devtype = NULL;
828
829                 (void)sd_device_get_subsystem(parent, &parent_subsystem);
830                 if (streq_ptr(parent_subsystem, subsystem)) {
831                         if (!devtype)
832                                 break;
833
834                         (void)sd_device_get_devtype(parent, &parent_devtype);
835                         if (streq_ptr(parent_devtype, devtype))
836                                 break;
837                 }
838                 r = sd_device_get_parent(parent, &parent);
839         }
840
841         if (r < 0)
842                 return r;
843
844         *ret = parent;
845
846         return 0;
847 }
848
849 _public_ int sd_device_get_devnum(sd_device *device, dev_t *devnum) {
850         int r;
851
852         assert_return(device, -EINVAL);
853         assert_return(devnum, -EINVAL);
854
855         r = device_read_uevent_file(device);
856         if (r < 0)
857                 return r;
858
859         *devnum = device->devnum;
860
861         return 0;
862 }
863
864 int device_set_driver(sd_device *device, const char *_driver) {
865         _cleanup_free_ char *driver = NULL;
866         int r;
867
868         assert(device);
869         assert(_driver);
870
871         driver = strdup(_driver);
872         if (!driver)
873                 return -ENOMEM;
874
875         r = device_add_property_internal(device, "DRIVER", driver);
876         if (r < 0)
877                 return r;
878
879         free(device->driver);
880         device->driver = driver;
881         driver = NULL;
882
883         device->driver_set = true;
884
885         return 0;
886 }
887
888 _public_ int sd_device_get_driver(sd_device *device, const char **ret) {
889         assert_return(device, -EINVAL);
890         assert_return(ret, -EINVAL);
891
892         if (!device->driver_set) {
893                 _cleanup_free_ char *driver = NULL;
894                 const char *syspath;
895                 char *path;
896                 int r;
897
898                 r = sd_device_get_syspath(device, &syspath);
899                 if (r < 0)
900                         return r;
901
902                 path = strjoina(syspath, "/driver");
903                 r = readlink_value(path, &driver);
904                 if (r >= 0) {
905                         r = device_set_driver(device, driver);
906                         if (r < 0)
907                                 return log_debug_errno(r, "sd-device: could not set driver for %s: %m", device->devpath);
908                 } else if (r == -ENOENT)
909                         device->driver_set = true;
910                 else
911                         return log_debug_errno(r, "sd-device: could not set driver for %s: %m", device->devpath);
912         }
913
914         if (!device->driver)
915                 return -ENOENT;
916
917         *ret = device->driver;
918
919         return 0;
920 }
921
922 _public_ int sd_device_get_devpath(sd_device *device, const char **devpath) {
923         assert_return(device, -EINVAL);
924         assert_return(devpath, -EINVAL);
925
926         assert(device->devpath);
927         assert(device->devpath[0] == '/');
928
929         *devpath = device->devpath;
930
931         return 0;
932 }
933
934 _public_ int sd_device_get_devname(sd_device *device, const char **devname) {
935         int r;
936
937         assert_return(device, -EINVAL);
938         assert_return(devname, -EINVAL);
939
940         r = device_read_uevent_file(device);
941         if (r < 0)
942                 return r;
943
944         if (!device->devname)
945                 return -ENOENT;
946
947         assert(path_startswith(device->devname, "/dev/"));
948
949         *devname = device->devname;
950
951         return 0;
952 }
953
954 static int device_set_sysname(sd_device *device) {
955         _cleanup_free_ char *sysname = NULL;
956         const char *sysnum = NULL;
957         const char *pos;
958         size_t len = 0;
959
960         pos = strrchr(device->devpath, '/');
961         if (!pos)
962                 return -EINVAL;
963         pos ++;
964
965         /* devpath is not a root directory */
966         if (*pos == '\0' || pos <= device->devpath)
967                 return -EINVAL;
968
969         sysname = strdup(pos);
970         if (!sysname)
971                 return -ENOMEM;
972
973         /* some devices have '!' in their name, change that to '/' */
974         while (sysname[len] != '\0') {
975                 if (sysname[len] == '!')
976                         sysname[len] = '/';
977
978                 len ++;
979         }
980
981         /* trailing number */
982         while (len > 0 && isdigit(sysname[--len]))
983                 sysnum = &sysname[len];
984
985         if (len == 0)
986                 sysnum = NULL;
987
988         free(device->sysname);
989         device->sysname = sysname;
990         sysname = NULL;
991
992         device->sysnum = sysnum;
993
994         device->sysname_set = true;
995
996         return 0;
997 }
998
999 _public_ int sd_device_get_sysname(sd_device *device, const char **ret) {
1000         int r;
1001
1002         assert_return(device, -EINVAL);
1003         assert_return(ret, -EINVAL);
1004
1005         if (!device->sysname_set) {
1006                 r = device_set_sysname(device);
1007                 if (r < 0)
1008                         return r;
1009         }
1010
1011         assert_return(device->sysname, -ENOENT);
1012
1013         *ret = device->sysname;
1014
1015         return 0;
1016 }
1017
1018 _public_ int sd_device_get_sysnum(sd_device *device, const char **ret) {
1019         int r;
1020
1021         assert_return(device, -EINVAL);
1022         assert_return(ret, -EINVAL);
1023
1024         if (!device->sysname_set) {
1025                 r = device_set_sysname(device);
1026                 if (r < 0)
1027                         return r;
1028         }
1029
1030         *ret = device->sysnum;
1031
1032         return 0;
1033 }
1034
1035 static bool is_valid_tag(const char *tag) {
1036         assert(tag);
1037
1038         return !strchr(tag, ':') && !strchr(tag, ' ');
1039 }
1040
1041 int device_add_tag(sd_device *device, const char *tag) {
1042         int r;
1043
1044         assert(device);
1045         assert(tag);
1046
1047         if (!is_valid_tag(tag))
1048                 return -EINVAL;
1049
1050         r = set_ensure_allocated(&device->tags, &string_hash_ops);
1051         if (r < 0)
1052                 return r;
1053
1054         r = set_put_strdup(device->tags, tag);
1055         if (r < 0)
1056                 return r;
1057
1058         device->tags_generation ++;
1059         device->property_tags_outdated = true;
1060
1061         return 0;
1062 }
1063
1064 int device_add_devlink(sd_device *device, const char *devlink) {
1065         int r;
1066
1067         assert(device);
1068         assert(devlink);
1069
1070         r = set_ensure_allocated(&device->devlinks, &string_hash_ops);
1071         if (r < 0)
1072                 return r;
1073
1074         r = set_put_strdup(device->devlinks, devlink);
1075         if (r < 0)
1076                 return r;
1077
1078         device->devlinks_generation ++;
1079         device->property_devlinks_outdated = true;
1080
1081         return 0;
1082 }
1083
1084 static int device_add_property_internal_from_string(sd_device *device, const char *str) {
1085         _cleanup_free_ char *key = NULL;
1086         char *value;
1087
1088         assert(device);
1089         assert(str);
1090
1091         key = strdup(str);
1092         if (!key)
1093                 return -ENOMEM;
1094
1095         value = strchr(key, '=');
1096         if (!value)
1097                 return -EINVAL;
1098
1099         *value = '\0';
1100
1101         if (isempty(++value))
1102                 value = NULL;
1103
1104         return device_add_property_internal(device, key, value);
1105 }
1106
1107 int device_set_usec_initialized(sd_device *device, const char *initialized) {
1108         uint64_t usec_initialized;
1109         int r;
1110
1111         assert(device);
1112         assert(initialized);
1113
1114         r = safe_atou64(initialized, &usec_initialized);
1115         if (r < 0)
1116                 return r;
1117
1118         r = device_add_property_internal(device, "USEC_INITIALIZED", initialized);
1119         if (r < 0)
1120                 return r;
1121
1122         device->usec_initialized = usec_initialized;
1123
1124         return 0;
1125 }
1126
1127 static int handle_db_line(sd_device *device, char key, const char *value) {
1128         char *path;
1129         int r;
1130
1131         assert(device);
1132         assert(value);
1133
1134         switch (key) {
1135         case 'G':
1136                 r = device_add_tag(device, value);
1137                 if (r < 0)
1138                         return r;
1139
1140                 break;
1141         case 'S':
1142                 path = strjoina("/dev/", value);
1143                 r = device_add_devlink(device, path);
1144                 if (r < 0)
1145                         return r;
1146
1147                 break;
1148         case 'E':
1149                 r = device_add_property_internal_from_string(device, value);
1150                 if (r < 0)
1151                         return r;
1152
1153                 break;
1154         case 'I':
1155                 r = device_set_usec_initialized(device, value);
1156                 if (r < 0)
1157                         return r;
1158
1159                 break;
1160         case 'L':
1161                 r = safe_atoi(value, &device->devlink_priority);
1162                 if (r < 0)
1163                         return r;
1164
1165                 break;
1166         case 'W':
1167                 r = safe_atoi(value, &device->watch_handle);
1168                 if (r < 0)
1169                         return r;
1170
1171                 break;
1172         default:
1173                 log_debug("device db: unknown key '%c'", key);
1174         }
1175
1176         return 0;
1177 }
1178
1179 int device_get_id_filename(sd_device *device, const char **ret) {
1180         assert(device);
1181         assert(ret);
1182
1183         if (!device->id_filename) {
1184                 _cleanup_free_ char *id = NULL;
1185                 const char *subsystem;
1186                 dev_t devnum;
1187                 int ifindex, r;
1188
1189                 r = sd_device_get_subsystem(device, &subsystem);
1190                 if (r < 0)
1191                         return r;
1192
1193                 r = sd_device_get_devnum(device, &devnum);
1194                 if (r < 0)
1195                         return r;
1196
1197                 r = sd_device_get_ifindex(device, &ifindex);
1198                 if (r < 0)
1199                         return r;
1200
1201                 if (major(devnum) > 0) {
1202                         assert(subsystem);
1203
1204                         /* use dev_t -- b259:131072, c254:0 */
1205                         r = asprintf(&id, "%c%u:%u",
1206                                      streq(subsystem, "block") ? 'b' : 'c',
1207                                      major(devnum), minor(devnum));
1208                         if (r < 0)
1209                                 return -ENOMEM;
1210                 } else if (ifindex > 0) {
1211                         /* use netdev ifindex -- n3 */
1212                         r = asprintf(&id, "n%u", ifindex);
1213                         if (r < 0)
1214                                 return -ENOMEM;
1215                 } else {
1216                         /* use $subsys:$sysname -- pci:0000:00:1f.2
1217                          * sysname() has '!' translated, get it from devpath
1218                          */
1219                         const char *sysname;
1220
1221                         sysname = basename(device->devpath);
1222                         if (!sysname)
1223                                 return -EINVAL;
1224
1225                         if (!subsystem)
1226                                 return -EINVAL;
1227
1228                         r = asprintf(&id, "+%s:%s", subsystem, sysname);
1229                         if (r < 0)
1230                                 return -ENOMEM;
1231                 }
1232
1233                 device->id_filename = id;
1234                 id = NULL;
1235         }
1236
1237         *ret = device->id_filename;
1238
1239         return 0;
1240 }
1241
1242 int device_read_db_aux(sd_device *device, bool force) {
1243         _cleanup_free_ char *db = NULL;
1244         char *path;
1245         const char *id, *value;
1246         char key;
1247         size_t db_len;
1248         unsigned i;
1249         int r;
1250
1251         enum {
1252                 PRE_KEY,
1253                 KEY,
1254                 PRE_VALUE,
1255                 VALUE,
1256                 INVALID_LINE,
1257         } state = PRE_KEY;
1258
1259         if (device->db_loaded || (!force && device->sealed))
1260                 return 0;
1261
1262         device->db_loaded = true;
1263
1264         r = device_get_id_filename(device, &id);
1265         if (r < 0)
1266                 return r;
1267
1268         path = strjoina("/run/udev/data/", id);
1269
1270         r = read_full_file(path, &db, &db_len);
1271         if (r < 0) {
1272                 if (r == -ENOENT)
1273                         return 0;
1274                 else {
1275                         log_debug("sd-device: failed to read db '%s': %s", path, strerror(-r));
1276                         return r;
1277                 }
1278         }
1279
1280         /* devices with a database entry are initialized */
1281         device->is_initialized = true;
1282
1283         for (i = 0; i < db_len; i++) {
1284                 switch (state) {
1285                 case PRE_KEY:
1286                         if (!strchr(NEWLINE, db[i])) {
1287                                 key = db[i];
1288
1289                                 state = KEY;
1290                         }
1291
1292                         break;
1293                 case KEY:
1294                         if (db[i] != ':') {
1295                                 log_debug("sd-device: ignoring invalid db entry with key '%c'", key);
1296
1297                                 state = INVALID_LINE;
1298                         } else {
1299                                 db[i] = '\0';
1300
1301                                 state = PRE_VALUE;
1302                         }
1303
1304                         break;
1305                 case PRE_VALUE:
1306                         value = &db[i];
1307
1308                         state = VALUE;
1309
1310                         break;
1311                 case INVALID_LINE:
1312                         if (strchr(NEWLINE, db[i]))
1313                                 state = PRE_KEY;
1314
1315                         break;
1316                 case VALUE:
1317                         if (strchr(NEWLINE, db[i])) {
1318                                 db[i] = '\0';
1319                                 r = handle_db_line(device, key, value);
1320                                 if (r < 0)
1321                                         log_debug("sd-device: failed to handle db entry '%c:%s': %s", key, value, strerror(-r));
1322
1323                                 state = PRE_KEY;
1324                         }
1325
1326                         break;
1327                 default:
1328                         assert_not_reached("invalid state when parsing db");
1329                 }
1330         }
1331
1332         return 0;
1333 }
1334
1335 static int device_read_db(sd_device *device) {
1336         return device_read_db_aux(device, false);
1337 }
1338
1339 _public_ int sd_device_get_is_initialized(sd_device *device, int *initialized) {
1340         int r;
1341
1342         assert_return(device, -EINVAL);
1343         assert_return(initialized, -EINVAL);
1344
1345         r = device_read_db(device);
1346         if (r < 0)
1347                 return r;
1348
1349         *initialized = device->is_initialized;
1350
1351         return 0;
1352 }
1353
1354 _public_ int sd_device_get_usec_since_initialized(sd_device *device, uint64_t *usec) {
1355         usec_t now_ts;
1356         int r;
1357
1358         assert_return(device, -EINVAL);
1359         assert_return(usec, -EINVAL);
1360
1361         r = device_read_db(device);
1362         if (r < 0)
1363                 return r;
1364
1365         if (!device->is_initialized)
1366                 return -EBUSY;
1367
1368         if (!device->usec_initialized)
1369                 return -ENODATA;
1370
1371         now_ts = now(clock_boottime_or_monotonic());
1372
1373         if (now_ts < device->usec_initialized)
1374                 return -EIO;
1375
1376         *usec = now_ts - device->usec_initialized;
1377
1378         return 0;
1379 }
1380
1381 _public_ const char *sd_device_get_tag_first(sd_device *device) {
1382         void *v;
1383
1384         assert_return(device, NULL);
1385
1386         (void) device_read_db(device);
1387
1388         device->tags_iterator_generation = device->tags_generation;
1389         device->tags_iterator = ITERATOR_FIRST;
1390
1391         set_iterate(device->tags, &device->tags_iterator, &v);
1392         return v;
1393 }
1394
1395 _public_ const char *sd_device_get_tag_next(sd_device *device) {
1396         void *v;
1397
1398         assert_return(device, NULL);
1399
1400         (void) device_read_db(device);
1401
1402         if (device->tags_iterator_generation != device->tags_generation)
1403                 return NULL;
1404
1405         set_iterate(device->tags, &device->tags_iterator, &v);
1406         return v;
1407 }
1408
1409 _public_ const char *sd_device_get_devlink_first(sd_device *device) {
1410         void *v;
1411
1412         assert_return(device, NULL);
1413
1414         (void) device_read_db(device);
1415
1416         device->devlinks_iterator_generation = device->devlinks_generation;
1417         device->devlinks_iterator = ITERATOR_FIRST;
1418
1419         set_iterate(device->devlinks, &device->devlinks_iterator, &v);
1420         return v;
1421 }
1422
1423 _public_ const char *sd_device_get_devlink_next(sd_device *device) {
1424         void *v;
1425
1426         assert_return(device, NULL);
1427
1428         (void) device_read_db(device);
1429
1430         if (device->devlinks_iterator_generation != device->devlinks_generation)
1431                 return NULL;
1432
1433         set_iterate(device->devlinks, &device->devlinks_iterator, &v);
1434         return v;
1435 }
1436
1437 static int device_properties_prepare(sd_device *device) {
1438         int r;
1439
1440         assert(device);
1441
1442         r = device_read_uevent_file(device);
1443         if (r < 0)
1444                 return r;
1445
1446         r = device_read_db(device);
1447         if (r < 0)
1448                 return r;
1449
1450         if (device->property_devlinks_outdated) {
1451                 char *devlinks = NULL;
1452                 const char *devlink;
1453
1454                 devlink = sd_device_get_devlink_first(device);
1455                 if (devlink)
1456                         devlinks = strdupa(devlink);
1457
1458                 while ((devlink = sd_device_get_devlink_next(device)))
1459                         devlinks = strjoina(devlinks, " ", devlink);
1460
1461                 r = device_add_property_internal(device, "DEVLINKS", devlinks);
1462                 if (r < 0)
1463                         return r;
1464
1465                 device->property_devlinks_outdated = false;
1466         }
1467
1468         if (device->property_tags_outdated) {
1469                 char *tags = NULL;
1470                 const char *tag;
1471
1472                 tag = sd_device_get_tag_first(device);
1473                 if (tag)
1474                         tags = strjoina(":", tag);
1475
1476                 while ((tag = sd_device_get_tag_next(device)))
1477                         tags = strjoina(tags, ":", tag);
1478
1479                 tags = strjoina(tags, ":");
1480
1481                 r = device_add_property_internal(device, "TAGS", tags);
1482                 if (r < 0)
1483                         return r;
1484
1485                 device->property_tags_outdated = false;
1486         }
1487
1488         return 0;
1489 }
1490
1491 _public_ const char *sd_device_get_property_first(sd_device *device, const char **_value) {
1492         const char *key;
1493         const char *value;
1494         int r;
1495
1496         assert_return(device, NULL);
1497
1498         r = device_properties_prepare(device);
1499         if (r < 0)
1500                 return NULL;
1501
1502         device->properties_iterator_generation = device->properties_generation;
1503         device->properties_iterator = ITERATOR_FIRST;
1504
1505         ordered_hashmap_iterate(device->properties, &device->properties_iterator, (void**)&value, (const void**)&key);
1506
1507         if (_value)
1508                 *_value = value;
1509
1510         return key;
1511 }
1512
1513 _public_ const char *sd_device_get_property_next(sd_device *device, const char **_value) {
1514         const char *key;
1515         const char *value;
1516         int r;
1517
1518         assert_return(device, NULL);
1519
1520         r = device_properties_prepare(device);
1521         if (r < 0)
1522                 return NULL;
1523
1524         if (device->properties_iterator_generation != device->properties_generation)
1525                 return NULL;
1526
1527         ordered_hashmap_iterate(device->properties, &device->properties_iterator, (void**)&value, (const void**)&key);
1528
1529         if (_value)
1530                 *_value = value;
1531
1532         return key;
1533 }
1534
1535 static int device_sysattrs_read_all(sd_device *device) {
1536         _cleanup_closedir_ DIR *dir = NULL;
1537         const char *syspath;
1538         struct dirent *dent;
1539         int r;
1540
1541         assert(device);
1542
1543         if (device->sysattrs_read)
1544                 return 0;
1545
1546         r = sd_device_get_syspath(device, &syspath);
1547         if (r < 0)
1548                 return r;
1549
1550         dir = opendir(syspath);
1551         if (!dir)
1552                 return -errno;
1553
1554         r = set_ensure_allocated(&device->sysattrs, &string_hash_ops);
1555         if (r < 0)
1556                 return r;
1557
1558         for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
1559                 char *path;
1560                 struct stat statbuf;
1561
1562                 /* only handle symlinks and regular files */
1563                 if (dent->d_type != DT_LNK && dent->d_type != DT_REG)
1564                         continue;
1565
1566                 path = strjoina(syspath, "/", dent->d_name);
1567
1568                 if (lstat(path, &statbuf) != 0)
1569                         continue;
1570
1571                 if (!(statbuf.st_mode & S_IRUSR))
1572                         continue;
1573
1574                 r = set_put_strdup(device->sysattrs, dent->d_name);
1575                 if (r < 0)
1576                         return r;
1577         }
1578
1579         device->sysattrs_read = true;
1580
1581         return 0;
1582 }
1583
1584 _public_ const char *sd_device_get_sysattr_first(sd_device *device) {
1585         void *v;
1586         int r;
1587
1588         assert_return(device, NULL);
1589
1590         if (!device->sysattrs_read) {
1591                 r = device_sysattrs_read_all(device);
1592                 if (r < 0) {
1593                         errno = -r;
1594                         return NULL;
1595                 }
1596         }
1597
1598         device->sysattrs_iterator = ITERATOR_FIRST;
1599
1600         set_iterate(device->sysattrs, &device->sysattrs_iterator, &v);
1601         return v;
1602 }
1603
1604 _public_ const char *sd_device_get_sysattr_next(sd_device *device) {
1605         void *v;
1606
1607         assert_return(device, NULL);
1608
1609         if (!device->sysattrs_read)
1610                 return NULL;
1611
1612         set_iterate(device->sysattrs, &device->sysattrs_iterator, &v);
1613         return v;
1614 }
1615
1616 _public_ int sd_device_has_tag(sd_device *device, const char *tag) {
1617         assert_return(device, -EINVAL);
1618         assert_return(tag, -EINVAL);
1619
1620         (void) device_read_db(device);
1621
1622         return !!set_contains(device->tags, tag);
1623 }
1624
1625 _public_ int sd_device_get_property_value(sd_device *device, const char *key, const char **_value) {
1626         char *value;
1627         int r;
1628
1629         assert_return(device, -EINVAL);
1630         assert_return(key, -EINVAL);
1631         assert_return(_value, -EINVAL);
1632
1633         r = device_properties_prepare(device);
1634         if (r < 0)
1635                 return r;
1636
1637         value = ordered_hashmap_get(device->properties, key);
1638         if (!value)
1639                 return -ENOENT;
1640
1641         *_value = value;
1642
1643         return 0;
1644 }
1645
1646 /* replaces the value if it already exists */
1647 static int device_add_sysattr_value(sd_device *device, const char *_key, char *value) {
1648         _cleanup_free_ char *key = NULL;
1649         _cleanup_free_ char *value_old = NULL;
1650         int r;
1651
1652         assert(device);
1653         assert(_key);
1654
1655         r = hashmap_ensure_allocated(&device->sysattr_values, &string_hash_ops);
1656         if (r < 0)
1657                 return r;
1658
1659         value_old = hashmap_remove2(device->sysattr_values, _key, (void **)&key);
1660         if (!key) {
1661                 key = strdup(_key);
1662                 if (!key)
1663                         return -ENOMEM;
1664         }
1665
1666         r = hashmap_put(device->sysattr_values, key, value);
1667         if (r < 0)
1668                 return r;
1669
1670         key = NULL;
1671
1672         return 0;
1673 }
1674
1675 static int device_get_sysattr_value(sd_device *device, const char *_key, const char **_value) {
1676         const char *key = NULL, *value;
1677
1678         assert(device);
1679         assert(_key);
1680
1681         value = hashmap_get2(device->sysattr_values, _key, (void **) &key);
1682         if (!key)
1683                 return -ENOENT;
1684
1685         if (_value)
1686                 *_value = value;
1687
1688         return 0;
1689 }
1690
1691 /* We cache all sysattr lookups. If an attribute does not exist, it is stored
1692  * with a NULL value in the cache, otherwise the returned string is stored */
1693 _public_ int sd_device_get_sysattr_value(sd_device *device, const char *sysattr, const char **_value) {
1694         _cleanup_free_ char *value = NULL;
1695         const char *syspath, *cached_value = NULL;
1696         char *path;
1697         struct stat statbuf;
1698         int r;
1699
1700         assert_return(device, -EINVAL);
1701         assert_return(sysattr, -EINVAL);
1702
1703         /* look for possibly already cached result */
1704         r = device_get_sysattr_value(device, sysattr, &cached_value);
1705         if (r != -ENOENT) {
1706                 if (r < 0)
1707                         return r;
1708
1709                 if (!cached_value)
1710                         /* we looked up the sysattr before and it did not exist */
1711                         return -ENOENT;
1712
1713                 if (_value)
1714                         *_value = cached_value;
1715
1716                 return 0;
1717         }
1718
1719         r = sd_device_get_syspath(device, &syspath);
1720         if (r < 0)
1721                 return r;
1722
1723         path = strjoina(syspath, "/", sysattr);
1724         r = lstat(path, &statbuf);
1725         if (r < 0) {
1726                 /* remember that we could not access the sysattr */
1727                 r = device_add_sysattr_value(device, sysattr, NULL);
1728                 if (r < 0)
1729                         return r;
1730
1731                 return -ENOENT;
1732         } else if (S_ISLNK(statbuf.st_mode)) {
1733                 /* Some core links return only the last element of the target path,
1734                  * these are just values, the paths should not be exposed. */
1735                 if (STR_IN_SET(sysattr, "driver", "subsystem", "module")) {
1736                         r = readlink_value(path, &value);
1737                         if (r < 0)
1738                                 return r;
1739                 } else
1740                         return -EINVAL;
1741         } else if (S_ISDIR(statbuf.st_mode)) {
1742                 /* skip directories */
1743                 return -EINVAL;
1744         } else if (!(statbuf.st_mode & S_IRUSR)) {
1745                 /* skip non-readable files */
1746                 return -EPERM;
1747         } else {
1748                 size_t size;
1749
1750                 /* read attribute value */
1751                 r = read_full_file(path, &value, &size);
1752                 if (r < 0)
1753                         return r;
1754
1755                 /* drop trailing newlines */
1756                 while (size > 0 && value[--size] == '\n')
1757                         value[size] = '\0';
1758         }
1759
1760         r = device_add_sysattr_value(device, sysattr, value);
1761         if (r < 0)
1762                 return r;
1763
1764         *_value = value;
1765         value = NULL;
1766
1767         return 0;
1768 }
1769
1770 static void device_remove_sysattr_value(sd_device *device, const char *_key) {
1771         _cleanup_free_ char *key = NULL;
1772         _cleanup_free_ char *value = NULL;
1773
1774         assert(device);
1775         assert(_key);
1776
1777         value = hashmap_remove2(device->sysattr_values, _key, (void **) &key);
1778
1779         return;
1780 }
1781
1782 /* set the attribute and save it in the cache. If a NULL value is passed the
1783  * attribute is cleared from the cache */
1784 _public_ int sd_device_set_sysattr_value(sd_device *device, const char *sysattr, char *_value) {
1785         _cleanup_close_ int fd = -1;
1786         _cleanup_free_ char *value = NULL;
1787         const char *syspath;
1788         char *path;
1789         struct stat statbuf;
1790         size_t value_len = 0;
1791         ssize_t size;
1792         int r;
1793
1794         assert_return(device, -EINVAL);
1795         assert_return(sysattr, -EINVAL);
1796
1797         if (!_value) {
1798                 device_remove_sysattr_value(device, sysattr);
1799
1800                 return 0;
1801         }
1802
1803         r = sd_device_get_syspath(device, &syspath);
1804         if (r < 0)
1805                 return r;
1806
1807         path = strjoina(syspath, "/", sysattr);
1808         r = lstat(path, &statbuf);
1809         if (r < 0) {
1810                 value = strdup("");
1811                 if (!value)
1812                         return -ENOMEM;
1813
1814                 r = device_add_sysattr_value(device, sysattr, value);
1815                 if (r < 0)
1816                         return r;
1817
1818                 return -ENXIO;
1819         }
1820
1821         if (S_ISLNK(statbuf.st_mode))
1822                 return -EINVAL;
1823
1824         /* skip directories */
1825         if (S_ISDIR(statbuf.st_mode))
1826                 return -EISDIR;
1827
1828         /* skip non-readable files */
1829         if ((statbuf.st_mode & S_IRUSR) == 0)
1830                 return -EACCES;
1831
1832         value_len = strlen(_value);
1833
1834         /* drop trailing newlines */
1835         while (value_len > 0 && _value[value_len - 1] == '\n')
1836                 _value[--value_len] = '\0';
1837
1838         /* value length is limited to 4k */
1839         if (value_len > 4096)
1840                 return -EINVAL;
1841
1842         fd = open(path, O_WRONLY | O_CLOEXEC);
1843         if (fd < 0)
1844                 return -errno;
1845
1846         value = strdup(_value);
1847         if (!value)
1848                 return -ENOMEM;
1849
1850         size = write(fd, value, value_len);
1851         if (size < 0)
1852                 return -errno;
1853
1854         if ((size_t)size != value_len)
1855                 return -EIO;
1856
1857         r = device_add_sysattr_value(device, sysattr, value);
1858         if (r < 0)
1859                 return r;
1860
1861         value = NULL;
1862
1863         return 0;
1864 }