xref: /openbsd/usr.bin/mktemp/mktemp.c (revision ec6f9a74)
1*ec6f9a74Smillert /*	$OpenBSD: mktemp.c,v 1.26 2024/03/01 21:50:40 millert Exp $	*/
25d2a10fbSmillert 
35d2a10fbSmillert /*
40bc28667Smillert  * Copyright (c) 1996, 1997, 2001-2003, 2013
5bf198cc6Smillert  *	Todd C. Miller <millert@openbsd.org>
65d2a10fbSmillert  *
706f01696Smillert  * Permission to use, copy, modify, and distribute this software for any
806f01696Smillert  * purpose with or without fee is hereby granted, provided that the above
906f01696Smillert  * copyright notice and this permission notice appear in all copies.
105d2a10fbSmillert  *
11328f1f07Smillert  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12328f1f07Smillert  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13328f1f07Smillert  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14328f1f07Smillert  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15328f1f07Smillert  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16328f1f07Smillert  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17328f1f07Smillert  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
185d2a10fbSmillert  */
195d2a10fbSmillert 
203be362b6Smillert #include <err.h>
2101596bb8Smillert #include <paths.h>
223be362b6Smillert #include <stdarg.h>
235d2a10fbSmillert #include <stdio.h>
245d2a10fbSmillert #include <stdlib.h>
255d2a10fbSmillert #include <string.h>
265d2a10fbSmillert #include <unistd.h>
275d2a10fbSmillert 
28c72b5b24Smillert __dead void usage(void);
293be362b6Smillert __dead void fatal(const char *, ...) __attribute__((__format__(printf, 1, 2)));
303be362b6Smillert __dead void fatalx(const char *, ...) __attribute__((__format__(printf, 1, 2)));
313be362b6Smillert 
323be362b6Smillert static int quiet;
335d2a10fbSmillert 
345d2a10fbSmillert int
main(int argc,char * argv[])351837a5caSderaadt main(int argc, char *argv[])
365d2a10fbSmillert {
373be362b6Smillert 	int ch, fd, uflag = 0, tflag = 0, makedir = 0;
38*ec6f9a74Smillert 	char *base, *cp, *template, *tempfile, *prefix = _PATH_TMP;
39*ec6f9a74Smillert 	size_t len, suffixlen = 0;
405d2a10fbSmillert 
410bd1216cSderaadt 	if (pledge("stdio rpath wpath cpath", NULL) == -1)
420bd1216cSderaadt 		err(1, "pledge");
439e824d36Sderaadt 
4401596bb8Smillert 	while ((ch = getopt(argc, argv, "dp:qtu")) != -1)
4501596bb8Smillert 		switch(ch) {
469a2404e3Smillert 		case 'd':
479a2404e3Smillert 			makedir = 1;
485d2a10fbSmillert 			break;
4901596bb8Smillert 		case 'p':
5001596bb8Smillert 			prefix = optarg;
5101596bb8Smillert 			tflag = 1;
5201596bb8Smillert 			break;
535d2a10fbSmillert 		case 'q':
541e9e26e9Smillert 			quiet = 1;
555d2a10fbSmillert 			break;
5601596bb8Smillert 		case 't':
5701596bb8Smillert 			tflag = 1;
5801596bb8Smillert 			break;
599a2404e3Smillert 		case 'u':
609a2404e3Smillert 			uflag = 1;
619a2404e3Smillert 			break;
625d2a10fbSmillert 		default:
635d2a10fbSmillert 			usage();
645d2a10fbSmillert 	}
655d2a10fbSmillert 
661e9e26e9Smillert 	/* If no template specified use a default one (implies -t mode) */
671e9e26e9Smillert 	switch (argc - optind) {
681e9e26e9Smillert 	case 1:
691e9e26e9Smillert 		template = argv[optind];
701e9e26e9Smillert 		break;
711e9e26e9Smillert 	case 0:
721e9e26e9Smillert 		template = "tmp.XXXXXXXXXX";
731e9e26e9Smillert 		tflag = 1;
741e9e26e9Smillert 		break;
751e9e26e9Smillert 	default:
765d2a10fbSmillert 		usage();
771e9e26e9Smillert 	}
785d2a10fbSmillert 
79*ec6f9a74Smillert 	base = strrchr(template, '/');
80*ec6f9a74Smillert 	if (base != NULL)
81*ec6f9a74Smillert 		base++;
82*ec6f9a74Smillert 	else
83*ec6f9a74Smillert 		base = template;
84*ec6f9a74Smillert 	len = strlen(base);
85*ec6f9a74Smillert 	if (len > 0 && base[len - 1] != 'X') {
86*ec6f9a74Smillert 		/* Check for suffix, e.g. /tmp/XXXXXX.foo in last component. */
87*ec6f9a74Smillert 		for (suffixlen = 0; suffixlen < len; suffixlen++) {
88*ec6f9a74Smillert 			if (base[len - suffixlen - 1] == 'X')
89*ec6f9a74Smillert 				break;
90*ec6f9a74Smillert 		}
91*ec6f9a74Smillert 	}
92*ec6f9a74Smillert 	if (len - suffixlen < 6 ||
93*ec6f9a74Smillert 	    strncmp(&base[len - suffixlen - 6], "XXXXXX", 6)) {
94c4ace12dSlandry 		fatalx("insufficient number of Xs in template `%s'",
95c4ace12dSlandry 		    template);
96c4ace12dSlandry 	}
9701596bb8Smillert 	if (tflag) {
98*ec6f9a74Smillert 		if (base != template) {
993be362b6Smillert 			fatalx("template must not contain directory "
100fb83f4f8Smillert 			    "separators in -t mode");
10101596bb8Smillert 		}
10201596bb8Smillert 
10301596bb8Smillert 		cp = getenv("TMPDIR");
10401596bb8Smillert 		if (cp != NULL && *cp != '\0')
10501596bb8Smillert 			prefix = cp;
1060bc28667Smillert 		len = strlen(prefix);
1070bc28667Smillert 		while (len != 0 && prefix[len - 1] == '/')
1080bc28667Smillert 			len--;
10901596bb8Smillert 
11095af8abfSderaadt 		if (asprintf(&tempfile, "%.*s/%s", (int)len, prefix, template) == -1)
111fb83f4f8Smillert 			tempfile = NULL;
112c4ace12dSlandry 	} else
113fb83f4f8Smillert 		tempfile = strdup(template);
114c4ace12dSlandry 
1153be362b6Smillert 	if (tempfile == NULL)
1163be362b6Smillert 		fatalx("cannot allocate memory");
1175d2a10fbSmillert 
1189a2404e3Smillert 	if (makedir) {
119*ec6f9a74Smillert 		if (mkdtemps(tempfile, suffixlen) == NULL)
1203be362b6Smillert 			fatal("cannot make temp dir %s", tempfile);
1219a2404e3Smillert 		if (uflag)
1221e9e26e9Smillert 			(void)rmdir(tempfile);
1239a2404e3Smillert 	} else {
124*ec6f9a74Smillert 		if ((fd = mkstemps(tempfile, suffixlen)) == -1)
1253be362b6Smillert 			fatal("cannot make temp file %s", tempfile);
1261e9e26e9Smillert 		(void)close(fd);
1275d2a10fbSmillert 		if (uflag)
1281e9e26e9Smillert 			(void)unlink(tempfile);
1299a2404e3Smillert 	}
1305d2a10fbSmillert 
1311e9e26e9Smillert 	(void)puts(tempfile);
1321e9e26e9Smillert 	free(tempfile);
1335d2a10fbSmillert 
134*ec6f9a74Smillert 	return EXIT_SUCCESS;
1353be362b6Smillert }
1363be362b6Smillert 
1373be362b6Smillert __dead void
fatal(const char * fmt,...)1383be362b6Smillert fatal(const char *fmt, ...)
1393be362b6Smillert {
1403be362b6Smillert 	if (!quiet) {
1413be362b6Smillert 		va_list ap;
1423be362b6Smillert 
1433be362b6Smillert 		va_start(ap, fmt);
1443be362b6Smillert 		vwarn(fmt, ap);
1453be362b6Smillert 		va_end(ap);
1463be362b6Smillert 	}
1473be362b6Smillert 	exit(EXIT_FAILURE);
1483be362b6Smillert }
1493be362b6Smillert 
1503be362b6Smillert __dead void
fatalx(const char * fmt,...)1513be362b6Smillert fatalx(const char *fmt, ...)
1523be362b6Smillert {
1533be362b6Smillert 	if (!quiet) {
1543be362b6Smillert 		va_list ap;
1553be362b6Smillert 
1563be362b6Smillert 		va_start(ap, fmt);
1573be362b6Smillert 		vwarnx(fmt, ap);
1583be362b6Smillert 		va_end(ap);
1593be362b6Smillert 	}
1603be362b6Smillert 	exit(EXIT_FAILURE);
1615d2a10fbSmillert }
1621e9e26e9Smillert 
1631e9e26e9Smillert __dead void
usage(void)1641837a5caSderaadt usage(void)
1651e9e26e9Smillert {
1661e9e26e9Smillert 	extern char *__progname;
1671e9e26e9Smillert 
1681e9e26e9Smillert 	(void)fprintf(stderr,
16906cbb4e0Ssobrado 	    "usage: %s [-dqtu] [-p directory] [template]\n", __progname);
1703be362b6Smillert 	exit(EXIT_FAILURE);
1711e9e26e9Smillert }
172