Fix unused parameter warnings
[cu.git] / xmodem.c
blob25f82975c306b3fdd48e624d0910a3926348a354
1 /* $OpenBSD: xmodem.c,v 1.5 2013/07/20 19:27:47 naddy Exp $ */
3 /*
4 * Copyright (c) 2012 Nicholas Marriott <nicm@openbsd.org>
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.
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.
19 #include <sys/types.h>
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 #include <inttypes.h>
29 #include "cu.h"
31 #define XMODEM_BLOCK 128
32 #define XMODEM_RETRIES 10
34 #define XMODEM_SOH '\001'
35 #define XMODEM_EOT '\004'
36 #define XMODEM_ACK '\006'
37 #define XMODEM_NAK '\025'
38 #define XMODEM_SUB '\032'
39 #define XMODEM_C '\103'
41 volatile sig_atomic_t xmodem_stop;
43 void
44 xmodem_signal(int sig __attribute__((unused)))
46 xmodem_stop = 1;
49 uint16_t
50 xmodem_crc16(const u_char *buf, size_t len)
52 uint16_t crc;
53 u_int i, j;
55 crc = 0;
56 for (i = 0; i < len; i++) {
57 crc = crc ^ *buf++ << 8;
58 for (j = 0; j < 8; j++)
59 if (crc & 0x8000)
60 crc = crc << 1 ^ 0x1021;
61 else
62 crc = crc << 1;
64 return (crc);
67 int
68 xmodem_read(u_char *c)
70 for (;;) {
71 switch (read(line_fd, c, 1)) {
72 case -1:
73 if (errno == EINTR && !xmodem_stop)
74 continue;
75 return (-1);
76 case 0:
77 errno = EPIPE;
78 return (-1);
79 case 1:
80 return (0);
85 int
86 xmodem_write(const u_char *buf, size_t len)
88 ssize_t n;
90 while (len > 0) {
91 n = write(line_fd, buf, len);
92 if (n == -1) {
93 if (errno == EINTR && !xmodem_stop)
94 continue;
95 return (-1);
97 buf += n;
98 len -= n;
100 return (0);
103 void
104 xmodem_send(const char *file)
106 FILE *f;
107 u_char buf[3 + XMODEM_BLOCK + 2], c;
108 size_t len, pktlen;
109 uint8_t num;
110 uint16_t crc;
111 int crc_mode;
112 u_int i, total;
113 struct termios tio;
114 struct sigaction act, oact;
116 f = fopen(file, "r");
117 if (f == NULL) {
118 cu_warn("%s", file);
119 return;
122 memset(&act, 0, sizeof(act));
123 sigemptyset(&act.sa_mask);
124 act.sa_flags = 0;
125 act.sa_handler = xmodem_signal;
126 if (sigaction(SIGINT, &act, &oact) != 0)
127 cu_err(1, "sigaction");
128 xmodem_stop = 0;
130 if (isatty(STDIN_FILENO)) {
131 memcpy(&tio, &saved_tio, sizeof(tio));
132 tio.c_lflag &= ~ECHO;
133 if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &tio) != 0)
134 cu_err(1, "tcsetattr");
137 tcflush(line_fd, TCIFLUSH);
138 if (xmodem_read(&c) != 0)
139 goto fail;
140 if (c == XMODEM_C)
141 crc_mode = 1;
142 else if (c == XMODEM_NAK)
143 crc_mode = 0;
144 else {
145 cu_warnx("%s: unexpected response \%03hho", file, c);
146 goto fail;
149 num = 1;
150 total = 1;
151 pktlen = 3 + XMODEM_BLOCK + (crc_mode ? 2 : 1);
152 for (;;) {
153 len = fread(buf + 3, 1, XMODEM_BLOCK, f);
154 if (len == 0)
155 break;
156 memset(buf + 3 + len, XMODEM_SUB, XMODEM_BLOCK - len);
158 buf[0] = XMODEM_SOH;
159 buf[1] = num;
160 buf[2] = 255 - num;
162 if (crc_mode) {
163 crc = xmodem_crc16(buf + 3, XMODEM_BLOCK);
164 buf[3 + XMODEM_BLOCK] = crc >> 8;
165 buf[3 + XMODEM_BLOCK + 1] = crc & 0xFF;
166 } else {
167 buf[3 + XMODEM_BLOCK] = 0;
168 for (i = 0; i < XMODEM_BLOCK; i++)
169 buf[3 + XMODEM_BLOCK] += buf[3 + i];
172 for (i = 0; i < XMODEM_RETRIES; i++) {
173 if (xmodem_stop) {
174 errno = EINTR;
175 goto fail;
177 cu_warnx("%s: sending block %u (attempt %u)", file,
178 total, 1 + i);
179 if (xmodem_write(buf, pktlen) != 0)
180 goto fail;
182 if (xmodem_read(&c) != 0)
183 goto fail;
184 if (c == XMODEM_ACK)
185 break;
186 if (c != XMODEM_NAK) {
187 cu_warnx("%s: unexpected response \%03hho",
188 file, c);
191 if (i == XMODEM_RETRIES) {
192 cu_warnx("%s: too many retries", file);
193 goto out;
196 if (len < XMODEM_BLOCK)
197 break;
198 num++;
199 total++;
202 buf[0] = XMODEM_EOT;
203 if (xmodem_write(buf, 1) != 0)
204 goto fail;
205 cu_warnx("%s: completed %u blocks", file, num);
207 goto out;
209 fail:
210 cu_warn("%s", file);
212 out:
213 set_termios();
215 sigaction(SIGINT, &oact, NULL);
217 fclose(f);