• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • tdecore
 

tdecore

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

tdecore

Skip menu "tdecore"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

tdecore

Skip menu "tdecore"
  • arts
  • dcop
  • dnssd
  • interfaces
  •   kspeech
  •     interface
  •     library
  •   tdetexteditor
  • kate
  • kded
  • kdoctools
  • kimgio
  • kjs
  • libtdemid
  • libtdescreensaver
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdeioslave
  •   http
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for tdecore by doxygen 1.9.8
This website is maintained by Timothy Pearson.