14642e01fSmrg/* main.c -- X application launcher 235c4bbdfSmrg * Copyright (c) 2007 Jeremy Huddleston 335c4bbdfSmrg * Copyright (c) 2007-2012 Apple Inc. All rights reserved. 435c4bbdfSmrg * 535c4bbdfSmrg * Permission is hereby granted, free of charge, to any person 635c4bbdfSmrg * obtaining a copy of this software and associated documentation files 735c4bbdfSmrg * (the "Software"), to deal in the Software without restriction, 835c4bbdfSmrg * including without limitation the rights to use, copy, modify, merge, 935c4bbdfSmrg * publish, distribute, sublicense, and/or sell copies of the Software, 1035c4bbdfSmrg * and to permit persons to whom the Software is furnished to do so, 1135c4bbdfSmrg * subject to the following conditions: 1235c4bbdfSmrg * 1335c4bbdfSmrg * The above copyright notice and this permission notice shall be 1435c4bbdfSmrg * included in all copies or substantial portions of the Software. 1535c4bbdfSmrg * 1635c4bbdfSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 1735c4bbdfSmrg * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 1835c4bbdfSmrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 1935c4bbdfSmrg * NONINFRINGEMENT. IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT 2035c4bbdfSmrg * HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 2135c4bbdfSmrg * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 2235c4bbdfSmrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 2335c4bbdfSmrg * DEALINGS IN THE SOFTWARE. 2435c4bbdfSmrg * 2535c4bbdfSmrg * Except as contained in this notice, the name(s) of the above 2635c4bbdfSmrg * copyright holders shall not be used in advertising or otherwise to 2735c4bbdfSmrg * promote the sale, use or other dealings in this Software without 2835c4bbdfSmrg * prior written authorization. 2935c4bbdfSmrg */ 304642e01fSmrg 314642e01fSmrg#include <CoreFoundation/CoreFoundation.h> 324642e01fSmrg 336747b715Smrg#ifdef HAVE_DIX_CONFIG_H 346747b715Smrg#include <dix-config.h> 356747b715Smrg#endif 366747b715Smrg 374642e01fSmrg#include <X11/Xlib.h> 389ace9065Smrg#include <assert.h> 394642e01fSmrg#include <unistd.h> 404642e01fSmrg#include <stdio.h> 414642e01fSmrg#include <string.h> 424642e01fSmrg#include <stdlib.h> 434642e01fSmrg#include <stdbool.h> 444642e01fSmrg#include <signal.h> 454642e01fSmrg 4635c4bbdfSmrg#include <dispatch/dispatch.h> 4735c4bbdfSmrg 484642e01fSmrg#include <sys/socket.h> 494642e01fSmrg#include <sys/un.h> 504642e01fSmrg 516747b715Smrg#include <fcntl.h> 524642e01fSmrg 534642e01fSmrg#include <mach/mach.h> 544642e01fSmrg#include <mach/mach_error.h> 554642e01fSmrg#include <servers/bootstrap.h> 564642e01fSmrg#include "mach_startup.h" 574642e01fSmrg#include "mach_startupServer.h" 584642e01fSmrg 59c8548ba8Smrg#include <asl.h> 6035c4bbdfSmrg 614642e01fSmrg/* From darwinEvents.c ... but don't want to pull in all the server cruft */ 6235c4bbdfSmrgvoid 6335c4bbdfSmrgDarwinListenOnOpenFD(int fd); 6435c4bbdfSmrg 6535c4bbdfSmrgextern aslclient aslc; 6635c4bbdfSmrg 6735c4bbdfSmrg/* Ditto, from os/log.c */ 6835c4bbdfSmrgextern void 6935c4bbdfSmrgErrorF(const char *f, ...) _X_ATTRIBUTE_PRINTF(1, 2); 7035c4bbdfSmrgextern void 7135c4bbdfSmrgFatalError(const char *f, ...) _X_ATTRIBUTE_PRINTF(1, 2) _X_NORETURN; 724642e01fSmrg 734642e01fSmrgextern int noPanoramiXExtension; 744642e01fSmrg 75a1e1cf94Smrg#ifdef COMPOSITE 76a1e1cf94Smrgextern Bool noCompositeExtension; 77a1e1cf94Smrg#endif 78a1e1cf94Smrg 794642e01fSmrg#define DEFAULT_CLIENT X11BINDIR "/xterm" 8035c4bbdfSmrg#define DEFAULT_STARTX X11BINDIR "/startx -- " X11BINDIR "/Xquartz" 814642e01fSmrg#define DEFAULT_SHELL "/bin/sh" 824642e01fSmrg 83ed6184dfSmrg#define _STRINGIZE(s) #s 84ed6184dfSmrg#define STRINGIZE(s) _STRINGIZE(s) 85ed6184dfSmrg 864642e01fSmrg#ifndef XSERVER_VERSION 874642e01fSmrg#define XSERVER_VERSION "?" 884642e01fSmrg#endif 894642e01fSmrg 9035c4bbdfSmrgstatic char __crashreporter_info_buff__[4096] = { 0 }; 9135c4bbdfSmrgstatic const char *__crashreporter_info__ __attribute__((__used__)) = 9235c4bbdfSmrg &__crashreporter_info_buff__[0]; 93c8548ba8Smrg// This line just tells the linker to never strip this symbol (such as for space optimization) 946747b715Smrgasm (".desc ___crashreporter_info__, 0x10"); 956747b715Smrg 9635c4bbdfSmrgstatic const char *__crashreporter_info__base = 97ed6184dfSmrg "X.Org X Server " XSERVER_VERSION; 984642e01fSmrg 9935c4bbdfSmrgchar *bundle_id_prefix = NULL; 1006747b715Smrgstatic char *server_bootstrap_name = NULL; 1014642e01fSmrg 1024642e01fSmrg#define DEBUG 1 1034642e01fSmrg 1044642e01fSmrg/* This is in quartzStartup.c */ 10535c4bbdfSmrgint 10635c4bbdfSmrgserver_main(int argc, char **argv, char **envp); 1074642e01fSmrg 10835c4bbdfSmrgstatic int 10935c4bbdfSmrgexecute(const char *command); 11035c4bbdfSmrgstatic char * 11135c4bbdfSmrgcommand_from_prefs(const char *key, const char *default_value); 1124642e01fSmrg 1139ace9065Smrgstatic char *pref_app_to_run; 1149ace9065Smrgstatic char *pref_login_shell; 1159ace9065Smrgstatic char *pref_startx_script; 1169ace9065Smrg 1174642e01fSmrg 1184642e01fSmrg/*** Mach-O IPC Stuffs ***/ 1194642e01fSmrg 1204642e01fSmrgunion MaxMsgSize { 12135c4bbdfSmrg union __RequestUnion__mach_startup_subsystem req; 12235c4bbdfSmrg union __ReplyUnion__mach_startup_subsystem rep; 1234642e01fSmrg}; 1244642e01fSmrg 12535c4bbdfSmrgstatic mach_port_t 12635c4bbdfSmrgcheckin_or_register(char *bname) 12735c4bbdfSmrg{ 1284642e01fSmrg kern_return_t kr; 1294642e01fSmrg mach_port_t mp; 1304642e01fSmrg 1314642e01fSmrg /* If we're started by launchd or the old mach_init */ 1324642e01fSmrg kr = bootstrap_check_in(bootstrap_port, bname, &mp); 1334642e01fSmrg if (kr == KERN_SUCCESS) 1344642e01fSmrg return mp; 1354642e01fSmrg 1364642e01fSmrg /* We probably were not started by launchd or the old mach_init */ 1374642e01fSmrg kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &mp); 1384642e01fSmrg if (kr != KERN_SUCCESS) { 13935c4bbdfSmrg ErrorF("mach_port_allocate(): %s\n", mach_error_string(kr)); 1404642e01fSmrg exit(EXIT_FAILURE); 1414642e01fSmrg } 1424642e01fSmrg 14335c4bbdfSmrg kr = mach_port_insert_right( 14435c4bbdfSmrg mach_task_self(), mp, mp, MACH_MSG_TYPE_MAKE_SEND); 1454642e01fSmrg if (kr != KERN_SUCCESS) { 14635c4bbdfSmrg ErrorF("mach_port_insert_right(): %s\n", mach_error_string(kr)); 1474642e01fSmrg exit(EXIT_FAILURE); 1484642e01fSmrg } 1494642e01fSmrg 15035c4bbdfSmrg#ifdef __clang__ 15135c4bbdfSmrg#pragma clang diagnostic push 15235c4bbdfSmrg#pragma clang diagnostic ignored "-Wdeprecated-declarations" // bootstrap_register 15335c4bbdfSmrg#endif 1544642e01fSmrg kr = bootstrap_register(bootstrap_port, bname, mp); 15535c4bbdfSmrg#ifdef __clang__ 15635c4bbdfSmrg#pragma clang diagnostic pop 15735c4bbdfSmrg#endif 15835c4bbdfSmrg 1594642e01fSmrg if (kr != KERN_SUCCESS) { 16035c4bbdfSmrg ErrorF("bootstrap_register(): %s\n", mach_error_string(kr)); 1614642e01fSmrg exit(EXIT_FAILURE); 1624642e01fSmrg } 1634642e01fSmrg 1644642e01fSmrg return mp; 1654642e01fSmrg} 1664642e01fSmrg 1674642e01fSmrg/*** $DISPLAY handoff ***/ 16835c4bbdfSmrgstatic int 16935c4bbdfSmrgaccept_fd_handoff(int connected_fd) 17035c4bbdfSmrg{ 1714642e01fSmrg int launchd_fd; 17235c4bbdfSmrg 1734642e01fSmrg char databuf[] = "display"; 1744642e01fSmrg struct iovec iov[1]; 17535c4bbdfSmrg 1764642e01fSmrg union { 1774642e01fSmrg struct cmsghdr hdr; 1784642e01fSmrg char bytes[CMSG_SPACE(sizeof(int))]; 1794642e01fSmrg } buf; 18035c4bbdfSmrg 1814642e01fSmrg struct msghdr msg; 1826747b715Smrg struct cmsghdr *cmsg; 1836747b715Smrg 1846747b715Smrg iov[0].iov_base = databuf; 18535c4bbdfSmrg iov[0].iov_len = sizeof(databuf); 18635c4bbdfSmrg 1874642e01fSmrg msg.msg_iov = iov; 1884642e01fSmrg msg.msg_iovlen = 1; 1894642e01fSmrg msg.msg_control = buf.bytes; 1904642e01fSmrg msg.msg_controllen = sizeof(buf); 1914642e01fSmrg msg.msg_name = 0; 1924642e01fSmrg msg.msg_namelen = 0; 1934642e01fSmrg msg.msg_flags = 0; 19435c4bbdfSmrg 19535c4bbdfSmrg cmsg = CMSG_FIRSTHDR(&msg); 1964642e01fSmrg cmsg->cmsg_level = SOL_SOCKET; 1974642e01fSmrg cmsg->cmsg_type = SCM_RIGHTS; 1984642e01fSmrg cmsg->cmsg_len = CMSG_LEN(sizeof(int)); 19935c4bbdfSmrg 2004642e01fSmrg msg.msg_controllen = cmsg->cmsg_len; 20135c4bbdfSmrg 20235c4bbdfSmrg *((int *)CMSG_DATA(cmsg)) = -1; 20335c4bbdfSmrg 20435c4bbdfSmrg if (recvmsg(connected_fd, &msg, 0) < 0) { 20535c4bbdfSmrg ErrorF( 20635c4bbdfSmrg "X11.app: Error receiving $DISPLAY file descriptor. recvmsg() error: %s\n", 20735c4bbdfSmrg strerror(errno)); 2084642e01fSmrg return -1; 2094642e01fSmrg } 21035c4bbdfSmrg 21135c4bbdfSmrg launchd_fd = *((int *)CMSG_DATA(cmsg)); 21235c4bbdfSmrg 2134642e01fSmrg return launchd_fd; 2144642e01fSmrg} 2154642e01fSmrg 2164642e01fSmrgtypedef struct { 2174642e01fSmrg int fd; 2184642e01fSmrg string_t filename; 2194642e01fSmrg} socket_handoff_t; 2204642e01fSmrg 2214642e01fSmrg/* This thread accepts an incoming connection and hands off the file 2224642e01fSmrg * descriptor for the new connection to accept_fd_handoff() 2234642e01fSmrg */ 22435c4bbdfSmrgstatic void 22535c4bbdfSmrgsocket_handoff(socket_handoff_t *handoff_data) 22635c4bbdfSmrg{ 22735c4bbdfSmrg 2284642e01fSmrg int launchd_fd = -1; 2294642e01fSmrg int connected_fd; 2304642e01fSmrg 2314642e01fSmrg /* Now actually get the passed file descriptor from this connection 2324642e01fSmrg * If we encounter an error, keep listening. 2334642e01fSmrg */ 23435c4bbdfSmrg while (launchd_fd == -1) { 2354642e01fSmrg connected_fd = accept(handoff_data->fd, NULL, NULL); 23635c4bbdfSmrg if (connected_fd == -1) { 23735c4bbdfSmrg ErrorF( 23835c4bbdfSmrg "X11.app: Failed to accept incoming connection on socket (fd=%d): %s\n", 23935c4bbdfSmrg handoff_data->fd, strerror(errno)); 2404642e01fSmrg sleep(2); 2414642e01fSmrg continue; 2424642e01fSmrg } 2434642e01fSmrg 2444642e01fSmrg launchd_fd = accept_fd_handoff(connected_fd); 24535c4bbdfSmrg if (launchd_fd == -1) 24635c4bbdfSmrg ErrorF( 24735c4bbdfSmrg "X11.app: Error receiving $DISPLAY file descriptor, no descriptor received? Waiting for another connection.\n"); 2484642e01fSmrg 2494642e01fSmrg close(connected_fd); 2504642e01fSmrg } 2514642e01fSmrg 2524642e01fSmrg close(handoff_data->fd); 2534642e01fSmrg unlink(handoff_data->filename); 2544642e01fSmrg free(handoff_data); 25535c4bbdfSmrg 25635c4bbdfSmrg ErrorF( 25735c4bbdfSmrg "X11.app Handing off fd to server thread via DarwinListenOnOpenFD(%d)\n", 25835c4bbdfSmrg launchd_fd); 2594642e01fSmrg DarwinListenOnOpenFD(launchd_fd); 2609ace9065Smrg 2614642e01fSmrg} 2624642e01fSmrg 26335c4bbdfSmrgstatic int 26435c4bbdfSmrgcreate_socket(char *filename_out) 26535c4bbdfSmrg{ 2664642e01fSmrg struct sockaddr_un servaddr_un; 2674642e01fSmrg struct sockaddr *servaddr; 2684642e01fSmrg socklen_t servaddr_len; 2694642e01fSmrg int ret_fd; 2704642e01fSmrg size_t try, try_max; 27135c4bbdfSmrg 27235c4bbdfSmrg for (try = 0, try_max = 5; try < try_max; try++) { 2734642e01fSmrg tmpnam(filename_out); 27435c4bbdfSmrg 2754642e01fSmrg /* Setup servaddr_un */ 27635c4bbdfSmrg memset(&servaddr_un, 0, sizeof(struct sockaddr_un)); 2774642e01fSmrg servaddr_un.sun_family = AF_UNIX; 27835c4bbdfSmrg strlcpy(servaddr_un.sun_path, filename_out, 27935c4bbdfSmrg sizeof(servaddr_un.sun_path)); 28035c4bbdfSmrg 28135c4bbdfSmrg servaddr = (struct sockaddr *)&servaddr_un; 28235c4bbdfSmrg servaddr_len = sizeof(struct sockaddr_un) - 28335c4bbdfSmrg sizeof(servaddr_un.sun_path) + strlen(filename_out); 28435c4bbdfSmrg 2854642e01fSmrg ret_fd = socket(PF_UNIX, SOCK_STREAM, 0); 28635c4bbdfSmrg if (ret_fd == -1) { 28735c4bbdfSmrg ErrorF( 28835c4bbdfSmrg "X11.app: Failed to create socket (try %d / %d): %s - %s\n", 28935c4bbdfSmrg (int)try + 1, (int)try_max, filename_out, strerror(errno)); 2904642e01fSmrg continue; 2914642e01fSmrg } 29235c4bbdfSmrg 29335c4bbdfSmrg if (bind(ret_fd, servaddr, servaddr_len) != 0) { 29435c4bbdfSmrg ErrorF("X11.app: Failed to bind socket: %d - %s\n", errno, 29535c4bbdfSmrg strerror( 29635c4bbdfSmrg errno)); 2974642e01fSmrg close(ret_fd); 2984642e01fSmrg return 0; 2994642e01fSmrg } 30035c4bbdfSmrg 30135c4bbdfSmrg if (listen(ret_fd, 10) != 0) { 30235c4bbdfSmrg ErrorF("X11.app: Failed to listen to socket: %s - %d - %s\n", 30335c4bbdfSmrg filename_out, errno, strerror( 30435c4bbdfSmrg errno)); 3054642e01fSmrg close(ret_fd); 3064642e01fSmrg return 0; 3074642e01fSmrg } 30835c4bbdfSmrg 3094642e01fSmrg#ifdef DEBUG 31035c4bbdfSmrg ErrorF("X11.app: Listening on socket for fd handoff: (%d) %s\n", 31135c4bbdfSmrg ret_fd, 31235c4bbdfSmrg filename_out); 3134642e01fSmrg#endif 31435c4bbdfSmrg 3154642e01fSmrg return ret_fd; 3164642e01fSmrg } 31735c4bbdfSmrg 3184642e01fSmrg return 0; 3194642e01fSmrg} 3204642e01fSmrg 3214642e01fSmrgstatic int launchd_socket_handed_off = 0; 3224642e01fSmrg 32335c4bbdfSmrgkern_return_t 32435c4bbdfSmrgdo_request_fd_handoff_socket(mach_port_t port, string_t filename) 32535c4bbdfSmrg{ 3264642e01fSmrg socket_handoff_t *handoff_data; 32735c4bbdfSmrg 3284642e01fSmrg launchd_socket_handed_off = 1; 3294642e01fSmrg 33035c4bbdfSmrg handoff_data = (socket_handoff_t *)calloc(1, sizeof(socket_handoff_t)); 33135c4bbdfSmrg if (!handoff_data) { 33235c4bbdfSmrg ErrorF("X11.app: Error allocating memory for handoff_data\n"); 3334642e01fSmrg return KERN_FAILURE; 3344642e01fSmrg } 3354642e01fSmrg 3364642e01fSmrg handoff_data->fd = create_socket(handoff_data->filename); 33735c4bbdfSmrg if (!handoff_data->fd) { 3386747b715Smrg free(handoff_data); 3394642e01fSmrg return KERN_FAILURE; 3404642e01fSmrg } 3414642e01fSmrg 3424642e01fSmrg strlcpy(filename, handoff_data->filename, STRING_T_SIZE); 34335c4bbdfSmrg 34435c4bbdfSmrg dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 34535c4bbdfSmrg 0), ^ { 34635c4bbdfSmrg socket_handoff(handoff_data); 34735c4bbdfSmrg }); 34835c4bbdfSmrg 3494642e01fSmrg#ifdef DEBUG 35035c4bbdfSmrg ErrorF( 35135c4bbdfSmrg "X11.app: Thread created for handoff. Returning success to tell caller to connect and push the fd.\n"); 3524642e01fSmrg#endif 3534642e01fSmrg 3544642e01fSmrg return KERN_SUCCESS; 3554642e01fSmrg} 3564642e01fSmrg 35735c4bbdfSmrgkern_return_t 35835c4bbdfSmrgdo_request_pid(mach_port_t port, int *my_pid) 35935c4bbdfSmrg{ 3604642e01fSmrg *my_pid = getpid(); 3614642e01fSmrg return KERN_SUCCESS; 3624642e01fSmrg} 3634642e01fSmrg 3644642e01fSmrg/*** Server Startup ***/ 36535c4bbdfSmrgkern_return_t 36635c4bbdfSmrgdo_start_x11_server(mach_port_t port, string_array_t argv, 36735c4bbdfSmrg mach_msg_type_number_t argvCnt, 36835c4bbdfSmrg string_array_t envp, 36935c4bbdfSmrg mach_msg_type_number_t envpCnt) 37035c4bbdfSmrg{ 3714642e01fSmrg /* And now back to char ** */ 3724642e01fSmrg char **_argv = alloca((argvCnt + 1) * sizeof(char *)); 3734642e01fSmrg char **_envp = alloca((envpCnt + 1) * sizeof(char *)); 3744642e01fSmrg size_t i; 37535c4bbdfSmrg 3766747b715Smrg /* If we didn't get handed a launchd DISPLAY socket, we should 3774642e01fSmrg * unset DISPLAY or we can run into problems with pbproxy 3784642e01fSmrg */ 37935c4bbdfSmrg if (!launchd_socket_handed_off) { 38035c4bbdfSmrg ErrorF("X11.app: No launchd socket handed off, unsetting DISPLAY\n"); 3814642e01fSmrg unsetenv("DISPLAY"); 3826747b715Smrg } 38335c4bbdfSmrg 38435c4bbdfSmrg if (!_argv || !_envp) { 3854642e01fSmrg return KERN_FAILURE; 3864642e01fSmrg } 3874642e01fSmrg 38835c4bbdfSmrg ErrorF("X11.app: do_start_x11_server(): argc=%d\n", argvCnt); 38935c4bbdfSmrg for (i = 0; i < argvCnt; i++) { 3904642e01fSmrg _argv[i] = argv[i]; 39135c4bbdfSmrg ErrorF("\targv[%u] = %s\n", (unsigned)i, argv[i]); 3924642e01fSmrg } 3934642e01fSmrg _argv[argvCnt] = NULL; 39435c4bbdfSmrg 39535c4bbdfSmrg for (i = 0; i < envpCnt; i++) { 3964642e01fSmrg _envp[i] = envp[i]; 3974642e01fSmrg } 3984642e01fSmrg _envp[envpCnt] = NULL; 39935c4bbdfSmrg 40035c4bbdfSmrg if (server_main(argvCnt, _argv, _envp) == 0) 4014642e01fSmrg return KERN_SUCCESS; 4024642e01fSmrg else 4034642e01fSmrg return KERN_FAILURE; 4044642e01fSmrg} 4054642e01fSmrg 40635c4bbdfSmrgstatic int 40735c4bbdfSmrgstartup_trigger(int argc, char **argv, char **envp) 40835c4bbdfSmrg{ 4094642e01fSmrg Display *display; 4104642e01fSmrg const char *s; 41135c4bbdfSmrg 4124642e01fSmrg /* Take care of the case where we're called like a normal DDX */ 41335c4bbdfSmrg if (argc > 1 && argv[1][0] == ':') { 4144642e01fSmrg size_t i; 4154642e01fSmrg kern_return_t kr; 4164642e01fSmrg mach_port_t mp; 4174642e01fSmrg string_array_t newenvp; 4184642e01fSmrg string_array_t newargv; 4194642e01fSmrg 4204642e01fSmrg /* We need to count envp */ 4214642e01fSmrg int envpc; 42235c4bbdfSmrg for (envpc = 0; envp[envpc]; envpc++) ; 4234642e01fSmrg 4244642e01fSmrg /* We have fixed-size string lengths due to limitations in IPC, 4254642e01fSmrg * so we need to copy our argv and envp. 4264642e01fSmrg */ 4274642e01fSmrg newargv = (string_array_t)alloca(argc * sizeof(string_t)); 4284642e01fSmrg newenvp = (string_array_t)alloca(envpc * sizeof(string_t)); 42935c4bbdfSmrg 43035c4bbdfSmrg if (!newargv || !newenvp) { 43135c4bbdfSmrg ErrorF("Memory allocation failure\n"); 4324642e01fSmrg exit(EXIT_FAILURE); 4334642e01fSmrg } 43435c4bbdfSmrg 43535c4bbdfSmrg for (i = 0; i < argc; i++) { 4364642e01fSmrg strlcpy(newargv[i], argv[i], STRING_T_SIZE); 4374642e01fSmrg } 43835c4bbdfSmrg for (i = 0; i < envpc; i++) { 4394642e01fSmrg strlcpy(newenvp[i], envp[i], STRING_T_SIZE); 4404642e01fSmrg } 4414642e01fSmrg 4424642e01fSmrg kr = bootstrap_look_up(bootstrap_port, server_bootstrap_name, &mp); 4434642e01fSmrg if (kr != KERN_SUCCESS) { 44435c4bbdfSmrg ErrorF("bootstrap_look_up(%s): %s\n", server_bootstrap_name, 44535c4bbdfSmrg bootstrap_strerror( 44635c4bbdfSmrg kr)); 4474642e01fSmrg exit(EXIT_FAILURE); 4484642e01fSmrg } 4494642e01fSmrg 4504642e01fSmrg kr = start_x11_server(mp, newargv, argc, newenvp, envpc); 4514642e01fSmrg if (kr != KERN_SUCCESS) { 45235c4bbdfSmrg ErrorF("start_x11_server: %s\n", mach_error_string(kr)); 4534642e01fSmrg exit(EXIT_FAILURE); 4544642e01fSmrg } 4554642e01fSmrg exit(EXIT_SUCCESS); 4564642e01fSmrg } 4574642e01fSmrg 4584642e01fSmrg /* If we have a process serial number and it's our only arg, act as if 4594642e01fSmrg * the user double clicked the app bundle: launch app_to_run if possible 4604642e01fSmrg */ 46135c4bbdfSmrg if (argc == 1 || (argc == 2 && !strncmp(argv[1], "-psn_", 5))) { 4624642e01fSmrg /* Now, try to open a display, if so, run the launcher */ 4634642e01fSmrg display = XOpenDisplay(NULL); 46435c4bbdfSmrg if (display) { 4654642e01fSmrg /* Could open the display, start the launcher */ 4664642e01fSmrg XCloseDisplay(display); 4674642e01fSmrg 4689ace9065Smrg return execute(pref_app_to_run); 4694642e01fSmrg } 4704642e01fSmrg } 4714642e01fSmrg 4724642e01fSmrg /* Start the server */ 47335c4bbdfSmrg if ((s = getenv("DISPLAY"))) { 47435c4bbdfSmrg ErrorF( 47535c4bbdfSmrg "X11.app: Could not connect to server (DISPLAY=\"%s\", unsetting). Starting X server.\n", 47635c4bbdfSmrg s); 4774642e01fSmrg unsetenv("DISPLAY"); 47835c4bbdfSmrg } 47935c4bbdfSmrg else { 48035c4bbdfSmrg ErrorF( 48135c4bbdfSmrg "X11.app: Could not connect to server (DISPLAY is not set). Starting X server.\n"); 4824642e01fSmrg } 4839ace9065Smrg return execute(pref_startx_script); 4844642e01fSmrg} 4854642e01fSmrg 4864642e01fSmrg/** Setup the environment we want our child processes to inherit */ 48735c4bbdfSmrgstatic void 48835c4bbdfSmrgensure_path(const char *dir) 48935c4bbdfSmrg{ 4904642e01fSmrg char buf[1024], *temp; 49135c4bbdfSmrg 4924642e01fSmrg /* Make sure /usr/X11/bin is in the $PATH */ 4934642e01fSmrg temp = getenv("PATH"); 49435c4bbdfSmrg if (temp == NULL || temp[0] == 0) { 49535c4bbdfSmrg snprintf(buf, sizeof(buf), 49635c4bbdfSmrg "/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:%s", 49735c4bbdfSmrg dir); 4984642e01fSmrg setenv("PATH", buf, TRUE); 49935c4bbdfSmrg } 50035c4bbdfSmrg else if (strnstr(temp, X11BINDIR, sizeof(temp)) == NULL) { 5014642e01fSmrg snprintf(buf, sizeof(buf), "%s:%s", temp, dir); 5024642e01fSmrg setenv("PATH", buf, TRUE); 5034642e01fSmrg } 5044642e01fSmrg} 5054642e01fSmrg 50635c4bbdfSmrgstatic void 50735c4bbdfSmrgsetup_console_redirect(const char *bundle_id) 50835c4bbdfSmrg{ 50935c4bbdfSmrg char *asl_sender; 51035c4bbdfSmrg char *asl_facility; 51135c4bbdfSmrg 51235c4bbdfSmrg asprintf(&asl_sender, "%s.server", bundle_id); 51335c4bbdfSmrg assert(asl_sender); 51435c4bbdfSmrg 51535c4bbdfSmrg asl_facility = strdup(bundle_id); 51635c4bbdfSmrg assert(asl_facility); 51735c4bbdfSmrg if (strcmp(asl_facility + strlen(asl_facility) - 4, ".X11") == 0) 51835c4bbdfSmrg asl_facility[strlen(asl_facility) - 4] = '\0'; 51935c4bbdfSmrg 52035c4bbdfSmrg assert(aslc = asl_open(asl_sender, asl_facility, ASL_OPT_NO_DELAY)); 52135c4bbdfSmrg free(asl_sender); 52235c4bbdfSmrg free(asl_facility); 52335c4bbdfSmrg 52435c4bbdfSmrg asl_set_filter(aslc, ASL_FILTER_MASK_UPTO(ASL_LEVEL_WARNING)); 52535c4bbdfSmrg 526c8548ba8Smrg asl_log_descriptor(aslc, NULL, ASL_LEVEL_INFO, STDOUT_FILENO, ASL_LOG_DESCRIPTOR_WRITE); 527c8548ba8Smrg asl_log_descriptor(aslc, NULL, ASL_LEVEL_NOTICE, STDERR_FILENO, ASL_LOG_DESCRIPTOR_WRITE); 52835c4bbdfSmrg} 52935c4bbdfSmrg 53035c4bbdfSmrgstatic void 53135c4bbdfSmrgsetup_env(void) 53235c4bbdfSmrg{ 5334642e01fSmrg char *temp; 5344642e01fSmrg const char *pds = NULL; 5356747b715Smrg const char *disp = getenv("DISPLAY"); 5366747b715Smrg size_t len; 5374642e01fSmrg 5384642e01fSmrg /* Pass on our prefs domain to startx and its inheritors (mainly for 5394642e01fSmrg * quartz-wm and the Xquartz stub's MachIPC) 5404642e01fSmrg */ 5414642e01fSmrg CFBundleRef bundle = CFBundleGetMainBundle(); 54235c4bbdfSmrg if (bundle) { 5434642e01fSmrg CFStringRef pd = CFBundleGetIdentifier(bundle); 54435c4bbdfSmrg if (pd) { 5454642e01fSmrg pds = CFStringGetCStringPtr(pd, 0); 5464642e01fSmrg } 5474642e01fSmrg } 5484642e01fSmrg 5496747b715Smrg /* fallback to hardcoded value if we can't discover it */ 55035c4bbdfSmrg if (!pds) { 55135c4bbdfSmrg pds = BUNDLE_ID_PREFIX ".X11"; 5526747b715Smrg } 5536747b715Smrg 55435c4bbdfSmrg setup_console_redirect(pds); 55535c4bbdfSmrg 5569ace9065Smrg server_bootstrap_name = strdup(pds); 55735c4bbdfSmrg if (!server_bootstrap_name) { 55835c4bbdfSmrg ErrorF("X11.app: Memory allocation error.\n"); 5596747b715Smrg exit(1); 5606747b715Smrg } 5616747b715Smrg setenv("X11_PREFS_DOMAIN", server_bootstrap_name, 1); 56235c4bbdfSmrg 5636747b715Smrg len = strlen(server_bootstrap_name); 56435c4bbdfSmrg bundle_id_prefix = malloc(sizeof(char) * (len - 3)); 56535c4bbdfSmrg if (!bundle_id_prefix) { 56635c4bbdfSmrg ErrorF("X11.app: Memory allocation error.\n"); 5676747b715Smrg exit(1); 5686747b715Smrg } 56935c4bbdfSmrg strlcpy(bundle_id_prefix, server_bootstrap_name, len - 3); 57035c4bbdfSmrg 5716747b715Smrg /* We need to unset DISPLAY if it is not our socket */ 57235c4bbdfSmrg if (disp) { 5736747b715Smrg /* s = basename(disp) */ 5746747b715Smrg const char *d, *s; 57535c4bbdfSmrg for (s = NULL, d = disp; *d; d++) { 57635c4bbdfSmrg if (*d == '/') 5776747b715Smrg s = d + 1; 5786747b715Smrg } 5796747b715Smrg 58035c4bbdfSmrg if (s && *s) { 58135c4bbdfSmrg if (strcmp(bundle_id_prefix, 58235c4bbdfSmrg "org.x") == 0 && strcmp(s, ":0") == 0) { 58335c4bbdfSmrg ErrorF( 58435c4bbdfSmrg "X11.app: Detected old style launchd DISPLAY, please update xinit.\n"); 58535c4bbdfSmrg } 58635c4bbdfSmrg else { 5876747b715Smrg temp = (char *)malloc(sizeof(char) * len); 58835c4bbdfSmrg if (!temp) { 58935c4bbdfSmrg ErrorF( 59035c4bbdfSmrg "X11.app: Memory allocation error creating space for socket name test.\n"); 5916747b715Smrg exit(1); 5926747b715Smrg } 59335c4bbdfSmrg strlcpy(temp, bundle_id_prefix, len); 5946747b715Smrg strlcat(temp, ":0", len); 59535c4bbdfSmrg 59635c4bbdfSmrg if (strcmp(temp, s) != 0) { 5976747b715Smrg /* If we don't have a match, unset it. */ 59835c4bbdfSmrg ErrorF( 59935c4bbdfSmrg "X11.app: DISPLAY (\"%s\") does not match our id (\"%s\"), unsetting.\n", 60035c4bbdfSmrg disp, bundle_id_prefix); 6016747b715Smrg unsetenv("DISPLAY"); 6026747b715Smrg } 6036747b715Smrg free(temp); 6046747b715Smrg } 60535c4bbdfSmrg } 60635c4bbdfSmrg else { 6076747b715Smrg /* The DISPLAY environment variable is not formatted like a launchd socket, so reset. */ 60835c4bbdfSmrg ErrorF( 60935c4bbdfSmrg "X11.app: DISPLAY does not look like a launchd set variable, unsetting.\n"); 6106747b715Smrg unsetenv("DISPLAY"); 6116747b715Smrg } 6126747b715Smrg } 6134642e01fSmrg 6144642e01fSmrg /* Make sure PATH is right */ 6154642e01fSmrg ensure_path(X11BINDIR); 61635c4bbdfSmrg 6174642e01fSmrg /* cd $HOME */ 6184642e01fSmrg temp = getenv("HOME"); 61935c4bbdfSmrg if (temp != NULL && temp[0] != '\0') 6204642e01fSmrg chdir(temp); 6214642e01fSmrg} 6224642e01fSmrg 6234642e01fSmrg/*** Main ***/ 62435c4bbdfSmrgint 62535c4bbdfSmrgmain(int argc, char **argv, char **envp) 62635c4bbdfSmrg{ 6274642e01fSmrg Bool listenOnly = FALSE; 6284642e01fSmrg int i; 6294642e01fSmrg mach_msg_size_t mxmsgsz = sizeof(union MaxMsgSize) + MAX_TRAILER_SIZE; 6304642e01fSmrg mach_port_t mp; 6314642e01fSmrg kern_return_t kr; 6324642e01fSmrg 633a1e1cf94Smrg /* Ignore SIGPIPE */ 634a1e1cf94Smrg signal(SIGPIPE, SIG_IGN); 635a1e1cf94Smrg 6364642e01fSmrg /* Setup our environment for our children */ 6374642e01fSmrg setup_env(); 63835c4bbdfSmrg 6394642e01fSmrg /* The server must not run the PanoramiX operations. */ 6404642e01fSmrg noPanoramiXExtension = TRUE; 6414642e01fSmrg 642a1e1cf94Smrg#ifdef COMPOSITE 643a1e1cf94Smrg /* https://gitlab.freedesktop.org/xorg/xserver/-/issues/1409 */ 644a1e1cf94Smrg noCompositeExtension = TRUE; 645a1e1cf94Smrg#endif 646a1e1cf94Smrg 6474642e01fSmrg /* Setup the initial crasherporter info */ 64835c4bbdfSmrg strlcpy(__crashreporter_info_buff__, __crashreporter_info__base, 64935c4bbdfSmrg sizeof(__crashreporter_info_buff__)); 65035c4bbdfSmrg 65135c4bbdfSmrg ErrorF("X11.app: main(): argc=%d\n", argc); 65235c4bbdfSmrg for (i = 0; i < argc; i++) { 65335c4bbdfSmrg ErrorF("\targv[%u] = %s\n", (unsigned)i, argv[i]); 65435c4bbdfSmrg if (!strcmp(argv[i], "--listenonly")) { 6554642e01fSmrg listenOnly = TRUE; 6564642e01fSmrg } 6574642e01fSmrg } 6584642e01fSmrg 6594642e01fSmrg mp = checkin_or_register(server_bootstrap_name); 66035c4bbdfSmrg if (mp == MACH_PORT_NULL) { 66135c4bbdfSmrg ErrorF("NULL mach service: %s", server_bootstrap_name); 6624642e01fSmrg return EXIT_FAILURE; 6634642e01fSmrg } 66435c4bbdfSmrg 6654642e01fSmrg /* Check if we need to do something other than listen, and make another 6664642e01fSmrg * thread handle it. 6674642e01fSmrg */ 66835c4bbdfSmrg if (!listenOnly) { 6696747b715Smrg pid_t child1, child2; 6706747b715Smrg int status; 6716747b715Smrg 6729ace9065Smrg pref_app_to_run = command_from_prefs("app_to_run", DEFAULT_CLIENT); 6739ace9065Smrg assert(pref_app_to_run); 6749ace9065Smrg 6759ace9065Smrg pref_login_shell = command_from_prefs("login_shell", DEFAULT_SHELL); 6769ace9065Smrg assert(pref_login_shell); 6779ace9065Smrg 67835c4bbdfSmrg pref_startx_script = command_from_prefs("startx_script", 67935c4bbdfSmrg DEFAULT_STARTX); 6809ace9065Smrg assert(pref_startx_script); 6819ace9065Smrg 6826747b715Smrg /* Do the fork-twice trick to avoid having to reap zombies */ 6836747b715Smrg child1 = fork(); 6846747b715Smrg switch (child1) { 68535c4bbdfSmrg case -1: /* error */ 68635c4bbdfSmrg FatalError("fork() failed: %s\n", strerror(errno)); 6876747b715Smrg 68835c4bbdfSmrg case 0: /* child1 */ 68935c4bbdfSmrg child2 = fork(); 6906747b715Smrg 69135c4bbdfSmrg switch (child2) { 69235c4bbdfSmrg int max_files; 6936747b715Smrg 69435c4bbdfSmrg case -1: /* error */ 69535c4bbdfSmrg FatalError("fork() failed: %s\n", strerror(errno)); 6966747b715Smrg 69735c4bbdfSmrg case 0: /* child2 */ 69835c4bbdfSmrg /* close all open files except for standard streams */ 69935c4bbdfSmrg max_files = sysconf(_SC_OPEN_MAX); 70035c4bbdfSmrg for (i = 3; i < max_files; i++) 70135c4bbdfSmrg close(i); 7026747b715Smrg 70335c4bbdfSmrg /* ensure stdin is on /dev/null */ 70435c4bbdfSmrg close(0); 70535c4bbdfSmrg open("/dev/null", O_RDONLY); 7066747b715Smrg 70735c4bbdfSmrg return startup_trigger(argc, argv, envp); 7086747b715Smrg 70935c4bbdfSmrg default: /* parent (child1) */ 71035c4bbdfSmrg _exit(0); 71135c4bbdfSmrg } 71235c4bbdfSmrg break; 7136747b715Smrg 71435c4bbdfSmrg default: /* parent */ 71535c4bbdfSmrg waitpid(child1, &status, 0); 7164642e01fSmrg } 7179ace9065Smrg 7189ace9065Smrg free(pref_app_to_run); 7199ace9065Smrg free(pref_login_shell); 7209ace9065Smrg free(pref_startx_script); 7214642e01fSmrg } 72235c4bbdfSmrg 7234642e01fSmrg /* Main event loop */ 72435c4bbdfSmrg ErrorF("Waiting for startup parameters via Mach IPC.\n"); 7254642e01fSmrg kr = mach_msg_server(mach_startup_server, mxmsgsz, mp, 0); 7264642e01fSmrg if (kr != KERN_SUCCESS) { 72735c4bbdfSmrg ErrorF("%s.X11(mp): %s\n", BUNDLE_ID_PREFIX, mach_error_string(kr)); 7284642e01fSmrg return EXIT_FAILURE; 7294642e01fSmrg } 73035c4bbdfSmrg 7314642e01fSmrg return EXIT_SUCCESS; 7324642e01fSmrg} 7334642e01fSmrg 73435c4bbdfSmrgstatic int 73535c4bbdfSmrgexecute(const char *command) 73635c4bbdfSmrg{ 7374642e01fSmrg const char *newargv[4]; 7384642e01fSmrg const char **p; 73935c4bbdfSmrg 7409ace9065Smrg newargv[0] = pref_login_shell; 7414642e01fSmrg newargv[1] = "-c"; 7424642e01fSmrg newargv[2] = command; 7434642e01fSmrg newargv[3] = NULL; 74435c4bbdfSmrg 74535c4bbdfSmrg ErrorF("X11.app: Launching %s:\n", command); 74635c4bbdfSmrg for (p = newargv; *p; p++) { 74735c4bbdfSmrg ErrorF("\targv[%ld] = %s\n", (long int)(p - newargv), *p); 7484642e01fSmrg } 7494642e01fSmrg 75035c4bbdfSmrg execvp(newargv[0], (char *const *)newargv); 75135c4bbdfSmrg perror("X11.app: Couldn't exec."); 7526747b715Smrg return 1; 7534642e01fSmrg} 7544642e01fSmrg 75535c4bbdfSmrgstatic char * 75635c4bbdfSmrgcommand_from_prefs(const char *key, const char *default_value) 75735c4bbdfSmrg{ 7584642e01fSmrg char *command = NULL; 75935c4bbdfSmrg 7606747b715Smrg CFStringRef cfKey; 7616747b715Smrg CFPropertyListRef PlistRef; 7626747b715Smrg 76335c4bbdfSmrg if (!key) 7646747b715Smrg return NULL; 7656747b715Smrg 7666747b715Smrg cfKey = CFStringCreateWithCString(NULL, key, kCFStringEncodingASCII); 7676747b715Smrg 76835c4bbdfSmrg if (!cfKey) 7696747b715Smrg return NULL; 7706747b715Smrg 77135c4bbdfSmrg PlistRef = CFPreferencesCopyAppValue(cfKey, 77235c4bbdfSmrg kCFPreferencesCurrentApplication); 77335c4bbdfSmrg 77435c4bbdfSmrg if ((PlistRef == NULL) || 77535c4bbdfSmrg (CFGetTypeID(PlistRef) != CFStringGetTypeID())) { 77635c4bbdfSmrg CFStringRef cfDefaultValue = CFStringCreateWithCString( 77735c4bbdfSmrg NULL, default_value, kCFStringEncodingASCII); 7786747b715Smrg int len = strlen(default_value) + 1; 7796747b715Smrg 78035c4bbdfSmrg if (!cfDefaultValue) 7816747b715Smrg goto command_from_prefs_out; 7824642e01fSmrg 78335c4bbdfSmrg CFPreferencesSetAppValue(cfKey, cfDefaultValue, 78435c4bbdfSmrg kCFPreferencesCurrentApplication); 7854642e01fSmrg CFPreferencesAppSynchronize(kCFPreferencesCurrentApplication); 7866747b715Smrg CFRelease(cfDefaultValue); 78735c4bbdfSmrg 7884642e01fSmrg command = (char *)malloc(len * sizeof(char)); 78935c4bbdfSmrg if (!command) 7906747b715Smrg goto command_from_prefs_out; 7914642e01fSmrg strcpy(command, default_value); 79235c4bbdfSmrg } 79335c4bbdfSmrg else { 7944642e01fSmrg int len = CFStringGetLength((CFStringRef)PlistRef) + 1; 7954642e01fSmrg command = (char *)malloc(len * sizeof(char)); 79635c4bbdfSmrg if (!command) 7976747b715Smrg goto command_from_prefs_out; 79835c4bbdfSmrg CFStringGetCString((CFStringRef)PlistRef, command, len, 79935c4bbdfSmrg kCFStringEncodingASCII); 8006747b715Smrg } 8016747b715Smrg 8026747b715Smrgcommand_from_prefs_out: 8034642e01fSmrg if (PlistRef) 8044642e01fSmrg CFRelease(PlistRef); 80535c4bbdfSmrg if (cfKey) 8066747b715Smrg CFRelease(cfKey); 8074642e01fSmrg return command; 8084642e01fSmrg} 809