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