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