summaryrefslogtreecommitdiff
Unidiff
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--libopie2/examples/opiecore/opiecore.pro2
-rw-r--r--libopie2/examples/opiecore/oprocessdemo/.cvsignore6
-rw-r--r--libopie2/examples/opiecore/oprocessdemo/oprocessdemo.cpp11
-rw-r--r--libopie2/examples/opiecore/oprocessdemo/oprocessdemo.pro12
-rw-r--r--libopie2/opiecore/oprocess.cpp30
-rw-r--r--libopie2/opiecore/oprocess.h5
6 files changed, 65 insertions, 1 deletions
diff --git a/libopie2/examples/opiecore/opiecore.pro b/libopie2/examples/opiecore/opiecore.pro
index 8f3aedc..ec14be0 100644
--- a/libopie2/examples/opiecore/opiecore.pro
+++ b/libopie2/examples/opiecore/opiecore.pro
@@ -1,3 +1,3 @@
1TEMPLATE = subdirs 1TEMPLATE = subdirs
2unix:SUBDIRS = odebugdemo oconfigdemo oglobalsettingsdemo 2unix:SUBDIRS = odebugdemo oconfigdemo oglobalsettingsdemo oprocessdemo
3 3
diff --git a/libopie2/examples/opiecore/oprocessdemo/.cvsignore b/libopie2/examples/opiecore/oprocessdemo/.cvsignore
new file mode 100644
index 0000000..8f7300c
--- a/dev/null
+++ b/libopie2/examples/opiecore/oprocessdemo/.cvsignore
@@ -0,0 +1,6 @@
1Makefile*
2moc*
3*moc
4*.o
5~*
6
diff --git a/libopie2/examples/opiecore/oprocessdemo/oprocessdemo.cpp b/libopie2/examples/opiecore/oprocessdemo/oprocessdemo.cpp
new file mode 100644
index 0000000..0abf53e
--- a/dev/null
+++ b/libopie2/examples/opiecore/oprocessdemo/oprocessdemo.cpp
@@ -0,0 +1,11 @@
1#include <opie2/oprocess.h>
2#include <iostream.h>
3
4int main( int argc, char** argv )
5{
6 printf( "my own PID seems to be '%d'\n", OProcess::processPID( "oprocessdemo" ) );
7 printf( "the PID of process 'Mickey' seems to be '%d'\n\n", OProcess::processPID( "Mickey" ) );
8
9 return 0;
10}
11
diff --git a/libopie2/examples/opiecore/oprocessdemo/oprocessdemo.pro b/libopie2/examples/opiecore/oprocessdemo/oprocessdemo.pro
new file mode 100644
index 0000000..72dac7f
--- a/dev/null
+++ b/libopie2/examples/opiecore/oprocessdemo/oprocessdemo.pro
@@ -0,0 +1,12 @@
1TEMPLATE = app
2CONFIG = qt warn_on debug
3HEADERS =
4SOURCES = oprocessdemo.cpp
5INCLUDEPATH += $(OPIEDIR)/include
6DEPENDPATH += $(OPIEDIR)/include
7LIBS += -lopiecore2
8TARGET = oprocessdemo
9
10include ( $(OPIEDIR)/include.pro )
11
12
diff --git a/libopie2/opiecore/oprocess.cpp b/libopie2/opiecore/oprocess.cpp
index f1a5f3b..5cfcf32 100644
--- a/libopie2/opiecore/oprocess.cpp
+++ b/libopie2/opiecore/oprocess.cpp
@@ -1,915 +1,945 @@
1/* 1/*
2                This file is part of the Opie Project 2                This file is part of the Opie Project
3             Copyright (C) 2002-2004 Holger Freyther <zecke@handhelds.org> 3             Copyright (C) 2002-2004 Holger Freyther <zecke@handhelds.org>
4 and The Opie Team <opie-devel@handhelds.org> 4 and The Opie Team <opie-devel@handhelds.org>
5 =. Based on KProcess (C) 1997 Christian Czezatke (e9025461@student.tuwien.ac.at) 5 =. Based on KProcess (C) 1997 Christian Czezatke (e9025461@student.tuwien.ac.at)
6 .=l. 6 .=l.
7          .>+-= 7          .>+-=
8_;:,     .>    :=|. This program is free software; you can 8_;:,     .>    :=|. This program is free software; you can
9.> <`_,   >  .   <= redistribute it and/or modify it under 9.> <`_,   >  .   <= redistribute it and/or modify it under
10:`=1 )Y*s>-.--   : the terms of the GNU Library General Public 10:`=1 )Y*s>-.--   : the terms of the GNU Library General Public
11.="- .-=="i,     .._ License as published by the Free Software 11.="- .-=="i,     .._ License as published by the Free Software
12- .   .-<_>     .<> Foundation; either version 2 of the License, 12- .   .-<_>     .<> Foundation; either version 2 of the License,
13    ._= =}       : or (at your option) any later version. 13    ._= =}       : or (at your option) any later version.
14   .%`+i>       _;_. 14   .%`+i>       _;_.
15   .i_,=:_.      -<s. This program is distributed in the hope that 15   .i_,=:_.      -<s. This program is distributed in the hope that
16    +  .  -:.       = it will be useful, but WITHOUT ANY WARRANTY; 16    +  .  -:.       = it will be useful, but WITHOUT ANY WARRANTY;
17   : ..    .:,     . . . without even the implied warranty of 17   : ..    .:,     . . . without even the implied warranty of
18   =_        +     =;=|` MERCHANTABILITY or FITNESS FOR A 18   =_        +     =;=|` MERCHANTABILITY or FITNESS FOR A
19 _.=:.       :    :=>`: PARTICULAR PURPOSE. See the GNU 19 _.=:.       :    :=>`: PARTICULAR PURPOSE. See the GNU
20..}^=.=       =       ; Library General Public License for more 20..}^=.=       =       ; Library General Public License for more
21++=   -.     .`     .: details. 21++=   -.     .`     .: details.
22:     =  ...= . :.=- 22:     =  ...= . :.=-
23-.   .:....=;==+<; You should have received a copy of the GNU 23-.   .:....=;==+<; You should have received a copy of the GNU
24 -_. . .   )=.  = Library General Public License along with 24 -_. . .   )=.  = Library General Public License along with
25   --        :-=` this library; see the file COPYING.LIB. 25   --        :-=` this library; see the file COPYING.LIB.
26 If not, write to the Free Software Foundation, 26 If not, write to the Free Software Foundation,
27 Inc., 59 Temple Place - Suite 330, 27 Inc., 59 Temple Place - Suite 330,
28 Boston, MA 02111-1307, USA. 28 Boston, MA 02111-1307, USA.
29*/ 29*/
30 30
31#include "oprocctrl.h" 31#include "oprocctrl.h"
32 32
33/* OPIE */ 33/* OPIE */
34#include <opie2/oprocess.h> 34#include <opie2/oprocess.h>
35 35
36/* QT */ 36/* QT */
37 37
38#include <qapplication.h> 38#include <qapplication.h>
39#include <qdir.h>
39#include <qfile.h> 40#include <qfile.h>
40#include <qmap.h> 41#include <qmap.h>
41#include <qregexp.h> 42#include <qregexp.h>
42#include <qsocketnotifier.h> 43#include <qsocketnotifier.h>
44#include <qtextstream.h>
43 45
44/* STD */ 46/* STD */
45#include <errno.h> 47#include <errno.h>
46#include <fcntl.h> 48#include <fcntl.h>
47#include <pwd.h> 49#include <pwd.h>
48#include <stdlib.h> 50#include <stdlib.h>
49#include <signal.h> 51#include <signal.h>
50#include <stdio.h> 52#include <stdio.h>
51#include <string.h> 53#include <string.h>
52#include <sys/time.h> 54#include <sys/time.h>
53#include <sys/types.h> 55#include <sys/types.h>
54#include <sys/stat.h> 56#include <sys/stat.h>
55#include <sys/socket.h> 57#include <sys/socket.h>
56#include <unistd.h> 58#include <unistd.h>
57#ifdef HAVE_SYS_SELECT_H 59#ifdef HAVE_SYS_SELECT_H
58#include <sys/select.h> 60#include <sys/select.h>
59#endif 61#endif
60#ifdef HAVE_INITGROUPS 62#ifdef HAVE_INITGROUPS
61#include <grp.h> 63#include <grp.h>
62#endif 64#endif
63 65
64class OProcessPrivate 66class OProcessPrivate
65{ 67{
66public: 68public:
67 OProcessPrivate() : useShell( false ) 69 OProcessPrivate() : useShell( false )
68 { } 70 { }
69 71
70 bool useShell; 72 bool useShell;
71 QMap<QString, QString> env; 73 QMap<QString, QString> env;
72 QString wd; 74 QString wd;
73 QCString shell; 75 QCString shell;
74}; 76};
75 77
76 78
77OProcess::OProcess( QObject *parent, const char *name ) 79OProcess::OProcess( QObject *parent, const char *name )
78 : QObject( parent, name ) 80 : QObject( parent, name )
79{ 81{
80 init ( ); 82 init ( );
81} 83}
82 84
83OProcess::OProcess( const QString &arg0, QObject *parent, const char *name ) 85OProcess::OProcess( const QString &arg0, QObject *parent, const char *name )
84 : QObject( parent, name ) 86 : QObject( parent, name )
85{ 87{
86 init ( ); 88 init ( );
87 *this << arg0; 89 *this << arg0;
88} 90}
89 91
90OProcess::OProcess( const QStringList &args, QObject *parent, const char *name ) 92OProcess::OProcess( const QStringList &args, QObject *parent, const char *name )
91 : QObject( parent, name ) 93 : QObject( parent, name )
92{ 94{
93 init ( ); 95 init ( );
94 *this << args; 96 *this << args;
95} 97}
96 98
97void OProcess::init ( ) 99void OProcess::init ( )
98{ 100{
99 run_mode = NotifyOnExit; 101 run_mode = NotifyOnExit;
100 runs = false; 102 runs = false;
101 pid_ = 0; 103 pid_ = 0;
102 status = 0; 104 status = 0;
103 keepPrivs = false; 105 keepPrivs = false;
104 innot = 0; 106 innot = 0;
105 outnot = 0; 107 outnot = 0;
106 errnot = 0; 108 errnot = 0;
107 communication = NoCommunication; 109 communication = NoCommunication;
108 input_data = 0; 110 input_data = 0;
109 input_sent = 0; 111 input_sent = 0;
110 input_total = 0; 112 input_total = 0;
111 d = 0; 113 d = 0;
112 114
113 if ( 0 == OProcessController::theOProcessController ) 115 if ( 0 == OProcessController::theOProcessController )
114 { 116 {
115 ( void ) new OProcessController(); 117 ( void ) new OProcessController();
116 CHECK_PTR( OProcessController::theOProcessController ); 118 CHECK_PTR( OProcessController::theOProcessController );
117 } 119 }
118 120
119 OProcessController::theOProcessController->addOProcess( this ); 121 OProcessController::theOProcessController->addOProcess( this );
120 out[ 0 ] = out[ 1 ] = -1; 122 out[ 0 ] = out[ 1 ] = -1;
121 in[ 0 ] = in[ 1 ] = -1; 123 in[ 0 ] = in[ 1 ] = -1;
122 err[ 0 ] = err[ 1 ] = -1; 124 err[ 0 ] = err[ 1 ] = -1;
123} 125}
124 126
125void OProcess::setEnvironment( const QString &name, const QString &value ) 127void OProcess::setEnvironment( const QString &name, const QString &value )
126{ 128{
127 if ( !d ) 129 if ( !d )
128 d = new OProcessPrivate; 130 d = new OProcessPrivate;
129 d->env.insert( name, value ); 131 d->env.insert( name, value );
130} 132}
131 133
132void OProcess::setWorkingDirectory( const QString &dir ) 134void OProcess::setWorkingDirectory( const QString &dir )
133{ 135{
134 if ( !d ) 136 if ( !d )
135 d = new OProcessPrivate; 137 d = new OProcessPrivate;
136 d->wd = dir; 138 d->wd = dir;
137} 139}
138 140
139void OProcess::setupEnvironment() 141void OProcess::setupEnvironment()
140{ 142{
141 if ( d ) 143 if ( d )
142 { 144 {
143 QMap<QString, QString>::Iterator it; 145 QMap<QString, QString>::Iterator it;
144 for ( it = d->env.begin(); it != d->env.end(); ++it ) 146 for ( it = d->env.begin(); it != d->env.end(); ++it )
145 setenv( QFile::encodeName( it.key() ).data(), 147 setenv( QFile::encodeName( it.key() ).data(),
146 QFile::encodeName( it.data() ).data(), 1 ); 148 QFile::encodeName( it.data() ).data(), 1 );
147 if ( !d->wd.isEmpty() ) 149 if ( !d->wd.isEmpty() )
148 chdir( QFile::encodeName( d->wd ).data() ); 150 chdir( QFile::encodeName( d->wd ).data() );
149 } 151 }
150} 152}
151 153
152void OProcess::setRunPrivileged( bool keepPrivileges ) 154void OProcess::setRunPrivileged( bool keepPrivileges )
153{ 155{
154 keepPrivs = keepPrivileges; 156 keepPrivs = keepPrivileges;
155} 157}
156 158
157bool OProcess::runPrivileged() const 159bool OProcess::runPrivileged() const
158{ 160{
159 return keepPrivs; 161 return keepPrivs;
160} 162}
161 163
162OProcess::~OProcess() 164OProcess::~OProcess()
163{ 165{
164 // destroying the OProcess instance sends a SIGKILL to the 166 // destroying the OProcess instance sends a SIGKILL to the
165 // child process (if it is running) after removing it from the 167 // child process (if it is running) after removing it from the
166 // list of valid processes (if the process is not started as 168 // list of valid processes (if the process is not started as
167 // "DontCare") 169 // "DontCare")
168 170
169 OProcessController::theOProcessController->removeOProcess( this ); 171 OProcessController::theOProcessController->removeOProcess( this );
170 // this must happen before we kill the child 172 // this must happen before we kill the child
171 // TODO: block the signal while removing the current process from the process list 173 // TODO: block the signal while removing the current process from the process list
172 174
173 if ( runs && ( run_mode != DontCare ) ) 175 if ( runs && ( run_mode != DontCare ) )
174 kill( SIGKILL ); 176 kill( SIGKILL );
175 177
176 // Clean up open fd's and socket notifiers. 178 // Clean up open fd's and socket notifiers.
177 closeStdin(); 179 closeStdin();
178 closeStdout(); 180 closeStdout();
179 closeStderr(); 181 closeStderr();
180 182
181 // TODO: restore SIGCHLD and SIGPIPE handler if this is the last OProcess 183 // TODO: restore SIGCHLD and SIGPIPE handler if this is the last OProcess
182 delete d; 184 delete d;
183} 185}
184 186
185void OProcess::detach() 187void OProcess::detach()
186{ 188{
187 OProcessController::theOProcessController->removeOProcess( this ); 189 OProcessController::theOProcessController->removeOProcess( this );
188 190
189 runs = false; 191 runs = false;
190 pid_ = 0; 192 pid_ = 0;
191 193
192 // Clean up open fd's and socket notifiers. 194 // Clean up open fd's and socket notifiers.
193 closeStdin(); 195 closeStdin();
194 closeStdout(); 196 closeStdout();
195 closeStderr(); 197 closeStderr();
196} 198}
197 199
198bool OProcess::setExecutable( const QString& proc ) 200bool OProcess::setExecutable( const QString& proc )
199{ 201{
200 if ( runs ) 202 if ( runs )
201 return false; 203 return false;
202 204
203 if ( proc.isEmpty() ) 205 if ( proc.isEmpty() )
204 return false; 206 return false;
205 207
206 if ( !arguments.isEmpty() ) 208 if ( !arguments.isEmpty() )
207 arguments.remove( arguments.begin() ); 209 arguments.remove( arguments.begin() );
208 arguments.prepend( QFile::encodeName( proc ) ); 210 arguments.prepend( QFile::encodeName( proc ) );
209 211
210 return true; 212 return true;
211} 213}
212 214
213OProcess &OProcess::operator<<( const QStringList& args ) 215OProcess &OProcess::operator<<( const QStringList& args )
214{ 216{
215 QStringList::ConstIterator it = args.begin(); 217 QStringList::ConstIterator it = args.begin();
216 for ( ; it != args.end() ; ++it ) 218 for ( ; it != args.end() ; ++it )
217 arguments.append( QFile::encodeName( *it ) ); 219 arguments.append( QFile::encodeName( *it ) );
218 return *this; 220 return *this;
219} 221}
220 222
221OProcess &OProcess::operator<<( const QCString& arg ) 223OProcess &OProcess::operator<<( const QCString& arg )
222{ 224{
223 return operator<< ( arg.data() ); 225 return operator<< ( arg.data() );
224} 226}
225 227
226OProcess &OProcess::operator<<( const char* arg ) 228OProcess &OProcess::operator<<( const char* arg )
227{ 229{
228 arguments.append( arg ); 230 arguments.append( arg );
229 return *this; 231 return *this;
230} 232}
231 233
232OProcess &OProcess::operator<<( const QString& arg ) 234OProcess &OProcess::operator<<( const QString& arg )
233{ 235{
234 arguments.append( QFile::encodeName( arg ) ); 236 arguments.append( QFile::encodeName( arg ) );
235 return *this; 237 return *this;
236} 238}
237 239
238void OProcess::clearArguments() 240void OProcess::clearArguments()
239{ 241{
240 arguments.clear(); 242 arguments.clear();
241} 243}
242 244
243bool OProcess::start( RunMode runmode, Communication comm ) 245bool OProcess::start( RunMode runmode, Communication comm )
244{ 246{
245 uint i; 247 uint i;
246 uint n = arguments.count(); 248 uint n = arguments.count();
247 char **arglist; 249 char **arglist;
248 250
249 if ( runs || ( 0 == n ) ) 251 if ( runs || ( 0 == n ) )
250 { 252 {
251 return false; // cannot start a process that is already running 253 return false; // cannot start a process that is already running
252 // or if no executable has been assigned 254 // or if no executable has been assigned
253 } 255 }
254 run_mode = runmode; 256 run_mode = runmode;
255 status = 0; 257 status = 0;
256 258
257 QCString shellCmd; 259 QCString shellCmd;
258 if ( d && d->useShell ) 260 if ( d && d->useShell )
259 { 261 {
260 if ( d->shell.isEmpty() ) 262 if ( d->shell.isEmpty() )
261 { 263 {
262 qWarning( "Could not find a valid shell" ); 264 qWarning( "Could not find a valid shell" );
263 return false; 265 return false;
264 } 266 }
265 267
266 arglist = static_cast<char **>( malloc( ( 4 ) * sizeof( char * ) ) ); 268 arglist = static_cast<char **>( malloc( ( 4 ) * sizeof( char * ) ) );
267 for ( i = 0; i < n; i++ ) 269 for ( i = 0; i < n; i++ )
268 { 270 {
269 shellCmd += arguments[ i ]; 271 shellCmd += arguments[ i ];
270 shellCmd += " "; // CC: to separate the arguments 272 shellCmd += " "; // CC: to separate the arguments
271 } 273 }
272 274
273 arglist[ 0 ] = d->shell.data(); 275 arglist[ 0 ] = d->shell.data();
274 arglist[ 1 ] = ( char * ) "-c"; 276 arglist[ 1 ] = ( char * ) "-c";
275 arglist[ 2 ] = shellCmd.data(); 277 arglist[ 2 ] = shellCmd.data();
276 arglist[ 3 ] = 0; 278 arglist[ 3 ] = 0;
277 } 279 }
278 else 280 else
279 { 281 {
280 arglist = static_cast<char **>( malloc( ( n + 1 ) * sizeof( char * ) ) ); 282 arglist = static_cast<char **>( malloc( ( n + 1 ) * sizeof( char * ) ) );
281 for ( i = 0; i < n; i++ ) 283 for ( i = 0; i < n; i++ )
282 arglist[ i ] = arguments[ i ].data(); 284 arglist[ i ] = arguments[ i ].data();
283 arglist[ n ] = 0; 285 arglist[ n ] = 0;
284 } 286 }
285 287
286 if ( !setupCommunication( comm ) ) 288 if ( !setupCommunication( comm ) )
287 qWarning( "Could not setup Communication!" ); 289 qWarning( "Could not setup Communication!" );
288 290
289 // We do this in the parent because if we do it in the child process 291 // We do this in the parent because if we do it in the child process
290 // gdb gets confused when the application runs from gdb. 292 // gdb gets confused when the application runs from gdb.
291 uid_t uid = getuid(); 293 uid_t uid = getuid();
292 gid_t gid = getgid(); 294 gid_t gid = getgid();
293#ifdef HAVE_INITGROUPS 295#ifdef HAVE_INITGROUPS
294 296
295 struct passwd *pw = getpwuid( uid ); 297 struct passwd *pw = getpwuid( uid );
296#endif 298#endif
297 299
298 int fd[ 2 ]; 300 int fd[ 2 ];
299 if ( 0 > pipe( fd ) ) 301 if ( 0 > pipe( fd ) )
300 { 302 {
301 fd[ 0 ] = fd[ 1 ] = 0; // Pipe failed.. continue 303 fd[ 0 ] = fd[ 1 ] = 0; // Pipe failed.. continue
302 } 304 }
303 305
304 runs = true; 306 runs = true;
305 307
306 QApplication::flushX(); 308 QApplication::flushX();
307 309
308 // WABA: Note that we use fork() and not vfork() because 310 // WABA: Note that we use fork() and not vfork() because
309 // vfork() has unclear semantics and is not standardized. 311 // vfork() has unclear semantics and is not standardized.
310 pid_ = fork(); 312 pid_ = fork();
311 313
312 if ( 0 == pid_ ) 314 if ( 0 == pid_ )
313 { 315 {
314 if ( fd[ 0 ] ) 316 if ( fd[ 0 ] )
315 close( fd[ 0 ] ); 317 close( fd[ 0 ] );
316 if ( !runPrivileged() ) 318 if ( !runPrivileged() )
317 { 319 {
318 setgid( gid ); 320 setgid( gid );
319#if defined( HAVE_INITGROUPS) 321#if defined( HAVE_INITGROUPS)
320 322
321 if ( pw ) 323 if ( pw )
322 initgroups( pw->pw_name, pw->pw_gid ); 324 initgroups( pw->pw_name, pw->pw_gid );
323#endif 325#endif
324 326
325 setuid( uid ); 327 setuid( uid );
326 } 328 }
327 // The child process 329 // The child process
328 if ( !commSetupDoneC() ) 330 if ( !commSetupDoneC() )
329 qWarning( "Could not finish comm setup in child!" ); 331 qWarning( "Could not finish comm setup in child!" );
330 332
331 setupEnvironment(); 333 setupEnvironment();
332 334
333 // Matthias 335 // Matthias
334 if ( run_mode == DontCare ) 336 if ( run_mode == DontCare )
335 setpgid( 0, 0 ); 337 setpgid( 0, 0 );
336 // restore default SIGPIPE handler (Harri) 338 // restore default SIGPIPE handler (Harri)
337 struct sigaction act; 339 struct sigaction act;
338 sigemptyset( &( act.sa_mask ) ); 340 sigemptyset( &( act.sa_mask ) );
339 sigaddset( &( act.sa_mask ), SIGPIPE ); 341 sigaddset( &( act.sa_mask ), SIGPIPE );
340 act.sa_handler = SIG_DFL; 342 act.sa_handler = SIG_DFL;
341 act.sa_flags = 0; 343 act.sa_flags = 0;
342 sigaction( SIGPIPE, &act, 0L ); 344 sigaction( SIGPIPE, &act, 0L );
343 345
344 // We set the close on exec flag. 346 // We set the close on exec flag.
345 // Closing of fd[1] indicates that the execvp succeeded! 347 // Closing of fd[1] indicates that the execvp succeeded!
346 if ( fd[ 1 ] ) 348 if ( fd[ 1 ] )
347 fcntl( fd[ 1 ], F_SETFD, FD_CLOEXEC ); 349 fcntl( fd[ 1 ], F_SETFD, FD_CLOEXEC );
348 execvp( arglist[ 0 ], arglist ); 350 execvp( arglist[ 0 ], arglist );
349 char resultByte = 1; 351 char resultByte = 1;
350 if ( fd[ 1 ] ) 352 if ( fd[ 1 ] )
351 write( fd[ 1 ], &resultByte, 1 ); 353 write( fd[ 1 ], &resultByte, 1 );
352 _exit( -1 ); 354 _exit( -1 );
353 } 355 }
354 else if ( -1 == pid_ ) 356 else if ( -1 == pid_ )
355 { 357 {
356 // forking failed 358 // forking failed
357 359
358 runs = false; 360 runs = false;
359 free( arglist ); 361 free( arglist );
360 return false; 362 return false;
361 } 363 }
362 else 364 else
363 { 365 {
364 if ( fd[ 1 ] ) 366 if ( fd[ 1 ] )
365 close( fd[ 1 ] ); 367 close( fd[ 1 ] );
366 // the parent continues here 368 // the parent continues here
367 369
368 // Discard any data for stdin that might still be there 370 // Discard any data for stdin that might still be there
369 input_data = 0; 371 input_data = 0;
370 372
371 // Check whether client could be started. 373 // Check whether client could be started.
372 if ( fd[ 0 ] ) 374 if ( fd[ 0 ] )
373 for ( ;; ) 375 for ( ;; )
374 { 376 {
375 char resultByte; 377 char resultByte;
376 int n = ::read( fd[ 0 ], &resultByte, 1 ); 378 int n = ::read( fd[ 0 ], &resultByte, 1 );
377 if ( n == 1 ) 379 if ( n == 1 )
378 { 380 {
379 // Error 381 // Error
380 runs = false; 382 runs = false;
381 close( fd[ 0 ] ); 383 close( fd[ 0 ] );
382 free( arglist ); 384 free( arglist );
383 pid_ = 0; 385 pid_ = 0;
384 return false; 386 return false;
385 } 387 }
386 if ( n == -1 ) 388 if ( n == -1 )
387 { 389 {
388 if ( ( errno == ECHILD ) || ( errno == EINTR ) ) 390 if ( ( errno == ECHILD ) || ( errno == EINTR ) )
389 continue; // Ignore 391 continue; // Ignore
390 } 392 }
391 break; // success 393 break; // success
392 } 394 }
393 if ( fd[ 0 ] ) 395 if ( fd[ 0 ] )
394 close( fd[ 0 ] ); 396 close( fd[ 0 ] );
395 397
396 if ( !commSetupDoneP() ) // finish communication socket setup for the parent 398 if ( !commSetupDoneP() ) // finish communication socket setup for the parent
397 qWarning( "Could not finish comm setup in parent!" ); 399 qWarning( "Could not finish comm setup in parent!" );
398 400
399 if ( run_mode == Block ) 401 if ( run_mode == Block )
400 { 402 {
401 commClose(); 403 commClose();
402 404
403 // The SIGCHLD handler of the process controller will catch 405 // The SIGCHLD handler of the process controller will catch
404 // the exit and set the status 406 // the exit and set the status
405 while ( runs ) 407 while ( runs )
406 { 408 {
407 OProcessController::theOProcessController-> 409 OProcessController::theOProcessController->
408 slotDoHousekeeping( 0 ); 410 slotDoHousekeeping( 0 );
409 } 411 }
410 runs = FALSE; 412 runs = FALSE;
411 emit processExited( this ); 413 emit processExited( this );
412 } 414 }
413 } 415 }
414 free( arglist ); 416 free( arglist );
415 return true; 417 return true;
416} 418}
417 419
418 420
419 421
420bool OProcess::kill( int signo ) 422bool OProcess::kill( int signo )
421{ 423{
422 bool rv = false; 424 bool rv = false;
423 425
424 if ( 0 != pid_ ) 426 if ( 0 != pid_ )
425 rv = ( -1 != ::kill( pid_, signo ) ); 427 rv = ( -1 != ::kill( pid_, signo ) );
426 // probably store errno somewhere... 428 // probably store errno somewhere...
427 return rv; 429 return rv;
428} 430}
429 431
430bool OProcess::isRunning() const 432bool OProcess::isRunning() const
431{ 433{
432 return runs; 434 return runs;
433} 435}
434 436
435pid_t OProcess::pid() const 437pid_t OProcess::pid() const
436{ 438{
437 return pid_; 439 return pid_;
438} 440}
439 441
440bool OProcess::normalExit() const 442bool OProcess::normalExit() const
441{ 443{
442 int _status = status; 444 int _status = status;
443 return ( pid_ != 0 ) && ( !runs ) && ( WIFEXITED( ( _status ) ) ); 445 return ( pid_ != 0 ) && ( !runs ) && ( WIFEXITED( ( _status ) ) );
444} 446}
445 447
446int OProcess::exitStatus() const 448int OProcess::exitStatus() const
447{ 449{
448 int _status = status; 450 int _status = status;
449 return WEXITSTATUS( ( _status ) ); 451 return WEXITSTATUS( ( _status ) );
450} 452}
451 453
452bool OProcess::writeStdin( const char *buffer, int buflen ) 454bool OProcess::writeStdin( const char *buffer, int buflen )
453{ 455{
454 bool rv; 456 bool rv;
455 457
456 // if there is still data pending, writing new data 458 // if there is still data pending, writing new data
457 // to stdout is not allowed (since it could also confuse 459 // to stdout is not allowed (since it could also confuse
458 // kprocess... 460 // kprocess...
459 if ( 0 != input_data ) 461 if ( 0 != input_data )
460 return false; 462 return false;
461 463
462 if ( runs && ( communication & Stdin ) ) 464 if ( runs && ( communication & Stdin ) )
463 { 465 {
464 input_data = buffer; 466 input_data = buffer;
465 input_sent = 0; 467 input_sent = 0;
466 input_total = buflen; 468 input_total = buflen;
467 slotSendData( 0 ); 469 slotSendData( 0 );
468 innot->setEnabled( true ); 470 innot->setEnabled( true );
469 rv = true; 471 rv = true;
470 } 472 }
471 else 473 else
472 rv = false; 474 rv = false;
473 return rv; 475 return rv;
474} 476}
475 477
476void OProcess::flushStdin ( ) 478void OProcess::flushStdin ( )
477{ 479{
478 if ( !input_data || ( input_sent == input_total ) ) 480 if ( !input_data || ( input_sent == input_total ) )
479 return ; 481 return ;
480 482
481 int d1, d2; 483 int d1, d2;
482 484
483 do 485 do
484 { 486 {
485 d1 = input_total - input_sent; 487 d1 = input_total - input_sent;
486 slotSendData ( 0 ); 488 slotSendData ( 0 );
487 d2 = input_total - input_sent; 489 d2 = input_total - input_sent;
488 } 490 }
489 while ( d2 <= d1 ); 491 while ( d2 <= d1 );
490} 492}
491 493
492void OProcess::suspend() 494void OProcess::suspend()
493{ 495{
494 if ( ( communication & Stdout ) && outnot ) 496 if ( ( communication & Stdout ) && outnot )
495 outnot->setEnabled( false ); 497 outnot->setEnabled( false );
496} 498}
497 499
498void OProcess::resume() 500void OProcess::resume()
499{ 501{
500 if ( ( communication & Stdout ) && outnot ) 502 if ( ( communication & Stdout ) && outnot )
501 outnot->setEnabled( true ); 503 outnot->setEnabled( true );
502} 504}
503 505
504bool OProcess::closeStdin() 506bool OProcess::closeStdin()
505{ 507{
506 bool rv; 508 bool rv;
507 509
508 if ( communication & Stdin ) 510 if ( communication & Stdin )
509 { 511 {
510 communication = ( Communication ) ( communication & ~Stdin ); 512 communication = ( Communication ) ( communication & ~Stdin );
511 delete innot; 513 delete innot;
512 innot = 0; 514 innot = 0;
513 close( in[ 1 ] ); 515 close( in[ 1 ] );
514 rv = true; 516 rv = true;
515 } 517 }
516 else 518 else
517 rv = false; 519 rv = false;
518 return rv; 520 return rv;
519} 521}
520 522
521bool OProcess::closeStdout() 523bool OProcess::closeStdout()
522{ 524{
523 bool rv; 525 bool rv;
524 526
525 if ( communication & Stdout ) 527 if ( communication & Stdout )
526 { 528 {
527 communication = ( Communication ) ( communication & ~Stdout ); 529 communication = ( Communication ) ( communication & ~Stdout );
528 delete outnot; 530 delete outnot;
529 outnot = 0; 531 outnot = 0;
530 close( out[ 0 ] ); 532 close( out[ 0 ] );
531 rv = true; 533 rv = true;
532 } 534 }
533 else 535 else
534 rv = false; 536 rv = false;
535 return rv; 537 return rv;
536} 538}
537 539
538bool OProcess::closeStderr() 540bool OProcess::closeStderr()
539{ 541{
540 bool rv; 542 bool rv;
541 543
542 if ( communication & Stderr ) 544 if ( communication & Stderr )
543 { 545 {
544 communication = static_cast<Communication>( communication & ~Stderr ); 546 communication = static_cast<Communication>( communication & ~Stderr );
545 delete errnot; 547 delete errnot;
546 errnot = 0; 548 errnot = 0;
547 close( err[ 0 ] ); 549 close( err[ 0 ] );
548 rv = true; 550 rv = true;
549 } 551 }
550 else 552 else
551 rv = false; 553 rv = false;
552 return rv; 554 return rv;
553} 555}
554 556
555void OProcess::slotChildOutput( int fdno ) 557void OProcess::slotChildOutput( int fdno )
556{ 558{
557 if ( !childOutput( fdno ) ) 559 if ( !childOutput( fdno ) )
558 closeStdout(); 560 closeStdout();
559} 561}
560 562
561void OProcess::slotChildError( int fdno ) 563void OProcess::slotChildError( int fdno )
562{ 564{
563 if ( !childError( fdno ) ) 565 if ( !childError( fdno ) )
564 closeStderr(); 566 closeStderr();
565} 567}
566 568
567void OProcess::slotSendData( int ) 569void OProcess::slotSendData( int )
568{ 570{
569 if ( input_sent == input_total ) 571 if ( input_sent == input_total )
570 { 572 {
571 innot->setEnabled( false ); 573 innot->setEnabled( false );
572 input_data = 0; 574 input_data = 0;
573 emit wroteStdin( this ); 575 emit wroteStdin( this );
574 } 576 }
575 else 577 else
576 input_sent += ::write( in[ 1 ], input_data + input_sent, input_total - input_sent ); 578 input_sent += ::write( in[ 1 ], input_data + input_sent, input_total - input_sent );
577} 579}
578 580
579void OProcess::processHasExited( int state ) 581void OProcess::processHasExited( int state )
580{ 582{
581 if ( runs ) 583 if ( runs )
582 { 584 {
583 runs = false; 585 runs = false;
584 status = state; 586 status = state;
585 587
586 commClose(); // cleanup communication sockets 588 commClose(); // cleanup communication sockets
587 589
588 // also emit a signal if the process was run Blocking 590 // also emit a signal if the process was run Blocking
589 if ( DontCare != run_mode ) 591 if ( DontCare != run_mode )
590 { 592 {
591 emit processExited( this ); 593 emit processExited( this );
592 } 594 }
593 } 595 }
594} 596}
595 597
596int OProcess::childOutput( int fdno ) 598int OProcess::childOutput( int fdno )
597{ 599{
598 if ( communication & NoRead ) 600 if ( communication & NoRead )
599 { 601 {
600 int len = -1; 602 int len = -1;
601 emit receivedStdout( fdno, len ); 603 emit receivedStdout( fdno, len );
602 errno = 0; // Make sure errno doesn't read "EAGAIN" 604 errno = 0; // Make sure errno doesn't read "EAGAIN"
603 return len; 605 return len;
604 } 606 }
605 else 607 else
606 { 608 {
607 char buffer[ 1024 ]; 609 char buffer[ 1024 ];
608 int len; 610 int len;
609 611
610 len = ::read( fdno, buffer, 1024 ); 612 len = ::read( fdno, buffer, 1024 );
611 613
612 if ( 0 < len ) 614 if ( 0 < len )
613 { 615 {
614 emit receivedStdout( this, buffer, len ); 616 emit receivedStdout( this, buffer, len );
615 } 617 }
616 return len; 618 return len;
617 } 619 }
618} 620}
619 621
620int OProcess::childError( int fdno ) 622int OProcess::childError( int fdno )
621{ 623{
622 char buffer[ 1024 ]; 624 char buffer[ 1024 ];
623 int len; 625 int len;
624 626
625 len = ::read( fdno, buffer, 1024 ); 627 len = ::read( fdno, buffer, 1024 );
626 628
627 if ( 0 < len ) 629 if ( 0 < len )
628 emit receivedStderr( this, buffer, len ); 630 emit receivedStderr( this, buffer, len );
629 return len; 631 return len;
630} 632}
631 633
632int OProcess::setupCommunication( Communication comm ) 634int OProcess::setupCommunication( Communication comm )
633{ 635{
634 int ok; 636 int ok;
635 637
636 communication = comm; 638 communication = comm;
637 639
638 ok = 1; 640 ok = 1;
639 if ( comm & Stdin ) 641 if ( comm & Stdin )
640 ok &= socketpair( AF_UNIX, SOCK_STREAM, 0, in ) >= 0; 642 ok &= socketpair( AF_UNIX, SOCK_STREAM, 0, in ) >= 0;
641 643
642 if ( comm & Stdout ) 644 if ( comm & Stdout )
643 ok &= socketpair( AF_UNIX, SOCK_STREAM, 0, out ) >= 0; 645 ok &= socketpair( AF_UNIX, SOCK_STREAM, 0, out ) >= 0;
644 646
645 if ( comm & Stderr ) 647 if ( comm & Stderr )
646 ok &= socketpair( AF_UNIX, SOCK_STREAM, 0, err ) >= 0; 648 ok &= socketpair( AF_UNIX, SOCK_STREAM, 0, err ) >= 0;
647 649
648 return ok; 650 return ok;
649} 651}
650 652
651int OProcess::commSetupDoneP() 653int OProcess::commSetupDoneP()
652{ 654{
653 int ok = 1; 655 int ok = 1;
654 656
655 if ( communication != NoCommunication ) 657 if ( communication != NoCommunication )
656 { 658 {
657 if ( communication & Stdin ) 659 if ( communication & Stdin )
658 close( in[ 0 ] ); 660 close( in[ 0 ] );
659 if ( communication & Stdout ) 661 if ( communication & Stdout )
660 close( out[ 1 ] ); 662 close( out[ 1 ] );
661 if ( communication & Stderr ) 663 if ( communication & Stderr )
662 close( err[ 1 ] ); 664 close( err[ 1 ] );
663 665
664 // Don't create socket notifiers and set the sockets non-blocking if 666 // Don't create socket notifiers and set the sockets non-blocking if
665 // blocking is requested. 667 // blocking is requested.
666 if ( run_mode == Block ) 668 if ( run_mode == Block )
667 return ok; 669 return ok;
668 670
669 if ( communication & Stdin ) 671 if ( communication & Stdin )
670 { 672 {
671 // ok &= (-1 != fcntl(in[1], F_SETFL, O_NONBLOCK)); 673 // ok &= (-1 != fcntl(in[1], F_SETFL, O_NONBLOCK));
672 innot = new QSocketNotifier( in[ 1 ], QSocketNotifier::Write, this ); 674 innot = new QSocketNotifier( in[ 1 ], QSocketNotifier::Write, this );
673 CHECK_PTR( innot ); 675 CHECK_PTR( innot );
674 innot->setEnabled( false ); // will be enabled when data has to be sent 676 innot->setEnabled( false ); // will be enabled when data has to be sent
675 QObject::connect( innot, SIGNAL( activated( int ) ), 677 QObject::connect( innot, SIGNAL( activated( int ) ),
676 this, SLOT( slotSendData( int ) ) ); 678 this, SLOT( slotSendData( int ) ) );
677 } 679 }
678 680
679 if ( communication & Stdout ) 681 if ( communication & Stdout )
680 { 682 {
681 // ok &= (-1 != fcntl(out[0], F_SETFL, O_NONBLOCK)); 683 // ok &= (-1 != fcntl(out[0], F_SETFL, O_NONBLOCK));
682 outnot = new QSocketNotifier( out[ 0 ], QSocketNotifier::Read, this ); 684 outnot = new QSocketNotifier( out[ 0 ], QSocketNotifier::Read, this );
683 CHECK_PTR( outnot ); 685 CHECK_PTR( outnot );
684 QObject::connect( outnot, SIGNAL( activated( int ) ), 686 QObject::connect( outnot, SIGNAL( activated( int ) ),
685 this, SLOT( slotChildOutput( int ) ) ); 687 this, SLOT( slotChildOutput( int ) ) );
686 if ( communication & NoRead ) 688 if ( communication & NoRead )
687 suspend(); 689 suspend();
688 } 690 }
689 691
690 if ( communication & Stderr ) 692 if ( communication & Stderr )
691 { 693 {
692 // ok &= (-1 != fcntl(err[0], F_SETFL, O_NONBLOCK)); 694 // ok &= (-1 != fcntl(err[0], F_SETFL, O_NONBLOCK));
693 errnot = new QSocketNotifier( err[ 0 ], QSocketNotifier::Read, this ); 695 errnot = new QSocketNotifier( err[ 0 ], QSocketNotifier::Read, this );
694 CHECK_PTR( errnot ); 696 CHECK_PTR( errnot );
695 QObject::connect( errnot, SIGNAL( activated( int ) ), 697 QObject::connect( errnot, SIGNAL( activated( int ) ),
696 this, SLOT( slotChildError( int ) ) ); 698 this, SLOT( slotChildError( int ) ) );
697 } 699 }
698 } 700 }
699 return ok; 701 return ok;
700} 702}
701 703
702int OProcess::commSetupDoneC() 704int OProcess::commSetupDoneC()
703{ 705{
704 int ok = 1; 706 int ok = 1;
705 struct linger so; 707 struct linger so;
706 memset( &so, 0, sizeof( so ) ); 708 memset( &so, 0, sizeof( so ) );
707 709
708 if ( communication & Stdin ) 710 if ( communication & Stdin )
709 close( in[ 1 ] ); 711 close( in[ 1 ] );
710 if ( communication & Stdout ) 712 if ( communication & Stdout )
711 close( out[ 0 ] ); 713 close( out[ 0 ] );
712 if ( communication & Stderr ) 714 if ( communication & Stderr )
713 close( err[ 0 ] ); 715 close( err[ 0 ] );
714 716
715 if ( communication & Stdin ) 717 if ( communication & Stdin )
716 ok &= dup2( in[ 0 ], STDIN_FILENO ) != -1; 718 ok &= dup2( in[ 0 ], STDIN_FILENO ) != -1;
717 else 719 else
718 { 720 {
719 int null_fd = open( "/dev/null", O_RDONLY ); 721 int null_fd = open( "/dev/null", O_RDONLY );
720 ok &= dup2( null_fd, STDIN_FILENO ) != -1; 722 ok &= dup2( null_fd, STDIN_FILENO ) != -1;
721 close( null_fd ); 723 close( null_fd );
722 } 724 }
723 if ( communication & Stdout ) 725 if ( communication & Stdout )
724 { 726 {
725 ok &= dup2( out[ 1 ], STDOUT_FILENO ) != -1; 727 ok &= dup2( out[ 1 ], STDOUT_FILENO ) != -1;
726 ok &= !setsockopt( out[ 1 ], SOL_SOCKET, SO_LINGER, ( char* ) & so, sizeof( so ) ); 728 ok &= !setsockopt( out[ 1 ], SOL_SOCKET, SO_LINGER, ( char* ) & so, sizeof( so ) );
727 } 729 }
728 else 730 else
729 { 731 {
730 int null_fd = open( "/dev/null", O_WRONLY ); 732 int null_fd = open( "/dev/null", O_WRONLY );
731 ok &= dup2( null_fd, STDOUT_FILENO ) != -1; 733 ok &= dup2( null_fd, STDOUT_FILENO ) != -1;
732 close( null_fd ); 734 close( null_fd );
733 } 735 }
734 if ( communication & Stderr ) 736 if ( communication & Stderr )
735 { 737 {
736 ok &= dup2( err[ 1 ], STDERR_FILENO ) != -1; 738 ok &= dup2( err[ 1 ], STDERR_FILENO ) != -1;
737 ok &= !setsockopt( err[ 1 ], SOL_SOCKET, SO_LINGER, reinterpret_cast<char *>( &so ), sizeof( so ) ); 739 ok &= !setsockopt( err[ 1 ], SOL_SOCKET, SO_LINGER, reinterpret_cast<char *>( &so ), sizeof( so ) );
738 } 740 }
739 else 741 else
740 { 742 {
741 int null_fd = open( "/dev/null", O_WRONLY ); 743 int null_fd = open( "/dev/null", O_WRONLY );
742 ok &= dup2( null_fd, STDERR_FILENO ) != -1; 744 ok &= dup2( null_fd, STDERR_FILENO ) != -1;
743 close( null_fd ); 745 close( null_fd );
744 } 746 }
745 return ok; 747 return ok;
746} 748}
747 749
748void OProcess::commClose() 750void OProcess::commClose()
749{ 751{
750 if ( NoCommunication != communication ) 752 if ( NoCommunication != communication )
751 { 753 {
752 bool b_in = ( communication & Stdin ); 754 bool b_in = ( communication & Stdin );
753 bool b_out = ( communication & Stdout ); 755 bool b_out = ( communication & Stdout );
754 bool b_err = ( communication & Stderr ); 756 bool b_err = ( communication & Stderr );
755 if ( b_in ) 757 if ( b_in )
756 delete innot; 758 delete innot;
757 759
758 if ( b_out || b_err ) 760 if ( b_out || b_err )
759 { 761 {
760 // If both channels are being read we need to make sure that one socket buffer 762 // If both channels are being read we need to make sure that one socket buffer
761 // doesn't fill up whilst we are waiting for data on the other (causing a deadlock). 763 // doesn't fill up whilst we are waiting for data on the other (causing a deadlock).
762 // Hence we need to use select. 764 // Hence we need to use select.
763 765
764 // Once one or other of the channels has reached EOF (or given an error) go back 766 // Once one or other of the channels has reached EOF (or given an error) go back
765 // to the usual mechanism. 767 // to the usual mechanism.
766 768
767 int fds_ready = 1; 769 int fds_ready = 1;
768 fd_set rfds; 770 fd_set rfds;
769 771
770 int max_fd = 0; 772 int max_fd = 0;
771 if ( b_out ) 773 if ( b_out )
772 { 774 {
773 fcntl( out[ 0 ], F_SETFL, O_NONBLOCK ); 775 fcntl( out[ 0 ], F_SETFL, O_NONBLOCK );
774 if ( out[ 0 ] > max_fd ) 776 if ( out[ 0 ] > max_fd )
775 max_fd = out[ 0 ]; 777 max_fd = out[ 0 ];
776 delete outnot; 778 delete outnot;
777 outnot = 0; 779 outnot = 0;
778 } 780 }
779 if ( b_err ) 781 if ( b_err )
780 { 782 {
781 fcntl( err[ 0 ], F_SETFL, O_NONBLOCK ); 783 fcntl( err[ 0 ], F_SETFL, O_NONBLOCK );
782 if ( err[ 0 ] > max_fd ) 784 if ( err[ 0 ] > max_fd )
783 max_fd = err[ 0 ]; 785 max_fd = err[ 0 ];
784 delete errnot; 786 delete errnot;
785 errnot = 0; 787 errnot = 0;
786 } 788 }
787 789
788 790
789 while ( b_out || b_err ) 791 while ( b_out || b_err )
790 { 792 {
791 // * If the process is still running we block until we 793 // * If the process is still running we block until we
792 // receive data. (p_timeout = 0, no timeout) 794 // receive data. (p_timeout = 0, no timeout)
793 // * If the process has already exited, we only check 795 // * If the process has already exited, we only check
794 // the available data, we don't wait for more. 796 // the available data, we don't wait for more.
795 // (p_timeout = &timeout, timeout immediately) 797 // (p_timeout = &timeout, timeout immediately)
796 struct timeval timeout; 798 struct timeval timeout;
797 timeout.tv_sec = 0; 799 timeout.tv_sec = 0;
798 timeout.tv_usec = 0; 800 timeout.tv_usec = 0;
799 struct timeval *p_timeout = runs ? 0 : &timeout; 801 struct timeval *p_timeout = runs ? 0 : &timeout;
800 802
801 FD_ZERO( &rfds ); 803 FD_ZERO( &rfds );
802 if ( b_out ) 804 if ( b_out )
803 FD_SET( out[ 0 ], &rfds ); 805 FD_SET( out[ 0 ], &rfds );
804 806
805 if ( b_err ) 807 if ( b_err )
806 FD_SET( err[ 0 ], &rfds ); 808 FD_SET( err[ 0 ], &rfds );
807 809
808 fds_ready = select( max_fd + 1, &rfds, 0, 0, p_timeout ); 810 fds_ready = select( max_fd + 1, &rfds, 0, 0, p_timeout );
809 if ( fds_ready <= 0 ) 811 if ( fds_ready <= 0 )
810 break; 812 break;
811 813
812 if ( b_out && FD_ISSET( out[ 0 ], &rfds ) ) 814 if ( b_out && FD_ISSET( out[ 0 ], &rfds ) )
813 { 815 {
814 int ret = 1; 816 int ret = 1;
815 while ( ret > 0 ) 817 while ( ret > 0 )
816 ret = childOutput( out[ 0 ] ); 818 ret = childOutput( out[ 0 ] );
817 if ( ( ret == -1 && errno != EAGAIN ) || ret == 0 ) 819 if ( ( ret == -1 && errno != EAGAIN ) || ret == 0 )
818 b_out = false; 820 b_out = false;
819 } 821 }
820 822
821 if ( b_err && FD_ISSET( err[ 0 ], &rfds ) ) 823 if ( b_err && FD_ISSET( err[ 0 ], &rfds ) )
822 { 824 {
823 int ret = 1; 825 int ret = 1;
824 while ( ret > 0 ) 826 while ( ret > 0 )
825 ret = childError( err[ 0 ] ); 827 ret = childError( err[ 0 ] );
826 if ( ( ret == -1 && errno != EAGAIN ) || ret == 0 ) 828 if ( ( ret == -1 && errno != EAGAIN ) || ret == 0 )
827 b_err = false; 829 b_err = false;
828 } 830 }
829 } 831 }
830 } 832 }
831 833
832 if ( b_in ) 834 if ( b_in )
833 { 835 {
834 communication = ( Communication ) ( communication & ~Stdin ); 836 communication = ( Communication ) ( communication & ~Stdin );
835 close( in[ 1 ] ); 837 close( in[ 1 ] );
836 } 838 }
837 if ( b_out ) 839 if ( b_out )
838 { 840 {
839 communication = ( Communication ) ( communication & ~Stdout ); 841 communication = ( Communication ) ( communication & ~Stdout );
840 close( out[ 0 ] ); 842 close( out[ 0 ] );
841 } 843 }
842 if ( b_err ) 844 if ( b_err )
843 { 845 {
844 communication = ( Communication ) ( communication & ~Stderr ); 846 communication = ( Communication ) ( communication & ~Stderr );
845 close( err[ 0 ] ); 847 close( err[ 0 ] );
846 } 848 }
847 } 849 }
848} 850}
849 851
850void OProcess::setUseShell( bool useShell, const char *shell ) 852void OProcess::setUseShell( bool useShell, const char *shell )
851{ 853{
852 if ( !d ) 854 if ( !d )
853 d = new OProcessPrivate; 855 d = new OProcessPrivate;
854 d->useShell = useShell; 856 d->useShell = useShell;
855 d->shell = shell; 857 d->shell = shell;
856 if ( d->shell.isEmpty() ) 858 if ( d->shell.isEmpty() )
857 d->shell = searchShell(); 859 d->shell = searchShell();
858} 860}
859 861
860QString OProcess::quote( const QString &arg ) 862QString OProcess::quote( const QString &arg )
861{ 863{
862 QString res = arg; 864 QString res = arg;
863 res.replace( QRegExp( QString::fromLatin1( "\'" ) ), 865 res.replace( QRegExp( QString::fromLatin1( "\'" ) ),
864 QString::fromLatin1( "'\"'\"'" ) ); 866 QString::fromLatin1( "'\"'\"'" ) );
865 res.prepend( '\'' ); 867 res.prepend( '\'' );
866 res.append( '\'' ); 868 res.append( '\'' );
867 return res; 869 return res;
868} 870}
869 871
870QCString OProcess::searchShell() 872QCString OProcess::searchShell()
871{ 873{
872 QCString tmpShell = QCString( getenv( "SHELL" ) ).stripWhiteSpace(); 874 QCString tmpShell = QCString( getenv( "SHELL" ) ).stripWhiteSpace();
873 if ( !isExecutable( tmpShell ) ) 875 if ( !isExecutable( tmpShell ) )
874 { 876 {
875 tmpShell = "/bin/sh"; 877 tmpShell = "/bin/sh";
876 } 878 }
877 879
878 return tmpShell; 880 return tmpShell;
879} 881}
880 882
881bool OProcess::isExecutable( const QCString &filename ) 883bool OProcess::isExecutable( const QCString &filename )
882{ 884{
883 struct stat fileinfo; 885 struct stat fileinfo;
884 886
885 if ( filename.isEmpty() ) 887 if ( filename.isEmpty() )
886 return false; 888 return false;
887 889
888 // CC: we've got a valid filename, now let's see whether we can execute that file 890 // CC: we've got a valid filename, now let's see whether we can execute that file
889 891
890 if ( -1 == stat( filename.data(), &fileinfo ) ) 892 if ( -1 == stat( filename.data(), &fileinfo ) )
891 return false; 893 return false;
892 // CC: return false if the file does not exist 894 // CC: return false if the file does not exist
893 895
894 // CC: anyway, we cannot execute directories, block/character devices, fifos or sockets 896 // CC: anyway, we cannot execute directories, block/character devices, fifos or sockets
895 if ( ( S_ISDIR( fileinfo.st_mode ) ) || 897 if ( ( S_ISDIR( fileinfo.st_mode ) ) ||
896 ( S_ISCHR( fileinfo.st_mode ) ) || 898 ( S_ISCHR( fileinfo.st_mode ) ) ||
897 ( S_ISBLK( fileinfo.st_mode ) ) || 899 ( S_ISBLK( fileinfo.st_mode ) ) ||
898#ifdef S_ISSOCK 900#ifdef S_ISSOCK
899 // CC: SYSVR4 systems don't have that macro 901 // CC: SYSVR4 systems don't have that macro
900 ( S_ISSOCK( fileinfo.st_mode ) ) || 902 ( S_ISSOCK( fileinfo.st_mode ) ) ||
901#endif 903#endif
902 ( S_ISFIFO( fileinfo.st_mode ) ) || 904 ( S_ISFIFO( fileinfo.st_mode ) ) ||
903 ( S_ISDIR( fileinfo.st_mode ) ) ) 905 ( S_ISDIR( fileinfo.st_mode ) ) )
904 { 906 {
905 return false; 907 return false;
906 } 908 }
907 909
908 // CC: now check for permission to execute the file 910 // CC: now check for permission to execute the file
909 if ( access( filename.data(), X_OK ) != 0 ) 911 if ( access( filename.data(), X_OK ) != 0 )
910 return false; 912 return false;
911 913
912 // CC: we've passed all the tests... 914 // CC: we've passed all the tests...
913 return true; 915 return true;
914} 916}
915 917
918int OProcess::processPID( const QString& process )
919{
920 QString line;
921 QDir d = QDir( "/proc" );
922 QStringList dirs = d.entryList( QDir::Dirs );
923 QStringList::Iterator it;
924 for ( it = dirs.begin(); it != dirs.end(); ++it )
925 {
926 //qDebug( "next entry: %s", (const char*) *it );
927 QFile file( "/proc/"+*it+"/cmdline" );
928 file.open( IO_ReadOnly );
929 if ( !file.isOpen() ) continue;
930 QTextStream t( &file );
931 line = t.readLine();
932 //qDebug( "cmdline = %s", (const char*) line );
933 if ( line.contains( process ) ) break; //FIXME: That may find also other process, if the name is not long enough ;)
934 }
935 if ( line.contains( process ) )
936 {
937 //qDebug( "found process id #%d", (*it).toInt() );
938 return (*it).toInt();
939 }
940 else
941 {
942 //qDebug( "process '%s' not found", (const char*) process );
943 return -1;
944 }
945}
diff --git a/libopie2/opiecore/oprocess.h b/libopie2/opiecore/oprocess.h
index 352485b..1a2472d 100644
--- a/libopie2/opiecore/oprocess.h
+++ b/libopie2/opiecore/oprocess.h
@@ -1,747 +1,752 @@
1/* 1/*
2                This file is part of the Opie Project 2                This file is part of the Opie Project
3             Copyright (C) 2003-2004 Holger Freyther <zecke@handhelds.org> 3             Copyright (C) 2003-2004 Holger Freyther <zecke@handhelds.org>
4 Copyright (C) The Opie Team <opie-devel@handhelds.org> 4 Copyright (C) The Opie Team <opie-devel@handhelds.org>
5 =. Based on KProcess (C) 1997 Christian Czezatke (e9025461@student.tuwien.ac.at) 5 =. Based on KProcess (C) 1997 Christian Czezatke (e9025461@student.tuwien.ac.at)
6 .=l. 6 .=l.
7          .>+-= 7          .>+-=
8_;:,     .>    :=|. This program is free software; you can 8_;:,     .>    :=|. This program is free software; you can
9.> <`_,   >  .   <= redistribute it and/or modify it under 9.> <`_,   >  .   <= redistribute it and/or modify it under
10:`=1 )Y*s>-.--   : the terms of the GNU Library General Public 10:`=1 )Y*s>-.--   : the terms of the GNU Library General Public
11.="- .-=="i,     .._ License as published by the Free Software 11.="- .-=="i,     .._ License as published by the Free Software
12- .   .-<_>     .<> Foundation; either version 2 of the License, 12- .   .-<_>     .<> Foundation; either version 2 of the License,
13    ._= =}       : or (at your option) any later version. 13    ._= =}       : or (at your option) any later version.
14   .%`+i>       _;_. 14   .%`+i>       _;_.
15   .i_,=:_.      -<s. This program is distributed in the hope that 15   .i_,=:_.      -<s. This program is distributed in the hope that
16    +  .  -:.       = it will be useful, but WITHOUT ANY WARRANTY; 16    +  .  -:.       = it will be useful, but WITHOUT ANY WARRANTY;
17   : ..    .:,     . . . without even the implied warranty of 17   : ..    .:,     . . . without even the implied warranty of
18   =_        +     =;=|` MERCHANTABILITY or FITNESS FOR A 18   =_        +     =;=|` MERCHANTABILITY or FITNESS FOR A
19 _.=:.       :    :=>`: PARTICULAR PURPOSE. See the GNU 19 _.=:.       :    :=>`: PARTICULAR PURPOSE. See the GNU
20..}^=.=       =       ; Library General Public License for more 20..}^=.=       =       ; Library General Public License for more
21++=   -.     .`     .: details. 21++=   -.     .`     .: details.
22:     =  ...= . :.=- 22:     =  ...= . :.=-
23-.   .:....=;==+<; You should have received a copy of the GNU 23-.   .:....=;==+<; You should have received a copy of the GNU
24 -_. . .   )=.  = Library General Public License along with 24 -_. . .   )=.  = Library General Public License along with
25   --        :-=` this library; see the file COPYING.LIB. 25   --        :-=` this library; see the file COPYING.LIB.
26 If not, write to the Free Software Foundation, 26 If not, write to the Free Software Foundation,
27 Inc., 59 Temple Place - Suite 330, 27 Inc., 59 Temple Place - Suite 330,
28 Boston, MA 02111-1307, USA. 28 Boston, MA 02111-1307, USA.
29*/ 29*/
30 30
31#ifndef OPROCESS_H 31#ifndef OPROCESS_H
32#define OPROCESS_H 32#define OPROCESS_H
33 33
34/* QT */ 34/* QT */
35#include <qcstring.h> 35#include <qcstring.h>
36#include <qobject.h> 36#include <qobject.h>
37#include <qvaluelist.h> 37#include <qvaluelist.h>
38 38
39/* STD */ 39/* STD */
40#include <sys/types.h> // for pid_t 40#include <sys/types.h> // for pid_t
41#include <sys/wait.h> 41#include <sys/wait.h>
42#include <signal.h> 42#include <signal.h>
43#include <unistd.h> 43#include <unistd.h>
44 44
45class QSocketNotifier; 45class QSocketNotifier;
46class OProcessPrivate; 46class OProcessPrivate;
47 47
48/** 48/**
49 * Child process invocation, monitoring and control. 49 * Child process invocation, monitoring and control.
50 * 50 *
51 * @sect General usage and features 51 * @sect General usage and features
52 * 52 *
53 *This class allows a KDE and OPIE application to start child processes without having 53 *This class allows a KDE and OPIE application to start child processes without having
54 *to worry about UN*X signal handling issues and zombie process reaping. 54 *to worry about UN*X signal handling issues and zombie process reaping.
55 * 55 *
56 *@see KProcIO 56 *@see KProcIO
57 * 57 *
58 *Basically, this class distinguishes three different ways of running 58 *Basically, this class distinguishes three different ways of running
59 *child processes: 59 *child processes:
60 * 60 *
61 *@li OProcess::DontCare -- The child process is invoked and both the child 61 *@li OProcess::DontCare -- The child process is invoked and both the child
62 *process and the parent process continue concurrently. 62 *process and the parent process continue concurrently.
63 * 63 *
64 *Starting a DontCare child process means that the application is 64 *Starting a DontCare child process means that the application is
65 *not interested in any notification to determine whether the 65 *not interested in any notification to determine whether the
66 *child process has already exited or not. 66 *child process has already exited or not.
67 * 67 *
68 *@li OProcess::NotifyOnExit -- The child process is invoked and both the 68 *@li OProcess::NotifyOnExit -- The child process is invoked and both the
69 *child and the parent process run concurrently. 69 *child and the parent process run concurrently.
70 * 70 *
71 *When the child process exits, the OProcess instance 71 *When the child process exits, the OProcess instance
72 *corresponding to it emits the Qt signal @ref processExited(). 72 *corresponding to it emits the Qt signal @ref processExited().
73 * 73 *
74 *Since this signal is @em not emitted from within a UN*X 74 *Since this signal is @em not emitted from within a UN*X
75 *signal handler, arbitrary function calls can be made. 75 *signal handler, arbitrary function calls can be made.
76 * 76 *
77 *Be aware: When the OProcess objects gets destructed, the child 77 *Be aware: When the OProcess objects gets destructed, the child
78 *process will be killed if it is still running! 78 *process will be killed if it is still running!
79 *This means in particular, that you cannot use a OProcess on the stack 79 *This means in particular, that you cannot use a OProcess on the stack
80 *with OProcess::NotifyOnExit. 80 *with OProcess::NotifyOnExit.
81 * 81 *
82 *@li OProcess::Block -- The child process starts and the parent process 82 *@li OProcess::Block -- The child process starts and the parent process
83 *is suspended until the child process exits. (@em Really not recommended 83 *is suspended until the child process exits. (@em Really not recommended
84 *for programs with a GUI.) 84 *for programs with a GUI.)
85 * 85 *
86 *OProcess also provides several functions for determining the exit status 86 *OProcess also provides several functions for determining the exit status
87 *and the pid of the child process it represents. 87 *and the pid of the child process it represents.
88 * 88 *
89 *Furthermore it is possible to supply command-line arguments to the process 89 *Furthermore it is possible to supply command-line arguments to the process
90 *in a clean fashion (no null -- terminated stringlists and such...) 90 *in a clean fashion (no null -- terminated stringlists and such...)
91 * 91 *
92 *A small usage example: 92 *A small usage example:
93 *<pre> 93 *<pre>
94 *OProcess *proc = new OProcess; 94 *OProcess *proc = new OProcess;
95 * 95 *
96 **proc << "my_executable"; 96 **proc << "my_executable";
97 **proc << "These" << "are" << "the" << "command" << "line" << "args"; 97 **proc << "These" << "are" << "the" << "command" << "line" << "args";
98 *QApplication::connect(proc, SIGNAL(processExited(OProcess *)), 98 *QApplication::connect(proc, SIGNAL(processExited(OProcess *)),
99 * pointer_to_my_object, SLOT(my_objects_slot(OProcess *))); 99 * pointer_to_my_object, SLOT(my_objects_slot(OProcess *)));
100 *proc->start(); 100 *proc->start();
101 *</pre> 101 *</pre>
102 * 102 *
103 *This will start "my_executable" with the commandline arguments "These"... 103 *This will start "my_executable" with the commandline arguments "These"...
104 * 104 *
105 *When the child process exits, the respective Qt signal will be emitted. 105 *When the child process exits, the respective Qt signal will be emitted.
106 * 106 *
107 *@sect Communication with the child process 107 *@sect Communication with the child process
108 * 108 *
109 *OProcess supports communication with the child process through 109 *OProcess supports communication with the child process through
110 *stdin/stdout/stderr. 110 *stdin/stdout/stderr.
111 * 111 *
112 *The following functions are provided for getting data from the child 112 *The following functions are provided for getting data from the child
113 *process or sending data to the child's stdin (For more information, 113 *process or sending data to the child's stdin (For more information,
114 *have a look at the documentation of each function): 114 *have a look at the documentation of each function):
115 * 115 *
116 *@li bool @ref writeStdin(char *buffer, int buflen); 116 *@li bool @ref writeStdin(char *buffer, int buflen);
117 *@li -- Transmit data to the child process's stdin. 117 *@li -- Transmit data to the child process's stdin.
118 * 118 *
119 *@li bool @ref closeStdin(); 119 *@li bool @ref closeStdin();
120 *@li -- Closes the child process's stdin (which causes it to see an feof(stdin)). 120 *@li -- Closes the child process's stdin (which causes it to see an feof(stdin)).
121 *Returns false if you try to close stdin for a process that has been started 121 *Returns false if you try to close stdin for a process that has been started
122 *without a communication channel to stdin. 122 *without a communication channel to stdin.
123 * 123 *
124 *@li bool @ref closeStdout(); 124 *@li bool @ref closeStdout();
125 *@li -- Closes the child process's stdout. 125 *@li -- Closes the child process's stdout.
126 *Returns false if you try to close stdout for a process that has been started 126 *Returns false if you try to close stdout for a process that has been started
127 *without a communication channel to stdout. 127 *without a communication channel to stdout.
128 * 128 *
129 *@li bool @ref closeStderr(); 129 *@li bool @ref closeStderr();
130 *@li -- Closes the child process's stderr. 130 *@li -- Closes the child process's stderr.
131 *Returns false if you try to close stderr for a process that has been started 131 *Returns false if you try to close stderr for a process that has been started
132 *without a communication channel to stderr. 132 *without a communication channel to stderr.
133 * 133 *
134 * 134 *
135 *@sect QT signals: 135 *@sect QT signals:
136 * 136 *
137 *@li void @ref receivedStdout(OProcess *proc, char *buffer, int buflen); 137 *@li void @ref receivedStdout(OProcess *proc, char *buffer, int buflen);
138 *@li void @ref receivedStderr(OProcess *proc, char *buffer, int buflen); 138 *@li void @ref receivedStderr(OProcess *proc, char *buffer, int buflen);
139 *@li -- Indicates that new data has arrived from either the 139 *@li -- Indicates that new data has arrived from either the
140 *child process's stdout or stderr. 140 *child process's stdout or stderr.
141 * 141 *
142 *@li void @ref wroteStdin(OProcess *proc); 142 *@li void @ref wroteStdin(OProcess *proc);
143 *@li -- Indicates that all data that has been sent to the child process 143 *@li -- Indicates that all data that has been sent to the child process
144 *by a prior call to @ref writeStdin() has actually been transmitted to the 144 *by a prior call to @ref writeStdin() has actually been transmitted to the
145 *client . 145 *client .
146 * 146 *
147 *@author Christian Czezakte e9025461@student.tuwien.ac.at 147 *@author Christian Czezakte e9025461@student.tuwien.ac.at
148 *@author Holger Freyther (Opie Port) 148 *@author Holger Freyther (Opie Port)
149 * 149 *
150 **/ 150 **/
151class OProcess : public QObject 151class OProcess : public QObject
152{ 152{
153 Q_OBJECT 153 Q_OBJECT
154 154
155public: 155public:
156 156
157 /** 157 /**
158 * Modes in which the communication channel can be opened. 158 * Modes in which the communication channel can be opened.
159 * 159 *
160 * If communication for more than one channel is required, 160 * If communication for more than one channel is required,
161 * the values have to be or'ed together, for example to get 161 * the values have to be or'ed together, for example to get
162 * communication with stdout as well as with stdin, you would 162 * communication with stdout as well as with stdin, you would
163 * specify @p Stdin @p | @p Stdout 163 * specify @p Stdin @p | @p Stdout
164 * 164 *
165 * If @p NoRead is specified in conjunction with @p Stdout, 165 * If @p NoRead is specified in conjunction with @p Stdout,
166 * no data is actually read from @p Stdout but only 166 * no data is actually read from @p Stdout but only
167 * the signal @ref childOutput(int fd) is emitted. 167 * the signal @ref childOutput(int fd) is emitted.
168 */ 168 */
169 enum Communication { NoCommunication = 0, Stdin = 1, Stdout = 2, Stderr = 4, 169 enum Communication { NoCommunication = 0, Stdin = 1, Stdout = 2, Stderr = 4,
170 AllOutput = 6, All = 7, 170 AllOutput = 6, All = 7,
171 NoRead }; 171 NoRead };
172 172
173 /** 173 /**
174 * Run-modes for a child process. 174 * Run-modes for a child process.
175 */ 175 */
176 enum RunMode { 176 enum RunMode {
177 /** 177 /**
178 * The application does not receive notifications from the subprocess when 178 * The application does not receive notifications from the subprocess when
179 * it is finished or aborted. 179 * it is finished or aborted.
180 */ 180 */
181 DontCare, 181 DontCare,
182 /** 182 /**
183 * The application is notified when the subprocess dies. 183 * The application is notified when the subprocess dies.
184 */ 184 */
185 NotifyOnExit, 185 NotifyOnExit,
186 /** 186 /**
187 * The application is suspended until the started process is finished. 187 * The application is suspended until the started process is finished.
188 */ 188 */
189 Block }; 189 Block };
190 190
191 /** 191 /**
192 * Constructor 192 * Constructor
193 */ 193 */
194 OProcess( QObject *parent = 0, const char *name = 0 ); 194 OProcess( QObject *parent = 0, const char *name = 0 );
195 /** 195 /**
196 * Constructor 196 * Constructor
197 */ 197 */
198 OProcess( const QString &arg0, QObject *parent = 0, const char *name = 0 ); 198 OProcess( const QString &arg0, QObject *parent = 0, const char *name = 0 );
199 /** 199 /**
200 * Constructor 200 * Constructor
201 */ 201 */
202 OProcess( const QStringList &args, QObject *parent = 0, const char *name = 0 ); 202 OProcess( const QStringList &args, QObject *parent = 0, const char *name = 0 );
203 203
204 /** 204 /**
205 *Destructor: 205 *Destructor:
206 * 206 *
207 * If the process is running when the destructor for this class 207 * If the process is running when the destructor for this class
208 * is called, the child process is killed with a SIGKILL, but 208 * is called, the child process is killed with a SIGKILL, but
209 * only if the run mode is not of type @p DontCare. 209 * only if the run mode is not of type @p DontCare.
210 * Processes started as @p DontCare keep running anyway. 210 * Processes started as @p DontCare keep running anyway.
211 */ 211 */
212 virtual ~OProcess(); 212 virtual ~OProcess();
213 213
214 /** 214 /**
215 @deprecated 215 @deprecated
216 216
217 The use of this function is now deprecated. -- Please use the 217 The use of this function is now deprecated. -- Please use the
218 "operator<<" instead of "setExecutable". 218 "operator<<" instead of "setExecutable".
219 219
220 Sets the executable to be started with this OProcess object. 220 Sets the executable to be started with this OProcess object.
221 Returns false if the process is currently running (in that 221 Returns false if the process is currently running (in that
222 case the executable remains unchanged.) 222 case the executable remains unchanged.)
223 223
224 @see operator<< 224 @see operator<<
225 225
226 */ 226 */
227 bool setExecutable( const QString& proc ); 227 bool setExecutable( const QString& proc );
228 228
229 229
230 /** 230 /**
231 * Sets the executable and the command line argument list for this process. 231 * Sets the executable and the command line argument list for this process.
232 * 232 *
233 * For example, doing an "ls -l /usr/local/bin" can be achieved by: 233 * For example, doing an "ls -l /usr/local/bin" can be achieved by:
234 * <pre> 234 * <pre>
235 * OProcess p; 235 * OProcess p;
236 * ... 236 * ...
237 * p << "ls" << "-l" << "/usr/local/bin" 237 * p << "ls" << "-l" << "/usr/local/bin"
238 * </pre> 238 * </pre>
239 * 239 *
240 **/ 240 **/
241 OProcess &operator<<( const QString& arg ); 241 OProcess &operator<<( const QString& arg );
242 /** 242 /**
243 * Similar to previous method, takes a char *, supposed to be in locale 8 bit already. 243 * Similar to previous method, takes a char *, supposed to be in locale 8 bit already.
244 */ 244 */
245 OProcess &operator<<( const char * arg ); 245 OProcess &operator<<( const char * arg );
246 /** 246 /**
247 * Similar to previous method, takes a QCString, supposed to be in locale 8 bit already. 247 * Similar to previous method, takes a QCString, supposed to be in locale 8 bit already.
248 */ 248 */
249 OProcess &operator<<( const QCString & arg ); 249 OProcess &operator<<( const QCString & arg );
250 250
251 /** 251 /**
252 * Sets the executable and the command line argument list for this process, 252 * Sets the executable and the command line argument list for this process,
253 * in a single method call, or add a list of arguments. 253 * in a single method call, or add a list of arguments.
254 **/ 254 **/
255 OProcess &operator<<( const QStringList& args ); 255 OProcess &operator<<( const QStringList& args );
256 256
257 /** 257 /**
258 * Clear a command line argument list that has been set by using 258 * Clear a command line argument list that has been set by using
259 * the "operator<<". 259 * the "operator<<".
260 */ 260 */
261 void clearArguments(); 261 void clearArguments();
262 262
263 /** 263 /**
264 * Starts the process. 264 * Starts the process.
265 * For a detailed description of the 265 * For a detailed description of the
266 * various run modes and communication semantics, have a look at the 266 * various run modes and communication semantics, have a look at the
267 * general description of the OProcess class. 267 * general description of the OProcess class.
268 * 268 *
269 * The following problems could cause this function to 269 * The following problems could cause this function to
270 * return false: 270 * return false:
271 * 271 *
272 * @li The process is already running. 272 * @li The process is already running.
273 * @li The command line argument list is empty. 273 * @li The command line argument list is empty.
274 * @li The starting of the process failed (could not fork). 274 * @li The starting of the process failed (could not fork).
275 * @li The executable was not found. 275 * @li The executable was not found.
276 * 276 *
277 * @param comm Specifies which communication links should be 277 * @param comm Specifies which communication links should be
278 * established to the child process (stdin/stdout/stderr). By default, 278 * established to the child process (stdin/stdout/stderr). By default,
279 * no communication takes place and the respective communication 279 * no communication takes place and the respective communication
280 * signals will never get emitted. 280 * signals will never get emitted.
281 * 281 *
282 * @return true on success, false on error 282 * @return true on success, false on error
283 * (see above for error conditions) 283 * (see above for error conditions)
284 **/ 284 **/
285 virtual bool start( RunMode runmode = NotifyOnExit, 285 virtual bool start( RunMode runmode = NotifyOnExit,
286 Communication comm = NoCommunication ); 286 Communication comm = NoCommunication );
287 287
288 /** 288 /**
289 * Stop the process (by sending it a signal). 289 * Stop the process (by sending it a signal).
290 * 290 *
291 * @param signoThe signal to send. The default is SIGTERM. 291 * @param signoThe signal to send. The default is SIGTERM.
292 * @return @p true if the signal was delivered successfully. 292 * @return @p true if the signal was delivered successfully.
293 */ 293 */
294 virtual bool kill( int signo = SIGTERM ); 294 virtual bool kill( int signo = SIGTERM );
295 295
296 /** 296 /**
297 @return @p true if the process is (still) considered to be running 297 @return @p true if the process is (still) considered to be running
298 */ 298 */
299 bool isRunning() const; 299 bool isRunning() const;
300 300
301 /** Returns the process id of the process. 301 /** Returns the process id of the process.
302 * 302 *
303 * If it is called after 303 * If it is called after
304 * the process has exited, it returns the process id of the last 304 * the process has exited, it returns the process id of the last
305 * child process that was created by this instance of OProcess. 305 * child process that was created by this instance of OProcess.
306 * 306 *
307 * Calling it before any child process has been started by this 307 * Calling it before any child process has been started by this
308 * OProcess instance causes pid() to return 0. 308 * OProcess instance causes pid() to return 0.
309 **/ 309 **/
310 pid_t pid() const; 310 pid_t pid() const;
311 311
312 /** 312 /**
313 * Suspend processing of data from stdout of the child process. 313 * Suspend processing of data from stdout of the child process.
314 */ 314 */
315 void suspend(); 315 void suspend();
316 316
317 /** 317 /**
318 * Resume processing of data from stdout of the child process. 318 * Resume processing of data from stdout of the child process.
319 */ 319 */
320 void resume(); 320 void resume();
321 321
322 /** 322 /**
323 * @return @p true if the process has already finished and has exited 323 * @return @p true if the process has already finished and has exited
324 * "voluntarily", ie: it has not been killed by a signal. 324 * "voluntarily", ie: it has not been killed by a signal.
325 * 325 *
326 * Note that you should check @ref OProcess::exitStatus() to determine 326 * Note that you should check @ref OProcess::exitStatus() to determine
327 * whether the process completed its task successful or not. 327 * whether the process completed its task successful or not.
328 */ 328 */
329 bool normalExit() const; 329 bool normalExit() const;
330 330
331 /** 331 /**
332 * Returns the exit status of the process. 332 * Returns the exit status of the process.
333 * 333 *
334 * Please use 334 * Please use
335 * @ref OProcess::normalExit() to check whether the process has exited 335 * @ref OProcess::normalExit() to check whether the process has exited
336 * cleanly (i.e., @ref OProcess::normalExit() returns @p true) before calling 336 * cleanly (i.e., @ref OProcess::normalExit() returns @p true) before calling
337 * this function because if the process did not exit normally, 337 * this function because if the process did not exit normally,
338 * it does not have a valid exit status. 338 * it does not have a valid exit status.
339 */ 339 */
340 int exitStatus() const; 340 int exitStatus() const;
341 341
342 342
343 /** 343 /**
344 * Transmit data to the child process's stdin. 344 * Transmit data to the child process's stdin.
345 * 345 *
346 * OProcess::writeStdin may return false in the following cases: 346 * OProcess::writeStdin may return false in the following cases:
347 * 347 *
348 * @li The process is not currently running. 348 * @li The process is not currently running.
349 * 349 *
350 * @li Communication to stdin has not been requested in the @ref start() call. 350 * @li Communication to stdin has not been requested in the @ref start() call.
351 * 351 *
352 * @li Transmission of data to the child process by a previous call to 352 * @li Transmission of data to the child process by a previous call to
353 * @ref writeStdin() is still in progress. 353 * @ref writeStdin() is still in progress.
354 * 354 *
355 * Please note that the data is sent to the client asynchronously, 355 * Please note that the data is sent to the client asynchronously,
356 * so when this function returns, the data might not have been 356 * so when this function returns, the data might not have been
357 * processed by the child process. 357 * processed by the child process.
358 * 358 *
359 * If all the data has been sent to the client, the signal 359 * If all the data has been sent to the client, the signal
360 * @ref wroteStdin() will be emitted. 360 * @ref wroteStdin() will be emitted.
361 * 361 *
362 * Please note that you must not free "buffer" or call @ref writeStdin() 362 * Please note that you must not free "buffer" or call @ref writeStdin()
363 * again until either a @ref wroteStdin() signal indicates that the 363 * again until either a @ref wroteStdin() signal indicates that the
364 * data has been sent or a @ref processHasExited() signal shows that 364 * data has been sent or a @ref processHasExited() signal shows that
365 * the child process is no longer alive... 365 * the child process is no longer alive...
366 **/ 366 **/
367 bool writeStdin( const char *buffer, int buflen ); 367 bool writeStdin( const char *buffer, int buflen );
368 368
369 void flushStdin(); 369 void flushStdin();
370 370
371 /** 371 /**
372 * This causes the stdin file descriptor of the child process to be 372 * This causes the stdin file descriptor of the child process to be
373 * closed indicating an "EOF" to the child. 373 * closed indicating an "EOF" to the child.
374 * 374 *
375 * @return @p false if no communication to the process's stdin 375 * @return @p false if no communication to the process's stdin
376 * had been specified in the call to @ref start(). 376 * had been specified in the call to @ref start().
377 */ 377 */
378 bool closeStdin(); 378 bool closeStdin();
379 379
380 /** 380 /**
381 * This causes the stdout file descriptor of the child process to be 381 * This causes the stdout file descriptor of the child process to be
382 * closed. 382 * closed.
383 * 383 *
384 * @return @p false if no communication to the process's stdout 384 * @return @p false if no communication to the process's stdout
385 * had been specified in the call to @ref start(). 385 * had been specified in the call to @ref start().
386 */ 386 */
387 bool closeStdout(); 387 bool closeStdout();
388 388
389 /** 389 /**
390 * This causes the stderr file descriptor of the child process to be 390 * This causes the stderr file descriptor of the child process to be
391 * closed. 391 * closed.
392 * 392 *
393 * @return @p false if no communication to the process's stderr 393 * @return @p false if no communication to the process's stderr
394 * had been specified in the call to @ref start(). 394 * had been specified in the call to @ref start().
395 */ 395 */
396 bool closeStderr(); 396 bool closeStderr();
397 397
398 /** 398 /**
399 * Lets you see what your arguments are for debugging. 399 * Lets you see what your arguments are for debugging.
400 */ 400 */
401 401
402 const QValueList<QCString> &args() 402 const QValueList<QCString> &args()
403 { 403 {
404 return arguments; 404 return arguments;
405 } 405 }
406 406
407 /** 407 /**
408 * Controls whether the started process should drop any 408 * Controls whether the started process should drop any
409 * setuid/segid privileges or whether it should keep them 409 * setuid/segid privileges or whether it should keep them
410 * 410 *
411 * The default is @p false : drop privileges 411 * The default is @p false : drop privileges
412 */ 412 */
413 void setRunPrivileged( bool keepPrivileges ); 413 void setRunPrivileged( bool keepPrivileges );
414 414
415 /** 415 /**
416 * Returns whether the started process will drop any 416 * Returns whether the started process will drop any
417 * setuid/segid privileges or whether it will keep them 417 * setuid/segid privileges or whether it will keep them
418 */ 418 */
419 bool runPrivileged() const; 419 bool runPrivileged() const;
420 420
421 /** 421 /**
422 * Modifies the environment of the process to be started. 422 * Modifies the environment of the process to be started.
423 * This function must be called before starting the process. 423 * This function must be called before starting the process.
424 */ 424 */
425 void setEnvironment( const QString &name, const QString &value ); 425 void setEnvironment( const QString &name, const QString &value );
426 426
427 /** 427 /**
428 * Changes the current working directory (CWD) of the process 428 * Changes the current working directory (CWD) of the process
429 * to be started. 429 * to be started.
430 * This function must be called before starting the process. 430 * This function must be called before starting the process.
431 */ 431 */
432 void setWorkingDirectory( const QString &dir ); 432 void setWorkingDirectory( const QString &dir );
433 433
434 /** 434 /**
435 * Specify whether to start the command via a shell or directly. 435 * Specify whether to start the command via a shell or directly.
436 * The default is to start the command directly. 436 * The default is to start the command directly.
437 * If @p useShell is true @p shell will be used as shell, or 437 * If @p useShell is true @p shell will be used as shell, or
438 * if shell is empty, the standard shell is used. 438 * if shell is empty, the standard shell is used.
439 * @p quote A flag indicating whether to quote the arguments. 439 * @p quote A flag indicating whether to quote the arguments.
440 * 440 *
441 * When using a shell, the caller should make sure that all filenames etc. 441 * When using a shell, the caller should make sure that all filenames etc.
442 * are properly quoted when passed as argument. 442 * are properly quoted when passed as argument.
443 * @see quote() 443 * @see quote()
444 */ 444 */
445 void setUseShell( bool useShell, const char *shell = 0 ); 445 void setUseShell( bool useShell, const char *shell = 0 );
446 446
447 /** 447 /**
448 * This function can be used to quote an argument string such that 448 * This function can be used to quote an argument string such that
449 * the shell processes it properly. This is e. g. necessary for 449 * the shell processes it properly. This is e. g. necessary for
450 * user-provided file names which may contain spaces or quotes. 450 * user-provided file names which may contain spaces or quotes.
451 * It also prevents expansion of wild cards and environment variables. 451 * It also prevents expansion of wild cards and environment variables.
452 */ 452 */
453 static QString quote( const QString &arg ); 453 static QString quote( const QString &arg );
454 454
455 /** 455 /**
456 * Detaches OProcess from child process. All communication is closed. 456 * Detaches OProcess from child process. All communication is closed.
457 * No exit notification is emitted any more for the child process. 457 * No exit notification is emitted any more for the child process.
458 * Deleting the OProcess will no longer kill the child process. 458 * Deleting the OProcess will no longer kill the child process.
459 * Note that the current process remains the parent process of the 459 * Note that the current process remains the parent process of the
460 * child process. 460 * child process.
461 */ 461 */
462 void detach(); 462 void detach();
463 463
464 /**
465 * @return the PID of @a process, or -1 if the process is not running
466 */
467 static int processPID( const QString& process );
468
464signals: 469signals:
465 470
466 /** 471 /**
467 * Emitted after the process has terminated when 472 * Emitted after the process has terminated when
468 * the process was run in the @p NotifyOnExit (==default option to 473 * the process was run in the @p NotifyOnExit (==default option to
469 * @ref start()) or the @ref Block mode. 474 * @ref start()) or the @ref Block mode.
470 **/ 475 **/
471 void processExited( OProcess *proc ); 476 void processExited( OProcess *proc );
472 477
473 478
474 /** 479 /**
475 * Emitted, when output from the child process has 480 * Emitted, when output from the child process has
476 * been received on stdout. 481 * been received on stdout.
477 * 482 *
478 * To actually get 483 * To actually get
479 * these signals, the respective communication link (stdout/stderr) 484 * these signals, the respective communication link (stdout/stderr)
480 * has to be turned on in @ref start(). 485 * has to be turned on in @ref start().
481 * 486 *
482 * @param buffer The data received. 487 * @param buffer The data received.
483 * @param buflen The number of bytes that are available. 488 * @param buflen The number of bytes that are available.
484 * 489 *
485 * You should copy the information contained in @p buffer to your private 490 * You should copy the information contained in @p buffer to your private
486 * data structures before returning from this slot. 491 * data structures before returning from this slot.
487 **/ 492 **/
488 void receivedStdout( OProcess *proc, char *buffer, int buflen ); 493 void receivedStdout( OProcess *proc, char *buffer, int buflen );
489 494
490 /** 495 /**
491 * Emitted when output from the child process has 496 * Emitted when output from the child process has
492 * been received on stdout. 497 * been received on stdout.
493 * 498 *
494 * To actually get these signals, the respective communications link 499 * To actually get these signals, the respective communications link
495 * (stdout/stderr) has to be turned on in @ref start() and the 500 * (stdout/stderr) has to be turned on in @ref start() and the
496 * @p NoRead flag should have been passed. 501 * @p NoRead flag should have been passed.
497 * 502 *
498 * You will need to explicitly call resume() after your call to start() 503 * You will need to explicitly call resume() after your call to start()
499 * to begin processing data from the child process's stdout. This is 504 * to begin processing data from the child process's stdout. This is
500 * to ensure that this signal is not emitted when no one is connected 505 * to ensure that this signal is not emitted when no one is connected
501 * to it, otherwise this signal will not be emitted. 506 * to it, otherwise this signal will not be emitted.
502 * 507 *
503 * The data still has to be read from file descriptor @p fd. 508 * The data still has to be read from file descriptor @p fd.
504 **/ 509 **/
505 void receivedStdout( int fd, int &len ); 510 void receivedStdout( int fd, int &len );
506 511
507 512
508 /** 513 /**
509 * Emitted, when output from the child process has 514 * Emitted, when output from the child process has
510 * been received on stderr. 515 * been received on stderr.
511 * To actually get 516 * To actually get
512 * these signals, the respective communication link (stdout/stderr) 517 * these signals, the respective communication link (stdout/stderr)
513 * has to be turned on in @ref start(). 518 * has to be turned on in @ref start().
514 * 519 *
515 * @param buffer The data received. 520 * @param buffer The data received.
516 * @param buflen The number of bytes that are available. 521 * @param buflen The number of bytes that are available.
517 * 522 *
518 * You should copy the information contained in @p buffer to your private 523 * You should copy the information contained in @p buffer to your private
519 * data structures before returning from this slot. 524 * data structures before returning from this slot.
520 */ 525 */
521 void receivedStderr( OProcess *proc, char *buffer, int buflen ); 526 void receivedStderr( OProcess *proc, char *buffer, int buflen );
522 527
523 /** 528 /**
524 * Emitted after all the data that has been 529 * Emitted after all the data that has been
525 * specified by a prior call to @ref writeStdin() has actually been 530 * specified by a prior call to @ref writeStdin() has actually been
526 * written to the child process. 531 * written to the child process.
527 **/ 532 **/
528 void wroteStdin( OProcess *proc ); 533 void wroteStdin( OProcess *proc );
529 534
530protected slots: 535protected slots:
531 536
532 /** 537 /**
533 * This slot gets activated when data from the child's stdout arrives. 538 * This slot gets activated when data from the child's stdout arrives.
534 * It usually calls "childOutput" 539 * It usually calls "childOutput"
535 */ 540 */
536 void slotChildOutput( int fdno ); 541 void slotChildOutput( int fdno );
537 542
538 /** 543 /**
539 * This slot gets activated when data from the child's stderr arrives. 544 * This slot gets activated when data from the child's stderr arrives.
540 * It usually calls "childError" 545 * It usually calls "childError"
541 */ 546 */
542 void slotChildError( int fdno ); 547 void slotChildError( int fdno );
543 /* 548 /*
544 Slot functions for capturing stdout and stderr of the child 549 Slot functions for capturing stdout and stderr of the child
545 */ 550 */
546 551
547 /** 552 /**
548 * Called when another bulk of data can be sent to the child's 553 * Called when another bulk of data can be sent to the child's
549 * stdin. If there is no more data to be sent to stdin currently 554 * stdin. If there is no more data to be sent to stdin currently
550 * available, this function must disable the QSocketNotifier "innot". 555 * available, this function must disable the QSocketNotifier "innot".
551 */ 556 */
552 void slotSendData( int dummy ); 557 void slotSendData( int dummy );
553 558
554protected: 559protected:
555 560
556 /** 561 /**
557 * Sets up the environment according to the data passed via 562 * Sets up the environment according to the data passed via
558 * setEnvironment(...) 563 * setEnvironment(...)
559 */ 564 */
560 void setupEnvironment(); 565 void setupEnvironment();
561 566
562 /** 567 /**
563 * The list of the process' command line arguments. The first entry 568 * The list of the process' command line arguments. The first entry
564 * in this list is the executable itself. 569 * in this list is the executable itself.
565 */ 570 */
566 QValueList<QCString> arguments; 571 QValueList<QCString> arguments;
567 /** 572 /**
568 * How to run the process (Block, NotifyOnExit, DontCare). You should 573 * How to run the process (Block, NotifyOnExit, DontCare). You should
569 * not modify this data member directly from derived classes. 574 * not modify this data member directly from derived classes.
570 */ 575 */
571 RunMode run_mode; 576 RunMode run_mode;
572 /** 577 /**
573 * true if the process is currently running. You should not 578 * true if the process is currently running. You should not
574 * modify this data member directly from derived classes. For 579 * modify this data member directly from derived classes. For
575 * reading the value of this data member, please use "isRunning()" 580 * reading the value of this data member, please use "isRunning()"
576 * since "runs" will probably be made private in later versions 581 * since "runs" will probably be made private in later versions
577 * of OProcess. 582 * of OProcess.
578 */ 583 */
579 bool runs; 584 bool runs;
580 585
581 /** 586 /**
582 * The PID of the currently running process (see "getPid()"). 587 * The PID of the currently running process (see "getPid()").
583 * You should not modify this data member in derived classes. 588 * You should not modify this data member in derived classes.
584 * Please use "getPid()" instead of directly accessing this 589 * Please use "getPid()" instead of directly accessing this
585 * member function since it will probably be made private in 590 * member function since it will probably be made private in
586 * later versions of OProcess. 591 * later versions of OProcess.
587 */ 592 */
588 pid_t pid_; 593 pid_t pid_;
589 594
590 /** 595 /**
591 * The process' exit status as returned by "waitpid". You should not 596 * The process' exit status as returned by "waitpid". You should not
592 * modify the value of this data member from derived classes. You should 597 * modify the value of this data member from derived classes. You should
593 * rather use @ref exitStatus than accessing this data member directly 598 * rather use @ref exitStatus than accessing this data member directly
594 * since it will probably be made private in further versions of 599 * since it will probably be made private in further versions of
595 * OProcess. 600 * OProcess.
596 */ 601 */
597 int status; 602 int status;
598 603
599 604
600 /** 605 /**
601 * See setRunPrivileged() 606 * See setRunPrivileged()
602 */ 607 */
603 bool keepPrivs; 608 bool keepPrivs;
604 609
605 /* 610 /*
606 Functions for setting up the sockets for communication. 611 Functions for setting up the sockets for communication.
607 setupCommunication 612 setupCommunication
608 -- is called from "start" before "fork"ing. 613 -- is called from "start" before "fork"ing.
609 commSetupDoneP 614 commSetupDoneP
610 -- completes communication socket setup in the parent 615 -- completes communication socket setup in the parent
611 commSetupDoneC 616 commSetupDoneC
612 -- completes communication setup in the child process 617 -- completes communication setup in the child process
613 commClose 618 commClose
614 -- frees all allocated communication resources in the parent 619 -- frees all allocated communication resources in the parent
615 after the process has exited 620 after the process has exited
616 */ 621 */
617 622
618 /** 623 /**
619 * This function is called from "OProcess::start" right before a "fork" takes 624 * This function is called from "OProcess::start" right before a "fork" takes
620 * place. According to 625 * place. According to
621 * the "comm" parameter this function has to initialize the "in", "out" and 626 * the "comm" parameter this function has to initialize the "in", "out" and
622 * "err" data member of OProcess. 627 * "err" data member of OProcess.
623 * 628 *
624 * This function should return 0 if setting the needed communication channels 629 * This function should return 0 if setting the needed communication channels
625 * was successful. 630 * was successful.
626 * 631 *
627 * The default implementation is to create UNIX STREAM sockets for the communication, 632 * The default implementation is to create UNIX STREAM sockets for the communication,
628 * but you could overload this function and establish a TCP/IP communication for 633 * but you could overload this function and establish a TCP/IP communication for
629 * network communication, for example. 634 * network communication, for example.
630 */ 635 */
631 virtual int setupCommunication( Communication comm ); 636 virtual int setupCommunication( Communication comm );
632 637
633 /** 638 /**
634 * Called right after a (successful) fork on the parent side. This function 639 * Called right after a (successful) fork on the parent side. This function
635 * will usually do some communications cleanup, like closing the reading end 640 * will usually do some communications cleanup, like closing the reading end
636 * of the "stdin" communication channel. 641 * of the "stdin" communication channel.
637 * 642 *
638 * Furthermore, it must also create the QSocketNotifiers "innot", "outnot" and 643 * Furthermore, it must also create the QSocketNotifiers "innot", "outnot" and
639 * "errnot" and connect their Qt slots to the respective OProcess member functions. 644 * "errnot" and connect their Qt slots to the respective OProcess member functions.
640 * 645 *
641 * For a more detailed explanation, it is best to have a look at the default 646 * For a more detailed explanation, it is best to have a look at the default
642 * implementation of "setupCommunication" in kprocess.cpp. 647 * implementation of "setupCommunication" in kprocess.cpp.
643 */ 648 */
644 virtual int commSetupDoneP(); 649 virtual int commSetupDoneP();
645 650
646 /** 651 /**
647 * Called right after a (successful) fork, but before an "exec" on the child 652 * Called right after a (successful) fork, but before an "exec" on the child
648 * process' side. It usually just closes the unused communication ends of 653 * process' side. It usually just closes the unused communication ends of
649 * "in", "out" and "err" (like the writing end of the "in" communication 654 * "in", "out" and "err" (like the writing end of the "in" communication
650 * channel. 655 * channel.
651 */ 656 */
652 virtual int commSetupDoneC(); 657 virtual int commSetupDoneC();
653 658
654 659
655 /** 660 /**
656 * Immediately called after a process has exited. This function normally 661 * Immediately called after a process has exited. This function normally
657 * calls commClose to close all open communication channels to this 662 * calls commClose to close all open communication channels to this
658 * process and emits the "processExited" signal (if the process was 663 * process and emits the "processExited" signal (if the process was
659 * not running in the "DontCare" mode). 664 * not running in the "DontCare" mode).
660 */ 665 */
661 virtual void processHasExited( int state ); 666 virtual void processHasExited( int state );
662 667
663 /** 668 /**
664 * Should clean up the communication links to the child after it has 669 * Should clean up the communication links to the child after it has
665 * exited. Should be called from "processHasExited". 670 * exited. Should be called from "processHasExited".
666 */ 671 */
667 virtual void commClose(); 672 virtual void commClose();
668 673
669 674
670 /** 675 /**
671 * the socket descriptors for stdin/stdout/stderr. 676 * the socket descriptors for stdin/stdout/stderr.
672 */ 677 */
673 int out[ 2 ]; 678 int out[ 2 ];
674 int in[ 2 ]; 679 int in[ 2 ];
675 int err[ 2 ]; 680 int err[ 2 ];
676 681
677 /** 682 /**
678 * The socket notifiers for the above socket descriptors. 683 * The socket notifiers for the above socket descriptors.
679 */ 684 */
680 QSocketNotifier *innot; 685 QSocketNotifier *innot;
681 QSocketNotifier *outnot; 686 QSocketNotifier *outnot;
682 QSocketNotifier *errnot; 687 QSocketNotifier *errnot;
683 688
684 /** 689 /**
685 * Lists the communication links that are activated for the child 690 * Lists the communication links that are activated for the child
686 * process. Should not be modified from derived classes. 691 * process. Should not be modified from derived classes.
687 */ 692 */
688 Communication communication; 693 Communication communication;
689 694
690 /** 695 /**
691 * Called by "slotChildOutput" this function copies data arriving from the 696 * Called by "slotChildOutput" this function copies data arriving from the
692 * child process's stdout to the respective buffer and emits the signal 697 * child process's stdout to the respective buffer and emits the signal
693 * "@ref receivedStderr". 698 * "@ref receivedStderr".
694 */ 699 */
695 int childOutput( int fdno ); 700 int childOutput( int fdno );
696 701
697 /** 702 /**
698 * Called by "slotChildOutput" this function copies data arriving from the 703 * Called by "slotChildOutput" this function copies data arriving from the
699 * child process's stdout to the respective buffer and emits the signal 704 * child process's stdout to the respective buffer and emits the signal
700 * "@ref receivedStderr" 705 * "@ref receivedStderr"
701 */ 706 */
702 int childError( int fdno ); 707 int childError( int fdno );
703 708
704 // information about the data that has to be sent to the child: 709 // information about the data that has to be sent to the child:
705 710
706 const char *input_data; // the buffer holding the data 711 const char *input_data; // the buffer holding the data
707 int input_sent; // # of bytes already transmitted 712 int input_sent; // # of bytes already transmitted
708 int input_total; // total length of input_data 713 int input_total; // total length of input_data
709 714
710 /** 715 /**
711 * @ref OProcessController is a friend of OProcess because it has to have 716 * @ref OProcessController is a friend of OProcess because it has to have
712 * access to various data members. 717 * access to various data members.
713 */ 718 */
714 friend class OProcessController; 719 friend class OProcessController;
715 720
716private: 721private:
717 /** 722 /**
718 * Searches for a valid shell. 723 * Searches for a valid shell.
719 * Here is the algorithm used for finding an executable shell: 724 * Here is the algorithm used for finding an executable shell:
720 * 725 *
721 * @li Try the executable pointed to by the "SHELL" environment 726 * @li Try the executable pointed to by the "SHELL" environment
722 * variable with white spaces stripped off 727 * variable with white spaces stripped off
723 * 728 *
724 * @li If your process runs with uid != euid or gid != egid, a shell 729 * @li If your process runs with uid != euid or gid != egid, a shell
725 * not listed in /etc/shells will not used. 730 * not listed in /etc/shells will not used.
726 * 731 *
727 * @li If no valid shell could be found, "/bin/sh" is used as a last resort. 732 * @li If no valid shell could be found, "/bin/sh" is used as a last resort.
728 */ 733 */
729 QCString searchShell(); 734 QCString searchShell();
730 735
731 /** 736 /**
732 * Used by @ref searchShell in order to find out whether the shell found 737 * Used by @ref searchShell in order to find out whether the shell found
733 * is actually executable at all. 738 * is actually executable at all.
734 */ 739 */
735 bool isExecutable( const QCString &filename ); 740 bool isExecutable( const QCString &filename );
736 741
737 // Disallow assignment and copy-construction 742 // Disallow assignment and copy-construction
738 OProcess( const OProcess& ); 743 OProcess( const OProcess& );
739 OProcess& operator= ( const OProcess& ); 744 OProcess& operator= ( const OProcess& );
740 745
741private: 746private:
742 void init ( ); 747 void init ( );
743 OProcessPrivate *d; 748 OProcessPrivate *d;
744}; 749};
745 750
746#endif 751#endif
747 752