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"
34 extern bool dos_file_warning;
35 extern bool ignore_case_with_glob;
36 extern bool allow_winsymlinks;
37 bool reset_com = false;
38 static bool envcache = true;
39 static bool create_upcaseenv = false;
41 static char **lastenviron;
43 /* Helper functions for the below environment variables which have to
44 be converted Win32<->POSIX. */
45 extern "C" ssize_t env_PATH_to_posix (const void *, void *, size_t);
48 env_plist_to_posix (const void *win32, void *posix, size_t size)
50 return cygwin_conv_path_list (CCP_WIN_A_TO_POSIX | CCP_RELATIVE, win32,
55 env_plist_to_win32 (const void *posix, void *win32, size_t size)
57 return cygwin_conv_path_list (CCP_POSIX_TO_WIN_A | CCP_RELATIVE, posix,
62 env_path_to_posix (const void *win32, void *posix, size_t size)
64 return cygwin_conv_path (CCP_WIN_A_TO_POSIX | CCP_ABSOLUTE, win32,
69 env_path_to_win32 (const void *posix, void *win32, size_t size)
71 return cygwin_conv_path (CCP_POSIX_TO_WIN_A | CCP_ABSOLUTE, posix,
76 (CYGWIN_VERSION_DLL_MAKE_COMBINED (user_data->api_major, user_data->api_minor) \
77 <= CYGWIN_VERSION_DLL_MALLOC_ENV)
79 #define NL(x) x, (sizeof (x) - 1)
80 /* List of names which are converted from dos to unix
81 on the way in and back again on the way out.
83 PATH needs to be here because CreateProcess uses it and gdb uses
84 CreateProcess. HOME is here because most shells use it and would be
85 confused by Windows style path names. */
86 static win_env conv_envvars[] =
88 {NL ("PATH="), NULL, NULL, env_PATH_to_posix, env_plist_to_win32, true},
89 {NL ("HOME="), NULL, NULL, env_path_to_posix, env_path_to_win32, false},
90 {NL ("LD_LIBRARY_PATH="), NULL, NULL,
91 env_plist_to_posix, env_plist_to_win32, true},
92 {NL ("TMPDIR="), NULL, NULL, env_path_to_posix, env_path_to_win32, false},
93 {NL ("TMP="), NULL, NULL, env_path_to_posix, env_path_to_win32, false},
94 {NL ("TEMP="), NULL, NULL, env_path_to_posix, env_path_to_win32, false},
95 {NULL, 0, NULL, NULL, 0, 0}
98 static unsigned char conv_start_chars[256] = {0};
101 win_env::operator = (struct win_env& x)
120 win_env::add_cache (const char *in_posix, const char *in_native)
123 posix = (char *) realloc (posix, strlen (in_posix) + 1);
124 strcpy (posix, in_posix);
127 native = (char *) realloc (native, namelen + 1 + strlen (in_native));
128 strcpy (native, name);
129 strcpy (native + namelen, in_native);
134 char *buf = tp.c_get ();
135 strcpy (buf, name + namelen);
136 towin32 (in_posix, buf, NT_MAX_PATH);
137 native = (char *) realloc (native, namelen + 1 + strlen (buf));
138 strcpy (native, name);
139 strcpy (native + namelen, buf);
142 if (immediate && cygwin_finished_initializing)
145 size_t n = namelen - 1;
148 SetEnvironmentVariable (s, native + namelen);
150 debug_printf ("posix %s", posix);
151 debug_printf ("native %s", native);
155 /* Check for a "special" environment variable name. *env is the pointer
156 to the beginning of the environment variable name. *in_posix is any
157 known posix value for the environment variable. Returns a pointer to
158 the appropriate conversion structure. */
160 getwinenv (const char *env, const char *in_posix, win_env *temp)
162 if (!conv_start_chars[(unsigned char)*env])
165 for (int i = 0; conv_envvars[i].name != NULL; i++)
166 if (strncmp (env, conv_envvars[i].name, conv_envvars[i].namelen) == 0)
168 win_env *we = conv_envvars + i;
170 if (!cur_environ () || !(val = in_posix ?: getenv (we->name)))
171 debug_printf ("can't set native for %s since no environ yet",
173 else if (!envcache || !we->posix || strcmp (val, we->posix) != 0)
187 /* Convert windows path specs to POSIX, if appropriate.
189 static void __stdcall
190 posify (char **here, const char *value, char *outenv)
195 if (!(conv = getwinenv (src)))
198 int len = strcspn (src, "=") + 1;
200 /* Turn all the items from c:<foo>;<bar> into their
201 mounted equivalents - if there is one. */
203 memcpy (outenv, src, len);
204 char *newvalue = outenv + len;
205 if (!conv->toposix (value, newvalue, NT_MAX_PATH - len)
206 || _impure_ptr->_errno != EIDRM)
207 conv->add_cache (newvalue, *value != '/' ? value : NULL);
210 /* The conversion routine removed elements from a path list so we have
211 to recalculate the windows path to remove elements there, too. */
212 char cleanvalue[strlen (value) + 1];
213 conv->towin32 (newvalue, cleanvalue, sizeof cleanvalue);
214 conv->add_cache (newvalue, cleanvalue);
217 debug_printf ("env var converted to %s", outenv);
218 *here = strdup (outenv);
223 /* Returns pointer to value associated with name, if any, else NULL.
224 Sets offset to be the offset of the name/value combination in the
225 environment array, for use by setenv(3) and unsetenv(3).
226 Explicitly removes '=' in argument name. */
228 static char * __stdcall
229 my_findenv (const char *name, int *offset)
237 while (*c && *c != '=')
243 for (p = cur_environ (); *p; ++p)
244 if (!strncmp (*p, name, len))
245 if (*(c = *p + len) == '=')
247 *offset = p - cur_environ ();
248 return (char *) (++c);
254 /* Primitive getenv before the environment is built. */
256 static char __stdcall *
257 getearly (const char * name, int *)
263 if (spawn_info && (ptr = spawn_info->moreinfo->envp))
267 if (strncasematch (name, *ptr, len) && (*ptr)[len] == '=')
268 return *ptr + len + 1;
270 else if ((len = GetEnvironmentVariableA (name, NULL, 0))
271 && (ret = (char *) cmalloc_abort (HEAP_2_STR, len))
272 && GetEnvironmentVariableA (name, ret, len))
278 static char * (*findenv_func)(const char *, int *) = (char * (*)(const char *, int *)) getearly;
280 /* Returns ptr to value associated with name, if any, else NULL. */
283 getenv (const char *name)
286 return findenv_func (name, &offset);
289 /* This function is required so that newlib uses the same environment
292 _getenv_r (struct _reent *, const char *name)
295 return findenv_func (name, &offset);
299 envsize (const char * const *in_envp)
301 const char * const *envp;
302 for (envp = in_envp; *envp; envp++)
304 return (1 + envp - in_envp) * sizeof (const char *);
307 /* Takes similar arguments to setenv except that overwrite is
308 either -1, 0, or 1. 0 or 1 signify that the function should
309 perform similarly to setenv. Otherwise putenv is assumed. */
311 _addenv (const char *name, const char *value, int overwrite)
313 int issetenv = overwrite >= 0;
317 unsigned int valuelen = strlen (value);
318 if ((p = my_findenv (name, &offset)))
319 { /* Already exists. */
320 if (!overwrite) /* Ok to overwrite? */
321 return 0; /* No. Wanted to add new value. FIXME: Right return value? */
323 /* We've found the offset into environ. If this is a setenv call and
324 there is room in the current environment entry then just overwrite it.
325 Otherwise handle this case below. */
326 if (issetenv && strlen (p) >= valuelen)
333 { /* Create new slot. */
334 int sz = envsize (cur_environ ());
335 int allocsz = sz + (2 * sizeof (char *));
337 offset = (sz - 1) / sizeof (char *);
339 /* Allocate space for additional element plus terminating NULL. */
340 if (cur_environ () == lastenviron)
341 lastenviron = __cygwin_environ = (char **) realloc (cur_environ (),
343 else if ((lastenviron = (char **) malloc (allocsz)) != NULL)
344 __cygwin_environ = (char **) memcpy ((char **) lastenviron,
345 __cygwin_environ, sz);
347 if (!__cygwin_environ)
352 return -1; /* Oops. No more memory. */
355 __cygwin_environ[offset + 1] = NULL; /* NULL terminate. */
356 update_envptrs (); /* Update any local copies of 'environ'. */
361 /* Not setenv. Just overwrite existing. */
362 envhere = cur_environ ()[offset] = (char *) (ENVMALLOC ? strdup (name) : name);
365 /* Look for an '=' in the name and ignore anything after that if found. */
366 for (p = (char *) name; *p && *p != '='; p++)
369 int namelen = p - name; /* Length of name. */
370 /* Allocate enough space for name + '=' + value + '\0' */
371 envhere = cur_environ ()[offset] = (char *) malloc (namelen + valuelen + 2);
373 return -1; /* Oops. No more memory. */
375 /* Put name '=' value into current slot. */
376 strncpy (envhere, name, namelen);
377 envhere[namelen] = '=';
378 strcpy (envhere + namelen + 1, value);
381 /* Update cygwin's cache, if appropriate */
383 if ((spenv = getwinenv (envhere)))
384 spenv->add_cache (value);
390 /* Set an environment variable */
395 if (efault.faulted (EFAULT))
399 char *eq = strchr (str, '=');
401 return _addenv (str, eq + 1, -1);
403 /* Remove str from the environment. */
409 /* Set the value of the environment variable "name" to be
410 "value". If overwrite is set, replace any current value. */
412 setenv (const char *name, const char *value, int overwrite)
415 if (efault.faulted (EFAULT))
417 if (!name || !*name || strchr (name, '='))
422 return _addenv (name, value, !!overwrite);
425 /* Delete environment variable "name". */
427 unsetenv (const char *name)
432 if (efault.faulted (EFAULT))
434 if (!name || *name == '\0' || strchr (name, '='))
440 while (my_findenv (name, &offset)) /* if set multiple times */
441 /* Move up the rest of the array */
442 for (e = cur_environ () + offset; ; e++)
443 if (!(*e = *(e + 1)))
449 /* Minimal list of Windows vars which must be converted to uppercase.
450 Either for POSIX compatibility of for backward compatibility with
451 existing applications. */
454 const size_t namelen;
456 { NL("ALLUSERSPROFILE=") }, // 0
457 { NL("COMMONPROGRAMFILES=") }, // 1
458 { NL("COMPUTERNAME=") },
460 { NL("HOME=") }, // 4
461 { NL("HOMEDRIVE=") },
463 { NL("NUMBER_OF_PROCESSORS=") }, // 7
465 { NL("PATH=") }, // 9
467 { NL("PROCESSOR_ARCHITECTURE=") },
468 { NL("PROCESSOR_IDENTIFIER=") },
469 { NL("PROCESSOR_LEVEL=") },
470 { NL("PROCESSOR_REVISION=") },
471 { NL("PROGRAMFILES=") },
472 { NL("SYSTEMDRIVE=") }, // 16
473 { NL("SYSTEMROOT=") },
474 { NL("TEMP=") }, // 18
478 { NL("WINDIR=") } // 22
480 #define RENV_SIZE (sizeof (renv_arr) / sizeof (renv_arr[0]))
481 /* Set of first characters of the above list of variables. */
482 static const char idx_arr[] = "ACHNOPSTW";
483 /* Index into renv_arr at which the variables with this specific character
485 static const int start_at[] = { 0, 1, 4, 7, 8, 9, 16, 18, 22 };
487 /* Turn environment variable part of a=b string into uppercase.
488 Conditionally controlled by upcaseenv CYGWIN setting. */
489 static __inline__ void
490 ucenv (char *p, const char *eq)
492 if (create_upcaseenv)
494 /* Amazingly, NT has a case sensitive environment name list,
496 It's normal to have NT set your "Path" to something.
497 Later, you set "PATH" to something else. This alters "Path".
498 But if you try and do a naive getenv on "PATH" you'll get nothing.
500 So we upper case the labels here to prevent confusion later but
501 we only do it for processes that are started by non-Cygwin programs. */
504 *p = cyg_toupper (*p);
508 /* Hopefully as quickly as possible - only upcase specific set of important
509 Windows variables. */
510 char first = cyg_toupper (*p);
511 const char *idx = strchr (idx_arr, first);
513 for (size_t i = start_at[idx - idx_arr];
514 i < RENV_SIZE && renv_arr[i].name[0] == first;
516 if (strncasematch (p, renv_arr[i].name, renv_arr[i].namelen))
518 strncpy (p, renv_arr[i].name, renv_arr[i].namelen);
524 /* Parse CYGWIN options */
526 static NO_COPY bool export_settings = false;
537 null or empty: disables globbing
538 "ignorecase": enables case-insensitive globbing
539 anything else: enables case-sensitive globbing */
541 glob_init (const char *buf)
546 ignore_case_with_glob = false;
548 else if (ascii_strncasematch (buf, "ignorecase", 10))
551 ignore_case_with_glob = true;
556 ignore_case_with_glob = false;
561 set_chunksize (const char *buf)
563 wincap.set_chunksize (strtoul (buf, NULL, 0));
567 set_proc_retry (const char *buf)
569 child_info::retry_count = strtoul (buf, NULL, 0);
572 /* The structure below is used to set up an array which is used to
573 parse the CYGWIN environment variable or, if enabled, options from
575 static struct parse_thing
583 void (*func)(const char *);
586 enum settings disposition;
595 {"dosfilewarning", {&dos_file_warning}, justset, NULL, {{false}, {true}}},
596 {"envcache", {&envcache}, justset, NULL, {{true}, {false}}},
597 {"error_start", {func: &error_start_init}, isfunc, NULL, {{0}, {0}}},
598 {"export", {&export_settings}, justset, NULL, {{false}, {true}}},
599 {"forkchunk", {func: set_chunksize}, isfunc, NULL, {{0}, {0}}},
600 {"glob", {func: &glob_init}, isfunc, NULL, {{0}, {s: "normal"}}},
601 {"proc_retry", {func: set_proc_retry}, isfunc, NULL, {{0}, {5}}},
602 {"reset_com", {&reset_com}, justset, NULL, {{false}, {true}}},
603 {"strip_title", {&strip_title_path}, justset, NULL, {{false}, {true}}},
604 {"title", {&display_title}, justset, NULL, {{false}, {true}}},
605 {"tty", {NULL}, set_process_state, NULL, {{0}, {PID_USETTY}}},
606 {"upcaseenv", {&create_upcaseenv}, justset, NULL, {{false}, {true}}},
607 {"winsymlinks", {&allow_winsymlinks}, justset, NULL, {{false}, {true}}},
608 {NULL, {0}, justset, 0, {{0}, {0}}}
611 /* Parse a string of the form "something=stuff somethingelse=more-stuff",
612 silently ignoring unknown "somethings". */
613 static void __stdcall
614 parse_options (char *buf)
623 char *newbuf = tp.c_get ();
625 for (k = known; k->name != NULL; k++)
628 strcat (strcat (newbuf, " "), k->remember);
635 debug_printf ("%s", newbuf + 1);
636 setenv ("CYGWIN", newbuf + 1, 1);
641 buf = strcpy ((char *) alloca (strlen (buf) + 1), buf);
642 for (p = strtok_r (buf, " \t", &lasts);
644 p = strtok_r (NULL, " \t", &lasts))
646 char *keyword_here = p;
647 if (!(istrue = !ascii_strncasematch (p, "no", 2)))
649 else if (!(istrue = *p != '-'))
653 if ((eq = strchr (p, '=')) != NULL || (eq = strchr (p, ':')) != NULL)
654 ch = *eq, *eq++ = '\0';
658 for (parse_thing *k = known; k->name != NULL; k++)
659 if (ascii_strcasematch (p, k->name))
661 switch (k->disposition)
664 k->setting.func ((!eq || !istrue) ?
665 k->values[istrue].s : eq);
666 debug_printf ("%s (called func)", k->name);
670 *k->setting.x = k->values[istrue].i;
672 *k->setting.x = strtol (eq, NULL, 0);
673 debug_printf ("%s %d", k->name, *k->setting.x);
675 case set_process_state:
676 k->setting.x = &myself->process_state;
679 *k->setting.x &= ~k->values[istrue].i;
680 if (istrue || (eq && strtol (eq, NULL, 0)))
681 *k->setting.x |= k->values[istrue].i;
682 debug_printf ("%s %x", k->name, *k->setting.x);
690 p = strdup (keyword_here);
697 debug_printf ("returning");
700 /* Set options from the registry. */
701 static bool __stdcall
702 regopt (const WCHAR *name, char *buf)
704 bool parsed_something = false;
705 UNICODE_STRING lname;
706 size_t len = (wcslen(name) + 1) * sizeof (WCHAR);
707 RtlInitEmptyUnicodeString(&lname, (PWCHAR) alloca (len), len);
708 wcscpy(lname.Buffer, name);
709 RtlDowncaseUnicodeString(&lname, &lname, FALSE);
711 for (int i = 0; i < 2; i++)
713 reg_key r (i, KEY_READ, CYGWIN_INFO_PROGRAM_OPTIONS_NAME, NULL);
715 if (r.get_string (lname.Buffer, (PWCHAR) buf, NT_MAX_PATH, L"") == ERROR_SUCCESS)
718 sys_wcstombs_alloc(&newp, HEAP_NOTHEAP, (PWCHAR) buf);
721 parsed_something = true;
727 return parsed_something;
730 /* Initialize the environ array. Look for the CYGWIN environment
731 environment variable and set appropriate options from it. */
733 environ_init (char **envp, int envc)
741 bool got_something_from_registry;
742 static char NO_COPY cygterm[] = "TERM=cygwin";
746 if (efault.faulted ())
747 api_fatal ("internal error reading the windows environment - too many environment variables?");
749 if (!conv_start_chars[0])
750 for (int i = 0; conv_envvars[i].name != NULL; i++)
752 conv_start_chars[(int) cyg_tolower (conv_envvars[i].name[0])] = 1;
753 conv_start_chars[(int) cyg_toupper (conv_envvars[i].name[0])] = 1;
756 char *tmpbuf = tp.t_get ();
757 got_something_from_registry = regopt (L"default", tmpbuf);
758 if (myself->progname[0])
759 got_something_from_registry = regopt (myself->progname, tmpbuf)
760 || got_something_from_registry;
767 envc *= sizeof (char *);
768 char **newenv = (char **) malloc (envc);
769 memcpy (newenv, envp, envc);
772 /* Older applications relied on the fact that cygwin malloced elements of the
776 for (char **e = newenv; *e; e++)
786 /* Allocate space for environment + trailing NULL + CYGWIN env. */
787 lastenviron = envp = (char **) malloc ((4 + (envc = 100)) * sizeof (char *));
789 /* We also need the CYGWIN variable early to know the value of the
790 CYGWIN=upcaseenv setting for the below loop. */
791 if ((i = GetEnvironmentVariableA ("CYGWIN", NULL, 0)))
793 char *buf = (char *) alloca (i);
794 GetEnvironmentVariableA ("CYGWIN", buf, i);
798 rawenv = GetEnvironmentStringsW ();
801 system_printf ("GetEnvironmentStrings returned NULL, %E");
804 debug_printf ("GetEnvironmentStrings returned %p", rawenv);
806 /* Current directory information is recorded as variables of the
807 form "=X:=X:\foo\bar; these must be changed into something legal
808 (we could just ignore them but maybe an application will
809 eventually want to use them). */
810 for (i = 0, w = rawenv; *w != L'\0'; w = wcschr (w, L'\0') + 1, i++)
812 sys_wcstombs_alloc (&newp, HEAP_NOTHEAP, w);
814 envp = (char **) realloc (envp, (4 + (envc += 100)) * sizeof (char *));
818 char *eq = strechr (newp, '=');
819 ucenv (newp, eq); /* (possibly conditionally) uppercase env vars. */
820 if (*newp == 'T' && strncmp (newp, "TERM=", 5) == 0)
822 if (*eq && conv_start_chars[(unsigned char) envp[i][0]])
823 posify (envp + i, *++eq ? eq : --eq, tmpbuf);
824 debug_printf ("%p: %s", envp[i], envp[i]);
828 envp[i++] = strdup (cygterm);
830 FreeEnvironmentStringsW (rawenv);
833 findenv_func = (char * (*)(const char*, int*)) my_findenv;
834 __cygwin_environ = envp;
838 p = getenv ("CYGWIN");
843 if (got_something_from_registry)
844 parse_options (NULL); /* possibly export registry settings to
849 /* Function called by qsort to sort environment strings. */
851 env_sort (const void *a, const void *b)
853 const char **p = (const char **) a;
854 const char **q = (const char **) b;
856 return strcmp (*p, *q);
860 getwinenveq (const char *name, size_t namelen, int x)
862 WCHAR name0[namelen - 1];
863 WCHAR valbuf[32768]; /* Max size of an env.var including trailing '\0'. */
865 name0[sys_mbstowcs (name0, sizeof name0, name, namelen - 1)] = L'\0';
866 int totlen = GetEnvironmentVariableW (name0, valbuf, 32768);
869 totlen = sys_wcstombs (NULL, 0, valbuf);
874 char *p = (char *) cmalloc_abort ((cygheap_types) x, totlen);
877 sys_wcstombs (p + namelen, totlen, valbuf);
878 debug_printf ("using value from GetEnvironmentVariable for '%W'", name0);
882 debug_printf ("warning: %s not present in environment", name);
890 bool force_into_environment; /* If true, always add to env if missing */
891 bool add_if_exists; /* if true, retrieve value from cache */
892 const char * (cygheap_user::*from_cygheap) (const char *, size_t);
894 char *retrieve (bool, const char * const = NULL)
895 __attribute__ ((regparm (3)));
898 #define env_dontadd almost_null
900 /* Keep this list in upper case and sorted */
901 static NO_COPY spenv spenvs[] =
904 {NL ("CYGWIN_DEBUG="), false, true, NULL},
906 {NL ("HOMEDRIVE="), false, false, &cygheap_user::env_homedrive},
907 {NL ("HOMEPATH="), false, false, &cygheap_user::env_homepath},
908 {NL ("LOGONSERVER="), false, false, &cygheap_user::env_logsrv},
909 {NL ("PATH="), false, true, NULL},
910 {NL ("SYSTEMDRIVE="), false, true, NULL},
911 {NL ("SYSTEMROOT="), true, true, &cygheap_user::env_systemroot},
912 {NL ("USERDOMAIN="), false, false, &cygheap_user::env_domain},
913 {NL ("USERNAME="), false, false, &cygheap_user::env_name},
914 {NL ("USERPROFILE="), false, false, &cygheap_user::env_userprofile},
915 {NL ("WINDIR="), true, true, &cygheap_user::env_systemroot}
919 spenv::retrieve (bool no_envblock, const char *const env)
921 if (env && !ascii_strncasematch (env, name, namelen))
924 debug_printf ("no_envblock %d", no_envblock);
929 if (env && !cygheap->user.issetuid ())
931 debug_printf ("duping existing value for '%s'", name);
932 /* Don't really care what it's set to if we're calling a cygwin program */
933 return cstrdup1 (env);
936 /* Calculate (potentially) value for given environment variable. */
937 p = (cygheap->user.*from_cygheap) (name, namelen);
938 if (!p || (no_envblock && !env) || (p == env_dontadd))
940 char *s = (char *) cmalloc_abort (HEAP_1_STR, namelen + strlen (p) + 1);
942 strcpy (s + namelen, p);
943 debug_printf ("using computed value for '%s'", name);
948 return cstrdup1 (env);
950 return getwinenveq (name, namelen, HEAP_1_STR);
953 #define SPENVS_SIZE (sizeof (spenvs) / sizeof (spenvs[0]))
955 /* Create a Windows-style environment block, i.e. a typical character buffer
956 filled with null terminated strings, terminated by double null characters.
957 Converts environment variables noted in conv_envvars into win32 form
958 prior to placing them in the string. */
960 build_env (const char * const *envp, PWCHAR &envblock, int &envc,
964 const char * const *srcp;
966 bool saw_spenv[SPENVS_SIZE] = {0};
968 debug_printf ("envp %p", envp);
970 /* How many elements? */
971 for (n = 0; envp[n]; n++)
974 /* Allocate a new "argv-style" environ list with room for extra stuff. */
975 char **newenv = (char **) cmalloc_abort (HEAP_1_ARGV, sizeof (char *) *
976 (n + SPENVS_SIZE + 1));
980 char **pass_env = (char **) alloca (sizeof (char *) * (n + SPENVS_SIZE + 1));
981 /* Iterate over input list, generating a new environment list and refreshing
982 "special" entries, if necessary. */
983 for (srcp = envp, dstp = newenv, pass_dstp = pass_env; *srcp; srcp++)
985 bool calc_tl = !no_envblock;
986 /* Look for entries that require special attention */
987 for (unsigned i = 0; i < SPENVS_SIZE; i++)
988 if (!saw_spenv[i] && (*dstp = spenvs[i].retrieve (no_envblock, *srcp)))
991 if (*dstp == env_dontadd)
993 if (spenvs[i].add_if_exists)
998 /* Add entry to new environment */
999 *dstp = cstrdup1 (*srcp);
1004 *pass_dstp++ = *dstp;
1005 tl += strlen (*dstp) + 1;
1012 assert ((srcp - envp) == n);
1013 /* Fill in any required-but-missing environment variables. */
1014 for (unsigned i = 0; i < SPENVS_SIZE; i++)
1015 if (!saw_spenv[i] && (spenvs[i].force_into_environment || cygheap->user.issetuid ()))
1017 *dstp = spenvs[i].retrieve (false);
1018 if (*dstp && *dstp != env_dontadd)
1020 *pass_dstp++ = *dstp;
1021 tl += strlen (*dstp) + 1;
1026 envc = dstp - newenv; /* Number of entries in newenv */
1027 assert ((size_t) envc <= (n + SPENVS_SIZE));
1028 *dstp = NULL; /* Terminate */
1030 size_t pass_envc = pass_dstp - pass_env;
1036 debug_printf ("env count %d, bytes %d", pass_envc, tl);
1040 /* Windows programs expect the environment block to be sorted. */
1041 qsort (pass_env, pass_envc, sizeof (char *), env_sort);
1043 /* Create an environment block suitable for passing to CreateProcess. */
1045 envblock = (PWCHAR) malloc ((2 + tl) * sizeof (WCHAR));
1047 for (srcp = pass_env, s = envblock; *srcp; srcp++)
1051 len = strcspn (*srcp, "=") + 1;
1052 const char *rest = *srcp + len;
1054 /* Check for a bad entry. This is necessary to get rid of empty
1055 strings, induced by putenv and changing the string afterwards.
1056 Note that this doesn't stop invalid strings without '=' in it
1057 etc., but we're opting for speed here for now. Adding complete
1058 checking would be pretty expensive. */
1059 if (len == 1 || !*rest)
1062 /* See if this entry requires posix->win32 conversion. */
1063 conv = getwinenv (*srcp, rest, &temp);
1065 p = conv->native; /* Use win32 path */
1067 p = *srcp; /* Don't worry about it */
1069 len = sys_mbstowcs (NULL, 0, p);
1070 new_tl += len; /* Keep running total of block length so far */
1072 /* See if we need to increase the size of the block. */
1076 PWCHAR new_envblock =
1077 (PWCHAR) realloc (envblock, (2 + tl) * sizeof (WCHAR));
1078 /* If realloc moves the block, move `s' with it. */
1079 if (new_envblock != envblock)
1081 s += new_envblock - envblock;
1082 envblock = new_envblock;
1086 int slen = sys_mbstowcs (s, len, p);
1088 /* See if environment variable is "special" in a Windows sense.
1089 Under NT, the current directories for visited drives are stored
1090 as =C:=\bar. Cygwin converts the '=' to '!' for hopefully obvious
1091 reasons. We need to convert it back when building the envblock */
1092 if (s[0] == L'!' && (iswdrive (s + 1) || (s[1] == L':' && s[2] == L':'))
1097 *s = L'\0'; /* Two null bytes at the end */
1098 assert ((s - envblock) <= tl); /* Detect if we somehow ran over end
1102 debug_printf ("envp %p, envc %d", newenv, envc);
1106 /* This idiocy is necessary because the early implementers of cygwin
1107 did not seem to know about importing data variables from the DLL.
1108 So, we have to synchronize cygwin's idea of the environment with the
1109 main program's with each reference to the environment. */
1110 extern "C" char ** __stdcall
1113 if (*main_environ != __cygwin_environ)
1115 __cygwin_environ = *main_environ;
1119 return __cygwin_environ;