d51ac2cff63c544ec2ab8913b3d70773b78df2b6
[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 <filecntl.h>
28
29 #if defined (HAVE_UNISTD_H)
30 #  include <unistd.h>
31 #endif
32
33 #include <stdio.h>
34 #include <errno.h>
35
36 #include <shell.h>
37
38 #ifndef errno
39 extern int errno;
40 #endif
41
42 #define BASEOPENFLAGS   (O_CREAT | O_TRUNC | O_EXCL)
43
44 #define DEFAULT_TMPDIR          "."     /* bogus default, should be changed */
45 #define DEFAULT_NAMEROOT        "shtmp"
46
47 extern pid_t dollar_dollar_pid;
48
49 static char *sys_tmpdir = (char *)NULL;
50 static int ntmpfiles;
51 static int tmpnamelen = -1;
52 static unsigned long filenum = 1L;
53
54 static char *
55 get_sys_tmpdir ()
56 {
57   struct stat sb;
58
59   if (sys_tmpdir)
60     return sys_tmpdir;
61
62 #ifdef P_tmpdir
63   sys_tmpdir = P_tmpdir;
64   if (stat (sys_tmpdir, &sb) == 0)
65     return sys_tmpdir;
66 #endif
67
68   sys_tmpdir = "/tmp";
69   if (stat (sys_tmpdir, &sb) == 0)
70     return sys_tmpdir;
71
72   sys_tmpdir = "/var/tmp";
73   if (stat (sys_tmpdir, &sb) == 0)
74     return sys_tmpdir;
75
76   sys_tmpdir = "/usr/tmp";
77   if (stat (sys_tmpdir, &sb) == 0)
78     return sys_tmpdir;
79
80   sys_tmpdir = DEFAULT_TMPDIR;
81
82   return sys_tmpdir;
83 }
84
85 static char *
86 get_tmpdir (flags)
87      int flags;
88 {
89   char *tdir;
90
91   tdir = (flags & MT_USETMPDIR) ? get_string_value ("TMPDIR") : (char *)NULL;
92   if (tdir == 0)
93     tdir = get_sys_tmpdir ();
94
95 #if defined (HAVE_PATHCONF) && defined (_PC_NAME_MAX)
96   if (tmpnamelen == -1)
97     tmpnamelen = pathconf (tdir, _PC_NAME_MAX);
98 #else
99   tmpnamelen = 0;
100 #endif
101
102   return tdir;
103 }
104
105 char *
106 sh_mktmpname (nameroot, flags)
107      char *nameroot;
108      int flags;
109 {
110   char *filename, *tdir, *lroot;
111   struct stat sb;
112   int r, tdlen;
113
114   filename = (char *)xmalloc (PATH_MAX + 1);
115   tdir = get_tmpdir (flags);
116   tdlen = strlen (tdir);
117
118   lroot = nameroot ? nameroot : DEFAULT_NAMEROOT;
119
120 #ifdef USE_MKTEMP
121   sprintf (filename, "%s/%s.XXXXXX", tdir, lroot);
122   if (mktemp (filename) == 0)
123     {
124       free (filename);
125       filename = NULL;
126     }
127 #else  /* !USE_MKTEMP */
128   while (1)
129     {
130       filenum = (filenum << 1) ^
131                 (unsigned long) time ((time_t *)0) ^
132                 (unsigned long) dollar_dollar_pid ^
133                 (unsigned long) ((flags & MT_USERANDOM) ? get_random_number () : ntmpfiles++);
134       sprintf (filename, "%s/%s-%lu", tdir, lroot, filenum);
135       if (tmpnamelen > 0 && tmpnamelen < 32)
136         filename[tdlen + 1 + tmpnamelen] = '\0';
137 #  ifdef HAVE_LSTAT
138       r = lstat (filename, &sb);
139 #  else
140       r = stat (filename, &sb);
141 #  endif
142       if (r < 0 && errno == ENOENT)
143         break;
144     }
145 #endif /* !USE_MKTEMP */
146
147   return filename;
148 }
149
150 int
151 sh_mktmpfd (nameroot, flags, namep)
152      char *nameroot;
153      int flags;
154      char **namep;
155 {
156   char *filename, *tdir, *lroot;
157   int fd, tdlen;
158
159   filename = (char *)xmalloc (PATH_MAX + 1);
160   tdir = get_tmpdir (flags);
161   tdlen = strlen (tdir);
162
163   lroot = nameroot ? nameroot : DEFAULT_NAMEROOT;
164
165 #ifdef USE_MKSTEMP
166   sprintf (filename, "%s/%s.XXXXXX", tdir, lroot);
167   fd = mkstemp (filename);
168   if (fd < 0 || namep == 0)
169     {
170       free (filename);
171       filename = NULL;
172     }
173   if (namep)
174     *namep = filename;
175   return fd;
176 #else /* !USE_MKSTEMP */
177   do
178     {
179       filenum = (filenum << 1) ^
180                 (unsigned long) time ((time_t *)0) ^
181                 (unsigned long) dollar_dollar_pid ^
182                 (unsigned long) ((flags & MT_USERANDOM) ? get_random_number () : ntmpfiles++);
183       sprintf (filename, "%s/%s-%lu", tdir, lroot, filenum);
184       if (tmpnamelen > 0 && tmpnamelen < 32)
185         filename[tdlen + 1 + tmpnamelen] = '\0';
186       fd = open (filename, BASEOPENFLAGS | ((flags & MT_READWRITE) ? O_RDWR : O_WRONLY), 0600);
187     }
188   while (fd < 0 && errno == EEXIST);
189
190   if (namep)
191     *namep = filename;
192   else
193     free (filename);
194
195   return fd;
196 #endif /* !USE_MKSTEMP */
197 }
198
199 FILE *
200 sh_mktmpfp (nameroot, flags, namep)
201      char *nameroot;
202      int flags;
203      char **namep;
204 {
205   int fd;
206   FILE *fp;
207
208   fd = sh_mktmpfd (nameroot, flags, namep);
209   if (fd < 0)
210     return ((FILE *)NULL);
211   fp = fdopen (fd, (flags & MT_READWRITE) ? "w+" : "w");
212   if (fp == 0)
213     close (fd);
214   return fp;
215 }