]> git.ipfire.org Git - thirdparty/glibc.git/commitdiff
elf: factor out ld.conf parsing
authorDJ Delorie <dj@redhat.com>
Tue, 17 Feb 2026 23:00:50 +0000 (18:00 -0500)
committerDJ Delorie <dj@redhat.com>
Mon, 16 Mar 2026 17:00:23 +0000 (13:00 -0400)
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Reviewed-by: Yury Khrustalev <yury.khrustalev@arm.com>
elf/Makefile
elf/ldconfig-parse.c [new file with mode: 0644]
elf/ldconfig.c
sysdeps/generic/ldconfig.h

index c8458f800003d69b3240041d9112d601621a101e..7f039b55631eb31bb032a5125d17d958925214d0 100644 (file)
@@ -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 (file)
index 0000000..b7bb664
--- /dev/null
@@ -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);
+}
index aca967403a2f763d559939bc13d827b29493198b..070e933df625f3f922195b458490459487436d50 100644 (file)
@@ -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);
index 5913bf40fc12d9ce23484bb0cfdb8c81f1ac7bf0..22d0fd0f8268e93f4100413065fec002cfe10955 100644 (file)
@@ -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>