Using cu with rz/sz? Can't be done?
Andrew Valencia
vandys at sequent.com
Tue May 14 14:49:44 AEST 1991
dls at genco.bungi.com (Dave L. Smith) writes:
>I have tried all sorts of contortions with rz/sz to make them work from
>within cu on SCO Xenix 386, with no luck. Does anyone have any ideas?
Well, I've already received enough requests that I'm going to post this
here. I know it's source, but it's a very modest C program so I hope
nobody'll get too mad. It's public domain, I wrote it from scratch,
so make your millions from it if you can!
Enjoy,
Andy Valencia
vandys at sequent.com
# This is a shell archive. Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
#
# Wrapped by vandys on Mon May 13 21:45:15 PDT 1991
# Contents: Makefile term.1 term.c
echo x - Makefile
sed 's/^@//' > "Makefile" <<'@//E*O*F Makefile//'
CFLAGS= -O # -g for debugging
OBJS= term.o
term: $(OBJS)
$(CC) $(CFLAGS) -o term $(OBJS)
@//E*O*F Makefile//
chmod u=rw,g=r,o=r Makefile
echo x - term.1
sed 's/^@//' > "term.1" <<'@//E*O*F term.1//'
@.TH TERM 1 "Public Domain" "" "5/91"
@.SH NAME
term \- provide simple terminal interface to serial port
@.SH SYNOPSIS
@.B term
@.RB "[ " \-s speed" ] [ "
@.RB "[ " \-p proto" ] [ "
@.BR "device ] "
@.SH DESCRIPTION
@.B term\^
allows a user to open a TTY device and run an interactive
session through it. It provides similar facilities to
@.B cu(1),
but is useful in cases where access to auxilary protocol
programs is desired or further customization of the
source code is needed.
@.TP
@.B \-s
is used to specify the baud rate the serial port should
be set to; the default is 9600 baud. Legal values are
300, 1200, 2400, and 9600.
@.TP
@.B \-p
selects which file transfer protocol (see below) is to be
used. The default is 'z' for Z-modem; legal values
are 'x', 'y', or 'z'.
@.PP
The final argument,
@.B device,
specifies which serial port to access. It should spell out the
complete path to the desired device. The default is
@.B /dev/tty1a
on XENIX, and
@.B /dev/tty01
on other breeds of UNIX.
@.PP
On startup
@.B term
goes into interactive mode immediately. All extended commands
are accessed by first typing ^U (control-U), then a command character.
Typing a second ^U merely sends a ^U to the remote system. Typing 'r'
starts a file transfer
@.I receive.
Typing 's' starts a file transfer
@.I send.
Typing 'q' causes the terminal program to clean up and exit.
Any other character causes a brief summary of the commands to be displayed.
@.SH FILE TRANSFERS
The
@.B term(1)
program itself has no knowledge of file transfers. It merely
builds a command line which it then launches on the host operating
system. The commands "rx", "ry", and "rz" must be in the user's
path for X- Y- and Z-modem file transfer receives. "sx", "sy", and
"sz" are needed similarly for file transfer sends. Chuck Forsberg's
excellent public domain Z-modem implementation is known to work
beautifully with
@.B term(1).
@.SH FILES
/dev/tty??
rx, ry, rz
sx, sy, sz
@.SH SEE ALSO
cu(1)
@.SH NOTES
XENIX is a registered trademark of The Santa Cruz Operation, Inc.
@.sp
UNIX is a registered trademark of AT&T.
@//E*O*F term.1//
chmod u=rw,g=r,o= term.1
echo x - term.c
sed 's/^@//' > "term.c" <<'@//E*O*F term.c//'
/*
* term.c
* Terminal utility for banging characters out a serial port
*/
#include <sys/types.h>
#include <sys/fcntl.h>
#include <stdio.h>
#include <termio.h>
#include <signal.h>
#include <errno.h>
static struct termio ntty, otty, ext;
static int baud = B9600;
static int ext_cmd();
int ttyfd, /* File descriptor of TTY port */
rs232; /* ...and of RS-232 port */
#define CMD_CHAR '\25' /* Control-U starts protocol transfer */
/*
* Protocols to receive under
*/
#define PROTO_RX 1
#define PROTO_RY 2
#define PROTO_RZ 3
static int proto = PROTO_RZ; /* Default--zmodem */
/*
* usr2()
* Handle SIGUSR2 signal
*
* Doesn't do anything except re-arm the handler because interrupting
* the system call is the whole point.
*/
usr2()
{
signal(SIGUSR2, usr2);
}
/*
* usr1()
* Handle SIGUSR1 signal
*
* Puts us to sleep until we're kicked back by a SIGUSR2
*/
usr1()
{
signal(SIGUSR1, usr1);
pause();
}
main(argc, argv)
int argc;
char **argv;
{
register char *p, *q;
int child, code;
int x;
char buf[30];
char c;
#ifdef XENIX
char *tty = "/dev/tty1a"; /* XENIX default */
#else
char *tty = "/dev/tty01"; /* Microport/ATT default */
#endif
for( x = 1; x < argc; ++x ){
if (argv[x][0] == '-') {
c = argv[x][1];
if (argv[x][2])
p = argv[x]+2;
else
p = argv[++x];
switch( c ){
/*
* Selection of baud rate
*/
case 's':
if (!strcmp(p, "300")) {
baud = B300;
break;
}
if (!strcmp(p, "1200")) {
baud = B1200;
break;
}
if (!strcmp(p, "2400")) {
baud = B2400;
break;
}
if (!strcmp(p, "9600")) {
baud = B9600;
break;
}
printf("Illegal speed: %s\n",p);
break;
/*
* Selection of transfer protocol
*/
case 'p':
if (!strcmp(p, "x")) {
proto = PROTO_RX;
break;
}
if (!strcmp(p, "y")) {
proto = PROTO_RY;
break;
}
if (!strcmp(p, "z")) {
proto = PROTO_RZ;
break;
}
printf("Illegal protocol: %s\n", p);
break;
default:
printf("Illegal option: %c\n", c);
printf("Usage is: %s [-s <speed>] [-p <protocol>] [<tty>]\n", argv[0]);
break;
}
} else
tty = argv[x];
}
/*
* The next bit of code makes assumptions about
* how UNIX manages its file descriptors. The goal
* is to make the terminal device be our standard
* input & output.
*/
ttyfd = dup(1);
close(0);
close(1);
if ((rs232 = open(tty, O_RDWR|O_EXCL)) < 0) {
perror(tty);
exit(1);
}
dup(rs232);
/*
* Set up for raw TTY I/O
*/
ioctl(ttyfd, TCGETA, &otty);
ioctl(ttyfd, TCGETA, &ntty);
ntty.c_lflag &= ~(ECHO|ICANON|ISIG);
ntty.c_oflag &= ~OPOST;
ntty.c_iflag = 0;
ntty.c_cc[VMIN] = 1;
ntty.c_cc[VTIME] = 0;
ioctl(ttyfd, TCSETAW, &ntty);
/*
* Set up serial port for raw access too
*/
ioctl(rs232, TCGETA, &ext);
ext.c_lflag &= ~(ECHO|ICANON|ISIG);
ext.c_cflag = (ext.c_cflag & ~CBAUD) | baud;
ext.c_oflag &= ~OPOST;
ext.c_iflag = 0;
ext.c_cc[VMIN] = sizeof(buf);
ext.c_cc[VTIME] = 1;
ioctl(rs232, TCSETAW, &ext);
/*
* Launch child. Child reads RS-232 and writes TTY. The
* child is also the half which is knocked asleep during
* protocol file transfers.
*/
if ((child = fork()) == 0) {
static char boot_msg[] = "Term ready for action!\r\n";
signal(SIGUSR1, usr1);
signal(SIGUSR2, usr2);
write(ttyfd, boot_msg, sizeof(boot_msg)-1);
for (;;) {
if ((x = read(rs232, buf, sizeof(buf))) < 0 ) {
if (errno == EINTR)
continue;
perror("child");
exit(1);
}
p = buf;
q = buf+x;
while (p < q)
*p++ &= 0x7F;
write(ttyfd, buf, x);
}
}
/*
* Launch of child failed. Restore TTY and leave.
*/
if (child < 0) {
ioctl(ttyfd, TCSETAW, &otty);
perror("child fork");
exit(1);
}
/*
* Parent loop. Read chars until device dies or we break out
* on exit.
*/
while ((code = read(ttyfd, &c, 1)) == 1) {
c &= 0x7F;
/* CMD_CHAR (usually Control-U) starts file transfers */
if (c == CMD_CHAR) {
kill(child, SIGUSR1);
/*
* Extended command returns non-zero when
* quit selected.
*/
if (ext_cmd())
break;
kill(child, SIGUSR2);
continue;
}
if (c == '\n')
c = '\r';
write(rs232, &c, 1);
}
if (code < 0)
perror("parent");
/*
* Finish up. Nuke the child, restore TTY, exit
*/
kill(child, SIGKILL);
ioctl(ttyfd, TCSETAW, &otty);
write(ttyfd, "Exiting\n", 8);
exit(0);
/*NOTREACHED*/
}
/*
* prompt_read()
* Ask for and receive a line in raw mode
*/
static void
prompt_read(prompt, buf, len)
char *prompt;
register char *buf;
register int len;
{
char c;
/* Leave room for null terminator */
len -= 1;
/* Prompt */
write(ttyfd, prompt, strlen(prompt));
/* Read chars until newline */
do {
while (read(ttyfd, &c, sizeof(c)) == 0)
;
c &= 0x7F;
write(ttyfd, &c, sizeof(c));
if (len) {
*buf++ = c;
--len;
}
} while ((c != '\n') && (c != '\r'));
/* Overwrite newline with terminator */
buf -= 1;
*buf = '\0';
}
/*
* rx_xfer()
* Execute a protocol receive
*/
static void
rx_xfer()
{
char buf[80];
char fname[60];
switch (proto) {
case PROTO_RX:
/*
* Xmodem doesn't send names, so we have to ask. Bleh.
*/
prompt_read("Receive file: ", fname, sizeof(fname));
sprintf(buf, "rx %s", fname);
break;
case PROTO_RY:
strcpy(buf, "ry");
break;
case PROTO_RZ:
default:
strcpy(buf, "rz");
break;
}
system(buf);
}
/*
* tx_xfer()
* Execute a protocol transmit
*/
static void
tx_xfer()
{
char buf[80];
char fname[60];
prompt_read("Send file: ", fname, sizeof(fname));
switch (proto) {
case PROTO_RX:
strcpy(buf, "sx");
break;
case PROTO_RY:
strcpy(buf, "sy");
break;
case PROTO_RZ:
default:
strcpy(buf, "sz");
break;
}
sprintf(buf, "%s %s", buf, fname);
system(buf);
}
/*
* ext_cmd()
* Do an extended command.
*
* Figure out what they want to do, drive a protcol transfer. Return
* value is 1 if you user wants to quit, 0 otherwise.
*/
static
ext_cmd()
{
char c;
register char c2;
char *helpmsg = "Options are: <r>eceive, <s>end, <q>uit\r\n";
/* Get next char to see what they want to do */
while (read(ttyfd, &c, sizeof(c)) == 0)
;
c &= 0x7F;
/* Send char through literally */
if (c == CMD_CHAR) {
write(rs232, &c, sizeof(c));
return(0);
}
/* Quit */
if (c == 'q')
return(1);
/* Receive? */
c2 = c;
if ((c2 == 'r') || (c2 == 'R'))
rx_xfer();
else if ((c2 == 's') || (c2 == 'S') || (c2 == 't') ||
(c2 == 'T'))
tx_xfer();
else
write(ttyfd, helpmsg, strlen(helpmsg));
return(0);
}
@//E*O*F term.c//
chmod u=rw,g=,o= term.c
exit 0
More information about the Comp.unix.sysv386
mailing list