picobsd revision 194635
1#!/bin/sh -
2#
3# $FreeBSD: head/release/picobsd/build/picobsd 194635 2009-06-22 16:06:38Z luigi $
4# This file requires sysutils/makefs to run
5#
6# The PicoBSD build script. Invoked as
7#
8#	picobsd [options] image_type [site_name]
9#
10# Where image_type is a directory with the picobsd config info,
11# and ${image_type}/floppy.tree.${site_name} contains
12# optional site-specific configuration.
13#
14# For Options, see the bottom of the file where the processing is
15# done. The picobsd(8) manpage might be of some help, but code and docs
16# tend to lose sync over time.
17#
18# This script depends on the following files:
19#
20# in ${PICO_TREE} :
21#   Makefile.conf	Makefile used to build the kernel
22#   config		shell variables, sourced here.
23#   mfs.mtree		mtree config file
24#   floppy.tree/	files which go on the floppy
25#   mfs_tree/		files which go onto the mfs
26#
27# in ${MY_TREE} :
28#   PICOBSD		kernel config file
29#   config		shell variables, sourced here.
30#   crunch.conf		crunchgen configuration
31#   mfs.mtree		overrides ${PICO_TREE}/mfs.mtree
32#   floppy.tree.exclude	files from floppy.tree/ which we do not need here.
33#   floppy.tree/	local additions to ${PICO_TREE}/mfs_free
34#   floppy.tree.${site}/ same as above, site specific.
35#   mfs_tree/		local additions to the mfs_free
36#   buildtree.mk	optional Makefile to build an extension for floppy tree
37#			(generated in buildtree/ )
38
39#
40#--- The main entry point is at the end.
41#
42
43# There are two initialization functions:
44#
45# + set_defaults
46#   is run on entry to the script, and is used to set default values
47#   for all variables that do not depend on image type and source tree.
48#
49# + set_build_parameters
50#   is run after command line parsing
51#
52# VARIABLE NAMES:
53# + variables that control operation (e.g. verbosity) and are generally
54#   set from the command line have o_ ("option") as a name prefix
55#
56# + variables that contain pathnames and values that should not change
57#   have c_ ("constant") as a name prefix
58#
59# + variables exported to Makefiles and subshells are CAPITAL
60#
61# + variables local to the script are lowercase, possibly with
62#   an l_ ("local") prefix.
63#
64# There are unfortunately exceptions:
65# name, l_usrtree, l_objtree
66
67# SRC points to your FreeBSD source tree.
68# l_usrtree points to the /usr subdir for the source tree.
69#     Normally /usr or ${SRC}/../usr
70# l_objtree points to the obj tree. Normally ${l_usrtree}/obj-pico
71# c_label is either bsdlabel or disklabel
72# PICO_TREE is where standard picobsd stuff resides.
73#     Normally ${SRC}/release/picobsd
74# You can set SRC with --src <directory>
75# It is not recommended to override the other variables.
76
77# MY_TREE (set later) is where this floppy type resides.
78# BUILDDIR is the build directory
79
80# log something on stdout if verbose.
81o_verbose=0	# this needs to be here!
82log() {	#	message
83    local foo
84    [ ${o_verbose} -gt 0 ] && printf "\n*** %s\n" "$*"
85    [ ${o_verbose}  -gt 1 ] && read -p "=== Press enter to continue" foo
86    return 0
87}
88
89# unconditionally log and wait for input
90logverbose() {	# message
91    local foo
92    printf "\n*** %s\n" "$*"
93    read -p "=== Press enter to continue" foo
94    return 0
95}
96
97# set some default values for variables.
98# needs to be done as the first thing in the script.
99
100set_defaults() {	# no arguments
101    # EDITOR is the editor you use
102    # fd_size  floppy size in KB (default to 1440). You can use 1480,
103    #	1720, 2880, etc. but beware that only 1440 and 1480 will boot
104    #	from 1.44M floppy drives (1480 will not work on vmware).
105    EDITOR=${EDITOR:-vi}
106    fd_size=${fd_size:-1440}
107
108    o_use_loader="yes"		# use /boot/loader
109	# You should not change it unless you are really short
110	# of space, and your kernel is small enough that the
111	# bootblocks manage to load it.
112
113    o_all_in_mfs="yes"		# put all files in mfs so you can boot
114				# and run the image via diskless boot.
115    o_clean=""			# set if you want to clean prev.builds.
116    o_interactive=""		# default is interactive
117    o_verbose=0			# verbose level, 0 is silent
118    o_tarv=""			# tar verbose flag, "" or "v"
119    o_init_src=""		# set to build libs and includes.
120    o_makeopts=${MAKEOPTS:--s}	# make options, be silent by default
121    o_no_devfs=			# default is use devfs.
122	# You should only set it when building 4.x images
123    o_do_modules=""		# do not build modules
124
125    SRC="/usr/src"		# default location for sources
126    c_startdir=`pwd`		# directory where we start
127				# used to lookup config and create BUILDDIR
128
129    # XXX 6.x/7.x have a single /boot/boot block, which is the concatenation
130    # of the old two. For the time being, we keep these, but this should
131    # be fixed at some point.
132
133    # blocks
134    c_boot1=/boot/boot1		# boot blocks (in case you want custom ones)
135    c_boot2=/boot/boot2
136
137    c_reply=${c_reply:-`mktemp "/tmp/reply.XXXXXXXXXX"`}
138    				# file where User replies will be put
139    c_mnt=`mktemp -d "/tmp/picobsd.XXXXXXXXXX"`
140    				# mountpoint used to build memory filesystems
141    c_fs=fs.PICOBSD		# filename used for the memory filesystem
142    c_img=picobsd.bin		# filename used for the picobsd image
143    c_iso=picobsd.iso		# filename used for the ISO image
144    generate_iso="NO"		# don't generate the iso image
145
146    # select the right disklabel program
147    case `uname -r` in
148	4.*)
149	    c_label="disklabel"
150	    ;;
151	*)
152	    c_label="bsdlabel"
153	    ;;
154    esac
155
156    set -e
157
158    trap fail 2
159    #trap fail 3
160    #trap fail 6
161    trap fail 15
162}
163
164# use the new build infrastructure to create libraries
165# and also to build a specific target
166create_includes_and_libraries2() { # opt_dir opt_target
167    local no
168    log "create_includes_and_libraries2() for ${SRC}"
169    if [ ${OSVERSION} -ge 600000 ] ; then
170	no="-DNO_CLEAN -DNO_PROFILE -DNO_GAMES -DNO_LIBC_R"
171    else
172	no="-DNOCLEAN -DNOPROFILE -DNOGAMES -DNOLIBC_R"
173    fi
174    MAKEOBJDIRPREFIX=${l_objtree}
175    export MAKEOBJDIRPREFIX
176    ( cd ${SRC};
177    # make -DNOCLEAN -DNOPROFILE -DNOGAMES -DNOLIBC_R -DPICOBSD buildworld
178    if [ -d "$1" ] ; then
179	cd $1 ; make $2	# specific target, e.g. ld-elf.so
180    else
181	make _+_= $no toolchain _includes _libraries
182    fi
183    )
184}
185
186# entry for 4.x and earlier trees
187create_includes_and_libraries() {
188    local e i
189
190    log "create_includes_and_libraries() for ${SRC}"
191    # Optionally creates include directory and libraries.
192    mkdir -p ${l_usrtree}/include	# the include directory...
193    mkdir -p ${l_usrtree}/share/misc	# a few things go here
194    mkdir -p ${l_usrtree}/lib		# libraries
195    mkdir -p ${l_usrtree}/sbin		# some binaries
196    # override variables for ownershiip and destinations
197    # BINOWN:BINGRP are also used for include files
198    (cd ${SRC}; \
199	BINOWN=`id -un` BINGRP=`id -gn` \
200	DESTDIR=${l_usrtree}/.. \
201	make -m ${SRC}/share/mk includes ) || fail $? includes
202    # Pick up the correct headers for libraries.
203    CFLAGS="-nostdinc -I${l_usrtree}/include" ; export CFLAGS
204
205    (cd ${SRC}
206	# $e is the invocation of make with correct environment
207	# XXX check the NO* options below, maybe system dependent.
208	e="MAKEOBJDIRPREFIX=${l_objtree}/picobsd/libraries \
209	    BINOWN=`id -un` BINGRP=`id -gn` \
210	    DESTDIR=${l_usrtree}/.. \
211	    make -m ${SRC}/share/mk \
212		-DNOHTML -DNOINFO -DNOMAN -DNOSHARE -DNOFSCHG "
213	log "do a 'make obj' in a few places."
214	# This is very version-specific... The following works for 5.0
215	for i in lib secure/lib gnu/lib \
216		gnu/usr.bin/perl usr.bin/lex usr.sbin/config ; do
217	    (cd ${i}; eval $e obj)
218	done
219	log "now make the static libraries"
220	eval $e -DNOPROFILE -DNOPIC libraries
221	(cd ${SRC}/usr.sbin/config
222	eval $e		# build binary
223	eval $e	install	# install it
224	)
225    ) || fail $? "libraries"
226    log "Libraries done"
227}
228
229# set_type <the_type> [the_site] looks in user or system directories
230# for the directory named as the first argument, reads the configuration
231# files and sets variables according to the config.
232# Also sets MY_TREE and BUILDDIR and SITE
233
234set_type() {	# the_type the_site
235    local a i
236
237    log "set_type() : Type '$1' site '$2'"
238    THETYPE=$1
239    SITE=$2
240    a=$1
241    name=""	# clear in case of errors
242    for i in ${c_startdir}/${a} ${PICO_TREE}/${a} ; do
243	log "set_type: checking $i"
244	[ -d $i -a -f $i/PICOBSD -a -f $i/crunch.conf ] || continue
245	set -- `cat $i/PICOBSD | \
246	    awk '/^#PicoBSD/ {print $2, $3, $4, $5, $6}'`
247	[ x"$1" != "x" ] || continue
248	MFS_SIZE=$1 ; init_name=$2
249	mfs_inodes=$3 ; fd_inodes=$4
250	name=`(cd $i ; pwd) `
251	name=`basename $name`
252	MY_TREE=$i
253	BUILDDIR=${c_startdir}/build_dir-${name}
254	log "Matching file $name in $i"
255	return ;
256    done
257    logverbose "Type $a NOT FOUND"
258}
259
260clean_tree() {
261    log "clean_tree()"
262    if [ -z "${name}" ] ; then
263	echo "---> Wrong floppy type"
264	exit 3
265    fi
266    rm -rf ${BUILDDIR}
267}
268
269# prepare a message to be printed in the dialog menus.
270set_msgs() {		# OK
271    log "set_msgs()"
272
273    MSG1="Type: ${THETYPE} name $name"
274
275    MSG="PicoBSD build -- Current parameters:\n\n\t1.  ${MSG1}\n\
276\t2.  MFS size: ${MFS_SIZE} kB\n\
277\t3.  Site-info: ${SITE}\n\t4.  Full-path: ${MY_TREE}\n"
278}
279
280# Main build procedure. Builds both the disk image and the ISO
281build_image() {
282    log "build_image() <${name}>"
283    [ -n "${name}" ] || fail $? bad_type
284    clear
285    set_msgs
286    printf "${MSG}---> We'll use the sources living in ${SRC}\n\n"
287
288    # read config variables from a global and then a type-specific file
289    # basically STAND_LINKS and MY_DEVS, but can also override other
290    # variables.
291    # 
292    . ${PICO_TREE}/build/config
293    [ -f "${MY_TREE}/config" ]		&& . ${MY_TREE}/config
294    [ -f "${o_additional_config}" ]	&& . ${o_additional_config}
295
296    # location of the object directory
297    PICO_OBJ=${l_objtree}/picobsd/${THETYPE}
298    log "PICO_OBJ is ${PICO_OBJ}"
299
300    if [ ${OSVERSION} -ge 500035 ] ; then
301	export MAKEOBJDIRPREFIX=${l_objtree}
302	eval "export BINMAKE=\"`cd ${SRC}; make -f Makefile -V BINMAKE`\""
303	eval export `cd ${SRC}; ${BINMAKE} -f Makefile.inc1 -V WMAKEENV`
304    fi
305    # create build directory and subtree
306    mkdir -p ${BUILDDIR}/crunch
307    # remove any old stuff
308    rm -f ${BUILDDIR}/kernel.gz ${BUILDDIR}/${c_fs}
309    # invoke commands to build a kernel
310    do_kernel
311    # fill a subdirectory with things that go into the floppy
312    # (mostly /etc and similar stuff)
313    populate_floppy_fs
314    # populate it and produce a file with the MFS image
315    populate_mfs_tree		# things which go into mfs
316    # create, mount and fill a filesystem with floppy image
317    fill_floppy_image # copies everything into the floppy
318}
319
320# Set build parameters interactively
321
322main_dialog() {
323  local ans i l
324
325  log "main_dialog()"
326  while true ; do
327    set_msgs
328    rm ${c_reply}
329    dialog --menu "PicoBSD build menu -- (29 sep 2001)" 19 70 12 \
330	N "--> READY, build it <---" \
331	T "${MSG1}" \
332	K "edit Kernel config file" \
333	E "Edit crunch.conf file" \
334	S "MFS Size: ${MFS_SIZE}kB" \
335	I "Init type: ${init_name}" \
336	F "Floppy size: ${fd_size}kB" \
337	M "MFS bytes per inode: ${mfs_inodes}" \
338	U "UFS bytes per inode: ${fd_inodes}" \
339	$ "Site-info: ${SITE}" \
340	Q "Quit" \
341	2> ${c_reply}
342    ans=`cat ${c_reply}`
343    rm ${c_reply}
344    case ${ans} in
345    T)
346	l=""
347	for i in ${c_startdir} ${c_startdir}/* ${PICO_TREE}/* ; do
348	    if [ -d $i -a -f $i/PICOBSD -a -f $i/crunch.conf ]; then
349		l="$l `basename $i` `basename $i`"
350	    fi
351	done
352	log $l
353	{ dialog --menu "Setup the type of configuration" 12 70 5 $l \
354		2> ${c_reply} && set_type "`cat ${c_reply}`" ${SITE} ; } || true
355	;;
356    I)
357	{ dialog --menu "Choose your init(8) program" \
358	10 70 2 init "Standard init (requires getty)" \
359	oinit "small init from TinyWare" 2> ${c_reply} \
360		&& init_name=`cat ${c_reply}` ; } || true
361	;;
362
363    K) ${EDITOR} ${MY_TREE}/PICOBSD ;;
364
365    E) ${EDITOR} ${MY_TREE}/crunch.conf ;;
366
367    S)
368	{ dialog --title "MFS Size setup" --inputbox \
369"MFS size depends on what you need to put on the MFS image. Typically \
370ranges between 820kB (for very small bridge/router images) to \
371as much as 2500kB kB for a densely packed image. \
372Keep in mind that this memory is \
373totally lost to other programs. Usually you want to keep \
374this as small as possible. " 10 70 2> ${c_reply} \
375	&& MFS_SIZE=`cat ${c_reply}` ; } || true
376	;;
377
378    \$)
379	{ dialog --title "Site info setup" --inputbox \
380	"Please enter the full path to the directory \
381	containing site-specific setup. \
382	This directory tree must contain files that replace \
383	standard ones in floppy.tree/ and mfs.tree/ . " \
384	10 70 2> ${c_reply} && SITE=`cat ${c_reply}` ; } || true
385	;;
386
387    F)
388	{ dialog --menu "Set floppy size" 15 70 4 \
389	    1440 "1.44MB" 1720 "1.72MB" 2880 "2.88MB" 4096 "4MB" \
390		 2> ${c_reply} && fd_size=`cat ${c_reply}` ; } || true
391	;;
392
393    M)
394	{ dialog --title "MFS bytes per inode:" --inputbox \
395	"Enter MFS bytes per inode (typically 4096..65536). \
396	A larger value means fewer inodes but more space on MFS" \
397	10 70 2> ${c_reply} && mfs_inodes=`cat ${c_reply}`  ; } || true
398	;;
399
400    U)
401	{ dialog --title "Floppy bytes per inode:" --inputbox \
402	"Enter floppy bytes per inode (typically 3072..65536). \
403	A larger value means fewer inodes but more space on the floppy." \
404	10 70 2> ${c_reply} && fd_inodes=`cat ${c_reply}` ; } || true
405	;;
406
407    N) break 2
408	;;
409
410    Q) exit 0 ;;
411
412    *) echo "Unknown option \"${ans}\". Try again."
413	sleep 2
414	clear
415	;;
416    esac
417  done
418}
419
420# Call the build procedure
421# Install image
422do_install() {
423    log "do_install()"
424
425    if [ "${o_interactive}" = "NO" ] ; then
426	echo "+++ Build completed +++"
427	cat .build.reply || true
428	return
429    fi
430    dialog --title "Build ${THETYPE} completed" --inputbox \
431"\nThe build process was completed successfuly.\n\
432`cat .build.reply` \n\n\
433Now we are going to install the image on the floppy.\n\
434Please insert a blank floppy in /dev/fd0.\\n
435WARNING: the contents of the floppy will be permanently erased!\n\
436\n\
437Your options:\n\
438	* ^C or [Cancel] to abort,\n\
439	* Enter to install ${c_img},\n\
440" 20 80 2> ${c_reply}
441    if [ "$?" = "0" ]; then
442	echo "Writing ${c_img}..."
443	dd if=${BUILDDIR}/${c_img} of=/dev/fd0.${fd_size}
444    else
445	echo "Ok, the image is in ${c_img}"
446    fi
447    echo "Done."
448}
449
450
451#-------------------------------------------------------------------
452
453# invoke the picobsd Makefile to compile the kernel.
454# if MODULES is set (value is irrelevant) the makefile will build modules.
455do_kernel() {		# OK
456    log "do_kernel() Preparing kernel \"$name\" in $MY_TREE"
457    (cd $MY_TREE; export name SRC BUILDDIR # used in this makefile ;
458	# export CONFIG
459	[ "${o_do_modules}" = "yes" ] && export MODULES=""
460	${BINMAKE} -v -f ${PICO_TREE}/build/Makefile.conf ) || \
461	fail $? missing_kernel
462}
463
464# Populate the variable part of the floppy filesystem. Must be done before
465# the MFS because its content might need to be copied there as well.
466#
467# This involves fetching files from three subtrees, in this order:
468#
469#  1. a standard one, from which type-specific files are excluded;
470#  2. a type-specific one;
471#  3. a site-specific one.
472#
473# Files are first copied to a local tree and then compressed.
474
475populate_floppy_fs() {		# OK
476    local dst excl srcdir
477
478    log "populate_floppy_fs()"
479    dst=${BUILDDIR}/floppy.tree
480    log "pwd=`pwd` Populating floppy filesystem..."
481
482    rm -rf ${dst} || true	# clean relics from old compilations.
483    mkdir ${dst}		# create a clean tree
484
485    # compute exclude list for generic tree
486    excl=${MY_TREE}/floppy.tree.exclude
487    if [ -f ${excl} ] ; then
488	log "Files excluded from generic tree: `echo;cat ${excl}`"
489	excl="--exclude-from ${excl}"
490    else
491	excl=""
492    fi
493    # copy from the floppy trees into the destination
494    for FLOPPY_TREE in ${PICO_TREE}/floppy.tree ${MY_TREE}/floppy.tree \
495		${MY_TREE}/floppy.tree.${SITE} ; do
496	if [ -d ${FLOPPY_TREE} ] ; then
497	    (cd ${FLOPPY_TREE} ; tar -cf - --exclude CVS \
498		    --exclude .svn ${excl} . ) | \
499		(cd ${dst} ; tar x${o_tarv}f - )
500	    log "Copied from ${FLOPPY_TREE}"
501	fi
502	excl="" # reset the exclude list.
503    done
504
505    # add local manipulation
506    if [ -f ${MY_TREE}/buildtree.mk ] ; then
507	log "building local floppy tree"
508	${BINMAKE} -C ${dst} -f ${MY_TREE}/buildtree.mk floppy.tree
509    fi
510 
511    # compress the files in etc/, just in case
512    # XXX this should be done in the makefile.
513    # gzip returns an error if it fails to compress some file
514    (cd $dst ; gzip -9 etc/*
515	    log "Compressed files in etc/ `echo; ls -l etc`"
516    ) || true
517}
518
519# Copy the specified files to the destination filesystem.
520# Each file is specified as a pair "src dst", dst is assumed to be
521# a directory (and created with mkdir -p) if it has a trailing /
522# Be careful to escape metacharacters.
523# You can use ${CROSS} to point to the root of the cross build
524# (remember that it might be incomplete)
525
526do_copyfiles() {	# rootdir varname
527	log Copy files to $1
528	local root=$1
529	local srcs dst
530	local CROSS=${_SHLIBDIRPREFIX}
531	eval set "\${${2}}"
532        srcs=""
533	for dst in $* ; do
534		[ -z "$srcs" ] && srcs=$dst && continue
535		eval srcs="$srcs"	# expand wildcard and vars
536		case x"$dst" in
537		*/ )	mkdir -p ${root}/${dst} ;;
538		# * )	mkdir -p `dirname ${root}/${dst}` ;;
539		esac
540		cp -p ${srcs} ${root}/${dst} || true
541		srcs=""
542        done
543}
544
545# do_links is a helper function to create links between programs
546# in stand/
547# This is done reading the names and destination from variable
548# links in a config file, in the format
549#	: dst names
550
551do_links() {	# rootdir varname
552	local root=$1
553	local l i dst
554	eval l="\${${2}}"
555        dst=""
556	log "Create links for ${l}"
557	(cd ${root}/stand
558	for i in $l ; do
559	    if [ "$dst" = ":" -o "$i" = ":" ] ; then
560		dst=$i
561	    elif [ -n "${dst}" ] ; then
562		ln -s ${dst} ${i}
563	    fi
564	done
565	)
566}
567
568# find_progs is a helper function to locate the named programs
569# or libraries in ${o_objdir} or ${_SHLIBDIRPREFIX},
570# and return the full pathnames.
571# Sets ${u_progs} to the list of programs, and ${u_libs}
572# to the list of shared libraries used.
573#
574# You can use it e.g. in a local configuration file by writing
575#
576#  do_copyfiles_user() {
577#	local dst=$1
578#	find_progs nvi sed less grep
579#	cp -p ${u_progs} ${dst}/bin
580#	cp -p ${u_libs} ${dst}/lib
581#	mkdir -p ${dst}/libexec
582#	find_progs ld-elf.so.1
583#	cp -p ${u_progs} ${dst}/libexec
584#  }
585
586find_progs() {	# programs
587	local i
588	u_progs="`find_progs_helper $*`"
589	local o=${o_objdir:-${_SHLIBDIRPREFIX}}
590	[ -z "${u_progs}" ] && return 1	# not found, error
591	i="`ldd ${u_progs} | grep -v '^/' | awk '{print $1}' | sort | uniq`"
592	u_libs="`find_progs_helper $i`"
593	return 0
594}
595
596find_progs_helper() {	# programs
597	local progs="$*"
598	local i o places names
599	local subdirs="bin sbin usr.bin usr.sbin libexec lib \
600		gnu/usr.bin gnu/lib \
601		secure/usr.bin secure/usr.sbin secure/libexec secure/lib"
602	names=""	# files to search
603	o=""
604	for i in $progs ; do
605		# plain programs come out verbatim
606		[ -f "$i" ] && echo $i && continue
607		names="${names} ${o} -name $i"
608		o="-o"
609	done
610	[ -z "${names}" ] && return 0
611	places=""				# places to search
612	o=${o_objdir:-${_SHLIBDIRPREFIX}/..}
613	for i in $subdirs ; do
614		[ -d "${o}/${i}" ] && places="${places} ${o}/${i}"
615	done
616	find ${places} -type f \( ${names} \)
617}
618
619# Populate the memory filesystem with binaries and non-variable
620# configuration files.
621# First do an mtree pass, then create directory links and device entries,
622# then run crunchgen etc. to build the binary and create links.
623# Then copy the specific/generic mfs_tree.
624# Finally, if required, make a copy of the floppy.tree onto /fd
625
626populate_mfs_tree() {
627    local i j a dst MFS_TREE
628
629    log "populate_mfs_tree()"
630    dst=${BUILDDIR}/mfs.tree
631    rm -rf ${dst} || true	# clean relics from old compilations.
632    mkdir ${dst}		# create a fresh tree
633
634    log "pwd=`pwd`, Populating MFS tree..."
635
636    # use type-specific mfs.mtree, default to generic one.
637    a=${MY_TREE}/mfs.mtree
638    [ -f ${a} ] || a=${PICO_TREE}/build/mfs.mtree
639    log "Running mtree using $a..."
640    mtree -deU -f $a -p ${dst} > /dev/null || fail $? mtree
641
642    # Create symlinks using relative pathnames, so it is possible
643    # to follow them also when building the image.
644    # Note that names in STAND_LINKS should not have a leading /
645    for i in ${STAND_LINKS}; do
646	j=`echo $i | sed -E 's:^[^/]+::;s:/[^/]+:../:g'`
647	ln -s ${j}stand ${dst}/$i
648    done
649    ln -s ../../dev/null ${dst}/var/run/log
650    ln -s ../../../etc/termcap ${dst}/usr/share/misc/termcap
651
652    ### now build the crunched binaries ###
653    (
654    cd ${BUILDDIR}/crunch
655    log "Making and installing crunch1 from `pwd` src ${SRC}..."
656    a=${BUILDDIR}/crunch1.conf
657    ( export BUILDDIR SRC MY_TREE PICO_OBJ ;
658	${BINMAKE} \
659		-v -f ${PICO_TREE}/build/Makefile.conf ${BUILDDIR}/crunch.mk )
660    log "Libs are ${LIBS} "
661    export SRC # used by crunch.mk
662    # export LIBS CFLAGS
663    log "Now make -f crunch.mk"
664    ${BINMAKE} ${o_makeopts} -f ${BUILDDIR}/crunch.mk
665    strip --remove-section=.note --remove-section=.comment crunch1
666    mv crunch1 ${dst}/stand/crunch
667    chmod 555 ${dst}/stand/crunch
668    log "Making links for binaries..."
669    for i in `crunchgen -l $a` ; do
670	ln ${dst}/stand/crunch ${dst}/stand/${i};
671    done
672    # rm $a # do not remove!
673    ) || fail $? crunch
674
675    if [ -f ${dst}/stand/sshd ] ; then
676	log "Setting up host key for sshd:"
677	if [ -f ${BUILDDIR}/floppy.tree/etc/ssh_host_key.gz ] ; then
678	    log "Using existing host key"
679	else
680	    log "Generating new host key" 
681	    ssh-keygen -t rsa1 -f ${BUILDDIR}/floppy.tree/etc/ssh_host_key \
682		 -N "" -C "root@picobsd"
683	    gzip -9 ${BUILDDIR}/floppy.tree/etc/ssh_host_key* || true
684	fi
685    fi
686
687    log "Copy generic and site-specific MFS tree..."
688    for MFS_TREE in ${PICO_TREE}/mfs_tree ${MY_TREE}/mfs_tree ; do
689	if [ -d ${MFS_TREE} ] ; then
690	    log "Copy ${MFS_TREE} ..."
691	    (cd ${MFS_TREE} ; tar -cf - --exclude CVS --exclude .svn . ) | \
692		    (cd ${dst} ; tar x${o_tarv}f - )
693	fi
694    done
695
696    if [ -f ${MY_TREE}/buildtree.mk ] ; then
697	log "building local floppy tree"
698	${BINMAKE} -C ${dst} -f ${MY_TREE}/buildtree.mk mfs.tree
699    fi
700
701    if [ "${o_all_in_mfs}" = "yes" ]; then
702	log "Copy generic floppy_tree into MFS..."
703	# ignore failure in case the floppy is empty
704	cp -Rp ${BUILDDIR}/floppy.tree/* ${dst}/fd || true
705    fi
706
707    # 4.x compatibility - create device nodes
708    if [ -n "${o_no_devfs}" ] ; then
709	# create device entries using MAKEDEV
710	(cd ${dst}/dev
711	ln -s ${SRC}/etc/MAKEDEV ; chmod 555 MAKEDEV
712	# log `pwd`
713	sh ./MAKEDEV ${MY_DEVS}
714	rm MAKEDEV
715	)
716    fi
717    if [ "`id -u`" = "0" ] ; then
718	log "Fixing permissions"
719	(cd ${dst}; chown -R root . )
720    fi
721
722    # If we are building a shared 'crunch', take the libraries
723    # and the dynamic loader as well
724    find_progs ${dst}/stand/crunch
725    if [ -n "${u_libs}" ] ; then
726	mkdir -p ${dst}/lib && cp -p ${u_libs} ${dst}/lib
727	mkdir -p ${dst}/libexec
728        create_includes_and_libraries2 libexec/rtld-elf
729        find_progs ld-elf.so.1 && cp -p ${u_progs} ${dst}/libexec
730    fi
731
732    [ -n "${copy_files}" ] && do_copyfiles ${dst} copy_files
733    do_copyfiles_user ${dst} || true
734    [ -n "${links}" ] && do_links ${dst} links
735    strip ${dst}/libexec/* ${dst}/lib/* ${dst}/stand/* 2> /dev/null || true
736
737    # The 'import_files' mechanism is deprecated, as it requires
738    # root permissions to follow the symlinks, and also does
739    # not let you rename the entries.
740    if [ -n "${import_files}" ] ; then
741	log "importing ${import_files} into mfs"
742	# We do it in a chroot environment on the target so
743	# symlinks are followed correctly.
744	# Make sure we have a statically linked tar there.
745	mkdir -p ${dst}/rescue
746	cp /rescue/tar ${dst}/rescue
747	(cd ${l_usrtree}/.. ; tar cf - ${import_files} ) | \
748	    (chroot ${dst} /rescue/tar xPf - )
749	rm -rf ${dst}/rescue
750    fi
751
752    # final step -- build the mfs image
753    (cd ${BUILDDIR}
754	# override the owner
755	echo "/set uid=0 gid=0" > mtree.out
756	mtree -ic -p ${dst} -k "" >> mtree.out
757	log "mtre.out at ${BUILDDIR}/mtree.out"
758	makefs -t ffs -o bsize=4096 -o fsize=512 \
759		-s ${MFS_SIZE}k -f 1000 -F mtree.out ${c_fs} ${dst}
760	ls -l ${c_fs} )
761    log "done mfs image"
762}
763
764final_cleanup() {
765    log "final_cleanup()"
766    rm -rf ${c_mnt} ${c_reply} 2> /dev/null || true
767    rm -f ${c_reply}
768}
769
770# fail errno errcode
771# This function is used to trap errors and print msgs
772#
773fail() {
774    local errno errocode where
775
776    errno=$1
777    errcode=$2
778    where=$3
779    echo "---> fail: Error <${errno}> error code <${errcode}> in <${where}>"
780    case ${errcode} in
781    mtree)
782	echo "Error while making hierarchy in ${c_mnt}"
783	;;
784    crunch)
785	echo "Error while building ${name}."
786	;;
787    missing_kernel)
788	echo "Error: you must build PICOBSD${suffix} kernel first"
789	;;
790    includes)
791	echo "Error: failed while making includes"
792	;;
793    libraries)
794	echo "Error: failed while making libraries"
795	;;
796    bad_type)
797	echo "Error: unknown floppy type ${name}"
798	;;
799    no_space)
800	echo "Error: no space left on device (${where})"
801	;;
802    no_mfs)
803	echo "Error: while writing MFS into the kernel."
804	;;
805    "")
806	echo "User break"
807	errcode="userbreak"
808	;;
809    *)
810	echo "unknown error, maybe user break: $errno $errcode"
811	;;
812    esac
813    echo "---> Aborting $0"
814    # try to cleanup the vnode.
815    final_cleanup
816    exit 2
817}
818
819fill_floppy_image() {
820    local blocks dst mfs_start mfs_end mfs_size img_size
821
822    log "fill_floppy_image()"
823    dst=${c_mnt}	# where to create the image
824
825    log "Preparing ${fd_size}kB floppy filesystem..."
826
827    # correct blocks according to size.
828    blocks=${fd_size};
829    if [ "${blocks}" = "1720" ]; then
830	blocks=1722
831    elif [ "${blocks}" = "1480" ]; then
832	blocks=1476
833    fi
834
835    log "Labeling floppy image"
836    b2=${BUILDDIR}/boot2 # modified boot2
837    cp -f ${c_boot2} ${b2}
838    chmod 0644 ${b2}
839
840    if [ ${o_use_loader} = "no" ] ; then
841	log "patch ${c_boot2} to boot /kernel right away"
842	set `strings -at d ${b2} | grep "/boot/loader"`
843	echo -e "/kernel\0\0\0\0\0" | \
844	    dd of=${b2} obs=$1 oseek=1 conv=notrunc 2>/dev/null
845    fi
846    chmod 0444 ${b2}
847
848    dst=${BUILDDIR}/image.tree
849    rm -rf ${dst}
850    mkdir -p ${dst}
851    (
852    cd ${BUILDDIR}
853    set 0 0 # reset variables
854    # $1 takes the offset of the MFS filesystem
855    set `strings -at d kernel | grep "MFS Filesystem goes here"`
856    mfs_start=$1
857    set 0 0 # reset variables
858    set `strings -at d kernel | grep "MFS Filesystem had better"`
859    mfs_end=$1
860    mfs_size="$((${mfs_end} - ${mfs_start}))"
861    set -- `ls -l ${c_fs}`; imgsize="$5"
862    if [ ${mfs_start} -gt 0 -a ${mfs_size} -ge ${imgsize} ] ; then
863	mfs_ofs=$((${mfs_start} + 8192))
864	log "Preload kernel with file ${c_fs} at ${mfs_ofs}"
865	logverbose "`ls -l ${c_fs}` to fit in ${mfs_size}"
866	dd if=${c_fs} ibs=8192 iseek=1 of=kernel obs=${mfs_ofs} \
867	    oseek=1 conv=notrunc # 2> /dev/null
868    else
869    	log "not loading mfs, size ${mfs_size} img ${imgsize}"
870    fi
871    log "Compress with kgzip and copy to floppy image"
872    if [ ${o_use_loader} = "no" ] ; then
873	kgzip -o kernel.gz kernel
874	cp -p kernel.gz ${dst}/kernel || fail $? no_space "copying kernel"
875    else
876        gzip kernel
877	mkdir -p  ${dst}/boot/kernel
878	echo "hint.acpi.0.disabled=\"1\"" > ${dst}/boot/loader.conf
879	echo "console=\"comconsole\"" >> ${dst}/boot/loader.conf
880	cp -p /boot/loader ${dst}/boot/loader || fail $? no_space "copying bootloader"
881	cp -p kernel.gz ${dst}/boot/kernel/kernel.gz || fail $? no_space "copying kernel"
882    fi
883
884    # now transfer the floppy tree. If it is already in mfs, dont bother.
885    if [ "${o_all_in_mfs}" != "yes" ] ; then
886	log "Now transfer floppy tree if not already in MFS image"
887	cp -Rp floppy.tree/* ${dst} || \
888		fail $? no_space "copying floppy tree"
889    fi
890    )
891
892    # add local manipulation to the image
893    if [ -f ${MY_TREE}/buildtree.mk ] ; then
894	${BINMAKE} -C ${dst} -f ${MY_TREE}/buildtree.mk image.tree
895    fi
896
897    log "image used `du -s ${dst}` of ${blocks}k"
898    if [ "${generate_iso}" = "YES" ]; then
899	logverbose "generate_iso ${generate_iso}"
900	# build_iso_image	# XXX not implemented yet
901	(cd ${BUILDDIR}
902	cp -p /boot/cdboot ${dst}/boot || fail $? no_space "copying cdboot"
903	mkisofs -b boot/cdboot -no-emul-boot -J -r -ldots -l -L \
904		-o ${c_iso} ${dst}
905	)
906    fi
907
908    (cd ${BUILDDIR}
909    makefs -t ffs -o bsize=4096 -o fsize=512 \
910	-s ${blocks}k -f 50 ${c_img} ${dst}
911
912    ${c_label} -w -f `pwd`/${c_img} auto # write in a label
913    # copy partition c: into a: with some sed magic
914    ${c_label} -f `pwd`/${c_img} | sed -e '/  c:/{p;s/c:/a:/;}' | \
915	${c_label} -R -f `pwd`/${c_img} /dev/stdin
916    ${c_label} -f `pwd`/${c_img}
917
918    ls -l ${c_img}
919    ${c_label} -f `pwd`/${c_img}
920    logverbose "after disklabel"
921    )
922
923    echo "BUILDDIR ${BUILDDIR}"
924
925    # dump the primary and secondary boot
926    # XXX primary is 512 bytes
927    dd if=${c_boot1} of=${BUILDDIR}/${c_img} conv=notrunc 2>/dev/null
928    # XXX secondary starts after the 0x114 = dec 276 bytes of the label
929    # so we skip 276 from the source, and 276+512=788 from dst
930    # the old style blocks used 512 and 1024 respectively
931
932    dd if=${b2} iseek=1 ibs=276 2> /dev/null | \
933	dd of=${BUILDDIR}/${c_img} oseek=1 obs=788 conv=notrunc 2>/dev/null
934    logverbose "done floppy image"
935    # XXX (log "Fixing permissions"; cd ${dst}; chown -R root *)
936    rm -rf ${BUILDDIR}/floppy.tree || true # cleanup
937    # df -ik ${dst} | colrm 70 > .build.reply
938    rm -rf ${dst}
939    rm ${BUILDDIR}/${c_fs}
940    # rm ${BUILDDIR}/kernel.gz
941}
942
943# This function creates variables which depend on the source tree in use:
944# SRC, l_usrtree, l_objtree
945# Optionally creates libraries, includes and the like (for cross compiles,
946# needs to be done once).
947
948set_build_parameters() {
949    if [ "${SRC}" = "/usr/src" ] ; then
950	l_usrtree=${USR:-/usr}
951    else
952	l_usrtree=${USR:-${SRC}/../usr}
953    fi
954    l_objtree=${l_usrtree}/obj-pico
955    PICO_TREE=${PICO_TREE:-${SRC}/release/picobsd}
956    set `grep "#define[\t ]__FreeBSD_version" ${SRC}/sys/sys/param.h`
957    OSVERSION=$3
958    log "OSVERSION is ${OSVERSION}"
959    if [ "${o_init_src}" != "" ] ; then
960	if [ ${OSVERSION} -lt 500035 ] ; then
961	    create_includes_and_libraries
962	else
963	    create_includes_and_libraries2
964	fi
965    fi
966    if [ ${OSVERSION} -lt 500035 ] ; then
967	# Create the right LIBS and CFLAGS for further builds.
968	# and build the config program
969	LIBS="-L${l_usrtree}/lib"
970	CFLAGS="-nostdinc -I${l_usrtree}/include"
971	export LIBS CFLAGS
972	CONFIG=${l_usrtree}/sbin/config
973	export CONFIG
974    fi
975
976    # if we have o_objdir, find where bin/ is
977    if [ ! -z "${o_objdir}" ] ; then
978	if [ -d ${o_objdir}/bin ] ; then
979	    # fine
980	elif [ -d "${o_objdir}${SRC}/bin" ] ; then
981	    o_objdir="${o_objdir}${SRC}"
982	    log "Changing objdir to ${o_objdir}"
983	else
984	    log "Cannot find objdir in ${o_objdir}, sorry"
985	    o_objdir=""
986	fi
987    fi
988}
989
990#-------------------------------------------------------------------
991# Main entry of the script. Initialize variables, parse command line
992# arguments.
993
994set_defaults
995while [ true ]; do
996    log "Parsing $1"
997    case $1 in
998    --src)	# set the source path instead of /usr/src
999	SRC=`realpath $2`
1000	shift
1001	;;
1002    --init)
1003	o_init_src="YES"
1004	;;
1005
1006    --floppy_size)
1007	fd_size=$2
1008	shift
1009	;;
1010
1011    --no_loader)	# omit /boot/loader, just rely on boot2
1012			# (it may have problems with kernels > 4MB)
1013	o_use_loader="no"
1014	;;
1015
1016    --all_in_mfs)
1017	o_all_in_mfs="yes"
1018	;;
1019
1020    --no_all_in_mfs)
1021	o_all_in_mfs="no"
1022	;;
1023
1024    --modules)	# also build kernel modules
1025	o_do_modules="yes"
1026	;;
1027    -n)
1028	o_interactive="NO"
1029	;;
1030
1031    -clear|-clean|-c) # clean
1032	o_clean="YES"
1033	o_interactive="NO"
1034	;;
1035
1036    -v) # need -v -v to wait for user input
1037	o_verbose=$((${o_verbose}+1))	# verbose level
1038	o_tarv="v"			# tar verbose flag
1039	o_makeopts="-d l" # be verbose
1040	;;
1041
1042    --iso) # generate iso image
1043	generate_iso="YES"
1044	;;
1045
1046    --cfg) # read additional config from this file
1047	o_additional_config=`realpath $2`
1048	shift
1049	;;
1050
1051    --objdir)	# Place with results of a previous buildworld
1052		# useful if you want to copy shared binaries and libs
1053	o_objdir=`realpath $2`
1054	shift
1055	;;
1056
1057    *)
1058	break
1059	;;
1060
1061    esac
1062    shift
1063done
1064
1065set_build_parameters	# things that depend on ${SRC}
1066set_type $1 $2		# type and site, respectively
1067
1068[ "${o_interactive}" != "NO" ] && main_dialog
1069
1070if [ "${o_clean}" = "YES" ] ; then
1071    clean_tree
1072else
1073    build_image
1074    do_install
1075fi
1076final_cleanup
1077exit 0
1078