Changeset 2725 in MondoRescue for branches/2.2.9/mindi-busybox/miscutils/rx.c


Ignore:
Timestamp:
Feb 25, 2011, 9:26:54 PM (13 years ago)
Author:
Bruno Cornec
Message:
  • Update mindi-busybox to 1.18.3 to avoid problems with the tar command which is now failing on recent versions with busybox 1.7.3
File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/2.2.9/mindi-busybox/miscutils/rx.c

    r1765 r2725  
    11/* vi: set sw=4 ts=4: */
    2 /*-------------------------------------------------------------------------
    3  * Filename:      xmodem.c
     2/*
    43 * Copyright:     Copyright (C) 2001, Hewlett-Packard Company
    54 * Author:        Christopher Hoover <ch@hpl.hp.com>
     
    76 *                and the like
    87 * 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
     8 *
     9 * xmodem functionality for uploading of kernels and the like
    1310 *
    1411 * Copyright (C) 2001 Hewlett-Packard Laboratories
    1512 *
    16  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     13 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    1714 *
    1815 * This was originally written for blob and then adapted for busybox.
    19  *
    2016 */
    2117
     
    2824#define NAK 0x15
    2925#define BS  0x08
     26#define PAD 0x1A
    3027
    3128/*
    32 
    3329Cf:
    34 
    3530  http://www.textfiles.com/apple/xmodem
    3631  http://www.phys.washington.edu/~belonis/xmodem/docxmodem.txt
    3732  http://www.phys.washington.edu/~belonis/xmodem/docymodem.txt
    3833  http://www.phys.washington.edu/~belonis/xmodem/modmprot.col
    39 
    4034*/
    4135
     
    4438#define MAXERRORS 10
    4539
    46 static int read_byte(int fd, unsigned int timeout)
    47 {
    48     char buf[1];
     40#define read_fd  STDIN_FILENO
     41#define write_fd STDOUT_FILENO
     42
     43static int read_byte(unsigned timeout)
     44{
     45    unsigned char buf;
    4946    int n;
    5047
    5148    alarm(timeout);
    52 
    53     n = read(fd, &buf, 1);
    54 
     49    /* NOT safe_read! We want ALRM to interrupt us */
     50    n = read(read_fd, &buf, 1);
    5551    alarm(0);
    56 
    5752    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)
     53        return buf;
     54    return -1;
     55}
     56
     57static int receive(/*int read_fd, */int file_fd)
     58{
     59    unsigned char blockBuf[1024];
     60    unsigned blockLength = 0;
     61    unsigned errors = 0;
     62    unsigned wantBlockNo = 1;
     63    unsigned length = 0;
     64    int do_crc = 1;
     65    char reply_char;
     66    unsigned timeout = TIMEOUT_LONG;
    7667
    7768    /* Flush pending input */
    78     tcflush(ttyfd, TCIFLUSH);
     69    tcflush(read_fd, TCIFLUSH);
    7970
    8071    /* Ask for CRC; if we get errors, we will go with checksum */
    81     write(ttyfd, &nak, 1);
     72    reply_char = 'C';
     73    full_write(write_fd, &reply_char, 1);
    8274
    8375    for (;;) {
    8476        int blockBegin;
    8577        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);
     78        int cksum_or_crc;
     79        int expected;
     80        int i, j;
     81
     82        blockBegin = read_byte(timeout);
    9283        if (blockBegin < 0)
    9384            goto timeout;
    9485
     86        /* If last block, remove padding */
     87        if (blockBegin == EOT) {
     88            /* Data blocks can be padded with ^Z characters */
     89            /* This code tries to detect and remove them */
     90            if (blockLength >= 3
     91             && blockBuf[blockLength - 1] == PAD
     92             && blockBuf[blockLength - 2] == PAD
     93             && blockBuf[blockLength - 3] == PAD
     94            ) {
     95                while (blockLength
     96                       && blockBuf[blockLength - 1] == PAD
     97                ) {
     98                    blockLength--;
     99                }
     100            }
     101        }
     102        /* Write previously received block */
     103        if (blockLength) {
     104            errno = 0;
     105            if (full_write(file_fd, blockBuf, blockLength) != blockLength) {
     106                bb_perror_msg("can't write to file");
     107                goto fatal;
     108            }
     109        }
     110
    95111        timeout = TIMEOUT;
    96         nak = NAK;
     112        reply_char = NAK;
    97113
    98114        switch (blockBegin) {
     
    100116        case STX:
    101117            break;
    102 
    103118        case EOT:
    104             nak = ACK;
    105             write(ttyfd, &nak, 1);
    106             goto done;
    107 
     119            reply_char = ACK;
     120            full_write(write_fd, &reply_char, 1);
     121            return length;
    108122        default:
    109123            goto error;
    110124        }
    111125
    112         /* block no */
    113         blockNo = read_byte(ttyfd, TIMEOUT);
     126        /* Block no */
     127        blockNo = read_byte(TIMEOUT);
    114128        if (blockNo < 0)
    115129            goto timeout;
    116130
    117         /* block no one's compliment */
    118         blockNoOnesCompl = read_byte(ttyfd, TIMEOUT);
     131        /* Block no, in one's complement form */
     132        blockNoOnesCompl = read_byte(TIMEOUT);
    119133        if (blockNoOnesCompl < 0)
    120134            goto timeout;
    121135
    122136        if (blockNo != (255 - blockNoOnesCompl)) {
    123             note_error("bad block ones compl");
     137            bb_error_msg("bad block ones compl");
    124138            goto error;
    125139        }
     
    127141        blockLength = (blockBegin == SOH) ? 128 : 1024;
    128142
    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)
     143        for (i = 0; i < blockLength; i++) {
     144            int cc = read_byte(TIMEOUT);
     145            if (cc < 0)
     146                goto timeout;
     147            blockBuf[i] = cc;
     148        }
     149
     150        if (do_crc) {
     151            cksum_or_crc = read_byte(TIMEOUT);
     152            if (cksum_or_crc < 0)
     153                goto timeout;
     154            cksum_or_crc = (cksum_or_crc << 8) | read_byte(TIMEOUT);
     155            if (cksum_or_crc < 0)
    147156                goto timeout;
    148157        } else {
    149             cksum = read_byte(ttyfd, TIMEOUT);
    150             if (cksum < 0)
     158            cksum_or_crc = read_byte(TIMEOUT);
     159            if (cksum_or_crc < 0)
    151160                goto timeout;
    152161        }
     
    157166            /* meta data. */
    158167            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 
     168        }
     169        if (blockNo != (wantBlockNo & 0xff)) {
     170            bb_error_msg("unexpected block no, 0x%08x, expecting 0x%08x", blockNo, wantBlockNo);
     171            goto error;
     172        }
     173
     174        expected = 0;
     175        if (do_crc) {
    170176            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;
     177                expected = expected ^ blockBuf[i] << 8;
     178                for (j = 0; j < 8; j++) {
     179                    if (expected & 0x8000)
     180                        expected = (expected << 1) ^ 0x1021;
    175181                    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             }
     182                        expected = (expected << 1);
     183                }
     184            }
     185            expected &= 0xffff;
    187186        } else {
    188             unsigned char expectedCksum = 0;
    189             int i;
    190 
    191187            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             }
     188                expected += blockBuf[i];
     189            expected &= 0xff;
     190        }
     191        if (cksum_or_crc != expected) {
     192            bb_error_msg(do_crc ? "crc error, expected 0x%04x, got 0x%04x"
     193                               : "checksum error, expected 0x%02x, got 0x%02x",
     194                    expected, cksum_or_crc);
     195            goto error;
    198196        }
    199197
    200198        wantBlockNo++;
    201199        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:
     200 next:
    209201        errors = 0;
    210         nak = ACK;
    211         write(ttyfd, &nak, 1);
     202        reply_char = ACK;
     203        full_write(write_fd, &reply_char, 1);
    212204        continue;
    213 
    214     error:
    215     timeout:
     205 error:
     206 timeout:
    216207        errors++;
    217208        if (errors == MAXERRORS) {
    218209            /* Abort */
    219210
    220             // if using crc, try again w/o crc
    221             if (nak == 'C') {
    222                 nak = NAK;
     211            /* If were asking for crc, try again w/o crc */
     212            if (reply_char == 'C') {
     213                reply_char = NAK;
    223214                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);
     215                do_crc = 0;
     216                goto timeout;
     217            }
     218            bb_error_msg("too many errors; giving up");
     219 fatal:
     220            /* 5 CAN followed by 5 BS. Don't try too hard... */
     221            safe_write(write_fd, "\030\030\030\030\030\010\010\010\010\010", 10);
    233222            return -1;
    234223        }
    235224
    236225        /* Flush pending input */
    237         tcflush(ttyfd, TCIFLUSH);
    238 
    239         write(ttyfd, &nak, 1);
     226        tcflush(read_fd, TCIFLUSH);
     227
     228        full_write(write_fd, &reply_char, 1);
     229    } /* for (;;) */
     230}
     231
     232static void sigalrm_handler(int UNUSED_PARAM signum)
     233{
     234}
     235
     236int rx_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     237int rx_main(int argc UNUSED_PARAM, char **argv)
     238{
     239    struct termios tty, orig_tty;
     240    int termios_err;
     241    int file_fd;
     242    int n;
     243
     244    /* Disabled by vda:
     245     * why we can't receive from stdin? Why we *require*
     246     * controlling tty?? */
     247    /*read_fd = xopen(CURRENT_TTY, O_RDWR);*/
     248    file_fd = xopen(single_argv(argv), O_RDWR|O_CREAT|O_TRUNC);
     249
     250    termios_err = tcgetattr(read_fd, &tty);
     251    if (termios_err == 0) {
     252        orig_tty = tty;
     253        cfmakeraw(&tty);
     254        tcsetattr(read_fd, TCSAFLUSH, &tty);
    240255    }
    241256
    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 int rx_main(int argc, char **argv)
    254 {
    255     char *fn;
    256     int ttyfd, filefd;
    257     struct termios tty, orig_tty;
    258     struct sigaction act;
    259     int n;
    260     char error_buf[256];
    261 
    262     if (argc != 2)
    263             bb_show_usage();
    264 
    265     fn = argv[1];
    266     ttyfd = xopen(CURRENT_TTY, O_RDWR);
    267     filefd = xopen(fn, O_RDWR|O_CREAT|O_TRUNC);
    268 
    269     if (tcgetattr(ttyfd, &tty) < 0)
    270             bb_perror_msg_and_die("tcgetattr");
    271 
    272     orig_tty = tty;
    273 
    274     cfmakeraw(&tty);
    275     tcsetattr(ttyfd, TCSAFLUSH, &tty);
    276 
    277     memset(&act, 0, sizeof(act));
    278     act.sa_handler = sigalrm_handler;
    279     sigaction(SIGALRM, &act, 0);
    280 
    281     n = receive(error_buf, sizeof(error_buf), ttyfd, filefd);
    282 
    283     close(filefd);
    284 
    285     tcsetattr(ttyfd, TCSAFLUSH, &orig_tty);
    286 
    287     if (n < 0)
    288         bb_error_msg_and_die("\nreceive failed:\n  %s", error_buf);
    289 
    290     fflush_stdout_and_exit(EXIT_SUCCESS);
    291 }
     257    /* No SA_RESTART: we want ALRM to interrupt read() */
     258    signal_no_SA_RESTART_empty_mask(SIGALRM, sigalrm_handler);
     259
     260    n = receive(file_fd);
     261
     262    if (termios_err == 0)
     263        tcsetattr(read_fd, TCSAFLUSH, &orig_tty);
     264    if (ENABLE_FEATURE_CLEAN_UP)
     265        close(file_fd);
     266    fflush_stdout_and_exit(n >= 0);
     267}
Note: See TracChangeset for help on using the changeset viewer.