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