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