1/* mktemp.c - Create a temporary file or directory. 2 * 3 * Copyright 2012 Elie De Brauwer <eliedebrauwer@gmail.com> 4 * 5 * http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/mktemp.html 6 7USE_MKTEMP(NEWTOY(mktemp, ">1(tmpdir);:uqd(directory)p:t", TOYFLAG_BIN)) 8 9config MKTEMP 10 bool "mktemp" 11 default y 12 help 13 usage: mktemp [-dqu] [-p DIR] [TEMPLATE] 14 15 Safely create a new file "DIR/TEMPLATE" and print its name. 16 17 -d Create directory instead of file (--directory) 18 -p Put new file in DIR (--tmpdir) 19 -q Quiet, no error messages 20 -t Prefer $TMPDIR > DIR > /tmp (default DIR > $TMPDIR > /tmp) 21 -u Don't create anything, just print what would be created 22 23 Each X in TEMPLATE is replaced with a random printable character. The 24 default TEMPLATE is tmp.XXXXXXXXXX. 25*/ 26 27#define FOR_mktemp 28#include "toys.h" 29 30GLOBALS( 31 char *p, *tmpdir; 32) 33 34void mktemp_main(void) 35{ 36 char *template = *toys.optargs, *dir, *te = getenv("TMPDIR"); 37 int len; 38 39 // --tmpdir's argument is optional's but -p is mandatory, so can't combine 40 if (!TT.p && FLAG(tmpdir)) { 41 TT.p = TT.tmpdir ? TT.tmpdir : ""; 42 toys.optflags |= FLAG_p; 43 } 44 dir = TT.p; 45 // if template, no prefix unless -pt. if !template, always prefix 46 if (!dir || !*dir || (FLAG(t) && te && *te)) dir = te; 47 if (!dir || !*dir) dir = "/tmp"; 48 if (!template) template = "tmp.XXXXXXXXXX"; 49 else { 50 if (*template == '/' && TT.p && *TT.p) perror_exit("-p + /template"); 51 if (!FLAG(p)&&!FLAG(t)) dir = 0; 52 } 53 54 // TODO: coreutils cleans paths, so -p /t/// would result in /t/xxx... 55 template = dir ? xmprintf("%s/%s", dir, template) : xstrdup(template); 56 len = strlen(template); 57 if (len<3 || strcmp(template+len-3, "XXX")) perror_exit("need XXX"); 58 59 // In theory you just xputs(mktemp(template)) for -u, in practice there's 60 // link-time deprecation warnings if you do that. So we fake up our own: 61 if (FLAG(u)) { 62 long long rr; 63 char *s = template+len; 64 65 // Fall back to random-ish if xgetrandom fails. 66 if (!xgetrandom(&rr, sizeof(rr), WARN_ONLY)) { 67 struct timespec ts; 68 69 clock_gettime(CLOCK_REALTIME, &ts); 70 rr = ts.tv_nsec*65537+(long)template+getpid()+(long)&template; 71 } 72 // Replace X with 64 chars from posix portable character set (all but "_"). 73 while (--s>template) { 74 if (*s != 'X') break; 75 *s = '-'+(rr&63); 76 if (*s>'.') ++*s; 77 if (*s>'9') (*s) += 7; 78 if (*s>'Z') (*s) += 6; 79 rr>>=6; 80 } 81 } else if (FLAG(d) ? !mkdtemp(template) : mkstemp(template) == -1) { 82 if (FLAG(q)) { 83 toys.exitval = 1; 84 return; 85 } else perror_exit("Failed to create %s %s", 86 FLAG(d) ? "directory" : "file", template); 87 } 88 89 xputs(template); 90 if (CFG_TOYBOX_FREE) free(template); 91} 92