1############################################################### smallutils 2 3smallyes() { 4 YES="${1-y}" 5 while echo "$YES" 2>/dev/null ; do : ; done 6} 7 8in_path () { 9 local OLD_IFS="$IFS" 10 IFS=":" 11 for dir in $PATH; do 12 if [ -x "$dir/$1" ]; then 13 IFS="$OLD_IFS" 14 return 0 15 fi 16 done 17 IFS="$OLD_IFS" 18 return 1 19} 20 21############################################################### interaction 22 23error () { 24 # <error code> <name> <string> <args> 25 local err name fmt 26 err="$1" 27 name="$2" 28 fmt="$3" 29 shift; shift; shift 30 if [ "$USE_DEBIANINSTALLER_INTERACTION" ]; then 31 (echo "E: $name" 32 for x in "$@"; do echo "EA: $x"; done 33 echo "EF: $fmt") >&4 34 else 35 (printf "E: $fmt\n" "$@") >&4 36 fi 37 exit "$err" 38} 39 40warning () { 41 # <name> <string> <args> 42 local name fmt 43 name="$1" 44 fmt="$2" 45 shift; shift 46 if [ "$USE_DEBIANINSTALLER_INTERACTION" ]; then 47 (echo "W: $name" 48 for x in "$@"; do echo "WA: $x"; done 49 echo "WF: $fmt") >&4 50 else 51 printf "W: $fmt\n" "$@" >&4 52 fi 53} 54 55info () { 56 # <name> <string> <args> 57 local name fmt 58 name="$1" 59 fmt="$2" 60 shift; shift 61 if [ "$USE_DEBIANINSTALLER_INTERACTION" ]; then 62 (echo "I: $name" 63 for x in "$@"; do echo "IA: $x"; done 64 echo "IF: $fmt") >&4 65 else 66 printf "I: $fmt\n" "$@" >&4 67 fi 68} 69 70PROGRESS_NOW=0 71PROGRESS_END=0 72PROGRESS_NEXT="" 73PROGRESS_WHAT="" 74 75progress_next () { 76 PROGRESS_NEXT="$1" 77} 78 79wgetprogress () { 80 [ ! "$VERBOSE" ] && NVSWITCH="-nv" 81 local ret=0 82 if [ "$USE_DEBIANINSTALLER_INTERACTION" ] && [ "$PROGRESS_NEXT" ]; then 83 # The exit status of a pipeline is that of the last command in 84 # the pipeline, so wget's exit status must be saved in the 85 # pipeline's first command. Since commands in a pipeline run in 86 # subshells, we have to print the exit status (on a file 87 # descriptor other than standard output, which is used by the 88 # pipeline itself) and then assign it to $ret outside of the 89 # pipeline. The "||" is necessary due to "set -e"; otherwise, a 90 # non-zero exit status would cause the echo command to be 91 # skipped. If wget succeeds, $ret will be "", so it then has to 92 # be set to a default value of 0. 93 ret=$({ { wget $@ 2>&1 >/dev/null || echo $? >&2; } | "$PKGDETAILS" "WGET%" "$PROGRESS_NOW" "$PROGRESS_NEXT" "$PROGRESS_END" >&3; } 2>&1) 94 : ${ret:=0} 95 else 96 wget ${NVSWITCH:+"$NVSWITCH"} "$@" 97 ret=$? 98 fi 99 return $ret 100} 101 102progress () { 103 # <now> <end> <name> <string> <args> 104 local now end name fmt 105 now="$1" 106 end="$2" 107 name="$3" 108 fmt="$4" 109 shift; shift; shift; shift 110 if [ "$USE_DEBIANINSTALLER_INTERACTION" ]; then 111 PROGRESS_NOW="$now" 112 PROGRESS_END="$end" 113 PROGRESS_NEXT="" 114 (echo "P: $now $end $name" 115 for x in "$@"; do echo "PA: $x"; done 116 echo "PF: $fmt") >&3 117 fi 118} 119 120dpkg_progress () { 121 # <now> <end> <name> <desc> UNPACKING|CONFIGURING 122 local now end name desc action expect 123 now="$1" 124 end="$2" 125 name="$3" 126 desc="$4" 127 action="$5" 128 expect="" 129 130 if [ "$action" = UNPACKING ]; then 131 expect=half-installed 132 elif [ "$action" = CONFIGURING ]; then 133 expect=half-configured 134 fi 135 136 dp () { 137 now=$(($now + ${1:-1})) 138 } 139 140 exitcode=0 141 while read status pkg qstate; do 142 if [ "$status" = "EXITCODE" ]; then 143 exitcode="$pkg" 144 continue 145 fi 146 [ "$qstate" = "$expect" ] || continue 147 case $qstate in 148 half-installed) 149 dp; progress "$now" "$end" "$name" "$desc" 150 info "$action" "Unpacking %s..." "${pkg%:}" 151 expect="unpacked" 152 ;; 153 unpacked) 154 expect="half-installed" 155 ;; 156 half-configured) 157 dp; progress "$now" "$end" "$name" "$desc" 158 info "$action" "Configuring %s..." "${pkg%:}" 159 expect="installed" 160 ;; 161 installed) 162 expect="half-configured" 163 ;; 164 esac 165 done 166 return "$exitcode" 167} 168 169############################################################# set variables 170 171default_mirror () { 172 DEF_MIRROR="$1" 173} 174 175FINDDEBS_NEEDS_INDICES="false" 176finddebs_style () { 177 case "$1" in 178 hardcoded) 179 ;; 180 from-indices) 181 FINDDEBS_NEEDS_INDICES="true" 182 ;; 183 *) 184 error 1 BADFINDDEBS "unknown finddebs style" 185 ;; 186 esac 187} 188 189mk_download_dirs () { 190 if [ "$DLDEST" = "apt_dest" ]; then 191 mkdir -p "$TARGET/$APTSTATE/lists/partial" 192 mkdir -p "$TARGET/var/cache/apt/archives/partial" 193 fi 194} 195 196download_style () { 197 case "$1" in 198 apt) 199 if [ "$2" = "var-state" ]; then 200 APTSTATE="var/state/apt" 201 else 202 APTSTATE="var/lib/apt" 203 fi 204 DLDEST="apt_dest" 205 export APTSTATE DLDEST DEBFOR 206 ;; 207 *) 208 error 1 BADDLOAD "unknown download style" 209 ;; 210 esac 211} 212 213keyring () { 214 # avoid unnecessary warning with --second-stage 215 if [ -z "$KEYRING" ] && [ "$SECOND_STAGE_ONLY" != true ]; then 216 if [ -e "$1" ]; then 217 KEYRING="$1" 218 elif [ -z "$DISABLE_KEYRING" ]; then 219 if [ -n "$DEF_HTTPS_MIRROR" ] && [ -z "$USER_MIRROR" ] && [ -z "$FORCE_KEYRING" ]; then 220 info KEYRING "Keyring file not available at %s; switching to https mirror %s" "$1" "$DEF_HTTPS_MIRROR" 221 USER_MIRROR="$DEF_HTTPS_MIRROR" 222 else 223 warning KEYRING "Cannot check Release signature; keyring file not available %s" "$1" 224 if [ -n "$FORCE_KEYRING" ]; then 225 error 1 KEYRING "Keyring-based check was requested; aborting accordingly" 226 fi 227 fi 228 fi 229 fi 230} 231 232detect_container () { 233 if [ "$container" = lxc ]; then 234 CONTAINER="lxc" 235 elif /usr/local/bin/grep -qs container=lxc-libvirt /proc/1/environ; then 236 CONTAINER="lxc-libvirt" 237 elif /usr/local/bin/grep -qs ^systemd-nspawn$ /run/systemd/container || /usr/local/bin/grep -qs systemd-nspawn /proc/1/environ || [ "$container" = "systemd-nspawn" ]; then 238 CONTAINER="systemd-nspawn" 239 elif /usr/local/bin/grep -qs '[[:space:]]/docker/.*/sys/fs/cgroup' /proc/1/mountinfo; then 240 CONTAINER="docker" 241 else 242 CONTAINER="" 243 fi 244} 245 246########################################################## variant handling 247 248doing_variant () { 249 if [ "$1" = "$VARIANT" ]; then return 0; fi 250 if [ "$1" = "-" ] && [ "$VARIANT" = "" ]; then return 0; fi 251 return 1 252} 253 254SUPPORTED_VARIANTS="-" 255variants () { 256 SUPPORTED_VARIANTS="$*" 257 for v in $*; do 258 if doing_variant "$v"; then return 0; fi 259 done 260 error 1 UNSUPPVARIANT "unsupported variant" 261} 262 263########################################################### option handling 264check_conflicting_option () { 265 if ( [ "$set_what_to_do" = --foreign ] && [ "${1%%=*}" = --unpack-tarball ] ) || \ 266 ( [ "${set_what_to_do%%=*}" = "--unpack-tarball" ] && [ "$1" = --foreign ] ); then 267 LOOSEN_CONFLICTING_RESTRICTION="true" 268 elif [ -n "$set_what_to_do" ]; then 269 error 1 ARG_CONFLICTING "$set_what_to_do is specified with $1, please use only one of those options." 270 fi 271 set_what_to_do="$1" 272} 273 274################################################# work out names for things 275 276mirror_style () { 277 case "$1" in 278 release) 279 DOWNLOAD_INDICES="download_release_indices" 280 DOWNLOAD_DEBS="download_release" 281 ;; 282 main) 283 DOWNLOAD_INDICES="download_main_indices" 284 DOWNLOAD_DEBS="download_main" 285 ;; 286 *) 287 error 1 BADMIRROR "unknown mirror style" 288 ;; 289 esac 290 export DOWNLOAD_INDICES 291 export DOWNLOAD_DEBS 292} 293 294force_md5 () { 295 DEBOOTSTRAP_CHECKSUM_FIELD=MD5SUM 296 export DEBOOTSTRAP_CHECKSUM_FIELD 297} 298 299verify_checksum () { 300 # args: dest checksum size 301 local expchecksum="$2" 302 local expsize="$3" 303 if [ "$DEBOOTSTRAP_CHECKSUM_FIELD" = "MD5SUM" ]; then 304 if in_path md5sum; then 305 relchecksum=$(md5sum < "$1" | sed 's/ .*$//') 306 elif in_path md5; then 307 relchecksum=$(md5 < "$1") 308 else 309 error 1 SIGCHECK "Cannot check md5sum" 310 fi 311 else 312 if in_path "sha${SHA_SIZE}sum"; then 313 relchecksum="$(sha${SHA_SIZE}sum < "$1" | sed 's/ .*$//')" 314 elif in_path "sha${SHA_SIZE}"; then 315 relchecksum="$(sha${SHA_SIZE} < "$1")" 316 else 317 error 1 SIGCHECK "Cannot check sha${SHA_SIZE}sum" 318 fi 319 fi 320 relsize="$(wc -c < "$1")" 321 if [ "$expsize" -ne "$relsize" ] || [ "$expchecksum" != "$relchecksum" ]; then 322 return 1 323 fi 324 return 0 325} 326 327get () { 328 # args: from dest 'nocache' 329 # args: from dest [checksum size] [alt {checksum size type}] 330 # args: from dest 'byhash' [checksum size] [alt {checksum size type}] 331 local displayname 332 local versionname 333 local from_base 334 local dest_base 335 local nocache="" 336 local byhash="" 337 from_base="$1"; shift 338 dest_base="$1"; shift 339 if [ "$1" = "nocache" ]; then 340 nocache="true"; shift 341 elif [ "$1" = "byhash" ]; then 342 byhash="true"; shift 343 fi 344 if [ "${dest_base%.deb}" != "$dest_base" ]; then 345 displayname="$(echo "$dest_base" | sed 's,^.*/,,;s,_.*$,,')" 346 versionname="$(echo "$dest_base" | sed 's,^.*/,,' | cut -d_ -f2 | sed 's/%3a/:/')" 347 else 348 displayname="$(echo "$from_base" | sed 's,^.*/,,')" 349 fi 350 351 if [ -e "$dest_base" ]; then 352 if [ -z "$1" ]; then 353 return 0 354 elif [ -n "$nocache" ]; then 355 rm -f "$dest_base" 356 else 357 info VALIDATING "Validating %s %s" "$displayname" "$versionname" 358 if verify_checksum "$dest_base" "$1" "$2"; then 359 return 0 360 else 361 rm -f "$dest_base" 362 fi 363 fi 364 fi 365 366 if [ "$#" -gt 3 ]; then 367 local st=1 368 if [ "$3" = "-" ]; then st=4; fi 369 local order="$(a=$st; while [ "$a" -le $# ]; do eval echo \"\${$(($a+1))}\" $a; 370 a=$(($a + 3)); done | sort -n | sed 's/.* //')" 371 else 372 local order=1 373 fi 374 for a in $order; do 375 local checksum siz typ from dest iters 376 checksum="$(eval echo \${$a})" 377 siz="$(eval echo \${$(( $a+1 ))})" 378 typ="$(eval echo \${$(( $a+2 ))})" 379 iters="0" 380 381 case "$typ" in 382 xz) from="$from_base.xz"; dest="$dest_base.xz" ;; 383 bz2) from="$from_base.bz2"; dest="$dest_base.bz2" ;; 384 gz) from="$from_base.gz"; dest="$dest_base.gz" ;; 385 *) from="$from_base"; dest="$dest_base" ;; 386 esac 387 388 if [ ! -z "$CACHE_DIR" ]; then 389 dest="${dest%%*/}" 390 elif [ "${dest#/}" = "$dest" ]; then 391 dest="./$dest" 392 fi 393 local dest2="$dest" 394 if [ -d "${dest2%/*}/partial" ]; then 395 dest2="${dest2%/*}/partial/${dest2##*/}" 396 fi 397 398 while [ "$iters" -lt 10 ]; do 399 local from2="" 400 info RETRIEVING "Retrieving %s %s" "$displayname" "$versionname" 401 if [ "$checksum" != "" ] && [ "$byhash" != "" ]; then 402 # assume we don't mix acquire-by-hash and md5 403 from2="$(dirname "$from")/by-hash/SHA${SHA_SIZE}/$checksum" 404 fi 405 if [ ! -e "$dest2" ]; then 406 if [ -z "$from2" ] || ! just_get "$from2" "$dest2"; then 407 if ! just_get "$from" "$dest2"; then continue 2; fi 408 fi 409 fi 410 if [ "$checksum" != "" ]; then 411 info VALIDATING "Validating %s %s" "$displayname" "$versionname" 412 if verify_checksum "$dest2" "$checksum" "$siz"; then 413 checksum="" 414 fi 415 fi 416 if [ -z "$checksum" ]; then 417 [ "$dest2" = "$dest" ] || mv "$dest2" "$dest" 418 case "$typ" in 419 gz) gunzip "$dest" ;; 420 bz2) bunzip2 "$dest" ;; 421 xz) unxz "$dest" ;; 422 esac 423 return 0 424 else 425 rm -f "$dest2" 426 warning RETRYING "Retrying failed download of %s" "$from" 427 iters=$(($iters + 1)) 428 fi 429 done 430 warning CORRUPTFILE "%s was corrupt" "$from" 431 done 432 return 1 433} 434 435just_get () { 436 # args: from dest 437 local from="$1" 438 local dest="$2" 439 mkdir -p "${dest%/*}" 440 if [ "${from#null:}" != "$from" ]; then 441 error 1 NOTPREDL "%s was not pre-downloaded" "${from#null:}" 442 elif [ "${from#http://}" != "$from" ] || [ "${from#https://}" != "$from" ] || [ "${from#ftp://}" != "$from" ]; then 443 # http/https/ftp mirror 444 if wgetprogress ${CHECKCERTIF:+"$CHECKCERTIF"} ${CERTIFICATE:+"$CERTIFICATE"} ${PRIVATEKEY:+"$PRIVATEKEY"} -O "$dest" "$from"; then 445 return 0 446 else 447 rm -f "$dest" 448 return 1 449 fi 450 elif [ "${from#file:}" != "$from" ]; then 451 local base="${from#file:}" 452 if [ "${base#//}" != "$base" ]; then 453 base="/${from#file://*/}" 454 fi 455 if [ -e "$base" ]; then 456 cp "$base" "$dest" 457 return 0 458 else 459 return 1 460 fi 461 elif [ "${from#ssh:}" != "$from" ]; then 462 local ssh_dest="$(echo "$from" | sed -e 's#ssh://##' -e 's#/#:/#')" 463 if [ -n "$ssh_dest" ]; then 464 scp "$ssh_dest" "$dest" 465 return 0 466 else 467 return 1 468 fi 469 else 470 error 1 UNKNOWNLOC "unknown location %s" "$from" 471 fi 472} 473 474download () { 475 mk_download_dirs 476 "$DOWNLOAD_DEBS" "$(echo "$@" | tr ' ' '\n' | sort)" 477} 478 479download_indices () { 480 mk_download_dirs 481 "$DOWNLOAD_INDICES" "$(echo "$@" | tr ' ' '\n' | sort)" 482} 483 484debfor () { 485 (while read pkg path; do 486 for p in "$@"; do 487 [ "$p" = "$pkg" ] || continue; 488 echo "$path" 489 done 490 done <"$TARGET/debootstrap/debpaths" 491 ) 492} 493 494apt_dest () { 495 # args: 496 # deb package version arch mirror path 497 # pkg suite component arch mirror path 498 # rel suite mirror path 499 case "$1" in 500 deb) 501 echo "/var/cache/apt/archives/${2}_${3}_${4}.deb" | sed 's/:/%3a/' 502 ;; 503 pkg) 504 local m="$5" 505 printf "%s" "$APTSTATE/lists/" 506 echo "${m}_$6" | sed -e 's,^[^:]\+://,,' -e 's/\//_/g' 507 ;; 508 rel) 509 local m="$3" 510 printf "%s" "$APTSTATE/lists/" 511 echo "${m}_$4" | sed -e 's,^[^:]\+://,,' -e 's/\//_/g' 512 ;; 513 esac 514} 515 516################################################################## download 517 518get_release_checksum () { 519 local reldest path 520 reldest="$1" 521 path="$2" 522 if [ "$DEBOOTSTRAP_CHECKSUM_FIELD" = MD5SUM ]; then 523 local match="^[Mm][Dd]5[Ss][Uu][Mm]" 524 else 525 local match="^[Ss][Hh][Aa]$SHA_SIZE:" 526 fi 527 sed -n "/$match/,/^[^ ]/p" < "$reldest" | \ 528 while read a b c; do 529 if [ "$c" = "$path" ]; then echo "$a $b"; fi 530 done | head -n 1 531} 532 533extract_release_components () { 534 local reldest="$1"; shift 535 TMPCOMPONENTS="$(sed -n 's/Components: *//p' "$reldest")" 536 for c in $TMPCOMPONENTS ; do 537 eval " 538 case \"\$c\" in 539 $USE_COMPONENTS) 540 COMPONENTS=\"\$COMPONENTS \$c\" 541 ;; 542 esac 543 " 544 done 545 546 if [ -z "$COMPONENTS" ]; then 547 mv "$reldest" "$reldest.malformed" 548 error 1 INVALIDREL "Invalid Release file, no valid components" 549 fi 550} 551 552CODENAME="" 553validate_suite () { 554 local reldest suite 555 reldest="$1" 556 557 CODENAME=$(sed -n "s/^Codename: *//p" "$reldest") 558 suite=$(sed -n "s/^Suite: *//p" "$reldest") 559 560 for s in $SUITE $EXTRA_SUITES; do 561 if [ "$s" = "$suite" ] || [ "$s" = "$CODENAME" ]; then 562 return 0 563 fi 564 done 565 if [ "$EXTRA_SUITES" = "" ]; then 566 error 1 WRONGSUITE "Asked to install suite %s, but got %s (codename: %s) from mirror" "$SUITE" "$suite" "$CODENAME" 567 else 568 error 1 WRONGSUITE "Asked to install suites %s %s, but got %s (codename: %s) from mirror" "$SUITE" "$EXTRA_SUITES" "$suite" "$CODENAME" 569 fi 570} 571 572split_inline_sig () { 573 local inreldest reldest relsigdest 574 inreldest="$1" 575 reldest="$2" 576 relsigdest="$3" 577 578 # Note: InRelease files are fun since one needs to remove the 579 # last newline from the PGP SIGNED MESSAGE part, while keeping 580 # the PGP SIGNATURE part intact. This shell implementation 581 # should work on most if not all systems, instead of trying to 582 # sed/tr/head, etc. 583 rm -f "$reldest" "$relsigdest" 584 nl="" 585 state="pre-begin" 586 while IFS= read -r line; do 587 case "${state}" in 588 pre-begin) 589 if [ "x${line}" = "x-----BEGIN PGP SIGNED MESSAGE-----" ]; then 590 state="begin" 591 fi 592 ;; 593 begin) 594 if [ "x${line}" = "x" ]; then 595 state="data" 596 fi 597 ;; 598 data) 599 if [ "x${line}" = "x-----BEGIN PGP SIGNATURE-----" ]; then 600 printf "%s\n" "${line}" > "$relsigdest" 601 state="signature" 602 else 603 printf "${nl}%s" "${line}" >> "$reldest" 604 nl="\n" 605 fi 606 ;; 607 signature) 608 printf "%s\n" "${line}" >> "$relsigdest" 609 if [ "x${line}" = "x-----END PGP SIGNATURE-----" ]; then 610 break 611 fi 612 esac 613 done < "$inreldest" 614} 615 616download_release_sig () { 617 local m1 suite inreldest reldest relsigdest 618 m1="$1" 619 suite="$2" 620 inreldest="$3" 621 reldest="$4" 622 relsigdest="$5" 623 624 progress 0 100 DOWNREL "Downloading Release file" 625 progress_next 100 626 if get "$m1/dists/$suite/InRelease" "$inreldest" nocache; then 627 split_inline_sig "$inreldest" "$reldest" "$relsigdest" 628 progress 100 100 DOWNREL "Downloading Release file" 629 else 630 get "$m1/dists/$suite/Release" "$reldest" nocache || 631 error 1 NOGETREL "Failed getting release file %s" "$m1/dists/$suite/Release" 632 progress 100 100 DOWNREL "Downloading Release file" 633 fi 634 if [ -n "$KEYRING" ] && [ -z "$DISABLE_KEYRING" ]; then 635 progress 0 100 DOWNRELSIG "Downloading Release file signature" 636 if ! [ -f "$relsigdest" ]; then 637 progress_next 50 638 get "$m1/dists/$suite/Release.gpg" "$relsigdest" nocache || 639 error 1 NOGETRELSIG "Failed getting release signature file %s" \ 640 "$m1/dists/$suite/Release.gpg" 641 progress 50 100 DOWNRELSIG "Downloading Release file signature" 642 fi 643 644 info RELEASESIG "Checking Release signature" 645 # Don't worry about the exit status from gpgv2; parsing the output will 646 # take care of that. 647 (gpgv2 --status-fd 1 --keyring "$KEYRING" --ignore-time-conflict \ 648 "$relsigdest" "$reldest" || true) | read_gpg_status 649 progress 100 100 DOWNRELSIG "Downloading Release file signature" 650 fi 651} 652 653download_release_indices () { 654 local m1 inreldest reldest relsigdest totalpkgs \ 655 subpath xzi bz2i gzi normi i ext \ 656 donepkgs pkgdest acquirebyhash 657 m1="${MIRRORS%% *}" 658 for s in $SUITE $EXTRA_SUITES; do 659 inreldest="$TARGET/$($DLDEST rel "$s" "$m1" "dists/$s/InRelease")" 660 reldest="$TARGET/$($DLDEST rel "$s" "$m1" "dists/$s/Release")" 661 relsigdest="$TARGET/$($DLDEST rel "$s" "$m1" "dists/$s/Release.gpg")" 662 663 download_release_sig "$m1" "$s" "$inreldest" "$reldest" "$relsigdest" 664 665 validate_suite "$reldest" 666 667 extract_release_components "$reldest" 668 669 acquirebyhash=$(/usr/local/bin/grep "^Acquire-By-Hash: yes$" "$reldest" || true) 670 totalpkgs=0 671 for c in $COMPONENTS; do 672 subpath="$c/binary-$ARCH/Packages" 673 xzi="$(get_release_checksum "$reldest" "$subpath.xz")" 674 bz2i="$(get_release_checksum "$reldest" "$subpath.bz2")" 675 gzi="$(get_release_checksum "$reldest" "$subpath.gz")" 676 normi="$(get_release_checksum "$reldest" "$subpath")" 677 if [ "$normi" != "" ]; then 678 i="$normi" 679 elif in_path bunzip2 && [ "$bz2i" != "" ]; then 680 i="$bz2i" 681 elif in_path unxz && [ "$xzi" != "" ]; then 682 i="$xzi" 683 elif in_path gunzip && [ "$gzi" != "" ]; then 684 i="$gzi" 685 fi 686 if [ "$i" != "" ]; then 687 totalpkgs=$(( $totalpkgs + ${i#* } )) 688 else 689 mv "$reldest" "$reldest.malformed" 690 error 1 MISSINGRELENTRY "Invalid Release file, no entry for %s" "$subpath" 691 fi 692 done 693 694 donepkgs=0 695 progress 0 $totalpkgs DOWNPKGS "Downloading Packages files" 696 for c in $COMPONENTS; do 697 subpath="$c/binary-$ARCH/Packages" 698 path="dists/$s/$subpath" 699 xzi="$(get_release_checksum "$reldest" "$subpath.xz")" 700 bz2i="$(get_release_checksum "$reldest" "$subpath.bz2")" 701 gzi="$(get_release_checksum "$reldest" "$subpath.gz")" 702 normi="$(get_release_checksum "$reldest" "$subpath")" 703 ext="" 704 if [ "$acquirebyhash" != "" ]; then 705 ext="$ext byhash" 706 fi 707 if [ "$normi" != "" ]; then 708 ext="$ext $normi ." 709 i="$normi" 710 fi 711 if in_path unxz && [ "$xzi" != "" ]; then 712 ext="$ext $xzi xz" 713 i="${i:-$xzi}" 714 fi 715 if in_path bunzip2 && [ "$bz2i" != "" ]; then 716 ext="$ext $bz2i bz2" 717 i="${i:-$bz2i}" 718 fi 719 if in_path gunzip && [ "$gzi" != "" ]; then 720 ext="$ext $gzi gz" 721 i="${i:-$gzi}" 722 fi 723 progress_next $(($donepkgs + ${i#* })) 724 for m in $MIRRORS; do 725 pkgdest="$TARGET/$($DLDEST pkg "$s" "$c" "$ARCH" "$m" "$path")" 726 if get "$m/$path" "$pkgdest" $ext; then break; fi 727 done 728 if [ ! -f "$pkgdest" ]; then 729 error 1 COULDNTDL "Couldn't download %s" "$m/$path" 730 fi 731 donepkgs=$(($donepkgs + ${i#* })) 732 progress $donepkgs $totalpkgs DOWNPKGS "Downloading Packages files" 733 done 734 done 735} 736 737get_package_sizes () { 738 # mirror pkgdest debs.. 739 local m pkgdest 740 m="$1"; shift 741 pkgdest="$1"; shift 742 $PKGDETAILS PKGS "$m" "$pkgdest" "$@" | ( 743 newleft="" 744 totaldebs=0 745 countdebs=0 746 while read p details; do 747 if [ "$details" = "-" ]; then 748 newleft="$newleft $p" 749 else 750 size="${details##* }"; 751 totaldebs=$(($totaldebs + $size)) 752 countdebs=$(($countdebs + 1)) 753 fi 754 done 755 echo "$countdebs $totaldebs$newleft" 756 ) 757} 758 759# note, leftovers come back on fd5 !! 760download_debs () { 761 local m pkgdest debdest debcache 762 m="$1" 763 pkgdest="$2" 764 shift; shift 765 766 "$PKGDETAILS" PKGS "$m" "$pkgdest" "$@" | ( 767 leftover="" 768 while read p ver arc mdup fil checksum size; do 769 if [ "$ver" = "-" ]; then 770 leftover="$leftover $p" 771 else 772 progress_next $(($dloaddebs + $size)) 773 debdest="$($DLDEST deb "$p" "$ver" "$arc" "$m" "$fil")" 774 debcache="$(echo "$p"_"$ver"_"$arc".deb | sed 's/:/%3a/')" 775 if [ -z "$CACHE_DIR" ] && get "$m/$fil" "$TARGET/$debdest" "$checksum" "$size"; then 776 dloaddebs=$(($dloaddebs + $size)) 777 echo >>"$TARGET/debootstrap/deburis" "$p $ver $m/$fil" 778 echo >>"$TARGET/debootstrap/debpaths" "$p $debdest" 779 elif [ -d "$CACHE_DIR" ] && get "$m/$fil" "$CACHE_DIR/$debcache" "$checksum" "$size"; then 780 dloaddebs=$(($dloaddebs + $size)) 781 echo >>"$TARGET/debootstrap/deburis" "$p $ver $m/$fil" 782 echo >>"$TARGET/debootstrap/debpaths" "$p $debdest" 783 cp "$CACHE_DIR/$debcache" "$TARGET/$debdest" 784 else 785 warning COULDNTDL "Couldn't download package %s (ver %s arch %s) at %s" "$p" "$ver" "$arc" "$m/$fil" 786 leftover="$leftover $p" 787 fi 788 fi 789 done 790 echo >&5 ${leftover# } 791 ) 792} 793 794download_release () { 795 local m1 numdebs countdebs totaldebs leftoverdebs path pkgdest dloaddebs 796 m1="${MIRRORS%% *}" 797 798 numdebs="$#" 799 800 countdebs=0 801 progress "$countdebs" "$numdebs" SIZEDEBS "Finding package sizes" 802 803 totaldebs=0 804 leftoverdebs="$*" 805 806 # Fix possible duplicate package names, which would screw up counts: 807 leftoverdebs=$(printf "$leftoverdebs"|tr ' ' '\n'|sort -u|tr '\n' ' ') 808 numdebs=$(printf "$leftoverdebs"|wc -w) 809 810 for s in $SUITE $EXTRA_SUITES; do 811 for c in $COMPONENTS; do 812 if [ "$countdebs" -ge "$numdebs" ]; then break; fi 813 814 path="dists/$s/$c/binary-$ARCH/Packages" 815 pkgdest="$TARGET/$($DLDEST pkg "$s" "$c" "$ARCH" "$m1" "$path")" 816 if [ ! -e "$pkgdest" ]; then continue; fi 817 818 info CHECKINGSIZES "Checking component %s on %s..." "$c" "$m1" 819 820 leftoverdebs="$(get_package_sizes "$m1" "$pkgdest" $leftoverdebs)" 821 822 countdebs=$(($countdebs + ${leftoverdebs%% *})) 823 leftoverdebs=${leftoverdebs#* } 824 825 totaldebs=${leftoverdebs%% *} 826 leftoverdebs=${leftoverdebs#* } 827 828 progress "$countdebs" "$numdebs" SIZEDEBS "Finding package sizes" 829 done 830 done 831 832 if [ "$countdebs" -ne "$numdebs" ]; then 833 error 1 LEFTOVERDEBS "Couldn't find these debs: %s" "$leftoverdebs" 834 fi 835 836 dloaddebs=0 837 838 progress "$dloaddebs" "$totaldebs" DOWNDEBS "Downloading packages" 839 :>"$TARGET/debootstrap/debpaths" 840 841 pkgs_to_get="$*" 842 for s in $SUITE $EXTRA_SUITES; do 843 for c in $COMPONENTS; do 844 path="dists/$s/$c/binary-$ARCH/Packages" 845 for m in $MIRRORS; do 846 pkgdest="$TARGET/$($DLDEST pkg "$s" "$c" "$ARCH" "$m" "$path")" 847 if [ ! -e "$pkgdest" ]; then continue; fi 848 pkgs_to_get="$(download_debs "$m" "$pkgdest" $pkgs_to_get 5>&1 1>&6)" 849 if [ -z "$pkgs_to_get" ]; then break; fi 850 done 6>&1 851 if [ -z "$pkgs_to_get" ]; then break; fi 852 done 853 if [ -z "$pkgs_to_get" ]; then break; fi 854 done 855 progress "$dloaddebs" "$totaldebs" DOWNDEBS "Downloading packages" 856 if [ "$pkgs_to_get" != "" ]; then 857 error 1 COULDNTDLPKGS "Couldn't download packages: %s" "$pkgs_to_get" 858 fi 859} 860 861download_main_indices () { 862 local m1 comp path pkgdest 863 m1="${MIRRORS%% *}" 864 comp="${USE_COMPONENTS}" 865 progress 0 100 DOWNMAINPKGS "Downloading Packages file" 866 progress_next 100 867 868 if [ -z "$comp" ]; then comp=main; fi 869 COMPONENTS="$(echo $comp | tr '|' ' ')" 870 871 export COMPONENTS 872 for m in $MIRRORS; do 873 for s in $SUITE $EXTRA_SUITES; do 874 for c in $COMPONENTS; do 875 path="dists/$s/$c/binary-$ARCH/Packages" 876 pkgdest="$TARGET/$($DLDEST pkg "$s" "$c" "$ARCH" "$m" "$path")" 877 if in_path gunzip && get "$m/${path}.gz" "${pkgdest}.gz"; then 878 rm -f "$pkgdest" 879 gunzip "$pkgdest.gz" 880 elif get "$m/$path" "$pkgdest"; then 881 true 882 fi 883 done 884 done 885 done 886 progress 100 100 DOWNMAINPKGS "Downloading Packages file" 887} 888 889download_main () { 890 local m1 path pkgdest debdest 891 m1="${MIRRORS%% *}" 892 893 :>"$TARGET/debootstrap/debpaths" 894 for p in "$@"; do 895 for s in $SUITE $EXTRA_SUITES; do 896 for c in $COMPONENTS; do 897 local details="" 898 for m in $MIRRORS; do 899 path="dists/$s/$c/binary-$ARCH/Packages" 900 pkgdest="$TARGET/$($DLDEST pkg "$s" "$c" "$ARCH" "$m" "$path")" 901 if [ ! -e "$pkgdest" ]; then continue; fi 902 details="$($PKGDETAILS PKGS "$m" "$pkgdest" "$p")" 903 if [ "$details" = "$p -" ]; then 904 details="" 905 continue 906 fi 907 size="${details##* }"; details="${details% *}" 908 checksum="${details##* }"; details="${details% *}" 909 debdest="$($DLDEST deb $details)" 910 if get "$m/${details##* }" "$TARGET/$debdest" "$checksum" "$size"; then 911 echo >>"$TARGET/debootstrap/debpaths" "$p $debdest" 912 details="done" 913 break 914 fi 915 done 916 if [ "$details" != "" ]; then 917 break 918 fi 919 done 920 if [ "$details" != "" ]; then 921 break 922 fi 923 done 924 if [ "$details" != "done" ]; then 925 error 1 COULDNTDL "Couldn't download %s" "$p" 926 fi 927 done 928} 929 930###################################################### deb choosing support 931 932get_debs () { 933 local field m1 c path pkgdest 934 field="$1" 935 shift 936 for m1 in $MIRRORS; do 937 for s in $SUITE $EXTRA_SUITES; do 938 for c in $COMPONENTS; do 939 path="dists/$s/$c/binary-$ARCH/Packages" 940 pkgdest="$TARGET/$($DLDEST pkg "$s" "$c" "$ARCH" "$m1" "$path")" 941 echo "$("$PKGDETAILS" FIELD "$field" "$m1" "$pkgdest" "$@" | sed 's/ .*//')" 942 done 943 done 944 done 945} 946 947################################################################ extraction 948 949EXTRACTORS_SUPPORTED="dpkg-deb ar" 950EXTRACT_DEB_TAR_OPTIONS= 951 952# Native dpkg-deb based extractors 953extract_dpkg_deb_field () { 954 local pkg field 955 pkg="$1" 956 field="$2" 957 958 dpkg-deb -f "$pkg" "$field" 959} 960 961extract_dpkg_deb_data () { 962 local pkg="$1" 963 964 dpkg-deb --fsys-tarfile "$pkg" | tar $EXTRACT_DEB_TAR_OPTIONS -xf - || error 1 FILEEXIST "Tried to extract package, but file already exists. Exit..." 965} 966 967# Raw .deb extractors 968extract_ar_deb_field () { 969 local pkg field tarball 970 pkg="$1" 971 field="$2" 972 tarball=$(ar -t "$pkg" | /usr/local/bin/grep "^control\.tar") 973 974 case "$tarball" in 975 control.tar.gz) cat_cmd=zcat ;; 976 control.tar.xz) cat_cmd=xzcat ;; 977 control.tar) cat_cmd=cat ;; 978 *) error 1 UNKNOWNCONTROLCOMP "Unknown compression type for %s in %s" "$tarball" "$pkg" ;; 979 esac 980 981 if in_path $cat_cmd; then 982 ar -p "$pkg" "$tarball" | $cat_cmd | 983 tar -O -xf - control ./control 2>/dev/null | 984 /usr/local/bin/grep -i "^$field:" | sed -e 's/[^:]*: *//' | head -n 1 985 else 986 error 1 UNPACKCMDUNVL "Extracting %s requires the %s command, which is not available" "$pkg" "$cat_cmd" 987 fi 988} 989 990extract_ar_deb_data () { 991 local pkg tarball 992 pkg="$1" 993 tarball="$(ar -t "$pkg" | /usr/local/bin/grep "^data.tar")" 994 995 case "$tarball" in 996 data.tar.gz) cat_cmd=zcat ;; 997 data.tar.bz2) cat_cmd=bzcat ;; 998 data.tar.xz) cat_cmd=xzcat ;; 999 data.tar) cat_cmd=cat ;; 1000 *) error 1 UNKNOWNDATACOMP "Unknown compression type for %s in %s" "$tarball" "$pkg" ;; 1001 esac 1002 1003 if in_path "$cat_cmd"; then 1004 ar -p "$pkg" "$tarball" | "$cat_cmd" | tar $EXTRACT_DEB_TAR_OPTIONS -xf - 1005 else 1006 error 1 UNPACKCMDUNVL "Extracting %s requires the %s command, which is not available" "$pkg" "$cat_cmd" 1007 fi 1008} 1009 1010valid_extractor () { 1011 local extractor="$1" 1012 1013 for E in $EXTRACTORS_SUPPORTED; do 1014 if [ "$extractor" = "$E" ]; then 1015 return 0 1016 fi 1017 done 1018 1019 return 1 1020} 1021 1022choose_extractor () { 1023 local extractor 1024 1025 if [ -n "$EXTRACTOR_OVERRIDE" ]; then 1026 extractor="$EXTRACTOR_OVERRIDE" 1027 elif in_path dpkg-deb; then 1028 extractor="dpkg-deb" 1029 else 1030 extractor="ar" 1031 fi 1032 1033 info CHOSENEXTRACTOR "Chosen extractor for .deb packages: %s" "$extractor" 1034 case "$extractor" in 1035 dpkg-deb) 1036 extract_deb_field () { extract_dpkg_deb_field "$@"; } 1037 extract_deb_data () { extract_dpkg_deb_data "$@"; } 1038 ;; 1039 ar) 1040 extract_deb_field () { extract_ar_deb_field "$@"; } 1041 extract_deb_data () { extract_ar_deb_data "$@"; } 1042 ;; 1043 esac 1044} 1045 1046extract () { ( 1047 cd "$TARGET" || exit 1 1048 local p cat_cmd 1049 p=0 1050 for pkg in $(debfor "$@"); do 1051 p=$(($p + 1)) 1052 progress "$p" "$#" EXTRACTPKGS "Extracting packages" 1053 packagename="$(echo "$pkg" | sed 's,^.*/,,;s,_.*$,,')" 1054 info EXTRACTING "Extracting %s..." "$packagename" 1055 extract_deb_data "./$pkg" 1056 done 1057); } 1058 1059in_target_nofail () { 1060 if ! PATH=/sbin:/usr/sbin:/bin:/usr/bin eval "$CHROOT_CMD \"\$@\"" 2>/dev/null; then 1061 true 1062 fi 1063 return 0 1064} 1065 1066in_target_failmsg () { 1067 local code msg arg 1068 code="$1" 1069 msg="$2" 1070 arg="$3" 1071 shift; shift; shift 1072 if ! PATH=/sbin:/usr/sbin:/bin:/usr/bin eval "$CHROOT_CMD \"\$@\""; then 1073 warning "$code" "$msg" "$arg" 1074 # Try to point user at actual failing package. 1075 msg="See %s for details" 1076 if [ -e "$TARGET/debootstrap/debootstrap.log" ]; then 1077 arg="$TARGET/debootstrap/debootstrap.log" 1078 local pkg="$(/usr/local/bin/grep '^dpkg: error processing ' "$TARGET/debootstrap/debootstrap.log" | head -n 1 | sed 's/\(error processing \)\(package \|archive \)/\1/' | cut -d ' ' -f 4)" 1079 if [ -n "$pkg" ]; then 1080 msg="$msg (possibly the package $pkg is at fault)" 1081 fi 1082 else 1083 arg="the log" 1084 fi 1085 warning "$code" "$msg" "$arg" 1086 return 1 1087 fi 1088 return 0 1089} 1090 1091in_target () { 1092 in_target_failmsg IN_TARGET_FAIL "Failure trying to run: %s" "$CHROOT_CMD $*" "$@" 1093} 1094 1095###################################################### standard setup stuff 1096 1097conditional_cp () { 1098 if [ ! -e "$2/$1" ]; then 1099 if [ -L "$1" ] && [ -e "$1" ]; then 1100 cat "$1" >"$2/$1" 1101 elif [ -e "$1" ]; then 1102 cp "$1" "$2/$1" 1103 fi 1104 fi 1105} 1106 1107 1108setup_apt_sources () { 1109 mkdir -p "$TARGET/etc/apt" 1110 for m in "$@"; do 1111 for s in $SUITE $EXTRA_SUITES; do 1112 local cs c path pkgdest 1113 for c in ${COMPONENTS:-$USE_COMPONENTS}; do 1114 path="dists/$s/$c/binary-$ARCH/Packages" 1115 pkgdest="$TARGET/$($DLDEST pkg "$s" "$c" "$ARCH" "$m" "$path")" 1116 if [ -e "$pkgdest" ]; then cs="$cs $c"; fi 1117 done 1118 if [ "$cs" != "" ]; then echo "deb $m $s$cs"; fi 1119 done 1120 done > "$TARGET/etc/apt/sources.list" 1121} 1122 1123setup_etc () { 1124 mkdir -p "$TARGET/etc" 1125 1126 conditional_cp /etc/resolv.conf "$TARGET" 1127 conditional_cp /etc/hostname "$TARGET" 1128} 1129 1130UMOUNT_DIRS= 1131 1132umount_exit_function () { 1133 local realdir 1134 for dir in $UMOUNT_DIRS; do 1135 realdir="$(in_target_nofail readlink -f "$dir")" 1136 [ "$realdir" ] || continue 1137 ( cd / ; umount "$TARGET/${realdir#/}" ) || true 1138 done 1139} 1140 1141umount_on_exit () { 1142 if [ "$UMOUNT_DIRS" ]; then 1143 UMOUNT_DIRS="$1 $UMOUNT_DIRS" 1144 else 1145 UMOUNT_DIRS="$1" 1146 on_exit umount_exit_function 1147 fi 1148} 1149 1150clear_mtab () { 1151 if [ -f "$TARGET/etc/mtab" ] && [ ! -h "$TARGET/etc/mtab" ]; then 1152 rm -f "$TARGET/etc/mtab" 1153 fi 1154} 1155 1156setup_proc () { 1157 case "$HOST_OS" in 1158 *freebsd*) 1159 umount_on_exit /dev 1160 umount_on_exit /dev/fd 1161 umount_on_exit /proc 1162 umount "$TARGET/proc" 2>/dev/null || true 1163 if [ "$HOST_OS" = kfreebsd ]; then 1164 in_target mount -t linprocfs proc /proc 1165 else 1166 mount -t linprocfs proc "$TARGET/proc" 1167 fi 1168 ;; 1169 hurd*) 1170 # firmlink $TARGET/{dev,servers,proc} to the system ones. 1171 settrans -a "$TARGET/dev" /hurd/firmlink /dev 1172 settrans -a "$TARGET/servers" /hurd/firmlink /servers 1173 settrans -a "$TARGET/proc" /hurd/firmlink /proc 1174 ;; 1175 *) 1176 umount_on_exit /dev/pts 1177 umount_on_exit /dev/shm 1178 umount_on_exit /proc 1179 umount_on_exit /proc/bus/usb 1180 umount "$TARGET/proc" 2>/dev/null || true 1181 1182 # some container environment are used at second-stage, it already treats /proc and so on 1183 if [ -z "$(ls -A "$TARGET/proc")" ]; then 1184 # second-stage in docker, we cannot detect it is inside docker... just ignore warning 1185 in_target mount -t proc proc /proc || true 1186 umount_on_exit /proc 1187 fi 1188 if [ -n "$(ls -A "$TARGET/sys")" ] && \ 1189 /usr/local/bin/grep -qs '[[:space:]]sysfs' "$TARGET/proc/filesystems" || \ 1190 [ "$CONTAINER" = "docker" ]; then 1191 umount_on_exit /sys 1192 umount "$TARGET/sys" 2>/dev/null || true 1193 else 1194 # second-stage in docker, we cannot detect it is inside docker... just ignore warning 1195 in_target mount -t sysfs sysfs /sys || true 1196 umount_on_exit /sys 1197 fi 1198 on_exit clear_mtab 1199 ;; 1200 esac 1201 umount_on_exit /lib/init/rw 1202} 1203 1204setup_proc_symlink () { 1205 rm -rf "$TARGET/proc" 1206 ln -s /proc "$TARGET" 1207} 1208 1209# create the static device nodes 1210setup_devices () { 1211 if doing_variant fakechroot; then 1212 setup_devices_fakechroot 1213 return 0 1214 fi 1215 1216 case "$HOST_OS" in 1217 kfreebsd*) 1218 ;; 1219 freebsd) 1220 ;; 1221 hurd*) 1222 ;; 1223 *) 1224 if [ "$CONTAINER" = "lxc" ] || [ "$CONTAINER" = "lxc-libvirt" ]; then 1225 if ! setup_devices_simple; then 1226 setup_devices_bind 1227 fi 1228 return 0 1229 fi 1230 1231 setup_devices_simple 1232 ;; 1233 esac 1234} 1235 1236# enable the dynamic device nodes 1237setup_dynamic_devices () { 1238 if doing_variant fakechroot; then 1239 return 0 1240 fi 1241 1242 case "$HOST_OS" in 1243 kfreebsd*) 1244 in_target mount -t devfs devfs /dev ;; 1245 freebsd) 1246 mount -t devfs devfs "$TARGET/dev" 1247 mount -t fdescfs -o linrdlnk fdescfs "$TARGET/dev/fd" ;; 1248 hurd*) 1249 # Use the setup-translators of the hurd package 1250 in_target /usr/lib/hurd/setup-translators -k ;; 1251 esac 1252} 1253 1254# Create a device node if it does not exist. By default, the mode is 666. 1255mknod_if_needed () { 1256 local device type major minor mode 1257 device="$1" 1258 type="$2" 1259 major="$3" 1260 minor="$4" 1261 mode="${5:-666}" 1262 1263 if [ ! -e "$device" ]; then 1264 mknod -m "$mode" "$device" "$type" "$major" "$minor" 1265 fi 1266} 1267 1268 1269setup_devices_simple () { 1270 # The list of devices that can be created in a container comes from 1271 # src/core/cgroup.c in the systemd source tree. 1272 mknod_if_needed "$TARGET/dev/null" c 1 3 1273 mknod_if_needed "$TARGET/dev/zero" c 1 5 1274 mknod_if_needed "$TARGET/dev/full" c 1 7 1275 mknod_if_needed "$TARGET/dev/random" c 1 8 1276 mknod_if_needed "$TARGET/dev/urandom" c 1 9 1277 mknod_if_needed "$TARGET/dev/tty" c 5 0 1278 if [ ! "$CONTAINER" = "systemd-nspawn" ]; then 1279 mknod_if_needed "$TARGET/dev/console" c 5 1 1280 fi 1281 # To avoid pre-exist directory causes error, specify "-p" option 1282 mkdir -p "$TARGET/dev/pts/" "$TARGET/dev/shm/" 1283 # Inside a container, we might not be allowed to create /dev/ptmx. 1284 # If not, do the next best thing. 1285 if ! mknod_if_needed "$TARGET/dev/ptmx" c 5 2; then 1286 warning MKNOD "Could not create /dev/ptmx, falling back to symlink. This chroot will require /dev/pts mounted with ptmxmode=666" 1287 ln -sf pts/ptmx "$TARGET/dev/ptmx" 1288 fi 1289 ln -sf /proc/self/fd "$TARGET/dev/fd" 1290 ln -sf /proc/self/fd/0 "$TARGET/dev/stdin" 1291 ln -sf /proc/self/fd/1 "$TARGET/dev/stdout" 1292 ln -sf /proc/self/fd/2 "$TARGET/dev/stderr" 1293} 1294 1295setup_devices_fakechroot () { 1296 rm -rf "$TARGET/dev" 1297 ln -s /dev "$TARGET" 1298} 1299 1300setup_devices_bind () { 1301 mount -t tmpfs nodev "$TARGET/dev" 1302 umount_on_exit /dev 1303 for device in null zero full random urandom tty pts shm ptmx; do 1304 if [ -d "/dev/$device" ]; then 1305 mkdir "$TARGET/dev/$device" 1306 elif [ -c "/dev/$device" ]; then 1307 touch "$TARGET/dev/$device" 1308 else 1309 continue 1310 fi 1311 mount -o bind "/dev/$device" "$TARGET/dev/$device" 1312 umount_on_exit "/dev/$device" 1313 done 1314 ln -s /proc/self/fd "$TARGET/dev/fd" 1315 ln -s /proc/self/fd/0 "$TARGET/dev/stdin" 1316 ln -s /proc/self/fd/1 "$TARGET/dev/stdout" 1317 ln -s /proc/self/fd/2 "$TARGET/dev/stderr" 1318} 1319 1320setup_dselect_method () { 1321 case "$1" in 1322 apt) 1323 mkdir -p "$TARGET/var/lib/dpkg" 1324 echo "apt apt" > "$TARGET/var/lib/dpkg/cmethopt" 1325 chmod 644 "$TARGET/var/lib/dpkg/cmethopt" 1326 ;; 1327 *) 1328 error 1 UNKNOWNDSELECT "unknown dselect method" 1329 ;; 1330 esac 1331} 1332 1333# Find out where the runtime dynamic linker and the shared libraries 1334# can be installed on each architecture: native, multilib and multiarch. 1335# This data can be verified by checking the files in the debian/sysdeps/ 1336# directory of the glibc package. 1337# 1338# This function must be updated to support any new architecture which 1339# either installs the RTLD in a directory different from /lib or builds 1340# multilib library packages. 1341setup_merged_usr() { 1342 if doing_variant buildd && [ -z "$MERGED_USR" ]; then 1343 MERGED_USR="no" 1344 fi 1345 1346 if [ "$MERGED_USR" = "no" ]; then return 0; fi 1347 1348 local link_dir 1349 case $ARCH in 1350 hurd-*) return 0 ;; 1351 amd64) link_dir="lib32 lib64 libx32" ;; 1352 i386) link_dir="lib64 libx32" ;; 1353 mips|mipsel) 1354 link_dir="lib32 lib64" ;; 1355 mips64*|mipsn32*) 1356 link_dir="lib32 lib64 libo32" ;; 1357 powerpc) link_dir="lib64" ;; 1358 ppc64) link_dir="lib32 lib64" ;; 1359 ppc64el) link_dir="lib64" ;; 1360 s390x) link_dir="lib32" ;; 1361 sparc) link_dir="lib64" ;; 1362 sparc64) link_dir="lib32 lib64" ;; 1363 x32) link_dir="lib32 lib64 libx32" ;; 1364 esac 1365 link_dir="bin sbin lib $link_dir" 1366 1367 local dir 1368 for dir in $link_dir; do 1369 ln -s usr/"$dir" "$TARGET/$dir" 1370 mkdir -p "$TARGET/usr/$dir" 1371 done 1372} 1373 1374################################################################ pkgdetails 1375 1376# NOTE 1377# For the debootstrap udeb, pkgdetails is provided by the bootstrap-base 1378# udeb, so the pkgdetails API needs to be kept in sync with that. 1379 1380if in_path perl; then 1381 PKGDETAILS=pkgdetails_perl 1382 1383 # test if /usr/local/bin/grep supports --perl-regexp 1384 set +e 1385 echo x | /usr/local/bin/grep --perl-regexp . >/dev/null 2>&1 1386 if [ $? -eq 2 ]; then 1387 gropt=-E 1388 else 1389 gropt=--perl-regexp 1390 fi 1391 set -e 1392 1393 pkgdetails_field () { 1394 # uniq field mirror Packages values... 1395 perl -le ' 1396$unique = shift @ARGV; $field = lc(shift @ARGV); $mirror = shift @ARGV; 1397%fields = map { $_, 0 } @ARGV; 1398$prevpkg = ""; 1399$chksumfield = lc($ENV{DEBOOTSTRAP_CHECKSUM_FIELD}).":"; 1400while (<STDIN>) { 1401 if (/^([^:]*:)\s*(.*)$/) { 1402 $f = lc($1); $v = $2; 1403 if ($f eq "package:") { 1404 $last = 0; 1405 $pkg = $v; 1406 if ($pkg ne $prevpkg) { 1407 print $output if defined $output; 1408 if ($unique && defined $output_val) { 1409 delete $fields{$output_val}; 1410 $last = 1 unless keys %fields; 1411 } 1412 $prevpkg = $pkg; 1413 } 1414 undef $output; 1415 undef $output_val; 1416 last if $last; 1417 } 1418 $ver = $v if ($f eq "version:"); 1419 $arc = $v if ($f eq "architecture:"); 1420 $fil = $v if ($f eq "filename:"); 1421 $chk = $v if ($f eq $chksumfield); 1422 $siz = $v if ($f eq "size:"); 1423 $val = $v if ($f eq $field); 1424 } elsif (/^$/) { 1425 if (defined $val && defined $fields{$val}) { 1426 $output = sprintf "%s %s %s %s %s %s %s", 1427 $pkg, $ver, $arc, $mirror, $fil, $chk, $siz; 1428 $output_val = $val; 1429 } 1430 undef $val; 1431 } 1432} 1433print $output if defined $output; 1434delete $fields{$output_val} if $unique && defined $output_val; 1435for $v (keys %fields) { 1436 printf ("%s -\n", $v) if ($unique); 1437} 1438' "$@" 1439 } 1440 1441 pkgdetails_perl () { 1442 if [ "$1" = "WGET%" ]; then 1443 shift; 1444 perl -e ' 1445$v = 0; 1446$allow_percentage = 0; 1447while (read STDIN, $x, 1) { 1448 if ($x =~ m/\s/) { 1449 $allow_percentage = 1; 1450 } elsif ($allow_percentage and $x =~ m/\d/) { 1451 $v *= 10; 1452 $v += $x; 1453 } elsif ($allow_percentage and $x eq "%") { 1454 printf "P: %d %d%s\n", int($v / 100.0 * ($ARGV[1] - $ARGV[0]) + $ARGV[0]), $ARGV[2], ($#ARGV == 3 ? " $ARGV[3]" : ""); 1455 $v = 0; 1456 } else { 1457 $v = 0; 1458 $allow_percentage = 0; 1459 } 1460}' "$@" 1461 elif [ "$1" = "GETDEPS" ]; then 1462 local pkgdest="$2"; shift; shift 1463LC_ALL=C /usr/local/bin/grep "$gropt" '^$|^Package:|^Depends:|^Pre-Depends:' $pkgdest | perl -e ' 1464%seen = map { $_ => 1 } @ARGV; 1465while (<STDIN>) { 1466 if (/^Package: (.*)$/) { 1467 $pkg = $1; 1468 next; 1469 } elsif (/^$/) { 1470 $in = 0; 1471 next; 1472 } 1473 $in = 1 if $seen{$pkg}; 1474 if ($in and (/^Depends: (.*)$/ or /^Pre-Depends: (.*)$/)) { 1475 for $d (split /\s*,\s*/, $1) { 1476 $d =~ s/\s*[|].*$//; 1477 $d =~ s/\s*[(].*[)]\s*//; 1478 $d =~ s/:.*//; 1479 $depends{$d} = 1; 1480 } 1481 } 1482} 1483 foreach (sort keys %depends) { 1484 print "$_\n"; 1485 } 1486' "$@" 1487 elif [ "$1" = "PKGS" ]; then 1488 local m="$2" 1489 local p="$3" 1490 shift; shift; shift 1491 LC_ALL=C /usr/local/bin/grep "$gropt" '^$|^Architecture:|^Filename:|^MD5sum:|^Package:|^Priority:|^SHA256:|^Size:|^Version:|^Depends:|^Pre-Depends:' "$p" | pkgdetails_field 1 Package: "$m" "$@" 1492 elif [ "$1" = "FIELD" ]; then 1493 local f="$2" 1494 local m="$3" 1495 local p="$4" 1496 shift; shift; shift; shift 1497 LC_ALL=C /usr/local/bin/grep "$gropt" '^$|^Package:|^Priority:' "$p" | pkgdetails_field 0 "$f" "$m" "$@" 1498 elif [ "$1" = "STANZAS" ]; then 1499 local pkgdest="$2"; shift; shift 1500 perl -e ' 1501my $accum = ""; 1502%seen = map { $_ => 1 } @ARGV; 1503while (<STDIN>) { 1504 $accum .= $_; 1505 $in = 1 if (/^Package: (.*)$/ && $seen{$1}); 1506 if ($in and /^$/) { 1507 print $accum; 1508 if (substr($accum, -1) != "\n") { 1509 print "\n\n"; 1510 } elsif (substr($accum, -2, 1) != "\n") { 1511 print "\n"; 1512 } 1513 $in = 0; 1514 } 1515 $accum = "" if /^$/; 1516}' <"$pkgdest" "$@" 1517 fi 1518 } 1519elif [ -e "/usr/lib/debootstrap/pkgdetails" ]; then 1520 PKGDETAILS="/usr/lib/debootstrap/pkgdetails" 1521elif [ -e "$DEBOOTSTRAP_DIR/pkgdetails" ]; then 1522 PKGDETAILS="$DEBOOTSTRAP_DIR/pkgdetails" 1523else 1524 PKGDETAILS="" 1525fi 1526 1527##################################################### dependency resolution 1528 1529resolve_deps () { 1530 local m1="${MIRRORS%% *}" 1531 1532 local PKGS="$*" 1533 local ALLPKGS="$PKGS"; 1534 local ALLPKGS2=""; 1535 while [ "$PKGS" != "" ]; do 1536 local NEWPKGS="" 1537 for s in $SUITE $EXTRA_SUITES; do 1538 for c in ${COMPONENTS:-$(echo ${USE_COMPONENTS} | tr '|' ' ')}; do 1539 local path="dists/$s/$c/binary-$ARCH/Packages" 1540 local pkgdest="$TARGET/$($DLDEST pkg "$s" "$c" "$ARCH" "$m1" "$path")" 1541 NEWPKGS="$NEWPKGS $("$PKGDETAILS" GETDEPS "$pkgdest" $PKGS)" 1542 done 1543 done 1544 PKGS=$(echo "$PKGS $NEWPKGS" | tr ' ' '\n' | sort | uniq) 1545 local REALPKGS="" 1546 for s in $SUITE $EXTRA_SUITES; do 1547 for c in ${COMPONENTS:-$(echo ${USE_COMPONENTS} | tr '|' ' ')}; do 1548 local path="dists/$s/$c/binary-$ARCH/Packages" 1549 local pkgdest="$TARGET/$($DLDEST pkg "$s" "$c" "$ARCH" "$m1" "$path")" 1550 REALPKGS="$REALPKGS $("$PKGDETAILS" PKGS REAL "$pkgdest" $PKGS | sed -n 's/ .*REAL.*$//p')" 1551 done 1552 done 1553 PKGS="$REALPKGS" 1554 ALLPKGS2=$(echo "$PKGS $ALLPKGS" | tr ' ' '\n' | sort | uniq) 1555 PKGS=$(without "$ALLPKGS2" "$ALLPKGS") 1556 ALLPKGS="$ALLPKGS2" 1557 done 1558 echo "$ALLPKGS" 1559} 1560 1561setup_available () { 1562 local m1 c path pkgdest pkg 1563 m1="${MIRRORS%% *}" 1564 1565 for s in $SUITE $EXTRA_SUITES; do 1566 for c in ${COMPONENTS:-$(echo ${USE_COMPONENTS} | tr '|' ' ')}; do 1567 path="dists/$s/$c/binary-$ARCH/Packages" 1568 pkgdest="$TARGET/$($DLDEST pkg "$s" "$c" "$ARCH" "$m1" "$path")" 1569 # XXX: What if a package is in more than one component? 1570 # -- cjwatson 2009-07-29 1571 # XXX: ...or suite? 1572 # -- jrtc27 2019-06-11 1573 "$PKGDETAILS" STANZAS "$pkgdest" "$@" 1574 done 1575 done >"$TARGET/var/lib/dpkg/available" 1576 1577 for pkg; do 1578 echo "$pkg install" 1579 done | in_target dpkg --set-selections 1580} 1581 1582get_next_predep () { 1583 local stanza="$(in_target_nofail dpkg --predep-package)" 1584 [ "$stanza" ] || return 1 1585 echo "$stanza" | /usr/local/bin/grep '^Package:' | sed 's/^Package://; s/^ *//' 1586} 1587 1588################################################################### helpers 1589 1590# Return zero if it is possible to create devices and execute programs in 1591# this directory. (Both may be forbidden by mount options, e.g. nodev and 1592# noexec respectively.) 1593check_sane_mount () { 1594 mkdir -p "$1" 1595 1596 case "$HOST_OS" in 1597 *freebsd*|hurd*) 1598 ;; 1599 *) 1600 if ! doing_variant fakechroot; then 1601 case "$CONTAINER" in 1602 lxc|lxc-libvirt) 1603 ;; 1604 *) 1605 mknod "$1/test-dev-null" c 1 3 || return 1 1606 if ! echo test > "$1/test-dev-null"; then 1607 rm -f "$1/test-dev-null" 1608 return 1 1609 fi 1610 rm -f "$1/test-dev-null" 1611 ;; 1612 esac 1613 fi 1614 esac 1615 1616 SH="/bin/sh" 1617 [ -x "$SH" ] || SH="$(which sh)" 1618 1619 cat > "$1/test-exec" <<EOF 1620#! $SH 1621: 1622EOF 1623 chmod +x "$1/test-exec" 1624 if ! "$1/test-exec"; then 1625 rm -f "$1/test-exec" 1626 return 1 1627 fi 1628 rm -f "$1/test-exec" 1629 1630 return 0 1631} 1632 1633read_gpg_status () { 1634 local badsig unkkey validsig 1635 while read prefix keyword keyid rest; do 1636 [ "$prefix" = '[GNUPG:]' ] || continue 1637 case $keyword in 1638 BADSIG) badsig="$keyid" ;; 1639 NO_PUBKEY) unkkey="$keyid" ;; 1640 VALIDSIG) validsig="$keyid" ;; 1641 esac 1642 done 1643 if [ "$validsig" ]; then 1644 info VALIDRELSIG "Valid Release signature (key id %s)" "$validsig" 1645 elif [ "$badsig" ]; then 1646 error 1 BADRELSIG "Invalid Release signature (key id %s)" "$badsig" 1647 elif [ "$unkkey" ]; then 1648 error 1 UNKNOWNRELSIG "Release signed by unknown key (key id %s)\n The specified keyring $KEYRING may be incorrect or out of date.\n You can find the latest Debian release key at https://ftp-master.debian.org/keys.html" "$unkkey" 1649 else 1650 error 1 SIGCHECK "Error executing gpgv2 to check Release signature" 1651 fi 1652} 1653 1654without () { 1655 # usage: without "a b c" "a d" -> "b" "c" 1656 (echo "$1" | tr ' ' '\n' | sort | uniq; 1657 echo "$2" "$2" | tr ' ' '\n') | sort | uniq -u | tr '\n' ' ' 1658 echo 1659} 1660 1661# Formerly called 'repeat', but that's a reserved word in zsh. 1662repeatn () { 1663 local n="$1" 1664 shift 1665 while [ "$n" -gt 0 ]; do 1666 if "$@"; then 1667 break 1668 else 1669 n=$(( $n - 1 )) 1670 sleep 1 1671 fi 1672 done 1673 if [ "$n" -eq 0 ]; then return 1; fi 1674 return 0 1675} 1676 1677N_EXIT_THINGS=0 1678exit_function () { 1679 local n=0 1680 while [ "$n" -lt "$N_EXIT_THINGS" ]; do 1681 (eval $(eval echo \${EXIT_THING_$n}) 2>/dev/null || true) 1682 n=$(( $n + 1 )) 1683 done 1684 N_EXIT_THINGS=0 1685} 1686 1687trap "exit_function" 0 1688trap "exit 129" 1 1689trap "error 130 INTERRUPTED \"Interrupt caught ... exiting\"" 2 1690trap "exit 131" 3 1691trap "exit 143" 15 1692 1693on_exit () { 1694 eval "$(echo EXIT_THING_${N_EXIT_THINGS}=\"$1\")" 1695 N_EXIT_THINGS=$(( $N_EXIT_THINGS + 1 )) 1696} 1697 1698############################################################## fakechroot tools 1699 1700install_fakechroot_tools () { 1701 if [ "$VARIANT" = "fakechroot" ]; then 1702 export PATH=/usr/sbin:/sbin:$PATH 1703 fi 1704 1705 mv "$TARGET/sbin/ldconfig" "$TARGET/sbin/ldconfig.REAL" 1706 echo \ 1707"#!/bin/sh 1708echo 1709echo \"Warning: Fake ldconfig called, doing nothing\"" > "$TARGET/sbin/ldconfig" 1710 chmod 755 "$TARGET/sbin/ldconfig" 1711 1712 echo \ 1713"/sbin/ldconfig 1714/sbin/ldconfig.REAL 1715fakechroot" >> "$TARGET/var/lib/dpkg/diversions" 1716 1717 mv "$TARGET/usr/bin/ldd" "$TARGET/usr/bin/ldd.REAL" 1718 cat << 'END' > "$TARGET/usr/bin/ldd" 1719#!/usr/bin/perl 1720 1721# fakeldd 1722# 1723# Replacement for ldd with usage of objdump 1724# 1725# (c) 2003-2005 Piotr Roszatycki <dexter@debian.org>, BSD 1726 1727 1728my %libs = (); 1729 1730my $status = 0; 1731my $dynamic = 0; 1732my $biarch = 0; 1733 1734my $ldlinuxsodir = "/lib"; 1735my @ld_library_path = qw(/usr/lib /lib); 1736 1737 1738sub ldso($) { 1739 my ($lib) = @_; 1740 my @files = (); 1741 1742 if ($lib =~ /^\//) { 1743 $libs{$lib} = $lib; 1744 push @files, $lib; 1745 } else { 1746 foreach my $ld_path (@ld_library_path) { 1747 next unless -f "$ld_path/$lib"; 1748 my $badformat = 0; 1749 open OBJDUMP, "objdump -p $ld_path/$lib 2>/dev/null |"; 1750 while (my $line = <OBJDUMP>) { 1751 if ($line =~ /file format (\S*)$/) { 1752 $badformat = 1 unless $format eq $1; 1753 last; 1754 } 1755 } 1756 close OBJDUMP; 1757 next if $badformat; 1758 $libs{$lib} = "$ld_path/$lib"; 1759 push @files, "$ld_path/$lib"; 1760 } 1761 objdump(@files); 1762 } 1763} 1764 1765 1766sub objdump(@) { 1767 my (@files) = @_; 1768 my @libs = (); 1769 1770 foreach my $file (@files) { 1771 open OBJDUMP, "objdump -p $file 2>/dev/null |"; 1772 while (my $line = <OBJDUMP>) { 1773 $line =~ s/^\s+//; 1774 my @f = split (/\s+/, $line); 1775 if ($line =~ /file format (\S*)$/) { 1776 if (not $format) { 1777 $format = $1; 1778 if ($unamearch eq "x86_64" and $format eq "elf32-i386") { 1779 my $link = readlink "/lib/ld-linux.so.2"; 1780 if ($link =~ /^\/emul\/ia32-linux\//) { 1781 $ld_library_path[-2] = "/emul/ia32-linux/usr/lib"; 1782 $ld_library_path[-1] = "/emul/ia32-linux/lib"; 1783 } 1784 } elsif ($unamearch =~ /^(sparc|sparc64)$/ and $format eq "elf64-sparc") { 1785 $ldlinuxsodir = "/lib64"; 1786 $ld_library_path[-2] = "/usr/lib64"; 1787 $ld_library_path[-1] = "/lib64"; 1788 } 1789 } else { 1790 next unless $format eq $1; 1791 } 1792 } 1793 if (not $dynamic and $f[0] eq "Dynamic") { 1794 $dynamic = 1; 1795 } 1796 next unless $f[0] eq "NEEDED"; 1797 if ($f[1] =~ /^ld-linux(\.|-)/) { 1798 $f[1] = "$ldlinuxsodir/" . $f[1]; 1799 } 1800 if (not defined $libs{$f[1]}) { 1801 $libs{$f[1]} = undef; 1802 push @libs, $f[1]; 1803 } 1804 } 1805 close OBJDUMP; 1806 } 1807 1808 foreach my $lib (@libs) { 1809 ldso($lib); 1810 } 1811} 1812 1813 1814if ($#ARGV < 0) { 1815 print STDERR "fakeldd: missing file arguments\n"; 1816 exit 1; 1817} 1818 1819while ($ARGV[0] =~ /^-/) { 1820 my $arg = $ARGV[0]; 1821 shift @ARGV; 1822 last if $arg eq "--"; 1823} 1824 1825open LD_SO_CONF, "/etc/ld.so.conf"; 1826while ($line = <LD_SO_CONF>) { 1827 chomp $line; 1828 unshift @ld_library_path, $line; 1829} 1830close LD_SO_CONF; 1831 1832unshift @ld_library_path, split(/:/, $ENV{LD_LIBRARY_PATH}); 1833 1834$unamearch = "$(/bin/uname -m)"; 1835chomp $unamearch; 1836 1837foreach my $file (@ARGV) { 1838 my $address; 1839 %libs = (); 1840 $dynamic = 0; 1841 1842 if ($#ARGV > 0) { 1843 print "$file:\n"; 1844 } 1845 1846 if (not -f $file) { 1847 print STDERR "ldd: $file: No such file or directory\n"; 1848 $status = 1; 1849 next; 1850 } 1851 1852 objdump($file); 1853 1854 if ($dynamic == 0) { 1855 print "\tnot a dynamic executable\n"; 1856 $status = 1; 1857 } elsif (scalar %libs eq "0") { 1858 print "\tstatically linked\n"; 1859 } 1860 1861 if ($format =~ /^elf64-/) { 1862 $address = "0x0000000000000000"; 1863 } else { 1864 $address = "0x00000000"; 1865 } 1866 1867 foreach $lib (keys %libs) { 1868 if ($libs{$lib}) { 1869 printf "\t%s => %s (%s)\n", $lib, $libs{$lib}, $address; 1870 } else { 1871 printf "\t%s => not found\n", $lib; 1872 } 1873 } 1874} 1875 1876exit $status; 1877END 1878 chmod 755 "$TARGET/usr/bin/ldd" 1879 1880 echo \ 1881"/usr/bin/ldd 1882/usr/bin/ldd.REAL 1883fakechroot" >> "$TARGET/var/lib/dpkg/diversions" 1884 1885} 1886