If multiple arguments are given to new-session, new-window,
authornicm <nicm@openbsd.org>
Tue, 13 May 2014 08:08:32 +0000 (08:08 +0000)
committernicm <nicm@openbsd.org>
Tue, 13 May 2014 08:08:32 +0000 (08:08 +0000)
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.

12 files changed:
usr.bin/tmux/cmd-new-session.c
usr.bin/tmux/cmd-new-window.c
usr.bin/tmux/cmd-respawn-pane.c
usr.bin/tmux/cmd-respawn-window.c
usr.bin/tmux/cmd-split-window.c
usr.bin/tmux/cmd.c
usr.bin/tmux/format.c
usr.bin/tmux/names.c
usr.bin/tmux/session.c
usr.bin/tmux/tmux.1
usr.bin/tmux/tmux.h
usr.bin/tmux/window.c

index c1b49fe..60d89f2 100644 (file)
@@ -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 <nicm@users.sourceforge.net>
@@ -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);
index 770e20e..daf8b88 100644 (file)
@@ -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 <nicm@users.sourceforge.net>
@@ -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);
index 986cd86..be7bd3a 100644 (file)
@@ -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 <nicm@users.sourceforge.net>
@@ -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);
index 6569052..8d7d350 100644 (file)
@@ -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 <nicm@users.sourceforge.net>
@@ -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);
index 8dde150..f5442c1 100644 (file)
@@ -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 <nicm@users.sourceforge.net>
@@ -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);
 
index c7cc683..3d2d321 100644 (file)
@@ -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 <nicm@users.sourceforge.net>
@@ -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)
 {
index a1dee99..379d305 100644 (file)
@@ -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 <nicm@users.sourceforge.net>
@@ -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);
index c14086d..c310150 100644 (file)
@@ -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 <nicm@users.sourceforge.net>
@@ -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 *
index c458366..cafe4e8 100644 (file)
@@ -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 <nicm@users.sourceforge.net>
@@ -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);
index 842dbea..38f5803 100644 (file)
@@ -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 <nicm@users.sourceforge.net>
 .\"
@@ -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
index 42f863d..0f54957 100644 (file)
@@ -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 <nicm@users.sourceforge.net>
@@ -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);
index 84fee23..fbd0974 100644 (file)
@@ -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 <nicm@users.sourceforge.net>
@@ -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);
 }