nanobsd.sh revision 156496
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 156496 2006-03-09 14:43:07Z phk $
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=${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}/etc
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=${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	# create diskless marker file
232	touch etc/diskless
233
234	# save config file for scripts
235	echo "NANO_DRIVE=${NANO_DRIVE}" > etc/nanobsd.conf
236
237	echo "/dev/${NANO_DRIVE}s1a / ufs ro 1 1" > etc/fstab
238	echo "/dev/${NANO_DRIVE}s3 /cfg ufs rw,noauto 2 2" >> etc/fstab
239	mkdir -p cfg
240
241	for d in var etc
242	do
243		# link /$d under /conf
244		# we use hard links so we have them both places.
245		# the files in /$d will be hidden by the mount.
246		# XXX: configure /$d ramdisk size
247		mkdir -p conf/base/$d conf/default/$d
248		find $d -print | cpio -dumpl conf/base/
249	done
250
251	echo "$NANO_RAM_ETCSIZE" > conf/base/etc/md_size
252	echo "$NANO_RAM_TMPVARSIZE" > conf/base/var/md_size
253
254	# pick up config files from the special partition
255	echo "mount -o ro /dev/${NANO_DRIVE}s3" > conf/default/etc/remount
256
257	# Put /tmp on the /var ramdisk (could be symlink already)
258	rmdir tmp || true
259	rm tmp || true
260	ln -s var/tmp tmp
261
262	) > ${MAKEOBJDIRPREFIX}/_.dl 2>&1
263)
264
265prune_usr() (
266
267	# Remove all empty directories in /usr 
268	find ${NANO_WORLDDIR}/usr -type d -depth -print |
269		while read d
270		do
271			rmdir $d > /dev/null 2>&1 || true 
272		done
273)
274
275create_i386_diskimage ( ) (
276	echo "## build diskimage"
277	echo "### log: ${MAKEOBJDIRPREFIX}/_.di"
278
279	(
280	echo $NANO_MEDIASIZE $NANO_IMAGES \
281		$NANO_SECTS $NANO_HEADS \
282		$NANO_CODESIZE $NANO_CONFSIZE $NANO_DATASIZE |
283	awk '
284	{
285		printf "# %s\n", $0
286
287		# size of cylinder in sectors
288		cs = $3 * $4
289
290		# number of full cylinders on media
291		cyl = int ($1 / cs)
292
293		# output fdisk geometry spec, truncate cyls to 1023
294		if (cyl <= 1023)
295			print "g c" cyl " h" $4 " s" $3
296		else
297			print "g c" 1023 " h" $4 " s" $3
298
299		if ($7 > 0) { 
300			# size of data partition in full cylinders
301			dsl = int (($7 + cs - 1) / cs)
302		} else {
303			dsl = 0;
304		}
305
306		# size of config partition in full cylinders
307		csl = int (($6 + cs - 1) / cs)
308
309		if ($5 == 0) {
310			# size of image partition(s) in full cylinders
311			isl = int ((cyl - dsl - csl) / $2)
312		} else {
313			isl = int (($5 + cs - 1) / cs)
314		}
315
316		# First image partition start at second track
317		print "p 1 165 " $3, isl * cs - $3
318		c = isl * cs;
319
320		# Second image partition (if any) also starts offset one 
321		# track to keep them identical.
322		if ($2 > 1) {
323			print "p 2 165 " $3 + c, isl * cs - $3
324			c += isl * cs;
325		}
326
327		# Config partition starts at cylinder boundary.
328		print "p 3 165 " c, csl * cs
329		c += csl * cs
330
331		# Data partition (if any) starts at cylinder boundary.
332		if ($7 > 0) {
333			print "p 4 165 " c, dsl * cs
334		} else if ($7 < 0 && $1 > $c) {
335			print "p 4 165 " c, $1 - $c
336		} else if ($1 < c) {
337			print "Disk space overcommitted by", \
338			    c - $1, "sectors" > "/dev/stderr"
339			exit 2
340		}
341	}
342	' > ${MAKEOBJDIRPREFIX}/_.fdisk
343
344	IMG=${MAKEOBJDIRPREFIX}/_.disk.full
345	MNT=${MAKEOBJDIRPREFIX}/_.mnt
346	mkdir -p ${MNT}
347
348	dd if=/dev/zero of=${IMG} bs=${NANO_SECTS}b \
349	    count=`expr ${NANO_MEDIASIZE} / ${NANO_SECTS}`
350
351	MD=`mdconfig -a -t vnode -f ${IMG} -x ${NANO_SECTS} -y ${NANO_HEADS}`
352
353	trap "df -i ${MNT} ; umount ${MNT} || true ; mdconfig -d -u $MD" 1 2 15 EXIT
354
355	fdisk -i -f ${MAKEOBJDIRPREFIX}/_.fdisk ${MD}
356	fdisk ${MD}
357	# XXX: params
358	# XXX: pick up cached boot* files, they may not be in image anymore.
359	boot0cfg -B -b ${NANO_WORLDDIR}/boot/boot0sio -o packet -s 1 -m 3 ${MD}
360	bsdlabel -w -B ${MD}s1
361	bsdlabel ${MD}s1
362
363	# Create first image
364	newfs ${NANO_NEWFS} /dev/${MD}s1a
365	mount /dev/${MD}s1a ${MNT}
366	df -i ${MNT}
367	( cd ${NANO_WORLDDIR} && find . -print | cpio -dump ${MNT} )
368	df -i ${MNT}
369	( cd ${MNT} && mtree -c ) > ${MAKEOBJDIRPREFIX}/_.mtree
370	( cd ${MNT} && du -k ) > ${MAKEOBJDIRPREFIX}/_.du
371	umount ${MNT}
372
373	if [ $NANO_IMAGES -gt 1 ] ; then
374		# Duplicate to second image (if present)
375		dd if=/dev/${MD}s1 of=/dev/${MD}s2 bs=64k
376	fi
377	
378	# Create Config slice
379	newfs ${NANO_NEWFS} /dev/${MD}s3
380	# XXX: fill from where ?
381
382	# Create Data slice, if any.
383	if [ $NANO_DATASIZE -gt 0 ] ; then
384		newfs ${NANO_NEWFS} /dev/${MD}s4
385		# XXX: fill from where ?
386	fi
387
388	dd if=/dev/${MD}s1 of=${MAKEOBJDIRPREFIX}/_.disk.image bs=64k
389	mdconfig -d -u $MD
390	) > ${MAKEOBJDIRPREFIX}/_.di 2>&1
391)
392
393last_orders () (
394	# Redefine this function with any last orders you may have
395	# after the build completed, for instance to copy the finished
396	# image to a more convenient place:
397	# cp ${MAKEOBJDIRPREFIX}/_.disk.image /home/ftp/pub/nanobsd.disk
398)
399
400#######################################################################
401#
402# Optional convenience functions.
403#
404#######################################################################
405
406#######################################################################
407# Common Flash device geometries
408#
409
410FlashDevice () {
411	if [ -d ${NANO_TOOLS} ] ; then
412		. ${NANO_TOOLS}/FlashDevice.sub
413	else
414		. ${NANO_SRC}/${NANO_TOOLS}/FlashDevice.sub
415	fi
416	sub_FlashDevice $1 $2
417}
418
419
420#######################################################################
421# Setup serial console
422
423cust_comconsole () (
424	# Enable getty on console
425	sed -i "" -e /ttyd0/s/off/on/ ${NANO_WORLDDIR}/etc/ttys
426
427	# Disable getty on syscons devices
428	sed -i "" -e '/^ttyv[0-8]/s/	on/	off/' ${NANO_WORLDDIR}/etc/ttys
429
430	# Tell loader to use serial console early.
431	echo " -h" > ${NANO_WORLDDIR}/boot.config
432)
433
434#######################################################################
435# Allow root login via ssh
436
437cust_allow_ssh_root () (
438	sed -i "" -e '/PermitRootLogin/s/.*/PermitRootLogin yes/' \
439	    ${NANO_WORLDDIR}/etc/ssh/sshd_config
440)
441
442#######################################################################
443# Install the stuff under ./Files
444
445cust_install_files () (
446	cd ${NANO_TOOLS}/Files
447	find . -print | grep -v /CVS | cpio -dumpv ${NANO_WORLDDIR}
448)
449
450#######################################################################
451# Convenience function:
452# 	Register $1 as customize function.
453
454customize_cmd () {
455	NANO_CUSTOMIZE="$NANO_CUSTOMIZE $1"
456}
457
458#######################################################################
459#
460# All set up to go...
461#
462#######################################################################
463
464usage () {
465	(
466	echo "Usage: $0 [-b/-k/-w] [-c config_file]"
467	echo "	-b	suppress builds (both kernel and world)"
468	echo "	-k	suppress buildkernel"
469	echo "	-w	suppress buildworld"
470	echo "	-c	specify config file"
471	) 1>&2
472	exit 2
473}
474
475#######################################################################
476# Parse arguments
477
478do_kernel=true
479do_world=true
480
481set +e
482args=`getopt bc:hkw $*`
483if [ $? -ne 0 ] ; then
484	usage
485	exit 2
486fi
487set -e
488
489set -- $args
490for i
491do
492	case "$i" 
493	in
494	-b)
495		shift;
496		do_world=false
497		do_kernel=false
498		;;
499	-k)
500		shift;
501		do_kernel=false
502		;;
503	-c)
504		. "$2"
505		shift;
506		shift;
507		;;
508	-h)
509		usage
510		;;
511	-w)
512		shift;
513		do_world=false
514		;;
515	--)
516		shift;
517		break;
518	esac
519done
520
521if [ $# -gt 0 ] ; then
522	echo "$0: Extraneous arguments supplied"
523	usage
524fi
525
526#######################################################################
527# Setup and Export Internal variables
528#
529if [ "x${NANO_OBJ}" = "x" ] ; then
530	MAKEOBJDIRPREFIX=/usr/obj/nanobsd.${NANO_NAME}/
531	NANO_OBJ=${MAKEOBJDIRPREFIX}
532else
533	MAKEOBJDIRPREFIX=${NANO_OBJ}
534fi
535
536NANO_WORLDDIR=${MAKEOBJDIRPREFIX}/_.w
537NANO_MAKE_CONF=${MAKEOBJDIRPREFIX}/make.conf
538
539if [ -d ${NANO_TOOLS} ] ; then
540	true
541elif [ -d ${NANO_SRC}/${NANO_TOOLS} ] ; then
542	NANO_TOOLS=${NANO_SRC}/${NANO_TOOLS}
543else
544	echo "NANO_TOOLS directory does not exist" 1>&2
545	exit 1
546fi
547
548export MAKEOBJDIRPREFIX
549
550export NANO_ARCH
551export NANO_CODESIZE
552export NANO_CONFSIZE
553export NANO_CUSTOMIZE
554export NANO_DATASIZE
555export NANO_DRIVE
556export NANO_HEADS
557export NANO_IMAGES
558export NANO_MAKE_CONF
559export NANO_MEDIASIZE
560export NANO_NAME
561export NANO_NEWFS
562export NANO_OBJ
563export NANO_PMAKE
564export NANO_SECTS
565export NANO_SRC
566export NANO_TOOLS
567export NANO_WORLDDIR
568
569#######################################################################
570# And then it is as simple as that...
571
572if $do_world ; then
573	clean_build
574	make_conf_build
575	build_world
576else
577	echo "## Skipping buildworld (as instructed)"
578fi
579
580if $do_kernel ; then
581	build_kernel
582else
583	echo "## Skipping buildkernel (as instructed)"
584fi
585
586clean_world
587make_conf_install
588install_world
589install_etc
590install_kernel
591
592run_customize
593setup_nanobsd
594prune_usr
595create_${NANO_ARCH}_diskimage
596last_orders
597
598echo "# NanoBSD image completed"
599