LCOV - code coverage report
Current view: top level - udev - udev-builtin-path_id.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 0 391 0.0 %
Date: 2019-08-22 15:41:25 Functions: 0 17 0.0 %

          Line data    Source code
       1             : /* SPDX-License-Identifier: GPL-2.0+ */
       2             : /*
       3             :  * compose persistent device path
       4             :  *
       5             :  * Logic based on Hannes Reinecke's shell script.
       6             :  */
       7             : 
       8             : #include <ctype.h>
       9             : #include <errno.h>
      10             : #include <fcntl.h>
      11             : #include <getopt.h>
      12             : #include <stdarg.h>
      13             : #include <stdio.h>
      14             : #include <stdlib.h>
      15             : #include <string.h>
      16             : #include <unistd.h>
      17             : 
      18             : #include "alloc-util.h"
      19             : #include "dirent-util.h"
      20             : #include "fd-util.h"
      21             : #include "libudev-util.h"
      22             : #include "string-util.h"
      23             : #include "strv.h"
      24             : #include "sysexits.h"
      25             : #include "udev-builtin.h"
      26             : 
      27             : _printf_(2,3)
      28           0 : static void path_prepend(char **path, const char *fmt, ...) {
      29             :         va_list va;
      30           0 :         _cleanup_free_ char *pre = NULL;
      31             :         int r;
      32             : 
      33           0 :         va_start(va, fmt);
      34           0 :         r = vasprintf(&pre, fmt, va);
      35           0 :         va_end(va);
      36           0 :         if (r < 0) {
      37           0 :                 log_oom();
      38           0 :                 exit(EX_OSERR);
      39             :         }
      40             : 
      41           0 :         if (*path) {
      42             :                 char *new;
      43             : 
      44           0 :                 new = strjoin(pre, "-", *path);
      45           0 :                 if (!new) {
      46           0 :                         log_oom();
      47           0 :                         exit(EX_OSERR);
      48             :                 }
      49             : 
      50           0 :                 free_and_replace(*path, new);
      51             :         } else
      52           0 :                 *path = TAKE_PTR(pre);
      53           0 : }
      54             : 
      55             : /*
      56             : ** Linux only supports 32 bit luns.
      57             : ** See drivers/scsi/scsi_scan.c::scsilun_to_int() for more details.
      58             : */
      59           0 : static int format_lun_number(sd_device *dev, char **path) {
      60             :         const char *sysnum;
      61             :         unsigned long lun;
      62             :         int r;
      63             : 
      64           0 :         r = sd_device_get_sysnum(dev, &sysnum);
      65           0 :         if (r < 0)
      66           0 :                 return r;
      67           0 :         if (!sysnum)
      68           0 :                 return -ENOENT;
      69             : 
      70           0 :         lun = strtoul(sysnum, NULL, 10);
      71           0 :         if (lun < 256)
      72             :                 /* address method 0, peripheral device addressing with bus id of zero */
      73           0 :                 path_prepend(path, "lun-%lu", lun);
      74             :         else
      75             :                 /* handle all other lun addressing methods by using a variant of the original lun format */
      76           0 :                 path_prepend(path, "lun-0x%04lx%04lx00000000", lun & 0xffff, (lun >> 16) & 0xffff);
      77             : 
      78           0 :         return 0;
      79             : }
      80             : 
      81           0 : static sd_device *skip_subsystem(sd_device *dev, const char *subsys) {
      82             :         sd_device *parent;
      83             : 
      84           0 :         assert(dev);
      85           0 :         assert(subsys);
      86             : 
      87           0 :         for (parent = dev; ; ) {
      88             :                 const char *subsystem;
      89             : 
      90           0 :                 if (sd_device_get_subsystem(parent, &subsystem) < 0)
      91           0 :                         break;
      92             : 
      93           0 :                 if (!streq(subsystem, subsys))
      94           0 :                         break;
      95             : 
      96           0 :                 dev = parent;
      97           0 :                 if (sd_device_get_parent(dev, &parent) < 0)
      98           0 :                         break;
      99             :         }
     100             : 
     101           0 :         return dev;
     102             : }
     103             : 
     104           0 : static sd_device *handle_scsi_fibre_channel(sd_device *parent, char **path) {
     105             :         sd_device *targetdev;
     106           0 :         _cleanup_(sd_device_unrefp) sd_device *fcdev = NULL;
     107             :         const char *port, *sysname;
     108           0 :         _cleanup_free_ char *lun = NULL;
     109             : 
     110           0 :         assert(parent);
     111           0 :         assert(path);
     112             : 
     113           0 :         if (sd_device_get_parent_with_subsystem_devtype(parent, "scsi", "scsi_target", &targetdev) < 0)
     114           0 :                 return NULL;
     115           0 :         if (sd_device_get_sysname(targetdev, &sysname) < 0)
     116           0 :                 return NULL;
     117           0 :         if (sd_device_new_from_subsystem_sysname(&fcdev, "fc_transport", sysname) < 0)
     118           0 :                 return NULL;
     119           0 :         if (sd_device_get_sysattr_value(fcdev, "port_name", &port) < 0)
     120           0 :                 return NULL;
     121             : 
     122           0 :         format_lun_number(parent, &lun);
     123           0 :         path_prepend(path, "fc-%s-%s", port, lun);
     124           0 :         return parent;
     125             : }
     126             : 
     127           0 : static sd_device *handle_scsi_sas_wide_port(sd_device *parent, char **path) {
     128             :         sd_device *targetdev, *target_parent;
     129           0 :         _cleanup_(sd_device_unrefp) sd_device *sasdev = NULL;
     130             :         const char *sas_address, *sysname;
     131           0 :         _cleanup_free_ char *lun = NULL;
     132             : 
     133           0 :         assert(parent);
     134           0 :         assert(path);
     135             : 
     136           0 :         if (sd_device_get_parent_with_subsystem_devtype(parent, "scsi", "scsi_target", &targetdev) < 0)
     137           0 :                 return NULL;
     138           0 :         if (sd_device_get_parent(targetdev, &target_parent) < 0)
     139           0 :                 return NULL;
     140           0 :         if (sd_device_get_sysname(target_parent, &sysname) < 0)
     141           0 :                 return NULL;
     142           0 :         if (sd_device_new_from_subsystem_sysname(&sasdev, "sas_device", sysname) < 0)
     143           0 :                 return NULL;
     144           0 :         if (sd_device_get_sysattr_value(sasdev, "sas_address", &sas_address) < 0)
     145           0 :                 return NULL;
     146             : 
     147           0 :         format_lun_number(parent, &lun);
     148           0 :         path_prepend(path, "sas-%s-%s", sas_address, lun);
     149           0 :         return parent;
     150             : }
     151             : 
     152           0 : static sd_device *handle_scsi_sas(sd_device *parent, char **path) {
     153             :         sd_device *targetdev, *target_parent, *port, *expander;
     154           0 :         _cleanup_(sd_device_unrefp) sd_device *target_sasdev = NULL, *expander_sasdev = NULL, *port_sasdev = NULL;
     155           0 :         const char *sas_address = NULL;
     156             :         const char *phy_id;
     157             :         const char *phy_count, *sysname;
     158           0 :         _cleanup_free_ char *lun = NULL;
     159             : 
     160           0 :         assert(parent);
     161           0 :         assert(path);
     162             : 
     163           0 :         if (sd_device_get_parent_with_subsystem_devtype(parent, "scsi", "scsi_target", &targetdev) < 0)
     164           0 :                 return NULL;
     165           0 :         if (sd_device_get_parent(targetdev, &target_parent) < 0)
     166           0 :                 return NULL;
     167           0 :         if (sd_device_get_sysname(target_parent, &sysname) < 0)
     168           0 :                 return NULL;
     169             :         /* Get sas device */
     170           0 :         if (sd_device_new_from_subsystem_sysname(&target_sasdev, "sas_device", sysname) < 0)
     171           0 :                 return NULL;
     172             :         /* The next parent is sas port */
     173           0 :         if (sd_device_get_parent(target_parent, &port) < 0)
     174           0 :                 return NULL;
     175           0 :         if (sd_device_get_sysname(port, &sysname) < 0)
     176           0 :                 return NULL;
     177             :         /* Get port device */
     178           0 :         if (sd_device_new_from_subsystem_sysname(&port_sasdev, "sas_port", sysname) < 0)
     179           0 :                 return NULL;
     180           0 :         if (sd_device_get_sysattr_value(port_sasdev, "num_phys", &phy_count) < 0)
     181           0 :                 return NULL;
     182             : 
     183             :         /* Check if we are simple disk */
     184           0 :         if (strncmp(phy_count, "1", 2) != 0)
     185           0 :                 return handle_scsi_sas_wide_port(parent, path);
     186             : 
     187             :         /* Get connected phy */
     188           0 :         if (sd_device_get_sysattr_value(target_sasdev, "phy_identifier", &phy_id) < 0)
     189           0 :                 return NULL;
     190             : 
     191             :         /* The port's parent is either hba or expander */
     192           0 :         if (sd_device_get_parent(port, &expander) < 0)
     193           0 :                 return NULL;
     194             : 
     195           0 :         if (sd_device_get_sysname(expander, &sysname) < 0)
     196           0 :                 return NULL;
     197             :         /* Get expander device */
     198           0 :         if (sd_device_new_from_subsystem_sysname(&expander_sasdev, "sas_device", sysname) >= 0) {
     199             :                 /* Get expander's address */
     200           0 :                 if (sd_device_get_sysattr_value(expander_sasdev, "sas_address", &sas_address) < 0)
     201           0 :                         return NULL;
     202             :         }
     203             : 
     204           0 :         format_lun_number(parent, &lun);
     205           0 :         if (sas_address)
     206           0 :                  path_prepend(path, "sas-exp%s-phy%s-%s", sas_address, phy_id, lun);
     207             :         else
     208           0 :                  path_prepend(path, "sas-phy%s-%s", phy_id, lun);
     209             : 
     210           0 :         return parent;
     211             : }
     212             : 
     213           0 : static sd_device *handle_scsi_iscsi(sd_device *parent, char **path) {
     214             :         sd_device *transportdev;
     215           0 :         _cleanup_(sd_device_unrefp) sd_device *sessiondev = NULL, *conndev = NULL;
     216             :         const char *target, *connname, *addr, *port;
     217           0 :         _cleanup_free_ char *lun = NULL;
     218             :         const char *sysname, *sysnum;
     219             : 
     220           0 :         assert(parent);
     221           0 :         assert(path);
     222             : 
     223             :         /* find iscsi session */
     224           0 :         for (transportdev = parent; ; ) {
     225             : 
     226           0 :                 if (sd_device_get_parent(transportdev, &transportdev) < 0)
     227           0 :                         return NULL;
     228           0 :                 if (sd_device_get_sysname(transportdev, &sysname) < 0)
     229           0 :                         return NULL;
     230           0 :                 if (startswith(sysname, "session"))
     231           0 :                         break;
     232             :         }
     233             : 
     234             :         /* find iscsi session device */
     235           0 :         if (sd_device_new_from_subsystem_sysname(&sessiondev, "iscsi_session", sysname) < 0)
     236           0 :                 return NULL;
     237             : 
     238           0 :         if (sd_device_get_sysattr_value(sessiondev, "targetname", &target) < 0)
     239           0 :                 return NULL;
     240             : 
     241           0 :         if (sd_device_get_sysnum(transportdev, &sysnum) < 0 || !sysnum)
     242           0 :                 return NULL;
     243           0 :         connname = strjoina("connection", sysnum, ":0");
     244           0 :         if (sd_device_new_from_subsystem_sysname(&conndev, "iscsi_connection", connname) < 0)
     245           0 :                 return NULL;
     246             : 
     247           0 :         if (sd_device_get_sysattr_value(conndev, "persistent_address", &addr) < 0)
     248           0 :                 return NULL;
     249           0 :         if (sd_device_get_sysattr_value(conndev, "persistent_port", &port) < 0)
     250           0 :                 return NULL;
     251             : 
     252           0 :         format_lun_number(parent, &lun);
     253           0 :         path_prepend(path, "ip-%s:%s-iscsi-%s-%s", addr, port, target, lun);
     254           0 :         return parent;
     255             : }
     256             : 
     257           0 : static sd_device *handle_scsi_ata(sd_device *parent, char **path) {
     258             :         sd_device *targetdev, *target_parent;
     259           0 :         _cleanup_(sd_device_unrefp) sd_device *atadev = NULL;
     260             :         const char *port_no, *sysname;
     261             : 
     262           0 :         assert(parent);
     263           0 :         assert(path);
     264             : 
     265           0 :         if (sd_device_get_parent_with_subsystem_devtype(parent, "scsi", "scsi_host", &targetdev) < 0)
     266           0 :                 return NULL;
     267             : 
     268           0 :         if (sd_device_get_parent(targetdev, &target_parent) < 0)
     269           0 :                 return NULL;
     270             : 
     271           0 :         if (sd_device_get_sysname(target_parent, &sysname) < 0)
     272           0 :                 return NULL;
     273           0 :         if (sd_device_new_from_subsystem_sysname(&atadev, "ata_port", sysname) < 0)
     274           0 :                 return NULL;
     275             : 
     276           0 :         if (sd_device_get_sysattr_value(atadev, "port_no", &port_no) < 0)
     277           0 :                 return NULL;
     278             : 
     279           0 :         path_prepend(path, "ata-%s", port_no);
     280           0 :         return parent;
     281             : }
     282             : 
     283           0 : static sd_device *handle_scsi_default(sd_device *parent, char **path) {
     284             :         sd_device *hostdev;
     285             :         int host, bus, target, lun;
     286             :         const char *name, *base, *pos;
     287           0 :         _cleanup_closedir_ DIR *dir = NULL;
     288             :         struct dirent *dent;
     289           0 :         int basenum = -1;
     290             : 
     291           0 :         assert(parent);
     292           0 :         assert(path);
     293             : 
     294           0 :         if (sd_device_get_parent_with_subsystem_devtype(parent, "scsi", "scsi_host", &hostdev) < 0)
     295           0 :                 return NULL;
     296             : 
     297           0 :         if (sd_device_get_sysname(parent, &name) < 0)
     298           0 :                 return NULL;
     299           0 :         if (sscanf(name, "%d:%d:%d:%d", &host, &bus, &target, &lun) != 4)
     300           0 :                 return NULL;
     301             : 
     302             :         /*
     303             :          * Rebase host offset to get the local relative number
     304             :          *
     305             :          * Note: This is by definition racy, unreliable and too simple.
     306             :          * Please do not copy this model anywhere. It's just a left-over
     307             :          * from the time we had no idea how things should look like in
     308             :          * the end.
     309             :          *
     310             :          * Making assumptions about a global in-kernel counter and use
     311             :          * that to calculate a local offset is a very broken concept. It
     312             :          * can only work as long as things are in strict order.
     313             :          *
     314             :          * The kernel needs to export the instance/port number of a
     315             :          * controller directly, without the need for rebase magic like
     316             :          * this. Manual driver unbind/bind, parallel hotplug/unplug will
     317             :          * get into the way of this "I hope it works" logic.
     318             :          */
     319             : 
     320           0 :         if (sd_device_get_syspath(hostdev, &base) < 0)
     321           0 :                 return NULL;
     322           0 :         pos = strrchr(base, '/');
     323           0 :         if (!pos)
     324           0 :                 return NULL;
     325             : 
     326           0 :         base = strndupa(base, pos - base);
     327           0 :         dir = opendir(base);
     328           0 :         if (!dir)
     329           0 :                 return NULL;
     330             : 
     331           0 :         FOREACH_DIRENT_ALL(dent, dir, break) {
     332             :                 char *rest;
     333             :                 int i;
     334             : 
     335           0 :                 if (dent->d_name[0] == '.')
     336           0 :                         continue;
     337           0 :                 if (!IN_SET(dent->d_type, DT_DIR, DT_LNK))
     338           0 :                         continue;
     339           0 :                 if (!startswith(dent->d_name, "host"))
     340           0 :                         continue;
     341           0 :                 i = strtoul(&dent->d_name[4], &rest, 10);
     342           0 :                 if (rest[0] != '\0')
     343           0 :                         continue;
     344             :                 /*
     345             :                  * find the smallest number; the host really needs to export its
     346             :                  * own instance number per parent device; relying on the global host
     347             :                  * enumeration and plainly rebasing the numbers sounds unreliable
     348             :                  */
     349           0 :                 if (basenum == -1 || i < basenum)
     350           0 :                         basenum = i;
     351             :         }
     352           0 :         if (basenum == -1)
     353           0 :                 return hostdev;
     354           0 :         host -= basenum;
     355             : 
     356           0 :         path_prepend(path, "scsi-%u:%u:%u:%u", host, bus, target, lun);
     357           0 :         return hostdev;
     358             : }
     359             : 
     360           0 : static sd_device *handle_scsi_hyperv(sd_device *parent, char **path, size_t guid_str_len) {
     361             :         sd_device *hostdev;
     362             :         sd_device *vmbusdev;
     363             :         const char *guid_str;
     364           0 :         _cleanup_free_ char *lun = NULL;
     365             :         char guid[39];
     366             :         size_t i, k;
     367             : 
     368           0 :         assert(parent);
     369           0 :         assert(path);
     370           0 :         assert(guid_str_len < sizeof(guid));
     371             : 
     372           0 :         if (sd_device_get_parent_with_subsystem_devtype(parent, "scsi", "scsi_host", &hostdev) < 0)
     373           0 :                 return NULL;
     374             : 
     375           0 :         if (sd_device_get_parent(hostdev, &vmbusdev) < 0)
     376           0 :                 return NULL;
     377             : 
     378           0 :         if (sd_device_get_sysattr_value(vmbusdev, "device_id", &guid_str) < 0)
     379           0 :                 return NULL;
     380             : 
     381           0 :         if (strlen(guid_str) < guid_str_len || guid_str[0] != '{' || guid_str[guid_str_len-1] != '}')
     382           0 :                 return NULL;
     383             : 
     384           0 :         for (i = 1, k = 0; i < guid_str_len-1; i++) {
     385           0 :                 if (guid_str[i] == '-')
     386           0 :                         continue;
     387           0 :                 guid[k++] = guid_str[i];
     388             :         }
     389           0 :         guid[k] = '\0';
     390             : 
     391           0 :         format_lun_number(parent, &lun);
     392           0 :         path_prepend(path, "vmbus-%s-%s", guid, lun);
     393           0 :         return parent;
     394             : }
     395             : 
     396           0 : static sd_device *handle_scsi(sd_device *parent, char **path, bool *supported_parent) {
     397             :         const char *devtype, *id, *name;
     398             : 
     399           0 :         if (sd_device_get_devtype(parent, &devtype) < 0 ||
     400           0 :             !streq(devtype, "scsi_device"))
     401           0 :                 return parent;
     402             : 
     403             :         /* firewire */
     404           0 :         if (sd_device_get_sysattr_value(parent, "ieee1394_id", &id) >= 0) {
     405           0 :                 path_prepend(path, "ieee1394-0x%s", id);
     406           0 :                 *supported_parent = true;
     407           0 :                 return skip_subsystem(parent, "scsi");
     408             :         }
     409             : 
     410             :         /* scsi sysfs does not have a "subsystem" for the transport */
     411           0 :         if (sd_device_get_syspath(parent, &name) < 0)
     412           0 :                 return NULL;
     413             : 
     414           0 :         if (strstr(name, "/rport-")) {
     415           0 :                 *supported_parent = true;
     416           0 :                 return handle_scsi_fibre_channel(parent, path);
     417             :         }
     418             : 
     419           0 :         if (strstr(name, "/end_device-")) {
     420           0 :                 *supported_parent = true;
     421           0 :                 return handle_scsi_sas(parent, path);
     422             :         }
     423             : 
     424           0 :         if (strstr(name, "/session")) {
     425           0 :                 *supported_parent = true;
     426           0 :                 return handle_scsi_iscsi(parent, path);
     427             :         }
     428             : 
     429           0 :         if (strstr(name, "/ata"))
     430           0 :                 return handle_scsi_ata(parent, path);
     431             : 
     432           0 :         if (strstr(name, "/vmbus_"))
     433           0 :                 return handle_scsi_hyperv(parent, path, 37);
     434           0 :         else if (strstr(name, "/VMBUS"))
     435           0 :                 return handle_scsi_hyperv(parent, path, 38);
     436             : 
     437           0 :         return handle_scsi_default(parent, path);
     438             : }
     439             : 
     440           0 : static sd_device *handle_cciss(sd_device *parent, char **path) {
     441             :         const char *str;
     442             :         unsigned controller, disk;
     443             : 
     444           0 :         if (sd_device_get_sysname(parent, &str) < 0)
     445           0 :                 return NULL;
     446           0 :         if (sscanf(str, "c%ud%u%*s", &controller, &disk) != 2)
     447           0 :                 return NULL;
     448             : 
     449           0 :         path_prepend(path, "cciss-disk%u", disk);
     450           0 :         return skip_subsystem(parent, "cciss");
     451             : }
     452             : 
     453           0 : static void handle_scsi_tape(sd_device *dev, char **path) {
     454             :         const char *name;
     455             : 
     456             :         /* must be the last device in the syspath */
     457           0 :         if (*path)
     458           0 :                 return;
     459             : 
     460           0 :         if (sd_device_get_sysname(dev, &name) < 0)
     461           0 :                 return;
     462             : 
     463           0 :         if (startswith(name, "nst") && strchr("lma", name[3]))
     464           0 :                 path_prepend(path, "nst%c", name[3]);
     465           0 :         else if (startswith(name, "st") && strchr("lma", name[2]))
     466           0 :                 path_prepend(path, "st%c", name[2]);
     467             : }
     468             : 
     469           0 : static sd_device *handle_usb(sd_device *parent, char **path) {
     470             :         const char *devtype, *str, *port;
     471             : 
     472           0 :         if (sd_device_get_devtype(parent, &devtype) < 0)
     473           0 :                 return parent;
     474           0 :         if (!STR_IN_SET(devtype, "usb_interface", "usb_device"))
     475           0 :                 return parent;
     476             : 
     477           0 :         if (sd_device_get_sysname(parent, &str) < 0)
     478           0 :                 return parent;
     479           0 :         port = strchr(str, '-');
     480           0 :         if (!port)
     481           0 :                 return parent;
     482           0 :         port++;
     483             : 
     484           0 :         path_prepend(path, "usb-0:%s", port);
     485           0 :         return skip_subsystem(parent, "usb");
     486             : }
     487             : 
     488           0 : static sd_device *handle_bcma(sd_device *parent, char **path) {
     489             :         const char *sysname;
     490             :         unsigned core;
     491             : 
     492           0 :         if (sd_device_get_sysname(parent, &sysname) < 0)
     493           0 :                 return NULL;
     494           0 :         if (sscanf(sysname, "bcma%*u:%u", &core) != 1)
     495           0 :                 return NULL;
     496             : 
     497           0 :         path_prepend(path, "bcma-%u", core);
     498           0 :         return parent;
     499             : }
     500             : 
     501             : /* Handle devices of AP bus in System z platform. */
     502           0 : static sd_device *handle_ap(sd_device *parent, char **path) {
     503             :         const char *type, *func;
     504             : 
     505           0 :         assert(parent);
     506           0 :         assert(path);
     507             : 
     508           0 :         if (sd_device_get_sysattr_value(parent, "type", &type) >= 0 &&
     509           0 :             sd_device_get_sysattr_value(parent, "ap_functions", &func) >= 0)
     510           0 :                 path_prepend(path, "ap-%s-%s", type, func);
     511             :         else {
     512             :                 const char *sysname;
     513             : 
     514           0 :                 if (sd_device_get_sysname(parent, &sysname) >= 0)
     515           0 :                         path_prepend(path, "ap-%s", sysname);
     516             :         }
     517             : 
     518           0 :         return skip_subsystem(parent, "ap");
     519             : }
     520             : 
     521           0 : static int builtin_path_id(sd_device *dev, int argc, char *argv[], bool test) {
     522             :         sd_device *parent;
     523           0 :         _cleanup_free_ char *path = NULL;
     524           0 :         bool supported_transport = false;
     525           0 :         bool supported_parent = false;
     526             :         const char *subsystem;
     527             : 
     528           0 :         assert(dev);
     529             : 
     530             :         /* walk up the chain of devices and compose path */
     531           0 :         parent = dev;
     532           0 :         while (parent) {
     533             :                 const char *subsys, *sysname;
     534             : 
     535           0 :                 if (sd_device_get_subsystem(parent, &subsys) < 0 ||
     536           0 :                     sd_device_get_sysname(parent, &sysname) < 0) {
     537             :                         ;
     538           0 :                 } else if (streq(subsys, "scsi_tape")) {
     539           0 :                         handle_scsi_tape(parent, &path);
     540           0 :                 } else if (streq(subsys, "scsi")) {
     541           0 :                         parent = handle_scsi(parent, &path, &supported_parent);
     542           0 :                         supported_transport = true;
     543           0 :                 } else if (streq(subsys, "cciss")) {
     544           0 :                         parent = handle_cciss(parent, &path);
     545           0 :                         supported_transport = true;
     546           0 :                 } else if (streq(subsys, "usb")) {
     547           0 :                         parent = handle_usb(parent, &path);
     548           0 :                         supported_transport = true;
     549           0 :                 } else if (streq(subsys, "bcma")) {
     550           0 :                         parent = handle_bcma(parent, &path);
     551           0 :                         supported_transport = true;
     552           0 :                 } else if (streq(subsys, "serio")) {
     553             :                         const char *sysnum;
     554             : 
     555           0 :                         if (sd_device_get_sysnum(parent, &sysnum) >= 0 && sysnum) {
     556           0 :                                 path_prepend(&path, "serio-%s", sysnum);
     557           0 :                                 parent = skip_subsystem(parent, "serio");
     558             :                         }
     559           0 :                 } else if (streq(subsys, "pci")) {
     560           0 :                         path_prepend(&path, "pci-%s", sysname);
     561           0 :                         parent = skip_subsystem(parent, "pci");
     562           0 :                         supported_parent = true;
     563           0 :                 } else if (streq(subsys, "platform")) {
     564           0 :                         path_prepend(&path, "platform-%s", sysname);
     565           0 :                         parent = skip_subsystem(parent, "platform");
     566           0 :                         supported_transport = true;
     567           0 :                         supported_parent = true;
     568           0 :                 } else if (streq(subsys, "acpi")) {
     569           0 :                         path_prepend(&path, "acpi-%s", sysname);
     570           0 :                         parent = skip_subsystem(parent, "acpi");
     571           0 :                         supported_parent = true;
     572           0 :                 } else if (streq(subsys, "xen")) {
     573           0 :                         path_prepend(&path, "xen-%s", sysname);
     574           0 :                         parent = skip_subsystem(parent, "xen");
     575           0 :                         supported_parent = true;
     576           0 :                 } else if (streq(subsys, "virtio")) {
     577           0 :                         parent = skip_subsystem(parent, "virtio");
     578           0 :                         supported_transport = true;
     579           0 :                 } else if (streq(subsys, "scm")) {
     580           0 :                         path_prepend(&path, "scm-%s", sysname);
     581           0 :                         parent = skip_subsystem(parent, "scm");
     582           0 :                         supported_transport = true;
     583           0 :                         supported_parent = true;
     584           0 :                 } else if (streq(subsys, "ccw")) {
     585           0 :                         path_prepend(&path, "ccw-%s", sysname);
     586           0 :                         parent = skip_subsystem(parent, "ccw");
     587           0 :                         supported_transport = true;
     588           0 :                         supported_parent = true;
     589           0 :                 } else if (streq(subsys, "ccwgroup")) {
     590           0 :                         path_prepend(&path, "ccwgroup-%s", sysname);
     591           0 :                         parent = skip_subsystem(parent, "ccwgroup");
     592           0 :                         supported_transport = true;
     593           0 :                         supported_parent = true;
     594           0 :                 } else if (streq(subsys, "ap")) {
     595           0 :                         parent = handle_ap(parent, &path);
     596           0 :                         supported_transport = true;
     597           0 :                         supported_parent = true;
     598           0 :                 } else if (streq(subsys, "iucv")) {
     599           0 :                         path_prepend(&path, "iucv-%s", sysname);
     600           0 :                         parent = skip_subsystem(parent, "iucv");
     601           0 :                         supported_transport = true;
     602           0 :                         supported_parent = true;
     603           0 :                 } else if (streq(subsys, "nvme")) {
     604             :                         const char *nsid;
     605             : 
     606           0 :                         if (sd_device_get_sysattr_value(dev, "nsid", &nsid) >= 0) {
     607           0 :                                 path_prepend(&path, "nvme-%s", nsid);
     608           0 :                                 parent = skip_subsystem(parent, "nvme");
     609           0 :                                 supported_parent = true;
     610           0 :                                 supported_transport = true;
     611             :                         }
     612             :                 }
     613             : 
     614           0 :                 if (!parent)
     615           0 :                         break;
     616           0 :                 if (sd_device_get_parent(parent, &parent) < 0)
     617           0 :                         break;
     618             :         }
     619             : 
     620           0 :         if (!path)
     621           0 :                 return -ENOENT;
     622             : 
     623             :         /*
     624             :          * Do not return devices with an unknown parent device type. They
     625             :          * might produce conflicting IDs if the parent does not provide a
     626             :          * unique and predictable name.
     627             :          */
     628           0 :         if (!supported_parent)
     629           0 :                 return -ENOENT;
     630             : 
     631             :         /*
     632             :          * Do not return block devices without a well-known transport. Some
     633             :          * devices do not expose their buses and do not provide a unique
     634             :          * and predictable name that way.
     635             :          */
     636           0 :         if (sd_device_get_subsystem(dev, &subsystem) >= 0 &&
     637           0 :             streq(subsystem, "block") &&
     638           0 :             !supported_transport)
     639           0 :                 return -ENOENT;
     640             : 
     641             :         {
     642             :                 char tag[UTIL_NAME_SIZE];
     643             :                 size_t i;
     644             :                 const char *p;
     645             : 
     646             :                 /* compose valid udev tag name */
     647           0 :                 for (p = path, i = 0; *p; p++) {
     648           0 :                         if ((*p >= '0' && *p <= '9') ||
     649           0 :                             (*p >= 'A' && *p <= 'Z') ||
     650           0 :                             (*p >= 'a' && *p <= 'z') ||
     651           0 :                             *p == '-') {
     652           0 :                                 tag[i++] = *p;
     653           0 :                                 continue;
     654             :                         }
     655             : 
     656             :                         /* skip all leading '_' */
     657           0 :                         if (i == 0)
     658           0 :                                 continue;
     659             : 
     660             :                         /* avoid second '_' */
     661           0 :                         if (tag[i-1] == '_')
     662           0 :                                 continue;
     663             : 
     664           0 :                         tag[i++] = '_';
     665             :                 }
     666             :                 /* strip trailing '_' */
     667           0 :                 while (i > 0 && tag[i-1] == '_')
     668           0 :                         i--;
     669           0 :                 tag[i] = '\0';
     670             : 
     671           0 :                 udev_builtin_add_property(dev, test, "ID_PATH", path);
     672           0 :                 udev_builtin_add_property(dev, test, "ID_PATH_TAG", tag);
     673             :         }
     674             : 
     675           0 :         return 0;
     676             : }
     677             : 
     678             : const UdevBuiltin udev_builtin_path_id = {
     679             :         .name = "path_id",
     680             :         .cmd = builtin_path_id,
     681             :         .help = "Compose persistent device path",
     682             :         .run_once = true,
     683             : };

Generated by: LCOV version 1.14