Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'winsup/cygwin/environ.cc')
-rw-r--r--winsup/cygwin/environ.cc567
1 files changed, 567 insertions, 0 deletions
diff --git a/winsup/cygwin/environ.cc b/winsup/cygwin/environ.cc
new file mode 100644
index 000000000..249e95c99
--- /dev/null
+++ b/winsup/cygwin/environ.cc
@@ -0,0 +1,567 @@
+/* environ.cc: Cygwin-adopted functions from newlib to manipulate
+ process's environment.
+
+ Copyright 1997, 1998, 1999, 2000 Cygnus Solutions.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+#include "winsup.h"
+#include <stdlib.h>
+#include <stddef.h>
+#include <ctype.h>
+#include <fcntl.h>
+
+#define environ (*user_data->envptr)
+
+extern BOOL allow_glob;
+extern BOOL allow_ntea;
+extern BOOL strip_title_path;
+extern DWORD chunksize;
+extern BOOL oldstack;
+BOOL threadsafe;
+BOOL reset_com = TRUE;
+static BOOL envcache = TRUE;
+
+/* List of names which are converted from dos to unix
+ * on the way in and back again on the way out.
+ *
+ * PATH needs to be here because CreateProcess uses it and gdb uses
+ * CreateProcess. HOME is here because most shells use it and would be
+ * confused by Windows style path names.
+ */
+static int return_MAX_PATH (const char *) {return MAX_PATH;}
+static win_env conv_envvars[] =
+ {
+ {"PATH=", 5, NULL, NULL, cygwin_win32_to_posix_path_list,
+ cygwin_posix_to_win32_path_list,
+ cygwin_win32_to_posix_path_list_buf_size,
+ cygwin_posix_to_win32_path_list_buf_size},
+ {"HOME=", 5, NULL, NULL, cygwin_conv_to_full_posix_path, cygwin_conv_to_full_win32_path,
+ return_MAX_PATH, return_MAX_PATH},
+ {"LD_LIBRARY_PATH=", 16, NULL, NULL, cygwin_conv_to_full_posix_path,
+ cygwin_conv_to_full_win32_path, return_MAX_PATH, return_MAX_PATH},
+ {NULL}
+ };
+
+void
+win_env::add_cache (const char *in_posix, const char *in_native)
+{
+ posix = (char *) realloc (posix, strlen (in_posix) + 1);
+ strcpy (posix, in_posix);
+ if (in_native)
+ {
+ native = (char *) realloc (native, namelen + 1 + strlen (in_native));
+ (void) strcpy (native, name);
+ (void) strcpy (native + namelen, in_native);
+ }
+ else
+ {
+ native = (char *) realloc (native, namelen + 1 + win32_len (in_posix));
+ (void) strcpy (native, name);
+ towin32 (in_posix, native + namelen);
+ }
+ debug_printf ("posix %s", posix);
+ debug_printf ("native %s", native);
+}
+
+
+/* Check for a "special" environment variable name. *env is the pointer
+ * to the beginning of the environment variable name. n is the length
+ * of the name including a mandatory '='. Returns a pointer to the
+ * appropriate conversion structure.
+ */
+win_env *
+getwinenv (const char *env, const char *in_posix)
+{
+ for (int i = 0; conv_envvars[i].name != NULL; i++)
+ if (strncasematch (env, conv_envvars[i].name, conv_envvars[i].namelen))
+ {
+ win_env *we = conv_envvars + i;
+ const char *val;
+ if (!environ || !(val = in_posix ?: getenv(we->name)))
+ debug_printf ("can't set native for %s since no environ yet",
+ we->name);
+ else if (!envcache || !we->posix || strcmp (val, we->posix))
+ we->add_cache (val);
+ return we;
+ }
+ return NULL;
+}
+
+/* Convert windows path specs to POSIX, if appropriate.
+ */
+static void __stdcall
+posify (char **here, const char *value)
+{
+ char *src = *here;
+ win_env *conv;
+ int len = strcspn (src, "=") + 1;
+
+ if (!(conv = getwinenv (src)))
+ return;
+
+ /* Turn all the items from c:<foo>;<bar> into their
+ mounted equivalents - if there is one. */
+
+ char *outenv = (char *) malloc (1 + len + conv->posix_len (value));
+ memcpy (outenv, src, len);
+ conv->toposix (value, outenv + len);
+ conv->add_cache (outenv + len, value);
+
+ debug_printf ("env var converted to %s", outenv);
+ *here = outenv;
+ free (src);
+}
+
+/*
+ * my_findenv --
+ * Returns pointer to value associated with name, if any, else NULL.
+ * Sets offset to be the offset of the name/value combination in the
+ * environment array, for use by setenv(3) and unsetenv(3).
+ * Explicitly removes '=' in argument name.
+ */
+
+static char * __stdcall
+my_findenv (const char *name, int *offset)
+{
+ register int len;
+ register char **p;
+ const char *c;
+
+ c = name;
+ len = 0;
+ while (*c && *c != '=')
+ {
+ c++;
+ len++;
+ }
+
+ for (p = environ; *p; ++p)
+ if (!strncmp (*p, name, len))
+ if (*(c = *p + len) == '=')
+ {
+ *offset = p - environ;
+ return (char *) (++c);
+ }
+ return NULL;
+}
+
+/*
+ * getenv --
+ * Returns ptr to value associated with name, if any, else NULL.
+ */
+
+extern "C"
+char *
+getenv (const char *name)
+{
+ int offset;
+
+ return my_findenv (name, &offset);
+}
+
+/* putenv --
+ * Sets an environment variable
+ */
+
+extern "C"
+int
+putenv (const char *str)
+{
+ register char *p, *equal;
+ int rval;
+
+ if (!(p = strdup (str)))
+ return 1;
+ if (!(equal = index (p, '=')))
+ {
+ (void) free (p);
+ return 1;
+ }
+ *equal = '\0';
+ rval = setenv (p, equal + 1, 1);
+ (void) free (p);
+ return rval;
+}
+
+/*
+ * setenv --
+ * Set the value of the environment variable "name" to be
+ * "value". If rewrite is set, replace any current value.
+ */
+
+extern "C"
+int
+setenv (const char *name, const char *value, int rewrite)
+{
+ register char *C;
+ unsigned int l_value;
+ int offset;
+
+ if (*value == '=') /* no `=' in value */
+ ++value;
+ l_value = strlen (value);
+ if ((C = my_findenv (name, &offset)))
+ { /* find if already exists */
+ if (!rewrite)
+ return 0;
+ if (strlen (C) >= l_value)
+ { /* old larger; copy over */
+ while ((*C++ = *value++));
+ return 0;
+ }
+ }
+ else
+ { /* create new slot */
+ register int cnt;
+ register char **P;
+
+ for (P = environ, cnt = 0; *P; ++P, ++cnt)
+ ;
+ __cygwin_environ = environ = (char **) realloc ((char *) environ,
+ (size_t) (sizeof (char *) * (cnt + 2)));
+ if (!environ)
+ return -1;
+ environ[cnt + 1] = NULL;
+ offset = cnt;
+ }
+
+ for (C = (char *) name; *C && *C != '='; ++C); /* no `=' in name */
+
+ if (!(environ[offset] = /* name + `=' + value */
+ (char *) malloc ((size_t) ((int) (C - name) + l_value + 2))))
+ return -1;
+ for (C = environ[offset]; (*C = *name++) && *C != '='; ++C);
+ *C++ = '=';
+ strcpy (C, value);
+
+ win_env *spenv;
+ if ((spenv = getwinenv (environ[offset])))
+ spenv->add_cache (value);
+
+ return 0;
+}
+
+/*
+ * unsetenv(name) --
+ * Delete environment variable "name".
+ */
+
+extern "C"
+void
+unsetenv (const char *name)
+{
+ register char **P;
+ int offset;
+
+ while (my_findenv (name, &offset)) /* if set multiple times */
+ for (P = &environ[offset];; ++P)
+ if (!(*P = *(P + 1)))
+ break;
+}
+
+/* Turn environment variable part of a=b string into uppercase. */
+
+static void __inline
+ucenv (char *p, char *eq)
+{
+ /* Amazingly, NT has a case sensitive environment name list,
+ but only sometimes.
+ It's normal to have NT set your "Path" to something.
+ Later, you set "PATH" to something else. This alters "Path".
+ But if you try and do a naive getenv on "PATH" you'll get nothing.
+
+ So we upper case the labels here to prevent confusion later but
+ we only do it for the first process in a session group. */
+ for (; p < eq; p++)
+ if (islower (*p))
+ *p = toupper (*p);
+}
+
+/* Parse CYGWIN options */
+
+static NO_COPY BOOL export_settings = FALSE;
+
+enum settings
+ {
+ justset,
+ isfunc,
+ setbit,
+ set_process_state,
+ };
+
+/* The structure below is used to set up an array which is used to
+ * parse the CYGWIN environment variable or, if enabled, options from
+ * the registry.
+ */
+struct parse_thing
+ {
+ const char *name;
+ union parse_setting
+ {
+ BOOL *b;
+ DWORD *x;
+ int *i;
+ void (*func)(const char *);
+ } setting;
+
+ enum settings disposition;
+ char *remember;
+ union parse_values
+ {
+ DWORD i;
+ const char *s;
+ } values[2];
+ } known[] =
+{
+ {"binmode", {&__fmode}, justset, NULL, {{O_TEXT}, {O_BINARY}}},
+ {"envcache", {&envcache}, justset, NULL, {{TRUE}, {FALSE}}},
+ {"error_start", {func: &error_start_init}, isfunc, NULL, {{0}, {0}}},
+ {"export", {&export_settings}, justset, NULL, {{FALSE}, {TRUE}}},
+ {"forkchunk", {x: &chunksize}, justset, NULL, {{8192}, {0}}},
+ {"glob", {&allow_glob}, justset, NULL, {{FALSE}, {TRUE}}},
+ {"ntea", {&allow_ntea}, justset, NULL, {{FALSE}, {TRUE}}},
+ {"ntsec", {&allow_ntsec}, justset, NULL, {{FALSE}, {TRUE}}},
+ {"oldstack", {&oldstack}, justset, NULL, {{FALSE}, {TRUE}}},
+ {"reset_com", {&reset_com}, justset, NULL, {{FALSE}, {TRUE}}},
+ {"strip_title", {&strip_title_path}, justset, NULL, {{FALSE}, {TRUE}}},
+ {"title", {&display_title}, justset, NULL, {{FALSE}, {TRUE}}},
+ {"tty", {NULL}, set_process_state, NULL, {{0}, {PID_USETTY}}},
+ {"threadsafe", {&threadsafe}, justset, NULL, {{TRUE}, {FALSE}}},
+ {NULL, {0}, justset, 0, {{0}, {0}}}
+};
+
+/* Parse a string of the form "something=stuff somethingelse=more-stuff",
+ * silently ignoring unknown "somethings".
+ */
+static void __stdcall
+parse_options (char *buf)
+{
+ int istrue;
+ char *p;
+ parse_thing *k;
+
+ if (buf == NULL)
+ {
+ char newbuf[MAX_PATH + 7] = "CYGWIN";
+ for (k = known; k->name != NULL; k++)
+ if (k->remember)
+ {
+ strcat (strcat (newbuf, " "), k->remember);
+ free (k->remember);
+ k->remember = NULL;
+ }
+ if (!export_settings)
+ return;
+ newbuf[sizeof ("CYGWIN") - 1] = '=';
+ debug_printf ("%s", newbuf);
+ putenv (newbuf);
+ return;
+ }
+
+ buf = strcpy ((char *) alloca (strlen (buf) + 1), buf);
+ for (p = strtok (buf, " \t"); p != NULL; p = strtok (NULL, " \t"))
+ {
+ if (!(istrue = !strncasematch (p, "no", 2)))
+ p += 2;
+ else if (!(istrue = *p != '-'))
+ p++;
+
+ char ch, *eq;
+ if ((eq = strchr (p, '=')) != NULL || (eq = strchr (p, ':')) != NULL)
+ ch = *eq, *eq++ = '\0';
+ else
+ ch = 0;
+
+ for (parse_thing *k = known; k->name != NULL; k++)
+ if (strcasematch (p, k->name))
+ {
+ switch (k->disposition)
+ {
+ case isfunc:
+ k->setting.func ((!eq || !istrue) ?
+ k->values[istrue].s : eq);
+ debug_printf ("%s (called func)", k->name);
+ break;
+ case justset:
+ if (!istrue || !eq)
+ *k->setting.x = k->values[istrue].i;
+ else
+ *k->setting.x = strtol (eq, NULL, 0);
+ debug_printf ("%s %d", k->name, *k->setting.x);
+ break;
+ case set_process_state:
+ k->setting.x = &myself->process_state;
+ /* fall through */
+ case setbit:
+ *k->setting.x &= ~k->values[istrue].i;
+ if (istrue || (eq && strtol (eq, NULL, 0)))
+ *k->setting.x |= k->values[istrue].i;
+ debug_printf ("%s %x", k->name, *k->setting.x);
+ break;
+ }
+
+ if (eq)
+ *--eq = ch;
+
+ int n = eq - p;
+ p = strdup (p);
+ if (n > 0)
+ p[n] = ':';
+ k->remember = p;
+ break;
+ }
+ }
+ debug_printf ("returning");
+ return;
+}
+
+/* Set options from the registry. */
+
+static void __stdcall
+regopt (const char *name)
+{
+ MALLOC_CHECK;
+ /* FIXME: should not be under mount */
+ reg_key r (KEY_READ, CYGWIN_INFO_PROGRAM_OPTIONS_NAME, NULL);
+ char buf[MAX_PATH];
+ char lname[strlen(name) + 1];
+ strlwr (strcpy (lname, name));
+ MALLOC_CHECK;
+ if (r.get_string (lname, buf, sizeof (buf) - 1, "") == ERROR_SUCCESS)
+ parse_options (buf);
+ MALLOC_CHECK;
+}
+
+/* Initialize the environ array. Look for the CYGWIN environment
+ * environment variable and set appropriate options from it.
+ */
+void
+environ_init (void)
+{
+ const char * const rawenv = GetEnvironmentStrings ();
+ int envsize, i;
+ char *newp, **envp;
+ const char *p;
+ int sawTERM = 0;
+
+ /* Allocate space for environment + trailing NULL + CYGWIN env. */
+ envp = (char **) malloc ((4 + (envsize = 100)) * sizeof (char *));
+
+ regopt ("default");
+ if (myself->progname[0])
+ regopt (myself->progname);
+
+#ifdef NTSEC_ON_BY_DEFAULT
+ /* Set ntsec explicit as default, if NT is running */
+ if (os_being_run == winNT)
+ allow_ntsec = TRUE;
+#endif
+
+ /* Current directory information is recorded as variables of the
+ form "=X:=X:\foo\bar; these must be changed into something legal
+ (we could just ignore them but maybe an application will
+ eventually want to use them). */
+ for (i = 0, p = rawenv; *p != '\0'; p = strchr (p, '\0') + 1, i++)
+ {
+ newp = strdup (p);
+ if (i >= envsize)
+ envp = (char **) realloc (envp, (4 + (envsize += 100)) *
+ sizeof (char *));
+ envp[i] = newp;
+ if (*newp == '=')
+ *newp = '!';
+ char *eq;
+ if ((eq = strchr (newp, '=')) == NULL)
+ eq = strchr (newp, '\0');
+ if (!parent_alive)
+ ucenv (newp, eq);
+ if (strncmp (newp, "TERM=", 5) == 0)
+ sawTERM = 1;
+ if (strncmp (newp, "CYGWIN=", sizeof("CYGWIN=") - 1) == 0)
+ parse_options (newp + sizeof("CYGWIN=") - 1);
+ if (*eq)
+ posify (envp + i, *++eq ? eq : --eq);
+ debug_printf ("%s", envp[i]);
+ }
+
+ if (!sawTERM)
+ envp[i++] = strdup ("TERM=cygwin");
+ envp[i] = NULL;
+ __cygwin_environ = *user_data->envptr = envp;
+ FreeEnvironmentStringsA ((char *) rawenv);
+ parse_options (NULL);
+ MALLOC_CHECK;
+}
+
+/* Function called by qsort to sort environment strings.
+ */
+static int
+env_sort (const void *a, const void *b)
+{
+ const char **p = (const char **) a;
+ const char **q = (const char **) b;
+
+ return strcmp (*p, *q);
+}
+
+/* Create a Windows-style environment block, i.e. a typical character buffer
+ * filled with null terminated strings, terminated by double null characters.
+ * Converts environment variables noted in conv_envvars into win32 form
+ * prior to placing them in the string.
+ */
+char *
+winenv (const char * const *envp)
+{
+ int len, n, tl;
+ const char * const *srcp;
+ const char * *dstp;
+
+ for (n = 0; envp[n]; n++)
+ continue;
+
+ const char *newenvp[n + 1];
+
+ for (tl = 0, srcp = envp, dstp = newenvp; *srcp; srcp++, dstp++)
+ {
+ len = strcspn (*srcp, "=") + 1;
+ win_env *conv;
+
+ if ((conv = getwinenv (*srcp, *srcp + len)))
+ *dstp = conv->native;
+ else
+ *dstp = *srcp;
+ tl += strlen (*dstp) + 1;
+ if ((*dstp)[0] == '!' && isalpha((*dstp)[1]) && (*dstp)[2] == ':' &&
+ (*dstp)[3] == '=')
+ {
+ char *p = (char *) alloca (strlen (*dstp) + 1);
+ strcpy (p, *dstp);
+ *p = '=';
+ *dstp = p;
+ }
+ }
+
+ *dstp = NULL; /* Terminate */
+
+ int envlen = dstp - newenvp;
+ debug_printf ("env count %d, bytes %d", envlen, tl);
+
+ /* Windows programs expect the environment block to be sorted. */
+ qsort (newenvp, envlen, sizeof (char *), env_sort);
+
+ /* Create an environment block suitable for passing to CreateProcess. */
+ char *ptr, *envblock;
+ envblock = (char *) malloc (tl + 2);
+ for (srcp = newenvp, ptr = envblock; *srcp; srcp++)
+ {
+ len = strlen (*srcp);
+ memcpy (ptr, *srcp, len + 1);
+ ptr += len + 1;
+ }
+ *ptr = '\0'; /* Two null bytes at the end */
+
+ return envblock;
+}