summaryrefslogtreecommitdiff
path: root/usr.bin
diff options
context:
space:
mode:
authorNicholas Marriott <nicm@cvs.openbsd.org>2012-07-10 11:42:03 +0000
committerNicholas Marriott <nicm@cvs.openbsd.org>2012-07-10 11:42:03 +0000
commiteeb061e6a00c9fe390c9aabd9f328893f1ed5811 (patch)
tree3ca36238903302013cd70cfa62a17169b4ca36d6 /usr.bin
parent4d9df6d17f7fe7a627c4f8a824e27f6655a49860 (diff)
Add builtin XMODEM send support with ~X, only tested with lrz -X so far.
Diffstat (limited to 'usr.bin')
-rw-r--r--usr.bin/cu/Makefile4
-rw-r--r--usr.bin/cu/command.c21
-rw-r--r--usr.bin/cu/cu.14
-rw-r--r--usr.bin/cu/cu.h6
-rw-r--r--usr.bin/cu/xmodem.c175
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;
+}