From a3a150faf22fe1d8303e8e92aa2a6d92e7e10b5c Mon Sep 17 00:00:00 2001 From: Tiago Cunha Date: Wed, 2 Sep 2009 01:02:44 +0000 Subject: [PATCH] Sync OpenBSD patchset 305: When using tmux as a login shell, there is currently no way to specify a shell to be used as a login shell inside tmux, so add a default-shell session option. This sets the shell invoked as a login shell when the default-command option is empty. The default option value is whichever of $SHELL, getpwuid(getuid())'s pw_shell or /bin/sh is valid first. Based on a diff from martynas@, changed by me to be a session option rather than a window option. --- cmd-respawn-window.c | 5 ++-- cmd-set-option.c | 3 ++- cmd-split-window.c | 10 ++++++-- names.c | 4 +-- session.c | 10 ++++++-- tmux.1 | 30 +++++++++++++++++----- tmux.c | 48 ++++++++++++++++++++++++++++++++++- tmux.h | 14 +++++++---- window.c | 60 +++++++++++++------------------------------- 9 files changed, 121 insertions(+), 63 deletions(-) diff --git a/cmd-respawn-window.c b/cmd-respawn-window.c index 849d40b7..114fdfd1 100644 --- a/cmd-respawn-window.c +++ b/cmd-respawn-window.c @@ -1,4 +1,4 @@ -/* $Id: cmd-respawn-window.c,v 1.20 2009-08-16 18:59:12 tcunha Exp $ */ +/* $Id: cmd-respawn-window.c,v 1.21 2009-09-02 01:02:44 tcunha Exp $ */ /* * Copyright (c) 2008 Nicholas Marriott @@ -75,7 +75,8 @@ cmd_respawn_window_exec(struct cmd *self, struct cmd_ctx *ctx) window_destroy_panes(w); TAILQ_INSERT_HEAD(&w->panes, wp, entry); window_pane_resize(wp, w->sx, w->sy); - if (window_pane_spawn(wp, data->arg, NULL, &env, &s->tio, &cause) != 0) { + if (window_pane_spawn( + wp, data->arg, NULL, NULL, &env, &s->tio, &cause) != 0) { ctx->error(ctx, "respawn window failed: %s", cause); xfree(cause); environ_free(&env); diff --git a/cmd-set-option.c b/cmd-set-option.c index 923d58fd..52d79395 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -1,4 +1,4 @@ -/* $Id: cmd-set-option.c,v 1.77 2009-08-31 22:30:15 tcunha Exp $ */ +/* $Id: cmd-set-option.c,v 1.78 2009-09-02 01:02:44 tcunha Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -55,6 +55,7 @@ const struct set_option_entry set_option_table[] = { { "buffer-limit", SET_OPTION_NUMBER, 1, INT_MAX, NULL }, { "default-command", SET_OPTION_STRING, 0, 0, NULL }, { "default-path", SET_OPTION_STRING, 0, 0, NULL }, + { "default-shell", SET_OPTION_STRING, 0, 0, NULL }, { "default-terminal", SET_OPTION_STRING, 0, 0, NULL }, { "display-panes-colour", SET_OPTION_COLOUR, 0, 0, NULL }, { "display-panes-time", SET_OPTION_NUMBER, 1, INT_MAX, NULL }, diff --git a/cmd-split-window.c b/cmd-split-window.c index f33ad562..8bee56d2 100644 --- a/cmd-split-window.c +++ b/cmd-split-window.c @@ -1,4 +1,4 @@ -/* $Id: cmd-split-window.c,v 1.24 2009-08-25 16:52:42 tcunha Exp $ */ +/* $Id: cmd-split-window.c,v 1.25 2009-09-02 01:02:44 tcunha Exp $ */ /* * Copyright (c) 2009 Nicholas Marriott @@ -18,6 +18,7 @@ #include +#include #include #include @@ -151,6 +152,7 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx) struct window_pane *wp; struct environ env; char *cmd, *cwd, *cause; + const char *shell; u_int hlimit; int size; enum layout_type type; @@ -183,8 +185,12 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx) if (data->flag_horizontal) type = LAYOUT_LEFTRIGHT; + shell = options_get_string(&s->options, "default-shell"); + if (*shell == '\0' || areshell(shell)) + shell = _PATH_BSHELL; + wp = window_add_pane(w, hlimit); - if (window_pane_spawn(wp, cmd, cwd, &env, &s->tio, &cause) != 0) + if (window_pane_spawn(wp, cmd, shell, cwd, &env, &s->tio, &cause) != 0) goto error; if (layout_split_pane(w->active, type, size, wp) != 0) { cause = xstrdup("pane too small"); diff --git a/names.c b/names.c index 6ff272bd..ee366aba 100644 --- a/names.c +++ b/names.c @@ -1,4 +1,4 @@ -/* $Id: names.c,v 1.14 2009-08-20 11:44:18 tcunha Exp $ */ +/* $Id: names.c,v 1.15 2009-09-02 01:02:44 tcunha Exp $ */ /* * Copyright (c) 2009 Nicholas Marriott @@ -90,7 +90,7 @@ default_window_name(struct window *w) return (xstrdup("[tmux]")); if (w->active->cmd != NULL && *w->active->cmd != '\0') return (parse_window_name(w->active->cmd)); - return (parse_window_name(window_default_command())); + return (parse_window_name(w->active->shell)); } char * diff --git a/session.c b/session.c index eedee301..39873082 100644 --- a/session.c +++ b/session.c @@ -1,4 +1,4 @@ -/* $Id: session.c,v 1.62 2009-08-16 19:16:27 tcunha Exp $ */ +/* $Id: session.c,v 1.63 2009-09-02 01:02:44 tcunha Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -207,6 +208,7 @@ session_new(struct session *s, { struct window *w; struct environ env; + const char *shell; u_int hlimit; environ_init(&env); @@ -214,9 +216,13 @@ session_new(struct session *s, environ_copy(&s->environ, &env); server_fill_environ(s, &env); + shell = options_get_string(&s->options, "default-shell"); + if (*shell == '\0' || areshell(shell)) + shell = _PATH_BSHELL; + hlimit = options_get_number(&s->options, "history-limit"); w = window_create( - name, cmd, cwd, &env, &s->tio, s->sx, s->sy, hlimit, cause); + name, cmd, shell, cwd, &env, &s->tio, s->sx, s->sy, hlimit, cause); if (w == NULL) { environ_free(&env); return (NULL); diff --git a/tmux.1 b/tmux.1 index bc0eacf6..1ab01e34 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1,4 +1,4 @@ -.\" $Id: tmux.1,v 1.160 2009-08-31 22:30:15 tcunha Exp $ +.\" $Id: tmux.1,v 1.161 2009-09-02 01:02:44 tcunha Exp $ .\" .\" Copyright (c) 2007 Nicholas Marriott .\" @@ -14,7 +14,7 @@ .\" IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING .\" OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: August 31 2009 $ +.Dd $Mdocdate: September 1 2009 $ .Dt TMUX 1 .Os .Sh NAME @@ -1143,13 +1143,31 @@ maintain this maximum length. .It Ic default-command Ar command Set the command used for new windows (if not specified when the window is created) to -.Ar command . +.Ar command , +which may be any +.Xr sh 1 +command. The default is an empty string, which instructs .Nm -to create a login shell using the +to create a login shell using the value of the +.Ic default-shell +option. +.It Ic default-shell Ar path +Specify the default shell. +This is used as the login shell for new windows when the +.Ic default-command +option is set to empty, and must be the full path of the executable. +When started +.Nm +tries to set a default value from the first suitable of the .Ev SHELL -environment variable or, if it is unset, the user's shell returned by -.Xr getpwuid 3 . +environment variable, the shell returned by +.Xr getpwuid 3 , +or +.Pa /bin/sh . +This option should be configured when +.Nm +is used as a login shell. .It Ic default-path Ar path Set the default working directory for processes created from keys, or interactively from the prompt. diff --git a/tmux.c b/tmux.c index 5c41061a..f145b4d4 100644 --- a/tmux.c +++ b/tmux.c @@ -1,4 +1,4 @@ -/* $Id: tmux.c,v 1.167 2009-09-02 00:55:49 tcunha Exp $ */ +/* $Id: tmux.c,v 1.168 2009-09-02 01:02:44 tcunha Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -184,6 +184,50 @@ sigreset(void) fatal("sigaction failed"); } +const char * +getshell(void) +{ + struct passwd *pw; + const char *shell; + + shell = getenv("SHELL"); + if (checkshell(shell)) + return (shell); + + pw = getpwuid(getuid()); + if (pw != NULL && checkshell(pw->pw_shell)) + return (pw->pw_shell); + + return (_PATH_BSHELL); +} + +int +checkshell(const char *shell) +{ + if (shell == NULL || *shell == '\0' || areshell(shell)) + return (0); + if (access(shell, X_OK) != 0) + return (0); + return (1); +} + +int +areshell(const char *shell) +{ + const char *progname, *ptr; + + if ((ptr = strrchr(shell, '/')) != NULL) + ptr++; + else + ptr = shell; + progname = __progname; + if (*progname == '-') + progname++; + if (strcmp(ptr, progname) == 0) + return (1); + return (0); +} + char * makesockpath(const char *label) { @@ -355,6 +399,8 @@ main(int argc, char **argv) options_set_number(&global_s_options, "bell-action", BELL_ANY); options_set_number(&global_s_options, "buffer-limit", 9); options_set_string(&global_s_options, "default-command", "%s", ""); + options_set_string( + &global_s_options, "default-shell", "%s", getshell()); options_set_string(&global_s_options, "default-terminal", "screen"); options_set_number(&global_s_options, "display-panes-colour", 4); options_set_number(&global_s_options, "display-panes-time", 1000); diff --git a/tmux.h b/tmux.h index bc328eb3..8a793561 100644 --- a/tmux.h +++ b/tmux.h @@ -1,4 +1,4 @@ -/* $Id: tmux.h,v 1.430 2009-08-31 22:30:15 tcunha Exp $ */ +/* $Id: tmux.h,v 1.431 2009-09-02 01:02:44 tcunha Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -673,6 +673,7 @@ struct window_pane { #define PANE_REDRAW 0x1 char *cmd; + char *shell; char *cwd; pid_t pid; @@ -1115,6 +1116,9 @@ void logfile(const char *); void siginit(void); void sigreset(void); void sighandler(int); +const char *getshell(void); +int checkshell(const char *); +int areshell(const char *); /* cfg.c */ int load_cfg(const char *, struct cmd_ctx *, char **); @@ -1580,7 +1584,6 @@ int screen_check_selection(struct screen *, u_int, u_int); /* window.c */ extern struct windows windows; -const char *window_default_command(void); int window_cmp(struct window *, struct window *); int winlink_cmp(struct winlink *, struct winlink *); RB_PROTOTYPE(windows, window, entry, window_cmp); @@ -1598,8 +1601,8 @@ void winlink_stack_remove(struct winlink_stack *, struct winlink *); int window_index(struct window *, u_int *); struct window *window_create1(u_int, u_int); struct window *window_create(const char *, const char *, const char *, - struct environ *, struct termios *, u_int, u_int, u_int, - char **); + const char *, struct environ *, struct termios *, + u_int, u_int, u_int, char **); void window_destroy(struct window *); void window_set_active_pane(struct window *, struct window_pane *); struct window_pane *window_add_pane(struct window *, u_int); @@ -1612,7 +1615,8 @@ void window_destroy_panes(struct window *); struct window_pane *window_pane_create(struct window *, u_int, u_int, u_int); void window_pane_destroy(struct window_pane *); int window_pane_spawn(struct window_pane *, const char *, - const char *, struct environ *, struct termios *, char **); + const char *, const char *, struct environ *, + struct termios *, char **); void window_pane_resize(struct window_pane *, u_int, u_int); int window_pane_set_mode( struct window_pane *, const struct window_mode *); diff --git a/window.c b/window.c index 38e542b6..cf6b1891 100644 --- a/window.c +++ b/window.c @@ -1,4 +1,4 @@ -/* $Id: window.c,v 1.104 2009-08-16 19:16:27 tcunha Exp $ */ +/* $Id: window.c,v 1.105 2009-09-02 01:02:44 tcunha Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -56,38 +56,6 @@ struct windows windows; RB_GENERATE(winlinks, winlink, entry, winlink_cmp); -const char * -window_default_command(void) -{ - const char *shell, *ptr; - char *progname; - struct passwd *pw; - - shell = getenv("SHELL"); - if (shell != NULL && *shell != '\0') - goto found; - - pw = getpwuid(getuid()); - if (pw != NULL && pw->pw_shell != NULL && *pw->pw_shell != '\0') { - shell = pw->pw_shell; - goto found; - } - - return (_PATH_BSHELL); - -found: - if ((ptr = strrchr(shell, '/')) != NULL) - ptr++; - else - ptr = shell; - progname = __progname; - if (*progname == '-') - progname++; - if (strcmp(ptr, progname) == 0) - return (_PATH_BSHELL); - return (shell); -} - int winlink_cmp(struct winlink *wl1, struct winlink *wl2) { @@ -268,9 +236,9 @@ window_create1(u_int sx, u_int sy) } struct window * -window_create(const char *name, const char *cmd, const char *cwd, - struct environ *env, struct termios *tio, u_int sx, u_int sy, u_int hlimit, - char **cause) +window_create(const char *name, const char *cmd, const char *shell, + const char *cwd, struct environ *env, struct termios *tio, + u_int sx, u_int sy, u_int hlimit,char **cause) { struct window *w; struct window_pane *wp; @@ -278,7 +246,7 @@ window_create(const char *name, const char *cmd, const char *cwd, w = window_create1(sx, sy); wp = window_add_pane(w, hlimit); layout_init(w); - if (window_pane_spawn(wp, cmd, cwd, env, tio, cause) != 0) { + if (window_pane_spawn(wp, cmd, shell, cwd, env, tio, cause) != 0) { window_destroy(w); return (NULL); } @@ -421,6 +389,7 @@ window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit) wp->window = w; wp->cmd = NULL; + wp->shell = NULL; wp->cwd = NULL; wp->fd = -1; @@ -465,13 +434,15 @@ window_pane_destroy(struct window_pane *wp) if (wp->cwd != NULL) xfree(wp->cwd); + if (wp->shell != NULL) + xfree(wp->shell); if (wp->cmd != NULL) xfree(wp->cmd); xfree(wp); } int -window_pane_spawn(struct window_pane *wp, const char *cmd, +window_pane_spawn(struct window_pane *wp, const char *cmd, const char *shell, const char *cwd, struct environ *env, struct termios *tio, char **cause) { struct winsize ws; @@ -490,6 +461,11 @@ window_pane_spawn(struct window_pane *wp, const char *cmd, xfree(wp->cmd); wp->cmd = xstrdup(cmd); } + if (shell != NULL) { + if (wp->shell != NULL) + xfree(wp->shell); + wp->shell = xstrdup(shell); + } if (cwd != NULL) { if (wp->cwd != NULL) xfree(wp->cwd); @@ -539,12 +515,12 @@ window_pane_spawn(struct window_pane *wp, const char *cmd, } /* No command; fork a login shell. */ - cmd = window_default_command(); - if ((ptr = strrchr(cmd, '/')) != NULL && *(ptr + 1) != '\0') + ptr = strrchr(wp->shell, '/'); + if (ptr != NULL && *(ptr + 1) != '\0') xasprintf(&argv0, "-%s", ptr + 1); else - xasprintf(&argv0, "-%s", cmd); - execl(cmd, argv0, (char *) NULL); + xasprintf(&argv0, "-%s", wp->shell); + execl(wp->shell, argv0, (char *) NULL); fatal("execl failed"); }