1 /* $OpenBSD: mktemp.c,v 1.26 2024/03/01 21:50:40 millert Exp $ */ 2 3 /* 4 * Copyright (c) 1996, 1997, 2001-2003, 2013 5 * Todd C. Miller <millert@openbsd.org> 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 #include <err.h> 21 #include <paths.h> 22 #include <stdarg.h> 23 #include <stdio.h> 24 #include <stdlib.h> 25 #include <string.h> 26 #include <unistd.h> 27 28 __dead void usage(void); 29 __dead void fatal(const char *, ...) __attribute__((__format__(printf, 1, 2))); 30 __dead void fatalx(const char *, ...) __attribute__((__format__(printf, 1, 2))); 31 32 static int quiet; 33 34 int 35 main(int argc, char *argv[]) 36 { 37 int ch, fd, uflag = 0, tflag = 0, makedir = 0; 38 char *base, *cp, *template, *tempfile, *prefix = _PATH_TMP; 39 size_t len, suffixlen = 0; 40 41 if (pledge("stdio rpath wpath cpath", NULL) == -1) 42 err(1, "pledge"); 43 44 while ((ch = getopt(argc, argv, "dp:qtu")) != -1) 45 switch(ch) { 46 case 'd': 47 makedir = 1; 48 break; 49 case 'p': 50 prefix = optarg; 51 tflag = 1; 52 break; 53 case 'q': 54 quiet = 1; 55 break; 56 case 't': 57 tflag = 1; 58 break; 59 case 'u': 60 uflag = 1; 61 break; 62 default: 63 usage(); 64 } 65 66 /* If no template specified use a default one (implies -t mode) */ 67 switch (argc - optind) { 68 case 1: 69 template = argv[optind]; 70 break; 71 case 0: 72 template = "tmp.XXXXXXXXXX"; 73 tflag = 1; 74 break; 75 default: 76 usage(); 77 } 78 79 base = strrchr(template, '/'); 80 if (base != NULL) 81 base++; 82 else 83 base = template; 84 len = strlen(base); 85 if (len > 0 && base[len - 1] != 'X') { 86 /* Check for suffix, e.g. /tmp/XXXXXX.foo in last component. */ 87 for (suffixlen = 0; suffixlen < len; suffixlen++) { 88 if (base[len - suffixlen - 1] == 'X') 89 break; 90 } 91 } 92 if (len - suffixlen < 6 || 93 strncmp(&base[len - suffixlen - 6], "XXXXXX", 6)) { 94 fatalx("insufficient number of Xs in template `%s'", 95 template); 96 } 97 if (tflag) { 98 if (base != template) { 99 fatalx("template must not contain directory " 100 "separators in -t mode"); 101 } 102 103 cp = getenv("TMPDIR"); 104 if (cp != NULL && *cp != '\0') 105 prefix = cp; 106 len = strlen(prefix); 107 while (len != 0 && prefix[len - 1] == '/') 108 len--; 109 110 if (asprintf(&tempfile, "%.*s/%s", (int)len, prefix, template) == -1) 111 tempfile = NULL; 112 } else 113 tempfile = strdup(template); 114 115 if (tempfile == NULL) 116 fatalx("cannot allocate memory"); 117 118 if (makedir) { 119 if (mkdtemps(tempfile, suffixlen) == NULL) 120 fatal("cannot make temp dir %s", tempfile); 121 if (uflag) 122 (void)rmdir(tempfile); 123 } else { 124 if ((fd = mkstemps(tempfile, suffixlen)) == -1) 125 fatal("cannot make temp file %s", tempfile); 126 (void)close(fd); 127 if (uflag) 128 (void)unlink(tempfile); 129 } 130 131 (void)puts(tempfile); 132 free(tempfile); 133 134 return EXIT_SUCCESS; 135 } 136 137 __dead void 138 fatal(const char *fmt, ...) 139 { 140 if (!quiet) { 141 va_list ap; 142 143 va_start(ap, fmt); 144 vwarn(fmt, ap); 145 va_end(ap); 146 } 147 exit(EXIT_FAILURE); 148 } 149 150 __dead void 151 fatalx(const char *fmt, ...) 152 { 153 if (!quiet) { 154 va_list ap; 155 156 va_start(ap, fmt); 157 vwarnx(fmt, ap); 158 va_end(ap); 159 } 160 exit(EXIT_FAILURE); 161 } 162 163 __dead void 164 usage(void) 165 { 166 extern char *__progname; 167 168 (void)fprintf(stderr, 169 "usage: %s [-dqtu] [-p directory] [template]\n", __progname); 170 exit(EXIT_FAILURE); 171 } 172