unpack-trees: oneway_merge to update submodules
[gitweb.git] / connect.c
index f3370510a6dbb63049d3f6171d7c534ac366777e..c3a014c5babf72ee4c0d135fec264afb37b040de 100644 (file)
--- a/connect.c
+++ b/connect.c
@@ -788,6 +788,7 @@ static const char *get_ssh_command(void)
 }
 
 enum ssh_variant {
+       VARIANT_AUTO,
        VARIANT_SIMPLE,
        VARIANT_SSH,
        VARIANT_PLINK,
@@ -795,14 +796,16 @@ enum ssh_variant {
        VARIANT_TORTOISEPLINK,
 };
 
-static int override_ssh_variant(enum ssh_variant *ssh_variant)
+static void override_ssh_variant(enum ssh_variant *ssh_variant)
 {
        const char *variant = getenv("GIT_SSH_VARIANT");
 
        if (!variant && git_config_get_string_const("ssh.variant", &variant))
-               return 0;
+               return;
 
-       if (!strcmp(variant, "plink"))
+       if (!strcmp(variant, "auto"))
+               *ssh_variant = VARIANT_AUTO;
+       else if (!strcmp(variant, "plink"))
                *ssh_variant = VARIANT_PLINK;
        else if (!strcmp(variant, "putty"))
                *ssh_variant = VARIANT_PUTTY;
@@ -812,18 +815,18 @@ static int override_ssh_variant(enum ssh_variant *ssh_variant)
                *ssh_variant = VARIANT_SIMPLE;
        else
                *ssh_variant = VARIANT_SSH;
-
-       return 1;
 }
 
 static enum ssh_variant determine_ssh_variant(const char *ssh_command,
                                              int is_cmdline)
 {
-       enum ssh_variant ssh_variant = VARIANT_SIMPLE;
+       enum ssh_variant ssh_variant = VARIANT_AUTO;
        const char *variant;
        char *p = NULL;
 
-       if (override_ssh_variant(&ssh_variant))
+       override_ssh_variant(&ssh_variant);
+
+       if (ssh_variant != VARIANT_AUTO)
                return ssh_variant;
 
        if (!is_cmdline) {
@@ -886,7 +889,8 @@ static struct child_process *git_connect_git(int fd[2], char *hostandport,
 
        transport_check_allowed("git");
 
-       /* These underlying connection commands die() if they
+       /*
+        * These underlying connection commands die() if they
         * cannot connect.
         */
        if (git_use_proxy(hostandport))
@@ -935,21 +939,49 @@ static void push_ssh_options(struct argv_array *args, struct argv_array *env,
                                 get_protocol_version_config());
        }
 
-       if (variant != VARIANT_SIMPLE) {
-               if (flags & CONNECT_IPV4)
+       if (flags & CONNECT_IPV4) {
+               switch (variant) {
+               case VARIANT_AUTO:
+                       BUG("VARIANT_AUTO passed to push_ssh_options");
+               case VARIANT_SIMPLE:
+                       die("ssh variant 'simple' does not support -4");
+               case VARIANT_SSH:
+               case VARIANT_PLINK:
+               case VARIANT_PUTTY:
+               case VARIANT_TORTOISEPLINK:
                        argv_array_push(args, "-4");
-               else if (flags & CONNECT_IPV6)
+               }
+       } else if (flags & CONNECT_IPV6) {
+               switch (variant) {
+               case VARIANT_AUTO:
+                       BUG("VARIANT_AUTO passed to push_ssh_options");
+               case VARIANT_SIMPLE:
+                       die("ssh variant 'simple' does not support -6");
+               case VARIANT_SSH:
+               case VARIANT_PLINK:
+               case VARIANT_PUTTY:
+               case VARIANT_TORTOISEPLINK:
                        argv_array_push(args, "-6");
+               }
        }
 
        if (variant == VARIANT_TORTOISEPLINK)
                argv_array_push(args, "-batch");
 
-       if (port && variant != VARIANT_SIMPLE) {
-               if (variant == VARIANT_SSH)
+       if (port) {
+               switch (variant) {
+               case VARIANT_AUTO:
+                       BUG("VARIANT_AUTO passed to push_ssh_options");
+               case VARIANT_SIMPLE:
+                       die("ssh variant 'simple' does not support setting port");
+               case VARIANT_SSH:
                        argv_array_push(args, "-p");
-               else
+                       break;
+               case VARIANT_PLINK:
+               case VARIANT_PUTTY:
+               case VARIANT_TORTOISEPLINK:
                        argv_array_push(args, "-P");
+               }
 
                argv_array_push(args, port);
        }
@@ -982,6 +1014,21 @@ static void fill_ssh_args(struct child_process *conn, const char *ssh_host,
                variant = determine_ssh_variant(ssh, 0);
        }
 
+       if (variant == VARIANT_AUTO) {
+               struct child_process detect = CHILD_PROCESS_INIT;
+
+               detect.use_shell = conn->use_shell;
+               detect.no_stdin = detect.no_stdout = detect.no_stderr = 1;
+
+               argv_array_push(&detect.args, ssh);
+               argv_array_push(&detect.args, "-G");
+               push_ssh_options(&detect.args, &detect.env_array,
+                                VARIANT_SSH, port, flags);
+               argv_array_push(&detect.args, ssh_host);
+
+               variant = run_command(&detect) ? VARIANT_SIMPLE : VARIANT_SSH;
+       }
+
        argv_array_push(&conn->args, ssh);
        push_ssh_options(&conn->args, &conn->env_array, variant, port, flags);
        argv_array_push(&conn->args, ssh_host);