/*
* Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * @APPLE_APACHE_LICENSE_HEADER_START@
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
*
- * @APPLE_LICENSE_HEADER_END@
+ * @APPLE_APACHE_LICENSE_HEADER_END@
*/
+
+#include "config.h"
+#include "launch.h"
+#include "launch_priv.h"
+#include "launch_internal.h"
+
+#include <mach/mach.h>
#include <libkern/OSByteOrder.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/fcntl.h>
#include <sys/un.h>
#include <sys/uio.h>
+#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#include <errno.h>
+#include <pwd.h>
+#include <assert.h>
-#include "launch.h"
-#include "launch_priv.h"
+#include "bootstrap.h"
+#include "vproc.h"
+#include "vproc_priv.h"
+#include "vproc_internal.h"
/* __OSBogusByteSwap__() must not really exist in the symbol namespace
* in order for the following to generate an error at build time.
#define LAUNCH_MSG_HEADER_MAGIC 0xD2FEA02366B39A41ull
struct _launch_data {
- int type;
+ uint64_t type;
union {
struct {
- launch_data_t *_array;
- size_t _array_cnt;
- };
- struct {
- char *string;
- size_t string_len;
- };
- struct {
- void *opaque;
- size_t opaque_size;
+ union {
+ launch_data_t *_array;
+ char *string;
+ void *opaque;
+ int64_t __junk;
+ };
+ union {
+ uint64_t _array_cnt;
+ uint64_t string_len;
+ uint64_t opaque_size;
+ };
};
int fd;
+ mach_port_t mp;
int err;
long long number;
- bool boolean;
+ 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 */
double float_num;
};
};
struct _launch {
void *sendbuf;
- int *sendfds;
+ int *sendfds;
void *recvbuf;
- int *recvfds;
- size_t sendlen;
- size_t sendfdcnt;
- size_t recvlen;
- size_t recvfdcnt;
- int fd;
+ int *recvfds;
+ size_t sendlen;
+ size_t sendfdcnt;
+ size_t recvlen;
+ size_t recvfdcnt;
+ int fd;
};
-static void make_msg_and_cmsg(launch_data_t, void **, size_t *, int **, size_t *);
-static launch_data_t make_data(launch_t, size_t *, size_t *);
+static launch_data_t launch_data_array_pop_first(launch_data_t where);
static int _fd(int fd);
+static void launch_client_init(void);
+static void launch_msg_getmsgs(launch_data_t m, void *context);
+static launch_data_t launch_msg_internal(launch_data_t d);
+static void launch_mach_checkin_service(launch_data_t obj, const char *key, void *context);
+static launch_t in_flight_msg_recv_client;
static pthread_once_t _lc_once = PTHREAD_ONCE_INIT;
static struct _launch_client {
launch_data_t async_resp;
} *_lc = NULL;
-static void launch_client_init(void)
+void
+launch_client_init(void)
{
struct sockaddr_un sun;
char *where = getenv(LAUNCHD_SOCKET_ENV);
char *_launchd_fd = getenv(LAUNCHD_TRUSTED_FD_ENV);
- int r, dfd, lfd = -1, tries;
+ int dfd, lfd = -1;
+ name_t spath;
_lc = calloc(1, sizeof(struct _launch_client));
memset(&sun, 0, sizeof(sun));
sun.sun_family = AF_UNIX;
- if (where)
+ if (where && where[0] != '\0') {
strncpy(sun.sun_path, where, sizeof(sun.sun_path));
- else
- snprintf(sun.sun_path, sizeof(sun.sun_path), "%s/%u/sock", LAUNCHD_SOCK_PREFIX, getuid());
+ } else if (!getenv("SUDO_COMMAND") && _vprocmgr_getsocket(spath) == 0) {
+ size_t min_len;
- if ((lfd = _fd(socket(AF_UNIX, SOCK_STREAM, 0))) == -1)
- goto out_bad;
+ min_len = sizeof(sun.sun_path) < sizeof(spath) ? sizeof(sun.sun_path) : sizeof(spath);
- for (tries = 0; tries < 10; tries++) {
- r = connect(lfd, (struct sockaddr *)&sun, sizeof(sun));
- if (r == -1) {
- if (getuid() != 0 && fork() == 0)
- execl("/sbin/launchd", "/sbin/launchd", NULL);
- sleep(1);
- } else {
- break;
- }
+ strncpy(sun.sun_path, spath, min_len);
+ } else {
+ strncpy(sun.sun_path, LAUNCHD_SOCK_PREFIX "/sock", sizeof(sun.sun_path));
}
- if (r == -1) {
- close(lfd);
+
+ if ((lfd = _fd(socket(AF_UNIX, SOCK_STREAM, 0))) == -1)
+ goto out_bad;
+ if (-1 == connect(lfd, (struct sockaddr *)&sun, sizeof(sun)))
goto out_bad;
- }
}
- if (!(_lc->l = launchd_fdopen(lfd))) {
- close(lfd);
+ if (!(_lc->l = launchd_fdopen(lfd)))
goto out_bad;
- }
if (!(_lc->async_resp = launch_data_alloc(LAUNCH_DATA_ARRAY)))
goto out_bad;
return;
out_bad:
if (_lc->l)
- launchd_close(_lc->l);
+ launchd_close(_lc->l, close);
+ else if (lfd != -1)
+ close(lfd);
if (_lc)
free(_lc);
_lc = NULL;
}
-launch_data_t launch_data_alloc(launch_data_type_t t)
+launch_data_t
+launch_data_alloc(launch_data_type_t t)
{
launch_data_t d = calloc(1, sizeof(struct _launch));
return d;
}
-launch_data_type_t launch_data_get_type(launch_data_t d)
+launch_data_type_t
+launch_data_get_type(launch_data_t d)
{
return d->type;
}
-void launch_data_free(launch_data_t d)
+void
+launch_data_free(launch_data_t d)
{
size_t i;
free(d);
}
-size_t launch_data_dict_get_count(launch_data_t dict)
+size_t
+launch_data_dict_get_count(launch_data_t dict)
{
return dict->_array_cnt / 2;
}
-bool launch_data_dict_insert(launch_data_t dict, launch_data_t what, const char *key)
+bool
+launch_data_dict_insert(launch_data_t dict, launch_data_t what, const char *key)
{
size_t i;
launch_data_t thekey = launch_data_alloc(LAUNCH_DATA_STRING);
return true;
}
-launch_data_t launch_data_dict_lookup(launch_data_t dict, const char *key)
+launch_data_t
+launch_data_dict_lookup(launch_data_t dict, const char *key)
{
size_t i;
return NULL;
}
-bool launch_data_dict_remove(launch_data_t dict, const char *key)
+bool
+launch_data_dict_remove(launch_data_t dict, const char *key)
{
size_t i;
return true;
}
-void launch_data_dict_iterate(launch_data_t dict, void (*cb)(launch_data_t, const char *, void *), void *context)
+void
+launch_data_dict_iterate(launch_data_t dict, void (*cb)(launch_data_t, const char *, void *), void *context)
{
size_t i;
cb(dict->_array[i + 1], dict->_array[i]->string, context);
}
-bool launch_data_array_set_index(launch_data_t where, launch_data_t what, size_t ind)
+bool
+launch_data_array_set_index(launch_data_t where, launch_data_t what, size_t ind)
{
if ((ind + 1) >= where->_array_cnt) {
- where->_array = realloc(where->_array, (ind + 1) * sizeof(launch_data_t));
+ where->_array = reallocf(where->_array, (ind + 1) * sizeof(launch_data_t));
memset(where->_array + where->_array_cnt, 0, (ind + 1 - where->_array_cnt) * sizeof(launch_data_t));
where->_array_cnt = ind + 1;
}
return true;
}
-launch_data_t launch_data_array_get_index(launch_data_t where, size_t ind)
+launch_data_t
+launch_data_array_get_index(launch_data_t where, size_t ind)
{
if (LAUNCH_DATA_ARRAY != where->type)
return NULL;
return NULL;
}
-launch_data_t launch_data_array_pop_first(launch_data_t where)
+launch_data_t
+launch_data_array_pop_first(launch_data_t where)
{
launch_data_t r = NULL;
-
+
if (where->_array_cnt > 0) {
r = where->_array[0];
memmove(where->_array, where->_array + 1, (where->_array_cnt - 1) * sizeof(launch_data_t));
return r;
}
-size_t launch_data_array_get_count(launch_data_t where)
+size_t
+launch_data_array_get_count(launch_data_t where)
{
if (LAUNCH_DATA_ARRAY != where->type)
return 0;
return where->_array_cnt;
}
-bool launch_data_set_errno(launch_data_t d, int e)
+bool
+launch_data_set_errno(launch_data_t d, int e)
{
d->err = e;
return true;
}
-bool launch_data_set_fd(launch_data_t d, int fd)
+bool
+launch_data_set_fd(launch_data_t d, int fd)
{
d->fd = fd;
return true;
}
-bool launch_data_set_integer(launch_data_t d, long long n)
+bool
+launch_data_set_machport(launch_data_t d, mach_port_t p)
+{
+ d->mp = p;
+ return true;
+}
+
+bool
+launch_data_set_integer(launch_data_t d, long long n)
{
d->number = n;
return true;
}
-bool launch_data_set_bool(launch_data_t d, bool b)
+bool
+launch_data_set_bool(launch_data_t d, bool b)
{
d->boolean = b;
return true;
}
-bool launch_data_set_real(launch_data_t d, double n)
+bool
+launch_data_set_real(launch_data_t d, double n)
{
d->float_num = n;
return true;
}
-bool launch_data_set_string(launch_data_t d, const char *s)
+bool
+launch_data_set_string(launch_data_t d, const char *s)
{
if (d->string)
free(d->string);
return false;
}
-bool launch_data_set_opaque(launch_data_t d, const void *o, size_t os)
+bool
+launch_data_set_opaque(launch_data_t d, const void *o, size_t os)
{
d->opaque_size = os;
if (d->opaque)
return false;
}
-int launch_data_get_errno(launch_data_t d)
+int
+launch_data_get_errno(launch_data_t d)
{
return d->err;
}
-int launch_data_get_fd(launch_data_t d)
+int
+launch_data_get_fd(launch_data_t d)
{
return d->fd;
}
-long long launch_data_get_integer(launch_data_t d)
+mach_port_t
+launch_data_get_machport(launch_data_t d)
+{
+ return d->mp;
+}
+
+long long
+launch_data_get_integer(launch_data_t d)
{
return d->number;
}
-bool launch_data_get_bool(launch_data_t d)
+bool
+launch_data_get_bool(launch_data_t d)
{
return d->boolean;
}
-double launch_data_get_real(launch_data_t d)
+double
+launch_data_get_real(launch_data_t d)
{
return d->float_num;
}
-const char *launch_data_get_string(launch_data_t d)
+const char *
+launch_data_get_string(launch_data_t d)
{
if (LAUNCH_DATA_STRING != d->type)
return NULL;
return d->string;
}
-void *launch_data_get_opaque(launch_data_t d)
+void *
+launch_data_get_opaque(launch_data_t d)
{
if (LAUNCH_DATA_OPAQUE != d->type)
return NULL;
return d->opaque;
}
-size_t launch_data_get_opaque_size(launch_data_t d)
+size_t
+launch_data_get_opaque_size(launch_data_t d)
{
return d->opaque_size;
}
-int launchd_getfd(launch_t l)
+int
+launchd_getfd(launch_t l)
{
return l->fd;
}
-launch_t launchd_fdopen(int fd)
+launch_t
+launchd_fdopen(int fd)
{
- launch_t c;
+ launch_t c;
- c = calloc(1, sizeof(struct _launch));
+ c = calloc(1, sizeof(struct _launch));
if (!c)
return NULL;
- c->fd = fd;
+ c->fd = fd;
fcntl(fd, F_SETFL, O_NONBLOCK);
- if ((c->sendbuf = malloc(0)) == NULL)
+ if ((c->sendbuf = malloc(0)) == NULL)
goto out_bad;
- if ((c->sendfds = malloc(0)) == NULL)
+ if ((c->sendfds = malloc(0)) == NULL)
goto out_bad;
- if ((c->recvbuf = malloc(0)) == NULL)
+ if ((c->recvbuf = malloc(0)) == NULL)
goto out_bad;
- if ((c->recvfds = malloc(0)) == NULL)
+ if ((c->recvfds = malloc(0)) == NULL)
goto out_bad;
return c;
return NULL;
}
-void launchd_close(launch_t lh)
+void
+launchd_close(launch_t lh, typeof(close) closefunc)
{
+ if (in_flight_msg_recv_client == lh) {
+ in_flight_msg_recv_client = NULL;
+ }
+
if (lh->sendbuf)
free(lh->sendbuf);
if (lh->sendfds)
free(lh->recvbuf);
if (lh->recvfds)
free(lh->recvfds);
- close(lh->fd);
+ closefunc(lh->fd);
free(lh);
}
-static void make_msg_and_cmsg(launch_data_t d, void **where, size_t *len, int **fd_where, size_t *fdcnt)
+#define ROUND_TO_64BIT_WORD_SIZE(x) ((x + 7) & ~7)
+
+size_t
+launch_data_pack(launch_data_t d, void *where, size_t len, int *fd_where, size_t *fd_cnt)
{
- launch_data_t o_in_w;
- size_t i;
+ launch_data_t o_in_w = where;
+ size_t i, rsz, total_data_len = sizeof(struct _launch_data);
- *where = realloc(*where, *len + sizeof(struct _launch_data));
+ if (total_data_len > len) {
+ return 0;
+ }
- o_in_w = *where + *len;
- memset(o_in_w, 0, sizeof(struct _launch_data));
- *len += sizeof(struct _launch_data);
+ where += total_data_len;
o_in_w->type = host2big(d->type);
break;
case LAUNCH_DATA_FD:
o_in_w->fd = host2big(d->fd);
- if (d->fd != -1) {
- *fd_where = realloc(*fd_where, (*fdcnt + 1) * sizeof(int));
- (*fd_where)[*fdcnt] = d->fd;
- (*fdcnt)++;
+ if (fd_where && d->fd != -1) {
+ fd_where[*fd_cnt] = d->fd;
+ (*fd_cnt)++;
}
break;
case LAUNCH_DATA_STRING:
o_in_w->string_len = host2big(d->string_len);
- *where = realloc(*where, *len + strlen(d->string) + 1);
- memcpy(*where + *len, d->string, strlen(d->string) + 1);
- *len += strlen(d->string) + 1;
+ total_data_len += ROUND_TO_64BIT_WORD_SIZE(strlen(d->string) + 1);
+ if (total_data_len > len) {
+ return 0;
+ }
+ memcpy(where, d->string, strlen(d->string) + 1);
break;
case LAUNCH_DATA_OPAQUE:
o_in_w->opaque_size = host2big(d->opaque_size);
- *where = realloc(*where, *len + d->opaque_size);
- memcpy(*where + *len, d->opaque, d->opaque_size);
- *len += d->opaque_size;
+ total_data_len += ROUND_TO_64BIT_WORD_SIZE(d->opaque_size);
+ if (total_data_len > len) {
+ return 0;
+ }
+ memcpy(where, d->opaque, d->opaque_size);
break;
case LAUNCH_DATA_DICTIONARY:
case LAUNCH_DATA_ARRAY:
o_in_w->_array_cnt = host2big(d->_array_cnt);
- *where = realloc(*where, *len + (d->_array_cnt * sizeof(launch_data_t)));
- memcpy(*where + *len, d->_array, d->_array_cnt * sizeof(launch_data_t));
- *len += d->_array_cnt * sizeof(launch_data_t);
+ total_data_len += d->_array_cnt * sizeof(uint64_t);
+ if (total_data_len > len) {
+ return 0;
+ }
- for (i = 0; i < d->_array_cnt; i++)
- make_msg_and_cmsg(d->_array[i], where, len, fd_where, fdcnt);
+ where += d->_array_cnt * sizeof(uint64_t);
+
+ for (i = 0; i < d->_array_cnt; i++) {
+ rsz = launch_data_pack(d->_array[i], where, len - total_data_len, fd_where, fd_cnt);
+ if (rsz == 0) {
+ return 0;
+ }
+ where += rsz;
+ total_data_len += rsz;
+ }
break;
default:
break;
}
+
+ return total_data_len;
}
-static launch_data_t make_data(launch_t conn, size_t *data_offset, size_t *fdoffset)
+launch_data_t
+launch_data_unpack(void *data, size_t data_size, int *fds, size_t fd_cnt, size_t *data_offset, size_t *fdoffset)
{
- launch_data_t r = conn->recvbuf + *data_offset;
+ launch_data_t r = data + *data_offset;
size_t i, tmpcnt;
- if ((conn->recvlen - *data_offset) < sizeof(struct _launch_data))
+ if ((data_size - *data_offset) < sizeof(struct _launch_data))
return NULL;
*data_offset += sizeof(struct _launch_data);
case LAUNCH_DATA_DICTIONARY:
case LAUNCH_DATA_ARRAY:
tmpcnt = big2host(r->_array_cnt);
- if ((conn->recvlen - *data_offset) < (tmpcnt * sizeof(launch_data_t))) {
+ if ((data_size - *data_offset) < (tmpcnt * sizeof(uint64_t))) {
errno = EAGAIN;
return NULL;
}
- r->_array = conn->recvbuf + *data_offset;
- *data_offset += tmpcnt * sizeof(launch_data_t);
+ r->_array = data + *data_offset;
+ *data_offset += tmpcnt * sizeof(uint64_t);
for (i = 0; i < tmpcnt; i++) {
- r->_array[i] = make_data(conn, data_offset, fdoffset);
+ r->_array[i] = launch_data_unpack(data, data_size, fds, fd_cnt, data_offset, fdoffset);
if (r->_array[i] == NULL)
return NULL;
}
break;
case LAUNCH_DATA_STRING:
tmpcnt = big2host(r->string_len);
- if ((conn->recvlen - *data_offset) < (tmpcnt + 1)) {
+ if ((data_size - *data_offset) < (tmpcnt + 1)) {
errno = EAGAIN;
return NULL;
}
- r->string = conn->recvbuf + *data_offset;
+ r->string = data + *data_offset;
r->string_len = tmpcnt;
- *data_offset += tmpcnt + 1;
+ *data_offset += ROUND_TO_64BIT_WORD_SIZE(tmpcnt + 1);
break;
case LAUNCH_DATA_OPAQUE:
tmpcnt = big2host(r->opaque_size);
- if ((conn->recvlen - *data_offset) < tmpcnt) {
+ if ((data_size - *data_offset) < tmpcnt) {
errno = EAGAIN;
return NULL;
}
- r->opaque = conn->recvbuf + *data_offset;
+ r->opaque = data + *data_offset;
r->opaque_size = tmpcnt;
- *data_offset += tmpcnt;
+ *data_offset += ROUND_TO_64BIT_WORD_SIZE(tmpcnt);
break;
case LAUNCH_DATA_FD:
- if (r->fd != -1) {
- r->fd = _fd(conn->recvfds[*fdoffset]);
+ if (r->fd != -1 && fd_cnt > *fdoffset) {
+ r->fd = _fd(fds[*fdoffset]);
*fdoffset += 1;
}
break;
break;
case LAUNCH_DATA_ERRNO:
r->err = big2host(r->err);
+ case LAUNCH_DATA_MACHPORT:
break;
default:
errno = EINVAL;
memset(&mh, 0, sizeof(mh));
+ /* confirm that the next hack works */
+ assert((d && lh->sendlen == 0) || (!d && lh->sendlen));
+
if (d) {
- uint64_t msglen = lh->sendlen;
+ size_t fd_slots_used = 0;
+ size_t good_enough_size = 10 * 1024 * 1024;
+ uint64_t msglen;
- make_msg_and_cmsg(d, &lh->sendbuf, &lh->sendlen, &lh->sendfds, &lh->sendfdcnt);
+ /* hack, see the above assert to verify "correctness" */
+ free(lh->sendbuf);
+ lh->sendbuf = malloc(good_enough_size);
+ free(lh->sendfds);
+ lh->sendfds = malloc(4 * 1024);
+
+ lh->sendlen = launch_data_pack(d, lh->sendbuf, good_enough_size, lh->sendfds, &fd_slots_used);
+
+ if (lh->sendlen == 0) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ lh->sendfdcnt = fd_slots_used;
- msglen = (lh->sendlen - msglen) + sizeof(struct launch_msg_header);
+ msglen = lh->sendlen + sizeof(struct launch_msg_header); /* type promotion to make the host2big() macro work right */
lmh.len = host2big(msglen);
lmh.magic = host2big(LAUNCH_MSG_HEADER_MAGIC);
iov[0].iov_base = &lmh;
iov[0].iov_len = sizeof(lmh);
mh.msg_iov = iov;
- mh.msg_iovlen = 2;
+ mh.msg_iovlen = 2;
} else {
mh.msg_iov = iov + 1;
- mh.msg_iovlen = 1;
+ mh.msg_iovlen = 1;
}
iov[1].iov_base = lh->sendbuf;
}
-int launch_get_fd(void)
+int
+launch_get_fd(void)
{
pthread_once(&_lc_once, launch_client_init);
return _lc->l->fd;
}
-static void launch_msg_getmsgs(launch_data_t m, void *context)
+void
+launch_msg_getmsgs(launch_data_t m, void *context)
{
launch_data_t async_resp, *sync_resp = context;
}
}
-launch_data_t launch_msg(launch_data_t d)
+void
+launch_mach_checkin_service(launch_data_t obj, const char *key, void *context __attribute__((unused)))
+{
+ kern_return_t result;
+ mach_port_t p;
+ name_t srvnm;
+
+ strlcpy(srvnm, key, sizeof(srvnm));
+
+ result = bootstrap_check_in(bootstrap_port, srvnm, &p);
+
+ if (result == BOOTSTRAP_SUCCESS)
+ launch_data_set_machport(obj, p);
+}
+
+launch_data_t
+launch_msg(launch_data_t d)
+{
+ launch_data_t mps, r = launch_msg_internal(d);
+
+ if (launch_data_get_type(d) == LAUNCH_DATA_STRING) {
+ if (strcmp(launch_data_get_string(d), LAUNCH_KEY_CHECKIN) != 0)
+ return r;
+ if (r == NULL)
+ return r;
+ if (launch_data_get_type(r) != LAUNCH_DATA_DICTIONARY)
+ return r;
+ mps = launch_data_dict_lookup(r, LAUNCH_JOBKEY_MACHSERVICES);
+ if (mps == NULL)
+ return r;
+ launch_data_dict_iterate(mps, launch_mach_checkin_service, NULL);
+ }
+
+ return r;
+}
+
+launch_data_t
+launch_msg_internal(launch_data_t d)
{
launch_data_t resp = NULL;
+ if (d && (launch_data_get_type(d) == LAUNCH_DATA_STRING)
+ && (strcmp(launch_data_get_string(d), LAUNCH_KEY_GETJOBS) == 0)
+ && vproc_swap_complex(NULL, VPROC_GSK_ALLJOBS, NULL, &resp) == NULL) {
+ return resp;
+ }
+
pthread_once(&_lc_once, launch_client_init);
if (!_lc) {
goto out;
} while (launchd_msg_send(_lc->l, NULL) == -1);
}
-
+
while (resp == NULL) {
if (d == NULL && launch_data_array_get_count(_lc->async_resp) > 0) {
resp = launch_data_array_pop_first(_lc->async_resp);
struct cmsghdr *cm = alloca(4096);
launch_data_t rmsg = NULL;
size_t data_offset, fd_offset;
- struct msghdr mh;
- struct iovec iov;
+ struct msghdr mh;
+ struct iovec iov;
int r;
- memset(&mh, 0, sizeof(mh));
- mh.msg_iov = &iov;
- mh.msg_iovlen = 1;
+ memset(&mh, 0, sizeof(mh));
+ mh.msg_iov = &iov;
+ mh.msg_iovlen = 1;
- lh->recvbuf = realloc(lh->recvbuf, lh->recvlen + 8*1024);
+ lh->recvbuf = reallocf(lh->recvbuf, lh->recvlen + 8*1024);
iov.iov_base = lh->recvbuf + lh->recvlen;
iov.iov_len = 8*1024;
}
lh->recvlen += r;
if (mh.msg_controllen > 0) {
- lh->recvfds = realloc(lh->recvfds, lh->recvfdcnt * sizeof(int) + mh.msg_controllen - sizeof(struct cmsghdr));
+ lh->recvfds = reallocf(lh->recvfds, lh->recvfdcnt * sizeof(int) + mh.msg_controllen - sizeof(struct cmsghdr));
memcpy(lh->recvfds + lh->recvfdcnt, CMSG_DATA(cm), mh.msg_controllen - sizeof(struct cmsghdr));
lh->recvfdcnt += (mh.msg_controllen - sizeof(struct cmsghdr)) / sizeof(int);
}
goto need_more_data;
}
- if ((rmsg = make_data(lh, &data_offset, &fd_offset)) == NULL) {
+ if ((rmsg = launch_data_unpack(lh->recvbuf, lh->recvlen, lh->recvfds, lh->recvfdcnt, &data_offset, &fd_offset)) == NULL) {
errno = EBADRPC;
goto out_bad;
}
+ in_flight_msg_recv_client = lh;
+
cb(rmsg, context);
+ /* launchd and only launchd can call launchd_close() as a part of the callback */
+ if (in_flight_msg_recv_client == NULL) {
+ r = 0;
+ break;
+ }
+
lh->recvlen -= data_offset;
if (lh->recvlen > 0) {
memmove(lh->recvbuf, lh->recvbuf + data_offset, lh->recvlen);
return r;
}
-void launchd_batch_enable(bool val)
+void
+launchd_batch_enable(bool b)
{
- launch_data_t resp, tmp, msg;
-
- tmp = launch_data_alloc(LAUNCH_DATA_BOOL);
- launch_data_set_bool(tmp, val);
+ int64_t val = b;
- msg = launch_data_alloc(LAUNCH_DATA_DICTIONARY);
- launch_data_dict_insert(msg, tmp, LAUNCH_KEY_BATCHCONTROL);
-
- resp = launch_msg(msg);
-
- launch_data_free(msg);
-
- if (resp)
- launch_data_free(resp);
+ vproc_swap_integer(NULL, VPROC_GSK_GLOBAL_ON_DEMAND, &val, NULL);
}
-bool launchd_batch_query(void)
+bool
+launchd_batch_query(void)
{
- launch_data_t resp, msg = launch_data_alloc(LAUNCH_DATA_STRING);
- bool rval = true;
-
- launch_data_set_string(msg, LAUNCH_KEY_BATCHQUERY);
-
- resp = launch_msg(msg);
-
- launch_data_free(msg);
+ int64_t val;
- if (resp) {
- if (launch_data_get_type(resp) == LAUNCH_DATA_BOOL)
- rval = launch_data_get_bool(resp);
- launch_data_free(resp);
+ if (vproc_swap_integer(NULL, VPROC_GSK_GLOBAL_ON_DEMAND, NULL, &val) == NULL) {
+ return (bool)val;
}
- return rval;
+
+ return false;
}
static int _fd(int fd)
launch_data_t r = launch_data_alloc(LAUNCH_DATA_ERRNO);
if (r)
- launch_data_set_errno(r, e);
+ launch_data_set_errno(r, e);
return r;
}
launch_data_t r = launch_data_alloc(LAUNCH_DATA_FD);
if (r)
- launch_data_set_fd(r, fd);
+ launch_data_set_fd(r, fd);
+
+ return r;
+}
+
+launch_data_t launch_data_new_machport(mach_port_t p)
+{
+ launch_data_t r = launch_data_alloc(LAUNCH_DATA_MACHPORT);
+
+ if (r)
+ launch_data_set_machport(r, p);
return r;
}
return r;
}
+
+void
+load_launchd_jobs_at_loginwindow_prompt(int flags __attribute__((unused)), ...)
+{
+ _vprocmgr_init("LoginWindow");
+}
+
+pid_t
+create_and_switch_to_per_session_launchd(const char *login __attribute__((unused)), int flags __attribute__((unused)), ...)
+{
+ mach_port_t bezel_ui_server;
+ struct stat sb;
+ uid_t target_user = geteuid() ? geteuid() : getuid();
+
+ if (_vprocmgr_move_subset_to_user(target_user, "Aqua")) {
+ return -1;
+ }
+
+#define BEZEL_UI_PATH "/System/Library/LoginPlugins/BezelServices.loginPlugin/Contents/Resources/BezelUI/BezelUIServer"
+#define BEZEL_UI_PLIST "/System/Library/LaunchAgents/com.apple.BezelUIServer.plist"
+#define BEZEL_UI_SERVICE "BezelUI"
+
+ if (!(stat(BEZEL_UI_PLIST, &sb) == 0 && S_ISREG(sb.st_mode))) {
+ if (bootstrap_create_server(bootstrap_port, BEZEL_UI_PATH, target_user, true, &bezel_ui_server) == BOOTSTRAP_SUCCESS) {
+ mach_port_t srv;
+
+ if (bootstrap_create_service(bezel_ui_server, BEZEL_UI_SERVICE, &srv) == BOOTSTRAP_SUCCESS) {
+ mach_port_deallocate(mach_task_self(), srv);
+ }
+
+ mach_port_deallocate(mach_task_self(), bezel_ui_server);
+ }
+ }
+
+ return 1;
+}