Skip to content
Snippets Groups Projects
xtrn.cpp 40.5 KiB
Newer Older
		if(mode&EX_OUTR)
			if(pipe(out_pipe)!=0) {
				errormsg(WHERE,ERR_CREATE,"out_pipe",0);
				return(-1);
			}


		if((pid=fork())==-1) {
			pthread_mutex_unlock(&input_thread_mutex);
			errormsg(WHERE,ERR_EXEC,cmdline,0);
	}
	if(pid==0) {	/* child process */
		if(startup_dir!=NULL && startup_dir[0])
			chdir(startup_dir);
		lprintf("Node %d executing external: %s",cfg.node_num,cmdline);
		if(mode&EX_SH || strcspn(cmdline,"<>|;")!=strlen(cmdline)) {
			argv[0]=comspec;
			argv[1]="-c";
			argv[2]=cmdline;
			argv[3]=NULL;
		} else {
			argv[0]=cmdline;	/* point to the beginning of the string */
			argc=1;
			for(i=0;cmdline[i] && argc<MAX_ARGS;i++)	/* Break up command line */
				if(cmdline[i]==SP) {
					cmdline[i]=0;			/* insert nulls */
					argv[argc++]=cmdline+i+1; /* point to the beginning of the next arg */
				}
			argv[argc]=NULL;
		}
		if(mode&EX_INR && !(mode&EX_OUTR))  {
			close(in_pipe[1]);		/* close write-end of pipe */
			dup2(in_pipe[0],0);		/* redirect stdin */
			close(in_pipe[0]);		/* close excess file descriptor */
		}
		if(mode&EX_OUTR && !(mode&EX_INR)) {
			close(out_pipe[0]);		/* close read-end of pipe */
			dup2(out_pipe[1],1);	/* stdout */
			dup2(out_pipe[1],2);	/* stderr */
			close(out_pipe[1]);		/* close excess file descriptor */
		if(mode&EX_BG)	/* background execution, detach child */
		{
			if(fork())
				exit(0);
			lprintf("Detaching external process pgid=%d",setsid());
		execvp(argv[0],argv);
		sprintf(str,"!ERROR %d executing %s",errno,argv[0]);
		errorlog(str);
		exit(-1);	/* should never get here */
		if(!(mode&EX_INR))
			close(out_pipe[1]);	/* close write-end of pipe */
			if(waitpid(pid, &i, WNOHANG)!=0)	/* child exited */
				break;
			if(!online && !(mode&EX_OFFLINE)) {
				sprintf(str,"%s hung-up in external program",useron.alias);
				logline("X!",str);
				break;
			}

			/* Input */	
			if(mode&EX_INR && RingBufFull(&inbuf)) {
				if((wr=RingBufRead(&inbuf,buf,sizeof(buf)))!=0)
					write(in_pipe[1],buf,wr);
			}
				
			/* Output */
			ioctl(out_pipe[0],FIONREAD,&rd);	/* peek at input */
			if(!rd) {
				mswait(1);
				continue;
			}
#else
			FD_ZERO(&ibits);
			FD_SET(out_pipe[0],&ibits);
			timeout.tv_sec=0;
			timeout.tv_usec=0;
			if(!select(out_pipe[0]+1,&ibits,NULL,NULL,&timeout))  {
				mswait(1);
				continue;
			}
#endif

			avail=RingBufFree(&outbuf);
			if(avail==0) {
				lprintf("Node %d !output buffer full (%u bytes)"
						,cfg.node_num,RingBufFull(&outbuf));
				rd=sizeof(buf);

			if((rd=read(out_pipe[0],buf,rd))<1) {
			if(mode&EX_BIN)	/* telnet IAC expansion */
   	       		bp=telnet_expand(buf, rd, output_buf, output_len);
			else			/* LF to CRLF expansion */
				bp=lf_expand(buf, rd, output_buf, output_len);
			
			/* Does expanded size fit? */
			if(output_len>RingBufFree(&outbuf)) {
				lprintf("Node %d !output buffer overflow (%u bytes)"
					,cfg.node_num,output_len);
				mswait(1);
				continue;
			}
			RingBufWrite(&outbuf, bp, output_len);
			sem_post(&output_sem);	
		}
		if(waitpid(pid, &i, WNOHANG)==0)  {		// Child still running? 
			kill(pid, SIGHUP);					// Tell child user has hung up
			time_t start=time(NULL);			// Wait up to 10 seconds
			while(time(NULL)-start<10) {		// for child to terminate
				if(waitpid(pid, &i, WNOHANG)!=0)
					break;
				mswait(500);
			}
			if(waitpid(pid, &i, WNOHANG)==0)	// Child still running?
				kill(pid, SIGKILL);				// terminate child process
		}
		/* close unneeded descriptors */
		if(mode&EX_INR)
			close(in_pipe[1]);
		close(out_pipe[0]);
	waitpid(pid, &i, 0); /* Wait for child to terminate */

	pthread_mutex_unlock(&input_thread_mutex);

	return(WEXITSTATUS(i));
uint fakeriobp=0xffff;

/*****************************************************************************/
/* Returns command line generated from instr with %c replacments             */
/*****************************************************************************/
char * sbbs_t::cmdstr(char *instr, char *fpath, char *fspec, char *outstr)
{
	char	str[256],*cmd;
    int		i,j,len;

    if(outstr==NULL)
        cmd=cmdstr_output;
    else
        cmd=outstr;
    len=strlen(instr);
    for(i=j=0;i<len && j<(int)sizeof(cmdstr_output);i++) {
        if(instr[i]=='%') {
            i++;
            cmd[j]=0;
			char ch=instr[i];
			if(isalpha(ch))
				ch=toupper(ch);
            switch(ch) {
                case 'A':   /* User alias */
                    strcat(cmd,useron.alias);
                    break;
                case 'B':   /* Baud (DTE) Rate */
                    strcat(cmd,ultoa(dte_rate,str,10));
                    break;
                case 'C':   /* Connect Description */
                    strcat(cmd,connection);
                    break;
                case 'D':   /* Connect (DCE) Rate */
                    strcat(cmd,ultoa((ulong)cur_rate,str,10));
                    break;
                case 'E':   /* Estimated Rate */
                    strcat(cmd,ultoa((ulong)cur_cps*10,str,10));
                    break;
                case 'F':   /* File path */
                    strcat(cmd,fpath);
                    break;
                case 'G':   /* Temp directory */
                    strcat(cmd,cfg.temp_dir);
                    break;
                case 'H':   /* Port Handle or Hardware Flow Control */
#if defined(__unix__)
					strcat(cmd,ultoa(client_socket,str,10));
#else
                    strcat(cmd,ultoa(client_socket_dup,str,10));
                    break;
                case 'I':   /* UART IRQ Line */
                    strcat(cmd,ultoa(cfg.com_irq,str,10));
                    break;
                case 'J':
                    strcat(cmd,cfg.data_dir);
                    break;
                case 'K':
                    strcat(cmd,cfg.ctrl_dir);
                    break;
                case 'L':   /* Lines per message */
                    strcat(cmd,ultoa(cfg.level_linespermsg[useron.level],str,10));
                    break;
                case 'M':   /* Minutes (credits) for user */
                    strcat(cmd,ultoa(useron.min,str,10));
                    break;
                case 'N':   /* Node Directory (same as SBBSNODE environment var) */
                    strcat(cmd,cfg.node_dir);
                    break;
                case 'O':   /* SysOp */
                    strcat(cmd,cfg.sys_op);
                    break;
                case 'P':   /* COM Port */
                    strcat(cmd,ultoa(online==ON_LOCAL ? 0:cfg.com_port,str,10));
                    break;
                case 'Q':   /* QWK ID */
                    strcat(cmd,cfg.sys_id);
                    break;
                case 'R':   /* Rows */
                    strcat(cmd,ultoa(rows,str,10));
                    break;
                case 'S':   /* File Spec */
                    strcat(cmd,fspec);
                    break;
                case 'T':   /* Time left in seconds */
                    gettimeleft();
                    strcat(cmd,ultoa(timeleft,str,10));
                    break;
                case 'U':   /* UART I/O Address (in hex) */
                    strcat(cmd,ultoa(cfg.com_base,str,16));
                    break;
                case 'V':   /* Synchronet Version */
                    sprintf(str,"%s%c",VERSION,REVISION);
                    break;
                case 'W':   /* Time-slice API type (mswtype) */
#if 0 //ndef __FLAT__
                    strcat(cmd,ultoa(mswtyp,str,10));
#endif
                    break;
                case 'X':
                    strcat(cmd,cfg.shell[useron.shell]->code);
                    break;
                case '&':   /* Address of msr */
                    sprintf(str,"%lu",(DWORD)&fakeriobp);
                    strcat(cmd,str);
                    break;
                case 'Y':
                    break;
                case 'Z':
                    strcat(cmd,cfg.text_dir);
                    break;
				case '~':	/* DOS-compatible (8.3) filename */
#ifdef _WIN32
					GetShortPathName(fpath,sfpath,sizeof(sfpath));
					strcat(cmd,sfpath);
#else
                    strcat(cmd,fpath);
#endif			
					break;
                case '!':   /* EXEC Directory */
                    strcat(cmd,cfg.exec_dir);
                    break;
                case '#':   /* Node number (same as SBBSNNUM environment var) */
                    sprintf(str,"%d",cfg.node_num);
                    strcat(cmd,str);
                    break;
                case '*':
                    sprintf(str,"%03d",cfg.node_num);
                    strcat(cmd,str);
                    break;
                case '$':   /* Credits */
                    strcat(cmd,ultoa(useron.cdt+useron.freecdt,str,10));
                    break;
                case '%':   /* %% for percent sign */
                    strcat(cmd,"%");
                    break;
				case '.':	/* .exe for DOS/OS2/Win32, blank for Unix */
#ifndef __unix__
					strcat(cmd,".exe");
#endif
					break;
				case '?':	/* Platform */
#ifdef __OS2__
					strcpy(str,"OS2");
#else
                default:    /* unknown specification */
                    if(isdigit(instr[i])) {
                        sprintf(str,"%0*d",instr[i]&0xf,useron.number);
                        strcat(cmd,str); }
                    break; }
            j=strlen(cmd); }
        else
            cmd[j++]=instr[i]; }
    cmd[j]=0;

    return(cmd);
}

#ifdef __unix__
void
setup_term(int fd)
{
	struct termios tt;
	// Shoud set speed here...

	tcgetattr(fd, &tt);
	tt.c_iflag = TTYDEF_IFLAG;
	tt.c_oflag = TTYDEF_OFLAG;
	tt.c_lflag = TTYDEF_LFLAG;
	tcsetattr(fd, TCSAFLUSH, &tt);

	setenv("TERM","ansi-bbs",1);
	/* The following termcap entry is nice:

<---SNIP--->
# Handy for HyperTerminal and such
ansi-bbs|ANSI terminals (emulators):\
        :co#80:li#24:am:\
        :bs:mi:ms:pt:xn:xo:it#8:\
        :RA=\E[?7l:SA=\E?7h:\
        :bl=^G:cr=^M:ta=^I:\
        :@7=\E[K:kh=\E[H::cm=\E[%i%d;%dH:\
        :le=^H:up=\E[A:do=\E[B:nd=\E[C:\
        :LE=\E[%dD:RI=\E[%dC:UP=\E[%dA:DO=\E[%dB:\
        :ho=\E[H:cl=\E[H\E[2J:ce=\E[K:cb=\E[1K:cd=\E[J:sf=\ED:sr=\EM:\
        :ct=\E[3g:st=\EH:\
        :cs=\E[%i%d;%dr:sc=\E7:rc=\E8:\
        :ic=\E[@:IC=\E[%d@:al=\E[L:AL=\E[%dL:\
        :dc=\E[P:DC=\E[%dP:dl=\E[M:DL=\E[%dM:\
        :so=\E[7m:se=\E[m:us=\E[4m:ue=\E[m:\
        :mb=\E[5m:mh=\E[2m:md=\E[1m:mr=\E[7m:me=\E[m:\
        :sc=\E7:rc=\E8:\
        :ku=\E[A:kd=\E[B:kr=\E[C:kl=\E[D:\
        :ZG#0:ZA=\E[0%?%p1%{0}%>%p1%{4}%<%&%t;1%;%?%p2%t;7%;%?%p3%t;5%;%?%p4%t;4%;m:\
        :is=:rs=\Ec:kb=^H:\
        :as=\E[m:ae=:eA=:\
        :ac=0\333+\257,\256.\031-\030a\261f\370g\361j\331k\277l\332m\300n\305q\304t\264u\303v\301w\302x\263~\025:\
        :kD=\177:kH=\E[Y:kN=\E[U:kP=\E[V:\
        :kj=\177::kf=\E[U:kg=\E[V:\
        :k0=\EOP:k1=\EOQ:k2=\EOR:k3=\EOS:k4=\EOT:\
        :k5=\EOU:k6=\EOV:k7=\EOW:k8=\EOX:k9=\EOY:\
        :gb=\332\300\277\331\304\263:\
        :Co#8:pa#64:so=\E[7m:se=\E[27m:AF=\E[3%dm:AB=\E[4%dm:op=\E[39;49m:

<---SNIP--->

	*/
}
#endif