Blame elf/cache.c

Packit Service 82fcde
/* Copyright (C) 1999-2018 Free Software Foundation, Inc.
Packit Service 82fcde
   This file is part of the GNU C Library.
Packit Service 82fcde
   Contributed by Andreas Jaeger <aj@suse.de>, 1999.
Packit Service 82fcde
Packit Service 82fcde
   This program is free software; you can redistribute it and/or modify
Packit Service 82fcde
   it under the terms of the GNU General Public License as published
Packit Service 82fcde
   by the Free Software Foundation; version 2 of the License, or
Packit Service 82fcde
   (at your option) any later version.
Packit Service 82fcde
Packit Service 82fcde
   This program is distributed in the hope that it will be useful,
Packit Service 82fcde
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 82fcde
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service 82fcde
   GNU General Public License for more details.
Packit Service 82fcde
Packit Service 82fcde
   You should have received a copy of the GNU General Public License
Packit Service 82fcde
   along with this program; if not, see <http://www.gnu.org/licenses/>.  */
Packit Service 82fcde
Packit Service 82fcde
#include <errno.h>
Packit Service 82fcde
#include <error.h>
Packit Service 82fcde
#include <dirent.h>
Packit Service 82fcde
#include <inttypes.h>
Packit Service 82fcde
#include <libgen.h>
Packit Service 82fcde
#include <libintl.h>
Packit Service 82fcde
#include <stdio.h>
Packit Service 82fcde
#include <stdlib.h>
Packit Service 82fcde
#include <string.h>
Packit Service 82fcde
#include <unistd.h>
Packit Service 82fcde
#include <stdint.h>
Packit Service 82fcde
#include <sys/fcntl.h>
Packit Service 82fcde
#include <sys/mman.h>
Packit Service 82fcde
#include <sys/stat.h>
Packit Service 82fcde
#include <sys/types.h>
Packit Service 82fcde
Packit Service 82fcde
#include <ldconfig.h>
Packit Service 82fcde
#include <dl-cache.h>
Packit Service 82fcde
Packit Service 82fcde
struct cache_entry
Packit Service 82fcde
{
Packit Service 82fcde
  char *lib;			/* Library name.  */
Packit Service 82fcde
  char *path;			/* Path to find library.  */
Packit Service 82fcde
  int flags;			/* Flags to indicate kind of library.  */
Packit Service 82fcde
  unsigned int osversion;	/* Required OS version.  */
Packit Service 82fcde
  uint64_t hwcap;		/* Important hardware capabilities.  */
Packit Service 82fcde
  int bits_hwcap;		/* Number of bits set in hwcap.  */
Packit Service 82fcde
  struct cache_entry *next;	/* Next entry in list.  */
Packit Service 82fcde
};
Packit Service 82fcde
Packit Service 82fcde
/* List of all cache entries.  */
Packit Service 82fcde
static struct cache_entry *entries;
Packit Service 82fcde
Packit Service 82fcde
static const char *flag_descr[] =
Packit Service 82fcde
{ "libc4", "ELF", "libc5", "libc6"};
Packit Service 82fcde
Packit Service 82fcde
/* Print a single entry.  */
Packit Service 82fcde
static void
Packit Service 82fcde
print_entry (const char *lib, int flag, unsigned int osversion,
Packit Service 82fcde
	     uint64_t hwcap, const char *key)
Packit Service 82fcde
{
Packit Service 82fcde
  printf ("\t%s (", lib);
Packit Service 82fcde
  switch (flag & FLAG_TYPE_MASK)
Packit Service 82fcde
    {
Packit Service 82fcde
    case FLAG_LIBC4:
Packit Service 82fcde
    case FLAG_ELF:
Packit Service 82fcde
    case FLAG_ELF_LIBC5:
Packit Service 82fcde
    case FLAG_ELF_LIBC6:
Packit Service 82fcde
      fputs (flag_descr[flag & FLAG_TYPE_MASK], stdout);
Packit Service 82fcde
      break;
Packit Service 82fcde
    default:
Packit Service 82fcde
      fputs (_("unknown"), stdout);
Packit Service 82fcde
      break;
Packit Service 82fcde
    }
Packit Service 82fcde
  switch (flag & FLAG_REQUIRED_MASK)
Packit Service 82fcde
    {
Packit Service 82fcde
    case FLAG_SPARC_LIB64:
Packit Service 82fcde
      fputs (",64bit", stdout);
Packit Service 82fcde
      break;
Packit Service 82fcde
    case FLAG_IA64_LIB64:
Packit Service 82fcde
      fputs (",IA-64", stdout);
Packit Service 82fcde
      break;
Packit Service 82fcde
    case FLAG_X8664_LIB64:
Packit Service 82fcde
      fputs (",x86-64", stdout);
Packit Service 82fcde
      break;
Packit Service 82fcde
    case FLAG_S390_LIB64:
Packit Service 82fcde
      fputs (",64bit", stdout);
Packit Service 82fcde
      break;
Packit Service 82fcde
    case FLAG_POWERPC_LIB64:
Packit Service 82fcde
      fputs (",64bit", stdout);
Packit Service 82fcde
      break;
Packit Service 82fcde
    case FLAG_MIPS64_LIBN32:
Packit Service 82fcde
      fputs (",N32", stdout);
Packit Service 82fcde
      break;
Packit Service 82fcde
    case FLAG_MIPS64_LIBN64:
Packit Service 82fcde
      fputs (",64bit", stdout);
Packit Service 82fcde
      break;
Packit Service 82fcde
    case FLAG_X8664_LIBX32:
Packit Service 82fcde
      fputs (",x32", stdout);
Packit Service 82fcde
      break;
Packit Service 82fcde
    case FLAG_ARM_LIBHF:
Packit Service 82fcde
      fputs (",hard-float", stdout);
Packit Service 82fcde
      break;
Packit Service 82fcde
    case FLAG_AARCH64_LIB64:
Packit Service 82fcde
      fputs (",AArch64", stdout);
Packit Service 82fcde
      break;
Packit Service 82fcde
    /* Uses the ARM soft-float ABI.  */
Packit Service 82fcde
    case FLAG_ARM_LIBSF:
Packit Service 82fcde
      fputs (",soft-float", stdout);
Packit Service 82fcde
      break;
Packit Service 82fcde
    case FLAG_MIPS_LIB32_NAN2008:
Packit Service 82fcde
      fputs (",nan2008", stdout);
Packit Service 82fcde
      break;
Packit Service 82fcde
    case FLAG_MIPS64_LIBN32_NAN2008:
Packit Service 82fcde
      fputs (",N32,nan2008", stdout);
Packit Service 82fcde
      break;
Packit Service 82fcde
    case FLAG_MIPS64_LIBN64_NAN2008:
Packit Service 82fcde
      fputs (",64bit,nan2008", stdout);
Packit Service 82fcde
      break;
Packit Service 82fcde
    case FLAG_RISCV_FLOAT_ABI_SOFT:
Packit Service 82fcde
      fputs (",soft-float", stdout);
Packit Service 82fcde
      break;
Packit Service 82fcde
    case FLAG_RISCV_FLOAT_ABI_DOUBLE:
Packit Service 82fcde
      fputs (",double-float", stdout);
Packit Service 82fcde
      break;
Packit Service 82fcde
    case 0:
Packit Service 82fcde
      break;
Packit Service 82fcde
    default:
Packit Service 82fcde
      printf (",%d", flag & FLAG_REQUIRED_MASK);
Packit Service 82fcde
      break;
Packit Service 82fcde
    }
Packit Service 82fcde
  if (hwcap != 0)
Packit Service 82fcde
    printf (", hwcap: %#.16" PRIx64, hwcap);
Packit Service 82fcde
  if (osversion != 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      static const char *const abi_tag_os[] =
Packit Service 82fcde
      {
Packit Service 82fcde
	[0] = "Linux",
Packit Service 82fcde
	[1] = "Hurd",
Packit Service 82fcde
	[2] = "Solaris",
Packit Service 82fcde
	[3] = "FreeBSD",
Packit Service 82fcde
	[4] = "kNetBSD",
Packit Service 82fcde
	[5] = "Syllable",
Packit Service 82fcde
	[6] = N_("Unknown OS")
Packit Service 82fcde
      };
Packit Service 82fcde
#define MAXTAG (sizeof abi_tag_os / sizeof abi_tag_os[0] - 1)
Packit Service 82fcde
      unsigned int os = osversion >> 24;
Packit Service 82fcde
Packit Service 82fcde
      printf (_(", OS ABI: %s %d.%d.%d"),
Packit Service 82fcde
	      _(abi_tag_os[os > MAXTAG ? MAXTAG : os]),
Packit Service 82fcde
	      (osversion >> 16) & 0xff,
Packit Service 82fcde
	      (osversion >> 8) & 0xff,
Packit Service 82fcde
	      osversion & 0xff);
Packit Service 82fcde
    }
Packit Service 82fcde
  printf (") => %s\n", key);
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
/* Print the whole cache file, if a file contains the new cache format
Packit Service 82fcde
   hidden in the old one, print the contents of the new format.  */
Packit Service 82fcde
void
Packit Service 82fcde
print_cache (const char *cache_name)
Packit Service 82fcde
{
Packit Service 82fcde
  int fd = open (cache_name, O_RDONLY);
Packit Service 82fcde
  if (fd < 0)
Packit Service 82fcde
    error (EXIT_FAILURE, errno, _("Can't open cache file %s\n"), cache_name);
Packit Service 82fcde
Packit Service 82fcde
  struct stat64 st;
Packit Service 82fcde
  if (fstat64 (fd, &st) < 0
Packit Service 82fcde
      /* No need to map the file if it is empty.  */
Packit Service 82fcde
      || st.st_size == 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      close (fd);
Packit Service 82fcde
      return;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  struct cache_file *cache
Packit Service 82fcde
    = mmap (NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
Packit Service 82fcde
  if (cache == MAP_FAILED)
Packit Service 82fcde
    error (EXIT_FAILURE, errno, _("mmap of cache file failed.\n"));
Packit Service 82fcde
Packit Service 82fcde
  size_t cache_size = st.st_size;
Packit Service 82fcde
  if (cache_size < sizeof (struct cache_file))
Packit Service 82fcde
    error (EXIT_FAILURE, 0, _("File is not a cache file.\n"));
Packit Service 82fcde
Packit Service 82fcde
  struct cache_file_new *cache_new = NULL;
Packit Service 82fcde
  const char *cache_data;
Packit Service 82fcde
  int format = 0;
Packit Service 82fcde
Packit Service 82fcde
  if (memcmp (cache->magic, CACHEMAGIC, sizeof CACHEMAGIC - 1))
Packit Service 82fcde
    {
Packit Service 82fcde
      /* This can only be the new format without the old one.  */
Packit Service 82fcde
      cache_new = (struct cache_file_new *) cache;
Packit Service 82fcde
Packit Service 82fcde
      if (memcmp (cache_new->magic, CACHEMAGIC_NEW, sizeof CACHEMAGIC_NEW - 1)
Packit Service 82fcde
	  || memcmp (cache_new->version, CACHE_VERSION,
Packit Service 82fcde
		      sizeof CACHE_VERSION - 1))
Packit Service 82fcde
	error (EXIT_FAILURE, 0, _("File is not a cache file.\n"));
Packit Service 82fcde
      format = 1;
Packit Service 82fcde
      /* This is where the strings start.  */
Packit Service 82fcde
      cache_data = (const char *) cache_new;
Packit Service 82fcde
    }
Packit Service 82fcde
  else
Packit Service 82fcde
    {
Packit Service 82fcde
      size_t offset = ALIGN_CACHE (sizeof (struct cache_file)
Packit Service 82fcde
				   + (cache->nlibs
Packit Service 82fcde
				      * sizeof (struct file_entry)));
Packit Service 82fcde
      /* This is where the strings start.  */
Packit Service 82fcde
      cache_data = (const char *) &cache->libs[cache->nlibs];
Packit Service 82fcde
Packit Service 82fcde
      /* Check for a new cache embedded in the old format.  */
Packit Service 82fcde
      if (cache_size >
Packit Service 82fcde
	  (offset + sizeof (struct cache_file_new)))
Packit Service 82fcde
	{
Packit Service 82fcde
Packit Service 82fcde
	  cache_new = (struct cache_file_new *) ((void *)cache + offset);
Packit Service 82fcde
Packit Service 82fcde
	  if (memcmp (cache_new->magic, CACHEMAGIC_NEW,
Packit Service 82fcde
		      sizeof CACHEMAGIC_NEW - 1) == 0
Packit Service 82fcde
	      && memcmp (cache_new->version, CACHE_VERSION,
Packit Service 82fcde
			 sizeof CACHE_VERSION - 1) == 0)
Packit Service 82fcde
	    {
Packit Service 82fcde
	      cache_data = (const char *) cache_new;
Packit Service 82fcde
	      format = 1;
Packit Service 82fcde
	    }
Packit Service 82fcde
	}
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  if (format == 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      printf (_("%d libs found in cache `%s'\n"), cache->nlibs, cache_name);
Packit Service 82fcde
Packit Service 82fcde
      /* Print everything.  */
Packit Service 82fcde
      for (unsigned int i = 0; i < cache->nlibs; i++)
Packit Service 82fcde
	print_entry (cache_data + cache->libs[i].key,
Packit Service 82fcde
		     cache->libs[i].flags, 0, 0,
Packit Service 82fcde
		     cache_data + cache->libs[i].value);
Packit Service 82fcde
    }
Packit Service 82fcde
  else if (format == 1)
Packit Service 82fcde
    {
Packit Service 82fcde
      printf (_("%d libs found in cache `%s'\n"),
Packit Service 82fcde
	      cache_new->nlibs, cache_name);
Packit Service 82fcde
Packit Service 82fcde
      /* Print everything.  */
Packit Service 82fcde
      for (unsigned int i = 0; i < cache_new->nlibs; i++)
Packit Service 82fcde
	print_entry (cache_data + cache_new->libs[i].key,
Packit Service 82fcde
		     cache_new->libs[i].flags,
Packit Service 82fcde
		     cache_new->libs[i].osversion,
Packit Service 82fcde
		     cache_new->libs[i].hwcap,
Packit Service 82fcde
		     cache_data + cache_new->libs[i].value);
Packit Service 82fcde
    }
Packit Service 82fcde
  /* Cleanup.  */
Packit Service 82fcde
  munmap (cache, cache_size);
Packit Service 82fcde
  close (fd);
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
/* Initialize cache data structures.  */
Packit Service 82fcde
void
Packit Service 82fcde
init_cache (void)
Packit Service 82fcde
{
Packit Service 82fcde
  entries = NULL;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
static int
Packit Service 82fcde
compare (const struct cache_entry *e1, const struct cache_entry *e2)
Packit Service 82fcde
{
Packit Service 82fcde
  /* We need to swap entries here to get the correct sort order.  */
Packit Service 82fcde
  int res = _dl_cache_libcmp (e2->lib, e1->lib);
Packit Service 82fcde
  if (res == 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      if (e1->flags < e2->flags)
Packit Service 82fcde
	return 1;
Packit Service 82fcde
      else if (e1->flags > e2->flags)
Packit Service 82fcde
	return -1;
Packit Service 82fcde
      /* Sort by most specific hwcap.  */
Packit Service 82fcde
      else if (e2->bits_hwcap > e1->bits_hwcap)
Packit Service 82fcde
	return 1;
Packit Service 82fcde
      else if (e2->bits_hwcap < e1->bits_hwcap)
Packit Service 82fcde
	return -1;
Packit Service 82fcde
      else if (e2->hwcap > e1->hwcap)
Packit Service 82fcde
	return 1;
Packit Service 82fcde
      else if (e2->hwcap < e1->hwcap)
Packit Service 82fcde
	return -1;
Packit Service 82fcde
      if (e2->osversion > e1->osversion)
Packit Service 82fcde
	return 1;
Packit Service 82fcde
      if (e2->osversion < e1->osversion)
Packit Service 82fcde
	return -1;
Packit Service 82fcde
    }
Packit Service 82fcde
  return res;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
/* Save the contents of the cache.  */
Packit Service 82fcde
void
Packit Service 82fcde
save_cache (const char *cache_name)
Packit Service 82fcde
{
Packit Service 82fcde
  /* The cache entries are sorted already, save them in this order. */
Packit Service 82fcde
Packit Service 82fcde
  /* Count the length of all strings.  */
Packit Service 82fcde
  /* The old format doesn't contain hwcap entries and doesn't contain
Packit Service 82fcde
     libraries in subdirectories with hwcaps entries.  Count therefore
Packit Service 82fcde
     also all entries with hwcap == 0.  */
Packit Service 82fcde
  size_t total_strlen = 0;
Packit Service 82fcde
  struct cache_entry *entry;
Packit Service 82fcde
  /* Number of cache entries.  */
Packit Service 82fcde
  int cache_entry_count = 0;
Packit Service 82fcde
  /* Number of normal cache entries.  */
Packit Service 82fcde
  int cache_entry_old_count = 0;
Packit Service 82fcde
Packit Service 82fcde
  for (entry = entries; entry != NULL; entry = entry->next)
Packit Service 82fcde
    {
Packit Service 82fcde
      /* Account the final NULs.  */
Packit Service 82fcde
      total_strlen += strlen (entry->lib) + strlen (entry->path) + 2;
Packit Service 82fcde
      ++cache_entry_count;
Packit Service 82fcde
      if (entry->hwcap == 0)
Packit Service 82fcde
	++cache_entry_old_count;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  /* Create the on disk cache structure.  */
Packit Service 82fcde
  struct cache_file *file_entries = NULL;
Packit Service 82fcde
  size_t file_entries_size = 0;
Packit Service 82fcde
Packit Service 82fcde
  if (opt_format != 2)
Packit Service 82fcde
    {
Packit Service 82fcde
      /* struct cache_file_new is 64-bit aligned on some arches while
Packit Service 82fcde
	 only 32-bit aligned on other arches.  Duplicate last old
Packit Service 82fcde
	 cache entry so that new cache in ld.so.cache can be used by
Packit Service 82fcde
	 both.  */
Packit Service 82fcde
      if (opt_format != 0)
Packit Service 82fcde
	cache_entry_old_count = (cache_entry_old_count + 1) & ~1;
Packit Service 82fcde
Packit Service 82fcde
      /* And the list of all entries in the old format.  */
Packit Service 82fcde
      file_entries_size = sizeof (struct cache_file)
Packit Service 82fcde
	+ cache_entry_old_count * sizeof (struct file_entry);
Packit Service 82fcde
      file_entries = xmalloc (file_entries_size);
Packit Service 82fcde
Packit Service 82fcde
      /* Fill in the header.  */
Packit Service 82fcde
      memset (file_entries, '\0', sizeof (struct cache_file));
Packit Service 82fcde
      memcpy (file_entries->magic, CACHEMAGIC, sizeof CACHEMAGIC - 1);
Packit Service 82fcde
Packit Service 82fcde
      file_entries->nlibs = cache_entry_old_count;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  struct cache_file_new *file_entries_new = NULL;
Packit Service 82fcde
  size_t file_entries_new_size = 0;
Packit Service 82fcde
Packit Service 82fcde
  if (opt_format != 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      /* And the list of all entries in the new format.  */
Packit Service 82fcde
      file_entries_new_size = sizeof (struct cache_file_new)
Packit Service 82fcde
	+ cache_entry_count * sizeof (struct file_entry_new);
Packit Service 82fcde
      file_entries_new = xmalloc (file_entries_new_size);
Packit Service 82fcde
Packit Service 82fcde
      /* Fill in the header.  */
Packit Service 82fcde
      memset (file_entries_new, '\0', sizeof (struct cache_file_new));
Packit Service 82fcde
      memcpy (file_entries_new->magic, CACHEMAGIC_NEW,
Packit Service 82fcde
	      sizeof CACHEMAGIC_NEW - 1);
Packit Service 82fcde
      memcpy (file_entries_new->version, CACHE_VERSION,
Packit Service 82fcde
	      sizeof CACHE_VERSION - 1);
Packit Service 82fcde
Packit Service 82fcde
      file_entries_new->nlibs = cache_entry_count;
Packit Service 82fcde
      file_entries_new->len_strings = total_strlen;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  /* Pad for alignment of cache_file_new.  */
Packit Service 82fcde
  size_t pad = ALIGN_CACHE (file_entries_size) - file_entries_size;
Packit Service 82fcde
Packit Service 82fcde
  /* If we have both formats, we hide the new format in the strings
Packit Service 82fcde
     table, we have to adjust all string indices for this so that
Packit Service 82fcde
     old libc5/glibc 2 dynamic linkers just ignore them.  */
Packit Service 82fcde
  unsigned int str_offset;
Packit Service 82fcde
  if (opt_format != 0)
Packit Service 82fcde
    str_offset = file_entries_new_size;
Packit Service 82fcde
  else
Packit Service 82fcde
    str_offset = 0;
Packit Service 82fcde
Packit Service 82fcde
  /* An array for all strings.  */
Packit Service 82fcde
  char *strings = xmalloc (total_strlen);
Packit Service 82fcde
  char *str = strings;
Packit Service 82fcde
  int idx_old;
Packit Service 82fcde
  int idx_new;
Packit Service 82fcde
Packit Service 82fcde
  for (idx_old = 0, idx_new = 0, entry = entries; entry != NULL;
Packit Service 82fcde
       entry = entry->next, ++idx_new)
Packit Service 82fcde
    {
Packit Service 82fcde
      /* First the library.  */
Packit Service 82fcde
      if (opt_format != 2 && entry->hwcap == 0)
Packit Service 82fcde
	{
Packit Service 82fcde
	  file_entries->libs[idx_old].flags = entry->flags;
Packit Service 82fcde
	  /* XXX: Actually we can optimize here and remove duplicates.  */
Packit Service 82fcde
	  file_entries->libs[idx_old].key = str_offset + pad;
Packit Service 82fcde
	}
Packit Service 82fcde
      if (opt_format != 0)
Packit Service 82fcde
	{
Packit Service 82fcde
	  /* We could subtract file_entries_new_size from str_offset -
Packit Service 82fcde
	     not doing so makes the code easier, the string table
Packit Service 82fcde
	     always begins at the beginning of the new cache
Packit Service 82fcde
	     struct.  */
Packit Service 82fcde
	  file_entries_new->libs[idx_new].flags = entry->flags;
Packit Service 82fcde
	  file_entries_new->libs[idx_new].osversion = entry->osversion;
Packit Service 82fcde
	  file_entries_new->libs[idx_new].hwcap = entry->hwcap;
Packit Service 82fcde
	  file_entries_new->libs[idx_new].key = str_offset;
Packit Service 82fcde
	}
Packit Service 82fcde
Packit Service 82fcde
      size_t len = strlen (entry->lib) + 1;
Packit Service 82fcde
      str = mempcpy (str, entry->lib, len);
Packit Service 82fcde
      str_offset += len;
Packit Service 82fcde
      /* Then the path.  */
Packit Service 82fcde
      if (opt_format != 2 && entry->hwcap == 0)
Packit Service 82fcde
	file_entries->libs[idx_old].value = str_offset + pad;
Packit Service 82fcde
      if (opt_format != 0)
Packit Service 82fcde
	file_entries_new->libs[idx_new].value = str_offset;
Packit Service 82fcde
      len = strlen (entry->path) + 1;
Packit Service 82fcde
      str = mempcpy (str, entry->path, len);
Packit Service 82fcde
      str_offset += len;
Packit Service 82fcde
      /* Ignore entries with hwcap for old format.  */
Packit Service 82fcde
      if (entry->hwcap == 0)
Packit Service 82fcde
	++idx_old;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  /* Duplicate last old cache entry if needed.  */
Packit Service 82fcde
  if (opt_format != 2
Packit Service 82fcde
      && idx_old < cache_entry_old_count)
Packit Service 82fcde
    file_entries->libs[idx_old] = file_entries->libs[idx_old - 1];
Packit Service 82fcde
Packit Service 82fcde
  /* Write out the cache.  */
Packit Service 82fcde
Packit Service 82fcde
  /* Write cache first to a temporary file and rename it later.  */
Packit Service 82fcde
  char *temp_name = xmalloc (strlen (cache_name) + 2);
Packit Service 82fcde
  sprintf (temp_name, "%s~", cache_name);
Packit Service 82fcde
Packit Service 82fcde
  /* Create file.  */
Packit Service 82fcde
  int fd = open (temp_name, O_CREAT|O_WRONLY|O_TRUNC|O_NOFOLLOW,
Packit Service 82fcde
		 S_IRUSR|S_IWUSR);
Packit Service 82fcde
  if (fd < 0)
Packit Service 82fcde
    error (EXIT_FAILURE, errno, _("Can't create temporary cache file %s"),
Packit Service 82fcde
	   temp_name);
Packit Service 82fcde
Packit Service 82fcde
  /* Write contents.  */
Packit Service 82fcde
  if (opt_format != 2)
Packit Service 82fcde
    {
Packit Service 82fcde
      if (write (fd, file_entries, file_entries_size)
Packit Service 82fcde
	  != (ssize_t) file_entries_size)
Packit Service 82fcde
	error (EXIT_FAILURE, errno, _("Writing of cache data failed"));
Packit Service 82fcde
    }
Packit Service 82fcde
  if (opt_format != 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      /* Align cache.  */
Packit Service 82fcde
      if (opt_format != 2)
Packit Service 82fcde
	{
Packit Service 82fcde
	  char zero[pad];
Packit Service 82fcde
	  memset (zero, '\0', pad);
Packit Service 82fcde
	  if (write (fd, zero, pad) != (ssize_t) pad)
Packit Service 82fcde
	    error (EXIT_FAILURE, errno, _("Writing of cache data failed"));
Packit Service 82fcde
	}
Packit Service 82fcde
      if (write (fd, file_entries_new, file_entries_new_size)
Packit Service 82fcde
	  != (ssize_t) file_entries_new_size)
Packit Service 82fcde
	error (EXIT_FAILURE, errno, _("Writing of cache data failed"));
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  if (write (fd, strings, total_strlen) != (ssize_t) total_strlen)
Packit Service 82fcde
    error (EXIT_FAILURE, errno, _("Writing of cache data failed"));
Packit Service 82fcde
Packit Service 82fcde
  /* Make sure user can always read cache file */
Packit Service 82fcde
  if (chmod (temp_name, S_IROTH|S_IRGRP|S_IRUSR|S_IWUSR))
Packit Service 82fcde
    error (EXIT_FAILURE, errno,
Packit Service 82fcde
	   _("Changing access rights of %s to %#o failed"), temp_name,
Packit Service 82fcde
	   S_IROTH|S_IRGRP|S_IRUSR|S_IWUSR);
Packit Service 82fcde
Packit Service 82fcde
  /* Make sure that data is written to disk.  */
Packit Service 82fcde
  if (fsync (fd) != 0 || close (fd) != 0)
Packit Service 82fcde
    error (EXIT_FAILURE, errno, _("Writing of cache data failed"));
Packit Service 82fcde
Packit Service 82fcde
  /* Move temporary to its final location.  */
Packit Service 82fcde
  if (rename (temp_name, cache_name))
Packit Service 82fcde
    error (EXIT_FAILURE, errno, _("Renaming of %s to %s failed"), temp_name,
Packit Service 82fcde
	   cache_name);
Packit Service 82fcde
Packit Service 82fcde
  /* Free all allocated memory.  */
Packit Service 82fcde
  free (file_entries_new);
Packit Service 82fcde
  free (file_entries);
Packit Service 82fcde
  free (strings);
Packit Service 82fcde
Packit Service 82fcde
  while (entries)
Packit Service 82fcde
    {
Packit Service 82fcde
      entry = entries;
Packit Service 82fcde
      entries = entries->next;
Packit Service 82fcde
      free (entry);
Packit Service 82fcde
    }
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
/* Add one library to the cache.  */
Packit Service 82fcde
void
Packit Service 82fcde
add_to_cache (const char *path, const char *lib, int flags,
Packit Service 82fcde
	      unsigned int osversion, uint64_t hwcap)
Packit Service 82fcde
{
Packit Service 82fcde
  size_t liblen = strlen (lib) + 1;
Packit Service 82fcde
  size_t len = liblen + strlen (path) + 1;
Packit Service 82fcde
  struct cache_entry *new_entry
Packit Service 82fcde
    = xmalloc (sizeof (struct cache_entry) + liblen + len);
Packit Service 82fcde
Packit Service 82fcde
  new_entry->lib = memcpy ((char *) (new_entry + 1), lib, liblen);
Packit Service 82fcde
  new_entry->path = new_entry->lib + liblen;
Packit Service 82fcde
  snprintf (new_entry->path, len, "%s/%s", path, lib);
Packit Service 82fcde
  new_entry->flags = flags;
Packit Service 82fcde
  new_entry->osversion = osversion;
Packit Service 82fcde
  new_entry->hwcap = hwcap;
Packit Service 82fcde
  new_entry->bits_hwcap = 0;
Packit Service 82fcde
Packit Service 82fcde
  /* Count the number of bits set in the masked value.  */
Packit Service 82fcde
  for (size_t i = 0;
Packit Service 82fcde
       (~((1ULL << i) - 1) & hwcap) != 0 && i < 8 * sizeof (hwcap); ++i)
Packit Service 82fcde
    if ((hwcap & (1ULL << i)) != 0)
Packit Service 82fcde
      ++new_entry->bits_hwcap;
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
  /* Keep the list sorted - search for right place to insert.  */
Packit Service 82fcde
  struct cache_entry *ptr = entries;
Packit Service 82fcde
  struct cache_entry *prev = entries;
Packit Service 82fcde
  while (ptr != NULL)
Packit Service 82fcde
    {
Packit Service 82fcde
      if (compare (ptr, new_entry) > 0)
Packit Service 82fcde
	break;
Packit Service 82fcde
      prev = ptr;
Packit Service 82fcde
      ptr = ptr->next;
Packit Service 82fcde
    }
Packit Service 82fcde
  /* Is this the first entry?  */
Packit Service 82fcde
  if (ptr == entries)
Packit Service 82fcde
    {
Packit Service 82fcde
      new_entry->next = entries;
Packit Service 82fcde
      entries = new_entry;
Packit Service 82fcde
    }
Packit Service 82fcde
  else
Packit Service 82fcde
    {
Packit Service 82fcde
      new_entry->next = prev->next;
Packit Service 82fcde
      prev->next = new_entry;
Packit Service 82fcde
    }
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
/* Auxiliary cache.  */
Packit Service 82fcde
Packit Service 82fcde
struct aux_cache_entry_id
Packit Service 82fcde
{
Packit Service 82fcde
  uint64_t ino;
Packit Service 82fcde
  uint64_t ctime;
Packit Service 82fcde
  uint64_t size;
Packit Service 82fcde
  uint64_t dev;
Packit Service 82fcde
};
Packit Service 82fcde
Packit Service 82fcde
struct aux_cache_entry
Packit Service 82fcde
{
Packit Service 82fcde
  struct aux_cache_entry_id id;
Packit Service 82fcde
  int flags;
Packit Service 82fcde
  unsigned int osversion;
Packit Service 82fcde
  int used;
Packit Service 82fcde
  char *soname;
Packit Service 82fcde
  struct aux_cache_entry *next;
Packit Service 82fcde
};
Packit Service 82fcde
Packit Service 82fcde
#define AUX_CACHEMAGIC		"glibc-ld.so.auxcache-1.0"
Packit Service 82fcde
Packit Service 82fcde
struct aux_cache_file_entry
Packit Service 82fcde
{
Packit Service 82fcde
  struct aux_cache_entry_id id;	/* Unique id of entry.  */
Packit Service 82fcde
  int32_t flags;		/* This is 1 for an ELF library.  */
Packit Service 82fcde
  uint32_t soname;		/* String table indice.  */
Packit Service 82fcde
  uint32_t osversion;		/* Required OS version.	 */
Packit Service 82fcde
  int32_t pad;
Packit Service 82fcde
};
Packit Service 82fcde
Packit Service 82fcde
/* ldconfig maintains an auxiliary cache file that allows
Packit Service 82fcde
   only reading those libraries that have changed since the last iteration.
Packit Service 82fcde
   For this for each library some information is cached in the auxiliary
Packit Service 82fcde
   cache.  */
Packit Service 82fcde
struct aux_cache_file
Packit Service 82fcde
{
Packit Service 82fcde
  char magic[sizeof AUX_CACHEMAGIC - 1];
Packit Service 82fcde
  uint32_t nlibs;		/* Number of entries.  */
Packit Service 82fcde
  uint32_t len_strings;		/* Size of string table. */
Packit Service 82fcde
  struct aux_cache_file_entry libs[0]; /* Entries describing libraries.  */
Packit Service 82fcde
  /* After this the string table of size len_strings is found.	*/
Packit Service 82fcde
};
Packit Service 82fcde
Packit Service 82fcde
static const unsigned int primes[] =
Packit Service 82fcde
{
Packit Service 82fcde
  1021, 2039, 4093, 8191, 16381, 32749, 65521, 131071, 262139,
Packit Service 82fcde
  524287, 1048573, 2097143, 4194301, 8388593, 16777213, 33554393,
Packit Service 82fcde
  67108859, 134217689, 268435399, 536870909, 1073741789, 2147483647
Packit Service 82fcde
};
Packit Service 82fcde
Packit Service 82fcde
static size_t aux_hash_size;
Packit Service 82fcde
static struct aux_cache_entry **aux_hash;
Packit Service 82fcde
Packit Service 82fcde
/* Simplistic hash function for aux_cache_entry_id.  */
Packit Service 82fcde
static unsigned int
Packit Service 82fcde
aux_cache_entry_id_hash (struct aux_cache_entry_id *id)
Packit Service 82fcde
{
Packit Service 82fcde
  uint64_t ret = ((id->ino * 11 + id->ctime) * 11 + id->size) * 11 + id->dev;
Packit Service 82fcde
  return ret ^ (ret >> 32);
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
static size_t nextprime (size_t x)
Packit Service 82fcde
{
Packit Service 82fcde
  for (unsigned int i = 0; i < sizeof (primes) / sizeof (primes[0]); ++i)
Packit Service 82fcde
    if (primes[i] >= x)
Packit Service 82fcde
      return primes[i];
Packit Service 82fcde
  return x;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
void
Packit Service 82fcde
init_aux_cache (void)
Packit Service 82fcde
{
Packit Service 82fcde
  aux_hash_size = primes[3];
Packit Service 82fcde
  aux_hash = xcalloc (aux_hash_size, sizeof (struct aux_cache_entry *));
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
int
Packit Service 82fcde
search_aux_cache (struct stat64 *stat_buf, int *flags,
Packit Service 82fcde
		  unsigned int *osversion, char **soname)
Packit Service 82fcde
{
Packit Service 82fcde
  struct aux_cache_entry_id id;
Packit Service 82fcde
  id.ino = (uint64_t) stat_buf->st_ino;
Packit Service 82fcde
  id.ctime = (uint64_t) stat_buf->st_ctime;
Packit Service 82fcde
  id.size = (uint64_t) stat_buf->st_size;
Packit Service 82fcde
  id.dev = (uint64_t) stat_buf->st_dev;
Packit Service 82fcde
Packit Service 82fcde
  unsigned int hash = aux_cache_entry_id_hash (&id;;
Packit Service 82fcde
  struct aux_cache_entry *entry;
Packit Service 82fcde
  for (entry = aux_hash[hash % aux_hash_size]; entry; entry = entry->next)
Packit Service 82fcde
    if (id.ino == entry->id.ino
Packit Service 82fcde
	&& id.ctime == entry->id.ctime
Packit Service 82fcde
	&& id.size == entry->id.size
Packit Service 82fcde
	&& id.dev == entry->id.dev)
Packit Service 82fcde
      {
Packit Service 82fcde
	*flags = entry->flags;
Packit Service 82fcde
	*osversion = entry->osversion;
Packit Service 82fcde
	if (entry->soname != NULL)
Packit Service 82fcde
	  *soname = xstrdup (entry->soname);
Packit Service 82fcde
	else
Packit Service 82fcde
	  *soname = NULL;
Packit Service 82fcde
	entry->used = 1;
Packit Service 82fcde
	return 1;
Packit Service 82fcde
      }
Packit Service 82fcde
Packit Service 82fcde
  return 0;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
static void
Packit Service 82fcde
insert_to_aux_cache (struct aux_cache_entry_id *id, int flags,
Packit Service 82fcde
		     unsigned int osversion, const char *soname, int used)
Packit Service 82fcde
{
Packit Service 82fcde
  size_t hash = aux_cache_entry_id_hash (id) % aux_hash_size;
Packit Service 82fcde
  struct aux_cache_entry *entry;
Packit Service 82fcde
  for (entry = aux_hash[hash]; entry; entry = entry->next)
Packit Service 82fcde
    if (id->ino == entry->id.ino
Packit Service 82fcde
	&& id->ctime == entry->id.ctime
Packit Service 82fcde
	&& id->size == entry->id.size
Packit Service 82fcde
	&& id->dev == entry->id.dev)
Packit Service 82fcde
      abort ();
Packit Service 82fcde
Packit Service 82fcde
  size_t len = soname ? strlen (soname) + 1 : 0;
Packit Service 82fcde
  entry = xmalloc (sizeof (struct aux_cache_entry) + len);
Packit Service 82fcde
  entry->id = *id;
Packit Service 82fcde
  entry->flags = flags;
Packit Service 82fcde
  entry->osversion = osversion;
Packit Service 82fcde
  entry->used = used;
Packit Service 82fcde
  if (soname != NULL)
Packit Service 82fcde
    entry->soname = memcpy ((char *) (entry + 1), soname, len);
Packit Service 82fcde
  else
Packit Service 82fcde
    entry->soname = NULL;
Packit Service 82fcde
  entry->next = aux_hash[hash];
Packit Service 82fcde
  aux_hash[hash] = entry;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
void
Packit Service 82fcde
add_to_aux_cache (struct stat64 *stat_buf, int flags,
Packit Service 82fcde
		  unsigned int osversion, const char *soname)
Packit Service 82fcde
{
Packit Service 82fcde
  struct aux_cache_entry_id id;
Packit Service 82fcde
  id.ino = (uint64_t) stat_buf->st_ino;
Packit Service 82fcde
  id.ctime = (uint64_t) stat_buf->st_ctime;
Packit Service 82fcde
  id.size = (uint64_t) stat_buf->st_size;
Packit Service 82fcde
  id.dev = (uint64_t) stat_buf->st_dev;
Packit Service 82fcde
  insert_to_aux_cache (&id, flags, osversion, soname, 1);
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
/* Load auxiliary cache to search for unchanged entries.   */
Packit Service 82fcde
void
Packit Service 82fcde
load_aux_cache (const char *aux_cache_name)
Packit Service 82fcde
{
Packit Service 82fcde
  int fd = open (aux_cache_name, O_RDONLY);
Packit Service 82fcde
  if (fd < 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      init_aux_cache ();
Packit Service 82fcde
      return;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  struct stat64 st;
Packit Service 82fcde
  if (fstat64 (fd, &st) < 0 || st.st_size < sizeof (struct aux_cache_file))
Packit Service 82fcde
    {
Packit Service 82fcde
      close (fd);
Packit Service 82fcde
      init_aux_cache ();
Packit Service 82fcde
      return;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  size_t aux_cache_size = st.st_size;
Packit Service 82fcde
  struct aux_cache_file *aux_cache
Packit Service 82fcde
    = mmap (NULL, aux_cache_size, PROT_READ, MAP_PRIVATE, fd, 0);
Packit Service 82fcde
  if (aux_cache == MAP_FAILED
Packit Service 82fcde
      || aux_cache_size < sizeof (struct aux_cache_file)
Packit Service 82fcde
      || memcmp (aux_cache->magic, AUX_CACHEMAGIC, sizeof AUX_CACHEMAGIC - 1)
Packit Service 82fcde
      || aux_cache_size != (sizeof(struct aux_cache_file) +
Packit Service 82fcde
			    aux_cache->nlibs * sizeof(struct aux_cache_file_entry) +
Packit Service 82fcde
			    aux_cache->len_strings))
Packit Service 82fcde
    {
Packit Service 82fcde
      close (fd);
Packit Service 82fcde
      init_aux_cache ();
Packit Service 82fcde
      return;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  aux_hash_size = nextprime (aux_cache->nlibs);
Packit Service 82fcde
  aux_hash = xcalloc (aux_hash_size, sizeof (struct aux_cache_entry *));
Packit Service 82fcde
Packit Service 82fcde
  const char *aux_cache_data
Packit Service 82fcde
    = (const char *) &aux_cache->libs[aux_cache->nlibs];
Packit Service 82fcde
  for (unsigned int i = 0; i < aux_cache->nlibs; ++i)
Packit Service 82fcde
    insert_to_aux_cache (&aux_cache->libs[i].id,
Packit Service 82fcde
			 aux_cache->libs[i].flags,
Packit Service 82fcde
			 aux_cache->libs[i].osversion,
Packit Service 82fcde
			 aux_cache->libs[i].soname == 0
Packit Service 82fcde
			 ? NULL : aux_cache_data + aux_cache->libs[i].soname,
Packit Service 82fcde
			 0);
Packit Service 82fcde
Packit Service 82fcde
  munmap (aux_cache, aux_cache_size);
Packit Service 82fcde
  close (fd);
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
/* Save the contents of the auxiliary cache.  */
Packit Service 82fcde
void
Packit Service 82fcde
save_aux_cache (const char *aux_cache_name)
Packit Service 82fcde
{
Packit Service 82fcde
  /* Count the length of all sonames.  We start with empty string.  */
Packit Service 82fcde
  size_t total_strlen = 1;
Packit Service 82fcde
  /* Number of cache entries.  */
Packit Service 82fcde
  int cache_entry_count = 0;
Packit Service 82fcde
Packit Service 82fcde
  for (size_t i = 0; i < aux_hash_size; ++i)
Packit Service 82fcde
    for (struct aux_cache_entry *entry = aux_hash[i];
Packit Service 82fcde
	 entry != NULL; entry = entry->next)
Packit Service 82fcde
      if (entry->used)
Packit Service 82fcde
	{
Packit Service 82fcde
	  ++cache_entry_count;
Packit Service 82fcde
	  if (entry->soname != NULL)
Packit Service 82fcde
	    total_strlen += strlen (entry->soname) + 1;
Packit Service 82fcde
	}
Packit Service 82fcde
Packit Service 82fcde
  /* Auxiliary cache.  */
Packit Service 82fcde
  size_t file_entries_size
Packit Service 82fcde
    = sizeof (struct aux_cache_file)
Packit Service 82fcde
      + cache_entry_count * sizeof (struct aux_cache_file_entry);
Packit Service 82fcde
  struct aux_cache_file *file_entries
Packit Service 82fcde
    = xmalloc (file_entries_size + total_strlen);
Packit Service 82fcde
Packit Service 82fcde
  /* Fill in the header of the auxiliary cache.  */
Packit Service 82fcde
  memset (file_entries, '\0', sizeof (struct aux_cache_file));
Packit Service 82fcde
  memcpy (file_entries->magic, AUX_CACHEMAGIC, sizeof AUX_CACHEMAGIC - 1);
Packit Service 82fcde
Packit Service 82fcde
  file_entries->nlibs = cache_entry_count;
Packit Service 82fcde
  file_entries->len_strings = total_strlen;
Packit Service 82fcde
Packit Service 82fcde
  /* Initial String offset for auxiliary cache is always after the
Packit Service 82fcde
     special empty string.  */
Packit Service 82fcde
  unsigned int str_offset = 1;
Packit Service 82fcde
Packit Service 82fcde
  /* An array for all strings.  */
Packit Service 82fcde
  char *str = (char *) file_entries + file_entries_size;
Packit Service 82fcde
  *str++ = '\0';
Packit Service 82fcde
Packit Service 82fcde
  size_t idx = 0;
Packit Service 82fcde
  for (size_t i = 0; i < aux_hash_size; ++i)
Packit Service 82fcde
    for (struct aux_cache_entry *entry = aux_hash[i];
Packit Service 82fcde
	 entry != NULL; entry = entry->next)
Packit Service 82fcde
      if (entry->used)
Packit Service 82fcde
	{
Packit Service 82fcde
	  file_entries->libs[idx].id = entry->id;
Packit Service 82fcde
	  file_entries->libs[idx].flags = entry->flags;
Packit Service 82fcde
	  if (entry->soname == NULL)
Packit Service 82fcde
	    file_entries->libs[idx].soname = 0;
Packit Service 82fcde
	  else
Packit Service 82fcde
	    {
Packit Service 82fcde
	      file_entries->libs[idx].soname = str_offset;
Packit Service 82fcde
Packit Service 82fcde
	      size_t len = strlen (entry->soname) + 1;
Packit Service 82fcde
	      str = mempcpy (str, entry->soname, len);
Packit Service 82fcde
	      str_offset += len;
Packit Service 82fcde
	    }
Packit Service 82fcde
	  file_entries->libs[idx].osversion = entry->osversion;
Packit Service 82fcde
	  file_entries->libs[idx++].pad = 0;
Packit Service 82fcde
	}
Packit Service 82fcde
Packit Service 82fcde
  /* Write out auxiliary cache file.  */
Packit Service 82fcde
  /* Write auxiliary cache first to a temporary file and rename it later.  */
Packit Service 82fcde
Packit Service 82fcde
  char *temp_name = xmalloc (strlen (aux_cache_name) + 2);
Packit Service 82fcde
  sprintf (temp_name, "%s~", aux_cache_name);
Packit Service 82fcde
Packit Service 82fcde
  /* Check that directory exists and create if needed.  */
Packit Service 82fcde
  char *dir = strdupa (aux_cache_name);
Packit Service 82fcde
  dir = dirname (dir);
Packit Service 82fcde
Packit Service 82fcde
  struct stat64 st;
Packit Service 82fcde
  if (stat64 (dir, &st) < 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      if (mkdir (dir, 0700) < 0)
Packit Service 82fcde
	goto out_fail;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  /* Create file.  */
Packit Service 82fcde
  int fd = open (temp_name, O_CREAT|O_WRONLY|O_TRUNC|O_NOFOLLOW,
Packit Service 82fcde
		 S_IRUSR|S_IWUSR);
Packit Service 82fcde
  if (fd < 0)
Packit Service 82fcde
    goto out_fail;
Packit Service 82fcde
Packit Service 82fcde
  if (write (fd, file_entries, file_entries_size + total_strlen)
Packit Service 82fcde
      != (ssize_t) (file_entries_size + total_strlen)
Packit Service 82fcde
      || fdatasync (fd) != 0
Packit Service 82fcde
      || close (fd) != 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      unlink (temp_name);
Packit Service 82fcde
      goto out_fail;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  /* Move temporary to its final location.  */
Packit Service 82fcde
  if (rename (temp_name, aux_cache_name))
Packit Service 82fcde
    unlink (temp_name);
Packit Service 82fcde
Packit Service 82fcde
out_fail:
Packit Service 82fcde
  /* Free allocated memory.  */
Packit Service 82fcde
  free (temp_name);
Packit Service 82fcde
  free (file_entries);
Packit Service 82fcde
}