1 /* 2 * Copyright (c) 1983 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 static char sccsid[] = "@(#)cmds.c 5.16 (Berkeley) 07/31/91"; 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 <-> local tty in 478 * 1 <-> local tty out 479 * 2 <-> local tty out 480 * 3 <-> remote tty in 481 * 4 <-> remote tty out 482 */ 483 consh(c) 484 { 485 char buf[256]; 486 int cpid, status, p; 487 time_t start; 488 489 putchar(c); 490 if (prompt("Local command? ", buf)) 491 return; 492 kill(pid, SIGIOT); /* put TIPOUT into a wait state */ 493 signal(SIGINT, SIG_IGN); 494 signal(SIGQUIT, SIG_IGN); 495 ioctl(0, TIOCSETC, &defchars); 496 read(repdes[0], (char *)&ccc, 1); 497 /* 498 * Set up file descriptors in the child and 499 * let it go... 500 */ 501 if ((cpid = fork()) < 0) 502 printf("can't fork!\r\n"); 503 else if (cpid) { 504 start = time(0); 505 while ((p = wait(&status)) > 0 && p != cpid) 506 ; 507 } else { 508 register int i; 509 510 dup2(FD, 3); 511 dup2(3, 4); 512 for (i = 5; i < 20; i++) 513 close(i); 514 signal(SIGINT, SIG_DFL); 515 signal(SIGQUIT, SIG_DFL); 516 execute(buf); 517 printf("can't find `%s'\r\n", buf); 518 exit(0); 519 } 520 if (boolean(value(VERBOSE))) 521 prtime("away for ", time(0)-start); 522 write(fildes[1], (char *)&ccc, 1); 523 ioctl(0, TIOCSETC, &tchars); 524 signal(SIGINT, SIG_DFL); 525 signal(SIGQUIT, SIG_DFL); 526 } 527 #endif 528 529 /* 530 * Escape to local shell 531 */ 532 shell() 533 { 534 int shpid, status; 535 extern char **environ; 536 char *cp; 537 538 printf("[sh]\r\n"); 539 signal(SIGINT, SIG_IGN); 540 signal(SIGQUIT, SIG_IGN); 541 unraw(); 542 if (shpid = fork()) { 543 while (shpid != wait(&status)); 544 raw(); 545 printf("\r\n!\r\n"); 546 signal(SIGINT, SIG_DFL); 547 signal(SIGQUIT, SIG_DFL); 548 return; 549 } else { 550 signal(SIGQUIT, SIG_DFL); 551 signal(SIGINT, SIG_DFL); 552 if ((cp = rindex(value(SHELL), '/')) == NULL) 553 cp = value(SHELL); 554 else 555 cp++; 556 shell_uid(); 557 execl(value(SHELL), cp, 0); 558 printf("\r\ncan't execl!\r\n"); 559 exit(1); 560 } 561 } 562 563 /* 564 * TIPIN portion of scripting 565 * initiate the conversation with TIPOUT 566 */ 567 setscript() 568 { 569 char c; 570 /* 571 * enable TIPOUT side for dialogue 572 */ 573 kill(pid, SIGEMT); 574 if (boolean(value(SCRIPT))) 575 write(fildes[1], value(RECORD), size(value(RECORD))); 576 write(fildes[1], "\n", 1); 577 /* 578 * wait for TIPOUT to finish 579 */ 580 read(repdes[0], &c, 1); 581 if (c == 'n') 582 printf("can't create %s\r\n", value(RECORD)); 583 } 584 585 /* 586 * Change current working directory of 587 * local portion of tip 588 */ 589 chdirectory() 590 { 591 char dirname[80]; 592 register char *cp = dirname; 593 594 if (prompt("[cd] ", dirname)) { 595 if (stoprompt) 596 return; 597 cp = value(HOME); 598 } 599 if (chdir(cp) < 0) 600 printf("%s: bad directory\r\n", cp); 601 printf("!\r\n"); 602 } 603 604 tipabort(msg) 605 char *msg; 606 { 607 608 kill(pid, SIGTERM); 609 disconnect(msg); 610 if (msg != NOSTR) 611 printf("\r\n%s", msg); 612 printf("\r\n[EOT]\r\n"); 613 daemon_uid(); 614 (void)uu_unlock(uucplock); 615 unraw(); 616 exit(0); 617 } 618 619 finish() 620 { 621 char *dismsg; 622 623 if ((dismsg = value(DISCONNECT)) != NOSTR) { 624 write(FD, dismsg, strlen(dismsg)); 625 sleep(5); 626 } 627 tipabort(NOSTR); 628 } 629 630 void 631 intcopy() 632 { 633 raw(); 634 quit = 1; 635 longjmp(intbuf, 1); 636 } 637 638 execute(s) 639 char *s; 640 { 641 register char *cp; 642 643 if ((cp = rindex(value(SHELL), '/')) == NULL) 644 cp = value(SHELL); 645 else 646 cp++; 647 shell_uid(); 648 execl(value(SHELL), cp, "-c", s, 0); 649 } 650 651 args(buf, a) 652 char *buf, *a[]; 653 { 654 register char *p = buf, *start; 655 register char **parg = a; 656 register int n = 0; 657 658 do { 659 while (*p && (*p == ' ' || *p == '\t')) 660 p++; 661 start = p; 662 if (*p) 663 *parg = p; 664 while (*p && (*p != ' ' && *p != '\t')) 665 p++; 666 if (p != start) 667 parg++, n++; 668 if (*p) 669 *p++ = '\0'; 670 } while (*p); 671 672 return(n); 673 } 674 675 prtime(s, a) 676 char *s; 677 time_t a; 678 { 679 register i; 680 int nums[3]; 681 682 for (i = 0; i < 3; i++) { 683 nums[i] = (int)(a % quant[i]); 684 a /= quant[i]; 685 } 686 printf("%s", s); 687 while (--i >= 0) 688 if (nums[i] || i == 0 && nums[1] == 0 && nums[2] == 0) 689 printf("%d %s%c ", nums[i], sep[i], 690 nums[i] == 1 ? '\0' : 's'); 691 printf("\r\n!\r\n"); 692 } 693 694 variable() 695 { 696 char buf[256]; 697 698 if (prompt("[set] ", buf)) 699 return; 700 vlex(buf); 701 if (vtable[BEAUTIFY].v_access&CHANGED) { 702 vtable[BEAUTIFY].v_access &= ~CHANGED; 703 kill(pid, SIGSYS); 704 } 705 if (vtable[SCRIPT].v_access&CHANGED) { 706 vtable[SCRIPT].v_access &= ~CHANGED; 707 setscript(); 708 /* 709 * So that "set record=blah script" doesn't 710 * cause two transactions to occur. 711 */ 712 if (vtable[RECORD].v_access&CHANGED) 713 vtable[RECORD].v_access &= ~CHANGED; 714 } 715 if (vtable[RECORD].v_access&CHANGED) { 716 vtable[RECORD].v_access &= ~CHANGED; 717 if (boolean(value(SCRIPT))) 718 setscript(); 719 } 720 if (vtable[TAND].v_access&CHANGED) { 721 vtable[TAND].v_access &= ~CHANGED; 722 if (boolean(value(TAND))) 723 tandem("on"); 724 else 725 tandem("off"); 726 } 727 if (vtable[LECHO].v_access&CHANGED) { 728 vtable[LECHO].v_access &= ~CHANGED; 729 HD = boolean(value(LECHO)); 730 } 731 if (vtable[PARITY].v_access&CHANGED) { 732 vtable[PARITY].v_access &= ~CHANGED; 733 setparity(); 734 } 735 } 736 737 /* 738 * Turn tandem mode on or off for remote tty. 739 */ 740 tandem(option) 741 char *option; 742 { 743 struct sgttyb rmtty; 744 745 ioctl(FD, TIOCGETP, &rmtty); 746 if (strcmp(option,"on") == 0) { 747 rmtty.sg_flags |= TANDEM; 748 arg.sg_flags |= TANDEM; 749 } else { 750 rmtty.sg_flags &= ~TANDEM; 751 arg.sg_flags &= ~TANDEM; 752 } 753 ioctl(FD, TIOCSETP, &rmtty); 754 ioctl(0, TIOCSETP, &arg); 755 } 756 757 /* 758 * Send a break. 759 */ 760 genbrk() 761 { 762 763 ioctl(FD, TIOCSBRK, NULL); 764 sleep(1); 765 ioctl(FD, TIOCCBRK, NULL); 766 } 767 768 /* 769 * Suspend tip 770 */ 771 suspend(c) 772 char c; 773 { 774 775 unraw(); 776 kill(c == CTRL('y') ? getpid() : 0, SIGTSTP); 777 raw(); 778 } 779 780 /* 781 * expand a file name if it includes shell meta characters 782 */ 783 784 char * 785 expand(name) 786 char name[]; 787 { 788 static char xname[BUFSIZ]; 789 char cmdbuf[BUFSIZ]; 790 register int pid, l, rc; 791 register char *cp, *Shell; 792 int s, pivec[2], (*sigint)(); 793 794 if (!anyof(name, "~{[*?$`'\"\\")) 795 return(name); 796 /* sigint = signal(SIGINT, SIG_IGN); */ 797 if (pipe(pivec) < 0) { 798 perror("pipe"); 799 /* signal(SIGINT, sigint) */ 800 return(name); 801 } 802 sprintf(cmdbuf, "echo %s", name); 803 if ((pid = vfork()) == 0) { 804 Shell = value(SHELL); 805 if (Shell == NOSTR) 806 Shell = _PATH_BSHELL; 807 close(pivec[0]); 808 close(1); 809 dup(pivec[1]); 810 close(pivec[1]); 811 close(2); 812 shell_uid(); 813 execl(Shell, Shell, "-c", cmdbuf, 0); 814 _exit(1); 815 } 816 if (pid == -1) { 817 perror("fork"); 818 close(pivec[0]); 819 close(pivec[1]); 820 return(NOSTR); 821 } 822 close(pivec[1]); 823 l = read(pivec[0], xname, BUFSIZ); 824 close(pivec[0]); 825 while (wait(&s) != pid); 826 ; 827 s &= 0377; 828 if (s != 0 && s != SIGPIPE) { 829 fprintf(stderr, "\"Echo\" failed\n"); 830 return(NOSTR); 831 } 832 if (l < 0) { 833 perror("read"); 834 return(NOSTR); 835 } 836 if (l == 0) { 837 fprintf(stderr, "\"%s\": No match\n", name); 838 return(NOSTR); 839 } 840 if (l == BUFSIZ) { 841 fprintf(stderr, "Buffer overflow expanding \"%s\"\n", name); 842 return(NOSTR); 843 } 844 xname[l] = 0; 845 for (cp = &xname[l-1]; *cp == '\n' && cp > xname; cp--) 846 ; 847 *++cp = '\0'; 848 return(xname); 849 } 850 851 /* 852 * Are any of the characters in the two strings the same? 853 */ 854 855 anyof(s1, s2) 856 register char *s1, *s2; 857 { 858 register int c; 859 860 while (c = *s1++) 861 if (any(c, s2)) 862 return(1); 863 return(0); 864 } 865