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