Convert glibc_post_upgrade to lua.
This commit is contained in:
parent
fcb4083893
commit
34927af202
@ -1,272 +0,0 @@
|
||||
Short description: RPM Post-upgrade cleanup program.
|
||||
Author(s): Fedora glibc team <glibc@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]);
|
||||
+}
|
167
glibc.spec
167
glibc.spec
@ -87,7 +87,7 @@
|
||||
Summary: The GNU libc libraries
|
||||
Name: glibc
|
||||
Version: %{glibcversion}
|
||||
Release: 22%{?dist}
|
||||
Release: 23%{?dist}
|
||||
|
||||
# In general, GPLv2+ is used by programs, LGPLv2+ is used for
|
||||
# libraries.
|
||||
@ -136,7 +136,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
|
||||
@ -399,8 +398,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
|
||||
|
||||
######################################################################
|
||||
@ -1089,10 +1091,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
|
||||
@ -1115,8 +1113,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
|
||||
|
||||
@ -1341,8 +1339,9 @@ 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 and we do this by using
|
||||
# a double negation of -v and [^i] so it removes all files in
|
||||
# sbin *but* iconvconfig.
|
||||
# - 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.
|
||||
@ -1357,7 +1356,7 @@ cat master.filelist \
|
||||
-e 'nscd' \
|
||||
-e '%{_prefix}/bin' \
|
||||
-e '%{_prefix}/lib/locale' \
|
||||
-e '%{_prefix}/sbin/[^gi]' \
|
||||
-e '%{_prefix}/sbin/[^i]' \
|
||||
-e '%{_prefix}/share' \
|
||||
-e '/var/db/Makefile' \
|
||||
-e '/libnss_.*\.so[0-9.]*$' \
|
||||
@ -1433,10 +1432,13 @@ 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. The iconvconfig binary is kept in the main glibc package
|
||||
# because we use it in the post-install scriptlet to rebuild the
|
||||
# gconv-modules.cache.
|
||||
grep '%{_prefix}/bin' master.filelist >> common.filelist
|
||||
grep '%{_prefix}/sbin/[^gi]' master.filelist \
|
||||
grep '%{_prefix}/sbin' master.filelist \
|
||||
| grep -v '%{_prefix}/sbin/iconvconfig' \
|
||||
| grep -v 'nscd' >> common.filelist
|
||||
# All of the files under share go into the common package since they should be
|
||||
# multilib-independent.
|
||||
@ -1736,7 +1738,135 @@ 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>
|
||||
-- We use lua's posix.exec because there may be no shell that we can
|
||||
-- run during glibc upgrade.
|
||||
function post_exec (program, ...)
|
||||
local pid = posix.fork ()
|
||||
if pid == 0 then
|
||||
assert (posix.exec (program, ...))
|
||||
elseif pid > 0 then
|
||||
posix.wait (pid)
|
||||
end
|
||||
end
|
||||
|
||||
-- (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 may be preferred by the dynamic linker
|
||||
-- during the execution of subsequent RPM scriptlets, likely
|
||||
-- resulting in process startup failures.
|
||||
|
||||
-- Full set of libraries glibc may install.
|
||||
install_libs = { "anl", "BrokenLocale", "c", "dl", "m", "mvec",
|
||||
"nss_compat", "nss_db", "nss_dns", "nss_files",
|
||||
"nss_hesiod", "pthread", "resolv", "rt", "SegFault",
|
||||
"thread_db", "util" }
|
||||
|
||||
-- We are going to remove these libraries. Generally speaking we remove
|
||||
-- all core libraries in the multilib directory.
|
||||
-- We employ a tight match where X.Y is in [2.0,9.9*], so we would
|
||||
-- match "libc-2.0.so" and so on up to "libc-9.9*".
|
||||
remove_regexps = {}
|
||||
for i = 1, #install_libs do
|
||||
remove_regexps[i] = ("lib" .. install_libs[i]
|
||||
.. "%%-[2-9]%%.[0-9]+%%.so$")
|
||||
end
|
||||
|
||||
-- Two exceptions:
|
||||
remove_regexps[#install_libs + 1] = "libthread_db%%-1%%.0%%.so"
|
||||
remove_regexps[#install_libs + 2] = "libSegFault%%.so"
|
||||
|
||||
-- We are going to search these directories.
|
||||
local remove_dirs = { "%{_libdir}/i686",
|
||||
"%{_libdir}/i686/nosegneg",
|
||||
"%{_libdir}/power6",
|
||||
"%{_libdir}/power7",
|
||||
"%{_libdir}/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 _, rregexp in ipairs (remove_regexps) do
|
||||
-- Does it match the regexp?
|
||||
local dso = string.match (rfile, rregexp)
|
||||
if (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"
|
||||
|
||||
if posix.access (ldsoconf) then
|
||||
|
||||
-- We must have a "include ld.so.conf.d/*.conf" line.
|
||||
local have_include = false
|
||||
for line in io.lines (ldsoconf) 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
|
||||
|
||||
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.
|
||||
|
||||
-- Note: We use _prefix because Fedora's UsrMove says so.
|
||||
post_exec ("%{_prefix}/sbin/ldconfig")
|
||||
|
||||
-- (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
|
||||
post_exec ("%{_prefix}/sbin/iconvconfig",
|
||||
"-o", iconv_cache,
|
||||
"--nostdlib",
|
||||
iconv_dir)
|
||||
else
|
||||
io.stdout:write ("Error: Missing " .. iconv_cache .. " file.\n")
|
||||
end
|
||||
|
||||
%pre headers
|
||||
# this used to be a link and it is causing nightmares now
|
||||
@ -1855,6 +1985,9 @@ fi
|
||||
%files -f compat-libpthread-nonshared.filelist -n compat-libpthread-nonshared
|
||||
|
||||
%changelog
|
||||
* Sat Jun 01 2019 Carlos O'Donell <carlos@redhat.com> - 2.29.9000-23
|
||||
- Convert glibc_post_upgrade to lua.
|
||||
|
||||
* Sat Jun 01 2019 Florian Weimer <fweimer@redhat.com> - 2.29.9000-22
|
||||
- Remove support for filtering glibc-all-langpacks (#1715891)
|
||||
- Auto-sync with upstream branch master,
|
||||
|
@ -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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user