chiark / gitweb /
sd-device: set_syspath - return ENODEV when passed something that is not a device
[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 static int device_read_db(sd_device *device) {
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 || 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 _public_ int sd_device_get_is_initialized(sd_device *device, int *initialized) {
1317         int r;
1318
1319         assert_return(device, -EINVAL);
1320         assert_return(initialized, -EINVAL);
1321
1322         r = device_read_db(device);
1323         if (r < 0)
1324                 return r;
1325
1326         *initialized = device->is_initialized;
1327
1328         return 0;
1329 }
1330
1331 _public_ int sd_device_get_usec_since_initialized(sd_device *device, uint64_t *usec) {
1332         usec_t now_ts;
1333         int r;
1334
1335         assert_return(device, -EINVAL);
1336         assert_return(usec, -EINVAL);
1337
1338         r = device_read_db(device);
1339         if (r < 0)
1340                 return r;
1341
1342         if (!device->is_initialized)
1343                 return -EBUSY;
1344
1345         if (!device->usec_initialized)
1346                 return -ENODATA;
1347
1348         now_ts = now(clock_boottime_or_monotonic());
1349
1350         if (now_ts < device->usec_initialized)
1351                 return -EIO;
1352
1353         *usec = now_ts - device->usec_initialized;
1354
1355         return 0;
1356 }
1357
1358 _public_ const char *sd_device_get_tag_first(sd_device *device) {
1359         assert_return(device, NULL);
1360
1361         (void) device_read_db(device);
1362
1363         device->tags_iterator_generation = device->tags_generation;
1364         device->tags_iterator = ITERATOR_FIRST;
1365
1366         return set_iterate(device->tags, &device->tags_iterator);
1367 }
1368
1369 _public_ const char *sd_device_get_tag_next(sd_device *device) {
1370         assert_return(device, NULL);
1371
1372         (void) device_read_db(device);
1373
1374         if (device->tags_iterator_generation != device->tags_generation)
1375                 return NULL;
1376
1377         return set_iterate(device->tags, &device->tags_iterator);
1378 }
1379
1380 _public_ const char *sd_device_get_devlink_first(sd_device *device) {
1381         assert_return(device, NULL);
1382
1383         (void) device_read_db(device);
1384
1385         device->devlinks_iterator_generation = device->devlinks_generation;
1386         device->devlinks_iterator = ITERATOR_FIRST;
1387
1388         return set_iterate(device->devlinks, &device->devlinks_iterator);
1389 }
1390
1391 _public_ const char *sd_device_get_devlink_next(sd_device *device) {
1392         assert_return(device, NULL);
1393
1394         (void) device_read_db(device);
1395
1396         if (device->devlinks_iterator_generation != device->devlinks_generation)
1397                 return NULL;
1398
1399         return set_iterate(device->devlinks, &device->devlinks_iterator);
1400 }
1401
1402 static int device_properties_prepare(sd_device *device) {
1403         int r;
1404
1405         assert(device);
1406
1407         r = device_read_uevent_file(device);
1408         if (r < 0)
1409                 return r;
1410
1411         r = device_read_db(device);
1412         if (r < 0)
1413                 return r;
1414
1415         if (device->property_devlinks_outdated) {
1416                 char *devlinks = NULL;
1417                 const char *devlink;
1418
1419                 devlink = sd_device_get_devlink_first(device);
1420                 if (devlink)
1421                         devlinks = strdupa(devlink);
1422
1423                 while ((devlink = sd_device_get_devlink_next(device)))
1424                         devlinks = strjoina(devlinks, " ", devlink);
1425
1426                 r = device_add_property_internal(device, "DEVLINKS", devlinks);
1427                 if (r < 0)
1428                         return r;
1429
1430                 device->property_devlinks_outdated = false;
1431         }
1432
1433         if (device->property_tags_outdated) {
1434                 char *tags = NULL;
1435                 const char *tag;
1436
1437                 tag = sd_device_get_tag_first(device);
1438                 if (tag)
1439                         tags = strjoina(":", tag);
1440
1441                 while ((tag = sd_device_get_tag_next(device)))
1442                         tags = strjoina(tags, ":", tag);
1443
1444                 tags = strjoina(tags, ":");
1445
1446                 r = device_add_property_internal(device, "TAGS", tags);
1447                 if (r < 0)
1448                         return r;
1449
1450                 device->property_tags_outdated = false;
1451         }
1452
1453         return 0;
1454 }
1455
1456 _public_ const char *sd_device_get_property_first(sd_device *device, const char **_value) {
1457         const char *key;
1458         const char *value;
1459         int r;
1460
1461         assert_return(device, NULL);
1462
1463         r = device_properties_prepare(device);
1464         if (r < 0)
1465                 return NULL;
1466
1467         device->properties_iterator_generation = device->properties_generation;
1468         device->properties_iterator = ITERATOR_FIRST;
1469
1470         value = ordered_hashmap_iterate(device->properties, &device->properties_iterator, (const void**)&key);
1471
1472         if (_value)
1473                 *_value = value;
1474
1475         return key;
1476 }
1477
1478 _public_ const char *sd_device_get_property_next(sd_device *device, const char **_value) {
1479         const char *key;
1480         const char *value;
1481         int r;
1482
1483         assert_return(device, NULL);
1484
1485         r = device_properties_prepare(device);
1486         if (r < 0)
1487                 return NULL;
1488
1489         if (device->properties_iterator_generation != device->properties_generation)
1490                 return NULL;
1491
1492         value = ordered_hashmap_iterate(device->properties, &device->properties_iterator, (const void**)&key);
1493
1494         if (_value)
1495                 *_value = value;
1496
1497         return key;
1498 }
1499
1500 static int device_sysattrs_read_all(sd_device *device) {
1501         _cleanup_closedir_ DIR *dir = NULL;
1502         const char *syspath;
1503         struct dirent *dent;
1504         int r;
1505
1506         assert(device);
1507
1508         if (device->sysattrs_read)
1509                 return 0;
1510
1511         r = sd_device_get_syspath(device, &syspath);
1512         if (r < 0)
1513                 return r;
1514
1515         dir = opendir(syspath);
1516         if (!dir)
1517                 return -errno;
1518
1519         r = set_ensure_allocated(&device->sysattrs, &string_hash_ops);
1520         if (r < 0)
1521                 return r;
1522
1523         for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
1524                 char *path;
1525                 struct stat statbuf;
1526
1527                 /* only handle symlinks and regular files */
1528                 if (dent->d_type != DT_LNK && dent->d_type != DT_REG)
1529                         continue;
1530
1531                 path = strjoina(syspath, "/", dent->d_name);
1532
1533                 if (lstat(path, &statbuf) != 0)
1534                         continue;
1535
1536                 if (!(statbuf.st_mode & S_IRUSR))
1537                         continue;
1538
1539                 r = set_put_strdup(device->sysattrs, dent->d_name);
1540                 if (r < 0)
1541                         return r;
1542         }
1543
1544         device->sysattrs_read = true;
1545
1546         return 0;
1547 }
1548
1549 _public_ const char *sd_device_get_sysattr_first(sd_device *device) {
1550         int r;
1551
1552         assert_return(device, NULL);
1553
1554         if (!device->sysattrs_read) {
1555                 r = device_sysattrs_read_all(device);
1556                 if (r < 0) {
1557                         errno = -r;
1558                         return NULL;
1559                 }
1560         }
1561
1562         device->sysattrs_iterator = ITERATOR_FIRST;
1563
1564         return set_iterate(device->sysattrs, &device->sysattrs_iterator);
1565 }
1566
1567 _public_ const char *sd_device_get_sysattr_next(sd_device *device) {
1568         assert_return(device, NULL);
1569
1570         if (!device->sysattrs_read)
1571                 return NULL;
1572
1573         return set_iterate(device->sysattrs, &device->sysattrs_iterator);
1574 }
1575
1576 _public_ int sd_device_has_tag(sd_device *device, const char *tag) {
1577         assert_return(device, -EINVAL);
1578         assert_return(tag, -EINVAL);
1579
1580         (void) device_read_db(device);
1581
1582         return !!set_contains(device->tags, tag);
1583 }
1584
1585 _public_ int sd_device_get_property_value(sd_device *device, const char *key, const char **_value) {
1586         char *value;
1587         int r;
1588
1589         assert_return(device, -EINVAL);
1590         assert_return(key, -EINVAL);
1591         assert_return(_value, -EINVAL);
1592
1593         r = device_properties_prepare(device);
1594         if (r < 0)
1595                 return r;
1596
1597         value = ordered_hashmap_get(device->properties, key);
1598         if (!value)
1599                 return -ENOENT;
1600
1601         *_value = value;
1602
1603         return 0;
1604 }
1605
1606 /* replaces the value if it already exists */
1607 static int device_add_sysattr_value(sd_device *device, const char *_key, char *value) {
1608         _cleanup_free_ char *key = NULL;
1609         _cleanup_free_ char *value_old = NULL;
1610         int r;
1611
1612         assert(device);
1613         assert(_key);
1614
1615         r = hashmap_ensure_allocated(&device->sysattr_values, &string_hash_ops);
1616         if (r < 0)
1617                 return r;
1618
1619         value_old = hashmap_remove2(device->sysattr_values, _key, (void **)&key);
1620         if (!key) {
1621                 key = strdup(_key);
1622                 if (!key)
1623                         return -ENOMEM;
1624         }
1625
1626         r = hashmap_put(device->sysattr_values, key, value);
1627         if (r < 0)
1628                 return r;
1629
1630         key = NULL;
1631
1632         return 0;
1633 }
1634
1635 static int device_get_sysattr_value(sd_device *device, const char *_key, const char **_value) {
1636         const char *key = NULL, *value;
1637
1638         assert(device);
1639         assert(_key);
1640
1641         value = hashmap_get2(device->sysattr_values, _key, (void **) &key);
1642         if (!key)
1643                 return -ENOENT;
1644
1645         if (_value)
1646                 *_value = value;
1647
1648         return 0;
1649 }
1650
1651 /* We cache all sysattr lookups. If an attribute does not exist, it is stored
1652  * with a NULL value in the cache, otherwise the returned string is stored */
1653 _public_ int sd_device_get_sysattr_value(sd_device *device, const char *sysattr, const char **_value) {
1654         _cleanup_free_ char *value = NULL;
1655         const char *syspath, *cached_value = NULL;
1656         char *path;
1657         struct stat statbuf;
1658         int r;
1659
1660         assert_return(device, -EINVAL);
1661         assert_return(sysattr, -EINVAL);
1662
1663         /* look for possibly already cached result */
1664         r = device_get_sysattr_value(device, sysattr, &cached_value);
1665         if (r != -ENOENT) {
1666                 if (r < 0)
1667                         return r;
1668
1669                 if (!cached_value)
1670                         /* we looked up the sysattr before and it did not exist */
1671                         return -ENOENT;
1672
1673                 if (_value)
1674                         *_value = cached_value;
1675
1676                 return 0;
1677         }
1678
1679         r = sd_device_get_syspath(device, &syspath);
1680         if (r < 0)
1681                 return r;
1682
1683         path = strjoina(syspath, "/", sysattr);
1684         r = lstat(path, &statbuf);
1685         if (r < 0) {
1686                 /* remember that we could not access the sysattr */
1687                 r = device_add_sysattr_value(device, sysattr, NULL);
1688                 if (r < 0)
1689                         return r;
1690
1691                 return -ENOENT;
1692         } else if (S_ISLNK(statbuf.st_mode)) {
1693                 /* Some core links return only the last element of the target path,
1694                  * these are just values, the paths should not be exposed. */
1695                 if (STR_IN_SET(sysattr, "driver", "subsystem", "module")) {
1696                         r = readlink_value(path, &value);
1697                         if (r < 0)
1698                                 return r;
1699                 } else
1700                         return -EINVAL;
1701         } else if (S_ISDIR(statbuf.st_mode)) {
1702                 /* skip directories */
1703                 return -EINVAL;
1704         } else if (!(statbuf.st_mode & S_IRUSR)) {
1705                 /* skip non-readable files */
1706                 return -EPERM;
1707         } else {
1708                 size_t size;
1709
1710                 /* read attribute value */
1711                 r = read_full_file(path, &value, &size);
1712                 if (r < 0)
1713                         return r;
1714
1715                 /* drop trailing newlines */
1716                 while (size > 0 && value[--size] == '\n')
1717                         value[size] = '\0';
1718         }
1719
1720         r = device_add_sysattr_value(device, sysattr, value);
1721         if (r < 0)
1722                 return r;
1723
1724         *_value = value;
1725         value = NULL;
1726
1727         return 0;
1728 }
1729
1730 static void device_remove_sysattr_value(sd_device *device, const char *_key) {
1731         _cleanup_free_ char *key = NULL;
1732         _cleanup_free_ char *value = NULL;
1733
1734         assert(device);
1735         assert(_key);
1736
1737         value = hashmap_remove2(device->sysattr_values, _key, (void **) &key);
1738
1739         return;
1740 }
1741
1742 /* set the attribute and save it in the cache. If a NULL value is passed the
1743  * attribute is cleared from the cache */
1744 _public_ int sd_device_set_sysattr_value(sd_device *device, const char *sysattr, char *_value) {
1745         _cleanup_close_ int fd = -1;
1746         _cleanup_free_ char *value = NULL;
1747         const char *syspath;
1748         char *path;
1749         struct stat statbuf;
1750         size_t value_len = 0;
1751         ssize_t size;
1752         int r;
1753
1754         assert_return(device, -EINVAL);
1755         assert_return(sysattr, -EINVAL);
1756
1757         if (!_value) {
1758                 device_remove_sysattr_value(device, sysattr);
1759
1760                 return 0;
1761         }
1762
1763         r = sd_device_get_syspath(device, &syspath);
1764         if (r < 0)
1765                 return r;
1766
1767         path = strjoina(syspath, "/", sysattr);
1768         r = lstat(path, &statbuf);
1769         if (r < 0) {
1770                 value = strdup("");
1771                 if (!value)
1772                         return -ENOMEM;
1773
1774                 r = device_add_sysattr_value(device, sysattr, value);
1775                 if (r < 0)
1776                         return r;
1777
1778                 return -ENXIO;
1779         }
1780
1781         if (S_ISLNK(statbuf.st_mode))
1782                 return -EINVAL;
1783
1784         /* skip directories */
1785         if (S_ISDIR(statbuf.st_mode))
1786                 return -EISDIR;
1787
1788         /* skip non-readable files */
1789         if ((statbuf.st_mode & S_IRUSR) == 0)
1790                 return -EACCES;
1791
1792         value_len = strlen(_value);
1793
1794         /* drop trailing newlines */
1795         while (value_len > 0 && _value[value_len - 1] == '\n')
1796                 _value[--value_len] = '\0';
1797
1798         /* value length is limited to 4k */
1799         if (value_len > 4096)
1800                 return -EINVAL;
1801
1802         fd = open(path, O_WRONLY | O_CLOEXEC);
1803         if (fd < 0)
1804                 return -errno;
1805
1806         value = strdup(_value);
1807         if (!value)
1808                 return -ENOMEM;
1809
1810         size = write(fd, value, value_len);
1811         if (size < 0)
1812                 return -errno;
1813
1814         if ((size_t)size != value_len)
1815                 return -EIO;
1816
1817         r = device_add_sysattr_value(device, sysattr, value);
1818         if (r < 0)
1819                 return r;
1820
1821         value = NULL;
1822
1823         return 0;
1824 }