b4981d79443c1abe323503951998233fec752f02
[yaboot.git] / ybin / ofpath
1 #! /bin/sh
2
3 ###############################################################################
4 ##
5 ## ofpath: determine OpenFirmware path from unix device node
6 ## Copyright (C) 2000, 2001, 2002, 2003 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.7
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, 2002, 2003 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 ## if readlink is missing use a kludge
147 if (command -v readlink > /dev/null 2>&1) ; then
148     true
149 else
150     readlink()
151     {
152         local SYMTARGET="$(v=`ls -l "$1" 2>/dev/null` ; echo ${v##*> })"
153         if [ -n "$SYMTARGET" ] ; then
154             echo "$SYMTARGET"
155             return 0
156         else
157             return 1
158         fi
159     }
160 fi
161
162 ## a function to print relevant scsi host path when there is more then
163 ## one.  this function also takes care of stripping off the trailing
164 ## /compatible.
165 printhost()
166 {
167     case "$1" in
168         1)
169         echo "${2%/*}"
170         ;;
171         2)
172         echo "${3%/*}"
173         ;;
174         3)
175         echo "${4%/*}"
176         ;;
177         4)
178         echo "${5%/*}"
179         ;;
180     esac
181     return 0
182 }
183
184 ## this finds information we need on both newworld and oldworld macs.
185 ## mainly what scsi host a disk is attached to.
186 scsiinfo()
187 {
188     ## see if system has scsi at all
189     if [ ! -f /proc/scsi/scsi ] ; then
190         local kver="$(uname -r)"
191         case "$kver" in
192             2.5.*|2.6.*)
193                 if [ -d /sys/bus/scsi/devices -a \
194                     -n "$(ls /sys/bus/scsi/devices 2>/dev/null)" ] ; then
195                     echo 1>&2 "$PRG: /proc/scsi/scsi does not exist"
196                     echo 1>&2 "$PRG: Make sure you compiled your kernel with CONFIG_SCSI_PROC_FS=y"
197                     return 1
198                 fi
199                 ;;
200         esac
201         echo 1>&2 "$PRG: /dev/$DEVNODE: Device not configured"
202         return 1
203     fi
204
205     ## first we have to figure out the SCSI ID, have to do that
206     ## anyway [to] find the attached scsi disks = "Direct-Access" and
207     ## stop at sda=1 sdb=2 or whatever count in 3 lines steps
208
209     ## get last letter of device node, ie sda -> a
210     SUBNODE=${DEVNODE##*sd}
211
212     ## turn SUBNODE above into a number starting at 1, ie a -> 1
213     SUBDEV="$(smalltr $SUBNODE)"
214     [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: SUBNODE=$SUBNODE SUBDEV=$SUBDEV"
215
216     DEVCOUNT=0
217
218     ## copy scsi file into a variable removing "Attached Devices"
219     ## which is the first line. this avoids a lot of
220     ## [incmopatible] crap later, and improves readability.
221
222     ## find number of lines once and recycle that number, to save
223     ## some time (linecount is a bit slow). subtract one line
224     ## to scrap Attached Devices:
225
226     SCSILINES="$(($(linecount /proc/scsi/scsi) - 1))"
227
228     if [ "$SUBDEV" -gt "$(cat /proc/scsi/scsi | grep Direct-Access | linecount)" ] ; then
229         echo 1>&2 "$PRG: /dev/$DEVNODE: Device not configured"
230         return 1
231     fi
232
233     PROCSCSI="$(cat /proc/scsi/scsi | tail -n $SCSILINES)"
234
235     for i in $(smallseq $(($SCSILINES / 3))) ; do
236
237         ## put every scsi device into one single line
238         DEVINFO="$(echo "$PROCSCSI" | head -n $(($i * 3)) | tail -n 3)"
239         [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: DEVINFO=$DEVINFO"
240
241         ## cut the type field, expect "Direct-Access" later.
242         DEVTYPE="$(v=$(echo ${DEVINFO##*Type: }) ; echo ${v%% *})"
243         [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: DEVTYPE=$DEVTYPE"
244
245         ## get the device id.
246         DEVID="$(v=$(echo ${DEVINFO##*Id: }) ; n=$(echo ${v%% *}) ; echo ${n#*0})"
247         [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: DEVID=$DEVID"
248
249         ## get the scsi host id.
250         DEVHOST="$(v=$(echo ${DEVINFO##*Host: scsi}) ; echo ${v%% *})"
251         [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: DEVHOST=$DEVHOST"
252
253         if [ "$DEVTYPE" = "Direct-Access" ] || [ "$DEVTYPE" = "Direct-Access-RBC" ] ; then
254             DEVCOUNT="$(($DEVCOUNT + 1))"
255             [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: DEVCOUNT=$DEVCOUNT"
256             if [ "$SUBDEV" = "$DEVCOUNT" ] ; then
257                 DEVICE_HOST=$DEVHOST
258                 DEVICE_ID=$DEVID
259                 [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: DEVICE_HOST=$DEVICE_HOST"
260                 break
261             fi
262         fi
263     done
264
265     ## figure out what the scsi driver is, it is /proc/scsi/dirname.
266     [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: DEVICE_HOST=$DEVICE_HOST"
267     SCSI_DRIVER="$(x=`ls /proc/scsi/*/$DEVICE_HOST 2>/dev/null | cat` ; y=`echo ${x##*proc/scsi/}` ; echo ${y%%/*})"
268     [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: SCSI_DRIVER=$SCSI_DRIVER"
269
270     ## figure out which host we found.
271     SCSI_HOSTNUMBER="$(v=`ls /proc/scsi/$SCSI_DRIVER/* 2>/dev/null | cat | grep -n "$DEVICE_HOST\>"` ; echo ${v%%:*})"
272     [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: SCSI_HOSTNUMBER=$SCSI_HOSTNUMBER"
273
274     return 0
275 }
276
277 ## generic function that can find OF device paths for scsi devices,
278 ## must be run after scsiinfo().
279 scsi_ofpath()
280 {
281     case "$SCSI_DRIVER" in
282         aic7xxx)
283             HOST_LIST="$(for i in `find /proc/device-tree -name compatible` ; do
284                         lgrep "$i" "^ADPT" "^pci900[45]" "^pciclass,01000" ; done)"
285             DEVICE_PATH="$(printhost $SCSI_HOSTNUMBER $HOST_LIST)"
286             echo "${DEVICE_PATH##*device-tree}/@$DEVICE_ID:$PARTITION"
287             ;;
288         sym53c8xx)
289             HOST_LIST="$(for i in `find /proc/device-tree -name compatible` ; do
290                         lgrep "$i" "^Symbios" "^pci1000" "^pciclass,01000" ; done)"
291             DEVICE_PATH="$(printhost $SCSI_HOSTNUMBER $HOST_LIST)"
292             echo "${DEVICE_PATH##*device-tree}/@$DEVICE_ID:$PARTITION"
293             ;;
294         mesh)
295             HOST_LIST="$(for i in `find /proc/device-tree -name compatible` ; do
296                         lgrep "$i" "mesh" ; done)"
297             DEVICE_PATH="$(printhost $SCSI_HOSTNUMBER $HOST_LIST)"
298             echo "${DEVICE_PATH##*device-tree}/@$DEVICE_ID:$PARTITION"
299             ;;
300         ata_k2|sata_svw)
301             #Not all G5 device trees have a compatible "k2-sata" node 
302             #per channel use parent
303             HOST_LIST="$(for i in `find /proc/device-tree -name compatible ` ; do
304                         lgrep "$i" "k2-s-ata" ; done | sort)"
305             DEVICE_PATH="$(printhost $SCSI_HOSTNUMBER $HOST_LIST)"
306             K2_DEVICE_ID=0
307             while [ "$DEVICE_PATH" = "" ] ; do
308                 SCSI_HOSTNUMBER=`expr $SCSI_HOSTNUMBER - 1`
309                 let "K2_DEVICE_ID += 1"
310                 DEVICE_PATH="$(printhost $SCSI_HOSTNUMBER $HOST_LIST)"
311             done
312             echo "${DEVICE_PATH##*device-tree}/k2-sata@$K2_DEVICE_ID/disk@0:$PARTITION"
313             ;;
314         usb-storage)
315             HOST_LIST="$(for i in `find /proc/device-tree -name name | grep usb` ; do
316                         lgrep "$i" "disk" ; done)"
317             DEVICE_PATH="$(printhost $SCSI_HOSTNUMBER $HOST_LIST)"
318             echo "${DEVICE_PATH##*device-tree}:$PARTITION"
319             ;;
320         sbp2|"")
321             # sbp-2 driver may not have a dir in /proc/scsi
322             HOST_LIST="$(for i in `find /proc/device-tree -name name` ; do
323                         lgrep "$i" "sbp-2" ; done)"
324             if [ "$SCSI_HOSTNUMBER" = "" ] ; then
325                 SCSI_HOSTNUMBER=1
326             fi
327             DEVICE_PATH="$(printhost $SCSI_HOSTNUMBER $HOST_LIST)"
328             echo "${DEVICE_PATH##*device-tree}/disk@0:$PARTITION"
329             ;;
330         *)
331             echo 1>&2 "$PRG: Driver: $SCSI_DRIVER is not supported"
332             return 1
333             ;;
334     esac
335     return 0
336 }
337
338 ide_ofpath()
339 {
340     if [ ! -L "/proc/ide/$DEVNODE" ] ; then
341         echo 1>&2 "$PRG: /dev/$DEVNODE: Device not configured"
342         return 1
343     fi
344
345     local IDEBUS="$(v=`readlink /proc/ide/$DEVNODE` ; echo ${v%%/*} )"
346     if [ -z "$IDEBUS" ] ; then
347         echo 1>&2 "$PRG: BUG: IDEBUS == NULL"
348         return 1
349     fi
350
351     case "$(uname -r)" in
352         2.5.*|2.6.0*|2.6.1|2.6.1-*|2.6.2|2.6.2-*)
353             echo 1>&2 "$PRG: Linux kernel `uname -r` is not supported"
354             return 1
355             ;;
356         2.6.*|2.7.*)
357             if ! (grep -q '.* .* sysfs ' /proc/mounts 2> /dev/null) ; then
358                 echo 1>&2 "$PRG: sysfs must be mounted for ofpath to support this system"
359                 return 1
360             fi
361             local SYS="$(m=`grep '.* .* sysfs ' /proc/mounts | head -n 1` ; echo `d=${m#* };echo ${d%% *}`)"
362             if [ -z "$SYS" -o ! -d "$SYS" ] ; then
363                 echo 1>&2 "$PRG: Unable to determine sysfs mountpoint"
364                 return 1
365             fi
366             local OF1275IDE="${SYS}/block/${DEVNODE}/device/../../devspec"
367             ;;
368         *)
369             local OF1275IDE="/proc/ide/$IDEBUS/devspec"
370             ;;
371     esac
372
373     if [ ! -f "$OF1275IDE" ] ; then
374         case "$(cat /proc/device-tree/model)" in
375             PowerMac3*|PowerMac4*|PowerMac5*|PowerMac6*|PowerMac7*|RackMac*)
376                 local CDROM="$(grep "^drive name:" /proc/sys/dev/cdrom/info 2> /dev/null | grep $DEVNODE)"
377                 if [ -z "$CDROM" ] ; then
378                     echo 1>&2 "$PRG: WARNING: Your kernel is too old for proper support, device may be innaccurate."
379                     echo "ultra2:$PARTITION"
380                 else
381                     echo "cd:$PARTITION"
382                 fi
383                 ;;
384             *)
385                 local CDROM="$(grep "^drive name:" /proc/sys/dev/cdrom/info 2> /dev/null | grep $DEVNODE)"
386                 if [ -z "$CDROM" ] ; then
387                     if [ "$DEVNODE" = hda ] ; then
388                         echo "hd:$PARTITION"
389                     else
390                         echo "ultra1:$PARTITION"
391                     fi
392                 else
393                     echo "cd:$PARTITION"
394                 fi
395                 ;;
396         esac
397     else
398         local DEVSPEC="$(cat $OF1275IDE)"
399         [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: DEVSPEC=$DEVSPEC"
400         if [ -z "$DEVSPEC" ] ; then
401             echo 1>&2 "$PRG: KERNEL BUG: $OF1275IDE exists, but is empty"
402             return 1
403         fi
404
405         if [ ! -f "/proc/ide/${IDEBUS}/channel" ] ; then
406             echo 1>&2 "$PRG: KERNEL BUG: /proc/ide/${IDEBUS}/channel does not exist"
407             return 1
408         fi
409
410         case "$(cat /proc/device-tree${DEVSPEC}/device_type 2> /dev/null)" in
411             ide|ata)
412                 local MASTER="/disk@0"
413                 local SLAVE="/disk@1"
414                 ;;
415             pci-ide|pci-ata)
416                 local MASTER="/@$(cat /proc/ide/${IDEBUS}/channel)/disk@0"
417                 local SLAVE="/@$(cat /proc/ide/${IDEBUS}/channel)/disk@1"
418                 ;;
419             scsi) ## some lame controllers pretend they are scsi, hopefully all kludges are created equal.
420                 local MASTER="/@$(($(cat /proc/ide/${IDEBUS}/channel) * 2 + 0))"
421                 local SLAVE="/@$(($(cat /proc/ide/${IDEBUS}/channel) * 2 + 1))"
422                 ;;
423             spi)
424                 local MASTER="/disk@$(cat /proc/ide/${IDEBUS}/channel),0"
425                 local SLAVE="/disk@$(cat /proc/ide/${IDEBUS}/channel),1"
426                 ;;
427             *)
428                 echo 1>&2 "$PRG: Unsupported IDE device type: \"$(cat /proc/device-tree${DEVSPEC}/device_type 2> /dev/null)\""
429                 return 1
430                 ;;
431         esac
432
433         case "$DEVNODE" in
434             hda|hdc|hde|hdg|hdi|hdk|hdm|hdo)
435                 echo "${DEVSPEC}${MASTER}:$PARTITION"
436                 return 0
437                 ;;
438             hdb|hdd|hdf|hdh|hdj|hdl|hdn|hdp)
439                 echo "${DEVSPEC}${SLAVE}:$PARTITION"
440                 return 0
441                 ;;
442             *)
443                 echo 1>&2 "$PRG: /dev/$DEVNODE is not supported"
444                 return 1
445                 ;;
446         esac
447     fi
448 }
449
450 ## figure out the OpenFirmware device path for newworld macs.
451 ## sd* scsi disks , hd* ide disks.
452 newworld()
453 {
454     case "$DEVNODE" in
455         sd*)
456             ## use common scsiinfo function to get info we need.
457             scsiinfo || return 1
458
459             ## now we have the data for /@$DEVID:$PARTITION
460             ## find the actual OF path.
461             scsi_ofpath || return 1
462             ;;
463         hd*)
464             ide_ofpath || return 1
465             ;;
466         *)
467             echo 1>&2 "$PRG: Device: /dev/$DEVNODE is not supported"
468             return 1
469             ;;
470     esac
471     return 0
472 }
473
474 oldworld()
475 {
476     ## for some reason 2.4 kernels put OF aliases in aliases@0/ instead of plain aliases/
477     if [ -d "/proc/device-tree/aliases" ] ; then
478         local ALIASES="aliases"
479     elif [ -d "/proc/device-tree/aliases@0" ] ; then
480         local ALIASES="aliases@0"
481     else
482         echo 1>&2 "$PRG: Cannot find OpenFirmware aliases directory in /proc/device-tree/"
483         return 1
484     fi
485
486     local MODEL="$(cat /proc/device-tree/compatible)"
487     [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: Oldworld subarch: $MODEL"
488
489     case "$MODEL" in
490         AAPL,7300*|AAPL,7500*|AAPL,8500*|AAPL,9500*|AAPL,\?\?\?\?*)
491             case "$DEVNODE" in
492                 sd*)
493                 scsiinfo || return 1
494                 case "$SCSI_DRIVER" in
495                     mesh)
496                     echo $(cat /proc/device-tree/$ALIASES/scsi-int)/sd\@$DEVICE_ID:$PARTITION
497                     ;;
498                     53c94)
499                     echo $(cat /proc/device-tree/$ALIASES/scsi)/sd\@$DEVICE_ID:$PARTITION
500                     ;;
501                     *)
502                     echo 1>&2 "$PRG: Driver $SCSI_DRIVER is not supported"
503                     return 1
504                     ;;
505                 esac
506                 ;;
507                 *)
508                 echo 1>&2 "$PRG: Unsupported device: /dev/$DEVNODE"
509                 return 1
510                 ;;
511             esac
512             ;;
513         AAPL,e407*)
514             case "$DEVNODE" in
515                 sd*)
516                 scsiinfo || return 1
517                 case "$SCSI_DRIVER" in
518                     mesh)
519                     echo $(cat /proc/device-tree/$ALIASES/scsi)/sd\@$DEVICE_ID:$PARTITION
520                     ;;
521                     *)
522                     echo 1>&2 "$PRG: Driver $SCSI_DRIVER is not supported"
523                     return 1
524                     ;;
525                 esac
526                 ;;
527                 hda*)
528                 echo $(cat /proc/device-tree/$ALIASES/ata)/ATA-Disk\@0:$PARTITION
529                 ;;
530                 hdb*)
531                 echo $(cat /proc/device-tree/$ALIASES/ata)/ATA-Disk\@1:$PARTITION
532                 ;;
533                 hd*)
534                 echo 1>&2 "$PRG: Device: /dev/$DEVNODE is not supported"
535                 ;;
536             esac
537             ;;
538         AAPL,e826*)
539             case "$DEVNODE" in
540                 sd*)
541                 scsiinfo || return 1
542                 case "$SCSI_DRIVER" in
543                     mesh)
544                     echo $(cat /proc/device-tree/$ALIASES/scsi)/sd\@$DEVICE_ID:$PARTITION
545                     ;;
546                     *)
547                     echo 1>&2 "$PRG: Driver $SCSI_DRIVER is not supported"
548                     return 1
549                     ;;
550                 esac
551                 ;;
552                 hda*)
553                 echo $(cat /proc/device-tree/$ALIASES/ata)/ata-disk\@0:$PARTITION
554                 ;;
555                 hdb*)
556                 echo $(cat /proc/device-tree/$ALIASES/ata)/ata-disk\@1:$PARTITION
557                 ;;
558                 hd*)
559                 echo 1>&2 "$PRG: Device: /dev/$DEVNODE is not supported"
560                 ;;
561             esac
562             ;;
563         AAPL,Gossamer*|AAPL,PowerMac\ G3*)
564             case "$DEVNODE" in
565                 sd*)
566                 scsiinfo || return 1
567                 case "$SCSI_DRIVER" in
568                     mesh)
569                     echo $(cat /proc/device-tree/$ALIASES/scsi)/sd\@$DEVICE_ID:$PARTITION
570                     ;;
571                     *)
572                     echo 1>&2 "$PRG: Driver $SCSI_DRIVER is not supported"
573                     return 1
574                     ;;
575                 esac
576                 ;;
577                 hda*)
578                 echo $(cat /proc/device-tree/$ALIASES/ide0)/ata-disk\@0:$PARTITION
579                 ;;
580                 hdb*)
581                 echo $(cat /proc/device-tree/$ALIASES/ide0)/ata-disk\@1:$PARTITION
582                 ;;
583                 hdc*)
584                 echo $(cat /proc/device-tree/$ALIASES/ide1)/ata-disk\@0:$PARTITION
585                 ;;
586                 hdd*)
587                 echo $(cat /proc/device-tree/$ALIASES/ide1)/ata-disk\@1:$PARTITION
588                 ;;
589                 hd*)
590                 echo 1>&2 "$PRG: Device: /dev/$DEVNODE is not supported"
591                 ;;
592             esac
593             ;;
594         AAPL,PowerBook1998*)
595             if [ -f  /proc/device-tree/$ALIASES/ata0 ] ; then
596                 local ATA0=ata0
597             else
598                 local ATA0=ide0
599             fi
600             if [ -f  /proc/device-tree/$ALIASES/ata1 ] ; then
601                 local ATA1=ata1
602             else
603                 local ATA1=bay-ata1
604             fi
605             case "$DEVNODE" in
606                 sd*)
607                 scsiinfo || return 1
608                 case "$SCSI_DRIVER" in
609                     mesh)
610                     echo $(cat /proc/device-tree/$ALIASES/scsi)/sd\@$DEVICE_ID:$PARTITON
611                     ;;
612                     *)
613                     echo 1>&2 "$PRG: Driver $SCSI_DRIVER is not supported"
614                     return 1
615                     ;;
616                 esac
617                 ;;
618                 hda*)
619                 echo $(cat /proc/device-tree/$ALIASES/$ATA0)/ata-disk\@0:$PARTITION
620                 ;;
621                 hdb*)
622                 echo $(cat /proc/device-tree/$ALIASES/$ATA0)/ata-disk\@1:$PARTITION
623                 ;;
624                 hdc*)
625                 echo $(cat /proc/device-tree/$ALIASES/$ATA1)/atapi-disk\@0:$PARTITION
626                 ;;
627                 hdd*)
628                 echo $(cat /proc/device-tree/$ALIASES/$ATA1)/atapi-disk\@1:$PARTITION
629                 ;;
630                 *)
631                 echo 1>&2 "$PRG: Unsupported device: /dev/$DEVNODE"
632                 return 1
633                 ;;
634             esac
635             ;;
636         AAPL,3400/2400*)
637             case "$DEVNODE" in
638                 sd*)
639                 scsiinfo || return 1
640                 case "$SCSI_DRIVER" in
641                     mesh)
642                     echo $(cat /proc/device-tree/$ALIASES/scsi-int)/sd\@$DEVICE_ID:$PARTITON
643                     ;;
644                     53c94)
645                     echo $(cat /proc/device-tree/$ALIASES/scsi)/sd\@$DEVICE_ID:$PARTITON
646                     ;;
647                     *)
648                     echo 1>&2 "$PRG: Driver $SCSI_DRIVER is not supported"
649                     return 1
650                     ;;
651                 esac
652                 ;;
653                 hda*)
654                 echo $(cat /proc/device-tree/$ALIASES/ata0)/ata-disk\@0:$PARTITION
655                 ;;
656                 hdb*)
657                 echo $(cat /proc/device-tree/$ALIASES/ata0)/ata-disk\@1:$PARTITION
658                 ;;
659                 hdc*)
660                 echo $(cat /proc/device-tree/$ALIASES/ata1)/atapi-disk\@0:$PARTITION
661                 ;;
662                 hdd*)
663                 echo $(cat /proc/device-tree/$ALIASES/ata1)/atapi-disk\@1:$PARTITION
664                 ;;
665                 hde*)
666                 echo $(cat /proc/device-tree/$ALIASES/ata2):$PARTITION
667                 ;;
668                 hdf*)
669                 echo $(cat /proc/device-tree/$ALIASES/ata3):$PARTITION
670                 ;;
671                 *)
672                 echo 1>&2 "$PRG: Unsupported device: /dev/$DEVNODE"
673                 return 1
674                 ;;
675             esac
676             ;;
677         *)
678             echo 1>&2 "$PRG: This machine is not supported: $MODEL"
679             return 1
680             ;;
681     esac
682     return 0
683 }
684
685 ## find OpenFirmware device path for IBM CHRP hardware (scsi only)
686 chrp()
687 {
688     case "$DEVNODE" in
689         sd*)
690             if ls -l /proc/device-tree | grep -q ^d ; then
691                 true
692             else
693                 echo 1>&2 "$PRG: /proc/device-tree is broken."
694                 return 1
695             fi
696
697             ## use common scsiinfo function to get info we need.
698             scsiinfo || return 1
699
700             ## now we have the data for /@$DEVID:$PARTITION
701             ## find the actual OF path.
702             scsi_ofpath || return 1
703             ;;
704         *)
705             echo 1>&2 "$PRG: Device: /dev/$DEVNODE is not supported"
706             return 1
707             ;;
708     esac
709     return 0
710 }
711
712 ## If we get lame devfs name, we need to make it foad
713 ckdevfs()
714 {
715     case "$1" in
716         /dev/ide/*|/dev/scsi/*|/dev/discs/*)
717         return 0
718         ;;
719         *)
720         return 1
721         ;;
722     esac
723 }
724
725 ## convert devfs names into normal short ones, written by Tom Rini.
726 fixdevfs()
727 {
728     ## get partition number, if any
729     local PARTNUM="${1##*[a-z]}"
730     ## Find the bus type.
731     local TYPE="$(v=${1#/dev/} ; echo ${v%/host*})"
732     ## Find the host number.
733     local HOST="$(v=${1#/dev/*/host} ; echo ${v%/bus*})"
734     ## Find the bus number.
735     local BUS="$(v=${1#/dev/*/bus} ; echo ${v%/tar*})"
736     ## Find the target.
737     local TARGET="$(v=${1#/dev/*/target} ; echo ${v%/lun*})"
738
739     case "$TYPE" in
740         ide)
741         case "$HOST" in
742             0)
743             case "$TARGET" in
744                 0)
745                 local DEV=hda
746                 ;;
747                 1)
748                 local DEV=hdb
749                 ;;
750             esac
751             ;;
752             1)
753             case "$TARGET" in
754                 0)
755                 local DEV=hdc
756                 ;;
757                 1)
758                 local DEV=hdd
759                 ;;
760             esac
761             ;;
762             *)
763                 echo 1>&2 "$PRG: $1: Unable to translate this device, try again without devfs."
764                 return 1
765         esac
766         local DEV="${DEV}${PARTNUM}"
767         echo "/dev/$DEV"
768         return 0
769         ;;
770         scsi)
771         local LUN="$(v=${1#/dev/*/lun} ; echo ${v%/*})"
772
773         ## In this case, we need to figure out what number our device is
774         local DEVCOUNT=0
775
776         ## copy scsi file into a variable removing "Attached Devices"
777         ## which is the first line. this avoids a lot of
778         ## [incmopatible] crap later, and improves readability.
779
780         ## find number of lines once and recycle that number, to save
781         ## some time (linecount is a bit slow). subtract one line
782         ## to scrap Attached Devices:
783
784         local SCSILINES="$(($(linecount /proc/scsi/scsi) - 1))"
785         local PROCSCSI="$(cat /proc/scsi/scsi | tail -n $SCSILINES)"
786
787         for i in $(smallseq $(($SCSILINES / 3))) ; do
788
789             ## put every scsi device into one single line
790             local DEVINFO="$(echo "$PROCSCSI" | head -n $(($i * 3)) | tail -n 3)"
791             [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: fixdevfs: DEVINFO=$DEVINFO"
792
793             ## cut the type field, expect "Direct-Access" later.
794             local DEVTYPE="$(v=$(echo ${DEVINFO##*Type: }) ; echo ${v%% *})"
795             [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: fixdevfs: DEVTYPE=$DEVTYPE"
796
797             if [ "$DEVTYPE" = "Direct-Access" ] || [ "$DEVTYPE" = "Direct-Access-RBC" ] ; then
798                 ## Lets find out some more information
799                 ## get the device id.
800                 local DEVID="$(v=$(echo ${DEVINFO##*Id: }) ; n=$(echo ${v%% *}) ; echo ${n#*0})"
801                 [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: fixdevfs: DEVID=$DEVID"
802
803                 ## get the device lun.
804                 local DEVLUN="$(v=$(echo ${DEVINFO##*Lun: }) ; n=$(echo ${v%% *}) ; echo ${n#*0})"
805                 [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: fixdevfs: DEVLUN=$DEVLUN"
806
807                 ## get the device channel.
808                 local DEVCHAN="$(v=$(echo ${DEVINFO##*Channel: }) ; n=$(echo ${v%% *}) ; echo ${n#*0})"
809                 [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: fixdevfs: DEVCHAN=$DEVCHAN"
810
811                 ## get the scsi host id.
812                 local DEVHOST="$(v=$(echo ${DEVINFO##*Host: scsi}) ; echo ${v%% *})"
813                 [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: fixdevfs: DEVHOST=$DEVHOST"
814
815                 local DEVCOUNT="$(($DEVCOUNT + 1))"
816                 [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: fixdevfs: DEVCOUNT=$DEVCOUNT"
817                 if [ "$DEVHOST" = "$HOST" -a "$DEVCHAN" = "$BUS" -a \
818                     "$DEVID" = "$TARGET" -a "$DEVLUN" = "$LUN" ] ; then
819                     local DEV="sd$(smalltr $DEVCOUNT)${PARTNUM}"
820                     echo "/dev/$DEV"
821                     return 0
822                 fi
823             fi
824         done
825         echo 1>&2 "$PRG: $1: Unable to translate this device, try again without devfs."
826         return 1
827         ;;
828         *)
829         echo 1>&2 "$PRG: Unknown bus $TYPE"
830         return 1
831         ;;
832     esac
833     ## we should never get here
834     return 1
835 }
836
837 ## make sure that find, head and tail can be found.  otherwise the
838 ## script will silently give bogus paths.  these are the only /usr/*
839 ## utilities this script depends on.
840 checkutils()
841 {
842     if command -v find > /dev/null 2>&1 ; then
843         [ -x `command -v find` ] || FAIL=1 ; else FAIL=1 ; fi
844     if command -v head > /dev/null 2>&1 ; then
845         [ -x `command -v head` ] || FAIL=1 ; else FAIL=1 ; fi
846     if command -v tail > /dev/null 2>&1 ; then
847         [ -x `command -v tail` ] || FAIL=1 ; else FAIL=1 ; fi
848
849     if [ "$FAIL" = 1 ] ; then
850         echo 1>&2 "$PRG: \`find', \`head', or \`tail' could not be found, aborting."
851         return 1
852     else
853         return 0
854     fi
855 }
856
857 ## parse command line switches.
858 if [ $# != 0 ] ; then
859     while true ; do
860         case "$1" in
861             -V|--version)
862                 version
863                 exit 0
864                 ;;
865             -h|--help)
866                 usage
867                 exit 0
868                 ;;
869             --debug)
870                 DEBUG=1
871                 shift
872                 ;;
873             -*)
874                 echo 1>&2 "$PRG: unrecognized option \`$1'"
875                 echo 1>&2 "$PRG: Try \`$PRG --help' for more information."
876                 exit 1
877                 ;;
878             "")
879                 echo 1>&2 "$PRG: You must specify a filename"
880                 echo 1>&2 "Try \`$PRG --help' for more information."
881                 exit 1
882                 ;;
883             *)
884                 device="$1"
885                 break
886                 ;;
887         esac
888     done
889 else
890     echo 1>&2 "$PRG: You must specify a /dev device"
891     echo 1>&2 "Try \`$PRG --help' for more information."
892     exit 1
893 fi
894
895 ## check that FILE is a block device and exists.
896 if [ ! -e "$device" ] ; then
897     echo 1>&2 "$PRG: $device: No such file or directory"
898     exit 1
899 elif [ ! -b "$device" ] ; then
900     echo 1>&2 "$PRG: $device is not a block device"
901     exit 1
902 fi
903
904 ## check that we are running on a GNU/Linux system, OSX/BSD does not
905 ## have the same /proc stuff
906 if [ `uname -s` != Linux ] ; then
907     echo 1>&2 "$PRG: This utility will only work with GNU/Linux"
908     exit 1
909 fi
910
911 ## check for ppc, i think uname -m is safe for this...
912 if [ `uname -m` != ppc -a `uname -m` != ppc64 ] ; then
913     echo 1>&2 "$PRG: This utility will only work on PowerPC hardware"
914     exit 1
915 fi
916
917 ## ofpath cannot live without procfs
918 if [ ! -f /proc/uptime ] ; then
919     echo 1>&2 "$PRG: This utility requires the /proc filesystem"
920     exit 1
921 fi
922
923 ## check for retarded devfs names and tell them to foad.
924 if ckdevfs "$device" ; then
925     device="$(fixdevfs $device)" || exit 1
926 fi
927
928 ## check for newworld mac. use cat hack due to /proc wierdness.
929 if [ "$(v=`cat /proc/cpuinfo 2>/dev/null | grep pmac-generation` ; echo ${v##*:[ ]})" = NewWorld ] ; then
930     SUBARCH=NewWorld
931 elif [ "$(v=`cat /proc/cpuinfo 2>/dev/null | grep pmac-generation` ; echo ${v##*:[ ]})" = OldWorld ] ; then
932     SUBARCH=OldWorld
933 elif (cat /proc/cpuinfo 2>/dev/null | grep ^motherboard | grep -q AAPL) ; then
934     SUBARCH=OldWorld
935 elif (cat /proc/cpuinfo 2> /dev/null | grep ^machine | grep -q 'CHRP IBM') ; then
936     SUBARCH=CHRP
937 elif (cat /proc/cpuinfo 2>/dev/null | grep ^machine | grep -q 'CHRP Pegasos') ; then
938     SUBARCH=Pegasos
939 else
940     echo 1>&2 "$PRG: This machine is not yet supported"
941     exit 1
942 fi
943
944 ## make sure /proc/device-tree exists
945 if [ ! -d /proc/device-tree ] ; then
946     echo 1>&2 "$PRG: /proc/device-tree does not exist"
947     echo 1>&2 "$PRG: Make sure you compiled your kernel with CONFIG_PROC_DEVICETREE=y"
948     exit 1
949 fi
950
951 ## make sure we have what we need.
952 checkutils || exit 1
953
954 ## get the base device node and scrap /dev/ ie /dev/hda2 -> hda
955 DEVICE="${device##*/}"
956 DEVNODE="${DEVICE%%[0-9]*}"
957 PARTITION="${DEVICE##*[a-z]}"
958
959 ## use appropriate search for right sub arch.
960 case "$SUBARCH" in
961     # Pegasos OF seems to be NewWorld-ish enough to cope with this.
962     NewWorld|Pegasos)
963         newworld || exit 1
964         ;;
965     OldWorld)
966         oldworld || exit 1
967         ;;
968     CHRP)
969         chrp || exit 1
970         ;;
971 esac
972
973 exit 0