#include <unistd.h>
#include "configd.h"
#include "configd_server.h"
#include "session.h"
__private_extern__
void
pushNotifications()
{
const void **sessionsToNotify;
CFIndex notifyCnt;
int server;
serverSessionRef theSession;
SCDynamicStorePrivateRef storePrivate;
if (needsNotification == NULL)
return;
notifyCnt = CFSetGetCount(needsNotification);
sessionsToNotify = malloc(notifyCnt * sizeof(CFNumberRef));
CFSetGetValues(needsNotification, sessionsToNotify);
while (--notifyCnt >= 0) {
(void) CFNumberGetValue(sessionsToNotify[notifyCnt],
kCFNumberIntType,
&server);
theSession = getSession(server);
storePrivate = (SCDynamicStorePrivateRef)theSession->store;
if ((storePrivate->notifyStatus == Using_NotifierInformViaMachPort) &&
(storePrivate->notifyPort != MACH_PORT_NULL)) {
mach_msg_empty_send_t msg;
mach_msg_option_t options;
kern_return_t status;
if (_configd_verbose) {
SCLog(TRUE, LOG_DEBUG, CFSTR("sending mach message notification."));
SCLog(TRUE, LOG_DEBUG, CFSTR(" port = %d"), storePrivate->notifyPort);
SCLog(TRUE, LOG_DEBUG, CFSTR(" msgid = %d"), storePrivate->notifyPortIdentifier);
}
msg.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
msg.header.msgh_size = sizeof(msg);
msg.header.msgh_remote_port = storePrivate->notifyPort;
msg.header.msgh_local_port = MACH_PORT_NULL;
msg.header.msgh_id = storePrivate->notifyPortIdentifier;
options = MACH_SEND_TIMEOUT;
status = mach_msg(&msg.header,
MACH_SEND_MSG|options,
msg.header.msgh_size,
0,
MACH_PORT_NULL,
0,
MACH_PORT_NULL);
}
if ((storePrivate->notifyStatus == Using_NotifierInformViaFD) &&
(storePrivate->notifyFile >= 0)) {
ssize_t written;
if (_configd_verbose) {
SCLog(TRUE, LOG_DEBUG, CFSTR("sending (UNIX domain) socket notification"));
SCLog(TRUE, LOG_DEBUG, CFSTR(" fd = %d"), storePrivate->notifyFile);
SCLog(TRUE, LOG_DEBUG, CFSTR(" msgid = %d"), storePrivate->notifyFileIdentifier);
}
written = write(storePrivate->notifyFile,
&storePrivate->notifyFileIdentifier,
sizeof(storePrivate->notifyFileIdentifier));
if (written == -1) {
if (errno == EWOULDBLOCK) {
SCLog(_configd_verbose, LOG_DEBUG,
CFSTR("sorry, only one outstanding notification per session."));
} else {
SCLog(_configd_verbose, LOG_DEBUG,
CFSTR("could not send notification, write() failed: %s"),
strerror(errno));
storePrivate->notifyFile = -1;
}
} else if (written != sizeof(storePrivate->notifyFileIdentifier)) {
SCLog(_configd_verbose, LOG_DEBUG,
CFSTR("could not send notification, incomplete write()"));
storePrivate->notifyFile = -1;
}
}
if ((storePrivate->notifyStatus == Using_NotifierInformViaSignal) &&
(storePrivate->notifySignal > 0)) {
kern_return_t status;
pid_t pid;
status = pid_for_task(storePrivate->notifySignalTask, &pid);
if (status == KERN_SUCCESS) {
if (_configd_verbose) {
SCLog(TRUE, LOG_DEBUG, CFSTR("sending signal notification"));
SCLog(TRUE, LOG_DEBUG, CFSTR(" pid = %d"), pid);
SCLog(TRUE, LOG_DEBUG, CFSTR(" signal = %d"), storePrivate->notifySignal);
}
if (kill(pid, storePrivate->notifySignal) != 0) {
SCLog(_configd_verbose, LOG_DEBUG, CFSTR("could not send signal: %s"), strerror(errno));
status = KERN_FAILURE;
}
} else {
mach_port_type_t pt;
if ((mach_port_type(mach_task_self(), storePrivate->notifySignalTask, &pt) == KERN_SUCCESS) &&
(pt & MACH_PORT_TYPE_DEAD_NAME)) {
SCLog(_configd_verbose, LOG_DEBUG, CFSTR("could not send signal, process died"));
} else {
SCLog(_configd_verbose, LOG_DEBUG, CFSTR("could not send signal: %s"), mach_error_string(status));
}
}
if (status != KERN_SUCCESS) {
(void) mach_port_destroy(mach_task_self(), storePrivate->notifySignalTask);
storePrivate->notifySignal = 0;
storePrivate->notifySignalTask = TASK_NULL;
}
}
}
free(sessionsToNotify);
CFRelease(needsNotification);
needsNotification = NULL;
return;
}