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, TQT_SIGNAL(activated(
int)),
967 outnot =
new TQSocketNotifier(
out[0], TQSocketNotifier::Read,
this);
969 TQObject::connect(
outnot, TQT_SIGNAL(activated(
int)),
976 errnot =
new TQSocketNotifier(
err[0], TQSocketNotifier::Read,
this );
978 TQObject::connect(
errnot, TQT_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") );
1134 void KShellProcess::virtual_hook(
int id,
void* data )
1135 { TDEProcess::virtual_hook(
id, data ); }
1137 #include "kprocess.moc"