Siddhesh Poyarekar 17b00fb
#include <sys/types.h>
Siddhesh Poyarekar 17b00fb
#include <sys/wait.h>
Siddhesh Poyarekar 17b00fb
#include <stdio.h>
Siddhesh Poyarekar 17b00fb
#include <errno.h>
Siddhesh Poyarekar 17b00fb
#include <unistd.h>
Siddhesh Poyarekar 17b00fb
#include <sys/time.h>
Siddhesh Poyarekar 17b00fb
#include <dirent.h>
Siddhesh Poyarekar 17b00fb
#include <stddef.h>
Siddhesh Poyarekar 17b00fb
#include <fcntl.h>
Siddhesh Poyarekar 17b00fb
#include <string.h>
Siddhesh Poyarekar 17b00fb
#include <sys/stat.h>
Siddhesh Poyarekar 17b00fb
#include <elf.h>
Siddhesh Poyarekar 17b00fb
e33b0e3
#define LD_SO_CONF "/etc/ld.so.conf"
707a1e8
#define ICONVCONFIG "/usr/sbin/iconvconfig"
e33b0e3
Siddhesh Poyarekar 17b00fb
#define verbose_exec(failcode, path...) \
Siddhesh Poyarekar 17b00fb
  do							\
Siddhesh Poyarekar 17b00fb
    {							\
Siddhesh Poyarekar 17b00fb
      char *const arr[] = { path, NULL };		\
Siddhesh Poyarekar 17b00fb
      vexec (failcode, arr);				\
Siddhesh Poyarekar 17b00fb
    } while (0)
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
__attribute__((noinline)) void vexec (int failcode, char *const path[]);
Siddhesh Poyarekar 17b00fb
__attribute__((noinline)) void says (const char *str);
Siddhesh Poyarekar 17b00fb
__attribute__((noinline)) void sayn (long num);
Siddhesh Poyarekar 17b00fb
__attribute__((noinline)) void message (char *const path[]);
Siddhesh Poyarekar 17b00fb
__attribute__((noinline)) int check_elf (const char *name);
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
int
Siddhesh Poyarekar 17b00fb
main (void)
Siddhesh Poyarekar 17b00fb
{
Siddhesh Poyarekar 17b00fb
  struct stat statbuf;
Siddhesh Poyarekar 17b00fb
  char initpath[256];
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
  char buffer[4096];
Siddhesh Poyarekar 17b00fb
  struct pref {
Siddhesh Poyarekar 17b00fb
    char *p;
Siddhesh Poyarekar 17b00fb
    int len;
Siddhesh Poyarekar 17b00fb
  } prefix[] = { { "libc-", 5 }, { "libm-", 5 },
Siddhesh Poyarekar 17b00fb
		 { "librt-", 6 }, { "libpthread-", 11 },
Siddhesh Poyarekar 17b00fb
		 { "librtkaio-", 10 }, { "libthread_db-", 13 } };
Siddhesh Poyarekar 17b00fb
  int i, j, fd;
Siddhesh Poyarekar 17b00fb
  off_t base;
Siddhesh Poyarekar 17b00fb
  ssize_t ret;
95cc2e8
95cc2e8
  /* In order to support in-place upgrades, we must immediately remove
95cc2e8
     obsolete platform directories after installing a new glibc
95cc2e8
     version.  RPM only deletes files removed by updates near the end
95cc2e8
     of the transaction.  If we did not remove the obsolete platform
95cc2e8
     directories here, they would be preferred by the dynamic linker
95cc2e8
     during the execution of subsequent RPM scriptlets, likely
95cc2e8
     resulting in process startup failures.  */
6e6bd41
  const char *remove_dirs[] =
6e6bd41
    {
a5a7506
#if defined (__i386__)
6e6bd41
      "/lib/i686",
6e6bd41
      "/lib/i686/nosegneg",
a5a7506
#elif defined (__powerpc64__) && _CALL_ELF != 2
a5a7506
      "/lib64/power6",
Siddhesh Poyarekar 17b00fb
#endif
a5a7506
    };
Siddhesh Poyarekar 17b00fb
  for (j = 0; j < sizeof (remove_dirs) / sizeof (remove_dirs[0]); ++j)
Siddhesh Poyarekar 17b00fb
    {
Siddhesh Poyarekar 17b00fb
      size_t rmlen = strlen (remove_dirs[j]);
Siddhesh Poyarekar 17b00fb
      fd = open (remove_dirs[j], O_RDONLY);
Siddhesh Poyarekar 17b00fb
      if (fd >= 0
Siddhesh Poyarekar 17b00fb
	  && (ret = getdirentries (fd, buffer, sizeof (buffer), &base))
Siddhesh Poyarekar 17b00fb
	     >= (ssize_t) offsetof (struct dirent, d_name))
Siddhesh Poyarekar 17b00fb
	{
Siddhesh Poyarekar 17b00fb
	  for (base = 0; base + offsetof (struct dirent, d_name) < ret; )
Siddhesh Poyarekar 17b00fb
	    {
Siddhesh Poyarekar 17b00fb
	      struct dirent *d = (struct dirent *) (buffer + base);
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
	      for (i = 0; i < sizeof (prefix) / sizeof (prefix[0]); i++)
Siddhesh Poyarekar 17b00fb
		if (! strncmp (d->d_name, prefix[i].p, prefix[i].len))
Siddhesh Poyarekar 17b00fb
		  {
Siddhesh Poyarekar 17b00fb
		    char *p = d->d_name + prefix[i].len;
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
		    while (*p == '.' || (*p >= '0' && *p <= '9')) p++;
Siddhesh Poyarekar 17b00fb
		    if (p[0] == 's' && p[1] == 'o' && p[2] == '\0'
Siddhesh Poyarekar 17b00fb
			&& p + 3 - d->d_name
Siddhesh Poyarekar 17b00fb
			   < sizeof (initpath) - rmlen - 1)
Siddhesh Poyarekar 17b00fb
		      {
Siddhesh Poyarekar 17b00fb
			memcpy (initpath, remove_dirs[j], rmlen);
Siddhesh Poyarekar 17b00fb
			initpath[rmlen] = '/';
Siddhesh Poyarekar 17b00fb
			strcpy (initpath + rmlen + 1, d->d_name);
Siddhesh Poyarekar 17b00fb
			unlink (initpath);
Siddhesh Poyarekar 17b00fb
			break;
Siddhesh Poyarekar 17b00fb
		      }
Siddhesh Poyarekar 17b00fb
		  }
Siddhesh Poyarekar 17b00fb
	      base += d->d_reclen;
Siddhesh Poyarekar 17b00fb
	    }
Siddhesh Poyarekar 17b00fb
	  close (fd);
Siddhesh Poyarekar 17b00fb
	}
Siddhesh Poyarekar 17b00fb
    }
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
  int ldsocfd = open (LD_SO_CONF, O_RDONLY);
Siddhesh Poyarekar 17b00fb
  struct stat ldsocst;
Siddhesh Poyarekar 17b00fb
  if (ldsocfd >= 0 && fstat (ldsocfd, &ldsocst) >= 0)
Siddhesh Poyarekar 17b00fb
    {
Siddhesh Poyarekar 17b00fb
      char p[ldsocst.st_size + 1];
Siddhesh Poyarekar 17b00fb
      if (read (ldsocfd, p, ldsocst.st_size) == ldsocst.st_size)
Siddhesh Poyarekar 17b00fb
	{
Siddhesh Poyarekar 17b00fb
	  p[ldsocst.st_size] = '\0';
Siddhesh Poyarekar 17b00fb
	  if (strstr (p, "include ld.so.conf.d/*.conf") == NULL)
Siddhesh Poyarekar 17b00fb
	    {
Siddhesh Poyarekar 17b00fb
	      close (ldsocfd);
Siddhesh Poyarekar 17b00fb
	      ldsocfd = open (LD_SO_CONF, O_WRONLY | O_TRUNC);
Siddhesh Poyarekar 17b00fb
	      if (ldsocfd >= 0)
Siddhesh Poyarekar 17b00fb
		{
Siddhesh Poyarekar 17b00fb
		  size_t slen = strlen ("include ld.so.conf.d/*.conf\n");
Siddhesh Poyarekar 17b00fb
		  if (write (ldsocfd, "include ld.so.conf.d/*.conf\n", slen)
Siddhesh Poyarekar 17b00fb
		      != slen
Siddhesh Poyarekar 17b00fb
		      || write (ldsocfd, p, ldsocst.st_size) != ldsocst.st_size)
Siddhesh Poyarekar 17b00fb
		    _exit (109);
Siddhesh Poyarekar 17b00fb
		}
Siddhesh Poyarekar 17b00fb
	    }
Siddhesh Poyarekar 17b00fb
	}
Siddhesh Poyarekar 17b00fb
      if (ldsocfd >= 0)
Siddhesh Poyarekar 17b00fb
	close (ldsocfd);
Siddhesh Poyarekar 17b00fb
    }
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
  /* If installing bi-arch glibc, rpm sometimes doesn't unpack all files
Siddhesh Poyarekar 17b00fb
     before running one of the lib's %post scriptlet.  /sbin/ldconfig will
Siddhesh Poyarekar 17b00fb
     then be run by the other arch's %post.  */
Siddhesh Poyarekar 17b00fb
  if (! access ("/sbin/ldconfig", X_OK))
Siddhesh Poyarekar 17b00fb
    verbose_exec (110, "/sbin/ldconfig", "/sbin/ldconfig");
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
  if (! utimes (GCONV_MODULES_DIR "/gconv-modules.cache", NULL))
Siddhesh Poyarekar 17b00fb
    {
Carlos O'Donell 0457f64
      char *iconv_cache = GCONV_MODULES_DIR"/gconv-modules.cache";
Carlos O'Donell 0457f64
      char *iconv_dir = GCONV_MODULES_DIR;
Siddhesh Poyarekar 17b00fb
      verbose_exec (113, ICONVCONFIG, "/usr/sbin/iconvconfig",
Siddhesh Poyarekar 17b00fb
		    "-o", iconv_cache,
Siddhesh Poyarekar 17b00fb
		    "--nostdlib", iconv_dir);
Siddhesh Poyarekar 17b00fb
    }
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
  _exit(0);
Siddhesh Poyarekar 17b00fb
}
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
void
Siddhesh Poyarekar 17b00fb
vexec (int failcode, char *const path[])
Siddhesh Poyarekar 17b00fb
{
Siddhesh Poyarekar 17b00fb
  pid_t pid;
Siddhesh Poyarekar 17b00fb
  int status, save_errno;
Siddhesh Poyarekar 17b00fb
  int devnull = 0;
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
  if (failcode < 0)
Siddhesh Poyarekar 17b00fb
    {
Siddhesh Poyarekar 17b00fb
      devnull = 1;
Siddhesh Poyarekar 17b00fb
      failcode = -failcode;
Siddhesh Poyarekar 17b00fb
    }
Siddhesh Poyarekar 17b00fb
  pid = vfork ();
Siddhesh Poyarekar 17b00fb
  if (pid == 0)
Siddhesh Poyarekar 17b00fb
    {
Siddhesh Poyarekar 17b00fb
      int fd;
Siddhesh Poyarekar 17b00fb
      if (devnull && (fd = open ("/dev/null", O_WRONLY)) >= 0)
Siddhesh Poyarekar 17b00fb
	{
Siddhesh Poyarekar 17b00fb
	  dup2 (fd, 1);
Siddhesh Poyarekar 17b00fb
	  dup2 (fd, 2);
Siddhesh Poyarekar 17b00fb
	  close (fd);
Siddhesh Poyarekar 17b00fb
	}
Siddhesh Poyarekar 17b00fb
      execv (path[0], path + 1);
Siddhesh Poyarekar 17b00fb
      save_errno = errno;
Siddhesh Poyarekar 17b00fb
      message (path);
Siddhesh Poyarekar 17b00fb
      says (" exec failed with errno ");
Siddhesh Poyarekar 17b00fb
      sayn (save_errno);
Siddhesh Poyarekar 17b00fb
      says ("\n");
Siddhesh Poyarekar 17b00fb
      _exit (failcode);
Siddhesh Poyarekar 17b00fb
    }
Siddhesh Poyarekar 17b00fb
  else if (pid < 0)
Siddhesh Poyarekar 17b00fb
    {
Siddhesh Poyarekar 17b00fb
      save_errno = errno;
Siddhesh Poyarekar 17b00fb
      message (path);
Siddhesh Poyarekar 17b00fb
      says (" fork failed with errno ");
Siddhesh Poyarekar 17b00fb
      sayn (save_errno);
Siddhesh Poyarekar 17b00fb
      says ("\n");
Siddhesh Poyarekar 17b00fb
      _exit (failcode + 1);
Siddhesh Poyarekar 17b00fb
    }
Siddhesh Poyarekar 17b00fb
  if (waitpid (0, &status, 0) != pid || !WIFEXITED (status))
Siddhesh Poyarekar 17b00fb
    {
Siddhesh Poyarekar 17b00fb
      message (path);
Siddhesh Poyarekar 17b00fb
      says (" child terminated abnormally\n");
Siddhesh Poyarekar 17b00fb
      _exit (failcode + 2);
Siddhesh Poyarekar 17b00fb
    }
Siddhesh Poyarekar 17b00fb
  if (WEXITSTATUS (status))
Siddhesh Poyarekar 17b00fb
    {
Siddhesh Poyarekar 17b00fb
      message (path);
Siddhesh Poyarekar 17b00fb
      says (" child exited with exit code ");
Siddhesh Poyarekar 17b00fb
      sayn (WEXITSTATUS (status));
Siddhesh Poyarekar 17b00fb
      says ("\n");
Siddhesh Poyarekar 17b00fb
      _exit (WEXITSTATUS (status));
Siddhesh Poyarekar 17b00fb
    }
Siddhesh Poyarekar 17b00fb
}
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
void
Siddhesh Poyarekar 17b00fb
says (const char *str)
Siddhesh Poyarekar 17b00fb
{
Siddhesh Poyarekar 17b00fb
  write (1, str, strlen (str));
Siddhesh Poyarekar 17b00fb
}
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
void
Siddhesh Poyarekar 17b00fb
sayn (long num)
Siddhesh Poyarekar 17b00fb
{
Siddhesh Poyarekar 17b00fb
  char string[sizeof (long) * 3 + 1];
Siddhesh Poyarekar 17b00fb
  char *p = string + sizeof (string) - 1;
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
  *p = '\0';
Siddhesh Poyarekar 17b00fb
  if (num == 0)
Siddhesh Poyarekar 17b00fb
    *--p = '0';
Siddhesh Poyarekar 17b00fb
  else
Siddhesh Poyarekar 17b00fb
    while (num)
Siddhesh Poyarekar 17b00fb
      {
Siddhesh Poyarekar 17b00fb
	*--p = '0' + num % 10;
Siddhesh Poyarekar 17b00fb
	num = num / 10;
Siddhesh Poyarekar 17b00fb
      }
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
  says (p);
Siddhesh Poyarekar 17b00fb
}
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
void
Siddhesh Poyarekar 17b00fb
message (char *const path[])
Siddhesh Poyarekar 17b00fb
{
Siddhesh Poyarekar 17b00fb
  says ("/usr/sbin/glibc_post_upgrade: While trying to execute ");
Siddhesh Poyarekar 17b00fb
  says (path[0]);
Siddhesh Poyarekar 17b00fb
}
Siddhesh Poyarekar 17b00fb
Siddhesh Poyarekar 17b00fb
int
Siddhesh Poyarekar 17b00fb
check_elf (const char *name)
Siddhesh Poyarekar 17b00fb
{
Siddhesh Poyarekar 17b00fb
  /* Play safe, if we can't open or read, assume it might be
Siddhesh Poyarekar 17b00fb
     ELF for the current arch.  */
Siddhesh Poyarekar 17b00fb
  int ret = 1;
Siddhesh Poyarekar 17b00fb
  int fd = open (name, O_RDONLY);
Siddhesh Poyarekar 17b00fb
  if (fd >= 0)
Siddhesh Poyarekar 17b00fb
    {
Siddhesh Poyarekar 17b00fb
      Elf32_Ehdr ehdr;
Siddhesh Poyarekar 17b00fb
      if (read (fd, &ehdr, offsetof (Elf32_Ehdr, e_version))
Siddhesh Poyarekar 17b00fb
	  == offsetof (Elf32_Ehdr, e_version))
Siddhesh Poyarekar 17b00fb
	{
Siddhesh Poyarekar 17b00fb
	  ret = 0;
Siddhesh Poyarekar 17b00fb
	  if (ehdr.e_ident[EI_CLASS]
Siddhesh Poyarekar 17b00fb
	      == (sizeof (long) == 8 ? ELFCLASS64 : ELFCLASS32))
Siddhesh Poyarekar 17b00fb
	    {
Siddhesh Poyarekar 17b00fb
#if defined __i386__
Siddhesh Poyarekar 17b00fb
	      ret = ehdr.e_machine == EM_386;
Siddhesh Poyarekar 17b00fb
#elif defined __x86_64__
Siddhesh Poyarekar 17b00fb
	      ret = ehdr.e_machine == EM_X86_64;
Siddhesh Poyarekar 17b00fb
#elif defined __powerpc64__
Siddhesh Poyarekar 17b00fb
	      ret = ehdr.e_machine == EM_PPC64;
Siddhesh Poyarekar 17b00fb
#elif defined __powerpc__
Siddhesh Poyarekar 17b00fb
	      ret = ehdr.e_machine == EM_PPC;
Siddhesh Poyarekar 17b00fb
#elif defined __s390__ || defined __s390x__
Siddhesh Poyarekar 17b00fb
	      ret = ehdr.e_machine == EM_S390;
Siddhesh Poyarekar 17b00fb
#elif defined __x86_64__
Siddhesh Poyarekar 17b00fb
	      ret = ehdr.e_machine == EM_X86_64;
Siddhesh Poyarekar 17b00fb
#elif defined __sparc__
Siddhesh Poyarekar 17b00fb
	      if (sizeof (long) == 8)
Siddhesh Poyarekar 17b00fb
		ret = ehdr.e_machine == EM_SPARCV9;
Siddhesh Poyarekar 17b00fb
	      else
Siddhesh Poyarekar 17b00fb
		ret = (ehdr.e_machine == EM_SPARC
Siddhesh Poyarekar 17b00fb
		       || ehdr.e_machine == EM_SPARC32PLUS);
Siddhesh Poyarekar 17b00fb
#else
Siddhesh Poyarekar 17b00fb
	      ret = 1;
Siddhesh Poyarekar 17b00fb
#endif
Siddhesh Poyarekar 17b00fb
	    }
Siddhesh Poyarekar 17b00fb
	}
Siddhesh Poyarekar 17b00fb
      close (fd);
Siddhesh Poyarekar 17b00fb
    }
Siddhesh Poyarekar 17b00fb
  return ret;
Siddhesh Poyarekar 17b00fb
}