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