2 * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
4 * @APPLE_APACHE_LICENSE_HEADER_START@
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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 * @APPLE_APACHE_LICENSE_HEADER_END@
20 #include <mach/mach.h>
21 #include <libkern/OSByteOrder.h>
22 #include <sys/types.h>
23 #include <sys/socket.h>
24 #include <sys/fcntl.h>
37 #include "launch_priv.h"
38 #include "bootstrap_public.h"
39 #include "bootstrap_private.h"
41 /* __OSBogusByteSwap__() must not really exist in the symbol namespace
42 * in order for the following to generate an error at build time.
44 extern void __OSBogusByteSwap__(void);
47 ({ typeof (x) _X, _x = (x); \
48 switch (sizeof(_x)) { \
50 _X = OSSwapHostToBigInt64(_x); \
53 _X = OSSwapHostToBigInt32(_x); \
56 _X = OSSwapHostToBigInt16(_x); \
62 __OSBogusByteSwap__(); \
70 ({ typeof (x) _X, _x = (x); \
71 switch (sizeof(_x)) { \
73 _X = OSSwapBigToHostInt64(_x); \
76 _X = OSSwapBigToHostInt32(_x); \
79 _X = OSSwapBigToHostInt16(_x); \
85 __OSBogusByteSwap__(); \
92 struct launch_msg_header
{
97 #define LAUNCH_MSG_HEADER_MAGIC 0xD2FEA02366B39A41ull
104 launch_data_t
*_array
;
112 uint64_t opaque_size
;
136 static void make_msg_and_cmsg(launch_data_t
, void **, size_t *, int **, size_t *);
137 static launch_data_t
make_data(launch_t
, size_t *, size_t *);
138 static launch_data_t
launch_data_array_pop_first(launch_data_t where
);
139 static int _fd(int fd
);
140 static void launch_client_init(void);
141 static void launch_msg_getmsgs(launch_data_t m
, void *context
);
142 static launch_data_t
launch_msg_internal(launch_data_t d
);
143 static void launch_mach_checkin_service(launch_data_t obj
, const char *key
, void *context
);
145 static pthread_once_t _lc_once
= PTHREAD_ONCE_INIT
;
147 static struct _launch_client
{
150 launch_data_t async_resp
;
154 launch_client_init(void)
156 struct sockaddr_un sun
;
157 char *where
= getenv(LAUNCHD_SOCKET_ENV
);
158 char *_launchd_fd
= getenv(LAUNCHD_TRUSTED_FD_ENV
);
161 _lc
= calloc(1, sizeof(struct _launch_client
));
166 pthread_mutex_init(&_lc
->mtx
, NULL
);
169 lfd
= strtol(_launchd_fd
, NULL
, 10);
170 if ((dfd
= dup(lfd
)) >= 0) {
176 unsetenv(LAUNCHD_TRUSTED_FD_ENV
);
179 memset(&sun
, 0, sizeof(sun
));
180 sun
.sun_family
= AF_UNIX
;
182 if (where
&& where
[0] != '\0') {
183 strncpy(sun
.sun_path
, where
, sizeof(sun
.sun_path
));
184 } else if (getuid() == 0) {
185 strncpy(sun
.sun_path
, LAUNCHD_SOCK_PREFIX
"/sock", sizeof(sun
.sun_path
));
190 if ((lfd
= _fd(socket(AF_UNIX
, SOCK_STREAM
, 0))) == -1)
192 if (-1 == connect(lfd
, (struct sockaddr
*)&sun
, sizeof(sun
)))
195 if (!(_lc
->l
= launchd_fdopen(lfd
)))
197 if (!(_lc
->async_resp
= launch_data_alloc(LAUNCH_DATA_ARRAY
)))
203 launchd_close(_lc
->l
);
212 launch_data_alloc(launch_data_type_t t
)
214 launch_data_t d
= calloc(1, sizeof(struct _launch
));
219 case LAUNCH_DATA_DICTIONARY
:
220 case LAUNCH_DATA_ARRAY
:
221 d
->_array
= malloc(0);
232 launch_data_get_type(launch_data_t d
)
238 launch_data_free(launch_data_t d
)
243 case LAUNCH_DATA_DICTIONARY
:
244 case LAUNCH_DATA_ARRAY
:
245 for (i
= 0; i
< d
->_array_cnt
; i
++)
246 launch_data_free(d
->_array
[i
]);
249 case LAUNCH_DATA_STRING
:
253 case LAUNCH_DATA_OPAQUE
:
264 launch_data_dict_get_count(launch_data_t dict
)
266 return dict
->_array_cnt
/ 2;
271 launch_data_dict_insert(launch_data_t dict
, launch_data_t what
, const char *key
)
274 launch_data_t thekey
= launch_data_alloc(LAUNCH_DATA_STRING
);
276 launch_data_set_string(thekey
, key
);
278 for (i
= 0; i
< dict
->_array_cnt
; i
+= 2) {
279 if (!strcasecmp(key
, dict
->_array
[i
]->string
)) {
280 launch_data_array_set_index(dict
, thekey
, i
);
281 launch_data_array_set_index(dict
, what
, i
+ 1);
285 launch_data_array_set_index(dict
, thekey
, i
);
286 launch_data_array_set_index(dict
, what
, i
+ 1);
291 launch_data_dict_lookup(launch_data_t dict
, const char *key
)
295 if (LAUNCH_DATA_DICTIONARY
!= dict
->type
)
298 for (i
= 0; i
< dict
->_array_cnt
; i
+= 2) {
299 if (!strcasecmp(key
, dict
->_array
[i
]->string
))
300 return dict
->_array
[i
+ 1];
307 launch_data_dict_remove(launch_data_t dict
, const char *key
)
311 for (i
= 0; i
< dict
->_array_cnt
; i
+= 2) {
312 if (!strcasecmp(key
, dict
->_array
[i
]->string
))
315 if (i
== dict
->_array_cnt
)
317 launch_data_free(dict
->_array
[i
]);
318 launch_data_free(dict
->_array
[i
+ 1]);
319 memmove(dict
->_array
+ i
, dict
->_array
+ i
+ 2, (dict
->_array_cnt
- (i
+ 2)) * sizeof(launch_data_t
));
320 dict
->_array_cnt
-= 2;
325 launch_data_dict_iterate(launch_data_t dict
, void (*cb
)(launch_data_t
, const char *, void *), void *context
)
329 if (LAUNCH_DATA_DICTIONARY
!= dict
->type
)
332 for (i
= 0; i
< dict
->_array_cnt
; i
+= 2)
333 cb(dict
->_array
[i
+ 1], dict
->_array
[i
]->string
, context
);
337 launch_data_array_set_index(launch_data_t where
, launch_data_t what
, size_t ind
)
339 if ((ind
+ 1) >= where
->_array_cnt
) {
340 where
->_array
= realloc(where
->_array
, (ind
+ 1) * sizeof(launch_data_t
));
341 memset(where
->_array
+ where
->_array_cnt
, 0, (ind
+ 1 - where
->_array_cnt
) * sizeof(launch_data_t
));
342 where
->_array_cnt
= ind
+ 1;
345 if (where
->_array
[ind
])
346 launch_data_free(where
->_array
[ind
]);
347 where
->_array
[ind
] = what
;
352 launch_data_array_get_index(launch_data_t where
, size_t ind
)
354 if (LAUNCH_DATA_ARRAY
!= where
->type
)
356 if (ind
< where
->_array_cnt
)
357 return where
->_array
[ind
];
362 launch_data_array_pop_first(launch_data_t where
)
364 launch_data_t r
= NULL
;
366 if (where
->_array_cnt
> 0) {
367 r
= where
->_array
[0];
368 memmove(where
->_array
, where
->_array
+ 1, (where
->_array_cnt
- 1) * sizeof(launch_data_t
));
375 launch_data_array_get_count(launch_data_t where
)
377 if (LAUNCH_DATA_ARRAY
!= where
->type
)
379 return where
->_array_cnt
;
383 launch_data_set_errno(launch_data_t d
, int e
)
390 launch_data_set_fd(launch_data_t d
, int fd
)
397 launch_data_set_machport(launch_data_t d
, mach_port_t p
)
404 launch_data_set_integer(launch_data_t d
, long long n
)
411 launch_data_set_bool(launch_data_t d
, bool b
)
418 launch_data_set_real(launch_data_t d
, double n
)
425 launch_data_set_string(launch_data_t d
, const char *s
)
429 d
->string
= strdup(s
);
431 d
->string_len
= strlen(d
->string
);
438 launch_data_set_opaque(launch_data_t d
, const void *o
, size_t os
)
443 d
->opaque
= malloc(os
);
445 memcpy(d
->opaque
, o
, os
);
452 launch_data_get_errno(launch_data_t d
)
458 launch_data_get_fd(launch_data_t d
)
464 launch_data_get_machport(launch_data_t d
)
470 launch_data_get_integer(launch_data_t d
)
476 launch_data_get_bool(launch_data_t d
)
482 launch_data_get_real(launch_data_t d
)
488 launch_data_get_string(launch_data_t d
)
490 if (LAUNCH_DATA_STRING
!= d
->type
)
496 launch_data_get_opaque(launch_data_t d
)
498 if (LAUNCH_DATA_OPAQUE
!= d
->type
)
504 launch_data_get_opaque_size(launch_data_t d
)
506 return d
->opaque_size
;
510 launchd_getfd(launch_t l
)
516 launchd_fdopen(int fd
)
520 c
= calloc(1, sizeof(struct _launch
));
526 fcntl(fd
, F_SETFL
, O_NONBLOCK
);
528 if ((c
->sendbuf
= malloc(0)) == NULL
)
530 if ((c
->sendfds
= malloc(0)) == NULL
)
532 if ((c
->recvbuf
= malloc(0)) == NULL
)
534 if ((c
->recvfds
= malloc(0)) == NULL
)
553 launchd_close(launch_t lh
)
568 make_msg_and_cmsg(launch_data_t d
, void **where
, size_t *len
, int **fd_where
, size_t *fdcnt
)
570 launch_data_t o_in_w
;
573 *where
= realloc(*where
, *len
+ sizeof(struct _launch_data
));
575 o_in_w
= *where
+ *len
;
576 memset(o_in_w
, 0, sizeof(struct _launch_data
));
577 *len
+= sizeof(struct _launch_data
);
579 o_in_w
->type
= host2big(d
->type
);
582 case LAUNCH_DATA_INTEGER
:
583 o_in_w
->number
= host2big(d
->number
);
585 case LAUNCH_DATA_REAL
:
586 o_in_w
->float_num
= host2big(d
->float_num
);
588 case LAUNCH_DATA_BOOL
:
589 o_in_w
->boolean
= host2big(d
->boolean
);
591 case LAUNCH_DATA_ERRNO
:
592 o_in_w
->err
= host2big(d
->err
);
595 o_in_w
->fd
= host2big(d
->fd
);
597 *fd_where
= realloc(*fd_where
, (*fdcnt
+ 1) * sizeof(int));
598 (*fd_where
)[*fdcnt
] = d
->fd
;
602 case LAUNCH_DATA_STRING
:
603 o_in_w
->string_len
= host2big(d
->string_len
);
604 *where
= realloc(*where
, *len
+ strlen(d
->string
) + 1);
605 memcpy(*where
+ *len
, d
->string
, strlen(d
->string
) + 1);
606 *len
+= strlen(d
->string
) + 1;
608 case LAUNCH_DATA_OPAQUE
:
609 o_in_w
->opaque_size
= host2big(d
->opaque_size
);
610 *where
= realloc(*where
, *len
+ d
->opaque_size
);
611 memcpy(*where
+ *len
, d
->opaque
, d
->opaque_size
);
612 *len
+= d
->opaque_size
;
614 case LAUNCH_DATA_DICTIONARY
:
615 case LAUNCH_DATA_ARRAY
:
616 o_in_w
->_array_cnt
= host2big(d
->_array_cnt
);
617 *where
= realloc(*where
, *len
+ (d
->_array_cnt
* sizeof(launch_data_t
)));
618 memcpy(*where
+ *len
, d
->_array
, d
->_array_cnt
* sizeof(launch_data_t
));
619 *len
+= d
->_array_cnt
* sizeof(launch_data_t
);
621 for (i
= 0; i
< d
->_array_cnt
; i
++)
622 make_msg_and_cmsg(d
->_array
[i
], where
, len
, fd_where
, fdcnt
);
629 static launch_data_t
make_data(launch_t conn
, size_t *data_offset
, size_t *fdoffset
)
631 launch_data_t r
= conn
->recvbuf
+ *data_offset
;
634 if ((conn
->recvlen
- *data_offset
) < sizeof(struct _launch_data
))
636 *data_offset
+= sizeof(struct _launch_data
);
638 switch (big2host(r
->type
)) {
639 case LAUNCH_DATA_DICTIONARY
:
640 case LAUNCH_DATA_ARRAY
:
641 tmpcnt
= big2host(r
->_array_cnt
);
642 if ((conn
->recvlen
- *data_offset
) < (tmpcnt
* sizeof(launch_data_t
))) {
646 r
->_array
= conn
->recvbuf
+ *data_offset
;
647 *data_offset
+= tmpcnt
* sizeof(launch_data_t
);
648 for (i
= 0; i
< tmpcnt
; i
++) {
649 r
->_array
[i
] = make_data(conn
, data_offset
, fdoffset
);
650 if (r
->_array
[i
] == NULL
)
653 r
->_array_cnt
= tmpcnt
;
655 case LAUNCH_DATA_STRING
:
656 tmpcnt
= big2host(r
->string_len
);
657 if ((conn
->recvlen
- *data_offset
) < (tmpcnt
+ 1)) {
661 r
->string
= conn
->recvbuf
+ *data_offset
;
662 r
->string_len
= tmpcnt
;
663 *data_offset
+= tmpcnt
+ 1;
665 case LAUNCH_DATA_OPAQUE
:
666 tmpcnt
= big2host(r
->opaque_size
);
667 if ((conn
->recvlen
- *data_offset
) < tmpcnt
) {
671 r
->opaque
= conn
->recvbuf
+ *data_offset
;
672 r
->opaque_size
= tmpcnt
;
673 *data_offset
+= tmpcnt
;
677 r
->fd
= _fd(conn
->recvfds
[*fdoffset
]);
681 case LAUNCH_DATA_INTEGER
:
682 r
->number
= big2host(r
->number
);
684 case LAUNCH_DATA_REAL
:
685 r
->float_num
= big2host(r
->float_num
);
687 case LAUNCH_DATA_BOOL
:
688 r
->boolean
= big2host(r
->boolean
);
690 case LAUNCH_DATA_ERRNO
:
691 r
->err
= big2host(r
->err
);
692 case LAUNCH_DATA_MACHPORT
:
700 r
->type
= big2host(r
->type
);
705 int launchd_msg_send(launch_t lh
, launch_data_t d
)
707 struct launch_msg_header lmh
;
708 struct cmsghdr
*cm
= NULL
;
711 size_t sentctrllen
= 0;
714 memset(&mh
, 0, sizeof(mh
));
717 uint64_t msglen
= lh
->sendlen
;
719 make_msg_and_cmsg(d
, &lh
->sendbuf
, &lh
->sendlen
, &lh
->sendfds
, &lh
->sendfdcnt
);
721 msglen
= (lh
->sendlen
- msglen
) + sizeof(struct launch_msg_header
);
722 lmh
.len
= host2big(msglen
);
723 lmh
.magic
= host2big(LAUNCH_MSG_HEADER_MAGIC
);
725 iov
[0].iov_base
= &lmh
;
726 iov
[0].iov_len
= sizeof(lmh
);
730 mh
.msg_iov
= iov
+ 1;
734 iov
[1].iov_base
= lh
->sendbuf
;
735 iov
[1].iov_len
= lh
->sendlen
;
738 if (lh
->sendfdcnt
> 0) {
739 sentctrllen
= mh
.msg_controllen
= CMSG_SPACE(lh
->sendfdcnt
* sizeof(int));
740 cm
= alloca(mh
.msg_controllen
);
743 memset(cm
, 0, mh
.msg_controllen
);
745 cm
->cmsg_len
= CMSG_LEN(lh
->sendfdcnt
* sizeof(int));
746 cm
->cmsg_level
= SOL_SOCKET
;
747 cm
->cmsg_type
= SCM_RIGHTS
;
749 memcpy(CMSG_DATA(cm
), lh
->sendfds
, lh
->sendfdcnt
* sizeof(int));
752 if ((r
= sendmsg(lh
->fd
, &mh
, 0)) == -1) {
757 } else if (sentctrllen
!= mh
.msg_controllen
) {
763 r
-= sizeof(struct launch_msg_header
);
767 if (lh
->sendlen
> 0) {
768 memmove(lh
->sendbuf
, lh
->sendbuf
+ r
, lh
->sendlen
);
771 lh
->sendbuf
= malloc(0);
776 lh
->sendfds
= malloc(0);
778 if (lh
->sendlen
> 0) {
790 pthread_once(&_lc_once
, launch_client_init
);
801 launch_msg_getmsgs(launch_data_t m
, void *context
)
803 launch_data_t async_resp
, *sync_resp
= context
;
805 if ((LAUNCH_DATA_DICTIONARY
== launch_data_get_type(m
)) && (async_resp
= launch_data_dict_lookup(m
, LAUNCHD_ASYNC_MSG_KEY
))) {
806 launch_data_array_set_index(_lc
->async_resp
, launch_data_copy(async_resp
), launch_data_array_get_count(_lc
->async_resp
));
808 *sync_resp
= launch_data_copy(m
);
813 launch_mach_checkin_service(launch_data_t obj
, const char *key
, void *context
__attribute__((unused
)))
815 kern_return_t result
;
819 strlcpy(srvnm
, key
, sizeof(srvnm
));
821 result
= bootstrap_check_in(bootstrap_port
, srvnm
, &p
);
823 if (result
== BOOTSTRAP_SUCCESS
)
824 launch_data_set_machport(obj
, p
);
828 launch_msg(launch_data_t d
)
830 launch_data_t mps
, r
= launch_msg_internal(d
);
832 if (launch_data_get_type(d
) == LAUNCH_DATA_STRING
) {
833 if (strcmp(launch_data_get_string(d
), LAUNCH_KEY_CHECKIN
) != 0)
837 if (launch_data_get_type(r
) != LAUNCH_DATA_DICTIONARY
)
839 mps
= launch_data_dict_lookup(r
, LAUNCH_JOBKEY_MACHSERVICES
);
842 launch_data_dict_iterate(mps
, launch_mach_checkin_service
, NULL
);
849 launch_msg_internal(launch_data_t d
)
851 launch_data_t resp
= NULL
;
853 pthread_once(&_lc_once
, launch_client_init
);
860 pthread_mutex_lock(&_lc
->mtx
);
862 if (d
&& launchd_msg_send(_lc
->l
, d
) == -1) {
866 } while (launchd_msg_send(_lc
->l
, NULL
) == -1);
869 while (resp
== NULL
) {
870 if (d
== NULL
&& launch_data_array_get_count(_lc
->async_resp
) > 0) {
871 resp
= launch_data_array_pop_first(_lc
->async_resp
);
874 if (launchd_msg_recv(_lc
->l
, launch_msg_getmsgs
, &resp
) == -1) {
875 if (errno
!= EAGAIN
) {
877 } else if (d
== NULL
) {
884 FD_SET(_lc
->l
->fd
, &rfds
);
886 select(_lc
->l
->fd
+ 1, &rfds
, NULL
, NULL
, NULL
);
892 pthread_mutex_unlock(&_lc
->mtx
);
897 int launchd_msg_recv(launch_t lh
, void (*cb
)(launch_data_t
, void *), void *context
)
899 struct cmsghdr
*cm
= alloca(4096);
900 launch_data_t rmsg
= NULL
;
901 size_t data_offset
, fd_offset
;
906 memset(&mh
, 0, sizeof(mh
));
910 lh
->recvbuf
= realloc(lh
->recvbuf
, lh
->recvlen
+ 8*1024);
912 iov
.iov_base
= lh
->recvbuf
+ lh
->recvlen
;
913 iov
.iov_len
= 8*1024;
915 mh
.msg_controllen
= 4096;
917 if ((r
= recvmsg(lh
->fd
, &mh
, 0)) == -1)
923 if (mh
.msg_flags
& MSG_CTRUNC
) {
924 errno
= ECONNABORTED
;
928 if (mh
.msg_controllen
> 0) {
929 lh
->recvfds
= realloc(lh
->recvfds
, lh
->recvfdcnt
* sizeof(int) + mh
.msg_controllen
- sizeof(struct cmsghdr
));
930 memcpy(lh
->recvfds
+ lh
->recvfdcnt
, CMSG_DATA(cm
), mh
.msg_controllen
- sizeof(struct cmsghdr
));
931 lh
->recvfdcnt
+= (mh
.msg_controllen
- sizeof(struct cmsghdr
)) / sizeof(int);
936 while (lh
->recvlen
> 0) {
937 struct launch_msg_header
*lmhp
= lh
->recvbuf
;
939 data_offset
= sizeof(struct launch_msg_header
);
942 if (lh
->recvlen
< sizeof(struct launch_msg_header
))
945 tmplen
= big2host(lmhp
->len
);
947 if (big2host(lmhp
->magic
) != LAUNCH_MSG_HEADER_MAGIC
|| tmplen
<= sizeof(struct launch_msg_header
)) {
952 if (lh
->recvlen
< tmplen
) {
956 if ((rmsg
= make_data(lh
, &data_offset
, &fd_offset
)) == NULL
) {
963 lh
->recvlen
-= data_offset
;
964 if (lh
->recvlen
> 0) {
965 memmove(lh
->recvbuf
, lh
->recvbuf
+ data_offset
, lh
->recvlen
);
968 lh
->recvbuf
= malloc(0);
971 lh
->recvfdcnt
-= fd_offset
;
972 if (lh
->recvfdcnt
> 0) {
973 memmove(lh
->recvfds
, lh
->recvfds
+ fd_offset
, lh
->recvfdcnt
* sizeof(int));
976 lh
->recvfds
= malloc(0);
988 launch_data_t
launch_data_copy(launch_data_t o
)
990 launch_data_t r
= launch_data_alloc(o
->type
);
994 memcpy(r
, o
, sizeof(struct _launch_data
));
997 case LAUNCH_DATA_DICTIONARY
:
998 case LAUNCH_DATA_ARRAY
:
999 r
->_array
= calloc(1, o
->_array_cnt
* sizeof(launch_data_t
));
1000 for (i
= 0; i
< o
->_array_cnt
; i
++) {
1002 r
->_array
[i
] = launch_data_copy(o
->_array
[i
]);
1005 case LAUNCH_DATA_STRING
:
1006 r
->string
= strdup(o
->string
);
1008 case LAUNCH_DATA_OPAQUE
:
1009 r
->opaque
= malloc(o
->opaque_size
);
1010 memcpy(r
->opaque
, o
->opaque
, o
->opaque_size
);
1019 void launchd_batch_enable(bool val
)
1021 launch_data_t resp
, tmp
, msg
;
1023 tmp
= launch_data_alloc(LAUNCH_DATA_BOOL
);
1024 launch_data_set_bool(tmp
, val
);
1026 msg
= launch_data_alloc(LAUNCH_DATA_DICTIONARY
);
1027 launch_data_dict_insert(msg
, tmp
, LAUNCH_KEY_BATCHCONTROL
);
1029 resp
= launch_msg(msg
);
1031 launch_data_free(msg
);
1034 launch_data_free(resp
);
1037 bool launchd_batch_query(void)
1039 launch_data_t resp
, msg
= launch_data_alloc(LAUNCH_DATA_STRING
);
1042 launch_data_set_string(msg
, LAUNCH_KEY_BATCHQUERY
);
1044 resp
= launch_msg(msg
);
1046 launch_data_free(msg
);
1049 if (launch_data_get_type(resp
) == LAUNCH_DATA_BOOL
)
1050 rval
= launch_data_get_bool(resp
);
1051 launch_data_free(resp
);
1056 static int _fd(int fd
)
1059 fcntl(fd
, F_SETFD
, 1);
1063 launch_data_t
launch_data_new_errno(int e
)
1065 launch_data_t r
= launch_data_alloc(LAUNCH_DATA_ERRNO
);
1068 launch_data_set_errno(r
, e
);
1073 launch_data_t
launch_data_new_fd(int fd
)
1075 launch_data_t r
= launch_data_alloc(LAUNCH_DATA_FD
);
1078 launch_data_set_fd(r
, fd
);
1083 launch_data_t
launch_data_new_machport(mach_port_t p
)
1085 launch_data_t r
= launch_data_alloc(LAUNCH_DATA_MACHPORT
);
1088 launch_data_set_machport(r
, p
);
1093 launch_data_t
launch_data_new_integer(long long n
)
1095 launch_data_t r
= launch_data_alloc(LAUNCH_DATA_INTEGER
);
1098 launch_data_set_integer(r
, n
);
1103 launch_data_t
launch_data_new_bool(bool b
)
1105 launch_data_t r
= launch_data_alloc(LAUNCH_DATA_BOOL
);
1108 launch_data_set_bool(r
, b
);
1113 launch_data_t
launch_data_new_real(double d
)
1115 launch_data_t r
= launch_data_alloc(LAUNCH_DATA_REAL
);
1118 launch_data_set_real(r
, d
);
1123 launch_data_t
launch_data_new_string(const char *s
)
1125 launch_data_t r
= launch_data_alloc(LAUNCH_DATA_STRING
);
1130 if (!launch_data_set_string(r
, s
)) {
1131 launch_data_free(r
);
1138 launch_data_t
launch_data_new_opaque(const void *o
, size_t os
)
1140 launch_data_t r
= launch_data_alloc(LAUNCH_DATA_OPAQUE
);
1145 if (!launch_data_set_opaque(r
, o
, os
)) {
1146 launch_data_free(r
);
1154 fexecv_as_user(const char *login
, uid_t u
, gid_t g
, char *const argv
[])
1159 if ((p
= fork()) != 0)
1166 initgroups(login
, g
);
1170 dtsz
= getdtablesize();
1172 for (i
= STDERR_FILENO
+ 1; i
< dtsz
; i
++)
1175 execv(argv
[0], argv
);
1176 _exit(EXIT_FAILURE
);
1180 create_and_switch_to_per_session_launchd(const char *login
, int flags
, ...)
1182 static char *const ldargv
[] = { "/sbin/launchd", "-S", "Aqua", NULL
};
1183 char *largv
[] = { "/bin/launchctl", "load", "-S", "Aqua", "-D", "all", "/etc/mach_init_per_user.d", NULL
};
1184 mach_port_t bezel_ui_server
;
1193 if ((pwe
= getpwnam(login
)) == NULL
)
1199 if ((ldp
= fexecv_as_user(login
, u
, g
, ldargv
)) == -1)
1202 while (bootstrap_getsocket(bootstrap_port
, sp
) != BOOTSTRAP_SUCCESS
)
1205 setenv(LAUNCHD_SOCKET_ENV
, sp
, 1);
1207 if (flags
& LOAD_ONLY_SAFEMODE_LAUNCHAGENTS
)
1208 largv
[5] = "system";
1210 if ((p
= fexecv_as_user(login
, u
, g
, largv
)) == -1)
1213 if (waitpid(p
, &wstatus
, 0) != p
)
1216 if (!(WIFEXITED(wstatus
) && WEXITSTATUS(wstatus
) == 0))
1219 #define BEZEL_UI_PATH "/System/Library/LoginPlugins/BezelServices.loginPlugin/Contents/Resources/BezelUI/BezelUIServer"
1220 #define BEZEL_UI_PLIST "/System/Library/LaunchAgents/com.apple.BezelUIServer.plist"
1221 #define BEZEL_UI_SERVICE "BezelUI"
1223 if (!(stat(BEZEL_UI_PLIST
, &sb
) == 0 && S_ISREG(sb
.st_mode
))) {
1224 if (bootstrap_create_server(bootstrap_port
, BEZEL_UI_PATH
, u
, true, &bezel_ui_server
) == BOOTSTRAP_SUCCESS
) {
1227 if (bootstrap_create_service(bezel_ui_server
, BEZEL_UI_SERVICE
, &srv
) == BOOTSTRAP_SUCCESS
) {
1228 mach_port_deallocate(mach_task_self(), srv
);
1231 mach_port_deallocate(mach_task_self(), bezel_ui_server
);