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 <stdio.h>
95 #include <stdlib.h>
96 #include <string.h>
97 #include <fcntl.h>
98 #include <errno.h>
99 #include <unistd.h>
100 
101 static NEWLIB_THREAD_LOCAL int _tls_inc;
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(char * result,const char * part1,const char * part2,int part3,int * part4)107 worker (
108        char *result,
109        const char *part1,
110        const char *part2,
111        int part3,
112        int *part4)
113 {
114   /*  Generate the filename and make sure that there isn't one called
115       it already.  */
116 
117   while (1)
118     {
119       int t;
120       sprintf ( result, "%s/%s%x.%x", part1, part2, part3, *part4);
121       (*part4)++;
122       t = open (result, O_RDONLY, 0);
123       if (t == -1)
124 	{
125 	  if (_REENT_ERRNO(ptr) == ENOSYS)
126 	    {
127 	      result[0] = '\0';
128 	      return 0;
129 	    }
130 	  break;
131 	}
132       close (t);
133     }
134   return 1;
135 }
136 
137 #define _TMPNAM_SIZE 25
138 
139 static NEWLIB_THREAD_LOCAL char _tmpnam_buf[_TMPNAM_SIZE];
140 
141 char *
tmpnam(char * s)142 tmpnam (
143        char *s)
144 {
145   char *result;
146   int pid;
147 
148   if (s == NULL)
149     {
150       /* ANSI states we must use an internal static buffer if s is NULL */
151       result = _tmpnam_buf;
152     }
153   else
154     {
155       result = s;
156     }
157   pid = getpid ();
158 
159   if (worker (result, P_tmpdir, "t", pid, &_tls_inc))
160     {
161       _tls_inc++;
162       return result;
163     }
164 
165   return NULL;
166 }
167 
168 char *
tempnam(const char * dir,const char * pfx)169 tempnam (
170        const char *dir,
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 (length);
183   if (filename)
184     {
185       if (! worker (filename, dir, prefix,
186 		    getpid (), &_tls_inc))
187       {
188         free(filename);
189 	return NULL;
190       }
191     }
192   return filename;
193 }
194