Some cleanup + ntp, and disconnected operations.
[bootcd.git] / build.sh
1 #!/bin/bash
2 #
3 # Builds custom BootCD ISO and USB images in the current
4 # directory. For backward compatibility, if an old-style static
5 # configuration is specified, that configuration file will be parsed
6 # instead of the current PLC configuration in
7 # /etc/planetlab/plc_config.
8 #
9 # Aaron Klingaman <alk@absarokasoft.com>
10 # Mark Huang <mlhuang@cs.princeton.edu>
11 # Copyright (C) 2004-2006 The Trustees of Princeton University
12 #
13 # $Id: build.sh,v 1.42 2006/11/22 20:40:48 mef Exp $
14 #
15
16 PATH=/sbin:/bin:/usr/sbin:/usr/bin
17
18 CONFIGURATION=default
19 NODE_CONFIGURATION_FILE=
20 ALL=0
21 # Leave 4 MB of free space
22 FREE_SPACE=4096
23
24 usage()
25 {
26     echo "Usage: build.sh [OPTION]..."
27     echo "      -c name         (Deprecated) Static configuration to use (default: $CONFIGURATION)"
28     echo "      -f planet.cnf   Node to customize CD for (default: none)"
29     echo "      -a              Build all images (default: only base images)"
30     echo "      -h              This message"
31     exit 1
32 }
33
34 # Get options
35 while getopts "c:f:ah" opt ; do
36     case $opt in
37         c)
38             CONFIGURATION=$OPTARG
39             ;;
40         f)
41             NODE_CONFIGURATION_FILE=$OPTARG
42             ;;
43         a)
44             ALL=1
45             ;;
46         h|*)
47             usage
48             ;;
49     esac
50 done
51
52 # Do not tolerate errors
53 set -e
54
55 # Change to our source directory
56 srcdir=$(cd $(dirname $0) && pwd -P)
57 pushd $srcdir
58
59 # Root of the isofs
60 isofs=$PWD/build/isofs
61
62 # Build reference image if it does not exist. This should only need to
63 # be executed once at build time, never at run time.
64 if [ ! -f $isofs/bootcd.img ] ; then
65     ./prep.sh
66 fi
67
68 # build/version.txt written by prep.sh
69 BOOTCD_VERSION=$(cat build/version.txt)
70
71 if [ -f /etc/planetlab/plc_config ] ; then
72     # Source PLC configuration
73     . /etc/planetlab/plc_config
74 fi
75
76 ### This support for backwards compatibility can be taken out in the
77 ### future. RC1 based MyPLCs set $PLC_BOOT_SSL_CRT in the plc_config
78 ### file, but >=RC2 based bootcd assumes that $PLC_BOOT_CA_SSL_CRT is
79 ### set.
80 if [ -z "$PLC_BOOT_CA_SSL_CRT" -a ! -z "$PLC_BOOT_SSL_CRT" ] ; then
81     PLC_BOOT_CA_SSL_CRT=$PLC_BOOT_SSL_CRT
82 fi
83
84 # If PLC configuration is not valid, try a static configuration
85 if [ -z "$PLC_BOOT_CA_SSL_CRT" -a -d configurations/$CONFIGURATION ] ; then
86     # (Deprecated) Source static configuration
87     . configurations/$CONFIGURATION/configuration
88     PLC_NAME="PlanetLab"
89     PLC_MAIL_SUPPORT_ADDRESS="support@planet-lab.org"
90     PLC_WWW_HOST="www.planet-lab.org"
91     PLC_WWW_PORT=80
92     if [ -n "$EXTRA_VERSION" ] ; then
93         BOOTCD_VERSION="$BOOTCD_VERSION $EXTRA_VERSION"
94     fi
95     PLC_BOOT_HOST=$PRIMARY_SERVER
96     PLC_BOOT_SSL_PORT=$PRIMARY_SERVER_PORT
97     PLC_BOOT_CA_SSL_CRT=configurations/$CONFIGURATION/$PRIMARY_SERVER_CERT
98     PLC_ROOT_GPG_KEY_PUB=configurations/$CONFIGURATION/$PRIMARY_SERVER_GPG
99 fi
100
101 FULL_VERSION_STRING="$PLC_NAME BootCD $BOOTCD_VERSION"
102
103 echo "* Building images for $FULL_VERSION_STRING"
104
105 # From within a myplc chroot /tmp is too small to build
106 # all possible images, whereas /data is part of the host
107 # filesystem and usually has sufficient space.  What we
108 # should do is check whether the expected amount of space
109 # is available.
110 [ -d /data ] && BUILDTMP=/data || BUILDTMP=/tmp
111
112 # Root of the ISO and USB images
113 echo "* Populating root filesystem..."
114 overlay=$(mktemp -d ${BUILDTMP}/overlay.XXXXXX)
115 install -d -m 755 $overlay
116 trap "rm -rf $overlay" ERR INT
117
118 # Create version files
119 echo "* Creating version files"
120
121 # Boot Manager compares pl_version in both places to make sure that
122 # the right CD is mounted. We used to boot from an initrd and mount
123 # the CD on /usr. Now we just run everything out of the initrd.
124 for file in $overlay/pl_version $overlay/usr/isolinux/pl_version ; do
125     mkdir -p $(dirname $file)
126     echo "$FULL_VERSION_STRING" >$file
127 done
128
129 # Install boot server configuration files
130 echo "* Installing boot server configuration files"
131
132 # We always intended to bring up and support backup boot servers,
133 # but never got around to it. Just install the same parameters for
134 # both for now.
135 for dir in $overlay/usr/boot $overlay/usr/boot/backup ; do
136         install -D -m 644 $PLC_BOOT_CA_SSL_CRT $dir/cacert.pem
137         install -D -m 644 $PLC_ROOT_GPG_KEY_PUB $dir/pubring.gpg
138         echo "$PLC_BOOT_HOST" >$dir/boot_server
139         echo "$PLC_BOOT_SSL_PORT" >$dir/boot_server_port
140         echo "/boot/" >$dir/boot_server_path
141 done
142
143 # (Deprecated) Install old-style boot server configuration files
144 install -D -m 644 $PLC_BOOT_CA_SSL_CRT $overlay/usr/bootme/cacert/$PLC_BOOT_HOST/cacert.pem
145 echo "$FULL_VERSION_STRING" >$overlay/usr/bootme/ID
146 echo "$PLC_BOOT_HOST" >$overlay/usr/bootme/BOOTSERVER
147 echo "$PLC_BOOT_HOST" >$overlay/usr/bootme/BOOTSERVER_IP
148 echo "$PLC_BOOT_SSL_PORT" >$overlay/usr/bootme/BOOTPORT
149
150 # Generate /etc/issue
151 echo "* Generating /etc/issue"
152
153 if [ "$PLC_WWW_PORT" = "443" ] ; then
154     PLC_WWW_URL="https://$PLC_WWW_HOST/"
155 elif [ "$PLC_WWW_PORT" != "80" ] ; then
156     PLC_WWW_URL="http://$PLC_WWW_HOST:$PLC_WWW_PORT/"
157 else
158     PLC_WWW_URL="http://$PLC_WWW_HOST/"
159 fi
160
161 mkdir -p $overlay/etc
162 cat >$overlay/etc/issue <<EOF
163 $FULL_VERSION_STRING
164 $PLC_NAME Node: \n
165 Kernel \r on an \m
166 $PLC_WWW_URL
167
168 This machine is a node in the $PLC_NAME distributed network.  It has
169 not fully booted yet. If you have cancelled the boot process at the
170 request of $PLC_NAME Support, please follow the instructions provided
171 to you. Otherwise, please contact $PLC_MAIL_SUPPORT_ADDRESS.
172
173 Console login at this point is restricted to root. Provide the root
174 password of the default $PLC_NAME Central administrator account at the
175 time that this CD was created.
176
177 EOF
178
179 # Set root password
180 echo "* Setting root password"
181
182 if [ -z "$ROOT_PASSWORD" ] ; then
183     # Generate an encrypted password with crypt() if not defined
184     # in a static configuration.
185     ROOT_PASSWORD=$(python <<EOF
186 import crypt, random, string
187 salt = [random.choice(string.letters + string.digits + "./") for i in range(0,8)]
188 print crypt.crypt('$PLC_ROOT_PASSWORD', '\$1\$' + "".join(salt) + '\$')
189 EOF
190 )
191 fi
192
193 # build/passwd copied out by prep.sh
194 sed -e "s@^root:[^:]*:\(.*\)@root:$ROOT_PASSWORD:\1@" build/passwd \
195     >$overlay/etc/passwd
196
197 # Install node configuration file (e.g., if node has no floppy disk or USB slot)
198 if [ -f "$NODE_CONFIGURATION_FILE" ] ; then
199     echo "* Installing node configuration file"
200     install -D -m 644 $NODE_CONFIGURATION_FILE $overlay/usr/boot/plnode.txt
201 fi
202
203 # Pack overlay files into a compressed archive
204 echo "* Compressing overlay image"
205 (cd $overlay && find . | cpio --quiet -c -o) | gzip -9 >$isofs/overlay.img
206
207 rm -rf $overlay
208 trap - ERR INT
209
210 # Calculate ramdisk size (total uncompressed size of both archives)
211 ramdisk_size=$(gzip -l $isofs/bootcd.img $isofs/overlay.img | tail -1 | awk '{ print $2; }') # bytes
212 ramdisk_size=$((($ramdisk_size + 1023) / 1024)) # kilobytes
213
214 # Write isolinux configuration
215 echo "$FULL_VERSION_STRING" >$isofs/pl_version
216 cat >$isofs/isolinux.cfg <<EOF
217 DEFAULT kernel
218 APPEND ramdisk_size=$ramdisk_size initrd=bootcd.img,overlay.img root=/dev/ram0 rw
219 DISPLAY pl_version
220 PROMPT 0
221 TIMEOUT 40
222 EOF
223
224 # Change back to output directory
225 popd
226
227 # Create ISO image
228 echo "* Creating ISO image"
229 iso="$PLC_NAME-BootCD-$BOOTCD_VERSION.iso"
230 mkisofs -o "$iso" \
231     -R -allow-leading-dots -J -r \
232     -b isolinux.bin -c boot.cat \
233     -no-emul-boot -boot-load-size 4 -boot-info-table \
234     $isofs
235
236 echo "* Creating ISO image with serial line support"
237 iso="$PLC_NAME-BootCD-$BOOTCD_VERSION-serial.iso"
238 cat >$isofs/isolinux.cfg <<EOF
239 SERIAL 0 115200
240 PROMPT 0
241 TIMEOUT 120
242 DISPLAY pl_version
243 DEFAULT serial
244 LABEL serial
245         KERNEL kernel
246         APPEND ramdisk_size=$ramdisk_size initrd=bootcd.img,overlay.img root=/dev/ram0 rw  console=ttyS0,115200n8
247 EOF
248 mkisofs -o "$iso" \
249     -R -allow-leading-dots -J -r \
250     -b isolinux.bin -c boot.cat \
251     -no-emul-boot -boot-load-size 4 -boot-info-table \
252     $isofs
253
254 # Create USB image
255 echo -n "* Creating USB image... "
256 usb="$PLC_NAME-BootCD-$BOOTCD_VERSION.usb"
257
258 mkfs.vfat -C "$usb" $(($(du -sk $isofs | awk '{ print $1; }') + $FREE_SPACE))
259
260 # Mount it
261 tmp=$(mktemp -d ${BUILDTMP}/bootcd.XXXXXX)
262 mount -o loop "$usb" $tmp
263 trap "umount $tmp; rm -rf $tmp" ERR INT
264
265 # Populate it
266 echo -n " populating USB image... "
267 (cd $isofs && find . | cpio -p -d -u $tmp/)
268
269 # Use syslinux instead of isolinux to make the image bootable
270 rm -f $tmp/isolinux.cfg
271 cat >$tmp/syslinux.cfg <<EOF
272 DEFAULT kernel
273 APPEND ramdisk_size=$ramdisk_size initrd=bootcd.img,overlay.img root=/dev/ram0 rw
274 DISPLAY pl_version
275 PROMPT 0
276 TIMEOUT 40
277 EOF
278 umount $tmp
279 rmdir $tmp
280 trap - ERR INT
281
282 echo "making USB image bootable."
283 $srcdir/syslinux/unix/syslinux "$usb"
284
285
286 # Create USB image with serial line support
287 echo -n "* Creating USB image... "
288 usb="$PLC_NAME-BootCD-$BOOTCD_VERSION-serial.usb"
289
290 mkfs.vfat -C "$usb" $(($(du -sk $isofs | awk '{ print $1; }') + $FREE_SPACE))
291
292 # Mount it
293 tmp=$(mktemp -d ${BUILDTMP}/bootcd.XXXXXX)
294 mount -o loop "$usb" $tmp
295 trap "umount $tmp; rm -rf $tmp" ERR INT
296
297 # Populate it
298 echo -n " populating USB image... "
299 (cd $isofs && find . | cpio -p -d -u $tmp/)
300
301 # Use syslinux instead of isolinux to make the image bootable
302 rm -f $tmp/isolinux.cfg
303 cat >$tmp/syslinux.cfg <<EOF
304 SERIAL 0 115200
305 PROMPT 0
306 TIMEOUT 120
307 DISPLAY pl_version
308 DEFAULT serial
309 LABEL serial
310         KERNEL kernel
311         APPEND ramdisk_size=$ramdisk_size initrd=bootcd.img,overlay.img root=/dev/ram0 rw  console=ttyS0,115200n8
312 EOF
313
314 umount $tmp
315 rmdir $tmp
316 trap - ERR INT
317
318 echo "making USB image with serial line support bootable."
319 $srcdir/syslinux/unix/syslinux "$usb"
320
321 [ $ALL -eq 0 ] && exit 0
322
323 # Setup CRAMFS related support
324 echo "* Setting up CRAMFS-based images"
325 tmp=$(mktemp -d ${BUILDTMP}/bootcd.XXXXXX)
326 cramfs=$(mktemp ${BUILDTMP}/cramfs.XXXXXX)
327 trap "$tmp; rm -rf $tmp $cramfs" ERR INT
328 pushd $tmp
329 gzip -d -c $isofs/bootcd.img  | cpio -diu
330 gzip -d -c $isofs/overlay.img | cpio -diu
331
332 # clean out unnecessary rpm lib
333 echo "* clearing var/lib/rpm/*"
334 rm -f var/lib/rpm/*
335
336 # bootcd requires this directory
337 mkdir -p mnt/confdevice
338
339 # relocate various directory to /tmp
340 rm -rf root
341 ln -fs /tmp/root root
342 ln -fs /sbin/init linuxrc 
343 ln -fs /tmp/resolv.conf etc/resolv.conf
344 ln -fs /tmp/etc/mtab etc/mtab
345
346 # have pl_rsysinit copy over appropriate etc & var directories into /tmp/etc/
347 # make /tmp/etc
348 echo "* renaming dirs in ./etc"
349 pushd etc
350 for dir in `find * -type d -prune | grep -v rc.d`; do mv ${dir} ${dir}_o; ln -fs /tmp/etc/${dir} ${dir} ; done
351 popd
352
353 echo "* renaming dirs in ./var"
354 # rename all top-level directories and put in a symlink to /tmp/var
355 pushd var
356 for dir in `find * -type d -prune`; do mv ${dir} ${dir}_o; ln -fs /tmp/var/${dir} ${dir} ; done
357 popd
358
359 #overwrite fstab to mount / as cramfs and /tmp as tmpfs
360 echo "* Overwriting etc/fstab to use cramfs and tmpfs"
361 rm -f ./etc/fstab
362 cat >./etc/fstab <<EOF
363 /dev/ram0     /              cramfs     ro              0 0
364 none          /dev/pts       devpts     gid=5,mode=620  0 0
365 none          /proc          proc       defaults        0 0
366 none          /sys           sysfs      defaults        0 0
367 EOF
368
369 pushd dev
370 rm -f console
371 mknod console c 5 1
372 #for i in 0 1 2 3 4 5 6 7 8; do rm -f ram${i} ; done
373 #for i in 0 1 2 3 4 5 6 7 8; do mknod ram${i} b 1 ${i} ; done
374 #ln -fs ram1 ram
375 #ln -fs ram0 ramdisk
376 popd
377
378 # update etc/inittab to start with pl_rsysinit
379 sed -i 's,pl_sysinit,pl_rsysinit,' etc/inittab
380
381 # modify inittab to have a serial console
382 echo "T0:23:respawn:/sbin/agetty -L ttyS0 9600 vt100" >> etc/inittab
383 # and let root log in
384 echo "ttyS0" >> etc/securetty
385
386 #calculate the size of /tmp based on the size of /etc & /var + 8MB slack
387 etcsize=$(du -s ./etc | awk '{ print $1 }')
388 varsize=$(du -s ./etc | awk '{ print $1 }')
389 let msize=($vsize+$esize+8192)/1024
390
391
392 # generate pl_rsysinit
393 cat > etc/rc.d/init.d/pl_rsysinit <<EOF
394 #!/bin/sh
395 # generated by build.sh
396 echo -n "pl_rsysinit: preparing /etc and /var for pl_sysinit..."
397 mount -t tmpfs -orw,size=${msize}M,mode=1777 tmpfs /tmp
398 mkdir -p /tmp/root
399 mkdir -p /tmp/etc
400 touch /tmp/etc/resolv.conf
401 touch /tmp/etc/mtab
402 mkdir -p /tmp/var
403
404 # make mtab happy
405 echo "tmpfs /tmp tmpfs rw,size=${msize}M,mode=1777 1 1" > /tmp/etc/mtab
406
407 # copy over directory contents of all _o directories from /etc and /var
408 # /tmp/etc and /tmp/var
409 pushd /etc
410 for odir in \$(cd /etc && ls -d *_o); do dir=\$(echo \$odir | sed 's,\_o$,,'); (mkdir -p /tmp/etc/\$dir && cd \$odir && find . | cpio -p -d -u /tmp/etc/\$dir); done
411 popd
412 pushd /var
413 for odir in \$(cd /var && ls -d *_o); do dir=\$(echo \$odir | sed 's,\_o$,,'); (mkdir -p /tmp/var/\$dir && cd \$odir && find . | cpio -p -d -u /tmp/var/\$dir); done
414 popd
415
416 echo "done"
417 # hand over to pl_sysinit
418 echo "pl_rsysinit: handing over to pl_sysinit"
419 /etc/init.d/pl_sysinit
420 EOF
421 chmod +x etc/rc.d/init.d/pl_rsysinit
422
423 popd
424
425 chown -R 0.0 $cramfs
426
427 #create the cramfs image
428 echo "* Creating cramfs image"
429 mkfs.cramfs $tmp/ $cramfs
430 cramfs_size=$(($(du -sk $cramfs | awk '{ print $1; }')))
431 mv $cramfs ${BUILDTMP}/cramfs.img
432 rm -rf $tmp
433 trap - ERR INT
434
435 # Create ISO CRAMFS image
436 echo "* Creating ISO CRAMFS-based image"
437 iso="$PLC_NAME-BootCD-$BOOTCD_VERSION-cramfs.iso"
438
439 tmp=$(mktemp -d ${BUILDTMP}/bootcd.XXXXXX)
440 trap "$tmp; rm -rf $tmp" ERR INT
441 (cd $isofs && find . | grep -v "\.img$" | cpio -p -d -u $tmp/)
442 cat >$tmp/isolinux.cfg <<EOF
443 DEFAULT kernel
444 APPEND ramdisk_size=$cramfs_size initrd=cramfs.img root=/dev/ram0 ro
445 DISPLAY pl_version
446 PROMPT 0
447 TIMEOUT 40
448 EOF
449
450 cp ${BUILDTMP}/cramfs.img $tmp
451 mkisofs -o "$iso" \
452     -R -allow-leading-dots -J -r \
453     -b isolinux.bin -c boot.cat \
454     -no-emul-boot -boot-load-size 4 -boot-info-table \
455     $tmp
456
457 # Create ISO CRAMFS image with serial line support
458 echo "* Creating ISO image with cramfs and serial line support"
459 cat >$tmp/isolinux.cfg <<EOF
460 SERIAL 0 115200
461 PROMPT 0
462 TIMEOUT 120
463 DISPLAY pl_version
464 DEFAULT serial
465 LABEL serial
466         KERNEL kernel
467         APPEND ramdisk_size=$cramfs_size initrd=cramfs.img root=/dev/ram0 ro  console=ttyS0,115200n8
468 EOF
469
470 iso="$PLC_NAME-BootCD-$BOOTCD_VERSION-cramfs-serial.iso"
471 mkisofs -o "$iso" \
472     -R -allow-leading-dots -J -r \
473     -b isolinux.bin -c boot.cat \
474     -no-emul-boot -boot-load-size 4 -boot-info-table \
475     $tmp
476
477 rm -rf $tmp
478 trap - ERR INT
479
480 # Create USB CRAMFS based image
481 echo "* Creating USB CRAMFS based image"
482 usb="$PLC_NAME-BootCD-$BOOTCD_VERSION-cramfs.usb"
483
484 let vfat_size=${cramfs_size}+$FREE_SPACE
485
486 # Make VFAT filesystem for USB
487 mkfs.vfat -C "$usb" $vfat_size
488
489 # Mount it
490 tmp=$(mktemp -d ${BUILDTMP}/bootcd.XXXXXX)
491 mount -o loop "$usb" $tmp
492 trap "umount $tmp; rm -rf $tmp ${BUILDTMP}/cramfs.img" ERR INT
493
494 # Populate it
495 echo "* Populating USB with overlay images and cramfs"
496 (cd $isofs && find . | grep -v "\.img$" | cpio -p -d -u $tmp/)
497 cp ${BUILDTMP}/cramfs.img $tmp/
498
499 # Use syslinux instead of isolinux to make the image bootable
500 cat >$tmp/syslinux.cfg <<EOF
501 TIMEOUT 120
502 DISPLAY pl_version
503 DEFAULT vga
504 LABEL vga
505         KERNEL kernel
506         APPEND ramdisk_size=$cramfs_size initrd=cramfs.img root=/dev/ram0 ro
507 EOF
508 umount $tmp
509 rmdir $tmp
510 trap - ERR INT
511
512 echo "* Making USB CRAMFS based image bootable"
513 $srcdir/syslinux/unix/syslinux "$usb"
514
515 # Create USB CRAMFS based image w/ serial line support
516 echo "* Creating USB CRAMFS based image w/ serial line support"
517 usb="$PLC_NAME-BootCD-$BOOTCD_VERSION-cramfs-serial.usb"
518
519 let vfat_size=${cramfs_size}+$FREE_SPACE
520
521 # Make VFAT filesystem for USB
522 mkfs.vfat -C "$usb" $vfat_size
523
524 # Mount it
525 tmp=$(mktemp -d ${BUILDTMP}/bootcd.XXXXXX)
526 mount -o loop "$usb" $tmp
527 trap "umount $tmp; rm -rf $tmp ${BUILDTMP}/cramfs.img" ERR INT
528
529 # Populate it
530 echo "* Populating USB with overlay images and cramfs"
531 (cd $isofs && find . | grep -v "\.img$" | cpio -p -d -u $tmp/)
532 cp ${BUILDTMP}/cramfs.img $tmp/
533
534 # Use syslinux instead of isolinux to make the image bootable
535 cat >$tmp/syslinux.cfg <<EOF
536 SERIAL 0 9600
537 PROMPT 0
538 TIMEOUT 120
539 DISPLAY pl_version
540 DEFAULT serial
541 LABEL serial
542         KERNEL kernel
543         APPEND ramdisk_size=$cramfs_size initrd=cramfs.img root=/dev/ram0 ro  console=ttyS0,9600n8
544 EOF
545 umount $tmp
546 rmdir $tmp
547 trap - ERR INT
548
549 echo "* Making USB CRAMFS based image /w serial line support bootable"
550 $srcdir/syslinux/unix/syslinux "$usb"
551
552 exit 0