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