26 #include "kprocctrl.h"
40 #include <sys/socket.h>
41 #include <sys/ioctl.h>
44 #include <sys/types.h>
46 #include <sys/resource.h>
50 #ifdef HAVE_SYS_STROPTS_H
51 #include <sys/stropts.h>
54 #ifdef HAVE_SYS_SELECT_H
55 #include <sys/select.h>
71 #include <tqsocketnotifier.h>
72 #include <tqapplication.h>
75 #include <kstandarddirs.h>
83 class TDEProcessPrivate {
87 addUtmp(false), useShell(false),
105 TQMap<TQString,TQString> env;
108 TQCString executable;
116 : TQObject( parent, name ),
117 run_mode(NotifyOnExit),
125 communication(NoCommunication),
133 d =
new TDEProcessPrivate;
142 run_mode(NotifyOnExit),
150 communication(NoCommunication),
158 d =
new TDEProcessPrivate;
168 d->env.insert(name, value);
180 TQMap<TQString,TQString>::Iterator it;
181 for(it = d->env.begin(); it != d->env.end(); ++it)
183 setenv(TQFile::encodeName(it.key()).data(),
184 TQFile::encodeName(it.data()).data(), 1);
186 if (!d->wd.isEmpty())
188 chdir(TQFile::encodeName(d->wd).data());
209 if (setpriority(PRIO_PROCESS,
pid_, prio))
212 if (prio > 19 || prio < (geteuid() ? getpriority(PRIO_PROCESS, 0) : -20))
247 d->executable = filename;
252 if (
runs)
return false;
254 if (proc.isEmpty())
return false;
258 arguments.prepend(TQFile::encodeName(proc));
265 TQStringList::ConstIterator it =
args.begin();
266 for ( ; it !=
args.end() ; ++it )
267 arguments.append(TQFile::encodeName(*it));
284 arguments.append(TQFile::encodeName(arg));
296 kdDebug(175) <<
"Attempted to start an already running process" <<
endl;
302 kdDebug(175) <<
"Attempted to start a process without arguments" <<
endl;
310 if (d->shell.isEmpty()) {
311 kdDebug(175) <<
"Invalid shell specified" <<
endl;
315 for (uint i = 0; i < n; i++) {
320 arglist =
static_cast<char **
>(malloc( 4 *
sizeof(
char *)));
321 arglist[0] = d->shell.data();
322 arglist[1] = (
char *)
"-c";
323 arglist[2] = shellCmd.data();
328 arglist =
static_cast<char **
>(malloc( (n + 1) *
sizeof(
char *)));
329 for (uint i = 0; i < n; i++)
338 kdDebug(175) <<
"Could not setup Communication!" <<
endl;
345 #ifdef HAVE_INITGROUPS
346 struct passwd *pw = geteuid() ? 0 : getpwuid(getuid());
362 fcntl(fd[1], F_SETFD, FD_CLOEXEC);
365 kdDebug(175) <<
"Could not finish comm setup in child!" <<
endl;
368 struct sigaction act;
369 sigemptyset(&act.sa_mask);
370 act.sa_handler = SIG_DFL;
372 for (
int sig = 1; sig < NSIG; sig++)
373 sigaction(sig, &act, 0L);
376 setpriority(PRIO_PROCESS, 0, d->priority);
381 #ifdef HAVE_INITGROUPS
383 initgroups(pw->pw_name, pw->pw_gid);
385 if (geteuid() != getuid())
387 if (geteuid() != getuid())
396 const char *executable = arglist[0];
397 if (!d->executable.isEmpty())
398 executable = d->executable.data();
399 execvp(executable, arglist);
402 write(fd[1], &resultByte, 1);
404 }
else if (
pid_ == -1) {
416 kdDebug(175) <<
"Could not finish comm setup in parent!" <<
endl;
423 int n = ::read(fd[0], &resultByte, 1);
512 # define timersub(a, b, result) \
514 (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
515 (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \
516 if ((result)->tv_usec < 0) { \
517 --(result)->tv_sec; \
518 (result)->tv_usec += 1000000; \
531 struct timeval tv, *tvp;
537 gettimeofday(&etv, 0);
538 etv.tv_sec += timeout;
557 gettimeofday(&tv, 0);
558 timersub(&etv, &tv, &tv);
560 tv.tv_sec = tv.tv_usec = 0;
564 switch( select( fd+1, &fds, 0, 0, tvp ) )
613 return WEXITSTATUS(
status);
635 innot->setEnabled(
true);
646 outnot->setEnabled(
false);
661 if (!(d->usePty & Stdin))
675 if (!(d->usePty & Stdout))
689 if (!(d->usePty & Stderr))
700 if (d->pty && d->pty->masterFd() >= 0) {
743 innot->setEnabled(
false);
752 else if ((errno != EAGAIN) && (errno != EINTR))
754 kdDebug(175) <<
"Error writing to stdin of child process" <<
endl;
762 d->useShell = useShell;
767 #if !defined(__linux__) && !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__) && !defined(__GNU__) && !defined(__DragonFly__)
769 if (!access(
"/usr/xpg4/bin/sh", X_OK ))
770 d->shell =
"/usr/xpg4/bin/sh";
773 if (!access(
"/bin/ksh", X_OK ))
774 d->shell =
"/bin/ksh";
777 if (!access(
"/usr/ucb/sh", X_OK ))
778 d->shell =
"/usr/ucb/sh";
781 d->shell =
"/bin/sh";
788 d->addUtmp = addUtmp;
807 return TQString(arg).replace(q,
"'\\''").prepend(q).append(q);
844 len = ::read(fdno, buffer, 1024);
859 len = ::read(fdno, buffer, 1024);
876 if (!(~(comm & d->usePty) & (Stdout | Stderr))) {
877 kdWarning(175) <<
"Invalid usePty/communication combination (" << d->usePty <<
"/" << comm <<
")" <<
endl;
883 int rcomm = comm & d->usePty;
884 int mfd = d->pty->masterFd();
897 if (socketpair(AF_UNIX, SOCK_STREAM, 0,
in))
899 fcntl(
in[0], F_SETFD, FD_CLOEXEC);
900 fcntl(
in[1], F_SETFD, FD_CLOEXEC);
903 if (socketpair(AF_UNIX, SOCK_STREAM, 0,
out))
905 fcntl(
out[0], F_SETFD, FD_CLOEXEC);
906 fcntl(
out[1], F_SETFD, FD_CLOEXEC);
909 if (socketpair(AF_UNIX, SOCK_STREAM, 0,
err))
911 fcntl(
err[0], F_SETFD, FD_CLOEXEC);
912 fcntl(
err[1], F_SETFD, FD_CLOEXEC);
953 fcntl(
in[1], F_SETFL, O_NONBLOCK | fcntl(
in[1], F_GETFL));
954 innot =
new TQSocketNotifier(
in[1], TQSocketNotifier::Write,
this);
956 innot->setEnabled(
false);
957 TQObject::connect(
innot, TQ_SIGNAL(activated(
int)),
962 outnot =
new TQSocketNotifier(
out[0], TQSocketNotifier::Read,
this);
964 TQObject::connect(
outnot, TQ_SIGNAL(activated(
int)),
971 errnot =
new TQSocketNotifier(
err[0], TQSocketNotifier::Read,
this );
973 TQObject::connect(
errnot, TQ_SIGNAL(activated(
int)),
987 if (d->usePty & Stdin) {
988 if (dup2(d->pty->slaveFd(), STDIN_FILENO) < 0) ok = 0;
990 if (dup2(
in[0], STDIN_FILENO) < 0) ok = 0;
992 int null_fd = open(
"/dev/null", O_RDONLY );
993 if (dup2( null_fd, STDIN_FILENO ) < 0) ok = 0;
997 memset(&so, 0,
sizeof(so));
998 if (d->usePty & Stdout) {
999 if (dup2(d->pty->slaveFd(), STDOUT_FILENO) < 0) ok = 0;
1001 if (dup2(
out[1], STDOUT_FILENO) < 0 ||
1002 setsockopt(
out[1], SOL_SOCKET, SO_LINGER, (
char *)&so,
sizeof(so)))
1005 if (dup2(
out[1], STDERR_FILENO) < 0)
1009 if (d->usePty & Stderr) {
1010 if (dup2(d->pty->slaveFd(), STDERR_FILENO) < 0) ok = 0;
1012 if (dup2(
err[1], STDERR_FILENO) < 0 ||
1013 setsockopt(
err[1], SOL_SOCKET, SO_LINGER, (
char *)&so,
sizeof(so)))
1047 struct timeval timeout, *p_timeout;
1051 FD_SET(
out[0], &rfds);
1055 FD_SET(
err[0], &rfds);
1056 if (
err[0] > max_fd)
1060 FD_SET(notfd, &rfds);
1069 timeout.tv_sec = timeout.tv_usec = 0;
1070 p_timeout = &timeout;
1073 int fds_ready = select(max_fd+1, &rfds, 0, 0, p_timeout);
1074 if (fds_ready < 0) {
1078 }
else if (!fds_ready)
1087 if (
runs && FD_ISSET(notfd, &rfds)) {
1102 void TDEProcess::virtual_hook(
int,
void* )
1113 setUseShell(
true, shellname ? shellname : getenv(
"SHELL") );
1119 TQString KShellProcess::quote(
const TQString &arg)
1129 void KShellProcess::virtual_hook(
int id,
void* data )
1130 { TDEProcess::virtual_hook(
id, data ); }
1132 #include "kprocess.moc"
int in[2]
The socket descriptors for stdin.
void setupEnvironment()
Sets up the environment according to the data passed via setEnvironment()
bool closeStderr()
Shuts down the Stderr communication link.
void setUsePty(Communication comm, bool addUtmp)
Specify whether to create a pty (pseudo-terminal) for running the command.
bool writeStdin(const char *buffer, int buflen)
const char * input_data
The buffer holding the data that has to be sent to the child.
const TQValueList< TQCString > & args()
Lets you see what your arguments are for debugging.
void rescheduleCheck()
This function must be called at some point after calling unscheduleCheck().
bool keepPrivs
If false, the child process' effective uid & gid will be reset to the real values.
void closeAll()
Close stdin, stdout, stderr and the pty.
Communication
Modes in which the communication channel can be opened.
TQValueList< TQCString > arguments
The list of the process' command line arguments.
bool runPrivileged() const
Returns whether the started process will drop any setuid/setgid privileges or whether it will keep th...
void setUseShell(bool useShell, const char *shell=0)
Specify whether to start the command via a shell or directly.
bool normalExit() const
Checks whether the process exited cleanly.
bool signalled() const
Checks whether the process was killed by a signal.
RunMode run_mode
How to run the process (Block, NotifyOnExit, DontCare).
TDEProcess & operator<<(const TQString &arg)
Sets the executable and the command line argument list for this process.
virtual void commClose()
Cleans up the communication links to the child after it has exited.
bool closeStdout()
Shuts down the Stdout communication link.
void resume()
Resume processing of data from stdout of the child process.
virtual ~TDEProcess()
Destructor:
void setBinaryExecutable(const char *filename)
Specify the actual executable that should be started (first argument to execve) Normally the the firs...
@ NotifyOnExit
The application is notified when the subprocess dies.
kndbgstream & endl(kndbgstream &s)
Does nothing.
bool coreDumped() const
Checks whether a killed process dumped core.
int childOutput(int fdno)
Called by slotChildOutput() this function copies data arriving from the child process' stdout to the ...
void slotChildError(int fdno)
This slot gets activated when data from the child's stderr arrives.
Provides a high level representation of a pseudo tty pair, including utmp support.
pid_t pid_
The PID of the currently running process.
bool runs
true if the process is currently running.
static TDEProcessController * theTDEProcessController
Only a single instance of this class is allowed at a time, and this static variable is used to track ...
bool isRunning() const
Checks whether the process is running.
virtual int commSetupDoneC()
Called right after a (successful) fork(), but before an exec() on the child process' side.
virtual void processHasExited(int state)
Immediately called after a successfully started process in NotifyOnExit mode has exited.
bool closePty()
Deletes the optional utmp entry and closes the pty.
void processExited(TDEProcess *proc)
Emitted after the process has terminated when the process was run in the NotifyOnExit (==default opti...
void slotChildOutput(int fdno)
This slot gets activated when data from the child's stdout arrives.
@ Block
The application is suspended until the started process is finished.
void suspend()
Suspend processing of data from stdout of the child process.
KShellProcess(const char *shellname=0)
Constructor.
~KShellProcess()
Destructor.
void unscheduleCheck()
Call this function to defer processing of the data that became available on notifierFd().
void setWorkingDirectory(const TQString &dir)
Changes the current working directory (CWD) of the process to be started.
pid_t pid() const
Returns the process id of the process.
int input_total
The total length of input_data.
void receivedStderr(TDEProcess *proc, char *buffer, int buflen)
Emitted, when output from the child process has been received on stderr.
virtual int commSetupDoneP()
Called right after a (successful) fork() on the parent side.
bool closeStdin()
Shuts down the Stdin communication link.
int out[2]
The socket descriptors for stdout.
void setEnvironment(const TQString &name, const TQString &value)
Adds the variable name to the process' environment.
KPty * pty() const
Obtains the pty object used by this process.
virtual bool start(RunMode runmode=NotifyOnExit, Communication comm=NoCommunication)
Starts the process.
static void ref()
Create an instance if none exists yet.
void receivedStdout(TDEProcess *proc, char *buffer, int buflen)
Emitted, when output from the child process has been received on stdout.
Represents a user on your system.
bool wait(int timeout=-1)
Suspend execution of the current thread until the child process dies or the timeout hits.
void detach()
Detaches TDEProcess from child process.
void wroteStdin(TDEProcess *proc)
Emitted after all the data that has been specified by a prior call to writeStdin() has actually been ...
int exitSignal() const
Returns the signal the process was killed by.
Child process invocation, monitoring and control.
Communication communication
Lists the communication links that are activated for the child process.
virtual bool start(RunMode runmode=NotifyOnExit, Communication comm=NoCommunication)
Starts the process.
virtual bool kill(int signo=SIGTERM)
Stop the process (by sending it a signal).
int err[2]
The socket descriptors for stderr.
int input_sent
The number of bytes already transmitted.
void slotSendData(int dummy)
Called when another bulk of data can be sent to the child's stdin.
@ OwnGroup
Same as NotifyOnExit, but the process is run in an own session, just like with DontCare.
static void deref()
Destroy the instance if one exists and it is not referenced any more.
static TQString quote(const TQString &arg)
This function can be used to quote an argument string such that the shell processes it properly.
int exitStatus() const
Returns the exit status of the process.
virtual int setupCommunication(Communication comm)
This function is called from start() right before a fork() takes place.
void clearArguments()
Clear a command line argument list that has been set by using operator<<.
int status
The process' exit status as returned by waitpid().
TQSocketNotifier * innot
The socket notifier for in[1].
TQSocketNotifier * outnot
The socket notifier for out[0].
@ DontCare
The application does not receive notifications from the subprocess when it is finished or aborted.
TQSocketNotifier * errnot
The socket notifier for err[0].
RunMode
Run-modes for a child process.
bool setExecutable(const TQString &proc) TDE_DEPRECATED
@ UseRealUserID
Use the real user id.
int childError(int fdno)
Called by slotChildError() this function copies data arriving from the child process' stderr to the r...
bool setPriority(int prio)
Sets the scheduling priority of the process.
void setRunPrivileged(bool keepPrivileges)
Controls whether the started process should drop any setuid/setgid privileges or whether it should ke...