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