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

tdecore

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

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
  •     tdecore
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  • tdeioslave
  •   http
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for tdecore by doxygen 1.8.8
This website is maintained by Timothy Pearson.