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

Last change on this file since 941 was 941, checked in by jrollins, 5 years ago

debirf: fixed #81

  • Property svn:executable set to *
File size: 12.2 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    -d|--no-initrd            do not make initramfs
56    -i|--initrd-only          just remake initramfs from existing root
57    -k|--kernel=KERNEL        install KERNEL .deb, instead of default kernel
58  enter PROFILE [CMDS]      enter shell in debirf profile root changes
59                            (optional execute CMDS in root and exit)
60  help                      this help
61
62EOF
63}
64
65usage_profile() {
66    cat <<EOF
67It looks like your profile is not correctly formed.  Please refer to the
68README file included with this package on how to setup a profile.
69EOF
70}
71
72failure() {
73    echo "$1" >&2
74    exit ${2:-'1'}
75}
76
77create_debootstrap() {
78    mkdir -p "$DEBIRF_ROOT"
79    if [ "$ROOT_BUILD" = 'true' ] ; then
80        /usr/sbin/debootstrap --exclude="$EXCLUDE" "$DEBIRF_DISTRO" "$DEBIRF_ROOT" "$DEBIRF_MIRROR"
81    else
82        fakeroot_if_needed fakechroot /usr/sbin/debootstrap --variant=fakechroot --include="$INCLUDE" --exclude="$EXCLUDE" "$DEBIRF_DISTRO" "$DEBIRF_ROOT" "$DEBIRF_MIRROR"
83    fi
84    fakeroot_if_needed mv "$DEBIRF_ROOT"/var/log/bootstrap.log "$DEBIRF_BUILDD"/.bootstrap.log
85}
86
87# fix the device tree in the debirf root if fakechroot variant was
88# used with debootstrap (default non-privileged behavior)
89fix_dev() {
90    if [ -L "$DEBIRF_ROOT"/dev -o ! -d "$DEBIRF_ROOT"/dev ] ; then
91        msg "fixing debirf root dev tree..."
92
93        # remove old dev
94        fakeroot_if_needed rm -f "$DEBIRF_ROOT"/dev
95
96        # create new dev from devices archive
97        fakeroot_if_needed sh -c "cd $DEBIRF_ROOT; tar -xzf $DEVICE_ARCHIVE"
98
99        # create /dev/console
100        fakeroot_if_needed sh -c "mknod $DEBIRF_ROOT/dev/console c 5 1; chmod 0600 $DEBIRF_ROOT/dev/console"
101    fi
102}
103
104# run modules in modules directory
105run_modules() {
106    fakeroot_if_needed run-parts --verbose --exit-on-error "$DEBIRF_MODULES"
107}
108
109# pack the rootfs archive
110# takes one input argument as name of output archive file
111pack_rootfs() {
112    # need to pack archive in fakechroot/chroot so that symlinks correctly
113    # point within debirf root, instead of to host path
114    fakeroot_if_needed fakechroot chroot "$DEBIRF_ROOT" sh -c "find * | cpio --create -H newc" | gzip > "$1"
115}
116export -f pack_rootfs
117
118
119## create_initrd functions
120# stupid simple method
121create_initrd_stupid_simple() {
122    fakeroot_if_needed ln -sf /sbin/init "$DEBIRF_ROOT/init"
123    pack_rootfs "$DEBIRF_INITRD"
124}
125
126# nested cpio archives
127create_initrd_nested() {
128    local util lib
129    local NEST_ROOT="$DEBIRF_BUILDD"/nest
130
131    # make the nested root
132    rm -rf "$NEST_ROOT"
133    mkdir -p "$NEST_ROOT"/{bin,lib}
134
135    # copy needed executables into nest
136    cp -f /bin/{busybox,cpio} "$NEST_ROOT"/bin/
137    for util in awk free grep gunzip ls mkdir mount sh umount ; do
138        ln "$NEST_ROOT"/bin/busybox "$NEST_ROOT"/bin/"$util"
139    done
140    cp -f /usr/lib/klibc/bin/run-init "$NEST_ROOT"/bin/
141
142    # copy in needed libraries
143    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
144        # pull libraries from most basic place libraries can live
145        # (avoid arch change between build env and debirf)
146        lib=/lib/$(basename "$lib")
147        echo -e "$lib\n$(readlink -f $lib)" | cpio --pass-through --make-directories "$NEST_ROOT"/
148    done
149    cp -f /lib/klibc-* "$NEST_ROOT"/lib/
150
151    # create nest init
152    cat > "$NEST_ROOT"/init <<EOF
153#!/bin/sh
154mkdir /proc
155mount -t proc proc /proc
156if (grep -q break=top /proc/cmdline); then
157  echo "honoring break=top kernel arg"
158  /bin/sh
159fi
160mkdir /newroot
161MEMSIZE=\$(free | grep 'Mem:' | awk '{ print \$2 }')
162mount -t tmpfs -o size=\${MEMSIZE}k tmpfs /newroot
163if (grep -q break=preunpack /proc/cmdline); then
164  echo "honoring break=preunpack kernel arg"
165  /bin/sh
166fi
167cd /newroot
168echo unpacking rootfs...
169# specify /bin/cpio so that it gets used instead of the busybox builtin
170# busybox cpio returns "need to fix this" when unpacking hard links
171gunzip - < /rootfs.cgz | /bin/cpio -i
172if (grep -q break=bottom /proc/cmdline); then
173  echo "honoring break=bottom kernel arg"
174  /bin/sh
175fi
176umount /proc
177echo running /sbin/init...
178exec /bin/run-init . /sbin/init < ./dev/console > ./dev/console
179EOF
180    chmod a+x "$NEST_ROOT"/init
181
182    msg "creating rootfs.cgz..."
183    fakeroot_if_needed ln -sf /sbin/init "$DEBIRF_ROOT/init"
184    pack_rootfs "$NEST_ROOT"/rootfs.cgz
185
186    msg "creating wrapper cgz..."
187    fakeroot_if_needed sh -c "cd $NEST_ROOT && find * | cpio --create -H newc" | gzip > "$DEBIRF_INITRD"
188}
189
190# setup profile environment
191setup_environment() {
192    # source debirf.conf defaults
193    source /usr/share/debirf/debirf.conf.defaults
194   
195    # check profile
196    if [ -d "$DEBIRF_PROFILE" ] ; then
197        echo "Loading profile '$DEBIRF_PROFILE'..."
198        DEBIRF_CONF="$DEBIRF_PROFILE/debirf.conf"
199        DEBIRF_MODULES="$DEBIRF_PROFILE/modules"
200    else
201        failure "Profile '$DEBIRF_PROFILE' not found."
202    fi
203   
204    # source profile debirf.conf
205    if [ -f "$DEBIRF_CONF" ] ; then
206        source "$DEBIRF_CONF"
207    else
208        echo "Configuration file '$DEBIRF_CONF' not found."
209        usage_profile
210        exit 1
211    fi
212
213    # check modules directory
214    if [ ! -d "$DEBIRF_MODULES" ] || [ -z "$(ls "$DEBIRF_MODULES")" ] ; then
215        echo "Modules directoy '$DEBIRF_MODULES' does not exist or is empty."
216        usage_profile
217        exit 1
218    fi
219    for MODULE in $(find "$DEBIRF_MODULES") ; do
220        if [ ! -s "$MODULE" ] ; then
221            failure "Module '$MODULE' is a broken link or empty file."
222        fi
223    done
224   
225    # check buildd
226    if [ -z "$DEBIRF_BUILDD" ] ; then
227        failure "DEBIRF_BUILDD is not set."
228    fi
229
230    # set root directory
231    DEBIRF_ROOT="$DEBIRF_BUILDD/root"
232
233    # set fakechroot save file
234    DEBIRF_FAKEROOT_STATE="$DEBIRF_BUILDD/.fakeroot-state.${DEBIRF_LABEL}"
235
236    # export all the DEBIRF_* environment variables:
237    for var in ${!DEBIRF_*}; do
238        if [ $var ] ; then
239            export $var
240        else
241            failure "Variable '$var' not properly set."
242        fi
243    done
244   
245    # check variables
246    if [ "$CHECK_VARS" ] ; then
247        echo "Debirf variables:"
248        env | /bin/grep "^DEBIRF_"
249        read -p "enter to continue: " OK
250    fi
251}
252
253# make profile
254make() {
255    # option parsing
256    TEMP=$(getopt --options -hcnosrwdik: --longoptions help,check-vars,new,overwrite,skip,root-build,no-warning,no-initrd,initrd-only,kernel: -n "$CMD" -- "$@")
257
258    if [ $? != 0 ] ; then
259        echo "Invalid options." >&2
260        usage
261        exit 1
262    fi
263   
264    # Note the quotes around `$TEMP': they are essential!
265    eval set -- "$TEMP"
266
267    while true ; do
268        case "$1" in
269            -c|--check-vars)
270                CHECK_VARS=true
271                shift 1
272                ;;
273            -n|--new)
274                WRITE_MODE=rewrite
275                shift 1
276                ;;
277            -o|--overwrite)
278                WRITE_MODE=overwrite
279                shift 1
280                ;;
281            -s|--skip)
282                WRITE_MODE=skip
283                shift 1
284                ;;
285            -r|--root-build)
286                ROOT_BUILD=true
287                shift 1
288                ;;
289            -w|--no-warning)
290                ROOT_WARNING=false
291                shift 1
292                ;;
293            -d|--no-initrd)
294                STAGE_INITRD=false
295                shift 1
296                ;;
297            -i|--initrd-only)
298                STAGE_ROOT=false
299                STAGE_MODULES=false
300                shift 1
301                ;;
302            -k|--kernel)
303                DEBIRF_KERNEL_PACKAGE="$2"
304                shift 2
305                ;;
306            --)
307                shift
308                ;;
309            *)
310                if (( $# < 1 )) ; then
311                    echo "Improper number of input arguments."
312                    usage
313                    exit 1
314                fi
315                DEBIRF_PROFILE="$1"
316                break
317                ;;
318        esac
319    done
320   
321    if [ $(id -u) = '0' ] ; then
322        cat <<EOF
323Warning: You are running debirf as root.  There is a potential
324for improperly written modules to damage your system.
325EOF
326        if [ "$ROOT_WARNING" = 'true' ] ; then
327            read -p "Are you sure you wish to continue? [y|N]: " OK; OK=${OK:=N}
328            if [ "${OK/y/Y}" != 'Y' ] ; then
329                failure "aborting."
330            fi
331        fi
332    fi
333
334    setup_environment
335
336    if [ "$DEBIRF_KERNEL_PACKAGE" ] ; then
337        if [ -f "$DEBIRF_KERNEL_PACKAGE" ] ; then
338            echo "Using kernel package '$DEBIRF_KERNEL_PACKAGE'."
339        else
340            failure "Kernel package '$DEBIRF_KERNEL_PACKAGE' not found."
341        fi
342    fi
343   
344    ### BUILD ROOT
345    if [ "$STAGE_ROOT" = 'true' ] ; then
346        # determine write mode
347        if [ -d "$DEBIRF_ROOT" ] ; then
348            if [ -z "$WRITE_MODE" ] ; then
349                echo "Debirf root already exists.  Select one of the following:"
350                CASE1='new: delete the old root and create a new one'
351                CASE2='overwrite: leave the old root and debootstrap on top of it'
352                CASE3='skip: skip building the root and go right to installing modules'
353                CASE4='exit'
354                select CASE in "$CASE1" "$CASE2" "$CASE3" "$CASE4" ; do
355                    case "$REPLY" in
356                        1)
357                            WRITE_MODE=rewrite
358                            ;;
359                        2)
360                            WRITE_MODE=overwrite
361                            ;;
362                        3)
363                            WRITE_MODE=skip
364                            ;;
365                        *)
366                            failure "aborting."
367                            ;;
368                    esac
369                    break
370                done
371            fi
372        else
373            WRITE_MODE=new
374        fi
375        case "$WRITE_MODE" in
376            'new')
377                msg "creating debirf root..."
378                > "$DEBIRF_FAKEROOT_STATE"
379                create_debootstrap
380                ;;
381            'rewrite')
382                msg "clearing old debirf root..."
383                rm -rf "$DEBIRF_ROOT"
384                msg "creating debirf root..."
385                > "$DEBIRF_FAKEROOT_STATE"
386                create_debootstrap
387                ;;
388            'overwrite')
389                msg "overwriting old debirf root..."
390                create_debootstrap
391                ;;
392            'skip')
393                msg "skipping debootstrap..."
394                ;;
395            *)
396                failure "aborting."
397                ;;
398        esac
399       
400        # fix the dev tree if running as non-priv user (fakechroot debootstrap)
401        fix_dev
402       
403    else
404        echo "Not building root."
405    fi
406    ### END BUILD ROOT
407   
408    ### RUN MODULES
409    if [ "$STAGE_MODULES" = 'true' ] ; then
410        msg "executing modules..."
411        run_modules
412        msg "modules complete."
413    else
414        echo "Not running modules."
415    fi
416    ### END RUN MODULES
417
418    ### BUILD INITRD
419    if [ "$STAGE_INITRD" = 'true' ] ; then
420        if [ ! -d "$DEBIRF_ROOT" ] ; then
421            failure "Debirf root '$DEBIRF_ROOT' not found."
422        fi
423        # determine initrd name
424        KERNEL_VERS=$(ls -1 "$DEBIRF_ROOT/lib/modules" | head -n1)
425        DEBIRF_INITRD="${DEBIRF_BUILDD}/${DEBIRF_LABEL}_${DEBIRF_DISTRO}_${KERNEL_VERS}.cgz"
426       
427        msg "creating debirf initrd ('$DEBIRF_METHOD')..."
428        create_initrd_${DEBIRF_METHOD} "$DEBIRF_INITRD"
429       
430        # final output
431        DEBIRF_KERNEL=$(ls "$DEBIRF_BUILDD" | grep "vmlinu" | grep "$KERNEL_VERS$")
432        msg "debirf initrd created."
433        if [ "$DEBIRF_BUILDD/$DEBIRF_KERNEL" ] ; then
434            msg "kernel: $DEBIRF_BUILDD/$DEBIRF_KERNEL"
435        fi
436        msg "initrd: $DEBIRF_INITRD"
437    else
438        echo "Not creating initramfs."
439    fi
440    ### END BUILD INITRD
441}
442
443# enter profile root
444enter() {
445    DEBIRF_PROFILE="$1"
446    shift
447
448    setup_environment
449
450    if [ "$1" ] ; then
451        fakeroot_if_needed debirf_exec "$@"
452    else
453        fakeroot_if_needed debirf_exec bash -i
454    fi
455}
456
457###############################################################
458### MAIN
459
460COMMAND="$1"
461[ "$COMMAND" ] || failure "Type '$CMD help' for usage."
462shift
463
464case $COMMAND in
465    'make'|'m')
466        make "$@"
467        ;;
468    'enter'|'e')
469        enter "$@"
470        ;;
471    'help'|'h'|'?')
472        usage
473        ;;
474    *)
475        failure "Unknown command: '$COMMAND'
476Type '$CMD help' for usage."
477        ;;
478esac
Note: See TracBrowser for help on using the repository browser.