/*    Copyright (C) 1998-2003 XIAO, Gang of Universite de Nice - Sophia Antipolis
 
 *
 
 *  This program is free software; you can redistribute it and/or modify
 
 *  it under the terms of the GNU General Public License as published by
 
 *  the Free Software Foundation; either version 2 of the License, or
 
 *  (at your option) any later version.
 
 *
 
 *  This program 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 General Public License for more details.
 
 *
 
 *  You should have received a copy of the GNU General Public License
 
 *  along with this program; if not, write to the Free Software
 
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
 */
 
 
 
        /* Common routines in interfaces */
 
 
 
#define ch_root "bin/ch..root"
 
 
 
int mypid;
 
int must_chroot=0;
 
char inputfname[256], outputfname[256];
 
char pidfname[256];
 
char parmbuf[parmlim+16];
 
char *inpf, *outpf, *errorf;
 
char *parm;
 
char *tmp_dir;
 
char cmdbuf[1024];
 
char inputbuf[inputlim];
 
char *inputptr, *inputend;
 
char stdinbuf[MAX_LINELEN+1];
 
char *cmdparm;
 
int isabout=0;
 
char *multiexec_random;
 
int multiexec=0, mxpid, notfirst;
 
int pipe_in[2], pipe_out[2];
 
int debug=0;
 
FILE *goin;
 
unsigned int seed;      /* random seed value */
 
char aboutbuf[aboutlen];
 
        /* this is only a default. It should usually be reset. */
 
char *tmpdir="/tmp";
 
char startstring[256], endstring[256];
 
char *obuf;
 
 
 
void check_parm(char *p);
 
void output(char *p);
 
void about(void);
 
char *dynsetup(char *p, char *end);
 
 
 
void *xmalloc(size_t n)
 
{
 
    void *p;
 
    if(p==NULL) {
 
        fprintf(stderr
, "%s: Malloc failure.\n",progname
);  
    }
 
    return p;
 
}
 
 
 
        /* strip trailing spaces; return string end. */
 
char *strip_trailing_spaces(char *p)
 
{
 
    char *pp;
 
    if(*p==0) return p;
 
    return pp;
 
}
 
 
 
        /* Points to the end of the word */
 
char *find_word_end(char *p)
 
{
 
    int i;
 
    for(i
=0;!isspace(*p
) && *p
!=0 && i
<MAX_LINELEN
; p
++,i
++);  
    return p;
 
}
 
 
 
        /* Strips leading spaces */
 
char *find_word_start(char *p)
 
{
 
    int i;
 
    for(i
=0; isspace(*p
) && i
<MAX_LINELEN
; p
++,i
++);  
    return p;
 
}
 
 
 
        /* Find first occurrence of word */
 
char *wordchr(char *p, char *w)
 
{
 
    char *r;
 
 
 
    if(*w==0) return NULL;
 
    return r;
 
}
 
 
 
         /* Returns the pointer or NULL. */
 
char *varchr(char *p, char *v)
 
{
 
            if((pp
==p 
|| (!isalnum(*(pp
-1)) && *(pp
-1)!='_')) &&  
               ((!isalnum(*(pp
+n
)) && *(pp
+n
)!='_') || *(pp
+n
)==0)) break;  
        }
 
        return pp;
 
}
 
 
 
        /* find matching parenthesis */
 
char *find_matching(char *p, char c)
 
{
 
    char *pp;
 
    int parenth, brak, brace;
 
    parenth=brak=brace=0;
 
    for(pp=p; *pp!=0; pp++) {
 
        switch(*pp) {
 
            case '[': brak++; break;
 
            case ']': brak--; break;
 
            case '(': parenth++; break;
 
            case ')': parenth--; break;
 
            case '{': brace++; break;
 
            case '}': brace--; break;
 
            default: continue;
 
        }
 
        if(parenth<0 || brak<0 || brace<0) {
 
            if(*pp!=c || parenth>0 || brak>0 || brace>0) return NULL;
 
            else break;
 
        }
 
    }
 
    if(*pp!=c) return NULL;
 
    return pp;
 
}
 
 
 
        /* searches a list. Returns index if found, -1 if nomatch. 
 
         * Uses binary search, list must be sorted. */
 
int search_list(void *list, int items, size_t item_size, const char *str)
 
{
 
    int i1,i2,j,k;
 
    char **p;
 
    char c;
 
    
 
    if(items<=0) return -1;
 
    j=0; c=*str;
 
    p=list;
 
    k
=**p
-c
; if(k
==0) k
=strcmp(*p
,str
); 
    if(k==0) return k; if(k>0) return -1;
 
    p=list+(items-1)*item_size; 
 
    k
=**p
-c
; if(k
==0) k
=strcmp(*p
,str
); 
    if(k==0) return items-1; if(k<0) return -1;
 
    for(i1=0,i2=items-1;i2>i1+1;) {
 
        j=i1+(i2-i1)/2;
 
        p=list+(j*item_size);
 
        k
=**p
-c
; if(k
==0) k
=strcmp(*p
,str
); 
        if(k==0) return j;
 
        if(k>0) {i2=j; continue;}
 
        if(k<0) {i1=j; continue;}       
 
    }
 
    return -1;
 
}
 
 
 
        /* Read/write to a file with variable parms to print filename */
 
void accessfile(char *content, char *type, char *s,...)
 
{
 
    va_list vp;
 
    char buf[MAX_LINELEN+1];
 
    FILE *f;
 
    int l;
 
 
 
    vsnprintf(buf,sizeof(buf),s,vp);
 
    f
=fopen(buf
,type
); if(f
==NULL
) { 
        if(*type=='r') content[0]=0; return;
 
    }
 
    switch(*type) {
 
        case 'a':
 
        case 'w': {
 
        }
 
        case 'r': {
 
            l
=fread(content
,1,MAX_LINELEN
-1,f
); 
            if(l>0 && l<MAX_LINELEN) content[l]=0;
 
            else content[0]=0;
 
            break;
 
        }
 
        default: {
 
            content[0]=0; break;
 
        }
 
    }
 
}
 
 
 
void getstdin(void)
 
{
 
    char *p;
 
    int i,j,k;
 
    i=0; k=MAX_LINELEN; stdinbuf[0]=0;
 
    do {
 
        j=read(0,stdinbuf+i,k);
 
        i+=j; k-=j; stdinbuf[i]=0;
 
        p
=strstr(stdinbuf
,multiexec_random
); 
        if(p) {*p=0; break;}
 
    }
 
    while(k>0);
 
}
 
 
 
        /* add a pid to the list of running childs */
 
void addpid(int pid)
 
{
 
    char buf[MAX_LINELEN+1], pidbuf[32];
 
    int l;
 
    snprintf(pidbuf
,sizeof(pidbuf
),"%u",pid
);  
    accessfile
(buf
,"r",pidfname
); l
=strlen(buf
); 
    if(l>=MAX_LINELEN-64) return;
 
    if(wordchr(buf,pidbuf)==NULL) {
 
        snprintf(buf
+l
,sizeof(buf
)-l
," %s",pidbuf
);  
        accessfile(buf,"w",pidfname);
 
    }
 
}
 
 
 
        /* Remove a pidname to the list of running childs */
 
void rmpid(int pid)
 
{
 
    char buf[MAX_LINELEN+1], pidbuf[32], *p;
 
    snprintf(pidbuf
,sizeof(pidbuf
),"%u",pid
);  
    accessfile(buf,"r",pidfname);
 
    p=wordchr(buf,pidbuf);
 
    if(p!=NULL) {
 
        strcpy(p
,find_word_start
(find_word_end
(p
)));  
        accessfile(buf,"w",pidfname);
 
    }
 
}
 
 
 
int execredirected(char *cmdf, char *inf, char *outf, char *errf,
 
                   char *args)
 
{
 
    pid_t pid;
 
    int i;
 
    struct stat st;
 
    char *cm, *p, *p2, abuf[MAX_LINELEN+1];
 
    char *arg[1024];
 
 
 
    for(cm
=cmdf
; isspace(*cm
); cm
++); if(*cmdf
==0) return -1;  
    fflush(NULL
);       /* flush all output streams before forking  
                         * otherwise they will be doubled */
 
    pid=fork(); if(pid==-1) return -1;
 
    if(!pid) {  /* child */
 
        if(!inf) {
 
            dup2(pipe_in[0],0); close(pipe_in[1]);
 
        }
 
        if(!outf) {
 
            dup2(pipe_out[1],1); close(pipe_out[0]);
 
        }
 
        snprintf(abuf
,sizeof(abuf
),"%s",find_word_start
(args
));  
        if(stat("../chroot/tmp/sessions/.chroot",&st)==0 || must_chroot) {
 
            arg[0]=ch_root; i=1;
 
        }
 
        else {
 
            i=0;
 
            setreuid(getuid(),getuid());setregid(getgid(),getgid());
 
        }
 
        arg[i++]=cmdf;
 
        for(p=abuf; *p && i<1000; i++, p=find_word_start(p2)) {
 
            arg[i]=p; p2=find_word_end(p); if(*p2) *p2++=0;
 
        }
 
        arg[i]=NULL;
 
        if(strchr(arg
[0],'/')) execv
(arg
[0],arg
);  
        else execvp(arg[0],arg);
 
        fprintf(stderr
,"%s not_INStalled",progname
);  
    }
 
    else {      /* parent */
 
        addpid(pid); mxpid=pid;
 
        if(outf) {
 
            int status;
 
            close(pipe_in[1]);
 
            if(waitpid(pid,&status,0)==pid) {
 
                rmpid(pid); mxpid=-1;
 
            }
 
        }
 
    }
 
    return 0;
 
}
 
 
 
        /* verify illegal strings in parms. */
 
void find_illegal(char *p)
 
{
 
    char *pp, *pe;
 
    int i, l;
 
    for(pp=p;*pp;pp++) {
 
        if((*pp<' ' && *pp!='\n' && *pp!='      ') || *pp>=127) *pp=' ';
 
    }
 
    for(i=0;i<illpart_no;i++) {
 
                if(pp[1]!='j' && pp[1]!='J') pp[1]='J';
 
                else pp[1]='Z';
 
            }
 
        }
 
    }
 
    for(i=0;i<illegal_no;i++) {
 
                if(pp[1]!='j' && pp[1]!='J') pp[1]='J';
 
                else pp[1]='Z';
 
            }
 
        }
 
    }
 
}
 
 
 
        /* strip trailing zeros */
 
void strip_zeros(char *p)
 
{
 
    char *pp, *p2, *numend, *ee;
 
    int i;
 
    for(pp=p;*pp!=0;pp++) {
 
        i=0;
 
        for(numend
=pp
;isdigit(*numend
) || *numend
=='.';numend
++)  
          if(*numend=='.') i=1;
 
        if(i==0) {
 
            pp=numend-1;continue;
 
        }
 
        for(p2=numend;p2>pp && *(p2-1)=='0';p2--);
 
        if(*(pp+1)=='.' && (*ee=='E' || *ee=='e') 
 
           && *(ee+1)=='-') {
 
            int k=0;
 
            char *pt=ee+2;
 
                k*=10;k+=*pt-'0';pt++;
 
            }
 
            if(precision>8 && (k>precision*2 || (k>precision && *pp=='0'))) {
 
                
 
                
 
                continue;
 
            }
 
        }
 
        
 
        if(*(p2-1)=='.' && p2<numend) p2++; 
 
        
 
        if(p2<numend) {
 
        }
 
        pp=numend-1;
 
    }
 
}
 
 
 
char *hname[]={"", "_1","_2","_3","_4","_5","_6","_7","_8"};
 
#define hnameno (sizeof(hname)/sizeof(hname[0]))
 
 
 
void putheader(void)
 
{
 
    char hbuf[64];
 
    char *p;
 
    int i;
 
    
 
    inputptr=dynsetup(inputptr,inputend);
 
    snprintf(inputptr
,inputend
-inputptr
,"%s",header
);  
    for(i=0;i<hnameno;i++) {
 
        snprintf(hbuf
,sizeof(hbuf
),"w_%s_header%s",progname
,hname
[i
]);  
        p
=getenv(hbuf
); if(p
!=NULL 
&& *p
!=0) { 
            check_parm(parmbuf); 
 
            snprintf(inputptr
,inputend
-inputptr
,"%s\n",parmbuf
);  
        }
 
    }
 
}
 
 
 
void putparm(void)
 
{
 
    snprintf(parmbuf
,parmlim
,"%s",parm
); check_parm
(parmbuf
);  
    snprintf(inputptr
,inputend
-inputptr
,stringprinter
,startstring
);  
    snprintf(inputptr
,inputend
-inputptr
,"%s",parmbuf
);  
    if(inputptr<inputend && inputptr>inputbuf && inputptr[-1]!='\n')
 
      *inputptr++='\n';
 
    snprintf(inputptr
,inputend
-inputptr
,stringprinter
,endstring
);  
    *inputptr=0;
 
}
 
 
 
        /* general first preparation */
 
void prepare1(void)
 
{
 
    char *p, buf[256];
 
    int i;
 
    unsigned int r[4];
 
    struct timeval t;
 
 
 
    parm
=getenv("wims_exec_parm"); 
        /* nothing to do if no calling parameter */
 
    if(parm
==NULL 
|| *parm
==0) exit(0);  
    inputptr=inputbuf; inputend=inputbuf+inputlim-1;
 
    multiexec_random
=getenv("multiexec_random"); 
    if(multiexec_random==NULL) multiexec_random="";
 
    if(*parm 
&& strcmp(parm
,multiexec_random
)==0) {  
        multiexec=1;
 
        getstdin(); parm=stdinbuf;
 
    }
 
    if(pipe(pipe_in)<0 || pipe(pipe_out)<0) {
 
        fprintf(stderr
,"%s: unable to create pipe.\n",progname
);  
    }
 
/*    i=fcntl(pipe_in[1],F_GETFL); if(i>=0) fcntl(pipe_in[1],F_SETFL,i|O_NONBLOCK);
 
    i=fcntl(pipe_out[0],F_GETFL); if(i>=0) fcntl(pipe_out[0],F_SETFL,i|O_NONBLOCK);
 
*/    tmp_dir
=getenv("tmp_dir"); if(tmp_dir
==NULL 
|| *tmp_dir
==0) tmp_dir
=tmpdir
;  
    setenv("TMPDIR",tmp_dir,1);
 
    mypid=getpid();
 
    gettimeofday(&t,NULL); seed=t.tv_usec*t.tv_sec+mypid;
 
    srandom(seed);
 
    for(i=0;i<4;i++) r[i]=random();
 
    snprintf(startstring
,sizeof(startstring
),  
             "Start line %s %u %u %u %u",progname,r[0],r[1],r[2],r[3]);
 
             "End line %s %u %u %u %u",progname,r[0],r[1],r[2],r[3]);
 
    if(p!=NULL && *find_word_start(p)!=0) nameofcmd=find_word_start(p);
 
    snprintf(cmdbuf
,sizeof(cmdbuf
),"%s",nameofcmd
); nameofcmd
=cmdbuf
;  
    cmdparm=find_word_end(nameofcmd); if(*cmdparm) *cmdparm++=0;
 
    cmdparm=find_word_start(cmdparm);
 
    snprintf(pidfname
,sizeof(pidfname
),"%s/exec.pid",tmp_dir
); addpid
(mypid
);  
    snprintf(inputfname
,sizeof(inputfname
),"%s/%s_input.%d",tmp_dir
,progname
,mypid
);  
    snprintf(outputfname
,sizeof(outputfname
),"%s/%s_output.%d",tmp_dir
,progname
,mypid
);  
    errorf=NULL;
 
    inpf=inputfname; outpf=outputfname;
 
    isabout
=0; p
=find_word_start
(parm
); i
=strlen("about"); 
    if(memcmp(p
,"about",i
)==0 && *find_word_start
(p
+i
)==0) isabout
=1;  
    p
=getenv("multiexec_debug"); if(p 
&& strcmp(p
,"yes")==0) debug
=1; 
}
 
 
 
void prepabout(char *cmd, char *outf, char *errf)
 
{
 
    write
(pipe_in
[1],cmd
,strlen(cmd
)); 
    execredirected(nameofcmd,NULL,outf,errf,cmdparm);
 
}
 
 
 
        /* read to aboutbuf. Returns content length. */
 
int readabout(void)
 
{
 
    FILE *ff;
 
    long int l;
 
    char *p;
 
    
 
    aboutbuf
[0]=0; ff
=fopen(outputfname
,"r"); 
    if(ff!=NULL) {
 
        if(l>0 && l<aboutlen) aboutbuf[l]=0; else aboutbuf[0]=0;
 
        p
=find_word_start
(aboutbuf
); if(p
>aboutbuf
) strcpy(aboutbuf
,p
); 
    }
 
}
 
 
 
        /* read result of execution */
 
void readresult(void)
 
{
 
    FILE *ff;
 
    char *p, *pp, *pe;
 
 
 
    if(debug) {
 
        ff
=fopen(outputfname
,"a"); if(ff
) { 
        }
 
    }
 
    pe=NULL;
 
    if(p) {
 
        if(pe) {
 
            for(pp=pe-1; pp>=p && pp>pe-64 && *pp!='\n'; pp--);
 
            if(pp>=p && *pp=='\n') pe=pp;
 
        }
 
    }
 
    if(pe) {
 
        *pe=0;
 
        while((pe
=strstr(p
,startstring
))!=NULL
) {  
        }
 
        output(p);
 
    }
 
    else {
 
        if(mxpid>=0) {
 
            if(kill(mxpid,0)<0 && errno==ESRCH) {       /* this doesn't work */
 
                fprintf(stderr
,"%s not_INStalled",progname
);  
            }
 
            else {
 
                fprintf(stderr
,"%s: execution error or time out.\n",progname
);  
                kill(mxpid,SIGKILL);
 
            }
 
            rmpid(mxpid); mxpid=-1;
 
        }
 
        else {
 
            fprintf(stderr
,"%s: aborted on earlier error.\n",progname
);  
        }
 
    }
 
    if(multiexec 
&& *multiexec_random
) printf("%s\n",multiexec_random
);  
}
 
 
 
#ifdef linebyline1
 
 
 
        /* this one is for maxima but not used */
 
void dopipes(void)
 
{
 
    long int i, l;
 
    char *outptr;
 
    char *p1, *p2, *pp, *pe;
 
    struct timeval t;
 
    fd_set rset;
 
 
 
    if(mxpid<0) {
 
        *obuf=0; return;
 
    }
 
    outptr=obuf; pp=pe=NULL;
 
    for(p1=ibuf; *p1; p1=p2) {
 
        write(pipe_in[1],p1,p2-p1);
 
        
 
        if(strstr(p1
,startstring
)!=NULL
) iactive
=1;  
        reread:
 
        l=read(fifofd2,lp,MAX_LINELEN-(lp-lbuf));
 
        if(!iactive) continue;
 
        if(l<0 || l>MAX_LINELEN-(lp-lbuf)) l=0;
 
        lp+=l; *lp=0;
 
        if(active==0) {
 
            char *pp;
 
            if(pp!=NULL) {
 
            }
 
        }
 
        if(active
!=0 && strstr(lbuf
,linebyline
)!=NULL
) {  
            if(strstr(lbuf
,endstring
)!=NULL
) {lbuf
[0]=0; active
=-1; break;}  
            lbuf[0]=0; continue;
 
        }
 
        /* time out allowance between each silence */
 
        t.tv_sec=3; t.tv_usec=400000;
 
        i=select(fifofd2+1,&rset,NULL,NULL,&t);
 
        if(i>0) goto reread;
 
        else break; /* time out or error */
 
    }
 
}
 
 
 
#else
 
 
 
void dopipes(void)
 
{
 
    long int i, k, l;
 
    int interval=20000; /* in microseconds */
 
    int timeout =300;   /* in intervals */
 
    char *outptr;
 
    char *p1, *p2, *inp, *pw;
 
    struct timeval t;
 
    fd_set rset, wset;
 
 
 
    *obuf=0; if(mxpid<0) return;
 
    outptr=obuf; inp=inputbuf; k=0; 
 
    while(inp<inputptr) {
 
        t.tv_sec=0; t.tv_usec=interval;
 
        FD_ZERO(&rset); FD_SET(pipe_out[0],&rset);
 
        FD_ZERO(&wset); FD_SET(pipe_in[1],&wset);
 
        i=pipe_out[0]; if(i<pipe_in[1]) i=pipe_in[1];
 
        i=select(i+1,&rset,&wset,NULL,&t);
 
        if(i<=0) {
 
            k++; if(k>=timeout) return; /* time out */
 
        }
 
        if(FD_ISSET(pipe_in[1],&wset)) {
 
                /* Writing must be line by line, for otherwise
 
                 * it will block when the input is large. */
 
            for(pw=inp; pw<inputptr && *pw!='\n'; pw++);
 
            if(pw<inputptr) pw++;
 
            l=write(pipe_in[1],inp,pw-inp);
 
            if(l<0 || l>inputptr-inp) return;
 
            inp+=l;
 
        }
 
        if(FD_ISSET(pipe_out[0],&rset)) {
 
            l=read(pipe_out[0],outptr,fsizelim-(outptr-obuf)-1);
 
            if(l<=0 || l>fsizelim-(outptr-obuf)-1) {
 
                *outptr=0; break;
 
            }
 
            outptr+=l; *outptr=0;
 
        }
 
    }
 
    p2=NULL;
 
    if(p1) {
 
    }
 
    while(!p2) {
 
        t.tv_sec=0; t.tv_usec=interval;
 
        FD_ZERO(&rset); FD_SET(pipe_out[0],&rset);
 
        i=select(pipe_out[0]+1,&rset,NULL,NULL,&t);
 
        if(i>0) {
 
            l=read(pipe_out[0],outptr,fsizelim-(outptr-obuf)-1);
 
            if(l<=0 || l>fsizelim-(outptr-obuf)-1) {
 
                *outptr=0; break;
 
            }
 
            outptr+=l; *outptr=0;
 
        }
 
        else {
 
            k++; if(k>=timeout) break;
 
        }
 
        if(!p1) {
 
            if(p1
) p1
+=strlen(startstring
);  
        }
 
        if(p1
) p2
=strstr(p1
,endstring
);  
    }
 
}
 
 
 
#endif
 
 
 
void run(void)
 
{
 
    FILE *ff;
 
    
 
    if(isabout) {about(); goto end;}
 
    execredirected(nameofcmd,NULL,NULL,NULL,cmdparm);
 
    putheader();
 
    obuf=xmalloc(fsizelim); if(!obuf) return;
 
    rep:
 
    putparm();
 
    if(!multiexec) {
 
        snprintf(inputptr
,inputend
-inputptr
,"%s",quitstring
);  
    }
 
    if(debug) {
 
        ff
=fopen(inputfname
,"a"); if(ff
) { 
        }
 
    }
 
    dopipes();
 
    readresult();
 
    if(multiexec) {
 
        getstdin(); inputptr=inputbuf; inputbuf[0]=0;
 
        goto rep;
 
    }
 
    end
: if(strstr(tmp_dir
,"tmp/sessions/")==NULL
) { 
        unlink(inputfname); unlink(outputfname);
 
    }
 
    free(obuf
); rmpid
(mypid
);  
    if(mxpid>0) {kill(mxpid,SIGKILL); rmpid(mxpid);}
 
}