Fix rare fstab parsing bug in yabootconfig
[yaboot.git] / ybin / ofpath
1 #! /bin/sh
2
3 ###############################################################################
4 ##
5 ## ofpath: determine OpenFirmware path from unix device node
6 ## Copyright (C) 2000, 2001 Ethan Benson
7 ##
8 ## Portions based on show_of_path.sh:
9 ##
10 ## Copyright (C) 2000 Olaf Hering <olh@suse.de>
11 ## 
12 ## This program is free software; you can redistribute it and/or
13 ## modify it under the terms of the GNU General Public License
14 ## as published by the Free Software Foundation; either version 2
15 ## of the License, or (at your option) any later version.
16 ##
17 ## This program is distributed in the hope that it will be useful,
18 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 ## GNU General Public License for more details.
21 ##
22 ## You should have received a copy of the GNU General Public License
23 ## along with this program; if not, write to the Free Software
24 ## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
25 ##
26 ###############################################################################
27
28 PATH="/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin"
29 PRG="${0##*/}"
30 VERSION=1.0.2
31 DEBUG=0
32 export LC_COLLATE=C
33
34 ## --version output.
35 version()
36 {
37 echo \
38 "$PRG $VERSION
39 Written by Ethan Benson
40 Portions based on show_of_path.sh written by Olaf Hering
41
42 Copyright (C) 2000, 2001 Ethan Benson
43 Portions Copyright (C) 2000 Olaf Hering
44 This is free software; see the source for copying conditions.  There is NO
45 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
46 }
47
48 ## --help output.
49 usage()
50 {
51 echo \
52 "Usage: $PRG [OPTION]... FILE
53 Find OpenFirmware device path from unix device node.
54
55       --debug                print boring junk only useful for debugging
56   -h, --help                 display this help and exit
57   -V, --version              output version information and exit"
58 }
59
60 ## a small seq replacement, seq is not present on boot/rescue floppies.
61 smallseq()
62 {
63     local v="$1"
64     local n=1
65     echo 1
66     while [ "$v" -gt 1 ] ; do
67         echo "$(($n + 1))"
68         local n="$(($n + 1))"
69         local v="$(($v - 1))"
70     done
71     return 0
72 }
73
74 ## a kludge to replace wc -l, wc is not present on boot/rescue
75 ## floppies. max file is 145 lines, 3 hosts * 16 devs each * 3 lines
76 ## per device, + 1 "Attached Devices:" line.
77 linecount()
78 {
79     if [ $# = 0 ] ; then
80         local file="$(cat)"
81         local v="$file"
82     else
83         local file="$(cat $1)"
84         local v="$file"
85     fi
86
87     if [ -z "$file" ] ; then
88         echo 0
89         return 0
90     fi
91
92     ## use real wc if available
93     if (command -v wc > /dev/null 2>&1) ; then
94         if [ -x `command -v wc` ] ; then
95             lines="$(echo "$file" | wc -l)"
96             if [ $? = 0 ] ; then
97                 echo $lines
98                 unset lines
99                 return 0
100             fi
101         fi
102     fi
103
104     while true ; do
105         for i in `smallseq 145` ; do
106             local b="$(echo "$file" | tail -n $i)"
107             if [ "$v" = "$b" ] ; then
108                 echo "$i"
109                 break 2
110             fi
111         done
112     done
113     return 0
114 }
115
116 ## small tr replacment which handles a specific need of this script.
117 smalltr()
118 {
119     case "$1" in 
120         a) echo 1 ;; b) echo 2 ;; c) echo 3 ;; d) echo 4 ;; e) echo 5 ;; f) echo 6 ;;
121         g) echo 7 ;; h) echo 8 ;; i) echo 9 ;; j) echo 10 ;; k) echo 11 ;; l) echo 12 ;;
122         m) echo 13 ;; n) echo 14 ;; o) echo 15 ;; p) echo 16 ;;
123         1) echo a ;; 2) echo b ;; 3) echo c ;; 4) echo d ;; 5) echo e ;; 
124         6) echo f ;; 7) echo g ;; 8) echo h ;; 9) echo i ;; 10) echo j ;;
125         11) echo k ;; 12) echo l ;; 13) echo m ;; 14) echo n ;; 15) echo o ;;
126         16) echo p ;;
127     esac
128     return 0
129 }
130
131 ## replacment for grep -l which is not supported by busybox grep.
132 ## echo $(cat..) hack needed because busybox grep barfs with `line too
133 ## long' when fed /proc files.  the for loop is needed since busybox
134 ## grep seems to have somewhat broken regexp support.
135 ## usage: lgrep filename regexp regexp ...
136 lgrep()
137 {
138     local f="$1"
139     shift
140     for i in "$@" ; do
141         echo "$(cat "$f")" | grep -q "$i" && echo "$f" && break
142     done
143     return 0
144 }
145
146 ## a function to print relevant scsi host path when there is more then
147 ## one.  this function also takes care of stripping off the trailing
148 ## /compatible.
149 printhost()
150 {
151     case "$1" in
152         1)
153         echo "${2%/*}"
154         ;;
155         2)
156         echo "${3%/*}"
157         ;;
158         3)
159         echo "${4%/*}"
160         ;;
161         4)
162         echo "${5%/*}"
163         ;;
164     esac
165     return 0
166 }
167
168 ## this finds information we need on both newworld and oldworld macs.
169 ## mainly what scsi host a disk is attached to.
170 scsiinfo()
171 {
172     ## see if system has scsi at all
173     if [ ! -f /proc/scsi/scsi ] ; then
174         echo 1>&2 "$PRG: /dev/$DEVNODE: Device not configured"
175         return 1
176     fi
177
178     ## first we have to figure out the SCSI ID, have to do that
179     ## anyway [to] find the attached scsi disks = "Direct-Access" and
180     ## stop at sda=1 sdb=2 or whatever count in 3 lines steps
181
182     ## get last letter of device node, ie sda -> a
183     SUBNODE=${DEVNODE##*sd}
184
185     ## turn SUBNODE above into a number starting at 1, ie a -> 1
186     SUBDEV="$(smalltr $SUBNODE)"
187     [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: SUBNODE=$SUBNODE SUBDEV=$SUBDEV"
188
189     DEVCOUNT=0
190
191     ## copy scsi file into a variable removing "Attached Devices"
192     ## which is the first line. this avoids a lot of
193     ## [incmopatible] crap later, and improves readability.
194
195     ## find number of lines once and recycle that number, to save
196     ## some time (linecount is a bit slow). subtract one line
197     ## to scrap Attached Devices:
198
199     SCSILINES="$(($(linecount /proc/scsi/scsi) - 1))"
200
201     if [ "$SUBDEV" -gt "$(cat /proc/scsi/scsi | grep Direct-Access | linecount)" ] ; then
202         echo 1>&2 "$PRG: /dev/$DEVNODE: Device not configured"
203         return 1
204     fi
205
206     PROCSCSI="$(cat /proc/scsi/scsi | tail -n $SCSILINES)"
207
208     for i in $(smallseq $(($SCSILINES / 3))) ; do
209
210         ## put every scsi device into one single line
211         DEVINFO="$(echo "$PROCSCSI" | head -n $(($i * 3)) | tail -n 3)"
212         [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: DEVINFO=$DEVINFO"
213
214         ## cut the type field, expect "Direct-Access" later.
215         DEVTYPE="$(v=$(echo ${DEVINFO##*Type: }) ; echo ${v%% *})"
216         [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: DEVTYPE=$DEVTYPE"
217
218         ## get the device id.
219         DEVID="$(v=$(echo ${DEVINFO##*Id: }) ; n=$(echo ${v%% *}) ; echo ${n#*0})"
220         [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: DEVID=$DEVID"
221
222         ## get the scsi host id.
223         DEVHOST="$(v=$(echo ${DEVINFO##*Host: scsi}) ; echo ${v%% *})"
224         [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: DEVHOST=$DEVHOST"
225
226         if [ "$DEVTYPE" = "Direct-Access" ] ; then
227             DEVCOUNT="$(($DEVCOUNT + 1))"
228             [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: DEVCOUNT=$DEVCOUNT"
229             if [ "$SUBDEV" = "$DEVCOUNT" ] ; then
230                 DEVICE_HOST=$DEVHOST
231                 DEVICE_ID=$DEVID
232                 [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: DEVICE_HOST=$DEVICE_HOST"
233                 break
234             fi
235         fi
236     done
237
238     ## figure out what the scsi driver is, it is /proc/scsi/dirname.
239     [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: DEVICE_HOST=$DEVICE_HOST"
240     SCSI_DRIVER="$(x=`ls /proc/scsi/*/$DEVICE_HOST 2>/dev/null | cat` ; y=`echo ${x##*proc/scsi/}` ; echo ${y%%/*})"
241     [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: SCSI_DRIVER=$SCSI_DRIVER"
242
243     ## figure out which host we found.
244     SCSI_HOSTNUMBER="$(v=`ls /proc/scsi/$SCSI_DRIVER/* 2>/dev/null | cat | grep -n "$DEVICE_HOST\>"` ; echo ${v%%:*})"
245     [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: SCSI_HOSTNUMBER=$SCSI_HOSTNUMBER"
246
247     return 0
248 }
249
250 ## generic function that can find OF device paths for scsi devices,
251 ## must be run after scsiinfo().
252 scsi_ofpath()
253 {
254     case "$SCSI_DRIVER" in
255         aic7xxx)
256             HOST_LIST="$(for i in `find /proc/device-tree -name compatible` ; do
257                         lgrep "$i" "^ADPT" "^pci900[45]" "^pciclass,01000" ; done)"
258             DEVICE_PATH="$(printhost $SCSI_HOSTNUMBER $HOST_LIST)"
259             echo "${DEVICE_PATH##*device-tree}/@$DEVICE_ID:$PARTITION"
260             ;;
261         sym53c8xx)
262             HOST_LIST="$(for i in `find /proc/device-tree -name compatible` ; do
263                         lgrep "$i" "^Symbios" "^pci1000" "^pciclass,01000" ; done)"
264             DEVICE_PATH="$(printhost $SCSI_HOSTNUMBER $HOST_LIST)"
265             echo "${DEVICE_PATH##*device-tree}/@$DEVICE_ID:$PARTITION"
266             ;;
267         mesh)
268             HOST_LIST="$(for i in `find /proc/device-tree -name compatible` ; do
269                         lgrep "$i" "mesh" ; done)"
270             DEVICE_PATH="$(printhost $SCSI_HOSTNUMBER $HOST_LIST)"
271             echo "${DEVICE_PATH##*device-tree}/@$DEVICE_ID:$PARTITION"
272             ;;
273         *)
274             echo 1>&2 "$PRG: Driver: $SCSI_DRIVER is not supported"
275             return 1
276             ;;
277     esac
278     return 0
279 }
280
281 ## figure out the OpenFirmware device path for newworld macs.
282 ## sd* scsi disks , hd* ide disks.
283 newworld()
284 {
285     case "$DEVNODE" in
286         sd*)
287             if ls -l /proc/device-tree | grep -q ^lr ; then
288                 true
289             else
290                 echo 1>&2 "$PRG: /proc/device-tree is broken.  Do not use BootX to boot, use yaboot."
291                 echo 1>&2 "$PRG: The yaboot FAQ can be found here: http://www.alaska.net/~erbenson/doc"
292                 return 1
293             fi
294
295             ## use common scsiinfo function to get info we need.
296             scsiinfo || return 1
297
298             ## now we have the data for /@$DEVID:$PARTITION
299             ## find the actual OF path. 
300             scsi_ofpath || return 1
301             ;;
302         hda*)
303             local CDROM="$(grep "^drive name:" /proc/sys/dev/cdrom/info 2> /dev/null | grep hda)"
304             if [ -z "$CDROM" ] ; then
305                 echo "hd:$PARTITION"
306             else
307                 echo "cd:$PARTITION"
308             fi
309             ;;
310         hdb*)
311             local CDROM="$(grep "^drive name:" /proc/sys/dev/cdrom/info 2> /dev/null | grep hdb)"
312             if [ -z "$CDROM" ] ; then
313                 echo "ultra1:$PARTITION"
314             else
315                 echo "cd:$PARTITION"
316             fi
317             ;;
318         hd*)
319             local CDROM="$(grep "^drive name:" /proc/sys/dev/cdrom/info 2> /dev/null | grep $DEVNODE)"
320             if [ -z "$CDROM" ] ; then
321                 echo 1>&2 "$PRG: Device: /dev/$DEVNODE is not supported"
322                 return 1
323             else
324                 echo "cd:$PARTITION"
325             fi
326             ;;
327         *)
328             echo 1>&2 "$PRG: Device: /dev/$DEVNODE is not supported"
329             return 1
330             ;;
331     esac
332     return 0
333 }
334
335 oldworld()
336 {
337     ## for some reason 2.4 kernels put OF aliases in aliases@0/ instead of plain aliases/
338     if [ -d "/proc/device-tree/aliases" ] ; then
339         local ALIASES="aliases"
340     elif [ -d "/proc/device-tree/aliases@0" ] ; then
341         local ALIASES="aliases@0"
342     else
343         echo 1>&2 "$PRG: Cannot find OpenFirmware aliases directory in /proc/device-tree/"
344         return 1
345     fi
346
347     local MODEL="$(cat /proc/device-tree/compatible)"
348     [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: Oldworld subarch: $MODEL"
349
350     case "$MODEL" in
351         AAPL,7300*|AAPL,7500*|AAPL,8500*|AAPL,9500*|AAPL,\?\?\?\?*)
352             case "$DEVNODE" in
353                 sd*)
354                 scsiinfo || return 1
355                 case "$SCSI_DRIVER" in
356                     mesh)
357                     echo $(cat /proc/device-tree/$ALIASES/scsi-int)/sd\@$DEVICE_ID:$PARTITION
358                     ;;
359                     53c94)
360                     echo $(cat /proc/device-tree/$ALIASES/scsi)/sd\@$DEVICE_ID:$PARTITION
361                     ;;
362                     *)
363                     echo 1>&2 "$PRG: Driver $SCSI_DRIVER is not supported"
364                     return 1
365                     ;;
366                 esac
367                 ;;
368                 *)
369                 echo 1>&2 "$PRG: Unsupported device: /dev/$DEVNODE"
370                 return 1
371                 ;;
372             esac
373             ;;
374         AAPL,e407*)
375             case "$DEVNODE" in
376                 sd*)
377                 scsiinfo || return 1
378                 case "$SCSI_DRIVER" in
379                     mesh)
380                     echo $(cat /proc/device-tree/$ALIASES/scsi)/sd\@$DEVICE_ID:$PARTITION
381                     ;;
382                     *)
383                     echo 1>&2 "$PRG: Driver $SCSI_DRIVER is not supported"
384                     return 1
385                     ;;
386                 esac
387                 ;;
388                 hda*)
389                 echo $(cat /proc/device-tree/$ALIASES/ata)/ATA-Disk\@0:$PARTITION
390                 ;;
391                 hdb*)
392                 echo $(cat /proc/device-tree/$ALIASES/ata)/ATA-Disk\@1:$PARTITION
393                 ;;
394                 hd*)
395                 echo 1>&2 "$PRG: Device: /dev/$DEVNODE is not supported"
396                 ;;
397             esac
398             ;;
399         AAPL,e826*)
400             case "$DEVNODE" in
401                 sd*)
402                 scsiinfo || return 1
403                 case "$SCSI_DRIVER" in
404                     mesh)
405                     echo $(cat /proc/device-tree/$ALIASES/scsi)/sd\@$DEVICE_ID:$PARTITION
406                     ;;
407                     *)
408                     echo 1>&2 "$PRG: Driver $SCSI_DRIVER is not supported"
409                     return 1
410                     ;;
411                 esac
412                 ;;
413                 hda*)
414                 echo $(cat /proc/device-tree/$ALIASES/ata)/ata-disk\@0:$PARTITION
415                 ;;
416                 hdb*)
417                 echo $(cat /proc/device-tree/$ALIASES/ata)/ata-disk\@1:$PARTITION
418                 ;;
419                 hd*)
420                 echo 1>&2 "$PRG: Device: /dev/$DEVNODE is not supported"
421                 ;;
422             esac
423             ;;
424         AAPL,Gossamer*|AAPL,PowerMac\ G3*)
425             case "$DEVNODE" in
426                 sd*)
427                 scsiinfo || return 1
428                 case "$SCSI_DRIVER" in
429                     mesh)
430                     echo $(cat /proc/device-tree/$ALIASES/scsi)/sd\@$DEVICE_ID:$PARTITION
431                     ;;
432                     *)
433                     echo 1>&2 "$PRG: Driver $SCSI_DRIVER is not supported"
434                     return 1
435                     ;;
436                 esac
437                 ;;
438                 hda*)
439                 echo $(cat /proc/device-tree/$ALIASES/ide0)/ata-disk\@0:$PARTITION
440                 ;;
441                 hdb*)
442                 echo $(cat /proc/device-tree/$ALIASES/ide0)/ata-disk\@1:$PARTITION
443                 ;;
444                 hdc*)
445                 echo $(cat /proc/device-tree/$ALIASES/ide1)/ata-disk\@0:$PARTITION
446                 ;;
447                 hdd*)
448                 echo $(cat /proc/device-tree/$ALIASES/ide1)/ata-disk\@1:$PARTITION
449                 ;;
450                 hd*)
451                 echo 1>&2 "$PRG: Device: /dev/$DEVNODE is not supported"
452                 ;;
453             esac
454             ;;
455         AAPL,PowerBook1998*)
456             if [ -f  /proc/device-tree/$ALIASES/ata0 ] ; then
457                 local ATA0=ata0
458             else
459                 local ATA0=ide0
460             fi
461             if [ -f  /proc/device-tree/$ALIASES/ata1 ] ; then
462                 local ATA1=ata1
463             else
464                 local ATA1=bay-ata1
465             fi
466             case "$DEVNODE" in
467                 sd*)
468                 scsiinfo || return 1
469                 case "$SCSI_DRIVER" in
470                     mesh)
471                     echo $(cat /proc/device-tree/$ALIASES/scsi)/sd\@$DEVICE_ID:$PARTITON
472                     ;;
473                     *)
474                     echo 1>&2 "$PRG: Driver $SCSI_DRIVER is not supported"
475                     return 1
476                     ;;
477                 esac
478                 ;;
479                 hda*)
480                 echo $(cat /proc/device-tree/$ALIASES/$ATA0)/ata-disk\@0:$PARTITION
481                 ;;
482                 hdb*)
483                 echo $(cat /proc/device-tree/$ALIASES/$ATA0)/ata-disk\@1:$PARTITION
484                 ;;
485                 hdc*)
486                 echo $(cat /proc/device-tree/$ALIASES/$ATA1)/atapi-disk\@0:$PARTITION
487                 ;;
488                 hdd*)
489                 echo $(cat /proc/device-tree/$ALIASES/$ATA1)/atapi-disk\@1:$PARTITION
490                 ;;
491                 *)
492                 echo 1>&2 "$PRG: Unsupported device: /dev/$DEVNODE"
493                 return 1
494                 ;;
495             esac
496             ;;
497         AAPL,3400/2400*)
498             case "$DEVNODE" in
499                 sd*)
500                 scsiinfo || return 1
501                 case "$SCSI_DRIVER" in
502                     mesh)
503                     echo $(cat /proc/device-tree/$ALIASES/scsi-int)/sd\@$DEVICE_ID:$PARTITON
504                     ;;
505                     53c94)
506                     echo $(cat /proc/device-tree/$ALIASES/scsi)/sd\@$DEVICE_ID:$PARTITON
507                     ;;
508                     *)
509                     echo 1>&2 "$PRG: Driver $SCSI_DRIVER is not supported"
510                     return 1
511                     ;;
512                 esac
513                 ;;
514                 hda*)
515                 echo $(cat /proc/device-tree/$ALIASES/ata0)/ata-disk\@0:$PARTITION
516                 ;;
517                 hdb*)
518                 echo $(cat /proc/device-tree/$ALIASES/ata0)/ata-disk\@1:$PARTITION
519                 ;;
520                 hdc*)
521                 echo $(cat /proc/device-tree/$ALIASES/ata1)/atapi-disk\@0:$PARTITION
522                 ;;
523                 hdd*)
524                 echo $(cat /proc/device-tree/$ALIASES/ata1)/atapi-disk\@1:$PARTITION
525                 ;;
526                 hde*)
527                 echo $(cat /proc/device-tree/$ALIASES/ata2):$PARTITION
528                 ;;
529                 hdf*)
530                 echo $(cat /proc/device-tree/$ALIASES/ata3):$PARTITION
531                 ;;
532                 *)
533                 echo 1>&2 "$PRG: Unsupported device: /dev/$DEVNODE"
534                 return 1
535                 ;;
536             esac
537             ;;
538         *)
539             echo 1>&2 "$PRG: This machine is not supported: $MODEL"
540             return 1
541             ;;
542     esac
543     return 0
544 }
545
546 ## find OpenFirmware device path for IBM CHRP hardware (scsi only)
547 chrp()
548 {
549     case "$DEVNODE" in
550         sd*)
551             if ls -l /proc/device-tree | grep -q ^lr ; then
552                 true
553             else
554                 echo 1>&2 "$PRG: /proc/device-tree is broken."
555                 return 1
556             fi
557
558             ## use common scsiinfo function to get info we need.
559             scsiinfo || return 1
560
561             ## now we have the data for /@$DEVID:$PARTITION
562             ## find the actual OF path. 
563             scsi_ofpath || return 1
564             ;;
565         *)
566             echo 1>&2 "$PRG: Device: /dev/$DEVNODE is not supported"
567             return 1
568             ;;
569     esac
570     return 0
571 }
572
573 ## If we get lame devfs name, we need to make it foad
574 ckdevfs()
575 {
576     case "$1" in
577         /dev/ide/*|/dev/scsi/*|/dev/discs/*)
578         return 0
579         ;;
580         *)
581         return 1
582         ;;
583     esac
584 }
585
586 ## convert devfs names into normal short ones, written by Tom Rini.
587 fixdevfs()
588 {
589     ## get partition number, if any
590     local PARTNUM="${1##*[a-z]}"
591     ## Find the bus type.
592     local TYPE="$(v=${1#/dev/} ; echo ${v%/host*})"
593     ## Find the host number.
594     local HOST="$(v=${1#/dev/*/host} ; echo ${v%/bus*})"
595     ## Find the bus number.
596     local BUS="$(v=${1#/dev/*/bus} ; echo ${v%/tar*})"
597     ## Find the target.
598     local TARGET="$(v=${1#/dev/*/target} ; echo ${v%/lun*})"
599
600     case "$TYPE" in
601         ide)
602         case "$HOST" in
603             0)
604             case "$TARGET" in
605                 0)
606                 local DEV=hda
607                 ;;
608                 1)
609                 local DEV=hdb
610                 ;;
611             esac
612             ;;
613             1)
614             case "$TARGET" in
615                 0)
616                 local DEV=hdc
617                 ;;
618                 1)
619                 local DEV=hdd
620                 ;;
621             esac
622             ;;
623             *)
624                 echo 1>&2 "$PRG: $1: Unable to translate this device, try again without devfs."
625                 return 1
626         esac
627         local DEV="${DEV}${PARTNUM}"
628         echo "/dev/$DEV"
629         return 0
630         ;;
631         scsi)
632         local LUN="$(v=${1#/dev/*/lun} ; echo ${v%/*})"
633
634         ## In this case, we need to figure out what number our device is
635         local DEVCOUNT=0
636
637         ## copy scsi file into a variable removing "Attached Devices"
638         ## which is the first line. this avoids a lot of
639         ## [incmopatible] crap later, and improves readability.
640
641         ## find number of lines once and recycle that number, to save
642         ## some time (linecount is a bit slow). subtract one line
643         ## to scrap Attached Devices:
644
645         local SCSILINES="$(($(linecount /proc/scsi/scsi) - 1))"
646         local PROCSCSI="$(cat /proc/scsi/scsi | tail -n $SCSILINES)"
647
648         for i in $(smallseq $(($SCSILINES / 3))) ; do
649
650             ## put every scsi device into one single line
651             local DEVINFO="$(echo "$PROCSCSI" | head -n $(($i * 3)) | tail -n 3)"
652             [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: fixdevfs: DEVINFO=$DEVINFO"
653
654             ## cut the type field, expect "Direct-Access" later.
655             local DEVTYPE="$(v=$(echo ${DEVINFO##*Type: }) ; echo ${v%% *})"
656             [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: fixdevfs: DEVTYPE=$DEVTYPE"
657
658             if [ "$DEVTYPE" = "Direct-Access" ] ; then
659                 ## Lets find out some more information
660                 ## get the device id.
661                 local DEVID="$(v=$(echo ${DEVINFO##*Id: }) ; n=$(echo ${v%% *}) ; echo ${n#*0})"
662                 [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: fixdevfs: DEVID=$DEVID"
663
664                 ## get the device lun.
665                 local DEVLUN="$(v=$(echo ${DEVINFO##*Lun: }) ; n=$(echo ${v%% *}) ; echo ${n#*0})"
666                 [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: fixdevfs: DEVLUN=$DEVLUN"
667
668                 ## get the device channel.
669                 local DEVCHAN="$(v=$(echo ${DEVINFO##*Channel: }) ; n=$(echo ${v%% *}) ; echo ${n#*0})"
670                 [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: fixdevfs: DEVCHAN=$DEVCHAN"
671
672                 ## get the scsi host id.
673                 local DEVHOST="$(v=$(echo ${DEVINFO##*Host: scsi}) ; echo ${v%% *})"
674                 [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: fixdevfs: DEVHOST=$DEVHOST"
675
676                 local DEVCOUNT="$(($DEVCOUNT + 1))"
677                 [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: fixdevfs: DEVCOUNT=$DEVCOUNT"
678                 if [ "$DEVHOST" = "$HOST" -a "$DEVCHAN" = "$BUS" -a \
679                     "$DEVID" = "$TARGET" -a "$DEVLUN" = "$LUN" ] ; then
680                     local DEV="sd$(smalltr $DEVCOUNT)${PARTNUM}"
681                     echo "/dev/$DEV"
682                     return 0
683                 fi
684             fi
685         done
686         echo 1>&2 "$PRG: $1: Unable to translate this device, try again without devfs."
687         return 1
688         ;;
689         *)
690         echo 1>&2 "$PRG: Unknown bus $TYPE"
691         return 1
692         ;;
693     esac
694     ## we should never get here
695     return 1
696 }
697
698 ## make sure that find, head and tail can be found.  otherwise the
699 ## script will silently give bogus paths.  these are the only /usr/*
700 ## utilities this script depends on.
701 checkutils()
702 {
703     if command -v find > /dev/null 2>&1 ; then
704         [ -x `command -v find` ] || FAIL=1 ; else FAIL=1 ; fi
705     if command -v head > /dev/null 2>&1 ; then
706         [ -x `command -v head` ] || FAIL=1 ; else FAIL=1 ; fi
707     if command -v tail > /dev/null 2>&1 ; then
708         [ -x `command -v tail` ] || FAIL=1 ; else FAIL=1 ; fi
709
710     if [ "$FAIL" = 1 ] ; then
711         echo 1>&2 "$PRG: \`find', \`head', or \`tail' could not be found, aborting."
712         return 1
713     else
714         return 0
715     fi
716 }
717
718 ## parse command line switches.
719 if [ $# != 0 ] ; then
720     while true ; do
721         case "$1" in
722             -V|--version)
723                 version
724                 exit 0
725                 ;;
726             -h|--help)
727                 usage
728                 exit 0
729                 ;;
730             --debug)
731                 DEBUG=1
732                 shift
733                 ;;
734             -*)
735                 echo 1>&2 "$PRG: unrecognized option \`$1'"
736                 echo 1>&2 "$PRG: Try \`$PRG --help' for more information."
737                 exit 1
738                 ;;
739             "")
740                 echo 1>&2 "$PRG: You must specify a filename"
741                 echo 1>&2 "Try \`$PRG --help' for more information."
742                 exit 1
743                 ;;
744             *)
745                 device="$1"
746                 break
747                 ;;
748         esac
749     done
750 else
751     echo 1>&2 "$PRG: You must specify a /dev device"
752     echo 1>&2 "Try \`$PRG --help' for more information."
753     exit 1
754 fi
755
756 ## check that FILE is a block device and exists.
757 if [ ! -e "$device" ] ; then
758     echo 1>&2 "$PRG: $device: No such file or directory"
759     exit 1
760 elif [ ! -b "$device" ] ; then
761     echo 1>&2 "$PRG: $device is not a block device"
762     exit 1
763 fi
764
765 ## check that we are running on a GNU/Linux system, OSX/BSD does not
766 ## have the same /proc stuff
767 if [ `uname -s` != Linux ] ; then
768     echo 1>&2 "$PRG: This utility will only work with GNU/Linux"
769     exit 1
770 fi
771
772 ## check for ppc, i think uname -m is safe for this...
773 if [ `uname -m` != ppc ] ; then
774     echo 1>&2 "$PRG: This utility will only work on PowerPC hardware"
775     exit 1
776 fi
777
778 ## ofpath cannot live without procfs
779 if [ ! -f /proc/uptime ] ; then
780     echo 1>&2 "$PRG: This utility requires the /proc filesystem"
781     exit 1
782 fi
783
784 ## check for retarded devfs names and tell them to foad.
785 if ckdevfs "$device" ; then
786     device="$(fixdevfs $device)" || exit 1
787 fi
788
789 ## check for newworld mac. use cat hack due to /proc wierdness.
790 if [ "$(v=`cat /proc/cpuinfo 2>/dev/null | grep pmac-generation` ; echo ${v##*:[ ]})" = NewWorld ] ; then
791     SUBARCH=NewWorld
792 elif [ "$(v=`cat /proc/cpuinfo 2>/dev/null | grep pmac-generation` ; echo ${v##*:[ ]})" = OldWorld ] ; then
793     SUBARCH=OldWorld
794 elif (cat /proc/cpuinfo 2>/dev/null | grep ^motherboard | grep -q AAPL) ; then
795     SUBARCH=OldWorld
796 elif (cat /proc/cpuinfo 2> /dev/null | grep ^machine | grep -q 'CHRP IBM') ; then
797     SUBARCH=CHRP
798 else
799     echo 1>&2 "$PRG: This machine is not yet supported"
800     exit 1
801 fi
802
803 ## make sure /proc/device-tree exists
804 if [ ! -d /proc/device-tree ] ; then
805     echo 1>&2 "$PRG: /proc/device-tree does not exist"
806     echo 1>&2 "$PRG: Make sure you compiled your kernel with CONFIG_PROC_DEVICETREE=y"
807     exit 1
808 fi
809
810 ## make sure we have what we need.
811 checkutils || exit 1
812
813 ## get the base device node and scrap /dev/ ie /dev/hda2 -> hda
814 DEVICE="${device##*/}"
815 DEVNODE="${DEVICE%%[0-9]*}"
816 PARTITION="${DEVICE##*[a-z]}"
817
818 ## use appropriate search for right sub arch.
819 case "$SUBARCH" in
820     NewWorld)
821         newworld || exit 1
822         ;;
823     OldWorld)
824         oldworld || exit 1
825         ;;
826     CHRP)
827         chrp || exit 1
828         ;;
829 esac
830
831 exit 0