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
34 static 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
57 int
sm_notify_init(flags)58 sm_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
78 int
sm_notify_start(owner,flags)79 sm_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
105 int
sm_notify_stop(owner,flags)106 sm_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
129 int
sm_notify_snd(buf,buflen)130 sm_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
161 int
sm_notify_rcv(buf,buflen,tmo)162 sm_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