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";
736 if (efault.faulted ())
737 api_fatal ("internal error reading the windows environment - too many environment variables?");
739 if (!conv_start_chars[0])
740 for (int i = 0; conv_envvars[i].name != NULL; i++)
742 conv_start_chars[(int) cyg_tolower (conv_envvars[i].name[0])] = 1;
743 conv_start_chars[(int) cyg_toupper (conv_envvars[i].name[0])] = 1;
746 char *tmpbuf = tp.t_get ();
747 got_something_from_registry = regopt ("default", tmpbuf);
748 if (myself->progname[0])
749 got_something_from_registry = regopt (myself->progname, tmpbuf)
750 || got_something_from_registry;
757 envc *= sizeof (char *);
758 char **newenv = (char **) malloc (envc);
759 memcpy (newenv, envp, envc);
762 /* Older applications relied on the fact that cygwin malloced elements of the
766 for (char **e = newenv; *e; e++)
776 /* Allocate space for environment + trailing NULL + CYGWIN env. */
777 lastenviron = envp = (char **) malloc ((4 + (envc = 100)) * sizeof (char *));
779 /* We also need the CYGWIN variable early to know the value of the
780 CYGWIN=upcaseenv setting for the below loop. */
781 if ((i = GetEnvironmentVariableA ("CYGWIN", NULL, 0)))
783 char *buf = (char *) alloca (i);
784 GetEnvironmentVariableA ("CYGWIN", buf, i);
788 rawenv = GetEnvironmentStringsW ();
791 system_printf ("GetEnvironmentStrings returned NULL, %E");
794 debug_printf ("GetEnvironmentStrings returned %p", rawenv);
796 /* Current directory information is recorded as variables of the
797 form "=X:=X:\foo\bar; these must be changed into something legal
798 (we could just ignore them but maybe an application will
799 eventually want to use them). */
800 for (i = 0, w = rawenv; *w != L'\0'; w = wcschr (w, L'\0') + 1, i++)
802 sys_wcstombs_alloc (&newp, HEAP_NOTHEAP, w);
804 envp = (char **) realloc (envp, (4 + (envc += 100)) * sizeof (char *));
808 char *eq = strechr (newp, '=');
809 ucenv (newp, eq); /* (possibly conditionally) uppercase env vars. */
810 if (*newp == 'T' && strncmp (newp, "TERM=", 5) == 0)
812 if (*eq && conv_start_chars[(unsigned char) envp[i][0]])
813 posify (envp + i, *++eq ? eq : --eq, tmpbuf);
814 debug_printf ("%p: %s", envp[i], envp[i]);
818 envp[i++] = strdup (cygterm);
820 FreeEnvironmentStringsW (rawenv);
823 findenv_func = (char * (*)(const char*, int*)) my_findenv;
824 __cygwin_environ = envp;
828 p = getenv ("CYGWIN");
833 if (got_something_from_registry)
834 parse_options (NULL); /* possibly export registry settings to
839 /* Function called by qsort to sort environment strings. */
841 env_sort (const void *a, const void *b)
843 const char **p = (const char **) a;
844 const char **q = (const char **) b;
846 return strcmp (*p, *q);
850 getwinenveq (const char *name, size_t namelen, int x)
852 WCHAR name0[namelen - 1];
853 WCHAR valbuf[32768]; /* Max size of an env.var including trailing '\0'. */
855 name0[sys_mbstowcs (name0, sizeof name0, name, namelen - 1)] = L'\0';
856 int totlen = GetEnvironmentVariableW (name0, valbuf, 32768);
859 totlen = sys_wcstombs (NULL, 0, valbuf);
864 char *p = (char *) cmalloc_abort ((cygheap_types) x, totlen);
867 sys_wcstombs (p + namelen, totlen, valbuf);
868 debug_printf ("using value from GetEnvironmentVariable for '%W'", name0);
872 debug_printf ("warning: %s not present in environment", name);
880 bool force_into_environment; /* If true, always add to env if missing */
881 bool add_if_exists; /* if true, retrieve value from cache */
882 const char * (cygheap_user::*from_cygheap) (const char *, size_t);
884 char *retrieve (bool, const char * const = NULL)
885 __attribute__ ((regparm (3)));
888 #define env_dontadd almost_null
890 /* Keep this list in upper case and sorted */
891 static NO_COPY spenv spenvs[] =
894 {NL ("CYGWIN_DEBUG="), false, true, NULL},
896 {NL ("HOMEDRIVE="), false, false, &cygheap_user::env_homedrive},
897 {NL ("HOMEPATH="), false, false, &cygheap_user::env_homepath},
898 {NL ("LOGONSERVER="), false, false, &cygheap_user::env_logsrv},
899 {NL ("PATH="), false, true, NULL},
900 {NL ("SYSTEMDRIVE="), false, true, NULL},
901 {NL ("SYSTEMROOT="), true, true, &cygheap_user::env_systemroot},
902 {NL ("USERDOMAIN="), false, false, &cygheap_user::env_domain},
903 {NL ("USERNAME="), false, false, &cygheap_user::env_name},
904 {NL ("USERPROFILE="), false, false, &cygheap_user::env_userprofile},
905 {NL ("WINDIR="), true, true, &cygheap_user::env_systemroot}
909 spenv::retrieve (bool no_envblock, const char *const env)
911 if (env && !ascii_strncasematch (env, name, namelen))
914 debug_printf ("no_envblock %d", no_envblock);
919 if (env && !cygheap->user.issetuid ())
921 debug_printf ("duping existing value for '%s'", name);
922 /* Don't really care what it's set to if we're calling a cygwin program */
923 return cstrdup1 (env);
926 /* Calculate (potentially) value for given environment variable. */
927 p = (cygheap->user.*from_cygheap) (name, namelen);
928 if (!p || (no_envblock && !env) || (p == env_dontadd))
930 char *s = (char *) cmalloc_abort (HEAP_1_STR, namelen + strlen (p) + 1);
932 strcpy (s + namelen, p);
933 debug_printf ("using computed value for '%s'", name);
938 return cstrdup1 (env);
940 return getwinenveq (name, namelen, HEAP_1_STR);
943 #define SPENVS_SIZE (sizeof (spenvs) / sizeof (spenvs[0]))
945 /* Create a Windows-style environment block, i.e. a typical character buffer
946 filled with null terminated strings, terminated by double null characters.
947 Converts environment variables noted in conv_envvars into win32 form
948 prior to placing them in the string. */
950 build_env (const char * const *envp, PWCHAR &envblock, int &envc,
954 const char * const *srcp;
956 bool saw_spenv[SPENVS_SIZE] = {0};
958 debug_printf ("envp %p", envp);
960 /* How many elements? */
961 for (n = 0; envp[n]; n++)
964 /* Allocate a new "argv-style" environ list with room for extra stuff. */
965 char **newenv = (char **) cmalloc_abort (HEAP_1_ARGV, sizeof (char *) *
966 (n + SPENVS_SIZE + 1));
970 char **pass_env = (char **) alloca (sizeof (char *) * (n + SPENVS_SIZE + 1));
971 /* Iterate over input list, generating a new environment list and refreshing
972 "special" entries, if necessary. */
973 for (srcp = envp, dstp = newenv, pass_dstp = pass_env; *srcp; srcp++)
975 bool calc_tl = !no_envblock;
976 /* Look for entries that require special attention */
977 for (unsigned i = 0; i < SPENVS_SIZE; i++)
978 if (!saw_spenv[i] && (*dstp = spenvs[i].retrieve (no_envblock, *srcp)))
981 if (*dstp == env_dontadd)
983 if (spenvs[i].add_if_exists)
988 /* Add entry to new environment */
989 *dstp = cstrdup1 (*srcp);
994 *pass_dstp++ = *dstp;
995 tl += strlen (*dstp) + 1;
1002 assert ((srcp - envp) == n);
1003 /* Fill in any required-but-missing environment variables. */
1004 for (unsigned i = 0; i < SPENVS_SIZE; i++)
1005 if (!saw_spenv[i] && (spenvs[i].force_into_environment || cygheap->user.issetuid ()))
1007 *dstp = spenvs[i].retrieve (false);
1008 if (*dstp && *dstp != env_dontadd)
1010 *pass_dstp++ = *dstp;
1011 tl += strlen (*dstp) + 1;
1016 envc = dstp - newenv; /* Number of entries in newenv */
1017 assert ((size_t) envc <= (n + SPENVS_SIZE));
1018 *dstp = NULL; /* Terminate */
1020 size_t pass_envc = pass_dstp - pass_env;
1026 debug_printf ("env count %d, bytes %d", pass_envc, tl);
1030 /* Windows programs expect the environment block to be sorted. */
1031 qsort (pass_env, pass_envc, sizeof (char *), env_sort);
1033 /* Create an environment block suitable for passing to CreateProcess. */
1035 envblock = (PWCHAR) malloc ((2 + tl) * sizeof (WCHAR));
1037 for (srcp = pass_env, s = envblock; *srcp; srcp++)
1041 len = strcspn (*srcp, "=") + 1;
1042 const char *rest = *srcp + len;
1044 /* Check for a bad entry. This is necessary to get rid of empty
1045 strings, induced by putenv and changing the string afterwards.
1046 Note that this doesn't stop invalid strings without '=' in it
1047 etc., but we're opting for speed here for now. Adding complete
1048 checking would be pretty expensive. */
1049 if (len == 1 || !*rest)
1052 /* See if this entry requires posix->win32 conversion. */
1053 conv = getwinenv (*srcp, rest, &temp);
1055 p = conv->native; /* Use win32 path */
1057 p = *srcp; /* Don't worry about it */
1059 len = sys_mbstowcs (NULL, 0, p);
1060 new_tl += len; /* Keep running total of block length so far */
1062 /* See if we need to increase the size of the block. */
1066 PWCHAR new_envblock =
1067 (PWCHAR) realloc (envblock, (2 + tl) * sizeof (WCHAR));
1068 /* If realloc moves the block, move `s' with it. */
1069 if (new_envblock != envblock)
1071 s += new_envblock - envblock;
1072 envblock = new_envblock;
1076 int slen = sys_mbstowcs (s, len, p);
1078 /* See if environment variable is "special" in a Windows sense.
1079 Under NT, the current directories for visited drives are stored
1080 as =C:=\bar. Cygwin converts the '=' to '!' for hopefully obvious
1081 reasons. We need to convert it back when building the envblock */
1082 if (s[0] == L'!' && (iswdrive (s + 1) || (s[1] == L':' && s[2] == L':'))
1087 *s = L'\0'; /* Two null bytes at the end */
1088 assert ((s - envblock) <= tl); /* Detect if we somehow ran over end
1092 debug_printf ("envp %p, envc %d", newenv, envc);
1096 /* This idiocy is necessary because the early implementers of cygwin
1097 did not seem to know about importing data variables from the DLL.
1098 So, we have to synchronize cygwin's idea of the environment with the
1099 main program's with each reference to the environment. */
1100 extern "C" char ** __stdcall
1103 if (*main_environ != __cygwin_environ)
1105 __cygwin_environ = *main_environ;
1109 return __cygwin_environ;