4 * Copyright (c) 2015 Nicholas Marriott <nicholas.marriott@gmail.com>
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 #include <sys/types.h>
20 #include <sys/socket.h>
22 #include <sys/utsname.h>
30 #if defined(HAVE_NCURSES_H)
40 void (*signalcb
)(int);
42 struct event ev_sigint
;
43 struct event ev_sighup
;
44 struct event ev_sigchld
;
45 struct event ev_sigcont
;
46 struct event ev_sigterm
;
47 struct event ev_sigusr1
;
48 struct event ev_sigusr2
;
49 struct event ev_sigwinch
;
51 TAILQ_HEAD(, tmuxpeer
) peers
;
55 struct tmuxproc
*parent
;
64 void (*dispatchcb
)(struct imsg
*, void *);
67 TAILQ_ENTRY(tmuxpeer
) entry
;
70 static int peer_check_version(struct tmuxpeer
*, struct imsg
*);
71 static void proc_update_event(struct tmuxpeer
*);
74 proc_event_cb(__unused
int fd
, short events
, void *arg
)
76 struct tmuxpeer
*peer
= arg
;
80 if (!(peer
->flags
& PEER_BAD
) && (events
& EV_READ
)) {
81 if (imsgbuf_read(&peer
->ibuf
) != 1) {
82 peer
->dispatchcb(NULL
, peer
->arg
);
86 if ((n
= imsg_get(&peer
->ibuf
, &imsg
)) == -1) {
87 peer
->dispatchcb(NULL
, peer
->arg
);
92 log_debug("peer %p message %d", peer
, imsg
.hdr
.type
);
94 if (peer_check_version(peer
, &imsg
) != 0) {
99 peer
->dispatchcb(&imsg
, peer
->arg
);
104 if (events
& EV_WRITE
) {
105 if (imsgbuf_write(&peer
->ibuf
) == -1) {
106 peer
->dispatchcb(NULL
, peer
->arg
);
111 if ((peer
->flags
& PEER_BAD
) && imsgbuf_queuelen(&peer
->ibuf
) == 0) {
112 peer
->dispatchcb(NULL
, peer
->arg
);
116 proc_update_event(peer
);
120 proc_signal_cb(int signo
, __unused
short events
, void *arg
)
122 struct tmuxproc
*tp
= arg
;
128 peer_check_version(struct tmuxpeer
*peer
, struct imsg
*imsg
)
132 version
= imsg
->hdr
.peerid
& 0xff;
133 if (imsg
->hdr
.type
!= MSG_VERSION
&& version
!= PROTOCOL_VERSION
) {
134 log_debug("peer %p bad version %d", peer
, version
);
136 proc_send(peer
, MSG_VERSION
, -1, NULL
, 0);
137 peer
->flags
|= PEER_BAD
;
145 proc_update_event(struct tmuxpeer
*peer
)
149 event_del(&peer
->event
);
152 if (imsgbuf_queuelen(&peer
->ibuf
) > 0)
154 event_set(&peer
->event
, peer
->ibuf
.fd
, events
, proc_event_cb
, peer
);
156 event_add(&peer
->event
, NULL
);
160 proc_send(struct tmuxpeer
*peer
, enum msgtype type
, int fd
, const void *buf
,
163 struct imsgbuf
*ibuf
= &peer
->ibuf
;
164 void *vp
= (void *)buf
;
167 if (peer
->flags
& PEER_BAD
)
169 log_debug("sending message %d to peer %p (%zu bytes)", type
, peer
, len
);
171 retval
= imsg_compose(ibuf
, type
, PROTOCOL_VERSION
, -1, fd
, vp
, len
);
174 proc_update_event(peer
);
179 proc_start(const char *name
)
185 setproctitle("%s (%s)", name
, socket_path
);
188 memset(&u
, 0, sizeof u
);
190 log_debug("%s started (%ld): version %s, socket %s, protocol %d", name
,
191 (long)getpid(), getversion(), socket_path
, PROTOCOL_VERSION
);
192 log_debug("on %s %s %s", u
.sysname
, u
.release
, u
.version
);
193 log_debug("using libevent %s %s", event_get_version(), event_get_method());
195 log_debug("using utf8proc %s", utf8proc_version());
197 #ifdef NCURSES_VERSION
198 log_debug("using ncurses %s %06u", NCURSES_VERSION
, NCURSES_VERSION_PATCH
);
201 tp
= xcalloc(1, sizeof *tp
);
202 tp
->name
= xstrdup(name
);
203 TAILQ_INIT(&tp
->peers
);
209 proc_loop(struct tmuxproc
*tp
, int (*loopcb
)(void))
211 log_debug("%s loop enter", tp
->name
);
213 event_loop(EVLOOP_ONCE
);
214 while (!tp
->exit
&& (loopcb
== NULL
|| !loopcb ()));
215 log_debug("%s loop exit", tp
->name
);
219 proc_exit(struct tmuxproc
*tp
)
221 struct tmuxpeer
*peer
;
223 TAILQ_FOREACH(peer
, &tp
->peers
, entry
)
224 imsgbuf_flush(&peer
->ibuf
);
229 proc_set_signals(struct tmuxproc
*tp
, void (*signalcb
)(int))
233 tp
->signalcb
= signalcb
;
235 memset(&sa
, 0, sizeof sa
);
236 sigemptyset(&sa
.sa_mask
);
237 sa
.sa_flags
= SA_RESTART
;
238 sa
.sa_handler
= SIG_IGN
;
240 sigaction(SIGPIPE
, &sa
, NULL
);
241 sigaction(SIGTSTP
, &sa
, NULL
);
242 sigaction(SIGTTIN
, &sa
, NULL
);
243 sigaction(SIGTTOU
, &sa
, NULL
);
244 sigaction(SIGQUIT
, &sa
, NULL
);
246 signal_set(&tp
->ev_sigint
, SIGINT
, proc_signal_cb
, tp
);
247 signal_add(&tp
->ev_sigint
, NULL
);
248 signal_set(&tp
->ev_sighup
, SIGHUP
, proc_signal_cb
, tp
);
249 signal_add(&tp
->ev_sighup
, NULL
);
250 signal_set(&tp
->ev_sigchld
, SIGCHLD
, proc_signal_cb
, tp
);
251 signal_add(&tp
->ev_sigchld
, NULL
);
252 signal_set(&tp
->ev_sigcont
, SIGCONT
, proc_signal_cb
, tp
);
253 signal_add(&tp
->ev_sigcont
, NULL
);
254 signal_set(&tp
->ev_sigterm
, SIGTERM
, proc_signal_cb
, tp
);
255 signal_add(&tp
->ev_sigterm
, NULL
);
256 signal_set(&tp
->ev_sigusr1
, SIGUSR1
, proc_signal_cb
, tp
);
257 signal_add(&tp
->ev_sigusr1
, NULL
);
258 signal_set(&tp
->ev_sigusr2
, SIGUSR2
, proc_signal_cb
, tp
);
259 signal_add(&tp
->ev_sigusr2
, NULL
);
260 signal_set(&tp
->ev_sigwinch
, SIGWINCH
, proc_signal_cb
, tp
);
261 signal_add(&tp
->ev_sigwinch
, NULL
);
265 proc_clear_signals(struct tmuxproc
*tp
, int defaults
)
269 memset(&sa
, 0, sizeof sa
);
270 sigemptyset(&sa
.sa_mask
);
271 sa
.sa_flags
= SA_RESTART
;
272 sa
.sa_handler
= SIG_DFL
;
274 sigaction(SIGPIPE
, &sa
, NULL
);
275 sigaction(SIGTSTP
, &sa
, NULL
);
277 signal_del(&tp
->ev_sigint
);
278 signal_del(&tp
->ev_sighup
);
279 signal_del(&tp
->ev_sigchld
);
280 signal_del(&tp
->ev_sigcont
);
281 signal_del(&tp
->ev_sigterm
);
282 signal_del(&tp
->ev_sigusr1
);
283 signal_del(&tp
->ev_sigusr2
);
284 signal_del(&tp
->ev_sigwinch
);
287 sigaction(SIGINT
, &sa
, NULL
);
288 sigaction(SIGQUIT
, &sa
, NULL
);
289 sigaction(SIGHUP
, &sa
, NULL
);
290 sigaction(SIGCHLD
, &sa
, NULL
);
291 sigaction(SIGCONT
, &sa
, NULL
);
292 sigaction(SIGTERM
, &sa
, NULL
);
293 sigaction(SIGUSR1
, &sa
, NULL
);
294 sigaction(SIGUSR2
, &sa
, NULL
);
295 sigaction(SIGWINCH
, &sa
, NULL
);
300 proc_add_peer(struct tmuxproc
*tp
, int fd
,
301 void (*dispatchcb
)(struct imsg
*, void *), void *arg
)
303 struct tmuxpeer
*peer
;
306 peer
= xcalloc(1, sizeof *peer
);
309 peer
->dispatchcb
= dispatchcb
;
312 if (imsgbuf_init(&peer
->ibuf
, fd
) == -1)
313 fatal("imsgbuf_init");
314 imsgbuf_allow_fdpass(&peer
->ibuf
);
315 event_set(&peer
->event
, fd
, EV_READ
, proc_event_cb
, peer
);
317 if (getpeereid(fd
, &peer
->uid
, &gid
) != 0)
318 peer
->uid
= (uid_t
)-1;
320 log_debug("add peer %p: %d (%p)", peer
, fd
, arg
);
321 TAILQ_INSERT_TAIL(&tp
->peers
, peer
, entry
);
323 proc_update_event(peer
);
328 proc_remove_peer(struct tmuxpeer
*peer
)
330 TAILQ_REMOVE(&peer
->parent
->peers
, peer
, entry
);
331 log_debug("remove peer %p", peer
);
333 event_del(&peer
->event
);
334 imsgbuf_clear(&peer
->ibuf
);
336 close(peer
->ibuf
.fd
);
341 proc_kill_peer(struct tmuxpeer
*peer
)
343 peer
->flags
|= PEER_BAD
;
347 proc_flush_peer(struct tmuxpeer
*peer
)
349 imsgbuf_flush(&peer
->ibuf
);
353 proc_toggle_log(struct tmuxproc
*tp
)
355 log_toggle(tp
->name
);
359 proc_fork_and_daemon(int *fd
)
364 if (socketpair(AF_UNIX
, SOCK_STREAM
, PF_UNSPEC
, pair
) != 0)
365 fatal("socketpair failed");
366 switch (pid
= fork()) {
368 fatal("fork failed");
372 if (daemon(1, 0) != 0)
373 fatal("daemon failed");
383 proc_get_peer_uid(struct tmuxpeer
*peer
)