]>
git.saurik.com Git - apple/launchd.git/blob - launchd/src/liblaunch.c
cc23170c5d1c3e535391bb7517da4c55307ba265
2 * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
23 #include <sys/types.h>
24 #include <sys/socket.h>
25 #include <sys/fcntl.h>
36 #include "launch_priv.h"
39 launch_data_type_t type
;
42 launch_data_t
*_array
;
73 static void make_msg_and_cmsg(launch_data_t
, void **, size_t *, int **, size_t *);
74 static launch_data_t
make_data(launch_t
, size_t *, size_t *);
75 static int _fd(int fd
);
77 static pthread_once_t _lc_once
= PTHREAD_ONCE_INIT
;
79 static struct _launch_client
{
82 launch_data_t async_resp
;
85 static void launch_client_init(void)
87 struct sockaddr_un sun
;
88 char *where
= getenv(LAUNCHD_SOCKET_ENV
);
89 char *_launchd_fd
= getenv(LAUNCHD_TRUSTED_FD_ENV
);
90 int r
, dfd
, lfd
= -1, tries
;
92 _lc
= calloc(1, sizeof(struct _launch_client
));
97 pthread_mutex_init(&_lc
->mtx
, NULL
);
100 lfd
= strtol(_launchd_fd
, NULL
, 10);
101 if ((dfd
= dup(lfd
)) >= 0) {
107 unsetenv(LAUNCHD_TRUSTED_FD_ENV
);
110 memset(&sun
, 0, sizeof(sun
));
111 sun
.sun_family
= AF_UNIX
;
114 strncpy(sun
.sun_path
, where
, sizeof(sun
.sun_path
));
116 snprintf(sun
.sun_path
, sizeof(sun
.sun_path
), "%s/%u/sock", LAUNCHD_SOCK_PREFIX
, getuid());
118 if ((lfd
= _fd(socket(AF_UNIX
, SOCK_STREAM
, 0))) == -1)
121 for (tries
= 0; tries
< 10; tries
++) {
122 r
= connect(lfd
, (struct sockaddr
*)&sun
, sizeof(sun
));
124 if (getuid() != 0 && fork() == 0)
125 execl("/sbin/launchd", "/sbin/launchd", NULL
);
136 if (!(_lc
->l
= launchd_fdopen(lfd
))) {
140 if (!(_lc
->async_resp
= launch_data_alloc(LAUNCH_DATA_ARRAY
)))
146 launchd_close(_lc
->l
);
152 launch_data_t
launch_data_alloc(launch_data_type_t t
)
154 launch_data_t d
= calloc(1, sizeof(struct _launch
));
159 case LAUNCH_DATA_DICTIONARY
:
160 case LAUNCH_DATA_ARRAY
:
161 d
->_array
= malloc(0);
171 launch_data_type_t
launch_data_get_type(launch_data_t d
)
176 void launch_data_free(launch_data_t d
)
181 case LAUNCH_DATA_DICTIONARY
:
182 case LAUNCH_DATA_ARRAY
:
183 for (i
= 0; i
< d
->_array_cnt
; i
++)
184 launch_data_free(d
->_array
[i
]);
187 case LAUNCH_DATA_STRING
:
191 case LAUNCH_DATA_OPAQUE
:
201 size_t launch_data_dict_get_count(launch_data_t dict
)
203 return dict
->_array_cnt
/ 2;
207 bool launch_data_dict_insert(launch_data_t dict
, launch_data_t what
, const char *key
)
210 launch_data_t thekey
= launch_data_alloc(LAUNCH_DATA_STRING
);
212 launch_data_set_string(thekey
, key
);
214 for (i
= 0; i
< dict
->_array_cnt
; i
+= 2) {
215 if (!strcasecmp(key
, dict
->_array
[i
]->string
)) {
216 launch_data_array_set_index(dict
, thekey
, i
);
217 launch_data_array_set_index(dict
, what
, i
+ 1);
221 launch_data_array_set_index(dict
, thekey
, i
);
222 launch_data_array_set_index(dict
, what
, i
+ 1);
226 launch_data_t
launch_data_dict_lookup(launch_data_t dict
, const char *key
)
230 if (LAUNCH_DATA_DICTIONARY
!= dict
->type
)
233 for (i
= 0; i
< dict
->_array_cnt
; i
+= 2) {
234 if (!strcasecmp(key
, dict
->_array
[i
]->string
))
235 return dict
->_array
[i
+ 1];
241 bool launch_data_dict_remove(launch_data_t dict
, const char *key
)
245 for (i
= 0; i
< dict
->_array_cnt
; i
+= 2) {
246 if (!strcasecmp(key
, dict
->_array
[i
]->string
))
249 if (i
== dict
->_array_cnt
)
251 launch_data_free(dict
->_array
[i
]);
252 launch_data_free(dict
->_array
[i
+ 1]);
253 memmove(dict
->_array
+ i
, dict
->_array
+ i
+ 2, (dict
->_array_cnt
- (i
+ 2)) * sizeof(launch_data_t
));
254 dict
->_array_cnt
-= 2;
258 void launch_data_dict_iterate(launch_data_t dict
, void (*cb
)(launch_data_t
, const char *, void *), void *context
)
262 if (LAUNCH_DATA_DICTIONARY
!= dict
->type
)
265 for (i
= 0; i
< dict
->_array_cnt
; i
+= 2)
266 cb(dict
->_array
[i
+ 1], dict
->_array
[i
]->string
, context
);
269 bool launch_data_array_set_index(launch_data_t where
, launch_data_t what
, size_t ind
)
271 if ((ind
+ 1) >= where
->_array_cnt
) {
272 where
->_array
= realloc(where
->_array
, (ind
+ 1) * sizeof(launch_data_t
));
273 memset(where
->_array
+ where
->_array_cnt
, 0, (ind
+ 1 - where
->_array_cnt
) * sizeof(launch_data_t
));
274 where
->_array_cnt
= ind
+ 1;
277 if (where
->_array
[ind
])
278 launch_data_free(where
->_array
[ind
]);
279 where
->_array
[ind
] = what
;
283 launch_data_t
launch_data_array_get_index(launch_data_t where
, size_t ind
)
285 if (LAUNCH_DATA_ARRAY
!= where
->type
)
287 if (ind
< where
->_array_cnt
)
288 return where
->_array
[ind
];
292 launch_data_t
launch_data_array_pop_first(launch_data_t where
)
294 launch_data_t r
= NULL
;
296 if (where
->_array_cnt
> 0) {
297 r
= where
->_array
[0];
298 memmove(where
->_array
, where
->_array
+ 1, (where
->_array_cnt
- 1) * sizeof(launch_data_t
));
304 size_t launch_data_array_get_count(launch_data_t where
)
306 if (LAUNCH_DATA_ARRAY
!= where
->type
)
308 return where
->_array_cnt
;
311 bool launch_data_set_errno(launch_data_t d
, int e
)
317 bool launch_data_set_fd(launch_data_t d
, int fd
)
323 bool launch_data_set_integer(launch_data_t d
, long long n
)
329 bool launch_data_set_bool(launch_data_t d
, bool b
)
335 bool launch_data_set_real(launch_data_t d
, double n
)
341 bool launch_data_set_string(launch_data_t d
, const char *s
)
345 d
->string
= strdup(s
);
347 d
->string_len
= strlen(d
->string
);
353 bool launch_data_set_opaque(launch_data_t d
, const void *o
, size_t os
)
358 d
->opaque
= malloc(os
);
360 memcpy(d
->opaque
, o
, os
);
366 int launch_data_get_errno(launch_data_t d
)
371 int launch_data_get_fd(launch_data_t d
)
376 long long launch_data_get_integer(launch_data_t d
)
381 bool launch_data_get_bool(launch_data_t d
)
386 double launch_data_get_real(launch_data_t d
)
391 const char *launch_data_get_string(launch_data_t d
)
393 if (LAUNCH_DATA_STRING
!= d
->type
)
398 void *launch_data_get_opaque(launch_data_t d
)
400 if (LAUNCH_DATA_OPAQUE
!= d
->type
)
405 size_t launch_data_get_opaque_size(launch_data_t d
)
407 return d
->opaque_size
;
410 int launchd_getfd(launch_t l
)
415 launch_t
launchd_fdopen(int fd
)
419 c
= calloc(1, sizeof(struct _launch
));
425 fcntl(fd
, F_SETFL
, O_NONBLOCK
);
427 if ((c
->sendbuf
= malloc(0)) == NULL
)
429 if ((c
->sendfds
= malloc(0)) == NULL
)
431 if ((c
->recvbuf
= malloc(0)) == NULL
)
433 if ((c
->recvfds
= malloc(0)) == NULL
)
451 void launchd_close(launch_t lh
)
465 static void make_msg_and_cmsg(launch_data_t d
, void **where
, size_t *len
, int **fd_where
, size_t *fdcnt
)
469 *where
= realloc(*where
, *len
+ sizeof(struct _launch_data
));
470 memcpy(*where
+ *len
, d
, sizeof(struct _launch_data
));
471 *len
+= sizeof(struct _launch_data
);
476 *fd_where
= realloc(*fd_where
, (*fdcnt
+ 1) * sizeof(int));
477 (*fd_where
)[*fdcnt
] = d
->fd
;
481 case LAUNCH_DATA_STRING
:
482 *where
= realloc(*where
, *len
+ strlen(d
->string
) + 1);
483 memcpy(*where
+ *len
, d
->string
, strlen(d
->string
) + 1);
484 *len
+= strlen(d
->string
) + 1;
486 case LAUNCH_DATA_OPAQUE
:
487 *where
= realloc(*where
, *len
+ d
->opaque_size
);
488 memcpy(*where
+ *len
, d
->opaque
, d
->opaque_size
);
489 *len
+= d
->opaque_size
;
491 case LAUNCH_DATA_DICTIONARY
:
492 case LAUNCH_DATA_ARRAY
:
493 *where
= realloc(*where
, *len
+ (d
->_array_cnt
* sizeof(launch_data_t
)));
494 memcpy(*where
+ *len
, d
->_array
, d
->_array_cnt
* sizeof(launch_data_t
));
495 *len
+= d
->_array_cnt
* sizeof(launch_data_t
);
497 for (i
= 0; i
< d
->_array_cnt
; i
++)
498 make_msg_and_cmsg(d
->_array
[i
], where
, len
, fd_where
, fdcnt
);
505 static launch_data_t
make_data(launch_t conn
, size_t *data_offset
, size_t *fdoffset
)
507 launch_data_t r
= conn
->recvbuf
+ *data_offset
;
510 if ((conn
->recvlen
- *data_offset
) < sizeof(struct _launch_data
))
512 *data_offset
+= sizeof(struct _launch_data
);
515 case LAUNCH_DATA_DICTIONARY
:
516 case LAUNCH_DATA_ARRAY
:
517 if ((conn
->recvlen
- *data_offset
) < (r
->_array_cnt
* sizeof(launch_data_t
))) {
521 r
->_array
= conn
->recvbuf
+ *data_offset
;
522 *data_offset
+= r
->_array_cnt
* sizeof(launch_data_t
);
523 for (i
= 0; i
< r
->_array_cnt
; i
++) {
524 r
->_array
[i
] = make_data(conn
, data_offset
, fdoffset
);
525 if (r
->_array
[i
] == NULL
)
529 case LAUNCH_DATA_STRING
:
530 if ((conn
->recvlen
- *data_offset
) < (r
->string_len
+ 1)) {
534 r
->string
= conn
->recvbuf
+ *data_offset
;
535 *data_offset
+= r
->string_len
+ 1;
537 case LAUNCH_DATA_OPAQUE
:
538 if ((conn
->recvlen
- *data_offset
) < r
->opaque_size
) {
542 r
->opaque
= conn
->recvbuf
+ *data_offset
;
543 *data_offset
+= r
->opaque_size
;
547 r
->fd
= _fd(conn
->recvfds
[*fdoffset
]);
551 case LAUNCH_DATA_INTEGER
:
552 case LAUNCH_DATA_REAL
:
553 case LAUNCH_DATA_BOOL
:
554 case LAUNCH_DATA_ERRNO
:
565 int launchd_msg_send(launch_t lh
, launch_data_t d
)
567 struct cmsghdr
*cm
= NULL
;
571 size_t sentctrllen
= 0;
573 memset(&mh
, 0, sizeof(mh
));
579 make_msg_and_cmsg(d
, &lh
->sendbuf
, &lh
->sendlen
, &lh
->sendfds
, &lh
->sendfdcnt
);
581 if (lh
->sendfdcnt
> 0) {
582 sentctrllen
= mh
.msg_controllen
= CMSG_SPACE(lh
->sendfdcnt
* sizeof(int));
583 cm
= alloca(mh
.msg_controllen
);
586 memset(cm
, 0, mh
.msg_controllen
);
588 cm
->cmsg_len
= CMSG_LEN(lh
->sendfdcnt
* sizeof(int));
589 cm
->cmsg_level
= SOL_SOCKET
;
590 cm
->cmsg_type
= SCM_RIGHTS
;
592 memcpy(CMSG_DATA(cm
), lh
->sendfds
, lh
->sendfdcnt
* sizeof(int));
595 iov
.iov_base
= lh
->sendbuf
;
596 iov
.iov_len
= lh
->sendlen
;
598 if ((r
= sendmsg(lh
->fd
, &mh
, 0)) == -1) {
603 } else if (sentctrllen
!= mh
.msg_controllen
) {
609 if (lh
->sendlen
> 0) {
610 memmove(lh
->sendbuf
, lh
->sendbuf
+ r
, lh
->sendlen
);
613 lh
->sendbuf
= malloc(0);
618 lh
->sendfds
= malloc(0);
620 if (lh
->sendlen
> 0) {
629 int launch_get_fd(void)
631 pthread_once(&_lc_once
, launch_client_init
);
641 static void launch_msg_getmsgs(launch_data_t m
, void *context
)
643 launch_data_t async_resp
, *sync_resp
= context
;
645 if ((LAUNCH_DATA_DICTIONARY
== launch_data_get_type(m
)) && (async_resp
= launch_data_dict_lookup(m
, LAUNCHD_ASYNC_MSG_KEY
))) {
646 launch_data_array_set_index(_lc
->async_resp
, launch_data_copy(async_resp
), launch_data_array_get_count(_lc
->async_resp
));
648 *sync_resp
= launch_data_copy(m
);
652 launch_data_t
launch_msg(launch_data_t d
)
654 launch_data_t resp
= NULL
;
656 pthread_once(&_lc_once
, launch_client_init
);
663 pthread_mutex_lock(&_lc
->mtx
);
665 if (d
&& launchd_msg_send(_lc
->l
, d
) == -1) {
669 } while (launchd_msg_send(_lc
->l
, NULL
) == -1);
672 while (resp
== NULL
) {
673 if (d
== NULL
&& launch_data_array_get_count(_lc
->async_resp
) > 0) {
674 resp
= launch_data_array_pop_first(_lc
->async_resp
);
677 if (launchd_msg_recv(_lc
->l
, launch_msg_getmsgs
, &resp
) == -1) {
678 if (errno
!= EAGAIN
) {
680 } else if (d
== NULL
) {
687 FD_SET(_lc
->l
->fd
, &rfds
);
689 select(_lc
->l
->fd
+ 1, &rfds
, NULL
, NULL
, NULL
);
695 pthread_mutex_unlock(&_lc
->mtx
);
700 int launchd_msg_recv(launch_t lh
, void (*cb
)(launch_data_t
, void *), void *context
)
702 struct cmsghdr
*cm
= alloca(4096);
704 size_t data_offset
, fd_offset
;
709 memset(&mh
, 0, sizeof(mh
));
713 lh
->recvbuf
= realloc(lh
->recvbuf
, lh
->recvlen
+ 8*1024);
715 iov
.iov_base
= lh
->recvbuf
+ lh
->recvlen
;
716 iov
.iov_len
= 8*1024;
718 mh
.msg_controllen
= 4096;
720 if ((r
= recvmsg(lh
->fd
, &mh
, 0)) == -1)
726 if (mh
.msg_flags
& MSG_CTRUNC
) {
727 errno
= ECONNABORTED
;
731 if (mh
.msg_controllen
> 0) {
732 lh
->recvfds
= realloc(lh
->recvfds
, lh
->recvfdcnt
* sizeof(int) + mh
.msg_controllen
- sizeof(struct cmsghdr
));
733 memcpy(lh
->recvfds
+ lh
->recvfdcnt
, CMSG_DATA(cm
), mh
.msg_controllen
- sizeof(struct cmsghdr
));
734 lh
->recvfdcnt
+= (mh
.msg_controllen
- sizeof(struct cmsghdr
)) / sizeof(int);
741 rmsg
= make_data(lh
, &data_offset
, &fd_offset
);
746 lh
->recvlen
-= data_offset
;
747 if (lh
->recvlen
> 0) {
748 memmove(lh
->recvbuf
, lh
->recvbuf
+ data_offset
, lh
->recvlen
);
751 lh
->recvbuf
= malloc(0);
754 lh
->recvfdcnt
-= fd_offset
;
755 if (lh
->recvfdcnt
> 0) {
756 memmove(lh
->recvfds
, lh
->recvfds
+ fd_offset
, lh
->recvfdcnt
* sizeof(int));
759 lh
->recvfds
= malloc(0);
774 launch_data_t
launch_data_copy(launch_data_t o
)
776 launch_data_t r
= launch_data_alloc(o
->type
);
780 memcpy(r
, o
, sizeof(struct _launch_data
));
783 case LAUNCH_DATA_DICTIONARY
:
784 case LAUNCH_DATA_ARRAY
:
785 r
->_array
= calloc(1, o
->_array_cnt
* sizeof(launch_data_t
));
786 for (i
= 0; i
< o
->_array_cnt
; i
++) {
788 r
->_array
[i
] = launch_data_copy(o
->_array
[i
]);
791 case LAUNCH_DATA_STRING
:
792 r
->string
= strdup(o
->string
);
794 case LAUNCH_DATA_OPAQUE
:
795 r
->opaque
= malloc(o
->opaque_size
);
796 memcpy(r
->opaque
, o
->opaque
, o
->opaque_size
);
805 void launchd_batch_enable(bool val
)
807 launch_data_t resp
, tmp
, msg
;
809 tmp
= launch_data_alloc(LAUNCH_DATA_BOOL
);
810 launch_data_set_bool(tmp
, val
);
812 msg
= launch_data_alloc(LAUNCH_DATA_DICTIONARY
);
813 launch_data_dict_insert(msg
, tmp
, LAUNCH_KEY_BATCHCONTROL
);
815 resp
= launch_msg(msg
);
817 launch_data_free(msg
);
820 launch_data_free(resp
);
823 bool launchd_batch_query(void)
825 launch_data_t resp
, msg
= launch_data_alloc(LAUNCH_DATA_STRING
);
828 launch_data_set_string(msg
, LAUNCH_KEY_BATCHQUERY
);
830 resp
= launch_msg(msg
);
832 launch_data_free(msg
);
835 if (launch_data_get_type(resp
) == LAUNCH_DATA_BOOL
)
836 rval
= launch_data_get_bool(resp
);
837 launch_data_free(resp
);
842 static int _fd(int fd
)
845 fcntl(fd
, F_SETFD
, 1);
849 launch_data_t
launch_data_new_errno(int e
)
851 launch_data_t r
= launch_data_alloc(LAUNCH_DATA_ERRNO
);
854 launch_data_set_errno(r
, e
);
859 launch_data_t
launch_data_new_fd(int fd
)
861 launch_data_t r
= launch_data_alloc(LAUNCH_DATA_FD
);
864 launch_data_set_fd(r
, fd
);
869 launch_data_t
launch_data_new_integer(long long n
)
871 launch_data_t r
= launch_data_alloc(LAUNCH_DATA_INTEGER
);
874 launch_data_set_integer(r
, n
);
879 launch_data_t
launch_data_new_bool(bool b
)
881 launch_data_t r
= launch_data_alloc(LAUNCH_DATA_BOOL
);
884 launch_data_set_bool(r
, b
);
889 launch_data_t
launch_data_new_real(double d
)
891 launch_data_t r
= launch_data_alloc(LAUNCH_DATA_REAL
);
894 launch_data_set_real(r
, d
);
899 launch_data_t
launch_data_new_string(const char *s
)
901 launch_data_t r
= launch_data_alloc(LAUNCH_DATA_STRING
);
906 if (!launch_data_set_string(r
, s
)) {
914 launch_data_t
launch_data_new_opaque(const void *o
, size_t os
)
916 launch_data_t r
= launch_data_alloc(LAUNCH_DATA_OPAQUE
);
921 if (!launch_data_set_opaque(r
, o
, os
)) {