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