nss failed with ImportError: This platform lacks a functioning sem_open implementation. https://github.com/python/cpython/issues/48020 multiprocessing.Semaphore is built on POSIX named semaphores, which glibc implements as files under /dev/shm. The chroot had no such mount, sem_open returned ENOSYS, and CPython reported it as the PLATFORM lacking the feature -- which reads like an s390x limitation and is a missing tmpfs. `mount --bind /dev` does not carry submounts. That is why /dev/pts already had a line of its own, and /dev/shm was simply missing from the same list. Mounted as its own tmpfs, mode 1777, and added to the umount order ahead of /dev. systemd's man page hook listed mv and rm and missed ln, so package_systemd() got one step further and stopped on a symlink between two man pages where neither exists. Sixteenth instance, and the lesson is narrower than the last: the procedure said grep for the output PATHS, and the paths were found -- what was missed was a VERB. Seven moves and links now, up from five. --- FR --- nss échouait sur ImportError: This platform lacks a functioning sem_open implementation. https://github.com/python/cpython/issues/48020 multiprocessing.Semaphore repose sur les sémaphores nommés POSIX, que glibc implémente en fichiers sous /dev/shm. Le chroot n'avait pas ce montage, sem_open renvoyait ENOSYS, et CPython l'a rapporté comme une absence de la PLATEFORME — ce qui se lit comme une limite de s390x et n'est qu'un tmpfs manquant. `mount --bind /dev` ne porte pas les sous-montages. C'est pourquoi /dev/pts avait déjà sa ligne, et /dev/shm manquait simplement dans la même liste. Monté en tmpfs propre, mode 1777, et ajouté au démontage avant /dev. Le hook des pages de manuel de systemd listait mv et rm et oubliait ln : package_systemd() est allé un cran plus loin et s'est arrêté sur un lien entre deux pages dont aucune n'existe. Seizième occurrence, et la leçon est plus fine que la précédente : la procédure disait de chercher les CHEMINS de sortie, et les chemins étaient trouvés — ce qui manquait était un VERBE. Sept déplacements et liens désormais, contre cinq. Assisted-by: Claude Opus 5
379 lines
18 KiB
Bash
Executable file
379 lines
18 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
# systemd: four defaults Arch can hold and s390x cannot.
|
|
#
|
|
# None of them is a missing host package. Two are hard errors raised by meson
|
|
# because the PKGBUILD ASKS for something this architecture does not have; two
|
|
# are defaults computed from the BUILD MACHINE rather than the target. No
|
|
# amount of apt-get fixes any of them. The libraries systemd wants (libbpf,
|
|
# clang, libfdisk, libkmod, ...) ARE host packages and belong in
|
|
# install_host_deps, not here.
|
|
#
|
|
# Three of the four fail with a message that names something else entirely.
|
|
# Each section says which, because that is the part worth reading twice.
|
|
set -euo pipefail
|
|
|
|
# 1. -Dbootloader=enabled: systemd-boot is EFI, and s390x has no EFI.
|
|
#
|
|
# The message you get is NOT about EFI:
|
|
#
|
|
# systemd/meson.build:1638:19: ERROR: python3 is missing modules: elftools
|
|
#
|
|
# because meson.build:1638 asks for pyelftools with
|
|
# `required : get_option('bootloader')`, and the PKGBUILD set that to enabled.
|
|
#
|
|
# THE TRAP is that this reads like a missing host package, and
|
|
# `apt install python3-pyelftools` looks like the fix. It is not. It buys four
|
|
# lines, and then meson.build:1642 says what is really wrong:
|
|
#
|
|
# ERROR: Feature bootloader cannot be enabled: unsupported EFI arch or
|
|
# EFI support is disabled
|
|
#
|
|
# (verified by planting a stub elftools module on PYTHONPATH; without it the
|
|
# EFI message is unreachable, which is why nobody ever sees it first.)
|
|
#
|
|
# meson.build:1627 maps a cpu family to an EFI machine type name -- aa64, arm,
|
|
# loongarch32/64, riscv32/64, x64, ia32 -- and s390x is not in that table, so
|
|
# efi_arch is ''. -Defi is still true; the architecture simply has no EFI.
|
|
# IBM Z boots from an IPL record, there is no ESP for systemd-boot to write
|
|
# into, and no configuration invents one.
|
|
#
|
|
# The cost is the systemd-boot artefacts. bootctl itself is still built and
|
|
# installed -- checked in the install plan -- package_systemd() names neither,
|
|
# and the arch.conf/loader.conf/splash-arch.bmp it ships are `install`ed from
|
|
# $srcdir rather than built. Packaging is untouched. Disabling also drops the
|
|
# pyelftools requirement in the same line.
|
|
sed -i 's/-Dbootloader=enabled/-Dbootloader=disabled/' PKGBUILD
|
|
grep -q -- '-Dbootloader=disabled' PKGBUILD || {
|
|
echo "systemd: bootloader option not rewritten" >&2; exit 1; }
|
|
echo "systemd: bootloader disabled (s390x has no EFI machine type)"
|
|
|
|
# 2. -Dvmlinux-h=provided: the file Arch points at is an Arch file.
|
|
#
|
|
# src/bpf/meson.build: error('Path to provided vmlinux.h does not exist.')
|
|
#
|
|
# Arch's linux-headers ships /usr/src/linux/vmlinux.h, the path hard-coded in
|
|
# the PKGBUILD. Ubuntu's linux-headers-* ship no vmlinux.h anywhere. This
|
|
# failure only appears AFTER libbpf and clang are installed, because the whole
|
|
# block is skipped while BPF_FRAMEWORK is off -- fixing libbpf uncovers it.
|
|
#
|
|
# systemd's own fallback dumps the header out of the running kernel's BTF,
|
|
# which is what 'generated' selects:
|
|
#
|
|
# bpftool btf dump file /sys/kernel/btf/vmlinux format c
|
|
#
|
|
# Checked on this host: exit 0, 122471 lines, and enum lsm_integrity_type is
|
|
# there at line 15931, so restrict-fsaccess.bpf.c builds rather than being
|
|
# quietly dropped.
|
|
#
|
|
# THE TRAP is that 'auto' would NOT have done this for us. The auto branch
|
|
# generates only when `host_machine.cpu_family() in ['x86_64', 'aarch64']`; on
|
|
# s390x it falls through to "neither provided nor generated" and silently
|
|
# drops the BPF programs that need the header. s390x has to say it out loud.
|
|
#
|
|
# Note the asymmetry this buys: on the 'provided' branch systemd probes the
|
|
# header with cc.compiles() before deciding what to build. On 'generated' it
|
|
# sets have_lsm_integrity_type = true outright. So the build now depends on
|
|
# the BTF of the kernel RUNNING when it starts -- fine on 6.17.0-41, and on an
|
|
# older kernel it turns into a compile error with no fallback.
|
|
#
|
|
# -Dvmlinux-h-path goes with it: 'generated' ignores the value, and leaving a
|
|
# path that resolves to nothing invites the next reader to "repair" it.
|
|
sed -i 's/-Dvmlinux-h=provided/-Dvmlinux-h=generated/' PKGBUILD
|
|
sed -i '/-Dvmlinux-h-path=/d' PKGBUILD
|
|
grep -q -- '-Dvmlinux-h=generated' PKGBUILD || {
|
|
echo "systemd: vmlinux.h still read from a provided path" >&2; exit 1; }
|
|
grep -q -- '-Dvmlinux-h-path' PKGBUILD && {
|
|
echo "systemd: stale vmlinux-h-path left in place" >&2; exit 1; }
|
|
echo "systemd: vmlinux.h generated from /sys/kernel/btf/vmlinux"
|
|
|
|
# 3. -Dsplit-bin=auto: the question is answered by the HOST, not the target.
|
|
#
|
|
# systemd/meson.build:123
|
|
# sbindir = prefixdir / (split_bin ? 'sbin' : 'bin')
|
|
#
|
|
# split-bin is a combo defaulting to 'auto', and 'auto' probes whether
|
|
# /usr/sbin on the BUILD MACHINE is a symlink to bin. On Arch it is, so
|
|
# split_bin is false and everything lands in /usr/bin. Here /usr/sbin is a
|
|
# real directory, and meson-log.txt says so:
|
|
#
|
|
# split bin-sbin : true
|
|
#
|
|
# THE TRAP is that arch-meson ALREADY passes --sbindir bin, and
|
|
# `meson configure` dutifully reports sbindir = bin. It is ignored: systemd
|
|
# computes its own sbindir from split_bin and never reads meson's builtin. The
|
|
# option that looks like the fix is not the fix, and the one that is mentions
|
|
# neither sbin nor a directory in its name.
|
|
#
|
|
# Nothing fails in build(). It fails much later, in package_systemd(), on the
|
|
# first line that names a path:
|
|
#
|
|
# rm: cannot remove '<pkgdir>/usr/bin/halt': No such file or directory
|
|
#
|
|
# because halt, init, poweroff, reboot, shutdown and resolvconf all went to
|
|
# /usr/sbin -- along with mount.ddi, mount.mstack and mount.storage, which the
|
|
# PKGBUILD never mentions at all. The rm is only the first victim. Suppress it
|
|
# and the package ships /usr/sbin as a DIRECTORY, which collides on the target
|
|
# with the ["usr/sbin"]="bin" SYMLINK our own filesystem package declares.
|
|
#
|
|
# Measured on a configured copy: with split-bin=false there is no /usr/sbin in
|
|
# the install tree at all, and all six paths are where package() looks.
|
|
#
|
|
# Same species as arch-meson's --libdir -- an Ubuntu default standing in for
|
|
# an Arch one -- but it cannot live in arch-meson: split-bin is systemd's own
|
|
# option, not a meson builtin. --auto-features does not reach it either; it is
|
|
# a combo, not a feature.
|
|
test "$(grep -c -- '-Dcompat-sysv-interfaces=false' PKGBUILD)" -eq 1 || {
|
|
echo "systemd: expected exactly one _meson_options array" >&2; exit 1; }
|
|
test "$(grep -c -- '-Dsplit-bin' PKGBUILD)" -eq 0 || {
|
|
echo "systemd: PKGBUILD already sets split-bin, re-read it" >&2; exit 1; }
|
|
sed -i 's/^\( *\)-Dcompat-sysv-interfaces=false/\1-Dsplit-bin=false\n\1-Dcompat-sysv-interfaces=false/' PKGBUILD
|
|
grep -q -- '-Dsplit-bin=false' PKGBUILD || {
|
|
echo "systemd: split-bin still auto (would install into /usr/sbin)" >&2; exit 1; }
|
|
echo "systemd: split-bin=false (Ubuntu's /usr/sbin is not Arch's)"
|
|
|
|
# 4. -Dukify=auto: the tool cannot run on this architecture at all.
|
|
#
|
|
# ukify assembles a Unified Kernel Image, and a UKI is a PE binary -- ukify.py
|
|
# imports pefile at module level and drives it directly (pefile.PE,
|
|
# SectionStructure, IMAGE_SCN_*). It is EFI tooling, so the same reasoning as
|
|
# section 1 applies. But it is stronger than "pointless on Z", and the source
|
|
# says so out loud:
|
|
#
|
|
# EFI_ARCH_MAP = {
|
|
# 'x86_64': ['x64','ia32'], 'i[3456]86': ['ia32'], 'aarch64': ['aa64'],
|
|
# 'armv[45678]*l': ['arm'], 'loongarch32': ..., 'riscv64': ...
|
|
# }
|
|
#
|
|
# def guess_efi_arch() -> str:
|
|
# ...
|
|
# else:
|
|
# raise ValueError(f'Unsupported architecture {arch}')
|
|
#
|
|
# s390x is not in that table, so ukify RAISES on this machine. Shipping it
|
|
# would put a program in the repository that cannot start.
|
|
#
|
|
# THE TRAP is that ukify does not announce itself as EFI-only anywhere the
|
|
# build stops. meson_options.txt:560 declares it a plain feature with no
|
|
# value -- 'auto' -- and meson.build:1659 is get_option('ukify').allowed(),
|
|
# which is true for 'auto'. So it is on by default, and what it broke was
|
|
# nowhere near ukify:
|
|
#
|
|
# FAILED: src/boot/test-hwids-section.c
|
|
# ModuleNotFoundError: No module named 'pefile'
|
|
#
|
|
# That looked like a missing host package, and `apt install python3-pefile`
|
|
# made it build. It was the wrong fix: the target at src/boot/meson.build:31
|
|
# is gated on ENABLE_UKIFY, not on ENABLE_BOOTLOADER, which is why disabling
|
|
# systemd-boot did not reach it. Disabling ukify does, and python3-pefile is
|
|
# then unnecessary -- nothing else in the tree needs it, since the only other
|
|
# importer, tools/check-efi-alignment.py, is reached from
|
|
# src/boot/meson.build:495, far below the ENABLE_BOOTLOADER subdir_done()
|
|
# guard.
|
|
#
|
|
# systemd-tests goes with it, for a different reason. It is a test suite --
|
|
# stage 1 runs --nocheck -- and it is the sole reason five python packages
|
|
# (colorama, packaging, pexpect, psutil, pytest) would enter the closure.
|
|
# Deferred, not architectural: TODO.md records it.
|
|
#
|
|
# The two subpackages leave in three places, and the pkgname array is the
|
|
# awkward one: its LAST entry carries the closing paren, so deleting a line
|
|
# would delete the ')' with it. The array is rebuilt rather than edited.
|
|
python3 - <<'PY'
|
|
import io, re
|
|
s = io.open("PKGBUILD", encoding="utf-8").read()
|
|
|
|
# (a) the option, next to the other EFI one so they read together
|
|
anchor = " -Dbootloader=disabled\n"
|
|
assert s.count(anchor) == 1, "expected section 1 to have set bootloader=disabled"
|
|
s = s.replace(anchor, anchor + " -Dukify=disabled\n", 1)
|
|
|
|
# (b) the pkgname array, rebuilt to keep its syntax intact
|
|
m = re.search(r"pkgname=\((.*?)\)\n", s, re.S)
|
|
assert m, "pkgname array not found"
|
|
names = re.findall(r"'([^']+)'", m.group(1))
|
|
drop = {"systemd-ukify", "systemd-tests"}
|
|
assert drop <= set(names), "expected both subpackages in pkgname, found %s" % names
|
|
kept = [n for n in names if n not in drop]
|
|
s = s[:m.start()] + "pkgname=(" + ("\n" + " " * 9).join("'%s'" % n for n in kept) + ")\n" + s[m.end():]
|
|
|
|
# (c) package_systemd() moves four ukify paths out. With ukify disabled none
|
|
# of them exists, and mv fails -- after a successful compile, which is the
|
|
# expensive way to find out.
|
|
blk = re.search(
|
|
r"\n # ukify shipped in separate package\n"
|
|
r"(?:.*\n)*?"
|
|
r" mv \"\$pkgdir\"/usr/lib/kernel/install\.d/60-ukify\.install systemd-ukify/install\.d\n",
|
|
s)
|
|
assert blk, "ukify mv block not found"
|
|
s = s[:blk.start()] + "\n" + s[blk.end():]
|
|
|
|
# (d) an optdepends on a package we no longer produce
|
|
s = re.sub(r"^.*'systemd-ukify: .*\n", "", s, flags=re.M)
|
|
|
|
io.open("PKGBUILD", "w", encoding="utf-8").write(s)
|
|
PY
|
|
# The guard checks what MATTERS, which is not "no mention of ukify remains".
|
|
# package_systemd-ukify() still sits in the file and still names four paths --
|
|
# harmless, because makepkg never calls a function whose name is absent from
|
|
# pkgname, exactly as with package_libquadmath() in gcc.sh. Counting mentions
|
|
# instead of checking the two real conditions made this hook exit 1 on a
|
|
# correctly patched PKGBUILD, and build_package reads that as a failed
|
|
# package: systemd would have been skipped entirely, with every edit applied.
|
|
grep -q -- '-Dukify=disabled' PKGBUILD || {
|
|
echo "systemd: ukify still enabled" >&2; exit 1; }
|
|
grep -q '# ukify shipped in separate package' PKGBUILD && {
|
|
echo "systemd: package_systemd() still moves ukify paths that cannot exist" >&2
|
|
exit 1; }
|
|
python3 - <<'PYGUARD'
|
|
import io, re, sys
|
|
s = io.open("PKGBUILD", encoding="utf-8").read()
|
|
m = re.search(r"pkgname=\((.*?)\)\n", s, re.S)
|
|
if not m:
|
|
sys.exit("systemd: pkgname array unreadable after patching")
|
|
names = re.findall(r"'([^']+)'", m.group(1))
|
|
left = sorted({"systemd-ukify", "systemd-tests"} & set(names))
|
|
if left:
|
|
sys.exit("systemd: still declared in pkgname: %s" % left)
|
|
print("systemd: pkgname -> %s" % " ".join(names))
|
|
PYGUARD
|
|
echo "systemd: ukify disabled (guess_efi_arch raises on s390x), tests dropped"
|
|
|
|
# --- no BPF framework ---------------------------------------------------------
|
|
#
|
|
# meson.build:1052:9: ERROR: Dependency "libbpf" not found (tried pkgconfig)
|
|
#
|
|
# libbpf is not in this port's package list, and adding it is not a small step:
|
|
# systemd's BPF programs are compiled with clang and llvm, so the dependency is
|
|
# an entire second compiler toolchain for a feature that only matters to
|
|
# systemd's own resource-control and socket-binding units.
|
|
#
|
|
# -Dbpf-framework=disabled is systemd's own switch for building without it,
|
|
# which is what every distribution that does not ship BPF-based unit features
|
|
# uses. Revisit if something on the target actually needs IPAddressAllow= or
|
|
# RestrictNetworkInterfaces=.
|
|
set -euo pipefail
|
|
python3 - <<'ZZPY'
|
|
import io
|
|
s = io.open("PKGBUILD", encoding="utf-8").read()
|
|
old = "-Dbpf-framework=enabled"
|
|
assert s.count(old) == 1, "systemd: expected one bpf-framework option, got %d" % s.count(old)
|
|
s = s.replace(old, "-Dbpf-framework=disabled", 1)
|
|
io.open("PKGBUILD", "w", encoding="utf-8").write(s)
|
|
ZZPY
|
|
grep -q -- "-Dbpf-framework=disabled" PKGBUILD || {
|
|
echo "systemd: bpf-framework was not disabled" >&2; exit 1; }
|
|
echo "systemd: BPF framework disabled (no libbpf, no clang)"
|
|
|
|
# --- no AppArmor ---------------------------------------------------------------
|
|
#
|
|
# meson.build:1098:14: ERROR: Dependency "libapparmor" not found (tried pkgconfig)
|
|
#
|
|
# The second dependency systemd asked for that this port does not package, after
|
|
# libbpf. AppArmor is a Debian/Ubuntu security module; Arch ships it but nothing
|
|
# in this bootstrap uses it, and systemd's support for it is a set of unit
|
|
# directives (AppArmorProfile=) rather than anything the system needs to boot.
|
|
#
|
|
# -Dapparmor=disabled is systemd's own switch. Revisit if the target ever runs
|
|
# an AppArmor policy.
|
|
set -euo pipefail
|
|
python3 - <<'ZZPY'
|
|
import io
|
|
s = io.open("PKGBUILD", encoding="utf-8").read()
|
|
old = "-Dapparmor=enabled"
|
|
assert s.count(old) == 1, "systemd: expected one apparmor option, got %d" % s.count(old)
|
|
s = s.replace(old, "-Dapparmor=disabled", 1)
|
|
io.open("PKGBUILD", "w", encoding="utf-8").write(s)
|
|
ZZPY
|
|
grep -q -- "-Dapparmor=disabled" PKGBUILD || { echo "systemd: apparmor not disabled" >&2; exit 1; }
|
|
echo "systemd: AppArmor disabled"
|
|
|
|
# --- no man pages -------------------------------------------------------------
|
|
#
|
|
# compilation error: file ../systemd/man/custom-man.xsl line 12 element import
|
|
#
|
|
# An XSLT import that cannot resolve: systemd renders its man pages from DocBook,
|
|
# and the stylesheets its own custom-man.xsl imports are not installed. xsltproc
|
|
# exists -- our libxslt supplies it -- so this is the FOURTH package to stop on
|
|
# missing DocBook DATA rather than a missing tool, after pam, shadow and p11-kit.
|
|
#
|
|
# systemd has by far the largest man page set of any package here, which is the
|
|
# strongest argument in the port for shipping docbook-xsl eventually. Not now.
|
|
set -euo pipefail
|
|
python3 - <<'ZZPY'
|
|
import io
|
|
s = io.open("PKGBUILD", encoding="utf-8").read()
|
|
old = "-Dman=enabled"
|
|
assert s.count(old) == 1, "systemd: expected one man option, got %d" % s.count(old)
|
|
s = s.replace(old, "-Dman=disabled", 1)
|
|
io.open("PKGBUILD", "w", encoding="utf-8").write(s)
|
|
ZZPY
|
|
grep -q -- "-Dman=disabled" PKGBUILD || { echo "systemd: man not disabled" >&2; exit 1; }
|
|
echo "systemd: man pages disabled (DocBook stylesheets absent, not xsltproc)"
|
|
|
|
# --- and every man page operation in package() --------------------------------
|
|
#
|
|
# mv: cannot stat '<pkgdir>/usr/share/man/man3': No such file or directory
|
|
#
|
|
# FIFTEENTH time, and the first where the whole class was handled at once instead
|
|
# of one path per pass. -Dman=disabled means NO man pages exist, and package()
|
|
# touches them six times:
|
|
#
|
|
# mv .../man/man3 systemd-libs/man3
|
|
# mv .../man/man8/*nss* systemd-libs/man8/
|
|
# mv .../man/man1/ukify.1 systemd-ukify/man1/
|
|
# rm .../man/man1/init.1
|
|
# rm .../man/man8/{halt,poweroff,reboot,shutdown}.8
|
|
# rm .../usr/{bin/resolvconf,share/man/man1/resolvconf.1}
|
|
#
|
|
# Treated by KIND rather than by name:
|
|
#
|
|
# mv -- neutralised. These move pages into split packages, and with no pages
|
|
# there is nothing to move and the split simply has no man section.
|
|
# rm -- made tolerant with -f. These delete pages Arch does not want shipped,
|
|
# and that intent still holds on a machine that HAS the DocBook stack.
|
|
# The last one also removes a binary, which must still go.
|
|
#
|
|
# This is the procedure written in jsoncpp's hook, applied before the failures
|
|
# arrive rather than after: grep package() for the output paths, not the tool.
|
|
set -euo pipefail
|
|
python3 - <<'ZZPY'
|
|
import io, re
|
|
lines = io.open("PKGBUILD", encoding="utf-8").read().split("\n")
|
|
mv_n = rm_n = 0
|
|
for i in range(len(lines) - 1, -1, -1):
|
|
l = lines[i]
|
|
if "share/man" not in l and not re.search(r"\bman[0-9]\b", l):
|
|
continue
|
|
# `ln` as well as `mv`. The first version listed mv and rm and missed it, so
|
|
# package_systemd() got one step further and stopped on
|
|
#
|
|
# ln: failed to create symbolic link '.../man/man8/...'
|
|
#
|
|
# a symlink between two man pages where neither exists. Sixteenth instance of
|
|
# this shape, and the lesson is narrower than the last: the procedure said
|
|
# grep for the output PATHS, and the paths were found -- what was missed was
|
|
# a VERB.
|
|
if re.match(r"^[ \t]*(mv|ln) ", l):
|
|
j = i
|
|
while lines[j].rstrip().endswith("\\"):
|
|
j += 1
|
|
ind = re.match(r"^[ \t]*", l).group(0)
|
|
lines[i:j + 1] = [ind + ": # no man pages are built: -Dman=disabled above."]
|
|
mv_n += 1
|
|
elif re.match(r"^[ \t]*rm ", l) and not re.match(r"^[ \t]*rm -[a-z]*f", l):
|
|
lines[i] = re.sub(r"^([ \t]*)rm ", r"\1rm -f ", l)
|
|
rm_n += 1
|
|
assert mv_n >= 1, "systemd: no man page moves found"
|
|
assert rm_n >= 1, "systemd: no man page removals found"
|
|
io.open("PKGBUILD", "w", encoding="utf-8").write("\n".join(lines))
|
|
print(" %d move(s) neutralised, %d removal(s) made tolerant" % (mv_n, rm_n))
|
|
ZZPY
|
|
grep -qE "^[[:space:]]*(mv|ln) .*(share/man|\bman[0-9]\b)" PKGBUILD && {
|
|
echo "systemd: a man page move or link survived" >&2; exit 1; }
|
|
# Scoped to man paths. The first version of this guard matched any `rm` without
|
|
# a dash and condemned correct code -- systemd's package() removes plenty of
|
|
# things that have nothing to do with documentation. Same mistake as the blanket
|
|
# `grep tcl8.6` in sqlite's hook: a check must ask about what it changed.
|
|
grep -qE "^[[:space:]]*rm [^-].*(share/man|\bman[0-9]\b)" PKGBUILD && {
|
|
echo "systemd: an intolerant rm of a man path survived" >&2; exit 1; }
|
|
echo "systemd: all man page operations handled"
|