diff options
Diffstat (limited to 'hw/xquartz/mach-startup/bundle-main.c')
-rw-r--r-- | hw/xquartz/mach-startup/bundle-main.c | 157 |
1 files changed, 153 insertions, 4 deletions
diff --git a/hw/xquartz/mach-startup/bundle-main.c b/hw/xquartz/mach-startup/bundle-main.c index 042fa3ab8..24b67d871 100644 --- a/hw/xquartz/mach-startup/bundle-main.c +++ b/hw/xquartz/mach-startup/bundle-main.c @@ -33,9 +33,16 @@ #include <stdio.h> #include <string.h> #include <stdlib.h> +#include <pthread.h> #include <CoreFoundation/CoreFoundation.h> +#include <mach/mach.h> +#include <mach/mach_error.h> +#include <servers/bootstrap.h> +#include "mach_startup.h" +#include "mach_startupServer.h" + #define DEFAULT_CLIENT "/usr/X11/bin/xterm" #define DEFAULT_STARTX "/usr/X11/bin/startx" #define DEFAULT_SHELL "/bin/sh" @@ -43,12 +50,146 @@ static int execute(const char *command); static char *command_from_prefs(const char *key, const char *default_value); +/* This is in quartzStartup.c */ int server_main(int argc, char **argv, char **envp); +struct arg { + int argc; + char **argv; + char **envp; +}; + +/*** Mach-O IPC Stuffs ***/ + +union MaxMsgSize { + union __RequestUnion__mach_startup_subsystem req; + union __ReplyUnion__mach_startup_subsystem rep; +}; + +kern_return_t do_start_x11_server(mach_port_t port, string_array_t argv, + mach_msg_type_number_t argvCnt, + string_array_t envp, + mach_msg_type_number_t envpCnt) { + if(server_main(argvCnt, argv, envp) == 0) + return KERN_SUCCESS; + else + return KERN_FAILURE; +} + +kern_return_t do_exit(mach_port_t port, int value) { + exit(value); +} + +static mach_port_t checkin_or_register(char *bname) { + kern_return_t kr; + mach_port_t mp; + + /* If we're started by launchd or the old mach_init */ + kr = bootstrap_check_in(bootstrap_port, bname, &mp); + if (kr == KERN_SUCCESS) + return mp; + + /* We probably were not started by launchd or the old mach_init */ + kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &mp); + if (kr != KERN_SUCCESS) { + fprintf(stderr, "mach_port_allocate(): %s\n", mach_error_string(kr)); + exit(EXIT_FAILURE); + } + + kr = mach_port_insert_right(mach_task_self(), mp, mp, MACH_MSG_TYPE_MAKE_SEND); + if (kr != KERN_SUCCESS) { + fprintf(stderr, "mach_port_insert_right(): %s\n", mach_error_string(kr)); + exit(EXIT_FAILURE); + } + + kr = bootstrap_register(bootstrap_port, bname, mp); + if (kr != KERN_SUCCESS) { + fprintf(stderr, "bootstrap_register(): %s\n", mach_error_string(kr)); + exit(EXIT_FAILURE); + } + + return mp; +} + +/*** Pthread Magics ***/ +static pthread_t create_thread(void *func, void *arg) { + pthread_attr_t attr; + pthread_t tid; + + pthread_attr_init (&attr); + pthread_attr_setscope (&attr, PTHREAD_SCOPE_SYSTEM); + pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED); + pthread_create (&tid, &attr, func, arg); + pthread_attr_destroy (&attr); + + return tid; +} + +/*** Main ***/ +static int execute(const char *command); +static char *command_from_prefs(const char *key, const char *default_value); + +#ifdef NEW_LAUNCH_METHOD +static void startup_trigger_thread(void *arg) { + struct arg args = *((struct arg *)arg); + free(arg); + startup_trigger(args.argc, args.argv, args.envp); +} + int main(int argc, char **argv, char **envp) { + BOOL listenOnly = FALSE; + int i; + + for(i=1; i < argc; i++) { + if(!strcmp(argv[i], "--listenonly")) { + listenOnly = TRUE; + break; + } + } + + /* Check if we need to do something other than listen, and make another + * thread handle it. + */ + if(!listenOnly) { + struct arg *args = (struct arg*)malloc(sizeof(struct arg)); + if(!args) + FatalError("Could not allocate memory.\n"); + + args->argc = argc; + args->argv = argv; + args->envp = envp; + + create_thread(startup_trigger_thread, args); + } else { + /* TODO: This should actually fall through rather than be the else + * case once we figure out how to get the stub to pass the + * file descriptor. For now, we only listen if we are explicitly + * told to. + */ + + mach_msg_size_t mxmsgsz = sizeof(union MaxMsgSize) + MAX_TRAILER_SIZE; + mach_port_t mp = checkin_or_register(SERVER_BOOTSTRAP_NAME); + kern_return_t kr; + + /* Main event loop */ + kr = mach_msg_server(mach_startup_server, mxmsgsz, mp, 0); + if (kr != KERN_SUCCESS) { + asl_log(NULL, NULL, ASL_LEVEL_ERR, + "org.x.X11(mp): %s\n", mach_error_string(kr)); + exit(EXIT_FAILURE); + } + } + + return EXIT_SUCCESS; +} + +int startup_trigger(int argc, char **argv, char **envp) { +#else +int main(int argc, char **argv, char **envp) { +#endif Display *display; const char *s; - + size_t i; fprintf(stderr, "X11.app: main(): argc=%d\n", argc); for(i=0; i < argc; i++) { @@ -57,7 +198,15 @@ int main(int argc, char **argv, char **envp) { /* Take care of the case where we're called like a normal DDX */ if(argc > 1 && argv[1][0] == ':') { - exit(server_main(argc, argv, envp)); +#ifdef NEW_LAUNCH_METHOD + /* We need to count envp */ + int envpc; + for(envpc=0; envp[envpc]; envpc++); + + return start_x11_server(argc, argv, envp, envpc); +#else + return server_main(argc, argv, envp); +#endif } /* If we have a process serial number and it's our only arg, act as if @@ -70,7 +219,7 @@ int main(int argc, char **argv, char **envp) { fprintf(stderr, "X11.app: Closing the display and sleeping for 2s to allow the X server to start up.\n"); /* Could open the display, start the launcher */ XCloseDisplay(display); - + /* Give 2 seconds for the server to start... * TODO: *Really* fix this race condition */ @@ -78,7 +227,7 @@ int main(int argc, char **argv, char **envp) { return execute(command_from_prefs("app_to_run", DEFAULT_CLIENT)); } } - + /* Start the server */ if((s = getenv("DISPLAY"))) { fprintf(stderr, "X11.app: Could not connect to server (DISPLAY=\"%s\", unsetting). Starting X server.\n", s); |