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