nanobsd.sh revision 164660
1#!/bin/sh
2#
3# Copyright (c) 2005 Poul-Henning Kamp.
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: head/tools/tools/nanobsd/nanobsd.sh 164660 2006-11-27 12:16:03Z n_hibma $
28#
29
30set -e
31
32#######################################################################
33#
34# Setup default values for all controlling variables.
35# These values can be overridden from the config file(s)
36#
37#######################################################################
38
39# Name of this NanoBSD build.  (Used to construct workdir names)
40NANO_NAME=full
41
42# Source tree directory
43NANO_SRC=/usr/src
44
45# Where nanobsd additional files live under the source tree
46NANO_TOOLS=tools/tools/nanobsd
47
48# Object tree directory
49# default is subdir of /usr/obj
50# XXX: MAKEOBJDIRPREFIX handling... ?
51#NANO_OBJ=""
52
53# Parallel Make
54NANO_PMAKE="make -j 3"
55
56# Options to put in make.conf during buildworld only
57CONF_BUILD=' '
58
59# Options to put in make.conf during installworld only
60CONF_INSTALL=' '
61
62# Options to put in make.conf during both build- & installworld.
63CONF_WORLD=' '
64
65# Kernel config file to use
66NANO_KERNEL=GENERIC
67
68# Customize commands.
69NANO_CUSTOMIZE=""
70
71# Newfs paramters to use
72NANO_NEWFS="-b 4096 -f 512 -i 8192 -O1 -U"
73
74# The drive name of the media at runtime
75NANO_DRIVE=ad0
76
77# Target media size in 512 bytes sectors
78NANO_MEDIASIZE=1048576
79
80# Number of code images on media (1 or 2)
81NANO_IMAGES=2
82
83# Size of code file system in 512 bytes sectors
84# If zero, size will be as large as possible.
85NANO_CODESIZE=0
86
87# Size of configuration file system in 512 bytes sectors
88# Cannot be zero.
89NANO_CONFSIZE=2048
90
91# Size of data file system in 512 bytes sectors
92# If zero: no partition configured.
93# If negative: max size possible
94NANO_DATASIZE=0
95
96# Size of the /etc ramdisk in 512 bytes sectors
97NANO_RAM_ETCSIZE=10240
98
99# Size of the /tmp+/var ramdisk in 512 bytes sectors
100NANO_RAM_TMPVARSIZE=10240
101
102# Media geometry, only relevant if bios doesn't understand LBA.
103NANO_SECTS=32
104NANO_HEADS=16
105
106#######################################################################
107# Not a variable at this time
108
109NANO_ARCH=i386
110
111#######################################################################
112#
113# The functions which do the real work.
114# Can be overridden from the config file(s)
115#
116#######################################################################
117
118clean_build ( ) (
119	echo "## Clean and create object directory (${MAKEOBJDIRPREFIX})"
120
121	if rm -rf ${MAKEOBJDIRPREFIX} > /dev/null 2>&1 ; then
122		true
123	else
124		chflags -R noschg ${MAKEOBJDIRPREFIX}
125		rm -rf ${MAKEOBJDIRPREFIX}
126	fi
127	mkdir -p ${MAKEOBJDIRPREFIX}
128	printenv > ${MAKEOBJDIRPREFIX}/_.env
129)
130
131make_conf_build ( ) (
132	echo "## Construct build make.conf ($NANO_MAKE_CONF)"
133
134	echo "${CONF_WORLD}" > ${NANO_MAKE_CONF}
135	echo "${CONF_BUILD}" >> ${NANO_MAKE_CONF}
136)
137
138build_world ( ) (
139	echo "## run buildworld"
140	echo "### log: ${MAKEOBJDIRPREFIX}/_.bw"
141
142	cd ${NANO_SRC}
143	${NANO_PMAKE} __MAKE_CONF=${NANO_MAKE_CONF} buildworld \
144		> ${MAKEOBJDIRPREFIX}/_.bw 2>&1
145)
146
147build_kernel ( ) (
148	echo "## build kernel ($NANO_KERNEL)"
149	echo "### log: ${MAKEOBJDIRPREFIX}/_.bk"
150
151	if [ -f ${NANO_KERNEL} ] ; then
152		cp ${NANO_KERNEL} ${NANO_SRC}/sys/${NANO_ARCH}/conf
153	fi
154
155	cd ${NANO_SRC}
156	${NANO_PMAKE} buildkernel \
157		__MAKE_CONF=${NANO_MAKE_CONF} KERNCONF=`basename ${NANO_KERNEL}` \
158		> ${MAKEOBJDIRPREFIX}/_.bk 2>&1
159)
160
161clean_world ( ) (
162	echo "## Clean and create world directory (${NANO_WORLDDIR})"
163	if rm -rf ${NANO_WORLDDIR}/ > /dev/null 2>&1 ; then
164		true
165	else
166		chflags -R noschg ${NANO_WORLDDIR}/
167		rm -rf ${NANO_WORLDDIR}/
168	fi
169	mkdir -p ${NANO_WORLDDIR}/
170)
171
172make_conf_install ( ) (
173	echo "## Construct install make.conf ($NANO_MAKE_CONF)"
174
175	echo "${CONF_WORLD}" > ${NANO_MAKE_CONF}
176	echo "${CONF_INSTALL}" >> ${NANO_MAKE_CONF}
177)
178
179install_world ( ) (
180	echo "## installworld"
181	echo "### log: ${MAKEOBJDIRPREFIX}/_.iw"
182
183	cd ${NANO_SRC}
184	${NANO_PMAKE} __MAKE_CONF=${NANO_MAKE_CONF} installworld \
185		DESTDIR=${NANO_WORLDDIR} \
186		> ${MAKEOBJDIRPREFIX}/_.iw 2>&1
187	chflags -R noschg ${NANO_WORLDDIR}
188)
189
190install_etc ( ) (
191
192	echo "## install /etc"
193	echo "### log: ${MAKEOBJDIRPREFIX}/_.etc"
194
195	cd ${NANO_SRC}
196	${NANO_PMAKE} __MAKE_CONF=${NANO_MAKE_CONF} distribution \
197		DESTDIR=${NANO_WORLDDIR} \
198		> ${MAKEOBJDIRPREFIX}/_.etc 2>&1
199)
200
201install_kernel ( ) (
202	echo "## install kernel"
203	echo "### log: ${MAKEOBJDIRPREFIX}/_.ik"
204
205	cd ${NANO_SRC}
206	${NANO_PMAKE} installkernel \
207		DESTDIR=${NANO_WORLDDIR} \
208		__MAKE_CONF=${NANO_MAKE_CONF} KERNCONF=`basename ${NANO_KERNEL}` \
209		> ${MAKEOBJDIRPREFIX}/_.ik 2>&1
210)
211
212run_customize() (
213
214	echo "## run customize scripts"
215	for c in $NANO_CUSTOMIZE
216	do
217		echo "## customize \"$c\""
218		echo "### log: ${MAKEOBJDIRPREFIX}/_.cust.$c"
219		echo "### `type $c`"
220		( $c ) > ${MAKEOBJDIRPREFIX}/_.cust.$c 2>&1
221	done
222)
223
224setup_nanobsd ( ) (
225	echo "## configure nanobsd setup"
226	echo "### log: ${MAKEOBJDIRPREFIX}/_.dl"
227
228	(
229	cd ${NANO_WORLDDIR}
230
231	for d in var etc
232	do
233		# link /$d under /conf
234		# we use hard links so we have them both places.
235		# the files in /$d will be hidden by the mount.
236		# XXX: configure /$d ramdisk size
237		mkdir -p conf/base/$d conf/default/$d
238		find $d -print | cpio -dumpl conf/base/
239	done
240
241	echo "$NANO_RAM_ETCSIZE" > conf/base/etc/md_size
242	echo "$NANO_RAM_TMPVARSIZE" > conf/base/var/md_size
243
244	# pick up config files from the special partition
245	echo "mount -o ro /dev/${NANO_DRIVE}s3" > conf/default/etc/remount
246
247	# Put /tmp on the /var ramdisk (could be symlink already)
248	rmdir tmp || true
249	rm tmp || true
250	ln -s var/tmp tmp
251
252	) > ${MAKEOBJDIRPREFIX}/_.dl 2>&1
253)
254
255setup_nanobsd_etc ( ) (
256	echo "## configure nanobsd /etc"
257
258	(
259	cd ${NANO_WORLDDIR}
260
261	# create diskless marker file
262	touch etc/diskless
263
264	# save config file for scripts
265	echo "NANO_DRIVE=${NANO_DRIVE}" > etc/nanobsd.conf
266
267	echo "/dev/${NANO_DRIVE}s1a / ufs ro 1 1" > etc/fstab
268	echo "/dev/${NANO_DRIVE}s3 /cfg ufs rw,noauto 2 2" >> etc/fstab
269	mkdir -p cfg
270	)
271)
272
273prune_usr() (
274
275	# Remove all empty directories in /usr 
276	find ${NANO_WORLDDIR}/usr -type d -depth -print |
277		while read d
278		do
279			rmdir $d > /dev/null 2>&1 || true 
280		done
281)
282
283create_i386_diskimage ( ) (
284	echo "## build diskimage"
285	echo "### log: ${MAKEOBJDIRPREFIX}/_.di"
286
287	(
288	echo $NANO_MEDIASIZE $NANO_IMAGES \
289		$NANO_SECTS $NANO_HEADS \
290		$NANO_CODESIZE $NANO_CONFSIZE $NANO_DATASIZE |
291	awk '
292	{
293		printf "# %s\n", $0
294
295		# size of cylinder in sectors
296		cs = $3 * $4
297
298		# number of full cylinders on media
299		cyl = int ($1 / cs)
300
301		# output fdisk geometry spec, truncate cyls to 1023
302		if (cyl <= 1023)
303			print "g c" cyl " h" $4 " s" $3
304		else
305			print "g c" 1023 " h" $4 " s" $3
306
307		if ($7 > 0) { 
308			# size of data partition in full cylinders
309			dsl = int (($7 + cs - 1) / cs)
310		} else {
311			dsl = 0;
312		}
313
314		# size of config partition in full cylinders
315		csl = int (($6 + cs - 1) / cs)
316
317		if ($5 == 0) {
318			# size of image partition(s) in full cylinders
319			isl = int ((cyl - dsl - csl) / $2)
320		} else {
321			isl = int (($5 + cs - 1) / cs)
322		}
323
324		# First image partition start at second track
325		print "p 1 165 " $3, isl * cs - $3
326		c = isl * cs;
327
328		# Second image partition (if any) also starts offset one 
329		# track to keep them identical.
330		if ($2 > 1) {
331			print "p 2 165 " $3 + c, isl * cs - $3
332			c += isl * cs;
333		}
334
335		# Config partition starts at cylinder boundary.
336		print "p 3 165 " c, csl * cs
337		c += csl * cs
338
339		# Data partition (if any) starts at cylinder boundary.
340		if ($7 > 0) {
341			print "p 4 165 " c, dsl * cs
342		} else if ($7 < 0 && $1 > $c) {
343			print "p 4 165 " c, $1 - $c
344		} else if ($1 < c) {
345			print "Disk space overcommitted by", \
346			    c - $1, "sectors" > "/dev/stderr"
347			exit 2
348		}
349	}
350	' > ${MAKEOBJDIRPREFIX}/_.fdisk
351
352	IMG=${MAKEOBJDIRPREFIX}/_.disk.full
353	MNT=${MAKEOBJDIRPREFIX}/_.mnt
354	mkdir -p ${MNT}
355
356	dd if=/dev/zero of=${IMG} bs=${NANO_SECTS}b \
357	    count=`expr ${NANO_MEDIASIZE} / ${NANO_SECTS}`
358
359	MD=`mdconfig -a -t vnode -f ${IMG} -x ${NANO_SECTS} -y ${NANO_HEADS}`
360
361	trap "df -i ${MNT} ; umount ${MNT} || true ; mdconfig -d -u $MD" 1 2 15 EXIT
362
363	fdisk -i -f ${MAKEOBJDIRPREFIX}/_.fdisk ${MD}
364	fdisk ${MD}
365	# XXX: params
366	# XXX: pick up cached boot* files, they may not be in image anymore.
367	boot0cfg -B -b ${NANO_WORLDDIR}/boot/boot0sio -o packet -s 1 -m 3 ${MD}
368	bsdlabel -w -B -b ${NANO_WORLDDIR}/boot/boot ${MD}s1
369	bsdlabel ${MD}s1
370
371	# Create first image
372	newfs ${NANO_NEWFS} /dev/${MD}s1a
373	mount /dev/${MD}s1a ${MNT}
374	df -i ${MNT}
375	( cd ${NANO_WORLDDIR} && find . -print | cpio -dump ${MNT} )
376	df -i ${MNT}
377	( cd ${MNT} && mtree -c ) > ${MAKEOBJDIRPREFIX}/_.mtree
378	( cd ${MNT} && du -k ) > ${MAKEOBJDIRPREFIX}/_.du
379	umount ${MNT}
380
381	if [ $NANO_IMAGES -gt 1 ] ; then
382		# Duplicate to second image (if present)
383		dd if=/dev/${MD}s1 of=/dev/${MD}s2 bs=64k
384	fi
385	
386	# Create Config slice
387	newfs ${NANO_NEWFS} /dev/${MD}s3
388	# XXX: fill from where ?
389
390	# Create Data slice, if any.
391	if [ $NANO_DATASIZE -gt 0 ] ; then
392		newfs ${NANO_NEWFS} /dev/${MD}s4
393		# XXX: fill from where ?
394	fi
395
396	dd if=/dev/${MD}s1 of=${MAKEOBJDIRPREFIX}/_.disk.image bs=64k
397	mdconfig -d -u $MD
398	) > ${MAKEOBJDIRPREFIX}/_.di 2>&1
399)
400
401last_orders () (
402	# Redefine this function with any last orders you may have
403	# after the build completed, for instance to copy the finished
404	# image to a more convenient place:
405	# cp ${MAKEOBJDIRPREFIX}/_.disk.image /home/ftp/pub/nanobsd.disk
406)
407
408#######################################################################
409#
410# Optional convenience functions.
411#
412#######################################################################
413
414#######################################################################
415# Common Flash device geometries
416#
417
418FlashDevice () {
419	if [ -d ${NANO_TOOLS} ] ; then
420		. ${NANO_TOOLS}/FlashDevice.sub
421	else
422		. ${NANO_SRC}/${NANO_TOOLS}/FlashDevice.sub
423	fi
424	sub_FlashDevice $1 $2
425}
426
427
428#######################################################################
429# Setup serial console
430
431cust_comconsole () (
432	# Enable getty on console
433	sed -i "" -e /ttyd0/s/off/on/ ${NANO_WORLDDIR}/etc/ttys
434
435	# Disable getty on syscons devices
436	sed -i "" -e '/^ttyv[0-8]/s/	on/	off/' ${NANO_WORLDDIR}/etc/ttys
437
438	# Tell loader to use serial console early.
439	echo " -h" > ${NANO_WORLDDIR}/boot.config
440)
441
442#######################################################################
443# Allow root login via ssh
444
445cust_allow_ssh_root () (
446	sed -i "" -e '/PermitRootLogin/s/.*/PermitRootLogin yes/' \
447	    ${NANO_WORLDDIR}/etc/ssh/sshd_config
448)
449
450#######################################################################
451# Install the stuff under ./Files
452
453cust_install_files () (
454	cd ${NANO_TOOLS}/Files
455	find . -print | grep -v /CVS | cpio -dumpv ${NANO_WORLDDIR}
456)
457
458#######################################################################
459# Convenience function:
460# 	Register $1 as customize function.
461
462customize_cmd () {
463	NANO_CUSTOMIZE="$NANO_CUSTOMIZE $1"
464}
465
466#######################################################################
467#
468# All set up to go...
469#
470#######################################################################
471
472usage () {
473	(
474	echo "Usage: $0 [-b/-k/-w] [-c config_file]"
475	echo "	-b	suppress builds (both kernel and world)"
476	echo "	-k	suppress buildkernel"
477	echo "	-w	suppress buildworld"
478	echo "	-c	specify config file"
479	) 1>&2
480	exit 2
481}
482
483#######################################################################
484# Parse arguments
485
486do_kernel=true
487do_world=true
488
489set +e
490args=`getopt bc:hkw $*`
491if [ $? -ne 0 ] ; then
492	usage
493	exit 2
494fi
495set -e
496
497set -- $args
498for i
499do
500	case "$i" 
501	in
502	-b)
503		shift;
504		do_world=false
505		do_kernel=false
506		;;
507	-k)
508		shift;
509		do_kernel=false
510		;;
511	-c)
512		. "$2"
513		shift;
514		shift;
515		;;
516	-h)
517		usage
518		;;
519	-w)
520		shift;
521		do_world=false
522		;;
523	--)
524		shift;
525		break;
526	esac
527done
528
529if [ $# -gt 0 ] ; then
530	echo "$0: Extraneous arguments supplied"
531	usage
532fi
533
534#######################################################################
535# Setup and Export Internal variables
536#
537if [ "x${NANO_OBJ}" = "x" ] ; then
538	MAKEOBJDIRPREFIX=/usr/obj/nanobsd.${NANO_NAME}/
539	NANO_OBJ=${MAKEOBJDIRPREFIX}
540else
541	MAKEOBJDIRPREFIX=${NANO_OBJ}
542fi
543
544NANO_WORLDDIR=${MAKEOBJDIRPREFIX}/_.w
545NANO_MAKE_CONF=${MAKEOBJDIRPREFIX}/make.conf
546
547if [ -d ${NANO_TOOLS} ] ; then
548	true
549elif [ -d ${NANO_SRC}/${NANO_TOOLS} ] ; then
550	NANO_TOOLS=${NANO_SRC}/${NANO_TOOLS}
551else
552	echo "NANO_TOOLS directory does not exist" 1>&2
553	exit 1
554fi
555
556export MAKEOBJDIRPREFIX
557
558export NANO_ARCH
559export NANO_CODESIZE
560export NANO_CONFSIZE
561export NANO_CUSTOMIZE
562export NANO_DATASIZE
563export NANO_DRIVE
564export NANO_HEADS
565export NANO_IMAGES
566export NANO_MAKE_CONF
567export NANO_MEDIASIZE
568export NANO_NAME
569export NANO_NEWFS
570export NANO_OBJ
571export NANO_PMAKE
572export NANO_SECTS
573export NANO_SRC
574export NANO_TOOLS
575export NANO_WORLDDIR
576
577#######################################################################
578# And then it is as simple as that...
579
580if $do_world ; then
581	clean_build
582	make_conf_build
583	build_world
584else
585	echo "## Skipping buildworld (as instructed)"
586fi
587
588if $do_kernel ; then
589	build_kernel
590else
591	echo "## Skipping buildkernel (as instructed)"
592fi
593
594clean_world
595make_conf_install
596install_world
597install_etc
598setup_nanobsd_etc
599install_kernel
600
601run_customize
602setup_nanobsd
603prune_usr
604create_${NANO_ARCH}_diskimage
605last_orders
606
607echo "# NanoBSD image completed"
608