OSDN Git Service

gas/opcodes: blackfin: move dsp mac func defines to common header
[pf3gnuchains/sourceware.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 #include "ntdll.h"
33
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;
40
41 static char **lastenviron;
42
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);
46
47 ssize_t
48 env_plist_to_posix (const void *win32, void *posix, size_t size)
49 {
50   return cygwin_conv_path_list (CCP_WIN_A_TO_POSIX | CCP_RELATIVE, win32,
51                                 posix, size);
52 }
53
54 ssize_t
55 env_plist_to_win32 (const void *posix, void *win32, size_t size)
56 {
57   return cygwin_conv_path_list (CCP_POSIX_TO_WIN_A | CCP_RELATIVE, posix,
58                                 win32, size);
59 }
60
61 ssize_t
62 env_path_to_posix (const void *win32, void *posix, size_t size)
63 {
64   return cygwin_conv_path (CCP_WIN_A_TO_POSIX | CCP_ABSOLUTE, win32,
65                            posix, size);
66 }
67
68 ssize_t
69 env_path_to_win32 (const void *posix, void *win32, size_t size)
70 {
71   return cygwin_conv_path (CCP_POSIX_TO_WIN_A | CCP_ABSOLUTE, posix,
72                            win32, size);
73 }
74
75 #define ENVMALLOC \
76   (CYGWIN_VERSION_DLL_MAKE_COMBINED (user_data->api_major, user_data->api_minor) \
77           <= CYGWIN_VERSION_DLL_MALLOC_ENV)
78
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.
82
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[] =
87   {
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}
96   };
97
98 static unsigned char conv_start_chars[256] = {0};
99
100 struct win_env&
101 win_env::operator = (struct win_env& x)
102 {
103   name = x.name;
104   namelen = x.namelen;
105   toposix = x.toposix;
106   towin32 = x.towin32;
107   immediate = false;
108   return *this;
109 }
110
111 win_env::~win_env ()
112 {
113   if (posix)
114     free (posix);
115   if (native)
116     free (native);
117 }
118
119 void
120 win_env::add_cache (const char *in_posix, const char *in_native)
121 {
122   MALLOC_CHECK;
123   posix = (char *) realloc (posix, strlen (in_posix) + 1);
124   strcpy (posix, in_posix);
125   if (in_native)
126     {
127       native = (char *) realloc (native, namelen + 1 + strlen (in_native));
128       strcpy (native, name);
129       strcpy (native + namelen, in_native);
130     }
131   else
132     {
133       tmp_pathbuf tp;
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);
140     }
141   MALLOC_CHECK;
142   if (immediate && cygwin_finished_initializing)
143     {
144       char s[namelen];
145       size_t n = namelen - 1;
146       memcpy (s, name, n);
147       s[n] = '\0';
148       SetEnvironmentVariable (s, native + namelen);
149     }
150   debug_printf ("posix %s", posix);
151   debug_printf ("native %s", native);
152 }
153
154
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.  */
159 win_env * __stdcall
160 getwinenv (const char *env, const char *in_posix, win_env *temp)
161 {
162   if (!conv_start_chars[(unsigned char)*env])
163     return NULL;
164
165   for (int i = 0; conv_envvars[i].name != NULL; i++)
166     if (strncmp (env, conv_envvars[i].name, conv_envvars[i].namelen) == 0)
167       {
168         win_env *we = conv_envvars + i;
169         const char *val;
170         if (!cur_environ () || !(val = in_posix ?: getenv (we->name)))
171           debug_printf ("can't set native for %s since no environ yet",
172                         we->name);
173         else if (!envcache || !we->posix || strcmp (val, we->posix) != 0)
174           {
175             if (temp)
176               {
177                 *temp = *we;
178                 we = temp;
179               }
180             we->add_cache (val);
181           }
182         return we;
183       }
184   return NULL;
185 }
186
187 /* Convert windows path specs to POSIX, if appropriate.
188  */
189 static void __stdcall
190 posify (char **here, const char *value, char *outenv)
191 {
192   char *src = *here;
193   win_env *conv;
194
195   if (!(conv = getwinenv (src)))
196     return;
197
198   int len = strcspn (src, "=") + 1;
199
200   /* Turn all the items from c:<foo>;<bar> into their
201      mounted equivalents - if there is one.  */
202
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);
208   else
209     {
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);
215     }
216
217   debug_printf ("env var converted to %s", outenv);
218   *here = strdup (outenv);
219   free (src);
220   MALLOC_CHECK;
221 }
222
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.  */
227
228 static char * __stdcall
229 my_findenv (const char *name, int *offset)
230 {
231   register int len;
232   register char **p;
233   const char *c;
234
235   c = name;
236   len = 0;
237   while (*c && *c != '=')
238     {
239       c++;
240       len++;
241     }
242
243   for (p = cur_environ (); *p; ++p)
244     if (!strncmp (*p, name, len))
245       if (*(c = *p + len) == '=')
246         {
247           *offset = p - cur_environ ();
248           return (char *) (++c);
249         }
250   MALLOC_CHECK;
251   return NULL;
252 }
253
254 /* Primitive getenv before the environment is built.  */
255
256 static char __stdcall *
257 getearly (const char * name, int *)
258 {
259   char *ret;
260   char **ptr;
261   int len;
262
263   if (spawn_info && (ptr = spawn_info->moreinfo->envp))
264     {
265       len = strlen (name);
266       for (; *ptr; ptr++)
267         if (strncasematch (name, *ptr, len) && (*ptr)[len] == '=')
268           return *ptr + len + 1;
269     }
270   else if ((len = GetEnvironmentVariableA (name, NULL, 0))
271            && (ret = (char *) cmalloc_abort (HEAP_2_STR, len))
272            && GetEnvironmentVariableA (name, ret, len))
273     return ret;
274
275   return NULL;
276 }
277
278 static char * (*findenv_func)(const char *, int *) = (char * (*)(const char *, int *)) getearly;
279
280 /* Returns ptr to value associated with name, if any, else NULL.  */
281
282 extern "C" char *
283 getenv (const char *name)
284 {
285   int offset;
286   return findenv_func (name, &offset);
287 }
288
289 /* This function is required so that newlib uses the same environment
290    as Cygwin. */
291 extern "C" char *
292 _getenv_r (struct _reent *, const char *name)
293 {
294   int offset;
295   return findenv_func (name, &offset);
296 }
297
298 static int __stdcall
299 envsize (const char * const *in_envp)
300 {
301   const char * const *envp;
302   for (envp = in_envp; *envp; envp++)
303     continue;
304   return (1 + envp - in_envp) * sizeof (const char *);
305 }
306
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. */
310 static int __stdcall
311 _addenv (const char *name, const char *value, int overwrite)
312 {
313   int issetenv = overwrite >= 0;
314   int offset;
315   char *p;
316
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? */
322
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)
327         {
328           strcpy (p, value);
329           return 0;
330         }
331     }
332   else
333     {                           /* Create new slot. */
334       int sz = envsize (cur_environ ());
335       int allocsz = sz + (2 * sizeof (char *));
336
337       offset = (sz - 1) / sizeof (char *);
338
339       /* Allocate space for additional element plus terminating NULL. */
340       if (cur_environ () == lastenviron)
341         lastenviron = __cygwin_environ = (char **) realloc (cur_environ (),
342                                                             allocsz);
343       else if ((lastenviron = (char **) malloc (allocsz)) != NULL)
344         __cygwin_environ = (char **) memcpy ((char **) lastenviron,
345                                              __cygwin_environ, sz);
346
347       if (!__cygwin_environ)
348         {
349 #ifdef DEBUGGING
350           try_to_debug ();
351 #endif
352           return -1;                            /* Oops.  No more memory. */
353         }
354
355       __cygwin_environ[offset + 1] = NULL;      /* NULL terminate. */
356       update_envptrs ();        /* Update any local copies of 'environ'. */
357     }
358
359   char *envhere;
360   if (!issetenv)
361     /* Not setenv. Just overwrite existing. */
362     envhere = cur_environ ()[offset] = (char *) (ENVMALLOC ? strdup (name) : name);
363   else
364     {                           /* setenv */
365       /* Look for an '=' in the name and ignore anything after that if found. */
366       for (p = (char *) name; *p && *p != '='; p++)
367         continue;
368
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);
372       if (!envhere)
373         return -1;              /* Oops.  No more memory. */
374
375       /* Put name '=' value into current slot. */
376       strncpy (envhere, name, namelen);
377       envhere[namelen] = '=';
378       strcpy (envhere + namelen + 1, value);
379     }
380
381   /* Update cygwin's cache, if appropriate */
382   win_env *spenv;
383   if ((spenv = getwinenv (envhere)))
384     spenv->add_cache (value);
385
386   MALLOC_CHECK;
387   return 0;
388 }
389
390 /* Set an environment variable */
391 extern "C" int
392 putenv (char *str)
393 {
394   myfault efault;
395   if (efault.faulted (EFAULT))
396     return -1;
397   if (*str)
398     {
399       char *eq = strchr (str, '=');
400       if (eq)
401         return _addenv (str, eq + 1, -1);
402
403       /* Remove str from the environment. */
404       unsetenv (str);
405     }
406   return 0;
407 }
408
409 /* Set the value of the environment variable "name" to be
410    "value".  If overwrite is set, replace any current value.  */
411 extern "C" int
412 setenv (const char *name, const char *value, int overwrite)
413 {
414   myfault efault;
415   if (efault.faulted (EFAULT))
416     return -1;
417   if (!name || !*name || strchr (name, '='))
418     {
419       set_errno (EINVAL);
420       return -1;
421     }
422   return _addenv (name, value, !!overwrite);
423 }
424
425 /* Delete environment variable "name".  */
426 extern "C" int
427 unsetenv (const char *name)
428 {
429   register char **e;
430   int offset;
431   myfault efault;
432   if (efault.faulted (EFAULT))
433     return -1;
434   if (!name || *name == '\0' || strchr (name, '='))
435     {
436       set_errno (EINVAL);
437       return -1;
438     }
439
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)))
444         break;
445
446   return 0;
447 }
448
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. */
452 static struct renv {
453         const char *name;
454         const size_t namelen;
455 } renv_arr[] = {
456         { NL("ALLUSERSPROFILE=") },             // 0
457         { NL("COMMONPROGRAMFILES=") },          // 1
458         { NL("COMPUTERNAME=") },
459         { NL("COMSPEC=") },
460         { NL("HOME=") },                        // 4
461         { NL("HOMEDRIVE=") },
462         { NL("HOMEPATH=") },
463         { NL("NUMBER_OF_PROCESSORS=") },        // 7
464         { NL("OS=") },                          // 8
465         { NL("PATH=") },                        // 9
466         { NL("PATHEXT=") },
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
475         { NL("TERM=") },
476         { NL("TMP=") },
477         { NL("TMPDIR=") },
478         { NL("WINDIR=") }                       // 22
479 };
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
484    starts. */
485 static const int start_at[] = { 0, 1, 4, 7, 8, 9, 16, 18, 22 };
486
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)
491 {
492   if (create_upcaseenv)
493     {
494       /* Amazingly, NT has a case sensitive environment name list,
495          but only sometimes.
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.
499
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. */
502       for (; p < eq; p++)
503         if (islower (*p))
504           *p = cyg_toupper (*p);
505     }
506   else
507     {
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);
512       if (idx)
513         for (size_t i = start_at[idx - idx_arr];
514              i < RENV_SIZE && renv_arr[i].name[0] == first;
515              ++i)
516           if (strncasematch (p, renv_arr[i].name, renv_arr[i].namelen))
517             {
518               strncpy (p, renv_arr[i].name, renv_arr[i].namelen);
519               break;
520             }
521     }
522 }
523
524 /* Parse CYGWIN options */
525
526 static NO_COPY bool export_settings = false;
527
528 enum settings
529   {
530     justset,
531     isfunc,
532     setbit,
533     set_process_state,
534   };
535
536 /* When BUF is:
537    null or empty: disables globbing
538    "ignorecase": enables case-insensitive globbing
539    anything else: enables case-sensitive globbing */
540 static void
541 glob_init (const char *buf)
542 {
543   if (!buf || !*buf)
544     {
545       allow_glob = false;
546       ignore_case_with_glob = false;
547     }
548   else if (ascii_strncasematch (buf, "ignorecase", 10))
549     {
550       allow_glob = true;
551       ignore_case_with_glob = true;
552     }
553   else
554     {
555       allow_glob = true;
556       ignore_case_with_glob = false;
557     }
558 }
559
560 static void
561 set_chunksize (const char *buf)
562 {
563   wincap.set_chunksize (strtoul (buf, NULL, 0));
564 }
565
566 static void
567 set_proc_retry (const char *buf)
568 {
569   child_info::retry_count = strtoul (buf, NULL, 0);
570 }
571
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
574    the registry.  */
575 static struct parse_thing
576   {
577     const char *name;
578     union parse_setting
579       {
580         bool *b;
581         DWORD *x;
582         int *i;
583         void (*func)(const char *);
584       } setting;
585
586     enum settings disposition;
587     char *remember;
588     union parse_values
589       {
590         DWORD i;
591         const char *s;
592       } values[2];
593   } known[] NO_COPY =
594 {
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}}}
609 };
610
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)
615 {
616   int istrue;
617   char *p, *lasts;
618   parse_thing *k;
619
620   if (buf == NULL)
621     {
622       tmp_pathbuf tp;
623       char *newbuf = tp.c_get ();
624       newbuf[0] = '\0';
625       for (k = known; k->name != NULL; k++)
626         if (k->remember)
627           {
628             strcat (strcat (newbuf, " "), k->remember);
629             free (k->remember);
630             k->remember = NULL;
631           }
632
633       if (export_settings)
634         {
635           debug_printf ("%s", newbuf + 1);
636           setenv ("CYGWIN", newbuf + 1, 1);
637         }
638       return;
639     }
640
641   buf = strcpy ((char *) alloca (strlen (buf) + 1), buf);
642   for (p = strtok_r (buf, " \t", &lasts);
643        p != NULL;
644        p = strtok_r (NULL, " \t", &lasts))
645     {
646       char *keyword_here = p;
647       if (!(istrue = !ascii_strncasematch (p, "no", 2)))
648         p += 2;
649       else if (!(istrue = *p != '-'))
650         p++;
651
652       char ch, *eq;
653       if ((eq = strchr (p, '=')) != NULL || (eq = strchr (p, ':')) != NULL)
654         ch = *eq, *eq++ = '\0';
655       else
656         ch = 0;
657
658       for (parse_thing *k = known; k->name != NULL; k++)
659         if (ascii_strcasematch (p, k->name))
660           {
661             switch (k->disposition)
662               {
663               case isfunc:
664                 k->setting.func ((!eq || !istrue) ?
665                   k->values[istrue].s : eq);
666                 debug_printf ("%s (called func)", k->name);
667                 break;
668               case justset:
669                 if (!istrue || !eq)
670                   *k->setting.x = k->values[istrue].i;
671                 else
672                   *k->setting.x = strtol (eq, NULL, 0);
673                 debug_printf ("%s %d", k->name, *k->setting.x);
674                 break;
675               case set_process_state:
676                 k->setting.x = &myself->process_state;
677                 /* fall through */
678               case setbit:
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);
683                 break;
684               }
685
686             if (eq)
687               *--eq = ch;
688
689             int n = eq - p;
690             p = strdup (keyword_here);
691             if (n > 0)
692               p[n] = ':';
693             k->remember = p;
694             break;
695           }
696       }
697   debug_printf ("returning");
698 }
699
700 /* Set options from the registry. */
701 static bool __stdcall
702 regopt (const WCHAR *name, char *buf)
703 {
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);
710
711   for (int i = 0; i < 2; i++)
712     {
713       reg_key r (i, KEY_READ, CYGWIN_INFO_PROGRAM_OPTIONS_NAME, NULL);
714
715       if (r.get_string (lname.Buffer, (PWCHAR) buf, NT_MAX_PATH, L"") == ERROR_SUCCESS)
716         {
717           char *newp;
718           sys_wcstombs_alloc(&newp, HEAP_NOTHEAP, (PWCHAR) buf);
719           strcpy(buf, newp);
720           parse_options (buf);
721           parsed_something = true;
722           break;
723         }
724     }
725
726   MALLOC_CHECK;
727   return parsed_something;
728 }
729
730 /* Initialize the environ array.  Look for the CYGWIN environment
731    environment variable and set appropriate options from it.  */
732 void
733 environ_init (char **envp, int envc)
734 {
735   PWCHAR rawenv, w;
736   int i;
737   char *p;
738   char *newp;
739   int sawTERM = 0;
740   bool envp_passed_in;
741   bool got_something_from_registry;
742   static char NO_COPY cygterm[] = "TERM=cygwin";
743   myfault efault;
744   tmp_pathbuf tp;
745
746   if (efault.faulted ())
747     api_fatal ("internal error reading the windows environment - too many environment variables?");
748
749   if (!conv_start_chars[0])
750     for (int i = 0; conv_envvars[i].name != NULL; i++)
751       {
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;
754       }
755
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;
761
762   if (!envp)
763     envp_passed_in = 0;
764   else
765     {
766       envc++;
767       envc *= sizeof (char *);
768       char **newenv = (char **) malloc (envc);
769       memcpy (newenv, envp, envc);
770       cfree (envp);
771
772       /* Older applications relied on the fact that cygwin malloced elements of the
773          environment list.  */
774       envp = newenv;
775       if (ENVMALLOC)
776         for (char **e = newenv; *e; e++)
777           {
778             char *p = *e;
779             *e = strdup (p);
780             cfree (p);
781           }
782       envp_passed_in = 1;
783       goto out;
784     }
785
786   /* Allocate space for environment + trailing NULL + CYGWIN env. */
787   lastenviron = envp = (char **) malloc ((4 + (envc = 100)) * sizeof (char *));
788
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)))
792     {
793       char *buf = (char *) alloca (i);
794       GetEnvironmentVariableA ("CYGWIN", buf, i);
795       parse_options (buf);
796     }
797
798   rawenv = GetEnvironmentStringsW ();
799   if (!rawenv)
800     {
801       system_printf ("GetEnvironmentStrings returned NULL, %E");
802       return;
803     }
804   debug_printf ("GetEnvironmentStrings returned %p", rawenv);
805
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++)
811     {
812       sys_wcstombs_alloc (&newp, HEAP_NOTHEAP, w);
813       if (i >= envc)
814         envp = (char **) realloc (envp, (4 + (envc += 100)) * sizeof (char *));
815       envp[i] = newp;
816       if (*newp == '=')
817         *newp = '!';
818       char *eq = strechr (newp, '=');
819       ucenv (newp, eq); /* (possibly conditionally) uppercase env vars. */
820       if (*newp == 'T' && strncmp (newp, "TERM=", 5) == 0)
821         sawTERM = 1;
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]);
825     }
826
827   if (!sawTERM)
828     envp[i++] = strdup (cygterm);
829   envp[i] = NULL;
830   FreeEnvironmentStringsW (rawenv);
831
832 out:
833   findenv_func = (char * (*)(const char*, int*)) my_findenv;
834   __cygwin_environ = envp;
835   update_envptrs ();
836   if (envp_passed_in)
837     {
838       p = getenv ("CYGWIN");
839       if (p)
840         parse_options (p);
841     }
842
843   if (got_something_from_registry)
844     parse_options (NULL);       /* possibly export registry settings to
845                                    environment */
846   MALLOC_CHECK;
847 }
848
849 /* Function called by qsort to sort environment strings.  */
850 static int
851 env_sort (const void *a, const void *b)
852 {
853   const char **p = (const char **) a;
854   const char **q = (const char **) b;
855
856   return strcmp (*p, *q);
857 }
858
859 char * __stdcall
860 getwinenveq (const char *name, size_t namelen, int x)
861 {
862   WCHAR name0[namelen - 1];
863   WCHAR valbuf[32768]; /* Max size of an env.var including trailing '\0'. */
864
865   name0[sys_mbstowcs (name0, sizeof name0, name, namelen - 1)] = L'\0';
866   int totlen = GetEnvironmentVariableW (name0, valbuf, 32768);
867   if (totlen > 0)
868     {
869       totlen = sys_wcstombs (NULL, 0, valbuf);
870       if (x == HEAP_1_STR)
871         totlen += namelen;
872       else
873         namelen = 0;
874       char *p = (char *) cmalloc_abort ((cygheap_types) x, totlen);
875       if (namelen)
876         strcpy (p, name);
877       sys_wcstombs (p + namelen, totlen, valbuf);
878       debug_printf ("using value from GetEnvironmentVariable for '%W'", name0);
879       return p;
880     }
881
882   debug_printf ("warning: %s not present in environment", name);
883   return NULL;
884 }
885
886 struct spenv
887 {
888   const char *name;
889   size_t namelen;
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);
893
894   char *retrieve (bool, const char * const = NULL)
895     __attribute__ ((regparm (3)));
896 };
897
898 #define env_dontadd almost_null
899
900 /* Keep this list in upper case and sorted */
901 static NO_COPY spenv spenvs[] =
902 {
903 #ifdef DEBUGGING
904   {NL ("CYGWIN_DEBUG="), false, true, NULL},
905 #endif
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}
916 };
917
918 char *
919 spenv::retrieve (bool no_envblock, const char *const env)
920 {
921   if (env && !ascii_strncasematch (env, name, namelen))
922     return NULL;
923
924   debug_printf ("no_envblock %d", no_envblock);
925
926   if (from_cygheap)
927     {
928       const char *p;
929       if (env && !cygheap->user.issetuid ())
930         {
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);
934         }
935
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))
939         return env_dontadd;
940       char *s = (char *) cmalloc_abort (HEAP_1_STR, namelen + strlen (p) + 1);
941       strcpy (s, name);
942       strcpy (s + namelen, p);
943       debug_printf ("using computed value for '%s'", name);
944       return s;
945     }
946
947   if (env)
948     return cstrdup1 (env);
949
950   return getwinenveq (name, namelen, HEAP_1_STR);
951 }
952
953 #define SPENVS_SIZE (sizeof (spenvs) / sizeof (spenvs[0]))
954
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.  */
959 char ** __stdcall
960 build_env (const char * const *envp, PWCHAR &envblock, int &envc,
961            bool no_envblock)
962 {
963   int len, n;
964   const char * const *srcp;
965   char **dstp;
966   bool saw_spenv[SPENVS_SIZE] = {0};
967
968   debug_printf ("envp %p", envp);
969
970   /* How many elements? */
971   for (n = 0; envp[n]; n++)
972     continue;
973
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));
977
978   int tl = 0;
979   char **pass_dstp;
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++)
984     {
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)))
989           {
990             saw_spenv[i] = 1;
991             if (*dstp == env_dontadd)
992               goto next1;
993             if (spenvs[i].add_if_exists)
994               calc_tl = true;
995             goto  next0;
996           }
997
998       /* Add entry to new environment */
999       *dstp = cstrdup1 (*srcp);
1000
1001     next0:
1002       if (calc_tl)
1003         {
1004           *pass_dstp++ = *dstp;
1005           tl += strlen (*dstp) + 1;
1006         }
1007       dstp++;
1008     next1:
1009       continue;
1010     }
1011
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 ()))
1016       {
1017           *dstp = spenvs[i].retrieve (false);
1018           if (*dstp && *dstp != env_dontadd)
1019             {
1020               *pass_dstp++ = *dstp;
1021               tl += strlen (*dstp) + 1;
1022               dstp++;
1023             }
1024         }
1025
1026   envc = dstp - newenv;         /* Number of entries in newenv */
1027   assert ((size_t) envc <= (n + SPENVS_SIZE));
1028   *dstp = NULL;                 /* Terminate */
1029
1030   size_t pass_envc = pass_dstp - pass_env;
1031   if (!pass_envc)
1032     envblock = NULL;
1033   else
1034     {
1035       *pass_dstp = NULL;
1036       debug_printf ("env count %d, bytes %d", pass_envc, tl);
1037       win_env temp;
1038       temp.reset ();
1039
1040       /* Windows programs expect the environment block to be sorted.  */
1041       qsort (pass_env, pass_envc, sizeof (char *), env_sort);
1042
1043       /* Create an environment block suitable for passing to CreateProcess.  */
1044       PWCHAR s;
1045       envblock = (PWCHAR) malloc ((2 + tl) * sizeof (WCHAR));
1046       int new_tl = 0;
1047       for (srcp = pass_env, s = envblock; *srcp; srcp++)
1048         {
1049           const char *p;
1050           win_env *conv;
1051           len = strcspn (*srcp, "=") + 1;
1052           const char *rest = *srcp + len;
1053
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)
1060             continue;
1061
1062           /* See if this entry requires posix->win32 conversion. */
1063           conv = getwinenv (*srcp, rest, &temp);
1064           if (conv)
1065             p = conv->native;   /* Use win32 path */
1066           else
1067             p = *srcp;          /* Don't worry about it */
1068
1069           len = sys_mbstowcs (NULL, 0, p);
1070           new_tl += len;        /* Keep running total of block length so far */
1071
1072           /* See if we need to increase the size of the block. */
1073           if (new_tl > tl)
1074             {
1075               tl = new_tl + 100;
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)
1080                 {
1081                   s += new_envblock - envblock;
1082                   envblock = new_envblock;
1083                 }
1084             }
1085
1086           int slen = sys_mbstowcs (s, len, p);
1087
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':'))
1093               && s[3] == L'=')
1094             *s = L'=';
1095           s += slen + 1;
1096         }
1097       *s = L'\0';                       /* Two null bytes at the end */
1098       assert ((s - envblock) <= tl);    /* Detect if we somehow ran over end
1099                                            of buffer */
1100     }
1101
1102   debug_printf ("envp %p, envc %d", newenv, envc);
1103   return newenv;
1104 }
1105
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
1111 cur_environ ()
1112 {
1113   if (*main_environ != __cygwin_environ)
1114     {
1115       __cygwin_environ = *main_environ;
1116       update_envptrs ();
1117     }
1118
1119   return __cygwin_environ;
1120 }