mirror of
https://github.com/tmate-io/tmate.git
synced 2024-12-23 07:09:10 +01:00
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 sesssion 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:
parent
e985629440
commit
6491274f60
3
Makefile
3
Makefile
@ -25,8 +25,9 @@ SRCS= attributes.c buffer-poll.c buffer.c cfg.c client-fn.c \
|
||||
cmd-split-window.c cmd-start-server.c cmd-string.c cmd-if-shell.c \
|
||||
cmd-suspend-client.c cmd-swap-pane.c cmd-swap-window.c \
|
||||
cmd-switch-client.c cmd-unbind-key.c cmd-unlink-window.c \
|
||||
cmd-set-environment.c cmd-show-environment.c \
|
||||
cmd-up-pane.c cmd-display-message.c cmd.c \
|
||||
colour.c grid-view.c grid.c input-keys.c \
|
||||
colour.c environ.c grid-view.c grid.c input-keys.c \
|
||||
input.c key-bindings.c key-string.c layout-set.c layout.c log.c \
|
||||
mode-key.c names.c options-cmd.c options.c paste.c procname.c \
|
||||
resize.c screen-redraw.c screen-write.c screen.c server-fn.c \
|
||||
|
18
client.c
18
client.c
@ -33,6 +33,7 @@
|
||||
|
||||
#include "tmux.h"
|
||||
|
||||
void client_send_environ(struct client_ctx *);
|
||||
void client_handle_winch(struct client_ctx *);
|
||||
|
||||
int
|
||||
@ -95,6 +96,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)");
|
||||
@ -133,6 +136,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)
|
||||
{
|
||||
@ -242,8 +258,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:
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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
88
cmd-set-environment.c
Normal file
@ -0,0 +1,88 @@
|
||||
/* $OpenBSD$ */
|
||||
|
||||
/*
|
||||
* 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);
|
||||
}
|
@ -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
67
cmd-show-environment.c
Normal file
@ -0,0 +1,67 @@
|
||||
/* $OpenBSD$ */
|
||||
|
||||
/*
|
||||
* 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);
|
||||
}
|
@ -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);
|
||||
|
28
cmd-string.c
28
cmd-string.c
@ -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;
|
||||
|
2
cmd.c
2
cmd.c
@ -84,10 +84,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
147
environ.c
Normal file
@ -0,0 +1,147 @@
|
||||
/* $OpenBSD$ */
|
||||
|
||||
/*
|
||||
* 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);
|
||||
}
|
19
server-fn.c
19
server-fn.c
@ -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];
|
||||
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
|
||||
|
10
server-msg.c
10
server-msg.c
@ -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");
|
||||
}
|
||||
|
22
session.c
22
session.c
@ -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);
|
||||
|
66
tmux.1
66
tmux.1
@ -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
|
||||
|
14
tmux.c
14
tmux.c
@ -44,6 +44,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;
|
||||
@ -262,7 +263,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;
|
||||
@ -320,6 +321,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
|
||||
@ -376,6 +381,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);
|
||||
@ -469,10 +475,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);
|
||||
}
|
||||
|
46
tmux.h
46
tmux.h
@ -39,6 +39,7 @@
|
||||
#include "array.h"
|
||||
|
||||
extern char *__progname;
|
||||
extern char **environ;
|
||||
|
||||
/* Default configuration files. */
|
||||
#define DEFAULT_CFG ".tmux.conf"
|
||||
@ -69,6 +70,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);
|
||||
@ -302,6 +304,7 @@ enum msgtype {
|
||||
MSG_SUSPEND,
|
||||
MSG_UNLOCK,
|
||||
MSG_WAKEUP,
|
||||
MSG_ENVIRON
|
||||
};
|
||||
|
||||
/*
|
||||
@ -356,6 +359,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,
|
||||
@ -765,6 +772,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;
|
||||
@ -792,6 +808,8 @@ struct session {
|
||||
|
||||
#define SESSION_UNATTACHED 0x1 /* not attached to any clients */
|
||||
int flags;
|
||||
|
||||
struct environ environ;
|
||||
};
|
||||
ARRAY_DECL(sessions, struct session *);
|
||||
|
||||
@ -894,6 +912,8 @@ struct client {
|
||||
struct buffer *in;
|
||||
struct buffer *out;
|
||||
|
||||
struct environ environ;
|
||||
|
||||
char *title;
|
||||
char *cwd;
|
||||
|
||||
@ -992,6 +1012,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) \
|
||||
@ -1074,6 +1095,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;
|
||||
@ -1123,6 +1145,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 *);
|
||||
@ -1285,10 +1319,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;
|
||||
@ -1384,7 +1420,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);
|
||||
@ -1554,8 +1590,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);
|
||||
@ -1568,7 +1604,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 *);
|
||||
@ -1648,7 +1684,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 *,
|
||||
|
31
window.c
31
window.c
@ -254,7 +254,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;
|
||||
@ -262,7 +262,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);
|
||||
}
|
||||
@ -456,13 +456,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;
|
||||
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);
|
||||
@ -495,10 +498,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();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user