source: trunk/debirf/fs/usr/bin/debirf @ 996

Last change on this file since 996 was 996, checked in by jrollins, 11 years ago

tweak to create_debootstrap to simplify debootstrap options

  • Property svn:executable set to *
File size: 14.8 KB
Line 
1#!/bin/bash -e
2
3# debirf: script to build debirf system.
4#
5# The debirf scripts were written by
6# Jameson Rollins <jrollins@fifthhorseman.net>
7# and
8# Daniel Kahn Gillmor <dkg-debian.org@fifthhorseman.net>.
9#
10# They are Copyright 2007, and are all released under the GPL,
11# version 3 or later.
12
13###############################################################
14### VARIABLES
15
16CMD=$(basename $0)
17
18DEBIRF_COMMON=${DEBIRF_COMMON:-"/usr/share/debirf/common"}
19source "$DEBIRF_COMMON"
20
21# default build type
22export ROOT_BUILD=false
23
24# stages to run by default
25STAGE_ROOT=true
26STAGE_MODULES=true
27STAGE_INITRD=true
28
29ROOT_WARNING=true
30
31# location of devices.tar.gz file
32export DEVICE_ARCHIVE=/usr/share/debirf/devices.tar.gz
33
34# list of packages to include/exclude from debootstrap
35export INCLUDE=less,udhcpc
36export EXCLUDE=apt-utils,bsdmainutils,cron,ed,dhcp3-common,dhcp3-client,info,logrotate,man-db,manpages,tasksel,tasksel-data,tcpd,traceroute
37
38###############################################################
39### FUNCTIONS
40
41usage() {
42    cat <<EOF
43Usage: $CMD <subcommand> [options] [args]
44Debirf system tool.
45
46subcommands:
47  make [options] PROFILE    build debirf profile (make kernel and initramfs)
48    -c|--check-vars           check variables before make
49    -n|--new                  create new root, even if old one exists
50    -o|--overwrite            debootstrap on top of old root if it exists
51    -s|--skip                 skip debootstrap step if old root exists
52    -r|--root-build           use real chroot to build instead of fakechroot
53                              (requires superuser privileges or CAP_SYS_CHROOT)
54    -w|--no-warning           skip superuser warning
55    -g|--gpg-keyring=KEYRING  keyring to verify Releases during debootstrap
56                              (if 'noverify', don't verify Releases)           
57    -d|--no-initrd            do not make initramfs
58    -i|--initrd-only          just remake initramfs from existing root
59    -k|--kernel=KERNEL        install KERNEL .deb, instead of default kernel
60  enter PROFILE [CMDS]      enter shell in debirf profile root changes
61                            (optional execute CMDS in root and exit)
62  makeiso PROFILE           create a bootable ISO using the given profile
63                            (requires GRUB)
64  help                      this help
65
66EOF
67}
68
69usage_profile() {
70    cat <<EOF
71It looks like your profile is not correctly formed.  Please refer to the
72README file included with this package on how to setup a profile.
73EOF
74}
75
76failure() {
77    echo "$1" >&2
78    exit ${2:-'1'}
79}
80
81create_debootstrap() {
82    local OPTS="--include=$INCLUDE --exclude=$EXCLUDE $DEBIRF_DISTRO $DEBIRF_ROOT $DEBIRF_MIRROR"
83
84    if [ "$DEBIRF_KEYRING" != 'noverify' ] ; then
85        [ -r "$DEBIRF_KEYRING" ] || failure "Cannot read keyring '$DEBIRF_KEYRING' for debootstrap verification."
86        OPTS="--keyring=$DEBIRF_KEYRING $OPTS"
87    fi
88
89    mkdir -p "$DEBIRF_ROOT"
90
91    if [ "$ROOT_BUILD" = 'true' ] ; then
92        /usr/sbin/debootstrap $OPTS
93    else
94        fakeroot_if_needed fakechroot /usr/sbin/debootstrap --variant=fakechroot $OPTS
95    fi
96
97    fakeroot_if_needed mv "$DEBIRF_ROOT"/var/log/bootstrap.log "$DEBIRF_BUILDD"/.bootstrap.log
98}
99
100# fix the device tree in the debirf root if fakechroot variant was
101# used with debootstrap (default non-privileged behavior)
102fix_dev() {
103    if [ -L "$DEBIRF_ROOT"/dev -o ! -d "$DEBIRF_ROOT"/dev ] ; then
104        msg "fixing debirf root dev tree..."
105
106        # remove old dev
107        fakeroot_if_needed rm -f "$DEBIRF_ROOT"/dev
108
109        # create new dev from devices archive
110        fakeroot_if_needed sh -c "cd $DEBIRF_ROOT; tar -xzf $DEVICE_ARCHIVE"
111
112        # create /dev/console
113        fakeroot_if_needed sh -c "mknod $DEBIRF_ROOT/dev/console c 5 1; chmod 0600 $DEBIRF_ROOT/dev/console"
114    fi
115}
116
117# run modules in modules directory
118run_modules() {
119    fakeroot_if_needed run-parts --verbose --exit-on-error "$DEBIRF_MODULES"
120}
121
122# pack the rootfs archive
123# takes one input argument as name of output archive file
124pack_rootfs() {
125    # need to pack archive in fakechroot/chroot so that symlinks correctly
126    # point within debirf root, instead of to host path
127    fakeroot_if_needed fakechroot chroot "$DEBIRF_ROOT" sh -c "find * | cpio --create -H newc" | gzip > "$1"
128}
129export -f pack_rootfs
130
131
132## create_initrd functions
133# stupid simple method
134create_initrd_stupid_simple() {
135    fakeroot_if_needed ln -sf /sbin/init "$DEBIRF_ROOT/init"
136    pack_rootfs "$DEBIRF_INITRD"
137}
138
139# nested cpio archives
140create_initrd_nested() {
141    local util lib
142    local NEST_ROOT="$DEBIRF_BUILDD"/nest
143
144    # make the nested root
145    rm -rf "$NEST_ROOT"
146    mkdir -p "$NEST_ROOT"/{bin,lib}
147
148    # copy needed executables into nest
149    cp -f /bin/{busybox,cpio} "$NEST_ROOT"/bin/
150    for util in awk free grep gunzip ls mkdir mount sh umount ; do
151        ln "$NEST_ROOT"/bin/busybox "$NEST_ROOT"/bin/"$util"
152    done
153    cp -f /usr/lib/klibc/bin/run-init "$NEST_ROOT"/bin/
154
155    # copy in needed libraries
156    for lib in $(ldd "$NEST_ROOT"/bin/* | egrep '*.so.[[:digit:]]+ \(0x[[:xdigit:]]{8}\)$' | sed -r 's|.*[[:space:]](/[^[[:space:]]*)[[:space:]]\(0x[[:xdigit:]]{8}\)$|\1|' | sort -u) ; do
157        # pull libraries from most basic place libraries can live
158        # (avoid arch change between build env and debirf)
159        lib=/lib/$(basename "$lib")
160        echo -e "$lib\n$(readlink -f $lib)" | cpio --pass-through --make-directories "$NEST_ROOT"/
161    done
162    cp -f /lib/klibc-* "$NEST_ROOT"/lib/
163
164    # create nest init
165    cat > "$NEST_ROOT"/init <<EOF
166#!/bin/sh
167mkdir /proc
168mount -t proc proc /proc
169if (grep -q break=top /proc/cmdline); then
170  echo "honoring break=top kernel arg"
171  /bin/sh
172fi
173mkdir /newroot
174MEMSIZE=\$(free | grep 'Mem:' | awk '{ print \$2 }')
175mount -t tmpfs -o size=\${MEMSIZE}k tmpfs /newroot
176if (grep -q break=preunpack /proc/cmdline); then
177  echo "honoring break=preunpack kernel arg"
178  /bin/sh
179fi
180cd /newroot
181echo unpacking rootfs...
182# specify /bin/cpio so that it gets used instead of the busybox builtin
183# busybox cpio returns "need to fix this" when unpacking hard links
184gunzip - < /rootfs.cgz | /bin/cpio -i
185if (grep -q break=bottom /proc/cmdline); then
186  echo "honoring break=bottom kernel arg"
187  /bin/sh
188fi
189umount /proc
190echo running /sbin/init...
191exec /bin/run-init . /sbin/init < ./dev/console > ./dev/console
192EOF
193    chmod a+x "$NEST_ROOT"/init
194
195    msg "creating rootfs.cgz..."
196    fakeroot_if_needed ln -sf /sbin/init "$DEBIRF_ROOT/init"
197    pack_rootfs "$NEST_ROOT"/rootfs.cgz
198
199    msg "creating wrapper cgz..."
200    fakeroot_if_needed sh -c "cd $NEST_ROOT && find * | cpio --create -H newc" | gzip > "$DEBIRF_INITRD"
201}
202
203# setup profile environment
204setup_environment() {
205    # source debirf.conf defaults
206    source /usr/share/debirf/debirf.conf.defaults
207   
208    # check profile
209    if [ -d "$DEBIRF_PROFILE" ] ; then
210        echo "Loading profile '$DEBIRF_PROFILE'..."
211        DEBIRF_CONF="$DEBIRF_PROFILE/debirf.conf"
212        DEBIRF_MODULES="$DEBIRF_PROFILE/modules"
213    else
214        failure "Profile '$DEBIRF_PROFILE' not found."
215    fi
216   
217    # source profile debirf.conf
218    if [ -f "$DEBIRF_CONF" ] ; then
219        source "$DEBIRF_CONF"
220    else
221        echo "Configuration file '$DEBIRF_CONF' not found."
222        usage_profile
223        exit 1
224    fi
225
226    # check modules directory
227    if [ ! -d "$DEBIRF_MODULES" ] || [ -z "$(ls "$DEBIRF_MODULES")" ] ; then
228        echo "Modules directoy '$DEBIRF_MODULES' does not exist or is empty."
229        usage_profile
230        exit 1
231    fi
232    for MODULE in $(find "$DEBIRF_MODULES") ; do
233        if [ ! -s "$MODULE" ] ; then
234            failure "Module '$MODULE' is a broken link or empty file."
235        fi
236    done
237   
238    # check buildd
239    if [ -z "$DEBIRF_BUILDD" ] ; then
240        failure "DEBIRF_BUILDD is not set."
241    fi
242
243    # set root directory
244    DEBIRF_ROOT="$DEBIRF_BUILDD/root"
245
246    # set fakechroot save file
247    DEBIRF_FAKEROOT_STATE="$DEBIRF_BUILDD/.fakeroot-state.${DEBIRF_LABEL}"
248
249    # export all the DEBIRF_* environment variables:
250    for var in ${!DEBIRF_*}; do
251        if [ $var ] ; then
252            export $var
253        else
254            failure "Variable '$var' not properly set."
255        fi
256    done
257   
258    # check variables
259    if [ "$CHECK_VARS" ] ; then
260        echo "Debirf variables:"
261        env | /bin/grep "^DEBIRF_"
262        read -p "enter to continue: " OK
263    fi
264}
265
266# make profile
267make() {
268    # option parsing
269    TEMP=$(getopt --options -hcnosrwg:dik: --longoptions help,check-vars,new,overwrite,skip,root-build,no-warning,gpg-keyring:,no-initrd,initrd-only,kernel: -n "$CMD" -- "$@")
270
271    if [ $? != 0 ] ; then
272        echo "Invalid options." >&2 
273        usage
274        exit 1
275    fi
276   
277    # Note the quotes around `$TEMP': they are essential!
278    eval set -- "$TEMP"
279
280    while true ; do
281        case "$1" in
282            -c|--check-vars)
283                CHECK_VARS=true
284                shift 1
285                ;;
286            -n|--new)
287                WRITE_MODE=rewrite
288                shift 1
289                ;;
290            -o|--overwrite)
291                WRITE_MODE=overwrite
292                shift 1
293                ;;
294            -s|--skip)
295                WRITE_MODE=skip
296                shift 1
297                ;;
298            -r|--root-build)
299                ROOT_BUILD=true
300                shift 1
301                ;;
302            -w|--no-warning)
303                ROOT_WARNING=false
304                shift 1
305                ;;
306            -g|--gpg-keyring)
307                DEBIRF_KEYRING="$2"
308                shift 2
309                ;;
310            -d|--no-initrd)
311                STAGE_INITRD=false
312                shift 1
313                ;;
314            -i|--initrd-only)
315                STAGE_ROOT=false
316                STAGE_MODULES=false
317                shift 1
318                ;;
319            -k|--kernel)
320                DEBIRF_KERNEL_PACKAGE="$2"
321                shift 2
322                ;;
323            --)
324                shift
325                ;;
326            *)
327                if (( $# < 1 )) ; then
328                    echo "Improper number of input arguments."
329                    usage
330                    exit 1
331                fi
332                DEBIRF_PROFILE="$1"
333                break
334                ;;
335        esac
336    done
337   
338    if [ $(id -u) = '0' ] ; then
339        cat <<EOF
340Warning: You are running debirf as root.  There is a potential
341for improperly written modules to damage your system.
342EOF
343        if [ "$ROOT_WARNING" = 'true' ] ; then
344            read -p "Are you sure you wish to continue? [y|N]: " OK; OK=${OK:=N}
345            if [ "${OK/y/Y}" != 'Y' ] ; then
346                failure "aborting."
347            fi
348        fi
349    fi
350
351    setup_environment
352
353    if [ "$DEBIRF_KERNEL_PACKAGE" ] ; then
354        if [ -f "$DEBIRF_KERNEL_PACKAGE" ] ; then
355            echo "Using kernel package '$DEBIRF_KERNEL_PACKAGE'."
356        else
357            failure "Kernel package '$DEBIRF_KERNEL_PACKAGE' not found."
358        fi
359    fi
360   
361    ### BUILD ROOT
362    if [ "$STAGE_ROOT" = 'true' ] ; then
363        # determine write mode
364        if [ -d "$DEBIRF_ROOT" ] ; then
365            if [ -z "$WRITE_MODE" ] ; then
366                echo "Debirf root already exists.  Select one of the following:"
367                CASE1='new: delete the old root and create a new one'
368                CASE2='overwrite: leave the old root and debootstrap on top of it'
369                CASE3='skip: skip building the root and go right to installing modules'
370                CASE4='exit'
371                select CASE in "$CASE1" "$CASE2" "$CASE3" "$CASE4" ; do
372                    case "$REPLY" in
373                        1)
374                            WRITE_MODE=rewrite
375                            ;;
376                        2)
377                            WRITE_MODE=overwrite
378                            ;;
379                        3)
380                            WRITE_MODE=skip
381                            ;;
382                        *)
383                            failure "aborting."
384                            ;;
385                    esac
386                    break
387                done
388            fi
389        else
390            WRITE_MODE=new
391        fi
392        case "$WRITE_MODE" in
393            'new')
394                msg "creating debirf root..."
395                > "$DEBIRF_FAKEROOT_STATE"
396                create_debootstrap
397                ;;
398            'rewrite')
399                msg "clearing old debirf root..."
400                rm -rf "$DEBIRF_ROOT"
401                msg "creating debirf root..."
402                > "$DEBIRF_FAKEROOT_STATE"
403                create_debootstrap
404                ;;
405            'overwrite')
406                msg "overwriting old debirf root..."
407                create_debootstrap
408                ;;
409            'skip')
410                msg "skipping debootstrap..."
411                ;;
412            *)
413                failure "aborting."
414                ;;
415        esac
416       
417        # fix the dev tree if running as non-priv user (fakechroot debootstrap)
418        fix_dev
419       
420    else
421        echo "Not building root."
422    fi
423    ### END BUILD ROOT
424   
425    ### RUN MODULES
426    if [ "$STAGE_MODULES" = 'true' ] ; then
427        msg "executing modules..."
428        run_modules
429        msg "modules complete."
430    else
431        echo "Not running modules."
432    fi
433    ### END RUN MODULES
434
435    ### BUILD INITRD
436    if [ "$STAGE_INITRD" = 'true' ] ; then
437        if [ ! -d "$DEBIRF_ROOT" ] ; then
438            failure "Debirf root '$DEBIRF_ROOT' not found."
439        fi
440        # determine initrd name
441        KERNEL_VERS=$(ls -1 "$DEBIRF_ROOT/lib/modules" | head -n1)
442        DEBIRF_INITRD="${DEBIRF_BUILDD}/${DEBIRF_LABEL}_${DEBIRF_DISTRO}_${KERNEL_VERS}.cgz"
443       
444        msg "creating debirf initrd ('$DEBIRF_METHOD')..."
445        create_initrd_${DEBIRF_METHOD} "$DEBIRF_INITRD"
446       
447        # final output
448        DEBIRF_KERNEL=$(ls "$DEBIRF_BUILDD" | grep "vmlinu" | grep "$KERNEL_VERS$")
449        msg "debirf initrd created."
450        if [ "$DEBIRF_BUILDD/$DEBIRF_KERNEL" ] ; then
451            msg "kernel: $DEBIRF_BUILDD/$DEBIRF_KERNEL"
452        fi
453        msg "initrd: $DEBIRF_INITRD"
454    else
455        echo "Not creating initramfs."
456    fi
457    ### END BUILD INITRD
458}
459
460# enter profile root
461enter() {
462    DEBIRF_PROFILE="$1"
463    shift
464
465    setup_environment
466
467    if [ "$1" ] ; then
468        fakeroot_if_needed debirf_exec "$@"
469    else
470        fakeroot_if_needed debirf_exec bash -i
471    fi
472}
473
474# create an ISO from the given kernel and initramfs (requires GRUB,
475# see:
476# http://www.gnu.org/software/grub/manual/html_node/Making-a-GRUB-bootable-CD-ROM.html)
477makeiso() {
478    DEBIRF_PROFILE="$1"
479    shift
480    (which mkisofs > /dev/null) || failure "mkisofs is not in your path.  Maybe you need to install it?"
481
482    [ -d "$DEBIRF_PROFILE" ] || failure "'$DEBIRF_PROFILE' does not seem to be a directory"
483
484    cd "$DEBIRF_PROFILE" || failure "Could not enter profile directory '$DEBIRF_PROFILE'."
485    local KERNEL=${KERNEL:-$(echo "vmlinu"*)}
486    local INITRAMFS=${INITRAMFS:-$(echo "debirf-"*.cgz)}
487
488    # FIXME: it would be best to pull the name of the architecture
489    # exactly instead of using shell globbing to guess at it:
490    local GRUB_ELTORITO=${GRUB_ELTORITO:-$(echo "/usr/lib/grub/"*"-pc/stage2_eltorito")}
491
492    ls -l "$KERNEL" > /dev/null || failure "Failed to find a single kernel in '$DEBIRF_PROFILE'"
493    ls -l "$INITRAMFS" > /dev/null || failure "Failed to find a single initramfs in '$DEBIRF_PROFILE'"
494    [ -r "$GRUB_ELTORITO" ] || failure "Failed to find a grub El Torito stage2 loader."
495
496    # get rid of the "iso" directory if it exists.
497    rm -rf iso
498    mkdir -p iso/boot/grub
499
500    # use hard links to avoid massive copying time and mkisofs's
501    # warning about -f (we're almost certainly on the same filesystem):
502    ln "$KERNEL" iso/ || failure "Failed to link kernel into iso"
503    ln "$INITRAMFS" iso/ || failure "Failed to link initramfs into iso"
504
505    # this file is very likely not on the same filesystem (and it's
506    # likely to be small) so copying it makes more sense than linking:
507    cp "$GRUB_ELTORITO" iso/boot/grub/
508    cat >iso/boot/grub/menu.lst <<EOF
509serial --unit=0 --speed=115200 --word=8 --parity=no --stop=1
510terminal --timeout=10 serial console
511
512title        Debirf ($DEBIRF_PROFILE) (created $(date -R))
513kernel       /$KERNEL
514initrd       /$INITRAMFS
515EOF
516
517    mkisofs -R -b boot/grub/stage2_eltorito -no-emul-boot -boot-load-size 4 -boot-info-table -o "debirf-$DEBIRF_PROFILE.iso" iso
518    # do we need to clean up the iso/ directory so that this can be run again?   
519}
520
521
522###############################################################
523### MAIN
524
525COMMAND="$1"
526[ "$COMMAND" ] || failure "Type '$CMD help' for usage."
527shift
528
529case $COMMAND in
530    'make'|'m')
531        make "$@"
532        ;;
533    'makeiso'|'i')
534        makeiso "$@"
535        ;;
536    'enter'|'e')
537        enter "$@"
538        ;;
539    'help'|'h'|'?')
540        usage
541        ;;
542    *)
543        failure "Unknown command: '$COMMAND'
544Type '$CMD help' for usage."
545        ;;
546esac
Note: See TracBrowser for help on using the repository browser.