OSDN Git Service

0dc00c1af15ab4f40f6b12436e3db84586a119ae
[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, 2010, 2011 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 "shared_info.h"
33 #include "ntdll.h"
34
35 extern bool dos_file_warning;
36 extern bool ignore_case_with_glob;
37 extern bool allow_winsymlinks;
38 bool reset_com = false;
39 static bool create_upcaseenv = false;
40
41 static char **lastenviron;
42
43 /* Parse CYGWIN options */
44
45 static NO_COPY bool export_settings = false;
46
47 enum settings
48   {
49     justset,
50     isfunc,
51     setbit
52   };
53
54 /* When BUF is:
55    null or empty: disables globbing
56    "ignorecase": enables case-insensitive globbing
57    anything else: enables case-sensitive globbing */
58 static void
59 glob_init (const char *buf)
60 {
61   if (!buf || !*buf)
62     {
63       allow_glob = false;
64       ignore_case_with_glob = false;
65     }
66   else if (ascii_strncasematch (buf, "ignorecase", 10))
67     {
68       allow_glob = true;
69       ignore_case_with_glob = true;
70     }
71   else
72     {
73       allow_glob = true;
74       ignore_case_with_glob = false;
75     }
76 }
77
78 static void
79 set_proc_retry (const char *buf)
80 {
81   child_info::retry_count = strtoul (buf, NULL, 0);
82 }
83
84 static void
85 tty_is_gone (const char *buf)
86 {
87   if (!user_shared->warned_notty)
88     {
89       small_printf ("\"tty\" option detected in CYGWIN environment variable.\n"
90                     "CYGWIN=tty is no longer supported.  Please remove it from your\n"
91                     "CYGWIN environment variable and use a terminal emulator like mintty, "
92                     "xterm, or rxvt\n");
93       user_shared->warned_notty = 1;
94     }
95 }
96
97 /* The structure below is used to set up an array which is used to
98    parse the CYGWIN environment variable or, if enabled, options from
99    the registry.  */
100 static struct parse_thing
101   {
102     const char *name;
103     union parse_setting
104       {
105         bool *b;
106         DWORD *x;
107         int *i;
108         void (*func)(const char *);
109       } setting;
110
111     enum settings disposition;
112     char *remember;
113     union parse_values
114       {
115         DWORD i;
116         const char *s;
117       } values[2];
118   } known[] NO_COPY =
119 {
120   {"dosfilewarning", {&dos_file_warning}, justset, NULL, {{false}, {true}}},
121   {"error_start", {func: error_start_init}, isfunc, NULL, {{0}, {0}}},
122   {"export", {&export_settings}, justset, NULL, {{false}, {true}}},
123   {"glob", {func: glob_init}, isfunc, NULL, {{0}, {s: "normal"}}},
124   {"proc_retry", {func: set_proc_retry}, isfunc, NULL, {{0}, {5}}},
125   {"reset_com", {&reset_com}, justset, NULL, {{false}, {true}}},
126   {"strip_title", {&strip_title_path}, justset, NULL, {{false}, {true}}},
127   {"title", {&display_title}, justset, NULL, {{false}, {true}}},
128   {"tty", {func: tty_is_gone}, isfunc, NULL, {{0}, {0}}},
129   {"upcaseenv", {&create_upcaseenv}, justset, NULL, {{false}, {true}}},
130   {"winsymlinks", {&allow_winsymlinks}, justset, NULL, {{false}, {true}}},
131   {NULL, {0}, justset, 0, {{0}, {0}}}
132 };
133
134 /* Parse a string of the form "something=stuff somethingelse=more-stuff",
135    silently ignoring unknown "somethings".  */
136 static void __stdcall
137 parse_options (const char *inbuf)
138 {
139   int istrue;
140   char *p, *lasts;
141   parse_thing *k;
142
143   if (inbuf == NULL)
144     {
145       tmp_pathbuf tp;
146       char *newbuf = tp.c_get ();
147       newbuf[0] = '\0';
148       for (k = known; k->name != NULL; k++)
149         if (k->remember)
150           {
151             strcat (strcat (newbuf, " "), k->remember);
152             free (k->remember);
153             k->remember = NULL;
154           }
155
156       if (export_settings)
157         {
158           debug_printf ("%s", newbuf + 1);
159           setenv ("CYGWIN", newbuf + 1, 1);
160         }
161       return;
162     }
163
164   char *buf = strcpy ((char *) alloca (strlen (inbuf) + 1), inbuf);
165   for (p = strtok_r (buf, " \t", &lasts);
166        p != NULL;
167        p = strtok_r (NULL, " \t", &lasts))
168     {
169       char *keyword_here = p;
170       if (!(istrue = !ascii_strncasematch (p, "no", 2)))
171         p += 2;
172       else if (!(istrue = *p != '-'))
173         p++;
174
175       char ch, *eq;
176       if ((eq = strchr (p, '=')) != NULL || (eq = strchr (p, ':')) != NULL)
177         ch = *eq, *eq++ = '\0';
178       else
179         ch = 0;
180
181       for (parse_thing *k = known; k->name != NULL; k++)
182         if (ascii_strcasematch (p, k->name))
183           {
184             switch (k->disposition)
185               {
186               case isfunc:
187                 k->setting.func ((!eq || !istrue) ?
188                   k->values[istrue].s : eq);
189                 debug_printf ("%s (called func)", k->name);
190                 break;
191               case justset:
192                 if (!istrue || !eq)
193                   *k->setting.x = k->values[istrue].i;
194                 else
195                   *k->setting.x = strtol (eq, NULL, 0);
196                 debug_printf ("%s %d", k->name, *k->setting.x);
197                 break;
198               case setbit:
199                 *k->setting.x &= ~k->values[istrue].i;
200                 if (istrue || (eq && strtol (eq, NULL, 0)))
201                   *k->setting.x |= k->values[istrue].i;
202                 debug_printf ("%s %x", k->name, *k->setting.x);
203                 break;
204               }
205
206             if (eq)
207               *--eq = ch;
208
209             int n = eq - p;
210             p = strdup (keyword_here);
211             if (n > 0)
212               p[n] = ':';
213             k->remember = p;
214             break;
215           }
216       }
217   debug_printf ("returning");
218 }
219
220 /* Helper functions for the below environment variables which have to
221    be converted Win32<->POSIX. */
222 extern "C" ssize_t env_PATH_to_posix (const void *, void *, size_t);
223
224 ssize_t
225 env_plist_to_posix (const void *win32, void *posix, size_t size)
226 {
227   return cygwin_conv_path_list (CCP_WIN_A_TO_POSIX | CCP_RELATIVE, win32,
228                                 posix, size);
229 }
230
231 ssize_t
232 env_plist_to_win32 (const void *posix, void *win32, size_t size)
233 {
234   return cygwin_conv_path_list (CCP_POSIX_TO_WIN_A | CCP_RELATIVE, posix,
235                                 win32, size);
236 }
237
238 ssize_t
239 env_path_to_posix (const void *win32, void *posix, size_t size)
240 {
241   return cygwin_conv_path (CCP_WIN_A_TO_POSIX | CCP_ABSOLUTE, win32,
242                            posix, size);
243 }
244
245 ssize_t
246 env_path_to_win32 (const void *posix, void *win32, size_t size)
247 {
248   return cygwin_conv_path (CCP_POSIX_TO_WIN_A | CCP_ABSOLUTE, posix,
249                            win32, size);
250 }
251
252 #define ENVMALLOC \
253   (CYGWIN_VERSION_DLL_MAKE_COMBINED (user_data->api_major, user_data->api_minor) \
254           <= CYGWIN_VERSION_DLL_MALLOC_ENV)
255
256 #define NL(x) x, (sizeof (x) - 1)
257 /* List of names which are converted from dos to unix
258    on the way in and back again on the way out.
259
260    PATH needs to be here because CreateProcess uses it and gdb uses
261    CreateProcess.  HOME is here because most shells use it and would be
262    confused by Windows style path names.  */
263 static win_env conv_envvars[] =
264   {
265     {NL ("PATH="), NULL, NULL, env_PATH_to_posix, env_plist_to_win32, true},
266     {NL ("HOME="), NULL, NULL, env_path_to_posix, env_path_to_win32, false},
267     {NL ("LD_LIBRARY_PATH="), NULL, NULL,
268                                env_plist_to_posix, env_plist_to_win32, true},
269     {NL ("TMPDIR="), NULL, NULL, env_path_to_posix, env_path_to_win32, false},
270     {NL ("TMP="), NULL, NULL, env_path_to_posix, env_path_to_win32, false},
271     {NL ("TEMP="), NULL, NULL, env_path_to_posix, env_path_to_win32, false},
272     {NULL, 0, NULL, NULL, 0, 0}
273   };
274
275 static unsigned char conv_start_chars[256] = {0};
276
277 struct win_env&
278 win_env::operator = (struct win_env& x)
279 {
280   name = x.name;
281   namelen = x.namelen;
282   toposix = x.toposix;
283   towin32 = x.towin32;
284   immediate = false;
285   return *this;
286 }
287
288 win_env::~win_env ()
289 {
290   if (posix)
291     free (posix);
292   if (native)
293     free (native);
294 }
295
296 void
297 win_env::add_cache (const char *in_posix, const char *in_native)
298 {
299   MALLOC_CHECK;
300   posix = (char *) realloc (posix, strlen (in_posix) + 1);
301   strcpy (posix, in_posix);
302   if (in_native)
303     {
304       native = (char *) realloc (native, namelen + 1 + strlen (in_native));
305       strcpy (native, name);
306       strcpy (native + namelen, in_native);
307     }
308   else
309     {
310       tmp_pathbuf tp;
311       char *buf = tp.c_get ();
312       strcpy (buf, name + namelen);
313       towin32 (in_posix, buf, NT_MAX_PATH);
314       native = (char *) realloc (native, namelen + 1 + strlen (buf));
315       strcpy (native, name);
316       strcpy (native + namelen, buf);
317     }
318   MALLOC_CHECK;
319   if (immediate && cygwin_finished_initializing)
320     {
321       char s[namelen];
322       size_t n = namelen - 1;
323       memcpy (s, name, n);
324       s[n] = '\0';
325       SetEnvironmentVariable (s, native + namelen);
326     }
327   debug_printf ("posix %s", posix);
328   debug_printf ("native %s", native);
329 }
330
331
332 /* Check for a "special" environment variable name.  *env is the pointer
333   to the beginning of the environment variable name.  *in_posix is any
334   known posix value for the environment variable. Returns a pointer to
335   the appropriate conversion structure.  */
336 win_env * __stdcall
337 getwinenv (const char *env, const char *in_posix, win_env *temp)
338 {
339   if (!conv_start_chars[(unsigned char)*env])
340     return NULL;
341
342   for (int i = 0; conv_envvars[i].name != NULL; i++)
343     if (strncmp (env, conv_envvars[i].name, conv_envvars[i].namelen) == 0)
344       {
345         win_env *we = conv_envvars + i;
346         const char *val;
347         if (!cur_environ () || !(val = in_posix ?: getenv (we->name)))
348           debug_printf ("can't set native for %s since no environ yet",
349                         we->name);
350         else if (!we->posix || strcmp (val, we->posix) != 0)
351           {
352             if (temp)
353               {
354                 *temp = *we;
355                 we = temp;
356               }
357             we->add_cache (val);
358           }
359         return we;
360       }
361   return NULL;
362 }
363
364 /* Convert windows path specs to POSIX, if appropriate.
365  */
366 static void __stdcall
367 posify (char **here, const char *value, char *outenv)
368 {
369   char *src = *here;
370   win_env *conv;
371
372   if (!(conv = getwinenv (src)))
373     return;
374
375   int len = strcspn (src, "=") + 1;
376
377   /* Turn all the items from c:<foo>;<bar> into their
378      mounted equivalents - if there is one.  */
379
380   memcpy (outenv, src, len);
381   char *newvalue = outenv + len;
382   if (!conv->toposix (value, newvalue, NT_MAX_PATH - len)
383       || _impure_ptr->_errno != EIDRM)
384     conv->add_cache (newvalue, *value != '/' ? value : NULL);
385   else
386     {
387       /* The conversion routine removed elements from a path list so we have
388          to recalculate the windows path to remove elements there, too. */
389       char cleanvalue[strlen (value) + 1];
390       conv->towin32 (newvalue, cleanvalue, sizeof cleanvalue);
391       conv->add_cache (newvalue, cleanvalue);
392     }
393
394   debug_printf ("env var converted to %s", outenv);
395   *here = strdup (outenv);
396   free (src);
397   MALLOC_CHECK;
398 }
399
400 /* Returns pointer to value associated with name, if any, else NULL.
401   Sets offset to be the offset of the name/value combination in the
402   environment array, for use by setenv(3) and unsetenv(3).
403   Explicitly removes '=' in argument name.  */
404
405 static char * __stdcall
406 my_findenv (const char *name, int *offset)
407 {
408   register int len;
409   register char **p;
410   const char *c;
411
412   c = name;
413   len = 0;
414   while (*c && *c != '=')
415     {
416       c++;
417       len++;
418     }
419
420   for (p = cur_environ (); *p; ++p)
421     if (!strncmp (*p, name, len))
422       if (*(c = *p + len) == '=')
423         {
424           *offset = p - cur_environ ();
425           return (char *) (++c);
426         }
427   MALLOC_CHECK;
428   return NULL;
429 }
430
431 /* Primitive getenv before the environment is built.  */
432
433 static char __stdcall *
434 getearly (const char * name, int *)
435 {
436   char *ret;
437   char **ptr;
438   int len;
439
440   if (spawn_info && (ptr = spawn_info->moreinfo->envp))
441     {
442       len = strlen (name);
443       for (; *ptr; ptr++)
444         if (strncasematch (name, *ptr, len) && (*ptr)[len] == '=')
445           return *ptr + len + 1;
446     }
447   else if ((len = GetEnvironmentVariableA (name, NULL, 0))
448            && (ret = (char *) cmalloc_abort (HEAP_2_STR, len))
449            && GetEnvironmentVariableA (name, ret, len))
450     return ret;
451
452   return NULL;
453 }
454
455 static char * (*findenv_func)(const char *, int *) = (char * (*)(const char *, int *)) getearly;
456
457 /* Returns ptr to value associated with name, if any, else NULL.  */
458
459 extern "C" char *
460 getenv (const char *name)
461 {
462   int offset;
463   return findenv_func (name, &offset);
464 }
465
466 /* This function is required so that newlib uses the same environment
467    as Cygwin. */
468 extern "C" char *
469 _getenv_r (struct _reent *, const char *name)
470 {
471   int offset;
472   return findenv_func (name, &offset);
473 }
474
475 static int __stdcall
476 envsize (const char * const *in_envp)
477 {
478   const char * const *envp;
479   for (envp = in_envp; *envp; envp++)
480     continue;
481   return (1 + envp - in_envp) * sizeof (const char *);
482 }
483
484 /* Takes similar arguments to setenv except that overwrite is
485    either -1, 0, or 1.  0 or 1 signify that the function should
486    perform similarly to setenv.  Otherwise putenv is assumed. */
487 static int __stdcall
488 _addenv (const char *name, const char *value, int overwrite)
489 {
490   int issetenv = overwrite >= 0;
491   int offset;
492   char *p;
493
494   unsigned int valuelen = strlen (value);
495   if ((p = my_findenv (name, &offset)))
496     {                           /* Already exists. */
497       if (!overwrite)           /* Ok to overwrite? */
498         return 0;               /* No.  Wanted to add new value.  FIXME: Right return value? */
499
500       /* We've found the offset into environ.  If this is a setenv call and
501          there is room in the current environment entry then just overwrite it.
502          Otherwise handle this case below. */
503       if (issetenv && strlen (p) >= valuelen)
504         {
505           strcpy (p, value);
506           return 0;
507         }
508     }
509   else
510     {                           /* Create new slot. */
511       int sz = envsize (cur_environ ());
512       int allocsz = sz + (2 * sizeof (char *));
513
514       offset = (sz - 1) / sizeof (char *);
515
516       /* Allocate space for additional element plus terminating NULL. */
517       if (cur_environ () == lastenviron)
518         lastenviron = __cygwin_environ = (char **) realloc (cur_environ (),
519                                                             allocsz);
520       else if ((lastenviron = (char **) malloc (allocsz)) != NULL)
521         __cygwin_environ = (char **) memcpy ((char **) lastenviron,
522                                              __cygwin_environ, sz);
523
524       if (!__cygwin_environ)
525         {
526 #ifdef DEBUGGING
527           try_to_debug ();
528 #endif
529           return -1;                            /* Oops.  No more memory. */
530         }
531
532       __cygwin_environ[offset + 1] = NULL;      /* NULL terminate. */
533       update_envptrs ();        /* Update any local copies of 'environ'. */
534     }
535
536   char *envhere;
537   if (!issetenv)
538     /* Not setenv. Just overwrite existing. */
539     envhere = cur_environ ()[offset] = (char *) (ENVMALLOC ? strdup (name) : name);
540   else
541     {                           /* setenv */
542       /* Look for an '=' in the name and ignore anything after that if found. */
543       for (p = (char *) name; *p && *p != '='; p++)
544         continue;
545
546       int namelen = p - name;   /* Length of name. */
547       /* Allocate enough space for name + '=' + value + '\0' */
548       envhere = cur_environ ()[offset] = (char *) malloc (namelen + valuelen + 2);
549       if (!envhere)
550         return -1;              /* Oops.  No more memory. */
551
552       /* Put name '=' value into current slot. */
553       strncpy (envhere, name, namelen);
554       envhere[namelen] = '=';
555       strcpy (envhere + namelen + 1, value);
556     }
557
558   /* Update cygwin's cache, if appropriate */
559   win_env *spenv;
560   if ((spenv = getwinenv (envhere)))
561     spenv->add_cache (value);
562   if (strcmp (name, "CYGWIN") == 0)
563     parse_options (value);
564
565   MALLOC_CHECK;
566   return 0;
567 }
568
569 /* Set an environment variable */
570 extern "C" int
571 putenv (char *str)
572 {
573   myfault efault;
574   if (efault.faulted (EFAULT))
575     return -1;
576   if (*str)
577     {
578       char *eq = strchr (str, '=');
579       if (eq)
580         return _addenv (str, eq + 1, -1);
581
582       /* Remove str from the environment. */
583       unsetenv (str);
584     }
585   return 0;
586 }
587
588 /* Set the value of the environment variable "name" to be
589    "value".  If overwrite is set, replace any current value.  */
590 extern "C" int
591 setenv (const char *name, const char *value, int overwrite)
592 {
593   myfault efault;
594   if (efault.faulted (EFAULT))
595     return -1;
596   if (!name || !*name || strchr (name, '='))
597     {
598       set_errno (EINVAL);
599       return -1;
600     }
601   return _addenv (name, value, !!overwrite);
602 }
603
604 /* Delete environment variable "name".  */
605 extern "C" int
606 unsetenv (const char *name)
607 {
608   register char **e;
609   int offset;
610   myfault efault;
611   if (efault.faulted (EFAULT))
612     return -1;
613   if (!name || *name == '\0' || strchr (name, '='))
614     {
615       set_errno (EINVAL);
616       return -1;
617     }
618
619   while (my_findenv (name, &offset))    /* if set multiple times */
620     /* Move up the rest of the array */
621     for (e = cur_environ () + offset; ; e++)
622       if (!(*e = *(e + 1)))
623         break;
624
625   return 0;
626 }
627
628 /* Minimal list of Windows vars which must be converted to uppercase.
629    Either for POSIX compatibility of for backward compatibility with
630    existing applications. */
631 static struct renv {
632         const char *name;
633         const size_t namelen;
634 } renv_arr[] = {
635         { NL("ALLUSERSPROFILE=") },             // 0
636         { NL("COMMONPROGRAMFILES=") },          // 1
637         { NL("COMPUTERNAME=") },
638         { NL("COMSPEC=") },
639         { NL("HOME=") },                        // 4
640         { NL("HOMEDRIVE=") },
641         { NL("HOMEPATH=") },
642         { NL("NUMBER_OF_PROCESSORS=") },        // 7
643         { NL("OS=") },                          // 8
644         { NL("PATH=") },                        // 9
645         { NL("PATHEXT=") },
646         { NL("PROCESSOR_ARCHITECTURE=") },
647         { NL("PROCESSOR_IDENTIFIER=") },
648         { NL("PROCESSOR_LEVEL=") },
649         { NL("PROCESSOR_REVISION=") },
650         { NL("PROGRAMFILES=") },
651         { NL("SYSTEMDRIVE=") },                 // 16
652         { NL("SYSTEMROOT=") },
653         { NL("TEMP=") },                        // 18
654         { NL("TERM=") },
655         { NL("TMP=") },
656         { NL("TMPDIR=") },
657         { NL("WINDIR=") }                       // 22
658 };
659 #define RENV_SIZE (sizeof (renv_arr) / sizeof (renv_arr[0]))
660 /* Set of first characters of the above list of variables. */
661 static const char idx_arr[] = "ACHNOPSTW";
662 /* Index into renv_arr at which the variables with this specific character
663    starts. */
664 static const int start_at[] = { 0, 1, 4, 7, 8, 9, 16, 18, 22 };
665
666 /* Turn environment variable part of a=b string into uppercase.
667    Conditionally controlled by upcaseenv CYGWIN setting.  */
668 static __inline__ void
669 ucenv (char *p, const char *eq)
670 {
671   if (create_upcaseenv)
672     {
673       /* Amazingly, NT has a case sensitive environment name list,
674          but only sometimes.
675          It's normal to have NT set your "Path" to something.
676          Later, you set "PATH" to something else.  This alters "Path".
677          But if you try and do a naive getenv on "PATH" you'll get nothing.
678
679          So we upper case the labels here to prevent confusion later but
680          we only do it for processes that are started by non-Cygwin programs. */
681       for (; p < eq; p++)
682         if (islower (*p))
683           *p = cyg_toupper (*p);
684     }
685   else
686     {
687       /* Hopefully as quickly as possible - only upcase specific set of important
688          Windows variables. */
689       char first = cyg_toupper (*p);
690       const char *idx = strchr (idx_arr, first);
691       if (idx)
692         for (size_t i = start_at[idx - idx_arr];
693              i < RENV_SIZE && renv_arr[i].name[0] == first;
694              ++i)
695           if (strncasematch (p, renv_arr[i].name, renv_arr[i].namelen))
696             {
697               strncpy (p, renv_arr[i].name, renv_arr[i].namelen);
698               break;
699             }
700     }
701 }
702
703 /* Set options from the registry. */
704 static bool __stdcall
705 regopt (const WCHAR *name, char *buf)
706 {
707   bool parsed_something = false;
708   UNICODE_STRING lname;
709   size_t len = (wcslen(name) + 1) * sizeof (WCHAR);
710   RtlInitEmptyUnicodeString(&lname, (PWCHAR) alloca (len), len);
711   wcscpy(lname.Buffer, name);
712   RtlDowncaseUnicodeString(&lname, &lname, FALSE);
713
714   for (int i = 0; i < 2; i++)
715     {
716       reg_key r (i, KEY_READ, _WIDE (CYGWIN_INFO_PROGRAM_OPTIONS_NAME), NULL);
717
718       if (NT_SUCCESS (r.get_string (lname.Buffer, (PWCHAR) buf,
719                                     NT_MAX_PATH, L"")))
720         {
721           char *newp;
722           sys_wcstombs_alloc(&newp, HEAP_NOTHEAP, (PWCHAR) buf);
723           strcpy(buf, newp);
724           parse_options (buf);
725           parsed_something = true;
726           break;
727         }
728     }
729
730   MALLOC_CHECK;
731   return parsed_something;
732 }
733
734 /* Initialize the environ array.  Look for the CYGWIN environment
735    environment variable and set appropriate options from it.  */
736 void
737 environ_init (char **envp, int envc)
738 {
739   PWCHAR rawenv, w;
740   int i;
741   char *p;
742   char *newp;
743   int sawTERM = 0;
744   bool envp_passed_in;
745   bool got_something_from_registry;
746   static char NO_COPY cygterm[] = "TERM=cygwin";
747   myfault efault;
748   tmp_pathbuf tp;
749
750   if (efault.faulted ())
751     api_fatal ("internal error reading the windows environment - too many environment variables?");
752
753   if (!conv_start_chars[0])
754     for (int i = 0; conv_envvars[i].name != NULL; i++)
755       {
756         conv_start_chars[(int) cyg_tolower (conv_envvars[i].name[0])] = 1;
757         conv_start_chars[(int) cyg_toupper (conv_envvars[i].name[0])] = 1;
758       }
759
760   char *tmpbuf = tp.t_get ();
761   got_something_from_registry = regopt (L"default", tmpbuf);
762   if (myself->progname[0])
763     got_something_from_registry = regopt (myself->progname, tmpbuf)
764                                   || got_something_from_registry;
765
766   if (!envp)
767     envp_passed_in = 0;
768   else
769     {
770       envc++;
771       envc *= sizeof (char *);
772       char **newenv = (char **) malloc (envc);
773       memcpy (newenv, envp, envc);
774       cfree (envp);
775
776       /* Older applications relied on the fact that cygwin malloced elements of the
777          environment list.  */
778       envp = newenv;
779       if (ENVMALLOC)
780         for (char **e = newenv; *e; e++)
781           {
782             char *p = *e;
783             *e = strdup (p);
784             cfree (p);
785           }
786       envp_passed_in = 1;
787       goto out;
788     }
789
790   /* Allocate space for environment + trailing NULL + CYGWIN env. */
791   lastenviron = envp = (char **) malloc ((4 + (envc = 100)) * sizeof (char *));
792
793   /* We also need the CYGWIN variable early to know the value of the
794      CYGWIN=upcaseenv setting for the below loop. */
795   if ((i = GetEnvironmentVariableA ("CYGWIN", NULL, 0)))
796     {
797       char *buf = (char *) alloca (i);
798       GetEnvironmentVariableA ("CYGWIN", buf, i);
799       parse_options (buf);
800     }
801
802   rawenv = GetEnvironmentStringsW ();
803   if (!rawenv)
804     {
805       system_printf ("GetEnvironmentStrings returned NULL, %E");
806       return;
807     }
808   debug_printf ("GetEnvironmentStrings returned %p", rawenv);
809
810   /* Current directory information is recorded as variables of the
811      form "=X:=X:\foo\bar; these must be changed into something legal
812      (we could just ignore them but maybe an application will
813      eventually want to use them).  */
814   for (i = 0, w = rawenv; *w != L'\0'; w = wcschr (w, L'\0') + 1, i++)
815     {
816       sys_wcstombs_alloc (&newp, HEAP_NOTHEAP, w);
817       if (i >= envc)
818         envp = (char **) realloc (envp, (4 + (envc += 100)) * sizeof (char *));
819       envp[i] = newp;
820       if (*newp == '=')
821         *newp = '!';
822       char *eq = strechr (newp, '=');
823       ucenv (newp, eq); /* (possibly conditionally) uppercase env vars. */
824       if (*newp == 'T' && strncmp (newp, "TERM=", 5) == 0)
825         sawTERM = 1;
826       if (*eq && conv_start_chars[(unsigned char) envp[i][0]])
827         posify (envp + i, *++eq ? eq : --eq, tmpbuf);
828       debug_printf ("%p: %s", envp[i], envp[i]);
829     }
830
831   if (!sawTERM)
832     envp[i++] = strdup (cygterm);
833   envp[i] = NULL;
834   FreeEnvironmentStringsW (rawenv);
835
836 out:
837   findenv_func = (char * (*)(const char*, int*)) my_findenv;
838   __cygwin_environ = envp;
839   update_envptrs ();
840   if (envp_passed_in)
841     {
842       p = getenv ("CYGWIN");
843       if (p)
844         parse_options (p);
845     }
846
847   if (got_something_from_registry)
848     parse_options (NULL);       /* possibly export registry settings to
849                                    environment */
850   MALLOC_CHECK;
851 }
852
853 /* Function called by qsort to sort environment strings.  */
854 static int
855 env_sort (const void *a, const void *b)
856 {
857   const char **p = (const char **) a;
858   const char **q = (const char **) b;
859
860   return strcmp (*p, *q);
861 }
862
863 char * __stdcall
864 getwinenveq (const char *name, size_t namelen, int x)
865 {
866   WCHAR name0[namelen - 1];
867   WCHAR valbuf[32768]; /* Max size of an env.var including trailing '\0'. */
868
869   name0[sys_mbstowcs (name0, sizeof name0, name, namelen - 1)] = L'\0';
870   int totlen = GetEnvironmentVariableW (name0, valbuf, 32768);
871   if (totlen > 0)
872     {
873       totlen = sys_wcstombs (NULL, 0, valbuf);
874       if (x == HEAP_1_STR)
875         totlen += namelen;
876       else
877         namelen = 0;
878       char *p = (char *) cmalloc_abort ((cygheap_types) x, totlen);
879       if (namelen)
880         strcpy (p, name);
881       sys_wcstombs (p + namelen, totlen, valbuf);
882       debug_printf ("using value from GetEnvironmentVariable for '%W'", name0);
883       return p;
884     }
885
886   debug_printf ("warning: %s not present in environment", name);
887   return NULL;
888 }
889
890 struct spenv
891 {
892   const char *name;
893   size_t namelen;
894   bool force_into_environment;  /* If true, always add to env if missing */
895   bool add_if_exists;           /* if true, retrieve value from cache */
896   const char * (cygheap_user::*from_cygheap) (const char *, size_t);
897
898   char *retrieve (bool, const char * const = NULL)
899     __attribute__ ((regparm (3)));
900 };
901
902 #define env_dontadd almost_null
903
904 /* Keep this list in upper case and sorted */
905 static NO_COPY spenv spenvs[] =
906 {
907 #ifdef DEBUGGING
908   {NL ("CYGWIN_DEBUG="), false, true, NULL},
909 #endif
910   {NL ("HOMEDRIVE="), false, false, &cygheap_user::env_homedrive},
911   {NL ("HOMEPATH="), false, false, &cygheap_user::env_homepath},
912   {NL ("LOGONSERVER="), false, false, &cygheap_user::env_logsrv},
913   {NL ("PATH="), false, true, NULL},
914   {NL ("SYSTEMDRIVE="), false, true, NULL},
915   {NL ("SYSTEMROOT="), true, true, &cygheap_user::env_systemroot},
916   {NL ("USERDOMAIN="), false, false, &cygheap_user::env_domain},
917   {NL ("USERNAME="), false, false, &cygheap_user::env_name},
918   {NL ("USERPROFILE="), false, false, &cygheap_user::env_userprofile},
919   {NL ("WINDIR="), true, true, &cygheap_user::env_systemroot}
920 };
921
922 char *
923 spenv::retrieve (bool no_envblock, const char *const env)
924 {
925   if (env && !ascii_strncasematch (env, name, namelen))
926     return NULL;
927
928   debug_printf ("no_envblock %d", no_envblock);
929
930   if (from_cygheap)
931     {
932       const char *p;
933       if (env && !cygheap->user.issetuid ())
934         {
935           debug_printf ("duping existing value for '%s'", name);
936           /* Don't really care what it's set to if we're calling a cygwin program */
937           return cstrdup1 (env);
938         }
939
940       /* Calculate (potentially) value for given environment variable.  */
941       p = (cygheap->user.*from_cygheap) (name, namelen);
942       if (!p || (no_envblock && !env) || (p == env_dontadd))
943         return env_dontadd;
944       char *s = (char *) cmalloc_abort (HEAP_1_STR, namelen + strlen (p) + 1);
945       strcpy (s, name);
946       strcpy (s + namelen, p);
947       debug_printf ("using computed value for '%s'", name);
948       return s;
949     }
950
951   if (env)
952     return cstrdup1 (env);
953
954   return getwinenveq (name, namelen, HEAP_1_STR);
955 }
956
957 #define SPENVS_SIZE (sizeof (spenvs) / sizeof (spenvs[0]))
958
959 /* Create a Windows-style environment block, i.e. a typical character buffer
960    filled with null terminated strings, terminated by double null characters.
961    Converts environment variables noted in conv_envvars into win32 form
962    prior to placing them in the string.  */
963 char ** __stdcall
964 build_env (const char * const *envp, PWCHAR &envblock, int &envc,
965            bool no_envblock)
966 {
967   int len, n;
968   const char * const *srcp;
969   char **dstp;
970   bool saw_spenv[SPENVS_SIZE] = {0};
971
972   debug_printf ("envp %p", envp);
973
974   /* How many elements? */
975   for (n = 0; envp[n]; n++)
976     continue;
977
978   /* Allocate a new "argv-style" environ list with room for extra stuff. */
979   char **newenv = (char **) cmalloc_abort (HEAP_1_ARGV, sizeof (char *) *
980                                      (n + SPENVS_SIZE + 1));
981
982   int tl = 0;
983   char **pass_dstp;
984   char **pass_env = (char **) alloca (sizeof (char *) * (n + SPENVS_SIZE + 1));
985   /* Iterate over input list, generating a new environment list and refreshing
986      "special" entries, if necessary. */
987   for (srcp = envp, dstp = newenv, pass_dstp = pass_env; *srcp; srcp++)
988     {
989       bool calc_tl = !no_envblock;
990       /* Look for entries that require special attention */
991       for (unsigned i = 0; i < SPENVS_SIZE; i++)
992         if (!saw_spenv[i] && (*dstp = spenvs[i].retrieve (no_envblock, *srcp)))
993           {
994             saw_spenv[i] = 1;
995             if (*dstp == env_dontadd)
996               goto next1;
997             if (spenvs[i].add_if_exists)
998               calc_tl = true;
999             goto  next0;
1000           }
1001
1002       /* Add entry to new environment */
1003       *dstp = cstrdup1 (*srcp);
1004
1005     next0:
1006       if (calc_tl)
1007         {
1008           *pass_dstp++ = *dstp;
1009           tl += strlen (*dstp) + 1;
1010         }
1011       dstp++;
1012     next1:
1013       continue;
1014     }
1015
1016   assert ((srcp - envp) == n);
1017   /* Fill in any required-but-missing environment variables. */
1018   for (unsigned i = 0; i < SPENVS_SIZE; i++)
1019     if (!saw_spenv[i] && (spenvs[i].force_into_environment || cygheap->user.issetuid ()))
1020       {
1021           *dstp = spenvs[i].retrieve (false);
1022           if (*dstp && *dstp != env_dontadd)
1023             {
1024               *pass_dstp++ = *dstp;
1025               tl += strlen (*dstp) + 1;
1026               dstp++;
1027             }
1028         }
1029
1030   envc = dstp - newenv;         /* Number of entries in newenv */
1031   assert ((size_t) envc <= (n + SPENVS_SIZE));
1032   *dstp = NULL;                 /* Terminate */
1033
1034   size_t pass_envc = pass_dstp - pass_env;
1035   if (!pass_envc)
1036     envblock = NULL;
1037   else
1038     {
1039       *pass_dstp = NULL;
1040       debug_printf ("env count %d, bytes %d", pass_envc, tl);
1041       win_env temp;
1042       temp.reset ();
1043
1044       /* Windows programs expect the environment block to be sorted.  */
1045       qsort (pass_env, pass_envc, sizeof (char *), env_sort);
1046
1047       /* Create an environment block suitable for passing to CreateProcess.  */
1048       PWCHAR s;
1049       envblock = (PWCHAR) malloc ((2 + tl) * sizeof (WCHAR));
1050       int new_tl = 0;
1051       for (srcp = pass_env, s = envblock; *srcp; srcp++)
1052         {
1053           const char *p;
1054           win_env *conv;
1055           len = strcspn (*srcp, "=") + 1;
1056           const char *rest = *srcp + len;
1057
1058           /* Check for a bad entry.  This is necessary to get rid of empty
1059              strings, induced by putenv and changing the string afterwards.
1060              Note that this doesn't stop invalid strings without '=' in it
1061              etc., but we're opting for speed here for now.  Adding complete
1062              checking would be pretty expensive. */
1063           if (len == 1 || !*rest)
1064             continue;
1065
1066           /* See if this entry requires posix->win32 conversion. */
1067           conv = getwinenv (*srcp, rest, &temp);
1068           if (conv)
1069             p = conv->native;   /* Use win32 path */
1070           else
1071             p = *srcp;          /* Don't worry about it */
1072
1073           len = sys_mbstowcs (NULL, 0, p);
1074           new_tl += len;        /* Keep running total of block length so far */
1075
1076           /* See if we need to increase the size of the block. */
1077           if (new_tl > tl)
1078             {
1079               tl = new_tl + 100;
1080               PWCHAR new_envblock =
1081                         (PWCHAR) realloc (envblock, (2 + tl) * sizeof (WCHAR));
1082               /* If realloc moves the block, move `s' with it. */
1083               if (new_envblock != envblock)
1084                 {
1085                   s += new_envblock - envblock;
1086                   envblock = new_envblock;
1087                 }
1088             }
1089
1090           int slen = sys_mbstowcs (s, len, p);
1091
1092           /* See if environment variable is "special" in a Windows sense.
1093              Under NT, the current directories for visited drives are stored
1094              as =C:=\bar.  Cygwin converts the '=' to '!' for hopefully obvious
1095              reasons.  We need to convert it back when building the envblock */
1096           if (s[0] == L'!' && (iswdrive (s + 1) || (s[1] == L':' && s[2] == L':'))
1097               && s[3] == L'=')
1098             *s = L'=';
1099           s += slen + 1;
1100         }
1101       *s = L'\0';                       /* Two null bytes at the end */
1102       assert ((s - envblock) <= tl);    /* Detect if we somehow ran over end
1103                                            of buffer */
1104     }
1105
1106   debug_printf ("envp %p, envc %d", newenv, envc);
1107   return newenv;
1108 }
1109
1110 /* This idiocy is necessary because the early implementers of cygwin
1111    did not seem to know about importing data variables from the DLL.
1112    So, we have to synchronize cygwin's idea of the environment with the
1113    main program's with each reference to the environment. */
1114 extern "C" char ** __stdcall
1115 cur_environ ()
1116 {
1117   if (*main_environ != __cygwin_environ)
1118     {
1119       __cygwin_environ = *main_environ;
1120       update_envptrs ();
1121     }
1122
1123   return __cygwin_environ;
1124 }