aboutsummaryrefslogtreecommitdiff
path: root/src/stable/process.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/stable/process.cpp')
-rw-r--r--src/stable/process.cpp441
1 files changed, 441 insertions, 0 deletions
diff --git a/src/stable/process.cpp b/src/stable/process.cpp
new file mode 100644
index 0000000..a98936e
--- /dev/null
+++ b/src/stable/process.cpp
@@ -0,0 +1,441 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/process.h"
9#include <sys/types.h>
10#include <sys/wait.h>
11#include <unistd.h>
12#include <stdarg.h>
13#include <signal.h>
14#include <fcntl.h>
15#include <errno.h>
16
17#include <sys/select.h>
18
19#include "bu/config.h"
20
21Bu::Process::Process( Flags eFlags, const char *sName, char *const argv[] ) :
22 iStdIn( -1 ),
23 iStdOut( -1 ),
24 iStdErr( -1 ),
25 iPid( 0 ),
26 iProcStatus( 0 ),
27 bBlocking( true ),
28 bStdOutEos( true ),
29 bStdErrEos( true )
30{
31 gexec( eFlags, sName, argv );
32}
33
34Bu::Process::Process( Flags eFlags, const char *sName, const char *argv, ...) :
35 iStdIn( -1 ),
36 iStdOut( -1 ),
37 iStdErr( -1 ),
38 iPid( 0 ),
39 iProcStatus( 0 ),
40 bBlocking( true ),
41 bStdOutEos( true ),
42 bStdErrEos( true )
43{
44 int iCnt = 0;
45 va_list ap;
46 va_start( ap, argv );
47 for(; va_arg( ap, const char *); iCnt++ ) { }
48 va_end( ap );
49
50 char const **list = new char const *[iCnt+2];
51 va_start( ap, argv );
52 list[0] = argv;
53 for( int j = 1; j <= iCnt; j++ )
54 {
55 list[j] = va_arg( ap, const char *);
56 }
57 list[iCnt+1] = NULL;
58 va_end( ap );
59
60 gexec( eFlags, sName, (char *const *)list );
61 delete[] list;
62}
63
64Bu::Process::Process( Flags eFlags, const Bu::Process::Options &opt, const char *sName, char *const argv[] ) :
65 iStdIn( -1 ),
66 iStdOut( -1 ),
67 iStdErr( -1 ),
68 iPid( 0 ),
69 iProcStatus( 0 ),
70 bBlocking( true ),
71 bStdOutEos( true ),
72 bStdErrEos( true ),
73 opt( opt )
74{
75 gexec( eFlags, sName, argv );
76}
77
78Bu::Process::Process( Flags eFlags, const Bu::Process::Options &opt, const char *sName, const char *argv, ...) :
79 iStdIn( -1 ),
80 iStdOut( -1 ),
81 iStdErr( -1 ),
82 iPid( 0 ),
83 iProcStatus( 0 ),
84 bBlocking( true ),
85 bStdOutEos( true ),
86 bStdErrEos( true ),
87 opt( opt )
88{
89 int iCnt = 0;
90 va_list ap;
91 va_start( ap, argv );
92 for(; va_arg( ap, const char *); iCnt++ ) { }
93 va_end( ap );
94
95 char const **list = new char const *[iCnt+2];
96 va_start( ap, argv );
97 list[0] = argv;
98 for( int j = 1; j <= iCnt; j++ )
99 {
100 list[j] = va_arg( ap, const char *);
101 }
102 list[iCnt+1] = NULL;
103 va_end( ap );
104
105 gexec( eFlags, sName, (char *const *)list );
106 delete[] list;
107}
108
109Bu::Process::~Process()
110{
111 close();
112}
113
114void Bu::Process::wait()
115{
116 close();
117}
118
119void Bu::Process::gexec( Flags eFlags, const char *sName, char *const argv[] )
120{
121 int iaStdIn[2];
122 int iaStdOut[2];
123 int iaStdErr[2];
124 pipe( iaStdIn );
125 if( eFlags & StdOut )
126 {
127 pipe( iaStdOut );
128 iStdOut = iaStdOut[0];
129 bStdOutEos = false;
130 }
131 if( eFlags & StdErr )
132 {
133 pipe( iaStdErr );
134 iStdErr = iaStdErr[0];
135 bStdErrEos = false;
136 }
137
138 iStdIn = iaStdIn[1];
139
140// fcntl( iStdOut, F_SETFL, fcntl( iStdOut, F_GETFL, 0 )|O_NONBLOCK );
141
142 iPid = fork();
143 if( iPid == 0 )
144 {
145 ::close( iaStdIn[1] );
146 dup2( iaStdIn[0], 0 );
147 if( eFlags & StdOut )
148 {
149 ::close( iaStdOut[0] );
150 dup2( iaStdOut[1], 1 );
151 }
152 if( eFlags & StdErr )
153 {
154 ::close( iaStdErr[0] );
155 dup2( iaStdErr[1], 2 );
156 }
157 if( (opt.eFlags&Options::SetGid) )
158 {
159 setgid( opt.iGid );
160 }
161 if( (opt.eFlags&Options::SetUid) )
162 {
163 setuid( opt.iUid );
164 }
165 execvp( sName, argv );
166 throw Bu::ExceptionBase("Hey, execvp failed!");
167 }
168 ::close( iaStdIn[0] );
169 if( eFlags & StdOut )
170 ::close( iaStdOut[1] );
171 if( eFlags & StdErr )
172 ::close( iaStdErr[1] );
173}
174
175void Bu::Process::close()
176{
177 if( iPid )
178 {
179 if( iStdIn > -1 )
180 ::close( iStdIn );
181 if( iStdOut > -1 )
182 ::close( iStdOut );
183 if( iStdErr > -1 )
184 ::close( iStdErr );
185 waitpid( iPid, &iProcStatus, 0 );
186 iPid = 0;
187 }
188}
189
190void Bu::Process::closeStdIn()
191{
192 ::close( iStdIn );
193 iStdIn = -1;
194}
195
196void Bu::Process::closeStdOut()
197{
198 ::close( iStdOut );
199 iStdOut = -1;
200}
201
202Bu::size Bu::Process::read( void *pBuf, Bu::size nBytes )
203{
204 if( bStdOutEos )
205 return 0;
206 fd_set rfds;
207 FD_ZERO( &rfds );
208 FD_SET( iStdOut, &rfds );
209 struct timeval tv = {0, 0};
210 if( ::bu_select( iStdOut+1, &rfds, NULL, NULL, &tv ) < 0 )
211 throw Bu::ExceptionBase( strerror( errno ) );
212 if( FD_ISSET( iStdOut, &rfds ) || bBlocking )
213 {
214 Bu::size nRead = TEMP_FAILURE_RETRY( ::read( iStdOut, pBuf, nBytes ) );
215 if( nRead == 0 )
216 {
217 bStdOutEos = true;
218 checkClose();
219 return 0;
220 }
221 if( nRead < 0 )
222 {
223 if( errno == EAGAIN )
224 return 0;
225 throw Bu::ExceptionBase( strerror( errno ) );
226 }
227 return nRead;
228 }
229 return 0;
230}
231
232Bu::size Bu::Process::readErr( void *pBuf, Bu::size nBytes )
233{
234 if( bStdErrEos )
235 return 0;
236 fd_set rfds;
237 FD_ZERO( &rfds );
238 FD_SET( iStdErr, &rfds );
239 struct timeval tv = {0, 0};
240 if( ::bu_select( iStdErr+1, &rfds, NULL, NULL, &tv ) < 0 )
241 throw Bu::ExceptionBase( strerror( errno ) );
242 if( FD_ISSET( iStdErr, &rfds ) || bBlocking )
243 {
244 Bu::size nRead = TEMP_FAILURE_RETRY( ::read( iStdErr, pBuf, nBytes ) );
245 if( nRead == 0 )
246 {
247 bStdErrEos = true;
248 checkClose();
249 return 0;
250 }
251 if( nRead < 0 )
252 {
253 if( errno == EAGAIN )
254 return 0;
255 throw Bu::ExceptionBase( strerror( errno ) );
256 }
257 return nRead;
258 }
259 return 0;
260}
261
262Bu::size Bu::Process::write( const void *pBuf, Bu::size nBytes )
263{
264 return TEMP_FAILURE_RETRY( ::write( iStdIn, pBuf, nBytes ) );
265}
266
267Bu::size Bu::Process::tell()
268{
269 return 0;
270}
271
272void Bu::Process::seek( Bu::size )
273{
274}
275
276void Bu::Process::setPos( Bu::size )
277{
278}
279
280void Bu::Process::setPosEnd( Bu::size )
281{
282}
283
284bool Bu::Process::isEos()
285{
286 return (iPid == 0);
287}
288
289bool Bu::Process::isOpen()
290{
291 return (iPid != 0);
292}
293
294void Bu::Process::flush()
295{
296}
297
298bool Bu::Process::canRead()
299{
300 return true;
301}
302
303bool Bu::Process::canWrite()
304{
305 return true;
306}
307
308bool Bu::Process::isReadable()
309{
310 return true;
311}
312
313bool Bu::Process::isWritable()
314{
315 return true;
316}
317
318bool Bu::Process::isSeekable()
319{
320 return false;
321}
322
323bool Bu::Process::isBlocking()
324{
325 return true;
326}
327
328void Bu::Process::setBlocking( bool bBlocking )
329{
330 if( bBlocking )
331 {
332 if( !bStdOutEos )
333 fcntl( iStdOut, F_SETFL, fcntl(iStdOut,F_GETFL,0 )&(~O_NONBLOCK) );
334 if( !bStdErrEos )
335 fcntl( iStdErr, F_SETFL, fcntl(iStdErr,F_GETFL,0 )&(~O_NONBLOCK) );
336 }
337 else
338 {
339 if( !bStdOutEos )
340 fcntl( iStdOut, F_SETFL, fcntl( iStdOut, F_GETFL, 0 )|O_NONBLOCK );
341 if( !bStdErrEos )
342 fcntl( iStdErr, F_SETFL, fcntl( iStdErr, F_GETFL, 0 )|O_NONBLOCK );
343 }
344 this->bBlocking = bBlocking;
345}
346
347void Bu::Process::setSize( Bu::size )
348{
349}
350
351Bu::size Bu::Process::getBlockSize() const
352{
353 return 0;
354}
355
356Bu::size Bu::Process::getSize() const
357{
358 return 0;
359}
360
361Bu::String Bu::Process::getLocation() const
362{
363 return "";
364}
365
366void Bu::Process::select( bool &bStdOut, bool &bStdErr )
367{
368 fd_set rfds;
369 FD_ZERO( &rfds );
370 if( !bStdOutEos )
371 FD_SET( iStdOut, &rfds );
372 if( !bStdErrEos )
373 FD_SET( iStdErr, &rfds );
374 if( ::bu_select( iStdErr+1, &rfds, NULL, NULL, NULL ) < 0 )
375 throw Bu::ExceptionBase( strerror( errno ) );
376
377 if( FD_ISSET( iStdOut, &rfds ) )
378 bStdOut = true;
379 else
380 bStdOut = false;
381
382 if( FD_ISSET( iStdErr, &rfds ) )
383 bStdErr = true;
384 else
385 bStdErr = false;
386}
387
388bool Bu::Process::isRunning()
389{
390 if( waitpid( iPid, NULL, WNOHANG ) == iPid )
391 checkClose();
392 return iPid != 0;
393}
394
395void Bu::Process::ignoreStdErr()
396{
397 if( iStdErr == -1 )
398 return;
399 ::close( iStdErr );
400 iStdErr = -1;
401 bStdErrEos = true;
402}
403
404pid_t Bu::Process::getPid()
405{
406 return iPid;
407}
408
409bool Bu::Process::childExited()
410{
411 return WIFEXITED( iProcStatus );
412}
413
414int Bu::Process::childExitStatus()
415{
416 return WEXITSTATUS( iProcStatus );
417}
418
419bool Bu::Process::childSignaled()
420{
421 return WIFSIGNALED( iProcStatus );
422}
423
424int Bu::Process::childSignal()
425{
426 return WTERMSIG( iProcStatus );
427}
428
429bool Bu::Process::childCoreDumped()
430{
431 return WCOREDUMP( iProcStatus );
432}
433
434void Bu::Process::checkClose()
435{
436 if( bStdOutEos && bStdErrEos )
437 {
438 close();
439 }
440}
441