#include "SysExec.h" #ifdef PLATFORM_POSIX #include #include #define DEFAULT_PATH "/bin:/usr/bin:." static int execvpe(const char *file, char * const *argv, char * const *envp) { char path[PATH_MAX]; const char *searchpath, *esp; size_t prefixlen, filelen, totallen; if (strchr(file, '/')) /* Specific path */ return execve(file, argv, envp); filelen = strlen(file); searchpath = getenv("PATH"); if (!searchpath) searchpath = DEFAULT_PATH; errno = ENOENT; /* Default errno, if execve() doesn't change it */ do { esp = strchr(searchpath, ':'); if (esp) prefixlen = esp - searchpath; else prefixlen = strlen(searchpath); if (prefixlen == 0 || searchpath[prefixlen-1] == '/') { totallen = prefixlen + filelen; if (totallen >= PATH_MAX) continue; memcpy(path, searchpath, prefixlen); memcpy(path + prefixlen, file, filelen); } else { totallen = prefixlen + filelen + 1; if (totallen >= PATH_MAX) continue; memcpy(path, searchpath, prefixlen); path[prefixlen] = '/'; memcpy(path + prefixlen + 1, file, filelen); } path[totallen] = '\0'; execve(path, argv, envp); if (errno == E2BIG || errno == ENOEXEC || errno == ENOMEM || errno == ETXTBSY) break; /* Report this as an error, no more search */ searchpath = esp + 1; } while (esp); return -1; } #else #include #endif NAMESPACE_UPP /////////////////////////////////////////////////////////////////////////////////////////////// // parses an args line to be useable by spawnxx functions static Buffer_BuildArgs(String const &argline) { Array args; int pos = 0; char c; int buflen = 0; // first arg should be command name... let's make it null // it MUST be set, as argv[0] has a special meaning args.Add(""); // skips leading spaces while ((c = argline[pos]) != 0 && isspace(c)) pos++; // loop reading args and putting to array while (c) { String &s = args.Add(); buflen++; while (c && !isspace(c)) { // reads enquoted strings if (c == '"') { c = argline[++pos]; while (c && c != '"') { s << c; buflen++; c = argline[++pos]; } if (c) c = argline[++pos]; } else { s << c; buflen++; c = argline[++pos]; } } // skips trailing spaces while (c && isspace(c)) c = argline[++pos]; } buflen += (args.GetCount() + 1) * sizeof(char *); // here we've got an array of args and the total size (in bytes) of them // we allocates a buffer for arg array Bufferbuf(buflen); // we fill the buffer with arg strings char **bufindex = buf; char *bufpos = (char *)(buf + args.GetCount() + 1); int i = 0; while (i < args.GetCount()) { String &s = args[i]; strcpy(bufpos, (const char *)s); *bufindex++ = bufpos; bufpos += s.GetCount() + 1 ; i++; } *bufindex = 0; // returns array of args return buf; } // END _BuildArgs() /////////////////////////////////////////////////////////////////////////////////////////////// // parses environment map and builds env array static Buffer_BuildEnv(const VectorMap &env = Environment()) { // calculates total environment size int envSize = 0; for (int i = 0; i < env.GetCount(); i++) envSize += env.GetKey(i).GetCount() + env[i].GetCount() + 2 + sizeof(char *); // we allocates a buffer for env array Bufferbuf(envSize); // we fill the buffer with env strings char **bufindex = buf; char *bufpos = (char *)(buf + env.GetCount() + 1); int i = 0; while (i < env.GetCount()) { const String &s = env.GetKey(i) + "=" + env[i]; strcpy(bufpos, (const char *)s); *bufindex++ = bufpos; bufpos += s.GetCount() + 1 ; i++; } *bufindex = 0; // returns array of args return buf; } // END _BuildEnv() /////////////////////////////////////////////////////////////////////////////////////////////// // 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) { FILE *fp; // 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(tmpfile()); 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(tmpfile()); dup2(ErrFile, 2); // builds the arguments and the environment Bufferargv = _BuildArgs(args); Bufferenvv = _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 dup2(saveStdout, 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); 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); 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) { String OutStr, ErrStr; return SysExec(command, args, Environment(), OutStr, ErrStr); } // END SysExec() END_UPP_NAMESPACE