GLIBC230 change for Fedora 31
by Florian Weimer
I've submitted that last week, to meet the deadline. It's pretty much a
copy from GLIBC229. I don't expect any issues with the approval.
Thanks,
Florian
4 years, 10 months
[PATCH] glibc: Support scanning for aligned chunks.
by Carlos O'Donell
Florian, DJ,
I have tested DJ's aligned chunk scanning code in Fedora Rawhide by doing a
full toolchain bootstrap and looking for problems. I found no issues and
didn't see any regressions in either glibc or gcc's testsuites.
I am fairly confident that the code works and doesn't cause serious problems,
but I'd like a double check from both of you.
I have pushed the commit to Fedora Rawhide so you can view it there, but
I haven't issued a Rawhide build yet.
--
Cheers,
Carlos.
4 years, 10 months
Replacing glibc langpacks
by Florian Weimer
I'm investigating whether it makes sense to switch to a scheme where the
glibc locale data is built from source, during package installation,
based on the langpack configuration system. This is similar to what
Debian does.
The reason is that the compressed locale source code (without the
charmaps, which are not strictly needed once we patch localedef) is
smaller than the subset of locales of a langpack package which people
actually. For example, glibc-langpack-en on Fedora 29 is 6.7 MiB when
installed, but en_US.utf8 is 2.9 MiB, and the locale sources are
3.4 MiB, so even the common case realizes a small saving.
For the installer, the savings might be much larger. If we can teach
anaconda to generate the appropriate locale only after the user has
selected the language, then we no longer need the full locale archive in
the installation image (and in RAM).
Thanks,
Florian
4 years, 10 months
[PATCH] Convert glibc_post_upgrade to Lua.
by Carlos O'Donell
Florian, DJ,
This took me quite some time to test in a variety of combinations to
ensure that I got everything right. Initially I developed all of these
as stand-along lua programs to test for robustness under various
conditions. Then I ported them to rpm and used the posix library to
some extent (though minimally). At this point I relied on strace logs
to extensively verify operation of rpm and the scripts under various
conditions.
Summary of the changes:
* There were two copies of glibc_post_upgrade, one in the patch and one
in dist-git, and I removed both. There
* I updated glibc.spec to removal all handling of the glibc_post_upgrade
binary.
* The 4 "steps" of glibc_post_upgrade were converted directly to lua.
* Step 1:
We don't check to see which architecture we're running on, and instead
we search *all* multilib directories during upgrade and remove anything
that would be bad. This does mean that if for some reason you had
/lib64/power6 on x86_64 we would remove libraries from that directory
during an upgrade. I consider this a reasonable simplification, the
directories are orthogonal and you really shouldn't have them mixed
like that in a normal install.
* Step 2:
I fix /etc/ld.so.conf with a slightly safer operation of writing a
temporary file and then moving it into place. Unfortunately lua doesn't
have good temp name support, so I use a static name, and if the 'rename'
operation fails we leave the tmp file /etc/glibc_post_upgrade.ld.so.conf
in place. Should we call it /etc/ld.so.conf.rpmnew to be more in line
with what rpm would do?
* Step 3:
We discussed that this step of re-running ldconfig is required since
the cache format might change so we recreate the cache early.
* Step 4:
This is the same issue as step 3, we might have an out-of-date gconv
cache so we recreate it as early as possible.
I've done extensive testing, but there were a lot of manual steps
involved in this process of testing, and it's possible I missed something.
What I'm looking for:
- Review of the C code to Lua conversion.
- Review of the overall steps and if they make sense.
I'd like to get this into Rawhide ASAP for general testing.
Thanks!
Cheers,
Carlos.
8< -- 8< -- 8<
From ad67afbb5f2a2c147abc97f7830fdb027fb3405f Mon Sep 17 00:00:00 2001
From: Carlos O'Donell <carlos(a)redhat.com>
Date: Thu, 16 May 2019 21:43:50 -0400
Subject: [PATCH] Convert glibc_post_upgrade to lua.
---
glibc-post_upgrade.patch | 272 --------------------------------------
glibc.spec | 157 +++++++++++++++++++---
glibc_post_upgrade.c | 274 ---------------------------------------
3 files changed, 139 insertions(+), 564 deletions(-)
delete mode 100644 glibc-post_upgrade.patch
delete mode 100644 glibc_post_upgrade.c
diff --git a/glibc-post_upgrade.patch b/glibc-post_upgrade.patch
deleted file mode 100644
index a64adfc..0000000
--- a/glibc-post_upgrade.patch
+++ /dev/null
@@ -1,272 +0,0 @@
-Short description: RPM Post-upgrade cleanup program.
-Author(s): Fedora glibc team <glibc(a)lists.fedoraproject.org>
-Origin: PATCH
-Upstream status: not-needed
-
-A helper program is needed to clean up the system configuration
-early during RPM package installation, so that other scriptlets
-can run successfully.
-
-diff --git a/elf/Makefile b/elf/Makefile
-index 2a432d8beebcd207..368dcae477fff2ae 100644
---- a/elf/Makefile
-+++ b/elf/Makefile
-@@ -117,6 +117,14 @@ others-extras = $(ldconfig-modules)
- endif
- endif
-
-+# This needs to be statically linked because it is executed at a time
-+# when there might be incompatible shared objects on disk, and the
-+# purpose of this program is to remove them (among other things).
-+others-static += glibc_post_upgrade
-+others += glibc_post_upgrade
-+glibc_post_upgrade-modules := static-stubs
-+CFLAGS-glibc_post_upgrade.c += -DGCONV_MODULES_DIR='"$(gconvdir)"'
-+
- # To find xmalloc.c and xstrdup.c
- vpath %.c ../locale/programs
-
-@@ -559,6 +567,8 @@ $(objpfx)sln: $(sln-modules:%=$(objpfx)%.o)
-
- $(objpfx)ldconfig: $(ldconfig-modules:%=$(objpfx)%.o)
-
-+$(objpfx)glibc_post_upgrade: $(glibc_post_upgrade-modules:%=$(objpfx)%.o)
-+
- SYSCONF-FLAGS := -D'SYSCONFDIR="$(sysconfdir)"'
- CFLAGS-ldconfig.c += $(SYSCONF-FLAGS) -D'LIBDIR="$(libdir)"' \
- -D'SLIBDIR="$(slibdir)"'
-diff --git a/elf/glibc_post_upgrade.c b/elf/glibc_post_upgrade.c
-new file mode 100644
-index 0000000000000000..19b59f70e2308032
---- /dev/null
-+++ b/elf/glibc_post_upgrade.c
-@@ -0,0 +1,229 @@
-+#include <sys/types.h>
-+#include <sys/wait.h>
-+#include <stdio.h>
-+#include <errno.h>
-+#include <unistd.h>
-+#include <sys/time.h>
-+#include <dirent.h>
-+#include <stddef.h>
-+#include <fcntl.h>
-+#include <string.h>
-+
-+#define LD_SO_CONF "/etc/ld.so.conf"
-+#define ICONVCONFIG "/usr/sbin/iconvconfig"
-+
-+#define verbose_exec(failcode, path...) \
-+ do \
-+ { \
-+ char *const arr[] = { path, NULL }; \
-+ vexec (failcode, arr); \
-+ } while (0)
-+
-+__attribute__((noinline)) static void vexec (int failcode, char *const path[]);
-+__attribute__((noinline)) static void says (const char *str);
-+__attribute__((noinline)) static void sayn (long num);
-+__attribute__((noinline)) static void message (char *const path[]);
-+
-+int
-+main (void)
-+{
-+ char initpath[256];
-+
-+ char buffer[4096];
-+ struct pref {
-+ const char *p;
-+ int len;
-+ } prefix[] = { { "libc-", 5 }, { "libm-", 5 },
-+ { "librt-", 6 }, { "libpthread-", 11 },
-+ { "librtkaio-", 10 }, { "libthread_db-", 13 } };
-+ int i, j, fd;
-+ off_t base;
-+ ssize_t ret;
-+
-+ /* In order to support in-place upgrades, we must immediately remove
-+ obsolete platform directories after installing a new glibc
-+ version. RPM only deletes files removed by updates near the end
-+ of the transaction. If we did not remove the obsolete platform
-+ directories here, they would be preferred by the dynamic linker
-+ during the execution of subsequent RPM scriptlets, likely
-+ resulting in process startup failures. */
-+ const char *remove_dirs[] =
-+ {
-+#if defined (__i386__)
-+ "/lib/i686",
-+ "/lib/i686/nosegneg",
-+#elif defined (__powerpc64__) && _CALL_ELF != 2
-+ "/lib64/power6",
-+#endif
-+ };
-+ for (j = 0; j < sizeof (remove_dirs) / sizeof (remove_dirs[0]); ++j)
-+ {
-+ size_t rmlen = strlen (remove_dirs[j]);
-+ fd = open (remove_dirs[j], O_RDONLY);
-+ if (fd >= 0
-+ && (ret = getdirentries (fd, buffer, sizeof (buffer), &base))
-+ >= (ssize_t) offsetof (struct dirent, d_name))
-+ {
-+ for (base = 0; base + offsetof (struct dirent, d_name) < ret; )
-+ {
-+ struct dirent *d = (struct dirent *) (buffer + base);
-+
-+ for (i = 0; i < sizeof (prefix) / sizeof (prefix[0]); i++)
-+ if (! strncmp (d->d_name, prefix[i].p, prefix[i].len))
-+ {
-+ char *p = d->d_name + prefix[i].len;
-+
-+ while (*p == '.' || (*p >= '0' && *p <= '9')) p++;
-+ if (p[0] == 's' && p[1] == 'o' && p[2] == '\0'
-+ && p + 3 - d->d_name
-+ < sizeof (initpath) - rmlen - 1)
-+ {
-+ memcpy (initpath, remove_dirs[j], rmlen);
-+ initpath[rmlen] = '/';
-+ strcpy (initpath + rmlen + 1, d->d_name);
-+ unlink (initpath);
-+ break;
-+ }
-+ }
-+ base += d->d_reclen;
-+ }
-+ close (fd);
-+ }
-+ }
-+
-+ int ldsocfd = open (LD_SO_CONF, O_RDONLY);
-+ struct stat ldsocst;
-+ if (ldsocfd >= 0 && fstat (ldsocfd, &ldsocst) >= 0)
-+ {
-+ char p[ldsocst.st_size + 1];
-+ if (read (ldsocfd, p, ldsocst.st_size) == ldsocst.st_size)
-+ {
-+ p[ldsocst.st_size] = '\0';
-+ if (strstr (p, "include ld.so.conf.d/*.conf") == NULL)
-+ {
-+ close (ldsocfd);
-+ ldsocfd = open (LD_SO_CONF, O_WRONLY | O_TRUNC);
-+ if (ldsocfd >= 0)
-+ {
-+ size_t slen = strlen ("include ld.so.conf.d/*.conf\n");
-+ if (write (ldsocfd, "include ld.so.conf.d/*.conf\n", slen)
-+ != slen
-+ || write (ldsocfd, p, ldsocst.st_size) != ldsocst.st_size)
-+ _exit (109);
-+ }
-+ }
-+ }
-+ if (ldsocfd >= 0)
-+ close (ldsocfd);
-+ }
-+
-+ /* If installing bi-arch glibc, rpm sometimes doesn't unpack all files
-+ before running one of the lib's %post scriptlet. /sbin/ldconfig will
-+ then be run by the other arch's %post. */
-+ if (! access ("/sbin/ldconfig", X_OK))
-+ verbose_exec (110,
-+ (char *) "/sbin/ldconfig",
-+ (char *) "/sbin/ldconfig");
-+
-+ if (! utimes (GCONV_MODULES_DIR "/gconv-modules.cache", NULL))
-+ {
-+ const char *iconv_cache = GCONV_MODULES_DIR "/gconv-modules.cache";
-+ const char *iconv_dir = GCONV_MODULES_DIR;
-+ verbose_exec (113,
-+ (char *) ICONVCONFIG,
-+ (char *) "/usr/sbin/iconvconfig",
-+ (char *) "-o",
-+ (char *) iconv_cache,
-+ (char *) "--nostdlib",
-+ (char *) iconv_dir);
-+ }
-+
-+ _exit(0);
-+}
-+
-+void
-+vexec (int failcode, char *const path[])
-+{
-+ pid_t pid;
-+ int status, save_errno;
-+ int devnull = 0;
-+
-+ if (failcode < 0)
-+ {
-+ devnull = 1;
-+ failcode = -failcode;
-+ }
-+ pid = vfork ();
-+ if (pid == 0)
-+ {
-+ int fd;
-+ if (devnull && (fd = open ("/dev/null", O_WRONLY)) >= 0)
-+ {
-+ dup2 (fd, 1);
-+ dup2 (fd, 2);
-+ close (fd);
-+ }
-+ execv (path[0], path + 1);
-+ save_errno = errno;
-+ message (path);
-+ says (" exec failed with errno ");
-+ sayn (save_errno);
-+ says ("\n");
-+ _exit (failcode);
-+ }
-+ else if (pid < 0)
-+ {
-+ save_errno = errno;
-+ message (path);
-+ says (" fork failed with errno ");
-+ sayn (save_errno);
-+ says ("\n");
-+ _exit (failcode + 1);
-+ }
-+ if (waitpid (0, &status, 0) != pid || !WIFEXITED (status))
-+ {
-+ message (path);
-+ says (" child terminated abnormally\n");
-+ _exit (failcode + 2);
-+ }
-+ if (WEXITSTATUS (status))
-+ {
-+ message (path);
-+ says (" child exited with exit code ");
-+ sayn (WEXITSTATUS (status));
-+ says ("\n");
-+ _exit (WEXITSTATUS (status));
-+ }
-+}
-+
-+static void
-+says (const char *str)
-+{
-+ write (1, str, strlen (str));
-+}
-+
-+static void
-+sayn (long num)
-+{
-+ char string[sizeof (long) * 3 + 1];
-+ char *p = string + sizeof (string) - 1;
-+
-+ *p = '\0';
-+ if (num == 0)
-+ *--p = '0';
-+ else
-+ while (num)
-+ {
-+ *--p = '0' + num % 10;
-+ num = num / 10;
-+ }
-+
-+ says (p);
-+}
-+
-+static void
-+message (char *const path[])
-+{
-+ says ("/usr/sbin/glibc_post_upgrade: While trying to execute ");
-+ says (path[0]);
-+}
diff --git a/glibc.spec b/glibc.spec
index df07e14..ce8d082 100644
--- a/glibc.spec
+++ b/glibc.spec
@@ -87,7 +87,7 @@
Summary: The GNU libc libraries
Name: glibc
Version: %{glibcversion}
-Release: 19%{?dist}
+Release: 20%{?dist}
# In general, GPLv2+ is used by programs, LGPLv2+ is used for
# libraries.
@@ -137,7 +137,6 @@ Source12: ChangeLog.old
# - See each individual patch file for origin and upstream status.
# - For new patches follow template.patch format.
##############################################################################
-Patch1: glibc-post_upgrade.patch
Patch2: glibc-fedora-nscd.patch
Patch3: glibc-rh697421.patch
Patch4: glibc-fedora-linux-tcsetattr.patch
@@ -401,8 +400,11 @@ libraries, as well as national language (locale) support.
/sbin/ldconfig
%end
-# We need to run ldconfig manually because ldconfig cannot handle the
-# relative include path in the /etc/ld.so.conf file we gneerate.
+# We need to run ldconfig manually because __brp_ldconfig assumes that
+# glibc itself is always installed in $RPM_BUILD_ROOT, but with sysroots
+# we may be installed into a subdirectory of that path. Therefore we
+# unset __brp_ldconfig and run ldconfig by hand with the sysroots path
+# passed to -r.
%undefine __brp_ldconfig
######################################################################
@@ -1094,10 +1096,6 @@ truncate -s 0 %{glibc_sysroot}/etc/gai.conf
truncate -s 0 %{glibc_sysroot}%{_libdir}/gconv/gconv-modules.cache
chmod 644 %{glibc_sysroot}%{_libdir}/gconv/gconv-modules.cache
-# Install the upgrade program
-install -m 700 build-%{target}/elf/glibc_post_upgrade \
- %{glibc_sysroot}%{_prefix}/sbin/glibc_post_upgrade.%{_target_cpu}
-
##############################################################################
# Install debug copies of unstripped static libraries
# - This step must be last in order to capture any additional static
@@ -1120,8 +1118,8 @@ rm -rf %{glibc_sysroot}%{_prefix}/share/zoneinfo
#
# XXX: Ideally ld.so.conf should have the timestamp of the spec file, but there
# doesn't seem to be any macro to give us that. So we do the next best thing,
-# which is to at least keep the timestamp consistent. The choice of using
-# glibc_post_upgrade.c is arbitrary.
+# which is to at least keep the timestamp consistent. The choice of using
+# %{SOURCE0} is arbitrary.
touch -r %{SOURCE0} %{glibc_sysroot}/etc/ld.so.conf
touch -r sunrpc/etc.rpc %{glibc_sysroot}/etc/rpc
@@ -1358,8 +1356,7 @@ chmod 0444 master.filelist
# - The partial (lib*_p.a) static libraries, include files.
# - The static files, objects, unversioned DSOs, and nscd.
# - The bin, locale, some sbin, and share.
-# - The use of [^gi] is meant to exclude all files except glibc_post_upgrade,
-# and iconvconfig, which we want in the main packages.
+# - We want iconvconfig in the main package.
# - All the libnss files (we add back the ones we want later).
# - All bench test binaries.
# - The aux-cache, since it's handled specially in the files section.
@@ -1375,7 +1372,7 @@ cat master.filelist \
-e 'nscd' \
-e '%{_prefix}/bin' \
-e '%{_prefix}/lib/locale' \
- -e '%{_prefix}/sbin/[^gi]' \
+ -e '%{_prefix}/sbin/iconvconfig' \
-e '%{_prefix}/share' \
-e '/var/db/Makefile' \
-e '/libnss_.*\.so[0-9.]*$' \
@@ -1452,10 +1449,10 @@ grep '%{_libdir}/lib.*\.a' < master.filelist \
###############################################################################
# All of the bin and certain sbin files go into the common package except
-# glibc_post_upgrade.* and iconvconfig which need to go in glibc. Likewise
-# nscd is excluded because it goes in nscd.
+# iconvconfig which needs to go in glibc. Likewise nscd is excluded because
+# it goes in nscd.
grep '%{_prefix}/bin' master.filelist >> common.filelist
-grep '%{_prefix}/sbin/[^gi]' master.filelist \
+grep '%{_prefix}/sbin/iconvconfig' master.filelist \
| grep -v 'nscd' >> common.filelist
# All of the files under share go into the common package since they should be
# multilib-independent.
@@ -1749,7 +1746,6 @@ $run_ldso /usr/bin/valgrind --error-exitcode=1 \
%endif # %{run_glibc_tests}
-
%pre -p <lua>
-- Check that the running kernel is new enough
required = '%{enablekernel}'
@@ -1758,7 +1754,129 @@ if rpm.vercmp(rel, required) < 0 then
error("FATAL: kernel too old", 0)
end
-%post -p %{_prefix}/sbin/glibc_post_upgrade.%{_target_cpu}
+%post -p <lua>
+-- (1) Remove multilib libraries from previous installs.
+-- In order to support in-place upgrades, we must immediately remove
+-- obsolete platform directories after installing a new glibc
+-- version. RPM only deletes files removed by updates near the end
+-- of the transaction. If we did not remove the obsolete platform
+-- directories here, they would be preferred by the dynamic linker
+-- during the execution of subsequent RPM scriptlets, likely
+-- resulting in process startup failures. */
+
+-- We are going to remove these libraries. Generally speaking we remove
+-- all core libraries in the multilib directory.
+local remove_prefixes = { "libc-",
+ "libm-",
+ "librt-",
+ "libpthread-",
+ "librtkaio-",
+ "libthread_db-" }
+
+-- We are going to search these directories.
+local remove_dirs = { "/lib/i686",
+ "/lib/i686/nosegneg",
+ "/lib64/power6",
+ "/lib64/power7",
+ "/lib64/power8" }
+
+-- Walk all the directories with files we need to remove...
+for _, rdir in ipairs (remove_dirs) do
+ if posix.access (rdir) then
+ -- If the directory exists we look at all the files...
+ local remove_files = posix.files (rdir)
+ for rfile in remove_files do
+ for _, rprefix in ipairs (remove_prefixes) do
+ -- Does the literal prefix match?
+ local prefix = string.find (rfile, rprefix, 1, true)
+ -- Does it end with '*.so'?
+ local dso = string.match (rfile, "%.so$")
+ if (prefix == 1 and (dso ~= nil)) then
+ -- Removing file...
+ os.remove (rdir .. '/' .. rfile)
+ end
+ end
+ end
+ end
+end
+
+-- (2) Update /etc/ld.so.conf
+-- Next we update /etc/ld.so.conf to ensure that it starts with
+-- a literal "include ld.so.conf.d/*.conf".
+
+local ldsoconf = "/etc/ld.so.conf"
+local ldsoconf_tmp = "/etc/glibc_post_upgrade.ld.so.conf"
+
+local conf_fd = io.open (ldsoconf, "r")
+
+if conf_fd ~= nil then
+
+ -- We must have a "include ld.so.conf.d/*.conf" line.
+ local have_include = false
+ for line in conf_fd:lines () do
+ -- This must match, and we don't ignore whitespace.
+ if string.match (line, "^include ld.so.conf.d/%*%.conf$") ~= nil then
+ have_include = true
+ end
+ end
+ conf_fd:close ()
+
+ if not have_include then
+ -- Insert "include ld.so.conf.d/*.conf" line at the start of the
+ -- file. We only support one of these post upgrades running at
+ -- a time (temporary file name is fixed).
+ local tmp_fd = io.open (ldsoconf_tmp, "w")
+ if tmp_fd ~= nil then
+ tmp_fd:write ("include ld.so.conf.d/*.conf\n")
+ for line in io.lines (ldsoconf) do
+ tmp_fd:write (line .. "\n")
+ end
+ tmp_fd:close ()
+ local res = os.rename (ldsoconf_tmp, ldsoconf)
+ if res == nil then
+ io.stdout:write ("Error: Unable to update configuration file (rename).\n")
+ end
+ else
+ io.stdout:write ("Error: Unable to update configuration file (open).\n")
+ end
+ end
+end
+
+-- (3) Rebuild ld.so.cache early.
+-- If the format of the cache changes then we need to rebuild
+-- the cache early to avoid any problems running binaries with
+-- the new glibc.
+
+if posix.access ("%{_prefix}/sbin/ldconfig", "x") then
+ local pid = posix.fork ()
+ if pid == 0 then
+ posix.exec ("%{_prefix}/sbin/ldconfig")
+ elseif pid > 0 then
+ posix.wait (pid)
+ end
+end
+
+-- (4) Update gconv modules cache.
+-- If the /usr/lib/gconv/gconv-modules.cache exists, then update it
+-- with the latest set of modules that were just installed.
+-- We assume that the cache is in %{_libdir}/gconv and called
+-- "gconv-modules.cache".
+
+local iconv_dir = "%{_libdir}/gconv"
+local iconv_cache = iconv_dir .. "/gconv-modules.cache"
+if posix.utime (iconv_cache) == 0 then
+ local pid = posix.fork ()
+ if pid == 0 then
+ posix.exec ("%{_prefix}/sbin/iconvconfig",
+ "-o", iconv_cache,
+ "--nostdlib",
+ iconv_dir)
+ elseif pid > 0 then
+ posix.wait (pid)
+ end
+else
+ io.stdout:write ("Error: Missing " .. iconv_cache .. " file.\n")
+end
%posttrans all-langpacks -e -p <lua>
-- If at the end of the transaction we are still installed
@@ -1899,6 +2017,9 @@ fi
%files -f compat-libpthread-nonshared.filelist -n compat-libpthread-nonshared
%changelog
+* Thu May 16 2019 Carlos O'Donell <carlos(a)redhat.com> - 2.29.9000-20
+- Convert glibc_post_upgrade to lua.
+
* Wed May 15 2019 Florian Weimer <fweimer(a)redhat.com> - 2.29.9000-19
- Auto-sync with upstream branch master,
commit 32ff397533715988c19cbf3675dcbd727ec13e18:
diff --git a/glibc_post_upgrade.c b/glibc_post_upgrade.c
deleted file mode 100644
index 9014857..0000000
--- a/glibc_post_upgrade.c
+++ /dev/null
@@ -1,274 +0,0 @@
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <stdio.h>
-#include <errno.h>
-#include <unistd.h>
-#include <sys/time.h>
-#include <dirent.h>
-#include <stddef.h>
-#include <fcntl.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <elf.h>
-
-#define LD_SO_CONF "/etc/ld.so.conf"
-#define ICONVCONFIG "/usr/sbin/iconvconfig"
-
-#define verbose_exec(failcode, path...) \
- do \
- { \
- char *const arr[] = { path, NULL }; \
- vexec (failcode, arr); \
- } while (0)
-
-__attribute__((noinline)) void vexec (int failcode, char *const path[]);
-__attribute__((noinline)) void says (const char *str);
-__attribute__((noinline)) void sayn (long num);
-__attribute__((noinline)) void message (char *const path[]);
-__attribute__((noinline)) int check_elf (const char *name);
-
-int
-main (void)
-{
- struct stat statbuf;
- char initpath[256];
-
- char buffer[4096];
- struct pref {
- char *p;
- int len;
- } prefix[] = { { "libc-", 5 }, { "libm-", 5 },
- { "librt-", 6 }, { "libpthread-", 11 },
- { "librtkaio-", 10 }, { "libthread_db-", 13 } };
- int i, j, fd;
- off_t base;
- ssize_t ret;
-
- /* In order to support in-place upgrades, we must immediately remove
- obsolete platform directories after installing a new glibc
- version. RPM only deletes files removed by updates near the end
- of the transaction. If we did not remove the obsolete platform
- directories here, they would be preferred by the dynamic linker
- during the execution of subsequent RPM scriptlets, likely
- resulting in process startup failures. */
- const char *remove_dirs[] =
- {
-#if defined (__i386__)
- "/lib/i686",
- "/lib/i686/nosegneg",
-#elif defined (__powerpc64__) && _CALL_ELF != 2
- "/lib64/power6",
- "/lib64/power7",
- "/lib64/power8",
-#endif
- };
- for (j = 0; j < sizeof (remove_dirs) / sizeof (remove_dirs[0]); ++j)
- {
- size_t rmlen = strlen (remove_dirs[j]);
- fd = open (remove_dirs[j], O_RDONLY);
- if (fd >= 0
- && (ret = getdirentries (fd, buffer, sizeof (buffer), &base))
- >= (ssize_t) offsetof (struct dirent, d_name))
- {
- for (base = 0; base + offsetof (struct dirent, d_name) < ret; )
- {
- struct dirent *d = (struct dirent *) (buffer + base);
-
- for (i = 0; i < sizeof (prefix) / sizeof (prefix[0]); i++)
- if (! strncmp (d->d_name, prefix[i].p, prefix[i].len))
- {
- char *p = d->d_name + prefix[i].len;
-
- while (*p == '.' || (*p >= '0' && *p <= '9')) p++;
- if (p[0] == 's' && p[1] == 'o' && p[2] == '\0'
- && p + 3 - d->d_name
- < sizeof (initpath) - rmlen - 1)
- {
- memcpy (initpath, remove_dirs[j], rmlen);
- initpath[rmlen] = '/';
- strcpy (initpath + rmlen + 1, d->d_name);
- unlink (initpath);
- break;
- }
- }
- base += d->d_reclen;
- }
- close (fd);
- }
- }
-
- int ldsocfd = open (LD_SO_CONF, O_RDONLY);
- struct stat ldsocst;
- if (ldsocfd >= 0 && fstat (ldsocfd, &ldsocst) >= 0)
- {
- char p[ldsocst.st_size + 1];
- if (read (ldsocfd, p, ldsocst.st_size) == ldsocst.st_size)
- {
- p[ldsocst.st_size] = '\0';
- if (strstr (p, "include ld.so.conf.d/*.conf") == NULL)
- {
- close (ldsocfd);
- ldsocfd = open (LD_SO_CONF, O_WRONLY | O_TRUNC);
- if (ldsocfd >= 0)
- {
- size_t slen = strlen ("include ld.so.conf.d/*.conf\n");
- if (write (ldsocfd, "include ld.so.conf.d/*.conf\n", slen)
- != slen
- || write (ldsocfd, p, ldsocst.st_size) != ldsocst.st_size)
- _exit (109);
- }
- }
- }
- if (ldsocfd >= 0)
- close (ldsocfd);
- }
-
- /* If installing bi-arch glibc, rpm sometimes doesn't unpack all files
- before running one of the lib's %post scriptlet. /sbin/ldconfig will
- then be run by the other arch's %post. */
- if (! access ("/sbin/ldconfig", X_OK))
- verbose_exec (110, "/sbin/ldconfig", "/sbin/ldconfig");
-
- if (! utimes (GCONV_MODULES_DIR "/gconv-modules.cache", NULL))
- {
- char *iconv_cache = GCONV_MODULES_DIR"/gconv-modules.cache";
- char *iconv_dir = GCONV_MODULES_DIR;
- verbose_exec (113, ICONVCONFIG, "/usr/sbin/iconvconfig",
- "-o", iconv_cache,
- "--nostdlib", iconv_dir);
- }
-
- _exit(0);
-}
-
-void
-vexec (int failcode, char *const path[])
-{
- pid_t pid;
- int status, save_errno;
- int devnull = 0;
-
- if (failcode < 0)
- {
- devnull = 1;
- failcode = -failcode;
- }
- pid = vfork ();
- if (pid == 0)
- {
- int fd;
- if (devnull && (fd = open ("/dev/null", O_WRONLY)) >= 0)
- {
- dup2 (fd, 1);
- dup2 (fd, 2);
- close (fd);
- }
- execv (path[0], path + 1);
- save_errno = errno;
- message (path);
- says (" exec failed with errno ");
- sayn (save_errno);
- says ("\n");
- _exit (failcode);
- }
- else if (pid < 0)
- {
- save_errno = errno;
- message (path);
- says (" fork failed with errno ");
- sayn (save_errno);
- says ("\n");
- _exit (failcode + 1);
- }
- if (waitpid (0, &status, 0) != pid || !WIFEXITED (status))
- {
- message (path);
- says (" child terminated abnormally\n");
- _exit (failcode + 2);
- }
- if (WEXITSTATUS (status))
- {
- message (path);
- says (" child exited with exit code ");
- sayn (WEXITSTATUS (status));
- says ("\n");
- _exit (WEXITSTATUS (status));
- }
-}
-
-void
-says (const char *str)
-{
- write (1, str, strlen (str));
-}
-
-void
-sayn (long num)
-{
- char string[sizeof (long) * 3 + 1];
- char *p = string + sizeof (string) - 1;
-
- *p = '\0';
- if (num == 0)
- *--p = '0';
- else
- while (num)
- {
- *--p = '0' + num % 10;
- num = num / 10;
- }
-
- says (p);
-}
-
-void
-message (char *const path[])
-{
- says ("/usr/sbin/glibc_post_upgrade: While trying to execute ");
- says (path[0]);
-}
-
-int
-check_elf (const char *name)
-{
- /* Play safe, if we can't open or read, assume it might be
- ELF for the current arch. */
- int ret = 1;
- int fd = open (name, O_RDONLY);
- if (fd >= 0)
- {
- Elf32_Ehdr ehdr;
- if (read (fd, &ehdr, offsetof (Elf32_Ehdr, e_version))
- == offsetof (Elf32_Ehdr, e_version))
- {
- ret = 0;
- if (ehdr.e_ident[EI_CLASS]
- == (sizeof (long) == 8 ? ELFCLASS64 : ELFCLASS32))
- {
-#if defined __i386__
- ret = ehdr.e_machine == EM_386;
-#elif defined __x86_64__
- ret = ehdr.e_machine == EM_X86_64;
-#elif defined __powerpc64__
- ret = ehdr.e_machine == EM_PPC64;
-#elif defined __powerpc__
- ret = ehdr.e_machine == EM_PPC;
-#elif defined __s390__ || defined __s390x__
- ret = ehdr.e_machine == EM_S390;
-#elif defined __x86_64__
- ret = ehdr.e_machine == EM_X86_64;
-#elif defined __sparc__
- if (sizeof (long) == 8)
- ret = ehdr.e_machine == EM_SPARCV9;
- else
- ret = (ehdr.e_machine == EM_SPARC
- || ehdr.e_machine == EM_SPARC32PLUS);
-#else
- ret = 1;
-#endif
- }
- }
- close (fd);
- }
- return ret;
-}
--
2.21.0
4 years, 10 months