GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/tmux/proc.c Lines: 0 92 0.0 %
Date: 2016-12-06 Branches: 0 53 0.0 %

Line Branch Exec Source
1
/* $OpenBSD: proc.c,v 1.8 2016/01/19 15:59:12 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 <stdlib.h>
28
#include <string.h>
29
#include <unistd.h>
30
31
#include "tmux.h"
32
33
struct tmuxproc {
34
	const char	 *name;
35
	int		  exit;
36
37
	void		(*signalcb)(int);
38
};
39
40
struct tmuxpeer {
41
	struct tmuxproc	*parent;
42
43
	struct imsgbuf	 ibuf;
44
	struct event	 event;
45
46
	int		 flags;
47
#define PEER_BAD 0x1
48
49
	void		(*dispatchcb)(struct imsg *, void *);
50
	void		*arg;
51
};
52
53
static int	peer_check_version(struct tmuxpeer *, struct imsg *);
54
static void	proc_update_event(struct tmuxpeer *);
55
56
static void
57
proc_event_cb(__unused int fd, short events, void *arg)
58
{
59
	struct tmuxpeer	*peer = arg;
60
	ssize_t		 n;
61
	struct imsg	 imsg;
62
63
	if (!(peer->flags & PEER_BAD) && (events & EV_READ)) {
64
		if (((n = imsg_read(&peer->ibuf)) == -1 && errno != EAGAIN) ||
65
		    n == 0) {
66
			peer->dispatchcb(NULL, peer->arg);
67
			return;
68
		}
69
		for (;;) {
70
			if ((n = imsg_get(&peer->ibuf, &imsg)) == -1) {
71
				peer->dispatchcb(NULL, peer->arg);
72
				return;
73
			}
74
			if (n == 0)
75
				break;
76
			log_debug("peer %p message %d", peer, imsg.hdr.type);
77
78
			if (peer_check_version(peer, &imsg) != 0) {
79
				if (imsg.fd != -1)
80
					close(imsg.fd);
81
				imsg_free(&imsg);
82
				break;
83
			}
84
85
			peer->dispatchcb(&imsg, peer->arg);
86
			imsg_free(&imsg);
87
		}
88
	}
89
90
	if (events & EV_WRITE) {
91
		if (msgbuf_write(&peer->ibuf.w) <= 0 && errno != EAGAIN) {
92
			peer->dispatchcb(NULL, peer->arg);
93
			return;
94
		}
95
	}
96
97
	if ((peer->flags & PEER_BAD) && peer->ibuf.w.queued == 0) {
98
		peer->dispatchcb(NULL, peer->arg);
99
		return;
100
	}
101
102
	proc_update_event(peer);
103
}
104
105
static void
106
proc_signal_cb(int signo, __unused short events, void *arg)
107
{
108
	struct tmuxproc	*tp = arg;
109
110
	tp->signalcb(signo);
111
}
112
113
static int
114
peer_check_version(struct tmuxpeer *peer, struct imsg *imsg)
115
{
116
	int	version;
117
118
	version = imsg->hdr.peerid & 0xff;
119
	if (imsg->hdr.type != MSG_VERSION && version != PROTOCOL_VERSION) {
120
		log_debug("peer %p bad version %d", peer, version);
121
122
		proc_send(peer, MSG_VERSION, -1, NULL, 0);
123
		peer->flags |= PEER_BAD;
124
125
		return (-1);
126
	}
127
	return (0);
128
}
129
130
static void
131
proc_update_event(struct tmuxpeer *peer)
132
{
133
	short	events;
134
135
	event_del(&peer->event);
136
137
	events = EV_READ;
138
	if (peer->ibuf.w.queued > 0)
139
		events |= EV_WRITE;
140
	event_set(&peer->event, peer->ibuf.fd, events, proc_event_cb, peer);
141
142
	event_add(&peer->event, NULL);
143
}
144
145
int
146
proc_send(struct tmuxpeer *peer, enum msgtype type, int fd, const void *buf,
147
    size_t len)
148
{
149
	struct imsgbuf	*ibuf = &peer->ibuf;
150
	void		*vp = (void *)buf;
151
	int		 retval;
152
153
	if (peer->flags & PEER_BAD)
154
		return (-1);
155
	log_debug("sending message %d to peer %p (%zu bytes)", type, peer, len);
156
157
	retval = imsg_compose(ibuf, type, PROTOCOL_VERSION, -1, fd, vp, len);
158
	if (retval != 1)
159
		return (-1);
160
	proc_update_event(peer);
161
	return (0);
162
}
163
164
int
165
proc_send_s(struct tmuxpeer *peer, enum msgtype type, const char *s)
166
{
167
	return (proc_send(peer, type, -1, s, strlen(s) + 1));
168
}
169
170
struct tmuxproc *
171
proc_start(const char *name, struct event_base *base, int forkflag,
172
    void (*signalcb)(int))
173
{
174
	struct tmuxproc	*tp;
175
	struct utsname	 u;
176
177
	if (forkflag) {
178
		switch (fork()) {
179
		case -1:
180
			fatal("fork failed");
181
		case 0:
182
			break;
183
		default:
184
			return (NULL);
185
		}
186
		if (daemon(1, 0) != 0)
187
			fatal("daemon failed");
188
189
		clear_signals(0);
190
		if (event_reinit(base) != 0)
191
			fatalx("event_reinit failed");
192
	}
193
194
	log_open(name);
195
	setproctitle("%s (%s)", name, socket_path);
196
197
	if (uname(&u) < 0)
198
		memset(&u, 0, sizeof u);
199
200
	log_debug("%s started (%ld): socket %s, protocol %d", name,
201
	    (long)getpid(), socket_path, PROTOCOL_VERSION);
202
	log_debug("on %s %s %s; libevent %s (%s)", u.sysname, u.release,
203
	    u.version, event_get_version(), event_get_method());
204
205
	tp = xcalloc(1, sizeof *tp);
206
	tp->name = xstrdup(name);
207
208
	tp->signalcb = signalcb;
209
	set_signals(proc_signal_cb, tp);
210
211
	return (tp);
212
}
213
214
void
215
proc_loop(struct tmuxproc *tp, int (*loopcb)(void))
216
{
217
	log_debug("%s loop enter", tp->name);
218
	do
219
		event_loop(EVLOOP_ONCE);
220
	while (!tp->exit && (loopcb == NULL || !loopcb ()));
221
	log_debug("%s loop exit", tp->name);
222
}
223
224
void
225
proc_exit(struct tmuxproc *tp)
226
{
227
	tp->exit = 1;
228
}
229
230
struct tmuxpeer *
231
proc_add_peer(struct tmuxproc *tp, int fd,
232
    void (*dispatchcb)(struct imsg *, void *), void *arg)
233
{
234
	struct tmuxpeer	*peer;
235
236
	peer = xcalloc(1, sizeof *peer);
237
	peer->parent = tp;
238
239
	peer->dispatchcb = dispatchcb;
240
	peer->arg = arg;
241
242
	imsg_init(&peer->ibuf, fd);
243
	event_set(&peer->event, fd, EV_READ, proc_event_cb, peer);
244
245
	log_debug("add peer %p: %d (%p)", peer, fd, arg);
246
247
	proc_update_event(peer);
248
	return (peer);
249
}
250
251
void
252
proc_remove_peer(struct tmuxpeer *peer)
253
{
254
	log_debug("remove peer %p", peer);
255
256
	event_del(&peer->event);
257
	imsg_clear(&peer->ibuf);
258
259
	close(peer->ibuf.fd);
260
	free(peer);
261
}
262
263
void
264
proc_kill_peer(struct tmuxpeer *peer)
265
{
266
	peer->flags |= PEER_BAD;
267
}