Start a shell process for running commands
( self, mnopts=None )
| 139 | |
| 140 | # Command support via shell process in namespace |
| 141 | def startShell( self, mnopts=None ): |
| 142 | "Start a shell process for running commands" |
| 143 | if self.shell: |
| 144 | error( "%s: shell is already running\n" % self.name ) |
| 145 | return |
| 146 | # mnexec: (c)lose descriptors, (d)etach from tty, |
| 147 | # (p)rint pid, and run in (n)amespace |
| 148 | opts = '-cd' if mnopts is None else mnopts |
| 149 | if self.inNamespace: |
| 150 | opts += 'n' |
| 151 | # bash -i: force interactive |
| 152 | # -s: pass $* to shell, and make process easy to find in ps |
| 153 | # prompt is set to sentinel chr( 127 ) |
| 154 | cmd = [ 'mnexec', opts, 'env', 'PS1=' + chr( 127 ), |
| 155 | 'bash', '--norc', '--noediting', |
| 156 | '-is', 'mininet:' + self.name ] |
| 157 | |
| 158 | # Spawn a shell subprocess in a pseudo-tty, to disable buffering |
| 159 | # in the subprocess and insulate it from signals (e.g. SIGINT) |
| 160 | # received by the parent |
| 161 | self.master, self.slave = pty.openpty() |
| 162 | self.shell = self._popen( cmd, stdin=self.slave, stdout=self.slave, |
| 163 | stderr=self.slave, close_fds=False ) |
| 164 | # XXX BL: This doesn't seem right, and we should also probably |
| 165 | # close our files when we exit... |
| 166 | self.stdin = os.fdopen( self.master, 'r' ) |
| 167 | self.stdout = self.stdin |
| 168 | self.pid = self.shell.pid |
| 169 | self.pollOut = select.poll() |
| 170 | self.pollOut.register( self.stdout ) |
| 171 | # Maintain mapping between file descriptors and nodes |
| 172 | # This is useful for monitoring multiple nodes |
| 173 | # using select.poll() |
| 174 | self.outToNode[ self.stdout.fileno() ] = self |
| 175 | self.inToNode[ self.stdin.fileno() ] = self |
| 176 | self.execed = False |
| 177 | self.lastCmd = None |
| 178 | self.lastPid = None |
| 179 | self.readbuf = '' |
| 180 | # Wait for prompt |
| 181 | while True: |
| 182 | data = self.read( 1024 ) |
| 183 | if data[ -1 ] == chr( 127 ): |
| 184 | break |
| 185 | self.pollOut.poll() |
| 186 | self.waiting = False |
| 187 | # +m: disable job control notification |
| 188 | self.cmd( 'unset HISTFILE; stty -echo; set +m' ) |
| 189 | |
| 190 | def mountPrivateDirs( self ): |
| 191 | "mount private directories" |