1 /*
2 Copyright (c) 1990 The Regents of the University of California.
3 All rights reserved.
4 
5 Redistribution and use in source and binary forms are permitted
6 provided that the above copyright notice and this paragraph are
7 duplicated in all such forms and that any documentation,
8 and/or other materials related to such
9 distribution and use acknowledge that the software was developed
10 by the University of California, Berkeley.  The name of the
11 University may not be used to endorse or promote products derived
12 from this software without specific prior written permission.
13 THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14 IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  */
17 /*
18  * tmpname.c
19  * Original Author:	G. Haley
20  */
21 /*
22 FUNCTION
23 <<tmpnam>>, <<tempnam>>---name for a temporary file
24 
25 INDEX
26 	tmpnam
27 INDEX
28 	tempnam
29 INDEX
30 	_tmpnam_r
31 INDEX
32 	_tempnam_r
33 
34 SYNOPSIS
35 	#include <stdio.h>
36 	char *tmpnam(char *<[s]>);
37 	char *tempnam(char *<[dir]>, char *<[pfx]>);
38 	char *tmpnam( char *<[s]>);
39 	char *tempnam( char *<[dir]>, char *<[pfx]>);
40 
41 DESCRIPTION
42 Use either of these functions to generate a name for a temporary file.
43 The generated name is guaranteed to avoid collision with other files
44 (for up to <<TMP_MAX>> calls of either function).
45 
46 <<tmpnam>> generates file names with the value of <<P_tmpdir>>
47 (defined in `<<stdio.h>>') as the leading directory component of the path.
48 
49 You can use the <<tmpnam>> argument <[s]> to specify a suitable area
50 of memory for the generated filename; otherwise, you can call
51 <<tmpnam(NULL)>> to use an internal static buffer.
52 
53 <<tempnam>> allows you more control over the generated filename: you
54 can use the argument <[dir]> to specify the path to a directory for
55 temporary files, and you can use the argument <[pfx]> to specify a
56 prefix for the base filename.
57 
58 If <[dir]> is <<NULL>>, <<tempnam>> will attempt to use the value of
59 environment variable <<TMPDIR>> instead; if there is no such value,
60 <<tempnam>> uses the value of <<P_tmpdir>> (defined in `<<stdio.h>>').
61 
62 If you don't need any particular prefix to the basename of temporary
63 files, you can pass <<NULL>> as the <[pfx]> argument to <<tempnam>>.
64 
65 <<_tmpnam_r>> and <<_tempnam_r>> are reentrant versions of <<tmpnam>>
66 and <<tempnam>> respectively.  The extra argument <[reent]> is a
67 pointer to a reentrancy structure.
68 
69 WARNINGS
70 The generated filenames are suitable for temporary files, but do not
71 in themselves make files temporary.  Files with these names must still
72 be explicitly removed when you no longer want them.
73 
74 If you supply your own data area <[s]> for <<tmpnam>>, you must ensure
75 that it has room for at least <<L_tmpnam>> elements of type <<char>>.
76 
77 RETURNS
78 Both <<tmpnam>> and <<tempnam>> return a pointer to the newly
79 generated filename.
80 
81 PORTABILITY
82 ANSI C requires <<tmpnam>>, but does not specify the use of
83 <<P_tmpdir>>.  The System V Interface Definition (Issue 2) requires
84 both <<tmpnam>> and <<tempnam>>.
85 
86 Supporting OS subroutines required: <<close>>,  <<fstat>>, <<getpid>>,
87 <<isatty>>, <<lseek>>, <<open>>, <<read>>, <<sbrk>>, <<write>>.
88 
89 The global pointer <<environ>> is also required.
90 */
91 
92 #define _DEFAULT_SOURCE
93 #define _DEFAULT_SOURCE
94 #include <_ansi.h>
95 #include <stdio.h>
96 #include <stdlib.h>
97 #include <string.h>
98 #include <fcntl.h>
99 #include <errno.h>
100 #include <unistd.h>
101 
102 static NEWLIB_THREAD_LOCAL int _tls_inc;
103 
104 /* Try to open the file specified, if it can't be opened then try
105    another one.  Return nonzero if successful, otherwise zero.  */
106 
107 static int
worker(char * result,const char * part1,const char * part2,int part3,int * part4)108 worker (
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 ( result, "%s/%s%x.%x", part1, part2, part3, *part4);
122       (*part4)++;
123       t = open (result, O_RDONLY, 0);
124       if (t == -1)
125 	{
126 	  if (_REENT_ERRNO(ptr) == ENOSYS)
127 	    {
128 	      result[0] = '\0';
129 	      return 0;
130 	    }
131 	  break;
132 	}
133       close (t);
134     }
135   return 1;
136 }
137 
138 #define _TMPNAM_SIZE 25
139 
140 static NEWLIB_THREAD_LOCAL char _tmpnam_buf[_TMPNAM_SIZE];
141 
142 char *
tmpnam(char * s)143 tmpnam (
144        char *s)
145 {
146   char *result;
147   int pid;
148 
149   if (s == NULL)
150     {
151       /* ANSI states we must use an internal static buffer if s is NULL */
152       result = _tmpnam_buf;
153     }
154   else
155     {
156       result = s;
157     }
158   pid = getpid ();
159 
160   if (worker (result, P_tmpdir, "t", pid, &_tls_inc))
161     {
162       _tls_inc++;
163       return result;
164     }
165 
166   return NULL;
167 }
168 
169 char *
tempnam(const char * dir,const char * pfx)170 tempnam (
171        const char *dir,
172        const char *pfx)
173 {
174   char *filename;
175   int length;
176   const char *prefix = (pfx) ? pfx : "";
177   if (dir == NULL && (dir = getenv ("TMPDIR")) == NULL)
178     dir = P_tmpdir;
179 
180   /* two 8 digit numbers + . / */
181   length = strlen (dir) + strlen (prefix) + (4 * sizeof (int)) + 2 + 1;
182 
183   filename = malloc (length);
184   if (filename)
185     {
186       if (! worker (filename, dir, prefix,
187 		    getpid (), &_tls_inc))
188 	return NULL;
189     }
190   return filename;
191 }
192