Download iTunes U Audio, Video, Slides, NetBoot Setup Script or NetBoot Diskless rc.netboot
In certain, situations you never want use a clients local disk for the NetBoot shadow file, like if you want to run hard disk utilities like Disk Utility or Disk Warrior, or for us if we want to run the file system maintenance software we use, radmind, out-of-context. Where we boot from NetBoot, but we update the file system on the clients local drives.
Also, due to the limitations of number concurrent Apple File Protocol [AFP] connections using Mac OS X 10.6.x (and others) client's File Sharing. If you need to NetBoot more than 10 clients and run maintenance utilities, you can't use a network shadow file, because after the tenth client connecting, it will either try to use a local disk for the shadow file or not NetBoot properly.
But, there is a 3rd option that NetInstall & NetRestore use saving the shadow file to a RAM disk. If you view a NetInstall image, you have the following...
Mount the "NetInstall.dmg" and then open the file...
You will get the idea on how to setup a RAM disk that will work with NetBoot, NetInstall & NetRestore...
For example, here is the default rc.cdrom file included with Mac OS X 10.6.7 NetInstall image...
#!/bin/sh
# Copyright 2000-2009, Apple Inc.
#
#
# NOTICE!
# Most of rc.cdrom is in rc.install temporarily while portions are migrated to launchd
#
#
#
# Disable prebinding-on-the-fly while we're CD booted
#
export DYLD_NO_FIX_PREBINDING=1
#
# mount root_device to update vnode information
#
mount -u -o ro /
#
# Sanity check date & time. Pin to 4/1/1976.
#
if [ `date +%s` -lt 197193600 ]; then
date 040100001976
fi
#
# Create a RAM disk with same perms as mountpoint
#
RAMDisk()
{
mntpt=$1
rdsize=$2
echo "Creating RAM Disk for $mntpt"
dev=`hdik -drivekey system-image=yes -nomount ram://$rdsize`
if [ $? -eq 0 ] ; then
newfs_hfs $dev
# save & restore fs permissions covered by the mount
eval `/usr/bin/stat -s $mntpt`
mount -t hfs -o union -o nobrowse $dev $mntpt
chown $st_uid:$st_gid $mntpt
chmod $st_mode $mntpt
fi
}
RAMDisk /Volumes 1024
RAMDisk /var/tmp 1024
RAMDisk /var/run 1024
RAMDisk /var/db 1024
mkdir -m 1777 /var/db/mds
# language prefs, colorsync need to be able to write some preferences (5424449)
RAMDisk /Library/Preferences 1024
RAMDisk /Library/ColorSync/Profiles/Displays 2048
# use or create the boot cache playlist, and allow B&I to force 32-bit playlist generation
FORCETHIRTYTWO="false"
if nvram boot-args | grep "no64exec" ; then
FORCETHIRTYTWO="true"
fi
SIXTYFOURBIT=`sysctl -n hw.cpu64bit_capable`
if [ $SIXTYFOURBIT = "0" -o $FORCETHIRTYTWO = "true" ] ; then
echo "using 32-bit bootcache playlist"
BootCacheControl -f /var/db/BootCache.playlist32 start
elif [ $SIXTYFOURBIT = "1" ] ; then
echo "using 64-bit bootcache playlist"
BootCacheControl -f /var/db/BootCache.playlist start
fi
# tell launchd to commence with loading the system.
# for the OS Install environment only, /etc/rc.install is included in this process.
launchctl load -D system
# this script sleeps forever; the installer or startup disk will always reboot the system.
sleep 9999999
And if you view a NetBoot image, you have the following...
Mount the "NetBoot.dmg" and then open the file...
For example, here is the default rc.netboot file included with Mac OS X 10.6.7 NetBoot image.
#!/bin/sh
##
# Copyright 2002-2009 Apple Inc.
#
# This script configures NetBoot
##
. /etc/rc.common
#
# Define: NETBOOT_SHADOW
# Purpose:
# To change the behavior of the system when choosing a netboot shadow
# to use.
# Values:
# -NETWORK- Try to use the network for the shadow file, if
# that fails, use the local drive
# -NETWORK_ONLY- Only use the network, fail if not available
# -LOCAL- Use the local drive for the shadow file, if that
# fails, use the network
# -LOCAL_ONLY- Only use the local drive for the shadow, fail if
# not available
NETBOOT_MOUNT=/var/netboot
NETBOOT_SHADOW=${NETBOOT_SHADOW:-NETWORK-}
Failed()
{
echo rc.netboot: $1
echo rc.netboot: $1 > /dev/console
sleep 5
exit 1
}
common_start()
{
netboot_dir=$1
netboot_shadow=$2
if [ "${netboot_dir}" = "" ] ; then
Failed "netboot_dir is empty"
fi
if [ "${netboot_shadow}" = "" ] ; then
Failed "netboot_shadow is empty"
fi
netboot_shadow="${netboot_dir}/${netboot_shadow}"
if ! mkdir -p "${netboot_dir}" ; then
Failed "create ${netboot_dir} failed"
fi
chmod 700 "${netboot_dir}"
mount -u -o ro /
root_device=$(mount | sed -n 's:/dev/\(.*\) on / .*:\1:p')
case "${root_device}" in
vn*)
if ! touch "${netboot_shadow}" ; then
Failed "create ${netboot_shadow} failed"
fi
chmod 600 "${netboot_shadow}"
if ! /usr/libexec/vndevice shadow "/dev/r${root_device}" "${netboot_shadow}" ; then
Failed "vndevice shadow failed"
fi
;;
"")
Failed "root device unknown"
;;
*)
if ! touch "${netboot_shadow}" ; then
Failed "failed to create shadow ${netboot_shadow}"
fi
chmod 600 "${netboot_shadow}"
if ! /usr/bin/nbdst -recycle "${root_device}" "${netboot_shadow}" ; then
Failed "nbdst failed"
fi
;;
esac
}
local_mount()
{
tries=0
limit=11
while [ $tries -lt $limit ]; do
tries=$(( tries + 1 ))
volinfo=`autodiskmount -F 2>/dev/null`
if [ $? -ne 0 ]; then
if [ $tries -lt $limit ]; then
echo "Waiting for local drives..."
echo "Waiting for local drives (retry ${tries}/$(( limit - 1 )))..." > /dev/console
sleep 5
else
echo "autodiskmount -F found no local drives"
return 1
fi
else
tries=$limit
fi
done
set ${volinfo}
devname=$1
fstype=$2
mount -t "${fstype}" -o nosuid,nodev "/dev/${devname}" "${NETBOOT_MOUNT}" 2>&1
if [ $? -ne 0 ]; then
echo "mount of ${devname} failed"
return 1
fi
common_start "${NETBOOT_MOUNT}/.com.apple.NetBootX" shadowfile
return 0
}
network_mount()
{
mount_from=$(ipconfig netbootoption shadow_mount_path 2>&1)
if [ $? -ne 0 ]; then
echo "no network shadow mount path available"
return 1
fi
shadow_path=$(ipconfig netbootoption shadow_file_path 2>&1)
if [ $? -ne 0 ]; then
echo "no network shadow file path available"
return 1
fi
case "${mount_from}" in
afp:*)
fstype=afp
kextutil -v 0 /System/Library/Filesystems/AppleShare/asp_tcp.kext
kextutil -v 0 /System/Library/Filesystems/AppleShare/afpfs.kext
;;
nfs:*) fstype=nfs;;
*) echo "unknown network filesystem mount from ${mount_from}"
return 1
;;
esac
mount -t "${fstype}" -o nobrowse "${mount_from}" "${NETBOOT_MOUNT}"
if [ $? -ne 0 ]; then
echo "mount -t ${fstype} -o nobrowse ${mount_from} ${NETBOOT_MOUNT} failed"
return 1
fi
common_start "${NETBOOT_MOUNT}" "${shadow_path}"
return 0
}
do_start()
{
case "${NETBOOT_SHADOW}" in
-LOCAL_ONLY-)
err=$(local_mount)
if [ $? -ne 0 ]; then
Failed "${err}"
fi
;;
-LOCAL-)
err=$(local_mount)
if [ $? -ne 0 ]; then
err=$(network_mount)
if [ $? -ne 0 ]; then
Failed "Could not find a local or network drive"
fi
fi
;;
-NETWORK_ONLY-)
err=$(network_mount)
if [ $? -ne 0 ]; then
Failed "${err}"
fi
;;
*)
err=$(network_mount)
if [ $? -ne 0 ]; then
err=$(local_mount)
if [ $? -ne 0 ]; then
Failed "Could not find a network or local drive"
fi
fi
;;
esac
}
do_init()
{
# attach the shadow file to the root disk image
do_start
# make sure the root filesystem is clean
fsck -p || fsck -fy || Failed "Could not clean root filesystem"
# make it writable
mount -uw /
# adjust /private/var/vm to point to the writable area (if not diskless)
swapdir=/private/var/vm
mounted_from=$(mount | sed -n 's:\(.*\) on .*/var/netboot.*:\1:p')
case "${mounted_from}" in
/dev/*)
netboot_dir="${NETBOOT_MOUNT}/.com.apple.NetBootX"
if [ -d "${netboot_dir}" ]; then
rm -rf "${swapdir}"
ln -s "${netboot_dir}" "${swapdir}"
fi
;;
*)
;;
esac
# set the ComputerName based on what the NetBoot server told us it was
machine_name=$(ipconfig netbootoption machine_name 2>&1)
if [ $? -ne 0 ]; then
echo "no machine name option available"
else
echo "Setting ComputerName to ${machine_name}"
scutil --set ComputerName "${machine_name}"
fi
}
if [ $# -lt 1 ] ; then
exit 0
fi
command=$1
shift
case "${command}" in
init)
do_init $@
;;
esac
##
# Exit
##
exit 0
To work around a variable assignment bug in the original rc.neboot script, change the following line from...
to...
In the local_mount() subroutine, comment out the following lines...
Add the following two lines to the local_mount() subroutine...
So, the entire updated local_mount() subroutine should look like this...
Lastly, add the following RAMDisk() subroutine to the rc.netboot script.
RAMDisk()
{
mntpt=$1
rdsize=500000
echo "Creating RAM Disk for $mntpt"
dev=`hdik -drivekey system-image=yes -nomount ram://$rdsize`
if [ $? -eq 0 ] ; then
newfs_hfs $dev
# save & restore fs permissions covered by the mount
eval `/usr/bin/stat -s $mntpt`
mount -t hfs -o union -o nobrowse $dev $mntpt
chown $st_uid:$st_gid $mntpt
chmod $st_mode $mntpt
fi
}
Download edited rc.netboot that supports diskless or ram-disk NetBoot.
The rc.netboot created with "System Image Utility" using Mac OS X 10.6.7 has a bug in the NETBOOT_SHADOW variable Assignment...
This assignment loses the beginning "-" so it never correctly matches the variable in the case statement in the do_start() sub routine and always uses the "*" branch. No matter what value you assign to the NETBOOT_SHADOW variable.
See the highlighted "*" branch in the default case statement below.
do_start()
{
case "${NETBOOT_SHADOW}" in
-LOCAL_ONLY-)
err=$(local_mount)
if [ $? -ne 0 ]; then
Failed "${err}"
fi
;;
-LOCAL-)
err=$(local_mount)
if [ $? -ne 0 ]; then
err=$(network_mount)
if [ $? -ne 0 ]; then
Failed "Could not find a local or network drive"
fi
fi
;;
-NETWORK_ONLY-)
err=$(network_mount)
if [ $? -ne 0 ]; then
Failed "${err}"
fi
;;
*)
err=$(network_mount)
if [ $? -ne 0 ]; then
err=$(local_mount)
if [ $? -ne 0 ]; then
Failed "Could not find a network or local drive"
fi
fi
;;
esac
}
A workaround this bug, is either escape the "-" character in the variable assigment or change the assigment to something like...
Lastly, you take this updated rc.netboot file and replace it with the one you are using with your NetBoot image.