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