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