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: }