chiark / gitweb /
sd-device: don't retry loading uevent/db files more than once
[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)
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                         /* use dev_t -- b259:131072, c254:0 */
1192                         r = asprintf(&id, "%c%u:%u",
1193                                      streq(subsystem, "block") ? 'b' : 'c',
1194                                      major(devnum), minor(devnum));
1195                         if (r < 0)
1196                                 return -errno;
1197                 } else if (ifindex > 0) {
1198                         /* use netdev ifindex -- n3 */
1199                         r = asprintf(&id, "n%u", ifindex);
1200                         if (r < 0)
1201                                 return -errno;
1202                 } else {
1203                         /* use $subsys:$sysname -- pci:0000:00:1f.2
1204                          * sysname() has '!' translated, get it from devpath
1205                          */
1206                         const char *sysname;
1207
1208                         sysname = basename(device->devpath);
1209                         if (!sysname)
1210                                 return -EINVAL;
1211
1212                         r = asprintf(&id, "+%s:%s", subsystem, sysname);
1213                         if (r < 0)
1214                                 return -errno;
1215                 }
1216
1217                 device->id_filename = id;
1218                 id = NULL;
1219         }
1220
1221         *ret = device->id_filename;
1222
1223         return 0;
1224 }
1225
1226 int device_read_db_aux(sd_device *device, bool force) {
1227         _cleanup_free_ char *db = NULL;
1228         char *path;
1229         const char *id, *value;
1230         char key;
1231         size_t db_len;
1232         unsigned i;
1233         int r;
1234
1235         enum {
1236                 PRE_KEY,
1237                 KEY,
1238                 PRE_VALUE,
1239                 VALUE,
1240                 INVALID_LINE,
1241         } state = PRE_KEY;
1242
1243         if (device->db_loaded || (!force && device->sealed))
1244                 return 0;
1245
1246         device->db_loaded = true;
1247
1248         r = device_get_id_filename(device, &id);
1249         if (r < 0)
1250                 return r;
1251
1252         path = strjoina("/run/udev/data/", id);
1253
1254         r = read_full_file(path, &db, &db_len);
1255         if (r < 0) {
1256                 if (r == -ENOENT)
1257                         return 0;
1258                 else {
1259                         log_debug("sd-device: failed to read db '%s': %s", path, strerror(-r));
1260                         return r;
1261                 }
1262         }
1263
1264         /* devices with a database entry are initialized */
1265         device->is_initialized = true;;
1266
1267         for (i = 0; i < db_len; i++) {
1268                 switch (state) {
1269                 case PRE_KEY:
1270                         if (!strchr(NEWLINE, db[i])) {
1271                                 key = db[i];
1272
1273                                 state = KEY;
1274                         }
1275
1276                         break;
1277                 case KEY:
1278                         if (db[i] != ':') {
1279                                 log_debug("sd-device: ignoring invalid db entry with key '%c'", key);
1280
1281                                 state = INVALID_LINE;
1282                         } else {
1283                                 db[i] = '\0';
1284
1285                                 state = PRE_VALUE;
1286                         }
1287
1288                         break;
1289                 case PRE_VALUE:
1290                         value = &db[i];
1291
1292                         state = VALUE;
1293
1294                         break;
1295                 case INVALID_LINE:
1296                         if (strchr(NEWLINE, db[i]))
1297                                 state = PRE_KEY;
1298
1299                         break;
1300                 case VALUE:
1301                         if (strchr(NEWLINE, db[i])) {
1302                                 db[i] = '\0';
1303                                 r = handle_db_line(device, key, value);
1304                                 if (r < 0)
1305                                         log_debug("sd-device: failed to handle db entry '%c:%s': %s", key, value, strerror(-r));
1306
1307                                 state = PRE_KEY;
1308                         }
1309
1310                         break;
1311                 default:
1312                         assert_not_reached("invalid state when parsing db");
1313                 }
1314         }
1315
1316         return 0;
1317 }
1318
1319 static int device_read_db(sd_device *device) {
1320         return device_read_db_aux(device, false);
1321 }
1322
1323 _public_ int sd_device_get_is_initialized(sd_device *device, int *initialized) {
1324         int r;
1325
1326         assert_return(device, -EINVAL);
1327         assert_return(initialized, -EINVAL);
1328
1329         r = device_read_db(device);
1330         if (r < 0)
1331                 return r;
1332
1333         *initialized = device->is_initialized;
1334
1335         return 0;
1336 }
1337
1338 _public_ int sd_device_get_usec_since_initialized(sd_device *device, uint64_t *usec) {
1339         usec_t now_ts;
1340         int r;
1341
1342         assert_return(device, -EINVAL);
1343         assert_return(usec, -EINVAL);
1344
1345         r = device_read_db(device);
1346         if (r < 0)
1347                 return r;
1348
1349         if (!device->is_initialized)
1350                 return -EBUSY;
1351
1352         if (!device->usec_initialized)
1353                 return -ENODATA;
1354
1355         now_ts = now(clock_boottime_or_monotonic());
1356
1357         if (now_ts < device->usec_initialized)
1358                 return -EIO;
1359
1360         *usec = now_ts - device->usec_initialized;
1361
1362         return 0;
1363 }
1364
1365 _public_ const char *sd_device_get_tag_first(sd_device *device) {
1366         assert_return(device, NULL);
1367
1368         (void) device_read_db(device);
1369
1370         device->tags_iterator_generation = device->tags_generation;
1371         device->tags_iterator = ITERATOR_FIRST;
1372
1373         return set_iterate(device->tags, &device->tags_iterator);
1374 }
1375
1376 _public_ const char *sd_device_get_tag_next(sd_device *device) {
1377         assert_return(device, NULL);
1378
1379         (void) device_read_db(device);
1380
1381         if (device->tags_iterator_generation != device->tags_generation)
1382                 return NULL;
1383
1384         return set_iterate(device->tags, &device->tags_iterator);
1385 }
1386
1387 _public_ const char *sd_device_get_devlink_first(sd_device *device) {
1388         assert_return(device, NULL);
1389
1390         (void) device_read_db(device);
1391
1392         device->devlinks_iterator_generation = device->devlinks_generation;
1393         device->devlinks_iterator = ITERATOR_FIRST;
1394
1395         return set_iterate(device->devlinks, &device->devlinks_iterator);
1396 }
1397
1398 _public_ const char *sd_device_get_devlink_next(sd_device *device) {
1399         assert_return(device, NULL);
1400
1401         (void) device_read_db(device);
1402
1403         if (device->devlinks_iterator_generation != device->devlinks_generation)
1404                 return NULL;
1405
1406         return set_iterate(device->devlinks, &device->devlinks_iterator);
1407 }
1408
1409 static int device_properties_prepare(sd_device *device) {
1410         int r;
1411
1412         assert(device);
1413
1414         r = device_read_uevent_file(device);
1415         if (r < 0)
1416                 return r;
1417
1418         r = device_read_db(device);
1419         if (r < 0)
1420                 return r;
1421
1422         if (device->property_devlinks_outdated) {
1423                 char *devlinks = NULL;
1424                 const char *devlink;
1425
1426                 devlink = sd_device_get_devlink_first(device);
1427                 if (devlink)
1428                         devlinks = strdupa(devlink);
1429
1430                 while ((devlink = sd_device_get_devlink_next(device)))
1431                         devlinks = strjoina(devlinks, " ", devlink);
1432
1433                 r = device_add_property_internal(device, "DEVLINKS", devlinks);
1434                 if (r < 0)
1435                         return r;
1436
1437                 device->property_devlinks_outdated = false;
1438         }
1439
1440         if (device->property_tags_outdated) {
1441                 char *tags = NULL;
1442                 const char *tag;
1443
1444                 tag = sd_device_get_tag_first(device);
1445                 if (tag)
1446                         tags = strjoina(":", tag);
1447
1448                 while ((tag = sd_device_get_tag_next(device)))
1449                         tags = strjoina(tags, ":", tag);
1450
1451                 tags = strjoina(tags, ":");
1452
1453                 r = device_add_property_internal(device, "TAGS", tags);
1454                 if (r < 0)
1455                         return r;
1456
1457                 device->property_tags_outdated = false;
1458         }
1459
1460         return 0;
1461 }
1462
1463 _public_ const char *sd_device_get_property_first(sd_device *device, const char **_value) {
1464         const char *key;
1465         const char *value;
1466         int r;
1467
1468         assert_return(device, NULL);
1469
1470         r = device_properties_prepare(device);
1471         if (r < 0)
1472                 return NULL;
1473
1474         device->properties_iterator_generation = device->properties_generation;
1475         device->properties_iterator = ITERATOR_FIRST;
1476
1477         value = ordered_hashmap_iterate(device->properties, &device->properties_iterator, (const void**)&key);
1478
1479         if (_value)
1480                 *_value = value;
1481
1482         return key;
1483 }
1484
1485 _public_ const char *sd_device_get_property_next(sd_device *device, const char **_value) {
1486         const char *key;
1487         const char *value;
1488         int r;
1489
1490         assert_return(device, NULL);
1491
1492         r = device_properties_prepare(device);
1493         if (r < 0)
1494                 return NULL;
1495
1496         if (device->properties_iterator_generation != device->properties_generation)
1497                 return NULL;
1498
1499         value = ordered_hashmap_iterate(device->properties, &device->properties_iterator, (const void**)&key);
1500
1501         if (_value)
1502                 *_value = value;
1503
1504         return key;
1505 }
1506
1507 static int device_sysattrs_read_all(sd_device *device) {
1508         _cleanup_closedir_ DIR *dir = NULL;
1509         const char *syspath;
1510         struct dirent *dent;
1511         int r;
1512
1513         assert(device);
1514
1515         if (device->sysattrs_read)
1516                 return 0;
1517
1518         r = sd_device_get_syspath(device, &syspath);
1519         if (r < 0)
1520                 return r;
1521
1522         dir = opendir(syspath);
1523         if (!dir)
1524                 return -errno;
1525
1526         r = set_ensure_allocated(&device->sysattrs, &string_hash_ops);
1527         if (r < 0)
1528                 return r;
1529
1530         for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
1531                 char *path;
1532                 struct stat statbuf;
1533
1534                 /* only handle symlinks and regular files */
1535                 if (dent->d_type != DT_LNK && dent->d_type != DT_REG)
1536                         continue;
1537
1538                 path = strjoina(syspath, "/", dent->d_name);
1539
1540                 if (lstat(path, &statbuf) != 0)
1541                         continue;
1542
1543                 if (!(statbuf.st_mode & S_IRUSR))
1544                         continue;
1545
1546                 r = set_put_strdup(device->sysattrs, dent->d_name);
1547                 if (r < 0)
1548                         return r;
1549         }
1550
1551         device->sysattrs_read = true;
1552
1553         return 0;
1554 }
1555
1556 _public_ const char *sd_device_get_sysattr_first(sd_device *device) {
1557         int r;
1558
1559         assert_return(device, NULL);
1560
1561         if (!device->sysattrs_read) {
1562                 r = device_sysattrs_read_all(device);
1563                 if (r < 0) {
1564                         errno = -r;
1565                         return NULL;
1566                 }
1567         }
1568
1569         device->sysattrs_iterator = ITERATOR_FIRST;
1570
1571         return set_iterate(device->sysattrs, &device->sysattrs_iterator);
1572 }
1573
1574 _public_ const char *sd_device_get_sysattr_next(sd_device *device) {
1575         assert_return(device, NULL);
1576
1577         if (!device->sysattrs_read)
1578                 return NULL;
1579
1580         return set_iterate(device->sysattrs, &device->sysattrs_iterator);
1581 }
1582
1583 _public_ int sd_device_has_tag(sd_device *device, const char *tag) {
1584         assert_return(device, -EINVAL);
1585         assert_return(tag, -EINVAL);
1586
1587         (void) device_read_db(device);
1588
1589         return !!set_contains(device->tags, tag);
1590 }
1591
1592 _public_ int sd_device_get_property_value(sd_device *device, const char *key, const char **_value) {
1593         char *value;
1594         int r;
1595
1596         assert_return(device, -EINVAL);
1597         assert_return(key, -EINVAL);
1598         assert_return(_value, -EINVAL);
1599
1600         r = device_properties_prepare(device);
1601         if (r < 0)
1602                 return r;
1603
1604         value = ordered_hashmap_get(device->properties, key);
1605         if (!value)
1606                 return -ENOENT;
1607
1608         *_value = value;
1609
1610         return 0;
1611 }
1612
1613 /* replaces the value if it already exists */
1614 static int device_add_sysattr_value(sd_device *device, const char *_key, char *value) {
1615         _cleanup_free_ char *key = NULL;
1616         _cleanup_free_ char *value_old = NULL;
1617         int r;
1618
1619         assert(device);
1620         assert(_key);
1621
1622         r = hashmap_ensure_allocated(&device->sysattr_values, &string_hash_ops);
1623         if (r < 0)
1624                 return r;
1625
1626         value_old = hashmap_remove2(device->sysattr_values, _key, (void **)&key);
1627         if (!key) {
1628                 key = strdup(_key);
1629                 if (!key)
1630                         return -ENOMEM;
1631         }
1632
1633         r = hashmap_put(device->sysattr_values, key, value);
1634         if (r < 0)
1635                 return r;
1636
1637         key = NULL;
1638
1639         return 0;
1640 }
1641
1642 static int device_get_sysattr_value(sd_device *device, const char *_key, const char **_value) {
1643         const char *key = NULL, *value;
1644
1645         assert(device);
1646         assert(_key);
1647
1648         value = hashmap_get2(device->sysattr_values, _key, (void **) &key);
1649         if (!key)
1650                 return -ENOENT;
1651
1652         if (_value)
1653                 *_value = value;
1654
1655         return 0;
1656 }
1657
1658 /* We cache all sysattr lookups. If an attribute does not exist, it is stored
1659  * with a NULL value in the cache, otherwise the returned string is stored */
1660 _public_ int sd_device_get_sysattr_value(sd_device *device, const char *sysattr, const char **_value) {
1661         _cleanup_free_ char *value = NULL;
1662         const char *syspath, *cached_value = NULL;
1663         char *path;
1664         struct stat statbuf;
1665         int r;
1666
1667         assert_return(device, -EINVAL);
1668         assert_return(sysattr, -EINVAL);
1669
1670         /* look for possibly already cached result */
1671         r = device_get_sysattr_value(device, sysattr, &cached_value);
1672         if (r != -ENOENT) {
1673                 if (r < 0)
1674                         return r;
1675
1676                 if (!cached_value)
1677                         /* we looked up the sysattr before and it did not exist */
1678                         return -ENOENT;
1679
1680                 if (_value)
1681                         *_value = cached_value;
1682
1683                 return 0;
1684         }
1685
1686         r = sd_device_get_syspath(device, &syspath);
1687         if (r < 0)
1688                 return r;
1689
1690         path = strjoina(syspath, "/", sysattr);
1691         r = lstat(path, &statbuf);
1692         if (r < 0) {
1693                 /* remember that we could not access the sysattr */
1694                 r = device_add_sysattr_value(device, sysattr, NULL);
1695                 if (r < 0)
1696                         return r;
1697
1698                 return -ENOENT;
1699         } else if (S_ISLNK(statbuf.st_mode)) {
1700                 /* Some core links return only the last element of the target path,
1701                  * these are just values, the paths should not be exposed. */
1702                 if (STR_IN_SET(sysattr, "driver", "subsystem", "module")) {
1703                         r = readlink_value(path, &value);
1704                         if (r < 0)
1705                                 return r;
1706                 } else
1707                         return -EINVAL;
1708         } else if (S_ISDIR(statbuf.st_mode)) {
1709                 /* skip directories */
1710                 return -EINVAL;
1711         } else if (!(statbuf.st_mode & S_IRUSR)) {
1712                 /* skip non-readable files */
1713                 return -EPERM;
1714         } else {
1715                 size_t size;
1716
1717                 /* read attribute value */
1718                 r = read_full_file(path, &value, &size);
1719                 if (r < 0)
1720                         return r;
1721
1722                 /* drop trailing newlines */
1723                 while (size > 0 && value[--size] == '\n')
1724                         value[size] = '\0';
1725         }
1726
1727         r = device_add_sysattr_value(device, sysattr, value);
1728         if (r < 0)
1729                 return r;
1730
1731         *_value = value;
1732         value = NULL;
1733
1734         return 0;
1735 }
1736
1737 static void device_remove_sysattr_value(sd_device *device, const char *_key) {
1738         _cleanup_free_ char *key = NULL;
1739         _cleanup_free_ char *value = NULL;
1740
1741         assert(device);
1742         assert(_key);
1743
1744         value = hashmap_remove2(device->sysattr_values, _key, (void **) &key);
1745
1746         return;
1747 }
1748
1749 /* set the attribute and save it in the cache. If a NULL value is passed the
1750  * attribute is cleared from the cache */
1751 _public_ int sd_device_set_sysattr_value(sd_device *device, const char *sysattr, char *_value) {
1752         _cleanup_close_ int fd = -1;
1753         _cleanup_free_ char *value = NULL;
1754         const char *syspath;
1755         char *path;
1756         struct stat statbuf;
1757         size_t value_len = 0;
1758         ssize_t size;
1759         int r;
1760
1761         assert_return(device, -EINVAL);
1762         assert_return(sysattr, -EINVAL);
1763
1764         if (!_value) {
1765                 device_remove_sysattr_value(device, sysattr);
1766
1767                 return 0;
1768         }
1769
1770         r = sd_device_get_syspath(device, &syspath);
1771         if (r < 0)
1772                 return r;
1773
1774         path = strjoina(syspath, "/", sysattr);
1775         r = lstat(path, &statbuf);
1776         if (r < 0) {
1777                 value = strdup("");
1778                 if (!value)
1779                         return -ENOMEM;
1780
1781                 r = device_add_sysattr_value(device, sysattr, value);
1782                 if (r < 0)
1783                         return r;
1784
1785                 return -ENXIO;
1786         }
1787
1788         if (S_ISLNK(statbuf.st_mode))
1789                 return -EINVAL;
1790
1791         /* skip directories */
1792         if (S_ISDIR(statbuf.st_mode))
1793                 return -EISDIR;
1794
1795         /* skip non-readable files */
1796         if ((statbuf.st_mode & S_IRUSR) == 0)
1797                 return -EACCES;
1798
1799         value_len = strlen(_value);
1800
1801         /* drop trailing newlines */
1802         while (value_len > 0 && _value[value_len - 1] == '\n')
1803                 _value[--value_len] = '\0';
1804
1805         /* value length is limited to 4k */
1806         if (value_len > 4096)
1807                 return -EINVAL;
1808
1809         fd = open(path, O_WRONLY | O_CLOEXEC);
1810         if (fd < 0)
1811                 return -errno;
1812
1813         value = strdup(_value);
1814         if (!value)
1815                 return -ENOMEM;
1816
1817         size = write(fd, value, value_len);
1818         if (size < 0)
1819                 return -errno;
1820
1821         if ((size_t)size != value_len)
1822                 return -EIO;
1823
1824         r = device_add_sysattr_value(device, sysattr, value);
1825         if (r < 0)
1826                 return r;
1827
1828         value = NULL;
1829
1830         return 0;
1831 }