init version.
[bush.git] / lib / sh / tmpfile.c
blob832895658c7ceb064b61bdfe32d49dadb397e889
1 /*
2 * tmpfile.c - functions to create and safely open temp files for the shell.
3 */
5 /* Copyright (C) 2000-2020 Free Software Foundation, Inc.
7 This file is part of GNU Bush, the Bourne Again SHell.
9 Bush is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
14 Bush is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with Bush. If not, see <http://www.gnu.org/licenses/>.
23 #include <config.h>
25 #include <bushtypes.h>
26 #include <posixstat.h>
27 #include <posixtime.h>
28 #include <filecntl.h>
30 #if defined (HAVE_UNISTD_H)
31 # include <unistd.h>
32 #endif
34 #include <bushansi.h>
36 #include <stdio.h>
37 #include <errno.h>
39 #include <shell.h>
41 #ifndef errno
42 extern int errno;
43 #endif
45 #define BASEOPENFLAGS (O_CREAT | O_TRUNC | O_EXCL | O_BINARY)
47 #define DEFAULT_TMPDIR "." /* bogus default, should be changed */
48 #define DEFAULT_NAMEROOT "shtmp"
50 /* Use ANSI-C rand() interface if random(3) is not available */
51 #if !HAVE_RANDOM
52 #define random() rand()
53 #endif
55 extern pid_t dollar_dollar_pid;
57 static char *get_sys_tmpdir PARAMS((void));
58 static char *get_tmpdir PARAMS((int));
60 static char *sys_tmpdir = (char *)NULL;
61 static int ntmpfiles;
62 static int tmpnamelen = -1;
63 static unsigned long filenum = 1L;
65 static char *
66 get_sys_tmpdir ()
68 if (sys_tmpdir)
69 return sys_tmpdir;
71 #ifdef P_tmpdir
72 sys_tmpdir = P_tmpdir;
73 if (file_iswdir (sys_tmpdir))
74 return sys_tmpdir;
75 #endif
77 sys_tmpdir = "/tmp";
78 if (file_iswdir (sys_tmpdir))
79 return sys_tmpdir;
81 sys_tmpdir = "/var/tmp";
82 if (file_iswdir (sys_tmpdir))
83 return sys_tmpdir;
85 sys_tmpdir = "/usr/tmp";
86 if (file_iswdir (sys_tmpdir))
87 return sys_tmpdir;
89 sys_tmpdir = DEFAULT_TMPDIR;
91 return sys_tmpdir;
94 static char *
95 get_tmpdir (flags)
96 int flags;
98 char *tdir;
100 tdir = (flags & MT_USETMPDIR) ? get_string_value ("TMPDIR") : (char *)NULL;
101 if (tdir && (file_iswdir (tdir) == 0 || strlen (tdir) > PATH_MAX))
102 tdir = 0;
104 if (tdir == 0)
105 tdir = get_sys_tmpdir ();
107 #if defined (HAVE_PATHCONF) && defined (_PC_NAME_MAX)
108 if (tmpnamelen == -1)
109 tmpnamelen = pathconf (tdir, _PC_NAME_MAX);
110 #else
111 tmpnamelen = 0;
112 #endif
114 return tdir;
117 static void
118 sh_seedrand ()
120 #if HAVE_RANDOM
121 int d;
122 static int seeded = 0;
123 if (seeded == 0)
125 struct timeval tv;
127 gettimeofday (&tv, NULL);
128 srandom (tv.tv_sec ^ tv.tv_usec ^ (getpid () << 16) ^ (uintptr_t)&d);
129 seeded = 1;
131 #endif
134 char *
135 sh_mktmpname (nameroot, flags)
136 char *nameroot;
137 int flags;
139 char *filename, *tdir, *lroot;
140 struct stat sb;
141 int r, tdlen;
142 static int seeded = 0;
144 filename = (char *)xmalloc (PATH_MAX + 1);
145 tdir = get_tmpdir (flags);
146 tdlen = strlen (tdir);
148 lroot = nameroot ? nameroot : DEFAULT_NAMEROOT;
149 if (nameroot == 0)
150 flags &= ~MT_TEMPLATE;
152 if ((flags & MT_TEMPLATE) && strlen (nameroot) > PATH_MAX)
153 flags &= ~MT_TEMPLATE;
155 #ifdef USE_MKTEMP
156 if (flags & MT_TEMPLATE)
157 strcpy (filename, nameroot);
158 else
159 sprintf (filename, "%s/%s.XXXXXX", tdir, lroot);
160 if (mktemp (filename) == 0)
162 free (filename);
163 filename = NULL;
165 #else /* !USE_MKTEMP */
166 sh_seedrand ();
167 while (1)
169 filenum = (filenum << 1) ^
170 (unsigned long) time ((time_t *)0) ^
171 (unsigned long) dollar_dollar_pid ^
172 (unsigned long) ((flags & MT_USERANDOM) ? random () : ntmpfiles++);
173 sprintf (filename, "%s/%s-%lu", tdir, lroot, filenum);
174 if (tmpnamelen > 0 && tmpnamelen < 32)
175 filename[tdlen + 1 + tmpnamelen] = '\0';
176 # ifdef HAVE_LSTAT
177 r = lstat (filename, &sb);
178 # else
179 r = stat (filename, &sb);
180 # endif
181 if (r < 0 && errno == ENOENT)
182 break;
184 #endif /* !USE_MKTEMP */
186 return filename;
190 sh_mktmpfd (nameroot, flags, namep)
191 char *nameroot;
192 int flags;
193 char **namep;
195 char *filename, *tdir, *lroot;
196 int fd, tdlen;
198 filename = (char *)xmalloc (PATH_MAX + 1);
199 tdir = get_tmpdir (flags);
200 tdlen = strlen (tdir);
202 lroot = nameroot ? nameroot : DEFAULT_NAMEROOT;
203 if (nameroot == 0)
204 flags &= ~MT_TEMPLATE;
206 if ((flags & MT_TEMPLATE) && strlen (nameroot) > PATH_MAX)
207 flags &= ~MT_TEMPLATE;
209 #ifdef USE_MKSTEMP
210 if (flags & MT_TEMPLATE)
211 strcpy (filename, nameroot);
212 else
213 sprintf (filename, "%s/%s.XXXXXX", tdir, lroot);
214 fd = mkstemp (filename);
215 if (fd < 0 || namep == 0)
217 free (filename);
218 filename = NULL;
220 if (namep)
221 *namep = filename;
222 return fd;
223 #else /* !USE_MKSTEMP */
224 sh_seedrand ();
227 filenum = (filenum << 1) ^
228 (unsigned long) time ((time_t *)0) ^
229 (unsigned long) dollar_dollar_pid ^
230 (unsigned long) ((flags & MT_USERANDOM) ? random () : ntmpfiles++);
231 sprintf (filename, "%s/%s-%lu", tdir, lroot, filenum);
232 if (tmpnamelen > 0 && tmpnamelen < 32)
233 filename[tdlen + 1 + tmpnamelen] = '\0';
234 fd = open (filename, BASEOPENFLAGS | ((flags & MT_READWRITE) ? O_RDWR : O_WRONLY), 0600);
236 while (fd < 0 && errno == EEXIST);
238 if (namep)
239 *namep = filename;
240 else
241 free (filename);
243 return fd;
244 #endif /* !USE_MKSTEMP */
247 FILE *
248 sh_mktmpfp (nameroot, flags, namep)
249 char *nameroot;
250 int flags;
251 char **namep;
253 int fd;
254 FILE *fp;
256 fd = sh_mktmpfd (nameroot, flags, namep);
257 if (fd < 0)
258 return ((FILE *)NULL);
259 fp = fdopen (fd, (flags & MT_READWRITE) ? "w+" : "w");
260 if (fp == 0)
261 close (fd);
262 return fp;
265 char *
266 sh_mktmpdir (nameroot, flags)
267 char *nameroot;
268 int flags;
270 char *filename, *tdir, *lroot, *dirname;
271 int fd, tdlen;
273 #ifdef USE_MKDTEMP
274 filename = (char *)xmalloc (PATH_MAX + 1);
275 tdir = get_tmpdir (flags);
276 tdlen = strlen (tdir);
278 lroot = nameroot ? nameroot : DEFAULT_NAMEROOT;
279 if (nameroot == 0)
280 flags &= ~MT_TEMPLATE;
282 if ((flags & MT_TEMPLATE) && strlen (nameroot) > PATH_MAX)
283 flags &= ~MT_TEMPLATE;
285 if (flags & MT_TEMPLATE)
286 strcpy (filename, nameroot);
287 else
288 sprintf (filename, "%s/%s.XXXXXX", tdir, lroot);
289 dirname = mkdtemp (filename);
290 if (dirname == 0)
292 free (filename);
293 filename = NULL;
295 return dirname;
296 #else /* !USE_MKDTEMP */
297 filename = (char *)NULL;
300 filename = sh_mktmpname (nameroot, flags);
301 fd = mkdir (filename, 0700);
302 if (fd == 0)
303 break;
304 free (filename);
305 filename = (char *)NULL;
307 while (fd < 0 && errno == EEXIST);
309 return (filename);
310 #endif /* !USE_MKDTEMP */