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