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