about summary refs log tree commit diff
path: root/fedora/glibc_post_upgrade.c
diff options
context:
space:
mode:
Diffstat (limited to 'fedora/glibc_post_upgrade.c')
-rw-r--r--fedora/glibc_post_upgrade.c340
1 files changed, 340 insertions, 0 deletions
diff --git a/fedora/glibc_post_upgrade.c b/fedora/glibc_post_upgrade.c
new file mode 100644
index 0000000000..cde931bde3
--- /dev/null
+++ b/fedora/glibc_post_upgrade.c
@@ -0,0 +1,340 @@
+#if defined __sparc__ && defined __arch64__
+register void *__thread_self __asm ("g7");
+#endif
+#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 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)
+{
+  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;
+#ifdef __i386__
+  const char *remove_dirs[] = { "/lib/tls", "/lib/i686", "/lib/tls/i486", "/lib/tls/i586", "/lib/tls/i686" };
+#else
+#ifndef LIBTLS
+#define LIBTLS "/lib/tls"
+#endif
+  const char *remove_dirs[] = { LIBTLS };
+#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))
+    {
+#ifndef ICONVCONFIG
+#define ICONVCONFIG "/usr/sbin/iconvconfig"
+#endif
+      verbose_exec (113, ICONVCONFIG, "/usr/sbin/iconvconfig",
+		    "-o", GCONV_MODULES_DIR"/gconv-modules.cache",
+		    "--nostdlib", GCONV_MODULES_DIR);
+    }
+
+  /* Check if telinit is available and the init fifo as well.  */
+  if (access ("/sbin/telinit", X_OK) || access ("/dev/initctl", F_OK))
+    _exit (0);
+  /* Check if we are not inside of some chroot, because we'd just
+     timeout and leave /etc/initrunlvl.  */
+  if (readlink ("/proc/1/exe", initpath, 256) <= 0 ||
+      readlink ("/proc/1/root", initpath, 256) <= 0)
+    _exit (0);
+
+  if (check_elf ("/proc/1/exe"))
+    verbose_exec (116, "/sbin/telinit", "/sbin/telinit", "u");
+
+  /* Check if we can safely condrestart sshd.  */
+  if (access ("/sbin/service", X_OK) == 0
+      && access ("/usr/sbin/sshd", X_OK) == 0
+      && access ("/bin/bash", X_OK) == 0)
+    {
+      if (check_elf ("/usr/sbin/sshd"))
+	verbose_exec (-121, "/sbin/service", "/sbin/service", "sshd", "condrestart");
+    }
+
+  _exit(0);
+}
+
+#ifndef NO_SIZE_OPTIMIZATION
+int __libc_multiple_threads __attribute__((nocommon));
+int __libc_enable_asynccancel (void) { return 0; }
+void __libc_disable_asynccancel (int x) { }
+void __libc_csu_init (void) { }
+void __libc_csu_fini (void) { }
+pid_t __fork (void) { return -1; }
+char thr_buf[65536];
+
+# ifndef __powerpc__
+int
+__libc_start_main (int (*main) (void), int argc, char **argv,
+		   void (*init) (void), void (*fini) (void),
+		   void (*rtld_fini) (void), void * stack_end)
+# else
+struct startup_info
+{
+  void *sda_base;
+  int (*main) (int, char **, char **, void *);
+  int (*init) (int, char **, char **, void *);
+  void (*fini) (void);
+};
+
+int
+__libc_start_main (int argc, char **ubp_av, char **ubp_ev,
+		   void *auxvec, void (*rtld_fini) (void),
+		   struct startup_info *stinfo,
+		   char **stack_on_entry)
+# endif
+{
+#if defined __ia64__ || defined __powerpc64__
+  register void *r13 __asm ("r13") = thr_buf + 32768;
+  __asm ("" : : "r" (r13));
+#elif defined __sparc__
+  register void *g6 __asm ("g6") = thr_buf + 32768;
+# ifdef __arch64__
+  __thread_self = thr_buf + 32768;
+# else
+  register void *__thread_self __asm ("g7") = thr_buf + 32768;
+# endif
+  __asm ("" : : "r" (g6), "r" (__thread_self));
+#elif defined __s390__ && !defined __s390x__
+  __asm ("sar %%a0,%0" : : "d" (thr_buf + 32768));
+#elif defined __s390x__
+  __asm ("sar %%a1,%0; srlg 0,%0,32; sar %%a0,0" : : "d" (thr_buf + 32768) : "0");
+#elif defined __powerpc__ && !defined __powerpc64__
+  register void *r2 __asm ("r2") = thr_buf + 32768;
+  __asm ("" : : "r" (r2));
+#endif
+  main();
+  return 0;
+}
+#endif
+
+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 __ia64__
+	      ret = ehdr.e_machine == EM_IA_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;
+}