source: ogBrowser-Git/qtermwidget/src/k3process.cpp

qndtest
Last change on this file was 8ab4781, checked in by adelcastillo <adelcastillo@…>, 15 years ago

Cambiando a qmake de nuevo.

git-svn-id: https://opengnsys.es/svn/trunk@518 a21b9725-9963-47de-94b9-378ad31fedc9

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