kdecore Library API Documentation

kprocess.cpp

00001 /* 00002 00003 $Id: kprocess.cpp,v 1.130.2.1 2004/01/19 13:01:23 waba Exp $ 00004 00005 This file is part of the KDE libraries 00006 Copyright (C) 1997 Christian Czezatke (e9025461@student.tuwien.ac.at) 00007 00008 This library is free software; you can redistribute it and/or 00009 modify it under the terms of the GNU Library General Public 00010 License as published by the Free Software Foundation; either 00011 version 2 of the License, or (at your option) any later version. 00012 00013 This library is distributed in the hope that it will be useful, 00014 but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 Library General Public License for more details. 00017 00018 You should have received a copy of the GNU Library General Public License 00019 along with this library; see the file COPYING.LIB. If not, write to 00020 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 00021 Boston, MA 02111-1307, USA. 00022 */ 00023 00024 00025 #include "kprocess.h" 00026 #include "kprocctrl.h" 00027 #include "kpty.h" 00028 00029 #include <config.h> 00030 00031 #ifdef __sgi 00032 #define __svr4__ 00033 #endif 00034 00035 #ifdef __osf__ 00036 #define _OSF_SOURCE 00037 #include <float.h> 00038 #endif 00039 00040 #ifdef _AIX 00041 #define _ALL_SOURCE 00042 #endif 00043 00044 #include <sys/types.h> 00045 #include <sys/ioctl.h> 00046 #include <sys/time.h> 00047 #include <sys/resource.h> 00048 #include <sys/stat.h> 00049 #include <sys/socket.h> 00050 #include <sys/wait.h> 00051 00052 #ifdef HAVE_SYS_STROPTS_H 00053 #include <sys/stropts.h> // Defines I_PUSH 00054 #define _NEW_TTY_CTRL 00055 #endif 00056 #ifdef HAVE_SYS_SELECT_H 00057 #include <sys/select.h> 00058 #endif 00059 00060 #include <errno.h> 00061 #include <assert.h> 00062 #include <fcntl.h> 00063 #include <time.h> 00064 #include <stdlib.h> 00065 #include <signal.h> 00066 #include <stdio.h> 00067 #include <string.h> 00068 #include <unistd.h> 00069 #include <pwd.h> 00070 #include <grp.h> 00071 00072 #include <qfile.h> 00073 #include <qsocketnotifier.h> 00074 #include <qapplication.h> 00075 00076 #include <kdebug.h> 00077 #include <kstandarddirs.h> 00078 #include <kuser.h> 00079 00080 00082 // private data // 00084 00085 class KProcessPrivate { 00086 public: 00087 KProcessPrivate() : 00088 usePty(KProcess::NoCommunication), 00089 addUtmp(false), useShell(false), 00090 pty(0), priority(0) 00091 { 00092 } 00093 00094 KProcess::Communication usePty; 00095 bool addUtmp : 1; 00096 bool useShell : 1; 00097 00098 KPty *pty; 00099 00100 int priority; 00101 00102 QMap<QString,QString> env; 00103 QString wd; 00104 QCString shell; 00105 QCString executable; 00106 }; 00107 00109 // public member functions // 00111 00112 KProcess::KProcess( QObject* parent, const char *name ) 00113 : QObject( parent, name ), 00114 run_mode(NotifyOnExit), 00115 runs(false), 00116 pid_(0), 00117 status(0), 00118 keepPrivs(false), 00119 innot(0), 00120 outnot(0), 00121 errnot(0), 00122 communication(NoCommunication), 00123 input_data(0), 00124 input_sent(0), 00125 input_total(0) 00126 { 00127 KProcessController::ref(); 00128 KProcessController::theKProcessController->addKProcess(this); 00129 00130 d = new KProcessPrivate; 00131 00132 out[0] = out[1] = -1; 00133 in[0] = in[1] = -1; 00134 err[0] = err[1] = -1; 00135 } 00136 00137 KProcess::KProcess() 00138 : QObject(), 00139 run_mode(NotifyOnExit), 00140 runs(false), 00141 pid_(0), 00142 status(0), 00143 keepPrivs(false), 00144 innot(0), 00145 outnot(0), 00146 errnot(0), 00147 communication(NoCommunication), 00148 input_data(0), 00149 input_sent(0), 00150 input_total(0) 00151 { 00152 KProcessController::ref(); 00153 KProcessController::theKProcessController->addKProcess(this); 00154 00155 d = new KProcessPrivate; 00156 00157 out[0] = out[1] = -1; 00158 in[0] = in[1] = -1; 00159 err[0] = err[1] = -1; 00160 } 00161 00162 void 00163 KProcess::setEnvironment(const QString &name, const QString &value) 00164 { 00165 d->env.insert(name, value); 00166 } 00167 00168 void 00169 KProcess::setWorkingDirectory(const QString &dir) 00170 { 00171 d->wd = dir; 00172 } 00173 00174 void 00175 KProcess::setupEnvironment() 00176 { 00177 QMap<QString,QString>::Iterator it; 00178 for(it = d->env.begin(); it != d->env.end(); ++it) 00179 { 00180 setenv(QFile::encodeName(it.key()).data(), 00181 QFile::encodeName(it.data()).data(), 1); 00182 } 00183 if (!d->wd.isEmpty()) 00184 { 00185 chdir(QFile::encodeName(d->wd).data()); 00186 } 00187 } 00188 00189 void 00190 KProcess::setRunPrivileged(bool keepPrivileges) 00191 { 00192 keepPrivs = keepPrivileges; 00193 } 00194 00195 bool 00196 KProcess::runPrivileged() const 00197 { 00198 return keepPrivs; 00199 } 00200 00201 bool 00202 KProcess::setPriority(int prio) 00203 { 00204 if (runs) { 00205 if (setpriority(PRIO_PROCESS, pid_, prio)) 00206 return false; 00207 } else { 00208 if (prio > 19 || prio < (geteuid() ? getpriority(PRIO_PROCESS, 0) : -20)) 00209 return false; 00210 } 00211 d->priority = prio; 00212 return true; 00213 } 00214 00215 KProcess::~KProcess() 00216 { 00217 if (run_mode != DontCare) 00218 kill(SIGKILL); 00219 detach(); 00220 00221 delete d->pty; 00222 delete d; 00223 00224 KProcessController::theKProcessController->removeKProcess(this); 00225 KProcessController::deref(); 00226 } 00227 00228 void KProcess::detach() 00229 { 00230 if (runs) { 00231 KProcessController::theKProcessController->addProcess(pid_); 00232 runs = false; 00233 pid_ = 0; // close without draining 00234 commClose(); // Clean up open fd's and socket notifiers. 00235 } 00236 } 00237 00238 void KProcess::setBinaryExecutable(const char *filename) 00239 { 00240 d->executable = filename; 00241 } 00242 00243 bool KProcess::setExecutable(const QString& proc) 00244 { 00245 if (runs) return false; 00246 00247 if (proc.isEmpty()) return false; 00248 00249 if (!arguments.isEmpty()) 00250 arguments.remove(arguments.begin()); 00251 arguments.prepend(QFile::encodeName(proc)); 00252 00253 return true; 00254 } 00255 00256 KProcess &KProcess::operator<<(const QStringList& args) 00257 { 00258 QStringList::ConstIterator it = args.begin(); 00259 for ( ; it != args.end() ; ++it ) 00260 arguments.append(QFile::encodeName(*it)); 00261 return *this; 00262 } 00263 00264 KProcess &KProcess::operator<<(const QCString& arg) 00265 { 00266 return operator<< (arg.data()); 00267 } 00268 00269 KProcess &KProcess::operator<<(const char* arg) 00270 { 00271 arguments.append(arg); 00272 return *this; 00273 } 00274 00275 KProcess &KProcess::operator<<(const QString& arg) 00276 { 00277 arguments.append(QFile::encodeName(arg)); 00278 return *this; 00279 } 00280 00281 void KProcess::clearArguments() 00282 { 00283 arguments.clear(); 00284 } 00285 00286 bool KProcess::start(RunMode runmode, Communication comm) 00287 { 00288 if (runs) { 00289 kdDebug(175) << "Attempted to start an already running process" << endl; 00290 return false; 00291 } 00292 00293 uint n = arguments.count(); 00294 if (n == 0) { 00295 kdDebug(175) << "Attempted to start a process without arguments" << endl; 00296 return false; 00297 } 00298 char **arglist; 00299 QCString shellCmd; 00300 if (d->useShell) 00301 { 00302 if (d->shell.isEmpty()) { 00303 kdDebug(175) << "Invalid shell specified" << endl; 00304 return false; 00305 } 00306 00307 for (uint i = 0; i < n; i++) { 00308 shellCmd += arguments[i]; 00309 shellCmd += " "; // CC: to separate the arguments 00310 } 00311 00312 arglist = static_cast<char **>(malloc( 4 * sizeof(char *))); 00313 arglist[0] = d->shell.data(); 00314 arglist[1] = (char *) "-c"; 00315 arglist[2] = shellCmd.data(); 00316 arglist[3] = 0; 00317 } 00318 else 00319 { 00320 arglist = static_cast<char **>(malloc( (n + 1) * sizeof(char *))); 00321 for (uint i = 0; i < n; i++) 00322 arglist[i] = arguments[i].data(); 00323 arglist[n] = 0; 00324 } 00325 00326 run_mode = runmode; 00327 00328 if (!setupCommunication(comm)) 00329 { 00330 kdDebug(175) << "Could not setup Communication!" << endl; 00331 free(arglist); 00332 return false; 00333 } 00334 00335 // We do this in the parent because if we do it in the child process 00336 // gdb gets confused when the application runs from gdb. 00337 #ifdef HAVE_INITGROUPS 00338 struct passwd *pw = geteuid() ? 0 : getpwuid(getuid()); 00339 #endif 00340 00341 int fd[2]; 00342 if (pipe(fd)) 00343 fd[0] = fd[1] = -1; // Pipe failed.. continue 00344 00345 QApplication::flushX(); 00346 00347 // we don't use vfork() because 00348 // - it has unclear semantics and is not standardized 00349 // - we do way too much magic in the child 00350 pid_ = fork(); 00351 if (pid_ == 0) { 00352 // The child process 00353 00354 close(fd[0]); 00355 // Closing of fd[1] indicates that the execvp() succeeded! 00356 fcntl(fd[1], F_SETFD, FD_CLOEXEC); 00357 00358 if (!commSetupDoneC()) 00359 kdDebug(175) << "Could not finish comm setup in child!" << endl; 00360 00361 // reset all signal handlers 00362 struct sigaction act; 00363 sigemptyset(&act.sa_mask); 00364 act.sa_handler = SIG_DFL; 00365 act.sa_flags = 0; 00366 for (int sig = 1; sig < NSIG; sig++) 00367 sigaction(sig, &act, 0L); 00368 00369 if (d->priority) 00370 setpriority(PRIO_PROCESS, 0, d->priority); 00371 00372 if (!runPrivileged()) 00373 { 00374 setgid(getgid()); 00375 #ifdef HAVE_INITGROUPS 00376 if (pw) 00377 initgroups(pw->pw_name, pw->pw_gid); 00378 #endif 00379 setuid(getuid()); 00380 } 00381 00382 setupEnvironment(); 00383 00384 if (runmode == DontCare || runmode == OwnGroup) 00385 setsid(); 00386 00387 const char *executable = arglist[0]; 00388 if (!d->executable.isEmpty()) 00389 executable = d->executable.data(); 00390 execvp(executable, arglist); 00391 00392 char resultByte = 1; 00393 write(fd[1], &resultByte, 1); 00394 _exit(-1); 00395 } else if (pid_ == -1) { 00396 // forking failed 00397 00398 // commAbort(); 00399 pid_ = 0; 00400 free(arglist); 00401 return false; 00402 } 00403 // the parent continues here 00404 free(arglist); 00405 00406 if (!commSetupDoneP()) 00407 kdDebug(175) << "Could not finish comm setup in parent!" << endl; 00408 00409 // Check whether client could be started. 00410 close(fd[1]); 00411 for(;;) 00412 { 00413 char resultByte; 00414 int n = ::read(fd[0], &resultByte, 1); 00415 if (n == 1) 00416 { 00417 // exec() failed 00418 close(fd[0]); 00419 waitpid(pid_, 0, 0); 00420 pid_ = 0; 00421 commClose(); 00422 return false; 00423 } 00424 if (n == -1) 00425 { 00426 if (errno == EINTR) 00427 continue; // Ignore 00428 } 00429 break; // success 00430 } 00431 close(fd[0]); 00432 00433 runs = true; 00434 switch (runmode) 00435 { 00436 case Block: 00437 for (;;) 00438 { 00439 commClose(); // drain only, unless obsolete reimplementation 00440 if (!runs) 00441 { 00442 // commClose detected data on the process exit notifification pipe 00443 KProcessController::theKProcessController->unscheduleCheck(); 00444 if (waitpid(pid_, &status, WNOHANG) != 0) // error finishes, too 00445 { 00446 commClose(); // this time for real (runs is false) 00447 KProcessController::theKProcessController->rescheduleCheck(); 00448 break; 00449 } 00450 runs = true; // for next commClose() iteration 00451 } 00452 else 00453 { 00454 // commClose is an obsolete reimplementation and waited until 00455 // all output channels were closed (or it was interrupted). 00456 // there is a chance that it never gets here ... 00457 waitpid(pid_, &status, 0); 00458 runs = false; 00459 break; 00460 } 00461 } 00462 // why do we do this? i think this signal should be emitted _only_ 00463 // after the process has successfully run _asynchronously_ --ossi 00464 emit processExited(this); 00465 break; 00466 default: // NotifyOnExit & OwnGroup 00467 input_data = 0; // Discard any data for stdin that might still be there 00468 break; 00469 } 00470 00471 return true; 00472 } 00473 00474 00475 00476 bool KProcess::kill(int signo) 00477 { 00478 if (runs && pid_ > 0 && !::kill(run_mode == OwnGroup ? -pid_ : pid_, signo)) 00479 return true; 00480 return false; 00481 } 00482 00483 00484 00485 bool KProcess::isRunning() const 00486 { 00487 return runs; 00488 } 00489 00490 00491 00492 pid_t KProcess::pid() const 00493 { 00494 return pid_; 00495 } 00496 00497 #ifndef timersub 00498 # define timersub(a, b, result) \ 00499 do { \ 00500 (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \ 00501 (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \ 00502 if ((result)->tv_usec < 0) { \ 00503 --(result)->tv_sec; \ 00504 (result)->tv_usec += 1000000; \ 00505 } \ 00506 } while (0) 00507 #endif 00508 00509 bool KProcess::wait(int timeout) 00510 { 00511 if (!runs) 00512 return true; 00513 00514 #ifndef __linux__ 00515 struct timeval etv; 00516 #endif 00517 struct timeval tv, *tvp; 00518 if (timeout < 0) 00519 tvp = 0; 00520 else 00521 { 00522 #ifndef __linux__ 00523 gettimeofday(&etv, 0); 00524 etv.tv_sec += timeout; 00525 #else 00526 tv.tv_sec = timeout; 00527 tv.tv_usec = 0; 00528 #endif 00529 tvp = &tv; 00530 } 00531 00532 int fd = KProcessController::theKProcessController->notifierFd(); 00533 for(;;) 00534 { 00535 fd_set fds; 00536 FD_ZERO( &fds ); 00537 FD_SET( fd, &fds ); 00538 00539 #ifndef __linux__ 00540 if (tvp) 00541 { 00542 gettimeofday(&tv, 0); 00543 timersub(&etv, &tv, &tv); 00544 if (tv.tv_sec < 0) 00545 tv.tv_sec = tv.tv_usec = 0; 00546 } 00547 #endif 00548 00549 switch( select( fd+1, &fds, 0, 0, tvp ) ) 00550 { 00551 case -1: 00552 if( errno == EINTR ) 00553 break; 00554 // fall through; should happen if tvp->tv_sec < 0 00555 case 0: 00556 KProcessController::theKProcessController->rescheduleCheck(); 00557 return false; 00558 default: 00559 KProcessController::theKProcessController->unscheduleCheck(); 00560 if (waitpid(pid_, &status, WNOHANG) != 0) // error finishes, too 00561 { 00562 processHasExited(status); 00563 KProcessController::theKProcessController->rescheduleCheck(); 00564 return true; 00565 } 00566 } 00567 } 00568 } 00569 00570 00571 00572 bool KProcess::normalExit() const 00573 { 00574 return (pid_ != 0) && !runs && WIFEXITED(status); 00575 } 00576 00577 00578 bool KProcess::signalled() const 00579 { 00580 return (pid_ != 0) && !runs && WIFSIGNALED(status); 00581 } 00582 00583 00584 bool KProcess::coreDumped() const 00585 { 00586 #ifdef WCOREDUMP 00587 return signalled() && WCOREDUMP(status); 00588 #else 00589 return false; 00590 #endif 00591 } 00592 00593 00594 int KProcess::exitStatus() const 00595 { 00596 return WEXITSTATUS(status); 00597 } 00598 00599 00600 int KProcess::exitSignal() const 00601 { 00602 return WTERMSIG(status); 00603 } 00604 00605 00606 bool KProcess::writeStdin(const char *buffer, int buflen) 00607 { 00608 // if there is still data pending, writing new data 00609 // to stdout is not allowed (since it could also confuse 00610 // kprocess ...) 00611 if (input_data != 0) 00612 return false; 00613 00614 if (communication & Stdin) { 00615 input_data = buffer; 00616 input_sent = 0; 00617 input_total = buflen; 00618 innot->setEnabled(true); 00619 if (input_total) 00620 slotSendData(0); 00621 return true; 00622 } else 00623 return false; 00624 } 00625 00626 void KProcess::suspend() 00627 { 00628 if (outnot) 00629 outnot->setEnabled(false); 00630 } 00631 00632 void KProcess::resume() 00633 { 00634 if (outnot) 00635 outnot->setEnabled(true); 00636 } 00637 00638 bool KProcess::closeStdin() 00639 { 00640 if (communication & Stdin) { 00641 communication = (Communication) (communication & ~Stdin); 00642 delete innot; 00643 innot = 0; 00644 if (!(d->usePty & Stdin)) 00645 close(in[1]); 00646 in[1] = -1; 00647 return true; 00648 } else 00649 return false; 00650 } 00651 00652 bool KProcess::closeStdout() 00653 { 00654 if (communication & Stdout) { 00655 communication = (Communication) (communication & ~Stdout); 00656 delete outnot; 00657 outnot = 0; 00658 if (!(d->usePty & Stdout)) 00659 close(out[0]); 00660 out[0] = -1; 00661 return true; 00662 } else 00663 return false; 00664 } 00665 00666 bool KProcess::closeStderr() 00667 { 00668 if (communication & Stderr) { 00669 communication = (Communication) (communication & ~Stderr); 00670 delete errnot; 00671 errnot = 0; 00672 if (!(d->usePty & Stderr)) 00673 close(err[0]); 00674 err[0] = -1; 00675 return true; 00676 } else 00677 return false; 00678 } 00679 00680 bool KProcess::closePty() 00681 { 00682 if (d->pty && d->pty->masterFd() >= 0) { 00683 if (d->addUtmp) 00684 d->pty->logout(); 00685 d->pty->close(); 00686 return true; 00687 } else 00688 return false; 00689 } 00690 00691 void KProcess::closeAll() 00692 { 00693 closeStdin(); 00694 closeStdout(); 00695 closeStderr(); 00696 closePty(); 00697 } 00698 00700 // protected slots // 00702 00703 00704 00705 void KProcess::slotChildOutput(int fdno) 00706 { 00707 if (!childOutput(fdno)) 00708 closeStdout(); 00709 } 00710 00711 00712 void KProcess::slotChildError(int fdno) 00713 { 00714 if (!childError(fdno)) 00715 closeStderr(); 00716 } 00717 00718 00719 void KProcess::slotSendData(int) 00720 { 00721 if (input_sent == input_total) { 00722 innot->setEnabled(false); 00723 input_data = 0; 00724 emit wroteStdin(this); 00725 } else { 00726 int result = ::write(in[1], input_data+input_sent, input_total-input_sent); 00727 if (result >= 0) 00728 { 00729 input_sent += result; 00730 } 00731 else if ((errno != EAGAIN) && (errno != EINTR)) 00732 { 00733 kdDebug(175) << "Error writing to stdin of child process" << endl; 00734 closeStdin(); 00735 } 00736 } 00737 } 00738 00739 void KProcess::setUseShell(bool useShell, const char *shell) 00740 { 00741 d->useShell = useShell; 00742 d->shell = (shell && *shell) ? shell : "/bin/sh"; 00743 } 00744 00745 void KProcess::setUsePty(Communication usePty, bool addUtmp) 00746 { 00747 d->usePty = usePty; 00748 d->addUtmp = addUtmp; 00749 if (usePty) { 00750 if (!d->pty) 00751 d->pty = new KPty; 00752 } else { 00753 delete d->pty; 00754 d->pty = 0; 00755 } 00756 } 00757 00758 KPty *KProcess::pty() const 00759 { 00760 return d->pty; 00761 } 00762 00763 QString KProcess::quote(const QString &arg) 00764 { 00765 QChar q('\''); 00766 return QString(arg).replace(q, "'\\''").prepend(q).append(q); 00767 } 00768 00769 00771 // private member functions // 00773 00774 00775 void KProcess::processHasExited(int state) 00776 { 00777 // only successfully run NotifyOnExit processes ever get here 00778 00779 status = state; 00780 runs = false; // do this before commClose, so it knows we're dead 00781 00782 commClose(); // cleanup communication sockets 00783 00784 if (run_mode != DontCare) 00785 emit processExited(this); 00786 } 00787 00788 00789 00790 int KProcess::childOutput(int fdno) 00791 { 00792 if (communication & NoRead) { 00793 int len = -1; 00794 emit receivedStdout(fdno, len); 00795 errno = 0; // Make sure errno doesn't read "EAGAIN" 00796 return len; 00797 } 00798 else 00799 { 00800 char buffer[1025]; 00801 int len; 00802 00803 len = ::read(fdno, buffer, 1024); 00804 00805 if (len > 0) { 00806 buffer[len] = 0; // Just in case. 00807 emit receivedStdout(this, buffer, len); 00808 } 00809 return len; 00810 } 00811 } 00812 00813 int KProcess::childError(int fdno) 00814 { 00815 char buffer[1025]; 00816 int len; 00817 00818 len = ::read(fdno, buffer, 1024); 00819 00820 if (len > 0) { 00821 buffer[len] = 0; // Just in case. 00822 emit receivedStderr(this, buffer, len); 00823 } 00824 return len; 00825 } 00826 00827 00828 int KProcess::setupCommunication(Communication comm) 00829 { 00830 // PTY stuff // 00831 if (d->usePty) 00832 { 00833 // cannot communicate on both stderr and stdout if they are both on the pty 00834 if (!(~(comm & d->usePty) & (Stdout | Stderr))) { 00835 kdWarning(175) << "Invalid usePty/communication combination (" << d->usePty << "/" << comm << ")" << endl; 00836 return 0; 00837 } 00838 if (!d->pty->open()) 00839 return 0; 00840 00841 int rcomm = comm & d->usePty; 00842 int mfd = d->pty->masterFd(); 00843 if (rcomm & Stdin) 00844 in[1] = mfd; 00845 if (rcomm & Stdout) 00846 out[0] = mfd; 00847 if (rcomm & Stderr) 00848 err[0] = mfd; 00849 } 00850 00851 communication = comm; 00852 00853 comm = (Communication) (comm & ~d->usePty); 00854 if (comm & Stdin) { 00855 if (socketpair(AF_UNIX, SOCK_STREAM, 0, in)) 00856 goto fail0; 00857 fcntl(in[0], F_SETFD, FD_CLOEXEC); 00858 fcntl(in[1], F_SETFD, FD_CLOEXEC); 00859 } 00860 if (comm & Stdout) { 00861 if (socketpair(AF_UNIX, SOCK_STREAM, 0, out)) 00862 goto fail1; 00863 fcntl(out[0], F_SETFD, FD_CLOEXEC); 00864 fcntl(out[1], F_SETFD, FD_CLOEXEC); 00865 } 00866 if (comm & Stderr) { 00867 if (socketpair(AF_UNIX, SOCK_STREAM, 0, err)) 00868 goto fail2; 00869 fcntl(err[0], F_SETFD, FD_CLOEXEC); 00870 fcntl(err[1], F_SETFD, FD_CLOEXEC); 00871 } 00872 return 1; // Ok 00873 fail2: 00874 if (comm & Stdout) 00875 { 00876 close(out[0]); 00877 close(out[1]); 00878 out[0] = out[1] = -1; 00879 } 00880 fail1: 00881 if (comm & Stdin) 00882 { 00883 close(in[0]); 00884 close(in[1]); 00885 in[0] = in[1] = -1; 00886 } 00887 fail0: 00888 communication = NoCommunication; 00889 return 0; // Error 00890 } 00891 00892 00893 00894 int KProcess::commSetupDoneP() 00895 { 00896 int rcomm = communication & ~d->usePty; 00897 if (rcomm & Stdin) 00898 close(in[0]); 00899 if (rcomm & Stdout) 00900 close(out[1]); 00901 if (rcomm & Stderr) 00902 close(err[1]); 00903 in[0] = out[1] = err[1] = -1; 00904 00905 // Don't create socket notifiers if no interactive comm is to be expected 00906 if (run_mode != NotifyOnExit && run_mode != OwnGroup) 00907 return 1; 00908 00909 if (communication & Stdin) { 00910 fcntl(in[1], F_SETFL, O_NONBLOCK | fcntl(in[1], F_GETFL)); 00911 innot = new QSocketNotifier(in[1], QSocketNotifier::Write, this); 00912 Q_CHECK_PTR(innot); 00913 innot->setEnabled(false); // will be enabled when data has to be sent 00914 QObject::connect(innot, SIGNAL(activated(int)), 00915 this, SLOT(slotSendData(int))); 00916 } 00917 00918 if (communication & Stdout) { 00919 outnot = new QSocketNotifier(out[0], QSocketNotifier::Read, this); 00920 Q_CHECK_PTR(outnot); 00921 QObject::connect(outnot, SIGNAL(activated(int)), 00922 this, SLOT(slotChildOutput(int))); 00923 if (communication & NoRead) 00924 suspend(); 00925 } 00926 00927 if (communication & Stderr) { 00928 errnot = new QSocketNotifier(err[0], QSocketNotifier::Read, this ); 00929 Q_CHECK_PTR(errnot); 00930 QObject::connect(errnot, SIGNAL(activated(int)), 00931 this, SLOT(slotChildError(int))); 00932 } 00933 00934 return 1; 00935 } 00936 00937 00938 00939 int KProcess::commSetupDoneC() 00940 { 00941 int ok = 1; 00942 00943 if (d->usePty & Stdin) { 00944 if (dup2(d->pty->slaveFd(), STDIN_FILENO) < 0) ok = 0; 00945 } else if (communication & Stdin) { 00946 if (dup2(in[0], STDIN_FILENO) < 0) ok = 0; 00947 } else { 00948 int null_fd = open( "/dev/null", O_RDONLY ); 00949 if (dup2( null_fd, STDIN_FILENO ) < 0) ok = 0; 00950 close( null_fd ); 00951 } 00952 struct linger so; 00953 memset(&so, 0, sizeof(so)); 00954 if (d->usePty & Stdout) { 00955 if (dup2(d->pty->slaveFd(), STDOUT_FILENO) < 0) ok = 0; 00956 } else if (communication & Stdout) { 00957 if (dup2(out[1], STDOUT_FILENO) < 0 || 00958 setsockopt(out[1], SOL_SOCKET, SO_LINGER, (char *)&so, sizeof(so))) 00959 ok = 0; 00960 } 00961 if (d->usePty & Stderr) { 00962 if (dup2(d->pty->slaveFd(), STDERR_FILENO) < 0) ok = 0; 00963 } else if (communication & Stderr) { 00964 if (dup2(err[1], STDERR_FILENO) < 0 || 00965 setsockopt(err[1], SOL_SOCKET, SO_LINGER, (char *)&so, sizeof(so))) 00966 ok = 0; 00967 } 00968 00969 // don't even think about closing all open fds here or anywhere else 00970 00971 // PTY stuff // 00972 if (d->usePty) { 00973 d->pty->setCTty(); 00974 if (d->addUtmp) 00975 d->pty->login(KUser(KUser::UseRealUserID).loginName().local8Bit().data(), getenv("DISPLAY")); 00976 } 00977 00978 return ok; 00979 } 00980 00981 00982 00983 void KProcess::commClose() 00984 { 00985 closeStdin(); 00986 00987 if (pid_) { // detached, failed, and killed processes have no output. basta. :) 00988 // If both channels are being read we need to make sure that one socket 00989 // buffer doesn't fill up whilst we are waiting for data on the other 00990 // (causing a deadlock). Hence we need to use select. 00991 00992 int notfd = KProcessController::theKProcessController->notifierFd(); 00993 00994 while ((communication & (Stdout | Stderr)) || runs) { 00995 fd_set rfds; 00996 FD_ZERO(&rfds); 00997 struct timeval timeout, *p_timeout; 00998 00999 int max_fd = 0; 01000 if (communication & Stdout) { 01001 FD_SET(out[0], &rfds); 01002 max_fd = out[0]; 01003 } 01004 if (communication & Stderr) { 01005 FD_SET(err[0], &rfds); 01006 if (err[0] > max_fd) 01007 max_fd = err[0]; 01008 } 01009 if (runs) { 01010 FD_SET(notfd, &rfds); 01011 if (notfd > max_fd) 01012 max_fd = notfd; 01013 // If the process is still running we block until we 01014 // receive data or the process exits. 01015 p_timeout = 0; // no timeout 01016 } else { 01017 // If the process has already exited, we only check 01018 // the available data, we don't wait for more. 01019 timeout.tv_sec = timeout.tv_usec = 0; // timeout immediately 01020 p_timeout = &timeout; 01021 } 01022 01023 int fds_ready = select(max_fd+1, &rfds, 0, 0, p_timeout); 01024 if (fds_ready < 0) { 01025 if (errno == EINTR) 01026 continue; 01027 break; 01028 } else if (!fds_ready) 01029 break; 01030 01031 if ((communication & Stdout) && FD_ISSET(out[0], &rfds)) 01032 slotChildOutput(out[0]); 01033 01034 if ((communication & Stderr) && FD_ISSET(err[0], &rfds)) 01035 slotChildError(err[0]); 01036 01037 if (runs && FD_ISSET(notfd, &rfds)) { 01038 runs = false; // hack: signal potential exit 01039 return; // don't close anything, we will be called again 01040 } 01041 } 01042 } 01043 01044 closeStdout(); 01045 closeStderr(); 01046 01047 closePty(); 01048 } 01049 01050 01051 void KProcess::virtual_hook( int, void* ) 01052 { /*BASE::virtual_hook( id, data );*/ } 01053 01054 01056 // CC: Class KShellProcess 01058 01059 KShellProcess::KShellProcess(const char *shellname): 01060 KProcess() 01061 { 01062 setUseShell( true, shellname ? shellname : getenv("SHELL") ); 01063 } 01064 01065 KShellProcess::~KShellProcess() { 01066 } 01067 01068 QString KShellProcess::quote(const QString &arg) 01069 { 01070 return KProcess::quote(arg); 01071 } 01072 01073 bool KShellProcess::start(RunMode runmode, Communication comm) 01074 { 01075 return KProcess::start(runmode, comm); 01076 } 01077 01078 void KShellProcess::virtual_hook( int id, void* data ) 01079 { KProcess::virtual_hook( id, data ); } 01080 01081 #include "kprocess.moc"
KDE Logo
This file is part of the documentation for kdecore Library Version 3.2.3.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Fri Aug 20 09:48:26 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003