[PATCH v1 1/1] ldconfig: add --install option

Adhemerval Zanella Netto adhemerval.zanella@linaro.org
Wed May 27 18:01:19 GMT 2026



On 27/05/26 12:47, DJ Delorie wrote:
> 
> Add --install option, which copies a pre-built ld.so.cache into place,
> honoring the cache and root options and defaults.  This gives the user
> a canonical "correct" way to install a pre-built cache.

I think we should add a NEWS entry for this.

> ---
>  elf/ldconfig.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++--
>  1 file changed, 53 insertions(+), 2 deletions(-)
> 
> diff --git a/elf/ldconfig.c b/elf/ldconfig.c
> index 070e933df6..dcd885449a 100644
> --- a/elf/ldconfig.c
> +++ b/elf/ldconfig.c
> @@ -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,50 @@ main (int argc, char **argv)
>        exit (0);
>      }
>  
> +  if (opt_install)
> +    {

This might copy any arbitrary file into /etc/ld.so.cache, should it first
validate whether the file is really a ld.so cache (CACHEMAGIC / CACHEMAGIC_NEW) ?

> +      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) + 6 + 1);
> +
> +      sprintf(dest, "%sXXXXXX", cache_file);
> +      int dest_fd = mkstemp (dest);
> +      if (dest_fd < 0)
> +	error (EXIT_FAILURE, errno, _("Can't create %s"), dest);

This will leak the temporary file if an error happens. save_cache in 
elf/cache.c:677-736 uses a fixed cache_name~ suffix, so it is implicitly 
overwritten on next run.

Maybe it would be better to consolidate this temporary file creation and 
use only one strategy, with possible adding also an atexit hook to delete
temporary files.

> +
> +      struct stat st;
> +      if (fstat (src_fd, &st) < 0)
> +	error (EXIT_FAILURE, errno, _("Can't stat %s"), source);
> +
> +      if (copy_file_range (src_fd, NULL, dest_fd, NULL, st.st_size, 0)
> +	  < st.st_size)
> +	error (EXIT_FAILURE, errno, _("Can't copy to %s"), dest);

Unfortunately copy_file_range only properly support on Linux, this will always
fail on Hurd which uses the generic io/copy_file_range.c. Also, copy_file_range
has many issues before Linux 5.3 [1] (and gnulib wrapper returns ENOSYS in
this case).

One option would to copy the lib/copy-file.c gnulib module, which handles 
copy_file failures with a fallback read/write.

[1] https://lwn.net/Articles/789527/

> +
> +      /* Make sure user can always read cache file */
> +      if (chmod (dest, S_IROTH|S_IRGRP|S_IRUSR|S_IWUSR))

Maybe use fchmod since it already has a dest_fp opened.

> +	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)
> +	error (EXIT_FAILURE, errno, _("Can't rename %s to %s"), dest, cache_file);
> +
> +      close (src_fd);
> +      close (dest_fd);
> +      exit (0);
> +    }
>  
>    if (opt_build_cache)
>      init_cache ();



More information about the Libc-alpha mailing list