diff options
Diffstat (limited to 'functions')
-rw-r--r-- | functions | 1174 |
1 files changed, 1174 insertions, 0 deletions
diff --git a/functions b/functions new file mode 100644 index 0000000..fc346d2 --- /dev/null +++ b/functions @@ -0,0 +1,1174 @@ + +############################################################### smallutils + +smallyes() { + YES="${1-y}" + while echo "$YES" ; do : ; done +} + +############################################################### 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 + elif [ "$USE_GETTEXT_INTERACTION" ]; then + (printf "E: `LANG=$GETTEXT_LANG gettext debootstrap "$fmt"`\n" "$@") >&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 + elif [ "$USE_GETTEXT_INTERACTION" ]; then + printf "W: `LANG=$GETTEXT_LANG gettext debootstrap "$fmt"`\n" "$@" >&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 + elif [ "$USE_GETTEXT_INTERACTION" ]; then + printf "I: `LANG=$GETTEXT_LANG gettext debootstrap "$fmt"`\n" "$@" >&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" -a "$PROGRESS_NEXT" ]; then + wget "$@" 2>&1 >/dev/null | $PKGDETAILS "WGET%" $PROGRESS_NOW $PROGRESS_NEXT $PROGRESS_END >&3 + ret=$? + elif [ "$USE_BOOTFLOPPIES_INTERACTION" -a "$PROGRESS_NEXT" ]; then + wget "$@" 2>&1 >/dev/null | $PKGDETAILS "WGET%" $PROGRESS_NOW $PROGRESS_NEXT $PROGRESS_END "$PROGRESS_WHAT" >&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 + elif [ "$USE_BOOTFLOPPIES_INTERACTION" ]; then + PROGRESS_NOW="$now" + PROGRESS_END="$end" + PROGRESS_WHAT="`printf "$fmt" "$@"`" + PROGRESS_NEXT="" + printf "P: %s %s %s\n" $now $end "$PROGRESS_WHAT" >&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 + +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 +} + +########################################################## variant handling + +doing_variant () { + if [ "$1" = "$VARIANT" ]; then return 0; fi + if [ "$1" = "-" -a "$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 +} + +check_md5 () { + # args: dest md5 size + local expmd5="$2" + local expsize="$3" + relmd5=`md5sum < "$1" | sed 's/ .*$//'` + relsize=`wc -c < "$1"` + if [ "$expsize" -ne "$relsize" -o "$expmd5" != "$relmd5" ]; then + return 1 + fi + return 0 +} + +get () { + # args: from dest [md5sum size] [alt {md5sum size type}] + local displayname + if [ "${2%.deb}" != "$2" ]; then + displayname="$(echo "$2" | sed 's,^.*/,,;s,_.*$,,')" + else + displayname="$(echo "$1" | sed 's,^.*/,,')" + fi + + if [ -e "$2" ]; then + if [ "$3" = "" ]; then + return 0 + fi + info VALIDATING "Validating %s" "$displayname" + if check_md5 $2 $3 $4; then + return 0 + else + rm -f "$2" + fi + 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 md5="$(eval echo \${$a})" + local siz="$(eval echo \${$(( $a+1 ))})" + local typ="$(eval echo \${$(( $a+2 ))})" + local from + local dest + + case "$typ" in + "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 + + info RETRIEVING "Retrieving %s" "$displayname" + if ! just_get "$from" "$dest2"; then continue; fi + if [ "$md5" != "" ]; then + info VALIDATING "Validating %s" "$displayname" + if check_md5 $dest2 $md5 $siz; then + md5="" + fi + fi + if [ "$md5" = "" ]; then + [ "$dest2" = "$dest" ] || mv "$dest2" "$dest" + case "$typ" in + "gz") gunzip "$dest" ;; + "bz2") bunzip2 "$dest" ;; + esac + return 0 + else + warning CORRUPTFILE "%s was corrupt" "$from" + fi + 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" -o "${from#ftp://}" != "$from" ]; then + # http/ftp mirror + if wgetprogress -O "$dest" "$from"; then + return 0 + elif [ -s "$dest" ]; then + local iters=0 + while [ "$iters" -lt 3 ]; do + warning RETRYING "Retrying failed download of %s" "$from" + if wgetprogress -c -O "$dest" "$from"; then break; fi + iters="$(($iters + 1))" + done + 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 + 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_md5 () { + local reldest="$1" + local path="$2" + sed -n '/^[Mm][Dd]5[Ss][Uu][Mm]/,/^[^ ]/p' < $reldest | while read a b c; do + if [ "$c" = "$path" ]; then echo "$a $b"; fi + done | head -n 1 +} + +download_release_sig () { + local m1="$1" + local reldest="$2" + local relsigdest="$TARGET/$($DLDEST rel $SUITE $m1 dists/$SUITE/Release.gpg)" + + if [ -n "$KEYRING" ]; then + progress 0 100 DOWNRELSIG "Downloading Release file signature" + progress_next 50 + get "$m1/dists/$SUITE/Release.gpg" $relsigdest || + error 1 NOGETRELSIG "Failed getting release signature file %s" \ + "$m1/dists/$SUITE/Release.gpg" + progress 50 100 DOWNRELSIG "Downloading Release file signature" + + 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 reldest="$TARGET/$($DLDEST rel $SUITE $m1 dists/$SUITE/Release)" + progress 0 100 DOWNREL "Downloading Release file" + progress_next 100 + get "$m1/dists/$SUITE/Release" $reldest || + error 1 NOGETREL "Failed getting release file %s" "$m1/dists/$SUITE/Release" + + 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 [ "$COMPONENTS" = "" ]; then + mv $reldest "$reldest.malformed" + error 1 INVALIDREL "Invalid Release file, no valid components" + fi + progress 100 100 DOWNREL "Downloading Release file" + + download_release_sig "$m1" "$reldest" + + local totalpkgs=0 + for c in $COMPONENTS; do + local subpath="$c/binary-$ARCH/Packages" + local normmd="`get_release_md5 $reldest ${subpath}`" + if [ "$normmd" = "" ]; then + mv $reldest "$reldest.malformed" + error 1 MISSINGRELENTRY "Invalid Release file, no entry for %s" "$subpath" + fi + totalpkgs="$(( $totalpkgs + ${normmd#* } ))" + done + + local donepkgs=0 + progress 0 $totalpkgs DOWNPKGS "Downloading Packages files" + for c in $COMPONENTS; do + local subpath="$c/binary-$ARCH/Packages" + local path="dists/$SUITE/$subpath" + local bz2md="`get_release_md5 $reldest ${subpath}.bz2`" + local gzmd="`get_release_md5 $reldest ${subpath}.gz`" + local normmd="`get_release_md5 $reldest ${subpath}`" + local ext="$normmd ." + if [ -x /usr/bin/bunzip2 -a "$bz2md" != "" ]; then + ext="$ext $bz2md bz2" + fi + if [ -x /bin/gunzip -a "$gzmd" != "" ]; then + ext="$ext $gzmd gz" + fi + progress_next "$(($donepkgs + ${normmd#* }))" + for m in $MIRRORS; do + local pkgdest="$TARGET/$($DLDEST pkg $SUITE $c $ARCH $m $path)" + if get "$m/$path" "$pkgdest" $ext; then break; fi + done + donepkgs="$(($donepkgs + ${normmd#* }))" + 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 md5 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" $md5 $size; then + dloaddebs="$(($dloaddebs + $size))" + echo >>$TARGET/debootstrap/debpaths "$p $debdest" + else + warning COULDNTDL "Couldn't download package %s" "$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="$*" + 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 [ "$pkgs_to_get" = "" ]; then break; fi + done 6>&1 + if [ "$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%% *} + progress 0 100 DOWNMAINPKGS "Downloading Packages file" + progress_next 100 + COMPONENTS=main + 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 [ -x /bin/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 continue; fi + size="${details##* }"; details="${details% *}" + md5="${details##* }"; details="${details% *}" + local debdest="$($DLDEST deb $details)" + if get "$m/${details##* }" "$TARGET/$debdest" $md5 $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 + +extract () { ( + cd "$TARGET" + local p=0 + for pkg in $(debfor "$@"); do + p="$(($p + 1))" + progress "$p" "$#" EXTRACTPKGS "Extracting packages" + packagename="$(echo "$pkg" | sed 's,^.*/,,;s,_.*$,,')" + info EXTRACTING "Extracting %s..." "$packagename" + ar -p ./$pkg data.tar.gz | zcat | tar -xf - + done +); } + +in_target_nofail () { + if ! eval chroot "$TARGET" "$@" 2>/dev/null; then + true + fi + return 0 +} + +in_target_failmsg () { + local code="$1" + local msg="$2" + local arg="$3" + shift; shift; shift + if ! eval chroot "$TARGET" "$@"; then + warning "$code" "$msg" "$arg" + return 1 + fi + return 0 +} + +in_target () { + in_target_failmsg IN_TARGET_FAIL "Failure trying to run: %s" "chroot $TARGET $*" "$@" +} + +###################################################### standard setup stuff + +conditional_cp () { + if [ ! -e "$2/$1" ]; then + if [ -L "$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; 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 -a ! -e "$TARGET/etc/apt/sources.list" ]; then + setup_apt_sources "htp://debootstrap.invalid/" + fi +} + +setup_proc () { + case "$ARCH" in + kfreebsd-*) + on_exit "umount $TARGET/dev" + on_exit "umount $TARGET/proc" + umount $TARGET/proc 2>/dev/null || true + in_target mount -t linprocfs proc /proc + ;; + *) + on_exit "umount $TARGET/dev/pts" + on_exit "umount $TARGET/dev/shm" + on_exit "umount $TARGET/proc/bus/usb" + on_exit "umount $TARGET/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 + on_exit "umount $TARGET/sys" + umount $TARGET/sys 2>/dev/null || true + in_target mount -t sysfs sysfs /sys + fi + ;; + esac +} + +setup_proc_fakechroot () { + rm -rf "$TARGET/proc" + ln -s /proc "$TARGET" +} + +setup_devices () { + case "$ARCH" in + kfreebsd-*) + in_target mount -t devfs devfs /dev ;; + *) + if [ -e $DEVICES_TARGZ ]; then + (cd "$TARGET"; zcat $DEVICES_TARGZ | tar -xf -) + else + if [ -e /dev/.devfsd ] ; then + in_target mount -t devfs devfs /dev + else + error 1 NODEVTGZ "no %s. cannot create devices" "$DEVICES_TARGZ" + fi + fi + ;; + esac +} + +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 +} + +################################################################ pkgdetails + +if [ -x /usr/bin/perl ]; then + PKGDETAILS=pkgdetails_perl + + pkgdetails_field () { + # uniq field mirror Packages values... + perl -le ' +$unique = shift @ARGV; $field = lc(shift @ARGV); $mirror = shift @ARGV; +$cnt = length(@ARGV); +%fields = map { $_, 0 } @ARGV; +while (<STDIN>) { + chomp; + next if (/^ /); + if (/^([^:]*:)\s*(.*)$/) { + $f = lc($1); $v = $2; + $pkg = $v if ($f eq "package:"); + $ver = $v if ($f eq "version:"); + $arc = $v if ($f eq "architecture:"); + $fil = $v if ($f eq "filename:"); + $md5 = $v if ($f eq "md5sum:"); + $siz = $v if ($f eq "size:"); + $val = $v if ($f eq $field); + } elsif (/^$/) { + if (defined $val && defined $fields{$val}) { + $cnt++; + printf "%s %s %s %s %s %s %s\n", + $pkg, $ver, $arc, $mirror, $fil, $md5, $siz; + if ($unique) { + delete $fields{$val}; + last if (--$cnt <= 0); + } + } + undef $val; + } +} +for $v (keys %fields) { + printf ("%s -\n", $v) if ($unique); +} +' "$@" + } + + pkgdetails_perl () { + if [ "$1" = "WGET%" ]; then + shift; + perl -e '$v = 0; while (read STDIN, $x, 1) { if ($x =~ m/\d/) { $v *= 10; $v += $x; } elsif ($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; } }' "$@" + elif [ "$1" = "GETDEPS" ]; then + local pkgdest="$2"; shift; shift + perl -e 'while (<STDIN>) { chomp; $in = 1 if (/^Package: (.*)$/ && grep {$_ eq $1} @ARGV); $in = 0 if (/^$/); if ($in and (/^Depends: (.*)$/ or /^Pre-Depends: (.*)$/)) { for $d (split /\s*,\s*/, $1) { $d =~ s/\s*[|].*$//; $d =~ s/\s*[(].*[)]\s*//; 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" + fi + } +elif [ -e "$DEBOOTSTRAP_DIR/pkgdetails" ]; then + PKGDETAILS=$DEBOOTSTRAP_DIR/pkgdetails +else + PKGDETAILS="" +fi + +##################################################### dependency resolution + +resolve_deps () { + local m1=${MIRRORS%% *} + + # XXX: I can't think how to deal well with dependency resolution and + # lots of Packages files. -- aj 2005/06/12 + + c="${COMPONENTS%% *}" + local path="dists/$SUITE/$c/binary-$ARCH/Packages" + local pkgdest="$TARGET/$($DLDEST pkg $SUITE $c $ARCH $m1 $path)" + + local PKGS="$*" + local ALLPKGS="$PKGS"; + local ALLPKGS2=""; + while [ "$PKGS" != "" ]; do + PKGS=$("$PKGDETAILS" GETDEPS "$pkgdest" $PKGS) + PKGS=$("$PKGDETAILS" PKGS REAL "$pkgdest" $PKGS | sed -n 's/ .*REAL.*$//p') + ALLPKGS2=$(echo "$PKGS $ALLPKGS" | tr ' ' '\n' | sort | uniq) + PKGS=$(without "$ALLPKGS2" "$ALLPKGS") + ALLPKGS="$ALLPKGS2" + done + echo $ALLPKGS +} + +################################################################### helpers + +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 +} + +repeat () { + 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 () { + 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" + +} |