Fix typos.
[kopensolaris-gnu/glibc.git] / locale / findlocale.c
index d73ba4a..e2fdd06 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996 Free Software Foundation, Inc.
+/* 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.
 
 #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:
 
@@ -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)
@@ -184,5 +179,77 @@ _nl_find_locale (const char *locale_path, size_t locale_path_len,
     }
   *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);