1 /* 2 * Copyright (c) 1983, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 static char sccsid[] = "@(#)cmds.c 8.1 (Berkeley) 06/06/93"; 10 #endif /* not lint */ 11 12 #include "tip.h" 13 #include "pathnames.h" 14 15 /* 16 * tip 17 * 18 * miscellaneous commands 19 */ 20 21 int quant[] = { 60, 60, 24 }; 22 23 char null = '\0'; 24 char *sep[] = { "second", "minute", "hour" }; 25 static char *argv[10]; /* argument vector for take and put */ 26 27 void timeout(); /* timeout function called on alarm */ 28 void stopsnd(); /* SIGINT handler during file transfers */ 29 void intcopy(); /* interrupt routine for file transfers */ 30 31 /* 32 * FTP - remote ==> local 33 * get a file from the remote host 34 */ 35 getfl(c) 36 char c; 37 { 38 char buf[256], *cp, *expand(); 39 40 putchar(c); 41 /* 42 * get the UNIX receiving file's name 43 */ 44 if (prompt("Local file name? ", copyname)) 45 return; 46 cp = expand(copyname); 47 if ((sfd = creat(cp, 0666)) < 0) { 48 printf("\r\n%s: cannot creat\r\n", copyname); 49 return; 50 } 51 52 /* 53 * collect parameters 54 */ 55 if (prompt("List command for remote system? ", buf)) { 56 unlink(copyname); 57 return; 58 } 59 transfer(buf, sfd, value(EOFREAD)); 60 } 61 62 /* 63 * Cu-like take command 64 */ 65 cu_take(cc) 66 char cc; 67 { 68 int fd, argc; 69 char line[BUFSIZ], *expand(), *cp; 70 71 if (prompt("[take] ", copyname)) 72 return; 73 if ((argc = args(copyname, argv)) < 1 || argc > 2) { 74 printf("usage: <take> from [to]\r\n"); 75 return; 76 } 77 if (argc == 1) 78 argv[1] = argv[0]; 79 cp = expand(argv[1]); 80 if ((fd = creat(cp, 0666)) < 0) { 81 printf("\r\n%s: cannot create\r\n", argv[1]); 82 return; 83 } 84 sprintf(line, "cat %s;echo \01", argv[0]); 85 transfer(line, fd, "\01"); 86 } 87 88 static jmp_buf intbuf; 89 /* 90 * Bulk transfer routine -- 91 * used by getfl(), cu_take(), and pipefile() 92 */ 93 transfer(buf, fd, eofchars) 94 char *buf, *eofchars; 95 { 96 register int ct; 97 char c, buffer[BUFSIZ]; 98 register char *p = buffer; 99 register int cnt, eof; 100 time_t start; 101 sig_t f; 102 char r; 103 104 pwrite(FD, buf, size(buf)); 105 quit = 0; 106 kill(pid, SIGIOT); 107 read(repdes[0], (char *)&ccc, 1); /* Wait until read process stops */ 108 109 /* 110 * finish command 111 */ 112 r = '\r'; 113 pwrite(FD, &r, 1); 114 do 115 read(FD, &c, 1); 116 while ((c&0177) != '\n'); 117 ioctl(0, TIOCSETC, &defchars); 118 119 (void) setjmp(intbuf); 120 f = signal(SIGINT, intcopy); 121 start = time(0); 122 for (ct = 0; !quit;) { 123 eof = read(FD, &c, 1) <= 0; 124 c &= 0177; 125 if (quit) 126 continue; 127 if (eof || any(c, eofchars)) 128 break; 129 if (c == 0) 130 continue; /* ignore nulls */ 131 if (c == '\r') 132 continue; 133 *p++ = c; 134 135 if (c == '\n' && boolean(value(VERBOSE))) 136 printf("\r%d", ++ct); 137 if ((cnt = (p-buffer)) == number(value(FRAMESIZE))) { 138 if (write(fd, buffer, cnt) != cnt) { 139 printf("\r\nwrite error\r\n"); 140 quit = 1; 141 } 142 p = buffer; 143 } 144 } 145 if (cnt = (p-buffer)) 146 if (write(fd, buffer, cnt) != cnt) 147 printf("\r\nwrite error\r\n"); 148 149 if (boolean(value(VERBOSE))) 150 prtime(" lines transferred in ", time(0)-start); 151 ioctl(0, TIOCSETC, &tchars); 152 write(fildes[1], (char *)&ccc, 1); 153 signal(SIGINT, f); 154 close(fd); 155 } 156 157 /* 158 * FTP - remote ==> local process 159 * send remote input to local process via pipe 160 */ 161 pipefile() 162 { 163 int cpid, pdes[2]; 164 char buf[256]; 165 int status, p; 166 extern int errno; 167 168 if (prompt("Local command? ", buf)) 169 return; 170 171 if (pipe(pdes)) { 172 printf("can't establish pipe\r\n"); 173 return; 174 } 175 176 if ((cpid = fork()) < 0) { 177 printf("can't fork!\r\n"); 178 return; 179 } else if (cpid) { 180 if (prompt("List command for remote system? ", buf)) { 181 close(pdes[0]), close(pdes[1]); 182 kill (cpid, SIGKILL); 183 } else { 184 close(pdes[0]); 185 signal(SIGPIPE, intcopy); 186 transfer(buf, pdes[1], value(EOFREAD)); 187 signal(SIGPIPE, SIG_DFL); 188 while ((p = wait(&status)) > 0 && p != cpid) 189 ; 190 } 191 } else { 192 register int f; 193 194 dup2(pdes[0], 0); 195 close(pdes[0]); 196 for (f = 3; f < 20; f++) 197 close(f); 198 execute(buf); 199 printf("can't execl!\r\n"); 200 exit(0); 201 } 202 } 203 204 /* 205 * Interrupt service routine for FTP 206 */ 207 void 208 stopsnd() 209 { 210 211 stop = 1; 212 signal(SIGINT, SIG_IGN); 213 } 214 215 /* 216 * FTP - local ==> remote 217 * send local file to remote host 218 * terminate transmission with pseudo EOF sequence 219 */ 220 sendfile(cc) 221 char cc; 222 { 223 FILE *fd; 224 char *fnamex; 225 char *expand(); 226 227 putchar(cc); 228 /* 229 * get file name 230 */ 231 if (prompt("Local file name? ", fname)) 232 return; 233 234 /* 235 * look up file 236 */ 237 fnamex = expand(fname); 238 if ((fd = fopen(fnamex, "r")) == NULL) { 239 printf("%s: cannot open\r\n", fname); 240 return; 241 } 242 transmit(fd, value(EOFWRITE), NULL); 243 if (!boolean(value(ECHOCHECK))) { 244 struct sgttyb buf; 245 246 ioctl(FD, TIOCGETP, &buf); /* this does a */ 247 ioctl(FD, TIOCSETP, &buf); /* wflushtty */ 248 } 249 } 250 251 /* 252 * Bulk transfer routine to remote host -- 253 * used by sendfile() and cu_put() 254 */ 255 transmit(fd, eofchars, command) 256 FILE *fd; 257 char *eofchars, *command; 258 { 259 char *pc, lastc; 260 int c, ccount, lcount; 261 time_t start_t, stop_t; 262 sig_t f; 263 264 kill(pid, SIGIOT); /* put TIPOUT into a wait state */ 265 stop = 0; 266 f = signal(SIGINT, stopsnd); 267 ioctl(0, TIOCSETC, &defchars); 268 read(repdes[0], (char *)&ccc, 1); 269 if (command != NULL) { 270 for (pc = command; *pc; pc++) 271 send(*pc); 272 if (boolean(value(ECHOCHECK))) 273 read(FD, (char *)&c, 1); /* trailing \n */ 274 else { 275 struct sgttyb buf; 276 277 ioctl(FD, TIOCGETP, &buf); /* this does a */ 278 ioctl(FD, TIOCSETP, &buf); /* wflushtty */ 279 sleep(5); /* wait for remote stty to take effect */ 280 } 281 } 282 lcount = 0; 283 lastc = '\0'; 284 start_t = time(0); 285 while (1) { 286 ccount = 0; 287 do { 288 c = getc(fd); 289 if (stop) 290 goto out; 291 if (c == EOF) 292 goto out; 293 if (c == 0177 && !boolean(value(RAWFTP))) 294 continue; 295 lastc = c; 296 if (c < 040) { 297 if (c == '\n') { 298 if (!boolean(value(RAWFTP))) 299 c = '\r'; 300 } 301 else if (c == '\t') { 302 if (!boolean(value(RAWFTP))) { 303 if (boolean(value(TABEXPAND))) { 304 send(' '); 305 while ((++ccount % 8) != 0) 306 send(' '); 307 continue; 308 } 309 } 310 } else 311 if (!boolean(value(RAWFTP))) 312 continue; 313 } 314 send(c); 315 } while (c != '\r' && !boolean(value(RAWFTP))); 316 if (boolean(value(VERBOSE))) 317 printf("\r%d", ++lcount); 318 if (boolean(value(ECHOCHECK))) { 319 timedout = 0; 320 alarm((int)value(ETIMEOUT)); 321 do { /* wait for prompt */ 322 read(FD, (char *)&c, 1); 323 if (timedout || stop) { 324 if (timedout) 325 printf("\r\ntimed out at eol\r\n"); 326 alarm(0); 327 goto out; 328 } 329 } while ((c&0177) != character(value(PROMPT))); 330 alarm(0); 331 } 332 } 333 out: 334 if (lastc != '\n' && !boolean(value(RAWFTP))) 335 send('\r'); 336 for (pc = eofchars; *pc; pc++) 337 send(*pc); 338 stop_t = time(0); 339 fclose(fd); 340 signal(SIGINT, f); 341 if (boolean(value(VERBOSE))) 342 if (boolean(value(RAWFTP))) 343 prtime(" chars transferred in ", stop_t-start_t); 344 else 345 prtime(" lines transferred in ", stop_t-start_t); 346 write(fildes[1], (char *)&ccc, 1); 347 ioctl(0, TIOCSETC, &tchars); 348 } 349 350 /* 351 * Cu-like put command 352 */ 353 cu_put(cc) 354 char cc; 355 { 356 FILE *fd; 357 char line[BUFSIZ]; 358 int argc; 359 char *expand(); 360 char *copynamex; 361 362 if (prompt("[put] ", copyname)) 363 return; 364 if ((argc = args(copyname, argv)) < 1 || argc > 2) { 365 printf("usage: <put> from [to]\r\n"); 366 return; 367 } 368 if (argc == 1) 369 argv[1] = argv[0]; 370 copynamex = expand(argv[0]); 371 if ((fd = fopen(copynamex, "r")) == NULL) { 372 printf("%s: cannot open\r\n", copynamex); 373 return; 374 } 375 if (boolean(value(ECHOCHECK))) 376 sprintf(line, "cat>%s\r", argv[1]); 377 else 378 sprintf(line, "stty -echo;cat>%s;stty echo\r", argv[1]); 379 transmit(fd, "\04", line); 380 } 381 382 /* 383 * FTP - send single character 384 * wait for echo & handle timeout 385 */ 386 send(c) 387 char c; 388 { 389 char cc; 390 int retry = 0; 391 392 cc = c; 393 pwrite(FD, &cc, 1); 394 #ifdef notdef 395 if (number(value(CDELAY)) > 0 && c != '\r') 396 nap(number(value(CDELAY))); 397 #endif 398 if (!boolean(value(ECHOCHECK))) { 399 #ifdef notdef 400 if (number(value(LDELAY)) > 0 && c == '\r') 401 nap(number(value(LDELAY))); 402 #endif 403 return; 404 } 405 tryagain: 406 timedout = 0; 407 alarm((int)value(ETIMEOUT)); 408 read(FD, &cc, 1); 409 alarm(0); 410 if (timedout) { 411 printf("\r\ntimeout error (%s)\r\n", ctrl(c)); 412 if (retry++ > 3) 413 return; 414 pwrite(FD, &null, 1); /* poke it */ 415 goto tryagain; 416 } 417 } 418 419 void 420 timeout() 421 { 422 signal(SIGALRM, timeout); 423 timedout = 1; 424 } 425 426 /* 427 * Stolen from consh() -- puts a remote file on the output of a local command. 428 * Identical to consh() except for where stdout goes. 429 */ 430 pipeout(c) 431 { 432 char buf[256]; 433 int cpid, status, p; 434 time_t start; 435 436 putchar(c); 437 if (prompt("Local command? ", buf)) 438 return; 439 kill(pid, SIGIOT); /* put TIPOUT into a wait state */ 440 signal(SIGINT, SIG_IGN); 441 signal(SIGQUIT, SIG_IGN); 442 ioctl(0, TIOCSETC, &defchars); 443 read(repdes[0], (char *)&ccc, 1); 444 /* 445 * Set up file descriptors in the child and 446 * let it go... 447 */ 448 if ((cpid = fork()) < 0) 449 printf("can't fork!\r\n"); 450 else if (cpid) { 451 start = time(0); 452 while ((p = wait(&status)) > 0 && p != cpid) 453 ; 454 } else { 455 register int i; 456 457 dup2(FD, 1); 458 for (i = 3; i < 20; i++) 459 close(i); 460 signal(SIGINT, SIG_DFL); 461 signal(SIGQUIT, SIG_DFL); 462 execute(buf); 463 printf("can't find `%s'\r\n", buf); 464 exit(0); 465 } 466 if (boolean(value(VERBOSE))) 467 prtime("away for ", time(0)-start); 468 write(fildes[1], (char *)&ccc, 1); 469 ioctl(0, TIOCSETC, &tchars); 470 signal(SIGINT, SIG_DFL); 471 signal(SIGQUIT, SIG_DFL); 472 } 473 474 #ifdef CONNECT 475 /* 476 * Fork a program with: 477 * 0 <-> remote tty in 478 * 1 <-> remote tty out 479 * 2 <-> local tty out 480 */ 481 consh(c) 482 { 483 char buf[256]; 484 int cpid, status, p; 485 time_t start; 486 487 putchar(c); 488 if (prompt("Local command? ", buf)) 489 return; 490 kill(pid, SIGIOT); /* put TIPOUT into a wait state */ 491 signal(SIGINT, SIG_IGN); 492 signal(SIGQUIT, SIG_IGN); 493 ioctl(0, TIOCSETC, &defchars); 494 read(repdes[0], (char *)&ccc, 1); 495 /* 496 * Set up file descriptors in the child and 497 * let it go... 498 */ 499 if ((cpid = fork()) < 0) 500 printf("can't fork!\r\n"); 501 else if (cpid) { 502 start = time(0); 503 while ((p = wait(&status)) > 0 && p != cpid) 504 ; 505 } else { 506 register int i; 507 508 dup2(FD, 0); 509 dup2(3, 1); 510 for (i = 3; i < 20; i++) 511 close(i); 512 signal(SIGINT, SIG_DFL); 513 signal(SIGQUIT, SIG_DFL); 514 execute(buf); 515 printf("can't find `%s'\r\n", buf); 516 exit(0); 517 } 518 if (boolean(value(VERBOSE))) 519 prtime("away for ", time(0)-start); 520 write(fildes[1], (char *)&ccc, 1); 521 ioctl(0, TIOCSETC, &tchars); 522 signal(SIGINT, SIG_DFL); 523 signal(SIGQUIT, SIG_DFL); 524 } 525 #endif 526 527 /* 528 * Escape to local shell 529 */ 530 shell() 531 { 532 int shpid, status; 533 extern char **environ; 534 char *cp; 535 536 printf("[sh]\r\n"); 537 signal(SIGINT, SIG_IGN); 538 signal(SIGQUIT, SIG_IGN); 539 unraw(); 540 if (shpid = fork()) { 541 while (shpid != wait(&status)); 542 raw(); 543 printf("\r\n!\r\n"); 544 signal(SIGINT, SIG_DFL); 545 signal(SIGQUIT, SIG_DFL); 546 return; 547 } else { 548 signal(SIGQUIT, SIG_DFL); 549 signal(SIGINT, SIG_DFL); 550 if ((cp = rindex(value(SHELL), '/')) == NULL) 551 cp = value(SHELL); 552 else 553 cp++; 554 shell_uid(); 555 execl(value(SHELL), cp, 0); 556 printf("\r\ncan't execl!\r\n"); 557 exit(1); 558 } 559 } 560 561 /* 562 * TIPIN portion of scripting 563 * initiate the conversation with TIPOUT 564 */ 565 setscript() 566 { 567 char c; 568 /* 569 * enable TIPOUT side for dialogue 570 */ 571 kill(pid, SIGEMT); 572 if (boolean(value(SCRIPT))) 573 write(fildes[1], value(RECORD), size(value(RECORD))); 574 write(fildes[1], "\n", 1); 575 /* 576 * wait for TIPOUT to finish 577 */ 578 read(repdes[0], &c, 1); 579 if (c == 'n') 580 printf("can't create %s\r\n", value(RECORD)); 581 } 582 583 /* 584 * Change current working directory of 585 * local portion of tip 586 */ 587 chdirectory() 588 { 589 char dirname[80]; 590 register char *cp = dirname; 591 592 if (prompt("[cd] ", dirname)) { 593 if (stoprompt) 594 return; 595 cp = value(HOME); 596 } 597 if (chdir(cp) < 0) 598 printf("%s: bad directory\r\n", cp); 599 printf("!\r\n"); 600 } 601 602 tipabort(msg) 603 char *msg; 604 { 605 606 kill(pid, SIGTERM); 607 disconnect(msg); 608 if (msg != NOSTR) 609 printf("\r\n%s", msg); 610 printf("\r\n[EOT]\r\n"); 611 daemon_uid(); 612 (void)uu_unlock(uucplock); 613 unraw(); 614 exit(0); 615 } 616 617 finish() 618 { 619 char *dismsg; 620 621 if ((dismsg = value(DISCONNECT)) != NOSTR) { 622 write(FD, dismsg, strlen(dismsg)); 623 sleep(5); 624 } 625 tipabort(NOSTR); 626 } 627 628 void 629 intcopy() 630 { 631 raw(); 632 quit = 1; 633 longjmp(intbuf, 1); 634 } 635 636 execute(s) 637 char *s; 638 { 639 register char *cp; 640 641 if ((cp = rindex(value(SHELL), '/')) == NULL) 642 cp = value(SHELL); 643 else 644 cp++; 645 shell_uid(); 646 execl(value(SHELL), cp, "-c", s, 0); 647 } 648 649 args(buf, a) 650 char *buf, *a[]; 651 { 652 register char *p = buf, *start; 653 register char **parg = a; 654 register int n = 0; 655 656 do { 657 while (*p && (*p == ' ' || *p == '\t')) 658 p++; 659 start = p; 660 if (*p) 661 *parg = p; 662 while (*p && (*p != ' ' && *p != '\t')) 663 p++; 664 if (p != start) 665 parg++, n++; 666 if (*p) 667 *p++ = '\0'; 668 } while (*p); 669 670 return(n); 671 } 672 673 prtime(s, a) 674 char *s; 675 time_t a; 676 { 677 register i; 678 int nums[3]; 679 680 for (i = 0; i < 3; i++) { 681 nums[i] = (int)(a % quant[i]); 682 a /= quant[i]; 683 } 684 printf("%s", s); 685 while (--i >= 0) 686 if (nums[i] || i == 0 && nums[1] == 0 && nums[2] == 0) 687 printf("%d %s%c ", nums[i], sep[i], 688 nums[i] == 1 ? '\0' : 's'); 689 printf("\r\n!\r\n"); 690 } 691 692 variable() 693 { 694 char buf[256]; 695 696 if (prompt("[set] ", buf)) 697 return; 698 vlex(buf); 699 if (vtable[BEAUTIFY].v_access&CHANGED) { 700 vtable[BEAUTIFY].v_access &= ~CHANGED; 701 kill(pid, SIGSYS); 702 } 703 if (vtable[SCRIPT].v_access&CHANGED) { 704 vtable[SCRIPT].v_access &= ~CHANGED; 705 setscript(); 706 /* 707 * So that "set record=blah script" doesn't 708 * cause two transactions to occur. 709 */ 710 if (vtable[RECORD].v_access&CHANGED) 711 vtable[RECORD].v_access &= ~CHANGED; 712 } 713 if (vtable[RECORD].v_access&CHANGED) { 714 vtable[RECORD].v_access &= ~CHANGED; 715 if (boolean(value(SCRIPT))) 716 setscript(); 717 } 718 if (vtable[TAND].v_access&CHANGED) { 719 vtable[TAND].v_access &= ~CHANGED; 720 if (boolean(value(TAND))) 721 tandem("on"); 722 else 723 tandem("off"); 724 } 725 if (vtable[LECHO].v_access&CHANGED) { 726 vtable[LECHO].v_access &= ~CHANGED; 727 HD = boolean(value(LECHO)); 728 } 729 if (vtable[PARITY].v_access&CHANGED) { 730 vtable[PARITY].v_access &= ~CHANGED; 731 setparity(); 732 } 733 } 734 735 /* 736 * Turn tandem mode on or off for remote tty. 737 */ 738 tandem(option) 739 char *option; 740 { 741 struct sgttyb rmtty; 742 743 ioctl(FD, TIOCGETP, &rmtty); 744 if (strcmp(option,"on") == 0) { 745 rmtty.sg_flags |= TANDEM; 746 arg.sg_flags |= TANDEM; 747 } else { 748 rmtty.sg_flags &= ~TANDEM; 749 arg.sg_flags &= ~TANDEM; 750 } 751 ioctl(FD, TIOCSETP, &rmtty); 752 ioctl(0, TIOCSETP, &arg); 753 } 754 755 /* 756 * Send a break. 757 */ 758 genbrk() 759 { 760 761 ioctl(FD, TIOCSBRK, NULL); 762 sleep(1); 763 ioctl(FD, TIOCCBRK, NULL); 764 } 765 766 /* 767 * Suspend tip 768 */ 769 suspend(c) 770 char c; 771 { 772 773 unraw(); 774 kill(c == CTRL('y') ? getpid() : 0, SIGTSTP); 775 raw(); 776 } 777 778 /* 779 * expand a file name if it includes shell meta characters 780 */ 781 782 char * 783 expand(name) 784 char name[]; 785 { 786 static char xname[BUFSIZ]; 787 char cmdbuf[BUFSIZ]; 788 register int pid, l, rc; 789 register char *cp, *Shell; 790 int s, pivec[2], (*sigint)(); 791 792 if (!anyof(name, "~{[*?$`'\"\\")) 793 return(name); 794 /* sigint = signal(SIGINT, SIG_IGN); */ 795 if (pipe(pivec) < 0) { 796 perror("pipe"); 797 /* signal(SIGINT, sigint) */ 798 return(name); 799 } 800 sprintf(cmdbuf, "echo %s", name); 801 if ((pid = vfork()) == 0) { 802 Shell = value(SHELL); 803 if (Shell == NOSTR) 804 Shell = _PATH_BSHELL; 805 close(pivec[0]); 806 close(1); 807 dup(pivec[1]); 808 close(pivec[1]); 809 close(2); 810 shell_uid(); 811 execl(Shell, Shell, "-c", cmdbuf, 0); 812 _exit(1); 813 } 814 if (pid == -1) { 815 perror("fork"); 816 close(pivec[0]); 817 close(pivec[1]); 818 return(NOSTR); 819 } 820 close(pivec[1]); 821 l = read(pivec[0], xname, BUFSIZ); 822 close(pivec[0]); 823 while (wait(&s) != pid); 824 ; 825 s &= 0377; 826 if (s != 0 && s != SIGPIPE) { 827 fprintf(stderr, "\"Echo\" failed\n"); 828 return(NOSTR); 829 } 830 if (l < 0) { 831 perror("read"); 832 return(NOSTR); 833 } 834 if (l == 0) { 835 fprintf(stderr, "\"%s\": No match\n", name); 836 return(NOSTR); 837 } 838 if (l == BUFSIZ) { 839 fprintf(stderr, "Buffer overflow expanding \"%s\"\n", name); 840 return(NOSTR); 841 } 842 xname[l] = 0; 843 for (cp = &xname[l-1]; *cp == '\n' && cp > xname; cp--) 844 ; 845 *++cp = '\0'; 846 return(xname); 847 } 848 849 /* 850 * Are any of the characters in the two strings the same? 851 */ 852 853 anyof(s1, s2) 854 register char *s1, *s2; 855 { 856 register int c; 857 858 while (c = *s1++) 859 if (any(c, s2)) 860 return(1); 861 return(0); 862 } 863