Contents of /trunk/mkinitrd-magellan/busybox/miscutils/rx.c
Parent Directory | Revision Log
Revision 532 -
(show annotations)
(download)
Sat Sep 1 22:45:15 2007 UTC (17 years ago) by niro
File MIME type: text/plain
File size: 5904 byte(s)
Sat Sep 1 22:45:15 2007 UTC (17 years ago) by niro
File MIME type: text/plain
File size: 5904 byte(s)
-import if magellan mkinitrd; it is a fork of redhats mkinitrd-5.0.8 with all magellan patches and features; deprecates magellan-src/mkinitrd
1 | /* vi: set sw=4 ts=4: */ |
2 | /*------------------------------------------------------------------------- |
3 | * Filename: xmodem.c |
4 | * Version: $Id: rx.c,v 1.1 2007-09-01 22:43:52 niro Exp $ |
5 | * Copyright: Copyright (C) 2001, Hewlett-Packard Company |
6 | * Author: Christopher Hoover <ch@hpl.hp.com> |
7 | * Description: xmodem functionality for uploading of kernels |
8 | * and the like |
9 | * Created at: Thu Dec 20 01:58:08 PST 2001 |
10 | *-----------------------------------------------------------------------*/ |
11 | /* |
12 | * xmodem.c: xmodem functionality for uploading of kernels and |
13 | * the like |
14 | * |
15 | * Copyright (C) 2001 Hewlett-Packard Laboratories |
16 | * |
17 | * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. |
18 | * |
19 | * This was originally written for blob and then adapted for busybox. |
20 | * |
21 | */ |
22 | |
23 | #include "busybox.h" |
24 | |
25 | #define SOH 0x01 |
26 | #define STX 0x02 |
27 | #define EOT 0x04 |
28 | #define ACK 0x06 |
29 | #define NAK 0x15 |
30 | #define BS 0x08 |
31 | |
32 | /* |
33 | |
34 | Cf: |
35 | |
36 | http://www.textfiles.com/apple/xmodem |
37 | http://www.phys.washington.edu/~belonis/xmodem/docxmodem.txt |
38 | http://www.phys.washington.edu/~belonis/xmodem/docymodem.txt |
39 | http://www.phys.washington.edu/~belonis/xmodem/modmprot.col |
40 | |
41 | */ |
42 | |
43 | #define TIMEOUT 1 |
44 | #define TIMEOUT_LONG 10 |
45 | #define MAXERRORS 10 |
46 | |
47 | static int read_byte(int fd, unsigned int timeout) { |
48 | char buf[1]; |
49 | int n; |
50 | |
51 | alarm(timeout); |
52 | |
53 | n = read(fd, &buf, 1); |
54 | |
55 | alarm(0); |
56 | |
57 | if (n == 1) |
58 | return buf[0] & 0xff; |
59 | else |
60 | return -1; |
61 | } |
62 | |
63 | static int receive(char *error_buf, size_t error_buf_size, |
64 | int ttyfd, int filefd) |
65 | { |
66 | char blockBuf[1024]; |
67 | unsigned int errors = 0; |
68 | unsigned int wantBlockNo = 1; |
69 | unsigned int length = 0; |
70 | int docrc = 1; |
71 | char nak = 'C'; |
72 | unsigned int timeout = TIMEOUT_LONG; |
73 | |
74 | #define note_error(fmt,args...) \ |
75 | snprintf(error_buf, error_buf_size, fmt,##args) |
76 | |
77 | /* Flush pending input */ |
78 | tcflush(ttyfd, TCIFLUSH); |
79 | |
80 | /* Ask for CRC; if we get errors, we will go with checksum */ |
81 | write(ttyfd, &nak, 1); |
82 | |
83 | for (;;) { |
84 | int blockBegin; |
85 | int blockNo, blockNoOnesCompl; |
86 | int blockLength; |
87 | int cksum = 0; |
88 | int crcHi = 0; |
89 | int crcLo = 0; |
90 | |
91 | blockBegin = read_byte(ttyfd, timeout); |
92 | if (blockBegin < 0) |
93 | goto timeout; |
94 | |
95 | timeout = TIMEOUT; |
96 | nak = NAK; |
97 | |
98 | switch (blockBegin) { |
99 | case SOH: |
100 | case STX: |
101 | break; |
102 | |
103 | case EOT: |
104 | nak = ACK; |
105 | write(ttyfd, &nak, 1); |
106 | goto done; |
107 | |
108 | default: |
109 | goto error; |
110 | } |
111 | |
112 | /* block no */ |
113 | blockNo = read_byte(ttyfd, TIMEOUT); |
114 | if (blockNo < 0) |
115 | goto timeout; |
116 | |
117 | /* block no one's compliment */ |
118 | blockNoOnesCompl = read_byte(ttyfd, TIMEOUT); |
119 | if (blockNoOnesCompl < 0) |
120 | goto timeout; |
121 | |
122 | if (blockNo != (255 - blockNoOnesCompl)) { |
123 | note_error("bad block ones compl"); |
124 | goto error; |
125 | } |
126 | |
127 | blockLength = (blockBegin == SOH) ? 128 : 1024; |
128 | |
129 | { |
130 | int i; |
131 | |
132 | for (i = 0; i < blockLength; i++) { |
133 | int cc = read_byte(ttyfd, TIMEOUT); |
134 | if (cc < 0) |
135 | goto timeout; |
136 | blockBuf[i] = cc; |
137 | } |
138 | } |
139 | |
140 | if (docrc) { |
141 | crcHi = read_byte(ttyfd, TIMEOUT); |
142 | if (crcHi < 0) |
143 | goto timeout; |
144 | |
145 | crcLo = read_byte(ttyfd, TIMEOUT); |
146 | if (crcLo < 0) |
147 | goto timeout; |
148 | } else { |
149 | cksum = read_byte(ttyfd, TIMEOUT); |
150 | if (cksum < 0) |
151 | goto timeout; |
152 | } |
153 | |
154 | if (blockNo == ((wantBlockNo - 1) & 0xff)) { |
155 | /* a repeat of the last block is ok, just ignore it. */ |
156 | /* this also ignores the initial block 0 which is */ |
157 | /* meta data. */ |
158 | goto next; |
159 | } else if (blockNo != (wantBlockNo & 0xff)) { |
160 | note_error("unexpected block no, 0x%08x, expecting 0x%08x", blockNo, wantBlockNo); |
161 | goto error; |
162 | } |
163 | |
164 | if (docrc) { |
165 | int crc = 0; |
166 | int i, j; |
167 | int expectedCrcHi; |
168 | int expectedCrcLo; |
169 | |
170 | for (i = 0; i < blockLength; i++) { |
171 | crc = crc ^ (int) blockBuf[i] << 8; |
172 | for (j = 0; j < 8; j++) |
173 | if (crc & 0x8000) |
174 | crc = crc << 1 ^ 0x1021; |
175 | else |
176 | crc = crc << 1; |
177 | } |
178 | |
179 | expectedCrcHi = (crc >> 8) & 0xff; |
180 | expectedCrcLo = crc & 0xff; |
181 | |
182 | if ((crcHi != expectedCrcHi) || |
183 | (crcLo != expectedCrcLo)) { |
184 | note_error("crc error, expected 0x%02x 0x%02x, got 0x%02x 0x%02x", expectedCrcHi, expectedCrcLo, crcHi, crcLo); |
185 | goto error; |
186 | } |
187 | } else { |
188 | unsigned char expectedCksum = 0; |
189 | int i; |
190 | |
191 | for (i = 0; i < blockLength; i++) |
192 | expectedCksum += blockBuf[i]; |
193 | |
194 | if (cksum != expectedCksum) { |
195 | note_error("checksum error, expected 0x%02x, got 0x%02x", expectedCksum, cksum); |
196 | goto error; |
197 | } |
198 | } |
199 | |
200 | wantBlockNo++; |
201 | length += blockLength; |
202 | |
203 | if (full_write(filefd, blockBuf, blockLength) < 0) { |
204 | note_error("write to file failed: %m"); |
205 | goto fatal; |
206 | } |
207 | |
208 | next: |
209 | errors = 0; |
210 | nak = ACK; |
211 | write(ttyfd, &nak, 1); |
212 | continue; |
213 | |
214 | error: |
215 | timeout: |
216 | errors++; |
217 | if (errors == MAXERRORS) { |
218 | /* Abort */ |
219 | |
220 | // if using crc, try again w/o crc |
221 | if (nak == 'C') { |
222 | nak = NAK; |
223 | errors = 0; |
224 | docrc = 0; |
225 | goto timeout; |
226 | } |
227 | |
228 | note_error("too many errors; giving up"); |
229 | |
230 | fatal: |
231 | /* 5 CAN followed by 5 BS */ |
232 | write(ttyfd, "\030\030\030\030\030\010\010\010\010\010", 10); |
233 | return -1; |
234 | } |
235 | |
236 | /* Flush pending input */ |
237 | tcflush(ttyfd, TCIFLUSH); |
238 | |
239 | write(ttyfd, &nak, 1); |
240 | } |
241 | |
242 | done: |
243 | return length; |
244 | |
245 | #undef note_error |
246 | } |
247 | |
248 | static void sigalrm_handler(int ATTRIBUTE_UNUSED signum) |
249 | { |
250 | } |
251 | |
252 | int rx_main(int argc, char **argv) |
253 | { |
254 | char *fn; |
255 | int ttyfd, filefd; |
256 | struct termios tty, orig_tty; |
257 | struct sigaction act; |
258 | int n; |
259 | char error_buf[256]; |
260 | |
261 | if (argc != 2) |
262 | bb_show_usage(); |
263 | |
264 | fn = argv[1]; |
265 | ttyfd = xopen(CURRENT_TTY, O_RDWR); |
266 | filefd = xopen(fn, O_RDWR|O_CREAT|O_TRUNC); |
267 | |
268 | if (tcgetattr(ttyfd, &tty) < 0) |
269 | bb_perror_msg_and_die("tcgetattr"); |
270 | |
271 | orig_tty = tty; |
272 | |
273 | cfmakeraw(&tty); |
274 | tcsetattr(ttyfd, TCSAFLUSH, &tty); |
275 | |
276 | memset(&act, 0, sizeof(act)); |
277 | act.sa_handler = sigalrm_handler; |
278 | sigaction(SIGALRM, &act, 0); |
279 | |
280 | n = receive(error_buf, sizeof(error_buf), ttyfd, filefd); |
281 | |
282 | close(filefd); |
283 | |
284 | tcsetattr(ttyfd, TCSAFLUSH, &orig_tty); |
285 | |
286 | if (n < 0) |
287 | bb_error_msg_and_die("\nreceive failed:\n %s", error_buf); |
288 | |
289 | fflush_stdout_and_exit(EXIT_SUCCESS); |
290 | } |