summaryrefslogtreecommitdiffabout
path: root/microkde/oprocess.cpp
Unidiff
Diffstat (limited to 'microkde/oprocess.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r--microkde/oprocess.cpp1
1 files changed, 1 insertions, 0 deletions
diff --git a/microkde/oprocess.cpp b/microkde/oprocess.cpp
index 95e3e4b..a935792 100644
--- a/microkde/oprocess.cpp
+++ b/microkde/oprocess.cpp
@@ -1,808 +1,809 @@
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 <oprocess.h> 34#include <oprocess.h>
35 35
36/* QT */ 36/* QT */
37 37
38#include <qapplication.h> 38#include <qapplication.h>
39#include <qdir.h> 39#include <qdir.h>
40#include <qmap.h> 40#include <qmap.h>
41#include <qregexp.h>
41#include <qsocketnotifier.h> 42#include <qsocketnotifier.h>
42#include <qtextstream.h> 43#include <qtextstream.h>
43 44
44/* STD */ 45/* STD */
45#include <errno.h> 46#include <errno.h>
46#include <fcntl.h> 47#include <fcntl.h>
47#include <pwd.h> 48#include <pwd.h>
48#include <stdlib.h> 49#include <stdlib.h>
49#include <signal.h> 50#include <signal.h>
50#include <stdio.h> 51#include <stdio.h>
51#include <string.h> 52#include <string.h>
52#include <sys/time.h> 53#include <sys/time.h>
53#include <sys/types.h> 54#include <sys/types.h>
54#include <sys/stat.h> 55#include <sys/stat.h>
55#include <sys/socket.h> 56#include <sys/socket.h>
56#include <unistd.h> 57#include <unistd.h>
57#ifdef HAVE_SYS_SELECT_H 58#ifdef HAVE_SYS_SELECT_H
58#include <sys/select.h> 59#include <sys/select.h>
59#endif 60#endif
60#ifdef HAVE_INITGROUPS 61#ifdef HAVE_INITGROUPS
61#include <grp.h> 62#include <grp.h>
62#endif 63#endif
63 64
64using namespace Opie::Core::Internal; 65using namespace Opie::Core::Internal;
65 66
66namespace Opie { 67namespace Opie {
67namespace Core { 68namespace Core {
68namespace Internal { 69namespace Internal {
69class OProcessPrivate 70class OProcessPrivate
70{ 71{
71public: 72public:
72 OProcessPrivate() : useShell( false ) 73 OProcessPrivate() : useShell( false )
73 { } 74 { }
74 75
75 bool useShell; 76 bool useShell;
76 QMap<QString, QString> env; 77 QMap<QString, QString> env;
77 QString wd; 78 QString wd;
78 QCString shell; 79 QCString shell;
79}; 80};
80} 81}
81 82
82OProcess::OProcess( QObject *parent, const char *name ) 83OProcess::OProcess( QObject *parent, const char *name )
83 : QObject( parent, name ) 84 : QObject( parent, name )
84{ 85{
85 init ( ); 86 init ( );
86} 87}
87 88
88OProcess::OProcess( const QString &arg0, QObject *parent, const char *name ) 89OProcess::OProcess( const QString &arg0, QObject *parent, const char *name )
89 : QObject( parent, name ) 90 : QObject( parent, name )
90{ 91{
91 init ( ); 92 init ( );
92 *this << arg0; 93 *this << arg0;
93} 94}
94 95
95OProcess::OProcess( const QStringList &args, QObject *parent, const char *name ) 96OProcess::OProcess( const QStringList &args, QObject *parent, const char *name )
96 : QObject( parent, name ) 97 : QObject( parent, name )
97{ 98{
98 init ( ); 99 init ( );
99 *this << args; 100 *this << args;
100} 101}
101 102
102void OProcess::init ( ) 103void OProcess::init ( )
103{ 104{
104 run_mode = NotifyOnExit; 105 run_mode = NotifyOnExit;
105 runs = false; 106 runs = false;
106 pid_ = 0; 107 pid_ = 0;
107 status = 0; 108 status = 0;
108 keepPrivs = false; 109 keepPrivs = false;
109 innot = 0; 110 innot = 0;
110 outnot = 0; 111 outnot = 0;
111 errnot = 0; 112 errnot = 0;
112 communication = NoCommunication; 113 communication = NoCommunication;
113 input_data = 0; 114 input_data = 0;
114 input_sent = 0; 115 input_sent = 0;
115 input_total = 0; 116 input_total = 0;
116 d = 0; 117 d = 0;
117 118
118 if ( 0 == OProcessController::theOProcessController ) 119 if ( 0 == OProcessController::theOProcessController )
119 { 120 {
120 ( void ) new OProcessController(); 121 ( void ) new OProcessController();
121 CHECK_PTR( OProcessController::theOProcessController ); 122 CHECK_PTR( OProcessController::theOProcessController );
122 } 123 }
123 124
124 OProcessController::theOProcessController->addOProcess( this ); 125 OProcessController::theOProcessController->addOProcess( this );
125 out[ 0 ] = out[ 1 ] = -1; 126 out[ 0 ] = out[ 1 ] = -1;
126 in[ 0 ] = in[ 1 ] = -1; 127 in[ 0 ] = in[ 1 ] = -1;
127 err[ 0 ] = err[ 1 ] = -1; 128 err[ 0 ] = err[ 1 ] = -1;
128} 129}
129 130
130void OProcess::setEnvironment( const QString &name, const QString &value ) 131void OProcess::setEnvironment( const QString &name, const QString &value )
131{ 132{
132 if ( !d ) 133 if ( !d )
133 d = new OProcessPrivate; 134 d = new OProcessPrivate;
134 d->env.insert( name, value ); 135 d->env.insert( name, value );
135} 136}
136 137
137void OProcess::setWorkingDirectory( const QString &dir ) 138void OProcess::setWorkingDirectory( const QString &dir )
138{ 139{
139 if ( !d ) 140 if ( !d )
140 d = new OProcessPrivate; 141 d = new OProcessPrivate;
141 d->wd = dir; 142 d->wd = dir;
142} 143}
143 144
144void OProcess::setupEnvironment() 145void OProcess::setupEnvironment()
145{ 146{
146 if ( d ) 147 if ( d )
147 { 148 {
148 QMap<QString, QString>::Iterator it; 149 QMap<QString, QString>::Iterator it;
149 for ( it = d->env.begin(); it != d->env.end(); ++it ) 150 for ( it = d->env.begin(); it != d->env.end(); ++it )
150 setenv( QFile::encodeName( it.key() ).data(), 151 setenv( QFile::encodeName( it.key() ).data(),
151 QFile::encodeName( it.data() ).data(), 1 ); 152 QFile::encodeName( it.data() ).data(), 1 );
152 if ( !d->wd.isEmpty() ) 153 if ( !d->wd.isEmpty() )
153 chdir( QFile::encodeName( d->wd ).data() ); 154 chdir( QFile::encodeName( d->wd ).data() );
154 } 155 }
155} 156}
156 157
157void OProcess::setRunPrivileged( bool keepPrivileges ) 158void OProcess::setRunPrivileged( bool keepPrivileges )
158{ 159{
159 keepPrivs = keepPrivileges; 160 keepPrivs = keepPrivileges;
160} 161}
161 162
162bool OProcess::runPrivileged() const 163bool OProcess::runPrivileged() const
163{ 164{
164 return keepPrivs; 165 return keepPrivs;
165} 166}
166 167
167OProcess::~OProcess() 168OProcess::~OProcess()
168{ 169{
169 // destroying the OProcess instance sends a SIGKILL to the 170 // destroying the OProcess instance sends a SIGKILL to the
170 // child process (if it is running) after removing it from the 171 // child process (if it is running) after removing it from the
171 // list of valid processes (if the process is not started as 172 // list of valid processes (if the process is not started as
172 // "DontCare") 173 // "DontCare")
173 174
174 OProcessController::theOProcessController->removeOProcess( this ); 175 OProcessController::theOProcessController->removeOProcess( this );
175 // this must happen before we kill the child 176 // this must happen before we kill the child
176 // TODO: block the signal while removing the current process from the process list 177 // TODO: block the signal while removing the current process from the process list
177 178
178 if ( runs && ( run_mode != DontCare ) ) 179 if ( runs && ( run_mode != DontCare ) )
179 kill( SIGKILL ); 180 kill( SIGKILL );
180 181
181 // Clean up open fd's and socket notifiers. 182 // Clean up open fd's and socket notifiers.
182 closeStdin(); 183 closeStdin();
183 closeStdout(); 184 closeStdout();
184 closeStderr(); 185 closeStderr();
185 186
186 // TODO: restore SIGCHLD and SIGPIPE handler if this is the last OProcess 187 // TODO: restore SIGCHLD and SIGPIPE handler if this is the last OProcess
187 delete d; 188 delete d;
188} 189}
189 190
190void OProcess::detach() 191void OProcess::detach()
191{ 192{
192 OProcessController::theOProcessController->removeOProcess( this ); 193 OProcessController::theOProcessController->removeOProcess( this );
193 194
194 runs = false; 195 runs = false;
195 pid_ = 0; 196 pid_ = 0;
196 197
197 // Clean up open fd's and socket notifiers. 198 // Clean up open fd's and socket notifiers.
198 closeStdin(); 199 closeStdin();
199 closeStdout(); 200 closeStdout();
200 closeStderr(); 201 closeStderr();
201} 202}
202 203
203bool OProcess::setExecutable( const QString& proc ) 204bool OProcess::setExecutable( const QString& proc )
204{ 205{
205 if ( runs ) 206 if ( runs )
206 return false; 207 return false;
207 208
208 if ( proc.isEmpty() ) 209 if ( proc.isEmpty() )
209 return false; 210 return false;
210 211
211 if ( !arguments.isEmpty() ) 212 if ( !arguments.isEmpty() )
212 arguments.remove( arguments.begin() ); 213 arguments.remove( arguments.begin() );
213 arguments.prepend( QFile::encodeName( proc ) ); 214 arguments.prepend( QFile::encodeName( proc ) );
214 215
215 return true; 216 return true;
216} 217}
217 218
218OProcess &OProcess::operator<<( const QStringList& args ) 219OProcess &OProcess::operator<<( const QStringList& args )
219{ 220{
220 QStringList::ConstIterator it = args.begin(); 221 QStringList::ConstIterator it = args.begin();
221 for ( ; it != args.end() ; ++it ) 222 for ( ; it != args.end() ; ++it )
222 arguments.append( QFile::encodeName( *it ) ); 223 arguments.append( QFile::encodeName( *it ) );
223 return *this; 224 return *this;
224} 225}
225 226
226OProcess &OProcess::operator<<( const QCString& arg ) 227OProcess &OProcess::operator<<( const QCString& arg )
227{ 228{
228 return operator<< ( arg.data() ); 229 return operator<< ( arg.data() );
229} 230}
230 231
231OProcess &OProcess::operator<<( const char* arg ) 232OProcess &OProcess::operator<<( const char* arg )
232{ 233{
233 arguments.append( arg ); 234 arguments.append( arg );
234 return *this; 235 return *this;
235} 236}
236 237
237OProcess &OProcess::operator<<( const QString& arg ) 238OProcess &OProcess::operator<<( const QString& arg )
238{ 239{
239 arguments.append( QFile::encodeName( arg ) ); 240 arguments.append( QFile::encodeName( arg ) );
240 return *this; 241 return *this;
241} 242}
242 243
243void OProcess::clearArguments() 244void OProcess::clearArguments()
244{ 245{
245 arguments.clear(); 246 arguments.clear();
246} 247}
247 248
248bool OProcess::start( RunMode runmode, Communication comm ) 249bool OProcess::start( RunMode runmode, Communication comm )
249{ 250{
250 uint i; 251 uint i;
251 uint n = arguments.count(); 252 uint n = arguments.count();
252 char **arglist; 253 char **arglist;
253 254
254 if ( runs || ( 0 == n ) ) 255 if ( runs || ( 0 == n ) )
255 { 256 {
256 return false; // cannot start a process that is already running 257 return false; // cannot start a process that is already running
257 // or if no executable has been assigned 258 // or if no executable has been assigned
258 } 259 }
259 run_mode = runmode; 260 run_mode = runmode;
260 status = 0; 261 status = 0;
261 262
262 QCString shellCmd; 263 QCString shellCmd;
263 if ( d && d->useShell ) 264 if ( d && d->useShell )
264 { 265 {
265 if ( d->shell.isEmpty() ) 266 if ( d->shell.isEmpty() )
266 { 267 {
267 qWarning( "Could not find a valid shell" ); 268 qWarning( "Could not find a valid shell" );
268 return false; 269 return false;
269 } 270 }
270 271
271 arglist = static_cast<char **>( malloc( ( 4 ) * sizeof( char * ) ) ); 272 arglist = static_cast<char **>( malloc( ( 4 ) * sizeof( char * ) ) );
272 for ( i = 0; i < n; i++ ) 273 for ( i = 0; i < n; i++ )
273 { 274 {
274 shellCmd += arguments[ i ]; 275 shellCmd += arguments[ i ];
275 shellCmd += " "; // CC: to separate the arguments 276 shellCmd += " "; // CC: to separate the arguments
276 } 277 }
277 278
278 arglist[ 0 ] = d->shell.data(); 279 arglist[ 0 ] = d->shell.data();
279 arglist[ 1 ] = ( char * ) "-c"; 280 arglist[ 1 ] = ( char * ) "-c";
280 arglist[ 2 ] = shellCmd.data(); 281 arglist[ 2 ] = shellCmd.data();
281 arglist[ 3 ] = 0; 282 arglist[ 3 ] = 0;
282 } 283 }
283 else 284 else
284 { 285 {
285 arglist = static_cast<char **>( malloc( ( n + 1 ) * sizeof( char * ) ) ); 286 arglist = static_cast<char **>( malloc( ( n + 1 ) * sizeof( char * ) ) );
286 for ( i = 0; i < n; i++ ) 287 for ( i = 0; i < n; i++ )
287 arglist[ i ] = arguments[ i ].data(); 288 arglist[ i ] = arguments[ i ].data();
288 arglist[ n ] = 0; 289 arglist[ n ] = 0;
289 } 290 }
290 291
291 if ( !setupCommunication( comm ) ) 292 if ( !setupCommunication( comm ) )
292 qWarning( "Could not setup Communication!" ); 293 qWarning( "Could not setup Communication!" );
293 294
294 // We do this in the parent because if we do it in the child process 295 // We do this in the parent because if we do it in the child process
295 // gdb gets confused when the application runs from gdb. 296 // gdb gets confused when the application runs from gdb.
296 uid_t uid = getuid(); 297 uid_t uid = getuid();
297 gid_t gid = getgid(); 298 gid_t gid = getgid();
298#ifdef HAVE_INITGROUPS 299#ifdef HAVE_INITGROUPS
299 300
300 struct passwd *pw = getpwuid( uid ); 301 struct passwd *pw = getpwuid( uid );
301#endif 302#endif
302 303
303 int fd[ 2 ]; 304 int fd[ 2 ];
304 if ( 0 > pipe( fd ) ) 305 if ( 0 > pipe( fd ) )
305 { 306 {
306 fd[ 0 ] = fd[ 1 ] = 0; // Pipe failed.. continue 307 fd[ 0 ] = fd[ 1 ] = 0; // Pipe failed.. continue
307 } 308 }
308 309
309 runs = true; 310 runs = true;
310 311
311 QApplication::flushX(); 312 QApplication::flushX();
312 313
313 // WABA: Note that we use fork() and not vfork() because 314 // WABA: Note that we use fork() and not vfork() because
314 // vfork() has unclear semantics and is not standardized. 315 // vfork() has unclear semantics and is not standardized.
315 pid_ = fork(); 316 pid_ = fork();
316 317
317 if ( 0 == pid_ ) 318 if ( 0 == pid_ )
318 { 319 {
319 if ( fd[ 0 ] ) 320 if ( fd[ 0 ] )
320 close( fd[ 0 ] ); 321 close( fd[ 0 ] );
321 if ( !runPrivileged() ) 322 if ( !runPrivileged() )
322 { 323 {
323 setgid( gid ); 324 setgid( gid );
324#if defined( HAVE_INITGROUPS) 325#if defined( HAVE_INITGROUPS)
325 326
326 if ( pw ) 327 if ( pw )
327 initgroups( pw->pw_name, pw->pw_gid ); 328 initgroups( pw->pw_name, pw->pw_gid );
328#endif 329#endif
329 330
330 setuid( uid ); 331 setuid( uid );
331 } 332 }
332 // The child process 333 // The child process
333 if ( !commSetupDoneC() ) 334 if ( !commSetupDoneC() )
334 qWarning( "Could not finish comm setup in child!" ); 335 qWarning( "Could not finish comm setup in child!" );
335 336
336 setupEnvironment(); 337 setupEnvironment();
337 338
338 // Matthias 339 // Matthias
339 if ( run_mode == DontCare ) 340 if ( run_mode == DontCare )
340 setpgid( 0, 0 ); 341 setpgid( 0, 0 );
341 // restore default SIGPIPE handler (Harri) 342 // restore default SIGPIPE handler (Harri)
342 struct sigaction act; 343 struct sigaction act;
343 sigemptyset( &( act.sa_mask ) ); 344 sigemptyset( &( act.sa_mask ) );
344 sigaddset( &( act.sa_mask ), SIGPIPE ); 345 sigaddset( &( act.sa_mask ), SIGPIPE );
345 act.sa_handler = SIG_DFL; 346 act.sa_handler = SIG_DFL;
346 act.sa_flags = 0; 347 act.sa_flags = 0;
347 sigaction( SIGPIPE, &act, 0L ); 348 sigaction( SIGPIPE, &act, 0L );
348 349
349 // We set the close on exec flag. 350 // We set the close on exec flag.
350 // Closing of fd[1] indicates that the execvp succeeded! 351 // Closing of fd[1] indicates that the execvp succeeded!
351 if ( fd[ 1 ] ) 352 if ( fd[ 1 ] )
352 fcntl( fd[ 1 ], F_SETFD, FD_CLOEXEC ); 353 fcntl( fd[ 1 ], F_SETFD, FD_CLOEXEC );
353 execvp( arglist[ 0 ], arglist ); 354 execvp( arglist[ 0 ], arglist );
354 char resultByte = 1; 355 char resultByte = 1;
355 if ( fd[ 1 ] ) 356 if ( fd[ 1 ] )
356 write( fd[ 1 ], &resultByte, 1 ); 357 write( fd[ 1 ], &resultByte, 1 );
357 _exit( -1 ); 358 _exit( -1 );
358 } 359 }
359 else if ( -1 == pid_ ) 360 else if ( -1 == pid_ )
360 { 361 {
361 // forking failed 362 // forking failed
362 363
363 runs = false; 364 runs = false;
364 free( arglist ); 365 free( arglist );
365 return false; 366 return false;
366 } 367 }
367 else 368 else
368 { 369 {
369 if ( fd[ 1 ] ) 370 if ( fd[ 1 ] )
370 close( fd[ 1 ] ); 371 close( fd[ 1 ] );
371 // the parent continues here 372 // the parent continues here
372 373
373 // Discard any data for stdin that might still be there 374 // Discard any data for stdin that might still be there
374 input_data = 0; 375 input_data = 0;
375 376
376 // Check whether client could be started. 377 // Check whether client could be started.
377 if ( fd[ 0 ] ) 378 if ( fd[ 0 ] )
378 for ( ;; ) 379 for ( ;; )
379 { 380 {
380 char resultByte; 381 char resultByte;
381 int n = ::read( fd[ 0 ], &resultByte, 1 ); 382 int n = ::read( fd[ 0 ], &resultByte, 1 );
382 if ( n == 1 ) 383 if ( n == 1 )
383 { 384 {
384 // Error 385 // Error
385 runs = false; 386 runs = false;
386 close( fd[ 0 ] ); 387 close( fd[ 0 ] );
387 free( arglist ); 388 free( arglist );
388 pid_ = 0; 389 pid_ = 0;
389 return false; 390 return false;
390 } 391 }
391 if ( n == -1 ) 392 if ( n == -1 )
392 { 393 {
393 if ( ( errno == ECHILD ) || ( errno == EINTR ) ) 394 if ( ( errno == ECHILD ) || ( errno == EINTR ) )
394 continue; // Ignore 395 continue; // Ignore
395 } 396 }
396 break; // success 397 break; // success
397 } 398 }
398 if ( fd[ 0 ] ) 399 if ( fd[ 0 ] )
399 close( fd[ 0 ] ); 400 close( fd[ 0 ] );
400 401
401 if ( !commSetupDoneP() ) // finish communication socket setup for the parent 402 if ( !commSetupDoneP() ) // finish communication socket setup for the parent
402 qWarning( "Could not finish comm setup in parent!" ); 403 qWarning( "Could not finish comm setup in parent!" );
403 404
404 if ( run_mode == Block ) 405 if ( run_mode == Block )
405 { 406 {
406 commClose(); 407 commClose();
407 408
408 // The SIGCHLD handler of the process controller will catch 409 // The SIGCHLD handler of the process controller will catch
409 // the exit and set the status 410 // the exit and set the status
410 while ( runs ) 411 while ( runs )
411 { 412 {
412 OProcessController::theOProcessController-> 413 OProcessController::theOProcessController->
413 slotDoHousekeeping( 0 ); 414 slotDoHousekeeping( 0 );
414 } 415 }
415 runs = FALSE; 416 runs = FALSE;
416 emit processExited( this ); 417 emit processExited( this );
417 } 418 }
418 } 419 }
419 free( arglist ); 420 free( arglist );
420 return true; 421 return true;
421} 422}
422 423
423 424
424 425
425bool OProcess::kill( int signo ) 426bool OProcess::kill( int signo )
426{ 427{
427 bool rv = false; 428 bool rv = false;
428 429
429 if ( 0 != pid_ ) 430 if ( 0 != pid_ )
430 rv = ( -1 != ::kill( pid_, signo ) ); 431 rv = ( -1 != ::kill( pid_, signo ) );
431 // probably store errno somewhere... 432 // probably store errno somewhere...
432 return rv; 433 return rv;
433} 434}
434 435
435bool OProcess::isRunning() const 436bool OProcess::isRunning() const
436{ 437{
437 return runs; 438 return runs;
438} 439}
439 440
440pid_t OProcess::pid() const 441pid_t OProcess::pid() const
441{ 442{
442 return pid_; 443 return pid_;
443} 444}
444 445
445bool OProcess::normalExit() const 446bool OProcess::normalExit() const
446{ 447{
447 int _status = status; 448 int _status = status;
448 return ( pid_ != 0 ) && ( !runs ) && ( WIFEXITED( ( _status ) ) ); 449 return ( pid_ != 0 ) && ( !runs ) && ( WIFEXITED( ( _status ) ) );
449} 450}
450 451
451int OProcess::exitStatus() const 452int OProcess::exitStatus() const
452{ 453{
453 int _status = status; 454 int _status = status;
454 return WEXITSTATUS( ( _status ) ); 455 return WEXITSTATUS( ( _status ) );
455} 456}
456 457
457bool OProcess::writeStdin( const char *buffer, int buflen ) 458bool OProcess::writeStdin( const char *buffer, int buflen )
458{ 459{
459 bool rv; 460 bool rv;
460 461
461 // if there is still data pending, writing new data 462 // if there is still data pending, writing new data
462 // to stdout is not allowed (since it could also confuse 463 // to stdout is not allowed (since it could also confuse
463 // kprocess... 464 // kprocess...
464 if ( 0 != input_data ) 465 if ( 0 != input_data )
465 return false; 466 return false;
466 467
467 if ( runs && ( communication & Stdin ) ) 468 if ( runs && ( communication & Stdin ) )
468 { 469 {
469 input_data = buffer; 470 input_data = buffer;
470 input_sent = 0; 471 input_sent = 0;
471 input_total = buflen; 472 input_total = buflen;
472 slotSendData( 0 ); 473 slotSendData( 0 );
473 innot->setEnabled( true ); 474 innot->setEnabled( true );
474 rv = true; 475 rv = true;
475 } 476 }
476 else 477 else
477 rv = false; 478 rv = false;
478 return rv; 479 return rv;
479} 480}
480 481
481void OProcess::flushStdin ( ) 482void OProcess::flushStdin ( )
482{ 483{
483 if ( !input_data || ( input_sent == input_total ) ) 484 if ( !input_data || ( input_sent == input_total ) )
484 return ; 485 return ;
485 486
486 int d1, d2; 487 int d1, d2;
487 488
488 do 489 do
489 { 490 {
490 d1 = input_total - input_sent; 491 d1 = input_total - input_sent;
491 slotSendData ( 0 ); 492 slotSendData ( 0 );
492 d2 = input_total - input_sent; 493 d2 = input_total - input_sent;
493 } 494 }
494 while ( d2 <= d1 ); 495 while ( d2 <= d1 );
495} 496}
496 497
497void OProcess::suspend() 498void OProcess::suspend()
498{ 499{
499 if ( ( communication & Stdout ) && outnot ) 500 if ( ( communication & Stdout ) && outnot )
500 outnot->setEnabled( false ); 501 outnot->setEnabled( false );
501} 502}
502 503
503void OProcess::resume() 504void OProcess::resume()
504{ 505{
505 if ( ( communication & Stdout ) && outnot ) 506 if ( ( communication & Stdout ) && outnot )
506 outnot->setEnabled( true ); 507 outnot->setEnabled( true );
507} 508}
508 509
509bool OProcess::closeStdin() 510bool OProcess::closeStdin()
510{ 511{
511 bool rv; 512 bool rv;
512 513
513 if ( communication & Stdin ) 514 if ( communication & Stdin )
514 { 515 {
515 communication = ( Communication ) ( communication & ~Stdin ); 516 communication = ( Communication ) ( communication & ~Stdin );
516 delete innot; 517 delete innot;
517 innot = 0; 518 innot = 0;
518 close( in[ 1 ] ); 519 close( in[ 1 ] );
519 rv = true; 520 rv = true;
520 } 521 }
521 else 522 else
522 rv = false; 523 rv = false;
523 return rv; 524 return rv;
524} 525}
525 526
526bool OProcess::closeStdout() 527bool OProcess::closeStdout()
527{ 528{
528 bool rv; 529 bool rv;
529 530
530 if ( communication & Stdout ) 531 if ( communication & Stdout )
531 { 532 {
532 communication = ( Communication ) ( communication & ~Stdout ); 533 communication = ( Communication ) ( communication & ~Stdout );
533 delete outnot; 534 delete outnot;
534 outnot = 0; 535 outnot = 0;
535 close( out[ 0 ] ); 536 close( out[ 0 ] );
536 rv = true; 537 rv = true;
537 } 538 }
538 else 539 else
539 rv = false; 540 rv = false;
540 return rv; 541 return rv;
541} 542}
542 543
543bool OProcess::closeStderr() 544bool OProcess::closeStderr()
544{ 545{
545 bool rv; 546 bool rv;
546 547
547 if ( communication & Stderr ) 548 if ( communication & Stderr )
548 { 549 {
549 communication = static_cast<Communication>( communication & ~Stderr ); 550 communication = static_cast<Communication>( communication & ~Stderr );
550 delete errnot; 551 delete errnot;
551 errnot = 0; 552 errnot = 0;
552 close( err[ 0 ] ); 553 close( err[ 0 ] );
553 rv = true; 554 rv = true;
554 } 555 }
555 else 556 else
556 rv = false; 557 rv = false;
557 return rv; 558 return rv;
558} 559}
559 560
560void OProcess::slotChildOutput( int fdno ) 561void OProcess::slotChildOutput( int fdno )
561{ 562{
562 if ( !childOutput( fdno ) ) 563 if ( !childOutput( fdno ) )
563 closeStdout(); 564 closeStdout();
564} 565}
565 566
566void OProcess::slotChildError( int fdno ) 567void OProcess::slotChildError( int fdno )
567{ 568{
568 if ( !childError( fdno ) ) 569 if ( !childError( fdno ) )
569 closeStderr(); 570 closeStderr();
570} 571}
571 572
572void OProcess::slotSendData( int ) 573void OProcess::slotSendData( int )
573{ 574{
574 if ( input_sent == input_total ) 575 if ( input_sent == input_total )
575 { 576 {
576 innot->setEnabled( false ); 577 innot->setEnabled( false );
577 input_data = 0; 578 input_data = 0;
578 emit wroteStdin( this ); 579 emit wroteStdin( this );
579 } 580 }
580 else 581 else
581 input_sent += ::write( in[ 1 ], input_data + input_sent, input_total - input_sent ); 582 input_sent += ::write( in[ 1 ], input_data + input_sent, input_total - input_sent );
582} 583}
583 584
584void OProcess::processHasExited( int state ) 585void OProcess::processHasExited( int state )
585{ 586{
586 if ( runs ) 587 if ( runs )
587 { 588 {
588 runs = false; 589 runs = false;
589 status = state; 590 status = state;
590 591
591 commClose(); // cleanup communication sockets 592 commClose(); // cleanup communication sockets
592 593
593 // also emit a signal if the process was run Blocking 594 // also emit a signal if the process was run Blocking
594 if ( DontCare != run_mode ) 595 if ( DontCare != run_mode )
595 { 596 {
596 emit processExited( this ); 597 emit processExited( this );
597 } 598 }
598 } 599 }
599} 600}
600 601
601int OProcess::childOutput( int fdno ) 602int OProcess::childOutput( int fdno )
602{ 603{
603 if ( communication & NoRead ) 604 if ( communication & NoRead )
604 { 605 {
605 int len = -1; 606 int len = -1;
606 emit receivedStdout( fdno, len ); 607 emit receivedStdout( fdno, len );
607 errno = 0; // Make sure errno doesn't read "EAGAIN" 608 errno = 0; // Make sure errno doesn't read "EAGAIN"
608 return len; 609 return len;
609 } 610 }
610 else 611 else
611 { 612 {
612 char buffer[ 1024 ]; 613 char buffer[ 1024 ];
613 int len; 614 int len;
614 615
615 len = ::read( fdno, buffer, 1024 ); 616 len = ::read( fdno, buffer, 1024 );
616 617
617 if ( 0 < len ) 618 if ( 0 < len )
618 { 619 {
619 emit receivedStdout( this, buffer, len ); 620 emit receivedStdout( this, buffer, len );
620 } 621 }
621 return len; 622 return len;
622 } 623 }
623} 624}
624 625
625int OProcess::childError( int fdno ) 626int OProcess::childError( int fdno )
626{ 627{
627 char buffer[ 1024 ]; 628 char buffer[ 1024 ];
628 int len; 629 int len;
629 630
630 len = ::read( fdno, buffer, 1024 ); 631 len = ::read( fdno, buffer, 1024 );
631 632
632 if ( 0 < len ) 633 if ( 0 < len )
633 emit receivedStderr( this, buffer, len ); 634 emit receivedStderr( this, buffer, len );
634 return len; 635 return len;
635} 636}
636 637
637int OProcess::setupCommunication( Communication comm ) 638int OProcess::setupCommunication( Communication comm )
638{ 639{
639 int ok; 640 int ok;
640 641
641 communication = comm; 642 communication = comm;
642 643
643 ok = 1; 644 ok = 1;
644 if ( comm & Stdin ) 645 if ( comm & Stdin )
645 ok &= socketpair( AF_UNIX, SOCK_STREAM, 0, in ) >= 0; 646 ok &= socketpair( AF_UNIX, SOCK_STREAM, 0, in ) >= 0;
646 647
647 if ( comm & Stdout ) 648 if ( comm & Stdout )
648 ok &= socketpair( AF_UNIX, SOCK_STREAM, 0, out ) >= 0; 649 ok &= socketpair( AF_UNIX, SOCK_STREAM, 0, out ) >= 0;
649 650
650 if ( comm & Stderr ) 651 if ( comm & Stderr )
651 ok &= socketpair( AF_UNIX, SOCK_STREAM, 0, err ) >= 0; 652 ok &= socketpair( AF_UNIX, SOCK_STREAM, 0, err ) >= 0;
652 653
653 return ok; 654 return ok;
654} 655}
655 656
656int OProcess::commSetupDoneP() 657int OProcess::commSetupDoneP()
657{ 658{
658 int ok = 1; 659 int ok = 1;
659 660
660 if ( communication != NoCommunication ) 661 if ( communication != NoCommunication )
661 { 662 {
662 if ( communication & Stdin ) 663 if ( communication & Stdin )
663 close( in[ 0 ] ); 664 close( in[ 0 ] );
664 if ( communication & Stdout ) 665 if ( communication & Stdout )
665 close( out[ 1 ] ); 666 close( out[ 1 ] );
666 if ( communication & Stderr ) 667 if ( communication & Stderr )
667 close( err[ 1 ] ); 668 close( err[ 1 ] );
668 669
669 // Don't create socket notifiers and set the sockets non-blocking if 670 // Don't create socket notifiers and set the sockets non-blocking if
670 // blocking is requested. 671 // blocking is requested.
671 if ( run_mode == Block ) 672 if ( run_mode == Block )
672 return ok; 673 return ok;
673 674
674 if ( communication & Stdin ) 675 if ( communication & Stdin )
675 { 676 {
676 // ok &= (-1 != fcntl(in[1], F_SETFL, O_NONBLOCK)); 677 // ok &= (-1 != fcntl(in[1], F_SETFL, O_NONBLOCK));
677 innot = new QSocketNotifier( in[ 1 ], QSocketNotifier::Write, this ); 678 innot = new QSocketNotifier( in[ 1 ], QSocketNotifier::Write, this );
678 CHECK_PTR( innot ); 679 CHECK_PTR( innot );
679 innot->setEnabled( false ); // will be enabled when data has to be sent 680 innot->setEnabled( false ); // will be enabled when data has to be sent
680 QObject::connect( innot, SIGNAL( activated(int) ), 681 QObject::connect( innot, SIGNAL( activated(int) ),
681 this, SLOT( slotSendData(int) ) ); 682 this, SLOT( slotSendData(int) ) );
682 } 683 }
683 684
684 if ( communication & Stdout ) 685 if ( communication & Stdout )
685 { 686 {
686 // ok &= (-1 != fcntl(out[0], F_SETFL, O_NONBLOCK)); 687 // ok &= (-1 != fcntl(out[0], F_SETFL, O_NONBLOCK));
687 outnot = new QSocketNotifier( out[ 0 ], QSocketNotifier::Read, this ); 688 outnot = new QSocketNotifier( out[ 0 ], QSocketNotifier::Read, this );
688 CHECK_PTR( outnot ); 689 CHECK_PTR( outnot );
689 QObject::connect( outnot, SIGNAL( activated(int) ), 690 QObject::connect( outnot, SIGNAL( activated(int) ),
690 this, SLOT( slotChildOutput(int) ) ); 691 this, SLOT( slotChildOutput(int) ) );
691 if ( communication & NoRead ) 692 if ( communication & NoRead )
692 suspend(); 693 suspend();
693 } 694 }
694 695
695 if ( communication & Stderr ) 696 if ( communication & Stderr )
696 { 697 {
697 // ok &= (-1 != fcntl(err[0], F_SETFL, O_NONBLOCK)); 698 // ok &= (-1 != fcntl(err[0], F_SETFL, O_NONBLOCK));
698 errnot = new QSocketNotifier( err[ 0 ], QSocketNotifier::Read, this ); 699 errnot = new QSocketNotifier( err[ 0 ], QSocketNotifier::Read, this );
699 CHECK_PTR( errnot ); 700 CHECK_PTR( errnot );
700 QObject::connect( errnot, SIGNAL( activated(int) ), 701 QObject::connect( errnot, SIGNAL( activated(int) ),
701 this, SLOT( slotChildError(int) ) ); 702 this, SLOT( slotChildError(int) ) );
702 } 703 }
703 } 704 }
704 return ok; 705 return ok;
705} 706}
706 707
707int OProcess::commSetupDoneC() 708int OProcess::commSetupDoneC()
708{ 709{
709 int ok = 1; 710 int ok = 1;
710 struct linger so; 711 struct linger so;
711 memset( &so, 0, sizeof( so ) ); 712 memset( &so, 0, sizeof( so ) );
712 713
713 if ( communication & Stdin ) 714 if ( communication & Stdin )
714 close( in[ 1 ] ); 715 close( in[ 1 ] );
715 if ( communication & Stdout ) 716 if ( communication & Stdout )
716 close( out[ 0 ] ); 717 close( out[ 0 ] );
717 if ( communication & Stderr ) 718 if ( communication & Stderr )
718 close( err[ 0 ] ); 719 close( err[ 0 ] );
719 720
720 if ( communication & Stdin ) 721 if ( communication & Stdin )
721 ok &= dup2( in[ 0 ], STDIN_FILENO ) != -1; 722 ok &= dup2( in[ 0 ], STDIN_FILENO ) != -1;
722 else 723 else
723 { 724 {
724 int null_fd = open( "/dev/null", O_RDONLY ); 725 int null_fd = open( "/dev/null", O_RDONLY );
725 ok &= dup2( null_fd, STDIN_FILENO ) != -1; 726 ok &= dup2( null_fd, STDIN_FILENO ) != -1;
726 close( null_fd ); 727 close( null_fd );
727 } 728 }
728 if ( communication & Stdout ) 729 if ( communication & Stdout )
729 { 730 {
730 ok &= dup2( out[ 1 ], STDOUT_FILENO ) != -1; 731 ok &= dup2( out[ 1 ], STDOUT_FILENO ) != -1;
731 ok &= !setsockopt( out[ 1 ], SOL_SOCKET, SO_LINGER, ( char* ) & so, sizeof( so ) ); 732 ok &= !setsockopt( out[ 1 ], SOL_SOCKET, SO_LINGER, ( char* ) & so, sizeof( so ) );
732 } 733 }
733 else 734 else
734 { 735 {
735 int null_fd = open( "/dev/null", O_WRONLY ); 736 int null_fd = open( "/dev/null", O_WRONLY );
736 ok &= dup2( null_fd, STDOUT_FILENO ) != -1; 737 ok &= dup2( null_fd, STDOUT_FILENO ) != -1;
737 close( null_fd ); 738 close( null_fd );
738 } 739 }
739 if ( communication & Stderr ) 740 if ( communication & Stderr )
740 { 741 {
741 ok &= dup2( err[ 1 ], STDERR_FILENO ) != -1; 742 ok &= dup2( err[ 1 ], STDERR_FILENO ) != -1;
742 ok &= !setsockopt( err[ 1 ], SOL_SOCKET, SO_LINGER, reinterpret_cast<char *>( &so ), sizeof( so ) ); 743 ok &= !setsockopt( err[ 1 ], SOL_SOCKET, SO_LINGER, reinterpret_cast<char *>( &so ), sizeof( so ) );
743 } 744 }
744 else 745 else
745 { 746 {
746 int null_fd = open( "/dev/null", O_WRONLY ); 747 int null_fd = open( "/dev/null", O_WRONLY );
747 ok &= dup2( null_fd, STDERR_FILENO ) != -1; 748 ok &= dup2( null_fd, STDERR_FILENO ) != -1;
748 close( null_fd ); 749 close( null_fd );
749 } 750 }
750 return ok; 751 return ok;
751} 752}
752 753
753void OProcess::commClose() 754void OProcess::commClose()
754{ 755{
755 if ( NoCommunication != communication ) 756 if ( NoCommunication != communication )
756 { 757 {
757 bool b_in = ( communication & Stdin ); 758 bool b_in = ( communication & Stdin );
758 bool b_out = ( communication & Stdout ); 759 bool b_out = ( communication & Stdout );
759 bool b_err = ( communication & Stderr ); 760 bool b_err = ( communication & Stderr );
760 if ( b_in ) 761 if ( b_in )
761 delete innot; 762 delete innot;
762 763
763 if ( b_out || b_err ) 764 if ( b_out || b_err )
764 { 765 {
765 // If both channels are being read we need to make sure that one socket buffer 766 // If both channels are being read we need to make sure that one socket buffer
766 // doesn't fill up whilst we are waiting for data on the other (causing a deadlock). 767 // doesn't fill up whilst we are waiting for data on the other (causing a deadlock).
767 // Hence we need to use select. 768 // Hence we need to use select.
768 769
769 // Once one or other of the channels has reached EOF (or given an error) go back 770 // Once one or other of the channels has reached EOF (or given an error) go back
770 // to the usual mechanism. 771 // to the usual mechanism.
771 772
772 int fds_ready = 1; 773 int fds_ready = 1;
773 fd_set rfds; 774 fd_set rfds;
774 775
775 int max_fd = 0; 776 int max_fd = 0;
776 if ( b_out ) 777 if ( b_out )
777 { 778 {
778 fcntl( out[ 0 ], F_SETFL, O_NONBLOCK ); 779 fcntl( out[ 0 ], F_SETFL, O_NONBLOCK );
779 if ( out[ 0 ] > max_fd ) 780 if ( out[ 0 ] > max_fd )
780 max_fd = out[ 0 ]; 781 max_fd = out[ 0 ];
781 delete outnot; 782 delete outnot;
782 outnot = 0; 783 outnot = 0;
783 } 784 }
784 if ( b_err ) 785 if ( b_err )
785 { 786 {
786 fcntl( err[ 0 ], F_SETFL, O_NONBLOCK ); 787 fcntl( err[ 0 ], F_SETFL, O_NONBLOCK );
787 if ( err[ 0 ] > max_fd ) 788 if ( err[ 0 ] > max_fd )
788 max_fd = err[ 0 ]; 789 max_fd = err[ 0 ];
789 delete errnot; 790 delete errnot;
790 errnot = 0; 791 errnot = 0;
791 } 792 }
792 793
793 794
794 while ( b_out || b_err ) 795 while ( b_out || b_err )
795 { 796 {
796 // * If the process is still running we block until we 797 // * If the process is still running we block until we
797 // receive data. (p_timeout = 0, no timeout) 798 // receive data. (p_timeout = 0, no timeout)
798 // * If the process has already exited, we only check 799 // * If the process has already exited, we only check
799 // the available data, we don't wait for more. 800 // the available data, we don't wait for more.
800 // (p_timeout = &timeout, timeout immediately) 801 // (p_timeout = &timeout, timeout immediately)
801 struct timeval timeout; 802 struct timeval timeout;
802 timeout.tv_sec = 0; 803 timeout.tv_sec = 0;
803 timeout.tv_usec = 0; 804 timeout.tv_usec = 0;
804 struct timeval *p_timeout = runs ? 0 : &timeout; 805 struct timeval *p_timeout = runs ? 0 : &timeout;
805 806
806 FD_ZERO( &rfds ); 807 FD_ZERO( &rfds );
807 if ( b_out ) 808 if ( b_out )
808 FD_SET( out[ 0 ], &rfds ); 809 FD_SET( out[ 0 ], &rfds );