1a7c91847Schristos /* tempname.c - generate the name of a temporary file.
2a7c91847Schristos
3a7c91847Schristos Copyright (C) 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
4a7c91847Schristos 2000, 2001, 2002, 2003, 2005 Free Software Foundation, Inc.
5a7c91847Schristos
6a7c91847Schristos This program is free software; you can redistribute it and/or modify
7a7c91847Schristos it under the terms of the GNU General Public License as published by
8a7c91847Schristos the Free Software Foundation; either version 2, or (at your option)
9a7c91847Schristos any later version.
10a7c91847Schristos
11a7c91847Schristos This program is distributed in the hope that it will be useful,
12a7c91847Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of
13a7c91847Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14a7c91847Schristos GNU General Public License for more details.
15a7c91847Schristos
16a7c91847Schristos You should have received a copy of the GNU General Public License along
17a7c91847Schristos with this program; if not, write to the Free Software Foundation,
18a7c91847Schristos Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
19*5a6c14c8Schristos #include <sys/cdefs.h>
20*5a6c14c8Schristos __RCSID("$NetBSD: tempname.c,v 1.2 2016/05/17 14:00:09 christos Exp $");
21*5a6c14c8Schristos
22a7c91847Schristos
23a7c91847Schristos #ifdef HAVE_CONFIG_H
24a7c91847Schristos # include <config.h>
25a7c91847Schristos #endif
26a7c91847Schristos
27a7c91847Schristos #include <sys/types.h>
28a7c91847Schristos #include <assert.h>
29a7c91847Schristos
30a7c91847Schristos #include <errno.h>
31a7c91847Schristos #ifndef __set_errno
32a7c91847Schristos # define __set_errno(Val) errno = (Val)
33a7c91847Schristos #endif
34a7c91847Schristos
35a7c91847Schristos #include <stdio.h>
36a7c91847Schristos #ifndef P_tmpdir
37a7c91847Schristos # define P_tmpdir "/tmp"
38a7c91847Schristos #endif
39a7c91847Schristos #ifndef TMP_MAX
40a7c91847Schristos # define TMP_MAX 238328
41a7c91847Schristos #endif
42a7c91847Schristos #ifndef __GT_FILE
43a7c91847Schristos # define __GT_FILE 0
44a7c91847Schristos # define __GT_BIGFILE 1
45a7c91847Schristos # define __GT_DIR 2
46a7c91847Schristos # define __GT_NOCREATE 3
47a7c91847Schristos #endif
48a7c91847Schristos
49a7c91847Schristos #include <stddef.h>
50a7c91847Schristos #include <stdlib.h>
51a7c91847Schristos #include <string.h>
52a7c91847Schristos
53a7c91847Schristos #include <fcntl.h>
54a7c91847Schristos
55a7c91847Schristos #if HAVE_SYS_TIME_H || _LIBC
56a7c91847Schristos # include <sys/time.h>
57a7c91847Schristos #endif
58a7c91847Schristos
59a7c91847Schristos #if HAVE_STDINT_H || _LIBC
60a7c91847Schristos # include <stdint.h>
61a7c91847Schristos #endif
62a7c91847Schristos #if HAVE_INTTYPES_H
63a7c91847Schristos # include <inttypes.h>
64a7c91847Schristos #endif
65a7c91847Schristos
66a7c91847Schristos #if HAVE_UNISTD_H || _LIBC
67a7c91847Schristos # include <unistd.h>
68a7c91847Schristos #endif
69a7c91847Schristos
70a7c91847Schristos #include <sys/stat.h>
71a7c91847Schristos
72a7c91847Schristos #if _LIBC
73a7c91847Schristos # define struct_stat64 struct stat64
74a7c91847Schristos #else
75a7c91847Schristos # include "stat-macros.h"
76a7c91847Schristos # define struct_stat64 struct stat
77a7c91847Schristos # define __getpid getpid
78a7c91847Schristos # define __gettimeofday gettimeofday
79a7c91847Schristos # define __mkdir mkdir
80a7c91847Schristos # define __open open
81a7c91847Schristos # define __open64 open
82a7c91847Schristos # define __lxstat64(version, file, buf) lstat (file, buf)
83a7c91847Schristos # define __xstat64(version, file, buf) stat (file, buf)
84a7c91847Schristos #endif
85a7c91847Schristos
86a7c91847Schristos #if ! (HAVE___SECURE_GETENV || _LIBC)
87a7c91847Schristos # define __secure_getenv getenv
88a7c91847Schristos #endif
89a7c91847Schristos
90a7c91847Schristos #ifdef _LIBC
91a7c91847Schristos # include <hp-timing.h>
92a7c91847Schristos # if HP_TIMING_AVAIL
93a7c91847Schristos # define RANDOM_BITS(Var) \
94a7c91847Schristos if (__builtin_expect (value == UINT64_C (0), 0)) \
95a7c91847Schristos { \
96a7c91847Schristos /* If this is the first time this function is used initialize \
97a7c91847Schristos the variable we accumulate the value in to some somewhat \
98a7c91847Schristos random value. If we'd not do this programs at startup time \
99a7c91847Schristos might have a reduced set of possible names, at least on slow \
100a7c91847Schristos machines. */ \
101a7c91847Schristos struct timeval tv; \
102a7c91847Schristos __gettimeofday (&tv, NULL); \
103a7c91847Schristos value = ((uint64_t) tv.tv_usec << 16) ^ tv.tv_sec; \
104a7c91847Schristos } \
105a7c91847Schristos HP_TIMING_NOW (Var)
106a7c91847Schristos # endif
107a7c91847Schristos #endif
108a7c91847Schristos
109a7c91847Schristos /* Use the widest available unsigned type if uint64_t is not
110a7c91847Schristos available. The algorithm below extracts a number less than 62**6
111a7c91847Schristos (approximately 2**35.725) from uint64_t, so ancient hosts where
112a7c91847Schristos uintmax_t is only 32 bits lose about 3.725 bits of randomness,
113a7c91847Schristos which is better than not having mkstemp at all. */
114a7c91847Schristos #if !defined UINT64_MAX && !defined uint64_t
115a7c91847Schristos # define uint64_t uintmax_t
116a7c91847Schristos #endif
117a7c91847Schristos
118a7c91847Schristos /* Return nonzero if DIR is an existent directory. */
119a7c91847Schristos static int
direxists(const char * dir)120a7c91847Schristos direxists (const char *dir)
121a7c91847Schristos {
122a7c91847Schristos struct_stat64 buf;
123a7c91847Schristos return __xstat64 (_STAT_VER, dir, &buf) == 0 && S_ISDIR (buf.st_mode);
124a7c91847Schristos }
125a7c91847Schristos
126a7c91847Schristos /* Path search algorithm, for tmpnam, tmpfile, etc. If DIR is
127a7c91847Schristos non-null and exists, uses it; otherwise uses the first of $TMPDIR,
128a7c91847Schristos P_tmpdir, /tmp that exists. Copies into TMPL a template suitable
129a7c91847Schristos for use with mk[s]temp. Will fail (-1) if DIR is non-null and
130a7c91847Schristos doesn't exist, none of the searched dirs exists, or there's not
131a7c91847Schristos enough space in TMPL. */
132a7c91847Schristos int
__path_search(char * tmpl,size_t tmpl_len,const char * dir,const char * pfx,int try_tmpdir)133a7c91847Schristos __path_search (char *tmpl, size_t tmpl_len, const char *dir, const char *pfx,
134a7c91847Schristos int try_tmpdir)
135a7c91847Schristos {
136a7c91847Schristos const char *d;
137a7c91847Schristos size_t dlen, plen;
138a7c91847Schristos
139a7c91847Schristos if (!pfx || !pfx[0])
140a7c91847Schristos {
141a7c91847Schristos pfx = "file";
142a7c91847Schristos plen = 4;
143a7c91847Schristos }
144a7c91847Schristos else
145a7c91847Schristos {
146a7c91847Schristos plen = strlen (pfx);
147a7c91847Schristos if (plen > 5)
148a7c91847Schristos plen = 5;
149a7c91847Schristos }
150a7c91847Schristos
151a7c91847Schristos if (try_tmpdir)
152a7c91847Schristos {
153a7c91847Schristos d = __secure_getenv ("TMPDIR");
154a7c91847Schristos if (d != NULL && direxists (d))
155a7c91847Schristos dir = d;
156a7c91847Schristos else if (dir != NULL && direxists (dir))
157a7c91847Schristos /* nothing */ ;
158a7c91847Schristos else
159a7c91847Schristos dir = NULL;
160a7c91847Schristos }
161a7c91847Schristos if (dir == NULL)
162a7c91847Schristos {
163a7c91847Schristos if (direxists (P_tmpdir))
164a7c91847Schristos dir = P_tmpdir;
165a7c91847Schristos else if (strcmp (P_tmpdir, "/tmp") != 0 && direxists ("/tmp"))
166a7c91847Schristos dir = "/tmp";
167a7c91847Schristos else
168a7c91847Schristos {
169a7c91847Schristos __set_errno (ENOENT);
170a7c91847Schristos return -1;
171a7c91847Schristos }
172a7c91847Schristos }
173a7c91847Schristos
174a7c91847Schristos dlen = strlen (dir);
175a7c91847Schristos while (dlen > 1 && dir[dlen - 1] == '/')
176a7c91847Schristos dlen--; /* remove trailing slashes */
177a7c91847Schristos
178a7c91847Schristos /* check we have room for "${dir}/${pfx}XXXXXX\0" */
179a7c91847Schristos if (tmpl_len < dlen + 1 + plen + 6 + 1)
180a7c91847Schristos {
181a7c91847Schristos __set_errno (EINVAL);
182a7c91847Schristos return -1;
183a7c91847Schristos }
184a7c91847Schristos
185a7c91847Schristos sprintf (tmpl, "%.*s/%.*sXXXXXX", (int) dlen, dir, (int) plen, pfx);
186a7c91847Schristos return 0;
187a7c91847Schristos }
188a7c91847Schristos
189a7c91847Schristos /* These are the characters used in temporary file names. */
190a7c91847Schristos static const char letters[] =
191a7c91847Schristos "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
192a7c91847Schristos
193a7c91847Schristos /* Generate a temporary file name based on TMPL. TMPL must match the
194a7c91847Schristos rules for mk[s]temp (i.e. end in "XXXXXX"). The name constructed
195a7c91847Schristos does not exist at the time of the call to __gen_tempname. TMPL is
196a7c91847Schristos overwritten with the result.
197a7c91847Schristos
198a7c91847Schristos KIND may be one of:
199a7c91847Schristos __GT_NOCREATE: simply verify that the name does not exist
200a7c91847Schristos at the time of the call.
201a7c91847Schristos __GT_FILE: create the file using open(O_CREAT|O_EXCL)
202a7c91847Schristos and return a read-write fd. The file is mode 0600.
203a7c91847Schristos __GT_BIGFILE: same as __GT_FILE but use open64().
204a7c91847Schristos __GT_DIR: create a directory, which will be mode 0700.
205a7c91847Schristos
206a7c91847Schristos We use a clever algorithm to get hard-to-predict names. */
207a7c91847Schristos int
__gen_tempname(char * tmpl,int kind)208a7c91847Schristos __gen_tempname (char *tmpl, int kind)
209a7c91847Schristos {
210a7c91847Schristos int len;
211a7c91847Schristos char *XXXXXX;
212a7c91847Schristos static uint64_t value;
213a7c91847Schristos uint64_t random_time_bits;
214a7c91847Schristos unsigned int count;
215a7c91847Schristos int fd = -1;
216a7c91847Schristos int save_errno = errno;
217a7c91847Schristos struct_stat64 st;
218a7c91847Schristos
219a7c91847Schristos /* A lower bound on the number of temporary files to attempt to
220a7c91847Schristos generate. The maximum total number of temporary file names that
221a7c91847Schristos can exist for a given template is 62**6. It should never be
222a7c91847Schristos necessary to try all these combinations. Instead if a reasonable
223a7c91847Schristos number of names is tried (we define reasonable as 62**3) fail to
224a7c91847Schristos give the system administrator the chance to remove the problems. */
225a7c91847Schristos unsigned int attempts_min = 62 * 62 * 62;
226a7c91847Schristos
227a7c91847Schristos /* The number of times to attempt to generate a temporary file. To
228a7c91847Schristos conform to POSIX, this must be no smaller than TMP_MAX. */
229a7c91847Schristos unsigned int attempts = attempts_min < TMP_MAX ? TMP_MAX : attempts_min;
230a7c91847Schristos
231a7c91847Schristos len = strlen (tmpl);
232a7c91847Schristos if (len < 6 || strcmp (&tmpl[len - 6], "XXXXXX"))
233a7c91847Schristos {
234a7c91847Schristos __set_errno (EINVAL);
235a7c91847Schristos return -1;
236a7c91847Schristos }
237a7c91847Schristos
238a7c91847Schristos /* This is where the Xs start. */
239a7c91847Schristos XXXXXX = &tmpl[len - 6];
240a7c91847Schristos
241a7c91847Schristos /* Get some more or less random data. */
242a7c91847Schristos #ifdef RANDOM_BITS
243a7c91847Schristos RANDOM_BITS (random_time_bits);
244a7c91847Schristos #else
245a7c91847Schristos # if HAVE_GETTIMEOFDAY || _LIBC
246a7c91847Schristos {
247a7c91847Schristos struct timeval tv;
248a7c91847Schristos __gettimeofday (&tv, NULL);
249a7c91847Schristos random_time_bits = ((uint64_t) tv.tv_usec << 16) ^ tv.tv_sec;
250a7c91847Schristos }
251a7c91847Schristos # else
252a7c91847Schristos random_time_bits = time (NULL);
253a7c91847Schristos # endif
254a7c91847Schristos #endif
255a7c91847Schristos value += random_time_bits ^ __getpid ();
256a7c91847Schristos
257a7c91847Schristos for (count = 0; count < attempts; value += 7777, ++count)
258a7c91847Schristos {
259a7c91847Schristos uint64_t v = value;
260a7c91847Schristos
261a7c91847Schristos /* Fill in the random bits. */
262a7c91847Schristos XXXXXX[0] = letters[v % 62];
263a7c91847Schristos v /= 62;
264a7c91847Schristos XXXXXX[1] = letters[v % 62];
265a7c91847Schristos v /= 62;
266a7c91847Schristos XXXXXX[2] = letters[v % 62];
267a7c91847Schristos v /= 62;
268a7c91847Schristos XXXXXX[3] = letters[v % 62];
269a7c91847Schristos v /= 62;
270a7c91847Schristos XXXXXX[4] = letters[v % 62];
271a7c91847Schristos v /= 62;
272a7c91847Schristos XXXXXX[5] = letters[v % 62];
273a7c91847Schristos
274a7c91847Schristos switch (kind)
275a7c91847Schristos {
276a7c91847Schristos case __GT_FILE:
277a7c91847Schristos fd = __open (tmpl, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
278a7c91847Schristos break;
279a7c91847Schristos
280a7c91847Schristos case __GT_BIGFILE:
281a7c91847Schristos fd = __open64 (tmpl, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
282a7c91847Schristos break;
283a7c91847Schristos
284a7c91847Schristos case __GT_DIR:
285a7c91847Schristos fd = __mkdir (tmpl, S_IRUSR | S_IWUSR | S_IXUSR);
286a7c91847Schristos break;
287a7c91847Schristos
288a7c91847Schristos case __GT_NOCREATE:
289a7c91847Schristos /* This case is backward from the other three. __gen_tempname
290a7c91847Schristos succeeds if __xstat fails because the name does not exist.
291a7c91847Schristos Note the continue to bypass the common logic at the bottom
292a7c91847Schristos of the loop. */
293a7c91847Schristos if (__lxstat64 (_STAT_VER, tmpl, &st) < 0)
294a7c91847Schristos {
295a7c91847Schristos if (errno == ENOENT)
296a7c91847Schristos {
297a7c91847Schristos __set_errno (save_errno);
298a7c91847Schristos return 0;
299a7c91847Schristos }
300a7c91847Schristos else
301a7c91847Schristos /* Give up now. */
302a7c91847Schristos return -1;
303a7c91847Schristos }
304a7c91847Schristos continue;
305a7c91847Schristos
306a7c91847Schristos default:
307a7c91847Schristos assert (! "invalid KIND in __gen_tempname");
308a7c91847Schristos }
309a7c91847Schristos
310a7c91847Schristos if (fd >= 0)
311a7c91847Schristos {
312a7c91847Schristos __set_errno (save_errno);
313a7c91847Schristos return fd;
314a7c91847Schristos }
315a7c91847Schristos else if (errno != EEXIST)
316a7c91847Schristos return -1;
317a7c91847Schristos }
318a7c91847Schristos
319a7c91847Schristos /* We got out of the loop because we ran out of combinations to try. */
320a7c91847Schristos __set_errno (EEXIST);
321a7c91847Schristos return -1;
322a7c91847Schristos }
323