1 #!/bin/sh
2 #
3 # CDDL HEADER START
4 #
5 # The contents of this file are subject to the terms of the
6 # Common Development and Distribution License (the "License").
7 # You may not use this file except in compliance with the License.
8 #
9 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 # or http://www.opensolaris.org/os/licensing.
11 # See the License for the specific language governing permissions
12 # and limitations under the License.
13 #
14 # When distributing Covered Code, include this CDDL HEADER in each
15 # file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 # If applicable, add the following below this CDDL HEADER, with the
17 # fields enclosed by brackets "[]" replaced with your own identifying
18 # information: Portions Copyright [yyyy] [name of copyright owner]
19 #
20 # CDDL HEADER END
21 #
22 # Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 # Use is subject to license terms.
24
25 #
26 # Description:
27 # Sets up client data specific for a particular client, in the
28 # non-default case. In general, client setup is not required and all
29 # clients will boot the default service as tagged in create-service.
30 # If it is desired to have a client boot and utilize specific services
31 # and manifests, this command is used to do so. The following
32 # functionality is provided:
33 #
34 # 1. Allow for specification of installation service for client to use.
35 # This will bypass the service discovery mechanism and use a specific
36 # service. The administrator can set up manifiests with that service
37 # to serve the clients.
38 #
39 # 2. For x86, creates a bootfile and /tftpboot entries. The bootfile
40 # name is derived from the MAC address.
41 # For sparc, create wanboot.conf file in following location:
42 #
43 # /etc/netboot/<network_address>/<client_id>/wanboot.conf
44 #
45 # where <client_id>=01<mac_address_without_collons>
46 # e.g. 0100144FA2574C
47 #
48 # 3. Setup the dhcp macro with the server and bootfile information
49 # if it doesn't exist.
50 #
51 # Files potentially changed on server:
52 # /tftpboot/ - directory created/populated with pxegrub files and links.
53 # /etc/inetd.conf - to turn on tftpboot daemon
54 # /etc/netboot/<network number>/<MACID>/wanboot.conf
55
56 # make sure path is ok
57 PATH=/usr/bin:/usr/sbin:/sbin:${PATH}; export PATH
58
59 # tr may fail in some locales. Hence set the env LANG=C and LC_ALL=C
60 TR='env LC_ALL=C LANG=C /bin/tr'
61
62 # Constants
63 #
64 SIGHUP=1
65 SIGINT=2
66 SIGQUIT=3
67 SIGTERM=15
68
69 # Variables
70 #
71 DHCP_CLIENT_ID=""
72 DIRNAME="/usr/lib/installadm"
73 INSTALL_TYPE="_OSInstall._tcp"
74 Bootdir="/tftpboot"
75
76 # Settings for client specific properties, to be passed via grub menu
77 #
78 BARGLIST=""
79
80 # import common functions
81 #
82 . ${DIRNAME}/installadm-common
83
84
85 # usage
86 #
87 # Purpose : Print the usage message in the event the user
88 # has input illegal command line parameters and
89 # then exit
90 #
91 # Arguments :
92 # none
93 #
94 usage () {
95 echo "Usage: $0 [-b <property>=<value>,...]"
96 echo "\t\t-e <macaddr> -n <svcname> [-t <imagepath>]"
97
98 exit 1
99 }
100
101 abort()
102 {
103 echo "${myname}: Aborted"
104 exit 1
105 }
106
107
108 #
109 # MAIN - Program
110 #
111
112 myname=`basename $0`
113 ID=`id`
114 USER=`expr "${ID}" : 'uid=\([^(]*\).*'`
115
116 unset BOOT_FILE IMAGE_PATH IMAGE_SERVER MAC_ADDR
117 unset SERVER SERVICE_NAME
118
119 trap abort $SIGHUP $SIGINT $SIGQUIT $SIGTERM
120
121 # Verify user ID before proceeding - must be root
122 #
123 if [ "${USER}" != "0" ]; then
124 echo "You must be root to run $0"
125 exit 1
126 fi
127
128
129 # Get SERVER info
130 #
131 SERVER_IP=`get_server_ip`
132 if [ -z $SERVER_IP ] ; then
133 echo "Failed to get server's IP address."
134 exit 1
135 fi
136
137 # Parse the command line options.
138 #
139 while [ "$1"x != "x" ]; do
140 case $1 in
141 -e) MAC_ADDR="$2";
142 if [ "X$MAC_ADDR" = "X" ]; then
143 usage ;
144 fi
145
146 fnum=`echo "${MAC_ADDR}" | awk 'BEGIN { FS = ":" } { print NF } ' `
147 if [ $fnum != 6 ]; then
148 echo "${myname}: malformed MAC address: $MAC_ADDR"
149 exit 1
150 fi
151
152 MAC_ADDR=`expr $MAC_ADDR : '\([0-9a-fA-F][0-9a-fA-F]*\:[0-9a-fA-F][0-9a-fA-F]*\:[0-9a-fA-F][0-9a-fA-F]*\:[0-9a-fA-F][0-9a-fA-F]*\:[0-9a-fA-F][0-9a-fA-F]*\:[0-9a-fA-F][0-9a-fA-F]*\)'`
153
154 if [ ! "${MAC_ADDR}" ] ; then
155 echo "${myname}: malformed MAC address: $2"
156 exit 1
157 fi
158 shift 2;;
159 -n) SERVICE_NAME=$2
160 if [ ! "$SERVICE_NAME" ]; then
161 usage ;
162 fi
163 shift 2;;
164
165 # Accept value for -t as either <server:/path> or </path>.
166 #
167 -t) if [ ! "$2" ]; then
168 usage;
169 fi
170 IMAGE_SERVER=`expr $2 : '\(.*\):.*'`
171 if [ -n "${IMAGE_SERVER}" ]; then
172 IMAGE_PATH=`expr $2 : '.*:\(.*\)'`
173 else
174 # no server provided, just get path
175 IMAGE_PATH=$2
176 fi
177 if [ ! "$IMAGE_PATH" ]; then
178 echo "${myname}: Invalid image pathname"
179 usage ;
180 fi
181 shift 2;;
182 -f) BOOT_FILE=$2
183 if [ ! "$BOOT_FILE" ] ; then
184 usage ;
185 fi
186 shift 2;;
187
188 # -b option is used to introduce changes in a client,
189 # e.g. console=ttya
190 #
191 -b) BARGLIST="$BARGLIST"$2","
192 shift 2;;
193
194 -*) # -anything else is an unknown argument
195 usage ;
196 ;;
197 *) # all else is spurious
198 usage ;
199 ;;
200 esac
201 done
202
203 if [ -z "${MAC_ADDR}" -o -z "${SERVICE_NAME}" ]; then
204 echo "${myname}: Missing one or more required options."
205 usage
206 fi
207
208
209 # Verify that service corresponding to SERVICE_NAME exists
210 #
211 # Check the service exists in SMF
212 svcprop -p AI${SERVICE_NAME}/image_path \
213 -c svc:/system/install/server:default 1>/dev/null 2>&1
214 if [ $? -ne 0 ]; then
215 echo "${myname}: Service does not exist: ${SERVICE_NAME}"
216 exit 1
217 fi
218 # Check that the service is running
219 ${DIRNAME}/setup-service lookup ${SERVICE_NAME} ${INSTALL_TYPE} local
220 if [ $? -ne 0 ] ; then
221 echo "${myname}: Service does not exist: ${SERVICE_NAME}"
222 exit 1
223 fi
224
225
226 # Determine IMAGE PATH if not provided
227 #
228 if [ -z "${IMAGE_PATH}" ]; then
229 # Find IMAGE PATH from SMF
230 IMAGE_PATH="`svcprop -p AI${SERVICE_NAME}/image_path \
231 -c svc:/system/install/server:default 2>/dev/null`"
232 if [ $? -ne 0 ]; then
233 echo "${myname}: Image-path record for service" \
234 "${SERVICE_NAME} is missing."
235 exit 1
236 fi
237 fi
238
239 # If IMAGE_SERVER is passed in, check that it is equal to the local system
240 # since we don't yet support a remote system being the image server.
241 #
242 if [ -n "${IMAGE_SERVER}" ]; then
243 IMAGE_IP=`get_host_ip ${IMAGE_SERVER}`
244 if [ -z $IMAGE_IP ] ; then
245 echo "${myname}: Failed to get IP address for ${IMAGE_SERVER}"
246 exit 1
247 fi
248
249 if [ "${IMAGE_IP}" != "${SERVER_IP}" ]; then
250 echo "${myname}: Remote image server is not supported at this time."
251 exit 1
252 fi
253 fi
254
255 # Verify that IMAGE_PATH is a valid directory
256 #
257 if [ ! -d ${IMAGE_PATH} ]; then
258 echo "${myname}: Install image directory ${IMAGE_PATH} does not exist."
259 exit 1
260 fi
261
262 # Verify valid image
263 #
264 if [ ! -f ${IMAGE_PATH}/solaris.zlib ]; then
265 echo "${myname}: ${IMAGE_PATH}/solaris.zlib does not exist. " \
266 "The specified image is not an OpenSolaris image."
267 exit 1
268 fi
269
270
271 # Determine if image is sparc or x86
272 #
273 IMAGE_TYPE=`get_image_type ${IMAGE_PATH}`
274
275 # For sparc, make sure the user hasn't specified a boot file via
276 # the "-f" option. If they have, the BOOT_FILE variable will be set.
277 #
278 if [ "${IMAGE_TYPE}" = "${SPARC_IMAGE}" ]; then
279 if [ "X$BOOT_FILE" != "X" ] ; then
280 echo "${myname}: \"-f\" is an invalid option for SPARC"
281 exit 1
282 fi
283 fi
284
285
286 # Convert the Ethernet address to DHCP "default client-ID" form:
287 # uppercase hex, preceded by the hardware
288 # address type ("01" for ethernet)
289 #
290 DHCP_CLIENT_ID=01`echo "${MAC_ADDR}" | ${TR} '[a-z]' '[A-Z]' |
291 awk -F: '
292 {
293 for (i = 1; i <= 6 ; i++)
294 if (length($i) == 1) {
295 printf("0%s", $i)
296 } else {
297 printf("%s", $i);
298 }
299 }'`
300
301
302 # Perform x86/sparc specific setup activities
303 #
304 if [ "${IMAGE_TYPE}" = "${X86_IMAGE}" ]; then
305 echo "Setting up X86 client..."
306 if [ "${BARGLIST}" = "" ]; then
307 # Set to null as a placeholder in the argument list
308 BARGLIST="null"
309 fi
310
311 #
312 # pass service location as "unknown" - it will be
313 # determined later when creating configuration file
314 #
315 ${DIRNAME}/setup-tftp-links client ${SERVICE_NAME} \
316 ${SERVICE_ADDRESS_UNKNOWN} ${IMAGE_PATH} ${DHCP_CLIENT_ID} \
317 ${BARGLIST} ${BOOT_FILE}
318 status=$?
319 if [ $status -ne 0 ]; then
320 echo "${myname}: Unable to setup x86 client"
321 exit 1
322 fi
323
324 # Set value of DHCP_BOOT_FILE.
325 DHCP_BOOT_FILE=${DHCP_CLIENT_ID}
326 if [ "X${BOOT_FILE}" != "X" ] ; then
327 DHCP_BOOT_FILE=${BOOT_FILE}
328 fi
329 dhcptype="x86"
330 else
331 echo "Setting up SPARC client..."
332 # For sparc, set value of DHCP_BOOT_FILE and setup wanboot.conf file.
333 #
334 DHCP_BOOT_FILE="http://${SERVER_IP}:${HTTP_PORT}/${CGIBIN_WANBOOTCGI}"
335 ${DIRNAME}/setup-sparc client ${DHCP_CLIENT_ID} ${IMAGE_PATH}
336 status=$?
337 if [ $status -ne 0 ]; then
338 echo "${myname}: Unable to setup SPARC client"
339 exit 1
340 fi
341 dhcptype="sparc"
342 fi
343
344
345 # Try to update the DHCP server automatically. If not possible,
346 # then tell the user how to define the DHCP macro.
347 #
348 ${DIRNAME}/setup-dhcp client ${dhcptype} ${SERVER_IP} ${DHCP_CLIENT_ID} \
349 ${DHCP_BOOT_FILE}
350
351 status=$?
352
353 # Print nothing if setup-dhcp returns non-zero. setup-dhcp takes care of
354 # providing instructions for the user in that case.
355 #
356 if [ $status -eq 0 ]; then
357 echo "Enabled network boot by adding a macro named ${DHCP_CLIENT_ID}"
358 echo "to DHCP server with:"
359 echo " Boot server IP (BootSrvA) : ${SERVER_IP}"
360 echo " Boot file (BootFile) : ${DHCP_BOOT_FILE}"
361 fi
362
363 exit 0