1 /* environ.cc: Cygwin-adopted functions from newlib to manipulate
4 Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
5 2006, 2007, 2008, 2009, 2010, 2011 Red Hat, Inc.
7 This software is a copyrighted work licensed under the terms of the
8 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
18 #include <cygwin/version.h>
21 #include "perprocess.h"
31 #include "child_info.h"
32 #include "shared_info.h"
35 extern bool dos_file_warning;
36 extern bool ignore_case_with_glob;
37 extern bool allow_winsymlinks;
38 bool reset_com = false;
39 static bool create_upcaseenv = false;
41 static char **lastenviron;
43 /* Parse CYGWIN options */
45 static NO_COPY bool export_settings = false;
55 null or empty: disables globbing
56 "ignorecase": enables case-insensitive globbing
57 anything else: enables case-sensitive globbing */
59 glob_init (const char *buf)
64 ignore_case_with_glob = false;
66 else if (ascii_strncasematch (buf, "ignorecase", 10))
69 ignore_case_with_glob = true;
74 ignore_case_with_glob = false;
79 set_proc_retry (const char *buf)
81 child_info::retry_count = strtoul (buf, NULL, 0);
85 tty_is_gone (const char *buf)
87 if (!user_shared->warned_notty)
89 small_printf ("\"tty\" option detected in CYGWIN environment variable.\n"
90 "CYGWIN=tty is no longer supported. Please remove it from your\n"
91 "CYGWIN environment variable and use a terminal emulator like mintty, "
93 user_shared->warned_notty = 1;
97 /* The structure below is used to set up an array which is used to
98 parse the CYGWIN environment variable or, if enabled, options from
100 static struct parse_thing
108 void (*func)(const char *);
111 enum settings disposition;
120 {"dosfilewarning", {&dos_file_warning}, justset, NULL, {{false}, {true}}},
121 {"error_start", {func: error_start_init}, isfunc, NULL, {{0}, {0}}},
122 {"export", {&export_settings}, justset, NULL, {{false}, {true}}},
123 {"glob", {func: glob_init}, isfunc, NULL, {{0}, {s: "normal"}}},
124 {"proc_retry", {func: set_proc_retry}, isfunc, NULL, {{0}, {5}}},
125 {"reset_com", {&reset_com}, justset, NULL, {{false}, {true}}},
126 {"strip_title", {&strip_title_path}, justset, NULL, {{false}, {true}}},
127 {"title", {&display_title}, justset, NULL, {{false}, {true}}},
128 {"tty", {func: tty_is_gone}, isfunc, NULL, {{0}, {0}}},
129 {"upcaseenv", {&create_upcaseenv}, justset, NULL, {{false}, {true}}},
130 {"winsymlinks", {&allow_winsymlinks}, justset, NULL, {{false}, {true}}},
131 {NULL, {0}, justset, 0, {{0}, {0}}}
134 /* Parse a string of the form "something=stuff somethingelse=more-stuff",
135 silently ignoring unknown "somethings". */
136 static void __stdcall
137 parse_options (const char *inbuf)
146 char *newbuf = tp.c_get ();
148 for (k = known; k->name != NULL; k++)
151 strcat (strcat (newbuf, " "), k->remember);
158 debug_printf ("%s", newbuf + 1);
159 setenv ("CYGWIN", newbuf + 1, 1);
164 char *buf = strcpy ((char *) alloca (strlen (inbuf) + 1), inbuf);
165 for (p = strtok_r (buf, " \t", &lasts);
167 p = strtok_r (NULL, " \t", &lasts))
169 char *keyword_here = p;
170 if (!(istrue = !ascii_strncasematch (p, "no", 2)))
172 else if (!(istrue = *p != '-'))
176 if ((eq = strchr (p, '=')) != NULL || (eq = strchr (p, ':')) != NULL)
177 ch = *eq, *eq++ = '\0';
181 for (parse_thing *k = known; k->name != NULL; k++)
182 if (ascii_strcasematch (p, k->name))
184 switch (k->disposition)
187 k->setting.func ((!eq || !istrue) ?
188 k->values[istrue].s : eq);
189 debug_printf ("%s (called func)", k->name);
193 *k->setting.x = k->values[istrue].i;
195 *k->setting.x = strtol (eq, NULL, 0);
196 debug_printf ("%s %d", k->name, *k->setting.x);
199 *k->setting.x &= ~k->values[istrue].i;
200 if (istrue || (eq && strtol (eq, NULL, 0)))
201 *k->setting.x |= k->values[istrue].i;
202 debug_printf ("%s %x", k->name, *k->setting.x);
210 p = strdup (keyword_here);
217 debug_printf ("returning");
220 /* Helper functions for the below environment variables which have to
221 be converted Win32<->POSIX. */
222 extern "C" ssize_t env_PATH_to_posix (const void *, void *, size_t);
225 env_plist_to_posix (const void *win32, void *posix, size_t size)
227 return cygwin_conv_path_list (CCP_WIN_A_TO_POSIX | CCP_RELATIVE, win32,
232 env_plist_to_win32 (const void *posix, void *win32, size_t size)
234 return cygwin_conv_path_list (CCP_POSIX_TO_WIN_A | CCP_RELATIVE, posix,
239 env_path_to_posix (const void *win32, void *posix, size_t size)
241 return cygwin_conv_path (CCP_WIN_A_TO_POSIX | CCP_ABSOLUTE, win32,
246 env_path_to_win32 (const void *posix, void *win32, size_t size)
248 return cygwin_conv_path (CCP_POSIX_TO_WIN_A | CCP_ABSOLUTE, posix,
253 (CYGWIN_VERSION_DLL_MAKE_COMBINED (user_data->api_major, user_data->api_minor) \
254 <= CYGWIN_VERSION_DLL_MALLOC_ENV)
256 #define NL(x) x, (sizeof (x) - 1)
257 /* List of names which are converted from dos to unix
258 on the way in and back again on the way out.
260 PATH needs to be here because CreateProcess uses it and gdb uses
261 CreateProcess. HOME is here because most shells use it and would be
262 confused by Windows style path names. */
263 static win_env conv_envvars[] =
265 {NL ("PATH="), NULL, NULL, env_PATH_to_posix, env_plist_to_win32, true},
266 {NL ("HOME="), NULL, NULL, env_path_to_posix, env_path_to_win32, false},
267 {NL ("LD_LIBRARY_PATH="), NULL, NULL,
268 env_plist_to_posix, env_plist_to_win32, true},
269 {NL ("TMPDIR="), NULL, NULL, env_path_to_posix, env_path_to_win32, false},
270 {NL ("TMP="), NULL, NULL, env_path_to_posix, env_path_to_win32, false},
271 {NL ("TEMP="), NULL, NULL, env_path_to_posix, env_path_to_win32, false},
272 {NULL, 0, NULL, NULL, 0, 0}
275 static unsigned char conv_start_chars[256] = {0};
278 win_env::operator = (struct win_env& x)
297 win_env::add_cache (const char *in_posix, const char *in_native)
300 posix = (char *) realloc (posix, strlen (in_posix) + 1);
301 strcpy (posix, in_posix);
304 native = (char *) realloc (native, namelen + 1 + strlen (in_native));
305 strcpy (native, name);
306 strcpy (native + namelen, in_native);
311 char *buf = tp.c_get ();
312 strcpy (buf, name + namelen);
313 towin32 (in_posix, buf, NT_MAX_PATH);
314 native = (char *) realloc (native, namelen + 1 + strlen (buf));
315 strcpy (native, name);
316 strcpy (native + namelen, buf);
319 if (immediate && cygwin_finished_initializing)
322 size_t n = namelen - 1;
325 SetEnvironmentVariable (s, native + namelen);
327 debug_printf ("posix %s", posix);
328 debug_printf ("native %s", native);
332 /* Check for a "special" environment variable name. *env is the pointer
333 to the beginning of the environment variable name. *in_posix is any
334 known posix value for the environment variable. Returns a pointer to
335 the appropriate conversion structure. */
337 getwinenv (const char *env, const char *in_posix, win_env *temp)
339 if (!conv_start_chars[(unsigned char)*env])
342 for (int i = 0; conv_envvars[i].name != NULL; i++)
343 if (strncmp (env, conv_envvars[i].name, conv_envvars[i].namelen) == 0)
345 win_env *we = conv_envvars + i;
347 if (!cur_environ () || !(val = in_posix ?: getenv (we->name)))
348 debug_printf ("can't set native for %s since no environ yet",
350 else if (!we->posix || strcmp (val, we->posix) != 0)
364 /* Convert windows path specs to POSIX, if appropriate.
366 static void __stdcall
367 posify (char **here, const char *value, char *outenv)
372 if (!(conv = getwinenv (src)))
375 int len = strcspn (src, "=") + 1;
377 /* Turn all the items from c:<foo>;<bar> into their
378 mounted equivalents - if there is one. */
380 memcpy (outenv, src, len);
381 char *newvalue = outenv + len;
382 if (!conv->toposix (value, newvalue, NT_MAX_PATH - len)
383 || _impure_ptr->_errno != EIDRM)
384 conv->add_cache (newvalue, *value != '/' ? value : NULL);
387 /* The conversion routine removed elements from a path list so we have
388 to recalculate the windows path to remove elements there, too. */
389 char cleanvalue[strlen (value) + 1];
390 conv->towin32 (newvalue, cleanvalue, sizeof cleanvalue);
391 conv->add_cache (newvalue, cleanvalue);
394 debug_printf ("env var converted to %s", outenv);
395 *here = strdup (outenv);
400 /* Returns pointer to value associated with name, if any, else NULL.
401 Sets offset to be the offset of the name/value combination in the
402 environment array, for use by setenv(3) and unsetenv(3).
403 Explicitly removes '=' in argument name. */
405 static char * __stdcall
406 my_findenv (const char *name, int *offset)
414 while (*c && *c != '=')
420 for (p = cur_environ (); *p; ++p)
421 if (!strncmp (*p, name, len))
422 if (*(c = *p + len) == '=')
424 *offset = p - cur_environ ();
425 return (char *) (++c);
431 /* Primitive getenv before the environment is built. */
433 static char __stdcall *
434 getearly (const char * name, int *)
440 if (spawn_info && (ptr = spawn_info->moreinfo->envp))
444 if (strncasematch (name, *ptr, len) && (*ptr)[len] == '=')
445 return *ptr + len + 1;
447 else if ((len = GetEnvironmentVariableA (name, NULL, 0))
448 && (ret = (char *) cmalloc_abort (HEAP_2_STR, len))
449 && GetEnvironmentVariableA (name, ret, len))
455 static char * (*findenv_func)(const char *, int *) = (char * (*)(const char *, int *)) getearly;
457 /* Returns ptr to value associated with name, if any, else NULL. */
460 getenv (const char *name)
463 return findenv_func (name, &offset);
466 /* This function is required so that newlib uses the same environment
469 _getenv_r (struct _reent *, const char *name)
472 return findenv_func (name, &offset);
476 envsize (const char * const *in_envp)
478 const char * const *envp;
479 for (envp = in_envp; *envp; envp++)
481 return (1 + envp - in_envp) * sizeof (const char *);
484 /* Takes similar arguments to setenv except that overwrite is
485 either -1, 0, or 1. 0 or 1 signify that the function should
486 perform similarly to setenv. Otherwise putenv is assumed. */
488 _addenv (const char *name, const char *value, int overwrite)
490 int issetenv = overwrite >= 0;
494 unsigned int valuelen = strlen (value);
495 if ((p = my_findenv (name, &offset)))
496 { /* Already exists. */
497 if (!overwrite) /* Ok to overwrite? */
498 return 0; /* No. Wanted to add new value. FIXME: Right return value? */
500 /* We've found the offset into environ. If this is a setenv call and
501 there is room in the current environment entry then just overwrite it.
502 Otherwise handle this case below. */
503 if (issetenv && strlen (p) >= valuelen)
510 { /* Create new slot. */
511 int sz = envsize (cur_environ ());
512 int allocsz = sz + (2 * sizeof (char *));
514 offset = (sz - 1) / sizeof (char *);
516 /* Allocate space for additional element plus terminating NULL. */
517 if (cur_environ () == lastenviron)
518 lastenviron = __cygwin_environ = (char **) realloc (cur_environ (),
520 else if ((lastenviron = (char **) malloc (allocsz)) != NULL)
521 __cygwin_environ = (char **) memcpy ((char **) lastenviron,
522 __cygwin_environ, sz);
524 if (!__cygwin_environ)
529 return -1; /* Oops. No more memory. */
532 __cygwin_environ[offset + 1] = NULL; /* NULL terminate. */
533 update_envptrs (); /* Update any local copies of 'environ'. */
538 /* Not setenv. Just overwrite existing. */
539 envhere = cur_environ ()[offset] = (char *) (ENVMALLOC ? strdup (name) : name);
542 /* Look for an '=' in the name and ignore anything after that if found. */
543 for (p = (char *) name; *p && *p != '='; p++)
546 int namelen = p - name; /* Length of name. */
547 /* Allocate enough space for name + '=' + value + '\0' */
548 envhere = cur_environ ()[offset] = (char *) malloc (namelen + valuelen + 2);
550 return -1; /* Oops. No more memory. */
552 /* Put name '=' value into current slot. */
553 strncpy (envhere, name, namelen);
554 envhere[namelen] = '=';
555 strcpy (envhere + namelen + 1, value);
558 /* Update cygwin's cache, if appropriate */
560 if ((spenv = getwinenv (envhere)))
561 spenv->add_cache (value);
562 if (strcmp (name, "CYGWIN") == 0)
563 parse_options (value);
569 /* Set an environment variable */
574 if (efault.faulted (EFAULT))
578 char *eq = strchr (str, '=');
580 return _addenv (str, eq + 1, -1);
582 /* Remove str from the environment. */
588 /* Set the value of the environment variable "name" to be
589 "value". If overwrite is set, replace any current value. */
591 setenv (const char *name, const char *value, int overwrite)
594 if (efault.faulted (EFAULT))
596 if (!name || !*name || strchr (name, '='))
601 return _addenv (name, value, !!overwrite);
604 /* Delete environment variable "name". */
606 unsetenv (const char *name)
611 if (efault.faulted (EFAULT))
613 if (!name || *name == '\0' || strchr (name, '='))
619 while (my_findenv (name, &offset)) /* if set multiple times */
620 /* Move up the rest of the array */
621 for (e = cur_environ () + offset; ; e++)
622 if (!(*e = *(e + 1)))
628 /* Minimal list of Windows vars which must be converted to uppercase.
629 Either for POSIX compatibility of for backward compatibility with
630 existing applications. */
633 const size_t namelen;
635 { NL("ALLUSERSPROFILE=") }, // 0
636 { NL("COMMONPROGRAMFILES=") }, // 1
637 { NL("COMPUTERNAME=") },
639 { NL("HOME=") }, // 4
640 { NL("HOMEDRIVE=") },
642 { NL("NUMBER_OF_PROCESSORS=") }, // 7
644 { NL("PATH=") }, // 9
646 { NL("PROCESSOR_ARCHITECTURE=") },
647 { NL("PROCESSOR_IDENTIFIER=") },
648 { NL("PROCESSOR_LEVEL=") },
649 { NL("PROCESSOR_REVISION=") },
650 { NL("PROGRAMFILES=") },
651 { NL("SYSTEMDRIVE=") }, // 16
652 { NL("SYSTEMROOT=") },
653 { NL("TEMP=") }, // 18
657 { NL("WINDIR=") } // 22
659 #define RENV_SIZE (sizeof (renv_arr) / sizeof (renv_arr[0]))
660 /* Set of first characters of the above list of variables. */
661 static const char idx_arr[] = "ACHNOPSTW";
662 /* Index into renv_arr at which the variables with this specific character
664 static const int start_at[] = { 0, 1, 4, 7, 8, 9, 16, 18, 22 };
666 /* Turn environment variable part of a=b string into uppercase.
667 Conditionally controlled by upcaseenv CYGWIN setting. */
668 static __inline__ void
669 ucenv (char *p, const char *eq)
671 if (create_upcaseenv)
673 /* Amazingly, NT has a case sensitive environment name list,
675 It's normal to have NT set your "Path" to something.
676 Later, you set "PATH" to something else. This alters "Path".
677 But if you try and do a naive getenv on "PATH" you'll get nothing.
679 So we upper case the labels here to prevent confusion later but
680 we only do it for processes that are started by non-Cygwin programs. */
683 *p = cyg_toupper (*p);
687 /* Hopefully as quickly as possible - only upcase specific set of important
688 Windows variables. */
689 char first = cyg_toupper (*p);
690 const char *idx = strchr (idx_arr, first);
692 for (size_t i = start_at[idx - idx_arr];
693 i < RENV_SIZE && renv_arr[i].name[0] == first;
695 if (strncasematch (p, renv_arr[i].name, renv_arr[i].namelen))
697 strncpy (p, renv_arr[i].name, renv_arr[i].namelen);
703 /* Set options from the registry. */
704 static bool __stdcall
705 regopt (const WCHAR *name, char *buf)
707 bool parsed_something = false;
708 UNICODE_STRING lname;
709 size_t len = (wcslen(name) + 1) * sizeof (WCHAR);
710 RtlInitEmptyUnicodeString(&lname, (PWCHAR) alloca (len), len);
711 wcscpy(lname.Buffer, name);
712 RtlDowncaseUnicodeString(&lname, &lname, FALSE);
714 for (int i = 0; i < 2; i++)
716 reg_key r (i, KEY_READ, _WIDE (CYGWIN_INFO_PROGRAM_OPTIONS_NAME), NULL);
718 if (NT_SUCCESS (r.get_string (lname.Buffer, (PWCHAR) buf,
722 sys_wcstombs_alloc(&newp, HEAP_NOTHEAP, (PWCHAR) buf);
725 parsed_something = true;
731 return parsed_something;
734 /* Initialize the environ array. Look for the CYGWIN environment
735 environment variable and set appropriate options from it. */
737 environ_init (char **envp, int envc)
745 bool got_something_from_registry;
746 static char NO_COPY cygterm[] = "TERM=cygwin";
750 if (efault.faulted ())
751 api_fatal ("internal error reading the windows environment - too many environment variables?");
753 if (!conv_start_chars[0])
754 for (int i = 0; conv_envvars[i].name != NULL; i++)
756 conv_start_chars[(int) cyg_tolower (conv_envvars[i].name[0])] = 1;
757 conv_start_chars[(int) cyg_toupper (conv_envvars[i].name[0])] = 1;
760 char *tmpbuf = tp.t_get ();
761 got_something_from_registry = regopt (L"default", tmpbuf);
762 if (myself->progname[0])
763 got_something_from_registry = regopt (myself->progname, tmpbuf)
764 || got_something_from_registry;
771 envc *= sizeof (char *);
772 char **newenv = (char **) malloc (envc);
773 memcpy (newenv, envp, envc);
776 /* Older applications relied on the fact that cygwin malloced elements of the
780 for (char **e = newenv; *e; e++)
790 /* Allocate space for environment + trailing NULL + CYGWIN env. */
791 lastenviron = envp = (char **) malloc ((4 + (envc = 100)) * sizeof (char *));
793 /* We also need the CYGWIN variable early to know the value of the
794 CYGWIN=upcaseenv setting for the below loop. */
795 if ((i = GetEnvironmentVariableA ("CYGWIN", NULL, 0)))
797 char *buf = (char *) alloca (i);
798 GetEnvironmentVariableA ("CYGWIN", buf, i);
802 rawenv = GetEnvironmentStringsW ();
805 system_printf ("GetEnvironmentStrings returned NULL, %E");
808 debug_printf ("GetEnvironmentStrings returned %p", rawenv);
810 /* Current directory information is recorded as variables of the
811 form "=X:=X:\foo\bar; these must be changed into something legal
812 (we could just ignore them but maybe an application will
813 eventually want to use them). */
814 for (i = 0, w = rawenv; *w != L'\0'; w = wcschr (w, L'\0') + 1, i++)
816 sys_wcstombs_alloc (&newp, HEAP_NOTHEAP, w);
818 envp = (char **) realloc (envp, (4 + (envc += 100)) * sizeof (char *));
822 char *eq = strechr (newp, '=');
823 ucenv (newp, eq); /* (possibly conditionally) uppercase env vars. */
824 if (*newp == 'T' && strncmp (newp, "TERM=", 5) == 0)
826 if (*eq && conv_start_chars[(unsigned char) envp[i][0]])
827 posify (envp + i, *++eq ? eq : --eq, tmpbuf);
828 debug_printf ("%p: %s", envp[i], envp[i]);
832 envp[i++] = strdup (cygterm);
834 FreeEnvironmentStringsW (rawenv);
837 findenv_func = (char * (*)(const char*, int*)) my_findenv;
838 __cygwin_environ = envp;
842 p = getenv ("CYGWIN");
847 if (got_something_from_registry)
848 parse_options (NULL); /* possibly export registry settings to
853 /* Function called by qsort to sort environment strings. */
855 env_sort (const void *a, const void *b)
857 const char **p = (const char **) a;
858 const char **q = (const char **) b;
860 return strcmp (*p, *q);
864 getwinenveq (const char *name, size_t namelen, int x)
866 WCHAR name0[namelen - 1];
867 WCHAR valbuf[32768]; /* Max size of an env.var including trailing '\0'. */
869 name0[sys_mbstowcs (name0, sizeof name0, name, namelen - 1)] = L'\0';
870 int totlen = GetEnvironmentVariableW (name0, valbuf, 32768);
873 totlen = sys_wcstombs (NULL, 0, valbuf);
878 char *p = (char *) cmalloc_abort ((cygheap_types) x, totlen);
881 sys_wcstombs (p + namelen, totlen, valbuf);
882 debug_printf ("using value from GetEnvironmentVariable for '%W'", name0);
886 debug_printf ("warning: %s not present in environment", name);
894 bool force_into_environment; /* If true, always add to env if missing */
895 bool add_if_exists; /* if true, retrieve value from cache */
896 const char * (cygheap_user::*from_cygheap) (const char *, size_t);
898 char *retrieve (bool, const char * const = NULL)
899 __attribute__ ((regparm (3)));
902 #define env_dontadd almost_null
904 /* Keep this list in upper case and sorted */
905 static NO_COPY spenv spenvs[] =
908 {NL ("CYGWIN_DEBUG="), false, true, NULL},
910 {NL ("HOMEDRIVE="), false, false, &cygheap_user::env_homedrive},
911 {NL ("HOMEPATH="), false, false, &cygheap_user::env_homepath},
912 {NL ("LOGONSERVER="), false, false, &cygheap_user::env_logsrv},
913 {NL ("PATH="), false, true, NULL},
914 {NL ("SYSTEMDRIVE="), false, true, NULL},
915 {NL ("SYSTEMROOT="), true, true, &cygheap_user::env_systemroot},
916 {NL ("USERDOMAIN="), false, false, &cygheap_user::env_domain},
917 {NL ("USERNAME="), false, false, &cygheap_user::env_name},
918 {NL ("USERPROFILE="), false, false, &cygheap_user::env_userprofile},
919 {NL ("WINDIR="), true, true, &cygheap_user::env_systemroot}
923 spenv::retrieve (bool no_envblock, const char *const env)
925 if (env && !ascii_strncasematch (env, name, namelen))
928 debug_printf ("no_envblock %d", no_envblock);
933 if (env && !cygheap->user.issetuid ())
935 debug_printf ("duping existing value for '%s'", name);
936 /* Don't really care what it's set to if we're calling a cygwin program */
937 return cstrdup1 (env);
940 /* Calculate (potentially) value for given environment variable. */
941 p = (cygheap->user.*from_cygheap) (name, namelen);
942 if (!p || (no_envblock && !env) || (p == env_dontadd))
944 char *s = (char *) cmalloc_abort (HEAP_1_STR, namelen + strlen (p) + 1);
946 strcpy (s + namelen, p);
947 debug_printf ("using computed value for '%s'", name);
952 return cstrdup1 (env);
954 return getwinenveq (name, namelen, HEAP_1_STR);
957 #define SPENVS_SIZE (sizeof (spenvs) / sizeof (spenvs[0]))
959 /* Create a Windows-style environment block, i.e. a typical character buffer
960 filled with null terminated strings, terminated by double null characters.
961 Converts environment variables noted in conv_envvars into win32 form
962 prior to placing them in the string. */
964 build_env (const char * const *envp, PWCHAR &envblock, int &envc,
968 const char * const *srcp;
970 bool saw_spenv[SPENVS_SIZE] = {0};
972 debug_printf ("envp %p", envp);
974 /* How many elements? */
975 for (n = 0; envp[n]; n++)
978 /* Allocate a new "argv-style" environ list with room for extra stuff. */
979 char **newenv = (char **) cmalloc_abort (HEAP_1_ARGV, sizeof (char *) *
980 (n + SPENVS_SIZE + 1));
984 char **pass_env = (char **) alloca (sizeof (char *) * (n + SPENVS_SIZE + 1));
985 /* Iterate over input list, generating a new environment list and refreshing
986 "special" entries, if necessary. */
987 for (srcp = envp, dstp = newenv, pass_dstp = pass_env; *srcp; srcp++)
989 bool calc_tl = !no_envblock;
990 /* Look for entries that require special attention */
991 for (unsigned i = 0; i < SPENVS_SIZE; i++)
992 if (!saw_spenv[i] && (*dstp = spenvs[i].retrieve (no_envblock, *srcp)))
995 if (*dstp == env_dontadd)
997 if (spenvs[i].add_if_exists)
1002 /* Add entry to new environment */
1003 *dstp = cstrdup1 (*srcp);
1008 *pass_dstp++ = *dstp;
1009 tl += strlen (*dstp) + 1;
1016 assert ((srcp - envp) == n);
1017 /* Fill in any required-but-missing environment variables. */
1018 for (unsigned i = 0; i < SPENVS_SIZE; i++)
1019 if (!saw_spenv[i] && (spenvs[i].force_into_environment || cygheap->user.issetuid ()))
1021 *dstp = spenvs[i].retrieve (false);
1022 if (*dstp && *dstp != env_dontadd)
1024 *pass_dstp++ = *dstp;
1025 tl += strlen (*dstp) + 1;
1030 envc = dstp - newenv; /* Number of entries in newenv */
1031 assert ((size_t) envc <= (n + SPENVS_SIZE));
1032 *dstp = NULL; /* Terminate */
1034 size_t pass_envc = pass_dstp - pass_env;
1040 debug_printf ("env count %d, bytes %d", pass_envc, tl);
1044 /* Windows programs expect the environment block to be sorted. */
1045 qsort (pass_env, pass_envc, sizeof (char *), env_sort);
1047 /* Create an environment block suitable for passing to CreateProcess. */
1049 envblock = (PWCHAR) malloc ((2 + tl) * sizeof (WCHAR));
1051 for (srcp = pass_env, s = envblock; *srcp; srcp++)
1055 len = strcspn (*srcp, "=") + 1;
1056 const char *rest = *srcp + len;
1058 /* Check for a bad entry. This is necessary to get rid of empty
1059 strings, induced by putenv and changing the string afterwards.
1060 Note that this doesn't stop invalid strings without '=' in it
1061 etc., but we're opting for speed here for now. Adding complete
1062 checking would be pretty expensive. */
1063 if (len == 1 || !*rest)
1066 /* See if this entry requires posix->win32 conversion. */
1067 conv = getwinenv (*srcp, rest, &temp);
1069 p = conv->native; /* Use win32 path */
1071 p = *srcp; /* Don't worry about it */
1073 len = sys_mbstowcs (NULL, 0, p);
1074 new_tl += len; /* Keep running total of block length so far */
1076 /* See if we need to increase the size of the block. */
1080 PWCHAR new_envblock =
1081 (PWCHAR) realloc (envblock, (2 + tl) * sizeof (WCHAR));
1082 /* If realloc moves the block, move `s' with it. */
1083 if (new_envblock != envblock)
1085 s += new_envblock - envblock;
1086 envblock = new_envblock;
1090 int slen = sys_mbstowcs (s, len, p);
1092 /* See if environment variable is "special" in a Windows sense.
1093 Under NT, the current directories for visited drives are stored
1094 as =C:=\bar. Cygwin converts the '=' to '!' for hopefully obvious
1095 reasons. We need to convert it back when building the envblock */
1096 if (s[0] == L'!' && (iswdrive (s + 1) || (s[1] == L':' && s[2] == L':'))
1101 *s = L'\0'; /* Two null bytes at the end */
1102 assert ((s - envblock) <= tl); /* Detect if we somehow ran over end
1106 debug_printf ("envp %p, envc %d", newenv, envc);
1110 /* This idiocy is necessary because the early implementers of cygwin
1111 did not seem to know about importing data variables from the DLL.
1112 So, we have to synchronize cygwin's idea of the environment with the
1113 main program's with each reference to the environment. */
1114 extern "C" char ** __stdcall
1117 if (*main_environ != __cygwin_environ)
1119 __cygwin_environ = *main_environ;
1123 return __cygwin_environ;