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