📄 kprocess.cpp
字号:
input_sent += ::write(in[1], input_data+input_sent, input_total-input_sent);}//////////////////////////////// private member functions ////////////////////////////////void KProcess::processHasExited(int state){ runs = FALSE; status = state; commClose(); // cleanup communication sockets // also emit a signal if the process was run Blocking if (DontCare != run_mode) emit processExited(this);}int KProcess::childOutput(int fdno){ char buffer[1024]; int len; len = ::read(fdno, buffer, 1024); if ( 0 < len) { emit receivedStdout(this, buffer, len); } return len;}int KProcess::childError(int fdno){ char buffer[1024]; int len; len = ::read(fdno, buffer, 1024); if ( 0 < len) emit receivedStderr(this, buffer, len); return len;}int KProcess::setupCommunication(Communication comm){ int ok; communication = comm; ok = 1; if (comm & Stdin) ok &= socketpair(AF_UNIX, SOCK_STREAM, 0, in) >= 0; if (comm & Stdout) ok &= socketpair(AF_UNIX, SOCK_STREAM, 0, out) >= 0; if (comm & Stderr) ok &= socketpair(AF_UNIX, SOCK_STREAM, 0, err) >= 0; return ok;}int KProcess::commSetupDoneP(){ int ok = 1; if (communication != NoCommunication) { if (communication & Stdin) close(in[0]); if (communication & Stdout) close(out[1]); if (communication & Stderr) close(err[1]); // Don't create socket notifiers and set the sockets non-blocking if // blocking is requested. if (run_mode == Block) return ok; if (communication & Stdin) { ok &= (-1 != fcntl(in[1], F_SETFL, O_NONBLOCK)); innot = new QSocketNotifier(in[1], QSocketNotifier::Write, this); CHECK_PTR(innot); innot->setEnabled(FALSE); // will be enabled when data has to be sent QObject::connect(innot, SIGNAL(activated(int)), this, SLOT(slotSendData(int))); } if (communication & Stdout) { ok &= (-1 != fcntl(out[0], F_SETFL, O_NONBLOCK)); outnot = new QSocketNotifier(out[0], QSocketNotifier::Read, this); CHECK_PTR(outnot); QObject::connect(outnot, SIGNAL(activated(int)), this, SLOT(slotChildOutput(int))); } if (communication & Stderr) { ok &= (-1 != fcntl(err[0], F_SETFL, O_NONBLOCK)); errnot = new QSocketNotifier(err[0], QSocketNotifier::Read, this ); CHECK_PTR(errnot); QObject::connect(errnot, SIGNAL(activated(int)), this, SLOT(slotChildError(int))); } } return ok;}int KProcess::commSetupDoneC(){ int ok = 1; struct linger so; if (communication != NoCommunication) { if (communication & Stdin) close(in[1]); if (communication & Stdout) close(out[0]); if (communication & Stderr) close(err[0]); if (communication & Stdin) ok &= dup2(in[0], STDIN_FILENO) != -1; if (communication & Stdout) { ok &= dup2(out[1], STDOUT_FILENO) != -1; ok &= !setsockopt(out[1], SOL_SOCKET, SO_LINGER, (char*)&so, sizeof(so)); } if (communication & Stderr) { ok &= dup2(err[1], STDERR_FILENO) != -1; ok &= !setsockopt(err[1], SOL_SOCKET, SO_LINGER, (char*)&so, sizeof(so)); } } return ok;}void KProcess::commClose(){ if (NoCommunication != communication) { bool b_in = (communication & Stdin); bool b_out = (communication & Stdout); bool b_err = (communication & Stderr); if (b_in) delete innot; if (b_out || b_err) { // If both channels are being read we need to make sure that one socket buffer // doesn't fill up whilst we are waiting for data on the other (causing a deadlock). // Hence we need to use select. // Once one or other of the channels has reached EOF (or given an error) go back // to the usual mechanism. int fds_ready = 1; fd_set rfds; int max_fd = 0; if (b_out) { if (out[0] > max_fd) max_fd = out[0]; delete outnot; } if (b_err) { if (err[0] > max_fd) max_fd = err[0]; delete errnot; } while (b_out || b_err) { FD_ZERO(&rfds); if (b_out) FD_SET(out[0], &rfds); if (b_err) FD_SET(err[0], &rfds); fds_ready = select(max_fd+1, &rfds, 0, 0, 0); if (fds_ready <= 0) break; if (b_out && FD_ISSET(out[0], &rfds)) { int ret = childOutput(out[0]); if ((ret == -1 && errno != EAGAIN) || ret == 0) b_out = false; } if (b_err && FD_ISSET(err[0], &rfds)) { int ret = childError(err[0]); if ((ret == -1 && errno != EAGAIN) || ret == 0) b_err = false; } } } if (communication & Stdin) close(in[1]); if (communication & Stdout) close(out[0]); if (communication & Stderr) close(err[0]); communication = NoCommunication; }}///////////////////////////// CC: Class KShellProcess///////////////////////////KShellProcess::KShellProcess(const char *shellname): KProcess(){ if (0 != shellname) shell = kstrdup(shellname); else shell = 0;}KShellProcess::~KShellProcess() { if(shell) free(shell);}bool KShellProcess::start(RunMode runmode, Communication comm){ uint i; uint n = arguments.count(); char *arglist[4]; QString cmd; if (runs || (0 == n)) { return FALSE; // cannot start a process that is already running // or if no executable has been assigned } run_mode = runmode; status = 0; if (0 == shell) shell = searchShell(); if (0 == shell) { debug("Could not find a valid shell\n"); return FALSE; } // CC: Changed the way the parameter was built up // CC: Arglist for KShellProcess is now always: // CC: <shell> -c <command> arglist[0] = shell; arglist[1] = "-c"; for (i=0; i < n; i++) { cmd += arguments.at(i); cmd += " "; // CC: to separate the arguments }// // execution in background// cmd.stripWhiteSpace();// if (cmd[cmd.length()-1] != '&')// cmd += '&'; arglist[2] = cmd.data(); arglist[3] = 0; if (!setupCommunication(comm)) debug("Could not setup Communication!"); runs = TRUE; pid = fork(); if (0 == pid) { // The child process if(!commSetupDoneC()) debug("Could not finish comm setup in child!"); // Matthias if (run_mode == DontCare) setpgid(0,0); // restore default SIGPIPE handler (Harri) struct sigaction act; sigemptyset(&(act.sa_mask)); sigaddset(&(act.sa_mask), SIGPIPE); act.sa_handler = SIG_DFL; act.sa_flags = 0; sigaction(SIGPIPE, &act, 0L); execvp(arglist[0], arglist); exit(-1); } else if (-1 == pid) { // forking failed runs = FALSE; return FALSE; } else { // the parent continues here if (!commSetupDoneP()) // finish communication socket setup for the parent debug("Could not finish comm setup in parent!"); // Discard any data for stdin that might still be there input_data = 0; if (run_mode == Block) { commClose(); // Its possible that the child's exit was caught by the SIGCHLD handler // which will have set status for us. if (waitpid(pid, &status, 0) != -1) this->status = status; runs = FALSE; emit processExited(this); } } return TRUE;}char *KShellProcess::searchShell(){ char *hlp = 0; char *copy = 0; // CC: now get the name of the shell we have to use hlp = getenv("SHELL"); if (isExecutable(hlp)) { copy = kstrdup(hlp); CHECK_PTR(copy); } if (0 == copy) { // CC: hmm, invalid $SHELL in environment -- maybe there are whitespaces to be stripped? QString stmp = QString(shell); QString shell_stripped = stmp.stripWhiteSpace(); if (isExecutable(shell_stripped.data())) { copy = kstrdup(shell_stripped.data()); CHECK_PTR(copy); } } return copy;}bool KShellProcess::isExecutable(const char *fname){ struct stat fileinfo; if ((0 == fname) || (strlen(fname) == 0)) return FALSE; // CC: filename is invalid // CC: we've got a valid filename, now let's see whether we can execute that file if (-1 == stat(fname, &fileinfo)) return FALSE; // CC: return false if the file does not exist // CC: anyway, we cannot execute directories, block/character devices, fifos or sockets if ( (S_ISDIR(fileinfo.st_mode)) || (S_ISCHR(fileinfo.st_mode)) || (S_ISBLK(fileinfo.st_mode)) ||#ifdef S_ISSOCK // CC: SYSVR4 systems don't have that macro (S_ISSOCK(fileinfo.st_mode)) ||#endif (S_ISFIFO(fileinfo.st_mode)) || (S_ISDIR(fileinfo.st_mode)) ) { return FALSE; } // CC: now check for permission to execute the file if (access(fname, X_OK) != 0) return FALSE; // CC: we've passed all the tests... return TRUE;}#include "kprocess.moc"
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -