changeset 1300:04d754570e50 draft

Make telnetd use generic_signal(), inline kill_session(), close race window where a SIGCHLD could get lost.
author Rob Landley <rob@landley.net>
date Wed, 21 May 2014 07:41:27 -0500
parents 313980d3d78c
children 1c25b5119072
files toys/pending/telnetd.c
diffstat 1 files changed, 31 insertions(+), 36 deletions(-) [+]
line wrap: on
line diff
--- a/toys/pending/telnetd.c	Wed May 21 07:24:16 2014 -0500
+++ b/toys/pending/telnetd.c	Wed May 21 07:41:27 2014 -0500
@@ -33,7 +33,6 @@
     long w_sec;
 
     int gmax_fd;
-    int sig;
     pid_t fork_pid;
 )
 
@@ -110,7 +109,7 @@
   else ((struct sockaddr_in6*)buf)->sin6_port = port_num;
 }
 
-static void utmp_entry(void)                                                                                                                                 
+static void utmp_entry(void)
 {               
   struct utmp entry;
   struct utmp *utp_ptr;
@@ -302,36 +301,6 @@
   return ret;
 }
 
-static void kill_session(void)
-{
-  int status;
-  struct term_session *tm, *prev = NULL;
-  pid_t pid = wait(&status);
-  TT.sig = 0; //ASAP
-
-  tm = session_list;
-  if (toys.optflags & FLAG_i) exit(EXIT_SUCCESS);
-
-  if (pid < 0) return;
-  while (tm) {
-    if (tm->child_pid == pid) break;
-    prev = tm;
-    tm = tm->next;
-  }
-  if (!tm) return; //paranoia
-  if (!prev) session_list = session_list->next;
-  else prev->next = tm->next;
-  utmp_entry();
-  xclose(tm->pty_fd);
-  xclose(tm->new_fd);
-  free(tm);
-}
-
-static void session_handler(int sig) 
-{
-  TT.sig = sig;
-}
-
 void telnetd_main(void)
 {
   errno = 0;
@@ -339,9 +308,8 @@
   struct term_session *tm = NULL;
   struct timeval tv, *tv_ptr = NULL;
   int pty_fd, new_fd, c = 0, w, master_fd = 0;
-  int inetd_m = (toys.optflags & FLAG_i);
+  int inetd_m = toys.optflags & FLAG_i;
 
-  TT.sig = 0;
   if (!(toys.optflags & FLAG_l)) TT.login_path = "/bin/login";
   if (!(toys.optflags & FLAG_f)) TT.issue_path = "/etc/issue.net";
   if (toys.optflags & FLAG_w) toys.optflags |= FLAG_F;
@@ -368,7 +336,7 @@
     tv.tv_usec = 0;
     tv_ptr = &tv;
   }                
-  signal(SIGCHLD, session_handler);
+  signal(SIGCHLD, generic_signal);
 
   for (;;) {
     FD_ZERO(&rd);
@@ -446,6 +414,33 @@
         tm->buff2_written = tm->buff2_avail = 0;
       fflush(NULL);
     }
-    if (TT.sig) kill_session();
+
+    // Loop to handle (unknown number of) SIGCHLD notifications
+    while (toys.signal) {
+      int status;
+      struct term_session *prev = NULL;
+      pid_t pid;
+
+      // funny little dance to avoid race conditions.
+      toys.signal = 0;
+      pid = waitpid(-1, &status, WNOHANG);
+      if (pid < 0) break;
+      toys.signal++;
+
+
+      for (tm = session_list; tm; tm = tm->next) {
+        if (tm->child_pid == pid) break;
+        prev = tm;
+      }
+      if (!tm) return; // reparented child we don't care about
+
+      if (toys.optflags & FLAG_i) exit(EXIT_SUCCESS);
+      if (!prev) session_list = session_list->next;
+      else prev->next = tm->next;
+      utmp_entry();
+      xclose(tm->pty_fd);
+      xclose(tm->new_fd);
+      free(tm);
+    }
   }
 }