xref: /freebsd/contrib/sendmail/libsm/notify.c (revision 43a5ec4eb41567cc92586503212743d89686d78f)
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
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
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
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
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
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