home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / boot / i386 / rescue / lib / udev / path_id < prev    next >
Text File  |  2006-11-29  |  12KB  |  563 lines

  1. #!/bin/sh
  2.  
  3. # provide the shortest possible unique hardware path to a device
  4. # for the Linux Persistent Device Naming scheme
  5. #
  6. # Copyright (C) 2005-2006 SUSE Linux Products GmbH
  7. # Author:
  8. #    Hannes Reinecke <hare@suse.de>
  9. #
  10. #    This program is free software; you can redistribute it and/or modify it
  11. #    under the terms of the GNU General Public License as published by the
  12. #    Free Software Foundation version 2 of the License.
  13. #
  14. # to be called from a udev rule to return the name for a symlink
  15. #    DEVPATH=<devpath>; path_id
  16. #    path_id <devpath>
  17.  
  18. # examples for all block devices on a system:
  19. #    for i in `find /sys/class/block`; do DEVPATH="`echo $i | sed -e 's@^/sys\|/dev@@g'`"; path_id; done
  20.  
  21. SYSFS=/sys
  22. RESULT=1
  23. TYPE=
  24. OPWD="`pwd`"
  25. full_sysfs_path=
  26. full_sysfs_device_path=
  27.  
  28. if [ -z "$DEVPATH" -a -z "$1" ] ; then
  29.     exit 1
  30. fi
  31.  
  32. if [ -z "$DEVPATH" ] ; then
  33.     case "$1" in
  34.         $SYSFS/*)
  35.             DEVPATH="${1#$SYSFS}"
  36.             ;;
  37.         *)
  38.             DEVPATH=$1
  39.             ;;
  40.     esac
  41. fi
  42.  
  43. if [ ! -e $SYSFS$DEVPATH/dev ] ; then
  44.     exit 1
  45. fi
  46.  
  47. case "$DEVPATH" in
  48.     /devices/*)
  49.         cd "$SYSFS$DEVPATH/subsystem";
  50.         TYPE="`pwd -P`"
  51.         cd "$OPWD"
  52.         TYPE="${TYPE##*/}"
  53.         ;;
  54.     /class/*)
  55.         TYPE="${DEVPATH#/class/}"
  56.         TYPE="${TYPE%%/*}"
  57.         ;;
  58.     /block/*)
  59.         TYPE=block
  60.         ;;
  61.     *)
  62.         exit 1
  63.         ;;
  64. esac
  65.  
  66. get_port_offset () {
  67.     local type offset port
  68.     type=$1
  69.     offset=$2
  70.     for i in $type[0-9]* ; do
  71.         : i $i
  72.         port="${i#$type}"
  73.         if [ "$port" -lt "$offset" ] ; then offset=$port ; fi
  74.     done
  75.     echo $offset
  76. }
  77.  
  78. handle_pci () {
  79.     local DEV=$1
  80.     cd -P $1
  81.     DEV=${PWD}
  82.     pci_id=${DEV##*/}
  83.     host_dev_path=$DEV
  84.     while [ ! -z "$host_dev_path" ] ; do
  85.         case "$host_dev_path" in
  86.             */pci[0-9]*)
  87.                 host_dev_path=${host_dev_path%/*}
  88.                 ;;
  89.             *)
  90.                 break
  91.                 ;;
  92.         esac
  93.     done
  94.     d="pci-$pci_id-$d"
  95.     D="$host_dev_path"
  96.     RESULT=0
  97. }
  98.  
  99. handle_platform () {
  100.     local DEV=$1
  101.     cd -P $1
  102.     DEV=${PWD}
  103.     platform_id=${DEV##*/}
  104.     host_dev_path=$DEV
  105.     while [ ! -z "$host_dev_path" ] ; do
  106.         case "$host_dev_path" in
  107.             */platform*)
  108.                 host_dev_path=${host_dev_path%/*}
  109.                 ;;
  110.             *)
  111.                 break
  112.                 ;;
  113.         esac
  114.     done
  115.     if [ "$d" ]; then
  116.         d="platform-$platform_id-$d"
  117.     else
  118.         d="platform-$platform_id"
  119.     fi
  120.     D="$host_dev_path"
  121.     RESULT=0
  122. }
  123.  
  124. handle_serio () {
  125.     local DEV=$1
  126.     cd -P $1
  127.     DEV=${PWD}
  128.     serio_id=${DEV##*/serio}
  129.     host_dev_path=$DEV
  130.     while [ ! -z "$host_dev_path" ] ; do
  131.         case "$host_dev_path" in
  132.             */serio*)
  133.                 host_dev_path=${host_dev_path%/*}
  134.                 ;;
  135.             *)
  136.                 break
  137.                 ;;
  138.         esac
  139.     done
  140.     if [ "$d" ]; then
  141.         d="serio-$serio_id-$d"
  142.     else
  143.         d="serio-$serio_id"
  144.     fi
  145.     D="$host_dev_path"
  146.     RESULT=0
  147. }
  148.  
  149. handle_ide () {
  150.     : handle_ide $*
  151.     local DEV=$1
  152.     local port idedev idecontroller
  153.     # IDE
  154.     : DEV $DEV
  155.     port=${DEV##*/}
  156.     idedev=${DEV%/*}
  157.     idecontroller=${idedev%/*}
  158.     # port info if the controller has more than one interface
  159.     port="${port#ide}"
  160.     : port $port d $d
  161.     : idedev $idedev kernel_port $port
  162.     case "${port#*.}" in
  163.         0)
  164.             channel=0
  165.             ;;
  166.         1)
  167.             channel=1
  168.             ;;
  169.         *)
  170.             echo "Error: $idedev is neither master or slave" >&2
  171.             ;;
  172.     esac
  173.     cd $idecontroller
  174.     offset="`get_port_offset ide ${port%.*}`"
  175.     cd "$OPWD"
  176.     :  port offset $offset
  177.     port=$((${port%.*} - $offset))
  178.     if [ "$d" ] ; then
  179.         d="ide-${port}:$channel-$d"
  180.     else
  181.         d="ide-${port}:$channel"
  182.     fi
  183.     D=$idecontroller
  184.     RESULT=0
  185. }
  186.  
  187. handle_scsi () {
  188.     : handle_scsi $*
  189.     local DEV=$1
  190.     local cil controller_port controller_dev
  191.     # SCSI device
  192.     cil="${DEV##*/}"
  193.     cil="${cil#*:}"
  194.     target_dev=${DEV%/*}
  195.     target_id=${target_dev##*/target}
  196.     cd "$target_dev"
  197.     target_num=0
  198.     for tid in ${target_id}* ; do
  199.         target_num=$(( $target_num + 1 ))
  200.     done
  201.     controller_port=${target_dev%/*}
  202.     controller_dev="${controller_port%/*}"
  203.     : controller_dev $controller_dev
  204.     : controller_port $controller_port
  205.     # a host controller may have more than one interface/port
  206.     controller_port="${controller_port##*/host}"
  207.     #
  208.     cd "$controller_dev"
  209.     controller_offset=$(get_port_offset host $controller_port)
  210.     cd "$OPWD"
  211.     controller_port=$(( $controller_port - $controller_offset))
  212.     scsi_id="scsi-${controller_port}:${cil}"
  213.     if [ "$d" ] ; then
  214.         d="${scsi_id}-$d"
  215.     else
  216.         d="$scsi_id"
  217.     fi
  218.     D="$controller_dev"
  219.     RESULT=0
  220. }
  221.  
  222. handle_firewire () {
  223.     : handle_firewire $*
  224.     local DEV=$1
  225.     if [ -f "$D/ieee1394_id" ] ; then
  226.         read ieee1394_id < $D/ieee1394_id
  227.     fi
  228.     if [ -z "$ieee1394_id" ] ; then
  229.         : no IEEE1394 ID
  230.         RESULT=1
  231.         return
  232.     fi
  233.     fw_host_dev=${DEV%/fw-host*}
  234.     # IEEE1394 devices are always endpoints
  235.     d="ieee1394-0x$ieee1394_id"
  236.     D="$fw_host_dev"
  237.     RESULT=0
  238. }
  239.  
  240. handle_fc () {
  241.     : handle_fc $*
  242.     local DEV=$1
  243.     local cil controller_port controller_dev
  244.     # SCSI-FC device
  245.     fc_tgt_hcil="${DEV##*/}"
  246.     fc_tgt_lun="${fc_tgt_hcil##*:}"
  247.     fc_tgt_path="${DEV%/*}"
  248.     fc_tgt_num="${fc_tgt_path##*/}"
  249.     fc_tgt_dev="${fc_tgt_path}/fc_transport:${fc_tgt_num}"
  250.     if [ -e "$fc_tgt_dev/port_name" ]; then
  251.         read wwpn < $fc_tgt_dev/port_name
  252.     fi
  253.     if [ -z "$wwpn" ] ; then
  254.         : no WWPN
  255.         D=
  256.         RESULT=1
  257.         return
  258.     fi
  259.     # Linux currently knows about 32bit luns
  260.     tmp_lun3=$(printf "%04x" $(($fc_tgt_lun & 0xFFFF)))
  261.     tmp_lun2=$(printf "%04x" $(( ($fc_tgt_lun >> 16) & 0xFFFF)))
  262.     tmp_lun1="0000"
  263.     tmp_lun0="0000"
  264.     if (($fc_tgt_lun == 0)) ; then
  265.         lun="0x0000000000000000"
  266.     else
  267.         lun="0x${tmp_lun3}${tmp_lun2}${tmp_lun1}${tmp_lun0}"
  268.     fi
  269.     controller_dev="${fc_tgt_path%/host[0-9]*}"
  270.     # FC devices are always endpoints
  271.     d="fc-${wwpn}:${lun}"
  272.     D="$controller_dev"
  273.     RESULT=0
  274. }
  275.  
  276. handle_sas () {
  277.     : handle_sas $*
  278.     local DEV=$1
  279.     local cil adapter controller_dev
  280.     # SAS device
  281.     sas_host_path="${DEV%%/port*}"
  282.     sas_phy_path="${DEV#*/host*/}"
  283.     sas_phy_path="${sas_phy_path%%/target*}"
  284.     sas_phy_id="${sas_phy_path%%/*}"
  285.     sas_phy_id="${sas_phy_id##*port-}"
  286.     sas_port_id="${sas_phy_path%%/end_device*}"
  287.     sas_port_id="${sas_port_id##*port-}"
  288.     sas_end_id="${sas_phy_path##*end_device-}"
  289.     sas_phy_dev="/sys/class/sas_phy/phy-${sas_phy_id}"
  290.     if [ -e "$sas_phy_dev/sas_address" ]; then
  291.         read phy_address < $sas_phy_dev/sas_address
  292.         read phy_id < $sas_phy_dev/phy_identifier
  293.     fi
  294.     if [ -z "$phy_address" ] ; then
  295.         : no initiator address
  296.         D=
  297.         RESULT=1
  298.         return
  299.     fi
  300.     sas_port_dev="/sys/class/sas_port/port-${sas_port_id}"
  301.     if [ -e "$sas_port_dev/num_phys" ] ; then
  302.         read phy_port < $sas_port_dev/num_phys
  303.     fi
  304.     if [ -z "$phy_port" ] ; then
  305.         : no initiator address
  306.         D=
  307.         RESULT=1
  308.         return
  309.     fi
  310.     sas_phy_address="$phy_address:$phy_port:$phy_id"
  311.     sas_end_dev="/sys/class/sas_device/end_device-${sas_end_id}"
  312.     if [ -e "$sas_end_dev/sas_address" ]; then
  313.         read end_address < $sas_end_dev/sas_address
  314.         read end_id < $sas_end_dev/phy_identifier
  315.     fi
  316.     if [ -z "$end_address" ] ; then
  317.         : no initiator address
  318.         D=
  319.         RESULT=1
  320.         return
  321.     fi
  322.     sas_end_address="$end_address:$end_id"
  323.     controller_dev="${sas_host_path%/host[0-9]*}"
  324.     # SAS devices are always endpoints
  325.     d="sas-${sas_phy_address}-${sas_end_address}"
  326.     D="$controller_dev"
  327.     RESULT=0
  328. }
  329.  
  330. handle_iscsi() {
  331.     local DEV=$1
  332.     local iscsi_session_dir
  333.     local iscsi_session iscsi_session_path
  334.     local iscsi_connection iscsi_connection_path
  335.     # iSCSI device
  336.     iscsi_session_dir="${DEV%%/target*}"
  337.     iscsi_session="${iscsi_session_dir##*/}"
  338.     iscsi_session_path=/sys/class/iscsi_session/${iscsi_session}
  339.     if [ ! -d "$iscsi_session_path" ] ; then
  340.         : no iSCSI session path
  341.         RESULT=1
  342.         return
  343.     fi
  344.     # Currently we're not doing MC/S
  345.     for conn in ${iscsi_session_dir}/connection* ; do
  346.         iscsi_conn_num=${conn##*:}
  347.         if [ "$iscsi_conn_num" = '0' ] ; then
  348.         iscsi_connection=$(basename $conn)
  349.         fi
  350.     done
  351.     if [ -z "$iscsi_connection" ] ; then
  352.         : no iSCSI connection found
  353.         RESULT=1
  354.         return
  355.     fi
  356.     iscsi_connection_path=/sys/class/iscsi_connection/${iscsi_connection}
  357.     if [ ! -d "$iscsi_connection_path" ] ; then
  358.         : no iSCSI connection path
  359.         RESULT=1
  360.         return
  361.     fi
  362.     if [ -e "${iscsi_session_path}/targetname" ]; then
  363.         read iscsi_tgtname < ${iscsi_session_path}/targetname
  364.     fi
  365.     if [ -z "$iscsi_tgtname" ] ; then
  366.         : No iSCSI Targetname
  367.         RESULT=1
  368.         return
  369.     fi
  370.     if [ -e "${iscsi_connection_path}/persistent_address" ] ; then
  371.         read iscsi_address < ${iscsi_connection_path}/persistent_address
  372.     fi
  373.     if [ -z "$iscsi_address" ] ; then
  374.         : No iSCSI Target address
  375.         RESULT=1
  376.         return
  377.     fi
  378.     if [ -e "${iscsi_connection_path}/persistent_port" ] ; then
  379.         read iscsi_port < ${iscsi_connection_path}/persistent_port
  380.     fi
  381.     d="ip-${iscsi_address}:${iscsi_port}-iscsi-${iscsi_tgtname}"
  382.     RESULT=0
  383. }
  384.  
  385. handle_usb () {
  386. : handle_usb $*
  387.     local DEV=$1
  388.     cd -P $1
  389.     DEV=${PWD}
  390.     port_id=${DEV##*/}
  391.     port_num=${port_id#*-}
  392.     host_dev_path=$DEV
  393.     while [ ! -z "$host_dev_path" ] ; do
  394.         case "$host_dev_path" in
  395.             */usb*)
  396.                 usb_host_path=$host_dev_path
  397.                 host_dev_path="${host_dev_path%/*}"
  398.                 ;;
  399.             *)
  400.                 break
  401.                 ;;
  402.         esac
  403.     done
  404.     : host_dev_path $host_dev_path
  405.     usb_host_num=${usb_host_path##*/usb}
  406.  
  407.     cd "$host_dev_path"
  408.     usb_host_offset=$(get_port_offset usb $usb_host_num)
  409.     usb_host_port=$(($usb_host_num - $usb_host_offset))
  410.     cd "$OPWD"
  411.     if [ "$d" ] ; then
  412.         d="usb-$usb_host_port:$port_num-${d}"
  413.     else
  414.         d="usb-$usb_host_port:$port_num"
  415.     fi
  416.     D="$host_dev_path"
  417.     RESULT=0
  418. }
  419.  
  420. handle_device () {
  421.     full_sysfs_path="$SYSFS$DEVPATH"
  422.     case "$DEVPATH" in
  423.         /devices/*)
  424.             # new sysfs layout
  425.             if [ -L $full_sysfs_path/subsystem ]; then
  426.                 full_sysfs_path="${full_sysfs_path%/*}"
  427.                 cd "$full_sysfs_path/subsystem";
  428.                 subsys="`pwd -P`"
  429.                 cd "$OPWD"
  430.                 subsys="${subsys##*/}"
  431.                 if [ "$subsys" = "block" ]; then
  432.                     # parent is "block", it's a partition, move one up
  433.                 full_sysfs_path="${full_sysfs_path%/*}"
  434.                 fi
  435.                 cd $full_sysfs_path
  436.             fi
  437.             ;;
  438.         *)
  439.             # old sysfs layout
  440.             if [ ! -L $full_sysfs_path/device ] ; then
  441.                 if [ -f $full_sysfs_path/range ] ; then return ; fi
  442.                 full_sysfs_path="${full_sysfs_path%/*}"
  443.                 : full_sysfs_path "$full_sysfs_path"
  444.                 if [ ! -L $full_sysfs_path/device -o ! -f $full_sysfs_path/dev ] ; then
  445.                     return
  446.                 fi
  447.             fi
  448.             cd $full_sysfs_path/device
  449.             ;;
  450.     esac
  451.     full_sysfs_device_path="`pwd -P`"
  452.     cd "$OPWD"
  453.     D=$full_sysfs_device_path
  454.     while [ ! -z "$D" ] ; do
  455.         case "$D" in
  456.             */ide[0-9]/[0-9].[0-9]*|*/ide[0-9][0-9]/[0-9][0-9].[0-9]*)
  457.                 handle_ide "$D"
  458.                 ;;
  459.             */css0/*)
  460.                 if [ -r $full_sysfs_device_path/wwpn ]; then
  461.                     read wwpn < $full_sysfs_device_path/wwpn
  462.                 fi
  463.                 if [ -r $full_sysfs_device_path/fcp_lun ]; then
  464.                     read lun < $full_sysfs_device_path/fcp_lun
  465.                 fi
  466.                 if [ -r $full_sysfs_device_path/hba_id ]; then
  467.                     read bus_id < $full_sysfs_device_path/hba_id
  468.                 fi
  469.                 if [ "$bus_id" -a "$wwpn" -a "$lun" ]; then
  470.                     # S/390 zfcp adapter
  471.                     d="ccw-$bus_id-zfcp-$wwpn:$lun"
  472.                     RESULT=0
  473.                 else
  474.                     # DASD devices
  475.                     bus="ccw"
  476.                     adapter=${D##*/}
  477.                     d="$bus-$adapter"
  478.                     RESULT=0
  479.                 fi
  480.                 D=
  481.                 ;;
  482.             */rport-[0-9]*:[0-9]*-[0-9]*/*)
  483.                 handle_fc "$D"
  484.                 ;;
  485.             */end_device-[0-9]*:[0-9]*:[0-9]*/*)
  486.                 handle_sas "$D"
  487.                 ;;
  488.             */fw-host[0-9]*/*)
  489.                 handle_firewire "$D"
  490.                 ;;
  491.             */session[0-9]*/*)
  492.                 handle_iscsi "$D"
  493.                 D=
  494.                 ;;
  495.             */host[0-9]*/[0-9]*:[0-9]*:[0-9]*:[0-9]*)
  496.                 handle_scsi "$D"
  497.                 ;;
  498.             */usb[0-9]*/[0-9]*/*)
  499.                 handle_usb "$D"
  500.                 ;;
  501.             */pci[0-9]*:[0-9]*)
  502.                 handle_pci "$D"
  503.                 ;;
  504.             */serio[0-9]*)
  505.                 handle_serio "$D"
  506.                 ;;
  507.             */platform/*)
  508.                 handle_platform "$D"
  509.                 ;;
  510.             */devices)
  511.                 D=
  512.                 ;;
  513.             *)
  514.                 : not handled
  515.                 RESULT=1
  516.                 return
  517.                 ;;
  518.         esac
  519.     done
  520.     if [ "$TYPE" = "scsi_tape" ] ; then
  521.         devname=${full_sysfs_path##*/}
  522.         rewind="${devname%%st*}"
  523.         mode="${devname##*st}"
  524.         case "$mode" in
  525.             *l)
  526.                 mode="l"
  527.                 ;;
  528.             *m)
  529.                 mode="m"
  530.                 ;;
  531.             *a)
  532.                 mode="a"
  533.                 ;;
  534.             *)
  535.                 mode=""
  536.                ;;
  537.         esac
  538.         if [ "$d" ]; then
  539.             d="$d-${rewind}st${mode}"
  540.         fi
  541.     fi
  542. }
  543.  
  544. case "$TYPE" in
  545.     block)
  546.         handle_device
  547.         echo "ID_PATH=$d"
  548.         ;;
  549.     scsi_tape)
  550.         handle_device
  551.         echo "ID_PATH=$d"
  552.         ;;
  553.     input)
  554.         handle_device
  555.         echo "ID_PATH=$d"
  556.         ;;
  557.     *)
  558.         RESULT=1
  559.         ;;
  560. esac
  561.  
  562. exit $RESULT
  563.