diff --git a/.gitignore b/.gitignore index d6d7adfd1..13d5de4fd 100644 --- a/.gitignore +++ b/.gitignore @@ -278,6 +278,10 @@ hw/xprint/doc/Xprt.1x hw/xprint/doc/Xprt.man hw/xprint/dpmsstubs-wrapper.c hw/xprint/miinitext-wrapper.c +hw/xquartz/mach-startup/mach_startup.h +hw/xquartz/mach-startup/mach_startupServer.c +hw/xquartz/mach-startup/mach_startupServer.h +hw/xquartz/mach-startup/mach_startupUser.c hw/xquartz/mach-startup/X11 hw/xquartz/mach-startup/Xquartz hw/xquartz/doc/Xquartz.1 diff --git a/hw/xquartz/mach-startup/Makefile.am b/hw/xquartz/mach-startup/Makefile.am index 966871126..ee2cbfe9e 100644 --- a/hw/xquartz/mach-startup/Makefile.am +++ b/hw/xquartz/mach-startup/Makefile.am @@ -5,9 +5,13 @@ AM_CPPFLAGS = \ x11appdir = $(APPLE_APPLICATIONS_DIR)/X11.app/Contents/MacOS x11app_PROGRAMS = X11 -X11_SOURCES = \ +dist_X11_SOURCES = \ bundle-main.c +nodist_X11_SOURCES = \ + mach_startupServer.c \ + mach_startupUser.c + X11_LDADD = \ $(top_builddir)/hw/xquartz/libXquartz.la \ $(top_builddir)/hw/xquartz/xpr/libXquartzXpr.la \ @@ -27,8 +31,28 @@ X11_LDFLAGS = \ bin_PROGRAMS = Xquartz -Xquartz_SOURCES = \ +dist_Xquartz_SOURCES = \ stub.c +nodist_Xquartz_SOURCES = \ + mach_startupUser.c + Xquartz_LDFLAGS = \ -Wl,-framework,CoreServices + +BUILT_SOURCES = \ + mach_startupServer.c \ + mach_startupUser.c \ + mach_startupServer.h \ + mach_startup.h + +CLEANFILES = \ + $(BUILT_SOURCES) + +$(BUILT_SOURCES): mach_startup.defs + mig -sheader mach_startupServer.h mach_startup.defs + +EXTRA_DIST = \ + mach_startup.defs \ + mach_startup_types.h + 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 #include #include +#include #include +#include +#include +#include +#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); diff --git a/hw/xquartz/mach-startup/mach_startup.defs b/hw/xquartz/mach-startup/mach_startup.defs new file mode 100644 index 000000000..83b31b7c0 --- /dev/null +++ b/hw/xquartz/mach-startup/mach_startup.defs @@ -0,0 +1,41 @@ +/* Copyright (c) 2008 Apple Inc. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT + * HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name(s) of the above + * copyright holders shall not be used in advertising or otherwise to + * promote the sale, use or other dealings in this Software without + * prior written authorization. + */ + +#include +#include +import "mach_startup_types.h"; + +subsystem mach_startup 1000; +serverprefix do_; + +type string_array_t = array[] of c_string[1024]; + +routine start_x11_server( + port : mach_port_t; + argv : string_array_t; + envp : string_array_t); diff --git a/hw/xquartz/mach-startup/mach_startup_types.h b/hw/xquartz/mach-startup/mach_startup_types.h new file mode 100644 index 000000000..03939af97 --- /dev/null +++ b/hw/xquartz/mach-startup/mach_startup_types.h @@ -0,0 +1,8 @@ +#ifndef _MACH_STARTUP_TYPES_H_ +#define _MACH_STARTUP_TYPES_H_ + +#define SERVER_BOOTSTRAP_NAME "org.x.X11" + +typedef char ** string_array_t; + +#endif