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