OSDN Git Service

d4e003f04d34df16ca271bc14e7d44b4c79e2dd3
[pf3gnuchains/pf3gnuchains4x.git] / winsup / cygwin / environ.cc
1 /* environ.cc: Cygwin-adopted functions from newlib to manipulate
2    process's environment.
3
4    Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
5    2006, 2007, 2008, 2009 Red Hat, Inc.
6
7 This software is a copyrighted work licensed under the terms of the
8 Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
9 details. */
10
11 #include "winsup.h"
12 #include <stdlib.h>
13 #include <wchar.h>
14 #include <wctype.h>
15 #include <ctype.h>
16 #include <locale.h>
17 #include <assert.h>
18 #include <cygwin/version.h>
19 #include <winnls.h>
20 #include "pinfo.h"
21 #include "perprocess.h"
22 #include "path.h"
23 #include "cygerrno.h"
24 #include "fhandler.h"
25 #include "dtable.h"
26 #include "cygheap.h"
27 #include "cygtls.h"
28 #include "tls_pbuf.h"
29 #include "registry.h"
30 #include "environ.h"
31 #include "child_info.h"
32
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;
39
40 static char **lastenviron;
41
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);
45
46 ssize_t
47 env_plist_to_posix (const void *win32, void *posix, size_t size)
48 {
49   return cygwin_conv_path_list (CCP_WIN_A_TO_POSIX | CCP_RELATIVE, win32,
50                                 posix, size);
51 }
52
53 ssize_t
54 env_plist_to_win32 (const void *posix, void *win32, size_t size)
55 {
56   return cygwin_conv_path_list (CCP_POSIX_TO_WIN_A | CCP_RELATIVE, posix,
57                                 win32, size);
58 }
59
60 ssize_t
61 env_path_to_posix (const void *win32, void *posix, size_t size)
62 {
63   return cygwin_conv_path (CCP_WIN_A_TO_POSIX | CCP_ABSOLUTE, win32,
64                            posix, size);
65 }
66
67 ssize_t
68 env_path_to_win32 (const void *posix, void *win32, size_t size)
69 {
70   return cygwin_conv_path (CCP_POSIX_TO_WIN_A | CCP_ABSOLUTE, posix,
71                            win32, size);
72 }
73
74 #define ENVMALLOC \
75   (CYGWIN_VERSION_DLL_MAKE_COMBINED (user_data->api_major, user_data->api_minor) \
76           <= CYGWIN_VERSION_DLL_MALLOC_ENV)
77
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.
81
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[] =
86   {
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}
95   };
96
97 static unsigned char conv_start_chars[256] = {0};
98
99 struct win_env&
100 win_env::operator = (struct win_env& x)
101 {
102   name = x.name;
103   namelen = x.namelen;
104   toposix = x.toposix;
105   towin32 = x.towin32;
106   immediate = false;
107   return *this;
108 }
109
110 win_env::~win_env ()
111 {
112   if (posix)
113     free (posix);
114   if (native)
115     free (native);
116 }
117
118 void
119 win_env::add_cache (const char *in_posix, const char *in_native)
120 {
121   MALLOC_CHECK;
122   posix = (char *) realloc (posix, strlen (in_posix) + 1);
123   strcpy (posix, in_posix);
124   if (in_native)
125     {
126       native = (char *) realloc (native, namelen + 1 + strlen (in_native));
127       strcpy (native, name);
128       strcpy (native + namelen, in_native);
129     }
130   else
131     {
132       tmp_pathbuf tp;
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);
139     }
140   MALLOC_CHECK;
141   if (immediate && cygwin_finished_initializing)
142     {
143       char s[namelen];
144       size_t n = namelen - 1;
145       memcpy (s, name, n);
146       s[n] = '\0';
147       SetEnvironmentVariable (s, native + namelen);
148     }
149   debug_printf ("posix %s", posix);
150   debug_printf ("native %s", native);
151 }
152
153
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.  */
158 win_env * __stdcall
159 getwinenv (const char *env, const char *in_posix, win_env *temp)
160 {
161   if (!conv_start_chars[(unsigned char)*env])
162     return NULL;
163
164   for (int i = 0; conv_envvars[i].name != NULL; i++)
165     if (strncmp (env, conv_envvars[i].name, conv_envvars[i].namelen) == 0)
166       {
167         win_env *we = conv_envvars + i;
168         const char *val;
169         if (!cur_environ () || !(val = in_posix ?: getenv (we->name)))
170           debug_printf ("can't set native for %s since no environ yet",
171                         we->name);
172         else if (!envcache || !we->posix || strcmp (val, we->posix) != 0)
173           {
174             if (temp)
175               {
176                 *temp = *we;
177                 we = temp;
178               }
179             we->add_cache (val);
180           }
181         return we;
182       }
183   return NULL;
184 }
185
186 /* Convert windows path specs to POSIX, if appropriate.
187  */
188 static void __stdcall
189 posify (char **here, const char *value, char *outenv)
190 {
191   char *src = *here;
192   win_env *conv;
193
194   if (!(conv = getwinenv (src)))
195     return;
196
197   int len = strcspn (src, "=") + 1;
198
199   /* Turn all the items from c:<foo>;<bar> into their
200      mounted equivalents - if there is one.  */
201
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);
207   else
208     {
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);
214     }
215
216   debug_printf ("env var converted to %s", outenv);
217   *here = strdup (outenv);
218   free (src);
219   MALLOC_CHECK;
220 }
221
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.  */
226
227 static char * __stdcall
228 my_findenv (const char *name, int *offset)
229 {
230   register int len;
231   register char **p;
232   const char *c;
233
234   c = name;
235   len = 0;
236   while (*c && *c != '=')
237     {
238       c++;
239       len++;
240     }
241
242   for (p = cur_environ (); *p; ++p)
243     if (!strncmp (*p, name, len))
244       if (*(c = *p + len) == '=')
245         {
246           *offset = p - cur_environ ();
247           return (char *) (++c);
248         }
249   MALLOC_CHECK;
250   return NULL;
251 }
252
253 /* Primitive getenv before the environment is built.  */
254
255 static char __stdcall *
256 getearly (const char * name, int *)
257 {
258   char *ret;
259   char **ptr;
260   int len;
261
262   if (spawn_info && (ptr = spawn_info->moreinfo->envp))
263     {
264       len = strlen (name);
265       for (; *ptr; ptr++)
266         if (strncasematch (name, *ptr, len) && (*ptr)[len] == '=')
267           return *ptr + len + 1;
268     }
269   else if ((len = GetEnvironmentVariableA (name, NULL, 0))
270            && (ret = (char *) cmalloc_abort (HEAP_2_STR, len))
271            && GetEnvironmentVariableA (name, ret, len))
272     return ret;
273
274   return NULL;
275 }
276
277 static char * (*findenv_func)(const char *, int *) = (char * (*)(const char *, int *)) getearly;
278
279 /* Returns ptr to value associated with name, if any, else NULL.  */
280
281 extern "C" char *
282 getenv (const char *name)
283 {
284   int offset;
285   return findenv_func (name, &offset);
286 }
287
288 /* This function is required so that newlib uses the same environment
289    as Cygwin. */
290 extern "C" char *
291 _getenv_r (struct _reent *, const char *name)
292 {
293   int offset;
294   return findenv_func (name, &offset);
295 }
296
297 static int __stdcall
298 envsize (const char * const *in_envp)
299 {
300   const char * const *envp;
301   for (envp = in_envp; *envp; envp++)
302     continue;
303   return (1 + envp - in_envp) * sizeof (const char *);
304 }
305
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. */
309 static int __stdcall
310 _addenv (const char *name, const char *value, int overwrite)
311 {
312   int issetenv = overwrite >= 0;
313   int offset;
314   char *p;
315
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? */
321
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)
326         {
327           strcpy (p, value);
328           return 0;
329         }
330     }
331   else
332     {                           /* Create new slot. */
333       int sz = envsize (cur_environ ());
334       int allocsz = sz + (2 * sizeof (char *));
335
336       offset = (sz - 1) / sizeof (char *);
337
338       /* Allocate space for additional element plus terminating NULL. */
339       if (cur_environ () == lastenviron)
340         lastenviron = __cygwin_environ = (char **) realloc (cur_environ (),
341                                                             allocsz);
342       else if ((lastenviron = (char **) malloc (allocsz)) != NULL)
343         __cygwin_environ = (char **) memcpy ((char **) lastenviron,
344                                              __cygwin_environ, sz);
345
346       if (!__cygwin_environ)
347         {
348 #ifdef DEBUGGING
349           try_to_debug ();
350 #endif
351           return -1;                            /* Oops.  No more memory. */
352         }
353
354       __cygwin_environ[offset + 1] = NULL;      /* NULL terminate. */
355       update_envptrs ();        /* Update any local copies of 'environ'. */
356     }
357
358   char *envhere;
359   if (!issetenv)
360     /* Not setenv. Just overwrite existing. */
361     envhere = cur_environ ()[offset] = (char *) (ENVMALLOC ? strdup (name) : name);
362   else
363     {                           /* setenv */
364       /* Look for an '=' in the name and ignore anything after that if found. */
365       for (p = (char *) name; *p && *p != '='; p++)
366         continue;
367
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);
371       if (!envhere)
372         return -1;              /* Oops.  No more memory. */
373
374       /* Put name '=' value into current slot. */
375       strncpy (envhere, name, namelen);
376       envhere[namelen] = '=';
377       strcpy (envhere + namelen + 1, value);
378     }
379
380   /* Update cygwin's cache, if appropriate */
381   win_env *spenv;
382   if ((spenv = getwinenv (envhere)))
383     spenv->add_cache (value);
384
385   MALLOC_CHECK;
386   return 0;
387 }
388
389 /* Set an environment variable */
390 extern "C" int
391 putenv (char *str)
392 {
393   myfault efault;
394   if (efault.faulted (EFAULT))
395     return -1;
396   if (*str)
397     {
398       char *eq = strchr (str, '=');
399       if (eq)
400         return _addenv (str, eq + 1, -1);
401
402       /* Remove str from the environment. */
403       unsetenv (str);
404     }
405   return 0;
406 }
407
408 /* Set the value of the environment variable "name" to be
409    "value".  If overwrite is set, replace any current value.  */
410 extern "C" int
411 setenv (const char *name, const char *value, int overwrite)
412 {
413   myfault efault;
414   if (efault.faulted (EFAULT))
415     return -1;
416   if (!*name)
417     return 0;
418   if (*value == '=')
419     value++;
420   return _addenv (name, value, !!overwrite);
421 }
422
423 /* Delete environment variable "name".  */
424 extern "C" int
425 unsetenv (const char *name)
426 {
427   register char **e;
428   int offset;
429   myfault efault;
430   if (efault.faulted () || *name == '\0' || strchr (name, '='))
431     {
432       set_errno (EINVAL);
433       return -1;
434     }
435
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)))
440         break;
441
442   return 0;
443 }
444
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. */
448 static struct renv {
449         const char *name;
450         const size_t namelen;
451 } renv_arr[] = {
452         { NL("ALLUSERSPROFILE=") },             // 0
453         { NL("COMMONPROGRAMFILES=") },          // 1
454         { NL("COMPUTERNAME=") },
455         { NL("COMSPEC=") },
456         { NL("HOME=") },                        // 4
457         { NL("HOMEDRIVE=") },
458         { NL("HOMEPATH=") },
459         { NL("NUMBER_OF_PROCESSORS=") },        // 7
460         { NL("OS=") },                          // 8
461         { NL("PATH=") },                        // 9
462         { NL("PATHEXT=") },
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
471         { NL("TERM=") },
472         { NL("TMP=") },
473         { NL("TMPDIR=") },
474         { NL("WINDIR=") }                       // 22
475 };
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
480    starts. */
481 static const int start_at[] = { 0, 1, 4, 7, 8, 9, 16, 18, 22 };
482
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)
487 {
488   if (create_upcaseenv)
489     {
490       /* Amazingly, NT has a case sensitive environment name list,
491          but only sometimes.
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.
495
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. */
498       for (; p < eq; p++)
499         if (islower (*p))
500           *p = cyg_toupper (*p);
501     }
502   else
503     {
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);
508       if (idx)
509         for (size_t i = start_at[idx - idx_arr];
510              i < RENV_SIZE && renv_arr[i].name[0] == first;
511              ++i)
512           if (strncasematch (p, renv_arr[i].name, renv_arr[i].namelen))
513             {
514               strncpy (p, renv_arr[i].name, renv_arr[i].namelen);
515               break;
516             }
517     }
518 }
519
520 /* Parse CYGWIN options */
521
522 static NO_COPY bool export_settings = false;
523
524 enum settings
525   {
526     justset,
527     isfunc,
528     setbit,
529     set_process_state,
530   };
531
532 /* When BUF is:
533    null or empty: disables globbing
534    "ignorecase": enables case-insensitive globbing
535    anything else: enables case-sensitive globbing */
536 static void
537 glob_init (const char *buf)
538 {
539   if (!buf || !*buf)
540     {
541       allow_glob = false;
542       ignore_case_with_glob = false;
543     }
544   else if (ascii_strncasematch (buf, "ignorecase", 10))
545     {
546       allow_glob = true;
547       ignore_case_with_glob = true;
548     }
549   else
550     {
551       allow_glob = true;
552       ignore_case_with_glob = false;
553     }
554 }
555
556 static void
557 set_chunksize (const char *buf)
558 {
559   wincap.set_chunksize (strtoul (buf, NULL, 0));
560 }
561
562 static void
563 set_proc_retry (const char *buf)
564 {
565   child_info::retry_count = strtoul (buf, NULL, 0);
566 }
567
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
570    the registry.  */
571 static struct parse_thing
572   {
573     const char *name;
574     union parse_setting
575       {
576         bool *b;
577         DWORD *x;
578         int *i;
579         void (*func)(const char *);
580       } setting;
581
582     enum settings disposition;
583     char *remember;
584     union parse_values
585       {
586         DWORD i;
587         const char *s;
588       } values[2];
589   } known[] NO_COPY =
590 {
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}}}
605 };
606
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)
611 {
612   int istrue;
613   char *p, *lasts;
614   parse_thing *k;
615
616   if (buf == NULL)
617     {
618       tmp_pathbuf tp;
619       char *newbuf = tp.c_get ();
620       newbuf[0] = '\0';
621       for (k = known; k->name != NULL; k++)
622         if (k->remember)
623           {
624             strcat (strcat (newbuf, " "), k->remember);
625             free (k->remember);
626             k->remember = NULL;
627           }
628
629       if (export_settings)
630         {
631           debug_printf ("%s", newbuf + 1);
632           setenv ("CYGWIN", newbuf + 1, 1);
633         }
634       return;
635     }
636
637   buf = strcpy ((char *) alloca (strlen (buf) + 1), buf);
638   for (p = strtok_r (buf, " \t", &lasts);
639        p != NULL;
640        p = strtok_r (NULL, " \t", &lasts))
641     {
642       char *keyword_here = p;
643       if (!(istrue = !ascii_strncasematch (p, "no", 2)))
644         p += 2;
645       else if (!(istrue = *p != '-'))
646         p++;
647
648       char ch, *eq;
649       if ((eq = strchr (p, '=')) != NULL || (eq = strchr (p, ':')) != NULL)
650         ch = *eq, *eq++ = '\0';
651       else
652         ch = 0;
653
654       for (parse_thing *k = known; k->name != NULL; k++)
655         if (ascii_strcasematch (p, k->name))
656           {
657             switch (k->disposition)
658               {
659               case isfunc:
660                 k->setting.func ((!eq || !istrue) ?
661                   k->values[istrue].s : eq);
662                 debug_printf ("%s (called func)", k->name);
663                 break;
664               case justset:
665                 if (!istrue || !eq)
666                   *k->setting.x = k->values[istrue].i;
667                 else
668                   *k->setting.x = strtol (eq, NULL, 0);
669                 debug_printf ("%s %d", k->name, *k->setting.x);
670                 break;
671               case set_process_state:
672                 k->setting.x = &myself->process_state;
673                 /* fall through */
674               case setbit:
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);
679                 break;
680               }
681
682             if (eq)
683               *--eq = ch;
684
685             int n = eq - p;
686             p = strdup (keyword_here);
687             if (n > 0)
688               p[n] = ':';
689             k->remember = p;
690             break;
691           }
692       }
693   debug_printf ("returning");
694 }
695
696 /* Set options from the registry. */
697 static bool __stdcall
698 regopt (const char *name, char *buf)
699 {
700   bool parsed_something = false;
701   char lname[strlen (name) + 1];
702   strlwr (strcpy (lname, name));
703
704   for (int i = 0; i < 2; i++)
705     {
706       reg_key r (i, KEY_READ, CYGWIN_INFO_PROGRAM_OPTIONS_NAME, NULL);
707
708       if (r.get_string (lname, buf, NT_MAX_PATH, "") == ERROR_SUCCESS)
709         {
710           parse_options (buf);
711           parsed_something = true;
712           break;
713         }
714     }
715
716   MALLOC_CHECK;
717   return parsed_something;
718 }
719
720 /* Initialize the environ array.  Look for the CYGWIN environment
721    environment variable and set appropriate options from it.  */
722 void
723 environ_init (char **envp, int envc)
724 {
725   PWCHAR rawenv, w;
726   int i;
727   char *p;
728   char *newp;
729   int sawTERM = 0;
730   bool envp_passed_in;
731   bool got_something_from_registry;
732   static char NO_COPY cygterm[] = "TERM=cygwin";
733   myfault efault;
734   tmp_pathbuf tp;
735   static const char *lc_arr[] = { "LC_ALL", "LC_CTYPE", "LANG", NULL };
736
737   if (efault.faulted ())
738     api_fatal ("internal error reading the windows environment - too many environment variables?");
739
740   if (!conv_start_chars[0])
741     for (int i = 0; conv_envvars[i].name != NULL; i++)
742       {
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;
745       }
746
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;
752
753   if (!envp)
754     envp_passed_in = 0;
755   else
756     {
757       envc++;
758       envc *= sizeof (char *);
759       char **newenv = (char **) malloc (envc);
760       memcpy (newenv, envp, envc);
761       cfree (envp);
762
763       /* Older applications relied on the fact that cygwin malloced elements of the
764          environment list.  */
765       envp = newenv;
766       if (ENVMALLOC)
767         for (char **e = newenv; *e; e++)
768           {
769             char *p = *e;
770             *e = strdup (p);
771             cfree (p);
772           }
773       envp_passed_in = 1;
774       goto out;
775     }
776
777   /* Allocate space for environment + trailing NULL + CYGWIN env. */
778   lastenviron = envp = (char **) malloc ((4 + (envc = 100)) * sizeof (char *));
779
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)
787     {
788       if ((i = GetEnvironmentVariableA (lc_arr[lc], NULL, 0)))
789         {
790           char *buf = (char *) alloca (i);
791           GetEnvironmentVariableA (lc_arr[lc], buf, i);
792           if (setlocale (LC_CTYPE, buf))
793             break;
794         }
795     }
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)))
799     {
800       char *buf = (char *) alloca (i);
801       GetEnvironmentVariableA ("CYGWIN", buf, i);
802       parse_options (buf);
803     }
804
805   rawenv = GetEnvironmentStringsW ();
806   if (!rawenv)
807     {
808       system_printf ("GetEnvironmentStrings returned NULL, %E");
809       return;
810     }
811   debug_printf ("GetEnvironmentStrings returned %p", rawenv);
812
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++)
818     {
819       sys_wcstombs_alloc (&newp, HEAP_NOTHEAP, w);
820       if (i >= envc)
821         envp = (char **) realloc (envp, (4 + (envc += 100)) * sizeof (char *));
822       envp[i] = newp;
823       if (*newp == '=')
824         *newp = '!';
825       char *eq = strechr (newp, '=');
826       ucenv (newp, eq); /* (possibly conditionally) uppercase env vars. */
827       if (*newp == 'T' && strncmp (newp, "TERM=", 5) == 0)
828         sawTERM = 1;
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]);
832     }
833
834   if (!sawTERM)
835     envp[i++] = strdup (cygterm);
836   envp[i] = NULL;
837   FreeEnvironmentStringsW (rawenv);
838
839 out:
840   findenv_func = (char * (*)(const char*, int*)) my_findenv;
841   __cygwin_environ = envp;
842   update_envptrs ();
843   if (envp_passed_in)
844     {
845       p = getenv ("CYGWIN");
846       if (p)
847         parse_options (p);
848     }
849
850   if (got_something_from_registry)
851     parse_options (NULL);       /* possibly export registry settings to
852                                    environment */
853   MALLOC_CHECK;
854 }
855
856 /* Function called by qsort to sort environment strings.  */
857 static int
858 env_sort (const void *a, const void *b)
859 {
860   const char **p = (const char **) a;
861   const char **q = (const char **) b;
862
863   return strcmp (*p, *q);
864 }
865
866 char * __stdcall
867 getwinenveq (const char *name, size_t namelen, int x)
868 {
869   WCHAR name0[namelen - 1];
870   WCHAR valbuf[32768]; /* Max size of an env.var including trailing '\0'. */
871
872   name0[sys_mbstowcs (name0, sizeof name0, name, namelen - 1)] = L'\0';
873   int totlen = GetEnvironmentVariableW (name0, valbuf, 32768);
874   if (totlen > 0)
875     {
876       totlen = sys_wcstombs (NULL, 0, valbuf);
877       if (x == HEAP_1_STR)
878         totlen += namelen;
879       else
880         namelen = 0;
881       char *p = (char *) cmalloc_abort ((cygheap_types) x, totlen);
882       if (namelen)
883         strcpy (p, name);
884       sys_wcstombs (p + namelen, totlen, valbuf);
885       debug_printf ("using value from GetEnvironmentVariable for '%W'", name0);
886       return p;
887     }
888
889   debug_printf ("warning: %s not present in environment", name);
890   return NULL;
891 }
892
893 struct spenv
894 {
895   const char *name;
896   size_t namelen;
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);
900
901   char *retrieve (bool, const char * const = NULL)
902     __attribute__ ((regparm (3)));
903 };
904
905 #define env_dontadd almost_null
906
907 /* Keep this list in upper case and sorted */
908 static NO_COPY spenv spenvs[] =
909 {
910 #ifdef DEBUGGING
911   {NL ("CYGWIN_DEBUG="), false, true, NULL},
912 #endif
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}
923 };
924
925 char *
926 spenv::retrieve (bool no_envblock, const char *const env)
927 {
928   if (env && !ascii_strncasematch (env, name, namelen))
929     return NULL;
930
931   debug_printf ("no_envblock %d", no_envblock);
932
933   if (from_cygheap)
934     {
935       const char *p;
936       if (env && !cygheap->user.issetuid ())
937         {
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);
941         }
942
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))
946         return env_dontadd;
947       char *s = (char *) cmalloc_abort (HEAP_1_STR, namelen + strlen (p) + 1);
948       strcpy (s, name);
949       strcpy (s + namelen, p);
950       debug_printf ("using computed value for '%s'", name);
951       return s;
952     }
953
954   if (env)
955     return cstrdup1 (env);
956
957   return getwinenveq (name, namelen, HEAP_1_STR);
958 }
959
960 #define SPENVS_SIZE (sizeof (spenvs) / sizeof (spenvs[0]))
961
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.  */
966 char ** __stdcall
967 build_env (const char * const *envp, PWCHAR &envblock, int &envc,
968            bool no_envblock)
969 {
970   int len, n;
971   const char * const *srcp;
972   char **dstp;
973   bool saw_spenv[SPENVS_SIZE] = {0};
974
975   debug_printf ("envp %p", envp);
976
977   /* How many elements? */
978   for (n = 0; envp[n]; n++)
979     continue;
980
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));
984
985   int tl = 0;
986   char **pass_dstp;
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++)
991     {
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)))
996           {
997             saw_spenv[i] = 1;
998             if (*dstp == env_dontadd)
999               goto next1;
1000             if (spenvs[i].add_if_exists)
1001               calc_tl = true;
1002             goto  next0;
1003           }
1004
1005       /* Add entry to new environment */
1006       *dstp = cstrdup1 (*srcp);
1007
1008     next0:
1009       if (calc_tl)
1010         {
1011           *pass_dstp++ = *dstp;
1012           tl += strlen (*dstp) + 1;
1013         }
1014       dstp++;
1015     next1:
1016       continue;
1017     }
1018
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 ()))
1023       {
1024           *dstp = spenvs[i].retrieve (false);
1025           if (*dstp && *dstp != env_dontadd)
1026             {
1027               *pass_dstp++ = *dstp;
1028               tl += strlen (*dstp) + 1;
1029               dstp++;
1030             }
1031         }
1032
1033   envc = dstp - newenv;         /* Number of entries in newenv */
1034   assert ((size_t) envc <= (n + SPENVS_SIZE));
1035   *dstp = NULL;                 /* Terminate */
1036
1037   size_t pass_envc = pass_dstp - pass_env;
1038   if (!pass_envc)
1039     envblock = NULL;
1040   else
1041     {
1042       *pass_dstp = NULL;
1043       debug_printf ("env count %d, bytes %d", pass_envc, tl);
1044       win_env temp;
1045       temp.reset ();
1046
1047       /* Windows programs expect the environment block to be sorted.  */
1048       qsort (pass_env, pass_envc, sizeof (char *), env_sort);
1049
1050       /* Create an environment block suitable for passing to CreateProcess.  */
1051       PWCHAR s;
1052       envblock = (PWCHAR) malloc ((2 + tl) * sizeof (WCHAR));
1053       int new_tl = 0;
1054       for (srcp = pass_env, s = envblock; *srcp; srcp++)
1055         {
1056           const char *p;
1057           win_env *conv;
1058           len = strcspn (*srcp, "=") + 1;
1059           const char *rest = *srcp + len;
1060
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)
1067             continue;
1068
1069           /* See if this entry requires posix->win32 conversion. */
1070           conv = getwinenv (*srcp, rest, &temp);
1071           if (conv)
1072             p = conv->native;   /* Use win32 path */
1073           else
1074             p = *srcp;          /* Don't worry about it */
1075
1076           len = sys_mbstowcs (NULL, 0, p);
1077           new_tl += len;        /* Keep running total of block length so far */
1078
1079           /* See if we need to increase the size of the block. */
1080           if (new_tl > tl)
1081             {
1082               tl = new_tl + 100;
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)
1087                 {
1088                   s += new_envblock - envblock;
1089                   envblock = new_envblock;
1090                 }
1091             }
1092
1093           int slen = sys_mbstowcs (s, len, p);
1094
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':'))
1100               && s[3] == L'=')
1101             *s = L'=';
1102           s += slen + 1;
1103         }
1104       *s = L'\0';                       /* Two null bytes at the end */
1105       assert ((s - envblock) <= tl);    /* Detect if we somehow ran over end
1106                                            of buffer */
1107     }
1108
1109   debug_printf ("envp %p, envc %d", newenv, envc);
1110   return newenv;
1111 }
1112
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
1118 cur_environ ()
1119 {
1120   if (*main_environ != __cygwin_environ)
1121     {
1122       __cygwin_environ = *main_environ;
1123       update_envptrs ();
1124     }
1125
1126   return __cygwin_environ;
1127 }