1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 1994, 1995, 1996, 1998 Peter Wemm <peter@netplex.com.au>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 *
28 */
29
30 /*
31 * This program was originally written long ago, originally for a non
32 * BSD-like OS without mkstemp(). It's been modified over the years
33 * to use mkstemp() rather than the original O_CREAT|O_EXCL/fstat/lstat
34 * etc style hacks.
35 * A cleanup, misc options and mkdtemp() calls were added to try and work
36 * more like the OpenBSD version - which was first to publish the interface.
37 */
38
39 #include <err.h>
40 #include <getopt.h>
41 #include <paths.h>
42 #include <stdbool.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <unistd.h>
47
48 static void usage(void) __dead2;
49
50 static const struct option long_opts[] = {
51 {"directory", no_argument, NULL, 'd'},
52 {"tmpdir", optional_argument, NULL, 'p'},
53 {"quiet", no_argument, NULL, 'q'},
54 {"dry-run", no_argument, NULL, 'u'},
55 {NULL, no_argument, NULL, 0},
56 };
57
58 int
main(int argc,char ** argv)59 main(int argc, char **argv)
60 {
61 int c, fd, ret;
62 const char *prefix, *tmpdir;
63 char *name;
64 int dflag, qflag, tflag, uflag;
65 bool prefer_tmpdir;
66
67 ret = dflag = qflag = tflag = uflag = 0;
68 prefer_tmpdir = true;
69 prefix = "mktemp";
70 name = NULL;
71 tmpdir = NULL;
72
73 while ((c = getopt_long(argc, argv, "dp:qt:u", long_opts, NULL)) != -1)
74 switch (c) {
75 case 'd':
76 dflag++;
77 break;
78
79 case 'p':
80 tmpdir = optarg;
81 if (tmpdir == NULL || *tmpdir == '\0')
82 tmpdir = getenv("TMPDIR");
83
84 /*
85 * We've already done the necessary environment
86 * fallback, skip the later one.
87 */
88 prefer_tmpdir = false;
89 break;
90
91 case 'q':
92 qflag++;
93 break;
94
95 case 't':
96 prefix = optarg;
97 tflag++;
98 break;
99
100 case 'u':
101 uflag++;
102 break;
103
104 default:
105 usage();
106 }
107
108 argc -= optind;
109 argv += optind;
110
111 if (!tflag && argc < 1) {
112 tflag = 1;
113 prefix = "tmp";
114
115 /*
116 * For this implied -t mode, we actually want to swap the usual
117 * order of precedence: -p, then TMPDIR, then /tmp.
118 */
119 prefer_tmpdir = false;
120 }
121
122 if (tflag) {
123 const char *envtmp;
124 size_t len;
125
126 envtmp = NULL;
127
128 /*
129 * $TMPDIR preferred over `-p` if specified, for compatibility.
130 */
131 if (prefer_tmpdir || tmpdir == NULL)
132 envtmp = getenv("TMPDIR");
133 if (envtmp != NULL)
134 tmpdir = envtmp;
135 if (tmpdir == NULL)
136 tmpdir = _PATH_TMP;
137 len = strlen(tmpdir);
138 if (len > 0 && tmpdir[len - 1] == '/')
139 asprintf(&name, "%s%s.XXXXXXXXXX", tmpdir, prefix);
140 else
141 asprintf(&name, "%s/%s.XXXXXXXXXX", tmpdir, prefix);
142 /* if this fails, the program is in big trouble already */
143 if (name == NULL) {
144 if (qflag)
145 return (1);
146 else
147 errx(1, "cannot generate template");
148 }
149 }
150
151 /* generate all requested files */
152 while (name != NULL || argc > 0) {
153 if (name == NULL) {
154 if (!tflag && tmpdir != NULL)
155 asprintf(&name, "%s/%s", tmpdir, argv[0]);
156 else
157 name = strdup(argv[0]);
158 if (name == NULL)
159 err(1, "%s", argv[0]);
160 argv++;
161 argc--;
162 }
163
164 if (dflag) {
165 if (mkdtemp(name) == NULL) {
166 ret = 1;
167 if (!qflag)
168 warn("mkdtemp failed on %s", name);
169 } else {
170 printf("%s\n", name);
171 if (uflag)
172 rmdir(name);
173 }
174 } else {
175 fd = mkstemp(name);
176 if (fd < 0) {
177 ret = 1;
178 if (!qflag)
179 warn("mkstemp failed on %s", name);
180 } else {
181 close(fd);
182 if (uflag)
183 unlink(name);
184 printf("%s\n", name);
185 }
186 }
187 if (name)
188 free(name);
189 name = NULL;
190 }
191 return (ret);
192 }
193
194 static void
usage(void)195 usage(void)
196 {
197 fprintf(stderr,
198 "usage: mktemp [-d] [-p tmpdir] [-q] [-t prefix] [-u] template "
199 "...\n");
200 fprintf(stderr,
201 " mktemp [-d] [-p tmpdir] [-q] [-u] -t prefix \n");
202 exit (1);
203 }
204