Siddhesh Poyarekar 17b00fb
#define _GNU_SOURCE
Siddhesh Poyarekar 17b00fb
#include <assert.h>
Siddhesh Poyarekar 17b00fb
#include <dirent.h>
Siddhesh Poyarekar 17b00fb
#include <errno.h>
Siddhesh Poyarekar 17b00fb
#include <fcntl.h>
Siddhesh Poyarekar 17b00fb
#include <locale.h>
Siddhesh Poyarekar 17b00fb
#include <stdarg.h>
Siddhesh Poyarekar 17b00fb
#include <stdbool.h>
Siddhesh Poyarekar 17b00fb
#include <stdio.h>
Siddhesh Poyarekar 17b00fb
#include <stdlib.h>
Carlos O'Donell 91764bd
#include <getopt.h>
Siddhesh Poyarekar 17b00fb
#include <string.h>
Siddhesh Poyarekar 17b00fb
#include <sys/mman.h>
Siddhesh Poyarekar 17b00fb
#include <sys/stat.h>
Siddhesh Poyarekar 17b00fb
#include <unistd.h>
Siddhesh Poyarekar 17b00fb
#include "../locale/hashval.h"
Siddhesh Poyarekar 17b00fb
#define __LC_LAST 13
Siddhesh Poyarekar 17b00fb
#include "../locale/locarchive.h"
Siddhesh Poyarekar 17b00fb
#include "../crypt/md5.h"
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
const char *alias_file = DATADIR "/locale/locale.alias";
Siddhesh Poyarekar 17b00fb
const char *locar_file = PREFIX "/lib/locale/locale-archive";
Siddhesh Poyarekar 17b00fb
const char *tmpl_file = PREFIX "/lib/locale/locale-archive.tmpl";
Siddhesh Poyarekar 17b00fb
const char *loc_path = PREFIX "/lib/locale/";
Carlos O'Donell 91764bd
/* Flags set by `--verbose` option.  */
Siddhesh Poyarekar 17b00fb
int be_quiet = 1;
Siddhesh Poyarekar 17b00fb
int verbose = 0;
Siddhesh Poyarekar 17b00fb
int max_locarchive_open_retry = 10;
Siddhesh Poyarekar 17b00fb
const char *output_prefix;
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 13a25e8
/* Endianness should have been taken care of by localedef.  We don't need to do
Siddhesh Poyarekar 13a25e8
   additional swapping.  We need this variable exported however, since
Siddhesh Poyarekar 13a25e8
   locarchive.c uses it to determine if it needs to swap endianness of a value
Siddhesh Poyarekar 13a25e8
   before writing to or reading from the archive.  */
Siddhesh Poyarekar 13a25e8
bool swap_endianness_p = false;
Siddhesh Poyarekar 13a25e8
Siddhesh Poyarekar 17b00fb
static const char *locnames[] =
Siddhesh Poyarekar 17b00fb
  {
Siddhesh Poyarekar 17b00fb
#define DEFINE_CATEGORY(category, category_name, items, a) \
Siddhesh Poyarekar 17b00fb
  [category] = category_name,
Siddhesh Poyarekar 17b00fb
#include "../locale/categories.def"
Siddhesh Poyarekar 17b00fb
#undef  DEFINE_CATEGORY
Siddhesh Poyarekar 17b00fb
  };
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
static int
Siddhesh Poyarekar 17b00fb
is_prime (unsigned long candidate)
Siddhesh Poyarekar 17b00fb
{
Siddhesh Poyarekar 17b00fb
  /* No even number and none less than 10 will be passed here.  */
Siddhesh Poyarekar 17b00fb
  unsigned long int divn = 3;
Siddhesh Poyarekar 17b00fb
  unsigned long int sq = divn * divn;
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
  while (sq < candidate && candidate % divn != 0)
Siddhesh Poyarekar 17b00fb
    {
Siddhesh Poyarekar 17b00fb
      ++divn;
Siddhesh Poyarekar 17b00fb
      sq += 4 * divn;
Siddhesh Poyarekar 17b00fb
      ++divn;
Siddhesh Poyarekar 17b00fb
    }
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
  return candidate % divn != 0;
Siddhesh Poyarekar 17b00fb
}
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
unsigned long
Siddhesh Poyarekar 17b00fb
next_prime (unsigned long seed)
Siddhesh Poyarekar 17b00fb
{
Siddhesh Poyarekar 17b00fb
  /* Make it definitely odd.  */
Siddhesh Poyarekar 17b00fb
  seed |= 1;
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
  while (!is_prime (seed))
Siddhesh Poyarekar 17b00fb
    seed += 2;
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
  return seed;
Siddhesh Poyarekar 17b00fb
}
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
void
Siddhesh Poyarekar 17b00fb
error (int status, int errnum, const char *message, ...)
Siddhesh Poyarekar 17b00fb
{
Siddhesh Poyarekar 17b00fb
  va_list args;
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
  va_start (args, message);
Siddhesh Poyarekar 17b00fb
  fflush (stdout);
Siddhesh Poyarekar 17b00fb
  fprintf (stderr, "%s: ", program_invocation_name);
Siddhesh Poyarekar 17b00fb
  vfprintf (stderr, message, args);
Siddhesh Poyarekar 17b00fb
  va_end (args);
Siddhesh Poyarekar 17b00fb
  if (errnum)
Siddhesh Poyarekar 17b00fb
    fprintf (stderr, ": %s", strerror (errnum));
Siddhesh Poyarekar 17b00fb
  putc ('\n', stderr);
Siddhesh Poyarekar 17b00fb
  fflush (stderr);
Siddhesh Poyarekar 17b00fb
  if (status)
Siddhesh Poyarekar 17b00fb
    exit (errnum == EROFS ? 0 : status);
Siddhesh Poyarekar 17b00fb
}
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
void *
Siddhesh Poyarekar 17b00fb
xmalloc (size_t size)
Siddhesh Poyarekar 17b00fb
{
Siddhesh Poyarekar 17b00fb
  void *p = malloc (size);
Siddhesh Poyarekar 17b00fb
  if (p == NULL)
Siddhesh Poyarekar 17b00fb
    error (EXIT_FAILURE, errno, "could not allocate %zd bytes of memory", size);
Siddhesh Poyarekar 17b00fb
  return p;
Siddhesh Poyarekar 17b00fb
}
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
static void
Siddhesh Poyarekar 17b00fb
open_tmpl_archive (struct locarhandle *ah)
Siddhesh Poyarekar 17b00fb
{
Siddhesh Poyarekar 17b00fb
  struct stat64 st;
Siddhesh Poyarekar 17b00fb
  int fd;
Siddhesh Poyarekar 17b00fb
  struct locarhead head;
c2021d0
  const char *archivefname = ah->fname == NULL ? tmpl_file : ah->fname;
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
  /* Open the archive.  We must have exclusive write access.  */
Siddhesh Poyarekar 17b00fb
  fd = open64 (archivefname, O_RDONLY);
Siddhesh Poyarekar 17b00fb
  if (fd == -1)
Siddhesh Poyarekar 17b00fb
    error (EXIT_FAILURE, errno, "cannot open locale archive template file \"%s\"",
Siddhesh Poyarekar 17b00fb
	   archivefname);
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
  if (fstat64 (fd, &st) < 0)
Siddhesh Poyarekar 17b00fb
    error (EXIT_FAILURE, errno, "cannot stat locale archive template file \"%s\"",
Siddhesh Poyarekar 17b00fb
	   archivefname);
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
  /* Read the header.  */
Siddhesh Poyarekar 17b00fb
  if (TEMP_FAILURE_RETRY (read (fd, &head, sizeof (head))) != sizeof (head))
Siddhesh Poyarekar 17b00fb
    error (EXIT_FAILURE, errno, "cannot read archive header");
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
  ah->fd = fd;
Siddhesh Poyarekar 17b00fb
  ah->mmaped = (head.sumhash_offset
Siddhesh Poyarekar 17b00fb
		+ head.sumhash_size * sizeof (struct sumhashent));
Siddhesh Poyarekar 17b00fb
  if (ah->mmaped > (unsigned long) st.st_size)
Carlos O'Donell 91764bd
    error (EXIT_FAILURE, 0, "locale archive template file truncated");
Siddhesh Poyarekar 17b00fb
  ah->mmaped = st.st_size;
Siddhesh Poyarekar 17b00fb
  ah->reserved = st.st_size;
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
  /* Now we know how large the administrative information part is.
Siddhesh Poyarekar 17b00fb
     Map all of it.  */
Siddhesh Poyarekar 17b00fb
  ah->addr = mmap64 (NULL, ah->mmaped, PROT_READ, MAP_SHARED, fd, 0);
Siddhesh Poyarekar 17b00fb
  if (ah->addr == MAP_FAILED)
Siddhesh Poyarekar 17b00fb
    error (EXIT_FAILURE, errno, "cannot map archive header");
Siddhesh Poyarekar 17b00fb
}
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
/* Open the locale archive.  */
Siddhesh Poyarekar 17b00fb
extern void open_archive (struct locarhandle *ah, bool readonly);
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
/* Close the locale archive.  */
Siddhesh Poyarekar 17b00fb
extern void close_archive (struct locarhandle *ah);
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
/* Add given locale data to the archive.  */
Siddhesh Poyarekar 17b00fb
extern int add_locale_to_archive (struct locarhandle *ah, const char *name,
Siddhesh Poyarekar 17b00fb
				  locale_data_t data, bool replace);
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
extern void add_alias (struct locarhandle *ah, const char *alias,
Siddhesh Poyarekar 17b00fb
		       bool replace, const char *oldname,
Siddhesh Poyarekar 17b00fb
		       uint32_t *locrec_offset_p);
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
extern struct namehashent *
Siddhesh Poyarekar 17b00fb
insert_name (struct locarhandle *ah,
Siddhesh Poyarekar 17b00fb
	     const char *name, size_t name_len, bool replace);
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
struct nameent
Siddhesh Poyarekar 17b00fb
{
Siddhesh Poyarekar 17b00fb
  char *name;
Siddhesh Poyarekar 17b00fb
  struct locrecent *locrec;
Siddhesh Poyarekar 17b00fb
};
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
struct dataent
Siddhesh Poyarekar 17b00fb
{
Siddhesh Poyarekar 17b00fb
  const unsigned char *sum;
Siddhesh Poyarekar 17b00fb
  uint32_t file_offset;
Siddhesh Poyarekar 17b00fb
};
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
static int
Siddhesh Poyarekar 17b00fb
nameentcmp (const void *a, const void *b)
Siddhesh Poyarekar 17b00fb
{
Siddhesh Poyarekar 17b00fb
  struct locrecent *la = ((const struct nameent *) a)->locrec;
Siddhesh Poyarekar 17b00fb
  struct locrecent *lb = ((const struct nameent *) b)->locrec;
Siddhesh Poyarekar 17b00fb
  uint32_t start_a = -1, end_a = 0;
Siddhesh Poyarekar 17b00fb
  uint32_t start_b = -1, end_b = 0;
Siddhesh Poyarekar 17b00fb
  int cnt;
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
  for (cnt = 0; cnt < __LC_LAST; ++cnt)
Siddhesh Poyarekar 17b00fb
    if (cnt != LC_ALL)
Siddhesh Poyarekar 17b00fb
      {
Siddhesh Poyarekar 17b00fb
	if (la->record[cnt].offset < start_a)
Siddhesh Poyarekar 17b00fb
	  start_a = la->record[cnt].offset;
Siddhesh Poyarekar 17b00fb
	if (la->record[cnt].offset + la->record[cnt].len > end_a)
Siddhesh Poyarekar 17b00fb
	  end_a = la->record[cnt].offset + la->record[cnt].len;
Siddhesh Poyarekar 17b00fb
      }
Siddhesh Poyarekar 17b00fb
  assert (start_a != (uint32_t)-1);
Siddhesh Poyarekar 17b00fb
  assert (end_a != 0);
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
  for (cnt = 0; cnt < __LC_LAST; ++cnt)
Siddhesh Poyarekar 17b00fb
    if (cnt != LC_ALL)
Siddhesh Poyarekar 17b00fb
      {
Siddhesh Poyarekar 17b00fb
	if (lb->record[cnt].offset < start_b)
Siddhesh Poyarekar 17b00fb
	  start_b = lb->record[cnt].offset;
Siddhesh Poyarekar 17b00fb
	if (lb->record[cnt].offset + lb->record[cnt].len > end_b)
Siddhesh Poyarekar 17b00fb
	  end_b = lb->record[cnt].offset + lb->record[cnt].len;
Siddhesh Poyarekar 17b00fb
      }
Siddhesh Poyarekar 17b00fb
  assert (start_b != (uint32_t)-1);
Siddhesh Poyarekar 17b00fb
  assert (end_b != 0);
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
  if (start_a != start_b)
Siddhesh Poyarekar 17b00fb
    return (int)start_a - (int)start_b;
Siddhesh Poyarekar 17b00fb
  return (int)end_a - (int)end_b;
Siddhesh Poyarekar 17b00fb
}
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
static int
Siddhesh Poyarekar 17b00fb
dataentcmp (const void *a, const void *b)
Siddhesh Poyarekar 17b00fb
{
Siddhesh Poyarekar 17b00fb
  if (((const struct dataent *) a)->file_offset
Siddhesh Poyarekar 17b00fb
      < ((const struct dataent *) b)->file_offset)
Siddhesh Poyarekar 17b00fb
    return -1;
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
  if (((const struct dataent *) a)->file_offset
Siddhesh Poyarekar 17b00fb
      > ((const struct dataent *) b)->file_offset)
Siddhesh Poyarekar 17b00fb
    return 1;
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
  return 0;
Siddhesh Poyarekar 17b00fb
}
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
static int
Siddhesh Poyarekar 17b00fb
sumsearchfn (const void *key, const void *ent)
Siddhesh Poyarekar 17b00fb
{
Siddhesh Poyarekar 17b00fb
  uint32_t keyn = *(uint32_t *)key;
Siddhesh Poyarekar 17b00fb
  uint32_t entn = ((struct dataent *)ent)->file_offset;
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
  if (keyn < entn)
Siddhesh Poyarekar 17b00fb
    return -1;
Siddhesh Poyarekar 17b00fb
  if (keyn > entn)
Siddhesh Poyarekar 17b00fb
    return 1;
Siddhesh Poyarekar 17b00fb
  return 0;
Siddhesh Poyarekar 17b00fb
}
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
static void
Siddhesh Poyarekar 17b00fb
compute_data (struct locarhandle *ah, struct nameent *name, size_t sumused,
Siddhesh Poyarekar 17b00fb
	      struct dataent *files, locale_data_t data)
Siddhesh Poyarekar 17b00fb
{
Siddhesh Poyarekar 17b00fb
  int cnt;
Siddhesh Poyarekar 17b00fb
  struct locrecent *locrec = name->locrec;
Siddhesh Poyarekar 17b00fb
  struct dataent *file;
Siddhesh Poyarekar 17b00fb
  data[LC_ALL].addr = ((char *) ah->addr) + locrec->record[LC_ALL].offset;
Siddhesh Poyarekar 17b00fb
  data[LC_ALL].size = locrec->record[LC_ALL].len;
Siddhesh Poyarekar 17b00fb
  for (cnt = 0; cnt < __LC_LAST; ++cnt)
Siddhesh Poyarekar 17b00fb
    if (cnt != LC_ALL)
Siddhesh Poyarekar 17b00fb
      {
Siddhesh Poyarekar 17b00fb
	data[cnt].addr = ((char *) ah->addr) + locrec->record[cnt].offset;
Siddhesh Poyarekar 17b00fb
	data[cnt].size = locrec->record[cnt].len;
Siddhesh Poyarekar 17b00fb
	if (data[cnt].addr >= data[LC_ALL].addr
Siddhesh Poyarekar 17b00fb
	    && data[cnt].addr + data[cnt].size
Siddhesh Poyarekar 17b00fb
	       <= data[LC_ALL].addr + data[LC_ALL].size)
Siddhesh Poyarekar 17b00fb
	  __md5_buffer (data[cnt].addr, data[cnt].size, data[cnt].sum);
Siddhesh Poyarekar 17b00fb
	else
Siddhesh Poyarekar 17b00fb
	  {
Siddhesh Poyarekar 17b00fb
	    file = bsearch (&locrec->record[cnt].offset, files, sumused,
Siddhesh Poyarekar 17b00fb
			    sizeof (*files), sumsearchfn);
Siddhesh Poyarekar 17b00fb
	    if (file == NULL)
Siddhesh Poyarekar 17b00fb
	      error (EXIT_FAILURE, 0, "inconsistent template file");
Siddhesh Poyarekar 17b00fb
	    memcpy (data[cnt].sum, file->sum, sizeof (data[cnt].sum));
Siddhesh Poyarekar 17b00fb
	  }
Siddhesh Poyarekar 17b00fb
      }
Siddhesh Poyarekar 17b00fb
}
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
static int
c2021d0
fill_archive (struct locarhandle *tmpl_ah,
Carlos O'Donell 91764bd
	      const char *fname,
Carlos O'Donell 91764bd
	      size_t install_langs_count, char *install_langs_list[],
Carlos O'Donell 91764bd
	      size_t nlist, char *list[],
Siddhesh Poyarekar 17b00fb
	      const char *primary)
Siddhesh Poyarekar 17b00fb
{
Siddhesh Poyarekar 17b00fb
  struct locarhandle ah;
Siddhesh Poyarekar 17b00fb
  struct locarhead *head;
Siddhesh Poyarekar 17b00fb
  int result = 0;
Siddhesh Poyarekar 17b00fb
  struct nameent *names;
Siddhesh Poyarekar 17b00fb
  struct namehashent *namehashtab;
Siddhesh Poyarekar 17b00fb
  size_t cnt, used;
Siddhesh Poyarekar 17b00fb
  struct dataent *files;
Siddhesh Poyarekar 17b00fb
  struct sumhashent *sumhashtab;
Siddhesh Poyarekar 17b00fb
  size_t sumused;
Siddhesh Poyarekar 17b00fb
  struct locrecent *primary_locrec = NULL;
Siddhesh Poyarekar 17b00fb
  struct nameent *primary_nameent = NULL;
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
  head = tmpl_ah->addr;
Siddhesh Poyarekar 17b00fb
  names = (struct nameent *) malloc (head->namehash_used
Siddhesh Poyarekar 17b00fb
				     * sizeof (struct nameent));
Siddhesh Poyarekar 17b00fb
  files = (struct dataent *) malloc (head->sumhash_used
Siddhesh Poyarekar 17b00fb
				     * sizeof (struct dataent));
Siddhesh Poyarekar 17b00fb
  if (names == NULL || files == NULL)
Siddhesh Poyarekar 17b00fb
    error (EXIT_FAILURE, errno, "could not allocate tables");
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
  namehashtab = (struct namehashent *) ((char *) tmpl_ah->addr
Siddhesh Poyarekar 17b00fb
					+ head->namehash_offset);
Siddhesh Poyarekar 17b00fb
  sumhashtab = (struct sumhashent *) ((char *) tmpl_ah->addr
Siddhesh Poyarekar 17b00fb
				      + head->sumhash_offset);
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
  for (cnt = used = 0; cnt < head->namehash_size; ++cnt)
Siddhesh Poyarekar 17b00fb
    if (namehashtab[cnt].locrec_offset != 0)
Siddhesh Poyarekar 17b00fb
      {
Carlos O'Donell 91764bd
	char * name;
Carlos O'Donell 91764bd
	int i;
Siddhesh Poyarekar 17b00fb
	assert (used < head->namehash_used);
Carlos O'Donell 91764bd
        name = tmpl_ah->addr + namehashtab[cnt].name_offset;
Carlos O'Donell 91764bd
        if (install_langs_count == 0)
Carlos O'Donell 91764bd
          {
Carlos O'Donell 91764bd
	    /* Always intstall the entry.  */
Carlos O'Donell 91764bd
            names[used].name = name;
Carlos O'Donell 91764bd
            names[used++].locrec
Carlos O'Donell 91764bd
                = (struct locrecent *) ((char *) tmpl_ah->addr +
Carlos O'Donell 91764bd
                                        namehashtab[cnt].locrec_offset);
Carlos O'Donell 91764bd
          }
Carlos O'Donell 91764bd
        else
Carlos O'Donell 91764bd
          {
Carlos O'Donell 91764bd
	    /* Only install the entry if the user asked for it via
Carlos O'Donell 91764bd
	       --install-langs.  */
Carlos O'Donell 91764bd
            for (i = 0; i < install_langs_count; i++)
Carlos O'Donell 91764bd
              {
Carlos O'Donell 91764bd
		/* Add one for "_" and one for the null terminator.  */
Carlos O'Donell 91764bd
		size_t len = strlen (install_langs_list[i]) + 2;
Carlos O'Donell 91764bd
		char *install_lang = (char *)xmalloc (len);
Carlos O'Donell 0457f64
                strcpy (install_lang, install_langs_list[i]);
Carlos O'Donell 91764bd
                if (strchr (install_lang, '_') == NULL)
Carlos O'Donell 91764bd
                  strcat (install_lang, "_");
Carlos O'Donell 91764bd
                if (strncmp (name, install_lang, strlen (install_lang)) == 0)
Carlos O'Donell 91764bd
                  {
Carlos O'Donell 91764bd
                    names[used].name = name;
Carlos O'Donell 91764bd
                    names[used++].locrec
Carlos O'Donell 91764bd
		      = (struct locrecent *) ((char *)tmpl_ah->addr
Carlos O'Donell 91764bd
					      + namehashtab[cnt].locrec_offset);
Carlos O'Donell 91764bd
                  }
Carlos O'Donell 91764bd
		free (install_lang);
Carlos O'Donell 91764bd
              }
Carlos O'Donell 91764bd
          }
Siddhesh Poyarekar 17b00fb
      }
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
  /* Sort the names.  */
Siddhesh Poyarekar 17b00fb
  qsort (names, used, sizeof (struct nameent), nameentcmp);
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
  for (cnt = sumused = 0; cnt < head->sumhash_size; ++cnt)
Siddhesh Poyarekar 17b00fb
    if (sumhashtab[cnt].file_offset != 0)
Siddhesh Poyarekar 17b00fb
      {
Siddhesh Poyarekar 17b00fb
	assert (sumused < head->sumhash_used);
Siddhesh Poyarekar 17b00fb
	files[sumused].sum = (const unsigned char *) sumhashtab[cnt].sum;
Siddhesh Poyarekar 17b00fb
	files[sumused++].file_offset = sumhashtab[cnt].file_offset;
Siddhesh Poyarekar 17b00fb
      }
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
  /* Sort by file locations.  */
Siddhesh Poyarekar 17b00fb
  qsort (files, sumused, sizeof (struct dataent), dataentcmp);
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
  /* Open the archive.  This call never returns if we cannot
Siddhesh Poyarekar 17b00fb
     successfully open the archive.  */
f652016
  ah.fname = NULL;
c2021d0
  if (fname != NULL)
c2021d0
    ah.fname = fname;
Siddhesh Poyarekar 17b00fb
  open_archive (&ah, false);
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
  if (primary != NULL)
Siddhesh Poyarekar 17b00fb
    {
Siddhesh Poyarekar 17b00fb
      for (cnt = 0; cnt < used; ++cnt)
Siddhesh Poyarekar 17b00fb
	if (strcmp (names[cnt].name, primary) == 0)
Siddhesh Poyarekar 17b00fb
	  break;
Siddhesh Poyarekar 17b00fb
      if (cnt < used)
Siddhesh Poyarekar 17b00fb
	{
Siddhesh Poyarekar 17b00fb
	  locale_data_t data;
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
	  compute_data (tmpl_ah, &names[cnt], sumused, files, data);
Siddhesh Poyarekar 17b00fb
	  result |= add_locale_to_archive (&ah, primary, data, 0);
Siddhesh Poyarekar 17b00fb
	  primary_locrec = names[cnt].locrec;
Siddhesh Poyarekar 17b00fb
	  primary_nameent = &names[cnt];
Siddhesh Poyarekar 17b00fb
	}
Siddhesh Poyarekar 17b00fb
    }
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
  for (cnt = 0; cnt < used; ++cnt)
Siddhesh Poyarekar 17b00fb
    if (&names[cnt] == primary_nameent)
Siddhesh Poyarekar 17b00fb
      continue;
Siddhesh Poyarekar 17b00fb
    else if ((cnt > 0 && names[cnt - 1].locrec == names[cnt].locrec)
Siddhesh Poyarekar 17b00fb
	     || names[cnt].locrec == primary_locrec)
Siddhesh Poyarekar 17b00fb
      {
Siddhesh Poyarekar 17b00fb
	const char *oldname;
Siddhesh Poyarekar 17b00fb
	struct namehashent *namehashent;
Siddhesh Poyarekar 17b00fb
	uint32_t locrec_offset;
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
	if (names[cnt].locrec == primary_locrec)
Siddhesh Poyarekar 17b00fb
	  oldname = primary;
Siddhesh Poyarekar 17b00fb
	else
Siddhesh Poyarekar 17b00fb
	  oldname = names[cnt - 1].name;
Siddhesh Poyarekar 17b00fb
	namehashent = insert_name (&ah, oldname, strlen (oldname), true);
Siddhesh Poyarekar 17b00fb
	assert (namehashent->name_offset != 0);
Siddhesh Poyarekar 17b00fb
	assert (namehashent->locrec_offset != 0);
Siddhesh Poyarekar 17b00fb
	locrec_offset = namehashent->locrec_offset;
Siddhesh Poyarekar 17b00fb
	add_alias (&ah, names[cnt].name, 0, oldname, &locrec_offset);
Siddhesh Poyarekar 17b00fb
      }
Siddhesh Poyarekar 17b00fb
    else
Siddhesh Poyarekar 17b00fb
      {
Siddhesh Poyarekar 17b00fb
	locale_data_t data;
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
	compute_data (tmpl_ah, &names[cnt], sumused, files, data);
Siddhesh Poyarekar 17b00fb
	result |= add_locale_to_archive (&ah, names[cnt].name, data, 0);
Siddhesh Poyarekar 17b00fb
      }
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
  while (nlist-- > 0)
Siddhesh Poyarekar 17b00fb
    {
Siddhesh Poyarekar 17b00fb
      const char *fname = *list++;
Siddhesh Poyarekar 17b00fb
      size_t fnamelen = strlen (fname);
Siddhesh Poyarekar 17b00fb
      struct stat64 st;
Siddhesh Poyarekar 17b00fb
      DIR *dirp;
Siddhesh Poyarekar 17b00fb
      struct dirent64 *d;
Siddhesh Poyarekar 17b00fb
      int seen;
Siddhesh Poyarekar 17b00fb
      locale_data_t data;
Siddhesh Poyarekar 17b00fb
      int cnt;
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
      /* First see whether this really is a directory and whether it
Siddhesh Poyarekar 17b00fb
	 contains all the require locale category files.  */
Siddhesh Poyarekar 17b00fb
      if (stat64 (fname, &st) < 0)
Siddhesh Poyarekar 17b00fb
	{
Siddhesh Poyarekar 17b00fb
	  error (0, 0, "stat of \"%s\" failed: %s: ignored", fname,
Siddhesh Poyarekar 17b00fb
		 strerror (errno));
Siddhesh Poyarekar 17b00fb
	  continue;
Siddhesh Poyarekar 17b00fb
	}
Siddhesh Poyarekar 17b00fb
      if (!S_ISDIR (st.st_mode))
Siddhesh Poyarekar 17b00fb
	{
Siddhesh Poyarekar 17b00fb
	  error (0, 0, "\"%s\" is no directory; ignored", fname);
Siddhesh Poyarekar 17b00fb
	  continue;
Siddhesh Poyarekar 17b00fb
	}
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
      dirp = opendir (fname);
Siddhesh Poyarekar 17b00fb
      if (dirp == NULL)
Siddhesh Poyarekar 17b00fb
	{
Siddhesh Poyarekar 17b00fb
	  error (0, 0, "cannot open directory \"%s\": %s: ignored",
Siddhesh Poyarekar 17b00fb
		 fname, strerror (errno));
Siddhesh Poyarekar 17b00fb
	  continue;
Siddhesh Poyarekar 17b00fb
	}
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
      seen = 0;
Siddhesh Poyarekar 17b00fb
      while ((d = readdir64 (dirp)) != NULL)
Siddhesh Poyarekar 17b00fb
	{
Siddhesh Poyarekar 17b00fb
	  for (cnt = 0; cnt < __LC_LAST; ++cnt)
Siddhesh Poyarekar 17b00fb
	    if (cnt != LC_ALL)
Siddhesh Poyarekar 17b00fb
	      if (strcmp (d->d_name, locnames[cnt]) == 0)
Siddhesh Poyarekar 17b00fb
		{
Siddhesh Poyarekar 17b00fb
		  unsigned char d_type;
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
		  /* We have an object of the required name.  If it's
Siddhesh Poyarekar 17b00fb
		     a directory we have to look at a file with the
Siddhesh Poyarekar 17b00fb
		     prefix "SYS_".  Otherwise we have found what we
Siddhesh Poyarekar 17b00fb
		     are looking for.  */
Siddhesh Poyarekar 17b00fb
#ifdef _DIRENT_HAVE_D_TYPE
Siddhesh Poyarekar 17b00fb
		  d_type = d->d_type;
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
		  if (d_type != DT_REG)
Siddhesh Poyarekar 17b00fb
#endif
Siddhesh Poyarekar 17b00fb
		    {
Siddhesh Poyarekar 17b00fb
		      char fullname[fnamelen + 2 * strlen (d->d_name) + 7];
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
#ifdef _DIRENT_HAVE_D_TYPE
Siddhesh Poyarekar 17b00fb
		      if (d_type == DT_UNKNOWN)
Siddhesh Poyarekar 17b00fb
#endif
Siddhesh Poyarekar 17b00fb
			{
Siddhesh Poyarekar 17b00fb
			  strcpy (stpcpy (stpcpy (fullname, fname), "/"),
Siddhesh Poyarekar 17b00fb
				  d->d_name);
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
			  if (stat64 (fullname, &st) == -1)
Siddhesh Poyarekar 17b00fb
			    /* We cannot stat the file, ignore it.  */
Siddhesh Poyarekar 17b00fb
			    break;
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
			  d_type = IFTODT (st.st_mode);
Siddhesh Poyarekar 17b00fb
			}
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
		      if (d_type == DT_DIR)
Siddhesh Poyarekar 17b00fb
			{
Siddhesh Poyarekar 17b00fb
			  /* We have to do more tests.  The file is a
Siddhesh Poyarekar 17b00fb
			     directory and it therefore must contain a
Siddhesh Poyarekar 17b00fb
			     regular file with the same name except a
Siddhesh Poyarekar 17b00fb
			     "SYS_" prefix.  */
Siddhesh Poyarekar 17b00fb
			  char *t = stpcpy (stpcpy (fullname, fname), "/");
Siddhesh Poyarekar 17b00fb
			  strcpy (stpcpy (stpcpy (t, d->d_name), "/SYS_"),
Siddhesh Poyarekar 17b00fb
				  d->d_name);
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
			  if (stat64 (fullname, &st) == -1)
Siddhesh Poyarekar 17b00fb
			    /* There is no SYS_* file or we cannot
Siddhesh Poyarekar 17b00fb
			       access it.  */
Siddhesh Poyarekar 17b00fb
			    break;
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
			  d_type = IFTODT (st.st_mode);
Siddhesh Poyarekar 17b00fb
			}
Siddhesh Poyarekar 17b00fb
		    }
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
		  /* If we found a regular file (eventually after
Siddhesh Poyarekar 17b00fb
		     following a symlink) we are successful.  */
Siddhesh Poyarekar 17b00fb
		  if (d_type == DT_REG)
Siddhesh Poyarekar 17b00fb
		    ++seen;
Siddhesh Poyarekar 17b00fb
		  break;
Siddhesh Poyarekar 17b00fb
		}
Siddhesh Poyarekar 17b00fb
	}
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
      closedir (dirp);
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
      if (seen != __LC_LAST - 1)
Siddhesh Poyarekar 17b00fb
	{
Siddhesh Poyarekar 17b00fb
	  /* We don't have all locale category files.  Ignore the name.  */
Siddhesh Poyarekar 17b00fb
	  error (0, 0, "incomplete set of locale files in \"%s\"",
Siddhesh Poyarekar 17b00fb
		 fname);
Siddhesh Poyarekar 17b00fb
	  continue;
Siddhesh Poyarekar 17b00fb
	}
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
      /* Add the files to the archive.  To do this we first compute
Siddhesh Poyarekar 17b00fb
	 sizes and the MD5 sums of all the files.  */
Siddhesh Poyarekar 17b00fb
      for (cnt = 0; cnt < __LC_LAST; ++cnt)
Siddhesh Poyarekar 17b00fb
	if (cnt != LC_ALL)
Siddhesh Poyarekar 17b00fb
	  {
Siddhesh Poyarekar 17b00fb
	    char fullname[fnamelen + 2 * strlen (locnames[cnt]) + 7];
Siddhesh Poyarekar 17b00fb
	    int fd;
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
	    strcpy (stpcpy (stpcpy (fullname, fname), "/"), locnames[cnt]);
Siddhesh Poyarekar 17b00fb
	    fd = open64 (fullname, O_RDONLY);
Siddhesh Poyarekar 17b00fb
	    if (fd == -1 || fstat64 (fd, &st) == -1)
Siddhesh Poyarekar 17b00fb
	      {
Siddhesh Poyarekar 17b00fb
		/* Cannot read the file.  */
Siddhesh Poyarekar 17b00fb
		if (fd != -1)
Siddhesh Poyarekar 17b00fb
		  close (fd);
Siddhesh Poyarekar 17b00fb
		break;
Siddhesh Poyarekar 17b00fb
	      }
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
	    if (S_ISDIR (st.st_mode))
Siddhesh Poyarekar 17b00fb
	      {
Siddhesh Poyarekar 17b00fb
		char *t;
Siddhesh Poyarekar 17b00fb
		close (fd);
Siddhesh Poyarekar 17b00fb
		t = stpcpy (stpcpy (fullname, fname), "/");
Siddhesh Poyarekar 17b00fb
		strcpy (stpcpy (stpcpy (t, locnames[cnt]), "/SYS_"),
Siddhesh Poyarekar 17b00fb
			locnames[cnt]);
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
		fd = open64 (fullname, O_RDONLY);
Siddhesh Poyarekar 17b00fb
		if (fd == -1 || fstat64 (fd, &st) == -1
Siddhesh Poyarekar 17b00fb
		    || !S_ISREG (st.st_mode))
Siddhesh Poyarekar 17b00fb
		  {
Siddhesh Poyarekar 17b00fb
		    if (fd != -1)
Siddhesh Poyarekar 17b00fb
		      close (fd);
Siddhesh Poyarekar 17b00fb
		    break;
Siddhesh Poyarekar 17b00fb
		  }
Siddhesh Poyarekar 17b00fb
	      }
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
	    /* Map the file.  */
Siddhesh Poyarekar 17b00fb
	    data[cnt].addr = mmap64 (NULL, st.st_size, PROT_READ, MAP_SHARED,
Siddhesh Poyarekar 17b00fb
				     fd, 0);
Siddhesh Poyarekar 17b00fb
	    if (data[cnt].addr == MAP_FAILED)
Siddhesh Poyarekar 17b00fb
	      {
Siddhesh Poyarekar 17b00fb
		/* Cannot map it.  */
Siddhesh Poyarekar 17b00fb
		close (fd);
Siddhesh Poyarekar 17b00fb
		break;
Siddhesh Poyarekar 17b00fb
	      }
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
	    data[cnt].size = st.st_size;
Siddhesh Poyarekar 17b00fb
	    __md5_buffer (data[cnt].addr, st.st_size, data[cnt].sum);
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
	    /* We don't need the file descriptor anymore.  */
Siddhesh Poyarekar 17b00fb
	    close (fd);
Siddhesh Poyarekar 17b00fb
	  }
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
      if (cnt != __LC_LAST)
Siddhesh Poyarekar 17b00fb
	{
Siddhesh Poyarekar 17b00fb
	  while (cnt-- > 0)
Siddhesh Poyarekar 17b00fb
	    if (cnt != LC_ALL)
Siddhesh Poyarekar 17b00fb
	      munmap (data[cnt].addr, data[cnt].size);
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
	  error (0, 0, "cannot read all files in \"%s\": ignored", fname);
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
	  continue;
Siddhesh Poyarekar 17b00fb
	}
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
      result |= add_locale_to_archive (&ah, basename (fname), data, 0);
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
      for (cnt = 0; cnt < __LC_LAST; ++cnt)
Siddhesh Poyarekar 17b00fb
	if (cnt != LC_ALL)
Siddhesh Poyarekar 17b00fb
	  munmap (data[cnt].addr, data[cnt].size);
Siddhesh Poyarekar 17b00fb
    }
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
  /* We are done.  */
Siddhesh Poyarekar 17b00fb
  close_archive (&ah;;
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
  return result;
Siddhesh Poyarekar 17b00fb
}
Siddhesh Poyarekar 17b00fb
Carlos O'Donell 91764bd
void usage()
Carlos O'Donell 91764bd
{
Carlos O'Donell 91764bd
  printf ("\
Carlos O'Donell 91764bd
Usage: build-locale-archive [OPTION]... [TEMPLATE-FILE] [ARCHIVE-FILE]\n\
Carlos O'Donell 91764bd
 Builds a locale archive from a template file.\n\
Carlos O'Donell 91764bd
 Options:\n\
Carlos O'Donell 91764bd
  -h, --help                 Print this usage message.\n\
Carlos O'Donell 91764bd
  -v, --verbose              Verbose execution.\n\
Carlos O'Donell 91764bd
  -l, --install-langs=LIST   Only include locales given in LIST into the \n\
Carlos O'Donell 91764bd
                             locale archive.  LIST is a colon separated list\n\
Carlos O'Donell 91764bd
                             of locale prefixes, for example \"de:en:ja\".\n\
Carlos O'Donell 91764bd
                             The special argument \"all\" means to install\n\
Carlos O'Donell 91764bd
                             all languages and it must be present by itself.\n\
Carlos O'Donell 91764bd
                             If \"all\" is present with any other language it\n\
Carlos O'Donell 91764bd
                             will be treated as the name of a locale.\n\
Carlos O'Donell 91764bd
                             If the --install-langs option is missing, all\n\
Carlos O'Donell 91764bd
                             locales are installed. The colon separated list\n\
Carlos O'Donell 91764bd
                             can contain any strings matching the beginning of\n\
Carlos O'Donell 91764bd
                             locale names.\n\
Carlos O'Donell 91764bd
                             If a string does not contain a \"_\", it is added.\n\
Carlos O'Donell 91764bd
                             Examples:\n\
Carlos O'Donell 91764bd
                               --install-langs=\"en\"\n\
Carlos O'Donell 91764bd
                                 installs en_US, en_US.iso88591,\n\
Carlos O'Donell 91764bd
                                 en_US.iso885915, en_US.utf8,\n\
Carlos O'Donell 91764bd
                                 en_GB ...\n\
Carlos O'Donell 91764bd
                               --install-langs=\"en_US.utf8\"\n\
Carlos O'Donell 91764bd
                                 installs only en_US.utf8.\n\
Carlos O'Donell 91764bd
                               --install-langs=\"ko\"\n\
Carlos O'Donell 91764bd
                                 installs ko_KR, ko_KR.euckr,\n\
Carlos O'Donell 91764bd
                                 ko_KR.utf8 but *not* kok_IN\n\
Carlos O'Donell 91764bd
                                 because \"ko\" does not contain\n\
Carlos O'Donell 91764bd
                                 \"_\" and it is silently added\n\
Carlos O'Donell 91764bd
                               --install-langs\"ko:kok\"\n\
Carlos O'Donell 91764bd
                                 installs ko_KR, ko_KR.euckr,\n\
Carlos O'Donell 91764bd
                                 ko_KR.utf8, kok_IN, and\n\
Carlos O'Donell 91764bd
                                 kok_IN.utf8.\n\
Carlos O'Donell 91764bd
                               --install-langs=\"POSIX\" will\n\
Carlos O'Donell 91764bd
                                 installs *no* locales at all\n\
Carlos O'Donell 91764bd
                                 because POSIX matches none of\n\
Carlos O'Donell 91764bd
                                 the locales. Actually, any string\n\
Carlos O'Donell 91764bd
                                 matching nothing will do that.\n\
Carlos O'Donell 91764bd
                                 POSIX and C will always be\n\
Carlos O'Donell 91764bd
                                 available because they are\n\
Carlos O'Donell 91764bd
                                 builtin.\n\
Carlos O'Donell 91764bd
                             Aliases are installed as well,\n\
Carlos O'Donell 91764bd
                             i.e. --install-langs=\"de\"\n\
Carlos O'Donell 91764bd
                             will install not only every locale starting with\n\
Carlos O'Donell 91764bd
                             \"de\" but also the aliases \"deutsch\"\n\
Carlos O'Donell 91764bd
                             and and \"german\" although the latter does not\n\
Carlos O'Donell 91764bd
                             start with \"de\".\n\
Carlos O'Donell 91764bd
\n\
Carlos O'Donell 91764bd
  If the arguments TEMPLATE-FILE and ARCHIVE-FILE are not given the locations\n\
Carlos O'Donell 91764bd
  where the glibc used expects these files are used by default.\n\
Carlos O'Donell 91764bd
");
Carlos O'Donell 91764bd
}
Carlos O'Donell 91764bd
c2021d0
int main (int argc, char *argv[])
Siddhesh Poyarekar 17b00fb
{
Siddhesh Poyarekar 17b00fb
  char path[4096];
Siddhesh Poyarekar 17b00fb
  DIR *dirp;
Siddhesh Poyarekar 17b00fb
  struct dirent64 *d;
Siddhesh Poyarekar 17b00fb
  struct stat64 st;
Siddhesh Poyarekar 17b00fb
  char *list[16384], *primary;
Carlos O'Donell 91764bd
  char *lang;
Carlos O'Donell 91764bd
  int install_langs_count = 0;
Carlos O'Donell 91764bd
  int i;
Carlos O'Donell 91764bd
  char *install_langs_arg, *ila_start;
Carlos O'Donell 91764bd
  char **install_langs_list;
Siddhesh Poyarekar 17b00fb
  unsigned int cnt = 0;
Siddhesh Poyarekar 17b00fb
  struct locarhandle tmpl_ah;
Carlos O'Donell 91764bd
  char *new_locar_fname = NULL;
Siddhesh Poyarekar 17b00fb
  size_t loc_path_len = strlen (loc_path);
Siddhesh Poyarekar 17b00fb
Carlos O'Donell 91764bd
  while (1)
Carlos O'Donell 91764bd
    {
Carlos O'Donell 91764bd
      int c;
Carlos O'Donell 91764bd
Carlos O'Donell 91764bd
      static struct option long_options[] =
Carlos O'Donell 91764bd
        {
Carlos O'Donell 91764bd
            {"help",            no_argument,       0, 'h'},
Carlos O'Donell 91764bd
            {"verbose",         no_argument,       0, 'v'},
Carlos O'Donell 91764bd
            {"install-langs",   required_argument, 0, 'l'},
Carlos O'Donell 91764bd
            {0, 0, 0, 0}
Carlos O'Donell 91764bd
        };
Carlos O'Donell 91764bd
      /* getopt_long stores the option index here. */
Carlos O'Donell 91764bd
      int option_index = 0;
Carlos O'Donell 91764bd
Carlos O'Donell 91764bd
      c = getopt_long (argc, argv, "vhl:",
Carlos O'Donell 91764bd
                       long_options, &option_index);
Carlos O'Donell 91764bd
Carlos O'Donell 91764bd
      /* Detect the end of the options. */
Carlos O'Donell 91764bd
      if (c == -1)
Carlos O'Donell 91764bd
        break;
Carlos O'Donell 91764bd
Carlos O'Donell 91764bd
      switch (c)
Carlos O'Donell 91764bd
        {
Carlos O'Donell 91764bd
        case 0:
Carlos O'Donell 91764bd
          printf ("unknown option %s", long_options[option_index].name);
Carlos O'Donell 91764bd
          if (optarg)
Carlos O'Donell 91764bd
            printf (" with arg %s", optarg);
Carlos O'Donell 91764bd
          printf ("\n");
Carlos O'Donell 91764bd
          usage ();
Carlos O'Donell 91764bd
          exit (1);
Carlos O'Donell 91764bd
Carlos O'Donell 91764bd
        case 'v':
Carlos O'Donell 91764bd
          verbose = 1;
Carlos O'Donell 91764bd
          be_quiet = 0;
Carlos O'Donell 91764bd
          break;
Carlos O'Donell 91764bd
Carlos O'Donell 91764bd
        case 'h':
Carlos O'Donell 91764bd
          usage ();
Carlos O'Donell 91764bd
          exit (0);
Carlos O'Donell 91764bd
Carlos O'Donell 91764bd
        case 'l':
Carlos O'Donell 91764bd
          install_langs_arg = ila_start = strdup (optarg);
Carlos O'Donell 91764bd
          /* If the argument to --install-lang is "all", do
Carlos O'Donell 91764bd
             not limit the list of languages to install and install
Carlos O'Donell 91764bd
             them all.  We do not support installing a single locale
Carlos O'Donell 91764bd
	     called "all".  */
Carlos O'Donell 91764bd
#define MAGIC_INSTALL_ALL "all"
Carlos O'Donell 91764bd
          if (install_langs_arg != NULL
Carlos O'Donell 91764bd
	      && install_langs_arg[0] != '\0'
Carlos O'Donell 91764bd
	      && !(strncmp(install_langs_arg, MAGIC_INSTALL_ALL,
Carlos O'Donell 91764bd
			   strlen(MAGIC_INSTALL_ALL)) == 0
Carlos O'Donell 91764bd
		   && strlen (install_langs_arg) == 3))
Carlos O'Donell 91764bd
            {
Carlos O'Donell 91764bd
	      /* Count the number of languages we will install.  */
Carlos O'Donell 91764bd
              while (true)
Carlos O'Donell 91764bd
                {
Carlos O'Donell 91764bd
                  lang = strtok(install_langs_arg, ":;,");
Carlos O'Donell 91764bd
                  if (lang == NULL)
Carlos O'Donell 91764bd
                    break;
Carlos O'Donell 91764bd
                  install_langs_count++;
Carlos O'Donell 91764bd
                  install_langs_arg = NULL;
Carlos O'Donell 91764bd
                }
Carlos O'Donell 91764bd
	      free (ila_start);
Carlos O'Donell 91764bd
	      /* Copy the list.  */
Carlos O'Donell 91764bd
	      install_langs_list = (char **)xmalloc (sizeof(char *) * install_langs_count);
Carlos O'Donell 91764bd
	      install_langs_arg = ila_start = strdup (optarg);
Carlos O'Donell 91764bd
	      install_langs_count = 0;
Carlos O'Donell 91764bd
	      while (true)
Carlos O'Donell 91764bd
                {
Carlos O'Donell 91764bd
                  lang = strtok(install_langs_arg, ":;,");
Carlos O'Donell 91764bd
                  if (lang == NULL)
Carlos O'Donell 91764bd
                    break;
Carlos O'Donell 91764bd
                  install_langs_list[install_langs_count] = lang;
Carlos O'Donell 91764bd
		  install_langs_count++;
Carlos O'Donell 91764bd
                  install_langs_arg = NULL;
Carlos O'Donell 91764bd
                }
Carlos O'Donell 91764bd
            }
Carlos O'Donell 91764bd
          break;
Carlos O'Donell 91764bd
Carlos O'Donell 91764bd
        case '?':
Carlos O'Donell 91764bd
          /* getopt_long already printed an error message. */
Carlos O'Donell 91764bd
          usage ();
Carlos O'Donell 91764bd
          exit (0);
Carlos O'Donell 91764bd
Carlos O'Donell 91764bd
        default:
Carlos O'Donell 91764bd
          abort ();
Carlos O'Donell 91764bd
        }
Carlos O'Donell 91764bd
    }
Carlos O'Donell 91764bd
  tmpl_ah.fname = NULL;
Carlos O'Donell 91764bd
  if (optind < argc)
Carlos O'Donell 91764bd
    tmpl_ah.fname = argv[optind];
Carlos O'Donell 91764bd
  if (optind + 1 < argc)
Carlos O'Donell 91764bd
    new_locar_fname = argv[optind + 1];
Carlos O'Donell 91764bd
  if (verbose)
Carlos O'Donell 91764bd
    {
Carlos O'Donell 91764bd
      if (tmpl_ah.fname)
Carlos O'Donell 91764bd
        printf("input archive file specified on command line: %s\n",
Carlos O'Donell 91764bd
               tmpl_ah.fname);
Carlos O'Donell 91764bd
      else
Carlos O'Donell 91764bd
        printf("using default input archive file.\n");
Carlos O'Donell 91764bd
      if (new_locar_fname)
Carlos O'Donell 91764bd
        printf("output archive file specified on command line: %s\n",
Carlos O'Donell 91764bd
               new_locar_fname);
Carlos O'Donell 91764bd
      else
Carlos O'Donell 91764bd
        printf("using default output archive file.\n");
Carlos O'Donell 91764bd
    }
Carlos O'Donell 91764bd
Siddhesh Poyarekar 17b00fb
  dirp = opendir (loc_path);
Siddhesh Poyarekar 17b00fb
  if (dirp == NULL)
Siddhesh Poyarekar 17b00fb
    error (EXIT_FAILURE, errno, "cannot open directory \"%s\"", loc_path);
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
  open_tmpl_archive (&tmpl_ah);
Siddhesh Poyarekar 17b00fb
Carlos O'Donell 91764bd
  if (new_locar_fname)
Carlos O'Donell 91764bd
    unlink (new_locar_fname);
Carlos O'Donell 91764bd
  else
Carlos O'Donell 91764bd
    unlink (locar_file);
Siddhesh Poyarekar 17b00fb
  primary = getenv ("LC_ALL");
Siddhesh Poyarekar 17b00fb
  if (primary == NULL)
Siddhesh Poyarekar 17b00fb
    primary = getenv ("LANG");
Siddhesh Poyarekar 17b00fb
  if (primary != NULL)
Siddhesh Poyarekar 17b00fb
    {
Siddhesh Poyarekar 17b00fb
      if (strncmp (primary, "ja", 2) != 0
Siddhesh Poyarekar 17b00fb
	  && strncmp (primary, "ko", 2) != 0
Siddhesh Poyarekar 17b00fb
	  && strncmp (primary, "zh", 2) != 0)
Siddhesh Poyarekar 17b00fb
	{
Siddhesh Poyarekar 17b00fb
	  char *ptr = malloc (strlen (primary) + strlen (".utf8") + 1), *p, *q;
Carlos O'Donell 91764bd
	  /* This leads to invalid locales sometimes:
Carlos O'Donell 91764bd
	     de_DE.iso885915@euro -> de_DE.utf8@euro */
Siddhesh Poyarekar 17b00fb
	  if (ptr != NULL)
Siddhesh Poyarekar 17b00fb
	    {
Siddhesh Poyarekar 17b00fb
	      p = ptr;
Siddhesh Poyarekar 17b00fb
	      q = primary;
Siddhesh Poyarekar 17b00fb
	      while (*q && *q != '.' && *q != '@')
Siddhesh Poyarekar 17b00fb
		*p++ = *q++;
Siddhesh Poyarekar 17b00fb
	      if (*q == '.')
Siddhesh Poyarekar 17b00fb
		while (*q && *q != '@')
Siddhesh Poyarekar 17b00fb
		  q++;
Siddhesh Poyarekar 17b00fb
	      p = stpcpy (p, ".utf8");
Siddhesh Poyarekar 17b00fb
	      strcpy (p, q);
Siddhesh Poyarekar 17b00fb
	      primary = ptr;
Siddhesh Poyarekar 17b00fb
	    }
Siddhesh Poyarekar 17b00fb
	  else
Siddhesh Poyarekar 17b00fb
	    primary = NULL;
Siddhesh Poyarekar 17b00fb
	}
Siddhesh Poyarekar 17b00fb
    }
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
  memcpy (path, loc_path, loc_path_len);
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
  while ((d = readdir64 (dirp)) != NULL)
Siddhesh Poyarekar 17b00fb
    {
Siddhesh Poyarekar 17b00fb
      if (strcmp (d->d_name, ".") == 0 || strcmp (d->d_name, "..") == 0)
Siddhesh Poyarekar 17b00fb
	continue;
Siddhesh Poyarekar 17b00fb
      if (strchr (d->d_name, '_') == NULL)
Siddhesh Poyarekar 17b00fb
	continue;
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
      size_t d_name_len = strlen (d->d_name);
Siddhesh Poyarekar 17b00fb
      if (loc_path_len + d_name_len + 1 > sizeof (path))
Siddhesh Poyarekar 17b00fb
	{
Siddhesh Poyarekar 17b00fb
	  error (0, 0, "too long filename \"%s\"", d->d_name);
Siddhesh Poyarekar 17b00fb
	  continue;
Siddhesh Poyarekar 17b00fb
	}
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
      memcpy (path + loc_path_len, d->d_name, d_name_len + 1);
Siddhesh Poyarekar 17b00fb
      if (stat64 (path, &st) < 0)
Siddhesh Poyarekar 17b00fb
	{
Siddhesh Poyarekar 17b00fb
	  error (0, errno, "cannot stat \"%s\"", path);
Siddhesh Poyarekar 17b00fb
	  continue;
Siddhesh Poyarekar 17b00fb
	}
Siddhesh Poyarekar 17b00fb
      if (! S_ISDIR (st.st_mode))
Siddhesh Poyarekar 17b00fb
	continue;
Siddhesh Poyarekar 17b00fb
      if (cnt == 16384)
Siddhesh Poyarekar 17b00fb
	{
Siddhesh Poyarekar 17b00fb
	  error (0, 0, "too many directories in \"%s\"", loc_path);
Siddhesh Poyarekar 17b00fb
	  break;
Siddhesh Poyarekar 17b00fb
	}
Siddhesh Poyarekar 17b00fb
      list[cnt] = strdup (path);
Siddhesh Poyarekar 17b00fb
      if (list[cnt] == NULL)
Siddhesh Poyarekar 17b00fb
	{
Siddhesh Poyarekar 17b00fb
	  error (0, errno, "cannot add file to list \"%s\"", path);
Siddhesh Poyarekar 17b00fb
	  continue;
Siddhesh Poyarekar 17b00fb
	}
Siddhesh Poyarekar 17b00fb
      if (primary != NULL && cnt > 0 && strcmp (primary, d->d_name) == 0)
Siddhesh Poyarekar 17b00fb
	{
Siddhesh Poyarekar 17b00fb
	  char *p = list[0];
Siddhesh Poyarekar 17b00fb
	  list[0] = list[cnt];
Siddhesh Poyarekar 17b00fb
	  list[cnt] = p;
Siddhesh Poyarekar 17b00fb
	}
Siddhesh Poyarekar 17b00fb
      cnt++;
Siddhesh Poyarekar 17b00fb
    }
Siddhesh Poyarekar 17b00fb
  closedir (dirp);
c2021d0
  /* Store the archive to the file specified as the second argument on the
c2021d0
     command line or the default locale archive.  */
Carlos O'Donell 91764bd
  fill_archive (&tmpl_ah, new_locar_fname,
Carlos O'Donell 91764bd
                install_langs_count, install_langs_list,
Carlos O'Donell 91764bd
                cnt, list, primary);
Siddhesh Poyarekar 17b00fb
  close_archive (&tmpl_ah);
Siddhesh Poyarekar 17b00fb
  truncate (tmpl_file, 0);
Carlos O'Donell 91764bd
  if (install_langs_count > 0)
Carlos O'Donell 91764bd
    {
Carlos O'Donell 91764bd
      free (ila_start);
Carlos O'Donell 91764bd
      free (install_langs_list);
Carlos O'Donell 91764bd
    }
c2021d0
  char *tz_argv[] = { "/usr/sbin/tzdata-update", NULL };
c2021d0
  execve (tz_argv[0], (char *const *)tz_argv, (char *const *)&tz_argv[1]);
Siddhesh Poyarekar 17b00fb
  exit (0);
Siddhesh Poyarekar 17b00fb
}