OILS / benchmarks / testdata / functions View on Github | oilshell.org

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