: ########################################################################## # bootsys_prep # # Prepare a system to be booted from the Ignite-UX install kernel # by modifying the AUTO file in on the boot disk's LIF area. # # @(#) bootsys_prep: $Revision: 10.26 $ # # Note: This script must work on both 10.X and 9.X systems (posix & ksh) # PATH=/usr/bin:/usr/sbin:/opt/ignite/bin:/sbin:/bin:/etc export PATH unset LANG # Need consistant output from commands myname="$0" usage="\ bootsys_prep -n IP-Addr bootsys_prep [-b boot-lif] [-k kernel] [-l loader-opts] [-rvu] -n => Retrieve networking information about lan interface as well as root disk's HW path, and disk free space. -b boot-lif => Use the specified boot lif to update the boot area -k kernel => Location of kernel (default: /stand/INSTALL) -l loader-opts => Options to add to the AUTO file (like dump devices) -r => Don't reboot system -s grace => use shutdown instead of \"reboot -q\" -u => undo the changes to the boot area, restore old AUTO -v => verbose " boot_lif="" r_opt=false n_opt=false u_opt=false ip_addr="" verbose=false kernel="/stand/INSTALL" loader_opts="" shutdown_grace="" ########################################################################## # get_net_info() # # Set the networking information variables: # $lan_hw - default lan interface HW-path that corresponds to $ip_addr # $iface - default lan interface name that corresponds to $ip_addr # $lla - LLA of $iface # $default_route - Default networking route # # This routine uses $ip_addr to determine which interface should be # used for information. # get_net_info() { # # Get networking information about the LAN card corresponding to the # given IP address. # lla="" iface="" netmask="" lanscan | awk '{if ($1 != "Hardware" && $1 != "Path") print $1 " " $2 " " $5}' | \ while read lan_hw lla iface do # see if the interface is configured for this IP - put spaces # around the ip_addr so we don't mactch a subset of an IP if ifconfig $iface 2>/dev/null | fgrep -q " $ip_addr " then break; fi done if [ "$lla" = "" -o "$iface" = "" ] ; then echo "\ ($(hostname)): Could not obtain interface information corresponding to $ip_addr lanscan failed to list the available interfaces. This could be caused by the kernel in place not being the currently booted kernel." >&2 exit 1 fi # # Get the netmask of this interface, the server's default netmask # may not always be correct (15031FSDdt) # netmask=`ifconfig $iface | awk '{if ($3=="netmask") nmask=$4 } END { if ( nmask != "" ) printf ("0x%s\n", nmask) else print "n/a"}'` # # Now get the default routing information. If there are multiple # default routes, then pick the one with a "G" (gateway) flag, and # if there are none with a G, then just pick the first entry. If # no default routes, then set it to "n/a". (See FSDdt22826, and # FSDdt22824) # default_route=$(netstat -rn |awk ' BEGIN {route="n/a"} /^default/ { if (route == "n/a") route=$2; if (match($3, "G") > 0) route=$2 } END {print route}') } ########################################################################## # Get information about the root/boot disk of the system. # # This sets the variable: # root_dev - to the device file path of the root disk # is_lvm - to true/false depending on if the disk is using LVM. # hw_path - the disk disk's HW path if it can be determined. # root_section - hard partitioned section # # get_root_dev_info() { # # Find out what disk is currently the root disk. # root_section=0 root_dev=`mount | awk '{ if($1=="/")print $3}'` # # If mnttab is confused about the root disk and reports /dev/root, # then find the real device by major/minor number. # (Note, This code is similar to that in save_cfg). # if [[ $root_dev = "/dev/root" ]] then # Look in /dev for disk that matches /dev/root major=$(ls -lL /dev/root | awk ' { print $5 } ' ) minor=$(ls -lL /dev/root | awk ' { print $6 } ' ) # Loop through files in /dev to find one that matches find /dev -type b | grep -v /dev/root | xargs ls -l | grep -v "^total" | while read line do dmajor=$(echo $line | awk ' { print $5 } ' ) if [[ $dmajor = $major ]] then dminor=$(echo $line | awk ' { print $6 } ' ) if [[ $dminor = $minor ]] then ddisk=$(echo $line | awk ' { print $NF } ' ) root_dev=$ddisk break fi fi done if [[ $root_dev = "/dev/root" ]] then echo "Root device is shown to be /dev/root. Could not find the real device file.">&2 exit 1 fi fi is_lvm=false # assume false case $root_dev in /dev/dsk/* | /dev+/localroot/dsk/*) # Must be either whole-disk, or hard partitioned disk: # Determine what "section" to use if not a whole-disk # section (note that in 9.X S800, *s2 was the whole-section). # if [ "${root_dev%s2}" != "$root_dev" \ -o "${root_dev%s0}" != "$root_dev" \ -o "${root_dev%d[0-7]}" != "$root_dev" ] then # devices references the whole disk, not a partitioned disk, okay # as-is : else # Get to root secion for use in the AUTO file. non_sec=${root_dev%s*} root_section=${root_dev#${non_sec}s} # Replace section number with section 6 (9.X boot partition) root_dev=${root_dev%s*}s6 fi ;; *) # Must be LVM, or else a non-standard configuration. # # Use one of two ways of getting the real root/boot disk. # This use to use lvlnboot, but there are many ways that # lvlnboot can be unreliable, such as some disks in the # root group being off-line, or there being two "root" # disks in the volume group (an old root group being # imported to the current root group). # So use lvdisplay -v to determine where the data for # the root volume lives. And if that fails (which it # should not), then fall back to lvlnboot: real_root_dev=$(lvdisplay -v $root_dev | awk '{if ($1 ~ "/dev/dsk/.*") {print $1; exit 0}}') if [ "$real_root_dev" != "" ] ; then root_dev=$real_root_dev else # Try using lvlnboot to get the physical volume that the root # FS is on. 9.04 lvlnboot gives some header output to stderr, # so put it to /dev/null root_dev=`lvlnboot -v 2>/dev/null | grep "^Root:" | awk '{print $4}'` if [ ! -f /etc/lvmtab -o "$root_dev" = "" ] ; then echo "\ ERROR($(hostname)): Cannot determine if the root disk is LVM or whole-disk. The device file is not of the form /dev/dsk/*, and either /etc/lvmtab does not exist or the lvlnboot command is not reporting the root disk as expected.">&2 if [ "$verbose" = true ] ; then # Report what info we can for debugging: echo "lvlnboot -v ouput:" lvlnboot -v echo "mount ouput:" mount fi exit 1 fi fi is_lvm=true ;; esac # # Now determine the HW path of the device. # Note that on HPFL disks, there are two "address" words # given by lssf, just use the last one (FSDdt20208) # hw_path="" if [ -x /sbin/lssf -o -x /etc/lssf ] ; then hw_path=$(lssf $root_dev | awk 'BEGIN { p="unknown" } { for(x=1; x< NF; x++) if ($x == "address") p=$(x+1)} END { print p }') else # must be a 9.X S700, no lssf. Just hack apart the minor number # # This ignores that last digit of the minor num (volume number) # which is not part of the modern hw path. # hw_path=$(ls -l $root_dev | awk '{ for(i=3; i < length($6); i++) { ch=substr($6, i, 1) if(ch == "a") ch = "10"; if(ch == "b") ch = "11"; if(ch == "c") ch = "12"; if(ch == "d") ch = "13"; if(ch == "e") ch = "14"; if(ch == "f") ch = "15"; if(i==3) printf("%s", ch); else printf(".%s", ch); } }') fi } ########################################################################## # enlarge_boot_lif new_lif old_lif # # Make $new_lif the same size as $old_lif so that mkboot will not # reduce the size it thinks is being used by the LIF and thus prevent # us from putting back the old LIF if we are asked to (-u) # enlarge_boot_lif() { new_lif="$1" old_lif="$2" typeset -i new_size=$(ls -l $new_lif | awk '{print $5}') typeset -i old_size=$(ls -l $old_lif | awk '{print $5}') # # Need to round $new_size to the nearest 2K boundary since the # PAD file will start at a 2K boundary via the -K2 option. # ((new_size=(($new_size + 2047) / 2048) * 2048)) if [ $new_size -gt $old_size ] ; then # Should not happen: echo "WARNING: New boot-lif is larger than old boot-lif, mkboot may fail." return fi ((pad_size=$old_size - $new_size)) if [ "$pad_size" -eq 0 ] ; then return fi [ "$verbose" = true ] && echo "\tEnlarging the new boot lif to match old one.">&2 prealloc /tmp/pad.$$ $pad_size || return lifcp -K2 -r -T -12290 /tmp/pad.$$ $new_lif:PAD rm -f /tmp/pad.$$ } ########################################################################## # MAIN: # while getopts :rvun:b:k:l:s: opt do case "$opt" in b) boot_lif="$OPTARG";; k) kernel="$OPTARG";; l) loader_opts="$OPTARG";; s) shutdown_grace="$OPTARG";; r) r_opt=true;; u) u_opt=true;; n) n_opt=true ip_addr="$OPTARG";; v) verbose=true;; "?") echo "Unrecognized option: \"-$OPTARG\"">&2 echo "$usage">&2 exit 1;; ":") echo "Argument missing to option: \"-$OPTARG\"">&2 echo "$usage">&2 exit 1;; esac done if [ "$n_opt" = true ] ; then # # bootsys is just wanting us to return some info back... # get_net_info get_root_dev_info # # Obtain the amount of space we have in /stand to hold the kernel # free_space=$(([ -d /stand ] && bdf /stand || bdf /) | \ awk ' {if ($4 != "avail") { if ( NF > 3 ) { printf("%d", $4) } else { getline; printf("%d", $3) } } }' ) for f in /stand/INSTALL /stand/INSTALLFS do if [ -f $f ] ; then # We will be replaceing these files so count tha space as free # Must use printf(%d) to avoid scientific notation... free_space=$(du -s $f | awk 'BEGIN {sum=0} {sum+= ($1 / 2)} END{printf("%d", sum + '$free_space')}') fi done if [ -x /usr/bin/model -o -x /bin/model ] ; then sys_model=$(model) else sys_model=$(uname -m) fi echo ${lan_hw:-"n/a"} ${lla:-"n/a"} ${default_route:-"n/a"} \ ${hw_path:-"n/a"} ${free_space:-"n/a"} ${netmask:-"n/a"} \ ${sys_model:-"n/a"} exit 0 fi if [ ! -f /stand/INSTALL -o ! -f /stand/INSTALLFS ] ; then if [ "$u_opt" = false ] ; then echo "ERROR($(hostname)): cannot access /stand/INSTALL* - failed to copy?">&2 exit 1 fi fi get_root_dev_info if [ "$verbose" = true ] ; then if [ "$is_lvm" = true ] ; then echo "\tBoot disk determined to be: $root_dev" >&2 else echo "\tBoot disk determined to be: $root_dev (section: $root_section)">&2 fi fi # Prepare the boot-lif volume to have the right auto file in it case $(uname -r) in *9.??) # # The 10.X install kernel will not boot from a 9.X system # without having the LIF area updated. So a boot_lif is required. # Also, the mkboot command does not have the "-a" option so # change the auto file in the boot lif prior to applying it. # for fl in /usr/lib/uxbootlf.700 /usr/lib/uxbootlf do # # Determine the orginal boot lif, so that we can make the # new one the same size in case we need to revert back (-u # option) # if [ -f $fl ] ; then orig_boot_lif=$fl break fi done if [ "$boot_lif" = "" ] ; then if [ "$u_opt" = true ] ; then boot_lif="$orig_boot_lif" fi if [ "$boot_lif" = "" ] ; then echo "Error: The -b option was not given to bootsys_prep">&2 echo " A 10.X boot-lif is needed for 9.X systems">&2 exit 1 fi fi if [ "$u_opt" = false ] ; then lifrm ${boot_lif}:AUTO || exit 1 echo "hpux $loader_opts (;$root_section)$kernel" | \ lifcp -K2 -r -T -12289 - ${boot_lif}:AUTO || exit 1 enlarge_boot_lif $boot_lif $orig_boot_lif else echo "\tRestoring orginal boot area." fi [ "$verbose" = true ] && echo "\tRunning mkboot to update boot area.">&2 if [ "$is_lvm" = true ] ; then # MUST preserve the LABEL file on LVM disks. Since the # -u option is not available on S800's prior to 9.04 PCO4 mkboot -p LABEL -b $boot_lif $root_dev || exit 1 else case $(uname -m) in 9000/7*) mkboot -u -b $boot_lif $root_dev || exit 1 ;; *) mkboot -b $boot_lif $root_dev || exit 1 ;; esac fi ;; *) if [ "$u_opt" = false ] ; then # For 10.X and beyond, use mkboot -a mkboot -a "hpux $loader_opts (;$root_section)$kernel" $root_dev || exit 1 # set the primary boot path so the system is sure to reboot # from this disk. if [ -x /usr/sbin/setboot -a "$hw_path" != "" ] ; then if [ "$verbose" = true ] ; then echo "\tEnsuring primary path is set to $hw_path">&2 fi setboot -b on -p $hw_path fi else echo "\tRestoring default AUTO file" mkboot -a "hpux" $root_dev || exit 1 fi ;; esac if [ "$verbose" = true -o "$u_opt" = true ] ; then auto_content=$(lifcp -r ${root_dev}:AUTO -) echo "\tAUTO file set to: \"$auto_content\"">&2 fi if [ "$u_opt" = false ] ; then if [ "$r_opt" = false ] ; then if [ "$shutdown_grace" = "" ] ; then echo "\tRebooting $(hostname) now.">&2 # Run reboot with stdout and stderr being redirected so that remsh does # not hang, and do it in the background so we can exit before reboot. (sync; sleep 2; reboot -q &) > /tmp/reboot.out 2>&1 <&- else echo "\tScheduling shutdown of $(hostname) in $shutdown_grace seconds.">&2 (sleep 2; shutdown -y -r $shutdown_grace &) > /tmp/reboot.out 2>&1 <&- fi else echo "\ \t* Will not reboot $(hostname) because of -r option. It will run \t Ignite-UX on next reboot. If you want to undo the changes to the \t boot area run \"$myname -u\" on $(hostname)">&2 fi else # # Finish undoing other changes. All but removing ourselves # for f in /stand/INSTALL /stand/INSTALLFS /tmp/boot_lif do if [ -f $f ] ; then echo "\tRemoving $f" rm -f $f fi done fi exit 0