1
0
Files
irix-657m-src/eoe/cmd/initpkg/mrcustomrc.sh
2022-09-29 17:59:04 +03:00

1264 lines
34 KiB
Bash

#! /bin/sh
#Tag 0x00000f00
#ident "$Revision $"
# This script is a no op unless executed with nvram mrmode set
# to either custom or customdebug, or unless the force argument
# is given on the command line.
# Contains functions used to implement roboinst hooks.
# Use "iscustom" argument to determine if executing in custom mode.
# Other arguments described at the end. If preceded by "force", the
# function is executed regardless of mrmode.
. mrprofrc
mrmode=`nvram mrmode 2>/dev/null`
if [ "$mrmode" != custom -a "$mrmode" != debug -a "$mrmode" != customdebug -a "$1" != force ]; then
exit 1
fi
if [ "$1" = force ]; then
shift 2>/dev/null
fi
if [ "$1" = iscustom ]; then
exit 0 # test for custom mode
fi
INSTRBASE=/root
BPCLT="/usr/etc/bootpc -dr"
PROCLAIM=/usr/etc/proclaim
PROCONFIG=/etc/config/proclaim.options
PROLEASE=/var/adm/proclaim.data
CUSTOM=/custom
MRNETRC=/etc/mrnetrc
MRMOUNTRC=/etc/mrmountrc
MRLOGRC=/etc/mrlogrc
MRCONF=mrconfig
MRCONFIG=$CUSTOM/$MRCONF
MREXPORTS=$CUSTOM/$MRCONF.exports
INDEXFILE=".index"
LOGOK="logmsg ok"
ERROR="logmsg error"
WARNING="logmsg warning"
INFO="logmsg info"
DEBUG=":"
DEFCUSTOM=/usr/local/boot/roboinst/custom
DEFSERVER=configserver
ROBOINSTLOG=/var/inst/.roboinstlog
ROBOSTATUS=$INSTRBASE/var/inst/.roboinst_status
ROBOREBOOT=$INSTRBASE/etc/rc2.d/S99roboinst
ROUTESFILE=/tmp/static-route.options
PRO_CONFIGDIR=pro_roboinstdir
TMPFILE=/tmp/mrc.$$
TEMPHOST=IRIS
DBGFD=-
LOGGER="logger -t roboinst"
IFCONFIG=/usr/etc/ifconfig
# The highest version of mrconfig we understand.
# DEFVERS is assumed if mrconfig contains no "version" keyword.
MAXVERS=1
DEFVERS=1
# Enable debugging if requested
if [ "$mrmode" = debug -o "$mrmode" = customdebug -o "$mrmode" = test ]; then
DEBUG="logmsg info"
DBGFD=1
fi
# Determine which network interface to use
ifname()
{
# this works even if there are interfaces without
# miniroot drivers:
hinv -c network | sed -ne 's/^Integr.* \([a-z][a-z]*0\),.*$/\1/p'
}
# Determine the hardware address
systemid()
{
$BPCLT -f `ifname` 2>/dev/null | grep '^chaddr=' | sed 's/^chaddr=//'
}
# Send a log message to various places
logmsg()
{
if [ "$1" = "ok" ]; then
shift 2>/dev/null ; mstate="$1" ; shift 2>/dev/null
msg="state=$mstate status=0 $*"
elif [ "$1" = "error" ]; then
shift 2>/dev/null ; mstate="$1" ;
shift 2>/dev/null ; mstatus="$1" ; shift 2>/dev/null
msg="state=$mstate status=$mstatus error: $*"
elif [ "$1" = "warning" ]; then
shift 2>/dev/null
msg="warning: $*"
elif [ "$1" = "info" ]; then
shift 2>/dev/null
msg="$*"
else
msg="$*"
fi
$LOGGER "$msg"
echo "roboinst: $msg"
if [ -f $ROBOINSTLOG ]; then
# queue remote msgs until loghost is known
echo "$msg" >> $ROBOINSTLOG
fi
}
dbgmsg()
{
while read dbline; do
$DEBUG "$dbline"
done
}
dirname()
{
ans=`/usr/bin/expr "${1:-.}/" : '\(/\)/*[^/]*//*$' `
if [ -n "$ans" ];then
echo $ans
else
ans=`/usr/bin/expr "${1:-.}/" : '\(.*[^/]\)//*[^/][^/]*//*$' `
if [ -n "$ans" ];then
echo $ans
else
echo "."
fi
fi
}
# Generate statements of the form: "A=val ; export A ; B=val ; export B ; "
# to represent SGI_CAPACITY and SGI_CAP_<device>
disk_capacity()
{
# Set SGI_CAP_<device>
(cd /dev/scsi && ls -1|grep '^sc'|xargs -n10 scsicontrol -c \
| sed -n 's/^sc\([0-9]*\)d\([0-9]*\)l\([0-9]*\):.*capacity=\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*/SGI_CAP_dks\1d\2vol=\4 ; export SGI_CAP_dks\1d\2vol ; /p')
# Set SGI_CAPACITY for root device
( cd /dev/rdsk && \
rootdev=`stat -rq root` && \
test "$rootdev" && \
for f in dks* ; do
test "$f" && \
test "`stat -rq $f`" = "$rootdev" && {
ff=`echo $f|sed -n 's/^dks\([0-9]*\)d\([0-9]*\)s\([0-9]*\)/dks\1d\2/p'`
echo "SGI_CAPACITY=\$SGI_CAP_${ff}vol ; export SGI_CAPACITY ; "
break;
}
done )
}
# Build the export file $MREXPORTS. This holds environment
# variables that will be exported over the course of the miniroot
# session. We only construct the file once, then . it in later
# invocations of mrcustomrc.
build_exports()
{
inst -H > $TMPFILE 2>&-
SGI_CPUBOARD=`sed -n 's/^CPUBOARD=//p' $TMPFILE`
SGI_CPUARCH=`sed -n 's/^CPUARCH=//p' $TMPFILE|grep -iv MIPS`
SGI_VIDEO=`sed -n 's/^VIDEO=//p' $TMPFILE`
SGI_ABI=`sed -n 's/^CPUARCH=//p' $TMPFILE|grep -i MIPS`
SGI_GFXBOARD=`sed -n 's/^GFXBOARD=//p' $TMPFILE`
SGI_SUBGR=`sed -n 's/^SUBGR=//p' $TMPFILE`
SGI_MODE=`sed -n 's/^MODE=//p' $TMPFILE`
SGI_MACHINE=`sed -n 's/^MACHINE=//p' $TMPFILE`
rm -f $TMPFILE 2>&-
SGI_ROOT=$INSTRBASE
SGI_CUSTOM=$CUSTOM
SGI_SYSID=`systemid`
SGI_IPADDR=`nvram netaddr 2>&-`
SGI_HOSTNAME=`sed -n p /etc/sys_id 2>&-`
SGI_MEMSIZE=`hinv | sed -n 's/.*Main memory size: \([0-9]*\) Mbytes.*/\1/p'`
tapedevice=`nvram tapedevice 2>&-`
bootfile=`echo "$tapedevice" | sed -e 's;.*bootp();;' -e 's;\([^ ()]*\).*;\1;'`
SGI_BOOTSERVER=`echo "$bootfile" | sed -n 's;:.*;;p'`
SGI_BOOTDIR=`echo "$bootfile" | sed -e 's;.*:;;' -e 's;^/sa$;/;' -e 's;/sa;;' -e 's;^sa$;.;'`
configfile=`nvram mrconfig 2>&-`
# determine whether to use DHCP or skip it.
# default is to use DHCP, so that empty $configfile does the right thing
# NOTE: the special character check is in multiple locations!
case "$configfile" in
!*)
# don't do any DHCP stuff
SGI_NETINQUIRY="NONE"
configfile=`echo "$configfile" | sed -e 's/^!//'`
;;
+*)
# DHCP assigns IP address if it is available
SGI_NETINQUIRY="DHCP"
configfile=`echo "$configfile" | sed -e 's/^+//'`
;;
%*|*)
# use extended BOOTP protocol
# (use IP address from nvram, but ask for network parameters)
SGI_NETINQUIRY="BOOTP1533"
configfile=`echo "$configfile" | sed -e 's/^%//'`
;;
esac
SGI_CONFIGSERVER=`echo "$configfile" | sed -n 's;:.*;;p'`
SGI_CONFIGDIR=`echo "$configfile" | sed -e 's;.*:;;'`
SGI_SYSTEMPART=`devnm / | sed 's/. .*/0/' | xargs basename`
SGI_SYSTEMDISK=`echo "$SGI_SYSTEMPART" | sed 's/s[0-9]*$//'`
rm -f $MREXPORTS 2>&-
( for var in SGI_CPUBOARD SGI_GFXBOARD SGI_SUBGR SGI_VIDEO \
SGI_CPUARCH SGI_ABI SGI_MODE SGI_MACHINE \
SGI_ROOT SGI_CUSTOM \
SGI_SYSID SGI_IPADDR SGI_HOSTNAME \
SGI_BOOTSERVER SGI_BOOTDIR SGI_CONFIGSERVER SGI_CONFIGDIR \
SGI_SYSTEMPART SGI_SYSTEMDISK \
SGI_MEMSIZE SGI_NETINQUIRY ; do
eval "echo \"\$$var\"" | \
sed -e 's/"/\\"/g' \
-e 's/\(.*\)/'$var'="\1"; export '$var'/'
done
disk_capacity 2>&-
) > $MREXPORTS
}
# tftp remote file ($1) to local file ($2) using
# mode ($3). Suppress msg if quiet is 1 ($4).
dotftp()
{
tstat=0
if [ "$3" != "" ]; then
MODE=$3
else
MODE=binary
fi
test "$4" != 1 && $DEBUG "tftp $1 $2"
tftp <<- EOF >$TMPFILE 2>&1
mode $MODE
get $1 $2
quit
EOF
test "$?" != 0 -o ! -f "$2" && {
cat $TMPFILE
tstat=1
}
rm -f $TMPFILE >/dev/null 2>&1
return $tstat
}
# test whether a file ($1) has the expected size ($2)
chksize()
{
test "$2" = "" && return 0
s=`/sbin/stat -qs $1`
test "$s" != "$2" && \
{ $ERROR init 1 "Size mismatch for $1 $s (expected $2)";
$ERROR init 1 "Try re-running roboinst_config on the configuration directory";
return 1; }
return 0
}
# test whether a file ($1) has the expected checksum ($2)
chksum()
{
test "$2" = "" && return 0
s=`sum -r $1 | nawk '{print $1}'`
test "$s" != "$2" && \
{ $ERROR init 1 "Checksum mismatch for $1 $s (expected $2)";
$ERROR init 1 "Try re-running roboinst_config on the configuration directory";
return 1; }
return 0
}
# $1 = remote pathname, $2 = local pathname, $3 = tftp(0)/rcp(1), $4= attrs
filecopy()
{
type=""
size=""
sum=""
mode=""
# parse valid attrs into local vars
eval ` echo "$4" | \
nawk \
' { for (i=1; i <= NF; ++i)
if (match($i,"^size=")) {
s=substr($i,RSTART+RLENGTH,length($i)-RLENGTH);
if (match(s,"^[0-9][0-9]*$"))
printf("size=%s;",s);
} else if (match($i,"^sum=")) {
s=substr($i,RSTART+RLENGTH,length($i)-RLENGTH);
if (match(s,"^[0-9][0-9]*$"))
printf("sum=%s;",s);
} else if (match($i,"^type=")) {
s=substr($i,RSTART+RLENGTH,length($i)-RLENGTH);
if (match(s,"^[fd]*$"))
printf("type=%s;",s);
} else if (match($i,"^mode=")) {
s=substr($i,RSTART+RLENGTH,length($i)-RLENGTH);
if (match(s,"^[0-7][0-7]*$"))
printf("mode=%s;",substr(s,length(s)-3,3));
}
} ' `
if [ "$type" = "" -o "$type" = "f" ]; then
if [ $3 -eq 0 ]; then
dotftp $1 $2
else
rcp -v $1 $2 >&$DBGFD 2>&$DBGFD
fi
( test $? -eq 0 &&
chksize $2 $size &&
chksum $2 $sum &&
chmod $mode $2 ) || return 1
elif [ "$type" = "d" ]; then
$DEBUG "mkdir $2"
( mkdir -p $2 &&
chmod $mode $2 ) || return 1
else
$ERROR init 1 "Unknown filetype $type"
return 1
fi
return 0
}
# $1 = remote dir (from), $2 = local dir (to), $3 = tftp(0) or rcp(1)
dircopy()
{
mkdir -p $2 || return 1
rm -f $2/$INDEXFILE >/dev/null 2>&1
if [ $3 -eq 0 ]; then
dotftp $1/$INDEXFILE $2/$INDEXFILE ascii 1
else
rcp -v $1/$INDEXFILE $2/$INDEXFILE >&$DBGFD 2>&$DBGFD
fi
( test $? -eq 0 && test -s $2/$INDEXFILE) || {
$DEBUG "dircopy: no index file $1/$INDEXFILE"
rm -f $2/$INDEXFILE >/dev/null 2>&1 # in case it was empty
if [ $3 -eq 0 ]; then
dotftp $1/$MRCONF $2/$MRCONF ascii 1
else
rcp -v $1/$MRCONF $2/$MRCONF >&$DBGFD 2>&$DBGFD
fi
( test $? -eq 0 && test -s $2/$MRCONF) || {
$DEBUG "dircopy: no configuration file $1/$MRCONF"
rm -f $2/$MRCONF >/dev/null 2>&1 # in case it was empty
return 1
}
return 0
}
( ret=0;
while read pathname attrs ; do
echo "$pathname" | grep '^#' >/dev/null || \
filecopy $1/$pathname $2/$pathname $3 "$attrs" || ret=1
done;
return $ret ) < $2/$INDEXFILE || return 1
return 0
}
# Copy the remote scripts ($1) to a local dir ($2),
# $3 is the hardware address, and $4 is the IP address
# ($3 and $4 and not currently used.)
getcustom()
{
remote="$1"
local="$2"
$DEBUG "getcustom $1 $2 $3 $4"
for src in $remote
do
rm -fr $local >/dev/null 2>&1
dircopy $src $local 0 && {
$LOGOK custom "using configuration $src"
return 0
}
done
echo "$remote" | grep "^.*@.*:" > /dev/null || \
remote="guest@$remote"
for src in $remote
do
rm -fr $local >/dev/null 2>&1
dircopy $src $local 1 && {
$LOGOK custom "using configuration $src"
return 0
}
done
rm -fr $local >/dev/null 2>&1
return 1
}
# Preprocess the setenv and if/then/else conditionals
# in the mrconfig file, and generate separate files such
# as /custom/mrconfig.preinst for each phase.
preprocess()
{
test -f $MRCONFIG && \
nawk -v p=1 -v top=-1 -v cfg=$MRCONFIG \
'function unexpected(kwd,line)
{ printf "ERROR: unexpected \"%s\" keyword at line %d\n", kwd, line; }
BEGIN { # the files for these phases are written
# raw, without the #!/bin/sh heading and
# opening environment section.
special["partition"] = 1;
special["onerror"] = 1;
special["loghost"] = 1;
special["version"] = 1;
special["nokernel"] = 1;
special["inst"] = 1;
# for these phases, write a separate side-file
# that contains the environment.
sepenv["inst"] = 1;
# slines[scount] is an array containing all
# the setenv commands we have seen thus far.
scount =0;
# name of temp file for variable expansions
srand;
envfile = "/tmp/roboenv" rand;
}
{ if (match($1, "^#")) {
next;
} else if ($1 == "if") {
sub($1,"",$0);
if ($NF == "then")
sub("then[ \t]*$","",$0);
t = p ? system(envargs " " $0) : 0;
pstack[++top] = p;
ifstack[top] = "if";
tstack[top] = t;
p = p && (t == 0);
next;
} else if ($1 == "elsif" || $1 == "elif") {
if (ifstack[top] != "if" && ifstack[top] != "elsif")
{ unexpected($1, FNR); next; }
sub($1,"",$0);
if ($NF == "then")
sub("then[ \t]*$","",$0);
ifstack[top] = "elsif";
if ((top < 0 || pstack[top]) && tstack[top] != 0)
t = system(envargs " " $0);
else
t = 1;
if (tstack[top] == 0)
t = 1;
else
tstack[top] = t;
p = (top < 0 || pstack[top]) && (t == 0);
next;
} else if ($1 == "else") {
if (ifstack[top] != "if" && ifstack[top] != "elsif")
{ unexpected($1, FNR); next; }
ifstack[top] = "else";
p = (top < 0 || pstack[top]) && (tstack[top] != 0);
next;
} else if ($1 == "endif" || $1 == "fi") {
if (ifstack[top] != "if" && ifstack[top] != "elsif" && ifstack[top] != "else")
{ unexpected($1, FNR); next; }
p = pstack[top--];
next;
}
if (!p) next;
if (match($1, "setenv>?") && length($2) > 0) {
# expand the envargs string for later use in
# this nawk script (when we run condition
# subprocesses above), and also save the environment
# setting in the file mrconfig.setenv.
var = $2;
val = $0;
sub("^[ \t]*setenv>?[ \t]+" var "[ \t]*", "", val);
if (!match(val, "^[A-Za-z0-9_\.\-]*$")) {
# do shell expansion
syscmd=sprintf(envargs " echo %s > %s", val, envfile);
system(syscmd);
getline val < envfile;
close(envfile);
}
ENVIRON[var] = val;
gsub("\"", "\\\"", val);
envargs = envargs var "=\"" val "\" ; export " var " ; ";
outfile = cfg ".setenv";
setcmd = sprintf ("%s=\"%s\"; export %s", var, val, var);
printf "%s\n", setcmd > outfile;
slines[scount++] = setcmd;
} else if (NF > 0) {
# save this line in corresponding output file
line = $0;
phase = $1;
sub(">$","",phase);
outfile = cfg "." phase;
if (!seenfile[phase]) {
seenfile[phase] = 1;
if (!special[phase]) {
# unless this phase is 'special', write the
# interpreter line, and any lines from the
# mrconfig.setenv file we have accumulated thus far.
printf "#!/bin/sh\n" > outfile
for (s=0; s<scount; ++s)
printf "%s\n", slines[s] > outfile;
system("chmod 755 " outfile);
}
if (sepenv[phase]) {
# some phases needed a separate environment file
# so remember the current contents of mrconfig.setenv
# as mrconfig.setenv.inst, for example.
system("cp " cfg ".setenv " cfg ".setenv." phase " 2>&-");
}
}
sub("^[ \t]*" phase ">?($|[ \t])", "", line);
if (special[phase]) {
# do envvar substitution for phases that
# are not interpreted by /bin/sh
while (1) {
if (match(line, "^\\$[A-Za-z_]+"))
;
else if (match(line, "[^\\\\]\\$[A-Za-z_]+"))
{ RSTART += 1; RLENGTH -=1 }
else
break;
line = substr(line,1,RSTART-1) \
ENVIRON[substr(line, RSTART+1, RLENGTH-1)] \
substr(line,RSTART+RLENGTH,length(line));
}
}
if (phase == "partition") {
# substitute systemdisk keywords in partition statements
w="";
if (match(line, "^[ \t]*")) w=substr(line, RSTART, RLENGTH);
if (sub("^[ \t]*systemdisk", "", line)) {
# if partition was omitted assume 0
if (match(line, "^[0-9]|^vh|^vol"))
line = w ENVIRON["SGI_SYSTEMDISK"] "s" line; # dks0d1 + s + line
else
line = w ENVIRON["SGI_SYSTEMPART"] line; # dks0d1s0
}
}
printf "%s\n", line > outfile;
}
}
END { system(sprintf("rm %s 2>&-", envfile)) }' $MRCONFIG
}
# Derive the fstab from the partition statements in the mrconfig
# file, and print results on stdout
buildfstab()
{
nawk ' { if ($3 != "swap" && $4 != "nomount") {
dev = match($1,"^/") ? $1 : "/dev/dsk/" $1;
type = $3;
dir = $4;
sub("/.*","",type);
if (type == "option" || type == "root")
type = "xfs";
if (type != "xfs" && type != "nfs" && type != "efs")
next;
opt = ""
# optional mount options are terminated
# by optional semicolon.
for (i=5; i <= NF && $i != ";"; ++i)
if (opt == "")
opt = $i;
else
opt = opt " " $i;
if (opt == "") {
if (type == "nfs") {
opt="ro,soft,bg"
} else {
rdev=dev;
sub("^/dev/dsk", "/dev/rdsk", rdev);
opt = "rw,raw=" rdev;
}
}
if (dir != "")
printf "%s %s %s %s 0 0\n", dev, dir, type, opt;
}
} ' $MRCONFIG.partition 2>&-
}
# Run user sh commands in the mrconfig file labeled with
# pattern ($1). Additional args ($2, $3, ...) are passed
# as positional parameters.
runuser()
{
phase=$1
runfile=$MRCONFIG.$phase
shift
if [ -x $runfile ]; then
$runfile $*
istat=$?
if [ $istat = 0 ]; then
$LOGOK $phase ok
else
$ERROR $phase "$istat" "failed"
fi
fi
}
# converts $1 IP address (or netmask) argument to hex format
tohex()
{
echo $1 | awk -F. '
/^0x/ && NF == 1 {a=substr($1,3);printf "%s\n",a; exit 0}
NF == 2 {printf "%02x%06x\n",$1,$2; exit 0}
NF == 3 {printf "%02x%02x%04x\n",$1,$2,$3; exit 0}
NF == 4 {printf "%02x%02x%02x%02x\n",$1,$2,$3,$4; exit 0}
{exit 1}
'
}
# Initial client discovery, determine hostname, ipaddress,
# and fetch contents of /custom directory.
startcustom()
{
# Create a file that queues state message to be delivered to
# loghost after we know it's IP address.
touch $ROBOINSTLOG
# Log the fact that we've reached miniroot state.
$LOGOK miniroot "miniroot booted"
# determine which interface to use and configure
# enough networking to use broadcast
/sbin/ioconfig -f /hw
cd /dev; ./MAKEDEV MAXPTY=10 MAXGRO=4 MAXGRI=4 tape scsi > /dev/null
chkconfig -f network on
interface=`ifname`
# determine whether/what dhcp mode to do
configfile=`nvram mrconfig 2>/dev/null`
$DEBUG "using nvram configfile= $configfile"
# NOTE: the special character check is in multiple locations!
case "$configfile" in
!*)
# skip DHCP totally, use nvram netaddr for IP address
doproclaim=n
tmpaddr=`nvram netaddr`
tmpid=0x`tohex $tmpaddr`
configfile=`echo $configfile | sed -e 's/^!//'`
;;
+*)
# DHCP mode == assign IP and network parameters
doproclaim=y
pro_opts="-i"
configfile=`echo $configfile | sed -e 's/^+//'`
# generate a pseudo random address on the test network
eval `/usr/etc/bootpc -t | nawk \
' { srand($2); a=int(rand()*253)+2;
if (a>254) a=254;
printf("tmpaddr=192.0.2.%d\n",a);
printf("tmpid=0xc00002%02x\n",a); }' `
;;
%*|*)
# extended BOOTP 1533 mode == ask for network parameters only
# use IP address from nvram netaddr
doproclaim=y
tmpaddr=`nvram netaddr`
tmpid=0x`tohex $tmpaddr`
pro_opts="-B"
configfile=`echo $configfile | sed -e 's/^%//'`
;;
esac
$DEBUG "after cleanup: configfile= $configfile, doproclaim= $doproclaim, pro_opts= $pro_opts"
if [ "$interface" = "" ]; then
$ERROR custom 1 "unable to determine network interface"
else
$DEBUG "using temp addr $tmpaddr and hostid $tmpid for client discovery"
$IFCONFIG $interface inet $tmpaddr up netmask 255.255.255.0
hostid $tmpid
fi
$DEBUG "networking for proclaim: `$IFCONFIG -a`"
# See what parameters we can get from bootp
# Derive -bbootfile from tapedevice, or use "" for local boot
# -i0 tells bootp to tell us our ip address
# -x6 yields about a 12 second timeout
tmp=` nvram tapedevice 2>/dev/null || echo 0 `
bootopt=` echo "$tmp" | sed -n 's;.*bootp()\([^ ()]*\).*;-b\1;p' `
$BPCLT -i0 -x6 $bootopt > $TMPFILE 2>&$DBGFD
$DEBUG "trace: after call to $BPCLT -i0 -x6 $bootopt"
if [ -s $TMPFILE ]; then
bootpnetaddr=`sed -n 's/^yiaddr=//p' $TMPFILE`
bootpserver=`sed -n 's/^bootpserver=//p' $TMPFILE`
bootpaddr=`sed -n 's/^bootpaddr=//p' $TMPFILE`
chaddr=`sed -n 's/^chaddr=//p' $TMPFILE`
fi
rm -f $TMPFILE > /dev/null 2>&1
if test "$doproclaim" = "y" ; then
# See what configuration parameters DHCP provides
# dhcp option 18 - extensions file (see rfc for registered numbers)
# dhcp option 40 - nis domain name (see rfc for registered numbers)
# dhcp option 3 - router list (see rfc for registered numbers)
# dhcp option 15 - dns domain name (see rfc for registered numbers)
# dhcp option 33 - static routes (see rfc for registered numbers)
# dhcp option 1 - subnet mask (see rfc for registered numbers)
mkdir -p /etc/config
cat > $PROCONFIG <<-!!
ShutdownOnExpiry: 0
DHCPoptionsToGet: 1,3,15,18,33,40
!!
$PROCLAIM $pro_opts -q >&$DBGFD 2>&$DBGFD &
propid=$!
sleep 20
kill $propid 2>&- # proclaim timeout is not reliable
$DEBUG "trace: after call to $PROCLAIM $pro_opts -q"
if test -s $PROLEASE ; then
# TAKE CARE: the following expressions contain true TABs.
dhcpserver=`sed -n 's/^[ ]*DHCPserverName:[ ]*//p' $PROLEASE`
dhcpaddr=`sed -n 's/^[ ]*ServerIPaddress:[ ]*//p' $PROLEASE`
dhcpnetaddr=`sed -n 's/^[ ]*HostIPaddress:[ ]*//p' $PROLEASE`
hostname=`sed -n 's/^[ ]*HostName:[ ]*//p' $PROLEASE`
netmask=`sed -n 's/^[ ]*NetworkMask:[ ]*//p' $PROLEASE`
extfile=`sed -n 's/^[ ]*ExtensionsPathname:[ ]*//p' $PROLEASE`
domain=`sed -n 's/^[ ]*DNSdomainName:[ ]*//p' $PROLEASE`
nisdomain=`sed -n 's/^[ ]*NISdomainName:[ ]*//p' $PROLEASE`
routers=`sed -n 's/^[ ]*Routers:[ ]*//p' $PROLEASE`
staticroutes=`sed -n 's/^[ ]*StaticRoutes:[ ]*//p' $PROLEASE`
$DEBUG "proclaim received hostname=$hostname"
$DEBUG "proclaim received netaddr=$dhcpnetpaddr netmask=$netmask"
$DEBUG "proclaim received extfile=$extfile domain=$domain nisdomain=$nisdomain"
$DEBUG "proclaim received routers=$routers staticroutes=$staticroutes"
fi
fi
$DEBUG "trace: after possible proclaim call"
# remember the current IP address and set the IP address
# from DHCP or BOOTP.
oldaddr=`nvram netaddr 2>/dev/null`
if $MRNETRC validaddr "$dhcpnetaddr" ; then
$INFO "ip address $dhcpnetaddr (from DHCP server $dhcpserver)"
netaddr=$dhcpnetaddr
nvram netaddr $netaddr
if [ -n "$netmask" ] ; then
# if we've got it, use it! (same below)
nvram netmask "$netmask" 2>/dev/null
fi
elif $MRNETRC validaddr "$bootpnetaddr" ; then
$INFO "ip address $bootpnetaddr from bootp server $bootpserver"
netaddr=$bootpnetaddr
nvram netaddr $netaddr
if [ -n "$netmask" ] ; then
nvram netmask "$netmask" 2>/dev/null
fi
else
$INFO "assuming existing IP address $oldaddr"
netaddr=$oldaddr
fi
# Determine hostname from DHCP if possible, otherwise from
# /root/etc/sys_id, otherwise pick something.
$DEBUG "trace: before mount /root"
$MRMOUNTRC rootonly >&$DBGFD 2>&$DBGFD
rm $ROBOSTATUS 2>&- # remove the status script
if [ "$hostname" ]; then
fullname="$hostname"
if [ "$domain" ] ; then
fullname="$fullname.$domain"
fi
$INFO "hostname $hostname (from DHCP server $dhcpserver)"
else
hostname=`nawk '{ if (length($0)) print ; exit }' /root/etc/sys_id 2>&-`
if [ "$hostname" != "" ]; then
$INFO "using most recent hostname $hostname"
else
hostname=$TEMPHOST
$INFO "using default hostname $hostname for now"
fi
fi
# Start minimal networking.
echo "$hostname" > /etc/sys_id
$MRNETRC startdefaultinterface "" /root
$DEBUG "mrcustomrc minimal networking: `$IFCONFIG -a`"
/bin/rm -f $ROUTESFILE
# setup static and default routes
if [ "$staticroutes" != "" ] ; then
# process all static routes
echo "$staticroutes" | /usr/bin/nawk '{for (i=1; i<NF; i=i+3){
j=i+1; if ($j != "-") {
system ("echo static route format botch! \"$0\" 1>&2")
exit 1;}
j=i+2;
print "route add net", $i, $j;
}}' > $ROUTESFILE
fi
if [ "$routers" != "" ] ; then
# use only the first pingable router as default gateway
for r in $routers ; do
$DEBUG "Trying gateway $r ..."
if /usr/etc/ping -nqQr -c 1 -w 3 $r >&$DBGFD 2>&$DBGFD ; then
$DEBUG "Setting default route to $r"
echo route add net default $r >> $ROUTESFILE
break;
fi
done
fi
test -s "$ROUTESFILE" && . $ROUTESFILE
umount /root >&$DBGFD 2>&$DBGFD
echo Waiting for routed initialization >&$DBGFD ; sleep 10
$MRNETRC netisup || $ERROR custom 2 "network configuration problem"
if [ "$bootpaddr" = "" ]; then
# if server has no bootptab, it will not respond to any bootp
# request that has client ip addr 0 (tell me my ip addr).
# So, try again w/o -i0 flag to at least get server's ip addr
# for our host file. This is very useful info.
$BPCLT -x6 $bootopt > $TMPFILE 2>&$DBGFD
if [ -s $TMPFILE ]; then
bootpserver=`sed -n 's/^bootpserver=//p' $TMPFILE`
bootpaddr=`sed -n 's/^bootpaddr=//p' $TMPFILE`
fi
fi
test "$bootpaddr" != "" -a "$bootpserver" != "" && \
$MRNETRC sethostaddr $bootpserver $bootpaddr
test "$dhcpaddr" != "" -a "$dhcpserver" != "" -a \
"$dhcpserver" != "$bootpserver" && \
$MRNETRC sethostaddr $dhcpserver $dhcpaddr
# Determine the location of the client's configuration directory,
# In the following order of preference:
# nvram mrconfig variable
# dhcp variable pro_roboinstdir from the vendor-extensions file
# default directory on the dhcpserver
# default directory on the bootpserver
# default directory on a host called "configserver"
# cleanup nvram mrconfig.
# NOTE: the special character check is in multiple locations!
configdir=`nvram mrconfig 2>/dev/null | sed -e 's/^[%!+]//'`
$DEBUG "trace: before Find Configuration Directory: configdir= $configdir"
if [ "$configdir" = "" -a "$extfile" != "" ]; then
(echo "$extfile" | grep "..*:" >/dev/null ) || {
# fallback on dhcpserver
extfile="$dhcpserver:$extfile"
}
rm -f $TMPFILE >/dev/null 2>&1
tftp <<- EOF >/dev/null 2>&1
get $extfile $TMPFILE
quit
EOF
if [ -s $TMPFILE ]; then
# dhcp_bootp config file format
configdir=`grep '^[ \t]*'$PRO_CONFIGDIR'[ \t]*:[ \t]*' $TMPFILE | \
sed 's/^[ ]*'$PRO_CONFIGDIR'[ ]*:[ ]*//'`
test "$configdir" \
&& (echo "$configdir" | grep -v "..*:" > /dev/null) \
&& configdir="$dhcpserver:$configdir"
else
$WARNING "unable to find DHCP extensions file $extfile"
fi
rm -f $TMPFILE >/dev/null 2>&1
fi
if [ "$configdir" = "" ]; then
if [ "$dhcppserver" ]; then
configdir="$dhcpserver:$DEFCUSTOM"
elif [ "$bootpserver" ]; then
configdir="$bootpserver:$DEFCUSTOM"
else
configdir="$DEFSERVER:$DEFCUSTOM"
fi
fi
# Copy the client configuration directory onto the miniroot
$DEBUG "trace: after Find Configuration Directory: configdir= $configdir"
getcustom "$configdir" $CUSTOM "$chaddr" "$netaddr"
if [ ! -d $CUSTOM ]; then
$ERROR custom 3 "unable to retrieve configuration from $configdir"
return 1
fi
# Compute the values of the SGI_ roboinst variables once,
# and store them in a file for use during the remainder
# of the miniroot session.
build_exports
test -s $MREXPORTS && . $MREXPORTS
# pre-process the mrconfig file to create a series
# of mrconfig.<phase> files that are access later in
# the miniroot session.
preprocess
# Verify that we understand this version of mrconfig
mrversion=`nawk '{if ($1 != "") { print $1; exit }}' $MRCONFIG.version 2>&-`
if [ "$mrversion" = "" ]; then
mrversion=$DEFVERS
fi
$DEBUG "mrversion= $mrversion"
if [ "$mrversion" -gt $MAXVERS ]; then
rm -rf $CUSTOM 2>&-
$ERROR custom 4 "mrconfig with invalid version $mrversion. This miniroot only understands mrconfig versions up through $MAXVERS."
return 1
fi
# Start remote logging if requested
loghosts=`cat $MRCONFIG.loghost 2>&-`
# filter out attempts to remote log to this host
thisipaddr="$netaddr"
loghost=""
for host in $loghosts ; do
if [ "$host" = "localhost" ]; then
ipaddr=$thisipaddr
else
ipaddr=`$MRNETRC gethostaddr $host`
if [ $? != 0 ]; then
ipaddr=$host
fi
fi
if [ "$ipaddr" != "$thisipaddr" ]; then
loghost="$loghost $host"
fi
done
if [ "$loghost" ]; then
$INFO "loghost $loghost"
echo "$loghost" > $MRCONFIG.loghost 2>&$DBGFD
$MRLOGRC addhost $loghost
if [ -f $ROBOINSTLOG ]; then
# Send any queued messages only to remote hosts
# since they are already in local syslog
$MRLOGRC localoff
$LOGGER -f $ROBOINSTLOG
$MRLOGRC localon
rm -f $ROBOINSTLOG
fi
fi
# We are done with the initial processing.
# Run user init commands immediately.
runuser init
}
#-------------- main procedures -----------------------
cmd="$1"
shift 2>/dev/null
test -s $MREXPORTS && . $MREXPORTS
case "$cmd" in
start)
startcustom
;;
stop)
$LOGOK stop "restarting system"
# Write the .roboinst_status script that sends "reboot complete"
# message to loghost after client reboots.
loghost=`cat $MRCONFIG.loghost 2>&-`
cat 2>&- >$ROBOSTATUS <<EOF
#! /bin/sh
#Tag 0x00000f00
# /var/inst/.roboinst_status
# created by /etc/mrcustomrc
LOGHOST="$loghost"
cp /etc/syslog.conf /etc/syslog.conf.new.\$\$ 2>&-
for HOST in \$LOGHOST ; do
echo '*.debug;kern,syslog.none @'\$HOST >> /etc/syslog.conf.new.\$\$
done
cp /etc/syslog.conf /etc/syslog.conf.old.\$\$
mv /etc/syslog.conf.new.\$\$ /etc/syslog.conf
killall -HUP syslogd
logger -t roboinst "state=reboot status=0 reboot completed"
mv /etc/syslog.conf.old.\$\$ /etc/syslog.conf
killall -HUP syslogd
EOF
chmod +x $ROBOSTATUS 2>&-
cat 2>&- >$ROBOREBOOT <<EOF
#! /sbin/sh
#Tag 0x00000f00
# On startup, execute any roboinst operations pending in the
# file /var/inst/.roboinst_status. This will send a summary
# message (either system rebooted, or system never reached miniroot)
# to the remote syslog.
set `who -r`
new_runlevel=\$3
if [ "\$new_runlevel" = "2" ] ; then
if [ -x /var/inst/.roboinst_status ]; then
/var/inst/.roboinst_status
mv /var/inst/.roboinst_status /var/inst/.roboinst_status.O 2>&-
fi
fi
EOF
chmod +x $ROBOREBOOT 2>&-
sleep 2 # wait for msg before shutting down
;;
run)
runuser $*
;;
mounthook)
# Before the disks are mounted, update the fstab on
# the root drive according to mrconfig.
buildfstab > /tmp/mrfs$$
if [ -s /tmp/mrfs$$ ]; then
cat /tmp/mrfs$$ | dbgmsg
mkdir -p /root/etc
cp /tmp/mrfs$$ /root/etc/fstab
fi
rm -f /tmp/mrfs$$ 2>/dev/null
;;
fx)
# Execute any scripted fx commands before mounting any disks.
# If an fx script has been supplied, use that instead.
# Perform any partitioning
test -s $MRCONFIG.partition && \
nawk '{if ($3 != "nfs") print}' $MRCONFIG.partition > $TMPFILE 2>&-
if [ -s $TMPFILE ]; then
(echo "fx -s" ; cat $TMPFILE) | dbgmsg
fx -x -s $TMPFILE
$LOGOK autofx ok # fx -s does not report status
fi
rm -f $TMPFILE >/dev/null 2>&1
# Run any user-requested fx operations
runuser fx || fxstat=$?
;;
mkfs)
# Make any filesystems requested with partition keywords
# Input lines are of the form:
# partition size type mountpoint mount-opt ... ; mkfs-opt ... ;
# Semicolons are only required to separate option types, or to
# specify mkfs options when there are no mount options.
# The mount options begin at word 5, up to but not including the
# the next semicolon (if present). The mkfs options follow, up to
# but not including the next semicolon (if present).
nawk ' BEGIN {
types[0] = "efs";
types[1] = "xfs";
types[2] = "root";
types[3] = "option";
ntypes = 4;
}
{ blksz = "";
device = $1;
for (i=0; i < ntypes; ++i) {
s = $3;
if (s == types[i])
break;
else if (sub("^" types[i] "/", "", s)) {
blksz = s
break;
}
}
if (i < ntypes) {
if (types[i] == "efs")
blksz = "512";
else if (blksz == "")
blksz = "4096";
type = types[i];
if (type != "efs")
type = "xfs";
# skip mount options
j = 4
while (++j <= NF && $j != ";")
;
# remember mkfs options
opt = ""
while (++j <= NF && $j != ";")
opt = opt " " $j
printf "/dev/dsk/%s %s %s %s\n", device, type, blksz, opt
}
}' $MRCONFIG.partition > $TMPFILE 2>&-
if [ -s $TMPFILE ]; then
mkstat=0
while read dev fstype bsize mkfsopts; do
$DEBUG "mrmkfsrc -a $dev $fstype $bsize $mkfsopts"
mrmkfsrc -a $dev $fstype $bsize $mkfsopts || mkstat=$?
done < $TMPFILE
if [ $mkstat = 0 ]; then
$LOGOK automkfs ok
else
$ERROR automkfs $mkstat "error occurred during filesystem creation"
fi
fi
rm -f $TMPFILE >/dev/null 2>&1
# Run any user-requested fx operations
runuser mkfs
;;
preinst) # Run the pre-inst phase
# try to start standard networking if we can find the "live"
# configuration. Try to revert to what we had if we get any errors
# This is as late as possible, while still providing a chance to
# override networking setup in the mrconfig file before installing
$MRNETRC safestart
test -s "$ROUTESFILE" && . $ROUTESFILE
runuser preinst $*
;;
inst) # Run the inst phase
# Pass the appropriate value of abort_cmdfile_on_error depending
# on the onerror keyword, so that inst goes interactive in
# case of conflicts or other errors.
onerror=`nawk '{ if ($1 != "") { print $1; exit} }' $MRCONFIG.onerror 2>&-`
if [ "$onerror" = wait ]; then
# inst will stop and give a prompt on error
errflag="-Vabort_cmdfile_on_error:on"
else
# inst will continue despite any errors
errflag="-Vabort_cmdfile_on_error:off"
fi
if [ -s $MRCONFIG.inst ]; then
echo quit >> $MRCONFIG.inst
# execute inst, using the mrconfig.setenv.inst file
# that was determined during preprocessing
( test -s $MRCONFIG.setenv.inst && . $MRCONFIG.setenv.inst;
inst -c $MRCONFIG.inst -Vinteractive:off $errflag -Vsyslog:on $* )
if [ $? = 0 ]; then
$LOGOK inst ok
else
$ERROR inst $? "Error occurred during software installation"
fi
fi
rm -f $TMPFILE 2>/dev/null
;;
postinst) # Run the post-inst phase
runuser postinst $*
;;
autoconfig) # Run autoconfig and report status, unless
# nokernel keyword is present
noauto=0
test -f $MRCONFIG.nokernel && noauto=1
if [ "$noauto" = 1 ]; then
$LOGOK kernel "skipping kernel build"
autostatus=0
else
mrconfigrc
autostatus=$?
if [ "$autostatus" = 0 ]; then
$LOGOK kernel "kernel is configured"
else
$ERROR kernel 1 "failed configuring kernel"
fi
fi
exit $autostatus
;;
*)
echo "Usage: $0 {start|run phase|configure|etc...}"
;;
esac