You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdebase/kioslave/floppy/program.cpp

202 lines
4.8 KiB

/* 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(&notifSet);
FD_SET(notificationPipe[0],&notifSet);
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,&notifSet,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);
}