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