/* * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */ /* * Modification History * * June 1, 2001 Allan Nathanson * - public API conversion * * March 31, 2000 Allan Nathanson * - initial revision */ #include #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; /* if no sessions need to be kicked */ 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; /* * deliver notifications to client sessions */ 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; /* * Post notification as mach message */ 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, /* msg */ MACH_SEND_MSG|options, /* options */ msg.header.msgh_size, /* send_size */ 0, /* rcv_size */ MACH_PORT_NULL, /* rcv_name */ 0, /* timeout */ MACH_PORT_NULL); /* notify */ } 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; /* * Post notification as signal */ 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) { /* don't bother with any more attempts */ (void) mach_port_destroy(mach_task_self(), storePrivate->notifySignalTask); storePrivate->notifySignal = 0; storePrivate->notifySignalTask = TASK_NULL; } } } free(sessionsToNotify); /* * this list of notifications have been posted, wait for some more. */ CFRelease(needsNotification); needsNotification = NULL; return; }