diff options
author | Darren Tucker <dtucker@zip.com.au> | 2009-10-07 08:37:48 +1100 |
---|---|---|
committer | Darren Tucker <dtucker@zip.com.au> | 2009-10-07 08:37:48 +1100 |
commit | 1b0dd175377c86abb7f3a3da2e9b1a89f36c7a1a (patch) | |
tree | d6b5f501c4c9890ed91ce4fd86be583213d7e8e6 /sftp.c | |
parent | 1477ea162c05c09b4b5ebc19ac588fbf469349dc (diff) |
- djm@cvs.openbsd.org 2009/08/18 18:36:21
[sftp-client.h sftp.1 sftp-client.c sftp.c]
recursive transfer support for get/put and on the commandline
work mostly by carlosvsilvapt@gmail.com for the Google Summer of Code
with some tweaks by me; "go for it" deraadt@
Diffstat (limited to 'sftp.c')
-rw-r--r-- | sftp.c | 219 |
1 files changed, 113 insertions, 106 deletions
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: sftp.c,v 1.110 2009/08/13 13:39:54 jmc Exp $ */ | 1 | /* $OpenBSD: sftp.c,v 1.111 2009/08/18 18:36:21 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org> | 3 | * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org> |
4 | * | 4 | * |
@@ -35,6 +35,9 @@ | |||
35 | #ifdef HAVE_PATHS_H | 35 | #ifdef HAVE_PATHS_H |
36 | # include <paths.h> | 36 | # include <paths.h> |
37 | #endif | 37 | #endif |
38 | #ifdef HAVE_LIBGEN_H | ||
39 | #include <libgen.h> | ||
40 | #endif | ||
38 | #ifdef USE_LIBEDIT | 41 | #ifdef USE_LIBEDIT |
39 | #include <histedit.h> | 42 | #include <histedit.h> |
40 | #else | 43 | #else |
@@ -83,6 +86,12 @@ static pid_t sshpid = -1; | |||
83 | /* This is set to 0 if the progressmeter is not desired. */ | 86 | /* This is set to 0 if the progressmeter is not desired. */ |
84 | int showprogress = 1; | 87 | int showprogress = 1; |
85 | 88 | ||
89 | /* When this option is set, we always recursively download/upload directories */ | ||
90 | int global_rflag = 0; | ||
91 | |||
92 | /* When this option is set, the file transfers will always preserve times */ | ||
93 | int global_pflag = 0; | ||
94 | |||
86 | /* SIGINT received during command processing */ | 95 | /* SIGINT received during command processing */ |
87 | volatile sig_atomic_t interrupted = 0; | 96 | volatile sig_atomic_t interrupted = 0; |
88 | 97 | ||
@@ -216,7 +225,7 @@ help(void) | |||
216 | "df [-hi] [path] Display statistics for current directory or\n" | 225 | "df [-hi] [path] Display statistics for current directory or\n" |
217 | " filesystem containing 'path'\n" | 226 | " filesystem containing 'path'\n" |
218 | "exit Quit sftp\n" | 227 | "exit Quit sftp\n" |
219 | "get [-P] remote-path [local-path] Download file\n" | 228 | "get [-Pr] remote-path [local-path] Download file\n" |
220 | "help Display this help text\n" | 229 | "help Display this help text\n" |
221 | "lcd path Change local directory to 'path'\n" | 230 | "lcd path Change local directory to 'path'\n" |
222 | "lls [ls-options [path]] Display local directory listing\n" | 231 | "lls [ls-options [path]] Display local directory listing\n" |
@@ -227,7 +236,7 @@ help(void) | |||
227 | "lumask umask Set local umask to 'umask'\n" | 236 | "lumask umask Set local umask to 'umask'\n" |
228 | "mkdir path Create remote directory\n" | 237 | "mkdir path Create remote directory\n" |
229 | "progress Toggle display of progress meter\n" | 238 | "progress Toggle display of progress meter\n" |
230 | "put [-P] local-path [remote-path] Upload file\n" | 239 | "put [-Pr] local-path [remote-path] Upload file\n" |
231 | "pwd Display remote working directory\n" | 240 | "pwd Display remote working directory\n" |
232 | "quit Quit sftp\n" | 241 | "quit Quit sftp\n" |
233 | "rename oldpath newpath Rename remote file\n" | 242 | "rename oldpath newpath Rename remote file\n" |
@@ -314,21 +323,6 @@ path_strip(char *path, char *strip) | |||
314 | } | 323 | } |
315 | 324 | ||
316 | static char * | 325 | static char * |
317 | path_append(char *p1, char *p2) | ||
318 | { | ||
319 | char *ret; | ||
320 | size_t len = strlen(p1) + strlen(p2) + 2; | ||
321 | |||
322 | ret = xmalloc(len); | ||
323 | strlcpy(ret, p1, len); | ||
324 | if (p1[0] != '\0' && p1[strlen(p1) - 1] != '/') | ||
325 | strlcat(ret, "/", len); | ||
326 | strlcat(ret, p2, len); | ||
327 | |||
328 | return(ret); | ||
329 | } | ||
330 | |||
331 | static char * | ||
332 | make_absolute(char *p, char *pwd) | 326 | make_absolute(char *p, char *pwd) |
333 | { | 327 | { |
334 | char *abs_str; | 328 | char *abs_str; |
@@ -343,27 +337,8 @@ make_absolute(char *p, char *pwd) | |||
343 | } | 337 | } |
344 | 338 | ||
345 | static int | 339 | static int |
346 | infer_path(const char *p, char **ifp) | 340 | parse_getput_flags(const char *cmd, char **argv, int argc, int *pflag, |
347 | { | 341 | int *rflag) |
348 | char *cp; | ||
349 | |||
350 | cp = strrchr(p, '/'); | ||
351 | if (cp == NULL) { | ||
352 | *ifp = xstrdup(p); | ||
353 | return(0); | ||
354 | } | ||
355 | |||
356 | if (!cp[1]) { | ||
357 | error("Invalid path"); | ||
358 | return(-1); | ||
359 | } | ||
360 | |||
361 | *ifp = xstrdup(cp + 1); | ||
362 | return(0); | ||
363 | } | ||
364 | |||
365 | static int | ||
366 | parse_getput_flags(const char *cmd, char **argv, int argc, int *pflag) | ||
367 | { | 342 | { |
368 | extern int opterr, optind, optopt, optreset; | 343 | extern int opterr, optind, optopt, optreset; |
369 | int ch; | 344 | int ch; |
@@ -371,13 +346,17 @@ parse_getput_flags(const char *cmd, char **argv, int argc, int *pflag) | |||
371 | optind = optreset = 1; | 346 | optind = optreset = 1; |
372 | opterr = 0; | 347 | opterr = 0; |
373 | 348 | ||
374 | *pflag = 0; | 349 | *rflag = *pflag = 0; |
375 | while ((ch = getopt(argc, argv, "Pp")) != -1) { | 350 | while ((ch = getopt(argc, argv, "PpRr")) != -1) { |
376 | switch (ch) { | 351 | switch (ch) { |
377 | case 'p': | 352 | case 'p': |
378 | case 'P': | 353 | case 'P': |
379 | *pflag = 1; | 354 | *pflag = 1; |
380 | break; | 355 | break; |
356 | case 'r': | ||
357 | case 'R': | ||
358 | *rflag = 1; | ||
359 | break; | ||
381 | default: | 360 | default: |
382 | error("%s: Invalid flag -%c", cmd, optopt); | 361 | error("%s: Invalid flag -%c", cmd, optopt); |
383 | return -1; | 362 | return -1; |
@@ -489,62 +468,79 @@ remote_is_dir(struct sftp_conn *conn, char *path) | |||
489 | return(S_ISDIR(a->perm)); | 468 | return(S_ISDIR(a->perm)); |
490 | } | 469 | } |
491 | 470 | ||
471 | /* Check whether path returned from glob(..., GLOB_MARK, ...) is a directory */ | ||
472 | static int | ||
473 | pathname_is_dir(char *pathname) | ||
474 | { | ||
475 | size_t l = strlen(pathname); | ||
476 | |||
477 | return l > 0 && pathname[l - 1] == '/'; | ||
478 | } | ||
479 | |||
492 | static int | 480 | static int |
493 | process_get(struct sftp_conn *conn, char *src, char *dst, char *pwd, int pflag) | 481 | process_get(struct sftp_conn *conn, char *src, char *dst, char *pwd, |
482 | int pflag, int rflag) | ||
494 | { | 483 | { |
495 | char *abs_src = NULL; | 484 | char *abs_src = NULL; |
496 | char *abs_dst = NULL; | 485 | char *abs_dst = NULL; |
497 | char *tmp; | ||
498 | glob_t g; | 486 | glob_t g; |
499 | int err = 0; | 487 | char *filename, *tmp=NULL; |
500 | int i; | 488 | int i, err = 0; |
501 | 489 | ||
502 | abs_src = xstrdup(src); | 490 | abs_src = xstrdup(src); |
503 | abs_src = make_absolute(abs_src, pwd); | 491 | abs_src = make_absolute(abs_src, pwd); |
504 | |||
505 | memset(&g, 0, sizeof(g)); | 492 | memset(&g, 0, sizeof(g)); |
493 | |||
506 | debug3("Looking up %s", abs_src); | 494 | debug3("Looking up %s", abs_src); |
507 | if (remote_glob(conn, abs_src, 0, NULL, &g)) { | 495 | if (remote_glob(conn, abs_src, GLOB_MARK, NULL, &g)) { |
508 | error("File \"%s\" not found.", abs_src); | 496 | error("File \"%s\" not found.", abs_src); |
509 | err = -1; | 497 | err = -1; |
510 | goto out; | 498 | goto out; |
511 | } | 499 | } |
512 | 500 | ||
513 | /* If multiple matches, dst must be a directory or unspecified */ | 501 | /* |
514 | if (g.gl_matchc > 1 && dst && !is_dir(dst)) { | 502 | * If multiple matches then dst must be a directory or |
515 | error("Multiple files match, but \"%s\" is not a directory", | 503 | * unspecified. |
516 | dst); | 504 | */ |
505 | if (g.gl_matchc > 1 && dst != NULL && !is_dir(dst)) { | ||
506 | error("Multiple source paths, but destination " | ||
507 | "\"%s\" is not a directory", dst); | ||
517 | err = -1; | 508 | err = -1; |
518 | goto out; | 509 | goto out; |
519 | } | 510 | } |
520 | 511 | ||
521 | for (i = 0; g.gl_pathv[i] && !interrupted; i++) { | 512 | for (i = 0; g.gl_pathv[i] && !interrupted; i++) { |
522 | if (infer_path(g.gl_pathv[i], &tmp)) { | 513 | tmp = xstrdup(g.gl_pathv[i]); |
514 | if ((filename = basename(tmp)) == NULL) { | ||
515 | error("basename %s: %s", tmp, strerror(errno)); | ||
516 | xfree(tmp); | ||
523 | err = -1; | 517 | err = -1; |
524 | goto out; | 518 | goto out; |
525 | } | 519 | } |
526 | 520 | ||
527 | if (g.gl_matchc == 1 && dst) { | 521 | if (g.gl_matchc == 1 && dst) { |
528 | /* If directory specified, append filename */ | ||
529 | xfree(tmp); | ||
530 | if (is_dir(dst)) { | 522 | if (is_dir(dst)) { |
531 | if (infer_path(g.gl_pathv[0], &tmp)) { | 523 | abs_dst = path_append(dst, filename); |
532 | err = 1; | 524 | } else { |
533 | goto out; | ||
534 | } | ||
535 | abs_dst = path_append(dst, tmp); | ||
536 | xfree(tmp); | ||
537 | } else | ||
538 | abs_dst = xstrdup(dst); | 525 | abs_dst = xstrdup(dst); |
526 | } | ||
539 | } else if (dst) { | 527 | } else if (dst) { |
540 | abs_dst = path_append(dst, tmp); | 528 | abs_dst = path_append(dst, filename); |
541 | xfree(tmp); | 529 | } else { |
542 | } else | 530 | abs_dst = xstrdup(filename); |
543 | abs_dst = tmp; | 531 | } |
532 | xfree(tmp); | ||
544 | 533 | ||
545 | printf("Fetching %s to %s\n", g.gl_pathv[i], abs_dst); | 534 | printf("Fetching %s to %s\n", g.gl_pathv[i], abs_dst); |
546 | if (do_download(conn, g.gl_pathv[i], abs_dst, pflag) == -1) | 535 | if (pathname_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) { |
547 | err = -1; | 536 | if (download_dir(conn, g.gl_pathv[i], abs_dst, NULL, |
537 | pflag || global_pflag, 1) == -1) | ||
538 | err = -1; | ||
539 | } else { | ||
540 | if (do_download(conn, g.gl_pathv[i], abs_dst, NULL, | ||
541 | pflag || global_pflag) == -1) | ||
542 | err = -1; | ||
543 | } | ||
548 | xfree(abs_dst); | 544 | xfree(abs_dst); |
549 | abs_dst = NULL; | 545 | abs_dst = NULL; |
550 | } | 546 | } |
@@ -556,14 +552,15 @@ out: | |||
556 | } | 552 | } |
557 | 553 | ||
558 | static int | 554 | static int |
559 | process_put(struct sftp_conn *conn, char *src, char *dst, char *pwd, int pflag) | 555 | process_put(struct sftp_conn *conn, char *src, char *dst, char *pwd, |
556 | int pflag, int rflag) | ||
560 | { | 557 | { |
561 | char *tmp_dst = NULL; | 558 | char *tmp_dst = NULL; |
562 | char *abs_dst = NULL; | 559 | char *abs_dst = NULL; |
563 | char *tmp; | 560 | char *tmp = NULL, *filename = NULL; |
564 | glob_t g; | 561 | glob_t g; |
565 | int err = 0; | 562 | int err = 0; |
566 | int i; | 563 | int i, dst_is_dir = 1; |
567 | struct stat sb; | 564 | struct stat sb; |
568 | 565 | ||
569 | if (dst) { | 566 | if (dst) { |
@@ -573,16 +570,20 @@ process_put(struct sftp_conn *conn, char *src, char *dst, char *pwd, int pflag) | |||
573 | 570 | ||
574 | memset(&g, 0, sizeof(g)); | 571 | memset(&g, 0, sizeof(g)); |
575 | debug3("Looking up %s", src); | 572 | debug3("Looking up %s", src); |
576 | if (glob(src, GLOB_NOCHECK, NULL, &g)) { | 573 | if (glob(src, GLOB_NOCHECK | GLOB_MARK, NULL, &g)) { |
577 | error("File \"%s\" not found.", src); | 574 | error("File \"%s\" not found.", src); |
578 | err = -1; | 575 | err = -1; |
579 | goto out; | 576 | goto out; |
580 | } | 577 | } |
581 | 578 | ||
579 | /* If we aren't fetching to pwd then stash this status for later */ | ||
580 | if (tmp_dst != NULL) | ||
581 | dst_is_dir = remote_is_dir(conn, tmp_dst); | ||
582 | |||
582 | /* If multiple matches, dst may be directory or unspecified */ | 583 | /* If multiple matches, dst may be directory or unspecified */ |
583 | if (g.gl_matchc > 1 && tmp_dst && !remote_is_dir(conn, tmp_dst)) { | 584 | if (g.gl_matchc > 1 && tmp_dst && !dst_is_dir) { |
584 | error("Multiple files match, but \"%s\" is not a directory", | 585 | error("Multiple paths match, but destination " |
585 | tmp_dst); | 586 | "\"%s\" is not a directory", tmp_dst); |
586 | err = -1; | 587 | err = -1; |
587 | goto out; | 588 | goto out; |
588 | } | 589 | } |
@@ -593,38 +594,38 @@ process_put(struct sftp_conn *conn, char *src, char *dst, char *pwd, int pflag) | |||
593 | error("stat %s: %s", g.gl_pathv[i], strerror(errno)); | 594 | error("stat %s: %s", g.gl_pathv[i], strerror(errno)); |
594 | continue; | 595 | continue; |
595 | } | 596 | } |
596 | 597 | ||
597 | if (!S_ISREG(sb.st_mode)) { | 598 | tmp = xstrdup(g.gl_pathv[i]); |
598 | error("skipping non-regular file %s", | 599 | if ((filename = basename(tmp)) == NULL) { |
599 | g.gl_pathv[i]); | 600 | error("basename %s: %s", tmp, strerror(errno)); |
600 | continue; | 601 | xfree(tmp); |
601 | } | ||
602 | if (infer_path(g.gl_pathv[i], &tmp)) { | ||
603 | err = -1; | 602 | err = -1; |
604 | goto out; | 603 | goto out; |
605 | } | 604 | } |
606 | 605 | ||
607 | if (g.gl_matchc == 1 && tmp_dst) { | 606 | if (g.gl_matchc == 1 && tmp_dst) { |
608 | /* If directory specified, append filename */ | 607 | /* If directory specified, append filename */ |
609 | if (remote_is_dir(conn, tmp_dst)) { | 608 | if (dst_is_dir) |
610 | if (infer_path(g.gl_pathv[0], &tmp)) { | 609 | abs_dst = path_append(tmp_dst, filename); |
611 | err = 1; | 610 | else |
612 | goto out; | ||
613 | } | ||
614 | abs_dst = path_append(tmp_dst, tmp); | ||
615 | xfree(tmp); | ||
616 | } else | ||
617 | abs_dst = xstrdup(tmp_dst); | 611 | abs_dst = xstrdup(tmp_dst); |
618 | |||
619 | } else if (tmp_dst) { | 612 | } else if (tmp_dst) { |
620 | abs_dst = path_append(tmp_dst, tmp); | 613 | abs_dst = path_append(tmp_dst, filename); |
621 | xfree(tmp); | 614 | } else { |
622 | } else | 615 | abs_dst = make_absolute(xstrdup(filename), pwd); |
623 | abs_dst = make_absolute(tmp, pwd); | 616 | } |
617 | xfree(tmp); | ||
624 | 618 | ||
625 | printf("Uploading %s to %s\n", g.gl_pathv[i], abs_dst); | 619 | printf("Uploading %s to %s\n", g.gl_pathv[i], abs_dst); |
626 | if (do_upload(conn, g.gl_pathv[i], abs_dst, pflag) == -1) | 620 | if (pathname_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) { |
627 | err = -1; | 621 | if (upload_dir(conn, g.gl_pathv[i], abs_dst, |
622 | pflag || global_pflag, 1) == -1) | ||
623 | err = -1; | ||
624 | } else { | ||
625 | if (do_upload(conn, g.gl_pathv[i], abs_dst, | ||
626 | pflag || global_pflag) == -1) | ||
627 | err = -1; | ||
628 | } | ||
628 | } | 629 | } |
629 | 630 | ||
630 | out: | 631 | out: |
@@ -1065,7 +1066,7 @@ makeargv(const char *arg, int *argcp) | |||
1065 | } | 1066 | } |
1066 | 1067 | ||
1067 | static int | 1068 | static int |
1068 | parse_args(const char **cpp, int *pflag, int *lflag, int *iflag, int *hflag, | 1069 | parse_args(const char **cpp, int *pflag, int *rflag, int *lflag, int *iflag, int *hflag, |
1069 | unsigned long *n_arg, char **path1, char **path2) | 1070 | unsigned long *n_arg, char **path1, char **path2) |
1070 | { | 1071 | { |
1071 | const char *cmd, *cp = *cpp; | 1072 | const char *cmd, *cp = *cpp; |
@@ -1109,13 +1110,13 @@ parse_args(const char **cpp, int *pflag, int *lflag, int *iflag, int *hflag, | |||
1109 | } | 1110 | } |
1110 | 1111 | ||
1111 | /* Get arguments and parse flags */ | 1112 | /* Get arguments and parse flags */ |
1112 | *lflag = *pflag = *hflag = *n_arg = 0; | 1113 | *lflag = *pflag = *rflag = *hflag = *n_arg = 0; |
1113 | *path1 = *path2 = NULL; | 1114 | *path1 = *path2 = NULL; |
1114 | optidx = 1; | 1115 | optidx = 1; |
1115 | switch (cmdnum) { | 1116 | switch (cmdnum) { |
1116 | case I_GET: | 1117 | case I_GET: |
1117 | case I_PUT: | 1118 | case I_PUT: |
1118 | if ((optidx = parse_getput_flags(cmd, argv, argc, pflag)) == -1) | 1119 | if ((optidx = parse_getput_flags(cmd, argv, argc, pflag, rflag)) == -1) |
1119 | return -1; | 1120 | return -1; |
1120 | /* Get first pathname (mandatory) */ | 1121 | /* Get first pathname (mandatory) */ |
1121 | if (argc - optidx < 1) { | 1122 | if (argc - optidx < 1) { |
@@ -1235,7 +1236,7 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd, | |||
1235 | int err_abort) | 1236 | int err_abort) |
1236 | { | 1237 | { |
1237 | char *path1, *path2, *tmp; | 1238 | char *path1, *path2, *tmp; |
1238 | int pflag = 0, lflag = 0, iflag = 0, hflag = 0, cmdnum, i; | 1239 | int pflag = 0, rflag = 0, lflag = 0, iflag = 0, hflag = 0, cmdnum, i; |
1239 | unsigned long n_arg = 0; | 1240 | unsigned long n_arg = 0; |
1240 | Attrib a, *aa; | 1241 | Attrib a, *aa; |
1241 | char path_buf[MAXPATHLEN]; | 1242 | char path_buf[MAXPATHLEN]; |
@@ -1243,7 +1244,7 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd, | |||
1243 | glob_t g; | 1244 | glob_t g; |
1244 | 1245 | ||
1245 | path1 = path2 = NULL; | 1246 | path1 = path2 = NULL; |
1246 | cmdnum = parse_args(&cmd, &pflag, &lflag, &iflag, &hflag, &n_arg, | 1247 | cmdnum = parse_args(&cmd, &pflag, &rflag, &lflag, &iflag, &hflag, &n_arg, |
1247 | &path1, &path2); | 1248 | &path1, &path2); |
1248 | 1249 | ||
1249 | if (iflag != 0) | 1250 | if (iflag != 0) |
@@ -1261,10 +1262,10 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd, | |||
1261 | err = -1; | 1262 | err = -1; |
1262 | break; | 1263 | break; |
1263 | case I_GET: | 1264 | case I_GET: |
1264 | err = process_get(conn, path1, path2, *pwd, pflag); | 1265 | err = process_get(conn, path1, path2, *pwd, pflag, rflag); |
1265 | break; | 1266 | break; |
1266 | case I_PUT: | 1267 | case I_PUT: |
1267 | err = process_put(conn, path1, path2, *pwd, pflag); | 1268 | err = process_put(conn, path1, path2, *pwd, pflag, rflag); |
1268 | break; | 1269 | break; |
1269 | case I_RENAME: | 1270 | case I_RENAME: |
1270 | path1 = make_absolute(path1, *pwd); | 1271 | path1 = make_absolute(path1, *pwd); |
@@ -1290,7 +1291,7 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd, | |||
1290 | attrib_clear(&a); | 1291 | attrib_clear(&a); |
1291 | a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS; | 1292 | a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS; |
1292 | a.perm = 0777; | 1293 | a.perm = 0777; |
1293 | err = do_mkdir(conn, path1, &a); | 1294 | err = do_mkdir(conn, path1, &a, 1); |
1294 | break; | 1295 | break; |
1295 | case I_RMDIR: | 1296 | case I_RMDIR: |
1296 | path1 = make_absolute(path1, *pwd); | 1297 | path1 = make_absolute(path1, *pwd); |
@@ -1668,7 +1669,7 @@ usage(void) | |||
1668 | extern char *__progname; | 1669 | extern char *__progname; |
1669 | 1670 | ||
1670 | fprintf(stderr, | 1671 | fprintf(stderr, |
1671 | "usage: %s [-1246Cqv] [-B buffer_size] [-b batchfile] [-c cipher]\n" | 1672 | "usage: %s [-1246Cpqrv] [-B buffer_size] [-b batchfile] [-c cipher]\n" |
1672 | " [-D sftp_server_path] [-F ssh_config] " | 1673 | " [-D sftp_server_path] [-F ssh_config] " |
1673 | "[-i identity_file]\n" | 1674 | "[-i identity_file]\n" |
1674 | " [-o ssh_option] [-P port] [-R num_requests] " | 1675 | " [-o ssh_option] [-P port] [-R num_requests] " |
@@ -1710,7 +1711,7 @@ main(int argc, char **argv) | |||
1710 | infile = stdin; | 1711 | infile = stdin; |
1711 | 1712 | ||
1712 | while ((ch = getopt(argc, argv, | 1713 | while ((ch = getopt(argc, argv, |
1713 | "1246hqvCc:D:i:o:s:S:b:B:F:P:R:")) != -1) { | 1714 | "1246hqrvCc:D:i:o:s:S:b:B:F:P:R:")) != -1) { |
1714 | switch (ch) { | 1715 | switch (ch) { |
1715 | /* Passed through to ssh(1) */ | 1716 | /* Passed through to ssh(1) */ |
1716 | case '4': | 1717 | case '4': |
@@ -1764,9 +1765,15 @@ main(int argc, char **argv) | |||
1764 | batchmode = 1; | 1765 | batchmode = 1; |
1765 | addargs(&args, "-obatchmode yes"); | 1766 | addargs(&args, "-obatchmode yes"); |
1766 | break; | 1767 | break; |
1768 | case 'p': | ||
1769 | global_pflag = 1; | ||
1770 | break; | ||
1767 | case 'D': | 1771 | case 'D': |
1768 | sftp_direct = optarg; | 1772 | sftp_direct = optarg; |
1769 | break; | 1773 | break; |
1774 | case 'r': | ||
1775 | global_rflag = 1; | ||
1776 | break; | ||
1770 | case 'R': | 1777 | case 'R': |
1771 | num_requests = strtol(optarg, &cp, 10); | 1778 | num_requests = strtol(optarg, &cp, 10); |
1772 | if (num_requests == 0 || *cp != '\0') | 1779 | if (num_requests == 0 || *cp != '\0') |