diff --git a/mux/src/ssh.rs b/mux/src/ssh.rs index 39de5b2b3..b4b2b5658 100644 --- a/mux/src/ssh.rs +++ b/mux/src/ssh.rs @@ -226,27 +226,45 @@ impl RemoteSshDomain { cmd: &CommandBuilder, env: &HashMap, ) -> anyhow::Result { - let mut env_cmd = vec!["env".to_string()]; - if let Some(dir) = dir { - env_cmd.push("-C".to_string()); - env_cmd.push(dir.clone()); + // "Soft" chdir: if it doesn't exist then it doesn't matter + let cd_cmd = if let Some(dir) = dir { + format!("cd {};", shell_words::quote(&dir)) } else if let Some(dir) = cmd.get_cwd() { let dir = dir.to_str().context("converting cwd to string")?; - env_cmd.push("-C".to_string()); - env_cmd.push(dir.to_string()); - } + format!("cd {};", shell_words::quote(&dir)) + } else { + String::new() + }; + + let mut env_cmd = vec!["env".to_string()]; for (k, v) in env { env_cmd.push(format!("{}={}", k, v)); } let cmd = if cmd.is_default_prog() { - "$SHELL".to_string() + // We'd like to spawn a login shell, but since we are invoking env + // we end up in a regular shell. + // This guff tries to find a reasonably portable way to execute + // the shell as a login shell. + // Per: + // the most portable way is to use perl, but in case perl is not + // installed, zsh, bash and ksh all support `exec -a`. + // Other shells may support `exec -a` but there isn't a simple + // way to test for them, so we assume that if we have one of those + // three that we can use it, otherwise we fall back to just running + // the shell directly. + let login_shell = "command -v perl > /dev/null && \ + exec perl -e 'use File::Basename; $shell = basename($ENV{SHELL}); exec {$ENV{SHELL}} \"-$shell\"'; \ + case \"$SHELL\" in */zsh|*/bash|*/ksh ) exec -a \"-$(basename $SHELL)\" $SHELL ;; esac ; \ + exec $SHELL"; + + format!("$SHELL -c {}", shell_words::quote(login_shell)) } else { cmd.as_unix_command_line()? }; - Ok(shell_words::join(env_cmd) + " " + &cmd) + Ok(cd_cmd + &shell_words::join(env_cmd) + " " + &cmd) } let command_line = match (cmd.is_default_prog(), self.dom.assume_shell, command_dir) {