1#!/bin/sh
2##
3# Copyright 2002-2014 Apple Inc.
4#
5# This script configures NetBoot
6##
7
8. /etc/rc.common
9
10# 
11# Define: NETBOOT_SHADOW
12# Purpose:
13#   To change the behavior of the system when choosing a netboot shadow
14#   to use.
15# Values:
16#   -NETWORK-		Try to use the network for the shadow file, if
17#			that fails, use the local drive
18#   -NETWORK_ONLY-	Only use the network, fail if not available
19#   -LOCAL-		Use the local drive for the shadow file, if that
20#			fails, use the network
21#   -LOCAL_ONLY-	Only use the local drive for the shadow, fail if
22#			not available
23
24NETBOOT_MOUNT=/var/netboot
25NETBOOT_SHADOW=${NETBOOT_SHADOW:-NETWORK-}
26LOCAL_NETBOOT_DIR=private/var/run/com.apple.NetBootX
27
28Failed()
29{
30	echo rc.netboot: $1
31	echo rc.netboot: $1 > /dev/console
32	sleep 5
33	exit 1
34}
35
36common_start()
37{
38    netboot_dir=$1
39    netboot_shadow=$2
40    if [ "${netboot_dir}" = "" ] ; then
41	Failed "netboot_dir is empty"
42    fi
43    if [ "${netboot_shadow}" = "" ] ; then
44	Failed "netboot_shadow is empty"
45    fi
46    netboot_shadow="${netboot_dir}/${netboot_shadow}"
47    if ! mkdir -p "${netboot_dir}" ; then
48	Failed "create ${netboot_dir} failed"
49    fi
50    chmod 700 "${netboot_dir}"
51    mount -u -o ro /
52    root_device=$(mount | sed -n 's:/dev/\(.*\) on / .*:\1:p')
53    case "${root_device}" in
54	vn*)
55	    if ! touch "${netboot_shadow}" ; then
56		Failed "create ${netboot_shadow} failed"
57	    fi
58	    chmod 600 "${netboot_shadow}"
59    	    if ! /usr/libexec/vndevice shadow "/dev/r${root_device}" "${netboot_shadow}" ; then
60		Failed "vndevice shadow failed"
61	    fi
62	    ;;
63	"")
64	    Failed "root device unknown"
65	    ;;
66	*)
67	    if ! touch "${netboot_shadow}" ; then
68		Failed "failed to create shadow ${netboot_shadow}"
69	    fi
70	    chmod 600 "${netboot_shadow}"
71	    if ! /usr/bin/nbdst -recycle "${root_device}" "${netboot_shadow}" ; then
72		Failed "nbdst failed"	
73	    fi
74	    ;;
75    esac
76}
77
78local_mount()
79{
80    tries=0
81    limit=11
82    while [ $tries -lt $limit ]; do
83	tries=$(( tries + 1 ))
84	volinfo=`autodiskmount -F 2>/dev/null`
85	if [ $? -ne 0 ]; then
86	    if [ $tries -lt $limit ]; then
87		echo "Waiting for local drives..."
88		echo "Waiting for local drives (retry ${tries}/$(( limit - 1 )))..." > /dev/console
89		sleep 5
90	    else
91		echo "autodiskmount -F found no local drives"
92		return 1
93	    fi
94	else
95	    tries=$limit
96	fi
97    done
98    set ${volinfo}
99    devname=$1
100    fstype=$2
101
102    mount -t "${fstype}" -o nosuid,nodev "/dev/${devname}" "${NETBOOT_MOUNT}" 2>&1
103    if [ $? -ne 0 ]; then
104	echo "mount of ${devname} failed"
105	return 1
106    fi
107    common_start "${NETBOOT_MOUNT}/${LOCAL_NETBOOT_DIR}" shadowfile
108    return 0
109}
110
111network_mount()
112{
113    mount_from=$(ipconfig netbootoption shadow_mount_path 2>&1)
114    if [ $? -ne 0 ]; then
115	echo "no network shadow mount path available"
116	return 1
117    fi
118    shadow_path=$(ipconfig netbootoption shadow_file_path 2>&1)
119    if [ $? -ne 0 ]; then
120	echo "no network shadow file path available"
121	return 1
122    fi
123    case "${mount_from}" in
124	afp:*)
125	    fstype=afp
126	    kextload -v 0 /System/Library/Filesystems/AppleShare/asp_tcp.kext
127	    kextload -v 0 /System/Library/Filesystems/AppleShare/afpfs.kext
128	    ;;
129 	nfs:*)
130	    fstype=nfs
131	    mount_from=${mount_from#nfs:}
132	    ;;
133	*) echo "unknown network filesystem mount from ${mount_from}"
134	    return 1
135	    ;;
136    esac
137    mount -t "${fstype}" -o nobrowse "${mount_from}" "${NETBOOT_MOUNT}"
138    if [ $? -ne 0 ]; then
139	echo "mount -t ${fstype} -o nobrowse ${mount_from} ${NETBOOT_MOUNT} failed"
140	return 1
141    fi
142    common_start "${NETBOOT_MOUNT}" "${shadow_path}"
143    return 0
144}
145
146do_start()
147{
148    case "${NETBOOT_SHADOW}" in
149	-LOCAL_ONLY-)
150		err=$(local_mount)
151		if [ $? -ne 0 ]; then
152		    Failed "${err}"
153		fi
154		;;
155	-LOCAL-)
156		err=$(local_mount)
157		if [ $? -ne 0 ]; then
158		    err=$(network_mount)
159		    if [ $? -ne 0 ]; then
160			Failed "Could not find a local or network drive"
161		    fi
162    		fi
163		;;
164	-NETWORK_ONLY-)
165		err=$(network_mount)
166		if [ $? -ne 0 ]; then
167		    Failed "${err}"
168		fi
169		;;
170
171	*)
172		err=$(network_mount)
173		if [ $? -ne 0 ]; then
174		    err=$(local_mount)
175		    if [ $? -ne 0 ]; then
176			Failed "Could not find a network or local drive"
177		    fi
178		fi
179		;;
180    esac
181
182}
183
184do_init()
185{
186    # attach the shadow file to the root disk image
187    do_start
188
189    # make sure the root filesystem is clean
190    fsck -p || fsck -fy || Failed "Could not clean root filesystem"
191
192    # make it writable
193    mount -uw /
194
195    # adjust /private/var/vm to point to the writable area (if not diskless)
196    swapdir=/private/var/vm
197    mounted_from=$(mount | sed -n 's:\(.*\) on .*/var/netboot.*:\1:p')
198    case "${mounted_from}" in
199	/dev/*)
200		netboot_dir="${NETBOOT_MOUNT}/${LOCAL_NETBOOT_DIR}"
201		if [ -d "${netboot_dir}" ]; then
202			rm -rf "${swapdir}"
203			ln -s "${netboot_dir}" "${swapdir}"
204		fi
205		;;
206	*)
207	;;
208    esac
209
210    # set the ComputerName based on what the NetBoot server told us it was
211    machine_name=$(ipconfig netbootoption machine_name 2>&1)
212    if [ $? -ne 0 ]; then
213	echo "no machine name option available"
214    else
215	echo "Setting ComputerName to ${machine_name}"
216	scutil --set ComputerName "${machine_name}"
217    fi
218}
219
220
221if [ $# -lt 1 ] ; then
222    exit 0
223fi
224
225command=$1
226
227shift
228
229case "${command}" in
230    init)
231	do_init $@
232	;;
233esac 
234
235##
236# Exit
237##
238exit 0
239