Added a terminal-creation capability.
authorlbatlle@npdl268.bpo.hp.com
Wed, 02 Jan 2008 15:15:11 +0100
changeset 82 5cbe47923060
parent 81 baf70c6a4116
child 83 76adae542b57
Added a terminal-creation capability.
app_control.c
app_term.c
dump.c
error.c
main.h
server.c
signals.c
user_term.c
--- a/app_control.c	Mon Oct 08 13:08:09 2007 +0200
+++ b/app_control.c	Wed Jan 02 15:15:11 2008 +0100
@@ -50,16 +50,16 @@
 
 void app_control_prepare_read_fdset(fd_set *read_set, int *maxfd)
 {
-    assert(app_stdout != -1 || app_stderr != -1);
-
     if (app_stdout != -1)
     {
+        debugmsg("Considering app_stdout %i", app_stdout);
         FD_SET(app_stdout, read_set);
         *maxfd = max(*maxfd, app_stdout);
     }
 
     if (app_stderr != -1 && app_stdout != app_stderr)
     {
+        debugmsg("Considering app_stderr %i", app_stderr);
         FD_SET(app_stderr, read_set);
         *maxfd = max(*maxfd, app_stderr);
     }
@@ -71,6 +71,7 @@
     if (app_stdout != -1 && FD_ISSET(app_stdout, read_set))
     {
         int res;
+        debugmsg("Read app_stdout %i", app_stdout);
         res = read(app_stdout, stream_buffer, stream_buffer_size);
         if (res == -1 && errno == EIO)
         {
@@ -83,12 +84,16 @@
             error("Error reading from app.");
         if (res == 0)
         {
+            debugmsg("Closing app_stdout %i", app_stdout);
             close(app_stdout);
             if (!command_line.s_param.nohup)
                 close(1);
+            app_stdout = -1;
             if (app_stdout == app_stderr || app_stderr == -1)
+            {
+                app_stderr = -1;
                 return -1;
-            app_stdout = -1;
+            }
         } else
         {
             hex_dump("from app", stream_buffer, res);
@@ -108,9 +113,11 @@
             FD_ISSET(app_stderr, read_set))
     {
         int res;
+        debugmsg("Read app_stderr %i", app_stdout);
         res = read(app_stderr, stream_buffer, stream_buffer_size);
         if (res == 0)
         {
+            debugmsg("Closing app_stderr %i", app_stderr);
             close(app_stderr);
             close(2); /* MOVE */
             app_stderr = -1;
@@ -137,7 +144,13 @@
 void app_control_local_send_to_stdin(const char *buffer, size_t size)
 {
     if (size == 0)
+    {
         close(app_stdin);
+        if (app_stdout == app_stdin)
+          app_stdout = -1;
+        if (app_stderr == app_stdin)
+          app_stderr = -1;
+    }
     else
     {
         hex_dump("from local to app", buffer, size);
@@ -177,7 +190,13 @@
         }
 
         if (size == 0 && command_line.s_param.client_may_close_app_stdin)
+        {
             close(app_stdin);
+            if (app_stdout == app_stdin)
+              app_stdout = -1;
+            if (app_stderr == app_stdin)
+              app_stderr = -1;
+        }
     }
 }
 
--- a/app_term.c	Mon Oct 08 13:08:09 2007 +0200
+++ b/app_term.c	Wed Jan 02 15:15:11 2008 +0100
@@ -46,6 +46,37 @@
         ioctl(app_stdin, TIOCSWINSZ, (char *) &app_winsize);
 }
 
+void get_term_options(struct termios *tios, struct winsize *wsize)
+{
+    int res;
+
+    /* Try to get the config from the actual terminal's stdout */
+    res = tcgetattr(1, tios);
+    if (res == -1)
+    {
+      /* Create the termios structure from scratch */
+      memset(tios, 0, sizeof(*tios));
+      cfmakeraw(tios);
+    }
+
+    /* if starting using shells' &, it doesn't get ECHO set.
+     * Let's force it. */
+    tios->c_lflag |= ECHO | ECHOE | ECHOK | ECHONL;
+    /* Try to emulate something compatible with xterm */
+    tios->c_oflag |= OPOST | ONLCR;
+    tios->c_lflag |= ISIG | ICANON | ECHOCTL | ECHOKE;
+    tios->c_iflag |= BRKINT | IGNPAR | IMAXBEL;
+
+    /* Get the original term's winsize */
+    res = ioctl(1, TIOCGWINSZ, wsize);
+    if (res == -1)
+    {
+      /* If we don't have original term, create an arbitrary winsize */
+      wsize->ws_row = 25;
+      wsize->ws_col = 80;
+    }
+}
+
 static void give_terminal(int parent[], int child[])
 {
     struct termios tios;
@@ -53,17 +84,7 @@
     int res;
     int master, slave;
 
-    res = tcgetattr(1, &tios);
-    if (res == -1)
-        error("tcgetatttr");
-
-    /* if starting using shells' &, it doesn't get ECHO set.
-     * Let's force it. */
-    tios.c_lflag |= ECHO | ECHOE | ECHOK | ECHONL;
-
-    res = ioctl(1, TIOCGWINSZ, &wsize);
-    if (res == -1)
-        error("ioctl TIOCGWINSZ");
+    get_term_options(&tios, &wsize);
 
     app_winsize = wsize;
 
--- a/dump.c	Mon Oct 08 13:08:09 2007 +0200
+++ b/dump.c	Wed Jan 02 15:15:11 2008 +0100
@@ -5,6 +5,7 @@
     Please find the license in the provided COPYING file.
 */
 #include <stdio.h>
+#include <sys/select.h>
 #include <stdarg.h>
 
 #include "main.h"
@@ -51,3 +52,14 @@
     fprintf(f, "\"\n");
     fclose(f);
 }
+
+void fdset_dump(fd_set *set, int maxfd)
+{
+  int i;
+
+  fprintf(stderr, "fdset:");
+  for (i=0; i <= maxfd; ++i)
+    if (FD_ISSET(i, set))
+      fprintf(stderr, " %i", i);
+  fprintf(stderr, "\n");
+}
--- a/error.c	Mon Oct 08 13:08:09 2007 +0200
+++ b/error.c	Wed Jan 02 15:15:11 2008 +0100
@@ -23,6 +23,27 @@
     finish(-1);
 }
 
+void warning(const char *msg, ...)
+{
+    va_list v;
+
+    va_start(v, msg);
+    vfprintf(stderr, msg, v);
+    putc('\n', stderr);
+}
+
+void debugmsg(const char *msg, ...)
+{
+    va_list v;
+
+    va_start(v, msg);
+    if (0)
+    {
+        vfprintf(stderr, msg, v);
+        putc('\n', stderr);
+    }
+}
+
 void not_implemented(const char *msg, ...)
 {
     va_list v;
--- a/main.h	Mon Oct 08 13:08:09 2007 +0200
+++ b/main.h	Wed Jan 02 15:15:11 2008 +0100
@@ -37,6 +37,8 @@
 /* error.c */
 void not_implemented(const char *msg, ...);
 void error(const char *msg, ...);
+void warning(const char *msg, ...);
+void debugmsg(const char *msg, ...);
 void finish(int ret);
 
 /* signals.c */
--- a/server.c	Mon Oct 08 13:08:09 2007 +0200
+++ b/server.c	Wed Jan 02 15:15:11 2008 +0100
@@ -16,6 +16,12 @@
 #include "main.h"
 #include "handlers.h"
 
+/* signals.c */
+extern int child_died;
+
+/*extern*/
+void fdset_dump(fd_set *set, int maxfd);
+
 static void loop()
 {
     fd_set read_set;
@@ -37,9 +43,12 @@
     {
         FD_ZERO(&read_set);
 
+        maxfd = -1;
         if (stdin_opened)
+        {
             FD_SET(0, &read_set);
-        maxfd = 0;
+            maxfd = 0;
+        }
 
         app_control_prepare_read_fdset(&read_set, &maxfd);
         if (command_line.s_param.serve_unix)
@@ -61,6 +70,13 @@
             eth_proto_process_timeouts();
 #endif
 
+        if (maxfd == -1)
+          error("No fds in select");
+
+        debugmsg("Blocking in pselect");
+        if (child_died == 1)
+          break;
+
         /* Will block */
         res = pselect(maxfd + 1, &read_set, 0, 0, 0, &sigold);
 #ifdef linux
@@ -85,7 +101,10 @@
             /* if res is 0, the fcall will close app_stdin */
             app_control_local_send_to_stdin(stream_buffer, res);
             if (res == 0)
+            {
+                debugmsg("Closing stdin\n");
                 stdin_opened = 0;
+            }
         }
 
         if (command_line.s_param.serve_unix)
--- a/signals.c	Mon Oct 08 13:08:09 2007 +0200
+++ b/signals.c	Wed Jan 02 15:15:11 2008 +0100
@@ -8,11 +8,14 @@
 #include <string.h>
 #include <unistd.h>
 #include <sys/types.h>
+#include <sys/wait.h>
+#include <assert.h>
 
 #include "main.h"
 #include "handlers.h"
 
 static int child;
+int child_died;
 static char old_alarm_handler_set;
 static struct sigaction old_alarm_handler;
 
@@ -23,6 +26,23 @@
     kill(child, val);
 }
 
+static void sig_child_died(int val)
+{
+    int status; 
+    int res;
+
+    assert(child_died == 0);
+
+    res = wait(&status);
+
+    if (WIFEXITED(status) || WIFSIGNALED(status))
+    {
+        debugmsg("Child exited");
+        child_died = 1;
+    }
+    debugmsg("Child handler");
+}
+
 static void update_window_size(int val)
 {
     char *xterm_str;
@@ -60,6 +80,10 @@
 
     act.sa_handler = update_window_size;
     sigaction(SIGWINCH, &act, 0);
+
+    act.sa_handler = sig_child_died;
+    act.sa_flags = SA_NOCLDSTOP;
+    sigaction(SIGCHLD, &act, 0);
 }
 
 static void alarm_handler(int x)
--- a/user_term.c	Mon Oct 08 13:08:09 2007 +0200
+++ b/user_term.c	Wed Jan 02 15:15:11 2008 +0100
@@ -26,7 +26,10 @@
 
     res = tcgetattr(1, &tios);
     if (res == -1)
-        error("tcgetatttr");
+    {
+        debugmsg("tcgetattr(1) failed - not a terminal");
+        return;
+    }
 
     memcpy(&saved_tios, &tios, sizeof(struct termios));
     is_tios_saved = 1;
@@ -34,22 +37,17 @@
     cfmakeraw(&tios);
     tios.c_lflag &= ~ECHO;
 
-    res = tcsetattr(0, TCSANOW, &tios);
+    res = tcsetattr(1, TCSANOW, &tios);
     if (res == -1)
-        error("tcsetatttr");
+        debugmsg("tcsetattr(1) failed - not a terminal");
 }
 
 void restore_user_terminal()
 {
     int res;
-    res = tcsetattr(0, TCSANOW, &saved_tios);
+    res = tcsetattr(1, TCSANOW, &saved_tios);
     if (res == -1)
-    {
-        /* cannot call error(), because it calls finish(), then
-         * restore_user_terminal() */
-        fprintf(stderr,"tcsetatttr failed: %s", strerror(errno));
-        exit(-1);
-    }
+        debugmsg("tcsetatttr failed: %s", strerror(errno));
 }
 
 void finish(int ret)