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