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