194 lines
6.2 KiB
Plaintext
194 lines
6.2 KiB
Plaintext
//
|
|
// main.m
|
|
// Used in both LauncherXPCService and LaunchRootXPCService targets
|
|
//
|
|
// Copyright (c) 2012 Apple Inc. All rights reserved.
|
|
//
|
|
#include <AvailabilityMacros.h>
|
|
|
|
#if !defined(MAC_OS_X_VERSION_10_7) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
|
|
#define BUILDING_ON_SNOW_LEOPARD 1
|
|
#endif
|
|
|
|
#if !BUILDING_ON_SNOW_LEOPARD
|
|
#define __XPC_PRIVATE_H__
|
|
#include <xpc/xpc.h>
|
|
#include <spawn.h>
|
|
#include <signal.h>
|
|
#include <assert.h>
|
|
#include "LauncherXPCService.h"
|
|
|
|
// Declaration. Returns 0 if successful.
|
|
int _validate_authorization(xpc_object_t message);
|
|
|
|
// Returns 0 if successful.
|
|
int _setup_posixspawn_attributes_file_actions(xpc_object_t message, posix_spawnattr_t *attr, posix_spawn_file_actions_t *file_actions)
|
|
{
|
|
*attr = 0;
|
|
|
|
int errorCode = posix_spawnattr_init(attr);
|
|
if (errorCode)
|
|
return errorCode;
|
|
|
|
cpu_type_t cpuType = (cpu_type_t)xpc_dictionary_get_int64(message, LauncherXPCServiceCPUTypeKey);
|
|
if (cpuType == -2) {
|
|
cpuType= CPU_TYPE_ANY;
|
|
}
|
|
size_t realCount;
|
|
errorCode = posix_spawnattr_setbinpref_np(attr, 1, &cpuType, &realCount);
|
|
if (errorCode)
|
|
return errorCode;
|
|
|
|
sigset_t no_signals;
|
|
sigset_t all_signals;
|
|
sigemptyset (&no_signals);
|
|
sigfillset (&all_signals);
|
|
posix_spawnattr_setsigmask(attr, &no_signals);
|
|
posix_spawnattr_setsigdefault(attr, &all_signals);
|
|
|
|
short flags = xpc_dictionary_get_int64(message, LauncherXPCServicePosixspawnFlagsKey);
|
|
errorCode = posix_spawnattr_setflags(attr, flags);
|
|
if (errorCode)
|
|
return errorCode;
|
|
|
|
// Setup any file actions. Here we are emulating what debugserver would do normally in Host.mm since the XPC service meant only for debugserver.
|
|
errorCode = posix_spawn_file_actions_init(file_actions);
|
|
if (errorCode)
|
|
return errorCode;
|
|
errorCode = posix_spawn_file_actions_addclose(file_actions, STDIN_FILENO);
|
|
if (errorCode)
|
|
return errorCode;
|
|
errorCode = posix_spawn_file_actions_addclose(file_actions, STDOUT_FILENO);
|
|
if (errorCode)
|
|
return errorCode;
|
|
errorCode = posix_spawn_file_actions_addclose(file_actions, STDERR_FILENO);
|
|
|
|
return errorCode;
|
|
}
|
|
|
|
bool extract_args(xpc_object_t message, const char *prefix, const char ***argsOut)
|
|
{
|
|
char buf[50]; // long enough for 'argXXX'
|
|
memset(buf, 0, 50);
|
|
sprintf(buf, "%sCount", prefix);
|
|
int argsCount = (int)xpc_dictionary_get_int64(message, buf);
|
|
if (argsCount == 0) {
|
|
return true;
|
|
}
|
|
|
|
const char **argsp = NULL;
|
|
argsp = (const char **)malloc((argsCount+1) * sizeof(argsp[0]));
|
|
if (argsp == NULL) {
|
|
return false;
|
|
}
|
|
|
|
for (int i=0; i<argsCount; i++) {
|
|
memset(buf, 0, 50);
|
|
sprintf(buf, "%s%i", prefix, i);
|
|
const char *arg = xpc_dictionary_get_string(message, buf);
|
|
argsp[i] = arg;
|
|
}
|
|
argsp[argsCount] = NULL;
|
|
|
|
*argsOut = argsp;
|
|
return true;
|
|
}
|
|
|
|
// Returns 0 if successful.
|
|
int get_args(xpc_object_t message, const char **path, const char ***argsOut, const char ***envOut)
|
|
{
|
|
if (!extract_args(message, LauncherXPCServiceArgPrefxKey, argsOut)) {
|
|
return 1;
|
|
}
|
|
*path = (*argsOut)[0];
|
|
|
|
if (!extract_args(message, LauncherXPCServiceEnvPrefxKey, envOut)) {
|
|
return 2;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void launcherXPC_peer_event_handler(xpc_connection_t peer, xpc_object_t event)
|
|
{
|
|
xpc_type_t type = xpc_get_type(event);
|
|
if (type == XPC_TYPE_ERROR) {
|
|
if (event == XPC_ERROR_CONNECTION_INVALID) {
|
|
// The client process on the other end of the connection has either
|
|
// crashed or cancelled the connection. After receiving this error,
|
|
// the connection is in an invalid state, and you do not need to
|
|
// call xpc_connection_cancel(). Just tear down any associated state
|
|
// here.
|
|
} else if (event == XPC_ERROR_TERMINATION_IMMINENT) {
|
|
// Handle per-connection termination cleanup.
|
|
}
|
|
} else {
|
|
assert(type == XPC_TYPE_DICTIONARY);
|
|
// Handle the message.
|
|
|
|
pid_t childPID = 0;
|
|
posix_spawn_file_actions_t file_actions;
|
|
posix_spawnattr_t attributes;
|
|
|
|
/*
|
|
Types of error. Error code will be specific to each type.
|
|
100 - authorization failure
|
|
101 - posixspawn attributes problem
|
|
102 - get args/env problem
|
|
103 - posixspawn problem
|
|
*/
|
|
int errorType = 100;
|
|
int errorCode = _validate_authorization(event);
|
|
if (!errorCode) {
|
|
errorType = 101;
|
|
errorCode = _setup_posixspawn_attributes_file_actions(event, &attributes, &file_actions);
|
|
if (!errorCode) {
|
|
const char *path = NULL;
|
|
const char **argvp = NULL;
|
|
const char **envp = NULL;
|
|
errorType = 102;
|
|
errorCode = get_args(event, &path, &argvp, &envp);
|
|
if (!errorCode) {
|
|
errorType = 103;
|
|
errorCode = posix_spawn(&childPID, path, &file_actions, &attributes, (char * const *)argvp, (char * const *)envp);
|
|
|
|
if (argvp) free(argvp);
|
|
if (envp) free(envp);
|
|
}
|
|
}
|
|
}
|
|
|
|
xpc_object_t reply = xpc_dictionary_create_reply(event);
|
|
|
|
xpc_dictionary_set_int64(reply, LauncherXPCServiceChildPIDKey, childPID);
|
|
if (!childPID) {
|
|
xpc_dictionary_set_int64(reply, LauncherXPCServiceErrorTypeKey, errorType);
|
|
xpc_dictionary_set_int64(reply, LauncherXPCServiceCodeTypeKey, errorCode);
|
|
}
|
|
|
|
xpc_connection_send_message(peer, reply);
|
|
xpc_release(reply);
|
|
}
|
|
}
|
|
|
|
static void launcherXPC_event_handler(xpc_connection_t peer)
|
|
{
|
|
// By defaults, new connections will target the default dispatch
|
|
// concurrent queue.
|
|
xpc_connection_set_event_handler(peer, ^(xpc_object_t event) {
|
|
launcherXPC_peer_event_handler(peer, event);
|
|
});
|
|
|
|
// This will tell the connection to begin listening for events. If you
|
|
// have some other initialization that must be done asynchronously, then
|
|
// you can defer this call until after that initialization is done.
|
|
xpc_connection_resume(peer);
|
|
}
|
|
|
|
int main(int argc, const char *argv[])
|
|
{
|
|
xpc_main(launcherXPC_event_handler);
|
|
return 0;
|
|
}
|
|
#endif
|