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

tdecore

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

tdecore

Skip menu "tdecore"
  • Main Page
  • Modules
  • 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.4
This website is maintained by Timothy Pearson.