|
|
|
/* This file is part of the KDE project
|
|
|
|
Copyright (C) 2000-2002 Alexander Neundorf <neundorf@kde.org>
|
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU Library General Public
|
|
|
|
License as published by the Free Software Foundation; either
|
|
|
|
version 2 of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
Library General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Library General Public License
|
|
|
|
along with this library; see the file COPYING.LIB. If not, write to
|
|
|
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
|
|
Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
#include "program.h"
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <sys/ioctl.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/time.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <sys/wait.h>
|
|
|
|
#include <signal.h>
|
|
|
|
|
|
|
|
#include <kdebug.h>
|
|
|
|
|
|
|
|
Program::Program(const TQStringList &args)
|
|
|
|
:m_pid(0)
|
|
|
|
,mArgs(args)
|
|
|
|
,mStarted(false)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
Program::~Program()
|
|
|
|
{
|
|
|
|
if (m_pid!=0)
|
|
|
|
{
|
|
|
|
::close(mStdin[0]);
|
|
|
|
::close(mStdout[0]);
|
|
|
|
::close(mStderr[0]);
|
|
|
|
|
|
|
|
::close(mStdin[1]);
|
|
|
|
::close(mStdout[1]);
|
|
|
|
::close(mStderr[1]);
|
|
|
|
|
|
|
|
int s(0);
|
|
|
|
//::wait(&s);
|
|
|
|
::waitpid(m_pid,&s,0);
|
|
|
|
this->kill();
|
|
|
|
::waitpid(m_pid,&s,WNOHANG);
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Program::start()
|
|
|
|
{
|
|
|
|
if (mStarted) return false;
|
|
|
|
if (pipe(mStdout)==-1) return false;
|
|
|
|
if (pipe(mStdin )==-1) return false;
|
|
|
|
if (pipe(mStderr )==-1) return false;
|
|
|
|
|
|
|
|
int notificationPipe[2];
|
|
|
|
if (pipe(notificationPipe )==-1) return false;
|
|
|
|
|
|
|
|
m_pid=fork();
|
|
|
|
|
|
|
|
if (m_pid>0)
|
|
|
|
{
|
|
|
|
//parent
|
|
|
|
::close(mStdin[0]);
|
|
|
|
::close(mStdout[1]);
|
|
|
|
::close(mStderr[1]);
|
|
|
|
::close(notificationPipe[1]);
|
|
|
|
mStarted=true;
|
|
|
|
fd_set notifSet;
|
|
|
|
FD_ZERO(¬ifSet);
|
|
|
|
FD_SET(notificationPipe[0],¬ifSet);
|
|
|
|
struct timeval tv;
|
|
|
|
//wait up to five seconds
|
|
|
|
|
|
|
|
kdDebug(7101)<<"**** waiting for notification"<<endl;
|
|
|
|
//0.2 sec
|
|
|
|
tv.tv_sec=0;
|
|
|
|
tv.tv_usec=1000*200;
|
|
|
|
int result=::select(notificationPipe[0]+1,¬ifSet,0,0,&tv);
|
|
|
|
/* if (result<1)
|
|
|
|
{
|
|
|
|
kdDebug(7101)<<"**** waiting for notification: failed "<<result<<endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else*/
|
|
|
|
if(result==1)
|
|
|
|
{
|
|
|
|
char buf[256];
|
|
|
|
result=::read(notificationPipe[0],buf,256);
|
|
|
|
//if execvp() failed the child sends us "failed"
|
|
|
|
if (result>0)
|
|
|
|
return false;
|
|
|
|
};
|
|
|
|
kdDebug(7101)<<"**** waiting for notification: succeeded"<<result<<endl;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else if (m_pid==-1)
|
|
|
|
{
|
|
|
|
//failed
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else if (m_pid==0)
|
|
|
|
{
|
|
|
|
::close(notificationPipe[0]);
|
|
|
|
|
|
|
|
//child
|
|
|
|
::close(0); // close the stdios
|
|
|
|
::close(1);
|
|
|
|
::close(2);
|
|
|
|
|
|
|
|
dup(mStdin[0]);
|
|
|
|
dup(mStdout[1]);
|
|
|
|
dup(mStderr[1]);
|
|
|
|
|
|
|
|
::close(mStdin[1]);
|
|
|
|
::close(mStdout[0]);
|
|
|
|
::close(mStderr[0]);
|
|
|
|
|
|
|
|
fcntl(mStdin[0], F_SETFD, FD_CLOEXEC);
|
|
|
|
fcntl(mStdout[1], F_SETFD, FD_CLOEXEC);
|
|
|
|
fcntl(mStderr[1], F_SETFD, FD_CLOEXEC);
|
|
|
|
|
|
|
|
char **arglist=(char**)malloc((mArgs.count()+1)*sizeof(char*));
|
|
|
|
int c=0;
|
|
|
|
|
|
|
|
for (TQStringList::Iterator it=mArgs.begin(); it!=mArgs.end(); ++it)
|
|
|
|
{
|
|
|
|
arglist[c]=(char*)malloc((*it).length()+1);
|
|
|
|
strcpy(arglist[c], (*it).latin1());
|
|
|
|
c++;
|
|
|
|
}
|
|
|
|
arglist[mArgs.count()]=0;
|
|
|
|
//make parsing easier
|
|
|
|
putenv(strdup("LANG=C"));
|
|
|
|
execvp(arglist[0], arglist);
|
|
|
|
//we only get here if execvp() failed
|
|
|
|
::write(notificationPipe[1],"failed",strlen("failed"));
|
|
|
|
::close(notificationPipe[1]);
|
|
|
|
_exit(-1);
|
|
|
|
};
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Program::isRunning()
|
|
|
|
{
|
|
|
|
return mStarted;
|
|
|
|
}
|
|
|
|
|
|
|
|
int Program::select(int secs, int usecs, bool& stdoutReceived, bool& stderrReceived/*, bool& stdinWaiting*/)
|
|
|
|
{
|
|
|
|
stdoutReceived=false;
|
|
|
|
stderrReceived=false;
|
|
|
|
|
|
|
|
struct timeval tv;
|
|
|
|
tv.tv_sec=secs;
|
|
|
|
tv.tv_usec=usecs;
|
|
|
|
|
|
|
|
fd_set readFDs;
|
|
|
|
FD_ZERO(&readFDs);
|
|
|
|
FD_SET(stdoutFD(),&readFDs);
|
|
|
|
FD_SET(stderrFD(),&readFDs);
|
|
|
|
|
|
|
|
int maxFD=stdoutFD();
|
|
|
|
if (stderrFD()>maxFD) maxFD=stderrFD();
|
|
|
|
|
|
|
|
/*fd_set writeFDs;
|
|
|
|
FD_ZERO(&writeFDs);
|
|
|
|
FD_SET(stdinFD(),&writeFDs);
|
|
|
|
if (stdinFD()>maxFD) maxFD=stdinFD();*/
|
|
|
|
maxFD++;
|
|
|
|
|
|
|
|
int result=::select(maxFD,&readFDs,/*&writeFDs*/0,0,&tv);
|
|
|
|
if (result>0)
|
|
|
|
{
|
|
|
|
stdoutReceived=FD_ISSET(stdoutFD(),&readFDs);
|
|
|
|
stderrReceived=FD_ISSET(stderrFD(),&readFDs);
|
|
|
|
//stdinWaiting=(FD_ISSET(stdinFD(),&writeFDs));
|
|
|
|
};
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
int Program::kill()
|
|
|
|
{
|
|
|
|
if (m_pid==0)
|
|
|
|
return -1;
|
|
|
|
return ::kill(m_pid, SIGTERM);
|
|
|
|
//::kill(m_pid, SIGKILL);
|
|
|
|
}
|
|
|
|
|