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 #ifndef lint 49 static const char rcsid[] = 50 "$FreeBSD$"; 51 #endif /* not lint */ 52 53 static void usage(void) __dead2; 54 55 static const struct option long_opts[] = { 56 {"directory", no_argument, NULL, 'd'}, 57 {"tmpdir", optional_argument, NULL, 'p'}, 58 {"quiet", no_argument, NULL, 'q'}, 59 {"dry-run", no_argument, NULL, 'u'}, 60 {NULL, no_argument, NULL, 0}, 61 }; 62 63 int 64 main(int argc, char **argv) 65 { 66 int c, fd, ret; 67 const char *prefix, *tmpdir; 68 char *name; 69 int dflag, qflag, tflag, uflag; 70 bool prefer_tmpdir; 71 72 ret = dflag = qflag = tflag = uflag = 0; 73 prefer_tmpdir = true; 74 prefix = "mktemp"; 75 name = NULL; 76 tmpdir = NULL; 77 78 while ((c = getopt_long(argc, argv, "dp:qt:u", long_opts, NULL)) != -1) 79 switch (c) { 80 case 'd': 81 dflag++; 82 break; 83 84 case 'p': 85 tmpdir = optarg; 86 if (tmpdir == NULL || *tmpdir == '\0') 87 tmpdir = getenv("TMPDIR"); 88 89 /* 90 * We've already done the necessary environment 91 * fallback, skip the later one. 92 */ 93 prefer_tmpdir = false; 94 break; 95 96 case 'q': 97 qflag++; 98 break; 99 100 case 't': 101 prefix = optarg; 102 tflag++; 103 break; 104 105 case 'u': 106 uflag++; 107 break; 108 109 default: 110 usage(); 111 } 112 113 argc -= optind; 114 argv += optind; 115 116 if (!tflag && argc < 1) { 117 tflag = 1; 118 prefix = "tmp"; 119 120 /* 121 * For this implied -t mode, we actually want to swap the usual 122 * order of precedence: -p, then TMPDIR, then /tmp. 123 */ 124 prefer_tmpdir = false; 125 } 126 127 if (tflag) { 128 const char *envtmp; 129 size_t len; 130 131 envtmp = NULL; 132 133 /* 134 * $TMPDIR preferred over `-p` if specified, for compatibility. 135 */ 136 if (prefer_tmpdir || tmpdir == NULL) 137 envtmp = getenv("TMPDIR"); 138 if (envtmp != NULL) 139 tmpdir = envtmp; 140 if (tmpdir == NULL) 141 tmpdir = _PATH_TMP; 142 len = strlen(tmpdir); 143 if (len > 0 && tmpdir[len - 1] == '/') 144 asprintf(&name, "%s%s.XXXXXXXXXX", tmpdir, prefix); 145 else 146 asprintf(&name, "%s/%s.XXXXXXXXXX", tmpdir, prefix); 147 /* if this fails, the program is in big trouble already */ 148 if (name == NULL) { 149 if (qflag) 150 return (1); 151 else 152 errx(1, "cannot generate template"); 153 } 154 } 155 156 /* generate all requested files */ 157 while (name != NULL || argc > 0) { 158 if (name == NULL) { 159 if (!tflag && tmpdir != NULL) 160 asprintf(&name, "%s/%s", tmpdir, argv[0]); 161 else 162 name = strdup(argv[0]); 163 if (name == NULL) 164 err(1, "%s", argv[0]); 165 argv++; 166 argc--; 167 } 168 169 if (dflag) { 170 if (mkdtemp(name) == NULL) { 171 ret = 1; 172 if (!qflag) 173 warn("mkdtemp failed on %s", name); 174 } else { 175 printf("%s\n", name); 176 if (uflag) 177 rmdir(name); 178 } 179 } else { 180 fd = mkstemp(name); 181 if (fd < 0) { 182 ret = 1; 183 if (!qflag) 184 warn("mkstemp failed on %s", name); 185 } else { 186 close(fd); 187 if (uflag) 188 unlink(name); 189 printf("%s\n", name); 190 } 191 } 192 if (name) 193 free(name); 194 name = NULL; 195 } 196 return (ret); 197 } 198 199 static void 200 usage(void) 201 { 202 fprintf(stderr, 203 "usage: mktemp [-d] [-p tmpdir] [-q] [-t prefix] [-u] template " 204 "...\n"); 205 fprintf(stderr, 206 " mktemp [-d] [-p tmpdir] [-q] [-u] -t prefix \n"); 207 exit (1); 208 } 209