1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403
|
#!/bin/bash
# This file is borrowed from Debian's diskless.
# Modified by Steven Shiau <steven _at_ clonezilla org>, Ceasar Sun <ceasar _at_ nchc org tw>
# License: GPL
# 2006/02/28
# Thanks to James MacLean for providing clientdir method in kernel cmdline.
# it looks like:
# append initrd=initrd-pxe.img ramdisk_size=12288 devfs=nomount drblthincli=off selinux=0 clientdir=images
#
DRBL_SCRIPT_PATH="${DRBL_SCRIPT_PATH:-/usr/share/drbl}"
# Append a default search path.
PATH="$PATH:/sbin:/usr/sbin:/bin:/usr/bin:/usr/X11R6/bin:$DRBL_SCRIPT_PATH/sbin:$DRBL_SCRIPT_PATH/bin"
export PATH
# NFS opt for /etc, /var, /usr, /opt..
nfs_ver_opt="nfsvers=3"
# If need, you can add "rsize=65536,wsize=65536"
RO_NFS_EXTRA_OPT="ro,tcp,nolock,$nfs_ver_opt"
RW_NFS_EXTRA_OPT="rw,tcp,nolock,$nfs_ver_opt"
# This param nosharecache is for Kernel 2.6.23 (some in kernel 2.6.22 in Fedora) or later... Kernel 2.6.23 or later will detect the nfs mounting parameters are the same or not for mounting point and sub-tree mouting point. If not, it will exit unless nosharecache is added. See "man 5 nfs" or https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=251655 for more details.
NFS_OPT_TO_ADD="nosharecache"
# Flag to have tmpfs /run or not. This value will be enabled by drblpush if /run is found as tmpfs mounted on DRBL server.
TMPFS_RUN="true"
#
create_dev(){
# Forget the devfs, we create it by ourself...
echo -n "Unmounting the old dev if it exists... "
umount -l /dev 2>/dev/null
echo "done!"
if ! mount -n -o size=10240k,mode=0755 -t devtmpfs devtmpfs /dev; then
echo "W: devtmpfs not available, falling back to tmpfs for /dev"
mount -n -t tmpfs -o nr_inodes=24576 -o mode=0755 udev /dev
[ -e /dev/console ] || mknod -m 0600 /dev/console c 5 1
[ -e /dev/null ] || mknod /dev/null c 1 3
fi
echo -n "Creating dev... "
# Note! We put dev.tgz as the first priority so that if necessary, such MDK 10, we can force to use dev.tgz instead of udev. (Since in MDK10, there is /usr/sbin/udev, but no /usr/sbin/udevstart or /usr/sbin)
if [ -f /etc/diskless-image/dev.tgz ]; then
# the option "m" to make sure the time will NOT be extracted, it will use
# the time now, so that we can avoid the wrong clock or timezone.
echo -n "Using old-style dev instead of udev... "
tar -xzmf /etc/diskless-image/dev.tgz -C /dev
elif [ -n "$(ls /usr/sbin/udev* /usr/bin/udev* 2>/dev/null)" ]; then
echo -n "Mounting sysfs... "
mount -n -t sysfs none /sys
ln -snf /proc/self/fd /dev/fd
ln -snf /proc/self/fd/0 /dev/stdin
ln -snf /proc/self/fd/1 /dev/stdout
ln -snf /proc/self/fd/2 /dev/stderr
ln -snf /proc/kcore /dev/core
[ -d /dev/pts ] || mkdir -m 0755 /dev/pts
[ -d /dev/shm ] || mkdir -m 1777 /dev/shm
echo -n "Using udev... "
# http://www.redhat.com/archives/rhl-devel-list/2006-April/msg00785.html
# * Thu Apr 13 2006 Harald Hoyer <harald redhat com> - 089-1
# - version 089
# - start_udev uses udevtrigger now instead of udevstart
# From FC12, it's udevadm trigger
udevadm trigger
# Create console, null, since in FC5, udevstart won't create them.
[ ! -e /dev/console ] && mknod -m 600 /dev/console c 5 1
[ ! -e /dev/null ] && mknod -m 666 /dev/null c 1 3
else
echo "Failed to create the dev filesystem!"
echo "System will not be able to function!"
echo "Program terminated!"
exit 1
fi
echo "done!"
} # end of create_dev()
#
do_nfs_mount() {
local nfs_src="$1"
local mnt_point="$2"
local nfs_opt="$3"
local nfs_opt_try="$4"
local flag
flag="0"
# Ex: mount -t nfs -n -o $RW_NFS_EXTRA_OPT $nfsserver:$nfshostsdir/$IP/etc /etc 2>/dev/null
mount -t nfs -n -o $nfs_opt $nfs_src $mnt_point 2>/dev/null
if [ "$?" -gt 0 ]; then
echo -n "Try to mount with option \"$NFS_OPT_TO_ADD\"... "
# Ex: mount -t nfs -n -o $RW_NFS_EXTRA_OPT,$NFS_OPT_TO_ADD $nfsserver:$nfshostsdir/$IP/etc /etc
mount -t nfs -n -o $nfs_opt,$nfs_opt_try $nfs_src $mnt_point
[ "$?" -eq 0 ] && flag="1"
fi
return $flag
} # end of do_nfs_mount
#
add_extra_nfs_opt_to_fstab() {
echo "Try to add $NFS_OPT_TO_ADD in /etc/fstab..."
if [ -z "$(grep -Ew "nosharecache" /etc/fstab)" ]; then
# Make it like:
# 192.168.130.254:/tftpboot/nodes/192.168.130.1/etc /etc nfs rw,rsize=65536,wsize=65536,tcp,nosharecache,defaults 0 0
perl -pi -e "s|(^[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+:.*[[:space:]]+.*nfs.*)(,defaults.*)|\$1,nosharecache\$2|g" /etc/fstab
fi
} # end of add_extra_nfs_opt_to_fstab
#
remove_extra_nfs_opt_to_fstab() {
echo "Try to remove $NFS_OPT_TO_ADD in /etc/fstab..."
if [ -n "$(grep -Ew "nosharecache" /etc/fstab)" ]; then
# Make it like:
# 192.168.130.254:/tftpboot/nodes/192.168.130.1/etc /etc nfs rw,rsize=65536,wsize=65536,tcp,defaults 0 0
perl -pi -e "s|,nosharecache||g" /etc/fstab
fi
} # end of remove_extra_nfs_opt_to_fstab() {
maybe_break(){
# Refer from Debian live-boot
if echo "${break:-}" | grep -E -q "(,|^)$1(,|$)"; then
if command -v chvt >/dev/null 2>&1; then
chvt 1
fi
echo "break point=$break"
#run_scripts /scripts/panic
for i in 1 2 3 4 5 6; do
[ -c /dev/tty$i ] || mknod /dev/tty$i c 4 $i
done
REASON="$@" PS1='(init.drbl) ' /bin/sh -i </dev/console >/dev/console 2>&1
fi
}
parse_cmd_append(){
for x in $(cat /proc/cmdline); do
case $x in
break=*)
break=${x#break=}
;;
esac
done
}
############
### MAIN ###
############
# Don't do anything special if computer is already booted
if [ $$ -ne 1 ]; then
exec /usr/sbin/init $*
echo "FATAL ERROR: exec /usr/sbin/init failed" >&2
exit 1
fi
# Don't do anything special if root is rw (ie master system).
if touch /test-rw 2> /dev/null; then
rm /test-rw
echo "WARNING: master system installed" >&2
exec /usr/sbin/init $*
echo "FATAL ERROR: exec /usr/sbin/init failed" >&2
exit 1
fi
# Try and find configuration file
if [ ! -f /etc/diskless-image/config ]; then
echo "ERROR: Cannot find image config file /etc/diskless-image/config!"
echo " Not mounting NFS-root directories"
echo "Program terminated!"
exit 1
fi
# Load config file
. /etc/diskless-image/config
# To get IP address, we need to mount /proc first
echo -n "Mounting /proc in init... "
mount -n none /proc -t proc
echo "done!"
# Remount the root filesystem read-write.
# For kernel 2.6.18, it seems if root is ro, all the mount later (such as /etc, /var) will be ro.
echo -n "Remounting root filesystem in read-write mode... "
mount -n -o remount,rw / 2>/dev/null
echo "done!"
# Create the necessary dev files, this should be as early as possible
create_dev
if [ "$TMPFS_RUN" = "true" ]; then
[ ! -d /run ] && mkdir /run
mount -t tmpfs -o "nosuid,size=20%,mode=0755" tmpfs /run
mkdir /run/initramfs
fi
# find my IP address
NETDEVICES="$(LC_ALL=C cat /proc/net/dev | awk -F: '/eth.:|tr.:|p.p.:/{print $1}')"
for DEVICE in $NETDEVICES; do
# //NOTE// Here we have to use grep "-w" to grep the IPv4 address, avoding getting IPv6 address.
# E.g.:
# eth1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
# inet 192.168.77.254 netmask 255.255.255.0 broadcast 192.168.77.255
# inet6 fe80::20c:29ff:fee9:f24e prefixlen 64 scopeid 0x20<link>
IP_tmp="$(LC_ALL=C ifconfig $DEVICE | grep -w -A1 $DEVICE | grep -w -v $DEVICE | grep -w "inet" | sed -e 's/addr://'| sed -e 's/^.*inet \([0-9\.]\+\).*$/\1/')"
if [ -n "$IP_tmp" ]; then
# Got the IP address, stop to get from other port, so break
IP=$IP_tmp
echo "My IP address is $IP ([$DEVICE])."
break
fi
done
# Find NFS server
for i in $NFSSERVER_LIST; do
# Use the clients-of-$nfsserver.txt in the common root.
if [ -n "$(grep -Ew "$IP" /etc/drbl/clients-of-${i}.txt 2>/dev/null)" ]; then
nfsserver="$i"
break
fi
done
if [ -z "$nfsserver" ]; then
# No NFS server found. Use plan B. Try to use gateway as NFS server
gateway="$(LANG=C route -n | awk '/^0.0.0.0/ {print $2}')"
if [ -n "$gateway" ]; then
nfsserver=$gateway
else
echo "NFSSERVER is not found, use default one: \"$nfsserver_default\"."
nfsserver=$nfsserver_default
fi
fi
if [ -n "$nfsserver" ]; then
echo "NFS server is $nfsserver."
else
echo "No NFS Server was found!"
echo "Program terminated!"
exit 1
fi
maybe_break drbl_prenfs
# Check if single system image is on
ssi_flag=0
# For PXE, it's clientdir=node_root in /proc/cmdline, while
# for GRUB uEFI NB, it's clientdir=\"node_root\"
#(added by function add_opt_in_grub_efi_cfg_block) in /proc/cmdline.
# It should be converted to be clientdir="node_root" by grub,
# like the cases in the booting of CD or USB flash drive.
# However somehow the GRUB uEFI NB has different behavior.
# Therefore here we have to deal with clientdir=node_root or clientdir=\"node_root\"
clientdir="$(LC_ALL=C grep clientdir /proc/cmdline | sed -e "s/.*clientdir=\([^ ]\+\).*$/\1/" | sed -e 's|\"||g' -e 's|\\||g')"
[ -n "$clientdir" ] && ssi_flag=1
# The flag to modify /etc/fstab
NFS_OPT_TO_ADD_FLAG=0
# client's /etc directory (1) NFS (2) created from a tarball template
if [ "$ssi_flag" = 0 ]; then
# Normal mode, every client has its own /etc, /var
echo -en "\\033[0;33m"
echo "Full DRBL mode: I have my own NFS-based /etc and /var directories."
echo -en "\\033[0;39m"
echo -n "Mounting NFS dir /etc... "
do_nfs_mount $nfsserver:$nfshostsdir/$IP/etc /etc $RW_NFS_EXTRA_OPT $NFS_OPT_TO_ADD
NFS_OPT_TO_ADD_FLAG=$((NFS_OPT_TO_ADD_FLAG + $?))
echo "done!"
echo -n "Mounting NFS dir /var... "
do_nfs_mount $nfsserver:$nfshostsdir/$IP/var /var $RW_NFS_EXTRA_OPT $NFS_OPT_TO_ADD
NFS_OPT_TO_ADD_FLAG=$((NFS_OPT_TO_ADD_FLAG + $?))
echo "done!"
else
# DRBL SSI mode
# We need to know if it's in clonezilla box mode (DRBL SSI + runlevel=1)
# Command "runlevel" in this stage is useless. we have to check by ourself
# Check if "1" exists in /proc/cmdline
RL=""
if grep -qE ".*[[:space:]]+\<1\>([[:space:]]+|$)" /proc/cmdline 2>/dev/null; then
RL=1
# It's clonezilla box mode, client does not have to use some graphics
# setting, expecially large dir like /etc/gconf, /etc/X11, /etc/selinux
# In RH, we still need an empty directory /etc/X11 for kudzu to write
# X config,,otherwise kudzu will complain. For Debian, it's not necessary
# To make it simple, we will create /etc/X11 later.
ETC_EXCLUDE="--exclude=gconf --exclude=X11 --exclude=selinux"
echo -en "\\033[0;33m"
echo "Clonezilla box mode: I use tmpfs /etc and /var, based on tarball templates."
echo -en "\\033[0;39m"
else
# DRBL SSI mode
echo -en "\\033[0;33m"
echo "DRBL SSI mode: I use tmpfs /etc and /var, based on tarball templates."
echo -en "\\033[0;39m"
fi
echo -n "Creating one-time-use dir... "
echo -n "/root... "
mount -n -t tmpfs -o mode=0700 none /root
tar -xzmf /drbl_ssi/template_root.tgz -C /
echo -n "/etc... "
mount -n -t tmpfs -o mode=0755 none /etc
tar $ETC_EXCLUDE -xzmf /drbl_ssi/template_etc.tgz -C /
echo -n "/var... "
mount -n -t tmpfs -o mode=0755 none /var
tar -xzmf /drbl_ssi/template_var.tgz -C /
echo "done!"
fi
# NFS-based /usr is necessary both for normal mode and DRBL SSI mode
echo -n "Mounting NFS dir /usr... "
do_nfs_mount $nfsserver:/usr /usr $RO_NFS_EXTRA_OPT $NFS_OPT_TO_ADD
NFS_OPT_TO_ADD_FLAG=$((NFS_OPT_TO_ADD_FLAG + $?))
echo "done!"
# We have to modify the fstab for DRBL SSI mode (drbl-ssi-client-prepare).
# Perl (used in drbl-ssi-client-prepare) is only available after
# /usr is mounted.
if [ "$ssi_flag" = "1" ]; then
if [ "$RL" = "1" ]; then
# In clonezill box mode, to let kudzu shut up, we need /etc/X11 to write X config, since we already use --exclude=X11 to exclude that dir.
mkdir -p /etc/X11
else
# only DRBL SSI mode, not in clonezilla box mode, use NFS
# We need /var/lib/dpkg or /var/lib/rpm so that later in drbl-ssi-client-prepare, we can use dpkg or rpm to query package to get the GDM_CFG or KDE_CFG
if [ -d /var/lib/dpkg ]; then
echo -n "/var/lib/dpkg... "
do_nfs_mount $nfsserver:/tftpboot/node_root/var/lib/dpkg /var/lib/dpkg $RO_NFS_EXTRA_OPT $NFS_OPT_TO_ADD
NFS_OPT_TO_ADD_FLAG=$((NFS_OPT_TO_ADD_FLAG + $?))
elif [ -d /var/lib/rpm ]; then
echo -n "/var/lib/rpm... "
do_nfs_mount $nfsserver:/tftpboot/node_root/var/lib/rpm /var/lib/rpm $RO_NFS_EXTRA_OPT
NFS_OPT_TO_ADD_FLAG=$((NFS_OPT_TO_ADD_FLAG + $?))
fi
fi
echo "done!"
drbl-ssi-client-prepare $nfsserver "$RO_NFS_EXTRA_OPT" $RL
fi
#
if [ "$NFS_OPT_TO_ADD_FLAG" -eq 0 ]; then
remove_extra_nfs_opt_to_fstab
else
add_extra_nfs_opt_to_fstab
fi
maybe_break drbl_postnfs
# Clear mtab
rm -f /etc/mtab /etc/mtab~ /etc/mtab~~ /etc/nologin
# systemd v227 forces to have /etc/mtab as symbolic file to /proc/mounts.
# Ref: https://github.com/stevenshiau/drbl/issues/4
## if, for any reason, mtab was not synced with what it should be, Sync it.
#while read ilist; do
# # skip the "rootfs / rootfs rw 0 0"
# [ -n "$(echo $ilist | grep -E "^rootfs \/ rootfs .*")" ] && continue
# echo $ilist >> /etc/mtab
#done < /proc/mounts
ln -fs /proc/mounts /etc/mtab
# umount the useless /initrd/proc and /initrd if they exist.
for i in /initrd/proc /initrd; do
if [ -n "$(awk -F " " '{print $2}' /etc/mtab | grep -E "^$i\>")" ]; then
umount -l $i
fi
done
# Public IP
if [ -n "$IP" ]; then
# public ip alias
if [ -e "/etc/diskless-image/public_ip.drbl" ]; then
# PUBLIC_IP result is like: 10.231.97.81 netmask 255.255.255.0
PUBLIC_IP="$(grep -Ew "$IP" /etc/diskless-image/public_ip.drbl | awk '{ print $2" netmask "$3; }')"
PUBLIC_GW="$(grep -Ew "$IP" /etc/diskless-image/public_ip.drbl | awk '{ print $4; }')"
if [ -z "$PUBLIC_IP" ]; then
PUBLIC_IP="$(grep -i -Ew "$HWADDR" /etc/diskless-image/public_ip.drbl | awk '{ print $2" netmask "$3; }')"
PUBLIC_GW="$(grep -i -Ew "$HWADDR" /etc/diskless-image/public_ip.drbl | awk '{ print $4; }')"
fi
if [ -n "$PUBLIC_IP" ]; then
echo "Setting public IP $PUBLIC_IP $GW in $DEVICE:1 by:"
echo "ifconfig $DEVICE:1 $PUBLIC_IP"
ifconfig $DEVICE:1 $PUBLIC_IP
GW="$(route -n | grep -e "^0\.0\.0\.0" | awk '{ print $2; }')"
route del default gw $GW
echo "Setting routing table by:"
echo "route add default gw $PUBLIC_GW dev $DEVICE"
route add default gw $PUBLIC_GW dev $DEVICE
fi
fi
fi
# report success
echo "Done. NFS-root directories are mounted."
echo "Let original init take over..."
# A normal bootparam in /proc/cmdline for clonezilla client is like:
# initrd=initrd-pxe.img devfs=nomount drblthincli=off selinux=0 1 ocs_opt="--language en -b -g auto -y0 -p true --max-time-to-wait 300 --mcast-port 22 32 multicast_restoredisk 2disks hda hdb"
# We have to filter the ocs_opt to avoid some options, like -b or 1 inside it, which init will think it's emergency mode or other mode
pure_cmdline="$(sed -e "s/ocs_opt=\".*\"//g" /proc/cmdline)"
maybe_break drbl_pre_run_init
# Since /usr is NFS mounted to DRBL server's /usr now. The /usr/sbin/init is the original one.
exec /usr/sbin/init $pure_cmdline $*
# Only should get here if something went wrong
echo "FATAL ERROR: exec /usr/sbin/init failed" >&2
exit 1
|