chiark / gitweb /
sd-device: get_driver - remember if a device does not have a driver
[elogind.git] / src / libelogind / sd-device / sd-device.c
1 /***
2   This file is part of systemd.
3
4   Copyright 2008-2012 Kay Sievers <kay@vrfy.org>
5   Copyright 2014 Tom Gundersen <teg@jklm.no>
6
7   systemd is free software; you can redistribute it and/or modify it
8   under the terms of the GNU Lesser General Public License as published by
9   the Free Software Foundation; either version 2.1 of the License, or
10   (at your option) any later version.
11
12   systemd is distributed in the hope that it will be useful, but
13   WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15   Lesser General Public License for more details.
16
17   You should have received a copy of the GNU Lesser General Public License
18   along with systemd; If not, see <http://www.gnu.org/licenses/>.
19 ***/
20
21 #include <ctype.h>
22 #include <sys/types.h>
23 #include <net/if.h>
24
25 #include "util.h"
26 #include "macro.h"
27 #include "path-util.h"
28 #include "strxcpyx.h"
29 #include "fileio.h"
30 #include "hashmap.h"
31 #include "set.h"
32 #include "strv.h"
33
34 #include "sd-device.h"
35
36 #include "device-util.h"
37 #include "device-private.h"
38 #include "device-internal.h"
39
40 int device_new_aux(sd_device **ret) {
41         _cleanup_device_unref_ sd_device *device = NULL;
42
43         assert(ret);
44
45         device = new0(sd_device, 1);
46         if (!device)
47                 return -ENOMEM;
48
49         device->n_ref = 1;
50         device->watch_handle = -1;
51
52         *ret = device;
53         device = NULL;
54
55         return 0;
56 }
57
58 _public_ sd_device *sd_device_ref(sd_device *device) {
59         if (device)
60                 assert_se(++ device->n_ref >= 2);
61
62         return device;
63 }
64
65 _public_ sd_device *sd_device_unref(sd_device *device) {
66         if (device && -- device->n_ref == 0) {
67                 sd_device_unref(device->parent);
68                 free(device->syspath);
69                 free(device->sysname);
70                 free(device->devtype);
71                 free(device->devname);
72                 free(device->subsystem);
73                 free(device->driver);
74                 free(device->id_filename);
75                 free(device->properties_strv);
76                 free(device->properties_nulstr);
77
78                 ordered_hashmap_free_free_free(device->properties);
79                 ordered_hashmap_free_free_free(device->properties_db);
80                 hashmap_free_free_free(device->sysattr_values);
81                 set_free_free(device->sysattrs);
82                 set_free_free(device->tags);
83                 set_free_free(device->devlinks);
84
85                 free(device);
86         }
87
88         return NULL;
89 }
90
91 int device_add_property_aux(sd_device *device, const char *_key, const char *_value, bool db) {
92         OrderedHashmap **properties;
93
94         assert(device);
95         assert(_key);
96
97         if (db)
98                 properties = &device->properties_db;
99         else
100                 properties = &device->properties;
101
102         if (_value) {
103                 _cleanup_free_ char *key = NULL, *value = NULL, *old_key = NULL, *old_value = NULL;
104                 int r;
105
106                 r = ordered_hashmap_ensure_allocated(properties, &string_hash_ops);
107                 if (r < 0)
108                         return r;
109
110                 key = strdup(_key);
111                 if (!key)
112                         return -ENOMEM;
113
114                 value = strdup(_value);
115                 if (!value)
116                         return -ENOMEM;
117
118                 old_value = ordered_hashmap_get2(*properties, key, (void**) &old_key);
119
120                 r = ordered_hashmap_replace(*properties, key, value);
121                 if (r < 0)
122                         return r;
123
124                 key = NULL;
125                 value = NULL;
126         } else {
127                 _cleanup_free_ char *key = NULL;
128                 _cleanup_free_ char *value = NULL;
129
130                 value = ordered_hashmap_remove2(*properties, _key, (void**) &key);
131         }
132
133         if (!db) {
134                 device->properties_generation ++;
135                 device->properties_buf_outdated = true;
136         }
137
138         return 0;
139 }
140
141 int device_add_property_internal(sd_device *device, const char *key, const char *value) {
142         return device_add_property_aux(device, key, value, false);
143 }
144
145 int device_set_syspath(sd_device *device, const char *_syspath, bool verify) {
146         _cleanup_free_ char *syspath = NULL;
147         const char *devpath;
148         int r;
149
150         assert(device);
151         assert(_syspath);
152
153         /* must be a subdirectory of /sys */
154         if (!path_startswith(_syspath, "/sys/")) {
155                 log_debug("sd-device: syspath '%s' is not a subdirectory of /sys", _syspath);
156                 return -EINVAL;
157         }
158
159         if (verify) {
160                 r = readlink_and_canonicalize(_syspath, &syspath);
161                 if (r == -ENOENT)
162                         /* the device does not exist (any more?) */
163                         return -ENODEV;
164                 else if (r == -EINVAL) {
165                         /* not a symlink */
166                         syspath = canonicalize_file_name(_syspath);
167                         if (!syspath) {
168                                 if (errno == ENOENT)
169                                         /* the device does not exist (any more?) */
170                                         return -ENODEV;
171
172                                 log_debug("sd-device: could not canonicalize '%s': %m", _syspath);
173                                 return -errno;
174                         }
175                 } else if (r < 0) {
176                         log_debug("sd-device: could not get target of '%s': %s", _syspath, strerror(-r));
177                         return r;
178                 }
179
180                 if (path_startswith(syspath,  "/sys/devices/")) {
181                         char *path;
182
183                         /* all 'devices' require an 'uevent' file */
184                         path = strjoina(syspath, "/uevent");
185                         r = access(path, F_OK);
186                         if (r < 0) {
187                                 if (errno == ENOENT)
188                                         /* this is not a valid device */
189                                         return -ENODEV;
190
191                                 log_debug("sd-device: %s does not have an uevent file: %m", syspath);
192                                 return -errno;
193                         }
194                 } else {
195                         /* everything else just just needs to be a directory */
196                         if (!is_dir(syspath, false))
197                                 return -ENODEV;
198                 }
199         } else {
200                 syspath = strdup(_syspath);
201                 if (!syspath)
202                         return -ENOMEM;
203         }
204
205         devpath = syspath + strlen("/sys");
206
207         r = device_add_property_internal(device, "DEVPATH", devpath);
208         if (r < 0)
209                 return r;
210
211         free(device->syspath);
212         device->syspath = syspath;
213         syspath = NULL;
214
215         device->devpath = devpath;
216
217         return 0;
218 }
219
220 _public_ int sd_device_new_from_syspath(sd_device **ret, const char *syspath) {
221         _cleanup_device_unref_ sd_device *device = NULL;
222         int r;
223
224         assert_return(ret, -EINVAL);
225         assert_return(syspath, -EINVAL);
226
227         r = device_new_aux(&device);
228         if (r < 0)
229                 return r;
230
231         r = device_set_syspath(device, syspath, true);
232         if (r < 0)
233                 return r;
234
235         *ret = device;
236         device = NULL;
237
238         return 0;
239 }
240
241 _public_ int sd_device_new_from_devnum(sd_device **ret, char type, dev_t devnum) {
242         char *syspath;
243         char id[DECIMAL_STR_MAX(unsigned) * 2 + 1];
244
245         assert_return(ret, -EINVAL);
246         assert_return(type == 'b' || type == 'c', -EINVAL);
247
248         /* use /sys/dev/{block,char}/<maj>:<min> link */
249         snprintf(id, sizeof(id), "%u:%u", major(devnum), minor(devnum));
250
251         syspath = strjoina("/sys/dev/", (type == 'b' ? "block" : "char"), "/", id);
252
253         return sd_device_new_from_syspath(ret, syspath);
254 }
255
256 _public_ int sd_device_new_from_subsystem_sysname(sd_device **ret, const char *subsystem, const char *sysname) {
257         char *syspath;
258
259         assert_return(ret, -EINVAL);
260         assert_return(subsystem, -EINVAL);
261         assert_return(sysname, -EINVAL);
262
263         if (streq(subsystem, "subsystem")) {
264                 syspath = strjoina("/sys/subsystem/", sysname);
265                 if (access(syspath, F_OK) >= 0)
266                         return sd_device_new_from_syspath(ret, syspath);
267
268                 syspath = strjoina("/sys/bus/", sysname);
269                 if (access(syspath, F_OK) >= 0)
270                         return sd_device_new_from_syspath(ret, syspath);
271
272                 syspath = strjoina("/sys/class/", sysname);
273                 if (access(syspath, F_OK) >= 0)
274                         return sd_device_new_from_syspath(ret, syspath);
275         } else  if (streq(subsystem, "module")) {
276                 syspath = strjoina("/sys/module/", sysname);
277                 if (access(syspath, F_OK) >= 0)
278                         return sd_device_new_from_syspath(ret, syspath);
279         } else if (streq(subsystem, "drivers")) {
280                 char subsys[PATH_MAX];
281                 char *driver;
282
283                 strscpy(subsys, sizeof(subsys), sysname);
284                 driver = strchr(subsys, ':');
285                 if (driver) {
286                         driver[0] = '\0';
287                         driver++;
288
289                         syspath = strjoina("/sys/subsystem/", subsys, "/drivers/", driver);
290                         if (access(syspath, F_OK) >= 0)
291                                 return sd_device_new_from_syspath(ret, syspath);
292
293                         syspath = strjoina("/sys/bus/", subsys, "/drivers/", driver);
294                         if (access(syspath, F_OK) >= 0)
295                                 return sd_device_new_from_syspath(ret, syspath);
296                 } else
297                         return -EINVAL;
298         } else {
299                 syspath = strjoina("/sys/subsystem/", subsystem, "/devices/", sysname);
300                 if (access(syspath, F_OK) >= 0)
301                         return sd_device_new_from_syspath(ret, syspath);
302
303                 syspath = strjoina("/sys/bus/", subsystem, "/devices/", sysname);
304                 if (access(syspath, F_OK) >= 0)
305                         return sd_device_new_from_syspath(ret, syspath);
306
307                 syspath = strjoina("/sys/class/", subsystem, "/", sysname);
308                 if (access(syspath, F_OK) >= 0)
309                         return sd_device_new_from_syspath(ret, syspath);
310         }
311
312         return -ENODEV;
313 }
314
315 int device_set_devtype(sd_device *device, const char *_devtype) {
316         _cleanup_free_ char *devtype = NULL;
317         int r;
318
319         assert(device);
320         assert(_devtype);
321
322         devtype = strdup(_devtype);
323         if (!devtype)
324                 return -ENOMEM;
325
326         r = device_add_property_internal(device, "DEVTYPE", devtype);
327         if (r < 0)
328                 return r;
329
330         free(device->devtype);
331         device->devtype = devtype;
332         devtype = NULL;
333
334         return 0;
335 }
336
337 int device_set_ifindex(sd_device *device, const char *_ifindex) {
338         int ifindex, r;
339
340         assert(device);
341         assert(_ifindex);
342
343         r = safe_atoi(_ifindex, &ifindex);
344         if (r < 0)
345                 return r;
346
347         if (ifindex <= 0)
348                 return -EINVAL;
349
350         r = device_add_property_internal(device, "IFINDEX", _ifindex);
351         if (r < 0)
352                 return r;
353
354         device->ifindex = ifindex;
355
356         return 0;
357 }
358
359 int device_set_devname(sd_device *device, const char *_devname) {
360         _cleanup_free_ char *devname = NULL;
361         int r;
362
363         assert(device);
364         assert(_devname);
365
366         if (_devname[0] != '/') {
367                 r = asprintf(&devname, "/dev/%s", _devname);
368                 if (r < 0)
369                         return -ENOMEM;
370         } else {
371                 devname = strdup(_devname);
372                 if (!devname)
373                         return -ENOMEM;
374         }
375
376         r = device_add_property_internal(device, "DEVNAME", devname);
377         if (r < 0)
378                 return r;
379
380         free(device->devname);
381         device->devname = devname;
382         devname = NULL;
383
384         return 0;
385 }
386
387 int device_set_devmode(sd_device *device, const char *_devmode) {
388         unsigned devmode;
389         int r;
390
391         assert(device);
392         assert(_devmode);
393
394         r = safe_atou(_devmode, &devmode);
395         if (r < 0)
396                 return r;
397
398         if (devmode > 07777)
399                 return -EINVAL;
400
401         r = device_add_property_internal(device, "DEVMODE", _devmode);
402         if (r < 0)
403                 return r;
404
405         device->devmode = devmode;
406
407         return 0;
408 }
409
410 int device_set_devnum(sd_device *device, const char *major, const char *minor) {
411         unsigned maj = 0, min = 0;
412         int r;
413
414         assert(device);
415         assert(major);
416
417         r = safe_atou(major, &maj);
418         if (r < 0)
419                 return r;
420         if (!maj)
421                 return 0;
422
423         if (minor) {
424                 r = safe_atou(minor, &min);
425                 if (r < 0)
426                         return r;
427         }
428
429         r = device_add_property_internal(device, "MAJOR", major);
430         if (r < 0)
431                 return r;
432
433         if (minor) {
434                 r = device_add_property_internal(device, "MINOR", minor);
435                 if (r < 0)
436                         return r;
437         }
438
439         device->devnum = makedev(maj, min);
440
441         return 0;
442 }
443
444 static int handle_uevent_line(sd_device *device, const char *key, const char *value, const char **major, const char **minor) {
445         int r;
446
447         assert(device);
448         assert(key);
449         assert(value);
450         assert(major);
451         assert(minor);
452
453         if (streq(key, "DEVTYPE")) {
454                 r = device_set_devtype(device, value);
455                 if (r < 0)
456                         return r;
457         } else if (streq(key, "IFINDEX")) {
458                 r = device_set_ifindex(device, value);
459                 if (r < 0)
460                         return r;
461         } else if (streq(key, "DEVNAME")) {
462                 r = device_set_devname(device, value);
463                 if (r < 0)
464                         return r;
465         } else if (streq(key, "DEVMODE")) {
466                 r = device_set_devmode(device, value);
467                 if (r < 0)
468                         return r;
469         } else if (streq(key, "MAJOR"))
470                 *major = value;
471         else if (streq(key, "MINOR"))
472                 *minor = value;
473         else {
474                 r = device_add_property_internal(device, key, value);
475                 if (r < 0)
476                         return r;
477         }
478
479         return 0;
480 }
481
482 int device_read_uevent_file(sd_device *device) {
483         _cleanup_free_ char *uevent = NULL;
484         const char *syspath, *key, *value, *major = NULL, *minor = NULL;
485         char *path;
486         size_t uevent_len;
487         unsigned i;
488         int r;
489
490         enum {
491                 PRE_KEY,
492                 KEY,
493                 PRE_VALUE,
494                 VALUE,
495                 INVALID_LINE,
496         } state = PRE_KEY;
497
498         assert(device);
499
500         if (device->uevent_loaded || device->sealed)
501                 return 0;
502
503         device->uevent_loaded = true;
504
505         r = sd_device_get_syspath(device, &syspath);
506         if (r < 0)
507                 return r;
508
509         path = strjoina(syspath, "/uevent");
510
511         r = read_full_file(path, &uevent, &uevent_len);
512         if (r == -EACCES)
513                 /* empty uevent files may be write-only */
514                 return 0;
515         else if (r == -ENOENT)
516                 /* some devices may not have uevent files, see set_syspath() */
517                 return 0;
518         else if (r < 0) {
519                 log_debug("sd-device: failed to read uevent file '%s': %s", path, strerror(-r));
520                 return r;
521         }
522
523         for (i = 0; i < uevent_len; i++) {
524                 switch (state) {
525                 case PRE_KEY:
526                         if (!strchr(NEWLINE, uevent[i])) {
527                                 key = &uevent[i];
528
529                                 state = KEY;
530                         }
531
532                         break;
533                 case KEY:
534                         if (uevent[i] == '=') {
535                                 uevent[i] = '\0';
536
537                                 state = PRE_VALUE;
538                         } else if (strchr(NEWLINE, uevent[i])) {
539                                 uevent[i] = '\0';
540                                 log_debug("sd-device: ignoring invalid uevent line '%s'", key);
541
542                                 state = PRE_KEY;
543                         }
544
545                         break;
546                 case PRE_VALUE:
547                         value = &uevent[i];
548
549                         state = VALUE;
550
551                         break;
552                 case VALUE:
553                         if (strchr(NEWLINE, uevent[i])) {
554                                 uevent[i] = '\0';
555
556                                 r = handle_uevent_line(device, key, value, &major, &minor);
557                                 if (r < 0)
558                                         log_debug("sd-device: failed to handle uevent entry '%s=%s': %s", key, value, strerror(-r));
559
560                                 state = PRE_KEY;
561                         }
562
563                         break;
564                 default:
565                         assert_not_reached("invalid state when parsing uevent file");
566                 }
567         }
568
569         if (major) {
570                 r = device_set_devnum(device, major, minor);
571                 if (r < 0)
572                         log_debug("sd-device: could not set 'MAJOR=%s' or 'MINOR=%s' from '%s': %s", major, minor, path, strerror(-r));
573         }
574
575         return 0;
576 }
577
578 _public_ int sd_device_get_ifindex(sd_device *device, int *ifindex) {
579         int r;
580
581         assert_return(device, -EINVAL);
582         assert_return(ifindex, -EINVAL);
583
584         r = device_read_uevent_file(device);
585         if (r < 0)
586                 return r;
587
588         *ifindex = device->ifindex;
589
590         return 0;
591 }
592
593 _public_ int sd_device_new_from_device_id(sd_device **ret, const char *id) {
594         int r;
595
596         assert_return(ret, -EINVAL);
597         assert_return(id, -EINVAL);
598
599         switch (id[0]) {
600         case 'b':
601         case 'c':
602         {
603                 char type;
604                 int maj, min;
605
606                 r = sscanf(id, "%c%i:%i", &type, &maj, &min);
607                 if (r != 3)
608                         return -EINVAL;
609
610                 return sd_device_new_from_devnum(ret, type, makedev(maj, min));
611         }
612         case 'n':
613         {
614                 _cleanup_device_unref_ sd_device *device = NULL;
615                 _cleanup_close_ int sk = -1;
616                 struct ifreq ifr = {};
617                 int ifindex;
618
619                 r = safe_atoi(&id[1], &ifr.ifr_ifindex);
620                 if (r < 0)
621                         return r;
622                 else if (ifr.ifr_ifindex <= 0)
623                         return -EINVAL;
624
625                 sk = socket(PF_INET, SOCK_DGRAM, 0);
626                 if (sk < 0)
627                         return -errno;
628
629                 r = ioctl(sk, SIOCGIFNAME, &ifr);
630                 if (r < 0)
631                         return -errno;
632
633                 r = sd_device_new_from_subsystem_sysname(&device, "net", ifr.ifr_name);
634                 if (r < 0)
635                         return r;
636
637                 r = sd_device_get_ifindex(device, &ifindex);
638                 if (r < 0)
639                         return r;
640
641                 /* this is racey, so we might end up with the wrong device */
642                 if (ifr.ifr_ifindex != ifindex)
643                         return -ENODEV;
644
645                 *ret = device;
646                 device = NULL;
647
648                 return 0;
649         }
650         case '+':
651         {
652                 char subsys[PATH_MAX];
653                 char *sysname;
654
655                 (void)strscpy(subsys, sizeof(subsys), id + 1);
656                 sysname = strchr(subsys, ':');
657                 if (!sysname)
658                         return -EINVAL;
659
660                 sysname[0] = '\0';
661                 sysname ++;
662
663                 return sd_device_new_from_subsystem_sysname(ret, subsys, sysname);
664         }
665         default:
666                 return -EINVAL;
667         }
668 }
669
670 _public_ int sd_device_get_syspath(sd_device *device, const char **ret) {
671         assert_return(device, -EINVAL);
672         assert_return(ret, -EINVAL);
673
674         assert(path_startswith(device->syspath, "/sys/"));
675
676         *ret = device->syspath;
677
678         return 0;
679 }
680
681 static int device_new_from_child(sd_device **ret, sd_device *child) {
682         _cleanup_free_ char *path = NULL;
683         const char *subdir, *syspath;
684         int r;
685
686         assert(ret);
687         assert(child);
688
689         r = sd_device_get_syspath(child, &syspath);
690         if (r < 0)
691                 return r;
692
693         path = strdup(syspath);
694         if (!path)
695                 return -ENOMEM;
696         subdir = path + strlen("/sys");
697
698         for (;;) {
699                 char *pos;
700
701                 pos = strrchr(subdir, '/');
702                 if (!pos || pos < subdir + 2)
703                         break;
704
705                 *pos = '\0';
706
707                 r = sd_device_new_from_syspath(ret, path);
708                 if (r < 0)
709                         continue;
710
711                 return 0;
712         }
713
714         return -ENODEV;
715 }
716
717 _public_ int sd_device_get_parent(sd_device *child, sd_device **ret) {
718
719         assert_return(ret, -EINVAL);
720         assert_return(child, -EINVAL);
721
722         if (!child->parent_set) {
723                 child->parent_set = true;
724
725                 (void)device_new_from_child(&child->parent, child);
726         }
727
728         if (!child->parent)
729                 return -ENOENT;
730
731         *ret = child->parent;
732
733         return 0;
734 }
735
736 int device_set_subsystem(sd_device *device, const char *_subsystem) {
737         _cleanup_free_ char *subsystem = NULL;
738         int r;
739
740         assert(device);
741         assert(_subsystem);
742
743         subsystem = strdup(_subsystem);
744         if (!subsystem)
745                 return -ENOMEM;
746
747         r = device_add_property_internal(device, "SUBSYSTEM", subsystem);
748         if (r < 0)
749                 return r;
750
751         free(device->subsystem);
752         device->subsystem = subsystem;
753         subsystem = NULL;
754
755         device->subsystem_set = true;
756
757         return 0;
758 }
759
760 _public_ int sd_device_get_subsystem(sd_device *device, const char **ret) {
761         assert_return(ret, -EINVAL);
762         assert_return(device, -EINVAL);
763
764         if (!device->subsystem_set) {
765                 _cleanup_free_ char *subsystem = NULL;
766                 const char *syspath;
767                 char *path;
768                 int r;
769
770                 /* read 'subsystem' link */
771                 r = sd_device_get_syspath(device, &syspath);
772                 if (r < 0)
773                         return r;
774
775                 path = strjoina(syspath, "/subsystem");
776                 r = readlink_value(path, &subsystem);
777                 if (r >= 0)
778                         r = device_set_subsystem(device, subsystem);
779                 /* use implicit names */
780                 else if (path_startswith(device->devpath, "/module/"))
781                         r = device_set_subsystem(device, "module");
782                 else if (strstr(device->devpath, "/drivers/"))
783                         r = device_set_subsystem(device, "drivers");
784                 else if (path_startswith(device->devpath, "/subsystem/") ||
785                          path_startswith(device->devpath, "/class/") ||
786                          path_startswith(device->devpath, "/bus/"))
787                         r = device_set_subsystem(device, "subsystem");
788                 if (r < 0 && r != -ENOENT)
789                         return log_debug_errno(r, "sd-device: could not set subsystem for %s: %m", device->devpath);
790
791                 device->subsystem_set = true;
792         }
793
794         *ret = device->subsystem;
795
796         return 0;
797 }
798
799 _public_ int sd_device_get_devtype(sd_device *device, const char **devtype) {
800         int r;
801
802         assert(devtype);
803         assert(device);
804
805         r = device_read_uevent_file(device);
806         if (r < 0)
807                 return r;
808
809         *devtype = device->devtype;
810
811         return 0;
812 }
813
814 _public_ int sd_device_get_parent_with_subsystem_devtype(sd_device *child, const char *subsystem, const char *devtype, sd_device **ret) {
815         sd_device *parent = NULL;
816         int r;
817
818         assert_return(child, -EINVAL);
819         assert_return(subsystem, -EINVAL);
820
821         r = sd_device_get_parent(child, &parent);
822         while (r >= 0) {
823                 const char *parent_subsystem = NULL;
824                 const char *parent_devtype = NULL;
825
826                 (void)sd_device_get_subsystem(parent, &parent_subsystem);
827                 if (streq_ptr(parent_subsystem, subsystem)) {
828                         if (!devtype)
829                                 break;
830
831                         (void)sd_device_get_devtype(parent, &parent_devtype);
832                         if (streq_ptr(parent_devtype, devtype))
833                                 break;
834                 }
835                 r = sd_device_get_parent(parent, &parent);
836         }
837
838         if (r < 0)
839                 return r;
840
841         *ret = parent;
842
843         return 0;
844 }
845
846 _public_ int sd_device_get_devnum(sd_device *device, dev_t *devnum) {
847         int r;
848
849         assert_return(device, -EINVAL);
850         assert_return(devnum, -EINVAL);
851
852         r = device_read_uevent_file(device);
853         if (r < 0)
854                 return r;
855
856         *devnum = device->devnum;
857
858         return 0;
859 }
860
861 int device_set_driver(sd_device *device, const char *_driver) {
862         _cleanup_free_ char *driver = NULL;
863         int r;
864
865         assert(device);
866         assert(_driver);
867
868         driver = strdup(_driver);
869         if (!driver)
870                 return -ENOMEM;
871
872         r = device_add_property_internal(device, "DRIVER", driver);
873         if (r < 0)
874                 return r;
875
876         free(device->driver);
877         device->driver = driver;
878         driver = NULL;
879
880         device->driver_set = true;
881
882         return 0;
883 }
884
885 _public_ int sd_device_get_driver(sd_device *device, const char **ret) {
886         assert_return(device, -EINVAL);
887         assert_return(ret, -EINVAL);
888
889         if (!device->driver_set) {
890                 _cleanup_free_ char *driver = NULL;
891                 const char *syspath;
892                 char *path;
893                 int r;
894
895                 r = sd_device_get_syspath(device, &syspath);
896                 if (r < 0)
897                         return r;
898
899                 path = strjoina(syspath, "/driver");
900                 r = readlink_value(path, &driver);
901                 if (r >= 0) {
902                         r = device_set_driver(device, driver);
903                         if (r < 0)
904                                 return log_debug_errno(r, "sd-device: could not set driver for %s: %m", device->devpath);
905                 } else if (r == -ENOENT)
906                         device->driver_set = true;
907                 else
908                         return log_debug_errno(r, "sd-device: could not set driver for %s: %m", device->devpath);
909         }
910
911         *ret = device->driver;
912
913         return 0;
914 }
915
916 _public_ int sd_device_get_devpath(sd_device *device, const char **devpath) {
917         assert_return(device, -EINVAL);
918         assert_return(devpath, -EINVAL);
919
920         assert(device->devpath);
921         assert(device->devpath[0] == '/');
922
923         *devpath = device->devpath;
924
925         return 0;
926 }
927
928 _public_ int sd_device_get_devname(sd_device *device, const char **devname) {
929         int r;
930
931         assert_return(device, -EINVAL);
932         assert_return(devname, -EINVAL);
933
934         r = device_read_uevent_file(device);
935         if (r < 0)
936                 return r;
937
938         if (!device->devname)
939                 return -ENOENT;
940
941         assert(path_startswith(device->devname, "/dev/"));
942
943         *devname = device->devname;
944
945         return 0;
946 }
947
948 static int device_set_sysname(sd_device *device) {
949         _cleanup_free_ char *sysname = NULL;
950         const char *sysnum = NULL;
951         const char *pos;
952         size_t len = 0;
953
954         pos = strrchr(device->devpath, '/');
955         if (!pos)
956                 return -EINVAL;
957         pos ++;
958
959         /* devpath is not a root directory */
960         if (*pos == '\0' || pos <= device->devpath)
961                 return -EINVAL;
962
963         sysname = strdup(pos);
964         if (!sysname)
965                 return -ENOMEM;
966
967         /* some devices have '!' in their name, change that to '/' */
968         while (sysname[len] != '\0') {
969                 if (sysname[len] == '!')
970                         sysname[len] = '/';
971
972                 len ++;
973         }
974
975         /* trailing number */
976         while (len > 0 && isdigit(sysname[--len]))
977                 sysnum = &sysname[len];
978
979         if (len == 0)
980                 sysnum = NULL;
981
982         free(device->sysname);
983         device->sysname = sysname;
984         sysname = NULL;
985
986         device->sysnum = sysnum;
987
988         device->sysname_set = true;
989
990         return 0;
991 }
992
993 _public_ int sd_device_get_sysname(sd_device *device, const char **ret) {
994         int r;
995
996         assert_return(device, -EINVAL);
997         assert_return(ret, -EINVAL);
998
999         if (!device->sysname_set) {
1000                 r = device_set_sysname(device);
1001                 if (r < 0)
1002                         return r;
1003         }
1004
1005         *ret = device->sysname;
1006
1007         return 0;
1008 }
1009
1010 _public_ int sd_device_get_sysnum(sd_device *device, const char **ret) {
1011         int r;
1012
1013         assert_return(device, -EINVAL);
1014         assert_return(ret, -EINVAL);
1015
1016         if (!device->sysname_set) {
1017                 r = device_set_sysname(device);
1018                 if (r < 0)
1019                         return r;
1020         }
1021
1022         *ret = device->sysnum;
1023
1024         return 0;
1025 }
1026
1027 static bool is_valid_tag(const char *tag) {
1028         assert(tag);
1029
1030         return !strchr(tag, ':') && !strchr(tag, ' ');
1031 }
1032
1033 int device_add_tag(sd_device *device, const char *tag) {
1034         int r;
1035
1036         assert(device);
1037         assert(tag);
1038
1039         if (!is_valid_tag(tag))
1040                 return -EINVAL;
1041
1042         r = set_ensure_allocated(&device->tags, &string_hash_ops);
1043         if (r < 0)
1044                 return r;
1045
1046         r = set_put_strdup(device->tags, tag);
1047         if (r < 0)
1048                 return r;
1049
1050         device->tags_generation ++;
1051         device->property_tags_outdated = true;
1052
1053         return 0;
1054 }
1055
1056 int device_add_devlink(sd_device *device, const char *devlink) {
1057         int r;
1058
1059         assert(device);
1060         assert(devlink);
1061
1062         r = set_ensure_allocated(&device->devlinks, &string_hash_ops);
1063         if (r < 0)
1064                 return r;
1065
1066         r = set_put_strdup(device->devlinks, devlink);
1067         if (r < 0)
1068                 return r;
1069
1070         device->devlinks_generation ++;
1071         device->property_devlinks_outdated = true;
1072
1073         return 0;
1074 }
1075
1076 static int device_add_property_internal_from_string(sd_device *device, const char *str) {
1077         _cleanup_free_ char *key = NULL;
1078         char *value;
1079
1080         assert(device);
1081         assert(str);
1082
1083         key = strdup(str);
1084         if (!key)
1085                 return -ENOMEM;
1086
1087         value = strchr(key, '=');
1088         if (!value)
1089                 return -EINVAL;
1090
1091         *value = '\0';
1092
1093         if (isempty(++value))
1094                 value = NULL;
1095
1096         return device_add_property_internal(device, key, value);
1097 }
1098
1099 int device_set_usec_initialized(sd_device *device, const char *initialized) {
1100         uint64_t usec_initialized;
1101         int r;
1102
1103         assert(device);
1104         assert(initialized);
1105
1106         r = safe_atou64(initialized, &usec_initialized);
1107         if (r < 0)
1108                 return r;
1109
1110         r = device_add_property_internal(device, "USEC_INITIALIZED", initialized);
1111         if (r < 0)
1112                 return r;
1113
1114         device->usec_initialized = usec_initialized;
1115
1116         return 0;
1117 }
1118
1119 static int handle_db_line(sd_device *device, char key, const char *value) {
1120         char *path;
1121         int r;
1122
1123         assert(device);
1124         assert(value);
1125
1126         switch (key) {
1127         case 'G':
1128                 r = device_add_tag(device, value);
1129                 if (r < 0)
1130                         return r;
1131
1132                 break;
1133         case 'S':
1134                 path = strjoina("/dev/", value);
1135                 r = device_add_devlink(device, path);
1136                 if (r < 0)
1137                         return r;
1138
1139                 break;
1140         case 'E':
1141                 r = device_add_property_internal_from_string(device, value);
1142                 if (r < 0)
1143                         return r;
1144
1145                 break;
1146         case 'I':
1147                 r = device_set_usec_initialized(device, value);
1148                 if (r < 0)
1149                         return r;
1150
1151                 break;
1152         case 'L':
1153                 r = safe_atoi(value, &device->devlink_priority);
1154                 if (r < 0)
1155                         return r;
1156
1157                 break;
1158         case 'W':
1159                 r = safe_atoi(value, &device->watch_handle);
1160                 if (r < 0)
1161                         return r;
1162
1163                 break;
1164         default:
1165                 log_debug("device db: unknown key '%c'", key);
1166         }
1167
1168         return 0;
1169 }
1170
1171 int device_get_id_filename(sd_device *device, const char **ret) {
1172         assert(device);
1173         assert(ret);
1174
1175         if (!device->id_filename) {
1176                 _cleanup_free_ char *id = NULL;
1177                 const char *subsystem;
1178                 dev_t devnum;
1179                 int ifindex, r;
1180
1181                 r = sd_device_get_subsystem(device, &subsystem);
1182                 if (r < 0)
1183                         return r;
1184
1185                 r = sd_device_get_devnum(device, &devnum);
1186                 if (r < 0)
1187                         return r;
1188
1189                 r = sd_device_get_ifindex(device, &ifindex);
1190                 if (r < 0)
1191                         return r;
1192
1193                 if (major(devnum) > 0) {
1194                         assert(subsystem);
1195
1196                         /* use dev_t -- b259:131072, c254:0 */
1197                         r = asprintf(&id, "%c%u:%u",
1198                                      streq(subsystem, "block") ? 'b' : 'c',
1199                                      major(devnum), minor(devnum));
1200                         if (r < 0)
1201                                 return -ENOMEM;
1202                 } else if (ifindex > 0) {
1203                         /* use netdev ifindex -- n3 */
1204                         r = asprintf(&id, "n%u", ifindex);
1205                         if (r < 0)
1206                                 return -ENOMEM;
1207                 } else {
1208                         /* use $subsys:$sysname -- pci:0000:00:1f.2
1209                          * sysname() has '!' translated, get it from devpath
1210                          */
1211                         const char *sysname;
1212
1213                         sysname = basename(device->devpath);
1214                         if (!sysname)
1215                                 return -EINVAL;
1216
1217                         if (!subsystem)
1218                                 return -EINVAL;
1219
1220                         r = asprintf(&id, "+%s:%s", subsystem, sysname);
1221                         if (r < 0)
1222                                 return -ENOMEM;
1223                 }
1224
1225                 device->id_filename = id;
1226                 id = NULL;
1227         }
1228
1229         *ret = device->id_filename;
1230
1231         return 0;
1232 }
1233
1234 int device_read_db_aux(sd_device *device, bool force) {
1235         _cleanup_free_ char *db = NULL;
1236         char *path;
1237         const char *id, *value;
1238         char key;
1239         size_t db_len;
1240         unsigned i;
1241         int r;
1242
1243         enum {
1244                 PRE_KEY,
1245                 KEY,
1246                 PRE_VALUE,
1247                 VALUE,
1248                 INVALID_LINE,
1249         } state = PRE_KEY;
1250
1251         if (device->db_loaded || (!force && device->sealed))
1252                 return 0;
1253
1254         device->db_loaded = true;
1255
1256         r = device_get_id_filename(device, &id);
1257         if (r < 0)
1258                 return r;
1259
1260         path = strjoina("/run/udev/data/", id);
1261
1262         r = read_full_file(path, &db, &db_len);
1263         if (r < 0) {
1264                 if (r == -ENOENT)
1265                         return 0;
1266                 else {
1267                         log_debug("sd-device: failed to read db '%s': %s", path, strerror(-r));
1268                         return r;
1269                 }
1270         }
1271
1272         /* devices with a database entry are initialized */
1273         device->is_initialized = true;;
1274
1275         for (i = 0; i < db_len; i++) {
1276                 switch (state) {
1277                 case PRE_KEY:
1278                         if (!strchr(NEWLINE, db[i])) {
1279                                 key = db[i];
1280
1281                                 state = KEY;
1282                         }
1283
1284                         break;
1285                 case KEY:
1286                         if (db[i] != ':') {
1287                                 log_debug("sd-device: ignoring invalid db entry with key '%c'", key);
1288
1289                                 state = INVALID_LINE;
1290                         } else {
1291                                 db[i] = '\0';
1292
1293                                 state = PRE_VALUE;
1294                         }
1295
1296                         break;
1297                 case PRE_VALUE:
1298                         value = &db[i];
1299
1300                         state = VALUE;
1301
1302                         break;
1303                 case INVALID_LINE:
1304                         if (strchr(NEWLINE, db[i]))
1305                                 state = PRE_KEY;
1306
1307                         break;
1308                 case VALUE:
1309                         if (strchr(NEWLINE, db[i])) {
1310                                 db[i] = '\0';
1311                                 r = handle_db_line(device, key, value);
1312                                 if (r < 0)
1313                                         log_debug("sd-device: failed to handle db entry '%c:%s': %s", key, value, strerror(-r));
1314
1315                                 state = PRE_KEY;
1316                         }
1317
1318                         break;
1319                 default:
1320                         assert_not_reached("invalid state when parsing db");
1321                 }
1322         }
1323
1324         return 0;
1325 }
1326
1327 static int device_read_db(sd_device *device) {
1328         return device_read_db_aux(device, false);
1329 }
1330
1331 _public_ int sd_device_get_is_initialized(sd_device *device, int *initialized) {
1332         int r;
1333
1334         assert_return(device, -EINVAL);
1335         assert_return(initialized, -EINVAL);
1336
1337         r = device_read_db(device);
1338         if (r < 0)
1339                 return r;
1340
1341         *initialized = device->is_initialized;
1342
1343         return 0;
1344 }
1345
1346 _public_ int sd_device_get_usec_since_initialized(sd_device *device, uint64_t *usec) {
1347         usec_t now_ts;
1348         int r;
1349
1350         assert_return(device, -EINVAL);
1351         assert_return(usec, -EINVAL);
1352
1353         r = device_read_db(device);
1354         if (r < 0)
1355                 return r;
1356
1357         if (!device->is_initialized)
1358                 return -EBUSY;
1359
1360         if (!device->usec_initialized)
1361                 return -ENODATA;
1362
1363         now_ts = now(clock_boottime_or_monotonic());
1364
1365         if (now_ts < device->usec_initialized)
1366                 return -EIO;
1367
1368         *usec = now_ts - device->usec_initialized;
1369
1370         return 0;
1371 }
1372
1373 _public_ const char *sd_device_get_tag_first(sd_device *device) {
1374         assert_return(device, NULL);
1375
1376         (void) device_read_db(device);
1377
1378         device->tags_iterator_generation = device->tags_generation;
1379         device->tags_iterator = ITERATOR_FIRST;
1380
1381         return set_iterate(device->tags, &device->tags_iterator);
1382 }
1383
1384 _public_ const char *sd_device_get_tag_next(sd_device *device) {
1385         assert_return(device, NULL);
1386
1387         (void) device_read_db(device);
1388
1389         if (device->tags_iterator_generation != device->tags_generation)
1390                 return NULL;
1391
1392         return set_iterate(device->tags, &device->tags_iterator);
1393 }
1394
1395 _public_ const char *sd_device_get_devlink_first(sd_device *device) {
1396         assert_return(device, NULL);
1397
1398         (void) device_read_db(device);
1399
1400         device->devlinks_iterator_generation = device->devlinks_generation;
1401         device->devlinks_iterator = ITERATOR_FIRST;
1402
1403         return set_iterate(device->devlinks, &device->devlinks_iterator);
1404 }
1405
1406 _public_ const char *sd_device_get_devlink_next(sd_device *device) {
1407         assert_return(device, NULL);
1408
1409         (void) device_read_db(device);
1410
1411         if (device->devlinks_iterator_generation != device->devlinks_generation)
1412                 return NULL;
1413
1414         return set_iterate(device->devlinks, &device->devlinks_iterator);
1415 }
1416
1417 static int device_properties_prepare(sd_device *device) {
1418         int r;
1419
1420         assert(device);
1421
1422         r = device_read_uevent_file(device);
1423         if (r < 0)
1424                 return r;
1425
1426         r = device_read_db(device);
1427         if (r < 0)
1428                 return r;
1429
1430         if (device->property_devlinks_outdated) {
1431                 char *devlinks = NULL;
1432                 const char *devlink;
1433
1434                 devlink = sd_device_get_devlink_first(device);
1435                 if (devlink)
1436                         devlinks = strdupa(devlink);
1437
1438                 while ((devlink = sd_device_get_devlink_next(device)))
1439                         devlinks = strjoina(devlinks, " ", devlink);
1440
1441                 r = device_add_property_internal(device, "DEVLINKS", devlinks);
1442                 if (r < 0)
1443                         return r;
1444
1445                 device->property_devlinks_outdated = false;
1446         }
1447
1448         if (device->property_tags_outdated) {
1449                 char *tags = NULL;
1450                 const char *tag;
1451
1452                 tag = sd_device_get_tag_first(device);
1453                 if (tag)
1454                         tags = strjoina(":", tag);
1455
1456                 while ((tag = sd_device_get_tag_next(device)))
1457                         tags = strjoina(tags, ":", tag);
1458
1459                 tags = strjoina(tags, ":");
1460
1461                 r = device_add_property_internal(device, "TAGS", tags);
1462                 if (r < 0)
1463                         return r;
1464
1465                 device->property_tags_outdated = false;
1466         }
1467
1468         return 0;
1469 }
1470
1471 _public_ const char *sd_device_get_property_first(sd_device *device, const char **_value) {
1472         const char *key;
1473         const char *value;
1474         int r;
1475
1476         assert_return(device, NULL);
1477
1478         r = device_properties_prepare(device);
1479         if (r < 0)
1480                 return NULL;
1481
1482         device->properties_iterator_generation = device->properties_generation;
1483         device->properties_iterator = ITERATOR_FIRST;
1484
1485         value = ordered_hashmap_iterate(device->properties, &device->properties_iterator, (const void**)&key);
1486
1487         if (_value)
1488                 *_value = value;
1489
1490         return key;
1491 }
1492
1493 _public_ const char *sd_device_get_property_next(sd_device *device, const char **_value) {
1494         const char *key;
1495         const char *value;
1496         int r;
1497
1498         assert_return(device, NULL);
1499
1500         r = device_properties_prepare(device);
1501         if (r < 0)
1502                 return NULL;
1503
1504         if (device->properties_iterator_generation != device->properties_generation)
1505                 return NULL;
1506
1507         value = ordered_hashmap_iterate(device->properties, &device->properties_iterator, (const void**)&key);
1508
1509         if (_value)
1510                 *_value = value;
1511
1512         return key;
1513 }
1514
1515 static int device_sysattrs_read_all(sd_device *device) {
1516         _cleanup_closedir_ DIR *dir = NULL;
1517         const char *syspath;
1518         struct dirent *dent;
1519         int r;
1520
1521         assert(device);
1522
1523         if (device->sysattrs_read)
1524                 return 0;
1525
1526         r = sd_device_get_syspath(device, &syspath);
1527         if (r < 0)
1528                 return r;
1529
1530         dir = opendir(syspath);
1531         if (!dir)
1532                 return -errno;
1533
1534         r = set_ensure_allocated(&device->sysattrs, &string_hash_ops);
1535         if (r < 0)
1536                 return r;
1537
1538         for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
1539                 char *path;
1540                 struct stat statbuf;
1541
1542                 /* only handle symlinks and regular files */
1543                 if (dent->d_type != DT_LNK && dent->d_type != DT_REG)
1544                         continue;
1545
1546                 path = strjoina(syspath, "/", dent->d_name);
1547
1548                 if (lstat(path, &statbuf) != 0)
1549                         continue;
1550
1551                 if (!(statbuf.st_mode & S_IRUSR))
1552                         continue;
1553
1554                 r = set_put_strdup(device->sysattrs, dent->d_name);
1555                 if (r < 0)
1556                         return r;
1557         }
1558
1559         device->sysattrs_read = true;
1560
1561         return 0;
1562 }
1563
1564 _public_ const char *sd_device_get_sysattr_first(sd_device *device) {
1565         int r;
1566
1567         assert_return(device, NULL);
1568
1569         if (!device->sysattrs_read) {
1570                 r = device_sysattrs_read_all(device);
1571                 if (r < 0) {
1572                         errno = -r;
1573                         return NULL;
1574                 }
1575         }
1576
1577         device->sysattrs_iterator = ITERATOR_FIRST;
1578
1579         return set_iterate(device->sysattrs, &device->sysattrs_iterator);
1580 }
1581
1582 _public_ const char *sd_device_get_sysattr_next(sd_device *device) {
1583         assert_return(device, NULL);
1584
1585         if (!device->sysattrs_read)
1586                 return NULL;
1587
1588         return set_iterate(device->sysattrs, &device->sysattrs_iterator);
1589 }
1590
1591 _public_ int sd_device_has_tag(sd_device *device, const char *tag) {
1592         assert_return(device, -EINVAL);
1593         assert_return(tag, -EINVAL);
1594
1595         (void) device_read_db(device);
1596
1597         return !!set_contains(device->tags, tag);
1598 }
1599
1600 _public_ int sd_device_get_property_value(sd_device *device, const char *key, const char **_value) {
1601         char *value;
1602         int r;
1603
1604         assert_return(device, -EINVAL);
1605         assert_return(key, -EINVAL);
1606         assert_return(_value, -EINVAL);
1607
1608         r = device_properties_prepare(device);
1609         if (r < 0)
1610                 return r;
1611
1612         value = ordered_hashmap_get(device->properties, key);
1613         if (!value)
1614                 return -ENOENT;
1615
1616         *_value = value;
1617
1618         return 0;
1619 }
1620
1621 /* replaces the value if it already exists */
1622 static int device_add_sysattr_value(sd_device *device, const char *_key, char *value) {
1623         _cleanup_free_ char *key = NULL;
1624         _cleanup_free_ char *value_old = NULL;
1625         int r;
1626
1627         assert(device);
1628         assert(_key);
1629
1630         r = hashmap_ensure_allocated(&device->sysattr_values, &string_hash_ops);
1631         if (r < 0)
1632                 return r;
1633
1634         value_old = hashmap_remove2(device->sysattr_values, _key, (void **)&key);
1635         if (!key) {
1636                 key = strdup(_key);
1637                 if (!key)
1638                         return -ENOMEM;
1639         }
1640
1641         r = hashmap_put(device->sysattr_values, key, value);
1642         if (r < 0)
1643                 return r;
1644
1645         key = NULL;
1646
1647         return 0;
1648 }
1649
1650 static int device_get_sysattr_value(sd_device *device, const char *_key, const char **_value) {
1651         const char *key = NULL, *value;
1652
1653         assert(device);
1654         assert(_key);
1655
1656         value = hashmap_get2(device->sysattr_values, _key, (void **) &key);
1657         if (!key)
1658                 return -ENOENT;
1659
1660         if (_value)
1661                 *_value = value;
1662
1663         return 0;
1664 }
1665
1666 /* We cache all sysattr lookups. If an attribute does not exist, it is stored
1667  * with a NULL value in the cache, otherwise the returned string is stored */
1668 _public_ int sd_device_get_sysattr_value(sd_device *device, const char *sysattr, const char **_value) {
1669         _cleanup_free_ char *value = NULL;
1670         const char *syspath, *cached_value = NULL;
1671         char *path;
1672         struct stat statbuf;
1673         int r;
1674
1675         assert_return(device, -EINVAL);
1676         assert_return(sysattr, -EINVAL);
1677
1678         /* look for possibly already cached result */
1679         r = device_get_sysattr_value(device, sysattr, &cached_value);
1680         if (r != -ENOENT) {
1681                 if (r < 0)
1682                         return r;
1683
1684                 if (!cached_value)
1685                         /* we looked up the sysattr before and it did not exist */
1686                         return -ENOENT;
1687
1688                 if (_value)
1689                         *_value = cached_value;
1690
1691                 return 0;
1692         }
1693
1694         r = sd_device_get_syspath(device, &syspath);
1695         if (r < 0)
1696                 return r;
1697
1698         path = strjoina(syspath, "/", sysattr);
1699         r = lstat(path, &statbuf);
1700         if (r < 0) {
1701                 /* remember that we could not access the sysattr */
1702                 r = device_add_sysattr_value(device, sysattr, NULL);
1703                 if (r < 0)
1704                         return r;
1705
1706                 return -ENOENT;
1707         } else if (S_ISLNK(statbuf.st_mode)) {
1708                 /* Some core links return only the last element of the target path,
1709                  * these are just values, the paths should not be exposed. */
1710                 if (STR_IN_SET(sysattr, "driver", "subsystem", "module")) {
1711                         r = readlink_value(path, &value);
1712                         if (r < 0)
1713                                 return r;
1714                 } else
1715                         return -EINVAL;
1716         } else if (S_ISDIR(statbuf.st_mode)) {
1717                 /* skip directories */
1718                 return -EINVAL;
1719         } else if (!(statbuf.st_mode & S_IRUSR)) {
1720                 /* skip non-readable files */
1721                 return -EPERM;
1722         } else {
1723                 size_t size;
1724
1725                 /* read attribute value */
1726                 r = read_full_file(path, &value, &size);
1727                 if (r < 0)
1728                         return r;
1729
1730                 /* drop trailing newlines */
1731                 while (size > 0 && value[--size] == '\n')
1732                         value[size] = '\0';
1733         }
1734
1735         r = device_add_sysattr_value(device, sysattr, value);
1736         if (r < 0)
1737                 return r;
1738
1739         *_value = value;
1740         value = NULL;
1741
1742         return 0;
1743 }
1744
1745 static void device_remove_sysattr_value(sd_device *device, const char *_key) {
1746         _cleanup_free_ char *key = NULL;
1747         _cleanup_free_ char *value = NULL;
1748
1749         assert(device);
1750         assert(_key);
1751
1752         value = hashmap_remove2(device->sysattr_values, _key, (void **) &key);
1753
1754         return;
1755 }
1756
1757 /* set the attribute and save it in the cache. If a NULL value is passed the
1758  * attribute is cleared from the cache */
1759 _public_ int sd_device_set_sysattr_value(sd_device *device, const char *sysattr, char *_value) {
1760         _cleanup_close_ int fd = -1;
1761         _cleanup_free_ char *value = NULL;
1762         const char *syspath;
1763         char *path;
1764         struct stat statbuf;
1765         size_t value_len = 0;
1766         ssize_t size;
1767         int r;
1768
1769         assert_return(device, -EINVAL);
1770         assert_return(sysattr, -EINVAL);
1771
1772         if (!_value) {
1773                 device_remove_sysattr_value(device, sysattr);
1774
1775                 return 0;
1776         }
1777
1778         r = sd_device_get_syspath(device, &syspath);
1779         if (r < 0)
1780                 return r;
1781
1782         path = strjoina(syspath, "/", sysattr);
1783         r = lstat(path, &statbuf);
1784         if (r < 0) {
1785                 value = strdup("");
1786                 if (!value)
1787                         return -ENOMEM;
1788
1789                 r = device_add_sysattr_value(device, sysattr, value);
1790                 if (r < 0)
1791                         return r;
1792
1793                 return -ENXIO;
1794         }
1795
1796         if (S_ISLNK(statbuf.st_mode))
1797                 return -EINVAL;
1798
1799         /* skip directories */
1800         if (S_ISDIR(statbuf.st_mode))
1801                 return -EISDIR;
1802
1803         /* skip non-readable files */
1804         if ((statbuf.st_mode & S_IRUSR) == 0)
1805                 return -EACCES;
1806
1807         value_len = strlen(_value);
1808
1809         /* drop trailing newlines */
1810         while (value_len > 0 && _value[value_len - 1] == '\n')
1811                 _value[--value_len] = '\0';
1812
1813         /* value length is limited to 4k */
1814         if (value_len > 4096)
1815                 return -EINVAL;
1816
1817         fd = open(path, O_WRONLY | O_CLOEXEC);
1818         if (fd < 0)
1819                 return -errno;
1820
1821         value = strdup(_value);
1822         if (!value)
1823                 return -ENOMEM;
1824
1825         size = write(fd, value, value_len);
1826         if (size < 0)
1827                 return -errno;
1828
1829         if ((size_t)size != value_len)
1830                 return -EIO;
1831
1832         r = device_add_sysattr_value(device, sysattr, value);
1833         if (r < 0)
1834                 return r;
1835
1836         value = NULL;
1837
1838         return 0;
1839 }