ultimatepp/bazaar/SysExec/SysExec.cpp
micio cd8aacf139 Bazaar/SysExec : another ArgEnv fix
git-svn-id: svn://ultimatepp.org/upp/trunk@3086 f0d560ea-af0d-0410-9eb7-867de7ffcac7
2011-01-25 08:47:18 +00:00

321 lines
9.5 KiB
C++

#include "SysExec.h"
#include "ArgEnv.h"
#ifdef PLATFORM_POSIX
#include <unistd.h>
#include <sys/wait.h>
#include "SudoLib.h"
#else
#include <process.h>
#include "ShellLib.h"
#endif
NAMESPACE_UPP
// replacement of tmpfile() -- has problems in windows
static FILE *TempFile(void)
{
String fName = GetTempFileName();
FILE *f = fopen(fName, "w+");
return f;
}
///////////////////////////////////////////////////////////////////////////////////////////////
// executes an external command, passing a command line to it and gathering the output
// from both stdout and stderr
bool SysExec(String const &command, String const &args, const VectorMap<String, String> &Environ, String &OutStr, String &ErrStr)
{
// flushes both stdout and stderr files
fflush(stdout);
fflush(stderr);
// saves stdout stream state
int saveStdout = dup(fileno(stdout));
// creates and opens a temporary file and assigns stdout to it
int OutFile = fileno(TempFile());
dup2(OutFile, 1);
// saves stderr stream state
int saveStderr = dup(fileno(stderr));
// creates and opens a temporary file and assigns stdout to it
int ErrFile = fileno(TempFile());
dup2(ErrFile, 2);
// builds the arguments and the environment
Buffer<char *>argv = BuildArgs(GetFileName(command), args);
Buffer<char *>envv = BuildEnv(Environ);
// executes the command
int result = 0;
#ifdef PLATFORM_POSIX
pid_t pID = fork();
if (pID == 0)
{
// Code only executed by child process
// exec svn, function shall not return if all ok
result = execvpe(command, argv, envv);
// terminates child process
_exit(result);
}
else if (pID < 0)
{
// code executed only if couldn't fork
Cerr() << "Couldn't fork...\n";
result = -1;
}
else
{
// Code only executed by parent process
// waits for parent to terminate
wait(&result);
}
#else
result = _spawnvpe(_P_WAIT, command, argv, envv);
#endif
// flushes both stdout and stderr files
fflush(stdout);
fflush(stderr);
// restores stdout and stderr handles
if(saveStdout != -1)
dup2(saveStdout, 1);
if(saveStderr != -1)
dup2(saveStderr, 2);
if (result == -1)
Cerr() << "Error spawning process\n";
// allocates char buffers and reads out end err data into them
OutStr.Clear();
int OutSize = lseek(OutFile, 0L, SEEK_END);
if (OutSize > 0)
{
char *buf = (char *)malloc(OutSize + 1);
lseek(OutFile, 0L, SEEK_SET);
int dummy = read(OutFile, buf, OutSize);
buf[OutSize] = 0;
OutStr.Cat(buf);
free(buf);
}
ErrStr.Clear();
int ErrSize = lseek(ErrFile, 0L, SEEK_END);
if (ErrSize > 0)
{
char *buf = (char *)malloc(ErrSize + 1);
lseek(ErrFile, 0L, SEEK_SET);
int dummy = read(ErrFile, buf, ErrSize);
buf[ErrSize] = 0;
ErrStr.Cat(buf);
free(buf);
}
// closes files
close(OutFile);
close(ErrFile);
return (!result);
} // END SysExec()
bool SysExec(String const &command, String const &args, String &OutStr, String &ErrStr)
{
return SysExec(command, args, Environment(), OutStr, ErrStr);
} // END SysExec()
bool SysExec(String const &command, String const &args, const VectorMap<String, String> &Environ, String &OutStr)
{
String ErrStr;
return SysExec(command, args, Environ, OutStr, ErrStr);
} // END SysExec()
bool SysExec(String const &command, String const &args, String &OutStr)
{
String ErrStr;
return SysExec(command, args, Environment(), OutStr, ErrStr);
} // END SysExec()
bool SysExec(String const &command, String const &args, const VectorMap<String, String> &Environ)
{
String OutStr, ErrStr;
return SysExec(command, args, Environ, OutStr, ErrStr);
}
bool SysExec(String const &command, String const &args)
{
String OutStr, ErrStr;
return SysExec(command, args, Environment(), OutStr, ErrStr);
} // END SysExec()
///////////////////////////////////////////////////////////////////////////////////////////////
// executes an external command, passing a command line to it without waiting for its termination
// optionally returns pid of started process
bool SysStart(String const &command, String const &args, const VectorMap<String, String> &Environ, intptr_t *pid)
{
// builds the arguments and the environment
Buffer<char *>argv = BuildArgs(GetFileName(command), args);
Buffer<char *>envv = BuildEnv(Environ);
// executes the command
int result = 0;
#ifdef PLATFORM_POSIX
// initializes result in case of successful fork but
// failed execvpe.... so the return value is correct
result = -1;
// forks the process
pid_t pID = fork();
if (pID == 0)
{
// Code only executed by child process
// exec process, function shall not return if all ok
result = execvpe(command, argv, envv);
// terminates child process
_exit(result);
}
else if (pID < 0)
{
// code executed only if couldn't fork
Cerr() << "Couldn't fork...\n";
result = -1;
}
else
{
// Code only executed by parent process
// just return spawned process id
result = getpid();
}
#else
result = _spawnvpe(_P_NOWAIT, command, argv, envv);
#endif
if(pid)
*pid = result;
if (result == -1)
Cerr() << "Error spawning process\n";
return (result != -1 ? true : false);
}
bool SysStart(String const &command, String const &args, intptr_t *pid)
{
return SysStart(command, args, Environment(), pid);
}
///////////////////////////////////////////////////////////////////////////////////////////////
// executes an external command as Admin user, passing a command line to it without waiting for its termination
// it WILL prompt for user intervention on secure systems (linux - Vista+ OSes)
// return true on success, false otherwise
bool SysStartAdmin(String const &password, String const &command, String const &args, const VectorMap<String, String> &Environ)
{
#ifdef PLATFORM_POSIX
// on linux, we must provide the password
return SudoExec("root", password, command + " " + args, Environ, false);
#else
// on windows, no pass should be needed, it'll display the dialog automatically
if(IsUserAdministrator())
return SysStart(command, args, Environ);
else
return ShellExec(command + " " + args, Environ, false);
#endif
}
bool SysStartAdmin(String const &password, String const &command, String const &args)
{
return SysStartAdmin(password, command, args, Environment());
}
///////////////////////////////////////////////////////////////////////////////////////////////
// executes an external command as Admin user, passing a command line to it waiting for its termination
// it WILL prompt for user intervention on secure systems (linux - Vista+ OSes)
// return true on success, false otherwise
bool SysExecAdmin(String const &password, String const &command, String const &args, const VectorMap<String, String> &Environ)
{
#ifdef PLATFORM_POSIX
// on linux, we must provide the password
return SudoExec("root", password, command + " " + args, Environ, true);
#else
// on windows, no pass should be needed, it'll display the dialog automatically
if(IsUserAdministrator())
return SysExec(command, args, Environ);
else
return ShellExec(command + " " + args, Environ, true);
#endif
}
bool SysExecAdmin(String const &password, String const &command, String const &args)
{
return SysExecAdmin(password, command, args, Environment());
}
///////////////////////////////////////////////////////////////////////////////////////////////
// executes an external command as required user, passing a command line to it without waiting for its termination
// on linux, will return an error if password is required AND wrong
// on windows, by now... it just spawn the process without changing security level
// I still shall find a way to go back to user mode on windows
// return true on success, false otherwise
bool SysStartUser(String const &user, String const &password, String const &command, String const &args, const VectorMap<String, String> &Environ)
{
#ifdef PLATFORM_POSIX
// on linux, we must provide the password
return SudoExec(user, password, command + " " + args, Environ, false);
#else
// on windows, don't know a way for re-lowering app level to user one, so I simply spawn a new process
return SysStart(command, args, Environ, NULL);
#endif
}
bool SysStartUser(String const &user, String const &password, String const &command, String const &args)
{
return SysStartUser(user, password, command, args, Environment());
}
///////////////////////////////////////////////////////////////////////////////////////////////
// executes an external command as required user, passing a command line to it waiting for its termination
// on linux, will return an error if password is required AND wrong
// on windows, by now... it just spawn the process without changing security level
// I still shall find a way to go back to user mode on windows
// return true on success, false otherwise
bool SysExecUser(String const &user, String const &password, String const &command, String const &args, const VectorMap<String, String> &Environ)
{
#ifdef PLATFORM_POSIX
// on linux, we must provide the password
return SudoExec(user, password, command + " " + args, Environ, true);
#else
// on windows, don't know a way for re-lowering app level to user one, so I simply spawn a new process
return SysExec(command, args, Environ);
#endif
}
bool SysExecUser(String const &user, String const &password, String const &command, String const &args)
{
return SysExecUser(user, password, command, args, Environment());
}
END_UPP_NAMESPACE