[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#210460: locale -a doesn't list all available locales



Package: libc6
Version: 2.3.1

Part of the LSB Runtime Environment test suite uses checks several executables for I18n compatibility.

locale failed the following test:

tp4()
{
tet_infoline "* When -a option is specified, verify if this utility writes information about all available public locales."
       tet_infoline " "

       locale_initialize
       export LANG=$targetlocale

       locale -a >out.stdout 2>out.stderr
(grep "^C" out.stdout && grep "^${targetlocale%.*}" out.stdout) >/dev/null 2>&1
       result_output_code $? "Can't print available locales."
}

locale_initialize()
{
       unset LANG
       for var in $LCVARS
       do
          unset $var
       done
       unset LC_ALL
}

locale_posix()
{
   locale | grep "^LANG"
   locale | grep "^LC_CTYPE"
   locale | grep "^LC_TIME"
   locale | grep "^LC_COLLATE"
   locale | grep "^LC_MONETARY"
   locale | grep "^LC_MESSAGES"
   locale | grep "^LC_ALL"
}

It only lists

C
POSIX

The attached patch fixes the problem.  (modified list file included)
#! /bin/sh -e

# DP: Fixes localization stuffsorz

if [ $# -ne 2 ]; then
echo >&2 "`basename $0`: script expects -patch|-unpatch as argument"
exit 1
fi
case "$1" in
-patch) patch -d "$2" -f --no-backup-if-mismatch -p1 < $0;;
-unpatch) patch -d "$2" -f --no-backup-if-mismatch -R -p1 < $0;;
*)
echo >&2 "`basename $0`: script expects -patch|-unpatch as argument"
exit 1
esac
exit 0

--- glibc-2.3.1/locale/programs/locale.c	2003-01-11 18:13:57.000000000 +0000
+++ glibc-2.3.1/locale/programs/locale.c	2003-01-11 18:13:59.000000000 +0000
@@ -43,10 +43,12 @@
 
 #include "localeinfo.h"
 #include "charmap-dir.h"
+#include "../locarchive.h"
 
 extern void *xmalloc (size_t __n);
 extern char *xstrdup (const char *__str);
 
+#define ARCHIVE_NAME LOCALEDIR "/locale-archive"
 
 /* If set print the name of the category.  */
 static int show_category_name;
@@ -168,7 +170,11 @@
 			    int show_keyword_name);
 
 /* Prototypes for local functions.  */
+static void print_LC_IDENTIFICATION (void *mapped, size_t size);
+static void print_LC_CTYPE (void *mapped, size_t size);
 static void write_locales (void);
+static int nameentcmp (const void *a, const void *b);
+static int write_archive_locales (void **all_datap, char *linebuf);
 static void write_charmaps (void);
 static void show_locale_vars (void);
 static void show_info (const char *name);
@@ -327,6 +333,74 @@
 }
 
 
+static void
+print_LC_IDENTIFICATION (void *mapped, size_t size)
+{
+  /* Read the information from the file.  */
+  struct
+    {
+      unsigned int magic;
+      unsigned int nstrings;
+      unsigned int strindex[0];
+    } *filedata = mapped;
+
+  if (filedata->magic == LIMAGIC (LC_IDENTIFICATION)
+      && (sizeof *filedata
+	  + (filedata->nstrings
+	     * sizeof (unsigned int))
+	  <= size))
+    {
+      const char *str;
+
+#define HANDLE(idx, name) \
+  str = ((char *) mapped						      \
+	 + filedata->strindex[_NL_ITEM_INDEX (_NL_IDENTIFICATION_##idx)]);    \
+  if (*str != '\0')							      \
+    printf ("%9s | %s\n", name, str)
+      HANDLE (TITLE, "title");
+      HANDLE (SOURCE, "source");
+      HANDLE (ADDRESS, "address");
+      HANDLE (CONTACT, "contact");
+      HANDLE (EMAIL, "email");
+      HANDLE (TEL, "telephone");
+      HANDLE (FAX, "fax");
+      HANDLE (LANGUAGE, "language");
+      HANDLE (TERRITORY, "territory");
+      HANDLE (AUDIENCE, "audience");
+      HANDLE (APPLICATION, "application");
+      HANDLE (ABBREVIATION, "abbreviation");
+      HANDLE (REVISION, "revision");
+      HANDLE (DATE, "date");
+    }
+}
+
+
+static void
+print_LC_CTYPE (void *mapped, size_t size)
+{
+  struct
+    {
+      unsigned int magic;
+      unsigned int nstrings;
+      unsigned int strindex[0];
+    } *filedata = mapped;
+
+  if (filedata->magic == LIMAGIC (LC_CTYPE)
+      && (sizeof *filedata
+	  + (filedata->nstrings
+	     * sizeof (unsigned int))
+	  <= size))
+    {
+      const char *str;
+
+      str = ((char *) mapped
+	     + filedata->strindex[_NL_ITEM_INDEX (_NL_CTYPE_CODESET_NAME)]);
+      if (*str != '\0')
+	printf ("  codeset | %s\n", str);
+    }
+}
+
+
 /* Write the names of all available locales to stdout.  We have some
    sources of the information: the contents of the locale directory
    and the locale.alias file.  To avoid duplicates and print the
@@ -358,6 +432,10 @@
   memset (linebuf, '-', sizeof (linebuf) - 1);
   linebuf[sizeof (linebuf) - 1] = '\0';
 
+  /* First scan the locale archive.  */
+  if (write_archive_locales (&all_data, linebuf))
+    first_locale = 0;
+
   /* Now we can look for all files in the directory.  */
   ndirents = scandir (LOCALEDIR, &dirents, select_dirs, alphasort);
   for (cnt = 0; cnt < ndirents; ++cnt)
@@ -375,7 +453,7 @@
 
       if (stat64 (buf, &st) == 0 && S_ISREG (st.st_mode))
 	{
-	  if (verbose)
+	  if (verbose && GET (dirents[cnt]->d_name) == NULL)
 	    {
 	      /* Provide some nice output of all kinds of
 		 information.  */
@@ -396,42 +474,7 @@
 					 MAP_SHARED, fd, 0);
 		  if (mapped != MAP_FAILED)
 		    {
-		      /* Read the information from the file.  */
-		      struct
-		      {
-			unsigned int magic;
-			unsigned int nstrings;
-			unsigned int strindex[0];
-		      } *filedata = mapped;
-
-		      if (filedata->magic == LIMAGIC (LC_IDENTIFICATION)
-			  && (sizeof *filedata
-			      + (filedata->nstrings
-				 * sizeof (unsigned int))
-			      <= (size_t) st.st_size))
-			{
-			  const char *str;
-
-#define HANDLE(idx, name) \
-  str = ((char *) mapped						      \
-	 + filedata->strindex[_NL_ITEM_INDEX (_NL_IDENTIFICATION_##idx)]);    \
-  if (*str != '\0')							      \
-    printf ("%9s | %s\n", name, str)
-			  HANDLE (TITLE, "title");
-			  HANDLE (SOURCE, "source");
-			  HANDLE (ADDRESS, "address");
-			  HANDLE (CONTACT, "contact");
-			  HANDLE (EMAIL, "email");
-			  HANDLE (TEL, "telephone");
-			  HANDLE (FAX, "fax");
-			  HANDLE (LANGUAGE, "language");
-			  HANDLE (TERRITORY, "territory");
-			  HANDLE (AUDIENCE, "audience");
-			  HANDLE (APPLICATION, "application");
-			  HANDLE (ABBREVIATION, "abbreviation");
-			  HANDLE (REVISION, "revision");
-			  HANDLE (DATE, "date");
-			}
+		      print_LC_IDENTIFICATION (mapped, st.st_size);
 
 		      munmap (mapped, st.st_size);
 		    }
@@ -446,26 +489,7 @@
 					    MAP_SHARED, fd, 0))
 			  != MAP_FAILED))
 		    {
-		      struct
-		      {
-			unsigned int magic;
-			unsigned int nstrings;
-			unsigned int strindex[0];
-		      } *filedata = mapped;
-
-		      if (filedata->magic == LIMAGIC (LC_CTYPE)
-			  && (sizeof *filedata
-			      + (filedata->nstrings
-				 * sizeof (unsigned int))
-			      <= (size_t) st.st_size))
-			{
-			  const char *str;
-
-			  str = ((char *) mapped
-				 + filedata->strindex[_NL_ITEM_INDEX (_NL_CTYPE_CODESET_NAME)]);
-			  if (*str != '\0')
-			    printf ("  codeset | %s\n", str);
-			}
+		      print_LC_CTYPE (mapped, st.st_size);
 
 		      munmap (mapped, st.st_size);
 		    }
@@ -474,10 +498,10 @@
 		    close (fd);
 		}
 	    }
-	  else
-	    /* If the verbose format is not selected we simply
-	       collect the names.  */
-	    PUT (xstrdup (dirents[cnt]->d_name));
+
+	  /* If the verbose format is not selected we simply
+	     collect the names.  */
+	  PUT (xstrdup (dirents[cnt]->d_name));
 	}
     }
   if (ndirents > 0)
@@ -584,6 +608,113 @@
 }
 
 
+struct nameent
+{
+  char *name;
+  uint32_t locrec_offset;
+};
+
+
+static int
+nameentcmp (const void *a, const void *b)
+{
+  return strcoll (((const struct nameent *) a)->name,
+		  ((const struct nameent *) b)->name);
+}
+
+
+static int
+write_archive_locales (void **all_datap, char *linebuf)
+{
+  struct stat64 st;
+  void *all_data = *all_datap;
+  size_t len = 0;
+  struct locarhead *head;
+  struct namehashent *namehashtab;
+  char *addr = MAP_FAILED;
+  int fd, ret = 0;
+  uint32_t cnt;
+
+  fd = open64 (ARCHIVE_NAME, O_RDONLY);
+  if (fd < 0)
+    return 0;
+
+  if (fstat64 (fd, &st) < 0 || st.st_size < sizeof (*head))
+    goto error_out;
+
+  len = st.st_size;
+  addr = mmap64 (NULL, len, PROT_READ, MAP_SHARED, fd, 0);
+  if (addr == MAP_FAILED)
+    goto error_out;
+
+  head = (struct locarhead *) addr;
+  if (head->namehash_offset + head->namehash_size > len
+      || head->string_offset + head->string_size > len
+      || head->locrectab_offset + head->locrectab_size > len
+      || head->sumhash_offset + head->sumhash_size > len)
+    goto error_out;
+
+  namehashtab = (struct namehashent *) (addr + head->namehash_offset);
+  if (! verbose)
+    {
+      for (cnt = 0; cnt < head->namehash_size; ++cnt)
+	if (namehashtab[cnt].locrec_offset != 0)
+	  {
+	    PUT (xstrdup (addr + namehashtab[cnt].name_offset));
+	    ++ret;
+	  }
+    }
+  else
+    {
+      struct nameent *names;
+      uint32_t used;
+
+      names = (struct nameent *) xmalloc (head->namehash_used
+					  * sizeof (struct nameent));
+      for (cnt = used = 0; cnt < head->namehash_size; ++cnt)
+	if (namehashtab[cnt].locrec_offset != 0)
+	  {
+	    names[used].name = addr + namehashtab[cnt].name_offset;
+	    names[used++].locrec_offset = namehashtab[cnt].locrec_offset;
+	  }
+
+      /* Sort the names.  */
+      qsort (names, used, sizeof (struct nameent), nameentcmp);
+
+      for (cnt = 0; cnt < used; ++cnt)
+	{
+	  struct locrecent *locrec;
+
+	  PUT (xstrdup (names[cnt].name));
+
+	  if (cnt)
+	    putchar_unlocked ('\n');
+
+	  printf ("locale: %-15.15s archive: " ARCHIVE_NAME "\n%s\n",
+		  names[cnt].name, linebuf);
+
+	  locrec = (struct locrecent *) (addr + names[cnt].locrec_offset);
+
+	  print_LC_IDENTIFICATION (addr
+				   + locrec->record[LC_IDENTIFICATION].offset,
+				   locrec->record[LC_IDENTIFICATION].len);
+
+	  print_LC_CTYPE (addr + locrec->record[LC_CTYPE].offset,
+			  locrec->record[LC_CTYPE].len);
+	}
+
+      ret = used;
+    }
+
+error_out:
+  if (addr != MAP_FAILED)
+    munmap (addr, len);
+  close (fd);
+  *all_datap = all_data;
+  return ret;
+}
+
+
 /* Write the names of all available character maps to stdout.  */
 static void
 write_charmaps (void)
cvs
makeconfig
locale-es_AR
ldconfig
ldd
glibcbug
fhs-linux-paths
# JB - 44697 string2-pointer-arith
glibc22-nss-upgrade
#glibc22-getaddrinfo - Update for post 2.3.1 CVS
glibc22-eo_EO
glibc22-m68k-compat
glibc22-m68k-fpic
glibc22-locales
sparc64-fixups
#glibc22-getdents-fix - There's a workaround in the kernel. Upstream refused this.
glibc22-ttyname-devfs
powerpc-sysconf
#ip6-fix - Bug#165287
arm-no-hwcap
locales-stuff
#JB - Update for 2.3? ia64-reloc-none
nscd-security-fix
#JB - Update for 2.3 ia64-perf
#ldso-disable-hwcap	- remove due to disabling hwcap is not good way.
elf-machine-rela-mips
librt-mips
glibc23-ctype-compat
#rtsig
#crypt
#s390x-lib64
#hurd-fork-fix
#glibc23-00-hppa-pthreads
glibc23-01-hppa-dl-machine
glibc23-07-hppa-atomicity
signal-texi
#s390-types
glibc23-ia64-strncpy
glibc23-hppa-Rminkernel
glibc23-function-compat
glibc23-getdents64-fix
glibc23-errno
glibc23-getaddrinfo
glibc23-hppa-shmlba
document-fix
glibc23-asserth-decls
alpha-pic
glibc23-cmov
glibc23-regcomp
libgcc-compat-all
glibc23-malloc-check
locales-supported
glibc23-hppa-compat
libgcc-compat-other
glibc23-m68k-madv
glibc23-00-hppa-pthreads 
glibc23-hppa-malloc8
glibc23-cert-rpcxdr
glibc-2.3.1-locale

Reply to: