1 /* vi: set sw=4 ts=4: */
3 * Copyright: Copyright (C) 2001, Hewlett-Packard Company
4 * Author: Christopher Hoover <ch@hpl.hp.com>
5 * Description: xmodem functionality for uploading of kernels
7 * Created at: Thu Dec 20 01:58:08 PST 2001
9 * xmodem functionality for uploading of kernels and the like
11 * Copyright (C) 2001 Hewlett-Packard Laboratories
13 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
15 * This was originally written for blob and then adapted for busybox.
18 //usage:#define rx_trivial_usage
20 //usage:#define rx_full_usage "\n\n"
21 //usage: "Receive a file using the xmodem protocol"
23 //usage:#define rx_example_usage
24 //usage: "$ rx /tmp/foo\n"
38 http://www.textfiles.com/apple/xmodem
39 http://www.phys.washington.edu/~belonis/xmodem/docxmodem.txt
40 http://www.phys.washington.edu/~belonis/xmodem/docymodem.txt
41 http://www.phys.washington.edu/~belonis/xmodem/modmprot.col
45 #define TIMEOUT_LONG 10
48 #define read_fd STDIN_FILENO
49 #define write_fd STDOUT_FILENO
51 static int read_byte(unsigned timeout
)
57 /* NOT safe_read! We want ALRM to interrupt us */
58 n
= read(read_fd
, &buf
, 1);
65 static int receive(/*int read_fd, */int file_fd
)
67 unsigned char blockBuf
[1024];
68 unsigned blockLength
= 0;
70 unsigned wantBlockNo
= 1;
74 unsigned timeout
= TIMEOUT_LONG
;
76 /* Flush pending input */
77 tcflush(read_fd
, TCIFLUSH
);
79 /* Ask for CRC; if we get errors, we will go with checksum */
81 full_write(write_fd
, &reply_char
, 1);
85 int blockNo
, blockNoOnesCompl
;
90 blockBegin
= read_byte(timeout
);
94 /* If last block, remove padding */
95 if (blockBegin
== EOT
) {
96 /* Data blocks can be padded with ^Z characters */
97 /* This code tries to detect and remove them */
99 && blockBuf
[blockLength
- 1] == PAD
100 && blockBuf
[blockLength
- 2] == PAD
101 && blockBuf
[blockLength
- 3] == PAD
104 && blockBuf
[blockLength
- 1] == PAD
110 /* Write previously received block */
112 if (full_write(file_fd
, blockBuf
, blockLength
) != blockLength
) {
113 bb_perror_msg(bb_msg_write_error
);
120 switch (blockBegin
) {
126 full_write(write_fd
, &reply_char
, 1);
133 blockNo
= read_byte(TIMEOUT
);
137 /* Block no, in one's complement form */
138 blockNoOnesCompl
= read_byte(TIMEOUT
);
139 if (blockNoOnesCompl
< 0)
142 if (blockNo
!= (255 - blockNoOnesCompl
)) {
143 bb_error_msg("bad block ones compl");
147 blockLength
= (blockBegin
== SOH
) ? 128 : 1024;
149 for (i
= 0; i
< blockLength
; i
++) {
150 int cc
= read_byte(TIMEOUT
);
156 cksum_or_crc
= read_byte(TIMEOUT
);
157 if (cksum_or_crc
< 0)
160 cksum_or_crc
= (cksum_or_crc
<< 8) | read_byte(TIMEOUT
);
161 if (cksum_or_crc
< 0)
165 if (blockNo
== ((wantBlockNo
- 1) & 0xff)) {
166 /* a repeat of the last block is ok, just ignore it. */
167 /* this also ignores the initial block 0 which is */
172 if (blockNo
!= (wantBlockNo
& 0xff)) {
173 bb_error_msg("unexpected block no, 0x%08x, expecting 0x%08x", blockNo
, wantBlockNo
);
179 for (i
= 0; i
< blockLength
; i
++) {
180 expected
= expected
^ blockBuf
[i
] << 8;
181 for (j
= 0; j
< 8; j
++) {
182 if (expected
& 0x8000)
183 expected
= (expected
<< 1) ^ 0x1021;
185 expected
= (expected
<< 1);
190 for (i
= 0; i
< blockLength
; i
++)
191 expected
+= blockBuf
[i
];
194 if (cksum_or_crc
!= expected
) {
195 bb_error_msg(do_crc
? "crc error, expected 0x%04x, got 0x%04x"
196 : "checksum error, expected 0x%02x, got 0x%02x",
197 expected
, cksum_or_crc
);
202 length
+= blockLength
;
206 full_write(write_fd
, &reply_char
, 1);
212 if (errors
== MAXERRORS
) {
215 /* If were asking for crc, try again w/o crc */
216 if (reply_char
== 'C') {
222 bb_error_msg("too many errors; giving up");
224 /* 5 CAN followed by 5 BS. Don't try too hard... */
225 safe_write(write_fd
, "\030\030\030\030\030\010\010\010\010\010", 10);
229 /* Flush pending input */
230 tcflush(read_fd
, TCIFLUSH
);
232 full_write(write_fd
, &reply_char
, 1);
236 static void sigalrm_handler(int UNUSED_PARAM signum
)
240 int rx_main(int argc
, char **argv
) MAIN_EXTERNALLY_VISIBLE
;
241 int rx_main(int argc UNUSED_PARAM
, char **argv
)
243 struct termios tty
, orig_tty
;
249 * why we can't receive from stdin? Why we *require*
250 * controlling tty?? */
251 /*read_fd = xopen(CURRENT_TTY, O_RDWR);*/
252 file_fd
= xopen(single_argv(argv
), O_RDWR
|O_CREAT
|O_TRUNC
);
254 termios_err
= tcgetattr(read_fd
, &tty
);
255 if (termios_err
== 0) {
258 tcsetattr(read_fd
, TCSAFLUSH
, &tty
);
261 /* No SA_RESTART: we want ALRM to interrupt read() */
262 signal_no_SA_RESTART_empty_mask(SIGALRM
, sigalrm_handler
);
264 n
= receive(file_fd
);
266 if (termios_err
== 0)
267 tcsetattr(read_fd
, TCSAFLUSH
, &orig_tty
);
268 if (ENABLE_FEATURE_CLEAN_UP
)
270 fflush_stdout_and_exit(n
>= 0);