1 /* $NetBSD: cmds.c,v 1.14 2003/08/07 11:16:16 agc 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.14 2003/08/07 11:16:16 agc 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 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 *, char *)); 57 void execute __P((char *)); 58 void intcopy __P((int)); 59 void prtime __P((char *, time_t)); 60 void stopsnd __P((int)); 61 void transfer __P((char *, int, char *)); 62 void transmit __P((FILE *, 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_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_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 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 char *eofchars, *command; 301 { 302 char *pc, lastc; 303 int c, ccount, lcount; 304 time_t start_t, stop_t; 305 sig_t f; 306 307 kill(pid, SIGIOT); /* put TIPOUT into a wait state */ 308 stop = 0; 309 f = signal(SIGINT, stopsnd); 310 tcsetattr(0, TCSAFLUSH, &defchars); 311 read(repdes[0], (char *)&ccc, 1); 312 if (command != NULL) { 313 for (pc = command; *pc; pc++) 314 send(*pc); 315 if (boolean(value(ECHOCHECK))) 316 read(FD, (char *)&c, 1); /* trailing \n */ 317 else { 318 tcdrain(FD); 319 sleep(5); /* wait for remote stty to take effect */ 320 } 321 } 322 lcount = 0; 323 lastc = '\0'; 324 start_t = time(0); 325 while (1) { 326 ccount = 0; 327 do { 328 c = getc(fd); 329 if (stop) 330 goto out; 331 if (c == EOF) 332 goto out; 333 if (c == 0177 && !boolean(value(RAWFTP))) 334 continue; 335 lastc = c; 336 if (c < 040) { 337 if (c == '\n') { 338 if (!boolean(value(RAWFTP))) 339 c = '\r'; 340 } 341 else if (c == '\t') { 342 if (!boolean(value(RAWFTP))) { 343 if (boolean(value(TABEXPAND))) { 344 send(' '); 345 while ((++ccount % 8) != 0) 346 send(' '); 347 continue; 348 } 349 } 350 } else 351 if (!boolean(value(RAWFTP))) 352 continue; 353 } 354 send(c); 355 } while (c != '\r' && !boolean(value(RAWFTP))); 356 if (boolean(value(VERBOSE))) 357 printf("\r%d", ++lcount); 358 if (boolean(value(ECHOCHECK))) { 359 timedout = 0; 360 alarm((long)value(ETIMEOUT)); 361 do { /* wait for prompt */ 362 read(FD, (char *)&c, 1); 363 if (timedout || stop) { 364 if (timedout) 365 printf( 366 "\r\ntimed out at eol\r\n"); 367 alarm(0); 368 goto out; 369 } 370 } while ((c&STRIP_PAR) != character(value(PROMPT))); 371 alarm(0); 372 } 373 } 374 out: 375 if (lastc != '\n' && !boolean(value(RAWFTP))) 376 send('\r'); 377 if (eofchars) { 378 for (pc = eofchars; *pc; pc++) 379 send(*pc); 380 } 381 stop_t = time(0); 382 fclose(fd); 383 signal(SIGINT, f); 384 if (boolean(value(VERBOSE))) { 385 if (boolean(value(RAWFTP))) 386 prtime(" chars transferred in ", stop_t-start_t); 387 else 388 prtime(" lines transferred in ", stop_t-start_t); 389 } 390 write(fildes[1], (char *)&ccc, 1); 391 tcsetattr(0, TCSAFLUSH, &term); 392 } 393 394 /* 395 * Cu-like put command 396 */ 397 void 398 cu_put(cc) 399 char cc; 400 { 401 FILE *fd; 402 char line[BUFSIZ]; 403 int argc; 404 char *copynamex; 405 406 if (prompt("[put] ", copyname, sizeof copyname)) 407 return; 408 if ((argc = args(copyname, argv)) < 1 || argc > 2) { 409 printf("usage: <put> from [to]\r\n"); 410 return; 411 } 412 if (argc == 1) 413 argv[1] = argv[0]; 414 copynamex = expand(argv[0]); 415 if ((fd = fopen(copynamex, "r")) == NULL) { 416 printf("%s: cannot open\r\n", copynamex); 417 return; 418 } 419 if (boolean(value(ECHOCHECK))) 420 (void)snprintf(line, sizeof line, "cat>%s\r", argv[1]); 421 else 422 (void)snprintf(line, sizeof line, "stty -echo;cat>%s;stty echo\r", argv[1]); 423 transmit(fd, "\04", line); 424 } 425 426 /* 427 * FTP - send single character 428 * wait for echo & handle timeout 429 */ 430 void 431 send(c) 432 char c; 433 { 434 char cc; 435 int retry = 0; 436 437 cc = c; 438 xpwrite(FD, &cc, 1); 439 #ifdef notdef 440 if (number(value(CDELAY)) > 0 && c != '\r') 441 nap(number(value(CDELAY))); 442 #endif 443 if (!boolean(value(ECHOCHECK))) { 444 #ifdef notdef 445 if (number(value(LDELAY)) > 0 && c == '\r') 446 nap(number(value(LDELAY))); 447 #endif 448 return; 449 } 450 tryagain: 451 timedout = 0; 452 alarm((long)value(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 xpwrite(FD, &null, 1); /* poke it */ 460 goto tryagain; 461 } 462 } 463 464 void 465 alrmtimeout(dummy) 466 int dummy; 467 { 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, sizeof 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, sizeof 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, sizeof 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 698 raw(); 699 quit = 1; 700 longjmp(intbuf, 1); 701 } 702 703 void 704 execute(s) 705 char *s; 706 { 707 char *cp; 708 709 if ((cp = strrchr(value(SHELL), '/')) == NULL) 710 cp = value(SHELL); 711 else 712 cp++; 713 shell_uid(); 714 execl(value(SHELL), cp, "-c", s, 0); 715 } 716 717 int 718 args(buf, a) 719 char *buf, *a[]; 720 { 721 char *p = buf, *start; 722 char **parg = a; 723 int n = 0; 724 725 do { 726 while (*p && (*p == ' ' || *p == '\t')) 727 p++; 728 start = p; 729 if (*p) 730 *parg = p; 731 while (*p && (*p != ' ' && *p != '\t')) 732 p++; 733 if (p != start) 734 parg++, n++; 735 if (*p) 736 *p++ = '\0'; 737 } while (*p); 738 739 return(n); 740 } 741 742 void 743 prtime(s, a) 744 char *s; 745 time_t a; 746 { 747 int i; 748 int nums[3]; 749 750 for (i = 0; i < 3; i++) { 751 nums[i] = (int)(a % quant[i]); 752 a /= quant[i]; 753 } 754 printf("%s", s); 755 while (--i >= 0) 756 if (nums[i] || (i == 0 && nums[1] == 0 && nums[2] == 0)) 757 printf("%d %s%c ", nums[i], sep[i], 758 nums[i] == 1 ? '\0' : 's'); 759 printf("\r\n!\r\n"); 760 } 761 762 void 763 variable(dummy) 764 char dummy; 765 { 766 char buf[256]; 767 768 if (prompt("[set] ", buf, sizeof buf)) 769 return; 770 vlex(buf); 771 if (vtable[BEAUTIFY].v_access&CHANGED) { 772 vtable[BEAUTIFY].v_access &= ~CHANGED; 773 kill(pid, SIGSYS); 774 } 775 if (vtable[SCRIPT].v_access&CHANGED) { 776 vtable[SCRIPT].v_access &= ~CHANGED; 777 setscript(); 778 /* 779 * So that "set record=blah script" doesn't 780 * cause two transactions to occur. 781 */ 782 if (vtable[RECORD].v_access&CHANGED) 783 vtable[RECORD].v_access &= ~CHANGED; 784 } 785 if (vtable[RECORD].v_access&CHANGED) { 786 vtable[RECORD].v_access &= ~CHANGED; 787 if (boolean(value(SCRIPT))) 788 setscript(); 789 } 790 if (vtable[TAND].v_access&CHANGED) { 791 vtable[TAND].v_access &= ~CHANGED; 792 if (boolean(value(TAND))) 793 tandem("on"); 794 else 795 tandem("off"); 796 } 797 if (vtable[LECHO].v_access&CHANGED) { 798 vtable[LECHO].v_access &= ~CHANGED; 799 HD = boolean(value(LECHO)); 800 } 801 if (vtable[PARITY].v_access&CHANGED) { 802 vtable[PARITY].v_access &= ~CHANGED; 803 setparity(NULL); /* XXX what is the correct arg? */ 804 } 805 } 806 807 /* 808 * Turn tandem mode on or off for remote tty. 809 */ 810 void 811 tandem(option) 812 char *option; 813 { 814 struct termios rmtty; 815 816 tcgetattr(FD, &rmtty); 817 if (strcmp(option, "on") == 0) { 818 rmtty.c_iflag |= IXOFF; 819 term.c_iflag |= IXOFF; 820 } else { 821 rmtty.c_iflag &= ~IXOFF; 822 term.c_iflag &= ~IXOFF; 823 } 824 tcsetattr(FD, TCSADRAIN, &rmtty); 825 tcsetattr(0, TCSADRAIN, &term); 826 } 827 828 /* 829 * Send a break. 830 */ 831 void 832 genbrk(dummy) 833 char dummy; 834 { 835 836 ioctl(FD, TIOCSBRK, NULL); 837 sleep(1); 838 ioctl(FD, TIOCCBRK, NULL); 839 } 840 841 /* 842 * Suspend tip 843 */ 844 void 845 suspend(c) 846 char c; 847 { 848 849 unraw(); 850 kill(c == CTRL('y') ? getpid() : 0, SIGTSTP); 851 raw(); 852 } 853 854 /* 855 * expand a file name if it includes shell meta characters 856 */ 857 858 char * 859 expand(name) 860 char name[]; 861 { 862 static char xname[BUFSIZ]; 863 char cmdbuf[BUFSIZ]; 864 int pid, l; 865 char *cp, *Shell; 866 int s, pivec[2]; 867 868 if (!anyof(name, "~{[*?$`'\"\\")) 869 return(name); 870 if (pipe(pivec) < 0) { 871 perror("pipe"); 872 return(name); 873 } 874 (void)snprintf(cmdbuf, sizeof cmdbuf, "echo %s", name); 875 if ((pid = vfork()) == 0) { 876 Shell = value(SHELL); 877 if (Shell == NULL) 878 Shell = _PATH_BSHELL; 879 close(pivec[0]); 880 close(1); 881 dup(pivec[1]); 882 close(pivec[1]); 883 close(2); 884 shell_uid(); 885 execl(Shell, Shell, "-c", cmdbuf, 0); 886 _exit(1); 887 } 888 if (pid == -1) { 889 perror("fork"); 890 close(pivec[0]); 891 close(pivec[1]); 892 return(NULL); 893 } 894 close(pivec[1]); 895 l = read(pivec[0], xname, BUFSIZ); 896 close(pivec[0]); 897 while (wait(&s) != pid); 898 ; 899 s &= 0377; 900 if (s != 0 && s != SIGPIPE) { 901 fprintf(stderr, "\"Echo\" failed\n"); 902 return(NULL); 903 } 904 if (l < 0) { 905 perror("read"); 906 return(NULL); 907 } 908 if (l == 0) { 909 fprintf(stderr, "\"%s\": No match\n", name); 910 return(NULL); 911 } 912 if (l == BUFSIZ) { 913 fprintf(stderr, "Buffer overflow expanding \"%s\"\n", name); 914 return(NULL); 915 } 916 xname[l] = 0; 917 for (cp = &xname[l-1]; *cp == '\n' && cp > xname; cp--) 918 ; 919 *++cp = '\0'; 920 return(xname); 921 } 922 923 /* 924 * Are any of the characters in the two strings the same? 925 */ 926 927 int 928 anyof(s1, s2) 929 char *s1, *s2; 930 { 931 int c; 932 933 while ((c = *s1++)) 934 if (any(c, s2)) 935 return(1); 936 return(0); 937 } 938