chiark / gitweb /
path_id: work with "all devices in /sys/devices"
[elogind.git] / extras / path_id
1 #!/bin/sh
2
3 # provide the shortest possible unique hardware path to a block device
4 # for the udev persistent disk device naming scheme
5 #
6 # Copyright (C) 2005 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=/block/sda/sda3 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 # SCSI cdrom
22 # /class/block/sr0 -> /devices/pci0002:30/0002:30:0c.0/host0/target0:0:0/0:0:1:0
23 # pci-0002:30:0c.0-scsi-0:0:1:0
24 #
25 # SCSI disk
26 # /class/block/sda -> /devices/pci0002:30/0002:30:0c.0/host0/target0:0:0/0:0:4:0
27 # pci-0002:30:0c.0-scsi-0:0:4:0
28 #
29 # SATA disk, 4 channels per controller
30 # /class/block/sda -> /devices/pci0001:00/0001:00:07.0/0001:05:0c.0/host0/target0:0:0/0:0:0:0
31 # pci-0001:05:0c.0-scsi-0:0:0:0
32 #
33 # IDE disk
34 # /class/block/hda -> /devices/pci0002:02/0002:02:0d.0/ide0/0.0
35 # pci-0002:02:0d.0-ide-0.0
36 #
37 # IDE cdrom on a Mac ASIC:
38 # /class/block/hdc -> /devices/pci0001:01/0001:01:17.0/0.80000000:mac-io/0.00020000:ata-3/ide1/1.0
39 # mac-io_ata-3_master
40 #
41 # IDE cdrom on a Mac ASIC, with ide-scsi:
42 # /class/block/sr0 -> /devices/pci0001:01/0001:01:17.0/0.80000000:mac-io/0.0001f000:ata-4/ide0/0.1/host2/target2:0:0/2:0:0:0
43 # mac-io_ata-4_slave
44
45 # USB CDrom drive without 'serial' number:
46 # reusing 'product' and 'manufacturer' string, if available
47 # /class/block/sr0 -> /devices/pci0001:00/0001:00:04.0/0001:02:0b.0/usb4/4-2/4-2:1.0/host4/4:0:0:0
48 # usb-storage-odd-Freecom-USIDERev930:0:0:0
49
50 # devices may have several interfaces on one PCI device, like IDE:
51 # pci-0001:00:04.0_ide1-master
52 # pci-0001:00:04.0_ide2-master
53 # pci-0001:00:04.0_ide2-slave
54 # they are marked as ports, it is expected that the driver shows
55 # ide1 even if there is nothing connected to either master or slave
56 # interface
57 #
58 # match order is important.
59 # first IDE to find ide-scsi devices, then SCSI
60 # first usb-storage, then firewire sbp2, then the rest
61
62 SYSFS=/sys
63 RESULT=1
64 TYPE=
65 OPWD="`pwd`"
66 full_sysfs_path=
67 full_sysfs_device_path=
68
69 if [ -z "$DEVPATH" -a -z "$1" ] ; then
70     exit 1
71 fi
72
73 if [ -z "$DEVPATH" ] ; then
74     case "$1" in
75         $SYSFS/*)
76             DEVPATH="${1#$SYSFS}"
77             ;;
78         *)
79             DEVPATH=$1
80             ;;
81     esac
82 fi
83
84 if [ ! -e $SYSFS$DEVPATH/dev ] ; then
85     exit 1
86 fi
87
88 case "$DEVPATH" in
89     /devices/*)
90         cd "$SYSFS$DEVPATH/subsystem";
91         TYPE="`pwd -P`"
92         cd "$OPWD"
93         TYPE="${TYPE##*/}"
94         ;;
95     /class/*)
96         TYPE="${DEVPATH#/class/}"
97         TYPE="${TYPE%%/*}"
98         ;;
99     /block/*)
100         TYPE=block
101         ;;
102     *)
103         exit 1
104         ;;
105 esac
106
107 get_port () {
108     local type offset port
109     type=$1
110     offset=$2
111     for i in $type[0-9]* ; do
112         : i $i
113         port="${i#$type}"
114         if [ "$port" -lt "$offset" ] ; then offset=$port ; fi
115     done
116     if [ "$port" != "0" ] ; then
117         echo $(($2 - $offset))
118     fi
119 }
120
121 handle_block_ide () {
122 : handle_block_ide $*
123         local DEV=$1
124         local port idedev idecontroller
125         # IDE
126         : DEV $DEV
127         d=$DEV
128         case "$DEV" in
129         # remove ide-scsi part, leave only channel info
130                 */ide[0-9]*/host[0-9]*)
131                 while [ ! -z "$d" ] ; do
132                         case "$d" in
133                                 */host[0-9]*)
134                                 d="${d%/*}"
135                                 continue
136                                 ;;
137                                 *)
138                                 break
139                                 ;;
140                         esac
141                 done
142                 ;;
143         esac
144         idedev=$d
145         while [ ! -z "$d" ] ; do
146                 case "$d" in
147                         */ide[0-9]*)
148                         port="${d##*/}"
149                         d="${d%/*}"
150                         continue
151                         ;;
152                         *)
153                         break
154                         ;;
155                 esac
156         done
157         idecontroller=$d
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 "${idedev##*.}" 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         esac
172         case "$d" in
173                 *:mac-io/*)
174                 : mac-io: $d
175                 d="`echo $d | sed -e 's@^.*:mac-io[^:]\+:\([^/]\+\).*@mac-io_\1@'`"
176                 ;;
177                 /sys/devices)
178                 # PCMCIA devices
179                 ifname=${full_sysfs_path##*/}
180                 set -- `sed -n "/$ifname/p" /var/lib/pcmcia/stab`
181                 d="pcmcia-$1"
182                 ;;
183                 *)
184                 d="pci-${d##*/}"
185                 # d="`echo $d | sed -e 's@^.*/\([^/]\{1,\}\)/.@pci-\1@'`"
186                 ;;
187         esac
188
189         cd $idecontroller
190         port="`get_port ide $port`"
191         cd "$OPWD"
192         :  hardware_port $port
193         if [ -z "$port" ] ; then
194                 d="${d}-ide-0:$channel"
195         else
196                 d="${d}-ide-${port}:$channel"
197         fi
198         RESULT=0
199 }
200
201 handle_block_scsi () {
202 : handle_block_scsi $*
203         local DEV=$1
204         local cil controller_port controller_dev
205         # SCSI device
206         cil="${DEV##*/}"
207         cil="${cil#*:}"
208         controller_dev=$DEV
209         while [ ! -z "$controller_dev" ] ; do
210                 case "$controller_dev" in
211                         */host[0-9]*)
212                         controller_port=$controller_dev
213                         controller_dev="${controller_dev%/*}"
214                         ;;
215                         *) break ;;
216                 esac
217         done
218         : controller_dev $controller_dev
219         : controller_port $controller_port
220         # a host controller may have more than one interface/port
221         controller_port="${controller_port##*/}"
222         controller_port="${controller_port##host}"
223         #
224         case "$controller_dev" in
225                 # grand central, old powermacs
226                 *:gc/*)
227                 adapter="`echo $controller_dev |  sed -e 's@/[^/]\{1,\}$@@;s@^.*/@@;s@^.*:@@'`"
228                 bus="gc"
229                 ;;
230                 # PARISC devices
231                 *parisc*)
232                 adapter="${controler_dev##*/}"
233                 bus=parisc;
234                 ;;
235                 *)
236                 adapter="${controller_dev##*/}"
237                 bus="pci"
238                 ;;
239         esac
240         cd "$controller_dev"
241         controller_port="`get_port host $controller_port`"
242         cd "$OPWD"
243         d="$bus-$adapter"
244         if [ -z "$controller_port" ] ; then
245                 controller_port=0
246         fi
247         d="${d}-scsi-${controller_port}:${cil}"
248         RESULT=0
249 }
250
251 handle_block_usb_storage () {
252 : handle_block_usb_storage $*
253         local DEV=$1
254         cil="${DEV##*/}"
255         cil="${cil#*:}"
256         controller_dev=$DEV
257         while [ ! -z "$controller_dev" ] ; do
258                 case "$controller_dev" in
259                         */host[0-9]*)
260                         controller_dev="${controller_dev%/*}"
261                         ;;
262                         *) break ;;
263                 esac
264         done
265         : controller_dev $controller_dev
266         #
267         # usb-storage devs have a serial number, hopefully unique
268         serial=
269         if [ -f $controller_dev/../serial ] ; then
270                 serial="`sed -e 's@^[ -]\{1,\}\|[ -]\{1,\}$@@g;s@[^abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789-]@@g' < $controller_dev/../serial`"
271                 : serial XXX_${serial}_XXX
272                 d="usb-$serial"
273                 serial="`echo $serial | sed -e 's@[ 0]\{1,\}@@g'`"
274         fi
275         if [ -z "$serial" ] ; then
276                 # no serial, broken device
277                 # has eventually binary junk in vpd
278                 identifier=
279                 if [ -f $controller_dev/../product ] ; then
280                 product="`sed -e 's@^[ -]\{1,\}\|[ -]\{1,\}$@@g;s@[^abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789-]@@g' < $controller_dev/../product`"
281                 fi
282                 if [ -f $controller_dev/../manufacturer ] ; then
283                 manufacturer="`sed -e 's@^[ -]\{1,\}\|[ -]\{1,\}$@@g;s@[^abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789-]@@g' < $controller_dev/../manufacturer`"
284                 fi
285                 if [ -z "$product" -o -z "$manufacturer" ] ; then
286                         read idvendor < $controller_dev/../idVendor
287                         read idproduct < $controller_dev/../idProduct
288                         identifier="0x${idvendor}-0x${idproduct}"
289                 else
290                         identifier="${manufacturer}-${product}"
291                 fi
292                 d="usb-${identifier}"
293         fi
294         d="$d:$cil"
295         RESULT=0
296 }
297
298 handle_block () {
299     full_sysfs_path="$SYSFS$DEVPATH"
300     if [ -L $full_sysfs_path/subsystem ]; then
301         # new sysfs block layout
302         full_sysfs_path="${full_sysfs_path%/*}"
303         cd "$full_sysfs_path/subsystem";
304         subsys="`pwd -P`"
305         cd "$OPWD"
306         subsys="${subsys##*/}"
307         if [ "$subsys" == "block" ]; then
308             # parent is "block", it's a partition, move one up
309             full_sysfs_path="${full_sysfs_path%/*}"
310         fi
311         cd $full_sysfs_path
312     else
313         # old sysfs block layout
314         if [ ! -L $full_sysfs_path/device ] ; then
315             if [ -f $full_sysfs_path/range ] ; then return ; fi
316             full_sysfs_path="${full_sysfs_path%/*}"
317             : full_sysfs_path "$full_sysfs_path"
318             if [ ! -L $full_sysfs_path/device -o ! -f $full_sysfs_path/dev ] ; then
319                 return
320             fi
321         fi
322         cd $full_sysfs_path/device
323     fi
324     full_sysfs_device_path="`pwd -P`"
325     cd "$OPWD"
326     D=$full_sysfs_device_path
327     case "$D" in
328         */ide[0-9]/[0-9].[0-9]*|*/ide[0-9][0-9]/[0-9][0-9].[0-9]*)
329         handle_block_ide "$D"
330         ;;
331         */usb[0-9]*/[0-9]*/host[0-9]*/[0-9]*:[0-9]*:[0-9]*:[0-9]*)
332         handle_block_usb_storage "$D"
333         ;;
334         */css0/*)
335         if [ -r $full_sysfs_device_path/wwpn ]; then
336             read wwpn < $full_sysfs_device_path/wwpn
337         fi
338         if [ -r $full_sysfs_device_path/fcp_lun ]; then
339             read lun < $full_sysfs_device_path/fcp_lun
340         fi
341         if [ -r $full_sysfs_device_path/hba_id ]; then
342             read bus_id < $full_sysfs_device_path/hba_id
343         fi
344         if [ "$bus_id" -a "$wwpn" -a "$lun" ]; then
345             # S/390 zfcp adapter
346             d="ccw-$bus_id-zfcp-$wwpn:$lun"
347             RESULT=0
348         else
349             # DASD devices
350             bus="ccw"
351             adapter=${D##*/}
352             d="$bus-$adapter"
353             RESULT=0
354         fi
355         ;;
356         */host[0-9]*/[0-9]*:[0-9]*:[0-9]*:[0-9]*)
357         # check for ieee1394 sbp2 
358         if test -f $D/ieee1394_id ; then
359             read ieee1394_id < $D/ieee1394_id
360             d="`echo ieee1394-${ieee1394_id} | sed -e 's@:@-@g'`"
361             RESULT=0
362         else
363             handle_block_scsi "$D"
364         fi
365         ;;
366         *)
367         : not handled
368         RESULT=1
369         return
370         ;;
371     esac
372     echo "ID_PATH=$d"
373 }
374
375 case "$TYPE" in
376         block)
377         handle_block
378         ;;
379         *)
380         RESULT=1
381         ;;
382 esac
383 exit $RESULT