]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - tools/tools/sysbuild/sysbuild.sh
Merge from head
[FreeBSD/FreeBSD.git] / tools / tools / sysbuild / sysbuild.sh
1 #!/bin/sh
2 #
3 # Copyright (c) 1994-2009 Poul-Henning Kamp.
4 # All rights reserved.
5 #
6 # Redistribution and use in source and binary forms, with or without
7 # modification, are permitted provided that the following conditions
8 # are met:
9 # 1. Redistributions of source code must retain the above copyright
10 #    notice, this list of conditions and the following disclaimer.
11 # 2. Redistributions in binary form must reproduce the above copyright
12 #    notice, this list of conditions and the following disclaimer in the
13 #    documentation and/or other materials provided with the distribution.
14 #
15 # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 # ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 # SUCH DAMAGE.
26 #
27 # $FreeBSD$
28 #
29
30 set -e
31
32 exec < /dev/null
33
34 if [ `uname -m` = "i386" -o `uname -m` = "amd64" ] ; then
35         TARGET_PART=`df / | sed '
36         1d
37         s/[    ].*//
38         s,/dev/,,
39         s,s1a,s3a,
40         s,s2a,s1a,
41         s,s3a,s2a,
42         '`
43
44         FREEBSD_PART=`sed -n    \
45                 -e 's/#.*//'    \
46                 -e '/[  ]\/freebsd[     ]/!d'   \
47                 -e 's/[         ].*//p' \
48                 /etc/fstab`
49
50         # Calculate a suggested gpart command
51         TARGET_DISK=`expr ${TARGET_PART} : '\(.*\)s[12]a$' || true`
52         TARGET_SLICE=`expr ${TARGET_PART} : '.*s\([12]\)a$' || true`
53         GPART_SUGGESTION="gpart set -a active -i $TARGET_SLICE /dev/$TARGET_DISK"
54         unset TARGET_DISK TARGET_SLICE
55 else
56         TARGET_PART=unknown
57         FREEBSD_PART=unknown
58         GPART_SUGGESTION=unknown
59 fi
60
61
62 # Relative to /freebsd
63 PORTS_PATH=ports
64 SRC_PATH=src
65 # OBJ_PATH=obj
66
67 # Name of kernel
68 KERNCONF=GENERIC
69
70 # srcconf
71 #SRCCONF="SRCCONF=/usr/src/src.conf"
72
73 # -j arg to make(1)
74
75 ncpu=`sysctl -n kern.smp.cpus`
76 if [ $ncpu -gt 1 ] ; then
77         JARG="-j $ncpu"
78 fi
79
80 # serial console ?
81 SERCONS=false
82
83 # Remotely mounted distfiles
84 # REMOTEDISTFILES=fs:/rdonly/distfiles
85
86 # Proxy
87 #FTP_PROXY=http://127.0.0.1:3128/
88 #HTTP_PROXY=http://127.0.0.1:3128/
89 #export FTP_PROXY HTTP_PROXY
90
91 PORTS_WE_WANT='
92 '
93
94 PORTS_OPTS="BATCH=YES A4=yes"
95
96 CONFIGFILES='
97 '
98
99 SBMNT="/mnt.sysbuild"
100
101 cleanup() (
102 )
103
104 before_ports() (
105 )
106
107 before_ports_chroot() (
108 )
109
110 final_root() (
111 )
112
113 final_chroot() (
114 )
115
116 #######################################################################
117 # -P is a pretty neat way to clean junk out from your ports dist-files:
118 #
119 #       mkdir /freebsd/ports/distfiles.old
120 #       mv /freebsd/ports/distfiles/* /freebsd/ports/distfiles.old
121 #       sh sysbuild.sh -c $yourconfig -P /freebsd/ports/distfiles.old
122 #       rm -rf /freebsd/ports/distfiles.old
123 #
124 # Unfortunately bsd.ports.mk does not attempt to use a hard-link so
125 # while this runs you need diskspace for both your old and your "new"
126 # distfiles.
127 #
128 #######################################################################
129
130 usage () {
131         (
132         echo "Usage: $0 [-b/-k/-w] [-c config_file]"
133         echo "  -b      suppress builds (both kernel and world)"
134         echo "  -k      suppress buildkernel"
135         echo "  -w      suppress buildworld"
136         echo "  -p      used cached packages"
137         echo "  -P <dir> prefetch ports"
138         echo "  -c      specify config file"
139         ) 1>&2
140         exit 2
141 }
142
143 #######################################################################
144 #######################################################################
145
146 if [ ! -f $0 ] ; then
147         echo "Must be able to access self ($0)" 1>&2
148         exit 1
149 fi
150
151 if grep -q 'Magic String: 0`0nQT40W%l,CX&' $0 ; then
152         true
153 else
154         echo "self ($0) does not contain magic string" 1>&2
155         exit 1
156 fi
157
158 #######################################################################
159
160 set -e
161
162 log_it() (
163         a="$*"
164         set `cat /tmp/_sb_log`
165         TX=`date +%s`
166         echo "$1 $TX" > /tmp/_sb_log
167         DT=`expr $TX - $1 || true`
168         DL=`expr $TX - $2 || true`
169         echo -n "### `date +%H:%M:%S`"
170         printf " ### %5d ### %5d ### %s\n" $DT $DL "$a"
171 )
172
173 #######################################################################
174
175
176 ports_recurse() (
177         t=$1
178         shift
179         if [ "x$t" = "x." ] ; then
180                 true > /tmp/_.plist
181                 true > /tmp/_.plist.tdone
182                 echo 'digraph {' > /tmp/_.plist.dot
183         fi
184         if grep -q "^$t\$" /tmp/_.plist.tdone ; then
185                 return
186         fi
187         echo "$t" >> /tmp/_.plist.tdone
188         for d
189         do
190                 if [ ! -d $d ] ; then
191                         echo "Missing port $d" 1>&2
192                         continue
193                 fi
194                 if [ ! -f $d/Makefile ] ; then
195                         echo "Missing port $d" 1>&2
196                         continue
197                 fi
198                 if [ "x$t" != "x." ] ; then
199                         echo "\"$t\" -> \"$d\"" >> /tmp/_.plist.dot
200                 fi
201                 if grep -q "^$d\$" /tmp/_.plist ; then
202                         true
203                 elif grep -q "^$d\$" /tmp/_.plist.tdone ; then
204                         true
205                 else
206                         (
207                         cd $d
208                         ports_recurse $d `make -V _DEPEND_DIRS ${PORTS_OPTS}`
209                         )
210                         echo "$d" >> /tmp/_.plist
211                 fi
212         done
213         if [ "x$t" = "x." ] ; then
214                 echo '}' >> /tmp/_.plist.dot
215         fi
216 )
217
218 ports_build() (
219
220         ports_recurse . $PORTS_WE_WANT 
221
222         # Now build & install them
223         for p in `cat /tmp/_.plist`
224         do
225                 b=`echo $p | tr / _`
226                 t=`echo $p | sed 's,/usr/ports/,,'`
227                 pn=`cd $p && make package-name`
228
229                 if [ "x$p" == "x/usr/ports/ports-mgmt/pkg" -o \
230                      "x$p" == "x/freebsd/ports/ports-mgmt/pkg" ] ; then
231                         log_it "Very Special: $t ($pn)"
232
233                         (
234                         cd $p
235                         make clean ${PORTS_OPTS}
236                         make all ${PORTS_OPTS}
237                         make install ${PORTS_OPTS}
238                         ) > _.$b 2>&1 < /dev/null
239                         continue
240                 fi
241
242                 if pkg info $pn > /dev/null 2>&1 ; then
243                         log_it "Already installed: $t ($pn)"
244                         continue
245                 fi
246
247                 if [ "x${PKG_DIR}" != "x" -a -f ${PKG_DIR}/$pn.txz ] ; then
248                         if [ "x$use_pkg" = "x-p" ] ; then
249                                 log_it "Install $t ($pn)"
250                                 (
251                                 set +e
252                                 pkg add ${PKG_DIR}/$pn.txz || true
253                                 ) > _.$b 2>&1 < /dev/null
254                                 continue
255                         fi
256                 fi
257
258                 miss=`(cd $p ; make missing ${PORTS_OPTS}) || true`
259
260                 if [ "x${miss}" != "x" ] ; then
261                         log_it "MISSING for $p:" $miss
262                         continue
263                 fi
264
265                 log_it "build $pn ($p)"
266                 (
267                         set +e
268                         cd $p
269                         make clean ${PORTS_OPTS}
270                         if make install ${PORTS_OPTS} ; then
271                                 if [ "x${PKG_DIR}" != "x" ] ; then
272                                         make package ${PORTS_OPTS}
273                                 fi
274                         else
275                                 log_it FAIL build $p
276                         fi
277                         make clean
278                 ) > _.$b 2>&1 < /dev/null
279         done
280 )
281
282 ports_prefetch() (
283         (
284         set +x
285         ldir=$1
286         true > /${ldir}/_.prefetch
287         echo "Building /tmp/_.plist" >> /${ldir}/_.prefetch
288
289         ports_recurse . $PORTS_WE_WANT
290
291         echo "Completed /tmp/_.plist" >> /${ldir}/_.prefetch
292         # Now checksump/fetch them
293         for p in `cat /tmp/_.plist`
294         do
295                 b=`echo $p | tr / _`
296                 (
297                         cd $p
298                         if make checksum $PORTS_OPTS ; then
299                                 rm -f /${ldir}/_.prefetch.$b
300                                 echo "OK $p" >> /${ldir}/_.prefetch
301                                 exit 0
302                         fi
303                         make distclean
304                         make checksum $PORTS_OPTS || true
305
306                         if make checksum $PORTS_OPTS > /dev/null 2>&1 ; then
307                                 rm -f /${ldir}/_.prefetch.$b
308                                 echo "OK $p" >> /${ldir}/_.prefetch
309                         else
310                                 echo "BAD $p" >> /${ldir}/_.prefetch
311                         fi
312                 ) > /${ldir}/_.prefetch.$b 2>&1
313         done
314         echo "Done" >> /${ldir}/_.prefetch
315         ) 
316 )
317
318 #######################################################################
319
320 do_world=true
321 do_kernel=true
322 do_prefetch=false
323 use_pkg=""
324 c_arg=""
325
326 set +e
327 args=`getopt bc:hkpP:w $*`
328 if [ $? -ne 0 ] ; then
329         usage
330 fi
331 set -e
332
333 set -- $args
334 for i
335 do
336         case "$i"
337         in
338         -b)
339                 shift;
340                 do_world=false
341                 do_kernel=false
342                 ;;
343         -c)
344                 c_arg=$2
345                 if [ ! -f "$c_arg" ] ; then
346                         echo "Cannot read $c_arg" 1>&2
347                         usage
348                 fi
349                 . "$2"
350                 shift
351                 shift
352                 ;;
353         -h)
354                 usage
355                 ;;
356         -k)
357                 shift;
358                 do_kernel=false
359                 ;;
360         -p)
361                 shift;
362                 use_pkg="-p"
363                 ;;
364         -P)
365                 shift;
366                 do_prefetch=true
367                 distfile_cache=$1
368                 shift;
369                 ;;
370         -w)
371                 shift;
372                 do_world=false
373                 ;;
374         --)
375                 shift
376                 break;
377                 ;;
378         esac
379 done
380
381 #######################################################################
382
383 if [ "x$1" = "xchroot_script" ] ; then
384         set -e
385
386         shift
387
388         before_ports_chroot
389
390         ports_build
391
392         exit 0
393 fi
394
395 if [ "x$1" = "xfinal_chroot" ] ; then
396         final_chroot
397         exit 0
398 fi
399
400 if [ $# -gt 0 ] ; then
401         echo "$0: Extraneous arguments supplied"
402         usage
403 fi
404
405 #######################################################################
406
407 T0=`date +%s`
408 echo $T0 $T0 > /tmp/_sb_log
409
410 [ ! -d ${SBMNT} ] && mkdir -p ${SBMNT}
411
412 if $do_prefetch ; then
413         rm -rf /tmp/sysbuild/ports
414         mkdir -p /tmp/sysbuild/ports
415         ln -s ${distfile_cache} /tmp/sysbuild/ports/distfiles
416         export PORTS_OPTS=CD_MOUNTPTS=/tmp/sysbuild
417         ports_prefetch /tmp 
418         exit 0
419 fi
420
421 log_it Unmount everything
422 (
423         ( cleanup )
424         umount /freebsd/distfiles || true
425         umount ${SBMNT}/freebsd/distfiles || true
426         umount ${FREEBSD_PART} || true
427         umount ${SBMNT}/freebsd || true
428         umount ${SBMNT}/dev || true
429         umount ${SBMNT} || true
430         umount /dev/${TARGET_PART} || true
431 ) # > /dev/null 2>&1
432
433 log_it Prepare running image
434 mkdir -p /freebsd
435 mount ${FREEBSD_PART} /freebsd
436
437 #######################################################################
438
439 if [ ! -d /freebsd/${PORTS_PATH} ] ;  then
440         echo PORTS_PATH does not exist 1>&2
441         exit 1
442 fi
443
444 if [ ! -d /freebsd/${SRC_PATH} ] ;  then
445         echo SRC_PATH does not exist 1>&2
446         exit 1
447 fi
448
449 log_it TARGET_PART $TARGET_PART
450 sleep 5
451
452 rm -rf /usr/ports
453 ln -s /freebsd/${PORTS_PATH} /usr/ports
454
455 rm -rf /usr/src
456 ln -s /freebsd/${SRC_PATH} /usr/src
457
458 if $do_world ; then
459         if [ "x${OBJ_PATH}" != "x" ] ; then
460                 rm -rf /usr/obj
461                 mkdir -p /freebsd/${OBJ_PATH}
462                 ln -s /freebsd/${OBJ_PATH} /usr/obj
463         else
464                 rm -rf /usr/obj
465                 mkdir -p /usr/obj
466         fi
467 fi
468
469 #######################################################################
470
471 for i in ${PORTS_WE_WANT}
472 do
473         if [ ! -d $i ]  ; then
474                 echo "Port $i not found" 1>&2
475                 exit 2
476         fi
477 done
478
479 export PORTS_WE_WANT
480 export PORTS_OPTS
481
482 #######################################################################
483
484 log_it Prepare destination partition
485 newfs -t -E -O2 -U /dev/${TARGET_PART} > /dev/null
486 mount /dev/${TARGET_PART} ${SBMNT}
487 mkdir -p ${SBMNT}/dev
488 mount -t devfs devfs ${SBMNT}/dev
489
490 if [ "x${REMOTEDISTFILES}" != "x" ] ; then
491         rm -rf /freebsd/${PORTS_PATH}/distfiles
492         ln -s /freebsd/distfiles /freebsd/${PORTS_PATH}/distfiles
493         mkdir -p /freebsd/distfiles
494         mount  ${REMOTEDISTFILES} /freebsd/distfiles
495 fi
496
497 log_it copy ports config files
498 (cd / ; find var/db/ports -print | cpio -dumpv ${SBMNT} > /dev/null 2>&1)
499
500 log_it "Start prefetch of ports distfiles"
501 ports_prefetch ${SBMNT} &
502
503 if $do_world ; then
504         (
505         cd /usr/src
506         log_it "Buildworld"
507         make ${JARG} -s buildworld ${SRCCONF} > ${SBMNT}/_.bw 2>&1
508         )
509 fi
510
511 if $do_kernel ; then
512         (
513         cd /usr/src
514         log_it "Buildkernel"
515         make ${JARG} -s buildkernel KERNCONF=$KERNCONF > ${SBMNT}/_.bk 2>&1
516         )
517 fi
518
519
520 log_it Installworld
521 (cd /usr/src && make ${JARG} installworld DESTDIR=${SBMNT} ${SRCCONF} ) \
522         > ${SBMNT}/_.iw 2>&1
523
524 log_it distribution
525 (cd /usr/src/etc && make -m /usr/src/share/mk distribution DESTDIR=${SBMNT} ${SRCCONF} ) \
526         > ${SBMNT}/_.dist 2>&1
527
528 log_it Installkernel
529 (cd /usr/src && make ${JARG} installkernel DESTDIR=${SBMNT} KERNCONF=$KERNCONF ) \
530         > ${SBMNT}/_.ik 2>&1
531
532 if [ "x${OBJ_PATH}" != "x" ] ; then
533         rmdir ${SBMNT}/usr/obj
534         ln -s /freebsd/${OBJ_PATH} ${SBMNT}/usr/obj
535 fi
536
537 log_it Wait for ports prefetch
538 log_it "(Tail ${SBMNT}/_.prefetch for progress)"
539 wait
540
541 log_it Move filesystems
542
543 if [ "x${REMOTEDISTFILES}" != "x" ] ; then
544         umount /freebsd/distfiles
545 fi
546 umount ${FREEBSD_PART} || true
547 mkdir -p ${SBMNT}/freebsd
548 mount ${FREEBSD_PART} ${SBMNT}/freebsd
549 if [ "x${REMOTEDISTFILES}" != "x" ] ; then
550         mount  ${REMOTEDISTFILES} ${SBMNT}/freebsd/distfiles
551 fi
552
553 rm -rf ${SBMNT}/usr/ports || true
554 ln -s /freebsd/${PORTS_PATH} ${SBMNT}/usr/ports
555
556 rm -rf ${SBMNT}/usr/src || true
557 ln -s /freebsd/${SRC_PATH} ${SBMNT}/usr/src
558
559 log_it Build and install ports
560
561 # Make sure fetching will work in the chroot
562 if [ -f /etc/resolv.conf ] ; then
563         log_it copy resolv.conf
564         cp /etc/resolv.conf ${SBMNT}/etc
565         chflags schg ${SBMNT}/etc/resolv.conf
566 fi
567
568 if [ -f /etc/localtime ] ; then
569         log_it copy localtime
570         cp /etc/localtime ${SBMNT}/etc
571 fi
572
573 log_it ldconfig in chroot
574 chroot ${SBMNT} sh /etc/rc.d/ldconfig start
575
576 log_it before_ports
577
578         before_ports 
579 )
580
581 log_it fixing fstab
582 sed "/[         ]\/[    ]/s;^[^         ]*[     ];/dev/${TARGET_PART}   ;" \
583         /etc/fstab > ${SBMNT}/etc/fstab
584
585 log_it build ports
586
587 cp $0 ${SBMNT}/root
588 cp /tmp/_sb_log ${SBMNT}/tmp
589 b=`basename $0`
590 if [ "x$c_arg" != "x" ] ; then
591         cp $c_arg ${SBMNT}/root
592         chroot ${SBMNT} sh /root/$0 -c /root/`basename $c_arg` $use_pkg chroot_script 
593 else
594         chroot ${SBMNT} sh /root/$0 $use_pkg chroot_script
595 fi
596 cp ${SBMNT}/tmp/_sb_log /tmp
597
598 log_it create all mountpoints
599 grep -v '^[     ]*#' ${SBMNT}/etc/fstab | 
600 while read a b c
601 do
602         mkdir -p ${SBMNT}/$b
603 done
604
605 if [ "x$SERCONS" != "xfalse" ] ; then
606         log_it serial console
607         echo " -h" > ${SBMNT}/boot.config
608         sed -i "" -e /ttyd0/s/off/on/ ${SBMNT}/etc/ttys
609         sed -i "" -e /ttyu0/s/off/on/ ${SBMNT}/etc/ttys
610         sed -i "" -e '/^ttyv[0-8]/s/    on/     off/' ${SBMNT}/etc/ttys
611 fi
612
613 log_it move dist config files "(expect warnings)"
614 (
615         cd ${SBMNT}
616         mkdir root/configfiles_dist
617         find ${CONFIGFILES} -print | cpio -dumpv root/configfiles_dist
618 )
619
620 log_it copy live config files
621 (cd / && find ${CONFIGFILES} -print | cpio -dumpv ${SBMNT})
622
623 log_it final_root
624 ( final_root )
625 log_it final_chroot
626 cp /tmp/_sb_log ${SBMNT}/tmp
627 if [ "x$c_arg" != "x" ] ; then
628         chroot ${SBMNT} sh /root/$0 -c /root/`basename $c_arg` final_chroot
629 else
630         chroot ${SBMNT} sh /root/$0 final_chroot
631 fi
632 cp ${SBMNT}/tmp/_sb_log /tmp
633 log_it "Check these messages (if any):"
634 grep '^Stop' ${SBMNT}/_* || true
635 log_it DONE
636 echo "Now you probably want to:"
637 echo "    $GPART_SUGGESTION"
638 echo "    shutdown -r now"