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