diff --git a/bin/samba4-netbsd4be/smbd b/bin/samba4-netbsd4be/smbd index ea4b086c..15ad813d 100755 Binary files a/bin/samba4-netbsd4be/smbd and b/bin/samba4-netbsd4be/smbd differ diff --git a/bin/samba4-netbsd4le/smbd b/bin/samba4-netbsd4le/smbd index 06ac36cd..2df5dfe2 100755 Binary files a/bin/samba4-netbsd4le/smbd and b/bin/samba4-netbsd4le/smbd differ diff --git a/bin/samba4/smbd b/bin/samba4/smbd index ebf76f1f..2c3ce01c 100755 Binary files a/bin/samba4/smbd and b/bin/samba4/smbd differ diff --git a/build/.env.example b/build/.env.example index e96a82a7..37f6b53d 100644 --- a/build/.env.example +++ b/build/.env.example @@ -14,6 +14,15 @@ # ./build/downloadsamba4oldbe.sh -> SDK_FAMILY=netbsd4, DEVICE_FAMILY=old, SAMBA_FAMILY=samba4, NETBSD4_ABI=be # ./build/samba4oldle.sh -> SDK_FAMILY=netbsd4, DEVICE_FAMILY=old, SAMBA_FAMILY=samba4, NETBSD4_ABI=le # ./build/samba4oldbe.sh -> SDK_FAMILY=netbsd4, DEVICE_FAMILY=old, SAMBA_FAMILY=samba4, NETBSD4_ABI=be +# ./build/downloadsamba4x.sh -> SDK_FAMILY=netbsd7, DEVICE_FAMILY=new, SAMBA_FAMILY=samba4x +# ./build/samba4x.sh -> SDK_FAMILY=netbsd7, DEVICE_FAMILY=new, SAMBA_FAMILY=samba4x +# ./build/downloadsamba4xoldle.sh -> SDK_FAMILY=netbsd4, DEVICE_FAMILY=old, SAMBA_FAMILY=samba4x, NETBSD4_ABI=le +# ./build/downloadsamba4xoldbe.sh -> SDK_FAMILY=netbsd4, DEVICE_FAMILY=old, SAMBA_FAMILY=samba4x, NETBSD4_ABI=be +# ./build/samba4xoldle.sh -> SDK_FAMILY=netbsd4, DEVICE_FAMILY=old, SAMBA_FAMILY=samba4x, NETBSD4_ABI=le +# ./build/samba4xoldbe.sh -> SDK_FAMILY=netbsd4, DEVICE_FAMILY=old, SAMBA_FAMILY=samba4x, NETBSD4_ABI=be +# ./build/generate-samba4x-cross-answers.sh -> SDK_FAMILY=netbsd7, DEVICE_FAMILY=new, SAMBA_FAMILY=samba4x +# ./build/generate-samba4x-cross-answers-oldle.sh -> SDK_FAMILY=netbsd4, DEVICE_FAMILY=old, SAMBA_FAMILY=samba4x, NETBSD4_ABI=le +# ./build/generate-samba4x-cross-answers-oldbe.sh -> SDK_FAMILY=netbsd4, DEVICE_FAMILY=old, SAMBA_FAMILY=samba4x, NETBSD4_ABI=be # NetBSD SDK roots on the VM NETBSD4LE_ROOT='/root/netbsd4' @@ -71,6 +80,12 @@ SAMBA4_NETBSD4BE_BUILD='/root/tc-samba4-netbsd4be/build' SAMBA4_NETBSD4BE_DOWNLOAD_LOG='/root/tc-armeb-netbsd4/downloadsamba4old.log' SAMBA4_NETBSD4BE_LOG='/root/tc-armeb-netbsd4/samba4old.log' +# Samba 4.x lanes +SAMBA4X_VERSION='4.24.1' +SAMBA4X_GIT_URL='https://github.com/samba-team/samba.git' +SAMBA4X_GIT_REF='samba-4.24.1' +SAMBA4X_JOBS='2' + # mDNS / NBNS helper outputs MDNS_STAGE_NETBSD7='/root/tc-netbsd7' NBNS_STAGE_NETBSD7='/root/tc-netbsd7' @@ -86,6 +101,18 @@ SAMBA4_CROSS_EXEC_TMP_NETBSD7='/tmp/tc-samba-probes-netbsd7' SAMBA4_CROSS_EXEC_TMP_NETBSD4LE='/mnt/Memory/tc-samba-probes-netbsd4le' SAMBA4_CROSS_EXEC_TMP_NETBSD4BE='/mnt/Memory/tc-samba-probes-netbsd4be' +# Samba 4.x builds use checked-in Waf cross-answer files by default and never +# SSH to a Time Capsule during normal configure. Set SAMBA4X_CROSS_ANSWERS to +# use a custom offline answers file. Run the generate-samba4x-cross-answers*.sh +# helpers only when a matching live target is reachable and you intentionally +# want Waf plus generation-only validation probes to refresh the checked-in +# answer file. SAMBA4X_REFRESH_CROSS_ANSWERS=1 remains as a legacy alias for +# that explicit generation mode; leave it at 0 for normal builds. +SAMBA4X_REFRESH_CROSS_ANSWERS='0' +SAMBA4X_CROSS_EXEC_TMP_NETBSD7='/tmp/tc-samba4x-probes-netbsd7' +SAMBA4X_CROSS_EXEC_TMP_NETBSD4LE='/mnt/Memory/tc-samba4x-probes-netbsd4le' +SAMBA4X_CROSS_EXEC_TMP_NETBSD4BE='/mnt/Memory/tc-samba4x-probes-netbsd4be' + # NetBSD 7 / NetBSD 6-generation Time Capsule connection TC_NETBSD7_HOST='root@192.168.1.217' TC_NETBSD7_SSH_OPTS='-o HostKeyAlgorithms=+ssh-rsa -o PubkeyAcceptedAlgorithms=+ssh-rsa -o KexAlgorithms=+diffie-hellman-group14-sha1' diff --git a/build/_samba4x.sh b/build/_samba4x.sh index 0fe26a7f..76ccd207 100755 --- a/build/_samba4x.sh +++ b/build/_samba4x.sh @@ -1,10 +1,12 @@ #!/bin/sh set -eu -. "$(dirname "$0")/env.sh" -. "$(dirname "$0")/_patch_helpers.sh" +SAMBA4X_SCRIPT_DIR="$(CDPATH= cd "$(dirname "$0")" && pwd)" -GNUTLS_PATCH_DIR="$(CDPATH= cd "$(dirname "$0")/patches/gnutls" && pwd)" +. "$SAMBA4X_SCRIPT_DIR/env.sh" +. "$SAMBA4X_SCRIPT_DIR/_patch_helpers.sh" + +GNUTLS_PATCH_DIR="$SAMBA4X_SCRIPT_DIR/patches/gnutls" TOOLDIR="$TOOLS" DESTDIR="$OBJ/destdir.evbarm" TRIPLE="$(select_tool_triple)" @@ -324,10 +326,305 @@ verify_samba4x_runtime_config() { require_config_symbol_defined "$config_header" "HAVE_IFACE_IFCONF" } +samba4x_cross_answer_lane() { + case "$SDK_FAMILY:$NETBSD4_ABI" in + netbsd7:*) + printf '%s\n' "netbsd7" + ;; + netbsd4:le) + printf '%s\n' "netbsd4le" + ;; + netbsd4:be) + printf '%s\n' "netbsd4be" + ;; + *) + echo "Unsupported Samba 4.x cross-answer lane: $SDK_FAMILY / $NETBSD4_ABI" >&2 + return 1 + ;; + esac +} + +samba4x_abs_path() { + path="$1" + case "$path" in + /*) + printf '%s\n' "$path" + ;; + *) + printf '%s/%s\n' "$(pwd)" "$path" + ;; + esac +} + +samba4x_default_cross_answers_file() { + printf '%s/cross-answers/samba4x-%s-%s.answers\n' "$SAMBA4X_SCRIPT_DIR" "$SAMBA4X_VERSION" "$SAMBA4X_CROSS_ANSWER_LANE" +} + +samba4x_generated_cross_answers_file() { + output_dir="${SAMBA4X_GENERATED_CROSS_ANSWERS_DIR:-$SAMBA4X_SCRIPT_DIR/cross-answers}" + printf '%s/samba4x-%s-%s.answers\n' "$output_dir" "$SAMBA4X_VERSION" "$SAMBA4X_CROSS_ANSWER_LANE" +} + +samba4x_answer_value() { + answers_file="$1" + answer_key="$2" + "$PYTHON3_BIN" - "$answers_file" "$answer_key" <<'PY' +import sys + +path, wanted = sys.argv[1], sys.argv[2] +value = None +with open(path, encoding="utf-8") as fh: + for raw in fh: + line = raw.strip() + if not line or line.startswith("#") or ":" not in line: + continue + key, val = line.rsplit(":", 1) + if key.rstrip() == wanted: + value = val.strip() +if value is None: + sys.exit(1) +print(value) +PY +} + +preflight_samba4x_cross_answers() { + answers_file="$1" + + if [ ! -f "$answers_file" ]; then + echo "Missing Samba 4.x cross-answers file: $answers_file" + echo "Set SAMBA4X_CROSS_ANSWERS to a complete answers file or add the default lane file under build/cross-answers." + exit 1 + fi + if [ ! -s "$answers_file" ]; then + echo "Samba 4.x cross-answers file is empty: $answers_file" + exit 1 + fi + if grep -E ':[[:space:]]*UNKNOWN([[:space:]]*$|[[:space:]]+#)' "$answers_file" >/dev/null 2>&1; then + echo "Samba 4.x cross-answers file contains UNKNOWN entries: $answers_file" + echo "Refresh or resolve those answers before running an offline build." + exit 1 + fi + duplicate_conflicts="$("$PYTHON3_BIN" - "$answers_file" <<'PY' +import sys + +seen = {} +conflicts = [] +with open(sys.argv[1], encoding="utf-8") as fh: + for raw in fh: + line = raw.strip() + if not line or line.startswith("#") or ":" not in line: + continue + key, value = line.rsplit(":", 1) + key = key.rstrip() + value = value.strip() + old = seen.get(key) + if old is not None and old != value: + conflicts.append(f"{key}: {old} != {value}") + seen[key] = value +print("\n".join(conflicts)) +PY +)" + if [ -n "$duplicate_conflicts" ]; then + echo "Samba 4.x cross-answers file contains conflicting duplicate answers: $answers_file" + printf '%s\n' "$duplicate_conflicts" + exit 1 + fi + if [ "$SDK_FAMILY" = "netbsd4" ]; then + realpath_answer="$(samba4x_answer_value "$answers_file" "Checking whether the realpath function allows a NULL argument" || true)" + if [ "$realpath_answer" = "OK" ]; then + echo "Samba 4.x NetBSD 4 cross-answers file incorrectly allows realpath(path, NULL): $answers_file" + echo "Regenerate this file with a matching live NetBSD 4 target before running an offline build." + exit 1 + fi + fi +} + +write_samba4x_cross_answer_seed() { + answers_file="$1" + lane="$2" + + case "$lane" in + netbsd7) + uname_release="6.0" + uname_version="NetBSD 6.0" + lane_description="NetBSD 6/7 Time Capsule" + ;; + netbsd4le) + uname_release="4.0" + uname_version="NetBSD 4.0" + lane_description="NetBSD 4 little-endian Time Capsule" + ;; + netbsd4be) + uname_release="4.0" + uname_version="NetBSD 4.0" + lane_description="NetBSD 4 big-endian Time Capsule" + ;; + *) + echo "Unsupported Samba 4.x cross-answer seed lane: $lane" >&2 + exit 1 + ;; + esac + + cat >"$answers_file" <"$probe_c" <<'EOF' +#include +#include +#include + +static void exit_on_signal(int ignored) +{ + (void)ignored; + _exit(2); +} + +int main(void) +{ + char *resolved; + signal(SIGSEGV, exit_on_signal); + signal(SIGBUS, exit_on_signal); + resolved = realpath("/tmp", NULL); + if (resolved == NULL) { + return 1; + } + free(resolved); + return 0; +} +EOF + + # Use the lane compiler command instead of raw $TRIPLE-gcc: NetBSD6/7 + # carries --sysroot in CC, and the validation probe must link exactly like + # the target configure tests it is checking. + # shellcheck disable=SC2086 + $CC $CPPFLAGS $CFLAGS $LDFLAGS "$probe_c" -o "$probe_bin" + if "$CROSS_EXECUTE" "$probe_bin" >/dev/null 2>&1; then + printf '%s\n' "OK" + else + printf '%s\n' "NO" + fi +} + +validate_generated_samba4x_cross_answers() { + answers_file="$1" + lane="$SAMBA4X_CROSS_ANSWER_LANE" + realpath_key="Checking whether the realpath function allows a NULL argument" + realpath_answer="$(samba4x_answer_value "$answers_file" "$realpath_key" || true)" + if [ -z "$realpath_answer" ]; then + echo "Generated Samba 4.x cross-answers file is missing: $realpath_key" + exit 1 + fi + + realpath_probe="$(samba4x_run_realpath_null_probe)" + if [ "$realpath_answer" != "$realpath_probe" ]; then + echo "Generated Samba 4.x cross-answer disagrees with independent realpath(path, NULL) probe." + echo "Waf answer: $realpath_answer" + echo "Independent probe: $realpath_probe" + exit 1 + fi + case "$lane:$realpath_answer" in + netbsd4le:NO|netbsd4be:NO|netbsd7:OK|netbsd7:NO) + ;; + netbsd4*:OK) + echo "Generated Samba 4.x NetBSD 4 answer incorrectly allows realpath(path, NULL)." + exit 1 + ;; + *) + echo "Unexpected realpath(path, NULL) answer for $lane: $realpath_answer" + exit 1 + ;; + esac +} + +install_generated_samba4x_cross_answers() { + source_file="$1" + output_file="$(samba4x_generated_cross_answers_file)" + lane="$SAMBA4X_CROSS_ANSWER_LANE" + mkdir -p "$(dirname "$output_file")" + + "$PYTHON3_BIN" - "$source_file" "$output_file" "$SAMBA4X_VERSION" "$lane" <<'PY' +import sys + +source, output, version, lane = sys.argv[1:5] +descriptions = { + "netbsd7": "NetBSD 6/7 Time Capsule", + "netbsd4le": "NetBSD 4 little-endian Time Capsule", + "netbsd4be": "NetBSD 4 big-endian Time Capsule", +} +description = descriptions[lane] +order = [] +values = {} +with open(source, encoding="utf-8") as fh: + for raw in fh: + line = raw.strip() + if not line or line.startswith("#") or ":" not in line: + continue + key, value = line.rsplit(":", 1) + key = key.rstrip() + value = value.strip() + if key in values: + order.remove(key) + order.append(key) + values[key] = value + +with open(output, "w", encoding="utf-8") as out: + out.write(f"# Samba {version} {description} cross-configure answers.\n") + out.write("# Generated with build/generate-samba4x-cross-answers*.sh from a matching live target.\n") + out.write("# Normal Samba4X builds consume this file offline and must not require device SSH.\n") + for key in order: + out.write(f"{key}: {values[key]}\n") +PY + preflight_samba4x_cross_answers "$output_file" + echo "Generated Samba 4.x cross-answers: $output_file" +} + +prepare_samba4x_cross_answers() { + lane="$SAMBA4X_CROSS_ANSWER_LANE" + default_answers="$(samba4x_default_cross_answers_file)" + if [ "$SAMBA4X_GENERATE_CROSS_ANSWERS" = "1" ]; then + active_answers="$SAMBA4X_BUILD/generated-samba4x-$SAMBA4X_VERSION-$lane.answers" + mkdir -p "$SAMBA4X_BUILD" + write_samba4x_cross_answer_seed "$active_answers" "$lane" + SAMBA4X_CROSS_ANSWERS_SOURCE="fresh generated seed" + SAMBA4X_ACTIVE_CROSS_ANSWERS="$active_answers" + export SAMBA4X_CROSS_ANSWERS_SOURCE SAMBA4X_ACTIVE_CROSS_ANSWERS + return 0 + fi + + source_answers="$(samba4x_abs_path "${SAMBA4X_CROSS_ANSWERS:-$default_answers}")" + active_answers="$SAMBA4X_BUILD/$(basename "$source_answers")" + + preflight_samba4x_cross_answers "$source_answers" + mkdir -p "$SAMBA4X_BUILD" + if [ "$source_answers" != "$active_answers" ]; then + cp "$source_answers" "$active_answers" + fi + preflight_samba4x_cross_answers "$active_answers" + + SAMBA4X_CROSS_ANSWERS_SOURCE="$source_answers" + SAMBA4X_ACTIVE_CROSS_ANSWERS="$active_answers" + export SAMBA4X_CROSS_ANSWERS_SOURCE SAMBA4X_ACTIVE_CROSS_ANSWERS +} + configure_samba4x() { + # Time Capsule smbd does not use filesystem quota integration, and Samba's + # optional quotactl runtime probe has a colon in its Waf message, which + # cannot be represented reliably in a colon-delimited cross-answers file. set -- \ --cross-compile \ - "--cross-execute=$CROSS_EXECUTE" \ + "--cross-answers=$SAMBA4X_ACTIVE_CROSS_ANSWERS" \ "--hostcc=$HOST_CC" \ "--prefix=$SAMBA4X_STAGE" \ --without-pie \ @@ -347,6 +644,7 @@ configure_samba4x() { --without-winbind \ --without-utmp \ --without-syslog \ + --without-quotas \ --nonshared-binary=smbd/smbd if [ -n "$SAMBA4X_STATIC_MODULES" ]; then @@ -355,6 +653,9 @@ configure_samba4x() { if [ "$SDK_FAMILY" = "netbsd4" ]; then set -- "$@" --disable-fault-handling --without-libarchive fi + if [ "$SAMBA4X_GENERATE_CROSS_ANSWERS" = "1" ]; then + set -- "$@" "--cross-execute=$CROSS_EXECUTE" + fi PYTHON="$PYTHON3_BIN" ./configure "$@" } @@ -691,9 +992,18 @@ export PKG_CONFIG_PATH="$SAMBA4X_DEPS/lib/pkgconfig" export PKG_CONFIG_LIBDIR="$SAMBA4X_DEPS/lib/pkgconfig" export PKG_CONFIG_SYSROOT_DIR= -CROSS_EXECUTE="$(cd "$(dirname "$0")" && pwd)/samba4-cross-exec.sh" +CROSS_EXECUTE="${SAMBA4X_CROSS_EXECUTE:-$SAMBA4X_SCRIPT_DIR/samba4-cross-exec.sh}" +SAMBA4X_REFRESH_CROSS_ANSWERS="${SAMBA4X_REFRESH_CROSS_ANSWERS:-0}" +SAMBA4X_GENERATE_CROSS_ANSWERS="${SAMBA4X_GENERATE_CROSS_ANSWERS:-0}" +if [ "$SAMBA4X_REFRESH_CROSS_ANSWERS" = "1" ]; then + SAMBA4X_GENERATE_CROSS_ANSWERS=1 +fi +SAMBA4X_CROSS_ANSWER_LANE="$(samba4x_cross_answer_lane)" || exit 1 +export SAMBA4X_CROSS_ANSWER_LANE SAMBA4X_STATIC_MODULES='vfs_catia,vfs_fruit,vfs_streams_xattr,vfs_xattr_tdb,vfs_acl_xattr' +mkdir -p "$(dirname "$SAMBA4X_LOG")" + { echo "SDK_FAMILY=$SDK_FAMILY" echo "DEVICE_FAMILY=$DEVICE_FAMILY" @@ -725,6 +1035,9 @@ SAMBA4X_STATIC_MODULES='vfs_catia,vfs_fruit,vfs_streams_xattr,vfs_xattr_tdb,vfs_ echo "PKG_CONFIG_LIBDIR=$PKG_CONFIG_LIBDIR" echo "CROSS_EXECUTE=$CROSS_EXECUTE" echo "CROSS_EXEC_REMOTE_DIR=$CROSS_EXEC_REMOTE_DIR" + echo "SAMBA4X_REFRESH_CROSS_ANSWERS=$SAMBA4X_REFRESH_CROSS_ANSWERS" + echo "SAMBA4X_GENERATE_CROSS_ANSWERS=$SAMBA4X_GENERATE_CROSS_ANSWERS" + echo "SAMBA4X_CROSS_ANSWER_LANE=$SAMBA4X_CROSS_ANSWER_LANE" if [ ! -f "$SAMBA4X_SRC_DIR/configure" ]; then echo "Missing Samba 4.x source tree at $SAMBA4X_SRC_DIR" @@ -739,12 +1052,20 @@ SAMBA4X_STATIC_MODULES='vfs_catia,vfs_fruit,vfs_streams_xattr,vfs_xattr_tdb,vfs_ echo "PYTHON3_BIN=$PYTHON3_BIN" prepare_samba4x_deps + prepare_samba4x_cross_answers + echo "SAMBA4X_CROSS_ANSWERS_SOURCE=$SAMBA4X_CROSS_ANSWERS_SOURCE" + echo "SAMBA4X_ACTIVE_CROSS_ANSWERS=$SAMBA4X_ACTIVE_CROSS_ANSWERS" mkdir -p "$SAMBA4X_BUILD" cd "$SAMBA4X_SRC_DIR" PYTHONHASHSEED=1 "$PYTHON3_BIN" ./buildtools/bin/waf distclean >/dev/null 2>&1 || true configure_samba4x + if [ "$SAMBA4X_GENERATE_CROSS_ANSWERS" = "1" ]; then + validate_generated_samba4x_cross_answers "$SAMBA4X_ACTIVE_CROSS_ANSWERS" + install_generated_samba4x_cross_answers "$SAMBA4X_ACTIVE_CROSS_ANSWERS" + exit 0 + fi for cache_file in "$SAMBA4X_SRC_DIR"/bin/c4che/*.py; do [ -f "$cache_file" ] || continue diff --git a/build/cross-answers/samba4x-4.24.1-netbsd4be.answers b/build/cross-answers/samba4x-4.24.1-netbsd4be.answers new file mode 100644 index 00000000..94f0b3b9 --- /dev/null +++ b/build/cross-answers/samba4x-4.24.1-netbsd4be.answers @@ -0,0 +1,33 @@ +# Samba 4.24.1 NetBSD 4 big-endian Time Capsule cross-configure answers. +# Generated with build/generate-samba4x-cross-answers*.sh from a matching live target. +# Normal Samba4X builds consume this file offline and must not require device SSH. +Checking uname sysname type: "NetBSD" +Checking uname machine type: "evbarm" +Checking uname release type: "4.0" +Checking uname version type: "NetBSD 4.0" +rpath library support: (2, "") +-Wl,--version-script support: (2, "") +Checking getconf LFS_CFLAGS: (127, "") +Checking for large file support without additional flags: OK +Checking correct behavior of strtoll: NO +Checking for working strptime: NO +Checking for C99 vsnprintf: "1" +Checking for HAVE_SHARED_MMAP: OK +Checking for HAVE_INCOHERENT_MMAP: NO +Checking for HAVE_SECURE_MKSTEMP: OK +Checking for gnutls fips mode support: NO +Checking value of NSIG: "64" +Checking value of _NSIG: "64" +Checking for a 64-bit host to support lmdb: NO +Checking errno of iconv for illegal multibyte sequence: (255, "") +Checking if can we convert from CP850 to UCS-2LE: (255, "") +Checking if can we convert from IBM850 to UCS-2LE: (255, "") +Checking if can we convert from UTF-8 to UCS-2LE: (255, "") +Checking if can we convert from UTF8 to UCS-2LE: (255, "") +Checking whether setreuid is available: "OK" +Checking whether fcntl locking is available: OK +Checking for the maximum value of the 'time_t' type: NO +Checking whether the realpath function allows a NULL argument: NO +Checking for ftruncate extend: OK +Checking for readlink breakage: NO +getcwd takes a NULL argument: OK diff --git a/build/cross-answers/samba4x-4.24.1-netbsd4le.answers b/build/cross-answers/samba4x-4.24.1-netbsd4le.answers new file mode 100644 index 00000000..b8901ce0 --- /dev/null +++ b/build/cross-answers/samba4x-4.24.1-netbsd4le.answers @@ -0,0 +1,33 @@ +# Samba 4.24.1 NetBSD 4 little-endian Time Capsule cross-configure answers. +# Generated with build/generate-samba4x-cross-answers*.sh from a matching live target. +# Normal Samba4X builds consume this file offline and must not require device SSH. +Checking uname sysname type: "NetBSD" +Checking uname machine type: "evbarm" +Checking uname release type: "4.0" +Checking uname version type: "NetBSD 4.0" +rpath library support: (2, "") +-Wl,--version-script support: (2, "") +Checking getconf LFS_CFLAGS: (127, "") +Checking for large file support without additional flags: OK +Checking correct behavior of strtoll: NO +Checking for working strptime: NO +Checking for C99 vsnprintf: "1" +Checking for HAVE_SHARED_MMAP: OK +Checking for HAVE_INCOHERENT_MMAP: NO +Checking for HAVE_SECURE_MKSTEMP: OK +Checking for gnutls fips mode support: NO +Checking value of NSIG: "64" +Checking value of _NSIG: "64" +Checking for a 64-bit host to support lmdb: NO +Checking errno of iconv for illegal multibyte sequence: (255, "") +Checking if can we convert from CP850 to UCS-2LE: (255, "") +Checking if can we convert from IBM850 to UCS-2LE: (255, "") +Checking if can we convert from UTF-8 to UCS-2LE: (255, "") +Checking if can we convert from UTF8 to UCS-2LE: (255, "") +Checking whether setreuid is available: "OK" +Checking whether fcntl locking is available: OK +Checking for the maximum value of the 'time_t' type: NO +Checking whether the realpath function allows a NULL argument: NO +Checking for ftruncate extend: OK +Checking for readlink breakage: NO +getcwd takes a NULL argument: OK diff --git a/build/cross-answers/samba4x-4.24.1-netbsd7.answers b/build/cross-answers/samba4x-4.24.1-netbsd7.answers new file mode 100644 index 00000000..a01b6ad1 --- /dev/null +++ b/build/cross-answers/samba4x-4.24.1-netbsd7.answers @@ -0,0 +1,33 @@ +# Samba 4.24.1 NetBSD 6/7 Time Capsule cross-configure answers. +# Generated with build/generate-samba4x-cross-answers*.sh from a matching live target. +# Normal Samba4X builds consume this file offline and must not require device SSH. +Checking uname sysname type: "NetBSD" +Checking uname machine type: "evbarm" +Checking uname release type: "6.0" +Checking uname version type: "NetBSD 6.0" +rpath library support: (127, "") +-Wl,--version-script support: (127, "") +Checking getconf LFS_CFLAGS: (127, "") +Checking for large file support without additional flags: OK +Checking correct behavior of strtoll: NO +Checking for working strptime: NO +Checking for C99 vsnprintf: "1" +Checking for HAVE_SHARED_MMAP: OK +Checking for HAVE_INCOHERENT_MMAP: NO +Checking for HAVE_SECURE_MKSTEMP: OK +Checking for gnutls fips mode support: NO +Checking value of NSIG: "64" +Checking value of _NSIG: "64" +Checking for a 64-bit host to support lmdb: NO +Checking errno of iconv for illegal multibyte sequence: (255, "") +Checking if can we convert from CP850 to UCS-2LE: (255, "") +Checking if can we convert from IBM850 to UCS-2LE: (255, "") +Checking if can we convert from UTF-8 to UCS-2LE: (255, "") +Checking if can we convert from UTF8 to UCS-2LE: (255, "") +Checking whether setreuid is available: "OK" +Checking whether fcntl locking is available: OK +Checking for the maximum value of the 'time_t' type: NO +Checking whether the realpath function allows a NULL argument: OK +Checking for ftruncate extend: OK +Checking for readlink breakage: NO +getcwd takes a NULL argument: OK diff --git a/build/generate-samba4x-cross-answers-oldbe.sh b/build/generate-samba4x-cross-answers-oldbe.sh new file mode 100755 index 00000000..3bf8a183 --- /dev/null +++ b/build/generate-samba4x-cross-answers-oldbe.sh @@ -0,0 +1,12 @@ +#!/bin/sh +set -eu + +SCRIPT_DIR="$(CDPATH= cd "$(dirname "$0")" && pwd)" + +export SDK_FAMILY=netbsd4 +export DEVICE_FAMILY=old +export SAMBA_FAMILY=samba4x +export NETBSD4_ABI=be +export SAMBA4X_GENERATE_CROSS_ANSWERS=1 + +exec "$SCRIPT_DIR/_samba4x.sh" "$@" diff --git a/build/generate-samba4x-cross-answers-oldle.sh b/build/generate-samba4x-cross-answers-oldle.sh new file mode 100755 index 00000000..a473325d --- /dev/null +++ b/build/generate-samba4x-cross-answers-oldle.sh @@ -0,0 +1,12 @@ +#!/bin/sh +set -eu + +SCRIPT_DIR="$(CDPATH= cd "$(dirname "$0")" && pwd)" + +export SDK_FAMILY=netbsd4 +export DEVICE_FAMILY=old +export SAMBA_FAMILY=samba4x +export NETBSD4_ABI=le +export SAMBA4X_GENERATE_CROSS_ANSWERS=1 + +exec "$SCRIPT_DIR/_samba4x.sh" "$@" diff --git a/build/generate-samba4x-cross-answers.sh b/build/generate-samba4x-cross-answers.sh new file mode 100755 index 00000000..5fcfddf9 --- /dev/null +++ b/build/generate-samba4x-cross-answers.sh @@ -0,0 +1,11 @@ +#!/bin/sh +set -eu + +SCRIPT_DIR="$(CDPATH= cd "$(dirname "$0")" && pwd)" + +export SDK_FAMILY=netbsd7 +export DEVICE_FAMILY=new +export SAMBA_FAMILY=samba4x +export SAMBA4X_GENERATE_CROSS_ANSWERS=1 + +exec "$SCRIPT_DIR/_samba4x.sh" "$@" diff --git a/src/timecapsulesmb/assets/artifact-manifest.json b/src/timecapsulesmb/assets/artifact-manifest.json index 717b0b24..fff59621 100644 --- a/src/timecapsulesmb/assets/artifact-manifest.json +++ b/src/timecapsulesmb/assets/artifact-manifest.json @@ -26,15 +26,15 @@ }, "smbd": { "path": "bin/samba4/smbd", - "sha256": "a5f4824a0bedfec506d9d9bcd1f4542cc058eba101d34319eb5e4c847687cdfc" + "sha256": "9d7862828abaa8c4780699fab452b64df1eaa1509035d80f01ba39226422a34f" }, "smbd-netbsd4le": { "path": "bin/samba4-netbsd4le/smbd", - "sha256": "deaeaa8eb10f29a12f251b1c2e5e054e4659535bc79a1a6ea19217b1238621ad" + "sha256": "873b81104496ef43ab8846fd3cfdc815cb15142962562b916cdd6be89e0764cb" }, "smbd-netbsd4be": { "path": "bin/samba4-netbsd4be/smbd", - "sha256": "8f70eb1a696c8a309274dfeb5f6a337e393399877541f355ef0d4aee3c889e1a" + "sha256": "b8ea930573e458a7a72e1397db7f50a97d08441008d53889491ce9c890e774f1" } } } diff --git a/tests/test_build_samba4x.py b/tests/test_build_samba4x.py new file mode 100644 index 00000000..30c6f129 --- /dev/null +++ b/tests/test_build_samba4x.py @@ -0,0 +1,498 @@ +from __future__ import annotations + +import os +import subprocess +import sys +import tempfile +import textwrap +import unittest +from pathlib import Path + + +REPO_ROOT = Path(__file__).resolve().parent.parent + + +class Samba4XBuildScriptTests(unittest.TestCase): + def make_executable(self, path: Path, text: str) -> None: + path.parent.mkdir(parents=True, exist_ok=True) + path.write_text(text) + path.chmod(0o755) + + def make_file(self, path: Path, content: str = "") -> None: + path.parent.mkdir(parents=True, exist_ok=True) + path.write_text(content) + + def make_fake_cross_execute(self, path: Path) -> None: + self.make_executable( + path, + textwrap.dedent( + """\ + #!/bin/sh + if [ -n "${TEST_CROSS_EXEC_ARGS:-}" ]; then + printf '%s\\n' "$@" >> "$TEST_CROSS_EXEC_ARGS" + fi + exit "${TEST_CROSS_EXEC_RC:-0}" + """ + ), + ) + + def prepare_fake_toolchain(self, out: Path, triple: str) -> None: + tools = out / "tools" / "bin" + tools.mkdir(parents=True, exist_ok=True) + self.make_executable(tools / "nbmake", "#!/bin/sh\nexit 0\n") + self.make_executable(tools / "nbfile", "#!/bin/sh\nprintf '%s: fake ELF\\n' \"$1\"\n") + self.make_executable( + tools / f"{triple}-gcc", + textwrap.dedent( + """\ + #!/bin/sh + out= + while [ "$#" -gt 0 ]; do + if [ "$1" = "-o" ]; then + shift + out="$1" + fi + shift || break + done + if [ -n "$out" ]; then + mkdir -p "$(dirname "$out")" + printf 'fake object\\n' >"$out" + fi + exit 0 + """ + ), + ) + self.make_executable(tools / f"{triple}-g++", "#!/bin/sh\nexit 0\n") + self.make_executable(tools / f"{triple}-cpp", "#!/bin/sh\nexit 0\n") + self.make_executable( + tools / f"{triple}-ld", + textwrap.dedent( + """\ + #!/bin/sh + if [ "${1:-}" = "--verbose" ]; then + printf '====\\nSECTIONS {\\n SIZEOF_HEADERS;\\n}\\n====\\n' + fi + exit 0 + """ + ), + ) + self.make_executable( + tools / f"{triple}-objdump", + textwrap.dedent( + """\ + #!/bin/sh + case "${1:-}" in + -h) + printf ' 1 .note.netbsd.ident 00000000\\n' + printf ' 2 .note.netbsd.pax 00000000\\n' + ;; + -p) + printf 'Program Header:\\n' + ;; + esac + exit 0 + """ + ), + ) + for name in ("ar", "ranlib", "readelf", "strip"): + self.make_executable(tools / f"{triple}-{name}", "#!/bin/sh\nexit 0\n") + + def prepare_fake_samba_source(self, src_dir: Path) -> None: + self.make_executable( + src_dir / "configure", + textwrap.dedent( + """\ + #!/bin/sh + : > "$TEST_CONFIGURE_ARGS" + cross_answers= + for arg in "$@"; do + printf '%s\\n' "$arg" >> "$TEST_CONFIGURE_ARGS" + case "$arg" in + --cross-answers=*) + cross_answers="${arg#--cross-answers=}" + ;; + esac + done + if [ -n "${TEST_SEED_CAPTURE:-}" ] && [ -n "$cross_answers" ]; then + cp "$cross_answers" "$TEST_SEED_CAPTURE" + fi + if [ "${TEST_CONFIGURE_WRITES_ANSWERS:-0}" = "1" ] && [ -n "$cross_answers" ]; then + printf '%s: %s\\n' \ + 'Checking whether the realpath function allows a NULL argument' \ + "${TEST_REALPATH_ANSWER:-OK}" >> "$cross_answers" + if [ -n "${TEST_DUPLICATE_REALPATH_ANSWER:-}" ]; then + printf '%s: %s\\n' \ + 'Checking whether the realpath function allows a NULL argument' \ + "$TEST_DUPLICATE_REALPATH_ANSWER" >> "$cross_answers" + fi + if [ -n "${TEST_EXTRA_GENERATED_ANSWER:-}" ]; then + printf '%s\\n' "$TEST_EXTRA_GENERATED_ANSWER" >> "$cross_answers" + fi + fi + mkdir -p bin/c4che bin/default/include bin/default/source3/include bin/default/source4/include + cat > bin/c4che/default.py <<'EOF' + ENABLE_PIE = True + LDFLAGS = [] + LINKFLAGS = [] + EOF + for header in bin/default/include/config.h bin/default/source3/include/config.h bin/default/source4/include/config.h; do + cat > "$header" <<'EOF' + /* #undef HAVE_IFACE_IFCONF */ + EOF + done + exit 0 + """ + ), + ) + self.make_executable( + src_dir / "buildtools" / "bin" / "waf", + textwrap.dedent( + """\ + import pathlib + import sys + + if "build" in sys.argv: + smbd = pathlib.Path("bin/default/source3/smbd/smbd") + smbd.parent.mkdir(parents=True, exist_ok=True) + smbd.write_text("fake smbd\\n") + sys.exit(0) + """ + ), + ) + + def prepare_fake_netbsd_inputs(self, root: Path, *, lane: str) -> dict[str, Path]: + out = root / f"out-{lane}" + build_src = root / f"netbsd-src-{lane}" + samba_src = root / f"samba-src-{lane}" + samba_build = root / f"samba-build-{lane}" + samba_stage = root / f"samba-stage-{lane}" + obj = out / "obj" + sysroot = obj / "destdir.evbarm" + + if lane == "netbsd4be": + triple = "armeb--netbsdelf" + gmp_arch = "armeb" + elif lane == "netbsd4le": + triple = "arm--netbsdelf" + gmp_arch = "arm" + else: + triple = "arm--netbsdelf" + gmp_arch = "earm" + + self.prepare_fake_toolchain(out, triple) + self.prepare_fake_samba_source(samba_src) + self.make_file(sysroot / "usr" / "include" / "zlib.h") + self.make_file(sysroot / "usr" / "lib" / "libz.a") + self.make_file(obj / "external" / "lgpl3" / "gmp" / "lib" / "libgmp" / "libgmp.a") + self.make_file(build_src / "external" / "lgpl3" / "gmp" / "lib" / "libgmp" / "arch" / gmp_arch / "gmp.h") + + deps = samba_build / "deps" + self.make_file(deps / ".stamp-nettle-3.10.1-system-gmp") + self.make_file(deps / "lib" / "libnettle.a") + self.make_file(deps / "lib" / "libhogweed.a") + self.make_file(deps / ".stamp-libtasn1-4.20.0") + self.make_file(deps / "lib" / "libtasn1.a") + self.make_file(deps / ".stamp-gnutls-3.8.5-system-nettle-oaep-no-thread-local") + self.make_file(deps / "lib" / "libgnutls.a") + self.make_file(deps / "lib" / "pkgconfig" / "gnutls.pc", "Libs: -L${libdir} -lgnutls\n") + + return { + "out": out, + "build_src": build_src, + "samba_src": samba_src, + "samba_build": samba_build, + "samba_stage": samba_stage, + } + + def env_for_lane(self, root: Path, lane: str, capture: Path) -> dict[str, str]: + paths = self.prepare_fake_netbsd_inputs(root, lane=lane) + env = os.environ.copy() + env.update( + { + "TC_ENV_FILE": "/dev/null", + "PYTHON3": sys.executable, + "TEST_CONFIGURE_ARGS": str(capture), + "BUILD_SRC": str(paths["build_src"]), + "BUILD_OUT": str(paths["out"]), + "SAMBA4X_NETBSD7_SRC_DIR": str(paths["samba_src"]), + "SAMBA4X_NETBSD7_WORK": str(root / "work-netbsd7"), + "SAMBA4X_NETBSD7_BUILD": str(paths["samba_build"]), + "SAMBA4X_NETBSD7_STAGE": str(paths["samba_stage"]), + "SAMBA4X_NETBSD7_LOG": str(root / "samba4x-netbsd7.log"), + "SAMBA4X_NETBSD4LE_SRC_DIR": str(paths["samba_src"]), + "SAMBA4X_NETBSD4LE_WORK": str(root / "work-netbsd4le"), + "SAMBA4X_NETBSD4LE_BUILD": str(paths["samba_build"]), + "SAMBA4X_NETBSD4LE_STAGE": str(paths["samba_stage"]), + "SAMBA4X_NETBSD4LE_LOG": str(root / "samba4x-netbsd4le.log"), + "SAMBA4X_NETBSD4BE_SRC_DIR": str(paths["samba_src"]), + "SAMBA4X_NETBSD4BE_WORK": str(root / "work-netbsd4be"), + "SAMBA4X_NETBSD4BE_BUILD": str(paths["samba_build"]), + "SAMBA4X_NETBSD4BE_STAGE": str(paths["samba_stage"]), + "SAMBA4X_NETBSD4BE_LOG": str(root / "samba4x-netbsd4be.log"), + } + ) + return env + + def run_wrapper(self, wrapper: str, env: dict[str, str]) -> subprocess.CompletedProcess[str]: + return subprocess.run( + ["/bin/sh", str(REPO_ROOT / "build" / wrapper)], + cwd=REPO_ROOT, + env=env, + text=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + check=False, + timeout=30, + ) + + def configure_args(self, capture: Path) -> list[str]: + return capture.read_text().splitlines() + + def cross_answer_arg(self, args: list[str]) -> str: + matches = [arg for arg in args if arg.startswith("--cross-answers=")] + self.assertEqual(len(matches), 1) + return matches[0] + + def cross_execute_args(self, args: list[str]) -> list[str]: + return [arg for arg in args if arg.startswith("--cross-execute=")] + + def test_default_build_uses_cross_answers_without_cross_execute(self) -> None: + with tempfile.TemporaryDirectory() as tmp: + root = Path(tmp) + capture = root / "configure-args.txt" + cross_exec_capture = root / "cross-exec-args.txt" + cross_exec = root / "cross-exec.sh" + self.make_fake_cross_execute(cross_exec) + env = self.env_for_lane(root, "netbsd7", capture) + env["SAMBA4X_CROSS_EXECUTE"] = str(cross_exec) + env["TEST_CROSS_EXEC_ARGS"] = str(cross_exec_capture) + + result = self.run_wrapper("samba4x.sh", env) + + self.assertEqual(result.returncode, 0, result.stdout + result.stderr) + args = self.configure_args(capture) + self.assertIn("--cross-compile", args) + self.assertEqual(self.cross_execute_args(args), []) + cross_answers = self.cross_answer_arg(args) + self.assertTrue(cross_answers.endswith("/samba4x-4.24.1-netbsd7.answers")) + self.assertFalse(cross_exec_capture.exists()) + + def test_generation_helper_starts_from_fresh_seed_and_ignores_stale_answers(self) -> None: + with tempfile.TemporaryDirectory() as tmp: + root = Path(tmp) + capture = root / "configure-args.txt" + seed_capture = root / "seed-before-configure.answers" + output_dir = root / "generated" + cross_exec_capture = root / "cross-exec-args.txt" + cross_exec = root / "cross-exec.sh" + stale_answers = root / "stale.answers" + stale_answers.write_text( + "Checking stale tracked answer: CARRIED-FORWARD\n" + "Checking whether the realpath function allows a NULL argument: OK\n" + ) + self.make_fake_cross_execute(cross_exec) + env = self.env_for_lane(root, "netbsd4be", capture) + env.update( + { + "SAMBA4X_CROSS_ANSWERS": str(stale_answers), + "SAMBA4X_CROSS_EXECUTE": str(cross_exec), + "SAMBA4X_GENERATED_CROSS_ANSWERS_DIR": str(output_dir), + "TEST_CONFIGURE_WRITES_ANSWERS": "1", + "TEST_REALPATH_ANSWER": "NO", + "TEST_SEED_CAPTURE": str(seed_capture), + "TEST_CROSS_EXEC_ARGS": str(cross_exec_capture), + "TEST_CROSS_EXEC_RC": "1", + } + ) + + result = self.run_wrapper("generate-samba4x-cross-answers-oldbe.sh", env) + + self.assertEqual(result.returncode, 0, result.stdout + result.stderr) + args = self.configure_args(capture) + cross_answers = self.cross_answer_arg(args) + self.assertTrue(cross_answers.endswith("/generated-samba4x-4.24.1-netbsd4be.answers")) + self.assertEqual(len(self.cross_execute_args(args)), 1) + seed = seed_capture.read_text() + self.assertIn('Checking uname sysname type: "NetBSD"', seed) + self.assertNotIn("CARRIED-FORWARD", seed) + generated = output_dir / "samba4x-4.24.1-netbsd4be.answers" + generated_text = generated.read_text() + self.assertIn("Checking whether the realpath function allows a NULL argument: NO", generated_text) + self.assertNotIn("CARRIED-FORWARD", generated_text) + self.assertTrue(cross_exec_capture.exists()) + + def test_refresh_mode_is_generation_alias_with_cross_execute(self) -> None: + with tempfile.TemporaryDirectory() as tmp: + root = Path(tmp) + capture = root / "configure-args.txt" + output_dir = root / "generated" + cross_exec = root / "cross-exec.sh" + self.make_fake_cross_execute(cross_exec) + env = self.env_for_lane(root, "netbsd7", capture) + env.update( + { + "SAMBA4X_REFRESH_CROSS_ANSWERS": "1", + "SAMBA4X_CROSS_EXECUTE": str(cross_exec), + "SAMBA4X_GENERATED_CROSS_ANSWERS_DIR": str(output_dir), + "TEST_CONFIGURE_WRITES_ANSWERS": "1", + "TEST_REALPATH_ANSWER": "OK", + "TEST_CROSS_EXEC_RC": "0", + } + ) + + result = self.run_wrapper("samba4x.sh", env) + + self.assertEqual(result.returncode, 0, result.stdout + result.stderr) + args = self.configure_args(capture) + self.cross_answer_arg(args) + self.assertEqual(len(self.cross_execute_args(args)), 1) + self.assertTrue((output_dir / "samba4x-4.24.1-netbsd7.answers").exists()) + + def test_lane_wrappers_select_their_default_cross_answer_files(self) -> None: + cases = ( + ("samba4x.sh", "netbsd7", "samba4x-4.24.1-netbsd7.answers"), + ("samba4xoldle.sh", "netbsd4le", "samba4x-4.24.1-netbsd4le.answers"), + ("samba4xoldbe.sh", "netbsd4be", "samba4x-4.24.1-netbsd4be.answers"), + ) + for wrapper, lane, expected in cases: + with self.subTest(wrapper=wrapper): + with tempfile.TemporaryDirectory() as tmp: + root = Path(tmp) + capture = root / "configure-args.txt" + env = self.env_for_lane(root, lane, capture) + + result = self.run_wrapper(wrapper, env) + + self.assertEqual(result.returncode, 0, result.stdout + result.stderr) + cross_answers = self.cross_answer_arg(self.configure_args(capture)) + self.assertTrue(cross_answers.endswith(f"/{expected}")) + + def test_missing_cross_answers_fail_before_configure(self) -> None: + with tempfile.TemporaryDirectory() as tmp: + root = Path(tmp) + capture = root / "configure-args.txt" + env = self.env_for_lane(root, "netbsd7", capture) + env["SAMBA4X_CROSS_ANSWERS"] = str(root / "missing.answers") + + result = self.run_wrapper("samba4x.sh", env) + + self.assertNotEqual(result.returncode, 0) + self.assertIn("Missing Samba 4.x cross-answers file", Path(env["SAMBA4X_NETBSD7_LOG"]).read_text()) + self.assertFalse(capture.exists()) + + def test_unknown_cross_answers_fail_before_configure(self) -> None: + with tempfile.TemporaryDirectory() as tmp: + root = Path(tmp) + capture = root / "configure-args.txt" + answers = root / "unknown.answers" + answers.write_text("Checking target behavior: UNKNOWN\n") + env = self.env_for_lane(root, "netbsd7", capture) + env["SAMBA4X_CROSS_ANSWERS"] = str(answers) + + result = self.run_wrapper("samba4x.sh", env) + + self.assertNotEqual(result.returncode, 0) + self.assertIn("contains UNKNOWN entries", Path(env["SAMBA4X_NETBSD7_LOG"]).read_text()) + self.assertFalse(capture.exists()) + + def test_conflicting_duplicate_cross_answers_fail_before_configure(self) -> None: + with tempfile.TemporaryDirectory() as tmp: + root = Path(tmp) + capture = root / "configure-args.txt" + answers = root / "conflicting.answers" + answers.write_text( + "Checking duplicate behavior: OK\n" + "Checking duplicate behavior: NO\n" + ) + env = self.env_for_lane(root, "netbsd7", capture) + env["SAMBA4X_CROSS_ANSWERS"] = str(answers) + + result = self.run_wrapper("samba4x.sh", env) + + self.assertNotEqual(result.returncode, 0) + log = Path(env["SAMBA4X_NETBSD7_LOG"]).read_text() + self.assertIn("contains conflicting duplicate answers", log) + self.assertFalse(capture.exists()) + + def test_netbsd4_realpath_ok_cross_answers_fail_before_configure(self) -> None: + with tempfile.TemporaryDirectory() as tmp: + root = Path(tmp) + capture = root / "configure-args.txt" + answers = root / "netbsd4-bad-realpath.answers" + answers.write_text( + 'Checking uname sysname type: "NetBSD"\n' + "Checking whether the realpath function allows a NULL argument: OK\n" + ) + env = self.env_for_lane(root, "netbsd4be", capture) + env["SAMBA4X_CROSS_ANSWERS"] = str(answers) + + result = self.run_wrapper("samba4xoldbe.sh", env) + + self.assertNotEqual(result.returncode, 0) + log = Path(env["SAMBA4X_NETBSD4BE_LOG"]).read_text() + self.assertIn("incorrectly allows realpath(path, NULL)", log) + self.assertFalse(capture.exists()) + + def test_generation_normalizes_duplicate_answers_before_install(self) -> None: + with tempfile.TemporaryDirectory() as tmp: + root = Path(tmp) + capture = root / "configure-args.txt" + output_dir = root / "generated" + cross_exec = root / "cross-exec.sh" + self.make_fake_cross_execute(cross_exec) + env = self.env_for_lane(root, "netbsd4be", capture) + env.update( + { + "SAMBA4X_CROSS_EXECUTE": str(cross_exec), + "SAMBA4X_GENERATED_CROSS_ANSWERS_DIR": str(output_dir), + "TEST_CONFIGURE_WRITES_ANSWERS": "1", + "TEST_REALPATH_ANSWER": "OK", + "TEST_DUPLICATE_REALPATH_ANSWER": "NO", + "TEST_CROSS_EXEC_RC": "1", + } + ) + + result = self.run_wrapper("generate-samba4x-cross-answers-oldbe.sh", env) + + self.assertEqual(result.returncode, 0, result.stdout + result.stderr) + generated = output_dir / "samba4x-4.24.1-netbsd4be.answers" + realpath_lines = [ + line + for line in generated.read_text().splitlines() + if line.startswith("Checking whether the realpath function allows a NULL argument:") + ] + self.assertEqual( + realpath_lines, + ["Checking whether the realpath function allows a NULL argument: NO"], + ) + + def test_generation_fails_when_independent_probe_disagrees(self) -> None: + with tempfile.TemporaryDirectory() as tmp: + root = Path(tmp) + capture = root / "configure-args.txt" + output_dir = root / "generated" + cross_exec = root / "cross-exec.sh" + self.make_fake_cross_execute(cross_exec) + env = self.env_for_lane(root, "netbsd4be", capture) + env.update( + { + "SAMBA4X_CROSS_EXECUTE": str(cross_exec), + "SAMBA4X_GENERATED_CROSS_ANSWERS_DIR": str(output_dir), + "TEST_CONFIGURE_WRITES_ANSWERS": "1", + "TEST_REALPATH_ANSWER": "OK", + "TEST_CROSS_EXEC_RC": "1", + } + ) + + result = self.run_wrapper("generate-samba4x-cross-answers-oldbe.sh", env) + + self.assertNotEqual(result.returncode, 0) + self.assertIn( + "disagrees with independent realpath(path, NULL) probe", + Path(env["SAMBA4X_NETBSD4BE_LOG"]).read_text(), + ) + self.assertFalse((output_dir / "samba4x-4.24.1-netbsd4be.answers").exists()) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_deploy_modules.py b/tests/test_deploy_modules.py index 5f4f6d71..eceefa2c 100644 --- a/tests/test_deploy_modules.py +++ b/tests/test_deploy_modules.py @@ -2180,7 +2180,10 @@ def test_mdns_auto_ip_runtime_socket_is_exclusive(self) -> None: selector = selectors.DefaultSelector() assert run.stderr is not None selector.register(run.stderr, selectors.EVENT_READ) - deadline = time.monotonic() + 8 + # The runtime intentionally waits AUTO_IP_STABILIZE_SECONDS before + # attempting the exclusive bind. Give slow CI hosts enough margin + # after that stabilization window to finish multicast setup. + deadline = time.monotonic() + 20 ready = False try: while run.poll() is None and time.monotonic() < deadline: