-rw-r--r-- | microkde/oprocess.cpp | 1 |
1 files changed, 1 insertions, 0 deletions
diff --git a/microkde/oprocess.cpp b/microkde/oprocess.cpp index 95e3e4b..a935792 100644 --- a/microkde/oprocess.cpp +++ b/microkde/oprocess.cpp | |||
@@ -1,552 +1,553 @@ | |||
1 | /* | 1 | /* |
2 | This file is part of the Opie Project | 2 | This file is part of the Opie Project |
3 | Copyright (C) 2002-2004 Holger Freyther <zecke@handhelds.org> | 3 | Copyright (C) 2002-2004 Holger Freyther <zecke@handhelds.org> |
4 | and The Opie Team <opie-devel@handhelds.org> | 4 | and The Opie Team <opie-devel@handhelds.org> |
5 | =. Based on KProcess (C) 1997 Christian Czezatke (e9025461@student.tuwien.ac.at) | 5 | =. Based on KProcess (C) 1997 Christian Czezatke (e9025461@student.tuwien.ac.at) |
6 | .=l. | 6 | .=l. |
7 | .>+-= | 7 | .>+-= |
8 | _;:, .> :=|. This program is free software; you can | 8 | _;:, .> :=|. This program is free software; you can |
9 | .> <`_, > . <= redistribute it and/or modify it under | 9 | .> <`_, > . <= redistribute it and/or modify it under |
10 | :`=1 )Y*s>-.-- : the terms of the GNU Library General Public | 10 | :`=1 )Y*s>-.-- : the terms of the GNU Library General Public |
11 | .="- .-=="i, .._ License as published by the Free Software | 11 | .="- .-=="i, .._ License as published by the Free Software |
12 | - . .-<_> .<> Foundation; either version 2 of the License, | 12 | - . .-<_> .<> Foundation; either version 2 of the License, |
13 | ._= =} : or (at your option) any later version. | 13 | ._= =} : or (at your option) any later version. |
14 | .%`+i> _;_. | 14 | .%`+i> _;_. |
15 | .i_,=:_. -<s. This program is distributed in the hope that | 15 | .i_,=:_. -<s. This program is distributed in the hope that |
16 | + . -:. = it will be useful, but WITHOUT ANY WARRANTY; | 16 | + . -:. = it will be useful, but WITHOUT ANY WARRANTY; |
17 | : .. .:, . . . without even the implied warranty of | 17 | : .. .:, . . . without even the implied warranty of |
18 | =_ + =;=|` MERCHANTABILITY or FITNESS FOR A | 18 | =_ + =;=|` MERCHANTABILITY or FITNESS FOR A |
19 | _.=:. : :=>`: PARTICULAR PURPOSE. See the GNU | 19 | _.=:. : :=>`: PARTICULAR PURPOSE. See the GNU |
20 | ..}^=.= = ; Library General Public License for more | 20 | ..}^=.= = ; Library General Public License for more |
21 | ++= -. .` .: details. | 21 | ++= -. .` .: details. |
22 | : = ...= . :.=- | 22 | : = ...= . :.=- |
23 | -. .:....=;==+<; You should have received a copy of the GNU | 23 | -. .:....=;==+<; You should have received a copy of the GNU |
24 | -_. . . )=. = Library General Public License along with | 24 | -_. . . )=. = Library General Public License along with |
25 | -- :-=` this library; see the file COPYING.LIB. | 25 | -- :-=` this library; see the file COPYING.LIB. |
26 | If not, write to the Free Software Foundation, | 26 | If not, write to the Free Software Foundation, |
27 | Inc., 59 Temple Place - Suite 330, | 27 | Inc., 59 Temple Place - Suite 330, |
28 | Boston, MA 02111-1307, USA. | 28 | Boston, MA 02111-1307, USA. |
29 | */ | 29 | */ |
30 | 30 | ||
31 | #include "oprocctrl.h" | 31 | #include "oprocctrl.h" |
32 | 32 | ||
33 | /* OPIE */ | 33 | /* OPIE */ |
34 | #include <oprocess.h> | 34 | #include <oprocess.h> |
35 | 35 | ||
36 | /* QT */ | 36 | /* QT */ |
37 | 37 | ||
38 | #include <qapplication.h> | 38 | #include <qapplication.h> |
39 | #include <qdir.h> | 39 | #include <qdir.h> |
40 | #include <qmap.h> | 40 | #include <qmap.h> |
41 | #include <qregexp.h> | ||
41 | #include <qsocketnotifier.h> | 42 | #include <qsocketnotifier.h> |
42 | #include <qtextstream.h> | 43 | #include <qtextstream.h> |
43 | 44 | ||
44 | /* STD */ | 45 | /* STD */ |
45 | #include <errno.h> | 46 | #include <errno.h> |
46 | #include <fcntl.h> | 47 | #include <fcntl.h> |
47 | #include <pwd.h> | 48 | #include <pwd.h> |
48 | #include <stdlib.h> | 49 | #include <stdlib.h> |
49 | #include <signal.h> | 50 | #include <signal.h> |
50 | #include <stdio.h> | 51 | #include <stdio.h> |
51 | #include <string.h> | 52 | #include <string.h> |
52 | #include <sys/time.h> | 53 | #include <sys/time.h> |
53 | #include <sys/types.h> | 54 | #include <sys/types.h> |
54 | #include <sys/stat.h> | 55 | #include <sys/stat.h> |
55 | #include <sys/socket.h> | 56 | #include <sys/socket.h> |
56 | #include <unistd.h> | 57 | #include <unistd.h> |
57 | #ifdef HAVE_SYS_SELECT_H | 58 | #ifdef HAVE_SYS_SELECT_H |
58 | #include <sys/select.h> | 59 | #include <sys/select.h> |
59 | #endif | 60 | #endif |
60 | #ifdef HAVE_INITGROUPS | 61 | #ifdef HAVE_INITGROUPS |
61 | #include <grp.h> | 62 | #include <grp.h> |
62 | #endif | 63 | #endif |
63 | 64 | ||
64 | using namespace Opie::Core::Internal; | 65 | using namespace Opie::Core::Internal; |
65 | 66 | ||
66 | namespace Opie { | 67 | namespace Opie { |
67 | namespace Core { | 68 | namespace Core { |
68 | namespace Internal { | 69 | namespace Internal { |
69 | class OProcessPrivate | 70 | class OProcessPrivate |
70 | { | 71 | { |
71 | public: | 72 | public: |
72 | OProcessPrivate() : useShell( false ) | 73 | OProcessPrivate() : useShell( false ) |
73 | { } | 74 | { } |
74 | 75 | ||
75 | bool useShell; | 76 | bool useShell; |
76 | QMap<QString, QString> env; | 77 | QMap<QString, QString> env; |
77 | QString wd; | 78 | QString wd; |
78 | QCString shell; | 79 | QCString shell; |
79 | }; | 80 | }; |
80 | } | 81 | } |
81 | 82 | ||
82 | OProcess::OProcess( QObject *parent, const char *name ) | 83 | OProcess::OProcess( QObject *parent, const char *name ) |
83 | : QObject( parent, name ) | 84 | : QObject( parent, name ) |
84 | { | 85 | { |
85 | init ( ); | 86 | init ( ); |
86 | } | 87 | } |
87 | 88 | ||
88 | OProcess::OProcess( const QString &arg0, QObject *parent, const char *name ) | 89 | OProcess::OProcess( const QString &arg0, QObject *parent, const char *name ) |
89 | : QObject( parent, name ) | 90 | : QObject( parent, name ) |
90 | { | 91 | { |
91 | init ( ); | 92 | init ( ); |
92 | *this << arg0; | 93 | *this << arg0; |
93 | } | 94 | } |
94 | 95 | ||
95 | OProcess::OProcess( const QStringList &args, QObject *parent, const char *name ) | 96 | OProcess::OProcess( const QStringList &args, QObject *parent, const char *name ) |
96 | : QObject( parent, name ) | 97 | : QObject( parent, name ) |
97 | { | 98 | { |
98 | init ( ); | 99 | init ( ); |
99 | *this << args; | 100 | *this << args; |
100 | } | 101 | } |
101 | 102 | ||
102 | void OProcess::init ( ) | 103 | void OProcess::init ( ) |
103 | { | 104 | { |
104 | run_mode = NotifyOnExit; | 105 | run_mode = NotifyOnExit; |
105 | runs = false; | 106 | runs = false; |
106 | pid_ = 0; | 107 | pid_ = 0; |
107 | status = 0; | 108 | status = 0; |
108 | keepPrivs = false; | 109 | keepPrivs = false; |
109 | innot = 0; | 110 | innot = 0; |
110 | outnot = 0; | 111 | outnot = 0; |
111 | errnot = 0; | 112 | errnot = 0; |
112 | communication = NoCommunication; | 113 | communication = NoCommunication; |
113 | input_data = 0; | 114 | input_data = 0; |
114 | input_sent = 0; | 115 | input_sent = 0; |
115 | input_total = 0; | 116 | input_total = 0; |
116 | d = 0; | 117 | d = 0; |
117 | 118 | ||
118 | if ( 0 == OProcessController::theOProcessController ) | 119 | if ( 0 == OProcessController::theOProcessController ) |
119 | { | 120 | { |
120 | ( void ) new OProcessController(); | 121 | ( void ) new OProcessController(); |
121 | CHECK_PTR( OProcessController::theOProcessController ); | 122 | CHECK_PTR( OProcessController::theOProcessController ); |
122 | } | 123 | } |
123 | 124 | ||
124 | OProcessController::theOProcessController->addOProcess( this ); | 125 | OProcessController::theOProcessController->addOProcess( this ); |
125 | out[ 0 ] = out[ 1 ] = -1; | 126 | out[ 0 ] = out[ 1 ] = -1; |
126 | in[ 0 ] = in[ 1 ] = -1; | 127 | in[ 0 ] = in[ 1 ] = -1; |
127 | err[ 0 ] = err[ 1 ] = -1; | 128 | err[ 0 ] = err[ 1 ] = -1; |
128 | } | 129 | } |
129 | 130 | ||
130 | void OProcess::setEnvironment( const QString &name, const QString &value ) | 131 | void OProcess::setEnvironment( const QString &name, const QString &value ) |
131 | { | 132 | { |
132 | if ( !d ) | 133 | if ( !d ) |
133 | d = new OProcessPrivate; | 134 | d = new OProcessPrivate; |
134 | d->env.insert( name, value ); | 135 | d->env.insert( name, value ); |
135 | } | 136 | } |
136 | 137 | ||
137 | void OProcess::setWorkingDirectory( const QString &dir ) | 138 | void OProcess::setWorkingDirectory( const QString &dir ) |
138 | { | 139 | { |
139 | if ( !d ) | 140 | if ( !d ) |
140 | d = new OProcessPrivate; | 141 | d = new OProcessPrivate; |
141 | d->wd = dir; | 142 | d->wd = dir; |
142 | } | 143 | } |
143 | 144 | ||
144 | void OProcess::setupEnvironment() | 145 | void OProcess::setupEnvironment() |
145 | { | 146 | { |
146 | if ( d ) | 147 | if ( d ) |
147 | { | 148 | { |
148 | QMap<QString, QString>::Iterator it; | 149 | QMap<QString, QString>::Iterator it; |
149 | for ( it = d->env.begin(); it != d->env.end(); ++it ) | 150 | for ( it = d->env.begin(); it != d->env.end(); ++it ) |
150 | setenv( QFile::encodeName( it.key() ).data(), | 151 | setenv( QFile::encodeName( it.key() ).data(), |
151 | QFile::encodeName( it.data() ).data(), 1 ); | 152 | QFile::encodeName( it.data() ).data(), 1 ); |
152 | if ( !d->wd.isEmpty() ) | 153 | if ( !d->wd.isEmpty() ) |
153 | chdir( QFile::encodeName( d->wd ).data() ); | 154 | chdir( QFile::encodeName( d->wd ).data() ); |
154 | } | 155 | } |
155 | } | 156 | } |
156 | 157 | ||
157 | void OProcess::setRunPrivileged( bool keepPrivileges ) | 158 | void OProcess::setRunPrivileged( bool keepPrivileges ) |
158 | { | 159 | { |
159 | keepPrivs = keepPrivileges; | 160 | keepPrivs = keepPrivileges; |
160 | } | 161 | } |
161 | 162 | ||
162 | bool OProcess::runPrivileged() const | 163 | bool OProcess::runPrivileged() const |
163 | { | 164 | { |
164 | return keepPrivs; | 165 | return keepPrivs; |
165 | } | 166 | } |
166 | 167 | ||
167 | OProcess::~OProcess() | 168 | OProcess::~OProcess() |
168 | { | 169 | { |
169 | // destroying the OProcess instance sends a SIGKILL to the | 170 | // destroying the OProcess instance sends a SIGKILL to the |
170 | // child process (if it is running) after removing it from the | 171 | // child process (if it is running) after removing it from the |
171 | // list of valid processes (if the process is not started as | 172 | // list of valid processes (if the process is not started as |
172 | // "DontCare") | 173 | // "DontCare") |
173 | 174 | ||
174 | OProcessController::theOProcessController->removeOProcess( this ); | 175 | OProcessController::theOProcessController->removeOProcess( this ); |
175 | // this must happen before we kill the child | 176 | // this must happen before we kill the child |
176 | // TODO: block the signal while removing the current process from the process list | 177 | // TODO: block the signal while removing the current process from the process list |
177 | 178 | ||
178 | if ( runs && ( run_mode != DontCare ) ) | 179 | if ( runs && ( run_mode != DontCare ) ) |
179 | kill( SIGKILL ); | 180 | kill( SIGKILL ); |
180 | 181 | ||
181 | // Clean up open fd's and socket notifiers. | 182 | // Clean up open fd's and socket notifiers. |
182 | closeStdin(); | 183 | closeStdin(); |
183 | closeStdout(); | 184 | closeStdout(); |
184 | closeStderr(); | 185 | closeStderr(); |
185 | 186 | ||
186 | // TODO: restore SIGCHLD and SIGPIPE handler if this is the last OProcess | 187 | // TODO: restore SIGCHLD and SIGPIPE handler if this is the last OProcess |
187 | delete d; | 188 | delete d; |
188 | } | 189 | } |
189 | 190 | ||
190 | void OProcess::detach() | 191 | void OProcess::detach() |
191 | { | 192 | { |
192 | OProcessController::theOProcessController->removeOProcess( this ); | 193 | OProcessController::theOProcessController->removeOProcess( this ); |
193 | 194 | ||
194 | runs = false; | 195 | runs = false; |
195 | pid_ = 0; | 196 | pid_ = 0; |
196 | 197 | ||
197 | // Clean up open fd's and socket notifiers. | 198 | // Clean up open fd's and socket notifiers. |
198 | closeStdin(); | 199 | closeStdin(); |
199 | closeStdout(); | 200 | closeStdout(); |
200 | closeStderr(); | 201 | closeStderr(); |
201 | } | 202 | } |
202 | 203 | ||
203 | bool OProcess::setExecutable( const QString& proc ) | 204 | bool OProcess::setExecutable( const QString& proc ) |
204 | { | 205 | { |
205 | if ( runs ) | 206 | if ( runs ) |
206 | return false; | 207 | return false; |
207 | 208 | ||
208 | if ( proc.isEmpty() ) | 209 | if ( proc.isEmpty() ) |
209 | return false; | 210 | return false; |
210 | 211 | ||
211 | if ( !arguments.isEmpty() ) | 212 | if ( !arguments.isEmpty() ) |
212 | arguments.remove( arguments.begin() ); | 213 | arguments.remove( arguments.begin() ); |
213 | arguments.prepend( QFile::encodeName( proc ) ); | 214 | arguments.prepend( QFile::encodeName( proc ) ); |
214 | 215 | ||
215 | return true; | 216 | return true; |
216 | } | 217 | } |
217 | 218 | ||
218 | OProcess &OProcess::operator<<( const QStringList& args ) | 219 | OProcess &OProcess::operator<<( const QStringList& args ) |
219 | { | 220 | { |
220 | QStringList::ConstIterator it = args.begin(); | 221 | QStringList::ConstIterator it = args.begin(); |
221 | for ( ; it != args.end() ; ++it ) | 222 | for ( ; it != args.end() ; ++it ) |
222 | arguments.append( QFile::encodeName( *it ) ); | 223 | arguments.append( QFile::encodeName( *it ) ); |
223 | return *this; | 224 | return *this; |
224 | } | 225 | } |
225 | 226 | ||
226 | OProcess &OProcess::operator<<( const QCString& arg ) | 227 | OProcess &OProcess::operator<<( const QCString& arg ) |
227 | { | 228 | { |
228 | return operator<< ( arg.data() ); | 229 | return operator<< ( arg.data() ); |
229 | } | 230 | } |
230 | 231 | ||
231 | OProcess &OProcess::operator<<( const char* arg ) | 232 | OProcess &OProcess::operator<<( const char* arg ) |
232 | { | 233 | { |
233 | arguments.append( arg ); | 234 | arguments.append( arg ); |
234 | return *this; | 235 | return *this; |
235 | } | 236 | } |
236 | 237 | ||
237 | OProcess &OProcess::operator<<( const QString& arg ) | 238 | OProcess &OProcess::operator<<( const QString& arg ) |
238 | { | 239 | { |
239 | arguments.append( QFile::encodeName( arg ) ); | 240 | arguments.append( QFile::encodeName( arg ) ); |
240 | return *this; | 241 | return *this; |
241 | } | 242 | } |
242 | 243 | ||
243 | void OProcess::clearArguments() | 244 | void OProcess::clearArguments() |
244 | { | 245 | { |
245 | arguments.clear(); | 246 | arguments.clear(); |
246 | } | 247 | } |
247 | 248 | ||
248 | bool OProcess::start( RunMode runmode, Communication comm ) | 249 | bool OProcess::start( RunMode runmode, Communication comm ) |
249 | { | 250 | { |
250 | uint i; | 251 | uint i; |
251 | uint n = arguments.count(); | 252 | uint n = arguments.count(); |
252 | char **arglist; | 253 | char **arglist; |
253 | 254 | ||
254 | if ( runs || ( 0 == n ) ) | 255 | if ( runs || ( 0 == n ) ) |
255 | { | 256 | { |
256 | return false; // cannot start a process that is already running | 257 | return false; // cannot start a process that is already running |
257 | // or if no executable has been assigned | 258 | // or if no executable has been assigned |
258 | } | 259 | } |
259 | run_mode = runmode; | 260 | run_mode = runmode; |
260 | status = 0; | 261 | status = 0; |
261 | 262 | ||
262 | QCString shellCmd; | 263 | QCString shellCmd; |
263 | if ( d && d->useShell ) | 264 | if ( d && d->useShell ) |
264 | { | 265 | { |
265 | if ( d->shell.isEmpty() ) | 266 | if ( d->shell.isEmpty() ) |
266 | { | 267 | { |
267 | qWarning( "Could not find a valid shell" ); | 268 | qWarning( "Could not find a valid shell" ); |
268 | return false; | 269 | return false; |
269 | } | 270 | } |
270 | 271 | ||
271 | arglist = static_cast<char **>( malloc( ( 4 ) * sizeof( char * ) ) ); | 272 | arglist = static_cast<char **>( malloc( ( 4 ) * sizeof( char * ) ) ); |
272 | for ( i = 0; i < n; i++ ) | 273 | for ( i = 0; i < n; i++ ) |
273 | { | 274 | { |
274 | shellCmd += arguments[ i ]; | 275 | shellCmd += arguments[ i ]; |
275 | shellCmd += " "; // CC: to separate the arguments | 276 | shellCmd += " "; // CC: to separate the arguments |
276 | } | 277 | } |
277 | 278 | ||
278 | arglist[ 0 ] = d->shell.data(); | 279 | arglist[ 0 ] = d->shell.data(); |
279 | arglist[ 1 ] = ( char * ) "-c"; | 280 | arglist[ 1 ] = ( char * ) "-c"; |
280 | arglist[ 2 ] = shellCmd.data(); | 281 | arglist[ 2 ] = shellCmd.data(); |
281 | arglist[ 3 ] = 0; | 282 | arglist[ 3 ] = 0; |
282 | } | 283 | } |
283 | else | 284 | else |
284 | { | 285 | { |
285 | arglist = static_cast<char **>( malloc( ( n + 1 ) * sizeof( char * ) ) ); | 286 | arglist = static_cast<char **>( malloc( ( n + 1 ) * sizeof( char * ) ) ); |
286 | for ( i = 0; i < n; i++ ) | 287 | for ( i = 0; i < n; i++ ) |
287 | arglist[ i ] = arguments[ i ].data(); | 288 | arglist[ i ] = arguments[ i ].data(); |
288 | arglist[ n ] = 0; | 289 | arglist[ n ] = 0; |
289 | } | 290 | } |
290 | 291 | ||
291 | if ( !setupCommunication( comm ) ) | 292 | if ( !setupCommunication( comm ) ) |
292 | qWarning( "Could not setup Communication!" ); | 293 | qWarning( "Could not setup Communication!" ); |
293 | 294 | ||
294 | // We do this in the parent because if we do it in the child process | 295 | // We do this in the parent because if we do it in the child process |
295 | // gdb gets confused when the application runs from gdb. | 296 | // gdb gets confused when the application runs from gdb. |
296 | uid_t uid = getuid(); | 297 | uid_t uid = getuid(); |
297 | gid_t gid = getgid(); | 298 | gid_t gid = getgid(); |
298 | #ifdef HAVE_INITGROUPS | 299 | #ifdef HAVE_INITGROUPS |
299 | 300 | ||
300 | struct passwd *pw = getpwuid( uid ); | 301 | struct passwd *pw = getpwuid( uid ); |
301 | #endif | 302 | #endif |
302 | 303 | ||
303 | int fd[ 2 ]; | 304 | int fd[ 2 ]; |
304 | if ( 0 > pipe( fd ) ) | 305 | if ( 0 > pipe( fd ) ) |
305 | { | 306 | { |
306 | fd[ 0 ] = fd[ 1 ] = 0; // Pipe failed.. continue | 307 | fd[ 0 ] = fd[ 1 ] = 0; // Pipe failed.. continue |
307 | } | 308 | } |
308 | 309 | ||
309 | runs = true; | 310 | runs = true; |
310 | 311 | ||
311 | QApplication::flushX(); | 312 | QApplication::flushX(); |
312 | 313 | ||
313 | // WABA: Note that we use fork() and not vfork() because | 314 | // WABA: Note that we use fork() and not vfork() because |
314 | // vfork() has unclear semantics and is not standardized. | 315 | // vfork() has unclear semantics and is not standardized. |
315 | pid_ = fork(); | 316 | pid_ = fork(); |
316 | 317 | ||
317 | if ( 0 == pid_ ) | 318 | if ( 0 == pid_ ) |
318 | { | 319 | { |
319 | if ( fd[ 0 ] ) | 320 | if ( fd[ 0 ] ) |
320 | close( fd[ 0 ] ); | 321 | close( fd[ 0 ] ); |
321 | if ( !runPrivileged() ) | 322 | if ( !runPrivileged() ) |
322 | { | 323 | { |
323 | setgid( gid ); | 324 | setgid( gid ); |
324 | #if defined( HAVE_INITGROUPS) | 325 | #if defined( HAVE_INITGROUPS) |
325 | 326 | ||
326 | if ( pw ) | 327 | if ( pw ) |
327 | initgroups( pw->pw_name, pw->pw_gid ); | 328 | initgroups( pw->pw_name, pw->pw_gid ); |
328 | #endif | 329 | #endif |
329 | 330 | ||
330 | setuid( uid ); | 331 | setuid( uid ); |
331 | } | 332 | } |
332 | // The child process | 333 | // The child process |
333 | if ( !commSetupDoneC() ) | 334 | if ( !commSetupDoneC() ) |
334 | qWarning( "Could not finish comm setup in child!" ); | 335 | qWarning( "Could not finish comm setup in child!" ); |
335 | 336 | ||
336 | setupEnvironment(); | 337 | setupEnvironment(); |
337 | 338 | ||
338 | // Matthias | 339 | // Matthias |
339 | if ( run_mode == DontCare ) | 340 | if ( run_mode == DontCare ) |
340 | setpgid( 0, 0 ); | 341 | setpgid( 0, 0 ); |
341 | // restore default SIGPIPE handler (Harri) | 342 | // restore default SIGPIPE handler (Harri) |
342 | struct sigaction act; | 343 | struct sigaction act; |
343 | sigemptyset( &( act.sa_mask ) ); | 344 | sigemptyset( &( act.sa_mask ) ); |
344 | sigaddset( &( act.sa_mask ), SIGPIPE ); | 345 | sigaddset( &( act.sa_mask ), SIGPIPE ); |
345 | act.sa_handler = SIG_DFL; | 346 | act.sa_handler = SIG_DFL; |
346 | act.sa_flags = 0; | 347 | act.sa_flags = 0; |
347 | sigaction( SIGPIPE, &act, 0L ); | 348 | sigaction( SIGPIPE, &act, 0L ); |
348 | 349 | ||
349 | // We set the close on exec flag. | 350 | // We set the close on exec flag. |
350 | // Closing of fd[1] indicates that the execvp succeeded! | 351 | // Closing of fd[1] indicates that the execvp succeeded! |
351 | if ( fd[ 1 ] ) | 352 | if ( fd[ 1 ] ) |
352 | fcntl( fd[ 1 ], F_SETFD, FD_CLOEXEC ); | 353 | fcntl( fd[ 1 ], F_SETFD, FD_CLOEXEC ); |
353 | execvp( arglist[ 0 ], arglist ); | 354 | execvp( arglist[ 0 ], arglist ); |
354 | char resultByte = 1; | 355 | char resultByte = 1; |
355 | if ( fd[ 1 ] ) | 356 | if ( fd[ 1 ] ) |
356 | write( fd[ 1 ], &resultByte, 1 ); | 357 | write( fd[ 1 ], &resultByte, 1 ); |
357 | _exit( -1 ); | 358 | _exit( -1 ); |
358 | } | 359 | } |
359 | else if ( -1 == pid_ ) | 360 | else if ( -1 == pid_ ) |
360 | { | 361 | { |
361 | // forking failed | 362 | // forking failed |
362 | 363 | ||
363 | runs = false; | 364 | runs = false; |
364 | free( arglist ); | 365 | free( arglist ); |
365 | return false; | 366 | return false; |
366 | } | 367 | } |
367 | else | 368 | else |
368 | { | 369 | { |
369 | if ( fd[ 1 ] ) | 370 | if ( fd[ 1 ] ) |
370 | close( fd[ 1 ] ); | 371 | close( fd[ 1 ] ); |
371 | // the parent continues here | 372 | // the parent continues here |
372 | 373 | ||
373 | // Discard any data for stdin that might still be there | 374 | // Discard any data for stdin that might still be there |
374 | input_data = 0; | 375 | input_data = 0; |
375 | 376 | ||
376 | // Check whether client could be started. | 377 | // Check whether client could be started. |
377 | if ( fd[ 0 ] ) | 378 | if ( fd[ 0 ] ) |
378 | for ( ;; ) | 379 | for ( ;; ) |
379 | { | 380 | { |
380 | char resultByte; | 381 | char resultByte; |
381 | int n = ::read( fd[ 0 ], &resultByte, 1 ); | 382 | int n = ::read( fd[ 0 ], &resultByte, 1 ); |
382 | if ( n == 1 ) | 383 | if ( n == 1 ) |
383 | { | 384 | { |
384 | // Error | 385 | // Error |
385 | runs = false; | 386 | runs = false; |
386 | close( fd[ 0 ] ); | 387 | close( fd[ 0 ] ); |
387 | free( arglist ); | 388 | free( arglist ); |
388 | pid_ = 0; | 389 | pid_ = 0; |
389 | return false; | 390 | return false; |
390 | } | 391 | } |
391 | if ( n == -1 ) | 392 | if ( n == -1 ) |
392 | { | 393 | { |
393 | if ( ( errno == ECHILD ) || ( errno == EINTR ) ) | 394 | if ( ( errno == ECHILD ) || ( errno == EINTR ) ) |
394 | continue; // Ignore | 395 | continue; // Ignore |
395 | } | 396 | } |
396 | break; // success | 397 | break; // success |
397 | } | 398 | } |
398 | if ( fd[ 0 ] ) | 399 | if ( fd[ 0 ] ) |
399 | close( fd[ 0 ] ); | 400 | close( fd[ 0 ] ); |
400 | 401 | ||
401 | if ( !commSetupDoneP() ) // finish communication socket setup for the parent | 402 | if ( !commSetupDoneP() ) // finish communication socket setup for the parent |
402 | qWarning( "Could not finish comm setup in parent!" ); | 403 | qWarning( "Could not finish comm setup in parent!" ); |
403 | 404 | ||
404 | if ( run_mode == Block ) | 405 | if ( run_mode == Block ) |
405 | { | 406 | { |
406 | commClose(); | 407 | commClose(); |
407 | 408 | ||
408 | // The SIGCHLD handler of the process controller will catch | 409 | // The SIGCHLD handler of the process controller will catch |
409 | // the exit and set the status | 410 | // the exit and set the status |
410 | while ( runs ) | 411 | while ( runs ) |
411 | { | 412 | { |
412 | OProcessController::theOProcessController-> | 413 | OProcessController::theOProcessController-> |
413 | slotDoHousekeeping( 0 ); | 414 | slotDoHousekeeping( 0 ); |
414 | } | 415 | } |
415 | runs = FALSE; | 416 | runs = FALSE; |
416 | emit processExited( this ); | 417 | emit processExited( this ); |
417 | } | 418 | } |
418 | } | 419 | } |
419 | free( arglist ); | 420 | free( arglist ); |
420 | return true; | 421 | return true; |
421 | } | 422 | } |
422 | 423 | ||
423 | 424 | ||
424 | 425 | ||
425 | bool OProcess::kill( int signo ) | 426 | bool OProcess::kill( int signo ) |
426 | { | 427 | { |
427 | bool rv = false; | 428 | bool rv = false; |
428 | 429 | ||
429 | if ( 0 != pid_ ) | 430 | if ( 0 != pid_ ) |
430 | rv = ( -1 != ::kill( pid_, signo ) ); | 431 | rv = ( -1 != ::kill( pid_, signo ) ); |
431 | // probably store errno somewhere... | 432 | // probably store errno somewhere... |
432 | return rv; | 433 | return rv; |
433 | } | 434 | } |
434 | 435 | ||
435 | bool OProcess::isRunning() const | 436 | bool OProcess::isRunning() const |
436 | { | 437 | { |
437 | return runs; | 438 | return runs; |
438 | } | 439 | } |
439 | 440 | ||
440 | pid_t OProcess::pid() const | 441 | pid_t OProcess::pid() const |
441 | { | 442 | { |
442 | return pid_; | 443 | return pid_; |
443 | } | 444 | } |
444 | 445 | ||
445 | bool OProcess::normalExit() const | 446 | bool OProcess::normalExit() const |
446 | { | 447 | { |
447 | int _status = status; | 448 | int _status = status; |
448 | return ( pid_ != 0 ) && ( !runs ) && ( WIFEXITED( ( _status ) ) ); | 449 | return ( pid_ != 0 ) && ( !runs ) && ( WIFEXITED( ( _status ) ) ); |
449 | } | 450 | } |
450 | 451 | ||
451 | int OProcess::exitStatus() const | 452 | int OProcess::exitStatus() const |
452 | { | 453 | { |
453 | int _status = status; | 454 | int _status = status; |
454 | return WEXITSTATUS( ( _status ) ); | 455 | return WEXITSTATUS( ( _status ) ); |
455 | } | 456 | } |
456 | 457 | ||
457 | bool OProcess::writeStdin( const char *buffer, int buflen ) | 458 | bool OProcess::writeStdin( const char *buffer, int buflen ) |
458 | { | 459 | { |
459 | bool rv; | 460 | bool rv; |
460 | 461 | ||
461 | // if there is still data pending, writing new data | 462 | // if there is still data pending, writing new data |
462 | // to stdout is not allowed (since it could also confuse | 463 | // to stdout is not allowed (since it could also confuse |
463 | // kprocess... | 464 | // kprocess... |
464 | if ( 0 != input_data ) | 465 | if ( 0 != input_data ) |
465 | return false; | 466 | return false; |
466 | 467 | ||
467 | if ( runs && ( communication & Stdin ) ) | 468 | if ( runs && ( communication & Stdin ) ) |
468 | { | 469 | { |
469 | input_data = buffer; | 470 | input_data = buffer; |
470 | input_sent = 0; | 471 | input_sent = 0; |
471 | input_total = buflen; | 472 | input_total = buflen; |
472 | slotSendData( 0 ); | 473 | slotSendData( 0 ); |
473 | innot->setEnabled( true ); | 474 | innot->setEnabled( true ); |
474 | rv = true; | 475 | rv = true; |
475 | } | 476 | } |
476 | else | 477 | else |
477 | rv = false; | 478 | rv = false; |
478 | return rv; | 479 | return rv; |
479 | } | 480 | } |
480 | 481 | ||
481 | void OProcess::flushStdin ( ) | 482 | void OProcess::flushStdin ( ) |
482 | { | 483 | { |
483 | if ( !input_data || ( input_sent == input_total ) ) | 484 | if ( !input_data || ( input_sent == input_total ) ) |
484 | return ; | 485 | return ; |
485 | 486 | ||
486 | int d1, d2; | 487 | int d1, d2; |
487 | 488 | ||
488 | do | 489 | do |
489 | { | 490 | { |
490 | d1 = input_total - input_sent; | 491 | d1 = input_total - input_sent; |
491 | slotSendData ( 0 ); | 492 | slotSendData ( 0 ); |
492 | d2 = input_total - input_sent; | 493 | d2 = input_total - input_sent; |
493 | } | 494 | } |
494 | while ( d2 <= d1 ); | 495 | while ( d2 <= d1 ); |
495 | } | 496 | } |
496 | 497 | ||
497 | void OProcess::suspend() | 498 | void OProcess::suspend() |
498 | { | 499 | { |
499 | if ( ( communication & Stdout ) && outnot ) | 500 | if ( ( communication & Stdout ) && outnot ) |
500 | outnot->setEnabled( false ); | 501 | outnot->setEnabled( false ); |
501 | } | 502 | } |
502 | 503 | ||
503 | void OProcess::resume() | 504 | void OProcess::resume() |
504 | { | 505 | { |
505 | if ( ( communication & Stdout ) && outnot ) | 506 | if ( ( communication & Stdout ) && outnot ) |
506 | outnot->setEnabled( true ); | 507 | outnot->setEnabled( true ); |
507 | } | 508 | } |
508 | 509 | ||
509 | bool OProcess::closeStdin() | 510 | bool OProcess::closeStdin() |
510 | { | 511 | { |
511 | bool rv; | 512 | bool rv; |
512 | 513 | ||
513 | if ( communication & Stdin ) | 514 | if ( communication & Stdin ) |
514 | { | 515 | { |
515 | communication = ( Communication ) ( communication & ~Stdin ); | 516 | communication = ( Communication ) ( communication & ~Stdin ); |
516 | delete innot; | 517 | delete innot; |
517 | innot = 0; | 518 | innot = 0; |
518 | close( in[ 1 ] ); | 519 | close( in[ 1 ] ); |
519 | rv = true; | 520 | rv = true; |
520 | } | 521 | } |
521 | else | 522 | else |
522 | rv = false; | 523 | rv = false; |
523 | return rv; | 524 | return rv; |
524 | } | 525 | } |
525 | 526 | ||
526 | bool OProcess::closeStdout() | 527 | bool OProcess::closeStdout() |
527 | { | 528 | { |
528 | bool rv; | 529 | bool rv; |
529 | 530 | ||
530 | if ( communication & Stdout ) | 531 | if ( communication & Stdout ) |
531 | { | 532 | { |
532 | communication = ( Communication ) ( communication & ~Stdout ); | 533 | communication = ( Communication ) ( communication & ~Stdout ); |
533 | delete outnot; | 534 | delete outnot; |
534 | outnot = 0; | 535 | outnot = 0; |
535 | close( out[ 0 ] ); | 536 | close( out[ 0 ] ); |
536 | rv = true; | 537 | rv = true; |
537 | } | 538 | } |
538 | else | 539 | else |
539 | rv = false; | 540 | rv = false; |
540 | return rv; | 541 | return rv; |
541 | } | 542 | } |
542 | 543 | ||
543 | bool OProcess::closeStderr() | 544 | bool OProcess::closeStderr() |
544 | { | 545 | { |
545 | bool rv; | 546 | bool rv; |
546 | 547 | ||
547 | if ( communication & Stderr ) | 548 | if ( communication & Stderr ) |
548 | { | 549 | { |
549 | communication = static_cast<Communication>( communication & ~Stderr ); | 550 | communication = static_cast<Communication>( communication & ~Stderr ); |
550 | delete errnot; | 551 | delete errnot; |
551 | errnot = 0; | 552 | errnot = 0; |
552 | close( err[ 0 ] ); | 553 | close( err[ 0 ] ); |