]>
git.saurik.com Git - apple/launchd.git/blob - launchd/src/liblaunch.c
87de3cca8bc1e889881f865aa55041b26494bfbd
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 <libkern/OSByteOrder.h>
24 #include <sys/types.h>
25 #include <sys/socket.h>
26 #include <sys/fcntl.h>
37 #include "launch_priv.h"
39 /* __OSBogusByteSwap__() must not really exist in the symbol namespace
40 * in order for the following to generate an error at build time.
42 extern void __OSBogusByteSwap__(void);
45 ({ typeof (x) _X, _x = (x); \
46 switch (sizeof(_x)) { \
48 _X = OSSwapHostToBigInt64(_x); \
51 _X = OSSwapHostToBigInt32(_x); \
54 _X = OSSwapHostToBigInt16(_x); \
60 __OSBogusByteSwap__(); \
68 ({ typeof (x) _X, _x = (x); \
69 switch (sizeof(_x)) { \
71 _X = OSSwapBigToHostInt64(_x); \
74 _X = OSSwapBigToHostInt32(_x); \
77 _X = OSSwapBigToHostInt16(_x); \
83 __OSBogusByteSwap__(); \
90 struct launch_msg_header
{
95 #define LAUNCH_MSG_HEADER_MAGIC 0xD2FEA02366B39A41ull
101 launch_data_t
*_array
;
132 static void make_msg_and_cmsg(launch_data_t
, void **, size_t *, int **, size_t *);
133 static launch_data_t
make_data(launch_t
, size_t *, size_t *);
134 static int _fd(int fd
);
136 static pthread_once_t _lc_once
= PTHREAD_ONCE_INIT
;
138 static struct _launch_client
{
141 launch_data_t async_resp
;
144 static void launch_client_init(void)
146 struct sockaddr_un sun
;
147 char *where
= getenv(LAUNCHD_SOCKET_ENV
);
148 char *_launchd_fd
= getenv(LAUNCHD_TRUSTED_FD_ENV
);
149 int r
, dfd
, lfd
= -1, tries
;
151 _lc
= calloc(1, sizeof(struct _launch_client
));
156 pthread_mutex_init(&_lc
->mtx
, NULL
);
159 lfd
= strtol(_launchd_fd
, NULL
, 10);
160 if ((dfd
= dup(lfd
)) >= 0) {
166 unsetenv(LAUNCHD_TRUSTED_FD_ENV
);
169 memset(&sun
, 0, sizeof(sun
));
170 sun
.sun_family
= AF_UNIX
;
173 strncpy(sun
.sun_path
, where
, sizeof(sun
.sun_path
));
175 snprintf(sun
.sun_path
, sizeof(sun
.sun_path
), "%s/%u/sock", LAUNCHD_SOCK_PREFIX
, getuid());
177 if ((lfd
= _fd(socket(AF_UNIX
, SOCK_STREAM
, 0))) == -1)
180 for (tries
= 0; tries
< 10; tries
++) {
181 r
= connect(lfd
, (struct sockaddr
*)&sun
, sizeof(sun
));
183 if (getuid() != 0 && fork() == 0)
184 execl("/sbin/launchd", "/sbin/launchd", NULL
);
195 if (!(_lc
->l
= launchd_fdopen(lfd
))) {
199 if (!(_lc
->async_resp
= launch_data_alloc(LAUNCH_DATA_ARRAY
)))
205 launchd_close(_lc
->l
);
211 launch_data_t
launch_data_alloc(launch_data_type_t t
)
213 launch_data_t d
= calloc(1, sizeof(struct _launch
));
218 case LAUNCH_DATA_DICTIONARY
:
219 case LAUNCH_DATA_ARRAY
:
220 d
->_array
= malloc(0);
230 launch_data_type_t
launch_data_get_type(launch_data_t d
)
235 void launch_data_free(launch_data_t d
)
240 case LAUNCH_DATA_DICTIONARY
:
241 case LAUNCH_DATA_ARRAY
:
242 for (i
= 0; i
< d
->_array_cnt
; i
++)
243 launch_data_free(d
->_array
[i
]);
246 case LAUNCH_DATA_STRING
:
250 case LAUNCH_DATA_OPAQUE
:
260 size_t launch_data_dict_get_count(launch_data_t dict
)
262 return dict
->_array_cnt
/ 2;
266 bool launch_data_dict_insert(launch_data_t dict
, launch_data_t what
, const char *key
)
269 launch_data_t thekey
= launch_data_alloc(LAUNCH_DATA_STRING
);
271 launch_data_set_string(thekey
, key
);
273 for (i
= 0; i
< dict
->_array_cnt
; i
+= 2) {
274 if (!strcasecmp(key
, dict
->_array
[i
]->string
)) {
275 launch_data_array_set_index(dict
, thekey
, i
);
276 launch_data_array_set_index(dict
, what
, i
+ 1);
280 launch_data_array_set_index(dict
, thekey
, i
);
281 launch_data_array_set_index(dict
, what
, i
+ 1);
285 launch_data_t
launch_data_dict_lookup(launch_data_t dict
, const char *key
)
289 if (LAUNCH_DATA_DICTIONARY
!= dict
->type
)
292 for (i
= 0; i
< dict
->_array_cnt
; i
+= 2) {
293 if (!strcasecmp(key
, dict
->_array
[i
]->string
))
294 return dict
->_array
[i
+ 1];
300 bool launch_data_dict_remove(launch_data_t dict
, const char *key
)
304 for (i
= 0; i
< dict
->_array_cnt
; i
+= 2) {
305 if (!strcasecmp(key
, dict
->_array
[i
]->string
))
308 if (i
== dict
->_array_cnt
)
310 launch_data_free(dict
->_array
[i
]);
311 launch_data_free(dict
->_array
[i
+ 1]);
312 memmove(dict
->_array
+ i
, dict
->_array
+ i
+ 2, (dict
->_array_cnt
- (i
+ 2)) * sizeof(launch_data_t
));
313 dict
->_array_cnt
-= 2;
317 void launch_data_dict_iterate(launch_data_t dict
, void (*cb
)(launch_data_t
, const char *, void *), void *context
)
321 if (LAUNCH_DATA_DICTIONARY
!= dict
->type
)
324 for (i
= 0; i
< dict
->_array_cnt
; i
+= 2)
325 cb(dict
->_array
[i
+ 1], dict
->_array
[i
]->string
, context
);
328 bool launch_data_array_set_index(launch_data_t where
, launch_data_t what
, size_t ind
)
330 if ((ind
+ 1) >= where
->_array_cnt
) {
331 where
->_array
= realloc(where
->_array
, (ind
+ 1) * sizeof(launch_data_t
));
332 memset(where
->_array
+ where
->_array_cnt
, 0, (ind
+ 1 - where
->_array_cnt
) * sizeof(launch_data_t
));
333 where
->_array_cnt
= ind
+ 1;
336 if (where
->_array
[ind
])
337 launch_data_free(where
->_array
[ind
]);
338 where
->_array
[ind
] = what
;
342 launch_data_t
launch_data_array_get_index(launch_data_t where
, size_t ind
)
344 if (LAUNCH_DATA_ARRAY
!= where
->type
)
346 if (ind
< where
->_array_cnt
)
347 return where
->_array
[ind
];
351 launch_data_t
launch_data_array_pop_first(launch_data_t where
)
353 launch_data_t r
= NULL
;
355 if (where
->_array_cnt
> 0) {
356 r
= where
->_array
[0];
357 memmove(where
->_array
, where
->_array
+ 1, (where
->_array_cnt
- 1) * sizeof(launch_data_t
));
363 size_t launch_data_array_get_count(launch_data_t where
)
365 if (LAUNCH_DATA_ARRAY
!= where
->type
)
367 return where
->_array_cnt
;
370 bool launch_data_set_errno(launch_data_t d
, int e
)
376 bool launch_data_set_fd(launch_data_t d
, int fd
)
382 bool launch_data_set_integer(launch_data_t d
, long long n
)
388 bool launch_data_set_bool(launch_data_t d
, bool b
)
394 bool launch_data_set_real(launch_data_t d
, double n
)
400 bool launch_data_set_string(launch_data_t d
, const char *s
)
404 d
->string
= strdup(s
);
406 d
->string_len
= strlen(d
->string
);
412 bool launch_data_set_opaque(launch_data_t d
, const void *o
, size_t os
)
417 d
->opaque
= malloc(os
);
419 memcpy(d
->opaque
, o
, os
);
425 int launch_data_get_errno(launch_data_t d
)
430 int launch_data_get_fd(launch_data_t d
)
435 long long launch_data_get_integer(launch_data_t d
)
440 bool launch_data_get_bool(launch_data_t d
)
445 double launch_data_get_real(launch_data_t d
)
450 const char *launch_data_get_string(launch_data_t d
)
452 if (LAUNCH_DATA_STRING
!= d
->type
)
457 void *launch_data_get_opaque(launch_data_t d
)
459 if (LAUNCH_DATA_OPAQUE
!= d
->type
)
464 size_t launch_data_get_opaque_size(launch_data_t d
)
466 return d
->opaque_size
;
469 int launchd_getfd(launch_t l
)
474 launch_t
launchd_fdopen(int fd
)
478 c
= calloc(1, sizeof(struct _launch
));
484 fcntl(fd
, F_SETFL
, O_NONBLOCK
);
486 if ((c
->sendbuf
= malloc(0)) == NULL
)
488 if ((c
->sendfds
= malloc(0)) == NULL
)
490 if ((c
->recvbuf
= malloc(0)) == NULL
)
492 if ((c
->recvfds
= malloc(0)) == NULL
)
510 void launchd_close(launch_t lh
)
524 static void make_msg_and_cmsg(launch_data_t d
, void **where
, size_t *len
, int **fd_where
, size_t *fdcnt
)
526 launch_data_t o_in_w
;
529 *where
= realloc(*where
, *len
+ sizeof(struct _launch_data
));
531 o_in_w
= *where
+ *len
;
532 memset(o_in_w
, 0, sizeof(struct _launch_data
));
533 *len
+= sizeof(struct _launch_data
);
535 o_in_w
->type
= host2big(d
->type
);
538 case LAUNCH_DATA_INTEGER
:
539 o_in_w
->number
= host2big(d
->number
);
541 case LAUNCH_DATA_REAL
:
542 o_in_w
->float_num
= host2big(d
->float_num
);
544 case LAUNCH_DATA_BOOL
:
545 o_in_w
->boolean
= host2big(d
->boolean
);
547 case LAUNCH_DATA_ERRNO
:
548 o_in_w
->err
= host2big(d
->err
);
551 o_in_w
->fd
= host2big(d
->fd
);
553 *fd_where
= realloc(*fd_where
, (*fdcnt
+ 1) * sizeof(int));
554 (*fd_where
)[*fdcnt
] = d
->fd
;
558 case LAUNCH_DATA_STRING
:
559 o_in_w
->string_len
= host2big(d
->string_len
);
560 *where
= realloc(*where
, *len
+ strlen(d
->string
) + 1);
561 memcpy(*where
+ *len
, d
->string
, strlen(d
->string
) + 1);
562 *len
+= strlen(d
->string
) + 1;
564 case LAUNCH_DATA_OPAQUE
:
565 o_in_w
->opaque_size
= host2big(d
->opaque_size
);
566 *where
= realloc(*where
, *len
+ d
->opaque_size
);
567 memcpy(*where
+ *len
, d
->opaque
, d
->opaque_size
);
568 *len
+= d
->opaque_size
;
570 case LAUNCH_DATA_DICTIONARY
:
571 case LAUNCH_DATA_ARRAY
:
572 o_in_w
->_array_cnt
= host2big(d
->_array_cnt
);
573 *where
= realloc(*where
, *len
+ (d
->_array_cnt
* sizeof(launch_data_t
)));
574 memcpy(*where
+ *len
, d
->_array
, d
->_array_cnt
* sizeof(launch_data_t
));
575 *len
+= d
->_array_cnt
* sizeof(launch_data_t
);
577 for (i
= 0; i
< d
->_array_cnt
; i
++)
578 make_msg_and_cmsg(d
->_array
[i
], where
, len
, fd_where
, fdcnt
);
585 static launch_data_t
make_data(launch_t conn
, size_t *data_offset
, size_t *fdoffset
)
587 launch_data_t r
= conn
->recvbuf
+ *data_offset
;
590 if ((conn
->recvlen
- *data_offset
) < sizeof(struct _launch_data
))
592 *data_offset
+= sizeof(struct _launch_data
);
594 switch (big2host(r
->type
)) {
595 case LAUNCH_DATA_DICTIONARY
:
596 case LAUNCH_DATA_ARRAY
:
597 tmpcnt
= big2host(r
->_array_cnt
);
598 if ((conn
->recvlen
- *data_offset
) < (tmpcnt
* sizeof(launch_data_t
))) {
602 r
->_array
= conn
->recvbuf
+ *data_offset
;
603 *data_offset
+= tmpcnt
* sizeof(launch_data_t
);
604 for (i
= 0; i
< tmpcnt
; i
++) {
605 r
->_array
[i
] = make_data(conn
, data_offset
, fdoffset
);
606 if (r
->_array
[i
] == NULL
)
609 r
->_array_cnt
= tmpcnt
;
611 case LAUNCH_DATA_STRING
:
612 tmpcnt
= big2host(r
->string_len
);
613 if ((conn
->recvlen
- *data_offset
) < (tmpcnt
+ 1)) {
617 r
->string
= conn
->recvbuf
+ *data_offset
;
618 r
->string_len
= tmpcnt
;
619 *data_offset
+= tmpcnt
+ 1;
621 case LAUNCH_DATA_OPAQUE
:
622 tmpcnt
= big2host(r
->opaque_size
);
623 if ((conn
->recvlen
- *data_offset
) < tmpcnt
) {
627 r
->opaque
= conn
->recvbuf
+ *data_offset
;
628 r
->opaque_size
= tmpcnt
;
629 *data_offset
+= tmpcnt
;
633 r
->fd
= _fd(conn
->recvfds
[*fdoffset
]);
637 case LAUNCH_DATA_INTEGER
:
638 r
->number
= big2host(r
->number
);
640 case LAUNCH_DATA_REAL
:
641 r
->float_num
= big2host(r
->float_num
);
643 case LAUNCH_DATA_BOOL
:
644 r
->boolean
= big2host(r
->boolean
);
646 case LAUNCH_DATA_ERRNO
:
647 r
->err
= big2host(r
->err
);
655 r
->type
= big2host(r
->type
);
660 int launchd_msg_send(launch_t lh
, launch_data_t d
)
662 struct launch_msg_header lmh
;
663 struct cmsghdr
*cm
= NULL
;
666 size_t sentctrllen
= 0;
669 memset(&mh
, 0, sizeof(mh
));
672 uint64_t msglen
= lh
->sendlen
;
674 make_msg_and_cmsg(d
, &lh
->sendbuf
, &lh
->sendlen
, &lh
->sendfds
, &lh
->sendfdcnt
);
676 msglen
= (lh
->sendlen
- msglen
) + sizeof(struct launch_msg_header
);
677 lmh
.len
= host2big(msglen
);
678 lmh
.magic
= host2big(LAUNCH_MSG_HEADER_MAGIC
);
680 iov
[0].iov_base
= &lmh
;
681 iov
[0].iov_len
= sizeof(lmh
);
685 mh
.msg_iov
= iov
+ 1;
689 iov
[1].iov_base
= lh
->sendbuf
;
690 iov
[1].iov_len
= lh
->sendlen
;
693 if (lh
->sendfdcnt
> 0) {
694 sentctrllen
= mh
.msg_controllen
= CMSG_SPACE(lh
->sendfdcnt
* sizeof(int));
695 cm
= alloca(mh
.msg_controllen
);
698 memset(cm
, 0, mh
.msg_controllen
);
700 cm
->cmsg_len
= CMSG_LEN(lh
->sendfdcnt
* sizeof(int));
701 cm
->cmsg_level
= SOL_SOCKET
;
702 cm
->cmsg_type
= SCM_RIGHTS
;
704 memcpy(CMSG_DATA(cm
), lh
->sendfds
, lh
->sendfdcnt
* sizeof(int));
707 if ((r
= sendmsg(lh
->fd
, &mh
, 0)) == -1) {
712 } else if (sentctrllen
!= mh
.msg_controllen
) {
718 r
-= sizeof(struct launch_msg_header
);
722 if (lh
->sendlen
> 0) {
723 memmove(lh
->sendbuf
, lh
->sendbuf
+ r
, lh
->sendlen
);
726 lh
->sendbuf
= malloc(0);
731 lh
->sendfds
= malloc(0);
733 if (lh
->sendlen
> 0) {
742 int launch_get_fd(void)
744 pthread_once(&_lc_once
, launch_client_init
);
754 static void launch_msg_getmsgs(launch_data_t m
, void *context
)
756 launch_data_t async_resp
, *sync_resp
= context
;
758 if ((LAUNCH_DATA_DICTIONARY
== launch_data_get_type(m
)) && (async_resp
= launch_data_dict_lookup(m
, LAUNCHD_ASYNC_MSG_KEY
))) {
759 launch_data_array_set_index(_lc
->async_resp
, launch_data_copy(async_resp
), launch_data_array_get_count(_lc
->async_resp
));
761 *sync_resp
= launch_data_copy(m
);
765 launch_data_t
launch_msg(launch_data_t d
)
767 launch_data_t resp
= NULL
;
769 pthread_once(&_lc_once
, launch_client_init
);
776 pthread_mutex_lock(&_lc
->mtx
);
778 if (d
&& launchd_msg_send(_lc
->l
, d
) == -1) {
782 } while (launchd_msg_send(_lc
->l
, NULL
) == -1);
785 while (resp
== NULL
) {
786 if (d
== NULL
&& launch_data_array_get_count(_lc
->async_resp
) > 0) {
787 resp
= launch_data_array_pop_first(_lc
->async_resp
);
790 if (launchd_msg_recv(_lc
->l
, launch_msg_getmsgs
, &resp
) == -1) {
791 if (errno
!= EAGAIN
) {
793 } else if (d
== NULL
) {
800 FD_SET(_lc
->l
->fd
, &rfds
);
802 select(_lc
->l
->fd
+ 1, &rfds
, NULL
, NULL
, NULL
);
808 pthread_mutex_unlock(&_lc
->mtx
);
813 int launchd_msg_recv(launch_t lh
, void (*cb
)(launch_data_t
, void *), void *context
)
815 struct cmsghdr
*cm
= alloca(4096);
816 launch_data_t rmsg
= NULL
;
817 size_t data_offset
, fd_offset
;
822 memset(&mh
, 0, sizeof(mh
));
826 lh
->recvbuf
= realloc(lh
->recvbuf
, lh
->recvlen
+ 8*1024);
828 iov
.iov_base
= lh
->recvbuf
+ lh
->recvlen
;
829 iov
.iov_len
= 8*1024;
831 mh
.msg_controllen
= 4096;
833 if ((r
= recvmsg(lh
->fd
, &mh
, 0)) == -1)
839 if (mh
.msg_flags
& MSG_CTRUNC
) {
840 errno
= ECONNABORTED
;
844 if (mh
.msg_controllen
> 0) {
845 lh
->recvfds
= realloc(lh
->recvfds
, lh
->recvfdcnt
* sizeof(int) + mh
.msg_controllen
- sizeof(struct cmsghdr
));
846 memcpy(lh
->recvfds
+ lh
->recvfdcnt
, CMSG_DATA(cm
), mh
.msg_controllen
- sizeof(struct cmsghdr
));
847 lh
->recvfdcnt
+= (mh
.msg_controllen
- sizeof(struct cmsghdr
)) / sizeof(int);
852 while (lh
->recvlen
> 0) {
853 struct launch_msg_header
*lmhp
= lh
->recvbuf
;
855 data_offset
= sizeof(struct launch_msg_header
);
858 if (lh
->recvlen
< sizeof(struct launch_msg_header
))
861 tmplen
= big2host(lmhp
->len
);
863 if (big2host(lmhp
->magic
) != LAUNCH_MSG_HEADER_MAGIC
|| tmplen
<= sizeof(struct launch_msg_header
)) {
868 if (lh
->recvlen
< tmplen
) {
872 if ((rmsg
= make_data(lh
, &data_offset
, &fd_offset
)) == NULL
) {
879 lh
->recvlen
-= data_offset
;
880 if (lh
->recvlen
> 0) {
881 memmove(lh
->recvbuf
, lh
->recvbuf
+ data_offset
, lh
->recvlen
);
884 lh
->recvbuf
= malloc(0);
887 lh
->recvfdcnt
-= fd_offset
;
888 if (lh
->recvfdcnt
> 0) {
889 memmove(lh
->recvfds
, lh
->recvfds
+ fd_offset
, lh
->recvfdcnt
* sizeof(int));
892 lh
->recvfds
= malloc(0);
904 launch_data_t
launch_data_copy(launch_data_t o
)
906 launch_data_t r
= launch_data_alloc(o
->type
);
910 memcpy(r
, o
, sizeof(struct _launch_data
));
913 case LAUNCH_DATA_DICTIONARY
:
914 case LAUNCH_DATA_ARRAY
:
915 r
->_array
= calloc(1, o
->_array_cnt
* sizeof(launch_data_t
));
916 for (i
= 0; i
< o
->_array_cnt
; i
++) {
918 r
->_array
[i
] = launch_data_copy(o
->_array
[i
]);
921 case LAUNCH_DATA_STRING
:
922 r
->string
= strdup(o
->string
);
924 case LAUNCH_DATA_OPAQUE
:
925 r
->opaque
= malloc(o
->opaque_size
);
926 memcpy(r
->opaque
, o
->opaque
, o
->opaque_size
);
935 void launchd_batch_enable(bool val
)
937 launch_data_t resp
, tmp
, msg
;
939 tmp
= launch_data_alloc(LAUNCH_DATA_BOOL
);
940 launch_data_set_bool(tmp
, val
);
942 msg
= launch_data_alloc(LAUNCH_DATA_DICTIONARY
);
943 launch_data_dict_insert(msg
, tmp
, LAUNCH_KEY_BATCHCONTROL
);
945 resp
= launch_msg(msg
);
947 launch_data_free(msg
);
950 launch_data_free(resp
);
953 bool launchd_batch_query(void)
955 launch_data_t resp
, msg
= launch_data_alloc(LAUNCH_DATA_STRING
);
958 launch_data_set_string(msg
, LAUNCH_KEY_BATCHQUERY
);
960 resp
= launch_msg(msg
);
962 launch_data_free(msg
);
965 if (launch_data_get_type(resp
) == LAUNCH_DATA_BOOL
)
966 rval
= launch_data_get_bool(resp
);
967 launch_data_free(resp
);
972 static int _fd(int fd
)
975 fcntl(fd
, F_SETFD
, 1);
979 launch_data_t
launch_data_new_errno(int e
)
981 launch_data_t r
= launch_data_alloc(LAUNCH_DATA_ERRNO
);
984 launch_data_set_errno(r
, e
);
989 launch_data_t
launch_data_new_fd(int fd
)
991 launch_data_t r
= launch_data_alloc(LAUNCH_DATA_FD
);
994 launch_data_set_fd(r
, fd
);
999 launch_data_t
launch_data_new_integer(long long n
)
1001 launch_data_t r
= launch_data_alloc(LAUNCH_DATA_INTEGER
);
1004 launch_data_set_integer(r
, n
);
1009 launch_data_t
launch_data_new_bool(bool b
)
1011 launch_data_t r
= launch_data_alloc(LAUNCH_DATA_BOOL
);
1014 launch_data_set_bool(r
, b
);
1019 launch_data_t
launch_data_new_real(double d
)
1021 launch_data_t r
= launch_data_alloc(LAUNCH_DATA_REAL
);
1024 launch_data_set_real(r
, d
);
1029 launch_data_t
launch_data_new_string(const char *s
)
1031 launch_data_t r
= launch_data_alloc(LAUNCH_DATA_STRING
);
1036 if (!launch_data_set_string(r
, s
)) {
1037 launch_data_free(r
);
1044 launch_data_t
launch_data_new_opaque(const void *o
, size_t os
)
1046 launch_data_t r
= launch_data_alloc(LAUNCH_DATA_OPAQUE
);
1051 if (!launch_data_set_opaque(r
, o
, os
)) {
1052 launch_data_free(r
);