Fix typos.
[kopensolaris-gnu/glibc.git] / locale / findlocale.c
index 5e87a33..e2fdd06 100644 (file)
@@ -1,42 +1,33 @@
-/* Copyright (C) 1996 Free Software Foundation, Inc.
-This file is part of the GNU C Library.
-Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1996.
+/* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1996.
 
-The GNU C Library is free software; you can redistribute it and/or
-modify it under the terms of the GNU Library General Public License as
-published by the Free Software Foundation; either version 2 of the
-License, or (at your option) any later version.
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
 
-The GNU C Library is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-Library General Public License for more details.
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
 
-You should have received a copy of the GNU Library General Public
-License along with the GNU C Library; see the file COPYING.LIB.  If
-not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
 
 #include <locale.h>
 #include <stdlib.h>
 #include <string.h>
+#include <unistd.h>
+#include <sys/mman.h>
 
 #include "localeinfo.h"
 
 
 /* Constant data defined in setlocale.c.  */
-extern const struct locale_data *const _nl_C[];
-
-
-static inline char *
-copy (const char *string)
-{
-  size_t len;
-  char *new;
-  len = strlen (string) + 1;
-  new = (char *) malloc (len);
-  return new != NULL ? memcpy (new, string, len) : NULL;
-}
+extern struct locale_data *const _nl_C[];
 
 
 /* For each category we keep a list of records for the locale files
@@ -44,9 +35,9 @@ copy (const char *string)
 static struct loaded_l10nfile *locale_file_list[LC_ALL];
 
 
-const struct locale_data *
+struct locale_data *
 _nl_find_locale (const char *locale_path, size_t locale_path_len,
-                int category, char **name)
+                int category, const char **name)
 {
   int mask;
   /* Name of the locale for this category.  */
@@ -61,7 +52,11 @@ _nl_find_locale (const char *locale_path, size_t locale_path_len,
   const char *revision;
   struct loaded_l10nfile *locale_file;
 
-  if ((*name)[0] == '\0')
+  if ((*name)[0] == '\0'
+      /* In SUID binaries we must not allow people to access files
+        outside the dedicated locale directories.  */
+      || (__libc_enable_secure
+         && memchr (*name, '/', _nl_find_language (*name) - *name) != NULL))
     {
       /* The user decides which locale to use by setting environment
         variables.  */
@@ -74,7 +69,7 @@ _nl_find_locale (const char *locale_path, size_t locale_path_len,
        *name = (char *) _nl_C_name;
     }
 
-  if (strcmp (*name, _nl_C_name) == 0 || strcmp (*name, "POSIX") == 0)
+  if (strcmp (*name, _nl_C_name) == 0 || strcmp (*name, _nl_POSIX_name) == 0)
     {
       /* We need not load anything.  The needed data is contained in
         the library itself.  */
@@ -88,10 +83,10 @@ _nl_find_locale (const char *locale_path, size_t locale_path_len,
   loc_name = (char *) _nl_expand_alias (*name);
   if (loc_name == NULL)
     /* It is no alias.  */
-    loc_name = *name;
+    loc_name = (char *) *name;
 
   /* Make a writable copy of the locale name.  */
-  loc_name = copy (loc_name);
+  loc_name = __strdup (loc_name);
 
   /* LOCALE can consist of up to four recognized parts for the XPG syntax:
 
@@ -99,7 +94,7 @@ _nl_find_locale (const char *locale_path, size_t locale_path_len,
 
      and six parts for the CEN syntax:
 
-       language[_territory][+audience][+special][,sponsor][_revision]
+       language[_territory][+audience][+special][,[sponsor][_revision]]
 
      Beside the first all of them are allowed to be missing.  If the
      full specified locale is not found, the less specific one are
@@ -141,9 +136,9 @@ _nl_find_locale (const char *locale_path, size_t locale_path_len,
        return NULL;
     }
   else
-    /* If the addressed locale is already available it should be freed.
-       If we would not do this switching back and force between two
-       locales would slowly eat up all memory.*/
+    /* If the addressed locale is already available it should be
+       freed.  If we would not do this switching back and force
+       between two locales would slowly eat up all memory.  */
     free ((void *) loc_name);
 
   if (locale_file->decided == 0)
@@ -170,23 +165,91 @@ _nl_find_locale (const char *locale_path, size_t locale_path_len,
 
   /* Determine the locale name for which loading succeeded.  This
      information comes from the file name.  The form is
-     <path>/<locale>/LC_foo.  We must extract this <locale> part.  */
+     <path>/<locale>/LC_foo.  We must extract the <locale> part.  */
   if (((struct locale_data *) locale_file->data)->name == NULL)
     {
-      char *newp, *cp, *endp;
+      char *cp, *endp;
 
       endp = strrchr (locale_file->filename, '/');
       cp = endp - 1;
       while (cp[-1] != '/')
        --cp;
-      newp = (char *) malloc (endp - cp + 1);
-      if (newp == NULL)
-       return NULL;
-      memcpy (newp, cp, endp - cp);
-      newp[endp - cp] = '\0';
-      ((struct locale_data *) locale_file->data)->name = newp;
+      ((struct locale_data *) locale_file->data)->name = __strndup (cp,
+                                                                   endp - cp);
     }
   *name = (char *) ((struct locale_data *) locale_file->data)->name;
 
+  /* Increment the usage count.  */
+  if (((struct locale_data *) locale_file->data)->usage_count
+      < MAX_USAGE_COUNT)
+    ++((struct locale_data *) locale_file->data)->usage_count;
+
   return (struct locale_data *) locale_file->data;
 }
+
+
+/* Calling this function assumes the lock for handling global locale data
+   is acquired.  */
+void
+_nl_remove_locale (int locale, struct locale_data *data)
+{
+  if (--data->usage_count == 0)
+    {
+      /* First search the entry in the list of loaded files.  */
+      struct loaded_l10nfile *ptr = locale_file_list[locale];
+
+      /* Search for the entry.  It must be in the list.  Otherwise it
+        is a bug and we crash badly.  */
+      while ((struct locale_data *) ptr->data != data)
+       ptr = ptr->next;
+
+      /* Mark the data as not available anymore.  So when the data has
+        to be used again it is reloaded.  */
+      ptr->decided = 0;
+      ptr->data = NULL;
+
+      /* Free the name.  */
+      free ((char *) data->name);
+
+      /* Really delete the data.  First delete the real data.  */
+      if (data->mmaped)
+       {
+         /* Try to unmap the area.  If this fails we mark the area as
+            permanent.  */
+         if (__munmap ((caddr_t) data->filedata, data->filesize) != 0)
+           {
+             data->usage_count = UNDELETABLE;
+             return;
+           }
+       }
+      else
+       /* The memory was malloced.  */
+       free ((void *) data->filedata);
+
+      /* Now free the structure itself.  */
+      free (data);
+    }
+}
+
+static void __attribute__ ((unused))
+free_mem (void)
+{
+  int locale;
+
+  for (locale = 0; locale < LC_ALL; ++locale)
+    {
+      struct loaded_l10nfile *runp = locale_file_list[locale];
+
+      while (runp != NULL)
+       {
+         struct loaded_l10nfile *here = runp;
+         struct locale_data *data = (struct locale_data *) runp->data;
+
+         if (data != NULL && data->usage_count != UNDELETABLE)
+           _nl_unload_locale (data);
+         runp = runp->next;
+         free (here);
+       }
+    }
+}
+text_set_element (__libc_subfreeres, free_mem);