kdecore Library API Documentation

kprocess.cpp

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