From 36e867a96fbc20777c4d3cb15e7aa4f7180f1452 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Thu, 4 Nov 2004 09:46:50 +0000 Subject: [PATCH] Add a timeout when waiting for child processes to exit before pppd exits. Send a SIGTERM to the child processes if the timeout expires or if pppd gets a SIGTERM or SIGINT itself. --- pppd/main.c | 45 ++++++++++++++++++++++++++++++++++----------- pppd/options.c | 6 +++++- pppd/pppd.h | 3 ++- 3 files changed, 41 insertions(+), 13 deletions(-) diff --git a/pppd/main.c b/pppd/main.c index 0bb9492..fe2e953 100644 --- a/pppd/main.c +++ b/pppd/main.c @@ -40,7 +40,7 @@ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#define RCSID "$Id: main.c,v 1.138 2004/10/28 00:32:32 paulus Exp $" +#define RCSID "$Id: main.c,v 1.139 2004/11/04 09:46:50 paulus Exp $" #include #include @@ -125,6 +125,8 @@ int do_callback; /* != 0 if we should do callback next */ int doing_callback; /* != 0 if we are doing callback */ int ppp_session_number; /* Session number, for channels with such a concept (eg PPPoE) */ +int childwait_done; /* have timed out waiting for children */ + #ifdef USE_TDB TDB_CONTEXT *pppdb; /* database for storing status etc. */ #endif @@ -210,7 +212,8 @@ static void toggle_debug __P((int)); static void open_ccp __P((int)); static void bad_signal __P((int)); static void holdoff_end __P((void *)); -static int reap_kids __P((int waitfor)); +static int reap_kids __P((void)); +static void childwait_end __P((void *)); #ifdef USE_TDB static void update_db_entry __P((void)); @@ -627,16 +630,21 @@ main(argc, argv) } /* Wait for scripts to finish */ - /* XXX should have a timeout here */ - while (n_children > 0) { + reap_kids(); + if (n_children > 0) { + if (child_wait > 0) + TIMEOUT(childwait_end, NULL, child_wait); if (debug) { struct subprocess *chp; dbglog("Waiting for %d child processes...", n_children); for (chp = children; chp != NULL; chp = chp->next) dbglog(" script %s, pid %d", chp->prog, chp->pid); } - if (reap_kids(1) < 0) - break; + while (n_children > 0 && !childwait_done) { + handle_events(); + if (kill_link && !childwait_done) + childwait_end(NULL); + } } die(status); @@ -677,8 +685,8 @@ handle_events() got_sigterm = 0; } if (got_sigchld) { - reap_kids(0); /* Don't leave dead kids lying around */ got_sigchld = 0; + reap_kids(); /* Don't leave dead kids lying around */ } if (got_sigusr2) { open_ccp_flag = 1; @@ -1735,22 +1743,37 @@ record_child(pid, prog, done, arg) } } +/* + * childwait_end - we got fed up waiting for the child processes to + * exit, send them all a SIGTERM. + */ +static void +childwait_end(arg) + void *arg; +{ + struct subprocess *chp; + + for (chp = children; chp != NULL; chp = chp->next) { + if (debug) + dbglog("sending SIGTERM to process %d", chp->pid); + kill(chp->pid, SIGTERM); + } + childwait_done = 1; +} /* * reap_kids - get status from any dead child processes, * and log a message for abnormal terminations. */ static int -reap_kids(waitfor) - int waitfor; +reap_kids() { int pid, status; struct subprocess *chp, **prevp; if (n_children == 0) return 0; - while ((pid = waitpid(-1, &status, (waitfor? 0: WNOHANG))) != -1 - && pid != 0) { + while ((pid = waitpid(-1, &status, WNOHANG)) != -1 && pid != 0) { for (prevp = &children; (chp = *prevp) != NULL; prevp = &chp->next) { if (chp->pid == pid) { --n_children; diff --git a/pppd/options.c b/pppd/options.c index f9f10b7..4870128 100644 --- a/pppd/options.c +++ b/pppd/options.c @@ -40,7 +40,7 @@ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#define RCSID "$Id: options.c,v 1.93 2004/10/28 00:15:08 paulus Exp $" +#define RCSID "$Id: options.c,v 1.94 2004/11/04 09:46:50 paulus Exp $" #include #include @@ -113,6 +113,7 @@ char *bundle_name = NULL; /* bundle name for multilink */ bool dump_options; /* print out option values */ bool dryrun; /* print out option values and exit */ char *domain; /* domain name set by domain option */ +int child_wait = 5; /* # seconds to wait for children at exit */ #ifdef MAXOCTETS unsigned int maxoctets = 0; /* default - no limit */ @@ -270,6 +271,9 @@ option_t general_options[] = { { "dryrun", o_bool, &dryrun, "Stop after parsing, printing, and checking options", 1 }, + { "child-timeout", o_int, &child_wait, + "Number of seconds to wait for child processes at exit" }, + #ifdef HAVE_MULTILINK { "multilink", o_bool, &multilink, "Enable multilink operation", OPT_PRIO | 1 }, diff --git a/pppd/pppd.h b/pppd/pppd.h index 02f983e..232aa32 100644 --- a/pppd/pppd.h +++ b/pppd/pppd.h @@ -39,7 +39,7 @@ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * - * $Id: pppd.h,v 1.84 2004/10/31 22:23:18 paulus Exp $ + * $Id: pppd.h,v 1.85 2004/11/04 09:46:50 paulus Exp $ */ /* @@ -309,6 +309,7 @@ extern bool noendpoint; /* don't send or accept endpt. discrim. */ extern char *bundle_name; /* bundle name for multilink */ extern bool dump_options; /* print out option values */ extern bool dryrun; /* check everything, print options, exit */ +extern int child_wait; /* # seconds to wait for children at end */ #ifdef MAXOCTETS extern unsigned int maxoctets; /* Maximum octetes per session (in bytes) */ -- 2.39.2