diff options
author | Jakub Jelinek <jakub@redhat.com> | 2007-07-12 18:26:36 +0000 |
---|---|---|
committer | Jakub Jelinek <jakub@redhat.com> | 2007-07-12 18:26:36 +0000 |
commit | 0ecb606cb6cf65de1d9fc8a919bceb4be476c602 (patch) | |
tree | 2ea1f8305970753e4a657acb2ccc15ca3eec8e2c /fedora/glibc_post_upgrade.c | |
parent | 7d58530341304d403a6626d7f7a1913165fe2f32 (diff) | |
download | glibc-0ecb606cb6cf65de1d9fc8a919bceb4be476c602.tar.gz |
2.5-18.1
Diffstat (limited to 'fedora/glibc_post_upgrade.c')
-rw-r--r-- | fedora/glibc_post_upgrade.c | 340 |
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; +} |