. "$BST_LIB" RC_GROUP=a RC_SFX= # BST-TIMEOUT: 1500 # group a is 82 transcript cases -- one scenario-driver run # of phases 0-8 (~40 resolvconf execs, each forking run-parts, # sed, flock and bash) plus the structural and real-path arms. # Set from a measurement, not a guess: the UNSPLIT suite ran # 577 s once and then overran 900 s on a busier host, so the # bound is declared against the worse of the two observations # rather than the better one, on the half. See the ==BST-SUITE # line this suite emits and the design doc. # resolvconf -- the WHOLE INTERFACE, driven under a temporary root and compared # BYTE FOR BYTE against a native oracle of the same scripts. # # WHY A TRANSCRIPT AND NOT ASSERTIONS. resolvconf compiles nothing: do_compile is # a no-op and every file it ships is a shell or sed script. So the usual reading # of "does the port work" -- did the compiler produce a correct binary -- has no # subject here. What the port is actually at risk in is everything UNDERNEATH it: # the ported bash (list-records needs nullglob and extglob), the ported sed # (normalize-resolvconf IS a sed program, and update.d/libc compiles the whole # file with four more), the ported coreutils, run-parts and flock. A defect in # any of those shows up as a WRONG /etc/resolv.conf and not as an error, which is # the failure a smoke test cannot see: "resolvconf -a exited 0" is satisfied by a # build that wrote an empty file. # # WHY A TEMPORARY ROOT. resolvconf hardcodes /run/resolvconf, /etc/resolvconf and # /lib/resolvconf in every script and offers no override, so a native oracle # cannot run it at all -- /run/resolvconf on a build host is neither writable nor # ours. The one rewrite that makes both sides possible is moving those prefixes # into a temporary root, and resolvconf-temproot.sh is that rewrite, run from the # SAME FILE on both sides so the two trees cannot be built differently. It # asserts afterwards that no unrewritten prefix survived, because a survivor on # target -- running as root -- is a silent write to the machine's live resolver # state rather than an error. # # WHAT THE ORACLE IS, AND WHERE IT IS NOT THE BUILD HOST. For the interface as a # whole it is a native run of the shipped scripts, recorded at do_install. For # normalize-resolvconf it is UPSTREAM ITSELF: the 21 cases in # resolvconf-normalize-corpus.txt are transcribed from debian/test-normalization, # which ships in the source and in no binary package, so their match= lines are a # comparison against the specification and hold no matter what sed either side # has. That distinction is what makes a red attributable: a case that differs # from the oracle but still matches upstream is a build-host difference, and one # that fails both is the port. # # # THIS SUITE IS ONE HALF OF A PAIR. The full matrix costs ~600 process spawns and # this platform does not return memory on process exit (brintos/linux#21, # brintos/hardwarejs#20), so running it in one guest peaked at 12.4 GiB and was # killed by brintos_local_verify's RSS-rate bound -- reporting ZERO cases, which # is worse than any red, and then overran the 900 s bound on the run that did # survive. resolvconf-scenarios.sh therefore takes a phase group, the oracle # records one expected transcript per group, and each half is its own suite so # each gets its own guest. 99-resolvconf.test is group a and owns the structural, # manifest, flock and real-path cases; 99-resolvconf-order.test is group b. # # THE REAL-PATH ARM IS SEPARATE AND IS NOT REDUNDANT. The temporary root proves # the LOGIC; it says nothing about whether the package is installed where its own # scripts look, whether /usr/bin/flock resolved to a flock that has -w (busybox's # applet does not, and it wins the alternative at priority 50 until # util-linux-flock is installed at 80), or whether run-parts exists at all. Those # are asserted at the end, against the machine's real /run/resolvconf, and then # restored. require resolvconf resolvconf$RC_SFX/present require bash resolvconf$RC_SFX/bash-present require sed resolvconf$RC_SFX/sed-present require run-parts resolvconf$RC_SFX/run-parts-present require flock resolvconf$RC_SFX/flock-present require awk resolvconf$RC_SFX/awk-present require cmp resolvconf$RC_SFX/cmp-present T=/usr/libexec/resolvconf-tests if [ ! -f "$T/expected-$RC_GROUP.txt" ] || [ ! -f "$T/oracle-info" ]; then bst_notok resolvconf$RC_SFX/corpus "no oracle payload at $T -- resolvconf-tests is not installed, so every comparison in this suite is unrunnable" exit 0 fi W=${TMPDIR:-/tmp}/bst-resolvconf-$RC_GROUP.$$ if ! mkdir -p "$W" 2>/dev/null; then bst_notok resolvconf$RC_SFX/stage "cannot create working directory $W" exit 0 fi # The payload is COPIED TO /tmp and read from there, never redirected from the # rootfs. A top-level `while read ... done < /usr/...` on the virtiofs root hits # brintos/linux#73: dup2(2) returns 513, ash prints "Unknown error 513" and exits, # and the runner then reports every case emitted so far as a pass and nothing at # all about the ones never reached -- a clean-looking run that is simply shorter. for f in "expected-$RC_GROUP.txt" oracle-info scripts.sha256 oracle-report.txt \ resolvconf-temproot.sh resolvconf-scenarios.sh resolvconf-normalize-corpus.txt \ resolvconf-cmp.awk; do cp "$T/$f" "$W/$f" 2>/dev/null done if [ ! -s "$W/expected-$RC_GROUP.txt" ]; then bst_notok resolvconf$RC_SFX/stage "cannot copy the oracle payload from $T to $W" rm -rf "$W"; exit 0 fi chmod 0755 "$W/resolvconf-temproot.sh" "$W/resolvconf-scenarios.sh" 2>/dev/null info_cases=$(sed -n "s/^cases-$RC_GROUP //p" "$W/oracle-info") info_corpus=$(sed -n 's/^corpus-cases //p' "$W/oracle-info") info_order=$(sed -n 's/^order-records //p' "$W/oracle-info") # --- 1. The shipped layout --------------------------------------------------- # resolvconf reaches these five by absolute path from inside its own scripts, so # a file installed one directory over is not a packaging detail -- it is a # NoSuchFile at run time with no other symptom. for p in /sbin/resolvconf \ /lib/resolvconf/list-records \ /lib/resolvconf/normalize-resolvconf \ /etc/resolvconf/interface-order \ /etc/resolvconf/update.d/libc; do if [ -f "$p" ]; then bst_ok "resolvconf$RC_SFX/installed$(echo "$p" | tr / -)" else bst_notok "resolvconf$RC_SFX/installed$(echo "$p" | tr / -)" "$p is not installed, but resolvconf names it by absolute path"; fi done for p in /sbin/resolvconf /lib/resolvconf/list-records \ /lib/resolvconf/normalize-resolvconf /etc/resolvconf/update.d/libc; do if [ -x "$p" ]; then bst_ok "resolvconf$RC_SFX/exec$(echo "$p" | tr / -)" else bst_notok "resolvconf$RC_SFX/exec$(echo "$p" | tr / -)" "$p is installed but not executable"; fi done # base_libdir and nonarch_base_libdir are separate variables that happen to be # the same directory on this arm. bin/resolvconf hardcodes /lib/resolvconf for # BOTH helpers, so an arm where they diverge ships a normalize-resolvconf the # main script cannot find -- and the only symptom is an empty record. check resolvconf$RC_SFX/libdirs-coincide \ test -f /lib/resolvconf/list-records -a -f /lib/resolvconf/normalize-resolvconf # /etc/resolvconf/run is the package's own indirection to the runtime directory. # Assert where it LANDS, not what it says: do_install writes an absolute # ${localstatedir}/run/resolvconf, and Yocto's packaging rewrites absolute # symlinks inside ${D} to relative ones, so the link text on target is # ../../var/run/resolvconf. Both spellings resolve to the same directory, and the # directory is the thing resolvconf needs -- pinning the text asserts a packaging # convention this port does not own. rc_run_target=$(readlink -f /etc/resolvconf/run 2>/dev/null) check_eq resolvconf$RC_SFX/run-symlink "/run/resolvconf" "$rc_run_target" # --- 2. Both sides ran the same bytes ---------------------------------------- # Without this a red is ambiguous between "the port is wrong" and "the oracle # measured a different script", which are opposite findings. if grep -v '^#' "$W/scripts.sha256" | sha256sum -c --quiet >/dev/null 2>&1; then bst_ok resolvconf$RC_SFX/manifest else bst_notok resolvconf$RC_SFX/manifest "an installed script does not match the checksum the oracle recorded at build time: $(_bst_1line "$(grep -v '^#' "$W/scripts.sha256" | sha256sum -c 2>&1 | grep -v ': OK$')")" fi # --- 3. flock and run-parts are the implementations the oracle used ---------- # bin/resolvconf calls `flock -w 10 9`. busybox's flock applet has no -w, so an # image where busybox wins /usr/bin/flock loses EVERY state-changing command -- # and loses it inside a { } block whose failure is reported as a lock timeout. if flock --version >/dev/null 2>&1; then bst_ok resolvconf$RC_SFX/flock-is-util-linux else bst_notok resolvconf$RC_SFX/flock-is-util-linux "$(command -v flock) does not answer --version, so it is not util-linux's flock; busybox's applet has no -w and every resolvconf -a/-d/-u would fail" fi # Whether `flock -w` can arm its timeout AT ALL on this kernel. util-linux # implements it with timer_create(2), which is ENOSYS here -- syscall slots # 222..226 are absent from the wasm32 table although CONFIG_POSIX_TIMERS=y and # posix-timers.o is in vmlinux (brintos.io/brintos/linux/issues/40, found by the # libcheck port). This is a PROBE, not an assertion: it records what the machine # does, so the day 40 lands the skip below becomes a pass with no edit here. rc_w=$(flock -w 1 9 2>&1 9>"$W/lockprobe"; echo "rc=$?") case "$rc_w" in "rc=0") bst_ok resolvconf$RC_SFX/flock-w-accepted ;; *"cannot set up timer"*) bst_skip resolvconf$RC_SFX/flock-w-accepted "flock -w cannot arm its timeout on this kernel ($rc_w): timer_create(2) is ENOSYS, brintos/linux#40. /sbin/resolvconf carries a bounded flock -n fallback for exactly this, pinned by resolvconf$RC_SFX/workaround-flock-fallback below" ;; *) bst_notok resolvconf$RC_SFX/flock-w-accepted "flock -w failed for a reason that is NOT brintos/linux#40, so the fallback in /sbin/resolvconf may be covering the wrong defect: $rc_w" ;; esac # The workaround itself, pinned at SOURCE level -- which is the only level that # can pin it. Its whole effect exists only where timer_create is missing, so on # the build host both the patched and the unpatched script produce byte-identical # output and no comparison in this suite would notice the patch being dropped. # The ORDER is the load-bearing part: the fallback has to sit after the -w # attempt, because a version that ran flock -n first would take the lock and then # never exercise -w at all, which is a different program that happens to work. if [ -r /sbin/resolvconf ]; then wa_marker=$(grep -c 'BRINTOS-WORKAROUND: brintos/linux#40' /sbin/resolvconf) wa_w=$(grep -n 'if ! flock -w \$LOCK_WAIT_S 9' /sbin/resolvconf | head -1 | cut -d: -f1) wa_n=$(grep -n 'while ! flock -n 9' /sbin/resolvconf | head -1 | cut -d: -f1) if [ "$wa_marker" -lt 1 ]; then bst_notok resolvconf$RC_SFX/workaround-flock-fallback "/sbin/resolvconf carries no BRINTOS-WORKAROUND marker for brintos/linux#40, so either the patch was dropped or the marker was -- and brintos_reconcile.py can only reclaim what is marked" elif [ -z "$wa_w" ] || [ -z "$wa_n" ]; then bst_notok resolvconf$RC_SFX/workaround-flock-fallback "the marker is there but the fallback is not: guarded -w at line '${wa_w:-none}', flock -n retry at line '${wa_n:-none}'" elif [ "$wa_w" -lt "$wa_n" ]; then bst_ok resolvconf$RC_SFX/workaround-flock-fallback else bst_notok resolvconf$RC_SFX/workaround-flock-fallback "the flock -n retry (line $wa_n) precedes the flock -w attempt (line $wa_w), so -w is never exercised and the fallback is not a fallback" fi else bst_notok resolvconf$RC_SFX/workaround-flock-fallback "/sbin/resolvconf is not readable" fi # run-parts has two implementations on this image -- busybox's applet at # alternative priority 50 and debianutils' at 60 -- and the expected transcript # was recorded against debianutils'. resolvconf-tests RDEPENDS on # debianutils-run-parts so that the comparison is against the same one. if run-parts --version 2>&1 | grep -q 'Debian run-parts'; then bst_ok resolvconf$RC_SFX/run-parts-is-debianutils else bst_notok resolvconf$RC_SFX/run-parts-is-debianutils "run-parts is $(run-parts --version 2>&1 | head -1), not debianutils' -- the expected transcript was recorded against debianutils'" fi # --- 4. The temporary root --------------------------------------------------- R="$W/root" if "$W/resolvconf-temproot.sh" "$R" \ /sbin/resolvconf /lib/resolvconf/list-records \ /lib/resolvconf/normalize-resolvconf /etc/resolvconf/interface-order \ /etc/resolvconf/update.d/libc > "$W/temproot.log" 2>&1; then bst_ok resolvconf$RC_SFX/temproot else bst_notok resolvconf$RC_SFX/temproot "$(_bst_1line "$(cat "$W/temproot.log")")" rm -rf "$W"; exit 0 fi # --- 5. The transcript ------------------------------------------------------- sh "$W/resolvconf-scenarios.sh" "$R" "$W/resolvconf-normalize-corpus.txt" "$RC_GROUP" \ > "$W/actual.txt" 2> "$W/actual.err" rc_sc=$? check_eq resolvconf$RC_SFX/scenarios-rc 0 "$rc_sc" if [ -s "$W/actual.err" ]; then bst_notok resolvconf$RC_SFX/scenarios-stderr "the scenario driver wrote to stderr: $(_bst_1line "$(cat "$W/actual.err")")" else bst_ok resolvconf$RC_SFX/scenarios-stderr fi # A driver that died half way emits a shorter transcript and every case it DID # reach still compares clean, so the run reads as a pass over fewer comparisons. # The sentinel is the only thing that separates the two. if [ "$(tail -1 "$W/actual.txt" 2>/dev/null)" = "==TRANSCRIPT-END==" ]; then bst_ok resolvconf$RC_SFX/transcript-complete else bst_notok resolvconf$RC_SFX/transcript-complete "the driver stopped before its last phase; last line was $(_bst_1line "$(tail -1 "$W/actual.txt")")" fi # Compare the two transcripts in ONE awk pass rather than per case. # # The obvious shape -- split both files into 131 pairs and cmp each -- costs 262 # file creations and 131 forks, and this guest does not return memory on process # exit: the guest's RSS climbed past brintos_local_verify's 2048 MiB/min bound # and the whole suite was quarantined as `guest-wedged`, reporting zero cases. # That is worse than a red, because it says nothing at all. One awk holds both # transcripts (~23 kB each), compares them in memory, and prints one verdict line # per case; the shell loop below is then entirely fork-free, since bst_ok, # bst_notok and _bst_1line are all printf and parameter expansion. # The controls ride the SAME awk invocation as the real comparison, appended as # three synthetic cases. Two reasons, and the second is why they are not a # separate run: a control that drives a different invocation leaves the real one # unmeasured, and every extra process is memory this guest never gives back -- # brintos/linux#21 / brintos/hardwarejs#20, which is what wedged an earlier # revision of this suite at 12.4 GiB with zero cases reported. cp "$W/expected-$RC_GROUP.txt" "$W/exp+ctl" cp "$W/actual.txt" "$W/act+ctl" printf '==CASE control-same==\nnameserver 10.0.0.1\n==END control-same==\n==CASE control-diff==\nnameserver 10.0.0.1\n==END control-diff==\n==CASE control-gone==\nx\n==END control-gone==\n' >> "$W/exp+ctl" printf '==CASE control-same==\nnameserver 10.0.0.1\n==END control-same==\n==CASE control-diff==\nnameserver 10.0.0.7\n==END control-diff==\n' >> "$W/act+ctl" awk -f "$W/resolvconf-cmp.awk" "$W/exp+ctl" "$W/act+ctl" > "$W/verdicts" n_all=0 n_bad=0 # BST-REDIRECT-OK: reads the $TMPDIR verdict file this suite just wrote, never the rootfs while read -r v n d; do [ -n "$n" ] || continue n_all=$((n_all + 1)) case "$n" in control-*) n_all=$((n_all - 1)) ;; esac case "$v" in ok) [ "${n#control-}" = "$n" ] && bst_ok "resolvconf$RC_SFX/$n" ;; diff) case "$n" in control-*) ;; *) n_bad=$((n_bad + 1)); bst_notok "resolvconf$RC_SFX/$n" "differs from the native oracle at $(_bst_1line "$d")" ;; esac ;; *) case "$n" in control-*) ;; *) n_bad=$((n_bad + 1)); bst_notok "resolvconf$RC_SFX/$n" "$(_bst_1line "$d")" ;; esac ;; esac done < "$W/verdicts" # The corpus must be the WHOLE corpus. A partially-recorded expectation makes # every comparison above pass over fewer cases, which is the one regression a # green run cannot show. check_eq resolvconf$RC_SFX/case-count "$info_cases" "$n_all" # --- Controls on the comparator itself --------------------------------------- # A comparison that cannot fail is not evidence. These read the verdicts the ONE # awk run above produced for the three synthetic cases appended to it, so what is # being controlled is the comparator that actually ran, in the invocation that # actually ran it. check_eq resolvconf$RC_SFX/control-detects-sameness "ok" "$(sed -n 's/^\(ok\) control-same$/\1/p' "$W/verdicts")" check_eq resolvconf$RC_SFX/control-detects-difference "diff" "$(sed -n 's/^\(diff\) control-diff line.*/\1/p' "$W/verdicts")" check_eq resolvconf$RC_SFX/control-detects-missing "missing" "$(sed -n 's/^\(missing\) control-gone .*/\1/p' "$W/verdicts")" # --- 6. The real-path arm ---------------------------------------------------- # Everything above ran under $W. This runs the INSTALLED /sbin/resolvconf at the # paths it was built for, which is the only thing that exercises the alternative # resolution of flock and run-parts, the /etc/resolvconf/run indirection, and the # fact that /run is writable at all. State is saved and restored around it. # # Nothing else on this image owns /run/resolvconf or /etc/resolv.conf: there is # no populate-volatile.sh here, so the package's own 99_resolvconf volatiles file # is never processed and both paths start absent. # First, what /run actually IS here. resolvconf puts its whole runtime state # under /run/resolvconf, and this image's /etc/inittab declares exactly two # ::sysinit: actions -- a tmpfs on /tmp and run-postinsts -- so nothing ever # mounts the `tmpfs /run tmpfs` line its own /etc/fstab carries. /run is # therefore a directory on the root filesystem, and whether resolvconf can work # at its real paths is a question about that filesystem rather than about the # port. Probed, and reported with the answer, rather than assumed either way. rp_rootfs=$(awk '$2=="/"{print $3; exit}' /proc/mounts 2>/dev/null) rp_runfs=$(awk '$2=="/run"{print $3; exit}' /proc/mounts 2>/dev/null) [ -n "$rp_runfs" ] || rp_runfs="none (/run is part of the $rp_rootfs root, not a mount point)" mkdir -p /run/bst-rcprobe 2>"$W/rp.err" if [ -d /run/bst-rcprobe ] && : > /run/bst-rcprobe/lock 2>>"$W/rp.err"; then bst_ok resolvconf$RC_SFX/run-writable rp_writable=1 else bst_notok resolvconf$RC_SFX/run-writable "/run is not writable on this boot ($rp_runfs): $(_bst_1line "$(cat "$W/rp.err")")" rp_writable= fi # The control comes first on purpose: a flock that fails on BOTH filesystems is a # statement about flock, and one that fails only under /run is a statement about # that filesystem. Without the control the two are indistinguishable, and the # temporary root above has already been locking successfully under $TMPDIR. rp_tmplock=$( flock -n 9 2>&1 9>"$W/tmpflock" ; echo "rc=$?" ) check_eq resolvconf$RC_SFX/tmp-flock-control "rc=0" "$rp_tmplock" if [ -n "$rp_writable" ]; then rp_runlock=$( flock -n 9 2>&1 9>/run/bst-rcprobe/lock ; echo "rc=$?" ) else rp_runlock="rc=skipped (/run not writable)" fi # rename(2) within the directory, which is the OTHER thing every state-changing # resolvconf command needs: both bin/resolvconf and update.d/libc write a # `_new.$$` temporary beside the real file and `mv -f` it into place, so a # filesystem that takes the write and refuses the rename produces exactly a # missing resolv.conf and a non-zero exit. Probed on both filesystems for the # same reason the lock is: only the pair distinguishes "this filesystem" from # "this kernel". if [ -n "$rp_writable" ]; then printf 'x\n' > /run/bst-rcprobe/a 2>/dev/null rp_runmv=$( mv -f /run/bst-rcprobe/a /run/bst-rcprobe/b 2>&1 ; echo "rc=$?" ) else rp_runmv="rc=skipped (/run not writable)" fi printf 'x\n' > "$W/mv-a" 2>/dev/null rp_tmpmv=$( mv -f "$W/mv-a" "$W/mv-b" 2>&1 ; echo "rc=$?" ) check_eq resolvconf$RC_SFX/tmp-rename-control "rc=0" "$rp_tmpmv" if [ "$rp_runmv" = "rc=0" ]; then bst_ok resolvconf$RC_SFX/run-rename else bst_notok resolvconf$RC_SFX/run-rename "rename(2) within /run ($rp_runfs) failed: $rp_runmv -- every state-changing resolvconf command mv -f's a _new.\$\$ temporary into place, so this alone would account for the real-path arm. Same operation under \$TMPDIR: $rp_tmpmv" fi rm -rf /run/bst-rcprobe rp_saved="$W/realpath-saved" mkdir -p "$rp_saved" [ -e /run/resolvconf ] && cp -a /run/resolvconf "$rp_saved/run-resolvconf" 2>/dev/null [ -e /etc/resolv.conf ] && cp -a /etc/resolv.conf "$rp_saved/resolv.conf" 2>/dev/null resolvconf --enable-updates >/dev/null 2>&1 printf 'nameserver 10.0.0.1\nsearch rp.example\n' > "$W/rp.in" rp_out=$( resolvconf -a eth0.brintostest < "$W/rp.in" 2>&1 ); rp_rc=$? # The expectation is built from the SHIPPED head file rather than hardcoded, so # this asserts the ordering -- head, then nameservers, then search -- without # also pinning text that belongs to upstream. { cat /etc/resolvconf/resolv.conf.d/head 2>/dev/null printf 'nameserver 10.0.0.1\nsearch rp.example\n' ; } > "$W/rp.want" # When the arm does not produce the file, run the update hook once more DIRECTLY # so its own diagnostic is captured rather than inferred. resolvconf execs it # through run-parts, which reports only "exited with return code N" and swallows # the line that says why -- and that line is the whole of the attribution below. rp_why=$rp_out if ! cmp -s "$W/rp.want" /run/resolvconf$RC_SFX/resolv.conf 2>/dev/null; then rp_why="$rp_out $( cd /run/resolvconf$RC_SFX/interface 2>/dev/null && /etc/resolvconf/update.d/libc -a eth0.brintostest 2>&1 )" fi # brintos/linux#73 -- the kernel's restart park sentinel reaching userspace # through a glibc errno return path, so a redirection returns 513 and the shell # dies. Measured by the selftests README at 20/20 on the virtiofs root and 0/20 # from /tmp, which is exactly the split this suite sees: the temporary-root arm # above is under $TMPDIR and passes 131/131, and this arm is on /run, which this # image never mounts a tmpfs over. update.d/libc dies at its FIRST redirection to # an existing file -- `cat "$HEADFILE" >> "$TMPFILE"` -- which is also why only # this arm reaches it: the temporary root ships no resolv.conf.d/head, so that # line is never executed there. # # Matched on the platform's own words rather than on a bare exit status: a # resolvconf that failed for any OTHER reason must still be a red, and this # becomes a real assertion the day 73 lands, with no edit here. rp_is73= case "$rp_why" in *"errno return path"*|*"Unknown error 513"*|*"error 513"*) rp_is73=1 ;; esac if [ "$rp_rc" = 0 ] && cmp -s "$W/rp.want" /run/resolvconf$RC_SFX/resolv.conf 2>/dev/null; then bst_ok resolvconf$RC_SFX/realpath-add-rc bst_ok resolvconf$RC_SFX/realpath-generated-file elif [ -n "$rp_is73" ]; then bst_skip resolvconf$RC_SFX/realpath-add-rc "brintos/linux#73 on the $rp_rootfs root: $(_bst_1line "$(printf '%s\n' "$rp_why" | grep -m1 -E 'errno return path|error 513')")" bst_skip resolvconf$RC_SFX/realpath-generated-file "brintos/linux#73: update.d/libc dies at its first append to an existing file (cat \$HEADFILE >> \$TMPFILE) because /run is part of the $rp_rootfs root and this image mounts no tmpfs over it -- its /etc/inittab declares only a /tmp tmpfs and run-postinsts. The same scripts pass 131/131 under \$TMPDIR above, which is the whole difference" else bst_notok resolvconf$RC_SFX/realpath-add-rc "resolvconf -a at the real paths: rc=$rp_rc on $rp_runfs (flock -n under /run: $rp_runlock, rename: $rp_runmv) and NOT brintos/linux#73 -- $(_bst_1line "$(printf '%s\n' "$rp_why" | tail -1)")" bst_notok resolvconf$RC_SFX/realpath-generated-file "the real /run/resolvconf$RC_SFX/resolv.conf is not what the shipped head plus this record implies, for a reason that is not brintos/linux#73 -- got: $(_bst_1line "$(cat /run/resolvconf$RC_SFX/resolv.conf 2>&1)")" fi # -i is answered BEFORE resolvconf takes its lock or runs any update hook, so it # is the one real-path case that stands whether or not #73 bites: it proves the # record reached /run/resolvconf$RC_SFX/interface and that list-records read it back # through the shipped /etc/resolvconf/interface-order. rp_list=$( resolvconf -i 2>&1 ) check_eq resolvconf$RC_SFX/realpath-list "eth0.brintostest" "$rp_list" resolvconf -d eth0.brintostest >/dev/null 2>&1 check resolvconf$RC_SFX/realpath-delete test ! -e /run/resolvconf$RC_SFX/interface/eth0.brintostest resolvconf --disable-updates >/dev/null 2>&1 rm -rf /run/resolvconf [ -e "$rp_saved/run-resolvconf" ] && cp -a "$rp_saved/run-resolvconf" /run/resolvconf if [ -e "$rp_saved/resolv.conf" ]; then cp -a "$rp_saved/resolv.conf" /etc/resolv.conf else rm -f /etc/resolv.conf fi check resolvconf$RC_SFX/realpath-restored test ! -e /run/resolvconf$RC_SFX/interface/eth0.brintostest rm -rf "$W"