diff options
author | Niels Provos <provos@cvs.openbsd.org> | 2002-07-09 20:46:19 +0000 |
---|---|---|
committer | Niels Provos <provos@cvs.openbsd.org> | 2002-07-09 20:46:19 +0000 |
commit | 7d6384b333a9b97f4d8ec808751d55c8ebc67672 (patch) | |
tree | 6c54ae2cb928042544779296ae2638c6a09f0a82 /bin/systrace/intercept.c | |
parent | 4629f922a7143c45adec6584532b3a1444b97da8 (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.c | 83 |
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); } |