[BACK]Return to xmodem.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / cu

Annotation of src/usr.bin/cu/xmodem.c, Revision 1.5

1.5     ! naddy       1: /* $OpenBSD: xmodem.c,v 1.4 2013/01/17 21:10:24 nicm Exp $ */
1.1       nicm        2:
                      3: /*
                      4:  * Copyright (c) 2012 Nicholas Marriott <nicm@openbsd.org>
                      5:  *
                      6:  * Permission to use, copy, modify, and distribute this software for any
                      7:  * purpose with or without fee is hereby granted, provided that the above
                      8:  * copyright notice and this permission notice appear in all copies.
                      9:  *
                     10:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
                     11:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
                     12:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
                     13:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
                     14:  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
                     15:  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
                     16:  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
                     17:  */
                     18:
                     19: #include <sys/types.h>
                     20:
                     21: #include <errno.h>
                     22: #include <signal.h>
                     23: #include <stdio.h>
                     24: #include <string.h>
                     25: #include <termios.h>
                     26: #include <unistd.h>
                     27:
                     28: #include "cu.h"
                     29:
                     30: #define XMODEM_BLOCK 128
                     31: #define XMODEM_RETRIES 10
                     32:
                     33: #define XMODEM_SOH '\001'
                     34: #define XMODEM_EOT '\004'
                     35: #define XMODEM_ACK '\006'
                     36: #define XMODEM_NAK '\025'
                     37: #define XMODEM_SUB '\032'
1.5     ! naddy      38: #define XMODEM_C   '\103'
1.1       nicm       39:
                     40: volatile sig_atomic_t xmodem_stop;
                     41:
                     42: void
                     43: xmodem_signal(int sig)
                     44: {
                     45:        xmodem_stop = 1;
                     46: }
                     47:
1.5     ! naddy      48: uint16_t
        !            49: xmodem_crc16(const u_char *buf, size_t len)
        !            50: {
        !            51:        uint16_t        crc;
        !            52:        u_int           i, j;
        !            53:
        !            54:        crc = 0;
        !            55:        for (i = 0; i < len; i++) {
        !            56:                crc = crc ^ *buf++ << 8;
        !            57:                for (j = 0; j < 8; j++)
        !            58:                        if (crc & 0x8000)
        !            59:                                crc = crc << 1 ^ 0x1021;
        !            60:                        else
        !            61:                                crc = crc << 1;
        !            62:        }
        !            63:        return (crc);
        !            64: }
        !            65:
1.1       nicm       66: int
                     67: xmodem_read(char *c)
                     68: {
                     69:        for (;;) {
                     70:                switch (read(line_fd, c, 1)) {
                     71:                case -1:
                     72:                        if (errno == EINTR && !xmodem_stop)
                     73:                                continue;
                     74:                        return (-1);
                     75:                case 0:
                     76:                        errno = EPIPE;
                     77:                        return (-1);
                     78:                case 1:
                     79:                        return (0);
                     80:                }
                     81:        }
                     82: }
                     83:
                     84: int
                     85: xmodem_write(const u_char *buf, size_t len)
                     86: {
                     87:        ssize_t n;
                     88:
                     89:        while (len > 0) {
                     90:                n = write(line_fd, buf, len);
                     91:                if (n == -1) {
                     92:                        if (errno == EINTR && !xmodem_stop)
                     93:                                continue;
                     94:                        return (-1);
                     95:                }
                     96:                buf += n;
                     97:                len -= n;
                     98:        }
                     99:        return (0);
                    100: }
                    101:
                    102: void
                    103: xmodem_send(const char *file)
                    104: {
                    105:        FILE                    *f;
1.5     ! naddy     106:        u_char                   buf[3 + XMODEM_BLOCK + 2], c;
        !           107:        size_t                   len, pktlen;
1.1       nicm      108:        uint8_t                  num;
1.5     ! naddy     109:        uint16_t                 crc;
        !           110:        int                      crc_mode;
1.2       nicm      111:        u_int                    i, total;
1.1       nicm      112:        struct termios           tio;
                    113:        struct sigaction         act, oact;
                    114:
                    115:        f = fopen(file, "r");
                    116:        if (f == NULL) {
                    117:                cu_warn("%s", file);
                    118:                return;
                    119:        }
                    120:
                    121:        memset(&act, 0, sizeof(act));
                    122:        sigemptyset(&act.sa_mask);
                    123:        act.sa_flags = 0;
                    124:        act.sa_handler = xmodem_signal;
                    125:        if (sigaction(SIGINT, &act, &oact) != 0)
                    126:                cu_err(1, "sigaction");
                    127:        xmodem_stop = 0;
                    128:
                    129:        if (isatty(STDIN_FILENO)) {
                    130:                memcpy(&tio, &saved_tio, sizeof(tio));
                    131:                tio.c_lflag &= ~ECHO;
                    132:                if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &tio) != 0)
                    133:                        cu_err(1, "tcsetattr");
                    134:        }
                    135:
1.5     ! naddy     136:        tcflush(line_fd, TCIFLUSH);
        !           137:        if (xmodem_read(&c) != 0)
        !           138:                goto fail;
        !           139:        if (c == XMODEM_C)
        !           140:                crc_mode = 1;
        !           141:        else if (c == XMODEM_NAK)
        !           142:                crc_mode = 0;
        !           143:        else {
        !           144:                cu_warnx("%s: unexpected response \%03hho", file, c);
        !           145:                goto fail;
        !           146:        }
        !           147:
1.1       nicm      148:        num = 1;
1.2       nicm      149:        total = 1;
1.5     ! naddy     150:        pktlen = 3 + XMODEM_BLOCK + (crc_mode ? 2 : 1);
1.1       nicm      151:        for (;;) {
                    152:                len = fread(buf + 3, 1, XMODEM_BLOCK, f);
                    153:                if (len == 0)
                    154:                        break;
                    155:                memset(buf + 3 + len, XMODEM_SUB, XMODEM_BLOCK - len);
                    156:
                    157:                buf[0] = XMODEM_SOH;
                    158:                buf[1] = num;
                    159:                buf[2] = 255 - num;
                    160:
1.5     ! naddy     161:                if (crc_mode) {
        !           162:                        crc = xmodem_crc16(buf + 3, XMODEM_BLOCK);
        !           163:                        buf[3 + XMODEM_BLOCK] = crc >> 8;
        !           164:                        buf[3 + XMODEM_BLOCK + 1] = crc & 0xFF;
        !           165:                } else {
        !           166:                        buf[3 + XMODEM_BLOCK] = 0;
        !           167:                        for (i = 0; i < XMODEM_BLOCK; i++)
        !           168:                                buf[3 + XMODEM_BLOCK] += buf[3 + i];
        !           169:                }
1.1       nicm      170:
                    171:                for (i = 0; i < XMODEM_RETRIES; i++) {
                    172:                        if (xmodem_stop) {
                    173:                                errno = EINTR;
                    174:                                goto fail;
                    175:                        }
                    176:                        cu_warnx("%s: sending block %u (attempt %u)", file,
1.2       nicm      177:                            total, 1 + i);
1.5     ! naddy     178:                        if (xmodem_write(buf, pktlen) != 0)
1.1       nicm      179:                                goto fail;
                    180:
                    181:                        if (xmodem_read(&c) != 0)
                    182:                                goto fail;
                    183:                        if (c == XMODEM_ACK)
                    184:                                break;
                    185:                        if (c != XMODEM_NAK) {
                    186:                                cu_warnx("%s: unexpected response \%03hho",
                    187:                                    file, c);
                    188:                        }
                    189:                }
                    190:                if (i == XMODEM_RETRIES) {
                    191:                        cu_warnx("%s: too many retries", file);
                    192:                        goto out;
1.4       nicm      193:                }
1.1       nicm      194:
                    195:                if (len < XMODEM_BLOCK)
                    196:                        break;
                    197:                num++;
1.2       nicm      198:                total++;
1.1       nicm      199:        }
                    200:
                    201:        buf[0] = XMODEM_EOT;
                    202:        if (xmodem_write(buf, 1) != 0)
                    203:                goto fail;
                    204:        cu_warnx("%s: completed %u blocks", file, num);
                    205:
                    206:        goto out;
                    207:
                    208: fail:
                    209:        cu_warn("%s", file);
                    210:
                    211: out:
                    212:        set_termios();
                    213:
                    214:        sigaction(SIGINT, &oact, NULL);
                    215:
1.4       nicm      216:        fclose(f);
1.1       nicm      217: }