From 4065511abb945c793187b23afc82590d7c966c84 Mon Sep 17 00:00:00 2001
From: Bob Lantz <rlantz@cs.stanford.edu>
Date: Thu, 11 Mar 2010 16:58:12 -0800
Subject: [PATCH] Detach shells from tty; monitoring changes.

Call netns using setsid to detach from the tty; this is
intended to fix the problem of control-C killing your network.

sendInt() doesn't actually work - hopefully we can fix this in the
future, but it's tricky since we want to detach the many shells from
our tty, but then optionally send tty interrupts to them! Ideally we
would either know the pid of the subprocess or be able to send a signal
to bash to get it to interrupt its subprocess.

waitOutput() now uses monitor. We also handle sentinels
coming in the middle of output (but default at end should
still work well.)
---
 mininet/node.py | 35 ++++++++++++++++-------------------
 1 file changed, 16 insertions(+), 19 deletions(-)

diff --git a/mininet/node.py b/mininet/node.py
index 718d04da..8dd13f71 100644
--- a/mininet/node.py
+++ b/mininet/node.py
@@ -66,8 +66,9 @@ def __init__( self, name, inNamespace=True,
            defaultIP: default IP address for intf 0"""
         self.name = name
         closeFds = False # speed vs. memory use
+        # setsid is necessary to detach from tty
         # xpg_echo is needed so we can echo our sentinel in sendCmd
-        cmd = [ '/bin/bash', '-O', 'xpg_echo' ]
+        cmd = [ '/usr/bin/setsid', '/bin/bash', '-O', 'xpg_echo' ]
         self.inNamespace = inNamespace
         if self.inNamespace:
             cmd = [ 'netns' ] + cmd
@@ -143,20 +144,22 @@ def sendCmd( self, cmd ):
         self.write( cmd + separator + ' echo -n "\\0177" \n' )
         self.waiting = True
 
+    def sendInt( self ):
+        """Placeholder for function to interrupt running subprocess.
+           This is a tricky problem to solve."""
+        self.write( chr( 3 ) )
+
     def monitor( self ):
         "Monitor the output of a command, returning (done?, data)."
         assert self.waiting
         self.waitReadable()
         data = self.read( 1024 )
-        if len( data ) > 0 and data[ -1 ] == chr( 0177 ):
+        if len( data ) > 0 and data[ -1 ] == chr( 127 ):
             self.waiting = False
             return True, data[ :-1 ]
-        else:
-            return False, data
-
-    def sendInt( self ):
-        "Send ^C, hopefully interrupting an interactive subprocess."
-        self.write( chr( 3 ) )
+        elif chr( 127 ) in data:
+            return True, data.replace( chr( 127 ), '' )
+        return False, data
 
     def waitOutput( self, verbose=False ):
         """Wait for a command to complete.
@@ -165,18 +168,12 @@ def waitOutput( self, verbose=False ):
            the output, including trailing newline.
            verbose: print output interactively"""
         log = info if verbose else debug
-        assert self.waiting
         output = ''
-        while True:
-            self.waitReadable()
-            data = self.read( 1024 )
-            if len( data ) > 0  and data[ -1 ] == chr( 0177 ):
-                output += data[ :-1 ]
-                log( output )
-                break
-            else:
-                output += data
-        self.waiting = False
+        done = False
+        while not done:
+            done, data = self.monitor()
+            output += data
+            log( data )
         return output
 
     def cmd( self, cmd, verbose=False ):
-- 
GitLab