• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
7 USE_MKTEMP(NEWTOY(mktemp, ">1uqd(directory)p(tmpdir):t", TOYFLAG_BIN))
8 
9 config 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 
GLOBALS(char * p;)30 GLOBALS(
31   char *p;
32 )
33 
34 void mktemp_main(void)
35 {
36   char *template = *toys.optargs, *dir = TT.p, *te = getenv("TMPDIR");
37   int len;
38 
39   // if template, no prefix unless -pt. if !template, always prefix
40   if (!dir || !*dir || (FLAG(t) && te && *te)) dir = te;
41   if (!dir || !*dir) dir = "/tmp";
42   if (!template) template = "tmp.XXXXXXXXXX";
43   else {
44     if (*template == '/' && TT.p && *TT.p) perror_exit("-p + /template");
45     if (!FLAG(p)&&!FLAG(t)) dir = 0;
46   }
47 
48   // TODO: coreutils cleans paths, so -p /t/// would result in /t/xxx...
49   template = dir ? xmprintf("%s/%s", dir, template) : xstrdup(template);
50   len = strlen(template);
51   if (len<3 || strcmp(template+len-3, "XXX")) perror_exit("need XXX");
52 
53   // In theory you just xputs(mktemp(template)) for -u, in practice there's
54   // link-time deprecation warnings if you do that. So we fake up our own:
55   if (toys.optflags & FLAG_u) {
56     long long rr;
57     char *s = template+len;
58 
59     // Fall back to random-ish if xgetrandom fails.
60     if (!xgetrandom(&rr, sizeof(rr), WARN_ONLY)) {
61       struct timespec ts;
62 
63       clock_gettime(CLOCK_REALTIME, &ts);
64       rr = ts.tv_nsec*65537+(long)template+getpid()+(long)&template;
65     }
66     // Replace X with 64 chars from posix portable character set (all but "_").
67     while (--s>template) {
68       if (*s != 'X') break;
69       *s = '-'+(rr&63);
70       if (*s>'.') ++*s;
71       if (*s>'9') (*s) += 7;
72       if (*s>'Z') (*s) += 6;
73       rr>>=6;
74     }
75   } else if ((toys.optflags & FLAG_d) ? !mkdtemp(template) : mkstemp(template) == -1) {
76     if (toys.optflags & FLAG_q) {
77       toys.exitval = 1;
78       return;
79     } else perror_exit("Failed to create %s %s/%s",
80         (toys.optflags & FLAG_d) ? "directory" : "file", TT.p, template);
81   }
82 
83   xputs(template);
84   if (CFG_TOYBOX_FREE) free(template);
85 }
86