LCOV - code coverage report
Current view: top level - libsystemd/sd-device - sd-device.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 797 1091 73.1 %
Date: 2019-08-22 15:41:25 Functions: 56 63 88.9 %

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

Generated by: LCOV version 1.14