Path: utzoo!utgpu!news-server.csri.toronto.edu!rpi!uwm.edu!ogicse!sequent!muncher.sequent.com!news From: vandys@sequent.com (Andrew Valencia) Newsgroups: comp.unix.sysv386 Subject: Re: Using cu with rz/sz? Can't be done? Message-ID: <1991May14.044944.11723@sequent.com> Date: 14 May 91 04:49:44 GMT References: <677@genco.bungi.com> Sender: news@sequent.com (News on Muncher) Organization: Sequent Computer Systems, Inc. Lines: 480 dls@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@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 #include #include #include #include #include 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 ] [-p ] []\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: eceive, end, 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