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