"Fossies" - the Fresh Open Source Software Archive

Member "xorg-server-1.20.5/hw/xquartz/mach-startup/bundle-main.c" (30 May 2019, 24744 Bytes) of package /linux/misc/xorg-server-1.20.5.tar.bz2:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "bundle-main.c" see the Fossies "Dox" file reference documentation.

    1 /* main.c -- X application launcher
    2  * Copyright (c) 2007 Jeremy Huddleston
    3  * Copyright (c) 2007-2012 Apple Inc. All rights reserved.
    4  *
    5  * Permission is hereby granted, free of charge, to any person
    6  * obtaining a copy of this software and associated documentation files
    7  * (the "Software"), to deal in the Software without restriction,
    8  * including without limitation the rights to use, copy, modify, merge,
    9  * publish, distribute, sublicense, and/or sell copies of the Software,
   10  * and to permit persons to whom the Software is furnished to do so,
   11  * subject to the following conditions:
   12  *
   13  * The above copyright notice and this permission notice shall be
   14  * included in all copies or substantial portions of the Software.
   15  *
   16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
   17  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
   18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
   19  * NONINFRINGEMENT.  IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT
   20  * HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
   21  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   22  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
   23  * DEALINGS IN THE SOFTWARE.
   24  *
   25  * Except as contained in this notice, the name(s) of the above
   26  * copyright holders shall not be used in advertising or otherwise to
   27  * promote the sale, use or other dealings in this Software without
   28  * prior written authorization.
   29  */
   30 
   31 #include <CoreFoundation/CoreFoundation.h>
   32 #include <AvailabilityMacros.h>
   33 
   34 #ifdef HAVE_DIX_CONFIG_H
   35 #include <dix-config.h>
   36 #endif
   37 
   38 #include <X11/Xlib.h>
   39 #include <assert.h>
   40 #include <unistd.h>
   41 #include <stdio.h>
   42 #include <string.h>
   43 #include <stdlib.h>
   44 #include <stdbool.h>
   45 #include <signal.h>
   46 
   47 #ifdef HAVE_LIBDISPATCH
   48 #include <dispatch/dispatch.h>
   49 #else
   50 #include <pthread.h>
   51 #endif
   52 
   53 #include <sys/socket.h>
   54 #include <sys/un.h>
   55 
   56 #include <fcntl.h>
   57 
   58 #include <mach/mach.h>
   59 #include <mach/mach_error.h>
   60 #include <servers/bootstrap.h>
   61 #include "mach_startup.h"
   62 #include "mach_startupServer.h"
   63 
   64 #include "console_redirect.h"
   65 
   66 /* From darwinEvents.c ... but don't want to pull in all the server cruft */
   67 void
   68 DarwinListenOnOpenFD(int fd);
   69 
   70 extern aslclient aslc;
   71 
   72 /* Ditto, from os/log.c */
   73 extern void
   74 ErrorF(const char *f, ...) _X_ATTRIBUTE_PRINTF(1, 2);
   75 extern void
   76 FatalError(const char *f, ...) _X_ATTRIBUTE_PRINTF(1, 2) _X_NORETURN;
   77 
   78 extern int noPanoramiXExtension;
   79 
   80 #define DEFAULT_CLIENT X11BINDIR "/xterm"
   81 #define DEFAULT_STARTX X11BINDIR "/startx -- " X11BINDIR "/Xquartz"
   82 #define DEFAULT_SHELL  "/bin/sh"
   83 
   84 #ifndef BUILD_DATE
   85 #define BUILD_DATE ""
   86 #endif
   87 #ifndef XSERVER_VERSION
   88 #define XSERVER_VERSION "?"
   89 #endif
   90 
   91 static char __crashreporter_info_buff__[4096] = { 0 };
   92 static const char *__crashreporter_info__ __attribute__((__used__)) =
   93     &__crashreporter_info_buff__[0];
   94 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
   95 // This is actually a toolchain requirement, but I'm not sure the correct check,
   96 // but it should be fine to just only include it for Leopard and later.  This line
   97 // just tells the linker to never strip this symbol (such as for space optimization)
   98 asm (".desc ___crashreporter_info__, 0x10");
   99 #endif
  100 
  101 static const char *__crashreporter_info__base =
  102     "X.Org X Server " XSERVER_VERSION " Build Date: " BUILD_DATE;
  103 
  104 char *bundle_id_prefix = NULL;
  105 static char *server_bootstrap_name = NULL;
  106 
  107 #define DEBUG 1
  108 
  109 /* This is in quartzStartup.c */
  110 int
  111 server_main(int argc, char **argv, char **envp);
  112 
  113 static int
  114 execute(const char *command);
  115 static char *
  116 command_from_prefs(const char *key, const char *default_value);
  117 
  118 static char *pref_app_to_run;
  119 static char *pref_login_shell;
  120 static char *pref_startx_script;
  121 
  122 #ifndef HAVE_LIBDISPATCH
  123 /*** Pthread Magics ***/
  124 static pthread_t
  125 create_thread(void *(*func)(void *), void *arg)
  126 {
  127     pthread_attr_t attr;
  128     pthread_t tid;
  129 
  130     pthread_attr_init(&attr);
  131     pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
  132     pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
  133     pthread_create(&tid, &attr, func, arg);
  134     pthread_attr_destroy(&attr);
  135 
  136     return tid;
  137 }
  138 #endif
  139 
  140 /*** Mach-O IPC Stuffs ***/
  141 
  142 union MaxMsgSize {
  143     union __RequestUnion__mach_startup_subsystem req;
  144     union __ReplyUnion__mach_startup_subsystem rep;
  145 };
  146 
  147 static mach_port_t
  148 checkin_or_register(char *bname)
  149 {
  150     kern_return_t kr;
  151     mach_port_t mp;
  152 
  153     /* If we're started by launchd or the old mach_init */
  154     kr = bootstrap_check_in(bootstrap_port, bname, &mp);
  155     if (kr == KERN_SUCCESS)
  156         return mp;
  157 
  158     /* We probably were not started by launchd or the old mach_init */
  159     kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &mp);
  160     if (kr != KERN_SUCCESS) {
  161         ErrorF("mach_port_allocate(): %s\n", mach_error_string(kr));
  162         exit(EXIT_FAILURE);
  163     }
  164 
  165     kr = mach_port_insert_right(
  166         mach_task_self(), mp, mp, MACH_MSG_TYPE_MAKE_SEND);
  167     if (kr != KERN_SUCCESS) {
  168         ErrorF("mach_port_insert_right(): %s\n", mach_error_string(kr));
  169         exit(EXIT_FAILURE);
  170     }
  171 
  172 #ifdef __clang__
  173 #pragma clang diagnostic push
  174 #pragma clang diagnostic ignored "-Wdeprecated-declarations" // bootstrap_register
  175 #endif
  176     kr = bootstrap_register(bootstrap_port, bname, mp);
  177 #ifdef __clang__
  178 #pragma clang diagnostic pop
  179 #endif
  180 
  181     if (kr != KERN_SUCCESS) {
  182         ErrorF("bootstrap_register(): %s\n", mach_error_string(kr));
  183         exit(EXIT_FAILURE);
  184     }
  185 
  186     return mp;
  187 }
  188 
  189 /*** $DISPLAY handoff ***/
  190 static int
  191 accept_fd_handoff(int connected_fd)
  192 {
  193     int launchd_fd;
  194 
  195     char databuf[] = "display";
  196     struct iovec iov[1];
  197 
  198     union {
  199         struct cmsghdr hdr;
  200         char bytes[CMSG_SPACE(sizeof(int))];
  201     } buf;
  202 
  203     struct msghdr msg;
  204     struct cmsghdr *cmsg;
  205 
  206     iov[0].iov_base = databuf;
  207     iov[0].iov_len = sizeof(databuf);
  208 
  209     msg.msg_iov = iov;
  210     msg.msg_iovlen = 1;
  211     msg.msg_control = buf.bytes;
  212     msg.msg_controllen = sizeof(buf);
  213     msg.msg_name = 0;
  214     msg.msg_namelen = 0;
  215     msg.msg_flags = 0;
  216 
  217     cmsg = CMSG_FIRSTHDR(&msg);
  218     cmsg->cmsg_level = SOL_SOCKET;
  219     cmsg->cmsg_type = SCM_RIGHTS;
  220     cmsg->cmsg_len = CMSG_LEN(sizeof(int));
  221 
  222     msg.msg_controllen = cmsg->cmsg_len;
  223 
  224     *((int *)CMSG_DATA(cmsg)) = -1;
  225 
  226     if (recvmsg(connected_fd, &msg, 0) < 0) {
  227         ErrorF(
  228             "X11.app: Error receiving $DISPLAY file descriptor.  recvmsg() error: %s\n",
  229             strerror(errno));
  230         return -1;
  231     }
  232 
  233     launchd_fd = *((int *)CMSG_DATA(cmsg));
  234 
  235     return launchd_fd;
  236 }
  237 
  238 typedef struct {
  239     int fd;
  240     string_t filename;
  241 } socket_handoff_t;
  242 
  243 /* This thread accepts an incoming connection and hands off the file
  244  * descriptor for the new connection to accept_fd_handoff()
  245  */
  246 #ifdef HAVE_LIBDISPATCH
  247 static void
  248 socket_handoff(socket_handoff_t *handoff_data)
  249 {
  250 #else
  251 static void *
  252 socket_handoff_thread(void *arg)
  253 {
  254     socket_handoff_t *handoff_data = (socket_handoff_t *)arg;
  255 #endif
  256 
  257     int launchd_fd = -1;
  258     int connected_fd;
  259 
  260     /* Now actually get the passed file descriptor from this connection
  261      * If we encounter an error, keep listening.
  262      */
  263     while (launchd_fd == -1) {
  264         connected_fd = accept(handoff_data->fd, NULL, NULL);
  265         if (connected_fd == -1) {
  266             ErrorF(
  267                 "X11.app: Failed to accept incoming connection on socket (fd=%d): %s\n",
  268                 handoff_data->fd, strerror(errno));
  269             sleep(2);
  270             continue;
  271         }
  272 
  273         launchd_fd = accept_fd_handoff(connected_fd);
  274         if (launchd_fd == -1)
  275             ErrorF(
  276                 "X11.app: Error receiving $DISPLAY file descriptor, no descriptor received?  Waiting for another connection.\n");
  277 
  278         close(connected_fd);
  279     }
  280 
  281     close(handoff_data->fd);
  282     unlink(handoff_data->filename);
  283     free(handoff_data);
  284 
  285     ErrorF(
  286         "X11.app Handing off fd to server thread via DarwinListenOnOpenFD(%d)\n",
  287         launchd_fd);
  288     DarwinListenOnOpenFD(launchd_fd);
  289 
  290 #ifndef HAVE_LIBDISPATCH
  291     return NULL;
  292 #endif
  293 }
  294 
  295 static int
  296 create_socket(char *filename_out)
  297 {
  298     struct sockaddr_un servaddr_un;
  299     struct sockaddr *servaddr;
  300     socklen_t servaddr_len;
  301     int ret_fd;
  302     size_t try, try_max;
  303 
  304     for (try = 0, try_max = 5; try < try_max; try++) {
  305         tmpnam(filename_out);
  306 
  307         /* Setup servaddr_un */
  308         memset(&servaddr_un, 0, sizeof(struct sockaddr_un));
  309         servaddr_un.sun_family = AF_UNIX;
  310         strlcpy(servaddr_un.sun_path, filename_out,
  311                 sizeof(servaddr_un.sun_path));
  312 
  313         servaddr = (struct sockaddr *)&servaddr_un;
  314         servaddr_len = sizeof(struct sockaddr_un) -
  315                        sizeof(servaddr_un.sun_path) + strlen(filename_out);
  316 
  317         ret_fd = socket(PF_UNIX, SOCK_STREAM, 0);
  318         if (ret_fd == -1) {
  319             ErrorF(
  320                 "X11.app: Failed to create socket (try %d / %d): %s - %s\n",
  321                 (int)try + 1, (int)try_max, filename_out, strerror(errno));
  322             continue;
  323         }
  324 
  325         if (bind(ret_fd, servaddr, servaddr_len) != 0) {
  326             ErrorF("X11.app: Failed to bind socket: %d - %s\n", errno,
  327                    strerror(
  328                        errno));
  329             close(ret_fd);
  330             return 0;
  331         }
  332 
  333         if (listen(ret_fd, 10) != 0) {
  334             ErrorF("X11.app: Failed to listen to socket: %s - %d - %s\n",
  335                    filename_out, errno, strerror(
  336                        errno));
  337             close(ret_fd);
  338             return 0;
  339         }
  340 
  341 #ifdef DEBUG
  342         ErrorF("X11.app: Listening on socket for fd handoff:  (%d) %s\n",
  343                ret_fd,
  344                filename_out);
  345 #endif
  346 
  347         return ret_fd;
  348     }
  349 
  350     return 0;
  351 }
  352 
  353 static int launchd_socket_handed_off = 0;
  354 
  355 kern_return_t
  356 do_request_fd_handoff_socket(mach_port_t port, string_t filename)
  357 {
  358     socket_handoff_t *handoff_data;
  359 
  360     launchd_socket_handed_off = 1;
  361 
  362     handoff_data = (socket_handoff_t *)calloc(1, sizeof(socket_handoff_t));
  363     if (!handoff_data) {
  364         ErrorF("X11.app: Error allocating memory for handoff_data\n");
  365         return KERN_FAILURE;
  366     }
  367 
  368     handoff_data->fd = create_socket(handoff_data->filename);
  369     if (!handoff_data->fd) {
  370         free(handoff_data);
  371         return KERN_FAILURE;
  372     }
  373 
  374     strlcpy(filename, handoff_data->filename, STRING_T_SIZE);
  375 
  376 #ifdef HAVE_LIBDISPATCH
  377     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,
  378                                              0), ^ {
  379                        socket_handoff(handoff_data);
  380                    });
  381 #else
  382     create_thread(socket_handoff_thread, handoff_data);
  383 #endif
  384 
  385 #ifdef DEBUG
  386     ErrorF(
  387         "X11.app: Thread created for handoff.  Returning success to tell caller to connect and push the fd.\n");
  388 #endif
  389 
  390     return KERN_SUCCESS;
  391 }
  392 
  393 kern_return_t
  394 do_request_pid(mach_port_t port, int *my_pid)
  395 {
  396     *my_pid = getpid();
  397     return KERN_SUCCESS;
  398 }
  399 
  400 /*** Server Startup ***/
  401 kern_return_t
  402 do_start_x11_server(mach_port_t port, string_array_t argv,
  403                     mach_msg_type_number_t argvCnt,
  404                     string_array_t envp,
  405                     mach_msg_type_number_t envpCnt)
  406 {
  407     /* And now back to char ** */
  408     char **_argv = alloca((argvCnt + 1) * sizeof(char *));
  409     char **_envp = alloca((envpCnt + 1) * sizeof(char *));
  410     size_t i;
  411 
  412     /* If we didn't get handed a launchd DISPLAY socket, we should
  413      * unset DISPLAY or we can run into problems with pbproxy
  414      */
  415     if (!launchd_socket_handed_off) {
  416         ErrorF("X11.app: No launchd socket handed off, unsetting DISPLAY\n");
  417         unsetenv("DISPLAY");
  418     }
  419 
  420     if (!_argv || !_envp) {
  421         return KERN_FAILURE;
  422     }
  423 
  424     ErrorF("X11.app: do_start_x11_server(): argc=%d\n", argvCnt);
  425     for (i = 0; i < argvCnt; i++) {
  426         _argv[i] = argv[i];
  427         ErrorF("\targv[%u] = %s\n", (unsigned)i, argv[i]);
  428     }
  429     _argv[argvCnt] = NULL;
  430 
  431     for (i = 0; i < envpCnt; i++) {
  432         _envp[i] = envp[i];
  433     }
  434     _envp[envpCnt] = NULL;
  435 
  436     if (server_main(argvCnt, _argv, _envp) == 0)
  437         return KERN_SUCCESS;
  438     else
  439         return KERN_FAILURE;
  440 }
  441 
  442 static int
  443 startup_trigger(int argc, char **argv, char **envp)
  444 {
  445     Display *display;
  446     const char *s;
  447 
  448     /* Take care of the case where we're called like a normal DDX */
  449     if (argc > 1 && argv[1][0] == ':') {
  450         size_t i;
  451         kern_return_t kr;
  452         mach_port_t mp;
  453         string_array_t newenvp;
  454         string_array_t newargv;
  455 
  456         /* We need to count envp */
  457         int envpc;
  458         for (envpc = 0; envp[envpc]; envpc++) ;
  459 
  460         /* We have fixed-size string lengths due to limitations in IPC,
  461          * so we need to copy our argv and envp.
  462          */
  463         newargv = (string_array_t)alloca(argc * sizeof(string_t));
  464         newenvp = (string_array_t)alloca(envpc * sizeof(string_t));
  465 
  466         if (!newargv || !newenvp) {
  467             ErrorF("Memory allocation failure\n");
  468             exit(EXIT_FAILURE);
  469         }
  470 
  471         for (i = 0; i < argc; i++) {
  472             strlcpy(newargv[i], argv[i], STRING_T_SIZE);
  473         }
  474         for (i = 0; i < envpc; i++) {
  475             strlcpy(newenvp[i], envp[i], STRING_T_SIZE);
  476         }
  477 
  478         kr = bootstrap_look_up(bootstrap_port, server_bootstrap_name, &mp);
  479         if (kr != KERN_SUCCESS) {
  480 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
  481             ErrorF("bootstrap_look_up(%s): %s\n", server_bootstrap_name,
  482                    bootstrap_strerror(
  483                        kr));
  484 #else
  485             ErrorF("bootstrap_look_up(%s): %ul\n", server_bootstrap_name,
  486                    (unsigned long)kr);
  487 #endif
  488             exit(EXIT_FAILURE);
  489         }
  490 
  491         kr = start_x11_server(mp, newargv, argc, newenvp, envpc);
  492         if (kr != KERN_SUCCESS) {
  493             ErrorF("start_x11_server: %s\n", mach_error_string(kr));
  494             exit(EXIT_FAILURE);
  495         }
  496         exit(EXIT_SUCCESS);
  497     }
  498 
  499     /* If we have a process serial number and it's our only arg, act as if
  500      * the user double clicked the app bundle: launch app_to_run if possible
  501      */
  502     if (argc == 1 || (argc == 2 && !strncmp(argv[1], "-psn_", 5))) {
  503         /* Now, try to open a display, if so, run the launcher */
  504         display = XOpenDisplay(NULL);
  505         if (display) {
  506             /* Could open the display, start the launcher */
  507             XCloseDisplay(display);
  508 
  509             return execute(pref_app_to_run);
  510         }
  511     }
  512 
  513     /* Start the server */
  514     if ((s = getenv("DISPLAY"))) {
  515         ErrorF(
  516             "X11.app: Could not connect to server (DISPLAY=\"%s\", unsetting).  Starting X server.\n",
  517             s);
  518         unsetenv("DISPLAY");
  519     }
  520     else {
  521         ErrorF(
  522             "X11.app: Could not connect to server (DISPLAY is not set).  Starting X server.\n");
  523     }
  524     return execute(pref_startx_script);
  525 }
  526 
  527 /** Setup the environment we want our child processes to inherit */
  528 static void
  529 ensure_path(const char *dir)
  530 {
  531     char buf[1024], *temp;
  532 
  533     /* Make sure /usr/X11/bin is in the $PATH */
  534     temp = getenv("PATH");
  535     if (temp == NULL || temp[0] == 0) {
  536         snprintf(buf, sizeof(buf),
  537                  "/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:%s",
  538                  dir);
  539         setenv("PATH", buf, TRUE);
  540     }
  541     else if (strnstr(temp, X11BINDIR, sizeof(temp)) == NULL) {
  542         snprintf(buf, sizeof(buf), "%s:%s", temp, dir);
  543         setenv("PATH", buf, TRUE);
  544     }
  545 }
  546 
  547 static void
  548 setup_console_redirect(const char *bundle_id)
  549 {
  550     char *asl_sender;
  551     char *asl_facility;
  552 
  553     asprintf(&asl_sender, "%s.server", bundle_id);
  554     assert(asl_sender);
  555 
  556     asl_facility = strdup(bundle_id);
  557     assert(asl_facility);
  558     if (strcmp(asl_facility + strlen(asl_facility) - 4, ".X11") == 0)
  559         asl_facility[strlen(asl_facility) - 4] = '\0';
  560 
  561     assert(aslc = asl_open(asl_sender, asl_facility, ASL_OPT_NO_DELAY));
  562     free(asl_sender);
  563     free(asl_facility);
  564 
  565     asl_set_filter(aslc, ASL_FILTER_MASK_UPTO(ASL_LEVEL_WARNING));
  566 
  567 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
  568 # if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
  569     if (asl_log_descriptor)
  570 # endif
  571     {
  572         asl_log_descriptor(aslc, NULL, ASL_LEVEL_INFO, STDOUT_FILENO, ASL_LOG_DESCRIPTOR_WRITE);
  573         asl_log_descriptor(aslc, NULL, ASL_LEVEL_NOTICE, STDERR_FILENO, ASL_LOG_DESCRIPTOR_WRITE);
  574     }
  575 # if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
  576     else {
  577         xq_asl_capture_fd(aslc, NULL, ASL_LEVEL_INFO, STDOUT_FILENO);
  578         xq_asl_capture_fd(aslc, NULL, ASL_LEVEL_NOTICE, STDERR_FILENO);
  579     }
  580 # endif
  581 #else
  582     xq_asl_capture_fd(aslc, NULL, ASL_LEVEL_INFO, STDOUT_FILENO);
  583     xq_asl_capture_fd(aslc, NULL, ASL_LEVEL_NOTICE, STDERR_FILENO);
  584 #endif
  585 }
  586 
  587 static void
  588 setup_env(void)
  589 {
  590     char *temp;
  591     const char *pds = NULL;
  592     const char *disp = getenv("DISPLAY");
  593     size_t len;
  594 
  595     /* Pass on our prefs domain to startx and its inheritors (mainly for
  596      * quartz-wm and the Xquartz stub's MachIPC)
  597      */
  598     CFBundleRef bundle = CFBundleGetMainBundle();
  599     if (bundle) {
  600         CFStringRef pd = CFBundleGetIdentifier(bundle);
  601         if (pd) {
  602             pds = CFStringGetCStringPtr(pd, 0);
  603         }
  604     }
  605 
  606     /* fallback to hardcoded value if we can't discover it */
  607     if (!pds) {
  608         pds = BUNDLE_ID_PREFIX ".X11";
  609     }
  610 
  611     setup_console_redirect(pds);
  612 
  613     server_bootstrap_name = strdup(pds);
  614     if (!server_bootstrap_name) {
  615         ErrorF("X11.app: Memory allocation error.\n");
  616         exit(1);
  617     }
  618     setenv("X11_PREFS_DOMAIN", server_bootstrap_name, 1);
  619 
  620     len = strlen(server_bootstrap_name);
  621     bundle_id_prefix = malloc(sizeof(char) * (len - 3));
  622     if (!bundle_id_prefix) {
  623         ErrorF("X11.app: Memory allocation error.\n");
  624         exit(1);
  625     }
  626     strlcpy(bundle_id_prefix, server_bootstrap_name, len - 3);
  627 
  628     /* We need to unset DISPLAY if it is not our socket */
  629     if (disp) {
  630         /* s = basename(disp) */
  631         const char *d, *s;
  632         for (s = NULL, d = disp; *d; d++) {
  633             if (*d == '/')
  634                 s = d + 1;
  635         }
  636 
  637         if (s && *s) {
  638             if (strcmp(bundle_id_prefix,
  639                        "org.x") == 0 && strcmp(s, ":0") == 0) {
  640                 ErrorF(
  641                     "X11.app: Detected old style launchd DISPLAY, please update xinit.\n");
  642             }
  643             else {
  644                 temp = (char *)malloc(sizeof(char) * len);
  645                 if (!temp) {
  646                     ErrorF(
  647                         "X11.app: Memory allocation error creating space for socket name test.\n");
  648                     exit(1);
  649                 }
  650                 strlcpy(temp, bundle_id_prefix, len);
  651                 strlcat(temp, ":0", len);
  652 
  653                 if (strcmp(temp, s) != 0) {
  654                     /* If we don't have a match, unset it. */
  655                     ErrorF(
  656                         "X11.app: DISPLAY (\"%s\") does not match our id (\"%s\"), unsetting.\n",
  657                         disp, bundle_id_prefix);
  658                     unsetenv("DISPLAY");
  659                 }
  660                 free(temp);
  661             }
  662         }
  663         else {
  664             /* The DISPLAY environment variable is not formatted like a launchd socket, so reset. */
  665             ErrorF(
  666                 "X11.app: DISPLAY does not look like a launchd set variable, unsetting.\n");
  667             unsetenv("DISPLAY");
  668         }
  669     }
  670 
  671     /* Make sure PATH is right */
  672     ensure_path(X11BINDIR);
  673 
  674     /* cd $HOME */
  675     temp = getenv("HOME");
  676     if (temp != NULL && temp[0] != '\0')
  677         chdir(temp);
  678 }
  679 
  680 /*** Main ***/
  681 int
  682 main(int argc, char **argv, char **envp)
  683 {
  684     Bool listenOnly = FALSE;
  685     int i;
  686     mach_msg_size_t mxmsgsz = sizeof(union MaxMsgSize) + MAX_TRAILER_SIZE;
  687     mach_port_t mp;
  688     kern_return_t kr;
  689 
  690     /* Setup our environment for our children */
  691     setup_env();
  692 
  693     /* The server must not run the PanoramiX operations. */
  694     noPanoramiXExtension = TRUE;
  695 
  696     /* Setup the initial crasherporter info */
  697     strlcpy(__crashreporter_info_buff__, __crashreporter_info__base,
  698             sizeof(__crashreporter_info_buff__));
  699 
  700     ErrorF("X11.app: main(): argc=%d\n", argc);
  701     for (i = 0; i < argc; i++) {
  702         ErrorF("\targv[%u] = %s\n", (unsigned)i, argv[i]);
  703         if (!strcmp(argv[i], "--listenonly")) {
  704             listenOnly = TRUE;
  705         }
  706     }
  707 
  708     mp = checkin_or_register(server_bootstrap_name);
  709     if (mp == MACH_PORT_NULL) {
  710         ErrorF("NULL mach service: %s", server_bootstrap_name);
  711         return EXIT_FAILURE;
  712     }
  713 
  714     /* Check if we need to do something other than listen, and make another
  715      * thread handle it.
  716      */
  717     if (!listenOnly) {
  718         pid_t child1, child2;
  719         int status;
  720 
  721         pref_app_to_run = command_from_prefs("app_to_run", DEFAULT_CLIENT);
  722         assert(pref_app_to_run);
  723 
  724         pref_login_shell = command_from_prefs("login_shell", DEFAULT_SHELL);
  725         assert(pref_login_shell);
  726 
  727         pref_startx_script = command_from_prefs("startx_script",
  728                                                 DEFAULT_STARTX);
  729         assert(pref_startx_script);
  730 
  731         /* Do the fork-twice trick to avoid having to reap zombies */
  732         child1 = fork();
  733         switch (child1) {
  734         case -1:                                    /* error */
  735             FatalError("fork() failed: %s\n", strerror(errno));
  736 
  737         case 0:                                     /* child1 */
  738             child2 = fork();
  739 
  740             switch (child2) {
  741                 int max_files;
  742 
  743             case -1:                                    /* error */
  744                 FatalError("fork() failed: %s\n", strerror(errno));
  745 
  746             case 0:                                     /* child2 */
  747                 /* close all open files except for standard streams */
  748                 max_files = sysconf(_SC_OPEN_MAX);
  749                 for (i = 3; i < max_files; i++)
  750                     close(i);
  751 
  752                 /* ensure stdin is on /dev/null */
  753                 close(0);
  754                 open("/dev/null", O_RDONLY);
  755 
  756                 return startup_trigger(argc, argv, envp);
  757 
  758             default:                                    /* parent (child1) */
  759                 _exit(0);
  760             }
  761             break;
  762 
  763         default:                                    /* parent */
  764             waitpid(child1, &status, 0);
  765         }
  766 
  767         free(pref_app_to_run);
  768         free(pref_login_shell);
  769         free(pref_startx_script);
  770     }
  771 
  772     /* Main event loop */
  773     ErrorF("Waiting for startup parameters via Mach IPC.\n");
  774     kr = mach_msg_server(mach_startup_server, mxmsgsz, mp, 0);
  775     if (kr != KERN_SUCCESS) {
  776         ErrorF("%s.X11(mp): %s\n", BUNDLE_ID_PREFIX, mach_error_string(kr));
  777         return EXIT_FAILURE;
  778     }
  779 
  780     return EXIT_SUCCESS;
  781 }
  782 
  783 static int
  784 execute(const char *command)
  785 {
  786     const char *newargv[4];
  787     const char **p;
  788 
  789     newargv[0] = pref_login_shell;
  790     newargv[1] = "-c";
  791     newargv[2] = command;
  792     newargv[3] = NULL;
  793 
  794     ErrorF("X11.app: Launching %s:\n", command);
  795     for (p = newargv; *p; p++) {
  796         ErrorF("\targv[%ld] = %s\n", (long int)(p - newargv), *p);
  797     }
  798 
  799     execvp(newargv[0], (char *const *)newargv);
  800     perror("X11.app: Couldn't exec.");
  801     return 1;
  802 }
  803 
  804 static char *
  805 command_from_prefs(const char *key, const char *default_value)
  806 {
  807     char *command = NULL;
  808 
  809     CFStringRef cfKey;
  810     CFPropertyListRef PlistRef;
  811 
  812     if (!key)
  813         return NULL;
  814 
  815     cfKey = CFStringCreateWithCString(NULL, key, kCFStringEncodingASCII);
  816 
  817     if (!cfKey)
  818         return NULL;
  819 
  820     PlistRef = CFPreferencesCopyAppValue(cfKey,
  821                                          kCFPreferencesCurrentApplication);
  822 
  823     if ((PlistRef == NULL) ||
  824         (CFGetTypeID(PlistRef) != CFStringGetTypeID())) {
  825         CFStringRef cfDefaultValue = CFStringCreateWithCString(
  826             NULL, default_value, kCFStringEncodingASCII);
  827         int len = strlen(default_value) + 1;
  828 
  829         if (!cfDefaultValue)
  830             goto command_from_prefs_out;
  831 
  832         CFPreferencesSetAppValue(cfKey, cfDefaultValue,
  833                                  kCFPreferencesCurrentApplication);
  834         CFPreferencesAppSynchronize(kCFPreferencesCurrentApplication);
  835         CFRelease(cfDefaultValue);
  836 
  837         command = (char *)malloc(len * sizeof(char));
  838         if (!command)
  839             goto command_from_prefs_out;
  840         strcpy(command, default_value);
  841     }
  842     else {
  843         int len = CFStringGetLength((CFStringRef)PlistRef) + 1;
  844         command = (char *)malloc(len * sizeof(char));
  845         if (!command)
  846             goto command_from_prefs_out;
  847         CFStringGetCString((CFStringRef)PlistRef, command, len,
  848                            kCFStringEncodingASCII);
  849     }
  850 
  851 command_from_prefs_out:
  852     if (PlistRef)
  853         CFRelease(PlistRef);
  854     if (cfKey)
  855         CFRelease(cfKey);
  856     return command;
  857 }