Temp dir falls back when TMPDIR or /tmp is unusable (Termux); v0.6.1
os_temp_dir() used $TMPDIR or "/tmp" without checking either. On Termux
/tmp usually does not exist (or SELinux denies it) unless TMPDIR points at
$PREFIX/tmp, so plugin and MCP temp files failed and shell children that
need a temp file (heredocs) broke.
* os_temp_dir() picks, once, the first of $TMPDIR, $PREFIX/tmp, /tmp,
/var/tmp and ~/.cache/cst-agent/tmp where a file can really be
created; if none works it keeps the old answer
* os_temp_dir_export() at startup writes the choice back to TMPDIR, so
shell children and the sandbox's writable temp dir agree
* tests/test_tmpdir.c covers the fallbacks in fresh forks
This commit is contained in:
@@ -192,6 +192,7 @@ int main(int argc, char **argv) {
|
||||
fprintf(stderr, "warning: the process code page is not UTF-8 (Windows 10 "
|
||||
"1903 or later is required); non-ASCII text may break\n");
|
||||
os_set_prog_path(argv[0]);
|
||||
os_temp_dir_export();
|
||||
curl_global_init(CURL_GLOBAL_DEFAULT);
|
||||
|
||||
cst_agent_config_t cfg = {0};
|
||||
|
||||
+71
-4
@@ -255,6 +255,66 @@ int os_config_dir(char *out, size_t out_sz) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
/* $TMPDIR is not always usable: Termux has no /tmp unless TMPDIR points at
|
||||
* $PREFIX/tmp, and Android may deny /tmp or /data/local/tmp outright. Take
|
||||
* the first candidate where a file can actually be created. */
|
||||
static char g_tmp[OS_PATH_MAX];
|
||||
static pthread_once_t g_tmp_once = PTHREAD_ONCE_INIT;
|
||||
|
||||
static int tmp_writable(const char *dir) {
|
||||
char probe[OS_PATH_MAX];
|
||||
struct stat st;
|
||||
if (!dir || dir[0] != '/' || stat(dir, &st) != 0 || !S_ISDIR(st.st_mode))
|
||||
return 0;
|
||||
int n = snprintf(probe, sizeof(probe), "%s/.cst-probe-XXXXXX", dir);
|
||||
if (n < 0 || (size_t)n >= sizeof(probe))
|
||||
return 0;
|
||||
int fd = mkstemp(probe);
|
||||
if (fd < 0)
|
||||
return 0;
|
||||
close(fd);
|
||||
unlink(probe);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void tmp_trim(char *s) {
|
||||
size_t n = strlen(s);
|
||||
while (n > 1 && s[n - 1] == '/')
|
||||
s[--n] = 0;
|
||||
}
|
||||
|
||||
static void tmp_pick(void) {
|
||||
char cand[5][OS_PATH_MAX];
|
||||
int nc = 0;
|
||||
const char *env = getenv("TMPDIR");
|
||||
const char *prefix = getenv("PREFIX");
|
||||
const char *home = getenv("HOME");
|
||||
const char *cache = getenv("XDG_CACHE_HOME");
|
||||
if (env && env[0])
|
||||
snprintf(cand[nc++], OS_PATH_MAX, "%s", env);
|
||||
if (prefix && prefix[0] == '/')
|
||||
snprintf(cand[nc++], OS_PATH_MAX, "%s/tmp", prefix);
|
||||
snprintf(cand[nc++], OS_PATH_MAX, "/tmp");
|
||||
snprintf(cand[nc++], OS_PATH_MAX, "/var/tmp");
|
||||
if (cache && cache[0] == '/')
|
||||
snprintf(cand[nc++], OS_PATH_MAX, "%s/cst-agent/tmp", cache);
|
||||
else if (home && home[0] == '/')
|
||||
snprintf(cand[nc++], OS_PATH_MAX, "%s/.cache/cst-agent/tmp", home);
|
||||
for (int i = 0; i < nc; i++) {
|
||||
tmp_trim(cand[i]);
|
||||
if (i == nc - 1)
|
||||
os_mkdir_p(cand[i], 0700);
|
||||
if (tmp_writable(cand[i])) {
|
||||
memcpy(g_tmp, cand[i], strlen(cand[i]) + 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* nothing works: keep the old answer so callers fail as before */
|
||||
memcpy(g_tmp, cand[0], strlen(cand[0]) + 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
int os_temp_dir(char *out, size_t out_sz) {
|
||||
if (!out || out_sz < 2)
|
||||
return -1;
|
||||
@@ -268,11 +328,18 @@ int os_temp_dir(char *out, size_t out_sz) {
|
||||
out[--L] = 0;
|
||||
return 0;
|
||||
#else
|
||||
pthread_once(&g_tmp_once, tmp_pick);
|
||||
int n = snprintf(out, out_sz, "%s", g_tmp);
|
||||
return n < 0 || (size_t)n >= out_sz ? -1 : 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void os_temp_dir_export(void) {
|
||||
#ifndef _WIN32
|
||||
char d[OS_PATH_MAX];
|
||||
const char *t = getenv("TMPDIR");
|
||||
if (!t || !t[0])
|
||||
t = "/tmp";
|
||||
snprintf(out, out_sz, "%s", t);
|
||||
return 0;
|
||||
if (os_temp_dir(d, sizeof(d)) == 0 && (!t || strcmp(t, d) != 0))
|
||||
setenv("TMPDIR", d, 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user