Omar Sandoval
2015-Aug-15 03:35 UTC
[PATCH v2] Add a ssh_config Term option to override TERM
This is useful when a server is missing the necessary terminfo and avoids having to manually set TERM before invoking ssh every time. Signed-off-by: Omar Sandoval <osandov at osandov.com> --- Changes from v1: - Allow ``none'' to force using TERM from the environment I'll elaborate on my use case. I use suckless's st terminal, so I install the st terminfo on the machines I frequent. On other machines, though, I end up having to set TERM to xterm manually on the command line, e.g., TERM=xterm-256color ssh foo Instead, it'd be much more convenient to do the following: Host machine_i_use_alot Term none Host * Term xterm-256color So ssh will default to using xterm-256color, but on hosts that I whitelist, it will use TERM from the environment. mux.c | 2 +- readconf.c | 10 +++++++++- readconf.h | 2 ++ ssh.c | 7 +++++-- ssh_config.5 | 10 ++++++++++ 5 files changed, 27 insertions(+), 4 deletions(-) diff --git a/mux.c b/mux.c index cdc01bd4fff5..1aa21f8eee27 100644 --- a/mux.c +++ b/mux.c @@ -1814,7 +1814,7 @@ mux_client_request_session(int fd) close(devnull); } - term = getenv("TERM"); + term = options.term; buffer_init(&m); buffer_put_int(&m, MUX_C_NEW_SESSION); diff --git a/readconf.c b/readconf.c index 1d03bdf72d92..27169a8e9094 100644 --- a/readconf.c +++ b/readconf.c @@ -148,7 +148,7 @@ typedef enum { oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout, oAddressFamily, oGssAuthentication, oGssDelegateCreds, oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly, - oSendEnv, oControlPath, oControlMaster, oControlPersist, + oSendEnv, oTerm, oControlPath, oControlMaster, oControlPersist, oHashKnownHosts, oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand, oVisualHostKey, oUseRoaming, @@ -251,6 +251,7 @@ static struct { { "serveraliveinterval", oServerAliveInterval }, { "serveralivecountmax", oServerAliveCountMax }, { "sendenv", oSendEnv }, + { "term", oTerm }, { "controlpath", oControlPath }, { "controlmaster", oControlMaster }, { "controlpersist", oControlPersist }, @@ -1294,6 +1295,10 @@ parse_keytypes: } break; + case oTerm: + charptr = &options->term; + goto parse_string; + case oControlPath: charptr = &options->control_path; goto parse_string; @@ -1650,6 +1655,7 @@ initialize_options(Options * options) options->server_alive_interval = -1; options->server_alive_count_max = -1; options->num_send_env = 0; + options->term = NULL; options->control_path = NULL; options->control_master = -1; options->control_persist = -1; @@ -1879,6 +1885,7 @@ fill_default_options(Options * options) /* options->hostname will be set in the main program if appropriate */ /* options->host_key_alias should not be set by default */ /* options->preferred_authentications will be set in ssh */ + /* options->term will be set in ssh */ } struct fwdarg { @@ -2302,6 +2309,7 @@ dump_client_config(Options *o, const char *host) /* String options */ dump_cfg_string(oBindAddress, o->bind_address); dump_cfg_string(oCiphers, o->ciphers ? o->ciphers : KEX_CLIENT_ENCRYPT); + dump_cfg_string(oTerm, o->term); dump_cfg_string(oControlPath, o->control_path); dump_cfg_string(oHostKeyAlgorithms, o->hostkeyalgorithms ? o->hostkeyalgorithms : KEX_DEFAULT_PK_ALG); dump_cfg_string(oHostKeyAlias, o->host_key_alias); diff --git a/readconf.h b/readconf.h index bb2d55283dd0..17e02f24ae4e 100644 --- a/readconf.h +++ b/readconf.h @@ -115,6 +115,8 @@ typedef struct { int num_send_env; char *send_env[MAX_SEND_ENV]; + char *term; + char *control_path; int control_master; int control_persist; /* ControlPersist flag */ diff --git a/ssh.c b/ssh.c index 59c1f931cb0a..db8bfd2d32eb 100644 --- a/ssh.c +++ b/ssh.c @@ -1117,6 +1117,9 @@ main(int ac, char **av) if (options.user == NULL) options.user = xstrdup(pw->pw_name); + if (option_clear_or_none(options.term)) + options.term = getenv("TERM"); + if (gethostname(thishost, sizeof(thishost)) == -1) fatal("gethostname: %s", strerror(errno)); strlcpy(shorthost, thishost, sizeof(shorthost)); @@ -1638,7 +1641,7 @@ ssh_session(void) /* Store TERM in the packet. There is no limit on the length of the string. */ - cp = getenv("TERM"); + cp = options.term; if (!cp) cp = ""; packet_put_cstring(cp); @@ -1804,7 +1807,7 @@ ssh_session2_setup(int id, int success, void *arg) packet_set_interactive(interactive, options.ip_qos_interactive, options.ip_qos_bulk); - client_session2_setup(id, tty_flag, subsystem_flag, getenv("TERM"), + client_session2_setup(id, tty_flag, subsystem_flag, options.term, NULL, fileno(stdin), &command, environ); } diff --git a/ssh_config.5 b/ssh_config.5 index 5b0975f87e2f..b0441f1c4dda 100644 --- a/ssh_config.5 +++ b/ssh_config.5 @@ -1521,6 +1521,16 @@ This is important in scripts, and many users want it too. .Pp To disable TCP keepalive messages, the value should be set to .Dq no . +.It Cm Term +Specifies the +.Ev TERM +environment variable which is sent to the server. This can be useful when the +server does not have the proper terminfo installed. By default, or if set to +.Dq none , +the server gets the +.Ev TERM +variable from the local +.Xr environ 7 . .It Cm Tunnel Request .Xr tun 4 -- 2.5.0
Damien Miller
2015-Aug-17 00:36 UTC
[PATCH v2] Add a ssh_config Term option to override TERM
On Fri, 14 Aug 2015, Omar Sandoval wrote:> This is useful when a server is missing the necessary terminfo and > avoids having to manually set TERM before invoking ssh every time.I don't think adding a special-case for TERM is worth it, but maybe a more generic "SetEnv" that works in conjunction with SendEnv? E.g. Host foo SetEnv TERM xterm SetEnv LANG C TERM would be sent implicitly as part of session setup, but the rest would be equivalent to pre-loading the environment and doing SendEnv. -d