From: nicm Date: Tue, 13 May 2014 08:08:32 +0000 (+0000) Subject: If multiple arguments are given to new-session, new-window, X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=58034113e8e7c6d8a0538d5881c6abe68d8777c1;p=openbsd If multiple arguments are given to new-session, new-window, split-window, respawn-window or respawn-pane, pass them directly to execvp() to help avoid quoting problems. One argument still goes to "sh -c" like before. Requested by many over the years. Patch from J Raynor. --- diff --git a/usr.bin/tmux/cmd-new-session.c b/usr.bin/tmux/cmd-new-session.c index c1b49fe1e9e..60d89f29e52 100644 --- a/usr.bin/tmux/cmd-new-session.c +++ b/usr.bin/tmux/cmd-new-session.c @@ -1,4 +1,4 @@ -/* $OpenBSD: cmd-new-session.c,v 1.59 2014/04/17 13:02:59 nicm Exp $ */ +/* $OpenBSD: cmd-new-session.c,v 1.60 2014/05/13 08:08:32 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -35,10 +35,10 @@ enum cmd_retval cmd_new_session_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_new_session_entry = { "new-session", "new", - "Ac:dDF:n:Ps:t:x:y:", 0, 1, + "Ac:dDF:n:Ps:t:x:y:", 0, -1, "[-AdDP] [-c start-directory] [-F format] [-n window-name] " - "[-s session-name] " CMD_TARGET_SESSION_USAGE " [-x width] [-y height] " - "[command]", + "[-s session-name] " CMD_TARGET_SESSION_USAGE " [-x width] " + "[-y height] [command]", CMD_STARTSERVER|CMD_CANTNEST, NULL, cmd_new_session_exec @@ -55,8 +55,9 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq) struct termios tio, *tiop; const char *newname, *target, *update, *errstr, *template; const char *path; - char *cmd, *cause, *cp; + char **argv, *cmd, *cause, *cp; int detached, already_attached, idx, cwd, fd = -1; + int argc; u_int sx, sy; struct format_tree *ft; struct environ_entry *envent; @@ -183,12 +184,21 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq) sy = 1; /* Figure out the command for the new window. */ - if (target != NULL) - cmd = NULL; - else if (args->argc != 0) - cmd = args->argv[0]; - else + argc = -1; + argv = NULL; + if (target == NULL && args->argc != 0) { + argc = args->argc; + argv = args->argv; + } else if (target == NULL) { cmd = options_get_string(&global_s_options, "default-command"); + if (cmd != NULL && *cmd != '\0') { + argc = 1; + argv = &cmd; + } else { + argc = 0; + argv = NULL; + } + } path = NULL; if (c != NULL && c->session == NULL) @@ -206,8 +216,8 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq) /* Create the new session. */ idx = -1 - options_get_number(&global_s_options, "base-index"); - s = session_create(newname, cmd, path, cwd, &env, tiop, idx, sx, sy, - &cause); + s = session_create(newname, argc, argv, path, cwd, &env, tiop, idx, sx, + sy, &cause); if (s == NULL) { cmdq_error(cmdq, "create session failed: %s", cause); free(cause); @@ -216,7 +226,7 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq) environ_free(&env); /* Set the initial window name if one given. */ - if (cmd != NULL && args_has(args, 'n')) { + if (argc >= 0 && args_has(args, 'n')) { w = s->curw->window; window_set_name(w, args_get(args, 'n')); options_set_number(&w->options, "automatic-rename", 0); diff --git a/usr.bin/tmux/cmd-new-window.c b/usr.bin/tmux/cmd-new-window.c index 770e20e721f..daf8b8877ea 100644 --- a/usr.bin/tmux/cmd-new-window.c +++ b/usr.bin/tmux/cmd-new-window.c @@ -1,4 +1,4 @@ -/* $OpenBSD: cmd-new-window.c,v 1.39 2014/04/17 13:02:59 nicm Exp $ */ +/* $OpenBSD: cmd-new-window.c,v 1.40 2014/05/13 08:08:32 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -34,7 +34,7 @@ enum cmd_retval cmd_new_window_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_new_window_entry = { "new-window", "neww", - "ac:dF:kn:Pt:", 0, 1, + "ac:dF:kn:Pt:", 0, -1, "[-adkP] [-c start-directory] [-F format] [-n window-name] " CMD_TARGET_WINDOW_USAGE " [command]", 0, @@ -50,8 +50,8 @@ cmd_new_window_exec(struct cmd *self, struct cmd_q *cmdq) struct winlink *wl; struct client *c; const char *cmd, *path, *template; - char *cause, *cp; - int idx, last, detached, cwd, fd = -1; + char **argv, *cause, *cp; + int argc, idx, last, detached, cwd, fd = -1; struct format_tree *ft; struct environ_entry *envent; @@ -84,10 +84,19 @@ cmd_new_window_exec(struct cmd *self, struct cmd_q *cmdq) } detached = args_has(args, 'd'); - if (args->argc == 0) + if (args->argc == 0) { cmd = options_get_string(&s->options, "default-command"); - else - cmd = args->argv[0]; + if (cmd != NULL && *cmd != '\0') { + argc = 1; + argv = (char**)&cmd; + } else { + argc = 0; + argv = NULL; + } + } else { + argc = args->argc; + argv = args->argv; + } path = NULL; if (cmdq->client != NULL && cmdq->client->session == NULL) @@ -145,7 +154,8 @@ cmd_new_window_exec(struct cmd *self, struct cmd_q *cmdq) if (idx == -1) idx = -1 - options_get_number(&s->options, "base-index"); - wl = session_new(s, args_get(args, 'n'), cmd, path, cwd, idx, &cause); + wl = session_new(s, args_get(args, 'n'), argc, argv, path, cwd, idx, + &cause); if (wl == NULL) { cmdq_error(cmdq, "create window failed: %s", cause); free(cause); diff --git a/usr.bin/tmux/cmd-respawn-pane.c b/usr.bin/tmux/cmd-respawn-pane.c index 986cd86c088..be7bd3a3e8c 100644 --- a/usr.bin/tmux/cmd-respawn-pane.c +++ b/usr.bin/tmux/cmd-respawn-pane.c @@ -1,4 +1,4 @@ -/* $OpenBSD: cmd-respawn-pane.c,v 1.11 2014/04/17 13:02:59 nicm Exp $ */ +/* $OpenBSD: cmd-respawn-pane.c,v 1.12 2014/05/13 08:08:32 nicm Exp $ */ /* * Copyright (c) 2008 Nicholas Marriott @@ -32,7 +32,7 @@ enum cmd_retval cmd_respawn_pane_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_respawn_pane_entry = { "respawn-pane", "respawnp", - "kt:", 0, 1, + "kt:", 0, -1, "[-k] " CMD_TARGET_PANE_USAGE " [command]", 0, NULL, @@ -48,7 +48,7 @@ cmd_respawn_pane_exec(struct cmd *self, struct cmd_q *cmdq) struct window_pane *wp; struct session *s; struct environ env; - const char *cmd, *path; + const char *path; char *cause; u_int idx; struct environ_entry *envent; @@ -74,11 +74,6 @@ cmd_respawn_pane_exec(struct cmd *self, struct cmd_q *cmdq) screen_reinit(&wp->base); input_init(wp); - if (args->argc != 0) - cmd = args->argv[0]; - else - cmd = NULL; - path = NULL; if (cmdq->client != NULL && cmdq->client->session == NULL) envent = environ_find(&cmdq->client->environ, "PATH"); @@ -87,8 +82,8 @@ cmd_respawn_pane_exec(struct cmd *self, struct cmd_q *cmdq) if (envent != NULL) path = envent->value; - if (window_pane_spawn(wp, cmd, path, NULL, -1, &env, s->tio, - &cause) != 0) { + if (window_pane_spawn(wp, args->argc, args->argv, path, NULL, -1, &env, + s->tio, &cause) != 0) { cmdq_error(cmdq, "respawn pane failed: %s", cause); free(cause); environ_free(&env); diff --git a/usr.bin/tmux/cmd-respawn-window.c b/usr.bin/tmux/cmd-respawn-window.c index 6569052b440..8d7d350796d 100644 --- a/usr.bin/tmux/cmd-respawn-window.c +++ b/usr.bin/tmux/cmd-respawn-window.c @@ -1,4 +1,4 @@ -/* $OpenBSD: cmd-respawn-window.c,v 1.21 2014/04/17 13:02:59 nicm Exp $ */ +/* $OpenBSD: cmd-respawn-window.c,v 1.22 2014/05/13 08:08:32 nicm Exp $ */ /* * Copyright (c) 2008 Nicholas Marriott @@ -31,7 +31,7 @@ enum cmd_retval cmd_respawn_window_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_respawn_window_entry = { "respawn-window", "respawnw", - "kt:", 0, 1, + "kt:", 0, -1, "[-k] " CMD_TARGET_WINDOW_USAGE " [command]", 0, NULL, @@ -47,7 +47,7 @@ cmd_respawn_window_exec(struct cmd *self, struct cmd_q *cmdq) struct window_pane *wp; struct session *s; struct environ env; - const char *cmd, *path; + const char *path; char *cause; struct environ_entry *envent; @@ -76,10 +76,6 @@ cmd_respawn_window_exec(struct cmd *self, struct cmd_q *cmdq) window_destroy_panes(w); TAILQ_INSERT_HEAD(&w->panes, wp, entry); window_pane_resize(wp, w->sx, w->sy); - if (args->argc != 0) - cmd = args->argv[0]; - else - cmd = NULL; path = NULL; if (cmdq->client != NULL && cmdq->client->session == NULL) @@ -89,8 +85,8 @@ cmd_respawn_window_exec(struct cmd *self, struct cmd_q *cmdq) if (envent != NULL) path = envent->value; - if (window_pane_spawn(wp, cmd, path, NULL, -1, &env, s->tio, - &cause) != 0) { + if (window_pane_spawn(wp, args->argc, args->argv, path, NULL, -1, &env, + s->tio, &cause) != 0) { cmdq_error(cmdq, "respawn window failed: %s", cause); free(cause); environ_free(&env); diff --git a/usr.bin/tmux/cmd-split-window.c b/usr.bin/tmux/cmd-split-window.c index 8dde150b4f6..f5442c1a6d5 100644 --- a/usr.bin/tmux/cmd-split-window.c +++ b/usr.bin/tmux/cmd-split-window.c @@ -1,4 +1,4 @@ -/* $OpenBSD: cmd-split-window.c,v 1.49 2014/04/17 13:02:59 nicm Exp $ */ +/* $OpenBSD: cmd-split-window.c,v 1.50 2014/05/13 08:08:32 nicm Exp $ */ /* * Copyright (c) 2009 Nicholas Marriott @@ -36,7 +36,7 @@ enum cmd_retval cmd_split_window_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_split_window_entry = { "split-window", "splitw", - "c:dF:l:hp:Pt:v", 0, 1, + "c:dF:l:hp:Pt:v", 0, -1, "[-dhvP] [-c start-directory] [-F format] [-p percentage|-l size] " CMD_TARGET_PANE_USAGE " [command]", 0, @@ -62,9 +62,9 @@ cmd_split_window_exec(struct cmd *self, struct cmd_q *cmdq) struct window_pane *wp, *new_wp = NULL; struct environ env; const char *cmd, *path, *shell, *template; - char *cause, *new_cause, *cp; + char **argv, *cause, *new_cause, *cp; u_int hlimit; - int size, percentage, cwd, fd = -1; + int argc, size, percentage, cwd, fd = -1; enum layout_type type; struct layout_cell *lc; struct client *c; @@ -81,10 +81,19 @@ cmd_split_window_exec(struct cmd *self, struct cmd_q *cmdq) environ_copy(&s->environ, &env); server_fill_environ(s, &env); - if (args->argc == 0) + if (args->argc == 0) { cmd = options_get_string(&s->options, "default-command"); - else - cmd = args->argv[0]; + if (cmd != NULL && *cmd != '\0') { + argc = 1; + argv = (char**)&cmd; + } else { + argc = 0; + argv = NULL; + } + } else { + argc = args->argc; + argv = args->argv; + } if (args_has(args, 'c')) { ft = format_create(); @@ -158,8 +167,8 @@ cmd_split_window_exec(struct cmd *self, struct cmd_q *cmdq) if (envent != NULL) path = envent->value; - if (window_pane_spawn( - new_wp, cmd, path, shell, cwd, &env, s->tio, &cause) != 0) + if (window_pane_spawn(new_wp, argc, argv, path, shell, cwd, &env, + s->tio, &cause) != 0) goto error; layout_assign_pane(lc, new_wp); diff --git a/usr.bin/tmux/cmd.c b/usr.bin/tmux/cmd.c index c7cc683e007..3d2d321a36e 100644 --- a/usr.bin/tmux/cmd.c +++ b/usr.bin/tmux/cmd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: cmd.c,v 1.93 2014/05/09 09:11:24 nicm Exp $ */ +/* $OpenBSD: cmd.c,v 1.94 2014/05/13 08:08:32 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -187,7 +187,7 @@ cmd_copy_argv(int argc, char **argv) if (argc == 0) return (NULL); - new_argv = xcalloc(argc, sizeof *new_argv); + new_argv = xcalloc(argc + 1, sizeof *new_argv); for (i = 0; i < argc; i++) { if (argv[i] != NULL) new_argv[i] = xstrdup(argv[i]); @@ -207,6 +207,32 @@ cmd_free_argv(int argc, char **argv) free(argv); } +char * +cmd_stringify_argv(int argc, char **argv) +{ + char *buf; + int i; + size_t len; + + if (argc == 0) + return (xstrdup("")); + + len = 0; + buf = NULL; + + for (i = 0; i < argc; i++) { + len += strlen(argv[i]) + 1; + buf = xrealloc(buf, 1, len); + + if (i == 0) + *buf = '\0'; + else + strlcat(buf, " ", len); + strlcat(buf, argv[i], len); + } + return (buf); +} + struct cmd * cmd_parse(int argc, char **argv, const char *file, u_int line, char **cause) { diff --git a/usr.bin/tmux/format.c b/usr.bin/tmux/format.c index a1dee99d5c8..379d305cc98 100644 --- a/usr.bin/tmux/format.c +++ b/usr.bin/tmux/format.c @@ -1,4 +1,4 @@ -/* $OpenBSD: format.c,v 1.45 2014/05/13 07:34:35 nicm Exp $ */ +/* $OpenBSD: format.c,v 1.46 2014/05/13 08:08:32 nicm Exp $ */ /* * Copyright (c) 2011 Nicholas Marriott @@ -368,7 +368,7 @@ format_get_command(struct window_pane *wp) cmd = get_proc_name(wp->fd, wp->tty); if (cmd == NULL || *cmd == '\0') { free(cmd); - cmd = xstrdup(wp->cmd); + cmd = cmd_stringify_argv(wp->argc, wp->argv); if (cmd == NULL || *cmd == '\0') { free(cmd); cmd = xstrdup(wp->shell); @@ -559,8 +559,10 @@ format_window_pane(struct format_tree *ft, struct window_pane *wp) if (wp->tty != NULL) format_add(ft, "pane_tty", "%s", wp->tty); format_add(ft, "pane_pid", "%ld", (long) wp->pid); - if (wp->cmd != NULL) - format_add(ft, "pane_start_command", "%s", wp->cmd); + if ((cmd = cmd_stringify_argv(wp->argc, wp->argv)) != NULL) { + format_add(ft, "pane_start_command", "%s", cmd); + free(cmd); + } if ((cmd = format_get_command(wp)) != NULL) { format_add(ft, "pane_current_command", "%s", cmd); free(cmd); diff --git a/usr.bin/tmux/names.c b/usr.bin/tmux/names.c index c14086db8ac..c3101501148 100644 --- a/usr.bin/tmux/names.c +++ b/usr.bin/tmux/names.c @@ -1,4 +1,4 @@ -/* $OpenBSD: names.c,v 1.22 2013/10/10 11:56:50 nicm Exp $ */ +/* $OpenBSD: names.c,v 1.23 2014/05/13 08:08:32 nicm Exp $ */ /* * Copyright (c) 2009 Nicholas Marriott @@ -68,9 +68,15 @@ window_name_callback(unused int fd, unused short events, void *data) char * default_window_name(struct window *w) { - if (w->active->cmd != NULL && *w->active->cmd != '\0') - return (parse_window_name(w->active->cmd)); - return (parse_window_name(w->active->shell)); + char *cmd, *s; + + cmd = cmd_stringify_argv(w->active->argc, w->active->argv); + if (cmd != NULL && *cmd != '\0') + s = parse_window_name(cmd); + else + s = parse_window_name(w->active->shell); + free(cmd); + return (s); } char * diff --git a/usr.bin/tmux/session.c b/usr.bin/tmux/session.c index c458366996f..cafe4e81448 100644 --- a/usr.bin/tmux/session.c +++ b/usr.bin/tmux/session.c @@ -1,4 +1,4 @@ -/* $OpenBSD: session.c,v 1.43 2014/04/17 13:02:59 nicm Exp $ */ +/* $OpenBSD: session.c,v 1.44 2014/05/13 08:08:32 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -85,11 +85,12 @@ session_find_by_id(u_int id) /* Create a new session. */ struct session * -session_create(const char *name, const char *cmd, const char *path, int cwd, - struct environ *env, struct termios *tio, int idx, u_int sx, u_int sy, - char **cause) +session_create(const char *name, int argc, char **argv, const char *path, + int cwd, struct environ *env, struct termios *tio, int idx, u_int sx, + u_int sy, char **cause) { struct session *s; + struct winlink *wl; s = xmalloc(sizeof *s); s->references = 0; @@ -132,8 +133,9 @@ session_create(const char *name, const char *cmd, const char *path, int cwd, } RB_INSERT(sessions, &sessions, s); - if (cmd != NULL) { - if (session_new(s, NULL, cmd, path, cwd, idx, cause) == NULL) { + if (argc >= 0) { + wl = session_new(s, NULL, argc, argv, path, cwd, idx, cause); + if (wl == NULL) { session_destroy(s); return (NULL); } @@ -227,7 +229,7 @@ session_previous_session(struct session *s) /* Create a new window on a session. */ struct winlink * -session_new(struct session *s, const char *name, const char *cmd, +session_new(struct session *s, const char *name, int argc, char **argv, const char *path, int cwd, int idx, char **cause) { struct window *w; @@ -251,8 +253,8 @@ session_new(struct session *s, const char *name, const char *cmd, shell = _PATH_BSHELL; hlimit = options_get_number(&s->options, "history-limit"); - w = window_create(name, cmd, path, shell, cwd, &env, s->tio, s->sx, - s->sy, hlimit, cause); + w = window_create(name, argc, argv, path, shell, cwd, &env, s->tio, + s->sx, s->sy, hlimit, cause); if (w == NULL) { winlink_remove(&s->windows, wl); environ_free(&env); diff --git a/usr.bin/tmux/tmux.1 b/usr.bin/tmux/tmux.1 index 842dbea0cd1..38f5803d703 100644 --- a/usr.bin/tmux/tmux.1 +++ b/usr.bin/tmux/tmux.1 @@ -1,4 +1,4 @@ -.\" $OpenBSD: tmux.1,v 1.393 2014/05/13 07:54:20 nicm Exp $ +.\" $OpenBSD: tmux.1,v 1.394 2014/05/13 08:08:32 nicm Exp $ .\" .\" Copyright (c) 2007 Nicholas Marriott .\" @@ -478,12 +478,37 @@ It may be used alone to target a pane or the window containing it. arguments are .Xr sh 1 commands. -These must be passed as a single item, which typically means quoting them, for -example: +This may be a single argument passed to the shell, for example: .Bd -literal -offset indent new-window 'vi /etc/passwd' .Ed .Pp +Will run: +.Bd -literal -offset indent +/bin/sh -c 'vi /etc/passwd' +.Ed +.Pp +Additionally, the +.Ic new-window , +.Ic new-session , +.Ic split-window , +.Ic respawn-window +and +.Ic respawn-pane +commands allow +.Ar shell-command +to be given as multiple arguments and executed directly (without +.Ql sh -c ) . +This can avoid issues with shell quoting. +For example: +.Bd -literal -offset indent +$ tmux new-window vi /etc/passwd +.Ed +.Pp +Will run +.Xr vi 1 +directly without invoking the shell. +.Pp .Ar command .Op Ar arguments refers to a diff --git a/usr.bin/tmux/tmux.h b/usr.bin/tmux/tmux.h index 42f863d74de..0f5495785f9 100644 --- a/usr.bin/tmux/tmux.h +++ b/usr.bin/tmux/tmux.h @@ -1,4 +1,4 @@ -/* $OpenBSD: tmux.h,v 1.462 2014/05/13 07:54:20 nicm Exp $ */ +/* $OpenBSD: tmux.h,v 1.463 2014/05/13 08:08:32 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -914,7 +914,8 @@ struct window_pane { #define PANE_RESIZE 0x8 #define PANE_FOCUSPUSH 0x10 - char *cmd; + int argc; + char **argv; char *shell; int cwd; @@ -1750,6 +1751,7 @@ int cmd_pack_argv(int, char **, char *, size_t); int cmd_unpack_argv(char *, size_t, int, char ***); char **cmd_copy_argv(int, char **); void cmd_free_argv(int, char **); +char *cmd_stringify_argv(int, char **); struct cmd *cmd_parse(int, char **, const char *, u_int, char **); size_t cmd_print(struct cmd *, char *, size_t); struct session *cmd_current_session(struct cmd_q *, int); @@ -2140,7 +2142,7 @@ void winlink_stack_remove(struct winlink_stack *, struct winlink *); int window_index(struct window *, u_int *); struct window *window_find_by_id(u_int); struct window *window_create1(u_int, u_int); -struct window *window_create(const char *, const char *, const char *, +struct window *window_create(const char *, int, char **, const char *, const char *, int, struct environ *, struct termios *, u_int, u_int, u_int, char **); void window_destroy(struct window *); @@ -2166,7 +2168,7 @@ struct window_pane *window_pane_find_by_id(u_int); struct window_pane *window_pane_create(struct window *, u_int, u_int, u_int); void window_pane_destroy(struct window_pane *); void window_pane_timer_start(struct window_pane *); -int window_pane_spawn(struct window_pane *, const char *, +int window_pane_spawn(struct window_pane *, int, char **, const char *, const char *, int, struct environ *, struct termios *, char **); void window_pane_resize(struct window_pane *, u_int, u_int); @@ -2304,18 +2306,18 @@ RB_PROTOTYPE(sessions, session, entry, session_cmp); int session_alive(struct session *); struct session *session_find(const char *); struct session *session_find_by_id(u_int); -struct session *session_create(const char *, const char *, const char *, int, - struct environ *, struct termios *, int, u_int, u_int, - char **); +struct session *session_create(const char *, int, char **, const char *, + int, struct environ *, struct termios *, int, u_int, + u_int, char **); void session_destroy(struct session *); int session_check_name(const char *); void session_update_activity(struct session *); struct session *session_next_session(struct session *); struct session *session_previous_session(struct session *); -struct winlink *session_new(struct session *, const char *, const char *, +struct winlink *session_new(struct session *, const char *, int, char **, const char *, int, int, char **); -struct winlink *session_attach( - struct session *, struct window *, int, char **); +struct winlink *session_attach(struct session *, struct window *, int, + char **); int session_detach(struct session *, struct winlink *); struct winlink *session_has(struct session *, struct window *); int session_next(struct session *, int); diff --git a/usr.bin/tmux/window.c b/usr.bin/tmux/window.c index 84fee23ef1b..fbd09743041 100644 --- a/usr.bin/tmux/window.c +++ b/usr.bin/tmux/window.c @@ -1,4 +1,4 @@ -/* $OpenBSD: window.c,v 1.109 2014/05/08 06:03:30 nicm Exp $ */ +/* $OpenBSD: window.c,v 1.110 2014/05/13 08:08:32 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -307,7 +307,7 @@ window_create1(u_int sx, u_int sy) } struct window * -window_create(const char *name, const char *cmd, const char *path, +window_create(const char *name, int argc, char **argv, const char *path, const char *shell, int cwd, struct environ *env, struct termios *tio, u_int sx, u_int sy, u_int hlimit, char **cause) { @@ -318,7 +318,7 @@ window_create(const char *name, const char *cmd, const char *path, wp = window_add_pane(w, hlimit); layout_init(w, wp); - if (window_pane_spawn(wp, cmd, path, shell, cwd, env, tio, + if (window_pane_spawn(wp, argc, argv, path, shell, cwd, env, tio, cause) != 0) { window_destroy(w); return (NULL); @@ -678,7 +678,8 @@ window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit) wp->id = next_window_pane_id++; RB_INSERT(window_pane_tree, &all_window_panes, wp); - wp->cmd = NULL; + wp->argc = 0; + wp->argv = NULL; wp->shell = NULL; wp->cwd = -1; @@ -737,27 +738,29 @@ window_pane_destroy(struct window_pane *wp) close(wp->cwd); free(wp->shell); - free(wp->cmd); + cmd_free_argv(wp->argc, wp->argv); free(wp); } int -window_pane_spawn(struct window_pane *wp, const char *cmd, const char *path, - const char *shell, int cwd, struct environ *env, struct termios *tio, - char **cause) +window_pane_spawn(struct window_pane *wp, int argc, char **argv, + const char *path, const char *shell, int cwd, struct environ *env, + struct termios *tio, char **cause) { struct winsize ws; - char *argv0, paneid[16]; - const char *ptr; + char *argv0, *cmd, **argvp, paneid[16]; + const char *ptr, *first; struct termios tio2; + int i; if (wp->fd != -1) { bufferevent_free(wp->event); close(wp->fd); } - if (cmd != NULL) { - free(wp->cmd); - wp->cmd = xstrdup(cmd); + if (argc > 0) { + cmd_free_argv(wp->argc, wp->argv); + wp->argc = argc; + wp->argv = cmd_copy_argv(argc, argv); } if (shell != NULL) { free(wp->shell); @@ -768,7 +771,10 @@ window_pane_spawn(struct window_pane *wp, const char *cmd, const char *path, wp->cwd = dup(cwd); } - log_debug("spawn: %s -- %s", wp->shell, wp->cmd); + cmd = cmd_stringify_argv(wp->argc, wp->argv); + log_debug("spawn: %s -- %s", wp->shell, cmd); + for (i = 0; i < wp->argc; i++) + log_debug("spawn: argv[%d] = %s", i, wp->argv[i]); memset(&ws, 0, sizeof ws); ws.ws_col = screen_size_x(&wp->base); @@ -778,6 +784,7 @@ window_pane_spawn(struct window_pane *wp, const char *cmd, const char *path, case -1: wp->fd = -1; xasprintf(cause, "%s: %s", cmd, strerror(errno)); + free(cmd); return (-1); case 0: if (fchdir(wp->cwd) != 0) @@ -805,31 +812,42 @@ window_pane_spawn(struct window_pane *wp, const char *cmd, const char *path, setenv("SHELL", wp->shell, 1); ptr = strrchr(wp->shell, '/'); - if (*wp->cmd != '\0') { - /* Use the command. */ + /* + * If given one argument, assume it should be passed to sh -c; + * with more than one argument, use execvp(). If there is no + * arguments, create a login shell. + */ + if (wp->argc > 0) { + if (wp->argc != 1) { + /* Copy to ensure argv ends in NULL. */ + argvp = cmd_copy_argv(wp->argc, wp->argv); + execvp(argvp[0], argvp); + fatal("execvp failed"); + } + first = wp->argv[0]; + if (ptr != NULL && *(ptr + 1) != '\0') xasprintf(&argv0, "%s", ptr + 1); else xasprintf(&argv0, "%s", wp->shell); - execl(wp->shell, argv0, "-c", wp->cmd, (char *) NULL); + execl(wp->shell, argv0, "-c", first, (char *)NULL); fatal("execl failed"); } - - /* No command; fork a login shell. */ if (ptr != NULL && *(ptr + 1) != '\0') xasprintf(&argv0, "-%s", ptr + 1); else xasprintf(&argv0, "-%s", wp->shell); - execl(wp->shell, argv0, (char *) NULL); + execl(wp->shell, argv0, (char *)NULL); fatal("execl failed"); } setblocking(wp->fd, 0); - wp->event = bufferevent_new(wp->fd, - window_pane_read_callback, NULL, window_pane_error_callback, wp); + wp->event = bufferevent_new(wp->fd, window_pane_read_callback, NULL, + window_pane_error_callback, wp); bufferevent_enable(wp->event, EV_READ|EV_WRITE); + free(cmd); return (0); }