New Fedora Diskless init script

From MythTV Official Wiki
Jump to: navigation, search

Author unknown
Description New Fedora Diskless init script
Supports



Script.png disklessrc

#!/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