26 #include "kpty/kpty.h"
37 #include <sys/socket.h>
38 #include <sys/ioctl.h>
40 #include <sys/types.h>
42 #include <sys/resource.h>
46 #ifdef HAVE_SYS_SELECT_H
47 #include <sys/select.h>
62 #include <QtCore/QMap>
63 #include <QtCore/QFile>
64 #include <QtCore/QSocketNotifier>
75 class K3ProcessPrivate {
79 addUtmp(false), useShell(false),
85 K3Process::Communication usePty;
96 QByteArray executable;
105 run_mode(NotifyOnExit),
113 communication(NoCommunication),
117 d(new K3ProcessPrivate)
131 d->env.insert(name, value);
144 for(it = d->env.begin(); it != d->env.end(); ++it)
146 setenv(QFile::encodeName(it.key()).data(),
147 QFile::encodeName(it.value()).data(), 1);
149 if (!d->wd.isEmpty())
151 chdir(QFile::encodeName(d->wd).data());
171 if (setpriority(PRIO_PROCESS,
pid_, prio))
174 if (prio > 19 || prio < (geteuid() ? getpriority(PRIO_PROCESS, 0) : -20))
206 d->executable = filename;
211 QStringList::ConstIterator it = args.begin();
212 for ( ; it != args.end() ; ++it )
213 arguments.append(QFile::encodeName(*it));
230 arguments.append(QFile::encodeName(arg));
242 kDebug(175) <<
"Attempted to start an already running process" << endl;
248 kDebug(175) <<
"Attempted to start a process without arguments" << endl;
255 if (d->shell.isEmpty()) {
256 kDebug(175) <<
"Invalid shell specified" << endl;
260 for (uint i = 0; i < n; i++) {
265 arglist =
static_cast<char **
>(malloc( 4 *
sizeof(
char *)));
266 arglist[0] = d->shell.data();
267 arglist[1] = (
char *)
"-c";
268 arglist[2] = shellCmd.data();
273 arglist =
static_cast<char **
>(malloc( (n + 1) *
sizeof(
char *)));
274 for (uint i = 0; i < n; i++)
283 kDebug(175) <<
"Could not setup Communication!" << endl;
290 #ifdef HAVE_INITGROUPS
291 struct passwd *pw = geteuid() ? 0 : getpwuid(getuid());
307 fcntl(fd[1], F_SETFD, FD_CLOEXEC);
310 kDebug(175) <<
"Could not finish comm setup in child!" << endl;
313 struct sigaction act;
314 sigemptyset(&act.sa_mask);
315 act.sa_handler = SIG_DFL;
317 for (
int sig = 1; sig < NSIG; sig++)
318 sigaction(sig, &act, 0L);
321 setpriority(PRIO_PROCESS, 0, d->priority);
326 #ifdef HAVE_INITGROUPS
328 initgroups(pw->pw_name, pw->pw_gid);
330 if (geteuid() != getuid())
332 if (geteuid() != getuid())
341 const char *executable = arglist[0];
342 if (!d->executable.isEmpty())
343 executable = d->executable.data();
344 execvp(executable, arglist);
347 write(fd[1], &resultByte, 1);
349 }
else if (
pid_ == -1) {
361 kDebug(175) <<
"Could not finish comm setup in parent!" << endl;
368 int n = ::read(fd[0], &resultByte, 1);
451 # define timersub(a, b, result) \
453 (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
454 (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \
455 if ((result)->tv_usec < 0) { \
456 --(result)->tv_sec; \
457 (result)->tv_usec += 1000000; \
470 struct timeval tv, *tvp;
476 gettimeofday(&etv, 0);
477 etv.tv_sec += timeout;
495 gettimeofday(&tv, 0);
498 tv.tv_sec = tv.tv_usec = 0;
502 switch( select( fd+1, &fds, 0, 0, tvp ) )
550 return WEXITSTATUS(
status);
572 innot->setEnabled(
true);
583 outnot->setEnabled(
false);
598 if (!(d->usePty & Stdin))
612 if (!(d->usePty & Stdout))
626 if (!(d->usePty & Stderr))
636 if (d->pty && d->pty->masterFd() >= 0) {
676 innot->setEnabled(
false);
685 else if ((errno != EAGAIN) && (errno != EINTR))
687 kDebug(175) <<
"Error writing to stdin of child process" << endl;
695 d->useShell = useShell;
700 #if !defined(__linux__) && !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__) && !defined(__GNU__) && !defined(__DragonFly__)
702 if (!
access(
"/usr/xpg4/bin/sh", X_OK ))
703 d->shell =
"/usr/xpg4/bin/sh";
706 if (!
access(
"/bin/ksh", X_OK ))
707 d->shell =
"/bin/ksh";
710 if (!
access(
"/usr/ucb/sh", X_OK ))
711 d->shell =
"/usr/ucb/sh";
714 d->shell =
"/bin/sh";
720 d->addUtmp = addUtmp;
738 return QString(arg).replace(q,
"'\\''").prepend(q).append(q);
775 len = ::read(fdno, buffer, 1024);
790 len = ::read(fdno, buffer, 1024);
807 kWarning(175) <<
"Invalid usePty/communication combination (" << d->usePty <<
"/" << comm <<
")" << endl;
813 int rcomm = comm & d->usePty;
814 int mfd = d->pty->masterFd();
825 comm = comm & ~d->usePty;
827 if (socketpair(AF_UNIX, SOCK_STREAM, 0,
in))
829 fcntl(
in[0], F_SETFD, FD_CLOEXEC);
830 fcntl(
in[1], F_SETFD, FD_CLOEXEC);
833 if (socketpair(AF_UNIX, SOCK_STREAM, 0,
out))
835 fcntl(
out[0], F_SETFD, FD_CLOEXEC);
836 fcntl(
out[1], F_SETFD, FD_CLOEXEC);
839 if (socketpair(AF_UNIX, SOCK_STREAM, 0,
err))
841 fcntl(
err[0], F_SETFD, FD_CLOEXEC);
842 fcntl(
err[1], F_SETFD, FD_CLOEXEC);
882 fcntl(
in[1], F_SETFL, O_NONBLOCK | fcntl(
in[1], F_GETFL));
883 innot =
new QSocketNotifier(
in[1], QSocketNotifier::Write,
this);
885 innot->setEnabled(
false);
886 QObject::connect(
innot, SIGNAL(activated(
int)),
891 outnot =
new QSocketNotifier(
out[0], QSocketNotifier::Read,
this);
893 QObject::connect(
outnot, SIGNAL(activated(
int)),
900 errnot =
new QSocketNotifier(
err[0], QSocketNotifier::Read,
this );
902 QObject::connect(
errnot, SIGNAL(activated(
int)),
915 if (d->usePty &
Stdin) {
916 if (dup2(d->pty->slaveFd(), STDIN_FILENO) < 0) ok = 0;
918 if (dup2(
in[0], STDIN_FILENO) < 0) ok = 0;
920 int null_fd =
open(
"/dev/null", O_RDONLY );
921 if (dup2( null_fd, STDIN_FILENO ) < 0) ok = 0;
925 memset(&so, 0,
sizeof(so));
927 if (dup2(d->pty->slaveFd(), STDOUT_FILENO) < 0) ok = 0;
929 if (dup2(
out[1], STDOUT_FILENO) < 0 ||
930 setsockopt(
out[1], SOL_SOCKET, SO_LINGER, (
char *)&so,
sizeof(so)))
933 if (dup2(
out[1], STDERR_FILENO) < 0)
938 if (dup2(d->pty->slaveFd(), STDERR_FILENO) < 0) ok = 0;
940 if (dup2(
err[1], STDERR_FILENO) < 0 ||
941 setsockopt(
err[1], SOL_SOCKET, SO_LINGER, (
char *)&so,
sizeof(so)))
973 struct timeval timeout, *p_timeout;
977 FD_SET(
out[0], &rfds);
981 FD_SET(
err[0], &rfds);
986 FD_SET(notfd, &rfds);
995 timeout.tv_sec = timeout.tv_usec = 0;
996 p_timeout = &timeout;
999 int fds_ready = select(max_fd+1, &rfds, 0, 0, p_timeout);
1000 if (fds_ready < 0) {
1004 }
else if (!fds_ready)
1013 if (
runs && FD_ISSET(notfd, &rfds)) {
1035 setUseShell(
true, shellname ? shellname : getenv(
"SHELL") );
1052 #include "k3process.moc"