00001 //---------------------------------------------------------------------------- 00002 /** @file SgProcess.cpp 00003 See SgProcess.h */ 00004 //---------------------------------------------------------------------------- 00005 00006 #include "SgSystem.h" 00007 #include "SgProcess.h" 00008 00009 // Not yet implemented for Windows 00010 #ifndef WIN32 00011 00012 #include <errno.h> 00013 #include <fstream> 00014 #include <iostream> 00015 #include <stdio.h> 00016 #include <stdlib.h> 00017 #include <string.h> 00018 #include <sys/types.h> 00019 #include <unistd.h> 00020 #include "SgDebug.h" 00021 #include "SgException.h" 00022 #include "SgStringUtil.h" 00023 00024 using namespace std; 00025 00026 //---------------------------------------------------------------------------- 00027 00028 namespace { 00029 00030 __gnu_cxx::stdio_filebuf<char>* CreateFileBuf(int fileDescriptor, 00031 std::ios_base::openmode mode) 00032 { 00033 #if __GNUC__ == 3 && __GNUC_MINOR__ >= 4 00034 return new __gnu_cxx::stdio_filebuf<char>(fileDescriptor, mode, 00035 static_cast<size_t>(BUFSIZ)); 00036 #elif __GNUC__ == 3 00037 return new __gnu_cxx::stdio_filebuf<char>(fileDescriptor, mode, true, 00038 static_cast<size_t>(BUFSIZ)); 00039 #else 00040 return new __gnu_cxx::stdio_filebuf<char>(fileDescriptor, mode); 00041 #endif 00042 } 00043 00044 void TerminateChild(const char* message) 00045 { 00046 SgDebug() << message << '\n'; 00047 exit(1); 00048 } 00049 00050 } // namespace 00051 00052 //---------------------------------------------------------------------------- 00053 00054 SgProcess::SgProcess(const std::string& command) 00055 { 00056 vector<string> args = SgStringUtil::SplitArguments(command); 00057 if (args.size() == 0) 00058 throw SgException("Empty command line"); 00059 int fd1[2]; 00060 if (pipe(fd1) < 0) 00061 throw SgException("Pipe error"); 00062 int fd2[2]; 00063 if (pipe(fd2) < 0) 00064 { 00065 close(fd1[0]); 00066 close(fd1[1]); 00067 throw SgException("Pipe error"); 00068 } 00069 pid_t pid; 00070 if ((pid = fork()) < 0) 00071 throw SgException("Fork error"); 00072 else if (pid > 0) // Parent 00073 { 00074 close(fd1[0]); 00075 close(fd2[1]); 00076 m_bufOut.reset(CreateFileBuf(fd1[1], ios::out)); 00077 m_out.reset(new ostream(m_bufOut.get())); 00078 m_bufIn.reset(CreateFileBuf(fd2[0], ios::in)); 00079 m_in.reset(new istream(m_bufIn.get())); 00080 return; 00081 } 00082 else // Child 00083 { 00084 close(fd1[1]); 00085 close(fd2[0]); 00086 if (fd1[0] != STDIN_FILENO) 00087 if (dup2(fd1[0], STDIN_FILENO) != STDIN_FILENO) 00088 { 00089 close(fd1[0]); 00090 TerminateChild("Error dup2 to stdin"); 00091 } 00092 if (fd2[1] != STDOUT_FILENO) 00093 if (dup2(fd2[1], STDOUT_FILENO) != STDOUT_FILENO) 00094 { 00095 close(fd2[1]); 00096 TerminateChild("Error dup2 to stdout"); 00097 } 00098 char** const argv = new char*[args.size() + 1]; 00099 for (size_t i = 0; i < args.size(); ++i) 00100 { 00101 argv[i] = new char[args[i].size()]; 00102 strcpy(argv[i], args[i].c_str()); 00103 } 00104 argv[args.size()] = 0; 00105 if (execvp(args[0].c_str(), argv) == -1) 00106 TerminateChild("Error execvp"); 00107 } 00108 } 00109 00110 SgProcess::~SgProcess() 00111 { 00112 } 00113 00114 //---------------------------------------------------------------------------- 00115 00116 #endif // ifndef WIN32