#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include "configd.h"
#include "session.h"
__private_extern__
int
__SCDynamicStoreNotifyFileDescriptor(SCDynamicStoreRef store,
int32_t identifier,
int *fd)
{
SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store;
int sock;
CFStringRef sessionKey;
CFDictionaryRef info;
if (!store || (storePrivate->server == MACH_PORT_NULL)) {
return kSCStatusNoStoreSession;
}
if (storePrivate->notifyStatus != NotifierNotRegistered) {
return kSCStatusNotifierActive;
}
if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
SCLog(TRUE, LOG_NOTICE, CFSTR("__SCDynamicStoreNotifyFileDescriptor socket() failed: %s"), strerror(errno));
return kSCStatusFailed;
}
*fd = sock;
sessionKey = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d"), storePrivate->server);
info = CFDictionaryGetValue(sessionData, sessionKey);
CFRelease(sessionKey);
if (info && CFDictionaryContainsKey(info, kSCDChangedKeys)) {
CFNumberRef sessionNum;
if (needsNotification == NULL)
needsNotification = CFSetCreateMutable(NULL,
0,
&kCFTypeSetCallBacks);
sessionNum = CFNumberCreate(NULL, kCFNumberIntType, &storePrivate->server);
CFSetAddValue(needsNotification, sessionNum);
CFRelease(sessionNum);
}
return kSCStatusOK;
}
__private_extern__
kern_return_t
_notifyviafd(mach_port_t server,
xmlData_t pathRef,
mach_msg_type_number_t pathLen,
int identifier,
int *sc_status
)
{
int bufSiz;
serverSessionRef mySession = getSession(server);
int nbioYes;
int sock;
kern_return_t status;
SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)mySession->store;
struct sockaddr_un un;
if (pathLen > (sizeof(un.sun_path) - 1)) {
SCLog(TRUE, LOG_NOTICE, CFSTR("_notifyviafd(): domain socket path length too long!"));
status = vm_deallocate(mach_task_self(), (vm_address_t)pathRef, pathLen);
#ifdef DEBUG
if (status != KERN_SUCCESS) {
SCLog(TRUE, LOG_DEBUG, CFSTR("_notifyviafd vm_deallocate() failed: %s"), mach_error_string(status));
}
#endif
*sc_status = kSCStatusFailed;
return KERN_SUCCESS;
}
un.sun_family = AF_UNIX;
bcopy(pathRef, un.sun_path, pathLen);
un.sun_path[pathLen] = '\0';
status = vm_deallocate(mach_task_self(), (vm_address_t)pathRef, pathLen);
#ifdef DEBUG
if (status != KERN_SUCCESS) {
SCLog(TRUE, LOG_DEBUG, CFSTR("_notifyviafd vm_deallocate() failed: %s"), mach_error_string(status));
}
#endif
if (!mySession) {
*sc_status = kSCStatusNoStoreSession;
return KERN_SUCCESS;
}
*sc_status = __SCDynamicStoreNotifyFileDescriptor(mySession->store, identifier, &sock);
if (*sc_status != kSCStatusOK) {
return KERN_SUCCESS;
}
if (connect(sock, (struct sockaddr *)&un, sizeof(un)) == -1) {
SCLog(TRUE, LOG_DEBUG, CFSTR("_notifyviafd connect() failed: %s"), strerror(errno));
(void) close(sock);
storePrivate->notifyStatus = NotifierNotRegistered;
storePrivate->notifyFile = -1;
*sc_status = kSCStatusFailed;
return KERN_SUCCESS;
}
(void) unlink(un.sun_path);
bufSiz = sizeof(storePrivate->notifyFileIdentifier);
if (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &bufSiz, sizeof(bufSiz)) < 0) {
SCLog(TRUE, LOG_DEBUG, CFSTR("_notifyviafd setsockopt() failed: %s"), strerror(errno));
(void) close(sock);
*sc_status = kSCStatusFailed;
return KERN_SUCCESS;
}
nbioYes = 1;
if (ioctl(sock, FIONBIO, &nbioYes) == -1) {
SCLog(TRUE, LOG_DEBUG, CFSTR("_notifyviafd ioctl(,FIONBIO,) failed: %s"), strerror(errno));
(void) close(sock);
*sc_status = kSCStatusFailed;
return KERN_SUCCESS;
}
storePrivate->notifyStatus = Using_NotifierInformViaFD;
storePrivate->notifyFile = sock;
storePrivate->notifyFileIdentifier = identifier;
return KERN_SUCCESS;
}