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