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