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

Last change on this file since 1000 was 1000, checked in by Daniel Kahn Gillmor, 11 years ago

debirf: revert changes from r996, since they break when the user supplies keyrings with spaces in the filenames.

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