diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/con/xms.c |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/con/xms.c')
-rwxr-xr-x | sys/src/cmd/con/xms.c | 215 |
1 files changed, 215 insertions, 0 deletions
diff --git a/sys/src/cmd/con/xms.c b/sys/src/cmd/con/xms.c new file mode 100755 index 000000000..2d46f845a --- /dev/null +++ b/sys/src/cmd/con/xms.c @@ -0,0 +1,215 @@ +#include <u.h> +#include <libc.h> +#include <ctype.h> + +enum { + Soh= 0x1, + Stx= 0x2, + Eot= 0x4, + Ack= 0x6, + Nak= 0x15, + Cancel= 0x18, +}; + +int send(uchar*, int); +int notifyf(void*, char*); + +int debug, progress, onek; + +void +errorout(int ctl, int bytes) +{ + uchar buf[2]; + + buf[0] = Cancel; + write(1, buf, 1); + fprint(2, "\nxms: gave up after %d bytes\n", bytes); + write(ctl, "rawoff", 6); + exits("cancel"); +} + +ushort +updcrc(int c, ushort crc) +{ + int count; + + for (count=8; --count>=0;) { + if (crc & 0x8000) { + crc <<= 1; + crc += (((c<<=1) & 0400) != 0); + crc ^= 0x1021; + } + else { + crc <<= 1; + crc += (((c<<=1) & 0400) != 0); + } + } + return crc; +} + +void +main(int argc, char **argv) +{ + uchar c; + uchar buf[1024+5]; + uchar seqno; + int fd, ctl; + long n; + int sum; + uchar *p; + int bytes; + int crcmode; + + ARGBEGIN{ + case 'd': + debug = 1; + break; + case 'p': + progress = 1; + break; + case '1': + onek = 1; + break; + }ARGEND + + if(argc != 1){ + fprint(2, "usage: xms filename\n"); + exits("usage"); + } + fd = open(argv[0], OREAD); + if(fd < 0){ + perror("xms"); + exits("open"); + } + + ctl = open("/dev/consctl", OWRITE); + if(ctl < 0){ + perror("xms"); + exits("consctl"); + } + write(ctl, "rawon", 5); + + /* give the other side a 30 seconds to signal ready */ + atnotify(notifyf, 1); + alarm(30*1000); + crcmode = 0; + for(;;){ + if(read(0, &c, 1) != 1){ + fprint(2, "xms: timeout\n"); + exits("timeout"); + } + c = c & 0x7f; + if(c == Nak) + break; + if(c == 'C') { + if (debug) + fprint(2, "crc mode engaged\n"); + crcmode = 1; + break; + } + } + alarm(0); + + /* send the file in 128/1024 byte chunks */ + for(bytes = 0, seqno = 1; ; bytes += n, seqno++){ + n = read(fd, buf+3, onek ? 1024 : 128); + if(n < 0) + exits("read"); + if(n == 0) + break; + if(n < (onek ? 1024 : 128)) + memset(&buf[n+3], 0, (onek ? 1024 : 128)-n); + buf[0] = onek ? Stx : Soh; + buf[1] = seqno; + buf[2] = 255 - seqno; + + /* calculate checksum and stuff into last byte */ + if (crcmode) { + unsigned short crc; + crc = 0; + for(p = buf + 3; p < &buf[(onek ? 1024 : 128)+3]; p++) + crc = updcrc(*p, crc); + crc = updcrc(0, crc); + crc = updcrc(0, crc); + buf[(onek ? 1024 : 128) + 3] = crc >> 8; + buf[(onek ? 1024 : 128) + 4] = crc; + } + else { + sum = 0; + for(p = buf + 3; p < &buf[(onek ? 1024 : 128)+3]; p++) + sum += *p; + buf[(onek ? 1024 : 128) + 3] = sum; + } + + if(send(buf, (onek ? 1024 : 128) + 4 + crcmode) < 0) + errorout(ctl, bytes); + if (progress && bytes % 10240 == 0) + fprint(2, "%dK\n", bytes / 1024); + } + + /* tell other side we're done */ + buf[0] = Eot; + if(send(buf, 1) < 0) + errorout(ctl, bytes); + + fprint(2, "xms: %d bytes transmitted\n", bytes); + write(ctl, "rawoff", 6); + exits(0); +} + +/* + * send a message till it's acked or we give up + */ +int +send(uchar *buf, int len) +{ + int tries; + int n; + uchar c; + + for(tries = 0;; tries++, sleep(2*1000)){ + if(tries == 10) + return -1; + if(write(1, buf, len) != len) + return -1; + + alarm(30*1000); + n = read(0, &c, 1); + alarm(0); + if(debug) switch(c){ + case Soh: + fprint(2, " Soh"); + break; + case Eot: + fprint(2, " Eot"); + break; + case Ack: + fprint(2, " Ack"); + break; + case Nak: + fprint(2, " Nak"); + break; + case Cancel: + fprint(2, "\nremote Cancel\n"); + return -1; + default: + if(isprint(c)) + fprint(2, "%c", c); + else + fprint(2, " \\0%o", c); + } + c = c & 0x7f; + if(n == 1 && c == Ack) + break; + } + return 0; +} + +int +notifyf(void *a, char *msg) +{ + USED(a); + if(strcmp(msg, "alarm") == 0) + return 1; + return 0; +} |