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