[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.4

1.4     ! nicm        1: /* $OpenBSD: xmodem.c,v 1.3 2012/11/21 19:48:49 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'
                     38:
                     39: volatile sig_atomic_t xmodem_stop;
                     40:
                     41: void
                     42: xmodem_signal(int sig)
                     43: {
                     44:        xmodem_stop = 1;
                     45: }
                     46:
                     47: int
                     48: xmodem_read(char *c)
                     49: {
                     50:        for (;;) {
                     51:                switch (read(line_fd, c, 1)) {
                     52:                case -1:
                     53:                        if (errno == EINTR && !xmodem_stop)
                     54:                                continue;
                     55:                        return (-1);
                     56:                case 0:
                     57:                        errno = EPIPE;
                     58:                        return (-1);
                     59:                case 1:
                     60:                        return (0);
                     61:                }
                     62:        }
                     63: }
                     64:
                     65: int
                     66: xmodem_write(const u_char *buf, size_t len)
                     67: {
                     68:        ssize_t n;
                     69:
                     70:        while (len > 0) {
                     71:                n = write(line_fd, buf, len);
                     72:                if (n == -1) {
                     73:                        if (errno == EINTR && !xmodem_stop)
                     74:                                continue;
                     75:                        return (-1);
                     76:                }
                     77:                buf += n;
                     78:                len -= n;
                     79:        }
                     80:        return (0);
                     81: }
                     82:
                     83: void
                     84: xmodem_send(const char *file)
                     85: {
                     86:        FILE                    *f;
                     87:        u_char                   buf[3 + XMODEM_BLOCK + 1], c;
                     88:        size_t                   len;
                     89:        uint8_t                  num;
1.2       nicm       90:        u_int                    i, total;
1.1       nicm       91:        struct termios           tio;
                     92:        struct sigaction         act, oact;
                     93:
                     94:        f = fopen(file, "r");
                     95:        if (f == NULL) {
                     96:                cu_warn("%s", file);
                     97:                return;
                     98:        }
                     99:
                    100:        memset(&act, 0, sizeof(act));
                    101:        sigemptyset(&act.sa_mask);
                    102:        act.sa_flags = 0;
                    103:        act.sa_handler = xmodem_signal;
                    104:        if (sigaction(SIGINT, &act, &oact) != 0)
                    105:                cu_err(1, "sigaction");
                    106:        xmodem_stop = 0;
                    107:
                    108:        if (isatty(STDIN_FILENO)) {
                    109:                memcpy(&tio, &saved_tio, sizeof(tio));
                    110:                tio.c_lflag &= ~ECHO;
                    111:                if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &tio) != 0)
                    112:                        cu_err(1, "tcsetattr");
                    113:        }
                    114:
                    115:        num = 1;
1.2       nicm      116:        total = 1;
1.1       nicm      117:        for (;;) {
                    118:                len = fread(buf + 3, 1, XMODEM_BLOCK, f);
                    119:                if (len == 0)
                    120:                        break;
                    121:                memset(buf + 3 + len, XMODEM_SUB, XMODEM_BLOCK - len);
                    122:
                    123:                buf[0] = XMODEM_SOH;
                    124:                buf[1] = num;
                    125:                buf[2] = 255 - num;
                    126:
                    127:                buf[3 + XMODEM_BLOCK] = 0;
                    128:                for (i = 0; i < 128; i++)
                    129:                        buf[3 + XMODEM_BLOCK] += buf[3 + i];
                    130:
                    131:                for (i = 0; i < XMODEM_RETRIES; i++) {
                    132:                        if (xmodem_stop) {
                    133:                                errno = EINTR;
                    134:                                goto fail;
                    135:                        }
                    136:                        cu_warnx("%s: sending block %u (attempt %u)", file,
1.2       nicm      137:                            total, 1 + i);
1.1       nicm      138:                        if (xmodem_write(buf, sizeof buf) != 0)
                    139:                                goto fail;
                    140:
                    141:                        if (xmodem_read(&c) != 0)
                    142:                                goto fail;
                    143:                        if (c == XMODEM_ACK)
                    144:                                break;
                    145:                        if (c != XMODEM_NAK) {
                    146:                                cu_warnx("%s: unexpected response \%03hho",
                    147:                                    file, c);
                    148:                        }
                    149:                }
                    150:                if (i == XMODEM_RETRIES) {
                    151:                        cu_warnx("%s: too many retries", file);
                    152:                        goto out;
1.4     ! nicm      153:                }
1.1       nicm      154:
                    155:                if (len < XMODEM_BLOCK)
                    156:                        break;
                    157:                num++;
1.2       nicm      158:                total++;
1.1       nicm      159:        }
                    160:
                    161:        buf[0] = XMODEM_EOT;
                    162:        if (xmodem_write(buf, 1) != 0)
                    163:                goto fail;
                    164:        cu_warnx("%s: completed %u blocks", file, num);
                    165:
                    166:        goto out;
                    167:
                    168: fail:
                    169:        cu_warn("%s", file);
                    170:
                    171: out:
                    172:        set_termios();
                    173:
                    174:        sigaction(SIGINT, &oact, NULL);
                    175:
1.4     ! nicm      176:        fclose(f);
1.1       nicm      177: }