}
enum ssh_variant {
+ VARIANT_AUTO,
VARIANT_SIMPLE,
VARIANT_SSH,
VARIANT_PLINK,
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;
*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) {
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))
return conn;
}
+/*
+ * Append the appropriate environment variables to `env` and options to
+ * `args` for running ssh in Git's SSH-tunneled transport.
+ */
+static void push_ssh_options(struct argv_array *args, struct argv_array *env,
+ enum ssh_variant variant, const char *port,
+ int flags)
+{
+ if (variant == VARIANT_SSH &&
+ get_protocol_version_config() > 0) {
+ argv_array_push(args, "-o");
+ argv_array_push(args, "SendEnv=" GIT_PROTOCOL_ENVIRONMENT);
+ argv_array_pushf(env, GIT_PROTOCOL_ENVIRONMENT "=version=%d",
+ get_protocol_version_config());
+ }
+
+ 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) {
+ 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) {
+ 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");
+ break;
+ case VARIANT_PLINK:
+ case VARIANT_PUTTY:
+ case VARIANT_TORTOISEPLINK:
+ argv_array_push(args, "-P");
+ }
+
+ argv_array_push(args, port);
+ }
+}
+
/* Prepare a child_process for use by Git's SSH-tunneled transport. */
static void fill_ssh_args(struct child_process *conn, const char *ssh_host,
const char *port, int flags)
variant = determine_ssh_variant(ssh, 0);
}
- argv_array_push(&conn->args, ssh);
+ if (variant == VARIANT_AUTO) {
+ struct child_process detect = CHILD_PROCESS_INIT;
- if (variant == VARIANT_SSH &&
- get_protocol_version_config() > 0) {
- argv_array_push(&conn->args, "-o");
- argv_array_push(&conn->args, "SendEnv=" GIT_PROTOCOL_ENVIRONMENT);
- argv_array_pushf(&conn->env_array, GIT_PROTOCOL_ENVIRONMENT "=version=%d",
- get_protocol_version_config());
- }
-
- if (variant != VARIANT_SIMPLE) {
- if (flags & CONNECT_IPV4)
- argv_array_push(&conn->args, "-4");
- else if (flags & CONNECT_IPV6)
- argv_array_push(&conn->args, "-6");
- }
-
- if (variant == VARIANT_TORTOISEPLINK)
- argv_array_push(&conn->args, "-batch");
+ detect.use_shell = conn->use_shell;
+ detect.no_stdin = detect.no_stdout = detect.no_stderr = 1;
- if (port && variant != VARIANT_SIMPLE) {
- if (variant == VARIANT_SSH)
- argv_array_push(&conn->args, "-p");
- else
- argv_array_push(&conn->args, "-P");
+ 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);
- argv_array_push(&conn->args, port);
+ 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);
}