source: ogBrowser-Git/qtermwidget/src/k3process.cpp @ 9d8d163

jenkinsmain
Last change on this file since 9d8d163 was 050d67a, checked in by adelcastillo <adelcastillo@…>, 16 years ago

Ahora el browser tiene consola en vez del output.
Pasado todo el sistema de compilacion a cmake.

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