• 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 <kstandarddirs.h>
76 #include <kuser.h>
77 
78 
80 // private data //
82 
83 class TDEProcessPrivate {
84 public:
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 
115 TDEProcess::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 
140 TDEProcess::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 
165 void
166 TDEProcess::setEnvironment(const TQString &name, const TQString &value)
167 {
168  d->env.insert(name, value);
169 }
170 
171 void
172 TDEProcess::setWorkingDirectory(const TQString &dir)
173 {
174  d->wd = dir;
175 }
176 
177 void
178 TDEProcess::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 
192 void
193 TDEProcess::setRunPrivileged(bool keepPrivileges)
194 {
195  keepPrivs = keepPrivileges;
196 }
197 
198 bool
199 TDEProcess::runPrivileged() const
200 {
201  return keepPrivs;
202 }
203 
204 bool
205 TDEProcess::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 
220 TDEProcess::~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 
235 void 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 
245 void TDEProcess::setBinaryExecutable(const char *filename)
246 {
247  d->executable = filename;
248 }
249 
250 bool 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 
263 TDEProcess &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 
271 TDEProcess &TDEProcess::operator<<(const TQCString& arg)
272 {
273  return operator<< (arg.data());
274 }
275 
276 TDEProcess &TDEProcess::operator<<(const char* arg)
277 {
278  arguments.append(arg);
279  return *this;
280 }
281 
282 TDEProcess &TDEProcess::operator<<(const TQString& arg)
283 {
284  arguments.append(TQFile::encodeName(arg));
285  return *this;
286 }
287 
288 void TDEProcess::clearArguments()
289 {
290  arguments.clear();
291 }
292 
293 bool 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 
488 bool 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 
499 bool TDEProcess::isRunning() const
500 {
501  return runs;
502 }
503 
504 
505 
506 pid_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 
523 bool 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 
589 bool TDEProcess::normalExit() const
590 {
591  return (pid_ != 0) && !runs && WIFEXITED(status);
592 }
593 
594 
595 bool TDEProcess::signalled() const
596 {
597  return (pid_ != 0) && !runs && WIFSIGNALED(status);
598 }
599 
600 
601 bool TDEProcess::coreDumped() const
602 {
603 #ifdef WCOREDUMP
604  return signalled() && WCOREDUMP(status);
605 #else
606  return false;
607 #endif
608 }
609 
610 
611 int TDEProcess::exitStatus() const
612 {
613  return WEXITSTATUS(status);
614 }
615 
616 
617 int TDEProcess::exitSignal() const
618 {
619  return WTERMSIG(status);
620 }
621 
622 
623 bool 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 
643 void TDEProcess::suspend()
644 {
645  if (outnot)
646  outnot->setEnabled(false);
647 }
648 
649 void TDEProcess::resume()
650 {
651  if (outnot)
652  outnot->setEnabled(true);
653 }
654 
655 bool 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 
669 bool 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 
683 bool 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 
697 bool 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 
712 void TDEProcess::closeAll()
713 {
714  closeStdin();
715  closeStdout();
716  closeStderr();
717  closePty();
718 }
719 
721 // protected slots //
723 
724 
725 
726 void TDEProcess::slotChildOutput(int fdno)
727 {
728  if (!childOutput(fdno))
729  closeStdout();
730 }
731 
732 
733 void TDEProcess::slotChildError(int fdno)
734 {
735  if (!childError(fdno))
736  closeStderr();
737 }
738 
739 
740 void 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 
760 void 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
785 void 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 
798 KPty *TDEProcess::pty() const
799 {
800  return d->pty;
801 }
802 #endif //Q_OS_UNIX
803 
804 TQString 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 
816 void 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 
831 int 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 
854 int 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 
869 int 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 
937 int 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 
982 int 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 
1032 void 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 
1102 void TDEProcess::virtual_hook( int, void* )
1103 { /*BASE::virtual_hook( id, data );*/ }
1104 
1105 
1107 // CC: Class KShellProcess
1109 
1110 KShellProcess::KShellProcess(const char *shellname):
1111  TDEProcess()
1112 {
1113  setUseShell( true, shellname ? shellname : getenv("SHELL") );
1114 }
1115 
1116 KShellProcess::~KShellProcess() {
1117 }
1118 
1119 TQString KShellProcess::quote(const TQString &arg)
1120 {
1121  return TDEProcess::quote(arg);
1122 }
1123 
1124 bool KShellProcess::start(RunMode runmode, Communication comm)
1125 {
1126  return TDEProcess::start(runmode, comm);
1127 }
1128 
1129 void 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::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
TDEProcess::args
const TQValueList< TQCString > & args()
Lets you see what your arguments are for debugging.
Definition: tdeprocess.h:472
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.1
This website is maintained by Timothy Pearson.