Permalink
Cannot retrieve contributors at this time
Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.
Sign up
Fetching contributors…
| ############################################################### smallutils | |
| smallyes() { | |
| YES="${1-y}" | |
| while echo "$YES" 2>/dev/null ; do : ; done | |
| } | |
| in_path () { | |
| local OLD_IFS="$IFS" | |
| IFS=":" | |
| for dir in $PATH; do | |
| if [ -x "$dir/$1" ]; then | |
| IFS="$OLD_IFS" | |
| return 0 | |
| fi | |
| done | |
| IFS="$OLD_IFS" | |
| return 1 | |
| } | |
| ############################################################### interaction | |
| error () { | |
| # <error code> <name> <string> <args> | |
| local err="$1" | |
| local name="$2" | |
| local fmt="$3" | |
| shift; shift; shift | |
| if [ "$USE_DEBIANINSTALLER_INTERACTION" ]; then | |
| (echo "E: $name" | |
| for x in "$@"; do echo "EA: $x"; done | |
| echo "EF: $fmt") >&4 | |
| else | |
| (printf "E: $fmt\n" "$@") >&4 | |
| fi | |
| exit $err | |
| } | |
| warning () { | |
| # <name> <string> <args> | |
| local name="$1" | |
| local fmt="$2" | |
| shift; shift | |
| if [ "$USE_DEBIANINSTALLER_INTERACTION" ]; then | |
| (echo "W: $name" | |
| for x in "$@"; do echo "WA: $x"; done | |
| echo "WF: $fmt") >&4 | |
| else | |
| printf "W: $fmt\n" "$@" >&4 | |
| fi | |
| } | |
| info () { | |
| # <name> <string> <args> | |
| local name="$1" | |
| local fmt="$2" | |
| shift; shift | |
| if [ "$USE_DEBIANINSTALLER_INTERACTION" ]; then | |
| (echo "I: $name" | |
| for x in "$@"; do echo "IA: $x"; done | |
| echo "IF: $fmt") >&4 | |
| else | |
| printf "I: $fmt\n" "$@" >&4 | |
| fi | |
| } | |
| PROGRESS_NOW=0 | |
| PROGRESS_END=0 | |
| PROGRESS_NEXT="" | |
| PROGRESS_WHAT="" | |
| progress_next () { | |
| PROGRESS_NEXT="$1" | |
| } | |
| wgetprogress () { | |
| [ ! "$VERBOSE" ] && QSWITCH="-q" | |
| local ret=0 | |
| if [ "$USE_DEBIANINSTALLER_INTERACTION" ] && [ "$PROGRESS_NEXT" ]; then | |
| wget "$@" 2>&1 >/dev/null | $PKGDETAILS "WGET%" $PROGRESS_NOW $PROGRESS_NEXT $PROGRESS_END >&3 | |
| ret=$? | |
| else | |
| wget $QSWITCH "$@" | |
| ret=$? | |
| fi | |
| return $ret | |
| } | |
| progress () { | |
| # <now> <end> <name> <string> <args> | |
| local now="$1" | |
| local end="$2" | |
| local name="$3" | |
| local fmt="$4" | |
| shift; shift; shift; shift | |
| if [ "$USE_DEBIANINSTALLER_INTERACTION" ]; then | |
| PROGRESS_NOW="$now" | |
| PROGRESS_END="$end" | |
| PROGRESS_NEXT="" | |
| (echo "P: $now $end $name" | |
| for x in "$@"; do echo "PA: $x"; done | |
| echo "PF: $fmt") >&3 | |
| fi | |
| } | |
| dpkg_progress () { | |
| # <now> <end> <name> <desc> UNPACKING|CONFIGURING | |
| local now="$1" | |
| local end="$2" | |
| local name="$3" | |
| local desc="$4" | |
| local action="$5" | |
| local expect= | |
| if [ "$action" = UNPACKING ]; then | |
| expect=half-installed | |
| elif [ "$action" = CONFIGURING ]; then | |
| expect=half-configured | |
| fi | |
| dp () { | |
| now="$(($now + ${1:-1}))" | |
| } | |
| exitcode=0 | |
| while read status pkg qstate; do | |
| if [ "$status" = "EXITCODE" ]; then | |
| exitcode="$pkg" | |
| continue | |
| fi | |
| [ "$qstate" = "$expect" ] || continue | |
| case $qstate in | |
| half-installed) | |
| dp; progress "$now" "$end" "$name" "$desc" | |
| info "$action" "Unpacking %s..." "${pkg%:}" | |
| expect=unpacked | |
| ;; | |
| unpacked) | |
| expect=half-installed | |
| ;; | |
| half-configured) | |
| dp; progress "$now" "$end" "$name" "$desc" | |
| info "$action" "Configuring %s..." "${pkg%:}" | |
| expect=installed | |
| ;; | |
| installed) | |
| expect=half-configured | |
| ;; | |
| esac | |
| done | |
| return $exitcode | |
| } | |
| ############################################################# set variables | |
| default_mirror () { | |
| DEF_MIRROR="$1" | |
| } | |
| FINDDEBS_NEEDS_INDICES=false | |
| finddebs_style () { | |
| case "$1" in | |
| hardcoded) | |
| ;; | |
| from-indices) | |
| FINDDEBS_NEEDS_INDICES=true | |
| ;; | |
| *) | |
| error 1 BADFINDDEBS "unknown finddebs style" | |
| ;; | |
| esac | |
| } | |
| mk_download_dirs () { | |
| if [ $DLDEST = "apt_dest" ]; then | |
| mkdir -p "$TARGET/$APTSTATE/lists/partial" | |
| mkdir -p "$TARGET/var/cache/apt/archives/partial" | |
| fi | |
| } | |
| download_style () { | |
| case "$1" in | |
| apt) | |
| if [ "$2" = "var-state" ]; then | |
| APTSTATE=var/state/apt | |
| else | |
| APTSTATE=var/lib/apt | |
| fi | |
| DLDEST=apt_dest | |
| export APTSTATE DLDEST DEBFOR | |
| ;; | |
| *) | |
| error 1 BADDLOAD "unknown download style" | |
| ;; | |
| esac | |
| } | |
| keyring () { | |
| if [ -z "$KEYRING" ]; then | |
| if [ -e "$1" ]; then | |
| KEYRING="$1" | |
| elif [ -z "$DISABLE_KEYRING" ]; then | |
| if [ -n "$DEF_HTTPS_MIRROR" ] && [ -z "$USER_MIRROR" ] && [ -z "$FORCE_KEYRING" ]; then | |
| info KEYRING "Keyring file not available at %s; switching to https mirror %s" "$1" "$DEF_HTTPS_MIRROR" | |
| USER_MIRROR="$DEF_HTTPS_MIRROR" | |
| else | |
| warning KEYRING "Cannot check Release signature; keyring file not available %s" "$1" | |
| if [ -n "$FORCE_KEYRING" ]; then | |
| error 1 KEYRING "Keyring-based check was requested; aborting accordingly" | |
| fi | |
| fi | |
| fi | |
| fi | |
| } | |
| ########################################################## variant handling | |
| doing_variant () { | |
| if [ "$1" = "$VARIANT" ]; then return 0; fi | |
| if [ "$1" = "-" ] && [ "$VARIANT" = "" ]; then return 0; fi | |
| return 1 | |
| } | |
| SUPPORTED_VARIANTS="-" | |
| variants () { | |
| SUPPORTED_VARIANTS="$*" | |
| for v in $*; do | |
| if doing_variant "$v"; then return 0; fi | |
| done | |
| error 1 UNSUPPVARIANT "unsupported variant" | |
| } | |
| ################################################# work out names for things | |
| mirror_style () { | |
| case "$1" in | |
| release) | |
| DOWNLOAD_INDICES=download_release_indices | |
| DOWNLOAD_DEBS=download_release | |
| ;; | |
| main) | |
| DOWNLOAD_INDICES=download_main_indices | |
| DOWNLOAD_DEBS=download_main | |
| ;; | |
| *) | |
| error 1 BADMIRROR "unknown mirror style" | |
| ;; | |
| esac | |
| export DOWNLOAD_INDICES | |
| export DOWNLOAD_DEBS | |
| } | |
| force_md5 () { | |
| DEBOOTSTRAP_CHECKSUM_FIELD=MD5SUM | |
| export DEBOOTSTRAP_CHECKSUM_FIELD | |
| } | |
| verify_checksum () { | |
| # args: dest checksum size | |
| local expchecksum="$2" | |
| local expsize="$3" | |
| if [ "$DEBOOTSTRAP_CHECKSUM_FIELD" = "MD5SUM" ]; then | |
| if in_path md5sum; then | |
| relchecksum=`md5sum < "$1" | sed 's/ .*$//'` | |
| elif in_path md5; then | |
| relchecksum=`md5 < "$1"` | |
| else | |
| error 1 SIGCHECK "Cannot check md5sum" | |
| fi | |
| else | |
| if in_path "sha${SHA_SIZE}sum"; then | |
| relchecksum=`sha${SHA_SIZE}sum < "$1" | sed 's/ .*$//'` | |
| elif in_path "sha${SHA_SIZE}"; then | |
| relchecksum=`sha${SHA_SIZE} < "$1"` | |
| else | |
| error 1 SIGCHECK "Cannot check sha${SHA_SIZE}sum" | |
| fi | |
| fi | |
| relsize=`wc -c < "$1"` | |
| if [ "$expsize" -ne "$relsize" ] || [ "$expchecksum" != "$relchecksum" ]; then | |
| return 1 | |
| fi | |
| return 0 | |
| } | |
| get () { | |
| # args: from dest 'nocache' | |
| # args: from dest [checksum size] [alt {checksum size type}] | |
| local displayname | |
| local versionname | |
| if [ "${2%.deb}" != "$2" ]; then | |
| displayname="$(echo "$2" | sed 's,^.*/,,;s,_.*$,,')" | |
| versionname="$(echo "$2" | sed 's,^.*/,,' | cut -d_ -f2 | sed 's/%3a/:/')" | |
| else | |
| displayname="$(echo "$1" | sed 's,^.*/,,')" | |
| fi | |
| if [ -e "$2" ]; then | |
| if [ -z "$3" ]; then | |
| return 0 | |
| elif [ "$3" = nocache ]; then | |
| rm -f "$2" | |
| else | |
| info VALIDATING "Validating %s %s" "$displayname" "$versionname" | |
| if verify_checksum "$2" "$3" "$4"; then | |
| return 0 | |
| else | |
| rm -f "$2" | |
| fi | |
| fi | |
| fi | |
| # Drop 'nocache' option | |
| if [ "$3" = nocache ]; then | |
| set "$1" "$2" | |
| fi | |
| if [ "$#" -gt 5 ]; then | |
| local st=3 | |
| if [ "$5" = "-" ]; then st=6; fi | |
| local order="$(a=$st; while [ "$a" -le $# ]; do eval echo \"\${$(($a+1))}\" $a; | |
| a=$(($a + 3)); done | sort -n | sed 's/.* //')" | |
| else | |
| local order=3 | |
| fi | |
| for a in $order; do | |
| local checksum="$(eval echo \${$a})" | |
| local siz="$(eval echo \${$(( $a+1 ))})" | |
| local typ="$(eval echo \${$(( $a+2 ))})" | |
| local from | |
| local dest | |
| local iters=0 | |
| case "$typ" in | |
| xz) from="$1.xz"; dest="$2.xz" ;; | |
| bz2) from="$1.bz2"; dest="$2.bz2" ;; | |
| gz) from="$1.gz"; dest="$2.gz" ;; | |
| *) from="$1"; dest="$2" ;; | |
| esac | |
| if [ "${dest#/}" = "$dest" ]; then | |
| dest="./$dest" | |
| fi | |
| local dest2="$dest" | |
| if [ -d "${dest2%/*}/partial" ]; then | |
| dest2="${dest2%/*}/partial/${dest2##*/}" | |
| fi | |
| while [ "$iters" -lt 10 ]; do | |
| info RETRIEVING "Retrieving %s %s" "$displayname" "$versionname" | |
| if ! just_get "$from" "$dest2"; then continue 2; fi | |
| if [ "$checksum" != "" ]; then | |
| info VALIDATING "Validating %s %s" "$displayname" "$versionname" | |
| if verify_checksum "$dest2" "$checksum" "$siz"; then | |
| checksum="" | |
| fi | |
| fi | |
| if [ -z "$checksum" ]; then | |
| [ "$dest2" = "$dest" ] || mv "$dest2" "$dest" | |
| case "$typ" in | |
| gz) gunzip "$dest" ;; | |
| bz2) bunzip2 "$dest" ;; | |
| xz) unxz "$dest" ;; | |
| esac | |
| return 0 | |
| else | |
| rm -f "$dest2" | |
| warning RETRYING "Retrying failed download of %s" "$from" | |
| iters="$(($iters + 1))" | |
| fi | |
| done | |
| warning CORRUPTFILE "%s was corrupt" "$from" | |
| done | |
| return 1 | |
| } | |
| just_get () { | |
| # args: from dest | |
| local from="$1" | |
| local dest="$2" | |
| mkdir -p "${dest%/*}" | |
| if [ "${from#null:}" != "$from" ]; then | |
| error 1 NOTPREDL "%s was not pre-downloaded" "${from#null:}" | |
| elif [ "${from#http://}" != "$from" ] || [ "${from#ftp://}" != "$from" ]; then | |
| # http/ftp mirror | |
| if wgetprogress -O "$dest" "$from"; then | |
| return 0 | |
| else | |
| rm -f "$dest" | |
| return 1 | |
| fi | |
| elif [ "${from#https://}" != "$from" ] ; then | |
| # http/ftp mirror | |
| if wgetprogress $CHECKCERTIF $CERTIFICATE $PRIVATEKEY -O "$dest" "$from"; then | |
| return 0 | |
| else | |
| rm -f "$dest" | |
| return 1 | |
| fi | |
| elif [ "${from#file:}" != "$from" ]; then | |
| local base="${from#file:}" | |
| if [ "${base#//}" != "$base" ]; then | |
| base="/${from#file://*/}" | |
| fi | |
| if [ -e "$base" ]; then | |
| cp "$base" "$dest" | |
| return 0 | |
| else | |
| return 1 | |
| fi | |
| elif [ "${from#ssh:}" != "$from" ]; then | |
| local ssh_dest="$(echo $from | sed -e 's#ssh://##' -e 's#/#:/#')" | |
| if [ -n "$ssh_dest" ]; then | |
| scp "$ssh_dest" "$dest" | |
| return 0 | |
| else | |
| return 1 | |
| fi | |
| else | |
| error 1 UNKNOWNLOC "unknown location %s" "$from" | |
| fi | |
| } | |
| download () { | |
| mk_download_dirs | |
| "$DOWNLOAD_DEBS" $(echo "$@" | tr ' ' '\n' | sort) | |
| } | |
| download_indices () { | |
| mk_download_dirs | |
| "$DOWNLOAD_INDICES" $(echo "$@" | tr ' ' '\n' | sort) | |
| } | |
| debfor () { | |
| (while read pkg path; do | |
| for p in "$@"; do | |
| [ "$p" = "$pkg" ] || continue; | |
| echo "$path" | |
| done | |
| done <"$TARGET/debootstrap/debpaths" | |
| ) | |
| } | |
| apt_dest () { | |
| # args: | |
| # deb package version arch mirror path | |
| # pkg suite component arch mirror path | |
| # rel suite mirror path | |
| case "$1" in | |
| deb) | |
| echo "/var/cache/apt/archives/${2}_${3}_${4}.deb" | sed 's/:/%3a/' | |
| ;; | |
| pkg) | |
| local m="$5" | |
| m="debootstrap.invalid" | |
| #if [ "${m#http://}" != "$m" ]; then | |
| # m="${m#http://}" | |
| #elif [ "${m#file://}" != "$m" ]; then | |
| # m="file_localhost_${m#file://*/}" | |
| #elif [ "${m#file:/}" != "$m" ]; then | |
| # m="file_localhost_${m#file:/}" | |
| #fi | |
| printf "%s" "$APTSTATE/lists/" | |
| echo "${m}_$6" | sed 's/\//_/g' | |
| ;; | |
| rel) | |
| local m="$3" | |
| m="debootstrap.invalid" | |
| #if [ "${m#http://}" != "$m" ]; then | |
| # m="${m#http://}" | |
| #elif [ "${m#file://}" != "$m" ]; then | |
| # m="file_localhost_${m#file://*/}" | |
| #elif [ "${m#file:/}" != "$m" ]; then | |
| # m="file_localhost_${m#file:/}" | |
| #fi | |
| printf "%s" "$APTSTATE/lists/" | |
| echo "${m}_$4" | sed 's/\//_/g' | |
| ;; | |
| esac | |
| } | |
| ################################################################## download | |
| get_release_checksum () { | |
| local reldest="$1" | |
| local path="$2" | |
| if [ "$DEBOOTSTRAP_CHECKSUM_FIELD" = MD5SUM ]; then | |
| local match="^[Mm][Dd]5[Ss][Uu][Mm]" | |
| else | |
| local match="^[Ss][Hh][Aa]$SHA_SIZE:" | |
| fi | |
| sed -n "/$match/,/^[^ ]/p" < "$reldest" | \ | |
| while read a b c; do | |
| if [ "$c" = "$path" ]; then echo "$a $b"; fi | |
| done | head -n 1 | |
| } | |
| extract_release_components () { | |
| local reldest="$1"; shift | |
| TMPCOMPONENTS="$(sed -n 's/Components: *//p' "$reldest")" | |
| for c in $TMPCOMPONENTS ; do | |
| eval " | |
| case \"\$c\" in | |
| $USE_COMPONENTS) | |
| COMPONENTS=\"\$COMPONENTS \$c\" | |
| ;; | |
| esac | |
| " | |
| done | |
| COMPONENTS="$(echo $COMPONENTS)" | |
| if [ -z "$COMPONENTS" ]; then | |
| mv "$reldest" "$reldest.malformed" | |
| error 1 INVALIDREL "Invalid Release file, no valid components" | |
| fi | |
| } | |
| CODENAME="" | |
| validate_suite () { | |
| local reldest="$1" | |
| CODENAME=$(sed -n "s/^Codename: *//p" "$reldest") | |
| local suite=$(sed -n "s/^Suite: *//p" "$reldest") | |
| if [ "$SUITE" != "$suite" ] && [ "$SUITE" != "$CODENAME" ]; then | |
| error 1 WRONGSUITE "Asked to install suite %s, but got %s (codename: %s) from mirror" "$SUITE" "$suite" "$CODENAME" | |
| fi | |
| } | |
| split_inline_sig () { | |
| local inreldest="$1" | |
| local reldest="$2" | |
| local relsigdest="$3" | |
| # Note: InRelease files are fun since one needs to remove the | |
| # last newline from the PGP SIGNED MESSAGE part, while keeping | |
| # the PGP SIGNATURE part intact. This shell implementation | |
| # should work on most if not all systems, instead of trying to | |
| # sed/tr/head, etc. | |
| rm -f "$reldest" "$relsigdest" | |
| nl="" | |
| state=pre-begin | |
| while IFS= read -r line; do | |
| case "${state}" in | |
| pre-begin) | |
| if [ "x${line}" = "x-----BEGIN PGP SIGNED MESSAGE-----" ]; then | |
| state=begin | |
| fi | |
| ;; | |
| begin) | |
| if [ "x${line}" = "x" ]; then | |
| state=data | |
| fi | |
| ;; | |
| data) | |
| if [ "x${line}" = "x-----BEGIN PGP SIGNATURE-----" ]; then | |
| printf "%s\n" "${line}" > "$relsigdest" | |
| state=signature | |
| else | |
| printf "${nl}%s" "${line}" >> "$reldest" | |
| nl="\n" | |
| fi | |
| ;; | |
| signature) | |
| printf "%s\n" "${line}" >> "$relsigdest" | |
| if [ "x${line}" = "x-----END PGP SIGNATURE-----" ]; then | |
| break | |
| fi | |
| esac | |
| done < "$inreldest" | |
| } | |
| download_release_sig () { | |
| local m1="$1" | |
| local inreldest="$2" | |
| local reldest="$3" | |
| local relsigdest="$4" | |
| progress 0 100 DOWNREL "Downloading Release file" | |
| progress_next 100 | |
| if get "$m1/dists/$SUITE/InRelease" "$inreldest" nocache; then | |
| split_inline_sig "$inreldest" "$reldest" "$relsigdest" | |
| progress 100 100 DOWNREL "Downloading Release file" | |
| else | |
| get "$m1/dists/$SUITE/Release" "$reldest" nocache || | |
| error 1 NOGETREL "Failed getting release file %s" "$m1/dists/$SUITE/Release" | |
| progress 100 100 DOWNREL "Downloading Release file" | |
| fi | |
| if [ -n "$KEYRING" ] && [ -z "$DISABLE_KEYRING" ]; then | |
| progress 0 100 DOWNRELSIG "Downloading Release file signature" | |
| if ! [ -f "$relsigdest" ]; then | |
| progress_next 50 | |
| get "$m1/dists/$SUITE/Release.gpg" "$relsigdest" nocache || | |
| error 1 NOGETRELSIG "Failed getting release signature file %s" \ | |
| "$m1/dists/$SUITE/Release.gpg" | |
| progress 50 100 DOWNRELSIG "Downloading Release file signature" | |
| fi | |
| info RELEASESIG "Checking Release signature" | |
| # Don't worry about the exit status from gpgv; parsing the output will | |
| # take care of that. | |
| (gpgv --status-fd 1 --keyring "$KEYRING" --ignore-time-conflict \ | |
| "$relsigdest" "$reldest" || true) | read_gpg_status | |
| progress 100 100 DOWNRELSIG "Downloading Release file signature" | |
| fi | |
| } | |
| download_release_indices () { | |
| local m1="${MIRRORS%% *}" | |
| local inreldest="$TARGET/$($DLDEST rel "$SUITE" "$m1" "dists/$SUITE/InRelease")" | |
| local reldest="$TARGET/$($DLDEST rel "$SUITE" "$m1" "dists/$SUITE/Release")" | |
| local relsigdest="$TARGET/$($DLDEST rel "$SUITE" "$m1" "dists/$SUITE/Release.gpg")" | |
| download_release_sig "$m1" "$inreldest" "$reldest" "$relsigdest" | |
| validate_suite "$reldest" | |
| extract_release_components $reldest | |
| local totalpkgs=0 | |
| for c in $COMPONENTS; do | |
| local subpath="$c/binary-$ARCH/Packages" | |
| local xzi="`get_release_checksum "$reldest" "$subpath.xz"`" | |
| local bz2i="`get_release_checksum "$reldest" "$subpath.bz2"`" | |
| local gzi="`get_release_checksum "$reldest" "$subpath.gz"`" | |
| local normi="`get_release_checksum "$reldest" "$subpath"`" | |
| local i= | |
| if [ "$normi" != "" ]; then | |
| i="$normi" | |
| elif in_path bunzip2 && [ "$bz2i" != "" ]; then | |
| i="$bz2i" | |
| elif in_path unxz && [ "$xzi" != "" ]; then | |
| i="$xzi" | |
| elif in_path gunzip && [ "$gzi" != "" ]; then | |
| i="$gzi" | |
| fi | |
| if [ "$i" != "" ]; then | |
| totalpkgs="$(( $totalpkgs + ${i#* } ))" | |
| else | |
| mv "$reldest" "$reldest.malformed" | |
| error 1 MISSINGRELENTRY "Invalid Release file, no entry for %s" "$subpath" | |
| fi | |
| done | |
| local donepkgs=0 | |
| local pkgdest | |
| progress 0 $totalpkgs DOWNPKGS "Downloading Packages files" | |
| for c in $COMPONENTS; do | |
| local subpath="$c/binary-$ARCH/Packages" | |
| local path="dists/$SUITE/$subpath" | |
| local xzi="`get_release_checksum "$reldest" "$subpath.xz"`" | |
| local bz2i="`get_release_checksum "$reldest" "$subpath.bz2"`" | |
| local gzi="`get_release_checksum "$reldest" "$subpath.gz"`" | |
| local normi="`get_release_checksum "$reldest" "$subpath"`" | |
| local ext= | |
| local i= | |
| if [ "$normi" != "" ]; then | |
| ext="$ext $normi ." | |
| i="$normi" | |
| fi | |
| if in_path unxz && [ "$xzi" != "" ]; then | |
| ext="$ext $xzi xz" | |
| i="${i:-$xzi}" | |
| fi | |
| if in_path bunzip2 && [ "$bz2i" != "" ]; then | |
| ext="$ext $bz2i bz2" | |
| i="${i:-$bz2i}" | |
| fi | |
| if in_path gunzip && [ "$gzi" != "" ]; then | |
| ext="$ext $gzi gz" | |
| i="${i:-$gzi}" | |
| fi | |
| progress_next "$(($donepkgs + ${i#* }))" | |
| for m in $MIRRORS; do | |
| pkgdest="$TARGET/$($DLDEST pkg "$SUITE" "$c" "$ARCH" "$m" "$path")" | |
| if get "$m/$path" "$pkgdest" $ext; then break; fi | |
| done | |
| if [ ! -f "$pkgdest" ]; then | |
| error 1 COULDNTDL "Couldn't download %s" "$path" | |
| fi | |
| donepkgs="$(($donepkgs + ${i#* }))" | |
| progress $donepkgs $totalpkgs DOWNPKGS "Downloading Packages files" | |
| done | |
| } | |
| get_package_sizes () { | |
| # mirror pkgdest debs.. | |
| local m="$1"; shift | |
| local pkgdest="$1"; shift | |
| $PKGDETAILS PKGS "$m" "$pkgdest" "$@" | ( | |
| newleft="" | |
| totaldebs=0 | |
| countdebs=0 | |
| while read p details; do | |
| if [ "$details" = "-" ]; then | |
| newleft="$newleft $p" | |
| else | |
| size="${details##* }"; | |
| totaldebs="$(($totaldebs + $size))" | |
| countdebs="$(($countdebs + 1))" | |
| fi | |
| done | |
| echo "$countdebs $totaldebs$newleft" | |
| ) | |
| } | |
| # note, leftovers come back on fd5 !! | |
| download_debs () { | |
| local m="$1" | |
| local pkgdest="$2" | |
| shift; shift | |
| $PKGDETAILS PKGS "$m" "$pkgdest" "$@" | ( | |
| leftover="" | |
| while read p ver arc mdup fil checksum size; do | |
| if [ "$ver" = "-" ]; then | |
| leftover="$leftover $p" | |
| else | |
| progress_next "$(($dloaddebs + $size))" | |
| local debdest="$($DLDEST deb "$p" "$ver" "$arc" "$m" "$fil")" | |
| if get "$m/$fil" "$TARGET/$debdest" "$checksum" "$size"; then | |
| dloaddebs="$(($dloaddebs + $size))" | |
| echo >>$TARGET/debootstrap/deburis "$p $ver $m/$fil" | |
| echo >>$TARGET/debootstrap/debpaths "$p $debdest" | |
| else | |
| warning COULDNTDL "Couldn't download package %s (ver %s arch %s)" "$p" "$ver" "$arc" | |
| leftover="$leftover $p" | |
| fi | |
| fi | |
| done | |
| echo >&5 ${leftover# } | |
| ) | |
| } | |
| download_release () { | |
| local m1="${MIRRORS%% *}" | |
| local numdebs="$#" | |
| local countdebs=0 | |
| progress $countdebs $numdebs SIZEDEBS "Finding package sizes" | |
| local totaldebs=0 | |
| local leftoverdebs="$*" | |
| # Fix possible duplicate package names, which would screw up counts: | |
| leftoverdebs=$(printf "$leftoverdebs"|tr ' ' '\n'|sort -u|tr '\n' ' ') | |
| numdebs=$(printf "$leftoverdebs"|wc -w) | |
| for c in $COMPONENTS; do | |
| if [ "$countdebs" -ge "$numdebs" ]; then break; fi | |
| local path="dists/$SUITE/$c/binary-$ARCH/Packages" | |
| local pkgdest="$TARGET/$($DLDEST pkg "$SUITE" "$c" "$ARCH" "$m1" "$path")" | |
| if [ ! -e "$pkgdest" ]; then continue; fi | |
| info CHECKINGSIZES "Checking component %s on %s..." "$c" "$m1" | |
| leftoverdebs="$(get_package_sizes "$m1" "$pkgdest" $leftoverdebs)" | |
| countdebs=$(($countdebs + ${leftoverdebs%% *})) | |
| leftoverdebs=${leftoverdebs#* } | |
| totaldebs=${leftoverdebs%% *} | |
| leftoverdebs=${leftoverdebs#* } | |
| progress $countdebs $numdebs SIZEDEBS "Finding package sizes" | |
| done | |
| if [ "$countdebs" -ne "$numdebs" ]; then | |
| error 1 LEFTOVERDEBS "Couldn't find these debs: %s" "$leftoverdebs" | |
| fi | |
| local dloaddebs=0 | |
| progress $dloaddebs $totaldebs DOWNDEBS "Downloading packages" | |
| :>$TARGET/debootstrap/debpaths | |
| pkgs_to_get="$*" | |
| for c in $COMPONENTS; do | |
| local path="dists/$SUITE/$c/binary-$ARCH/Packages" | |
| for m in $MIRRORS; do | |
| local pkgdest="$TARGET/$($DLDEST pkg "$SUITE" "$c" "$ARCH" "$m" "$path")" | |
| if [ ! -e "$pkgdest" ]; then continue; fi | |
| pkgs_to_get="$(download_debs "$m" "$pkgdest" $pkgs_to_get 5>&1 1>&6)" | |
| if [ -z "$pkgs_to_get" ]; then break; fi | |
| done 6>&1 | |
| if [ -z "$pkgs_to_get" ]; then break; fi | |
| done | |
| progress $dloaddebs $totaldebs DOWNDEBS "Downloading packages" | |
| if [ "$pkgs_to_get" != "" ]; then | |
| error 1 COULDNTDLPKGS "Couldn't download packages: %s" "$pkgs_to_get" | |
| fi | |
| } | |
| download_main_indices () { | |
| local m1="${MIRRORS%% *}" | |
| local comp="${USE_COMPONENTS}" | |
| progress 0 100 DOWNMAINPKGS "Downloading Packages file" | |
| progress_next 100 | |
| if [ -z "$comp" ]; then comp=main; fi | |
| COMPONENTS="$(echo $comp | tr '|' ' ')" | |
| export COMPONENTS | |
| for m in $MIRRORS; do | |
| for c in $COMPONENTS; do | |
| local path="dists/$SUITE/$c/binary-$ARCH/Packages" | |
| local pkgdest="$TARGET/$($DLDEST pkg "$SUITE" "$c" "$ARCH" "$m" "$path")" | |
| if in_path gunzip && get "$m/${path}.gz" "${pkgdest}.gz"; then | |
| rm -f "$pkgdest" | |
| gunzip "$pkgdest.gz" | |
| elif get "$m/$path" "$pkgdest"; then | |
| true | |
| fi | |
| done | |
| done | |
| progress 100 100 DOWNMAINPKGS "Downloading Packages file" | |
| } | |
| download_main () { | |
| local m1="${MIRRORS%% *}" | |
| :>$TARGET/debootstrap/debpaths | |
| for p in "$@"; do | |
| for c in $COMPONENTS; do | |
| local details="" | |
| for m in $MIRRORS; do | |
| local path="dists/$SUITE/$c/binary-$ARCH/Packages" | |
| local pkgdest="$TARGET/$($DLDEST pkg "$SUITE" "$c" "$ARCH" "$m" "$path")" | |
| if [ ! -e "$pkgdest" ]; then continue; fi | |
| details="$($PKGDETAILS PKGS "$m" "$pkgdest" "$p")" | |
| if [ "$details" = "$p -" ]; then | |
| details="" | |
| continue | |
| fi | |
| size="${details##* }"; details="${details% *}" | |
| checksum="${details##* }"; details="${details% *}" | |
| local debdest="$($DLDEST deb $details)" | |
| if get "$m/${details##* }" "$TARGET/$debdest" "$checksum" "$size"; then | |
| echo >>$TARGET/debootstrap/debpaths "$p $debdest" | |
| details="done" | |
| break | |
| fi | |
| done | |
| if [ "$details" != "" ]; then | |
| break | |
| fi | |
| done | |
| if [ "$details" != "done" ]; then | |
| error 1 COULDNTDL "Couldn't download %s" "$p" | |
| fi | |
| done | |
| } | |
| ###################################################### deb choosing support | |
| get_debs () { | |
| local field="$1" | |
| shift | |
| local m1 c | |
| for m1 in $MIRRORS; do | |
| for c in $COMPONENTS; do | |
| local path="dists/$SUITE/$c/binary-$ARCH/Packages" | |
| local pkgdest="$TARGET/$($DLDEST pkg "$SUITE" "$c" "$ARCH" "$m1" "$path")" | |
| echo $("$PKGDETAILS" FIELD "$field" "$m1" "$pkgdest" "$@" | sed 's/ .*//') | |
| done | |
| done | |
| } | |
| ################################################################ extraction | |
| EXTRACTORS_SUPPORTED="dpkg-deb ar" | |
| EXTRACT_DEB_TAR_OPTIONS= | |
| # Native dpkg-deb based extractors | |
| extract_dpkg_deb_field () { | |
| local pkg="$1" | |
| local field="$2" | |
| dpkg-deb -f "$pkg" "$field" | |
| } | |
| extract_dpkg_deb_data () { | |
| local pkg="$1" | |
| dpkg-deb --fsys-tarfile "$pkg" | tar $EXTRACT_DEB_TAR_OPTIONS -xf - | |
| } | |
| # Raw .deb extractors | |
| extract_ar_deb_field () { | |
| local pkg="$1" | |
| local field="$2" | |
| local tarball=$(ar -t "$pkg" | grep "^control\.tar") | |
| case "$tarball" in | |
| control.tar.gz) cat_cmd=zcat ;; | |
| control.tar.xz) cat_cmd=xzcat ;; | |
| control.tar) cat_cmd=cat ;; | |
| *) error 1 UNKNOWNCONTROLCOMP "Unknown compression type for %s in %s" "$tarball" "$pkg" ;; | |
| esac | |
| if type $cat_cmd >/dev/null 2>&1; then | |
| ar -p "$pkg" "$tarball" | $cat_cmd | | |
| tar -O -xf - control ./control 2>/dev/null | | |
| grep -i "^$field:" | sed -e 's/[^:]*: *//' | head -n 1 | |
| else | |
| error 1 UNPACKCMDUNVL "Extracting %s requires the %s command, which is not available" "$pkg" "$cat_cmd" | |
| fi | |
| } | |
| extract_ar_deb_data () { | |
| local pkg="$1" | |
| local tarball=$(ar -t "$pkg" | grep "^data.tar") | |
| case "$tarball" in | |
| data.tar.gz) cat_cmd=zcat ;; | |
| data.tar.bz2) cat_cmd=bzcat ;; | |
| data.tar.xz) cat_cmd=xzcat ;; | |
| data.tar) cat_cmd=cat ;; | |
| *) error 1 UNKNOWNDATACOMP "Unknown compression type for %s in %s" "$tarball" "$pkg" ;; | |
| esac | |
| if type $cat_cmd >/dev/null 2>&1; then | |
| ar -p "$pkg" "$tarball" | $cat_cmd | tar $EXTRACT_DEB_TAR_OPTIONS -xf - | |
| else | |
| error 1 UNPACKCMDUNVL "Extracting %s requires the %s command, which is not available" "$pkg" "$cat_cmd" | |
| fi | |
| } | |
| valid_extractor () { | |
| local extractor="$1" | |
| for E in $EXTRACTORS_SUPPORTED; do | |
| if [ "$extractor" = "$E" ]; then | |
| return 0 | |
| fi | |
| done | |
| return 1 | |
| } | |
| choose_extractor () { | |
| local extractor | |
| if [ -n "$EXTRACTOR_OVERRIDE" ]; then | |
| extractor="$EXTRACTOR_OVERRIDE" | |
| elif type dpkg-deb >/dev/null 2>&1; then | |
| extractor="dpkg-deb" | |
| else | |
| extractor="ar" | |
| fi | |
| info CHOSENEXTRACTOR "Chosen extractor for .deb packages: %s" "$extractor" | |
| case "$extractor" in | |
| dpkg-deb) | |
| extract_deb_field () { extract_dpkg_deb_field "$@"; } | |
| extract_deb_data () { extract_dpkg_deb_data "$@"; } | |
| ;; | |
| ar) | |
| extract_deb_field () { extract_ar_deb_field "$@"; } | |
| extract_deb_data () { extract_ar_deb_data "$@"; } | |
| ;; | |
| esac | |
| } | |
| extract () { ( | |
| cd "$TARGET" | |
| local p=0 cat_cmd | |
| for pkg in $(debfor "$@"); do | |
| p="$(($p + 1))" | |
| progress "$p" "$#" EXTRACTPKGS "Extracting packages" | |
| packagename="$(echo "$pkg" | sed 's,^.*/,,;s,_.*$,,')" | |
| info EXTRACTING "Extracting %s..." "$packagename" | |
| extract_deb_data "./$pkg" | |
| done | |
| ); } | |
| in_target_nofail () { | |
| if ! $CHROOT_CMD "$@" 2>/dev/null; then | |
| true | |
| fi | |
| return 0 | |
| } | |
| in_target_failmsg () { | |
| local code="$1" | |
| local msg="$2" | |
| local arg="$3" | |
| shift; shift; shift | |
| if ! $CHROOT_CMD "$@"; then | |
| warning "$code" "$msg" "$arg" | |
| # Try to point user at actual failing package. | |
| msg="See %s for details" | |
| if [ -e "$TARGET/debootstrap/debootstrap.log" ]; then | |
| arg="$TARGET/debootstrap/debootstrap.log" | |
| local pkg="$(grep '^dpkg: error processing ' "$TARGET/debootstrap/debootstrap.log" | head -n 1 | sed 's/\(error processing \)\(package \|archive \)/\1/' | cut -d ' ' -f 4)" | |
| if [ -n "$pkg" ]; then | |
| msg="$msg (possibly the package $pkg is at fault)" | |
| fi | |
| else | |
| arg="the log" | |
| fi | |
| warning "$code" "$msg" "$arg" | |
| return 1 | |
| fi | |
| return 0 | |
| } | |
| in_target () { | |
| in_target_failmsg IN_TARGET_FAIL "Failure trying to run: %s" "$CHROOT_CMD $*" "$@" | |
| } | |
| ###################################################### standard setup stuff | |
| conditional_cp () { | |
| if [ ! -e "$2/$1" ]; then | |
| if [ -L "$1" ] && [ -e "$1" ]; then | |
| cat "$1" >"$2/$1" | |
| elif [ -e "$1" ]; then | |
| cp -a "$1" "$2/$1" | |
| fi | |
| fi | |
| } | |
| mv_invalid_to () { | |
| local m="$1" | |
| m="$(echo "${m#http://}" | tr '/' '_' | sed 's/_*//')" | |
| (cd "$TARGET/$APTSTATE/lists" | |
| for a in debootstrap.invalid_*; do | |
| mv "$a" "${m}_${a#*_}" | |
| done | |
| ) | |
| } | |
| setup_apt_sources () { | |
| mkdir -p "$TARGET/etc/apt" | |
| for m in "$@"; do | |
| local cs="" | |
| for c in ${COMPONENTS:-$USE_COMPONENTS}; do | |
| local path="dists/$SUITE/$c/binary-$ARCH/Packages" | |
| local pkgdest="$TARGET/$($DLDEST pkg "$SUITE" "$c" "$ARCH" "$m" "$path")" | |
| if [ -e "$pkgdest" ]; then cs="$cs $c"; fi | |
| done | |
| if [ "$cs" != "" ]; then echo "deb $m $SUITE$cs"; fi | |
| done > "$TARGET/etc/apt/sources.list" | |
| } | |
| setup_etc () { | |
| mkdir -p "$TARGET/etc" | |
| conditional_cp /etc/resolv.conf "$TARGET" | |
| conditional_cp /etc/hostname "$TARGET" | |
| if [ "$DLDEST" = apt_dest ] && [ ! -e "$TARGET/etc/apt/sources.list" ]; then | |
| setup_apt_sources "http://debootstrap.invalid/" | |
| fi | |
| } | |
| UMOUNT_DIRS= | |
| umount_exit_function () { | |
| local realdir | |
| for dir in $UMOUNT_DIRS; do | |
| realdir="$(in_target_nofail readlink -f "$dir")" | |
| [ "$realdir" ] || continue | |
| ( cd / ; umount "$TARGET/${realdir#/}" ) || true | |
| done | |
| } | |
| umount_on_exit () { | |
| if [ "$UMOUNT_DIRS" ]; then | |
| UMOUNT_DIRS="$UMOUNT_DIRS $1" | |
| else | |
| UMOUNT_DIRS="$1" | |
| on_exit umount_exit_function | |
| fi | |
| } | |
| clear_mtab () { | |
| if [ -f "$TARGET/etc/mtab" ] && [ ! -h "$TARGET/etc/mtab" ]; then | |
| rm -f "$TARGET/etc/mtab" | |
| fi | |
| } | |
| setup_proc () { | |
| case "$HOST_OS" in | |
| *freebsd*) | |
| umount_on_exit /dev | |
| umount_on_exit /proc | |
| umount "$TARGET/proc" 2>/dev/null || true | |
| if [ "$HOST_OS" = kfreebsd ]; then | |
| in_target mount -t linprocfs proc /proc | |
| else | |
| mount -t linprocfs proc $TARGET/proc | |
| fi | |
| ;; | |
| hurd*) | |
| # firmlink $TARGET/{dev,servers,proc} to the system ones. | |
| settrans -a "$TARGET/dev" /hurd/firmlink /dev | |
| settrans -a "$TARGET/servers" /hurd/firmlink /servers | |
| settrans -a "$TARGET/proc" /hurd/firmlink /proc | |
| ;; | |
| *) | |
| umount_on_exit /dev/pts | |
| umount_on_exit /dev/shm | |
| umount_on_exit /proc/bus/usb | |
| umount_on_exit /proc | |
| umount "$TARGET/proc" 2>/dev/null || true | |
| in_target mount -t proc proc /proc | |
| if [ -d "$TARGET/sys" ] && \ | |
| grep -q '[[:space:]]sysfs' /proc/filesystems 2>/dev/null; then | |
| umount_on_exit /sys | |
| umount "$TARGET/sys" 2>/dev/null || true | |
| in_target mount -t sysfs sysfs /sys | |
| fi | |
| on_exit clear_mtab | |
| ;; | |
| esac | |
| umount_on_exit /lib/init/rw | |
| } | |
| setup_proc_fakechroot () { | |
| rm -rf "$TARGET/proc" | |
| ln -s /proc "$TARGET" | |
| } | |
| # create the static device nodes | |
| setup_devices () { | |
| if doing_variant fakechroot; then | |
| setup_devices_fakechroot | |
| return 0 | |
| fi | |
| case "$HOST_OS" in | |
| kfreebsd*) | |
| ;; | |
| freebsd) | |
| ;; | |
| hurd*) | |
| ;; | |
| *) | |
| setup_devices_simple | |
| ;; | |
| esac | |
| } | |
| # enable the dynamic device nodes | |
| setup_dynamic_devices () { | |
| if doing_variant fakechroot; then | |
| return 0 | |
| fi | |
| case "$HOST_OS" in | |
| kfreebsd*) | |
| in_target mount -t devfs devfs /dev ;; | |
| freebsd) | |
| mount -t devfs devfs $TARGET/dev ;; | |
| hurd*) | |
| # Use the setup-translators of the hurd package | |
| in_target /usr/lib/hurd/setup-translators -k ;; | |
| esac | |
| } | |
| setup_devices_simple () { | |
| # The list of devices that can be created in a container comes from | |
| # src/core/cgroup.c in the systemd source tree. | |
| mknod -m 666 $TARGET/dev/null c 1 3 | |
| mknod -m 666 $TARGET/dev/zero c 1 5 | |
| mknod -m 666 $TARGET/dev/full c 1 7 | |
| mknod -m 666 $TARGET/dev/random c 1 8 | |
| mknod -m 666 $TARGET/dev/urandom c 1 9 | |
| mknod -m 666 $TARGET/dev/tty c 5 0 | |
| mkdir $TARGET/dev/pts/ $TARGET/dev/shm/ | |
| # Inside a container, we might not be allowed to create /dev/ptmx. | |
| # If not, do the next best thing. | |
| if ! mknod -m 666 $TARGET/dev/ptmx c 5 2; then | |
| warning MKNOD "Could not create /dev/ptmx, falling back to symlink. This chroot will require /dev/pts mounted with ptmxmode=666" | |
| ln -s pts/ptmx $TARGET/dev/ptmx | |
| fi | |
| ln -s /proc/self/fd $TARGET/dev/fd | |
| ln -s /proc/self/fd/0 $TARGET/dev/stdin | |
| ln -s /proc/self/fd/1 $TARGET/dev/stdout | |
| ln -s /proc/self/fd/2 $TARGET/dev/stderr | |
| } | |
| setup_devices_fakechroot () { | |
| rm -rf "$TARGET/dev" | |
| ln -s /dev "$TARGET" | |
| } | |
| setup_dselect_method () { | |
| case "$1" in | |
| apt) | |
| mkdir -p "$TARGET/var/lib/dpkg" | |
| echo "apt apt" > "$TARGET/var/lib/dpkg/cmethopt" | |
| chmod 644 "$TARGET/var/lib/dpkg/cmethopt" | |
| ;; | |
| *) | |
| error 1 UNKNOWNDSELECT "unknown dselect method" | |
| ;; | |
| esac | |
| } | |
| # Find out where the runtime dynamic linker and the shared libraries | |
| # can be installed on each architecture: native, multilib and multiarch. | |
| # This data can be verified by checking the files in the debian/sysdeps/ | |
| # directory of the glibc package. | |
| # | |
| # This function must be updated to support any new architecture which | |
| # either installs the RTLD in a directory different from /lib or builds | |
| # multilib library packages. | |
| setup_merged_usr() { | |
| if [ "$MERGED_USR" = "no" ]; then return 0; fi | |
| local link_dir | |
| case $ARCH in | |
| hurd-*) return 0 ;; | |
| amd64) link_dir="lib32 lib64 libx32" ;; | |
| i386) link_dir="lib64 libx32" ;; | |
| mips|mipsel) | |
| link_dir="lib32 lib64" ;; | |
| mips64*|mipsn32*) | |
| link_dir="lib32 lib64 libo32" ;; | |
| powerpc) link_dir="lib64" ;; | |
| ppc64) link_dir="lib32 lib64" ;; | |
| ppc64el) link_dir="lib64" ;; | |
| s390x) link_dir="lib32" ;; | |
| sparc) link_dir="lib64" ;; | |
| sparc64) link_dir="lib32 lib64" ;; | |
| x32) link_dir="lib32 lib64 libx32" ;; | |
| esac | |
| link_dir="bin sbin lib $link_dir" | |
| local dir | |
| for dir in $link_dir; do | |
| ln -s usr/$dir $TARGET/$dir | |
| mkdir -p $TARGET/usr/$dir | |
| done | |
| } | |
| ################################################################ pkgdetails | |
| # NOTE | |
| # For the debootstrap udeb, pkgdetails is provided by the bootstrap-base | |
| # udeb, so the pkgdetails API needs to be kept in sync with that. | |
| if in_path perl; then | |
| PKGDETAILS=pkgdetails_perl | |
| pkgdetails_field () { | |
| # uniq field mirror Packages values... | |
| perl -le ' | |
| $unique = shift @ARGV; $field = lc(shift @ARGV); $mirror = shift @ARGV; | |
| %fields = map { $_, 0 } @ARGV; | |
| $prevpkg = ""; | |
| while (<STDIN>) { | |
| chomp; | |
| next if (/^ /); | |
| if (/^([^:]*:)\s*(.*)$/) { | |
| $f = lc($1); $v = $2; | |
| if ($f eq "package:") { | |
| $last = 0; | |
| $pkg = $v; | |
| if ($pkg ne $prevpkg) { | |
| print $output if defined $output; | |
| if ($unique && defined $output_val) { | |
| delete $fields{$output_val}; | |
| $last = 1 unless keys %fields; | |
| } | |
| $prevpkg = $pkg; | |
| } | |
| undef $output; | |
| undef $output_val; | |
| last if $last; | |
| } | |
| $ver = $v if ($f eq "version:"); | |
| $arc = $v if ($f eq "architecture:"); | |
| $fil = $v if ($f eq "filename:"); | |
| $chk = $v if (lc $f eq lc($ENV{DEBOOTSTRAP_CHECKSUM_FIELD}).":"); | |
| $siz = $v if ($f eq "size:"); | |
| $val = $v if ($f eq $field); | |
| } elsif (/^$/) { | |
| if (defined $val && defined $fields{$val}) { | |
| $output = sprintf "%s %s %s %s %s %s %s", | |
| $pkg, $ver, $arc, $mirror, $fil, $chk, $siz; | |
| $output_val = $val; | |
| } | |
| undef $val; | |
| } | |
| } | |
| print $output if defined $output; | |
| delete $fields{$output_val} if $unique && defined $output_val; | |
| for $v (keys %fields) { | |
| printf ("%s -\n", $v) if ($unique); | |
| } | |
| ' "$@" | |
| } | |
| pkgdetails_perl () { | |
| if [ "$1" = "WGET%" ]; then | |
| shift; | |
| perl -e ' | |
| $v = 0; | |
| $allow_percentage = 0; | |
| while (read STDIN, $x, 1) { | |
| if ($x =~ m/\s/) { | |
| $allow_percentage = 1; | |
| } elsif ($allow_percentage and $x =~ m/\d/) { | |
| $v *= 10; | |
| $v += $x; | |
| } elsif ($allow_percentage and $x eq "%") { | |
| printf "P: %d %d%s\n", int($v / 100.0 * ($ARGV[1] - $ARGV[0]) + $ARGV[0]), $ARGV[2], ($#ARGV == 3 ? " $ARGV[3]" : ""); | |
| $v = 0; | |
| } else { | |
| $v = 0; | |
| $allow_percentage = 0; | |
| } | |
| }' "$@" | |
| elif [ "$1" = "GETDEPS" ]; then | |
| local pkgdest="$2"; shift; shift | |
| perl -e ' | |
| $prevpkg = ""; | |
| @d = (); | |
| while (<STDIN>) { | |
| chomp; | |
| if (/^Package: (.*)$/) { | |
| $pkg = $1; | |
| if ($pkg ne $prevpkg) { | |
| for my $d (@d) { | |
| print "$d\n"; | |
| } | |
| } | |
| $prevpkg = $1; | |
| @d = (); | |
| } | |
| $in = 1 if (grep {$_ eq $pkg} @ARGV); | |
| $in = 0 if (/^$/); | |
| if ($in and (/^Depends: (.*)$/ or /^Pre-Depends: (.*)$/)) { | |
| for $d (split /\s*,\s*/, $1) { | |
| $d =~ s/\s*[|].*$//; | |
| $d =~ s/\s*[(].*[)]\s*//; | |
| $d =~ s/:.*//; | |
| push @d, $d; | |
| } | |
| } | |
| } | |
| for my $d (@d) { | |
| print "$d\n"; | |
| }' <"$pkgdest" "$@" | sort | uniq | |
| elif [ "$1" = "PKGS" ]; then | |
| local m="$2" | |
| local p="$3" | |
| shift; shift; shift | |
| pkgdetails_field 1 Package: "$m" "$@" < "$p" | |
| elif [ "$1" = "FIELD" ]; then | |
| local f="$2" | |
| local m="$3" | |
| local p="$4" | |
| shift; shift; shift; shift | |
| pkgdetails_field 0 "$f" "$m" "$@" < "$p" | |
| elif [ "$1" = "STANZAS" ]; then | |
| local pkgdest="$2"; shift; shift | |
| perl -e ' | |
| my $accum = ""; | |
| while (<STDIN>) { | |
| $accum .= $_; | |
| $in = 1 if (/^Package: (.*)$/ && grep {$_ eq $1} @ARGV); | |
| if ($in and /^$/) { | |
| print $accum; | |
| if (substr($accum, -1) != "\n") { | |
| print "\n\n"; | |
| } elsif (substr($accum, -2, 1) != "\n") { | |
| print "\n"; | |
| } | |
| $in = 0; | |
| } | |
| $accum = "" if /^$/; | |
| }' <"$pkgdest" "$@" | |
| fi | |
| } | |
| elif [ -e "/usr/lib/debootstrap/pkgdetails" ]; then | |
| PKGDETAILS="/usr/lib/debootstrap/pkgdetails" | |
| elif [ -e "$DEBOOTSTRAP_DIR/pkgdetails" ]; then | |
| PKGDETAILS="$DEBOOTSTRAP_DIR/pkgdetails" | |
| else | |
| PKGDETAILS="" | |
| fi | |
| ##################################################### dependency resolution | |
| resolve_deps () { | |
| local m1="${MIRRORS%% *}" | |
| local PKGS="$*" | |
| local ALLPKGS="$PKGS"; | |
| local ALLPKGS2=""; | |
| while [ "$PKGS" != "" ]; do | |
| local NEWPKGS="" | |
| for c in ${COMPONENTS:-$USE_COMPONENTS}; do | |
| local path="dists/$SUITE/$c/binary-$ARCH/Packages" | |
| local pkgdest="$TARGET/$($DLDEST pkg "$SUITE" "$c" "$ARCH" "$m1" "$path")" | |
| NEWPKGS="$NEWPKGS $("$PKGDETAILS" GETDEPS "$pkgdest" $PKGS)" | |
| done | |
| PKGS=$(echo "$PKGS $NEWPKGS" | tr ' ' '\n' | sort | uniq) | |
| local REALPKGS="" | |
| for c in ${COMPONENTS:-$USE_COMPONENTS}; do | |
| local path="dists/$SUITE/$c/binary-$ARCH/Packages" | |
| local pkgdest="$TARGET/$($DLDEST pkg "$SUITE" "$c" "$ARCH" "$m1" "$path")" | |
| REALPKGS="$REALPKGS $("$PKGDETAILS" PKGS REAL "$pkgdest" $PKGS | sed -n 's/ .*REAL.*$//p')" | |
| done | |
| PKGS="$REALPKGS" | |
| ALLPKGS2=$(echo "$PKGS $ALLPKGS" | tr ' ' '\n' | sort | uniq) | |
| PKGS=$(without "$ALLPKGS2" "$ALLPKGS") | |
| ALLPKGS="$ALLPKGS2" | |
| done | |
| echo $ALLPKGS | |
| } | |
| setup_available () { | |
| local m1="${MIRRORS%% *}" | |
| for c in ${COMPONENTS:-$USE_COMPONENTS}; do | |
| local path="dists/$SUITE/$c/binary-$ARCH/Packages" | |
| local pkgdest="$TARGET/$($DLDEST pkg "$SUITE" "$c" "$ARCH" "$m1" "$path")" | |
| # XXX: What if a package is in more than one component? | |
| # -- cjwatson 2009-07-29 | |
| "$PKGDETAILS" STANZAS "$pkgdest" "$@" | |
| done >"$TARGET/var/lib/dpkg/available" | |
| for pkg; do | |
| echo "$pkg install" | |
| done | in_target dpkg --set-selections | |
| } | |
| get_next_predep () { | |
| local stanza="$(in_target_nofail dpkg --predep-package)" | |
| [ "$stanza" ] || return 1 | |
| echo "$stanza" | grep '^Package:' | sed 's/^Package://; s/^ *//' | |
| } | |
| ################################################################### helpers | |
| # Return zero if it is possible to create devices and execute programs in | |
| # this directory. (Both may be forbidden by mount options, e.g. nodev and | |
| # noexec respectively.) | |
| check_sane_mount () { | |
| mkdir -p "$1" | |
| case "$HOST_OS" in | |
| *freebsd*|hurd*) | |
| ;; | |
| *) | |
| mknod "$1/test-dev-null" c 1 3 || return 1 | |
| if ! echo test > "$1/test-dev-null"; then | |
| rm -f "$1/test-dev-null" | |
| return 1 | |
| fi | |
| rm -f "$1/test-dev-null" | |
| ;; | |
| esac | |
| SH=/bin/sh | |
| [ -x $SH ] || SH=`which sh` | |
| cat > "$1/test-exec" <<EOF | |
| #! $SH | |
| : | |
| EOF | |
| chmod +x "$1/test-exec" | |
| if ! "$1/test-exec"; then | |
| rm -f "$1/test-exec" | |
| return 1 | |
| fi | |
| rm -f "$1/test-exec" | |
| return 0 | |
| } | |
| read_gpg_status () { | |
| badsig= | |
| unkkey= | |
| validsig= | |
| while read prefix keyword keyid rest; do | |
| [ "$prefix" = '[GNUPG:]' ] || continue | |
| case $keyword in | |
| BADSIG) badsig="$keyid" ;; | |
| NO_PUBKEY) unkkey="$keyid" ;; | |
| VALIDSIG) validsig="$keyid" ;; | |
| esac | |
| done | |
| if [ "$validsig" ]; then | |
| info VALIDRELSIG "Valid Release signature (key id %s)" "$validsig" | |
| elif [ "$badsig" ]; then | |
| error 1 BADRELSIG "Invalid Release signature (key id %s)" "$badsig" | |
| elif [ "$unkkey" ]; then | |
| error 1 UNKNOWNRELSIG "Release signed by unknown key (key id %s)" "$unkkey" | |
| else | |
| error 1 SIGCHECK "Error executing gpgv to check Release signature" | |
| fi | |
| } | |
| without () { | |
| # usage: without "a b c" "a d" -> "b" "c" | |
| (echo $1 | tr ' ' '\n' | sort | uniq; | |
| echo $2 $2 | tr ' ' '\n') | sort | uniq -u | tr '\n' ' ' | |
| echo | |
| } | |
| # Formerly called 'repeat', but that's a reserved word in zsh. | |
| repeatn () { | |
| local n="$1" | |
| shift | |
| while [ "$n" -gt 0 ]; do | |
| if "$@"; then | |
| break | |
| else | |
| n="$(( $n - 1 ))" | |
| sleep 1 | |
| fi | |
| done | |
| if [ "$n" -eq 0 ]; then return 1; fi | |
| return 0 | |
| } | |
| N_EXIT_THINGS=0 | |
| exit_function () { | |
| local n=0 | |
| while [ "$n" -lt "$N_EXIT_THINGS" ]; do | |
| (eval $(eval echo \${EXIT_THING_$n}) 2>/dev/null || true) | |
| n="$(( $n + 1 ))" | |
| done | |
| N_EXIT_THINGS=0 | |
| } | |
| trap "exit_function" 0 | |
| trap "exit 129" 1 | |
| trap "error 130 INTERRUPTED \"Interrupt caught ... exiting\"" 2 | |
| trap "exit 131" 3 | |
| trap "exit 143" 15 | |
| on_exit () { | |
| eval `echo EXIT_THING_${N_EXIT_THINGS}=\"$1\"` | |
| N_EXIT_THINGS="$(( $N_EXIT_THINGS + 1 ))" | |
| } | |
| ############################################################## fakechroot tools | |
| install_fakechroot_tools () { | |
| if [ "$VARIANT" = "fakechroot" ]; then | |
| export PATH=/usr/sbin:/sbin:$PATH | |
| fi | |
| mv "$TARGET/sbin/ldconfig" "$TARGET/sbin/ldconfig.REAL" | |
| echo \ | |
| "#!/bin/sh | |
| echo | |
| echo \"Warning: Fake ldconfig called, doing nothing\"" > "$TARGET/sbin/ldconfig" | |
| chmod 755 "$TARGET/sbin/ldconfig" | |
| echo \ | |
| "/sbin/ldconfig | |
| /sbin/ldconfig.REAL | |
| fakechroot" >> "$TARGET/var/lib/dpkg/diversions" | |
| mv "$TARGET/usr/bin/ldd" "$TARGET/usr/bin/ldd.REAL" | |
| cat << 'END' > "$TARGET/usr/bin/ldd" | |
| #!/usr/bin/perl | |
| # fakeldd | |
| # | |
| # Replacement for ldd with usage of objdump | |
| # | |
| # (c) 2003-2005 Piotr Roszatycki <dexter@debian.org>, BSD | |
| my %libs = (); | |
| my $status = 0; | |
| my $dynamic = 0; | |
| my $biarch = 0; | |
| my $ldlinuxsodir = "/lib"; | |
| my @ld_library_path = qw(/usr/lib /lib); | |
| sub ldso($) { | |
| my ($lib) = @_; | |
| my @files = (); | |
| if ($lib =~ /^\//) { | |
| $libs{$lib} = $lib; | |
| push @files, $lib; | |
| } else { | |
| foreach my $ld_path (@ld_library_path) { | |
| next unless -f "$ld_path/$lib"; | |
| my $badformat = 0; | |
| open OBJDUMP, "objdump -p $ld_path/$lib 2>/dev/null |"; | |
| while (my $line = <OBJDUMP>) { | |
| if ($line =~ /file format (\S*)$/) { | |
| $badformat = 1 unless $format eq $1; | |
| last; | |
| } | |
| } | |
| close OBJDUMP; | |
| next if $badformat; | |
| $libs{$lib} = "$ld_path/$lib"; | |
| push @files, "$ld_path/$lib"; | |
| } | |
| objdump(@files); | |
| } | |
| } | |
| sub objdump(@) { | |
| my (@files) = @_; | |
| my @libs = (); | |
| foreach my $file (@files) { | |
| open OBJDUMP, "objdump -p $file 2>/dev/null |"; | |
| while (my $line = <OBJDUMP>) { | |
| $line =~ s/^\s+//; | |
| my @f = split (/\s+/, $line); | |
| if ($line =~ /file format (\S*)$/) { | |
| if (not $format) { | |
| $format = $1; | |
| if ($unamearch eq "x86_64" and $format eq "elf32-i386") { | |
| my $link = readlink "/lib/ld-linux.so.2"; | |
| if ($link =~ /^\/emul\/ia32-linux\//) { | |
| $ld_library_path[-2] = "/emul/ia32-linux/usr/lib"; | |
| $ld_library_path[-1] = "/emul/ia32-linux/lib"; | |
| } | |
| } elsif ($unamearch =~ /^(sparc|sparc64)$/ and $format eq "elf64-sparc") { | |
| $ldlinuxsodir = "/lib64"; | |
| $ld_library_path[-2] = "/usr/lib64"; | |
| $ld_library_path[-1] = "/lib64"; | |
| } | |
| } else { | |
| next unless $format eq $1; | |
| } | |
| } | |
| if (not $dynamic and $f[0] eq "Dynamic") { | |
| $dynamic = 1; | |
| } | |
| next unless $f[0] eq "NEEDED"; | |
| if ($f[1] =~ /^ld-linux(\.|-)/) { | |
| $f[1] = "$ldlinuxsodir/" . $f[1]; | |
| } | |
| if (not defined $libs{$f[1]}) { | |
| $libs{$f[1]} = undef; | |
| push @libs, $f[1]; | |
| } | |
| } | |
| close OBJDUMP; | |
| } | |
| foreach my $lib (@libs) { | |
| ldso($lib); | |
| } | |
| } | |
| if ($#ARGV < 0) { | |
| print STDERR "fakeldd: missing file arguments\n"; | |
| exit 1; | |
| } | |
| while ($ARGV[0] =~ /^-/) { | |
| my $arg = $ARGV[0]; | |
| shift @ARGV; | |
| last if $arg eq "--"; | |
| } | |
| open LD_SO_CONF, "/etc/ld.so.conf"; | |
| while ($line = <LD_SO_CONF>) { | |
| chomp $line; | |
| unshift @ld_library_path, $line; | |
| } | |
| close LD_SO_CONF; | |
| unshift @ld_library_path, split(/:/, $ENV{LD_LIBRARY_PATH}); | |
| $unamearch = `/bin/uname -m`; | |
| chomp $unamearch; | |
| foreach my $file (@ARGV) { | |
| my $address; | |
| %libs = (); | |
| $dynamic = 0; | |
| if ($#ARGV > 0) { | |
| print "$file:\n"; | |
| } | |
| if (not -f $file) { | |
| print STDERR "ldd: $file: No such file or directory\n"; | |
| $status = 1; | |
| next; | |
| } | |
| objdump($file); | |
| if ($dynamic == 0) { | |
| print "\tnot a dynamic executable\n"; | |
| $status = 1; | |
| } elsif (scalar %libs eq "0") { | |
| print "\tstatically linked\n"; | |
| } | |
| if ($format =~ /^elf64-/) { | |
| $address = "0x0000000000000000"; | |
| } else { | |
| $address = "0x00000000"; | |
| } | |
| foreach $lib (keys %libs) { | |
| if ($libs{$lib}) { | |
| printf "\t%s => %s (%s)\n", $lib, $libs{$lib}, $address; | |
| } else { | |
| printf "\t%s => not found\n", $lib; | |
| } | |
| } | |
| } | |
| exit $status; | |
| END | |
| chmod 755 "$TARGET/usr/bin/ldd" | |
| echo \ | |
| "/usr/bin/ldd | |
| /usr/bin/ldd.REAL | |
| fakechroot" >> "$TARGET/var/lib/dpkg/diversions" | |
| } |