New Fedora Diskless init script
Jump to navigation
Jump to search
| Author | unknown |
| Description | New Fedora Diskless init script |
| Supports |
#!/bin/bash
#
# disklessrc file for initrd (Initial Ram Disk)
#
# Copyright (C) 2003 Daniel Walsh <dwalsh@redhat.com>
#
# Copyright (C) 2005, 2006 Jason Vas Dias <jvdias@redhat.com> (Red Hat Inc.)
#
# Taken in part from James A. McQuillan <jam@McQuil.Com> linuxrc for LTSP
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
#
export LD_LIBRARY_PATH=/lib:/usr/lib:/usr/kerberos/lib
MODULE=""
PCICLASS="0200 0280 0680"
#
# This function is used to load the ETHERNET module
#
loadmodules() {
for MODULE in $1; do {
echo -n "Loading $MODULE module... "
if ! `grep "^$MODULE[ \ ]" /proc/modules > /dev/null`; then
if modprobe $MODULE; then
echo " Loaded $MODULE OK." ;
else
e=$?
echo "Module $MODULE load failed: $e";
return $e;
fi;
else
echo "module already loaded"
fi
} done
return 0;
}
#
# This function is used to find the correct module for hardware
# devices of PCI Class ID arguments that are on the PCI bus:
#
findModules()
{
matchClasses=(${1})
(/sbin/lspci -n | sed 's/Class\ //' | while read id class vendev rev;
# pciutils < 2.2 inserts 'Class' as 2nd string; >= 2.2 does not :-(
do
class=${class%:}
if [ ${#matchClasses[@]} -gt 0 ]; then
found=0
for matchClass in ${matchClasses[@]};
do
[ ${matchClass} = ${class} ] && found=1;
done;
[ $found -eq 0 ] && continue;
fi;
vendor='0x'"`printf '%8s' ${vendev%:*} | /sbin/sed 's/ /0/g'`"
device='0x'"`printf '%8s' ${vendev#*:} | /sbin/sed 's/ /0/g'`"
(/sbin/grep '[^# ][^# ]*[\ \ ][\ \ ]*'$vendor'[\ \ ]'$device /lib/modules/`/sbin/uname -r`/modules.pcimap) |
(while read m rest; do echo $m; done)
done
) | /sbin/uniq
}
#
# This function is used to load the correct ETHERNET modules
#
findhardware() {
no_modules=13
findModules "$PCICLASS" |
while read MODULE; do
echo "Found Ethernet Card Module: $MODULE"
loadmodules $MODULE && no_modules=0 ;
done
return $no_modules;
}
#
# This function is used to mount files/directories from the snapshot directory
# over the root directory.
#
mountfile () {
snapshotfile=/mnt/.snapshot/${2}${1}
dir=`dirname $snapshotfile`
#
# Check if file already exists in snapshot directory. If not attempt to copy
# from root directory to snapshot directory.
#
if [ ! -e $snapshotfile ]; then
mkdir -p $dir
echo "${1} missing from client specific area."
if [ -e /mnt/${1} ] ; then
echo "Copying ${1}"
rsync -a /mnt/${1} $snapshotfile
else
echo "Creating ${1}"
touch $snapshotfile
fi
else
# If dev directory already exists in snapshot directory, check if the root
# /dev directory is newer. If it is rsync the root directory over the
# snapshot directory.
if [ ${1} == "/dev" -a ${1} -nt ${dir}/dev ]; then
echo "RSYNC-ing /dev";
rsync -a /mnt/${1} $snapshotfile
fi
fi
#
# Mount the snapshotfile over the root file so the client will have r/w access
#
mount -n -o bind /mnt/.snapshot/${2}${1} /mnt/${1}
}
echo "==============================================================================="
echo "Running /disklessrc"
echo "Mounting /proc"
/bin/mount -n -t proc /proc /proc
if [ "${INITRD_DBG}" = "1" ]; then exec /bin/bash; fi
if [ -w /proc/progress ]; then echo 40 "Detecting network card" >/proc/progress; fi
if [ -z "${ETHERNET}" ]; then export ETHERNET="eth0"; fi
#
# Bring up the loopback interface first to avoid RHEL-4-U2's kernel-2.6.9-12.2.EL
# getting an Oops panic later on when the IPv6 module is loaded
#
/sbin/ifconfig lo 127.0.0.1 netmask 255.0.0.0 up
#
# Attempt to find and load the network card module
#
findhardware "$PCICLASS"
#
# load the NFS module
#
if [ ! -d /proc/sys/fs/nfs ]; then
loadmodules nfs
if [ $? -ne 0 ]; then
exec /bin/bash;
fi;
fi;
# Mount initrd root rw, and mount /tmp
echo "Mounting /"
mount -n -o remount,rw /
mount -n -t tmpfs /dev/shm /tmp
if [ "${INITRD_DBG}" = "2" ]; then exec /bin/bash; fi
#
# Setup dhclient to retrieve IP address
#
cat <<EOF >/tmp/dhclient.conf
interface "$ETHERNET" {
request subnet-mask,
broadcast-address,
routers,
domain-name,
domain-name-servers,
host-name,
root-path;
}
EOF
#
# dhclient runs as a daemon. Once it acquires the info from the
# server, it runs a script called /sbin/dhclient-script. That script
# will take care of configuring the interface.
#
if [ "${INITRD_DBG}" = "3" ]; then exec /bin/bash; fi
if [ -w /proc/progress ]; then echo 50 "Sending DHCP request" >/proc/progress; fi
# Ensure host/domain name are set to '' before running dhclient
/sbin/hostname '(none)'
# for network_functions' need_hostname()
/sbin/domainname ''
# Run dhclient -
# dhclient MAY set hostname and domainname if sent in DHCP options by server
#
echo "Running dhclient"
/bin/dhclient -1 -cf /tmp/dhclient.conf -pf /tmp/dhclient.pid -lf /tmp/dhclient.leases $ETHERNET >/tmp/dhclient.out 2>&1
if [ $? -ne 0 ]; then
exec /bin/bash
if [ -w /proc/progress ]; then echo f >/proc/progress; fi
echo
cat /tmp/dhclient.out
echo
echo "ERROR! dhclient failed!"
echo
exit 1
fi
# wait for some time for dhclient to create the resolv.conf file; otherwise
# hostname lookup is pretty pointless, and we may end up doing the pivot_root
# BEFORE dhclient creates the resolv.conf file :-)
t=0
while [ "$t" -lt 20 ] && [ ! -e /etc/resolv.conf ]; do
sleep 1;
((t=t+1));
done
#
if [ ! -e /etc/resolv.conf ]; then
echo '********'
echo 'WARNING: /etc/resolv.conf not created - DNS service unavailable.';
echo '********'
fi;
# Set up the hostname, domainname and SNAPSHOT name for the diskless client:
#
hname=`/bin/hostname`
dhhname="${hname}"
dname=`/bin/domainname`
if [ "${hname}" = '(none)' ]; then
/sbin/hostname '';
hname='';
else
echo "DHCP host-name option received: $hname";
fi
IP=`/sbin/ip addr show ${ETHERNET} scope global primary |
grep '^[\ \ ]*inet.*scope global '${ETHERNET} |
sed 's/^.*inet\ //;s/[\/\ ].*$//'`;
if [ -z "${hname}" ]; then
if dnsptr=`(/sbin/host $IP 2>/dev/null || echo '';) | /sbin/grep 'domain name pointer' | /sbin/tail -n 1`; then
hname=${dnsptr//*\ };
hname=${hname%.};
elif [ -n "${SNAPSHOT}" ]; then
hname=${SNAPSHOT};
elif [ -n "$IP" ]; then
hname=${IP};
echo "WARNING: no DNS PTR record found for $IP and no host-name set with DHCP";
else
echo "ERROR! No IP address obtained and no SNAPSHOT= setting.";
echo;
exit 1;
fi;
fi;
if [ -n "${hname}" ] && [ -z "${SNAPSHOT}" ]; then
SNAPSHOT=${hname}
elif [ -z "${SNAPSHOT}" ]; then
SNAPSHOT=${IP}
fi;
if [ -n "${hname}" ]; then
if [[ $hname = *\.* ]]; then
if [ -z "${dname}" ] && [ -z "${NISDOMAIN}" ]; then
# "nis-domain" dhcp option NOT sent.
if [ ${hname} != ${IP} ]; then
dname=${hname#*\.}
else
# hostname was IP address.
# set domainname to proper dns reverse IP domain name
dname=${hname%\.*}
IFS='.' octs=($dname)
unset IFS
dname=''
for oct in ${octs[@]}; do
dname="$oct.$dname";
done
dname="${dname}in-addr.arpa."
fi;
if [ -n "${dname}" ] ; then
/sbin/domainname ${dname}
echo "Domain Name set to ${dname}"
fi;
fi;
if [ "${NISDOMAIN}" = '(none)' ]; then
unset NISDOMAIN;
fi
if [ ${hname} != ${IP} ]; then
hname=${hname%%\.*};
else
hname=${hname##*\.};
fi;
fi;
if [ "${hname}" != "${dhhname}" ]; then
/sbin/hostname ${hname};
echo "Host Name set to ${hname}"
fi;
fi;
#
# Mount the NFS root-path from the diskless server
#
if [ "${INITRD_DBG}" = "4" ]; then exec /bin/bash; fi
if [ -z "${NFSROOT}" ]; then
if [ -w /proc/progress ]; then echo f >/proc/progress; fi
echo
echo "ERROR! No root-path. Check your DHCP configuration, to make"
echo " sure that the 'option root-path' is specified"
echo
exit 1
fi
NFS_IP=` echo ${NFSROOT} | cut -d : -f 1`
NFS_DIR=`echo ${NFSROOT} | cut -d : -f 2`
if [ -w /proc/progress ]; then echo 55 "Mounting root filesystem" >/proc/progress; fi
echo "Mounting root filesystem: ${NFS_DIR}/root from: ${NFS_IP}"
mount -n -o nosharecache,nolock,ro,rsize=32768,async,intr ${NFS_IP}:${NFS_DIR}/root /mnt
if [ $? -ne 0 ]; then
if [ -w /proc/progress ]; then echo f >/proc/progress; fi
echo
echo "ERROR! Failed to mount the root directory via NFS!"
echo " Possible reasons include:"
echo
echo " 1) NFS services may not be running on the server"
echo " 2) Workstation IP does not map to a hostname, either"
echo " in /etc/hosts, or in DNS"
echo " 3) Wrong address for NFS server in the DHCP config file"
echo " 4) Wrong pathname for root directory in the DHCP config file"
echo
exit 1
fi
if [ "${INITRD_DBG}" = "5" ]; then exec /bin/bash; fi
export LD_LIBRARY_PATH=/mnt/usr/lib64:/mnt/usr/lib:/mnt/lib64:/mnt/lib
export PATH=/mnt/usr/sbin:/mnt/usr/bin:/mnt/sbin:/mnt/bin:$PATH
#
# Mount the snapshot directory from the server and then mount files
# in the snapshot/files file over the the shared ones
#
echo Mounting Snapshot directories
mount -n -t nfs $NFS_IP:${NFS_DIR}/snapshot /mnt/.snapshot -o nosharecache,rw,nolock,rsize=32768,wsize=32768,async,intr &&
{
for i in `grep -v "^#" /mnt/.snapshot/files`; do
if [ -e /mnt/$i ]; then
mountfile $i ${SNAPSHOT}
fi;
done
if [ -e /mnt/.snapshot/files.custom ]; then
for i in `grep -v "^#" /mnt/.snapshot/files.custom`; do
if [ -e /mnt/$i ]; then
mountfile $i ${SNAPSHOT}
fi;
done
fi
RELEASE=`uname -r`
for i in `ls /mnt/lib/modules/$RELEASE/modules.*`; do
if [ -e /mnt/$i ]; then
mountfile $i ${SNAPSHOT}
fi;
done
/mnt/sbin/ifup lo
}
if [ "${INITRD_DBG}" = "6" ]; then exec /bin/bash; fi
#
# Copy the files written by dhclient to new root:
#
[ -e /etc/resolv.conf ] && cp -fp /etc/resolv.conf /mnt/etc/resolv.conf 2>/dev/null
[ -e /etc/yp.conf ] && cp -fp /etc/yp.conf /mnt/etc/yp.conf 2>/dev/null
[ -e /etc/ntp.conf ] && cp -fp /etc/ntp.conf /mnt/etc/ntp.conf 2>/dev/null
[ -e /etc/ntp/step-kickers ] && cp -fp /etc/ntp/step-tickers /mnt/etc/ntp/step-tickers 2>/dev/null
# This will allow dhclient to be re-run for nfs interface by initscripts (keep_old_ip=yes):
cp -fp /tmp/dhclient.leases /mnt/var/lib/dhcp/dhclient-eth0.leases 2>/dev/null
cp -fp /tmp/dhclient.leases /mnt/var/lib/dhclient/dhclient-eth0.leases 2>/dev/null
if [ "${INITRD_DBG}" = "7" ]; then exec /bin/bash; fi
#echo "Mounting the devfs filesystem"
#mount -n -t devfs /devfs /dev
#
# Complete the network boot by killing the dhcp client.
# Umount file systems that are no longer used.
# Start the init process to run the NFS Roots bootup sequence.
#
if [ "${INITRD_DBG}" = "8" ]; then exec /bin/bash; fi
/bin/kill -TERM `cat /tmp/dhclient.pid`
echo "Running /sbin/init"
umount /tmp
echo 0x100 > /mnt/proc/sys/kernel/real-root-dev
# Some useful environment variables to stop initscripts / dhclient-script
# doing silly things:
export keep_old_ip=yes
export fastboot=yes
export READONLY=yes
exec /sbin/switch_root -c /dev/console /mnt /sbin/init