xcat-core/xCAT-genesis-scripts/etc/init.d/functions
2013-05-13 08:50:34 +00:00

1829 lines
58 KiB
Bash

#!/bin/sh
#
# "SystemImager"
#
# Copyright (C) 1999-2011 Brian Elliott Finley <brian@thefinleys.com>
#
# $Id: functions 4559 2011-07-05 21:04:36Z finley $
# vi: set filetype=sh et ts=4:
#
# Others who have contributed to this code:
# Charles C. Bennett, Jr. <ccb@acm.org>
# Sean Dague <japh@us.ibm.com>
# Dann Frazier <dannf@dannf.org>
# Curtis Zinzilieta <czinzilieta@valinux.com>
#
################################################################################
#
# Variables
#
PATH=/sbin:/bin:/usr/bin:/usr/sbin:/tmp
LD_LIBRARY_PATH=/lib
SCRIPTS=scripts
SCRIPTS_DIR=/scripts
TORRENTS=torrents
TORRENTS_DIR=/torrents
FLAMETHROWER_DIRECTORY_DIR=/var/lib/systemimager/flamethrower
BOEL_BINARIES_DIR=/tmp/boel_binaries
VERSION="4.3.0"
FLAVOR="standard"
IMAGESERVER=$XCATMASTER
#
################################################################################
################################################################################
#
# Subroutines
#
################################################################################
#
# logmsg
#
# Usage: log a message, redirects to console / syslog depending on usage
logmsg() {
# log to console
echo $@
# log to temporary file (which will go away when we reboot)
# this is good for envs that have bad consoles
local FILE=/tmp/si.log
echo $@ >> $FILE || shellout
# if syslog is running, log to it. In order to avoid hangs we have to
# add the "logger: " part in case $@ is ""
if [ ! -z $USELOGGER ] ;
then logger "logger: $@"
fi
}
################################################################################
#
# check_version
#
# Usage: check_version
check_version() {
logmsg
logmsg check_version
INITRD_VERSION=$VERSION
KERNEL_VERSION=`uname -r | sed -e s/.*boel_v//`
if [ "$INITRD_VERSION" != "$KERNEL_VERSION" ] ; then
logmsg "FATAL: Kernel version ($KERNEL_VERSION) doesn't match initrd version ($INITRD_VERSION)!"
shellout
fi
}
#
################################################################################
#
# get_arch
#
# Usage: get_arch; echo $ARCH
get_arch() {
logmsg
logmsg get_arch
ARCH=`uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/`
}
#
################################################################################
#
# adjust_arch
#
# based on info in /proc adjust the ARCH variable. This needs to run
# after proc is mounted.
#
adjust_arch() {
logmsg
logmsg adjust_arch
if [ "ppc64" = "$ARCH" ] ; then
# This takes a little bit of futzing with due to all the PPC platforms that exist.
if [ -d /proc/iSeries ] ; then
ARCH=ppc64-iSeries
logmsg "Detected ppc64 is really an iSeries partition..."
fi
if grep -qs PS3 /proc/cpuinfo; then
ARCH=ppc64-ps3
fi
fi
}
#
################################################################################
#
# write_variables
#
# Usage: write_variables
write_variables() {
logmsg
logmsg write_variables
# pass all variables set here on to the hostname.sh script
rm -f /tmp/variables.txt
echo "HOSTNAME=$HOSTNAME" >> /tmp/variables.txt || shellout
echo "DOMAINNAME=$DOMAINNAME" >> /tmp/variables.txt
echo "DEVICE=$DEVICE" >> /tmp/variables.txt
echo "IPADDR=$IPADDR" >> /tmp/variables.txt
echo "NETMASK=$NETMASK" >> /tmp/variables.txt
echo "NETWORK=$NETWORK" >> /tmp/variables.txt
echo "BROADCAST=$BROADCAST" >> /tmp/variables.txt
echo "GATEWAY=$GATEWAY" >> /tmp/variables.txt
echo "GATEWAYDEV=$GATEWAYDEV" >> /tmp/variables.txt
echo "IMAGESERVER=$IMAGESERVER" >> /tmp/variables.txt
echo "IMAGENAME=$IMAGENAME" >> /tmp/variables.txt
echo "LOG_SERVER=$LOG_SERVER" >> /tmp/variables.txt
echo "LOG_SERVER_PORT=$LOG_SERVER_PORT" >> /tmp/variables.txt
echo "USELOGGER=$USELOGGER" >> /tmp/variables.txt
echo "TMPFS_STAGING=$TMPFS_STAGING" >> /tmp/variables.txt
echo "SSH=$SSH" >> /tmp/variables.txt
echo "SSHD=$SSHD" >> /tmp/variables.txt
echo "SSH_USER=$SSH_USER" >> /tmp/variables.txt
echo "SSH_DOWNLOAD_URL=$SSH_DOWNLOAD_URL" >> /tmp/variables.txt
echo "FLAMETHROWER_DIRECTORY_PORTBASE=$FLAMETHROWER_DIRECTORY_PORTBASE" >> /tmp/variables.txt
echo "MONITOR_SERVER=$MONITOR_SERVER" >> /tmp/variables.txt
echo "MONITOR_PORT=$MONITOR_PORT" >> /tmp/variables.txt
echo "MONITOR_CONSOLE=$MONITOR_CONSOLE" >> /tmp/variables.txt
echo "BITTORRENT=$BITTORRENT" >> /tmp/variables.txt
echo "BITTORRENT_STAGING=$BITTORRENT_STAGING" >> /tmp/variables.txt
echo "BITTORRENT_POLLING_TIME=$BITTORRENT_POLLING_TIME" >> /tmp/variables.txt
echo "BITTORRENT_SEED_WAIT=$BITTORRENT_SEED_WAIT" >> /tmp/variables.txt
echo "BITTORRENT_UPLOAD_MIN=$BITTORRENT_UPLOAD_MIN" >> /tmp/variables.txt
echo "GROUPNAMES=\"$GROUPNAMES\"" >> /tmp/variables.txt
echo "GROUP_OVERRIDES=\"$GROUP_OVERRIDES\"" >> /tmp/variables.txt
}
#
################################################################################
#
# Description:
# watches the tmpfs filesystem (/) and gives warnings and/or does a shellout
#
# Usage: tmpfs_watcher
#
tmpfs_watcher() {
logmsg
logmsg tmpfs_watcher
# Note: Transfer to staging area can fail if tmpfs runs out of inodes.
{
while :; do
DF=`df -k / | egrep ' /$' | sed -e 's/ */ /g' -e 's/.*[0-9] //' -e 's/%.*//'`
[ $DF -ge 95 ] && logmsg "WARNING: Your tmpfs filesystem is ${DF}% full!"
[ $DF -ge 99 ] && logmsg " Search the FAQ for tmpfs to learn about sizing options."
[ $DF -ge 99 ] && shellout
sleep 1
done
unset DF
}&
TMPFS_WATCHER_PID=$!
}
#
################################################################################
#
# Description:
# Exit with the message stored in /etc/issue.
#
# Usage: $COMMAND || shellout
#
shellout() {
logmsg "Last command exited with $?"
COUNT="$RETRY"
logmsg "Killing off running processes."
kill -9 $TMPFS_WATCHER_PID >/dev/null 2>/dev/null
killall -9 udp-receiver rsync >/dev/null 2>/dev/null
write_variables
cat /etc/issue
if [ ! -z $USELOGGER ] ;
then cat /etc/issue | logger
fi
if [ ! -z $MONITOR_SERVER ]; then
logmsg "Installation failed!! Stopping report task."
stop_report_task -1
fi
exec sh > /dev/console 2>&1
}
#
################################################################################
#
# Description:
# Count the specified number, printing each number, and exit only the count
# loop when <ctrl>+<c> is hit (SIGINT, or Signal 2). Thanks to
# CCB <ccb@acm.org> for this chunk of code. -BEF-
#
# Usage:
# count_loop 35
# count_loop $ETHER_SLEEP
#
count_loop() {
COUNT=$1
trap 'echo ; echo "Skipping ETHER_SLEEP -> Caught <ctrl>+<c>" ; I=$COUNT' INT
I=0
while [ $I -lt $COUNT ]; do
I=$(( $I + 1 ))
logmsg -n "$I "
sleep 1
done
trap INT
logmsg
}
#
################################################################################
#
# Usage: get_torrents_directory
#
get_torrents_directory() {
if [ ! "x$BITTORRENT" = "xy" ]; then
return
fi
logmsg
logmsg get_torrents_directory
if [ ! -z $FLAMETHROWER_DIRECTORY_PORTBASE ]; then
#
# We're using Multicast, so we should already have a directory
# full of scripts. Break out here, so that we don't try to pull
# the scripts dir again (that would be redundant).
#
MODULE_NAME="autoinstall_torrents"
DIR="${SCRIPTS_DIR}"
RETRY=7
flamethrower_client
else
mkdir -p ${TORRENTS_DIR}
CMD="rsync -a ${IMAGESERVER}::${TORRENTS}/ ${TORRENTS_DIR}/"
logmsg "$CMD"
$CMD
fi
}
#
################################################################################
#
# Usage: get_scripts_directory
#
get_scripts_directory() {
logmsg
logmsg get_scripts_directory
if [ ! -z $FLAMETHROWER_DIRECTORY_PORTBASE ]; then
#
# We're using Multicast, so we should already have a directory
# full of scripts. Break out here, so that we don't try to pull
# the scripts dir again (that would be redundant).
#
MODULE_NAME="autoinstall_scripts"
DIR="${SCRIPTS_DIR}"
RETRY=7
flamethrower_client
else
mkdir -p ${SCRIPTS_DIR}
CMD="rsync -a ${IMAGESERVER}::${SCRIPTS}/ ${SCRIPTS_DIR}/"
logmsg "$CMD"
$CMD || shellout
fi
}
#
################################################################################
#
# Usage: get_flamethrower_directory
#
get_flamethrower_directory() {
logmsg
logmsg Using multicast...
logmsg get_flamethrower_directory
MODULE_NAME=flamethrower_directory
DIR=${FLAMETHROWER_DIRECTORY_DIR}
RETRY=7
PORTBASE=9000
flamethrower_client
}
#
################################################################################
#
# Usage:
#
# MODULE_NAME=my_module # Required
# DIR=/my/destination/dir # Required
# [RETRY=7] # Optional
# [PORTBASE=9000] # Required if a sourceable file called $MODULE_NAME
# # doesn't exist
# [FLAMETHROWER_TARPIPE] # If not empty, untar received data directly,
# # without storing it to a temporary file
#
# flamethrower_client
#
flamethrower_client() {
if [ ! -z $FLAMETHROWER_TARPIPE ]; then
FLAMETHROWER_TARPIPE=tarpipe
fi
logmsg
logmsg "flamethrower_client(${MODULE_NAME}) $FLAMETHROWER_TARPIPE "
logmsg ---------------------------------------------------------------------
# validate
if [ -z $PORTBASE ]; then
if [ -f ${FLAMETHROWER_DIRECTORY_DIR}/${MODULE_NAME} ]; then
. ${FLAMETHROWER_DIRECTORY_DIR}/${MODULE_NAME}
else
logmsg WARNING WARNING WARNING WARNING WARNING
logmsg You must either set PORTBASE, or have a sourceable file called
logmsg ${FLAMETHROWER_DIRECTORY_DIR}/MODULE_NAME
# allow for now to continue until overrides get their modules
return
#shellout
fi
fi
if [ -z $DIR ]; then
logmsg "Must set DIR !!!"
shellout
else
mkdir -p $DIR
fi
# build command
UDP_RECEIVER_OPTIONS="--interface ${DEVICE} --portbase $PORTBASE --nokbd"
if [ ! -z $TTL ]; then
UDP_RECEIVER_OPTIONS="$UDP_RECEIVER_OPTIONS --ttl $TTL"
fi
if [ "$NOSYNC" = "on" ]; then
UDP_RECEIVER_OPTIONS="$UDP_RECEIVER_OPTIONS --nosync"
fi
if [ "$ASYNC" = "on" ]; then
UDP_RECEIVER_OPTIONS="$UDP_RECEIVER_OPTIONS --async"
fi
if [ ! -z $MCAST_ALL_ADDR ]; then
UDP_RECEIVER_OPTIONS="$UDP_RECEIVER_OPTIONS --mcast-all-addr $MCAST_ALL_ADDR"
fi
# Which tar opts should we use? If our tar has --overwrite capability, use it.
# Summary: busybox tar doesn't (boel_binaries and prior).
# Debian patched gnu tar does (image and on).
# We want this option enabled for the image to ensure proper directory
# permissions. -BEF-
tar --help 2>&1 | grep -q overwrite && TAR_OPTS='--overwrite -xp' || TAR_OPTS='-x'
# set vars
[ -z $RETRY ] && RETRY=0
COUNT=0
FLAMETHROWER_CLIENT_SLEEP=3
# it's the new new style (loop)
SUCCESS="Not Yet"
until [ "$SUCCESS" = "yes" ]
do
# receive cast
# example udp-receiver command:
# udp-receiver --interface lo --portbase 9002 --nokbd --nosync --file /tmp/multicast.tar
if [ ! -z $FLAMETHROWER_TARPIPE ]; then
TAR_OPTS="$TAR_OPTS -f -"
logmsg "udp-receiver $UDP_RECEIVER_OPTIONS | tar $TAR_OPTS -C $DIR"
udp-receiver $UDP_RECEIVER_OPTIONS | tar $TAR_OPTS -C $DIR
TAR_EXIT_STATUS=$?
UDP_RECEIVER_EXIT_STATUS=0
else
logmsg udp-receiver $UDP_RECEIVER_OPTIONS --file /tmp/multicast.tar
udp-receiver $UDP_RECEIVER_OPTIONS --file /tmp/multicast.tar
UDP_RECEIVER_EXIT_STATUS=$?
# untar it
if [ "$UDP_RECEIVER_EXIT_STATUS" = "0" ]; then
logmsg tar ${TAR_OPTS} -f /tmp/multicast.tar -C ${DIR}
tar ${TAR_OPTS} -f /tmp/multicast.tar -C ${DIR}
TAR_EXIT_STATUS=$?
fi
# discard used tarball like an old sock (recommended by: Ramon Bastiaans <bastiaans@sara.nl>)
rm -f /tmp/multicast.tar
fi
# did everything work properly
if [ $UDP_RECEIVER_EXIT_STATUS -eq 0 ] && [ $TAR_EXIT_STATUS -eq 0 ]; then
SUCCESS=yes
else
if [ $COUNT -lt $RETRY ]; then
COUNT=$(( $COUNT + 1 ))
logmsg "flamethrower_client: Proceeding with retry $COUNT of $RETRY"
else
logmsg
logmsg "flamethrower_client: FATAL: Initial attempt and $RETRY retries failed!"
shellout
fi
fi
# sleep apnea
sleep_loop $FLAMETHROWER_CLIENT_SLEEP
done
# done
logmsg 'finished!'
logmsg
# Unset vars, so next module (which may not have them set) won't use then unintentially
unset TTL
unset NOSYNC
unset ASYNC
unset MCAST_ALL_ADDR
unset RETRY
unset COUNT
unset DIR
unset PORTBASE
unset UDP_RECEIVER_EXIT_STATUS
unset UDP_RECEIVER_OPTIONS
unset TAR_EXIT_STATUS
unset TAR_OPTS
unset SUCCESS
unset FLAMETHROWER_TARPIPE
}
#
################################################################################
#
# Autodetect a staging directory for the bittorrent tarball
#
# Usage: bittorrent_autodetect_staging_dir torrent
#
bittorrent_autodetect_staging_dir() {
torrent=$1
if [ ! -f $torrent ]; then
logmsg "warning: torrent file $torrent does not exist!"
return
fi
# List of preferred staging directory (/tmp = ramdisk staging)
preferred_dirs="/tmp /a/tmp `df 2>/dev/null | sed '1d' | sed 's/[[:space:]]\+/ /g' | cut -d' ' -f6`"
# Use a breathing room of 100MB (this should be enough for a lot of cases)
breathing_room=102400
# Evaluate torrent size
torrent_size=$((`/bin/torrentinfo-console $torrent | sed -ne 's/^file size\.*: \([0-9]\+\).*$/\1/p'` / 1024 + $breathing_room))
# Find a directory to host the image tarball
for dir in $preferred_dirs; do
[ ! -d $dir ] && continue;
dir_space=`df $dir 2>/dev/null | sed '1d' | sed 's/[[:space:]]\+/ /g' | cut -d' ' -f4 | sed -ne '$p'`
[ -z $dir_space ] && continue
[ $torrent_size -lt $dir_space ] && echo $dir && return
done
}
#
################################################################################
#
# Download a file using bittorrent.
#
# Usage: bittorrent_get_file torrent destination
#
bittorrent_get_file() {
torrent=$1
destination=$2
# Bittorrent log file
bittorrent_log=/tmp/bittorrent-`basename ${torrent}`.log
# Time to poll bittorrent events
bittorrent_polling_time=${BITTORRENT_POLLING_TIME:-5}
# Wait after the download is finished to seed the other peers
bittorrent_seed_wait=${BITTORRENT_SEED_WAIT:-n}
# Minimum upload rate threshold (in KB/s), if lesser stop seeding
bittorrent_upload_min=${BITTORRENT_UPLOAD_MIN:-50}
# Start downloading.
/bin/bittorrent-console --no_upnp --no_start_trackerless_client --max_upload_rate 0 --display_interval 1 --rerequest_interval 1 --bind ${IPADDR} --save_in ${destination} ${torrent} > $bittorrent_log &
pid=$!
if [ ! -d /proc/$pid ]; then
logmsg "error: couldn't run bittorrent-console!"
shellout
fi
unset pid
# Wait for BitTorrent log to appear.
while [ ! -e $bittorrent_log ]; do
sleep 1
done
# Checking download...
while :; do
while :; do
status=`grep 'percent done:' $bittorrent_log | sed -ne '$p' | sed 's/percent done: *//' | sed -ne '/^[0-9]*\.[0-9]*$/p'`
[ ! -z "$status" ] && break
done
logmsg "percent done: $status %"
if [ "$status" = "100.0" ]; then
# Sleep until upload rate reaches the minimum threshold
while [ "$bittorrent_seed_wait" = "y" ]; do
sleep $bittorrent_polling_time
while :; do
upload_rate=`grep 'upload rate:' $bittorrent_log | sed -ne '$p' | sed 's/upload rate: *\([0-9]*\)\.[0-9]* .*$/\1/' | sed -ne '/^\([0-9]*\)$/p'`
[ ! -z $upload_rate ] && break
done
logmsg "upload rate: $upload_rate KB/s"
[ $upload_rate -lt $bittorrent_upload_min ] && break
done
logmsg "Download completed"
unset bittorrent_log upload_rate counter
break
fi
sleep $bittorrent_polling_time
done
unset bittorrent_polling_time
unset bittorrent_seed_wait
unset bittorrent_upload_min
unset torrent
unset destination
}
#
################################################################################
#
# Stop bittorrent client.
#
# Usage: bittorrent_stop
#
bittorrent_stop() {
# Try to kill all the BitTorrent processes
btclient="bittorrent-console"
logmsg "killing BitTorrent client..."
killall -15 $btclient >/dev/null 2>&1
# Forced kill after 5 secs.
sleep 5
killall -9 $btclient >/dev/null 2>&1
# Remove bittorrent logs.
rm -rf /tmp/bittorrent*.log
unset btclient
}
#
################################################################################
#
# Get other binaries, kernel module tree, and miscellaneous other stuff that
# got put in the binaries tarball. -BEF-
#
get_boel_binaries_tarball() {
logmsg
logmsg get_boel_binaries_tarball
# mkdir -p ${BOEL_BINARIES_DIR}
#
# if [ ! -z $SSH_DOWNLOAD_URL ]; then
# # If we're using SSH, get the boel_binaries from a web server.
# logmsg "SSH_DOWNLOAD_URL variable is set, so we will install over SSH!"
#
# if [ ! -z $FLAMETHROWER_DIRECTORY_PORTBASE ]; then
# logmsg "FLAMETHROWER_DIRECTORY_PORTBASE is also set, but I will be conservative and proceed with SSH."
# fi
#
# # Remove possible trailing / from URL
# SSH_DOWNLOAD_URL=`echo $SSH_DOWNLOAD_URL | sed 's/\/$//'`
#
# cd ${BOEL_BINARIES_DIR}
# CMD="wget ${SSH_DOWNLOAD_URL}/${ARCH}/${FLAVOR}/boel_binaries.tar.gz"
# logmsg "$CMD"
# $CMD || shellout
#
# elif [ "x$BITTORRENT" = "xy" ]; then
#
# # Download BOEL binaries from peers
# bittorrent_tarball="boel_binaries.tar.gz"
# logmsg "Start downloading ${bittorrent_tarball} (${ARCH}) using bittorrent"
# logmsg ""
# logmsg "--> INFO: remember to start /etc/init.d/systemimager-server-bittorrent on the image server!"
# logmsg ""
# bittorrent_get_file ${TORRENTS_DIR}/${ARCH}-${bittorrent_tarball}.torrent ${BOEL_BINARIES_DIR}
# cd ${BOEL_BINARIES_DIR} && mv ${ARCH}-${bittorrent_tarball} ${bittorrent_tarball}
# unset bittorrent_tarball
#
# elif [ ! -z $FLAMETHROWER_DIRECTORY_PORTBASE ]; then
#
# MODULE_NAME="boot-${ARCH}-${FLAVOR}"
# DIR="${BOEL_BINARIES_DIR}"
# RETRY=7
# flamethrower_client
#
# else
# # Use rsync
# CMD="rsync -av ${IMAGESERVER}::boot/${ARCH}/${FLAVOR}/boel_binaries.tar.gz ${BOEL_BINARIES_DIR}"
# logmsg "$CMD"
# $CMD || shellout
# fi
#
# # Untar the tarball
# tar -C / -xzf ${BOEL_BINARIES_DIR}/boel_binaries.tar.gz || shellout
# chown -R 0.0 /lib/modules || shellout
}
#
################################################################################
#
# Parse tmpfs options from /proc/cpuinfo
#
parse_tmpfs_opts() {
logmsg
logmsg parse_tmpfs_opts
tmpfs_size=$(tr ' ' '\n' < /proc/cmdline | grep tmpfs_size\= | sed 's/.*=//')
tmpfs_nr_blocks=$(tr ' ' '\n' < /proc/cmdline | grep tmpfs_nr_blocks\= | sed 's/.*=//')
tmpfs_nr_inodes=$(tr ' ' '\n' < /proc/cmdline | grep tmpfs_nr_inodes\= | sed 's/.*=//')
tmpfs_mode=$(tr ' ' '\n' < /proc/cmdline | grep tmpfs_mode\= | sed 's/.*=//')
if [ "$tmpfs_size" != "" ]; then
tmpfs_opts="size=$tmpfs_size"
fi
if [ "$tmpfs_nr_blocks" != "" ]; then
if [ "$tmpfs_opts" != "" ]; then
tmpfs_opts="${tmpfs_opts},nr_blocks=$tmpfs_nr_blocks"
else
tmpfs_opts="nr_blocks=$tmpfs_nr_blocks"
fi
fi
if [ "$tmpfs_nr_inodes" != "" ]; then
if [ "$tmpfs_opts" != "" ]; then
tmpfs_opts="${tmpfs_opts},nr_inodes=$tmpfs_nr_inodes"
else
tmpfs_opts="nr_inodes=$tmpfs_nr_inodes"
fi
fi
if [ "$tmpfs_mode" != "" ]; then
if [ "$tmpfs_opts" != "" ]; then
tmpfs_opts="${tmpfs_opts},mode=$tmpfs_mode"
else
tmpfs_opts="mode=$tmpfs_mode"
fi
fi
if [ "$tmpfs_opts" != "" ]; then
tmpfs_opts="-o $tmpfs_opts"
fi
unset tmpfs_size
unset tmpfs_nr_blocks
unset tmpfs_nr_inodes
unset tmpfs_mode
}
#
################################################################################
#
# Switch root to tmpfs
#
#switch_root_to_tmpfs() {
# local MODULE=tmpfs
# logmsg
# logmsg switch_root_to_tmpfs
# logmsg "Loading $MODULE... "
# modprobe $MODULE 2>/dev/null && logmsg "done!" || logmsg "Didn't load -- assuming it's built into the kernel."
# parse_tmpfs_opts
#
# # Switch root over to tmpfs so we don't have to worry about the size of
# # the tarball and binaries that users may decide to copy over. -BEF-
# if [ -d /old_root ]; then
# logmsg
# logmsg "already switched to tmpfs..."
# else
# logmsg
# logmsg "switching root to tmpfs..."
#
# mkdir -p /new_root || shellout
# mount tmpfs /new_root -t tmpfs $tmpfs_opts || shellout
#
# cd / || shellout
# cp -a `/bin/ls | grep -v -E '^(new_root|dev)$'` /new_root/ || shellout
#
# mkdir -p /new_root/dev || shellout
# mount -t devtmpfs -o mode=0755 none /new_root/dev || shellout
#
# cd /new_root || shellout
# mkdir -p old_root || shellout
# pivot_root . old_root || switch_root
# fi
#
# unset tmpfs_opts
#}
#
################################################################################
################################################################################
#
mount_initial_filesystems() {
# Much of this taken from "init" from an Ubuntu Lucid initrd.img
logmsg
logmsg mount_initial_filesystems
[ -d /dev ] || mkdir -m 0755 /dev
[ -d /root ] || mkdir -m 0700 /root
[ -d /sys ] || mkdir /sys
[ -d /proc ] || mkdir /proc
[ -d /tmp ] || mkdir /tmp
mkdir -p /var/lock
mount -t sysfs -o nodev,noexec,nosuid none /sys
mount -t proc -o nodev,noexec,nosuid none /proc
# Note that this only becomes /dev on the real filesystem if udev's scripts
# are used; which they will be, but it's worth pointing out
if ! mount -t devtmpfs -o mode=0755 none /dev; then
mount -t tmpfs -o mode=0755 none /dev
mknod -m 0600 /dev/console c 5 1
mknod -m 0666 /dev/null c 1 3
mknod -m 0660 /dev/kmsg c 1 11
fi
mkdir /dev/pts
mount -t devpts -o noexec,nosuid,gid=5,mode=0620 none /dev/pts || true
}
#
################################################################################
################################################################################
#
monitor_save_dmesg() {
if [ -z $MONITOR_SERVER ]; then
return
fi
logmsg
logmsg monitor_save_dmesg
dmesg -s 16392 > /tmp/si_monitor.log
}
#
################################################################################
#
start_udevd() {
logmsg
logmsg start_udevd
echo -n " "
/etc/init.d/udev start
# If udev failed fall back to a static /dev
if [ $? -ne 0 ]; then
logmsg "failed!"
#XXX -delete me -BEF- - logmsg "Creating a static /dev..."
# cd / && tar -xzf dev.tar.gz || shellout
logmsg done
fi
}
#
################################################################################
#
# Configure loopback interface (may as well)
ifconfig_loopback() {
logmsg
logmsg ifconfig_loopback
ifconfig lo 127.0.0.1
}
#
################################################################################
#
# Load any modules that were placed in the my_modules directory prior to
# running "make initrd.gz". -BEF-
load_my_modules() {
logmsg
logmsg load_my_modules
cd /my_modules || shellout
sh ./INSMOD_COMMANDS
}
#
################################################################################
#
# read in varibles obtained from kernel appends
#
read_kernel_append_parameters() {
logmsg
logmsg read_kernel_append_parameters
. /tmp/kernel_append_parameter_variables.txt
}
#
################################################################################
#
# Variable-ize /proc/cmdline arguments
#
variableize_kernel_append_parameters() {
logmsg
logmsg variableize_kernel_append_parameters
cat /proc/cmdline | tr ' ' '\n' | grep '=' > /tmp/kernel_append_parameter_variables.txt
}
#
################################################################################
#
# Look for local.cfg file
# This code inspired by Ian McLeod <ian@valinux.com>
#
read_local_cfg() {
logmsg
logmsg read_local_cfg
if [ "x$SKIP_LOCAL_CFG" = "xy" ]; then
logmsg "Skipping local.cfg: option SKIP_LOCAL_CFG=y has been specified"
return
fi
# Try with local.cfg directly from initrd.
if [ -f /local.cfg ]; then
cp -f /local.cfg /tmp/local.cfg
fi
#
# BEGIN try hard drive
#
if [ ! -z "$LAST_ROOT" ]; then
logmsg
logmsg "Checking for /local.cfg file on hard drive..."
mkdir /last_root
logmsg "Mounting hard drive..."
mount $LAST_ROOT /last_root -o ro > /dev/null 2>&1
if [ $? != 0 ]; then
logmsg "FATAL: Couldn't mount hard drive!"
logmsg "Your kernel must have all necessary block and filesystem drivers compiled in"
logmsg "statically (not modules) in order to use a local.cfg on your hard drive. The"
logmsg "standard SystemImager kernel is modular, so you will need to compile your own"
logmsg "kernel. See the SystemImager documentation for details. To proceed at this"
logmsg "point, you will need to unset the LAST_ROOT append parameter by typing"
logmsg ""systemimager LAST_ROOT=", or similar, at your boot prompt. This will not use"
logmsg "the local.cfg file on your hard drive, but will still use one on a floppy."
shellout
fi
if [ -f /last_root/local.cfg ]; then
logmsg "Found /local.cfg on hard drive."
logmsg "Copying /local.cfg settings to /tmp/local.cfg."
cat /last_root/local.cfg >> /tmp/local.cfg || shellout
else
logmsg "No /local.cfg on hard drive."
fi
logmsg "Unmounting hard drive..."
umount /last_root || shellout
logmsg
fi
# END try hard drive
### BEGIN try floppy ###
logmsg "Checking for floppy diskette."
logmsg 'YOU MAY SEE SOME "wrong magic" ERRORS HERE, AND THAT IS NORMAL.'
mkdir -p /floppy
mount /dev/fd0 /floppy -o ro > /dev/null 2>&1
if [ $? = 0 ]; then
logmsg "Found floppy diskette."
if [ -f /floppy/local.cfg ]; then
logmsg "Found /local.cfg on floppy."
logmsg "Copying /local.cfg settings to /tmp/local.cfg."
logmsg "NOTE: local.cfg settings from a floppy will override settings from"
logmsg " a local.cfg file on your hard drive and DHCP."
# We use cat instead of copy, so that floppy settings can
# override hard disk settings. -BEF-
cat /floppy/local.cfg >> /tmp/local.cfg || shellout
else
logmsg "No /local.cfg on floppy diskette."
fi
else
logmsg "No floppy diskette in drive."
fi
### END try floppy ###
# /tmp/local.cfg may be created from a local.cfg file on the hard drive, or a
# floppy. If both are used, settings on the floppy take precedence. -BEF-
if [ -f /tmp/local.cfg ]; then
logmsg "Reading configuration from /tmp/local.cfg"
. /tmp/local.cfg || shellout
fi
}
#
################################################################################
#
# Configure network interface using local.cfg settings if possible, else
# use DHCP. -BEF-
#
start_network() {
logmsg
logmsg start_network
if [ ! -z $IPADDR ]; then
# configure interface and add default gateway
ifconfig $DEVICE $IPADDR netmask $NETMASK broadcast $BROADCAST
if [ $? != 0 ]; then
logmsg
logmsg "I couldn't configure the network interface using your pre-boot settings:"
logmsg " DEVICE: $DEVICE"
logmsg " IPADDR: $IPADDR"
logmsg " NETMASK: $NETMASK"
logmsg " BROADCAST: $BROADCAST"
logmsg
shellout
fi
if [ ! -z $GATEWAY ]; then
route add default gw $GATEWAY
if [ $? != 0 ]; then
logmsg
logmsg "The command \"route add default gw $GATEWAY\" failed."
logmsg "Check your pre-boot network settings."
logmsg
shellout
fi
fi
else
### try dhcp ###
logmsg "IP Address not set with pre-boot settings."
### BEGIN ether sleep ###
# Give the switch time to start passing packets. Some switches won't
# forward packets until 30 seconds or so after an interface comes up.
# This means the dhcp server won't even get the request for 30 seconds.
# Many ethernet cards aren't considered "up" by the switch until the
# driver is loaded. Because the driver is compiled directly into the
# kernel here, the driver is definitely loaded at this point.
#
# Default is 0. The recommended setting of ETHER_SLEEP=35 can be set
# with a local.cfg file. -BEF-
#
[ -z $ETHER_SLEEP ] && ETHER_SLEEP=0
logmsg
logmsg "sleep $ETHER_SLEEP: This is to give your switch (if you're using one) time to"
logmsg " recognize your ethernet card before we try the network."
logmsg " Tip: You can use <ctrl>+<c> to pass the time (pun intended)."
logmsg
count_loop $ETHER_SLEEP
logmsg
### END ether sleep ###
# create directory to catch dhcp information
DHCLIENT_DIR="/var/state/dhcp"
mkdir -p $DHCLIENT_DIR
# combine systemimager code to the stock debian dhclient-script
# and make executable
cat /etc/dhclient-script.si-prefix \
/etc/dhclient-script.debian-dist \
> /etc/dhclient-script
chmod +x /etc/dhclient-script
# be sure AF_PACKET is supported in the kernel
[ -f /lib/modules/`uname -r`/modules.dep ] && modprobe af_packet &> /dev/null
# get info via dhcp
logmsg
logmsg "dhclient"
dhclient $DEVICE
if [ ! -s ${DHCLIENT_DIR}/dhclient.leases ]; then
logmsg
logmsg "I couldn't configure the network interface using DHCP."
logmsg
shellout
fi
if [ -z ${DEVICE} ]; then
# Figure out which interface actually got configured.
# Suggested by James Oakley.
#
DEVICE=`grep interface ${DHCLIENT_DIR}/dhclient.leases | \
sed -e 's/^.*interface "//' -e 's/";//'`
fi
# read dhcp info in as variables -- this file will be created by
# the /etc/dhclient-start script that is run automatically by
# dhclient.
. /tmp/dhcp_info.${DEVICE} || shellout
### END dhcp ###
# Re-read configuration information from local.cfg to over-ride
# DHCP settings, if necessary. -BEF-
if [ -f /tmp/local.cfg ]; then
logmsg
logmsg "Overriding any DHCP settings with pre-boot local.cfg settings."
. /tmp/local.cfg || shellout
fi
logmsg
logmsg "Overriding any DHCP settings with pre-boot settings from kernel append"
logmsg "parameters."
read_kernel_append_parameters
fi
}
#
################################################################################
#
# Ping test
ping_test() {
logmsg
logmsg ping_test
# The reason we don't ping the IMAGESERVER if FLAMETHROWER_DIRECTORY_PORTBASE
# is set, is that the client may never be given, know, or need to know, the
# IP address of the imageserver because the client is receiving _all_ of it's
# data via multicast, which is more like listening to a channel, as compared
# with connecting directly to a server. -BEF-
#
if [ ! -z "$FLAMETHROWER_DIRECTORY_PORTBASE" ]; then
PING_DESTINATION=$GATEWAY
HOST_TYPE="default gateway"
else
PING_DESTINATION=$IMAGESERVER
HOST_TYPE="SystemImager server"
fi
logmsg
logmsg "Pinging your $HOST_TYPE to ensure we have network connectivity."
logmsg
# Ping test code submitted by Grant Noruschat <grant@eigen.ee.ualberta.ca>
# modified slightly by Brian Finley.
PING_COUNT=1
PING_EXIT_STATUS=1
while [ "$PING_EXIT_STATUS" != "0" ]
do
logmsg "PING ATTEMPT $PING_COUNT: "
ping -c 1 $PING_DESTINATION
PING_EXIT_STATUS=$?
if [ "$PING_EXIT_STATUS" = "0" ]; then
logmsg
logmsg " We have connectivity to your $HOST_TYPE!"
fi
PING_COUNT=$(( $PING_COUNT + 1 ))
if [ "$PING_COUNT" = "4" ]; then
logmsg
logmsg " WARNING: Failed ping test."
logmsg " Despite this seemingly depressing result, I will attempt"
logmsg " to proceed with the install. Your $HOST_TYPE may be"
logmsg " configured to not respond to pings, but it wouldn't hurt"
logmsg " to double check that your networking equipment is"
logmsg " working properly!"
logmsg
sleep 5
PING_EXIT_STATUS=0
fi
done
unset PING_DESTINATION
unset HOST_TYPE
}
#
################################################################################
#
start_syslogd() {
logmsg
logmsg start_syslogd
if [ ! -z $LOG_SERVER ]; then
logmsg "Starting syslogd..."
[ -z $LOG_SERVER_PORT ] && LOG_SERVER_PORT="514"
syslogd -R ${LOG_SERVER}:${LOG_SERVER_PORT}
# as long as we are starting syslogd, start klogd as well, in case
# there is a kernel issue that happens
klogd
# set USELOGGER=1 so logmsg knows to do the right thing
USELOGGER=1
logmsg "Successfully started syslogd!"
fi
}
#
################################################################################
#
show_loaded_modules() {
# Show loaded modules
logmsg ">> Loaded kernel modules:"
for m in `cut -d' ' -f1 /proc/modules`; do
logmsg "$m"
done
}
#
################################################################################
#
get_hostname_by_hosts_file() {
logmsg
logmsg get_hostname_by_hosts_file
#
# Look in $FILE for that magic joy.
#
FILE=${SCRIPTS_DIR}/hosts
if [ -e $FILE ]; then
logmsg "Hosts file exists..."
# add escape characters to IPADDR so that it can be used to find HOSTNAME below
IPADDR_ESCAPED=`echo "$IPADDR" | sed -e 's/\./\\\./g'`
# get HOSTNAME by parsing hosts file
logmsg "Searching for this machine's hostname in $FILE by IP: $IPADDR"
# Command summary by line:
# 1: convert tabs to spaces -- contains a literal tab: <ctrl>+<v> then <tab>
# 2: remove comments
# 3: add a space at the beginning of every line
# 4: get line with IP address (no more no less)
# 5: strip out ip address
# 6: strip out space(s) before first hostname on line
# 7: remove any aliases on line
# 8: remove domain name, leaving naught but the hostname, naked as the day it were born
HOSTNAME=`
sed 's/[[:space:]]/ /g' $FILE | \
grep -v '^ *#' | \
sed 's/^/ /' | \
grep " $IPADDR_ESCAPED " | \
sed 's/ [0-9]*\.[0-9]*\.[0-9]*\.[0-9]*//' | \
sed 's/ *//' | \
sed 's/ .*//' | \
sed 's/\..*$//g'
`
else
logmsg "No hosts file."
fi
}
#
################################################################################
#
get_hostname_by_dns() {
logmsg
logmsg get_hostname_by_dns
# Get base hostname. For example, www7.domain.com will become www7. -BEF-
HOSTNAME=`nslookup $IPADDR | sed -ne "s/^Address 1:[[:space:]]\+$IPADDR[[:space:]]\+\([^\.]\+\).*$/\1/p"`
}
#
################################################################################
#
get_base_hostname() {
BASE_HOSTNAME=`echo $HOSTNAME | sed "s/[.0-9].*$//"`
}
#
################################################################################
#
get_group_name() {
if [ -f ${SCRIPTS_DIR}/cluster.txt ]; then
[ -z "$GROUPNAMES" ] && \
GROUPNAMES=`unique $(grep "^${HOSTNAME}:" ${SCRIPTS_DIR}/cluster.txt | cut -d: -f2 | tr "\n" ' ')`
[ -z "$IMAGENAME" ] && \
IMAGENAME=`grep "^${HOSTNAME}:" ${SCRIPTS_DIR}/cluster.txt | cut -d: -f3 | grep -v '^[[:space:]]*$' | sed -ne '1p'`
if [ -z "$GROUP_OVERRIDES" ]; then
GROUP_OVERRIDES=`reverse $(unique $(grep "^${HOSTNAME}:" ${SCRIPTS_DIR}/cluster.txt | cut -d: -f4 | tr "\n" ' '))`
# Add the global override on top (least important).
GROUP_OVERRIDES="`sed -ne 's/^# global_override=:\([^:]*\):$/\1/p' ${SCRIPTS_DIR}/cluster.txt` $GROUP_OVERRIDES"
fi
fi
}
#
################################################################################
#
choose_autoinstall_script() {
logmsg
logmsg choose_autoinstall_script
#
# Get the base hostname for the last attempt at choosing an autoinstall
# script. For example, if the hostname is compute99, then try to get
# compute.master. -BEF-
#
get_base_hostname
# Get group name (defined in /etc/systemimager/cluster.xml on the image
# server). -AR-
get_group_name
#
# If SCRIPTNAME is specified as a kernel append, or via local.cfg, then use that script.
#
if [ ! -z $SCRIPTNAME ]; then
#
# SCRIPTNAME was specified, but let's be flexible. Try explicit first, then .master, .sh. -BEF-
#
SCRIPTNAMES="${SCRIPTS_DIR}/${SCRIPTNAME} ${SCRIPTS_DIR}/${SCRIPTNAME}.sh ${SCRIPTS_DIR}/${SCRIPTNAME}.master"
else
#
# If SCRIPTNAME was not specified, choose one, in order of preference. First hit wins.
# Order of preference is:
# HOSTNAME (i.e. node001.sh)
# GROUPNAMES (i.e. Login.sh) - see /etc/systemimager/cluster.xml on the image server
# BASE_HOSTNAME (i.e. node.sh)
# IMAGENAME (i.e. ubuntu7_04.sh)
#
[ ! -z $HOSTNAME ] && \
SCRIPTNAMES="${SCRIPTNAMES} ${SCRIPTS_DIR}/${HOSTNAME}.sh ${SCRIPTS_DIR}/${HOSTNAME}.master"
for GROUPNAME in $GROUPNAMES; do
SCRIPTNAMES="${SCRIPTNAMES} ${SCRIPTS_DIR}/${GROUPNAME}.sh ${SCRIPTS_DIR}/${GROUPNAME}.master"
done
unset GROUPNAME
[ ! -z $BASE_HOSTNAME ] && \
SCRIPTNAMES="${SCRIPTNAMES} ${SCRIPTS_DIR}/${BASE_HOSTNAME}.sh ${SCRIPTS_DIR}/${BASE_HOSTNAME}.master"
[ ! -z $IMAGENAME ] && \
SCRIPTNAMES="${SCRIPTNAMES} ${SCRIPTS_DIR}/${IMAGENAME}.sh ${SCRIPTS_DIR}/${IMAGENAME}.master"
fi
#
# Choose a winner!
#
for SCRIPTNAME in $SCRIPTNAMES
do
[ -e $SCRIPTNAME ] && break
done
# Did we really find one, or just exit the loop without a 'break'
if [ ! -e $SCRIPTNAME ]; then
logmsg "FATAL: couldn't find any of the following autoinstall scripts!"
logmsg "---"
logmsg ${SCRIPTNAMES}
logmsg "---"
logmsg "Be sure that at least one of the scripts above exists in"
logmsg "the autoinstall scripts directory on your image server."
logmsg
logmsg "See also: si_mkautoinstallscript(8)."
shellout
fi
logmsg "Using autoinstall script: ${SCRIPTNAME}"
}
#
################################################################################
#
run_autoinstall_script() {
logmsg
logmsg run_autoinstall_script
# Run the autoinstall script.
chmod 755 $SCRIPTNAME || shellout
logmsg ">>> $SCRIPTNAME"
$SCRIPTNAME || shellout
}
#
################################################################################
#
# Description: remove duplicated elements from a list, preserving the order.
#
unique() {
ret=
for i in $*; do
flag=0
for j in $ret; do
[ "$i" = "$j" ] && flag=1 && break
done
[ $flag -eq 0 ] && ret="$ret $i"
done
echo $ret
unset i j flag ret
}
#
################################################################################
#
# Description: reverse a list
#
reverse() {
ret=
for i in $*; do
ret="$i $ret"
done
echo $ret
unset i
}
#
################################################################################
#
run_pre_install_scripts() {
logmsg
logmsg run_pre_install_scripts
get_base_hostname
# Get group name (defined in /etc/systemimager/cluster.xml on the image
# server). -AR-
get_group_name
if [ -e "${SCRIPTS_DIR}/pre-install/" ]; then
cd ${SCRIPTS_DIR}/pre-install/
PRE_INSTALL_SCRIPTS="$PRE_INSTALL_SCRIPTS `ls | grep "^[0-9][0-9]all\..*"`"
PRE_INSTALL_SCRIPTS="$PRE_INSTALL_SCRIPTS `ls | grep "^[0-9][0-9]${IMAGENAME}\..*"`"
PRE_INSTALL_SCRIPTS="$PRE_INSTALL_SCRIPTS `ls | grep "^[0-9][0-9]${BASE_HOSTNAME}\..*"`"
for GROUPNAME in ${GROUPNAMES}; do
PRE_INSTALL_SCRIPTS="$PRE_INSTALL_SCRIPTS `ls | grep "^[0-9][0-9]${GROUPNAME}\..*"`"
done
unset GROUPNAME
PRE_INSTALL_SCRIPTS="$PRE_INSTALL_SCRIPTS `ls | grep "^[0-9][0-9]${HOSTNAME}\..*"`"
# Now, to get rid of those pesky newlines. -BEF-
PRE_INSTALL_SCRIPTS=`echo $PRE_INSTALL_SCRIPTS | tr '\n' ' '`
if [ ! -z "`echo ${PRE_INSTALL_SCRIPTS}|sed 's/ //'`" ]; then
for PRE_INSTALL_SCRIPT in `unique $PRE_INSTALL_SCRIPTS`
do
logmsg ">>> $PRE_INSTALL_SCRIPT"
chmod +x $PRE_INSTALL_SCRIPT || shellout
./$PRE_INSTALL_SCRIPT || shellout
done
else
logmsg "No pre-install scripts found."
fi
if [ -e "/tmp/pre-install_variables.txt" ]; then
. /tmp/pre-install_variables.txt
fi
fi
}
#
################################################################################
#
run_post_install_scripts() {
logmsg
logmsg run_post_install_scripts
get_base_hostname
# Get group name (defined in /etc/systemimager/cluster.xml on the image
# server). -AR-
get_group_name
if [ -e "${SCRIPTS_DIR}/post-install/" ]; then
# make a copy of variables.txt available to post-install scripts -BEF-
cp -f /tmp/variables.txt ${SCRIPTS_DIR}/post-install/
cd ${SCRIPTS_DIR}/post-install/
POST_INSTALL_SCRIPTS="$POST_INSTALL_SCRIPTS `ls | grep "^[0-9][0-9]all\..*" | grep -v "~$" `"
POST_INSTALL_SCRIPTS="$POST_INSTALL_SCRIPTS `ls | grep "^[0-9][0-9]${IMAGENAME}\..*" | grep -v "~$" `"
POST_INSTALL_SCRIPTS="$POST_INSTALL_SCRIPTS `ls | grep "^[0-9][0-9]${BASE_HOSTNAME}\..*" | grep -v "~$" `"
for GROUPNAME in ${GROUPNAMES}; do
POST_INSTALL_SCRIPTS="$POST_INSTALL_SCRIPTS `ls | grep "^[0-9][0-9]${GROUPNAME}\..*" | grep -v "~$" `"
done
POST_INSTALL_SCRIPTS="$POST_INSTALL_SCRIPTS `ls | grep "^[0-9][0-9]${HOSTNAME}\..*" | grep -v "~$" `"
# Now, to get rid of those pesky newlines. -BEF-
POST_INSTALL_SCRIPTS=`echo $POST_INSTALL_SCRIPTS | tr '\n' ' '`
if [ ! -z "`echo ${POST_INSTALL_SCRIPTS}|sed 's/ //'`" ]; then
mkdir -p /a/tmp/post-install/ || shellout
rsync -a ${SCRIPTS_DIR}/post-install/ /a/tmp/post-install/ || shellout
for POST_INSTALL_SCRIPT in `unique $POST_INSTALL_SCRIPTS`
do
if [ -e "$POST_INSTALL_SCRIPT" ]; then
logmsg ">>> $POST_INSTALL_SCRIPT"
chmod +x /a/tmp/post-install/$POST_INSTALL_SCRIPT || shellout
chroot /a/ /tmp/post-install/$POST_INSTALL_SCRIPT || shellout
fi
done
else
logmsg "No post-install scripts found."
fi
# Clean up post-install script directory.
rm -rf /a/tmp/post-install/ || shellout
fi
}
#
################################################################################
#
# Stuff for SSH installs
#
start_sshd() {
mkdir -p /root/.ssh/ || shellout
# download ssh authorized_keys if it's not present into the initrd.
if [ ! -f /root/.ssh/authorized_keys ]; then
if [ -z $SSH_DOWNLOAD_URL ]; then
logmsg
logmsg "error: authorized_keys not found and SSH_DOWNLOAD_URL not defined in the installation parameters!"
logmsg "sshd can't be started!"
shellout
fi
CMD="wget ${SSH_DOWNLOAD_URL}/${ARCH}/ssh/authorized_keys"
logmsg
logmsg $CMD
$CMD || shellout
fi
# set permissions to 600 -- otherwise, sshd will refuse to use it
chmod 600 /root/.ssh/authorized_keys || shellout
# must be owned by root
chown -R 0.0 /root/
# create a private host key for this autoinstall client
logmsg
logmsg "Using ssh-keygen to create this hosts private key"
logmsg
mkdir -p /var/empty || shellout
if [ ! -f /etc/ssh/ssh_host_dsa_key ]; then
ssh-keygen -t dsa -N "" -f /etc/ssh/ssh_host_dsa_key || shellout
fi
if [ ! -f /etc/ssh/ssh_host_rsa_key ]; then
ssh-keygen -t rsa -N "" -f /etc/ssh/ssh_host_rsa_key || shellout
fi
# try to mount devpts (sometimes it's not really necessary)
mkdir -p /dev/pts
mount -t devpts none /dev/pts >/dev/null 2>&1
# fire up sshd
mkdir -p /var/run/sshd || shellout
chmod 0755 /var/run/sshd || shellout
/usr/sbin/sshd || shellout
logmsg "sshd started"
touch /tmp/sshd_started
}
#
################################################################################
#
start_ssh() {
# create root's ssh dir
mkdir -p /root/.ssh
############################################################################
#
# If a private key exists, put it in the right place so this autoinstall
# client can use it to authenticate itself to the imageserver.
#
if [ -e /root/.ssh/id_dsa ]; then
# (ssh2 dsa style user private key)
PRIVATE_KEY=/root/.ssh/id_dsa
chmod 600 $PRIVATE_KEY || shellout
elif [ -e /root/.ssh/id_rsa ]; then
# (ssh2 rsa style user private key)
PRIVATE_KEY=/root/.ssh/id_rsa
chmod 600 $PRIVATE_KEY || shellout
elif [ -e /floppy/id_dsa ]; then
# (ssh2 dsa style user private key) from floppy
PRIVATE_KEY=/root/.ssh/id_dsa
cp /floppy/id_dsa $PRIVATE_KEY || shellout
chmod 600 $PRIVATE_KEY || shellout
elif [ -e /floppy/id_rsa ]; then
#
# (ssh2 rsa style user private key) from floppy
PRIVATE_KEY=/root/.ssh/id_rsa
cp /floppy/id_rsa $PRIVATE_KEY || shellout
chmod 600 $PRIVATE_KEY || shellout
fi
#
############################################################################
# If we have a private key from the media above, go ahead and open secure tunnel
# to the imageserver and continue with the autoinstall like normal.
if [ ! -z $PRIVATE_KEY ]; then
# With the prep ready, start the ssh tunnel connection.
#
# Determine if we should run interactive and set redirection options appropriately.
# So if the key is blank, go interactive. (Suggested by Don Stocks <don_stocks@leaseloan.com>)
if [ -s $PRIVATE_KEY ]; then
# key is *not* blank
REDIRECTION_OPTIONS="> /dev/null 2>&1"
else
# key is blank - go interactive
REDIRECTION_OPTIONS=""
fi
# Default ssh user is root.
[ -z $SSH_USER ] && SSH_USER=root
CMD="ssh -N -l $SSH_USER -n -f -L873:127.0.0.1:873 $IMAGESERVER $REDIRECTION_OPTIONS"
logmsg $CMD
$CMD || shellout
# Since we're using SSH, change the $IMAGESERVER variable to reflect
# the forwarded connection.
IMAGESERVER=127.0.0.1
else
########################################################################
#
# Looks like we didn't get a private key so let's just fire up
# sshd and wait for someone to connect to us to initiate the
# next step of the autoinstall.
#
if [ -z $HOSTNAME ]; then
logmsg
logmsg "Trying to get hostname via DNS..."
logmsg
get_hostname_by_dns
fi
if [ -z $HOSTNAME ]; then
HOST_OR_IP=$IPADDR
else
HOST_OR_IP=$HOSTNAME
fi
if [ ! -f /tmp/sshd_started ]; then
start_sshd
# Give sshd time to initialize before we yank the parent process
# rug out from underneath it.
sleep 15
fi
logmsg
logmsg
logmsg "Started sshd. You must now go to your imageserver and issue"
logmsg "the following command:"
logmsg
logmsg " \"si_pushinstall --hosts ${HOST_OR_IP}\"."
logmsg
logmsg
# Since we're using SSH, change the $IMAGESERVER variable to reflect
# the forwarded connection.
IMAGESERVER=127.0.0.1
while [ ! -f /tmp/si_pushupdate.completed ]; do
sleep 5
done
fi
}
#
################################################################################
#
# send_monitor_msg
#
# Description:
# Redirect a message to the monitor server.
#
# Usage: send_monitor_msg "var=$msg"
#
send_monitor_msg() {
if [ -z $MONITOR_SERVER ]; then
return
fi
if [ -z $MONITOR_PORT ]; then
MONITOR_PORT=8181
fi
# Message to send.
msg=`echo "$@"`
# Get the client mac address.
if [ -z "$mac" ]; then
mac=`ifconfig $DEVICE 2>/dev/null | sed -ne "s/.*HWaddr //p" | sed "s/ //g" | sed s/:/./g`
fi
# Collect some special info only after proc file system is mounted.
if [ `mount 2>/dev/null | grep proc > /dev/null; echo $?` -eq 0 ]; then
# Collect the CPU info.
if [ -z "$cpu" ]; then
cpu=$(echo `cat /proc/cpuinfo | grep "cpu\|clock\|model name\|cpu MHz" | grep -v "cpu family" | sed -ne '1,2p' | sed "s/.*: //" | sed "s/^\([0-9\.]*\)MHz$/(\1 MHz)/" | sed "s/^\([0-9\.]*\)$/(\1 MHz)/"` | sed "s/\(MHz)\)/\1 |/g" | sed "s/ |$//")
fi
# Collect the number of CPUs.
if [ -z "$ncpus" ]; then
ncpus=$((`cat /proc/cpuinfo | grep "^processor" | sed -n '$p' | sed "s/.*: \([0-9]\)*$/\1/"` + 1))
fi
# Collect the kernel information.
if [ -z "$kernel_name" ]; then
kernel_name=`uname -r`
fi
# Collect the amount of phyisical memory.
if [ -z "$mem" ]; then
mem=`cat /proc/meminfo | sed -ne "s/MemTotal: *//p" | sed "s/ kB//"`
fi
# Evaluate the amount of available RAM.
tmpfs=`df | grep tmpfs | grep "/$" | sed "s/.* \([0-9]*%\) .*/\1/"`
# Evaluate the uptime of the client.
time=`cat /proc/uptime | sed "s/\..*//"`
fi
# Report the message to the monitor server.
send_msg=`echo "mac=$mac:ip=$IPADDR:host=$HOSTNAME:cpu=$cpu:ncpus=$ncpus:kernel=$kernel_name:mem=$mem:os=$IMAGENAME:tmpfs=$tmpfs:time=$time:$msg"`
# Send data to monitor server.
echo "$send_msg" | nc $MONITOR_SERVER $MONITOR_PORT
}
#
################################################################################
#
# send_monitor_stdout
#
# Description:
# Redirect a stdout of a command to the monitor console.
#
# Usage: <cmd> | send_monitor_stdout
#
send_monitor_stdout() {
while read l; do
# echo to the console -AR-
echo "$l"
# Send the message to the monitor daemon.
if [ "x$MONITOR_CONSOLE" = "xy" ]; then
MONITOR_CONSOLE=yes
fi
if [ "x$MONITOR_CONSOLE" = "xyes" ]; then
# Log message into the global monitor log.
echo "$l" >> /tmp/si_monitor.log
fi
done
}
#
################################################################################
#
# Initialize the monitor server
#
init_monitor_server() {
# Send initialization status.
send_monitor_msg "status=0:first_timestamp=on:speed=0"
logmsg "Monitoring initialized."
# Start client log gathering server: for each connection
# to the local client on port 8181 the full log is sent
# to the requestor. -AR-
if [ "x$MONITOR_CONSOLE" = "xy" ]; then
MONITOR_CONSOLE=yes
fi
if [ "x$MONITOR_CONSOLE" = "xyes" ]; then
while :; do nc -p 8181 -l < /tmp/si_monitor.log; done &
fi
}
#
################################################################################
#
# Report installation status to the monitor server
#
start_report_task() {
# Reporting interval (in sec).
REPORT_INTERVAL=10
# Evaluate image size.
logmsg "Evaluating image size..."
if [ ! "x$BITTORRENT" = "xy" ]; then
IMAGESIZE=`rsync -av --numeric-ids $IMAGESERVER::$IMAGENAME | grep "total size" | sed -e "s/total size is \([0-9]*\).*/\1/"`
else
if [ -f "${TORRENTS_DIR}/image-${IMAGENAME}.tar.torrent" ]; then
torrent_file="${TORRENTS_DIR}/image-${IMAGENAME}.tar.torrent"
elif [ -f "${TORRENTS_DIR}/image-${IMAGENAME}.tar.gz.torrent" ]; then
torrent_file="${TORRENTS_DIR}/image-${IMAGENAME}.tar.gz.torrent"
else
logmsg "error: cannot find a valid torrent file for image ${IMAGENAME}"
shellout
fi
IMAGESIZE=`/bin/torrentinfo-console $torrent_file | sed -ne "s/file size\.*: \([0-9]*\) .*$/\1/p"`
fi
IMAGESIZE=`expr $IMAGESIZE / 1024`
logmsg " --> Image size = `expr $IMAGESIZE / 1024`MiB"
# Evaluate disks size.
LIST=`df 2>/dev/null | grep "/" | sed "s/ */ /g" | cut -d' ' -f3 | sed -ne 's/^\([0-9]*\)$/\1+/p'`0
DISKSIZE=`echo $LIST | bc`
# Spawn the report task -AR-
{
TOT=0; CURR_SIZE=0
while :; do
LIST=`df 2>/dev/null | grep "/" | sed "s/ */ /g" | cut -d' ' -f3 | sed -ne 's/^\([0-9]*\)$/\1+/p'`0
TOT=`echo $LIST | bc`
# Evaluate bandwidth.
speed=`echo "scale=2; (($TOT - $DISKSIZE) - $CURR_SIZE) / $REPORT_INTERVAL" | bc`
speed=`echo "scale=2; if ($speed >= 0) { print $speed; } else { print 0; }" | bc`
# Evaluate status.
CURR_SIZE=$(($TOT - $DISKSIZE))
status=`echo "scale=2; $CURR_SIZE * 100 / $IMAGESIZE" | bc`
if [ `echo "scale=2; $status <= 0" | bc` -eq 1 ]; then
status=1
elif [ `echo "scale=2; $status >= 100" | bc` -eq 1 ]; then
status=99
fi
# Send status and bandwidth to the monitor server.
send_monitor_msg "status=$status:speed=$speed"
# Wait $REPORT_INTERVAL sec between each report -AR-
sleep $REPORT_INTERVAL
done
}&
logmsg "Report task started."
REPORT_PID=$!
}
#
################################################################################
#
# Stop to report installation status to the monitor server
#
stop_report_task() {
if [ ! -z $REPORT_PID ]; then
kill -9 $REPORT_PID
logmsg "Report task stopped."
fi
# Try to report the error to the monitor server.
send_monitor_msg "status=$1:speed=0"
}
#
################################################################################
#
# Beep incessantly
#
beep_incessantly() {
local SECONDS=1
local MINUTES
local MINUTES_X_SIXTY
{ while :;
do
echo -n -e "\\a"
if [ $SECONDS -lt 60 ]; then
logmsg "I have been done for $SECONDS seconds. Reboot me already!"
else
MINUTES=`echo "$SECONDS / 60"|bc`
MINUTES_X_SIXTY=`echo "$MINUTES * 60"|bc`
if [ "$MINUTES_X_SIXTY" = "$SECONDS" ]; then
logmsg "I have been done for $MINUTES minutes now. Reboot me already!"
fi
fi
sleep 1
SECONDS=`echo "$SECONDS + 1"|bc`
done
}
}
#
################################################################################
#
# Beep incessantly
#
# Usage: beep [$COUNT [$INTERVAL]]
# Usage: beep
beep() {
local COUNT=$1
local INTERVAL=$2
[ -z $COUNT ] && COUNT=1
[ -z $INTERVAL ] && INTERVAL=1
local COUNTED=0
until [ "$COUNTED" = "$COUNT" ]
do
echo -n -e "\\a"
sleep $INTERVAL
COUNTED=$(( $COUNTED + 1 ))
done
}
#
################################################################################
#
# Print out dots while sleeping
#
# Usage: sleep_loop [[$COUNT [$INTERVAL]] $CHARACTER]
# Usage: sleep_loop
sleep_loop() {
local COUNT=$1
local INTERVAL=$2
local CHARACTER=$3
local COUNTED
[ -z $COUNT ] && COUNT=1
[ -z $INTERVAL ] && INTERVAL=1
[ -z $CHARACTER ] && CHARACTER=.
COUNTED=0
until [ "$COUNTED" = "$COUNT" ]
do
echo -n "$CHARACTER"
sleep $INTERVAL
COUNTED=$(( $COUNTED + 1 ))
done
}
#
################################################################################