chiark / gitweb /
73d5c834dd2545ba280dd75cb2d090eea36b9c39
[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="${controller_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_fc () {
252 : handle_block_fc $*
253         local DEV=$1
254         local cil controller_port controller_dev
255         # SCSI-FC device
256         fc_tgt_hcil="${DEV##*/}"
257         fc_tgt_lun="${fc_tgt_hcil##*:}"
258         fc_tgt_path="${DEV%/*}"
259         fc_tgt_num="${fc_tgt_path##*/}"
260         fc_tgt_dev="${fc_tgt_path}/fc_transport:${fc_tgt_num}"
261         if [ -e "$fc_tgt_dev/port_name" ]; then
262             read wwpn < $fc_tgt_dev/port_name
263         fi
264         if [ -z "$wwpn" ] ; then
265             : no WWPN
266             RESULT=1
267             return
268         fi
269         # Linux currently knows about 32bit luns
270         tmp_lun3=$(printf "%04x" $(($fc_tgt_lun & 0xFFFF)))
271         tmp_lun2=$(printf "%04x" $(( ($fc_tgt_lun >> 16) & 0xFFFF)))
272         tmp_lun1="0000"
273         tmp_lun0="0000"
274
275         if (($fc_tgt_lun == 0)) ; then
276             lun="0x0000000000000000"
277         else
278             lun="0x${tmp_lun3}${tmp_lun2}${tmp_lun1}${tmp_lun0}"
279         fi
280         controller_dev="${fc_tgt_path%/host[0-9]*}"
281         adapter="${controller_dev##*/}"
282         bus="pci"
283         d="$bus-$adapter"
284         if [ -z "$controller_port" ] ; then
285                 controller_port=0
286         fi
287         d="${d}-fc-${wwpn}:${lun}"
288         RESULT=0
289 }
290
291 handle_block_usb_storage () {
292 : handle_block_usb_storage $*
293         local DEV=$1
294         cil="${DEV##*/}"
295         cil="${cil#*:}"
296         controller_dev=$DEV
297         while [ ! -z "$controller_dev" ] ; do
298                 case "$controller_dev" in
299                         */host[0-9]*)
300                         controller_dev="${controller_dev%/*}"
301                         ;;
302                         *) break ;;
303                 esac
304         done
305         : controller_dev $controller_dev
306         #
307         # usb-storage devs have a serial number, hopefully unique
308         serial=
309         if [ -f $controller_dev/../serial ] ; then
310                 serial="`sed -e 's@^[ -]\{1,\}\|[ -]\{1,\}$@@g;s@[^abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789-]@@g' < $controller_dev/../serial`"
311                 : serial XXX_${serial}_XXX
312                 d="usb-$serial"
313                 serial="`echo $serial | sed -e 's@[ 0]\{1,\}@@g'`"
314         fi
315         if [ -z "$serial" ] ; then
316                 # no serial, broken device
317                 # has eventually binary junk in vpd
318                 identifier=
319                 if [ -f $controller_dev/../product ] ; then
320                 product="`sed -e 's@^[ -]\{1,\}\|[ -]\{1,\}$@@g;s@[^abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789-]@@g' < $controller_dev/../product`"
321                 fi
322                 if [ -f $controller_dev/../manufacturer ] ; then
323                 manufacturer="`sed -e 's@^[ -]\{1,\}\|[ -]\{1,\}$@@g;s@[^abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789-]@@g' < $controller_dev/../manufacturer`"
324                 fi
325                 if [ -z "$product" -o -z "$manufacturer" ] ; then
326                         read idvendor < $controller_dev/../idVendor
327                         read idproduct < $controller_dev/../idProduct
328                         identifier="0x${idvendor}-0x${idproduct}"
329                 else
330                         identifier="${manufacturer}-${product}"
331                 fi
332                 d="usb-${identifier}"
333         fi
334         d="$d:$cil"
335         RESULT=0
336 }
337
338 handle_block () {
339     full_sysfs_path="$SYSFS$DEVPATH"
340     if [ -L $full_sysfs_path/subsystem ]; then
341         # new sysfs block layout
342         full_sysfs_path="${full_sysfs_path%/*}"
343         cd "$full_sysfs_path/subsystem";
344         subsys="`pwd -P`"
345         cd "$OPWD"
346         subsys="${subsys##*/}"
347         if [ "$subsys" == "block" ]; then
348             # parent is "block", it's a partition, move one up
349             full_sysfs_path="${full_sysfs_path%/*}"
350         fi
351         cd $full_sysfs_path
352     else
353         # old sysfs block layout
354         if [ ! -L $full_sysfs_path/device ] ; then
355             if [ -f $full_sysfs_path/range ] ; then return ; fi
356             full_sysfs_path="${full_sysfs_path%/*}"
357             : full_sysfs_path "$full_sysfs_path"
358             if [ ! -L $full_sysfs_path/device -o ! -f $full_sysfs_path/dev ] ; then
359                 return
360             fi
361         fi
362         cd $full_sysfs_path/device
363     fi
364     full_sysfs_device_path="`pwd -P`"
365     cd "$OPWD"
366     D=$full_sysfs_device_path
367     case "$D" in
368         */ide[0-9]/[0-9].[0-9]*|*/ide[0-9][0-9]/[0-9][0-9].[0-9]*)
369         handle_block_ide "$D"
370         ;;
371         */usb[0-9]*/[0-9]*/host[0-9]*/[0-9]*:[0-9]*:[0-9]*:[0-9]*)
372         handle_block_usb_storage "$D"
373         ;;
374         */css0/*)
375         if [ -r $full_sysfs_device_path/wwpn ]; then
376             read wwpn < $full_sysfs_device_path/wwpn
377         fi
378         if [ -r $full_sysfs_device_path/fcp_lun ]; then
379             read lun < $full_sysfs_device_path/fcp_lun
380         fi
381         if [ -r $full_sysfs_device_path/hba_id ]; then
382             read bus_id < $full_sysfs_device_path/hba_id
383         fi
384         if [ "$bus_id" -a "$wwpn" -a "$lun" ]; then
385             # S/390 zfcp adapter
386             d="ccw-$bus_id-zfcp-$wwpn:$lun"
387             RESULT=0
388         else
389             # DASD devices
390             bus="ccw"
391             adapter=${D##*/}
392             d="$bus-$adapter"
393             RESULT=0
394         fi
395         ;;
396         */rport-[0-9]*:[0-9]*-[0-9]*/*)
397         handle_block_fc "$D"
398         ;;
399         */host[0-9]*/[0-9]*:[0-9]*:[0-9]*:[0-9]*)
400         # check for ieee1394 sbp2 
401         if test -f $D/ieee1394_id ; then
402             read ieee1394_id < $D/ieee1394_id
403             d="`echo ieee1394-${ieee1394_id} | sed -e 's@:@-@g'`"
404             RESULT=0
405         else
406             handle_block_scsi "$D"
407         fi
408         ;;
409         *)
410         : not handled
411         RESULT=1
412         return
413         ;;
414     esac
415     echo "ID_PATH=$d"
416 }
417
418 case "$TYPE" in
419         block)
420         handle_block
421         ;;
422         *)
423         RESULT=1
424         ;;
425 esac
426 exit $RESULT