Use writable temp dirs for binary builds

ober

d647d99393b8b92a76079ce40a5f7a2d8f01931f

diff --git a/data/cookbooks.sexp b/data/cookbooks.sexp
index 11611a5..92e0d33 100644
--- 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")))
diff --git a/data/error-fixes.sexp b/data/error-fixes.sexp
index fd51283..ce0e6ba 100644
--- 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")))
diff --git a/support/build-binary.sh b/support/build-binary.sh
index e77b726..223dddf 100755
--- 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);