Imported from ../bash-2.05b.tar.gz.
[platform/upstream/bash.git] / lib / sh / tmpfile.c
1 /*
2  * tmpfile.c - functions to create and safely open temp files for the shell.
3  */
4
5 /* Copyright (C) 2000 Free Software Foundation, Inc.
6
7    This file is part of GNU Bash, the Bourne Again SHell.
8
9    Bash is free software; you can redistribute it and/or modify it
10    under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2, or (at your option)
12    any later version.
13
14    Bash is distributed in the hope that it will be useful, but WITHOUT
15    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
17    License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with Bash; see the file COPYING.  If not, write to the Free
21    Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
22
23 #include <config.h>
24
25 #include <bashtypes.h>
26 #include <posixstat.h>
27 #include <posixtime.h>
28 #include <filecntl.h>
29
30 #if defined (HAVE_UNISTD_H)
31 #  include <unistd.h>
32 #endif
33
34 #include <stdio.h>
35 #include <errno.h>
36
37 #include <shell.h>
38
39 #ifndef errno
40 extern int errno;
41 #endif
42
43 #define BASEOPENFLAGS   (O_CREAT | O_TRUNC | O_EXCL)
44
45 #define DEFAULT_TMPDIR          "."     /* bogus default, should be changed */
46 #define DEFAULT_NAMEROOT        "shtmp"
47
48 extern pid_t dollar_dollar_pid;
49
50 static char *sys_tmpdir = (char *)NULL;
51 static int ntmpfiles;
52 static int tmpnamelen = -1;
53 static unsigned long filenum = 1L;
54
55 static char *
56 get_sys_tmpdir ()
57 {
58   struct stat sb;
59
60   if (sys_tmpdir)
61     return sys_tmpdir;
62
63 #ifdef P_tmpdir
64   sys_tmpdir = P_tmpdir;
65   if (stat (sys_tmpdir, &sb) == 0)
66     return sys_tmpdir;
67 #endif
68
69   sys_tmpdir = "/tmp";
70   if (stat (sys_tmpdir, &sb) == 0)
71     return sys_tmpdir;
72
73   sys_tmpdir = "/var/tmp";
74   if (stat (sys_tmpdir, &sb) == 0)
75     return sys_tmpdir;
76
77   sys_tmpdir = "/usr/tmp";
78   if (stat (sys_tmpdir, &sb) == 0)
79     return sys_tmpdir;
80
81   sys_tmpdir = DEFAULT_TMPDIR;
82
83   return sys_tmpdir;
84 }
85
86 static char *
87 get_tmpdir (flags)
88      int flags;
89 {
90   char *tdir;
91
92   tdir = (flags & MT_USETMPDIR) ? get_string_value ("TMPDIR") : (char *)NULL;
93   if (tdir == 0)
94     tdir = get_sys_tmpdir ();
95
96 #if defined (HAVE_PATHCONF) && defined (_PC_NAME_MAX)
97   if (tmpnamelen == -1)
98     tmpnamelen = pathconf (tdir, _PC_NAME_MAX);
99 #else
100   tmpnamelen = 0;
101 #endif
102
103   return tdir;
104 }
105
106 char *
107 sh_mktmpname (nameroot, flags)
108      char *nameroot;
109      int flags;
110 {
111   char *filename, *tdir, *lroot;
112   struct stat sb;
113   int r, tdlen;
114
115   filename = (char *)xmalloc (PATH_MAX + 1);
116   tdir = get_tmpdir (flags);
117   tdlen = strlen (tdir);
118
119   lroot = nameroot ? nameroot : DEFAULT_NAMEROOT;
120
121 #ifdef USE_MKTEMP
122   sprintf (filename, "%s/%s.XXXXXX", tdir, lroot);
123   if (mktemp (filename) == 0)
124     {
125       free (filename);
126       filename = NULL;
127     }
128 #else  /* !USE_MKTEMP */
129   while (1)
130     {
131       filenum = (filenum << 1) ^
132                 (unsigned long) time ((time_t *)0) ^
133                 (unsigned long) dollar_dollar_pid ^
134                 (unsigned long) ((flags & MT_USERANDOM) ? get_random_number () : ntmpfiles++);
135       sprintf (filename, "%s/%s-%lu", tdir, lroot, filenum);
136       if (tmpnamelen > 0 && tmpnamelen < 32)
137         filename[tdlen + 1 + tmpnamelen] = '\0';
138 #  ifdef HAVE_LSTAT
139       r = lstat (filename, &sb);
140 #  else
141       r = stat (filename, &sb);
142 #  endif
143       if (r < 0 && errno == ENOENT)
144         break;
145     }
146 #endif /* !USE_MKTEMP */
147
148   return filename;
149 }
150
151 int
152 sh_mktmpfd (nameroot, flags, namep)
153      char *nameroot;
154      int flags;
155      char **namep;
156 {
157   char *filename, *tdir, *lroot;
158   int fd, tdlen;
159
160   filename = (char *)xmalloc (PATH_MAX + 1);
161   tdir = get_tmpdir (flags);
162   tdlen = strlen (tdir);
163
164   lroot = nameroot ? nameroot : DEFAULT_NAMEROOT;
165
166 #ifdef USE_MKSTEMP
167   sprintf (filename, "%s/%s.XXXXXX", tdir, lroot);
168   fd = mkstemp (filename);
169   if (fd < 0 || namep == 0)
170     {
171       free (filename);
172       filename = NULL;
173     }
174   if (namep)
175     *namep = filename;
176   return fd;
177 #else /* !USE_MKSTEMP */
178   do
179     {
180       filenum = (filenum << 1) ^
181                 (unsigned long) time ((time_t *)0) ^
182                 (unsigned long) dollar_dollar_pid ^
183                 (unsigned long) ((flags & MT_USERANDOM) ? get_random_number () : ntmpfiles++);
184       sprintf (filename, "%s/%s-%lu", tdir, lroot, filenum);
185       if (tmpnamelen > 0 && tmpnamelen < 32)
186         filename[tdlen + 1 + tmpnamelen] = '\0';
187       fd = open (filename, BASEOPENFLAGS | ((flags & MT_READWRITE) ? O_RDWR : O_WRONLY), 0600);
188     }
189   while (fd < 0 && errno == EEXIST);
190
191   if (namep)
192     *namep = filename;
193   else
194     free (filename);
195
196   return fd;
197 #endif /* !USE_MKSTEMP */
198 }
199
200 FILE *
201 sh_mktmpfp (nameroot, flags, namep)
202      char *nameroot;
203      int flags;
204      char **namep;
205 {
206   int fd;
207   FILE *fp;
208
209   fd = sh_mktmpfd (nameroot, flags, namep);
210   if (fd < 0)
211     return ((FILE *)NULL);
212   fp = fdopen (fd, (flags & MT_READWRITE) ? "w+" : "w");
213   if (fp == 0)
214     close (fd);
215   return fp;
216 }