[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 (©, "%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 (©, "%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