|
|
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: 10152 (0x27a8)
Types: TextFile
Notes: UNIX file
Names: »crccu.c«
└─⟦f27320a65⟧ Bits:30001972 Commodore 900 hard disk image with partial source code
└─⟦0a3c255ba⟧ UNIX Filesystem
└─⟦this⟧ »cu_src/crccu.c«
/*
* A version of Ward Christensen's file transfer protocol for
* Unix System V or 4.2 bsd.
*
* Emmet P. Gray, ..!ihnp4!uiucuxc!fthood!egray, 16 Aug 85
*
* Modified by Sanford Zelkovitz 08/18/86
*
* This is a SPECIAL VERSION of crc which is used with CU
* October 1, 1986
*/
#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <termio.h>
#define MAXERRORS 10 /* max number of times to retry */
#define SECSIZE 128 /* CP/M sector, transmission block */
#define CPMEOF 26 /* End Of File (for CP/M) */
#define SOH 1 /* Start Of Header */
#define EOT 4 /* End Of Transmission */
#define ACK 6 /* ACKnowledge */
#define NAK 21 /* Negative AcKnowledge */
#define CAN 24 /* CANcel */
int synchron;
unsigned char crc1, crc2;
struct termio ttyhold;
FILE *outbuf;
FILE *inbuf;
int xyz, fd;
main(argc, argv)
int argc;
char *argv[];
{
int msgstat;
char *tty, *comm, *ttyname();
char xbuf[50];
struct stat stbuf;
if (argc != 3) {
usage();
exit(1);
}
outbuf = fopen("/tmp/dev.CU","r");
fscanf(outbuf,"%d",&fd);
fclose(outbuf);
tty = ttyname(fd);
stat(tty, &stbuf);
msgstat = (stbuf.st_mode & 0777);
chmod(tty, 0600); /* mesg n */
ioctl(fd, TCGETA, &ttyhold); /* get current settings */
comm = ttyname(fd);
strcpy(xbuf,comm);
outbuf = fopen(xbuf,"w");
inbuf = fopen(xbuf,"r");
switch (*argv[1]) {
case 'r':
recvfile(argv[2]);
break;
case 's':
sendfile(argv[2]);
break;
default:
usage();
}
ioctl(fd, TCSETAF, &ttyhold); /* restore settings */
chmod(tty, msgstat); /* restore mesg status */
exit(0);
}
/* send a file to the remote */
sendfile(tfile)
char *tfile;
{
FILE *fp;
unsigned char chr, checksum, block, sector[SECSIZE];
int i, mode, nbytes, errcount, size, speed;
long real_block;
long min, sec;
static int baud[14] = {0, 50, 75, 110, 134, 150, 200,
300, 600, 1200, 1800, 2400, 4800, 9600};
struct stat sbuf;
if (!(fp = fopen(tfile, "r"))) {
fprintf(stderr, "xmodem: Can't open '%s' for read\r\n", tfile);
return;
}
stat(tfile, &sbuf);
size = (sbuf.st_size / 128) + 1;
speed = baud[ttyhold.c_cflag & 017];
sec = size;
sec = sec * 128L * 11L / speed;
min = sec / 60L;
sec = sec - min * 60L;
fprintf(stderr, "File open: %d records\r\n", size);
fprintf(stderr, "Send time: %ld min, %ld sec at %d baud\r\n", min, sec, speed);
fprintf(stderr, "To cancel: use CTRL-X numerous times\r\n");
fprintf(stderr, "Waiting ready signal\r\n");
rawmode();
errcount = 0;
mode = 0;
block = 1;
real_block = 1L;
while (errcount < MAXERRORS) {
chr = getchar_t();
if (chr == NAK) /* checksum mode */
{
fprintf(stderr,"\n\rChecksum mode\n\r");
break;
}
if (chr == 'C') { /* CRC mode */
fprintf(stderr,"\n\rCRC mode\n\r");
mode = 1;
break;
}
errcount++;
}
if (errcount == MAXERRORS) {
sleep(3);
fprintf(stderr, "xmodem: Timed out on acknowledge\r\n");
return;
}
while (nbytes = fread(sector, sizeof(sector[0]), SECSIZE, fp)) {
if (nbytes < SECSIZE) { /* fill short sector */
for (i=nbytes; i < SECSIZE; i++)
sector[i] = CPMEOF;
}
errcount = 0;
while (errcount < MAXERRORS) {
fprintf(stderr,"%s%ld","\n\rSending block ",real_block);
putc(SOH, outbuf); /* the header */
putc(block, outbuf); /* the block number */
chr = ~block;
putc(chr, outbuf); /* it's complement */
checksum = 0;
crc1 = 0;
crc2 = 0;
for (i=0; i < SECSIZE; i++) {
putc(sector[i], outbuf);
if (mode)
update_crc(sector[i]);
else
checksum += sector[i];
}
if (mode) {
update_crc(0);
update_crc(0);
putc(crc1, outbuf);
putc(crc2, outbuf);
}
else
putc(checksum, outbuf);
chr = getchar_t();
if (chr == CAN) {
sleep(3);
fprintf(stderr,"\r\nxmodem: Abort request received\r\n");
return;
}
if (chr == ACK)
{
fprintf(stderr," received ACK");
break; /* got it! */
}
fprintf(stderr," received NAK");
errcount++;
}
if (errcount == MAXERRORS) {
error();
return;
}
block++;
real_block++;
}
errcount = 0;
while (errcount < MAXERRORS) {
putc(EOT, outbuf);
fprintf(stderr,"\n\rSending EOT ");
if (getchar_t() == ACK)
{
fprintf(stderr," received ACK\n\r");
break;
}
fprintf(stderr," received NAK");
errcount++;
}
return;
}
/* receive a file from the remote */
recvfile(tfile)
char *tfile;
{
FILE *fp;
unsigned char hdr, blk, cblk, tmp, cksum;
unsigned char c1, c2, sum, block, sector[SECSIZE];
int i, stop = 0, mode, errcount, resync();
long true_end, real_block;
char ans[40];
if (!access(tfile, 00)) {
while (1) {
fprintf(stderr, "File already exists \r\n");
return;
}
}
if (!(fp = fopen(tfile, "w"))) {
fprintf(stderr, "xmodem: Can't open '%s' for write\r\n", tfile);
return;
}
fprintf(stderr, "File open - ready to receive\r\n");
rawmode();
errcount = 0;
block = 1;
real_block = 1L;
while (errcount < MAXERRORS) {
if (errcount < (MAXERRORS / 2)) {
putc('C', outbuf); /* try CRC mode first */
fprintf(stderr,"\n\rStarting CRC mode\n\r");
mode = 1;
}
else {
putc(NAK, outbuf); /* then checksum */
fprintf(stderr,"\n\rSwitching to Checksum mode\n\r");
mode = 0;
}
if ((hdr = getchar_t()) == SOH) {
ungetc(SOH, inbuf);
break;
}
errcount++;
}
if (errcount == MAXERRORS) {
sleep(3);
fprintf(stderr, "\r\nxmodem: Timed out on acknowledge\r\n");
return;
}
errcount = 0;
while (errcount < MAXERRORS) {
hdr = getchar_t();
if (hdr == CAN) {
sleep(3);
fprintf(stderr, "\r\nxmodem: Abort request received\r\n");
return;
}
if (hdr == EOT) /* done! */
{
fprintf(stderr,"\n\r ***** Received EOT! *****\n\r");
break;
}
if (hdr != SOH) { /* read in junk for 6 seconds */
synchron = 0; /* to re-synchronized block */
fprintf(stderr,"\n\r***** Resync for 6 seconds *****\n\r");
signal(SIGALRM, resync);
alarm(6);
while(synchron == 0)
hdr = getc(inbuf);
goto nak;
}
fprintf(stderr,"%s%ld","\n\rWaiting for block ",real_block);
blk = getchar_t();
cblk = getchar_t();
crc1 = 0;
crc2 = 0;
sum = 0;
for (i=0; i < SECSIZE; i++) {
sector[i] = getchar_t();
if (mode)
update_crc(sector[i]);
else
sum += sector[i];
}
if (mode) {
c1 = getchar_t();
c2 = getchar_t();
}
else
cksum = getchar_t();
if (blk != block && blk != (block - 1))
goto nak;
tmp = ~blk;
if (cblk != tmp)
goto nak;
if (mode) {
update_crc(0);
update_crc(0);
if (c1 != crc1 || c2 != crc2)
goto nak;
}
else {
if (cksum != sum)
goto nak;
}
if (block == blk) {
fflush(fp);
fwrite(sector, sizeof(sector[0]), SECSIZE, fp);
}
block = blk + 1;
real_block++;
putc(ACK, outbuf); /* got it! */
fprintf(stderr," Received --- sending ACK");
errcount = 0;
continue;
nak: putc(NAK, outbuf); /* do it over */
fprintf(stderr," Error - sending NAK");
errcount++;
}
if (errcount == MAXERRORS) {
error();
return;
}
putc(ACK, outbuf);
fprintf(stderr,"\n\r***** Sending Final ACK *****\n\r");
for (i = SECSIZE -1; i >= 0; i--) { /* find true EOF */
if (sector[i] != CPMEOF) {
stop = i;
break;
}
}
/*
* Some CPM systems don't pad the end of the file with ^Z's so the file may
* have junk at the end. A conservative approach had to be taken in order
* for Unix object code (where ^Z's may be valid data) to transfer properly.
*/
true_end = ftell(fp) - SECSIZE + stop +1;
fclose(fp);
truncate(tfile, true_end);
return;
}
/* give minimal usage message */
usage()
{
fprintf(stderr, "Usage: xmodem [ s | r ] filename\r\n");
fprintf(stderr, " options are 's' for send or 'r' for receive\r\n");
return;
}
/* exceeded the maximum number of retry's */
error()
{
putc(CAN, outbuf);
putc(CAN, outbuf);
putc(CAN, outbuf);
putc(CAN, outbuf);
sleep(3);
fprintf(stderr, "\r\nxmodem: Exceeded error limit...aborting\r\n");
return;
}
/* update the CRC bytes */
update_crc(c)
unsigned char c;
{
int i, temp;
unsigned char carry, c_crc1, c_crc2;
for (i=0; i < 8; i++) {
temp = c * 2;
c = temp; /* rotate left */
carry = ((temp > 255) ? 1 : 0);
temp = crc2 * 2;
crc2 = temp;
crc2 |= carry; /* rotate with carry */
c_crc2 = ((temp > 255) ? 1 : 0);
temp = crc1 * 2;
crc1 = temp;
crc1 |= c_crc2;
c_crc1 = ((temp > 255) ? 1 : 0);
if (c_crc1) {
crc2 ^= 0x21;
crc1 ^= 0x10;
}
}
return;
}
/* getchar with a 10 sec time out */
getchar_t()
{
int force_it();
unsigned char c;
signal(SIGALRM, force_it);
alarm(10); /* only have 10 sec... */
c = getc(inbuf);
alarm(0);
return(c);
}
/*
* This code (and the resync() below) is the most machine dependent part
* of the program. The action of the signal SIGALRM during a read system
* call is not well defined. Some systems return the stack to the point
* outside the system call, others inside the call itself. Have fun...
*/
force_it()
{
unsigned char c;
c = CPMEOF; /* arbitrary default char */
ungetc(c, inbuf);
return;
}
/* truncate file to given length */
truncate(path, length)
char *path;
long length;
{
FILE *fp, *tempfp;
long i;
char c, string[80], *tempfile, *mktemp();
if (!(fp = fopen(path, "r"))) {
fprintf(stderr, "xmodem: Can't open '%s' for read\r\n", path);
return;
}
tempfile = mktemp("/tmp/trunXXXXXX");
if (!(tempfp = fopen(tempfile, "w"))) {
fprintf(stderr, "xmodem: Can't open temporary file\r\n");
return;
}
for (i=0; i < length; i++) {
c = fgetc(fp);
fputc(c, tempfp);
}
fclose(fp);
fclose(tempfp);
sprintf(string, "mv %s %s", tempfile, path);
system(string);
return;
}
/* put the stdin/stdout in the "raw" mode */
rawmode()
{
struct termio tbuf;
ioctl(fd, TCGETA, &tbuf);
tbuf.c_cc[4] = 1; /* VMIN */
tbuf.c_cc[5] = 0; /* VTIME */
tbuf.c_iflag = 0;
tbuf.c_oflag = 0;
tbuf.c_lflag = 0;
tbuf.c_cflag &= ~CSIZE;
tbuf.c_cflag |= CS8;
tbuf.c_cflag &= ~PARENB;
ioctl(fd, TCSETAF, &tbuf);
return;
}
/* after 6 seconds of reading junk data... */
resync()
{
char c;
synchron = 1; /* set the flag */
c = SOH;
ungetc(c, inbuf);
return;
}