• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* GLIB - Library of useful routines for C programming
2  * Copyright (C) 1995-1998  Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 /*
19  * Modified by the GLib Team and others 1997-2000.  See the AUTHORS
20  * file for a list of people on the GLib Team.  See the ChangeLog
21  * files for a list of changes.  These files are distributed with
22  * GLib at ftp://ftp.gtk.org/pub/gtk/.
23  */
24 
25 #include "config.h"
26 
27 #include "genviron.h"
28 
29 #include <stdlib.h>
30 #include <string.h>
31 #ifdef HAVE_CRT_EXTERNS_H
32 #include <crt_externs.h> /* for _NSGetEnviron */
33 #endif
34 #ifdef G_OS_WIN32
35 #include <windows.h>
36 #endif
37 
38 #include "glib-private.h"
39 #include "gmem.h"
40 #include "gmessages.h"
41 #include "gstrfuncs.h"
42 #include "gunicode.h"
43 #include "gconvert.h"
44 #include "gquark.h"
45 #include "gthreadprivate.h"
46 
47 /* Environ array functions {{{1 */
48 static gboolean
g_environ_matches(const gchar * env,const gchar * variable,gsize len)49 g_environ_matches (const gchar *env, const gchar *variable, gsize len)
50 {
51 #ifdef G_OS_WIN32
52     /* TODO handle Unicode environment variable names */
53     /* Like filesystem paths, environment variables are case-insensitive. */
54     return g_ascii_strncasecmp (env, variable, len) == 0 && env[len] == '=';
55 #else
56     return strncmp (env, variable, len) == 0 && env[len] == '=';
57 #endif
58 }
59 
60 static gint
g_environ_find(gchar ** envp,const gchar * variable)61 g_environ_find (gchar       **envp,
62                 const gchar  *variable)
63 {
64   gsize len;
65   gint i;
66 
67   if (envp == NULL)
68     return -1;
69 
70   len = strlen (variable);
71 
72   for (i = 0; envp[i]; i++)
73     {
74       if (g_environ_matches (envp[i], variable, len))
75         return i;
76     }
77 
78   return -1;
79 }
80 
81 /**
82  * g_environ_getenv:
83  * @envp: (nullable) (array zero-terminated=1) (transfer none) (element-type filename):
84  *     an environment list (eg, as returned from g_get_environ()), or %NULL
85  *     for an empty environment list
86  * @variable: (type filename): the environment variable to get
87  *
88  * Returns the value of the environment variable @variable in the
89  * provided list @envp.
90  *
91  * Returns: (type filename): the value of the environment variable, or %NULL if
92  *     the environment variable is not set in @envp. The returned
93  *     string is owned by @envp, and will be freed if @variable is
94  *     set or unset again.
95  *
96  * Since: 2.32
97  */
98 const gchar *
g_environ_getenv(gchar ** envp,const gchar * variable)99 g_environ_getenv (gchar       **envp,
100                   const gchar  *variable)
101 {
102   gint index;
103 
104   g_return_val_if_fail (variable != NULL, NULL);
105 
106   index = g_environ_find (envp, variable);
107   if (index != -1)
108     return envp[index] + strlen (variable) + 1;
109   else
110     return NULL;
111 }
112 
113 /**
114  * g_environ_setenv:
115  * @envp: (nullable) (array zero-terminated=1) (element-type filename) (transfer full):
116  *     an environment list that can be freed using g_strfreev() (e.g., as
117  *     returned from g_get_environ()), or %NULL for an empty
118  *     environment list
119  * @variable: (type filename): the environment variable to set, must not
120  *     contain '='
121  * @value: (type filename): the value for to set the variable to
122  * @overwrite: whether to change the variable if it already exists
123  *
124  * Sets the environment variable @variable in the provided list
125  * @envp to @value.
126  *
127  * Returns: (array zero-terminated=1) (element-type filename) (transfer full):
128  *     the updated environment list. Free it using g_strfreev().
129  *
130  * Since: 2.32
131  */
132 gchar **
g_environ_setenv(gchar ** envp,const gchar * variable,const gchar * value,gboolean overwrite)133 g_environ_setenv (gchar       **envp,
134                   const gchar  *variable,
135                   const gchar  *value,
136                   gboolean      overwrite)
137 {
138   gint index;
139 
140   g_return_val_if_fail (variable != NULL, NULL);
141   g_return_val_if_fail (strchr (variable, '=') == NULL, NULL);
142   g_return_val_if_fail (value != NULL, NULL);
143 
144   index = g_environ_find (envp, variable);
145   if (index != -1)
146     {
147       if (overwrite)
148         {
149           g_free (envp[index]);
150           envp[index] = g_strdup_printf ("%s=%s", variable, value);
151         }
152     }
153   else
154     {
155       gint length;
156 
157       length = envp ? g_strv_length (envp) : 0;
158       envp = g_renew (gchar *, envp, length + 2);
159       envp[length] = g_strdup_printf ("%s=%s", variable, value);
160       envp[length + 1] = NULL;
161     }
162 
163   return envp;
164 }
165 
166 static gchar **
g_environ_unsetenv_internal(gchar ** envp,const gchar * variable,gboolean free_value)167 g_environ_unsetenv_internal (gchar        **envp,
168                              const gchar   *variable,
169                              gboolean       free_value)
170 {
171   gsize len;
172   gchar **e, **f;
173 
174   len = strlen (variable);
175 
176   /* Note that we remove *all* environment entries for
177    * the variable name, not just the first.
178    */
179   e = f = envp;
180   while (*e != NULL)
181     {
182       if (!g_environ_matches (*e, variable, len))
183         {
184           *f = *e;
185           f++;
186         }
187       else
188         {
189           if (free_value)
190             g_free (*e);
191         }
192 
193       e++;
194     }
195   *f = NULL;
196 
197   return envp;
198 }
199 
200 
201 /**
202  * g_environ_unsetenv:
203  * @envp: (nullable) (array zero-terminated=1) (element-type filename) (transfer full):
204  *     an environment list that can be freed using g_strfreev() (e.g., as
205  *     returned from g_get_environ()), or %NULL for an empty environment list
206  * @variable: (type filename): the environment variable to remove, must not
207  *     contain '='
208  *
209  * Removes the environment variable @variable from the provided
210  * environment @envp.
211  *
212  * Returns: (array zero-terminated=1) (element-type filename) (transfer full):
213  *     the updated environment list. Free it using g_strfreev().
214  *
215  * Since: 2.32
216  */
217 gchar **
g_environ_unsetenv(gchar ** envp,const gchar * variable)218 g_environ_unsetenv (gchar       **envp,
219                     const gchar  *variable)
220 {
221   g_return_val_if_fail (variable != NULL, NULL);
222   g_return_val_if_fail (strchr (variable, '=') == NULL, NULL);
223 
224   if (envp == NULL)
225     return NULL;
226 
227   return g_environ_unsetenv_internal (envp, variable, TRUE);
228 }
229 
230 /* UNIX implementation {{{1 */
231 #ifndef G_OS_WIN32
232 
233 /**
234  * g_getenv:
235  * @variable: (type filename): the environment variable to get
236  *
237  * Returns the value of an environment variable.
238  *
239  * On UNIX, the name and value are byte strings which might or might not
240  * be in some consistent character set and encoding. On Windows, they are
241  * in UTF-8.
242  * On Windows, in case the environment variable's value contains
243  * references to other environment variables, they are expanded.
244  *
245  * Returns: (type filename): the value of the environment variable, or %NULL if
246  *     the environment variable is not found. The returned string
247  *     may be overwritten by the next call to g_getenv(), g_setenv()
248  *     or g_unsetenv().
249  */
250 const gchar *
g_getenv(const gchar * variable)251 g_getenv (const gchar *variable)
252 {
253   g_return_val_if_fail (variable != NULL, NULL);
254 
255   return getenv (variable);
256 }
257 
258 /**
259  * g_setenv:
260  * @variable: (type filename): the environment variable to set, must not
261  *     contain '='.
262  * @value: (type filename): the value for to set the variable to.
263  * @overwrite: whether to change the variable if it already exists.
264  *
265  * Sets an environment variable. On UNIX, both the variable's name and
266  * value can be arbitrary byte strings, except that the variable's name
267  * cannot contain '='. On Windows, they should be in UTF-8.
268  *
269  * Note that on some systems, when variables are overwritten, the memory
270  * used for the previous variables and its value isn't reclaimed.
271  *
272  * You should be mindful of the fact that environment variable handling
273  * in UNIX is not thread-safe, and your program may crash if one thread
274  * calls g_setenv() while another thread is calling getenv(). (And note
275  * that many functions, such as gettext(), call getenv() internally.)
276  * This function is only safe to use at the very start of your program,
277  * before creating any other threads (or creating objects that create
278  * worker threads of their own).
279  *
280  * If you need to set up the environment for a child process, you can
281  * use g_get_environ() to get an environment array, modify that with
282  * g_environ_setenv() and g_environ_unsetenv(), and then pass that
283  * array directly to execvpe(), g_spawn_async(), or the like.
284  *
285  * Returns: %FALSE if the environment variable couldn't be set.
286  *
287  * Since: 2.4
288  */
289 gboolean
g_setenv(const gchar * variable,const gchar * value,gboolean overwrite)290 g_setenv (const gchar *variable,
291           const gchar *value,
292           gboolean     overwrite)
293 {
294   gint result;
295 #ifndef HAVE_SETENV
296   gchar *string;
297 #endif
298 
299   g_return_val_if_fail (variable != NULL, FALSE);
300   g_return_val_if_fail (strchr (variable, '=') == NULL, FALSE);
301   g_return_val_if_fail (value != NULL, FALSE);
302 
303 #ifndef G_DISABLE_CHECKS
304   /* FIXME: This will be upgraded to a g_warning() in a future release of GLib.
305    * See https://gitlab.gnome.org/GNOME/glib/issues/715 */
306   if (g_thread_n_created () > 0)
307     g_debug ("setenv()/putenv() are not thread-safe and should not be used after threads are created");
308 #endif
309 
310 #ifdef HAVE_SETENV
311   result = setenv (variable, value, overwrite);
312 #else
313   if (!overwrite && getenv (variable) != NULL)
314     return TRUE;
315 
316   /* This results in a leak when you overwrite existing
317    * settings. It would be fairly easy to fix this by keeping
318    * our own parallel array or hash table.
319    */
320   string = g_strconcat (variable, "=", value, NULL);
321   result = putenv (string);
322 #endif
323   return result == 0;
324 }
325 
326 #ifdef HAVE__NSGETENVIRON
327 #define environ (*_NSGetEnviron())
328 #else
329 /* According to the Single Unix Specification, environ is not
330  * in any system header, although unistd.h often declares it.
331  */
332 extern char **environ;
333 #endif
334 
335 /**
336  * g_unsetenv:
337  * @variable: (type filename): the environment variable to remove, must
338  *     not contain '='
339  *
340  * Removes an environment variable from the environment.
341  *
342  * Note that on some systems, when variables are overwritten, the
343  * memory used for the previous variables and its value isn't reclaimed.
344  *
345  * You should be mindful of the fact that environment variable handling
346  * in UNIX is not thread-safe, and your program may crash if one thread
347  * calls g_unsetenv() while another thread is calling getenv(). (And note
348  * that many functions, such as gettext(), call getenv() internally.) This
349  * function is only safe to use at the very start of your program, before
350  * creating any other threads (or creating objects that create worker
351  * threads of their own).
352  *
353  * If you need to set up the environment for a child process, you can
354  * use g_get_environ() to get an environment array, modify that with
355  * g_environ_setenv() and g_environ_unsetenv(), and then pass that
356  * array directly to execvpe(), g_spawn_async(), or the like.
357  *
358  * Since: 2.4
359  */
360 void
g_unsetenv(const gchar * variable)361 g_unsetenv (const gchar *variable)
362 {
363   g_return_if_fail (variable != NULL);
364   g_return_if_fail (strchr (variable, '=') == NULL);
365 
366 #ifndef G_DISABLE_CHECKS
367   /* FIXME: This will be upgraded to a g_warning() in a future release of GLib.
368    * See https://gitlab.gnome.org/GNOME/glib/issues/715 */
369   if (g_thread_n_created () > 0)
370     g_debug ("unsetenv() is not thread-safe and should not be used after threads are created");
371 #endif
372 
373 #ifdef HAVE_UNSETENV
374   unsetenv (variable);
375 #else /* !HAVE_UNSETENV */
376   /* Mess directly with the environ array.
377    * This seems to be the only portable way to do this.
378    */
379   g_environ_unsetenv_internal (environ, variable, FALSE);
380 #endif /* !HAVE_UNSETENV */
381 }
382 
383 /**
384  * g_listenv:
385  *
386  * Gets the names of all variables set in the environment.
387  *
388  * Programs that want to be portable to Windows should typically use
389  * this function and g_getenv() instead of using the environ array
390  * from the C library directly. On Windows, the strings in the environ
391  * array are in system codepage encoding, while in most of the typical
392  * use cases for environment variables in GLib-using programs you want
393  * the UTF-8 encoding that this function and g_getenv() provide.
394  *
395  * Returns: (array zero-terminated=1) (element-type filename) (transfer full):
396  *     a %NULL-terminated list of strings which must be freed with
397  *     g_strfreev().
398  *
399  * Since: 2.8
400  */
401 gchar **
g_listenv(void)402 g_listenv (void)
403 {
404   gchar **result, *eq;
405   gint len, i, j;
406 
407   len = g_strv_length (environ);
408   result = g_new0 (gchar *, len + 1);
409 
410   j = 0;
411   for (i = 0; i < len; i++)
412     {
413       eq = strchr (environ[i], '=');
414       if (eq)
415         result[j++] = g_strndup (environ[i], eq - environ[i]);
416     }
417 
418   result[j] = NULL;
419 
420   return result;
421 }
422 
423 /**
424  * g_get_environ:
425  *
426  * Gets the list of environment variables for the current process.
427  *
428  * The list is %NULL terminated and each item in the list is of the
429  * form 'NAME=VALUE'.
430  *
431  * This is equivalent to direct access to the 'environ' global variable,
432  * except portable.
433  *
434  * The return value is freshly allocated and it should be freed with
435  * g_strfreev() when it is no longer needed.
436  *
437  * Returns: (array zero-terminated=1) (element-type filename) (transfer full):
438  *     the list of environment variables
439  *
440  * Since: 2.28
441  */
442 gchar **
g_get_environ(void)443 g_get_environ (void)
444 {
445   return g_strdupv (environ);
446 }
447 
448 /* Win32 implementation {{{1 */
449 #else   /* G_OS_WIN32 */
450 
451 const gchar *
g_getenv(const gchar * variable)452 g_getenv (const gchar *variable)
453 {
454   GQuark quark;
455   gchar *value;
456   wchar_t dummy[2], *wname, *wvalue;
457   int len;
458 
459   g_return_val_if_fail (variable != NULL, NULL);
460   g_return_val_if_fail (g_utf8_validate (variable, -1, NULL), NULL);
461 
462   /* On Windows NT, it is relatively typical that environment
463    * variables contain references to other environment variables. If
464    * so, use ExpandEnvironmentStrings(). (In an ideal world, such
465    * environment variables would be stored in the Registry as
466    * REG_EXPAND_SZ type values, and would then get automatically
467    * expanded before a program sees them. But there is broken software
468    * that stores environment variables as REG_SZ values even if they
469    * contain references to other environment variables.)
470    */
471 
472   wname = g_utf8_to_utf16 (variable, -1, NULL, NULL, NULL);
473 
474   len = GetEnvironmentVariableW (wname, dummy, 2);
475 
476   if (len == 0)
477     {
478       g_free (wname);
479       if (GetLastError () == ERROR_ENVVAR_NOT_FOUND)
480         return NULL;
481 
482       quark = g_quark_from_static_string ("");
483       return g_quark_to_string (quark);
484     }
485   else if (len == 1)
486     len = 2;
487 
488   wvalue = g_new (wchar_t, len);
489 
490   if (GetEnvironmentVariableW (wname, wvalue, len) != len - 1)
491     {
492       g_free (wname);
493       g_free (wvalue);
494       return NULL;
495     }
496 
497   if (wcschr (wvalue, L'%') != NULL)
498     {
499       wchar_t *tem = wvalue;
500 
501       len = ExpandEnvironmentStringsW (wvalue, dummy, 2);
502 
503       if (len > 0)
504         {
505           wvalue = g_new (wchar_t, len);
506 
507           if (ExpandEnvironmentStringsW (tem, wvalue, len) != len)
508             {
509               g_free (wvalue);
510               wvalue = tem;
511             }
512           else
513             g_free (tem);
514         }
515     }
516 
517   value = g_utf16_to_utf8 (wvalue, -1, NULL, NULL, NULL);
518 
519   g_free (wname);
520   g_free (wvalue);
521 
522   quark = g_quark_from_string (value);
523   g_free (value);
524 
525   return g_quark_to_string (quark);
526 }
527 
528 gboolean
g_setenv(const gchar * variable,const gchar * value,gboolean overwrite)529 g_setenv (const gchar *variable,
530           const gchar *value,
531           gboolean     overwrite)
532 {
533   gboolean retval;
534   wchar_t *wname, *wvalue, *wassignment;
535   gchar *tem;
536 
537   g_return_val_if_fail (variable != NULL, FALSE);
538   g_return_val_if_fail (strchr (variable, '=') == NULL, FALSE);
539   g_return_val_if_fail (value != NULL, FALSE);
540   g_return_val_if_fail (g_utf8_validate (variable, -1, NULL), FALSE);
541   g_return_val_if_fail (g_utf8_validate (value, -1, NULL), FALSE);
542 
543   if (!overwrite && g_getenv (variable) != NULL)
544     return TRUE;
545 
546   /* We want to (if possible) set both the environment variable copy
547    * kept by the C runtime and the one kept by the system.
548    *
549    * We can't use only the C runtime's putenv or _wputenv() as that
550    * won't work for arbitrary Unicode strings in a "non-Unicode" app
551    * (with main() and not wmain()). In a "main()" app the C runtime
552    * initializes the C runtime's environment table by converting the
553    * real (wide char) environment variables to system codepage, thus
554    * breaking those that aren't representable in the system codepage.
555    *
556    * As the C runtime's putenv() will also set the system copy, we do
557    * the putenv() first, then call SetEnvironmentValueW ourselves.
558    */
559 
560   wname = g_utf8_to_utf16 (variable, -1, NULL, NULL, NULL);
561   wvalue = g_utf8_to_utf16 (value, -1, NULL, NULL, NULL);
562   tem = g_strconcat (variable, "=", value, NULL);
563   wassignment = g_utf8_to_utf16 (tem, -1, NULL, NULL, NULL);
564 
565   g_free (tem);
566   _wputenv (wassignment);
567   g_free (wassignment);
568 
569   retval = (SetEnvironmentVariableW (wname, wvalue) != 0);
570 
571   g_free (wname);
572   g_free (wvalue);
573 
574   return retval;
575 }
576 
577 void
g_unsetenv(const gchar * variable)578 g_unsetenv (const gchar *variable)
579 {
580   wchar_t *wname, *wassignment;
581   gchar *tem;
582 
583   g_return_if_fail (variable != NULL);
584   g_return_if_fail (strchr (variable, '=') == NULL);
585   g_return_if_fail (g_utf8_validate (variable, -1, NULL));
586 
587   wname = g_utf8_to_utf16 (variable, -1, NULL, NULL, NULL);
588   tem = g_strconcat (variable, "=", NULL);
589   wassignment = g_utf8_to_utf16 (tem, -1, NULL, NULL, NULL);
590 
591   g_free (tem);
592   _wputenv (wassignment);
593   g_free (wassignment);
594 
595   SetEnvironmentVariableW (wname, NULL);
596 
597   g_free (wname);
598 }
599 
600 gchar **
g_listenv(void)601 g_listenv (void)
602 {
603   gchar **result, *eq;
604   gint len = 0, j;
605   wchar_t *p, *q;
606 
607   p = (wchar_t *) GetEnvironmentStringsW ();
608   if (p != NULL)
609     {
610       q = p;
611       while (*q)
612         {
613           q += wcslen (q) + 1;
614           len++;
615         }
616     }
617   result = g_new0 (gchar *, len + 1);
618 
619   j = 0;
620   q = p;
621   while (*q)
622     {
623       result[j] = g_utf16_to_utf8 (q, -1, NULL, NULL, NULL);
624       if (result[j] != NULL)
625         {
626           eq = strchr (result[j], '=');
627           if (eq && eq > result[j])
628             {
629               *eq = '\0';
630               j++;
631             }
632           else
633             g_free (result[j]);
634         }
635       q += wcslen (q) + 1;
636     }
637   result[j] = NULL;
638   FreeEnvironmentStringsW (p);
639 
640   return result;
641 }
642 
643 gchar **
g_get_environ(void)644 g_get_environ (void)
645 {
646   gunichar2 *strings;
647   gchar **result;
648   gint i, n;
649 
650   strings = GetEnvironmentStringsW ();
651   for (n = 0, i = 0; strings[n]; i++)
652     n += wcslen (strings + n) + 1;
653 
654   result = g_new (char *, i + 1);
655   for (n = 0, i = 0; strings[n]; i++)
656     {
657       result[i] = g_utf16_to_utf8 (strings + n, -1, NULL, NULL, NULL);
658       n += wcslen (strings + n) + 1;
659     }
660   FreeEnvironmentStringsW (strings);
661   result[i] = NULL;
662 
663   return result;
664 }
665 
666 #endif  /* G_OS_WIN32 */
667 
668 #ifdef G_OS_WIN32
669 
670 /* Binary compatibility versions. Not for newly compiled code. */
671 
672 _GLIB_EXTERN const gchar *g_getenv_utf8   (const gchar  *variable);
673 _GLIB_EXTERN gboolean     g_setenv_utf8   (const gchar  *variable,
674                                            const gchar  *value,
675                                            gboolean      overwrite);
676 _GLIB_EXTERN void         g_unsetenv_utf8 (const gchar  *variable);
677 
678 const gchar *
g_getenv_utf8(const gchar * variable)679 g_getenv_utf8 (const gchar *variable)
680 {
681   return g_getenv (variable);
682 }
683 
684 gboolean
g_setenv_utf8(const gchar * variable,const gchar * value,gboolean overwrite)685 g_setenv_utf8 (const gchar *variable,
686                const gchar *value,
687                gboolean     overwrite)
688 {
689   return g_setenv (variable, value, overwrite);
690 }
691 
692 void
g_unsetenv_utf8(const gchar * variable)693 g_unsetenv_utf8 (const gchar *variable)
694 {
695   g_unsetenv (variable);
696 }
697 
698 #endif
699 
700 /* Epilogue {{{1 */
701 /* vim: set foldmethod=marker: */
702