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