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