Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/openlaunchd
Path: blob/master/SystemStarter/IPC.c
374 views
1
/**
2
* IPC.c - System Starter IPC routines
3
* Wilfredo Sanchez | [email protected]
4
* Kevin Van Vechten | [email protected]
5
* $Apple$
6
**
7
* Copyright (c) 1999-2002 Apple Computer, Inc. All rights reserved.
8
*
9
* @APPLE_APACHE_LICENSE_HEADER_START@
10
*
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
14
*
15
* http://www.apache.org/licenses/LICENSE-2.0
16
*
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.
22
*
23
* @APPLE_APACHE_LICENSE_HEADER_END@
24
**/
25
26
#include <sys/wait.h>
27
#include <mach/mach.h>
28
#include <mach/message.h>
29
#include <mach/mach_error.h>
30
#include <CoreFoundation/CoreFoundation.h>
31
#include <syslog.h>
32
33
#include "bootstrap.h"
34
35
#include "IPC.h"
36
#include "StartupItems.h"
37
#include "SystemStarter.h"
38
#include "SystemStarterIPC.h"
39
40
/* Structure to pass StartupContext and anItem to the termination handler. */
41
typedef struct TerminationContextStorage {
42
StartupContext aStartupContext;
43
CFMutableDictionaryRef anItem;
44
} *TerminationContext;
45
46
/**
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.
50
**/
51
static void
52
startupItemTerminated(CFMachPortRef aMachPort, void *anInfo)
53
{
54
TerminationContext aTerminationContext = (TerminationContext) anInfo;
55
56
if (aMachPort) {
57
mach_port_deallocate(mach_task_self(), CFMachPortGetPort(aMachPort));
58
}
59
if (aTerminationContext && aTerminationContext->anItem) {
60
pid_t aPID = 0;
61
pid_t rPID = 0;
62
int aStatus = 0;
63
CFMutableDictionaryRef anItem = aTerminationContext->anItem;
64
StartupContext aStartupContext = aTerminationContext->aStartupContext;
65
66
/* Get the exit status */
67
if (anItem) {
68
aPID = StartupItemGetPID(anItem);
69
if (aPID > 0)
70
rPID = waitpid(aPID, &aStatus, 0);
71
}
72
if (aStartupContext) {
73
--aStartupContext->aRunningCount;
74
75
/* Record the item's status */
76
if (aStartupContext->aStatusDict) {
77
StartupItemExit(aStartupContext->aStatusDict, anItem, (WIFEXITED(aStatus) && WEXITSTATUS(aStatus) == 0));
78
if (aStatus) {
79
CF_syslog(LOG_WARNING, CFSTR("%@ (%d) did not complete successfully"), CFDictionaryGetValue(anItem, CFSTR("Description")), aPID);
80
} else {
81
CF_syslog(LOG_DEBUG, CFSTR("Finished %@ (%d)"), CFDictionaryGetValue(anItem, CFSTR("Description")), aPID);
82
}
83
}
84
/*
85
* If the item failed to start, then add it to the
86
* failed list
87
*/
88
if (WEXITSTATUS(aStatus) || WTERMSIG(aStatus) || WCOREDUMP(aStatus)) {
89
CFDictionarySetValue(anItem, kErrorKey, kErrorReturnNonZero);
90
AddItemToFailedList(aStartupContext, anItem);
91
}
92
/*
93
* Remove the item from the waiting list regardless
94
* if it was successful or it failed.
95
*/
96
RemoveItemFromWaitingList(aStartupContext, anItem);
97
}
98
}
99
if (aTerminationContext)
100
free(aTerminationContext);
101
}
102
103
void
104
MonitorStartupItem(StartupContext aStartupContext, CFMutableDictionaryRef anItem)
105
{
106
pid_t aPID = StartupItemGetPID(anItem);
107
if (anItem && aPID > 0) {
108
mach_port_t aPort;
109
kern_return_t aResult;
110
CFMachPortContext aContext;
111
CFMachPortRef aMachPort;
112
CFRunLoopSourceRef aSource;
113
TerminationContext aTerminationContext = (TerminationContext) malloc(sizeof(struct TerminationContextStorage));
114
115
aTerminationContext->aStartupContext = aStartupContext;
116
aTerminationContext->anItem = anItem;
117
118
aContext.version = 0;
119
aContext.info = aTerminationContext;
120
aContext.retain = 0;
121
aContext.release = 0;
122
123
if ((aResult = task_name_for_pid(mach_task_self(), aPID, &aPort)) != KERN_SUCCESS)
124
goto out_bad;
125
126
if (!(aMachPort = CFMachPortCreateWithPort(NULL, aPort, NULL, &aContext, NULL)))
127
goto out_bad;
128
129
if (!(aSource = CFMachPortCreateRunLoopSource(NULL, aMachPort, 0))) {
130
CFRelease(aMachPort);
131
goto out_bad;
132
}
133
CFMachPortSetInvalidationCallBack(aMachPort, startupItemTerminated);
134
CFRunLoopAddSource(CFRunLoopGetCurrent(), aSource, kCFRunLoopCommonModes);
135
CFRelease(aSource);
136
CFRelease(aMachPort);
137
return;
138
out_bad:
139
/*
140
* The assumption is something failed, the task already
141
* terminated.
142
*/
143
startupItemTerminated(NULL, aTerminationContext);
144
}
145
}
146
147