]> git.saurik.com Git - apple/launchd.git/blob - launchd/src/liblaunch.c
cc23170c5d1c3e535391bb7517da4c55307ba265
[apple/launchd.git] / launchd / src / liblaunch.c
1 /*
2 * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23 #include <sys/types.h>
24 #include <sys/socket.h>
25 #include <sys/fcntl.h>
26 #include <sys/un.h>
27 #include <sys/uio.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <pthread.h>
32 #include <unistd.h>
33 #include <errno.h>
34
35 #include "launch.h"
36 #include "launch_priv.h"
37
38 struct _launch_data {
39 launch_data_type_t type;
40 union {
41 struct {
42 launch_data_t *_array;
43 size_t _array_cnt;
44 };
45 struct {
46 char *string;
47 size_t string_len;
48 };
49 struct {
50 void *opaque;
51 size_t opaque_size;
52 };
53 int fd;
54 int err;
55 long long number;
56 bool boolean;
57 double float_num;
58 };
59 };
60
61 struct _launch {
62 void *sendbuf;
63 int *sendfds;
64 void *recvbuf;
65 int *recvfds;
66 size_t sendlen;
67 size_t sendfdcnt;
68 size_t recvlen;
69 size_t recvfdcnt;
70 int fd;
71 };
72
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);
76
77 static pthread_once_t _lc_once = PTHREAD_ONCE_INIT;
78
79 static struct _launch_client {
80 pthread_mutex_t mtx;
81 launch_t l;
82 launch_data_t async_resp;
83 } *_lc = NULL;
84
85 static void launch_client_init(void)
86 {
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;
91
92 _lc = calloc(1, sizeof(struct _launch_client));
93
94 if (!_lc)
95 return;
96
97 pthread_mutex_init(&_lc->mtx, NULL);
98
99 if (_launchd_fd) {
100 lfd = strtol(_launchd_fd, NULL, 10);
101 if ((dfd = dup(lfd)) >= 0) {
102 close(dfd);
103 _fd(lfd);
104 } else {
105 lfd = -1;
106 }
107 unsetenv(LAUNCHD_TRUSTED_FD_ENV);
108 }
109 if (lfd == -1) {
110 memset(&sun, 0, sizeof(sun));
111 sun.sun_family = AF_UNIX;
112
113 if (where)
114 strncpy(sun.sun_path, where, sizeof(sun.sun_path));
115 else
116 snprintf(sun.sun_path, sizeof(sun.sun_path), "%s/%u/sock", LAUNCHD_SOCK_PREFIX, getuid());
117
118 if ((lfd = _fd(socket(AF_UNIX, SOCK_STREAM, 0))) == -1)
119 goto out_bad;
120
121 for (tries = 0; tries < 10; tries++) {
122 r = connect(lfd, (struct sockaddr *)&sun, sizeof(sun));
123 if (r == -1) {
124 if (getuid() != 0 && fork() == 0)
125 execl("/sbin/launchd", "/sbin/launchd", NULL);
126 sleep(1);
127 } else {
128 break;
129 }
130 }
131 if (r == -1) {
132 close(lfd);
133 goto out_bad;
134 }
135 }
136 if (!(_lc->l = launchd_fdopen(lfd))) {
137 close(lfd);
138 goto out_bad;
139 }
140 if (!(_lc->async_resp = launch_data_alloc(LAUNCH_DATA_ARRAY)))
141 goto out_bad;
142
143 return;
144 out_bad:
145 if (_lc->l)
146 launchd_close(_lc->l);
147 if (_lc)
148 free(_lc);
149 _lc = NULL;
150 }
151
152 launch_data_t launch_data_alloc(launch_data_type_t t)
153 {
154 launch_data_t d = calloc(1, sizeof(struct _launch));
155
156 if (d) {
157 d->type = t;
158 switch (t) {
159 case LAUNCH_DATA_DICTIONARY:
160 case LAUNCH_DATA_ARRAY:
161 d->_array = malloc(0);
162 break;
163 default:
164 break;
165 }
166 }
167
168 return d;
169 }
170
171 launch_data_type_t launch_data_get_type(launch_data_t d)
172 {
173 return d->type;
174 }
175
176 void launch_data_free(launch_data_t d)
177 {
178 size_t i;
179
180 switch (d->type) {
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]);
185 free(d->_array);
186 break;
187 case LAUNCH_DATA_STRING:
188 if (d->string)
189 free(d->string);
190 break;
191 case LAUNCH_DATA_OPAQUE:
192 if (d->opaque)
193 free(d->opaque);
194 break;
195 default:
196 break;
197 }
198 free(d);
199 }
200
201 size_t launch_data_dict_get_count(launch_data_t dict)
202 {
203 return dict->_array_cnt / 2;
204 }
205
206
207 bool launch_data_dict_insert(launch_data_t dict, launch_data_t what, const char *key)
208 {
209 size_t i;
210 launch_data_t thekey = launch_data_alloc(LAUNCH_DATA_STRING);
211
212 launch_data_set_string(thekey, key);
213
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);
218 return true;
219 }
220 }
221 launch_data_array_set_index(dict, thekey, i);
222 launch_data_array_set_index(dict, what, i + 1);
223 return true;
224 }
225
226 launch_data_t launch_data_dict_lookup(launch_data_t dict, const char *key)
227 {
228 size_t i;
229
230 if (LAUNCH_DATA_DICTIONARY != dict->type)
231 return NULL;
232
233 for (i = 0; i < dict->_array_cnt; i += 2) {
234 if (!strcasecmp(key, dict->_array[i]->string))
235 return dict->_array[i + 1];
236 }
237
238 return NULL;
239 }
240
241 bool launch_data_dict_remove(launch_data_t dict, const char *key)
242 {
243 size_t i;
244
245 for (i = 0; i < dict->_array_cnt; i += 2) {
246 if (!strcasecmp(key, dict->_array[i]->string))
247 break;
248 }
249 if (i == dict->_array_cnt)
250 return false;
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;
255 return true;
256 }
257
258 void launch_data_dict_iterate(launch_data_t dict, void (*cb)(launch_data_t, const char *, void *), void *context)
259 {
260 size_t i;
261
262 if (LAUNCH_DATA_DICTIONARY != dict->type)
263 return;
264
265 for (i = 0; i < dict->_array_cnt; i += 2)
266 cb(dict->_array[i + 1], dict->_array[i]->string, context);
267 }
268
269 bool launch_data_array_set_index(launch_data_t where, launch_data_t what, size_t ind)
270 {
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;
275 }
276
277 if (where->_array[ind])
278 launch_data_free(where->_array[ind]);
279 where->_array[ind] = what;
280 return true;
281 }
282
283 launch_data_t launch_data_array_get_index(launch_data_t where, size_t ind)
284 {
285 if (LAUNCH_DATA_ARRAY != where->type)
286 return NULL;
287 if (ind < where->_array_cnt)
288 return where->_array[ind];
289 return NULL;
290 }
291
292 launch_data_t launch_data_array_pop_first(launch_data_t where)
293 {
294 launch_data_t r = NULL;
295
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));
299 where->_array_cnt--;
300 }
301 return r;
302 }
303
304 size_t launch_data_array_get_count(launch_data_t where)
305 {
306 if (LAUNCH_DATA_ARRAY != where->type)
307 return 0;
308 return where->_array_cnt;
309 }
310
311 bool launch_data_set_errno(launch_data_t d, int e)
312 {
313 d->err = e;
314 return true;
315 }
316
317 bool launch_data_set_fd(launch_data_t d, int fd)
318 {
319 d->fd = fd;
320 return true;
321 }
322
323 bool launch_data_set_integer(launch_data_t d, long long n)
324 {
325 d->number = n;
326 return true;
327 }
328
329 bool launch_data_set_bool(launch_data_t d, bool b)
330 {
331 d->boolean = b;
332 return true;
333 }
334
335 bool launch_data_set_real(launch_data_t d, double n)
336 {
337 d->float_num = n;
338 return true;
339 }
340
341 bool launch_data_set_string(launch_data_t d, const char *s)
342 {
343 if (d->string)
344 free(d->string);
345 d->string = strdup(s);
346 if (d->string) {
347 d->string_len = strlen(d->string);
348 return true;
349 }
350 return false;
351 }
352
353 bool launch_data_set_opaque(launch_data_t d, const void *o, size_t os)
354 {
355 d->opaque_size = os;
356 if (d->opaque)
357 free(d->opaque);
358 d->opaque = malloc(os);
359 if (d->opaque) {
360 memcpy(d->opaque, o, os);
361 return true;
362 }
363 return false;
364 }
365
366 int launch_data_get_errno(launch_data_t d)
367 {
368 return d->err;
369 }
370
371 int launch_data_get_fd(launch_data_t d)
372 {
373 return d->fd;
374 }
375
376 long long launch_data_get_integer(launch_data_t d)
377 {
378 return d->number;
379 }
380
381 bool launch_data_get_bool(launch_data_t d)
382 {
383 return d->boolean;
384 }
385
386 double launch_data_get_real(launch_data_t d)
387 {
388 return d->float_num;
389 }
390
391 const char *launch_data_get_string(launch_data_t d)
392 {
393 if (LAUNCH_DATA_STRING != d->type)
394 return NULL;
395 return d->string;
396 }
397
398 void *launch_data_get_opaque(launch_data_t d)
399 {
400 if (LAUNCH_DATA_OPAQUE != d->type)
401 return NULL;
402 return d->opaque;
403 }
404
405 size_t launch_data_get_opaque_size(launch_data_t d)
406 {
407 return d->opaque_size;
408 }
409
410 int launchd_getfd(launch_t l)
411 {
412 return l->fd;
413 }
414
415 launch_t launchd_fdopen(int fd)
416 {
417 launch_t c;
418
419 c = calloc(1, sizeof(struct _launch));
420 if (!c)
421 return NULL;
422
423 c->fd = fd;
424
425 fcntl(fd, F_SETFL, O_NONBLOCK);
426
427 if ((c->sendbuf = malloc(0)) == NULL)
428 goto out_bad;
429 if ((c->sendfds = malloc(0)) == NULL)
430 goto out_bad;
431 if ((c->recvbuf = malloc(0)) == NULL)
432 goto out_bad;
433 if ((c->recvfds = malloc(0)) == NULL)
434 goto out_bad;
435
436 return c;
437
438 out_bad:
439 if (c->sendbuf)
440 free(c->sendbuf);
441 if (c->sendfds)
442 free(c->sendfds);
443 if (c->recvbuf)
444 free(c->recvbuf);
445 if (c->recvfds)
446 free(c->recvfds);
447 free(c);
448 return NULL;
449 }
450
451 void launchd_close(launch_t lh)
452 {
453 if (lh->sendbuf)
454 free(lh->sendbuf);
455 if (lh->sendfds)
456 free(lh->sendfds);
457 if (lh->recvbuf)
458 free(lh->recvbuf);
459 if (lh->recvfds)
460 free(lh->recvfds);
461 close(lh->fd);
462 free(lh);
463 }
464
465 static void make_msg_and_cmsg(launch_data_t d, void **where, size_t *len, int **fd_where, size_t *fdcnt)
466 {
467 size_t i;
468
469 *where = realloc(*where, *len + sizeof(struct _launch_data));
470 memcpy(*where + *len, d, sizeof(struct _launch_data));
471 *len += sizeof(struct _launch_data);
472
473 switch (d->type) {
474 case LAUNCH_DATA_FD:
475 if (d->fd != -1) {
476 *fd_where = realloc(*fd_where, (*fdcnt + 1) * sizeof(int));
477 (*fd_where)[*fdcnt] = d->fd;
478 (*fdcnt)++;
479 }
480 break;
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;
485 break;
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;
490 break;
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);
496
497 for (i = 0; i < d->_array_cnt; i++)
498 make_msg_and_cmsg(d->_array[i], where, len, fd_where, fdcnt);
499 break;
500 default:
501 break;
502 }
503 }
504
505 static launch_data_t make_data(launch_t conn, size_t *data_offset, size_t *fdoffset)
506 {
507 launch_data_t r = conn->recvbuf + *data_offset;
508 size_t i;
509
510 if ((conn->recvlen - *data_offset) < sizeof(struct _launch_data))
511 return NULL;
512 *data_offset += sizeof(struct _launch_data);
513
514 switch (r->type) {
515 case LAUNCH_DATA_DICTIONARY:
516 case LAUNCH_DATA_ARRAY:
517 if ((conn->recvlen - *data_offset) < (r->_array_cnt * sizeof(launch_data_t))) {
518 errno = EAGAIN;
519 return NULL;
520 }
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)
526 return NULL;
527 }
528 break;
529 case LAUNCH_DATA_STRING:
530 if ((conn->recvlen - *data_offset) < (r->string_len + 1)) {
531 errno = EAGAIN;
532 return NULL;
533 }
534 r->string = conn->recvbuf + *data_offset;
535 *data_offset += r->string_len + 1;
536 break;
537 case LAUNCH_DATA_OPAQUE:
538 if ((conn->recvlen - *data_offset) < r->opaque_size) {
539 errno = EAGAIN;
540 return NULL;
541 }
542 r->opaque = conn->recvbuf + *data_offset;
543 *data_offset += r->opaque_size;
544 break;
545 case LAUNCH_DATA_FD:
546 if (r->fd != -1) {
547 r->fd = _fd(conn->recvfds[*fdoffset]);
548 *fdoffset += 1;
549 }
550 break;
551 case LAUNCH_DATA_INTEGER:
552 case LAUNCH_DATA_REAL:
553 case LAUNCH_DATA_BOOL:
554 case LAUNCH_DATA_ERRNO:
555 break;
556 default:
557 errno = EINVAL;
558 return NULL;
559 break;
560 }
561
562 return r;
563 }
564
565 int launchd_msg_send(launch_t lh, launch_data_t d)
566 {
567 struct cmsghdr *cm = NULL;
568 struct msghdr mh;
569 struct iovec iov;
570 int r;
571 size_t sentctrllen = 0;
572
573 memset(&mh, 0, sizeof(mh));
574
575 mh.msg_iov = &iov;
576 mh.msg_iovlen = 1;
577
578 if (d)
579 make_msg_and_cmsg(d, &lh->sendbuf, &lh->sendlen, &lh->sendfds, &lh->sendfdcnt);
580
581 if (lh->sendfdcnt > 0) {
582 sentctrllen = mh.msg_controllen = CMSG_SPACE(lh->sendfdcnt * sizeof(int));
583 cm = alloca(mh.msg_controllen);
584 mh.msg_control = cm;
585
586 memset(cm, 0, mh.msg_controllen);
587
588 cm->cmsg_len = CMSG_LEN(lh->sendfdcnt * sizeof(int));
589 cm->cmsg_level = SOL_SOCKET;
590 cm->cmsg_type = SCM_RIGHTS;
591
592 memcpy(CMSG_DATA(cm), lh->sendfds, lh->sendfdcnt * sizeof(int));
593 }
594
595 iov.iov_base = lh->sendbuf;
596 iov.iov_len = lh->sendlen;
597
598 if ((r = sendmsg(lh->fd, &mh, 0)) == -1) {
599 return -1;
600 } else if (r == 0) {
601 errno = ECONNRESET;
602 return -1;
603 } else if (sentctrllen != mh.msg_controllen) {
604 errno = ECONNRESET;
605 return -1;
606 }
607
608 lh->sendlen -= r;
609 if (lh->sendlen > 0) {
610 memmove(lh->sendbuf, lh->sendbuf + r, lh->sendlen);
611 } else {
612 free(lh->sendbuf);
613 lh->sendbuf = malloc(0);
614 }
615
616 lh->sendfdcnt = 0;
617 free(lh->sendfds);
618 lh->sendfds = malloc(0);
619
620 if (lh->sendlen > 0) {
621 errno = EAGAIN;
622 return -1;
623 }
624
625 return 0;
626 }
627
628
629 int launch_get_fd(void)
630 {
631 pthread_once(&_lc_once, launch_client_init);
632
633 if (!_lc) {
634 errno = ENOTCONN;
635 return -1;
636 }
637
638 return _lc->l->fd;
639 }
640
641 static void launch_msg_getmsgs(launch_data_t m, void *context)
642 {
643 launch_data_t async_resp, *sync_resp = context;
644
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));
647 } else {
648 *sync_resp = launch_data_copy(m);
649 }
650 }
651
652 launch_data_t launch_msg(launch_data_t d)
653 {
654 launch_data_t resp = NULL;
655
656 pthread_once(&_lc_once, launch_client_init);
657
658 if (!_lc) {
659 errno = ENOTCONN;
660 return NULL;
661 }
662
663 pthread_mutex_lock(&_lc->mtx);
664
665 if (d && launchd_msg_send(_lc->l, d) == -1) {
666 do {
667 if (errno != EAGAIN)
668 goto out;
669 } while (launchd_msg_send(_lc->l, NULL) == -1);
670 }
671
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);
675 goto out;
676 }
677 if (launchd_msg_recv(_lc->l, launch_msg_getmsgs, &resp) == -1) {
678 if (errno != EAGAIN) {
679 goto out;
680 } else if (d == NULL) {
681 errno = 0;
682 goto out;
683 } else {
684 fd_set rfds;
685
686 FD_ZERO(&rfds);
687 FD_SET(_lc->l->fd, &rfds);
688
689 select(_lc->l->fd + 1, &rfds, NULL, NULL, NULL);
690 }
691 }
692 }
693
694 out:
695 pthread_mutex_unlock(&_lc->mtx);
696
697 return resp;
698 }
699
700 int launchd_msg_recv(launch_t lh, void (*cb)(launch_data_t, void *), void *context)
701 {
702 struct cmsghdr *cm = alloca(4096);
703 launch_data_t rmsg;
704 size_t data_offset, fd_offset;
705 struct msghdr mh;
706 struct iovec iov;
707 int r;
708
709 memset(&mh, 0, sizeof(mh));
710 mh.msg_iov = &iov;
711 mh.msg_iovlen = 1;
712
713 lh->recvbuf = realloc(lh->recvbuf, lh->recvlen + 8*1024);
714
715 iov.iov_base = lh->recvbuf + lh->recvlen;
716 iov.iov_len = 8*1024;
717 mh.msg_control = cm;
718 mh.msg_controllen = 4096;
719
720 if ((r = recvmsg(lh->fd, &mh, 0)) == -1)
721 return -1;
722 if (r == 0) {
723 errno = ECONNRESET;
724 return -1;
725 }
726 if (mh.msg_flags & MSG_CTRUNC) {
727 errno = ECONNABORTED;
728 return -1;
729 }
730 lh->recvlen += r;
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);
735 }
736
737 parse_more:
738 data_offset = 0;
739 fd_offset = 0;
740
741 rmsg = make_data(lh, &data_offset, &fd_offset);
742
743 if (rmsg) {
744 cb(rmsg, context);
745
746 lh->recvlen -= data_offset;
747 if (lh->recvlen > 0) {
748 memmove(lh->recvbuf, lh->recvbuf + data_offset, lh->recvlen);
749 } else {
750 free(lh->recvbuf);
751 lh->recvbuf = malloc(0);
752 }
753
754 lh->recvfdcnt -= fd_offset;
755 if (lh->recvfdcnt > 0) {
756 memmove(lh->recvfds, lh->recvfds + fd_offset, lh->recvfdcnt * sizeof(int));
757 } else {
758 free(lh->recvfds);
759 lh->recvfds = malloc(0);
760 }
761
762 if (lh->recvlen > 0)
763 goto parse_more;
764 else
765 r = 0;
766 } else {
767 errno = EAGAIN;
768 r = -1;
769 }
770
771 return r;
772 }
773
774 launch_data_t launch_data_copy(launch_data_t o)
775 {
776 launch_data_t r = launch_data_alloc(o->type);
777 size_t i;
778
779 free(r->_array);
780 memcpy(r, o, sizeof(struct _launch_data));
781
782 switch (o->type) {
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++) {
787 if (o->_array[i])
788 r->_array[i] = launch_data_copy(o->_array[i]);
789 }
790 break;
791 case LAUNCH_DATA_STRING:
792 r->string = strdup(o->string);
793 break;
794 case LAUNCH_DATA_OPAQUE:
795 r->opaque = malloc(o->opaque_size);
796 memcpy(r->opaque, o->opaque, o->opaque_size);
797 break;
798 default:
799 break;
800 }
801
802 return r;
803 }
804
805 void launchd_batch_enable(bool val)
806 {
807 launch_data_t resp, tmp, msg;
808
809 tmp = launch_data_alloc(LAUNCH_DATA_BOOL);
810 launch_data_set_bool(tmp, val);
811
812 msg = launch_data_alloc(LAUNCH_DATA_DICTIONARY);
813 launch_data_dict_insert(msg, tmp, LAUNCH_KEY_BATCHCONTROL);
814
815 resp = launch_msg(msg);
816
817 launch_data_free(msg);
818
819 if (resp)
820 launch_data_free(resp);
821 }
822
823 bool launchd_batch_query(void)
824 {
825 launch_data_t resp, msg = launch_data_alloc(LAUNCH_DATA_STRING);
826 bool rval = true;
827
828 launch_data_set_string(msg, LAUNCH_KEY_BATCHQUERY);
829
830 resp = launch_msg(msg);
831
832 launch_data_free(msg);
833
834 if (resp) {
835 if (launch_data_get_type(resp) == LAUNCH_DATA_BOOL)
836 rval = launch_data_get_bool(resp);
837 launch_data_free(resp);
838 }
839 return rval;
840 }
841
842 static int _fd(int fd)
843 {
844 if (fd >= 0)
845 fcntl(fd, F_SETFD, 1);
846 return fd;
847 }
848
849 launch_data_t launch_data_new_errno(int e)
850 {
851 launch_data_t r = launch_data_alloc(LAUNCH_DATA_ERRNO);
852
853 if (r)
854 launch_data_set_errno(r, e);
855
856 return r;
857 }
858
859 launch_data_t launch_data_new_fd(int fd)
860 {
861 launch_data_t r = launch_data_alloc(LAUNCH_DATA_FD);
862
863 if (r)
864 launch_data_set_fd(r, fd);
865
866 return r;
867 }
868
869 launch_data_t launch_data_new_integer(long long n)
870 {
871 launch_data_t r = launch_data_alloc(LAUNCH_DATA_INTEGER);
872
873 if (r)
874 launch_data_set_integer(r, n);
875
876 return r;
877 }
878
879 launch_data_t launch_data_new_bool(bool b)
880 {
881 launch_data_t r = launch_data_alloc(LAUNCH_DATA_BOOL);
882
883 if (r)
884 launch_data_set_bool(r, b);
885
886 return r;
887 }
888
889 launch_data_t launch_data_new_real(double d)
890 {
891 launch_data_t r = launch_data_alloc(LAUNCH_DATA_REAL);
892
893 if (r)
894 launch_data_set_real(r, d);
895
896 return r;
897 }
898
899 launch_data_t launch_data_new_string(const char *s)
900 {
901 launch_data_t r = launch_data_alloc(LAUNCH_DATA_STRING);
902
903 if (r == NULL)
904 return NULL;
905
906 if (!launch_data_set_string(r, s)) {
907 launch_data_free(r);
908 return NULL;
909 }
910
911 return r;
912 }
913
914 launch_data_t launch_data_new_opaque(const void *o, size_t os)
915 {
916 launch_data_t r = launch_data_alloc(LAUNCH_DATA_OPAQUE);
917
918 if (r == NULL)
919 return NULL;
920
921 if (!launch_data_set_opaque(r, o, os)) {
922 launch_data_free(r);
923 return NULL;
924 }
925
926 return r;
927 }