1 /* $OpenBSD: mktemp.c,v 1.25 2019/06/28 05:35:34 deraadt 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 *cp, *template, *tempfile, *prefix = _PATH_TMP; 39 size_t len; 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 len = strlen(template); 80 if (len < 6 || strcmp(&template[len - 6], "XXXXXX")) { 81 fatalx("insufficient number of Xs in template `%s'", 82 template); 83 } 84 if (tflag) { 85 if (strchr(template, '/')) { 86 fatalx("template must not contain directory " 87 "separators in -t mode"); 88 } 89 90 cp = getenv("TMPDIR"); 91 if (cp != NULL && *cp != '\0') 92 prefix = cp; 93 len = strlen(prefix); 94 while (len != 0 && prefix[len - 1] == '/') 95 len--; 96 97 if (asprintf(&tempfile, "%.*s/%s", (int)len, prefix, template) == -1) 98 tempfile = NULL; 99 } else 100 tempfile = strdup(template); 101 102 if (tempfile == NULL) 103 fatalx("cannot allocate memory"); 104 105 if (makedir) { 106 if (mkdtemp(tempfile) == NULL) 107 fatal("cannot make temp dir %s", tempfile); 108 if (uflag) 109 (void)rmdir(tempfile); 110 } else { 111 if ((fd = mkstemp(tempfile)) == -1) 112 fatal("cannot make temp file %s", tempfile); 113 (void)close(fd); 114 if (uflag) 115 (void)unlink(tempfile); 116 } 117 118 (void)puts(tempfile); 119 free(tempfile); 120 121 exit(EXIT_SUCCESS); 122 } 123 124 __dead void 125 fatal(const char *fmt, ...) 126 { 127 if (!quiet) { 128 va_list ap; 129 130 va_start(ap, fmt); 131 vwarn(fmt, ap); 132 va_end(ap); 133 } 134 exit(EXIT_FAILURE); 135 } 136 137 __dead void 138 fatalx(const char *fmt, ...) 139 { 140 if (!quiet) { 141 va_list ap; 142 143 va_start(ap, fmt); 144 vwarnx(fmt, ap); 145 va_end(ap); 146 } 147 exit(EXIT_FAILURE); 148 } 149 150 __dead void 151 usage(void) 152 { 153 extern char *__progname; 154 155 (void)fprintf(stderr, 156 "usage: %s [-dqtu] [-p directory] [template]\n", __progname); 157 exit(EXIT_FAILURE); 158 } 159