summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Cady <d@cryptonomic.net>2021-01-21 10:44:39 -0500
committerAndrew Cady <d@cryptonomic.net>2021-01-21 10:44:39 -0500
commit01f7c340c36290a85ed13ddbc76ec497c83e6f9b (patch)
tree33be3a30c5b18674af538933626b50da82f85e29
parent7a5a13c17be7bf7a6e8315240ded71d90babd1f4 (diff)
remove selfstrap from this archive, which should be installed from fsmgr
-rwxr-xr-xsrc/selfstrap453
1 files changed, 0 insertions, 453 deletions
diff --git a/src/selfstrap b/src/selfstrap
deleted file mode 100755
index 6766c0c..0000000
--- a/src/selfstrap
+++ /dev/null
@@ -1,453 +0,0 @@
1#!/bin/bash
2debian_mirror=http://httpredir.debian.org/debian
3debian_security_mirror=http://security.debian.org
4EXTRA_PACKAGES='apt debian-archive-keyring locales'
5
6die() { printf 'Error: %s\n' "$*"; exit 1; }
7
8usage()
9{
10 echo "Usage: $0 -t <target directory> [options] [packages]" >&2
11 cat <<EOF
12 Options:
13 --target|-t (Mandatory) Target directory
14 --help|-h
15 --verbose|-v
16 --unpack Only unpack; do not configure
17 --chroot=<prog> Use prog for chroot command
18 --packages=<file> Text file contains names of packages to install
19 --real-apt Use 'apt-get install' to install packages
20 --skip-update Do not run 'apt-get update' at startup
21EOF
22 exit ${1:-1}
23}
24
25GETOPT=$(getopt -n "${0##*/}" -o t:hv --long help,target:,verbose,unpack,chroot:,packages:,real-apt,skip-update -- "$@") || exit
26eval set -- "$GETOPT"
27while [ $# -gt 0 ]; do
28 case "$1" in
29 -t|--target) TARGET=$2; shift ;;
30 -h|--help) usage 0 ;;
31 -v|--verbose) VERBOSE=y ;;
32 --skip-update) SKIP_UPDATE=y ;;
33 --unpack) UNPACK_ONLY=y ;;
34 --packages) x=$(cat < "$2") || die "could not read file '$2'"
35 EXTRA_PACKAGES="$EXTRA_PACKAGES $x"
36 shift ;;
37 --chroot) CHROOT_PROG=$2; shift ;;
38 --real-apt) REAL_APT_INSTALL=y ;;
39 --) shift; break ;;
40 *) usage 1 ;;
41 esac
42 shift
43done
44
45[ "$TARGET" ] || usage
46
47! [ "$REAL_APT_INSTALL" -a "$UNPACK_ONLY" ] || die "option --real-apt is incompatible with option --unpack"
48
49EXTRA_PACKAGES="$EXTRA_PACKAGES $*"
50
51am_root() { [ "$(id -u)" = 0 ]; }
52
53current_debian_codename()
54{
55 # lsb_release -cs
56 sed -ne 's/^VERSION=.* (\(.*\)).*/\1/p' /etc/os-release
57}
58
59sanity_checks()
60{
61 am_root || die 'you are not root'
62 TARGET=$(realpath "$TARGET") || die 'realpath failed'
63 [ "$TARGET" ] || die 'no $TARGET'
64 [ -d "$TARGET" ] || mkdir "$TARGET" || die 'could not mkdir($TARGET)'
65}
66
67generate_apt_config()
68{
69 APT_CONFIG=$(mktemp) || exit
70 chmod 644 "$APT_CONFIG"
71 cat > "$APT_CONFIG" <<EOF
72Dir "${TARGET}";
73EOF
74 export APT_CONFIG
75}
76
77apt_()
78{
79 local apt_cmd="$1"
80 shift
81
82 [ "$TARGET" ] || die 'no $TARGET'
83 [ "$APT_CONFIG" ] || die 'no $APT_CONFIG'
84
85 if [ "$VERBOSE" ]; then
86 printf "+ apt-${apt_cmd} %s\n" "$*" >&2
87 fi
88
89 set -- "$@" -o Apt::Install-Recommends=false
90 set -- "$@" -o Apt::Architecture="$target_arch"
91 set -- "$@" -o Apt::Default-Release="$target_release"
92
93 # Set default paths to within the created system.
94 set -- "$@" -o Dir="$TARGET"
95 set -- "$@" -o Dir::State::Status="$TARGET"/var/lib/dpkg/status
96
97 # We must also set dpkg to use the created system.
98 # Dpkg::options requires undocumented apt CLI magic.
99 if [ "$DEBUG_DPKG" ]; then
100 [ "$DEBUG_DPKG" -gt 0 ] 2>/dev/null || DEBUG_DPKG=10013
101 set -- "$@" -o DPkg::options::arg0=--debug="${DEBUG_DPKG}"
102 fi
103 # This is the important one:
104 set -- "$@" -o DPkg::options::arg1=--root="$TARGET"
105 set -- "$@" -o DPkg::options::arg2=--force-unsafe-io
106
107 # Use the calling system for these. This is an optimization.
108 #set -- "$@" -o Dir::Etc::sourcelist=/etc/apt/sources.list
109 #set -- "$@" -o Dir::Etc::sourceparts=/etc/apt/sources.list.d
110 set -- "$@" -o Dir::Etc::Trusted=/etc/apt/trusted.gpg
111 set -- "$@" -o Dir::Etc::TrustedParts=/etc/apt/trusted.gpg.d
112 set -- "$@" -o Dir::State::lists=/var/lib/apt/lists
113 set -- "$@" -o Dir::Cache::archives=/var/cache/apt/archives
114
115 # Avoid deleting lists on the calling system.
116 set -- "$@" -o APT::Get::List-Cleanup=false
117
118 apt-"${apt_cmd}" "$@"
119}
120apt_get() { apt_ get "$@"; }
121apt_cache() { apt_ cache "$@"; }
122
123idem() { if [ ! -e "${!#}" ]; then "$@"; fi; }
124idem_mknod() { if [ ! -e "$3" ]; then mknod "$@"; fi; }
125
126# This function is copied (with modifications) from debootstrap.
127install_devices()
128{
129 [ "$TARGET" -a -d "$TARGET" ] || die 'no $TARGET'
130 idem mkdir "$TARGET"/dev
131 # The list of devices that can be created in a container comes from
132 # src/core/cgroup.c in the systemd source tree.
133 idem_mknod -m 666 "$TARGET"/dev/null c 1 3
134 idem_mknod -m 666 "$TARGET"/dev/zero c 1 5
135 idem_mknod -m 666 "$TARGET"/dev/full c 1 7
136 idem_mknod -m 666 "$TARGET"/dev/random c 1 8
137 idem_mknod -m 666 "$TARGET"/dev/urandom c 1 9
138 idem_mknod -m 666 "$TARGET"/dev/tty c 5 0
139 idem mkdir "$TARGET"/dev/pts/
140 idem mkdir "$TARGET"/dev/shm/
141 # Inside a container, we might not be allowed to create /dev/ptmx.
142 # If not, do the next best thing.
143 if ! idem_mknod -m 666 "$TARGET"/dev/ptmx c 5 2; then
144 idem ln -s pts/ptmx "$TARGET"/dev/ptmx
145 fi
146 idem ln -s /proc/self/fd "$TARGET"/dev/fd
147 idem ln -s /proc/self/fd/0 "$TARGET"/dev/stdin
148 idem ln -s /proc/self/fd/1 "$TARGET"/dev/stdout
149 idem ln -s /proc/self/fd/2 "$TARGET"/dev/stderr
150}
151
152mount_virtfs()
153{
154 [ "$TARGET" ] || die 'no $TARGET'
155 [ -d "$TARGET"/proc ] || mkdir "$TARGET"/proc
156 [ -d "$TARGET"/sys ] || mkdir "$TARGET"/sys
157 mount -t proc proc "$TARGET"/proc
158 mount -t sysfs sysfs "$TARGET"/sys
159}
160
161umount_virtfs()
162{
163 [ "$TARGET" ] || die 'no $TARGET'
164 umount "$TARGET"/proc || fail=y
165 umount "$TARGET"/sys || fail=y
166 [ ! "$fail" ]
167}
168
169write_lines_once()
170{
171 local output="$1"
172 shift
173 [ -e "$output" ] || printf '%s\n' "$@" > "$output"
174}
175
176populate_rootfs()
177{
178 [ "$TARGET" ] || die 'no $TARGET'
179 set -B
180 mkdir -p \
181 "$TARGET"/etc/apt/{preferences.d,apt.conf.d,trusted.gpg.d,sources.list.d} \
182 "$TARGET"/var/{lib/{apt/lists/partial,dpkg/{info,parts,triggers,alternatives,updates}},cache/apt} \
183 "$TARGET"/var/log/apt
184
185 touch "$TARGET"/var/lib/dpkg/status
186
187 [ -d "$TARGET"/usr/bin ] || mkdir -p "$TARGET"/usr/bin
188 [ -e "$TARGET/usr/bin/awk" -o -L "$TARGET/usr/bin/awk" ] || ln -s mawk "$TARGET/usr/bin/awk"
189
190 write_lines_once "$TARGET"/var/lib/dpkg/arch "$target_arch"
191 write_sources_list
192 install_devices
193}
194
195write_sources_list()
196{
197 local dest="$TARGET"/etc/apt/sources.list
198 [ -e "$dest" ] && return
199 printf '%s\n' \
200 "deb ${debian_mirror} ${target_release} main contrib non-free" \
201 "deb ${debian_mirror} ${target_release}-backports main contrib non-free" \
202 "deb ${debian_security_mirror} ${target_release}/updates main contrib non-free" |
203 column -t > "$dest"
204}
205
206parse_apt_simul_line()
207{
208 set -- $*
209 action=$1
210 package=$2
211 # Third word might either be "(version" or "[version]" depending on which
212 # apt is producing the output. Newer apt versions apparently add an extra
213 # "[version]" parameter, making "(version" the fourth argument.
214 version=${3#\(}
215 version=${version#\[}
216 version=${version%]}
217 shift 3
218
219 # Find the last word, which is inside (a group of words that are inside
220 # parentheses).
221 while [ "$1" ]; do
222 case "$1" in
223 *\))
224 arch=${1%\)}
225 arch=${arch#\[}
226 arch=${arch%\]}
227 return
228 ;;
229 *) shift ;;
230 esac
231 done
232 return 1
233}
234
235dpkg_unpack()
236{
237 [ "$TARGET" -a -d "$TARGET" ] || die 'no $TARGET'
238 local deb="$1" multiarch="$2" SET_STATUS="$3" command PKG
239 PKG=${deb##*/}
240 PKG=${PKG%%_*}
241 PKG=$PKG$multiarch
242
243 extract_tmp_ci "$deb"
244 install_metadata_from_tmp_ci # uses TARGET PKG SET_STATUS
245 remove_tmp_ci
246
247 dpkg --fsys-tarfile "$deb" |
248 (cd "$TARGET" && tar -xv) |
249 sed 's?^\.??; s?^/$?/.?; s?/$??' > "$TARGET/var/lib/dpkg/info/$PKG.list"
250}
251
252install_metadata_from_tmp_ci() # uses TARGET PKG SET_STATUS
253{
254 (cd "$TARGET"/var/lib/dpkg/tmp.ci || die "cannot cd to /var/lib/dpkg/tmp.ci"
255# PKG=$(sed -n 's/^Package: *//p' control)
256 for f in *; do
257 [ "$f" = postinst ] && SET_STATUS=${SET_STATUS:+installed} || true
258 [ "$f" = control ] || mv "$f" "$TARGET"/var/lib/dpkg/info/"$PKG"."$f"
259 done
260 if [ "$SET_STATUS" -a -e control ]; then
261 (sed "/^Package:/a Status: install ok $SET_STATUS"; echo) < control >> "$TARGET"/var/lib/dpkg/status
262 fi)
263}
264
265verbosely()
266{
267 if [ "$VERBOSE" ]; then
268 (set -x; "$@")
269 else
270 "$@"
271 fi
272}
273
274remove_tmp_ci()
275{
276 [ ! -e "$TARGET"/var/lib/dpkg/tmp.ci ] || rm -r "$TARGET"/var/lib/dpkg/tmp.ci
277}
278
279# /var/lib/dpkg/tmp.ci/control is read by debconf to determine the owner package
280# See `grep -A3 control /usr/share/debconf/frontend`
281extract_tmp_ci()
282{
283 local deb="$1"
284 remove_tmp_ci
285 mkdir "$TARGET"/var/lib/dpkg/tmp.ci
286 dpkg --ctrl-tarfile "$deb" | tar -C "$TARGET"/var/lib/dpkg/tmp.ci -x
287}
288
289dpkg_configure_from_apt_actions()
290{
291 while read line; do
292 parse_apt_simul_line "$line" || die "parse_apt_simul_line: unexpected output from apt-get: $line"
293 export LC_ALL=C
294 export DEBIAN_FRONTEND=noninteractive
295 export DPKG_MAINTSCRIPT_PACKAGE="$package" DPKG_MAINTSCRIPT_ARCH="$arch"
296 is_multiarch_same "$package" && multiarch=":$arch" || multiarch=
297 case "$action" in
298 Inst)
299 export DPKG_MAINTSCRIPT_NAME=preinst
300 preinst=/var/lib/dpkg/info/${package}${multiarch}.preinst
301 if [ -x "$TARGET"/"$preinst" ]; then
302 extract_tmp_ci "$deb"
303 verbosely ${CHROOT_PROG:-chroot} "$TARGET" "$preinst" install
304 remove_tmp_ci
305 fi
306 ;;
307 Conf)
308 export DPKG_MAINTSCRIPT_NAME=postinst
309 postinst=/var/lib/dpkg/info/${package}${multiarch}.postinst
310 if [ -x "$TARGET"/"$postinst" ]; then
311 extract_tmp_ci "$deb"
312 verbosely ${CHROOT_PROG:-chroot} "$TARGET" "$postinst" configure
313 remove_tmp_ci
314 fi
315 ;;
316 Remv) ;;
317 *) die "dpkg_configure_from_apt_actions: unknown apt simul action: $action" ;;
318 esac
319 done
320}
321
322apt_extract()
323{
324 apt_get -d -yqq install "$@"
325 actions=$(mktemp) || die 'mktemp failed'
326 apt_get -s -yqq install "$@" > "$actions" || die 'apt-get failed'
327
328 dpkg_unpack_from_apt_actions < "$actions" || die 'dpkg unpack (using internal dpkg) failed'
329
330 if [ ! "$UNPACK_ONLY" ]; then
331 install_etc_passwd
332 dpkg_configure_from_apt_actions < "$actions" || die 'dpkg configure (using internal dpkg) failed'
333 fi
334
335 rm "$actions"
336}
337
338dpkg_unpack_from_apt_actions()
339{
340 while read line; do
341
342 parse_apt_simul_line "$line" || die "parse_apt_simul_line: unexpected output from apt-get: $line"
343
344 deb=/var/cache/apt/archives/${package}_${version//:/%3a}_${arch}.deb
345 [ -f "$deb" ] || {
346 echo "line=$line" >&2
347 printf '%s\n' "$action" "$package" "$version" "$arch" >&2
348 die "deb not found: $deb"
349 }
350 case "$action" in
351 Inst)
352 printf 'Unpacking %s\n' "${deb##*/}" >&2
353 if [ "$REAL_APT_INSTALL" ]; then
354 dpkg --extract "$deb" "$TARGET" || die 'dpkg'
355 else
356 is_multiarch_same "$package" && multiarch=":$arch" || multiarch=
357 [ "$UNPACK_ONLY" ] && set_status=unpacked || set_status=installed
358 dpkg_unpack "$deb" "$multiarch" "$set_status" || die "dpkg_unpack"
359 fi
360 ;;
361 Conf) ;;
362 Remv) ;;
363 *) die "dpkg_unpack_from_apt_actions: unknown apt simul action: $action" ;;
364 esac
365 done
366}
367
368install_etc_passwd()
369{
370 [ -e "$TARGET"/etc/passwd ] || cp "$TARGET"/usr/share/base-passwd/passwd.master "$TARGET"/etc/passwd
371 [ -e "$TARGET"/etc/group ] || cp "$TARGET"/usr/share/base-passwd/group.master "$TARGET"/etc/group
372}
373
374required_packages()
375{
376 apt_cache dumpavail |
377 perl -00 -ne '/^Priority: required/m || next; /^Package: (.*)$/m && print "$1\n"' |
378 sort -u
379}
380
381declare -A is_multiarch_same
382multicheck()
383{
384 local m
385 if [ ! "$multichecked" ]; then
386 for m in $(multiarch_same_packages); do
387 is_multiarch_same[$m]=y
388 done
389 fi
390 multichecked=y
391}
392
393multiarch_same_packages()
394{
395 apt_cache dumpavail |
396 perl -00 -ne '/^Multi-Arch: same/mi || next; /^Package: (.*)$/m && print "$1\n"' |
397 sort -u
398}
399
400is_multiarch_same()
401{
402 multicheck
403 [ "${is_multiarch_same[$1]}" ]
404}
405
406apt_update_stamp=~/.selfstrap/apt-update-stamp
407
408apt_get_update()
409{
410 if [ ! -e "$apt_update_stamp" ] || [ $(( $(date +%s) - $(stat -c %Y "$apt_update_stamp") )) -gt $(( 60 * 60 * 24 )) ]
411 then
412 apt_get update
413 mkdir -p ~/.selfstrap
414 touch "$apt_update_stamp"
415 fi
416}
417
418set -e
419
420target_arch=$(dpkg-architecture -q DEB_HOST_ARCH) || die 'dpkg-architecture failed'
421target_release=$(current_debian_codename) && [ "$target_release" ] || die 'could not determine Debian release name'
422
423# Set things up so apt-get update works.
424sanity_checks
425generate_apt_config
426populate_rootfs
427[ "$SKIP_UPDATE" ] || apt_get_update
428
429required_packages=$(required_packages) && [ "$required_packages" ] || die 'failed to determine list of required packages'
430
431export LC_ALL=C
432export DEBIAN_FRONTEND=noninteractive
433
434if [ "$REAL_APT_INSTALL" ]; then
435 # Some files need to be present before 'apt-get install' can install anything.
436 # In particular:
437 #
438 # 1. binaries used by dpkg 'inst' scripts.
439 # 2. /etc/passwd and /etc/group so that 'chown' works
440
441 # Unpack required packages. Handles (1)
442 # Note: populate_rootfs() already created a necessary symlink /usr/bin/awk -> /usr/bin/mawk
443 apt_extract $required_packages
444
445 # This handles (2).
446 # An alternative (used by debootstrap) is to configure base-passwd
447 install_etc_passwd
448
449 apt_get install -y $required_packages $EXTRA_PACKAGES
450else
451 apt_extract $required_packages
452 apt_extract $EXTRA_PACKAGES
453fi