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