Contents of /tags/mkinitrd-6_1_1/busybox/miscutils/rx.c
Parent Directory | Revision Log
Revision 841 -
(show annotations)
(download)
Mon May 4 16:31:54 2009 UTC (15 years, 4 months ago) by niro
File MIME type: text/plain
File size: 5701 byte(s)
Mon May 4 16:31:54 2009 UTC (15 years, 4 months ago) by niro
File MIME type: text/plain
File size: 5701 byte(s)
tagged 'mkinitrd-6_1_1'
1 | /* vi: set sw=4 ts=4: */ |
2 | /*------------------------------------------------------------------------- |
3 | * Filename: xmodem.c |
4 | * Copyright: Copyright (C) 2001, Hewlett-Packard Company |
5 | * Author: Christopher Hoover <ch@hpl.hp.com> |
6 | * Description: xmodem functionality for uploading of kernels |
7 | * and the like |
8 | * Created at: Thu Dec 20 01:58:08 PST 2001 |
9 | *-----------------------------------------------------------------------*/ |
10 | /* |
11 | * xmodem.c: xmodem functionality for uploading of kernels and |
12 | * the like |
13 | * |
14 | * Copyright (C) 2001 Hewlett-Packard Laboratories |
15 | * |
16 | * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. |
17 | * |
18 | * This was originally written for blob and then adapted for busybox. |
19 | */ |
20 | |
21 | #include "libbb.h" |
22 | |
23 | #define SOH 0x01 |
24 | #define STX 0x02 |
25 | #define EOT 0x04 |
26 | #define ACK 0x06 |
27 | #define NAK 0x15 |
28 | #define BS 0x08 |
29 | |
30 | /* |
31 | Cf: |
32 | http://www.textfiles.com/apple/xmodem |
33 | http://www.phys.washington.edu/~belonis/xmodem/docxmodem.txt |
34 | http://www.phys.washington.edu/~belonis/xmodem/docymodem.txt |
35 | http://www.phys.washington.edu/~belonis/xmodem/modmprot.col |
36 | */ |
37 | |
38 | #define TIMEOUT 1 |
39 | #define TIMEOUT_LONG 10 |
40 | #define MAXERRORS 10 |
41 | |
42 | #define read_fd STDIN_FILENO |
43 | #define write_fd STDOUT_FILENO |
44 | |
45 | static int read_byte(unsigned timeout) |
46 | { |
47 | char buf[1]; |
48 | int n; |
49 | |
50 | alarm(timeout); |
51 | /* NOT safe_read! We want ALRM to interrupt us */ |
52 | n = read(read_fd, buf, 1); |
53 | alarm(0); |
54 | if (n == 1) |
55 | return (unsigned char)buf[0]; |
56 | return -1; |
57 | } |
58 | |
59 | static int receive(/*int read_fd, */int file_fd) |
60 | { |
61 | unsigned char blockBuf[1024]; |
62 | unsigned errors = 0; |
63 | unsigned wantBlockNo = 1; |
64 | unsigned length = 0; |
65 | int do_crc = 1; |
66 | char nak = 'C'; |
67 | unsigned timeout = TIMEOUT_LONG; |
68 | |
69 | /* Flush pending input */ |
70 | tcflush(read_fd, TCIFLUSH); |
71 | |
72 | /* Ask for CRC; if we get errors, we will go with checksum */ |
73 | full_write(write_fd, &nak, 1); |
74 | |
75 | for (;;) { |
76 | int blockBegin; |
77 | int blockNo, blockNoOnesCompl; |
78 | int blockLength; |
79 | int cksum_crc; /* cksum OR crc */ |
80 | int expected; |
81 | int i,j; |
82 | |
83 | blockBegin = read_byte(timeout); |
84 | if (blockBegin < 0) |
85 | goto timeout; |
86 | |
87 | timeout = TIMEOUT; |
88 | nak = NAK; |
89 | |
90 | switch (blockBegin) { |
91 | case SOH: |
92 | case STX: |
93 | break; |
94 | |
95 | case EOT: |
96 | nak = ACK; |
97 | full_write(write_fd, &nak, 1); |
98 | return length; |
99 | |
100 | default: |
101 | goto error; |
102 | } |
103 | |
104 | /* block no */ |
105 | blockNo = read_byte(TIMEOUT); |
106 | if (blockNo < 0) |
107 | goto timeout; |
108 | |
109 | /* block no one's compliment */ |
110 | blockNoOnesCompl = read_byte(TIMEOUT); |
111 | if (blockNoOnesCompl < 0) |
112 | goto timeout; |
113 | |
114 | if (blockNo != (255 - blockNoOnesCompl)) { |
115 | bb_error_msg("bad block ones compl"); |
116 | goto error; |
117 | } |
118 | |
119 | blockLength = (blockBegin == SOH) ? 128 : 1024; |
120 | |
121 | for (i = 0; i < blockLength; i++) { |
122 | int cc = read_byte(TIMEOUT); |
123 | if (cc < 0) |
124 | goto timeout; |
125 | blockBuf[i] = cc; |
126 | } |
127 | |
128 | if (do_crc) { |
129 | cksum_crc = read_byte(TIMEOUT); |
130 | if (cksum_crc < 0) |
131 | goto timeout; |
132 | cksum_crc = (cksum_crc << 8) | read_byte(TIMEOUT); |
133 | if (cksum_crc < 0) |
134 | goto timeout; |
135 | } else { |
136 | cksum_crc = read_byte(TIMEOUT); |
137 | if (cksum_crc < 0) |
138 | goto timeout; |
139 | } |
140 | |
141 | if (blockNo == ((wantBlockNo - 1) & 0xff)) { |
142 | /* a repeat of the last block is ok, just ignore it. */ |
143 | /* this also ignores the initial block 0 which is */ |
144 | /* meta data. */ |
145 | goto next; |
146 | } |
147 | if (blockNo != (wantBlockNo & 0xff)) { |
148 | bb_error_msg("unexpected block no, 0x%08x, expecting 0x%08x", blockNo, wantBlockNo); |
149 | goto error; |
150 | } |
151 | |
152 | expected = 0; |
153 | if (do_crc) { |
154 | for (i = 0; i < blockLength; i++) { |
155 | expected = expected ^ blockBuf[i] << 8; |
156 | for (j = 0; j < 8; j++) { |
157 | if (expected & 0x8000) |
158 | expected = expected << 1 ^ 0x1021; |
159 | else |
160 | expected = expected << 1; |
161 | } |
162 | } |
163 | expected &= 0xffff; |
164 | } else { |
165 | for (i = 0; i < blockLength; i++) |
166 | expected += blockBuf[i]; |
167 | expected &= 0xff; |
168 | } |
169 | if (cksum_crc != expected) { |
170 | bb_error_msg(do_crc ? "crc error, expected 0x%04x, got 0x%04x" |
171 | : "checksum error, expected 0x%02x, got 0x%02x", |
172 | expected, cksum_crc); |
173 | goto error; |
174 | } |
175 | |
176 | wantBlockNo++; |
177 | length += blockLength; |
178 | |
179 | errno = 0; |
180 | if (full_write(file_fd, blockBuf, blockLength) != blockLength) { |
181 | bb_perror_msg("can't write to file"); |
182 | goto fatal; |
183 | } |
184 | next: |
185 | errors = 0; |
186 | nak = ACK; |
187 | full_write(write_fd, &nak, 1); |
188 | continue; |
189 | error: |
190 | timeout: |
191 | errors++; |
192 | if (errors == MAXERRORS) { |
193 | /* Abort */ |
194 | |
195 | /* if were asking for crc, try again w/o crc */ |
196 | if (nak == 'C') { |
197 | nak = NAK; |
198 | errors = 0; |
199 | do_crc = 0; |
200 | goto timeout; |
201 | } |
202 | bb_error_msg("too many errors; giving up"); |
203 | fatal: |
204 | /* 5 CAN followed by 5 BS. Don't try too hard... */ |
205 | safe_write(write_fd, "\030\030\030\030\030\010\010\010\010\010", 10); |
206 | return -1; |
207 | } |
208 | |
209 | /* Flush pending input */ |
210 | tcflush(read_fd, TCIFLUSH); |
211 | |
212 | full_write(write_fd, &nak, 1); |
213 | } /* for (;;) */ |
214 | } |
215 | |
216 | static void sigalrm_handler(int UNUSED_PARAM signum) |
217 | { |
218 | } |
219 | |
220 | int rx_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
221 | int rx_main(int argc, char **argv) |
222 | { |
223 | struct termios tty, orig_tty; |
224 | int termios_err; |
225 | int file_fd; |
226 | int n; |
227 | |
228 | if (argc != 2) |
229 | bb_show_usage(); |
230 | |
231 | /* Disabled by vda: |
232 | * why we can't receive from stdin? Why we *require* |
233 | * controlling tty?? */ |
234 | /*read_fd = xopen(CURRENT_TTY, O_RDWR);*/ |
235 | file_fd = xopen(argv[1], O_RDWR|O_CREAT|O_TRUNC); |
236 | |
237 | termios_err = tcgetattr(read_fd, &tty); |
238 | if (termios_err == 0) { |
239 | orig_tty = tty; |
240 | cfmakeraw(&tty); |
241 | tcsetattr(read_fd, TCSAFLUSH, &tty); |
242 | } |
243 | |
244 | /* No SA_RESTART: we want ALRM to interrupt read() */ |
245 | signal_no_SA_RESTART_empty_mask(SIGALRM, sigalrm_handler); |
246 | |
247 | n = receive(file_fd); |
248 | |
249 | if (termios_err == 0) |
250 | tcsetattr(read_fd, TCSAFLUSH, &orig_tty); |
251 | if (ENABLE_FEATURE_CLEAN_UP) |
252 | close(file_fd); |
253 | fflush_stdout_and_exit(n >= 0); |
254 | } |