src/debug.c
/* [<][>][^][v][top][bottom][index][help] */
FUNCTIONS
This source file includes following functions.
- sigalrm
- alrm_set
- debug_watch
- debug_call_gdb
- debug_pid
- watch_call_gdb
- sigchld
- watch_main
- watch_init
/* $Id: debug.c,v 1.5 2000/06/11 19:29:28 proff Exp $
* $Copyright$
*/
#include "nglobal.h"
#include "debug.h"
static bool alrm_caught;
static RETSIGTYPE sigalrm (int sig)
/* [<][>][^][v][top][bottom][index][help] */
{
alrm_caught = TRUE;
}
static void
alrm_set()
/* [<][>][^][v][top][bottom][index][help] */
{
alrm_caught = FALSE;
signal(SIGALRM, sigalrm);
alarm(100);
}
static void
debug_watch()
/* [<][>][^][v][top][bottom][index][help] */
{
char buf[512];
sprintf(buf, "%d %s\n", getpid(), logPrintP);
if (write(Watch_fd, buf, strlen(buf)) != strlen(buf))
{
loge (("couldn't inform watch"));
return;
}
alrm_set();
pause();
}
static void
debug_call_gdb(pid_t pid)
/* [<][>][^][v][top][bottom][index][help] */
{
char pid_asc[80];
sprintf(pid_asc, "%d", (int)pid);
execl("/bin/sh", "sh", PATH_DEBUG_SH, Argv0, pid_asc, Version, logPrintP, NULL);
_exit(1);
}
EXPORT void debug_pid()
/* [<][>][^][v][top][bottom][index][help] */
{
pid_t ptrace_child;
if (Watch_fd >= 0)
{
debug_watch();
return;
}
ptrace_child = fork();
if (ptrace_child == 0)
{
sigset_t set;
pid_t gdb_child;
ptrace_child = getpid();
sigemptyset(&set);
sigprocmask(SIG_SETMASK, &set, NULL);
signal (SIGPIPE, SIG_DFL);
signal (SIGCHLD, SIG_DFL);
signal (SIGTERM, SIG_DFL);
signal (SIGHUP, SIG_DFL);
gdb_child = fork();
if (gdb_child == 0)
{
debug_call_gdb(ptrace_child);
NOTREACHED;
}
if (gdb_child < 1)
_exit(1);
waitpid(gdb_child, NULL, 0);
_exit(0);
}
if (ptrace_child < 1)
return;
alrm_set();
waitpid(ptrace_child, NULL, 0);
if (alrm_caught)
{
kill(SIGKILL, ptrace_child);
}
else
alarm(0);
}
/*
* all the following frigging hocus-pocus is to hack around
* the fact that process can't be ptraced() if has *ever*
* had an ancestor that called setuid(), without an intervening
* exec*(). grrr.
*/
EXPORT void watch_call_gdb(pid_t pid, char *msg)
/* [<][>][^][v][top][bottom][index][help] */
{
pid_t child = fork();
if (child == 0)
{
char pid_asc[80];
sprintf(pid_asc, "%d", (int)pid);
execl("/bin/sh", "sh", PATH_DEBUG_SH, Argv0, pid_asc, Version, msg, NULL);
_exit(1);
}
if (child == -1)
{
loge (("fork()"));
return;
}
}
static RETSIGTYPE
sigchld(int sig)
/* [<][>][^][v][top][bottom][index][help] */
{
waitpid(-1, NULL, WNOHANG);
signal(SIGCHLD, sigchld);
}
static void
watch_main(int fd)
/* [<][>][^][v][top][bottom][index][help] */
{
settaskinfo("watch: ready");
signal(SIGCHLD, sigchld);
for (;;)
{
char buf[512];
int pid;
char *msg;
FILE *fh = fdopen(fd, "r");
if (!fgets(buf, sizeof buf, fh))
retire_vm_proc(1);
waitpid(-1, NULL, WNOHANG);
msg = strchr(buf, ' ');
sscanf(buf, "%d", &pid);
if (!msg || pid < 1)
{
logen (("bad pid: %s", buf));
continue;
}
msg++;
watch_call_gdb((pid_t)pid, msg);
}
}
EXPORT void watch_init()
/* [<][>][^][v][top][bottom][index][help] */
{
int p[2];
if (pipe(p) != 0)
{
loge (("pipe()"));
Exit(1);
}
Watch_fd = p[1];
if (make_vm_proc(nc_watch, -1, "watch") == 0) /* 0 == child */
{
watch_main(p[0]);
NOTREACHED;
}
}