]>
Commit | Line | Data |
---|---|---|
e91b9f68 A |
1 | /* |
2 | * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. | |
3 | * | |
ed34e3c3 | 4 | * @APPLE_APACHE_LICENSE_HEADER_START@ |
e91b9f68 | 5 | * |
ed34e3c3 A |
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 | |
e91b9f68 | 9 | * |
ed34e3c3 A |
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 | |
e91b9f68 A |
16 | * limitations under the License. |
17 | * | |
ed34e3c3 | 18 | * @APPLE_APACHE_LICENSE_HEADER_END@ |
e91b9f68 | 19 | */ |
5b0a4722 A |
20 | |
21 | #include "config.h" | |
22 | #include "liblaunch_public.h" | |
23 | #include "liblaunch_private.h" | |
24 | #include "liblaunch_internal.h" | |
25 | ||
ed34e3c3 | 26 | #include <mach/mach.h> |
aa59983a | 27 | #include <libkern/OSByteOrder.h> |
e91b9f68 A |
28 | #include <sys/types.h> |
29 | #include <sys/socket.h> | |
30 | #include <sys/fcntl.h> | |
31 | #include <sys/un.h> | |
32 | #include <sys/uio.h> | |
ed34e3c3 | 33 | #include <sys/stat.h> |
e91b9f68 A |
34 | #include <stdio.h> |
35 | #include <stdlib.h> | |
36 | #include <string.h> | |
37 | #include <pthread.h> | |
38 | #include <unistd.h> | |
39 | #include <errno.h> | |
ed34e3c3 | 40 | #include <pwd.h> |
5b0a4722 | 41 | #include <assert.h> |
e91b9f68 | 42 | |
5b0a4722 A |
43 | #include "libbootstrap_public.h" |
44 | #include "libvproc_public.h" | |
45 | #include "libvproc_private.h" | |
46 | #include "libvproc_internal.h" | |
e91b9f68 | 47 | |
aa59983a A |
48 | /* __OSBogusByteSwap__() must not really exist in the symbol namespace |
49 | * in order for the following to generate an error at build time. | |
50 | */ | |
51 | extern void __OSBogusByteSwap__(void); | |
52 | ||
53 | #define host2big(x) \ | |
54 | ({ typeof (x) _X, _x = (x); \ | |
55 | switch (sizeof(_x)) { \ | |
56 | case 8: \ | |
57 | _X = OSSwapHostToBigInt64(_x); \ | |
58 | break; \ | |
59 | case 4: \ | |
60 | _X = OSSwapHostToBigInt32(_x); \ | |
61 | break; \ | |
62 | case 2: \ | |
63 | _X = OSSwapHostToBigInt16(_x); \ | |
64 | break; \ | |
65 | case 1: \ | |
66 | _X = _x; \ | |
67 | break; \ | |
68 | default: \ | |
69 | __OSBogusByteSwap__(); \ | |
70 | break; \ | |
71 | } \ | |
72 | _X; \ | |
73 | }) | |
74 | ||
75 | ||
76 | #define big2host(x) \ | |
77 | ({ typeof (x) _X, _x = (x); \ | |
78 | switch (sizeof(_x)) { \ | |
79 | case 8: \ | |
80 | _X = OSSwapBigToHostInt64(_x); \ | |
81 | break; \ | |
82 | case 4: \ | |
83 | _X = OSSwapBigToHostInt32(_x); \ | |
84 | break; \ | |
85 | case 2: \ | |
86 | _X = OSSwapBigToHostInt16(_x); \ | |
87 | break; \ | |
88 | case 1: \ | |
89 | _X = _x; \ | |
90 | break; \ | |
91 | default: \ | |
92 | __OSBogusByteSwap__(); \ | |
93 | break; \ | |
94 | } \ | |
95 | _X; \ | |
96 | }) | |
97 | ||
98 | ||
99 | struct launch_msg_header { | |
100 | uint64_t magic; | |
101 | uint64_t len; | |
102 | }; | |
103 | ||
104 | #define LAUNCH_MSG_HEADER_MAGIC 0xD2FEA02366B39A41ull | |
105 | ||
e91b9f68 | 106 | struct _launch_data { |
ed34e3c3 | 107 | uint64_t type; |
e91b9f68 A |
108 | union { |
109 | struct { | |
ed34e3c3 A |
110 | union { |
111 | launch_data_t *_array; | |
112 | char *string; | |
113 | void *opaque; | |
114 | int64_t __junk; | |
115 | }; | |
116 | union { | |
117 | uint64_t _array_cnt; | |
118 | uint64_t string_len; | |
119 | uint64_t opaque_size; | |
120 | }; | |
e91b9f68 A |
121 | }; |
122 | int fd; | |
ed34e3c3 | 123 | mach_port_t mp; |
e91b9f68 A |
124 | int err; |
125 | long long number; | |
5b0a4722 | 126 | uint32_t boolean; /* We'd use 'bool' but this struct needs to be used under Rosetta, and sizeof(bool) is different between PowerPC and Intel */ |
e91b9f68 A |
127 | double float_num; |
128 | }; | |
129 | }; | |
130 | ||
131 | struct _launch { | |
132 | void *sendbuf; | |
ed34e3c3 | 133 | int *sendfds; |
e91b9f68 | 134 | void *recvbuf; |
ed34e3c3 A |
135 | int *recvfds; |
136 | size_t sendlen; | |
137 | size_t sendfdcnt; | |
138 | size_t recvlen; | |
139 | size_t recvfdcnt; | |
140 | int fd; | |
e91b9f68 A |
141 | }; |
142 | ||
ed34e3c3 | 143 | static launch_data_t launch_data_array_pop_first(launch_data_t where); |
e91b9f68 | 144 | static int _fd(int fd); |
ed34e3c3 A |
145 | static void launch_client_init(void); |
146 | static void launch_msg_getmsgs(launch_data_t m, void *context); | |
147 | static launch_data_t launch_msg_internal(launch_data_t d); | |
148 | static void launch_mach_checkin_service(launch_data_t obj, const char *key, void *context); | |
e91b9f68 | 149 | |
f36da725 | 150 | static launch_t in_flight_msg_recv_client; |
e91b9f68 A |
151 | static pthread_once_t _lc_once = PTHREAD_ONCE_INIT; |
152 | ||
153 | static struct _launch_client { | |
154 | pthread_mutex_t mtx; | |
155 | launch_t l; | |
156 | launch_data_t async_resp; | |
157 | } *_lc = NULL; | |
158 | ||
ed34e3c3 A |
159 | void |
160 | launch_client_init(void) | |
e91b9f68 A |
161 | { |
162 | struct sockaddr_un sun; | |
163 | char *where = getenv(LAUNCHD_SOCKET_ENV); | |
164 | char *_launchd_fd = getenv(LAUNCHD_TRUSTED_FD_ENV); | |
ed34e3c3 | 165 | int dfd, lfd = -1; |
5b0a4722 | 166 | name_t spath; |
e91b9f68 A |
167 | |
168 | _lc = calloc(1, sizeof(struct _launch_client)); | |
169 | ||
170 | if (!_lc) | |
171 | return; | |
172 | ||
173 | pthread_mutex_init(&_lc->mtx, NULL); | |
174 | ||
175 | if (_launchd_fd) { | |
176 | lfd = strtol(_launchd_fd, NULL, 10); | |
177 | if ((dfd = dup(lfd)) >= 0) { | |
ed34e3c3 | 178 | close(dfd); |
e91b9f68 A |
179 | _fd(lfd); |
180 | } else { | |
181 | lfd = -1; | |
182 | } | |
183 | unsetenv(LAUNCHD_TRUSTED_FD_ENV); | |
184 | } | |
185 | if (lfd == -1) { | |
186 | memset(&sun, 0, sizeof(sun)); | |
187 | sun.sun_family = AF_UNIX; | |
188 | ||
ed34e3c3 | 189 | if (where && where[0] != '\0') { |
e91b9f68 | 190 | strncpy(sun.sun_path, where, sizeof(sun.sun_path)); |
5b0a4722 A |
191 | } else if (!getenv("SUDO_COMMAND") && _vprocmgr_getsocket(spath) == 0) { |
192 | size_t min_len; | |
193 | ||
194 | min_len = sizeof(sun.sun_path) < sizeof(spath) ? sizeof(sun.sun_path) : sizeof(spath); | |
195 | ||
196 | strncpy(sun.sun_path, spath, min_len); | |
ed34e3c3 | 197 | } else { |
5b0a4722 | 198 | strncpy(sun.sun_path, LAUNCHD_SOCK_PREFIX "/sock", sizeof(sun.sun_path)); |
e91b9f68 | 199 | } |
ed34e3c3 A |
200 | |
201 | if ((lfd = _fd(socket(AF_UNIX, SOCK_STREAM, 0))) == -1) | |
202 | goto out_bad; | |
203 | if (-1 == connect(lfd, (struct sockaddr *)&sun, sizeof(sun))) | |
e91b9f68 | 204 | goto out_bad; |
e91b9f68 | 205 | } |
ed34e3c3 | 206 | if (!(_lc->l = launchd_fdopen(lfd))) |
e91b9f68 | 207 | goto out_bad; |
e91b9f68 A |
208 | if (!(_lc->async_resp = launch_data_alloc(LAUNCH_DATA_ARRAY))) |
209 | goto out_bad; | |
210 | ||
211 | return; | |
212 | out_bad: | |
213 | if (_lc->l) | |
5b0a4722 | 214 | launchd_close(_lc->l, close); |
ed34e3c3 A |
215 | else if (lfd != -1) |
216 | close(lfd); | |
e91b9f68 A |
217 | if (_lc) |
218 | free(_lc); | |
219 | _lc = NULL; | |
220 | } | |
221 | ||
ed34e3c3 A |
222 | launch_data_t |
223 | launch_data_alloc(launch_data_type_t t) | |
e91b9f68 A |
224 | { |
225 | launch_data_t d = calloc(1, sizeof(struct _launch)); | |
226 | ||
227 | if (d) { | |
228 | d->type = t; | |
229 | switch (t) { | |
230 | case LAUNCH_DATA_DICTIONARY: | |
231 | case LAUNCH_DATA_ARRAY: | |
232 | d->_array = malloc(0); | |
233 | break; | |
234 | default: | |
235 | break; | |
236 | } | |
237 | } | |
238 | ||
239 | return d; | |
240 | } | |
241 | ||
ed34e3c3 A |
242 | launch_data_type_t |
243 | launch_data_get_type(launch_data_t d) | |
e91b9f68 A |
244 | { |
245 | return d->type; | |
246 | } | |
247 | ||
ed34e3c3 A |
248 | void |
249 | launch_data_free(launch_data_t d) | |
e91b9f68 A |
250 | { |
251 | size_t i; | |
252 | ||
253 | switch (d->type) { | |
254 | case LAUNCH_DATA_DICTIONARY: | |
255 | case LAUNCH_DATA_ARRAY: | |
256 | for (i = 0; i < d->_array_cnt; i++) | |
257 | launch_data_free(d->_array[i]); | |
258 | free(d->_array); | |
259 | break; | |
260 | case LAUNCH_DATA_STRING: | |
261 | if (d->string) | |
262 | free(d->string); | |
263 | break; | |
264 | case LAUNCH_DATA_OPAQUE: | |
265 | if (d->opaque) | |
266 | free(d->opaque); | |
267 | break; | |
268 | default: | |
269 | break; | |
270 | } | |
271 | free(d); | |
272 | } | |
273 | ||
ed34e3c3 A |
274 | size_t |
275 | launch_data_dict_get_count(launch_data_t dict) | |
e91b9f68 A |
276 | { |
277 | return dict->_array_cnt / 2; | |
278 | } | |
279 | ||
280 | ||
ed34e3c3 A |
281 | bool |
282 | launch_data_dict_insert(launch_data_t dict, launch_data_t what, const char *key) | |
e91b9f68 A |
283 | { |
284 | size_t i; | |
ed34e3c3 | 285 | launch_data_t thekey = launch_data_alloc(LAUNCH_DATA_STRING); |
e91b9f68 | 286 | |
ed34e3c3 | 287 | launch_data_set_string(thekey, key); |
e91b9f68 A |
288 | |
289 | for (i = 0; i < dict->_array_cnt; i += 2) { | |
290 | if (!strcasecmp(key, dict->_array[i]->string)) { | |
291 | launch_data_array_set_index(dict, thekey, i); | |
292 | launch_data_array_set_index(dict, what, i + 1); | |
293 | return true; | |
294 | } | |
295 | } | |
296 | launch_data_array_set_index(dict, thekey, i); | |
297 | launch_data_array_set_index(dict, what, i + 1); | |
298 | return true; | |
299 | } | |
300 | ||
ed34e3c3 A |
301 | launch_data_t |
302 | launch_data_dict_lookup(launch_data_t dict, const char *key) | |
e91b9f68 A |
303 | { |
304 | size_t i; | |
305 | ||
ed34e3c3 | 306 | if (LAUNCH_DATA_DICTIONARY != dict->type) |
e91b9f68 A |
307 | return NULL; |
308 | ||
309 | for (i = 0; i < dict->_array_cnt; i += 2) { | |
310 | if (!strcasecmp(key, dict->_array[i]->string)) | |
311 | return dict->_array[i + 1]; | |
312 | } | |
313 | ||
314 | return NULL; | |
315 | } | |
316 | ||
ed34e3c3 A |
317 | bool |
318 | launch_data_dict_remove(launch_data_t dict, const char *key) | |
e91b9f68 A |
319 | { |
320 | size_t i; | |
321 | ||
322 | for (i = 0; i < dict->_array_cnt; i += 2) { | |
323 | if (!strcasecmp(key, dict->_array[i]->string)) | |
324 | break; | |
325 | } | |
326 | if (i == dict->_array_cnt) | |
327 | return false; | |
328 | launch_data_free(dict->_array[i]); | |
329 | launch_data_free(dict->_array[i + 1]); | |
330 | memmove(dict->_array + i, dict->_array + i + 2, (dict->_array_cnt - (i + 2)) * sizeof(launch_data_t)); | |
331 | dict->_array_cnt -= 2; | |
332 | return true; | |
333 | } | |
334 | ||
ed34e3c3 A |
335 | void |
336 | launch_data_dict_iterate(launch_data_t dict, void (*cb)(launch_data_t, const char *, void *), void *context) | |
e91b9f68 A |
337 | { |
338 | size_t i; | |
339 | ||
ed34e3c3 | 340 | if (LAUNCH_DATA_DICTIONARY != dict->type) |
e91b9f68 A |
341 | return; |
342 | ||
343 | for (i = 0; i < dict->_array_cnt; i += 2) | |
344 | cb(dict->_array[i + 1], dict->_array[i]->string, context); | |
345 | } | |
346 | ||
ed34e3c3 A |
347 | bool |
348 | launch_data_array_set_index(launch_data_t where, launch_data_t what, size_t ind) | |
e91b9f68 A |
349 | { |
350 | if ((ind + 1) >= where->_array_cnt) { | |
5b0a4722 | 351 | where->_array = reallocf(where->_array, (ind + 1) * sizeof(launch_data_t)); |
e91b9f68 A |
352 | memset(where->_array + where->_array_cnt, 0, (ind + 1 - where->_array_cnt) * sizeof(launch_data_t)); |
353 | where->_array_cnt = ind + 1; | |
354 | } | |
355 | ||
356 | if (where->_array[ind]) | |
357 | launch_data_free(where->_array[ind]); | |
358 | where->_array[ind] = what; | |
359 | return true; | |
360 | } | |
361 | ||
ed34e3c3 A |
362 | launch_data_t |
363 | launch_data_array_get_index(launch_data_t where, size_t ind) | |
e91b9f68 | 364 | { |
ed34e3c3 | 365 | if (LAUNCH_DATA_ARRAY != where->type) |
e91b9f68 A |
366 | return NULL; |
367 | if (ind < where->_array_cnt) | |
368 | return where->_array[ind]; | |
369 | return NULL; | |
370 | } | |
371 | ||
ed34e3c3 A |
372 | launch_data_t |
373 | launch_data_array_pop_first(launch_data_t where) | |
e91b9f68 A |
374 | { |
375 | launch_data_t r = NULL; | |
5b0a4722 | 376 | |
e91b9f68 A |
377 | if (where->_array_cnt > 0) { |
378 | r = where->_array[0]; | |
379 | memmove(where->_array, where->_array + 1, (where->_array_cnt - 1) * sizeof(launch_data_t)); | |
380 | where->_array_cnt--; | |
381 | } | |
382 | return r; | |
383 | } | |
384 | ||
ed34e3c3 A |
385 | size_t |
386 | launch_data_array_get_count(launch_data_t where) | |
e91b9f68 | 387 | { |
ed34e3c3 | 388 | if (LAUNCH_DATA_ARRAY != where->type) |
e91b9f68 A |
389 | return 0; |
390 | return where->_array_cnt; | |
391 | } | |
392 | ||
ed34e3c3 A |
393 | bool |
394 | launch_data_set_errno(launch_data_t d, int e) | |
e91b9f68 A |
395 | { |
396 | d->err = e; | |
397 | return true; | |
398 | } | |
399 | ||
ed34e3c3 A |
400 | bool |
401 | launch_data_set_fd(launch_data_t d, int fd) | |
e91b9f68 A |
402 | { |
403 | d->fd = fd; | |
404 | return true; | |
405 | } | |
406 | ||
ed34e3c3 A |
407 | bool |
408 | launch_data_set_machport(launch_data_t d, mach_port_t p) | |
409 | { | |
410 | d->mp = p; | |
411 | return true; | |
412 | } | |
413 | ||
414 | bool | |
415 | launch_data_set_integer(launch_data_t d, long long n) | |
e91b9f68 A |
416 | { |
417 | d->number = n; | |
418 | return true; | |
419 | } | |
420 | ||
ed34e3c3 A |
421 | bool |
422 | launch_data_set_bool(launch_data_t d, bool b) | |
e91b9f68 A |
423 | { |
424 | d->boolean = b; | |
425 | return true; | |
426 | } | |
427 | ||
ed34e3c3 A |
428 | bool |
429 | launch_data_set_real(launch_data_t d, double n) | |
e91b9f68 A |
430 | { |
431 | d->float_num = n; | |
432 | return true; | |
433 | } | |
434 | ||
ed34e3c3 A |
435 | bool |
436 | launch_data_set_string(launch_data_t d, const char *s) | |
e91b9f68 A |
437 | { |
438 | if (d->string) | |
439 | free(d->string); | |
440 | d->string = strdup(s); | |
441 | if (d->string) { | |
442 | d->string_len = strlen(d->string); | |
443 | return true; | |
444 | } | |
445 | return false; | |
446 | } | |
447 | ||
ed34e3c3 A |
448 | bool |
449 | launch_data_set_opaque(launch_data_t d, const void *o, size_t os) | |
e91b9f68 A |
450 | { |
451 | d->opaque_size = os; | |
452 | if (d->opaque) | |
453 | free(d->opaque); | |
454 | d->opaque = malloc(os); | |
455 | if (d->opaque) { | |
456 | memcpy(d->opaque, o, os); | |
457 | return true; | |
458 | } | |
459 | return false; | |
460 | } | |
461 | ||
ed34e3c3 A |
462 | int |
463 | launch_data_get_errno(launch_data_t d) | |
e91b9f68 A |
464 | { |
465 | return d->err; | |
466 | } | |
467 | ||
ed34e3c3 A |
468 | int |
469 | launch_data_get_fd(launch_data_t d) | |
e91b9f68 A |
470 | { |
471 | return d->fd; | |
472 | } | |
473 | ||
ed34e3c3 A |
474 | mach_port_t |
475 | launch_data_get_machport(launch_data_t d) | |
476 | { | |
477 | return d->mp; | |
478 | } | |
479 | ||
480 | long long | |
481 | launch_data_get_integer(launch_data_t d) | |
e91b9f68 A |
482 | { |
483 | return d->number; | |
484 | } | |
485 | ||
ed34e3c3 A |
486 | bool |
487 | launch_data_get_bool(launch_data_t d) | |
e91b9f68 A |
488 | { |
489 | return d->boolean; | |
490 | } | |
491 | ||
ed34e3c3 A |
492 | double |
493 | launch_data_get_real(launch_data_t d) | |
e91b9f68 A |
494 | { |
495 | return d->float_num; | |
496 | } | |
497 | ||
ed34e3c3 A |
498 | const char * |
499 | launch_data_get_string(launch_data_t d) | |
e91b9f68 | 500 | { |
ed34e3c3 | 501 | if (LAUNCH_DATA_STRING != d->type) |
e91b9f68 A |
502 | return NULL; |
503 | return d->string; | |
504 | } | |
505 | ||
ed34e3c3 A |
506 | void * |
507 | launch_data_get_opaque(launch_data_t d) | |
e91b9f68 | 508 | { |
ed34e3c3 | 509 | if (LAUNCH_DATA_OPAQUE != d->type) |
e91b9f68 A |
510 | return NULL; |
511 | return d->opaque; | |
512 | } | |
513 | ||
ed34e3c3 A |
514 | size_t |
515 | launch_data_get_opaque_size(launch_data_t d) | |
e91b9f68 A |
516 | { |
517 | return d->opaque_size; | |
518 | } | |
519 | ||
ed34e3c3 A |
520 | int |
521 | launchd_getfd(launch_t l) | |
e91b9f68 A |
522 | { |
523 | return l->fd; | |
524 | } | |
525 | ||
ed34e3c3 A |
526 | launch_t |
527 | launchd_fdopen(int fd) | |
e91b9f68 | 528 | { |
5b0a4722 | 529 | launch_t c; |
e91b9f68 | 530 | |
5b0a4722 | 531 | c = calloc(1, sizeof(struct _launch)); |
e91b9f68 A |
532 | if (!c) |
533 | return NULL; | |
534 | ||
5b0a4722 | 535 | c->fd = fd; |
e91b9f68 | 536 | |
ed34e3c3 | 537 | fcntl(fd, F_SETFL, O_NONBLOCK); |
e91b9f68 | 538 | |
5b0a4722 | 539 | if ((c->sendbuf = malloc(0)) == NULL) |
e91b9f68 | 540 | goto out_bad; |
5b0a4722 | 541 | if ((c->sendfds = malloc(0)) == NULL) |
e91b9f68 | 542 | goto out_bad; |
5b0a4722 | 543 | if ((c->recvbuf = malloc(0)) == NULL) |
e91b9f68 | 544 | goto out_bad; |
5b0a4722 | 545 | if ((c->recvfds = malloc(0)) == NULL) |
e91b9f68 A |
546 | goto out_bad; |
547 | ||
548 | return c; | |
549 | ||
550 | out_bad: | |
551 | if (c->sendbuf) | |
552 | free(c->sendbuf); | |
553 | if (c->sendfds) | |
554 | free(c->sendfds); | |
555 | if (c->recvbuf) | |
556 | free(c->recvbuf); | |
557 | if (c->recvfds) | |
558 | free(c->recvfds); | |
559 | free(c); | |
560 | return NULL; | |
561 | } | |
562 | ||
ed34e3c3 | 563 | void |
5b0a4722 | 564 | launchd_close(launch_t lh, typeof(close) closefunc) |
e91b9f68 | 565 | { |
f36da725 A |
566 | if (in_flight_msg_recv_client == lh) { |
567 | in_flight_msg_recv_client = NULL; | |
568 | } | |
569 | ||
e91b9f68 A |
570 | if (lh->sendbuf) |
571 | free(lh->sendbuf); | |
572 | if (lh->sendfds) | |
573 | free(lh->sendfds); | |
574 | if (lh->recvbuf) | |
575 | free(lh->recvbuf); | |
576 | if (lh->recvfds) | |
577 | free(lh->recvfds); | |
5b0a4722 | 578 | closefunc(lh->fd); |
e91b9f68 A |
579 | free(lh); |
580 | } | |
581 | ||
5b0a4722 A |
582 | #define ROUND_TO_64BIT_WORD_SIZE(x) ((x + 7) & ~7) |
583 | ||
584 | size_t | |
585 | launch_data_pack(launch_data_t d, void *where, size_t len, int *fd_where, size_t *fd_cnt) | |
e91b9f68 | 586 | { |
5b0a4722 A |
587 | launch_data_t o_in_w = where; |
588 | size_t i, rsz, total_data_len = sizeof(struct _launch_data); | |
e91b9f68 | 589 | |
5b0a4722 A |
590 | if (total_data_len > len) { |
591 | return 0; | |
592 | } | |
aa59983a | 593 | |
5b0a4722 | 594 | where += total_data_len; |
e91b9f68 | 595 | |
aa59983a A |
596 | o_in_w->type = host2big(d->type); |
597 | ||
e91b9f68 | 598 | switch (d->type) { |
aa59983a A |
599 | case LAUNCH_DATA_INTEGER: |
600 | o_in_w->number = host2big(d->number); | |
601 | break; | |
602 | case LAUNCH_DATA_REAL: | |
603 | o_in_w->float_num = host2big(d->float_num); | |
604 | break; | |
605 | case LAUNCH_DATA_BOOL: | |
606 | o_in_w->boolean = host2big(d->boolean); | |
607 | break; | |
608 | case LAUNCH_DATA_ERRNO: | |
609 | o_in_w->err = host2big(d->err); | |
610 | break; | |
e91b9f68 | 611 | case LAUNCH_DATA_FD: |
aa59983a | 612 | o_in_w->fd = host2big(d->fd); |
5b0a4722 A |
613 | if (fd_where && d->fd != -1) { |
614 | fd_where[*fd_cnt] = d->fd; | |
615 | (*fd_cnt)++; | |
e91b9f68 A |
616 | } |
617 | break; | |
618 | case LAUNCH_DATA_STRING: | |
aa59983a | 619 | o_in_w->string_len = host2big(d->string_len); |
5b0a4722 A |
620 | total_data_len += ROUND_TO_64BIT_WORD_SIZE(strlen(d->string) + 1); |
621 | if (total_data_len > len) { | |
622 | return 0; | |
623 | } | |
624 | memcpy(where, d->string, strlen(d->string) + 1); | |
e91b9f68 A |
625 | break; |
626 | case LAUNCH_DATA_OPAQUE: | |
aa59983a | 627 | o_in_w->opaque_size = host2big(d->opaque_size); |
5b0a4722 A |
628 | total_data_len += ROUND_TO_64BIT_WORD_SIZE(d->opaque_size); |
629 | if (total_data_len > len) { | |
630 | return 0; | |
631 | } | |
632 | memcpy(where, d->opaque, d->opaque_size); | |
e91b9f68 A |
633 | break; |
634 | case LAUNCH_DATA_DICTIONARY: | |
635 | case LAUNCH_DATA_ARRAY: | |
aa59983a | 636 | o_in_w->_array_cnt = host2big(d->_array_cnt); |
5b0a4722 A |
637 | total_data_len += d->_array_cnt * sizeof(uint64_t); |
638 | if (total_data_len > len) { | |
639 | return 0; | |
640 | } | |
e91b9f68 | 641 | |
5b0a4722 A |
642 | where += d->_array_cnt * sizeof(uint64_t); |
643 | ||
644 | for (i = 0; i < d->_array_cnt; i++) { | |
645 | rsz = launch_data_pack(d->_array[i], where, len - total_data_len, fd_where, fd_cnt); | |
646 | if (rsz == 0) { | |
647 | return 0; | |
648 | } | |
649 | where += rsz; | |
650 | total_data_len += rsz; | |
651 | } | |
e91b9f68 A |
652 | break; |
653 | default: | |
654 | break; | |
655 | } | |
5b0a4722 A |
656 | |
657 | return total_data_len; | |
e91b9f68 A |
658 | } |
659 | ||
5b0a4722 A |
660 | launch_data_t |
661 | launch_data_unpack(void *data, size_t data_size, int *fds, size_t fd_cnt, size_t *data_offset, size_t *fdoffset) | |
e91b9f68 | 662 | { |
5b0a4722 | 663 | launch_data_t r = data + *data_offset; |
aa59983a | 664 | size_t i, tmpcnt; |
e91b9f68 | 665 | |
5b0a4722 | 666 | if ((data_size - *data_offset) < sizeof(struct _launch_data)) |
e91b9f68 A |
667 | return NULL; |
668 | *data_offset += sizeof(struct _launch_data); | |
669 | ||
aa59983a | 670 | switch (big2host(r->type)) { |
e91b9f68 A |
671 | case LAUNCH_DATA_DICTIONARY: |
672 | case LAUNCH_DATA_ARRAY: | |
aa59983a | 673 | tmpcnt = big2host(r->_array_cnt); |
5b0a4722 | 674 | if ((data_size - *data_offset) < (tmpcnt * sizeof(uint64_t))) { |
e91b9f68 A |
675 | errno = EAGAIN; |
676 | return NULL; | |
677 | } | |
5b0a4722 A |
678 | r->_array = data + *data_offset; |
679 | *data_offset += tmpcnt * sizeof(uint64_t); | |
aa59983a | 680 | for (i = 0; i < tmpcnt; i++) { |
5b0a4722 | 681 | r->_array[i] = launch_data_unpack(data, data_size, fds, fd_cnt, data_offset, fdoffset); |
e91b9f68 A |
682 | if (r->_array[i] == NULL) |
683 | return NULL; | |
684 | } | |
aa59983a | 685 | r->_array_cnt = tmpcnt; |
e91b9f68 A |
686 | break; |
687 | case LAUNCH_DATA_STRING: | |
aa59983a | 688 | tmpcnt = big2host(r->string_len); |
5b0a4722 | 689 | if ((data_size - *data_offset) < (tmpcnt + 1)) { |
e91b9f68 A |
690 | errno = EAGAIN; |
691 | return NULL; | |
692 | } | |
5b0a4722 | 693 | r->string = data + *data_offset; |
aa59983a | 694 | r->string_len = tmpcnt; |
5b0a4722 | 695 | *data_offset += ROUND_TO_64BIT_WORD_SIZE(tmpcnt + 1); |
e91b9f68 A |
696 | break; |
697 | case LAUNCH_DATA_OPAQUE: | |
aa59983a | 698 | tmpcnt = big2host(r->opaque_size); |
5b0a4722 | 699 | if ((data_size - *data_offset) < tmpcnt) { |
e91b9f68 A |
700 | errno = EAGAIN; |
701 | return NULL; | |
702 | } | |
5b0a4722 | 703 | r->opaque = data + *data_offset; |
aa59983a | 704 | r->opaque_size = tmpcnt; |
5b0a4722 | 705 | *data_offset += ROUND_TO_64BIT_WORD_SIZE(tmpcnt); |
e91b9f68 A |
706 | break; |
707 | case LAUNCH_DATA_FD: | |
5b0a4722 A |
708 | if (r->fd != -1 && fd_cnt > *fdoffset) { |
709 | r->fd = _fd(fds[*fdoffset]); | |
e91b9f68 A |
710 | *fdoffset += 1; |
711 | } | |
712 | break; | |
713 | case LAUNCH_DATA_INTEGER: | |
aa59983a A |
714 | r->number = big2host(r->number); |
715 | break; | |
e91b9f68 | 716 | case LAUNCH_DATA_REAL: |
aa59983a A |
717 | r->float_num = big2host(r->float_num); |
718 | break; | |
e91b9f68 | 719 | case LAUNCH_DATA_BOOL: |
aa59983a A |
720 | r->boolean = big2host(r->boolean); |
721 | break; | |
e91b9f68 | 722 | case LAUNCH_DATA_ERRNO: |
aa59983a | 723 | r->err = big2host(r->err); |
ed34e3c3 | 724 | case LAUNCH_DATA_MACHPORT: |
e91b9f68 A |
725 | break; |
726 | default: | |
727 | errno = EINVAL; | |
728 | return NULL; | |
729 | break; | |
730 | } | |
731 | ||
aa59983a A |
732 | r->type = big2host(r->type); |
733 | ||
e91b9f68 A |
734 | return r; |
735 | } | |
736 | ||
737 | int launchd_msg_send(launch_t lh, launch_data_t d) | |
738 | { | |
aa59983a | 739 | struct launch_msg_header lmh; |
e91b9f68 A |
740 | struct cmsghdr *cm = NULL; |
741 | struct msghdr mh; | |
aa59983a | 742 | struct iovec iov[2]; |
e91b9f68 | 743 | size_t sentctrllen = 0; |
aa59983a | 744 | int r; |
e91b9f68 A |
745 | |
746 | memset(&mh, 0, sizeof(mh)); | |
747 | ||
5b0a4722 A |
748 | /* confirm that the next hack works */ |
749 | assert((d && lh->sendlen == 0) || (!d && lh->sendlen)); | |
750 | ||
aa59983a | 751 | if (d) { |
5b0a4722 A |
752 | size_t fd_slots_used = 0; |
753 | size_t good_enough_size = 10 * 1024 * 1024; | |
754 | uint64_t msglen; | |
755 | ||
756 | /* hack, see the above assert to verify "correctness" */ | |
757 | free(lh->sendbuf); | |
758 | lh->sendbuf = malloc(good_enough_size); | |
759 | free(lh->sendfds); | |
760 | lh->sendfds = malloc(4 * 1024); | |
761 | ||
762 | lh->sendlen = launch_data_pack(d, lh->sendbuf, good_enough_size, lh->sendfds, &fd_slots_used); | |
763 | ||
764 | if (lh->sendlen == 0) { | |
765 | errno = ENOMEM; | |
766 | return -1; | |
767 | } | |
e91b9f68 | 768 | |
5b0a4722 | 769 | lh->sendfdcnt = fd_slots_used; |
e91b9f68 | 770 | |
5b0a4722 | 771 | msglen = lh->sendlen + sizeof(struct launch_msg_header); /* type promotion to make the host2big() macro work right */ |
aa59983a A |
772 | lmh.len = host2big(msglen); |
773 | lmh.magic = host2big(LAUNCH_MSG_HEADER_MAGIC); | |
774 | ||
775 | iov[0].iov_base = &lmh; | |
776 | iov[0].iov_len = sizeof(lmh); | |
777 | mh.msg_iov = iov; | |
5b0a4722 | 778 | mh.msg_iovlen = 2; |
aa59983a A |
779 | } else { |
780 | mh.msg_iov = iov + 1; | |
5b0a4722 | 781 | mh.msg_iovlen = 1; |
aa59983a A |
782 | } |
783 | ||
784 | iov[1].iov_base = lh->sendbuf; | |
785 | iov[1].iov_len = lh->sendlen; | |
786 | ||
787 | ||
e91b9f68 A |
788 | if (lh->sendfdcnt > 0) { |
789 | sentctrllen = mh.msg_controllen = CMSG_SPACE(lh->sendfdcnt * sizeof(int)); | |
790 | cm = alloca(mh.msg_controllen); | |
791 | mh.msg_control = cm; | |
792 | ||
793 | memset(cm, 0, mh.msg_controllen); | |
794 | ||
795 | cm->cmsg_len = CMSG_LEN(lh->sendfdcnt * sizeof(int)); | |
796 | cm->cmsg_level = SOL_SOCKET; | |
797 | cm->cmsg_type = SCM_RIGHTS; | |
798 | ||
799 | memcpy(CMSG_DATA(cm), lh->sendfds, lh->sendfdcnt * sizeof(int)); | |
800 | } | |
801 | ||
ed34e3c3 | 802 | if ((r = sendmsg(lh->fd, &mh, 0)) == -1) { |
e91b9f68 A |
803 | return -1; |
804 | } else if (r == 0) { | |
805 | errno = ECONNRESET; | |
806 | return -1; | |
807 | } else if (sentctrllen != mh.msg_controllen) { | |
808 | errno = ECONNRESET; | |
809 | return -1; | |
810 | } | |
811 | ||
aa59983a A |
812 | if (d) { |
813 | r -= sizeof(struct launch_msg_header); | |
814 | } | |
815 | ||
e91b9f68 A |
816 | lh->sendlen -= r; |
817 | if (lh->sendlen > 0) { | |
818 | memmove(lh->sendbuf, lh->sendbuf + r, lh->sendlen); | |
819 | } else { | |
820 | free(lh->sendbuf); | |
821 | lh->sendbuf = malloc(0); | |
822 | } | |
823 | ||
824 | lh->sendfdcnt = 0; | |
825 | free(lh->sendfds); | |
826 | lh->sendfds = malloc(0); | |
827 | ||
828 | if (lh->sendlen > 0) { | |
829 | errno = EAGAIN; | |
830 | return -1; | |
831 | } | |
832 | ||
833 | return 0; | |
834 | } | |
835 | ||
836 | ||
ed34e3c3 A |
837 | int |
838 | launch_get_fd(void) | |
e91b9f68 A |
839 | { |
840 | pthread_once(&_lc_once, launch_client_init); | |
841 | ||
842 | if (!_lc) { | |
843 | errno = ENOTCONN; | |
844 | return -1; | |
845 | } | |
846 | ||
847 | return _lc->l->fd; | |
848 | } | |
849 | ||
ed34e3c3 A |
850 | void |
851 | launch_msg_getmsgs(launch_data_t m, void *context) | |
e91b9f68 A |
852 | { |
853 | launch_data_t async_resp, *sync_resp = context; | |
854 | ||
855 | if ((LAUNCH_DATA_DICTIONARY == launch_data_get_type(m)) && (async_resp = launch_data_dict_lookup(m, LAUNCHD_ASYNC_MSG_KEY))) { | |
856 | launch_data_array_set_index(_lc->async_resp, launch_data_copy(async_resp), launch_data_array_get_count(_lc->async_resp)); | |
857 | } else { | |
858 | *sync_resp = launch_data_copy(m); | |
859 | } | |
860 | } | |
861 | ||
ed34e3c3 A |
862 | void |
863 | launch_mach_checkin_service(launch_data_t obj, const char *key, void *context __attribute__((unused))) | |
864 | { | |
865 | kern_return_t result; | |
866 | mach_port_t p; | |
867 | name_t srvnm; | |
868 | ||
869 | strlcpy(srvnm, key, sizeof(srvnm)); | |
870 | ||
871 | result = bootstrap_check_in(bootstrap_port, srvnm, &p); | |
872 | ||
873 | if (result == BOOTSTRAP_SUCCESS) | |
874 | launch_data_set_machport(obj, p); | |
875 | } | |
876 | ||
877 | launch_data_t | |
878 | launch_msg(launch_data_t d) | |
879 | { | |
880 | launch_data_t mps, r = launch_msg_internal(d); | |
881 | ||
882 | if (launch_data_get_type(d) == LAUNCH_DATA_STRING) { | |
883 | if (strcmp(launch_data_get_string(d), LAUNCH_KEY_CHECKIN) != 0) | |
884 | return r; | |
885 | if (r == NULL) | |
886 | return r; | |
887 | if (launch_data_get_type(r) != LAUNCH_DATA_DICTIONARY) | |
888 | return r; | |
889 | mps = launch_data_dict_lookup(r, LAUNCH_JOBKEY_MACHSERVICES); | |
890 | if (mps == NULL) | |
891 | return r; | |
892 | launch_data_dict_iterate(mps, launch_mach_checkin_service, NULL); | |
893 | } | |
894 | ||
895 | return r; | |
896 | } | |
897 | ||
898 | launch_data_t | |
899 | launch_msg_internal(launch_data_t d) | |
e91b9f68 A |
900 | { |
901 | launch_data_t resp = NULL; | |
902 | ||
5b0a4722 A |
903 | if (d && (launch_data_get_type(d) == LAUNCH_DATA_STRING) |
904 | && (strcmp(launch_data_get_string(d), LAUNCH_KEY_GETJOBS) == 0) | |
905 | && vproc_swap_complex(NULL, VPROC_GSK_ALLJOBS, NULL, &resp) == NULL) { | |
906 | return resp; | |
907 | } | |
908 | ||
e91b9f68 A |
909 | pthread_once(&_lc_once, launch_client_init); |
910 | ||
911 | if (!_lc) { | |
912 | errno = ENOTCONN; | |
913 | return NULL; | |
914 | } | |
915 | ||
916 | pthread_mutex_lock(&_lc->mtx); | |
917 | ||
918 | if (d && launchd_msg_send(_lc->l, d) == -1) { | |
919 | do { | |
ed34e3c3 | 920 | if (errno != EAGAIN) |
e91b9f68 A |
921 | goto out; |
922 | } while (launchd_msg_send(_lc->l, NULL) == -1); | |
923 | } | |
5b0a4722 | 924 | |
e91b9f68 A |
925 | while (resp == NULL) { |
926 | if (d == NULL && launch_data_array_get_count(_lc->async_resp) > 0) { | |
927 | resp = launch_data_array_pop_first(_lc->async_resp); | |
928 | goto out; | |
929 | } | |
930 | if (launchd_msg_recv(_lc->l, launch_msg_getmsgs, &resp) == -1) { | |
ed34e3c3 | 931 | if (errno != EAGAIN) { |
e91b9f68 A |
932 | goto out; |
933 | } else if (d == NULL) { | |
934 | errno = 0; | |
935 | goto out; | |
936 | } else { | |
937 | fd_set rfds; | |
938 | ||
939 | FD_ZERO(&rfds); | |
940 | FD_SET(_lc->l->fd, &rfds); | |
941 | ||
ed34e3c3 | 942 | select(_lc->l->fd + 1, &rfds, NULL, NULL, NULL); |
e91b9f68 A |
943 | } |
944 | } | |
945 | } | |
946 | ||
947 | out: | |
948 | pthread_mutex_unlock(&_lc->mtx); | |
949 | ||
950 | return resp; | |
951 | } | |
952 | ||
953 | int launchd_msg_recv(launch_t lh, void (*cb)(launch_data_t, void *), void *context) | |
954 | { | |
955 | struct cmsghdr *cm = alloca(4096); | |
aa59983a | 956 | launch_data_t rmsg = NULL; |
e91b9f68 | 957 | size_t data_offset, fd_offset; |
5b0a4722 A |
958 | struct msghdr mh; |
959 | struct iovec iov; | |
e91b9f68 A |
960 | int r; |
961 | ||
5b0a4722 A |
962 | memset(&mh, 0, sizeof(mh)); |
963 | mh.msg_iov = &iov; | |
964 | mh.msg_iovlen = 1; | |
e91b9f68 | 965 | |
5b0a4722 | 966 | lh->recvbuf = reallocf(lh->recvbuf, lh->recvlen + 8*1024); |
e91b9f68 A |
967 | |
968 | iov.iov_base = lh->recvbuf + lh->recvlen; | |
969 | iov.iov_len = 8*1024; | |
970 | mh.msg_control = cm; | |
971 | mh.msg_controllen = 4096; | |
972 | ||
ed34e3c3 | 973 | if ((r = recvmsg(lh->fd, &mh, 0)) == -1) |
e91b9f68 A |
974 | return -1; |
975 | if (r == 0) { | |
976 | errno = ECONNRESET; | |
977 | return -1; | |
978 | } | |
ed34e3c3 | 979 | if (mh.msg_flags & MSG_CTRUNC) { |
e91b9f68 A |
980 | errno = ECONNABORTED; |
981 | return -1; | |
982 | } | |
983 | lh->recvlen += r; | |
984 | if (mh.msg_controllen > 0) { | |
5b0a4722 | 985 | lh->recvfds = reallocf(lh->recvfds, lh->recvfdcnt * sizeof(int) + mh.msg_controllen - sizeof(struct cmsghdr)); |
e91b9f68 A |
986 | memcpy(lh->recvfds + lh->recvfdcnt, CMSG_DATA(cm), mh.msg_controllen - sizeof(struct cmsghdr)); |
987 | lh->recvfdcnt += (mh.msg_controllen - sizeof(struct cmsghdr)) / sizeof(int); | |
988 | } | |
989 | ||
aa59983a A |
990 | r = 0; |
991 | ||
992 | while (lh->recvlen > 0) { | |
993 | struct launch_msg_header *lmhp = lh->recvbuf; | |
994 | uint64_t tmplen; | |
995 | data_offset = sizeof(struct launch_msg_header); | |
996 | fd_offset = 0; | |
997 | ||
998 | if (lh->recvlen < sizeof(struct launch_msg_header)) | |
999 | goto need_more_data; | |
1000 | ||
1001 | tmplen = big2host(lmhp->len); | |
1002 | ||
ed34e3c3 | 1003 | if (big2host(lmhp->magic) != LAUNCH_MSG_HEADER_MAGIC || tmplen <= sizeof(struct launch_msg_header)) { |
aa59983a A |
1004 | errno = EBADRPC; |
1005 | goto out_bad; | |
1006 | } | |
1007 | ||
1008 | if (lh->recvlen < tmplen) { | |
1009 | goto need_more_data; | |
1010 | } | |
e91b9f68 | 1011 | |
5b0a4722 | 1012 | if ((rmsg = launch_data_unpack(lh->recvbuf, lh->recvlen, lh->recvfds, lh->recvfdcnt, &data_offset, &fd_offset)) == NULL) { |
aa59983a A |
1013 | errno = EBADRPC; |
1014 | goto out_bad; | |
1015 | } | |
e91b9f68 | 1016 | |
f36da725 A |
1017 | in_flight_msg_recv_client = lh; |
1018 | ||
e91b9f68 A |
1019 | cb(rmsg, context); |
1020 | ||
f36da725 A |
1021 | /* launchd and only launchd can call launchd_close() as a part of the callback */ |
1022 | if (in_flight_msg_recv_client == NULL) { | |
1023 | r = 0; | |
1024 | break; | |
1025 | } | |
1026 | ||
e91b9f68 A |
1027 | lh->recvlen -= data_offset; |
1028 | if (lh->recvlen > 0) { | |
1029 | memmove(lh->recvbuf, lh->recvbuf + data_offset, lh->recvlen); | |
1030 | } else { | |
1031 | free(lh->recvbuf); | |
1032 | lh->recvbuf = malloc(0); | |
1033 | } | |
1034 | ||
1035 | lh->recvfdcnt -= fd_offset; | |
1036 | if (lh->recvfdcnt > 0) { | |
1037 | memmove(lh->recvfds, lh->recvfds + fd_offset, lh->recvfdcnt * sizeof(int)); | |
1038 | } else { | |
1039 | free(lh->recvfds); | |
1040 | lh->recvfds = malloc(0); | |
1041 | } | |
e91b9f68 A |
1042 | } |
1043 | ||
1044 | return r; | |
aa59983a A |
1045 | |
1046 | need_more_data: | |
1047 | errno = EAGAIN; | |
1048 | out_bad: | |
1049 | return -1; | |
e91b9f68 A |
1050 | } |
1051 | ||
1052 | launch_data_t launch_data_copy(launch_data_t o) | |
1053 | { | |
1054 | launch_data_t r = launch_data_alloc(o->type); | |
1055 | size_t i; | |
1056 | ||
1057 | free(r->_array); | |
1058 | memcpy(r, o, sizeof(struct _launch_data)); | |
1059 | ||
1060 | switch (o->type) { | |
1061 | case LAUNCH_DATA_DICTIONARY: | |
1062 | case LAUNCH_DATA_ARRAY: | |
1063 | r->_array = calloc(1, o->_array_cnt * sizeof(launch_data_t)); | |
1064 | for (i = 0; i < o->_array_cnt; i++) { | |
1065 | if (o->_array[i]) | |
1066 | r->_array[i] = launch_data_copy(o->_array[i]); | |
1067 | } | |
1068 | break; | |
1069 | case LAUNCH_DATA_STRING: | |
1070 | r->string = strdup(o->string); | |
1071 | break; | |
1072 | case LAUNCH_DATA_OPAQUE: | |
1073 | r->opaque = malloc(o->opaque_size); | |
1074 | memcpy(r->opaque, o->opaque, o->opaque_size); | |
1075 | break; | |
1076 | default: | |
1077 | break; | |
1078 | } | |
1079 | ||
1080 | return r; | |
1081 | } | |
1082 | ||
5b0a4722 A |
1083 | void |
1084 | launchd_batch_enable(bool b) | |
e91b9f68 | 1085 | { |
5b0a4722 | 1086 | int64_t val = b; |
e91b9f68 | 1087 | |
5b0a4722 | 1088 | vproc_swap_integer(NULL, VPROC_GSK_GLOBAL_ON_DEMAND, &val, NULL); |
e91b9f68 A |
1089 | } |
1090 | ||
5b0a4722 A |
1091 | bool |
1092 | launchd_batch_query(void) | |
e91b9f68 | 1093 | { |
5b0a4722 | 1094 | int64_t val; |
e91b9f68 | 1095 | |
5b0a4722 A |
1096 | if (vproc_swap_integer(NULL, VPROC_GSK_GLOBAL_ON_DEMAND, NULL, &val) == NULL) { |
1097 | return (bool)val; | |
e91b9f68 | 1098 | } |
5b0a4722 A |
1099 | |
1100 | return false; | |
e91b9f68 A |
1101 | } |
1102 | ||
1103 | static int _fd(int fd) | |
1104 | { | |
1105 | if (fd >= 0) | |
ed34e3c3 | 1106 | fcntl(fd, F_SETFD, 1); |
e91b9f68 A |
1107 | return fd; |
1108 | } | |
1109 | ||
1110 | launch_data_t launch_data_new_errno(int e) | |
1111 | { | |
1112 | launch_data_t r = launch_data_alloc(LAUNCH_DATA_ERRNO); | |
1113 | ||
1114 | if (r) | |
5b0a4722 | 1115 | launch_data_set_errno(r, e); |
e91b9f68 A |
1116 | |
1117 | return r; | |
1118 | } | |
1119 | ||
1120 | launch_data_t launch_data_new_fd(int fd) | |
1121 | { | |
1122 | launch_data_t r = launch_data_alloc(LAUNCH_DATA_FD); | |
1123 | ||
1124 | if (r) | |
5b0a4722 | 1125 | launch_data_set_fd(r, fd); |
e91b9f68 A |
1126 | |
1127 | return r; | |
1128 | } | |
1129 | ||
ed34e3c3 A |
1130 | launch_data_t launch_data_new_machport(mach_port_t p) |
1131 | { | |
1132 | launch_data_t r = launch_data_alloc(LAUNCH_DATA_MACHPORT); | |
1133 | ||
1134 | if (r) | |
5b0a4722 | 1135 | launch_data_set_machport(r, p); |
ed34e3c3 A |
1136 | |
1137 | return r; | |
1138 | } | |
1139 | ||
e91b9f68 A |
1140 | launch_data_t launch_data_new_integer(long long n) |
1141 | { | |
1142 | launch_data_t r = launch_data_alloc(LAUNCH_DATA_INTEGER); | |
1143 | ||
1144 | if (r) | |
1145 | launch_data_set_integer(r, n); | |
1146 | ||
1147 | return r; | |
1148 | } | |
1149 | ||
1150 | launch_data_t launch_data_new_bool(bool b) | |
1151 | { | |
1152 | launch_data_t r = launch_data_alloc(LAUNCH_DATA_BOOL); | |
1153 | ||
1154 | if (r) | |
1155 | launch_data_set_bool(r, b); | |
1156 | ||
1157 | return r; | |
1158 | } | |
1159 | ||
1160 | launch_data_t launch_data_new_real(double d) | |
1161 | { | |
1162 | launch_data_t r = launch_data_alloc(LAUNCH_DATA_REAL); | |
1163 | ||
1164 | if (r) | |
1165 | launch_data_set_real(r, d); | |
1166 | ||
1167 | return r; | |
1168 | } | |
1169 | ||
1170 | launch_data_t launch_data_new_string(const char *s) | |
1171 | { | |
1172 | launch_data_t r = launch_data_alloc(LAUNCH_DATA_STRING); | |
1173 | ||
1174 | if (r == NULL) | |
1175 | return NULL; | |
1176 | ||
1177 | if (!launch_data_set_string(r, s)) { | |
1178 | launch_data_free(r); | |
1179 | return NULL; | |
1180 | } | |
1181 | ||
1182 | return r; | |
1183 | } | |
1184 | ||
1185 | launch_data_t launch_data_new_opaque(const void *o, size_t os) | |
1186 | { | |
1187 | launch_data_t r = launch_data_alloc(LAUNCH_DATA_OPAQUE); | |
1188 | ||
1189 | if (r == NULL) | |
1190 | return NULL; | |
1191 | ||
1192 | if (!launch_data_set_opaque(r, o, os)) { | |
1193 | launch_data_free(r); | |
1194 | return NULL; | |
1195 | } | |
1196 | ||
1197 | return r; | |
1198 | } | |
ed34e3c3 | 1199 | |
5b0a4722 A |
1200 | void |
1201 | load_launchd_jobs_at_loginwindow_prompt(int flags __attribute__((unused)), ...) | |
ed34e3c3 | 1202 | { |
5b0a4722 | 1203 | _vprocmgr_init("LoginWindow"); |
ed34e3c3 A |
1204 | } |
1205 | ||
1206 | pid_t | |
5b0a4722 | 1207 | create_and_switch_to_per_session_launchd(const char *login __attribute__((unused)), int flags __attribute__((unused)), ...) |
ed34e3c3 | 1208 | { |
ed34e3c3 | 1209 | mach_port_t bezel_ui_server; |
ed34e3c3 | 1210 | struct stat sb; |
5b0a4722 | 1211 | uid_t target_user = geteuid() ? geteuid() : getuid(); |
ed34e3c3 | 1212 | |
5b0a4722 | 1213 | if (_vprocmgr_move_subset_to_user(target_user, "Aqua")) { |
ed34e3c3 | 1214 | return -1; |
5b0a4722 | 1215 | } |
ed34e3c3 A |
1216 | |
1217 | #define BEZEL_UI_PATH "/System/Library/LoginPlugins/BezelServices.loginPlugin/Contents/Resources/BezelUI/BezelUIServer" | |
1218 | #define BEZEL_UI_PLIST "/System/Library/LaunchAgents/com.apple.BezelUIServer.plist" | |
1219 | #define BEZEL_UI_SERVICE "BezelUI" | |
1220 | ||
1221 | if (!(stat(BEZEL_UI_PLIST, &sb) == 0 && S_ISREG(sb.st_mode))) { | |
5b0a4722 | 1222 | if (bootstrap_create_server(bootstrap_port, BEZEL_UI_PATH, target_user, true, &bezel_ui_server) == BOOTSTRAP_SUCCESS) { |
ed34e3c3 A |
1223 | mach_port_t srv; |
1224 | ||
1225 | if (bootstrap_create_service(bezel_ui_server, BEZEL_UI_SERVICE, &srv) == BOOTSTRAP_SUCCESS) { | |
1226 | mach_port_deallocate(mach_task_self(), srv); | |
1227 | } | |
1228 | ||
1229 | mach_port_deallocate(mach_task_self(), bezel_ui_server); | |
1230 | } | |
1231 | } | |
1232 | ||
5b0a4722 | 1233 | return 1; |
ed34e3c3 | 1234 | } |