]>
Commit | Line | Data |
---|---|---|
ed34e3c3 A |
1 | /* |
2 | * Copyright (c) 1999-2005 Apple Computer, Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_APACHE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * Licensed under the Apache License, Version 2.0 (the "License"); | |
7 | * you may not use this file except in compliance with the License. | |
8 | * You may obtain a copy of the License at | |
9 | * | |
10 | * http://www.apache.org/licenses/LICENSE-2.0 | |
11 | * | |
12 | * Unless required by applicable law or agreed to in writing, software | |
13 | * distributed under the License is distributed on an "AS IS" BASIS, | |
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
15 | * See the License for the specific language governing permissions and | |
16 | * limitations under the License. | |
17 | * | |
18 | * @APPLE_APACHE_LICENSE_HEADER_END@ | |
19 | */ | |
20 | ||
21 | #include <mach/mach.h> | |
22 | #include <mach/vm_map.h> | |
23 | ||
24 | #include "bootstrap_public.h" | |
25 | #include "bootstrap_private.h" | |
26 | #include "launch.h" | |
27 | #include "launch_priv.h" | |
28 | ||
29 | #define mig_external static | |
30 | #include "bootstrap.h" | |
31 | #include "bootstrapUser.c" | |
32 | ||
33 | #include <sys/param.h> | |
34 | #include <stdlib.h> | |
35 | #include <errno.h> | |
36 | ||
37 | kern_return_t | |
38 | _launchd_to_launchd(mach_port_t bp, mach_port_t *reqport, mach_port_t *rcvright, | |
39 | name_array_t *service_names, mach_msg_type_number_t *service_namesCnt, | |
40 | mach_port_array_t *ports, mach_msg_type_number_t *portCnt) | |
41 | { | |
42 | return raw_bootstrap_transfer_subset(bp, reqport, rcvright, service_names, service_namesCnt, ports, portCnt); | |
43 | } | |
44 | ||
45 | pid_t | |
46 | _spawn_via_launchd(const char *label, const char *const *argv, const struct spawn_via_launchd_attr *spawn_attrs, int struct_version) | |
47 | { | |
48 | kern_return_t kr; | |
49 | const char *const *tmpp; | |
50 | size_t len, buf_len = strlen(label) + 1; | |
51 | char *buf = strdup(label); | |
52 | uint64_t flags = 0; | |
53 | uint32_t argc = 0; | |
54 | uint32_t envc = 0; | |
55 | pid_t p = -1; | |
56 | mode_t u_mask = CMASK; | |
57 | mach_port_t obsvr_port = MACH_PORT_NULL; | |
58 | ||
59 | for (tmpp = argv; *tmpp; tmpp++) { | |
60 | argc++; | |
61 | len = strlen(*tmpp) + 1; | |
62 | buf = reallocf(buf, buf_len + len); | |
63 | strcpy(buf + buf_len, *tmpp); | |
64 | buf_len += len; | |
65 | } | |
66 | ||
67 | if (spawn_attrs) switch (struct_version) { | |
68 | case 0: | |
69 | if (spawn_attrs->spawn_flags & SPAWN_VIA_LAUNCHD_STOPPED) { | |
70 | flags |= SPAWN_WANTS_WAIT4DEBUGGER; | |
71 | } | |
72 | if (spawn_attrs->spawn_flags & SPAWN_VIA_LAUNCHD_FORCE_PPC) { | |
73 | flags |= SPAWN_WANTS_FORCE_PPC; | |
74 | } | |
75 | ||
76 | if (spawn_attrs->spawn_env) { | |
77 | for (tmpp = spawn_attrs->spawn_env; *tmpp; tmpp++) { | |
78 | envc++; | |
79 | len = strlen(*tmpp) + 1; | |
80 | buf = reallocf(buf, buf_len + len); | |
81 | strcpy(buf + buf_len, *tmpp); | |
82 | buf_len += len; | |
83 | } | |
84 | } | |
85 | ||
86 | if (spawn_attrs->spawn_path) { | |
87 | flags |= SPAWN_HAS_PATH; | |
88 | len = strlen(spawn_attrs->spawn_path) + 1; | |
89 | buf = reallocf(buf, buf_len + len); | |
90 | strcpy(buf + buf_len, spawn_attrs->spawn_path); | |
91 | buf_len += len; | |
92 | } | |
93 | ||
94 | if (spawn_attrs->spawn_chdir) { | |
95 | flags |= SPAWN_HAS_WDIR; | |
96 | len = strlen(spawn_attrs->spawn_chdir) + 1; | |
97 | buf = reallocf(buf, buf_len + len); | |
98 | strcpy(buf + buf_len, spawn_attrs->spawn_chdir); | |
99 | buf_len += len; | |
100 | } | |
101 | ||
102 | if (spawn_attrs->spawn_umask) { | |
103 | flags |= SPAWN_HAS_UMASK; | |
104 | u_mask = *spawn_attrs->spawn_umask; | |
105 | } | |
106 | ||
107 | break; | |
108 | default: | |
109 | break; | |
110 | } | |
111 | ||
112 | kr = raw_mpm_spawn(bootstrap_port, buf, buf_len, argc, envc, flags, u_mask, &p, &obsvr_port); | |
113 | ||
114 | free(buf); | |
115 | ||
116 | if (kr == BOOTSTRAP_SUCCESS) { | |
117 | if (spawn_attrs && spawn_attrs->spawn_observer_port) { | |
118 | *spawn_attrs->spawn_observer_port = obsvr_port; | |
119 | } else { | |
120 | mach_port_deallocate(mach_task_self(), obsvr_port); | |
121 | } | |
122 | return p; | |
123 | } | |
124 | ||
125 | switch (kr) { | |
126 | case BOOTSTRAP_NOT_PRIVILEGED: | |
127 | errno = EPERM; break; | |
128 | case BOOTSTRAP_NO_MEMORY: | |
129 | errno = ENOMEM; break; | |
130 | default: | |
131 | errno = EINVAL; break; | |
132 | } | |
133 | return -1; | |
134 | } | |
135 | ||
136 | kern_return_t | |
137 | mpm_wait(mach_port_t ajob, int *wstatus) | |
138 | { | |
139 | return raw_mpm_wait(ajob, wstatus); | |
140 | } | |
141 | ||
142 | kern_return_t | |
143 | mpm_uncork_fork(mach_port_t ajob) | |
144 | { | |
145 | return raw_mpm_uncork_fork(ajob); | |
146 | } | |
147 | ||
148 | kern_return_t | |
149 | bootstrap_create_server(mach_port_t bp, cmd_t server_cmd, uid_t server_uid, boolean_t on_demand, mach_port_t *server_port) | |
150 | { | |
151 | return raw_bootstrap_create_server(bp, server_cmd, server_uid, on_demand, server_port); | |
152 | } | |
153 | ||
154 | kern_return_t | |
155 | bootstrap_subset(mach_port_t bp, mach_port_t requestor_port, mach_port_t *subset_port) | |
156 | { | |
157 | return raw_bootstrap_subset(bp, requestor_port, subset_port); | |
158 | } | |
159 | ||
160 | kern_return_t | |
161 | bootstrap_unprivileged(mach_port_t bp, mach_port_t *unpriv_port) | |
162 | { | |
163 | return raw_bootstrap_unprivileged(bp, unpriv_port); | |
164 | } | |
165 | ||
166 | kern_return_t | |
167 | bootstrap_getsocket(mach_port_t bp, name_t sockpath) | |
168 | { | |
169 | return raw_bootstrap_getsocket(bp, sockpath); | |
170 | } | |
171 | ||
172 | kern_return_t | |
173 | bootstrap_parent(mach_port_t bp, mach_port_t *parent_port) | |
174 | { | |
175 | return raw_bootstrap_parent(bp, parent_port); | |
176 | } | |
177 | ||
178 | kern_return_t | |
179 | bootstrap_register(mach_port_t bp, name_t service_name, mach_port_t sp) | |
180 | { | |
181 | return raw_bootstrap_register(bp, service_name, sp); | |
182 | } | |
183 | ||
184 | kern_return_t | |
185 | bootstrap_create_service(mach_port_t bp, name_t service_name, mach_port_t *sp) | |
186 | { | |
187 | return raw_bootstrap_create_service(bp, service_name, sp); | |
188 | } | |
189 | ||
190 | kern_return_t | |
191 | bootstrap_check_in(mach_port_t bp, name_t service_name, mach_port_t *sp) | |
192 | { | |
193 | return raw_bootstrap_check_in(bp, service_name, sp); | |
194 | } | |
195 | ||
196 | kern_return_t | |
197 | bootstrap_look_up(mach_port_t bp, name_t service_name, mach_port_t *sp) | |
198 | { | |
199 | return raw_bootstrap_look_up(bp, service_name, sp); | |
200 | } | |
201 | ||
202 | kern_return_t | |
203 | bootstrap_look_up_array(mach_port_t bp, | |
204 | name_array_t names, mach_msg_type_number_t name_cnt, | |
205 | mach_port_array_t *ports, mach_msg_type_number_t *port_cnt, | |
206 | boolean_t *all) | |
207 | { | |
208 | unsigned int i; | |
209 | kern_return_t r; | |
210 | ||
211 | if (name_cnt > BOOTSTRAP_MAX_LOOKUP_COUNT) | |
212 | return BOOTSTRAP_BAD_COUNT; | |
213 | ||
214 | *port_cnt = name_cnt; | |
215 | ||
216 | r = vm_allocate(mach_task_self(), (vm_address_t *)&ports, name_cnt * sizeof(mach_port_t), true); | |
217 | ||
218 | if (r != KERN_SUCCESS) | |
219 | return r; | |
220 | ||
221 | *all = true; | |
222 | ||
223 | for (i = 0; i < name_cnt; i++) { | |
224 | if (bootstrap_look_up(bp, names[i], &((*ports)[i])) == BOOTSTRAP_SUCCESS) | |
225 | continue; | |
226 | *all = false; | |
227 | ports[i] = MACH_PORT_NULL; | |
228 | } | |
229 | ||
230 | return BOOTSTRAP_SUCCESS; | |
231 | } | |
232 | ||
233 | kern_return_t | |
234 | bootstrap_status(mach_port_t bp, name_t service_name, bootstrap_status_t *service_active) | |
235 | { | |
236 | mach_port_t p; | |
237 | ||
238 | if (bootstrap_check_in(bp, service_name, &p) == BOOTSTRAP_SUCCESS) { | |
239 | mach_port_mod_refs(mach_task_self(), p, MACH_PORT_RIGHT_RECEIVE, -1); | |
240 | *service_active = BOOTSTRAP_STATUS_ON_DEMAND; | |
241 | if (raw_bootstrap_unprivileged(bp, &p) == BOOTSTRAP_SUCCESS) { | |
242 | if (bp == p) | |
243 | *service_active = BOOTSTRAP_STATUS_INACTIVE; | |
244 | mach_port_deallocate(mach_task_self(), p); | |
245 | } | |
246 | return BOOTSTRAP_SUCCESS; | |
247 | } else if (bootstrap_look_up(bp, service_name, &p) == BOOTSTRAP_SUCCESS) { | |
248 | mach_port_deallocate(mach_task_self(), p); | |
249 | *service_active = BOOTSTRAP_STATUS_ACTIVE; | |
250 | return BOOTSTRAP_SUCCESS; | |
251 | } | |
252 | ||
253 | return BOOTSTRAP_UNKNOWN_SERVICE; | |
254 | } | |
255 | ||
256 | kern_return_t | |
257 | bootstrap_info(mach_port_t bp, | |
258 | name_array_t *service_names, mach_msg_type_number_t *service_namesCnt, | |
259 | bootstrap_status_array_t *service_active, mach_msg_type_number_t *service_activeCnt) | |
260 | { | |
261 | return raw_bootstrap_info(bp, service_names, service_namesCnt, | |
262 | service_active, service_activeCnt); | |
263 | } | |
264 | ||
265 | const char * | |
266 | bootstrap_strerror(kern_return_t r) | |
267 | { | |
268 | switch (r) { | |
269 | case BOOTSTRAP_SUCCESS: | |
270 | return "Success"; | |
271 | case BOOTSTRAP_NOT_PRIVILEGED: | |
272 | return "Permission denied"; | |
273 | case BOOTSTRAP_NAME_IN_USE: | |
274 | case BOOTSTRAP_SERVICE_ACTIVE: | |
275 | return "Service name already exists"; | |
276 | case BOOTSTRAP_UNKNOWN_SERVICE: | |
277 | return "Unknown service name"; | |
278 | case BOOTSTRAP_BAD_COUNT: | |
279 | return "Too many lookups were requested in one request"; | |
280 | case BOOTSTRAP_NO_MEMORY: | |
281 | return "Out of memory"; | |
282 | default: | |
283 | return mach_error_string(r); | |
284 | } | |
285 | } |