1#!/bin/sh 2# 3# Copyright (c) 1999 Matt Dillon 4# All rights reserved. 5# 6# Redistribution and use in source and binary forms, with or without 7# modification, are permitted provided that the following conditions 8# are met: 9# 1. Redistributions of source code must retain the above copyright 10# notice, this list of conditions and the following disclaimer. 11# 2. Redistributions in binary form must reproduce the above copyright 12# notice, this list of conditions and the following disclaimer in the 13# documentation and/or other materials provided with the distribution. 14# 15# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25# SUCH DAMAGE. 26# 27# $FreeBSD: src/etc/rc.d/initdiskless,v 1.24 2003/06/30 21:47:06 brooks Exp $ 28# $DragonFly: src/etc/rc.d/initdiskless,v 1.9 2008/02/19 22:02:47 thomas Exp $ 29# 30# PROVIDE: initdiskless 31 32. /etc/rc.subr 33dummy_rc_command "$1" 34 35# On entry to this script the entire system consists of a read-only root 36# mounted via NFS. We use the contents of /conf to create and populate 37# memory filesystems. The kernel has run BOOTP and configured an interface 38# (otherwise it would not have been able to mount the NFS root!) 39# 40# The following directories are scanned. Each successive directory overrides 41# (is merged into) the previous one. 42# 43# /conf/base universal base 44# /conf/default modified by a secondary universal base 45# /conf/${ipbca} modified based on the assigned broadcast IP 46# /conf/${ipa} modified based on the machine's assigned IP 47# 48# If a directory contains the file 'remount', the contents of the file is 49# used to remount the directory. For example, if /conf/base/remount contains 50# the string 'my.server.com:/new_conf' then my.server.com:/new_conf will be 51# mounted in place of the directory. 52# 53# Each of these directories may contain any number of subdirectories which 54# represent directories in / on the diskless machine. The existence of 55# these subdirectories causes this script to create a MEMORY FILESYSTEM for 56# /<sub_directory_name>. For example, if /conf/base/etc exists then a 57# memory filesystem will be created for /etc. 58# 59# If a subdirectory contains the file 'diskless_remount' the contents of 60# the file is used to remount the subdirectory prior to it being copied to 61# the memory filesystem. For example, if /conf/base/etc/diskless_remount 62# contains the string 'my.server.com:/etc' then my.server.com:/etc will be 63# mounted in place of the subdirectory. This allows you to avoid making 64# duplicates of system directories in /conf. 65# 66# If a subdirectory contains the file 'md_size', the contents of the 67# file is used to determine the size of the memory filesystem, in 512 68# byte sectors. The default is 4096 (2MB). You only have to specify an 69# md_size if the default doesn't work for you (i.e. if it is too big or 70# too small). For example, /conf/base/etc/md_size might contain '16384'. 71# 72# If /conf/<special_dir>/SUBDIR.cpio.gz exists, the file is cpio'd into 73# the specified /SUBDIR (and a memory filesystem is created for /SUBDIR 74# if necessary). 75# 76# If /conf/<special_dir>/SUBDIR.remove exists, the file contains a list 77# of paths which are rm -rf'd relative to /SUBDIR. 78# 79# You will almost universally want to create a /conf/base/etc containing 80# a diskless_remount and possibly an md_size file. You will then almost 81# universally want to override rc.conf, rc.local, and fstab by creating 82# /conf/default/etc/{rc.conf,rc.local,fstab}. Your fstab should be sure 83# to mount a /usr... typically an NFS readonly /usr. 84# 85# NOTE! rc.d/diskless will create /var, /tmp, and /dev. Those filesystems 86# should not be specified in /conf. At least not yet. 87 88dlv=`/sbin/sysctl -n vfs.nfs.diskless_valid 2> /dev/null` 89[ ${dlv:=0} -eq 0 ] && exit 0 90 91# chkerr: 92# 93# Routine to check for error 94# 95# checks error code and drops into shell on failure. 96# if shell exits, terminates script as well as /etc/rc. 97# 98chkerr() { 99 case $1 in 100 0) 101 ;; 102 *) 103 echo "$2 failed: dropping into /bin/sh" 104 /bin/sh 105 # RESUME 106 ;; 107 esac 108} 109 110# Create a generic memory disk 111# 112mount_md() { 113 /sbin/mount_tmpfs -s $1 tmpfs $2 114} 115 116# Create the memory filesystem if it has not already been created 117# 118create_md() { 119 if [ "x`eval echo \\$md_created_$1`" = "x" ]; then 120 if [ "x`eval echo \\$md_size_$1`" = "x" ]; then 121 if [ "$1" = "etc" ]; then 122 md_size=12M 123 else 124 md_size=2M 125 fi 126 else 127 md_size=`eval echo \\$md_size_$1` 128 129 # for backwards compatibility... 130 # if it's a number, then treat it as number of sectors 131 # 132 if [ "$md_size" = "${md_size%%[!0-9]*}" ]; then 133 md_size=`expr $md_size '*' 512` 134 fi 135 fi 136 mount_md $md_size /$1 137 /bin/chmod 755 /$1 138 eval md_created_$1=created 139 fi 140} 141 142# DEBUGGING 143# 144# set -v 145 146# Figure out our interface and IP. 147# 148bootp_ifc="" 149bootp_ipa="" 150bootp_ipbca="" 151iflist=`ifconfig -l` 152for i in ${iflist} ; do 153 set `ifconfig ${i}` 154 while [ $# -ge 1 ] ; do 155 if [ "${bootp_ifc}" = "" -a "$1" = "inet" ] ; then 156 bootp_ifc=${i} ; bootp_ipa=${2} ; shift 157 fi 158 if [ "${bootp_ipbca}" = "" -a "$1" = "broadcast" ] ; then 159 bootp_ipbca=$2; shift 160 fi 161 shift 162 done 163 if [ "${bootp_ifc}" != "" ] ; then 164 break 165 fi 166done 167echo "Interface ${bootp_ifc} IP-Address ${bootp_ipa} Broadcast ${bootp_ipbca}" 168 169# Figure out our NFS root path 170# 171set `mount -t nfs` 172while [ $# -ge 1 ] ; do 173 if [ "$2" = "on" -a "$3" = "/" ]; then 174 nfsroot="$1" 175 break 176 fi 177 shift 178done 179 180# Resolve templates in /conf/base, /conf/default, /conf/${bootp_ipbca}, 181# and /conf/${bootp_ipa}. For each subdirectory found within these 182# directories: 183# 184# - calculate memory filesystem sizes. If the subdirectory (prior to 185# NFS remounting) contains the file 'md_size', the contents specified 186# in 512 byte sectors will be used to size the memory filesystem. 187# 188# - handle NFS remounts. If the subdirectory contains the file 189# diskless_remount, the contents of the file is NFS mounted over 190# the directory. For example /conf/base/etc/diskless_remount 191# might contain 'myserver:/etc'. NFS remounts allow you to avoid 192# having to dup your system directories in /conf. Your server must 193# be sure to export those filesystems -alldirs, however. 194# If the diskless_remount file contains a string beginning with a 195# '/' it is assumed that the local nfsroot should be prepended to 196# it before attemping to the remount. This allows the root to be 197# relocated without needing to change the remount files. 198# 199for i in base default ${bootp_ipbca} ${bootp_ipa} ; do 200 if [ -f /conf/$i/remount ]; then 201 nfspt=`/bin/cat /conf/$i/remount` 202 if [ `expr "$nfspt" : '\(.\)'` = "/" ]; then 203 nfspt="${nfsroot}${nfspt}" 204 fi 205 mount_nfs $nfspt /conf/$i 206 chkerr $? "mount_nfs $nfspt /conf/$i" 207 fi 208 209 for j in /conf/$i/* ; do 210 # memory filesystem size specification 211 # 212 subdir=${j##*/} 213 if [ -d $j -a -f $j/md_size ]; then 214 eval md_size_$subdir=`cat $j/md_size` 215 fi 216 217 # NFS remount 218 # 219 if [ -d $j -a -f $j/diskless_remount ]; then 220 nfspt=`/bin/cat $j/diskless_remount` 221 if [ `expr "$nfspt" : '\(.\)'` = "/" ]; then 222 nfspt="${nfsroot}${nfspt}" 223 fi 224 mount_nfs $nfspt $j 225 chkerr $? "mount_nfs $nfspt $j" 226 fi 227 done 228done 229 230# - Create all required MFS filesystems and populate them from 231# our templates. Support both a direct template and a dir.cpio.gz 232# archive. Support dir.remove files containing a list of relative 233# paths to remove. 234# 235# TODO: 236# + find a way to assign a 'group' identifier to a machine 237# so we can use group-specific configurations; 238 239for i in base default ${bootp_ipbca} ${bootp_ipa} ; do 240 for j in /conf/$i/* ; do 241 subdir=${j##*/} 242 if [ -d $j ]; then 243 create_md $subdir 244 cp -Rp $j/* /$subdir 245 fi 246 done 247 for j in /conf/$i/*.cpio.gz ; do 248 subdir=${j%*.cpio.gz} 249 subdir=${subdir##*/} 250 if [ -f $j ]; then 251 create_md $subdir 252 echo "Loading /$subdir from cpio archive $j" 253 (cd /$subdir ; /usr/bin/cpio --extract -d -F $j ) 254 fi 255 done 256 for j in /conf/$i/*.remove ; do 257 subdir=${j%*.remove} 258 subdir=${subdir##*/} 259 if [ -f $j ]; then 260 # doubly sure it is a memory disk before rm -rf'ing 261 create_md $subdir 262 (cd /$subdir; rm -rf `/bin/cat $j`) 263 fi 264 done 265done 266