]>
Commit | Line | Data |
---|---|---|
1fd5e000 CF |
1 | /* environ.cc: Cygwin-adopted functions from newlib to manipulate |
2 | process's environment. | |
3 | ||
0ae86d18 | 4 | Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, |
a7d2cc16 | 5 | 2006, 2007, 2008 Red Hat, Inc. |
1fd5e000 CF |
6 | |
7 | This software is a copyrighted work licensed under the terms of the | |
8 | Cygwin license. Please consult the file "CYGWIN_LICENSE" for | |
9 | details. */ | |
10 | ||
4c8d72de | 11 | #include "winsup.h" |
1fd5e000 | 12 | #include <stdlib.h> |
5ab0b5cf | 13 | #include <wchar.h> |
752b16ce | 14 | #include <wctype.h> |
1fd5e000 | 15 | #include <ctype.h> |
12a2ef44 | 16 | #include <assert.h> |
f0338f54 | 17 | #include <cygwin/version.h> |
a7197550 | 18 | #include <winnls.h> |
e2ebe117 | 19 | #include "pinfo.h" |
95a8465b | 20 | #include "perprocess.h" |
bccd5e0d | 21 | #include "path.h" |
9e2baf8d | 22 | #include "cygerrno.h" |
169c465a | 23 | #include "fhandler.h" |
0381fec6 | 24 | #include "dtable.h" |
d8242040 | 25 | #include "cygheap.h" |
f4a1f8a1 | 26 | #include "cygtls.h" |
752b16ce | 27 | #include "tls_pbuf.h" |
f0338f54 CF |
28 | #include "registry.h" |
29 | #include "environ.h" | |
7c02f861 | 30 | #include "child_info.h" |
1fd5e000 | 31 | |
01bbb24d | 32 | extern bool dos_file_warning; |
3872e9a4 | 33 | extern bool allow_glob; |
95a8465b | 34 | extern bool ignore_case_with_glob; |
3872e9a4 CF |
35 | extern bool allow_winsymlinks; |
36 | extern bool strip_title_path; | |
70c370d6 | 37 | extern int pcheck_case; |
3872e9a4 | 38 | bool reset_com = false; |
3872e9a4 | 39 | static bool envcache = true; |
4392d36c CF |
40 | #ifdef USE_SERVER |
41 | extern bool allow_server; | |
42 | #endif | |
1fd5e000 | 43 | |
08b78edf | 44 | static char **lastenviron; |
b0e82b74 | 45 | |
edab6053 CV |
46 | /* Helper functions for the below environment variables which have to |
47 | be converted Win32<->POSIX. */ | |
48 | extern "C" ssize_t env_PATH_to_posix (const void *, void *, size_t); | |
49 | ||
50 | ssize_t | |
51 | env_plist_to_posix (const void *win32, void *posix, size_t size) | |
52 | { | |
53 | return cygwin_conv_path_list (CCP_WIN_A_TO_POSIX | CCP_RELATIVE, win32, | |
54 | posix, size); | |
55 | } | |
56 | ||
57 | ssize_t | |
58 | env_plist_to_win32 (const void *posix, void *win32, size_t size) | |
59 | { | |
60 | return cygwin_conv_path_list (CCP_POSIX_TO_WIN_A | CCP_RELATIVE, posix, | |
61 | win32, size); | |
62 | } | |
63 | ||
64 | ssize_t | |
65 | env_path_to_posix (const void *win32, void *posix, size_t size) | |
66 | { | |
67 | return cygwin_conv_path (CCP_WIN_A_TO_POSIX | CCP_ABSOLUTE, win32, | |
68 | posix, size); | |
69 | } | |
70 | ||
71 | ssize_t | |
72 | env_path_to_win32 (const void *posix, void *win32, size_t size) | |
73 | { | |
74 | return cygwin_conv_path (CCP_POSIX_TO_WIN_A | CCP_ABSOLUTE, posix, | |
75 | win32, size); | |
76 | } | |
6f1d4862 | 77 | |
9bc846bd CF |
78 | #define ENVMALLOC \ |
79 | (CYGWIN_VERSION_DLL_MAKE_COMBINED (user_data->api_major, user_data->api_minor) \ | |
80 | <= CYGWIN_VERSION_DLL_MALLOC_ENV) | |
81 | ||
a05a9e01 | 82 | #define NL(x) x, (sizeof (x) - 1) |
1fd5e000 | 83 | /* List of names which are converted from dos to unix |
ee1d77e4 | 84 | on the way in and back again on the way out. |
94b03f23 | 85 | |
ee1d77e4 CF |
86 | PATH needs to be here because CreateProcess uses it and gdb uses |
87 | CreateProcess. HOME is here because most shells use it and would be | |
88 | confused by Windows style path names. */ | |
ac300315 | 89 | static win_env conv_envvars[] = |
1fd5e000 | 90 | { |
edab6053 CV |
91 | {NL ("PATH="), NULL, NULL, env_PATH_to_posix, env_plist_to_win32, true}, |
92 | {NL ("HOME="), NULL, NULL, env_path_to_posix, env_path_to_win32, false}, | |
93 | {NL ("LD_LIBRARY_PATH="), NULL, NULL, | |
94 | env_plist_to_posix, env_plist_to_win32, true}, | |
95 | {NL ("TMPDIR="), NULL, NULL, env_path_to_posix, env_path_to_win32, false}, | |
96 | {NL ("TMP="), NULL, NULL, env_path_to_posix, env_path_to_win32, false}, | |
97 | {NL ("TEMP="), NULL, NULL, env_path_to_posix, env_path_to_win32, false}, | |
98 | {NULL, 0, NULL, NULL, 0, 0} | |
1fd5e000 CF |
99 | }; |
100 | ||
6e8f36bc DD |
101 | static unsigned char conv_start_chars[256] = {0}; |
102 | ||
47dc3dec CF |
103 | struct win_env& |
104 | win_env::operator = (struct win_env& x) | |
105 | { | |
106 | name = x.name; | |
107 | namelen = x.namelen; | |
108 | toposix = x.toposix; | |
109 | towin32 = x.towin32; | |
47dc3dec CF |
110 | immediate = false; |
111 | return *this; | |
112 | } | |
113 | ||
114 | win_env::~win_env () | |
115 | { | |
116 | if (posix) | |
117 | free (posix); | |
118 | if (native) | |
119 | free (native); | |
120 | } | |
121 | ||
1fd5e000 CF |
122 | void |
123 | win_env::add_cache (const char *in_posix, const char *in_native) | |
124 | { | |
ebd645e7 | 125 | MALLOC_CHECK; |
1fd5e000 CF |
126 | posix = (char *) realloc (posix, strlen (in_posix) + 1); |
127 | strcpy (posix, in_posix); | |
128 | if (in_native) | |
129 | { | |
130 | native = (char *) realloc (native, namelen + 1 + strlen (in_native)); | |
0c55f6ed CF |
131 | strcpy (native, name); |
132 | strcpy (native + namelen, in_native); | |
1fd5e000 CF |
133 | } |
134 | else | |
135 | { | |
752b16ce CV |
136 | tmp_pathbuf tp; |
137 | char *buf = tp.c_get (); | |
1feea0bf | 138 | strcpy (buf, name + namelen); |
edab6053 | 139 | towin32 (in_posix, buf, NT_MAX_PATH); |
1feea0bf | 140 | native = (char *) realloc (native, namelen + 1 + strlen (buf)); |
0c55f6ed | 141 | strcpy (native, name); |
1feea0bf | 142 | strcpy (native + namelen, buf); |
1fd5e000 | 143 | } |
ebd645e7 | 144 | MALLOC_CHECK; |
77ae8757 | 145 | if (immediate && cygwin_finished_initializing) |
47dc3dec CF |
146 | { |
147 | char s[namelen]; | |
148 | size_t n = namelen - 1; | |
149 | memcpy (s, name, n); | |
150 | s[n] = '\0'; | |
151 | SetEnvironmentVariable (s, native + namelen); | |
152 | } | |
1fd5e000 CF |
153 | debug_printf ("posix %s", posix); |
154 | debug_printf ("native %s", native); | |
155 | } | |
156 | ||
157 | ||
158 | /* Check for a "special" environment variable name. *env is the pointer | |
12a2ef44 CF |
159 | to the beginning of the environment variable name. *in_posix is any |
160 | known posix value for the environment variable. Returns a pointer to | |
161 | the appropriate conversion structure. */ | |
2b706f3f | 162 | win_env * __stdcall |
47dc3dec | 163 | getwinenv (const char *env, const char *in_posix, win_env *temp) |
1fd5e000 | 164 | { |
6e8f36bc DD |
165 | if (!conv_start_chars[(unsigned char)*env]) |
166 | return NULL; | |
167 | ||
1fd5e000 | 168 | for (int i = 0; conv_envvars[i].name != NULL; i++) |
0381fec6 | 169 | if (strncmp (env, conv_envvars[i].name, conv_envvars[i].namelen) == 0) |
1fd5e000 | 170 | { |
47dc3dec | 171 | win_env *we = conv_envvars + i; |
1fd5e000 | 172 | const char *val; |
12a2ef44 | 173 | if (!cur_environ () || !(val = in_posix ?: getenv (we->name))) |
1fd5e000 CF |
174 | debug_printf ("can't set native for %s since no environ yet", |
175 | we->name); | |
17743fbc | 176 | else if (!envcache || !we->posix || strcmp (val, we->posix) != 0) |
47dc3dec CF |
177 | { |
178 | if (temp) | |
179 | { | |
180 | *temp = *we; | |
181 | we = temp; | |
182 | } | |
183 | we->add_cache (val); | |
184 | } | |
1fd5e000 CF |
185 | return we; |
186 | } | |
187 | return NULL; | |
188 | } | |
189 | ||
190 | /* Convert windows path specs to POSIX, if appropriate. | |
191 | */ | |
192 | static void __stdcall | |
752b16ce | 193 | posify (char **here, const char *value, char *outenv) |
1fd5e000 CF |
194 | { |
195 | char *src = *here; | |
196 | win_env *conv; | |
1fd5e000 CF |
197 | |
198 | if (!(conv = getwinenv (src))) | |
199 | return; | |
200 | ||
ac944e37 CF |
201 | int len = strcspn (src, "=") + 1; |
202 | ||
b0e82b74 CF |
203 | /* Turn all the items from c:<foo>;<bar> into their |
204 | mounted equivalents - if there is one. */ | |
1fd5e000 | 205 | |
b0e82b74 | 206 | memcpy (outenv, src, len); |
6f1d4862 | 207 | char *newvalue = outenv + len; |
edab6053 CV |
208 | if (!conv->toposix (value, newvalue, NT_MAX_PATH - len) |
209 | || _impure_ptr->_errno != EIDRM) | |
6f1d4862 CF |
210 | conv->add_cache (newvalue, *value != '/' ? value : NULL); |
211 | else | |
212 | { | |
213 | /* The conversion routine removed elements from a path list so we have | |
214 | to recalculate the windows path to remove elements there, too. */ | |
215 | char cleanvalue[strlen (value) + 1]; | |
edab6053 | 216 | conv->towin32 (newvalue, cleanvalue, sizeof cleanvalue); |
6f1d4862 CF |
217 | conv->add_cache (newvalue, cleanvalue); |
218 | } | |
1fd5e000 | 219 | |
b0e82b74 | 220 | debug_printf ("env var converted to %s", outenv); |
1feea0bf | 221 | *here = strdup (outenv); |
b0e82b74 | 222 | free (src); |
ebd645e7 | 223 | MALLOC_CHECK; |
1fd5e000 CF |
224 | } |
225 | ||
478e8b15 CF |
226 | /* Returns pointer to value associated with name, if any, else NULL. |
227 | Sets offset to be the offset of the name/value combination in the | |
228 | environment array, for use by setenv(3) and unsetenv(3). | |
229 | Explicitly removes '=' in argument name. */ | |
1fd5e000 CF |
230 | |
231 | static char * __stdcall | |
232 | my_findenv (const char *name, int *offset) | |
233 | { | |
234 | register int len; | |
235 | register char **p; | |
236 | const char *c; | |
237 | ||
238 | c = name; | |
239 | len = 0; | |
240 | while (*c && *c != '=') | |
241 | { | |
242 | c++; | |
243 | len++; | |
244 | } | |
245 | ||
4c8d72de | 246 | for (p = cur_environ (); *p; ++p) |
1fd5e000 CF |
247 | if (!strncmp (*p, name, len)) |
248 | if (*(c = *p + len) == '=') | |
249 | { | |
4c8d72de | 250 | *offset = p - cur_environ (); |
1fd5e000 CF |
251 | return (char *) (++c); |
252 | } | |
ebd645e7 | 253 | MALLOC_CHECK; |
1fd5e000 CF |
254 | return NULL; |
255 | } | |
34f5d087 | 256 | |
16dc3c95 | 257 | /* Primitive getenv before the environment is built. */ |
33b0abd1 | 258 | |
16dc3c95 | 259 | static char __stdcall * |
3a83d3a8 | 260 | getearly (const char * name, int *) |
33b0abd1 | 261 | { |
3a83d3a8 | 262 | char *ret; |
16dc3c95 | 263 | char **ptr; |
3a83d3a8 | 264 | int len; |
16dc3c95 | 265 | |
3a83d3a8 CF |
266 | if (spawn_info && (ptr = spawn_info->moreinfo->envp)) |
267 | { | |
268 | len = strlen (name); | |
269 | for (; *ptr; ptr++) | |
a2649dc6 | 270 | if (strncasematch (name, *ptr, len) && (*ptr)[len] == '=') |
3a83d3a8 CF |
271 | return *ptr + len + 1; |
272 | } | |
5ab0b5cf | 273 | else if ((len = GetEnvironmentVariableA (name, NULL, 0)) |
ee4388c4 | 274 | && (ret = (char *) cmalloc_abort (HEAP_2_STR, len)) |
5ab0b5cf | 275 | && GetEnvironmentVariableA (name, ret, len)) |
3a83d3a8 | 276 | return ret; |
33b0abd1 | 277 | |
33b0abd1 CV |
278 | return NULL; |
279 | } | |
280 | ||
281 | static char * (*findenv_func)(const char *, int *) = (char * (*)(const char *, int *)) getearly; | |
282 | ||
16dc3c95 | 283 | /* Returns ptr to value associated with name, if any, else NULL. */ |
1fd5e000 | 284 | |
2b706f3f | 285 | extern "C" char * |
1fd5e000 CF |
286 | getenv (const char *name) |
287 | { | |
288 | int offset; | |
33b0abd1 | 289 | return findenv_func (name, &offset); |
1fd5e000 CF |
290 | } |
291 | ||
da086d02 CF |
292 | static int __stdcall |
293 | envsize (const char * const *in_envp) | |
b0e82b74 CF |
294 | { |
295 | const char * const *envp; | |
296 | for (envp = in_envp; *envp; envp++) | |
da086d02 | 297 | continue; |
b0e82b74 CF |
298 | return (1 + envp - in_envp) * sizeof (const char *); |
299 | } | |
300 | ||
2a1a9785 CF |
301 | /* Takes similar arguments to setenv except that overwrite is |
302 | either -1, 0, or 1. 0 or 1 signify that the function should | |
303 | perform similarly to setenv. Otherwise putenv is assumed. */ | |
304 | static int __stdcall | |
305 | _addenv (const char *name, const char *value, int overwrite) | |
1fd5e000 | 306 | { |
2a1a9785 CF |
307 | int issetenv = overwrite >= 0; |
308 | int offset; | |
309 | char *p; | |
1fd5e000 | 310 | |
2a1a9785 CF |
311 | unsigned int valuelen = strlen (value); |
312 | if ((p = my_findenv (name, &offset))) | |
313 | { /* Already exists. */ | |
314 | if (!overwrite) /* Ok to overwrite? */ | |
315 | return 0; /* No. Wanted to add new value. FIXME: Right return value? */ | |
1fd5e000 | 316 | |
2a1a9785 CF |
317 | /* We've found the offset into environ. If this is a setenv call and |
318 | there is room in the current environment entry then just overwrite it. | |
319 | Otherwise handle this case below. */ | |
320 | if (issetenv && strlen (p) >= valuelen) | |
321 | { | |
322 | strcpy (p, value); | |
1fd5e000 CF |
323 | return 0; |
324 | } | |
325 | } | |
326 | else | |
2a1a9785 | 327 | { /* Create new slot. */ |
b0e82b74 | 328 | int sz = envsize (cur_environ ()); |
ebd645e7 | 329 | int allocsz = sz + (2 * sizeof (char *)); |
2a1a9785 | 330 | |
b0e82b74 | 331 | offset = (sz - 1) / sizeof (char *); |
2a1a9785 CF |
332 | |
333 | /* Allocate space for additional element plus terminating NULL. */ | |
ebd645e7 | 334 | if (cur_environ () == lastenviron) |
b0e82b74 CF |
335 | lastenviron = __cygwin_environ = (char **) realloc (cur_environ (), |
336 | allocsz); | |
337 | else if ((lastenviron = (char **) malloc (allocsz)) != NULL) | |
338 | __cygwin_environ = (char **) memcpy ((char **) lastenviron, | |
339 | __cygwin_environ, sz); | |
340 | ||
b0d5cd02 | 341 | if (!__cygwin_environ) |
ad30b4ff | 342 | { |
64ef9db7 | 343 | #ifdef DEBUGGING |
ad30b4ff | 344 | try_to_debug (); |
ad30b4ff | 345 | #endif |
ebd645e7 | 346 | return -1; /* Oops. No more memory. */ |
ad30b4ff | 347 | } |
1fd5e000 | 348 | |
2a1a9785 CF |
349 | __cygwin_environ[offset + 1] = NULL; /* NULL terminate. */ |
350 | update_envptrs (); /* Update any local copies of 'environ'. */ | |
351 | } | |
1fd5e000 | 352 | |
2a1a9785 CF |
353 | char *envhere; |
354 | if (!issetenv) | |
9bc846bd CF |
355 | /* Not setenv. Just overwrite existing. */ |
356 | envhere = cur_environ ()[offset] = (char *) (ENVMALLOC ? strdup (name) : name); | |
2a1a9785 CF |
357 | else |
358 | { /* setenv */ | |
359 | /* Look for an '=' in the name and ignore anything after that if found. */ | |
360 | for (p = (char *) name; *p && *p != '='; p++) | |
361 | continue; | |
362 | ||
363 | int namelen = p - name; /* Length of name. */ | |
364 | /* Allocate enough space for name + '=' + value + '\0' */ | |
4c8d72de | 365 | envhere = cur_environ ()[offset] = (char *) malloc (namelen + valuelen + 2); |
2a1a9785 CF |
366 | if (!envhere) |
367 | return -1; /* Oops. No more memory. */ | |
368 | ||
369 | /* Put name '=' value into current slot. */ | |
370 | strncpy (envhere, name, namelen); | |
371 | envhere[namelen] = '='; | |
372 | strcpy (envhere + namelen + 1, value); | |
373 | } | |
1fd5e000 | 374 | |
2a1a9785 | 375 | /* Update cygwin's cache, if appropriate */ |
1fd5e000 | 376 | win_env *spenv; |
2a1a9785 | 377 | if ((spenv = getwinenv (envhere))) |
1fd5e000 CF |
378 | spenv->add_cache (value); |
379 | ||
ebd645e7 | 380 | MALLOC_CHECK; |
1fd5e000 CF |
381 | return 0; |
382 | } | |
383 | ||
16dc3c95 | 384 | /* Set an environment variable */ |
2a1a9785 | 385 | extern "C" int |
69037299 | 386 | putenv (char *str) |
2a1a9785 | 387 | { |
893ac8e0 CF |
388 | myfault efault; |
389 | if (efault.faulted (EFAULT)) | |
390 | return -1; | |
391 | if (*str) | |
0d4c5950 | 392 | { |
893ac8e0 CF |
393 | char *eq = strchr (str, '='); |
394 | if (eq) | |
395 | return _addenv (str, eq + 1, -1); | |
2a1a9785 | 396 | |
893ac8e0 CF |
397 | /* Remove str from the environment. */ |
398 | unsetenv (str); | |
399 | } | |
2a1a9785 CF |
400 | return 0; |
401 | } | |
402 | ||
16dc3c95 | 403 | /* Set the value of the environment variable "name" to be |
ee1d77e4 | 404 | "value". If overwrite is set, replace any current value. */ |
2a1a9785 CF |
405 | extern "C" int |
406 | setenv (const char *name, const char *value, int overwrite) | |
407 | { | |
893ac8e0 CF |
408 | myfault efault; |
409 | if (efault.faulted (EFAULT)) | |
410 | return -1; | |
411 | if (!*name) | |
412 | return 0; | |
2a1a9785 CF |
413 | if (*value == '=') |
414 | value++; | |
415 | return _addenv (name, value, !!overwrite); | |
416 | } | |
417 | ||
16dc3c95 | 418 | /* Delete environment variable "name". */ |
e5a0cf24 | 419 | extern "C" int |
1fd5e000 CF |
420 | unsetenv (const char *name) |
421 | { | |
5bc584ba | 422 | register char **e; |
1fd5e000 | 423 | int offset; |
e5a0cf24 CF |
424 | myfault efault; |
425 | if (efault.faulted () || *name == '\0' || strchr (name, '=')) | |
426 | { | |
427 | set_errno (EINVAL); | |
428 | return -1; | |
429 | } | |
1fd5e000 CF |
430 | |
431 | while (my_findenv (name, &offset)) /* if set multiple times */ | |
5bc584ba | 432 | /* Move up the rest of the array */ |
4c8d72de | 433 | for (e = cur_environ () + offset; ; e++) |
5bc584ba | 434 | if (!(*e = *(e + 1))) |
1fd5e000 | 435 | break; |
e5a0cf24 CF |
436 | |
437 | return 0; | |
1fd5e000 CF |
438 | } |
439 | ||
440 | /* Turn environment variable part of a=b string into uppercase. */ | |
9cec3d45 | 441 | static __inline__ void |
1fd5e000 CF |
442 | ucenv (char *p, char *eq) |
443 | { | |
444 | /* Amazingly, NT has a case sensitive environment name list, | |
445 | but only sometimes. | |
446 | It's normal to have NT set your "Path" to something. | |
447 | Later, you set "PATH" to something else. This alters "Path". | |
448 | But if you try and do a naive getenv on "PATH" you'll get nothing. | |
449 | ||
450 | So we upper case the labels here to prevent confusion later but | |
451 | we only do it for the first process in a session group. */ | |
452 | for (; p < eq; p++) | |
453 | if (islower (*p)) | |
2556e737 | 454 | *p = cyg_toupper (*p); |
1fd5e000 CF |
455 | } |
456 | ||
457 | /* Parse CYGWIN options */ | |
458 | ||
3872e9a4 | 459 | static NO_COPY bool export_settings = false; |
1fd5e000 CF |
460 | |
461 | enum settings | |
462 | { | |
463 | justset, | |
464 | isfunc, | |
465 | setbit, | |
466 | set_process_state, | |
467 | }; | |
468 | ||
6ccb6bcf | 469 | /* When BUF is: |
ee1d77e4 CF |
470 | null or empty: disables globbing |
471 | "ignorecase": enables case-insensitive globbing | |
472 | anything else: enables case-sensitive globbing */ | |
6ccb6bcf CF |
473 | static void |
474 | glob_init (const char *buf) | |
475 | { | |
476 | if (!buf || !*buf) | |
477 | { | |
3872e9a4 CF |
478 | allow_glob = false; |
479 | ignore_case_with_glob = false; | |
6ccb6bcf | 480 | } |
c69d873f | 481 | else if (ascii_strncasematch (buf, "ignorecase", 10)) |
6ccb6bcf | 482 | { |
3872e9a4 CF |
483 | allow_glob = true; |
484 | ignore_case_with_glob = true; | |
6ccb6bcf CF |
485 | } |
486 | else | |
487 | { | |
3872e9a4 CF |
488 | allow_glob = true; |
489 | ignore_case_with_glob = false; | |
6ccb6bcf CF |
490 | } |
491 | } | |
492 | ||
70c370d6 CV |
493 | static void |
494 | check_case_init (const char *buf) | |
495 | { | |
496 | if (!buf || !*buf) | |
497 | return; | |
498 | ||
c69d873f | 499 | if (ascii_strncasematch (buf, "relax", 5)) |
70c370d6 CV |
500 | { |
501 | pcheck_case = PCHECK_RELAXED; | |
502 | debug_printf ("File case checking set to RELAXED"); | |
503 | } | |
c69d873f | 504 | else if (ascii_strcasematch (buf, "adjust")) |
70c370d6 CV |
505 | { |
506 | pcheck_case = PCHECK_ADJUST; | |
507 | debug_printf ("File case checking set to ADJUST"); | |
508 | } | |
c69d873f | 509 | else if (ascii_strcasematch (buf, "strict")) |
70c370d6 CV |
510 | { |
511 | pcheck_case = PCHECK_STRICT; | |
512 | debug_printf ("File case checking set to STRICT"); | |
513 | } | |
514 | else | |
515 | { | |
516 | debug_printf ("Wrong case checking name: %s", buf); | |
517 | } | |
518 | } | |
519 | ||
4c15b7ab ED |
520 | void |
521 | set_file_api_mode (codepage_type cp) | |
522 | { | |
523 | if (cp == oem_cp) | |
524 | { | |
525 | SetFileApisToOEM (); | |
526 | debug_printf ("File APIs set to OEM"); | |
527 | } | |
1597484c | 528 | else |
4c15b7ab ED |
529 | { |
530 | SetFileApisToANSI (); | |
531 | debug_printf ("File APIs set to ANSI"); | |
532 | } | |
533 | } | |
534 | ||
a7197550 | 535 | void |
077ec4cb CF |
536 | codepage_init (const char *buf) |
537 | { | |
a7197550 CV |
538 | if (!buf) |
539 | buf = "ansi"; | |
077ec4cb | 540 | |
c69d873f | 541 | if (ascii_strcasematch (buf, "oem")) |
a7197550 CV |
542 | { |
543 | current_codepage = oem_cp; | |
544 | active_codepage = GetOEMCP (); | |
545 | } | |
c69d873f | 546 | else if (ascii_strcasematch (buf, "utf8")) |
a7197550 CV |
547 | { |
548 | current_codepage = utf8_cp; | |
549 | active_codepage = CP_UTF8; | |
550 | } | |
077ec4cb | 551 | else |
a7197550 CV |
552 | { |
553 | if (!ascii_strcasematch (buf, "ansi")) | |
554 | debug_printf ("Wrong codepage name: %s", buf); | |
555 | /* Fallback to ANSI */ | |
556 | current_codepage = ansi_cp; | |
557 | active_codepage = GetACP (); | |
558 | } | |
1597484c | 559 | set_file_api_mode (current_codepage); |
077ec4cb CF |
560 | } |
561 | ||
ba946828 CV |
562 | static void |
563 | set_chunksize (const char *buf) | |
564 | { | |
84d38174 CF |
565 | wincap.set_chunksize (strtoul (buf, NULL, 0)); |
566 | } | |
567 | ||
568 | static void | |
a9396868 | 569 | set_proc_retry (const char *buf) |
84d38174 | 570 | { |
a9396868 | 571 | child_info::retry_count = strtoul (buf, NULL, 0); |
ba946828 CV |
572 | } |
573 | ||
12618f5f CV |
574 | static void |
575 | set_ntsec (const char *buf) | |
576 | { | |
c69d873f | 577 | allow_ntsec = (buf && ascii_strcasematch (buf, "yes")); |
12618f5f CV |
578 | } |
579 | ||
580 | static void | |
581 | set_smbntsec (const char *buf) | |
582 | { | |
c69d873f | 583 | allow_smbntsec = (buf && ascii_strcasematch (buf, "yes")); |
12618f5f CV |
584 | } |
585 | ||
1fd5e000 | 586 | /* The structure below is used to set up an array which is used to |
ee1d77e4 CF |
587 | parse the CYGWIN environment variable or, if enabled, options from |
588 | the registry. */ | |
57c89867 | 589 | static struct parse_thing |
1fd5e000 CF |
590 | { |
591 | const char *name; | |
592 | union parse_setting | |
593 | { | |
3872e9a4 | 594 | bool *b; |
1fd5e000 CF |
595 | DWORD *x; |
596 | int *i; | |
597 | void (*func)(const char *); | |
598 | } setting; | |
599 | ||
600 | enum settings disposition; | |
601 | char *remember; | |
602 | union parse_values | |
603 | { | |
604 | DWORD i; | |
605 | const char *s; | |
606 | } values[2]; | |
57c89867 | 607 | } known[] NO_COPY = |
1fd5e000 | 608 | { |
5a41f96d | 609 | {"binmode", {x: &binmode}, justset, NULL, {{O_TEXT}, {O_BINARY}}}, |
70c370d6 | 610 | {"check_case", {func: &check_case_init}, isfunc, NULL, {{0}, {0}}}, |
ee1d77e4 | 611 | {"codepage", {func: &codepage_init}, isfunc, NULL, {{0}, {0}}}, |
01bbb24d | 612 | {"dosfilewarning", {&dos_file_warning}, justset, NULL, {{false}, {true}}}, |
3872e9a4 | 613 | {"envcache", {&envcache}, justset, NULL, {{true}, {false}}}, |
1fd5e000 | 614 | {"error_start", {func: &error_start_init}, isfunc, NULL, {{0}, {0}}}, |
3872e9a4 | 615 | {"export", {&export_settings}, justset, NULL, {{false}, {true}}}, |
ba946828 | 616 | {"forkchunk", {func: set_chunksize}, isfunc, NULL, {{0}, {0}}}, |
6ccb6bcf | 617 | {"glob", {func: &glob_init}, isfunc, NULL, {{0}, {s: "normal"}}}, |
12618f5f | 618 | {"ntsec", {func: set_ntsec}, isfunc, NULL, {{0}, {s: "yes"}}}, |
01bbb24d | 619 | {"proc_retry", {func: set_proc_retry}, isfunc, NULL, {{0}, {5}}}, |
3872e9a4 | 620 | {"reset_com", {&reset_com}, justset, NULL, {{false}, {true}}}, |
740760ec CV |
621 | #ifdef USE_SERVER |
622 | {"server", {&allow_server}, justset, NULL, {{false}, {true}}}, | |
623 | #endif | |
624 | {"smbntsec", {func: set_smbntsec}, isfunc, NULL, {{0}, {s: "yes"}}}, | |
3872e9a4 | 625 | {"strip_title", {&strip_title_path}, justset, NULL, {{false}, {true}}}, |
3872e9a4 | 626 | {"title", {&display_title}, justset, NULL, {{false}, {true}}}, |
1fd5e000 | 627 | {"tty", {NULL}, set_process_state, NULL, {{0}, {PID_USETTY}}}, |
3872e9a4 | 628 | {"winsymlinks", {&allow_winsymlinks}, justset, NULL, {{false}, {true}}}, |
fbae2bf8 | 629 | {"transparent_exe", {&transparent_exe}, justset, NULL, {{false}, {true}}}, |
1fd5e000 CF |
630 | {NULL, {0}, justset, 0, {{0}, {0}}} |
631 | }; | |
632 | ||
633 | /* Parse a string of the form "something=stuff somethingelse=more-stuff", | |
ee1d77e4 | 634 | silently ignoring unknown "somethings". */ |
1fd5e000 CF |
635 | static void __stdcall |
636 | parse_options (char *buf) | |
637 | { | |
638 | int istrue; | |
e212576d | 639 | char *p, *lasts; |
1fd5e000 CF |
640 | parse_thing *k; |
641 | ||
642 | if (buf == NULL) | |
643 | { | |
becf251f CV |
644 | tmp_pathbuf tp; |
645 | char *newbuf = tp.c_get (); | |
8a2ce995 | 646 | newbuf[0] = '\0'; |
1fd5e000 CF |
647 | for (k = known; k->name != NULL; k++) |
648 | if (k->remember) | |
649 | { | |
650 | strcat (strcat (newbuf, " "), k->remember); | |
651 | free (k->remember); | |
652 | k->remember = NULL; | |
653 | } | |
8a2ce995 CF |
654 | |
655 | if (export_settings) | |
656 | { | |
657 | debug_printf ("%s", newbuf + 1); | |
658 | setenv ("CYGWIN", newbuf + 1, 1); | |
659 | } | |
1fd5e000 CF |
660 | return; |
661 | } | |
662 | ||
663 | buf = strcpy ((char *) alloca (strlen (buf) + 1), buf); | |
e212576d CV |
664 | for (p = strtok_r (buf, " \t", &lasts); |
665 | p != NULL; | |
666 | p = strtok_r (NULL, " \t", &lasts)) | |
1fd5e000 | 667 | { |
25859d7c | 668 | char *keyword_here = p; |
c69d873f | 669 | if (!(istrue = !ascii_strncasematch (p, "no", 2))) |
1fd5e000 CF |
670 | p += 2; |
671 | else if (!(istrue = *p != '-')) | |
672 | p++; | |
673 | ||
674 | char ch, *eq; | |
675 | if ((eq = strchr (p, '=')) != NULL || (eq = strchr (p, ':')) != NULL) | |
676 | ch = *eq, *eq++ = '\0'; | |
677 | else | |
678 | ch = 0; | |
679 | ||
680 | for (parse_thing *k = known; k->name != NULL; k++) | |
c69d873f | 681 | if (ascii_strcasematch (p, k->name)) |
1fd5e000 CF |
682 | { |
683 | switch (k->disposition) | |
684 | { | |
685 | case isfunc: | |
686 | k->setting.func ((!eq || !istrue) ? | |
687 | k->values[istrue].s : eq); | |
688 | debug_printf ("%s (called func)", k->name); | |
689 | break; | |
690 | case justset: | |
691 | if (!istrue || !eq) | |
692 | *k->setting.x = k->values[istrue].i; | |
693 | else | |
694 | *k->setting.x = strtol (eq, NULL, 0); | |
695 | debug_printf ("%s %d", k->name, *k->setting.x); | |
696 | break; | |
697 | case set_process_state: | |
698 | k->setting.x = &myself->process_state; | |
699 | /* fall through */ | |
700 | case setbit: | |
701 | *k->setting.x &= ~k->values[istrue].i; | |
702 | if (istrue || (eq && strtol (eq, NULL, 0))) | |
703 | *k->setting.x |= k->values[istrue].i; | |
704 | debug_printf ("%s %x", k->name, *k->setting.x); | |
705 | break; | |
706 | } | |
707 | ||
708 | if (eq) | |
709 | *--eq = ch; | |
710 | ||
711 | int n = eq - p; | |
25859d7c | 712 | p = strdup (keyword_here); |
1fd5e000 CF |
713 | if (n > 0) |
714 | p[n] = ':'; | |
715 | k->remember = p; | |
716 | break; | |
717 | } | |
718 | } | |
719 | debug_printf ("returning"); | |
1fd5e000 CF |
720 | } |
721 | ||
722 | /* Set options from the registry. */ | |
8a2ce995 | 723 | static bool __stdcall |
becf251f | 724 | regopt (const char *name, char *buf) |
1fd5e000 | 725 | { |
8a2ce995 | 726 | bool parsed_something = false; |
f0227ea3 | 727 | char lname[strlen (name) + 1]; |
1fd5e000 | 728 | strlwr (strcpy (lname, name)); |
8a2ce995 | 729 | |
8151e674 | 730 | for (int i = 0; i < 2; i++) |
8a2ce995 | 731 | { |
8151e674 PH |
732 | reg_key r (i, KEY_READ, CYGWIN_INFO_PROGRAM_OPTIONS_NAME, NULL); |
733 | ||
becf251f | 734 | if (r.get_string (lname, buf, NT_MAX_PATH, "") == ERROR_SUCCESS) |
8a2ce995 CF |
735 | { |
736 | parse_options (buf); | |
737 | parsed_something = true; | |
8151e674 | 738 | break; |
8a2ce995 | 739 | } |
9e1ab0ca | 740 | } |
8151e674 | 741 | |
1fd5e000 | 742 | MALLOC_CHECK; |
8a2ce995 | 743 | return parsed_something; |
1fd5e000 CF |
744 | } |
745 | ||
746 | /* Initialize the environ array. Look for the CYGWIN environment | |
ee1d77e4 | 747 | environment variable and set appropriate options from it. */ |
1fd5e000 | 748 | void |
166b2571 | 749 | environ_init (char **envp, int envc) |
1fd5e000 | 750 | { |
5ab0b5cf | 751 | PWCHAR rawenv, w; |
166b2571 | 752 | int i; |
2a1a9785 | 753 | char *p; |
b0e82b74 | 754 | char *newp; |
1fd5e000 | 755 | int sawTERM = 0; |
fb5956da | 756 | bool envp_passed_in; |
8a2ce995 | 757 | bool got_something_from_registry; |
57c89867 | 758 | static char NO_COPY cygterm[] = "TERM=cygwin"; |
541ea313 | 759 | myfault efault; |
752b16ce | 760 | tmp_pathbuf tp; |
541ea313 CF |
761 | |
762 | if (efault.faulted ()) | |
763 | api_fatal ("internal error reading the windows environment - too many environment variables?"); | |
1fd5e000 | 764 | |
e5aa298d CF |
765 | if (!conv_start_chars[0]) |
766 | for (int i = 0; conv_envvars[i].name != NULL; i++) | |
767 | { | |
768 | conv_start_chars[(int) cyg_tolower (conv_envvars[i].name[0])] = 1; | |
769 | conv_start_chars[(int) cyg_toupper (conv_envvars[i].name[0])] = 1; | |
770 | } | |
6e8f36bc | 771 | |
becf251f CV |
772 | char *tmpbuf = tp.t_get (); |
773 | got_something_from_registry = regopt ("default", tmpbuf); | |
1fd5e000 | 774 | if (myself->progname[0]) |
becf251f CV |
775 | got_something_from_registry = regopt (myself->progname, tmpbuf) |
776 | || got_something_from_registry; | |
1fd5e000 | 777 | |
fb5956da CF |
778 | if (!envp) |
779 | envp_passed_in = 0; | |
780 | else | |
b0e82b74 | 781 | { |
da086d02 CF |
782 | envc++; |
783 | envc *= sizeof (char *); | |
166b2571 CF |
784 | char **newenv = (char **) malloc (envc); |
785 | memcpy (newenv, envp, envc); | |
b0e82b74 | 786 | cfree (envp); |
9bc846bd CF |
787 | |
788 | /* Older applications relied on the fact that cygwin malloced elements of the | |
789 | environment list. */ | |
d8242040 | 790 | envp = newenv; |
9bc846bd CF |
791 | if (ENVMALLOC) |
792 | for (char **e = newenv; *e; e++) | |
793 | { | |
794 | char *p = *e; | |
795 | *e = strdup (p); | |
796 | cfree (p); | |
797 | } | |
fb5956da | 798 | envp_passed_in = 1; |
b0e82b74 CF |
799 | goto out; |
800 | } | |
801 | ||
802 | /* Allocate space for environment + trailing NULL + CYGWIN env. */ | |
166b2571 | 803 | lastenviron = envp = (char **) malloc ((4 + (envc = 100)) * sizeof (char *)); |
4dc2cfe5 | 804 | |
5ab0b5cf CV |
805 | /* We need the CYGWIN variable content before we can loop through |
806 | the whole environment, so that the wide-char to multibyte conversion | |
807 | can be done according to the "codepage" setting. */ | |
808 | if ((i = GetEnvironmentVariableA ("CYGWIN", NULL, 0))) | |
809 | { | |
810 | char *buf = (char *) alloca (i); | |
811 | GetEnvironmentVariableA ("CYGWIN", buf, i); | |
812 | parse_options (buf); | |
813 | } | |
814 | ||
815 | rawenv = GetEnvironmentStringsW (); | |
4dc2cfe5 CF |
816 | if (!rawenv) |
817 | { | |
3a83d3a8 CF |
818 | system_printf ("GetEnvironmentStrings returned NULL, %E"); |
819 | return; | |
4dc2cfe5 | 820 | } |
5ab0b5cf | 821 | debug_printf ("GetEnvironmentStrings returned %p", rawenv); |
b0e82b74 | 822 | |
1fd5e000 CF |
823 | /* Current directory information is recorded as variables of the |
824 | form "=X:=X:\foo\bar; these must be changed into something legal | |
825 | (we could just ignore them but maybe an application will | |
826 | eventually want to use them). */ | |
5ab0b5cf | 827 | for (i = 0, w = rawenv; *w != L'\0'; w = wcschr (w, L'\0') + 1, i++) |
1fd5e000 | 828 | { |
5ab0b5cf | 829 | sys_wcstombs_alloc (&newp, HEAP_NOTHEAP, w); |
166b2571 CF |
830 | if (i >= envc) |
831 | envp = (char **) realloc (envp, (4 + (envc += 100)) * sizeof (char *)); | |
0d4c5950 CV |
832 | envp[i] = newp; |
833 | if (*newp == '=') | |
834 | *newp = '!'; | |
2858de3a | 835 | char *eq = strechr (newp, '='); |
7c02f861 | 836 | if (!child_proc_info) |
0d4c5950 | 837 | ucenv (newp, eq); |
6e8f36bc | 838 | if (*newp == 'T' && strncmp (newp, "TERM=", 5) == 0) |
1fd5e000 | 839 | sawTERM = 1; |
f0227ea3 CF |
840 | if (*newp == 'C' && strncmp (newp, "CYGWIN=", sizeof ("CYGWIN=") - 1) == 0) |
841 | parse_options (newp + sizeof ("CYGWIN=") - 1); | |
6e8f36bc | 842 | if (*eq && conv_start_chars[(unsigned char)envp[i][0]]) |
752b16ce | 843 | posify (envp + i, *++eq ? eq : --eq, tmpbuf); |
64ef9db7 | 844 | debug_printf ("%p: %s", envp[i], envp[i]); |
1fd5e000 CF |
845 | } |
846 | ||
847 | if (!sawTERM) | |
e9efc270 | 848 | envp[i++] = strdup (cygterm); |
1fd5e000 | 849 | envp[i] = NULL; |
5ab0b5cf | 850 | FreeEnvironmentStringsW (rawenv); |
b0e82b74 CF |
851 | |
852 | out: | |
33b0abd1 | 853 | findenv_func = (char * (*)(const char*, int*)) my_findenv; |
0763ee9d | 854 | __cygwin_environ = envp; |
81010d21 | 855 | update_envptrs (); |
fb5956da CF |
856 | if (envp_passed_in) |
857 | { | |
858 | p = getenv ("CYGWIN"); | |
859 | if (p) | |
860 | parse_options (p); | |
861 | } | |
8a2ce995 CF |
862 | |
863 | if (got_something_from_registry) | |
864 | parse_options (NULL); /* possibly export registry settings to | |
865 | environment */ | |
1fd5e000 CF |
866 | MALLOC_CHECK; |
867 | } | |
868 | ||
ee1d77e4 | 869 | /* Function called by qsort to sort environment strings. */ |
1fd5e000 CF |
870 | static int |
871 | env_sort (const void *a, const void *b) | |
872 | { | |
873 | const char **p = (const char **) a; | |
874 | const char **q = (const char **) b; | |
875 | ||
876 | return strcmp (*p, *q); | |
877 | } | |
878 | ||
094d5193 CF |
879 | char * __stdcall |
880 | getwinenveq (const char *name, size_t namelen, int x) | |
881 | { | |
5ab0b5cf CV |
882 | WCHAR name0[namelen - 1]; |
883 | WCHAR valbuf[32768]; /* Max size of an env.var including trailing '\0'. */ | |
884 | ||
885 | name0[sys_mbstowcs (name0, sizeof name0, name, namelen - 1)] = L'\0'; | |
886 | int totlen = GetEnvironmentVariableW (name0, valbuf, 32768); | |
094d5193 CF |
887 | if (totlen > 0) |
888 | { | |
5ab0b5cf | 889 | totlen = sys_wcstombs (NULL, 0, valbuf); |
094d5193 CF |
890 | if (x == HEAP_1_STR) |
891 | totlen += namelen; | |
892 | else | |
893 | namelen = 0; | |
ee4388c4 | 894 | char *p = (char *) cmalloc_abort ((cygheap_types) x, totlen); |
094d5193 CF |
895 | if (namelen) |
896 | strcpy (p, name); | |
5ab0b5cf CV |
897 | sys_wcstombs (p + namelen, totlen, valbuf); |
898 | debug_printf ("using value from GetEnvironmentVariable for '%W'", name0); | |
899 | return p; | |
094d5193 CF |
900 | } |
901 | ||
902 | debug_printf ("warning: %s not present in environment", name); | |
903 | return NULL; | |
904 | } | |
905 | ||
da086d02 CF |
906 | struct spenv |
907 | { | |
908 | const char *name; | |
a05a9e01 | 909 | size_t namelen; |
1bbf1ac6 | 910 | bool force_into_environment; /* If true, always add to env if missing */ |
f0b14f14 | 911 | bool add_if_exists; /* if true, retrieve value from cache */ |
094d5193 | 912 | const char * (cygheap_user::*from_cygheap) (const char *, size_t); |
60cb120f | 913 | |
a05a9e01 | 914 | char *retrieve (bool, const char * const = NULL) |
6ea3e429 | 915 | __attribute__ ((regparm (3))); |
da086d02 CF |
916 | }; |
917 | ||
179cae11 | 918 | #define env_dontadd almost_null |
e40670ee | 919 | |
723190cf | 920 | /* Keep this list in upper case and sorted */ |
da086d02 CF |
921 | static NO_COPY spenv spenvs[] = |
922 | { | |
1bbf1ac6 | 923 | #ifdef DEBUGGING |
72733445 | 924 | {NL ("CYGWIN_DEBUG="), false, true, NULL}, |
1bbf1ac6 | 925 | #endif |
47dc3dec CF |
926 | {NL ("HOMEDRIVE="), false, false, &cygheap_user::env_homedrive}, |
927 | {NL ("HOMEPATH="), false, false, &cygheap_user::env_homepath}, | |
928 | {NL ("LOGONSERVER="), false, false, &cygheap_user::env_logsrv}, | |
929 | {NL ("PATH="), false, true, NULL}, | |
1f99dd3e | 930 | {NL ("SYSTEMDRIVE="), false, true, NULL}, |
4e6c0729 | 931 | {NL ("SYSTEMROOT="), true, true, &cygheap_user::env_systemroot}, |
47dc3dec CF |
932 | {NL ("USERDOMAIN="), false, false, &cygheap_user::env_domain}, |
933 | {NL ("USERNAME="), false, false, &cygheap_user::env_name}, | |
9fc0d144 | 934 | {NL ("USERPROFILE="), false, false, &cygheap_user::env_userprofile}, |
3e45d281 | 935 | {NL ("WINDIR="), true, true, &cygheap_user::env_systemroot} |
da086d02 CF |
936 | }; |
937 | ||
938 | char * | |
47dc3dec | 939 | spenv::retrieve (bool no_envblock, const char *const env) |
da086d02 | 940 | { |
c69d873f | 941 | if (env && !ascii_strncasematch (env, name, namelen)) |
da086d02 | 942 | return NULL; |
03a2ce9a CF |
943 | |
944 | debug_printf ("no_envblock %d", no_envblock); | |
945 | ||
da086d02 CF |
946 | if (from_cygheap) |
947 | { | |
948 | const char *p; | |
47dc3dec | 949 | if (env && !cygheap->user.issetuid ()) |
e40670ee | 950 | { |
094d5193 | 951 | debug_printf ("duping existing value for '%s'", name); |
47dc3dec | 952 | /* Don't really care what it's set to if we're calling a cygwin program */ |
6829b6e9 | 953 | return cstrdup1 (env); |
e40670ee | 954 | } |
da086d02 | 955 | |
e40670ee | 956 | /* Calculate (potentially) value for given environment variable. */ |
094d5193 | 957 | p = (cygheap->user.*from_cygheap) (name, namelen); |
6829b6e9 | 958 | if (!p || (no_envblock && !env) || (p == env_dontadd)) |
7c02f861 | 959 | return env_dontadd; |
ee4388c4 | 960 | char *s = (char *) cmalloc_abort (HEAP_1_STR, namelen + strlen (p) + 1); |
da086d02 | 961 | strcpy (s, name); |
0c55f6ed | 962 | strcpy (s + namelen, p); |
03a2ce9a | 963 | debug_printf ("using computed value for '%s'", name); |
da086d02 CF |
964 | return s; |
965 | } | |
966 | ||
47dc3dec CF |
967 | if (env) |
968 | return cstrdup1 (env); | |
da086d02 | 969 | |
094d5193 | 970 | return getwinenveq (name, namelen, HEAP_1_STR); |
da086d02 | 971 | } |
723190cf | 972 | |
da086d02 | 973 | #define SPENVS_SIZE (sizeof (spenvs) / sizeof (spenvs[0])) |
723190cf | 974 | |
1fd5e000 | 975 | /* Create a Windows-style environment block, i.e. a typical character buffer |
ee1d77e4 CF |
976 | filled with null terminated strings, terminated by double null characters. |
977 | Converts environment variables noted in conv_envvars into win32 form | |
978 | prior to placing them in the string. */ | |
da086d02 | 979 | char ** __stdcall |
752b16ce | 980 | build_env (const char * const *envp, PWCHAR &envblock, int &envc, |
da086d02 | 981 | bool no_envblock) |
1fd5e000 | 982 | { |
12a2ef44 | 983 | int len, n; |
1fd5e000 | 984 | const char * const *srcp; |
da086d02 CF |
985 | char **dstp; |
986 | bool saw_spenv[SPENVS_SIZE] = {0}; | |
723190cf | 987 | |
da086d02 | 988 | debug_printf ("envp %p", envp); |
723190cf | 989 | |
12a2ef44 | 990 | /* How many elements? */ |
1fd5e000 CF |
991 | for (n = 0; envp[n]; n++) |
992 | continue; | |
993 | ||
12a2ef44 | 994 | /* Allocate a new "argv-style" environ list with room for extra stuff. */ |
ee4388c4 | 995 | char **newenv = (char **) cmalloc_abort (HEAP_1_ARGV, sizeof (char *) * |
6829b6e9 | 996 | (n + SPENVS_SIZE + 1)); |
1fd5e000 | 997 | |
12a2ef44 | 998 | int tl = 0; |
6829b6e9 CF |
999 | char **pass_dstp; |
1000 | char **pass_env = (char **) alloca (sizeof (char *) * (n + SPENVS_SIZE + 1)); | |
12a2ef44 CF |
1001 | /* Iterate over input list, generating a new environment list and refreshing |
1002 | "special" entries, if necessary. */ | |
6829b6e9 | 1003 | for (srcp = envp, dstp = newenv, pass_dstp = pass_env; *srcp; srcp++) |
1fd5e000 | 1004 | { |
6829b6e9 | 1005 | bool calc_tl = !no_envblock; |
12a2ef44 | 1006 | /* Look for entries that require special attention */ |
da086d02 | 1007 | for (unsigned i = 0; i < SPENVS_SIZE; i++) |
a05a9e01 | 1008 | if (!saw_spenv[i] && (*dstp = spenvs[i].retrieve (no_envblock, *srcp))) |
da086d02 CF |
1009 | { |
1010 | saw_spenv[i] = 1; | |
6829b6e9 CF |
1011 | if (*dstp == env_dontadd) |
1012 | goto next1; | |
f0b14f14 | 1013 | if (spenvs[i].add_if_exists) |
6829b6e9 CF |
1014 | calc_tl = true; |
1015 | goto next0; | |
da086d02 | 1016 | } |
1fd5e000 | 1017 | |
a05a9e01 | 1018 | /* Add entry to new environment */ |
12a2ef44 | 1019 | *dstp = cstrdup1 (*srcp); |
723190cf | 1020 | |
e40670ee | 1021 | next0: |
6829b6e9 CF |
1022 | if (calc_tl) |
1023 | { | |
1024 | *pass_dstp++ = *dstp; | |
1025 | tl += strlen (*dstp) + 1; | |
1026 | } | |
e40670ee CF |
1027 | dstp++; |
1028 | next1: | |
1029 | continue; | |
1fd5e000 CF |
1030 | } |
1031 | ||
8a2ce995 | 1032 | assert ((srcp - envp) == n); |
12a2ef44 | 1033 | /* Fill in any required-but-missing environment variables. */ |
60cb120f | 1034 | for (unsigned i = 0; i < SPENVS_SIZE; i++) |
1bbf1ac6 | 1035 | if (!saw_spenv[i] && (spenvs[i].force_into_environment || cygheap->user.issetuid ())) |
e3778517 | 1036 | { |
f0b14f14 CF |
1037 | *dstp = spenvs[i].retrieve (false); |
1038 | if (*dstp && *dstp != env_dontadd) | |
94f29ccd | 1039 | { |
dd991a75 | 1040 | *pass_dstp++ = *dstp; |
94f29ccd PH |
1041 | tl += strlen (*dstp) + 1; |
1042 | dstp++; | |
1043 | } | |
1044 | } | |
e3778517 | 1045 | |
a05a9e01 | 1046 | envc = dstp - newenv; /* Number of entries in newenv */ |
8a2ce995 | 1047 | assert ((size_t) envc <= (n + SPENVS_SIZE)); |
da086d02 | 1048 | *dstp = NULL; /* Terminate */ |
1fd5e000 | 1049 | |
6829b6e9 CF |
1050 | size_t pass_envc = pass_dstp - pass_env; |
1051 | if (!pass_envc) | |
da086d02 CF |
1052 | envblock = NULL; |
1053 | else | |
1054 | { | |
6829b6e9 CF |
1055 | *pass_dstp = NULL; |
1056 | debug_printf ("env count %d, bytes %d", pass_envc, tl); | |
47dc3dec CF |
1057 | win_env temp; |
1058 | temp.reset (); | |
1fd5e000 | 1059 | |
da086d02 | 1060 | /* Windows programs expect the environment block to be sorted. */ |
6829b6e9 | 1061 | qsort (pass_env, pass_envc, sizeof (char *), env_sort); |
1fd5e000 | 1062 | |
da086d02 | 1063 | /* Create an environment block suitable for passing to CreateProcess. */ |
752b16ce CV |
1064 | PWCHAR s; |
1065 | envblock = (PWCHAR) malloc ((2 + tl) * sizeof (WCHAR)); | |
12a2ef44 | 1066 | int new_tl = 0; |
6829b6e9 | 1067 | for (srcp = pass_env, s = envblock; *srcp; srcp++) |
da086d02 | 1068 | { |
12a2ef44 CF |
1069 | const char *p; |
1070 | win_env *conv; | |
1071 | len = strcspn (*srcp, "=") + 1; | |
d6b1ac7f | 1072 | const char *rest = *srcp + len; |
12a2ef44 | 1073 | |
d1ce9364 CV |
1074 | /* Check for a bad entry. This is necessary to get rid of empty |
1075 | strings, induced by putenv and changing the string afterwards. | |
1076 | Note that this doesn't stop invalid strings without '=' in it | |
1077 | etc., but we're opting for speed here for now. Adding complete | |
1078 | checking would be pretty expensive. */ | |
d6b1ac7f | 1079 | if (len == 1 || !*rest) |
d1ce9364 CV |
1080 | continue; |
1081 | ||
12a2ef44 | 1082 | /* See if this entry requires posix->win32 conversion. */ |
d6b1ac7f | 1083 | conv = getwinenv (*srcp, rest, &temp); |
12a2ef44 CF |
1084 | if (conv) |
1085 | p = conv->native; /* Use win32 path */ | |
1086 | else | |
1087 | p = *srcp; /* Don't worry about it */ | |
1088 | ||
d6b1ac7f | 1089 | len = strlen (p) + 1; |
d6b1ac7f | 1090 | new_tl += len; /* Keep running total of block length so far */ |
12a2ef44 CF |
1091 | |
1092 | /* See if we need to increase the size of the block. */ | |
1093 | if (new_tl > tl) | |
470e8c46 | 1094 | { |
638180f5 | 1095 | tl = new_tl + 100; |
752b16ce CV |
1096 | PWCHAR new_envblock = |
1097 | (PWCHAR) realloc (envblock, (2 + tl) * sizeof (WCHAR)); | |
470e8c46 CV |
1098 | /* If realloc moves the block, move `s' with it. */ |
1099 | if (new_envblock != envblock) | |
5bf785a0 | 1100 | { |
470e8c46 CV |
1101 | s += new_envblock - envblock; |
1102 | envblock = new_envblock; | |
1103 | } | |
1104 | } | |
12a2ef44 | 1105 | |
752b16ce | 1106 | int slen = sys_mbstowcs (s, len, p, len); |
12a2ef44 CF |
1107 | |
1108 | /* See if environment variable is "special" in a Windows sense. | |
1109 | Under NT, the current directories for visited drives are stored | |
1110 | as =C:=\bar. Cygwin converts the '=' to '!' for hopefully obvious | |
1111 | reasons. We need to convert it back when building the envblock */ | |
752b16ce CV |
1112 | if (s[0] == L'!' && (iswdrive (s + 1) || (s[1] == L':' && s[2] == L':')) |
1113 | && s[3] == L'=') | |
1114 | *s = L'='; | |
1115 | s += slen + 1; | |
da086d02 | 1116 | } |
752b16ce | 1117 | *s = L'\0'; /* Two null bytes at the end */ |
12a2ef44 CF |
1118 | assert ((s - envblock) <= tl); /* Detect if we somehow ran over end |
1119 | of buffer */ | |
1fd5e000 | 1120 | } |
1fd5e000 | 1121 | |
6d171b44 | 1122 | debug_printf ("envp %p, envc %d", newenv, envc); |
da086d02 | 1123 | return newenv; |
1fd5e000 | 1124 | } |
0763ee9d CF |
1125 | |
1126 | /* This idiocy is necessary because the early implementers of cygwin | |
1127 | did not seem to know about importing data variables from the DLL. | |
1128 | So, we have to synchronize cygwin's idea of the environment with the | |
1129 | main program's with each reference to the environment. */ | |
84c7d409 | 1130 | extern "C" char ** __stdcall |
0763ee9d CF |
1131 | cur_environ () |
1132 | { | |
1133 | if (*main_environ != __cygwin_environ) | |
1134 | { | |
1135 | __cygwin_environ = *main_environ; | |
1136 | update_envptrs (); | |
1137 | } | |
1138 | ||
1139 | return __cygwin_environ; | |
1140 | } |