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