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);

rswindell
committed
return(-1);
}
}
if(pid==0) { /* child process */
setup_term(0);
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)) {

rswindell
committed
close(in_pipe[1]); /* close write-end of pipe */
dup2(in_pipe[0],0); /* redirect stdin */
close(in_pipe[0]); /* close excess file descriptor */
}

rswindell
committed
if(mode&EX_OUTR && !(mode&EX_INR)) {

rswindell
committed
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 */

rswindell
committed
}
if(mode&EX_BG) /* background execution, detach child */
{
if(fork())
exit(0);
lprintf("Detaching external process pgid=%d",setsid());
}
sprintf(str,"!ERROR %d executing %s",errno,argv[0]);
errorlog(str);
exit(-1); /* should never get here */

rswindell
committed
if(mode&EX_OUTR) {
if(!(mode&EX_INR))
close(out_pipe[1]); /* close write-end of pipe */
while(!terminated) {

rswindell
committed
if(waitpid(pid, &i, WNOHANG)!=0) /* child exited */
break;
if(mode&EX_CHKTIME)
gettimeleft();

rswindell
committed
if(!online && !(mode&EX_OFFLINE)) {
sprintf(str,"%s hung-up in external program",useron.alias);
logline("X!",str);
break;
}

rswindell
committed
/* Input */
if(mode&EX_INR && RingBufFull(&inbuf)) {
if((wr=RingBufRead(&inbuf,buf,sizeof(buf)))!=0)
write(in_pipe[1],buf,wr);
}
/* Output */
#if 0

rswindell
committed
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));
mswait(1);
continue;
}
#if 0
if(rd>(int)avail)
#endif
rd=avail;
if(rd>(int)sizeof(buf))
rd=sizeof(buf);
if((rd=read(out_pipe[0],buf,rd))<1) {

rswindell
committed
mswait(1);
continue;
}

rswindell
committed
if(mode&EX_BIN) /* telnet IAC expansion */
bp=telnet_expand(buf, rd, output_buf, output_len);

rswindell
committed
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;
}

rswindell
committed
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]);

rswindell
committed
}

rswindell
committed
waitpid(pid, &i, 0); /* Wait for child to terminate */
pthread_mutex_unlock(&input_thread_mutex);
return(WEXITSTATUS(i));
}
#endif /* !WIN32 */
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) {
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
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));
#endif
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 */
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__
#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':
strcat(cmd,comspec);
break;
case 'Z':
strcat(cmd,cfg.text_dir);
break;
case '~': /* DOS-compatible (8.3) filename */
#ifdef _WIN32
char sfpath[MAX_PATH+1];
SAFECOPY(sfpath,fpath);
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
strcpy(str,PLATFORM_DESC);
#endif
strlwr(str);
strcat(cmd,str);
break;
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);
}
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
#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