summaryrefslogtreecommitdiff
path: root/bin/systrace/intercept.c
diff options
context:
space:
mode:
authorNiels Provos <provos@cvs.openbsd.org>2002-07-09 20:46:19 +0000
committerNiels Provos <provos@cvs.openbsd.org>2002-07-09 20:46:19 +0000
commit7d6384b333a9b97f4d8ec808751d55c8ebc67672 (patch)
tree6c54ae2cb928042544779296ae2638c6a09f0a82 /bin/systrace/intercept.c
parent4629f922a7143c45adec6584532b3a1444b97da8 (diff)
allow systrace to run in the background if possible so that the executed
process gets the terminal correctly and exit status reporting works; based on a diff from atatat@atatdot.net from netbsd.
Diffstat (limited to 'bin/systrace/intercept.c')
-rw-r--r--bin/systrace/intercept.c83
1 files changed, 73 insertions, 10 deletions
diff --git a/bin/systrace/intercept.c b/bin/systrace/intercept.c
index c39fc673e01..3580167fe04 100644
--- a/bin/systrace/intercept.c
+++ b/bin/systrace/intercept.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: intercept.c,v 1.11 2002/07/09 15:22:27 provos Exp $ */
+/* $OpenBSD: intercept.c,v 1.12 2002/07/09 20:46:18 provos Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
* All rights reserved.
@@ -213,20 +213,65 @@ intercept_register_execcb(void (*cb)(int, pid_t, int, char *, char *, void *), v
return (0);
}
+static void
+sigusr1_handler(int signum)
+{
+ /* all we need to do is pretend to handle it */
+}
+
pid_t
-intercept_run(int fd, char *path, char *const argv[])
+intercept_run(int bg, int fd, char *path, char *const argv[])
{
- pid_t pid;
-
- pid = fork();
- if (pid == -1)
+ sigset_t none, set, oset;
+ sig_t ohandler;
+ pid_t pid, cpid;
+ int status;
+
+ /* Block signals so that timeing on signal delivery does not matter */
+ sigemptyset(&none);
+ sigemptyset(&set);
+ sigaddset(&set, SIGUSR1);
+ if (sigprocmask(SIG_BLOCK, &set, &oset) == -1)
+ err(1, "sigprocmask");
+ ohandler = signal(SIGUSR1, sigusr1_handler);
+ if (ohandler == SIG_ERR)
+ err(1, "signal");
+
+ pid = getpid();
+ cpid = fork();
+ if (cpid == -1)
return (-1);
- if (pid == 0) {
+
+ /*
+ * If the systrace process should be in the background and we're
+ * the parent, or vice versa.
+ */
+ if ((!bg && cpid == 0) || (bg && cpid != 0)) {
/* Needs to be closed */
close(fd);
- /* Stop myself */
- raise(SIGSTOP);
+ if (bg) {
+ /* Wait for child to "detach" */
+ cpid = wait(&status);
+ if (cpid == -1)
+ err(1, "wait");
+ if (status != 0)
+ errx(1, "wait: child gave up");
+ }
+
+ /* Sleep */
+ sigsuspend(&none);
+
+ /*
+ * Woken up, restore signal handling state.
+ *
+ * Note that there is either no child or we have no idea
+ * what pid it might have at this point. If we fail.
+ */
+ if (signal(SIGUSR1, ohandler) == SIG_ERR)
+ err(1, "signal");
+ if (sigprocmask(SIG_SETMASK, &oset, NULL) == -1)
+ err(1, "sigprocmask");
execvp(path, argv);
@@ -234,7 +279,25 @@ intercept_run(int fd, char *path, char *const argv[])
err(1, "execvp");
}
- sleep(1); /* XXX */
+ /* Choose the pid of the systraced process */
+ pid = bg ? pid : cpid;
+
+ /* Setup done, restore signal handling state */
+ if (signal(SIGUSR1, ohandler) == SIG_ERR) {
+ kill(pid, SIGKILL);
+ err(1, "signal");
+ }
+ if (sigprocmask(SIG_SETMASK, &oset, NULL) == -1) {
+ kill(pid, SIGKILL);
+ err(1, "sigprocmask");
+ }
+
+ if (bg) {
+ if (daemon(0, 0) == -1) {
+ kill(pid, SIGKILL);
+ err(1, "daemon");
+ }
+ }
return (pid);
}