Exemple #1
0
 def get_outconfig(self, pipe, session, outConfName, proc):
     try:
         # Read from the named pipe we passed to launch_plugin and 
         # write to file
         edfexecution.write_outconfig(outConfName, pipe)
     except KeyboardInterrupt:
         self.io.print_error("Canceled by User")
         self.io.print_error("Stopping plugin")
         try:
             proc.kill()
         except:
             pass
     finally:
         # XXX - Remove_pipe too?
         edfexecution.close_pipe(pipe)
     try:
         #name   = self.getName()
         params = self.read_outxml(outConfName)
         params.append(util.oParam("Status", "Success", "String", "Scalar"))
         if len(params) > 1:
             session.mark_ready()
         else:
             session.mark_used()
     except (ValueError, TrchError, AttributeError) as e:
         # We get here if the following conditions happen:
         #  Argument errors to any calls
         #  Plug-in failed and didn't actually write an outconfig
         #  Output created an invalid XML configuration
         #self.io.print_warning("Output XML error: It's either empty or does not parse: %s" % (e))
         self.io.print_warning("Plugin failed")
         proc.wait()
         params = [util.oParam("Status", "Failed", "String", "Scalar"),
                   util.oParam("ReturnCode", str(proc.returncode), "String", "Scalar")]
         session.mark_fail()
     session.contract = params
Exemple #2
0
    def getParameterListExt(self):
        item = oParam(self.getName(), self.getValue(), self.getType(), 'Scalar')
        plist = [item]
        if self.hasValidValue():
            plist.extend(self.groupList[self.getValue().lower()].getParameterListExt())

        return plist
    def execute(self,
                session,
                consolemode,
                interactive,
                scripted,
                globalvars={},
                runMode=''):
        self.lastsession = session
        baseDir, logDir = session.get_dirs()
        waitmode, newconsole = self.get_runflags(consolemode, interactive,
                                                 scripted)

        # save history
        session.history = self.getParameters()

        timestamp = util.formattime()
        exeBaseName = os.path.basename(self.executable)

        logName = "%s-%s.log" % (exeBaseName, timestamp)
        logFile = os.path.join(logDir, logName)
        try:
            os.remove(logFile)
        except:
            pass

        # Touch the logfile
        tmpFile = open(logFile, "w")
        tmpFile.close()

        # Create InConfig and write to the logdir
        inConfName = "%s-%s-InConfig.xml" % (exeBaseName, timestamp)
        inConfFile = os.path.join(logDir, inConfName)
        self.write_interpreted_xml_file(inConfFile, globalvars=globalvars)

        # Create the pipe that we will use for the --OutConfig parameter
        pipeName = edfexecution.generate_pipename()
        pipe = edfexecution.create_pipe(pipeName)

        cwd = os.getcwd()
        os.chdir(logDir)
        try:
            #
            # This is the sneaky bit for the output.  We call launch_plugin,
            # which does two things.  First, it passes stdin,stdout, and stderr
            # to the call to subprocess.Popen so that output is duplicated to
            # the console.  Second, it passes --OutConfig a pipe so that, when we
            # later call write_outconfig, this contains only the data we want
            #
            proc = edfexecution.launch_plugin(self.executable, inConfFile,
                                              pipeName, logFile, self.io,
                                              newconsole)
            self.procs.append(proc)
        except KeyboardInterrupt:
            self.io.print_error("Stopping plugin")
            try:
                self.procs.remove(proc)
                proc.kill()
            except:
                pass
            # Create the output param for the contract
            session.contract = [
                util.oParam("Status", "Failed", "String", "Scalar"),
                util.oParam("ReturnCode", "User Abort", "String", "Scalar")
            ]
            session.mark_fail()
            raise exception.CmdErr, "Canceled by User"

        os.chdir(cwd)

        try:
            # Wait for the spawned process to connect to our named pipe
            pipe = edfexecution.connect_pipe(pipe, pipeName)
        except edfexecution.PipeError, err:
            self.io.print_error(str(err))
            pipe = None
class EDFPlugin(Plugin):
    def __init__(self, files, io):
        try:
            Plugin.__init__(self, files, io)
            self.metaconfig = files[2]
            self.initTouches()
            self.initRedirection()
            self.initConsoleMode()
        except TrchError:
            # There was an error parsing the plug-in XML
            raise
        except IndexError:
            # We didn't get the right number of files
            raise
        self.procs = []

    def getMetaHash(self):
        return "%s %s %s" % (hashlib.sha1(open(
            self.metaconfig,
            'rb').read()).hexdigest(), os.lstat(
                self.metaconfig).st_size, os.path.basename(self.metaconfig))

    def killPlugin(self):
        """Helper function for forceful termination of the plugin executable,
        primarily used for testing
        """
        for p in self.procs:
            p.kill()
        self.procs = []

    def write_interpreted_xml_file(self, inConfFile, globalvars={}):
        """Rewrite the inconfig, substituting variables"""
        tmpFile = open(inConfFile, "w")

        # Note: Truantchild has been used to this point to store parameters, so
        # the inconfig here represents all of the prompted data
        configdata = self.getMarshalledInConfig()
        configlines = configdata.split("\n")
        newlines = []
        for line in configlines:
            newlines.append(util.variable_replace(line, globalvars))
        newconfig = "\n".join(newlines)
        tmpFile.write(newconfig)
        tmpFile.close()
        return inConfFile

    """
    Plugin validation routine

    """

    def validate(self, dirs, globalvars={}):
        baseDir, logDir = dirs
        timestamp = util.formattime()
        exeBaseName = os.path.basename(self.executable)

        logName = "%s-%s.log" % (exeBaseName, timestamp)
        logFile = os.path.join(logDir, logName)
        try:
            os.remove(logFile)
        except:
            pass

        inConfName = "%s-%s-InConfig.validate.xml" % (exeBaseName, timestamp)
        inConfFile = os.path.join(logDir, inConfName)
        self.write_interpreted_xml_file(inConfFile, globalvars=globalvars)

        if edfexecution.validate_plugin(self.executable, inConfFile,
                                        self.io) == 0:
            return True
        else:
            return False

    """
    Plugin execution routine

    """

    def execute(self,
                session,
                consolemode,
                interactive,
                scripted,
                globalvars={},
                runMode=''):
        self.lastsession = session
        baseDir, logDir = session.get_dirs()
        waitmode, newconsole = self.get_runflags(consolemode, interactive,
                                                 scripted)

        # save history
        session.history = self.getParameters()

        timestamp = util.formattime()
        exeBaseName = os.path.basename(self.executable)

        logName = "%s-%s.log" % (exeBaseName, timestamp)
        logFile = os.path.join(logDir, logName)
        try:
            os.remove(logFile)
        except:
            pass

        # Touch the logfile
        tmpFile = open(logFile, "w")
        tmpFile.close()

        # Create InConfig and write to the logdir
        inConfName = "%s-%s-InConfig.xml" % (exeBaseName, timestamp)
        inConfFile = os.path.join(logDir, inConfName)
        self.write_interpreted_xml_file(inConfFile, globalvars=globalvars)

        # Create the pipe that we will use for the --OutConfig parameter
        pipeName = edfexecution.generate_pipename()
        pipe = edfexecution.create_pipe(pipeName)

        cwd = os.getcwd()
        os.chdir(logDir)
        try:
            #
            # This is the sneaky bit for the output.  We call launch_plugin,
            # which does two things.  First, it passes stdin,stdout, and stderr
            # to the call to subprocess.Popen so that output is duplicated to
            # the console.  Second, it passes --OutConfig a pipe so that, when we
            # later call write_outconfig, this contains only the data we want
            #
            proc = edfexecution.launch_plugin(self.executable, inConfFile,
                                              pipeName, logFile, self.io,
                                              newconsole)
            self.procs.append(proc)
        except KeyboardInterrupt:
            self.io.print_error("Stopping plugin")
            try:
                self.procs.remove(proc)
                proc.kill()
            except:
                pass
            # Create the output param for the contract
            session.contract = [
                util.oParam("Status", "Failed", "String", "Scalar"),
                util.oParam("ReturnCode", "User Abort", "String", "Scalar")
            ]
            session.mark_fail()
            raise exception.CmdErr, "Canceled by User"

        os.chdir(cwd)

        try:
            # Wait for the spawned process to connect to our named pipe
            pipe = edfexecution.connect_pipe(pipe, pipeName)
        except edfexecution.PipeError, err:
            self.io.print_error(str(err))
            pipe = None

        if pipe == None:
            try:
                # Try to kill the process
                self.procs.remove(proc)
                proc.kill()
            except:
                pass
            try:
                # See if the process has terminated
                proc.poll()
            except:
                pass
            # Create the output param for the contract
            session.contract = [
                util.oParam("Status", "Failed", "String", "Scalar"),
                util.oParam("ReturnCode", str(proc.returncode), "String",
                            "Scalar")
            ]
            session.mark_fail()
            raise exception.CmdErr, "Error Connecting Pipe to Plugin"

        # Create OutConfig file name
        outConfName = "%s-%s-OutConfig.xml" % (exeBaseName, timestamp)
        outConfFile = os.path.join(logDir, outConfName)

        if waitmode:
            # Wait for the plugin to finish.  So, we don't have overlapping
            # output or problems waiting for the outconfig
            self.get_outconfig(pipe, session, outConfFile, proc)
        else:
            # Creates a new thread to read output config from the executed plugin.
            pluginThread = threading.Thread(None, self.get_outconfig, None,
                                            (pipe, session, outConfFile, proc))
            pluginThread.start()
        return newconsole, logFile
Exemple #5
0
 def getParameterListExt(self):
     #if not self.isHidden():
     return [
         oParam(self.getName(), self.getValue(), self.getType(),
                self.getFormat())
     ]
    def execute(self,
                session,
                consolemode,
                interactive,
                scripted,
                globalvars={},
                runMode='',
                archOs='x86-Windows',
                listenPort=0):
        self.lastsession = session
        baseDir, logDir = session.get_dirs()
        waitmode, newconsole = self.get_runflags(consolemode, interactive,
                                                 scripted)
        timestamp = util.formattime()

        # Save history
        session.history = self.getParameters()

        # Prompt for run mode
        if runMode in ("DANE", "DAVE"):

            # TODO: prompt operator to verify remote callback tunnel exists for localhost comms

            if runMode == "DANE":
                # Build package
                packagePath = self.build_package(logDir,
                                                 archOs,
                                                 listenPort,
                                                 globalvars=globalvars)

                # Print package info
                self.io.print_success("DANE Package: %s" % packagePath)
            # elif runMode == "DAVE":
            # # Marshal params (and get core module name)
            # modulePath, inputPath = self.marshal_params(logDir, archOs, globalvars=globalvars)

            # # Build up DAVE commandline
            # dvcmds = 'daringveteran -module "%s" -input "%s" -run %s' % (
            # modulePath,
            # inputPath,
            # 'interactive' if (listenPort) else 'batch')
            # if listenPort:
            # dvcmds += " -homeport %d" % listenPort

            # # Print core module and marshaled data info
            # self.io.print_success('DAVE Pastable:\n\t' + dvcmds)
            else:
                raise NotImplementedError(
                    "No such option '%s'; what happened??" % (runMode))

            # Set "DaveProxyPort" hidden parameter in current config
            if listenPort:
                #self.set("DaveProxyPort", str(listenPort))
                self.io.print_msg("Proxy listening on localhost:%d" %
                                  listenPort)
            else:
                # Bail right now--gracefully...
                return newconsole, None
        elif runMode == 'FB':
            # Make sure the proxy port is zeroed
            self.set("DaveProxyPort", "0")
        else:
            raise NotImplementedError("No such option '%s'; what happened??" %
                                      (runMode))

        exeBaseName = os.path.basename(self.executable)

        logName = "%s-%s.log" % (exeBaseName, timestamp)
        logFile = os.path.join(logDir, logName)
        try:
            os.remove(logFile)
        except:
            pass

        # Touch the logfile
        tmpFile = open(logFile, "w")
        tmpFile.close()

        # Create InConfig and write to the logdir
        inConfName = "%s-%s-InConfig.xml" % (exeBaseName, timestamp)
        inConfFile = os.path.join(logDir, inConfName)
        self.write_interpreted_xml_file(inConfFile, globalvars=globalvars)

        # Create the pipe that we will use for the --OutConfig parameter
        pipeName = edfexecution.generate_pipename()
        pipe = edfexecution.create_pipe(pipeName)

        cwd = os.getcwd()
        os.chdir(logDir)
        try:
            #
            # This is the sneaky bit for the output.  We call launch_plugin,
            # which does two things.  First, it passes stdin,stdout, and stderr
            # to the call to subprocess.Popen so that output is duplicated to
            # the console.  Second, it passes --OutConfig a pipe so that, when we
            # later call write_outconfig, this contains only the data we want
            #
            proc = edfexecution.launch_plugin(self.executable, inConfFile,
                                              pipeName, logFile, self.io,
                                              newconsole)
            self.procs.append(proc)
        except KeyboardInterrupt:
            self.io.print_error("Stopping plugin")
            try:
                self.procs.remove(proc)
                proc.kill()
            except:
                pass
            # Create the output param for the contract
            session.contract = [
                util.oParam("Status", "Failed", "String", "Scalar"),
                util.oParam("ReturnCode", "User Abort", "String", "Scalar")
            ]
            session.mark_fail()
            raise exception.CmdErr, "Canceled by User"

        os.chdir(cwd)

        try:
            # Wait for the spawned process to connect to our named pipe
            pipe = edfexecution.connect_pipe(pipe, pipeName)
        except edfexecution.PipeError, err:
            self.io.print_error(str(err))
            pipe = None
class DAVEPlugin(EDFPlugin):
    def __init__(self, files, io):
        # DAVE plugins are *currently* supported only on Win32 (that's a
        # restriction based on delivery mechanisms, not the DAVE spec itself)
        import sys
        if sys.platform != "win32":
            raise EnvironmentError(
                "DAVEPlugins are supported only on Windows for this version of Fuzzbunch!"
            )

        try:
            EDFPlugin.__init__(self, files, io)
            self.metaconfig = files[2]
            self.initTouches()
            self.initConsoleMode()
            self.initRedirection()
        except TrchError:
            # There was an error parsing the plug-in XML
            raise
        except IndexError:
            # We didn't get the right number of files
            raise
        self.procs = []
        self.package_arches = edfmeta.parse_forward(self.metaconfig)
        if not self.package_arches:
            raise EnvironmentError(
                "A DAVEPlugin is missing required 'package' information in its .fb file!"
            )

    def getMetaHash(self):
        return "%s %s %s" % (hashlib.sha1(open(
            self.metaconfig,
            'rb').read()).hexdigest(), os.lstat(
                self.metaconfig).st_size, os.path.basename(self.metaconfig))

    def canDeploy(self):
        return True

    def killPlugin(self):
        """Helper function for forceful termination of the plugin executable,
        primarily used for testing
        """
        for p in self.procs:
            p.kill()
        self.procs = []

    def write_interpreted_xml_file(self, inConfFile, globalvars={}):
        """Rewrite the inconfig, substituting variables"""
        tmpFile = open(inConfFile, "w")

        # Note: Truantchild has been used to this point to store parameters, so
        # the inconfig here represents all of the prompted data
        configdata = self.getMarshalledInConfig()
        configlines = configdata.split("\n")
        newlines = []
        for line in configlines:
            newlines.append(util.variable_replace(line, globalvars))
        newconfig = "\n".join(newlines)
        tmpFile.write(newconfig)
        tmpFile.close()
        return inConfFile

    """
    Plugin validation routine

    """

    def validate(self, dirs, globalvars={}):
        baseDir, logDir = dirs
        timestamp = util.formattime()
        exeBaseName = os.path.basename(self.executable)

        logName = "%s-%s.log" % (exeBaseName, timestamp)
        logFile = os.path.join(logDir, logName)
        try:
            os.remove(logFile)
        except:
            pass

        inConfName = "%s-%s-InConfig.validate.xml" % (exeBaseName, timestamp)
        inConfFile = os.path.join(logDir, inConfName)
        self.write_interpreted_xml_file(inConfFile, globalvars=globalvars)

        if edfexecution.validate_plugin(self.executable, inConfFile,
                                        self.io) == 0:
            return True
        else:
            return False

    def marshal_params(self,
                       logDir,
                       archOs,
                       output_filename=None,
                       globalvars={}):
        import sys, subprocess, platform

        # Find/compute various paths and filename components we'll need later
        storageDir = globalvars['FbStorage']
        timestamp = util.formattime()
        exeBaseName = os.path.basename(self.executable)

        # Get our own packaging options (for reference)
        arch_map = self.package_arches

        # Figure out which piece to use for marshaling
        host_archOs = "%s-%s" % (platform.machine(), platform.system())
        proxy = arch_map[host_archOs][0]
        core = arch_map[archOs][1]

        # Non supported!
        if proxy is None:
            return (None, None)

        # Get files/paths set up for marshaling
        if output_filename is None:
            output_filename = os.path.join(
                logDir, "%s-%s-Marshal.bin" % (exeBaseName, timestamp))
        output_path = os.path.dirname(output_filename)
        try:
            os.makedirs(output_path)
        except os.error:
            assert os.path.isdir(
                output_path
            ), "Output path '%s' could not be found/created!" % output_path
        xml_config_name = os.path.join(
            logDir, "%s-%s-InConfig.marshal.xml" % (exeBaseName, timestamp))
        self.write_interpreted_xml_file(xml_config_name, globalvars=globalvars)

        # Fire off the DANE config utility to actually create the package.  Note that this is strictly
        # Win32[/64] for now...
        # (This stuff should be abtracted away form cross-platformness and to avoid hard-coded paths.)
        proxy_dll = os.path.join(os.path.dirname(self.executable), proxy)
        assert os.path.isfile(
            proxy_dll), "Required file '%s' doesn't exist!" % proxy_dll
        self.io.print_msg("\tUsing '%s' to handle parameter marshaling" %
                          proxy_dll)
        self.io.print_msg("\tMarshaling the contents of '%s'" %
                          xml_config_name)

        config_exe = os.path.join(storageDir, 'dvmarshal.exe')
        assert os.path.isfile(
            config_exe), "Required program '%s' doesn't exist!" % config_exe
        subprocess.check_call(
            [config_exe, proxy_dll, xml_config_name, output_filename])

        core_dll = os.path.join(os.path.dirname(self.executable), core)
        return (core_dll, output_filename)

    def build_package(self,
                      logDir,
                      archOs,
                      listenPort=None,
                      output_filename=None,
                      globalvars={}):
        import sys, subprocess, platform

        # Find/compute various paths and filename components we'll need later
        storageDir = globalvars['FbStorage']
        timestamp = util.formattime()
        exeBaseName = os.path.basename(self.executable)

        # Get our own packaging options (for reference)
        arch_map = self.package_arches

        # Figure out which architecture/OS to use for each piece
        host_archOs = "%s-%s" % (platform.machine(), platform.system())
        proxy = arch_map[host_archOs][0]
        core = arch_map[archOs][1]

        if (proxy is None) or (core is None):
            # Not supported!
            return None

        if output_filename is None:
            output_filename = os.path.join(
                logDir, "%s-%s-Package.dll" % (exeBaseName, timestamp))

        output_path = os.path.dirname(output_filename)
        try:
            os.makedirs(output_path)
        except os.error:
            assert os.path.isdir(
                output_path
            ), "Output path '%s' could not be found/created!" % output_path

        xml_config_name = os.path.join(
            logDir, "%s-%s-InConfig.package.xml" % (exeBaseName, timestamp))
        self.write_interpreted_xml_file(xml_config_name, globalvars=globalvars)

        # Fire off the DANE config utility to actually create the package.  Note that this is strictly
        # Win32[/64] for now...
        # (This stuff should be abtracted away for cross-platformness and to avoid hard-coded paths.)
        baseArch = archOs.split('-')[0]

        dane_dll = os.path.join(storageDir, 'dane_%s.dll' % baseArch)
        assert os.path.isfile(
            dane_dll), "Required file '%s' doesn't exist!" % dane_dll
        self.io.print_msg("\tUsing '%s' as the output template" % dane_dll)

        proxy_dll = os.path.join(os.path.dirname(self.executable), proxy)
        assert os.path.isfile(
            proxy_dll), "Required file '%s' doesn't exist!" % proxy_dll
        self.io.print_msg("\tUsing '%s' to handle parameter marshaling" %
                          proxy_dll)

        core_dll = os.path.join(os.path.dirname(self.executable), core)
        assert os.path.isfile(
            core_dll), "Required file '%s' doesn't exist!" % core_dll
        self.io.print_msg("\tUsing '%s' as the input payload" % core_dll)

        config_exe = os.path.join(storageDir, 'danecfg.exe')
        assert os.path.isfile(
            config_exe), "Required program '%s' doesn't exist!" % config_exe
        subprocess.check_call([
            config_exe, dane_dll, proxy_dll, core_dll, xml_config_name,
            output_filename
        ])

        if listenPort:
            # Pack in the listen-port as a particular binary resource
            import ctypes, struct
            RT_RCDATA = 10
            ID_PORTNUM = 101
            LANG_ID = 0x0000

            BeginUpdateResource = ctypes.windll.kernel32.BeginUpdateResourceA
            UpdateResource = ctypes.windll.kernel32.UpdateResourceA
            EndUpdateResource = ctypes.windll.kernel32.EndUpdateResourceA

            rblob = struct.pack("<H", listenPort)
            handle = BeginUpdateResource(output_filename, False)
            if handle is None:
                raise ctypes.WinError()
            if not UpdateResource(handle, RT_RCDATA, ID_PORTNUM, LANG_ID,
                                  rblob, len(rblob)):
                raise ctypes.WinError()
            if not EndUpdateResource(handle, False):
                raise ctypes.WinError()

        return output_filename

    """
    Plugin execution routine

    """

    def execute(self,
                session,
                consolemode,
                interactive,
                scripted,
                globalvars={},
                runMode='',
                archOs='x86-Windows',
                listenPort=0):
        self.lastsession = session
        baseDir, logDir = session.get_dirs()
        waitmode, newconsole = self.get_runflags(consolemode, interactive,
                                                 scripted)
        timestamp = util.formattime()

        # Save history
        session.history = self.getParameters()

        # Prompt for run mode
        if runMode in ("DANE", "DAVE"):

            # TODO: prompt operator to verify remote callback tunnel exists for localhost comms

            if runMode == "DANE":
                # Build package
                packagePath = self.build_package(logDir,
                                                 archOs,
                                                 listenPort,
                                                 globalvars=globalvars)

                # Print package info
                self.io.print_success("DANE Package: %s" % packagePath)
            # elif runMode == "DAVE":
            # # Marshal params (and get core module name)
            # modulePath, inputPath = self.marshal_params(logDir, archOs, globalvars=globalvars)

            # # Build up DAVE commandline
            # dvcmds = 'daringveteran -module "%s" -input "%s" -run %s' % (
            # modulePath,
            # inputPath,
            # 'interactive' if (listenPort) else 'batch')
            # if listenPort:
            # dvcmds += " -homeport %d" % listenPort

            # # Print core module and marshaled data info
            # self.io.print_success('DAVE Pastable:\n\t' + dvcmds)
            else:
                raise NotImplementedError(
                    "No such option '%s'; what happened??" % (runMode))

            # Set "DaveProxyPort" hidden parameter in current config
            if listenPort:
                #self.set("DaveProxyPort", str(listenPort))
                self.io.print_msg("Proxy listening on localhost:%d" %
                                  listenPort)
            else:
                # Bail right now--gracefully...
                return newconsole, None
        elif runMode == 'FB':
            # Make sure the proxy port is zeroed
            self.set("DaveProxyPort", "0")
        else:
            raise NotImplementedError("No such option '%s'; what happened??" %
                                      (runMode))

        exeBaseName = os.path.basename(self.executable)

        logName = "%s-%s.log" % (exeBaseName, timestamp)
        logFile = os.path.join(logDir, logName)
        try:
            os.remove(logFile)
        except:
            pass

        # Touch the logfile
        tmpFile = open(logFile, "w")
        tmpFile.close()

        # Create InConfig and write to the logdir
        inConfName = "%s-%s-InConfig.xml" % (exeBaseName, timestamp)
        inConfFile = os.path.join(logDir, inConfName)
        self.write_interpreted_xml_file(inConfFile, globalvars=globalvars)

        # Create the pipe that we will use for the --OutConfig parameter
        pipeName = edfexecution.generate_pipename()
        pipe = edfexecution.create_pipe(pipeName)

        cwd = os.getcwd()
        os.chdir(logDir)
        try:
            #
            # This is the sneaky bit for the output.  We call launch_plugin,
            # which does two things.  First, it passes stdin,stdout, and stderr
            # to the call to subprocess.Popen so that output is duplicated to
            # the console.  Second, it passes --OutConfig a pipe so that, when we
            # later call write_outconfig, this contains only the data we want
            #
            proc = edfexecution.launch_plugin(self.executable, inConfFile,
                                              pipeName, logFile, self.io,
                                              newconsole)
            self.procs.append(proc)
        except KeyboardInterrupt:
            self.io.print_error("Stopping plugin")
            try:
                self.procs.remove(proc)
                proc.kill()
            except:
                pass
            # Create the output param for the contract
            session.contract = [
                util.oParam("Status", "Failed", "String", "Scalar"),
                util.oParam("ReturnCode", "User Abort", "String", "Scalar")
            ]
            session.mark_fail()
            raise exception.CmdErr, "Canceled by User"

        os.chdir(cwd)

        try:
            # Wait for the spawned process to connect to our named pipe
            pipe = edfexecution.connect_pipe(pipe, pipeName)
        except edfexecution.PipeError, err:
            self.io.print_error(str(err))
            pipe = None

        if pipe == None:
            try:
                # Try to kill the process
                self.procs.remove(proc)
                proc.kill()
            except:
                pass
            try:
                # See if the process has terminated
                proc.poll()
            except:
                pass
            # Create the output param for the contract
            session.contract = [
                util.oParam("Status", "Failed", "String", "Scalar"),
                util.oParam("ReturnCode", str(proc.returncode), "String",
                            "Scalar")
            ]
            session.mark_fail()
            raise exception.CmdErr, "Error Connecting Pipe to Plugin"

        # Create OutConfig file name
        outConfName = "%s-%s-OutConfig.xml" % (exeBaseName, timestamp)
        outConfFile = os.path.join(logDir, outConfName)

        if waitmode:
            # Wait for the plugin to finish.  So, we don't have overlapping
            # output or problems waiting for the outconfig
            self.get_outconfig(pipe, session, outConfFile, proc)
        else:
            # Creates a new thread to read output config from the executed plugin.
            pluginThread = threading.Thread(None, self.get_outconfig, None,
                                            (pipe, session, outConfFile, proc))
            pluginThread.start()
        return newconsole, logFile