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