1 /*
2  * tmpname.c
3  * Original Author:	G. Haley
4  */
5 
6 /*
7 FUNCTION
8 <<tmpnam>>, <<tempnam>>---name for a temporary file
9 
10 INDEX
11 	tmpnam
12 INDEX
13 	tempnam
14 INDEX
15 	_tmpnam_r
16 INDEX
17 	_tempnam_r
18 
19 ANSI_SYNOPSIS
20 	#include <stdio.h>
21 	char *tmpnam(char *<[s]>);
22 	char *tempnam(char *<[dir]>, char *<[pfx]>);
23 	char *_tmpnam_r(void *<[reent]>, char *<[s]>);
24 	char *_tempnam_r(void *<[reent]>, char *<[dir]>, char *<[pfx]>);
25 
26 TRAD_SYNOPSIS
27 	#include <stdio.h>
28 	char *tmpnam(<[s]>)
29 	char *<[s]>;
30 
31 	char *tempnam(<[dir]>, <[pfx]>)
32 	char *<[dir]>;
33 	char *<[pfx]>;
34 
35 	char *_tmpnam_r(<[reent]>, <[s]>)
36 	char *<[reent]>;
37 	char *<[s]>;
38 
39 	char *_tempnam_r(<[reent]>, <[dir]>, <[pfx]>)
40 	char *<[reent]>;
41 	char *<[dir]>;
42 	char *<[pfx]>;
43 
44 DESCRIPTION
45 Use either of these functions to generate a name for a temporary file.
46 The generated name is guaranteed to avoid collision with other files
47 (for up to <<TMP_MAX>> calls of either function).
48 
49 <<tmpnam>> generates file names with the value of <<P_tmpdir>>
50 (defined in `<<stdio.h>>') as the leading directory component of the path.
51 
52 You can use the <<tmpnam>> argument <[s]> to specify a suitable area
53 of memory for the generated filename; otherwise, you can call
54 <<tmpnam(NULL)>> to use an internal static buffer.
55 
56 <<tempnam>> allows you more control over the generated filename: you
57 can use the argument <[dir]> to specify the path to a directory for
58 temporary files, and you can use the argument <[pfx]> to specify a
59 prefix for the base filename.
60 
61 If <[dir]> is <<NULL>>, <<tempnam>> will attempt to use the value of
62 environment variable <<TMPDIR>> instead; if there is no such value,
63 <<tempnam>> uses the value of <<P_tmpdir>> (defined in `<<stdio.h>>').
64 
65 If you don't need any particular prefix to the basename of temporary
66 files, you can pass <<NULL>> as the <[pfx]> argument to <<tempnam>>.
67 
68 <<_tmpnam_r>> and <<_tempnam_r>> are reentrant versions of <<tmpnam>>
69 and <<tempnam>> respectively.  The extra argument <[reent]> is a
70 pointer to a reentrancy structure.
71 
72 WARNINGS
73 The generated filenames are suitable for temporary files, but do not
74 in themselves make files temporary.  Files with these names must still
75 be explicitly removed when you no longer want them.
76 
77 If you supply your own data area <[s]> for <<tmpnam>>, you must ensure
78 that it has room for at least <<L_tmpnam>> elements of type <<char>>.
79 
80 RETURNS
81 Both <<tmpnam>> and <<tempnam>> return a pointer to the newly
82 generated filename.
83 
84 PORTABILITY
85 ANSI C requires <<tmpnam>>, but does not specify the use of
86 <<P_tmpdir>>.  The System V Interface Definition (Issue 2) requires
87 both <<tmpnam>> and <<tempnam>>.
88 
89 Supporting OS subroutines required: <<close>>,  <<fstat>>, <<getpid>>,
90 <<isatty>>, <<lseek>>, <<open>>, <<read>>, <<sbrk>>, <<write>>.
91 
92 The global pointer <<environ>> is also required.
93 */
94 
95 #include <_ansi.h>
96 #include <stdio.h>
97 #include <stdlib.h>
98 #include <string.h>
99 #include <fcntl.h>
100 #include <reent.h>
101 #include <errno.h>
102 
103 /* Try to open the file specified, if it can't be opened then try
104    another one.  Return nonzero if successful, otherwise zero.  */
105 
106 static int
worker(ptr,result,part1,part2,part3,part4)107 worker (ptr, result, part1, part2, part3, part4)
108      struct _reent *ptr;
109      char *result;
110      _CONST char *part1;
111      _CONST char *part2;
112      int part3;
113      int *part4;
114 {
115   /*  Generate the filename and make sure that there isn't one called
116       it already.  */
117 
118   while (1)
119     {
120       int t;
121       _sprintf_r (ptr, result, "%s/%s%x.%x", part1, part2, part3, *part4);
122       (*part4)++;
123       t = _open_r (ptr, result, O_RDONLY, 0);
124       if (t == -1)
125 	{
126 	  if (ptr->_errno == ENOSYS)
127 	    {
128 	      result[0] = '\0';
129 	      return 0;
130 	    }
131 	  break;
132 	}
133       _close_r (ptr, t);
134     }
135   return 1;
136 }
137 
138 char *
139 _DEFUN (_tmpnam_r, (p, s),
140 	struct _reent *p _AND
141 	char *s)
142 {
143   char *result;
144   int pid;
145 
146   if (s == NULL)
147     {
148       /* ANSI states we must use an internal static buffer if s is NULL */
149       _REENT_CHECK_EMERGENCY(p);
150       result = _REENT_EMERGENCY(p);
151     }
152   else
153     {
154       result = s;
155     }
156   pid = _getpid_r (p);
157 
158   if (worker (p, result, P_tmpdir, "t", pid, &p->_inc))
159     {
160       p->_inc++;
161       return result;
162     }
163 
164   return NULL;
165 }
166 
167 char *
168 _DEFUN (_tempnam_r, (p, dir, pfx),
169 	struct _reent *p _AND
170 	_CONST char *dir _AND
171 	_CONST char *pfx)
172 {
173   char *filename;
174   int length;
175   _CONST char *prefix = (pfx) ? pfx : "";
176   if (dir == NULL && (dir = getenv ("TMPDIR")) == NULL)
177     dir = P_tmpdir;
178 
179   /* two 8 digit numbers + . / */
180   length = strlen (dir) + strlen (prefix) + (4 * sizeof (int)) + 2 + 1;
181 
182   filename = _malloc_r (p, length);
183   if (filename)
184     {
185       if (! worker (p, filename, dir, prefix,
186 		    _getpid_r (p) ^ (int) (_POINTER_INT) p, &p->_inc))
187 	return NULL;
188     }
189   return filename;
190 }
191 
192 #ifndef _REENT_ONLY
193 
194 char *
195 _DEFUN (tempnam, (dir, pfx),
196 	_CONST char *dir _AND
197 	_CONST char *pfx)
198 {
199   return _tempnam_r (_REENT, dir, pfx);
200 }
201 
202 char *
203 _DEFUN (tmpnam, (s),
204 	char *s)
205 {
206   return _tmpnam_r (_REENT, s);
207 }
208 
209 #endif
210