nanobsd.sh revision 171986
1#!/bin/sh 2# 3# Copyright (c) 2005 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: head/tools/tools/nanobsd/nanobsd.sh 171986 2007-08-26 14:57:08Z phk $ 28# 29 30set -e 31 32####################################################################### 33# 34# Setup default values for all controlling variables. 35# These values can be overridden from the config file(s) 36# 37####################################################################### 38 39# Name of this NanoBSD build. (Used to construct workdir names) 40NANO_NAME=full 41 42# Source tree directory 43NANO_SRC=/usr/src 44 45# Where nanobsd additional files live under the source tree 46NANO_TOOLS=tools/tools/nanobsd 47 48# Where cust_pkg() finds packages to install 49NANO_PACKAGE_DIR=${NANO_SRC}/${NANO_TOOLS}/Pkg 50 51# Object tree directory 52# default is subdir of /usr/obj 53# XXX: MAKEOBJDIRPREFIX handling... ? 54#NANO_OBJ="" 55 56# Parallel Make 57NANO_PMAKE="make -j 3" 58 59# Options to put in make.conf during buildworld only 60CONF_BUILD=' ' 61 62# Options to put in make.conf during installworld only 63CONF_INSTALL=' ' 64 65# Options to put in make.conf during both build- & installworld. 66CONF_WORLD=' ' 67 68# Kernel config file to use 69NANO_KERNEL=GENERIC 70 71# Customize commands. 72NANO_CUSTOMIZE="" 73 74# Newfs paramters to use 75NANO_NEWFS="-b 4096 -f 512 -i 8192 -O1 -U" 76 77# The drive name of the media at runtime 78NANO_DRIVE=ad0 79 80# Target media size in 512 bytes sectors 81NANO_MEDIASIZE=1000000 82 83# Number of code images on media (1 or 2) 84NANO_IMAGES=2 85 86# 0 -> Leave second image all zeroes so it compresses better. 87# 1 -> Initialize second image with a copy of the first 88NANO_INIT_IMG2=1 89 90# Size of code file system in 512 bytes sectors 91# If zero, size will be as large as possible. 92NANO_CODESIZE=0 93 94# Size of configuration file system in 512 bytes sectors 95# Cannot be zero. 96NANO_CONFSIZE=2048 97 98# Size of data file system in 512 bytes sectors 99# If zero: no partition configured. 100# If negative: max size possible 101NANO_DATASIZE=0 102 103# Size of the /etc ramdisk in 512 bytes sectors 104NANO_RAM_ETCSIZE=10240 105 106# Size of the /tmp+/var ramdisk in 512 bytes sectors 107NANO_RAM_TMPVARSIZE=10240 108 109# Media geometry, only relevant if bios doesn't understand LBA. 110NANO_SECTS=63 111NANO_HEADS=16 112 113# boot0 flags/options and configuration 114NANO_BOOT0CFG="-o packet -s 1 -m 3" 115NANO_BOOTLOADER="boot/boot0sio" 116 117####################################################################### 118# Not a variable at this time 119 120NANO_ARCH=i386 121 122####################################################################### 123# 124# The functions which do the real work. 125# Can be overridden from the config file(s) 126# 127####################################################################### 128 129clean_build ( ) ( 130 echo "## Clean and create object directory (${MAKEOBJDIRPREFIX})" 131 132 if rm -rf ${MAKEOBJDIRPREFIX} > /dev/null 2>&1 ; then 133 true 134 else 135 chflags -R noschg ${MAKEOBJDIRPREFIX} 136 rm -rf ${MAKEOBJDIRPREFIX} 137 fi 138 mkdir -p ${MAKEOBJDIRPREFIX} 139 printenv > ${MAKEOBJDIRPREFIX}/_.env 140) 141 142make_conf_build ( ) ( 143 echo "## Construct build make.conf ($NANO_MAKE_CONF)" 144 145 echo "${CONF_WORLD}" > ${NANO_MAKE_CONF} 146 echo "${CONF_BUILD}" >> ${NANO_MAKE_CONF} 147) 148 149build_world ( ) ( 150 echo "## run buildworld" 151 echo "### log: ${MAKEOBJDIRPREFIX}/_.bw" 152 153 cd ${NANO_SRC} 154 ${NANO_PMAKE} __MAKE_CONF=${NANO_MAKE_CONF} buildworld \ 155 > ${MAKEOBJDIRPREFIX}/_.bw 2>&1 156) 157 158build_kernel ( ) ( 159 echo "## build kernel ($NANO_KERNEL)" 160 echo "### log: ${MAKEOBJDIRPREFIX}/_.bk" 161 162 if [ -f ${NANO_KERNEL} ] ; then 163 cp ${NANO_KERNEL} ${NANO_SRC}/sys/${NANO_ARCH}/conf 164 fi 165 166 cd ${NANO_SRC} 167 ${NANO_PMAKE} buildkernel \ 168 __MAKE_CONF=${NANO_MAKE_CONF} KERNCONF=`basename ${NANO_KERNEL}` \ 169 > ${MAKEOBJDIRPREFIX}/_.bk 2>&1 170) 171 172clean_world ( ) ( 173 echo "## Clean and create world directory (${NANO_WORLDDIR})" 174 if rm -rf ${NANO_WORLDDIR}/ > /dev/null 2>&1 ; then 175 true 176 else 177 chflags -R noschg ${NANO_WORLDDIR}/ 178 rm -rf ${NANO_WORLDDIR}/ 179 fi 180 mkdir -p ${NANO_WORLDDIR}/ 181) 182 183make_conf_install ( ) ( 184 echo "## Construct install make.conf ($NANO_MAKE_CONF)" 185 186 echo "${CONF_WORLD}" > ${NANO_MAKE_CONF} 187 echo "${CONF_INSTALL}" >> ${NANO_MAKE_CONF} 188) 189 190install_world ( ) ( 191 echo "## installworld" 192 echo "### log: ${MAKEOBJDIRPREFIX}/_.iw" 193 194 cd ${NANO_SRC} 195 ${NANO_PMAKE} __MAKE_CONF=${NANO_MAKE_CONF} installworld \ 196 DESTDIR=${NANO_WORLDDIR} \ 197 > ${MAKEOBJDIRPREFIX}/_.iw 2>&1 198 chflags -R noschg ${NANO_WORLDDIR} 199) 200 201install_etc ( ) ( 202 203 echo "## install /etc" 204 echo "### log: ${MAKEOBJDIRPREFIX}/_.etc" 205 206 cd ${NANO_SRC} 207 ${NANO_PMAKE} __MAKE_CONF=${NANO_MAKE_CONF} distribution \ 208 DESTDIR=${NANO_WORLDDIR} \ 209 > ${MAKEOBJDIRPREFIX}/_.etc 2>&1 210) 211 212install_kernel ( ) ( 213 echo "## install kernel" 214 echo "### log: ${MAKEOBJDIRPREFIX}/_.ik" 215 216 cd ${NANO_SRC} 217 ${NANO_PMAKE} installkernel \ 218 DESTDIR=${NANO_WORLDDIR} \ 219 __MAKE_CONF=${NANO_MAKE_CONF} KERNCONF=`basename ${NANO_KERNEL}` \ 220 > ${MAKEOBJDIRPREFIX}/_.ik 2>&1 221) 222 223run_customize() ( 224 225 echo "## run customize scripts" 226 for c in $NANO_CUSTOMIZE 227 do 228 echo "## customize \"$c\"" 229 echo "### log: ${MAKEOBJDIRPREFIX}/_.cust.$c" 230 echo "### `type $c`" 231 ( $c ) > ${MAKEOBJDIRPREFIX}/_.cust.$c 2>&1 232 done 233) 234 235setup_nanobsd ( ) ( 236 echo "## configure nanobsd setup" 237 echo "### log: ${MAKEOBJDIRPREFIX}/_.dl" 238 239 ( 240 cd ${NANO_WORLDDIR} 241 242 # Move /usr/local/etc to /etc/local so that the /cfg stuff 243 # can stomp on it. Otherwise packages like ipsec-tools which 244 # have hardcoded paths under ${prefix}/etc are not tweakable. 245 if [ -d usr/local/etc ] ; then 246 ( 247 mkdir etc/local 248 cd usr/local/etc 249 find . -print | cpio -dumpl ../../../etc/local 250 cd .. 251 rm -rf etc 252 ln -s ../../etc/local etc 253 ) 254 fi 255 256 for d in var etc 257 do 258 # link /$d under /conf 259 # we use hard links so we have them both places. 260 # the files in /$d will be hidden by the mount. 261 # XXX: configure /$d ramdisk size 262 mkdir -p conf/base/$d conf/default/$d 263 find $d -print | cpio -dumpl conf/base/ 264 done 265 266 echo "$NANO_RAM_ETCSIZE" > conf/base/etc/md_size 267 echo "$NANO_RAM_TMPVARSIZE" > conf/base/var/md_size 268 269 # pick up config files from the special partition 270 echo "mount -o ro /dev/${NANO_DRIVE}s3" > conf/default/etc/remount 271 272 # Put /tmp on the /var ramdisk (could be symlink already) 273 rmdir tmp || true 274 rm tmp || true 275 ln -s var/tmp tmp 276 277 ) > ${MAKEOBJDIRPREFIX}/_.dl 2>&1 278) 279 280setup_nanobsd_etc ( ) ( 281 echo "## configure nanobsd /etc" 282 283 ( 284 cd ${NANO_WORLDDIR} 285 286 # create diskless marker file 287 touch etc/diskless 288 289 # Make root filesystem R/O by default 290 echo "root_rw_mount=NO" >> etc/defaults/rc.conf 291 292 # save config file for scripts 293 echo "NANO_DRIVE=${NANO_DRIVE}" > etc/nanobsd.conf 294 295 echo "/dev/${NANO_DRIVE}s1a / ufs ro 1 1" > etc/fstab 296 echo "/dev/${NANO_DRIVE}s3 /cfg ufs rw,noauto 2 2" >> etc/fstab 297 mkdir -p cfg 298 ) 299) 300 301prune_usr() ( 302 303 # Remove all empty directories in /usr 304 find ${NANO_WORLDDIR}/usr -type d -depth -print | 305 while read d 306 do 307 rmdir $d > /dev/null 2>&1 || true 308 done 309) 310 311create_i386_diskimage ( ) ( 312 echo "## build diskimage" 313 echo "### log: ${MAKEOBJDIRPREFIX}/_.di" 314 315 ( 316 echo $NANO_MEDIASIZE $NANO_IMAGES \ 317 $NANO_SECTS $NANO_HEADS \ 318 $NANO_CODESIZE $NANO_CONFSIZE $NANO_DATASIZE | 319 awk ' 320 { 321 printf "# %s\n", $0 322 323 # size of cylinder in sectors 324 cs = $3 * $4 325 326 # number of full cylinders on media 327 cyl = int ($1 / cs) 328 329 # output fdisk geometry spec, truncate cyls to 1023 330 if (cyl <= 1023) 331 print "g c" cyl " h" $4 " s" $3 332 else 333 print "g c" 1023 " h" $4 " s" $3 334 335 if ($7 > 0) { 336 # size of data partition in full cylinders 337 dsl = int (($7 + cs - 1) / cs) 338 } else { 339 dsl = 0; 340 } 341 342 # size of config partition in full cylinders 343 csl = int (($6 + cs - 1) / cs) 344 345 if ($5 == 0) { 346 # size of image partition(s) in full cylinders 347 isl = int ((cyl - dsl - csl) / $2) 348 } else { 349 isl = int (($5 + cs - 1) / cs) 350 } 351 352 # First image partition start at second track 353 print "p 1 165 " $3, isl * cs - $3 354 c = isl * cs; 355 356 # Second image partition (if any) also starts offset one 357 # track to keep them identical. 358 if ($2 > 1) { 359 print "p 2 165 " $3 + c, isl * cs - $3 360 c += isl * cs; 361 } 362 363 # Config partition starts at cylinder boundary. 364 print "p 3 165 " c, csl * cs 365 c += csl * cs 366 367 # Data partition (if any) starts at cylinder boundary. 368 if ($7 > 0) { 369 print "p 4 165 " c, dsl * cs 370 } else if ($7 < 0 && $1 > $c) { 371 print "p 4 165 " c, $1 - $c 372 } else if ($1 < c) { 373 print "Disk space overcommitted by", \ 374 c - $1, "sectors" > "/dev/stderr" 375 exit 2 376 } 377 } 378 ' > ${MAKEOBJDIRPREFIX}/_.fdisk 379 380 IMG=${MAKEOBJDIRPREFIX}/_.disk.full 381 MNT=${MAKEOBJDIRPREFIX}/_.mnt 382 mkdir -p ${MNT} 383 384 dd if=/dev/zero of=${IMG} bs=${NANO_SECTS}b \ 385 count=`expr ${NANO_MEDIASIZE} / ${NANO_SECTS}` 386 387 MD=`mdconfig -a -t vnode -f ${IMG} -x ${NANO_SECTS} -y ${NANO_HEADS}` 388 389 trap "df -i ${MNT} ; umount ${MNT} || true ; mdconfig -d -u $MD" 1 2 15 EXIT 390 391 fdisk -i -f ${MAKEOBJDIRPREFIX}/_.fdisk ${MD} 392 fdisk ${MD} 393 # XXX: params 394 # XXX: pick up cached boot* files, they may not be in image anymore. 395 boot0cfg -B -b ${NANO_WORLDDIR}/${NANO_BOOTLOADER} ${NANO_BOOT0CFG} ${MD} 396 bsdlabel -w -B -b ${NANO_WORLDDIR}/boot/boot ${MD}s1 397 bsdlabel ${MD}s1 398 399 # Create first image 400 newfs ${NANO_NEWFS} /dev/${MD}s1a 401 mount /dev/${MD}s1a ${MNT} 402 df -i ${MNT} 403 ( cd ${NANO_WORLDDIR} && find . -print | cpio -dump ${MNT} ) 404 df -i ${MNT} 405 ( cd ${MNT} && mtree -c ) > ${MAKEOBJDIRPREFIX}/_.mtree 406 ( cd ${MNT} && du -k ) > ${MAKEOBJDIRPREFIX}/_.du 407 umount ${MNT} 408 409 if [ $NANO_IMAGES -gt 1 -a $NANO_INIT_IMG2 -gt 0 ] ; then 410 # Duplicate to second image (if present) 411 dd if=/dev/${MD}s1 of=/dev/${MD}s2 bs=64k 412 mount /dev/${MD}s2a ${MNT} 413 for f in ${MNT}/etc/fstab ${MNT}/conf/base/etc/fstab 414 do 415 sed -i "" "s/${NANO_DRIVE}s1/${NANO_DRIVE}s2/g" $f 416 done 417 umount ${MNT} 418 419 fi 420 421 # Create Config slice 422 newfs ${NANO_NEWFS} /dev/${MD}s3 423 # XXX: fill from where ? 424 425 # Create Data slice, if any. 426 if [ $NANO_DATASIZE -gt 0 ] ; then 427 newfs ${NANO_NEWFS} /dev/${MD}s4 428 # XXX: fill from where ? 429 fi 430 431 dd if=/dev/${MD}s1 of=${MAKEOBJDIRPREFIX}/_.disk.image bs=64k 432 mdconfig -d -u $MD 433 ) > ${MAKEOBJDIRPREFIX}/_.di 2>&1 434) 435 436last_orders () ( 437 # Redefine this function with any last orders you may have 438 # after the build completed, for instance to copy the finished 439 # image to a more convenient place: 440 # cp ${MAKEOBJDIRPREFIX}/_.disk.image /home/ftp/pub/nanobsd.disk 441) 442 443####################################################################### 444# 445# Optional convenience functions. 446# 447####################################################################### 448 449####################################################################### 450# Common Flash device geometries 451# 452 453FlashDevice () { 454 if [ -d ${NANO_TOOLS} ] ; then 455 . ${NANO_TOOLS}/FlashDevice.sub 456 else 457 . ${NANO_SRC}/${NANO_TOOLS}/FlashDevice.sub 458 fi 459 sub_FlashDevice $1 $2 460} 461 462 463####################################################################### 464# Setup serial console 465 466cust_comconsole () ( 467 # Enable getty on console 468 sed -i "" -e /ttyd0/s/off/on/ ${NANO_WORLDDIR}/etc/ttys 469 470 # Disable getty on syscons devices 471 sed -i "" -e '/^ttyv[0-8]/s/ on/ off/' ${NANO_WORLDDIR}/etc/ttys 472 473 # Tell loader to use serial console early. 474 echo " -h" > ${NANO_WORLDDIR}/boot.config 475) 476 477####################################################################### 478# Allow root login via ssh 479 480cust_allow_ssh_root () ( 481 sed -i "" -e '/PermitRootLogin/s/.*/PermitRootLogin yes/' \ 482 ${NANO_WORLDDIR}/etc/ssh/sshd_config 483) 484 485####################################################################### 486# Install the stuff under ./Files 487 488cust_install_files () ( 489 cd ${NANO_TOOLS}/Files 490 find . -print | grep -v /CVS | cpio -dumpv ${NANO_WORLDDIR} 491) 492 493####################################################################### 494# Install packages from ${NANO_PACKAGE_DIR} 495 496cust_pkg () ( 497 498 # Copy packages into chroot 499 mkdir -p ${NANO_WORLDDIR}/Pkg 500 cp ${NANO_PACKAGE_DIR}/* ${NANO_WORLDDIR}/Pkg 501 502 # Count & report how many we have to install 503 todo=`ls ${NANO_WORLDDIR}/Pkg | wc -l` 504 echo "=== TODO: $todo" 505 ls ${NANO_WORLDDIR}/Pkg 506 echo "===" 507 while true 508 do 509 # Record how may we have now 510 have=`ls ${NANO_WORLDDIR}/var/db/pkg | wc -l` 511 512 # Attempt to install more packages 513 # ...but no more than 200 at a time due to pkg_add's internal 514 # limitations. 515 chroot ${NANO_WORLDDIR} sh -c \ 516 'ls Pkg/*tbz | xargs -n 200 pkg_add -F' || true 517 518 # See what that got us 519 now=`ls ${NANO_WORLDDIR}/var/db/pkg | wc -l` 520 echo "=== NOW $now" 521 ls ${NANO_WORLDDIR}/var/db/pkg 522 echo "===" 523 524 525 if [ $now -eq $todo ] ; then 526 echo "DONE $now packages" 527 break 528 elif [ $now -eq $have ] ; then 529 echo "FAILED: Nothing happened on this pass" 530 exit 2 531 fi 532 done 533 rm -rf ${NANO_WORLDDIR}/Pkg 534) 535 536####################################################################### 537# Convenience function: 538# Register $1 as customize function. 539 540customize_cmd () { 541 NANO_CUSTOMIZE="$NANO_CUSTOMIZE $1" 542} 543 544####################################################################### 545# 546# All set up to go... 547# 548####################################################################### 549 550usage () { 551 ( 552 echo "Usage: $0 [-b/-k/-w] [-c config_file]" 553 echo " -b suppress builds (both kernel and world)" 554 echo " -k suppress buildkernel" 555 echo " -w suppress buildworld" 556 echo " -c specify config file" 557 ) 1>&2 558 exit 2 559} 560 561####################################################################### 562# Parse arguments 563 564do_kernel=true 565do_world=true 566 567set +e 568args=`getopt bc:hkw $*` 569if [ $? -ne 0 ] ; then 570 usage 571 exit 2 572fi 573set -e 574 575set -- $args 576for i 577do 578 case "$i" 579 in 580 -b) 581 shift; 582 do_world=false 583 do_kernel=false 584 ;; 585 -k) 586 shift; 587 do_kernel=false 588 ;; 589 -c) 590 . "$2" 591 shift; 592 shift; 593 ;; 594 -h) 595 usage 596 ;; 597 -w) 598 shift; 599 do_world=false 600 ;; 601 --) 602 shift; 603 break; 604 esac 605done 606 607if [ $# -gt 0 ] ; then 608 echo "$0: Extraneous arguments supplied" 609 usage 610fi 611 612####################################################################### 613# Setup and Export Internal variables 614# 615if [ "x${NANO_OBJ}" = "x" ] ; then 616 MAKEOBJDIRPREFIX=/usr/obj/nanobsd.${NANO_NAME}/ 617 NANO_OBJ=${MAKEOBJDIRPREFIX} 618else 619 MAKEOBJDIRPREFIX=${NANO_OBJ} 620fi 621 622NANO_WORLDDIR=${MAKEOBJDIRPREFIX}/_.w 623NANO_MAKE_CONF=${MAKEOBJDIRPREFIX}/make.conf 624 625if [ -d ${NANO_TOOLS} ] ; then 626 true 627elif [ -d ${NANO_SRC}/${NANO_TOOLS} ] ; then 628 NANO_TOOLS=${NANO_SRC}/${NANO_TOOLS} 629else 630 echo "NANO_TOOLS directory does not exist" 1>&2 631 exit 1 632fi 633 634export MAKEOBJDIRPREFIX 635 636export NANO_ARCH 637export NANO_CODESIZE 638export NANO_CONFSIZE 639export NANO_CUSTOMIZE 640export NANO_DATASIZE 641export NANO_DRIVE 642export NANO_HEADS 643export NANO_IMAGES 644export NANO_MAKE_CONF 645export NANO_MEDIASIZE 646export NANO_NAME 647export NANO_NEWFS 648export NANO_OBJ 649export NANO_PMAKE 650export NANO_SECTS 651export NANO_SRC 652export NANO_TOOLS 653export NANO_WORLDDIR 654export NANO_BOOT0CFG 655export NANO_BOOTLOADER 656 657####################################################################### 658# And then it is as simple as that... 659 660if $do_world ; then 661 clean_build 662 make_conf_build 663 build_world 664else 665 echo "## Skipping buildworld (as instructed)" 666fi 667 668if $do_kernel ; then 669 build_kernel 670else 671 echo "## Skipping buildkernel (as instructed)" 672fi 673 674clean_world 675make_conf_install 676install_world 677install_etc 678setup_nanobsd_etc 679install_kernel 680 681run_customize 682setup_nanobsd 683prune_usr 684create_${NANO_ARCH}_diskimage 685last_orders 686 687echo "# NanoBSD image completed" 688