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, ">1(tmpdir);:uqd(directory)p: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. The number of X needs to be no less than 6.
25 */
26
27 #define FOR_mktemp
28 #include "toys.h"
29
30 GLOBALS(
31 char *p, *tmpdir;
32 )
33
mktemp_main(void)34 void 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 #ifdef TOYBOX_OH_ADAPT
51 /* fix "mktemp -q mytempdir.XX" print error log problem*/
52 if (*template == '/' && TT.p && *TT.p) {
53 if (FLAG(q)) {
54 toys.exitval = 1;
55 return;
56 } else perror_exit("-p + /template");
57 }
58 #else
59 if (*template == '/' && TT.p && *TT.p) perror_exit("-p + /template");
60 #endif
61 if (!FLAG(p)&&!FLAG(t)) dir = 0;
62 }
63
64 // TODO: coreutils cleans paths, so -p /t/// would result in /t/xxx...
65 template = dir ? xmprintf("%s/%s", dir, template) : xstrdup(template);
66 len = strlen(template);
67 #ifdef TOYBOX_OH_ADAPT
68 /* fix "mktemp -q mytempdir.XX" print error log problem*/
69 if (len<6 || strcmp(template+len-6, "XXXXXX")) {
70 if (FLAG(q)) {
71 toys.exitval = 1;
72 return;
73 } else perror_exit("need XXXXXX");
74 }
75 #else
76 if (len<3 || strcmp(template+len-3, "XXX")) perror_exit("need XXX");
77 #endif
78
79 // In theory you just xputs(mktemp(template)) for -u, in practice there's
80 // link-time deprecation warnings if you do that. So we fake up our own:
81 if (FLAG(u)) {
82 long long rr;
83 char *s = template+len;
84
85 // Fall back to random-ish if xgetrandom fails.
86 if (!xgetrandom(&rr, sizeof(rr), WARN_ONLY)) {
87 struct timespec ts;
88
89 clock_gettime(CLOCK_REALTIME, &ts);
90 rr = ts.tv_nsec*65537+(long)template+getpid()+(long)&template;
91 }
92 // Replace X with 64 chars from posix portable character set (all but "_").
93 while (--s>template) {
94 if (*s != 'X') break;
95 *s = '-'+(rr&63);
96 if (*s>'.') ++*s;
97 if (*s>'9') (*s) += 7;
98 if (*s>'Z') (*s) += 6;
99 rr>>=6;
100 }
101 } else if (FLAG(d) ? !mkdtemp(template) : mkstemp(template) == -1) {
102 if (FLAG(q)) {
103 toys.exitval = 1;
104 return;
105 } else perror_exit("Failed to create %s %s",
106 FLAG(d) ? "directory" : "file", template);
107 }
108
109 xputs(template);
110 if (CFG_TOYBOX_FREE) free(template);
111 }
112