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