From afdd5ef8a719add9f69529a9aaa4f201bb1e6444 Mon Sep 17 00:00:00 2001 From: sjing Date: Wed, 10 Apr 2013 06:18:46 +0000 Subject: [PATCH] use genesis kernel/initrd for sysclone. git-svn-id: https://svn.code.sf.net/p/xcat/code/xcat-core/trunk@15916 8638fb3e-16cb-4fca-ae20-7b5d299a9bcd --- xCAT-genesis-scripts/etc/init.d/functions | 1828 +++++++++++++++++++++ 1 file changed, 1828 insertions(+) create mode 100644 xCAT-genesis-scripts/etc/init.d/functions diff --git a/xCAT-genesis-scripts/etc/init.d/functions b/xCAT-genesis-scripts/etc/init.d/functions new file mode 100644 index 000000000..0744c87ed --- /dev/null +++ b/xCAT-genesis-scripts/etc/init.d/functions @@ -0,0 +1,1828 @@ +#!/bin/sh +# +# "SystemImager" +# +# Copyright (C) 1999-2011 Brian Elliott Finley +# +# $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. +# Sean Dague +# Dann Frazier +# Curtis Zinzilieta +# + + +################################################################################ +# +# 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 + is hit (SIGINT, or Signal 2). Thanks to +# CCB 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 +" ; 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 ) + 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 +# +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 + 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 + # 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: + then + # 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 ) + 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: | 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 +} +# +################################################################################