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