Пример #1
0
void MainFrame::OnQueryCompletion(wxCommandEvent& WXUNUSED(event))
{
    m_busy = false;
    m_queryThread->m_flags = 0;
    m_queryThread->singlefile = FALSE;
    wxUnsetEnv(L"UD_CUT_FILTER");    
}
Пример #2
0
bool nsEnvVars::EnvvarDiscard(const wxString &key)
{
#if defined(TRACE_ENVVARS)
  Manager::Get()->GetLogManager()->DebugLog(F(_T("EnvvarDiscard")));
#endif

  // Replace all macros the user might have setup for the key
  wxString the_key = key;
  Manager::Get()->GetMacrosManager()->ReplaceMacros(the_key);
  if (the_key.Trim().IsEmpty()) return false;
  if (!wxGetEnv(the_key, NULL)) return false; // envvar was not set - nothing to do.

  std::map<wxString,wxString>::iterator it = nsEnvVars::EnvVarsStack.find(the_key);
  if (it!=nsEnvVars::EnvVarsStack.end()) // found an old envvar on the stack
    return nsEnvVars::EnvvarApply(the_key, it->second); // restore old value

  if (!wxUnsetEnv(the_key))
  {
    Manager::Get()->GetLogManager()->Log(F(
      _("Unsetting environment variable '%s' failed."), the_key.wx_str())
    );
    EV_DBGLOG(_T("EnvVars: Unsetting environment variable '%s' failed."), the_key.wx_str());
    return false;
  }

  return true;
}// EnvvarDiscard
Пример #3
0
bool nsEnvVars::EnvvarDiscard(const wxString &key)
{
#if TRACE_ENVVARS
  Manager::Get()->GetLogManager()->DebugLog(F(_T("EnvvarDiscard")));
#endif

  // Replace all macros the user might have setup for the key
  wxString the_key = key;
  Manager::Get()->GetMacrosManager()->ReplaceMacros(the_key);

  if (!wxUnsetEnv(the_key))
  {
    Manager::Get()->GetLogManager()->Log(F(
      _("Unsetting environment variable '%s' failed."),
      #if wxCHECK_VERSION(2, 9, 0)
      the_key.wx_str())
      #else
      the_key.c_str())
      #endif
    );
    EV_DBGLOG(_T("EnvVars: Unsetting environment variable '%s' failed."),
    #if wxCHECK_VERSION(2, 9, 0)
      the_key.wx_str());
    #else
      the_key.c_str());
    #endif
    return false;
  }
Пример #4
0
//---------------------------------------------------------
bool CSG_Module_Library::Create(const CSG_String &File_Name)
{
	Destroy();

	TSG_PFNC_MLB_Initialize		MLB_Initialize;
	TSG_PFNC_MLB_Get_Interface	MLB_Get_Interface;

	wxString	sPath;
	wxFileName	fName(File_Name.c_str());

	fName.MakeAbsolute();
	m_File_Name		= fName.GetFullPath();

	//-----------------------------------------------------
	if( wxGetEnv(ENV_LIB_PATH, &sPath) && sPath.Length() > 0 )
	{
		wxSetEnv(ENV_LIB_PATH, CSG_String::Format(SG_T("%s%c%s"), sPath.c_str(), ENV_LIB_SEPA, SG_File_Get_Path(m_File_Name).c_str()));
	}
	else
	{
		wxSetEnv(ENV_LIB_PATH, SG_File_Get_Path(m_File_Name).c_str());
	}

	//-----------------------------------------------------
	if(	m_pLibrary->Load(m_File_Name.c_str())
	&&	(MLB_Get_Interface	= (TSG_PFNC_MLB_Get_Interface)	m_pLibrary->GetSymbol(SYMBOL_MLB_Get_Interface)) != NULL
	&&	(MLB_Initialize		= (TSG_PFNC_MLB_Initialize)		m_pLibrary->GetSymbol(SYMBOL_MLB_Initialize)   ) != NULL
	&&	 MLB_Initialize(m_File_Name) )
	{
		m_pInterface	= MLB_Get_Interface();
	}

	//-----------------------------------------------------
	if( sPath.Length() > 0 )
	{
		wxSetEnv(ENV_LIB_PATH, sPath);
	}
	else
	{
		wxUnsetEnv(ENV_LIB_PATH);
	}

	//-----------------------------------------------------
	if( Get_Count() > 0 )
	{
		for(int i=0; i<Get_Count(); i++)
			Get_Module(i)->Set_Managed(false);

		return( true );
	}

	Destroy();

	return( false );
}
Пример #5
0
void CrtTestCase::SetGetEnv()
{
    wxString val;
    wxSetEnv(_T("TESTVAR"), _T("value"));
    CPPUNIT_ASSERT( wxGetEnv(_T("TESTVAR"), &val) == true );
    CPPUNIT_ASSERT( val == _T("value") );
    wxSetEnv(_T("TESTVAR"), _T("something else"));
    CPPUNIT_ASSERT( wxGetEnv(_T("TESTVAR"), &val) );
    CPPUNIT_ASSERT( val == _T("something else") );
    CPPUNIT_ASSERT( wxUnsetEnv(_T("TESTVAR")) );
    CPPUNIT_ASSERT( wxGetEnv(_T("TESTVAR"), NULL) == false );
}
Пример #6
0
bool LadspaEffectsModule::RegisterPlugin(PluginManagerInterface & pm, const wxString & path)
{
   // Since we now have builtin VST support, ignore the VST bridge as it
   // causes duplicate menu entries to appear.
   wxFileName f(path);
   if (f.GetName().CmpNoCase(wxT("vst-bridge")) == 0) {
      return false;
   }

   // As a courtesy to some plug-ins that might be bridges to
   // open other plug-ins, we set the current working
   // directory to be the plug-in's directory.
   wxString envpath;
   bool hadpath = wxGetEnv(wxT("PATH"), &envpath);
   wxSetEnv(wxT("PATH"), f.GetPath() + wxFILE_SEP_PATH + envpath);
   wxString saveOldCWD = f.GetCwd();
   f.SetCwd();
   
   int index = 0;
   LADSPA_Descriptor_Function mainFn = NULL;
   wxDynamicLibrary lib;
   if (lib.Load(path, wxDL_NOW)) {
      wxLogNull logNo;

      mainFn = (LADSPA_Descriptor_Function) lib.GetSymbol(wxT("ladspa_descriptor"));
      if (mainFn) {
         const LADSPA_Descriptor *data;

         for (data = mainFn(index); data; data = mainFn(++index)) {
            LadspaEffect effect(path, index);
            if (effect.SetHost(NULL)) {
               pm.RegisterPlugin(this, &effect);
            }
         }
      }
   }

   if (lib.IsLoaded()) {
      // PRL:  I suspect Bug1257 -- Crash when enabling Amplio2 -- is the fault of a timing-
      // dependent multi-threading bug in the Amplio2 library itself, in case the unload of the .dll
      // comes too soon after the load.  I saw the bug in Release builds but not Debug.
      // A sleep of even 1 ms was enough to fix the problem for me, but let's be even more generous.
      ::wxMilliSleep(10);
      lib.Unload();
   }

   wxSetWorkingDirectory(saveOldCWD);
   hadpath ? wxSetEnv(wxT("PATH"), envpath) : wxUnsetEnv(wxT("PATH"));

   return index > 0;
}
Пример #7
0
bool LadspaEffectsModule::RegisterPlugin(PluginManagerInterface & pm, const wxString & path)
{
   // Since we now have builtin VST support, ignore the VST bridge as it
   // causes duplicate menu entries to appear.
   wxFileName f(path);
   if (f.GetName().CmpNoCase(wxT("vst-bridge")) == 0) {
      return false;
   }

   // As a courtesy to some plug-ins that might be bridges to
   // open other plug-ins, we set the current working
   // directory to be the plug-in's directory.
   wxString envpath;
   bool hadpath = wxGetEnv(wxT("PATH"), &envpath);
   wxSetEnv(wxT("PATH"), f.GetPath() + wxFILE_SEP_PATH + envpath);
   wxString saveOldCWD = f.GetCwd();
   f.SetCwd();
   
   int index = 0;
   LADSPA_Descriptor_Function mainFn = NULL;
   wxDynamicLibrary lib;
   if (lib.Load(path, wxDL_NOW)) {
      wxLogNull logNo;

      mainFn = (LADSPA_Descriptor_Function) lib.GetSymbol(wxT("ladspa_descriptor"));
      if (mainFn) {
         const LADSPA_Descriptor *data;

         for (data = mainFn(index); data; data = mainFn(++index)) {
            LadspaEffect effect(path, index);
            if (effect.SetHost(NULL)) {
               pm.RegisterPlugin(this, &effect);
            }
         }
      }
   }

   if (lib.IsLoaded()) {
      lib.Unload();
   }

   wxSetWorkingDirectory(saveOldCWD);
   hadpath ? wxSetEnv(wxT("PATH"), envpath) : wxUnsetEnv(wxT("PATH"));

   return index > 0;
}
Пример #8
0
void CrtTestCase::SetGetEnv()
{
    wxString val;
    wxSetEnv(_T("TESTVAR"), _T("value"));
    CPPUNIT_ASSERT( wxGetEnv(_T("TESTVAR"), &val) == true );
    CPPUNIT_ASSERT( val == _T("value") );
    wxSetEnv(_T("TESTVAR"), _T("something else"));
    CPPUNIT_ASSERT( wxGetEnv(_T("TESTVAR"), &val) );
    CPPUNIT_ASSERT( val == _T("something else") );

    // this test doesn't work under Unix systems without setenv(): putenv() can
    // only be used to add or modify environment variables but not to unset
    // them
#if !defined(__UNIX__) || defined(HAVE_SETENV)
    CPPUNIT_ASSERT( wxUnsetEnv(_T("TESTVAR")) );
    CPPUNIT_ASSERT( wxGetEnv(_T("TESTVAR"), NULL) == false );
#endif
}
Пример #9
0
void EnvTestCase::GetSet()
{
    const wxChar *var = wxT("wxTestVar");
    wxString contents;

    CPPUNIT_ASSERT(!wxGetEnv(var, &contents));
    CPPUNIT_ASSERT(contents.empty());

    wxSetEnv(var, wxT("value for wxTestVar"));
    CPPUNIT_ASSERT(wxGetEnv(var, &contents));
    CPPUNIT_ASSERT(contents == wxT("value for wxTestVar"));

    wxSetEnv(var, wxT("another value"));
    CPPUNIT_ASSERT(wxGetEnv(var, &contents));
    CPPUNIT_ASSERT(contents == wxT("another value"));

    wxUnsetEnv(var);
    CPPUNIT_ASSERT(!wxGetEnv(var, &contents));
}
Пример #10
0
void CrtTestCase::SetGetEnv()
{
#define TESTVAR_NAME wxT("WXTESTVAR")

    wxString val;
    wxSetEnv(TESTVAR_NAME, wxT("value"));
    CPPUNIT_ASSERT( wxGetEnv(TESTVAR_NAME, &val) );
    CPPUNIT_ASSERT_EQUAL( "value", val );
    CPPUNIT_ASSERT_EQUAL( "value", wxString(wxGetenv(TESTVAR_NAME)) );

    wxSetEnv(TESTVAR_NAME, wxT("something else"));
    CPPUNIT_ASSERT( wxGetEnv(TESTVAR_NAME, &val) );
    CPPUNIT_ASSERT_EQUAL( "something else", val );
    CPPUNIT_ASSERT_EQUAL( "something else", wxString(wxGetenv(TESTVAR_NAME)) );

    CPPUNIT_ASSERT( wxUnsetEnv(TESTVAR_NAME) );
    CPPUNIT_ASSERT( !wxGetEnv(TESTVAR_NAME, NULL) );
    CPPUNIT_ASSERT( !wxGetenv(TESTVAR_NAME) );

#undef TESTVAR_NAME
}
Пример #11
0
wxWindow *pluginUtilityFactory::StartDialog(frmMain *form, pgObject *obj)
{
	wxString execCmd = command;
	wxArrayString environment = set_env;

	// Remember this as the last plugin used
	form->SetLastPluginUtility(this);

	// Replace all the place holders with appropriate values
	if (HaveDatabase(obj))
	{
		execCmd.Replace(wxT("$$HOSTNAME"), obj->GetConnection()->GetHostName());
		execCmd.Replace(wxT("$$HOSTADDR"), obj->GetConnection()->GetHostName());
		execCmd.Replace(wxT("$$PORT"), NumToStr((long)obj->GetConnection()->GetPort()));
		execCmd.Replace(wxT("$$SSLMODE"), obj->GetConnection()->GetSslModeName());
		execCmd.Replace(wxT("$$DATABASE"), obj->GetConnection()->GetDbname());
		execCmd.Replace(wxT("$$USERNAME"), obj->GetConnection()->GetUser());
		execCmd.Replace(wxT("$$PASSWORD"), obj->GetConnection()->GetPassword());

		// Set the PGPASSWORD variable if required.
		if (set_password && !obj->GetConnection()->GetPassword().IsEmpty())
			wxSetEnv(wxT("PGPASSWORD"), obj->GetConnection()->GetPassword());

		// Pass the SSL settings via the environment
		switch (obj->GetConnection()->GetSslMode())
		{
			case 1:
				wxSetEnv(wxT("PGREQUIRESSL"), wxT("1"));
				break;
			case 2:
				wxSetEnv(wxT("PGREQUIRESSL"), wxT("0"));
				break;
		}

		wxSetEnv(wxT("PGSSLMODE"), obj->GetConnection()->GetSslModeName());
		wxSetEnv(wxT("PGSSLCERT"), obj->GetConnection()->GetSSLCert());
		wxSetEnv(wxT("PGSSLKEY"), obj->GetConnection()->GetSSLKey());
		wxSetEnv(wxT("PGSSLROOTCERT"), obj->GetConnection()->GetSSLRootCert());
		wxSetEnv(wxT("PGSSLCRL"), obj->GetConnection()->GetSSLCrl());
	}
	else
	{
		// Blank the rest
		execCmd.Replace(wxT("$$HOSTNAME"), wxEmptyString);
		execCmd.Replace(wxT("$$HOSTADDR"), wxEmptyString);
		execCmd.Replace(wxT("$$PORT"), wxEmptyString);
		execCmd.Replace(wxT("$$SSLMODE"), wxEmptyString);
		execCmd.Replace(wxT("$$DATABASE"), wxEmptyString);
		execCmd.Replace(wxT("$$USERNAME"), wxEmptyString);
		execCmd.Replace(wxT("$$PASSWORD"), wxEmptyString);
	}

	// Name
	if (obj && obj->IsCollection())
		execCmd.Replace(wxT("$$OBJECTNAME"), wxT("*"));
	else if (obj)
		execCmd.Replace(wxT("$$OBJECTNAME"), obj->GetName());
	else
		execCmd.Replace(wxT("$$OBJECTNAME"), wxEmptyString);

	// Object type
	if (obj && obj->GetFactory())
		execCmd.Replace(wxT("$$OBJECTTYPE"), wxString(obj->GetFactory()->GetTypeName()).Upper());
	else
		execCmd.Replace(wxT("$$OBJECTTYPE"), wxEmptyString);

	// Schema
	if (obj)
	{
		if (obj->GetMetaType() == PGM_SCHEMA)
			execCmd.Replace(wxT("$$SCHEMA"), obj->GetName());
		else if (obj->GetSchema())
			execCmd.Replace(wxT("$$SCHEMA"), obj->GetSchema()->GetName());
	}
	else
		execCmd.Replace(wxT("$$SCHEMA"), wxEmptyString);

	// Table
	if (obj)
	{
		if (obj->GetMetaType() == PGM_TABLE || obj->GetMetaType() == GP_PARTITION)
			execCmd.Replace(wxT("$$TABLE"), obj->GetName());
		else if (obj->GetTable())
			execCmd.Replace(wxT("$$TABLE"), obj->GetTable()->GetName());
	}
	else
		execCmd.Replace(wxT("$$TABLE"), wxEmptyString);

	// Directory substitutions
	execCmd.Replace(wxT("$$BINDIR"), loadPath);
	execCmd.Replace(wxT("$$WORKINGDIR"), wxGetCwd());
	execCmd.Replace(wxT("$$PGBINDIR"), settings->GetPostgresqlPath());
	execCmd.Replace(wxT("$$EDBBINDIR"), settings->GetEnterprisedbPath());
	execCmd.Replace(wxT("$$SLONYBINDIR"), settings->GetSlonyPath());

	// set Environment variable.
	for (size_t i = 0 ; i < environment.GetCount() ; i++)
	{
		wxString str = environment.Item(i);
		wxSetEnv(str.BeforeFirst('='), str.AfterFirst('='));
	}

	// Let's go!!
	if (wxExecute(execCmd) == 0)
	{
		wxLogError(_("Failed to execute plugin %s (%s)"), title.c_str(), command.c_str());
	}

	// Reset the environment variables set by us
	wxUnsetEnv(wxT("PGPASSWORD"));
	wxUnsetEnv(wxT("PGSSLMODE"));
	wxUnsetEnv(wxT("PGREQUIRESSL"));
	wxUnsetEnv(wxT("PGSSLCERT"));
	wxUnsetEnv(wxT("PGSSLKEY"));
	wxUnsetEnv(wxT("PGSSLROOTCERT"));
	wxUnsetEnv(wxT("PGSSLCRL"));

	return 0;
}
Пример #12
0
// wxExecute: the real worker function
long wxExecute(char **argv, int flags, wxProcess *process,
        const wxExecuteEnv *env)
{
    // for the sync execution, we return -1 to indicate failure, but for async
    // case we return 0 which is never a valid PID
    //
    // we define this as a macro, not a variable, to avoid compiler warnings
    // about "ERROR_RETURN_CODE value may be clobbered by fork()"
    #define ERROR_RETURN_CODE ((flags & wxEXEC_SYNC) ? -1 : 0)

    wxCHECK_MSG( *argv, ERROR_RETURN_CODE, wxT("can't exec empty command") );

#if wxUSE_THREADS
    // fork() doesn't mix well with POSIX threads: on many systems the program
    // deadlocks or crashes for some reason. Probably our code is buggy and
    // doesn't do something which must be done to allow this to work, but I
    // don't know what yet, so for now just warn the user (this is the least we
    // can do) about it
    wxASSERT_MSG( wxThread::IsMain(),
                    wxT("wxExecute() can be called only from the main thread") );
#endif // wxUSE_THREADS

#if defined(__DARWIN__) && !defined(__WXOSX_IPHONE__)
    // wxMacLaunch() only executes app bundles and only does it asynchronously.
    // It returns false if the target is not an app bundle, thus falling
    // through to the regular code for non app bundles.
    if ( !(flags & wxEXEC_SYNC) && wxMacLaunch(argv) )
    {
        // we don't have any PID to return so just make up something non null
        return -1;
    }
#endif // __DARWIN__

    // this struct contains all information which we use for housekeeping
    wxScopedPtr<wxExecuteData> execDataPtr(new wxExecuteData);
    wxExecuteData& execData = *execDataPtr;

    execData.flags = flags;
    execData.process = process;

    // create pipes for inter process communication
    wxPipe pipeIn,      // stdin
           pipeOut,     // stdout
           pipeErr;     // stderr

    if ( process && process->IsRedirected() )
    {
        if ( !pipeIn.Create() || !pipeOut.Create() || !pipeErr.Create() )
        {
            wxLogError( _("Failed to execute '%s'\n"), *argv );

            return ERROR_RETURN_CODE;
        }
    }

    // priority: we need to map wxWidgets priority which is in the range 0..100
    // to Unix nice value which is in the range -20..19. As there is an odd
    // number of elements in our range and an even number in the Unix one, we
    // have to do it in this rather ugly way to guarantee that:
    //  1. wxPRIORITY_{MIN,DEFAULT,MAX} map to -20, 0 and 19 respectively.
    //  2. The mapping is monotonously increasing.
    //  3. The mapping is onto the target range.
    int prio = process ? int(process->GetPriority()) : int(wxPRIORITY_DEFAULT);
    if ( prio <= 50 )
        prio = (2*prio)/5 - 20;
    else if ( prio < 55 )
        prio = 1;
    else
        prio = (2*prio)/5 - 21;

    // fork the process
    //
    // NB: do *not* use vfork() here, it completely breaks this code for some
    //     reason under Solaris (and maybe others, although not under Linux)
    //     But on OpenVMS we do not have fork so we have to use vfork and
    //     cross our fingers that it works.
#ifdef __VMS
   pid_t pid = vfork();
#else
   pid_t pid = fork();
#endif
   if ( pid == -1 )     // error?
    {
        wxLogSysError( _("Fork failed") );

        return ERROR_RETURN_CODE;
    }
    else if ( pid == 0 )  // we're in child
    {
        // NB: we used to close all the unused descriptors of the child here
        //     but this broke some programs which relied on e.g. FD 1 being
        //     always opened so don't do it any more, after all there doesn't
        //     seem to be any real problem with keeping them opened

#if !defined(__VMS)
        if ( flags & wxEXEC_MAKE_GROUP_LEADER )
        {
            // Set process group to child process' pid.  Then killing -pid
            // of the parent will kill the process and all of its children.
            setsid();
        }
#endif // !__VMS

#if defined(HAVE_SETPRIORITY)
        if ( prio && setpriority(PRIO_PROCESS, 0, prio) != 0 )
        {
            wxLogSysError(_("Failed to set process priority"));
        }
#endif // HAVE_SETPRIORITY

        // redirect stdin, stdout and stderr
        if ( pipeIn.IsOk() )
        {
            if ( dup2(pipeIn[wxPipe::Read], STDIN_FILENO) == -1 ||
                 dup2(pipeOut[wxPipe::Write], STDOUT_FILENO) == -1 ||
                 dup2(pipeErr[wxPipe::Write], STDERR_FILENO) == -1 )
            {
                wxLogSysError(_("Failed to redirect child process input/output"));
            }

            pipeIn.Close();
            pipeOut.Close();
            pipeErr.Close();
        }

        // Close all (presumably accidentally) inherited file descriptors to
        // avoid descriptor leaks. This means that we don't allow inheriting
        // them purposefully but this seems like a lesser evil in wx code.
        // Ideally we'd provide some flag to indicate that none (or some?) of
        // the descriptors do not need to be closed but for now this is better
        // than never closing them at all as wx code never used FD_CLOEXEC.

        // TODO: Iterating up to FD_SETSIZE is both inefficient (because it may
        //       be quite big) and incorrect (because in principle we could
        //       have more opened descriptions than this number). Unfortunately
        //       there is no good portable solution for closing all descriptors
        //       above a certain threshold but non-portable solutions exist for
        //       most platforms, see [http://stackoverflow.com/questions/899038/
        //          getting-the-highest-allocated-file-descriptor]
        for ( int fd = 0; fd < (int)FD_SETSIZE; ++fd )
        {
            if ( fd != STDIN_FILENO  &&
                 fd != STDOUT_FILENO &&
                 fd != STDERR_FILENO )
            {
                close(fd);
            }
        }


        // Process additional options if we have any
        if ( env )
        {
            // Change working directory if it is specified
            if ( !env->cwd.empty() )
                wxSetWorkingDirectory(env->cwd);

            // Change environment if needed.
            //
            // NB: We can't use execve() currently because we allow using
            //     non full paths to wxExecute(), i.e. we want to search for
            //     the program in PATH. However it just might be simpler/better
            //     to do the search manually and use execve() envp parameter to
            //     set up the environment of the child process explicitly
            //     instead of doing what we do below.
            if ( !env->env.empty() )
            {
                wxEnvVariableHashMap oldenv;
                wxGetEnvMap(&oldenv);

                // Remove unwanted variables
                wxEnvVariableHashMap::const_iterator it;
                for ( it = oldenv.begin(); it != oldenv.end(); ++it )
                {
                    if ( env->env.find(it->first) == env->env.end() )
                        wxUnsetEnv(it->first);
                }

                // And add the new ones (possibly replacing the old values)
                for ( it = env->env.begin(); it != env->env.end(); ++it )
                    wxSetEnv(it->first, it->second);
            }
        }

        execvp(*argv, argv);

        fprintf(stderr, "execvp(");
        for ( char **a = argv; *a; a++ )
            fprintf(stderr, "%s%s", a == argv ? "" : ", ", *a);
        fprintf(stderr, ") failed with error %d!\n", errno);

        // there is no return after successful exec()
        _exit(-1);

        // some compilers complain about missing return - of course, they
        // should know that exit() doesn't return but what else can we do if
        // they don't?
        //
        // and, sure enough, other compilers complain about unreachable code
        // after exit() call, so we can just always have return here...
#if defined(__VMS) || defined(__INTEL_COMPILER)
        return 0;
#endif
    }
    else // we're in parent
    {
        // prepare for IO redirection

#if HAS_PIPE_STREAMS

        if ( process && process->IsRedirected() )
        {
            // Avoid deadlocks which could result from trying to write to the
            // child input pipe end while the child itself is writing to its
            // output end and waiting for us to read from it.
            if ( !pipeIn.MakeNonBlocking(wxPipe::Write) )
            {
                // This message is not terrible useful for the user but what
                // else can we do? Also, should we fail here or take the risk
                // to continue and deadlock? Currently we choose the latter but
                // it might not be the best idea.
                wxLogSysError(_("Failed to set up non-blocking pipe, "
                                "the program might hang."));
#if wxUSE_LOG
                wxLog::FlushActive();
#endif
            }

            wxOutputStream *inStream =
                new wxPipeOutputStream(pipeIn.Detach(wxPipe::Write));

            const int fdOut = pipeOut.Detach(wxPipe::Read);
            wxPipeInputStream *outStream = new wxPipeInputStream(fdOut);

            const int fdErr = pipeErr.Detach(wxPipe::Read);
            wxPipeInputStream *errStream = new wxPipeInputStream(fdErr);

            process->SetPipeStreams(outStream, inStream, errStream);

            if ( flags & wxEXEC_SYNC )
            {
                execData.bufOut.Init(outStream);
                execData.bufErr.Init(errStream);

                execData.fdOut = fdOut;
                execData.fdErr = fdErr;
            }
        }
#endif // HAS_PIPE_STREAMS

        if ( pipeIn.IsOk() )
        {
            pipeIn.Close();
            pipeOut.Close();
            pipeErr.Close();
        }

        if ( !(flags & wxEXEC_SYNC) )
        {
            // Ensure that the housekeeping data is kept alive, it will be
            // destroyed only when the child terminates.
            execDataPtr.release();
        }

        // Put the housekeeping data into the child process lookup table.
        // Note that when running asynchronously, if the child has already
        // finished this call will delete the execData and call any
        // wxProcess's OnTerminate() handler immediately.
        execData.OnStart(pid);

        // For the asynchronous case we don't have to do anything else, just
        // let the process run (if not already finished).
        if ( !(flags & wxEXEC_SYNC) )
            return pid;


        // If we don't need to dispatch any events, things are relatively
        // simple and we don't need to delegate to wxAppTraits.
        if ( flags & wxEXEC_NOEVENTS )
        {
            return BlockUntilChildExit(execData);
        }


        // If we do need to dispatch events, enter a local event loop waiting
        // until the child exits. As the exact kind of event loop depends on
        // the sort of application we're in (console or GUI), we delegate this
        // to wxAppTraits which virtualizes all the differences between the
        // console and the GUI programs.
        return wxApp::GetValidTraits().WaitForChild(execData);
    }

#if !defined(__VMS) && !defined(__INTEL_COMPILER)
    return ERROR_RETURN_CODE;
#endif
}
Пример #13
0
// wxExecute: the real worker function
long wxExecute(char **argv, int flags, wxProcess *process,
        const wxExecuteEnv *env)
{
    // for the sync execution, we return -1 to indicate failure, but for async
    // case we return 0 which is never a valid PID
    //
    // we define this as a macro, not a variable, to avoid compiler warnings
    // about "ERROR_RETURN_CODE value may be clobbered by fork()"
    #define ERROR_RETURN_CODE ((flags & wxEXEC_SYNC) ? -1 : 0)

    wxCHECK_MSG( *argv, ERROR_RETURN_CODE, wxT("can't exec empty command") );

#if wxUSE_THREADS
    // fork() doesn't mix well with POSIX threads: on many systems the program
    // deadlocks or crashes for some reason. Probably our code is buggy and
    // doesn't do something which must be done to allow this to work, but I
    // don't know what yet, so for now just warn the user (this is the least we
    // can do) about it
    wxASSERT_MSG( wxThread::IsMain(),
                    wxT("wxExecute() can be called only from the main thread") );
#endif // wxUSE_THREADS

#if defined(__WXCOCOA__) || ( defined(__WXOSX_MAC__) && wxOSX_USE_COCOA_OR_CARBON )
    // wxMacLaunch() only executes app bundles and only does it asynchronously.
    // It returns false if the target is not an app bundle, thus falling
    // through to the regular code for non app bundles.
    if ( !(flags & wxEXEC_SYNC) && wxMacLaunch(argv) )
    {
        // we don't have any PID to return so just make up something non null
        return -1;
    }
#endif // __DARWIN__


    // this struct contains all information which we use for housekeeping
    wxExecuteData execData;
    execData.flags = flags;
    execData.process = process;

    // create pipes
    if ( !execData.pipeEndProcDetect.Create() )
    {
        wxLogError( _("Failed to execute '%s'\n"), *argv );

        return ERROR_RETURN_CODE;
    }

    // pipes for inter process communication
    wxPipe pipeIn,      // stdin
           pipeOut,     // stdout
           pipeErr;     // stderr

    if ( process && process->IsRedirected() )
    {
        if ( !pipeIn.Create() || !pipeOut.Create() || !pipeErr.Create() )
        {
            wxLogError( _("Failed to execute '%s'\n"), *argv );

            return ERROR_RETURN_CODE;
        }
    }

    // fork the process
    //
    // NB: do *not* use vfork() here, it completely breaks this code for some
    //     reason under Solaris (and maybe others, although not under Linux)
    //     But on OpenVMS we do not have fork so we have to use vfork and
    //     cross our fingers that it works.
#ifdef __VMS
   pid_t pid = vfork();
#else
   pid_t pid = fork();
#endif
   if ( pid == -1 )     // error?
    {
        wxLogSysError( _("Fork failed") );

        return ERROR_RETURN_CODE;
    }
    else if ( pid == 0 )  // we're in child
    {
        // NB: we used to close all the unused descriptors of the child here
        //     but this broke some programs which relied on e.g. FD 1 being
        //     always opened so don't do it any more, after all there doesn't
        //     seem to be any real problem with keeping them opened

#if !defined(__VMS) && !defined(__EMX__)
        if ( flags & wxEXEC_MAKE_GROUP_LEADER )
        {
            // Set process group to child process' pid.  Then killing -pid
            // of the parent will kill the process and all of its children.
            setsid();
        }
#endif // !__VMS

        // redirect stdin, stdout and stderr
        if ( pipeIn.IsOk() )
        {
            if ( dup2(pipeIn[wxPipe::Read], STDIN_FILENO) == -1 ||
                 dup2(pipeOut[wxPipe::Write], STDOUT_FILENO) == -1 ||
                 dup2(pipeErr[wxPipe::Write], STDERR_FILENO) == -1 )
            {
                wxLogSysError(_("Failed to redirect child process input/output"));
            }

            pipeIn.Close();
            pipeOut.Close();
            pipeErr.Close();
        }

        // Close all (presumably accidentally) inherited file descriptors to
        // avoid descriptor leaks. This means that we don't allow inheriting
        // them purposefully but this seems like a lesser evil in wx code.
        // Ideally we'd provide some flag to indicate that none (or some?) of
        // the descriptors do not need to be closed but for now this is better
        // than never closing them at all as wx code never used FD_CLOEXEC.

        // Note that while the reading side of the end process detection pipe
        // can be safely closed, we should keep the write one opened, it will
        // be only closed when the process terminates resulting in a read
        // notification to the parent
        const int fdEndProc = execData.pipeEndProcDetect.Detach(wxPipe::Write);
        execData.pipeEndProcDetect.Close();

        // TODO: Iterating up to FD_SETSIZE is both inefficient (because it may
        //       be quite big) and incorrect (because in principle we could
        //       have more opened descriptions than this number). Unfortunately
        //       there is no good portable solution for closing all descriptors
        //       above a certain threshold but non-portable solutions exist for
        //       most platforms, see [http://stackoverflow.com/questions/899038/
        //          getting-the-highest-allocated-file-descriptor]
        for ( int fd = 0; fd < (int)FD_SETSIZE; ++fd )
        {
            if ( fd != STDIN_FILENO  &&
                 fd != STDOUT_FILENO &&
                 fd != STDERR_FILENO &&
                 fd != fdEndProc )
            {
                close(fd);
            }
        }


        // Process additional options if we have any
        if ( env )
        {
            // Change working directory if it is specified
            if ( !env->cwd.empty() )
                wxSetWorkingDirectory(env->cwd);

            // Change environment if needed.
            //
            // NB: We can't use execve() currently because we allow using
            //     non full paths to wxExecute(), i.e. we want to search for
            //     the program in PATH. However it just might be simpler/better
            //     to do the search manually and use execve() envp parameter to
            //     set up the environment of the child process explicitly
            //     instead of doing what we do below.
            if ( !env->env.empty() )
            {
                wxEnvVariableHashMap oldenv;
                wxGetEnvMap(&oldenv);

                // Remove unwanted variables
                wxEnvVariableHashMap::const_iterator it;
                for ( it = oldenv.begin(); it != oldenv.end(); ++it )
                {
                    if ( env->env.find(it->first) == env->env.end() )
                        wxUnsetEnv(it->first);
                }

                // And add the new ones (possibly replacing the old values)
                for ( it = env->env.begin(); it != env->env.end(); ++it )
                    wxSetEnv(it->first, it->second);
            }
        }

        execvp(*argv, argv);

        fprintf(stderr, "execvp(");
        for ( char **a = argv; *a; a++ )
            fprintf(stderr, "%s%s", a == argv ? "" : ", ", *a);
        fprintf(stderr, ") failed with error %d!\n", errno);

        // there is no return after successful exec()
        _exit(-1);

        // some compilers complain about missing return - of course, they
        // should know that exit() doesn't return but what else can we do if
        // they don't?
        //
        // and, sure enough, other compilers complain about unreachable code
        // after exit() call, so we can just always have return here...
#if defined(__VMS) || defined(__INTEL_COMPILER)
        return 0;
#endif
    }
    else // we're in parent
    {
        // save it for WaitForChild() use
        execData.pid = pid;
        if (execData.process)
            execData.process->SetPid(pid);  // and also in the wxProcess

        // prepare for IO redirection

#if HAS_PIPE_STREAMS
        // the input buffer bufOut is connected to stdout, this is why it is
        // called bufOut and not bufIn
        wxStreamTempInputBuffer bufOut,
                                bufErr;

        if ( process && process->IsRedirected() )
        {
            // Avoid deadlocks which could result from trying to write to the
            // child input pipe end while the child itself is writing to its
            // output end and waiting for us to read from it.
            if ( !pipeIn.MakeNonBlocking(wxPipe::Write) )
            {
                // This message is not terrible useful for the user but what
                // else can we do? Also, should we fail here or take the risk
                // to continue and deadlock? Currently we choose the latter but
                // it might not be the best idea.
                wxLogSysError(_("Failed to set up non-blocking pipe, "
                                "the program might hang."));
#if wxUSE_LOG
                wxLog::FlushActive();
#endif
            }

            wxOutputStream *inStream =
                new wxPipeOutputStream(pipeIn.Detach(wxPipe::Write));

            const int fdOut = pipeOut.Detach(wxPipe::Read);
            wxPipeInputStream *outStream = new wxPipeInputStream(fdOut);

            const int fdErr = pipeErr.Detach(wxPipe::Read);
            wxPipeInputStream *errStream = new wxPipeInputStream(fdErr);

            process->SetPipeStreams(outStream, inStream, errStream);

            bufOut.Init(outStream);
            bufErr.Init(errStream);

            execData.bufOut = &bufOut;
            execData.bufErr = &bufErr;

            execData.fdOut = fdOut;
            execData.fdErr = fdErr;
        }
#endif // HAS_PIPE_STREAMS

        if ( pipeIn.IsOk() )
        {
            pipeIn.Close();
            pipeOut.Close();
            pipeErr.Close();
        }

        // we want this function to work even if there is no wxApp so ensure
        // that we have a valid traits pointer
        wxConsoleAppTraits traitsConsole;
        wxAppTraits *traits = wxTheApp ? wxTheApp->GetTraits() : NULL;
        if ( !traits )
            traits = &traitsConsole;

        return traits->WaitForChild(execData);
    }

#if !defined(__VMS) && !defined(__INTEL_COMPILER)
    return ERROR_RETURN_CODE;
#endif
}