chiark / gitweb /
rule_generator: fix enumeration for write_cd_rules
[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         local lun
289         lun=${DEV##*:}
290         # SAS device
291         sas_end_path="${DEV%%/target*}"
292         sas_host_path="${sas_end_path%%/port*}"
293         sas_phy_path="${sas_end_path#*/host*/}"
294         sas_phy_path="${sas_phy_path%%/*}"
295         sas_phy_path="${sas_host_path}/${sas_phy_path}"
296
297         sas_phy_id=255
298         for phy in $sas_phy_path/phy-*/sas_phy/phy-* ; do
299                 if [ -d "$phy" ] ; then
300                         read phy_id < $phy/phy_identifier
301                         if [ $phy_id -lt $sas_phy_id ]; then
302                                 sas_phy_id=$phy_id
303                         fi
304                 fi
305         done
306
307         if [ $sas_phy_id -eq 255 ] ; then
308                 : no initiator address
309                 D=
310                 RESULT=1
311                 return
312         fi
313
314         sas_port_id="${sas_phy_path##*/port-}"
315         sas_port_dev="/sys/class/sas_port/port-${sas_port_id}"
316         if [ -e "$sas_port_dev/num_phys" ] ; then
317                 read phy_port < $sas_port_dev/num_phys
318         fi
319
320         sas_end_id="${sas_end_path##*end_device-}"
321         sas_end_dev="/sys/class/sas_device/end_device-${sas_end_id}"
322         if [ -e "$sas_end_dev/sas_address" ]; then
323                 read end_address < $sas_end_dev/sas_address
324                 read end_id < $sas_end_dev/phy_identifier
325         fi
326         if [ -z "$end_address" ] ; then
327                 : no end device address
328                 D=
329                 RESULT=1
330                 return
331         fi
332         sas_end_address="$end_address:$end_id"
333         controller_dev="${sas_host_path%/host[0-9]*}"
334         # SAS devices are always endpoints
335         d="sas-phy${sas_phy_id}:${phy_port}-${sas_end_address}-lun$lun"
336         D="$controller_dev"
337         RESULT=0
338 }
339
340 handle_iscsi() {
341         local DEV=$1
342         local iscsi_session_dir
343         local iscsi_session iscsi_session_path
344         local iscsi_connection iscsi_connection_path
345         local iscsi_scsi_lun
346         # iSCSI device
347         iscsi_session_dir="${DEV%%/target*}"
348         iscsi_session="${iscsi_session_dir##*/}"
349         iscsi_session_path=/sys/class/iscsi_session/${iscsi_session}
350         if [ ! -d "$iscsi_session_path" ] ; then
351             : no iSCSI session path
352             RESULT=1
353             return
354         fi
355         # Currently we're not doing MC/S
356         for conn in ${iscsi_session_dir}/connection* ; do
357             iscsi_conn_num=${conn##*:}
358             if [ "$iscsi_conn_num" = '0' ] ; then
359                 iscsi_connection=$(basename $conn)
360             fi
361         done
362         if [ -z "$iscsi_connection" ] ; then
363             : no iSCSI connection found
364             RESULT=1
365             return
366         fi
367         iscsi_connection_path=/sys/class/iscsi_connection/${iscsi_connection}
368         if [ ! -d "$iscsi_connection_path" ] ; then
369             : no iSCSI connection path
370             RESULT=1
371             return
372         fi
373         if [ -e "${iscsi_session_path}/targetname" ]; then
374             read iscsi_tgtname < ${iscsi_session_path}/targetname
375         fi
376         if [ -z "$iscsi_tgtname" ] ; then
377             : No iSCSI Targetname
378             RESULT=1
379             return
380         fi
381         if [ -e "${iscsi_connection_path}/persistent_address" ] ; then
382             read iscsi_address < ${iscsi_connection_path}/persistent_address
383         fi
384         if [ -z "$iscsi_address" ] ; then
385             : No iSCSI Target address
386             RESULT=1
387             return
388         fi
389         if [ -e "${iscsi_connection_path}/persistent_port" ] ; then
390             read iscsi_port < ${iscsi_connection_path}/persistent_port
391         fi
392         iscsi_scsi_lun="${DEV##*:}"
393         d="ip-${iscsi_address}:${iscsi_port}-iscsi-${iscsi_tgtname}-lun-${iscsi_scsi_lun}"
394         RESULT=0
395 }
396
397 handle_usb () {
398 : handle_usb $*
399         local DEV=$1
400         cd -P $1
401         DEV=${PWD}
402         port_id=${DEV##*/}
403         port_num=${port_id#*-}
404         host_dev_path=$DEV
405         while [ ! -z "$host_dev_path" ] ; do
406                 case "$host_dev_path" in
407                         */usb*)
408                                 usb_host_path=$host_dev_path
409                                 host_dev_path="${host_dev_path%/*}"
410                                 ;;
411                         *)
412                                 break
413                                 ;;
414                 esac
415         done
416         : host_dev_path $host_dev_path
417         usb_host_num=${usb_host_path##*/usb}
418
419         cd "$host_dev_path"
420         usb_host_offset=$(get_port_offset usb $usb_host_num)
421         usb_host_port=$(($usb_host_num - $usb_host_offset))
422         cd "$OPWD"
423         if [ "$d" ] ; then
424                 d="usb-$usb_host_port:$port_num-${d}"
425         else
426                 d="usb-$usb_host_port:$port_num"
427         fi
428         D="$host_dev_path"
429         RESULT=0
430 }
431
432 handle_device () {
433         full_sysfs_path="$SYSFS$DEVPATH"
434         case "$DEVPATH" in
435                 /devices/*)
436                         full_sysfs_path="${full_sysfs_path%/*}"
437                         # skip parent device of the same subsystem
438                         if [ -L $full_sysfs_path/subsystem ]; then
439                                 cd "$full_sysfs_path/subsystem";
440                                 subsys="`pwd -P`"
441                                 cd "$OPWD"
442                                 subsys="${subsys##*/}"
443                                 if [ "$subsys" = "$TYPE" ]; then
444                                         : skip same subsystem parent
445                                         full_sysfs_path="${full_sysfs_path%/*}"
446                                 fi
447                         fi
448                         # skip subsystem directory
449                         subsys="${full_sysfs_path##*/}"
450                         if [ "$subsys" = "$TYPE" ]; then
451                                 : skip subsystem directory
452                                 full_sysfs_path="${full_sysfs_path%/*}"
453                         fi
454                         cd $full_sysfs_path
455                         ;;
456                 *)
457                         # old sysfs layout
458                         if [ ! -L $full_sysfs_path/device ]; then
459                                 full_sysfs_path="${full_sysfs_path%/*}"
460                                 : full_sysfs_path "$full_sysfs_path"
461                                 if [ ! -L $full_sysfs_path/device -o ! -f $full_sysfs_path/dev ]; then
462                                         return
463                                 fi
464                         fi
465                         if [ -L $full_sysfs_path/device/device ]; then
466                                 cd $full_sysfs_path/device/device
467                         else
468                                 cd $full_sysfs_path/device
469                         fi
470                         ;;
471         esac
472         full_sysfs_device_path="`pwd -P`"
473         cd "$OPWD"
474
475         D=$full_sysfs_device_path
476         while [ ! -z "$D" ] ; do
477                 case "$D" in
478                         */ide[0-9]/[0-9].[0-9]*|*/ide[0-9][0-9]/[0-9][0-9].[0-9]*)
479                                 handle_ide "$D"
480                                 ;;
481                         */css0/*)
482                                 if [ -r $full_sysfs_device_path/wwpn ]; then
483                                         read wwpn < $full_sysfs_device_path/wwpn
484                                 fi
485                                 if [ -r $full_sysfs_device_path/fcp_lun ]; then
486                                         read lun < $full_sysfs_device_path/fcp_lun
487                                 fi
488                                 if [ -r $full_sysfs_device_path/hba_id ]; then
489                                         read bus_id < $full_sysfs_device_path/hba_id
490                                 fi
491                                 if [ "$bus_id" -a "$wwpn" -a "$lun" ]; then
492                                         # S/390 zfcp adapter
493                                         d="ccw-$bus_id-zfcp-$wwpn:$lun"
494                                         RESULT=0
495                                 else
496                                         # DASD devices
497                                         bus="ccw"
498                                         adapter=${D##*/}
499                                         d="$bus-$adapter"
500                                         RESULT=0
501                                 fi
502                                 D=
503                                 ;;
504                         */rport-[0-9]*:[0-9]*-[0-9]*/*)
505                                 handle_fc "$D"
506                                 ;;
507                         */end_device-[0-9]*:[0-9]*:[0-9]*/*)
508                                 handle_sas "$D"
509                                 ;;
510                         */fw-host[0-9]*/*)
511                                 handle_firewire "$D"
512                                 ;;
513                         */session[0-9]*/*)
514                                 handle_iscsi "$D"
515                                 D=
516                                 ;;
517                         */host[0-9]*/[0-9]*:[0-9]*:[0-9]*:[0-9]*)
518                                 handle_scsi "$D"
519                                 ;;
520                         */ttyUSB*)
521                                 D=${D%/ttyUSB*}
522                                 ;;
523                         */usb[0-9]*/[0-9]*/*)
524                                 handle_usb "$D"
525                                 ;;
526                         */pci[0-9]*:[0-9]*)
527                                 handle_pci "$D"
528                                 ;;
529                         */serio[0-9]*)
530                                 handle_serio "$D"
531                                 ;;
532                         */platform/*)
533                                 handle_platform "$D"
534                                 ;;
535                         */devices)
536                                 D=
537                                 ;;
538                         *)
539                                 : not handled
540                                 RESULT=1
541                                 return
542                                 ;;
543                 esac
544         done
545         if [ "$TYPE" = "scsi_tape" ] ; then
546                 devname=${full_sysfs_path##*/}
547                 rewind="${devname%%st*}"
548                 mode="${devname##*st}"
549                 case "$mode" in
550                         *l)
551                                 mode="l"
552                                 ;;
553                         *m)
554                                 mode="m"
555                                 ;;
556                         *a)
557                                 mode="a"
558                                 ;;
559                         *)
560                                 mode=""
561                                 ;;
562                 esac
563                 if [ "$d" ]; then
564                         d="$d-${rewind}st${mode}"
565                 fi
566         fi
567 }
568
569 handle_device
570 if [ -z "$d" ]; then
571         exit 1
572 fi
573 echo "ID_PATH=$d"
574 exit 0