2 * IPC.c - System Starter IPC routines
3 * Wilfredo Sanchez | wsanchez@opensource.apple.com
4 * Kevin Van Vechten | kevinvv@uclink4.berkeley.edu
7 * Copyright (c) 1999-2002 Apple Computer, Inc. All rights reserved.
9 * @APPLE_APACHE_LICENSE_HEADER_START@
11 * Licensed under the Apache License, Version 2.0 (the "License");
12 * you may not use this file except in compliance with the License.
13 * You may obtain a copy of the License at
15 * http://www.apache.org/licenses/LICENSE-2.0
17 * Unless required by applicable law or agreed to in writing, software
18 * distributed under the License is distributed on an "AS IS" BASIS,
19 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 * See the License for the specific language governing permissions and
21 * limitations under the License.
23 * @APPLE_APACHE_LICENSE_HEADER_END@
27 #include <mach/mach.h>
28 #include <mach/message.h>
29 #include <mach/mach_error.h>
30 #include <CoreFoundation/CoreFoundation.h>
33 #include "libbootstrap_public.h"
36 #include "StartupItems.h"
37 #include "SystemStarter.h"
38 #include "SystemStarterIPC.h"
40 /* Structure to pass StartupContext and anItem to the termination handler. */
41 typedef struct TerminationContextStorage
{
42 StartupContext aStartupContext
;
43 CFMutableDictionaryRef anItem
;
44 } *TerminationContext
;
47 * A CFMachPort invalidation callback that records the termination of
48 * a startup item task. Stops the current run loop to give system_starter
49 * another go at running items.
52 startupItemTerminated(CFMachPortRef aMachPort
, void *anInfo
)
54 TerminationContext aTerminationContext
= (TerminationContext
) anInfo
;
57 mach_port_deallocate(mach_task_self(), CFMachPortGetPort(aMachPort
));
59 if (aTerminationContext
&& aTerminationContext
->anItem
) {
63 CFMutableDictionaryRef anItem
= aTerminationContext
->anItem
;
64 StartupContext aStartupContext
= aTerminationContext
->aStartupContext
;
66 /* Get the exit status */
68 aPID
= StartupItemGetPID(anItem
);
70 rPID
= waitpid(aPID
, &aStatus
, 0);
72 if (aStartupContext
) {
73 --aStartupContext
->aRunningCount
;
75 /* Record the item's status */
76 if (aStartupContext
->aStatusDict
) {
77 StartupItemExit(aStartupContext
->aStatusDict
, anItem
, (WIFEXITED(aStatus
) && WEXITSTATUS(aStatus
) == 0));
79 CF_syslog(LOG_WARNING
, CFSTR("%@ (%d) did not complete successfully"), CFDictionaryGetValue(anItem
, CFSTR("Description")), aPID
);
81 CF_syslog(LOG_DEBUG
, CFSTR("Finished %@ (%d)"), CFDictionaryGetValue(anItem
, CFSTR("Description")), aPID
);
85 * If the item failed to start, then add it to the
88 if (WEXITSTATUS(aStatus
) || WTERMSIG(aStatus
) || WCOREDUMP(aStatus
)) {
89 CFDictionarySetValue(anItem
, kErrorKey
, kErrorReturnNonZero
);
90 AddItemToFailedList(aStartupContext
, anItem
);
93 * Remove the item from the waiting list regardless
94 * if it was successful or it failed.
96 RemoveItemFromWaitingList(aStartupContext
, anItem
);
99 if (aTerminationContext
)
100 free(aTerminationContext
);
104 MonitorStartupItem(StartupContext aStartupContext
, CFMutableDictionaryRef anItem
)
106 pid_t aPID
= StartupItemGetPID(anItem
);
107 if (anItem
&& aPID
> 0) {
109 kern_return_t aResult
;
110 CFMachPortContext aContext
;
111 CFMachPortRef aMachPort
;
112 CFRunLoopSourceRef aSource
;
113 TerminationContext aTerminationContext
= (TerminationContext
) malloc(sizeof(struct TerminationContextStorage
));
115 aTerminationContext
->aStartupContext
= aStartupContext
;
116 aTerminationContext
->anItem
= anItem
;
118 aContext
.version
= 0;
119 aContext
.info
= aTerminationContext
;
121 aContext
.release
= 0;
123 if ((aResult
= task_name_for_pid(mach_task_self(), aPID
, &aPort
)) != KERN_SUCCESS
)
126 if (!(aMachPort
= CFMachPortCreateWithPort(NULL
, aPort
, NULL
, &aContext
, NULL
)))
129 if (!(aSource
= CFMachPortCreateRunLoopSource(NULL
, aMachPort
, 0))) {
130 CFRelease(aMachPort
);
133 CFMachPortSetInvalidationCallBack(aMachPort
, startupItemTerminated
);
134 CFRunLoopAddSource(CFRunLoopGetCurrent(), aSource
, kCFRunLoopCommonModes
);
136 CFRelease(aMachPort
);
140 * The assumption is something failed, the task already
143 startupItemTerminated(NULL
, aTerminationContext
);