/* Portions derived from Fedora Core glibc_post_upgrade.c */ #include <stdio.h> #include <string.h> #include <limits.h> #include <errno.h> #include <unistd.h> #include <sys/wait.h> #include <sys/types.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[]); int main(int argc, char *argv[]) { static const char *libs[] = { "libc.so.6", "libm.so.6", "libpthread.so.0", "librt.so.1", "libthread_db.so.1" }; /* 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. */ static const char *dirs[] = { SLIBDIR "/i686" }; int i, j, ret; /* Remove obsolete libraries. */ for (i = 0; i < sizeof(dirs) / sizeof(dirs[0]); i++) { for (j = 0; j < sizeof(libs) / sizeof(libs[0]); j++) { char path[PATH_MAX], temp_path[PATH_MAX]; ret = snprintf(path, sizeof(path), "%s/%s", dirs[i], libs[j]); if (ret < 0 || ret >= sizeof(path)) continue; if ((ret = readlink(path, temp_path, sizeof(temp_path) - 1)) != -1) { char resolved_path[PATH_MAX]; temp_path[ret] = '\0'; if (temp_path[0] == '/') strcpy(resolved_path, temp_path); else ret = snprintf(resolved_path, sizeof(resolved_path), "%s/%s", dirs[i], temp_path); if (ret > 0 && ret < sizeof(resolved_path)) unlink(resolved_path); } unlink(path); } } /* Update ld.so.cache only. */ if (access("/usr/sbin/ldconfig", X_OK) == 0) verbose_exec(110, "/usr/sbin/ldconfig", "/usr/sbin/ldconfig", "-X"); /* always generate the gconv-modules.cache */ if (access("/usr/sbin/iconvconfig", X_OK) == 0) verbose_exec(113, "/usr/sbin/iconvconfig", "/usr/sbin/iconvconfig", "-o", GCONV_DIR"/gconv-modules.cache", "--nostdlib", GCONV_DIR); /* bail out if inside chroot */ char pathbuf[256]; if (readlink ("/proc/1/exe", pathbuf, 256) <= 0 || readlink ("/proc/1/root", pathbuf, 256) <= 0) _exit (0); } void vexec (int failcode, char *const path[]) { pid_t pid; int status, save_errno; pid = vfork (); if (pid == 0) { 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-wrapper: While trying to execute "); says (path[0]); }