mirror of
https://github.com/tmux/tmux.git
synced 2024-12-13 01:48:47 +00:00
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:
parent
5fa377d927
commit
d01e7aac89
9
proc.c
9
proc.c
@ -35,6 +35,7 @@ struct tmuxproc {
|
|||||||
|
|
||||||
void (*signalcb)(int);
|
void (*signalcb)(int);
|
||||||
|
|
||||||
|
struct event ev_sigint;
|
||||||
struct event ev_sighup;
|
struct event ev_sighup;
|
||||||
struct event ev_sigchld;
|
struct event ev_sigchld;
|
||||||
struct event ev_sigcont;
|
struct event ev_sigcont;
|
||||||
@ -219,10 +220,13 @@ proc_set_signals(struct tmuxproc *tp, void (*signalcb)(int))
|
|||||||
sa.sa_flags = SA_RESTART;
|
sa.sa_flags = SA_RESTART;
|
||||||
sa.sa_handler = SIG_IGN;
|
sa.sa_handler = SIG_IGN;
|
||||||
|
|
||||||
sigaction(SIGINT, &sa, NULL);
|
|
||||||
sigaction(SIGPIPE, &sa, NULL);
|
sigaction(SIGPIPE, &sa, NULL);
|
||||||
sigaction(SIGTSTP, &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_set(&tp->ev_sighup, SIGHUP, proc_signal_cb, tp);
|
||||||
signal_add(&tp->ev_sighup, NULL);
|
signal_add(&tp->ev_sighup, NULL);
|
||||||
signal_set(&tp->ev_sigchld, SIGCHLD, proc_signal_cb, tp);
|
signal_set(&tp->ev_sigchld, SIGCHLD, proc_signal_cb, tp);
|
||||||
@ -249,10 +253,10 @@ proc_clear_signals(struct tmuxproc *tp, int defaults)
|
|||||||
sa.sa_flags = SA_RESTART;
|
sa.sa_flags = SA_RESTART;
|
||||||
sa.sa_handler = SIG_DFL;
|
sa.sa_handler = SIG_DFL;
|
||||||
|
|
||||||
sigaction(SIGINT, &sa, NULL);
|
|
||||||
sigaction(SIGPIPE, &sa, NULL);
|
sigaction(SIGPIPE, &sa, NULL);
|
||||||
sigaction(SIGTSTP, &sa, NULL);
|
sigaction(SIGTSTP, &sa, NULL);
|
||||||
|
|
||||||
|
signal_del(&tp->ev_sigint);
|
||||||
signal_del(&tp->ev_sighup);
|
signal_del(&tp->ev_sighup);
|
||||||
signal_del(&tp->ev_sigchld);
|
signal_del(&tp->ev_sigchld);
|
||||||
signal_del(&tp->ev_sigcont);
|
signal_del(&tp->ev_sigcont);
|
||||||
@ -262,6 +266,7 @@ proc_clear_signals(struct tmuxproc *tp, int defaults)
|
|||||||
signal_del(&tp->ev_sigwinch);
|
signal_del(&tp->ev_sigwinch);
|
||||||
|
|
||||||
if (defaults) {
|
if (defaults) {
|
||||||
|
sigaction(SIGINT, &sa, NULL);
|
||||||
sigaction(SIGHUP, &sa, NULL);
|
sigaction(SIGHUP, &sa, NULL);
|
||||||
sigaction(SIGCHLD, &sa, NULL);
|
sigaction(SIGCHLD, &sa, NULL);
|
||||||
sigaction(SIGCONT, &sa, NULL);
|
sigaction(SIGCONT, &sa, NULL);
|
||||||
|
@ -236,11 +236,22 @@ server_client_create(int fd)
|
|||||||
int
|
int
|
||||||
server_client_open(struct client *c, char **cause)
|
server_client_open(struct client *c, char **cause)
|
||||||
{
|
{
|
||||||
|
const char *ttynam = _PATH_TTY;
|
||||||
|
|
||||||
if (c->flags & CLIENT_CONTROL)
|
if (c->flags & CLIENT_CONTROL)
|
||||||
return (0);
|
return (0);
|
||||||
|
|
||||||
if (strcmp(c->ttyname, "/dev/tty") == 0) {
|
if (strcmp(c->ttyname, ttynam) ||
|
||||||
*cause = xstrdup("can't use /dev/tty");
|
((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);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
44
server.c
44
server.c
@ -160,29 +160,35 @@ server_start(struct tmuxproc *client, int flags, struct event_base *base,
|
|||||||
struct client *c;
|
struct client *c;
|
||||||
char *cause = NULL;
|
char *cause = NULL;
|
||||||
|
|
||||||
if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pair) != 0)
|
|
||||||
fatal("socketpair failed");
|
|
||||||
server_client_flags = flags;
|
|
||||||
|
|
||||||
sigfillset(&set);
|
sigfillset(&set);
|
||||||
sigprocmask(SIG_BLOCK, &set, &oldset);
|
sigprocmask(SIG_BLOCK, &set, &oldset);
|
||||||
switch (fork()) {
|
|
||||||
case -1:
|
if (~flags & CLIENT_NOFORK) {
|
||||||
fatal("fork failed");
|
if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pair) != 0)
|
||||||
case 0:
|
fatal("socketpair failed");
|
||||||
break;
|
|
||||||
default:
|
switch (fork()) {
|
||||||
sigprocmask(SIG_SETMASK, &oldset, NULL);
|
case -1:
|
||||||
close(pair[1]);
|
fatal("fork failed");
|
||||||
return (pair[0]);
|
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)
|
server_client_flags = flags;
|
||||||
fatal("daemon failed");
|
|
||||||
proc_clear_signals(client, 0);
|
proc_clear_signals(client, 0);
|
||||||
|
|
||||||
if (event_reinit(base) != 0)
|
if (event_reinit(base) != 0)
|
||||||
fatalx("event_reinit failed");
|
fatalx("event_reinit failed");
|
||||||
server_proc = proc_start("server");
|
server_proc = proc_start("server");
|
||||||
|
|
||||||
proc_set_signals(server_proc, server_signal);
|
proc_set_signals(server_proc, server_signal);
|
||||||
sigprocmask(SIG_SETMASK, &oldset, NULL);
|
sigprocmask(SIG_SETMASK, &oldset, NULL);
|
||||||
|
|
||||||
@ -204,7 +210,10 @@ server_start(struct tmuxproc *client, int flags, struct event_base *base,
|
|||||||
server_fd = server_create_socket(flags, &cause);
|
server_fd = server_create_socket(flags, &cause);
|
||||||
if (server_fd != -1)
|
if (server_fd != -1)
|
||||||
server_update_socket();
|
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) {
|
if (lockfd >= 0) {
|
||||||
unlink(lockfile);
|
unlink(lockfile);
|
||||||
@ -395,6 +404,7 @@ server_signal(int sig)
|
|||||||
|
|
||||||
log_debug("%s: %s", __func__, strsignal(sig));
|
log_debug("%s: %s", __func__, strsignal(sig));
|
||||||
switch (sig) {
|
switch (sig) {
|
||||||
|
case SIGINT:
|
||||||
case SIGTERM:
|
case SIGTERM:
|
||||||
server_exit = 1;
|
server_exit = 1;
|
||||||
server_send_exit();
|
server_send_exit();
|
||||||
|
13
tmux.1
13
tmux.1
@ -23,7 +23,7 @@
|
|||||||
.Sh SYNOPSIS
|
.Sh SYNOPSIS
|
||||||
.Nm tmux
|
.Nm tmux
|
||||||
.Bk -words
|
.Bk -words
|
||||||
.Op Fl 2CluvV
|
.Op Fl 2CDluvV
|
||||||
.Op Fl c Ar shell-command
|
.Op Fl c Ar shell-command
|
||||||
.Op Fl f Ar file
|
.Op Fl f Ar file
|
||||||
.Op Fl L Ar socket-name
|
.Op Fl L Ar socket-name
|
||||||
@ -122,6 +122,17 @@ This option is for compatibility with
|
|||||||
when
|
when
|
||||||
.Nm
|
.Nm
|
||||||
is used as a login shell.
|
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
|
.It Fl f Ar file
|
||||||
Specify an alternative configuration file.
|
Specify an alternative configuration file.
|
||||||
By default,
|
By default,
|
||||||
|
9
tmux.c
9
tmux.c
@ -54,7 +54,7 @@ static __dead void
|
|||||||
usage(void)
|
usage(void)
|
||||||
{
|
{
|
||||||
fprintf(stderr,
|
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",
|
" [-S socket-path] [-T features] [command [flags]]\n",
|
||||||
getprogname());
|
getprogname());
|
||||||
exit(1);
|
exit(1);
|
||||||
@ -327,7 +327,7 @@ main(int argc, char **argv)
|
|||||||
if (**argv == '-')
|
if (**argv == '-')
|
||||||
flags = CLIENT_LOGIN;
|
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) {
|
switch (opt) {
|
||||||
case '2':
|
case '2':
|
||||||
tty_add_features(&feat, "256", ":,");
|
tty_add_features(&feat, "256", ":,");
|
||||||
@ -335,6 +335,9 @@ main(int argc, char **argv)
|
|||||||
case 'c':
|
case 'c':
|
||||||
shell_command = optarg;
|
shell_command = optarg;
|
||||||
break;
|
break;
|
||||||
|
case 'D':
|
||||||
|
flags |= CLIENT_NOFORK;
|
||||||
|
break;
|
||||||
case 'C':
|
case 'C':
|
||||||
if (flags & CLIENT_CONTROL)
|
if (flags & CLIENT_CONTROL)
|
||||||
flags |= CLIENT_CONTROLCONTROL;
|
flags |= CLIENT_CONTROLCONTROL;
|
||||||
@ -378,6 +381,8 @@ main(int argc, char **argv)
|
|||||||
|
|
||||||
if (shell_command != NULL && argc != 0)
|
if (shell_command != NULL && argc != 0)
|
||||||
usage();
|
usage();
|
||||||
|
if ((flags & CLIENT_NOFORK) && argc != 0)
|
||||||
|
usage();
|
||||||
|
|
||||||
if ((ptm_fd = getptmfd()) == -1)
|
if ((ptm_fd = getptmfd()) == -1)
|
||||||
err(1, "getptmfd");
|
err(1, "getptmfd");
|
||||||
|
1
tmux.h
1
tmux.h
@ -1586,6 +1586,7 @@ struct client {
|
|||||||
#define CLIENT_DEFAULTSOCKET 0x8000000
|
#define CLIENT_DEFAULTSOCKET 0x8000000
|
||||||
#define CLIENT_STARTSERVER 0x10000000
|
#define CLIENT_STARTSERVER 0x10000000
|
||||||
#define CLIENT_REDRAWPANES 0x20000000
|
#define CLIENT_REDRAWPANES 0x20000000
|
||||||
|
#define CLIENT_NOFORK 0x40000000
|
||||||
#define CLIENT_ALLREDRAWFLAGS \
|
#define CLIENT_ALLREDRAWFLAGS \
|
||||||
(CLIENT_REDRAWWINDOW| \
|
(CLIENT_REDRAWWINDOW| \
|
||||||
CLIENT_REDRAWSTATUS| \
|
CLIENT_REDRAWSTATUS| \
|
||||||
|
7
tty.c
7
tty.c
@ -154,16 +154,21 @@ tty_read_callback(__unused int fd, __unused short events, void *data)
|
|||||||
{
|
{
|
||||||
struct tty *tty = data;
|
struct tty *tty = data;
|
||||||
struct client *c = tty->client;
|
struct client *c = tty->client;
|
||||||
|
const char *name = c->name;
|
||||||
size_t size = EVBUFFER_LENGTH(tty->in);
|
size_t size = EVBUFFER_LENGTH(tty->in);
|
||||||
int nread;
|
int nread;
|
||||||
|
|
||||||
nread = evbuffer_read(tty->in, tty->fd, -1);
|
nread = evbuffer_read(tty->in, tty->fd, -1);
|
||||||
if (nread == 0 || nread == -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);
|
event_del(&tty->event_in);
|
||||||
server_client_lost(tty->client);
|
server_client_lost(tty->client);
|
||||||
return;
|
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))
|
while (tty_keys_next(tty))
|
||||||
;
|
;
|
||||||
|
Loading…
Reference in New Issue
Block a user