xref: /freebsd/usr.bin/mktemp/mktemp.c (revision eba230afba4932f02a1ca44efc797cf7499a5cb0)
14ca332d5SPeter Wemm /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
31de7b4b8SPedro F. Giffuni  *
44ca332d5SPeter Wemm  * Copyright (c) 1994, 1995, 1996, 1998 Peter Wemm <peter@netplex.com.au>
54ca332d5SPeter Wemm  * All rights reserved.
64ca332d5SPeter Wemm  *
74ca332d5SPeter Wemm  * Redistribution and use in source and binary forms, with or without
84ca332d5SPeter Wemm  * modification, are permitted provided that the following conditions
94ca332d5SPeter Wemm  * are met:
104ca332d5SPeter Wemm  * 1. Redistributions of source code must retain the above copyright
114ca332d5SPeter Wemm  *    notice, this list of conditions and the following disclaimer.
124ca332d5SPeter Wemm  * 2. Redistributions in binary form must reproduce the above copyright
134ca332d5SPeter Wemm  *    notice, this list of conditions and the following disclaimer in the
144ca332d5SPeter Wemm  *    documentation and/or other materials provided with the distribution.
154ca332d5SPeter Wemm  *
164ca332d5SPeter Wemm  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
174ca332d5SPeter Wemm  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
184ca332d5SPeter Wemm  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
194ca332d5SPeter Wemm  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
204ca332d5SPeter Wemm  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
214ca332d5SPeter Wemm  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
224ca332d5SPeter Wemm  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
234ca332d5SPeter Wemm  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
244ca332d5SPeter Wemm  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
254ca332d5SPeter Wemm  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
264ca332d5SPeter Wemm  * SUCH DAMAGE.
274ca332d5SPeter Wemm  *
284ca332d5SPeter Wemm  */
294ca332d5SPeter Wemm 
304ca332d5SPeter Wemm /*
314ca332d5SPeter Wemm  * This program was originally written long ago, originally for a non
324ca332d5SPeter Wemm  * BSD-like OS without mkstemp().  It's been modified over the years
334ca332d5SPeter Wemm  * to use mkstemp() rather than the original O_CREAT|O_EXCL/fstat/lstat
344ca332d5SPeter Wemm  * etc style hacks.
354ca332d5SPeter Wemm  * A cleanup, misc options and mkdtemp() calls were added to try and work
364ca332d5SPeter Wemm  * more like the OpenBSD version - which was first to publish the interface.
374ca332d5SPeter Wemm  */
384ca332d5SPeter Wemm 
39d4eaae7aSPhilippe Charnier #include <err.h>
40cfc57d7dSKyle Evans #include <getopt.h>
41d4eaae7aSPhilippe Charnier #include <paths.h>
42ac6f924eSKyle Evans #include <stdbool.h>
434ca332d5SPeter Wemm #include <stdio.h>
444ca332d5SPeter Wemm #include <stdlib.h>
454ca332d5SPeter Wemm #include <string.h>
46d4eaae7aSPhilippe Charnier #include <unistd.h>
47d4eaae7aSPhilippe Charnier 
48*1a7ac2bdSAlfonso Gregory static void usage(void) __dead2;
494ca332d5SPeter Wemm 
50cfc57d7dSKyle Evans static const struct option long_opts[] = {
51cfc57d7dSKyle Evans 	{"directory",	no_argument,	NULL,	'd'},
52ac6f924eSKyle Evans 	{"tmpdir",	optional_argument,	NULL,	'p'},
53cfc57d7dSKyle Evans 	{"quiet",	no_argument,	NULL,	'q'},
54cfc57d7dSKyle Evans 	{"dry-run",	no_argument,	NULL,	'u'},
55cfc57d7dSKyle Evans 	{NULL,		no_argument,	NULL,	0},
56cfc57d7dSKyle Evans };
57cfc57d7dSKyle Evans 
584ca332d5SPeter Wemm int
main(int argc,char ** argv)594ca332d5SPeter Wemm main(int argc, char **argv)
604ca332d5SPeter Wemm {
614ca332d5SPeter Wemm 	int c, fd, ret;
62ac6f924eSKyle Evans 	const char *prefix, *tmpdir;
634ca332d5SPeter Wemm 	char *name;
644ca332d5SPeter Wemm 	int dflag, qflag, tflag, uflag;
65ac6f924eSKyle Evans 	bool prefer_tmpdir;
664ca332d5SPeter Wemm 
674ca332d5SPeter Wemm 	ret = dflag = qflag = tflag = uflag = 0;
68ac6f924eSKyle Evans 	prefer_tmpdir = true;
69d4eaae7aSPhilippe Charnier 	prefix = "mktemp";
704ca332d5SPeter Wemm 	name = NULL;
71ac6f924eSKyle Evans 	tmpdir = NULL;
724ca332d5SPeter Wemm 
73ac6f924eSKyle Evans 	while ((c = getopt_long(argc, argv, "dp:qt:u", long_opts, NULL)) != -1)
744ca332d5SPeter Wemm 		switch (c) {
754ca332d5SPeter Wemm 		case 'd':
764ca332d5SPeter Wemm 			dflag++;
774ca332d5SPeter Wemm 			break;
784ca332d5SPeter Wemm 
79ac6f924eSKyle Evans 		case 'p':
80ac6f924eSKyle Evans 			tmpdir = optarg;
81ac6f924eSKyle Evans 			if (tmpdir == NULL || *tmpdir == '\0')
82ac6f924eSKyle Evans 				tmpdir = getenv("TMPDIR");
83d22f0363SKyle Evans 
84d22f0363SKyle Evans 			/*
85d22f0363SKyle Evans 			 * We've already done the necessary environment
86d22f0363SKyle Evans 			 * fallback, skip the later one.
87d22f0363SKyle Evans 			 */
88d22f0363SKyle Evans 			prefer_tmpdir = false;
89ac6f924eSKyle Evans 			break;
90ac6f924eSKyle Evans 
914ca332d5SPeter Wemm 		case 'q':
924ca332d5SPeter Wemm 			qflag++;
934ca332d5SPeter Wemm 			break;
944ca332d5SPeter Wemm 
954ca332d5SPeter Wemm 		case 't':
964ca332d5SPeter Wemm 			prefix = optarg;
974ca332d5SPeter Wemm 			tflag++;
984ca332d5SPeter Wemm 			break;
994ca332d5SPeter Wemm 
1004ca332d5SPeter Wemm 		case 'u':
1014ca332d5SPeter Wemm 			uflag++;
1024ca332d5SPeter Wemm 			break;
1034ca332d5SPeter Wemm 
1044ca332d5SPeter Wemm 		default:
105d4eaae7aSPhilippe Charnier 			usage();
1064ca332d5SPeter Wemm 		}
1074ca332d5SPeter Wemm 
1084ca332d5SPeter Wemm 	argc -= optind;
1094ca332d5SPeter Wemm 	argv += optind;
1104ca332d5SPeter Wemm 
1118e0079a0SEitan Adler 	if (!tflag && argc < 1) {
1128e0079a0SEitan Adler 		tflag = 1;
1138e0079a0SEitan Adler 		prefix = "tmp";
114ac6f924eSKyle Evans 
115ac6f924eSKyle Evans 		/*
116ac6f924eSKyle Evans 		 * For this implied -t mode, we actually want to swap the usual
117ac6f924eSKyle Evans 		 * order of precedence: -p, then TMPDIR, then /tmp.
118ac6f924eSKyle Evans 		 */
119ac6f924eSKyle Evans 		prefer_tmpdir = false;
1208e0079a0SEitan Adler 	}
1218e0079a0SEitan Adler 
1224ca332d5SPeter Wemm 	if (tflag) {
123ac6f924eSKyle Evans 		const char *envtmp;
124a6346c02SKyle Evans 		size_t len;
125ac6f924eSKyle Evans 
126ac6f924eSKyle Evans 		envtmp = NULL;
127ac6f924eSKyle Evans 
128ac6f924eSKyle Evans 		/*
129ac6f924eSKyle Evans 		 * $TMPDIR preferred over `-p` if specified, for compatibility.
130ac6f924eSKyle Evans 		 */
131ac6f924eSKyle Evans 		if (prefer_tmpdir || tmpdir == NULL)
132ac6f924eSKyle Evans 			envtmp = getenv("TMPDIR");
133ac6f924eSKyle Evans 		if (envtmp != NULL)
134ac6f924eSKyle Evans 			tmpdir = envtmp;
1354ca332d5SPeter Wemm 		if (tmpdir == NULL)
136a6346c02SKyle Evans 			tmpdir = _PATH_TMP;
137a6346c02SKyle Evans 		len = strlen(tmpdir);
138a6346c02SKyle Evans 		if (len > 0 && tmpdir[len - 1] == '/')
139a6346c02SKyle Evans 			asprintf(&name, "%s%s.XXXXXXXXXX", tmpdir, prefix);
1404ca332d5SPeter Wemm 		else
14198839c40SWolfram Schneider 			asprintf(&name, "%s/%s.XXXXXXXXXX", tmpdir, prefix);
1424ca332d5SPeter Wemm 		/* if this fails, the program is in big trouble already */
1434ca332d5SPeter Wemm 		if (name == NULL) {
1444ca332d5SPeter Wemm 			if (qflag)
1454ca332d5SPeter Wemm 				return (1);
1464ca332d5SPeter Wemm 			else
147d4eaae7aSPhilippe Charnier 				errx(1, "cannot generate template");
1484ca332d5SPeter Wemm 		}
1494ca332d5SPeter Wemm 	}
1504ca332d5SPeter Wemm 
1514ca332d5SPeter Wemm 	/* generate all requested files */
1524ca332d5SPeter Wemm 	while (name != NULL || argc > 0) {
1534ca332d5SPeter Wemm 		if (name == NULL) {
154ac6f924eSKyle Evans 			if (!tflag && tmpdir != NULL)
155ac6f924eSKyle Evans 				asprintf(&name, "%s/%s", tmpdir, argv[0]);
156ac6f924eSKyle Evans 			else
1574ca332d5SPeter Wemm 				name = strdup(argv[0]);
158ac6f924eSKyle Evans 			if (name == NULL)
159ac6f924eSKyle Evans 				err(1, "%s", argv[0]);
1604ca332d5SPeter Wemm 			argv++;
1614ca332d5SPeter Wemm 			argc--;
1624ca332d5SPeter Wemm 		}
1634ca332d5SPeter Wemm 
1644ca332d5SPeter Wemm 		if (dflag) {
1654ca332d5SPeter Wemm 			if (mkdtemp(name) == NULL) {
1664ca332d5SPeter Wemm 				ret = 1;
1674ca332d5SPeter Wemm 				if (!qflag)
1684ca332d5SPeter Wemm 					warn("mkdtemp failed on %s", name);
1694ca332d5SPeter Wemm 			} else {
1704ca332d5SPeter Wemm 				printf("%s\n", name);
1714ca332d5SPeter Wemm 				if (uflag)
1724ca332d5SPeter Wemm 					rmdir(name);
1734ca332d5SPeter Wemm 			}
1744ca332d5SPeter Wemm 		} else {
1754ca332d5SPeter Wemm 			fd = mkstemp(name);
1764ca332d5SPeter Wemm 			if (fd < 0) {
1774ca332d5SPeter Wemm 				ret = 1;
1784ca332d5SPeter Wemm 				if (!qflag)
1794ca332d5SPeter Wemm 					warn("mkstemp failed on %s", name);
1804ca332d5SPeter Wemm 			} else {
1814ca332d5SPeter Wemm 				close(fd);
1824ca332d5SPeter Wemm 				if (uflag)
1834ca332d5SPeter Wemm 					unlink(name);
1844ca332d5SPeter Wemm 				printf("%s\n", name);
1854ca332d5SPeter Wemm 			}
1864ca332d5SPeter Wemm 		}
1874ca332d5SPeter Wemm 		if (name)
1884ca332d5SPeter Wemm 			free(name);
1894ca332d5SPeter Wemm 		name = NULL;
1904ca332d5SPeter Wemm 	}
1914ca332d5SPeter Wemm 	return (ret);
1924ca332d5SPeter Wemm }
193d4eaae7aSPhilippe Charnier 
194d4eaae7aSPhilippe Charnier static void
usage(void)1957d0d4ebcSXin LI usage(void)
196d4eaae7aSPhilippe Charnier {
197d4eaae7aSPhilippe Charnier 	fprintf(stderr,
198ac6f924eSKyle Evans 		"usage: mktemp [-d] [-p tmpdir] [-q] [-t prefix] [-u] template "
199ac6f924eSKyle Evans 		"...\n");
200c0206f33SAlexander Langer 	fprintf(stderr,
201ac6f924eSKyle Evans 		"       mktemp [-d] [-p tmpdir] [-q] [-u] -t prefix \n");
202d4eaae7aSPhilippe Charnier 	exit (1);
203d4eaae7aSPhilippe Charnier }
204