xref: /freebsd/contrib/sendmail/libsm/notify.c (revision b3e7694832e81d7a904a10f525f8797b753bf0d3)
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 #if _FFR_DMTRIGGER
14 #include <sm/conf.h>	/* FDSET_CAST */
15 #include <sm/fdset.h>
16 #include <sm/assert.h>
17 #include <sm/notify.h>
18 #include <sm/time.h>
19 #include <sm/string.h>
20 
21 #include <sys/types.h>
22 #include <signal.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <unistd.h>
26 #include <stdbool.h>
27 #include <errno.h>
28 #include <fcntl.h>
29 #include <string.h>	/* for memset() */
30 
31 #if SM_NOTIFY_DEBUG
32 #define SM_DBG(p)	fprintf p
33 #else
34 #define SM_DBG(p)
35 #endif
36 
37 static int	Notifypipe[2];
38 #define NotifyRDpipe Notifypipe[0]
39 #define NotifyWRpipe Notifypipe[1]
40 
41 #define CLOSEFD(fd) do { \
42 		if ((fd) != -1) {	\
43 			(void) close(fd);	\
44 			fd = - 1;	\
45 		}	\
46 	} while (0)	\
47 
48 
49 /*
50 **  SM_NOTIFY_INIT -- initialize notify system
51 **
52 **	Parameters:
53 **		flags -- ignored
54 **
55 **	Returns:
56 **		0: success
57 **		<0: -errno
58 */
59 
60 int
61 sm_notify_init(flags)
62 	int flags;
63 {
64 	if (pipe(Notifypipe) < 0)
65 		return -errno;
66 	return 0;
67 }
68 
69 /*
70 **  SM_NOTIFY_START -- start notify system
71 **
72 **	Parameters:
73 **		owner -- owner.
74 **		flags -- currently ignored.
75 **
76 **	Returns:
77 **		0: success
78 **		<0: -errno
79 */
80 
81 int
82 sm_notify_start(owner, flags)
83 	bool owner;
84 	int flags;
85 {
86 	int r;
87 
88 	r = 0;
89 	if (owner)
90 		CLOSEFD(NotifyWRpipe);
91 	else
92 		CLOSEFD(NotifyRDpipe);
93 	return r;
94 }
95 
96 /*
97 **  SM_NOTIFY_STOP -- stop notify system
98 **
99 **	Parameters:
100 **		owner -- owner.
101 **		flags -- currently ignored.
102 **
103 **	Returns:
104 **		0: success
105 **		<0: -errno
106 */
107 
108 int
109 sm_notify_stop(owner, flags)
110 	bool owner;
111 	int flags;
112 {
113 	if (owner)
114 		CLOSEFD(NotifyRDpipe);
115 	else
116 		CLOSEFD(NotifyWRpipe);
117 	return 0;
118 }
119 
120 /*
121 **  SM_NOTIFY_SND -- send notification
122 **
123 **	Parameters:
124 **		buf -- where to write data
125 **		buflen -- len of buffer
126 **
127 **	Returns:
128 **		0: success
129 **		<0: -errno
130 */
131 
132 #define MAX_NETSTR 1024
133 #define NETSTRPRE 5
134 
135 int
136 sm_notify_snd(buf, buflen)
137 	char *buf;
138 	size_t buflen;
139 {
140 	int r;
141 	int save_errno;
142 	size_t len;
143 	char netstr[MAX_NETSTR];
144 
145 	SM_REQUIRE(buf != NULL);
146 	SM_REQUIRE(buflen > 0);
147 	if (NotifyWRpipe < 0)
148 		return -EINVAL;
149 	if (buflen >= MAX_NETSTR - 7)
150 		return -E2BIG;	/* XXX "TOO LARGE"? */
151 
152 	len = sm_snprintf(netstr, sizeof(netstr), "%04d:%s,", (int)buflen, buf);
153 	r = write(NotifyWRpipe, netstr, len);
154 	save_errno = errno;
155 	SM_DBG((stderr, "write=%d, fd=%d, e=%d\n", r, NotifyWRpipe, save_errno));
156 	return r >= 0 ? 0 : -save_errno;
157 }
158 
159 /*
160 **  SM_NOTIFY_RCV -- receive notification
161 **
162 **	Parameters:
163 **		buf -- where to write data
164 **		buflen -- len of buffer
165 **		tmo -- timeout (micro seconds)
166 **
167 **	Returns:
168 **		0: success
169 **		<0: -errno
170 */
171 
172 int
173 sm_notify_rcv(buf, buflen, tmo)
174 	char *buf;
175 	size_t buflen;
176 	long tmo;
177 {
178 	int r, len;
179 	int save_errno;
180 	fd_set readfds;
181 	struct timeval timeout, *tval;
182 
183 	SM_REQUIRE(buf != NULL);
184 	SM_REQUIRE(buflen > NETSTRPRE + 2);
185 	if (NotifyRDpipe < 0)
186 		return -EINVAL;
187 	FD_ZERO(&readfds);
188 	SM_FD_SET(NotifyRDpipe, &readfds);
189 	if (tmo < 0)
190 		tval = NULL;
191 	else
192 	{
193 		timeout.tv_sec = (long) (tmo / SM_MICROS);
194 		timeout.tv_usec = tmo % SM_MICROS;
195 		tval = &timeout;
196 	}
197 
198 	do {
199 		r = select(NotifyRDpipe + 1, FDSET_CAST &readfds, NULL, NULL, tval);
200 		save_errno = errno;
201 		SM_DBG((stderr, "select=%d, fd=%d, e=%d\n", r, NotifyRDpipe, save_errno));
202 	} while (r < 0 && save_errno == EINTR);
203 
204 	if (r <= 0)
205 	{
206 		SM_DBG((stderr, "select=%d, e=%d\n", r, save_errno));
207 		return -ETIMEDOUT;
208 	}
209 
210 	/* bogus... need to check again? */
211 	if (!FD_ISSET(NotifyRDpipe, &readfds))
212 		return -ETIMEDOUT;
213 
214 	r = read(NotifyRDpipe, buf, NETSTRPRE);
215 	if (NETSTRPRE != r)
216 		return -1;	/* ??? */
217 
218 	if (sm_io_sscanf(buf, "%4u:", &len) != 1)
219 		return -EINVAL;	/* ??? */
220 	if (len >= MAX_NETSTR)
221 		return -E2BIG;	/* ??? */
222 	if (len >= buflen - 1)
223 		return -E2BIG;	/* ??? */
224 	if (len <= 0)
225 		return -EINVAL;	/* ??? */
226 	r = read(NotifyRDpipe, buf, len + 1);
227 	save_errno = errno;
228 	SM_DBG((stderr, "read=%d, e=%d\n", r, save_errno));
229 	if (r == 0)
230 		return -1;	/* ??? */
231 	if (r < 0)
232 		return -save_errno;
233 	if (len + 1 != r)
234 		return -1;	/* ??? */
235 	if (buf[len] != ',')
236 		return -EINVAL;	/* ??? */
237 	buf[len] = '\0';
238 	return r;
239 }
240 #endif /* _FFR_DMTRIGGER */
241