]> git.ozlabs.org Git - ppp.git/blobdiff - pppd/main.c
Patch from Robert Vogelgesang:
[ppp.git] / pppd / main.c
index 86315662b0611ba6b7d62434ee8b380e9c10396b..d53f6412746f081e1796bc1dc17c345435aa1418 100644 (file)
@@ -40,7 +40,7 @@
  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#define RCSID  "$Id: main.c,v 1.130 2003/12/17 08:56:05 kad Exp $"
+#define RCSID  "$Id: main.c,v 1.137 2004/10/24 23:13:16 paulus Exp $"
 
 #include <stdio.h>
 #include <ctype.h>
@@ -150,6 +150,7 @@ int got_sigusr2;
 int got_sigterm;
 int got_sighup;
 
+static sigset_t signals_handled;
 static int waiting;
 static sigjmp_buf sigjmp;
 
@@ -589,7 +590,8 @@ main(argc, argv)
         */
     disconnect:
        new_phase(PHASE_DISCONNECT);
-       the_channel->disconnect();
+       if (the_channel->disconnect)
+           the_channel->disconnect();
 
     fail:
        if (the_channel->cleanup)
@@ -647,16 +649,15 @@ static void
 handle_events()
 {
     struct timeval timo;
-    sigset_t mask;
 
     kill_link = open_ccp_flag = 0;
     if (sigsetjmp(sigjmp, 1) == 0) {
-       sigprocmask(SIG_BLOCK, &mask, NULL);
+       sigprocmask(SIG_BLOCK, &signals_handled, NULL);
        if (got_sighup || got_sigterm || got_sigusr2 || got_sigchld) {
-           sigprocmask(SIG_UNBLOCK, &mask, NULL);
+           sigprocmask(SIG_UNBLOCK, &signals_handled, NULL);
        } else {
            waiting = 1;
-           sigprocmask(SIG_UNBLOCK, &mask, NULL);
+           sigprocmask(SIG_UNBLOCK, &signals_handled, NULL);
            wait_input(timeleft(&timo));
        }
     }
@@ -691,19 +692,18 @@ static void
 setup_signals()
 {
     struct sigaction sa;
-    sigset_t mask;
 
     /*
      * Compute mask of all interesting signals and install signal handlers
      * for each.  Only one signal handler may be active at a time.  Therefore,
      * all other signals should be masked when any handler is executing.
      */
-    sigemptyset(&mask);
-    sigaddset(&mask, SIGHUP);
-    sigaddset(&mask, SIGINT);
-    sigaddset(&mask, SIGTERM);
-    sigaddset(&mask, SIGCHLD);
-    sigaddset(&mask, SIGUSR2);
+    sigemptyset(&signals_handled);
+    sigaddset(&signals_handled, SIGHUP);
+    sigaddset(&signals_handled, SIGINT);
+    sigaddset(&signals_handled, SIGTERM);
+    sigaddset(&signals_handled, SIGCHLD);
+    sigaddset(&signals_handled, SIGUSR2);
 
 #define SIGNAL(s, handler)     do { \
        sa.sa_handler = handler; \
@@ -711,7 +711,7 @@ setup_signals()
            fatal("Couldn't establish signal handler (%d): %m", s); \
     } while (0)
 
-    sa.sa_mask = mask;
+    sa.sa_mask = signals_handled;
     sa.sa_flags = 0;
     SIGNAL(SIGHUP, hup);               /* Hangup */
     SIGNAL(SIGINT, term);              /* Interrupt */
@@ -1172,6 +1172,7 @@ print_link_stats()
        info("Connect time %d.%d minutes.", t/10, t%10);
        info("Sent %u bytes, received %u bytes.",
            link_stats.bytes_out, link_stats.bytes_in);
+       link_stats_valid = 0;
     }
 }
 
@@ -1328,6 +1329,7 @@ timeleft(tvp)
 
 /*
  * kill_my_pg - send a signal to our process group, and ignore it ourselves.
+ * We assume that sig is currently blocked.
  */
 static void
 kill_my_pg(sig)
@@ -1335,10 +1337,22 @@ kill_my_pg(sig)
 {
     struct sigaction act, oldact;
 
+    sigemptyset(&act.sa_mask);         /* unnecessary in fact */
     act.sa_handler = SIG_IGN;
     act.sa_flags = 0;
-    sigaction(sig, &act, &oldact);
     kill(0, sig);
+    /*
+     * The kill() above made the signal pending for us, as well as
+     * the rest of our process group, but we don't want it delivered
+     * to us.  It is blocked at the moment.  Setting it to be ignored
+     * will cause the pending signal to be discarded.  If we did the
+     * kill() after setting the signal to be ignored, it is unspecified
+     * (by POSIX) whether the signal is immediately discarded or left
+     * pending, and in fact Linux would leave it pending, and so it
+     * would be delivered after the current signal handler exits,
+     * leading to an infinite loop.
+     */
+    sigaction(sig, &act, &oldact);
     sigaction(sig, &oldact, NULL);
 }
 
@@ -1561,6 +1575,8 @@ device_script(program, in, out, dont_wait)
     close(2);
     if (the_channel->close)
        (*the_channel->close)();
+    else
+       close(devfd);   /* some plugins don't have a close function */
     closelog();
     close(fd_devnull);