summary refs log tree commit diff
path: root/elf/ldconfig.c
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>2007-08-12 20:09:16 +0000
committerUlrich Drepper <drepper@redhat.com>2007-08-12 20:09:16 +0000
commit27d9ffda17df4d2388687afd12897774fde39bcc (patch)
treee68c74b095d9ae0b5eea23c0b80c54b73b94d3b6 /elf/ldconfig.c
parent8d944b0fc6195a2cd2308287e96a46b21f675015 (diff)
downloadglibc-27d9ffda17df4d2388687afd12897774fde39bcc.tar.gz
glibc-27d9ffda17df4d2388687afd12897774fde39bcc.tar.xz
glibc-27d9ffda17df4d2388687afd12897774fde39bcc.zip
2007-08-01 Andreas Jaeger <aj@suse.de>
	    Jakub Jelinek  <jakub@redhat.com>

	* elf/ldconfig.c (opt_ignore_aux_cache): Add new option.
	(options): Add option.
	(parse_opt): Handle option.
	(manual_link): Adjust process_file caller.  Call implicit_soname.
	(search_dir): Formatting.  Use and populate auxiliary cache.
	(main): Load and save auxiliary cache.
	* elf/readlib.c (process_file): Add stat_buf argument.  Pass struct
	stat64 from fstat64 to caller.
	(implicit_soname): New function.
	* elf/readelflib.c (process_elf_file): If DT_SONAME is not present,
	leave *soname as NULL.
	* elf/cache.c: Include libgen.h.
	(print_entry, print_cache, compare, save_cache, add_to_cache):
	Formatting and cleanups.
	(aux_cache_entry_id, aux_cache_entry, aux_cache_file_entry,
	aux_cache_file): New structures.
	(AUX_CACHEMAGIC): Define.
	(primes): New array.
	(aux_hash_size, aux_hash): New variables.
	(aux_cache_entry_id_hash, nextprime, init_aux_cache,
	search_aux_cache, insert_to_aux_cache, add_to_aux_cache,
	load_aux_cache, save_aux_cache): New functions.
	* sysdeps/generic/ldconfig.h (_PATH_LDCONFIG_AUX_CACHE): Define.
	(init_aux_cache, search_aux_cache, add_to_aux_cache,
	load_aux_cache, save_aux_cache, implicit_soname): New prototypes.
	(process_file): Adjust prototype.
Diffstat (limited to 'elf/ldconfig.c')
-rw-r--r--elf/ldconfig.c148
1 files changed, 95 insertions, 53 deletions
diff --git a/elf/ldconfig.c b/elf/ldconfig.c
index accc9f95d5..31d13c4802 100644
--- a/elf/ldconfig.c
+++ b/elf/ldconfig.c
@@ -112,6 +112,9 @@ static char *opt_chroot;
 /* Manually link given shared libraries.  */
 static int opt_manual_link;
 
+/* Should we ignore an old auxiliary cache file?  */
+static int opt_ignore_aux_cache;
+
 /* Cache file to use.  */
 static char *cache_file;
 
@@ -142,6 +145,7 @@ static const struct argp_option options[] =
   { NULL, 'n', NULL, 0, N_("Only process directories specified on the command line.  Don't build cache."), 0},
   { NULL, 'l', NULL, 0, N_("Manually link individual libraries."), 0},
   { "format", 'c', N_("FORMAT"), 0, N_("Format to use: new, old or compat (default)"), 0},
+  { "ignore-aux-cache", 'i', NULL, 0, N_("Ignore auxiliary cache file"), 0},
   { NULL, 0, NULL, 0, NULL, 0 }
 };
 
@@ -238,10 +242,15 @@ parse_opt (int key, char *arg, struct argp_state *state)
     {
     case 'C':
       cache_file = arg;
+      /* Ignore auxiliary cache since we use non-standard cache.  */
+      opt_ignore_aux_cache = 1;
       break;
     case 'f':
       config_file = arg;
       break;
+    case 'i':
+      opt_ignore_aux_cache = 1;
+      break;
     case 'l':
       opt_manual_link = 1;
       break;
@@ -518,7 +527,7 @@ manual_link (char *library)
   if (libname)
     {
       /* Successfully split names.  Check if path is just "/" to avoid
-         an empty path.  */
+	 an empty path.  */
       if (libname == path)
 	{
 	  libname = library + 1;
@@ -572,14 +581,17 @@ manual_link (char *library)
       free (path);
       return;
     }
+
   if (process_file (real_library, library, libname, &flag, &osversion,
-		    &soname, 0))
+		    &soname, 0, &stat_buf))
     {
       error (0, 0, _("No link created since soname could not be found for %s"),
 	     library);
       free (path);
       return;
     }
+  if (soname == NULL)
+    soname = implicit_soname (libname, flag);
   create_links (real_path, path, libname, soname);
   free (soname);
   free (path);
@@ -625,23 +637,7 @@ struct dlib_entry
 static void
 search_dir (const struct dir_entry *entry)
 {
-  DIR *dir;
-  struct dirent64 *direntry;
-  char *file_name, *dir_name, *real_file_name, *real_name;
-  int file_name_len, real_file_name_len, len;
-  char *soname;
-  struct dlib_entry *dlibs;
-  struct dlib_entry *dlib_ptr;
-  struct stat64 lstat_buf, stat_buf;
-  int is_link, is_dir;
   uint64_t hwcap = path_hwcap (entry->path);
-  unsigned int osversion;
-
-  file_name_len = PATH_MAX;
-  file_name = alloca (file_name_len);
-
-  dlibs = NULL;
-
   if (opt_verbose)
     {
       if (hwcap != 0)
@@ -650,6 +646,11 @@ search_dir (const struct dir_entry *entry)
 	printf ("%s:\n", entry->path);
     }
 
+  char *dir_name;
+  char *real_file_name;
+  size_t real_file_name_len;
+  size_t file_name_len = PATH_MAX;
+  char *file_name = alloca (file_name_len);
   if (opt_chroot)
     {
       dir_name = chroot_canon (opt_chroot, entry->path);
@@ -663,6 +664,7 @@ search_dir (const struct dir_entry *entry)
       real_file_name = file_name;
     }
 
+  DIR *dir;
   if (dir_name == NULL || (dir = opendir (dir_name)) == NULL)
     {
       if (opt_verbose)
@@ -672,6 +674,8 @@ search_dir (const struct dir_entry *entry)
       return;
     }
 
+  struct dirent64 *direntry;
+  struct dlib_entry *dlibs = NULL;
   while ((direntry = readdir64 (dir)) != NULL)
     {
       int flag;
@@ -695,7 +699,8 @@ search_dir (const struct dir_entry *entry)
 #endif
 	      !is_hwcap_platform (direntry->d_name)))
 	continue;
-      len = strlen (direntry->d_name);
+
+      size_t len = strlen (direntry->d_name);
       /* Skip temporary files created by the prelink program.  Files with
 	 names like these are never really DSOs we want to look at.  */
       if (len >= sizeof (".#prelink#") - 1)
@@ -727,7 +732,10 @@ search_dir (const struct dir_entry *entry)
 	    }
 	  sprintf (real_file_name, "%s/%s", dir_name, direntry->d_name);
 	}
+
+      struct stat64 lstat_buf;
 #ifdef _DIRENT_HAVE_D_TYPE
+      /* We optimize and try to do the lstat call only if needed.  */
       if (direntry->d_type != DT_UNKNOWN)
 	lstat_buf.st_mode = DTTOIF (direntry->d_type);
       else
@@ -738,9 +746,11 @@ search_dir (const struct dir_entry *entry)
 	    continue;
 	  }
 
-      is_link = S_ISLNK (lstat_buf.st_mode);
+      struct stat64 stat_buf;
+      int is_dir;
+      int is_link = S_ISLNK (lstat_buf.st_mode);
       if (is_link)
-        {
+	{
 	  /* In case of symlink, we check if the symlink refers to
 	     a directory. */
 	  if (__builtin_expect (stat64 (real_file_name, &stat_buf), 0))
@@ -754,6 +764,12 @@ search_dir (const struct dir_entry *entry)
 	      continue;
 	    }
 	  is_dir = S_ISDIR (stat_buf.st_mode);
+
+	  /* lstat_buf is later stored, update contents.  */
+	  lstat_buf.st_dev = stat_buf.st_dev;
+	  lstat_buf.st_ino = stat_buf.st_ino;
+	  lstat_buf.st_size = stat_buf.st_size;
+	  lstat_buf.st_ctime = stat_buf.st_ctime;
 	}
       else
 	is_dir = S_ISDIR (lstat_buf.st_mode);
@@ -767,36 +783,28 @@ search_dir (const struct dir_entry *entry)
 	  new_entry->path = xstrdup (file_name);
 	  new_entry->flag = entry->flag;
 	  new_entry->next = NULL;
-	  if (is_link)
+#ifdef _DIRENT_HAVE_D_TYPE
+	  /* We have filled in lstat only #ifndef
+	     _DIRENT_HAVE_D_TYPE.  Fill it in if needed.  */
+	  if (!is_link
+	      && direntry->d_type != DT_UNKNOWN
+	      && __builtin_expect (lstat64 (real_file_name, &lstat_buf), 0))
 	    {
-	      new_entry->ino = stat_buf.st_ino;
-	      new_entry->dev = stat_buf.st_dev;
+	      error (0, errno, _("Cannot lstat %s"), file_name);
+	      free (new_entry->path);
+	      free (new_entry);
+	      continue;
 	    }
-	  else
-	    {
-#ifdef _DIRENT_HAVE_D_TYPE
-	      /* We have filled in lstat only #ifndef
-		 _DIRENT_HAVE_D_TYPE.  Fill it in if needed.  */
-	      if (direntry->d_type != DT_UNKNOWN
-		  && __builtin_expect (lstat64 (real_file_name, &lstat_buf),
-				       0))
-		{
-		  error (0, errno, _("Cannot lstat %s"), file_name);
-		  free (new_entry->path);
-		  free (new_entry);
-		  continue;
-		}
 #endif
-
-	      new_entry->ino = lstat_buf.st_ino;
-	      new_entry->dev = lstat_buf.st_dev;
-	    }
+	  new_entry->ino = lstat_buf.st_ino;
+	  new_entry->dev = lstat_buf.st_dev;
 	  add_single_dir (new_entry, 0);
 	  continue;
 	}
       else if (!S_ISREG (lstat_buf.st_mode) && !is_link)
 	continue;
 
+      char *real_name;
       if (opt_chroot && is_link)
 	{
 	  real_name = chroot_canon (opt_chroot, file_name);
@@ -810,14 +818,36 @@ search_dir (const struct dir_entry *entry)
       else
 	real_name = real_file_name;
 
-      if (process_file (real_name, file_name, direntry->d_name, &flag,
-			&osversion, &soname, is_link))
+#ifdef _DIRENT_HAVE_D_TYPE
+      /* Call lstat64 if not done yet.  */
+      if (!is_link
+	  && direntry->d_type != DT_UNKNOWN
+	  && __builtin_expect (lstat64 (real_file_name, &lstat_buf), 0))
 	{
-	  if (real_name != real_file_name)
-	    free (real_name);
+	  error (0, errno, _("Cannot lstat %s"), file_name);
 	  continue;
 	}
+#endif
+
+      /* First search whether the auxiliary cache contains this
+	 library already and it's not changed.  */
+      char *soname;
+      unsigned int osversion;
+      if (!search_aux_cache (&lstat_buf, &flag, &osversion, &soname))
+	{
+	  if (process_file (real_name, file_name, direntry->d_name, &flag,
+			    &osversion, &soname, is_link, &lstat_buf))
+	    {
+	      if (real_name != real_file_name)
+		free (real_name);
+	      continue;
+	    }
+	  else if (opt_build_cache)
+	    add_to_aux_cache (&lstat_buf, flag, osversion, soname);
+	}
 
+      if (soname == NULL)
+	soname = implicit_soname (direntry->d_name, flag);
 
       /* A link may just point to itself.  */
       if (is_link)
@@ -834,7 +864,7 @@ search_dir (const struct dir_entry *entry)
 		  || strncmp (real_base_name, soname, len) != 0)
 		is_link = 0;
 	    }
-        }
+	}
 
       if (real_name != real_file_name)
 	free (real_name);
@@ -849,6 +879,7 @@ search_dir (const struct dir_entry *entry)
 	  && (entry->flag == FLAG_ELF_LIBC5
 	      || entry->flag == FLAG_ELF_LIBC6))
 	flag = entry->flag;
+
       /* Some sanity checks to print warnings.  */
       if (opt_verbose)
 	{
@@ -864,6 +895,7 @@ search_dir (const struct dir_entry *entry)
 	}
 
       /* Add library to list.  */
+      struct dlib_entry *dlib_ptr;
       for (dlib_ptr = dlibs; dlib_ptr != NULL; dlib_ptr = dlib_ptr->next)
 	{
 	  /* Is soname already in list?  */
@@ -888,12 +920,13 @@ search_dir (const struct dir_entry *entry)
 			dlib_ptr->flag = flag;
 		      else
 			error (0, 0, _("libraries %s and %s in directory %s have same soname but different type."),
-			       dlib_ptr->name, direntry->d_name, entry->path);
+			       dlib_ptr->name, direntry->d_name,
+			       entry->path);
 		    }
 		  free (dlib_ptr->name);
-		  dlib_ptr->osversion = osversion;
 		  dlib_ptr->name = xstrdup (direntry->d_name);
 		  dlib_ptr->is_link = is_link;
+		  dlib_ptr->osversion = osversion;
 		}
 	      /* Don't add this library, abort loop.  */
 	      /* Also free soname, since it's dynamically allocated.  */
@@ -906,10 +939,10 @@ search_dir (const struct dir_entry *entry)
 	{
 	  dlib_ptr = (struct dlib_entry *)xmalloc (sizeof (struct dlib_entry));
 	  dlib_ptr->name = xstrdup (direntry->d_name);
-	  dlib_ptr->flag = flag;
-	  dlib_ptr->osversion = osversion;
 	  dlib_ptr->soname = soname;
+	  dlib_ptr->flag = flag;
 	  dlib_ptr->is_link = is_link;
+	  dlib_ptr->osversion = osversion;
 	  /* Add at head of list.  */
 	  dlib_ptr->next = dlibs;
 	  dlibs = dlib_ptr;
@@ -920,6 +953,7 @@ search_dir (const struct dir_entry *entry)
 
   /* Now dlibs contains a list of all libs - add those to the cache
      and created all symbolic links.  */
+  struct dlib_entry *dlib_ptr;
   for (dlib_ptr = dlibs; dlib_ptr != NULL; dlib_ptr = dlib_ptr->next)
     {
       /* Don't create links to links.  */
@@ -1246,7 +1280,7 @@ main (int argc, char **argv)
   if (opt_chroot)
     {
       /* Canonicalize the directory name of cache_file, not cache_file,
-         because we'll rename a temporary cache file to it.  */
+	 because we'll rename a temporary cache file to it.  */
       char *p = strrchr (cache_file, '/');
       char *canon = chroot_canon (opt_chroot,
 				  p ? (*p = '\0', cache_file) : "/");
@@ -1293,10 +1327,18 @@ main (int argc, char **argv)
 	add_system_dir (LIBDIR);
     }
 
+  if (! opt_ignore_aux_cache)
+    load_aux_cache (_PATH_LDCONFIG_AUX_CACHE);
+  else
+    init_aux_cache ();
+
   search_dirs ();
 
   if (opt_build_cache)
-    save_cache (cache_file);
+    {
+      save_cache (cache_file);
+      save_aux_cache (_PATH_LDCONFIG_AUX_CACHE);
+    }
 
   return 0;
 }