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