Xinu7/src/cmd/download/cmd/odt.c
#include "/usr/include/stdio.h"
#include "/usr/include/sgtty.h"
#include "/usr/include/signal.h"
#include "/usr/include/sys/types.h"
#include "/usr/include/sys/stat.h"
#include "/usr/include/sys/file.h"
#include <getdev.h>
#include <baud.h>
/************************************************************************/
/* */
/* program: */
/* odt -- talk to an LSI 11 from a VAX UNIX terminal */
/* */
/* synopsis: */
/* odt [-lx] */
/* */
/* description: */
/* lsi attaches a user's terminal to a tty line that connects */
/* to an LSI 11 so that keystrokes typed at the terminal are */
/* sent to the LSI 11, and characters that the LSI 11 emits */
/* are sent to the terminal display (without any processing). */
/* The standard input, standard output, and standard error */
/* files remain attached to the terminal. File descriptor */
/* lsifd is attached to the LSI 11 tty line. A backslash / */
/* causes lsi to change the keyboard mode to RAW for the next */
/* character, making it possible to send special characters */
/* like interrupt or kill characters. Echo is turned off when */
/* lsi begins. Thus, any echoing of keystrokes is coming from */
/* the LSI 11. */
/* */
/* Normally, odt looks for any available LSI 11. The argument */
/* -lx restricts the search to the LSI 11 with "number" x. */
/* */
/* Author/status: */
/* Doug Comer, based on a program by Bob Brown */
/* CS Dept., Purdue University */
/* */
/* Modification history: */
/* 12/86 -- Tom Stonecypher */
/* deleted shell escape */
/* modified -t argument to bypass reference to database */
/* */
/************************************************************************/
#define STDOUT 1
#define STDIN 0
#ifndef TRUE
#define TRUE 1
#define FALSE 0
typedef int Bool;
#endif
int devfd = -1; /* line tty file descriptor */
int flags;
int quit(); /* procedure called to quit */
int quit2(); /* safe interim quit procedure */
struct sgttyb Lttymode; /* line tty mode upon entry */
struct sgttyb lttymode; /* line tty mode for gtty/stty */
struct sgttyb kttymode; /* keyboard mode upon entry */
struct sgttyb cttymode; /* changed keyboard mode */
int baudrate; /* rate line tty should be at */
int timeout; /* time keyboard can be idle */
int pid; /* process id of this process */
char *class; /* group of machines to use */
int machnum; /* number of requested machine */
char *dev;
char *lockfile; /* name of lock file */
DevDesc *Dev;
/*
*========================
* M a i n E n t r y
*========================
*/
main(argc, argv)
int argc;
char *argv[];
{
int tandem;
int i;
int fUsedb;
if (ioctl(STDIN, TIOCGETP, &kttymode) < 0 ) {
perror("Cannot set terminal modes");
exit(1);
}
signal(SIGINT, quit2); /* safe handler for parent and child
to execute until fork has completed
and both have reset the handler */
class = NULL;
machnum = GD_ANYDEV;
flags = 0;
baudrate = B9600;
timeout = -1;
tandem = TRUE;
fUsedb = TRUE;
for ( ; argc > 1; --argc) {
if (**++argv != '-') {
fprintf(stderr, "Argument %s unexpected.\n", *argv);
exit(1);
}
switch (*++argv[0]) {
case 'c':
class = ++argv[0];
break;
case 'l':
if (sscanf(++argv[0], "%d", &machnum) != 1) {
fprintf(stderr, "Illegal device number: %s\n",
argv[0]);
exit(1);
}
break;
case 'h':
flags |= GD_HLDDEVS;
break;
case 't':
dev = ++argv[0];
fUsedb = FALSE;
break;
case 'B':
if (*++argv[0] == '\0') {
baudrate = NOBAUD;
break;
}
for (i = 0; i < NBAUD; ++i)
if (strcmp(baudlist[i].name, argv[0]) == 0)
break;
if (i < NBAUD)
baudrate = baudlist[i].rate;
else {
fprintf(stderr, "Unknown baud rate: %s\n",
argv[0]);
exit(1);
}
break;
case 'T':
if (*++argv[0] == '\0')
timeout = 0;
else if (sscanf(argv[0], "%d", &timeout) != 1 ||
timeout < 0) {
fprintf(stderr,"Illegal timeout period: %s\n",
argv[0]);
exit(1);
}
break;
case 'f':
tandem = FALSE;
break;
default:
fprintf(stderr, "Usage: odt [-cclass] [-lnumber] [-Bbaudrate] [-Ttimeout] [-f] [-h]\n");
exit(1);
}
}
if (fUsedb) {
Dev = getdev(class, machnum, flags);
if (Dev == NULL)
exit(1);
printf("Using %s\n", shortname(Dev->machine));
devfd = Dev->fd;
touch(lockfile = Dev->locknm);
if (timeout < 0)
timeout = atoi(get_limit(Dev->class));
dev = get_name(Dev->machine);
} else {
if ( (devfd = open(dev, O_RDWR, 0)) < 0) {
fprintf(stderr, "Cannot open %s\n", dev);
exit(1);
}
printf("Using %s\n", dev);
}
if (ioctl(devfd, TIOCGETP, &Lttymode) < 0) {
perror(dev);
exit(1);
} else {
lttymode = Lttymode;
lttymode.sg_flags |= RAW;
lttymode.sg_flags &= ~ECHO;
if (tandem)
lttymode.sg_flags |= TANDEM;
if (baudrate != NOBAUD) {
Lttymode.sg_ospeed = Lttymode.sg_ispeed = baudrate;
lttymode.sg_ospeed = lttymode.sg_ispeed = baudrate;
}
if (ioctl(devfd, TIOCSETP, <tymode) < 0) {
perror(dev);
exit(1);
}
}
/*
* set up local terminal in cbreak mode
*/
cttymode = kttymode;
cttymode.sg_flags |= CBREAK;
cttymode.sg_flags &= ~ECHO;
cttymode.sg_flags &= ~CRMOD;
if (ioctl(STDIN, TIOCSETP, &cttymode) < 0) {
perror("Cannot set terminal modes");
exit(1);
}
/*
* start up the keyboard monitor and line monitor tasks
*/
if ((pid=fork()))
keymon();
else
linemon();
exit(0);
}
int idle = 0;
/*
*------------------------------------------------------------------
*
* keymon() - terminal keyboard monitor process
*
*------------------------------------------------------------------
*/
keymon()
{
int i;
int esc;
char c, buf[BUFSIZ];
int sigsusp(), sigcont(), sigalrm();
/*
* catch interrupt, suspend and continue signals
*/
signal(SIGINT, quit);
signal(SIGTSTP, sigsusp);
signal(SIGCONT, sigcont);
signal(SIGALRM, sigalrm);
alarm(60);
/*
* loop forever over the following: process each keystroke
* on the keyboard.
*/
esc = 0;
while( (i=read(STDIN,&c,1)) != 0) {
if (i == 1) {
idle = 0;
if ( c=='\\' && esc==0 ) {
cttymode.sg_flags |= RAW;
stty(STDIN,&cttymode);
esc = 1;
} else {
if ( esc && (c&0177)=='\0' ) {
ioctl(devfd, TIOCSBRK, NULL);
sleep(2);
ioctl(devfd, TIOCCBRK, NULL);
} else
write(devfd, &c, 1);
if ( esc ) {
cttymode.sg_flags &= ~RAW;
stty(STDIN, &cttymode);
}
esc = 0;
}
}
}
esc = 0;
ioctl(STDIN, TIOCSETP, &kttymode);
ioctl(devfd, TIOCSETP, &Lttymode);
quit();
}
quit()
{
kill(pid,9);
ioctl(STDIN, TIOCSETP, &kttymode);
ioctl(devfd, TIOCSETP, &Lttymode);
printf("\n");
exit(0);
}
quit2() /* safe interim quit procedure */
{
ioctl(STDIN, TIOCSETP, &kttymode);
if (devfd >= 0)
ioctl(devfd, TIOCSETP, &Lttymode);
printf("\n");
touch(lockfile);
exit(0);
}
sigsusp()
{
ioctl(STDIN, TIOCSETP, &kttymode);
fflush(stdout);
signal(SIGTSTP, SIG_DFL);
kill(getpid(), SIGTSTP);
}
sigcont()
{
signal(SIGCONT, sigcont);
signal(SIGTSTP, sigsusp);
ioctl(STDIN, TIOCSETP, &cttymode);
}
/*
* sigalrm -- terminate if keyboard idle too long
*/
sigalrm()
{
if (timeout > 0 && ++idle > timeout) {
fprintf(stderr,"\nKeyboard idle %d minute%s. %s released.\n",
timeout, (timeout == 1)? "" : "s", dev);
quit();
}
signal(SIGALRM, sigalrm);
touch(lockfile);
alarm(60);
}
/*
*------------------------------------------------------------------
*
* linemon -- monitor LSI line and print characters that arrive
*
*------------------------------------------------------------------
*/
linemon()
{
char buf[512];
int cch;
/*
* ignore interrupt signal -- keyboard process kills us
*/
signal(SIGINT, SIG_IGN);
signal(SIGQUIT, SIG_IGN);
signal(SIGTSTP,SIG_DFL);
signal(SIGCONT, SIG_DFL);
for (;;) {
if ((cch=read(devfd, buf, sizeof(buf))) > 0)
write(STDOUT, buf, cch);
}
}