File: | hw/xquartz/mach-startup/bundle-main.c |
Location: | line 464, column 35 |
Description: | Call to 'alloca' has an allocation size of 0 bytes |
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_H1 | |||||
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_LIBDISPATCH1 | |||||
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)__attribute__((__format__(__printf__,1,2))); | |||||
75 | extern void | |||||
76 | FatalError(const char *f, ...) _X_ATTRIBUTE_PRINTF(1, 2)__attribute__((__format__(__printf__,1,2))) _X_NORETURN__attribute((noreturn)); | |||||
77 | ||||||
78 | extern int noPanoramiXExtension; | |||||
79 | ||||||
80 | #define DEFAULT_CLIENT"/Users/jeremy/src/freedesktop/jhbuild/build/bin" "/xterm" X11BINDIR"/Users/jeremy/src/freedesktop/jhbuild/build/bin" "/xterm" | |||||
81 | #define DEFAULT_STARTX"/Users/jeremy/src/freedesktop/jhbuild/build/bin" "/startx -- " "/Users/jeremy/src/freedesktop/jhbuild/build/bin" "/Xquartz" X11BINDIR"/Users/jeremy/src/freedesktop/jhbuild/build/bin" "/startx -- " X11BINDIR"/Users/jeremy/src/freedesktop/jhbuild/build/bin" "/Xquartz" | |||||
82 | #define DEFAULT_SHELL"/bin/sh" "/bin/sh" | |||||
83 | ||||||
84 | #ifndef BUILD_DATE"20160529" | |||||
85 | #define BUILD_DATE"20160529" "" | |||||
86 | #endif | |||||
87 | #ifndef XSERVER_VERSION"1.17.4" | |||||
88 | #define XSERVER_VERSION"1.17.4" "?" | |||||
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_REQUIRED101100 >= 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"1.17.4" " Build Date: " BUILD_DATE"20160529"; | |||||
103 | ||||||
104 | char *bundle_id_prefix = NULL((void*)0); | |||||
105 | static char *server_bootstrap_name = NULL((void*)0); | |||||
106 | ||||||
107 | #define DEBUG1 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_LIBDISPATCH1 | |||||
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_SUCCESS0) | |||||
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_task_self_, MACH_PORT_RIGHT_RECEIVE((mach_port_right_t) 1), &mp); | |||||
160 | if (kr != KERN_SUCCESS0) { | |||||
161 | ErrorF("mach_port_allocate(): %s\n", mach_error_string(kr)); | |||||
162 | exit(EXIT_FAILURE1); | |||||
163 | } | |||||
164 | ||||||
165 | kr = mach_port_insert_right( | |||||
166 | mach_task_self()mach_task_self_, mp, mp, MACH_MSG_TYPE_MAKE_SEND20); | |||||
167 | if (kr != KERN_SUCCESS0) { | |||||
168 | ErrorF("mach_port_insert_right(): %s\n", mach_error_string(kr)); | |||||
169 | exit(EXIT_FAILURE1); | |||||
170 | } | |||||
171 | ||||||
172 | #ifdef __clang__1 | |||||
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__1 | |||||
178 | #pragma clang diagnostic pop | |||||
179 | #endif | |||||
180 | ||||||
181 | if (kr != KERN_SUCCESS0) { | |||||
182 | ErrorF("bootstrap_register(): %s\n", mach_error_string(kr)); | |||||
183 | exit(EXIT_FAILURE1); | |||||
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))(((__darwin_size_t)((char *)(__darwin_size_t)(sizeof(struct cmsghdr )) + (sizeof(__uint32_t) - 1)) &~ (sizeof(__uint32_t) - 1 )) + ((__darwin_size_t)((char *)(__darwin_size_t)(sizeof(int) ) + (sizeof(__uint32_t) - 1)) &~ (sizeof(__uint32_t) - 1) ))]; | |||||
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)((&msg)->msg_controllen >= sizeof(struct cmsghdr) ? (struct cmsghdr *)(&msg)->msg_control : (struct cmsghdr *)0L); | |||||
218 | cmsg->cmsg_level = SOL_SOCKET0xffff; | |||||
219 | cmsg->cmsg_type = SCM_RIGHTS0x01; | |||||
220 | cmsg->cmsg_len = CMSG_LEN(sizeof(int))(((__darwin_size_t)((char *)(__darwin_size_t)(sizeof(struct cmsghdr )) + (sizeof(__uint32_t) - 1)) &~ (sizeof(__uint32_t) - 1 )) + (sizeof(int))); | |||||
221 | ||||||
222 | msg.msg_controllen = cmsg->cmsg_len; | |||||
223 | ||||||
224 | *((int *)CMSG_DATA(cmsg)((unsigned char *)(cmsg) + ((__darwin_size_t)((char *)(__darwin_size_t )(sizeof(struct cmsghdr)) + (sizeof(__uint32_t) - 1)) &~ ( sizeof(__uint32_t) - 1)))) = -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(*__error()))); | |||||
230 | return -1; | |||||
231 | } | |||||
232 | ||||||
233 | launchd_fd = *((int *)CMSG_DATA(cmsg)((unsigned char *)(cmsg) + ((__darwin_size_t)((char *)(__darwin_size_t )(sizeof(struct cmsghdr)) + (sizeof(__uint32_t) - 1)) &~ ( sizeof(__uint32_t) - 1)))); | |||||
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_LIBDISPATCH1 | |||||
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((void*)0), NULL((void*)0)); | |||||
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(*__error()))); | |||||
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_LIBDISPATCH1 | |||||
291 | return NULL((void*)0); | |||||
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))__builtin___memset_chk (&servaddr_un, 0, sizeof(struct sockaddr_un ), __builtin_object_size (&servaddr_un, 0)); | |||||
309 | servaddr_un.sun_family = AF_UNIX1; | |||||
310 | strlcpy(servaddr_un.sun_path, filename_out,__builtin___strlcpy_chk (servaddr_un.sun_path, filename_out, sizeof (servaddr_un.sun_path), __builtin_object_size (servaddr_un.sun_path , 2 > 1 ? 1 : 0)) | |||||
311 | sizeof(servaddr_un.sun_path))__builtin___strlcpy_chk (servaddr_un.sun_path, filename_out, sizeof (servaddr_un.sun_path), __builtin_object_size (servaddr_un.sun_path , 2 > 1 ? 1 : 0)); | |||||
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_UNIX1, SOCK_STREAM1, 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(*__error()))); | |||||
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(*__error()), | |||||
327 | strerror( | |||||
328 | errno(*__error()))); | |||||
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(*__error()), strerror( | |||||
336 | errno(*__error()))); | |||||
337 | close(ret_fd); | |||||
338 | return 0; | |||||
339 | } | |||||
340 | ||||||
341 | #ifdef DEBUG1 | |||||
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_FAILURE5; | |||||
366 | } | |||||
367 | ||||||
368 | handoff_data->fd = create_socket(handoff_data->filename); | |||||
369 | if (!handoff_data->fd) { | |||||
370 | free(handoff_data); | |||||
371 | return KERN_FAILURE5; | |||||
372 | } | |||||
373 | ||||||
374 | strlcpy(filename, handoff_data->filename, STRING_T_SIZE)__builtin___strlcpy_chk (filename, handoff_data->filename, 1024, __builtin_object_size (filename, 2 > 1 ? 1 : 0)); | |||||
375 | ||||||
376 | #ifdef HAVE_LIBDISPATCH1 | |||||
377 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT0, | |||||
378 | 0), ^ { | |||||
379 | socket_handoff(handoff_data); | |||||
380 | }); | |||||
381 | #else | |||||
382 | create_thread(socket_handoff_thread, handoff_data); | |||||
383 | #endif | |||||
384 | ||||||
385 | #ifdef DEBUG1 | |||||
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_SUCCESS0; | |||||
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_SUCCESS0; | |||||
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 *))__builtin_alloca((argvCnt + 1) * sizeof(char *)); | |||||
409 | char **_envp = alloca((envpCnt + 1) * sizeof(char *))__builtin_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_FAILURE5; | |||||
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((void*)0); | |||||
430 | ||||||
431 | for (i = 0; i < envpCnt; i++) { | |||||
432 | _envp[i] = envp[i]; | |||||
433 | } | |||||
434 | _envp[envpCnt] = NULL((void*)0); | |||||
435 | ||||||
436 | if (server_main(argvCnt, _argv, _envp) == 0) | |||||
437 | return KERN_SUCCESS0; | |||||
438 | else | |||||
439 | return KERN_FAILURE5; | |||||
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))__builtin_alloca(argc * sizeof(string_t)); | |||||
464 | newenvp = (string_array_t)alloca(envpc * sizeof(string_t))__builtin_alloca(envpc * sizeof(string_t)); | |||||
| ||||||
465 | ||||||
466 | if (!newargv || !newenvp) { | |||||
467 | ErrorF("Memory allocation failure\n"); | |||||
468 | exit(EXIT_FAILURE1); | |||||
469 | } | |||||
470 | ||||||
471 | for (i = 0; i < argc; i++) { | |||||
472 | strlcpy(newargv[i], argv[i], STRING_T_SIZE)__builtin___strlcpy_chk (newargv[i], argv[i], 1024, __builtin_object_size (newargv[i], 2 > 1 ? 1 : 0)); | |||||
473 | } | |||||
474 | for (i = 0; i < envpc; i++) { | |||||
475 | strlcpy(newenvp[i], envp[i], STRING_T_SIZE)__builtin___strlcpy_chk (newenvp[i], envp[i], 1024, __builtin_object_size (newenvp[i], 2 > 1 ? 1 : 0)); | |||||
476 | } | |||||
477 | ||||||
478 | kr = bootstrap_look_up(bootstrap_port, server_bootstrap_name, &mp); | |||||
479 | if (kr != KERN_SUCCESS0) { | |||||
480 | #if MAC_OS_X_VERSION_MIN_REQUIRED101100 >= 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_FAILURE1); | |||||
489 | } | |||||
490 | ||||||
491 | kr = start_x11_server(mp, newargv, argc, newenvp, envpc); | |||||
492 | if (kr != KERN_SUCCESS0) { | |||||
493 | ErrorF("start_x11_server: %s\n", mach_error_string(kr)); | |||||
494 | exit(EXIT_FAILURE1); | |||||
495 | } | |||||
496 | exit(EXIT_SUCCESS0); | |||||
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((void*)0)); | |||||
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((void*)0) || temp[0] == 0) { | |||||
536 | snprintf(buf, sizeof(buf),__builtin___snprintf_chk (buf, sizeof(buf), 0, __builtin_object_size (buf, 2 > 1 ? 1 : 0), "/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:%s" , dir) | |||||
537 | "/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:%s",__builtin___snprintf_chk (buf, sizeof(buf), 0, __builtin_object_size (buf, 2 > 1 ? 1 : 0), "/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:%s" , dir) | |||||
538 | dir)__builtin___snprintf_chk (buf, sizeof(buf), 0, __builtin_object_size (buf, 2 > 1 ? 1 : 0), "/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:%s" , dir); | |||||
539 | setenv("PATH", buf, TRUE1); | |||||
540 | } | |||||
541 | else if (strnstr(temp, X11BINDIR"/Users/jeremy/src/freedesktop/jhbuild/build/bin", sizeof(temp)) == NULL((void*)0)) { | |||||
542 | snprintf(buf, sizeof(buf), "%s:%s", temp, dir)__builtin___snprintf_chk (buf, sizeof(buf), 0, __builtin_object_size (buf, 2 > 1 ? 1 : 0), "%s:%s", temp, dir); | |||||
543 | setenv("PATH", buf, TRUE1); | |||||
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)(__builtin_expect(!(asl_sender), 0) ? __assert_rtn(__func__, "bundle-main.c" , 554, "asl_sender") : (void)0); | |||||
555 | ||||||
556 | asl_facility = strdup(bundle_id); | |||||
557 | assert(asl_facility)(__builtin_expect(!(asl_facility), 0) ? __assert_rtn(__func__ , "bundle-main.c", 557, "asl_facility") : (void)0); | |||||
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))(__builtin_expect(!(aslc = asl_open(asl_sender, asl_facility, 0x00000002)), 0) ? __assert_rtn(__func__, "bundle-main.c", 561 , "aslc = asl_open(asl_sender, asl_facility, ASL_OPT_NO_DELAY)" ) : (void)0); | |||||
562 | free(asl_sender); | |||||
563 | free(asl_facility); | |||||
564 | ||||||
565 | asl_set_filter(aslc, ASL_FILTER_MASK_UPTO(ASL_LEVEL_WARNING)((1 << ((4) + 1)) - 1)); | |||||
566 | ||||||
567 | #if MAC_OS_X_VERSION_MAX_ALLOWED101102 >= 1080 | |||||
568 | # if MAC_OS_X_VERSION_MIN_REQUIRED101100 < 1080 | |||||
569 | if (asl_log_descriptor) | |||||
570 | # endif | |||||
571 | { | |||||
572 | asl_log_descriptor(aslc, NULL((void*)0), ASL_LEVEL_INFO6, STDOUT_FILENO1, ASL_LOG_DESCRIPTOR_WRITE2); | |||||
573 | asl_log_descriptor(aslc, NULL((void*)0), ASL_LEVEL_NOTICE5, STDERR_FILENO2, ASL_LOG_DESCRIPTOR_WRITE2); | |||||
574 | } | |||||
575 | # if MAC_OS_X_VERSION_MIN_REQUIRED101100 < 1080 | |||||
576 | else { | |||||
577 | xq_asl_capture_fd(aslc, NULL((void*)0), ASL_LEVEL_INFO6, STDOUT_FILENO1); | |||||
578 | xq_asl_capture_fd(aslc, NULL((void*)0), ASL_LEVEL_NOTICE5, STDERR_FILENO2); | |||||
579 | } | |||||
580 | # endif | |||||
581 | #else | |||||
582 | xq_asl_capture_fd(aslc, NULL((void*)0), ASL_LEVEL_INFO6, STDOUT_FILENO1); | |||||
583 | xq_asl_capture_fd(aslc, NULL((void*)0), ASL_LEVEL_NOTICE5, STDERR_FILENO2); | |||||
584 | #endif | |||||
585 | } | |||||
586 | ||||||
587 | static void | |||||
588 | setup_env(void) | |||||
589 | { | |||||
590 | char *temp; | |||||
591 | const char *pds = NULL((void*)0); | |||||
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"org.x" ".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)__builtin___strlcpy_chk (bundle_id_prefix, server_bootstrap_name , len - 3, __builtin_object_size (bundle_id_prefix, 2 > 1 ? 1 : 0)); | |||||
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((void*)0), 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)__builtin___strlcpy_chk (temp, bundle_id_prefix, len, __builtin_object_size (temp, 2 > 1 ? 1 : 0)); | |||||
651 | strlcat(temp, ":0", len)__builtin___strlcat_chk (temp, ":0", len, __builtin_object_size (temp, 2 > 1 ? 1 : 0)); | |||||
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"/Users/jeremy/src/freedesktop/jhbuild/build/bin"); | |||||
673 | ||||||
674 | /* cd $HOME */ | |||||
675 | temp = getenv("HOME"); | |||||
676 | if (temp != NULL((void*)0) && temp[0] != '\0') | |||||
677 | chdir(temp); | |||||
678 | } | |||||
679 | ||||||
680 | /*** Main ***/ | |||||
681 | int | |||||
682 | main(int argc, char **argv, char **envp) | |||||
683 | { | |||||
684 | Boolint listenOnly = FALSE0; | |||||
685 | int i; | |||||
686 | mach_msg_size_t mxmsgsz = sizeof(union MaxMsgSize) + MAX_TRAILER_SIZE((mach_msg_size_t)sizeof(mach_msg_max_trailer_t)); | |||||
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 = TRUE1; | |||||
695 | ||||||
696 | /* Setup the initial crasherporter info */ | |||||
697 | strlcpy(__crashreporter_info_buff__, __crashreporter_info__base,__builtin___strlcpy_chk (__crashreporter_info_buff__, __crashreporter_info__base , sizeof(__crashreporter_info_buff__), __builtin_object_size ( __crashreporter_info_buff__, 2 > 1 ? 1 : 0)) | |||||
698 | sizeof(__crashreporter_info_buff__))__builtin___strlcpy_chk (__crashreporter_info_buff__, __crashreporter_info__base , sizeof(__crashreporter_info_buff__), __builtin_object_size ( __crashreporter_info_buff__, 2 > 1 ? 1 : 0)); | |||||
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 = TRUE1; | |||||
705 | } | |||||
706 | } | |||||
707 | ||||||
708 | mp = checkin_or_register(server_bootstrap_name); | |||||
709 | if (mp == MACH_PORT_NULL0) { | |||||
710 | ErrorF("NULL mach service: %s", server_bootstrap_name); | |||||
711 | return EXIT_FAILURE1; | |||||
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"/Users/jeremy/src/freedesktop/jhbuild/build/bin" "/xterm"); | |||||
722 | assert(pref_app_to_run)(__builtin_expect(!(pref_app_to_run), 0) ? __assert_rtn(__func__ , "bundle-main.c", 722, "pref_app_to_run") : (void)0); | |||||
723 | ||||||
724 | pref_login_shell = command_from_prefs("login_shell", DEFAULT_SHELL"/bin/sh"); | |||||
725 | assert(pref_login_shell)(__builtin_expect(!(pref_login_shell), 0) ? __assert_rtn(__func__ , "bundle-main.c", 725, "pref_login_shell") : (void)0); | |||||
726 | ||||||
727 | pref_startx_script = command_from_prefs("startx_script", | |||||
728 | DEFAULT_STARTX"/Users/jeremy/src/freedesktop/jhbuild/build/bin" "/startx -- " "/Users/jeremy/src/freedesktop/jhbuild/build/bin" "/Xquartz"); | |||||
729 | assert(pref_startx_script)(__builtin_expect(!(pref_startx_script), 0) ? __assert_rtn(__func__ , "bundle-main.c", 729, "pref_startx_script") : (void)0); | |||||
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(*__error()))); | |||||
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(*__error()))); | |||||
745 | ||||||
746 | case 0: /* child2 */ | |||||
747 | /* close all open files except for standard streams */ | |||||
748 | max_files = sysconf(_SC_OPEN_MAX5); | |||||
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_RDONLY0x0000); | |||||
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_SUCCESS0) { | |||||
776 | ErrorF("%s.X11(mp): %s\n", BUNDLE_ID_PREFIX"org.x", mach_error_string(kr)); | |||||
777 | return EXIT_FAILURE1; | |||||
778 | } | |||||
779 | ||||||
780 | return EXIT_SUCCESS0; | |||||
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((void*)0); | |||||
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((void*)0); | |||||
808 | ||||||
809 | CFStringRef cfKey; | |||||
810 | CFPropertyListRef PlistRef; | |||||
811 | ||||||
812 | if (!key) | |||||
813 | return NULL((void*)0); | |||||
814 | ||||||
815 | cfKey = CFStringCreateWithCString(NULL((void*)0), key, kCFStringEncodingASCII); | |||||
816 | ||||||
817 | if (!cfKey) | |||||
818 | return NULL((void*)0); | |||||
819 | ||||||
820 | PlistRef = CFPreferencesCopyAppValue(cfKey, | |||||
821 | kCFPreferencesCurrentApplication); | |||||
822 | ||||||
823 | if ((PlistRef == NULL((void*)0)) || | |||||
824 | (CFGetTypeID(PlistRef) != CFStringGetTypeID())) { | |||||
825 | CFStringRef cfDefaultValue = CFStringCreateWithCString( | |||||
826 | NULL((void*)0), 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)__builtin___strcpy_chk (command, default_value, __builtin_object_size (command, 2 > 1 ? 1 : 0)); | |||||
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 | } |