Annotation of src/usr.bin/cu/command.c, Revision 1.18
1.18 ! deraadt 1: /* $OpenBSD: command.c,v 1.17 2019/03/22 07:03:23 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: #include <sys/ioctl.h>
21: #include <sys/wait.h>
22:
23: #include <event.h>
24: #include <errno.h>
25: #include <fcntl.h>
1.7 nicm 26: #include <limits.h>
1.1 nicm 27: #include <paths.h>
28: #include <signal.h>
29: #include <stdlib.h>
30: #include <stdio.h>
1.16 deraadt 31: #include <string.h>
1.1 nicm 32: #include <unistd.h>
1.17 nicm 33: #include <vis.h>
1.1 nicm 34:
35: #include "cu.h"
36:
37: void pipe_command(void);
1.4 nicm 38: void connect_command(void);
1.1 nicm 39: void send_file(void);
1.8 nicm 40: void send_xmodem(void);
1.13 deraadt 41: void set_speed(void);
42: void start_record(void);
1.1 nicm 43:
44: void
45: pipe_command(void)
46: {
47: const char *cmd;
48: pid_t pid;
49: int fd;
50:
51: cmd = get_input("Local command?");
52: if (cmd == NULL || *cmd == '\0')
53: return;
54:
1.3 nicm 55: restore_termios();
1.15 nicm 56: set_blocking(line_fd, 1);
1.3 nicm 57:
1.1 nicm 58: switch (pid = fork()) {
59: case -1:
1.6 nicm 60: cu_err(1, "fork");
1.1 nicm 61: case 0:
62: fd = open(_PATH_DEVNULL, O_RDWR);
1.18 ! deraadt 63: if (fd == -1 || dup2(fd, STDIN_FILENO) == -1)
1.1 nicm 64: _exit(1);
65: close(fd);
66:
1.3 nicm 67: if (signal(SIGINT, SIG_DFL) == SIG_ERR)
68: _exit(1);
69: if (signal(SIGQUIT, SIG_DFL) == SIG_ERR)
70: _exit(1);
71:
1.1 nicm 72: /* attach stdout to line */
73: if (dup2(line_fd, STDOUT_FILENO) == -1)
74: _exit(1);
75:
1.5 nicm 76: if (closefrom(STDERR_FILENO + 1) != 0)
1.1 nicm 77: _exit(1);
78:
1.14 nicm 79: execl(_PATH_BSHELL, "sh", "-c", cmd, (char *)NULL);
1.1 nicm 80: _exit(1);
81: default:
82: while (waitpid(pid, NULL, 0) == -1 && errno == EINTR)
83: /* nothing */;
84: break;
85: }
1.3 nicm 86:
1.15 nicm 87: set_blocking(line_fd, 0);
1.3 nicm 88: set_termios();
1.1 nicm 89: }
90:
91: void
1.4 nicm 92: connect_command(void)
93: {
94: const char *cmd;
95: pid_t pid;
96:
97: /*
98: * Fork a program with:
99: * 0 <-> remote tty in
100: * 1 <-> remote tty out
101: * 2 <-> local tty stderr
102: */
103:
104: cmd = get_input("Local command?");
105: if (cmd == NULL || *cmd == '\0')
106: return;
107:
108: restore_termios();
1.15 nicm 109: set_blocking(line_fd, 1);
1.4 nicm 110:
111: switch (pid = fork()) {
112: case -1:
1.6 nicm 113: cu_err(1, "fork");
1.4 nicm 114: case 0:
115: if (signal(SIGINT, SIG_DFL) == SIG_ERR)
116: _exit(1);
117: if (signal(SIGQUIT, SIG_DFL) == SIG_ERR)
118: _exit(1);
119:
120: /* attach stdout and stdin to line */
121: if (dup2(line_fd, STDOUT_FILENO) == -1)
122: _exit(1);
123: if (dup2(line_fd, STDIN_FILENO) == -1)
124: _exit(1);
125:
1.5 nicm 126: if (closefrom(STDERR_FILENO + 1) != 0)
1.4 nicm 127: _exit(1);
128:
1.14 nicm 129: execl(_PATH_BSHELL, "sh", "-c", cmd, (char *)NULL);
1.4 nicm 130: _exit(1);
131: default:
132: while (waitpid(pid, NULL, 0) == -1 && errno == EINTR)
133: /* nothing */;
134: break;
135: }
136:
1.15 nicm 137: set_blocking(line_fd, 0);
1.4 nicm 138: set_termios();
139: }
140:
141: void
1.1 nicm 142: send_file(void)
143: {
144: const char *file;
145: FILE *f;
146: char buf[BUFSIZ], *expanded;
147: size_t len;
148:
149: file = get_input("Local file?");
150: if (file == NULL || *file == '\0')
151: return;
152:
153: expanded = tilde_expand(file);
154: f = fopen(expanded, "r");
155: if (f == NULL) {
1.6 nicm 156: cu_warn("%s", file);
1.1 nicm 157: return;
158: }
159:
160: while (!feof(f) && !ferror(f)) {
161: len = fread(buf, 1, sizeof(buf), f);
162: if (len != 0)
163: bufferevent_write(line_ev, buf, len);
164: }
165:
166: fclose(f);
167: free(expanded);
168: }
169:
170: void
1.8 nicm 171: send_xmodem(void)
172: {
173: const char *file;
174: char *expanded;
175:
176: file = get_input("Local file?");
177: if (file == NULL || *file == '\0')
178: return;
179:
180: expanded = tilde_expand(file);
181: xmodem_send(expanded);
182: free(expanded);
183: }
184:
185: void
1.2 nicm 186: set_speed(void)
187: {
188: const char *s, *errstr;
189: int speed;
190:
191: s = get_input("New speed?");
192: if (s == NULL || *s == '\0')
193: return;
194:
195: speed = strtonum(s, 0, UINT_MAX, &errstr);
196: if (errstr != NULL) {
1.6 nicm 197: cu_warnx("speed is %s: %s", errstr, s);
1.2 nicm 198: return;
199: }
200:
1.6 nicm 201: if (set_line(speed) != 0)
202: cu_warn("tcsetattr");
1.2 nicm 203: }
204:
205: void
1.10 nicm 206: start_record(void)
207: {
208: const char *file;
209:
210: if (record_file != NULL) {
211: fclose(record_file);
212: record_file = NULL;
213: }
214:
215: file = get_input("Record file?");
216: if (file == NULL || *file == '\0')
217: return;
218:
219: record_file = fopen(file, "a");
220: if (record_file == NULL)
221: cu_warnx("%s", file);
222: }
223:
224: void
1.1 nicm 225: do_command(char c)
226: {
1.17 nicm 227: char esc[4 + 1];
228:
1.16 deraadt 229: if (restricted && strchr("CRX$>", c) != NULL) {
230: cu_warnx("~%c command is not allowed in restricted mode", c);
231: return;
232: }
233:
1.1 nicm 234: switch (c) {
235: case '.':
236: case '\004': /* ^D */
237: event_loopexit(NULL);
238: break;
239: case '\032': /* ^Z */
240: restore_termios();
241: kill(getpid(), SIGTSTP);
242: set_termios();
243: break;
1.4 nicm 244: case 'C':
245: connect_command();
246: break;
1.12 nicm 247: case 'D':
248: ioctl(line_fd, TIOCCDTR, NULL);
249: sleep(1);
250: ioctl(line_fd, TIOCSDTR, NULL);
251: break;
1.10 nicm 252: case 'R':
253: start_record();
254: break;
1.2 nicm 255: case 'S':
256: set_speed();
1.8 nicm 257: break;
258: case 'X':
259: send_xmodem();
1.2 nicm 260: break;
1.1 nicm 261: case '$':
262: pipe_command();
263: break;
264: case '>':
265: send_file();
266: break;
267: case '#':
268: ioctl(line_fd, TIOCSBRK, NULL);
269: sleep(1);
270: ioctl(line_fd, TIOCCBRK, NULL);
1.11 nicm 271: break;
1.17 nicm 272: default:
273: if ((u_char)c == escape_char)
274: bufferevent_write(line_ev, &c, 1);
1.1 nicm 275: break;
276: case '?':
1.17 nicm 277: vis(esc, escape_char, VIS_WHITE | VIS_NOSLASH, 0);
1.1 nicm 278: printf("\r\n"
1.17 nicm 279: "%s# send break\r\n"
280: "%s$ pipe local command to remote host\r\n"
281: "%s> send file to remote host\r\n"
282: "%sC connect program to remote host\r\n"
283: "%sD de-assert DTR line briefly\r\n"
284: "%sR start recording to file\r\n"
285: "%sS set speed\r\n"
286: "%sX send file with XMODEM\r\n"
287: "%s? get this summary\r\n",
288: esc, esc, esc, esc, esc, esc, esc, esc, esc
1.2 nicm 289: );
1.1 nicm 290: break;
291: }
292: }