nanobsd.sh revision 215070
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 215070 2010-11-10 00:56:44Z imp $
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# Where cust_pkg() finds packages to install
49NANO_PACKAGE_DIR=${NANO_SRC}/${NANO_TOOLS}/Pkg
50NANO_PACKAGE_LIST="*"
51
52# Object tree directory
53# default is subdir of /usr/obj
54#NANO_OBJ=""
55
56# The directory to put the final images
57# default is ${NANO_OBJ}
58#NANO_DISKIMGDIR=""
59
60# Parallel Make
61NANO_PMAKE="make -j 3"
62
63# The default name for any image we create.
64NANO_IMGNAME="_.disk.full"
65
66# Options to put in make.conf during buildworld only
67CONF_BUILD=' '
68
69# Options to put in make.conf during installworld only
70CONF_INSTALL=' '
71
72# Options to put in make.conf during both build- & installworld.
73CONF_WORLD=' '
74
75# Kernel config file to use
76NANO_KERNEL=GENERIC
77
78# Kernel modules to build; default is none
79NANO_MODULES=
80
81# Customize commands.
82NANO_CUSTOMIZE=""
83
84# Late customize commands.
85NANO_LATE_CUSTOMIZE=""
86
87# Newfs paramters to use
88NANO_NEWFS="-b 4096 -f 512 -i 8192 -O1 -U"
89
90# The drive name of the media at runtime
91NANO_DRIVE=ad0
92
93# Target media size in 512 bytes sectors
94NANO_MEDIASIZE=1200000
95
96# Number of code images on media (1 or 2)
97NANO_IMAGES=2
98
99# 0 -> Leave second image all zeroes so it compresses better.
100# 1 -> Initialize second image with a copy of the first
101NANO_INIT_IMG2=1
102
103# Size of code file system in 512 bytes sectors
104# If zero, size will be as large as possible.
105NANO_CODESIZE=0
106
107# Size of configuration file system in 512 bytes sectors
108# Cannot be zero.
109NANO_CONFSIZE=2048
110
111# Size of data file system in 512 bytes sectors
112# If zero: no partition configured.
113# If negative: max size possible
114NANO_DATASIZE=0
115
116# Size of the /etc ramdisk in 512 bytes sectors
117NANO_RAM_ETCSIZE=10240
118
119# Size of the /tmp+/var ramdisk in 512 bytes sectors
120NANO_RAM_TMPVARSIZE=10240
121
122# Media geometry, only relevant if bios doesn't understand LBA.
123NANO_SECTS=63
124NANO_HEADS=16
125
126# boot0 flags/options and configuration
127NANO_BOOT0CFG="-o packet -s 1 -m 3"
128NANO_BOOTLOADER="boot/boot0sio"
129
130# boot2 flags/options
131# default force serial console
132NANO_BOOT2CFG="-h"
133
134# Backing type of md(4) device
135# Can be "file" or "swap"
136NANO_MD_BACKING="file"
137
138# Progress Print level
139PPLEVEL=3
140
141# Set NANO_LABEL to non-blank to form the basis for using /dev/ufs/label
142# in preference to /dev/${NANO_DRIVE}
143# Root partition will be ${NANO_LABEL}s{1,2}
144# /cfg partition will be ${NANO_LABEL}s3
145# /data partition will be ${NANO_LABEL}s4
146NANO_LABEL=""
147
148#######################################################################
149# Architecture to build.  Corresponds to TARGET_ARCH in a buildworld.
150# Unfortunately, there's no way to set TARGET at this time, and it
151# conflates the two, so architectures where TARGET != TARGET_ARCH do
152# not work.  This defaults to the arch of the current machine.
153
154NANO_ARCH=`uname -p`
155
156# Directory to populate /cfg from
157NANO_CFGDIR=""
158
159# Directory to populate /data from
160NANO_DATADIR=""
161
162#######################################################################
163#
164# The functions which do the real work.
165# Can be overridden from the config file(s)
166#
167#######################################################################
168
169clean_build ( ) (
170	pprint 2 "Clean and create object directory (${MAKEOBJDIRPREFIX})"
171
172	if ! rm -rf ${MAKEOBJDIRPREFIX} > /dev/null 2>&1 ; then
173		chflags -R noschg ${MAKEOBJDIRPREFIX}
174		rm -r ${MAKEOBJDIRPREFIX}
175	fi
176	mkdir -p ${MAKEOBJDIRPREFIX}
177	printenv > ${MAKEOBJDIRPREFIX}/_.env
178)
179
180make_conf_build ( ) (
181	pprint 2 "Construct build make.conf ($NANO_MAKE_CONF_BUILD)"
182
183	echo "${CONF_WORLD}" > ${NANO_MAKE_CONF_BUILD}
184	echo "${CONF_BUILD}" >> ${NANO_MAKE_CONF_BUILD}
185)
186
187build_world ( ) (
188	pprint 2 "run buildworld"
189	pprint 3 "log: ${MAKEOBJDIRPREFIX}/_.bw"
190
191	cd ${NANO_SRC}
192	env TARGET_ARCH=${NANO_ARCH} ${NANO_PMAKE} \
193		__MAKE_CONF=${NANO_MAKE_CONF_BUILD} buildworld \
194		> ${MAKEOBJDIRPREFIX}/_.bw 2>&1
195)
196
197build_kernel ( ) (
198	pprint 2 "build kernel ($NANO_KERNEL)"
199	pprint 3 "log: ${MAKEOBJDIRPREFIX}/_.bk"
200
201	(
202	if [ -f ${NANO_KERNEL} ] ; then
203		kernconfdir=$(realpath $(dirname ${NANO_KERNEL}))
204		kernconf=$(basename ${NANO_KERNEL})
205	else
206		kernconf=${NANO_KERNEL}
207	fi
208
209	cd ${NANO_SRC};
210	# unset these just in case to avoid compiler complaints
211	# when cross-building
212	unset TARGET_CPUTYPE
213	unset TARGET_BIG_ENDIAN
214	# Note: We intentionally build all modules, not only the ones in
215	# NANO_MODULES so the built world can be reused by multiple images.
216	env TARGET_ARCH=${NANO_ARCH} ${NANO_PMAKE} buildkernel \
217		__MAKE_CONF=${NANO_MAKE_CONF_BUILD} \
218		${kernconfdir:+"KERNCONFDIR="}${kernconfdir} \
219		KERNCONF=${kernconf}
220	) > ${MAKEOBJDIRPREFIX}/_.bk 2>&1
221)
222
223clean_world ( ) (
224	if [ "${NANO_OBJ}" != "${MAKEOBJDIRPREFIX}" ]; then
225		pprint 2 "Clean and create object directory (${NANO_OBJ})"
226		if ! rm -rf ${NANO_OBJ} > /dev/null 2>&1 ; then
227			chflags -R noschg ${NANO_OBJ}
228			rm -r ${NANO_OBJ}
229		fi
230		mkdir -p ${NANO_OBJ} ${NANO_WORLDDIR}
231		printenv > ${NANO_OBJ}/_.env
232	else
233		pprint 2 "Clean and create world directory (${NANO_WORLDDIR})"
234		if ! rm -rf ${NANO_WORLDDIR}/ > /dev/null 2>&1 ; then
235			chflags -R noschg ${NANO_WORLDDIR}
236			rm -rf ${NANO_WORLDDIR}
237		fi
238		mkdir -p ${NANO_WORLDDIR}
239	fi
240)
241
242make_conf_install ( ) (
243	pprint 2 "Construct install make.conf ($NANO_MAKE_CONF_INSTALL)"
244
245	echo "${CONF_WORLD}" > ${NANO_MAKE_CONF_INSTALL}
246	echo "${CONF_INSTALL}" >> ${NANO_MAKE_CONF_INSTALL}
247)
248
249install_world ( ) (
250	pprint 2 "installworld"
251	pprint 3 "log: ${NANO_OBJ}/_.iw"
252
253	cd ${NANO_SRC}
254	env TARGET_ARCH=${NANO_ARCH} \
255	${NANO_PMAKE} __MAKE_CONF=${NANO_MAKE_CONF_INSTALL} installworld \
256		DESTDIR=${NANO_WORLDDIR} \
257		> ${NANO_OBJ}/_.iw 2>&1
258	chflags -R noschg ${NANO_WORLDDIR}
259)
260
261install_etc ( ) (
262
263	pprint 2 "install /etc"
264	pprint 3 "log: ${NANO_OBJ}/_.etc"
265
266	cd ${NANO_SRC}
267	env TARGET_ARCH=${NANO_ARCH} \
268	${NANO_PMAKE} __MAKE_CONF=${NANO_MAKE_CONF_INSTALL} distribution \
269		DESTDIR=${NANO_WORLDDIR} \
270		> ${NANO_OBJ}/_.etc 2>&1
271	# make.conf doesn't get created by default, but some ports need it
272	# so they can spam it.
273	cp /dev/null ${NANO_WORLDDIR}/etc/make.conf
274)
275
276install_kernel ( ) (
277	pprint 2 "install kernel ($NANO_KERNEL)"
278	pprint 3 "log: ${NANO_OBJ}/_.ik"
279
280	(
281	if [ -f ${NANO_KERNEL} ] ; then
282		kernconfdir=$(realpath $(dirname ${NANO_KERNEL}))
283		kernconf=$(basename ${NANO_KERNEL})
284	else
285		kernconf=${NANO_KERNEL}
286	fi
287
288	cd ${NANO_SRC}
289	env TARGET_ARCH=${NANO_ARCH} ${NANO_PMAKE} installkernel \
290		DESTDIR=${NANO_WORLDDIR} \
291		__MAKE_CONF=${NANO_MAKE_CONF_INSTALL} \
292		${kernconfdir:+"KERNCONFDIR="}${kernconfdir} \
293		KERNCONF=${kernconf} \
294		MODULES_OVERRIDE="${NANO_MODULES}"
295	) > ${NANO_OBJ}/_.ik 2>&1
296)
297
298run_customize() (
299
300	pprint 2 "run customize scripts"
301	for c in $NANO_CUSTOMIZE
302	do
303		pprint 2 "customize \"$c\""
304		pprint 3 "log: ${NANO_OBJ}/_.cust.$c"
305		pprint 4 "`type $c`"
306		( set -x ; $c ) > ${NANO_OBJ}/_.cust.$c 2>&1
307	done
308)
309
310run_late_customize() (
311
312	pprint 2 "run late customize scripts"
313	for c in $NANO_LATE_CUSTOMIZE
314	do
315		pprint 2 "late customize \"$c\""
316		pprint 3 "log: ${NANO_OBJ}/_.late_cust.$c"
317		pprint 4 "`type $c`"
318		( set -x ; $c ) > ${NANO_OBJ}/_.late_cust.$c 2>&1
319	done
320)
321
322setup_nanobsd ( ) (
323	pprint 2 "configure nanobsd setup"
324	pprint 3 "log: ${NANO_OBJ}/_.dl"
325
326	(
327	cd ${NANO_WORLDDIR}
328
329	# Move /usr/local/etc to /etc/local so that the /cfg stuff
330	# can stomp on it.  Otherwise packages like ipsec-tools which
331	# have hardcoded paths under ${prefix}/etc are not tweakable.
332	if [ -d usr/local/etc ] ; then
333		(
334		mkdir -p etc/local
335		cd usr/local/etc
336		find . -print | cpio -dumpl ../../../etc/local
337		cd ..
338		rm -rf etc
339		ln -s ../../etc/local etc
340		)
341	fi
342
343	for d in var etc
344	do
345		# link /$d under /conf
346		# we use hard links so we have them both places.
347		# the files in /$d will be hidden by the mount.
348		# XXX: configure /$d ramdisk size
349		mkdir -p conf/base/$d conf/default/$d
350		find $d -print | cpio -dumpl conf/base/
351	done
352
353	echo "$NANO_RAM_ETCSIZE" > conf/base/etc/md_size
354	echo "$NANO_RAM_TMPVARSIZE" > conf/base/var/md_size
355
356	# pick up config files from the special partition
357	echo "mount -o ro /dev/${NANO_DRIVE}s3" > conf/default/etc/remount
358
359	# Put /tmp on the /var ramdisk (could be symlink already)
360	rmdir tmp || true
361	rm tmp || true
362	ln -s var/tmp tmp
363
364	) > ${NANO_OBJ}/_.dl 2>&1
365)
366
367setup_nanobsd_etc ( ) (
368	pprint 2 "configure nanobsd /etc"
369
370	(
371	cd ${NANO_WORLDDIR}
372
373	# create diskless marker file
374	touch etc/diskless
375
376	# Make root filesystem R/O by default
377	echo "root_rw_mount=NO" >> etc/defaults/rc.conf
378
379	# save config file for scripts
380	echo "NANO_DRIVE=${NANO_DRIVE}" > etc/nanobsd.conf
381
382	echo "/dev/${NANO_DRIVE}s1a / ufs ro 1 1" > etc/fstab
383	echo "/dev/${NANO_DRIVE}s3 /cfg ufs rw,noauto 2 2" >> etc/fstab
384	mkdir -p cfg
385	)
386)
387
388prune_usr() (
389
390	# Remove all empty directories in /usr 
391	find ${NANO_WORLDDIR}/usr -type d -depth -print |
392		while read d
393		do
394			rmdir $d > /dev/null 2>&1 || true 
395		done
396)
397
398newfs_part ( ) (
399	local dev mnt lbl
400	dev=$1
401	mnt=$2
402	lbl=$3
403	echo newfs ${NANO_NEWFS} ${NANO_LABEL:+-L${NANO_LABEL}${lbl}} ${dev}
404	newfs ${NANO_NEWFS} ${NANO_LABEL:+-L${NANO_LABEL}${lbl}} ${dev}
405	mount ${dev} ${mnt}
406)
407
408populate_slice ( ) (
409	local dev dir mnt lbl
410	dev=$1
411	dir=$2
412	mnt=$3
413	lbl=$4
414	test -z $2 && dir=/var/empty
415	test -d $dir || dir=/var/empty
416	echo "Creating ${dev} with ${dir} (mounting on ${mnt})"
417	newfs_part $dev $mnt $lbl
418	cd ${dir}
419	find . -print | grep -Ev '/(CVS|\.svn)' | cpio -dumpv ${mnt}
420	df -i ${mnt}
421	umount ${mnt}
422)
423
424populate_cfg_slice ( ) (
425	populate_slice "$1" "$2" "$3" "$4"
426)
427
428populate_data_slice ( ) (
429	populate_slice "$1" "$2" "$3" "$4"
430)
431
432create_i386_diskimage ( ) (
433	pprint 2 "build diskimage"
434	pprint 3 "log: ${NANO_OBJ}/_.di"
435
436	(
437	echo $NANO_MEDIASIZE $NANO_IMAGES \
438		$NANO_SECTS $NANO_HEADS \
439		$NANO_CODESIZE $NANO_CONFSIZE $NANO_DATASIZE |
440	awk '
441	{
442		printf "# %s\n", $0
443
444		# size of cylinder in sectors
445		cs = $3 * $4
446
447		# number of full cylinders on media
448		cyl = int ($1 / cs)
449
450		# output fdisk geometry spec, truncate cyls to 1023
451		if (cyl <= 1023)
452			print "g c" cyl " h" $4 " s" $3
453		else
454			print "g c" 1023 " h" $4 " s" $3
455
456		if ($7 > 0) { 
457			# size of data partition in full cylinders
458			dsl = int (($7 + cs - 1) / cs)
459		} else {
460			dsl = 0;
461		}
462
463		# size of config partition in full cylinders
464		csl = int (($6 + cs - 1) / cs)
465
466		if ($5 == 0) {
467			# size of image partition(s) in full cylinders
468			isl = int ((cyl - dsl - csl) / $2)
469		} else {
470			isl = int (($5 + cs - 1) / cs)
471		}
472
473		# First image partition start at second track
474		print "p 1 165 " $3, isl * cs - $3
475		c = isl * cs;
476
477		# Second image partition (if any) also starts offset one 
478		# track to keep them identical.
479		if ($2 > 1) {
480			print "p 2 165 " $3 + c, isl * cs - $3
481			c += isl * cs;
482		}
483
484		# Config partition starts at cylinder boundary.
485		print "p 3 165 " c, csl * cs
486		c += csl * cs
487
488		# Data partition (if any) starts at cylinder boundary.
489		if ($7 > 0) {
490			print "p 4 165 " c, dsl * cs
491		} else if ($7 < 0 && $1 > c) {
492			print "p 4 165 " c, $1 - c
493		} else if ($1 < c) {
494			print "Disk space overcommitted by", \
495			    c - $1, "sectors" > "/dev/stderr"
496			exit 2
497		}
498
499		# Force slice 1 to be marked active. This is necessary
500		# for booting the image from a USB device to work.
501		print "a 1"
502	}
503	' > ${NANO_OBJ}/_.fdisk
504
505	IMG=${NANO_DISKIMGDIR}/${NANO_IMGNAME}
506	MNT=${NANO_OBJ}/_.mnt
507	mkdir -p ${MNT}
508
509	if [ "${NANO_MD_BACKING}" = "swap" ] ; then
510		MD=`mdconfig -a -t swap -s ${NANO_MEDIASIZE} -x ${NANO_SECTS} \
511			-y ${NANO_HEADS}`
512	else
513		echo "Creating md backing file..."
514		dd if=/dev/zero of=${IMG} bs=${NANO_SECTS}b \
515			count=`expr ${NANO_MEDIASIZE} / ${NANO_SECTS}`
516		MD=`mdconfig -a -t vnode -f ${IMG} -x ${NANO_SECTS} \
517			-y ${NANO_HEADS}`
518	fi
519
520	trap "echo 'Running exit trap code' ; df -i ${MNT} ; umount ${MNT} || true ; mdconfig -d -u $MD" 1 2 15 EXIT
521
522	fdisk -i -f ${NANO_OBJ}/_.fdisk ${MD}
523	fdisk ${MD}
524	# XXX: params
525	# XXX: pick up cached boot* files, they may not be in image anymore.
526	boot0cfg -B -b ${NANO_WORLDDIR}/${NANO_BOOTLOADER} ${NANO_BOOT0CFG} ${MD}
527	bsdlabel -w -B -b ${NANO_WORLDDIR}/boot/boot ${MD}s1
528	bsdlabel ${MD}s1
529
530	# Create first image
531	populate_slice /dev/${MD}s1a ${NANO_WORLDDIR} ${MNT} "s1a"
532	mount /dev/${MD}s1a ${MNT}
533	echo "Generating mtree..."
534	( cd ${MNT} && mtree -c ) > ${NANO_OBJ}/_.mtree
535	( cd ${MNT} && du -k ) > ${NANO_OBJ}/_.du
536	umount ${MNT}
537
538	if [ $NANO_IMAGES -gt 1 -a $NANO_INIT_IMG2 -gt 0 ] ; then
539		# Duplicate to second image (if present)
540		echo "Duplicating to second image..."
541		dd if=/dev/${MD}s1 of=/dev/${MD}s2 bs=64k
542		mount /dev/${MD}s2a ${MNT}
543		for f in ${MNT}/etc/fstab ${MNT}/conf/base/etc/fstab
544		do
545			sed -i "" "s=${NANO_DRIVE}s1=${NANO_DRIVE}s2=g" $f
546		done
547		umount ${MNT}
548		# Override the label from the first partition so we
549		# don't confuse glabel with duplicates.
550		if [ ! -z ${NANO_LABEL} ]; then
551			tunefs -L ${NANO_LABEL}"s2a" /dev/${MD}s2a
552		fi
553	fi
554	
555	# Create Config slice
556	populate_cfg_slice /dev/${MD}s3 "${NANO_CFGDIR}" ${MNT} "s3"
557
558	# Create Data slice, if any.
559	if [ $NANO_DATASIZE -ne 0 ] ; then
560		populate_data_slice /dev/${MD}s4 "${NANO_DATADIR}" ${MNT} "s4"
561	fi
562
563	if [ "${NANO_MD_BACKING}" = "swap" ] ; then
564		echo "Writing out ${NANO_IMGNAME}..."
565		dd if=/dev/${MD} of=${IMG} bs=64k
566	fi
567
568	echo "Writing out _.disk.image..."
569	dd if=/dev/${MD}s1 of=${NANO_DISKIMGDIR}/_.disk.image bs=64k
570	mdconfig -d -u $MD
571
572	trap - 1 2 15 EXIT
573
574	) > ${NANO_OBJ}/_.di 2>&1
575)
576
577# i386 and amd64 are identical for disk images
578create_amd64_diskimage ( ) (
579	create_i386_diskimage
580)
581
582last_orders () (
583	# Redefine this function with any last orders you may have
584	# after the build completed, for instance to copy the finished
585	# image to a more convenient place:
586	# cp ${NANO_DISKIMGDIR}/_.disk.image /home/ftp/pub/nanobsd.disk
587)
588
589#######################################################################
590#
591# Optional convenience functions.
592#
593#######################################################################
594
595#######################################################################
596# Common Flash device geometries
597#
598
599FlashDevice () {
600	if [ -d ${NANO_TOOLS} ] ; then
601		. ${NANO_TOOLS}/FlashDevice.sub
602	else
603		. ${NANO_SRC}/${NANO_TOOLS}/FlashDevice.sub
604	fi
605	sub_FlashDevice $1 $2
606}
607
608#######################################################################
609# USB device geometries
610#
611# Usage:
612#	UsbDevice Generic 1000	# a generic flash key sold as having 1GB
613#
614# This function will set NANO_MEDIASIZE, NANO_HEADS and NANO_SECTS for you.
615#
616# Note that the capacity of a flash key is usually advertised in MB or
617# GB, *not* MiB/GiB. As such, the precise number of cylinders available
618# for C/H/S geometry may vary depending on the actual flash geometry.
619#
620# The following generic device layouts are understood:
621#  generic           An alias for generic-hdd.
622#  generic-hdd       255H 63S/T xxxxC with no MBR restrictions.
623#  generic-fdd       64H 32S/T xxxxC with no MBR restrictions.
624#
625# The generic-hdd device is preferred for flash devices larger than 1GB.
626#
627
628UsbDevice () {
629	a1=`echo $1 | tr '[:upper:]' '[:lower:]'`
630	case $a1 in
631	generic-fdd)
632		NANO_HEADS=64
633		NANO_SECTS=32
634		NANO_MEDIASIZE=$(( $2 * 1000 * 1000 / 512 ))
635		;;
636	generic|generic-hdd)
637		NANO_HEADS=255
638		NANO_SECTS=63
639		NANO_MEDIASIZE=$(( $2 * 1000 * 1000 / 512 ))
640		;;
641	*)
642		echo "Unknown USB flash device"
643		exit 2
644		;;
645	esac
646}
647
648#######################################################################
649# Setup serial console
650
651cust_comconsole () (
652	# Enable getty on console
653	sed -i "" -e /tty[du]0/s/off/on/ ${NANO_WORLDDIR}/etc/ttys
654
655	# Disable getty on syscons devices
656	sed -i "" -e '/^ttyv[0-8]/s/	on/	off/' ${NANO_WORLDDIR}/etc/ttys
657
658	# Tell loader to use serial console early.
659	echo " -h" > ${NANO_WORLDDIR}/boot.config
660)
661
662#######################################################################
663# Allow root login via ssh
664
665cust_allow_ssh_root () (
666	sed -i "" -e '/PermitRootLogin/s/.*/PermitRootLogin yes/' \
667	    ${NANO_WORLDDIR}/etc/ssh/sshd_config
668)
669
670#######################################################################
671# Install the stuff under ./Files
672
673cust_install_files () (
674	cd ${NANO_TOOLS}/Files
675	find . -print | grep -Ev '/(CVS|\.svn)' | cpio -dumpv ${NANO_WORLDDIR}
676)
677
678#######################################################################
679# Install packages from ${NANO_PACKAGE_DIR}
680
681cust_pkg () (
682
683	# Copy packages into chroot
684	mkdir -p ${NANO_WORLDDIR}/Pkg
685	(
686		cd ${NANO_PACKAGE_DIR}
687		find ${NANO_PACKAGE_LIST} -print |
688		    cpio -dumpv ${NANO_WORLDDIR}/Pkg
689	)
690
691	# Count & report how many we have to install
692	todo=`ls ${NANO_WORLDDIR}/Pkg | wc -l`
693	echo "=== TODO: $todo"
694	ls ${NANO_WORLDDIR}/Pkg
695	echo "==="
696	while true
697	do
698		# Record how many we have now
699		have=`ls ${NANO_WORLDDIR}/var/db/pkg | wc -l`
700
701		# Attempt to install more packages
702		# ...but no more than 200 at a time due to pkg_add's internal
703		# limitations.
704		chroot ${NANO_WORLDDIR} sh -c \
705			'ls Pkg/*tbz | xargs -n 200 pkg_add -F' || true
706
707		# See what that got us
708		now=`ls ${NANO_WORLDDIR}/var/db/pkg | wc -l`
709		echo "=== NOW $now"
710		ls ${NANO_WORLDDIR}/var/db/pkg
711		echo "==="
712
713
714		if [ $now -eq $todo ] ; then
715			echo "DONE $now packages"
716			break
717		elif [ $now -eq $have ] ; then
718			echo "FAILED: Nothing happened on this pass"
719			exit 2
720		fi
721	done
722	rm -rf ${NANO_WORLDDIR}/Pkg
723)
724
725#######################################################################
726# Convenience function:
727# 	Register all args as customize function.
728
729customize_cmd () {
730	NANO_CUSTOMIZE="$NANO_CUSTOMIZE $*"
731}
732
733#######################################################################
734# Convenience function:
735# 	Register all args as late customize function to run just before
736#	image creation.
737
738late_customize_cmd () {
739	NANO_LATE_CUSTOMIZE="$NANO_LATE_CUSTOMIZE $*"
740}
741
742#######################################################################
743#
744# All set up to go...
745#
746#######################################################################
747
748# Progress Print
749#	Print $2 at level $1.
750pprint() {
751    if [ "$1" -le $PPLEVEL ]; then
752	runtime=$(( `date +%s` - $NANO_STARTTIME ))
753	printf "%s %.${1}s %s\n" "`date -u -r $runtime +%H:%M:%S`" "#####" "$2" 1>&3
754    fi
755}
756
757usage () {
758	(
759	echo "Usage: $0 [-biknqvw] [-c config_file]"
760	echo "	-b	suppress builds (both kernel and world)"
761	echo "	-i	suppress disk image build"
762	echo "	-k	suppress buildkernel"
763	echo "	-n	add -DNO_CLEAN to buildworld, buildkernel, etc"
764	echo "	-q	make output more quiet"
765	echo "	-v	make output more verbose"
766	echo "	-w	suppress buildworld"
767	echo "	-c	specify config file"
768	) 1>&2
769	exit 2
770}
771
772#######################################################################
773# Parse arguments
774
775do_clean=true
776do_kernel=true
777do_world=true
778do_image=true
779
780set +e
781args=`getopt bc:hiknqvw $*`
782if [ $? -ne 0 ] ; then
783	usage
784	exit 2
785fi
786set -e
787
788set -- $args
789for i
790do
791	case "$i" 
792	in
793	-b)
794		do_world=false
795		do_kernel=false
796		shift
797		;;
798	-k)
799		do_kernel=false
800		shift
801		;;
802	-c)
803		. "$2"
804		shift
805		shift
806		;;
807	-h)
808		usage
809		;;
810	-i)
811		do_image=false
812		shift
813		;;
814	-n)
815		do_clean=false
816		shift
817		;;
818	-q)
819		PPLEVEL=$(($PPLEVEL - 1))
820		shift
821		;;
822	-v)
823		PPLEVEL=$(($PPLEVEL + 1))
824		shift
825		;;
826	-w)
827		do_world=false
828		shift
829		;;
830	--)
831		shift
832		break
833	esac
834done
835
836if [ $# -gt 0 ] ; then
837	echo "$0: Extraneous arguments supplied"
838	usage
839fi
840
841#######################################################################
842# Setup and Export Internal variables
843#
844test -n "${NANO_OBJ}" || NANO_OBJ=/usr/obj/nanobsd.${NANO_NAME}/
845test -n "${MAKEOBJDIRPREFIX}" || MAKEOBJDIRPREFIX=${NANO_OBJ}
846test -n "${NANO_DISKIMGDIR}" || NANO_DISKIMGDIR=${NANO_OBJ}
847
848NANO_WORLDDIR=${NANO_OBJ}/_.w
849NANO_MAKE_CONF_BUILD=${MAKEOBJDIRPREFIX}/make.conf.build
850NANO_MAKE_CONF_INSTALL=${NANO_OBJ}/make.conf.install
851
852if [ -d ${NANO_TOOLS} ] ; then
853	true
854elif [ -d ${NANO_SRC}/${NANO_TOOLS} ] ; then
855	NANO_TOOLS=${NANO_SRC}/${NANO_TOOLS}
856else
857	echo "NANO_TOOLS directory does not exist" 1>&2
858	exit 1
859fi
860
861if $do_clean ; then
862	true
863else
864	NANO_PMAKE="${NANO_PMAKE} -DNO_CLEAN"
865fi
866
867# Override user's NANO_DRIVE if they specified a NANO_LABEL
868if [ ! -z "${NANO_LABEL}" ]; then
869	NANO_DRIVE=ufs/${NANO_LABEL}
870fi
871
872export MAKEOBJDIRPREFIX
873
874export NANO_ARCH
875export NANO_CODESIZE
876export NANO_CONFSIZE
877export NANO_CUSTOMIZE
878export NANO_DATASIZE
879export NANO_DRIVE
880export NANO_HEADS
881export NANO_IMAGES
882export NANO_IMGNAME
883export NANO_MAKE_CONF_BUILD
884export NANO_MAKE_CONF_INSTALL
885export NANO_MEDIASIZE
886export NANO_NAME
887export NANO_NEWFS
888export NANO_OBJ
889export NANO_PMAKE
890export NANO_SECTS
891export NANO_SRC
892export NANO_TOOLS
893export NANO_WORLDDIR
894export NANO_BOOT0CFG
895export NANO_BOOTLOADER
896export NANO_LABEL
897
898#######################################################################
899# And then it is as simple as that...
900
901# File descriptor 3 is used for logging output, see pprint
902exec 3>&1
903
904NANO_STARTTIME=`date +%s`
905pprint 1 "NanoBSD image ${NANO_NAME} build starting"
906
907if $do_world ; then
908	if $do_clean ; then
909		clean_build
910	else
911		pprint 2 "Using existing build tree (as instructed)"
912	fi
913	make_conf_build
914	build_world
915else
916	pprint 2 "Skipping buildworld (as instructed)"
917fi
918
919if $do_kernel ; then
920	if ! $do_world ; then
921		make_conf_build
922	fi
923	build_kernel
924else
925	pprint 2 "Skipping buildkernel (as instructed)"
926fi
927
928clean_world
929make_conf_install
930install_world
931install_etc
932setup_nanobsd_etc
933install_kernel
934
935run_customize
936setup_nanobsd
937prune_usr
938run_late_customize
939if $do_image ; then
940	create_${NANO_ARCH}_diskimage
941else
942	pprint 2 "Skipping image build (as instructed)"
943fi
944last_orders
945
946pprint 1 "NanoBSD image ${NANO_NAME} completed"
947