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