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