39 #if defined(NCBI_OS_MSWIN)
41 #elif defined(NCBI_OS_UNIX)
44 # include <sys/types.h>
45 # include <sys/wait.h>
49 #define NCBI_USE_ERRCODE_X Corelib_System
58 "CExec:: CResult contains process handle, not exit code");
65 if ( (m_Flags & fHandle) == 0 ) {
67 "CExec:: CResult contains process exit code, not handle");
69 return m_Result.handle;
81 "CExec:: CResult undefined conversion");
88 #if defined(NCBI_OS_MSWIN)
93 static const int s_Mode[] = {
94 P_OVERLAY, P_WAIT, P_NOWAIT, P_DETACH
99 _ASSERT(0 <= x_mode && x_mode <
sizeof(s_Mode)/
sizeof(s_Mode[0]));
100 return s_Mode[x_mode];
105 #if defined(NCBI_OS_UNIX)
112 const char *cmdname,
const char *
const *argv,
113 const char *
const *envp = (
const char *
const*)0)
116 const char* empty_env[] = { 0 };
132 return execv(cmdname,
const_cast<char**
>(argv));
134 return execvp(cmdname,
const_cast<char**
>(argv));
137 return execve(cmdname,
const_cast<char**
>(argv),
138 const_cast<char**
>(envp));
146 if (pipe(status_pipe) < 0) {
148 "CExec:: Failed to create status pipe");
150 fcntl(status_pipe[0], F_SETFL,
151 fcntl(status_pipe[0], F_GETFL, 0) & ~O_NONBLOCK);
152 fcntl(status_pipe[1], F_SETFD,
153 fcntl(status_pipe[1], F_GETFD, 0) | FD_CLOEXEC);
157 switch (pid = fork()) {
165 close(status_pipe[0]);
168 if ( freopen(
"/dev/null",
"r", stdin) ) { };
169 if ( freopen(
"/dev/null",
"w", stdout) ) { };
170 if ( freopen(
"/dev/null",
"a", stderr) ) { };
180 status = execv(cmdname,
const_cast<char**
>(argv));
183 status = execvp(cmdname,
const_cast<char**
>(argv));
187 status = execve(cmdname,
const_cast<char**
>(argv),
188 const_cast<char**
>(envp));
193 if ( write(status_pipe[1], &errcode,
sizeof(errcode)) ) { };
194 close(status_pipe[1]);
203 close(status_pipe[1]);
208 while ((
n = read(status_pipe[0], &errcode,
sizeof(errcode))) < 0) {
212 close(status_pipe[0]);
216 errno = (size_t)
n >=
sizeof(errcode) ? errcode : 0;
235 (arg.find(
' ') !=
NPOS && arg.find(
'"') ==
NPOS) ) {
236 return '"' + arg +
'"';
250 #if defined(NCBI_OS_MSWIN)
252 if (!arg.empty() && arg.find_first_of(
" \t\n\v\"") ==
NPOS) {
259 unsigned int n_backslashes = 0;
261 while (it != arg.end() && *it ==
'\\') {
265 if (it == arg.end()) {
270 s.append(n_backslashes * 2,
'\\');
273 }
else if (*it ==
'"') {
277 s.append(n_backslashes * 2 + 1,
'\\');
282 s.append(n_backslashes,
'\\');
299 #if defined(_DEBUG) && SIZEOF_VOIDP > SIZEOF_INT
302 # if defined(WORDS_BIGENDIAN)
303 int lo =
int(((
Uint8)arg >> 32) & 0xffffffffU);
304 int hi =
int((
Uint8)arg & 0xffffffffU);
306 int hi =
int(((
Uint8)arg >> 32) & 0xffffffffU);
307 int lo =
int((
Uint8)arg & 0xffffffffU);
309 if (lo == 0 && hi != 0) {
311 "It is possible that you used 0 instead of NULL "
312 "to terminate the argument list of a CExec::Spawn*() call.");
316 # define s_CheckExecArg(x)
324 #if defined(NCBI_OS_MSWIN)
328 va_list& begin,
const char* cmdname,
const char* argv)
331 va_list v_args = begin;
333 while ( va_arg(v_args,
const char*) ) {
347 for (
size_t i=2;
i < xcnt; ++
i) {
351 for (
size_t i=0;
i < xargs.size(); ++
i) {
352 args[
i] = xargs[
i].c_str();
355 va_arg(v_args,
const char**);
360 vector<TXString>& xargs,
TXArgsOrEnv& t_args,
const char* cmdname,
const char** argv)
363 const char** p = argv;
378 for (
size_t i=1;
i < xcnt; ++
i) {
382 for (
size_t i=0;
i < xargs.size(); ++
i) {
383 args[
i] = xargs[
i].c_str();
389 vector<TXString>& xargs,
TXArgsOrEnv& t_args,
const char** begin)
391 const char** envp = begin;
393 while ( *(envp++) ) {
404 while ( i_arg < xcnt ) {
405 # if defined(_UNICODE)
408 args[i_arg] = *(envp++);
412 # if defined(_UNICODE)
413 for (
size_t i=0;
i < xargs.size(); ++
i) {
414 args[
i] = xargs[
i].c_str();
417 args[i_arg++] =
NULL;
422 #if defined(NCBI_OS_MSWIN)
423 #define XGET_EXEC_ARGS(name, ptr) \
424 const TXChar* const *a_##name; \
425 vector<TXString> x_##name; \
426 TXArgsOrEnv t_##name; \
428 va_start(vargs, ptr); \
429 s_Create_Args_L(x_##name, t_##name, vargs, cmdname, ptr); \
430 a_##name = t_##name.get();
432 #define XGET_EXEC_ARGS(name, ptr) \
435 va_start(vargs, ptr); \
436 while ( va_arg(vargs, const char*) ) xcnt++; \
438 const char ** a_##name = new const char*[xcnt+1]; \
440 NCBI_THROW(CCoreException, eNullPtr, kEmptyStr); \
441 TXArgsOrEnv t_##name(a_##name); \
442 a_##name[0] = cmdname; \
444 va_start(vargs, ptr); \
446 while ( xi < xcnt ) { \
448 a_##name[xi] = va_arg(vargs, const char*); \
449 s_CheckExecArg(a_##name[xi]); \
451 a_##name[xi] = (const char*)0
454 #if defined(NCBI_OS_MSWIN)
455 # define XGET_PTR_ARGS(name, ptr) \
456 const TXChar* const *a_##name; \
457 vector<TXString> x_##name; \
458 TXArgsOrEnv t_##name; \
459 s_Create_Args_V(x_##name, t_##name, cmdname, (const char**)ptr); \
460 a_##name = t_##name.get();
461 # define XGET_PTR_ENVP(name, ptr) \
462 const TXChar* const *a_##name; \
463 vector<TXString> x_##name; \
464 TXArgsOrEnv t_##name; \
465 s_Create_Env(x_##name, t_##name, (const char**)ptr); \
466 a_##name = t_##name.get();
468 # define XGET_PTR_ARGS(name, ptr) \
469 const char* const *a_##name = ptr; \
470 char** xptr = const_cast<char**>(ptr); \
471 xptr[0] = const_cast<char*>(cmdname);
472 # define XGET_PTR_ENVP(name, ptr) \
473 const char* const *a_##name = ptr;
476 #if defined(NCBI_OS_MSWIN) && defined(_UNICODE)
477 # define XGET_EXEC_ENVP(name) \
478 const TXChar* const *a_##name; \
479 vector<TXString> x_##name; \
480 TXArgsOrEnv t_##name; \
481 s_Create_Env(x_##name, t_##name, va_arg(vargs, const char**)); \
482 a_##name = t_##name.get();
484 # define XGET_EXEC_ENVP(name) \
485 const char * const * a_##name = va_arg(vargs, const char**);
490 #define RETURN_RESULT(func) \
491 if (status == -1) { \
492 NCBI_THROW(CExecException, eSpawn, "CExec::" #func "() failed"); \
495 if ((mode & static_cast<EMode>(fModeMask)) == eWait) { \
496 result.m_Flags = CResult::fExitCode; \
497 result.m_Result.exitcode = (TExitCode)status; \
499 result.m_Flags = CResult::fHandle; \
500 result.m_Result.handle = (TProcessHandle)status; \
508 #if defined(NCBI_OS_MSWIN)
511 #elif defined(NCBI_OS_UNIX)
512 status = system(cmdline);
516 "CExec::System: call to system failed");
518 #if defined(NCBI_OS_UNIX)
520 return WIFSIGNALED(status) ? WTERMSIG(status) + 0x80
521 : WEXITSTATUS(status);
537 #if defined(NCBI_OS_MSWIN)
540 if (realmode == P_OVERLAY) {
544 #elif defined(NCBI_OS_UNIX)
558 #if defined(NCBI_OS_MSWIN)
561 if (realmode == P_OVERLAY) {
565 #elif defined(NCBI_OS_UNIX)
578 #if defined(NCBI_OS_MSWIN)
581 if (realmode == P_OVERLAY) {
585 #elif defined(NCBI_OS_UNIX)
599 #if defined(NCBI_OS_MSWIN)
602 if (realmode == P_OVERLAY) {
606 #elif defined(NCBI_OS_UNIX)
619 #if defined(NCBI_OS_MSWIN)
622 if (realmode == P_OVERLAY) {
626 #elif defined(NCBI_OS_UNIX)
635 const char *
const *argv,
const char *
const *envp)
641 #if defined(NCBI_OS_MSWIN)
644 if (realmode == P_OVERLAY) {
648 #elif defined(NCBI_OS_UNIX)
661 #if defined(NCBI_OS_MSWIN)
664 if (realmode == P_OVERLAY) {
668 #elif defined(NCBI_OS_UNIX)
677 const char *
const *argv,
const char *
const *envp)
683 #if defined(NCBI_OS_MSWIN)
686 if (realmode == P_OVERLAY) {
690 #elif defined(NCBI_OS_UNIX)
709 unsigned long timeout)
711 typedef list<TProcessHandle>::iterator THandleIt;
716 for (THandleIt it = handles.begin(); it != handles.end(); ) {
719 if ( exitcode != -1 ) {
739 if (x_sleep > timeout) {
750 return (
int)
result.size();
755 const char *argv, ... )
759 #if defined(NCBI_OS_MSWIN)
761 # if defined(NCBI_COMPILER_MSVC)
765 STARTUPINFO StartupInfo;
766 PROCESS_INFORMATION ProcessInfo;
767 const int kMaxCmdLength = 4096;
771 memset(&StartupInfo, 0,
sizeof(StartupInfo));
772 StartupInfo.cb =
sizeof(STARTUPINFOA);
773 StartupInfo.dwFlags = STARTF_USESHOWWINDOW;
774 StartupInfo.wShowWindow = SW_HIDE;
776 DETACHED_PROCESS : CREATE_NEW_CONSOLE;
777 # if defined(_UNICODE)
778 dwCreateFlags |= CREATE_UNICODE_ENVIRONMENT;
782 cmdline.reserve(kMaxCmdLength);
789 va_start(vargs, argv);
790 const char* p =
NULL;
791 while ( (p = va_arg(vargs,
const char*)) ) {
806 dwCreateFlags,
NULL,
NULL, &StartupInfo, &ProcessInfo))
814 WaitForSingleObject(ProcessInfo.hProcess, INFINITE);
816 GetExitCodeProcess(ProcessInfo.hProcess, &exitcode);
818 CloseHandle(ProcessInfo.hProcess);
823 CloseHandle(ProcessInfo.hProcess);
828 status = (
intptr_t)ProcessInfo.hProcess;
830 CloseHandle(ProcessInfo.hThread);
833 #elif defined(NCBI_OS_UNIX)
866 string tmp = filename;
867 # ifdef NCBI_OS_MSWIN
870 string dir, title, ext;
878 size_t sep =
tmp.find_first_of(
"/\\");
884 # ifdef NCBI_OS_MSWIN
895 if ( path.empty() ) {
898 list<string> split_path;
899 # ifdef NCBI_OS_MSWIN
906 ITERATE(list<string>, it, split_path) {
917 if ( path.empty() &&
CFile(
tmp).Exists() ) {
927 if ( !path.empty() ) {
936 switch (GetErrCode()) {
937 case eSystem:
return "eSystem";
938 case eSpawn:
return "eSpawn";
939 case eResult:
return "eResult";
The result type for Spawn methods.
#define ITERATE(Type, Var, Cont)
ITERATE macro to sequence through container elements.
CDiagContext & GetDiagContext(void)
Get diag context instance.
#define ERR_POST_X(err_subcode, message)
Error posting with default error code and given error subcode.
void PrintStop(void)
Print exit message.
#define NCBI_THROW(exception_class, err_code, message)
Generic macro to throw an exception, given the exception class, error code and message string.
void Warning(CExceptionArgs_Base &args)
virtual const char * GetErrCodeString(void) const
Get error code interpreted as text.
static TExitCode System(const char *cmdline)
Execute the specified command.
static CResult RunSilent(EMode mode, const char *cmdname, const char *argv,...)
Run console application in invisible mode.
static bool IsExecutable(const string &path)
Check executable permissions for specified file.
static CResult SpawnLPE(EMode mode, const char *cmdname, const char *argv,...)
Spawn a new process with specified command-line arguments, environment settings and find file to exec...
int TExitCode
Exit code type.
struct CExec::CResult::@98 m_Result
Result of Spawn*() methods.
TExitCode GetExitCode(void)
Get exit code.
virtual const char * GetErrCodeString(void) const override
Translate from the error code value to its string representation.
EMode
Which exec mode the spawned process is called with.
static string ResolvePath(const string &filename)
Find executable file.
static CResult SpawnL(EMode mode, const char *cmdname, const char *argv,...)
Spawn a new process with specified command-line arguments.
static string QuoteArg(const string &arg)
Quote argument.
TProcessHandle GetProcessHandle(void)
Get process handle/pid.
static CResult SpawnLP(EMode mode, const char *cmdname, const char *argv,...)
Spawn a new process with variable number of command-line arguments and find file to execute from the ...
static TExitCode Wait(TProcessHandle handle, unsigned long timeout=kInfiniteTimeoutMs)
Wait until specified process terminates.
static CResult SpawnVPE(EMode mode, const char *cmdname, const char *const *argv, const char *const *envp)
Spawn a new process with variable number of command-line arguments and specified environment settings...
static CResult SpawnV(EMode mode, const char *cmdname, const char *const *argv)
Spawn a new process with variable number of command-line arguments.
static CResult SpawnVP(EMode mode, const char *cmdname, const char *const *argv)
Spawn a new process with variable number of command-line arguments and find file to execute from the ...
static CResult SpawnLE(EMode mode, const char *cmdname, const char *argv,...)
Spawn a new process with specified command-line arguments and environment settings.
EWaitMode
Mode used to wait processes termination.
static CResult SpawnVE(EMode mode, const char *cmdname, const char *const *argv, const char *const *envp)
Spawn a new process with variable number of command-line arguments and specified environment settings...
TFlags m_Flags
What m_Result stores.
@ fModeMask
Mask for all master modes, all EModeFlags must be above it.
@ fNewGroup
After fork() move a process to new group (assign new PGID).
@ eWait
Suspends calling thread until execution of new process is complete (synchronous operation).
@ eDetach
Like eNoWait, continues to execute calling process; new process is run in background with no access t...
@ eOverlay
Overlays calling process with new process, destroying calling process.
@ eNoWait
Continues to execute calling process concurrently with new process (asynchronous process).
@ eWaitAny
Wait any process to terminate.
@ eWaitAll
Wait all processes to terminate.
static string NormalizePath(const string &path, EFollowLinks follow_links=eIgnoreLinks)
Normalize a path.
static bool IsAbsolutePath(const string &path)
Check if a "path" is absolute for the current OS.
static string MakePath(const string &dir=kEmptyStr, const string &base=kEmptyStr, const string &ext=kEmptyStr)
Assemble a path from basic components.
static char GetPathSeparator(void)
Get path separator symbol specific for the current platform.
static string GetCwd(void)
Get the current working directory.
static void SplitPath(const string &path, string *dir=0, string *base=0, string *ext=0)
Split a path string into its basic components.
@ fExecute
Execute / List(directory) permission.
uint64_t Uint8
8-byte (64-bit) unsigned integer
const unsigned long kInfiniteTimeoutMs
Infinite timeout in milliseconds.
int Wait(unsigned long timeout=kInfiniteTimeoutMs, CExitInfo *info=0) const
Wait until process terminates.
@ eHandle
A process handle (MS Windows).
#define END_NCBI_SCOPE
End previously defined NCBI scope.
#define BEGIN_NCBI_SCOPE
Define ncbi namespace.
static list< string > & Split(const CTempString str, const CTempString delim, list< string > &arr, TSplitFlags flags=0, vector< SIZE_TYPE > *token_pos=NULL)
Split a string using specified delimiters.
@ fSplit_MergeDelimiters
Merge adjacent delimiters.
unsigned int
A callback function used to compare two keys in a database.
Definition of all error codes used in corelib (xncbi.lib).
void SleepMilliSec(unsigned long ml_sec, EInterruptOnSignal onsignal=eRestartOnSignal)
void s_Create_Args_L(vector< TXString > &xargs, TXArgsOrEnv &t_args, va_list &begin, const char *cmdname, const char *argv)
void s_Create_Env(vector< TXString > &xargs, TXArgsOrEnv &t_args, const char **begin)
string s_QuoteSpawnArg(const string &arg)
static int s_SpawnUnix(ESpawnFunc func, CExec::EMode full_mode, const char *cmdname, const char *const *argv, const char *const *envp=(const char *const *) 0)
#define XGET_EXEC_ARGS(name, ptr)
static int s_GetRealMode(CExec::EMode mode)
void s_Create_Args_V(vector< TXString > &xargs, TXArgsOrEnv &t_args, const char *cmdname, const char **argv)
#define XGET_PTR_ENVP(name, ptr)
AutoPtr< const TXChar *, TXArgsDeleter > TXArgsOrEnv
#define RETURN_RESULT(func)
#define XGET_PTR_ARGS(name, ptr)
#define s_CheckExecArg(x)
const unsigned long kWaitPrecision
#define XGET_EXEC_ENVP(name)
ArrayDeleter< const TXChar * > TXArgsDeleter
Defines a portable execute class.
Defines classes: CDirEntry, CFile, CDir, CSymLink, CMemoryFile, CFileUtil, CFileLock,...
double f(double x_, const double &y_)
Functor template for deleting array of objects.