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