• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdelibs API Reference
  • KDE Home
  • Contact Us
 

KDE3Support

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

KDE's Doxygen guidelines are available online.

KDE3Support

Skip menu "KDE3Support"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdelibs API Reference

Skip menu "kdelibs API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal