[PATCH v5 1/4] Add system-wide tunables: ldconfig part

DJ Delorie dj@redhat.com
Tue Feb 17 23:02:37 GMT 2026


Yury Khrustalev <yury.khrustalev@arm.com> writes:
> Overall I think this commit should be preceded with a refactoring of
> reading ld config files to allow for also reading other types of
> configs. The size of duplicated code is huge, IMO.

This is a quicky... I didn't try using this with the tunables patch,
but... something like this?

    elf: factor out ld.conf parsing

diff --git a/elf/Makefile b/elf/Makefile
index 396e97b5e7..c422011d5f 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -226,6 +226,7 @@ install-rootsbin += ldconfig
 ldconfig-modules := \
   cache \
   chroot_canon \
+  parseconf \
   readlib \
   static-stubs \
   stringtable \
diff --git a/elf/ldconfig.c b/elf/ldconfig.c
index aca967403a..c071c4dc00 100644
--- a/elf/ldconfig.c
+++ b/elf/ldconfig.c
@@ -44,6 +44,7 @@
 #include <dl-cache.h>
 #include <dl-hwcaps.h>
 #include <dl-is_dso.h>
+#include "parseconf.h"
 
 
 #ifndef LD_SO_CONF
@@ -1017,156 +1018,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 +1136,7 @@ main (int argc, char **argv)
 
   if (!opt_only_cline)
     {
-      parse_conf (config_file, true);
+      parse_conf (config_file, true, opt_chroot, add_dir_1);
 
       /* Always add the standard search paths.  */
       add_system_dir (SLIBDIR);
diff --git a/elf/parseconf.c b/elf/parseconf.c
new file mode 100644
index 0000000000..c48ea9c2d1
--- /dev/null
+++ b/elf/parseconf.c
@@ -0,0 +1,177 @@
+/* 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>
+#include "parseconf.h"
+
+/* Parse configuration file.  */
+void
+parse_conf (const char *filename, bool do_chroot, char *opt_chroot, parse_conf_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 if (!strncasecmp (cp, "hwcap", 5) && isblank (cp[5]))
+	error (0, 0, _("%s:%u: hwcap directive ignored"), filename, lineno);
+      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, parse_conf_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)
+	parse_conf (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/parseconf.h b/elf/parseconf.h
new file mode 100644
index 0000000000..faf5375232
--- /dev/null
+++ b/elf/parseconf.h
@@ -0,0 +1,5 @@
+typedef void (parse_conf_cb) (const char *line, const char *from_file, int from_line);
+
+void parse_conf_include (const char *config_file, unsigned int lineno,
+			 bool do_chroot, const char *pattern, char *opt_chroot, parse_conf_cb *cb);
+void parse_conf (const char *filename, bool do_chroot, char *opt_chroot, parse_conf_cb *cb);



More information about the Libc-alpha mailing list