Use writable temp dirs for binary builds
ober
d647d99393b8b92a76079ce40a5f7a2d8f01931f
--- a/data/cookbooks.sexp +++ b/data/cookbooks.sexp @@ -6515,4 +6515,15 @@ "Termux reports uname -s as Linux and uname -o as Android. Chez Scheme's vendored make-android helper passes CFLAGS, LDFLAGS, and LIBS=-liconv because GNU libiconv is a separate Termux library. Gate these settings on Android so normal Linux builds do not link against a separate libiconv.") ("tags" "chez" "termux" "android" "build" "libiconv" "makefile") - ("title" . "Build native Chez on Termux with libiconv"))) + ("title" . "Build native Chez on Termux with libiconv")) + (("code" + . + "choose_tmp_parent() {\n if [ -n \"${TMPDIR:-}\" ] && [ -d \"$TMPDIR\" ] && [ -w \"$TMPDIR\" ]; then\n printf '%s\\n' \"$TMPDIR\"\n return\n fi\n if [ -n \"${PREFIX:-}\" ] && [ -d \"$PREFIX/tmp\" ] && [ -w \"$PREFIX/tmp\" ]; then\n printf '%s\\n' \"$PREFIX/tmp\"\n return\n fi\n if [ -d /tmp ] && [ -w /tmp ]; then\n printf '%s\\n' /tmp\n return\n fi\n\n mkdir -p \"$PROJECT_ROOT/build/tmp\"\n printf '%s\\n' \"$PROJECT_ROOT/build/tmp\"\n}\n\nTMP_PARENT=$(choose_tmp_parent)\nOBJ_DIR=$(mktemp -d \"$TMP_PARENT/my-build.XXXXXX\")") ("id" . "portable-build-temp-dir-termux") ("imports") + ("notes" + . + "Some Termux SSH hosts report Linux but cannot create files under /tmp. Build scripts should prefer TMPDIR, then Termux's $PREFIX/tmp, then /tmp, and finally a repo-local temp directory. Generated C that uses mkstemp should make the same runtime choice instead of embedding /tmp/template directly.") + ("tags" "termux" "tmpdir" "mktemp" "shell" "build" + "portable") + ("title" + . + "Choose a writable build temp directory on Termux"))) --- a/data/error-fixes.sexp +++ b/data/error-fixes.sexp @@ -2566,4 +2566,18 @@ ("pattern" . "undefined symbol: libiconv_open|undefined symbol: libiconv_close|undefined symbol: libiconv") - ("type" . "linker"))) + ("type" . "linker")) + (("code_example" + . + "choose_tmp_parent() {\n if [ -n \"${TMPDIR:-}\" ] && [ -d \"$TMPDIR\" ] && [ -w \"$TMPDIR\" ]; then printf '%s\\n' \"$TMPDIR\"; return; fi\n if [ -n \"${PREFIX:-}\" ] && [ -d \"$PREFIX/tmp\" ] && [ -w \"$PREFIX/tmp\" ]; then printf '%s\\n' \"$PREFIX/tmp\"; return; fi\n if [ -d /tmp ] && [ -w /tmp ]; then printf '%s\\n' /tmp; return; fi\n mkdir -p \"$JERBOA_HOME/build/tmp\"\n printf '%s\\n' \"$JERBOA_HOME/build/tmp\"\n}") + ("explanation" + . + "Some Termux SSH environments report /tmp but do not permit the app user to create files there. Scripts and generated binaries that call mktemp or mkstemp with a /tmp template fail after the main compile succeeds.") + ("fix" + . + "Do not hard-code /tmp for build artifacts on Termux or other restricted environments. Prefer TMPDIR when writable, then $PREFIX/tmp on Termux, then /tmp, and finally a repo-local build/tmp directory for build-time artifacts.") + ("id" . "termux-unwritable-tmp-mktemp") + ("pattern" + . + "mktemp: failed to create directory via template .*/tmp/.*: Permission denied") + ("type" . "build"))) --- a/support/build-binary.sh +++ b/support/build-binary.sh @@ -41,6 +41,24 @@ flag_enabled() { esac } +choose_tmp_parent() { + if [ -n "${TMPDIR:-}" ] && [ -d "$TMPDIR" ] && [ -w "$TMPDIR" ]; then + printf '%s\n' "$TMPDIR" + return + fi + if [ -n "${PREFIX:-}" ] && [ -d "$PREFIX/tmp" ] && [ -w "$PREFIX/tmp" ]; then + printf '%s\n' "$PREFIX/tmp" + return + fi + if [ -d /tmp ] && [ -w /tmp ]; then + printf '%s\n' /tmp + return + fi + + mkdir -p "$JERBOA_HOME/build/tmp" + printf '%s\n' "$JERBOA_HOME/build/tmp" +} + if [ -n "$TARGET_MACHINE" ]; then CROSS_BUILD=yes [ -n "$JERBOA_CROSS_PREFIX" ] || { echo "ERROR: TARGET_MACHINE set but JERBOA_CROSS_PREFIX is not" >&2; exit 1; } @@ -229,7 +247,8 @@ echo "" # ── Step 1: WPO-compile entry script -> program.so ─────────────────────────── WPO_SO="${OUTPUT}.wp.so" -OBJ_DIR=$(mktemp -d "/tmp/jerboa-bin-obj.XXXXXX") +TMP_PARENT=$(choose_tmp_parent) +OBJ_DIR=$(mktemp -d "$TMP_PARENT/jerboa-bin-obj.XXXXXX") trap 'rm -rf "$OBJ_DIR" "$WPO_SO" petite_boot.h scheme_boot.h program_boot.h typed_symbols.h "${OUTPUT}-main.c"' EXIT echo "==> [1/4] WPO compile" @@ -314,7 +333,29 @@ cat > "${OUTPUT}-main.c" <<'CMAIN' #include "hardening-report.h" static const char *write_program_tmpfile(void) { - static char path[] = "/tmp/jerboa-prog-XXXXXX"; + static char path[4096]; + const char *tmpdir = getenv("TMPDIR"); + if (tmpdir == NULL || tmpdir[0] == '\0' || access(tmpdir, W_OK) != 0) { + const char *prefix = getenv("PREFIX"); + if (prefix != NULL && prefix[0] != '\0') { + int n = snprintf(path, sizeof(path), "%s/tmp", prefix); + if (n > 0 && (size_t)n < sizeof(path) && access(path, W_OK) == 0) { + tmpdir = path; + } else { + tmpdir = NULL; + } + } else { + tmpdir = NULL; + } + } + if (tmpdir == NULL || tmpdir[0] == '\0') { + tmpdir = (access("/tmp", W_OK) == 0) ? "/tmp" : "."; + } + int len = snprintf(path, sizeof(path), "%s/jerboa-prog-XXXXXX", tmpdir); + if (len <= 0 || (size_t)len >= sizeof(path)) { + fprintf(stderr, "temporary path too long\n"); + exit(1); + } int fd = mkstemp(path); if (fd < 0) { perror("mkstemp"); exit(1); } ssize_t n = write(fd, program_boot_data, program_boot_size);