Add a -D flag to ask tmux not to daemonize, useful both for running a

debugger (lldb does not have follow-fork-mode) and for running with a
managed supervisor init system. GitHub issue 2190.
This commit is contained in:
nicm 2020-05-16 16:07:55 +00:00
parent 126bacb473
commit dceb6a15d0
7 changed files with 73 additions and 25 deletions

9
proc.c
View File

@ -37,6 +37,7 @@ struct tmuxproc {
void (*signalcb)(int);
struct event ev_sigint;
struct event ev_sighup;
struct event ev_sigchld;
struct event ev_sigcont;
@ -221,10 +222,13 @@ proc_set_signals(struct tmuxproc *tp, void (*signalcb)(int))
sa.sa_flags = SA_RESTART;
sa.sa_handler = SIG_IGN;
sigaction(SIGINT, &sa, NULL);
sigaction(SIGPIPE, &sa, NULL);
sigaction(SIGTSTP, &sa, NULL);
sigaction(SIGTTIN, &sa, NULL);
sigaction(SIGTTOU, &sa, NULL);
signal_set(&tp->ev_sigint, SIGINT, proc_signal_cb, tp);
signal_add(&tp->ev_sigint, NULL);
signal_set(&tp->ev_sighup, SIGHUP, proc_signal_cb, tp);
signal_add(&tp->ev_sighup, NULL);
signal_set(&tp->ev_sigchld, SIGCHLD, proc_signal_cb, tp);
@ -251,10 +255,10 @@ proc_clear_signals(struct tmuxproc *tp, int defaults)
sa.sa_flags = SA_RESTART;
sa.sa_handler = SIG_DFL;
sigaction(SIGINT, &sa, NULL);
sigaction(SIGPIPE, &sa, NULL);
sigaction(SIGTSTP, &sa, NULL);
signal_del(&tp->ev_sigint);
signal_del(&tp->ev_sighup);
signal_del(&tp->ev_sigchld);
signal_del(&tp->ev_sigcont);
@ -264,6 +268,7 @@ proc_clear_signals(struct tmuxproc *tp, int defaults)
signal_del(&tp->ev_sigwinch);
if (defaults) {
sigaction(SIGINT, &sa, NULL);
sigaction(SIGHUP, &sa, NULL);
sigaction(SIGCHLD, &sa, NULL);
sigaction(SIGCONT, &sa, NULL);

View File

@ -238,11 +238,22 @@ server_client_create(int fd)
int
server_client_open(struct client *c, char **cause)
{
const char *ttynam = _PATH_TTY;
if (c->flags & CLIENT_CONTROL)
return (0);
if (strcmp(c->ttyname, "/dev/tty") == 0) {
*cause = xstrdup("can't use /dev/tty");
if (strcmp(c->ttyname, ttynam) == 0||
((isatty(STDIN_FILENO) &&
(ttynam = ttyname(STDIN_FILENO)) != NULL &&
strcmp(c->ttyname, ttynam) == 0) ||
(isatty(STDOUT_FILENO) &&
(ttynam = ttyname(STDOUT_FILENO)) != NULL &&
strcmp(c->ttyname, ttynam) == 0) ||
(isatty(STDERR_FILENO) &&
(ttynam = ttyname(STDERR_FILENO)) != NULL &&
strcmp(c->ttyname, ttynam) == 0))) {
xasprintf(cause, "can't use %s", c->ttyname);
return (-1);
}

View File

@ -161,29 +161,35 @@ server_start(struct tmuxproc *client, int flags, struct event_base *base,
struct client *c;
char *cause = NULL;
if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pair) != 0)
fatal("socketpair failed");
server_client_flags = flags;
sigfillset(&set);
sigprocmask(SIG_BLOCK, &set, &oldset);
switch (fork()) {
case -1:
fatal("fork failed");
case 0:
break;
default:
sigprocmask(SIG_SETMASK, &oldset, NULL);
close(pair[1]);
return (pair[0]);
if (~flags & CLIENT_NOFORK) {
if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pair) != 0)
fatal("socketpair failed");
switch (fork()) {
case -1:
fatal("fork failed");
case 0:
break;
default:
sigprocmask(SIG_SETMASK, &oldset, NULL);
close(pair[1]);
return (pair[0]);
}
close(pair[0]);
if (daemon(1, 0) != 0)
fatal("daemon failed");
}
close(pair[0]);
if (daemon(1, 0) != 0)
fatal("daemon failed");
server_client_flags = flags;
proc_clear_signals(client, 0);
if (event_reinit(base) != 0)
fatalx("event_reinit failed");
server_proc = proc_start("server");
proc_set_signals(server_proc, server_signal);
sigprocmask(SIG_SETMASK, &oldset, NULL);
@ -205,7 +211,10 @@ server_start(struct tmuxproc *client, int flags, struct event_base *base,
server_fd = server_create_socket(flags, &cause);
if (server_fd != -1)
server_update_socket();
c = server_client_create(pair[1]);
if (~flags & CLIENT_NOFORK)
c = server_client_create(pair[1]);
else
options_set_number(global_options, "exit-empty", 0);
if (lockfd >= 0) {
unlink(lockfile);
@ -396,6 +405,7 @@ server_signal(int sig)
log_debug("%s: %s", __func__, strsignal(sig));
switch (sig) {
case SIGINT:
case SIGTERM:
server_exit = 1;
server_send_exit();

13
tmux.1
View File

@ -23,7 +23,7 @@
.Sh SYNOPSIS
.Nm tmux
.Bk -words
.Op Fl 2CluvV
.Op Fl 2CDluvV
.Op Fl c Ar shell-command
.Op Fl f Ar file
.Op Fl L Ar socket-name
@ -122,6 +122,17 @@ This option is for compatibility with
when
.Nm
is used as a login shell.
.It Fl D
Do not start the
.Nm
server as a daemon.
This also turns the
.Ic exit-empty
option off.
With
.Fl D ,
.Ar command
may not be specified.
.It Fl f Ar file
Specify an alternative configuration file.
By default,

9
tmux.c
View File

@ -57,7 +57,7 @@ static __dead void
usage(void)
{
fprintf(stderr,
"usage: %s [-2CluvV] [-c shell-command] [-f file] [-L socket-name]\n"
"usage: %s [-2CDluvV] [-c shell-command] [-f file] [-L socket-name]\n"
" [-S socket-path] [-T features] [command [flags]]\n",
getprogname());
exit(1);
@ -336,7 +336,7 @@ main(int argc, char **argv)
if (**argv == '-')
flags = CLIENT_LOGIN;
while ((opt = getopt(argc, argv, "2c:Cdf:lL:qS:T:uUvV")) != -1) {
while ((opt = getopt(argc, argv, "2c:CDdf:lL:qS:T:uUvV")) != -1) {
switch (opt) {
case '2':
tty_add_features(&feat, "256", ":,");
@ -344,6 +344,9 @@ main(int argc, char **argv)
case 'c':
shell_command = optarg;
break;
case 'D':
flags |= CLIENT_NOFORK;
break;
case 'C':
if (flags & CLIENT_CONTROL)
flags |= CLIENT_CONTROLCONTROL;
@ -387,6 +390,8 @@ main(int argc, char **argv)
if (shell_command != NULL && argc != 0)
usage();
if ((flags & CLIENT_NOFORK) && argc != 0)
usage();
if ((ptm_fd = getptmfd()) == -1)
err(1, "getptmfd");

1
tmux.h
View File

@ -1584,6 +1584,7 @@ struct client {
#define CLIENT_DEFAULTSOCKET 0x8000000
#define CLIENT_STARTSERVER 0x10000000
#define CLIENT_REDRAWPANES 0x20000000
#define CLIENT_NOFORK 0x40000000
#define CLIENT_ALLREDRAWFLAGS \
(CLIENT_REDRAWWINDOW| \
CLIENT_REDRAWSTATUS| \

7
tty.c
View File

@ -154,16 +154,21 @@ tty_read_callback(__unused int fd, __unused short events, void *data)
{
struct tty *tty = data;
struct client *c = tty->client;
const char *name = c->name;
size_t size = EVBUFFER_LENGTH(tty->in);
int nread;
nread = evbuffer_read(tty->in, tty->fd, -1);
if (nread == 0 || nread == -1) {
if (nread == 0)
log_debug("%s: read closed", name);
else
log_debug("%s: read error: %s", name, strerror(errno));
event_del(&tty->event_in);
server_client_lost(tty->client);
return;
}
log_debug("%s: read %d bytes (already %zu)", c->name, nread, size);
log_debug("%s: read %d bytes (already %zu)", name, nread, size);
while (tty_keys_next(tty))
;