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