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