hjl / source-git / glibc

Forked from source-git/glibc 3 years ago
Clone

Blame SPECS/build-locale-archive.c

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