rc.frisbee 17.8 KB
Newer Older
1
#!/bin/sh
Leigh B. Stoller's avatar
Leigh B. Stoller committed
2
#
Mike Hibler's avatar
Mike Hibler committed
3
# Copyright (c) 2000-2015 University of Utah and the Flux Group.
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
# 
# {{{EMULAB-LICENSE
# 
# This file is part of the Emulab network testbed software.
# 
# This file is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or (at
# your option) any later version.
# 
# This file is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public
# License for more details.
# 
# You should have received a copy of the GNU Affero General Public License
# along with this file.  If not, see <http://www.gnu.org/licenses/>.
# 
# }}}
Leigh B. Stoller's avatar
Leigh B. Stoller committed
23
#
24 25 26 27 28 29
# Optional flag argument says "do not reboot"
#
reboot=1
if [ $# -eq 1 -a "$1" = "-noreboot" ]; then
    reboot=0
fi
Leigh B. Stoller's avatar
Leigh B. Stoller committed
30

31 32
echo "`date`: rc.frisbee starting"

33 34 35 36 37 38
#
# Amount of memory in MB to leave for everyone else in the system.  If you
# get out-of-memory or vm_pager error while running frisbee, increase this.
#
RESIDMEM=32

39 40 41 42 43 44
#
# Maximum socket buffer size in KB.
# Big enough to buffer a whole chunk.
#
MAXSOCKBUF=1024

45 46 47 48
if [ -r /etc/emulab/paths.sh ]; then
	. /etc/emulab/paths.sh
else
	BINDIR=/etc/testbed
49
	BOOTDIR=/etc/testbed
50 51 52 53 54 55 56
	ETCDIR=/etc/testbed
fi

# Behave a little different on widearea nodes.
isrem=0
if [ -e $ETCDIR/isrem ]; then
    isrem=1
57
fi
58

59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
#
# Extract a variable of interest from the VAR=VALUE string and return value.
# If variable does not exist, return the given default (if provided).
#
getvar() {
    _VAR=$1
    _STR=$2
    _DFL=$3

    for _kv in $_STR; do
	_k=${_kv%%=*}
	if [ -n "$_k" -a "$_k" = "$_VAR" ]; then
	    echo "${_kv##*=}"
	    return 0
	fi
    done
    echo "$_DFL"
    return 0
}

79 80 81 82 83 84 85
#
# Update the MBR of the given disk to the indicated "version."
#
# XXX this is somewhat of a hack right now.  We recognize two
# versions of the MBR:
#	v1 (partition 1 size 6281352)
#	v2 (partition 1 size 12305790)
86
#	v3 (partition 1 size 33554432)
87 88 89 90 91 92
# Currently we only install a new MBR if the existing one is the
# wrong size, just in case the user has customized the boot program.
#
tweakmbr() {
    _DSK=$1
    _NEW=$2
93
    _ALWAYS=$3
94 95 96 97 98 99 100 101 102 103 104 105

    dd if=/dev/$_DSK of=/dev/null bs=512 count=1 2>/dev/null || {
	echo "WARNING: could not read from $_DSK, MBR not changed"
	return
    }

    _size=`fdisk -s $_DSK 2>/dev/null | sed -n -e 's/^ *1: *[0-9][0-9]* *\([0-9][0-9]*\).*$/\1/p'`
    case ${_size}s in
    6281352s)
	_CUR=1
	;;
    12305790s)
106
	_CUR=2
107
	;;
108 109 110
    33554432s)
	_CUR=3
	;;
111 112
    s)
        # special case: no part1 so probably no MBR at all, make sure we install
113
	echo "Found no MBR on $_DSK, installing version $_NEW"
114 115 116
	_CUR=1000000
	;;
    *)
117 118 119 120 121 122 123
        if [ $_ALWAYS -eq 1 ]; then
	    echo "WARNING: overwriting unknown MBR on $_DSK with version $_NEW"
	    _CUR=1000000
	else
	    echo "WARNING: custom MBR on $_DSK, not changed"
	    return
	fi
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
    	;;
    esac

    if [ $_CUR = $_NEW ]; then
	return
    fi

    # now set it if we can
    if [ ! -r "/etc/emulab/mbr${_NEW}.dd" ]; then
	echo "WARNING: cannot find MBR version $_NEW, not installed"
	return
    fi

    echo "Installing MBR version $_NEW ..."
    dd if=/etc/emulab/mbr${_NEW}.dd of=/dev/$_DSK bs=512 count=1
}

141
find_disks() {
Mike Hibler's avatar
Mike Hibler committed
142 143 144
    _DISKS=""
    for d in `sed -n 's/^\([a-z]*[0-9][0-9]*\): [0-9][0-9]*MB/\1/p' /var/run/dmesg.boot`; do
	case $d in
145
	    ad*|da*|ar*|aacd*|amrd*|mfid*|mfisyspd*) _DISKS="$_DISKS $d"
Mike Hibler's avatar
Mike Hibler committed
146 147
	esac
    done
148

Mike Hibler's avatar
Mike Hibler committed
149
    echo $_DISKS
150 151
}

152 153 154 155 156 157 158 159 160 161 162
#
# Function to zero all potential superblocks in the DOS partitions that
# could interfere with the OSes on the image being loaded.
#
# FreeBSD 4 or 5 goes out of its way to make this hard.  In FBSD4, we
# cannot overwrite the beginning of partitions that have a legit superblock.
# In FBSD5, DOS partitions that have a zero type cannot even be accessed.
# So we have to use the whole-disk special file using offsets extracted
# via fdisk.
#
zapsuperblocks() {
Mike Hibler's avatar
Mike Hibler committed
163
    _DSK=$1
164

165 166 167 168 169 170 171 172
    echo "Invalidating old potential superblocks on $_DSK"
    if [ -x "$BINDIR/zapdisk" ]; then
	$BINDIR/zapdisk -v -SZ /dev/$_DSK
	return
    fi

    # XXX fall back to the old way

173 174 175 176
    #
    # Note we are not overly concerned about the consequences of misparsing
    # the fdisk output.  If we whack random blocks, it doesn't hurt anything.
    #
Mike Hibler's avatar
Mike Hibler committed
177
    offs=`fdisk -s $_DSK 2>/dev/null | sed -n -e 's/^[ 0-9]*: *\([0-9]*\).*$/\1/p'`
178 179 180 181 182

    if [ x"$offs" = x ]; then
        return
    fi

Mike Hibler's avatar
Mike Hibler committed
183
    echo -n "Invalidating old potential superblocks on $_DSK: "
184 185
    for off in $offs; do
        echo -n "$off "
Mike Hibler's avatar
Mike Hibler committed
186
	dd if=/dev/zero of=/dev/${_DSK} oseek=$off count=16 >/dev/null 2>&1 || {
187 188 189 190 191 192 193 194
	    echo "WARNING: failed to invalidate $off"
	}
    done
    echo ""

    return
}

195 196 197 198
#
# Function to load a single image on a disk
#
loadone() {
199 200 201 202
    _DISK=$1
    _PART=$2
    _LOADINFO=$3
    _NUM=$4
Mike Hibler's avatar
Mike Hibler committed
203 204 205

    echo "Loading image #$_NUM"

206 207 208 209 210 211 212 213 214
    ADDR=`getvar ADDR "$_LOADINFO"`;
    SERVER=`getvar SERVER "$_LOADINFO" $BOSSIP`;
    PARTOS=`getvar PARTOS "$_LOADINFO" unknown`;
    ZFILL=`getvar ZFILL "$_LOADINFO" 0`;
    MBRVERS=`getvar MBRVERS "$_LOADINFO" 1`;
    PREPARE=`getvar PREPARE "$_LOADINFO" 0`;
    IMAGEID=`getvar IMAGEID "$_LOADINFO"`;
    KEEPALIVE=`getvar KEEPALIVE "$_LOADINFO"`;
    OSVERSION=`getvar OSVERSION "$_LOADINFO" 0`;
215

216 217 218 219 220 221 222 223 224 225 226 227
    #
    # XXX If KEEPALIVE is not explicitly set, attempt to intuit a value.
    #
    # It appears that FreeBSD 8.x's IGMP v3 implementation doesn't
    # properly sent V2 reports when it is connected to a V2-only querier
    # (switch). It insists on sending V3 reports event when the default
    # version is set to 2. So if detect that we have the newer IGMP
    # implementation, we will use the V2 keep alive mechanism in the
    # frisbee client.
    #
    if [ -z "$KEEPALIVE" ]; then
	igmpversion=`sysctl -n net.inet.igmp.default_version 2>/dev/null`
228
	if [ -n "$igmpversion" ]; then
229 230 231 232 233 234 235
	    echo "WARNING: possible IGMP issues; using frisbee keep alive timer"
	    KEEPALIVE=30
	else
	    KEEPALIVE=0
	fi
    fi

236 237 238
    #
    # One of ADDR or IMAGEID must be set.
    #
239
    if [ -n "$IMAGEID" ]; then
240 241 242 243 244
        ADDR=""
    	# IMAGEID=pid,gid,imagename
	pid=`echo $IMAGEID | awk -F, '{ printf $1 }'`
	name=`echo $IMAGEID | awk -F, '{ printf $3 }'`
	IMAGEID="$pid/$name"
245
    elif [ -z "$ADDR" ]; then
246 247 248 249
	echo "Unable to get imageid or address for loading image"
	return 1
    fi

Mike Hibler's avatar
Mike Hibler committed
250 251
    if [ "$PART" != "0" ]; then
	SLICE="-s $PART"
252 253 254 255 256 257 258 259 260
	case $PARTOS in
	FreeBSD)
		SLICE="$SLICE -D 165"
		PTYPE=165
		;;
	OpenBSD)
		SLICE="$SLICE -D 166"
		PTYPE=166
		;;
261
	Fedora|Linux)
262 263 264 265 266 267
		SLICE="$SLICE -D 131"
		PTYPE=131
		;;
	*)
		;;
	esac
268
    fi
269

270 271 272 273 274
    #
    # set memory limits:
    #	allow $RESIDMEM MB for non-frisbee stuff
    #	split remaining memory (min of 2MB) between network/disk buffering
    #
275
    MEMARGS=""
276 277 278
    HOSTMEM=`sysctl -n hw.usermem`
    HOSTMEM=`expr $HOSTMEM / 1048576`
    if [ $HOSTMEM -ge `expr $RESIDMEM + 2` ]; then
279
	HOSTMEM=`expr $HOSTMEM - $RESIDMEM`
280
	KBYTES=`expr $HOSTMEM \* 1024`
281
	DATASEGSZ=`ulimit -d`
282 283 284
	if [ $KBYTES -gt $DATASEGSZ ]; then
	    KBYTES=$DATASEGSZ
	    HOSTMEM=`expr $KBYTES / 1024`
285 286
	    echo "WARNING: kernel limits buffering to $HOSTMEM MB"
	fi
287
	ulimit -v $KBYTES
288

289
	# Let the client split up the memory
290
	MEMARGS="-M $HOSTMEM"
291
    fi
292

293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308

    #
    # Allow for large-ish socketbuf for frisbee
    # NOTE: add 12.5% slop to get socketbuf of the appropriate size
    # NOTE: if the sysctl fails, it doesn't matter as frisbee will downsize
    #
    osbs=`sysctl -n kern.ipc.maxsockbuf`
    sbs=`expr $MAXSOCKBUF \* 1024`
    sbs=`expr $sbs \+ \( $sbs / 8 \)`
    if [ $sbs -gt $osbs ]; then
	sysctl kern.ipc.maxsockbuf=$sbs
    fi

    # NOTE: make sure you install the latest frisbee client for -k!
    MEMARGS="$MEMARGS -k $MAXSOCKBUF"

309
    #
310 311 312
    # Make sure the necessary device files exist (only necessary on
    # FreeBSD 4.x).  Note that we create partition files for all slices,
    # not just slice 1, for the benefit of the slicefix script.
313 314
    #
    if [ -x /dev/MAKEDEV -a ! -e /dev/$DISK ]; then
315
	(cd /dev; ./MAKEDEV $DISK ${DISK}s2a ${DISK}s3a ${DISK}s4a)
316
    fi
317

Mike Hibler's avatar
Mike Hibler committed
318 319 320
    if [ x"$ADDR" != x ]; then
	isurl=`echo $ADDR | grep http -`
	ispath=`echo $ADDR | grep '^/' -`
321 322

	if [ x"$isurl" != x ]; then
Mike Hibler's avatar
Mike Hibler committed
323
	    echo "Need to download $ADDR"
324 325

	    isurl=1
326
	    ispath=0
327 328
	    if [ ! -d /images ]; then
		echo "Need to create or mount /images directory!"
329
		return 1
330
	    fi
331

332 333 334
	    #
	    # This needs a lot more work ...
	    #
Mike Hibler's avatar
Mike Hibler committed
335
	    imagefile=`echo $ADDR | sed -e 's,^http[s]*://[^/]*/,,'`
336 337
	    imagefile="/images/$imagefile"
	elif [ x"$ispath" != x ]; then
338
	    isurl=0
339
	    ispath=1
340

Mike Hibler's avatar
Mike Hibler committed
341 342
	    if [ ! -e $ADDR ]; then
		echo "$ADDR does not exist!"
343
		return 1
344
	    fi
Mike Hibler's avatar
Mike Hibler committed
345
	    imagefile="$ADDR"
346
	else
Mike Hibler's avatar
Mike Hibler committed
347 348
	    PORT=`echo $ADDR | awk -F: '{ printf $2 }'`
	    MCAST=`echo $ADDR | awk -F: '{ printf $1 }'`
349 350 351
	    if [ -e $BOOTDIR/myip ]; then
		MCASTIF="-i `cat $BOOTDIR/myip`"
	    else
352
		MCASTIF=""
353 354
	    fi
	    MCASTADDR="-m $MCAST -p $PORT"
355
	    IMAGEID="$MCASTIF $MCASTADDR"
356 357
	    isurl=0
	    ispath=0
358
	fi
359
    else
360 361 362 363
	#
	# Note: if you want to use broadcast rather that multicast as
	# the distribution method, add "-X bcast" to the IMAGEID= below.
	#
364 365 366 367
        IMAGEID="-B 30 -F $IMAGEID"
	isurl=0
	ispath=0
    fi
368

369 370 371 372 373 374 375 376 377
    #
    # ZFILL==1: use frisbee
    # ZFILL==2: separate disk-wipe pass (not yet implemented)
    #
    if [ "$ZFILL" != "0" ]; then
	ZFILL="-z"
    else
	ZFILL=""
    fi
378

379 380 381 382 383 384
    if [ "$KEEPALIVE" != "0" ]; then
	KA="-K $KEEPALIVE"
    else
	KA=""
    fi

385 386 387 388 389 390 391 392 393 394 395
    #
    # Make sure the write-cache is enabled on SCSI disks.  It makes a
    # huge difference.  We don't worry about data corruption in the
    # case of a crash, because we will just reload the disk again anyway
    # in that situation.
    #
    turncacheoff=0
    case $DISK in
    da*)
	if [ -x $BINDIR/camwce ] && $BINDIR/camwce on $DISK; then
	    turncacheoff=1;
396
	fi
397 398
	;;
    esac
399

400 401 402 403 404 405
    #
    # For slice images, ensure that the MBR is the correct version
    # and replace if not.
    #
    if [ $_NUM -eq 0 ]; then
	if [ "$PART" != "0" ]; then
406
	    tweakmbr $DISK $MBRVERS $PREPARE
407
	fi
408 409 410 411
        FIRSTMBR=$MBRVERS
    else
	if [ "$FIRSTMBR" != "$MBRVERS" ]; then
	    echo "MBR Mismatch: First MBR is \"$FIRSTMBR\" while image #$_NUM is \"$MBRVERS\""
412
	fi
413
    fi
414

415 416 417 418 419 420 421
    #
    # If a remote node and we have a URL, make sure that we have a place
    # to put it. Done after the MBR tweak of course. Then download the URL.
    #
    if [ $isrem -eq 1 -a $isurl -eq 1 ]; then
	echo "Downloading image \'$ADDR\' to /images directory ..."
	$BINDIR/mkextrafs.pl -c -s 4 -r $DISK /images || {
422 423
	    # XXX run growdisk to ensure we have a partition in the MBR
	    $BINDIR/growdisk -vW /dev/$DISK >/dev/null 2>&1
424 425 426 427 428 429 430 431
	    $BINDIR/mkextrafs.pl -n -f -s 4 -r $DISK /images || {
		echo "Could not create /images partition"
		return 1
	    }
	}
	wget -nv -N -P /images "$ADDR"
	wstat=$?
	case $wstat in
432
	0)
433
	    echo "wget succeeded getting the image"
434
	    ;;
435
	*)
436 437
	    echo "wget failed, status $wstat"
	    return 1
438
	    ;;
439
	esac
440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459
    fi

    #
    # If not zeroing the disk and we are loading a full disk image
    # we need to ensure that we at least invalidate any old superblocks
    # that might leak through (most likely in partition 4 which isn't
    # touched by our current image).  We do this before running frisbee
    # so that any legit filesystems loaded from the image work.
    #
    # Since we do it before frisbee, we are counting on the current
    # MBR being the same as the MBR being layed down.  While not
    # a reasonable assumption in general, it mostly works in our
    # environment and at least won't hurt anything if not true.
    #
    if [ $PREPARE -eq 1 -o \
         \( $isrem -eq 0 -a x"$ZFILL" = x -a "$PART" = "0" \) ]; then
	zapsuperblocks $DISK
    fi

    if [ x"$imagefile" != x ]; then
460
	echo "`date`: Running /usr/local/bin/imageunzip -o -O -W 32 $ZFILL $imagefile /dev/${DISK}s${PART}"
461
	/usr/local/bin/imageunzip -o -O -W 32 $ZFILL $imagefile /dev/${DISK}s${PART}
462
    else
463
	echo "`date`: Running $BINDIR/frisbee -S $SERVER $MEMARGS $KA $ZFILL $SLICE $IMAGEID /dev/$DISK"
464
	$BINDIR/frisbee -S $SERVER $MEMARGS $KA $ZFILL $SLICE $IMAGEID /dev/$DISK
465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484
    fi
    fstat=$?

    #
    # If we mounted a partition from the disk to store the image,
    # we must unmount it now so that slicefix and others don't fail
    # due to an in-use partition.
    #
    if [ $isrem -eq 1 -a $isurl -eq 1 ]; then
	umount /images || {
	    echo "WARNING: could not unmount /images"
	}
    fi

    #
    # Turn the cache back off if we turned it on.
    # Is this sufficient to ensure the cache gets flushed?
    #
    if [ $turncacheoff -eq 1 ]; then
	$BINDIR/camwce off $DISK
485
    fi
486 487 488 489 490 491 492 493

    case $fstat in
    0)
	;;
    *)
	echo "Frisbee run failed, status $fstat"
	;;
    esac
494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511
    return $fstat
}

#
# Run slicefix on the indicated partition
#
fixone() {
    DISK=$1
    PART=$2
    iline=$3

    echo "`date`: Adjusting slice-related files on $DISK slice $PART"

    export SLICEFIX_ACPI=`getvar ACPI "$iline" unknown`
    export SLICEFIX_ASF=`getvar ASF "$iline" unknown`
    export SLICEFIX_NOCLFLUSH=`getvar NOCLFLUSH "$iline" unknown`
    export SLICEFIX_VGAONLY=`getvar VGAONLY "$iline" unknown`
    export SLICEFIX_CONSOLE=`getvar CONSOLE "$iline" unknown`
512
    export SLICEFIX_BIOSDISK=`getvar BIOSDISK "$iline"`
513 514 515
    export SLICEFIX_DOM0MEM=`getvar DOM0MEM "$iline" unknown`
    $BINDIR/slicefix $PART $DISK
    return $?
516 517 518 519 520 521 522 523 524
}

$BINDIR/tmcc state RELOADSETUP

BOSSINFO=`$BINDIR/tmcc bossinfo`
STATUS=`$BINDIR/tmcc status`

BOSSIP=`echo $BOSSINFO | awk '{ print $2 }'`

525 526 527 528
NTPIP=`grep -w ntp1 /etc/hosts 2>/dev/null | awk '{ print $1 }'`
if [ -z "$NTPIP" ]; then
    NTPIP=$BOSSIP
fi
529
if [ -x /usr/sbin/ntpdate ]; then
530
	/usr/sbin/ntpdate -b $NTPIP >/dev/null 2>&1
531 532 533 534 535
fi

# Enable IPoD
if [ -r $BINDIR/rc.ipod ]; then
    . $BINDIR/rc.ipod
536
fi
537 538

#
Mike Hibler's avatar
Mike Hibler committed
539 540
# Assign each line (one image) to one of the positional parameters.
# This is done by setting IFS to a newline and using set.
541 542
# XXX there must be a better way to do this!
#
Mike Hibler's avatar
Mike Hibler committed
543
OIFS="$IFS"
544 545 546
IFS='
'
set -- `$BINDIR/tmcc loadinfo`
Mike Hibler's avatar
Mike Hibler committed
547
IFS="$OIFS"
548
if [ -z "$1" ]; then
549 550 551 552 553 554
    echo "No load information for node"
    exit 1
fi

$BINDIR/tmcc state RELOADING

555 556 557 558 559 560 561 562 563 564
# HACK ALERT: If we're reloading we need to zap the superblocks and
# MBRs of any other disks in the system.  This is to prevent Linux from
# finding an old filesystem with the same label or UUID and mounting
# that instead of the right one.  We skip the disks that are mounted
# and the disk we're going to write to.
# DOUBLE HACK ALERT: Changed this to zap all disks to avoid having
# to figure out what the other disks are when loading multiple images.
# Since a new MBR will be laid down anyway there is no harm in doing
# this as long as we are sure we are in the reloading experiment.
case $STATUS in
565 566 567 568
*ALLOCATED=emulab-ops/reloading*)
    disks=`find_disks`
    for d in $disks; do
	#[ $d = $DISK ] && continue
569 570 571 572
	mount | grep "^/dev/$d" >/dev/null && continue
	if [ -x "$BINDIR/zapdisk" ]; then
	    echo "Invalidating superblocks and MBR/GPT on $d"
	    $BINDIR/zapdisk -v -SBZ /dev/$d
Mike Hibler's avatar
Mike Hibler committed
573
	else
574 575
	    zapsuperblocks $d
	    echo "Invalidating MBR/GPT on $d"
Mike Hibler's avatar
Mike Hibler committed
576 577
	    dd if=/dev/zero of=/dev/$d bs=512 count=16
	fi
578 579 580 581 582 583 584 585 586 587 588
    done

    #
    # If we have nodecheck, run it. This allows us to both collect HW info
    # (if nodecheck "collect" is enabled in the DB) and to run a destructive
    # disk write speed test (as part of a nodecheck "check" operation).
    #
    if [ -x $BINDIR/rc.nodecheck ]; then
	$BINDIR/rc.nodecheck boot
    fi
    ;;
589 590
esac

591 592 593 594 595 596 597
#
# Load each image in turn.
# If a load fails, we exit non-zero so that the rc script will drop into
# single-user mode.  If all loads succeed we either reboot or continue with
# the rc script as desired by the caller.
#
NUM=0
598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619
devs=""
while [ -n "$1" ]; do
    iline=$1

    #
    # Remember the info for this partition line so we can run slicefix later.
    # Yes, we can load the same partition multiple times due to our delta
    # image mechanism.
    #
    # Note that we always overwrite the saved info so we wind up with the
    # info for the last image loaded on the slice. Thus we assume that the
    # last image loaded has the right info. Probably this will never matter
    # as delta images should always have the same attributes as the full
    # image loaded.
    #
    DISK=`getvar DISK "$iline" ad0`
    PART=`getvar PART "$iline" 0`
    dev="${DISK}_${PART}"
    devs="$devs $dev"
    eval ${dev}_info=\"$iline\"

    loadone $DISK $PART "$iline" $NUM || {
620
	echo "`date`: Failed to load disk, dropping to login prompt"
621 622
        exit 1
    }
623
    echo "`date`: Image #$_NUM load complete"
624
    NUM=`expr $NUM + 1`
625
    shift
626
done
627
echo "`date`: Frisbee run(s) finished"
628

629 630 631 632 633 634 635 636 637 638 639 640 641 642 643
echo "`date`: Running slicefix"
for dev in $devs; do
    DISK=${dev%%_*}
    PART=${dev##*_}
    eval iline=\$${dev}_info
    if [ -n "$iline" ]; then
	fixone $DISK $PART "$iline" || {
	    echo "`date`: WARNING: slicefix on $DISK slice $PART failed"
	}
	# whack the info so we don't slicefix again
	eval ${dev}_info=\"\"
    fi
done
echo "`date`: slicefix run(s) done"

644
echo "`date`: Resizing final disk partition"
645
$BINDIR/growdisk -vW /dev/$DISK
646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663

#
# If requested to reboot, do so.
#
# Note: there is a race condition with stated here.
# If we reboot immediately after sending RELOADDONE,
# it is possible that, under heavy server load, we will
# finish the reboot and reach the bootinfo stage before
# stated gets and processes our RELOADDONE.  So now we
# wait around after sending the RELOADDONE.  stated should
# force us to reboot when the transition takes place.
# For backward compatibility we use a new state: RELOADDONEV2.
# For paranoia we just wait around for awhile and then
# reboot anyway, just in case stated's reboot fails for
# some reason.
#
if [ $reboot -eq 1 ]; then
    $BINDIR/tmcc state RELOADDONEV2
664
    echo "`date`: Waiting for server to reboot us ..."
665 666 667
    if [ $isrem -eq 1 ]; then
	sleep 30
    else
668
	sleep 300
669
    fi
670
    echo "`date`: No response from server, rebooting myself ..."
671 672 673 674 675 676
    /sbin/reboot
    sleep 100
else
    $BINDIR/tmcc state RELOADDONE
fi

677
echo "`date`: rc.frisbee finished"
678 679

exit 0