Annotation of src/usr.bin/ftp/cmds.c, Revision 1.65
1.65 ! martynas 1: /* $OpenBSD: cmds.c,v 1.64 2008/08/22 08:52:35 sobrado Exp $ */
1.23 millert 2: /* $NetBSD: cmds.c,v 1.27 1997/08/18 10:20:15 lukem Exp $ */
1.1 deraadt 3:
4: /*
1.32 itojun 5: * Copyright (C) 1997 and 1998 WIDE Project.
6: * All rights reserved.
7: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
16: * 3. Neither the name of the project nor the names of its contributors
17: * may be used to endorse or promote products derived from this software
18: * without specific prior written permission.
19: *
20: * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23: * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30: * SUCH DAMAGE.
31: */
32:
33: /*
1.1 deraadt 34: * Copyright (c) 1985, 1989, 1993, 1994
35: * The Regents of the University of California. All rights reserved.
36: *
37: * Redistribution and use in source and binary forms, with or without
38: * modification, are permitted provided that the following conditions
39: * are met:
40: * 1. Redistributions of source code must retain the above copyright
41: * notice, this list of conditions and the following disclaimer.
42: * 2. Redistributions in binary form must reproduce the above copyright
43: * notice, this list of conditions and the following disclaimer in the
44: * documentation and/or other materials provided with the distribution.
1.45 millert 45: * 3. Neither the name of the University nor the names of its contributors
1.1 deraadt 46: * may be used to endorse or promote products derived from this software
47: * without specific prior written permission.
48: *
49: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
50: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
53: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59: * SUCH DAMAGE.
60: */
61:
1.46 deraadt 62: #if !defined(lint) && !defined(SMALL)
1.65 ! martynas 63: static const char rcsid[] = "$OpenBSD: cmds.c,v 1.64 2008/08/22 08:52:35 sobrado Exp $";
1.46 deraadt 64: #endif /* not lint and not SMALL */
1.1 deraadt 65:
66: /*
67: * FTP User Program -- Command Routines.
68: */
1.13 millert 69: #include <sys/types.h>
70: #include <sys/socket.h>
71: #include <sys/stat.h>
1.1 deraadt 72: #include <sys/wait.h>
73: #include <arpa/ftp.h>
74:
75: #include <ctype.h>
76: #include <err.h>
1.63 martynas 77: #ifndef SMALL
78: #include <fnmatch.h>
79: #endif /* !SMALL */
1.1 deraadt 80: #include <glob.h>
81: #include <netdb.h>
82: #include <stdio.h>
83: #include <stdlib.h>
84: #include <string.h>
85: #include <unistd.h>
86:
87: #include "ftp_var.h"
88: #include "pathnames.h"
89:
90: jmp_buf jabort;
91: char *mname;
92: char *home = "/";
93:
94: struct types {
95: char *t_name;
96: char *t_mode;
97: int t_type;
98: char *t_arg;
99: } types[] = {
100: { "ascii", "A", TYPE_A, 0 },
101: { "binary", "I", TYPE_I, 0 },
102: { "image", "I", TYPE_I, 0 },
103: { "ebcdic", "E", TYPE_E, 0 },
104: { "tenex", "L", TYPE_L, bytename },
105: { NULL }
106: };
107:
108: /*
109: * Set transfer type.
110: */
111: void
1.47 deraadt 112: settype(int argc, char *argv[])
1.1 deraadt 113: {
114: struct types *p;
115: int comret;
116:
117: if (argc > 2) {
118: char *sep;
119:
1.20 deraadt 120: fprintf(ttyout, "usage: %s [", argv[0]);
1.64 sobrado 121: sep = "";
1.1 deraadt 122: for (p = types; p->t_name; p++) {
1.20 deraadt 123: fprintf(ttyout, "%s%s", sep, p->t_name);
1.1 deraadt 124: sep = " | ";
125: }
1.64 sobrado 126: fputs("]\n", ttyout);
1.1 deraadt 127: code = -1;
128: return;
129: }
130: if (argc < 2) {
1.20 deraadt 131: fprintf(ttyout, "Using %s mode to transfer files.\n", typename);
1.1 deraadt 132: code = 0;
133: return;
134: }
135: for (p = types; p->t_name; p++)
136: if (strcmp(argv[1], p->t_name) == 0)
137: break;
138: if (p->t_name == 0) {
1.20 deraadt 139: fprintf(ttyout, "%s: unknown mode.\n", argv[1]);
1.1 deraadt 140: code = -1;
141: return;
142: }
143: if ((p->t_arg != NULL) && (*(p->t_arg) != '\0'))
1.15 millert 144: comret = command("TYPE %s %s", p->t_mode, p->t_arg);
1.1 deraadt 145: else
146: comret = command("TYPE %s", p->t_mode);
147: if (comret == COMPLETE) {
1.44 deraadt 148: (void)strlcpy(typename, p->t_name, sizeof typename);
1.1 deraadt 149: curtype = type = p->t_type;
150: }
151: }
152:
153: /*
154: * Internal form of settype; changes current type in use with server
155: * without changing our notion of the type for data transfers.
156: * Used to change to and from ascii for listings.
157: */
158: void
1.47 deraadt 159: changetype(int newtype, int show)
1.1 deraadt 160: {
161: struct types *p;
162: int comret, oldverbose = verbose;
163:
164: if (newtype == 0)
165: newtype = TYPE_I;
166: if (newtype == curtype)
167: return;
1.63 martynas 168: if (
169: #ifndef SMALL
170: !debug &&
171: #endif /* !SMALL */
172: show == 0)
1.1 deraadt 173: verbose = 0;
174: for (p = types; p->t_name; p++)
175: if (newtype == p->t_type)
176: break;
177: if (p->t_name == 0) {
1.16 millert 178: warnx("internal error: unknown type %d.", newtype);
1.1 deraadt 179: return;
180: }
181: if (newtype == TYPE_L && bytename[0] != '\0')
182: comret = command("TYPE %s %s", p->t_mode, bytename);
183: else
184: comret = command("TYPE %s", p->t_mode);
185: if (comret == COMPLETE)
186: curtype = newtype;
187: verbose = oldverbose;
188: }
189:
190: char *stype[] = {
191: "type",
192: "",
193: 0
194: };
195:
196: /*
197: * Set binary transfer type.
198: */
1.48 deraadt 199: /*ARGSUSED*/
1.1 deraadt 200: void
1.47 deraadt 201: setbinary(int argc, char *argv[])
1.1 deraadt 202: {
203:
204: stype[1] = "binary";
205: settype(2, stype);
206: }
207:
208: /*
209: * Set ascii transfer type.
210: */
1.48 deraadt 211: /*ARGSUSED*/
1.1 deraadt 212: void
1.47 deraadt 213: setascii(int argc, char *argv[])
1.1 deraadt 214: {
215:
216: stype[1] = "ascii";
217: settype(2, stype);
218: }
219:
220: /*
221: * Set tenex transfer type.
222: */
1.48 deraadt 223: /*ARGSUSED*/
1.1 deraadt 224: void
1.47 deraadt 225: settenex(int argc, char *argv[])
1.1 deraadt 226: {
227:
228: stype[1] = "tenex";
229: settype(2, stype);
230: }
231:
232: /*
233: * Set file transfer mode.
234: */
235: /*ARGSUSED*/
236: void
1.47 deraadt 237: setftmode(int argc, char *argv[])
1.1 deraadt 238: {
239:
1.20 deraadt 240: fprintf(ttyout, "We only support %s mode, sorry.\n", modename);
1.1 deraadt 241: code = -1;
242: }
243:
244: /*
245: * Set file transfer format.
246: */
247: /*ARGSUSED*/
248: void
1.47 deraadt 249: setform(int argc, char *argv[])
1.1 deraadt 250: {
251:
1.20 deraadt 252: fprintf(ttyout, "We only support %s format, sorry.\n", formname);
1.1 deraadt 253: code = -1;
254: }
255:
256: /*
257: * Set file transfer structure.
258: */
259: /*ARGSUSED*/
260: void
1.47 deraadt 261: setstruct(int argc, char *argv[])
1.1 deraadt 262: {
263:
1.20 deraadt 264: fprintf(ttyout, "We only support %s structure, sorry.\n", structname);
1.1 deraadt 265: code = -1;
266: }
267:
1.62 martynas 268: #ifndef SMALL
269: void
270: reput(int argc, char *argv[])
271: {
272:
273: (void)putit(argc, argv, 1);
274: }
275: #endif /* !SMALL */
276:
277: void
278: put(int argc, char *argv[])
279: {
280:
281: (void)putit(argc, argv, 0);
282: }
283:
1.1 deraadt 284: /*
285: * Send a single file.
286: */
287: void
1.62 martynas 288: putit(int argc, char *argv[], int restartit)
1.1 deraadt 289: {
290: char *cmd;
291: int loc = 0;
292: char *oldargv1, *oldargv2;
293:
294: if (argc == 2) {
295: argc++;
296: argv[2] = argv[1];
297: loc++;
298: }
299: if (argc < 2 && !another(&argc, &argv, "local-file"))
300: goto usage;
1.13 millert 301: if ((argc < 3 && !another(&argc, &argv, "remote-file")) || argc > 3) {
1.1 deraadt 302: usage:
1.64 sobrado 303: fprintf(ttyout, "usage: %s local-file [remote-file]\n",
304: argv[0]);
1.1 deraadt 305: code = -1;
306: return;
307: }
308: oldargv1 = argv[1];
309: oldargv2 = argv[2];
310: if (!globulize(&argv[1])) {
311: code = -1;
312: return;
313: }
314: /*
315: * If "globulize" modifies argv[1], and argv[2] is a copy of
316: * the old argv[1], make it a copy of the new argv[1].
317: */
318: if (argv[1] != oldargv1 && argv[2] == oldargv1) {
319: argv[2] = argv[1];
320: }
1.62 martynas 321: #ifndef SMALL
322: if (restartit == 1) {
323: if (curtype != type)
324: changetype(type, 0);
325: restart_point = remotesize(argv[2], 1);
326: if (restart_point < 0) {
327: restart_point = 0;
328: code = -1;
329: return;
330: }
331: }
332: #endif /* !SMALL */
333: if (strcmp(argv[0], "append") == 0) {
334: restartit = 1;
335: }
336: cmd = restartit ? "APPE" : ((sunique) ? "STOU" : "STOR");
1.1 deraadt 337: if (loc && ntflag) {
338: argv[2] = dotrans(argv[2]);
339: }
340: if (loc && mapflag) {
341: argv[2] = domap(argv[2]);
342: }
343: sendrequest(cmd, argv[1], argv[2],
344: argv[1] != oldargv1 || argv[2] != oldargv2);
1.62 martynas 345: restart_point = 0;
1.23 millert 346: if (oldargv1 != argv[1]) /* free up after globulize() */
347: free(argv[1]);
1.1 deraadt 348: }
349:
350: /*
351: * Send multiple files.
352: */
353: void
1.47 deraadt 354: mput(int argc, char *argv[])
1.1 deraadt 355: {
1.62 martynas 356: extern int optind, optreset;
357: int ch, i, restartit = 0;
1.1 deraadt 358: sig_t oldintr;
1.62 martynas 359: char *cmd, *tp;
360:
361: optind = optreset = 1;
1.1 deraadt 362:
1.62 martynas 363: #ifndef SMALL
364: while ((ch = getopt(argc, argv, "c")) != -1) {
365: switch(ch) {
366: case 'c':
367: restartit = 1;
368: break;
369: default:
370: goto usage;
371: }
372: }
373: #endif /* !SMALL */
374:
375: if (argc - optind < 1 && !another(&argc, &argv, "local-files")) {
376: usage:
377: fprintf(ttyout, "usage: %s [-c] local-files\n", argv[0]);
1.1 deraadt 378: code = -1;
379: return;
380: }
1.62 martynas 381:
382: #ifndef SMALL
1.63 martynas 383: argv[optind - 1] = argv[0];
384: argc -= optind - 1;
385: argv += optind - 1;
1.62 martynas 386: #endif /* !SMALL */
387:
1.1 deraadt 388: mname = argv[0];
389: mflag = 1;
1.62 martynas 390:
1.1 deraadt 391: oldintr = signal(SIGINT, mabort);
1.14 millert 392: (void)setjmp(jabort);
1.1 deraadt 393: if (proxy) {
394: char *cp, *tp2, tmpbuf[MAXPATHLEN];
395:
1.16 millert 396: while ((cp = remglob(argv, 0, NULL)) != NULL) {
1.13 millert 397: if (*cp == '\0') {
1.1 deraadt 398: mflag = 0;
399: continue;
400: }
1.63 martynas 401: if (mflag && confirm(argv[0], cp)) {
1.1 deraadt 402: tp = cp;
403: if (mcase) {
404: while (*tp && !islower(*tp)) {
405: tp++;
406: }
407: if (!*tp) {
408: tp = cp;
409: tp2 = tmpbuf;
1.21 millert 410: while ((*tp2 = *tp) != '\0') {
1.1 deraadt 411: if (isupper(*tp2)) {
1.23 millert 412: *tp2 =
413: tolower(*tp2);
1.1 deraadt 414: }
415: tp++;
416: tp2++;
417: }
418: }
419: tp = tmpbuf;
420: }
421: if (ntflag) {
422: tp = dotrans(tp);
423: }
424: if (mapflag) {
425: tp = domap(tp);
426: }
1.62 martynas 427: #ifndef SMALL
428: if (restartit == 1) {
429: off_t ret;
430:
431: if (curtype != type)
432: changetype(type, 0);
433: ret = remotesize(tp, 0);
434: restart_point = (ret < 0) ? 0 : ret;
435: }
436: #endif /* !SMALL */
437: cmd = restartit ? "APPE" : ((sunique) ?
438: "STOU" : "STOR");
439: sendrequest(cmd, cp, tp,
440: cp != tp || !interactive);
441: restart_point = 0;
1.1 deraadt 442: if (!mflag && fromatty) {
1.63 martynas 443: if (confirm(argv[0], NULL))
1.61 martynas 444: mflag = 1;
1.1 deraadt 445: }
446: }
447: }
1.14 millert 448: (void)signal(SIGINT, oldintr);
1.1 deraadt 449: mflag = 0;
450: return;
451: }
452: for (i = 1; i < argc; i++) {
1.13 millert 453: char **cpp;
1.1 deraadt 454: glob_t gl;
455: int flags;
456:
457: if (!doglob) {
1.63 martynas 458: if (mflag && confirm(argv[0], argv[i])) {
1.1 deraadt 459: tp = (ntflag) ? dotrans(argv[i]) : argv[i];
460: tp = (mapflag) ? domap(tp) : tp;
1.62 martynas 461: #ifndef SMALL
462: if (restartit == 1) {
463: off_t ret;
464:
465: if (curtype != type)
466: changetype(type, 0);
467: ret = remotesize(tp, 0);
468: restart_point = (ret < 0) ? 0 : ret;
469: }
470: #endif /* !SMALL */
471: cmd = restartit ? "APPE" : ((sunique) ?
472: "STOU" : "STOR");
473: sendrequest(cmd, argv[i], tp,
474: tp != argv[i] || !interactive);
475: restart_point = 0;
1.1 deraadt 476: if (!mflag && fromatty) {
1.63 martynas 477: if (confirm(argv[0], NULL))
1.61 martynas 478: mflag = 1;
1.1 deraadt 479: }
480: }
481: continue;
482: }
483:
484: memset(&gl, 0, sizeof(gl));
485: flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE;
486: if (glob(argv[i], flags, NULL, &gl) || gl.gl_pathc == 0) {
487: warnx("%s: not found", argv[i]);
488: globfree(&gl);
489: continue;
490: }
491: for (cpp = gl.gl_pathv; cpp && *cpp != NULL; cpp++) {
1.63 martynas 492: if (mflag && confirm(argv[0], *cpp)) {
1.1 deraadt 493: tp = (ntflag) ? dotrans(*cpp) : *cpp;
494: tp = (mapflag) ? domap(tp) : tp;
1.62 martynas 495: #ifndef SMALL
496: if (restartit == 1) {
497: off_t ret;
498:
499: if (curtype != type)
500: changetype(type, 0);
501: ret = remotesize(tp, 0);
502: restart_point = (ret < 0) ? 0 : ret;
503: }
504: #endif /* !SMALL */
505: cmd = restartit ? "APPE" : ((sunique) ?
506: "STOU" : "STOR");
507: sendrequest(cmd, *cpp, tp,
508: *cpp != tp || !interactive);
509: restart_point = 0;
1.1 deraadt 510: if (!mflag && fromatty) {
1.63 martynas 511: if (confirm(argv[0], NULL))
1.61 martynas 512: mflag = 1;
1.1 deraadt 513: }
514: }
515: }
516: globfree(&gl);
517: }
1.14 millert 518: (void)signal(SIGINT, oldintr);
1.1 deraadt 519: mflag = 0;
520: }
521:
1.62 martynas 522: #ifndef SMALL
1.1 deraadt 523: void
1.47 deraadt 524: reget(int argc, char *argv[])
1.1 deraadt 525: {
526:
1.14 millert 527: (void)getit(argc, argv, 1, "r+w");
1.1 deraadt 528: }
1.62 martynas 529: #endif /* !SMALL */
1.1 deraadt 530:
531: void
1.47 deraadt 532: get(int argc, char *argv[])
1.1 deraadt 533: {
534:
1.14 millert 535: (void)getit(argc, argv, 0, restart_point ? "r+w" : "w" );
1.1 deraadt 536: }
537:
538: /*
539: * Receive one file.
540: */
541: int
1.47 deraadt 542: getit(int argc, char *argv[], int restartit, const char *mode)
1.1 deraadt 543: {
544: int loc = 0;
1.23 millert 545: int rval = 0;
546: char *oldargv1, *oldargv2, *globargv2;
1.1 deraadt 547:
548: if (argc == 2) {
549: argc++;
550: argv[2] = argv[1];
551: loc++;
552: }
553: if (argc < 2 && !another(&argc, &argv, "remote-file"))
554: goto usage;
1.13 millert 555: if ((argc < 3 && !another(&argc, &argv, "local-file")) || argc > 3) {
1.1 deraadt 556: usage:
1.64 sobrado 557: fprintf(ttyout, "usage: %s remote-file [local-file]\n",
558: argv[0]);
1.1 deraadt 559: code = -1;
560: return (0);
561: }
562: oldargv1 = argv[1];
563: oldargv2 = argv[2];
564: if (!globulize(&argv[2])) {
565: code = -1;
566: return (0);
567: }
1.23 millert 568: globargv2 = argv[2];
1.1 deraadt 569: if (loc && mcase) {
570: char *tp = argv[1], *tp2, tmpbuf[MAXPATHLEN];
571:
572: while (*tp && !islower(*tp)) {
573: tp++;
574: }
575: if (!*tp) {
576: tp = argv[2];
577: tp2 = tmpbuf;
1.21 millert 578: while ((*tp2 = *tp) != '\0') {
1.1 deraadt 579: if (isupper(*tp2)) {
1.23 millert 580: *tp2 = tolower(*tp2);
1.1 deraadt 581: }
582: tp++;
583: tp2++;
584: }
585: argv[2] = tmpbuf;
586: }
587: }
588: if (loc && ntflag)
589: argv[2] = dotrans(argv[2]);
590: if (loc && mapflag)
591: argv[2] = domap(argv[2]);
1.62 martynas 592: #ifndef SMALL
1.1 deraadt 593: if (restartit) {
594: struct stat stbuf;
595: int ret;
596:
597: ret = stat(argv[2], &stbuf);
598: if (restartit == 1) {
599: if (ret < 0) {
600: warn("local: %s", argv[2]);
1.23 millert 601: goto freegetit;
1.1 deraadt 602: }
603: restart_point = stbuf.st_size;
604: } else {
605: if (ret == 0) {
1.13 millert 606: time_t mtime;
1.1 deraadt 607:
1.13 millert 608: mtime = remotemodtime(argv[1], 0);
609: if (mtime == -1)
1.23 millert 610: goto freegetit;
611: if (stbuf.st_mtime >= mtime) {
612: rval = 1;
613: goto freegetit;
614: }
1.1 deraadt 615: }
616: }
617: }
1.62 martynas 618: #endif /* !SMALL */
1.1 deraadt 619:
620: recvrequest("RETR", argv[2], argv[1], mode,
1.65 ! martynas 621: argv[1] != oldargv1 || argv[2] != oldargv2 || !interactive, loc);
1.1 deraadt 622: restart_point = 0;
1.23 millert 623: freegetit:
624: if (oldargv2 != globargv2) /* free up after globulize() */
625: free(globargv2);
626: return (rval);
1.1 deraadt 627: }
628:
1.55 ray 629: /* XXX - Signal race. */
1.1 deraadt 630: /* ARGSUSED */
631: void
1.47 deraadt 632: mabort(int signo)
1.1 deraadt 633: {
1.13 millert 634: alarmtimer(0);
1.20 deraadt 635: putc('\n', ttyout);
636: (void)fflush(ttyout);
1.60 martynas 637: if (mflag && fromatty)
1.63 martynas 638: if (confirm(mname, NULL))
1.40 art 639: longjmp(jabort, 1);
1.1 deraadt 640: mflag = 0;
1.40 art 641: longjmp(jabort, 1);
1.1 deraadt 642: }
643:
644: /*
645: * Get multiple files.
646: */
647: void
1.47 deraadt 648: mget(int argc, char *argv[])
1.1 deraadt 649: {
1.62 martynas 650: extern int optind, optreset;
1.1 deraadt 651: sig_t oldintr;
1.65 ! martynas 652: int ch, xargc = 2;
! 653: char *cp, localcwd[MAXPATHLEN], *xargv[] = {argv[0], NULL, NULL};
! 654: static int restartit = 0;
! 655: #ifndef SMALL
! 656: extern char *optarg;
! 657: int i = 1;
! 658: char type = NULL, *dummyargv[] = {argv[0], ".", NULL};
1.63 martynas 659: FILE *ftemp = NULL;
1.65 ! martynas 660: static int depth = 0, max_depth = 0;
1.63 martynas 661: #endif /* !SMALL */
1.1 deraadt 662:
1.62 martynas 663: optind = optreset = 1;
664:
665: #ifndef SMALL
1.65 ! martynas 666: const char *errstr;
! 667:
! 668: if (depth)
! 669: depth++;
! 670:
! 671: while ((ch = getopt(argc, argv, "cd:nr")) != -1) {
1.62 martynas 672: switch(ch) {
673: case 'c':
674: restartit = 1;
675: break;
1.65 ! martynas 676: case 'd':
! 677: max_depth = strtonum(optarg, 0, INT_MAX, &errstr);
! 678: if (errstr != NULL) {
! 679: fprintf(ttyout, "bad depth value, %s: %s\n",
! 680: errstr, optarg);
! 681: code = -1;
! 682: return;
! 683: }
! 684: break;
! 685: case 'n':
! 686: restartit = -1;
! 687: break;
1.63 martynas 688: case 'r':
1.65 ! martynas 689: depth = 1;
1.63 martynas 690: break;
1.62 martynas 691: default:
692: goto usage;
693: }
694: }
695: #endif /* !SMALL */
696:
697: if (argc - optind < 1 && !another(&argc, &argv, "remote-files")) {
698: usage:
1.65 ! martynas 699: fprintf(ttyout, "usage: %s [-cnr] [-d depth] remote-files\n",
! 700: argv[0]);
1.1 deraadt 701: code = -1;
702: return;
703: }
1.62 martynas 704:
705: #ifndef SMALL
1.63 martynas 706: argv[optind - 1] = argv[0];
707: argc -= optind - 1;
708: argv += optind - 1;
1.62 martynas 709: #endif /* !SMALL */
710:
1.1 deraadt 711: mname = argv[0];
712: mflag = 1;
1.49 otto 713: if (getcwd(localcwd, sizeof(localcwd)) == NULL)
714: err(1, "can't get cwd");
715:
1.1 deraadt 716: oldintr = signal(SIGINT, mabort);
1.14 millert 717: (void)setjmp(jabort);
1.63 martynas 718: while ((cp =
719: #ifndef SMALL
1.65 ! martynas 720: depth ? remglob2(dummyargv, proxy, NULL, &ftemp, &type) :
1.63 martynas 721: #endif /* !SMALL */
722: remglob(argv, proxy, NULL)) != NULL
723: #ifndef SMALL
724: || (mflag && depth && ++i < argc)
725: #endif /* !SMALL */
726: ) {
727: #ifndef SMALL
728: if (cp == NULL)
729: continue;
730: #endif /* !SMALL */
1.1 deraadt 731: if (*cp == '\0') {
732: mflag = 0;
733: continue;
734: }
1.49 otto 735: if (!mflag)
736: continue;
1.63 martynas 737: #ifndef SMALL
738: if (depth && fnmatch(argv[i], cp, FNM_PATHNAME) != 0)
739: continue;
740: #endif /* !SMALL */
1.49 otto 741: if (!fileindir(cp, localcwd)) {
742: fprintf(ttyout, "Skipping non-relative filename `%s'\n",
743: cp);
744: continue;
745: }
1.65 ! martynas 746: #ifndef SMALL
! 747: if (type == 'd' && depth == max_depth)
! 748: continue;
! 749: #endif /* !SMALL */
1.63 martynas 750: if (confirm(argv[0], cp)) {
751: #ifndef SMALL
752: if (type == 'd') {
753: mkdir(cp, 0755);
754: if (chdir(cp) != 0) {
755: warn("local: %s", cp);
756: continue;
757: }
758:
759: xargv[1] = cp;
760: cd(xargc, xargv);
761: if (dirchange != 1)
762: goto out;
763:
1.65 ! martynas 764: xargv[1] = "*";
1.63 martynas 765: mget(xargc, xargv);
766:
767: xargv[1] = "..";
768: cd(xargc, xargv);
769: if (dirchange != 1) {
770: mflag = 0;
771: goto out;
772: }
773:
774: out:
775: if (chdir("..") != 0) {
776: warn("local: %s", cp);
777: mflag = 0;
778: }
779: continue;
780: }
781: if (type == 's')
782: /* Currently ignored. */
783: continue;
784: #endif /* !SMALL */
1.65 ! martynas 785: xargv[1] = cp;
! 786: (void)getit(xargc, xargv, restartit,
! 787: (restartit == 1 || restart_point) ? "r+w" : "w");
1.1 deraadt 788: if (!mflag && fromatty) {
1.63 martynas 789: if (confirm(argv[0], NULL))
1.61 martynas 790: mflag = 1;
1.1 deraadt 791: }
792: }
793: }
1.14 millert 794: (void)signal(SIGINT, oldintr);
1.63 martynas 795: #ifndef SMALL
796: if (depth)
797: depth--;
798: if (depth == 0 || mflag == 0)
1.65 ! martynas 799: depth = max_depth = mflag = restartit = 0;
1.63 martynas 800: #else /* !SMALL */
1.1 deraadt 801: mflag = 0;
1.63 martynas 802: #endif /* !SMALL */
1.1 deraadt 803: }
804:
805: char *
1.47 deraadt 806: onoff(int bool)
1.1 deraadt 807: {
808:
809: return (bool ? "on" : "off");
810: }
811:
812: /*
813: * Show status.
814: */
815: /*ARGSUSED*/
816: void
1.47 deraadt 817: status(int argc, char *argv[])
1.1 deraadt 818: {
819: int i;
820:
821: if (connected)
1.20 deraadt 822: fprintf(ttyout, "Connected %sto %s.\n",
1.19 millert 823: connected == -1 ? "and logged in" : "", hostname);
1.1 deraadt 824: else
1.20 deraadt 825: fputs("Not connected.\n", ttyout);
1.1 deraadt 826: if (!proxy) {
827: pswitch(1);
828: if (connected) {
1.20 deraadt 829: fprintf(ttyout, "Connected for proxy commands to %s.\n",
1.13 millert 830: hostname);
1.1 deraadt 831: }
832: else {
1.20 deraadt 833: fputs("No proxy connection.\n", ttyout);
1.1 deraadt 834: }
835: pswitch(0);
836: }
1.32 itojun 837: fprintf(ttyout, "Gate ftp: %s, server %s, port %s.\n", onoff(gatemode),
838: *gateserver ? gateserver : "(none)", gateport);
1.20 deraadt 839: fprintf(ttyout, "Passive mode: %s.\n", onoff(passivemode));
840: fprintf(ttyout, "Mode: %s; Type: %s; Form: %s; Structure: %s.\n",
1.1 deraadt 841: modename, typename, formname, structname);
1.20 deraadt 842: fprintf(ttyout, "Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s.\n",
1.1 deraadt 843: onoff(verbose), onoff(bell), onoff(interactive),
844: onoff(doglob));
1.20 deraadt 845: fprintf(ttyout, "Store unique: %s; Receive unique: %s.\n", onoff(sunique),
1.1 deraadt 846: onoff(runique));
1.20 deraadt 847: fprintf(ttyout, "Preserve modification times: %s.\n", onoff(preserve));
848: fprintf(ttyout, "Case: %s; CR stripping: %s.\n", onoff(mcase), onoff(crflag));
1.1 deraadt 849: if (ntflag) {
1.20 deraadt 850: fprintf(ttyout, "Ntrans: (in) %s (out) %s\n", ntin, ntout);
1.1 deraadt 851: }
852: else {
1.20 deraadt 853: fputs("Ntrans: off.\n", ttyout);
1.1 deraadt 854: }
855: if (mapflag) {
1.20 deraadt 856: fprintf(ttyout, "Nmap: (in) %s (out) %s\n", mapin, mapout);
1.1 deraadt 857: }
858: else {
1.20 deraadt 859: fputs("Nmap: off.\n", ttyout);
1.1 deraadt 860: }
1.20 deraadt 861: fprintf(ttyout, "Hash mark printing: %s; Mark count: %d; Progress bar: %s.\n",
1.13 millert 862: onoff(hash), mark, onoff(progress));
1.32 itojun 863: fprintf(ttyout, "Use of PORT/LPRT cmds: %s.\n", onoff(sendport));
1.34 itojun 864: fprintf(ttyout, "Use of EPSV/EPRT cmds for IPv4: %s%s.\n", onoff(epsv4),
865: epsv4bad ? " (disabled for this connection)" : "");
1.17 millert 866: #ifndef SMALL
1.20 deraadt 867: fprintf(ttyout, "Command line editing: %s.\n", onoff(editing));
1.17 millert 868: #endif /* !SMALL */
1.1 deraadt 869: if (macnum > 0) {
1.27 millert 870: fputs("Macros:\n", ttyout);
1.1 deraadt 871: for (i=0; i<macnum; i++) {
1.20 deraadt 872: fprintf(ttyout, "\t%s\n", macros[i].mac_name);
1.1 deraadt 873: }
874: }
875: code = 0;
876: }
877:
878: /*
1.13 millert 879: * Toggle a variable
880: */
881: int
1.47 deraadt 882: togglevar(int argc, char *argv[], int *var, const char *mesg)
1.13 millert 883: {
884: if (argc < 2) {
885: *var = !*var;
886: } else if (argc == 2 && strcasecmp(argv[1], "on") == 0) {
887: *var = 1;
888: } else if (argc == 2 && strcasecmp(argv[1], "off") == 0) {
889: *var = 0;
890: } else {
1.64 sobrado 891: fprintf(ttyout, "usage: %s [on | off]\n", argv[0]);
1.16 millert 892: return (-1);
1.13 millert 893: }
1.15 millert 894: if (mesg)
1.20 deraadt 895: fprintf(ttyout, "%s %s.\n", mesg, onoff(*var));
1.14 millert 896: return (*var);
1.13 millert 897: }
898:
899: /*
1.1 deraadt 900: * Set beep on cmd completed mode.
901: */
1.48 deraadt 902: /*ARGSUSED*/
1.1 deraadt 903: void
1.47 deraadt 904: setbell(int argc, char *argv[])
1.1 deraadt 905: {
906:
1.13 millert 907: code = togglevar(argc, argv, &bell, "Bell mode");
1.1 deraadt 908: }
909:
910: /*
1.13 millert 911: * Set command line editing
1.1 deraadt 912: */
1.63 martynas 913: #ifndef SMALL
1.48 deraadt 914: /*ARGSUSED*/
1.1 deraadt 915: void
1.47 deraadt 916: setedit(int argc, char *argv[])
1.1 deraadt 917: {
918:
1.13 millert 919: code = togglevar(argc, argv, &editing, "Editing mode");
1.18 millert 920: controlediting();
1.1 deraadt 921: }
1.17 millert 922: #endif /* !SMALL */
1.34 itojun 923:
924: /*
925: * Toggle use of IPv4 EPSV/EPRT
926: */
1.48 deraadt 927: /*ARGSUSED*/
1.34 itojun 928: void
1.47 deraadt 929: setepsv4(int argc, char *argv[])
1.34 itojun 930: {
931:
932: code = togglevar(argc, argv, &epsv4, "EPSV/EPRT on IPv4");
933: epsv4bad = 0;
934: }
1.1 deraadt 935:
936: /*
1.13 millert 937: * Turn on packet tracing.
1.1 deraadt 938: */
1.48 deraadt 939: /*ARGSUSED*/
1.1 deraadt 940: void
1.47 deraadt 941: settrace(int argc, char *argv[])
1.1 deraadt 942: {
943:
1.13 millert 944: code = togglevar(argc, argv, &trace, "Packet tracing");
1.1 deraadt 945: }
1.6 kstailey 946:
947: /*
1.13 millert 948: * Toggle hash mark printing during transfers, or set hash mark bytecount.
1.6 kstailey 949: */
1.48 deraadt 950: /*ARGSUSED*/
1.6 kstailey 951: void
1.47 deraadt 952: sethash(int argc, char *argv[])
1.6 kstailey 953: {
954: if (argc == 1)
1.13 millert 955: hash = !hash;
1.6 kstailey 956: else if (argc != 2) {
1.64 sobrado 957: fprintf(ttyout, "usage: %s [on | off | size]\n", argv[0]);
1.13 millert 958: code = -1;
959: return;
960: } else if (strcasecmp(argv[1], "on") == 0)
961: hash = 1;
962: else if (strcasecmp(argv[1], "off") == 0)
963: hash = 0;
964: else {
1.50 tedu 965: int nmark;
966: const char *errstr;
1.28 millert 967:
1.50 tedu 968: nmark = strtonum(argv[1], 1, INT_MAX, &errstr);
969: if (errstr) {
970: fprintf(ttyout, "bytecount value is %s: %s\n",
971: errstr, argv[1]);
1.13 millert 972: code = -1;
973: return;
1.6 kstailey 974: }
1.13 millert 975: mark = nmark;
976: hash = 1;
1.6 kstailey 977: }
1.20 deraadt 978: fprintf(ttyout, "Hash mark printing %s", onoff(hash));
1.13 millert 979: if (hash)
1.20 deraadt 980: fprintf(ttyout, " (%d bytes/hash mark)", mark);
981: fputs(".\n", ttyout);
1.13 millert 982: code = hash;
1.6 kstailey 983: }
984:
1.1 deraadt 985: /*
986: * Turn on printing of server echo's.
987: */
1.48 deraadt 988: /*ARGSUSED*/
1.1 deraadt 989: void
1.47 deraadt 990: setverbose(int argc, char *argv[])
1.1 deraadt 991: {
992:
1.13 millert 993: code = togglevar(argc, argv, &verbose, "Verbose mode");
1.1 deraadt 994: }
995:
996: /*
1.32 itojun 997: * Toggle PORT/LPRT cmd use before each data connection.
1.1 deraadt 998: */
1.48 deraadt 999: /*ARGSUSED*/
1.1 deraadt 1000: void
1.47 deraadt 1001: setport(int argc, char *argv[])
1.1 deraadt 1002: {
1003:
1.32 itojun 1004: code = togglevar(argc, argv, &sendport, "Use of PORT/LPRT cmds");
1.13 millert 1005: }
1006:
1007: /*
1008: * Toggle transfer progress bar.
1009: */
1.48 deraadt 1010: /*ARGSUSED*/
1.13 millert 1011: void
1.47 deraadt 1012: setprogress(int argc, char *argv[])
1.13 millert 1013: {
1014:
1015: code = togglevar(argc, argv, &progress, "Progress bar");
1.1 deraadt 1016: }
1017:
1018: /*
1.23 millert 1019: * Turn on interactive prompting during mget, mput, and mdelete.
1.1 deraadt 1020: */
1.48 deraadt 1021: /*ARGSUSED*/
1.1 deraadt 1022: void
1.47 deraadt 1023: setprompt(int argc, char *argv[])
1.1 deraadt 1024: {
1025:
1.13 millert 1026: code = togglevar(argc, argv, &interactive, "Interactive mode");
1.1 deraadt 1027: }
1028:
1029: /*
1.23 millert 1030: * Toggle gate-ftp mode, or set gate-ftp server
1031: */
1.48 deraadt 1032: /*ARGSUSED*/
1.23 millert 1033: void
1.47 deraadt 1034: setgate(int argc, char *argv[])
1.23 millert 1035: {
1036: static char gsbuf[MAXHOSTNAMELEN];
1037:
1038: if (argc > 3) {
1.64 sobrado 1039: fprintf(ttyout, "usage: %s [on | off | host [port]]\n",
1.23 millert 1040: argv[0]);
1041: code = -1;
1042: return;
1043: } else if (argc < 2) {
1044: gatemode = !gatemode;
1045: } else {
1046: if (argc == 2 && strcasecmp(argv[1], "on") == 0)
1047: gatemode = 1;
1048: else if (argc == 2 && strcasecmp(argv[1], "off") == 0)
1049: gatemode = 0;
1050: else {
1051: if (argc == 3) {
1.32 itojun 1052: gateport = strdup(argv[2]);
1.41 deraadt 1053: if (gateport == NULL)
1054: err(1, NULL);
1.23 millert 1055: }
1.36 lebel 1056: strlcpy(gsbuf, argv[1], sizeof(gsbuf));
1.23 millert 1057: gateserver = gsbuf;
1058: gatemode = 1;
1059: }
1060: }
1061: if (gatemode && (gateserver == NULL || *gateserver == '\0')) {
1062: fprintf(ttyout,
1063: "Disabling gate-ftp mode - no gate-ftp server defined.\n");
1064: gatemode = 0;
1065: } else {
1.32 itojun 1066: fprintf(ttyout, "Gate ftp: %s, server %s, port %s.\n",
1.23 millert 1067: onoff(gatemode),
1.32 itojun 1068: *gateserver ? gateserver : "(none)", gateport);
1.23 millert 1069: }
1070: code = gatemode;
1071: }
1072:
1073: /*
1074: * Toggle metacharacter interpretation on local file names.
1.1 deraadt 1075: */
1.48 deraadt 1076: /*ARGSUSED*/
1.1 deraadt 1077: void
1.47 deraadt 1078: setglob(int argc, char *argv[])
1.1 deraadt 1079: {
1.13 millert 1080:
1081: code = togglevar(argc, argv, &doglob, "Globbing");
1082: }
1083:
1084: /*
1.31 aaron 1085: * Toggle preserving modification times on retrieved files.
1.13 millert 1086: */
1.48 deraadt 1087: /*ARGSUSED*/
1.13 millert 1088: void
1.47 deraadt 1089: setpreserve(int argc, char *argv[])
1.13 millert 1090: {
1091:
1092: code = togglevar(argc, argv, &preserve, "Preserve modification times");
1.1 deraadt 1093: }
1094:
1095: /*
1.23 millert 1096: * Set debugging mode on/off and/or set level of debugging.
1.1 deraadt 1097: */
1.63 martynas 1098: #ifndef SMALL
1.48 deraadt 1099: /*ARGSUSED*/
1.1 deraadt 1100: void
1.47 deraadt 1101: setdebug(int argc, char *argv[])
1.1 deraadt 1102: {
1.13 millert 1103: if (argc > 2) {
1.64 sobrado 1104: fprintf(ttyout, "usage: %s [on | off | debuglevel]\n", argv[0]);
1.13 millert 1105: code = -1;
1106: return;
1107: } else if (argc == 2) {
1108: if (strcasecmp(argv[1], "on") == 0)
1109: debug = 1;
1110: else if (strcasecmp(argv[1], "off") == 0)
1111: debug = 0;
1112: else {
1.50 tedu 1113: const char *errstr;
1114: int val;
1.21 millert 1115:
1.50 tedu 1116: val = strtonum(argv[1], 0, INT_MAX, &errstr);
1117: if (errstr) {
1118: fprintf(ttyout, "debugging value is %s: %s\n",
1119: errstr, argv[1]);
1.13 millert 1120: code = -1;
1121: return;
1122: }
1.50 tedu 1123: debug = val;
1.1 deraadt 1124: }
1125: } else
1.13 millert 1126: debug = !debug;
1.1 deraadt 1127: if (debug)
1128: options |= SO_DEBUG;
1129: else
1130: options &= ~SO_DEBUG;
1.20 deraadt 1131: fprintf(ttyout, "Debugging %s (debug=%d).\n", onoff(debug), debug);
1.1 deraadt 1132: code = debug > 0;
1133: }
1.63 martynas 1134: #endif /* !SMALL */
1.1 deraadt 1135:
1136: /*
1.23 millert 1137: * Set current working directory on remote machine.
1.1 deraadt 1138: */
1.13 millert 1139: void
1.47 deraadt 1140: cd(int argc, char *argv[])
1.1 deraadt 1141: {
1.13 millert 1142: int r;
1.1 deraadt 1143:
1.13 millert 1144: if ((argc < 2 && !another(&argc, &argv, "remote-directory")) ||
1145: argc > 2) {
1.20 deraadt 1146: fprintf(ttyout, "usage: %s remote-directory\n", argv[0]);
1.1 deraadt 1147: code = -1;
1.13 millert 1148: return;
1.1 deraadt 1149: }
1.13 millert 1150: r = command("CWD %s", argv[1]);
1151: if (r == ERROR && code == 500) {
1152: if (verbose)
1.20 deraadt 1153: fputs("CWD command not recognized, trying XCWD.\n", ttyout);
1.13 millert 1154: r = command("XCWD %s", argv[1]);
1.42 deraadt 1155: }
1156: if (r == ERROR && code == 550) {
1157: dirchange = 0;
1158: return;
1.1 deraadt 1159: }
1.13 millert 1160: if (r == COMPLETE)
1161: dirchange = 1;
1.1 deraadt 1162: }
1163:
1164: /*
1.23 millert 1165: * Set current working directory on local machine.
1.1 deraadt 1166: */
1167: void
1.47 deraadt 1168: lcd(int argc, char *argv[])
1.1 deraadt 1169: {
1170: char buf[MAXPATHLEN];
1.23 millert 1171: char *oldargv1;
1.1 deraadt 1172:
1173: if (argc < 2)
1174: argc++, argv[1] = home;
1175: if (argc != 2) {
1.64 sobrado 1176: fprintf(ttyout, "usage: %s [local-directory]\n", argv[0]);
1.1 deraadt 1177: code = -1;
1178: return;
1179: }
1.23 millert 1180: oldargv1 = argv[1];
1.1 deraadt 1181: if (!globulize(&argv[1])) {
1182: code = -1;
1183: return;
1184: }
1185: if (chdir(argv[1]) < 0) {
1186: warn("local: %s", argv[1]);
1187: code = -1;
1.23 millert 1188: } else {
1189: if (getcwd(buf, sizeof(buf)) != NULL)
1190: fprintf(ttyout, "Local directory now %s\n", buf);
1191: else
1192: warn("getcwd: %s", argv[1]);
1193: code = 0;
1.1 deraadt 1194: }
1.23 millert 1195: if (oldargv1 != argv[1]) /* free up after globulize() */
1196: free(argv[1]);
1.1 deraadt 1197: }
1198:
1199: /*
1200: * Delete a single file.
1201: */
1202: void
1.48 deraadt 1203: deletecmd(int argc, char *argv[])
1.1 deraadt 1204: {
1205:
1.13 millert 1206: if ((argc < 2 && !another(&argc, &argv, "remote-file")) || argc > 2) {
1.20 deraadt 1207: fprintf(ttyout, "usage: %s remote-file\n", argv[0]);
1.1 deraadt 1208: code = -1;
1209: return;
1210: }
1.14 millert 1211: (void)command("DELE %s", argv[1]);
1.1 deraadt 1212: }
1213:
1214: /*
1215: * Delete multiple files.
1216: */
1217: void
1.47 deraadt 1218: mdelete(int argc, char *argv[])
1.1 deraadt 1219: {
1220: sig_t oldintr;
1221: char *cp;
1222:
1223: if (argc < 2 && !another(&argc, &argv, "remote-files")) {
1.20 deraadt 1224: fprintf(ttyout, "usage: %s remote-files\n", argv[0]);
1.1 deraadt 1225: code = -1;
1226: return;
1227: }
1228: mname = argv[0];
1229: mflag = 1;
1230: oldintr = signal(SIGINT, mabort);
1.14 millert 1231: (void)setjmp(jabort);
1.16 millert 1232: while ((cp = remglob(argv, 0, NULL)) != NULL) {
1.1 deraadt 1233: if (*cp == '\0') {
1234: mflag = 0;
1235: continue;
1236: }
1.63 martynas 1237: if (mflag && confirm(argv[0], cp)) {
1.14 millert 1238: (void)command("DELE %s", cp);
1.1 deraadt 1239: if (!mflag && fromatty) {
1.63 martynas 1240: if (confirm(argv[0], NULL))
1.61 martynas 1241: mflag = 1;
1.1 deraadt 1242: }
1243: }
1244: }
1.14 millert 1245: (void)signal(SIGINT, oldintr);
1.1 deraadt 1246: mflag = 0;
1247: }
1248:
1249: /*
1250: * Rename a remote file.
1251: */
1252: void
1.47 deraadt 1253: renamefile(int argc, char *argv[])
1.1 deraadt 1254: {
1255:
1256: if (argc < 2 && !another(&argc, &argv, "from-name"))
1257: goto usage;
1.13 millert 1258: if ((argc < 3 && !another(&argc, &argv, "to-name")) || argc > 3) {
1.1 deraadt 1259: usage:
1.20 deraadt 1260: fprintf(ttyout, "usage: %s from-name to-name\n", argv[0]);
1.1 deraadt 1261: code = -1;
1262: return;
1263: }
1264: if (command("RNFR %s", argv[1]) == CONTINUE)
1.14 millert 1265: (void)command("RNTO %s", argv[2]);
1.1 deraadt 1266: }
1267:
1268: /*
1.23 millert 1269: * Get a directory listing of remote files.
1.1 deraadt 1270: */
1271: void
1.47 deraadt 1272: ls(int argc, char *argv[])
1.1 deraadt 1273: {
1.13 millert 1274: const char *cmd;
1.23 millert 1275: char *oldargv2, *globargv2;
1.1 deraadt 1276:
1277: if (argc < 2)
1278: argc++, argv[1] = NULL;
1279: if (argc < 3)
1280: argc++, argv[2] = "-";
1281: if (argc > 3) {
1.64 sobrado 1282: fprintf(ttyout, "usage: %s [remote-directory [local-file]]\n",
1283: argv[0]);
1.1 deraadt 1284: code = -1;
1285: return;
1286: }
1.33 millert 1287: cmd = strcmp(argv[0], "nlist") == 0 ? "NLST" : "LIST";
1.23 millert 1288: oldargv2 = argv[2];
1.1 deraadt 1289: if (strcmp(argv[2], "-") && !globulize(&argv[2])) {
1290: code = -1;
1291: return;
1292: }
1.23 millert 1293: globargv2 = argv[2];
1294: if (strcmp(argv[2], "-") && *argv[2] != '|' && (!globulize(&argv[2]) ||
1.63 martynas 1295: !confirm("output to local-file:", argv[2]))) {
1.23 millert 1296: code = -1;
1297: goto freels;
1.1 deraadt 1298: }
1.23 millert 1299: recvrequest(cmd, argv[2], argv[1], "w", 0, 0);
1.3 downsj 1300:
1301: /* flush results in case commands are coming from a pipe */
1.20 deraadt 1302: fflush(ttyout);
1.23 millert 1303: freels:
1304: if (argv[2] != globargv2) /* free up after globulize() */
1305: free(argv[2]);
1306: if (globargv2 != oldargv2)
1307: free(globargv2);
1.1 deraadt 1308: }
1309:
1310: /*
1.23 millert 1311: * Get a directory listing of multiple remote files.
1.1 deraadt 1312: */
1313: void
1.47 deraadt 1314: mls(int argc, char *argv[])
1.1 deraadt 1315: {
1316: sig_t oldintr;
1.60 martynas 1317: int i;
1.51 ray 1318: char lmode[1], *dest, *odest;
1.1 deraadt 1319:
1320: if (argc < 2 && !another(&argc, &argv, "remote-files"))
1321: goto usage;
1322: if (argc < 3 && !another(&argc, &argv, "local-file")) {
1323: usage:
1.20 deraadt 1324: fprintf(ttyout, "usage: %s remote-files local-file\n", argv[0]);
1.1 deraadt 1325: code = -1;
1326: return;
1327: }
1.23 millert 1328: odest = dest = argv[argc - 1];
1.1 deraadt 1329: argv[argc - 1] = NULL;
1330: if (strcmp(dest, "-") && *dest != '|')
1331: if (!globulize(&dest) ||
1.63 martynas 1332: !confirm("output to local-file:", dest)) {
1.1 deraadt 1333: code = -1;
1334: return;
1335: }
1336: mname = argv[0];
1337: mflag = 1;
1338: oldintr = signal(SIGINT, mabort);
1.14 millert 1339: (void)setjmp(jabort);
1.1 deraadt 1340: for (i = 1; mflag && i < argc-1; ++i) {
1.51 ray 1341: *lmode = (i == 1) ? 'w' : 'a';
1342: recvrequest("LIST", dest, argv[i], lmode, 0, 0);
1.1 deraadt 1343: if (!mflag && fromatty) {
1.63 martynas 1344: if (confirm(argv[0], NULL))
1.1 deraadt 1345: mflag ++;
1346: }
1347: }
1.14 millert 1348: (void)signal(SIGINT, oldintr);
1.1 deraadt 1349: mflag = 0;
1.23 millert 1350: if (dest != odest) /* free up after globulize() */
1351: free(dest);
1.1 deraadt 1352: }
1353:
1354: /*
1355: * Do a shell escape
1356: */
1357: /*ARGSUSED*/
1358: void
1.47 deraadt 1359: shell(int argc, char *argv[])
1.1 deraadt 1360: {
1361: pid_t pid;
1362: sig_t old1, old2;
1.51 ray 1363: char shellnam[MAXPATHLEN], *shellp, *namep;
1.24 millert 1364: int wait_status;
1.1 deraadt 1365:
1366: old1 = signal (SIGINT, SIG_IGN);
1367: old2 = signal (SIGQUIT, SIG_IGN);
1368: if ((pid = fork()) == 0) {
1369: for (pid = 3; pid < 20; pid++)
1.14 millert 1370: (void)close(pid);
1371: (void)signal(SIGINT, SIG_DFL);
1372: (void)signal(SIGQUIT, SIG_DFL);
1.51 ray 1373: shellp = getenv("SHELL");
1374: if (shellp == NULL || *shellp == '\0')
1375: shellp = _PATH_BSHELL;
1376: namep = strrchr(shellp, '/');
1.1 deraadt 1377: if (namep == NULL)
1.51 ray 1378: namep = shellp;
1.13 millert 1379: shellnam[0] = '-';
1.36 lebel 1380: (void)strlcpy(shellnam + 1, ++namep, sizeof(shellnam) - 1);
1.1 deraadt 1381: if (strcmp(namep, "sh") != 0)
1382: shellnam[0] = '+';
1.63 martynas 1383: #ifndef SMALL
1.1 deraadt 1384: if (debug) {
1.51 ray 1385: fputs(shellp, ttyout);
1.21 millert 1386: fputc('\n', ttyout);
1.20 deraadt 1387: (void)fflush(ttyout);
1.1 deraadt 1388: }
1.63 martynas 1389: #endif /* !SMALL */
1.1 deraadt 1390: if (argc > 1) {
1.51 ray 1391: execl(shellp, shellnam, "-c", altarg, (char *)0);
1.1 deraadt 1392: }
1393: else {
1.51 ray 1394: execl(shellp, shellnam, (char *)0);
1.1 deraadt 1395: }
1.51 ray 1396: warn("%s", shellp);
1.1 deraadt 1397: code = -1;
1398: exit(1);
1399: }
1400: if (pid > 0)
1.24 millert 1401: while (wait(&wait_status) != pid)
1.1 deraadt 1402: ;
1.14 millert 1403: (void)signal(SIGINT, old1);
1404: (void)signal(SIGQUIT, old2);
1.1 deraadt 1405: if (pid == -1) {
1.16 millert 1406: warn("Try again later");
1.1 deraadt 1407: code = -1;
1408: }
1409: else {
1410: code = 0;
1411: }
1412: }
1413:
1414: /*
1415: * Send new user information (re-login)
1416: */
1417: void
1.47 deraadt 1418: user(int argc, char *argv[])
1.1 deraadt 1419: {
1.51 ray 1420: char acctname[80];
1.1 deraadt 1421: int n, aflag = 0;
1422:
1423: if (argc < 2)
1.14 millert 1424: (void)another(&argc, &argv, "username");
1.1 deraadt 1425: if (argc < 2 || argc > 4) {
1.64 sobrado 1426: fprintf(ttyout, "usage: %s username [password [account]]\n",
1427: argv[0]);
1.1 deraadt 1428: code = -1;
1429: return;
1430: }
1431: n = command("USER %s", argv[1]);
1432: if (n == CONTINUE) {
1433: if (argc < 3 )
1.56 millert 1434: argv[2] = getpass("Password:"), argc++;
1.1 deraadt 1435: n = command("PASS %s", argv[2]);
1436: }
1437: if (n == CONTINUE) {
1438: if (argc < 4) {
1.20 deraadt 1439: (void)fputs("Account: ", ttyout);
1440: (void)fflush(ttyout);
1.59 martynas 1441: if (fgets(acctname, sizeof(acctname), stdin) == NULL) {
1442: clearerr(stdin);
1.53 ray 1443: goto fail;
1.59 martynas 1444: }
1.57 gilles 1445:
1446: acctname[strcspn(acctname, "\n")] = '\0';
1447:
1.51 ray 1448: argv[3] = acctname;
1449: argc++;
1.1 deraadt 1450: }
1451: n = command("ACCT %s", argv[3]);
1452: aflag++;
1453: }
1454: if (n != COMPLETE) {
1.53 ray 1455: fail:
1.20 deraadt 1456: fputs("Login failed.\n", ttyout);
1.1 deraadt 1457: return;
1458: }
1459: if (!aflag && argc == 4) {
1.14 millert 1460: (void)command("ACCT %s", argv[3]);
1.1 deraadt 1461: }
1.19 millert 1462: connected = -1;
1.1 deraadt 1463: }
1464:
1465: /*
1.13 millert 1466: * Print working directory on remote machine.
1.1 deraadt 1467: */
1.48 deraadt 1468: /*ARGSUSED*/
1.1 deraadt 1469: void
1.47 deraadt 1470: pwd(int argc, char *argv[])
1.1 deraadt 1471: {
1472: int oldverbose = verbose;
1473:
1474: /*
1475: * If we aren't verbose, this doesn't do anything!
1476: */
1477: verbose = 1;
1478: if (command("PWD") == ERROR && code == 500) {
1.20 deraadt 1479: fputs("PWD command not recognized, trying XPWD.\n", ttyout);
1.14 millert 1480: (void)command("XPWD");
1.1 deraadt 1481: }
1482: verbose = oldverbose;
1483: }
1484:
1485: /*
1.13 millert 1486: * Print working directory on local machine.
1487: */
1.48 deraadt 1488: /* ARGSUSED */
1.13 millert 1489: void
1.47 deraadt 1490: lpwd(int argc, char *argv[])
1.13 millert 1491: {
1492: char buf[MAXPATHLEN];
1493:
1494: if (getcwd(buf, sizeof(buf)) != NULL)
1.20 deraadt 1495: fprintf(ttyout, "Local directory %s\n", buf);
1.13 millert 1496: else
1497: warn("getcwd");
1498: code = 0;
1499: }
1500:
1501: /*
1.1 deraadt 1502: * Make a directory.
1503: */
1504: void
1.47 deraadt 1505: makedir(int argc, char *argv[])
1.1 deraadt 1506: {
1507:
1.13 millert 1508: if ((argc < 2 && !another(&argc, &argv, "directory-name")) ||
1509: argc > 2) {
1.20 deraadt 1510: fprintf(ttyout, "usage: %s directory-name\n", argv[0]);
1.1 deraadt 1511: code = -1;
1512: return;
1513: }
1514: if (command("MKD %s", argv[1]) == ERROR && code == 500) {
1515: if (verbose)
1.20 deraadt 1516: fputs("MKD command not recognized, trying XMKD.\n", ttyout);
1.14 millert 1517: (void)command("XMKD %s", argv[1]);
1.1 deraadt 1518: }
1519: }
1520:
1521: /*
1522: * Remove a directory.
1523: */
1524: void
1.47 deraadt 1525: removedir(int argc, char *argv[])
1.1 deraadt 1526: {
1527:
1.13 millert 1528: if ((argc < 2 && !another(&argc, &argv, "directory-name")) ||
1529: argc > 2) {
1.20 deraadt 1530: fprintf(ttyout, "usage: %s directory-name\n", argv[0]);
1.1 deraadt 1531: code = -1;
1532: return;
1533: }
1534: if (command("RMD %s", argv[1]) == ERROR && code == 500) {
1535: if (verbose)
1.20 deraadt 1536: fputs("RMD command not recognized, trying XRMD.\n", ttyout);
1.14 millert 1537: (void)command("XRMD %s", argv[1]);
1.1 deraadt 1538: }
1539: }
1540:
1541: /*
1542: * Send a line, verbatim, to the remote machine.
1543: */
1544: void
1.47 deraadt 1545: quote(int argc, char *argv[])
1.1 deraadt 1546: {
1547:
1548: if (argc < 2 && !another(&argc, &argv, "command line to send")) {
1.64 sobrado 1549: fprintf(ttyout, "usage: %s arg ...\n", argv[0]);
1.1 deraadt 1550: code = -1;
1551: return;
1552: }
1553: quote1("", argc, argv);
1554: }
1555:
1556: /*
1557: * Send a SITE command to the remote machine. The line
1558: * is sent verbatim to the remote machine, except that the
1559: * word "SITE" is added at the front.
1560: */
1561: void
1.47 deraadt 1562: site(int argc, char *argv[])
1.1 deraadt 1563: {
1564:
1565: if (argc < 2 && !another(&argc, &argv, "arguments to SITE command")) {
1.64 sobrado 1566: fprintf(ttyout, "usage: %s arg ...\n", argv[0]);
1.1 deraadt 1567: code = -1;
1568: return;
1569: }
1.26 weingart 1570: quote1("SITE", argc, argv);
1.1 deraadt 1571: }
1572:
1573: /*
1574: * Turn argv[1..argc) into a space-separated string, then prepend initial text.
1575: * Send the result as a one-line command and get response.
1576: */
1577: void
1.47 deraadt 1578: quote1(const char *initial, int argc, char *argv[])
1.1 deraadt 1579: {
1580: int i, len;
1581: char buf[BUFSIZ]; /* must be >= sizeof(line) */
1582:
1.36 lebel 1583: (void)strlcpy(buf, initial, sizeof(buf));
1.1 deraadt 1584: if (argc > 1) {
1.26 weingart 1585: for (i = 1, len = strlen(buf); i < argc && len < sizeof(buf)-1; i++) {
1586: /* Space for next arg */
1587: if (len > 1)
1588: buf[len++] = ' ';
1589:
1590: /* Sanity check */
1591: if (len >= sizeof(buf) - 1)
1592: break;
1593:
1.27 millert 1594: /* Copy next argument, NUL terminate always */
1.36 lebel 1595: strlcpy(&buf[len], argv[i], sizeof(buf) - len);
1.26 weingart 1596:
1597: /* Update string length */
1598: len = strlen(buf);
1.1 deraadt 1599: }
1600: }
1.26 weingart 1601:
1.35 aaron 1602: /* Make double (triple?) sure the sucker is NUL terminated */
1.26 weingart 1603: buf[sizeof(buf) - 1] = '\0';
1604:
1.29 deraadt 1605: if (command("%s", buf) == PRELIM) {
1.1 deraadt 1606: while (getreply(0) == PRELIM)
1607: continue;
1608: }
1609: }
1610:
1611: void
1.47 deraadt 1612: do_chmod(int argc, char *argv[])
1.1 deraadt 1613: {
1614:
1615: if (argc < 2 && !another(&argc, &argv, "mode"))
1616: goto usage;
1.64 sobrado 1617: if ((argc < 3 && !another(&argc, &argv, "file")) || argc > 3) {
1.1 deraadt 1618: usage:
1.64 sobrado 1619: fprintf(ttyout, "usage: %s mode file\n", argv[0]);
1.1 deraadt 1620: code = -1;
1621: return;
1622: }
1.14 millert 1623: (void)command("SITE CHMOD %s %s", argv[1], argv[2]);
1.1 deraadt 1624: }
1625:
1626: void
1.47 deraadt 1627: do_umask(int argc, char *argv[])
1.1 deraadt 1628: {
1629: int oldverbose = verbose;
1630:
1631: verbose = 1;
1.14 millert 1632: (void)command(argc == 1 ? "SITE UMASK" : "SITE UMASK %s", argv[1]);
1.1 deraadt 1633: verbose = oldverbose;
1634: }
1635:
1636: void
1.47 deraadt 1637: idle(int argc, char *argv[])
1.1 deraadt 1638: {
1639: int oldverbose = verbose;
1640:
1641: verbose = 1;
1.14 millert 1642: (void)command(argc == 1 ? "SITE IDLE" : "SITE IDLE %s", argv[1]);
1.1 deraadt 1643: verbose = oldverbose;
1644: }
1645:
1646: /*
1647: * Ask the other side for help.
1648: */
1649: void
1.47 deraadt 1650: rmthelp(int argc, char *argv[])
1.1 deraadt 1651: {
1652: int oldverbose = verbose;
1653:
1654: verbose = 1;
1.14 millert 1655: (void)command(argc == 1 ? "HELP" : "HELP %s", argv[1]);
1.1 deraadt 1656: verbose = oldverbose;
1657: }
1658:
1659: /*
1660: * Terminate session and exit.
1661: */
1.48 deraadt 1662: /*ARGSUSED*/
1.1 deraadt 1663: void
1.47 deraadt 1664: quit(int argc, char *argv[])
1.1 deraadt 1665: {
1666:
1667: if (connected)
1668: disconnect(0, 0);
1669: pswitch(1);
1670: if (connected) {
1671: disconnect(0, 0);
1672: }
1673: exit(0);
1674: }
1675:
1676: /*
1677: * Terminate session, but don't exit.
1678: */
1.48 deraadt 1679: /* ARGSUSED */
1.1 deraadt 1680: void
1.47 deraadt 1681: disconnect(int argc, char *argv[])
1.1 deraadt 1682: {
1683:
1684: if (!connected)
1685: return;
1.14 millert 1686: (void)command("QUIT");
1.1 deraadt 1687: if (cout) {
1.14 millert 1688: (void)fclose(cout);
1.1 deraadt 1689: }
1690: cout = NULL;
1691: connected = 0;
1692: data = -1;
1693: if (!proxy) {
1694: macnum = 0;
1695: }
1696: }
1697:
1698: void
1.47 deraadt 1699: account(int argc, char *argv[])
1.1 deraadt 1700: {
1.13 millert 1701: char *ap;
1.1 deraadt 1702:
1.13 millert 1703: if (argc > 2) {
1.20 deraadt 1704: fprintf(ttyout, "usage: %s [password]\n", argv[0]);
1.13 millert 1705: code = -1;
1706: return;
1.1 deraadt 1707: }
1.13 millert 1708: else if (argc == 2)
1709: ap = argv[1];
1710: else
1.1 deraadt 1711: ap = getpass("Account:");
1.14 millert 1712: (void)command("ACCT %s", ap);
1.1 deraadt 1713: }
1714:
1715: jmp_buf abortprox;
1716:
1.48 deraadt 1717: /* ARGSUSED */
1.1 deraadt 1718: void
1.48 deraadt 1719: proxabort(int signo)
1.1 deraadt 1720: {
1721:
1.13 millert 1722: alarmtimer(0);
1.1 deraadt 1723: if (!proxy) {
1724: pswitch(1);
1725: }
1726: if (connected) {
1727: proxflag = 1;
1728: }
1729: else {
1730: proxflag = 0;
1731: }
1732: pswitch(0);
1.13 millert 1733: longjmp(abortprox, 1);
1.1 deraadt 1734: }
1735:
1736: void
1.47 deraadt 1737: doproxy(int argc, char *argv[])
1.1 deraadt 1738: {
1739: struct cmd *c;
1.13 millert 1740: int cmdpos;
1.1 deraadt 1741: sig_t oldintr;
1742:
1743: if (argc < 2 && !another(&argc, &argv, "command")) {
1.20 deraadt 1744: fprintf(ttyout, "usage: %s command\n", argv[0]);
1.1 deraadt 1745: code = -1;
1746: return;
1747: }
1748: c = getcmd(argv[1]);
1749: if (c == (struct cmd *) -1) {
1.20 deraadt 1750: fputs("?Ambiguous command.\n", ttyout);
1751: (void)fflush(ttyout);
1.1 deraadt 1752: code = -1;
1753: return;
1754: }
1755: if (c == 0) {
1.20 deraadt 1756: fputs("?Invalid command.\n", ttyout);
1757: (void)fflush(ttyout);
1.1 deraadt 1758: code = -1;
1759: return;
1760: }
1761: if (!c->c_proxy) {
1.20 deraadt 1762: fputs("?Invalid proxy command.\n", ttyout);
1763: (void)fflush(ttyout);
1.1 deraadt 1764: code = -1;
1765: return;
1766: }
1767: if (setjmp(abortprox)) {
1768: code = -1;
1769: return;
1770: }
1771: oldintr = signal(SIGINT, proxabort);
1772: pswitch(1);
1773: if (c->c_conn && !connected) {
1.20 deraadt 1774: fputs("Not connected.\n", ttyout);
1775: (void)fflush(ttyout);
1.1 deraadt 1776: pswitch(0);
1.14 millert 1777: (void)signal(SIGINT, oldintr);
1.1 deraadt 1778: code = -1;
1779: return;
1780: }
1.13 millert 1781: cmdpos = strcspn(line, " \t");
1782: if (cmdpos > 0) /* remove leading "proxy " from input buffer */
1783: memmove(line, line + cmdpos + 1, strlen(line) - cmdpos + 1);
1.1 deraadt 1784: (*c->c_handler)(argc-1, argv+1);
1785: if (connected) {
1786: proxflag = 1;
1787: }
1788: else {
1789: proxflag = 0;
1790: }
1791: pswitch(0);
1.14 millert 1792: (void)signal(SIGINT, oldintr);
1.1 deraadt 1793: }
1794:
1795: void
1.47 deraadt 1796: setcase(int argc, char *argv[])
1.1 deraadt 1797: {
1798:
1.13 millert 1799: code = togglevar(argc, argv, &mcase, "Case mapping");
1.1 deraadt 1800: }
1801:
1802: void
1.47 deraadt 1803: setcr(int argc, char *argv[])
1.1 deraadt 1804: {
1805:
1.13 millert 1806: code = togglevar(argc, argv, &crflag, "Carriage Return stripping");
1.1 deraadt 1807: }
1808:
1809: void
1.47 deraadt 1810: setntrans(int argc, char *argv[])
1.1 deraadt 1811: {
1812: if (argc == 1) {
1813: ntflag = 0;
1.20 deraadt 1814: fputs("Ntrans off.\n", ttyout);
1.1 deraadt 1815: code = ntflag;
1816: return;
1817: }
1818: ntflag++;
1819: code = ntflag;
1.36 lebel 1820: (void)strlcpy(ntin, argv[1], sizeof(ntin));
1.1 deraadt 1821: if (argc == 2) {
1822: ntout[0] = '\0';
1823: return;
1824: }
1.36 lebel 1825: (void)strlcpy(ntout, argv[2], sizeof(ntout));
1.1 deraadt 1826: }
1827:
1828: char *
1.47 deraadt 1829: dotrans(char *name)
1.1 deraadt 1830: {
1831: static char new[MAXPATHLEN];
1832: char *cp1, *cp2 = new;
1833: int i, ostop, found;
1834:
1835: for (ostop = 0; *(ntout + ostop) && ostop < 16; ostop++)
1836: continue;
1837: for (cp1 = name; *cp1; cp1++) {
1838: found = 0;
1839: for (i = 0; *(ntin + i) && i < 16; i++) {
1840: if (*cp1 == *(ntin + i)) {
1841: found++;
1842: if (i < ostop) {
1843: *cp2++ = *(ntout + i);
1844: }
1845: break;
1846: }
1847: }
1848: if (!found) {
1849: *cp2++ = *cp1;
1850: }
1851: }
1852: *cp2 = '\0';
1853: return (new);
1854: }
1855:
1856: void
1.47 deraadt 1857: setnmap(int argc, char *argv[])
1.1 deraadt 1858: {
1859: char *cp;
1860:
1861: if (argc == 1) {
1862: mapflag = 0;
1.20 deraadt 1863: fputs("Nmap off.\n", ttyout);
1.1 deraadt 1864: code = mapflag;
1865: return;
1866: }
1.64 sobrado 1867: if ((argc < 3 && !another(&argc, &argv, "outpattern")) || argc > 3) {
1868: fprintf(ttyout, "usage: %s [inpattern outpattern]\n", argv[0]);
1.1 deraadt 1869: code = -1;
1870: return;
1871: }
1872: mapflag = 1;
1873: code = 1;
1874: cp = strchr(altarg, ' ');
1875: if (proxy) {
1876: while(*++cp == ' ')
1877: continue;
1878: altarg = cp;
1879: cp = strchr(altarg, ' ');
1880: }
1881: *cp = '\0';
1.14 millert 1882: (void)strncpy(mapin, altarg, MAXPATHLEN - 1);
1.1 deraadt 1883: while (*++cp == ' ')
1884: continue;
1.14 millert 1885: (void)strncpy(mapout, cp, MAXPATHLEN - 1);
1.1 deraadt 1886: }
1887:
1888: char *
1.47 deraadt 1889: domap(char *name)
1.1 deraadt 1890: {
1891: static char new[MAXPATHLEN];
1892: char *cp1 = name, *cp2 = mapin;
1893: char *tp[9], *te[9];
1894: int i, toks[9], toknum = 0, match = 1;
1895:
1896: for (i=0; i < 9; ++i) {
1897: toks[i] = 0;
1898: }
1899: while (match && *cp1 && *cp2) {
1900: switch (*cp2) {
1901: case '\\':
1902: if (*++cp2 != *cp1) {
1903: match = 0;
1904: }
1905: break;
1906: case '$':
1907: if (*(cp2+1) >= '1' && (*cp2+1) <= '9') {
1908: if (*cp1 != *(++cp2+1)) {
1909: toks[toknum = *cp2 - '1']++;
1910: tp[toknum] = cp1;
1911: while (*++cp1 && *(cp2+1)
1912: != *cp1);
1913: te[toknum] = cp1;
1914: }
1915: cp2++;
1916: break;
1917: }
1918: /* FALLTHROUGH */
1919: default:
1920: if (*cp2 != *cp1) {
1921: match = 0;
1922: }
1923: break;
1924: }
1925: if (match && *cp1) {
1926: cp1++;
1927: }
1928: if (match && *cp2) {
1929: cp2++;
1930: }
1931: }
1932: if (!match && *cp1) /* last token mismatch */
1933: {
1934: toks[toknum] = 0;
1935: }
1936: cp1 = new;
1937: *cp1 = '\0';
1938: cp2 = mapout;
1939: while (*cp2) {
1940: match = 0;
1941: switch (*cp2) {
1942: case '\\':
1943: if (*(cp2 + 1)) {
1944: *cp1++ = *++cp2;
1945: }
1946: break;
1947: case '[':
1948: LOOP:
1.13 millert 1949: if (*++cp2 == '$' && isdigit(*(cp2+1))) {
1.1 deraadt 1950: if (*++cp2 == '0') {
1951: char *cp3 = name;
1952:
1953: while (*cp3) {
1954: *cp1++ = *cp3++;
1955: }
1956: match = 1;
1957: }
1958: else if (toks[toknum = *cp2 - '1']) {
1959: char *cp3 = tp[toknum];
1960:
1961: while (cp3 != te[toknum]) {
1962: *cp1++ = *cp3++;
1963: }
1964: match = 1;
1965: }
1966: }
1967: else {
1.13 millert 1968: while (*cp2 && *cp2 != ',' &&
1.1 deraadt 1969: *cp2 != ']') {
1970: if (*cp2 == '\\') {
1971: cp2++;
1972: }
1973: else if (*cp2 == '$' &&
1974: isdigit(*(cp2+1))) {
1975: if (*++cp2 == '0') {
1976: char *cp3 = name;
1977:
1978: while (*cp3) {
1979: *cp1++ = *cp3++;
1980: }
1981: }
1982: else if (toks[toknum =
1983: *cp2 - '1']) {
1984: char *cp3=tp[toknum];
1985:
1986: while (cp3 !=
1987: te[toknum]) {
1988: *cp1++ = *cp3++;
1989: }
1990: }
1991: }
1992: else if (*cp2) {
1993: *cp1++ = *cp2++;
1994: }
1995: }
1996: if (!*cp2) {
1.20 deraadt 1997: fputs(
1998: "nmap: unbalanced brackets.\n", ttyout);
1.1 deraadt 1999: return (name);
2000: }
2001: match = 1;
2002: cp2--;
2003: }
2004: if (match) {
2005: while (*++cp2 && *cp2 != ']') {
2006: if (*cp2 == '\\' && *(cp2 + 1)) {
2007: cp2++;
2008: }
2009: }
2010: if (!*cp2) {
1.20 deraadt 2011: fputs(
2012: "nmap: unbalanced brackets.\n", ttyout);
1.1 deraadt 2013: return (name);
2014: }
2015: break;
2016: }
2017: switch (*++cp2) {
2018: case ',':
2019: goto LOOP;
2020: case ']':
2021: break;
2022: default:
2023: cp2--;
2024: goto LOOP;
2025: }
2026: break;
2027: case '$':
2028: if (isdigit(*(cp2 + 1))) {
2029: if (*++cp2 == '0') {
2030: char *cp3 = name;
2031:
2032: while (*cp3) {
2033: *cp1++ = *cp3++;
2034: }
2035: }
2036: else if (toks[toknum = *cp2 - '1']) {
2037: char *cp3 = tp[toknum];
2038:
2039: while (cp3 != te[toknum]) {
2040: *cp1++ = *cp3++;
2041: }
2042: }
2043: break;
2044: }
1.51 ray 2045: /* FALLTHROUGH */
1.1 deraadt 2046: default:
2047: *cp1++ = *cp2;
2048: break;
2049: }
2050: cp2++;
2051: }
2052: *cp1 = '\0';
2053: if (!*new) {
2054: return (name);
2055: }
2056: return (new);
2057: }
2058:
2059: void
1.47 deraadt 2060: setpassive(int argc, char *argv[])
1.1 deraadt 2061: {
2062:
1.15 millert 2063: code = togglevar(argc, argv, &passivemode,
2064: verbose ? "Passive mode" : NULL);
1.1 deraadt 2065: }
2066:
2067: void
1.47 deraadt 2068: setsunique(int argc, char *argv[])
1.1 deraadt 2069: {
2070:
1.13 millert 2071: code = togglevar(argc, argv, &sunique, "Store unique");
1.1 deraadt 2072: }
2073:
2074: void
1.47 deraadt 2075: setrunique(int argc, char *argv[])
1.1 deraadt 2076: {
2077:
1.13 millert 2078: code = togglevar(argc, argv, &runique, "Receive unique");
1.1 deraadt 2079: }
2080:
1.13 millert 2081: /* change directory to parent directory */
1.48 deraadt 2082: /* ARGSUSED */
1.1 deraadt 2083: void
1.47 deraadt 2084: cdup(int argc, char *argv[])
1.1 deraadt 2085: {
1.13 millert 2086: int r;
1.1 deraadt 2087:
1.13 millert 2088: r = command("CDUP");
2089: if (r == ERROR && code == 500) {
1.1 deraadt 2090: if (verbose)
1.20 deraadt 2091: fputs("CDUP command not recognized, trying XCUP.\n", ttyout);
1.13 millert 2092: r = command("XCUP");
1.1 deraadt 2093: }
1.13 millert 2094: if (r == COMPLETE)
2095: dirchange = 1;
1.1 deraadt 2096: }
2097:
1.23 millert 2098: /*
2099: * Restart transfer at specific point
2100: */
1.1 deraadt 2101: void
1.47 deraadt 2102: restart(int argc, char *argv[])
1.1 deraadt 2103: {
1.27 millert 2104: quad_t nrestart_point;
2105: char *ep;
1.1 deraadt 2106:
2107: if (argc != 2)
1.20 deraadt 2108: fputs("restart: offset not specified.\n", ttyout);
1.1 deraadt 2109: else {
1.38 millert 2110: nrestart_point = strtoq(argv[1], &ep, 10);
1.27 millert 2111: if (nrestart_point == QUAD_MAX || *ep != '\0')
2112: fputs("restart: invalid offset.\n", ttyout);
2113: else {
1.39 millert 2114: fprintf(ttyout, "Restarting at %lld. Execute get, put "
2115: "or append to initiate transfer\n",
1.37 deraadt 2116: (long long)nrestart_point);
1.27 millert 2117: restart_point = nrestart_point;
2118: }
1.1 deraadt 2119: }
2120: }
2121:
1.23 millert 2122: /*
2123: * Show remote system type
2124: */
1.48 deraadt 2125: /* ARGSUSED */
1.1 deraadt 2126: void
1.47 deraadt 2127: syst(int argc, char *argv[])
1.1 deraadt 2128: {
2129:
1.14 millert 2130: (void)command("SYST");
1.1 deraadt 2131: }
2132:
2133: void
1.47 deraadt 2134: macdef(int argc, char *argv[])
1.1 deraadt 2135: {
2136: char *tmp;
2137: int c;
2138:
2139: if (macnum == 16) {
1.20 deraadt 2140: fputs("Limit of 16 macros have already been defined.\n", ttyout);
1.1 deraadt 2141: code = -1;
2142: return;
2143: }
1.64 sobrado 2144: if ((argc < 2 && !another(&argc, &argv, "macro-name")) || argc > 2) {
2145: fprintf(ttyout, "usage: %s macro-name\n", argv[0]);
1.1 deraadt 2146: code = -1;
2147: return;
2148: }
1.16 millert 2149: if (interactive)
1.20 deraadt 2150: fputs(
2151: "Enter macro line by line, terminating it with a null line.\n", ttyout);
1.36 lebel 2152: (void)strlcpy(macros[macnum].mac_name, argv[1],
2153: sizeof(macros[macnum].mac_name));
1.14 millert 2154: if (macnum == 0)
1.1 deraadt 2155: macros[macnum].mac_start = macbuf;
1.14 millert 2156: else
1.1 deraadt 2157: macros[macnum].mac_start = macros[macnum - 1].mac_end + 1;
2158: tmp = macros[macnum].mac_start;
2159: while (tmp != macbuf+4096) {
2160: if ((c = getchar()) == EOF) {
1.20 deraadt 2161: fputs("macdef: end of file encountered.\n", ttyout);
1.1 deraadt 2162: code = -1;
2163: return;
2164: }
2165: if ((*tmp = c) == '\n') {
2166: if (tmp == macros[macnum].mac_start) {
2167: macros[macnum++].mac_end = tmp;
2168: code = 0;
2169: return;
2170: }
2171: if (*(tmp-1) == '\0') {
2172: macros[macnum++].mac_end = tmp - 1;
2173: code = 0;
2174: return;
2175: }
2176: *tmp = '\0';
2177: }
2178: tmp++;
2179: }
2180: while (1) {
2181: while ((c = getchar()) != '\n' && c != EOF)
2182: /* LOOP */;
2183: if (c == EOF || getchar() == '\n') {
1.20 deraadt 2184: fputs("Macro not defined - 4K buffer exceeded.\n", ttyout);
1.1 deraadt 2185: code = -1;
2186: return;
2187: }
2188: }
2189: }
2190:
2191: /*
1.23 millert 2192: * Get size of file on remote machine
1.1 deraadt 2193: */
2194: void
1.47 deraadt 2195: sizecmd(int argc, char *argv[])
1.1 deraadt 2196: {
1.13 millert 2197: off_t size;
1.1 deraadt 2198:
1.64 sobrado 2199: if ((argc < 2 && !another(&argc, &argv, "file")) || argc > 2) {
2200: fprintf(ttyout, "usage: %s file\n", argv[0]);
1.1 deraadt 2201: code = -1;
2202: return;
2203: }
1.13 millert 2204: size = remotesize(argv[1], 1);
2205: if (size != -1)
1.37 deraadt 2206: fprintf(ttyout, "%s\t%lld\n", argv[1], (long long)size);
1.13 millert 2207: code = size;
1.1 deraadt 2208: }
2209:
2210: /*
1.23 millert 2211: * Get last modification time of file on remote machine
1.1 deraadt 2212: */
2213: void
1.47 deraadt 2214: modtime(int argc, char *argv[])
1.1 deraadt 2215: {
1.13 millert 2216: time_t mtime;
1.1 deraadt 2217:
1.64 sobrado 2218: if ((argc < 2 && !another(&argc, &argv, "file")) || argc > 2) {
2219: fprintf(ttyout, "usage: %s file\n", argv[0]);
1.1 deraadt 2220: code = -1;
2221: return;
2222: }
1.13 millert 2223: mtime = remotemodtime(argv[1], 1);
2224: if (mtime != -1)
1.20 deraadt 2225: fprintf(ttyout, "%s\t%s", argv[1], asctime(localtime(&mtime)));
1.13 millert 2226: code = mtime;
1.1 deraadt 2227: }
2228:
2229: /*
1.23 millert 2230: * Show status on remote machine
1.1 deraadt 2231: */
2232: void
1.47 deraadt 2233: rmtstatus(int argc, char *argv[])
1.1 deraadt 2234: {
2235:
1.14 millert 2236: (void)command(argc > 1 ? "STAT %s" : "STAT" , argv[1]);
1.1 deraadt 2237: }
2238:
2239: /*
1.23 millert 2240: * Get file if modtime is more recent than current file
1.1 deraadt 2241: */
2242: void
1.47 deraadt 2243: newer(int argc, char *argv[])
1.1 deraadt 2244: {
2245:
2246: if (getit(argc, argv, -1, "w"))
1.20 deraadt 2247: fprintf(ttyout, "Local file \"%s\" is newer than remote file \"%s\".\n",
1.1 deraadt 2248: argv[2], argv[1]);
1.16 millert 2249: }
2250:
2251: /*
2252: * Display one file through $PAGER (defaults to "more").
2253: */
2254: void
1.47 deraadt 2255: page(int argc, char *argv[])
1.16 millert 2256: {
2257: int orestart_point, ohash, overbose;
1.23 millert 2258: char *p, *pager, *oldargv1;
1.16 millert 2259:
1.64 sobrado 2260: if ((argc < 2 && !another(&argc, &argv, "file")) || argc > 2) {
2261: fprintf(ttyout, "usage: %s file\n", argv[0]);
1.16 millert 2262: code = -1;
2263: return;
2264: }
1.23 millert 2265: oldargv1 = argv[1];
1.16 millert 2266: if (!globulize(&argv[1])) {
2267: code = -1;
2268: return;
2269: }
2270: p = getenv("PAGER");
1.30 pjanzen 2271: if (p == NULL || (*p == '\0'))
1.16 millert 2272: p = PAGER;
1.44 deraadt 2273: if (asprintf(&pager, "|%s", p) == -1)
1.16 millert 2274: errx(1, "Can't allocate memory for $PAGER");
2275:
2276: orestart_point = restart_point;
2277: ohash = hash;
2278: overbose = verbose;
2279: restart_point = hash = verbose = 0;
1.23 millert 2280: recvrequest("RETR", pager, argv[1], "r+w", 1, 0);
1.16 millert 2281: (void)free(pager);
2282: restart_point = orestart_point;
2283: hash = ohash;
2284: verbose = overbose;
1.23 millert 2285: if (oldargv1 != argv[1]) /* free up after globulize() */
2286: free(argv[1]);
1.1 deraadt 2287: }