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