0
|
1 |
/*
|
|
2 |
* CDDL HEADER START
|
|
3 |
*
|
|
4 |
* The contents of this file are subject to the terms of the
|
1475
|
5 |
* Common Development and Distribution License (the "License").
|
|
6 |
* You may not use this file except in compliance with the License.
|
0
|
7 |
*
|
|
8 |
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
|
9 |
* or http://www.opensolaris.org/os/licensing.
|
|
10 |
* See the License for the specific language governing permissions
|
|
11 |
* and limitations under the License.
|
|
12 |
*
|
|
13 |
* When distributing Covered Code, include this CDDL HEADER in each
|
|
14 |
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
|
15 |
* If applicable, add the following below this CDDL HEADER, with the
|
|
16 |
* fields enclosed by brackets "[]" replaced with your own identifying
|
|
17 |
* information: Portions Copyright [yyyy] [name of copyright owner]
|
|
18 |
*
|
|
19 |
* CDDL HEADER END
|
|
20 |
*/
|
|
21 |
/*
|
1475
|
22 |
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
|
0
|
23 |
* Use is subject to license terms.
|
|
24 |
*/
|
|
25 |
|
|
26 |
#pragma ident "%Z%%M% %I% %E% SMI"
|
|
27 |
|
|
28 |
/* Copyright (c) 1988 AT&T */
|
|
29 |
/* All Rights Reserved */
|
|
30 |
|
|
31 |
|
|
32 |
/*
|
|
33 |
* mktemp() expects a string with up to six trailing 'X's.
|
|
34 |
* These will be overlaid with letters, digits and symbols from
|
|
35 |
* the portable filename character set. If every combination thus
|
|
36 |
* inserted leads to an existing file name, the string is shortened
|
|
37 |
* to length zero and a pointer to a null string is returned.
|
|
38 |
*
|
|
39 |
* The guarantee made by mktime() to the caller is that the
|
|
40 |
* generated file name string will not match the string
|
|
41 |
* produced by any other concurrent process using mktemp().
|
|
42 |
* To guarantee uniqueness across the process-id space,
|
|
43 |
* the process-id of the caller is encoded into the string.
|
|
44 |
* To allow repeated calls within the same process to generate
|
|
45 |
* different strings on each call, a sequence number is encoded
|
|
46 |
* into the string along with process-id.
|
|
47 |
*
|
|
48 |
* The encoding is performed using radix-64 (6 bits per character),
|
|
49 |
* with 64 characters taken from the portable file name character set.
|
|
50 |
* This allows the six X's to be a representation of a 36-bit integer
|
|
51 |
* composed of bit fields:
|
|
52 |
* ( pid | seq )
|
|
53 |
* where the process-id occupies the high-order bits and the sequence
|
|
54 |
* number occupies the low-order bits. The size of the pid field is
|
|
55 |
* not fixed at the traditional 15 bits (MAXPID = 30000); the system
|
|
56 |
* now allows a larger process-id space and MAXPID is obtained from
|
|
57 |
* the system with a call to sysconf(_SC_MAXPID).
|
|
58 |
*
|
|
59 |
* mktime() should fail if fewer than six X's are presented to it.
|
|
60 |
* However, this has been traditionally accepted and is preserved
|
|
61 |
* in the present code. The consequence is that the 36-bit integer
|
|
62 |
* is reduced to a (6*N)-bit integer, where N is the number of X's.
|
|
63 |
* mktime() fails immediately if the resulting integer is not large
|
|
64 |
* enough to contain MAXPID.
|
|
65 |
*
|
|
66 |
* In an attempt to confuse and thwart hackers, the starting
|
|
67 |
* sequence number is randomized using the current time.
|
|
68 |
*/
|
|
69 |
|
|
70 |
#define XCNT 6
|
|
71 |
#pragma weak mktemp = _mktemp
|
|
72 |
|
|
73 |
#include "synonyms.h"
|
|
74 |
#include "mtlib.h"
|
|
75 |
#include <sys/types.h>
|
|
76 |
#include <string.h>
|
|
77 |
#include <unistd.h>
|
|
78 |
#include <thread.h>
|
|
79 |
#include <synch.h>
|
|
80 |
#include <sys/stat.h>
|
|
81 |
#include <errno.h>
|
|
82 |
#include <sys/time.h>
|
|
83 |
#include <stdlib.h>
|
|
84 |
#include <stdio.h>
|
|
85 |
#include <sys/param.h>
|
|
86 |
|
|
87 |
/*
|
|
88 |
* 64-bit digits, must be from the POSIX "portable file name character set".
|
|
89 |
*/
|
|
90 |
static char
|
|
91 |
chars[64] = {
|
|
92 |
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
|
|
93 |
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
|
|
94 |
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
|
|
95 |
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
|
|
96 |
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.', '_',
|
|
97 |
};
|
|
98 |
|
|
99 |
/*
|
|
100 |
* Find highest one bit set.
|
|
101 |
* Returns bit number of highest bit that is set.
|
|
102 |
* Low order bit is number 0, high order bit is number 31.
|
|
103 |
*/
|
|
104 |
static int
|
|
105 |
highbit(uint_t i)
|
|
106 |
{
|
|
107 |
int h = 0;
|
|
108 |
|
|
109 |
if (i & 0xffff0000)
|
|
110 |
h += 16, i >>= 16;
|
|
111 |
if (i & 0xff00)
|
|
112 |
h += 8, i >>= 8;
|
|
113 |
if (i & 0xf0)
|
|
114 |
h += 4, i >>= 4;
|
|
115 |
if (i & 0xc)
|
|
116 |
h += 2, i >>= 2;
|
|
117 |
if (i & 0x2)
|
|
118 |
h += 1;
|
|
119 |
return (h);
|
|
120 |
}
|
|
121 |
|
|
122 |
char *
|
1475
|
123 |
libc_mktemps(char *as, int slen)
|
0
|
124 |
{
|
|
125 |
/* statics are protected by this static mutex */
|
|
126 |
static mutex_t mktemp_lock = DEFAULTMUTEX;
|
|
127 |
static int pidshift = 0;
|
|
128 |
static int previous_try = 0;
|
|
129 |
static pid_t previous_pid = 0;
|
|
130 |
static int previous_xcnt = XCNT;
|
|
131 |
|
|
132 |
pid_t pid;
|
|
133 |
int try;
|
|
134 |
int tryshift;
|
|
135 |
int max_try;
|
|
136 |
char *s;
|
|
137 |
char *first_x;
|
|
138 |
int len;
|
|
139 |
uint_t xcnt;
|
|
140 |
struct stat64 buf;
|
|
141 |
|
|
142 |
if (as == NULL || *as == '\0') /* If the string passed is null then */
|
|
143 |
return (as); /* a pointer to a null string is returned. */
|
|
144 |
|
|
145 |
lmutex_lock(&mktemp_lock);
|
|
146 |
|
|
147 |
pid = getpid();
|
|
148 |
if (pid != previous_pid) { /* first time or first after fork() */
|
|
149 |
/*
|
|
150 |
* Randomize the starting sequence number in
|
|
151 |
* an attempt to confuse and thwart hackers.
|
|
152 |
* Use the low 12 bits of the time in milliseconds.
|
|
153 |
*/
|
|
154 |
struct timeval tm;
|
|
155 |
|
|
156 |
(void) gettimeofday(&tm, NULL);
|
|
157 |
previous_try = (tm.tv_sec * 1000 + tm.tv_usec / 1000) & 0xfff;
|
|
158 |
previous_pid = pid;
|
|
159 |
previous_xcnt = XCNT;
|
|
160 |
}
|
|
161 |
|
|
162 |
/* for all possible values of pid, 0 <= pid < (1 << pidshift) */
|
|
163 |
if (pidshift == 0) /* one-time initialization */
|
|
164 |
pidshift = highbit((uint_t)MAXPID) + 1;
|
|
165 |
|
|
166 |
/* count the X's */
|
|
167 |
xcnt = 0;
|
|
168 |
len = (int)strlen(as);
|
1475
|
169 |
if (slen >= len || slen < 0)
|
|
170 |
goto fail;
|
|
171 |
len -= slen;
|
0
|
172 |
s = as + (len - 1);
|
|
173 |
while ((len != 0) && (xcnt < XCNT) && (*s == 'X')) {
|
|
174 |
xcnt++;
|
|
175 |
len--;
|
|
176 |
--s;
|
|
177 |
}
|
|
178 |
first_x = s + 1; /* Remember pointer to the first X */
|
|
179 |
|
|
180 |
/* fail if we don't have enough X's to represent MAXPID */
|
|
181 |
if ((tryshift = xcnt * 6 - pidshift) < 0) {
|
|
182 |
/*
|
|
183 |
* Some broken programs call mktemp() repeatedly,
|
|
184 |
* passing the same string without reinserting the X's.
|
|
185 |
* Check to see if this is such a call by testing
|
|
186 |
* the trailing characters of the string for a
|
|
187 |
* match with the process-id.
|
|
188 |
*/
|
|
189 |
uint64_t xpid = 0; /* reconstructed pid */
|
|
190 |
|
|
191 |
s = as + len;
|
|
192 |
for (xcnt = previous_xcnt; xcnt && s > as; xcnt--) {
|
|
193 |
int c;
|
|
194 |
int i;
|
|
195 |
|
|
196 |
c = *--s;
|
|
197 |
for (i = 0; i < 64; i++)
|
|
198 |
if (c == chars[i])
|
|
199 |
break;
|
|
200 |
if (i == 64)
|
|
201 |
goto fail;
|
|
202 |
xpid = xpid * 64 + i;
|
|
203 |
}
|
|
204 |
xpid >>= (previous_xcnt * 6 - pidshift);
|
|
205 |
xpid &= ((1 << pidshift) - 1);
|
|
206 |
|
|
207 |
if (xpid == pid &&
|
|
208 |
lstat64(as, &buf) == -1 && errno == ENOENT) {
|
|
209 |
lmutex_unlock(&mktemp_lock);
|
|
210 |
return (as);
|
|
211 |
}
|
|
212 |
|
|
213 |
goto fail;
|
|
214 |
}
|
|
215 |
|
|
216 |
/* we can try sequence numbers in the range 0 <= try < max_try */
|
|
217 |
max_try = 1 << tryshift;
|
|
218 |
if (previous_try >= max_try)
|
|
219 |
previous_try = 0;
|
|
220 |
|
|
221 |
try = previous_try;
|
|
222 |
for (;;) {
|
|
223 |
/* num is up to a 36-bit integer ... */
|
|
224 |
uint64_t num = ((uint64_t)pid << tryshift) + (uint64_t)try;
|
|
225 |
int i;
|
|
226 |
|
|
227 |
/* ... which we represent backwards in base 64 */
|
|
228 |
for (i = 0, s = first_x; i < xcnt; i++) {
|
|
229 |
*s++ = chars[num & 077];
|
|
230 |
num >>= 6;
|
|
231 |
}
|
|
232 |
|
|
233 |
if (lstat64(as, &buf) == -1) {
|
|
234 |
if (errno != ENOENT)
|
|
235 |
break; /* unrecoverable error */
|
|
236 |
/* remember where we left off for the next call */
|
|
237 |
previous_try = try + 1;
|
|
238 |
previous_xcnt = xcnt;
|
|
239 |
lmutex_unlock(&mktemp_lock);
|
|
240 |
return (as);
|
|
241 |
}
|
|
242 |
|
|
243 |
if (++try == max_try)
|
|
244 |
try = 0;
|
|
245 |
if (try == previous_try)
|
|
246 |
break;
|
|
247 |
}
|
|
248 |
|
|
249 |
fail:
|
|
250 |
lmutex_unlock(&mktemp_lock);
|
|
251 |
*as = '\0';
|
|
252 |
return (as);
|
|
253 |
}
|
1475
|
254 |
|
|
255 |
char *
|
|
256 |
mktemp(char *template)
|
|
257 |
{
|
|
258 |
return (libc_mktemps(template, 0));
|
|
259 |
}
|