1/*
2 * Copyright (c) 2016 Proofpoint, Inc. and its suppliers.
3 *	All rights reserved.
4 *
5 * By using this file, you agree to the terms and conditions set
6 * forth in the LICENSE file which can be found at the top level of
7 * the sendmail distribution.
8 *
9 */
10
11#include <sm/gen.h>
12
13#include <sys/types.h>
14#include <signal.h>
15#include <stdio.h>
16#include <stdlib.h>
17#include <unistd.h>
18#include <stdbool.h>
19#include <errno.h>
20#include <fcntl.h>
21#include <string.h>	/* for memset() */
22
23#include <sm/conf.h>	/* FDSET_CAST */
24#include <sm/fdset.h>
25#include <sm/assert.h>
26#include <sm/notify.h>
27
28#if SM_NOTIFY_DEBUG
29#define SM_DBG(p)	fprintf p
30#else
31#define SM_DBG(p)
32#endif
33
34static int	Notifypipe[2];
35#define NotifyRDpipe Notifypipe[0]
36#define NotifyWRpipe Notifypipe[1]
37
38#define CLOSEFD(fd) do { \
39		if ((fd) != -1) {	\
40			(void) close(fd);	\
41			fd = - 1;	\
42		}	\
43	} while (0)	\
44
45
46/*
47**  SM_NOTIFY_INIT -- initialize notify system
48**
49**	Parameters:
50**		flags -- ignored
51**
52**	Returns:
53**		0: success
54**		<0: -errno
55*/
56
57int
58sm_notify_init(flags)
59	int flags;
60{
61	if (pipe(Notifypipe) < 0)
62		return -errno;
63	return 0;
64}
65
66/*
67**  SM_NOTIFY_START -- start notify system
68**
69**	Parameters:
70**		owner -- owner.
71**		flags -- currently ignored.
72**
73**	Returns:
74**		0: success
75**		<0: -errno
76*/
77
78int
79sm_notify_start(owner, flags)
80	bool owner;
81	int flags;
82{
83	int r;
84
85	r = 0;
86	if (owner)
87		CLOSEFD(NotifyWRpipe);
88	else
89		CLOSEFD(NotifyRDpipe);
90	return r;
91}
92
93/*
94**  SM_NOTIFY_STOP -- stop notify system
95**
96**	Parameters:
97**		owner -- owner.
98**		flags -- currently ignored.
99**
100**	Returns:
101**		0: success
102**		<0: -errno
103*/
104
105int
106sm_notify_stop(owner, flags)
107	bool owner;
108	int flags;
109{
110	if (owner)
111		CLOSEFD(NotifyRDpipe);
112	else
113		CLOSEFD(NotifyWRpipe);
114	return 0;
115}
116
117/*
118**  SM_NOTIFY_SND -- send notification
119**
120**	Parameters:
121**		buf -- where to write data
122**		buflen -- len of buffer
123**
124**	Returns:
125**		0: success
126**		<0: -errno
127*/
128
129int
130sm_notify_snd(buf, buflen)
131	char *buf;
132	size_t buflen;
133{
134	int r;
135	int save_errno;
136
137	SM_REQUIRE(buf != NULL);
138	SM_REQUIRE(buflen > 0);
139	if (NotifyWRpipe < 0)
140		return -EINVAL;
141
142	r = write(NotifyWRpipe, buf, buflen);
143	save_errno = errno;
144	SM_DBG((stderr, "write=%d, fd=%d, e=%d\n", r, NotifyWRpipe, save_errno));
145	return r >= 0 ? 0 : -save_errno;
146}
147
148/*
149**  SM_NOTIFY_RCV -- receive notification
150**
151**	Parameters:
152**		buf -- where to write data
153**		buflen -- len of buffer
154**		tmo -- timeout
155**
156**	Returns:
157**		0: success
158**		<0: -errno
159*/
160
161int
162sm_notify_rcv(buf, buflen, tmo)
163	char *buf;
164	size_t buflen;
165	int tmo;
166{
167	int r;
168	int save_errno;
169	fd_set readfds;
170	struct timeval timeout;
171
172	SM_REQUIRE(buf != NULL);
173	SM_REQUIRE(buflen > 0);
174	if (NotifyRDpipe < 0)
175		return -EINVAL;
176	FD_ZERO(&readfds);
177	SM_FD_SET(NotifyRDpipe, &readfds);
178	timeout.tv_sec = tmo;
179	timeout.tv_usec = 0;
180
181	do {
182		r = select(NotifyRDpipe + 1, FDSET_CAST &readfds, NULL, NULL, &timeout);
183		save_errno = errno;
184		SM_DBG((stderr, "select=%d, fd=%d, e=%d\n", r, NotifyRDpipe, save_errno));
185	} while (r < 0 && save_errno == EINTR);
186
187	if (r <= 0)
188	{
189		SM_DBG((stderr, "select=%d, e=%d\n", r, save_errno));
190		return -ETIMEDOUT;
191	}
192
193	/* bogus... need to check again? */
194	if (!FD_ISSET(NotifyRDpipe, &readfds))
195		return -ETIMEDOUT;
196
197	r = read(NotifyRDpipe, buf, buflen);
198	save_errno = errno;
199	SM_DBG((stderr, "read=%d, e=%d\n", r, save_errno));
200	if (r == 0)
201		return -1;	/* ??? */
202	if (r < 0)
203		return -save_errno;
204	return r;
205}
206