25#include "tdeprocess.h"
26#include "tdeprocctrl.h"
36#include <sys/socket.h>
42#include <sys/resource.h>
46#ifdef HAVE_SYS_STROPTS_H
47#include <sys/stropts.h>
50#ifdef HAVE_SYS_SELECT_H
51#include <sys/select.h>
67#include <tqsocketnotifier.h>
68#include <tqapplication.h>
71#include <tdestandarddirs.h>
79class TDEProcessPrivate {
83 addUtmp(false), useShell(false),
101 TQMap<TQString,TQString> env;
104 TQCString executable;
112 : TQObject( parent, name ),
113 run_mode(NotifyOnExit),
121 communication(NoCommunication),
129 d =
new TDEProcessPrivate;
138 run_mode(NotifyOnExit),
146 communication(NoCommunication),
154 d =
new TDEProcessPrivate;
164 d->env.insert(name, value);
176 TQMap<TQString,TQString>::Iterator it;
177 for(it = d->env.begin(); it != d->env.end(); ++it)
179 setenv(TQFile::encodeName(it.key()).data(),
180 TQFile::encodeName(it.data()).data(), 1);
182 if (!d->wd.isEmpty())
184 chdir(TQFile::encodeName(d->wd).data());
205 if (setpriority(PRIO_PROCESS,
pid_, prio))
208 if (prio > 19 || prio < (geteuid() ? getpriority(PRIO_PROCESS, 0) : -20))
243 d->executable = filename;
248 if (
runs)
return false;
250 if (proc.isEmpty())
return false;
254 arguments.prepend(TQFile::encodeName(proc));
261 TQStringList::ConstIterator it =
args.begin();
262 for ( ; it !=
args.end() ; ++it )
263 arguments.append(TQFile::encodeName(*it));
280 arguments.append(TQFile::encodeName(arg));
292 kdDebug(175) <<
"Attempted to start an already running process" <<
endl;
298 kdDebug(175) <<
"Attempted to start a process without arguments" <<
endl;
306 if (d->shell.isEmpty()) {
307 kdDebug(175) <<
"Invalid shell specified" <<
endl;
311 for (uint i = 0; i < n; i++) {
316 arglist =
static_cast<char **
>(malloc( 4 *
sizeof(
char *)));
317 arglist[0] = d->shell.data();
318 arglist[1] = (
char *)
"-c";
319 arglist[2] = shellCmd.data();
324 arglist =
static_cast<char **
>(malloc( (n + 1) *
sizeof(
char *)));
325 for (uint i = 0; i < n; i++)
334 kdDebug(175) <<
"Could not setup Communication!" <<
endl;
341#ifdef HAVE_INITGROUPS
342 struct passwd *pw = geteuid() ? 0 : getpwuid(getuid());
358 fcntl(fd[1], F_SETFD, FD_CLOEXEC);
361 kdDebug(175) <<
"Could not finish comm setup in child!" <<
endl;
364 struct sigaction act;
365 sigemptyset(&act.sa_mask);
366 act.sa_handler = SIG_DFL;
368 for (
int sig = 1; sig < NSIG; sig++)
369 sigaction(sig, &act, 0L);
372 setpriority(PRIO_PROCESS, 0, d->priority);
377#ifdef HAVE_INITGROUPS
379 initgroups(pw->pw_name, pw->pw_gid);
381 if (geteuid() != getuid())
383 if (geteuid() != getuid())
392 const char *executable = arglist[0];
393 if (!d->executable.isEmpty())
394 executable = d->executable.data();
395 execvp(executable, arglist);
398 write(fd[1], &resultByte, 1);
400 }
else if (
pid_ == -1) {
412 kdDebug(175) <<
"Could not finish comm setup in parent!" <<
endl;
419 int n = ::read(fd[0], &resultByte, 1);
508# define timersub(a, b, result) \
510 (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
511 (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \
512 if ((result)->tv_usec < 0) { \
513 --(result)->tv_sec; \
514 (result)->tv_usec += 1000000; \
527 struct timeval tv, *tvp;
533 gettimeofday(&etv, 0);
534 etv.tv_sec += timeout;
553 gettimeofday(&tv, 0);
554 timersub(&etv, &tv, &tv);
556 tv.tv_sec = tv.tv_usec = 0;
560 switch( select( fd+1, &fds, 0, 0, tvp ) )
609 return WEXITSTATUS(
status);
631 innot->setEnabled(
true);
642 outnot->setEnabled(
false);
657 if (!(d->usePty & Stdin))
671 if (!(d->usePty & Stdout))
685 if (!(d->usePty & Stderr))
696 if (d->pty && d->pty->masterFd() >= 0) {
739 innot->setEnabled(
false);
748 else if ((errno != EAGAIN) && (errno != EINTR))
750 kdDebug(175) <<
"Error writing to stdin of child process" <<
endl;
758 d->useShell = useShell;
763#if !defined(__linux__) && !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__) && !defined(__GNU__) && !defined(__DragonFly__)
765 if (!access(
"/usr/xpg4/bin/sh", X_OK ))
766 d->shell =
"/usr/xpg4/bin/sh";
769 if (!access(
"/bin/ksh", X_OK ))
770 d->shell =
"/bin/ksh";
773 if (!access(
"/usr/ucb/sh", X_OK ))
774 d->shell =
"/usr/ucb/sh";
777 d->shell =
"/bin/sh";
784 d->addUtmp = addUtmp;
803 return TQString(arg).replace(q,
"'\\''").prepend(q).append(q);
840 len = ::read(fdno, buffer, 1024);
855 len = ::read(fdno, buffer, 1024);
872 if (!(~(comm & d->usePty) & (Stdout | Stderr))) {
873 kdWarning(175) <<
"Invalid usePty/communication combination (" << d->usePty <<
"/" << comm <<
")" <<
endl;
879 int rcomm = comm & d->usePty;
880 int mfd = d->pty->masterFd();
893 if (socketpair(AF_UNIX, SOCK_STREAM, 0,
in))
895 fcntl(
in[0], F_SETFD, FD_CLOEXEC);
896 fcntl(
in[1], F_SETFD, FD_CLOEXEC);
899 if (socketpair(AF_UNIX, SOCK_STREAM, 0,
out))
901 fcntl(
out[0], F_SETFD, FD_CLOEXEC);
902 fcntl(
out[1], F_SETFD, FD_CLOEXEC);
905 if (socketpair(AF_UNIX, SOCK_STREAM, 0,
err))
907 fcntl(
err[0], F_SETFD, FD_CLOEXEC);
908 fcntl(
err[1], F_SETFD, FD_CLOEXEC);
949 fcntl(
in[1], F_SETFL, O_NONBLOCK | fcntl(
in[1], F_GETFL));
950 innot =
new TQSocketNotifier(
in[1], TQSocketNotifier::Write,
this);
952 innot->setEnabled(
false);
953 TQObject::connect(
innot, TQ_SIGNAL(activated(
int)),
958 outnot =
new TQSocketNotifier(
out[0], TQSocketNotifier::Read,
this);
960 TQObject::connect(
outnot, TQ_SIGNAL(activated(
int)),
967 errnot =
new TQSocketNotifier(
err[0], TQSocketNotifier::Read,
this );
969 TQObject::connect(
errnot, TQ_SIGNAL(activated(
int)),
983 if (d->usePty & Stdin) {
984 if (dup2(d->pty->slaveFd(), STDIN_FILENO) < 0) ok = 0;
986 if (dup2(
in[0], STDIN_FILENO) < 0) ok = 0;
988 int null_fd = open(
"/dev/null", O_RDONLY );
989 if (dup2( null_fd, STDIN_FILENO ) < 0) ok = 0;
993 memset(&so, 0,
sizeof(so));
994 if (d->usePty & Stdout) {
995 if (dup2(d->pty->slaveFd(), STDOUT_FILENO) < 0) ok = 0;
997 if (dup2(
out[1], STDOUT_FILENO) < 0 ||
998 setsockopt(
out[1], SOL_SOCKET, SO_LINGER, (
char *)&so,
sizeof(so)))
1001 if (dup2(
out[1], STDERR_FILENO) < 0)
1005 if (d->usePty & Stderr) {
1006 if (dup2(d->pty->slaveFd(), STDERR_FILENO) < 0) ok = 0;
1008 if (dup2(
err[1], STDERR_FILENO) < 0 ||
1009 setsockopt(
err[1], SOL_SOCKET, SO_LINGER, (
char *)&so,
sizeof(so)))
1043 struct timeval timeout, *p_timeout;
1047 FD_SET(
out[0], &rfds);
1051 FD_SET(
err[0], &rfds);
1052 if (
err[0] > max_fd)
1056 FD_SET(notfd, &rfds);
1065 timeout.tv_sec = timeout.tv_usec = 0;
1066 p_timeout = &timeout;
1069 int fds_ready = select(max_fd+1, &rfds, 0, 0, p_timeout);
1070 if (fds_ready < 0) {
1074 }
else if (!fds_ready)
1083 if (
runs && FD_ISSET(notfd, &rfds)) {
1098void TDEProcess::virtual_hook(
int,
void* )
1109 setUseShell(
true, shellname ? shellname : getenv(
"SHELL") );
1115TQString KShellProcess::quote(
const TQString &arg)
1125void KShellProcess::virtual_hook(
int id,
void* data )
1126{ TDEProcess::virtual_hook(
id, data ); }
1128#include "tdeprocess.moc"
Provides a high level representation of a pseudo tty pair, including utmp support.
KShellProcess(const char *shellname=0)
Constructor.
virtual bool start(RunMode runmode=NotifyOnExit, Communication comm=NoCommunication)
Starts the process.
~KShellProcess()
Destructor.
Represents a user on your system.
@ UseRealUserID
Use the real user id.
static void deref()
Destroy the instance if one exists and it is not referenced any more.
static void ref()
Create an instance if none exists yet.
void rescheduleCheck()
This function must be called at some point after calling unscheduleCheck().
static TDEProcessController * theTDEProcessController
Only a single instance of this class is allowed at a time, and this static variable is used to track ...
void unscheduleCheck()
Call this function to defer processing of the data that became available on notifierFd().
Child process invocation, monitoring and control.
int status
The process' exit status as returned by waitpid().
TDEProcess & operator<<(const TQString &arg)
Sets the executable and the command line argument list for this process.
pid_t pid_
The PID of the currently running process.
TQSocketNotifier * outnot
The socket notifier for out[0].
virtual void processHasExited(int state)
Immediately called after a successfully started process in NotifyOnExit mode has exited.
bool isRunning() const
Checks whether the process is running.
bool closePty()
Deletes the optional utmp entry and closes the pty.
int out[2]
The socket descriptors for stdout.
virtual int commSetupDoneC()
Called right after a (successful) fork(), but before an exec() on the child process' side.
const TQValueList< TQCString > & args()
Lets you see what your arguments are for debugging.
pid_t pid() const
Returns the process id of the process.
virtual int commSetupDoneP()
Called right after a (successful) fork() on the parent side.
Communication communication
Lists the communication links that are activated for the child process.
bool runs
true if the process is currently running.
int in[2]
The socket descriptors for stdin.
virtual bool start(RunMode runmode=NotifyOnExit, Communication comm=NoCommunication)
Starts the process.
int exitStatus() const
Returns the exit status of the process.
int childError(int fdno)
Called by slotChildError() this function copies data arriving from the child process' stderr to the r...
void suspend()
Suspend processing of data from stdout of the child process.
int input_sent
The number of bytes already transmitted.
void processExited(TDEProcess *proc)
Emitted after the process has terminated when the process was run in the NotifyOnExit (==default opti...
bool keepPrivs
If false, the child process' effective uid & gid will be reset to the real values.
void clearArguments()
Clear a command line argument list that has been set by using operator<<.
virtual bool kill(int signo=SIGTERM)
Stop the process (by sending it a signal).
bool wait(int timeout=-1)
Suspend execution of the current thread until the child process dies or the timeout hits.
static TQString quote(const TQString &arg)
This function can be used to quote an argument string such that the shell processes it properly.
void setEnvironment(const TQString &name, const TQString &value)
Adds the variable name to the process' environment.
RunMode
Run-modes for a child process.
@ OwnGroup
Same as NotifyOnExit, but the process is run in an own session, just like with DontCare.
@ DontCare
The application does not receive notifications from the subprocess when it is finished or aborted.
@ NotifyOnExit
The application is notified when the subprocess dies.
@ Block
The application is suspended until the started process is finished.
void setupEnvironment()
Sets up the environment according to the data passed via setEnvironment()
Communication
Modes in which the communication channel can be opened.
void slotSendData(int dummy)
Called when another bulk of data can be sent to the child's stdin.
void detach()
Detaches TDEProcess from child process.
TQValueList< TQCString > arguments
The list of the process' command line arguments.
void setUsePty(Communication comm, bool addUtmp)
Specify whether to create a pty (pseudo-terminal) for running the command.
RunMode run_mode
How to run the process (Block, NotifyOnExit, DontCare).
int childOutput(int fdno)
Called by slotChildOutput() this function copies data arriving from the child process' stdout to the ...
bool writeStdin(const char *buffer, int buflen)
virtual void commClose()
Cleans up the communication links to the child after it has exited.
int input_total
The total length of input_data.
int exitSignal() const
Returns the signal the process was killed by.
void resume()
Resume processing of data from stdout of the child process.
void setWorkingDirectory(const TQString &dir)
Changes the current working directory (CWD) of the process to be started.
virtual int setupCommunication(Communication comm)
This function is called from start() right before a fork() takes place.
void slotChildError(int fdno)
This slot gets activated when data from the child's stderr arrives.
TQSocketNotifier * errnot
The socket notifier for err[0].
bool closeStderr()
Shuts down the Stderr communication link.
TQSocketNotifier * innot
The socket notifier for in[1].
void slotChildOutput(int fdno)
This slot gets activated when data from the child's stdout arrives.
const char * input_data
The buffer holding the data that has to be sent to the child.
bool setPriority(int prio)
Sets the scheduling priority of the process.
void receivedStderr(TDEProcess *proc, char *buffer, int buflen)
Emitted, when output from the child process has been received on stderr.
bool signalled() const
Checks whether the process was killed by a signal.
void wroteStdin(TDEProcess *proc)
Emitted after all the data that has been specified by a prior call to writeStdin() has actually been ...
virtual ~TDEProcess()
Destructor:
void closeAll()
Close stdin, stdout, stderr and the pty.
int err[2]
The socket descriptors for stderr.
bool closeStdout()
Shuts down the Stdout communication link.
bool setExecutable(const TQString &proc) TDE_DEPRECATED
bool closeStdin()
Shuts down the Stdin communication link.
bool coreDumped() const
Checks whether a killed process dumped core.
void setUseShell(bool useShell, const char *shell=0)
Specify whether to start the command via a shell or directly.
void setRunPrivileged(bool keepPrivileges)
Controls whether the started process should drop any setuid/setgid privileges or whether it should ke...
bool normalExit() const
Checks whether the process exited cleanly.
bool runPrivileged() const
Returns whether the started process will drop any setuid/setgid privileges or whether it will keep th...
void setBinaryExecutable(const char *filename)
Specify the actual executable that should be started (first argument to execve) Normally the the firs...
void receivedStdout(TDEProcess *proc, char *buffer, int buflen)
Emitted, when output from the child process has been received on stdout.
KPty * pty() const
Obtains the pty object used by this process.
kndbgstream & endl(kndbgstream &s)
Does nothing.