#ifdef RCS
static char rcsid[]=
"$Id: pipes.c,v 1.73 2001/08/27 08:43:59 guenther Exp $";
#endif
#include "procmail.h"
#include "robust.h"
#include "shell.h"
#include "misc.h"
#include "memblk.h"
#include "pipes.h"
#include "common.h"
#include "mcommon.h"
#include "foldinfo.h"
#include "mailfold.h"
#include "goodies.h"
#include "variables.h"
static const char comma[]=",";
pid_t pidchild;
volatile time_t alrmtime;
volatile int toutflag;
static char*lastexec,*backblock;
static long backlen;
static pid_t pidfilt;
static int pbackfd[2];
int pipw;
#define PRDO poutfd[0]
#define PWRO poutfd[1]
#define PRDI pinfd[0]
#define PWRI pinfd[1]
#define PRDB pbackfd[0]
#define PWRB pbackfd[1]
void inittmout(progname)const char*const progname;
{ lastexec=cstr(lastexec,progname);toutflag=0;
alrmtime=timeoutv?time((time_t*)0)+(unsigned)timeoutv:0;
alarm((unsigned)timeoutv);
}
void ftimeout P((void))
{ alarm(0);alrmtime=0;toutflag=1;nlog("Timeout, ");
elog(pidchild>0&&!kill(pidchild,SIGTERM)?"terminating":"was waiting for");
logqnl(lastexec);signal(SIGALRM,(void(*)())ftimeout);
}
void resettmout P((void))
{ if(alrmtime)
alarm((unsigned)(alrmtime=0));
}
static void stermchild P((void))
{ static const char rescdata[]="Rescue of unfiltered data ";
if(pidfilt>0)
kill(pidfilt,SIGTERM);
rawnonl=1;
if(PWRB<0);
else if(dump(PWRB,ft_PIPE,backblock,backlen))
nlog(rescdata),elog("failed\n");
else if(verbose||pwait!=4)
nlog(rescdata),elog("succeeded\n");
exit(lexitcode);
}
static void childsetup P((void))
{ lexitcode=EX_UNAVAILABLE;qsignal(SIGTERM,stermchild);
qsignal(SIGINT,stermchild);qsignal(SIGHUP,stermchild);
qsignal(SIGQUIT,stermchild);shutdesc();
}
static void getstdin(pip)const int pip;
{ rclose(STDIN);rdup(pip);rclose(pip);
}
static void callnewprog(newname)const char*const newname;
{
#ifdef RESTRICT_EXEC
if(erestrict&&uid>=RESTRICT_EXEC)
{ syslog(LOG_ERR,slogstr,"Attempt to execute",newname);
nlog("No permission to execute");logqnl(newname);
return;
}
#endif
if(sh)
{ const char*newargv[4];
yell(executing,newname);newargv[3]=0;newargv[2]=newname;
newargv[1]=shellflags;*newargv=tgetenv(shell);shexec(newargv);
}
;{ register const char*p;int argc;
argc=1;p=newname;
if(verbose)
{ nlog(executing);elog(oquote);
goto no_1st_comma;
}
do
{ if(verbose)
{ elog(comma);
no_1st_comma:
elog(p);
}
while(*p++);
if(verbose&&p-1==All_args&&crestarg)
{ const char*const*walkargs=restargv;
goto No_1st_comma;
do
{ elog(comma);
No_1st_comma: elog(*walkargs);
}
while(*++walkargs);
}
if(p-1==All_args)
argc+=crestarg-1;
}
while(argc++,p!=Tmnate);
if(verbose)
elog(cquote);
;{ const char**newargv;
newargv=malloc(argc*sizeof*newargv);p=newname;argc=0;
do
{ newargv[argc++]=p;
while(*p++);
if(p-1==All_args&&crestarg)
{ const char*const*walkargs=restargv;
argc--;
while(newargv[argc]= *walkargs++)
argc++;
}
}
while(p!=Tmnate);
newargv[argc]=0;shexec(newargv);
}
}
}
int pipthrough(line,source,len)char*line,*source;const long len;
{ int pinfd[2],poutfd[2];char*eq;
if(Stdout)
{ *(eq=strchr(Stdout,'\0')-1)='\0';
if(!(backblock=getenv(Stdout)))
PRDB=PWRB= -1;
else
{ backlen=strlen(backblock);
goto pip;
}
}
else
pip: rpipe(pbackfd);
rpipe(pinfd);
if(!(pidchild=sfork()))
{ if(Stdout&&backblock)
backlen=strlen(backblock);
else
backblock=source,backlen=len;
childsetup();rclose(PRDI);rclose(PRDB);
rpipe(poutfd);rclose(STDOUT);
if(!(pidfilt=sfork()))
{ rclose(PWRB);rclose(PWRO);rdup(PWRI);rclose(PWRI);getstdin(PRDO);
callnewprog(line);
}
rclose(PWRI);rclose(PRDO);
if(forkerr(pidfilt,line))
rclose(PWRO),stermchild();
if(dump(PWRO,ft_PIPE,source,len)&&!ignwerr)
writeerr(line),lexitcode=EX_IOERR,stermchild();
;{ int excode;
if(pwait&&(excode=waitfor(pidfilt))!=EXIT_SUCCESS)
{ pidfilt=0;
if(pwait&2)
{ pwait=4;
if(verbose)
goto perr;
}
else
perr: progerr(line,excode,pwait==4);
stermchild();
}
}
rclose(PWRB);exit(EXIT_SUCCESS);
}
rclose(PWRB);rclose(PWRI);getstdin(PRDI);
if(forkerr(pidchild,procmailn))
return -1;
if(Stdout)
{ char*name;memblk temp;
*eq='=';name=Stdout;Stdout=0;primeStdout(name);free(name);
makeblock(&temp,Stdfilled);
tmemmove(temp.p,Stdout,Stdfilled);
readdyn(&temp,&Stdfilled,Stdfilled+backlen+1);
Stdout=realloc(Stdout,&Stdfilled+1);
tmemmove(Stdout,temp.p,Stdfilled+1);
freeblock(&temp);
retStdout(Stdout,pwait&&pipw,!backblock);
return pipw;
}
return 0;
}
long pipin(line,source,len,asgnlastf)char*const line;char*source;long len;
int asgnlastf;
{ int poutfd[2];
#if 0
if(!sh)
{ const char*t1,*t2,*t3;
static const char pbuiltin[]="Builtin";
t1=strchr(line,'\0')+1;
if(!strcmp(test,line))
{ if(t1!=Tmnate)
{ t2=strchr(t1,'\0')+1;
if(t2!=Tmnate)
{ t3=strchr(t2,'\0')+1;
if(t3!=Tmnate&&!strcmp(t2,"=")&&strchr(t3,'\0')==Tmnate-1)
{ int excode;
if(verbose)
{ nlog(pbuiltin);elog(oquote);elog(test);elog(comma),
if(!ignwerr)
writeerr(line);
else
len=0;
if(pwait&&(excode=strcmp(t1,t3)?1:EXIT_SUCCESS)!=EXIT_SUCCESS)
{ if(!(pwait&2)||verbose)
progerr(line,excode,pwait&2);
len=1;
}
goto builtin;
}
}
}
}
}
#endif
rpipe(poutfd);
if(!(pidchild=sfork()))
rclose(PWRO),shutdesc(),getstdin(PRDO),callnewprog(line);
rclose(PRDO);
if(forkerr(pidchild,line))
{ rclose(PWRO);
return -1;
}
if((len=dump(PWRO,ft_PIPE,source,len))&&(!ignwerr||(len=0)))
writeerr(line);
;{ int excode;
if(pwait&&(excode=waitfor(pidchild))!=EXIT_SUCCESS)
{ if(!(pwait&2)||verbose)
progerr(line,excode,pwait&2);
len=1;
}
}
pidchild=0;
builtin:
if(!sh)
concatenate(line);
if(asgnlastf)
setlastfolder(line);
return len;
}
static char*read_read(p,left,data)char*p;long left;void*data;
{ long got;
do
if(0>=(got=rread(STDIN,p,left)))
return p;
while(p+=got,left-=got);
return 0;
}
static int read_cleanup(mb,filledp,origfilled,data)memblk*mb;
long*filledp,origfilled;void*data;
{ long oldfilled= *(long*)data;
if(pidchild>0)
{ if(PRDB>=0)
{ getstdin(PRDB);
if(1==rread(STDIN,buf,1))
{ resizeblock(mb,oldfilled,0);
mb->p[origfilled]= *buf;
*filledp=origfilled+1;
PRDB= -1;pwait=2;
return 1;
}
}
if(pwait)
pipw=waitfor(pidchild);
}
pidchild=0;
return 0;
}
char*readdyn(mb,filled,oldfilled)memblk*const mb;long*const filled,oldfilled;
{ return read2blk(mb,filled,&read_read,&read_cleanup,&oldfilled);
}
char*fromprog(name,dest,max)char*name;char*const dest;size_t max;
{ int pinfd[2],poutfd[2];int i;char*p;
concon('\n');rpipe(pinfd);inittmout(name);
if(!(pidchild=sfork()))
{ Stdout=name;childsetup();rclose(PRDI);rpipe(poutfd);rclose(STDOUT);
if(!(pidfilt=sfork()))
rclose(PWRO),rdup(PWRI),rclose(PWRI),getstdin(PRDO),callnewprog(name);
rclose(PWRI);rclose(PRDO);
if(forkerr(pidfilt,name))
rclose(PWRO),stermchild();
dump(PWRO,ft_PIPE,themail.p,filled);waitfor(pidfilt);exit(lexitcode);
}
rclose(PWRI);p=dest;
if(!forkerr(pidchild,name))
{ name=tstrdup(name);
while(0<(i=rread(PRDI,p,(int)max))&&(p+=i,max-=i));
if(0<rread(PRDI,p,1))
{ nlog("Excessive output quenched from");logqnl(name);
setoverflow();
}
else
while(--p>=dest&&*p=='\n');
rclose(PRDI);free(name);
p++;waitfor(pidchild);
}
else
rclose(PRDI);
resettmout();
pidchild=0;*p='\0';
return p;
}
void exectrap(tp)const char*const tp;
{ int forceret;
forceret=setexitcode(*tp);
if(*tp)
{ int poutfd[2];
rawnonl=0;
metaparse(tp);concon('\n');
rpipe(poutfd);inittmout(buf);
if(!(pidchild=sfork()))
{ rclose(PWRO);getstdin(PRDO);rclose(STDOUT);rdup(STDERR);
callnewprog(buf);
}
rclose(PRDO);
if(!forkerr(pidchild,buf))
{ int newret;
dump(PWRO,ft_PIPE,themail.p,filled);
if((newret=waitfor(pidchild))!=EXIT_SUCCESS&&forceret==-2)
retval=newret;
pidchild=0;
}
else
rclose(PWRO);
resettmout();
}
}