1/*
2 This file is part of the KDE libraries
3 Copyright (C) 1997 Christian Czezatke (e9025461@student.tuwien.ac.at)
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20
21
22#include "k3process.h"
23#include <config.h>
24
25#include "k3processcontroller.h"
26#include "kpty/kpty.h"
27
28#ifdef __osf__
29#define _OSF_SOURCE
30#include <float.h>
31#endif
32
33#ifdef _AIX
34#define _ALL_SOURCE
35#endif
36
37#include <sys/socket.h>
38#include <sys/ioctl.h>
39
40#include <sys/types.h>
41#include <sys/time.h>
42#include <sys/resource.h>
43#include <sys/stat.h>
44#include <sys/wait.h>
45
46#ifdef HAVE_SYS_SELECT_H
47#include <sys/select.h>
48#endif
49
50#include <errno.h>
51#include <assert.h>
52#include <fcntl.h>
53#include <time.h>
54#include <stdlib.h>
55#include <signal.h>
56#include <stdio.h>
57#include <string.h>
58#include <unistd.h>
59#include <pwd.h>
60#include <grp.h>
61
62#include <QtCore/QMap>
63#include <QtCore/QFile>
64#include <QtCore/QSocketNotifier>
65
66#include <kdebug.h>
67#include <kstandarddirs.h>
68#include <kuser.h>
69
70
71//////////////////
72// private data //
73//////////////////
74
75class K3ProcessPrivate {
76public:
77 K3ProcessPrivate() :
78 usePty(K3Process::NoCommunication),
79 addUtmp(false), useShell(false),
80 pty(0),
81 priority(0)
82 {
83 }
84
85 K3Process::Communication usePty;
86 bool addUtmp : 1;
87 bool useShell : 1;
88
89 KPty *pty;
90
91 int priority;
92
93 QMap<QString,QString> env;
94 QString wd;
95 QByteArray shell;
96 QByteArray executable;
97};
98
99/////////////////////////////
100// public member functions //
101/////////////////////////////
102
103K3Process::K3Process( QObject* parent )
104 : QObject( parent ),
105 run_mode(NotifyOnExit),
106 runs(false),
107 pid_(0),
108 status(0),
109 keepPrivs(false),
110 innot(0),
111 outnot(0),
112 errnot(0),
113 communication(NoCommunication),
114 input_data(0),
115 input_sent(0),
116 input_total(0),
117 d(new K3ProcessPrivate)
118{
119 K3ProcessController::ref();
120 K3ProcessController::instance()->addKProcess(this);
121
122
123 out[0] = out[1] = -1;
124 in[0] = in[1] = -1;
125 err[0] = err[1] = -1;
126}
127
128void
129K3Process::setEnvironment(const QString &name, const QString &value)
130{
131 d->env.insert(name, value);
132}
133
134void
135K3Process::setWorkingDirectory(const QString &dir)
136{
137 d->wd = dir;
138}
139
140void
141K3Process::setupEnvironment()
142{
143 QMap<QString,QString>::Iterator it;
144 for(it = d->env.begin(); it != d->env.end(); ++it)
145 {
146 setenv(QFile::encodeName(it.key()).data(),
147 QFile::encodeName(it.value()).data(), 1);
148 }
149 if (!d->wd.isEmpty())
150 {
151 chdir(QFile::encodeName(d->wd).data());
152 }
153}
154
155void
156K3Process::setRunPrivileged(bool keepPrivileges)
157{
158 keepPrivs = keepPrivileges;
159}
160
161bool
162K3Process::runPrivileged() const
163{
164 return keepPrivs;
165}
166
167bool
168K3Process::setPriority(int prio)
169{
170 if (runs) {
171 if (setpriority(PRIO_PROCESS, pid_, prio))
172 return false;
173 } else {
174 if (prio > 19 || prio < (geteuid() ? getpriority(PRIO_PROCESS, 0) : -20))
175 return false;
176 }
177 d->priority = prio;
178 return true;
179}
180
181K3Process::~K3Process()
182{
183 if (run_mode != DontCare)
184 kill(SIGKILL);
185 detach();
186
187 delete d->pty;
188 delete d;
189
190 K3ProcessController::instance()->removeKProcess(this);
191 K3ProcessController::deref();
192}
193
194void K3Process::detach()
195{
196 if (runs) {
197 K3ProcessController::instance()->addProcess(pid_);
198 runs = false;
199 pid_ = 0; // close without draining
200 commClose(); // Clean up open fd's and socket notifiers.
201 }
202}
203
204void K3Process::setBinaryExecutable(const char *filename)
205{
206 d->executable = filename;
207}
208
209K3Process &K3Process::operator<<(const QStringList& args)
210{
211 QStringList::ConstIterator it = args.begin();
212 for ( ; it != args.end() ; ++it )
213 arguments.append(QFile::encodeName(*it));
214 return *this;
215}
216
217K3Process &K3Process::operator<<(const QByteArray& arg)
218{
219 return operator<< (arg.data());
220}
221
222K3Process &K3Process::operator<<(const char* arg)
223{
224 arguments.append(arg);
225 return *this;
226}
227
228K3Process &K3Process::operator<<(const QString& arg)
229{
230 arguments.append(QFile::encodeName(arg));
231 return *this;
232}
233
234void K3Process::clearArguments()
235{
236 arguments.clear();
237}
238
239bool K3Process::start(RunMode runmode, Communication comm)
240{
241 if (runs) {
242 kDebug(175) << "Attempted to start an already running process" << endl;
243 return false;
244 }
245
246 uint n = arguments.count();
247 if (n == 0) {
248 kDebug(175) << "Attempted to start a process without arguments" << endl;
249 return false;
250 }
251 char **arglist;
252 QByteArray shellCmd;
253 if (d->useShell)
254 {
255 if (d->shell.isEmpty()) {
256 kDebug(175) << "Invalid shell specified" << endl;
257 return false;
258 }
259
260 for (uint i = 0; i < n; i++) {
261 shellCmd += arguments[i];
262 shellCmd += ' '; // CC: to separate the arguments
263 }
264
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();
269 arglist[3] = 0;
270 }
271 else
272 {
273 arglist = static_cast<char **>(malloc( (n + 1) * sizeof(char *)));
274 for (uint i = 0; i < n; i++)
275 arglist[i] = arguments[i].data();
276 arglist[n] = 0;
277 }
278
279 run_mode = runmode;
280
281 if (!setupCommunication(comm))
282 {
283 kDebug(175) << "Could not setup Communication!" << endl;
284 free(arglist);
285 return false;
286 }
287
288 // We do this in the parent because if we do it in the child process
289 // gdb gets confused when the application runs from gdb.
290#ifdef HAVE_INITGROUPS
291 struct passwd *pw = geteuid() ? 0 : getpwuid(getuid());
292#endif
293
294 int fd[2];
295 if (pipe(fd))
296 fd[0] = fd[1] = -1; // Pipe failed.. continue
297
298 // we don't use vfork() because
299 // - it has unclear semantics and is not standardized
300 // - we do way too much magic in the child
301 pid_ = fork();
302 if (pid_ == 0) {
303 // The child process
304
305 close(fd[0]);
306 // Closing of fd[1] indicates that the execvp() succeeded!
307 fcntl(fd[1], F_SETFD, FD_CLOEXEC);
308
309 if (!commSetupDoneC())
310 kDebug(175) << "Could not finish comm setup in child!" << endl;
311
312 // reset all signal handlers
313 struct sigaction act;
314 sigemptyset(&act.sa_mask);
315 act.sa_handler = SIG_DFL;
316 act.sa_flags = 0;
317 for (int sig = 1; sig < NSIG; sig++)
318 sigaction(sig, &act, 0L);
319
320 if (d->priority)
321 setpriority(PRIO_PROCESS, 0, d->priority);
322
323 if (!runPrivileged())
324 {
325 setgid(getgid());
326#ifdef HAVE_INITGROUPS
327 if (pw)
328 initgroups(pw->pw_name, pw->pw_gid);
329#endif
330 if (geteuid() != getuid())
331 setuid(getuid());
332 if (geteuid() != getuid())
333 _exit(1);
334 }
335
336 setupEnvironment();
337
338 if (runmode == DontCare || runmode == OwnGroup)
339 setsid();
340
341 const char *executable = arglist[0];
342 if (!d->executable.isEmpty())
343 executable = d->executable.data();
344 execvp(executable, arglist);
345
346 char resultByte = 1;
347 write(fd[1], &resultByte, 1);
348 _exit(-1);
349 } else if (pid_ == -1) {
350 // forking failed
351
352 // commAbort();
353 pid_ = 0;
354 free(arglist);
355 return false;
356 }
357 // the parent continues here
358 free(arglist);
359
360 if (!commSetupDoneP())
361 kDebug(175) << "Could not finish comm setup in parent!" << endl;
362
363 // Check whether client could be started.
364 close(fd[1]);
365 for(;;)
366 {
367 char resultByte;
368 int n = ::read(fd[0], &resultByte, 1);
369 if (n == 1)
370 {
371 // exec() failed
372 close(fd[0]);
373 waitpid(pid_, 0, 0);
374 pid_ = 0;
375 commClose();
376 return false;
377 }
378 if (n == -1)
379 {
380 if (errno == EINTR)
381 continue; // Ignore
382 }
383 break; // success
384 }
385 close(fd[0]);
386
387 runs = true;
388 switch (runmode)
389 {
390 case Block:
391 for (;;)
392 {
393 commClose(); // drain only, unless obsolete reimplementation
394 if (!runs)
395 {
396 // commClose detected data on the process exit notifification pipe
397 K3ProcessController::instance()->unscheduleCheck();
398 if (waitpid(pid_, &status, WNOHANG) != 0) // error finishes, too
399 {
400 commClose(); // this time for real (runs is false)
401 K3ProcessController::instance()->rescheduleCheck();
402 break;
403 }
404 runs = true; // for next commClose() iteration
405 }
406 else
407 {
408 // commClose is an obsolete reimplementation and waited until
409 // all output channels were closed (or it was interrupted).
410 // there is a chance that it never gets here ...
411 waitpid(pid_, &status, 0);
412 runs = false;
413 break;
414 }
415 }
416 // why do we do this? i think this signal should be emitted _only_
417 // after the process has successfully run _asynchronously_ --ossi
418 emit processExited(this);
419 break;
420 default: // NotifyOnExit & OwnGroup
421 input_data = 0; // Discard any data for stdin that might still be there
422 break;
423 }
424 return true;
425}
426
427
428
429bool K3Process::kill(int signo)
430{
431 if (runs && pid_ > 0 && !::kill(run_mode == OwnGroup ? -pid_ : pid_, signo))
432 return true;
433 return false;
434}
435
436
437
438bool K3Process::isRunning() const
439{
440 return runs;
441}
442
443
444
445pid_t K3Process::pid() const
446{
447 return pid_;
448}
449
450#ifndef timersub
451# define timersub(a, b, result) \
452 do { \
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; \
458 } \
459 } while (0)
460#endif
461
462bool K3Process::wait(int timeout)
463{
464 if (!runs)
465 return true;
466
467#ifndef __linux__
468 struct timeval etv;
469#endif
470 struct timeval tv, *tvp;
471 if (timeout < 0)
472 tvp = 0;
473 else
474 {
475#ifndef __linux__
476 gettimeofday(&etv, 0);
477 etv.tv_sec += timeout;
478#else
479 tv.tv_sec = timeout;
480 tv.tv_usec = 0;
481#endif
482 tvp = &tv;
483 }
484
485 int fd = K3ProcessController::instance()->notifierFd();
486 for(;;)
487 {
488 fd_set fds;
489 FD_ZERO( &fds );
490 FD_SET( fd, &fds );
491
492#ifndef __linux__
493 if (tvp)
494 {
495 gettimeofday(&tv, 0);
496 timersub(&etv, &tv, &tv);
497 if (tv.tv_sec < 0)
498 tv.tv_sec = tv.tv_usec = 0;
499 }
500#endif
501
502 switch( select( fd+1, &fds, 0, 0, tvp ) )
503 {
504 case -1:
505 if( errno == EINTR )
506 break;
507 // fall through; should happen if tvp->tv_sec < 0
508 case 0:
509 K3ProcessController::instance()->rescheduleCheck();
510 return false;
511 default:
512 K3ProcessController::instance()->unscheduleCheck();
513 if (waitpid(pid_, &status, WNOHANG) != 0) // error finishes, too
514 {
515 processHasExited(status);
516 K3ProcessController::instance()->rescheduleCheck();
517 return true;
518 }
519 }
520 }
521 return false;
522}
523
524
525
526bool K3Process::normalExit() const
527{
528 return (pid_ != 0) && !runs && WIFEXITED(status);
529}
530
531
532bool K3Process::signalled() const
533{
534 return (pid_ != 0) && !runs && WIFSIGNALED(status);
535}
536
537
538bool K3Process::coreDumped() const
539{
540#ifdef WCOREDUMP
541 return signalled() && WCOREDUMP(status);
542#else
543 return false;
544#endif
545}
546
547
548int K3Process::exitStatus() const
549{
550 return WEXITSTATUS(status);
551}
552
553
554int K3Process::exitSignal() const
555{
556 return WTERMSIG(status);
557}
558
559
560bool K3Process::writeStdin(const char *buffer, int buflen)
561{
562 // if there is still data pending, writing new data
563 // to stdout is not allowed (since it could also confuse
564 // kprocess ...)
565 if (input_data != 0)
566 return false;
567
568 if (communication & Stdin) {
569 input_data = buffer;
570 input_sent = 0;
571 input_total = buflen;
572 innot->setEnabled(true);
573 if (input_total)
574 slotSendData(0);
575 return true;
576 } else
577 return false;
578}
579
580void K3Process::suspend()
581{
582 if (outnot)
583 outnot->setEnabled(false);
584}
585
586void K3Process::resume()
587{
588 if (outnot)
589 outnot->setEnabled(true);
590}
591
592bool K3Process::closeStdin()
593{
594 if (communication & Stdin) {
595 communication = communication & ~Stdin;
596 delete innot;
597 innot = 0;
598 if (!(d->usePty & Stdin))
599 close(in[1]);
600 in[1] = -1;
601 return true;
602 } else
603 return false;
604}
605
606bool K3Process::closeStdout()
607{
608 if (communication & Stdout) {
609 communication = communication & ~Stdout;
610 delete outnot;
611 outnot = 0;
612 if (!(d->usePty & Stdout))
613 close(out[0]);
614 out[0] = -1;
615 return true;
616 } else
617 return false;
618}
619
620bool K3Process::closeStderr()
621{
622 if (communication & Stderr) {
623 communication = communication & ~Stderr;
624 delete errnot;
625 errnot = 0;
626 if (!(d->usePty & Stderr))
627 close(err[0]);
628 err[0] = -1;
629 return true;
630 } else
631 return false;
632}
633
634bool K3Process::closePty()
635{
636 if (d->pty && d->pty->masterFd() >= 0) {
637 if (d->addUtmp)
638 d->pty->logout();
639 d->pty->close();
640 return true;
641 } else
642 return false;
643}
644
645void K3Process::closeAll()
646{
647 closeStdin();
648 closeStdout();
649 closeStderr();
650 closePty();
651}
652
653/////////////////////////////
654// protected slots //
655/////////////////////////////
656
657
658
659void K3Process::slotChildOutput(int fdno)
660{
661 if (!childOutput(fdno))
662 closeStdout();
663}
664
665
666void K3Process::slotChildError(int fdno)
667{
668 if (!childError(fdno))
669 closeStderr();
670}
671
672
673void K3Process::slotSendData(int)
674{
675 if (input_sent == input_total) {
676 innot->setEnabled(false);
677 input_data = 0;
678 emit wroteStdin(this);
679 } else {
680 int result = ::write(in[1], input_data+input_sent, input_total-input_sent);
681 if (result >= 0)
682 {
683 input_sent += result;
684 }
685 else if ((errno != EAGAIN) && (errno != EINTR))
686 {
687 kDebug(175) << "Error writing to stdin of child process" << endl;
688 closeStdin();
689 }
690 }
691}
692
693void K3Process::setUseShell(bool useShell, const char *shell)
694{
695 d->useShell = useShell;
696 if (shell && *shell)
697 d->shell = shell;
698 else
699// #ifdef NON_FREE // ... as they ship non-POSIX /bin/sh
700#if !defined(__linux__) && !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__) && !defined(__GNU__) && !defined(__DragonFly__)
701 // Solaris POSIX ...
702 if (!access( "/usr/xpg4/bin/sh", X_OK ))
703 d->shell = "/usr/xpg4/bin/sh";
704 else
705 // ... which links here anyway
706 if (!access( "/bin/ksh", X_OK ))
707 d->shell = "/bin/ksh";
708 else
709 // dunno, maybe superfluous?
710 if (!access( "/usr/ucb/sh", X_OK ))
711 d->shell = "/usr/ucb/sh";
712 else
713#endif
714 d->shell = "/bin/sh";
715}
716
717void K3Process::setUsePty(Communication usePty, bool addUtmp)
718{
719 d->usePty = usePty;
720 d->addUtmp = addUtmp;
721 if (usePty) {
722 if (!d->pty)
723 d->pty = new KPty;
724 } else {
725 delete d->pty;
726 d->pty = 0;
727 }
728}
729
730KPty *K3Process::pty() const
731{
732 return d->pty;
733}
734
735QString K3Process::quote(const QString &arg)
736{
737 QChar q('\'');
738 return QString(arg).replace(q, "'\\''").prepend(q).append(q);
739}
740
741
742//////////////////////////////
743// private member functions //
744//////////////////////////////
745
746
747void K3Process::processHasExited(int state)
748{
749 // only successfully run NotifyOnExit processes ever get here
750
751 status = state;
752 runs = false; // do this before commClose, so it knows we're dead
753
754 commClose(); // cleanup communication sockets
755
756 if (run_mode != DontCare)
757 emit processExited(this);
758}
759
760
761
762int K3Process::childOutput(int fdno)
763{
764 if (communication & NoRead) {
765 int len = -1;
766 emit receivedStdout(fdno, len);
767 errno = 0; // Make sure errno doesn't read "EAGAIN"
768 return len;
769 }
770 else
771 {
772 char buffer[1025];
773 int len;
774
775 len = ::read(fdno, buffer, 1024);
776
777 if (len > 0) {
778 buffer[len] = 0; // Just in case.
779 emit receivedStdout(this, buffer, len);
780 }
781 return len;
782 }
783}
784
785int K3Process::childError(int fdno)
786{
787 char buffer[1025];
788 int len;
789
790 len = ::read(fdno, buffer, 1024);
791
792 if (len > 0) {
793 buffer[len] = 0; // Just in case.
794 emit receivedStderr(this, buffer, len);
795 }
796 return len;
797}
798
799
800int K3Process::setupCommunication(Communication comm)
801{
802 // PTY stuff //
803 if (d->usePty)
804 {
805 // cannot communicate on both stderr and stdout if they are both on the pty
806 if (!(~(comm & d->usePty) & (Stdout | Stderr))) {
807 kWarning(175) << "Invalid usePty/communication combination (" << d->usePty << "/" << comm << ")" << endl;
808 return 0;
809 }
810 if (!d->pty->open())
811 return 0;
812
813 int rcomm = comm & d->usePty;
814 int mfd = d->pty->masterFd();
815 if (rcomm & Stdin)
816 in[1] = mfd;
817 if (rcomm & Stdout)
818 out[0] = mfd;
819 if (rcomm & Stderr)
820 err[0] = mfd;
821 }
822
823 communication = comm;
824
825 comm = comm & ~d->usePty;
826 if (comm & Stdin) {
827 if (socketpair(AF_UNIX, SOCK_STREAM, 0, in))
828 goto fail0;
829 fcntl(in[0], F_SETFD, FD_CLOEXEC);
830 fcntl(in[1], F_SETFD, FD_CLOEXEC);
831 }
832 if (comm & Stdout) {
833 if (socketpair(AF_UNIX, SOCK_STREAM, 0, out))
834 goto fail1;
835 fcntl(out[0], F_SETFD, FD_CLOEXEC);
836 fcntl(out[1], F_SETFD, FD_CLOEXEC);
837 }
838 if (comm & Stderr) {
839 if (socketpair(AF_UNIX, SOCK_STREAM, 0, err))
840 goto fail2;
841 fcntl(err[0], F_SETFD, FD_CLOEXEC);
842 fcntl(err[1], F_SETFD, FD_CLOEXEC);
843 }
844 return 1; // Ok
845 fail2:
846 if (comm & Stdout)
847 {
848 close(out[0]);
849 close(out[1]);
850 out[0] = out[1] = -1;
851 }
852 fail1:
853 if (comm & Stdin)
854 {
855 close(in[0]);
856 close(in[1]);
857 in[0] = in[1] = -1;
858 }
859 fail0:
860 communication = NoCommunication;
861 return 0; // Error
862}
863
864
865
866int K3Process::commSetupDoneP()
867{
868 int rcomm = communication & ~d->usePty;
869 if (rcomm & Stdin)
870 close(in[0]);
871 if (rcomm & Stdout)
872 close(out[1]);
873 if (rcomm & Stderr)
874 close(err[1]);
875 in[0] = out[1] = err[1] = -1;
876
877 // Don't create socket notifiers if no interactive comm is to be expected
878 if (run_mode != NotifyOnExit && run_mode != OwnGroup)
879 return 1;
880
881 if (communication & Stdin) {
882 fcntl(in[1], F_SETFL, O_NONBLOCK | fcntl(in[1], F_GETFL));
883 innot = new QSocketNotifier(in[1], QSocketNotifier::Write, this);
884 Q_CHECK_PTR(innot);
885 innot->setEnabled(false); // will be enabled when data has to be sent
886 QObject::connect(innot, SIGNAL(activated(int)),
887 this, SLOT(slotSendData(int)));
888 }
889
890 if (communication & Stdout) {
891 outnot = new QSocketNotifier(out[0], QSocketNotifier::Read, this);
892 Q_CHECK_PTR(outnot);
893 QObject::connect(outnot, SIGNAL(activated(int)),
894 this, SLOT(slotChildOutput(int)));
895 if (communication & NoRead)
896 suspend();
897 }
898
899 if (communication & Stderr) {
900 errnot = new QSocketNotifier(err[0], QSocketNotifier::Read, this );
901 Q_CHECK_PTR(errnot);
902 QObject::connect(errnot, SIGNAL(activated(int)),
903 this, SLOT(slotChildError(int)));
904 }
905
906 return 1;
907}
908
909
910
911int K3Process::commSetupDoneC()
912{
913 int ok = 1;
914
915 if (d->usePty & Stdin) {
916 if (dup2(d->pty->slaveFd(), STDIN_FILENO) < 0) ok = 0;
917 } else if (communication & Stdin) {
918 if (dup2(in[0], STDIN_FILENO) < 0) ok = 0;
919 } else {
920 int null_fd = open( "/dev/null", O_RDONLY );
921 if (dup2( null_fd, STDIN_FILENO ) < 0) ok = 0;
922 close( null_fd );
923 }
924 struct linger so;
925 memset(&so, 0, sizeof(so));
926 if (d->usePty & Stdout) {
927 if (dup2(d->pty->slaveFd(), STDOUT_FILENO) < 0) ok = 0;
928 } else if (communication & Stdout) {
929 if (dup2(out[1], STDOUT_FILENO) < 0 ||
930 setsockopt(out[1], SOL_SOCKET, SO_LINGER, (char *)&so, sizeof(so)))
931 ok = 0;
932 if (communication & MergedStderr) {
933 if (dup2(out[1], STDERR_FILENO) < 0)
934 ok = 0;
935 }
936 }
937 if (d->usePty & Stderr) {
938 if (dup2(d->pty->slaveFd(), STDERR_FILENO) < 0) ok = 0;
939 } else if (communication & Stderr) {
940 if (dup2(err[1], STDERR_FILENO) < 0 ||
941 setsockopt(err[1], SOL_SOCKET, SO_LINGER, (char *)&so, sizeof(so)))
942 ok = 0;
943 }
944
945 // don't even think about closing all open fds here or anywhere else
946
947 // PTY stuff //
948 if (d->usePty) {
949 d->pty->setCTty();
950 if (d->addUtmp)
951 d->pty->login(KUser(KUser::UseRealUserID).loginName().toLocal8Bit().data(), getenv("DISPLAY"));
952 }
953
954 return ok;
955}
956
957
958
959void K3Process::commClose()
960{
961 closeStdin();
962
963 if (pid_) { // detached, failed, and killed processes have no output. basta. :)
964 // If both channels are being read we need to make sure that one socket
965 // buffer doesn't fill up whilst we are waiting for data on the other
966 // (causing a deadlock). Hence we need to use select.
967
968 int notfd = K3ProcessController::instance()->notifierFd();
969
970 while ((communication & (Stdout | Stderr)) || runs) {
971 fd_set rfds;
972 FD_ZERO(&rfds);
973 struct timeval timeout, *p_timeout;
974
975 int max_fd = 0;
976 if (communication & Stdout) {
977 FD_SET(out[0], &rfds);
978 max_fd = out[0];
979 }
980 if (communication & Stderr) {
981 FD_SET(err[0], &rfds);
982 if (err[0] > max_fd)
983 max_fd = err[0];
984 }
985 if (runs) {
986 FD_SET(notfd, &rfds);
987 if (notfd > max_fd)
988 max_fd = notfd;
989 // If the process is still running we block until we
990 // receive data or the process exits.
991 p_timeout = 0; // no timeout
992 } else {
993 // If the process has already exited, we only check
994 // the available data, we don't wait for more.
995 timeout.tv_sec = timeout.tv_usec = 0; // timeout immediately
996 p_timeout = &timeout;
997 }
998
999 int fds_ready = select(max_fd+1, &rfds, 0, 0, p_timeout);
1000 if (fds_ready < 0) {
1001 if (errno == EINTR)
1002 continue;
1003 break;
1004 } else if (!fds_ready)
1005 break;
1006
1007 if ((communication & Stdout) && FD_ISSET(out[0], &rfds))
1008 slotChildOutput(out[0]);
1009
1010 if ((communication & Stderr) && FD_ISSET(err[0], &rfds))
1011 slotChildError(err[0]);
1012
1013 if (runs && FD_ISSET(notfd, &rfds)) {
1014 runs = false; // hack: signal potential exit
1015 return; // don't close anything, we will be called again
1016 }
1017 }
1018 }
1019
1020 closeStdout();
1021 closeStderr();
1022
1023 closePty();
1024}
1025
1026
1027
1028///////////////////////////
1029// CC: Class K3ShellProcess
1030///////////////////////////
1031
1032K3ShellProcess::K3ShellProcess(const char *shellname):
1033 K3Process(), d(0)
1034{
1035 setUseShell( true, shellname ? shellname : getenv("SHELL") );
1036}
1037
1038K3ShellProcess::~K3ShellProcess() {
1039}
1040
1041QString K3ShellProcess::quote(const QString &arg)
1042{
1043 return K3Process::quote(arg);
1044}
1045
1046bool K3ShellProcess::start(RunMode runmode, Communication comm)
1047{
1048 return K3Process::start(runmode, comm);
1049}
1050
1051
1052#include "k3process.moc"
1053