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