aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--toys/lsb/mktemp.c64
1 files changed, 40 insertions, 24 deletions
diff --git a/toys/lsb/mktemp.c b/toys/lsb/mktemp.c
index 112f84c4..22c880fa 100644
--- a/toys/lsb/mktemp.c
+++ b/toys/lsb/mktemp.c
@@ -33,37 +33,53 @@ GLOBALS(
void mktemp_main(void)
{
- char *template = *toys.optargs;
- int use_dir = (toys.optflags & (FLAG_p|FLAG_t));
+ char *template = *toys.optargs, *dir = TT.p, *te = getenv("TMPDIR");
+ int len;
- if (!template) {
- template = "tmp.XXXXXXXXXX";
- use_dir = 1;
- }
-
- // Normally, the precedence is DIR (if set), $TMPDIR (if set), /tmp.
- // With -t it's $TMPDIR, DIR, /tmp.
- if (use_dir) {
- char *tmpdir = getenv("TMPDIR");
-
- if (toys.optflags & FLAG_t) {
- if (tmpdir && *tmpdir) TT.p = tmpdir;
- } else {
- if (!TT.p || !*TT.p) TT.p = tmpdir;
- }
- if (!TT.p || !*TT.p) TT.p = "/tmp";
+ // if template, no prefix unless -pt. if !template, always prefix
+ if (!dir || !*dir || (FLAG(t) && te && *te)) dir = te;
+ if (!dir || !*dir) dir = "/tmp";
+ if (!template) template = "tmp.XXXXXXXXXX";
+ else {
+ if (*template == '/' && TT.p && *TT.p) perror_exit("-p + /template");
+ if (!FLAG(p)&&!FLAG(t)) dir = 0;
}
// TODO: coreutils cleans paths, so -p /t/// would result in /t/xxx...
- template = use_dir ? xmprintf("%s/%s", TT.p, template) : xstrdup(template);
+ template = dir ? xmprintf("%s/%s", dir, template) : xstrdup(template);
+ len = strlen(template);
+ if (len<3 || strcmp(template+len-3, "XXX")) perror_exit("need XXX");
+ // In theory you just xputs(mktemp(template)) for -u, in practice there's
+ // link-time deprecation warnings if you do that. So we fake up our own:
if (toys.optflags & FLAG_u) {
- xputs(mktemp(template));
- } else if (toys.optflags & FLAG_d ? !mkdtemp(template) : mkstemp(template) == -1) {
- if (toys.optflags & FLAG_q) toys.exitval = 1;
- else perror_exit("Failed to create %s %s/%s",
- toys.optflags & FLAG_d ? "directory" : "file", TT.p, template);
+ long long rr;
+ char *s = template+len;
+
+ // Fall back to random-ish if xgetrandom fails.
+ if (!xgetrandom(&rr, sizeof(rr), WARN_ONLY)) {
+ struct timespec ts;
+
+ clock_gettime(CLOCK_REALTIME, &ts);
+ rr = ts.tv_nsec*65537+(long)template+getpid()+(long)&template;
+ }
+ // Replace X with 64 chars from posix portable character set (all but "_").
+ while (--s>template) {
+ if (*s != 'X') break;
+ *s = '-'+(rr&63);
+ if (*s>'.') ++*s;
+ if (*s>'9') (*s) += 7;
+ if (*s>'Z') (*s) += 6;
+ rr>>=6;
+ }
+ } else if ((toys.optflags & FLAG_d) ? !mkdtemp(template) : mkstemp(template) == -1) {
+ if (toys.optflags & FLAG_q) {
+ toys.exitval = 1;
+ return;
+ } else perror_exit("Failed to create %s %s/%s",
+ (toys.optflags & FLAG_d) ? "directory" : "file", TT.p, template);
}
+ xputs(template);
if (CFG_TOYBOX_FREE) free(template);
}