Back to index

glibc  2.9
Defines | Functions | Variables
ldconfig.h File Reference
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Defines

#define FLAG_ANY   -1
#define FLAG_TYPE_MASK   0x00ff
#define FLAG_LIBC4   0x0000
#define FLAG_ELF   0x0001
#define FLAG_ELF_LIBC5   0x0002
#define FLAG_ELF_LIBC6   0x0003
#define FLAG_REQUIRED_MASK   0xff00
#define FLAG_SPARC_LIB64   0x0100
#define FLAG_IA64_LIB64   0x0200
#define FLAG_X8664_LIB64   0x0300
#define FLAG_S390_LIB64   0x0400
#define FLAG_POWERPC_LIB64   0x0500
#define FLAG_MIPS64_LIBN32   0x0600
#define FLAG_MIPS64_LIBN64   0x0700
#define _PATH_LDCONFIG_AUX_CACHE   "/var/cache/ldconfig/aux-cache"

Functions

void print_cache (const char *cache_name)
void init_cache (void)
void save_cache (const char *cache_name)
void add_to_cache (const char *path, const char *lib, int flags, unsigned int osversion, uint64_t hwcap)
void init_aux_cache (void)
void load_aux_cache (const char *aux_cache_name)
int search_aux_cache (struct stat64 *stat_buf, int *flags, unsigned int *osversion, char **soname)
void add_to_aux_cache (struct stat64 *stat_buf, int flags, unsigned int osversion, const char *soname)
void save_aux_cache (const char *aux_cache_name)
int process_file (const char *real_file_name, const char *file_name, const char *lib, int *flag, unsigned int *osversion, char **soname, int is_link, struct stat64 *stat_buf)
char * implicit_soname (const char *lib, int flag)
int process_elf_file (const char *file_name, const char *lib, int *flag, unsigned int *osversion, char **soname, void *file_contents, size_t file_length)
char * chroot_canon (const char *chroot, const char *name)
void * xmalloc (size_t __n)
void * xcalloc (size_t __n, size_t __size)
void * xrealloc (void *__p, size_t __n)
char * xstrdup (const char *__str)

Variables

int opt_verbose
int opt_format

Define Documentation

#define _PATH_LDCONFIG_AUX_CACHE   "/var/cache/ldconfig/aux-cache"

Definition at line 39 of file ldconfig.h.

#define FLAG_ANY   -1

Definition at line 23 of file ldconfig.h.

#define FLAG_ELF   0x0001

Definition at line 26 of file ldconfig.h.

#define FLAG_ELF_LIBC5   0x0002

Definition at line 27 of file ldconfig.h.

#define FLAG_ELF_LIBC6   0x0003

Definition at line 28 of file ldconfig.h.

#define FLAG_IA64_LIB64   0x0200

Definition at line 31 of file ldconfig.h.

#define FLAG_LIBC4   0x0000

Definition at line 25 of file ldconfig.h.

#define FLAG_MIPS64_LIBN32   0x0600

Definition at line 35 of file ldconfig.h.

#define FLAG_MIPS64_LIBN64   0x0700

Definition at line 36 of file ldconfig.h.

#define FLAG_POWERPC_LIB64   0x0500

Definition at line 34 of file ldconfig.h.

#define FLAG_REQUIRED_MASK   0xff00

Definition at line 29 of file ldconfig.h.

#define FLAG_S390_LIB64   0x0400

Definition at line 33 of file ldconfig.h.

#define FLAG_SPARC_LIB64   0x0100

Definition at line 30 of file ldconfig.h.

#define FLAG_TYPE_MASK   0x00ff

Definition at line 24 of file ldconfig.h.

#define FLAG_X8664_LIB64   0x0300

Definition at line 32 of file ldconfig.h.


Function Documentation

void add_to_aux_cache ( struct stat64 stat_buf,
int  flags,
unsigned int  osversion,
const char *  soname 
)

Definition at line 642 of file cache.c.

{
  struct aux_cache_entry_id id;
  id.ino = (uint64_t) stat_buf->st_ino;
  id.ctime = (uint64_t) stat_buf->st_ctime;
  id.size = (uint64_t) stat_buf->st_size;
  id.dev = (uint64_t) stat_buf->st_dev;
  insert_to_aux_cache (&id, flags, osversion, soname, 1);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void add_to_cache ( const char *  path,
const char *  lib,
int  flags,
unsigned int  osversion,
uint64_t  hwcap 
)

Definition at line 459 of file cache.c.

{
  size_t liblen = strlen (lib) + 1;
  size_t len = liblen + strlen (path) + 1;
  struct cache_entry *new_entry
    = xmalloc (sizeof (struct cache_entry) + liblen + len);

  new_entry->lib = memcpy ((char *) (new_entry + 1), lib, liblen);
  new_entry->path = new_entry->lib + liblen;
  snprintf (new_entry->path, len, "%s/%s", path, lib);
  new_entry->flags = flags;
  new_entry->osversion = osversion;
  new_entry->hwcap = hwcap;
  new_entry->bits_hwcap = 0;

  /* Count the number of bits set in the masked value.  */
  for (size_t i = 0;
       (~((1ULL << i) - 1) & hwcap) != 0 && i < 8 * sizeof (hwcap); ++i)
    if ((hwcap & (1ULL << i)) != 0)
      ++new_entry->bits_hwcap;


  /* Keep the list sorted - search for right place to insert.  */
  struct cache_entry *ptr = entries;
  struct cache_entry *prev = entries;
  while (ptr != NULL)
    {
      if (compare (ptr, new_entry) > 0)
       break;
      prev = ptr;
      ptr = ptr->next;
    }
  /* Is this the first entry?  */
  if (ptr == entries)
    {
      new_entry->next = entries;
      entries = new_entry;
    }
  else
    {
      new_entry->next = prev->next;
      prev->next = new_entry;
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

char* chroot_canon ( const char *  chroot,
const char *  name 
)

Definition at line 43 of file chroot_canon.c.

{
  char *rpath;
  char *dest;
  char *extra_buf = NULL;
  char *rpath_root;
  const char *start;
  const char *end;
  const char *rpath_limit;
  int num_links = 0;
  size_t chroot_len = strlen (chroot);

  if (chroot_len < 1)
    {
      __set_errno (EINVAL);
      return NULL;
    }

  rpath = malloc (chroot_len + PATH_MAX);
  if (rpath == NULL)
    return NULL;

  rpath_limit = rpath + chroot_len + PATH_MAX;

  rpath_root = (char *) mempcpy (rpath, chroot, chroot_len) - 1;
  if (*rpath_root != '/')
    *++rpath_root = '/';
  dest = rpath_root + 1;

  for (start = end = name; *start; start = end)
    {
      struct stat64 st;
      int n;

      /* Skip sequence of multiple path-separators.  */
      while (*start == '/')
       ++start;

      /* Find end of path component.  */
      for (end = start; *end && *end != '/'; ++end)
       /* Nothing.  */;

      if (end - start == 0)
       break;
      else if (end - start == 1 && start[0] == '.')
       /* nothing */;
      else if (end - start == 2 && start[0] == '.' && start[1] == '.')
       {
         /* Back up to previous component, ignore if at root already.  */
         if (dest > rpath_root + 1)
           while ((--dest)[-1] != '/');
       }
      else
       {
         size_t new_size;

         if (dest[-1] != '/')
           *dest++ = '/';

         if (dest + (end - start) >= rpath_limit)
           {
             ptrdiff_t dest_offset = dest - rpath;
             char *new_rpath;

             new_size = rpath_limit - rpath;
             if (end - start + 1 > PATH_MAX)
              new_size += end - start + 1;
             else
              new_size += PATH_MAX;
             new_rpath = (char *) realloc (rpath, new_size);
             if (new_rpath == NULL)
              goto error;
             rpath = new_rpath;
             rpath_limit = rpath + new_size;

             dest = rpath + dest_offset;
           }

         dest = mempcpy (dest, start, end - start);
         *dest = '\0';

         if (lstat64 (rpath, &st) < 0)
           {
             if (*end == '\0')
              goto done;
             goto error;
           }

         if (S_ISLNK (st.st_mode))
           {
             char *buf = alloca (PATH_MAX);
             size_t len;

             if (++num_links > MAXSYMLINKS)
              {
                __set_errno (ELOOP);
                goto error;
              }

             n = readlink (rpath, buf, PATH_MAX);
             if (n < 0)
              {
                if (*end == '\0')
                  goto done;
                goto error;
              }
             buf[n] = '\0';

             if (!extra_buf)
              extra_buf = alloca (PATH_MAX);

             len = strlen (end);
             if ((long int) (n + len) >= PATH_MAX)
              {
                __set_errno (ENAMETOOLONG);
                goto error;
              }

             /* Careful here, end may be a pointer into extra_buf... */
             memmove (&extra_buf[n], end, len + 1);
             name = end = memcpy (extra_buf, buf, n);

             if (buf[0] == '/')
              dest = rpath_root + 1;      /* It's an absolute symlink */
             else
              /* Back up to previous component, ignore if at root already: */
              if (dest > rpath_root + 1)
                while ((--dest)[-1] != '/');
           }
       }
    }
 done:
  if (dest > rpath_root + 1 && dest[-1] == '/')
    --dest;
  *dest = '\0';

  return rpath;

 error:
  free (rpath);
  return NULL;
}

Here is the call graph for this function:

Here is the caller graph for this function:

char* implicit_soname ( const char *  lib,
int  flag 
)

Definition at line 185 of file readlib.c.

{
  char *soname = xstrdup (lib);

  if ((flag & FLAG_TYPE_MASK) != FLAG_LIBC4)
    return soname;

  /* Aout files don't have a soname, just return the name
     including the major number.  */
  char *major = strstr (soname, ".so.");
  if (major)
    {
      char *dot = strstr (major + 4, ".");
      if (dot)
       *dot = '\0';
    }
  return soname;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void init_aux_cache ( void  )

Definition at line 577 of file cache.c.

Here is the call graph for this function:

Here is the caller graph for this function:

void init_cache ( void  )

Definition at line 227 of file cache.c.

{
  entries = NULL;
}

Here is the caller graph for this function:

void load_aux_cache ( const char *  aux_cache_name)

Definition at line 655 of file cache.c.

{
  int fd = open (aux_cache_name, O_RDONLY);
  if (fd < 0)
    {
      init_aux_cache ();
      return;
    }

  struct stat64 st;
  if (fstat64 (fd, &st) < 0 || st.st_size < sizeof (struct aux_cache_file))
    {
      close (fd);
      init_aux_cache ();
      return;
    }

  size_t aux_cache_size = st.st_size;
  struct aux_cache_file *aux_cache
    = mmap (NULL, aux_cache_size, PROT_READ, MAP_PRIVATE, fd, 0);
  if (aux_cache == MAP_FAILED
      || aux_cache_size < sizeof (struct aux_cache_file)
      || memcmp (aux_cache->magic, AUX_CACHEMAGIC, sizeof AUX_CACHEMAGIC - 1)
      || aux_cache->nlibs < 0
      || aux_cache->nlibs >= aux_cache_size)
    {
      close (fd);
      init_aux_cache ();
      return;
    }

  aux_hash_size = nextprime (aux_cache->nlibs);
  aux_hash = xcalloc (aux_hash_size, sizeof (struct aux_cache_entry *));

  const char *aux_cache_data
    = (const char *) &aux_cache->libs[aux_cache->nlibs];
  for (unsigned int i = 0; i < aux_cache->nlibs; ++i)
    insert_to_aux_cache (&aux_cache->libs[i].id,
                      aux_cache->libs[i].flags,
                      aux_cache->libs[i].osversion,
                      aux_cache->libs[i].soname == 0
                      ? NULL : aux_cache_data + aux_cache->libs[i].soname,
                      0);

  munmap (aux_cache, aux_cache_size);
  close (fd);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void print_cache ( const char *  cache_name)

Definition at line 130 of file cache.c.

{
  int fd = open (cache_name, O_RDONLY);
  if (fd < 0)
    error (EXIT_FAILURE, errno, _("Can't open cache file %s\n"), cache_name);

  struct stat64 st;
  if (fstat64 (fd, &st) < 0
      /* No need to map the file if it is empty.  */
      || st.st_size == 0)
    {
      close (fd);
      return;
    }

  struct cache_file *cache
    = mmap (NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
  if (cache == MAP_FAILED)
    error (EXIT_FAILURE, errno, _("mmap of cache file failed.\n"));

  size_t cache_size = st.st_size;
  if (cache_size < sizeof (struct cache_file))
    error (EXIT_FAILURE, 0, _("File is not a cache file.\n"));

  struct cache_file_new *cache_new = NULL;
  const char *cache_data;
  int format = 0;

  if (memcmp (cache->magic, CACHEMAGIC, sizeof CACHEMAGIC - 1))
    {
      /* This can only be the new format without the old one.  */
      cache_new = (struct cache_file_new *) cache;

      if (memcmp (cache_new->magic, CACHEMAGIC_NEW, sizeof CACHEMAGIC_NEW - 1)
         || memcmp (cache_new->version, CACHE_VERSION,
                    sizeof CACHE_VERSION - 1))
       error (EXIT_FAILURE, 0, _("File is not a cache file.\n"));
      format = 1;
      /* This is where the strings start.  */
      cache_data = (const char *) cache_new;
    }
  else
    {
      size_t offset = ALIGN_CACHE (sizeof (struct cache_file)
                               + (cache->nlibs
                                  * sizeof (struct file_entry)));
      /* This is where the strings start.  */
      cache_data = (const char *) &cache->libs[cache->nlibs];

      /* Check for a new cache embedded in the old format.  */
      if (cache_size >
         (offset + sizeof (struct cache_file_new)))
       {

         cache_new = (struct cache_file_new *) ((void *)cache + offset);

         if (memcmp (cache_new->magic, CACHEMAGIC_NEW,
                    sizeof CACHEMAGIC_NEW - 1) == 0
             && memcmp (cache_new->version, CACHE_VERSION,
                      sizeof CACHE_VERSION - 1) == 0)
           {
             cache_data = (const char *) cache_new;
             format = 1;
           }
       }
    }

  if (format == 0)
    {
      printf (_("%d libs found in cache `%s'\n"), cache->nlibs, cache_name);

      /* Print everything.  */
      for (unsigned int i = 0; i < cache->nlibs; i++)
       print_entry (cache_data + cache->libs[i].key,
                   cache->libs[i].flags, 0, 0,
                   cache_data + cache->libs[i].value);
    }
  else if (format == 1)
    {
      printf (_("%d libs found in cache `%s'\n"),
             cache_new->nlibs, cache_name);

      /* Print everything.  */
      for (unsigned int i = 0; i < cache_new->nlibs; i++)
       print_entry (cache_data + cache_new->libs[i].key,
                   cache_new->libs[i].flags,
                   cache_new->libs[i].osversion,
                   cache_new->libs[i].hwcap,
                   cache_data + cache_new->libs[i].value);
    }
  /* Cleanup.  */
  munmap (cache, cache_size);
  close (fd);
}

Here is the call graph for this function:

Here is the caller graph for this function:

int process_elf_file ( const char *  file_name,
const char *  lib,
int flag,
unsigned int osversion,
char **  soname,
void *  file_contents,
size_t  file_length 
)

Definition at line 43 of file readelflib.c.

{
  int i;
  unsigned int j;
  ElfW(Addr) loadaddr;
  unsigned int dynamic_addr;
  size_t dynamic_size;
  char *program_interpreter;

  ElfW(Ehdr) *elf_header;
  ElfW(Phdr) *elf_pheader, *segment;
  ElfW(Dyn) *dynamic_segment, *dyn_entry;
  char *dynamic_strings;

  elf_header = (ElfW(Ehdr) *) file_contents;
  *osversion = 0;

  if (elf_header->e_ident [EI_CLASS] != ElfW (CLASS))
    {
      if (opt_verbose)
       {
         if (elf_header->e_ident [EI_CLASS] == ELFCLASS32)
           error (0, 0, _("%s is a 32 bit ELF file.\n"), file_name);
         else if (elf_header->e_ident [EI_CLASS] == ELFCLASS64)
           error (0, 0, _("%s is a 64 bit ELF file.\n"), file_name);
         else
           error (0, 0, _("Unknown ELFCLASS in file %s.\n"), file_name);
       }
      return 1;
    }

  if (elf_header->e_type != ET_DYN)
    {
      error (0, 0, _("%s is not a shared object file (Type: %d).\n"), file_name,
            elf_header->e_type);
      return 1;
    }

  /* Get information from elf program header.  */
  elf_pheader = (ElfW(Phdr) *) (elf_header->e_phoff + file_contents);
  check_ptr (elf_pheader);

  /* The library is an elf library, now search for soname and
     libc5/libc6.  */
  *flag = FLAG_ELF;

  loadaddr = -1;
  dynamic_addr = 0;
  dynamic_size = 0;
  program_interpreter = NULL;
  for (i = 0, segment = elf_pheader;
       i < elf_header->e_phnum; i++, segment++)
    {
      check_ptr (segment);

      switch (segment->p_type)
       {
       case PT_LOAD:
         if (loadaddr == (ElfW(Addr)) -1)
           loadaddr = segment->p_vaddr - segment->p_offset;
         break;

       case PT_DYNAMIC:
         if (dynamic_addr)
           error (0, 0, _("more than one dynamic segment\n"));

         dynamic_addr = segment->p_offset;
         dynamic_size = segment->p_filesz;
         break;

       case PT_INTERP:
         program_interpreter = (char *) (file_contents + segment->p_offset);
         check_ptr (program_interpreter);

         /* Check if this is enough to classify the binary.  */
         for (j = 0; j < sizeof (interpreters) / sizeof (interpreters [0]);
              ++j)
           if (strcmp (program_interpreter, interpreters[j].soname) == 0)
             {
              *flag = interpreters[j].flag;
              break;
             }
         break;

       case PT_NOTE:
         if (!*osversion && segment->p_filesz >= 32 && segment->p_align >= 4)
           {
             ElfW(Word) *abi_note = (ElfW(Word) *) (file_contents
                                               + segment->p_offset);
             ElfW(Addr) size = segment->p_filesz;

             while (abi_note [0] != 4 || abi_note [1] != 16
                   || abi_note [2] != 1
                   || memcmp (abi_note + 3, "GNU", 4) != 0)
              {
#define ROUND(len) (((len) + sizeof (ElfW(Word)) - 1) & -sizeof (ElfW(Word)))
                ElfW(Addr) note_size = 3 * sizeof (ElfW(Word))
                                    + ROUND (abi_note[0])
                                    + ROUND (abi_note[1]);

                if (size - 32 < note_size || note_size == 0)
                  {
                    size = 0;
                    break;
                  }
                size -= note_size;
                abi_note = (void *) abi_note + note_size;
              }

             if (size == 0)
              break;

             *osversion = (abi_note [4] << 24) |
                        ((abi_note [5] & 0xff) << 16) |
                        ((abi_note [6] & 0xff) << 8) |
                        (abi_note [7] & 0xff);
           }
         break;

       default:
         break;
       }

    }
  if (loadaddr == (ElfW(Addr)) -1)
    {
      /* Very strange. */
      loadaddr = 0;
    }

  /* Now we can read the dynamic sections.  */
  if (dynamic_size == 0)
    return 1;

  dynamic_segment = (ElfW(Dyn) *) (file_contents + dynamic_addr);
  check_ptr (dynamic_segment);

  /* Find the string table.  */
  dynamic_strings = NULL;
  for (dyn_entry = dynamic_segment; dyn_entry->d_tag != DT_NULL;
       ++dyn_entry)
    {
      check_ptr (dyn_entry);
      if (dyn_entry->d_tag == DT_STRTAB)
       {
         dynamic_strings = (char *) (file_contents + dyn_entry->d_un.d_val - loadaddr);
         check_ptr (dynamic_strings);
         break;
       }
    }

  if (dynamic_strings == NULL)
    return 1;

  /* Now read the DT_NEEDED and DT_SONAME entries.  */
  for (dyn_entry = dynamic_segment; dyn_entry->d_tag != DT_NULL;
       ++dyn_entry)
    {
      if (dyn_entry->d_tag == DT_NEEDED || dyn_entry->d_tag == DT_SONAME)
       {
         char *name = dynamic_strings + dyn_entry->d_un.d_val;
         check_ptr (name);

         if (dyn_entry->d_tag == DT_NEEDED)
           {

             if (*flag == FLAG_ELF)
              {
                /* Check if this is enough to classify the binary.  */
                for (j = 0;
                     j < sizeof (known_libs) / sizeof (known_libs [0]);
                     ++j)
                  if (strcmp (name, known_libs [j].soname) == 0)
                    {
                     *flag = known_libs [j].flag;
                     break;
                    }
              }
           }

         else if (dyn_entry->d_tag == DT_SONAME)
           *soname = xstrdup (name);

         /* Do we have everything we need?  */
         if (*soname && *flag != FLAG_ELF)
           return 0;
       }
    }

  return 0;
}

Here is the call graph for this function:

int process_file ( const char *  real_file_name,
const char *  file_name,
const char *  lib,
int flag,
unsigned int osversion,
char **  soname,
int  is_link,
struct stat64 stat_buf 
)

Definition at line 70 of file readlib.c.

{
  FILE *file;
  struct stat64 statbuf;
  void *file_contents;
  int ret;
  ElfW(Ehdr) *elf_header;
  struct exec *aout_header;

  ret = 0;
  *flag = FLAG_ANY;
  *soname = NULL;

  file = fopen (real_file_name, "rb");
  if (file == NULL)
    {
      /* No error for stale symlink.  */
      if (is_link && strstr (file_name, ".so") != NULL)
       return 1;
      error (0, 0, _("Input file %s not found.\n"), file_name);
      return 1;
    }

  if (fstat64 (fileno (file), &statbuf) < 0)
    {
      error (0, 0, _("Cannot fstat file %s.\n"), file_name);
      fclose (file);
      return 1;
    }

  /* Check that the file is large enough so that we can access the
     information.  We're only checking the size of the headers here.  */
  if ((size_t) statbuf.st_size < sizeof (struct exec)
      || (size_t) statbuf.st_size < sizeof (ElfW(Ehdr)))
    {
      if (statbuf.st_size == 0)
       error (0, 0, _("File %s is empty, not checked."), file_name);
      else
       {
         char buf[SELFMAG];
         size_t n = MIN (statbuf.st_size, SELFMAG);
         if (fread (buf, n, 1, file) == 1 && memcmp (buf, ELFMAG, n) == 0)
           error (0, 0, _("File %s is too small, not checked."), file_name);
       }
      fclose (file);
      return 1;
    }

  file_contents = mmap (0, statbuf.st_size, PROT_READ, MAP_SHARED,
                     fileno (file), 0);
  if (file_contents == MAP_FAILED)
    {
      error (0, 0, _("Cannot mmap file %s.\n"), file_name);
      fclose (file);
      return 1;
    }

  /* First check if this is an aout file.  */
  aout_header = (struct exec *) file_contents;
  if (N_MAGIC (*aout_header) == ZMAGIC
#ifdef QMAGIC               /* Linuxism.  */
      || N_MAGIC (*aout_header) == QMAGIC
#endif
      )
    {
      /* Aout files don't have a soname, just return the name
        including the major number.  */
      char *copy, *major, *dot;
      copy = xstrdup (lib);
      major = strstr (copy, ".so.");
      if (major)
       {
         dot = strstr (major + 4, ".");
         if (dot)
           *dot = '\0';
       }
      *soname = copy;
      *flag = FLAG_LIBC4;
      goto done;
    }

  elf_header = (ElfW(Ehdr) *) file_contents;
  if (memcmp (elf_header->e_ident, ELFMAG, SELFMAG) != 0)
    {
      /* The file is neither ELF nor aout.  Check if it's a linker
        script, like libc.so - otherwise complain.  Only search the
        beginning of the file.  */
      size_t len = MIN (statbuf.st_size, 512);
      if (memmem (file_contents, len, "GROUP", 5) == NULL
         && memmem (file_contents, len, "GNU ld script", 13) == NULL)
       error (0, 0, _("%s is not an ELF file - it has the wrong magic bytes at the start.\n"),
              file_name);
      ret = 1;
    }
  /* Libraries have to be shared object files.  */
  else if (elf_header->e_type != ET_DYN)
    ret = 1;
  else if (process_elf_file (file_name, lib, flag, osversion, soname,
                          file_contents, statbuf.st_size))
    ret = 1;

 done:
  /* Clean up allocated memory and resources.  */
  munmap (file_contents, statbuf.st_size);
  fclose (file);

  *stat_buf = statbuf;
  return ret;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void save_aux_cache ( const char *  aux_cache_name)

Definition at line 705 of file cache.c.

{
  /* Count the length of all sonames.  We start with empty string.  */
  size_t total_strlen = 1;
  /* Number of cache entries.  */
  int cache_entry_count = 0;

  for (size_t i = 0; i < aux_hash_size; ++i)
    for (struct aux_cache_entry *entry = aux_hash[i];
        entry != NULL; entry = entry->next)
      if (entry->used)
       {
         ++cache_entry_count;
         if (entry->soname != NULL)
           total_strlen += strlen (entry->soname) + 1;
       }

  /* Auxiliary cache.  */
  size_t file_entries_size
    = sizeof (struct aux_cache_file)
      + cache_entry_count * sizeof (struct aux_cache_file_entry);
  struct aux_cache_file *file_entries
    = xmalloc (file_entries_size + total_strlen);

  /* Fill in the header of the auxiliary cache.  */
  memset (file_entries, '\0', sizeof (struct aux_cache_file));
  memcpy (file_entries->magic, AUX_CACHEMAGIC, sizeof AUX_CACHEMAGIC - 1);

  file_entries->nlibs = cache_entry_count;
  file_entries->len_strings = total_strlen;

  /* Initial String offset for auxiliary cache is always after the
     special empty string.  */
  unsigned int str_offset = 1;

  /* An array for all strings.  */
  char *str = (char *) file_entries + file_entries_size;
  *str++ = '\0';

  size_t idx = 0;
  for (size_t i = 0; i < aux_hash_size; ++i)
    for (struct aux_cache_entry *entry = aux_hash[i];
        entry != NULL; entry = entry->next)
      if (entry->used)
       {
         file_entries->libs[idx].id = entry->id;
         file_entries->libs[idx].flags = entry->flags;
         if (entry->soname == NULL)
           file_entries->libs[idx].soname = 0;
         else
           {
             file_entries->libs[idx].soname = str_offset;

             size_t len = strlen (entry->soname) + 1;
             str = mempcpy (str, entry->soname, len);
             str_offset += len;
           }
         file_entries->libs[idx].osversion = entry->osversion;
         file_entries->libs[idx++].pad = 0;
       }

  /* Write out auxiliary cache file.  */
  /* Write auxiliary cache first to a temporary file and rename it later.  */

  char *temp_name = xmalloc (strlen (aux_cache_name) + 2);
  sprintf (temp_name, "%s~", aux_cache_name);

  /* Check that directory exists and create if needed.  */
  char *dir = strdupa (aux_cache_name);
  dir = dirname (dir);

  struct stat64 st;
  if (stat64 (dir, &st) < 0)
    {
      if (mkdir (dir, 0700) < 0)
       goto out_fail;
    }

  /* Create file.  */
  int fd = open (temp_name, O_CREAT|O_WRONLY|O_TRUNC|O_NOFOLLOW,
               S_IRUSR|S_IWUSR);
  if (fd < 0)
    goto out_fail;

  if (write (fd, file_entries, file_entries_size + total_strlen)
      != (ssize_t) (file_entries_size + total_strlen)
      || close (fd))
    {
      unlink (temp_name);
      goto out_fail;
    }

  /* Move temporary to its final location.  */
  if (rename (temp_name, aux_cache_name))
    unlink (temp_name);

out_fail:
  /* Free allocated memory.  */
  free (temp_name);
  free (file_entries);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void save_cache ( const char *  cache_name)

Definition at line 262 of file cache.c.

{
  /* The cache entries are sorted already, save them in this order. */

  /* Count the length of all strings.  */
  /* The old format doesn't contain hwcap entries and doesn't contain
     libraries in subdirectories with hwcaps entries.  Count therefore
     also all entries with hwcap == 0.  */
  size_t total_strlen = 0;
  struct cache_entry *entry;
  /* Number of cache entries.  */
  int cache_entry_count = 0;
  /* Number of normal cache entries.  */
  int cache_entry_old_count = 0;

  for (entry = entries; entry != NULL; entry = entry->next)
    {
      /* Account the final NULs.  */
      total_strlen += strlen (entry->lib) + strlen (entry->path) + 2;
      ++cache_entry_count;
      if (entry->hwcap == 0)
       ++cache_entry_old_count;
    }

  /* Create the on disk cache structure.  */
  struct cache_file *file_entries = NULL;
  size_t file_entries_size = 0;

  if (opt_format != 2)
    {
      /* struct cache_file_new is 64-bit aligned on some arches while
        only 32-bit aligned on other arches.  Duplicate last old
        cache entry so that new cache in ld.so.cache can be used by
        both.  */
      if (opt_format != 0)
       cache_entry_old_count = (cache_entry_old_count + 1) & ~1;

      /* And the list of all entries in the old format.  */
      file_entries_size = sizeof (struct cache_file)
       + cache_entry_old_count * sizeof (struct file_entry);
      file_entries = xmalloc (file_entries_size);

      /* Fill in the header.  */
      memset (file_entries, '\0', sizeof (struct cache_file));
      memcpy (file_entries->magic, CACHEMAGIC, sizeof CACHEMAGIC - 1);

      file_entries->nlibs = cache_entry_old_count;
    }

  struct cache_file_new *file_entries_new = NULL;
  size_t file_entries_new_size = 0;

  if (opt_format != 0)
    {
      /* And the list of all entries in the new format.  */
      file_entries_new_size = sizeof (struct cache_file_new)
       + cache_entry_count * sizeof (struct file_entry_new);
      file_entries_new = xmalloc (file_entries_new_size);

      /* Fill in the header.  */
      memset (file_entries_new, '\0', sizeof (struct cache_file_new));
      memcpy (file_entries_new->magic, CACHEMAGIC_NEW,
             sizeof CACHEMAGIC_NEW - 1);
      memcpy (file_entries_new->version, CACHE_VERSION,
             sizeof CACHE_VERSION - 1);

      file_entries_new->nlibs = cache_entry_count;
      file_entries_new->len_strings = total_strlen;
    }

  /* Pad for alignment of cache_file_new.  */
  size_t pad = ALIGN_CACHE (file_entries_size) - file_entries_size;

  /* If we have both formats, we hide the new format in the strings
     table, we have to adjust all string indices for this so that
     old libc5/glibc 2 dynamic linkers just ignore them.  */
  unsigned int str_offset;
  if (opt_format != 0)
    str_offset = file_entries_new_size;
  else
    str_offset = 0;

  /* An array for all strings.  */
  char *strings = xmalloc (total_strlen);
  char *str = strings;
  int idx_old;
  int idx_new;

  for (idx_old = 0, idx_new = 0, entry = entries; entry != NULL;
       entry = entry->next, ++idx_new)
    {
      /* First the library.  */
      if (opt_format != 2 && entry->hwcap == 0)
       {
         file_entries->libs[idx_old].flags = entry->flags;
         /* XXX: Actually we can optimize here and remove duplicates.  */
         file_entries->libs[idx_old].key = str_offset + pad;
       }
      if (opt_format != 0)
       {
         /* We could subtract file_entries_new_size from str_offset -
            not doing so makes the code easier, the string table
            always begins at the beginning of the the new cache
            struct.  */
         file_entries_new->libs[idx_new].flags = entry->flags;
         file_entries_new->libs[idx_new].osversion = entry->osversion;
         file_entries_new->libs[idx_new].hwcap = entry->hwcap;
         file_entries_new->libs[idx_new].key = str_offset;
       }

      size_t len = strlen (entry->lib) + 1;
      str = mempcpy (str, entry->lib, len);
      str_offset += len;
      /* Then the path.  */
      if (opt_format != 2 && entry->hwcap == 0)
       file_entries->libs[idx_old].value = str_offset + pad;
      if (opt_format != 0)
       file_entries_new->libs[idx_new].value = str_offset;
      len = strlen (entry->path) + 1;
      str = mempcpy (str, entry->path, len);
      str_offset += len;
      /* Ignore entries with hwcap for old format.  */
      if (entry->hwcap == 0)
       ++idx_old;
    }

  /* Duplicate last old cache entry if needed.  */
  if (opt_format != 2
      && idx_old < cache_entry_old_count)
    file_entries->libs[idx_old] = file_entries->libs[idx_old - 1];

  /* Write out the cache.  */

  /* Write cache first to a temporary file and rename it later.  */
  char *temp_name = xmalloc (strlen (cache_name) + 2);
  sprintf (temp_name, "%s~", cache_name);

  /* Create file.  */
  int fd = open (temp_name, O_CREAT|O_WRONLY|O_TRUNC|O_NOFOLLOW,
               S_IRUSR|S_IWUSR);
  if (fd < 0)
    error (EXIT_FAILURE, errno, _("Can't create temporary cache file %s"),
          temp_name);

  /* Write contents.  */
  if (opt_format != 2)
    {
      if (write (fd, file_entries, file_entries_size)
         != (ssize_t) file_entries_size)
       error (EXIT_FAILURE, errno, _("Writing of cache data failed"));
    }
  if (opt_format != 0)
    {
      /* Align cache.  */
      if (opt_format != 2)
       {
         char zero[pad];
         memset (zero, '\0', pad);
         if (write (fd, zero, pad) != (ssize_t) pad)
           error (EXIT_FAILURE, errno, _("Writing of cache data failed"));
       }
      if (write (fd, file_entries_new, file_entries_new_size)
         != (ssize_t) file_entries_new_size)
       error (EXIT_FAILURE, errno, _("Writing of cache data failed"));
    }

  if (write (fd, strings, total_strlen) != (ssize_t) total_strlen
      || close (fd))
    error (EXIT_FAILURE, errno, _("Writing of cache data failed"));

  /* Make sure user can always read cache file */
  if (chmod (temp_name, S_IROTH|S_IRGRP|S_IRUSR|S_IWUSR))
    error (EXIT_FAILURE, errno,
          _("Changing access rights of %s to %#o failed"), temp_name,
          S_IROTH|S_IRGRP|S_IRUSR|S_IWUSR);

  /* Move temporary to its final location.  */
  if (rename (temp_name, cache_name))
    error (EXIT_FAILURE, errno, _("Renaming of %s to %s failed"), temp_name,
          cache_name);

  /* Free all allocated memory.  */
  free (file_entries_new);
  free (file_entries);
  free (strings);

  while (entries)
    {
      entry = entries;
      entries = entries->next;
      free (entry);
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

int search_aux_cache ( struct stat64 stat_buf,
int flags,
unsigned int osversion,
char **  soname 
)

Definition at line 584 of file cache.c.

{
  struct aux_cache_entry_id id;
  id.ino = (uint64_t) stat_buf->st_ino;
  id.ctime = (uint64_t) stat_buf->st_ctime;
  id.size = (uint64_t) stat_buf->st_size;
  id.dev = (uint64_t) stat_buf->st_dev;

  unsigned int hash = aux_cache_entry_id_hash (&id);
  struct aux_cache_entry *entry;
  for (entry = aux_hash[hash % aux_hash_size]; entry; entry = entry->next)
    if (id.ino == entry->id.ino
       && id.ctime == entry->id.ctime
       && id.size == entry->id.size
       && id.dev == entry->id.dev)
      {
       *flags = entry->flags;
       *osversion = entry->osversion;
       if (entry->soname != NULL)
         *soname = xstrdup (entry->soname);
       else
         *soname = NULL;
       entry->used = 1;
       return 1;
      }

  return 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void* xcalloc ( size_t  __n,
size_t  __size 
)

Definition at line 91 of file xmalloc.c.

{
  VOID *p;

  p = calloc (n, s);
  if (p == 0)
    p = fixup_null_alloc (n);
  return p;
}

Here is the call graph for this function:

void* xmalloc ( size_t  __n)

Definition at line 77 of file xmalloc.c.

{
  VOID *p;

  p = malloc (n);
  if (p == 0)
    p = fixup_null_alloc (n);
  return p;
}

Here is the call graph for this function:

void* xrealloc ( void *  __p,
size_t  __n 
)
char* xstrdup ( const char *  __str)

Variable Documentation

Definition at line 98 of file ldconfig.c.

Definition at line 94 of file ldconfig.c.