26 #include "kprocctrl.h"
45 #include <sys/socket.h>
46 #include <sys/ioctl.h>
49 #include <sys/types.h>
51 #include <sys/resource.h>
55 #ifdef HAVE_SYS_STROPTS_H
56 #include <sys/stropts.h>
59 #ifdef HAVE_SYS_SELECT_H
60 #include <sys/select.h>
76 #include <tqsocketnotifier.h>
77 #include <tqapplication.h>
80 #include <kstandarddirs.h>
88 class TDEProcessPrivate {
92 addUtmp(false), useShell(false),
110 TQMap<TQString,TQString> env;
113 TQCString executable;
121 : TQObject( parent, name ),
122 run_mode(NotifyOnExit),
130 communication(NoCommunication),
138 d =
new TDEProcessPrivate;
147 run_mode(NotifyOnExit),
155 communication(NoCommunication),
163 d =
new TDEProcessPrivate;
173 d->env.insert(name, value);
185 TQMap<TQString,TQString>::Iterator it;
186 for(it = d->env.begin(); it != d->env.end(); ++it)
188 setenv(TQFile::encodeName(it.key()).data(),
189 TQFile::encodeName(it.data()).data(), 1);
191 if (!d->wd.isEmpty())
193 chdir(TQFile::encodeName(d->wd).data());
214 if (setpriority(PRIO_PROCESS,
pid_, prio))
217 if (prio > 19 || prio < (geteuid() ? getpriority(PRIO_PROCESS, 0) : -20))
252 d->executable = filename;
257 if (
runs)
return false;
259 if (proc.isEmpty())
return false;
263 arguments.prepend(TQFile::encodeName(proc));
270 TQStringList::ConstIterator it =
args.begin();
271 for ( ; it !=
args.end() ; ++it )
272 arguments.append(TQFile::encodeName(*it));
289 arguments.append(TQFile::encodeName(arg));
301 kdDebug(175) <<
"Attempted to start an already running process" <<
endl;
307 kdDebug(175) <<
"Attempted to start a process without arguments" <<
endl;
315 if (d->shell.isEmpty()) {
316 kdDebug(175) <<
"Invalid shell specified" <<
endl;
320 for (uint i = 0; i < n; i++) {
325 arglist =
static_cast<char **
>(malloc( 4 *
sizeof(
char *)));
326 arglist[0] = d->shell.data();
327 arglist[1] = (
char *)
"-c";
328 arglist[2] = shellCmd.data();
333 arglist =
static_cast<char **
>(malloc( (n + 1) *
sizeof(
char *)));
334 for (uint i = 0; i < n; i++)
343 kdDebug(175) <<
"Could not setup Communication!" <<
endl;
350 #ifdef HAVE_INITGROUPS
351 struct passwd *pw = geteuid() ? 0 : getpwuid(getuid());
367 fcntl(fd[1], F_SETFD, FD_CLOEXEC);
370 kdDebug(175) <<
"Could not finish comm setup in child!" <<
endl;
373 struct sigaction act;
374 sigemptyset(&act.sa_mask);
375 act.sa_handler = SIG_DFL;
377 for (
int sig = 1; sig < NSIG; sig++)
378 sigaction(sig, &act, 0L);
381 setpriority(PRIO_PROCESS, 0, d->priority);
386 #ifdef HAVE_INITGROUPS
388 initgroups(pw->pw_name, pw->pw_gid);
390 if (geteuid() != getuid())
392 if (geteuid() != getuid())
401 const char *executable = arglist[0];
402 if (!d->executable.isEmpty())
403 executable = d->executable.data();
404 execvp(executable, arglist);
407 write(fd[1], &resultByte, 1);
409 }
else if (
pid_ == -1) {
421 kdDebug(175) <<
"Could not finish comm setup in parent!" <<
endl;
428 int n = ::read(fd[0], &resultByte, 1);
517 # define timersub(a, b, result) \
519 (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
520 (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \
521 if ((result)->tv_usec < 0) { \
522 --(result)->tv_sec; \
523 (result)->tv_usec += 1000000; \
536 struct timeval tv, *tvp;
542 gettimeofday(&etv, 0);
543 etv.tv_sec += timeout;
562 gettimeofday(&tv, 0);
563 timersub(&etv, &tv, &tv);
565 tv.tv_sec = tv.tv_usec = 0;
569 switch( select( fd+1, &fds, 0, 0, tvp ) )
618 return WEXITSTATUS(
status);
640 innot->setEnabled(
true);
651 outnot->setEnabled(
false);
666 if (!(d->usePty & Stdin))
680 if (!(d->usePty & Stdout))
694 if (!(d->usePty & Stderr))
705 if (d->pty && d->pty->masterFd() >= 0) {
748 innot->setEnabled(
false);
757 else if ((errno != EAGAIN) && (errno != EINTR))
759 kdDebug(175) <<
"Error writing to stdin of child process" <<
endl;
767 d->useShell = useShell;
772 #if !defined(__linux__) && !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__) && !defined(__GNU__) && !defined(__DragonFly__)
774 if (!access(
"/usr/xpg4/bin/sh", X_OK ))
775 d->shell =
"/usr/xpg4/bin/sh";
778 if (!access(
"/bin/ksh", X_OK ))
779 d->shell =
"/bin/ksh";
782 if (!access(
"/usr/ucb/sh", X_OK ))
783 d->shell =
"/usr/ucb/sh";
786 d->shell =
"/bin/sh";
793 d->addUtmp = addUtmp;
812 return TQString(arg).replace(q,
"'\\''").prepend(q).append(q);
849 len = ::read(fdno, buffer, 1024);
864 len = ::read(fdno, buffer, 1024);
881 if (!(~(comm & d->usePty) & (Stdout | Stderr))) {
882 kdWarning(175) <<
"Invalid usePty/communication combination (" << d->usePty <<
"/" << comm <<
")" <<
endl;
888 int rcomm = comm & d->usePty;
889 int mfd = d->pty->masterFd();
902 if (socketpair(AF_UNIX, SOCK_STREAM, 0,
in))
904 fcntl(
in[0], F_SETFD, FD_CLOEXEC);
905 fcntl(
in[1], F_SETFD, FD_CLOEXEC);
908 if (socketpair(AF_UNIX, SOCK_STREAM, 0,
out))
910 fcntl(
out[0], F_SETFD, FD_CLOEXEC);
911 fcntl(
out[1], F_SETFD, FD_CLOEXEC);
914 if (socketpair(AF_UNIX, SOCK_STREAM, 0,
err))
916 fcntl(
err[0], F_SETFD, FD_CLOEXEC);
917 fcntl(
err[1], F_SETFD, FD_CLOEXEC);
958 fcntl(
in[1], F_SETFL, O_NONBLOCK | fcntl(
in[1], F_GETFL));
959 innot =
new TQSocketNotifier(
in[1], TQSocketNotifier::Write,
this);
961 innot->setEnabled(
false);
962 TQObject::connect(
innot, TQ_SIGNAL(activated(
int)),
967 outnot =
new TQSocketNotifier(
out[0], TQSocketNotifier::Read,
this);
969 TQObject::connect(
outnot, TQ_SIGNAL(activated(
int)),
976 errnot =
new TQSocketNotifier(
err[0], TQSocketNotifier::Read,
this );
978 TQObject::connect(
errnot, TQ_SIGNAL(activated(
int)),
992 if (d->usePty & Stdin) {
993 if (dup2(d->pty->slaveFd(), STDIN_FILENO) < 0) ok = 0;
995 if (dup2(
in[0], STDIN_FILENO) < 0) ok = 0;
997 int null_fd = open(
"/dev/null", O_RDONLY );
998 if (dup2( null_fd, STDIN_FILENO ) < 0) ok = 0;
1002 memset(&so, 0,
sizeof(so));
1003 if (d->usePty & Stdout) {
1004 if (dup2(d->pty->slaveFd(), STDOUT_FILENO) < 0) ok = 0;
1006 if (dup2(
out[1], STDOUT_FILENO) < 0 ||
1007 setsockopt(
out[1], SOL_SOCKET, SO_LINGER, (
char *)&so,
sizeof(so)))
1010 if (dup2(
out[1], STDERR_FILENO) < 0)
1014 if (d->usePty & Stderr) {
1015 if (dup2(d->pty->slaveFd(), STDERR_FILENO) < 0) ok = 0;
1017 if (dup2(
err[1], STDERR_FILENO) < 0 ||
1018 setsockopt(
err[1], SOL_SOCKET, SO_LINGER, (
char *)&so,
sizeof(so)))
1052 struct timeval timeout, *p_timeout;
1056 FD_SET(
out[0], &rfds);
1060 FD_SET(
err[0], &rfds);
1061 if (
err[0] > max_fd)
1065 FD_SET(notfd, &rfds);
1074 timeout.tv_sec = timeout.tv_usec = 0;
1075 p_timeout = &timeout;
1078 int fds_ready = select(max_fd+1, &rfds, 0, 0, p_timeout);
1079 if (fds_ready < 0) {
1083 }
else if (!fds_ready)
1092 if (
runs && FD_ISSET(notfd, &rfds)) {
1107 void TDEProcess::virtual_hook(
int,
void* )
1118 setUseShell(
true, shellname ? shellname : getenv(
"SHELL") );
1124 TQString KShellProcess::quote(
const TQString &arg)
1134 void KShellProcess::virtual_hook(
int id,
void* data )
1135 { TDEProcess::virtual_hook(
id, data ); }
1137 #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...