#include "SysExec.h" #include "ArgEnv.h" #ifdef PLATFORM_POSIX #include #include #include "SudoLib.h" #else #include #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 &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 char **argv = BuildArgs(command, args); 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 = */ (void)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 = */(void)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 &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 &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 &Environ, intptr_t *pid) { // builds the arguments and the environment char **argv = BuildArgs(GetFileName(command), args); 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 &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 &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 &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 &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