From 1bc733dea997a50f87b788473285e7202fa21c81 Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Fri, 7 Dec 2018 09:27:25 -0600 Subject: Fix mktemp to pass tests. --- toys/lsb/mktemp.c | 64 ++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 40 insertions(+), 24 deletions(-) (limited to 'toys/lsb') 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); } -- cgit v1.2.3