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