• 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 _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 <kstandarddirs.h>
72 #include <kuser.h>
73 
74 
76 // private data //
78 
79 class TDEProcessPrivate {
80 public:
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 
111 TDEProcess::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 
136 TDEProcess::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 
161 void
162 TDEProcess::setEnvironment(const TQString &name, const TQString &value)
163 {
164  d->env.insert(name, value);
165 }
166 
167 void
168 TDEProcess::setWorkingDirectory(const TQString &dir)
169 {
170  d->wd = dir;
171 }
172 
173 void
174 TDEProcess::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 
188 void
189 TDEProcess::setRunPrivileged(bool keepPrivileges)
190 {
191  keepPrivs = keepPrivileges;
192 }
193 
194 bool
195 TDEProcess::runPrivileged() const
196 {
197  return keepPrivs;
198 }
199 
200 bool
201 TDEProcess::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 
216 TDEProcess::~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 
231 void 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 
241 void TDEProcess::setBinaryExecutable(const char *filename)
242 {
243  d->executable = filename;
244 }
245 
246 bool 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 
259 TDEProcess &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 
267 TDEProcess &TDEProcess::operator<<(const TQCString& arg)
268 {
269  return operator<< (arg.data());
270 }
271 
272 TDEProcess &TDEProcess::operator<<(const char* arg)
273 {
274  arguments.append(arg);
275  return *this;
276 }
277 
278 TDEProcess &TDEProcess::operator<<(const TQString& arg)
279 {
280  arguments.append(TQFile::encodeName(arg));
281  return *this;
282 }
283 
284 void TDEProcess::clearArguments()
285 {
286  arguments.clear();
287 }
288 
289 bool 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 
484 bool 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 
495 bool TDEProcess::isRunning() const
496 {
497  return runs;
498 }
499 
500 
501 
502 pid_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 
519 bool 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 
585 bool TDEProcess::normalExit() const
586 {
587  return (pid_ != 0) && !runs && WIFEXITED(status);
588 }
589 
590 
591 bool TDEProcess::signalled() const
592 {
593  return (pid_ != 0) && !runs && WIFSIGNALED(status);
594 }
595 
596 
597 bool TDEProcess::coreDumped() const
598 {
599 #ifdef WCOREDUMP
600  return signalled() && WCOREDUMP(status);
601 #else
602  return false;
603 #endif
604 }
605 
606 
607 int TDEProcess::exitStatus() const
608 {
609  return WEXITSTATUS(status);
610 }
611 
612 
613 int TDEProcess::exitSignal() const
614 {
615  return WTERMSIG(status);
616 }
617 
618 
619 bool 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  // kprocess ...)
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 
639 void TDEProcess::suspend()
640 {
641  if (outnot)
642  outnot->setEnabled(false);
643 }
644 
645 void TDEProcess::resume()
646 {
647  if (outnot)
648  outnot->setEnabled(true);
649 }
650 
651 bool 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 
665 bool 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 
679 bool 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 
693 bool 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 
708 void TDEProcess::closeAll()
709 {
710  closeStdin();
711  closeStdout();
712  closeStderr();
713  closePty();
714 }
715 
717 // protected slots //
719 
720 
721 
722 void TDEProcess::slotChildOutput(int fdno)
723 {
724  if (!childOutput(fdno))
725  closeStdout();
726 }
727 
728 
729 void TDEProcess::slotChildError(int fdno)
730 {
731  if (!childError(fdno))
732  closeStderr();
733 }
734 
735 
736 void 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 
756 void 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
781 void 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 
794 KPty *TDEProcess::pty() const
795 {
796  return d->pty;
797 }
798 #endif //Q_OS_UNIX
799 
800 TQString 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 
812 void 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 
827 int 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 
850 int 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 
865 int 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 
933 int 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 
978 int 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 
1028 void 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 
1098 void TDEProcess::virtual_hook( int, void* )
1099 { /*BASE::virtual_hook( id, data );*/ }
1100 
1101 
1103 // CC: Class KShellProcess
1105 
1106 KShellProcess::KShellProcess(const char *shellname):
1107  TDEProcess()
1108 {
1109  setUseShell( true, shellname ? shellname : getenv("SHELL") );
1110 }
1111 
1112 KShellProcess::~KShellProcess() {
1113 }
1114 
1115 TQString KShellProcess::quote(const TQString &arg)
1116 {
1117  return TDEProcess::quote(arg);
1118 }
1119 
1120 bool KShellProcess::start(RunMode runmode, Communication comm)
1121 {
1122  return TDEProcess::start(runmode, comm);
1123 }
1124 
1125 void KShellProcess::virtual_hook( int id, void* data )
1126 { TDEProcess::virtual_hook( id, data ); }
1127 
1128 #include "kprocess.moc"
KPty
Provides a high level representation of a pseudo tty pair, including utmp support.
Definition: kpty.h:40
KShellProcess::KShellProcess
KShellProcess(const char *shellname=0)
Constructor.
Definition: kprocess.cpp:1106
KShellProcess::start
virtual bool start(RunMode runmode=NotifyOnExit, Communication comm=NoCommunication)
Starts the process.
Definition: kprocess.cpp:1120
KShellProcess::~KShellProcess
~KShellProcess()
Destructor.
Definition: kprocess.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: kprocctrl.cpp:48
TDEProcessController::ref
static void ref()
Create an instance if none exists yet.
Definition: kprocctrl.cpp:39
TDEProcessController::rescheduleCheck
void rescheduleCheck()
This function must be called at some point after calling unscheduleCheck().
Definition: kprocctrl.cpp:178
TDEProcessController::theTDEProcessController
static TDEProcessController * theTDEProcessController
Only a single instance of this class is allowed at a time, and this static variable is used to track ...
Definition: kprocctrl.h:60
TDEProcessController::unscheduleCheck
void unscheduleCheck()
Call this function to defer processing of the data that became available on notifierFd().
Definition: kprocctrl.cpp:170
TDEProcess
Child process invocation, monitoring and control.
Definition: kprocess.h:131
TDEProcess::status
int status
The process' exit status as returned by waitpid().
Definition: kprocess.h:726
TDEProcess::operator<<
TDEProcess & operator<<(const TQString &arg)
Sets the executable and the command line argument list for this process.
Definition: kprocess.cpp:278
TDEProcess::pid_
pid_t pid_
The PID of the currently running process.
Definition: kprocess.h:717
TDEProcess::outnot
TQSocketNotifier * outnot
The socket notifier for out[0].
Definition: kprocess.h:842
TDEProcess::processHasExited
virtual void processHasExited(int state)
Immediately called after a successfully started process in NotifyOnExit mode has exited.
Definition: kprocess.cpp:812
TDEProcess::isRunning
bool isRunning() const
Checks whether the process is running.
Definition: kprocess.cpp:495
TDEProcess::closePty
bool closePty()
Deletes the optional utmp entry and closes the pty.
Definition: kprocess.cpp:693
TDEProcess::out
int out[2]
The socket descriptors for stdout.
Definition: kprocess.h:825
TDEProcess::commSetupDoneC
virtual int commSetupDoneC()
Called right after a (successful) fork(), but before an exec() on the child process' side.
Definition: kprocess.cpp:978
TDEProcess::pid
pid_t pid() const
Returns the process id of the process.
Definition: kprocess.cpp:502
TDEProcess::TDEProcess
TDEProcess()
Constructor.
Definition: kprocess.cpp:136
TDEProcess::commSetupDoneP
virtual int commSetupDoneP()
Called right after a (successful) fork() on the parent side.
Definition: kprocess.cpp:933
TDEProcess::communication
Communication communication
Lists the communication links that are activated for the child process.
Definition: kprocess.h:852
TDEProcess::runs
bool runs
true if the process is currently running.
Definition: kprocess.h:708
TDEProcess::in
int in[2]
The socket descriptors for stdin.
Definition: kprocess.h:829
TDEProcess::start
virtual bool start(RunMode runmode=NotifyOnExit, Communication comm=NoCommunication)
Starts the process.
Definition: kprocess.cpp:289
TDEProcess::exitStatus
int exitStatus() const
Returns the exit status of the process.
Definition: kprocess.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: kprocess.cpp:850
TDEProcess::suspend
void suspend()
Suspend processing of data from stdout of the child process.
Definition: kprocess.cpp:639
TDEProcess::input_sent
int input_sent
The number of bytes already transmitted.
Definition: kprocess.h:875
TDEProcess::processExited
void processExited(TDEProcess *proc)
Emitted after the process has terminated when the process was run in the NotifyOnExit (==default opti...
TDEProcess::keepPrivs
bool keepPrivs
If false, the child process' effective uid & gid will be reset to the real values.
Definition: kprocess.h:734
TDEProcess::clearArguments
void clearArguments()
Clear a command line argument list that has been set by using operator<<.
Definition: kprocess.cpp:284
TDEProcess::kill
virtual bool kill(int signo=SIGTERM)
Stop the process (by sending it a signal).
Definition: kprocess.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: kprocess.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: kprocess.cpp:800
TDEProcess::setEnvironment
void setEnvironment(const TQString &name, const TQString &value)
Adds the variable name to the process' environment.
Definition: kprocess.cpp:162
TDEProcess::RunMode
RunMode
Run-modes for a child process.
Definition: kprocess.h:169
TDEProcess::OwnGroup
@ OwnGroup
Same as NotifyOnExit, but the process is run in an own session, just like with DontCare.
Definition: kprocess.h:187
TDEProcess::DontCare
@ DontCare
The application does not receive notifications from the subprocess when it is finished or aborted.
Definition: kprocess.h:174
TDEProcess::NotifyOnExit
@ NotifyOnExit
The application is notified when the subprocess dies.
Definition: kprocess.h:178
TDEProcess::Block
@ Block
The application is suspended until the started process is finished.
Definition: kprocess.h:182
TDEProcess::setupEnvironment
void setupEnvironment()
Sets up the environment according to the data passed via setEnvironment()
Definition: kprocess.cpp:174
TDEProcess::Communication
Communication
Modes in which the communication channel can be opened.
Definition: kprocess.h:157
TDEProcess::slotSendData
void slotSendData(int dummy)
Called when another bulk of data can be sent to the child's stdin.
Definition: kprocess.cpp:736
TDEProcess::detach
void detach()
Detaches TDEProcess from child process.
Definition: kprocess.cpp:231
TDEProcess::arguments
TQValueList< TQCString > arguments
The list of the process' command line arguments.
Definition: kprocess.h:696
TDEProcess::setUsePty
void setUsePty(Communication comm, bool addUtmp)
Specify whether to create a pty (pseudo-terminal) for running the command.
Definition: kprocess.cpp:781
TDEProcess::run_mode
RunMode run_mode
How to run the process (Block, NotifyOnExit, DontCare).
Definition: kprocess.h:701
TDEProcess::childOutput
int childOutput(int fdno)
Called by slotChildOutput() this function copies data arriving from the child process' stdout to the ...
Definition: kprocess.cpp:827
TDEProcess::writeStdin
bool writeStdin(const char *buffer, int buflen)
Definition: kprocess.cpp:619
TDEProcess::commClose
virtual void commClose()
Cleans up the communication links to the child after it has exited.
Definition: kprocess.cpp:1028
TDEProcess::input_total
int input_total
The total length of input_data.
Definition: kprocess.h:879
TDEProcess::exitSignal
int exitSignal() const
Returns the signal the process was killed by.
Definition: kprocess.cpp:613
TDEProcess::resume
void resume()
Resume processing of data from stdout of the child process.
Definition: kprocess.cpp:645
TDEProcess::setWorkingDirectory
void setWorkingDirectory(const TQString &dir)
Changes the current working directory (CWD) of the process to be started.
Definition: kprocess.cpp:168
TDEProcess::setupCommunication
virtual int setupCommunication(Communication comm)
This function is called from start() right before a fork() takes place.
Definition: kprocess.cpp:865
TDEProcess::slotChildError
void slotChildError(int fdno)
This slot gets activated when data from the child's stderr arrives.
Definition: kprocess.cpp:729
TDEProcess::errnot
TQSocketNotifier * errnot
The socket notifier for err[0].
Definition: kprocess.h:846
TDEProcess::closeStderr
bool closeStderr()
Shuts down the Stderr communication link.
Definition: kprocess.cpp:679
TDEProcess::innot
TQSocketNotifier * innot
The socket notifier for in[1].
Definition: kprocess.h:838
TDEProcess::slotChildOutput
void slotChildOutput(int fdno)
This slot gets activated when data from the child's stdout arrives.
Definition: kprocess.cpp:722
TDEProcess::input_data
const char * input_data
The buffer holding the data that has to be sent to the child.
Definition: kprocess.h:871
TDEProcess::setPriority
bool setPriority(int prio)
Sets the scheduling priority of the process.
Definition: kprocess.cpp: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: kprocess.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: kprocess.cpp:216
TDEProcess::closeAll
void closeAll()
Close stdin, stdout, stderr and the pty.
Definition: kprocess.cpp:708
TDEProcess::err
int err[2]
The socket descriptors for stderr.
Definition: kprocess.h:833
TDEProcess::closeStdout
bool closeStdout()
Shuts down the Stdout communication link.
Definition: kprocess.cpp:665
TDEProcess::setExecutable
bool setExecutable(const TQString &proc) TDE_DEPRECATED
Definition: kprocess.cpp:246
TDEProcess::closeStdin
bool closeStdin()
Shuts down the Stdin communication link.
Definition: kprocess.cpp:651
TDEProcess::coreDumped
bool coreDumped() const
Checks whether a killed process dumped core.
Definition: kprocess.cpp:597
TDEProcess::setUseShell
void setUseShell(bool useShell, const char *shell=0)
Specify whether to start the command via a shell or directly.
Definition: kprocess.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: kprocess.cpp:189
TDEProcess::normalExit
bool normalExit() const
Checks whether the process exited cleanly.
Definition: kprocess.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: kprocess.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: kprocess.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: kprocess.cpp:794
TDEProcess::args
const TQValueList< TQCString > & args()
Lets you see what your arguments are for debugging.
Definition: kprocess.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.