1 1.144 christos /* $NetBSD: cmds.c,v 1.144 2024/10/04 18:05:43 christos Exp $ */ 2 1.39 thorpej 3 1.39 thorpej /*- 4 1.141 lukem * Copyright (c) 1996-2021 The NetBSD Foundation, Inc. 5 1.39 thorpej * All rights reserved. 6 1.39 thorpej * 7 1.39 thorpej * This code is derived from software contributed to The NetBSD Foundation 8 1.70 lukem * by Luke Mewburn. 9 1.70 lukem * 10 1.70 lukem * This code is derived from software contributed to The NetBSD Foundation 11 1.39 thorpej * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 12 1.39 thorpej * NASA Ames Research Center. 13 1.39 thorpej * 14 1.39 thorpej * Redistribution and use in source and binary forms, with or without 15 1.39 thorpej * modification, are permitted provided that the following conditions 16 1.39 thorpej * are met: 17 1.39 thorpej * 1. Redistributions of source code must retain the above copyright 18 1.39 thorpej * notice, this list of conditions and the following disclaimer. 19 1.39 thorpej * 2. Redistributions in binary form must reproduce the above copyright 20 1.39 thorpej * notice, this list of conditions and the following disclaimer in the 21 1.39 thorpej * documentation and/or other materials provided with the distribution. 22 1.39 thorpej * 23 1.39 thorpej * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 24 1.39 thorpej * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 25 1.39 thorpej * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 26 1.39 thorpej * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 27 1.39 thorpej * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 28 1.39 thorpej * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 29 1.39 thorpej * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 30 1.39 thorpej * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 31 1.39 thorpej * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 32 1.39 thorpej * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33 1.39 thorpej * POSSIBILITY OF SUCH DAMAGE. 34 1.39 thorpej */ 35 1.8 tls 36 1.1 cgd /* 37 1.4 cgd * Copyright (c) 1985, 1989, 1993, 1994 38 1.4 cgd * The Regents of the University of California. All rights reserved. 39 1.1 cgd * 40 1.1 cgd * Redistribution and use in source and binary forms, with or without 41 1.1 cgd * modification, are permitted provided that the following conditions 42 1.1 cgd * are met: 43 1.1 cgd * 1. Redistributions of source code must retain the above copyright 44 1.1 cgd * notice, this list of conditions and the following disclaimer. 45 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 46 1.1 cgd * notice, this list of conditions and the following disclaimer in the 47 1.1 cgd * documentation and/or other materials provided with the distribution. 48 1.102 agc * 3. Neither the name of the University nor the names of its contributors 49 1.1 cgd * may be used to endorse or promote products derived from this software 50 1.1 cgd * without specific prior written permission. 51 1.1 cgd * 52 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 53 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 54 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 55 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 56 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 57 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 58 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 59 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 60 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 61 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 62 1.1 cgd * SUCH DAMAGE. 63 1.1 cgd */ 64 1.1 cgd 65 1.65 lukem /* 66 1.65 lukem * Copyright (C) 1997 and 1998 WIDE Project. 67 1.65 lukem * All rights reserved. 68 1.112 lukem * 69 1.65 lukem * Redistribution and use in source and binary forms, with or without 70 1.65 lukem * modification, are permitted provided that the following conditions 71 1.65 lukem * are met: 72 1.65 lukem * 1. Redistributions of source code must retain the above copyright 73 1.65 lukem * notice, this list of conditions and the following disclaimer. 74 1.65 lukem * 2. Redistributions in binary form must reproduce the above copyright 75 1.65 lukem * notice, this list of conditions and the following disclaimer in the 76 1.65 lukem * documentation and/or other materials provided with the distribution. 77 1.65 lukem * 3. Neither the name of the project nor the names of its contributors 78 1.65 lukem * may be used to endorse or promote products derived from this software 79 1.65 lukem * without specific prior written permission. 80 1.112 lukem * 81 1.65 lukem * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 82 1.65 lukem * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 83 1.65 lukem * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 84 1.65 lukem * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 85 1.65 lukem * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 86 1.65 lukem * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 87 1.65 lukem * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 88 1.65 lukem * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 89 1.65 lukem * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 90 1.65 lukem * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 91 1.65 lukem * SUCH DAMAGE. 92 1.65 lukem */ 93 1.65 lukem 94 1.25 lukem #include <sys/cdefs.h> 95 1.1 cgd #ifndef lint 96 1.8 tls #if 0 97 1.8 tls static char sccsid[] = "@(#)cmds.c 8.6 (Berkeley) 10/9/94"; 98 1.8 tls #else 99 1.144 christos __RCSID("$NetBSD: cmds.c,v 1.144 2024/10/04 18:05:43 christos Exp $"); 100 1.8 tls #endif 101 1.1 cgd #endif /* not lint */ 102 1.1 cgd 103 1.1 cgd /* 104 1.1 cgd * FTP User Program -- Command Routines. 105 1.1 cgd */ 106 1.16 lukem #include <sys/types.h> 107 1.16 lukem #include <sys/socket.h> 108 1.16 lukem #include <sys/stat.h> 109 1.1 cgd #include <sys/wait.h> 110 1.1 cgd #include <arpa/ftp.h> 111 1.1 cgd 112 1.4 cgd #include <ctype.h> 113 1.4 cgd #include <err.h> 114 1.133 christos #include <errno.h> 115 1.4 cgd #include <glob.h> 116 1.42 lukem #include <limits.h> 117 1.4 cgd #include <netdb.h> 118 1.67 lukem #include <paths.h> 119 1.129 lukem #include <stddef.h> 120 1.1 cgd #include <stdio.h> 121 1.4 cgd #include <stdlib.h> 122 1.4 cgd #include <string.h> 123 1.35 kleink #include <time.h> 124 1.4 cgd #include <unistd.h> 125 1.1 cgd 126 1.1 cgd #include "ftp_var.h" 127 1.81 lukem #include "version.h" 128 1.1 cgd 129 1.121 lukem static struct types { 130 1.129 lukem const char *t_name; 131 1.129 lukem const char *t_mode; 132 1.129 lukem int t_type; 133 1.129 lukem const char *t_arg; 134 1.1 cgd } types[] = { 135 1.1 cgd { "ascii", "A", TYPE_A, 0 }, 136 1.1 cgd { "binary", "I", TYPE_I, 0 }, 137 1.1 cgd { "image", "I", TYPE_I, 0 }, 138 1.1 cgd { "ebcdic", "E", TYPE_E, 0 }, 139 1.1 cgd { "tenex", "L", TYPE_L, bytename }, 140 1.129 lukem { NULL, NULL, 0, NULL } 141 1.1 cgd }; 142 1.1 cgd 143 1.121 lukem static sigjmp_buf jabort; 144 1.74 lukem 145 1.85 lukem static int confirm(const char *, const char *); 146 1.132 joerg __dead static void mintr(int); 147 1.121 lukem static void mabort(const char *); 148 1.129 lukem static void set_type(const char *); 149 1.74 lukem 150 1.144 christos static char *doprocess(char *, size_t, char *, int, int, int); 151 1.144 christos static char *domap(char *, size_t, const char *); 152 1.144 christos static char *docase(char *, size_t, const char *); 153 1.144 christos static char *dotrans(char *, size_t, const char *); 154 1.110 christos 155 1.121 lukem /* 156 1.121 lukem * Confirm if "cmd" is to be performed upon "file". 157 1.121 lukem * If "file" is NULL, generate a "Continue with" prompt instead. 158 1.121 lukem */ 159 1.74 lukem static int 160 1.85 lukem confirm(const char *cmd, const char *file) 161 1.74 lukem { 162 1.115 lukem const char *errormsg; 163 1.128 lukem char cline[BUFSIZ]; 164 1.121 lukem const char *promptleft, *promptright; 165 1.74 lukem 166 1.74 lukem if (!interactive || confirmrest) 167 1.74 lukem return (1); 168 1.121 lukem if (file == NULL) { 169 1.121 lukem promptleft = "Continue with"; 170 1.121 lukem promptright = cmd; 171 1.121 lukem } else { 172 1.121 lukem promptleft = cmd; 173 1.121 lukem promptright = file; 174 1.121 lukem } 175 1.143 christos for (;;) { 176 1.121 lukem fprintf(ttyout, "%s %s [anpqy?]? ", promptleft, promptright); 177 1.74 lukem (void)fflush(ttyout); 178 1.130 roy if (get_line(stdin, cline, sizeof(cline), &errormsg) < 0) { 179 1.74 lukem mflag = 0; 180 1.121 lukem fprintf(ttyout, "%s; %s aborted\n", errormsg, cmd); 181 1.74 lukem return (0); 182 1.74 lukem } 183 1.128 lukem switch (tolower((unsigned char)*cline)) { 184 1.74 lukem case 'a': 185 1.74 lukem confirmrest = 1; 186 1.74 lukem fprintf(ttyout, 187 1.74 lukem "Prompting off for duration of %s.\n", cmd); 188 1.74 lukem break; 189 1.74 lukem case 'p': 190 1.74 lukem interactive = 0; 191 1.74 lukem fputs("Interactive mode: off.\n", ttyout); 192 1.74 lukem break; 193 1.74 lukem case 'q': 194 1.74 lukem mflag = 0; 195 1.121 lukem fprintf(ttyout, "%s aborted.\n", cmd); 196 1.75 lukem /* FALLTHROUGH */ 197 1.75 lukem case 'n': 198 1.74 lukem return (0); 199 1.74 lukem case '?': 200 1.74 lukem fprintf(ttyout, 201 1.76 lukem " confirmation options:\n" 202 1.74 lukem "\ta answer `yes' for the duration of %s\n" 203 1.74 lukem "\tn answer `no' for this file\n" 204 1.74 lukem "\tp turn off `prompt' mode\n" 205 1.74 lukem "\tq stop the current %s\n" 206 1.74 lukem "\ty answer `yes' for this file\n" 207 1.74 lukem "\t? this help list\n", 208 1.74 lukem cmd, cmd); 209 1.75 lukem continue; /* back to while(1) */ 210 1.74 lukem } 211 1.75 lukem return (1); 212 1.74 lukem } 213 1.74 lukem /* NOTREACHED */ 214 1.74 lukem } 215 1.74 lukem 216 1.1 cgd /* 217 1.1 cgd * Set transfer type. 218 1.1 cgd */ 219 1.4 cgd void 220 1.85 lukem settype(int argc, char *argv[]) 221 1.1 cgd { 222 1.4 cgd struct types *p; 223 1.1 cgd 224 1.88 lukem if (argc == 0 || argc > 2) { 225 1.129 lukem const char *sep; 226 1.1 cgd 227 1.116 christos UPRINTF("usage: %s [", argv[0]); 228 1.1 cgd sep = " "; 229 1.1 cgd for (p = types; p->t_name; p++) { 230 1.37 lukem fprintf(ttyout, "%s%s", sep, p->t_name); 231 1.1 cgd sep = " | "; 232 1.1 cgd } 233 1.37 lukem fputs(" ]\n", ttyout); 234 1.1 cgd code = -1; 235 1.1 cgd return; 236 1.1 cgd } 237 1.1 cgd if (argc < 2) { 238 1.37 lukem fprintf(ttyout, "Using %s mode to transfer files.\n", typename); 239 1.1 cgd code = 0; 240 1.1 cgd return; 241 1.1 cgd } 242 1.129 lukem set_type(argv[1]); 243 1.129 lukem } 244 1.129 lukem 245 1.129 lukem void 246 1.129 lukem set_type(const char *ttype) 247 1.129 lukem { 248 1.129 lukem struct types *p; 249 1.129 lukem int comret; 250 1.129 lukem 251 1.1 cgd for (p = types; p->t_name; p++) 252 1.129 lukem if (strcmp(ttype, p->t_name) == 0) 253 1.1 cgd break; 254 1.1 cgd if (p->t_name == 0) { 255 1.129 lukem fprintf(ttyout, "%s: unknown mode.\n", ttype); 256 1.1 cgd code = -1; 257 1.1 cgd return; 258 1.1 cgd } 259 1.1 cgd if ((p->t_arg != NULL) && (*(p->t_arg) != '\0')) 260 1.19 lukem comret = command("TYPE %s %s", p->t_mode, p->t_arg); 261 1.1 cgd else 262 1.1 cgd comret = command("TYPE %s", p->t_mode); 263 1.1 cgd if (comret == COMPLETE) { 264 1.63 lukem (void)strlcpy(typename, p->t_name, sizeof(typename)); 265 1.1 cgd curtype = type = p->t_type; 266 1.1 cgd } 267 1.1 cgd } 268 1.1 cgd 269 1.1 cgd /* 270 1.1 cgd * Internal form of settype; changes current type in use with server 271 1.1 cgd * without changing our notion of the type for data transfers. 272 1.1 cgd * Used to change to and from ascii for listings. 273 1.1 cgd */ 274 1.4 cgd void 275 1.85 lukem changetype(int newtype, int show) 276 1.1 cgd { 277 1.4 cgd struct types *p; 278 1.1 cgd int comret, oldverbose = verbose; 279 1.1 cgd 280 1.1 cgd if (newtype == 0) 281 1.1 cgd newtype = TYPE_I; 282 1.1 cgd if (newtype == curtype) 283 1.1 cgd return; 284 1.118 christos if (ftp_debug == 0 && show == 0) 285 1.1 cgd verbose = 0; 286 1.1 cgd for (p = types; p->t_name; p++) 287 1.1 cgd if (newtype == p->t_type) 288 1.1 cgd break; 289 1.1 cgd if (p->t_name == 0) { 290 1.120 lukem errx(1, "changetype: unknown type %d", newtype); 291 1.1 cgd } 292 1.1 cgd if (newtype == TYPE_L && bytename[0] != '\0') 293 1.1 cgd comret = command("TYPE %s %s", p->t_mode, bytename); 294 1.1 cgd else 295 1.1 cgd comret = command("TYPE %s", p->t_mode); 296 1.1 cgd if (comret == COMPLETE) 297 1.1 cgd curtype = newtype; 298 1.1 cgd verbose = oldverbose; 299 1.1 cgd } 300 1.1 cgd 301 1.1 cgd /* 302 1.1 cgd * Set binary transfer type. 303 1.1 cgd */ 304 1.1 cgd /*VARARGS*/ 305 1.4 cgd void 306 1.85 lukem setbinary(int argc, char *argv[]) 307 1.1 cgd { 308 1.4 cgd 309 1.88 lukem if (argc == 0) { 310 1.116 christos UPRINTF("usage: %s\n", argv[0]); 311 1.76 lukem code = -1; 312 1.76 lukem return; 313 1.76 lukem } 314 1.129 lukem set_type("binary"); 315 1.1 cgd } 316 1.1 cgd 317 1.1 cgd /* 318 1.1 cgd * Set ascii transfer type. 319 1.1 cgd */ 320 1.1 cgd /*VARARGS*/ 321 1.4 cgd void 322 1.85 lukem setascii(int argc, char *argv[]) 323 1.1 cgd { 324 1.4 cgd 325 1.88 lukem if (argc == 0) { 326 1.116 christos UPRINTF("usage: %s\n", argv[0]); 327 1.76 lukem code = -1; 328 1.76 lukem return; 329 1.76 lukem } 330 1.129 lukem set_type("ascii"); 331 1.1 cgd } 332 1.1 cgd 333 1.1 cgd /* 334 1.1 cgd * Set tenex transfer type. 335 1.1 cgd */ 336 1.1 cgd /*VARARGS*/ 337 1.4 cgd void 338 1.85 lukem settenex(int argc, char *argv[]) 339 1.1 cgd { 340 1.4 cgd 341 1.88 lukem if (argc == 0) { 342 1.116 christos UPRINTF("usage: %s\n", argv[0]); 343 1.76 lukem code = -1; 344 1.76 lukem return; 345 1.76 lukem } 346 1.129 lukem set_type("tenex"); 347 1.1 cgd } 348 1.1 cgd 349 1.1 cgd /* 350 1.1 cgd * Set file transfer mode. 351 1.1 cgd */ 352 1.1 cgd /*ARGSUSED*/ 353 1.4 cgd void 354 1.85 lukem setftmode(int argc, char *argv[]) 355 1.1 cgd { 356 1.1 cgd 357 1.88 lukem if (argc != 2) { 358 1.116 christos UPRINTF("usage: %s mode-name\n", argv[0]); 359 1.76 lukem code = -1; 360 1.76 lukem return; 361 1.76 lukem } 362 1.37 lukem fprintf(ttyout, "We only support %s mode, sorry.\n", modename); 363 1.1 cgd code = -1; 364 1.1 cgd } 365 1.1 cgd 366 1.1 cgd /* 367 1.1 cgd * Set file transfer format. 368 1.1 cgd */ 369 1.1 cgd /*ARGSUSED*/ 370 1.4 cgd void 371 1.85 lukem setform(int argc, char *argv[]) 372 1.1 cgd { 373 1.1 cgd 374 1.88 lukem if (argc != 2) { 375 1.116 christos UPRINTF("usage: %s format\n", argv[0]); 376 1.76 lukem code = -1; 377 1.76 lukem return; 378 1.76 lukem } 379 1.37 lukem fprintf(ttyout, "We only support %s format, sorry.\n", formname); 380 1.1 cgd code = -1; 381 1.1 cgd } 382 1.1 cgd 383 1.1 cgd /* 384 1.1 cgd * Set file transfer structure. 385 1.1 cgd */ 386 1.1 cgd /*ARGSUSED*/ 387 1.4 cgd void 388 1.85 lukem setstruct(int argc, char *argv[]) 389 1.1 cgd { 390 1.1 cgd 391 1.88 lukem if (argc != 2) { 392 1.116 christos UPRINTF("usage: %s struct-mode\n", argv[0]); 393 1.76 lukem code = -1; 394 1.76 lukem return; 395 1.76 lukem } 396 1.37 lukem fprintf(ttyout, "We only support %s structure, sorry.\n", structname); 397 1.1 cgd code = -1; 398 1.1 cgd } 399 1.1 cgd 400 1.1 cgd /* 401 1.1 cgd * Send a single file. 402 1.1 cgd */ 403 1.4 cgd void 404 1.85 lukem put(int argc, char *argv[]) 405 1.1 cgd { 406 1.110 christos char buf[MAXPATHLEN]; 407 1.129 lukem const char *cmd; 408 1.1 cgd int loc = 0; 409 1.110 christos char *locfile; 410 1.144 christos char *remfile; 411 1.1 cgd 412 1.1 cgd if (argc == 2) { 413 1.1 cgd argc++; 414 1.1 cgd argv[2] = argv[1]; 415 1.1 cgd loc++; 416 1.1 cgd } 417 1.88 lukem if (argc == 0 || (argc == 1 && !another(&argc, &argv, "local-file"))) 418 1.1 cgd goto usage; 419 1.10 lukem if ((argc < 3 && !another(&argc, &argv, "remote-file")) || argc > 3) { 420 1.88 lukem usage: 421 1.116 christos UPRINTF("usage: %s local-file [remote-file]\n", argv[0]); 422 1.1 cgd code = -1; 423 1.1 cgd return; 424 1.1 cgd } 425 1.63 lukem if ((locfile = globulize(argv[1])) == NULL) { 426 1.1 cgd code = -1; 427 1.1 cgd return; 428 1.1 cgd } 429 1.63 lukem remfile = argv[2]; 430 1.63 lukem if (loc) /* If argv[2] is a copy of the old argv[1], update it */ 431 1.63 lukem remfile = locfile; 432 1.1 cgd cmd = (argv[0][0] == 'a') ? "APPE" : ((sunique) ? "STOU" : "STOR"); 433 1.110 christos remfile = doprocess(buf, sizeof(buf), remfile, 434 1.110 christos 0, loc && ntflag, loc && mapflag); 435 1.63 lukem sendrequest(cmd, locfile, remfile, 436 1.63 lukem locfile != argv[1] || remfile != argv[2]); 437 1.63 lukem free(locfile); 438 1.1 cgd } 439 1.1 cgd 440 1.144 christos static char * 441 1.144 christos doprocess(char *dst, size_t dlen, char *src, 442 1.110 christos int casef, int transf, int mapf) 443 1.110 christos { 444 1.110 christos if (casef) 445 1.110 christos src = docase(dst, dlen, src); 446 1.110 christos if (transf) 447 1.110 christos src = dotrans(dst, dlen, src); 448 1.110 christos if (mapf) 449 1.110 christos src = domap(dst, dlen, src); 450 1.110 christos return src; 451 1.110 christos } 452 1.110 christos 453 1.1 cgd /* 454 1.1 cgd * Send multiple files. 455 1.1 cgd */ 456 1.4 cgd void 457 1.85 lukem mput(int argc, char *argv[]) 458 1.1 cgd { 459 1.4 cgd int i; 460 1.82 lukem sigfunc oldintr; 461 1.1 cgd int ointer; 462 1.110 christos const char *tp; 463 1.1 cgd 464 1.88 lukem if (argc == 0 || (argc == 1 && !another(&argc, &argv, "local-files"))) { 465 1.116 christos UPRINTF("usage: %s local-files\n", argv[0]); 466 1.1 cgd code = -1; 467 1.1 cgd return; 468 1.1 cgd } 469 1.1 cgd mflag = 1; 470 1.72 lukem oldintr = xsignal(SIGINT, mintr); 471 1.72 lukem if (sigsetjmp(jabort, 1)) 472 1.121 lukem mabort(argv[0]); 473 1.1 cgd if (proxy) { 474 1.63 lukem char *cp; 475 1.1 cgd 476 1.19 lukem while ((cp = remglob(argv, 0, NULL)) != NULL) { 477 1.76 lukem if (*cp == '\0' || !connected) { 478 1.1 cgd mflag = 0; 479 1.1 cgd continue; 480 1.1 cgd } 481 1.1 cgd if (mflag && confirm(argv[0], cp)) { 482 1.110 christos char buf[MAXPATHLEN]; 483 1.110 christos tp = doprocess(buf, sizeof(buf), cp, 484 1.110 christos mcase, ntflag, mapflag); 485 1.1 cgd sendrequest((sunique) ? "STOU" : "STOR", 486 1.1 cgd cp, tp, cp != tp || !interactive); 487 1.1 cgd if (!mflag && fromatty) { 488 1.1 cgd ointer = interactive; 489 1.1 cgd interactive = 1; 490 1.121 lukem if (confirm(argv[0], NULL)) { 491 1.1 cgd mflag++; 492 1.1 cgd } 493 1.1 cgd interactive = ointer; 494 1.1 cgd } 495 1.1 cgd } 496 1.1 cgd } 497 1.72 lukem goto cleanupmput; 498 1.1 cgd } 499 1.76 lukem for (i = 1; i < argc && connected; i++) { 500 1.9 lukem char **cpp; 501 1.4 cgd glob_t gl; 502 1.4 cgd int flags; 503 1.1 cgd 504 1.1 cgd if (!doglob) { 505 1.1 cgd if (mflag && confirm(argv[0], argv[i])) { 506 1.110 christos char buf[MAXPATHLEN]; 507 1.110 christos tp = doprocess(buf, sizeof(buf), argv[i], 508 1.110 christos 0, ntflag, mapflag); 509 1.1 cgd sendrequest((sunique) ? "STOU" : "STOR", 510 1.1 cgd argv[i], tp, tp != argv[i] || !interactive); 511 1.1 cgd if (!mflag && fromatty) { 512 1.1 cgd ointer = interactive; 513 1.1 cgd interactive = 1; 514 1.121 lukem if (confirm(argv[0], NULL)) { 515 1.1 cgd mflag++; 516 1.1 cgd } 517 1.1 cgd interactive = ointer; 518 1.1 cgd } 519 1.1 cgd } 520 1.1 cgd continue; 521 1.1 cgd } 522 1.4 cgd 523 1.4 cgd memset(&gl, 0, sizeof(gl)); 524 1.38 kleink flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_TILDE; 525 1.4 cgd if (glob(argv[i], flags, NULL, &gl) || gl.gl_pathc == 0) { 526 1.120 lukem warnx("Glob pattern `%s' not found", argv[i]); 527 1.4 cgd globfree(&gl); 528 1.1 cgd continue; 529 1.1 cgd } 530 1.76 lukem for (cpp = gl.gl_pathv; cpp && *cpp != NULL && connected; 531 1.76 lukem cpp++) { 532 1.1 cgd if (mflag && confirm(argv[0], *cpp)) { 533 1.110 christos char buf[MAXPATHLEN]; 534 1.110 christos tp = *cpp; 535 1.110 christos tp = doprocess(buf, sizeof(buf), *cpp, 536 1.110 christos 0, ntflag, mapflag); 537 1.1 cgd sendrequest((sunique) ? "STOU" : "STOR", 538 1.1 cgd *cpp, tp, *cpp != tp || !interactive); 539 1.1 cgd if (!mflag && fromatty) { 540 1.1 cgd ointer = interactive; 541 1.1 cgd interactive = 1; 542 1.121 lukem if (confirm(argv[0], NULL)) { 543 1.1 cgd mflag++; 544 1.1 cgd } 545 1.1 cgd interactive = ointer; 546 1.1 cgd } 547 1.1 cgd } 548 1.1 cgd } 549 1.4 cgd globfree(&gl); 550 1.1 cgd } 551 1.88 lukem cleanupmput: 552 1.62 lukem (void)xsignal(SIGINT, oldintr); 553 1.1 cgd mflag = 0; 554 1.1 cgd } 555 1.1 cgd 556 1.4 cgd void 557 1.85 lukem reget(int argc, char *argv[]) 558 1.1 cgd { 559 1.4 cgd 560 1.134 christos (void)getit(argc, argv, 1, restart_point ? "r+" : "a"); 561 1.1 cgd } 562 1.1 cgd 563 1.4 cgd void 564 1.85 lukem get(int argc, char *argv[]) 565 1.1 cgd { 566 1.4 cgd 567 1.134 christos (void)getit(argc, argv, 0, restart_point ? "r+" : "w"); 568 1.1 cgd } 569 1.1 cgd 570 1.1 cgd /* 571 1.1 cgd * Receive one file. 572 1.92 lukem * If restartit is 1, restart the xfer always. 573 1.92 lukem * If restartit is -1, restart the xfer only if the remote file is newer. 574 1.1 cgd */ 575 1.4 cgd int 576 1.128 lukem getit(int argc, char *argv[], int restartit, const char *gmode) 577 1.1 cgd { 578 1.112 lukem int loc, rval; 579 1.144 christos char *remfile, *olocfile, *locfile; 580 1.112 lukem char buf[MAXPATHLEN]; 581 1.1 cgd 582 1.94 lukem loc = rval = 0; 583 1.1 cgd if (argc == 2) { 584 1.1 cgd argc++; 585 1.1 cgd argv[2] = argv[1]; 586 1.1 cgd loc++; 587 1.1 cgd } 588 1.88 lukem if (argc == 0 || (argc == 1 && !another(&argc, &argv, "remote-file"))) 589 1.1 cgd goto usage; 590 1.10 lukem if ((argc < 3 && !another(&argc, &argv, "local-file")) || argc > 3) { 591 1.88 lukem usage: 592 1.116 christos UPRINTF("usage: %s remote-file [local-file]\n", argv[0]); 593 1.1 cgd code = -1; 594 1.1 cgd return (0); 595 1.1 cgd } 596 1.63 lukem remfile = argv[1]; 597 1.63 lukem if ((olocfile = globulize(argv[2])) == NULL) { 598 1.1 cgd code = -1; 599 1.1 cgd return (0); 600 1.1 cgd } 601 1.110 christos locfile = doprocess(buf, sizeof(buf), olocfile, 602 1.110 christos loc && mcase, loc && ntflag, loc && mapflag); 603 1.1 cgd if (restartit) { 604 1.1 cgd struct stat stbuf; 605 1.1 cgd int ret; 606 1.1 cgd 607 1.88 lukem if (! features[FEAT_REST_STREAM]) { 608 1.88 lukem fprintf(ttyout, 609 1.88 lukem "Restart is not supported by the remote server.\n"); 610 1.88 lukem return (0); 611 1.88 lukem } 612 1.63 lukem ret = stat(locfile, &stbuf); 613 1.1 cgd if (restartit == 1) { 614 1.1 cgd if (ret < 0) { 615 1.133 christos if (errno != ENOENT) { 616 1.133 christos warn("Can't stat `%s'", locfile); 617 1.133 christos goto freegetit; 618 1.133 christos } 619 1.133 christos restart_point = 0; 620 1.1 cgd } 621 1.133 christos else 622 1.133 christos restart_point = stbuf.st_size; 623 1.1 cgd } else { 624 1.1 cgd if (ret == 0) { 625 1.10 lukem time_t mtime; 626 1.1 cgd 627 1.13 lukem mtime = remotemodtime(argv[1], 0); 628 1.10 lukem if (mtime == -1) 629 1.27 lukem goto freegetit; 630 1.27 lukem if (stbuf.st_mtime >= mtime) { 631 1.27 lukem rval = 1; 632 1.27 lukem goto freegetit; 633 1.27 lukem } 634 1.1 cgd } 635 1.1 cgd } 636 1.1 cgd } 637 1.1 cgd 638 1.128 lukem recvrequest("RETR", locfile, remfile, gmode, 639 1.63 lukem remfile != argv[1] || locfile != argv[2], loc); 640 1.1 cgd restart_point = 0; 641 1.88 lukem freegetit: 642 1.63 lukem (void)free(olocfile); 643 1.27 lukem return (rval); 644 1.1 cgd } 645 1.1 cgd 646 1.4 cgd /* ARGSUSED */ 647 1.121 lukem static void 648 1.85 lukem mintr(int signo) 649 1.1 cgd { 650 1.72 lukem 651 1.72 lukem alarmtimer(0); 652 1.74 lukem if (fromatty) 653 1.74 lukem write(fileno(ttyout), "\n", 1); 654 1.72 lukem siglongjmp(jabort, 1); 655 1.72 lukem } 656 1.72 lukem 657 1.121 lukem static void 658 1.121 lukem mabort(const char *cmd) 659 1.72 lukem { 660 1.10 lukem int ointer, oconf; 661 1.1 cgd 662 1.1 cgd if (mflag && fromatty) { 663 1.1 cgd ointer = interactive; 664 1.10 lukem oconf = confirmrest; 665 1.1 cgd interactive = 1; 666 1.10 lukem confirmrest = 0; 667 1.121 lukem if (confirm(cmd, NULL)) { 668 1.1 cgd interactive = ointer; 669 1.10 lukem confirmrest = oconf; 670 1.72 lukem return; 671 1.1 cgd } 672 1.1 cgd interactive = ointer; 673 1.10 lukem confirmrest = oconf; 674 1.1 cgd } 675 1.1 cgd mflag = 0; 676 1.1 cgd } 677 1.1 cgd 678 1.1 cgd /* 679 1.1 cgd * Get multiple files. 680 1.1 cgd */ 681 1.4 cgd void 682 1.85 lukem mget(int argc, char *argv[]) 683 1.1 cgd { 684 1.82 lukem sigfunc oldintr; 685 1.92 lukem int ointer; 686 1.144 christos char *cp, *tp; 687 1.129 lukem int volatile restartit; 688 1.1 cgd 689 1.88 lukem if (argc == 0 || 690 1.76 lukem (argc == 1 && !another(&argc, &argv, "remote-files"))) { 691 1.116 christos UPRINTF("usage: %s remote-files\n", argv[0]); 692 1.1 cgd code = -1; 693 1.1 cgd return; 694 1.1 cgd } 695 1.1 cgd mflag = 1; 696 1.92 lukem restart_point = 0; 697 1.92 lukem restartit = 0; 698 1.92 lukem if (strcmp(argv[0], "mreget") == 0) { 699 1.92 lukem if (! features[FEAT_REST_STREAM]) { 700 1.92 lukem fprintf(ttyout, 701 1.92 lukem "Restart is not supported by the remote server.\n"); 702 1.92 lukem return; 703 1.92 lukem } 704 1.92 lukem restartit = 1; 705 1.92 lukem } 706 1.72 lukem oldintr = xsignal(SIGINT, mintr); 707 1.72 lukem if (sigsetjmp(jabort, 1)) 708 1.121 lukem mabort(argv[0]); 709 1.19 lukem while ((cp = remglob(argv, proxy, NULL)) != NULL) { 710 1.110 christos char buf[MAXPATHLEN]; 711 1.76 lukem if (*cp == '\0' || !connected) { 712 1.1 cgd mflag = 0; 713 1.1 cgd continue; 714 1.1 cgd } 715 1.109 lukem if (! mflag) 716 1.109 lukem continue; 717 1.109 lukem if (! fileindir(cp, localcwd)) { 718 1.109 lukem fprintf(ttyout, "Skipping non-relative filename `%s'\n", 719 1.109 lukem cp); 720 1.109 lukem continue; 721 1.109 lukem } 722 1.109 lukem if (!confirm(argv[0], cp)) 723 1.92 lukem continue; 724 1.110 christos tp = doprocess(buf, sizeof(buf), cp, mcase, ntflag, mapflag); 725 1.92 lukem if (restartit) { 726 1.92 lukem struct stat stbuf; 727 1.92 lukem 728 1.92 lukem if (stat(tp, &stbuf) == 0) 729 1.92 lukem restart_point = stbuf.st_size; 730 1.92 lukem else 731 1.120 lukem warn("Can't stat `%s'", tp); 732 1.92 lukem } 733 1.97 lukem recvrequest("RETR", tp, cp, restart_point ? "r+" : "w", 734 1.92 lukem tp != cp || !interactive, 1); 735 1.92 lukem restart_point = 0; 736 1.92 lukem if (!mflag && fromatty) { 737 1.92 lukem ointer = interactive; 738 1.92 lukem interactive = 1; 739 1.121 lukem if (confirm(argv[0], NULL)) 740 1.92 lukem mflag++; 741 1.92 lukem interactive = ointer; 742 1.1 cgd } 743 1.1 cgd } 744 1.62 lukem (void)xsignal(SIGINT, oldintr); 745 1.1 cgd mflag = 0; 746 1.84 lukem } 747 1.84 lukem 748 1.84 lukem /* 749 1.84 lukem * Read list of filenames from a local file and get those 750 1.84 lukem */ 751 1.84 lukem void 752 1.85 lukem fget(int argc, char *argv[]) 753 1.84 lukem { 754 1.129 lukem const char *gmode; 755 1.84 lukem FILE *fp; 756 1.129 lukem char buf[MAXPATHLEN], cmdbuf[MAX_C_NAME]; 757 1.84 lukem 758 1.84 lukem if (argc != 2) { 759 1.116 christos UPRINTF("usage: %s localfile\n", argv[0]); 760 1.84 lukem code = -1; 761 1.84 lukem return; 762 1.84 lukem } 763 1.84 lukem 764 1.84 lukem fp = fopen(argv[1], "r"); 765 1.84 lukem if (fp == NULL) { 766 1.120 lukem fprintf(ttyout, "Can't open source file %s\n", argv[1]); 767 1.84 lukem code = -1; 768 1.84 lukem return; 769 1.84 lukem } 770 1.84 lukem 771 1.129 lukem (void)strlcpy(cmdbuf, "get", sizeof(cmdbuf)); 772 1.129 lukem argv[0] = cmdbuf; 773 1.128 lukem gmode = restart_point ? "r+" : "w"; 774 1.84 lukem 775 1.130 roy while (get_line(fp, buf, sizeof(buf), NULL) >= 0) { 776 1.84 lukem if (buf[0] == '\0') 777 1.84 lukem continue; 778 1.84 lukem argv[1] = buf; 779 1.128 lukem (void)getit(argc, argv, 0, gmode); 780 1.84 lukem } 781 1.84 lukem fclose(fp); 782 1.1 cgd } 783 1.1 cgd 784 1.113 lukem const char * 785 1.131 lukem onoff(int val) 786 1.1 cgd { 787 1.1 cgd 788 1.131 lukem return (val ? "on" : "off"); 789 1.1 cgd } 790 1.1 cgd 791 1.1 cgd /* 792 1.1 cgd * Show status. 793 1.1 cgd */ 794 1.1 cgd /*ARGSUSED*/ 795 1.4 cgd void 796 1.85 lukem status(int argc, char *argv[]) 797 1.1 cgd { 798 1.1 cgd 799 1.88 lukem if (argc == 0) { 800 1.116 christos UPRINTF("usage: %s\n", argv[0]); 801 1.76 lukem code = -1; 802 1.76 lukem return; 803 1.76 lukem } 804 1.105 kleink #ifndef NO_STATUS 805 1.1 cgd if (connected) 806 1.37 lukem fprintf(ttyout, "Connected %sto %s.\n", 807 1.23 lukem connected == -1 ? "and logged in" : "", hostname); 808 1.1 cgd else 809 1.37 lukem fputs("Not connected.\n", ttyout); 810 1.1 cgd if (!proxy) { 811 1.1 cgd pswitch(1); 812 1.1 cgd if (connected) { 813 1.37 lukem fprintf(ttyout, "Connected for proxy commands to %s.\n", 814 1.10 lukem hostname); 815 1.1 cgd } 816 1.1 cgd else { 817 1.37 lukem fputs("No proxy connection.\n", ttyout); 818 1.1 cgd } 819 1.1 cgd pswitch(0); 820 1.1 cgd } 821 1.54 itojun fprintf(ttyout, "Gate ftp: %s, server %s, port %s.\n", onoff(gatemode), 822 1.54 itojun *gateserver ? gateserver : "(none)", gateport); 823 1.76 lukem fprintf(ttyout, "Passive mode: %s; fallback to active mode: %s.\n", 824 1.76 lukem onoff(passivemode), onoff(activefallback)); 825 1.37 lukem fprintf(ttyout, "Mode: %s; Type: %s; Form: %s; Structure: %s.\n", 826 1.37 lukem modename, typename, formname, structname); 827 1.37 lukem fprintf(ttyout, "Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s.\n", 828 1.37 lukem onoff(verbose), onoff(bell), onoff(interactive), onoff(doglob)); 829 1.37 lukem fprintf(ttyout, "Store unique: %s; Receive unique: %s.\n", 830 1.37 lukem onoff(sunique), onoff(runique)); 831 1.37 lukem fprintf(ttyout, "Preserve modification times: %s.\n", onoff(preserve)); 832 1.37 lukem fprintf(ttyout, "Case: %s; CR stripping: %s.\n", onoff(mcase), 833 1.37 lukem onoff(crflag)); 834 1.1 cgd if (ntflag) { 835 1.37 lukem fprintf(ttyout, "Ntrans: (in) %s (out) %s\n", ntin, ntout); 836 1.1 cgd } 837 1.1 cgd else { 838 1.37 lukem fputs("Ntrans: off.\n", ttyout); 839 1.1 cgd } 840 1.1 cgd if (mapflag) { 841 1.37 lukem fprintf(ttyout, "Nmap: (in) %s (out) %s\n", mapin, mapout); 842 1.1 cgd } 843 1.1 cgd else { 844 1.37 lukem fputs("Nmap: off.\n", ttyout); 845 1.1 cgd } 846 1.37 lukem fprintf(ttyout, 847 1.37 lukem "Hash mark printing: %s; Mark count: %d; Progress bar: %s.\n", 848 1.11 lukem onoff(hash), mark, onoff(progress)); 849 1.52 lukem fprintf(ttyout, 850 1.52 lukem "Get transfer rate throttle: %s; maximum: %d; increment %d.\n", 851 1.52 lukem onoff(rate_get), rate_get, rate_get_incr); 852 1.52 lukem fprintf(ttyout, 853 1.52 lukem "Put transfer rate throttle: %s; maximum: %d; increment %d.\n", 854 1.52 lukem onoff(rate_put), rate_put, rate_put_incr); 855 1.58 lukem fprintf(ttyout, 856 1.58 lukem "Socket buffer sizes: send %d, receive %d.\n", 857 1.58 lukem sndbuf_size, rcvbuf_size); 858 1.37 lukem fprintf(ttyout, "Use of PORT cmds: %s.\n", onoff(sendport)); 859 1.68 lukem fprintf(ttyout, "Use of EPSV/EPRT cmds for IPv4: %s%s.\n", onoff(epsv4), 860 1.68 lukem epsv4bad ? " (disabled for this connection)" : ""); 861 1.125 skd fprintf(ttyout, "Use of EPSV/EPRT cmds for IPv6: %s%s.\n", onoff(epsv6), 862 1.125 skd epsv6bad ? " (disabled for this connection)" : ""); 863 1.69 lukem fprintf(ttyout, "Command line editing: %s.\n", 864 1.69 lukem #ifdef NO_EDITCOMPLETE 865 1.69 lukem "support not compiled in" 866 1.69 lukem #else /* !def NO_EDITCOMPLETE */ 867 1.69 lukem onoff(editing) 868 1.69 lukem #endif /* !def NO_EDITCOMPLETE */ 869 1.69 lukem ); 870 1.1 cgd if (macnum > 0) { 871 1.104 pooka int i; 872 1.104 pooka 873 1.37 lukem fputs("Macros:\n", ttyout); 874 1.1 cgd for (i=0; i<macnum; i++) { 875 1.37 lukem fprintf(ttyout, "\t%s\n", macros[i].mac_name); 876 1.1 cgd } 877 1.1 cgd } 878 1.105 kleink #endif /* !def NO_STATUS */ 879 1.103 christos fprintf(ttyout, "Version: %s %s\n", FTP_PRODUCT, FTP_VERSION); 880 1.1 cgd code = 0; 881 1.1 cgd } 882 1.1 cgd 883 1.1 cgd /* 884 1.10 lukem * Toggle a variable 885 1.10 lukem */ 886 1.10 lukem int 887 1.85 lukem togglevar(int argc, char *argv[], int *var, const char *mesg) 888 1.10 lukem { 889 1.76 lukem if (argc == 1) { 890 1.10 lukem *var = !*var; 891 1.10 lukem } else if (argc == 2 && strcasecmp(argv[1], "on") == 0) { 892 1.10 lukem *var = 1; 893 1.10 lukem } else if (argc == 2 && strcasecmp(argv[1], "off") == 0) { 894 1.10 lukem *var = 0; 895 1.10 lukem } else { 896 1.116 christos UPRINTF("usage: %s [ on | off ]\n", argv[0]); 897 1.19 lukem return (-1); 898 1.10 lukem } 899 1.46 lukem if (mesg) 900 1.37 lukem fprintf(ttyout, "%s %s.\n", mesg, onoff(*var)); 901 1.19 lukem return (*var); 902 1.10 lukem } 903 1.10 lukem 904 1.10 lukem /* 905 1.1 cgd * Set beep on cmd completed mode. 906 1.1 cgd */ 907 1.1 cgd /*VARARGS*/ 908 1.4 cgd void 909 1.85 lukem setbell(int argc, char *argv[]) 910 1.1 cgd { 911 1.1 cgd 912 1.10 lukem code = togglevar(argc, argv, &bell, "Bell mode"); 913 1.1 cgd } 914 1.1 cgd 915 1.16 lukem /* 916 1.16 lukem * Set command line editing 917 1.16 lukem */ 918 1.16 lukem /*VARARGS*/ 919 1.16 lukem void 920 1.85 lukem setedit(int argc, char *argv[]) 921 1.16 lukem { 922 1.16 lukem 923 1.69 lukem #ifdef NO_EDITCOMPLETE 924 1.88 lukem if (argc == 0) { 925 1.116 christos UPRINTF("usage: %s\n", argv[0]); 926 1.76 lukem code = -1; 927 1.76 lukem return; 928 1.76 lukem } 929 1.69 lukem if (verbose) 930 1.69 lukem fputs("Editing support not compiled in; ignoring command.\n", 931 1.69 lukem ttyout); 932 1.69 lukem #else /* !def NO_EDITCOMPLETE */ 933 1.16 lukem code = togglevar(argc, argv, &editing, "Editing mode"); 934 1.22 lukem controlediting(); 935 1.69 lukem #endif /* !def NO_EDITCOMPLETE */ 936 1.16 lukem } 937 1.16 lukem 938 1.1 cgd /* 939 1.1 cgd * Turn on packet tracing. 940 1.1 cgd */ 941 1.1 cgd /*VARARGS*/ 942 1.4 cgd void 943 1.85 lukem settrace(int argc, char *argv[]) 944 1.1 cgd { 945 1.1 cgd 946 1.10 lukem code = togglevar(argc, argv, &trace, "Packet tracing"); 947 1.1 cgd } 948 1.1 cgd 949 1.1 cgd /* 950 1.9 lukem * Toggle hash mark printing during transfers, or set hash mark bytecount. 951 1.1 cgd */ 952 1.1 cgd /*VARARGS*/ 953 1.4 cgd void 954 1.85 lukem sethash(int argc, char *argv[]) 955 1.1 cgd { 956 1.10 lukem if (argc == 1) 957 1.9 lukem hash = !hash; 958 1.10 lukem else if (argc != 2) { 959 1.116 christos UPRINTF("usage: %s [ on | off | bytecount ]\n", 960 1.37 lukem argv[0]); 961 1.10 lukem code = -1; 962 1.10 lukem return; 963 1.10 lukem } else if (strcasecmp(argv[1], "on") == 0) 964 1.10 lukem hash = 1; 965 1.10 lukem else if (strcasecmp(argv[1], "off") == 0) 966 1.10 lukem hash = 0; 967 1.10 lukem else { 968 1.31 lukem int nmark; 969 1.31 lukem 970 1.52 lukem nmark = strsuftoi(argv[1]); 971 1.52 lukem if (nmark < 1) { 972 1.37 lukem fprintf(ttyout, "mark: bad bytecount value `%s'.\n", 973 1.37 lukem argv[1]); 974 1.10 lukem code = -1; 975 1.10 lukem return; 976 1.9 lukem } 977 1.10 lukem mark = nmark; 978 1.10 lukem hash = 1; 979 1.9 lukem } 980 1.37 lukem fprintf(ttyout, "Hash mark printing %s", onoff(hash)); 981 1.10 lukem if (hash) 982 1.37 lukem fprintf(ttyout, " (%d bytes/hash mark)", mark); 983 1.37 lukem fputs(".\n", ttyout); 984 1.44 lukem if (hash) 985 1.44 lukem progress = 0; 986 1.10 lukem code = hash; 987 1.1 cgd } 988 1.1 cgd 989 1.1 cgd /* 990 1.1 cgd * Turn on printing of server echo's. 991 1.1 cgd */ 992 1.1 cgd /*VARARGS*/ 993 1.4 cgd void 994 1.85 lukem setverbose(int argc, char *argv[]) 995 1.1 cgd { 996 1.1 cgd 997 1.10 lukem code = togglevar(argc, argv, &verbose, "Verbose mode"); 998 1.1 cgd } 999 1.1 cgd 1000 1.1 cgd /* 1001 1.54 itojun * Toggle PORT/LPRT cmd use before each data connection. 1002 1.1 cgd */ 1003 1.1 cgd /*VARARGS*/ 1004 1.4 cgd void 1005 1.85 lukem setport(int argc, char *argv[]) 1006 1.1 cgd { 1007 1.1 cgd 1008 1.54 itojun code = togglevar(argc, argv, &sendport, "Use of PORT/LPRT cmds"); 1009 1.1 cgd } 1010 1.1 cgd 1011 1.1 cgd /* 1012 1.11 lukem * Toggle transfer progress bar. 1013 1.11 lukem */ 1014 1.11 lukem /*VARARGS*/ 1015 1.11 lukem void 1016 1.85 lukem setprogress(int argc, char *argv[]) 1017 1.11 lukem { 1018 1.11 lukem 1019 1.11 lukem code = togglevar(argc, argv, &progress, "Progress bar"); 1020 1.44 lukem if (progress) 1021 1.44 lukem hash = 0; 1022 1.11 lukem } 1023 1.11 lukem 1024 1.11 lukem /* 1025 1.27 lukem * Turn on interactive prompting during mget, mput, and mdelete. 1026 1.1 cgd */ 1027 1.1 cgd /*VARARGS*/ 1028 1.4 cgd void 1029 1.85 lukem setprompt(int argc, char *argv[]) 1030 1.1 cgd { 1031 1.1 cgd 1032 1.10 lukem code = togglevar(argc, argv, &interactive, "Interactive mode"); 1033 1.1 cgd } 1034 1.1 cgd 1035 1.1 cgd /* 1036 1.27 lukem * Toggle gate-ftp mode, or set gate-ftp server 1037 1.27 lukem */ 1038 1.27 lukem /*VARARGS*/ 1039 1.27 lukem void 1040 1.85 lukem setgate(int argc, char *argv[]) 1041 1.27 lukem { 1042 1.27 lukem static char gsbuf[MAXHOSTNAMELEN]; 1043 1.27 lukem 1044 1.88 lukem if (argc == 0 || argc > 3) { 1045 1.116 christos UPRINTF( 1046 1.76 lukem "usage: %s [ on | off | gateserver [port] ]\n", argv[0]); 1047 1.27 lukem code = -1; 1048 1.27 lukem return; 1049 1.27 lukem } else if (argc < 2) { 1050 1.27 lukem gatemode = !gatemode; 1051 1.27 lukem } else { 1052 1.27 lukem if (argc == 2 && strcasecmp(argv[1], "on") == 0) 1053 1.27 lukem gatemode = 1; 1054 1.27 lukem else if (argc == 2 && strcasecmp(argv[1], "off") == 0) 1055 1.27 lukem gatemode = 0; 1056 1.27 lukem else { 1057 1.59 lukem if (argc == 3) 1058 1.117 christos gateport = ftp_strdup(argv[2]); 1059 1.63 lukem (void)strlcpy(gsbuf, argv[1], sizeof(gsbuf)); 1060 1.27 lukem gateserver = gsbuf; 1061 1.27 lukem gatemode = 1; 1062 1.27 lukem } 1063 1.27 lukem } 1064 1.27 lukem if (gatemode && (gateserver == NULL || *gateserver == '\0')) { 1065 1.37 lukem fprintf(ttyout, 1066 1.27 lukem "Disabling gate-ftp mode - no gate-ftp server defined.\n"); 1067 1.27 lukem gatemode = 0; 1068 1.27 lukem } else { 1069 1.54 itojun fprintf(ttyout, "Gate ftp: %s, server %s, port %s.\n", 1070 1.37 lukem onoff(gatemode), *gateserver ? gateserver : "(none)", 1071 1.54 itojun gateport); 1072 1.27 lukem } 1073 1.27 lukem code = gatemode; 1074 1.27 lukem } 1075 1.27 lukem 1076 1.27 lukem /* 1077 1.27 lukem * Toggle metacharacter interpretation on local file names. 1078 1.1 cgd */ 1079 1.1 cgd /*VARARGS*/ 1080 1.4 cgd void 1081 1.85 lukem setglob(int argc, char *argv[]) 1082 1.1 cgd { 1083 1.9 lukem 1084 1.10 lukem code = togglevar(argc, argv, &doglob, "Globbing"); 1085 1.10 lukem } 1086 1.10 lukem 1087 1.10 lukem /* 1088 1.40 lukem * Toggle preserving modification times on retrieved files. 1089 1.10 lukem */ 1090 1.10 lukem /*VARARGS*/ 1091 1.10 lukem void 1092 1.85 lukem setpreserve(int argc, char *argv[]) 1093 1.10 lukem { 1094 1.10 lukem 1095 1.10 lukem code = togglevar(argc, argv, &preserve, "Preserve modification times"); 1096 1.1 cgd } 1097 1.1 cgd 1098 1.1 cgd /* 1099 1.27 lukem * Set debugging mode on/off and/or set level of debugging. 1100 1.1 cgd */ 1101 1.1 cgd /*VARARGS*/ 1102 1.4 cgd void 1103 1.85 lukem setdebug(int argc, char *argv[]) 1104 1.1 cgd { 1105 1.88 lukem if (argc == 0 || argc > 2) { 1106 1.116 christos UPRINTF("usage: %s [ on | off | debuglevel ]\n", argv[0]); 1107 1.10 lukem code = -1; 1108 1.10 lukem return; 1109 1.10 lukem } else if (argc == 2) { 1110 1.10 lukem if (strcasecmp(argv[1], "on") == 0) 1111 1.118 christos ftp_debug = 1; 1112 1.10 lukem else if (strcasecmp(argv[1], "off") == 0) 1113 1.118 christos ftp_debug = 0; 1114 1.10 lukem else { 1115 1.52 lukem int val; 1116 1.25 lukem 1117 1.52 lukem val = strsuftoi(argv[1]); 1118 1.52 lukem if (val < 0) { 1119 1.37 lukem fprintf(ttyout, "%s: bad debugging value.\n", 1120 1.37 lukem argv[1]); 1121 1.10 lukem code = -1; 1122 1.10 lukem return; 1123 1.10 lukem } 1124 1.118 christos ftp_debug = val; 1125 1.1 cgd } 1126 1.1 cgd } else 1127 1.118 christos ftp_debug = !ftp_debug; 1128 1.118 christos if (ftp_debug) 1129 1.1 cgd options |= SO_DEBUG; 1130 1.1 cgd else 1131 1.1 cgd options &= ~SO_DEBUG; 1132 1.141 lukem fprintf(ttyout, "Debugging %s (debug=%d).\n", onoff(ftp_debug), ftp_debug); 1133 1.118 christos code = ftp_debug > 0; 1134 1.1 cgd } 1135 1.1 cgd 1136 1.1 cgd /* 1137 1.27 lukem * Set current working directory on remote machine. 1138 1.1 cgd */ 1139 1.4 cgd void 1140 1.85 lukem cd(int argc, char *argv[]) 1141 1.1 cgd { 1142 1.16 lukem int r; 1143 1.1 cgd 1144 1.88 lukem if (argc == 0 || argc > 2 || 1145 1.88 lukem (argc == 1 && !another(&argc, &argv, "remote-directory"))) { 1146 1.116 christos UPRINTF("usage: %s remote-directory\n", argv[0]); 1147 1.1 cgd code = -1; 1148 1.1 cgd return; 1149 1.1 cgd } 1150 1.17 veego r = command("CWD %s", argv[1]); 1151 1.16 lukem if (r == ERROR && code == 500) { 1152 1.1 cgd if (verbose) 1153 1.37 lukem fputs("CWD command not recognized, trying XCWD.\n", 1154 1.37 lukem ttyout); 1155 1.16 lukem r = command("XCWD %s", argv[1]); 1156 1.1 cgd } 1157 1.79 lukem if (r == COMPLETE) { 1158 1.16 lukem dirchange = 1; 1159 1.138 kre remotecwd[0] = '\0'; 1160 1.138 kre remcwdvalid = 0; 1161 1.79 lukem } 1162 1.1 cgd } 1163 1.1 cgd 1164 1.1 cgd /* 1165 1.27 lukem * Set current working directory on local machine. 1166 1.1 cgd */ 1167 1.4 cgd void 1168 1.85 lukem lcd(int argc, char *argv[]) 1169 1.1 cgd { 1170 1.63 lukem char *locdir; 1171 1.1 cgd 1172 1.76 lukem code = -1; 1173 1.76 lukem if (argc == 1) { 1174 1.64 lukem argc++; 1175 1.92 lukem argv[1] = localhome; 1176 1.64 lukem } 1177 1.1 cgd if (argc != 2) { 1178 1.116 christos UPRINTF("usage: %s [local-directory]\n", argv[0]); 1179 1.1 cgd return; 1180 1.1 cgd } 1181 1.76 lukem if ((locdir = globulize(argv[1])) == NULL) 1182 1.1 cgd return; 1183 1.109 lukem if (chdir(locdir) == -1) 1184 1.120 lukem warn("Can't chdir `%s'", locdir); 1185 1.76 lukem else { 1186 1.109 lukem updatelocalcwd(); 1187 1.109 lukem if (localcwd[0]) { 1188 1.109 lukem fprintf(ttyout, "Local directory now: %s\n", localcwd); 1189 1.76 lukem code = 0; 1190 1.109 lukem } else { 1191 1.109 lukem fprintf(ttyout, "Unable to determine local directory\n"); 1192 1.109 lukem } 1193 1.1 cgd } 1194 1.63 lukem (void)free(locdir); 1195 1.1 cgd } 1196 1.1 cgd 1197 1.1 cgd /* 1198 1.1 cgd * Delete a single file. 1199 1.1 cgd */ 1200 1.4 cgd void 1201 1.85 lukem delete(int argc, char *argv[]) 1202 1.1 cgd { 1203 1.1 cgd 1204 1.88 lukem if (argc == 0 || argc > 2 || 1205 1.88 lukem (argc == 1 && !another(&argc, &argv, "remote-file"))) { 1206 1.116 christos UPRINTF("usage: %s remote-file\n", argv[0]); 1207 1.1 cgd code = -1; 1208 1.1 cgd return; 1209 1.1 cgd } 1210 1.101 lukem if (command("DELE %s", argv[1]) == COMPLETE) 1211 1.101 lukem dirchange = 1; 1212 1.1 cgd } 1213 1.1 cgd 1214 1.1 cgd /* 1215 1.1 cgd * Delete multiple files. 1216 1.1 cgd */ 1217 1.4 cgd void 1218 1.85 lukem mdelete(int argc, char *argv[]) 1219 1.1 cgd { 1220 1.82 lukem sigfunc oldintr; 1221 1.1 cgd int ointer; 1222 1.1 cgd char *cp; 1223 1.1 cgd 1224 1.88 lukem if (argc == 0 || 1225 1.88 lukem (argc == 1 && !another(&argc, &argv, "remote-files"))) { 1226 1.116 christos UPRINTF("usage: %s [remote-files]\n", argv[0]); 1227 1.1 cgd code = -1; 1228 1.1 cgd return; 1229 1.1 cgd } 1230 1.1 cgd mflag = 1; 1231 1.72 lukem oldintr = xsignal(SIGINT, mintr); 1232 1.72 lukem if (sigsetjmp(jabort, 1)) 1233 1.121 lukem mabort(argv[0]); 1234 1.19 lukem while ((cp = remglob(argv, 0, NULL)) != NULL) { 1235 1.1 cgd if (*cp == '\0') { 1236 1.1 cgd mflag = 0; 1237 1.1 cgd continue; 1238 1.1 cgd } 1239 1.1 cgd if (mflag && confirm(argv[0], cp)) { 1240 1.101 lukem if (command("DELE %s", cp) == COMPLETE) 1241 1.101 lukem dirchange = 1; 1242 1.1 cgd if (!mflag && fromatty) { 1243 1.1 cgd ointer = interactive; 1244 1.1 cgd interactive = 1; 1245 1.121 lukem if (confirm(argv[0], NULL)) { 1246 1.1 cgd mflag++; 1247 1.1 cgd } 1248 1.1 cgd interactive = ointer; 1249 1.1 cgd } 1250 1.1 cgd } 1251 1.1 cgd } 1252 1.62 lukem (void)xsignal(SIGINT, oldintr); 1253 1.1 cgd mflag = 0; 1254 1.1 cgd } 1255 1.1 cgd 1256 1.1 cgd /* 1257 1.1 cgd * Rename a remote file. 1258 1.1 cgd */ 1259 1.4 cgd void 1260 1.85 lukem renamefile(int argc, char *argv[]) 1261 1.1 cgd { 1262 1.1 cgd 1263 1.88 lukem if (argc == 0 || (argc == 1 && !another(&argc, &argv, "from-name"))) 1264 1.1 cgd goto usage; 1265 1.10 lukem if ((argc < 3 && !another(&argc, &argv, "to-name")) || argc > 3) { 1266 1.88 lukem usage: 1267 1.116 christos UPRINTF("usage: %s from-name to-name\n", argv[0]); 1268 1.1 cgd code = -1; 1269 1.1 cgd return; 1270 1.1 cgd } 1271 1.101 lukem if (command("RNFR %s", argv[1]) == CONTINUE && 1272 1.101 lukem command("RNTO %s", argv[2]) == COMPLETE) 1273 1.101 lukem dirchange = 1; 1274 1.1 cgd } 1275 1.1 cgd 1276 1.1 cgd /* 1277 1.27 lukem * Get a directory listing of remote files. 1278 1.88 lukem * Supports being invoked as: 1279 1.88 lukem * cmd runs 1280 1.88 lukem * --- ---- 1281 1.88 lukem * dir, ls LIST 1282 1.88 lukem * mlsd MLSD 1283 1.88 lukem * nlist NLST 1284 1.88 lukem * pdir, pls LIST |$PAGER 1285 1.127 lukem * pmlsd MLSD |$PAGER 1286 1.1 cgd */ 1287 1.4 cgd void 1288 1.85 lukem ls(int argc, char *argv[]) 1289 1.1 cgd { 1290 1.10 lukem const char *cmd; 1291 1.144 christos char *remdir, *locbuf, *locfile; 1292 1.129 lukem int pagecmd, mlsdcmd; 1293 1.1 cgd 1294 1.63 lukem remdir = NULL; 1295 1.129 lukem locbuf = NULL; 1296 1.129 lukem pagecmd = mlsdcmd = 0; 1297 1.63 lukem /* 1298 1.88 lukem * the only commands that start with `p' are 1299 1.88 lukem * the `pager' versions. 1300 1.63 lukem */ 1301 1.63 lukem if (argv[0][0] == 'p') 1302 1.63 lukem pagecmd = 1; 1303 1.88 lukem if (strcmp(argv[0] + pagecmd , "mlsd") == 0) { 1304 1.88 lukem if (! features[FEAT_MLST]) { 1305 1.88 lukem fprintf(ttyout, 1306 1.88 lukem "MLSD is not supported by the remote server.\n"); 1307 1.88 lukem return; 1308 1.88 lukem } 1309 1.88 lukem mlsdcmd = 1; 1310 1.88 lukem } 1311 1.88 lukem if (argc == 0) 1312 1.76 lukem goto usage; 1313 1.63 lukem 1314 1.88 lukem if (mlsdcmd) 1315 1.88 lukem cmd = "MLSD"; 1316 1.88 lukem else if (strcmp(argv[0] + pagecmd, "nlist") == 0) 1317 1.86 lukem cmd = "NLST"; 1318 1.88 lukem else 1319 1.88 lukem cmd = "LIST"; 1320 1.63 lukem 1321 1.63 lukem if (argc > 1) 1322 1.63 lukem remdir = argv[1]; 1323 1.63 lukem if (argc > 2) 1324 1.63 lukem locfile = argv[2]; 1325 1.144 christos else 1326 1.144 christos locfile = locbuf = ftp_strdup("-"); 1327 1.88 lukem if (argc > 3 || ((pagecmd | mlsdcmd) && argc > 2)) { 1328 1.76 lukem usage: 1329 1.88 lukem if (pagecmd || mlsdcmd) 1330 1.116 christos UPRINTF("usage: %s [remote-path]\n", argv[0]); 1331 1.63 lukem else 1332 1.116 christos UPRINTF("usage: %s [remote-path [local-file]]\n", 1333 1.63 lukem argv[0]); 1334 1.1 cgd code = -1; 1335 1.63 lukem goto freels; 1336 1.1 cgd } 1337 1.63 lukem 1338 1.63 lukem if (pagecmd) { 1339 1.129 lukem const char *p; 1340 1.114 lukem size_t len; 1341 1.63 lukem 1342 1.76 lukem p = getoptionvalue("pager"); 1343 1.76 lukem if (EMPTYSTRING(p)) 1344 1.76 lukem p = DEFAULTPAGER; 1345 1.63 lukem len = strlen(p) + 2; 1346 1.144 christos free(locbuf); 1347 1.129 lukem locbuf = ftp_malloc(len); 1348 1.129 lukem locbuf[0] = '|'; 1349 1.129 lukem (void)strlcpy(locbuf + 1, p, len - 1); 1350 1.129 lukem locfile = locbuf; 1351 1.144 christos } else if (locfile != locbuf) { 1352 1.129 lukem if ((locbuf = globulize(locfile)) == NULL || 1353 1.129 lukem !confirm("output to local-file:", locbuf)) { 1354 1.1 cgd code = -1; 1355 1.27 lukem goto freels; 1356 1.63 lukem } 1357 1.129 lukem locfile = locbuf; 1358 1.1 cgd } 1359 1.63 lukem recvrequest(cmd, locfile, remdir, "w", 0, 0); 1360 1.88 lukem freels: 1361 1.129 lukem if (locbuf) 1362 1.129 lukem (void)free(locbuf); 1363 1.1 cgd } 1364 1.1 cgd 1365 1.1 cgd /* 1366 1.27 lukem * Get a directory listing of multiple remote files. 1367 1.1 cgd */ 1368 1.4 cgd void 1369 1.85 lukem mls(int argc, char *argv[]) 1370 1.1 cgd { 1371 1.82 lukem sigfunc oldintr; 1372 1.1 cgd int ointer, i; 1373 1.129 lukem int volatile dolist; 1374 1.129 lukem char * volatile dest, *odest; 1375 1.129 lukem const char *lmode; 1376 1.1 cgd 1377 1.88 lukem if (argc == 0) 1378 1.76 lukem goto usage; 1379 1.1 cgd if (argc < 2 && !another(&argc, &argv, "remote-files")) 1380 1.1 cgd goto usage; 1381 1.1 cgd if (argc < 3 && !another(&argc, &argv, "local-file")) { 1382 1.88 lukem usage: 1383 1.116 christos UPRINTF("usage: %s remote-files local-file\n", argv[0]); 1384 1.1 cgd code = -1; 1385 1.1 cgd return; 1386 1.1 cgd } 1387 1.27 lukem odest = dest = argv[argc - 1]; 1388 1.1 cgd argv[argc - 1] = NULL; 1389 1.1 cgd if (strcmp(dest, "-") && *dest != '|') 1390 1.63 lukem if (((dest = globulize(dest)) == NULL) || 1391 1.1 cgd !confirm("output to local-file:", dest)) { 1392 1.1 cgd code = -1; 1393 1.1 cgd return; 1394 1.1 cgd } 1395 1.25 lukem dolist = strcmp(argv[0], "mls"); 1396 1.1 cgd mflag = 1; 1397 1.72 lukem oldintr = xsignal(SIGINT, mintr); 1398 1.72 lukem if (sigsetjmp(jabort, 1)) 1399 1.121 lukem mabort(argv[0]); 1400 1.76 lukem for (i = 1; mflag && i < argc-1 && connected; i++) { 1401 1.128 lukem lmode = (i == 1) ? "w" : "a"; 1402 1.128 lukem recvrequest(dolist ? "LIST" : "NLST", dest, argv[i], lmode, 1403 1.27 lukem 0, 0); 1404 1.1 cgd if (!mflag && fromatty) { 1405 1.1 cgd ointer = interactive; 1406 1.1 cgd interactive = 1; 1407 1.121 lukem if (confirm(argv[0], NULL)) { 1408 1.111 simonb mflag++; 1409 1.1 cgd } 1410 1.1 cgd interactive = ointer; 1411 1.1 cgd } 1412 1.1 cgd } 1413 1.62 lukem (void)xsignal(SIGINT, oldintr); 1414 1.1 cgd mflag = 0; 1415 1.27 lukem if (dest != odest) /* free up after globulize() */ 1416 1.27 lukem free(dest); 1417 1.1 cgd } 1418 1.1 cgd 1419 1.1 cgd /* 1420 1.1 cgd * Do a shell escape 1421 1.1 cgd */ 1422 1.1 cgd /*ARGSUSED*/ 1423 1.4 cgd void 1424 1.85 lukem shell(int argc, char *argv[]) 1425 1.1 cgd { 1426 1.4 cgd pid_t pid; 1427 1.106 lukem sigfunc oldintr; 1428 1.129 lukem char shellnam[MAXPATHLEN]; 1429 1.129 lukem const char *shellp, *namep; 1430 1.29 lukem int wait_status; 1431 1.1 cgd 1432 1.88 lukem if (argc == 0) { 1433 1.116 christos UPRINTF("usage: %s [command [args]]\n", argv[0]); 1434 1.76 lukem code = -1; 1435 1.76 lukem return; 1436 1.76 lukem } 1437 1.106 lukem oldintr = xsignal(SIGINT, SIG_IGN); 1438 1.1 cgd if ((pid = fork()) == 0) { 1439 1.1 cgd for (pid = 3; pid < 20; pid++) 1440 1.19 lukem (void)close(pid); 1441 1.62 lukem (void)xsignal(SIGINT, SIG_DFL); 1442 1.128 lukem shellp = getenv("SHELL"); 1443 1.128 lukem if (shellp == NULL) 1444 1.128 lukem shellp = _PATH_BSHELL; 1445 1.128 lukem namep = strrchr(shellp, '/'); 1446 1.1 cgd if (namep == NULL) 1447 1.128 lukem namep = shellp; 1448 1.71 lukem else 1449 1.71 lukem namep++; 1450 1.71 lukem (void)strlcpy(shellnam, namep, sizeof(shellnam)); 1451 1.118 christos if (ftp_debug) { 1452 1.128 lukem fputs(shellp, ttyout); 1453 1.37 lukem putc('\n', ttyout); 1454 1.1 cgd } 1455 1.1 cgd if (argc > 1) { 1456 1.128 lukem execl(shellp, shellnam, "-c", altarg, (char *)0); 1457 1.1 cgd } 1458 1.1 cgd else { 1459 1.128 lukem execl(shellp, shellnam, (char *)0); 1460 1.1 cgd } 1461 1.128 lukem warn("Can't execute `%s'", shellp); 1462 1.1 cgd code = -1; 1463 1.1 cgd exit(1); 1464 1.4 cgd } 1465 1.1 cgd if (pid > 0) 1466 1.29 lukem while (wait(&wait_status) != pid) 1467 1.1 cgd ; 1468 1.106 lukem (void)xsignal(SIGINT, oldintr); 1469 1.1 cgd if (pid == -1) { 1470 1.120 lukem warn("Can't fork a subshell; try again later"); 1471 1.1 cgd code = -1; 1472 1.76 lukem } else 1473 1.1 cgd code = 0; 1474 1.1 cgd } 1475 1.1 cgd 1476 1.1 cgd /* 1477 1.1 cgd * Send new user information (re-login) 1478 1.1 cgd */ 1479 1.4 cgd void 1480 1.85 lukem user(int argc, char *argv[]) 1481 1.1 cgd { 1482 1.115 lukem char *password; 1483 1.119 lukem char emptypass[] = ""; 1484 1.1 cgd int n, aflag = 0; 1485 1.1 cgd 1486 1.88 lukem if (argc == 0) 1487 1.76 lukem goto usage; 1488 1.1 cgd if (argc < 2) 1489 1.19 lukem (void)another(&argc, &argv, "username"); 1490 1.1 cgd if (argc < 2 || argc > 4) { 1491 1.76 lukem usage: 1492 1.116 christos UPRINTF("usage: %s username [password [account]]\n", 1493 1.37 lukem argv[0]); 1494 1.1 cgd code = -1; 1495 1.4 cgd return; 1496 1.1 cgd } 1497 1.1 cgd n = command("USER %s", argv[1]); 1498 1.1 cgd if (n == CONTINUE) { 1499 1.49 lukem if (argc < 3) { 1500 1.115 lukem password = getpass("Password: "); 1501 1.119 lukem if (password == NULL) 1502 1.119 lukem password = emptypass; 1503 1.115 lukem } else { 1504 1.115 lukem password = argv[2]; 1505 1.49 lukem } 1506 1.115 lukem n = command("PASS %s", password); 1507 1.115 lukem memset(password, 0, strlen(password)); 1508 1.1 cgd } 1509 1.1 cgd if (n == CONTINUE) { 1510 1.115 lukem aflag++; 1511 1.1 cgd if (argc < 4) { 1512 1.115 lukem password = getpass("Account: "); 1513 1.119 lukem if (password == NULL) 1514 1.119 lukem password = emptypass; 1515 1.115 lukem } else { 1516 1.115 lukem password = argv[3]; 1517 1.1 cgd } 1518 1.115 lukem n = command("ACCT %s", password); 1519 1.115 lukem memset(password, 0, strlen(password)); 1520 1.1 cgd } 1521 1.1 cgd if (n != COMPLETE) { 1522 1.37 lukem fputs("Login failed.\n", ttyout); 1523 1.4 cgd return; 1524 1.1 cgd } 1525 1.1 cgd if (!aflag && argc == 4) { 1526 1.115 lukem password = argv[3]; 1527 1.115 lukem (void)command("ACCT %s", password); 1528 1.115 lukem memset(password, 0, strlen(password)); 1529 1.1 cgd } 1530 1.23 lukem connected = -1; 1531 1.88 lukem getremoteinfo(); 1532 1.1 cgd } 1533 1.1 cgd 1534 1.1 cgd /* 1535 1.10 lukem * Print working directory on remote machine. 1536 1.1 cgd */ 1537 1.1 cgd /*VARARGS*/ 1538 1.4 cgd void 1539 1.85 lukem pwd(int argc, char *argv[]) 1540 1.1 cgd { 1541 1.1 cgd 1542 1.109 lukem code = -1; 1543 1.109 lukem if (argc != 1) { 1544 1.116 christos UPRINTF("usage: %s\n", argv[0]); 1545 1.76 lukem return; 1546 1.76 lukem } 1547 1.138 kre if (!remcwdvalid || remotecwd[0] == '\0') 1548 1.109 lukem updateremotecwd(); 1549 1.138 kre if (remotecwd[0] == '\0') 1550 1.109 lukem fprintf(ttyout, "Unable to determine remote directory\n"); 1551 1.109 lukem else { 1552 1.109 lukem fprintf(ttyout, "Remote directory: %s\n", remotecwd); 1553 1.109 lukem code = 0; 1554 1.1 cgd } 1555 1.1 cgd } 1556 1.1 cgd 1557 1.1 cgd /* 1558 1.10 lukem * Print working directory on local machine. 1559 1.10 lukem */ 1560 1.10 lukem void 1561 1.85 lukem lpwd(int argc, char *argv[]) 1562 1.10 lukem { 1563 1.10 lukem 1564 1.109 lukem code = -1; 1565 1.109 lukem if (argc != 1) { 1566 1.116 christos UPRINTF("usage: %s\n", argv[0]); 1567 1.76 lukem return; 1568 1.76 lukem } 1569 1.109 lukem if (! localcwd[0]) 1570 1.109 lukem updatelocalcwd(); 1571 1.109 lukem if (! localcwd[0]) 1572 1.109 lukem fprintf(ttyout, "Unable to determine local directory\n"); 1573 1.109 lukem else { 1574 1.109 lukem fprintf(ttyout, "Local directory: %s\n", localcwd); 1575 1.76 lukem code = 0; 1576 1.76 lukem } 1577 1.10 lukem } 1578 1.10 lukem 1579 1.10 lukem /* 1580 1.1 cgd * Make a directory. 1581 1.1 cgd */ 1582 1.4 cgd void 1583 1.85 lukem makedir(int argc, char *argv[]) 1584 1.1 cgd { 1585 1.101 lukem int r; 1586 1.1 cgd 1587 1.88 lukem if (argc == 0 || argc > 2 || 1588 1.88 lukem (argc == 1 && !another(&argc, &argv, "directory-name"))) { 1589 1.116 christos UPRINTF("usage: %s directory-name\n", argv[0]); 1590 1.1 cgd code = -1; 1591 1.1 cgd return; 1592 1.1 cgd } 1593 1.101 lukem r = command("MKD %s", argv[1]); 1594 1.101 lukem if (r == ERROR && code == 500) { 1595 1.1 cgd if (verbose) 1596 1.37 lukem fputs("MKD command not recognized, trying XMKD.\n", 1597 1.37 lukem ttyout); 1598 1.101 lukem r = command("XMKD %s", argv[1]); 1599 1.1 cgd } 1600 1.101 lukem if (r == COMPLETE) 1601 1.101 lukem dirchange = 1; 1602 1.1 cgd } 1603 1.1 cgd 1604 1.1 cgd /* 1605 1.1 cgd * Remove a directory. 1606 1.1 cgd */ 1607 1.4 cgd void 1608 1.85 lukem removedir(int argc, char *argv[]) 1609 1.1 cgd { 1610 1.101 lukem int r; 1611 1.1 cgd 1612 1.88 lukem if (argc == 0 || argc > 2 || 1613 1.88 lukem (argc == 1 && !another(&argc, &argv, "directory-name"))) { 1614 1.116 christos UPRINTF("usage: %s directory-name\n", argv[0]); 1615 1.1 cgd code = -1; 1616 1.1 cgd return; 1617 1.1 cgd } 1618 1.101 lukem r = command("RMD %s", argv[1]); 1619 1.101 lukem if (r == ERROR && code == 500) { 1620 1.1 cgd if (verbose) 1621 1.37 lukem fputs("RMD command not recognized, trying XRMD.\n", 1622 1.37 lukem ttyout); 1623 1.101 lukem r = command("XRMD %s", argv[1]); 1624 1.1 cgd } 1625 1.101 lukem if (r == COMPLETE) 1626 1.101 lukem dirchange = 1; 1627 1.1 cgd } 1628 1.1 cgd 1629 1.1 cgd /* 1630 1.1 cgd * Send a line, verbatim, to the remote machine. 1631 1.1 cgd */ 1632 1.4 cgd void 1633 1.85 lukem quote(int argc, char *argv[]) 1634 1.1 cgd { 1635 1.1 cgd 1636 1.88 lukem if (argc == 0 || 1637 1.88 lukem (argc == 1 && !another(&argc, &argv, "command line to send"))) { 1638 1.116 christos UPRINTF("usage: %s line-to-send\n", argv[0]); 1639 1.1 cgd code = -1; 1640 1.1 cgd return; 1641 1.1 cgd } 1642 1.1 cgd quote1("", argc, argv); 1643 1.1 cgd } 1644 1.1 cgd 1645 1.1 cgd /* 1646 1.1 cgd * Send a SITE command to the remote machine. The line 1647 1.1 cgd * is sent verbatim to the remote machine, except that the 1648 1.1 cgd * word "SITE" is added at the front. 1649 1.1 cgd */ 1650 1.4 cgd void 1651 1.85 lukem site(int argc, char *argv[]) 1652 1.1 cgd { 1653 1.1 cgd 1654 1.88 lukem if (argc == 0 || 1655 1.88 lukem (argc == 1 && !another(&argc, &argv, "arguments to SITE command"))){ 1656 1.116 christos UPRINTF("usage: %s line-to-send\n", argv[0]); 1657 1.1 cgd code = -1; 1658 1.1 cgd return; 1659 1.1 cgd } 1660 1.1 cgd quote1("SITE ", argc, argv); 1661 1.1 cgd } 1662 1.1 cgd 1663 1.1 cgd /* 1664 1.1 cgd * Turn argv[1..argc) into a space-separated string, then prepend initial text. 1665 1.1 cgd * Send the result as a one-line command and get response. 1666 1.1 cgd */ 1667 1.4 cgd void 1668 1.85 lukem quote1(const char *initial, int argc, char *argv[]) 1669 1.1 cgd { 1670 1.63 lukem int i; 1671 1.1 cgd char buf[BUFSIZ]; /* must be >= sizeof(line) */ 1672 1.1 cgd 1673 1.63 lukem (void)strlcpy(buf, initial, sizeof(buf)); 1674 1.63 lukem for (i = 1; i < argc; i++) { 1675 1.63 lukem (void)strlcat(buf, argv[i], sizeof(buf)); 1676 1.63 lukem if (i < (argc - 1)) 1677 1.63 lukem (void)strlcat(buf, " ", sizeof(buf)); 1678 1.1 cgd } 1679 1.43 lukem if (command("%s", buf) == PRELIM) { 1680 1.4 cgd while (getreply(0) == PRELIM) 1681 1.4 cgd continue; 1682 1.1 cgd } 1683 1.101 lukem dirchange = 1; 1684 1.1 cgd } 1685 1.1 cgd 1686 1.4 cgd void 1687 1.85 lukem do_chmod(int argc, char *argv[]) 1688 1.1 cgd { 1689 1.1 cgd 1690 1.88 lukem if (argc == 0 || (argc == 1 && !another(&argc, &argv, "mode"))) 1691 1.1 cgd goto usage; 1692 1.76 lukem if ((argc < 3 && !another(&argc, &argv, "remote-file")) || argc > 3) { 1693 1.88 lukem usage: 1694 1.116 christos UPRINTF("usage: %s mode remote-file\n", argv[0]); 1695 1.1 cgd code = -1; 1696 1.1 cgd return; 1697 1.1 cgd } 1698 1.19 lukem (void)command("SITE CHMOD %s %s", argv[1], argv[2]); 1699 1.1 cgd } 1700 1.1 cgd 1701 1.112 lukem #define COMMAND_1ARG(argc, argv, cmd) \ 1702 1.91 is if (argc == 1) \ 1703 1.91 is command(cmd); \ 1704 1.91 is else \ 1705 1.91 is command(cmd " %s", argv[1]) 1706 1.91 is 1707 1.4 cgd void 1708 1.85 lukem do_umask(int argc, char *argv[]) 1709 1.1 cgd { 1710 1.1 cgd int oldverbose = verbose; 1711 1.1 cgd 1712 1.88 lukem if (argc == 0) { 1713 1.116 christos UPRINTF("usage: %s [umask]\n", argv[0]); 1714 1.76 lukem code = -1; 1715 1.76 lukem return; 1716 1.76 lukem } 1717 1.1 cgd verbose = 1; 1718 1.91 is COMMAND_1ARG(argc, argv, "SITE UMASK"); 1719 1.1 cgd verbose = oldverbose; 1720 1.1 cgd } 1721 1.1 cgd 1722 1.4 cgd void 1723 1.85 lukem idlecmd(int argc, char *argv[]) 1724 1.1 cgd { 1725 1.1 cgd int oldverbose = verbose; 1726 1.1 cgd 1727 1.80 lukem if (argc < 1 || argc > 2) { 1728 1.116 christos UPRINTF("usage: %s [seconds]\n", argv[0]); 1729 1.76 lukem code = -1; 1730 1.76 lukem return; 1731 1.76 lukem } 1732 1.1 cgd verbose = 1; 1733 1.91 is COMMAND_1ARG(argc, argv, "SITE IDLE"); 1734 1.1 cgd verbose = oldverbose; 1735 1.1 cgd } 1736 1.1 cgd 1737 1.1 cgd /* 1738 1.1 cgd * Ask the other side for help. 1739 1.1 cgd */ 1740 1.4 cgd void 1741 1.85 lukem rmthelp(int argc, char *argv[]) 1742 1.1 cgd { 1743 1.1 cgd int oldverbose = verbose; 1744 1.1 cgd 1745 1.88 lukem if (argc == 0) { 1746 1.116 christos UPRINTF("usage: %s\n", argv[0]); 1747 1.76 lukem code = -1; 1748 1.76 lukem return; 1749 1.76 lukem } 1750 1.1 cgd verbose = 1; 1751 1.91 is COMMAND_1ARG(argc, argv, "HELP"); 1752 1.1 cgd verbose = oldverbose; 1753 1.1 cgd } 1754 1.1 cgd 1755 1.1 cgd /* 1756 1.1 cgd * Terminate session and exit. 1757 1.88 lukem * May be called with 0, NULL. 1758 1.1 cgd */ 1759 1.1 cgd /*VARARGS*/ 1760 1.4 cgd void 1761 1.85 lukem quit(int argc, char *argv[]) 1762 1.1 cgd { 1763 1.1 cgd 1764 1.88 lukem /* this may be called with argc == 0, argv == NULL */ 1765 1.76 lukem if (argc == 0 && argv != NULL) { 1766 1.116 christos UPRINTF("usage: %s\n", argv[0]); 1767 1.76 lukem code = -1; 1768 1.76 lukem return; 1769 1.76 lukem } 1770 1.1 cgd if (connected) 1771 1.76 lukem disconnect(0, NULL); 1772 1.1 cgd pswitch(1); 1773 1.76 lukem if (connected) 1774 1.76 lukem disconnect(0, NULL); 1775 1.1 cgd exit(0); 1776 1.1 cgd } 1777 1.1 cgd 1778 1.139 mrg void __dead 1779 1.139 mrg justquit(void) 1780 1.139 mrg { 1781 1.139 mrg 1782 1.139 mrg quit(0, NULL); 1783 1.140 martin /* 1784 1.140 martin * quit is not __dead, but for our invocation it never will return, 1785 1.140 martin * but some compilers are not smart enough to find this out. 1786 1.140 martin */ 1787 1.140 martin exit(0); 1788 1.139 mrg } 1789 1.139 mrg 1790 1.1 cgd /* 1791 1.1 cgd * Terminate session, but don't exit. 1792 1.88 lukem * May be called with 0, NULL. 1793 1.1 cgd */ 1794 1.4 cgd void 1795 1.85 lukem disconnect(int argc, char *argv[]) 1796 1.1 cgd { 1797 1.1 cgd 1798 1.88 lukem /* this may be called with argc == 0, argv == NULL */ 1799 1.76 lukem if (argc == 0 && argv != NULL) { 1800 1.116 christos UPRINTF("usage: %s\n", argv[0]); 1801 1.76 lukem code = -1; 1802 1.76 lukem return; 1803 1.76 lukem } 1804 1.1 cgd if (!connected) 1805 1.1 cgd return; 1806 1.19 lukem (void)command("QUIT"); 1807 1.76 lukem cleanuppeer(); 1808 1.1 cgd } 1809 1.1 cgd 1810 1.4 cgd void 1811 1.85 lukem account(int argc, char *argv[]) 1812 1.1 cgd { 1813 1.13 lukem char *ap; 1814 1.119 lukem char emptypass[] = ""; 1815 1.1 cgd 1816 1.88 lukem if (argc == 0 || argc > 2) { 1817 1.116 christos UPRINTF("usage: %s [password]\n", argv[0]); 1818 1.13 lukem code = -1; 1819 1.13 lukem return; 1820 1.1 cgd } 1821 1.13 lukem else if (argc == 2) 1822 1.13 lukem ap = argv[1]; 1823 1.119 lukem else { 1824 1.1 cgd ap = getpass("Account:"); 1825 1.119 lukem if (ap == NULL) 1826 1.119 lukem ap = emptypass; 1827 1.119 lukem } 1828 1.19 lukem (void)command("ACCT %s", ap); 1829 1.119 lukem memset(ap, 0, strlen(ap)); 1830 1.1 cgd } 1831 1.1 cgd 1832 1.143 christos static sigjmp_buf abortprox; 1833 1.1 cgd 1834 1.1 cgd void 1835 1.143 christos proxabort(int notused __unused) 1836 1.1 cgd { 1837 1.1 cgd 1838 1.106 lukem sigint_raised = 1; 1839 1.18 lukem alarmtimer(0); 1840 1.1 cgd if (!proxy) { 1841 1.1 cgd pswitch(1); 1842 1.1 cgd } 1843 1.1 cgd if (connected) { 1844 1.1 cgd proxflag = 1; 1845 1.1 cgd } 1846 1.1 cgd else { 1847 1.1 cgd proxflag = 0; 1848 1.1 cgd } 1849 1.1 cgd pswitch(0); 1850 1.72 lukem siglongjmp(abortprox, 1); 1851 1.1 cgd } 1852 1.1 cgd 1853 1.4 cgd void 1854 1.85 lukem doproxy(int argc, char *argv[]) 1855 1.1 cgd { 1856 1.4 cgd struct cmd *c; 1857 1.143 christos size_t cmdpos; 1858 1.82 lukem sigfunc oldintr; 1859 1.129 lukem char cmdbuf[MAX_C_NAME]; 1860 1.1 cgd 1861 1.88 lukem if (argc == 0 || (argc == 1 && !another(&argc, &argv, "command"))) { 1862 1.116 christos UPRINTF("usage: %s command\n", argv[0]); 1863 1.1 cgd code = -1; 1864 1.1 cgd return; 1865 1.1 cgd } 1866 1.1 cgd c = getcmd(argv[1]); 1867 1.1 cgd if (c == (struct cmd *) -1) { 1868 1.37 lukem fputs("?Ambiguous command.\n", ttyout); 1869 1.1 cgd code = -1; 1870 1.1 cgd return; 1871 1.1 cgd } 1872 1.1 cgd if (c == 0) { 1873 1.37 lukem fputs("?Invalid command.\n", ttyout); 1874 1.1 cgd code = -1; 1875 1.1 cgd return; 1876 1.1 cgd } 1877 1.1 cgd if (!c->c_proxy) { 1878 1.37 lukem fputs("?Invalid proxy command.\n", ttyout); 1879 1.1 cgd code = -1; 1880 1.1 cgd return; 1881 1.1 cgd } 1882 1.72 lukem if (sigsetjmp(abortprox, 1)) { 1883 1.1 cgd code = -1; 1884 1.1 cgd return; 1885 1.1 cgd } 1886 1.62 lukem oldintr = xsignal(SIGINT, proxabort); 1887 1.1 cgd pswitch(1); 1888 1.1 cgd if (c->c_conn && !connected) { 1889 1.37 lukem fputs("Not connected.\n", ttyout); 1890 1.1 cgd pswitch(0); 1891 1.62 lukem (void)xsignal(SIGINT, oldintr); 1892 1.1 cgd code = -1; 1893 1.1 cgd return; 1894 1.1 cgd } 1895 1.14 lukem cmdpos = strcspn(line, " \t"); 1896 1.14 lukem if (cmdpos > 0) /* remove leading "proxy " from input buffer */ 1897 1.14 lukem memmove(line, line + cmdpos + 1, strlen(line) - cmdpos + 1); 1898 1.129 lukem (void)strlcpy(cmdbuf, c->c_name, sizeof(cmdbuf)); 1899 1.129 lukem argv[1] = cmdbuf; 1900 1.1 cgd (*c->c_handler)(argc-1, argv+1); 1901 1.1 cgd if (connected) { 1902 1.1 cgd proxflag = 1; 1903 1.1 cgd } 1904 1.1 cgd else { 1905 1.1 cgd proxflag = 0; 1906 1.1 cgd } 1907 1.1 cgd pswitch(0); 1908 1.62 lukem (void)xsignal(SIGINT, oldintr); 1909 1.1 cgd } 1910 1.1 cgd 1911 1.4 cgd void 1912 1.85 lukem setcase(int argc, char *argv[]) 1913 1.1 cgd { 1914 1.4 cgd 1915 1.10 lukem code = togglevar(argc, argv, &mcase, "Case mapping"); 1916 1.1 cgd } 1917 1.1 cgd 1918 1.63 lukem /* 1919 1.63 lukem * convert the given name to lower case if it's all upper case, into 1920 1.63 lukem * a static buffer which is returned to the caller 1921 1.63 lukem */ 1922 1.144 christos static char * 1923 1.110 christos docase(char *dst, size_t dlen, const char *src) 1924 1.63 lukem { 1925 1.110 christos size_t i; 1926 1.110 christos int dochange = 1; 1927 1.63 lukem 1928 1.110 christos for (i = 0; src[i] != '\0' && i < dlen - 1; i++) { 1929 1.110 christos dst[i] = src[i]; 1930 1.110 christos if (islower((unsigned char)dst[i])) 1931 1.63 lukem dochange = 0; 1932 1.63 lukem } 1933 1.110 christos dst[i] = '\0'; 1934 1.63 lukem 1935 1.63 lukem if (dochange) { 1936 1.110 christos for (i = 0; dst[i] != '\0'; i++) 1937 1.110 christos if (isupper((unsigned char)dst[i])) 1938 1.110 christos dst[i] = tolower((unsigned char)dst[i]); 1939 1.63 lukem } 1940 1.110 christos return dst; 1941 1.63 lukem } 1942 1.63 lukem 1943 1.4 cgd void 1944 1.85 lukem setcr(int argc, char *argv[]) 1945 1.1 cgd { 1946 1.4 cgd 1947 1.10 lukem code = togglevar(argc, argv, &crflag, "Carriage Return stripping"); 1948 1.1 cgd } 1949 1.1 cgd 1950 1.4 cgd void 1951 1.85 lukem setntrans(int argc, char *argv[]) 1952 1.1 cgd { 1953 1.76 lukem 1954 1.88 lukem if (argc == 0 || argc > 3) { 1955 1.116 christos UPRINTF("usage: %s [inchars [outchars]]\n", argv[0]); 1956 1.76 lukem code = -1; 1957 1.76 lukem return; 1958 1.76 lukem } 1959 1.1 cgd if (argc == 1) { 1960 1.1 cgd ntflag = 0; 1961 1.37 lukem fputs("Ntrans off.\n", ttyout); 1962 1.1 cgd code = ntflag; 1963 1.1 cgd return; 1964 1.1 cgd } 1965 1.1 cgd ntflag++; 1966 1.1 cgd code = ntflag; 1967 1.63 lukem (void)strlcpy(ntin, argv[1], sizeof(ntin)); 1968 1.1 cgd if (argc == 2) { 1969 1.1 cgd ntout[0] = '\0'; 1970 1.1 cgd return; 1971 1.1 cgd } 1972 1.63 lukem (void)strlcpy(ntout, argv[2], sizeof(ntout)); 1973 1.1 cgd } 1974 1.1 cgd 1975 1.144 christos #define ADDC(x) \ 1976 1.144 christos do { \ 1977 1.144 christos *cp2++ = x; \ 1978 1.144 christos if (cp2 - dst >= (ptrdiff_t)(dlen - 1)) \ 1979 1.144 christos goto out; \ 1980 1.144 christos } while (0) 1981 1.144 christos 1982 1.144 christos static char * 1983 1.110 christos dotrans(char *dst, size_t dlen, const char *src) 1984 1.1 cgd { 1985 1.110 christos const char *cp1; 1986 1.110 christos char *cp2 = dst; 1987 1.110 christos size_t i, ostop; 1988 1.1 cgd 1989 1.136 christos for (ostop = 0; ntout[ostop] && ostop < sizeof(ntout); ostop++) 1990 1.4 cgd continue; 1991 1.110 christos for (cp1 = src; *cp1; cp1++) { 1992 1.110 christos int found = 0; 1993 1.137 christos for (i = 0; i < sizeof(ntin) && ntin[i]; i++) { 1994 1.136 christos if (*cp1 == ntin[i]) { 1995 1.1 cgd found++; 1996 1.1 cgd if (i < ostop) { 1997 1.144 christos ADDC(ntout[i]); 1998 1.1 cgd } 1999 1.1 cgd break; 2000 1.1 cgd } 2001 1.1 cgd } 2002 1.1 cgd if (!found) { 2003 1.144 christos ADDC(*cp1); 2004 1.1 cgd } 2005 1.1 cgd } 2006 1.110 christos out: 2007 1.1 cgd *cp2 = '\0'; 2008 1.110 christos return dst; 2009 1.1 cgd } 2010 1.1 cgd 2011 1.4 cgd void 2012 1.85 lukem setnmap(int argc, char *argv[]) 2013 1.1 cgd { 2014 1.1 cgd char *cp; 2015 1.1 cgd 2016 1.1 cgd if (argc == 1) { 2017 1.1 cgd mapflag = 0; 2018 1.37 lukem fputs("Nmap off.\n", ttyout); 2019 1.1 cgd code = mapflag; 2020 1.1 cgd return; 2021 1.1 cgd } 2022 1.88 lukem if (argc == 0 || 2023 1.76 lukem (argc < 3 && !another(&argc, &argv, "mapout")) || argc > 3) { 2024 1.116 christos UPRINTF("usage: %s [mapin mapout]\n", argv[0]); 2025 1.1 cgd code = -1; 2026 1.1 cgd return; 2027 1.1 cgd } 2028 1.1 cgd mapflag = 1; 2029 1.1 cgd code = 1; 2030 1.4 cgd cp = strchr(altarg, ' '); 2031 1.1 cgd if (proxy) { 2032 1.4 cgd while(*++cp == ' ') 2033 1.4 cgd continue; 2034 1.1 cgd altarg = cp; 2035 1.4 cgd cp = strchr(altarg, ' '); 2036 1.1 cgd } 2037 1.1 cgd *cp = '\0'; 2038 1.63 lukem (void)strlcpy(mapin, altarg, MAXPATHLEN); 2039 1.4 cgd while (*++cp == ' ') 2040 1.4 cgd continue; 2041 1.63 lukem (void)strlcpy(mapout, cp, MAXPATHLEN); 2042 1.1 cgd } 2043 1.1 cgd 2044 1.144 christos static char * 2045 1.144 christos domap(char *dst, size_t dlen, const char *src) 2046 1.1 cgd { 2047 1.110 christos const char *cp1 = src; 2048 1.110 christos char *cp2 = mapin; 2049 1.110 christos const char *tp[9], *te[9]; 2050 1.1 cgd int i, toks[9], toknum = 0, match = 1; 2051 1.1 cgd 2052 1.1 cgd for (i=0; i < 9; ++i) { 2053 1.1 cgd toks[i] = 0; 2054 1.1 cgd } 2055 1.1 cgd while (match && *cp1 && *cp2) { 2056 1.1 cgd switch (*cp2) { 2057 1.1 cgd case '\\': 2058 1.1 cgd if (*++cp2 != *cp1) { 2059 1.1 cgd match = 0; 2060 1.1 cgd } 2061 1.1 cgd break; 2062 1.1 cgd case '$': 2063 1.1 cgd if (*(cp2+1) >= '1' && (*cp2+1) <= '9') { 2064 1.1 cgd if (*cp1 != *(++cp2+1)) { 2065 1.1 cgd toks[toknum = *cp2 - '1']++; 2066 1.1 cgd tp[toknum] = cp1; 2067 1.1 cgd while (*++cp1 && *(cp2+1) 2068 1.1 cgd != *cp1); 2069 1.1 cgd te[toknum] = cp1; 2070 1.1 cgd } 2071 1.1 cgd cp2++; 2072 1.1 cgd break; 2073 1.1 cgd } 2074 1.1 cgd /* FALLTHROUGH */ 2075 1.1 cgd default: 2076 1.1 cgd if (*cp2 != *cp1) { 2077 1.1 cgd match = 0; 2078 1.1 cgd } 2079 1.1 cgd break; 2080 1.1 cgd } 2081 1.1 cgd if (match && *cp1) { 2082 1.1 cgd cp1++; 2083 1.1 cgd } 2084 1.1 cgd if (match && *cp2) { 2085 1.1 cgd cp2++; 2086 1.1 cgd } 2087 1.1 cgd } 2088 1.1 cgd if (!match && *cp1) /* last token mismatch */ 2089 1.1 cgd { 2090 1.1 cgd toks[toknum] = 0; 2091 1.1 cgd } 2092 1.110 christos cp2 = dst; 2093 1.110 christos *cp2 = '\0'; 2094 1.110 christos cp1 = mapout; 2095 1.110 christos while (*cp1) { 2096 1.1 cgd match = 0; 2097 1.110 christos switch (*cp1) { 2098 1.1 cgd case '\\': 2099 1.110 christos if (*(cp1 + 1)) { 2100 1.144 christos ADDC(*++cp1); 2101 1.1 cgd } 2102 1.1 cgd break; 2103 1.1 cgd case '[': 2104 1.1 cgd LOOP: 2105 1.110 christos if (*++cp1 == '$' && 2106 1.110 christos isdigit((unsigned char)*(cp1+1))) { 2107 1.110 christos if (*++cp1 == '0') { 2108 1.110 christos const char *cp3 = src; 2109 1.1 cgd 2110 1.1 cgd while (*cp3) { 2111 1.144 christos ADDC(*cp3++); 2112 1.1 cgd } 2113 1.1 cgd match = 1; 2114 1.1 cgd } 2115 1.110 christos else if (toks[toknum = *cp1 - '1']) { 2116 1.110 christos const char *cp3 = tp[toknum]; 2117 1.1 cgd 2118 1.1 cgd while (cp3 != te[toknum]) { 2119 1.144 christos ADDC(*cp3++); 2120 1.1 cgd } 2121 1.1 cgd match = 1; 2122 1.1 cgd } 2123 1.1 cgd } 2124 1.1 cgd else { 2125 1.110 christos while (*cp1 && *cp1 != ',' && 2126 1.110 christos *cp1 != ']') { 2127 1.110 christos if (*cp1 == '\\') { 2128 1.110 christos cp1++; 2129 1.1 cgd } 2130 1.110 christos else if (*cp1 == '$' && 2131 1.110 christos isdigit((unsigned char)*(cp1+1))) { 2132 1.110 christos if (*++cp1 == '0') { 2133 1.110 christos const char *cp3 = src; 2134 1.1 cgd 2135 1.1 cgd while (*cp3) { 2136 1.144 christos ADDC(*cp3++); 2137 1.1 cgd } 2138 1.1 cgd } 2139 1.1 cgd else if (toks[toknum = 2140 1.110 christos *cp1 - '1']) { 2141 1.110 christos const char *cp3=tp[toknum]; 2142 1.1 cgd 2143 1.1 cgd while (cp3 != 2144 1.1 cgd te[toknum]) { 2145 1.144 christos ADDC(*cp3++); 2146 1.1 cgd } 2147 1.1 cgd } 2148 1.1 cgd } 2149 1.110 christos else if (*cp1) { 2150 1.144 christos ADDC(*cp1++); 2151 1.1 cgd } 2152 1.1 cgd } 2153 1.110 christos if (!*cp1) { 2154 1.144 christos goto unbalanced; 2155 1.1 cgd } 2156 1.1 cgd match = 1; 2157 1.110 christos cp1--; 2158 1.1 cgd } 2159 1.1 cgd if (match) { 2160 1.110 christos while (*++cp1 && *cp1 != ']') { 2161 1.110 christos if (*cp1 == '\\' && *(cp1 + 1)) { 2162 1.110 christos cp1++; 2163 1.1 cgd } 2164 1.1 cgd } 2165 1.110 christos if (!*cp1) { 2166 1.144 christos goto unbalanced; 2167 1.1 cgd } 2168 1.1 cgd break; 2169 1.1 cgd } 2170 1.110 christos switch (*++cp1) { 2171 1.1 cgd case ',': 2172 1.1 cgd goto LOOP; 2173 1.1 cgd case ']': 2174 1.1 cgd break; 2175 1.1 cgd default: 2176 1.110 christos cp1--; 2177 1.1 cgd goto LOOP; 2178 1.1 cgd } 2179 1.1 cgd break; 2180 1.1 cgd case '$': 2181 1.110 christos if (isdigit((unsigned char)*(cp1 + 1))) { 2182 1.110 christos if (*++cp1 == '0') { 2183 1.110 christos const char *cp3 = src; 2184 1.1 cgd 2185 1.1 cgd while (*cp3) { 2186 1.144 christos ADDC(*cp3++); 2187 1.1 cgd } 2188 1.1 cgd } 2189 1.110 christos else if (toks[toknum = *cp1 - '1']) { 2190 1.110 christos const char *cp3 = tp[toknum]; 2191 1.1 cgd 2192 1.1 cgd while (cp3 != te[toknum]) { 2193 1.144 christos ADDC(*cp3++); 2194 1.1 cgd } 2195 1.1 cgd } 2196 1.1 cgd break; 2197 1.1 cgd } 2198 1.139 mrg /* FALLTHROUGH */ 2199 1.1 cgd default: 2200 1.144 christos ADDC(*cp1); 2201 1.1 cgd break; 2202 1.1 cgd } 2203 1.110 christos cp1++; 2204 1.1 cgd } 2205 1.144 christos out: 2206 1.110 christos *cp2 = '\0'; 2207 1.144 christos if (!*dst) 2208 1.144 christos strlcpy(dst, src, dlen); 2209 1.144 christos return dst; 2210 1.144 christos unbalanced: 2211 1.144 christos fputs("nmap: unbalanced brackets.\n", ttyout); 2212 1.144 christos *dst = '\0'; 2213 1.144 christos goto out; 2214 1.1 cgd } 2215 1.1 cgd 2216 1.4 cgd void 2217 1.85 lukem setpassive(int argc, char *argv[]) 2218 1.5 cgd { 2219 1.5 cgd 2220 1.76 lukem if (argc == 1) { 2221 1.76 lukem passivemode = !passivemode; 2222 1.76 lukem activefallback = passivemode; 2223 1.76 lukem } else if (argc != 2) { 2224 1.76 lukem passiveusage: 2225 1.116 christos UPRINTF("usage: %s [ on | off | auto ]\n", argv[0]); 2226 1.76 lukem code = -1; 2227 1.76 lukem return; 2228 1.76 lukem } else if (strcasecmp(argv[1], "on") == 0) { 2229 1.76 lukem passivemode = 1; 2230 1.76 lukem activefallback = 0; 2231 1.76 lukem } else if (strcasecmp(argv[1], "off") == 0) { 2232 1.76 lukem passivemode = 0; 2233 1.76 lukem activefallback = 0; 2234 1.76 lukem } else if (strcasecmp(argv[1], "auto") == 0) { 2235 1.76 lukem passivemode = 1; 2236 1.76 lukem activefallback = 1; 2237 1.76 lukem } else 2238 1.76 lukem goto passiveusage; 2239 1.76 lukem fprintf(ttyout, "Passive mode: %s; fallback to active mode: %s.\n", 2240 1.76 lukem onoff(passivemode), onoff(activefallback)); 2241 1.76 lukem code = passivemode; 2242 1.5 cgd } 2243 1.5 cgd 2244 1.125 skd 2245 1.5 cgd void 2246 1.85 lukem setepsv4(int argc, char *argv[]) 2247 1.68 lukem { 2248 1.68 lukem code = togglevar(argc, argv, &epsv4, 2249 1.68 lukem verbose ? "EPSV/EPRT on IPv4" : NULL); 2250 1.68 lukem epsv4bad = 0; 2251 1.68 lukem } 2252 1.68 lukem 2253 1.68 lukem void 2254 1.125 skd setepsv6(int argc, char *argv[]) 2255 1.125 skd { 2256 1.125 skd code = togglevar(argc, argv, &epsv6, 2257 1.125 skd verbose ? "EPSV/EPRT on IPv6" : NULL); 2258 1.125 skd epsv6bad = 0; 2259 1.125 skd } 2260 1.125 skd 2261 1.125 skd void 2262 1.125 skd setepsv(int argc, char*argv[]) 2263 1.125 skd { 2264 1.125 skd setepsv4(argc,argv); 2265 1.125 skd setepsv6(argc,argv); 2266 1.125 skd } 2267 1.125 skd 2268 1.125 skd void 2269 1.85 lukem setsunique(int argc, char *argv[]) 2270 1.1 cgd { 2271 1.4 cgd 2272 1.10 lukem code = togglevar(argc, argv, &sunique, "Store unique"); 2273 1.1 cgd } 2274 1.1 cgd 2275 1.4 cgd void 2276 1.85 lukem setrunique(int argc, char *argv[]) 2277 1.1 cgd { 2278 1.4 cgd 2279 1.10 lukem code = togglevar(argc, argv, &runique, "Receive unique"); 2280 1.1 cgd } 2281 1.1 cgd 2282 1.52 lukem int 2283 1.85 lukem parserate(int argc, char *argv[], int cmdlineopt) 2284 1.52 lukem { 2285 1.52 lukem int dir, max, incr, showonly; 2286 1.82 lukem sigfunc oldusr1, oldusr2; 2287 1.52 lukem 2288 1.52 lukem if (argc > 4 || (argc < (cmdlineopt ? 3 : 2))) { 2289 1.88 lukem usage: 2290 1.52 lukem if (cmdlineopt) 2291 1.116 christos UPRINTF( 2292 1.66 lukem "usage: %s (all|get|put),maximum-bytes[,increment-bytes]]\n", 2293 1.52 lukem argv[0]); 2294 1.52 lukem else 2295 1.116 christos UPRINTF( 2296 1.66 lukem "usage: %s (all|get|put) [maximum-bytes [increment-bytes]]\n", 2297 1.52 lukem argv[0]); 2298 1.52 lukem return -1; 2299 1.52 lukem } 2300 1.52 lukem dir = max = incr = showonly = 0; 2301 1.76 lukem #define RATE_GET 1 2302 1.76 lukem #define RATE_PUT 2 2303 1.76 lukem #define RATE_ALL (RATE_GET | RATE_PUT) 2304 1.52 lukem 2305 1.52 lukem if (strcasecmp(argv[1], "all") == 0) 2306 1.52 lukem dir = RATE_ALL; 2307 1.52 lukem else if (strcasecmp(argv[1], "get") == 0) 2308 1.52 lukem dir = RATE_GET; 2309 1.52 lukem else if (strcasecmp(argv[1], "put") == 0) 2310 1.52 lukem dir = RATE_PUT; 2311 1.52 lukem else 2312 1.52 lukem goto usage; 2313 1.52 lukem 2314 1.52 lukem if (argc >= 3) { 2315 1.52 lukem if ((max = strsuftoi(argv[2])) < 0) 2316 1.52 lukem goto usage; 2317 1.52 lukem } else 2318 1.52 lukem showonly = 1; 2319 1.52 lukem 2320 1.52 lukem if (argc == 4) { 2321 1.52 lukem if ((incr = strsuftoi(argv[3])) <= 0) 2322 1.52 lukem goto usage; 2323 1.52 lukem } else 2324 1.52 lukem incr = DEFAULTINCR; 2325 1.52 lukem 2326 1.62 lukem oldusr1 = xsignal(SIGUSR1, SIG_IGN); 2327 1.62 lukem oldusr2 = xsignal(SIGUSR2, SIG_IGN); 2328 1.52 lukem if (dir & RATE_GET) { 2329 1.52 lukem if (!showonly) { 2330 1.52 lukem rate_get = max; 2331 1.52 lukem rate_get_incr = incr; 2332 1.52 lukem } 2333 1.52 lukem if (!cmdlineopt || verbose) 2334 1.52 lukem fprintf(ttyout, 2335 1.53 lukem "Get transfer rate throttle: %s; maximum: %d; increment %d.\n", 2336 1.52 lukem onoff(rate_get), rate_get, rate_get_incr); 2337 1.52 lukem } 2338 1.52 lukem if (dir & RATE_PUT) { 2339 1.52 lukem if (!showonly) { 2340 1.52 lukem rate_put = max; 2341 1.52 lukem rate_put_incr = incr; 2342 1.52 lukem } 2343 1.52 lukem if (!cmdlineopt || verbose) 2344 1.52 lukem fprintf(ttyout, 2345 1.53 lukem "Put transfer rate throttle: %s; maximum: %d; increment %d.\n", 2346 1.52 lukem onoff(rate_put), rate_put, rate_put_incr); 2347 1.52 lukem } 2348 1.62 lukem (void)xsignal(SIGUSR1, oldusr1); 2349 1.62 lukem (void)xsignal(SIGUSR2, oldusr2); 2350 1.52 lukem return 0; 2351 1.52 lukem } 2352 1.52 lukem 2353 1.52 lukem void 2354 1.85 lukem setrate(int argc, char *argv[]) 2355 1.52 lukem { 2356 1.52 lukem 2357 1.52 lukem code = parserate(argc, argv, 0); 2358 1.52 lukem } 2359 1.52 lukem 2360 1.16 lukem /* change directory to parent directory */ 2361 1.4 cgd void 2362 1.85 lukem cdup(int argc, char *argv[]) 2363 1.1 cgd { 2364 1.16 lukem int r; 2365 1.4 cgd 2366 1.88 lukem if (argc == 0) { 2367 1.116 christos UPRINTF("usage: %s\n", argv[0]); 2368 1.76 lukem code = -1; 2369 1.76 lukem return; 2370 1.76 lukem } 2371 1.16 lukem r = command("CDUP"); 2372 1.16 lukem if (r == ERROR && code == 500) { 2373 1.1 cgd if (verbose) 2374 1.37 lukem fputs("CDUP command not recognized, trying XCUP.\n", 2375 1.37 lukem ttyout); 2376 1.16 lukem r = command("XCUP"); 2377 1.1 cgd } 2378 1.79 lukem if (r == COMPLETE) { 2379 1.16 lukem dirchange = 1; 2380 1.138 kre remotecwd[0] = '\0'; 2381 1.138 kre remcwdvalid = 0; 2382 1.79 lukem } 2383 1.1 cgd } 2384 1.1 cgd 2385 1.27 lukem /* 2386 1.27 lukem * Restart transfer at specific point 2387 1.27 lukem */ 2388 1.4 cgd void 2389 1.85 lukem restart(int argc, char *argv[]) 2390 1.1 cgd { 2391 1.4 cgd 2392 1.88 lukem if (argc == 0 || argc > 2) { 2393 1.116 christos UPRINTF("usage: %s [restart-point]\n", argv[0]); 2394 1.31 lukem code = -1; 2395 1.31 lukem return; 2396 1.31 lukem } 2397 1.88 lukem if (! features[FEAT_REST_STREAM]) { 2398 1.88 lukem fprintf(ttyout, 2399 1.88 lukem "Restart is not supported by the remote server.\n"); 2400 1.88 lukem return; 2401 1.88 lukem } 2402 1.31 lukem if (argc == 2) { 2403 1.60 lukem off_t rp; 2404 1.31 lukem char *ep; 2405 1.31 lukem 2406 1.89 lukem rp = STRTOLL(argv[1], &ep, 10); 2407 1.31 lukem if (rp < 0 || *ep != '\0') 2408 1.37 lukem fprintf(ttyout, "restart: Invalid offset `%s'\n", 2409 1.37 lukem argv[1]); 2410 1.31 lukem else 2411 1.31 lukem restart_point = rp; 2412 1.1 cgd } 2413 1.31 lukem if (restart_point == 0) 2414 1.37 lukem fputs("No restart point defined.\n", ttyout); 2415 1.31 lukem else 2416 1.37 lukem fprintf(ttyout, 2417 1.90 lukem "Restarting at " LLF " for next get, put or append\n", 2418 1.90 lukem (LLT)restart_point); 2419 1.1 cgd } 2420 1.1 cgd 2421 1.47 lukem /* 2422 1.27 lukem * Show remote system type 2423 1.27 lukem */ 2424 1.4 cgd void 2425 1.85 lukem syst(int argc, char *argv[]) 2426 1.1 cgd { 2427 1.88 lukem int oldverbose = verbose; 2428 1.4 cgd 2429 1.88 lukem if (argc == 0) { 2430 1.116 christos UPRINTF("usage: %s\n", argv[0]); 2431 1.76 lukem code = -1; 2432 1.76 lukem return; 2433 1.76 lukem } 2434 1.88 lukem verbose = 1; /* If we aren't verbose, this doesn't do anything! */ 2435 1.19 lukem (void)command("SYST"); 2436 1.88 lukem verbose = oldverbose; 2437 1.1 cgd } 2438 1.1 cgd 2439 1.4 cgd void 2440 1.85 lukem macdef(int argc, char *argv[]) 2441 1.1 cgd { 2442 1.1 cgd char *tmp; 2443 1.1 cgd int c; 2444 1.1 cgd 2445 1.88 lukem if (argc == 0) 2446 1.76 lukem goto usage; 2447 1.1 cgd if (macnum == 16) { 2448 1.37 lukem fputs("Limit of 16 macros have already been defined.\n", 2449 1.37 lukem ttyout); 2450 1.1 cgd code = -1; 2451 1.1 cgd return; 2452 1.1 cgd } 2453 1.10 lukem if ((argc < 2 && !another(&argc, &argv, "macro name")) || argc > 2) { 2454 1.76 lukem usage: 2455 1.116 christos UPRINTF("usage: %s macro_name\n", argv[0]); 2456 1.1 cgd code = -1; 2457 1.1 cgd return; 2458 1.1 cgd } 2459 1.19 lukem if (interactive) 2460 1.37 lukem fputs( 2461 1.37 lukem "Enter macro line by line, terminating it with a null line.\n", 2462 1.37 lukem ttyout); 2463 1.63 lukem (void)strlcpy(macros[macnum].mac_name, argv[1], 2464 1.63 lukem sizeof(macros[macnum].mac_name)); 2465 1.19 lukem if (macnum == 0) 2466 1.1 cgd macros[macnum].mac_start = macbuf; 2467 1.19 lukem else 2468 1.1 cgd macros[macnum].mac_start = macros[macnum - 1].mac_end + 1; 2469 1.1 cgd tmp = macros[macnum].mac_start; 2470 1.1 cgd while (tmp != macbuf+4096) { 2471 1.1 cgd if ((c = getchar()) == EOF) { 2472 1.37 lukem fputs("macdef: end of file encountered.\n", ttyout); 2473 1.1 cgd code = -1; 2474 1.1 cgd return; 2475 1.1 cgd } 2476 1.1 cgd if ((*tmp = c) == '\n') { 2477 1.1 cgd if (tmp == macros[macnum].mac_start) { 2478 1.1 cgd macros[macnum++].mac_end = tmp; 2479 1.1 cgd code = 0; 2480 1.1 cgd return; 2481 1.1 cgd } 2482 1.1 cgd if (*(tmp-1) == '\0') { 2483 1.1 cgd macros[macnum++].mac_end = tmp - 1; 2484 1.1 cgd code = 0; 2485 1.1 cgd return; 2486 1.1 cgd } 2487 1.1 cgd *tmp = '\0'; 2488 1.1 cgd } 2489 1.1 cgd tmp++; 2490 1.1 cgd } 2491 1.143 christos for (;;) { 2492 1.1 cgd while ((c = getchar()) != '\n' && c != EOF) 2493 1.1 cgd /* LOOP */; 2494 1.1 cgd if (c == EOF || getchar() == '\n') { 2495 1.142 lukem fputs("Macro not defined - 4 KiB buffer exceeded.\n", 2496 1.37 lukem ttyout); 2497 1.1 cgd code = -1; 2498 1.1 cgd return; 2499 1.1 cgd } 2500 1.1 cgd } 2501 1.1 cgd } 2502 1.1 cgd 2503 1.1 cgd /* 2504 1.27 lukem * Get size of file on remote machine 2505 1.1 cgd */ 2506 1.4 cgd void 2507 1.85 lukem sizecmd(int argc, char *argv[]) 2508 1.1 cgd { 2509 1.11 lukem off_t size; 2510 1.1 cgd 2511 1.88 lukem if (argc == 0 || argc > 2 || 2512 1.88 lukem (argc == 1 && !another(&argc, &argv, "remote-file"))) { 2513 1.116 christos UPRINTF("usage: %s remote-file\n", argv[0]); 2514 1.1 cgd code = -1; 2515 1.1 cgd return; 2516 1.1 cgd } 2517 1.13 lukem size = remotesize(argv[1], 1); 2518 1.11 lukem if (size != -1) 2519 1.37 lukem fprintf(ttyout, 2520 1.90 lukem "%s\t" LLF "\n", argv[1], (LLT)size); 2521 1.76 lukem code = (size > 0); 2522 1.10 lukem } 2523 1.10 lukem 2524 1.10 lukem /* 2525 1.27 lukem * Get last modification time of file on remote machine 2526 1.10 lukem */ 2527 1.10 lukem void 2528 1.85 lukem modtime(int argc, char *argv[]) 2529 1.10 lukem { 2530 1.10 lukem time_t mtime; 2531 1.10 lukem 2532 1.88 lukem if (argc == 0 || argc > 2 || 2533 1.88 lukem (argc == 1 && !another(&argc, &argv, "remote-file"))) { 2534 1.116 christos UPRINTF("usage: %s remote-file\n", argv[0]); 2535 1.10 lukem code = -1; 2536 1.10 lukem return; 2537 1.10 lukem } 2538 1.13 lukem mtime = remotemodtime(argv[1], 1); 2539 1.10 lukem if (mtime != -1) 2540 1.123 lukem fprintf(ttyout, "%s\t%s", argv[1], 2541 1.123 lukem rfc2822time(localtime(&mtime))); 2542 1.76 lukem code = (mtime > 0); 2543 1.1 cgd } 2544 1.1 cgd 2545 1.1 cgd /* 2546 1.27 lukem * Show status on remote machine 2547 1.1 cgd */ 2548 1.4 cgd void 2549 1.85 lukem rmtstatus(int argc, char *argv[]) 2550 1.1 cgd { 2551 1.4 cgd 2552 1.88 lukem if (argc == 0) { 2553 1.116 christos UPRINTF("usage: %s [remote-file]\n", argv[0]); 2554 1.76 lukem code = -1; 2555 1.76 lukem return; 2556 1.76 lukem } 2557 1.91 is COMMAND_1ARG(argc, argv, "STAT"); 2558 1.1 cgd } 2559 1.1 cgd 2560 1.1 cgd /* 2561 1.27 lukem * Get file if modtime is more recent than current file 2562 1.1 cgd */ 2563 1.4 cgd void 2564 1.85 lukem newer(int argc, char *argv[]) 2565 1.1 cgd { 2566 1.4 cgd 2567 1.1 cgd if (getit(argc, argv, -1, "w")) 2568 1.37 lukem fprintf(ttyout, 2569 1.37 lukem "Local file \"%s\" is newer than remote file \"%s\".\n", 2570 1.37 lukem argv[2], argv[1]); 2571 1.19 lukem } 2572 1.19 lukem 2573 1.19 lukem /* 2574 1.76 lukem * Display one local file through $PAGER. 2575 1.19 lukem */ 2576 1.19 lukem void 2577 1.85 lukem lpage(int argc, char *argv[]) 2578 1.19 lukem { 2579 1.114 lukem size_t len; 2580 1.129 lukem const char *p; 2581 1.129 lukem char *pager, *locfile; 2582 1.19 lukem 2583 1.88 lukem if (argc == 0 || argc > 2 || 2584 1.88 lukem (argc == 1 && !another(&argc, &argv, "local-file"))) { 2585 1.116 christos UPRINTF("usage: %s local-file\n", argv[0]); 2586 1.19 lukem code = -1; 2587 1.19 lukem return; 2588 1.19 lukem } 2589 1.63 lukem if ((locfile = globulize(argv[1])) == NULL) { 2590 1.63 lukem code = -1; 2591 1.63 lukem return; 2592 1.63 lukem } 2593 1.76 lukem p = getoptionvalue("pager"); 2594 1.76 lukem if (EMPTYSTRING(p)) 2595 1.76 lukem p = DEFAULTPAGER; 2596 1.63 lukem len = strlen(p) + strlen(locfile) + 2; 2597 1.117 christos pager = ftp_malloc(len); 2598 1.63 lukem (void)strlcpy(pager, p, len); 2599 1.63 lukem (void)strlcat(pager, " ", len); 2600 1.63 lukem (void)strlcat(pager, locfile, len); 2601 1.63 lukem system(pager); 2602 1.76 lukem code = 0; 2603 1.63 lukem (void)free(pager); 2604 1.63 lukem (void)free(locfile); 2605 1.63 lukem } 2606 1.63 lukem 2607 1.63 lukem /* 2608 1.76 lukem * Display one remote file through $PAGER. 2609 1.63 lukem */ 2610 1.63 lukem void 2611 1.85 lukem page(int argc, char *argv[]) 2612 1.63 lukem { 2613 1.143 christos int ohash, overbose; 2614 1.143 christos off_t orestart_point; 2615 1.114 lukem size_t len; 2616 1.129 lukem const char *p; 2617 1.129 lukem char *pager; 2618 1.63 lukem 2619 1.88 lukem if (argc == 0 || argc > 2 || 2620 1.88 lukem (argc == 1 && !another(&argc, &argv, "remote-file"))) { 2621 1.116 christos UPRINTF("usage: %s remote-file\n", argv[0]); 2622 1.19 lukem code = -1; 2623 1.19 lukem return; 2624 1.19 lukem } 2625 1.76 lukem p = getoptionvalue("pager"); 2626 1.76 lukem if (EMPTYSTRING(p)) 2627 1.76 lukem p = DEFAULTPAGER; 2628 1.49 lukem len = strlen(p) + 2; 2629 1.117 christos pager = ftp_malloc(len); 2630 1.57 lukem pager[0] = '|'; 2631 1.63 lukem (void)strlcpy(pager + 1, p, len - 1); 2632 1.19 lukem 2633 1.19 lukem ohash = hash; 2634 1.37 lukem orestart_point = restart_point; 2635 1.19 lukem overbose = verbose; 2636 1.143 christos hash = verbose = 0; 2637 1.143 christos restart_point = 0; 2638 1.97 lukem recvrequest("RETR", pager, argv[1], "r+", 1, 0); 2639 1.19 lukem hash = ohash; 2640 1.37 lukem restart_point = orestart_point; 2641 1.19 lukem verbose = overbose; 2642 1.63 lukem (void)free(pager); 2643 1.39 thorpej } 2644 1.39 thorpej 2645 1.39 thorpej /* 2646 1.58 lukem * Set the socket send or receive buffer size. 2647 1.39 thorpej */ 2648 1.39 thorpej void 2649 1.85 lukem setxferbuf(int argc, char *argv[]) 2650 1.39 thorpej { 2651 1.58 lukem int size, dir; 2652 1.39 thorpej 2653 1.39 thorpej if (argc != 2) { 2654 1.58 lukem usage: 2655 1.116 christos UPRINTF("usage: %s size\n", argv[0]); 2656 1.39 thorpej code = -1; 2657 1.39 thorpej return; 2658 1.39 thorpej } 2659 1.58 lukem if (strcasecmp(argv[0], "sndbuf") == 0) 2660 1.58 lukem dir = RATE_PUT; 2661 1.58 lukem else if (strcasecmp(argv[0], "rcvbuf") == 0) 2662 1.58 lukem dir = RATE_GET; 2663 1.58 lukem else if (strcasecmp(argv[0], "xferbuf") == 0) 2664 1.58 lukem dir = RATE_ALL; 2665 1.39 thorpej else 2666 1.58 lukem goto usage; 2667 1.39 thorpej 2668 1.58 lukem if ((size = strsuftoi(argv[1])) == -1) 2669 1.58 lukem goto usage; 2670 1.39 thorpej 2671 1.58 lukem if (size == 0) { 2672 1.58 lukem fprintf(ttyout, "%s: size must be positive.\n", argv[0]); 2673 1.58 lukem goto usage; 2674 1.39 thorpej } 2675 1.39 thorpej 2676 1.58 lukem if (dir & RATE_PUT) 2677 1.58 lukem sndbuf_size = size; 2678 1.58 lukem if (dir & RATE_GET) 2679 1.58 lukem rcvbuf_size = size; 2680 1.58 lukem fprintf(ttyout, "Socket buffer sizes: send %d, receive %d.\n", 2681 1.58 lukem sndbuf_size, rcvbuf_size); 2682 1.76 lukem code = 0; 2683 1.76 lukem } 2684 1.76 lukem 2685 1.76 lukem /* 2686 1.76 lukem * Set or display options (defaults are provided by various env vars) 2687 1.76 lukem */ 2688 1.76 lukem void 2689 1.85 lukem setoption(int argc, char *argv[]) 2690 1.76 lukem { 2691 1.76 lukem struct option *o; 2692 1.76 lukem 2693 1.76 lukem code = -1; 2694 1.88 lukem if (argc == 0 || (argc != 1 && argc != 3)) { 2695 1.116 christos UPRINTF("usage: %s [option value]\n", argv[0]); 2696 1.76 lukem return; 2697 1.76 lukem } 2698 1.76 lukem 2699 1.135 christos #define OPTIONINDENT ((int) sizeof("https_proxy")) 2700 1.76 lukem if (argc == 1) { 2701 1.76 lukem for (o = optiontab; o->name != NULL; o++) { 2702 1.76 lukem fprintf(ttyout, "%-*s\t%s\n", OPTIONINDENT, 2703 1.76 lukem o->name, o->value ? o->value : ""); 2704 1.76 lukem } 2705 1.76 lukem } else { 2706 1.129 lukem set_option(argv[1], argv[2], 1); 2707 1.76 lukem } 2708 1.76 lukem code = 0; 2709 1.76 lukem } 2710 1.76 lukem 2711 1.129 lukem void 2712 1.129 lukem set_option(const char * option, const char * value, int doverbose) 2713 1.129 lukem { 2714 1.129 lukem struct option *o; 2715 1.129 lukem 2716 1.129 lukem o = getoption(option); 2717 1.129 lukem if (o == NULL) { 2718 1.129 lukem fprintf(ttyout, "No such option `%s'.\n", option); 2719 1.129 lukem return; 2720 1.129 lukem } 2721 1.129 lukem FREEPTR(o->value); 2722 1.129 lukem o->value = ftp_strdup(value); 2723 1.129 lukem if (verbose && doverbose) 2724 1.129 lukem fprintf(ttyout, "Setting `%s' to `%s'.\n", 2725 1.129 lukem o->name, o->value); 2726 1.129 lukem } 2727 1.129 lukem 2728 1.76 lukem /* 2729 1.76 lukem * Unset an option 2730 1.76 lukem */ 2731 1.76 lukem void 2732 1.85 lukem unsetoption(int argc, char *argv[]) 2733 1.76 lukem { 2734 1.76 lukem struct option *o; 2735 1.76 lukem 2736 1.76 lukem code = -1; 2737 1.88 lukem if (argc == 0 || argc != 2) { 2738 1.116 christos UPRINTF("usage: %s option\n", argv[0]); 2739 1.76 lukem return; 2740 1.76 lukem } 2741 1.76 lukem 2742 1.76 lukem o = getoption(argv[1]); 2743 1.76 lukem if (o == NULL) { 2744 1.76 lukem fprintf(ttyout, "No such option `%s'.\n", argv[1]); 2745 1.76 lukem return; 2746 1.76 lukem } 2747 1.76 lukem FREEPTR(o->value); 2748 1.76 lukem fprintf(ttyout, "Unsetting `%s'.\n", o->name); 2749 1.76 lukem code = 0; 2750 1.88 lukem } 2751 1.88 lukem 2752 1.88 lukem /* 2753 1.88 lukem * Display features supported by the remote host. 2754 1.88 lukem */ 2755 1.88 lukem void 2756 1.88 lukem feat(int argc, char *argv[]) 2757 1.88 lukem { 2758 1.88 lukem int oldverbose = verbose; 2759 1.88 lukem 2760 1.88 lukem if (argc == 0) { 2761 1.116 christos UPRINTF("usage: %s\n", argv[0]); 2762 1.88 lukem code = -1; 2763 1.88 lukem return; 2764 1.88 lukem } 2765 1.88 lukem if (! features[FEAT_FEAT]) { 2766 1.88 lukem fprintf(ttyout, 2767 1.88 lukem "FEAT is not supported by the remote server.\n"); 2768 1.88 lukem return; 2769 1.88 lukem } 2770 1.88 lukem verbose = 1; /* If we aren't verbose, this doesn't do anything! */ 2771 1.88 lukem (void)command("FEAT"); 2772 1.88 lukem verbose = oldverbose; 2773 1.88 lukem } 2774 1.88 lukem 2775 1.88 lukem void 2776 1.88 lukem mlst(int argc, char *argv[]) 2777 1.88 lukem { 2778 1.88 lukem int oldverbose = verbose; 2779 1.88 lukem 2780 1.88 lukem if (argc < 1 || argc > 2) { 2781 1.116 christos UPRINTF("usage: %s [remote-path]\n", argv[0]); 2782 1.88 lukem code = -1; 2783 1.88 lukem return; 2784 1.88 lukem } 2785 1.88 lukem if (! features[FEAT_MLST]) { 2786 1.88 lukem fprintf(ttyout, 2787 1.88 lukem "MLST is not supported by the remote server.\n"); 2788 1.88 lukem return; 2789 1.88 lukem } 2790 1.88 lukem verbose = 1; /* If we aren't verbose, this doesn't do anything! */ 2791 1.91 is COMMAND_1ARG(argc, argv, "MLST"); 2792 1.88 lukem verbose = oldverbose; 2793 1.88 lukem } 2794 1.88 lukem 2795 1.88 lukem void 2796 1.88 lukem opts(int argc, char *argv[]) 2797 1.88 lukem { 2798 1.88 lukem int oldverbose = verbose; 2799 1.88 lukem 2800 1.88 lukem if (argc < 2 || argc > 3) { 2801 1.116 christos UPRINTF("usage: %s command [options]\n", argv[0]); 2802 1.88 lukem code = -1; 2803 1.88 lukem return; 2804 1.88 lukem } 2805 1.88 lukem if (! features[FEAT_FEAT]) { 2806 1.88 lukem fprintf(ttyout, 2807 1.88 lukem "OPTS is not supported by the remote server.\n"); 2808 1.88 lukem return; 2809 1.88 lukem } 2810 1.88 lukem verbose = 1; /* If we aren't verbose, this doesn't do anything! */ 2811 1.91 is if (argc == 2) 2812 1.91 is command("OPTS %s", argv[1]); 2813 1.91 is else 2814 1.91 is command("OPTS %s %s", argv[1], argv[2]); 2815 1.88 lukem verbose = oldverbose; 2816 1.1 cgd } 2817