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