pax_global_header00006660000000000000000000000064142206002200014476gustar00rootroot0000000000000052 comment=c6cb8ae20ca4912b186522186f03b3567b785182 opencu-3/000077500000000000000000000000001422060022000124735ustar00rootroot00000000000000opencu-3/CMakeLists.txt000066400000000000000000000036471422060022000152450ustar00rootroot00000000000000# Copyright (c) 2022 Tobias Heider # # 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 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. cmake_minimum_required(VERSION 3.12) include(CheckFunctionExists) include(CheckIncludeFiles) project(cu) add_definitions(-D_GNU_SOURCE) check_function_exists(closefrom HAVE_CLOSEFROM) if(HAVE_CLOSEFROM) add_definitions(-DHAVE_CLOSEFROM) endif() check_include_files("linux/close_range.h" HAVE_LINUX_CLOSE_RANGE_H) if(HAVE_LINUX_CLOSE_RANGE_H) add_definitions(-DHAVE_LINUX_CLOSE_RANGE_H) endif() check_function_exists(close_range HAVE_CLOSE_RANGE) if(HAVE_CLOSE_RANGE) add_definitions(-DHAVE_CLOSE_RANGE) endif() set(CFLAGS) list(APPEND CFLAGS -O2 -Wall -Wno-pointer-sign -Wno-deprecated-declarations -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -Wshadow -Wpointer-arith -Wcast-qual -Wsign-compare "$<$:-O0;-g>" ) add_executable(cu command.c cu.c error.c input.c xmodem.c compat/closefrom.c compat/strtonum.c compat/vis.c ) target_compile_options(cu PRIVATE ${CFLAGS}) target_link_libraries(cu event) target_include_directories(cu PUBLIC compat ) install(TARGETS cu RUNTIME DESTINATION bin) set (CMAKE_INSTALL_MANDIR /usr/share/man) install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/cu.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1/) opencu-3/LICENSE000066400000000000000000000012741422060022000135040ustar00rootroot00000000000000Permission 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. opencu-3/Makefile000066400000000000000000000003341422060022000141330ustar00rootroot00000000000000# $OpenBSD: Makefile,v 1.3 2012/07/10 11:42:02 nicm Exp $ PROG= cu SRCS= cu.c command.c error.c input.c xmodem.c CDIAGFLAGS+= -Wall -W -Wno-unused-parameter LDADD= -levent DPADD= ${LIBEVENT} .include opencu-3/README.md000066400000000000000000000003551422060022000137550ustar00rootroot00000000000000# cu(1) - serial terminal emulator This is a port of OpenBSD's serial terminal emulator cu(1) to Linux. ## Dependencies Portable cu(1) is built using cmake. It requires a working C compiler, standard library and headers and libevent. opencu-3/command.c000066400000000000000000000136061422060022000142630ustar00rootroot00000000000000/* $OpenBSD: command.c,v 1.18 2019/06/28 13:35:00 deraadt Exp $ */ /* * Copyright (c) 2012 Nicholas Marriott * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include "cu.h" void pipe_command(void); void connect_command(void); void send_file(void); void send_xmodem(void); void set_speed(void); void start_record(void); void pipe_command(void) { const char *cmd; pid_t pid; int fd; cmd = get_input("Local command?"); if (cmd == NULL || *cmd == '\0') return; restore_termios(); set_blocking(line_fd, 1); switch (pid = fork()) { case -1: cu_err(1, "fork"); case 0: fd = open(_PATH_DEVNULL, O_RDWR); if (fd == -1 || dup2(fd, STDIN_FILENO) == -1) _exit(1); close(fd); if (signal(SIGINT, SIG_DFL) == SIG_ERR) _exit(1); if (signal(SIGQUIT, SIG_DFL) == SIG_ERR) _exit(1); /* attach stdout to line */ if (dup2(line_fd, STDOUT_FILENO) == -1) _exit(1); #ifdef __OpenBSD__ if (closefrom(STDERR_FILENO + 1) != 0) _exit(1); #else closefrom(STDERR_FILENO + 1); #endif execl(_PATH_BSHELL, "sh", "-c", cmd, (char *)NULL); _exit(1); default: while (waitpid(pid, NULL, 0) == -1 && errno == EINTR) /* nothing */; break; } set_blocking(line_fd, 0); set_termios(); } void connect_command(void) { const char *cmd; pid_t pid; /* * Fork a program with: * 0 <-> remote tty in * 1 <-> remote tty out * 2 <-> local tty stderr */ cmd = get_input("Local command?"); if (cmd == NULL || *cmd == '\0') return; restore_termios(); set_blocking(line_fd, 1); switch (pid = fork()) { case -1: cu_err(1, "fork"); case 0: if (signal(SIGINT, SIG_DFL) == SIG_ERR) _exit(1); if (signal(SIGQUIT, SIG_DFL) == SIG_ERR) _exit(1); /* attach stdout and stdin to line */ if (dup2(line_fd, STDOUT_FILENO) == -1) _exit(1); if (dup2(line_fd, STDIN_FILENO) == -1) _exit(1); #ifdef __OpenBSD__ if (closefrom(STDERR_FILENO + 1) != 0) _exit(1); #else closefrom(STDERR_FILENO + 1); #endif execl(_PATH_BSHELL, "sh", "-c", cmd, (char *)NULL); _exit(1); default: while (waitpid(pid, NULL, 0) == -1 && errno == EINTR) /* nothing */; break; } set_blocking(line_fd, 0); set_termios(); } void send_file(void) { const char *file; FILE *f; char buf[BUFSIZ], *expanded; size_t len; file = get_input("Local file?"); if (file == NULL || *file == '\0') return; expanded = tilde_expand(file); f = fopen(expanded, "r"); if (f == NULL) { cu_warn("%s", file); return; } while (!feof(f) && !ferror(f)) { len = fread(buf, 1, sizeof(buf), f); if (len != 0) bufferevent_write(line_ev, buf, len); } fclose(f); free(expanded); } 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; int speed; s = get_input("New speed?"); if (s == NULL || *s == '\0') return; speed = strtonum(s, 0, UINT_MAX, &errstr); if (errstr != NULL) { cu_warnx("speed is %s: %s", errstr, s); return; } if (set_line(speed) != 0) cu_warn("tcsetattr"); } void start_record(void) { const char *file; if (record_file != NULL) { fclose(record_file); record_file = NULL; } file = get_input("Record file?"); if (file == NULL || *file == '\0') return; record_file = fopen(file, "a"); if (record_file == NULL) cu_warnx("%s", file); } void do_command(char c) { char esc[4 + 1]; if (restricted && strchr("CRX$>", c) != NULL) { cu_warnx("~%c command is not allowed in restricted mode", c); return; } switch (c) { case '.': case '\004': /* ^D */ event_loopexit(NULL); break; case '\032': /* ^Z */ restore_termios(); kill(getpid(), SIGTSTP); set_termios(); break; case 'C': connect_command(); break; case 'D': { #ifdef __OpenBSD__ ioctl(line_fd, TIOCCDTR, NULL); sleep(1); ioctl(line_fd, TIOCSDTR, NULL); #else const int dtrbits = TIOCM_DTR; ioctl(line_fd, TIOCMBIC, &dtrbits); sleep(1); ioctl(line_fd, TIOCMBIS, &dtrbits); #endif break; } case 'R': start_record(); break; case 'S': set_speed(); break; case 'X': send_xmodem(); break; case '$': pipe_command(); break; case '>': send_file(); break; case '#': ioctl(line_fd, TIOCSBRK, NULL); sleep(1); ioctl(line_fd, TIOCCBRK, NULL); break; default: if ((u_char)c == escape_char) bufferevent_write(line_ev, &c, 1); break; case '?': vis(esc, escape_char, VIS_WHITE | VIS_NOSLASH, 0); printf("\r\n" "%s# send break\r\n" "%s$ pipe local command to remote host\r\n" "%s> send file to remote host\r\n" "%sC connect program to remote host\r\n" "%sD de-assert DTR line briefly\r\n" "%sR start recording to file\r\n" "%sS set speed\r\n" "%sX send file with XMODEM\r\n" "%s? get this summary\r\n", esc, esc, esc, esc, esc, esc, esc, esc, esc ); break; } } opencu-3/compat/000077500000000000000000000000001422060022000137565ustar00rootroot00000000000000opencu-3/compat/closefrom.c000066400000000000000000000035021422060022000161130ustar00rootroot00000000000000/* * Copyright (c) 2004-2005, 2007, 2010, 2012-2015, 2017-2022 * Todd C. Miller * * 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 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. */ #ifdef HAVE_LINUX_CLOSE_RANGE_H #include #endif #include #include #include "unistd.h" #ifndef OPEN_MAX # define OPEN_MAX 256 #endif #if defined(HAVE_CLOSE_RANGE) void closefrom(int lowfd) { close_range(lowfd, ~0U, 0); } #else /* * Close all file descriptors greater than or equal to lowfd. * This is the expensive (fallback) method. */ void closefrom(int lowfd) { long fd, maxfd; /* * Fall back on sysconf(_SC_OPEN_MAX). This is equivalent to * checking the RLIMIT_NOFILE soft limit. It is possible for * there to be open file descriptors past this limit but there's * not much we can do about that since the hard limit may be * RLIM_INFINITY (LLONG_MAX or ULLONG_MAX on modern systems). */ maxfd = sysconf(_SC_OPEN_MAX); if (maxfd < OPEN_MAX) maxfd = OPEN_MAX; /* Make sure we didn't get RLIM_INFINITY as the upper limit. */ if (maxfd > INT_MAX) maxfd = INT_MAX; for (fd = lowfd; fd < maxfd; fd++) { (void)close((int)fd); } } #endif opencu-3/compat/stdlib.h000066400000000000000000000003241422060022000154070ustar00rootroot00000000000000/* * stdlib.h compatibility shim * Public domain */ #include_next #ifndef CUCOMPAT_STDLIB_H long long strtonum(const char *nptr, long long minval, long long maxval, const char **errstr); #endif opencu-3/compat/strtonum.c000066400000000000000000000033541422060022000160220ustar00rootroot00000000000000/* $OpenBSD: strtonum.c,v 1.8 2015/09/13 08:31:48 guenther Exp $ */ /* * Copyright (c) 2004 Ted Unangst and Todd Miller * All rights reserved. * * 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 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 #include #include #define INVALID 1 #define TOOSMALL 2 #define TOOLARGE 3 long long strtonum(const char *numstr, long long minval, long long maxval, const char **errstrp) { long long ll = 0; int error = 0; char *ep; struct errval { const char *errstr; int err; } ev[4] = { { NULL, 0 }, { "invalid", EINVAL }, { "too small", ERANGE }, { "too large", ERANGE }, }; ev[0].err = errno; errno = 0; if (minval > maxval) { error = INVALID; } else { ll = strtoll(numstr, &ep, 10); if (numstr == ep || *ep != '\0') error = INVALID; else if ((ll == LLONG_MIN && errno == ERANGE) || ll < minval) error = TOOSMALL; else if ((ll == LLONG_MAX && errno == ERANGE) || ll > maxval) error = TOOLARGE; } if (errstrp != NULL) *errstrp = ev[error].errstr; errno = ev[error].err; if (error) ll = 0; return (ll); } opencu-3/compat/unistd.h000066400000000000000000000003021422060022000154300ustar00rootroot00000000000000/* * unistd.h compatibility shim * Public domain */ #include_next #ifndef CUCOMPAT_UNISTD_H #define CUCOMPAT_UNISTD_H #ifndef HAVE_CLOSEFROM void closefrom(int); #endif #endif opencu-3/compat/vis.c000066400000000000000000000072761422060022000147370ustar00rootroot00000000000000/* $OpenBSD: vis.c,v 1.19 2005/09/01 17:15:49 millert Exp $ */ /*- * Copyright (c) 1989, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* OPENBSD ORIGINAL: lib/libc/gen/vis.c */ #if !defined(HAVE_STRNVIS) #include #include #include "vis.h" #define isoctal(c) (((u_char)(c)) >= '0' && ((u_char)(c)) <= '7') #define isvisible(c) \ (((u_int)(c) <= UCHAR_MAX && isascii((u_char)(c)) && \ (((c) != '*' && (c) != '?' && (c) != '[' && (c) != '#') || \ (flag & VIS_GLOB) == 0) && isgraph((u_char)(c))) || \ ((flag & VIS_SP) == 0 && (c) == ' ') || \ ((flag & VIS_TAB) == 0 && (c) == '\t') || \ ((flag & VIS_NL) == 0 && (c) == '\n') || \ ((flag & VIS_SAFE) && ((c) == '\b' || \ (c) == '\007' || (c) == '\r' || \ isgraph((u_char)(c))))) /* * vis - visually encode characters */ char * vis(char *dst, int c, int flag, int nextc) { if (isvisible(c)) { *dst++ = c; if (c == '\\' && (flag & VIS_NOSLASH) == 0) *dst++ = '\\'; *dst = '\0'; return (dst); } if (flag & VIS_CSTYLE) { switch(c) { case '\n': *dst++ = '\\'; *dst++ = 'n'; goto done; case '\r': *dst++ = '\\'; *dst++ = 'r'; goto done; case '\b': *dst++ = '\\'; *dst++ = 'b'; goto done; case '\a': *dst++ = '\\'; *dst++ = 'a'; goto done; case '\v': *dst++ = '\\'; *dst++ = 'v'; goto done; case '\t': *dst++ = '\\'; *dst++ = 't'; goto done; case '\f': *dst++ = '\\'; *dst++ = 'f'; goto done; case ' ': *dst++ = '\\'; *dst++ = 's'; goto done; case '\0': *dst++ = '\\'; *dst++ = '0'; if (isoctal(nextc)) { *dst++ = '0'; *dst++ = '0'; } goto done; } } if (((c & 0177) == ' ') || (flag & VIS_OCTAL) || ((flag & VIS_GLOB) && (c == '*' || c == '?' || c == '[' || c == '#'))) { *dst++ = '\\'; *dst++ = ((u_char)c >> 6 & 07) + '0'; *dst++ = ((u_char)c >> 3 & 07) + '0'; *dst++ = ((u_char)c & 07) + '0'; goto done; } if ((flag & VIS_NOSLASH) == 0) *dst++ = '\\'; if (c & 0200) { c &= 0177; *dst++ = 'M'; } if (iscntrl((u_char)c)) { *dst++ = '^'; if (c == 0177) *dst++ = '?'; else *dst++ = c + '@'; } else { *dst++ = '-'; *dst++ = c; } done: *dst = '\0'; return (dst); } #endif opencu-3/compat/vis.h000066400000000000000000000060301422060022000147270ustar00rootroot00000000000000/* $OpenBSD: vis.h,v 1.11 2005/08/09 19:38:31 millert Exp $ */ /* $NetBSD: vis.h,v 1.4 1994/10/26 00:56:41 cgd Exp $ */ /*- * Copyright (c) 1990 The Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)vis.h 5.9 (Berkeley) 4/3/91 */ /* OPENBSD ORIGINAL: include/vis.h */ #ifdef HAVE_CONFIG_H #include "includes.h" #endif // #if !defined(HAVE_STRNVIS) #ifndef _VIS_H_ #define _VIS_H_ #include #include /* * to select alternate encoding format */ #define VIS_OCTAL 0x01 /* use octal \ddd format */ #define VIS_CSTYLE 0x02 /* use \[nrft0..] where appropriate */ /* * to alter set of characters encoded (default is to encode all * non-graphic except space, tab, and newline). */ #define VIS_SP 0x04 /* also encode space */ #define VIS_TAB 0x08 /* also encode tab */ #define VIS_NL 0x10 /* also encode newline */ #define VIS_WHITE (VIS_SP | VIS_TAB | VIS_NL) #define VIS_SAFE 0x20 /* only encode "unsafe" characters */ /* * other */ #define VIS_NOSLASH 0x40 /* inhibit printing '\' */ #define VIS_GLOB 0x100 /* encode glob(3) magics and '#' */ /* * unvis return codes */ #define UNVIS_VALID 1 /* character valid */ #define UNVIS_VALIDPUSH 2 /* character valid, push back passed char */ #define UNVIS_NOCHAR 3 /* valid sequence, no character produced */ #define UNVIS_SYNBAD -1 /* unrecognized escape sequence */ #define UNVIS_ERROR -2 /* decoder in unknown state (unrecoverable) */ /* * unvis flags */ #define UNVIS_END 1 /* no more characters */ char *vis(char *, int, int, int); #endif /* !_VIS_H_ */ //#endif /* !HAVE_STRNVIS */ opencu-3/cu.1000066400000000000000000000127061422060022000131720ustar00rootroot00000000000000.\" $OpenBSD: cu.1,v 1.21 2020/12/12 06:35:37 bentley Exp $ .\" .\" Copyright (c) 1980, 1990, 1993 .\" The Regents of the University of California. All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" 3. Neither the name of the University nor the names of its contributors .\" may be used to endorse or promote products derived from this software .\" without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .Dd $Mdocdate: December 12 2020 $ .Dt CU 1 .Os .Sh NAME .Nm cu .Nd serial terminal emulator .Sh SYNOPSIS .Nm .Op Fl dr .Op Fl E Ar escape_char .Op Fl l Ar line .Op Fl s Ar speed | Fl Ar speed .Nm .Op Ar host .Sh DESCRIPTION .Nm is used to connect to another system over a serial link. In the era before modern networks, it was typically used to connect to a modem in order to dial in to a remote host. It is now frequently used for tasks such as attaching to the serial console of another machine for administrative or debugging purposes. .Pp The options are as follows: .Bl -tag -width 4n .It Fl d Specify that the line is directly connected and .Nm should not allow the driver to block waiting for a carrier to be detected. .It Fl E Ar escape_char Specify an escape character to use instead of the default tilde. .It Fl l Ar line Specify the line to use. Either of the forms like .Pa cua00 or .Pa /dev/cua00 are permitted. The default is .Pa /dev/cua00 . See .Xr cua 4 for information on terminal devices. Users in group .Dq dialer are permitted to use .Xr cua 4 devices by default. .It Fl r Start .Nm in restricted mode. This prevents all local filesystem operations .Po .Cm ~R , .Cm ~X , and .Cm ~> .Pc and command executions .Po .Cm ~C and .Cm ~$ .Pc . .It Fl s Ar speed | Fl Ar speed Set the speed of the connection. The default is 9600. .El .Pp If .Ar host is given, .Nm uses the .Xr remote 5 database to retrieve the .Sy dc Pq directly connected , .Sy dv Pq device and .Sy br Pq baud rate capabilities for that host. The .Nm utility ignores other capabilities found in that database. .Pp Typed characters are normally transmitted directly to the remote machine (which does the echoing as well). A tilde .Pq Ql ~ appearing as the first character of a line is an escape signal; the following are recognized: .Bl -tag -offset indent -width Fl .It Ic ~^D No or Ic ~. Drop the connection and exit. Only the connection is dropped \(en the login session is not terminated. .It Ic ~> Copy file from local to remote. .Nm prompts for the name of a local file to transmit. .It Ic ~$ Pipe the output from a local .Ux process to the remote host. The command string sent to the local .Ux system is processed by the shell. .It Ic ~# Send a .Dv BREAK to the remote system. .It Ic ~^Z Stop .Nm (only available with job control). .It Ic ~C Fork a child process on the local system to perform special protocols such as XMODEM. The child program will be run with the following arrangement of file descriptors: .Pp .Bl -item -compact -offset indent .It 0 \(<> remote tty in .It 1 \(<> remote tty out .It 2 \(<> local tty stderr .El .It Ic ~D Deassert the data terminal ready (DTR) line briefly. .It Ic ~R Record all output from the remote system to a file. If the given file already exists, it is appended to. If no file is specified, any existing recording is stopped. .It Ic ~S Change the speed of the connection. .It Ic ~X Send a file with the XMODEM protocol. .It Ic ~? Get a summary of the tilde escapes. .El .Pp When .Nm prompts for an argument, for example during setup of a file transfer, the line typed may be edited with the standard erase and kill characters. A null line in response to a prompt, or an interrupt, will abort the dialogue and return the user to the remote machine. .Pp .Nm guards against multiple users connecting to a remote system by opening modems and terminal lines with exclusive access. .Sh ENVIRONMENT .Bl -tag -width REMOTEXXX .It Ev HOST The default value for .Ar host if none is specified via the command line. .It Ev REMOTE A system description, or an absolute path to a .Xr remote 5 system description database. .El .Sh FILES .Bl -tag -width /etc/remote .It Pa /etc/remote host description file .El .Sh EXIT STATUS .Ex -std cu .Sh SEE ALSO .Xr remote 5 .Sh HISTORY The .Nm command appeared in .At v7 . This version was written for .Ox 5.4 by Nicholas Marriott. opencu-3/cu.c000066400000000000000000000254351422060022000132570ustar00rootroot00000000000000/* $OpenBSD: cu.c,v 1.28 2019/06/28 13:35:00 deraadt Exp $ */ /* * Copyright (c) 2012 Nicholas Marriott * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "cu.h" extern char *__progname; FILE *record_file; struct termios saved_tio; struct bufferevent *input_ev; struct bufferevent *output_ev; int escape_char = '~'; int is_direct = -1; int restricted = 0; const char *line_path = NULL; int line_speed = -1; int line_fd; struct termios line_tio; struct bufferevent *line_ev; struct event sigterm_ev; struct event sighup_ev; enum { STATE_NONE, STATE_NEWLINE, STATE_ESCAPE } last_state = STATE_NEWLINE; # define __dead __attribute__((__noreturn__)) __dead void usage(void); void signal_event(int, short, void *); void stream_read(struct bufferevent *, void *); void stream_error(struct bufferevent *, short, void *); void line_read(struct bufferevent *, void *); void line_error(struct bufferevent *, short, void *); void try_remote(const char *, const char *, const char *); __dead void usage(void) { fprintf(stderr, "usage: %s [-dr] [-E escape_char] [-l line] " "[-s speed | -speed]\n", __progname); fprintf(stderr, " %s [host]\n", __progname); exit(1); } int main(int argc, char **argv) { const char *errstr; #ifdef __OpenBSD__ char *tmp, *s, *host; #else char *tmp, *host; #endif int opt, i, flags; #ifdef __OpenBSD__ if (pledge("stdio rpath wpath cpath getpw proc exec tty", NULL) == -1) err(1, "pledge"); #endif if (isatty(STDIN_FILENO) && tcgetattr(STDIN_FILENO, &saved_tio) != 0) err(1, "tcgetattr"); /* * Convert obsolescent -### speed to modern -s### syntax which getopt() * can handle. */ for (i = 1; i < argc; i++) { if (strcmp("--", argv[i]) == 0) break; if (argv[i][0] != '-' || !isdigit((u_char)argv[i][1])) continue; if (asprintf(&argv[i], "-s%s", &argv[i][1]) == -1) errx(1, "speed asprintf"); } while ((opt = getopt(argc, argv, "drE:l:s:")) != -1) { switch (opt) { case 'd': is_direct = 1; break; #ifdef __OpenBSD__ case 'r': if (pledge("stdio rpath wpath tty", NULL) == -1) err(1, "pledge"); restricted = 1; break; #endif case 'E': if (optarg[0] == '^' && optarg[2] == '\0' && (u_char)optarg[1] >= 64 && (u_char)optarg[1] < 128) escape_char = (u_char)optarg[1] & 31; else if (strlen(optarg) == 1) escape_char = (u_char)optarg[0]; else errx(1, "invalid escape character: %s", optarg); break; case 'l': line_path = optarg; break; case 's': line_speed = strtonum(optarg, 0, INT_MAX, &errstr); if (errstr != NULL) errx(1, "speed is %s: %s", errstr, optarg); break; default: usage(); } } argc -= optind; argv += optind; if (argc != 0 && argc != 1) usage(); if (line_path != NULL || line_speed != -1 || is_direct != -1) { if (argc != 0) usage(); } else { if (argc == 1) host = argv[0]; else host = getenv("HOST"); if (host != NULL && *host != '\0') { if (*host == '/') line_path = host; #ifdef __OpenBSD__ else { s = getenv("REMOTE"); if (s != NULL && *s == '/') try_remote(host, s, NULL); else try_remote(host, NULL, s); } #endif } } if (line_path == NULL) line_path = "/dev/ttyUSB0"; if (line_speed == -1) line_speed = 115200; if (is_direct == -1) is_direct = 0; if (strchr(line_path, '/') == NULL) { if (asprintf(&tmp, "%s%s", _PATH_DEV, line_path) == -1) err(1, "asprintf"); line_path = tmp; } flags = O_RDWR; if (is_direct) flags |= O_NONBLOCK; line_fd = open(line_path, flags); if (line_fd == -1) err(1, "open(\"%s\")", line_path); #ifdef __OpenBSD__ if (restricted && pledge("stdio tty", NULL) == -1) err(1, "pledge"); #endif if (!isatty(line_fd)) err(1, "%s", line_path); if (ioctl(line_fd, TIOCEXCL) != 0) err(1, "ioctl(TIOCEXCL)"); if (tcgetattr(line_fd, &line_tio) != 0) err(1, "tcgetattr"); if (set_line(line_speed) != 0) err(1, "tcsetattr"); event_init(); signal_set(&sigterm_ev, SIGTERM, signal_event, NULL); signal_add(&sigterm_ev, NULL); signal_set(&sighup_ev, SIGHUP, signal_event, NULL); signal_add(&sighup_ev, NULL); if (signal(SIGINT, SIG_IGN) == SIG_ERR) err(1, "signal"); if (signal(SIGQUIT, SIG_IGN) == SIG_ERR) err(1, "signal"); set_termios(); /* after this use cu_err and friends */ /* stdin and stdout get separate events */ input_ev = bufferevent_new(STDIN_FILENO, stream_read, NULL, stream_error, NULL); bufferevent_enable(input_ev, EV_READ); output_ev = bufferevent_new(STDOUT_FILENO, NULL, NULL, stream_error, NULL); bufferevent_enable(output_ev, EV_WRITE); set_blocking(line_fd, 0); line_ev = bufferevent_new(line_fd, line_read, NULL, line_error, NULL); bufferevent_enable(line_ev, EV_READ|EV_WRITE); printf("Connected to %s (speed %d)\r\n", line_path, line_speed); event_dispatch(); restore_termios(); printf("\r\n[EOT]\n"); exit(0); } void signal_event(int fd, short events, void *data) { restore_termios(); #ifdef __OpenBSD__ printf("\r\n[SIG%s]\n", sys_signame[fd]); #else printf("\r\n[SIG%s]\n", strsignal(fd)); #endif exit(0); } void set_blocking(int fd, int state) { int mode; state = state ? 0 : O_NONBLOCK; if ((mode = fcntl(fd, F_GETFL)) == -1) cu_err(1, "fcntl"); if ((mode & O_NONBLOCK) != state) { mode = (mode & ~O_NONBLOCK) | state; if (fcntl(fd, F_SETFL, mode) == -1) cu_err(1, "fcntl"); } } void set_termios(void) { struct termios tio; if (!isatty(STDIN_FILENO)) return; memcpy(&tio, &saved_tio, sizeof(tio)); tio.c_lflag &= ~(ICANON|IEXTEN|ECHO); tio.c_iflag &= ~(INPCK|ICRNL); tio.c_oflag &= ~OPOST; tio.c_cc[VMIN] = 1; tio.c_cc[VTIME] = 0; tio.c_cc[VDISCARD] = _POSIX_VDISABLE; #ifdef __OpenBSD__ tio.c_cc[VDSUSP] = _POSIX_VDISABLE; #endif tio.c_cc[VINTR] = _POSIX_VDISABLE; tio.c_cc[VLNEXT] = _POSIX_VDISABLE; tio.c_cc[VQUIT] = _POSIX_VDISABLE; tio.c_cc[VSUSP] = _POSIX_VDISABLE; if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &tio) != 0) cu_err(1, "tcsetattr"); } void restore_termios(void) { if (isatty(STDIN_FILENO)) tcsetattr(STDIN_FILENO, TCSAFLUSH, &saved_tio); } int set_line(int speed) { struct termios tio; memcpy(&tio, &line_tio, sizeof(tio)); tio.c_iflag &= ~(ISTRIP|ICRNL); tio.c_oflag &= ~OPOST; tio.c_lflag &= ~(ICANON|ISIG|IEXTEN|ECHO); tio.c_cflag &= ~(CSIZE|PARENB); tio.c_cflag |= CREAD|CS8|CLOCAL; tio.c_cc[VMIN] = 1; tio.c_cc[VTIME] = 0; cfsetspeed(&tio, speed); if (tcsetattr(line_fd, TCSAFLUSH, &tio) != 0) return (-1); return (0); } void stream_read(struct bufferevent *bufev, void *data) { char *new_data, *ptr; size_t new_size; int state_change; new_data = EVBUFFER_DATA(input_ev->input); new_size = EVBUFFER_LENGTH(input_ev->input); if (new_size == 0) return; state_change = isatty(STDIN_FILENO); for (ptr = new_data; ptr < new_data + new_size; ptr++) { switch (last_state) { case STATE_NONE: if (state_change && *ptr == '\r') last_state = STATE_NEWLINE; break; case STATE_NEWLINE: if (state_change && (u_char)*ptr == escape_char) { last_state = STATE_ESCAPE; continue; } if (*ptr != '\r') last_state = STATE_NONE; break; case STATE_ESCAPE: do_command(*ptr); last_state = STATE_NEWLINE; continue; } bufferevent_write(line_ev, ptr, 1); } evbuffer_drain(input_ev->input, new_size); } void stream_error(struct bufferevent *bufev, short what, void *data) { event_loopexit(NULL); } void line_read(struct bufferevent *bufev, void *data) { char *new_data; size_t new_size; new_data = EVBUFFER_DATA(line_ev->input); new_size = EVBUFFER_LENGTH(line_ev->input); if (new_size == 0) return; if (record_file != NULL) fwrite(new_data, 1, new_size, record_file); bufferevent_write(output_ev, new_data, new_size); evbuffer_drain(line_ev->input, new_size); } void line_error(struct bufferevent *bufev, short what, void *data) { event_loopexit(NULL); } #ifdef __OpenBSD__ void try_remote(const char *host, const char *path, const char *entry) { const char *paths[] = { "/etc/remote", NULL, NULL }; char *cp, *s; long l; int error; if (path != NULL) { paths[0] = path; paths[1] = "/etc/remote"; } if (entry != NULL && cgetset(entry) != 0) cu_errx(1, "cgetset failed"); error = cgetent(&cp, (char **)paths, (char *)host); if (error < 0) { switch (error) { case -1: cu_errx(1, "unknown host %s", host); case -2: cu_errx(1, "can't open remote file"); case -3: cu_errx(1, "loop in remote file"); default: cu_errx(1, "unknown error in remote file"); } } if (is_direct == -1 && cgetcap(cp, "dc", ':') != NULL) is_direct = 1; if (line_path == NULL && cgetstr(cp, "dv", &s) >= 0) line_path = s; if (line_speed == -1 && cgetnum(cp, "br", &l) >= 0) { if (l < 0 || l > INT_MAX) cu_errx(1, "speed out of range"); line_speed = l; } } #endif /* Expands tildes in the file name. Based on code from ssh/misc.c. */ char * tilde_expand(const char *filename1) { const char *filename, *path, *sep; char user[128], *out; struct passwd *pw; u_int len, slash; int rv; if (*filename1 != '~') goto no_change; filename = filename1 + 1; path = strchr(filename, '/'); if (path != NULL && path > filename) { /* ~user/path */ slash = path - filename; if (slash > sizeof(user) - 1) goto no_change; memcpy(user, filename, slash); user[slash] = '\0'; if ((pw = getpwnam(user)) == NULL) goto no_change; } else if ((pw = getpwuid(getuid())) == NULL) /* ~/path */ goto no_change; /* Make sure directory has a trailing '/' */ len = strlen(pw->pw_dir); if (len == 0 || pw->pw_dir[len - 1] != '/') sep = "/"; else sep = ""; /* Skip leading '/' from specified path */ if (path != NULL) filename = path + 1; if ((rv = asprintf(&out, "%s%s%s", pw->pw_dir, sep, filename)) == -1) cu_err(1, "asprintf"); if (rv >= PATH_MAX) { free(out); goto no_change; } return (out); no_change: out = strdup(filename1); if (out == NULL) cu_err(1, "strdup"); return (out); } opencu-3/cu.h000066400000000000000000000033321422060022000132540ustar00rootroot00000000000000/* $OpenBSD: cu.h,v 1.9 2019/03/22 07:03:23 nicm Exp $ */ /* * Copyright (c) 2012 Nicholas Marriott * * 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. */ #ifndef CU_H #define CU_H /* command.c */ void do_command(char); /* cu.c */ extern int escape_char; extern int restricted; extern FILE *record_file; extern struct termios saved_tio; extern int line_fd; extern struct bufferevent *line_ev; void set_blocking(int, int); int set_line(int); void set_termios(void); void restore_termios(void); char *tilde_expand(const char *); /* input.c */ const char *get_input(const char *); /* error.c */ void cu_warn(const char *, ...) __attribute__ ((format (printf, 1, 2))); void cu_warnx(const char *, ...) __attribute__ ((format (printf, 1, 2))); void cu_err(int, const char *, ...) __attribute__ ((format (printf, 2, 3))); void cu_errx(int, const char *, ...) __attribute__ ((format (printf, 2, 3))); /* xmodem.c */ void xmodem_send(const char *); #endif opencu-3/error.c000066400000000000000000000034231422060022000137720ustar00rootroot00000000000000/* $OpenBSD: error.c,v 1.1 2012/07/10 10:28:05 nicm Exp $ */ /* * Copyright (c) 2012 Nicholas Marriott * * 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 #include #include #include #include #include #include #include "cu.h" /* * Once we've configured termios, we need to use \r\n to end lines, so use our * own versions of warn/warnx/err/errx. */ extern char *__progname; void cu_err(int eval, const char *fmt, ...) { va_list ap; restore_termios(); va_start(ap, fmt); verr(eval, fmt, ap); } void cu_errx(int eval, const char *fmt, ...) { va_list ap; restore_termios(); va_start(ap, fmt); verrx(eval, fmt, ap); } void cu_warn(const char *fmt, ...) { va_list ap; fprintf(stderr, "%s: ", __progname); va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); fprintf(stderr, ": %s\r\n", strerror(errno)); } void cu_warnx(const char *fmt, ...) { va_list ap; fprintf(stderr, "%s: ", __progname); va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); fprintf(stderr, "\r\n"); } opencu-3/input.c000066400000000000000000000040101422060022000137710ustar00rootroot00000000000000/* $OpenBSD: input.c,v 1.2 2012/07/10 10:28:05 nicm Exp $ */ /* * Copyright (c) 2012 Nicholas Marriott * * 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 #include #include #include #include #include #include #include #include "cu.h" /* * Prompt and read a line of user input from stdin. We want to use the termios * we were started with so restore and stick in a signal handler for ^C. */ volatile sig_atomic_t input_stop; void input_signal(int); void input_signal(int sig) { input_stop = 1; } const char * get_input(const char *prompt) { static char s[BUFSIZ]; struct sigaction act, oact; char c, *cp, *out = NULL; ssize_t n; memset(&act, 0, sizeof(act)); sigemptyset(&act.sa_mask); act.sa_flags = 0; act.sa_handler = input_signal; if (sigaction(SIGINT, &act, &oact) != 0) cu_err(1, "sigaction"); input_stop = 0; restore_termios(); printf("%s ", prompt); fflush(stdout); cp = s; while (cp != s + sizeof(s) - 1) { n = read(STDIN_FILENO, &c, 1); if (n == -1 && errno != EINTR) cu_err(1, "read"); if (n != 1 || input_stop) break; if (c == '\n') { out = s; break; } if (!iscntrl((u_char)c)) *cp++ = c; } *cp = '\0'; set_termios(); sigaction(SIGINT, &oact, NULL); return (out); } opencu-3/xmodem.c000066400000000000000000000107361422060022000141370ustar00rootroot00000000000000/* $OpenBSD: xmodem.c,v 1.9 2016/02/04 18:33:30 millert Exp $ */ /* * Copyright (c) 2012 Nicholas Marriott * * 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 #include #include #include #include #include #include #include #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' #define XMODEM_C '\103' volatile sig_atomic_t xmodem_stop; void xmodem_signal(int sig); uint16_t xmodem_crc16(const u_char *buf, size_t len); int xmodem_read(char *c); int xmodem_write(const u_char *buf, size_t len); void xmodem_signal(int sig) { xmodem_stop = 1; } uint16_t xmodem_crc16(const u_char *buf, size_t len) { uint16_t crc; u_int i, j; crc = 0; for (i = 0; i < len; i++) { crc = crc ^ *buf++ << 8; for (j = 0; j < 8; j++) if (crc & 0x8000) crc = crc << 1 ^ 0x1021; else crc = crc << 1; } return (crc); } 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 + 2], c; size_t len, pktlen; uint8_t num; uint16_t crc; int crc_mode; u_int i, total; 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"); } set_blocking(line_fd, 1); tcflush(line_fd, TCIFLUSH); if (xmodem_read(&c) != 0) goto fail; if (c == XMODEM_C) crc_mode = 1; else if (c == XMODEM_NAK) crc_mode = 0; else { cu_warnx("%s: unexpected response \\%03hho", file, c); goto fail; } num = 1; total = 1; pktlen = 3 + XMODEM_BLOCK + (crc_mode ? 2 : 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; if (crc_mode) { crc = xmodem_crc16(buf + 3, XMODEM_BLOCK); buf[3 + XMODEM_BLOCK] = crc >> 8; buf[3 + XMODEM_BLOCK + 1] = crc & 0xFF; } else { buf[3 + XMODEM_BLOCK] = 0; for (i = 0; i < XMODEM_BLOCK; 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, total, 1 + i); if (xmodem_write(buf, pktlen) != 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++; total++; } 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_blocking(line_fd, 0); set_termios(); sigaction(SIGINT, &oact, NULL); fclose(f); }