DataMuseum.dk

Presents historical artifacts from the history of:

Commodore CBM-900

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about Commodore CBM-900

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - download

⟦8f9ea0b72⟧ TextFile

    Length: 10152 (0x27a8)
    Types: TextFile
    Notes: UNIX file
    Names: »crccu.c«

Derivation

└─⟦f27320a65⟧ Bits:30001972 Commodore 900 hard disk image with partial source code
    └─⟦0a3c255ba⟧ UNIX V7 Filesystem
        └─ ⟦this⟧ »cu_src/crccu.c« 

TextFile

/*
 * 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;
}