1: #ifndef lint 2: static char RCSid[] = "$Header: cmds.c,v 2.0 85/11/21 07:22:41 jqj Exp $"; 3: #endif 4: /* $Log: cmds.c,v $ 5: * Revision 2.0 85/11/21 07:22:41 jqj 6: * 4.3BSD standard release 7: * 8: * Revision 1.2 85/10/30 08:06:37 root 9: * if prompt=off but verbose=on, print the name of each file during 10: * multiplefile transfers. 11: * 12: * Revision 1.1 85/05/27 06:30:51 jqj 13: * Initial revision 14: * 15: * based on Berkeley tcp/ftp 16: */ 17: /* static char sccsid[] = "@(#)cmds.c 4.9 (Berkeley) 7/26/83"; */ 18: 19: /* 20: * FTP User Program -- Command Routines. 21: */ 22: #include <sys/param.h> 23: #include <sys/stat.h> 24: #include <sys/socket.h> 25: 26: #include <signal.h> 27: #include <stdio.h> 28: #include <errno.h> 29: 30: #include "ftp_var.h" 31: 32: extern char *globerr; 33: extern char **glob(); 34: extern char *home; 35: extern short gflag; 36: extern char *remglob(); 37: extern char *getenv(); 38: extern char *index(); 39: extern char *rindex(); 40: 41: /* 42: * Connect to peer server and 43: * auto-login, if possible. 44: */ 45: setpeer(argc, argv) 46: int argc; 47: char *argv[]; 48: { 49: CourierConnection *hookup(); 50: 51: if (connected != (CourierConnection*)0) { 52: printf("Already connected to %s, use disconnect first.\n", 53: hostname); 54: return; 55: } 56: if (argc < 2) { 57: strcat(line, " "); 58: printf("(to) "); 59: gets(&line[strlen(line)]); 60: makeargv(); 61: argc = margc; 62: argv = margv; 63: } 64: if (argc > 2) { 65: printf("usage: %s fileservice-name\n", argv[0]); 66: return; 67: } 68: connected = hookup(argv[1]); 69: if (connected != (CourierConnection*)0) { 70: if (autologin) { 71: char *pwd, name[128], *getXNSpass(); 72: printf("XNS UserName: "); 73: gets(name); 74: pwd = getXNSpass("Password:"); 75: login(name,pwd); 76: } 77: } 78: } 79: 80: struct types { 81: char *t_name; 82: char *t_mode; 83: int t_type; 84: char *t_arg; 85: } types[] = { 86: { "ascii", "A", TYPE_A, 0 }, 87: { "binary", "I", TYPE_I, 0 }, 88: { "image", "I", TYPE_I, 0 }, 89: /* { "ebcdic", "E", TYPE_E, 0 }, */ 90: /* { "tenex", "L", TYPE_L, bytename }, */ 91: 0 92: }; 93: 94: /* 95: * Set transfer type. 96: */ 97: settype(argc, argv) 98: char *argv[]; 99: { 100: register struct types *p; 101: int comret; 102: 103: if (argc > 2) { 104: char *sep; 105: 106: printf("usage: %s [", argv[0]); 107: sep = " "; 108: for (p = types; p->t_name; p++) { 109: printf("%s%s", sep, p->t_name); 110: if (*sep == ' ') 111: sep = " | "; 112: } 113: printf(" ]\n"); 114: return; 115: } 116: if (argc < 2) { 117: printf("Using %s mode to transfer files.\n", typename); 118: return; 119: } 120: for (p = types; p->t_name; p++) 121: if (strcmp(argv[1], p->t_name) == 0) 122: break; 123: if (p->t_name == 0) { 124: printf("%s: unknown mode\n", argv[1]); 125: return; 126: } 127: strcpy(typename, p->t_name); 128: typevalue = p->t_type; 129: } 130: 131: /* 132: * Set binary transfer type. 133: */ 134: /*VARARGS*/ 135: setbinary() 136: { 137: 138: call(settype, "type", "binary", 0); 139: } 140: 141: /* 142: * Set ascii transfer type. 143: */ 144: /*VARARGS*/ 145: setascii() 146: { 147: 148: call(settype, "type", "ascii", 0); 149: } 150: 151: /* 152: * Set tenex transfer type. 153: */ 154: /*VARARGS*/ 155: settenex() 156: { 157: 158: call(settype, "type", "tenex", 0); 159: } 160: 161: /* 162: * Set ebcdic transfer type. 163: */ 164: /*VARARGS*/ 165: setebcdic() 166: { 167: 168: call(settype, "type", "ebcdic", 0); 169: } 170: 171: /* 172: * Set file transfer mode. 173: */ 174: setmode(argc, argv) 175: char *argv[]; 176: { 177: 178: printf("We only support %s mode, sorry.\n", modename); 179: } 180: 181: /* 182: * Set file transfer format. 183: */ 184: setform(argc, argv) 185: char *argv[]; 186: { 187: 188: printf("We only support %s format, sorry.\n", formname); 189: } 190: 191: /* 192: * Set file transfer structure. 193: */ 194: setstruct(argc, argv) 195: char *argv[]; 196: { 197: 198: printf("We only support %s structure, sorry.\n", structname); 199: } 200: 201: put(argc, argv) 202: int argc; 203: char *argv[]; 204: { 205: char *cmd; 206: 207: if (argc == 2) 208: argc++, argv[2] = argv[1]; 209: if (argc < 2) { 210: strcat(line, " "); 211: printf("(local-file) "); 212: gets(&line[strlen(line)]); 213: makeargv(); 214: argc = margc; 215: argv = margv; 216: } 217: if (argc < 2) { 218: usage: 219: printf("%s local-file remote-file\n", argv[0]); 220: return; 221: } 222: if (argc < 3) { 223: strcat(line, " "); 224: printf("(remote-file) "); 225: gets(&line[strlen(line)]); 226: makeargv(); 227: argc = margc; 228: argv = margv; 229: } 230: if (argc < 3) 231: goto usage; 232: if (!globulize(&argv[1])) 233: return; 234: cmd = (argv[0][0] == 'a') ? "APPE" : "STOR"; 235: sendrequest(cmd, argv[1], argv[2]); 236: 237: } 238: 239: /* 240: * Send multiple files. 241: */ 242: mput(argc, argv) 243: char *argv[]; 244: { 245: register int i; 246: 247: if (argc < 2) { 248: strcat(line, " "); 249: printf("(local-files) "); 250: gets(&line[strlen(line)]); 251: makeargv(); 252: argc = margc; 253: argv = margv; 254: } 255: if (argc < 2) { 256: printf("%s local-files\n", argv[0]); 257: return; 258: } 259: for (i = 1; i < argc; i++) { 260: register char **cpp, **gargs; 261: 262: if (!doglob) { 263: if (confirm(argv[0], argv[i])) 264: sendrequest("STOR", argv[i], argv[i]); 265: continue; 266: } 267: gargs = glob(argv[i]); 268: if (globerr != NULL) { 269: printf("%s\n", globerr); 270: if (gargs) 271: blkfree(gargs); 272: continue; 273: } 274: for (cpp = gargs; cpp && *cpp != NULL; cpp++) 275: if (confirm(argv[0], *cpp)) 276: sendrequest("STOR", *cpp, *cpp); 277: if (gargs != NULL) 278: blkfree(gargs); 279: } 280: } 281: 282: /* 283: * Receive one file. 284: */ 285: get(argc, argv) 286: char *argv[]; 287: { 288: 289: if (argc == 2) 290: argc++, argv[2] = argv[1]; 291: if (argc < 2) { 292: strcat(line, " "); 293: printf("(remote-file) "); 294: gets(&line[strlen(line)]); 295: makeargv(); 296: argc = margc; 297: argv = margv; 298: } 299: if (argc < 2) { 300: usage: 301: printf("%s remote-file [ local-file ]\n", argv[0]); 302: return; 303: } 304: if (argc < 3) { 305: strcat(line, " "); 306: printf("(local-file) "); 307: gets(&line[strlen(line)]); 308: makeargv(); 309: argc = margc; 310: argv = margv; 311: } 312: if (argc < 3) 313: goto usage; 314: if (!globulize(&argv[2])) 315: return; 316: recvrequest("RETR", argv[2], argv[1], "w"); 317: } 318: /* 319: * given a remote file name, strip directory path and version number 320: */ 321: char * 322: getlocalname(cp) 323: char *cp; 324: { 325: char *result; 326: static char buf[MAXPATHLEN]; 327: 328: result = rindex(cp,'/'); /* find last component */ 329: if (result == NULL) result = cp; 330: strcpy(buf, result); 331: result = index(buf,'!'); /* strip version # if any */ 332: if (result != NULL && result != buf) *result = '\000'; 333: return(buf); 334: } 335: 336: /* 337: * Get multiple files. 338: */ 339: mget(argc, argv) 340: char *argv[]; 341: { 342: char *cp; 343: char *tailp; 344: 345: if (argc < 2) { 346: strcat(line, " "); 347: printf("(remote-files) "); 348: gets(&line[strlen(line)]); 349: makeargv(); 350: argc = margc; 351: argv = margv; 352: } 353: if (argc < 2) { 354: printf("%s remote-files\n", argv[0]); 355: return; 356: } 357: while ((cp = remglob(argc, argv)) != NULL) 358: if (confirm(argv[0], cp)) { 359: tailp = getlocalname(cp); 360: recvrequest("RETR", cp, tailp, "w"); 361: } 362: } 363: 364: char * 365: remglob(argc, argv) 366: char *argv[]; 367: { 368: char temp[16]; 369: static char buf[MAXPATHLEN]; 370: static FILE *ftemp = NULL; 371: static char **args; 372: int oldverbose, oldhash; 373: char *cp, *mode; 374: 375: if (!doglob) { 376: if (args == NULL) 377: args = argv; 378: if ((cp = *++args) == NULL) 379: args = NULL; 380: return (cp); 381: } 382: if (ftemp == NULL) { 383: strcpy(temp, "/tmp/ftpXXXXXX"); 384: mktemp(temp); 385: oldverbose = verbose, verbose = 0; 386: oldhash = hash, hash = 0; 387: for (mode = "w"; *++argv != NULL; mode = "a") 388: recvrequest("NLST", temp, *argv, mode); 389: verbose = oldverbose; hash = oldhash; 390: ftemp = fopen(temp, "r"); 391: unlink(temp); 392: if (ftemp == NULL) { 393: printf("can't find list of remote files, oops\n"); 394: return (NULL); 395: } 396: } 397: if (fgets(buf, sizeof (buf), ftemp) == NULL) { 398: fclose(ftemp), ftemp = NULL; 399: return (NULL); 400: } 401: if ((cp = index(buf, '\n')) != NULL) 402: *cp = '\0'; 403: return (buf); 404: } 405: 406: char * 407: onoff(bool) 408: int bool; 409: { 410: 411: return (bool ? "on" : "off"); 412: } 413: 414: /* 415: * Show status. 416: */ 417: status(argc, argv) 418: char *argv[]; 419: { 420: 421: if (connected) 422: printf("Connected to %s.\n", hostname); 423: else 424: printf("Not connected.\n"); 425: printf("Mode: %s; Type: %s; Form: %s; Structure: %s\n", 426: modename, typename, formname, structname); 427: printf("Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s\n", 428: onoff(verbose), onoff(bell), onoff(interactive), 429: onoff(doglob)); 430: printf("Hash mark printing: %s\n", 431: onoff(hash)); 432: } 433: 434: /* 435: * Set beep on cmd completed mode. 436: */ 437: /*VARARGS*/ 438: setbell() 439: { 440: 441: bell = !bell; 442: printf("Bell mode %s.\n", onoff(bell)); 443: } 444: 445: /* 446: * Turn on packet tracing. 447: */ 448: /*VARARGS*/ 449: settrace() 450: { 451: 452: trace = !trace; 453: printf("Packet tracing %s.\n", onoff(trace)); 454: } 455: 456: /* 457: * Toggle hash mark printing during transfers. 458: */ 459: /*VARARGS*/ 460: sethash() 461: { 462: 463: hash = !hash; 464: printf("Hash mark printing %s", onoff(hash)); 465: if (hash) 466: printf(" (1 packet/hash mark)"); 467: printf(".\n"); 468: } 469: 470: /* 471: * Turn on printing of server echo's. 472: */ 473: /*VARARGS*/ 474: setverbose() 475: { 476: 477: verbose = !verbose; 478: printf("Verbose mode %s.\n", onoff(verbose)); 479: } 480: 481: /* 482: * Turn on interactive prompting 483: * during mget, mput, and mdelete. 484: */ 485: /*VARARGS*/ 486: setprompt() 487: { 488: 489: interactive = !interactive; 490: printf("Interactive mode %s.\n", onoff(interactive)); 491: } 492: 493: /* 494: * Toggle metacharacter interpretation 495: * on local file names. 496: */ 497: /*VARARGS*/ 498: setglob() 499: { 500: 501: doglob = !doglob; 502: printf("Globbing %s.\n", onoff(doglob)); 503: } 504: 505: /* 506: * Set debugging mode on/off and/or 507: * set level of debugging. 508: */ 509: /*VARARGS*/ 510: setdebug(argc, argv) 511: char *argv[]; 512: { 513: int val; 514: 515: if (argc > 1) { 516: val = atoi(argv[1]); 517: if (val < 0) { 518: printf("%s: bad debugging value.\n", argv[1]); 519: return; 520: } 521: } else 522: val = !debug; 523: debug = val; 524: printf("Debugging %s (debug=%d).\n", onoff(debug), debug); 525: } 526: 527: /* 528: * Set current working directory 529: * on remote machine. 530: */ 531: cd(argc, argv) 532: char *argv[]; 533: { 534: 535: if (argc < 2) { 536: strcat(line, " "); 537: printf("(remote-directory) "); 538: gets(&line[strlen(line)]); 539: makeargv(); 540: argc = margc; 541: argv = margv; 542: } 543: if (argc < 2) { 544: printf("%s remote-directory\n", argv[0]); 545: return; 546: } 547: (void) docd(argv[1]); 548: } 549: 550: /* 551: * Set current working directory 552: * on local machine. 553: */ 554: lcd(argc, argv) 555: char *argv[]; 556: { 557: char buf[MAXPATHLEN]; 558: 559: if (argc < 2) 560: argc++, argv[1] = home; 561: if (argc != 2) { 562: printf("%s local-directory\n", argv[0]); 563: return; 564: } 565: if (!globulize(&argv[1])) 566: return; 567: if (chdir(argv[1]) < 0) { 568: perror(argv[1]); 569: return; 570: } 571: printf("Local directory now %s\n", getwd(buf)); 572: } 573: 574: /* 575: * Delete a single file. 576: */ 577: delete(argc, argv) 578: char *argv[]; 579: { 580: 581: if (argc < 2) { 582: strcat(line, " "); 583: printf("(remote-file) "); 584: gets(&line[strlen(line)]); 585: makeargv(); 586: argc = margc; 587: argv = margv; 588: } 589: if (argc < 2) { 590: printf("%s remote-file\n", argv[0]); 591: return; 592: } 593: (void) dodelete( argv[1]); 594: } 595: 596: /* 597: * Delete multiple files. 598: */ 599: mdelete(argc, argv) 600: char *argv[]; 601: { 602: char *cp; 603: 604: if (argc < 2) { 605: strcat(line, " "); 606: printf("(remote-files) "); 607: gets(&line[strlen(line)]); 608: makeargv(); 609: argc = margc; 610: argv = margv; 611: } 612: if (argc < 2) { 613: printf("%s remote-files\n", argv[0]); 614: return; 615: } 616: while ((cp = remglob(argc, argv)) != NULL) 617: if (confirm(argv[0], cp)) 618: (void) dodelete( cp); 619: } 620: 621: /* 622: * Rename a remote file. 623: */ 624: renamefile(argc, argv) 625: char *argv[]; 626: { 627: 628: if (argc < 2) { 629: strcat(line, " "); 630: printf("(from-name) "); 631: gets(&line[strlen(line)]); 632: makeargv(); 633: argc = margc; 634: argv = margv; 635: } 636: if (argc < 2) { 637: usage: 638: printf("%s from-name to-name\n", argv[0]); 639: return; 640: } 641: if (argc < 3) { 642: strcat(line, " "); 643: printf("(to-name) "); 644: gets(&line[strlen(line)]); 645: makeargv(); 646: argc = margc; 647: argv = margv; 648: } 649: if (argc < 3) 650: goto usage; 651: dorename(argv[1], argv[2]); 652: } 653: 654: /* 655: * Get a directory listing 656: * of remote files. 657: */ 658: ls(argc, argv) 659: char *argv[]; 660: { 661: char *cmd; 662: 663: if (argc < 2) 664: argc++, argv[1] = NULL; 665: if (argc < 3) 666: argc++, argv[2] = "-"; 667: if (argc > 3) { 668: printf("usage: %s remote-directory local-file\n", argv[0]); 669: return; 670: } 671: cmd = argv[0][0] == 'l' ? "NLST" : "LIST"; 672: if (strcmp(argv[2], "-") && !globulize(&argv[2])) 673: return; 674: recvrequest(cmd, argv[2], argv[1], "w"); 675: } 676: 677: /* 678: * Get a directory listing 679: * of multiple remote files. 680: */ 681: mls(argc, argv) 682: char *argv[]; 683: { 684: char *cmd, *mode, *cp, *dest; 685: 686: if (argc < 2) { 687: strcat(line, " "); 688: printf("(remote-files) "); 689: gets(&line[strlen(line)]); 690: makeargv(); 691: argc = margc; 692: argv = margv; 693: } 694: if (argc < 3) { 695: strcat(line, " "); 696: printf("(local-file) "); 697: gets(&line[strlen(line)]); 698: makeargv(); 699: argc = margc; 700: argv = margv; 701: } 702: if (argc < 3) { 703: printf("%s remote-files local-file\n", argv[0]); 704: return; 705: } 706: dest = argv[argc - 1]; 707: argv[argc - 1] = NULL; 708: if (strcmp(dest, "-")) 709: if (globulize(&dest) && confirm("local-file", dest)) 710: return; 711: cmd = argv[0][1] == 'l' ? "NLST" : "LIST"; 712: for (mode = "w"; cp = remglob(argc, argv); mode = "a") 713: if (confirm(argv[0], cp)) 714: recvrequest(cmd, argv[2], argv[1], "w"); 715: } 716: 717: /* 718: * Do a shell escape 719: */ 720: shell(argc, argv) 721: char *argv[]; 722: { 723: int pid, status, (*old1)(), (*old2)(); 724: char shellnam[40], *shell, *namep; 725: char **cpp, **gargs; 726: 727: old1 = signal (SIGINT, SIG_IGN); 728: old2 = signal (SIGQUIT, SIG_IGN); 729: if ((pid = fork()) == 0) { 730: for (pid = 3; pid < 20; pid++) 731: close(pid); 732: signal(SIGINT, SIG_DFL); 733: signal(SIGQUIT, SIG_DFL); 734: if (argc <= 1) { 735: shell = getenv("SHELL"); 736: if (shell == NULL) 737: shell = "/bin/sh"; 738: namep = rindex(shell,'/'); 739: if (namep == NULL) 740: namep = shell; 741: strcpy(shellnam,"-"); 742: strcat(shellnam, ++namep); 743: if (strcmp(namep, "sh") != 0) 744: shellnam[0] = '+'; 745: if (debug) { 746: printf ("%s\n", shell); 747: fflush (stdout); 748: } 749: execl(shell, shellnam, 0); 750: perror(shell); 751: exit(1); 752: } 753: cpp = &argv[1]; 754: if (argc > 2) { 755: if ((gargs = glob(cpp)) != NULL) 756: cpp = gargs; 757: if (globerr != NULL) { 758: printf("%s\n", globerr); 759: exit(1); 760: } 761: } 762: if (debug) { 763: register char **zip = cpp; 764: 765: printf("%s", *zip); 766: while (*++zip != NULL) 767: printf(" %s", *zip); 768: printf("\n"); 769: fflush(stdout); 770: } 771: execvp(argv[1], cpp); 772: perror(argv[1]); 773: exit(1); 774: } 775: if (pid > 0) 776: while (wait(&status) != pid) 777: ; 778: signal(SIGINT, old1); 779: signal(SIGQUIT, old2); 780: if (pid == -1) 781: perror("Try again later"); 782: return (0); 783: } 784: 785: /* 786: * Send new user information (re-login) 787: */ 788: user(argc, argv) 789: int argc; 790: char **argv; 791: { 792: char *getXNSpass(); 793: 794: if (argc < 2) { 795: strcat(line, " "); 796: printf("(XNS username) "); 797: gets(&line[strlen(line)]); 798: makeargv(); 799: argc = margc; 800: argv = margv; 801: } 802: if (argc > 3) { 803: printf("usage: %s username [password]\n", argv[0]); 804: return (0); 805: } 806: if (argc < 3 ) 807: argv[2] = getXNSpass("Password: "), argc++; 808: login(argv[1], argv[2]); 809: return (1); 810: } 811: 812: /* 813: * Print working directory. 814: */ 815: /*VARARGS*/ 816: pwd() 817: { 818: dopwd(); 819: } 820: 821: /* 822: * Make a directory. 823: */ 824: makedir(argc, argv) 825: char *argv[]; 826: { 827: 828: if (argc < 2) { 829: strcat(line, " "); 830: printf("(directory-name) "); 831: gets(&line[strlen(line)]); 832: makeargv(); 833: argc = margc; 834: argv = margv; 835: } 836: if (argc < 2) { 837: printf("%s directory-name\n", argv[0]); 838: return; 839: } 840: domakedir(argv[1]); 841: } 842: 843: /* 844: * Remove a directory. 845: */ 846: removedir(argc, argv) 847: char *argv[]; 848: { 849: 850: if (argc < 2) { 851: strcat(line, " "); 852: printf("(directory-name) "); 853: gets(&line[strlen(line)]); 854: makeargv(); 855: argc = margc; 856: argv = margv; 857: } 858: if (argc < 2) { 859: printf("%s directory-name\n", argv[0]); 860: return; 861: } 862: doremovedir(argv[1]); 863: } 864: 865: /* 866: * Terminate session and exit. 867: */ 868: /*VARARGS*/ 869: quit() 870: { 871: 872: disconnect(); 873: exit(0); 874: } 875: 876: /* 877: * Terminate session, but don't exit. 878: */ 879: disconnect() 880: { 881: extern FILE *cout; 882: extern int data; 883: 884: if (!connected) 885: return; 886: logout(); 887: CourierClose(connected); 888: connected = (CourierConnection *)0; 889: } 890: 891: confirm(cmd, file) 892: char *cmd, *file; 893: { 894: char line[BUFSIZ]; 895: 896: if (!interactive) { 897: if (verbose) 898: printf("%s %s\n", cmd, file); 899: return (1); 900: } 901: printf("%s %s? ", cmd, file); 902: fflush(stdout); 903: gets(line); 904: return (*line != 'n' && *line != 'N'); 905: } 906: 907: fatal(msg) 908: char *msg; 909: { 910: 911: fprintf(stderr, "ftp: %s\n"); 912: exit(1); 913: } 914: 915: /* 916: * Glob a local file name specification with 917: * the expectation of a single return value. 918: * Can't control multiple values being expanded 919: * from the expression, we return only the first. 920: */ 921: globulize(cpp) 922: char **cpp; 923: { 924: char **globbed; 925: 926: if (!doglob) 927: return (1); 928: globbed = glob(*cpp); 929: if (globerr != NULL) { 930: printf("%s: %s\n", *cpp, globerr); 931: if (globbed) 932: blkfree(globbed); 933: return (0); 934: } 935: if (globbed) { 936: *cpp = *globbed++; 937: /* don't waste too much memory */ 938: if (*globbed) 939: blkfree(globbed); 940: } 941: return (1); 942: }