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