chiark / gitweb /
a7d650bf423b62b46cfd188d3b31c9814d370c53
[elogind.git] / extras / path_id / path_id
1 #!/bin/sh
2
3 # provide the shortest possible unique hardware path to a device
4 # for the Linux Persistent Device Naming scheme
5 #
6 # Copyright (C) 2005-2006 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 SYSFS=/sys
15 RESULT=1
16 TYPE=
17 OPWD="`pwd`"
18 full_sysfs_path=
19 full_sysfs_device_path=
20
21 if [ -z "$DEVPATH" -a -z "$1" ] ; then
22         exit 1
23 fi
24
25 if [ -z "$DEVPATH" ] ; then
26         case "$1" in
27                 $SYSFS/*)
28                         DEVPATH="${1#$SYSFS}"
29                         ;;
30                 *)
31                         DEVPATH=$1
32                         ;;
33         esac
34 fi
35
36 if [ ! -e $SYSFS$DEVPATH/dev ] ; then
37         exit 1
38 fi
39
40 case "$DEVPATH" in
41         /devices/*)
42                 cd "$SYSFS$DEVPATH/subsystem";
43                 TYPE="`pwd -P`"
44                 cd "$OPWD"
45                 TYPE="${TYPE##*/}"
46                 ;;
47         /class/*)
48                 TYPE="${DEVPATH#/class/}"
49                 TYPE="${TYPE%%/*}"
50                 ;;
51         /block/*)
52                 TYPE=block
53                 ;;
54         *)
55                 exit 1
56                 ;;
57 esac
58
59 get_port_offset () {
60         local type offset port
61         type=$1
62         offset=$2
63         for i in $type[0-9]* ; do
64                 : i $i
65                 port="${i#$type}"
66                 if [ "$port" -lt "$offset" ] ; then offset=$port ; fi
67         done
68         echo $offset
69 }
70
71 handle_pci () {
72         local DEV=$1
73         cd -P $1
74         DEV=${PWD}
75         pci_id=${DEV##*/}
76         host_dev_path=$DEV
77         while [ ! -z "$host_dev_path" ] ; do
78                 case "$host_dev_path" in
79                         */pci[0-9]*)
80                                 host_dev_path=${host_dev_path%/*}
81                                 ;;
82                         *)
83                                 break
84                                 ;;
85                 esac
86         done
87         d="pci-$pci_id-$d"
88         D="$host_dev_path"
89         RESULT=0
90 }
91
92 handle_platform () {
93         local DEV=$1
94         cd -P $1
95         DEV=${PWD}
96         platform_id=${DEV##*/}
97         host_dev_path=$DEV
98         while [ ! -z "$host_dev_path" ] ; do
99                 case "$host_dev_path" in
100                         */platform*)
101                                 host_dev_path=${host_dev_path%/*}
102                                 ;;
103                         *)
104                                 break
105                                 ;;
106                 esac
107         done
108         if [ "$d" ]; then
109                 d="platform-$platform_id-$d"
110         else
111                 d="platform-$platform_id"
112         fi
113         D="$host_dev_path"
114         RESULT=0
115 }
116
117 handle_serio () {
118         local DEV=$1
119         cd -P $1
120         DEV=${PWD}
121         serio_id=${DEV##*/serio}
122         host_dev_path=$DEV
123         while [ ! -z "$host_dev_path" ] ; do
124                 case "$host_dev_path" in
125                         */serio*)
126                                 host_dev_path=${host_dev_path%/*}
127                                 ;;
128                         *)
129                                 break
130                                 ;;
131                 esac
132         done
133         if [ "$d" ]; then
134                 d="serio-$serio_id-$d"
135         else
136                 d="serio-$serio_id"
137         fi
138         D="$host_dev_path"
139         RESULT=0
140 }
141
142 handle_ide () {
143         : handle_ide $*
144         local DEV=$1
145         local port idedev idecontroller
146         # IDE
147         : DEV $DEV
148         port=${DEV##*/}
149         idedev=${DEV%/*}
150         idecontroller=${idedev%/*}
151         # port info if the controller has more than one interface
152         port="${port#ide}"
153         : port $port d $d
154         : idedev $idedev kernel_port $port
155         case "${port#*.}" in
156                 0)
157                         channel=0
158                         ;;
159                 1)
160                         channel=1
161                         ;;
162                 *)
163                         echo "Error: $idedev is neither master or slave" >&2
164                         ;;
165         esac
166         cd $idecontroller
167         offset="`get_port_offset ide ${port%.*}`"
168         cd "$OPWD"
169         :  port offset $offset
170         port=$((${port%.*} - $offset))
171         if [ "$d" ] ; then
172                 d="ide-${port}:$channel-$d"
173         else
174                 d="ide-${port}:$channel"
175         fi
176         D=$idecontroller
177         RESULT=0
178 }
179
180 handle_scsi () {
181         : handle_scsi $*
182         local DEV=$1
183         local cil controller_port controller_dev
184         # SCSI device
185         cil="${DEV##*/}"
186         cil="${cil#*:}"
187         target_dev=${DEV%/*}
188         target_id=${target_dev##*/target}
189         cd "$target_dev"
190         target_num=0
191         for tid in ${target_id}* ; do
192                 target_num=$(( $target_num + 1 ))
193         done
194         controller_port=${target_dev%/*}
195         controller_dev="${controller_port%/*}"
196         : controller_dev $controller_dev
197         : controller_port $controller_port
198         # a host controller may have more than one interface/port
199         controller_port="${controller_port##*/host}"
200         #
201         cd "$controller_dev"
202         controller_offset=$(get_port_offset host $controller_port)
203         cd "$OPWD"
204         controller_port=$(( $controller_port - $controller_offset))
205         scsi_id="scsi-${controller_port}:${cil}"
206         if [ "$d" ] ; then
207                 d="${scsi_id}-$d"
208         else
209                 d="$scsi_id"
210         fi
211         D="$controller_dev"
212         RESULT=0
213 }
214
215 handle_firewire () {
216         : handle_firewire $*
217         local DEV=$1
218         if [ -f "$D/ieee1394_id" ] ; then
219                 read ieee1394_id < $D/ieee1394_id
220         fi
221         if [ -z "$ieee1394_id" ] ; then
222                 : no IEEE1394 ID
223                 RESULT=1
224                 return
225         fi
226         fw_host_dev=${DEV%/fw-host*}
227         # IEEE1394 devices are always endpoints
228         d="ieee1394-0x$ieee1394_id"
229         D="$fw_host_dev"
230         RESULT=0
231 }
232
233 handle_fc () {
234         : handle_fc $*
235         local DEV=$1
236         local cil controller_port controller_dev
237         # SCSI-FC device
238         fc_tgt_hcil="${DEV##*/}"
239         fc_tgt_lun="${fc_tgt_hcil##*:}"
240         fc_tgt_path="${DEV%/*}"
241         fc_tgt_num="${fc_tgt_path##*/}"
242         fc_tgt_dev="${fc_tgt_path}/fc_transport:${fc_tgt_num}"
243         if [ -e "$fc_tgt_dev/port_name" ]; then
244                 read wwpn < $fc_tgt_dev/port_name
245         fi
246         if [ -z "$wwpn" ] ; then
247                 : no WWPN
248                 D=
249                 RESULT=1
250                 return
251         fi
252         # Linux currently knows about 32bit luns
253         tmp_lun3=$(printf "%04x" $(($fc_tgt_lun & 0xFFFF)))
254         tmp_lun2=$(printf "%04x" $(( ($fc_tgt_lun >> 16) & 0xFFFF)))
255         tmp_lun1="0000"
256         tmp_lun0="0000"
257         if (($fc_tgt_lun == 0)) ; then
258                 lun="0x0000000000000000"
259         else
260                 lun="0x${tmp_lun3}${tmp_lun2}${tmp_lun1}${tmp_lun0}"
261         fi
262         controller_dev="${fc_tgt_path%/host[0-9]*}"
263         # FC devices are always endpoints
264         d="fc-${wwpn}:${lun}"
265         D="$controller_dev"
266         RESULT=0
267 }
268
269 handle_sas () {
270         : handle_sas $*
271         local DEV=$1
272         local cil adapter controller_dev
273         # SAS device
274         sas_host_path="${DEV%%/port*}"
275         sas_phy_path="${DEV#*/host*/}"
276         sas_phy_path="${sas_phy_path%%/target*}"
277         sas_phy_id="${sas_phy_path%%/*}"
278         sas_phy_id="${sas_phy_id##*port-}"
279         sas_port_id="${sas_phy_path%%/end_device*}"
280         sas_port_id="${sas_port_id##*port-}"
281         sas_end_id="${sas_phy_path##*end_device-}"
282         sas_phy_dev="/sys/class/sas_phy/phy-${sas_phy_id}"
283         if [ -e "$sas_phy_dev/sas_address" ]; then
284                 read phy_address < $sas_phy_dev/sas_address
285                 read phy_id < $sas_phy_dev/phy_identifier
286         fi
287         if [ -z "$phy_address" ] ; then
288                 : no initiator address
289                 D=
290                 RESULT=1
291                 return
292         fi
293         sas_port_dev="/sys/class/sas_port/port-${sas_port_id}"
294         if [ -e "$sas_port_dev/num_phys" ] ; then
295                 read phy_port < $sas_port_dev/num_phys
296         fi
297         if [ -z "$phy_port" ] ; then
298                 : no initiator address
299                 D=
300                 RESULT=1
301                 return
302         fi
303         sas_phy_address="$phy_address:$phy_port:$phy_id"
304         sas_end_dev="/sys/class/sas_device/end_device-${sas_end_id}"
305         if [ -e "$sas_end_dev/sas_address" ]; then
306                 read end_address < $sas_end_dev/sas_address
307                 read end_id < $sas_end_dev/phy_identifier
308         fi
309         if [ -z "$end_address" ] ; then
310                 : no initiator address
311                 D=
312                 RESULT=1
313                 return
314         fi
315         sas_end_address="$end_address:$end_id"
316         controller_dev="${sas_host_path%/host[0-9]*}"
317         # SAS devices are always endpoints
318         d="sas-${sas_phy_address}-${sas_end_address}"
319         D="$controller_dev"
320         RESULT=0
321 }
322
323 handle_iscsi() {
324         local DEV=$1
325         local iscsi_session_dir
326         local iscsi_session iscsi_session_path
327         local iscsi_connection iscsi_connection_path
328         local iscsi_scsi_lun
329         # iSCSI device
330         iscsi_session_dir="${DEV%%/target*}"
331         iscsi_session="${iscsi_session_dir##*/}"
332         iscsi_session_path=/sys/class/iscsi_session/${iscsi_session}
333         if [ ! -d "$iscsi_session_path" ] ; then
334             : no iSCSI session path
335             RESULT=1
336             return
337         fi
338         # Currently we're not doing MC/S
339         for conn in ${iscsi_session_dir}/connection* ; do
340             iscsi_conn_num=${conn##*:}
341             if [ "$iscsi_conn_num" = '0' ] ; then
342                 iscsi_connection=$(basename $conn)
343             fi
344         done
345         if [ -z "$iscsi_connection" ] ; then
346             : no iSCSI connection found
347             RESULT=1
348             return
349         fi
350         iscsi_connection_path=/sys/class/iscsi_connection/${iscsi_connection}
351         if [ ! -d "$iscsi_connection_path" ] ; then
352             : no iSCSI connection path
353             RESULT=1
354             return
355         fi
356         if [ -e "${iscsi_session_path}/targetname" ]; then
357             read iscsi_tgtname < ${iscsi_session_path}/targetname
358         fi
359         if [ -z "$iscsi_tgtname" ] ; then
360             : No iSCSI Targetname
361             RESULT=1
362             return
363         fi
364         if [ -e "${iscsi_connection_path}/persistent_address" ] ; then
365             read iscsi_address < ${iscsi_connection_path}/persistent_address
366         fi
367         if [ -z "$iscsi_address" ] ; then
368             : No iSCSI Target address
369             RESULT=1
370             return
371         fi
372         if [ -e "${iscsi_connection_path}/persistent_port" ] ; then
373             read iscsi_port < ${iscsi_connection_path}/persistent_port
374         fi
375         iscsi_scsi_lun="${DEV##*:}"
376         d="ip-${iscsi_address}:${iscsi_port}-iscsi-${iscsi_tgtname}-lun-${iscsi_scsi_lun}"
377         RESULT=0
378 }
379
380 handle_usb () {
381 : handle_usb $*
382         local DEV=$1
383         cd -P $1
384         DEV=${PWD}
385         port_id=${DEV##*/}
386         port_num=${port_id#*-}
387         host_dev_path=$DEV
388         while [ ! -z "$host_dev_path" ] ; do
389                 case "$host_dev_path" in
390                         */usb*)
391                                 usb_host_path=$host_dev_path
392                                 host_dev_path="${host_dev_path%/*}"
393                                 ;;
394                         *)
395                                 break
396                                 ;;
397                 esac
398         done
399         : host_dev_path $host_dev_path
400         usb_host_num=${usb_host_path##*/usb}
401
402         cd "$host_dev_path"
403         usb_host_offset=$(get_port_offset usb $usb_host_num)
404         usb_host_port=$(($usb_host_num - $usb_host_offset))
405         cd "$OPWD"
406         if [ "$d" ] ; then
407                 d="usb-$usb_host_port:$port_num-${d}"
408         else
409                 d="usb-$usb_host_port:$port_num"
410         fi
411         D="$host_dev_path"
412         RESULT=0
413 }
414
415 handle_device () {
416         full_sysfs_path="$SYSFS$DEVPATH"
417         case "$DEVPATH" in
418                 /devices/*)
419                         # new sysfs layout
420                         if [ -L $full_sysfs_path/subsystem ]; then
421                                 full_sysfs_path="${full_sysfs_path%/*}"
422                                 cd "$full_sysfs_path/subsystem";
423                                 subsys="`pwd -P`"
424                                 cd "$OPWD"
425                                 subsys="${subsys##*/}"
426                                 if [ "$subsys" = "block" ]; then
427                                         # parent is "block", it's a partition, move one up
428                                 full_sysfs_path="${full_sysfs_path%/*}"
429                                 fi
430                                 cd $full_sysfs_path
431                         fi
432                         ;;
433                 *)
434                         # old sysfs layout
435                         if [ ! -L $full_sysfs_path/device ] ; then
436                                 if [ -f $full_sysfs_path/range ] ; then return ; fi
437                                 full_sysfs_path="${full_sysfs_path%/*}"
438                                 : full_sysfs_path "$full_sysfs_path"
439                                 if [ ! -L $full_sysfs_path/device -o ! -f $full_sysfs_path/dev ] ; then
440                                         return
441                                 fi
442                         fi
443                         cd $full_sysfs_path/device
444                         ;;
445         esac
446         full_sysfs_device_path="`pwd -P`"
447         cd "$OPWD"
448         D=$full_sysfs_device_path
449         while [ ! -z "$D" ] ; do
450                 case "$D" in
451                         */ide[0-9]/[0-9].[0-9]*|*/ide[0-9][0-9]/[0-9][0-9].[0-9]*)
452                                 handle_ide "$D"
453                                 ;;
454                         */css0/*)
455                                 if [ -r $full_sysfs_device_path/wwpn ]; then
456                                         read wwpn < $full_sysfs_device_path/wwpn
457                                 fi
458                                 if [ -r $full_sysfs_device_path/fcp_lun ]; then
459                                         read lun < $full_sysfs_device_path/fcp_lun
460                                 fi
461                                 if [ -r $full_sysfs_device_path/hba_id ]; then
462                                         read bus_id < $full_sysfs_device_path/hba_id
463                                 fi
464                                 if [ "$bus_id" -a "$wwpn" -a "$lun" ]; then
465                                         # S/390 zfcp adapter
466                                         d="ccw-$bus_id-zfcp-$wwpn:$lun"
467                                         RESULT=0
468                                 else
469                                         # DASD devices
470                                         bus="ccw"
471                                         adapter=${D##*/}
472                                         d="$bus-$adapter"
473                                         RESULT=0
474                                 fi
475                                 D=
476                                 ;;
477                         */rport-[0-9]*:[0-9]*-[0-9]*/*)
478                                 handle_fc "$D"
479                                 ;;
480                         */end_device-[0-9]*:[0-9]*:[0-9]*/*)
481                                 handle_sas "$D"
482                                 ;;
483                         */fw-host[0-9]*/*)
484                                 handle_firewire "$D"
485                                 ;;
486                         */session[0-9]*/*)
487                                 handle_iscsi "$D"
488                                 D=
489                                 ;;
490                         */host[0-9]*/[0-9]*:[0-9]*:[0-9]*:[0-9]*)
491                                 handle_scsi "$D"
492                                 ;;
493                         */usb[0-9]*/[0-9]*/*)
494                                 handle_usb "$D"
495                                 ;;
496                         */pci[0-9]*:[0-9]*)
497                                 handle_pci "$D"
498                                 ;;
499                         */serio[0-9]*)
500                                 handle_serio "$D"
501                                 ;;
502                         */platform/*)
503                                 handle_platform "$D"
504                                 ;;
505                         */devices)
506                                 D=
507                                 ;;
508                         *)
509                                 : not handled
510                                 RESULT=1
511                                 return
512                                 ;;
513                 esac
514         done
515         if [ "$TYPE" = "scsi_tape" ] ; then
516                 devname=${full_sysfs_path##*/}
517                 rewind="${devname%%st*}"
518                 mode="${devname##*st}"
519                 case "$mode" in
520                         *l)
521                                 mode="l"
522                                 ;;
523                         *m)
524                                 mode="m"
525                                 ;;
526                         *a)
527                                 mode="a"
528                                 ;;
529                         *)
530                                 mode=""
531                            ;;
532                 esac
533                 if [ "$d" ]; then
534                         d="$d-${rewind}st${mode}"
535                 fi
536         fi
537 }
538
539 case "$TYPE" in
540         block)
541                 handle_device
542                 echo "ID_PATH=$d"
543                 ;;
544         scsi_tape)
545                 handle_device
546                 echo "ID_PATH=$d"
547                 ;;
548         input)
549                 handle_device
550                 echo "ID_PATH=$d"
551                 ;;
552         *)
553                 RESULT=1
554                 ;;
555 esac
556
557 exit $RESULT