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.4 (Berkeley) 5/5/86"; 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 *copynamex; 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: copynamex = expand(argv[0]); 366: if ((fd = fopen(copynamex, "r")) == NULL) { 367: printf("%s: cannot open\r\n", copynamex); 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: execl(value(SHELL), cp, 0); 551: printf("\r\ncan't execl!\r\n"); 552: exit(1); 553: } 554: } 555: 556: /* 557: * TIPIN portion of scripting 558: * initiate the conversation with TIPOUT 559: */ 560: setscript() 561: { 562: char c; 563: /* 564: * enable TIPOUT side for dialogue 565: */ 566: kill(pid, SIGEMT); 567: if (boolean(value(SCRIPT))) 568: write(fildes[1], value(RECORD), size(value(RECORD))); 569: write(fildes[1], "\n", 1); 570: /* 571: * wait for TIPOUT to finish 572: */ 573: read(repdes[0], &c, 1); 574: if (c == 'n') 575: printf("can't create %s\r\n", value(RECORD)); 576: } 577: 578: /* 579: * Change current working directory of 580: * local portion of tip 581: */ 582: chdirectory() 583: { 584: char dirname[80]; 585: register char *cp = dirname; 586: 587: if (prompt("[cd] ", dirname)) { 588: if (stoprompt) 589: return; 590: cp = value(HOME); 591: } 592: if (chdir(cp) < 0) 593: printf("%s: bad directory\r\n", cp); 594: printf("!\r\n"); 595: } 596: 597: abort(msg) 598: char *msg; 599: { 600: 601: kill(pid, SIGTERM); 602: setreuid(euid, euid); 603: setregid(egid, egid); 604: disconnect(msg); 605: if (msg != NOSTR) 606: printf("\r\n%s", msg); 607: printf("\r\n[EOT]\r\n"); 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: execl(value(SHELL), cp, "-c", s, 0); 642: } 643: 644: args(buf, a) 645: char *buf, *a[]; 646: { 647: register char *p = buf, *start; 648: register char **parg = a; 649: register int n = 0; 650: 651: do { 652: while (*p && (*p == ' ' || *p == '\t')) 653: p++; 654: start = p; 655: if (*p) 656: *parg = p; 657: while (*p && (*p != ' ' && *p != '\t')) 658: p++; 659: if (p != start) 660: parg++, n++; 661: if (*p) 662: *p++ = '\0'; 663: } while (*p); 664: 665: return(n); 666: } 667: 668: prtime(s, a) 669: char *s; 670: time_t a; 671: { 672: register i; 673: int nums[3]; 674: 675: for (i = 0; i < 3; i++) { 676: nums[i] = (int)(a % quant[i]); 677: a /= quant[i]; 678: } 679: printf("%s", s); 680: while (--i >= 0) 681: if (nums[i] || i == 0 && nums[1] == 0 && nums[2] == 0) 682: printf("%d %s%c ", nums[i], sep[i], 683: nums[i] == 1 ? '\0' : 's'); 684: printf("\r\n!\r\n"); 685: } 686: 687: variable() 688: { 689: char buf[256]; 690: 691: if (prompt("[set] ", buf)) 692: return; 693: vlex(buf); 694: if (vtable[BEAUTIFY].v_access&CHANGED) { 695: vtable[BEAUTIFY].v_access &= ~CHANGED; 696: kill(pid, SIGSYS); 697: } 698: if (vtable[SCRIPT].v_access&CHANGED) { 699: vtable[SCRIPT].v_access &= ~CHANGED; 700: setscript(); 701: /* 702: * So that "set record=blah script" doesn't 703: * cause two transactions to occur. 704: */ 705: if (vtable[RECORD].v_access&CHANGED) 706: vtable[RECORD].v_access &= ~CHANGED; 707: } 708: if (vtable[RECORD].v_access&CHANGED) { 709: vtable[RECORD].v_access &= ~CHANGED; 710: if (boolean(value(SCRIPT))) 711: setscript(); 712: } 713: if (vtable[TAND].v_access&CHANGED) { 714: vtable[TAND].v_access &= ~CHANGED; 715: if (boolean(value(TAND))) 716: tandem("on"); 717: else 718: tandem("off"); 719: } 720: if (vtable[LECHO].v_access&CHANGED) { 721: vtable[LECHO].v_access &= ~CHANGED; 722: HD = boolean(value(LECHO)); 723: } 724: if (vtable[PARITY].v_access&CHANGED) { 725: vtable[PARITY].v_access &= ~CHANGED; 726: setparity(); 727: } 728: } 729: 730: /* 731: * Turn tandem mode on or off for remote tty. 732: */ 733: tandem(option) 734: char *option; 735: { 736: struct sgttyb rmtty; 737: 738: ioctl(FD, TIOCGETP, &rmtty); 739: if (strcmp(option,"on") == 0) { 740: rmtty.sg_flags |= TANDEM; 741: arg.sg_flags |= TANDEM; 742: } else { 743: rmtty.sg_flags &= ~TANDEM; 744: arg.sg_flags &= ~TANDEM; 745: } 746: ioctl(FD, TIOCSETP, &rmtty); 747: ioctl(0, TIOCSETP, &arg); 748: } 749: 750: /* 751: * Send a break. 752: */ 753: genbrk() 754: { 755: 756: ioctl(FD, TIOCSBRK, NULL); 757: sleep(1); 758: ioctl(FD, TIOCCBRK, NULL); 759: } 760: 761: /* 762: * Suspend tip 763: */ 764: suspend(c) 765: char c; 766: { 767: 768: unraw(); 769: kill(c == CTRL(y) ? getpid() : 0, SIGTSTP); 770: raw(); 771: } 772: 773: /* 774: * expand a file name if it includes shell meta characters 775: */ 776: 777: char * 778: expand(name) 779: char name[]; 780: { 781: static char xname[BUFSIZ]; 782: char cmdbuf[BUFSIZ]; 783: register int pid, l, rc; 784: register char *cp, *Shell; 785: int s, pivec[2], (*sigint)(); 786: 787: if (!anyof(name, "~{[*?$`'\"\\")) 788: return(name); 789: /* sigint = signal(SIGINT, SIG_IGN); */ 790: if (pipe(pivec) < 0) { 791: perror("pipe"); 792: /* signal(SIGINT, sigint) */ 793: return(name); 794: } 795: sprintf(cmdbuf, "echo %s", name); 796: if ((pid = vfork()) == 0) { 797: Shell = value(SHELL); 798: if (Shell == NOSTR) 799: Shell = "/bin/sh"; 800: close(pivec[0]); 801: close(1); 802: dup(pivec[1]); 803: close(pivec[1]); 804: close(2); 805: execl(Shell, Shell, "-c", cmdbuf, 0); 806: _exit(1); 807: } 808: if (pid == -1) { 809: perror("fork"); 810: close(pivec[0]); 811: close(pivec[1]); 812: return(NOSTR); 813: } 814: close(pivec[1]); 815: l = read(pivec[0], xname, BUFSIZ); 816: close(pivec[0]); 817: while (wait(&s) != pid); 818: ; 819: s &= 0377; 820: if (s != 0 && s != SIGPIPE) { 821: fprintf(stderr, "\"Echo\" failed\n"); 822: return(NOSTR); 823: } 824: if (l < 0) { 825: perror("read"); 826: return(NOSTR); 827: } 828: if (l == 0) { 829: fprintf(stderr, "\"%s\": No match\n", name); 830: return(NOSTR); 831: } 832: if (l == BUFSIZ) { 833: fprintf(stderr, "Buffer overflow expanding \"%s\"\n", name); 834: return(NOSTR); 835: } 836: xname[l] = 0; 837: for (cp = &xname[l-1]; *cp == '\n' && cp > xname; cp--) 838: ; 839: *++cp = '\0'; 840: return(xname); 841: } 842: 843: /* 844: * Are any of the characters in the two strings the same? 845: */ 846: 847: anyof(s1, s2) 848: register char *s1, *s2; 849: { 850: register int c; 851: 852: while (c = *s1++) 853: if (any(c, s2)) 854: return(1); 855: return(0); 856: }