xref: /freebsd/contrib/sendmail/libsm/notify.c (revision d39bd2c1)
1 /*
2  * Copyright (c) 2020 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 && _FFR_NOTIFY < 2
14 #include <sm/conf.h>	/* FDSET_CAST */
15 #include <sm/fdset.h>
16 #include <sm/assert.h>
17 #include <sm/notify.h>
18 #include "notify.h"
19 #include <sm/time.h>
20 #include <sm/string.h>
21 
22 #include <sys/types.h>
23 #include <signal.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <unistd.h>
27 #include <stdbool.h>
28 #include <errno.h>
29 #include <fcntl.h>
30 #include <string.h>	/* for memset() */
31 
32 static int	Notifypipe[2];
33 #define NotifyRDpipe Notifypipe[0]
34 #define NotifyWRpipe Notifypipe[1]
35 
36 #define CLOSEFD(fd) do { \
37 		if ((fd) != -1) {	\
38 			(void) close(fd);	\
39 			fd = - 1;	\
40 		}	\
41 	} while (0)	\
42 
43 
44 /*
45 **  SM_NOTIFY_INIT -- initialize notify system
46 **
47 **	Parameters:
48 **		flags -- ignored
49 **
50 **	Returns:
51 **		0: success
52 **		<0: -errno
53 */
54 
55 int
sm_notify_init(flags)56 sm_notify_init(flags)
57 	int flags;
58 {
59 	if (pipe(Notifypipe) < 0)
60 		return -errno;
61 	return 0;
62 }
63 
64 /*
65 **  SM_NOTIFY_START -- start notify system
66 **
67 **	Parameters:
68 **		owner -- owner.
69 **		flags -- currently ignored.
70 **
71 **	Returns:
72 **		0: success
73 **		<0: -errno
74 */
75 
76 int
sm_notify_start(owner,flags)77 sm_notify_start(owner, flags)
78 	bool owner;
79 	int flags;
80 {
81 	int r;
82 
83 	r = 0;
84 	if (owner)
85 		CLOSEFD(NotifyWRpipe);
86 	else
87 		CLOSEFD(NotifyRDpipe);
88 	return r;
89 }
90 
91 /*
92 **  SM_NOTIFY_STOP -- stop notify system
93 **
94 **	Parameters:
95 **		owner -- owner.
96 **		flags -- currently ignored.
97 **
98 **	Returns:
99 **		0: success
100 **		<0: -errno
101 */
102 
103 int
sm_notify_stop(owner,flags)104 sm_notify_stop(owner, flags)
105 	bool owner;
106 	int flags;
107 {
108 	if (owner)
109 		CLOSEFD(NotifyRDpipe);
110 	else
111 		CLOSEFD(NotifyWRpipe);
112 	return 0;
113 }
114 
115 /*
116 **  SM_NOTIFY_SND -- send notification
117 **
118 **	Parameters:
119 **		buf -- where to write data
120 **		buflen -- len of buffer
121 **
122 **	Returns:
123 **		0: success
124 **		<0: -errno
125 */
126 
127 int
sm_notify_snd(buf,buflen)128 sm_notify_snd(buf, buflen)
129 	char *buf;
130 	size_t buflen;
131 {
132 	int r;
133 	int save_errno;
134 	size_t len;
135 	char netstr[MAX_NETSTR];
136 
137 	SM_REQUIRE(buf != NULL);
138 	SM_REQUIRE(buflen > 0);
139 	if (NotifyWRpipe < 0)
140 		return -EINVAL;
141 	if (buflen >= MAX_NETSTR - 7)
142 		return -E2BIG;	/* XXX "TOO LARGE"? */
143 
144 	len = sm_snprintf(netstr, sizeof(netstr), "%04d:%s,", (int)buflen, buf);
145 	r = write(NotifyWRpipe, netstr, len);
146 	save_errno = errno;
147 	SM_DBG((stderr, "pid=%ld, write=%d, fd=%d, e=%d\n", (long)getpid(), r, NotifyWRpipe, save_errno));
148 	return r >= 0 ? 0 : -save_errno;
149 }
150 
151 /*
152 **  SM_NOTIFY_RCV -- receive notification
153 **
154 **	Parameters:
155 **		buf -- where to write data
156 **		buflen -- len of buffer
157 **		tmo -- timeout (micro seconds)
158 **
159 **	Returns:
160 **		0: EOF (XXX need to provide info about client)
161 **		>0: length of received data
162 **		<0: -errno
163 */
164 
165 int
sm_notify_rcv(buf,buflen,tmo)166 sm_notify_rcv(buf, buflen, tmo)
167 	char *buf;
168 	size_t buflen;
169 	long tmo;
170 {
171 	int r, len;
172 	int save_errno;
173 	fd_set readfds;
174 	struct timeval timeout, *tval;
175 
176 	SM_REQUIRE(buf != NULL);
177 	SM_REQUIRE(buflen > NETSTRPRE + 2);
178 	if (NotifyRDpipe < 0)
179 		return -EINVAL;
180 	FD_ZERO(&readfds);
181 	SM_FD_SET(NotifyRDpipe, &readfds);
182 	SM_MICROS2TVAL(tmo, tval, timeout);
183 
184 	do {
185 		r = select(NotifyRDpipe + 1, FDSET_CAST &readfds, NULL, NULL, tval);
186 		save_errno = errno;
187 		SM_DBG((stderr, "pid=%ld, select=%d, fd=%d, e=%d\n", (long)getpid(), r, NotifyRDpipe, save_errno));
188 	} while (r < 0 && save_errno == EINTR);
189 
190 	RDNETSTR(r, NotifyRDpipe, (void)0);
191 }
192 #endif /* _FFR_DMTRIGGER && _FFR_NOTIFY < 2 */
193