[PATCH v2] Break out ldconfig parser

Adhemerval Zanella Netto adhemerval.zanella@linaro.org
Tue Mar 3 14:37:07 GMT 2026



On 26/02/26 23:49, DJ Delorie wrote:
> 
> Florian Weimer <fweimer@redhat.com> writes:
>> I think we should start giving the ldconfig files ldconfig- or similar
>> prefixes, so that things appear a bit less crowded in the elf directory.
> 
> Renamed.
> 
>> Do we need a separate parseconf.h file, or could we stick it into an
>> existing shared header?
> 
> I moved it to ldconfig.h, which for some reason is in sysdeps...
> 
>> And I think the function comment should be a bit more elaborate.
> 
> Documented.  I also cleaned up the API a bit.
> 
>     elf: factor out ld.conf parsing

LGTM, thanks.  The ldconfig_parse_config could be marked as hidden, but
the attribute_hidden expands to nothing for ldconfig build.

Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>

> 
> diff --git a/elf/Makefile b/elf/Makefile
> index 1a0ed49bc3..21ea58b10b 100644
> --- a/elf/Makefile
> +++ b/elf/Makefile
> @@ -220,6 +220,7 @@ install-rootsbin += ldconfig
>  ldconfig-modules := \
>    cache \
>    chroot_canon \
> +  ldconfig-parse \
>    readlib \
>    static-stubs \
>    stringtable \
> diff --git a/elf/ldconfig-parse.c b/elf/ldconfig-parse.c
> new file mode 100644
> index 0000000000..9da5bd96e6
> --- /dev/null
> +++ b/elf/ldconfig-parse.c
> @@ -0,0 +1,204 @@
> +/* Copyright (C) 2026 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   This program is free software; you can redistribute it and/or modify
> +   it under the terms of the GNU General Public License as published
> +   by the Free Software Foundation; version 2 of the License, or
> +   (at your option) any later version.
> +
> +   This program is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +   GNU General Public License for more details.
> +
> +   You should have received a copy of the GNU General Public License
> +   along with this program; if not, see <https://www.gnu.org/licenses/>.  */
> +
> +#include <stdbool.h>
> +#include <glob.h>
> +#include <stdio.h>
> +#include <error.h>
> +#include <errno.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <locale.h>
> +#include <libintl.h>
> +#include <ctype.h>
> +#include <stdio_ext.h>
> +#include <libgen.h>
> +
> +#include <ldconfig.h>
> +
> +static void
> +parse_conf_include (const char *config_file, unsigned int lineno,
> +		    bool do_chroot, const char *pattern,
> +		    char *opt_chroot, ldconfig_parse_config_cb *cb);
> +
> +static void
> +ldconfig_parse_config_1 (const char *filename, bool do_chroot,
> +			 char *opt_chroot,
> +			 ldconfig_parse_config_cb *callback);
> +
> +/* Parse a configuration file.
> +
> +   Parameters:
> +
> +     filename - The name of the file.  It may be a full path or relative.
> +
> +     opt_chroot - If non-NULL, all paths are relative to this.
> +
> +     callback - for each non-blank line in the file, this function is called
> +	with the line and it's location.
> + */
> +
> +void
> +ldconfig_parse_config (const char *filename, char *opt_chroot,
> +		       ldconfig_parse_config_cb *callback)
> +{
> +  ldconfig_parse_config_1 (filename, true, opt_chroot, callback);
> +}
> +
> +static void
> +ldconfig_parse_config_1 (const char *filename, bool do_chroot,
> +			 char *opt_chroot, ldconfig_parse_config_cb *callback)
> +{
> +  FILE *file = NULL;
> +  char *line = NULL;
> +  const char *canon;
> +  size_t len = 0;
> +  unsigned int lineno;
> +
> +  if (do_chroot && opt_chroot)
> +    {
> +      canon = chroot_canon (opt_chroot, filename);
> +      if (canon)
> +	file = fopen (canon, "r");
> +      else
> +	canon = filename;
> +    }
> +  else
> +    {
> +      canon = filename;
> +      file = fopen (filename, "r");
> +    }
> +
> +  if (file == NULL)
> +    {
> +      if (errno != ENOENT)
> +	error (0, errno, _("\
> +Warning: ignoring configuration file that cannot be opened: %s"),
> +	       canon);
> +      if (canon != filename)
> +	free ((char *) canon);
> +      return;
> +    }
> +
> +  /* No threads use this stream.  */
> +  __fsetlocking (file, FSETLOCKING_BYCALLER);
> +
> +  if (canon != filename)
> +    free ((char *) canon);
> +
> +  lineno = 0;
> +  do
> +    {
> +      ssize_t n = getline (&line, &len, file);
> +      if (n < 0)
> +	break;
> +
> +      ++lineno;
> +      if (line[n - 1] == '\n')
> +	line[n - 1] = '\0';
> +
> +      /* Because the file format does not know any form of quoting we
> +	 can search forward for the next '#' character and if found
> +	 make it terminating the line.  */
> +      *strchrnul (line, '#') = '\0';
> +
> +      /* Remove leading whitespace.  NUL is no whitespace character.  */
> +      char *cp = line;
> +      while (isspace (*cp))
> +	++cp;
> +
> +      /* If the line is blank it is ignored.  */
> +      if (cp[0] == '\0')
> +	continue;
> +
> +      if (!strncmp (cp, "include", 7) && isblank (cp[7]))
> +	{
> +	  char *dir;
> +	  cp += 8;
> +	  while ((dir = strsep (&cp, " \t")) != NULL)
> +	    if (dir[0] != '\0')
> +	      parse_conf_include (filename, lineno, do_chroot, dir, opt_chroot, callback);
> +	}
> +      else
> +	(*callback) (cp, filename, lineno);
> +    }
> +  while (!feof_unlocked (file));
> +
> +  /* Free buffer and close file.  */
> +  free (line);
> +  fclose (file);
> +}
> +
> +/* Handle one word in an `include' line, a glob pattern of additional
> +   config files to read.  */
> +void
> +parse_conf_include (const char *config_file, unsigned int lineno,
> +		    bool do_chroot, const char *pattern, char *opt_chroot,
> +		    ldconfig_parse_config_cb *callback)
> +{
> +  if (opt_chroot != NULL && pattern[0] != '/')
> +    error (EXIT_FAILURE, 0,
> +	   _("need absolute file name for configuration file when using -r"));
> +
> +  char *copy = NULL;
> +  if (pattern[0] != '/' && strchr (config_file, '/') != NULL)
> +    {
> +      if (asprintf (&copy, "%s/%s", dirname (strdupa (config_file)),
> +		    pattern) < 0)
> +	error (EXIT_FAILURE, 0, _("memory exhausted"));
> +      pattern = copy;
> +    }
> +
> +  glob64_t gl;
> +  int result;
> +  if (do_chroot && opt_chroot)
> +    {
> +      char *canon = chroot_canon (opt_chroot, pattern);
> +      if (canon == NULL)
> +	return;
> +      result = glob64 (canon, 0, NULL, &gl);
> +      free (canon);
> +    }
> +  else
> +    result = glob64 (pattern, 0, NULL, &gl);
> +
> +  switch (result)
> +    {
> +    case 0:
> +      for (size_t i = 0; i < gl.gl_pathc; ++i)
> +	ldconfig_parse_config_1 (gl.gl_pathv[i], false, opt_chroot, callback);
> +      globfree64 (&gl);
> +      break;
> +
> +    case GLOB_NOMATCH:
> +      break;
> +
> +    case GLOB_NOSPACE:
> +      errno = ENOMEM;
> +      [[fallthrough]];
> +    case GLOB_ABORTED:
> +      if (opt_verbose)
> +	error (0, errno, _("%s:%u: cannot read directory %s"),
> +	       config_file, lineno, pattern);
> +      break;
> +
> +    default:
> +      abort ();
> +      break;
> +    }
> +
> +  free (copy);
> +}
> diff --git a/elf/ldconfig.c b/elf/ldconfig.c
> index aca967403a..070e933df6 100644
> --- a/elf/ldconfig.c
> +++ b/elf/ldconfig.c
> @@ -420,6 +420,16 @@ add_dir_1 (const char *line, const char *from_file, int from_line)
>      free (path);
>  }
>  
> +static void
> +add_dir_callback (const char *line, const char *from_file, int from_line)
> +{
> +  if (!strncasecmp (line, "hwcap", 5) && isblank (line[5]))
> +    error (0, 0, _("%s:%u: hwcap directive ignored"), from_file, from_line);
> +  else
> +    add_dir_1 (line, from_file, from_line);
> +}
> +
> +
>  static void
>  add_dir (const char *line)
>  {
> @@ -1017,156 +1027,6 @@ search_dirs (void)
>  }
>  
>  
> -static void parse_conf_include (const char *config_file, unsigned int lineno,
> -				bool do_chroot, const char *pattern);
> -
> -/* Parse configuration file.  */
> -static void
> -parse_conf (const char *filename, bool do_chroot)
> -{
> -  FILE *file = NULL;
> -  char *line = NULL;
> -  const char *canon;
> -  size_t len = 0;
> -  unsigned int lineno;
> -
> -  if (do_chroot && opt_chroot)
> -    {
> -      canon = chroot_canon (opt_chroot, filename);
> -      if (canon)
> -	file = fopen (canon, "r");
> -      else
> -	canon = filename;
> -    }
> -  else
> -    {
> -      canon = filename;
> -      file = fopen (filename, "r");
> -    }
> -
> -  if (file == NULL)
> -    {
> -      if (errno != ENOENT)
> -	error (0, errno, _("\
> -Warning: ignoring configuration file that cannot be opened: %s"),
> -	       canon);
> -      if (canon != filename)
> -	free ((char *) canon);
> -      return;
> -    }
> -
> -  /* No threads use this stream.  */
> -  __fsetlocking (file, FSETLOCKING_BYCALLER);
> -
> -  if (canon != filename)
> -    free ((char *) canon);
> -
> -  lineno = 0;
> -  do
> -    {
> -      ssize_t n = getline (&line, &len, file);
> -      if (n < 0)
> -	break;
> -
> -      ++lineno;
> -      if (line[n - 1] == '\n')
> -	line[n - 1] = '\0';
> -
> -      /* Because the file format does not know any form of quoting we
> -	 can search forward for the next '#' character and if found
> -	 make it terminating the line.  */
> -      *strchrnul (line, '#') = '\0';
> -
> -      /* Remove leading whitespace.  NUL is no whitespace character.  */
> -      char *cp = line;
> -      while (isspace (*cp))
> -	++cp;
> -
> -      /* If the line is blank it is ignored.  */
> -      if (cp[0] == '\0')
> -	continue;
> -
> -      if (!strncmp (cp, "include", 7) && isblank (cp[7]))
> -	{
> -	  char *dir;
> -	  cp += 8;
> -	  while ((dir = strsep (&cp, " \t")) != NULL)
> -	    if (dir[0] != '\0')
> -	      parse_conf_include (filename, lineno, do_chroot, dir);
> -	}
> -      else if (!strncasecmp (cp, "hwcap", 5) && isblank (cp[5]))
> -	error (0, 0, _("%s:%u: hwcap directive ignored"), filename, lineno);
> -      else
> -	add_dir_1 (cp, filename, lineno);
> -    }
> -  while (!feof_unlocked (file));
> -
> -  /* Free buffer and close file.  */
> -  free (line);
> -  fclose (file);
> -}
> -
> -/* Handle one word in an `include' line, a glob pattern of additional
> -   config files to read.  */
> -static void
> -parse_conf_include (const char *config_file, unsigned int lineno,
> -		    bool do_chroot, const char *pattern)
> -{
> -  if (opt_chroot != NULL && pattern[0] != '/')
> -    error (EXIT_FAILURE, 0,
> -	   _("need absolute file name for configuration file when using -r"));
> -
> -  char *copy = NULL;
> -  if (pattern[0] != '/' && strchr (config_file, '/') != NULL)
> -    {
> -      if (asprintf (&copy, "%s/%s", dirname (strdupa (config_file)),
> -		    pattern) < 0)
> -	error (EXIT_FAILURE, 0, _("memory exhausted"));
> -      pattern = copy;
> -    }
> -
> -  glob64_t gl;
> -  int result;
> -  if (do_chroot && opt_chroot)
> -    {
> -      char *canon = chroot_canon (opt_chroot, pattern);
> -      if (canon == NULL)
> -	return;
> -      result = glob64 (canon, 0, NULL, &gl);
> -      free (canon);
> -    }
> -  else
> -    result = glob64 (pattern, 0, NULL, &gl);
> -
> -  switch (result)
> -    {
> -    case 0:
> -      for (size_t i = 0; i < gl.gl_pathc; ++i)
> -	parse_conf (gl.gl_pathv[i], false);
> -      globfree64 (&gl);
> -      break;
> -
> -    case GLOB_NOMATCH:
> -      break;
> -
> -    case GLOB_NOSPACE:
> -      errno = ENOMEM;
> -      [[fallthrough]];
> -    case GLOB_ABORTED:
> -      if (opt_verbose)
> -	error (0, errno, _("%s:%u: cannot read directory %s"),
> -	       config_file, lineno, pattern);
> -      break;
> -
> -    default:
> -      abort ();
> -      break;
> -    }
> -
> -  free (copy);
> -}
> -
> -
>  int
>  main (int argc, char **argv)
>  {
> @@ -1285,7 +1145,7 @@ main (int argc, char **argv)
>  
>    if (!opt_only_cline)
>      {
> -      parse_conf (config_file, true);
> +      ldconfig_parse_config (config_file, opt_chroot, add_dir_callback);
>  
>        /* Always add the standard search paths.  */
>        add_system_dir (SLIBDIR);
> diff --git a/sysdeps/generic/ldconfig.h b/sysdeps/generic/ldconfig.h
> index 5913bf40fc..5a2a0f1d8d 100644
> --- a/sysdeps/generic/ldconfig.h
> +++ b/sysdeps/generic/ldconfig.h
> @@ -111,6 +111,13 @@ enum opt_format
>  
>  extern enum opt_format opt_format;
>  
> +/* Declared in ldconfig-parse.c */
> +typedef void (ldconfig_parse_config_cb) (const char *line,
> +					 const char *from_file, int from_line);
> +
> +void ldconfig_parse_config (const char *filename, char *opt_chroot,
> +			    ldconfig_parse_config_cb *cb);
> +
>  /* Prototypes for a few program-wide used functions.  */
>  #include <programs/xmalloc.h>
>  
> 



More information about the Libc-alpha mailing list