forked from rpms/glibc
0e17ea22c1
The following commit removes the requirement for patches to be placed in 1000, 2000, or 3000 ID blocks depending on their upstream status. Instead upstream status is documented in the header of the patch with some semi-standard notation as described in template.patch. The patches are re-numbered and defined and applied in the same order. Verified that before and after the patch that the source tree does not change. The patch definition is resorted to match the patch application order.
273 lines
8.1 KiB
Diff
273 lines
8.1 KiB
Diff
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]);
|
|
+}
|