#!/bin/ksh # A script to emulate the Solaris format command # Mario Stargard Dec 12 2000 # Mario Stargard May 1 2002 - ported for Tru64 5.1a # LIMITATIONS # Can only have 1024 disks since they are stored in an array. # disklabel(3) requires a non-zero partition to read the label from the disk # and to write a new label to the disk. As a result you cannot change the # partition you are referencing with disklabel, and you must have an # active non-zero partition to reference to read the label from. # cleanup(){ rm -f /tmp/format.$$ rm -f /tmp/format2.$$ } trap "cleanup" 0 1 3 # Parse the command line while getopts f:l:x:d:t:p:smMe c ;do case $c in f|x|t|p|s|m|M|e) print "Not Implemented" print "Exiting..." exit 1 ;; l) print "Use script(1) to capture your session." exit 1 ;; d) case $OPTARG in /dev/disk/*|/dev/rdisk/*) DISK=$( basename $OPTARG |sed 's,[a-h]$,,') ;; dsk*) DISK=$( print $OPTARG |sed 's,[a-h]$,,' ) ;; *) print "Don't know disk $OPTARG" ;; esac ;; \?) print "Usage:" print "format [ -f command-file ] [ -l log-file ] [ -x data-file ] [ -d disk-name ] [ -t disk-type ] [ -p partition-name ] [ -s ] [ -m ] [ -M ] [ -e ] [ disk-list ]" exit 2 ;; esac done shift `expr $OPTIND - 1` # The main menu list mainmenu(){ if scu -f /dev/rdisk/${DISK}c show inquiry 2> /dev/null |grep "Removable Media: Yes" > /dev/null 2>&1 ; then removeable=" eject - eject the disk" else unset removeable fi cat << _HERE_ FORMAT MENU: disk - select a disk partition - select (define) a partition table current - describe the current disk format - format and analyze the disk verify - display current label on disk ${DISK}$removeable help - redisplay this menu quit _HERE_ } # Function to display the current label with # meaningful size information printlabel(){ # If we call this with an argument, then print # the label directly from the disk # else use the tmpfile. # Need to use ksh coprocess for the dangling pipes if [[ -n $1 ]]; then ( print "From disklabel" disklabel -r ${DISK}c ) |& else ( print "From tempfile" cat /tmp/format.$$ ) |& fi sed 's,# ~Cyl .*$,,; /^ [a-h]/s,# .*$,,' <&p | nawk '/bytes\/sector/{ split($0,bps,":") } /^ [a-h]:/{ size = bps[2] * $2 sum = $2 + $3 done = 0 for ( i=3 ; i >= 1 ; i-- ){ if ( size >= 1024 ^ i ){ nsize = size / 1024 ^ i mult = substr("KMG",i,1) printf("%4s %10d %10d %9s %8s %5s %5s # %7.2f %s ", $1, $2, $3, $4, $5, $6, $7, nsize, mult ) done = 1 break } if ( size < 1024 ){ nsize = size printf("%4s %10d %10d %9s %8s %5s %5s # %7d B ", $1, $2, $3, $4, $5, $6, $7, nsize) done = 1 break } } if ( done = 1 ) { printf("%9d\n", sum ) next } } /^#.*fstype/ { printf("%s%14s%11s%10s%9s%6s%7s# Size End Sect\n", $1, $2, $3, $4, $5, $6, $7) } $0 !~ /^#.*fstype/{ print } ' | more -d } # A function to find, list and choose available disks disksel(){ # Only scan once per invocation of format # to populate disks array if [[ -z $scanflag ]]; then scanflag=1 #scu scan edt print "Scanning for SCSI disks..." hwmgr -scan scsi sleep 2 # Set an array # of disks of the form rza9 rzb10 # indexed at zero # Can only have 1024 disks though. # In 5.1, all disks have the form dsk0 set -A disks $( hwmgr -view dev -cat disk | sed -n 's,^.*\(/dev/disk/dsk[0-9][0-9]*\)c *..*$,\1,p' |sed 's,/dev/disk/,,' ) # No need to worry about dev files anymore. That's taken care of # by hwmgr -scan scsi # Check for character file and make # devices as needed #for d in ${disks[*]} ; do # if [[ ! -c /dev/r${d}c ]]; then # # Use a subshell to avoid fussing with pwd. # # Dont need to export d since the variable gets expanded # # before the subshell spawns. # ( cd /dev # ./MAKEDEV $d # ) # fi #done fi # number of lines to display at a time li=10 lstep=$li dcount=0 while [[ $dcount -le ${#disks[*]} ]]; do # Do this until we get a satisfactory answer while : ; do # Print the disk list and prompt for a selection print "AVAILABLE DISK SELECTIONS:" while [[ $dcount -lt ${#disks[*]} && $dcount -lt $li ]] ; do print -n " ${dcount}. " scu -f /dev/rdisk/${disks[$dcount]}c show capacity >/dev/null 2>&1 if [[ $? -eq 0 ]] ; then scu <<-_HERE_ 2>&1 | switch /dev/rdisk/${disks[$dcount]}c show inquiry show capacity _HERE_ nawk -v DEV=${disks[$dcount]} '/Product Identification/{ split($0,prodid,": ") printf("%s <%s ", DEV, prodid[2] )} /Maximum Capacity/{ split($0,cap,"(") printf("(%s>\n", cap[2])} /read capacity/{ printf("(Capacity Unavailable)>\n")}' print -n " " scu -f /dev/rdisk/${disks[$dcount]}c show nexus |sed 's/[ ]*Device:.*, Bus/Bus/; s/, Type.*$//' else print "${disks[$dcount]} " fi let dcount=dcount+1 done print -n "Specify disk (enter its number): " read answer if [[ -z $answer ]]; then # If we are at the end of our list, redisplay list from the start. if [[ $li -ne $dcount || $dcount -eq ${#disks[*]} ]]; then li=0 dcount=0 fi break fi case $answer in +([0-9])) if [[ $answer -lt 0 || $answer -ge $li || -z ${disks[$answer]} ]]; then li=0 dcount=0 break fi DISK=${disks[$answer]} print "" print "Working on disk: $DISK" mainmenu return 0 ;; *) print "Don't know" li=0 dcount=0 break ;; esac done let li=li+lstep done } # Create or modify a partition table partmenu(){ cat << _HERE_ PARTITION MENU: a - change \`a' partition b - change \`b' partition c - change \`c' partition d - change \`d' partition e - change \`e' partition f - change \`f' partition g - change \`g' partition h - change \`h' partition bblock - show boot block type new - create a new table on the disk volname - set a volume name print - display the current table from temp file label - write partition map and label to the disk save - save new disk/partition definitions help - redisplay this menu quit _HERE_ } # A function to right justify strings # $1 is the length of the string, ${#var} # $2 is the width of the field you want sp(){ num=$(( $2 - $1 )) while [[ $num -gt 0 ]]; do sp=" $sp" let num=num-1 done print "$sp" unset num unset sp } # A function to populate the tempfile with the current label # We need format.$$ to work on, and format2.$$ to compare to getlabel(){ disklabel -r ${DISK}c |tee /tmp/format2.$$ > /tmp/format.$$ } # A function to return the first non-zero slice that # starts at 0 and we havent changed nonzero(){ nonzero=$( sdiff -l /tmp/format2.$$ /tmp/format.$$ | sed -n "/^ ${1:-x}:/d; p" | awk '$0 !~ /\|/ && $0 ~ /^ [a-h]:/ && $2 != 0 && $3 == 0 {split($1,part,":") ; printf("%s\n", part[1] ) }' | head -1 ) # If there are no unchanged non-zero partitions available, return 0 # This is reversed on purpose if [[ -z $nonzero ]]; then return 0 else return 1 fi } # A function to show the boot block showboot(){ bblock=$( dd if=/dev/rdisk/${DISK}a count=1 2> /dev/null |od -c |awk '$1 ~ /^0000740$/{ print $10 }' ) case $bblock in 001) print "ufs" ;; @) print "AdvFS" ;; *) print "unknown" ;; esac } partition(){ # Display the menu partmenu # Get the current partition into a tempfile getlabel while : ; do print "" print -n "partition> " read part case $part in [a-h]) # If nonzero returns successfully, then there are no non-zero partitions if nonzero $part ; then print "There would be no non-zero partitions with a zero" print "offset to write out the label to." continue fi totsect=$(awk -F: '/sectors\/unit/{ print $2 }' /tmp/format.$$) bps=$(awk -F: '/bytes\/sector/{ print $2 }' /tmp/format.$$) # Partition type unset answer done=0 while [[ $done -eq 0 ]]; do print -n "Type [advfs/ufs/swap/unused]:" read answer case $answer in a*) type[1]="AdvFS" done=1 ;; uf*) type[1]="4.2BSD" fsize[1]=1024 bsize[1]=8192 cpg[1]=16 done=1 ;; s*) type[1]="swap" done=1 ;; un*) type[1]="unused" done=1 ;; *) : ;; esac done # Start sector unset answer if [[ $done -ne 2 ]] ; then if [[ $part != c ]]; then unset done while [[ -z $done ]]; do print -n "Starting Sector:" read answer case $answer in +([0-9])) if [[ $answer -gt $totsect ]]; then print "There are only $totsect sectors." continue fi start[1]=$answer done=1 ;; *) : ;; esac done else print "Partition c must start at 0." start[1]=0 fi # Partition size sectleft=$(( $totsect - ${start[1]} )) unset answer unset done while [[ -z $done ]]; do print -n "Partition Size[0s, 0.00M, 0.00G, all]:" read answer # Convert to sectors case $answer in +([0-9])[GMs]|+([0-9]).+([0-9])[GM]) case $answer in +([0-9])G|+([0-9]).+([0-9])G) pow=3 ;; +([0-9])M|+([0-9]).+([0-9])M) pow=2 ;; +([0-9])s) pow=0 noconvert=1 ;; esac if [[ -z $noconvert ]]; then answer=$(print "$answer,$pow" | nawk -F, '{ # Dont need to worry about variable # typing; nawk does that for us size=$1 * ( 1024 ^ $2 ) / 512 if ( size != int(size) ) size = size + 1 printf("%d\n", size )}' ) else answer=$(print $answer |sed 's,s$,,') fi unset noconvert if [[ $answer -gt $sectleft ]]; then print "There are only $sectleft sectors." continue elif [[ $answer -eq 0 && $part = c ]]; then print "Can't zero the c partition." continue fi size[1]=$answer done=1 ;; [aA]*) size[1]=$sectleft done=1 ;; *) : ;; esac done print "slice: $part" print "type: ${type[1]}" print "start: ${start[1]}" print "size: ${size[1]}" type[2]="$( sp ${#type[1]} 9 )" start[2]="$( sp ${#start[1]} 10 )" size[2]="$( sp ${#size[1]} 10 )" fsize[2]="$( sp ${#fsize[1]} 8 )" bsize[2]="$( sp ${#bsize[1]} 5 )" cpg[2]="$( sp ${#cpg[1]} 5)" eval ex -s /tmp/format.$$ <<-_HERE_ /^ ${part}:/s,^.*$, ${part}: ${size[2]}${size[1]} ${start[2]}${start[1]} ${type[2]}${type[1]} ${fsize[2]}${fsize[1]} ${bsize[2]}${bsize[1]} ${cpg[2]}${cpg[1]} , w q _HERE_ changedc=1 unset fsize[1] bsize[1] cpg[1] fi ;; bb*) print "The boot block type is retrieved from byte \\\0750 on the disk's" print "first block. It may not be correctly reported after" print "committing a label nor is this a guarantee that the" print "boot block is intact. If in doubt, commit a new boot" print "block with the label function found here." showboot ;; n*) print "This will DESTROY your existing table on" print -n "disk $DISK. Are you sure?[Y/n]" read answer case $answer in [yY]) print "Zeroing..." disklabel -z $DISK print "Adding a default label..." disklabel -rw $DISK rzxx print "Reading label..." getlabel print "Done." ;; *) print "Nothing Done" ;; esac ;; v*) print -n "Volume Name: " read answer ex -s /tmp/format.$$ <<-_HERE_ /^label/s,:.*$,: $answer, w q _HERE_ ;; p*) print "" printlabel ;; l*) print "Ready to Label ${DISK}$nonzero." bootfs=$( awk '/^ a:/ { print $4 }' /tmp/format.$$ ) case $bootfs in 4.2BSD) btype=ufs ;; AdvFS) btype=advfs ;; *) btype=none ;; esac print "What would you like your boot block type to be?" print -n "I think it's currently set to " showboot print "(ufs|advfs|none|quit) [$btype]" read bootype if [[ -z $bootype ]]; then bootype=$btype fi case $bootype in [uU]*) print "Using ufs" type="-t ufs" ;; [aA]*) print "Using advfs" type="-t advfs" ;; [nN]*) print "Using none" type="-n" ;; *) print "Nothing done" continue ;; esac print -n "Labeling..." disklabel -R -r $type ${DISK}$nonzero /tmp/format.$$ rzxx getlabel print "Done." ;; s*) print -n "Filename: " read answer if [[ -n $answer ]]; then cp /tmp/format.$$ $answer else print "Nothing done" fi ;; he*) partmenu ;; q*) diff /tmp/format2.$$ /tmp/format.$$ if [[ $? -ne 0 ]] ; then print "You haven't committed your new disklabel." print "Really exit?[Y/n]" read answer case $answer in [Yy]) return 0 ;; *) : ;; esac else return 0 fi ;; *) print "Huh?" ;; esac done } # Describe the disk current(){ scu -f /dev/rdisk/${DISK}c << _HERE_ |more -d show device show capacity _HERE_ } if [[ -z $DISK ]]; then disksel else print "Working on disk: $DISK" mainmenu fi # Main loop while : ; do print "" print -n "format> " read choice case $choice in d*) disksel ;; p*) partition ;; c*) current ;; f*) print "Low Level format of disk can take a long time" print "and will destroy all information on $DISK." print -n "Are you sure? (Y|n) " read answer case $answer in [yY]*) scu -f /dev/rdisk/${DISK}c time format ;; *) print "Nothing done." esac ;; l*) print "Not implemented" ;; v*) print "" printlabel fromdisk ;; e*) if [[ -n $removeable ]]; then scu -f /dev/rdisk/${DISK}c eject fi ;; h*) mainmenu ;; q*) print "Bye" exit 0 ;; *) print "Huh?" ;; esac done