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