glibc40/glibc-post-wrapper.c
2012-02-01 14:42:15 +04:00

141 lines
3.1 KiB
C

/* 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"
};
static const char *dirs[] = {
SLIBDIR "/tls"
};
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("/sbin/ldconfig", X_OK) == 0)
verbose_exec(110, "/sbin/ldconfig", "/sbin/ldconfig", "-X");
/* Delegate to ash for normal %post execution. */
argv[0] = ASH_BIN;
execv(ASH_BIN, argv);
return 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_upgrade: While trying to execute ");
says (path[0]);
}