cmds.c revision 79452
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 79452 2001-07-09 09:24:06Z brian $"; 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 */ 728int 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 return 0; 737} 738#endif 739 740/* 741 * Escape to local shell 742 */ 743void 744shell() 745{ 746 int shpid, status; 747 char *cp; 748 749 printf("[sh]\r\n"); 750 signal(SIGINT, SIG_IGN); 751 signal(SIGQUIT, SIG_IGN); 752 unraw(); 753 if ((shpid = fork())) { 754 while (shpid != wait(&status)); 755 raw(); 756 printf("\r\n!\r\n"); 757 signal(SIGINT, SIG_DFL); 758 signal(SIGQUIT, SIG_DFL); 759 return; 760 } else { 761 signal(SIGQUIT, SIG_DFL); 762 signal(SIGINT, SIG_DFL); 763 if ((cp = rindex(value(SHELL), '/')) == NULL) 764 cp = value(SHELL); 765 else 766 cp++; 767 shell_uid(); 768 execl(value(SHELL), cp, (char *)0); 769 printf("\r\ncan't execl!\r\n"); 770 exit(1); 771 } 772} 773 774/* 775 * TIPIN portion of scripting 776 * initiate the conversation with TIPOUT 777 */ 778void 779setscript() 780{ 781 char c; 782 /* 783 * enable TIPOUT side for dialogue 784 */ 785 kill(pid, SIGEMT); 786 if (boolean(value(SCRIPT))) 787 write(fildes[1], value(RECORD), size(value(RECORD))); 788 write(fildes[1], "\n", 1); 789 /* 790 * wait for TIPOUT to finish 791 */ 792 read(repdes[0], &c, 1); 793 if (c == 'n') 794 printf("can't create %s\r\n", value(RECORD)); 795} 796 797/* 798 * Change current working directory of 799 * local portion of tip 800 */ 801void 802chdirectory() 803{ 804 char dirname[PATH_MAX]; 805 register char *cp = dirname; 806 807 if (prompt("[cd] ", dirname, sizeof(dirname))) { 808 if (stoprompt) 809 return; 810 cp = value(HOME); 811 } 812 if (chdir(cp) < 0) 813 printf("%s: bad directory\r\n", cp); 814 printf("!\r\n"); 815} 816 817void 818tipabort(msg) 819 char *msg; 820{ 821 822 kill(pid, SIGTERM); 823 disconnect(msg); 824 if (msg != NOSTR) 825 printf("\r\n%s", msg); 826 printf("\r\n[EOT]\r\n"); 827 daemon_uid(); 828 (void)uu_unlock(uucplock); 829 unraw(); 830 exit(0); 831} 832 833void 834finish() 835{ 836 char *abortmsg = NOSTR, *dismsg; 837 838 if (LO != NOSTR && tiplink (LO, TL_SIGNAL_TIPOUT) != 0) { 839 abortmsg = "logout failed"; 840 } 841 842 if ((dismsg = value(DISCONNECT)) != NOSTR) { 843 write(FD, dismsg, strlen(dismsg)); 844 sleep (2); 845 } 846 tipabort(abortmsg); 847} 848 849void 850intcopy() 851{ 852 raw(); 853 quit = 1; 854 longjmp(intbuf, 1); 855} 856 857static void 858execute(s) 859 char *s; 860{ 861 register char *cp; 862 863 if ((cp = rindex(value(SHELL), '/')) == NULL) 864 cp = value(SHELL); 865 else 866 cp++; 867 shell_uid(); 868 execl(value(SHELL), cp, "-c", s, (char *)0); 869} 870 871static int 872args(buf, a, num) 873 char *buf, *a[]; 874 int num; 875{ 876 register char *p = buf, *start; 877 register char **parg = a; 878 register int n = 0; 879 880 while (*p && n < num) { 881 while (*p && (*p == ' ' || *p == '\t')) 882 p++; 883 start = p; 884 if (*p) 885 *parg = p; 886 while (*p && (*p != ' ' && *p != '\t')) 887 p++; 888 if (p != start) 889 parg++, n++; 890 if (*p) 891 *p++ = '\0'; 892 } 893 return(n); 894} 895 896static void 897prtime(s, a) 898 char *s; 899 time_t a; 900{ 901 register i; 902 int nums[3]; 903 904 for (i = 0; i < 3; i++) { 905 nums[i] = (int)(a % quant[i]); 906 a /= quant[i]; 907 } 908 printf("%s", s); 909 while (--i >= 0) 910 if (nums[i] || (i == 0 && nums[1] == 0 && nums[2] == 0)) 911 printf("%d %s%c ", nums[i], sep[i], 912 nums[i] == 1 ? '\0' : 's'); 913 printf("\r\n!\r\n"); 914} 915 916void 917variable() 918{ 919 char buf[256]; 920 921 if (prompt("[set] ", buf, sizeof(buf))) 922 return; 923 vlex(buf); 924 if (vtable[BEAUTIFY].v_access&CHANGED) { 925 vtable[BEAUTIFY].v_access &= ~CHANGED; 926 kill(pid, SIGSYS); 927 } 928 if (vtable[SCRIPT].v_access&CHANGED) { 929 vtable[SCRIPT].v_access &= ~CHANGED; 930 setscript(); 931 /* 932 * So that "set record=blah script" doesn't 933 * cause two transactions to occur. 934 */ 935 if (vtable[RECORD].v_access&CHANGED) 936 vtable[RECORD].v_access &= ~CHANGED; 937 } 938 if (vtable[RECORD].v_access&CHANGED) { 939 vtable[RECORD].v_access &= ~CHANGED; 940 if (boolean(value(SCRIPT))) 941 setscript(); 942 } 943 if (vtable[TAND].v_access&CHANGED) { 944 vtable[TAND].v_access &= ~CHANGED; 945 if (boolean(value(TAND))) 946 tandem("on"); 947 else 948 tandem("off"); 949 } 950 if (vtable[LECHO].v_access&CHANGED) { 951 vtable[LECHO].v_access &= ~CHANGED; 952 HD = boolean(value(LECHO)); 953 } 954 if (vtable[PARITY].v_access&CHANGED) { 955 vtable[PARITY].v_access &= ~CHANGED; 956 setparity(value(PARITY)); 957 } 958} 959 960/* 961 * Turn tandem mode on or off for remote tty. 962 */ 963static void 964tandem(option) 965 char *option; 966{ 967#if HAVE_TERMIOS 968 struct termios ttermios; 969 tcgetattr (FD, &ttermios); 970 if (strcmp(option,"on") == 0) { 971 ttermios.c_iflag |= IXOFF; 972 ctermios.c_iflag |= IXOFF; 973 } 974 else { 975 ttermios.c_iflag &= ~IXOFF; 976 ctermios.c_iflag &= ~IXOFF; 977 } 978 tcsetattr (FD, TCSANOW, &ttermios); 979 tcsetattr (0, TCSANOW, &ctermios); 980#else /* HAVE_TERMIOS */ 981 struct sgttyb rmtty; 982 983 ioctl(FD, TIOCGETP, &rmtty); 984 if (strcmp(option,"on") == 0) { 985 rmtty.sg_flags |= TANDEM; 986 arg.sg_flags |= TANDEM; 987 } else { 988 rmtty.sg_flags &= ~TANDEM; 989 arg.sg_flags &= ~TANDEM; 990 } 991 ioctl(FD, TIOCSETP, &rmtty); 992 ioctl(0, TIOCSETP, &arg); 993#endif /* HAVE_TERMIOS */ 994} 995 996/* 997 * Send a break. 998 */ 999void 1000genbrk() 1001{ 1002 1003 ioctl(FD, TIOCSBRK, NULL); 1004 sleep(1); 1005 ioctl(FD, TIOCCBRK, NULL); 1006} 1007 1008/* 1009 * Suspend tip 1010 */ 1011void 1012suspend(c) 1013 char c; 1014{ 1015 1016 unraw(); 1017 kill(c == CTRL('y') ? getpid() : 0, SIGTSTP); 1018 raw(); 1019} 1020 1021/* 1022 * expand a file name if it includes shell meta characters 1023 */ 1024 1025char * 1026expand(name) 1027 char name[]; 1028{ 1029 static char xname[BUFSIZ]; 1030 char cmdbuf[BUFSIZ]; 1031 register int pid, l; 1032 register char *cp, *Shell; 1033 int s, pivec[2] /*, (*sigint)()*/; 1034 1035 if (!anyof(name, "~{[*?$`'\"\\")) 1036 return(name); 1037 /* sigint = signal(SIGINT, SIG_IGN); */ 1038 if (pipe(pivec) < 0) { 1039 warn("pipe"); 1040 /* signal(SIGINT, sigint) */ 1041 return(name); 1042 } 1043 snprintf(cmdbuf, sizeof(cmdbuf), "echo %s", name); 1044 if ((pid = vfork()) == 0) { 1045 Shell = value(SHELL); 1046 if (Shell == NOSTR) 1047 Shell = _PATH_BSHELL; 1048 close(pivec[0]); 1049 close(1); 1050 dup(pivec[1]); 1051 close(pivec[1]); 1052 close(2); 1053 shell_uid(); 1054 execl(Shell, Shell, "-c", cmdbuf, (char *)0); 1055 _exit(1); 1056 } 1057 if (pid == -1) { 1058 warn("fork"); 1059 close(pivec[0]); 1060 close(pivec[1]); 1061 return(NOSTR); 1062 } 1063 close(pivec[1]); 1064 l = read(pivec[0], xname, BUFSIZ); 1065 close(pivec[0]); 1066 while (wait(&s) != pid); 1067 ; 1068 s &= 0377; 1069 if (s != 0 && s != SIGPIPE) { 1070 fprintf(stderr, "\"Echo\" failed\n"); 1071 return(NOSTR); 1072 } 1073 if (l < 0) { 1074 warn("read"); 1075 return(NOSTR); 1076 } 1077 if (l == 0) { 1078 fprintf(stderr, "\"%s\": No match\n", name); 1079 return(NOSTR); 1080 } 1081 if (l == BUFSIZ) { 1082 fprintf(stderr, "Buffer overflow expanding \"%s\"\n", name); 1083 return(NOSTR); 1084 } 1085 xname[l] = 0; 1086 for (cp = &xname[l-1]; *cp == '\n' && cp > xname; cp--) 1087 ; 1088 *++cp = '\0'; 1089 return(xname); 1090} 1091 1092/* 1093 * Are any of the characters in the two strings the same? 1094 */ 1095 1096static int 1097anyof(s1, s2) 1098 register char *s1, *s2; 1099{ 1100 register int c; 1101 1102 while ((c = *s1++)) 1103 if (any(c, s2)) 1104 return(1); 1105 return(0); 1106} 1107