1 1.37 mlelstv /* $NetBSD: cmds.c,v 1.37 2014/07/12 05:28:07 mlelstv Exp $ */ 2 1.3 jtc 3 1.1 cgd /* 4 1.3 jtc * Copyright (c) 1983, 1993 5 1.3 jtc * The Regents of the University of California. All rights reserved. 6 1.1 cgd * 7 1.1 cgd * Redistribution and use in source and binary forms, with or without 8 1.1 cgd * modification, are permitted provided that the following conditions 9 1.1 cgd * are met: 10 1.1 cgd * 1. Redistributions of source code must retain the above copyright 11 1.1 cgd * notice, this list of conditions and the following disclaimer. 12 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 cgd * notice, this list of conditions and the following disclaimer in the 14 1.1 cgd * documentation and/or other materials provided with the distribution. 15 1.14 agc * 3. Neither the name of the University nor the names of its contributors 16 1.1 cgd * may be used to endorse or promote products derived from this software 17 1.1 cgd * without specific prior written permission. 18 1.1 cgd * 19 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 1.1 cgd * SUCH DAMAGE. 30 1.1 cgd */ 31 1.1 cgd 32 1.8 lukem #include <sys/cdefs.h> 33 1.1 cgd #ifndef lint 34 1.3 jtc #if 0 35 1.3 jtc static char sccsid[] = "@(#)cmds.c 8.1 (Berkeley) 6/6/93"; 36 1.3 jtc #endif 37 1.37 mlelstv __RCSID("$NetBSD: cmds.c,v 1.37 2014/07/12 05:28:07 mlelstv Exp $"); 38 1.1 cgd #endif /* not lint */ 39 1.1 cgd 40 1.1 cgd #include "tip.h" 41 1.1 cgd #include "pathnames.h" 42 1.1 cgd 43 1.1 cgd /* 44 1.1 cgd * tip 45 1.1 cgd * 46 1.1 cgd * miscellaneous commands 47 1.1 cgd */ 48 1.1 cgd 49 1.1 cgd int quant[] = { 60, 60, 24 }; 50 1.1 cgd 51 1.1 cgd char null = '\0'; 52 1.16 christos const char *sep[] = { "second", "minute", "hour" }; 53 1.11 mrg static char *argv[10]; /* argument vector for take and put */ 54 1.1 cgd 55 1.20 perry int args(char *, char **); 56 1.20 perry int anyof(char *, const char *); 57 1.20 perry void execute(char *); 58 1.33 joerg __dead static void intcopy(int); 59 1.20 perry void prtime(const char *, time_t); 60 1.20 perry void stopsnd(int); 61 1.20 perry void transfer(char *, int, const char *); 62 1.20 perry void transmit(FILE *, const char *, char *); 63 1.1 cgd 64 1.1 cgd /* 65 1.1 cgd * FTP - remote ==> local 66 1.1 cgd * get a file from the remote host 67 1.1 cgd */ 68 1.8 lukem void 69 1.20 perry getfl(char c) 70 1.1 cgd { 71 1.8 lukem char buf[256], *cp; 72 1.20 perry 73 1.32 christos (void)putchar(c); 74 1.1 cgd /* 75 1.1 cgd * get the UNIX receiving file's name 76 1.1 cgd */ 77 1.11 mrg if (prompt("Local file name? ", copyname, sizeof copyname)) 78 1.1 cgd return; 79 1.1 cgd cp = expand(copyname); 80 1.15 uebayasi if ((sfd = open(cp, O_RDWR|O_CREAT, 0666)) < 0) { 81 1.32 christos (void)printf("\r\n%s: cannot create\r\n", copyname); 82 1.1 cgd return; 83 1.1 cgd } 84 1.20 perry 85 1.1 cgd /* 86 1.1 cgd * collect parameters 87 1.1 cgd */ 88 1.11 mrg if (prompt("List command for remote system? ", buf, 89 1.11 mrg sizeof buf)) { 90 1.32 christos (void)unlink(copyname); 91 1.1 cgd return; 92 1.1 cgd } 93 1.1 cgd transfer(buf, sfd, value(EOFREAD)); 94 1.1 cgd } 95 1.1 cgd 96 1.1 cgd /* 97 1.1 cgd * Cu-like take command 98 1.1 cgd */ 99 1.23 perry /* ARGSUSED */ 100 1.8 lukem void 101 1.32 christos cu_take(char dummy __unused) 102 1.1 cgd { 103 1.1 cgd int fd, argc; 104 1.8 lukem char line[BUFSIZ], *cp; 105 1.1 cgd 106 1.11 mrg if (prompt("[take] ", copyname, sizeof copyname)) 107 1.1 cgd return; 108 1.1 cgd if ((argc = args(copyname, argv)) < 1 || argc > 2) { 109 1.32 christos (void)printf("usage: <take> from [to]\r\n"); 110 1.1 cgd return; 111 1.1 cgd } 112 1.1 cgd if (argc == 1) 113 1.1 cgd argv[1] = argv[0]; 114 1.1 cgd cp = expand(argv[1]); 115 1.15 uebayasi if ((fd = open(cp, O_RDWR|O_CREAT, 0666)) < 0) { 116 1.32 christos (void)printf("\r\n%s: cannot create\r\n", argv[1]); 117 1.1 cgd return; 118 1.1 cgd } 119 1.7 mrg (void)snprintf(line, sizeof line, "cat %s;echo \01", argv[0]); 120 1.1 cgd transfer(line, fd, "\01"); 121 1.1 cgd } 122 1.1 cgd 123 1.1 cgd static jmp_buf intbuf; 124 1.1 cgd /* 125 1.1 cgd * Bulk transfer routine -- 126 1.1 cgd * used by getfl(), cu_take(), and pipefile() 127 1.1 cgd */ 128 1.8 lukem void 129 1.20 perry transfer(char *buf, int fd, const char *eofchars) 130 1.1 cgd { 131 1.8 lukem int ct; 132 1.1 cgd char c, buffer[BUFSIZ]; 133 1.31 christos char * volatile p; 134 1.8 lukem int cnt, eof; 135 1.1 cgd time_t start; 136 1.1 cgd sig_t f; 137 1.3 jtc char r; 138 1.1 cgd 139 1.31 christos p = buffer; 140 1.10 thorpej xpwrite(FD, buf, strlen(buf)); 141 1.1 cgd quit = 0; 142 1.32 christos (void)write(attndes[1], "W", 1); /* Put TIPOUT into a wait state */ 143 1.32 christos (void)read(repdes[0], (char *)&ccc, 1); /* Wait until read process stops */ 144 1.20 perry 145 1.1 cgd /* 146 1.1 cgd * finish command 147 1.1 cgd */ 148 1.3 jtc r = '\r'; 149 1.10 thorpej xpwrite(FD, &r, 1); 150 1.1 cgd do 151 1.32 christos (void)read(FD, &c, 1); 152 1.6 pk while ((c&STRIP_PAR) != '\n'); 153 1.32 christos (void)tcsetattr(0, TCSAFLUSH, &defchars); 154 1.20 perry 155 1.1 cgd (void) setjmp(intbuf); 156 1.1 cgd f = signal(SIGINT, intcopy); 157 1.1 cgd start = time(0); 158 1.1 cgd for (ct = 0; !quit;) { 159 1.1 cgd eof = read(FD, &c, 1) <= 0; 160 1.6 pk c &= STRIP_PAR; 161 1.1 cgd if (quit) 162 1.1 cgd continue; 163 1.1 cgd if (eof || any(c, eofchars)) 164 1.1 cgd break; 165 1.1 cgd if (c == 0) 166 1.1 cgd continue; /* ignore nulls */ 167 1.1 cgd if (c == '\r') 168 1.1 cgd continue; 169 1.1 cgd *p++ = c; 170 1.1 cgd 171 1.1 cgd if (c == '\n' && boolean(value(VERBOSE))) 172 1.32 christos (void)printf("\r%d", ++ct); 173 1.1 cgd if ((cnt = (p-buffer)) == number(value(FRAMESIZE))) { 174 1.24 christos if (write(fd, buffer, (size_t)cnt) != cnt) { 175 1.32 christos (void)printf("\r\nwrite error\r\n"); 176 1.1 cgd quit = 1; 177 1.1 cgd } 178 1.1 cgd p = buffer; 179 1.1 cgd } 180 1.1 cgd } 181 1.8 lukem if ((cnt = (p-buffer)) != 0) 182 1.24 christos if (write(fd, buffer, (size_t)cnt) != cnt) 183 1.32 christos (void)printf("\r\nwrite error\r\n"); 184 1.1 cgd 185 1.1 cgd if (boolean(value(VERBOSE))) 186 1.1 cgd prtime(" lines transferred in ", time(0)-start); 187 1.24 christos (void)tcsetattr(0, TCSAFLUSH, &term); 188 1.24 christos (void)write(fildes[1], (char *)&ccc, 1); 189 1.24 christos (void)signal(SIGINT, f); 190 1.24 christos (void)close(fd); 191 1.1 cgd } 192 1.1 cgd 193 1.1 cgd /* 194 1.1 cgd * FTP - remote ==> local process 195 1.1 cgd * send remote input to local process via pipe 196 1.1 cgd */ 197 1.23 perry /* ARGSUSED */ 198 1.8 lukem void 199 1.32 christos pipefile(char dummy __unused) 200 1.1 cgd { 201 1.1 cgd int cpid, pdes[2]; 202 1.1 cgd char buf[256]; 203 1.1 cgd int status, p; 204 1.1 cgd 205 1.11 mrg if (prompt("Local command? ", buf, sizeof buf)) 206 1.1 cgd return; 207 1.1 cgd 208 1.1 cgd if (pipe(pdes)) { 209 1.32 christos (void)printf("can't establish pipe\r\n"); 210 1.1 cgd return; 211 1.1 cgd } 212 1.1 cgd 213 1.1 cgd if ((cpid = fork()) < 0) { 214 1.32 christos (void)printf("can't fork!\r\n"); 215 1.1 cgd return; 216 1.1 cgd } else if (cpid) { 217 1.11 mrg if (prompt("List command for remote system? ", buf, 218 1.11 mrg sizeof buf)) { 219 1.32 christos (void)close(pdes[0]); 220 1.32 christos (void)close(pdes[1]); 221 1.32 christos (void)kill(cpid, SIGKILL); 222 1.1 cgd } else { 223 1.32 christos (void)close(pdes[0]); 224 1.32 christos (void)signal(SIGPIPE, intcopy); 225 1.1 cgd transfer(buf, pdes[1], value(EOFREAD)); 226 1.32 christos (void)signal(SIGPIPE, SIG_DFL); 227 1.1 cgd while ((p = wait(&status)) > 0 && p != cpid) 228 1.1 cgd ; 229 1.1 cgd } 230 1.1 cgd } else { 231 1.32 christos (void)dup2(pdes[0], 0); 232 1.32 christos (void)close(pdes[0]); 233 1.32 christos (void)closefrom(3); 234 1.1 cgd execute(buf); 235 1.32 christos (void)printf("can't execl!\r\n"); 236 1.1 cgd exit(0); 237 1.1 cgd } 238 1.1 cgd } 239 1.1 cgd 240 1.1 cgd /* 241 1.1 cgd * Interrupt service routine for FTP 242 1.1 cgd */ 243 1.23 perry /* ARGSUSED */ 244 1.1 cgd void 245 1.32 christos stopsnd(int dummy __unused) 246 1.1 cgd { 247 1.1 cgd 248 1.1 cgd stop = 1; 249 1.32 christos (void)signal(SIGINT, SIG_IGN); 250 1.1 cgd } 251 1.1 cgd 252 1.1 cgd /* 253 1.1 cgd * FTP - local ==> remote 254 1.1 cgd * send local file to remote host 255 1.1 cgd * terminate transmission with pseudo EOF sequence 256 1.1 cgd */ 257 1.8 lukem void 258 1.20 perry sendfile(char cc) 259 1.1 cgd { 260 1.1 cgd FILE *fd; 261 1.1 cgd char *fnamex; 262 1.1 cgd 263 1.32 christos (void)putchar(cc); 264 1.1 cgd /* 265 1.1 cgd * get file name 266 1.1 cgd */ 267 1.11 mrg if (prompt("Local file name? ", fname, sizeof fname)) 268 1.1 cgd return; 269 1.1 cgd 270 1.1 cgd /* 271 1.1 cgd * look up file 272 1.1 cgd */ 273 1.1 cgd fnamex = expand(fname); 274 1.1 cgd if ((fd = fopen(fnamex, "r")) == NULL) { 275 1.32 christos (void)printf("%s: cannot open\r\n", fname); 276 1.1 cgd return; 277 1.1 cgd } 278 1.1 cgd transmit(fd, value(EOFWRITE), NULL); 279 1.6 pk if (!boolean(value(ECHOCHECK))) 280 1.32 christos (void)tcdrain(FD); 281 1.1 cgd } 282 1.1 cgd 283 1.1 cgd /* 284 1.1 cgd * Bulk transfer routine to remote host -- 285 1.1 cgd * used by sendfile() and cu_put() 286 1.1 cgd */ 287 1.8 lukem void 288 1.20 perry transmit(FILE *fd, const char *eofchars, char *command) 289 1.1 cgd { 290 1.16 christos const char *pc; 291 1.16 christos char lastc; 292 1.24 christos int c; 293 1.24 christos int ccount, lcount; 294 1.1 cgd time_t start_t, stop_t; 295 1.1 cgd sig_t f; 296 1.1 cgd 297 1.32 christos (void)write(attndes[1], "W", 1); /* put TIPOUT into a wait state */ 298 1.1 cgd stop = 0; 299 1.1 cgd f = signal(SIGINT, stopsnd); 300 1.32 christos (void)tcsetattr(0, TCSAFLUSH, &defchars); 301 1.32 christos (void)read(repdes[0], (char *)&ccc, 1); 302 1.1 cgd if (command != NULL) { 303 1.1 cgd for (pc = command; *pc; pc++) 304 1.24 christos sendchar(*pc); 305 1.1 cgd if (boolean(value(ECHOCHECK))) 306 1.24 christos (void)read(FD, &c, (size_t)1); /* trailing \n */ 307 1.1 cgd else { 308 1.32 christos (void)tcdrain(FD); 309 1.32 christos (void)sleep(5); /* wait for remote stty to take effect */ 310 1.1 cgd } 311 1.1 cgd } 312 1.1 cgd lcount = 0; 313 1.1 cgd lastc = '\0'; 314 1.1 cgd start_t = time(0); 315 1.23 perry /* CONSTCOND */ 316 1.1 cgd while (1) { 317 1.1 cgd ccount = 0; 318 1.1 cgd do { 319 1.1 cgd c = getc(fd); 320 1.1 cgd if (stop) 321 1.1 cgd goto out; 322 1.1 cgd if (c == EOF) 323 1.1 cgd goto out; 324 1.1 cgd if (c == 0177 && !boolean(value(RAWFTP))) 325 1.1 cgd continue; 326 1.1 cgd lastc = c; 327 1.1 cgd if (c < 040) { 328 1.1 cgd if (c == '\n') { 329 1.1 cgd if (!boolean(value(RAWFTP))) 330 1.1 cgd c = '\r'; 331 1.1 cgd } 332 1.1 cgd else if (c == '\t') { 333 1.1 cgd if (!boolean(value(RAWFTP))) { 334 1.1 cgd if (boolean(value(TABEXPAND))) { 335 1.24 christos sendchar(' '); 336 1.1 cgd while ((++ccount % 8) != 0) 337 1.24 christos sendchar(' '); 338 1.1 cgd continue; 339 1.1 cgd } 340 1.1 cgd } 341 1.1 cgd } else 342 1.1 cgd if (!boolean(value(RAWFTP))) 343 1.1 cgd continue; 344 1.1 cgd } 345 1.24 christos sendchar(c); 346 1.1 cgd } while (c != '\r' && !boolean(value(RAWFTP))); 347 1.1 cgd if (boolean(value(VERBOSE))) 348 1.32 christos (void)printf("\r%d", ++lcount); 349 1.1 cgd if (boolean(value(ECHOCHECK))) { 350 1.1 cgd timedout = 0; 351 1.32 christos (void)alarm((unsigned int)number(value(ETIMEOUT))); 352 1.1 cgd do { /* wait for prompt */ 353 1.32 christos (void)read(FD, &c, (size_t)1); 354 1.1 cgd if (timedout || stop) { 355 1.1 cgd if (timedout) 356 1.32 christos (void)printf( 357 1.8 lukem "\r\ntimed out at eol\r\n"); 358 1.32 christos (void)alarm(0); 359 1.1 cgd goto out; 360 1.1 cgd } 361 1.6 pk } while ((c&STRIP_PAR) != character(value(PROMPT))); 362 1.32 christos (void)alarm(0); 363 1.1 cgd } 364 1.1 cgd } 365 1.1 cgd out: 366 1.1 cgd if (lastc != '\n' && !boolean(value(RAWFTP))) 367 1.24 christos sendchar('\r'); 368 1.5 jtc if (eofchars) { 369 1.5 jtc for (pc = eofchars; *pc; pc++) 370 1.24 christos sendchar(*pc); 371 1.5 jtc } 372 1.1 cgd stop_t = time(0); 373 1.32 christos (void)fclose(fd); 374 1.32 christos (void)signal(SIGINT, f); 375 1.12 ross if (boolean(value(VERBOSE))) { 376 1.1 cgd if (boolean(value(RAWFTP))) 377 1.1 cgd prtime(" chars transferred in ", stop_t-start_t); 378 1.1 cgd else 379 1.1 cgd prtime(" lines transferred in ", stop_t-start_t); 380 1.12 ross } 381 1.32 christos (void)write(fildes[1], (char *)&ccc, 1); 382 1.32 christos (void)tcsetattr(0, TCSAFLUSH, &term); 383 1.1 cgd } 384 1.1 cgd 385 1.1 cgd /* 386 1.1 cgd * Cu-like put command 387 1.1 cgd */ 388 1.23 perry /* ARGSUSED */ 389 1.8 lukem void 390 1.32 christos cu_put(char dummy __unused) 391 1.1 cgd { 392 1.1 cgd FILE *fd; 393 1.1 cgd char line[BUFSIZ]; 394 1.1 cgd int argc; 395 1.1 cgd char *copynamex; 396 1.1 cgd 397 1.11 mrg if (prompt("[put] ", copyname, sizeof copyname)) 398 1.1 cgd return; 399 1.1 cgd if ((argc = args(copyname, argv)) < 1 || argc > 2) { 400 1.32 christos (void)printf("usage: <put> from [to]\r\n"); 401 1.1 cgd return; 402 1.1 cgd } 403 1.1 cgd if (argc == 1) 404 1.1 cgd argv[1] = argv[0]; 405 1.1 cgd copynamex = expand(argv[0]); 406 1.1 cgd if ((fd = fopen(copynamex, "r")) == NULL) { 407 1.32 christos (void)printf("%s: cannot open\r\n", copynamex); 408 1.1 cgd return; 409 1.1 cgd } 410 1.1 cgd if (boolean(value(ECHOCHECK))) 411 1.7 mrg (void)snprintf(line, sizeof line, "cat>%s\r", argv[1]); 412 1.1 cgd else 413 1.7 mrg (void)snprintf(line, sizeof line, "stty -echo;cat>%s;stty echo\r", argv[1]); 414 1.1 cgd transmit(fd, "\04", line); 415 1.1 cgd } 416 1.1 cgd 417 1.1 cgd /* 418 1.1 cgd * FTP - send single character 419 1.1 cgd * wait for echo & handle timeout 420 1.1 cgd */ 421 1.8 lukem void 422 1.24 christos sendchar(char c) 423 1.1 cgd { 424 1.1 cgd char cc; 425 1.1 cgd int retry = 0; 426 1.1 cgd 427 1.1 cgd cc = c; 428 1.10 thorpej xpwrite(FD, &cc, 1); 429 1.1 cgd #ifdef notdef 430 1.1 cgd if (number(value(CDELAY)) > 0 && c != '\r') 431 1.1 cgd nap(number(value(CDELAY))); 432 1.1 cgd #endif 433 1.1 cgd if (!boolean(value(ECHOCHECK))) { 434 1.1 cgd #ifdef notdef 435 1.1 cgd if (number(value(LDELAY)) > 0 && c == '\r') 436 1.1 cgd nap(number(value(LDELAY))); 437 1.1 cgd #endif 438 1.1 cgd return; 439 1.1 cgd } 440 1.1 cgd tryagain: 441 1.1 cgd timedout = 0; 442 1.32 christos (void)alarm((unsigned int)number(value(ETIMEOUT))); 443 1.32 christos (void)read(FD, &cc, 1); 444 1.32 christos (void)alarm(0); 445 1.1 cgd if (timedout) { 446 1.32 christos (void)printf("\r\ntimeout error (%s)\r\n", ctrl(c)); 447 1.1 cgd if (retry++ > 3) 448 1.1 cgd return; 449 1.10 thorpej xpwrite(FD, &null, 1); /* poke it */ 450 1.1 cgd goto tryagain; 451 1.1 cgd } 452 1.1 cgd } 453 1.1 cgd 454 1.23 perry /* ARGSUSED */ 455 1.1 cgd void 456 1.32 christos alrmtimeout(int dummy __unused) 457 1.1 cgd { 458 1.11 mrg 459 1.32 christos (void)signal(SIGALRM, alrmtimeout); 460 1.1 cgd timedout = 1; 461 1.1 cgd } 462 1.1 cgd 463 1.1 cgd /* 464 1.1 cgd * Stolen from consh() -- puts a remote file on the output of a local command. 465 1.1 cgd * Identical to consh() except for where stdout goes. 466 1.1 cgd */ 467 1.8 lukem void 468 1.20 perry pipeout(char c) 469 1.1 cgd { 470 1.1 cgd char buf[256]; 471 1.1 cgd int cpid, status, p; 472 1.8 lukem time_t start = 0; 473 1.1 cgd 474 1.32 christos (void)putchar(c); 475 1.11 mrg if (prompt("Local command? ", buf, sizeof buf)) 476 1.1 cgd return; 477 1.32 christos (void)write(attndes[1], "W", 1); /* put TIPOUT into a wait state */ 478 1.32 christos (void)signal(SIGINT, SIG_IGN); 479 1.32 christos (void)signal(SIGQUIT, SIG_IGN); 480 1.32 christos (void)tcsetattr(0, TCSAFLUSH, &defchars); 481 1.32 christos (void)read(repdes[0], (char *)&ccc, 1); 482 1.1 cgd /* 483 1.1 cgd * Set up file descriptors in the child and 484 1.1 cgd * let it go... 485 1.1 cgd */ 486 1.1 cgd if ((cpid = fork()) < 0) 487 1.32 christos (void)printf("can't fork!\r\n"); 488 1.1 cgd else if (cpid) { 489 1.1 cgd start = time(0); 490 1.1 cgd while ((p = wait(&status)) > 0 && p != cpid) 491 1.1 cgd ; 492 1.1 cgd } else { 493 1.32 christos (void)dup2(FD, 1); 494 1.32 christos (void)closefrom(3); 495 1.32 christos (void)signal(SIGINT, SIG_DFL); 496 1.32 christos (void)signal(SIGQUIT, SIG_DFL); 497 1.1 cgd execute(buf); 498 1.32 christos (void)printf("can't find `%s'\r\n", buf); 499 1.1 cgd exit(0); 500 1.1 cgd } 501 1.1 cgd if (boolean(value(VERBOSE))) 502 1.1 cgd prtime("away for ", time(0)-start); 503 1.32 christos (void)write(fildes[1], (char *)&ccc, 1); 504 1.32 christos (void)tcsetattr(0, TCSAFLUSH, &term); 505 1.32 christos (void)signal(SIGINT, SIG_DFL); 506 1.32 christos (void)signal(SIGQUIT, SIG_DFL); 507 1.1 cgd } 508 1.1 cgd 509 1.1 cgd /* 510 1.1 cgd * Fork a program with: 511 1.1 cgd * 0 <-> remote tty in 512 1.1 cgd * 1 <-> remote tty out 513 1.1 cgd * 2 <-> local tty out 514 1.1 cgd */ 515 1.8 lukem void 516 1.20 perry consh(char c) 517 1.1 cgd { 518 1.1 cgd char buf[256]; 519 1.1 cgd int cpid, status, p; 520 1.8 lukem time_t start = 0; 521 1.1 cgd 522 1.32 christos (void)putchar(c); 523 1.11 mrg if (prompt("Local command? ", buf, sizeof buf)) 524 1.1 cgd return; 525 1.32 christos (void)write(attndes[1], "W", 1); /* put TIPOUT into a wait state */ 526 1.32 christos (void)signal(SIGINT, SIG_IGN); 527 1.32 christos (void)signal(SIGQUIT, SIG_IGN); 528 1.32 christos (void)tcsetattr(0, TCSAFLUSH, &defchars); 529 1.32 christos (void)read(repdes[0], (char *)&ccc, 1); 530 1.1 cgd /* 531 1.1 cgd * Set up file descriptors in the child and 532 1.1 cgd * let it go... 533 1.1 cgd */ 534 1.1 cgd if ((cpid = fork()) < 0) 535 1.32 christos (void)printf("can't fork!\r\n"); 536 1.1 cgd else if (cpid) { 537 1.1 cgd start = time(0); 538 1.1 cgd while ((p = wait(&status)) > 0 && p != cpid) 539 1.1 cgd ; 540 1.1 cgd } else { 541 1.32 christos (void)dup2(FD, 0); 542 1.32 christos (void)dup2(FD, 1); 543 1.32 christos (void)closefrom(3); 544 1.32 christos (void)signal(SIGINT, SIG_DFL); 545 1.32 christos (void)signal(SIGQUIT, SIG_DFL); 546 1.1 cgd execute(buf); 547 1.32 christos (void)printf("can't find `%s'\r\n", buf); 548 1.1 cgd exit(0); 549 1.1 cgd } 550 1.1 cgd if (boolean(value(VERBOSE))) 551 1.1 cgd prtime("away for ", time(0)-start); 552 1.32 christos (void)write(fildes[1], (char *)&ccc, 1); 553 1.32 christos (void)tcsetattr(0, TCSAFLUSH, &term); 554 1.32 christos (void)signal(SIGINT, SIG_DFL); 555 1.32 christos (void)signal(SIGQUIT, SIG_DFL); 556 1.1 cgd } 557 1.1 cgd 558 1.1 cgd /* 559 1.1 cgd * Escape to local shell 560 1.1 cgd */ 561 1.23 perry /* ARGSUSED */ 562 1.8 lukem void 563 1.32 christos shell(char dummy __unused) 564 1.1 cgd { 565 1.1 cgd int shpid, status; 566 1.16 christos const char *cp; 567 1.1 cgd 568 1.32 christos (void)printf("[sh]\r\n"); 569 1.32 christos (void)signal(SIGINT, SIG_IGN); 570 1.32 christos (void)signal(SIGQUIT, SIG_IGN); 571 1.1 cgd unraw(); 572 1.8 lukem switch (shpid = fork()) { 573 1.8 lukem default: 574 1.1 cgd while (shpid != wait(&status)); 575 1.1 cgd raw(); 576 1.32 christos (void)printf("\r\n!\r\n"); 577 1.32 christos (void)signal(SIGINT, SIG_DFL); 578 1.32 christos (void)signal(SIGQUIT, SIG_DFL); 579 1.8 lukem break; 580 1.8 lukem case 0: 581 1.32 christos (void)signal(SIGQUIT, SIG_DFL); 582 1.32 christos (void)signal(SIGINT, SIG_DFL); 583 1.8 lukem if ((cp = strrchr(value(SHELL), '/')) == NULL) 584 1.1 cgd cp = value(SHELL); 585 1.1 cgd else 586 1.1 cgd cp++; 587 1.32 christos (void)execl(value(SHELL), cp, NULL); 588 1.32 christos (void)fprintf(stderr, "\r\n"); 589 1.8 lukem err(1, "can't execl"); 590 1.8 lukem /* NOTREACHED */ 591 1.8 lukem case -1: 592 1.32 christos (void)fprintf(stderr, "\r\n"); 593 1.8 lukem err(1, "can't fork"); 594 1.8 lukem /* NOTREACHED */ 595 1.1 cgd } 596 1.1 cgd } 597 1.1 cgd 598 1.1 cgd /* 599 1.1 cgd * TIPIN portion of scripting 600 1.1 cgd * initiate the conversation with TIPOUT 601 1.1 cgd */ 602 1.8 lukem void 603 1.20 perry setscript(void) 604 1.1 cgd { 605 1.1 cgd char c; 606 1.1 cgd /* 607 1.1 cgd * enable TIPOUT side for dialogue 608 1.1 cgd */ 609 1.32 christos (void)write(attndes[1], "S", 1); 610 1.9 lukem if (boolean(value(SCRIPT)) && strlen(value(RECORD))) 611 1.32 christos (void)write(fildes[1], value(RECORD), strlen(value(RECORD))); 612 1.32 christos (void)write(fildes[1], "\n", 1); 613 1.1 cgd /* 614 1.1 cgd * wait for TIPOUT to finish 615 1.1 cgd */ 616 1.32 christos (void)read(repdes[0], &c, 1); 617 1.1 cgd if (c == 'n') 618 1.32 christos (void)printf("can't create %s\r\n", (char *)value(RECORD)); 619 1.1 cgd } 620 1.1 cgd 621 1.1 cgd /* 622 1.1 cgd * Change current working directory of 623 1.1 cgd * local portion of tip 624 1.1 cgd */ 625 1.23 perry /* ARGSUSED */ 626 1.8 lukem void 627 1.32 christos chdirectory(char dummy __unused) 628 1.1 cgd { 629 1.16 christos char dirnam[80]; 630 1.16 christos const char *cp = dirnam; 631 1.1 cgd 632 1.16 christos if (prompt("[cd] ", dirnam, sizeof dirnam)) { 633 1.1 cgd if (stoprompt) 634 1.1 cgd return; 635 1.1 cgd cp = value(HOME); 636 1.1 cgd } 637 1.1 cgd if (chdir(cp) < 0) 638 1.32 christos (void)printf("%s: bad directory\r\n", cp); 639 1.32 christos (void)printf("!\r\n"); 640 1.1 cgd } 641 1.1 cgd 642 1.8 lukem void 643 1.20 perry tipabort(const char *msg) 644 1.1 cgd { 645 1.1 cgd 646 1.32 christos (void)kill(pid, SIGTERM); 647 1.1 cgd disconnect(msg); 648 1.8 lukem if (msg != NULL) 649 1.32 christos (void)printf("\r\n%s", msg); 650 1.32 christos (void)printf("\r\n[EOT]\r\n"); 651 1.1 cgd unraw(); 652 1.1 cgd exit(0); 653 1.1 cgd } 654 1.1 cgd 655 1.23 perry /* ARGSUSED */ 656 1.8 lukem void 657 1.32 christos finish(char dummy __unused) 658 1.1 cgd { 659 1.16 christos const char *dismsg; 660 1.1 cgd 661 1.9 lukem dismsg = value(DISCONNECT); 662 1.9 lukem if (dismsg != NULL && dismsg[0] != '\0') { 663 1.32 christos (void)write(FD, dismsg, strlen(dismsg)); 664 1.32 christos (void)sleep(5); 665 1.1 cgd } 666 1.8 lukem tipabort(NULL); 667 1.1 cgd } 668 1.1 cgd 669 1.23 perry /* ARGSUSED */ 670 1.1 cgd void 671 1.32 christos intcopy(int dummy __unused) 672 1.1 cgd { 673 1.11 mrg 674 1.1 cgd raw(); 675 1.1 cgd quit = 1; 676 1.1 cgd longjmp(intbuf, 1); 677 1.1 cgd } 678 1.1 cgd 679 1.8 lukem void 680 1.20 perry execute(char *s) 681 1.1 cgd { 682 1.16 christos const char *cp; 683 1.1 cgd 684 1.8 lukem if ((cp = strrchr(value(SHELL), '/')) == NULL) 685 1.1 cgd cp = value(SHELL); 686 1.1 cgd else 687 1.1 cgd cp++; 688 1.32 christos (void)execl(value(SHELL), cp, "-c", s, NULL); 689 1.1 cgd } 690 1.1 cgd 691 1.8 lukem int 692 1.20 perry args(char *buf, char *a[]) 693 1.1 cgd { 694 1.8 lukem char *p = buf, *start; 695 1.8 lukem char **parg = a; 696 1.8 lukem int n = 0; 697 1.1 cgd 698 1.1 cgd do { 699 1.1 cgd while (*p && (*p == ' ' || *p == '\t')) 700 1.1 cgd p++; 701 1.1 cgd start = p; 702 1.1 cgd if (*p) 703 1.1 cgd *parg = p; 704 1.1 cgd while (*p && (*p != ' ' && *p != '\t')) 705 1.1 cgd p++; 706 1.1 cgd if (p != start) 707 1.1 cgd parg++, n++; 708 1.1 cgd if (*p) 709 1.1 cgd *p++ = '\0'; 710 1.1 cgd } while (*p); 711 1.1 cgd 712 1.1 cgd return(n); 713 1.1 cgd } 714 1.1 cgd 715 1.8 lukem void 716 1.20 perry prtime(const char *s, time_t a) 717 1.1 cgd { 718 1.8 lukem int i; 719 1.1 cgd int nums[3]; 720 1.1 cgd 721 1.1 cgd for (i = 0; i < 3; i++) { 722 1.1 cgd nums[i] = (int)(a % quant[i]); 723 1.1 cgd a /= quant[i]; 724 1.1 cgd } 725 1.32 christos (void)printf("%s", s); 726 1.1 cgd while (--i >= 0) 727 1.8 lukem if (nums[i] || (i == 0 && nums[1] == 0 && nums[2] == 0)) 728 1.32 christos (void)printf("%d %s%c ", nums[i], sep[i], 729 1.1 cgd nums[i] == 1 ? '\0' : 's'); 730 1.32 christos (void)printf("\r\n!\r\n"); 731 1.1 cgd } 732 1.1 cgd 733 1.23 perry /* ARGSUSED */ 734 1.8 lukem void 735 1.32 christos variable(char dummy __unused) 736 1.1 cgd { 737 1.1 cgd char buf[256]; 738 1.1 cgd 739 1.11 mrg if (prompt("[set] ", buf, sizeof buf)) 740 1.1 cgd return; 741 1.1 cgd vlex(buf); 742 1.1 cgd if (vtable[BEAUTIFY].v_access&CHANGED) { 743 1.1 cgd vtable[BEAUTIFY].v_access &= ~CHANGED; 744 1.32 christos (void)write(attndes[1], "B", 1); /* Tell TIPOUT to toggle */ 745 1.1 cgd } 746 1.1 cgd if (vtable[SCRIPT].v_access&CHANGED) { 747 1.1 cgd vtable[SCRIPT].v_access &= ~CHANGED; 748 1.1 cgd setscript(); 749 1.1 cgd /* 750 1.1 cgd * So that "set record=blah script" doesn't 751 1.1 cgd * cause two transactions to occur. 752 1.1 cgd */ 753 1.1 cgd if (vtable[RECORD].v_access&CHANGED) 754 1.1 cgd vtable[RECORD].v_access &= ~CHANGED; 755 1.1 cgd } 756 1.1 cgd if (vtable[RECORD].v_access&CHANGED) { 757 1.1 cgd vtable[RECORD].v_access &= ~CHANGED; 758 1.1 cgd if (boolean(value(SCRIPT))) 759 1.1 cgd setscript(); 760 1.1 cgd } 761 1.1 cgd if (vtable[TAND].v_access&CHANGED) { 762 1.1 cgd vtable[TAND].v_access &= ~CHANGED; 763 1.1 cgd if (boolean(value(TAND))) 764 1.1 cgd tandem("on"); 765 1.1 cgd else 766 1.1 cgd tandem("off"); 767 1.1 cgd } 768 1.1 cgd if (vtable[LECHO].v_access&CHANGED) { 769 1.1 cgd vtable[LECHO].v_access &= ~CHANGED; 770 1.1 cgd HD = boolean(value(LECHO)); 771 1.1 cgd } 772 1.1 cgd if (vtable[PARITY].v_access&CHANGED) { 773 1.1 cgd vtable[PARITY].v_access &= ~CHANGED; 774 1.8 lukem setparity(NULL); /* XXX what is the correct arg? */ 775 1.1 cgd } 776 1.17 yamt if (vtable[HARDWAREFLOW].v_access&CHANGED) { 777 1.17 yamt vtable[HARDWAREFLOW].v_access &= ~CHANGED; 778 1.17 yamt if (boolean(value(HARDWAREFLOW))) 779 1.17 yamt hardwareflow("on"); 780 1.17 yamt else 781 1.17 yamt hardwareflow("off"); 782 1.17 yamt } 783 1.1 cgd } 784 1.1 cgd 785 1.1 cgd /* 786 1.1 cgd * Turn tandem mode on or off for remote tty. 787 1.1 cgd */ 788 1.8 lukem void 789 1.20 perry tandem(const char *option) 790 1.1 cgd { 791 1.6 pk struct termios rmtty; 792 1.1 cgd 793 1.32 christos (void)tcgetattr(FD, &rmtty); 794 1.6 pk if (strcmp(option, "on") == 0) { 795 1.37 mlelstv rmtty.c_iflag |= IXON|IXOFF; 796 1.37 mlelstv term.c_iflag |= IXON|IXOFF; 797 1.1 cgd } else { 798 1.37 mlelstv rmtty.c_iflag &= ~(IXON|IXOFF); 799 1.37 mlelstv term.c_iflag &= ~(IXON|IXOFF); 800 1.1 cgd } 801 1.32 christos (void)tcsetattr(FD, TCSADRAIN, &rmtty); 802 1.32 christos (void)tcsetattr(0, TCSADRAIN, &term); 803 1.1 cgd } 804 1.1 cgd 805 1.1 cgd /* 806 1.17 yamt * Turn hardware flow control on or off for remote tty. 807 1.17 yamt */ 808 1.17 yamt void 809 1.20 perry hardwareflow(const char *option) 810 1.17 yamt { 811 1.17 yamt struct termios rmtty; 812 1.17 yamt 813 1.32 christos (void)tcgetattr(FD, &rmtty); 814 1.17 yamt if (strcmp(option, "on") == 0) 815 1.19 tls rmtty.c_cflag |= CRTSCTS; 816 1.17 yamt else 817 1.19 tls rmtty.c_cflag &= ~CRTSCTS; 818 1.32 christos (void)tcsetattr(FD, TCSADRAIN, &rmtty); 819 1.17 yamt } 820 1.17 yamt 821 1.17 yamt /* 822 1.1 cgd * Send a break. 823 1.1 cgd */ 824 1.23 perry /* ARGSUSED */ 825 1.8 lukem void 826 1.32 christos genbrk(char dummy __unused) 827 1.1 cgd { 828 1.1 cgd 829 1.32 christos (void)ioctl(FD, TIOCSBRK, NULL); 830 1.32 christos (void)sleep(1); 831 1.32 christos (void)ioctl(FD, TIOCCBRK, NULL); 832 1.1 cgd } 833 1.1 cgd 834 1.1 cgd /* 835 1.1 cgd * Suspend tip 836 1.1 cgd */ 837 1.8 lukem void 838 1.20 perry suspend(char c) 839 1.1 cgd { 840 1.1 cgd 841 1.1 cgd unraw(); 842 1.32 christos (void)kill(c == CTRL('y') ? getpid() : 0, SIGTSTP); 843 1.1 cgd raw(); 844 1.1 cgd } 845 1.1 cgd 846 1.1 cgd /* 847 1.1 cgd * expand a file name if it includes shell meta characters 848 1.1 cgd */ 849 1.1 cgd 850 1.1 cgd char * 851 1.30 christos expand(char aname[]) 852 1.1 cgd { 853 1.1 cgd static char xname[BUFSIZ]; 854 1.31 christos char * volatile name; 855 1.1 cgd char cmdbuf[BUFSIZ]; 856 1.16 christos int mypid, l; 857 1.16 christos char *cp; 858 1.16 christos const char *Shell; 859 1.8 lukem int s, pivec[2]; 860 1.1 cgd 861 1.31 christos name = aname; 862 1.1 cgd if (!anyof(name, "~{[*?$`'\"\\")) 863 1.1 cgd return(name); 864 1.1 cgd if (pipe(pivec) < 0) { 865 1.18 tls warn("pipe"); 866 1.1 cgd return(name); 867 1.1 cgd } 868 1.7 mrg (void)snprintf(cmdbuf, sizeof cmdbuf, "echo %s", name); 869 1.16 christos if ((mypid = vfork()) == 0) { 870 1.1 cgd Shell = value(SHELL); 871 1.8 lukem if (Shell == NULL) 872 1.1 cgd Shell = _PATH_BSHELL; 873 1.32 christos (void)close(pivec[0]); 874 1.32 christos (void)close(1); 875 1.32 christos (void)dup(pivec[1]); 876 1.32 christos (void)close(pivec[1]); 877 1.32 christos (void)close(2); 878 1.32 christos (void)execl(Shell, Shell, "-c", cmdbuf, NULL); 879 1.1 cgd _exit(1); 880 1.1 cgd } 881 1.16 christos if (mypid == -1) { 882 1.18 tls warn("fork"); 883 1.32 christos (void)close(pivec[0]); 884 1.32 christos (void)close(pivec[1]); 885 1.8 lukem return(NULL); 886 1.1 cgd } 887 1.32 christos (void)close(pivec[1]); 888 1.1 cgd l = read(pivec[0], xname, BUFSIZ); 889 1.32 christos (void)close(pivec[0]); 890 1.34 joerg while (wait(&s) != mypid) 891 1.35 joerg continue; 892 1.1 cgd s &= 0377; 893 1.1 cgd if (s != 0 && s != SIGPIPE) { 894 1.32 christos (void)fprintf(stderr, "\"Echo\" failed\n"); 895 1.8 lukem return(NULL); 896 1.1 cgd } 897 1.1 cgd if (l < 0) { 898 1.18 tls warn("read"); 899 1.8 lukem return(NULL); 900 1.1 cgd } 901 1.1 cgd if (l == 0) { 902 1.32 christos (void)fprintf(stderr, "\"%s\": No match\n", name); 903 1.8 lukem return(NULL); 904 1.1 cgd } 905 1.1 cgd if (l == BUFSIZ) { 906 1.32 christos (void)fprintf(stderr, "Buffer overflow expanding \"%s\"\n", name); 907 1.8 lukem return(NULL); 908 1.1 cgd } 909 1.1 cgd xname[l] = 0; 910 1.1 cgd for (cp = &xname[l-1]; *cp == '\n' && cp > xname; cp--) 911 1.1 cgd ; 912 1.1 cgd *++cp = '\0'; 913 1.1 cgd return(xname); 914 1.1 cgd } 915 1.1 cgd 916 1.1 cgd /* 917 1.1 cgd * Are any of the characters in the two strings the same? 918 1.1 cgd */ 919 1.1 cgd 920 1.8 lukem int 921 1.20 perry anyof(char *s1, const char *s2) 922 1.1 cgd { 923 1.8 lukem int c; 924 1.1 cgd 925 1.24 christos while ((c = *s1++) != '\0') 926 1.1 cgd if (any(c, s2)) 927 1.1 cgd return(1); 928 1.1 cgd return(0); 929 1.1 cgd } 930