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 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"
33 extern bool dos_file_warning;
34 extern bool ignore_case_with_glob;
35 extern bool allow_winsymlinks;
36 bool reset_com = false;
37 static bool envcache = true;
38 static bool create_upcaseenv = false;
40 static char **lastenviron;
42 /* Helper functions for the below environment variables which have to
43 be converted Win32<->POSIX. */
44 extern "C" ssize_t env_PATH_to_posix (const void *, void *, size_t);
47 env_plist_to_posix (const void *win32, void *posix, size_t size)
49 return cygwin_conv_path_list (CCP_WIN_A_TO_POSIX | CCP_RELATIVE, win32,
54 env_plist_to_win32 (const void *posix, void *win32, size_t size)
56 return cygwin_conv_path_list (CCP_POSIX_TO_WIN_A | CCP_RELATIVE, posix,
61 env_path_to_posix (const void *win32, void *posix, size_t size)
63 return cygwin_conv_path (CCP_WIN_A_TO_POSIX | CCP_ABSOLUTE, win32,
68 env_path_to_win32 (const void *posix, void *win32, size_t size)
70 return cygwin_conv_path (CCP_POSIX_TO_WIN_A | CCP_ABSOLUTE, posix,
75 (CYGWIN_VERSION_DLL_MAKE_COMBINED (user_data->api_major, user_data->api_minor) \
76 <= CYGWIN_VERSION_DLL_MALLOC_ENV)
78 #define NL(x) x, (sizeof (x) - 1)
79 /* List of names which are converted from dos to unix
80 on the way in and back again on the way out.
82 PATH needs to be here because CreateProcess uses it and gdb uses
83 CreateProcess. HOME is here because most shells use it and would be
84 confused by Windows style path names. */
85 static win_env conv_envvars[] =
87 {NL ("PATH="), NULL, NULL, env_PATH_to_posix, env_plist_to_win32, true},
88 {NL ("HOME="), NULL, NULL, env_path_to_posix, env_path_to_win32, false},
89 {NL ("LD_LIBRARY_PATH="), NULL, NULL,
90 env_plist_to_posix, env_plist_to_win32, true},
91 {NL ("TMPDIR="), NULL, NULL, env_path_to_posix, env_path_to_win32, false},
92 {NL ("TMP="), NULL, NULL, env_path_to_posix, env_path_to_win32, false},
93 {NL ("TEMP="), NULL, NULL, env_path_to_posix, env_path_to_win32, false},
94 {NULL, 0, NULL, NULL, 0, 0}
97 static unsigned char conv_start_chars[256] = {0};
100 win_env::operator = (struct win_env& x)
119 win_env::add_cache (const char *in_posix, const char *in_native)
122 posix = (char *) realloc (posix, strlen (in_posix) + 1);
123 strcpy (posix, in_posix);
126 native = (char *) realloc (native, namelen + 1 + strlen (in_native));
127 strcpy (native, name);
128 strcpy (native + namelen, in_native);
133 char *buf = tp.c_get ();
134 strcpy (buf, name + namelen);
135 towin32 (in_posix, buf, NT_MAX_PATH);
136 native = (char *) realloc (native, namelen + 1 + strlen (buf));
137 strcpy (native, name);
138 strcpy (native + namelen, buf);
141 if (immediate && cygwin_finished_initializing)
144 size_t n = namelen - 1;
147 SetEnvironmentVariable (s, native + namelen);
149 debug_printf ("posix %s", posix);
150 debug_printf ("native %s", native);
154 /* Check for a "special" environment variable name. *env is the pointer
155 to the beginning of the environment variable name. *in_posix is any
156 known posix value for the environment variable. Returns a pointer to
157 the appropriate conversion structure. */
159 getwinenv (const char *env, const char *in_posix, win_env *temp)
161 if (!conv_start_chars[(unsigned char)*env])
164 for (int i = 0; conv_envvars[i].name != NULL; i++)
165 if (strncmp (env, conv_envvars[i].name, conv_envvars[i].namelen) == 0)
167 win_env *we = conv_envvars + i;
169 if (!cur_environ () || !(val = in_posix ?: getenv (we->name)))
170 debug_printf ("can't set native for %s since no environ yet",
172 else if (!envcache || !we->posix || strcmp (val, we->posix) != 0)
186 /* Convert windows path specs to POSIX, if appropriate.
188 static void __stdcall
189 posify (char **here, const char *value, char *outenv)
194 if (!(conv = getwinenv (src)))
197 int len = strcspn (src, "=") + 1;
199 /* Turn all the items from c:<foo>;<bar> into their
200 mounted equivalents - if there is one. */
202 memcpy (outenv, src, len);
203 char *newvalue = outenv + len;
204 if (!conv->toposix (value, newvalue, NT_MAX_PATH - len)
205 || _impure_ptr->_errno != EIDRM)
206 conv->add_cache (newvalue, *value != '/' ? value : NULL);
209 /* The conversion routine removed elements from a path list so we have
210 to recalculate the windows path to remove elements there, too. */
211 char cleanvalue[strlen (value) + 1];
212 conv->towin32 (newvalue, cleanvalue, sizeof cleanvalue);
213 conv->add_cache (newvalue, cleanvalue);
216 debug_printf ("env var converted to %s", outenv);
217 *here = strdup (outenv);
222 /* Returns pointer to value associated with name, if any, else NULL.
223 Sets offset to be the offset of the name/value combination in the
224 environment array, for use by setenv(3) and unsetenv(3).
225 Explicitly removes '=' in argument name. */
227 static char * __stdcall
228 my_findenv (const char *name, int *offset)
236 while (*c && *c != '=')
242 for (p = cur_environ (); *p; ++p)
243 if (!strncmp (*p, name, len))
244 if (*(c = *p + len) == '=')
246 *offset = p - cur_environ ();
247 return (char *) (++c);
253 /* Primitive getenv before the environment is built. */
255 static char __stdcall *
256 getearly (const char * name, int *)
262 if (spawn_info && (ptr = spawn_info->moreinfo->envp))
266 if (strncasematch (name, *ptr, len) && (*ptr)[len] == '=')
267 return *ptr + len + 1;
269 else if ((len = GetEnvironmentVariableA (name, NULL, 0))
270 && (ret = (char *) cmalloc_abort (HEAP_2_STR, len))
271 && GetEnvironmentVariableA (name, ret, len))
277 static char * (*findenv_func)(const char *, int *) = (char * (*)(const char *, int *)) getearly;
279 /* Returns ptr to value associated with name, if any, else NULL. */
282 getenv (const char *name)
285 return findenv_func (name, &offset);
288 /* This function is required so that newlib uses the same environment
291 _getenv_r (struct _reent *, const char *name)
294 return findenv_func (name, &offset);
298 envsize (const char * const *in_envp)
300 const char * const *envp;
301 for (envp = in_envp; *envp; envp++)
303 return (1 + envp - in_envp) * sizeof (const char *);
306 /* Takes similar arguments to setenv except that overwrite is
307 either -1, 0, or 1. 0 or 1 signify that the function should
308 perform similarly to setenv. Otherwise putenv is assumed. */
310 _addenv (const char *name, const char *value, int overwrite)
312 int issetenv = overwrite >= 0;
316 unsigned int valuelen = strlen (value);
317 if ((p = my_findenv (name, &offset)))
318 { /* Already exists. */
319 if (!overwrite) /* Ok to overwrite? */
320 return 0; /* No. Wanted to add new value. FIXME: Right return value? */
322 /* We've found the offset into environ. If this is a setenv call and
323 there is room in the current environment entry then just overwrite it.
324 Otherwise handle this case below. */
325 if (issetenv && strlen (p) >= valuelen)
332 { /* Create new slot. */
333 int sz = envsize (cur_environ ());
334 int allocsz = sz + (2 * sizeof (char *));
336 offset = (sz - 1) / sizeof (char *);
338 /* Allocate space for additional element plus terminating NULL. */
339 if (cur_environ () == lastenviron)
340 lastenviron = __cygwin_environ = (char **) realloc (cur_environ (),
342 else if ((lastenviron = (char **) malloc (allocsz)) != NULL)
343 __cygwin_environ = (char **) memcpy ((char **) lastenviron,
344 __cygwin_environ, sz);
346 if (!__cygwin_environ)
351 return -1; /* Oops. No more memory. */
354 __cygwin_environ[offset + 1] = NULL; /* NULL terminate. */
355 update_envptrs (); /* Update any local copies of 'environ'. */
360 /* Not setenv. Just overwrite existing. */
361 envhere = cur_environ ()[offset] = (char *) (ENVMALLOC ? strdup (name) : name);
364 /* Look for an '=' in the name and ignore anything after that if found. */
365 for (p = (char *) name; *p && *p != '='; p++)
368 int namelen = p - name; /* Length of name. */
369 /* Allocate enough space for name + '=' + value + '\0' */
370 envhere = cur_environ ()[offset] = (char *) malloc (namelen + valuelen + 2);
372 return -1; /* Oops. No more memory. */
374 /* Put name '=' value into current slot. */
375 strncpy (envhere, name, namelen);
376 envhere[namelen] = '=';
377 strcpy (envhere + namelen + 1, value);
380 /* Update cygwin's cache, if appropriate */
382 if ((spenv = getwinenv (envhere)))
383 spenv->add_cache (value);
389 /* Set an environment variable */
394 if (efault.faulted (EFAULT))
398 char *eq = strchr (str, '=');
400 return _addenv (str, eq + 1, -1);
402 /* Remove str from the environment. */
408 /* Set the value of the environment variable "name" to be
409 "value". If overwrite is set, replace any current value. */
411 setenv (const char *name, const char *value, int overwrite)
414 if (efault.faulted (EFAULT))
420 return _addenv (name, value, !!overwrite);
423 /* Delete environment variable "name". */
425 unsetenv (const char *name)
430 if (efault.faulted () || *name == '\0' || strchr (name, '='))
436 while (my_findenv (name, &offset)) /* if set multiple times */
437 /* Move up the rest of the array */
438 for (e = cur_environ () + offset; ; e++)
439 if (!(*e = *(e + 1)))
445 /* Minimal list of Windows vars which must be converted to uppercase.
446 Either for POSIX compatibility of for backward compatibility with
447 existing applications. */
450 const size_t namelen;
452 { NL("ALLUSERSPROFILE=") }, // 0
453 { NL("COMMONPROGRAMFILES=") }, // 1
454 { NL("COMPUTERNAME=") },
456 { NL("HOME=") }, // 4
457 { NL("HOMEDRIVE=") },
459 { NL("NUMBER_OF_PROCESSORS=") }, // 7
461 { NL("PATH=") }, // 9
463 { NL("PROCESSOR_ARCHITECTURE=") },
464 { NL("PROCESSOR_IDENTIFIER=") },
465 { NL("PROCESSOR_LEVEL=") },
466 { NL("PROCESSOR_REVISION=") },
467 { NL("PROGRAMFILES=") },
468 { NL("SYSTEMDRIVE=") }, // 16
469 { NL("SYSTEMROOT=") },
470 { NL("TEMP=") }, // 18
474 { NL("WINDIR=") } // 22
476 #define RENV_SIZE (sizeof (renv_arr) / sizeof (renv_arr[0]))
477 /* Set of first characters of the above list of variables. */
478 static const char idx_arr[] = "ACHNOPSTW";
479 /* Index into renv_arr at which the variables with this specific character
481 static const int start_at[] = { 0, 1, 4, 7, 8, 9, 16, 18, 22 };
483 /* Turn environment variable part of a=b string into uppercase.
484 Conditionally controlled by upcaseenv CYGWIN setting. */
485 static __inline__ void
486 ucenv (char *p, const char *eq)
488 if (create_upcaseenv)
490 /* Amazingly, NT has a case sensitive environment name list,
492 It's normal to have NT set your "Path" to something.
493 Later, you set "PATH" to something else. This alters "Path".
494 But if you try and do a naive getenv on "PATH" you'll get nothing.
496 So we upper case the labels here to prevent confusion later but
497 we only do it for processes that are started by non-Cygwin programs. */
500 *p = cyg_toupper (*p);
504 /* Hopefully as quickly as possible - only upcase specific set of important
505 Windows variables. */
506 char first = cyg_toupper (*p);
507 const char *idx = strchr (idx_arr, first);
509 for (size_t i = start_at[idx - idx_arr];
510 i < RENV_SIZE && renv_arr[i].name[0] == first;
512 if (strncasematch (p, renv_arr[i].name, renv_arr[i].namelen))
514 strncpy (p, renv_arr[i].name, renv_arr[i].namelen);
520 /* Parse CYGWIN options */
522 static NO_COPY bool export_settings = false;
533 null or empty: disables globbing
534 "ignorecase": enables case-insensitive globbing
535 anything else: enables case-sensitive globbing */
537 glob_init (const char *buf)
542 ignore_case_with_glob = false;
544 else if (ascii_strncasematch (buf, "ignorecase", 10))
547 ignore_case_with_glob = true;
552 ignore_case_with_glob = false;
557 set_chunksize (const char *buf)
559 wincap.set_chunksize (strtoul (buf, NULL, 0));
563 set_proc_retry (const char *buf)
565 child_info::retry_count = strtoul (buf, NULL, 0);
568 /* The structure below is used to set up an array which is used to
569 parse the CYGWIN environment variable or, if enabled, options from
571 static struct parse_thing
579 void (*func)(const char *);
582 enum settings disposition;
591 {"dosfilewarning", {&dos_file_warning}, justset, NULL, {{false}, {true}}},
592 {"envcache", {&envcache}, justset, NULL, {{true}, {false}}},
593 {"error_start", {func: &error_start_init}, isfunc, NULL, {{0}, {0}}},
594 {"export", {&export_settings}, justset, NULL, {{false}, {true}}},
595 {"forkchunk", {func: set_chunksize}, isfunc, NULL, {{0}, {0}}},
596 {"glob", {func: &glob_init}, isfunc, NULL, {{0}, {s: "normal"}}},
597 {"proc_retry", {func: set_proc_retry}, isfunc, NULL, {{0}, {5}}},
598 {"reset_com", {&reset_com}, justset, NULL, {{false}, {true}}},
599 {"strip_title", {&strip_title_path}, justset, NULL, {{false}, {true}}},
600 {"title", {&display_title}, justset, NULL, {{false}, {true}}},
601 {"tty", {NULL}, set_process_state, NULL, {{0}, {PID_USETTY}}},
602 {"upcaseenv", {&create_upcaseenv}, justset, NULL, {{false}, {true}}},
603 {"winsymlinks", {&allow_winsymlinks}, justset, NULL, {{false}, {true}}},
604 {NULL, {0}, justset, 0, {{0}, {0}}}
607 /* Parse a string of the form "something=stuff somethingelse=more-stuff",
608 silently ignoring unknown "somethings". */
609 static void __stdcall
610 parse_options (char *buf)
619 char *newbuf = tp.c_get ();
621 for (k = known; k->name != NULL; k++)
624 strcat (strcat (newbuf, " "), k->remember);
631 debug_printf ("%s", newbuf + 1);
632 setenv ("CYGWIN", newbuf + 1, 1);
637 buf = strcpy ((char *) alloca (strlen (buf) + 1), buf);
638 for (p = strtok_r (buf, " \t", &lasts);
640 p = strtok_r (NULL, " \t", &lasts))
642 char *keyword_here = p;
643 if (!(istrue = !ascii_strncasematch (p, "no", 2)))
645 else if (!(istrue = *p != '-'))
649 if ((eq = strchr (p, '=')) != NULL || (eq = strchr (p, ':')) != NULL)
650 ch = *eq, *eq++ = '\0';
654 for (parse_thing *k = known; k->name != NULL; k++)
655 if (ascii_strcasematch (p, k->name))
657 switch (k->disposition)
660 k->setting.func ((!eq || !istrue) ?
661 k->values[istrue].s : eq);
662 debug_printf ("%s (called func)", k->name);
666 *k->setting.x = k->values[istrue].i;
668 *k->setting.x = strtol (eq, NULL, 0);
669 debug_printf ("%s %d", k->name, *k->setting.x);
671 case set_process_state:
672 k->setting.x = &myself->process_state;
675 *k->setting.x &= ~k->values[istrue].i;
676 if (istrue || (eq && strtol (eq, NULL, 0)))
677 *k->setting.x |= k->values[istrue].i;
678 debug_printf ("%s %x", k->name, *k->setting.x);
686 p = strdup (keyword_here);
693 debug_printf ("returning");
696 /* Set options from the registry. */
697 static bool __stdcall
698 regopt (const char *name, char *buf)
700 bool parsed_something = false;
701 char lname[strlen (name) + 1];
702 strlwr (strcpy (lname, name));
704 for (int i = 0; i < 2; i++)
706 reg_key r (i, KEY_READ, CYGWIN_INFO_PROGRAM_OPTIONS_NAME, NULL);
708 if (r.get_string (lname, buf, NT_MAX_PATH, "") == ERROR_SUCCESS)
711 parsed_something = true;
717 return parsed_something;
720 /* Initialize the environ array. Look for the CYGWIN environment
721 environment variable and set appropriate options from it. */
723 environ_init (char **envp, int envc)
731 bool got_something_from_registry;
732 static char NO_COPY cygterm[] = "TERM=cygwin";
735 static const char *lc_arr[] = { "LC_ALL", "LC_CTYPE", "LANG", NULL };
737 if (efault.faulted ())
738 api_fatal ("internal error reading the windows environment - too many environment variables?");
740 if (!conv_start_chars[0])
741 for (int i = 0; conv_envvars[i].name != NULL; i++)
743 conv_start_chars[(int) cyg_tolower (conv_envvars[i].name[0])] = 1;
744 conv_start_chars[(int) cyg_toupper (conv_envvars[i].name[0])] = 1;
747 char *tmpbuf = tp.t_get ();
748 got_something_from_registry = regopt ("default", tmpbuf);
749 if (myself->progname[0])
750 got_something_from_registry = regopt (myself->progname, tmpbuf)
751 || got_something_from_registry;
758 envc *= sizeof (char *);
759 char **newenv = (char **) malloc (envc);
760 memcpy (newenv, envp, envc);
763 /* Older applications relied on the fact that cygwin malloced elements of the
767 for (char **e = newenv; *e; e++)
777 /* Allocate space for environment + trailing NULL + CYGWIN env. */
778 lastenviron = envp = (char **) malloc ((4 + (envc = 100)) * sizeof (char *));
780 /* We need the locale variables' content before we can loop through
781 the whole environment, so that the wide-char to multibyte conversion
782 can be done according to the $LC_ALL/$LC_CTYPE/$LANG/current_codepage
783 setting, as well as the uppercasing according to the "upcaseenv"
784 setting. Note that we have to reset the LC_CTYPE setting to "C"
785 before calling main() for POSIX compatibility. */
786 for (int lc = 0; lc_arr[lc]; ++lc)
788 if ((i = GetEnvironmentVariableA (lc_arr[lc], NULL, 0)))
790 char *buf = (char *) alloca (i);
791 GetEnvironmentVariableA (lc_arr[lc], buf, i);
792 if (setlocale (LC_CTYPE, buf))
796 /* We also need the CYGWIN variable early to know the value of the
797 CYGWIN=upcaseenv setting for the below loop. */
798 if ((i = GetEnvironmentVariableA ("CYGWIN", NULL, 0)))
800 char *buf = (char *) alloca (i);
801 GetEnvironmentVariableA ("CYGWIN", buf, i);
805 rawenv = GetEnvironmentStringsW ();
808 system_printf ("GetEnvironmentStrings returned NULL, %E");
811 debug_printf ("GetEnvironmentStrings returned %p", rawenv);
813 /* Current directory information is recorded as variables of the
814 form "=X:=X:\foo\bar; these must be changed into something legal
815 (we could just ignore them but maybe an application will
816 eventually want to use them). */
817 for (i = 0, w = rawenv; *w != L'\0'; w = wcschr (w, L'\0') + 1, i++)
819 sys_wcstombs_alloc (&newp, HEAP_NOTHEAP, w);
821 envp = (char **) realloc (envp, (4 + (envc += 100)) * sizeof (char *));
825 char *eq = strechr (newp, '=');
826 ucenv (newp, eq); /* (possibly conditionally) uppercase env vars. */
827 if (*newp == 'T' && strncmp (newp, "TERM=", 5) == 0)
829 if (*eq && conv_start_chars[(unsigned char) envp[i][0]])
830 posify (envp + i, *++eq ? eq : --eq, tmpbuf);
831 debug_printf ("%p: %s", envp[i], envp[i]);
835 envp[i++] = strdup (cygterm);
837 FreeEnvironmentStringsW (rawenv);
840 findenv_func = (char * (*)(const char*, int*)) my_findenv;
841 __cygwin_environ = envp;
845 p = getenv ("CYGWIN");
850 if (got_something_from_registry)
851 parse_options (NULL); /* possibly export registry settings to
856 /* Function called by qsort to sort environment strings. */
858 env_sort (const void *a, const void *b)
860 const char **p = (const char **) a;
861 const char **q = (const char **) b;
863 return strcmp (*p, *q);
867 getwinenveq (const char *name, size_t namelen, int x)
869 WCHAR name0[namelen - 1];
870 WCHAR valbuf[32768]; /* Max size of an env.var including trailing '\0'. */
872 name0[sys_mbstowcs (name0, sizeof name0, name, namelen - 1)] = L'\0';
873 int totlen = GetEnvironmentVariableW (name0, valbuf, 32768);
876 totlen = sys_wcstombs (NULL, 0, valbuf);
881 char *p = (char *) cmalloc_abort ((cygheap_types) x, totlen);
884 sys_wcstombs (p + namelen, totlen, valbuf);
885 debug_printf ("using value from GetEnvironmentVariable for '%W'", name0);
889 debug_printf ("warning: %s not present in environment", name);
897 bool force_into_environment; /* If true, always add to env if missing */
898 bool add_if_exists; /* if true, retrieve value from cache */
899 const char * (cygheap_user::*from_cygheap) (const char *, size_t);
901 char *retrieve (bool, const char * const = NULL)
902 __attribute__ ((regparm (3)));
905 #define env_dontadd almost_null
907 /* Keep this list in upper case and sorted */
908 static NO_COPY spenv spenvs[] =
911 {NL ("CYGWIN_DEBUG="), false, true, NULL},
913 {NL ("HOMEDRIVE="), false, false, &cygheap_user::env_homedrive},
914 {NL ("HOMEPATH="), false, false, &cygheap_user::env_homepath},
915 {NL ("LOGONSERVER="), false, false, &cygheap_user::env_logsrv},
916 {NL ("PATH="), false, true, NULL},
917 {NL ("SYSTEMDRIVE="), false, true, NULL},
918 {NL ("SYSTEMROOT="), true, true, &cygheap_user::env_systemroot},
919 {NL ("USERDOMAIN="), false, false, &cygheap_user::env_domain},
920 {NL ("USERNAME="), false, false, &cygheap_user::env_name},
921 {NL ("USERPROFILE="), false, false, &cygheap_user::env_userprofile},
922 {NL ("WINDIR="), true, true, &cygheap_user::env_systemroot}
926 spenv::retrieve (bool no_envblock, const char *const env)
928 if (env && !ascii_strncasematch (env, name, namelen))
931 debug_printf ("no_envblock %d", no_envblock);
936 if (env && !cygheap->user.issetuid ())
938 debug_printf ("duping existing value for '%s'", name);
939 /* Don't really care what it's set to if we're calling a cygwin program */
940 return cstrdup1 (env);
943 /* Calculate (potentially) value for given environment variable. */
944 p = (cygheap->user.*from_cygheap) (name, namelen);
945 if (!p || (no_envblock && !env) || (p == env_dontadd))
947 char *s = (char *) cmalloc_abort (HEAP_1_STR, namelen + strlen (p) + 1);
949 strcpy (s + namelen, p);
950 debug_printf ("using computed value for '%s'", name);
955 return cstrdup1 (env);
957 return getwinenveq (name, namelen, HEAP_1_STR);
960 #define SPENVS_SIZE (sizeof (spenvs) / sizeof (spenvs[0]))
962 /* Create a Windows-style environment block, i.e. a typical character buffer
963 filled with null terminated strings, terminated by double null characters.
964 Converts environment variables noted in conv_envvars into win32 form
965 prior to placing them in the string. */
967 build_env (const char * const *envp, PWCHAR &envblock, int &envc,
971 const char * const *srcp;
973 bool saw_spenv[SPENVS_SIZE] = {0};
975 debug_printf ("envp %p", envp);
977 /* How many elements? */
978 for (n = 0; envp[n]; n++)
981 /* Allocate a new "argv-style" environ list with room for extra stuff. */
982 char **newenv = (char **) cmalloc_abort (HEAP_1_ARGV, sizeof (char *) *
983 (n + SPENVS_SIZE + 1));
987 char **pass_env = (char **) alloca (sizeof (char *) * (n + SPENVS_SIZE + 1));
988 /* Iterate over input list, generating a new environment list and refreshing
989 "special" entries, if necessary. */
990 for (srcp = envp, dstp = newenv, pass_dstp = pass_env; *srcp; srcp++)
992 bool calc_tl = !no_envblock;
993 /* Look for entries that require special attention */
994 for (unsigned i = 0; i < SPENVS_SIZE; i++)
995 if (!saw_spenv[i] && (*dstp = spenvs[i].retrieve (no_envblock, *srcp)))
998 if (*dstp == env_dontadd)
1000 if (spenvs[i].add_if_exists)
1005 /* Add entry to new environment */
1006 *dstp = cstrdup1 (*srcp);
1011 *pass_dstp++ = *dstp;
1012 tl += strlen (*dstp) + 1;
1019 assert ((srcp - envp) == n);
1020 /* Fill in any required-but-missing environment variables. */
1021 for (unsigned i = 0; i < SPENVS_SIZE; i++)
1022 if (!saw_spenv[i] && (spenvs[i].force_into_environment || cygheap->user.issetuid ()))
1024 *dstp = spenvs[i].retrieve (false);
1025 if (*dstp && *dstp != env_dontadd)
1027 *pass_dstp++ = *dstp;
1028 tl += strlen (*dstp) + 1;
1033 envc = dstp - newenv; /* Number of entries in newenv */
1034 assert ((size_t) envc <= (n + SPENVS_SIZE));
1035 *dstp = NULL; /* Terminate */
1037 size_t pass_envc = pass_dstp - pass_env;
1043 debug_printf ("env count %d, bytes %d", pass_envc, tl);
1047 /* Windows programs expect the environment block to be sorted. */
1048 qsort (pass_env, pass_envc, sizeof (char *), env_sort);
1050 /* Create an environment block suitable for passing to CreateProcess. */
1052 envblock = (PWCHAR) malloc ((2 + tl) * sizeof (WCHAR));
1054 for (srcp = pass_env, s = envblock; *srcp; srcp++)
1058 len = strcspn (*srcp, "=") + 1;
1059 const char *rest = *srcp + len;
1061 /* Check for a bad entry. This is necessary to get rid of empty
1062 strings, induced by putenv and changing the string afterwards.
1063 Note that this doesn't stop invalid strings without '=' in it
1064 etc., but we're opting for speed here for now. Adding complete
1065 checking would be pretty expensive. */
1066 if (len == 1 || !*rest)
1069 /* See if this entry requires posix->win32 conversion. */
1070 conv = getwinenv (*srcp, rest, &temp);
1072 p = conv->native; /* Use win32 path */
1074 p = *srcp; /* Don't worry about it */
1076 len = sys_mbstowcs (NULL, 0, p);
1077 new_tl += len; /* Keep running total of block length so far */
1079 /* See if we need to increase the size of the block. */
1083 PWCHAR new_envblock =
1084 (PWCHAR) realloc (envblock, (2 + tl) * sizeof (WCHAR));
1085 /* If realloc moves the block, move `s' with it. */
1086 if (new_envblock != envblock)
1088 s += new_envblock - envblock;
1089 envblock = new_envblock;
1093 int slen = sys_mbstowcs (s, len, p);
1095 /* See if environment variable is "special" in a Windows sense.
1096 Under NT, the current directories for visited drives are stored
1097 as =C:=\bar. Cygwin converts the '=' to '!' for hopefully obvious
1098 reasons. We need to convert it back when building the envblock */
1099 if (s[0] == L'!' && (iswdrive (s + 1) || (s[1] == L':' && s[2] == L':'))
1104 *s = L'\0'; /* Two null bytes at the end */
1105 assert ((s - envblock) <= tl); /* Detect if we somehow ran over end
1109 debug_printf ("envp %p, envc %d", newenv, envc);
1113 /* This idiocy is necessary because the early implementers of cygwin
1114 did not seem to know about importing data variables from the DLL.
1115 So, we have to synchronize cygwin's idea of the environment with the
1116 main program's with each reference to the environment. */
1117 extern "C" char ** __stdcall
1120 if (*main_environ != __cygwin_environ)
1122 __cygwin_environ = *main_environ;
1126 return __cygwin_environ;