]> git.saurik.com Git - apple/launchd.git/blame - launchd/src/liblaunch.c
launchd-258.19.tar.gz
[apple/launchd.git] / launchd / src / liblaunch.c
CommitLineData
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 */
51extern 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
99struct launch_msg_header {
100 uint64_t magic;
101 uint64_t len;
102};
103
104#define LAUNCH_MSG_HEADER_MAGIC 0xD2FEA02366B39A41ull
105
e91b9f68 106struct _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
131struct _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 143static launch_data_t launch_data_array_pop_first(launch_data_t where);
e91b9f68 144static int _fd(int fd);
ed34e3c3
A
145static void launch_client_init(void);
146static void launch_msg_getmsgs(launch_data_t m, void *context);
147static launch_data_t launch_msg_internal(launch_data_t d);
148static void launch_mach_checkin_service(launch_data_t obj, const char *key, void *context);
e91b9f68 149
f36da725 150static launch_t in_flight_msg_recv_client;
e91b9f68
A
151static pthread_once_t _lc_once = PTHREAD_ONCE_INIT;
152
153static struct _launch_client {
154 pthread_mutex_t mtx;
155 launch_t l;
156 launch_data_t async_resp;
157} *_lc = NULL;
158
ed34e3c3
A
159void
160launch_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;
212out_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
222launch_data_t
223launch_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
242launch_data_type_t
243launch_data_get_type(launch_data_t d)
e91b9f68
A
244{
245 return d->type;
246}
247
ed34e3c3
A
248void
249launch_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
274size_t
275launch_data_dict_get_count(launch_data_t dict)
e91b9f68
A
276{
277 return dict->_array_cnt / 2;
278}
279
280
ed34e3c3
A
281bool
282launch_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
301launch_data_t
302launch_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
317bool
318launch_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
335void
336launch_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
347bool
348launch_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
362launch_data_t
363launch_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
372launch_data_t
373launch_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
385size_t
386launch_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
393bool
394launch_data_set_errno(launch_data_t d, int e)
e91b9f68
A
395{
396 d->err = e;
397 return true;
398}
399
ed34e3c3
A
400bool
401launch_data_set_fd(launch_data_t d, int fd)
e91b9f68
A
402{
403 d->fd = fd;
404 return true;
405}
406
ed34e3c3
A
407bool
408launch_data_set_machport(launch_data_t d, mach_port_t p)
409{
410 d->mp = p;
411 return true;
412}
413
414bool
415launch_data_set_integer(launch_data_t d, long long n)
e91b9f68
A
416{
417 d->number = n;
418 return true;
419}
420
ed34e3c3
A
421bool
422launch_data_set_bool(launch_data_t d, bool b)
e91b9f68
A
423{
424 d->boolean = b;
425 return true;
426}
427
ed34e3c3
A
428bool
429launch_data_set_real(launch_data_t d, double n)
e91b9f68
A
430{
431 d->float_num = n;
432 return true;
433}
434
ed34e3c3
A
435bool
436launch_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
448bool
449launch_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
462int
463launch_data_get_errno(launch_data_t d)
e91b9f68
A
464{
465 return d->err;
466}
467
ed34e3c3
A
468int
469launch_data_get_fd(launch_data_t d)
e91b9f68
A
470{
471 return d->fd;
472}
473
ed34e3c3
A
474mach_port_t
475launch_data_get_machport(launch_data_t d)
476{
477 return d->mp;
478}
479
480long long
481launch_data_get_integer(launch_data_t d)
e91b9f68
A
482{
483 return d->number;
484}
485
ed34e3c3
A
486bool
487launch_data_get_bool(launch_data_t d)
e91b9f68
A
488{
489 return d->boolean;
490}
491
ed34e3c3
A
492double
493launch_data_get_real(launch_data_t d)
e91b9f68
A
494{
495 return d->float_num;
496}
497
ed34e3c3
A
498const char *
499launch_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
506void *
507launch_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
514size_t
515launch_data_get_opaque_size(launch_data_t d)
e91b9f68
A
516{
517 return d->opaque_size;
518}
519
ed34e3c3
A
520int
521launchd_getfd(launch_t l)
e91b9f68
A
522{
523 return l->fd;
524}
525
ed34e3c3
A
526launch_t
527launchd_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
550out_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 563void
5b0a4722 564launchd_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
584size_t
585launch_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
660launch_data_t
661launch_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
737int 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
837int
838launch_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
850void
851launch_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
862void
863launch_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
877launch_data_t
878launch_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
898launch_data_t
899launch_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
947out:
948 pthread_mutex_unlock(&_lc->mtx);
949
950 return resp;
951}
952
953int 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
1046need_more_data:
1047 errno = EAGAIN;
1048out_bad:
1049 return -1;
e91b9f68
A
1050}
1051
1052launch_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
1083void
1084launchd_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
1091bool
1092launchd_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
1103static int _fd(int fd)
1104{
1105 if (fd >= 0)
ed34e3c3 1106 fcntl(fd, F_SETFD, 1);
e91b9f68
A
1107 return fd;
1108}
1109
1110launch_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
1120launch_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
1130launch_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
1140launch_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
1150launch_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
1160launch_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
1170launch_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
1185launch_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
1200void
1201load_launchd_jobs_at_loginwindow_prompt(int flags __attribute__((unused)), ...)
ed34e3c3 1202{
5b0a4722 1203 _vprocmgr_init("LoginWindow");
ed34e3c3
A
1204}
1205
1206pid_t
5b0a4722 1207create_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}