(root)/
glibc-2.38/
locale/
setlocale.c
       1  /* Copyright (C) 1991-2023 Free Software Foundation, Inc.
       2     This file is part of the GNU C Library.
       3  
       4     The GNU C 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     The GNU C 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 the GNU C Library; if not, see
      16     <https://www.gnu.org/licenses/>.  */
      17  
      18  #include <alloca.h>
      19  #include <argz.h>
      20  #include <errno.h>
      21  #include <libc-lock.h>
      22  #include <locale.h>
      23  #include <stdlib.h>
      24  #include <string.h>
      25  #include <unistd.h>
      26  
      27  #include "localeinfo.h"
      28  
      29  #ifdef NL_CURRENT_INDIRECT
      30  
      31  /* For each category declare a special external symbol
      32     _nl_current_CATEGORY_used with a weak reference.
      33     This symbol will is defined in lc-CATEGORY.c and will be linked in
      34     if anything uses _nl_current_CATEGORY (also defined in that module).
      35     Also use a weak reference for the _nl_current_CATEGORY thread variable.  */
      36  
      37  # define DEFINE_CATEGORY(category, category_name, items, a) \
      38      extern char _nl_current_##category##_used; \
      39      weak_extern (_nl_current_##category##_used) \
      40      weak_extern (_nl_current_##category)
      41  # include "categories.def"
      42  # undef	DEFINE_CATEGORY
      43  
      44  /* Now define a table of flags based on those special weak symbols' values.
      45     _nl_current_used[CATEGORY] will be zero if _nl_current_CATEGORY is not
      46     linked in.  */
      47  static char *const _nl_current_used[] =
      48    {
      49  # define DEFINE_CATEGORY(category, category_name, items, a) \
      50      [category] = &_nl_current_##category##_used,
      51  # include "categories.def"
      52  # undef	DEFINE_CATEGORY
      53    };
      54  
      55  # define CATEGORY_USED(category)	(_nl_current_used[category] != 0)
      56  
      57  #else
      58  
      59  /* The shared library always loads all the categories,
      60     and the current global settings are kept in _nl_global_locale.  */
      61  
      62  # define CATEGORY_USED(category)	(1)
      63  
      64  #endif
      65  
      66  
      67  /* Define an array of category names (also the environment variable names).  */
      68  const struct catnamestr_t _nl_category_names attribute_hidden =
      69    {
      70  #define DEFINE_CATEGORY(category, category_name, items, a) \
      71      category_name,
      72  #include "categories.def"
      73  #undef DEFINE_CATEGORY
      74    };
      75  
      76  const uint8_t _nl_category_name_idxs[__LC_LAST] attribute_hidden =
      77    {
      78  #define DEFINE_CATEGORY(category, category_name, items, a) \
      79      [category] = offsetof (struct catnamestr_t, CATNAMEMF (__LINE__)),
      80  #include "categories.def"
      81  #undef DEFINE_CATEGORY
      82    };
      83  
      84  /* An array of their lengths, for convenience.  */
      85  const uint8_t _nl_category_name_sizes[] attribute_hidden =
      86    {
      87  #define DEFINE_CATEGORY(category, category_name, items, a) \
      88      [category] = sizeof (category_name) - 1,
      89  #include "categories.def"
      90  #undef	DEFINE_CATEGORY
      91      [LC_ALL] = sizeof ("LC_ALL") - 1
      92    };
      93  
      94  
      95  #ifdef NL_CURRENT_INDIRECT
      96  # define WEAK_POSTLOAD(postload) weak_extern (postload)
      97  #else
      98  # define WEAK_POSTLOAD(postload) /* Need strong refs in static linking.  */
      99  #endif
     100  
     101  /* Declare the postload functions used below.  */
     102  #undef	NO_POSTLOAD
     103  #define NO_POSTLOAD _nl_postload_ctype /* Harmless thing known to exist.  */
     104  #define DEFINE_CATEGORY(category, category_name, items, postload) \
     105  extern void postload (void); WEAK_POSTLOAD (postload)
     106  #include "categories.def"
     107  #undef	DEFINE_CATEGORY
     108  #undef	NO_POSTLOAD
     109  
     110  /* Define an array indexed by category of postload functions to call after
     111     loading and installing that category's data.  */
     112  static void (*const _nl_category_postload[]) (void) =
     113    {
     114  #define DEFINE_CATEGORY(category, category_name, items, postload) \
     115      [category] = postload,
     116  #include "categories.def"
     117  #undef	DEFINE_CATEGORY
     118    };
     119  
     120  
     121  /* Lock for protecting global data.  */
     122  __libc_rwlock_define_initialized (, __libc_setlocale_lock attribute_hidden)
     123  
     124  /* Defined in loadmsgcat.c.  */
     125  extern int _nl_msg_cat_cntr;
     126  
     127  
     128  /* Use this when we come along an error.  */
     129  #define ERROR_RETURN							      \
     130    do {									      \
     131      __set_errno (EINVAL);						      \
     132      return NULL;							      \
     133    } while (0)
     134  
     135  
     136  /* Construct a new composite name.  */
     137  static char *
     138  new_composite_name (int category, const char **newnames)
     139  {
     140    size_t last_len = 0;
     141    size_t cumlen = 0;
     142    int i;
     143    char *new, *p;
     144    int same = 1;
     145  
     146    for (i = 0; i < __LC_LAST; ++i)
     147      if (i != LC_ALL)
     148        {
     149  	const char *name = (category == LC_ALL ? newnames[i]
     150  			    : category == i ? newnames[0]
     151  			    : _nl_global_locale.__names[i]);
     152  	last_len = strlen (name);
     153  	cumlen += _nl_category_name_sizes[i] + 1 + last_len + 1;
     154  	if (same && name != newnames[0] && strcmp (name, newnames[0]) != 0)
     155  	  same = 0;
     156        }
     157  
     158    if (same)
     159      {
     160        /* All the categories use the same name.  */
     161        if (strcmp (newnames[0], _nl_C_name) == 0
     162  	  || strcmp (newnames[0], _nl_POSIX_name) == 0)
     163  	return (char *) _nl_C_name;
     164  
     165        new = malloc (last_len + 1);
     166  
     167        return new == NULL ? NULL : memcpy (new, newnames[0], last_len + 1);
     168      }
     169  
     170    new = malloc (cumlen);
     171    if (new == NULL)
     172      return NULL;
     173    p = new;
     174    for (i = 0; i < __LC_LAST; ++i)
     175      if (i != LC_ALL)
     176        {
     177  	/* Add "CATEGORY=NAME;" to the string.  */
     178  	const char *name = (category == LC_ALL ? newnames[i]
     179  			    : category == i ? newnames[0]
     180  			    : _nl_global_locale.__names[i]);
     181  	p = __stpcpy (p, _nl_category_names_get (i));
     182  	*p++ = '=';
     183  	p = __stpcpy (p, name);
     184  	*p++ = ';';
     185        }
     186    p[-1] = '\0';		/* Clobber the last ';'.  */
     187    return new;
     188  }
     189  
     190  
     191  /* Put NAME in _nl_global_locale.__names.  */
     192  static void
     193  setname (int category, const char *name)
     194  {
     195    if (_nl_global_locale.__names[category] == name)
     196      return;
     197  
     198    if (_nl_global_locale.__names[category] != _nl_C_name)
     199      free ((char *) _nl_global_locale.__names[category]);
     200  
     201    _nl_global_locale.__names[category] = name;
     202  }
     203  
     204  /* Put DATA in *_nl_current[CATEGORY].  */
     205  static void
     206  setdata (int category, struct __locale_data *data)
     207  {
     208    if (CATEGORY_USED (category))
     209      {
     210        _nl_global_locale.__locales[category] = data;
     211        if (_nl_category_postload[category])
     212  	(*_nl_category_postload[category]) ();
     213      }
     214  }
     215  
     216  char *
     217  setlocale (int category, const char *locale)
     218  {
     219    char *locale_path;
     220    size_t locale_path_len;
     221    const char *locpath_var;
     222    char *composite;
     223  
     224    /* Sanity check for CATEGORY argument.  */
     225    if (__builtin_expect (category, 0) < 0
     226        || __builtin_expect (category, 0) >= __LC_LAST)
     227      ERROR_RETURN;
     228  
     229    /* Does user want name of current locale?  */
     230    if (locale == NULL)
     231      return (char *) _nl_global_locale.__names[category];
     232  
     233    /* Protect global data.  */
     234    __libc_rwlock_wrlock (__libc_setlocale_lock);
     235  
     236    if (strcmp (locale, _nl_global_locale.__names[category]) == 0)
     237      {
     238        /* Changing to the same thing.  */
     239        __libc_rwlock_unlock (__libc_setlocale_lock);
     240  
     241        return (char *) _nl_global_locale.__names[category];
     242      }
     243  
     244    /* We perhaps really have to load some data.  So we determine the
     245       path in which to look for the data now.  The environment variable
     246       `LOCPATH' must only be used when the binary has no SUID or SGID
     247       bit set.  If using the default path, we tell _nl_find_locale
     248       by passing null and it can check the canonical locale archive.  */
     249    locale_path = NULL;
     250    locale_path_len = 0;
     251  
     252    locpath_var = getenv ("LOCPATH");
     253    if (locpath_var != NULL && locpath_var[0] != '\0')
     254      {
     255        if (__argz_create_sep (locpath_var, ':',
     256  			     &locale_path, &locale_path_len) != 0
     257  	  || __argz_add_sep (&locale_path, &locale_path_len,
     258  			     _nl_default_locale_path, ':') != 0)
     259  	{
     260  	  __libc_rwlock_unlock (__libc_setlocale_lock);
     261  	  return NULL;
     262  	}
     263      }
     264  
     265    if (category == LC_ALL)
     266      {
     267        /* The user wants to set all categories.  The desired locales
     268  	 for the individual categories can be selected by using a
     269  	 composite locale name.  This is a semi-colon separated list
     270  	 of entries of the form `CATEGORY=VALUE'.  */
     271        const char *newnames[__LC_LAST];
     272        struct __locale_data *newdata[__LC_LAST];
     273        /* Copy of the locale argument, for in-place splitting.  */
     274        char *locale_copy = NULL;
     275  
     276        /* Set all name pointers to the argument name.  */
     277        for (category = 0; category < __LC_LAST; ++category)
     278  	if (category != LC_ALL)
     279  	  newnames[category] = (char *) locale;
     280  
     281        if (__glibc_unlikely (strchr (locale, ';') != NULL))
     282  	{
     283  	  /* This is a composite name.  Make a copy and split it up.  */
     284  	  locale_copy = __strdup (locale);
     285  	  if (__glibc_unlikely (locale_copy == NULL))
     286  	    {
     287  	      __libc_rwlock_unlock (__libc_setlocale_lock);
     288  	      return NULL;
     289  	    }
     290  	  char *np = locale_copy;
     291  	  char *cp;
     292  	  int cnt;
     293  
     294  	  while ((cp = strchr (np, '=')) != NULL)
     295  	    {
     296  	      for (cnt = 0; cnt < __LC_LAST; ++cnt)
     297  		if (cnt != LC_ALL
     298  		    && (size_t) (cp - np) == _nl_category_name_sizes[cnt]
     299  		    && (memcmp (np, (_nl_category_names_get (cnt)), cp - np)
     300  			== 0))
     301  		  break;
     302  
     303  	      if (cnt == __LC_LAST)
     304  		{
     305  		error_return:
     306  		  __libc_rwlock_unlock (__libc_setlocale_lock);
     307  		  free (locale_copy);
     308  
     309  		  /* Bogus category name.  */
     310  		  ERROR_RETURN;
     311  		}
     312  
     313  	      /* Found the category this clause sets.  */
     314  	      newnames[cnt] = ++cp;
     315  	      cp = strchr (cp, ';');
     316  	      if (cp != NULL)
     317  		{
     318  		  /* Examine the next clause.  */
     319  		  *cp = '\0';
     320  		  np = cp + 1;
     321  		}
     322  	      else
     323  		/* This was the last clause.  We are done.  */
     324  		break;
     325  	    }
     326  
     327  	  for (cnt = 0; cnt < __LC_LAST; ++cnt)
     328  	    if (cnt != LC_ALL && newnames[cnt] == locale)
     329  	      /* The composite name did not specify all categories.  */
     330  	      goto error_return;
     331  	}
     332  
     333        /* Load the new data for each category.  */
     334        while (category-- > 0)
     335  	if (category != LC_ALL)
     336  	  {
     337  	    newdata[category] = _nl_find_locale (locale_path, locale_path_len,
     338  						 category,
     339  						 &newnames[category]);
     340  
     341  	    if (newdata[category] == NULL)
     342  	      {
     343  #ifdef NL_CURRENT_INDIRECT
     344  		if (newnames[category] == _nl_C_name)
     345  		  /* Null because it's the weak value of _nl_C_LC_FOO.  */
     346  		  continue;
     347  #endif
     348  		break;
     349  	      }
     350  
     351  	    /* We must not simply free a global locale since we have
     352  	       no control over the usage.  So we mark it as
     353  	       un-deletable.  And yes, the 'if' is needed, the data
     354  	       might be in read-only memory.  */
     355  	    if (newdata[category]->usage_count != UNDELETABLE)
     356  	      newdata[category]->usage_count = UNDELETABLE;
     357  
     358  	    /* Make a copy of locale name.  */
     359  	    if (newnames[category] != _nl_C_name)
     360  	      {
     361  		if (strcmp (newnames[category],
     362  			    _nl_global_locale.__names[category]) == 0)
     363  		  newnames[category] = _nl_global_locale.__names[category];
     364  		else
     365  		  {
     366  		    newnames[category] = __strdup (newnames[category]);
     367  		    if (newnames[category] == NULL)
     368  		      break;
     369  		  }
     370  	      }
     371  	  }
     372  
     373        /* Create new composite name.  */
     374        composite = (category >= 0
     375  		   ? NULL : new_composite_name (LC_ALL, newnames));
     376        if (composite != NULL)
     377  	{
     378  	  /* Now we have loaded all the new data.  Put it in place.  */
     379  	  for (category = 0; category < __LC_LAST; ++category)
     380  	    if (category != LC_ALL)
     381  	      {
     382  		setdata (category, newdata[category]);
     383  		setname (category, newnames[category]);
     384  	      }
     385  	  setname (LC_ALL, composite);
     386  
     387  	  /* We successfully loaded a new locale.  Let the message catalog
     388  	     functions know about this.  */
     389  	  ++_nl_msg_cat_cntr;
     390  	}
     391        else
     392  	for (++category; category < __LC_LAST; ++category)
     393  	  if (category != LC_ALL && newnames[category] != _nl_C_name
     394  	      && newnames[category] != _nl_global_locale.__names[category])
     395  	    free ((char *) newnames[category]);
     396  
     397        /* Critical section left.  */
     398        __libc_rwlock_unlock (__libc_setlocale_lock);
     399  
     400        /* Free the resources.  */
     401        free (locale_path);
     402        free (locale_copy);
     403  
     404        return composite;
     405      }
     406    else
     407      {
     408        struct __locale_data *newdata = NULL;
     409        const char *newname[1] = { locale };
     410  
     411        if (CATEGORY_USED (category))
     412  	{
     413  	  /* Only actually load the data if anything will use it.  */
     414  	  newdata = _nl_find_locale (locale_path, locale_path_len, category,
     415  				     &newname[0]);
     416  	  if (newdata == NULL)
     417  	    goto abort_single;
     418  
     419  	  /* We must not simply free a global locale since we have no
     420  	     control over the usage.  So we mark it as un-deletable.
     421  
     422  	     Note: do not remove the `if', it's necessary to cope with
     423  	     the builtin locale data.  */
     424  	  if (newdata->usage_count != UNDELETABLE)
     425  	    newdata->usage_count = UNDELETABLE;
     426  	}
     427  
     428        /* Make a copy of locale name.  */
     429        if (newname[0] != _nl_C_name)
     430  	{
     431  	  newname[0] = __strdup (newname[0]);
     432  	  if (newname[0] == NULL)
     433  	    goto abort_single;
     434  	}
     435  
     436        /* Create new composite name.  */
     437        composite = new_composite_name (category, newname);
     438        if (composite == NULL)
     439  	{
     440  	  if (newname[0] != _nl_C_name)
     441  	    free ((char *) newname[0]);
     442  
     443  	  /* Say that we don't have any data loaded.  */
     444  	abort_single:
     445  	  newname[0] = NULL;
     446  	}
     447        else
     448  	{
     449  	  if (CATEGORY_USED (category))
     450  	    setdata (category, newdata);
     451  
     452  	  setname (category, newname[0]);
     453  	  setname (LC_ALL, composite);
     454  
     455  	  /* We successfully loaded a new locale.  Let the message catalog
     456  	     functions know about this.  */
     457  	  ++_nl_msg_cat_cntr;
     458  	}
     459  
     460        /* Critical section left.  */
     461        __libc_rwlock_unlock (__libc_setlocale_lock);
     462  
     463        /* Free the resources (the locale path variable.  */
     464        free (locale_path);
     465  
     466        return (char *) newname[0];
     467      }
     468  }
     469  libc_hidden_def (setlocale)
     470  
     471  static void
     472  free_category (int category,
     473  	       struct __locale_data *here, struct __locale_data *c_data)
     474  {
     475    struct loaded_l10nfile *runp = _nl_locale_file_list[category];
     476  
     477    /* If this category is already "C" don't do anything.  */
     478    if (here != c_data)
     479      {
     480        /* We have to be prepared that sometime later we still
     481  	 might need the locale information.  */
     482        setdata (category, c_data);
     483        setname (category, _nl_C_name);
     484      }
     485  
     486    while (runp != NULL)
     487      {
     488        struct loaded_l10nfile *curr = runp;
     489        struct __locale_data *data = (struct __locale_data *) runp->data;
     490  
     491        if (data != NULL && data != c_data)
     492  	_nl_unload_locale (category, data);
     493        runp = runp->next;
     494        free ((char *) curr->filename);
     495        free (curr);
     496      }
     497  }
     498  
     499  /* This is called from iconv/gconv_db.c's free_mem, as locales must
     500     be freed before freeing gconv steps arrays.  */
     501  void
     502  _nl_locale_subfreeres (void)
     503  {
     504  #ifdef NL_CURRENT_INDIRECT
     505    /* We don't use the loop because we want to have individual weak
     506       symbol references here.  */
     507  # define DEFINE_CATEGORY(category, category_name, items, a)		      \
     508    if (CATEGORY_USED (category))						      \
     509      {									      \
     510        extern struct __locale_data _nl_C_##category;			      \
     511        weak_extern (_nl_C_##category)					      \
     512        free_category (category, *_nl_current_##category, &_nl_C_##category);   \
     513      }
     514  # include "categories.def"
     515  # undef	DEFINE_CATEGORY
     516  #else
     517    int category;
     518  
     519    for (category = 0; category < __LC_LAST; ++category)
     520      if (category != LC_ALL)
     521        free_category (category, _NL_CURRENT_DATA (category),
     522  		     _nl_C_locobj.__locales[category]);
     523  #endif
     524  
     525    setname (LC_ALL, _nl_C_name);
     526  
     527    /* This frees the data structures associated with the locale archive.
     528       The locales from the archive are not in the file list, so we have
     529       not called _nl_unload_locale on them above.  */
     530    _nl_archive_subfreeres ();
     531  }