2018-01-19 15:32:18 +00:00
|
|
|
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
|
2018-01-19 15:49:19 +00:00
|
|
|
index 0000000000000000..19b59f70e2308032
|
2018-01-19 15:32:18 +00:00
|
|
|
--- /dev/null
|
|
|
|
+++ b/elf/glibc_post_upgrade.c
|
2018-01-19 15:49:19 +00:00
|
|
|
@@ -0,0 +1,229 @@
|
2018-01-19 15:32:18 +00:00
|
|
|
+#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]);
|
|
|
|
+}
|