Add foreground mode with -F

This commit is contained in:
Nicolas Viennot 2019-11-03 05:11:37 -05:00
parent 7f693a97ae
commit 6e84bab68c
14 changed files with 196 additions and 38 deletions

18
cfg.c
View File

@ -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))

View File

@ -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. */

View File

@ -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
View File

@ -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
View File

@ -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);

View File

@ -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();

View File

@ -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. */

View File

@ -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);

View File

@ -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))

View File

@ -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);
}

View File

@ -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;

View File

@ -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
View File

@ -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
View File

@ -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 *, ...);