File: setup-testbed

package info (click to toggle)
autopkgtest 5.53
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,600 kB
  • sloc: python: 15,484; sh: 2,317; makefile: 116; perl: 19
file content (747 lines) | stat: -rwxr-xr-x 26,995 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
#!/bin/sh
# setup-testbed is part of autopkgtest
# autopkgtest is a tool for testing Debian binary packages
#
# autopkgtest is Copyright (C) 2006-2014 Canonical Ltd.
#
# Setup script for e. g. vmdebootstrap, generic Debian/Ubuntu VM or container
# images to start a root serial console on ttyS1, set up networking for
# ethernet, configure apt sources, install necessary and clean up unnecessary
# packages, etc. This can be used both for building tailored autopkgtest images
# as well as on a per-test basis as --setup-commands script (then some steps
# will be skipped).
#
# See autopkgtest-virt-qemu(1) for details how to use this with vmdeboostrap.
#
# You can set $AUTOPKGTEST_APT_PROXY; if set, it will be configured in apt in
# /etc/apt/apt.conf.d/01proxy. If you have an apt proxy configured on the host,
# it will be used automatically, unless $AUTOPKGTEST_APT_PROXY is set.
#
# You can set $MIRROR to change the default apt mirror.

set -eu

# Created files should be readable by user (this script is called as root)
umask 0022

# avoid debconf hangs
export DEBIAN_FRONTEND=noninteractive

if [ "${1:-}" = "--help" ]; then
    echo "Usage: $0 [chroot dir]"
    echo "if chroot dir is not given, run on the main system (for running in VMs)"
    exit 0
fi

root=${1:-/}
need_update_initramfs=

# Return true if $1 is correctly unpacked and configured.
package_is_installed () {
    # Debian Policy 10.4 says we have local even though it's non-POSIX
    # shellcheck disable=SC3043
    local status

    # ${Status} is dpkg-query syntax, not a shell variable here
    # shellcheck disable=SC2016
    if ! status="$(chroot "$root" dpkg-query -W -f '${Status}' "$1" 2>/dev/null)"; then
        return 1
    fi

    case "$status" in
        (*\ installed)
            return 0
            ;;
        (*)
            return 1
            ;;
    esac
}

# Return true if $1 is present in some form (maybe removed but not purged).
package_is_present () {
    if ! chroot "$root" dpkg-query -W "$1" >/dev/null 2>/dev/null; then
        return 1
    fi

    return 0
}

# set up init script for root shell on ttyS1; necessary for autopkgtest-virt-qemu local
# images
if [ "$root" != "/" ] || [ -e /dev/ttyS1 ] || [ -e /dev/hvc1 ]; then
    mkdir -p "$root/etc/init.d"
    cat <<EOF > "$root/etc/init.d/autopkgtest"
#!/bin/sh
### BEGIN INIT INFO
# Provides:          autopkgtest
# Required-Start:    \$all
# Required-Stop:
# Default-Start:     2 3 4 5
# Default-Stop:
### END INIT INFO

if [ "\$1" = start ]; then
    for device in ttyS1 hvc1; do
        if [ -e "/dev/\$device" ]; then
            echo "Starting root shell on \$device for autopkgtest"
            (setsid sh <"/dev/\$device" >"/dev/\$device" 2>&1) &
        fi
    done
fi
EOF

    chmod 755 "$root/etc/init.d/autopkgtest"
    chroot "$root" update-rc.d autopkgtest defaults

    if [ -n "${AUTOPKGTEST_BUILD_QEMU:-}" ]; then
        mkdir -p "$root/etc/initramfs-tools/hooks"
        cat <<EOF > "$root/etc/initramfs-tools/hooks/autopkgtest-build-qemu"
#!/bin/sh
set -e
PREREQ=""

prereqs () {
    echo "\${PREREQ}"
}

case "\${1}" in
    prereqs)
        prereqs
        exit 0
        ;;
esac

. /usr/share/initramfs-tools/hook-functions
manual_add_modules virtio_console
exit 0
EOF
        chmod 755 "$root/etc/initramfs-tools/hooks/autopkgtest-build-qemu"
        need_update_initramfs=yes
    fi

    cat <<EOF > "$root/etc/systemd/system/autopkgtest@.service"
[Unit]
Description=autopkgtest root shell on %I
ConditionPathExists=/dev/%I

[Service]
ExecStart=/bin/sh
StandardInput=tty-fail
StandardOutput=tty
StandardError=tty
TTYPath=/dev/%I
SendSIGHUP=yes
# ignore I/O errors on unusable tty
SuccessExitStatus=0 208 SIGHUP SIGINT SIGTERM SIGPIPE

[Install]
WantedBy=multi-user.target
EOF
    # Mask the unit generated for /etc/init.d/autopkgtest
    ln -sf /dev/null "$root/etc/systemd/system/autopkgtest.service"

    mkdir -p "$root/etc/systemd/system/multi-user.target.wants"
    for device in ttyS1 hvc1; do
        ln -sf ../autopkgtest@.service "$root/etc/systemd/system/multi-user.target.wants/autopkgtest@${device}.service"
    done
fi

# serial console for upstart
if [ -e "$root/etc/init/tty2.conf" ] && ! [ -e "$root/etc/init/ttyS0.conf" ]; then
    sed 's/tty2/ttyS0/g; s! *exec.*$!exec /sbin/getty -L ttyS0 115200 vt102!' \
        "$root/etc/init/tty2.conf" > "$root/etc/init/ttyS0.conf"
fi

ARCH="$(chroot "$root" dpkg --print-architecture)"

# Note that whichever console is specified *last* is the one we will get
# if we open /dev/console. See
# <https://www.kernel.org/doc/Documentation/admin-guide/serial-console.rst>
case "$ARCH" in
    (amd64|i386)
        consoles="console=tty0 console=hvc0 console=ttyS0"
        ;;

    (arm*)
        consoles="console=tty0 console=hvc0 console=ttyAMA0"
        ;;

    (ppc64*)
        consoles="console=tty0 console=hvc0"
        ;;

    (*)
        echo "Unknown architecture, assuming PC-style ttyS0" >&2
        # Let's make /dev/hvc0 the primary console for new architectures
        consoles="console=tty0 console=ttyS0 console=hvc0"
        ;;
esac

# serial console for systemd
# bump vmalloc on i386, necessary for tests like udisks2
if [ ! -e "$root/etc/default/grub.d/90-autopkgtest.cfg" ] && chroot "$root" which update-grub >/dev/null 2>&1; then
    changed=
    if [ -d "$root/etc/default/grub.d" ]; then
        if [ "$ARCH" = "i386" ]; then
            echo "GRUB_CMDLINE_LINUX_DEFAULT=\"$consoles vmalloc=512M\"" > \
                "$root/etc/default/grub.d/90-autopkgtest.cfg"
            changed=1
        elif [ "$ARCH" = "amd64" ]; then
            echo "GRUB_CMDLINE_LINUX_DEFAULT=\"$consoles\"" > \
                "$root/etc/default/grub.d/90-autopkgtest.cfg"
            changed=1
        fi
    else
        # fallback for Ubuntu 12.04
        if [ "$ARCH" = "i386" ]; then
            sed -i "/CMDLINE_LINUX_DEFAULT/ s/\"$/ $consoles vmalloc=512M\"/" "$root/etc/default/grub"
            changed=1
        elif [ "$ARCH" = "amd64" ]; then
            sed -i "/CMDLINE_LINUX_DEFAULT/ s/\"$/ $consoles\"/" "$root/etc/default/grub"
            changed=1
        fi
        if ! grep -q GRUB_HIDDEN_TIMEOUT=0 "$root/etc/default/grub" ; then
            sed -i '/^GRUB_TIMEOUT=/ s/=.*$/=1/' "$root/etc/default/grub"
            changed=1
        fi
    fi
    [ -z "${changed:-}" ] || chroot "$root" update-grub || echo "WARNING: update-grub failed!"
fi

# set up apt sources
if [ -e "$root/etc/os-release" ]; then
    # shellcheck disable=SC1090 disable=SC1091
    DISTRO_ID=$(. "$root/etc/os-release" && echo "$ID" || echo INVALID)
fi

if [ -n "${AUTOPKGTEST_KEEP_APT_SOURCES:-}" ]; then
    echo "$0: Keeping existing apt sources" >&2
elif [ -n "${AUTOPKGTEST_APT_SOURCES_FILE:-}" ]; then
    echo "$0: Copying apt sources from $AUTOPKGTEST_APT_SOURCES_FILE" >&2
    rm -f "$root/etc/apt/sources.list"
    rm -fr "$root/etc/apt/sources.list.d"
    mkdir "$root/etc/apt/sources.list.d"

    if grep -q "^Types:" "$AUTOPKGTEST_APT_SOURCES_FILE"; then
        # These look like .sources format.
        install -m644 "$AUTOPKGTEST_APT_SOURCES_FILE" "$root/etc/apt/sources.list.d/$DISTRO_ID.sources"
    else
        install -m644 "$AUTOPKGTEST_APT_SOURCES_FILE" "$root/etc/apt/sources.list"
    fi
elif [ -n "${AUTOPKGTEST_APT_SOURCES:-}" ]; then
    echo "$0: Setting apt sources from \$AUTOPKGTEST_APT_SOURCES" >&2
    rm -f "$root/etc/apt/sources.list"
    rm -fr "$root/etc/apt/sources.list.d"
    mkdir "$root/etc/apt/sources.list.d"

    if echo "$AUTOPKGTEST_APT_SOURCES" | grep -q "^Types:"; then
        # These look like .sources format.
        printf '%s\n' "$AUTOPKGTEST_APT_SOURCES" > "$root/etc/apt/sources.list.d/$DISTRO_ID.sources"
    else
        printf '%s\n' "$AUTOPKGTEST_APT_SOURCES" > "$root/etc/apt/sources.list"
    fi
else
    echo "$0: Attempting to set up Debian/Ubuntu apt sources automatically" >&2

    # Starting with 24.04, Ubuntu uses /etc/apt/sources.list.d/ubuntu.sources
    # for default sources, so check for that here.
    if [ -f "$root/etc/apt/sources.list.d/$DISTRO_ID.sources" ]; then
        deb822="y"
    else
        deb822=
    fi

    if [ -z "${RELEASE:-}" ]; then
        # This release detection logic should be kept in sync with setup-commands/get-default-release.
        # We can't simply call that script from here because setup-testbed can't have external
        # dependencies due to the way it is used by tools/autopkgtest-build* scripts.
        if [ -n "$deb822" ]; then
            RELEASE=$(chroot "$root" sed -En 's/^Suites:\s*(\w+).*/\1/Ip' "/etc/apt/sources.list.d/$DISTRO_ID.sources" | head -n1 || :)
        else
            RELEASE=$(chroot "$root" sed -En '/^(deb|deb-src) +(\[.*\] *)?(http|https|file):/ { s/\[.*\] +//; s/^[^ ]+ +[^ ]* +([^ ]+) +.*$/\1/p }' /etc/apt/sources.list | head -n1 || :)
        fi
    fi

    if [ -z "$RELEASE" ]; then
        # Deliberately not expanding $RELEASE here
        # shellcheck disable=SC2016
        echo 'Failed to auto-detect distribution release name; set $RELEASE explicitly' >&2
        exit 1
    fi

    if [ -z "${MIRROR:-}" ]; then
        if [ -n "$deb822" ]; then
            # shellcheck disable=SC2016
            MIRROR=$(chroot "$root" awk '/^URIs: .*'"$DISTRO_ID"'/ { sub(/\[.*\]/, "", $0); print $2; exit }' "/etc/apt/sources.list.d/$DISTRO_ID.sources" || :)
        else
            # shellcheck disable=SC2016
            MIRROR=$(chroot "$root" awk '/^deb .*'"$DISTRO_ID"'/ { sub(/\[.*\]/, "", $0); print $2; exit }' "/etc/apt/sources.list" || :)
        fi
    fi

    if [ -z "$MIRROR" ]; then
        # shellcheck disable=SC2016
        echo 'Failed to auto-detect apt mirror; set $MIRROR explicitly' >&2
        exit 1
    fi

    rm -f "$root/etc/apt/sources.list"
    rm -fr "$root/etc/apt/sources.list.d"
    mkdir "$root/etc/apt/sources.list.d"

    if [ "${MIRROR%ubuntu*}" != "$MIRROR" ]; then
        echo "$0: Distribution appears to be Ubuntu" >&2

        if [ -n "$deb822" ]; then
            cat << EOF > "$root/etc/apt/sources.list.d/$DISTRO_ID.sources"
Types: deb deb-src
URIs: $MIRROR
Suites: ${RELEASE} ${RELEASE}-updates ${RELEASE}-security
Components: main restricted universe multiverse
Signed-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg
EOF
        else
            cat << EOF > "$root/etc/apt/sources.list"
deb     $MIRROR ${RELEASE} main restricted universe multiverse
deb     $MIRROR ${RELEASE}-updates main restricted universe multiverse
deb     $MIRROR ${RELEASE}-security main restricted universe multiverse
deb-src $MIRROR ${RELEASE} main restricted universe multiverse
deb-src $MIRROR ${RELEASE}-updates main restricted universe multiverse
deb-src $MIRROR ${RELEASE}-security main restricted universe multiverse
EOF
        fi
    else
        echo "$0: Distribution assumed to resemble Debian" >&2
        case "$RELEASE" in
            jessie|stretch|buster|bullseye)
                COMPONENTS="main contrib non-free"
                ;;
            *)
                COMPONENTS="main contrib non-free non-free-firmware"
                ;;
        esac

        if [ -n "$deb822" ]; then
            cat << EOF > "$root/etc/apt/sources.list.d/$DISTRO_ID.sources"

Types: deb deb-src
URIs: $MIRROR
Suites: $RELEASE
Components: $COMPONENTS
EOF
        else
            cat << EOF > "$root/etc/apt/sources.list"
deb     $MIRROR $RELEASE $COMPONENTS
deb-src $MIRROR $RELEASE $COMPONENTS
EOF
        fi
        if [ "$DISTRO_ID" = debian ]; then
            if [ -z "${DEBIAN_SECURITY_MIRROR:-}" ]; then
                case "$RELEASE" in
                    (jessie|stretch|buster)
                        DEBIAN_SECURITY_MIRROR=http://archive.debian.org/debian-security
                        ;;
                    (*)
                        DEBIAN_SECURITY_MIRROR=http://security.debian.org/debian-security
                        ;;
                esac
            fi

            case "$RELEASE" in
                # no security support for these
                jessie|stretch|sid|unstable)
                    ;;
                buster)
                    # no security support since 2024 but we can use the
                    # set of security updates that existed at the end of LTS
                    if [ -n "$deb822" ]; then
                        cat << EOF >> "$root/etc/apt/sources.list.d/$DISTRO_ID.sources"

Types: deb deb-src
URIs: ${DEBIAN_SECURITY_MIRROR}
Suites: ${RELEASE}/updates
Components: $COMPONENTS
EOF
                    else
                        cat << EOF >> "$root/etc/apt/sources.list"
deb     ${DEBIAN_SECURITY_MIRROR} $RELEASE/updates $COMPONENTS
deb-src ${DEBIAN_SECURITY_MIRROR} $RELEASE/updates $COMPONENTS
EOF
                    fi
                    ;;
                *)
                    if [ -n "$deb822" ]; then
                        cat << EOF >> "$root/etc/apt/sources.list.d/$DISTRO_ID.sources"

Types: deb deb-src
URIs: ${DEBIAN_SECURITY_MIRROR}
Suites: ${RELEASE}-security
Components: $COMPONENTS
EOF
                    else
                        cat << EOF >> "$root/etc/apt/sources.list"
deb     ${DEBIAN_SECURITY_MIRROR} $RELEASE-security $COMPONENTS
deb-src ${DEBIAN_SECURITY_MIRROR} $RELEASE-security $COMPONENTS
EOF
                    fi
                    ;;
            esac
        fi
    fi
fi

# prevent subsequent cloud-init runs from modifying the apt sources again
if package_is_installed cloud-init; then
    mkdir -p "$root/etc/cloud/cloud.cfg.d"
    # cloud-init 23.4 introduced non-zero exit code for deprecation warnings.
    # apt_preserve_sources_list is a deprecated cloud-config key.
    cloudinit_version=$(dpkg-query -W -f '${Version}' cloud-init)
    cloud_cfg_file=$root/etc/cloud/cloud.cfg.d/01_autopkgtest.cfg
    if dpkg --compare-versions "${cloudinit_version}" ge 23.4; then
        echo 'apt: {preserve_sources_list: true}' > "$cloud_cfg_file"
    else
        echo 'apt_preserve_sources_list: true' > "$cloud_cfg_file"
    fi
fi

# Return 0 when an existing network configuration is detected, otherwise 1
#
# An existing configuration is indicated by:
#   (1) For plain /etc/network/interfaces, the presence of an auto stanza
#       other than lo
#   (2) For the drop-in directories, the mere existence of one or more files
netconf_exists () {
    # iproute2: legal interface name is anything excluding front slash and whitespace
    if [ -e "$root"/etc/network/interfaces ] && \
	    grep -qE '^auto[[:space:]]+(.*[[:space:]])?([^l/]|l[^o]|lo[^[:space:]])' \
		"$root/etc/network/interfaces"; then
        return 0
    elif ls "$root"/etc/network/interfaces.d/* >/dev/null 2>&1; then
        return 0
    elif [ -h "$root/etc/systemd/system/multi-user.target.wants/systemd-networkd.service" ]; then
	# systemd-networkd has been enabled. It is not default-enabled and
	# netplan.io would only runtime-enable it. If something enabled it,
	# it most likely also is configured (e.g. for host0 networking).
        return 0
    elif ls "$root"/etc/netplan/*.yaml >/dev/null 2>&1; then
        return 0
    fi
    return 1
}

# Print the name of an installed network configuration utility, or ""
#
# The order of checks affects the outcome. systemd must be placed last, as it
# will almost always be installed.
get_netconf_util () {
    for pname in ifupdown netplan.io systemd; do
        if package_is_installed "$pname"; then
            printf '%s' "$pname"
            break
        fi
    done
}

configure_networking_ifupdown () {
    iface="$1"

    # Ensure that the drop-in directory exists and is used
    if ! grep -q 'source.*interfaces.d' "$root/etc/network/interfaces"; then
        mkdir -p "$root/etc/network/interfaces.d"
        printf "\nsource-directory /etc/network/interfaces.d\n" >> "$root/etc/network/interfaces"
    fi

    printf 'auto %s\niface %s inet dhcp\n' "$iface" "$iface" >> "$root/etc/network/interfaces.d/$iface"
}

configure_networking_netplan () {
    iface="$1"

    cat > "$root/etc/netplan/$iface.yaml" <<EOF
network:
  version: 2
  renderer: networkd
  ethernets:
    $iface:
      dhcp4: yes
EOF

    chroot "$root" netplan apply
}

configure_networking () {
    if netconf_exists; then
        echo "network config already present, skipping network config"
        return
    fi

    netconf_util="$(get_netconf_util)"
    if [ -z "$netconf_util" ]; then
        echo "no known network config tool found, skipping network config"
        return
    fi

    IFACE=""
    if [ "$root" = / ] ; then
        # we are already in a VM, so figure out our network device
        IFACE=$(find /sys/class/net \( -name 'en*' -o -name 'wl*' -o -name 'eth*' \) -printf '%f' -quit)
    else
        # the kernel will choose eth0 as the interface name, so
        # keep that (and tell udev to not rename the interface,
        # we won't know how it will be called)
        IFACE="eth0"
        if ! [ -e "$root/etc/udev/rules.d/80-net-setup-link.rules" ] ; then
            ln -s /dev/null "$root/etc/udev/rules.d/80-net-setup-link.rules"
            need_update_initramfs=yes
        fi
    fi

    case "$netconf_util" in
        ifupdown)
            configure_networking_ifupdown "$IFACE"
            ;;
        netplan.io)
            configure_networking_netplan "$IFACE"
            ;;
        *)
            echo "Network configuration using $netconf_util not implemented yet" >&2
            ;;
    esac
}

if [ -z "${AUTOPKGTEST_IS_SETUP_COMMAND:-}" ]; then
    configure_networking
fi

# go-faster apt/dpkg
echo "Acquire::Languages \"none\";" > "$root"/etc/apt/apt.conf.d/90nolanguages
echo 'force-unsafe-io' > "$root"/etc/dpkg/dpkg.cfg.d/autopkgtest

# avoid failures do to transient timeouts
echo 'Acquire::Retries "10";' > "$root"/etc/apt/apt.conf.d/90retry
# make apt update fail even on transient errors
echo 'APT::Update::Error-Mode "any";' > "$root"/etc/apt/apt.conf.d/90errmode

# Set up apt proxy for setup, if given.
# Unlike AUTOPKGTEST_APT_PROXY, this is expected to be a proxy that is
# valid both during setup and during use.
if [ -n "${AUTOPKGTEST_SETUP_APT_PROXY-}" ]; then
    echo "Acquire::http { Proxy \"$AUTOPKGTEST_SETUP_APT_PROXY\"; };" > "$root"/etc/apt/apt.conf.d/01autopkgtest-setup-proxy
fi

# support backwards compatible env var too
AUTOPKGTEST_APT_PROXY=${AUTOPKGTEST_APT_PROXY:-${ADT_APT_PROXY:-}}

# detect apt proxy on the host (in chroot mode)
if [ "$root" != "/" ] && [ -z "$AUTOPKGTEST_APT_PROXY" ] && command -v apt-config; then
    RES=$(apt-config shell proxy Acquire::http::Proxy)
    if [ -n "$RES" ]; then
        # evaluating $RES will set proxy, but shellcheck can't know that
        proxy=
        eval "$RES"
        if echo "$proxy" | grep -E -q '(localhost|127\.0\.0\.[0-9]*)'; then
            AUTOPKGTEST_APT_PROXY=$(echo "$proxy" | sed -r "s#localhost|127\.0\.0\.[0-9]*#10.0.2.2#")
        elif [ -n "${proxy:-}" ]; then
            AUTOPKGTEST_APT_PROXY="$proxy"
        fi
    fi
fi

# Ensure chroot has a working resolv.conf; it might be a symlink on the host
if [ "$root" != "/" ] && [ -e /etc/resolv.conf ]; then
    if [ -e "$root/etc/resolv.conf" ] || [ -L "$root/etc/resolv.conf" ]; then
        mv "$root/etc/resolv.conf" "$root/etc/resolv.conf.vmdebootstrap"
    fi
    cat /etc/resolv.conf > "$root/etc/resolv.conf"
    trap 'if [ -e "$root/etc/resolv.conf.vmdebootstrap" ] || [ -L "$root/etc/resolv.conf.vmdebootstrap" ]; then mv "$root/etc/resolv.conf.vmdebootstrap" "$root/etc/resolv.conf"; fi' EXIT INT QUIT PIPE
fi

if [ -z "${AUTOPKGTEST_IS_SETUP_COMMAND:-}" ]; then
    # This || and the following retry should be removed when
    # distro releases with an apt version < 1.6 no longer need to be supported.
    # This means Buster & later for Debian, and releases after Bionic for Ubuntu.
    chroot "$root" apt-get update || (sleep 15; chroot "$root" apt-get update)
fi

# eatmydata for fast dpkg
chroot "$root" apt-get install -y eatmydata < /dev/null

# Optionally set up an init system.
# This can be used to swap a normally-systemd qemu image to sysv-rc,
# or to add systemd to a Docker/Podman image that does not normally have
# an init system.
if [ -z "${AUTOPKGTEST_IS_SETUP_COMMAND:-}" ]; then
    case "${AUTOPKGTEST_SETUP_INIT_SYSTEM-}" in
        ('')
            ;;

        (systemd | systemd-sysv)
            packages="init systemd-sysv"

            if chroot "$root" apt-cache show libpam-systemd >/dev/null 2>&1; then
                packages="$packages libpam-systemd"
            fi

            # Deliberately word-splitting:
            # shellcheck disable=SC2086
            chroot "$root" eatmydata apt-get install -y $packages < /dev/null
            ;;

        (sysv-rc | openrc | sysvinit | sysvinit-core)
            # procps is not strictly mandatory, but lib/await-boot.sh needs it
            packages="init sysvinit-core procps"

            case "$AUTOPKGTEST_SETUP_INIT_SYSTEM" in
                (sysvinit*)
                    ;;
                (*)
                    packages="$packages $AUTOPKGTEST_SETUP_INIT_SYSTEM"
                    ;;
            esac

            if chroot "$root" apt-cache show libpam-elogind >/dev/null 2>&1; then
                packages="$packages libpam-elogind"
            fi

            # Deliberately word-splitting:
            # shellcheck disable=SC2086
            chroot "$root" eatmydata apt-get install -y $packages < /dev/null
            ;;

        (*)
            echo "Error: unsupported init system AUTOPKGTEST_SETUP_INIT_SYSTEM=$AUTOPKGTEST_SETUP_INIT_SYSTEM"
            exit 1
            ;;
    esac

    # serial console for sysvinit
    if [ -e "$root/etc/inittab" ] && ! grep '^T0:' "$root/etc/inittab" > /dev/null; then
        echo "T0:23:respawn:/sbin/getty -L ttyS0 115200 vt100" >> "$root/etc/inittab"
    fi
fi

# install some necessary packages

if [ -x "$root/sbin/init" ]; then
    if [ ! -e "$root/usr/sbin/policy-rc.d" ]; then
        printf "#!/bin/sh\nexit 101\n" > "$root/usr/sbin/policy-rc.d"
        chmod +x "$root/usr/sbin/policy-rc.d"
    fi

    # lot of tests expect a logind session
    chroot "$root" eatmydata apt-get install -y dbus < /dev/null

    if package_is_installed systemd && ! package_is_installed libpam-systemd && chroot "$root" apt-cache show libpam-systemd >/dev/null 2>&1; then
        chroot "$root" eatmydata apt-get install -y libpam-systemd </dev/null
    fi

    # some tests use a lot of /dev/random, avoid hangs
    if ! systemd-detect-virt --quiet --container; then
        chroot "$root" eatmydata apt-get install -y rng-tools </dev/null
    fi
fi

# optimization as we need to install it for most tests anyway
if ! package_is_installed dpkg-dev; then
    chroot "$root" eatmydata apt-get install -y --no-install-recommends dpkg-dev </dev/null
fi

# upgrade and trim image (not for --setup-command)
if [ -z "${AUTOPKGTEST_IS_SETUP_COMMAND:-}" ]; then
    # Mark some packages as manually installed, so that apt-get --auto-remove in the
    # "clean up bloat" stage just below won't remove them.
    for p in apparmor apt cloud-init iproute2 lxd-agent-loader netplan.io openssh-server sudo; do
        if package_is_installed "$p"; then
            chroot "$root" apt-mark manual "$p"
        fi
    done

    # clean up bloat from Ubuntu cloud images when building an image
    purge_list=''
    for p in accountsservice apt-xapian-index cryptsetup landscape-client \
             landscape-common open-vm-tools w3m vim-runtime aptitude-common \
             command-not-found-data manpages ntfs-3g sosreport \
             ubuntu-release-upgrader-core libcpan-changes-perl git \
             cgmanager lxc-common lxc lxd lxd-client open-iscsi mdadm dmeventd lvm2 \
             unattended-upgrades update-notifier-common ureadahead debootstrap \
             lxcfs ppp pppconfig pppoeconf snapd snap-confine ubuntu-core-launcher \
             thermald xdg-user-dirs zerofree xml-core needrestart ubuntu-pro-client \
             motd-news-config; do
        if package_is_present "$p"; then
            purge_list="$purge_list $p"
        fi
    done
    if [ -n "$purge_list" ]; then
        # Deliberately word-splitting $purge_list:
        # shellcheck disable=SC2086
        chroot "$root" eatmydata apt-get --auto-remove -y purge $purge_list || true
    fi

    if [ "${AUTOPKGTEST_SETUP_VM_UPGRADE:-}" != "false" ]; then
        chroot "$root" eatmydata apt-get -o Dpkg::Options::="--force-confold" -y dist-upgrade </dev/null
        chroot "$root" eatmydata apt-get -o Dpkg::Options::="--force-confold" -y --purge autoremove </dev/null
    fi
else
    # we want to keep cloud-init on autopkgtest images for instantiating, but not
    # on test instances themselves as it often gets in the way
    if package_is_present cloud-init; then
        chroot "$root" eatmydata apt-get --auto-remove -y purge cloud-init || true
    fi
fi

if grep -q buntu "$root/etc/os-release" "$root/etc/lsb-release"; then
    if ls "$root"/boot/vmlinu* >/dev/null 2>&1; then
        # provides kmods like scsi_debug or mac80211_hwsim on Ubuntu
        chroot "$root" eatmydata apt-get install -y --no-install-recommends linux-generic < /dev/null
    else
        chroot "$root" eatmydata apt-get install -y --no-install-recommends linux-headers-generic < /dev/null
    fi
fi

# we need Python to run the auxverb helper
if ! chroot "$root" sh -c 'type python3 >/dev/null 2>&1 || type python >/dev/null 2>&1'; then
    chroot "$root" eatmydata apt-get install -y --no-install-recommends python3-minimal < /dev/null
fi

# run post-install commands
if [ -n "${AUTOPKGTEST_SETUP_VM_POST_COMMAND:-}" ]; then
    chroot "$root" sh -ec "$AUTOPKGTEST_SETUP_VM_POST_COMMAND"
fi

if [ -z "${AUTOPKGTEST_IS_SETUP_COMMAND:-}" ]; then
    chroot "$root" eatmydata apt-get clean
fi

rm -f "$root"/etc/apt/apt.conf.d/01autopkgtest-setup-proxy

# set up apt proxy, if given (this might be an IP which only works in the VM,
# so don't run the previous apt-get with that already)
if [ -n "$AUTOPKGTEST_APT_PROXY" ]; then
    echo "Acquire::http { Proxy \"$AUTOPKGTEST_APT_PROXY\"; };" > "$root"/etc/apt/apt.conf.d/01proxy
fi

# avoid cron interference with apt-get update
echo 'APT::Periodic::Enable "0";' > "$root/etc/apt/apt.conf.d/02periodic"

# always include phased updates, so that the output is what we expect.
echo 'APT::Get::Always-Include-Phased-Updates "true";' > "$root/etc/apt/apt.conf.d/90always-include-phased-updates"

if [ -n "$need_update_initramfs" ] && chroot "$root" which update-initramfs >/dev/null 2>&1; then
    chroot "$root" update-initramfs -u
fi

if [ -x "$root/sbin/init" ]; then
    rm -f "$root/usr/sbin/policy-rc.d"
fi

# prevent /tmp to be a tmpfs due to size limits this imposes
if [ -d /run/systemd/system ]; then
    chroot "$root" touch /etc/systemd/system/tmp.mount
    # configure /tmp to be deleted on every boot to mimic tmpfs behavior
    chroot "$root" mkdir -p /etc/tmpfiles.d
    cat <<EOF > "$root/etc/tmpfiles.d/tmp.conf"
D /tmp 1777 root root 10d
q /var/tmp 1777 root root 30d
EOF
fi