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