135c4bbdfSmrg/* Copyright (c) 2008-2012 Apple Inc. 24642e01fSmrg * 34642e01fSmrg * Permission is hereby granted, free of charge, to any person 44642e01fSmrg * obtaining a copy of this software and associated documentation files 54642e01fSmrg * (the "Software"), to deal in the Software without restriction, 64642e01fSmrg * including without limitation the rights to use, copy, modify, merge, 74642e01fSmrg * publish, distribute, sublicense, and/or sell copies of the Software, 84642e01fSmrg * and to permit persons to whom the Software is furnished to do so, 94642e01fSmrg * subject to the following conditions: 104642e01fSmrg * 114642e01fSmrg * The above copyright notice and this permission notice shall be 124642e01fSmrg * included in all copies or substantial portions of the Software. 134642e01fSmrg * 144642e01fSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 154642e01fSmrg * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 164642e01fSmrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 174642e01fSmrg * NONINFRINGEMENT. IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT 184642e01fSmrg * HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 194642e01fSmrg * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 204642e01fSmrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 214642e01fSmrg * DEALINGS IN THE SOFTWARE. 224642e01fSmrg * 234642e01fSmrg * Except as contained in this notice, the name(s) of the above 244642e01fSmrg * copyright holders shall not be used in advertising or otherwise to 254642e01fSmrg * promote the sale, use or other dealings in this Software without 264642e01fSmrg * prior written authorization. 274642e01fSmrg */ 284642e01fSmrg 294642e01fSmrg#include <CoreServices/CoreServices.h> 304642e01fSmrg 314642e01fSmrg#ifdef HAVE_DIX_CONFIG_H 324642e01fSmrg#include <dix-config.h> 334642e01fSmrg#endif 344642e01fSmrg 354642e01fSmrg#include <string.h> 364642e01fSmrg#include <unistd.h> 374642e01fSmrg#include <errno.h> 3835c4bbdfSmrg#include <asl.h> 394642e01fSmrg 404642e01fSmrg#include <sys/socket.h> 414642e01fSmrg#include <sys/un.h> 424642e01fSmrg 4335c4bbdfSmrg#define kX11AppBundleId BUNDLE_ID_PREFIX ".X11" 444642e01fSmrg#define kX11AppBundlePath "/Contents/MacOS/X11" 454642e01fSmrg 464642e01fSmrg#include <mach/mach.h> 474642e01fSmrg#include <mach/mach_error.h> 484642e01fSmrg#include <servers/bootstrap.h> 494642e01fSmrg#include "mach_startup.h" 504642e01fSmrg 514642e01fSmrg#include <signal.h> 524642e01fSmrg 534642e01fSmrg#include "launchd_fd.h" 544642e01fSmrg 55d36a1693Smrgstatic CFURLRef x11appURL; 56d36a1693Smrgstatic FSRef x11_appRef; 574642e01fSmrgstatic pid_t x11app_pid = 0; 5835c4bbdfSmrgaslclient aslc; 594642e01fSmrg 6035c4bbdfSmrgstatic void 6135c4bbdfSmrgset_x11_path(void) 6235c4bbdfSmrg{ 63d36a1693Smrg OSStatus osstatus = LSFindApplicationForInfo(kLSUnknownCreator, CFSTR(kX11AppBundleId), 64d36a1693Smrg nil, &x11_appRef, &x11appURL); 654642e01fSmrg 664642e01fSmrg switch (osstatus) { 6735c4bbdfSmrg case noErr: 68d36a1693Smrg if (x11appURL == NULL) { 6935c4bbdfSmrg asl_log(aslc, NULL, ASL_LEVEL_ERR, 70d36a1693Smrg "Xquartz: Invalid response from LSFindApplicationForInfo(%s)", 7135c4bbdfSmrg kX11AppBundleId); 72d36a1693Smrg exit(1); 7335c4bbdfSmrg } 7435c4bbdfSmrg break; 7535c4bbdfSmrg 7635c4bbdfSmrg case kLSApplicationNotFoundErr: 7735c4bbdfSmrg asl_log(aslc, NULL, ASL_LEVEL_ERR, 7835c4bbdfSmrg "Xquartz: Unable to find application for %s", 7935c4bbdfSmrg kX11AppBundleId); 8035c4bbdfSmrg exit(10); 8135c4bbdfSmrg 8235c4bbdfSmrg default: 8335c4bbdfSmrg asl_log(aslc, NULL, ASL_LEVEL_ERR, 8435c4bbdfSmrg "Xquartz: Unable to find application for %s, error code = %d", 85d36a1693Smrg kX11AppBundleId, (int)osstatus); 8635c4bbdfSmrg exit(11); 874642e01fSmrg } 884642e01fSmrg} 894642e01fSmrg 9035c4bbdfSmrgstatic int 9135c4bbdfSmrgconnect_to_socket(const char *filename) 9235c4bbdfSmrg{ 934642e01fSmrg struct sockaddr_un servaddr_un; 944642e01fSmrg struct sockaddr *servaddr; 954642e01fSmrg socklen_t servaddr_len; 964642e01fSmrg int ret_fd; 974642e01fSmrg 984642e01fSmrg /* Setup servaddr_un */ 9935c4bbdfSmrg memset(&servaddr_un, 0, sizeof(struct sockaddr_un)); 1004642e01fSmrg servaddr_un.sun_family = AF_UNIX; 1014642e01fSmrg strlcpy(servaddr_un.sun_path, filename, sizeof(servaddr_un.sun_path)); 10235c4bbdfSmrg 10335c4bbdfSmrg servaddr = (struct sockaddr *)&servaddr_un; 10435c4bbdfSmrg servaddr_len = sizeof(struct sockaddr_un) - 10535c4bbdfSmrg sizeof(servaddr_un.sun_path) + strlen(filename); 10635c4bbdfSmrg 1074642e01fSmrg ret_fd = socket(PF_UNIX, SOCK_STREAM, 0); 10835c4bbdfSmrg if (ret_fd == -1) { 10935c4bbdfSmrg asl_log(aslc, NULL, ASL_LEVEL_ERR, 110d36a1693Smrg "Xquartz: Failed to create socket: %s - %d - %s", 111d36a1693Smrg filename, errno, strerror(errno)); 1124642e01fSmrg return -1; 1134642e01fSmrg } 1144642e01fSmrg 11535c4bbdfSmrg if (connect(ret_fd, servaddr, servaddr_len) < 0) { 11635c4bbdfSmrg asl_log(aslc, NULL, ASL_LEVEL_ERR, 11735c4bbdfSmrg "Xquartz: Failed to connect to socket: %s - %d - %s", 118d36a1693Smrg filename, errno, strerror(errno)); 1194642e01fSmrg close(ret_fd); 1204642e01fSmrg return -1; 1214642e01fSmrg } 12235c4bbdfSmrg 1234642e01fSmrg return ret_fd; 1244642e01fSmrg} 1254642e01fSmrg 12635c4bbdfSmrgstatic void 12735c4bbdfSmrgsend_fd_handoff(int connected_fd, int launchd_fd) 12835c4bbdfSmrg{ 1294642e01fSmrg char databuf[] = "display"; 1304642e01fSmrg struct iovec iov[1]; 13135c4bbdfSmrg 1324642e01fSmrg union { 1334642e01fSmrg struct cmsghdr hdr; 1344642e01fSmrg char bytes[CMSG_SPACE(sizeof(int))]; 1354642e01fSmrg } buf; 13635c4bbdfSmrg 1374642e01fSmrg struct msghdr msg; 1386747b715Smrg struct cmsghdr *cmsg; 1396747b715Smrg 1406747b715Smrg iov[0].iov_base = databuf; 14135c4bbdfSmrg iov[0].iov_len = sizeof(databuf); 1426747b715Smrg 1434642e01fSmrg msg.msg_iov = iov; 1444642e01fSmrg msg.msg_iovlen = 1; 1454642e01fSmrg msg.msg_control = buf.bytes; 1464642e01fSmrg msg.msg_controllen = sizeof(buf); 1474642e01fSmrg msg.msg_name = 0; 1484642e01fSmrg msg.msg_namelen = 0; 1494642e01fSmrg msg.msg_flags = 0; 1504642e01fSmrg 15135c4bbdfSmrg cmsg = CMSG_FIRSTHDR(&msg); 1524642e01fSmrg cmsg->cmsg_level = SOL_SOCKET; 1534642e01fSmrg cmsg->cmsg_type = SCM_RIGHTS; 1544642e01fSmrg cmsg->cmsg_len = CMSG_LEN(sizeof(int)); 1554642e01fSmrg 1564642e01fSmrg msg.msg_controllen = cmsg->cmsg_len; 15735c4bbdfSmrg 15835c4bbdfSmrg *((int *)CMSG_DATA(cmsg)) = launchd_fd; 15935c4bbdfSmrg 16035c4bbdfSmrg if (sendmsg(connected_fd, &msg, 0) < 0) { 161d36a1693Smrg asl_log(aslc, NULL, ASL_LEVEL_ERR, 162d36a1693Smrg "Xquartz: Error sending $DISPLAY file descriptor over fd %d: %d -- %s", 163d36a1693Smrg connected_fd, errno, strerror(errno)); 1644642e01fSmrg return; 1654642e01fSmrg } 1664642e01fSmrg 16735c4bbdfSmrg asl_log(aslc, NULL, ASL_LEVEL_DEBUG, 16835c4bbdfSmrg "Xquartz: Message sent. Closing handoff fd."); 1694642e01fSmrg close(connected_fd); 1704642e01fSmrg} 1714642e01fSmrg 17235c4bbdfSmrg__attribute__((__noreturn__)) 17335c4bbdfSmrgstatic void 17435c4bbdfSmrgsignal_handler(int sig) 17535c4bbdfSmrg{ 17635c4bbdfSmrg if (x11app_pid) 1774642e01fSmrg kill(x11app_pid, sig); 1784642e01fSmrg _exit(0); 1794642e01fSmrg} 1804642e01fSmrg 18135c4bbdfSmrgint 18235c4bbdfSmrgmain(int argc, char **argv, char **envp) 18335c4bbdfSmrg{ 1844642e01fSmrg int envpc; 1854642e01fSmrg kern_return_t kr; 1864642e01fSmrg mach_port_t mp; 1874642e01fSmrg string_array_t newenvp; 1884642e01fSmrg string_array_t newargv; 1894642e01fSmrg size_t i; 1904642e01fSmrg int launchd_fd; 1914642e01fSmrg string_t handoff_socket_filename; 1924642e01fSmrg sig_t handler; 19335c4bbdfSmrg char *asl_sender; 19435c4bbdfSmrg char *asl_facility; 19535c4bbdfSmrg char *server_bootstrap_name = kX11AppBundleId; 1964642e01fSmrg 19735c4bbdfSmrg if (getenv("X11_PREFS_DOMAIN")) 1984642e01fSmrg server_bootstrap_name = getenv("X11_PREFS_DOMAIN"); 19935c4bbdfSmrg 20035c4bbdfSmrg asprintf(&asl_sender, "%s.stub", server_bootstrap_name); 20135c4bbdfSmrg assert(asl_sender); 20235c4bbdfSmrg 20335c4bbdfSmrg asl_facility = strdup(server_bootstrap_name); 20435c4bbdfSmrg assert(asl_facility); 20535c4bbdfSmrg if (strcmp(asl_facility + strlen(asl_facility) - 4, ".X11") == 0) 20635c4bbdfSmrg asl_facility[strlen(asl_facility) - 4] = '\0'; 20735c4bbdfSmrg 20835c4bbdfSmrg assert(aslc = asl_open(asl_sender, asl_facility, ASL_OPT_NO_DELAY)); 20935c4bbdfSmrg free(asl_sender); 21035c4bbdfSmrg free(asl_facility); 21135c4bbdfSmrg 2124642e01fSmrg /* We don't have a mechanism in place to handle this interrupt driven 2134642e01fSmrg * server-start notification, so just send the signal now, so xinit doesn't 2144642e01fSmrg * time out waiting for it and will just poll for the server. 2154642e01fSmrg */ 2164642e01fSmrg handler = signal(SIGUSR1, SIG_IGN); 21735c4bbdfSmrg if (handler == SIG_IGN) 2184642e01fSmrg kill(getppid(), SIGUSR1); 2194642e01fSmrg signal(SIGUSR1, handler); 2204642e01fSmrg 2214642e01fSmrg /* Pass on SIGs to X11.app */ 2224642e01fSmrg signal(SIGINT, signal_handler); 2234642e01fSmrg signal(SIGTERM, signal_handler); 22435c4bbdfSmrg 2254642e01fSmrg /* Get the $DISPLAY FD */ 2264642e01fSmrg launchd_fd = launchd_display_fd(); 2274642e01fSmrg 2284642e01fSmrg kr = bootstrap_look_up(bootstrap_port, server_bootstrap_name, &mp); 22935c4bbdfSmrg if (kr != KERN_SUCCESS) { 2306747b715Smrg pid_t child; 2316747b715Smrg 23235c4bbdfSmrg asl_log(aslc, NULL, ASL_LEVEL_WARNING, 23335c4bbdfSmrg "Xquartz: Unable to locate waiting server: %s", 23435c4bbdfSmrg server_bootstrap_name); 2354642e01fSmrg set_x11_path(); 2364642e01fSmrg 237d36a1693Smrg char *listenOnlyArg = "--listenonly"; 238d36a1693Smrg CFStringRef silentLaunchArg = CFStringCreateWithCString(NULL, listenOnlyArg, kCFStringEncodingUTF8); 239d36a1693Smrg CFStringRef args[] = { silentLaunchArg }; 240d36a1693Smrg CFArrayRef passArgv = CFArrayCreate(NULL, (const void**) args, 1, NULL); 241d36a1693Smrg LSApplicationParameters params = { 0, /* CFIndex version == 0 */ 242d36a1693Smrg kLSLaunchDefaults, /* LSLaunchFlags flags */ 243d36a1693Smrg &x11_appRef, /* FSRef application */ 244d36a1693Smrg NULL, /* void* asyncLaunchRefCon*/ 245d36a1693Smrg NULL, /* CFDictionaryRef environment */ 246d36a1693Smrg passArgv, /* CFArrayRef arguments */ 247d36a1693Smrg NULL /* AppleEvent* initialEvent */ 248d36a1693Smrg }; 249d36a1693Smrg 250d36a1693Smrg OSStatus status = LSOpenApplication(¶ms, NULL); 251d36a1693Smrg if (status != noErr) { 252d36a1693Smrg asl_log(aslc, NULL, ASL_LEVEL_ERR, "Xquartz: Unable to launch: %d", (int)status); 2534642e01fSmrg return EXIT_FAILURE; 2544642e01fSmrg } 2554642e01fSmrg 2564642e01fSmrg /* Try connecting for 10 seconds */ 25735c4bbdfSmrg for (i = 0; i < 80; i++) { 2584642e01fSmrg usleep(250000); 2594642e01fSmrg kr = bootstrap_look_up(bootstrap_port, server_bootstrap_name, &mp); 26035c4bbdfSmrg if (kr == KERN_SUCCESS) 2614642e01fSmrg break; 2624642e01fSmrg } 2634642e01fSmrg 26435c4bbdfSmrg if (kr != KERN_SUCCESS) { 26535c4bbdfSmrg asl_log(aslc, NULL, ASL_LEVEL_ERR, 266d36a1693Smrg "Xquartz: bootstrap_look_up(): %s", bootstrap_strerror(kr)); 2674642e01fSmrg return EXIT_FAILURE; 2684642e01fSmrg } 2694642e01fSmrg } 27035c4bbdfSmrg 2714642e01fSmrg /* Get X11.app's pid */ 2724642e01fSmrg request_pid(mp, &x11app_pid); 2734642e01fSmrg 2744642e01fSmrg /* Handoff the $DISPLAY FD */ 27535c4bbdfSmrg if (launchd_fd != -1) { 2764642e01fSmrg size_t try, try_max; 2774642e01fSmrg int handoff_fd = -1; 2784642e01fSmrg 27935c4bbdfSmrg for (try = 0, try_max = 5; try < try_max; try++) { 280d36a1693Smrg if (request_fd_handoff_socket(mp, handoff_socket_filename) != KERN_SUCCESS) { 281d36a1693Smrg asl_log(aslc, NULL, ASL_LEVEL_INFO, 282d36a1693Smrg "Xquartz: Failed to request a socket from the server to send the $DISPLAY fd over (try %d of %d)", 283d36a1693Smrg (int)try + 1, (int)try_max); 2844642e01fSmrg continue; 2854642e01fSmrg } 2864642e01fSmrg 2874642e01fSmrg handoff_fd = connect_to_socket(handoff_socket_filename); 28835c4bbdfSmrg if (handoff_fd == -1) { 28935c4bbdfSmrg asl_log(aslc, NULL, ASL_LEVEL_ERR, 29035c4bbdfSmrg "Xquartz: Failed to connect to socket (try %d of %d)", 291d36a1693Smrg (int)try + 1, (int)try_max); 2924642e01fSmrg continue; 2934642e01fSmrg } 2944642e01fSmrg 295d36a1693Smrg asl_log(aslc, NULL, ASL_LEVEL_INFO, 296d36a1693Smrg "Xquartz: Handoff connection established (try %d of %d) on fd %d, \"%s\". Sending message.", 297d36a1693Smrg (int)try + 1, (int)try_max, handoff_fd, handoff_socket_filename); 29835c4bbdfSmrg send_fd_handoff(handoff_fd, launchd_fd); 2994642e01fSmrg close(handoff_fd); 3004642e01fSmrg break; 3014642e01fSmrg } 3024642e01fSmrg } 3034642e01fSmrg 3044642e01fSmrg /* Count envp */ 30535c4bbdfSmrg for (envpc = 0; envp[envpc]; envpc++) ; 30635c4bbdfSmrg 3074642e01fSmrg /* We have fixed-size string lengths due to limitations in IPC, 3084642e01fSmrg * so we need to copy our argv and envp. 3094642e01fSmrg */ 31035c4bbdfSmrg newargv = (string_array_t)calloc((1 + argc), sizeof(string_t)); 31135c4bbdfSmrg newenvp = (string_array_t)calloc((1 + envpc), sizeof(string_t)); 3126747b715Smrg 31335c4bbdfSmrg if (!newargv || !newenvp) { 31435c4bbdfSmrg /* Silence the clang static analyzer */ 31535c4bbdfSmrg free(newargv); 31635c4bbdfSmrg free(newenvp); 31735c4bbdfSmrg 318d36a1693Smrg asl_log(aslc, NULL, ASL_LEVEL_ERR, "Xquartz: Memory allocation failure"); 3196747b715Smrg return EXIT_FAILURE; 3204642e01fSmrg } 32135c4bbdfSmrg 32235c4bbdfSmrg for (i = 0; i < argc; i++) { 3234642e01fSmrg strlcpy(newargv[i], argv[i], STRING_T_SIZE); 3244642e01fSmrg } 32535c4bbdfSmrg for (i = 0; i < envpc; i++) { 3264642e01fSmrg strlcpy(newenvp[i], envp[i], STRING_T_SIZE); 3274642e01fSmrg } 3284642e01fSmrg 3294642e01fSmrg kr = start_x11_server(mp, newargv, argc, newenvp, envpc); 3306747b715Smrg 3316747b715Smrg free(newargv); 3326747b715Smrg free(newenvp); 3336747b715Smrg 3344642e01fSmrg if (kr != KERN_SUCCESS) { 33535c4bbdfSmrg asl_log(aslc, NULL, ASL_LEVEL_ERR, "Xquartz: start_x11_server: %s", 336d36a1693Smrg mach_error_string(kr)); 3374642e01fSmrg return EXIT_FAILURE; 3384642e01fSmrg } 3394642e01fSmrg return EXIT_SUCCESS; 3404642e01fSmrg} 341