static int startup_trigger(int argc, char **argv, char **envp) { Display *display; const char *s; /* Take care of the case where we're called like a normal DDX */ if(argc > 1 && argv[1][0] == ':') { size_t i; kern_return_t kr; mach_port_t mp; string_array_t newenvp; string_array_t newargv; /* We need to count envp */ int envpc; for(envpc=0; envp[envpc]; envpc++); /* We have fixed-size string lengths due to limitations in IPC, * so we need to copy our argv and envp. */ newargv = (string_array_t)alloca(argc * sizeof(string_t)); newenvp = (string_array_t)alloca(envpc * sizeof(string_t)); if(!newargv || !newenvp) { fprintf(stderr, "Memory allocation failure\n"); exit(EXIT_FAILURE); } for(i=0; i < argc; i++) { strlcpy(newargv[i], argv[i], STRING_T_SIZE); } for(i=0; i < envpc; i++) { strlcpy(newenvp[i], envp[i], STRING_T_SIZE); } kr = bootstrap_look_up(bootstrap_port, server_bootstrap_name, &mp); if (kr != KERN_SUCCESS) { #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050 fprintf(stderr, "bootstrap_look_up(%s): %s\n", server_bootstrap_name, bootstrap_strerror(kr)); #else fprintf(stderr, "bootstrap_look_up(%s): %ul\n", server_bootstrap_name, (unsigned long)kr); #endif exit(EXIT_FAILURE); } kr = start_x11_server(mp, newargv, argc, newenvp, envpc); if (kr != KERN_SUCCESS) { fprintf(stderr, "start_x11_server: %s\n", mach_error_string(kr)); exit(EXIT_FAILURE); } exit(EXIT_SUCCESS); } /* If we have a process serial number and it's our only arg, act as if * the user double clicked the app bundle: launch app_to_run if possible */ if(argc == 1 || (argc == 2 && !strncmp(argv[1], "-psn_", 5))) { /* Now, try to open a display, if so, run the launcher */ display = XOpenDisplay(NULL); if(display) { /* Could open the display, start the launcher */ XCloseDisplay(display); 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); unsetenv("DISPLAY"); } else { fprintf(stderr, "X11.app: Could not connect to server (DISPLAY is not set). Starting X server.\n"); } return execute(command_from_prefs("startx_script", DEFAULT_STARTX)); }
int main(int argc, char **argv, char **envp) { int envpc; kern_return_t kr; mach_port_t mp; string_array_t newenvp; string_array_t newargv; size_t i; int launchd_fd; string_t handoff_socket_filename; sig_t handler; if(argc == 2 && !strcmp(argv[1], "-version")) { fprintf(stderr, "X.org Release 7.5\n"); fprintf(stderr, "X.Org X Server %s\n", XSERVER_VERSION); fprintf(stderr, "Build Date: %s\n", BUILD_DATE); return EXIT_SUCCESS; } if(getenv("X11_PREFS_DOMAIN")) server_bootstrap_name = getenv("X11_PREFS_DOMAIN"); /* We don't have a mechanism in place to handle this interrupt driven * server-start notification, so just send the signal now, so xinit doesn't * time out waiting for it and will just poll for the server. */ handler = signal(SIGUSR1, SIG_IGN); if(handler == SIG_IGN) kill(getppid(), SIGUSR1); signal(SIGUSR1, handler); /* Pass on SIGs to X11.app */ signal(SIGINT, signal_handler); signal(SIGTERM, signal_handler); /* Get the $DISPLAY FD */ launchd_fd = launchd_display_fd(); kr = bootstrap_look_up(bootstrap_port, server_bootstrap_name, &mp); if(kr != KERN_SUCCESS) { pid_t child; fprintf(stderr, "Xquartz: Unable to locate waiting server: %s\n", server_bootstrap_name); set_x11_path(); /* This forking is ugly and will be cleaned up later */ child = fork(); if(child == -1) { fprintf(stderr, "Xquartz: Could not fork: %s\n", strerror(errno)); return EXIT_FAILURE; } if(child == 0) { char *_argv[3]; _argv[0] = x11_path; _argv[1] = "--listenonly"; _argv[2] = NULL; fprintf(stderr, "Xquartz: Starting X server: %s --listenonly\n", x11_path); return execvp(x11_path, _argv); } /* Try connecting for 10 seconds */ for(i=0; i < 80; i++) { usleep(250000); kr = bootstrap_look_up(bootstrap_port, server_bootstrap_name, &mp); if(kr == KERN_SUCCESS) break; } if(kr != KERN_SUCCESS) { #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050 fprintf(stderr, "Xquartz: bootstrap_look_up(): %s\n", bootstrap_strerror(kr)); #else fprintf(stderr, "Xquartz: bootstrap_look_up(): %ul\n", (unsigned long)kr); #endif return EXIT_FAILURE; } } /* Get X11.app's pid */ request_pid(mp, &x11app_pid); /* Handoff the $DISPLAY FD */ if(launchd_fd != -1) { size_t try, try_max; int handoff_fd = -1; for(try=0, try_max=5; try < try_max; try++) { if(request_fd_handoff_socket(mp, handoff_socket_filename) != KERN_SUCCESS) { fprintf(stderr, "Xquartz: Failed to request a socket from the server to send the $DISPLAY fd over (try %d of %d)\n", (int)try+1, (int)try_max); continue; } handoff_fd = connect_to_socket(handoff_socket_filename); if(handoff_fd == -1) { fprintf(stderr, "Xquartz: Failed to connect to socket (try %d of %d)\n", (int)try+1, (int)try_max); continue; } #ifdef DEBUG fprintf(stderr, "Xquartz: Handoff connection established (try %d of %d) on fd %d, \"%s\". Sending message.\n", (int)try+1, (int)try_max, handoff_fd, handoff_socket_filename); #endif send_fd_handoff(handoff_fd, launchd_fd); close(handoff_fd); break; } } /* Count envp */ for(envpc=0; envp[envpc]; envpc++); /* We have fixed-size string lengths due to limitations in IPC, * so we need to copy our argv and envp. */ newargv = (string_array_t)malloc(argc * sizeof(string_t)); newenvp = (string_array_t)malloc(envpc * sizeof(string_t)); if(!newargv || !newenvp) { fprintf(stderr, "Xquartz: Memory allocation failure\n"); return EXIT_FAILURE; } for(i=0; i < argc; i++) { strlcpy(newargv[i], argv[i], STRING_T_SIZE); } for(i=0; i < envpc; i++) { strlcpy(newenvp[i], envp[i], STRING_T_SIZE); } kr = start_x11_server(mp, newargv, argc, newenvp, envpc); free(newargv); free(newenvp); if (kr != KERN_SUCCESS) { fprintf(stderr, "Xquartz: start_x11_server: %s\n", mach_error_string(kr)); return EXIT_FAILURE; } return EXIT_SUCCESS; }