LCOV - code coverage report
Current view: top level - udev - udevadm-info.c (source / functions) Hit Total Coverage
Test: systemd_full.info Lines: 0 258 0.0 %
Date: 2019-08-23 13:36:53 Functions: 0 11 0.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 198 0.0 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: GPL-2.0+ */
       2                 :            : 
       3                 :            : #include <ctype.h>
       4                 :            : #include <errno.h>
       5                 :            : #include <fcntl.h>
       6                 :            : #include <getopt.h>
       7                 :            : #include <stddef.h>
       8                 :            : #include <stdio.h>
       9                 :            : #include <string.h>
      10                 :            : #include <sys/stat.h>
      11                 :            : #include <unistd.h>
      12                 :            : 
      13                 :            : #include "sd-device.h"
      14                 :            : 
      15                 :            : #include "alloc-util.h"
      16                 :            : #include "device-enumerator-private.h"
      17                 :            : #include "device-private.h"
      18                 :            : #include "device-util.h"
      19                 :            : #include "dirent-util.h"
      20                 :            : #include "fd-util.h"
      21                 :            : #include "string-table.h"
      22                 :            : #include "string-util.h"
      23                 :            : #include "udev-util.h"
      24                 :            : #include "udevadm-util.h"
      25                 :            : #include "udevadm.h"
      26                 :            : 
      27                 :            : typedef enum ActionType {
      28                 :            :         ACTION_QUERY,
      29                 :            :         ACTION_ATTRIBUTE_WALK,
      30                 :            :         ACTION_DEVICE_ID_FILE,
      31                 :            : } ActionType;
      32                 :            : 
      33                 :            : typedef enum QueryType {
      34                 :            :         QUERY_NAME,
      35                 :            :         QUERY_PATH,
      36                 :            :         QUERY_SYMLINK,
      37                 :            :         QUERY_PROPERTY,
      38                 :            :         QUERY_ALL,
      39                 :            : } QueryType;
      40                 :            : 
      41                 :            : static bool arg_root = false;
      42                 :            : static bool arg_export = false;
      43                 :            : static const char *arg_export_prefix = NULL;
      44                 :            : static usec_t arg_wait_for_initialization_timeout = 0;
      45                 :            : 
      46                 :          0 : static bool skip_attribute(const char *name) {
      47                 :            :         static const char* const skip[] = {
      48                 :            :                 "uevent",
      49                 :            :                 "dev",
      50                 :            :                 "modalias",
      51                 :            :                 "resource",
      52                 :            :                 "driver",
      53                 :            :                 "subsystem",
      54                 :            :                 "module",
      55                 :            :         };
      56                 :            : 
      57                 :          0 :         return string_table_lookup(skip, ELEMENTSOF(skip), name) >= 0;
      58                 :            : }
      59                 :            : 
      60                 :          0 : static void print_all_attributes(sd_device *device, const char *key) {
      61                 :            :         const char *name, *value;
      62                 :            : 
      63         [ #  # ]:          0 :         FOREACH_DEVICE_SYSATTR(device, name) {
      64                 :            :                 size_t len;
      65                 :            : 
      66         [ #  # ]:          0 :                 if (skip_attribute(name))
      67                 :          0 :                         continue;
      68                 :            : 
      69         [ #  # ]:          0 :                 if (sd_device_get_sysattr_value(device, name, &value) < 0)
      70                 :          0 :                         continue;
      71                 :            : 
      72                 :            :                 /* skip any values that look like a path */
      73         [ #  # ]:          0 :                 if (value[0] == '/')
      74                 :          0 :                         continue;
      75                 :            : 
      76                 :            :                 /* skip nonprintable attributes */
      77                 :          0 :                 len = strlen(value);
      78   [ #  #  #  # ]:          0 :                 while (len > 0 && isprint(value[len-1]))
      79                 :          0 :                         len--;
      80         [ #  # ]:          0 :                 if (len > 0)
      81                 :          0 :                         continue;
      82                 :            : 
      83                 :          0 :                 printf("    %s{%s}==\"%s\"\n", key, name, value);
      84                 :            :         }
      85                 :          0 :         puts("");
      86                 :          0 : }
      87                 :            : 
      88                 :          0 : static int print_device_chain(sd_device *device) {
      89                 :            :         sd_device *child, *parent;
      90                 :            :         const char *str;
      91                 :            : 
      92                 :          0 :         printf("\n"
      93                 :            :                "Udevadm info starts with the device specified by the devpath and then\n"
      94                 :            :                "walks up the chain of parent devices. It prints for every device\n"
      95                 :            :                "found, all possible attributes in the udev rules key format.\n"
      96                 :            :                "A rule to match, can be composed by the attributes of the device\n"
      97                 :            :                "and the attributes from one single parent device.\n"
      98                 :            :                "\n");
      99                 :            : 
     100                 :          0 :         (void) sd_device_get_devpath(device, &str);
     101                 :          0 :         printf("  looking at device '%s':\n", str);
     102                 :          0 :         (void) sd_device_get_sysname(device, &str);
     103                 :          0 :         printf("    KERNEL==\"%s\"\n", str);
     104         [ #  # ]:          0 :         if (sd_device_get_subsystem(device, &str) < 0)
     105                 :          0 :                 str = "";
     106                 :          0 :         printf("    SUBSYSTEM==\"%s\"\n", str);
     107         [ #  # ]:          0 :         if (sd_device_get_driver(device, &str) < 0)
     108                 :          0 :                 str = "";
     109                 :          0 :         printf("    DRIVER==\"%s\"\n", str);
     110                 :          0 :         print_all_attributes(device, "ATTR");
     111                 :            : 
     112         [ #  # ]:          0 :         for (child = device; sd_device_get_parent(child, &parent) >= 0; child = parent) {
     113                 :          0 :                 (void) sd_device_get_devpath(parent, &str);
     114                 :          0 :                 printf("  looking at parent device '%s':\n", str);
     115                 :          0 :                 (void) sd_device_get_sysname(parent, &str);
     116                 :          0 :                 printf("    KERNELS==\"%s\"\n", str);
     117         [ #  # ]:          0 :                 if (sd_device_get_subsystem(parent, &str) < 0)
     118                 :          0 :                         str = "";
     119                 :          0 :                 printf("    SUBSYSTEMS==\"%s\"\n", str);
     120         [ #  # ]:          0 :                 if (sd_device_get_driver(parent, &str) < 0)
     121                 :          0 :                         str = "";
     122                 :          0 :                 printf("    DRIVERS==\"%s\"\n", str);
     123                 :          0 :                 print_all_attributes(parent, "ATTRS");
     124                 :            :         }
     125                 :            : 
     126                 :          0 :         return 0;
     127                 :            : }
     128                 :            : 
     129                 :          0 : static int print_record(sd_device *device) {
     130                 :            :         const char *str, *val;
     131                 :            :         int i;
     132                 :            : 
     133                 :          0 :         (void) sd_device_get_devpath(device, &str);
     134                 :          0 :         printf("P: %s\n", str);
     135                 :            : 
     136         [ #  # ]:          0 :         if (sd_device_get_devname(device, &str) >= 0) {
     137         [ #  # ]:          0 :                 assert_se(val = path_startswith(str, "/dev/"));
     138                 :          0 :                 printf("N: %s\n", val);
     139                 :            :         }
     140                 :            : 
     141         [ #  # ]:          0 :         if (device_get_devlink_priority(device, &i) >= 0)
     142                 :          0 :                 printf("L: %i\n", i);
     143                 :            : 
     144         [ #  # ]:          0 :         FOREACH_DEVICE_DEVLINK(device, str) {
     145         [ #  # ]:          0 :                 assert_se(val = path_startswith(str, "/dev/"));
     146                 :          0 :                 printf("S: %s\n", val);
     147                 :            :         }
     148                 :            : 
     149         [ #  # ]:          0 :         FOREACH_DEVICE_PROPERTY(device, str, val)
     150                 :          0 :                 printf("E: %s=%s\n", str, val);
     151                 :            : 
     152                 :          0 :         puts("");
     153                 :          0 :         return 0;
     154                 :            : }
     155                 :            : 
     156                 :          0 : static int stat_device(const char *name, bool export, const char *prefix) {
     157                 :            :         struct stat statbuf;
     158                 :            : 
     159         [ #  # ]:          0 :         if (stat(name, &statbuf) != 0)
     160                 :          0 :                 return -errno;
     161                 :            : 
     162         [ #  # ]:          0 :         if (export) {
     163         [ #  # ]:          0 :                 if (!prefix)
     164                 :          0 :                         prefix = "INFO_";
     165                 :          0 :                 printf("%sMAJOR=%u\n"
     166                 :            :                        "%sMINOR=%u\n",
     167                 :            :                        prefix, major(statbuf.st_dev),
     168                 :            :                        prefix, minor(statbuf.st_dev));
     169                 :            :         } else
     170                 :          0 :                 printf("%u:%u\n", major(statbuf.st_dev), minor(statbuf.st_dev));
     171                 :          0 :         return 0;
     172                 :            : }
     173                 :            : 
     174                 :          0 : static int export_devices(void) {
     175                 :          0 :         _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
     176                 :            :         sd_device *d;
     177                 :            :         int r;
     178                 :            : 
     179                 :          0 :         r = sd_device_enumerator_new(&e);
     180         [ #  # ]:          0 :         if (r < 0)
     181                 :          0 :                 return r;
     182                 :            : 
     183                 :          0 :         r = sd_device_enumerator_allow_uninitialized(e);
     184         [ #  # ]:          0 :         if (r < 0)
     185                 :          0 :                 return r;
     186                 :            : 
     187                 :          0 :         r = device_enumerator_scan_devices(e);
     188         [ #  # ]:          0 :         if (r < 0)
     189                 :          0 :                 return r;
     190                 :            : 
     191         [ #  # ]:          0 :         FOREACH_DEVICE_AND_SUBSYSTEM(e, d)
     192                 :          0 :                 print_record(d);
     193                 :            : 
     194                 :          0 :         return 0;
     195                 :            : }
     196                 :            : 
     197                 :          0 : static void cleanup_dir(DIR *dir, mode_t mask, int depth) {
     198                 :            :         struct dirent *dent;
     199                 :            : 
     200         [ #  # ]:          0 :         if (depth <= 0)
     201                 :          0 :                 return;
     202                 :            : 
     203   [ #  #  #  # ]:          0 :         FOREACH_DIRENT_ALL(dent, dir, break) {
     204                 :            :                 struct stat stats;
     205                 :            : 
     206         [ #  # ]:          0 :                 if (dent->d_name[0] == '.')
     207                 :          0 :                         continue;
     208         [ #  # ]:          0 :                 if (fstatat(dirfd(dir), dent->d_name, &stats, AT_SYMLINK_NOFOLLOW) != 0)
     209                 :          0 :                         continue;
     210         [ #  # ]:          0 :                 if ((stats.st_mode & mask) != 0)
     211                 :          0 :                         continue;
     212         [ #  # ]:          0 :                 if (S_ISDIR(stats.st_mode)) {
     213                 :          0 :                         _cleanup_closedir_ DIR *dir2 = NULL;
     214                 :            : 
     215                 :          0 :                         dir2 = fdopendir(openat(dirfd(dir), dent->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC));
     216         [ #  # ]:          0 :                         if (dir2)
     217                 :          0 :                                 cleanup_dir(dir2, mask, depth-1);
     218                 :            : 
     219                 :          0 :                         (void) unlinkat(dirfd(dir), dent->d_name, AT_REMOVEDIR);
     220                 :            :                 } else
     221                 :          0 :                         (void) unlinkat(dirfd(dir), dent->d_name, 0);
     222                 :            :         }
     223                 :            : }
     224                 :            : 
     225                 :          0 : static void cleanup_db(void) {
     226                 :          0 :         _cleanup_closedir_ DIR *dir1 = NULL, *dir2 = NULL, *dir3 = NULL, *dir4 = NULL, *dir5 = NULL;
     227                 :            : 
     228                 :          0 :         (void) unlink("/run/udev/queue.bin");
     229                 :            : 
     230                 :          0 :         dir1 = opendir("/run/udev/data");
     231         [ #  # ]:          0 :         if (dir1)
     232                 :          0 :                 cleanup_dir(dir1, S_ISVTX, 1);
     233                 :            : 
     234                 :          0 :         dir2 = opendir("/run/udev/links");
     235         [ #  # ]:          0 :         if (dir2)
     236                 :          0 :                 cleanup_dir(dir2, 0, 2);
     237                 :            : 
     238                 :          0 :         dir3 = opendir("/run/udev/tags");
     239         [ #  # ]:          0 :         if (dir3)
     240                 :          0 :                 cleanup_dir(dir3, 0, 2);
     241                 :            : 
     242                 :          0 :         dir4 = opendir("/run/udev/static_node-tags");
     243         [ #  # ]:          0 :         if (dir4)
     244                 :          0 :                 cleanup_dir(dir4, 0, 2);
     245                 :            : 
     246                 :          0 :         dir5 = opendir("/run/udev/watch");
     247         [ #  # ]:          0 :         if (dir5)
     248                 :          0 :                 cleanup_dir(dir5, 0, 1);
     249                 :          0 : }
     250                 :            : 
     251                 :          0 : static int query_device(QueryType query, sd_device* device) {
     252                 :            :         int r;
     253                 :            : 
     254         [ #  # ]:          0 :         assert(device);
     255                 :            : 
     256   [ #  #  #  #  :          0 :         switch(query) {
                   #  # ]
     257                 :          0 :         case QUERY_NAME: {
     258                 :            :                 const char *node;
     259                 :            : 
     260                 :          0 :                 r = sd_device_get_devname(device, &node);
     261         [ #  # ]:          0 :                 if (r < 0)
     262         [ #  # ]:          0 :                         return log_error_errno(r, "No device node found: %m");
     263                 :            : 
     264         [ #  # ]:          0 :                 if (!arg_root)
     265         [ #  # ]:          0 :                         assert_se(node = path_startswith(node, "/dev/"));
     266                 :          0 :                 printf("%s\n", node);
     267                 :          0 :                 return 0;
     268                 :            :         }
     269                 :            : 
     270                 :          0 :         case QUERY_SYMLINK: {
     271                 :          0 :                 const char *devlink, *prefix = "";
     272                 :            : 
     273         [ #  # ]:          0 :                 FOREACH_DEVICE_DEVLINK(device, devlink) {
     274         [ #  # ]:          0 :                         if (!arg_root)
     275         [ #  # ]:          0 :                                 assert_se(devlink = path_startswith(devlink, "/dev/"));
     276                 :          0 :                         printf("%s%s", prefix, devlink);
     277                 :          0 :                         prefix = " ";
     278                 :            :                 }
     279                 :          0 :                 puts("");
     280                 :          0 :                 return 0;
     281                 :            :         }
     282                 :            : 
     283                 :          0 :         case QUERY_PATH: {
     284                 :            :                 const char *devpath;
     285                 :            : 
     286                 :          0 :                 r = sd_device_get_devpath(device, &devpath);
     287         [ #  # ]:          0 :                 if (r < 0)
     288         [ #  # ]:          0 :                         return log_error_errno(r, "Failed to get device path: %m");
     289                 :            : 
     290                 :          0 :                 printf("%s\n", devpath);
     291                 :          0 :                 return 0;
     292                 :            :         }
     293                 :            : 
     294                 :          0 :         case QUERY_PROPERTY: {
     295                 :            :                 const char *key, *value;
     296                 :            : 
     297         [ #  # ]:          0 :                 FOREACH_DEVICE_PROPERTY(device, key, value)
     298         [ #  # ]:          0 :                         if (arg_export)
     299                 :          0 :                                 printf("%s%s='%s'\n", strempty(arg_export_prefix), key, value);
     300                 :            :                         else
     301                 :          0 :                                 printf("%s=%s\n", key, value);
     302                 :          0 :                 return 0;
     303                 :            :         }
     304                 :            : 
     305                 :          0 :         case QUERY_ALL:
     306                 :          0 :                 return print_record(device);
     307                 :            :         }
     308                 :            : 
     309                 :          0 :         assert_not_reached("unknown query type");
     310                 :            :         return 0;
     311                 :            : }
     312                 :            : 
     313                 :          0 : static int help(void) {
     314                 :          0 :         printf("%s info [OPTIONS] [DEVPATH|FILE]\n\n"
     315                 :            :                "Query sysfs or the udev database.\n\n"
     316                 :            :                "  -h --help                   Print this message\n"
     317                 :            :                "  -V --version                Print version of the program\n"
     318                 :            :                "  -q --query=TYPE             Query device information:\n"
     319                 :            :                "       name                     Name of device node\n"
     320                 :            :                "       symlink                  Pointing to node\n"
     321                 :            :                "       path                     sysfs device path\n"
     322                 :            :                "       property                 The device properties\n"
     323                 :            :                "       all                      All values\n"
     324                 :            :                "  -p --path=SYSPATH           sysfs device path used for query or attribute walk\n"
     325                 :            :                "  -n --name=NAME              Node or symlink name used for query or attribute walk\n"
     326                 :            :                "  -r --root                   Prepend dev directory to path names\n"
     327                 :            :                "  -a --attribute-walk         Print all key matches walking along the chain\n"
     328                 :            :                "                              of parent devices\n"
     329                 :            :                "  -d --device-id-of-file=FILE Print major:minor of device containing this file\n"
     330                 :            :                "  -x --export                 Export key/value pairs\n"
     331                 :            :                "  -P --export-prefix          Export the key name with a prefix\n"
     332                 :            :                "  -e --export-db              Export the content of the udev database\n"
     333                 :            :                "  -c --cleanup-db             Clean up the udev database\n"
     334                 :            :                "  -w --wait-for-initialization[=SECONDS]\n"
     335                 :            :                "                              Wait for device to be initialized\n"
     336                 :            :                , program_invocation_short_name);
     337                 :            : 
     338                 :          0 :         return 0;
     339                 :            : }
     340                 :            : 
     341                 :          0 : int info_main(int argc, char *argv[], void *userdata) {
     342                 :          0 :         _cleanup_strv_free_ char **devices = NULL;
     343                 :          0 :         _cleanup_free_ char *name = NULL;
     344                 :            :         int c, r;
     345                 :            : 
     346                 :            :         static const struct option options[] = {
     347                 :            :                 { "name",                    required_argument, NULL, 'n' },
     348                 :            :                 { "path",                    required_argument, NULL, 'p' },
     349                 :            :                 { "query",                   required_argument, NULL, 'q' },
     350                 :            :                 { "attribute-walk",          no_argument,       NULL, 'a' },
     351                 :            :                 { "cleanup-db",              no_argument,       NULL, 'c' },
     352                 :            :                 { "export-db",               no_argument,       NULL, 'e' },
     353                 :            :                 { "root",                    no_argument,       NULL, 'r' },
     354                 :            :                 { "device-id-of-file",       required_argument, NULL, 'd' },
     355                 :            :                 { "export",                  no_argument,       NULL, 'x' },
     356                 :            :                 { "export-prefix",           required_argument, NULL, 'P' },
     357                 :            :                 { "wait-for-initialization", optional_argument, NULL, 'w' },
     358                 :            :                 { "version",                 no_argument,       NULL, 'V' },
     359                 :            :                 { "help",                    no_argument,       NULL, 'h' },
     360                 :            :                 {}
     361                 :            :         };
     362                 :            : 
     363                 :          0 :         ActionType action = ACTION_QUERY;
     364                 :          0 :         QueryType query = QUERY_ALL;
     365                 :            : 
     366         [ #  # ]:          0 :         while ((c = getopt_long(argc, argv, "aced:n:p:q:rxP:w::Vh", options, NULL)) >= 0)
     367   [ #  #  #  #  :          0 :                 switch (c) {
          #  #  #  #  #  
             #  #  #  #  
                      # ]
     368                 :          0 :                 case 'n':
     369                 :            :                 case 'p': {
     370         [ #  # ]:          0 :                         const char *prefix = c == 'n' ? "/dev/" : "/sys/";
     371                 :            :                         char *path;
     372                 :            : 
     373         [ #  # ]:          0 :                         path = path_join(path_startswith(optarg, prefix) ? NULL : prefix, optarg);
     374         [ #  # ]:          0 :                         if (!path)
     375                 :          0 :                                 return log_oom();
     376                 :            : 
     377                 :          0 :                         r = strv_consume(&devices, path);
     378         [ #  # ]:          0 :                         if (r < 0)
     379                 :          0 :                                 return log_oom();
     380                 :          0 :                         break;
     381                 :            :                 }
     382                 :            : 
     383                 :          0 :                 case 'q':
     384                 :          0 :                         action = ACTION_QUERY;
     385   [ #  #  #  # ]:          0 :                         if (streq(optarg, "property") || streq(optarg, "env"))
     386                 :          0 :                                 query = QUERY_PROPERTY;
     387         [ #  # ]:          0 :                         else if (streq(optarg, "name"))
     388                 :          0 :                                 query = QUERY_NAME;
     389         [ #  # ]:          0 :                         else if (streq(optarg, "symlink"))
     390                 :          0 :                                 query = QUERY_SYMLINK;
     391         [ #  # ]:          0 :                         else if (streq(optarg, "path"))
     392                 :          0 :                                 query = QUERY_PATH;
     393         [ #  # ]:          0 :                         else if (streq(optarg, "all"))
     394                 :          0 :                                 query = QUERY_ALL;
     395                 :            :                         else
     396         [ #  # ]:          0 :                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "unknown query type");
     397                 :          0 :                         break;
     398                 :          0 :                 case 'r':
     399                 :          0 :                         arg_root = true;
     400                 :          0 :                         break;
     401                 :          0 :                 case 'd':
     402                 :          0 :                         action = ACTION_DEVICE_ID_FILE;
     403                 :          0 :                         r = free_and_strdup(&name, optarg);
     404         [ #  # ]:          0 :                         if (r < 0)
     405                 :          0 :                                 return log_oom();
     406                 :          0 :                         break;
     407                 :          0 :                 case 'a':
     408                 :          0 :                         action = ACTION_ATTRIBUTE_WALK;
     409                 :          0 :                         break;
     410                 :          0 :                 case 'e':
     411                 :          0 :                         return export_devices();
     412                 :          0 :                 case 'c':
     413                 :          0 :                         cleanup_db();
     414                 :          0 :                         return 0;
     415                 :          0 :                 case 'x':
     416                 :          0 :                         arg_export = true;
     417                 :          0 :                         break;
     418                 :          0 :                 case 'P':
     419                 :          0 :                         arg_export = true;
     420                 :          0 :                         arg_export_prefix = optarg;
     421                 :          0 :                         break;
     422                 :          0 :                 case 'w':
     423         [ #  # ]:          0 :                         if (optarg) {
     424                 :          0 :                                 r = parse_sec(optarg, &arg_wait_for_initialization_timeout);
     425         [ #  # ]:          0 :                                 if (r < 0)
     426         [ #  # ]:          0 :                                         return log_error_errno(r, "Failed to parse timeout value: %m");
     427                 :            :                         } else
     428                 :          0 :                                 arg_wait_for_initialization_timeout = USEC_INFINITY;
     429                 :          0 :                         break;
     430                 :          0 :                 case 'V':
     431                 :          0 :                         return print_version();
     432                 :          0 :                 case 'h':
     433                 :          0 :                         return help();
     434                 :          0 :                 case '?':
     435                 :          0 :                         return -EINVAL;
     436                 :          0 :                 default:
     437                 :          0 :                         assert_not_reached("Unknown option");
     438                 :            :                 }
     439                 :            : 
     440         [ #  # ]:          0 :         if (action == ACTION_DEVICE_ID_FILE) {
     441         [ #  # ]:          0 :                 if (argv[optind])
     442         [ #  # ]:          0 :                         return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     443                 :            :                                                "Positional arguments are not allowed with -d/--device-id-of-file.");
     444         [ #  # ]:          0 :                 assert(name);
     445                 :          0 :                 return stat_device(name, arg_export, arg_export_prefix);
     446                 :            :         }
     447                 :            : 
     448                 :          0 :         r = strv_extend_strv(&devices, argv + optind, false);
     449         [ #  # ]:          0 :         if (r < 0)
     450         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to build argument list: %m");
     451                 :            : 
     452         [ #  # ]:          0 :         if (strv_isempty(devices))
     453         [ #  # ]:          0 :                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     454                 :            :                                        "A device name or path is required");
     455   [ #  #  #  # ]:          0 :         if (action == ACTION_ATTRIBUTE_WALK && strv_length(devices) > 1)
     456         [ #  # ]:          0 :                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     457                 :            :                                        "Only one device may be specified with -a/--attribute-walk");
     458                 :            : 
     459                 :            :         char **p;
     460   [ #  #  #  # ]:          0 :         STRV_FOREACH(p, devices) {
     461         [ #  # ]:          0 :                 _cleanup_(sd_device_unrefp) sd_device *device = NULL;
     462                 :            : 
     463                 :          0 :                 r = find_device(*p, NULL, &device);
     464         [ #  # ]:          0 :                 if (r == -EINVAL)
     465         [ #  # ]:          0 :                         return log_error_errno(r, "Bad argument \"%s\", expected an absolute path in /dev/ or /sys or a unit name: %m", *p);
     466         [ #  # ]:          0 :                 if (r < 0)
     467         [ #  # ]:          0 :                         return log_error_errno(r, "Unknown device \"%s\": %m",  *p);
     468                 :            : 
     469         [ #  # ]:          0 :                 if (arg_wait_for_initialization_timeout > 0) {
     470                 :            :                         sd_device *d;
     471                 :            : 
     472                 :          0 :                         r = device_wait_for_initialization(device, NULL, arg_wait_for_initialization_timeout, &d);
     473         [ #  # ]:          0 :                         if (r < 0)
     474                 :          0 :                                 return r;
     475                 :            : 
     476                 :          0 :                         sd_device_unref(device);
     477                 :          0 :                         device = d;
     478                 :            :                 }
     479                 :            : 
     480         [ #  # ]:          0 :                 if (action == ACTION_QUERY)
     481                 :          0 :                         r = query_device(query, device);
     482         [ #  # ]:          0 :                 else if (action == ACTION_ATTRIBUTE_WALK)
     483                 :          0 :                         r = print_device_chain(device);
     484                 :            :                 else
     485                 :          0 :                         assert_not_reached("Unknown action");
     486         [ #  # ]:          0 :                 if (r < 0)
     487                 :          0 :                         return r;
     488                 :            :         }
     489                 :            : 
     490                 :          0 :         return 0;
     491                 :            : }

Generated by: LCOV version 1.14