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