**
* Copyright (c) 1999-2002 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
- *
- * Portions Copyright (c) 1999 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 1.1 (the "License"). You may not use this file
- * except in compliance with the License. Please obtain a copy of the
- * License at http://www.apple.com/publicsource 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 OR NON- INFRINGEMENT. Please see the
- * License for the specific language governing rights and limitations
- * under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
+ * @APPLE_APACHE_LICENSE_HEADER_START@
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @APPLE_APACHE_LICENSE_HEADER_END@
**/
#include <sys/wait.h>
#include <mach/mach.h>
#include <mach/message.h>
#include <mach/mach_error.h>
-#include <servers/bootstrap.h>
#include <CoreFoundation/CoreFoundation.h>
#include <syslog.h>
+
+#include "bootstrap.h"
+
#include "IPC.h"
#include "StartupItems.h"
#include "SystemStarter.h"
startupItemTerminated(NULL, aTerminationContext);
}
}
-
-/**
- * Returns a reference to an item based on tokens passed in an IPC message.
- * This is useful for figuring out which item the message came from.
- *
- * Currently two tokens are supported:
- * kIPCProcessIDKey - the pid of the running startup script
- * kIPCServiceNameKey - a name of a service that the item provides. This
- * takes precedence over the pid key when both are present.
- **/
-static CFMutableDictionaryRef
-itemFromIPCMessage(StartupContext aStartupContext, CFDictionaryRef anIPCMessage)
-{
- CFMutableDictionaryRef anItem = NULL;
-
- if (aStartupContext && anIPCMessage) {
- CFStringRef aServiceName = CFDictionaryGetValue(anIPCMessage, kIPCServiceNameKey);
- CFIndex aPID = 0;
- CFNumberRef aPIDNumber = CFDictionaryGetValue(anIPCMessage, kIPCProcessIDKey);
-
- if (aServiceName && CFGetTypeID(aServiceName) == CFStringGetTypeID()) {
- anItem = StartupItemListGetProvider(aStartupContext->aWaitingList, aServiceName);
- } else if (aPIDNumber &&
- CFGetTypeID(aPIDNumber) == CFNumberGetTypeID() &&
- CFNumberGetValue(aPIDNumber, kCFNumberCFIndexType, &aPID)) {
- anItem = StartupItemWithPID(aStartupContext->aWaitingList, aPID);
- }
- }
- return anItem;
-}
-
-/**
- * Displays a message on the console.
- * aConsoleMessage will be localized according to the dictionary in the specified item.
- * Running tems may be specified by their current process id. Items may also be specified
- * by one of the service names they provide.
- **/
-static void
-consoleMessage(StartupContext aStartupContext, CFDictionaryRef anIPCMessage)
-{
- if (aStartupContext && anIPCMessage) {
- CFStringRef aConsoleMessage = CFDictionaryGetValue(anIPCMessage, kIPCConsoleMessageKey);
-
- if (aConsoleMessage && CFGetTypeID(aConsoleMessage) == CFStringGetTypeID()) {
- CF_syslog(LOG_INFO, CFSTR("%@"), aConsoleMessage);
- }
- }
-}
-
-/**
- * Records the success or failure or a particular service.
- * If no service name is specified, but a pid is, then all services provided
- * by the item are flagged.
- **/
-static void
-statusMessage(StartupContext aStartupContext, CFDictionaryRef anIPCMessage)
-{
- if (anIPCMessage && aStartupContext && aStartupContext->aStatusDict) {
- CFMutableDictionaryRef anItem = itemFromIPCMessage(aStartupContext, anIPCMessage);
- CFStringRef aServiceName = CFDictionaryGetValue(anIPCMessage, kIPCServiceNameKey);
- CFBooleanRef aStatus = CFDictionaryGetValue(anIPCMessage, kIPCStatusKey);
-
- if (anItem && aStatus &&
- CFGetTypeID(aStatus) == CFBooleanGetTypeID() &&
- (!aServiceName || CFGetTypeID(aServiceName) == CFStringGetTypeID())) {
- StartupItemSetStatus(aStartupContext->aStatusDict, anItem, aServiceName, CFBooleanGetValue(aStatus), TRUE);
- }
- }
-}
-
-/**
- * Queries one of several configuration settings.
- */
-static CFDataRef
-queryConfigSetting(StartupContext aStartupContext, CFDictionaryRef anIPCMessage)
-{
- char *aValue = "";
-
- if (anIPCMessage) {
- CFStringRef aSetting = CFDictionaryGetValue(anIPCMessage, kIPCConfigSettingKey);
-
- if (aSetting && CFGetTypeID(aSetting) == CFStringGetTypeID()) {
- if (CFEqual(aSetting, kIPCConfigSettingVerboseFlag)) {
- aValue = gVerboseFlag ? "-YES-" : "-NO-";
- } else if (CFEqual(aSetting, kIPCConfigSettingNetworkUp)) {
- Boolean aNetworkUpFlag = FALSE;
- if (aStartupContext && aStartupContext->aStatusDict) {
- aNetworkUpFlag = CFDictionaryContainsKey(aStartupContext->aStatusDict, CFSTR("Network"));
- }
- aValue = aNetworkUpFlag ? "-YES-" : "-NO-";
- }
- }
- }
- return CFDataCreate(NULL, (const UInt8 *)aValue, strlen(aValue) + 1); /* aValue + null */
-}
-
-static void *handleIPCMessage(void *aMsgParam, CFIndex aMessageSize __attribute__((unused)), CFAllocatorRef anAllocator __attribute__((unused)), void *aMachPort) {
- SystemStarterIPCMessage *aMessage = (SystemStarterIPCMessage *) aMsgParam;
- SystemStarterIPCMessage *aReplyMessage = NULL;
-
- CFDataRef aResult = NULL;
- CFDataRef aData = NULL;
-
- if (aMessage->aHeader.msgh_bits & MACH_MSGH_BITS_COMPLEX) {
- syslog(LOG_WARNING, "Ignoring out-of-line IPC message");
- return NULL;
- } else {
- mach_msg_security_trailer_t *aSecurityTrailer = (mach_msg_security_trailer_t *)
- ((uint8_t *) aMessage + round_msg(sizeof(SystemStarterIPCMessage) + aMessage->aByteLength));
-
- /*
- * CFRunLoop includes the format 0 message trailer with the
- * passed message.
- */
- if (aSecurityTrailer->msgh_trailer_type == MACH_MSG_TRAILER_FORMAT_0 &&
- aSecurityTrailer->msgh_sender.val[0] != 0) {
- syslog(LOG_WARNING, "Ignoring IPC message sent from uid %d", aSecurityTrailer->msgh_sender.val[0]);
- return NULL;
- }
- }
-
- if (aMessage->aProtocol != kIPCProtocolVersion) {
- syslog(LOG_WARNING, "Unsupported IPC protocol version number: %d. Message ignored", aMessage->aProtocol);
- return NULL;
- }
- aData = CFDataCreateWithBytesNoCopy(NULL,
- (uint8_t *) aMessage + sizeof(SystemStarterIPCMessage),
- aMessage->aByteLength,
- kCFAllocatorNull);
- /*
- * Dispatch the IPC message.
- */
- if (aData) {
- StartupContext aStartupContext = NULL;
- CFStringRef anErrorString = NULL;
- CFDictionaryRef anIPCMessage = (CFDictionaryRef) CFPropertyListCreateFromXMLData(NULL, aData, kCFPropertyListImmutable, &anErrorString);
-
- CF_syslog(LOG_DEBUG, CFSTR("IPC message = %@"), anIPCMessage);
-
- if (aMachPort) {
- CFMachPortContext aMachPortContext;
- CFMachPortGetContext((CFMachPortRef) aMachPort, &aMachPortContext);
- aStartupContext = (StartupContext) aMachPortContext.info;
- }
- if (anIPCMessage && CFGetTypeID(anIPCMessage) == CFDictionaryGetTypeID()) {
- /* switch on the type of the IPC message */
- CFStringRef anIPCMessageType = CFDictionaryGetValue(anIPCMessage, kIPCMessageKey);
- if (anIPCMessageType && CFGetTypeID(anIPCMessageType) == CFStringGetTypeID()) {
- if (CFEqual(anIPCMessageType, kIPCConsoleMessage)) {
- consoleMessage(aStartupContext, anIPCMessage);
- } else if (CFEqual(anIPCMessageType, kIPCStatusMessage)) {
- statusMessage(aStartupContext, anIPCMessage);
- } else if (CFEqual(anIPCMessageType, kIPCQueryMessage)) {
- aResult = queryConfigSetting(aStartupContext, anIPCMessage);
- }
- }
- } else {
- CF_syslog(LOG_ERR, CFSTR("Unable to parse IPC message: %@"), anErrorString);
- }
- CFRelease(aData);
- } else {
- syslog(LOG_ERR, "Out of memory. Could not allocate space for IPC message");
- }
-
- /*
- * Generate a Mach message for the result data.
- */
- if (!aResult)
- aResult = CFDataCreateWithBytesNoCopy(NULL, (const UInt8 *)"", 1, kCFAllocatorNull);
- if (aResult) {
- CFIndex aDataSize = CFDataGetLength(aResult);
- CFIndex aReplyMessageSize = round_msg(sizeof(SystemStarterIPCMessage) + aDataSize + 3);
- aReplyMessage = CFAllocatorAllocate(kCFAllocatorSystemDefault, aReplyMessageSize, 0);
- if (aReplyMessage) {
- aReplyMessage->aHeader.msgh_id = -1 * (SInt32) aMessage->aHeader.msgh_id;
- aReplyMessage->aHeader.msgh_size = aReplyMessageSize;
- aReplyMessage->aHeader.msgh_remote_port = aMessage->aHeader.msgh_remote_port;
- aReplyMessage->aHeader.msgh_local_port = MACH_PORT_NULL;
- aReplyMessage->aHeader.msgh_reserved = 0;
- aReplyMessage->aHeader.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE, 0);
- aReplyMessage->aBody.msgh_descriptor_count = 0;
- aReplyMessage->aProtocol = kIPCProtocolVersion;
- aReplyMessage->aByteLength = CFDataGetLength(aResult);
- memmove((uint8_t *) aReplyMessage + sizeof(SystemStarterIPCMessage),
- CFDataGetBytePtr(aResult),
- CFDataGetLength(aResult));
- }
- CFRelease(aResult);
- }
- if (!aReplyMessage) {
- syslog(LOG_ERR, "Out of memory. Could not allocate IPC result");
- }
- return aReplyMessage;
-}
-
-
-static mach_port_t
-getIPCPort(void *anInfo)
-{
- return anInfo ? CFMachPortGetPort((CFMachPortRef) anInfo) : MACH_PORT_NULL;
-}
-
-CFRunLoopSourceRef
-CreateIPCRunLoopSource(CFStringRef aPortName, StartupContext aStartupContext)
-{
- CFRunLoopSourceRef aSource = NULL;
- CFMachPortRef aMachPort = NULL;
- CFMachPortContext aContext;
- kern_return_t aKernReturn = KERN_FAILURE;
-
- aContext.version = 0;
- aContext.info = (void *) aStartupContext;
- aContext.retain = 0;
- aContext.release = 0;
- aContext.copyDescription = 0;
- aMachPort = CFMachPortCreate(NULL, NULL, &aContext, NULL);
-
- if (aMachPort && aPortName) {
- CFIndex aPortNameLength = CFStringGetLength(aPortName);
- CFIndex aPortNameSize = CFStringGetMaximumSizeForEncoding(aPortNameLength, kCFStringEncodingUTF8) + 1;
- char *aBuffer = CFAllocatorAllocate(NULL, aPortNameSize, 0);
- if (aBuffer && CFStringGetCString(aPortName,
- aBuffer,
- aPortNameSize,
- kCFStringEncodingUTF8)) {
- mach_port_t aBootstrapPort;
- task_get_bootstrap_port(mach_task_self(), &aBootstrapPort);
- aKernReturn = bootstrap_register(aBootstrapPort, aBuffer, CFMachPortGetPort(aMachPort));
- }
- if (aBuffer)
- CFAllocatorDeallocate(NULL, aBuffer);
- }
- if (aMachPort && aKernReturn == KERN_SUCCESS) {
- CFRunLoopSourceContext1 aSourceContext;
- aSourceContext.version = 1;
- aSourceContext.info = aMachPort;
- aSourceContext.retain = CFRetain;
- aSourceContext.release = CFRelease;
- aSourceContext.copyDescription = CFCopyDescription;
- aSourceContext.equal = CFEqual;
- aSourceContext.hash = CFHash;
- aSourceContext.getPort = getIPCPort;
- aSourceContext.perform = (void *) handleIPCMessage;
- aSource = CFRunLoopSourceCreate(NULL, 0, (CFRunLoopSourceContext *) & aSourceContext);
- }
- if (aMachPort && (!aSource || aKernReturn != KERN_SUCCESS)) {
- CFMachPortInvalidate(aMachPort);
- CFRelease(aMachPort);
- aMachPort = NULL;
- }
- return aSource;
-}