It seems that currently scp just silently ignores command-line options that it does not understand. That is surprising and possibly dangerous or damageable (since once will expect the option to have been taken into account). It seems pretty standard for a tool to fail on unknown options, but since that might break existing scripts, maybe starting with reporting a warning would be the best compromise.
To clarify, this is the case with long options (starting with --...). Example: touch a; scp --foobarbaz a b does not report any error or warning.
scp does report unknown options: $ scp -X a: b: scp: illegal option -- X usage: scp [-12346BCpqrv] [-c cipher] [-F ssh_config] [-i identity_file] [-l limit] [-o ssh_option] [-P port] [-S program] [[user@]host1:]file1 ... [[user@]host2:]file2 It also reports --options options on OpenBSD: $ scp --blah a: b: scp: illegal option -- - usage: scp [-12346BCpqrv] [-c cipher] [-F ssh_config] [-i identity_file] [-l limit] [-o ssh_option] [-P port] [-S program] [[user@]host1:]file1 ... [[user@]host2:]file2 I think what is happening that GNU getopt is swallowing the long options before scp sees them. There isn't much scp could do here except perhaps avoid the system getopt() for its own and I don't think this is worth it.
I don't know scp interracts with getopt. But it seems to me that either getopt offers a way to know that that long option was given, and scp could fail/warn if it does not know the option. Or getopt does not allow that, and a bug report/feature request is in order.
whatever it is, it doesn't seem to be gnu-getopt specific. or if it is, it's not enabled with the default set of defines. #include <stdio.h> #include <unistd.h> int main(int argc, char **argv) { int ch; while ((ch = getopt(argc, argv, "abc:")) != -1) { printf("opt %c optarg %s\n", ch, optarg ? optarg : "(null)"); } } gives me: $ ./a.out --foo ./a.out: invalid option -- '-' opt ? optarg (null) ./a.out: invalid option -- 'f' opt ? optarg (null) ./a.out: invalid option -- 'o' opt ? optarg (null) ./a.out: invalid option -- 'o' opt ? optarg (null) whatever it is, I think it's in our compat library: $ nm scp | grep -i getop 08051710 T BSDgetopt
sure looks like something of ours: $ gcc getopt-test.c -Dgetopt=BSDgetopt openbsd-compat/libopenbsd-compat.a $ ./a.out -a opt a optarg (null) $ ./a.out --foo $
ok, so it turns out the original upstream source in OpenBSD's getopt.c had the same behaviour, but was replaced in 2004 with getopt_long.c which doesn't. For long-term maintainability I think we should switch. What I'm going to do is 1) factor out the portability changes in getopt.c 2) add getopt_long.c to openssh and remove getopt.c 3) pull the portability changes into getopt_long.c
Created attachment 2257 [details] Factor out portability changes in getopt.c
Created attachment 2258 [details] import getopt_long.c from openbsd
Created attachment 2259 [details] apply portability changes to getopt_long.c switch over to it and remove getopt.c
With these changes I get the following for your testcase: $ touch a; ./scp --foobarbaz a b unknown option -- - usage: scp [-12346BCpqrv] [-c cipher] [-F ssh_config] [-i identity_file] [-l limit] [-o ssh_option] [-P port] [-S program] [[user@]host1:]file1 ... [[user@]host2:]file2 Thanks for the report (and patience :-). These changes will be in the 6.3p1 release.
Thank you for the fix :) Any chance the portability fixes could be applied upstream?
It's already as upstream as it gets. The file with the bug in openbsd is dead, and the current version of the current file is fine.
Set all RESOLVED bugs to CLOSED with release of OpenSSH 7.1