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
sm_notify_init(flags)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
sm_notify_start(owner,flags)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
sm_notify_stop(owner,flags)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
sm_notify_snd(buf,buflen)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
sm_notify_rcv(buf,buflen,tmo)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