Convert glibc_post_upgrade to lua.

This commit is contained in:
Carlos O'Donell 2019-05-16 21:43:50 -04:00
parent fcb4083893
commit 34927af202
3 changed files with 150 additions and 563 deletions

View File

@ -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]);
+}

View File

@ -87,7 +87,7 @@
Summary: The GNU libc libraries Summary: The GNU libc libraries
Name: glibc Name: glibc
Version: %{glibcversion} Version: %{glibcversion}
Release: 22%{?dist} Release: 23%{?dist}
# In general, GPLv2+ is used by programs, LGPLv2+ is used for # In general, GPLv2+ is used by programs, LGPLv2+ is used for
# libraries. # libraries.
@ -136,7 +136,6 @@ Source12: ChangeLog.old
# - See each individual patch file for origin and upstream status. # - See each individual patch file for origin and upstream status.
# - For new patches follow template.patch format. # - For new patches follow template.patch format.
############################################################################## ##############################################################################
Patch1: glibc-post_upgrade.patch
Patch2: glibc-fedora-nscd.patch Patch2: glibc-fedora-nscd.patch
Patch3: glibc-rh697421.patch Patch3: glibc-rh697421.patch
Patch4: glibc-fedora-linux-tcsetattr.patch Patch4: glibc-fedora-linux-tcsetattr.patch
@ -399,8 +398,11 @@ libraries, as well as national language (locale) support.
/sbin/ldconfig /sbin/ldconfig
%end %end
# We need to run ldconfig manually because ldconfig cannot handle the # We need to run ldconfig manually because __brp_ldconfig assumes that
# relative include path in the /etc/ld.so.conf file we gneerate. # 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 %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 truncate -s 0 %{glibc_sysroot}%{_libdir}/gconv/gconv-modules.cache
chmod 644 %{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 # Install debug copies of unstripped static libraries
# - This step must be last in order to capture any additional static # - This step must be last in order to capture any additional static
@ -1116,7 +1114,7 @@ rm -rf %{glibc_sysroot}%{_prefix}/share/zoneinfo
# XXX: Ideally ld.so.conf should have the timestamp of the spec file, but there # 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, # 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 # which is to at least keep the timestamp consistent. The choice of using
# glibc_post_upgrade.c is arbitrary. # SOURCE0 is arbitrary.
touch -r %{SOURCE0} %{glibc_sysroot}/etc/ld.so.conf touch -r %{SOURCE0} %{glibc_sysroot}/etc/ld.so.conf
touch -r sunrpc/etc.rpc %{glibc_sysroot}/etc/rpc 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 partial (lib*_p.a) static libraries, include files.
# - The static files, objects, unversioned DSOs, and nscd. # - The static files, objects, unversioned DSOs, and nscd.
# - The bin, locale, some sbin, and share. # - The bin, locale, some sbin, and share.
# - The use of [^gi] is meant to exclude all files except glibc_post_upgrade, # - We want iconvconfig in the main package and we do this by using
# and iconvconfig, which we want in the main packages. # 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 the libnss files (we add back the ones we want later).
# - All bench test binaries. # - All bench test binaries.
# - The aux-cache, since it's handled specially in the files section. # - The aux-cache, since it's handled specially in the files section.
@ -1357,7 +1356,7 @@ cat master.filelist \
-e 'nscd' \ -e 'nscd' \
-e '%{_prefix}/bin' \ -e '%{_prefix}/bin' \
-e '%{_prefix}/lib/locale' \ -e '%{_prefix}/lib/locale' \
-e '%{_prefix}/sbin/[^gi]' \ -e '%{_prefix}/sbin/[^i]' \
-e '%{_prefix}/share' \ -e '%{_prefix}/share' \
-e '/var/db/Makefile' \ -e '/var/db/Makefile' \
-e '/libnss_.*\.so[0-9.]*$' \ -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 # 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 # iconvconfig which needs to go in glibc. Likewise nscd is excluded because
# nscd is excluded because it goes in nscd. # 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}/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 | grep -v 'nscd' >> common.filelist
# All of the files under share go into the common package since they should be # All of the files under share go into the common package since they should be
# multilib-independent. # multilib-independent.
@ -1736,7 +1738,135 @@ if rpm.vercmp(rel, required) < 0 then
error("FATAL: kernel too old", 0) error("FATAL: kernel too old", 0)
end 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 %pre headers
# this used to be a link and it is causing nightmares now # 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 %files -f compat-libpthread-nonshared.filelist -n compat-libpthread-nonshared
%changelog %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 * Sat Jun 01 2019 Florian Weimer <fweimer@redhat.com> - 2.29.9000-22
- Remove support for filtering glibc-all-langpacks (#1715891) - Remove support for filtering glibc-all-langpacks (#1715891)
- Auto-sync with upstream branch master, - Auto-sync with upstream branch master,

View File

@ -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;
}