LCOV - code coverage report
Current view: top level - libsystemd/sd-device - sd-device.c (source / functions) Hit Total Coverage
Test: systemd test coverage Lines: 601 1054 57.0 %
Date: 2015-07-29 18:47:03 Functions: 44 61 72.1 %

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

Generated by: LCOV version 1.11