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