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