]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.bin/mktemp/mktemp.c
Merge bmake-20230622
[FreeBSD/FreeBSD.git] / usr.bin / mktemp / mktemp.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 1994, 1995, 1996, 1998 Peter Wemm <peter@netplex.com.au>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  *
28  */
29
30 /*
31  * This program was originally written long ago, originally for a non
32  * BSD-like OS without mkstemp().  It's been modified over the years
33  * to use mkstemp() rather than the original O_CREAT|O_EXCL/fstat/lstat
34  * etc style hacks.
35  * A cleanup, misc options and mkdtemp() calls were added to try and work
36  * more like the OpenBSD version - which was first to publish the interface.
37  */
38
39 #include <err.h>
40 #include <getopt.h>
41 #include <paths.h>
42 #include <stdbool.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <unistd.h>
47
48 #ifndef lint
49 static const char rcsid[] =
50         "$FreeBSD$";
51 #endif /* not lint */
52
53 static void usage(void);
54
55 static const struct option long_opts[] = {
56         {"directory",   no_argument,    NULL,   'd'},
57         {"tmpdir",      optional_argument,      NULL,   'p'},
58         {"quiet",       no_argument,    NULL,   'q'},
59         {"dry-run",     no_argument,    NULL,   'u'},
60         {NULL,          no_argument,    NULL,   0},
61 };
62
63 int
64 main(int argc, char **argv)
65 {
66         int c, fd, ret;
67         const char *prefix, *tmpdir;
68         char *name;
69         int dflag, qflag, tflag, uflag;
70         bool prefer_tmpdir;
71
72         ret = dflag = qflag = tflag = uflag = 0;
73         prefer_tmpdir = true;
74         prefix = "mktemp";
75         name = NULL;
76         tmpdir = NULL;
77
78         while ((c = getopt_long(argc, argv, "dp:qt:u", long_opts, NULL)) != -1)
79                 switch (c) {
80                 case 'd':
81                         dflag++;
82                         break;
83
84                 case 'p':
85                         tmpdir = optarg;
86                         if (tmpdir == NULL || *tmpdir == '\0')
87                                 tmpdir = getenv("TMPDIR");
88
89                         /*
90                          * We've already done the necessary environment
91                          * fallback, skip the later one.
92                          */
93                         prefer_tmpdir = false;
94                         break;
95
96                 case 'q':
97                         qflag++;
98                         break;
99
100                 case 't':
101                         prefix = optarg;
102                         tflag++;
103                         break;
104
105                 case 'u':
106                         uflag++;
107                         break;
108
109                 default:
110                         usage();
111                 }
112
113         argc -= optind;
114         argv += optind;
115
116         if (!tflag && argc < 1) {
117                 tflag = 1;
118                 prefix = "tmp";
119
120                 /*
121                  * For this implied -t mode, we actually want to swap the usual
122                  * order of precedence: -p, then TMPDIR, then /tmp.
123                  */
124                 prefer_tmpdir = false;
125         }
126
127         if (tflag) {
128                 const char *envtmp;
129                 size_t len;
130
131                 envtmp = NULL;
132
133                 /*
134                  * $TMPDIR preferred over `-p` if specified, for compatibility.
135                  */
136                 if (prefer_tmpdir || tmpdir == NULL)
137                         envtmp = getenv("TMPDIR");
138                 if (envtmp != NULL)
139                         tmpdir = envtmp;
140                 if (tmpdir == NULL)
141                         tmpdir = _PATH_TMP;
142                 len = strlen(tmpdir);
143                 if (len > 0 && tmpdir[len - 1] == '/')
144                         asprintf(&name, "%s%s.XXXXXXXXXX", tmpdir, prefix);
145                 else
146                         asprintf(&name, "%s/%s.XXXXXXXXXX", tmpdir, prefix);
147                 /* if this fails, the program is in big trouble already */
148                 if (name == NULL) {
149                         if (qflag)
150                                 return (1);
151                         else
152                                 errx(1, "cannot generate template");
153                 }
154         }
155
156         /* generate all requested files */
157         while (name != NULL || argc > 0) {
158                 if (name == NULL) {
159                         if (!tflag && tmpdir != NULL)
160                                 asprintf(&name, "%s/%s", tmpdir, argv[0]);
161                         else
162                                 name = strdup(argv[0]);
163                         if (name == NULL)
164                                 err(1, "%s", argv[0]);
165                         argv++;
166                         argc--;
167                 }
168
169                 if (dflag) {
170                         if (mkdtemp(name) == NULL) {
171                                 ret = 1;
172                                 if (!qflag)
173                                         warn("mkdtemp failed on %s", name);
174                         } else {
175                                 printf("%s\n", name);
176                                 if (uflag)
177                                         rmdir(name);
178                         }
179                 } else {
180                         fd = mkstemp(name);
181                         if (fd < 0) {
182                                 ret = 1;
183                                 if (!qflag)
184                                         warn("mkstemp failed on %s", name);
185                         } else {
186                                 close(fd);
187                                 if (uflag)
188                                         unlink(name);
189                                 printf("%s\n", name);
190                         }
191                 }
192                 if (name)
193                         free(name);
194                 name = NULL;
195         }
196         return (ret);
197 }
198
199 static void
200 usage(void)
201 {
202         fprintf(stderr,
203                 "usage: mktemp [-d] [-p tmpdir] [-q] [-t prefix] [-u] template "
204                 "...\n");
205         fprintf(stderr,
206                 "       mktemp [-d] [-p tmpdir] [-q] [-u] -t prefix \n");
207         exit (1);
208 }