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