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 34static 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 57int 58sm_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 78int 79sm_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 105int 106sm_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 129int 130sm_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 161int 162sm_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