#!/bin/sh set -e setvar VERSION = ''@VERSION@'' unset TMP TEMP TMPDIR || true # might not be exported if we're running from init=/bin/sh or similar export PATH ########################################################################### if test -z $DEBOOTSTRAP_DIR { if test -x /debootstrap/debootstrap { setvar DEBOOTSTRAP_DIR = "/debootstrap" } else { setvar DEBOOTSTRAP_DIR = "/usr/share/debootstrap" } } source $DEBOOTSTRAP_DIR/functions exec 4>&1 setvar LANG = 'C' setvar USE_COMPONENTS = 'main' setvar KEYRING = """" setvar DISABLE_KEYRING = """" setvar FORCE_KEYRING = """" setvar VARIANT = """" setvar MERGED_USR = ""no"" setvar ARCH = """" setvar HOST_ARCH = """" setvar HOST_OS = """" setvar KEEP_DEBOOTSTRAP_DIR = """" setvar USE_DEBIANINSTALLER_INTERACTION = """" setvar SECOND_STAGE_ONLY = """" setvar PRINT_DEBS = """" setvar CHROOTDIR = """" setvar MAKE_TARBALL = """" setvar EXTRACTOR_OVERRIDE = """" setvar UNPACK_TARBALL = """" setvar ADDITIONAL = """" setvar EXCLUDE = """" setvar VERBOSE = """" setvar CERTIFICATE = """" setvar CHECKCERTIF = """" setvar PRIVATEKEY = """" setvar DEF_MIRROR = ""http://deb.debian.org/debian"" setvar DEF_HTTPS_MIRROR = ""https://deb.debian.org/debian"" export LANG USE_COMPONENTS umask 022 ########################################################################### ## phases: ## finddebs dldebs printdebs first_stage second_stage setvar RESOLVE_DEPS = 'true' setvar WHAT_TO_DO = ""finddebs dldebs first_stage second_stage"" proc am_doing_phase { # usage: if am_doing_phase finddebs; then ...; fi local x; for x in "$@" { if echo " $WHAT_TO_DO " | grep -q " $x " { return 0; } } return 1 } ########################################################################### proc usage_err { info USAGE1 "usage: [OPTION]... <suite> <target> [<mirror> [<script>]]" info USAGE2 "Try \`${0##*/} --help' for more information." error @ARGV } proc usage { echo "Usage: ${0##*/} [OPTION]... <suite> <target> [<mirror> [<script>]]" echo "Bootstrap a Debian base system into a target directory." echo cat <<< """ --help display this help and exit --version display version information and exit --verbose don't turn off the output of wget --download-only download packages, but don't perform installation --print-debs print the packages to be installed, and exit --arch=A set the architecture to install (use if no dpkg) [ --arch=powerpc ] --include=A,B,C adds specified names to the list of base packages --exclude=A,B,C removes specified packages from the list --components=A,B,C use packages from the listed components of the archive --variant=X use variant X of the bootstrap scripts (currently supported variants: buildd, fakechroot, minbase) --merged-usr make /{bin,sbin,lib}/ symlinks to /usr/ --keyring=K check Release files against keyring K --no-check-gpg avoid checking Release file signatures --force-check-gpg force checking Release file signatures (also disables automatic fallback to HTTPS in case of a missing keyring), aborting otherwise --no-resolve-deps don't try to resolve dependencies automatically --unpack-tarball=T acquire .debs from a tarball instead of http --make-tarball=T download .debs and create a tarball (tgz format) --second-stage-target=DIR Run second stage in a subdirectory instead of root (can be used to create a foreign chroot) (requires --second-stage) --extractor=TYPE override automatic .deb extractor selection (supported: $EXTRACTORS_SUPPORTED) --debian-installer used for internal purposes by debian-installer --private-key=file read the private key from file --certificate=file use the client certificate stored in file (PEM) --no-check-certificate do not check certificate against certificate authorities """ } ########################################################################### if test -z $PKGDETAILS { error 1 NO_PKGDETAILS "No pkgdetails available; either install perl, or build pkgdetails.c from the base-installer source package" } ########################################################################### if test $Argc != 0 { while true { case (1) { --help { usage exit 0 } --version { echo "debootstrap $VERSION" exit 0 } --debian-installer { if ! shell {echo -n "" >&3} 2>/dev/null { error 1 ARG_DIBYHAND "If running debootstrap by hand, don't use --debian-installer" } setvar USE_DEBIANINSTALLER_INTERACTION = 'yes' shift } --foreign { if test $PRINT_DEBS != "true" { setvar WHAT_TO_DO = ""finddebs dldebs first_stage"" } shift } --second-stage { setvar WHAT_TO_DO = ""second_stage"" setvar SECOND_STAGE_ONLY = 'true' shift } --second-stage-target|--second-stage-target=?* { if test $SECOND_STAGE_ONLY != "true" { error 1 STAGE2ONLY "option %s only applies in the second stage" $1 } if test $1 = "--second-stage-target" -a -n $2 { setvar CHROOTDIR = "$2" shift 2 } elif test $1 != ${1#--second-stage-target=} { setvar CHROOTDIR = "${1#--second-stage-target=}" shift } else { error 1 NEEDARG "option requires an argument: %s" $1 } } --print-debs { setvar WHAT_TO_DO = ""finddebs printdebs kill_target"" setvar PRINT_DEBS = 'true' shift } --download-only { setvar WHAT_TO_DO = ""finddebs dldebs"" shift } --make-tarball|--make-tarball=?* { setvar WHAT_TO_DO = ""finddebs dldebs maketarball kill_target"" if test $1 = "--make-tarball" -a -n $2 { setvar MAKE_TARBALL = "$2" shift 2 } elif test $1 != ${1#--make-tarball=} { setvar MAKE_TARBALL = "${1#--make-tarball=}" shift } else { error 1 NEEDARG "option requires an argument %s" $1 } } --resolve-deps { # redundant, but avoids breaking compatibility setvar RESOLVE_DEPS = 'true' shift } --no-resolve-deps { setvar RESOLVE_DEPS = 'false' shift } --keep-debootstrap-dir { setvar KEEP_DEBOOTSTRAP_DIR = 'true' shift } --arch|--arch=?* { if test $1 = "--arch" -a -n $2 { setvar ARCH = "$2" shift 2 } elif test $1 != ${1#--arch=} { setvar ARCH = "${1#--arch=}" shift } else { error 1 NEEDARG "option requires an argument %s" $1 } } --extractor|--extractor=?* { if test $1 = "--extractor" -a -n $2 { setvar EXTRACTOR_OVERRIDE = "$2" shift 2 } elif test $1 != ${1#--extractor=} { setvar EXTRACTOR_OVERRIDE = "${1#--extractor=}" shift } else { error 1 NEEDARG "option requires an argument %s" $1 } if valid_extractor $EXTRACTOR_OVERRIDE { if ! type $EXTRACTOR_OVERRIDE >/dev/null 2>&1 { error 1 MISSINGEXTRACTOR "The selected extractor cannot be found: %s" $EXTRACTOR_OVERRIDE } } else { error 1 BADEXTRACTOR "%s: unknown extractor" $EXTRACTOR_OVERRIDE } } --unpack-tarball|--unpack-tarball=?* { if test $1 = "--unpack-tarball" -a -n $2 { setvar UNPACK_TARBALL = "$2" shift 2 } elif test $1 != ${1#--unpack-tarball=} { setvar UNPACK_TARBALL = "${1#--unpack-tarball=}" shift } else { error 1 NEEDARG "option requires an argument %s" $1 } if test ! -f $UNPACK_TARBALL { error 1 NOTARBALL "%s: No such file or directory" $UNPACK_TARBALL } } --include|--include=?* { if test $1 = "--include" -a -n $2 { setvar ADDITIONAL = "$2" shift 2 } elif test $1 != ${1#--include=} { setvar ADDITIONAL = "${1#--include=}" shift 1 } else { error 1 NEEDARG "option requires an argument %s" $1 } setvar ADDITIONAL = "$(echo "$ADDITIONAL" | tr , " ")" } --exclude|--exclude=?* { if test $1 = "--exclude" -a -n $2 { setvar EXCLUDE = "$2" shift 2 } elif test $1 != ${1#--exclude=} { setvar EXCLUDE = "${1#--exclude=}" shift 1 } else { error 1 NEEDARG "option requires an argument %s" $1 } setvar EXCLUDE = "$(echo "$EXCLUDE" | tr , " ")" } --verbose { setvar VERBOSE = 'true' export VERBOSE shift 1 } --components|--components=?* { if test $1 = "--components" -a -n $2 { setvar USE_COMPONENTS = "$2" shift 2 } elif test $1 != ${1#--components=} { setvar USE_COMPONENTS = "${1#--components=}" shift 1 } else { error 1 NEEDARG "option requires an argument %s" $1 } setvar USE_COMPONENTS = "$(echo "$USE_COMPONENTS" | tr , "|")" } --variant|--variant=?* { if test $1 = "--variant" -a -n $2 { setvar VARIANT = "$2" shift 2 } elif test $1 != ${1#--variant=} { setvar VARIANT = "${1#--variant=}" shift 1 } else { error 1 NEEDARG "option requires an argument %s" $1 } } --merged-usr { setvar MERGED_USR = 'yes' shift } --no-merged-usr { setvar MERGED_USR = 'no' shift } --keyring|--keyring=?* { if ! gpgv --version >/dev/null 2>&1 { error 1 NEEDGPGV "gpgv not installed, but required for Release verification" } if test $1 = "--keyring" -a -n $2 { setvar KEYRING = "$2" shift 2 } elif test $1 != ${1#--keyring=} { setvar KEYRING = "${1#--keyring=}" shift 1 } else { error 1 NEEDARG "option requires an argument %s" $1 } } --no-check-gpg { shift 1 setvar DISABLE_KEYRING = '1' } --force-check-gpg { shift 1 setvar FORCE_KEYRING = '1' } --certificate|--certificate=?* { if test $1 = "--certificate" -a -n $2 { setvar CERTIFICATE = ""--certificate=$2"" shift 2 } elif test $1 != ${1#--certificate=} { setvar CERTIFICATE = ""--certificate=${1#--certificate=}"" shift 1 } else { error 1 NEEDARG "option requires an argument %s" $1 } } --private-key|--private-key=?* { if test $1 = "--private-key" -a -n $2 { setvar PRIVATEKEY = ""--private-key=$2"" shift 2 } elif test $1 != ${1#--private-key=} { setvar PRIVATEKEY = ""--private-key=${1#--private-key=}"" shift 1 } else { error 1 NEEDARG "option requires an argument %s" $1 } } --no-check-certificate { setvar CHECKCERTIF = ""--no-check-certificate"" shift } -* { error 1 BADARG "unrecognized or invalid option %s" $1 } * { break } } } } ########################################################################### if test -n $DISABLE_KEYRING -a -n $FORCE_KEYRING { error 1 BADARG "Both --no-check-gpg and --force-check-gpg specified, please pick one (at most)" } ########################################################################### if test $SECOND_STAGE_ONLY = "true" { setvar SUITE = $(cat $DEBOOTSTRAP_DIR/suite) setvar ARCH = $(cat $DEBOOTSTRAP_DIR/arch) if test -e $DEBOOTSTRAP_DIR/variant { setvar VARIANT = $(cat $DEBOOTSTRAP_DIR/variant) setvar SUPPORTED_VARIANTS = "$VARIANT" } if test -z $CHROOTDIR { setvar TARGET = '/' } else { setvar TARGET = "$CHROOTDIR" } setvar SCRIPT = "$DEBOOTSTRAP_DIR/suite-script" } else { if test -z $1 || test -z $2 { usage_err 1 NEEDSUITETARGET "You must specify a suite and a target." } setvar SUITE = "$1" setvar TARGET = "$2" setvar USER_MIRROR = "$3" setvar TARGET = "${TARGET%/}" if test ${TARGET#/} = ${TARGET} { if test ${TARGET%/*} = $TARGET { setvar TARGET = "$(echo "`pwd`/$TARGET")" } else { setvar TARGET = "$(cd "${TARGET%/*}"; echo "`pwd`/${TARGET##*/}")" } } setvar SCRIPT = ""$DEBOOTSTRAP_DIR/scripts/$1"" if test -n $VARIANT && test -e "${SCRIPT}.${VARIANT}" { setvar SCRIPT = ""${SCRIPT}.${VARIANT}"" setvar SUPPORTED_VARIANTS = "$VARIANT" } if test $4 != "" { setvar SCRIPT = "$4" } } ########################################################################### if in_path dpkg && \ dpkg --print-architecture >/dev/null 2>&1 { setvar HOST_ARCH = $(/usr/bin/dpkg --print-architecture) } elif in_path udpkg && \ udpkg --print-architecture >/dev/null 2>&1 { setvar HOST_ARCH = $(/usr/bin/udpkg --print-architecture) } elif test -e $DEBOOTSTRAP_DIR/arch { setvar HOST_ARCH = $(cat $DEBOOTSTRAP_DIR/arch) } setvar HOST_OS = "$HOST_ARCH" # basic host OS guessing for non-Debian systems if test -z $HOST_OS { case{ Linux { setvar HOST_OS = 'linux' } GNU/kFreeBSD { setvar HOST_OS = 'kfreebsd' } GNU { setvar HOST_OS = 'hurd' } FreeBSD* { setvar HOST_OS = 'freebsd' } } } if test -z $ARCH { setvar ARCH = "$HOST_ARCH" } if test -z $ARCH || test -z $HOST_OS { error 1 WHATARCH "Couldn't work out current architecture" } if test $HOST_OS = "kfreebsd" || test $HOST_OS = "freebsd" { for module in linprocfs fdescfs tmpfs linsysfs { kldstat -m $module > /dev/null 2>&1 || warning SANITYCHECK "Probably required module %s is not loaded" $module } } if test $TARGET = "/" { setvar CHROOT_CMD = """" } else { setvar CHROOT_CMD = ""chroot $TARGET"" } if test -z $SHA_SIZE { setvar SHA_SIZE = '256' } if ! in_path "sha${SHA_SIZE}sum" && ! in_path "sha${SHA_SIZE}" { setvar SHA_SIZE = '1' } setvar DEBOOTSTRAP_CHECKSUM_FIELD = ""SHA$SHA_SIZE"" export ARCH SUITE TARGET CHROOT_CMD SHA_SIZE DEBOOTSTRAP_CHECKSUM_FIELD if am_doing_phase first_stage second_stage { if in_path id && test $(id -u) -ne 0 { error 1 NEEDROOT "debootstrap can only run as root" } # Ensure that we can create working devices and executables on the target. if ! check_sane_mount $TARGET { error 1 NOEXEC "Cannot install into target '$TARGET' mounted with noexec or nodev" } } if test ! -e $SCRIPT { error 1 NOSCRIPT "No such script: %s" $SCRIPT } ########################################################################### if test $TARGET != "" { mkdir -p "$TARGET/debootstrap" } ########################################################################### # Use of fd's by functions/scripts: # # stdin/stdout/stderr: used normally # fd 4: I:/W:/etc information # fd 5,6: spare for functions # fd 7,8: spare for scripts if test $USE_DEBIANINSTALLER_INTERACTION = yes { # stdout=stderr: full log of debootstrap run # fd 3: I:/W:/etc information exec 4>&3 } elif am_doing_phase printdebs { # stderr: I:/W:/etc information # stdout: debs needed exec 4>&2 } else { # stderr: used in exceptional circumstances only # stdout: I:/W:/etc information # $TARGET/debootstrap/debootstrap.log: full log of debootstrap run exec 4>&1 exec >>"$TARGET/debootstrap/debootstrap.log" exec 2>&1 } ########################################################################### if test $UNPACK_TARBALL { if test ${UNPACK_TARBALL#/} = $UNPACK_TARBALL { error 1 TARPATH "Tarball must be given a complete path" } if test ${UNPACK_TARBALL%.tar} != $UNPACK_TARBALL { shell {cd $TARGET && tar -xf $UNPACK_TARBALL} } elif test ${UNPACK_TARBALL%.tgz} != $UNPACK_TARBALL { shell {cd $TARGET && zcat $UNPACK_TARBALL | tar -xf -} } else { error 1 NOTTAR "Unknown tarball: must be either .tar or .tgz" } } ########################################################################### source "$SCRIPT" if test $SECOND_STAGE_ONLY = "true" { setvar MIRRORS = "null:" } else { setvar MIRRORS = "$DEF_MIRROR" if test $USER_MIRROR != "" { setvar MIRRORS = "$USER_MIRROR" setvar MIRRORS = "${MIRRORS%/}" } } export MIRRORS setvar ok = 'false' for v in $SUPPORTED_VARIANTS { if doing_variant $v { setvar ok = 'true'; } } if ! $ok { error 1 UNSUPPVARIANT "unsupported variant" } ########################################################################### if am_doing_phase finddebs { if test $FINDDEBS_NEEDS_INDICES = "true" || \ test $RESOLVE_DEPS = "true" { download_indices setvar GOT_INDICES = 'true' } work_out_debs setvar base = $(without "$base $ADDITIONAL" "$EXCLUDE") if test $RESOLVE_DEPS = true { setvar requiredX = $(echo $(echo $required | tr ' ' '\n' | sort | uniq)) setvar baseX = $(echo $(echo $base | tr ' ' '\n' | sort | uniq)) setvar baseN = $(without "$baseX" "$requiredX") setvar baseU = $(without "$baseX" "$baseN") if test $baseU != "" { info REDUNDANTBASE "Found packages in base already in required: %s" $baseU } info RESOLVEREQ "Resolving dependencies of required packages..." setvar required = $(resolve_deps $requiredX) info RESOLVEBASE "Resolving dependencies of base packages..." setvar base = $(resolve_deps $baseX) setvar base = $(without "$base" "$required") setvar requiredX = $(without "$required" "$requiredX") setvar baseX = $(without "$base" "$baseX") if test $requiredX != "" { info NEWREQUIRED "Found additional required dependencies: %s" $requiredX } if test $baseX != "" { info NEWBASE "Found additional base dependencies: %s" $baseX } } setvar all_debs = ""$required $base"" } if am_doing_phase printdebs { echo $all_debs } if am_doing_phase dldebs { if test $GOT_INDICES != "true" { download_indices } download $all_debs } if am_doing_phase maketarball { shell {cd $TARGET; tar czf - var/lib/apt var/cache/apt} >$MAKE_TARBALL } if am_doing_phase first_stage { choose_extractor # first stage sets up the chroot -- no calls should be made to # "chroot $TARGET" here; but they should be possible by the time it's # finished first_stage_install if ! am_doing_phase second_stage { cp $0 "$TARGET/debootstrap/debootstrap" cp $DEBOOTSTRAP_DIR/functions "$TARGET/debootstrap/functions" cp $SCRIPT "$TARGET/debootstrap/suite-script" echo $ARCH >"$TARGET/debootstrap/arch" echo $SUITE >"$TARGET/debootstrap/suite" test "" = $VARIANT || echo $VARIANT >"$TARGET/debootstrap/variant" echo $required >"$TARGET/debootstrap/required" echo $base >"$TARGET/debootstrap/base" chmod 755 "$TARGET/debootstrap/debootstrap" } } if am_doing_phase second_stage { if test $SECOND_STAGE_ONLY = true { setvar required = "$(cat $DEBOOTSTRAP_DIR/required)" setvar base = "$(cat $DEBOOTSTRAP_DIR/base)" setvar all_debs = ""$required $base"" } # second stage uses the chroot to clean itself up -- has to be able to # work from entirely within the chroot (in case we've booted into it, # possibly over NFS eg) second_stage_install # create sources.list # first, kill debootstrap.invalid sources.list if test -e "$TARGET/etc/apt/sources.list" { rm -f "$TARGET/etc/apt/sources.list" } if test ${MIRRORS#http://} != $MIRRORS { setup_apt_sources ${MIRRORS%% *} mv_invalid_to ${MIRRORS%% *} } else { setup_apt_sources $DEF_MIRROR mv_invalid_to $DEF_MIRROR } if test -e "$TARGET/debootstrap/debootstrap.log" { if test $KEEP_DEBOOTSTRAP_DIR = true { cp "$TARGET/debootstrap/debootstrap.log" "$TARGET/var/log/bootstrap.log" } else { # debootstrap.log is still open as stdout/stderr and needs # to remain so, but after unlinking it some NFS servers # implement this by a temporary file in the same directory, # which makes it impossible to rmdir that directory. # Moving it instead works around the problem. mv "$TARGET/debootstrap/debootstrap.log" "$TARGET/var/log/bootstrap.log" } } sync if test $KEEP_DEBOOTSTRAP_DIR = true { if test -x "$TARGET/debootstrap/debootstrap" { chmod 644 "$TARGET/debootstrap/debootstrap" } } else { rm -rf "$TARGET/debootstrap" } } if am_doing_phase kill_target { if test $KEEP_DEBOOTSTRAP_DIR != true { info KILLTARGET "Deleting target directory" rm -rf $TARGET } }