source: box/trunk/lib/server/LocalProcessStream.cpp @ 2597

Revision 2597, 4.4 KB checked in by chris, 2 years ago (diff)

Revert the quotes part of [2588] as it breaks the unit tests.

Make LocalProcessStream? constructor take a std::string& for C++ style.

  • Property svn:eol-style set to native
Line 
1// --------------------------------------------------------------------------
2//
3// File
4//              Name:    LocalProcessStream.cpp
5//              Purpose: Opens a process, and presents stdin/stdout as a stream.
6//              Created: 12/3/04
7//
8// --------------------------------------------------------------------------
9
10#include "Box.h"
11
12#ifdef HAVE_SYS_SOCKET_H
13        #include <sys/socket.h>
14#endif
15
16#ifdef HAVE_UNISTD_H
17        #include <unistd.h>
18#endif
19
20#include "LocalProcessStream.h"
21#include "autogen_ServerException.h"
22#include "Utils.h"
23
24#ifdef WIN32
25        #include "FileStream.h"
26#else
27        #include "SocketStream.h"
28#endif
29
30#include "MemLeakFindOn.h"
31
32#define MAX_ARGUMENTS   64
33
34// --------------------------------------------------------------------------
35//
36// Function
37//              Name:    LocalProcessStream(const char *, pid_t &)
38//              Purpose: Run a new process, and return a stream giving access
39//                       to its stdin and stdout (stdout and stderr on
40//                       Win32). Returns the PID of the new process -- this
41//                       must be waited on at some point to avoid zombies
42//                       (except on Win32).
43//              Created: 12/3/04
44//
45// --------------------------------------------------------------------------
46std::auto_ptr<IOStream> LocalProcessStream(const std::string& rCommandLine,
47        pid_t &rPidOut)
48{
49#ifndef WIN32
50
51        // Split up command
52        std::vector<std::string> command;
53        SplitString(rCommandLine, ' ', command);
54
55        // Build arguments
56        char *args[MAX_ARGUMENTS + 4];
57        {
58                int a = 0;
59                std::vector<std::string>::const_iterator i(command.begin());
60                while(a < MAX_ARGUMENTS && i != command.end())
61                {
62                        args[a++] = (char*)(*(i++)).c_str();
63                }
64                args[a] = NULL;
65        }
66
67        // Create a socket pair to communicate over.
68        int sv[2] = {-1,-1};
69        if(::socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, sv) != 0)
70        {
71                THROW_EXCEPTION(ServerException, SocketPairFailed)
72        }
73       
74        std::auto_ptr<IOStream> stream(new SocketStream(sv[0]));
75
76        // Fork
77        pid_t pid = 0;
78        switch(pid = vfork())
79        {
80        case -1:        // error
81                ::close(sv[0]);
82                ::close(sv[1]);
83                THROW_EXCEPTION(ServerException, ServerForkError)
84                break;
85               
86        case 0:         // child
87                // Close end of the socket not being used
88                ::close(sv[0]);
89                // Duplicate the file handles to stdin and stdout
90                if(sv[1] != 0) ::dup2(sv[1], 0);
91                if(sv[1] != 1) ::dup2(sv[1], 1);
92                // Close the now redundant socket
93                if(sv[1] != 0 && sv[1] != 1)
94                {
95                        ::close(sv[1]);
96                }
97                // Execute command!
98                ::execv(args[0], args);
99                ::_exit(127);   // report error
100                break;
101       
102        default:
103                // just continue...
104                break;
105        }
106       
107        // Close the file descriptor not being used
108        ::close(sv[1]);
109
110        // Return the stream object and PID
111        rPidOut = pid;
112        return stream; 
113
114#else // WIN32
115
116        SECURITY_ATTRIBUTES secAttr; 
117        secAttr.nLength = sizeof(SECURITY_ATTRIBUTES); 
118        secAttr.bInheritHandle = TRUE; 
119        secAttr.lpSecurityDescriptor = NULL; 
120
121        HANDLE writeInChild, readFromChild;
122        if(!CreatePipe(&readFromChild, &writeInChild, &secAttr, 0))
123        {
124                BOX_ERROR("Failed to CreatePipe for child process: " <<
125                        GetErrorMessage(GetLastError()));
126                THROW_EXCEPTION(ServerException, SocketPairFailed)
127        }
128        SetHandleInformation(readFromChild, HANDLE_FLAG_INHERIT, 0);
129
130        PROCESS_INFORMATION procInfo; 
131        STARTUPINFO startupInfo;
132
133        ZeroMemory(&procInfo,    sizeof(procInfo));
134        ZeroMemory(&startupInfo, sizeof(startupInfo));
135        startupInfo.cb         = sizeof(startupInfo);
136        startupInfo.hStdError  = writeInChild;
137        startupInfo.hStdOutput = writeInChild;
138        startupInfo.hStdInput  = INVALID_HANDLE_VALUE;
139        startupInfo.dwFlags   |= STARTF_USESTDHANDLES;
140
141        CHAR* commandLineCopy = (CHAR*)malloc(rCommandLine.size() + 1);
142        strcpy(commandLineCopy, rCommandLine.c_str());
143
144        BOOL result = CreateProcess(NULL, 
145                commandLineCopy, // command line
146                NULL,          // process security attributes
147                NULL,          // primary thread security attributes
148                TRUE,          // handles are inherited
149                0,             // creation flags
150                NULL,          // use parent's environment
151                NULL,          // use parent's current directory
152                &startupInfo,  // STARTUPINFO pointer
153                &procInfo);    // receives PROCESS_INFORMATION
154
155        free(commandLineCopy);
156   
157        if(!result)
158        {
159                BOX_ERROR("Failed to CreateProcess: '" << rCommandLine <<
160                        "': " << GetErrorMessage(GetLastError()));
161                CloseHandle(writeInChild);
162                CloseHandle(readFromChild);
163                THROW_EXCEPTION(ServerException, ServerForkError)
164        }
165
166        CloseHandle(procInfo.hProcess);
167        CloseHandle(procInfo.hThread);
168        CloseHandle(writeInChild);
169
170        rPidOut = (int)(procInfo.dwProcessId);
171
172        std::auto_ptr<IOStream> stream(new FileStream(readFromChild));
173        return stream;
174
175#endif // ! WIN32
176}
177
178
179
180
Note: See TracBrowser for help on using the repository browser.