@@ -21,6 +21,8 @@ Major new features:
* Static PIE is now supported for arm-*-linux-gnueabi. It requires toolchain
support to correctly set the expected linker options.
+* Pre-built ld.so.cache files can be installed with ldconfig.
+
Deprecated and removed features, and other changes affecting compatibility:
* Although malloc and related functions currently return pointers
@@ -104,6 +104,9 @@ static int opt_manual_link;
/* Should we ignore an old auxiliary cache file? */
static int opt_ignore_aux_cache;
+/* Install a pre-existing cache file instead of generating a new one. */
+static int opt_install;
+
/* Cache file to use. */
static char *cache_file;
@@ -132,6 +135,7 @@ static const struct argp_option options[] =
{ NULL, 'l', NULL, 0, N_("Manually link individual libraries."), 0},
{ "format", 'c', N_("FORMAT"), 0, N_("Format to use: new (default), old, or compat"), 0},
{ "ignore-aux-cache", 'i', NULL, 0, N_("Ignore auxiliary cache file"), 0},
+ { "install", 'I', NULL, 0, N_("install pre-existing cache file"), 0},
{ NULL, 0, NULL, 0, NULL, 0 }
};
@@ -197,6 +201,9 @@ parse_opt (int key, char *arg, struct argp_state *state)
else if (strcmp (arg, "new") == 0)
opt_format = opt_format_new;
break;
+ case 'I':
+ opt_install = 1;
+ break;
default:
return ARGP_ERR_UNKNOWN;
}
@@ -1045,8 +1052,8 @@ main (int argc, char **argv)
argp_parse (&argp, argc, argv, 0, &remaining, NULL);
/* Remaining arguments are additional directories if opt_manual_link
- is not set. */
- if (remaining != argc && !opt_manual_link)
+ and opt_install are not set. */
+ if (remaining != argc && !opt_manual_link && !opt_install)
{
int i;
for (i = remaining; i < argc; ++i)
@@ -1139,6 +1146,135 @@ main (int argc, char **argv)
exit (0);
}
+ if (opt_install)
+ {
+ if (argv[remaining] == NULL)
+ error (EXIT_FAILURE, 0, _("Missing source file name"));
+
+ char *source = (opt_chroot
+ ? chroot_canon (opt_chroot, argv[remaining])
+ : argv[remaining]);
+ if (source == NULL)
+ error (EXIT_FAILURE, errno, _("Can't find %s"), argv[remaining]);
+
+ int src_fd = open (source, O_RDONLY);
+ if (src_fd < 0)
+ error (EXIT_FAILURE, errno, _("Can't open %s"), source);
+
+ char *dest = xmalloc (strlen (cache_file) + 1 + 1);
+
+ /* This matches the temp file created by cache.c, and should be
+ on the same filesystem as the cache file. */
+ sprintf(dest, "%s~", cache_file);
+ int dest_fd;
+
+ struct stat st;
+ if (fstat (src_fd, &st) < 0)
+ error (EXIT_FAILURE, errno, _("Can't stat %s"), source);
+
+ char buf[512];
+ int r, w, sz = 0;
+ char *bp = buf;
+
+ /* Read the first part of the file and verify it looks
+ reasonable. */
+ while (sz < sizeof (buf)
+ && (r = read (src_fd, bp, sizeof (buf) - sz)) > 0)
+ {
+ sz += r;
+ bp += r;
+ }
+ if (r < 0)
+ error (EXIT_FAILURE, errno, _("Error reading file %s"), source);
+
+ if (! ((sz >= sizeof (CACHEMAGIC)
+ && memcmp (buf, CACHEMAGIC,
+ sizeof (CACHEMAGIC) - 1) == 0)
+ || (sz >= sizeof (CACHEMAGIC_NEW)
+ && memcmp (buf, CACHEMAGIC_NEW,
+ sizeof (CACHEMAGIC_NEW) - 1) == 0)))
+ {
+ error (EXIT_FAILURE, 0,
+ _("File %s does not look like an ld.so.cache file"),
+ source);
+ }
+
+ /* If the two files are on the same filesystem, we can just
+ rename it. */
+ if (rename (source, cache_file) == 0)
+ {
+ /* A simple rename was sufficient. */
+ close (src_fd);
+ exit (0);
+ }
+ /* Otherwise, a cross-filesystem copy/rename is needed. */
+
+ /* Now write that first part out. */
+ dest_fd = open (dest, O_WRONLY, 0644);
+ if (dest_fd < 0)
+ error (EXIT_FAILURE, errno, _("Can't create %s"), dest);
+
+ r = sz;
+ bp = buf;
+ while (r > 0 && (w = write (dest_fd, bp, r)) > 0)
+ {
+ r -= w;
+ bp += w;
+ }
+ if (w < 0)
+ {
+ unlink (dest);
+ close (dest_fd);
+ error (EXIT_FAILURE, errno, _("Error writing file %s"), dest);
+ }
+
+ /* At this point, sz contains the number of bytes copied so far.
+ Copy the rest of the file. */
+ while ((r = read (src_fd, buf, sizeof(buf))) > 0)
+ {
+ bp = buf;
+ while (r > 0 && (w = write (dest_fd, bp, r)) > 0)
+ {
+ bp += r;
+ r -= w;
+ sz += w;
+ }
+ if (w <= 0)
+ break;
+ }
+
+ close (src_fd);
+
+ /* Make sure we copied it all. */
+ if (sz < st.st_size)
+ {
+ unlink (dest);
+ close (dest_fd);
+ error (EXIT_FAILURE, errno, _("Unable to copy file %s to %s"),
+ source, dest);
+ }
+
+ /* Make sure user can always read the cache file */
+ if (fchmod (dest_fd, S_IROTH|S_IRGRP|S_IRUSR|S_IWUSR))
+ {
+ unlink (dest);
+ close (dest_fd);
+ error (EXIT_FAILURE, errno,
+ _("Changing access rights of %s to %#o failed"), dest,
+ S_IROTH|S_IRGRP|S_IRUSR|S_IWUSR);
+ }
+
+ fsync (dest_fd);
+ if (rename (dest, cache_file) < 0)
+ {
+ unlink (dest);
+ close (dest_fd);
+ error (EXIT_FAILURE, errno, _("Can't rename %s to %s"), dest, cache_file);
+ }
+
+ close (dest_fd);
+ exit (0);
+ }
if (opt_build_cache)
init_cache ();