summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Cady <d@jerkface.net>2017-08-30 23:11:02 -0400
committerAndrew Cady <d@jerkface.net>2017-08-30 23:14:56 -0400
commitd8301b27dcda3bb9a66f145e3181c6ea781567fe (patch)
tree30830bb581f1bd28c6ba4875228bc6d9e6c090a4
parenta39c3c4520ecea31cf85d31741275657268a8cc8 (diff)
selfstrap: internally manage /var/lib/dpkg/status
-rwxr-xr-xmultistrap/selfstrap116
1 files changed, 91 insertions, 25 deletions
diff --git a/multistrap/selfstrap b/multistrap/selfstrap
index 88dc07e..c693a4e 100755
--- a/multistrap/selfstrap
+++ b/multistrap/selfstrap
@@ -43,6 +43,8 @@ apt_get()
43 [ "$rootfs" ] || die 'no $rootfs' 43 [ "$rootfs" ] || die 'no $rootfs'
44 [ "$APT_CONFIG" ] || die 'no $APT_CONFIG' 44 [ "$APT_CONFIG" ] || die 'no $APT_CONFIG'
45 45
46 visible_args="$*"
47
46 set -- -o Apt::Install-Recommends=false "$@" 48 set -- -o Apt::Install-Recommends=false "$@"
47 49
48 # Set various paths to within the created system. 50 # Set various paths to within the created system.
@@ -59,7 +61,7 @@ apt_get()
59 # We must also set dpkg to use the created system. 61 # We must also set dpkg to use the created system.
60 # Dpkg::options requires undocumented apt CLI magic. 62 # Dpkg::options requires undocumented apt CLI magic.
61 if [ "$DEBUG_DPKG" ]; then 63 if [ "$DEBUG_DPKG" ]; then
62 [ "$DEBUG_DPKG" -gt 0 ] 2>/dev/null || DEBUG_DPKG=013 64 [ "$DEBUG_DPKG" -gt 0 ] 2>/dev/null || DEBUG_DPKG=10013
63 set -- -o DPkg::options::arg0=--debug="${DEBUG_DPKG}" "$@" 65 set -- -o DPkg::options::arg0=--debug="${DEBUG_DPKG}" "$@"
64 fi 66 fi
65 # This is the important one: 67 # This is the important one:
@@ -75,9 +77,60 @@ apt_get()
75 # Avoid deleting lists on the calling system. 77 # Avoid deleting lists on the calling system.
76 set -- -o APT::Get::List-Cleanup=false "$@" 78 set -- -o APT::Get::List-Cleanup=false "$@"
77 79
80 [ "$VERBOSE" ] && printf '+ apt-get %s\n' "$visible_args" >&2 || true
81
78 apt-get "$@" 82 apt-get "$@"
79} 83}
80 84
85idem() { if [ ! -e "${!#}" ]; then "$@"; fi; }
86idem_mknod() { if [ ! -e "$3" ]; then mknod "$@"; fi; }
87
88# This function is copied (with modifications) from debootstrap.
89install_devices()
90{
91 local TARGET="$rootfs"
92 [ "$TARGET" -a -d "$TARGET" ] || die 'no $TARGET'
93 idem mkdir "$TARGET"/dev
94 # The list of devices that can be created in a container comes from
95 # src/core/cgroup.c in the systemd source tree.
96 idem_mknod -m 666 "$TARGET"/dev/null c 1 3
97 idem_mknod -m 666 "$TARGET"/dev/zero c 1 5
98 idem_mknod -m 666 "$TARGET"/dev/full c 1 7
99 idem_mknod -m 666 "$TARGET"/dev/random c 1 8
100 idem_mknod -m 666 "$TARGET"/dev/urandom c 1 9
101 idem_mknod -m 666 "$TARGET"/dev/tty c 5 0
102 idem mkdir "$TARGET"/dev/pts/
103 idem mkdir "$TARGET"/dev/shm/
104 # Inside a container, we might not be allowed to create /dev/ptmx.
105 # If not, do the next best thing.
106 if ! idem_mknod -m 666 "$TARGET"/dev/ptmx c 5 2; then
107 idem ln -s pts/ptmx "$TARGET"/dev/ptmx
108 fi
109 idem ln -s /proc/self/fd "$TARGET"/dev/fd
110 idem ln -s /proc/self/fd/0 "$TARGET"/dev/stdin
111 idem ln -s /proc/self/fd/1 "$TARGET"/dev/stdout
112 idem ln -s /proc/self/fd/2 "$TARGET"/dev/stderr
113}
114
115mount_virtfs()
116{
117 local TARGET="$1"
118 [ "$TARGET" ] || die 'no $TARGET'
119 [ -d "$TARGET"/proc ] || mkdir "$TARGET"/proc
120 [ -d "$TARGET"/sys ] || mkdir "$TARGET"/sys
121 mount -t proc proc "$TARGET"/proc
122 mount -t sysfs sysfs "$TARGET"/sys
123}
124
125umount_virtfs()
126{
127 local TARGET="$1" fail=
128 [ "$TARGET" ] || die 'no $TARGET'
129 umount "$TARGET"/proc || fail=y
130 umount "$TARGET"/sys || fail=y
131 [ ! "$fail" ]
132}
133
81write_lines_once() 134write_lines_once()
82{ 135{
83 local output="$1" 136 local output="$1"
@@ -100,6 +153,7 @@ populate_rootfs()
100 write_lines_once "$rootfs"/etc/apt/sources.list \ 153 write_lines_once "$rootfs"/etc/apt/sources.list \
101 "deb $debian_mirror $release main contrib non-free" \ 154 "deb $debian_mirror $release main contrib non-free" \
102 "deb http://security.debian.org $release/updates main contrib non-free" 155 "deb http://security.debian.org $release/updates main contrib non-free"
156 install_devices
103} 157}
104 158
105parse_apt_noact_line() 159parse_apt_noact_line()
@@ -131,23 +185,33 @@ dpkg_extract_with_info()
131 PKG=${PKG%%_*} 185 PKG=${PKG%%_*}
132 PKG=$PKG$multiarch 186 PKG=$PKG$multiarch
133 187
134 command=' 188 command=$(cat <<'EOF'
135[ "$TAR_FILENAME" = ./control ] && exit 189if [ "$TAR_FILENAME" = ./control ]; then
136f=$TARGET/var/lib/dpkg/info/$PKG.${TAR_FILENAME#./} 190 (sed "/^Package:/a Status: install ok installed"; echo) >> "$TARGET"/var/lib/dpkg/status
137cat > "$f" 191else
138chmod $TAR_MODE "$f" 192 f=$TARGET/var/lib/dpkg/info/$PKG.${TAR_FILENAME#./}
139' 193 cat > "$f"
194 chmod $TAR_MODE "$f"
195fi
196EOF
197)
140 (export PKG TARGET; dpkg --ctrl-tarfile "$deb" | tar -x --to-command "$command") 198 (export PKG TARGET; dpkg --ctrl-tarfile "$deb" | tar -x --to-command "$command")
141 dpkg --fsys-tarfile "$deb" | 199 dpkg --fsys-tarfile "$deb" |
142 (cd "$TARGET" && tar -xv) | 200 (cd "$TARGET" && tar -xv) |
143 sed 's?^\.??; s?^/$?/.?; s?/$??' > "$TARGET/var/lib/dpkg/info/$PKG.list" 201 sed 's?^\.??; s?^/$?/.?; s?/$??' > "$TARGET/var/lib/dpkg/info/$PKG.list"
144
145} 202}
146 203
147apt_run_inst() 204apt_run_inst()
148{ 205{
149 apt_get -s -yqq install "$@" | while read line; do 206 apt_get -s -yqq install "$@" | dpkg_inst_from_apt
207}
208
209dpkg_inst_from_apt()
210{
211 while read line; do
150 parse_apt_noact_line "$line" || die "unexpected output from apt-get: $line" 212 parse_apt_noact_line "$line" || die "unexpected output from apt-get: $line"
213 export LC_ALL=C
214 export DEBIAN_FRONTEND=noninteractive
151 export DPKG_MAINTSCRIPT_PACKAGE="$package" DPKG_MAINTSCRIPT_ARCH="$arch" 215 export DPKG_MAINTSCRIPT_PACKAGE="$package" DPKG_MAINTSCRIPT_ARCH="$arch"
152 is_multiarch_same "$package" && multiarch=":$arch" || multiarch= 216 is_multiarch_same "$package" && multiarch=":$arch" || multiarch=
153 case "$action" in 217 case "$action" in
@@ -174,7 +238,9 @@ apt_run_inst()
174apt_extract() 238apt_extract()
175{ 239{
176 apt_get -d -yqq install "$@" 240 apt_get -d -yqq install "$@"
177 apt_get -s -yqq install "$@" | while read line; do 241 actions=$(mktemp) || die 'mktemp failed'
242 apt_get -s -yqq install "$@" | tee "$actions" | while read line; do
243
178 parse_apt_noact_line "$line" || die "unexpected output from apt-get: $line" 244 parse_apt_noact_line "$line" || die "unexpected output from apt-get: $line"
179 245
180 deb=/var/cache/apt/archives/${package}_${version//:/%3a}_${arch}.deb 246 deb=/var/cache/apt/archives/${package}_${version//:/%3a}_${arch}.deb
@@ -194,18 +260,22 @@ apt_extract()
194 dpkg-deb --extract "$deb" "$rootfs" 260 dpkg-deb --extract "$deb" "$rootfs"
195 fi 261 fi
196 ;; 262 ;;
197 Conf) 263 Conf) ;;
198 ;;
199 Remv) ;; 264 Remv) ;;
200 *) die "impossible" ;; 265 *) die "impossible" ;;
201 esac 266 esac
202 done 267 done
268 if [ "$EXTRACT_DPKG_INFO" ]; then
269 install_etc_passwd
270 dpkg_inst_from_apt < "$actions"
271 fi
272 rm "$actions"
203} 273}
204 274
205install_etc_passwd() 275install_etc_passwd()
206{ 276{
207 [ -e "$rootfs"/etc/passwd ] || cp "$rootfs"//usr/share/base-passwd/passwd.master "$rootfs"/etc/passwd 277 [ -e "$rootfs"/etc/passwd ] || cp "$rootfs"/usr/share/base-passwd/passwd.master "$rootfs"/etc/passwd
208 [ -e "$rootfs"/etc/group ] || cp "$rootfs"//usr/share/base-passwd/group.master "$rootfs"/etc/group 278 [ -e "$rootfs"/etc/group ] || cp "$rootfs"/usr/share/base-passwd/group.master "$rootfs"/etc/group
209} 279}
210 280
211main_packages_file() 281main_packages_file()
@@ -273,8 +343,6 @@ packages=$(required_packages) && [ "$packages" ] || die 'failed to determine lis
273extra_packages='apt debian-archive-keyring locales' 343extra_packages='apt debian-archive-keyring locales'
274 344
275 345
276# Extract files from downloaded packages.
277#
278# Some files need to be present before 'apt-get install' can install anything. 346# Some files need to be present before 'apt-get install' can install anything.
279# In particular: 347# In particular:
280# 348#
@@ -282,20 +350,18 @@ extra_packages='apt debian-archive-keyring locales'
282# 2. /etc/passwd and /etc/group so that 'chown' works 350# 2. /etc/passwd and /etc/group so that 'chown' works
283 351
284# Rather than fuss about (1), extract everything from all packages. 352# Rather than fuss about (1), extract everything from all packages.
285apt_extract $packages
286# This handles (2).
287install_etc_passwd
288 353
354# Note: apt_extract() runs preinst and postinst scripts itself when
355# $EXTRACT_DPKG_INFO is true.
356apt_extract $packages
289 357
290# Finally we are ready to run apt-get install.
291export LC_ALL=C
292export DEBIAN_FRONTEND=noninteractive
293if [ "$SKIP_INSTALL" ]; then 358if [ "$SKIP_INSTALL" ]; then
294 apt_extract $extra_packages 359 apt_extract $extra_packages
295 if [ "$RUN_INST_SCRIPTS" ]; then
296 apt_run_inst $packages $extra_packages
297 fi
298else 360else
361 export LC_ALL=C
362 export DEBIAN_FRONTEND=noninteractive
363
364 install_etc_passwd # This handles (2).
299 if [ "$FIX_BROKEN" ]; then 365 if [ "$FIX_BROKEN" ]; then
300 dpkg --root="$rootfs" --configure -a 366 dpkg --root="$rootfs" --configure -a
301 fi 367 fi