1 /* environ.cc: Cygwin-adopted functions from newlib to manipulate
4 This software is a copyrighted work licensed under the terms of the
5 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
16 #include <sys/param.h>
17 #include <cygwin/version.h>
19 #include "perprocess.h"
29 #include "child_info.h"
30 #include "shared_info.h"
33 /* If this is not NULL, it points to memory allocated by us. */
34 static char **lastenviron
;
36 /* Parse CYGWIN options */
38 static NO_COPY
bool export_settings
= false;
49 null or empty: disables globbing
50 "ignorecase": enables case-insensitive globbing
51 anything else: enables case-sensitive globbing */
53 glob_init (const char *buf
)
58 ignore_case_with_glob
= false;
60 else if (ascii_strncasematch (buf
, "ignorecase", 10))
63 ignore_case_with_glob
= true;
68 ignore_case_with_glob
= false;
73 set_proc_retry (const char *buf
)
75 child_info::retry_count
= strtoul (buf
, NULL
, 0);
79 set_winsymlinks (const char *buf
)
82 allow_winsymlinks
= WSYM_lnk
;
83 else if (ascii_strncasematch (buf
, "lnk", 3))
84 allow_winsymlinks
= WSYM_lnk
;
85 else if (ascii_strncasematch (buf
, "sys", 3))
86 allow_winsymlinks
= WSYM_sysfile
;
87 /* Make sure to try native symlinks only on systems supporting them. */
88 else if (ascii_strncasematch (buf
, "native", 6))
89 allow_winsymlinks
= ascii_strcasematch (buf
+ 6, "strict")
90 ? WSYM_nativestrict
: WSYM_native
;
93 /* The structure below is used to set up an array which is used to
94 parse the CYGWIN environment variable or, if enabled, options from
96 static struct parse_thing
104 void (*func
)(const char *);
107 enum settings disposition
;
116 {"disable_pcon", {&disable_pcon
}, setbool
, NULL
, {{false}, {true}}},
117 {"error_start", {func
: error_start_init
}, isfunc
, NULL
, {{0}, {0}}},
118 {"export", {&export_settings
}, setbool
, NULL
, {{false}, {true}}},
119 {"glob", {func
: glob_init
}, isfunc
, NULL
, {{0}, {s
: "normal"}}},
120 {"pipe_byte", {&pipe_byte
}, setbool
, NULL
, {{false}, {true}}},
121 {"proc_retry", {func
: set_proc_retry
}, isfunc
, NULL
, {{0}, {5}}},
122 {"reset_com", {&reset_com
}, setbool
, NULL
, {{false}, {true}}},
123 {"wincmdln", {&wincmdln
}, setbool
, NULL
, {{false}, {true}}},
124 {"winjitdebug", {&winjitdebug
}, setbool
, NULL
, {{false}, {true}}},
125 {"winsymlinks", {func
: set_winsymlinks
}, isfunc
, NULL
, {{0}, {0}}},
126 {NULL
, {0}, setdword
, 0, {{0}, {0}}}
129 /* Return a possibly-quoted token.
130 Returns NULL when no more tokens available. */
134 buf
+= strspn(buf
, " \t");
138 char *sep
= buf
+ strcspn(buf
, " \t");
139 char *quotestart
= strchr(buf
, '"');
140 if (!quotestart
|| quotestart
> sep
)
142 buf
= sep
+ !!*sep
; /* Don't point beyond EOS */
147 char *quote
= quotestart
;
151 char *clquote
= strchr (quote
+ 1, '"');
153 sep
= strchr (quote
, '\0');
154 else if (clquote
[-1] != '\\')
158 memmove (clquote
- 1, clquote
, 1 + strchr (clquote
, '\0') - clquote
);
163 memmove (quotestart
, quotestart
+ 1, sep
- quotestart
);
171 /* Parse a string of the form "something=stuff somethingelse=more-stuff",
172 silently ignoring unknown "somethings". */
174 parse_options (const char *inbuf
)
182 char *newbuf
= tp
.c_get ();
184 for (k
= known
; k
->name
!= NULL
; k
++)
187 strcat (strcat (newbuf
, " "), k
->remember
);
194 debug_printf ("%s", newbuf
+ 1);
195 setenv ("CYGWIN", newbuf
+ 1, 1);
200 char *buf
= strcpy ((char *) alloca (strlen (inbuf
) + 1), inbuf
);
202 while (char *p
= strbrk (buf
))
204 char *keyword_here
= p
;
205 if (!(istrue
= !ascii_strncasematch (p
, "no", 2)))
207 else if (!(istrue
= *p
!= '-'))
211 if ((eq
= strchr (p
, '=')) != NULL
|| (eq
= strchr (p
, ':')) != NULL
)
212 ch
= *eq
, *eq
++ = '\0';
216 for (parse_thing
*k
= known
; k
->name
!= NULL
; k
++)
217 if (ascii_strcasematch (p
, k
->name
))
219 switch (k
->disposition
)
222 k
->setting
.func ((!eq
|| !istrue
) ? k
->values
[istrue
].s
: eq
);
223 debug_printf ("%s (called func)", k
->name
);
227 *k
->setting
.x
= k
->values
[istrue
].i
;
229 *k
->setting
.x
= strtol (eq
, NULL
, 0);
230 debug_printf ("%s %u", k
->name
, *k
->setting
.x
);
234 *k
->setting
.b
= k
->values
[istrue
].i
;
236 *k
->setting
.b
= !!strtol (eq
, NULL
, 0);
237 debug_printf ("%s%s", *k
->setting
.b
? "" : "no", k
->name
);
240 *k
->setting
.x
&= ~k
->values
[istrue
].i
;
241 if (istrue
|| (eq
&& strtol (eq
, NULL
, 0)))
242 *k
->setting
.x
|= k
->values
[istrue
].i
;
243 debug_printf ("%s %x", k
->name
, *k
->setting
.x
);
253 p
= strdup (keyword_here
);
260 debug_printf ("returning");
263 /* Helper functions for the below environment variables which have to
264 be converted Win32<->POSIX. */
265 extern "C" ssize_t
env_PATH_to_posix (const void *, void *, size_t);
268 env_plist_to_posix (const void *win32
, void *posix
, size_t size
)
270 return cygwin_conv_path_list (CCP_WIN_A_TO_POSIX
| CCP_RELATIVE
, win32
,
275 env_plist_to_win32 (const void *posix
, void *win32
, size_t size
)
277 return cygwin_conv_path_list (CCP_POSIX_TO_WIN_A
| CCP_RELATIVE
, posix
,
282 env_path_to_posix (const void *win32
, void *posix
, size_t size
)
284 return cygwin_conv_path (CCP_WIN_A_TO_POSIX
| CCP_ABSOLUTE
, win32
,
289 env_path_to_win32 (const void *posix
, void *win32
, size_t size
)
291 return cygwin_conv_path (CCP_POSIX_TO_WIN_A
| CCP_ABSOLUTE
, posix
,
295 #define NL(x) x, (sizeof (x) - 1)
296 /* List of names which are converted from dos to unix
297 on the way in and back again on the way out.
299 PATH needs to be here because CreateProcess uses it and gdb uses
300 CreateProcess. HOME is here because most shells use it and would be
301 confused by Windows style path names. */
302 static win_env conv_envvars
[] =
304 {NL ("PATH="), NULL
, NULL
, env_PATH_to_posix
, env_plist_to_win32
, true},
305 {NL ("HOME="), NULL
, NULL
, env_path_to_posix
, env_path_to_win32
, false},
306 {NL ("LD_LIBRARY_PATH="), NULL
, NULL
,
307 env_plist_to_posix
, env_plist_to_win32
, true},
308 {NL ("TMPDIR="), NULL
, NULL
, env_path_to_posix
, env_path_to_win32
, false},
309 {NL ("TMP="), NULL
, NULL
, env_path_to_posix
, env_path_to_win32
, false},
310 {NL ("TEMP="), NULL
, NULL
, env_path_to_posix
, env_path_to_win32
, false},
311 {NULL
, 0, NULL
, NULL
, 0, 0}
314 #define WC ((unsigned char) 1)
315 /* Note: You *must* fill in this array setting the ordinal value of the first
316 character of the above environment variable names to 1.
317 This table is intended to speed up lookup of these variables. */
319 static const unsigned char conv_start_chars
[256] =
321 0, 0, 0, 0, 0, 0, 0, 0,
322 0, 0, 0, 0, 0, 0, 0, 0,
323 0, 0, 0, 0, 0, 0, 0, 0,
324 0, 0, 0, 0, 0, 0, 0, 0,
325 0, 0, 0, 0, 0, 0, 0, 0,
326 0, 0, 0, 0, 0, 0, 0, 0,
327 0, 0, 0, 0, 0, 0, 0, 0,
328 0, 0, 0, 0, 0, 0, 0, 0,
330 0, 0, 0, 0, 0, 0, 0, 0,
332 /* H I J K L M N O */
333 WC
, 0, 0, 0, WC
, 0, 0, 0,
335 /* P Q R S T U V W */
336 WC
, 0, 0, 0, WC
, 0, 0, 0,
339 0, 0, 0, 0, 0, 0, 0, 0,
342 0, 0, 0, 0, 0, 0, 0, 0,
344 /* h i j k l m n o */
345 WC
, 0, 0, 0, WC
, 0, 0, 0,
347 /* p q r s t u v w */
348 WC
, 0, 0, 0, WC
, 0, 0, 0,
352 match_first_char (const char *s
, unsigned char m
)
354 return conv_start_chars
[*(unsigned char *)s
] & m
;
358 win_env::operator = (struct win_env
& x
)
377 win_env::add_cache (const char *in_posix
, const char *in_native
)
379 posix
= (char *) realloc (posix
, strlen (in_posix
) + 1);
380 strcpy (posix
, in_posix
);
383 native
= (char *) realloc (native
, namelen
+ 1 + strlen (in_native
));
384 stpcpy (stpcpy (native
, name
), in_native
);
389 char *buf
= tp
.c_get ();
390 towin32 (in_posix
, buf
, NT_MAX_PATH
);
391 native
= (char *) realloc (native
, namelen
+ 1 + strlen (buf
));
392 stpcpy (stpcpy (native
, name
), buf
);
394 if (immediate
&& cygwin_finished_initializing
)
396 wchar_t s
[sys_mbstowcs (NULL
, 0, native
) + 1];
397 sys_mbstowcs (s
, sizeof s
, native
);
398 /* Hack. Relies on affected variables only having ASCII names. */
399 s
[namelen
- 1] = L
'\0';
400 SetEnvironmentVariableW (s
, s
+ namelen
);
402 debug_printf ("posix %s", posix
);
403 debug_printf ("native %s", native
);
407 /* Check for a "special" environment variable name. *env is the pointer
408 to the beginning of the environment variable name. *in_posix is any
409 known posix value for the environment variable. Returns a pointer to
410 the appropriate conversion structure. */
412 getwinenv (const char *env
, const char *in_posix
, win_env
*temp
)
414 if (!match_first_char (env
, WC
))
417 for (int i
= 0; conv_envvars
[i
].name
!= NULL
; i
++)
418 if (strncmp (env
, conv_envvars
[i
].name
, conv_envvars
[i
].namelen
) == 0)
420 win_env
*we
= conv_envvars
+ i
;
422 if (!environ
|| !(val
= in_posix
?: getenv (we
->name
)))
423 debug_printf ("can't set native for %s since no environ yet",
425 else if (!we
->posix
|| strcmp (val
, we
->posix
) != 0)
439 /* Convert windows path specs to POSIX, if appropriate.
442 posify_maybe (char **here
, const char *value
, char *outenv
)
447 if (!(conv
= getwinenv (src
)))
450 int len
= strcspn (src
, "=") + 1;
452 /* Turn all the items from c:<foo>;<bar> into their
453 mounted equivalents - if there is one. */
455 memcpy (outenv
, src
, len
);
456 char *newvalue
= outenv
+ len
;
457 if (!conv
->toposix (value
, newvalue
, NT_MAX_PATH
- len
) || errno
!= EIDRM
)
458 conv
->add_cache (newvalue
, *value
!= '/' ? value
: NULL
);
461 /* The conversion routine removed elements from a path list so we have
462 to recalculate the windows path to remove elements there, too. */
464 char *cleanvalue
= tp
.c_get ();
465 conv
->towin32 (newvalue
, cleanvalue
, NT_MAX_PATH
);
466 conv
->add_cache (newvalue
, cleanvalue
);
469 debug_printf ("env var converted to %s", outenv
);
470 *here
= strdup (outenv
);
474 /* Returns pointer to value associated with name, if any, else NULL.
475 Sets offset to be the offset of the name/value combination in the
476 environment array, for use by setenv(3) and unsetenv(3).
477 Explicitly removes '=' in argument name. */
480 my_findenv (const char *name
, int *offset
)
491 while (*c
&& *c
!= '=')
497 for (p
= environ
; *p
; ++p
)
498 if (!strncmp (*p
, name
, len
))
499 if (*(c
= *p
+ len
) == '=')
501 *offset
= p
- environ
;
502 return (char *) (++c
);
507 /* Primitive getenv before the environment is built. */
510 getearly (const char * name
, int *)
516 if (spawn_info
&& (ptr
= spawn_info
->moreinfo
->envp
))
520 if (strncasematch (name
, *ptr
, len
) && (*ptr
)[len
] == '=')
521 return *ptr
+ len
+ 1;
523 else if ((len
= GetEnvironmentVariableA (name
, NULL
, 0))
524 && (ret
= (char *) cmalloc_abort (HEAP_2_STR
, len
))
525 && GetEnvironmentVariableA (name
, ret
, len
))
531 static char * (*findenv_func
)(const char *, int *) = getearly
;
533 /* Returns ptr to value associated with name, if any, else NULL. */
536 getenv (const char *name
)
539 return findenv_func (name
, &offset
);
542 /* This function is required so that newlib uses the same environment
545 _getenv_r (struct _reent
*, const char *name
)
548 return findenv_func (name
, &offset
);
551 /* Like getenv, but returns NULL if effective and real UID/GIDs do not match */
553 secure_getenv (const char *name
)
556 if (cygheap
->user
.issetuid ())
558 return findenv_func (name
, &offset
);
561 /* Return number of environment entries, including terminating NULL. */
563 envsize (const char * const *in_envp
)
565 const char * const *envp
;
570 for (envp
= in_envp
; *envp
; envp
++)
572 return 1 + envp
- in_envp
;
575 /* Takes similar arguments to setenv except that overwrite is
576 either -1, 0, or 1. 0 or 1 signify that the function should
577 perform similarly to setenv. Otherwise putenv is assumed. */
579 _addenv (const char *name
, const char *value
, int overwrite
)
581 int issetenv
= overwrite
>= 0;
585 unsigned int valuelen
= strlen (value
);
586 if ((p
= my_findenv (name
, &offset
)))
587 { /* Already exists. */
588 if (!overwrite
) /* Ok to overwrite? */
589 return 0; /* No. Wanted to add new value. FIXME: Right return value? */
591 /* We've found the offset into environ. If this is a setenv call and
592 there is room in the current environment entry then just overwrite it.
593 Otherwise handle this case below. */
594 if (issetenv
&& strlen (p
) >= valuelen
)
601 { /* Create new slot. */
602 int sz
= envsize (environ
);
604 /* If sz == 0, we need two new slots, one for the terminating NULL. */
605 int newsz
= sz
== 0 ? 2 : sz
+ 1;
606 int allocsz
= newsz
* sizeof (char *);
610 /* Allocate space for additional element. */
611 if (environ
== lastenviron
)
612 lastenviron
= environ
= (char **) realloc (lastenviron
,
614 else if ((lastenviron
= (char **) realloc (lastenviron
, allocsz
)) != NULL
)
615 environ
= (char **) memcpy (lastenviron
, environ
,
616 sz
* sizeof (char *));
622 return -1; /* Oops. No more memory. */
625 environ
[offset
+ 1] = NULL
; /* NULL terminate. */
630 /* Not setenv. Just overwrite existing. */
631 envhere
= environ
[offset
] = (char *) name
;
634 /* Look for an '=' in the name and ignore anything after that if found. */
635 for (p
= (char *) name
; *p
&& *p
!= '='; p
++)
638 int namelen
= p
- name
; /* Length of name. */
639 /* Allocate enough space for name + '=' + value + '\0' */
640 envhere
= environ
[offset
] = (char *) malloc (namelen
+ valuelen
+ 2);
642 return -1; /* Oops. No more memory. */
644 /* Put name '=' value into current slot. */
645 memcpy (envhere
, name
, namelen
);
646 envhere
[namelen
] = '=';
647 strcpy (envhere
+ namelen
+ 1, value
);
650 /* Update cygwin's cache, if appropriate */
652 if ((spenv
= getwinenv (envhere
)))
653 spenv
->add_cache (value
);
654 if (strcmp (name
, "CYGWIN") == 0)
655 parse_options (value
);
660 /* Set an environment variable */
668 char *eq
= strchr (str
, '=');
670 return _addenv (str
, eq
+ 1, -1);
672 /* Remove str from the environment. */
682 /* Set the value of the environment variable "name" to be
683 "value". If overwrite is set, replace any current value. */
685 setenv (const char *name
, const char *value
, int overwrite
)
689 if (!name
|| !*name
|| strchr (name
, '='))
694 return _addenv (name
, value
, !!overwrite
);
701 /* Delete environment variable "name". */
703 unsetenv (const char *name
)
710 if (!name
|| *name
== '\0' || strchr (name
, '='))
716 while (my_findenv (name
, &offset
)) /* if set multiple times */
717 /* Move up the rest of the array */
718 for (e
= environ
+ offset
; ; e
++)
719 if (!(*e
= *(e
+ 1)))
729 /* Clear the environment. */
735 if (environ
== lastenviron
)
748 /* Minimal list of Windows vars which must be converted to uppercase.
749 Either for POSIX compatibility of for backward compatibility with
750 existing applications. */
753 const size_t namelen
;
755 { NL("COMMONPROGRAMFILES=") }, // 0
757 { NL("PATH=") }, // 2
758 { NL("PROGRAMFILES=") },
759 { NL("SYSTEMDRIVE=") }, // 4
760 { NL("SYSTEMROOT=") },
761 { NL("TEMP=") }, // 6
763 { NL("WINDIR=") } // 8
765 #define RENV_SIZE (sizeof (renv_arr) / sizeof (renv_arr[0]))
767 /* Set of first characters of the above list of variables. */
768 static const char idx_arr
[] = "CPSTW";
769 /* Index into renv_arr at which the variables with this specific character
771 static const int start_at
[] = { 0, 2, 4, 6, 8 };
773 /* Turn environment variable part of a=b string into uppercase - for some
774 environment variables only. */
775 static __inline__
void
776 ucenv (char *p
, const char *eq
)
778 /* Hopefully as quickly as possible - only upper case specific set of important
779 Windows variables. */
780 char first
= cyg_toupper (*p
);
781 const char *idx
= strchr (idx_arr
, first
);
783 for (size_t i
= start_at
[idx
- idx_arr
];
784 i
< RENV_SIZE
&& renv_arr
[i
].name
[0] == first
;
786 if (strncasematch (p
, renv_arr
[i
].name
, renv_arr
[i
].namelen
))
788 strncpy (p
, renv_arr
[i
].name
, renv_arr
[i
].namelen
);
793 /* Initialize the environ array. Look for the CYGWIN environment variable and
794 set appropriate options from it. */
796 environ_init (char **envp
, int envc
)
809 envc
*= sizeof (char *);
810 char **newenv
= (char **) malloc (envc
);
811 memcpy (newenv
, envp
, envc
);
814 /* Older applications relied on the fact that cygwin malloced elements of the
821 rawenv
= GetEnvironmentStringsW ();
824 system_printf ("GetEnvironmentStrings returned NULL, %E");
827 debug_printf ("GetEnvironmentStrings returned %p", rawenv
);
829 lastenviron
= envp
= win32env_to_cygenv (rawenv
, true);
831 FreeEnvironmentStringsW (rawenv
);
834 findenv_func
= (char * (*)(const char*, int*)) my_findenv
;
839 p
= getenv ("CYGWIN");
846 api_fatal ("internal error reading the windows environment "
847 "- too many environment variables?");
855 win32env_to_cygenv (PWCHAR rawenv
, bool posify
)
862 const char cygterm
[] = "TERM=cygwin";
863 const char xterm
[] = "TERM=xterm-256color";
864 char *tmpbuf
= tp
.t_get ();
867 /* Allocate space for environment + trailing NULL + CYGWIN env. */
868 envp
= (char **) malloc ((4 + (envc
= 100)) * sizeof (char *));
870 /* Current directory information is recorded as variables of the
871 form "=X:=X:\foo\bar; these must be changed into something legal
872 (we could just ignore them but maybe an application will
873 eventually want to use them). */
874 for (i
= 0, w
= rawenv
; *w
!= L
'\0'; w
= wcschr (w
, L
'\0') + 1, i
++)
876 sys_wcstombs_alloc_no_path (&newp
, HEAP_NOTHEAP
, w
);
878 envp
= (char **) realloc (envp
, (4 + (envc
+= 100)) * sizeof (char *));
882 char *eq
= strchrnul (newp
, '=');
883 ucenv (newp
, eq
); /* uppercase env vars which need it */
884 if (*newp
== 'T' && strncmp (newp
, "TERM=", 5) == 0)
886 else if (*newp
== 'C' && strncmp (newp
, "CYGWIN=", 7) == 0)
887 parse_options (newp
+ 7);
889 posify_maybe (envp
+ i
, *++eq
? eq
: --eq
, tmpbuf
);
890 debug_printf ("%p: %s", envp
[i
], envp
[i
]);
893 /* If console has 24 bit color capability, TERM=xterm-256color,
894 otherwise, TERM=cygwin */
896 envp
[i
++] = strdup (wincap
.has_con_24bit_colors () ? xterm
: cygterm
);
902 /* Function called by qsort to sort environment strings. */
904 env_sort (const void *a
, const void *b
)
906 const char **p
= (const char **) a
;
907 const char **q
= (const char **) b
;
909 return strcmp (*p
, *q
);
913 getwinenveq (const char *name
, size_t namelen
, int x
)
915 WCHAR name0
[namelen
- 1];
916 WCHAR valbuf
[32768]; /* Max size of an env.var including trailing '\0'. */
918 name0
[sys_mbstowcs (name0
, sizeof name0
, name
, namelen
- 1)] = L
'\0';
919 int totlen
= GetEnvironmentVariableW (name0
, valbuf
, 32768);
922 totlen
= sys_wcstombs_no_path (NULL
, 0, valbuf
) + 1;
927 char *p
= (char *) cmalloc_abort ((cygheap_types
) x
, totlen
);
930 sys_wcstombs_no_path (p
+ namelen
, totlen
, valbuf
);
931 debug_printf ("using value from GetEnvironmentVariable for '%W'", name0
);
935 debug_printf ("warning: %s not present in environment", name
);
943 bool force_into_environment
; /* If true, always add to env if missing */
944 bool add_if_exists
; /* if true, retrieve value from cache */
945 const char * (cygheap_user::*from_cygheap
) (const char *, size_t);
947 char *retrieve (bool, const char * const = NULL
);
950 #define env_dontadd almost_null
952 /* Keep this list in upper case and sorted */
953 static NO_COPY spenv spenvs
[] =
956 {NL ("CYGWIN_DEBUG="), false, true, NULL
},
958 {NL ("HOMEDRIVE="), false, false, &cygheap_user::env_homedrive
},
959 {NL ("HOMEPATH="), false, false, &cygheap_user::env_homepath
},
960 {NL ("LOGONSERVER="), false, false, &cygheap_user::env_logsrv
},
961 {NL ("PATH="), false, true, NULL
},
962 {NL ("SYSTEMDRIVE="), false, true, NULL
},
963 {NL ("SYSTEMROOT="), true, true, &cygheap_user::env_systemroot
},
964 {NL ("USERDOMAIN="), false, false, &cygheap_user::env_domain
},
965 {NL ("USERNAME="), false, false, &cygheap_user::env_name
},
966 {NL ("USERPROFILE="), false, false, &cygheap_user::env_userprofile
},
967 {NL ("WINDIR="), true, true, &cygheap_user::env_systemroot
}
971 spenv::retrieve (bool no_envblock
, const char *const env
)
973 if (env
&& !ascii_strncasematch (env
, name
, namelen
))
976 debug_printf ("no_envblock %d", no_envblock
);
981 if (env
&& !cygheap
->user
.issetuid ())
983 debug_printf ("duping existing value for '%s'", name
);
984 /* Don't really care what it's set to if we're calling a cygwin program */
985 return cstrdup1 (env
);
988 /* Calculate (potentially) value for given environment variable. */
989 p
= (cygheap
->user
.*from_cygheap
) (name
, namelen
);
990 if (!p
|| (no_envblock
&& !env
) || (p
== env_dontadd
))
992 char *s
= (char *) cmalloc_abort (HEAP_1_STR
, namelen
+ strlen (p
) + 1);
994 strcpy (s
+ namelen
, p
);
995 debug_printf ("using computed value for '%s'", name
);
1000 return cstrdup1 (env
);
1002 return getwinenveq (name
, namelen
, HEAP_1_STR
);
1006 raise_envblock (int new_tl
, PWCHAR
&envblock
, PWCHAR
&s
)
1008 int tl
= new_tl
+ 100;
1009 PWCHAR new_envblock
=
1010 (PWCHAR
) realloc (envblock
, (2 + tl
) * sizeof (WCHAR
));
1011 /* If realloc moves the block, move `s' with it. */
1012 if (new_envblock
!= envblock
)
1014 s
+= new_envblock
- envblock
;
1015 envblock
= new_envblock
;
1020 #define SPENVS_SIZE (sizeof (spenvs) / sizeof (spenvs[0]))
1023 env_compare (const void *key
, const void *memb
)
1025 const char *k
= *(const char **) key
;
1026 const char *m
= *(const char **) memb
;
1028 char *ke
= strchr (k
, '=');
1029 char *me
= strchr (m
, '=');
1030 if (ke
== NULL
|| me
== NULL
)
1031 return strcasecmp (k
, m
);
1032 int ret
= strncasecmp (k
, m
, MIN (ke
- k
, me
- m
));
1034 ret
= (ke
- k
) - (me
- m
);
1038 /* Create a Windows-style environment block, i.e. a typical character buffer
1039 filled with null terminated strings, terminated by double null characters.
1040 Converts environment variables noted in conv_envvars into win32 form
1041 prior to placing them in the string.
1043 If new_token is set, we're going to switch the user account in
1044 child_info_spawn::worker. If so, we're also fetching the Windows default
1045 environment for the new user, and merge it into the environment we propage
1048 build_env (const char * const *envp
, PWCHAR
&envblock
, int &envc
,
1049 bool no_envblock
, HANDLE new_token
)
1051 PWCHAR cwinenv
= NULL
;
1053 char **winenv
= NULL
;
1056 const char * const *srcp
;
1058 bool saw_spenv
[SPENVS_SIZE
] = {0};
1060 static char *const empty_env
[] = { NULL
};
1062 debug_printf ("envp %p", envp
);
1067 /* How many elements? */
1068 for (n
= 0; envp
[n
]; n
++)
1071 /* Fetch windows env and convert to POSIX-style env. */
1073 && CreateEnvironmentBlock ((LPVOID
*) &cwinenv
, new_token
, FALSE
))
1075 PWCHAR var
= cwinenv
;
1079 var
= wcschr (var
, L
'\0') + 1;
1081 winenv
= (char **) calloc (winnum
+ 1, sizeof (char *));
1084 for (winnum
= 0, var
= cwinenv
;
1086 ++winnum
, var
= wcschr (var
, L
'\0') + 1)
1087 sys_wcstombs_alloc_no_path (&winenv
[winnum
], HEAP_NOTHEAP
, var
);
1089 DestroyEnvironmentBlock (cwinenv
);
1090 /* Eliminate variables which are already available in envp, as well as
1091 the small set of crucial variables needing POSIX conversion and
1092 potentially collide. The windows env is sorted, so we can use
1093 bsearch. We're doing this first step, so the following code doesn't
1094 allocate too much memory. */
1097 for (srcp
= envp
; *srcp
; srcp
++)
1099 char **elem
= (char **) bsearch (srcp
, winenv
, winnum
,
1100 sizeof *winenv
, env_compare
);
1104 /* Use memmove to keep array sorted.
1105 winnum - (elem - winenv) copies all elements following
1106 elem, including the trailing NULL pointer. */
1107 memmove (elem
, elem
+ 1,
1108 (winnum
- (elem
- winenv
)) * sizeof *elem
);
1112 for (char **elem
= winenv
; *elem
; elem
++)
1114 if (match_first_char (*elem
, WC
))
1115 for (int i
= 0; conv_envvars
[i
].name
!= NULL
; i
++)
1116 if (strncmp (*elem
, conv_envvars
[i
].name
,
1117 conv_envvars
[i
].namelen
) == 0)
1120 memmove (elem
, elem
+ 1,
1121 (winnum
- (elem
- winenv
)) * sizeof *elem
);
1129 /* Allocate a new "argv-style" environ list with room for extra stuff. */
1130 char **newenv
= (char **) cmalloc_abort (HEAP_1_ARGV
, sizeof (char *) *
1131 (n
+ winnum
+ SPENVS_SIZE
+ 1));
1135 char **pass_env
= (char **) alloca (sizeof (char *)
1136 * (n
+ winnum
+ SPENVS_SIZE
+ 1));
1137 /* Iterate over input list, generating a new environment list and refreshing
1138 "special" entries, if necessary. */
1139 for (srcp
= envp
, dstp
= newenv
, pass_dstp
= pass_env
; *srcp
; srcp
++)
1141 bool calc_tl
= !no_envblock
;
1142 /* Look for entries that require special attention */
1143 for (unsigned i
= 0; i
< SPENVS_SIZE
; i
++)
1144 if (!saw_spenv
[i
] && (*dstp
= spenvs
[i
].retrieve (no_envblock
, *srcp
)))
1147 if (*dstp
== env_dontadd
)
1149 if (spenvs
[i
].add_if_exists
)
1154 /* Add entry to new environment */
1155 *dstp
= cstrdup1 (*srcp
);
1160 *pass_dstp
++ = *dstp
;
1161 tl
+= strlen (*dstp
) + 1;
1168 assert ((srcp
- envp
) == n
);
1169 /* Fill in any required-but-missing environment variables. */
1170 for (unsigned i
= 0; i
< SPENVS_SIZE
; i
++)
1171 if (!saw_spenv
[i
] && (spenvs
[i
].force_into_environment
1172 || cygheap
->user
.issetuid ()))
1174 *dstp
= spenvs
[i
].retrieve (false);
1175 if (*dstp
&& *dstp
!= env_dontadd
)
1177 *pass_dstp
++ = *dstp
;
1178 tl
+= strlen (*dstp
) + 1;
1179 /* Eliminate from winenv. */
1182 char **elem
= (char **) bsearch (dstp
, winenv
, winnum
,
1183 sizeof *winenv
, env_compare
);
1187 memmove (elem
, elem
+ 1,
1188 (winnum
- (elem
- winenv
)) * sizeof *elem
);
1196 /* Fill in any Windows environment vars still missing. */
1200 for (elem
= winenv
; *elem
; ++elem
)
1202 *dstp
= cstrdup1 (*elem
);
1204 *pass_dstp
++ = *dstp
;
1205 tl
+= strlen (*dstp
) + 1;
1211 envc
= dstp
- newenv
; /* Number of entries in newenv */
1212 assert ((size_t) envc
<= (n
+ winnum
+ SPENVS_SIZE
));
1213 *dstp
= NULL
; /* Terminate */
1215 size_t pass_envc
= pass_dstp
- pass_env
;
1221 debug_printf ("env count %ld, bytes %d", pass_envc
, tl
);
1225 /* Windows programs expect the environment block to be sorted. */
1226 qsort (pass_env
, pass_envc
, sizeof (char *), env_sort
);
1228 /* Create an environment block suitable for passing to CreateProcess. */
1230 envblock
= (PWCHAR
) malloc ((2 + tl
) * sizeof (WCHAR
));
1232 bool saw_PATH
= false;
1233 for (srcp
= pass_env
, s
= envblock
; *srcp
; srcp
++)
1237 len
= strcspn (*srcp
, "=") + 1;
1238 const char *rest
= *srcp
+ len
;
1240 /* Check for a bad entry. This is necessary to get rid of empty
1241 strings, induced by putenv and changing the string afterwards.
1242 Note that this doesn't stop invalid strings without '=' in it
1243 etc., but we're opting for speed here for now. Adding complete
1244 checking would be pretty expensive. */
1245 if (len
== 1 || !*rest
)
1248 /* See if this entry requires posix->win32 conversion. */
1249 conv
= getwinenv (*srcp
, rest
, &temp
);
1252 p
= conv
->native
; /* Use win32 path */
1253 /* Does PATH exist in the environment? */
1256 /* And is it non-empty? */
1257 if (!conv
->native
|| !conv
->native
[0])
1263 p
= *srcp
; /* Don't worry about it */
1265 len
= sys_mbstowcs (NULL
, 0, p
);
1266 new_tl
+= len
; /* Keep running total of block length so far */
1268 /* See if we need to increase the size of the block. */
1270 tl
= raise_envblock (new_tl
, envblock
, s
);
1272 len
= sys_mbstowcs (s
, len
, p
);
1274 /* See if environment variable is "special" in a Windows sense.
1275 Under NT, the current directories for visited drives are stored
1276 as =C:=\bar. Cygwin converts the '=' to '!' for hopefully obvious
1277 reasons. We need to convert it back when building the envblock */
1278 if (s
[0] == L
'!' && (iswdrive (s
+ 1) || (s
[1] == L
':' && s
[2] == L
':'))
1283 /* If PATH doesn't exist in the environment, add a PATH with just
1284 Cygwin's bin dir to the Windows env to allow loading system DLLs
1288 new_tl
+= cygheap
->installation_dir
.Length
/ sizeof (WCHAR
) + 5 + 1;
1290 tl
= raise_envblock (new_tl
, envblock
, s
);
1291 s
= wcpcpy (wcpcpy (s
, L
"PATH="),
1292 cygheap
->installation_dir
.Buffer
) + 1;
1294 *s
= L
'\0'; /* Two null bytes at the end */
1295 assert ((s
- envblock
) <= tl
); /* Detect if we somehow ran over end
1299 debug_printf ("envp %p, envc %d", newenv
, envc
);