|
|
DataMuseum.dkPresents historical artifacts from the history of: Commodore CBM-900 |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about Commodore CBM-900 Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - download
Length: 36289 (0x8dc1)
Types: TextFile
Notes: UNIX file
Names: »cu.c«
└─⟦f27320a65⟧ Bits:30001972 Commodore 900 hard disk image with partial source code
└─⟦0a3c255ba⟧ UNIX Filesystem
└─⟦this⟧ »cu_src/cu.c«
/* @(#)cu.c 1.4 */
#define ddt
/***************************************************************
* cu [-s baud] [-l line] [-h] [-d] [-p] [-t] [-o | -e] telno
*
* legal baud rates: 110,134,150,300,600,1200,2400,4800,9600.
*
* -l is for specifying a line unit from the file whose
* name is defined under LDEVS below.
* -h is for half-duplex (local echoing).
* -t is for adding CR to LF on output to remote (for terminals).
* -d can be used (with ddt) to get some tracing & diagnostics.
* -o or -e is for odd or even parity on transmission to remote.
* Telno is a telephone number with `=' for secondary dial-tone.
* If "-l dev" is used, speed is taken from LDEVS.
*
* Escape with `~' at beginning of line.
* Silent output diversions are ~>:filename and ~>>:filename.
* Terminate output diversion with ~> alone.
* ~. is quit, and ~![cmd] gives local shell [or command].
* Also ~$ for canned local procedure pumping remote.
* Both ~%put from [to] and ~%take from [to] invoke built-ins.
* Also, ~%break or just ~%b will transmit a BREAK to remote.
* ~%nostop toggles on/off the DC3/DC1 input control from remote,
* (certain remote systems cannot cope with DC3 or DC1).
*
* As a device-lockout semaphore mechanism, create an entry
* in the directory #defined as LOCK whose name is LCK..dev
* where dev is the device name taken from the "line" column
* in the file #defined as LDEVS. Be sure to trap every possible
* way out of cu execution in order to "release" the device.
* This entry is `touched' from the dial() library routine
* every hour in order to keep uucp from removing it on
* its 90 minute rounds. Also, have the system start-up
* procedure clean all such entries from the LOCK directory.
*
* Modified by Sanford Zelkovitz to include Xmodem transfers
* and telephone directory lookup ( -p on the command line ).
* The file, /usr/lib/uucp/dirCU, has the following format
* per entry:
* name baudrate telephone_number comments
* An example of an entry for me:
* alphacm 2400 17148280288 XBBS
*
***************************************************************/
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <sys/termio.h>
#include <sys/errno.h>
#include <setjmp.h>
#include "dial.h"
#define LOW 1200 /* default speed for modems */
#define HIGH 2400 /* high speed for modems */
#define MID BUFSIZ/2 /* mnemonic */
#define RUB '\177' /* mnemonic */
#define XON '\21' /* mnemonic */
#define XOFF '\23' /* mnemonic */
#define TTYIN 0 /* mnemonic */
#define TTYOUT 1 /* mnemonic */
#define TTYERR 2 /* mnemonic */
#define YES 1 /* mnemonic */
#define NO 0 /* mnemonic */
#define EQUALS !strcmp /* mnemonic */
#define EXIT 0 /* exit code */
#define CMDERR 1 /* exit code */
#define NODIAL 2 /* exit code */
#define HUNGUP 3 /* exit code */
#define IOERR 4 /* exit code */
#define SIGQIT 5 /* exit code */
#define NOFORK 6 /* exit code */
#define CRCR "/usr/bin/crcCU r "
#define CRCS "/usr/bin/crcCU s "
#define DIREC "/usr/lib/uucp/dirCU"
extern int
_debug, /* flag for more diagnostics */
errno, /* supplied by system interface */
optind, /* variable in getopt() */
strcmp(); /* c-lib routine */
extern unsigned
sleep(); /* c-lib routine */
extern char
*optarg; /* variable in getopt() */
static struct termio tv, tv0; /* for saving, changing TTY atributes */
static struct termio lv; /* attributes for the line to remote */
static CALL call; /* from dial.h */
static char
cxc, /* place into which we do character io*/
tintr, /* current input INTR */
tquit, /* current input QUIT */
terase, /* current input ERASE */
tkill, /* current input KILL */
myeol, /* current input EOL */
teol, /* current sencondary input EOL */
myeof; /* current input EOF */
static int
terminal=NO, /* flag; remote is a terminal */
echoe, /* save users ECHOE bit */
echok, /* save users ECHOK bit */
rlfd, /* fd for remote comm line */
child, /* pid for recieve proccess */
intrupt=NO, /* interrupt indicator */
duplex=YES, /* half(NO), or full(YES) duplex */
sstop=YES, /* NO means remote can't XON/XOFF */
rtn_code=0, /* default return code */
takeflag=NO, /* indicates a ~%take is in progress */
w_char(), /* local io routine */
r_char(); /* local io routine */
static
onintrpt(), /* interrupt routine */
rcvdead(), /* interrupt routine */
hangup(), /* interrupt routine */
quit(), /* interrupt routine */
bye(); /* interrupt routine */
static void
flush(),
shell(),
dopercen(),
receive(),
mode(),
say(),
#ifdef ddt
tdmp(),
#endif
w_str();
char *msg[]= {
/* 0*/ "usage: %s [-s baud] [-l line] [-h] [-t] [-p] [-d] [-m] [-o|-e] telno\n",
/* 1*/ "interrupt",
/* 2*/ "dialer hung",
/* 3*/ "no answer",
/* 4*/ "illegal baud-rate",
/* 5*/ "acu problem",
/* 6*/ "line problem",
/* 7*/ "can't open L-devices file",
/* 8*/ "Requested device not available\r\n",
/* 9*/ "Requested device not known\r\n",
/* 10*/ "No device available at %d baud\r\n",
/* 11*/ "No device known at %d baud\r\n",
/* 12*/ "Connect failed: %s\r\n",
/* 13*/ "Can not open: %s\r\n",
/* 14*/ "Line gone\r\n",
/* 15*/ "Can't execute shell\r\n",
/* 16*/ "Can't divert %s\r\n",
/* 17*/ "Use `~~' to start line with `~'\r\n",
/* 18*/ "character missed\r\n",
/* 19*/ "after %ld bytes\r\n",
/* 20*/ "%d lines/%ld characters\r\n",
/* 21*/ "Only digits & '-'s or '='s in telno\n",
/* 22*/ "File transmission interrupted\r\n",
/* 23*/ "Cannot fork -- try later\r\n",
/* 24*/ "\r\nCan't transmit special character `%#o'\r\n",
/* 25*/ "\nLine too long\r\n",
/* 26*/ "r\nIO error\r\n",
/* 27*/ "Use `~$'cmd \r\n",
/* 28*/ "Unable to locate phone directory\r\n",
/* 29*/ "Unable to locate requested entry in the telephone directory\n\r",
};
char xstring[50];
char crc_buff[100];
char in_string[50];
char CUname[20], CUbaud[6], CUtele[20];
int result;
FILE *xyz;
jmp_buf mark;
int markint;
/***************************************************************
* main: get command line args, establish connection, and fork.
* Child invokes "receive" to read from remote & write to TTY.
* Main line invokes "transmit" to read TTY & write to remote.
***************************************************************/
main(argc, argv)
char *argv[];
{
char *string, *tstring;
int i, errflag=0;
lv.c_iflag = (IGNPAR | IGNBRK | ISTRIP | IXON | IXOFF);
lv.c_cc[VMIN] = '\1';
call.attr = &lv;
call.baud = LOW;
call.speed = LOW;
call.line = NULL;
call.telno = NULL;
call.modem = 0;
strcpy(xstring,"ATDT");
while((i = getopt(argc, argv, "dhteoms:p:l:")) != EOF)
switch(i) {
case 'd':
#ifdef ddt
_debug = YES;
#else
++errflag;
#endif
break;
case 'h':
duplex ^= YES;
lv.c_iflag &= ~(IXON | IXOFF);
sstop = NO;
break;
case 't':
terminal = YES;
lv.c_oflag |= (OPOST | ONLCR);
break;
case 'e':
if(lv.c_cflag & PARENB)
++errflag;
else
goto PAROUT;
break;
case 'o':
if(lv.c_cflag & PARENB)
++errflag;
else
lv.c_cflag = PARODD;
PAROUT:
lv.c_cflag |= (CS7 | PARENB);
break;
case 's':
call.baud = atoi(optarg);
if(call.baud > LOW)
call.speed = HIGH;
break;
case 'p':
strcpy(in_string,optarg);
if((xyz = fopen(DIREC,"r")) == NULL)
{
say(msg[28]);
exit (1);
}
while ((fscanf(xyz,"%s%s%s",CUname,CUbaud,CUtele)) != EOF)
{
if((strcmp(CUname,in_string)) == 0)
{
call.baud = atoi(CUbaud);
if(call.baud > LOW)
call.speed = HIGH;
strcat(xstring,CUtele);
goto around;
}
while ((fgetc(xyz)) != '\n');
}
say(msg[29]);
exit (1);
case 'l':
call.line = optarg;
break;
case 'm':
call.modem = 1; /* override modem control for direct lines */
break;
case '?':
++errflag;
}
if(optind < argc && optind > 0) {
tstring = argv[optind];
strcat(xstring,argv[optind]);
around:
strcat(xstring,"\r");
string = xstring;
if(strlen(string) == strspn(string, "ATDZ0123456789=-\r"))
call.telno = string;
else {
if(EQUALS(tstring, "dir")) {
if(call.line == NULL)
++errflag;
} else
++errflag;
}
} else
if(call.line == NULL)
++errflag;
if(errflag) {
say(msg[0], argv[0]);
exit(1);
}
(void)ioctl(TTYIN, TCGETA, &tv0); /* save initial tty state */
tintr = tv0.c_cc[VINTR]? tv0.c_cc[VINTR]: '\377';
tquit = tv0.c_cc[VQUIT]? tv0.c_cc[VQUIT]: '\377';
terase = tv0.c_cc[VERASE]? tv0.c_cc[VERASE]: '\377';
tkill = tv0.c_cc[VKILL]? tv0.c_cc[VKILL]: '\377';
teol = tv0.c_cc[VEOL]? tv0.c_cc[VEOL]: '\377';
myeol = (tv0.c_iflag & ICRNL)? '\r': '\n';
myeof = tv0.c_cc[VEOF]? tv0.c_cc[VEOF]: '\04';
echoe = tv0.c_lflag & ECHOE;
echok = tv0.c_lflag & ECHOK;
(void)signal(SIGHUP, hangup);
(void)signal(SIGQUIT, hangup);
(void)signal(SIGINT, onintrpt);
if((rlfd = dial(call)) < 0) {
if(rlfd == NO_BD_A || rlfd == NO_BD_K)
say(msg[-rlfd], call.baud);
else
say(msg[12], msg[-rlfd]);
exit(NODIAL);
}
/* When we get this far we have an open communication line */
mode(1); /* put terminal in `raw' mode */
xyz = fopen("/tmp/dev.CU","w");
fprintf(xyz, "%d", rlfd);
fclose(xyz);
markint = setjmp(mark);
child = dofork();
if(child == 0) {
(void)signal(SIGHUP, rcvdead);
(void)signal(SIGQUIT, SIG_IGN);
(void)signal(SIGINT, SIG_IGN);
(void)signal(SIGCLD, SIG_IGN);
receive(); /* This should run until killed */
/*NOTREACHED*/
} else if(child > 0) {
(void)signal(SIGUSR1, bye);
(void)signal(SIGHUP, SIG_IGN);
(void)signal(SIGQUIT, onintrpt);
rtn_code = transmit();
quit(rtn_code);
} else {
hangup(rlfd);
exit(NOFORK);
}
}
\f
/***************************************************************
* transmit: copy stdin to rlfd, except:
* ~. terminate
* ~! local login-style shell
* ~!cmd execute cmd locally
* ~$proc execute proc locally, send output to line
* ~%cmd execute builtin cmd (put, take, or break)
* ~X xmodem interface
****************************************************************/
int
transmit()
{
char b[BUFSIZ];
register char *p;
register int escape;
#ifdef ddt
if(_debug == YES) say("transmit started\n\r");
#endif
while(1) {
p = b;
while(r_char(TTYIN) == YES) {
if(p == b) /* Escape on leading ~ */
escape = (cxc == '~');
if(p == b+1) /* But not on leading ~~ */
escape &= (cxc != '~');
if(escape) {
if(cxc == myeol || cxc == teol) {
*p = '\0';
if(tilda(b+1) == YES)
return(EXIT);
break;
}
if(cxc == tintr || cxc == tkill || cxc == tquit ||
(intrupt && cxc == '\0')) {
if(!(cxc == tkill) || echok)
say("\r\n");
break;
}
if(cxc == terase) {
p = (--p < b)? b:p;
if(p > b)
if(echoe)
say("\b \b");
else
(void)w_char(TTYOUT);
} else {
(void)w_char(TTYOUT);
if(p-b < BUFSIZ)
*p++ = cxc;
else {
say(msg[25]);
break;
}
}
} else {
if(intrupt && cxc == '\0') {
#ifdef ddt
if(_debug == YES)
say("got break in transmit\n\r");
#endif
intrupt = NO;
(void)ioctl(rlfd, TCSBRK, 0);
flush();
break;
}
if(w_char(rlfd) == NO) {
say(msg[14]);
return(IOERR);
}
if(duplex == NO)
if(w_char(TTYERR) == NO)
return(IOERR);
if ( (cxc == tintr) || (cxc == tquit) || ( (p==b) && (cxc == myeof) ) ) {
#ifdef ddt
if(_debug == YES) say("got a tintr\n\r");
#endif
flush();
break;
}
if(cxc == myeol || cxc == teol ||
cxc == tkill) {
takeflag = NO;
break;
}
p = (char*)0;
}
}
}
}
/***************************************************************
* routine to halt input from remote and flush buffers
***************************************************************/
static void
flush()
{
(void)ioctl(TTYOUT, TCXONC, 0); /* stop tty output */
(void)ioctl(rlfd, TCFLSH, 0); /* flush remote input */
(void)ioctl(TTYOUT, TCFLSH, 1); /* flush tty output */
(void)ioctl(TTYOUT, TCXONC, 1); /* restart tty output */
if(takeflag == NO) {
return; /* didn't interupt file transmission */
}
say(msg[22]);
(void)sleep(3);
w_str("echo '\n~>\n';mesg y;stty echo\n");
takeflag = NO;
}
/**************************************************************
* command interpreter for escape lines
**************************************************************/
int
tilda(cmd)
char *cmd;
{
char resp[50];
say("\r\n");
#ifdef ddt
if(_debug == YES) say("call tilda(%s)\r\n", cmd);
#endif
switch(cmd[0]) {
case '.':
if(call.telno == NULL)
if(cmd[1] != '.')
w_str("\04\04\04\04\04");
return(YES);
case '!':
shell(cmd); /* local shell */
say("\r%c\r\n", *cmd);
break;
case '$':
if(cmd[1] == '\0')
say(msg[27]);
else {
shell(cmd); /* Local shell */
say("\r%c\r\n", *cmd);
}
break;
case '%':
dopercen(++cmd);
break;
#ifdef ddt
case 't':
tdmp(TTYIN);
break;
case 'l':
tdmp(rlfd);
break;
#endif
/* xmodem section */
case 'X':
mode(0);
(void)kill(child,SIGKILL);
printf("\n\rReceive or Send (R S)? ");
scanf("%s",resp);
switch (resp[0]){
case 's' :
case 'S' :
printf("\n\rInput file name to send: ");
scanf("%s",in_string);
printf("\n\r");
strcpy(crc_buff,CRCS);
strcat(crc_buff,in_string);
result = system(crc_buff);
mode(1);
longjmp(mark, -1);
case 'r' :
case 'R' :
printf("\n\rInput file name to receive: ");
scanf("%s",in_string);
printf("\n\r");
strcpy(crc_buff,CRCR);
strcat(crc_buff,in_string);
result = system(crc_buff);
mode(1);
longjmp(mark, -1);
default :
printf("\n\rIllegial Xmodem Option \n\r");
mode(1);
longjmp(mark, -1);
}
default:
say(msg[17]);
}
return(NO);
}
/***************************************************************
* The routine "shell" takes an argument starting with
* either "!" or "$", and terminated with '\0'.
* If $arg, arg is the name of a local shell file which
* is executed and its output is passed to the remote.
* If !arg, we escape to a local shell to execute arg
* with output to TTY, and if arg is null, escape to
* a local shell and blind the remote line. In either
* case, RUBout or '^D' will kill the escape status.
**************************************************************/
static void
shell(str)
char *str;
{
int fk, (*xx)(), (*yy)();
#ifdef ddt
if(_debug == YES) say("call shell(%s)\r\n", str);
#endif
fk = dofork();
if(fk < 0)
return;
mode(0); /* restore normal tty attributes */
xx = signal(SIGINT, SIG_IGN);
yy = signal(SIGQUIT, SIG_IGN);
if(fk == 0) {
/***********************************************
* Hook-up our "standard output"
* to either the tty or the line
* as appropriate for '!' or '$'
***********************************************/
(void)close(TTYOUT);
(void)fcntl((*str == '$')? rlfd:TTYERR,F_DUPFD,TTYOUT);
(void)close(rlfd);
(void)signal(SIGINT, SIG_DFL);
(void)signal(SIGHUP, SIG_DFL);
(void)signal(SIGQUIT, SIG_DFL);
(void)signal(SIGUSR1, SIG_DFL);
if(*++str == '\0')
(void)execl("/bin/sh","",(char*)0,(char*)0,0);
else
(void)execl("/bin/sh","sh","-c",str,0);
say(msg[15]);
exit(0);
}
/* our hourly alarm clock (for uucp) can interupt this wait */
while(wait((int*)0) != fk);
(void)signal(SIGINT, xx);
(void)signal(SIGQUIT, yy);
mode(1);
}
/***************************************************************
* This function implements the 'put', 'take', 'break', and
* 'nostop' commands which are internal to cu.
***************************************************************/
static void
dopercen(cmd)
register char *cmd;
{
char *arg[5];
int narg;
#ifdef ddt
if(_debug == YES) say("call dopercen(\"%s\")\r\n", cmd);
#endif
arg[narg=0] = strtok(cmd, " \t\n");
/* following loop breaks out the command and args */
while((arg[++narg] = strtok((char*) NULL, " \t\n")) != NULL) {
if(narg < 5)
continue;
else
break;
}
if(EQUALS(arg[0], "take")) {
if(narg < 2 || narg > 3) {
say("usage: ~%%take from [to]\r\n");
return;
}
if(narg == 2)
arg[2] = arg[1];
w_str("stty -echo;mesg n;echo '~>':");
w_str(arg[2]);
w_str(";cat ");
w_str(arg[1]);
w_str(";echo '~>';mesg y;stty echo\n");
takeflag = YES;
return;
}
else if(EQUALS(arg[0], "put")) {
FILE *file;
char ch, buf[BUFSIZ], spec[NCC+1], *b, *p, *q;
int i, j, len, tc=0, lines=0;
long chars=0L;
if(narg < 2 || narg > 3) {
say("usage: ~%%put from [to]\r\n");
goto R;
}
if(narg == 2)
arg[2] = arg[1];
if((file = fopen(arg[1], "r")) == NULL) {
say(msg[13], arg[1]);
R:
w_str("\n");
return;
}
w_str("stty -echo; cat - > ");
w_str(arg[2]);
w_str("; stty echo\n");
intrupt = NO;
for(i=0,j=0; i < NCC; ++i)
if((ch=tv0.c_cc[i]) != '\0')
spec[j++] = ch;
spec[j] = '\0';
mode(2);
(void)sleep(5);
while(intrupt == NO &&
fgets(b= &buf[MID],MID,file) != NULL) {
len = strlen(b);
chars += len; /* character count */
p = b;
while(q = strpbrk(p, spec)) {
if(*q == tintr || *q == tquit ||
*q == teol) {
say(msg[24], *q);
(void)strcpy(q, q+1);
intrupt = YES;
}
b = strncpy(b-1, b, q-b);
*(q-1) = '\\';
p = q+1;
}
if((tc += len) >= MID) {
(void)sleep(1);
tc = len;
}
if(write(rlfd, b, (unsigned)strlen(b)) < 0) {
say(msg[26]);
intrupt = YES;
break;
}
++lines; /* line count */
}
mode(1);
(void)fclose(file);
if(intrupt == YES) {
intrupt = NO;
say(msg[22]);
w_str("\n");
say(msg[19], ++chars);
} else
say(msg[20], lines, chars);
w_str("\04");
(void)sleep(3);
return;
}
else if(EQUALS(arg[0], "b") || EQUALS(arg[0], "break")) {
(void)ioctl(rlfd, TCSBRK, 0);
return;
}
else if(EQUALS(arg[0], "nostop")) {
(void)ioctl(rlfd, TCGETA, &tv);
if(sstop == NO)
tv.c_iflag |= IXOFF;
else
tv.c_iflag &= ~IXOFF;
(void)ioctl(rlfd, TCSETAW, &tv);
sstop = !sstop;
mode(1);
return;
}
say("~%%%s unknown to cu\r\n", arg[0]);
}
/***************************************************************
* receive: read from remote line, write to fd=1 (TTYOUT)
* catch:
* ~>[>]:file
* .
* . stuff for file
* .
* ~> (ends diversion)
***************************************************************/
static void
receive()
{
register silent=NO, file;
register char *p;
int tic;
char b[BUFSIZ];
long lseek(), count;
#ifdef ddt
if(_debug == YES) say("receive started\r\n");
#endif
file = -1;
p = b;
while(r_char(rlfd) == YES) {
if(silent == NO)
if(w_char(TTYOUT) == NO)
rcvdead(IOERR); /* this will exit */
/* remove CR's and fill inserted by remote */
if(cxc == '\0' || cxc == '\177' || cxc == '\r')
continue;
*p++ = cxc;
if(cxc != '\n' && (p-b) < BUFSIZ)
continue;
/***********************************************
* The rest of this code is to deal with what
* happens at the beginning, middle or end of
* a diversion to a file.
************************************************/
if(b[0] == '~' && b[1] == '>') {
/****************************************
* The line is the beginning or
* end of a diversion to a file.
****************************************/
if((file < 0) && (b[2] == ':' || b[2] == '>')) {
/**********************************
* Beginning of a diversion
*********************************/
int append;
*(p-1) = '\0'; /* terminate file name */
append = (b[2] == '>')? 1:0;
p = b + 3 + append;
if(append && (file=open(p,O_WRONLY))>0)
(void)lseek(file, 0L, 2);
else
file = creat(p, 0666);
if(file < 0) {
say(msg[16], p);
perror("");
(void)sleep(10);
} else {
silent = YES;
count = tic = 0;
}
} else {
/*******************************
* End of a diversion (or queer data)
*******************************/
if(b[2] != '\n')
goto D; /* queer data */
if(silent = close(file)) {
say(msg[16], b);
silent = NO;
}
say("~>\r\n");
say(msg[20], tic, count);
file = -1;
}
} else {
/***************************************
* This line is not an escape line.
* Either no diversion; or else yes, and
* we've got to divert the line to the file.
***************************************/
D:
if(file > 0) {
(void)write(file, b, (unsigned)(p-b));
count += p-b; /* tally char count */
++tic; /* tally lines */
}
}
p = b;
}
rcvdead(IOERR);
}
/***************************************************************
* change the TTY attributes of the users terminal:
* 0 means restore attributes to pre-cu status.
* 1 means set `raw' mode for use during cu session.
* 2 means like 1 but accept interrupts from the keyboard.
***************************************************************/
static void
mode(arg)
{
#ifdef ddt
if(_debug == YES) say("call mode(%d)\r\n", arg);
#endif
if(arg == 0) {
(void)ioctl(TTYIN, TCSETAW, &tv0);
} else {
(void)ioctl(TTYIN, TCGETA, &tv);
if(arg == 1) {
tv.c_iflag &= ~(INLCR | ICRNL | IGNCR |
IXOFF | IUCLC);
tv.c_iflag |= ISTRIP;
tv.c_oflag |= OPOST;
tv.c_oflag &= ~(OLCUC | ONLCR | OCRNL | ONOCR
| ONLRET);
tv.c_lflag &= ~(ICANON | ISIG | ECHO);
if(sstop == NO)
tv.c_iflag &= ~IXON;
else
tv.c_iflag |= IXON;
if(terminal) {
tv.c_oflag |= ONLCR;
tv.c_iflag |= ICRNL;
}
tv.c_cc[VEOF] = '\01';
tv.c_cc[VEOL] = '\0';
}
if(arg == 2) {
tv.c_iflag |= IXON;
tv.c_lflag |= ISIG;
}
(void)ioctl(TTYIN, TCSETAW, &tv);
}
}
static int
dofork()
{
register int x, i=0;
while(++i < 6)
if((x = fork()) >= 0)
return(x);
#ifdef ddt
if(_debug == YES) perror("dofork");
#endif
say(msg[23]);
return(x);
}
static int
r_char(fd)
{
int rtn;
while((rtn = read(fd, &cxc, 1)) < 0)
if(errno == EINTR)
if(intrupt == YES) {
cxc = '\0'; /* got a BREAK */
return(YES);
} else
continue; /* alarm went off */
else {
#ifdef ddt
if(_debug == YES)
say("got read error, not EINTR\n\r");
#endif
break; /* something wrong */
}
return(rtn == 1? YES: NO);
}
static int
w_char(fd)
{
int rtn;
while((rtn = write(fd, &cxc, 1)) < 0)
if(errno == EINTR)
if(intrupt == YES) {
say("\ncu: Output blocked\r\n");
quit(IOERR);
} else
continue; /* alarm went off */
else
break; /* bad news */
return(rtn == 1? YES: NO);
}
/*VARARGS1*/
static void
say(fmt, arg1, arg2, arg3, arg4, arg5)
char *fmt;
{
(void)fprintf(stderr, fmt, arg1, arg2, arg3, arg4, arg5);
}
static void
w_str(string)
register char *string;
{
int len;
len = strlen(string);
if(write(rlfd, string, (unsigned)len) != len)
say(msg[14]);
}
static
onintrpt()
{
(void)signal(SIGINT, onintrpt);
(void)signal(SIGQUIT, onintrpt);
intrupt = YES;
}
static
rcvdead(arg) /* this is executed only in the receive proccess */
int arg;
{
#ifdef ddt
if(_debug == YES) say("call rcvdead(%d)\r\n", arg);
#endif
(void)kill(getppid(), SIGUSR1);
exit((arg == SIGHUP)? SIGHUP: arg);
/*NOTREACHED*/
}
static
quit(arg) /* this is executed only in the parent proccess */
int arg;
{
#ifdef ddt
if(_debug == YES) say("call quit(%d)\r\n", arg);
#endif
(void)kill(child, SIGKILL);
bye(arg);
/*NOTREACHED*/
}
static
bye(arg) /* this is executed only in the parent proccess */
int arg;
{
int status;
#ifdef ddt
if(_debug == YES) say("call bye(%d)\r\n", arg);
#endif
(void)wait(&status);
say("\r\nDisconnected\r\n");
hangup((arg == SIGUSR1)? (status >>= 8): arg);
/*NOTREACHED*/
}
static
hangup(arg) /* this is executed only in the parent proccess */
int arg;
{
#ifdef ddt
if(_debug == YES) say("call hangup(%d)\r\n", arg);
#endif
undial(rlfd);
mode(0); /* restore users prior tty status */
exit(arg);
/*NOTREACHED*/
}
#ifdef ddt
static void
tdmp(arg)
{
struct termio xv;
int i;
say("\rdevice status for fd=%d\n", arg);
say("\rF_GETFL=%o,", fcntl(arg, F_GETFL,1));
if(ioctl(arg, TCGETA, &xv) < 0) {
char buf[100];
i = errno;
(void)sprintf(buf, "\rtdmp for fd=%d", arg);
errno = i;
perror(buf);
return;
}
say("iflag=`%o',", xv.c_iflag);
say("oflag=`%o',", xv.c_oflag);
say("cflag=`%o',", xv.c_cflag);
say("lflag=`%o',", xv.c_lflag);
say("line=`%o'\r\n", xv.c_line);
say("cc[0]=`%o',", xv.c_cc[0]);
for(i=1; i<8; ++i)
say("[%d]=`%o',", i, xv.c_cc[i]);
say("\r\n");
}
#endif