-/* $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>
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
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;
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)
/* 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);
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);
-/* $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>
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,
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;
}
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)
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);
-/* $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>
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,
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;
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");
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);
-/* $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>
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,
struct window_pane *wp;
struct session *s;
struct environ env;
- const char *cmd, *path;
+ const char *path;
char *cause;
struct environ_entry *envent;
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)
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);
-/* $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>
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,
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;
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();
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);
-/* $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>
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]);
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)
{
-/* $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>
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);
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);
-/* $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>
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 *
-/* $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>
/* 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;
}
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);
}
/* 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;
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);
-.\" $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>
.\"
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
-/* $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>
#define PANE_RESIZE 0x8
#define PANE_FOCUSPUSH 0x10
- char *cmd;
+ int argc;
+ char **argv;
char *shell;
int cwd;
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);
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 *);
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);
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);
-/* $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>
}
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)
{
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);
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;
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);
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);
case -1:
wp->fd = -1;
xasprintf(cause, "%s: %s", cmd, strerror(errno));
+ free(cmd);
return (-1);
case 0:
if (fchdir(wp->cwd) != 0)
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);
}