Sync OpenBSD patchset 231:

Infrastructure and commands to manage the environment for processes started
within tmux.

There is a global environment, copied from the external environment when the
server is started and each session has an (initially empty) session
environment which overrides it.

New commands set-environment and show-environment manipulate or display the
environments.

A new session option, update-environment, is a space-separated list of
variables which are updated from the external environment into the session
environment every time a new session is created - the default is DISPLAY.
This commit is contained in:
Tiago Cunha 2009-08-09 17:48:55 +00:00
parent af3db9a4fe
commit 29b1b2fb5e
18 changed files with 562 additions and 77 deletions

View File

@ -1,4 +1,4 @@
/* $Id: client.c,v 1.60 2009-08-09 17:43:00 tcunha Exp $ */
/* $Id: client.c,v 1.61 2009-08-09 17:48:55 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -33,6 +33,7 @@
#include "tmux.h"
void client_send_environ(struct client_ctx *);
void client_handle_winch(struct client_ctx *);
int
@ -99,6 +100,8 @@ server_started:
cctx->srv_in = buffer_create(BUFSIZ);
cctx->srv_out = buffer_create(BUFSIZ);
if (cmdflags & CMD_SENDENVIRON)
client_send_environ(cctx);
if (isatty(STDIN_FILENO)) {
if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1)
fatal("ioctl(TIOCGWINSZ)");
@ -137,6 +140,19 @@ not_found:
return (1);
}
void
client_send_environ(struct client_ctx *cctx)
{
char **var;
struct msg_environ_data data;
for (var = environ; *var != NULL; var++) {
if (strlcpy(data.var, *var, sizeof data.var) >= sizeof data.var)
continue;
client_write_server(cctx, MSG_ENVIRON, &data, sizeof data);
}
}
int
client_main(struct client_ctx *cctx)
{
@ -246,8 +262,8 @@ client_msg_dispatch(struct client_ctx *cctx)
if (hdr.size != sizeof printdata)
fatalx("bad MSG_PRINT size");
buffer_read(cctx->srv_in, &printdata, sizeof printdata);
printdata.msg[(sizeof printdata.msg) - 1] = '\0';
printdata.msg[(sizeof printdata.msg) - 1] = '\0';
cctx->errstr = xstrdup(printdata.msg);
return (-1);
case MSG_EXIT:

View File

@ -1,4 +1,4 @@
/* $Id: cmd-attach-session.c,v 1.31 2009-08-09 15:26:24 tcunha Exp $ */
/* $Id: cmd-attach-session.c,v 1.32 2009-08-09 17:48:55 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -29,7 +29,7 @@ int cmd_attach_session_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_attach_session_entry = {
"attach-session", "attach",
"[-d] " CMD_TARGET_SESSION_USAGE,
CMD_CANTNEST|CMD_STARTSERVER, CMD_CHFLAG('d'),
CMD_CANTNEST|CMD_STARTSERVER|CMD_SENDENVIRON, CMD_CHFLAG('d'),
cmd_target_init,
cmd_target_parse,
cmd_attach_session_exec,
@ -43,6 +43,7 @@ cmd_attach_session_exec(struct cmd *self, struct cmd_ctx *ctx)
struct cmd_target_data *data = self->data;
struct session *s;
struct client *c;
const char *update;
char *overrides, *cause;
u_int i;
@ -93,6 +94,10 @@ cmd_attach_session_exec(struct cmd *self, struct cmd_ctx *ctx)
ctx->cmdclient->session = s;
server_write_client(ctx->cmdclient, MSG_READY, NULL, 0);
update = options_get_string(&s->options, "update-environment");
environ_update(update, &ctx->cmdclient->environ, &s->environ);
server_redraw_client(ctx->cmdclient);
}
recalculate_sizes();

View File

@ -1,4 +1,4 @@
/* $Id: cmd-new-session.c,v 1.50 2009-08-09 15:26:24 tcunha Exp $ */
/* $Id: cmd-new-session.c,v 1.51 2009-08-09 17:48:55 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -40,7 +40,7 @@ struct cmd_new_session_data {
const struct cmd_entry cmd_new_session_entry = {
"new-session", "new",
"[-d] [-n window-name] [-s session-name] [command]",
CMD_STARTSERVER|CMD_CANTNEST, 0,
CMD_STARTSERVER|CMD_CANTNEST|CMD_SENDENVIRON, 0,
cmd_new_session_init,
cmd_new_session_parse,
cmd_new_session_exec,
@ -108,6 +108,8 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct cmd_new_session_data *data = self->data;
struct session *s;
struct environ env;
const char *update;
char *overrides, *cmd, *cwd, *cause;
int detached;
u_int sx, sy;
@ -184,13 +186,20 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx)
else
cmd = options_get_string(&global_s_options, "default-command");
/* Construct the environment. */
environ_init(&env);
update = options_get_string(&global_s_options, "update-environment");
if (ctx->cmdclient != NULL)
environ_update(update, &ctx->cmdclient->environ, &env);
/* Create the new session. */
s = session_create(data->newname, cmd, cwd, sx, sy, &cause);
s = session_create(data->newname, cmd, cwd, &env, sx, sy, &cause);
if (s == NULL) {
ctx->error(ctx, "create session failed: %s", cause);
xfree(cause);
return (-1);
}
environ_free(&env);
if (data->winname != NULL) {
xfree(s->curw->window->name);

View File

@ -1,4 +1,4 @@
/* $Id: cmd-respawn-window.c,v 1.18 2009-07-28 22:12:16 tcunha Exp $ */
/* $Id: cmd-respawn-window.c,v 1.19 2009-08-09 17:48:55 tcunha Exp $ */
/*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@ -47,7 +47,7 @@ cmd_respawn_window_exec(struct cmd *self, struct cmd_ctx *ctx)
struct window *w;
struct window_pane *wp;
struct session *s;
const char **env;
struct environ env;
char *cause;
if ((wl = cmd_find_window(ctx, data->target, &s)) == NULL)
@ -64,7 +64,10 @@ cmd_respawn_window_exec(struct cmd *self, struct cmd_ctx *ctx)
}
}
env = server_fill_environ(s);
environ_init(&env);
environ_copy(&global_environ, &env);
environ_copy(&s->environ, &env);
server_fill_environ(s, &env);
wp = TAILQ_FIRST(&w->panes);
TAILQ_REMOVE(&w->panes, wp, entry);
@ -72,9 +75,10 @@ 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, &cause) != 0) {
if (window_pane_spawn(wp, data->arg, NULL, &env, &cause) != 0) {
ctx->error(ctx, "respawn window failed: %s", cause);
xfree(cause);
environ_free(&env);
return (-1);
}
layout_init(w);
@ -84,5 +88,6 @@ cmd_respawn_window_exec(struct cmd *self, struct cmd_ctx *ctx)
recalculate_sizes();
server_redraw_window(w);
environ_free(&env);
return (0);
}

88
cmd-set-environment.c Normal file
View File

@ -0,0 +1,88 @@
/* $Id: cmd-set-environment.c,v 1.1 2009-08-09 17:48:55 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include "tmux.h"
/*
* Set an environment variable.
*/
int cmd_set_environment_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_set_environment_entry = {
"set-environment", "setenv",
"[-gru] " CMD_OPTION_SESSION_USAGE,
0, CMD_CHFLAG('g')|CMD_CHFLAG('r')|CMD_CHFLAG('u'),
NULL,
cmd_option_parse,
cmd_set_environment_exec,
cmd_option_free,
cmd_option_print
};
int
cmd_set_environment_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct cmd_option_data *data = self->data;
struct session *s;
struct environ *env;
if (*data->option == '\0') {
ctx->error(ctx, "empty variable name");
return (-1);
}
if (strchr(data->option, '=') != NULL) {
ctx->error(ctx, "variable name contains =");
return (-1);
}
if (data->chflags & CMD_CHFLAG('g'))
env = &global_environ;
else {
if ((s = cmd_find_session(ctx, data->target)) == NULL)
return (-1);
env = &s->environ;
}
if (data->chflags & CMD_CHFLAG('u')) {
if (data->value != NULL) {
ctx->error(ctx, "can't specify a value with -u");
return (-1);
}
environ_unset(env, data->option);
} else if (data->chflags & CMD_CHFLAG('r')) {
if (data->value != NULL) {
ctx->error(ctx, "can't specify a value with -r");
return (-1);
}
environ_set(env, data->option, NULL);
} else {
if (data->value == NULL) {
ctx->error(ctx, "no value specified");
return (-1);
}
environ_set(env, data->option, data->value);
}
return (0);
}

View File

@ -1,4 +1,4 @@
/* $Id: cmd-set-option.c,v 1.73 2009-08-09 17:40:17 tcunha Exp $ */
/* $Id: cmd-set-option.c,v 1.74 2009-08-09 17:48:55 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -85,6 +85,7 @@ const struct set_option_entry set_option_table[] = {
{ "status-right-length", SET_OPTION_NUMBER, 0, SHRT_MAX, NULL },
{ "status-utf8", SET_OPTION_FLAG, 0, 0, NULL },
{ "terminal-overrides", SET_OPTION_STRING, 0, 0, NULL },
{ "update-environment", SET_OPTION_STRING, 0, 0, NULL },
{ "visual-activity", SET_OPTION_FLAG, 0, 0, NULL },
{ "visual-bell", SET_OPTION_FLAG, 0, 0, NULL },
{ "visual-content", SET_OPTION_FLAG, 0, 0, NULL },

67
cmd-show-environment.c Normal file
View File

@ -0,0 +1,67 @@
/* $Id: cmd-show-environment.c,v 1.1 2009-08-09 17:48:55 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include "tmux.h"
/*
* Show environment.
*/
int cmd_show_environment_exec(struct cmd *, struct cmd_ctx *);
const struct cmd_entry cmd_show_environment_entry = {
"show-environment", "showenv",
"[-g] " CMD_TARGET_SESSION_USAGE,
0, CMD_CHFLAG('g'),
cmd_target_init,
cmd_target_parse,
cmd_show_environment_exec,
cmd_target_free,
cmd_target_print
};
int
cmd_show_environment_exec(struct cmd *self, struct cmd_ctx *ctx)
{
struct cmd_target_data *data = self->data;
struct session *s;
struct environ *env;
struct environ_entry *envent;
if (data->chflags & CMD_CHFLAG('g'))
env = &global_environ;
else {
if ((s = cmd_find_session(ctx, data->target)) == NULL)
return (-1);
env = &s->environ;
}
RB_FOREACH(envent, environ, env) {
if (envent->value != NULL)
ctx->print(ctx, "%s=%s", envent->name, envent->value);
else
ctx->print(ctx, "-%s", envent->name);
}
return (0);
}

View File

@ -1,4 +1,4 @@
/* $Id: cmd-split-window.c,v 1.21 2009-07-28 22:12:16 tcunha Exp $ */
/* $Id: cmd-split-window.c,v 1.22 2009-08-09 17:48:55 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
@ -149,7 +149,7 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx)
struct winlink *wl;
struct window *w;
struct window_pane *wp;
const char **env;
struct environ env;
char *cmd, *cwd, *cause;
u_int hlimit;
int size;
@ -159,7 +159,10 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx)
return (-1);
w = wl->window;
env = server_fill_environ(s);
environ_init(&env);
environ_copy(&global_environ, &env);
environ_copy(&s->environ, &env);
server_fill_environ(s, &env);
cmd = data->cmd;
if (cmd == NULL)
@ -181,7 +184,7 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx)
type = LAYOUT_LEFTRIGHT;
wp = window_add_pane(w, hlimit);
if (window_pane_spawn(wp, cmd, cwd, env, &cause) != 0)
if (window_pane_spawn(wp, cmd, cwd, &env, &cause) != 0)
goto error;
if (layout_split_pane(w->active, type, size, wp) != 0) {
cause = xstrdup("pane too small");
@ -197,9 +200,11 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx)
} else
server_status_session(s);
environ_free(&env);
return (0);
error:
environ_free(&env);
if (wp != NULL)
window_remove_pane(w, wp);
ctx->error(ctx, "create pane failed: %s", cause);

View File

@ -1,4 +1,4 @@
/* $Id: cmd-string.c,v 1.22 2009-08-09 15:26:24 tcunha Exp $ */
/* $Id: cmd-string.c,v 1.23 2009-08-09 17:48:55 tcunha Exp $ */
/*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@ -59,21 +59,11 @@ int
cmd_string_parse(const char *s, struct cmd_list **cmdlist, char **cause)
{
size_t p;
int ch, argc, rval, have_arg;
char **argv, *buf, *t, *u;
int ch, i, argc, rval, have_arg;
char **argv, *buf, *t;
const char *whitespace, *equals;
size_t len;
if ((t = strchr(s, ' ')) == NULL && (t = strchr(s, '\t')) == NULL)
t = strchr(s, '\0');
if ((u = strchr(s, '=')) != NULL && u < t) {
if (putenv(xstrdup(s)) != 0) {
xasprintf(cause, "assignment failed: %s", s);
return (-1);
}
*cmdlist = NULL;
return (0);
}
argv = NULL;
argc = 0;
@ -147,6 +137,18 @@ cmd_string_parse(const char *s, struct cmd_list **cmdlist, char **cause)
if (argc == 0)
goto out;
for (i = 0; i < argc; i++) {
equals = strchr(argv[i], '=');
whitespace = argv[i] + strcspn(argv[i], " \t");
if (equals == NULL || equals > whitespace)
break;
environ_put(&global_environ, argv[i]);
memmove(&argv[i], &argv[i + 1], argc - i - 1);
argc--;
}
if (argc == 0)
goto out;
*cmdlist = cmd_list_parse(argc, argv, cause);
if (*cmdlist == NULL)
goto out;

4
cmd.c
View File

@ -1,4 +1,4 @@
/* $Id: cmd.c,v 1.111 2009-07-30 20:45:20 tcunha Exp $ */
/* $Id: cmd.c,v 1.112 2009-08-09 17:48:55 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -83,10 +83,12 @@ const struct cmd_entry *cmd_table[] = {
&cmd_send_prefix_entry,
&cmd_server_info_entry,
&cmd_set_buffer_entry,
&cmd_set_environment_entry,
&cmd_set_option_entry,
&cmd_set_password_entry,
&cmd_set_window_option_entry,
&cmd_show_buffer_entry,
&cmd_show_environment_entry,
&cmd_show_options_entry,
&cmd_show_window_options_entry,
&cmd_source_file_entry,

147
environ.c Normal file
View File

@ -0,0 +1,147 @@
/* $Id: environ.c,v 1.1 2009-08-09 17:48:55 tcunha Exp $ */
/*
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include "tmux.h"
/*
* Environment - manipulate a set of environment variables.
*/
RB_GENERATE(environ, environ_entry, entry, environ_cmp);
void environ_set1(struct environ *, char *, char *);
int
environ_cmp(struct environ_entry *envent1, struct environ_entry *envent2)
{
return (strcmp(envent1->name, envent2->name));
}
void
environ_init(struct environ *env)
{
RB_INIT(env);
}
void
environ_free(struct environ *env)
{
struct environ_entry *envent;
while (!RB_EMPTY(env)) {
envent = RB_ROOT(env);
RB_REMOVE(environ, env, envent);
xfree(envent->name);
if (envent->value != NULL)
xfree(envent->value);
xfree(envent);
}
}
void
environ_copy(struct environ *srcenv, struct environ *dstenv)
{
struct environ_entry *envent;
RB_FOREACH(envent, environ, srcenv)
environ_set(dstenv, envent->name, envent->value);
}
struct environ_entry *
environ_find(struct environ *env, const char *name)
{
struct environ_entry envent;
envent.name = (char *) name;
return (RB_FIND(environ, env, &envent));
}
void
environ_set(struct environ *env, const char *name, const char *value)
{
struct environ_entry *envent;
if ((envent = environ_find(env, name)) != NULL) {
if (envent->value != NULL)
xfree(envent->value);
if (value != NULL)
envent->value = xstrdup(value);
else
envent->value = NULL;
} else {
envent = xmalloc(sizeof *envent);
envent->name = xstrdup(name);
if (value != NULL)
envent->value = xstrdup(value);
else
envent->value = NULL;
RB_INSERT(environ, env, envent);
}
}
void
environ_put(struct environ *env, const char *var)
{
char *name, *value;
value = strchr(var, '=');
if (value == NULL)
return;
value++;
name = xstrdup(var);
name[strcspn(name, "=")] = '\0';
environ_set(env, name, value);
xfree(name);
}
void
environ_unset(struct environ *env, const char *name)
{
struct environ_entry *envent;
if ((envent = environ_find(env, name)) == NULL)
return;
RB_REMOVE(environ, env, envent);
xfree(envent->name);
if (envent->value != NULL)
xfree(envent->value);
xfree(envent);
}
void
environ_update(const char *vars, struct environ *srcenv, struct environ *dstenv)
{
struct environ_entry *envent;
char *var, *next;
vars = next = xstrdup(vars);
while ((var = strsep(&next, " ")) != NULL) {
if ((envent = environ_find(srcenv, var)) == NULL)
environ_set(dstenv, var, NULL);
else
environ_set(dstenv, envent->name, envent->value);
}
xfree(vars);
}

View File

@ -1,4 +1,4 @@
/* $Id: server-fn.c,v 1.79 2009-08-09 17:19:18 tcunha Exp $ */
/* $Id: server-fn.c,v 1.80 2009-08-09 17:48:55 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -26,25 +26,20 @@
int server_lock_callback(void *, const char *);
const char **
server_fill_environ(struct session *s)
void
server_fill_environ(struct session *s, struct environ *env)
{
static const char *env[] = { NULL /* TMUX= */, NULL /* TERM */, NULL };
static char tmuxvar[MAXPATHLEN + 256], termvar[256];
u_int idx;
char tmuxvar[MAXPATHLEN], *term;
u_int idx;
if (session_index(s, &idx) != 0)
fatalx("session not found");
xsnprintf(tmuxvar, sizeof tmuxvar,
"TMUX=%s,%ld,%u", socket_path, (long) getpid(), idx);
env[0] = tmuxvar;
"%s,%ld,%u", socket_path, (long) getpid(), idx);
environ_set(env, "TMUX", tmuxvar);
xsnprintf(termvar, sizeof termvar,
"TERM=%s", options_get_string(&s->options, "default-terminal"));
env[1] = termvar;
return (env);
term = options_get_string(&s->options, "default-terminal");
environ_set(env, "TERM", term);
}
void

View File

@ -1,4 +1,4 @@
/* $Id: server-msg.c,v 1.76 2009-07-30 21:01:01 tcunha Exp $ */
/* $Id: server-msg.c,v 1.77 2009-08-09 17:48:55 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -42,6 +42,7 @@ server_msg_dispatch(struct client *c)
struct msg_identify_data identifydata;
struct msg_resize_data resizedata;
struct msg_unlock_data unlockdata;
struct msg_environ_data environdata;
for (;;) {
if (BUFFER_USED(c->in) < sizeof hdr)
@ -100,6 +101,15 @@ server_msg_dispatch(struct client *c)
tty_start_tty(&c->tty);
server_redraw_client(c);
break;
case MSG_ENVIRON:
if (hdr.size != sizeof environdata)
fatalx("bad MSG_ENVIRON size");
buffer_read(c->in, &environdata, sizeof environdata);
environdata.var[(sizeof environdata.var) - 1] = '\0';
if (strchr(environdata.var, '=') != NULL)
environ_put(&c->environ, environdata.var);
break;
default:
fatalx("unexpected message");
}

View File

@ -1,4 +1,4 @@
/* $Id: session.c,v 1.59 2009-07-08 18:03:03 nicm Exp $ */
/* $Id: session.c,v 1.60 2009-08-09 17:48:55 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -112,8 +112,8 @@ session_find(const char *name)
/* Create a new session. */
struct session *
session_create(const char *name,
const char *cmd, const char *cwd, u_int sx, u_int sy, char **cause)
session_create(const char *name, const char *cmd, const char *cwd,
struct environ *env, u_int sx, u_int sy, char **cause)
{
struct session *s;
u_int i;
@ -128,6 +128,9 @@ session_create(const char *name,
SLIST_INIT(&s->alerts);
paste_init_stack(&s->buffers);
options_init(&s->options, &global_s_options);
environ_init(&s->environ);
if (env != NULL)
environ_copy(env, &s->environ);
s->sx = sx;
s->sy = sy;
@ -171,6 +174,7 @@ session_destroy(struct session *s)
ARRAY_TRUNC(&sessions, 1);
session_alert_cancel(s, NULL);
environ_free(&s->environ);
options_free(&s->options);
paste_free_stack(&s->buffers);
@ -200,15 +204,21 @@ session_new(struct session *s,
const char *name, const char *cmd, const char *cwd, int idx, char **cause)
{
struct window *w;
const char **env;
struct environ env;
u_int hlimit;
env = server_fill_environ(s);
environ_init(&env);
environ_copy(&global_environ, &env);
environ_copy(&s->environ, &env);
server_fill_environ(s, &env);
hlimit = options_get_number(&s->options, "history-limit");
w = window_create(name, cmd, cwd, env, s->sx, s->sy, hlimit, cause);
if (w == NULL)
w = window_create(name, cmd, cwd, &env, s->sx, s->sy, hlimit, cause);
if (w == NULL) {
environ_free(&env);
return (NULL);
}
environ_free(&env);
if (options_get_number(&s->options, "set-remain-on-exit"))
options_set_number(&w->options, "remain-on-exit", 1);

68
tmux.1
View File

@ -1,4 +1,4 @@
.\" $Id: tmux.1,v 1.144 2009-08-09 17:40:17 tcunha Exp $
.\" $Id: tmux.1,v 1.145 2009-08-09 17:48:55 tcunha Exp $
.\"
.\" Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
.\"
@ -1321,6 +1321,18 @@ entry for terminals which support 88 or 256 colours:
.Bd -literal -offset indent
"*88col*:colors=88,*256col*:colors=256"
.Ed
.It Ic update-environment Ar variables
Set a space-separated string containing a list of environment variables to be
copied into the session environment when a new session is created or an
existing session is attached.
Any variables that do not exist in the source environment are set to be
removed from the session environment (as if
.Fl r
was given to the
.Ic set-environment
command).
The default is
.Ev DISPLAY .
.It Xo Ic visual-activity
.Op Ic on | off
.Xc
@ -1525,6 +1537,60 @@ or the global window options if
.Fl g
is used.
.El
.Sh ENVIRONMENT
When the server is started,
.Nm
copies the environment into the
.Em global environment ;
in addition, each session has a
.Em session environment .
When a window is created, the session and global environments are merged with
the session environment overriding any variable present in both.
This is the initial environment passed to the new process.
.Pp
The
.Ic update-environment
session option may be used to update the session environment from the client
when a new session is created or an old reattached.
.Nm
also initialises the
.Ev TMUX
variable with some internal information to allow commands to be executed
from inside, and the
.Ev TERM
variable with the correct terminal setting of
.Ql screen .
.Pp
Commands to alter and view the environment are:
.Bl -tag -width Ds
.It Xo Ic set-environment
.Op Fl gru
.Op Fl t Ar target-session
.Ar name Op Ar value
.Xc
Set or unset an environment variable.
If
.Fl g
is used, the change is made in the global environment; otherwise, it is applied
to the session environment for
.Ar target-session .
The
.Fl u
flag unsets a variable.
.Fl r
indicates the variable is to be removed from the environment before starting a
new process.
.It Xo Ic show-environment
.Op Fl g
.Op Fl t Ar target-session
.Xc
Display the environment for
.Ar target-session
or the global environment with
.Fl g .
Variables removed from the environment are prefixed with
.Ql - .
.El
.Sh STATUS LINE
.Nm
includes an optional status line which is displayed in the bottom line of each

16
tmux.c
View File

@ -1,4 +1,4 @@
/* $Id: tmux.c,v 1.157 2009-08-09 17:40:17 tcunha Exp $ */
/* $Id: tmux.c,v 1.158 2009-08-09 17:48:55 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -49,6 +49,7 @@ volatile sig_atomic_t sigusr2;
char *cfg_file;
struct options global_s_options; /* session options */
struct options global_w_options; /* window options */
struct environ global_environ;
int server_locked;
u_int password_failures;
@ -271,7 +272,7 @@ main(int argc, char **argv)
struct hdr hdr;
struct passwd *pw;
struct msg_print_data printdata;
char *s, *path, *label, *home, *cause;
char *s, *path, *label, *home, *cause, **var;
char cwd[MAXPATHLEN];
void *buf;
size_t len;
@ -329,6 +330,10 @@ main(int argc, char **argv)
log_open_tty(debug_level);
siginit();
environ_init(&global_environ);
for (var = environ; *var != NULL; var++)
environ_put(&global_environ, *var);
if (!(flags & IDENTIFY_UTF8)) {
/*
* If the user has set whichever of LC_ALL, LC_CTYPE or LANG
@ -385,6 +390,7 @@ main(int argc, char **argv)
options_set_number(&global_s_options, "status-utf8", 0);
options_set_string(&global_s_options,
"terminal-overrides", "*88col*:colors=88,*256col*:colors=256");
options_set_string(&global_s_options, "update-environment", "DISPLAY");
options_set_number(&global_s_options, "visual-activity", 0);
options_set_number(&global_s_options, "visual-bell", 0);
options_set_number(&global_s_options, "visual-content", 0);
@ -478,10 +484,10 @@ main(int argc, char **argv)
}
cmdflags &= ~CMD_STARTSERVER;
TAILQ_FOREACH(cmd, cmdlist, qentry) {
if (cmd->entry->flags & CMD_STARTSERVER) {
if (cmd->entry->flags & CMD_STARTSERVER)
cmdflags |= CMD_STARTSERVER;
break;
}
if (cmd->entry->flags & CMD_SENDENVIRON)
cmdflags |= CMD_SENDENVIRON;
}
cmd_list_free(cmdlist);
}

48
tmux.h
View File

@ -1,4 +1,4 @@
/* $Id: tmux.h,v 1.407 2009-08-09 17:32:06 tcunha Exp $ */
/* $Id: tmux.h,v 1.408 2009-08-09 17:48:55 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -38,6 +38,7 @@
#include "compat.h"
extern char *__progname;
extern char **environ;
/* Default configuration files. */
#define DEFAULT_CFG ".tmux.conf"
@ -68,6 +69,7 @@ extern char *__progname;
#define COMMAND_LENGTH 2048 /* packed argv size */
#define TERMINAL_LENGTH 128 /* length of TERM environment variable */
#define PRINT_LENGTH 512 /* printed error/message size */
#define ENVIRON_LENGTH 1024 /* environment variable length */
/* Fatal errors. */
#define fatal(msg) log_fatal("%s: %s", __func__, msg);
@ -301,6 +303,7 @@ enum msgtype {
MSG_SUSPEND,
MSG_UNLOCK,
MSG_WAKEUP,
MSG_ENVIRON
};
/*
@ -355,6 +358,10 @@ struct msg_unlock_data {
char pass[PASS_MAX];
};
struct msg_environ_data {
char var[ENVIRON_LENGTH];
};
/* Mode key commands. */
enum mode_key_cmd {
MODEKEY_NONE,
@ -764,6 +771,15 @@ struct paste_buffer {
};
ARRAY_DECL(paste_stack, struct paste_buffer *);
/* Environment variable. */
struct environ_entry {
char *name;
char *value;
RB_ENTRY(environ_entry) entry;
};
RB_HEAD(environ, environ_entry);
/* Client session. */
struct session_alert {
struct winlink *wl;
@ -791,6 +807,8 @@ struct session {
#define SESSION_UNATTACHED 0x1 /* not attached to any clients */
int flags;
struct environ environ;
};
ARRAY_DECL(sessions, struct session *);
@ -893,6 +911,8 @@ struct client {
struct buffer *in;
struct buffer *out;
struct environ environ;
char *title;
char *cwd;
@ -991,6 +1011,7 @@ struct cmd_entry {
#define CMD_CANTNEST 0x2
#define CMD_ARG1 0x4
#define CMD_ARG01 0x8
#define CMD_SENDENVIRON 0x10
int flags;
#define CMD_CHFLAG(flag) \
@ -1073,6 +1094,7 @@ extern volatile sig_atomic_t sigusr1;
extern volatile sig_atomic_t sigusr2;
extern struct options global_s_options;
extern struct options global_w_options;
extern struct environ global_environ;
extern char *cfg_file;
extern int server_locked;
extern u_int password_failures;
@ -1122,6 +1144,18 @@ char *options_get_string(struct options *, const char *);
void options_set_number(struct options *, const char *, long long);
long long options_get_number(struct options *, const char *);
/* environ.c */
int environ_cmp(struct environ_entry *, struct environ_entry *);
RB_PROTOTYPE(environ, environ_entry, entry, environ_cmp);
void environ_init(struct environ *);
void environ_free(struct environ *);
void environ_copy(struct environ *, struct environ *);
struct environ_entry *environ_find(struct environ *, const char *);
void environ_set(struct environ *, const char *, const char *);
void environ_put(struct environ *, const char *);
void environ_unset(struct environ *, const char *);
void environ_update(const char *, struct environ *, struct environ *);
/* tty.c */
u_char tty_get_acs(struct tty *, u_char);
void tty_reset(struct tty *);
@ -1284,10 +1318,12 @@ extern const struct cmd_entry cmd_send_keys_entry;
extern const struct cmd_entry cmd_send_prefix_entry;
extern const struct cmd_entry cmd_server_info_entry;
extern const struct cmd_entry cmd_set_buffer_entry;
extern const struct cmd_entry cmd_set_environment_entry;
extern const struct cmd_entry cmd_set_option_entry;
extern const struct cmd_entry cmd_set_password_entry;
extern const struct cmd_entry cmd_set_window_option_entry;
extern const struct cmd_entry cmd_show_buffer_entry;
extern const struct cmd_entry cmd_show_environment_entry;
extern const struct cmd_entry cmd_show_options_entry;
extern const struct cmd_entry cmd_show_window_options_entry;
extern const struct cmd_entry cmd_source_file_entry;
@ -1383,7 +1419,7 @@ int server_start(char *);
int server_msg_dispatch(struct client *);
/* server-fn.c */
const char **server_fill_environ(struct session *);
void server_fill_environ(struct session *, struct environ *);
void server_write_error(struct client *, const char *);
void server_write_client(
struct client *, enum msgtype, const void *, size_t);
@ -1553,8 +1589,8 @@ void winlink_stack_push(struct winlink_stack *, struct winlink *);
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 *, const char **, u_int, u_int, u_int, char **);
struct window *window_create(const char *, const char *, const char *,
struct environ *, 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);
@ -1567,7 +1603,7 @@ 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 *, const char **, char **);
const char *, const char *, struct environ *, char **);
void window_pane_resize(struct window_pane *, u_int, u_int);
int window_pane_set_mode(
struct window_pane *, const struct window_mode *);
@ -1647,7 +1683,7 @@ int session_alert_has(struct session *, struct winlink *, int);
int session_alert_has_window(struct session *, struct window *, int);
struct session *session_find(const char *);
struct session *session_create(const char *, const char *,
const char *, u_int, u_int, char **);
const char *, struct environ *, u_int, u_int, char **);
void session_destroy(struct session *);
int session_index(struct session *, u_int *);
struct winlink *session_new(struct session *,

View File

@ -1,4 +1,4 @@
/* $Id: window.c,v 1.99 2009-07-28 23:04:29 tcunha Exp $ */
/* $Id: window.c,v 1.100 2009-08-09 17:48:55 tcunha Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -252,7 +252,7 @@ window_create1(u_int sx, u_int sy)
struct window *
window_create(const char *name, const char *cmd, const char *cwd,
const char **envp, u_int sx, u_int sy, u_int hlimit, char **cause)
struct environ *env, u_int sx, u_int sy, u_int hlimit, char **cause)
{
struct window *w;
struct window_pane *wp;
@ -260,7 +260,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, envp, cause) != 0) {
if (window_pane_spawn(wp, cmd, cwd, env, cause) != 0) {
window_destroy(w);
return (NULL);
}
@ -454,13 +454,16 @@ window_pane_destroy(struct window_pane *wp)
int
window_pane_spawn(struct window_pane *wp,
const char *cmd, const char *cwd, const char **envp, char **cause)
const char *cmd, const char *cwd, struct environ *env, char **cause)
{
struct winsize ws;
int mode;
const char **envq, *ptr;
char *argv0;
struct timeval tv;
struct winsize ws;
int mode;
char *argv0, **varp, *var;
ARRAY_DECL(, char *) varlist;
struct environ_entry *envent;
const char *ptr;
struct timeval tv;
u_int i;
if (wp->fd != -1)
close(wp->fd);
@ -493,10 +496,22 @@ window_pane_spawn(struct window_pane *wp,
case 0:
if (chdir(wp->cwd) != 0)
chdir("/");
for (envq = envp; *envq != NULL; envq++) {
if (putenv(xstrdup(*envq)) != 0)
fatal("putenv failed");
ARRAY_INIT(&varlist);
for (varp = environ; *varp != NULL; varp++) {
var = xstrdup(*varp);
var[strcspn(var, "=")] = '\0';
ARRAY_ADD(&varlist, var);
}
for (i = 0; i < ARRAY_LENGTH(&varlist); i++) {
var = ARRAY_ITEM(&varlist, i);
unsetenv(var);
}
RB_FOREACH(envent, environ, env) {
if (envent->value != NULL)
setenv(envent->name, envent->value, 1);
}
sigreset();
log_close();