summaryrefslogtreecommitdiff
authormickeyl <mickeyl>2004-01-13 19:51:42 (UTC)
committer mickeyl <mickeyl>2004-01-13 19:51:42 (UTC)
commite117e8427cd8bcd0ab1a74abdc5cd4ab12654194 (patch) (unidiff)
treef013f4f92cceefd20fb519f7e9a4d23f00fadac5
parent81b48fa5be4806e3afa64a0d1fa254fbdf9b7315 (diff)
downloadopie-e117e8427cd8bcd0ab1a74abdc5cd4ab12654194.zip
opie-e117e8427cd8bcd0ab1a74abdc5cd4ab12654194.tar.gz
opie-e117e8427cd8bcd0ab1a74abdc5cd4ab12654194.tar.bz2
- add the static method int OProcess::processPID(const QString&)
- add an example program for dealing with OProcess. This should be enhanced...
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,298 +1,300 @@
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 ];
@@ -660,256 +662,284 @@ int OProcess::commSetupDoneP()
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
@@ -208,512 +208,517 @@ public:
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: