From 0e00b161c4be40f5edcf349228019c718fed879e Mon Sep 17 00:00:00 2001 From: Mathieu Benoit Date: Mon, 24 Aug 2026 00:29:13 -0400 Subject: [PATCH] [FIX] the chroot had no /dev/shm, and systemd links man pages too MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- patches/pkgbuild/systemd.sh | 15 ++++++++++++--- scripts/build-stage2.sh | 23 +++++++++++++++++++++-- 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/patches/pkgbuild/systemd.sh b/patches/pkgbuild/systemd.sh index 53d4f7c..0a09258 100755 --- a/patches/pkgbuild/systemd.sh +++ b/patches/pkgbuild/systemd.sh @@ -344,7 +344,16 @@ 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 - if re.match(r"^[ \t]*mv ", l): + # `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 @@ -359,8 +368,8 @@ 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 .*(share/man|\bman[0-9]\b)" PKGBUILD && { - echo "systemd: a man page move survived" >&2; exit 1; } +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 diff --git a/scripts/build-stage2.sh b/scripts/build-stage2.sh index 8d65d4a..985a2af 100755 --- a/scripts/build-stage2.sh +++ b/scripts/build-stage2.sh @@ -516,13 +516,32 @@ mount_chroot() { # /dev/pts is not optional: without it any build step that opens a pty -- # and gcc's testsuite driver does -- fails in a way that names the pty and # not the missing mount. - for m in proc sys dev dev/pts; do + for m in proc sys dev dev/pts dev/shm; do sudo mkdir -p "$ROOT/$m" done mountpoint -q "$ROOT/proc" || sudo mount -t proc proc "$ROOT/proc" mountpoint -q "$ROOT/sys" || sudo mount -t sysfs sys "$ROOT/sys" mountpoint -q "$ROOT/dev" || sudo mount --bind /dev "$ROOT/dev" mountpoint -q "$ROOT/dev/pts" || sudo mount -t devpts devpts "$ROOT/dev/pts" + # /dev/shm, for the same reason /dev/pts needs its own line: `mount --bind + # /dev` does NOT carry submounts, and both of these are separate mounts on + # the host. + # + # 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. Without the mount, sem_open returns + # ENOSYS and CPython reports it as the PLATFORM lacking the feature -- which + # reads like an s390x limitation and is a missing tmpfs. + # + # A tmpfs of its own rather than a bind: nothing here shares semaphores with + # anything outside the chroot. Mode 1777 because unprivileged builds write + # into it. + mountpoint -q "$ROOT/dev/shm" || + sudo mount -t tmpfs -o mode=1777,nosuid,nodev tmpfs "$ROOT/dev/shm" # Sources and PKGBUILDs, already fetched by stage 1. Bind-mounting them # means the chroot needs no network at all, which is worth having: this # host cannot reach dev.gnupg.org, and a build that silently re-fetches @@ -532,7 +551,7 @@ mount_chroot() { } umount_chroot() { - for m in repo2 build dev/pts dev sys proc; do + for m in repo2 build dev/shm dev/pts dev sys proc; do mountpoint -q "$ROOT/$m" && sudo umount -l "$ROOT/$m" done return 0