GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/tmux/proc.c Lines: 91 140 65.0 %
Date: 2017-11-07 Branches: 22 46 47.8 %

Line Branch Exec Source
1
/* $OpenBSD: proc.c,v 1.15 2017/07/14 18:49:07 nicm Exp $ */
2
3
/*
4
 * Copyright (c) 2015 Nicholas Marriott <nicholas.marriott@gmail.com>
5
 *
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.
9
 *
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.
17
 */
18
19
#include <sys/types.h>
20
#include <sys/queue.h>
21
#include <sys/uio.h>
22
#include <sys/utsname.h>
23
24
#include <errno.h>
25
#include <event.h>
26
#include <imsg.h>
27
#include <signal.h>
28
#include <stdlib.h>
29
#include <string.h>
30
#include <unistd.h>
31
32
#include "tmux.h"
33
34
struct tmuxproc {
35
	const char	 *name;
36
	int		  exit;
37
38
	void		(*signalcb)(int);
39
40
	struct event	  ev_sighup;
41
	struct event	  ev_sigchld;
42
	struct event	  ev_sigcont;
43
	struct event	  ev_sigterm;
44
	struct event	  ev_sigusr1;
45
	struct event	  ev_sigusr2;
46
	struct event	  ev_sigwinch;
47
};
48
49
struct tmuxpeer {
50
	struct tmuxproc	*parent;
51
52
	struct imsgbuf	 ibuf;
53
	struct event	 event;
54
55
	int		 flags;
56
#define PEER_BAD 0x1
57
58
	void		(*dispatchcb)(struct imsg *, void *);
59
	void		 *arg;
60
};
61
62
static int	peer_check_version(struct tmuxpeer *, struct imsg *);
63
static void	proc_update_event(struct tmuxpeer *);
64
65
static void
66
proc_event_cb(__unused int fd, short events, void *arg)
67
{
68
62
	struct tmuxpeer	*peer = arg;
69
	ssize_t		 n;
70
31
	struct imsg	 imsg;
71
72

62
	if (!(peer->flags & PEER_BAD) && (events & EV_READ)) {
73

26
		if (((n = imsg_read(&peer->ibuf)) == -1 && errno != EAGAIN) ||
74
13
		    n == 0) {
75
			peer->dispatchcb(NULL, peer->arg);
76
			return;
77
		}
78
14
		for (;;) {
79
27
			if ((n = imsg_get(&peer->ibuf, &imsg)) == -1) {
80
				peer->dispatchcb(NULL, peer->arg);
81
				return;
82
			}
83
27
			if (n == 0)
84
				break;
85
14
			log_debug("peer %p message %d", peer, imsg.hdr.type);
86
87
14
			if (peer_check_version(peer, &imsg) != 0) {
88
				if (imsg.fd != -1)
89
					close(imsg.fd);
90
				imsg_free(&imsg);
91
				break;
92
			}
93
94
14
			peer->dispatchcb(&imsg, peer->arg);
95
14
			imsg_free(&imsg);
96
		}
97
	}
98
99
31
	if (events & EV_WRITE) {
100

18
		if (msgbuf_write(&peer->ibuf.w) <= 0 && errno != EAGAIN) {
101
			peer->dispatchcb(NULL, peer->arg);
102
			return;
103
		}
104
	}
105
106

31
	if ((peer->flags & PEER_BAD) && peer->ibuf.w.queued == 0) {
107
		peer->dispatchcb(NULL, peer->arg);
108
		return;
109
	}
110
111
31
	proc_update_event(peer);
112
62
}
113
114
static void
115
proc_signal_cb(int signo, __unused short events, void *arg)
116
{
117
4
	struct tmuxproc	*tp = arg;
118
119
2
	tp->signalcb(signo);
120
2
}
121
122
static int
123
peer_check_version(struct tmuxpeer *peer, struct imsg *imsg)
124
{
125
	int	version;
126
127
28
	version = imsg->hdr.peerid & 0xff;
128
14
	if (imsg->hdr.type != MSG_VERSION && version != PROTOCOL_VERSION) {
129
		log_debug("peer %p bad version %d", peer, version);
130
131
		proc_send(peer, MSG_VERSION, -1, NULL, 0);
132
		peer->flags |= PEER_BAD;
133
134
		return (-1);
135
	}
136
14
	return (0);
137
14
}
138
139
static void
140
proc_update_event(struct tmuxpeer *peer)
141
{
142
	short	events;
143
144
290
	event_del(&peer->event);
145
146
	events = EV_READ;
147
145
	if (peer->ibuf.w.queued > 0)
148
122
		events |= EV_WRITE;
149
145
	event_set(&peer->event, peer->ibuf.fd, events, proc_event_cb, peer);
150
151
145
	event_add(&peer->event, NULL);
152
145
}
153
154
int
155
proc_send(struct tmuxpeer *peer, enum msgtype type, int fd, const void *buf,
156
    size_t len)
157
{
158
218
	struct imsgbuf	*ibuf = &peer->ibuf;
159
	void		*vp = (void *)buf;
160
	int		 retval;
161
162
109
	if (peer->flags & PEER_BAD)
163
		return (-1);
164
109
	log_debug("sending message %d to peer %p (%zu bytes)", type, peer, len);
165
166
109
	retval = imsg_compose(ibuf, type, PROTOCOL_VERSION, -1, fd, vp, len);
167
109
	if (retval != 1)
168
		return (-1);
169
109
	proc_update_event(peer);
170
109
	return (0);
171
109
}
172
173
struct tmuxproc *
174
proc_start(const char *name)
175
{
176
	struct tmuxproc	*tp;
177
10
	struct utsname	 u;
178
179
5
	log_open(name);
180
5
	setproctitle("%s (%s)", name, socket_path);
181
182
5
	if (uname(&u) < 0)
183
		memset(&u, 0, sizeof u);
184
185
5
	log_debug("%s started (%ld): socket %s, protocol %d", name,
186
5
	    (long)getpid(), socket_path, PROTOCOL_VERSION);
187
10
	log_debug("on %s %s %s; libevent %s (%s)", u.sysname, u.release,
188
5
	    u.version, event_get_version(), event_get_method());
189
190
5
	tp = xcalloc(1, sizeof *tp);
191
5
	tp->name = xstrdup(name);
192
193
5
	return (tp);
194
5
}
195
196
void
197
proc_loop(struct tmuxproc *tp, int (*loopcb)(void))
198
{
199
10
	log_debug("%s loop enter", tp->name);
200
5
	do
201
33
		event_loop(EVLOOP_ONCE);
202

61
	while (!tp->exit && (loopcb == NULL || !loopcb ()));
203
5
	log_debug("%s loop exit", tp->name);
204
5
}
205
206
void
207
proc_exit(struct tmuxproc *tp)
208
{
209
10
	tp->exit = 1;
210
5
}
211
212
void
213
proc_set_signals(struct tmuxproc *tp, void (*signalcb)(int))
214
{
215
10
	struct sigaction	sa;
216
217
5
	tp->signalcb = signalcb;
218
219
5
	memset(&sa, 0, sizeof sa);
220
5
	sigemptyset(&sa.sa_mask);
221
5
	sa.sa_flags = SA_RESTART;
222
5
	sa.sa_handler = SIG_IGN;
223
224
5
	sigaction(SIGINT, &sa, NULL);
225
5
	sigaction(SIGPIPE, &sa, NULL);
226
5
	sigaction(SIGTSTP, &sa, NULL);
227
228
5
	signal_set(&tp->ev_sighup, SIGHUP, proc_signal_cb, tp);
229
5
	signal_add(&tp->ev_sighup, NULL);
230
5
	signal_set(&tp->ev_sigchld, SIGCHLD, proc_signal_cb, tp);
231
5
	signal_add(&tp->ev_sigchld, NULL);
232
5
	signal_set(&tp->ev_sigcont, SIGCONT, proc_signal_cb, tp);
233
5
	signal_add(&tp->ev_sigcont, NULL);
234
5
	signal_set(&tp->ev_sigterm, SIGTERM, proc_signal_cb, tp);
235
5
	signal_add(&tp->ev_sigterm, NULL);
236
5
	signal_set(&tp->ev_sigusr1, SIGUSR1, proc_signal_cb, tp);
237
5
	signal_add(&tp->ev_sigusr1, NULL);
238
5
	signal_set(&tp->ev_sigusr2, SIGUSR2, proc_signal_cb, tp);
239
5
	signal_add(&tp->ev_sigusr2, NULL);
240
5
	signal_set(&tp->ev_sigwinch, SIGWINCH, proc_signal_cb, tp);
241
5
	signal_add(&tp->ev_sigwinch, NULL);
242
5
}
243
244
void
245
proc_clear_signals(struct tmuxproc *tp, int defaults)
246
{
247
	struct sigaction	sa;
248
249
	memset(&sa, 0, sizeof sa);
250
	sigemptyset(&sa.sa_mask);
251
	sa.sa_flags = SA_RESTART;
252
	sa.sa_handler = SIG_DFL;
253
254
	sigaction(SIGINT, &sa, NULL);
255
	sigaction(SIGPIPE, &sa, NULL);
256
	sigaction(SIGTSTP, &sa, NULL);
257
258
	signal_del(&tp->ev_sighup);
259
	signal_del(&tp->ev_sigchld);
260
	signal_del(&tp->ev_sigcont);
261
	signal_del(&tp->ev_sigterm);
262
	signal_del(&tp->ev_sigusr1);
263
	signal_del(&tp->ev_sigusr2);
264
	signal_del(&tp->ev_sigwinch);
265
266
	if (defaults) {
267
		sigaction(SIGHUP, &sa, NULL);
268
		sigaction(SIGCHLD, &sa, NULL);
269
		sigaction(SIGCONT, &sa, NULL);
270
		sigaction(SIGTERM, &sa, NULL);
271
		sigaction(SIGUSR1, &sa, NULL);
272
		sigaction(SIGUSR2, &sa, NULL);
273
		sigaction(SIGWINCH, &sa, NULL);
274
	}
275
}
276
277
struct tmuxpeer *
278
proc_add_peer(struct tmuxproc *tp, int fd,
279
    void (*dispatchcb)(struct imsg *, void *), void *arg)
280
{
281
	struct tmuxpeer	*peer;
282
283
10
	peer = xcalloc(1, sizeof *peer);
284
5
	peer->parent = tp;
285
286
5
	peer->dispatchcb = dispatchcb;
287
5
	peer->arg = arg;
288
289
5
	imsg_init(&peer->ibuf, fd);
290
5
	event_set(&peer->event, fd, EV_READ, proc_event_cb, peer);
291
292
5
	log_debug("add peer %p: %d (%p)", peer, fd, arg);
293
294
5
	proc_update_event(peer);
295
5
	return (peer);
296
}
297
298
void
299
proc_remove_peer(struct tmuxpeer *peer)
300
{
301
	log_debug("remove peer %p", peer);
302
303
	event_del(&peer->event);
304
	imsg_clear(&peer->ibuf);
305
306
	close(peer->ibuf.fd);
307
	free(peer);
308
}
309
310
void
311
proc_kill_peer(struct tmuxpeer *peer)
312
{
313
	peer->flags |= PEER_BAD;
314
}
315
316
void
317
proc_toggle_log(struct tmuxproc *tp)
318
{
319
	log_toggle(tp->name);
320
}