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