Passing SFTP options when using SCP
Damien Miller
djm at mindrot.org
Thu Dec 8 15:03:25 AEDT 2022
On Wed, 7 Dec 2022, Darren Tucker wrote:
> On Wed, 7 Dec 2022 at 14:23, Damien Miller <djm at mindrot.org> wrote:
> [...]
> > There are no options to do this ATM and at least one of the option
> > letters that sftp uses already has meaning for sftp. These are
> > rarely used, so maybe it makes sent to put them behind a single
> > getopt chat that accepts multiple arguments.
>
> Similar to ssh-keygen's -M, I like it. Since you picked a letter not
> in use by sftp either, you could also put it in sftp and provide a
> consistent interface in both.
Here's a fleshed out version of the previous diff, including the same
option for sftp and manpage bits.
diff --git a/scp.1 b/scp.1
index cd23f97..a98df59 100644
--- a/scp.1
+++ b/scp.1
@@ -28,6 +28,7 @@
.Op Fl o Ar ssh_option
.Op Fl P Ar port
.Op Fl S Ar program
+.Op Fl X Ar sftp_option
.Ar source ... target
.Sh DESCRIPTION
.Nm
@@ -278,6 +279,19 @@ and
to print debugging messages about their progress.
This is helpful in
debugging connection, authentication, and configuration problems.
+.It Fl X Ar sftp_option
+Specify an option that controls aspects of SFTP protocol behaviour.
+The valid options are:
+.Bl -tag -width Ds
+.It Cm nrequests Ns = Ns Ar value
+Controls how many concurrent SFTP read or write requests may be in progress
+at any point in time during a download or upload.
+By default 64 requests may be active concurrently.
+.It Cm buffer Ns = Ns Ar value
+Controls the maximum buffer size for a single SFTP read/write operation used
+during download or upload.
+By default a 32KB buffer is used.
+.El
.El
.Sh EXIT STATUS
.Ex -std scp
diff --git a/scp.c b/scp.c
index c7194c2..d401718 100644
--- a/scp.c
+++ b/scp.c
@@ -150,6 +150,10 @@ char *ssh_program = _PATH_SSH_PROGRAM;
pid_t do_cmd_pid = -1;
pid_t do_cmd_pid2 = -1;
+/* SFTP copy parameters */
+size_t sftp_copy_buflen;
+size_t sftp_nrequests;
+
/* Needed for sftp */
volatile sig_atomic_t interrupted = 0;
@@ -419,7 +423,7 @@ int
main(int argc, char **argv)
{
int ch, fflag, tflag, status, n;
- char **newargv, *argv0;
+ char **newargv, *argv0, *cp;
const char *errstr;
extern char *optarg;
extern int optind;
@@ -452,7 +456,7 @@ main(int argc, char **argv)
fflag = Tflag = tflag = 0;
while ((ch = getopt(argc, argv,
- "12346ABCTdfOpqRrstvD:F:J:M:P:S:c:i:l:o:")) != -1) {
+ "12346ABCTdfOpqRrstvD:F:J:M:P:S:c:i:l:o:X:")) != -1) {
switch (ch) {
/* User-visible flags. */
case '1':
@@ -533,6 +537,24 @@ main(int argc, char **argv)
addargs(&remote_remote_args, "-q");
showprogress = 0;
break;
+ case 'X':
+ /* Please keep in sync with sftp.c -X */
+ if (strncmp(optarg, "buffer=", 7) == 0) {
+ sftp_copy_buflen = strtol(optarg + 7, &cp, 10);
+ if (sftp_copy_buflen == 0 || *cp != '\0') {
+ fatal("Invalid buffer size \"%s\"",
+ optarg + 7);
+ }
+ } else if (strncmp(optarg, "nrequests=", 10) == 0) {
+ sftp_nrequests = strtol(optarg + 10, &cp, 10);
+ if (sftp_nrequests == 0 || *cp != '\0') {
+ fatal("Invalid number of requests "
+ "\"%s\"", optarg + 10);
+ }
+ } else {
+ fatal("Invalid -X option");
+ }
+ break;
/* Server options. */
case 'd':
@@ -941,7 +963,8 @@ do_sftp_connect(char *host, char *user, int port, char *sftp_direct,
reminp, remoutp, pidp) < 0)
return NULL;
}
- return do_init(*reminp, *remoutp, 32768, 64, limit_kbps);
+ return do_init(*reminp, *remoutp,
+ sftp_copy_buflen, sftp_nrequests, limit_kbps);
}
void
diff --git a/sftp-client.c b/sftp-client.c
index a3e7a5d..1907753 100644
--- a/sftp-client.c
+++ b/sftp-client.c
@@ -55,10 +55,10 @@
extern volatile sig_atomic_t interrupted;
extern int showprogress;
-/* Default size of buffer for up/download */
+/* Default size of buffer for up/download (fix sftp.1 scp.1 if changed) */
#define DEFAULT_COPY_BUFLEN 32768
-/* Default number of concurrent outstanding requests */
+/* Default number of concurrent xfer requests (fix sftp.1 scp.1 if changed) */
#define DEFAULT_NUM_REQUESTS 64
/* Minimum amount of data to read at a time */
diff --git a/sftp.1 b/sftp.1
index 3b3f2c5..3b430c5 100644
--- a/sftp.1
+++ b/sftp.1
@@ -44,6 +44,7 @@
.Op Fl R Ar num_requests
.Op Fl S Ar program
.Op Fl s Ar subsystem | sftp_server
+.Op Fl X Ar sftp_option
.Ar destination
.Sh DESCRIPTION
.Nm
@@ -320,6 +321,19 @@ does not have an sftp subsystem configured.
.It Fl v
Raise logging level.
This option is also passed to ssh.
+.It Fl X Ar sftp_option
+Specify an option that controls aspects of SFTP protocol behaviour.
+The valid options are:
+.Bl -tag -width Ds
+.It Cm nrequests Ns = Ns Ar value
+Controls how many concurrent SFTP read or write requests may be in progress
+at any point in time during a download or upload.
+By default 64 requests may be active concurrently.
+.It Cm buffer Ns = Ns Ar value
+Controls the maximum buffer size for a single SFTP read/write operation used
+during download or upload.
+By default a 32KB buffer is used.
+.El
.El
.Sh INTERACTIVE COMMANDS
Once in interactive mode,
diff --git a/sftp.c b/sftp.c
index 02547f6..01999e1 100644
--- a/sftp.c
+++ b/sftp.c
@@ -2497,6 +2497,24 @@ main(int argc, char **argv)
ssh_program = optarg;
replacearg(&args, 0, "%s", ssh_program);
break;
+ case 'X':
+ /* Please keep in sync with ssh.c -X */
+ if (strncmp(optarg, "buffer=", 7) == 0) {
+ copy_buffer_len = strtol(optarg + 7, &cp, 10);
+ if (copy_buffer_len == 0 || *cp != '\0') {
+ fatal("Invalid buffer size \"%s\"",
+ optarg + 7);
+ }
+ } else if (strncmp(optarg, "nrequests=", 10) == 0) {
+ num_requests = strtol(optarg + 10, &cp, 10);
+ if (num_requests == 0 || *cp != '\0') {
+ fatal("Invalid number of requests "
+ "\"%s\"", optarg + 10);
+ }
+ } else {
+ fatal("Invalid -X option");
+ }
+ break;
case 'h':
default:
usage();
More information about the openssh-unix-dev
mailing list