mirror of
https://github.com/tmate-io/tmate.git
synced 2025-02-16 10:21:37 +01:00
Add foreground mode with -F
This commit is contained in:
parent
7f693a97ae
commit
6e84bab68c
18
cfg.c
18
cfg.c
@ -149,6 +149,20 @@ load_cfg(const char *path, struct cmd_q *cmdq, char **cause)
|
||||
return (found);
|
||||
}
|
||||
|
||||
static void print_cfg_errors(void)
|
||||
{
|
||||
u_int i;
|
||||
|
||||
for (i = 0; i < cfg_ncauses; i++) {
|
||||
tmate_info("%s", cfg_causes[i]);
|
||||
free(cfg_causes[i]);
|
||||
}
|
||||
|
||||
free(cfg_causes);
|
||||
cfg_causes = NULL;
|
||||
cfg_ncauses = 0;
|
||||
}
|
||||
|
||||
void
|
||||
cfg_default_done(__unused struct cmd_q *cmdq)
|
||||
{
|
||||
@ -158,6 +172,10 @@ cfg_default_done(__unused struct cmd_q *cmdq)
|
||||
|
||||
#ifdef TMATE
|
||||
tmate_session_start();
|
||||
if (tmate_foreground && cfg_ncauses) {
|
||||
print_cfg_errors();
|
||||
exit(1);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!RB_EMPTY(&sessions))
|
||||
|
51
client.c
51
client.c
@ -32,6 +32,7 @@
|
||||
#include <unistd.h>
|
||||
|
||||
#include "tmux.h"
|
||||
#include "tmate.h"
|
||||
|
||||
struct tmuxproc *client_proc;
|
||||
struct tmuxpeer *client_peer;
|
||||
@ -213,8 +214,56 @@ client_exit_message(void)
|
||||
#ifdef TMATE
|
||||
extern const struct cmd_entry cmd_attach_session_entry;
|
||||
extern const struct cmd_entry cmd_new_session_entry;
|
||||
|
||||
/* For foreground mode */
|
||||
static int __argc;
|
||||
static char **__argv;
|
||||
#endif
|
||||
|
||||
static void _run_initial_client_cmd(int argc, char **argv)
|
||||
{
|
||||
struct cmd_q *cmd_q;
|
||||
struct cmd_list *cmdlist;
|
||||
char *cause;
|
||||
const char *default_argv[] = {"new-session"};
|
||||
|
||||
if (argc == 0) {
|
||||
argc = 1;
|
||||
argv = (char **)default_argv;
|
||||
}
|
||||
|
||||
cmd_q = cmdq_new(NULL); /* No client */
|
||||
|
||||
if ((cmdlist = cmd_list_parse(argc, (char **)argv, NULL, 0, &cause)) == NULL) {
|
||||
tmate_fatal("%s", cause);
|
||||
}
|
||||
|
||||
cmdq_run(cmd_q, cmdlist, NULL);
|
||||
cmd_list_free(cmdlist);
|
||||
cmdq_free(cmd_q);
|
||||
|
||||
/* error messages land in cfg_causes */
|
||||
extern char **cfg_causes;
|
||||
extern u_int cfg_ncauses;
|
||||
int has_error = !!cfg_ncauses;
|
||||
for (u_int i = 0; i < cfg_ncauses; i++) {
|
||||
tmate_info("%s", cfg_causes[i]);
|
||||
free(cfg_causes[i]);
|
||||
}
|
||||
|
||||
free(cfg_causes);
|
||||
cfg_causes = NULL;
|
||||
cfg_ncauses = 0;
|
||||
|
||||
if (has_error)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void run_initial_client_cmd(void)
|
||||
{
|
||||
_run_initial_client_cmd(__argc, __argv);
|
||||
}
|
||||
|
||||
/* Client main loop. */
|
||||
int
|
||||
client_main(struct event_base *base, int argc, char **argv, int flags,
|
||||
@ -232,6 +281,8 @@ client_main(struct event_base *base, int argc, char **argv, int flags,
|
||||
size_t size;
|
||||
#ifdef TMATE
|
||||
int cant_nest = 0;
|
||||
__argc = argc;
|
||||
__argv = argv;
|
||||
#endif
|
||||
|
||||
/* Ignore SIGCHLD now or daemon() in the server will leave a zombie. */
|
||||
|
@ -131,6 +131,9 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq)
|
||||
if (c == NULL)
|
||||
detached = 1;
|
||||
|
||||
if (tmate_foreground)
|
||||
detached = 1;
|
||||
|
||||
/* Is this client already attached? */
|
||||
already_attached = 0;
|
||||
if (c != NULL && c->session != NULL)
|
||||
|
49
log.c
49
log.c
@ -32,6 +32,11 @@ static int log_level;
|
||||
static void log_event_cb(int, const char *);
|
||||
static void log_vwrite(const char *, va_list);
|
||||
|
||||
static int is_log_stdout(void)
|
||||
{
|
||||
return fileno(log_file) <= 2;
|
||||
}
|
||||
|
||||
/* Log callback for libevent. */
|
||||
static void
|
||||
log_event_cb(__unused int severity, const char *msg)
|
||||
@ -53,6 +58,18 @@ log_get_level(void)
|
||||
return (log_level);
|
||||
}
|
||||
|
||||
void
|
||||
log_open_fp(FILE *f)
|
||||
{
|
||||
if (log_file != NULL && !is_log_stdout())
|
||||
fclose(log_file);
|
||||
|
||||
log_file = f;
|
||||
|
||||
setvbuf(log_file, NULL, _IOLBF, 0);
|
||||
event_set_log_callback(log_event_cb);
|
||||
}
|
||||
|
||||
/* Open logging to file. */
|
||||
void
|
||||
log_open(const char *name)
|
||||
@ -62,24 +79,18 @@ log_open(const char *name)
|
||||
if (log_level == 0)
|
||||
return;
|
||||
|
||||
if (log_file != NULL)
|
||||
fclose(log_file);
|
||||
|
||||
xasprintf(&path, "tmate-%s-%ld.log", name, (long)getpid());
|
||||
log_file = fopen(path, "w");
|
||||
FILE *f = fopen(path, "w");
|
||||
free(path);
|
||||
if (log_file == NULL)
|
||||
return;
|
||||
|
||||
setvbuf(log_file, NULL, _IOLBF, 0);
|
||||
event_set_log_callback(log_event_cb);
|
||||
if (f)
|
||||
log_open_fp(f);
|
||||
}
|
||||
|
||||
/* Close logging. */
|
||||
void
|
||||
log_close(void)
|
||||
{
|
||||
if (log_file != NULL)
|
||||
if (log_file != NULL && !is_log_stdout())
|
||||
fclose(log_file);
|
||||
log_file = NULL;
|
||||
|
||||
@ -102,9 +113,16 @@ log_vwrite(const char *msg, va_list ap)
|
||||
exit(1);
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
if (fprintf(log_file, "%lld.%06d %s\n", (long long)tv.tv_sec,
|
||||
(int)tv.tv_usec, out) == -1)
|
||||
exit(1);
|
||||
|
||||
if (is_log_stdout()) {
|
||||
if (fprintf(log_file, "%s\n", out) == -1)
|
||||
exit(1);
|
||||
} else {
|
||||
if (fprintf(log_file, "%lld.%06d %s\n", (long long)tv.tv_sec,
|
||||
(int)tv.tv_usec, out) == -1)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
fflush(log_file);
|
||||
|
||||
free(out);
|
||||
@ -113,10 +131,13 @@ log_vwrite(const char *msg, va_list ap)
|
||||
|
||||
/* Log a debug message. */
|
||||
void
|
||||
log_debug(const char *msg, ...)
|
||||
log_emit(int level, const char *msg, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
if (log_level < level)
|
||||
return;
|
||||
|
||||
va_start(ap, msg);
|
||||
log_vwrite(msg, ap);
|
||||
va_end(ap);
|
||||
|
10
proc.c
10
proc.c
@ -172,7 +172,7 @@ proc_start(const char *name, struct event_base *base, int forkflag,
|
||||
struct tmuxproc *tp;
|
||||
struct utsname u;
|
||||
|
||||
if (forkflag) {
|
||||
if (forkflag && !tmate_foreground) {
|
||||
switch (fork()) {
|
||||
case -1:
|
||||
fatal("fork failed");
|
||||
@ -189,7 +189,13 @@ proc_start(const char *name, struct event_base *base, int forkflag,
|
||||
fatalx("event_reinit failed");
|
||||
}
|
||||
|
||||
log_open(name);
|
||||
if (tmate_foreground) {
|
||||
if (forkflag)
|
||||
clear_signals(0);
|
||||
log_open_fp(stdout);
|
||||
} else {
|
||||
log_open(name);
|
||||
}
|
||||
|
||||
#ifdef HAVE_SETPROCTITLE
|
||||
setproctitle("%s (%s)", name, socket_path);
|
||||
|
14
server.c
14
server.c
@ -152,14 +152,16 @@ server_start(struct event_base *base, int lockfd, char *lockfile)
|
||||
{
|
||||
int pair[2];
|
||||
|
||||
if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pair) != 0)
|
||||
fatal("socketpair failed");
|
||||
if (!tmate_foreground)
|
||||
if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pair) != 0)
|
||||
fatal("socketpair failed");
|
||||
|
||||
server_proc = proc_start("server", base, 1, server_signal);
|
||||
if (server_proc == NULL) {
|
||||
close(pair[1]);
|
||||
return (pair[0]);
|
||||
}
|
||||
|
||||
close(pair[0]);
|
||||
|
||||
if (log_get_level() > 3)
|
||||
@ -190,7 +192,8 @@ server_start(struct event_base *base, int lockfd, char *lockfile)
|
||||
if (server_fd == -1)
|
||||
fatal("couldn't create socket");
|
||||
server_update_socket();
|
||||
server_client_create(pair[1]);
|
||||
if (!tmate_foreground)
|
||||
server_client_create(pair[1]);
|
||||
|
||||
if (lockfd >= 0) {
|
||||
unlink(lockfile);
|
||||
@ -207,11 +210,15 @@ server_start(struct event_base *base, int lockfd, char *lockfile)
|
||||
|
||||
server_add_accept(0);
|
||||
|
||||
if (tmate_foreground)
|
||||
run_initial_client_cmd();
|
||||
|
||||
proc_loop(server_proc, server_loop);
|
||||
status_prompt_save_history();
|
||||
#ifdef TMATE
|
||||
unlink(socket_path);
|
||||
#endif
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
@ -361,6 +368,7 @@ server_signal(int sig)
|
||||
int fd;
|
||||
|
||||
switch (sig) {
|
||||
case SIGINT:
|
||||
case SIGTERM:
|
||||
server_exit = 1;
|
||||
server_send_exit();
|
||||
|
21
session.c
21
session.c
@ -215,10 +215,6 @@ session_destroy(struct session *s)
|
||||
|
||||
log_debug("session %s destroyed", s->name);
|
||||
|
||||
#ifdef TMATE
|
||||
tmate_write_fin();
|
||||
#endif
|
||||
|
||||
RB_REMOVE(sessions, &sessions, s);
|
||||
notify_session_closed(s);
|
||||
|
||||
@ -240,6 +236,23 @@ session_destroy(struct session *s)
|
||||
free((void *)s->cwd);
|
||||
|
||||
session_unref(s);
|
||||
|
||||
#ifdef TMATE
|
||||
if (tmate_foreground && !server_exit) {
|
||||
tmate_info("Shell exited, restarting");
|
||||
/*
|
||||
* throttle restarts. This is a blocking sleep.
|
||||
* It's simpler than using a timer, but fairly harmless
|
||||
* from a blocking perspective.
|
||||
*/
|
||||
usleep(500*1000);
|
||||
next_session_id = 0;
|
||||
run_initial_client_cmd();
|
||||
} else {
|
||||
tmate_info("Session terminated");
|
||||
tmate_write_fin();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Check a session name is valid: not empty and no colons or periods. */
|
||||
|
18
signal.c
18
signal.c
@ -24,6 +24,7 @@
|
||||
|
||||
#include "tmux.h"
|
||||
|
||||
struct event ev_sigint;
|
||||
struct event ev_sighup;
|
||||
struct event ev_sigchld;
|
||||
struct event ev_sigcont;
|
||||
@ -40,15 +41,23 @@ set_signals(void (*handler)(int, short, void *), void *arg)
|
||||
sigemptyset(&sigact.sa_mask);
|
||||
sigact.sa_flags = SA_RESTART;
|
||||
sigact.sa_handler = SIG_IGN;
|
||||
#ifndef TMATE
|
||||
if (sigaction(SIGINT, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
#endif
|
||||
if (sigaction(SIGPIPE, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
if (sigaction(SIGUSR2, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
#ifndef TMATE
|
||||
if (sigaction(SIGTSTP, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
#endif
|
||||
|
||||
#ifdef TMATE
|
||||
signal_set(&ev_sigint, SIGINT, handler, arg);
|
||||
signal_add(&ev_sigint, NULL);
|
||||
#endif
|
||||
signal_set(&ev_sighup, SIGHUP, handler, arg);
|
||||
signal_add(&ev_sighup, NULL);
|
||||
signal_set(&ev_sigchld, SIGCHLD, handler, arg);
|
||||
@ -72,16 +81,24 @@ clear_signals(int after_fork)
|
||||
sigemptyset(&sigact.sa_mask);
|
||||
sigact.sa_flags = SA_RESTART;
|
||||
sigact.sa_handler = SIG_DFL;
|
||||
#ifndef TMATE
|
||||
if (sigaction(SIGINT, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
#endif
|
||||
if (sigaction(SIGPIPE, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
if (sigaction(SIGUSR2, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
#ifndef TMATE
|
||||
if (sigaction(SIGTSTP, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
#endif
|
||||
|
||||
if (after_fork) {
|
||||
#ifdef TMATE
|
||||
if (sigaction(SIGINT, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
#endif
|
||||
if (sigaction(SIGHUP, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
if (sigaction(SIGCHLD, &sigact, NULL) != 0)
|
||||
@ -95,6 +112,7 @@ clear_signals(int after_fork)
|
||||
if (sigaction(SIGWINCH, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
} else {
|
||||
event_del(&ev_sigint);
|
||||
event_del(&ev_sighup);
|
||||
event_del(&ev_sigchld);
|
||||
event_del(&ev_sigcont);
|
||||
|
@ -56,7 +56,7 @@ void __tmate_status_message(const char *fmt, va_list ap)
|
||||
char *message;
|
||||
|
||||
xvasprintf(&message, fmt, ap);
|
||||
tmate_debug("%s", message);
|
||||
tmate_info("%s", message);
|
||||
|
||||
TAILQ_FOREACH(c, &clients, entry) {
|
||||
if (c && !(c->flags & CLIENT_READONLY))
|
||||
|
@ -96,7 +96,7 @@ static void lookup_and_connect(void)
|
||||
|
||||
tmate_server_host = options_get_string(global_options,
|
||||
"tmate-server-host");
|
||||
tmate_info("Looking up %s...", tmate_server_host);
|
||||
tmate_debug("Looking up %s...", tmate_server_host);
|
||||
(void)evdns_getaddrinfo(tmate_session.ev_dnsbase, tmate_server_host, NULL,
|
||||
&hints, dns_cb, (void *)tmate_server_host);
|
||||
}
|
||||
|
@ -171,12 +171,12 @@ static void request_passphrase(struct tmate_ssh_client *client)
|
||||
#define KEEPALIVE_IDLE 20
|
||||
#define KEEPALIVE_INTVL 10
|
||||
|
||||
static void setup_socket(int fd)
|
||||
static void tune_socket_opts(int fd)
|
||||
{
|
||||
#define SSO(level, optname, val) ({ \
|
||||
int _flag = val; \
|
||||
if (setsockopt(fd, level, optname, &(_flag), sizeof(int)) < 0) { \
|
||||
tmate_warn("setsockopt(" #level ", " #optname ", %d) failed", val); \
|
||||
tmate_debug("setsockopt(" #level ", " #optname ", %d) failed", val); \
|
||||
} \
|
||||
})
|
||||
|
||||
@ -197,7 +197,7 @@ static void setup_socket(int fd)
|
||||
#undef SSO
|
||||
}
|
||||
|
||||
static void init_conn_fd(struct tmate_ssh_client *client)
|
||||
static void init_conn_fd(struct tmate_ssh_client *client, bool tune_socket)
|
||||
{
|
||||
int fd;
|
||||
|
||||
@ -207,7 +207,9 @@ static void init_conn_fd(struct tmate_ssh_client *client)
|
||||
if ((fd = ssh_get_fd(client->session)) < 0)
|
||||
return;
|
||||
|
||||
setup_socket(fd);
|
||||
if (tune_socket)
|
||||
tune_socket_opts(fd);
|
||||
|
||||
event_set(&client->ev_ssh, fd, EV_READ | EV_PERSIST, __on_ssh_client_event, client);
|
||||
event_add(&client->ev_ssh, NULL);
|
||||
|
||||
@ -267,14 +269,14 @@ static void on_ssh_client_event(struct tmate_ssh_client *client)
|
||||
case SSH_CONNECT:
|
||||
switch (ssh_connect(session)) {
|
||||
case SSH_AGAIN:
|
||||
init_conn_fd(client);
|
||||
init_conn_fd(client, false);
|
||||
return;
|
||||
case SSH_ERROR:
|
||||
kill_ssh_client(client, "Error connecting: %s",
|
||||
ssh_get_error(session));
|
||||
return;
|
||||
case SSH_OK:
|
||||
init_conn_fd(client);
|
||||
init_conn_fd(client, true);
|
||||
|
||||
tmate_debug("Establishing connection to %s", client->server_ip);
|
||||
client->state = SSH_AUTH_SERVER;
|
||||
|
7
tmate.h
7
tmate.h
@ -9,10 +9,9 @@
|
||||
|
||||
#include "tmux.h"
|
||||
|
||||
#define tmate_debug(...) log_debug("[tmate] D " __VA_ARGS__)
|
||||
#define tmate_warn(...) log_debug("[tmate] W " __VA_ARGS__)
|
||||
#define tmate_info(...) log_debug("[tmate] I " __VA_ARGS__)
|
||||
#define tmate_fatal(...) fatalx("[tmate] " __VA_ARGS__)
|
||||
#define tmate_debug(...) log_emit(LOG_DEBUG, __VA_ARGS__)
|
||||
#define tmate_info(...) log_emit(LOG_INFO, __VA_ARGS__)
|
||||
#define tmate_fatal(...) fatalx( __VA_ARGS__)
|
||||
|
||||
/* tmate-msgpack.c */
|
||||
|
||||
|
13
tmux.c
13
tmux.c
@ -48,7 +48,11 @@ __dead void usage(void);
|
||||
static char *make_label(const char *);
|
||||
|
||||
#ifndef HAVE___PROGNAME
|
||||
char *__progname = (char *) "tmux";
|
||||
char *__progname = (char *) "tmate";
|
||||
#endif
|
||||
|
||||
#ifdef TMATE
|
||||
int tmate_foreground;
|
||||
#endif
|
||||
|
||||
__dead void
|
||||
@ -228,7 +232,7 @@ main(int argc, char **argv)
|
||||
#endif
|
||||
|
||||
label = path = NULL;
|
||||
while ((opt = getopt(argc, argv, "2c:Cdf:lL:qS:uUVv")) != -1) {
|
||||
while ((opt = getopt(argc, argv, "2c:CdFf:lL:qS:uUVv")) != -1) {
|
||||
switch (opt) {
|
||||
case '2':
|
||||
flags |= CLIENT_256COLOURS;
|
||||
@ -268,6 +272,11 @@ main(int argc, char **argv)
|
||||
case 'v':
|
||||
log_add_level();
|
||||
break;
|
||||
case 'F':
|
||||
tmate_foreground = 1;
|
||||
log_add_level();
|
||||
unsetenv("TMUX");
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
|
12
tmux.h
12
tmux.h
@ -1549,6 +1549,9 @@ extern struct options *global_w_options;
|
||||
extern struct environ *global_environ;
|
||||
extern struct timeval start_time;
|
||||
extern const char *socket_path;
|
||||
#ifdef TMATE
|
||||
extern int tmate_foreground;
|
||||
#endif
|
||||
const char *getshell(void);
|
||||
int checkshell(const char *);
|
||||
int areshell(const char *);
|
||||
@ -1875,6 +1878,7 @@ void signal_waiting_clients(const char *name);
|
||||
void cmd_wait_for_flush(void);
|
||||
|
||||
/* client.c */
|
||||
void run_initial_client_cmd(void);
|
||||
int client_main(struct event_base *, int, char **, int, const char *);
|
||||
|
||||
/* key-bindings.c */
|
||||
@ -1902,6 +1906,7 @@ void alerts_queue(struct window *, int);
|
||||
void alerts_check_session(struct session *);
|
||||
|
||||
/* server.c */
|
||||
extern int server_exit;
|
||||
extern struct tmuxproc *server_proc;
|
||||
extern struct clients clients;
|
||||
extern struct cmd_find_state marked_pane;
|
||||
@ -2356,9 +2361,14 @@ struct event_base *osdep_event_init(void);
|
||||
/* log.c */
|
||||
void log_add_level(void);
|
||||
int log_get_level(void);
|
||||
void log_open_fp(FILE *f);
|
||||
void log_open(const char *);
|
||||
void log_close(void);
|
||||
void printflike(1, 2) log_debug(const char *, ...);
|
||||
#define LOG_ERROR 0
|
||||
#define LOG_INFO 1
|
||||
#define LOG_DEBUG 2
|
||||
#define log_debug(...) log_emit(LOG_DEBUG+1, __VA_ARGS__)
|
||||
void printflike(2, 3) log_emit(int level, const char *, ...);
|
||||
__dead void printflike(1, 2) fatal(const char *, ...);
|
||||
__dead void printflike(1, 2) fatalx(const char *, ...);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user