diff options
Diffstat (limited to 'usr.bin')
-rw-r--r-- | usr.bin/cu/Makefile | 4 | ||||
-rw-r--r-- | usr.bin/cu/command.c | 21 | ||||
-rw-r--r-- | usr.bin/cu/cu.1 | 4 | ||||
-rw-r--r-- | usr.bin/cu/cu.h | 6 | ||||
-rw-r--r-- | usr.bin/cu/xmodem.c | 175 |
5 files changed, 205 insertions, 5 deletions
diff --git a/usr.bin/cu/Makefile b/usr.bin/cu/Makefile index df93cbeb190..0d974ecb0f7 100644 --- a/usr.bin/cu/Makefile +++ b/usr.bin/cu/Makefile @@ -1,7 +1,7 @@ -# $OpenBSD: Makefile,v 1.2 2012/07/10 10:28:05 nicm Exp $ +# $OpenBSD: Makefile,v 1.3 2012/07/10 11:42:02 nicm Exp $ PROG= cu -SRCS= cu.c command.c input.c error.c +SRCS= cu.c command.c error.c input.c xmodem.c CDIAGFLAGS+= -Wall -W -Wno-unused-parameter diff --git a/usr.bin/cu/command.c b/usr.bin/cu/command.c index a6e168dfce9..91d1c7cce00 100644 --- a/usr.bin/cu/command.c +++ b/usr.bin/cu/command.c @@ -1,4 +1,4 @@ -/* $OpenBSD: command.c,v 1.7 2012/07/10 10:56:12 nicm Exp $ */ +/* $OpenBSD: command.c,v 1.8 2012/07/10 11:42:02 nicm Exp $ */ /* * Copyright (c) 2012 Nicholas Marriott <nicm@openbsd.org> @@ -35,6 +35,7 @@ void pipe_command(void); void connect_command(void); void send_file(void); +void send_xmodem(void); void pipe_command(void) @@ -159,6 +160,21 @@ send_file(void) } void +send_xmodem(void) +{ + const char *file; + char *expanded; + + file = get_input("Local file?"); + if (file == NULL || *file == '\0') + return; + + expanded = tilde_expand(file); + xmodem_send(expanded); + free(expanded); +} + +void set_speed(void) { const char *s, *errstr; @@ -197,6 +213,9 @@ do_command(char c) case 'S': set_speed(); break; + case 'X': + send_xmodem(); + break; case '$': pipe_command(); break; diff --git a/usr.bin/cu/cu.1 b/usr.bin/cu/cu.1 index edf1bb4e549..e37cb2d7720 100644 --- a/usr.bin/cu/cu.1 +++ b/usr.bin/cu/cu.1 @@ -1,4 +1,4 @@ -.\" $OpenBSD: cu.1,v 1.3 2012/07/10 09:10:04 nicm Exp $ +.\" $OpenBSD: cu.1,v 1.4 2012/07/10 11:42:02 nicm Exp $ .\" .\" Copyright (c) 1980, 1990, 1993 .\" The Regents of the University of California. All rights reserved. @@ -125,6 +125,8 @@ file descriptors: .Ed .It Ic ~S Change the speed of the connection. +.It Ic ~X +Transfer a file with the XMODEM protocol. .It Ic ~? Get a summary of the tilde escapes. .El diff --git a/usr.bin/cu/cu.h b/usr.bin/cu/cu.h index e51e6efe25f..dfd6b30b6b8 100644 --- a/usr.bin/cu/cu.h +++ b/usr.bin/cu/cu.h @@ -1,4 +1,4 @@ -/* $OpenBSD: cu.h,v 1.3 2012/07/10 10:28:05 nicm Exp $ */ +/* $OpenBSD: cu.h,v 1.4 2012/07/10 11:42:02 nicm Exp $ */ /* * Copyright (c) 2012 Nicholas Marriott <nicm@openbsd.org> @@ -23,6 +23,7 @@ void do_command(char); /* cu.c */ +extern struct termios saved_tio; extern struct bufferevent *input_ev; extern struct bufferevent *output_ev; extern int line_fd; @@ -45,4 +46,7 @@ void cu_err(int, const char *, ...) void cu_errx(int, const char *, ...) __attribute__ ((format (printf, 2, 3))); +/* xmodem.c */ +void xmodem_send(const char *); + #endif diff --git a/usr.bin/cu/xmodem.c b/usr.bin/cu/xmodem.c new file mode 100644 index 00000000000..48f2358c770 --- /dev/null +++ b/usr.bin/cu/xmodem.c @@ -0,0 +1,175 @@ +/* $OpenBSD: xmodem.c,v 1.1 2012/07/10 11:42:02 nicm Exp $ */ + +/* + * Copyright (c) 2012 Nicholas Marriott <nicm@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/types.h> + +#include <errno.h> +#include <signal.h> +#include <stdio.h> +#include <string.h> +#include <termios.h> +#include <unistd.h> + +#include "cu.h" + +#define XMODEM_BLOCK 128 +#define XMODEM_RETRIES 10 + +#define XMODEM_SOH '\001' +#define XMODEM_EOT '\004' +#define XMODEM_ACK '\006' +#define XMODEM_NAK '\025' +#define XMODEM_SUB '\032' + +volatile sig_atomic_t xmodem_stop; + +void +xmodem_signal(int sig) +{ + xmodem_stop = 1; +} + +int +xmodem_read(char *c) +{ + for (;;) { + switch (read(line_fd, c, 1)) { + case -1: + if (errno == EINTR && !xmodem_stop) + continue; + return (-1); + case 0: + errno = EPIPE; + return (-1); + case 1: + return (0); + } + } +} + +int +xmodem_write(const u_char *buf, size_t len) +{ + ssize_t n; + + while (len > 0) { + n = write(line_fd, buf, len); + if (n == -1) { + if (errno == EINTR && !xmodem_stop) + continue; + return (-1); + } + buf += n; + len -= n; + } + return (0); +} + +void +xmodem_send(const char *file) +{ + FILE *f; + u_char buf[3 + XMODEM_BLOCK + 1], c; + size_t len; + uint8_t num; + u_int i; + struct termios tio; + struct sigaction act, oact; + + f = fopen(file, "r"); + if (f == NULL) { + cu_warn("%s", file); + return; + } + + memset(&act, 0, sizeof(act)); + sigemptyset(&act.sa_mask); + act.sa_flags = 0; + act.sa_handler = xmodem_signal; + if (sigaction(SIGINT, &act, &oact) != 0) + cu_err(1, "sigaction"); + xmodem_stop = 0; + + if (isatty(STDIN_FILENO)) { + memcpy(&tio, &saved_tio, sizeof(tio)); + tio.c_lflag &= ~ECHO; + if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &tio) != 0) + cu_err(1, "tcsetattr"); + } + + num = 1; + for (;;) { + len = fread(buf + 3, 1, XMODEM_BLOCK, f); + if (len == 0) + break; + memset(buf + 3 + len, XMODEM_SUB, XMODEM_BLOCK - len); + + buf[0] = XMODEM_SOH; + buf[1] = num; + buf[2] = 255 - num; + + buf[3 + XMODEM_BLOCK] = 0; + for (i = 0; i < 128; i++) + buf[3 + XMODEM_BLOCK] += buf[3 + i]; + + for (i = 0; i < XMODEM_RETRIES; i++) { + if (xmodem_stop) { + errno = EINTR; + goto fail; + } + cu_warnx("%s: sending block %u (attempt %u)", file, + num, 1 + i); + if (xmodem_write(buf, sizeof buf) != 0) + goto fail; + + if (xmodem_read(&c) != 0) + goto fail; + if (c == XMODEM_ACK) + break; + if (c != XMODEM_NAK) { + cu_warnx("%s: unexpected response \%03hho", + file, c); + } + } + if (i == XMODEM_RETRIES) { + cu_warnx("%s: too many retries", file); + goto out; + }; + + if (len < XMODEM_BLOCK) + break; + num++; + } + + buf[0] = XMODEM_EOT; + if (xmodem_write(buf, 1) != 0) + goto fail; + cu_warnx("%s: completed %u blocks", file, num); + + goto out; + +fail: + cu_warn("%s", file); + +out: + set_termios(); + + sigaction(SIGINT, &oact, NULL); + + return; +} |