glibc_post_upgrade: Integrate into the build process
This gives us access to the relevant definitions and also enables us to perform a static PIE build without replicate the entire compiler invocation. Due to the move into the glibc build process, the program had to be cleaned up to compile without warnings.
This commit is contained in:
parent
34f077631c
commit
737f7e8513
360
glibc-post_upgrade.patch
Normal file
360
glibc-post_upgrade.patch
Normal file
@ -0,0 +1,360 @@
|
|||||||
|
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..3c9839ae523d2cc7
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/elf/glibc_post_upgrade.c
|
||||||
|
@@ -0,0 +1,322 @@
|
||||||
|
+#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)) 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[]);
|
||||||
|
+__attribute__((noinline)) static int check_elf (const char *name);
|
||||||
|
+
|
||||||
|
+int
|
||||||
|
+main (void)
|
||||||
|
+{
|
||||||
|
+ struct stat statbuf;
|
||||||
|
+ 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);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /* Check if telinit is available and either SysVInit fifo,
|
||||||
|
+ or upstart telinit. */
|
||||||
|
+ if (access ("/sbin/telinit", X_OK)
|
||||||
|
+ || ((!!access ("/dev/initctl", F_OK))
|
||||||
|
+ ^ !access ("/sbin/initctl", X_OK)))
|
||||||
|
+ _exit (0);
|
||||||
|
+
|
||||||
|
+ /* Check if we are not inside of some chroot, because we'd just
|
||||||
|
+ timeout and leave /etc/initrunlvl.
|
||||||
|
+
|
||||||
|
+ On more modern systems this test is not sufficient to detect
|
||||||
|
+ if we're in a chroot. */
|
||||||
|
+ if (readlink ("/proc/1/exe", initpath, 256) <= 0 ||
|
||||||
|
+ readlink ("/proc/1/root", initpath, 256) <= 0)
|
||||||
|
+ _exit (0);
|
||||||
|
+
|
||||||
|
+ /* Here's another well known way to detect chroot, at least on an
|
||||||
|
+ ext and xfs filesystems and assuming nothing mounted on the chroot's
|
||||||
|
+ root. */
|
||||||
|
+ if (stat ("/", &statbuf) != 0
|
||||||
|
+ || (statbuf.st_ino != 2
|
||||||
|
+ && statbuf.st_ino != 128))
|
||||||
|
+ _exit (0);
|
||||||
|
+
|
||||||
|
+ if (check_elf ("/proc/1/exe"))
|
||||||
|
+ verbose_exec (116,
|
||||||
|
+ (char *) "/sbin/telinit",
|
||||||
|
+ (char *) "/sbin/telinit",
|
||||||
|
+ (char *) "u");
|
||||||
|
+
|
||||||
|
+ /* Check if we can safely condrestart sshd. */
|
||||||
|
+ if (access ("/sbin/service", X_OK) == 0
|
||||||
|
+ && access ("/usr/sbin/sshd", X_OK) == 0
|
||||||
|
+ && access ("/etc/rc.d/init.d/sshd", X_OK) == 0
|
||||||
|
+ && access ("/bin/bash", X_OK) == 0)
|
||||||
|
+ {
|
||||||
|
+ if (check_elf ("/usr/sbin/sshd"))
|
||||||
|
+ verbose_exec (-121,
|
||||||
|
+ (char *) "/sbin/service",
|
||||||
|
+ (char *) "/sbin/service",
|
||||||
|
+ (char *) "sshd",
|
||||||
|
+ (char *) "condrestart");
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ _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]);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static 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;
|
||||||
|
+}
|
23
glibc.spec
23
glibc.spec
@ -118,7 +118,6 @@ License: LGPLv2+ and LGPLv2+ with exceptions and GPLv2+
|
|||||||
URL: http://www.gnu.org/software/glibc/
|
URL: http://www.gnu.org/software/glibc/
|
||||||
Source0: %{?glibc_release_url}%{glibcsrcdir}.tar.gz
|
Source0: %{?glibc_release_url}%{glibcsrcdir}.tar.gz
|
||||||
Source1: build-locale-archive.c
|
Source1: build-locale-archive.c
|
||||||
Source2: glibc_post_upgrade.c
|
|
||||||
Source4: nscd.conf
|
Source4: nscd.conf
|
||||||
Source7: nsswitch.conf
|
Source7: nsswitch.conf
|
||||||
Source8: power6emul.c
|
Source8: power6emul.c
|
||||||
@ -154,7 +153,8 @@ Source11: SUPPORTED
|
|||||||
#
|
#
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
Patch0001: glibc-fedora-nscd.patch
|
Patch1: glibc-post_upgrade.patch
|
||||||
|
Patch2: glibc-fedora-nscd.patch
|
||||||
|
|
||||||
# All these were from the glibc-fedora.patch mega-patch and need another
|
# All these were from the glibc-fedora.patch mega-patch and need another
|
||||||
# round of reviewing. Ideally they'll either be submitted upstream or
|
# round of reviewing. Ideally they'll either be submitted upstream or
|
||||||
@ -734,7 +734,8 @@ microbenchmark tests on the system.
|
|||||||
%setup -q -n %{glibcsrcdir}
|
%setup -q -n %{glibcsrcdir}
|
||||||
|
|
||||||
# Patch order matters.
|
# Patch order matters.
|
||||||
%patch0001 -p1
|
%patch1 -p1
|
||||||
|
%patch2 -p1
|
||||||
%patch2007 -p1
|
%patch2007 -p1
|
||||||
%patch0012 -p1
|
%patch0012 -p1
|
||||||
%patch2013 -p1
|
%patch2013 -p1
|
||||||
@ -999,18 +1000,6 @@ build
|
|||||||
)
|
)
|
||||||
%endif
|
%endif
|
||||||
|
|
||||||
##############################################################################
|
|
||||||
# Build the glibc post-upgrade program:
|
|
||||||
# We only build one of these with the default set of options. This program
|
|
||||||
# must be able to run on all hardware for the lowest common denomintor since
|
|
||||||
# we only build it once.
|
|
||||||
##############################################################################
|
|
||||||
pushd build-%{target}
|
|
||||||
$GCC -static -L. -Os -g %{SOURCE2} \
|
|
||||||
-o glibc_post_upgrade.%{_target_cpu} \
|
|
||||||
'-DGCONV_MODULES_DIR="%{_libdir}/gconv"'
|
|
||||||
popd
|
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
# Install glibc...
|
# Install glibc...
|
||||||
##############################################################################
|
##############################################################################
|
||||||
@ -1245,7 +1234,7 @@ chmod 644 $RPM_BUILD_ROOT%{_libdir}/gconv/gconv-modules.cache
|
|||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
# Install the upgrade program
|
# Install the upgrade program
|
||||||
install -m 700 build-%{target}/glibc_post_upgrade.%{_target_cpu} \
|
install -m 700 build-%{target}/elf/glibc_post_upgrade \
|
||||||
$RPM_BUILD_ROOT%{_prefix}/sbin/glibc_post_upgrade.%{_target_cpu}
|
$RPM_BUILD_ROOT%{_prefix}/sbin/glibc_post_upgrade.%{_target_cpu}
|
||||||
|
|
||||||
# Strip all of the installed object files.
|
# Strip all of the installed object files.
|
||||||
@ -1494,7 +1483,7 @@ rm -rf $RPM_BUILD_ROOT%{_prefix}/share/zoneinfo
|
|||||||
# 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.
|
# glibc_post_upgrade.c is arbitrary.
|
||||||
touch -r %{SOURCE2} $RPM_BUILD_ROOT/etc/ld.so.conf
|
touch -r %{SOURCE0} $RPM_BUILD_ROOT/etc/ld.so.conf
|
||||||
touch -r sunrpc/etc.rpc $RPM_BUILD_ROOT/etc/rpc
|
touch -r sunrpc/etc.rpc $RPM_BUILD_ROOT/etc/rpc
|
||||||
|
|
||||||
pushd build-%{target}
|
pushd build-%{target}
|
||||||
|
Loading…
Reference in New Issue
Block a user