Merge remote-tracking branch 'jeremyhu/master'

This commit is contained in:
Keith Packard 2011-05-13 13:54:29 -07:00
commit 6347a0b802
16 changed files with 668 additions and 93 deletions

View File

@ -566,8 +566,7 @@ AC_ARG_WITH(launchd-id-prefix, AS_HELP_STRING([--with-launchd-id-prefix=PATH],
[ BUNDLE_ID_PREFIX="${withval}" ],
[ BUNDLE_ID_PREFIX="org.x" ])
AC_ARG_WITH(bundle-id-prefix, AS_HELP_STRING([--with-bundle-id-prefix=PATH], [Prefix to use for bundle identifiers (default: org.x)]),
[ BUNDLE_ID_PREFIX="${withval}" ],
[ BUNDLE_ID_PREFIX="org.x" ])
[ BUNDLE_ID_PREFIX="${withval}" ])
AC_SUBST([BUNDLE_ID_PREFIX])
AC_DEFINE_UNQUOTED(BUNDLE_ID_PREFIX, "$BUNDLE_ID_PREFIX", [Prefix to use for bundle identifiers])
AC_ARG_ENABLE(sparkle,AS_HELP_STRING([--enable-sparkle], [Enable updating of X11.app using the Sparkle Framework (default: disabled)]),

View File

@ -33,7 +33,8 @@ libXquartz_la_SOURCES = \
quartzCocoa.m \
quartzKeyboard.c \
quartzStartup.c \
quartzRandR.c
quartzRandR.c \
console_redirect.c
EXTRA_DIST = \
X11Application.h \
@ -49,4 +50,5 @@ EXTRA_DIST = \
quartzKeyboard.h \
quartzRandR.h \
sanitizedCarbon.h \
sanitizedCocoa.h
sanitizedCocoa.h \
console_redirect.h

View File

@ -43,11 +43,12 @@
- (void) set_controller:controller;
- (void) set_window_menu:(NSArray *)list;
- (CFPropertyListRef) prefs_get_copy:(NSString *)key CF_RETURNS_RETAINED;
- (int) prefs_get_integer:(NSString *)key default:(int)def;
- (const char *) prefs_get_string:(NSString *)key default:(const char *)def;
- (float) prefs_get_float:(NSString *)key default:(float)def;
- (int) prefs_get_boolean:(NSString *)key default:(int)def;
- (NSURL *) prefs_copy_url:(NSString *)key default:(NSURL *)def;
- (NSURL *) prefs_copy_url:(NSString *)key default:(NSURL *)def NS_RETURNS_RETAINED;
- (NSArray *) prefs_get_array:(NSString *)key;
- (void) prefs_set_integer:(NSString *)key value:(int)value;
- (void) prefs_set_float:(NSString *)key value:(float)value;

View File

@ -35,9 +35,9 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#include <Xplugin.h>
#if XPLUGIN_VERSION < 4
typedef xp_frame_attr int;
typedef xp_frame_class int;
typedef xp_frame_rect int;
typedef int xp_frame_attr;
typedef int xp_frame_class;
typedef int xp_frame_rect;
#endif
typedef int (*DisableUpdateProc)(void);

View File

@ -0,0 +1,418 @@
/* Copyright (c) 2011 Apple Inc.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT
* HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* Except as contained in this notice, the name(s) of the above
* copyright holders shall not be used in advertising or otherwise to
* promote the sale, use or other dealings in this Software without
* prior written authorization.
*/
#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#else
#define DEBUG_CONSOLE_REDIRECT 1
#define HAVE_LIBDISPATCH 1
#endif
#include <assert.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/event.h>
#include <asl.h>
#include <errno.h>
#include <fcntl.h>
#include "console_redirect.h"
#define BUF_SIZE 512
#ifdef HAVE_LIBDISPATCH
#include <dispatch/dispatch.h>
static dispatch_queue_t redirect_serial_q;
static dispatch_group_t read_source_group;
#else
#include <pthread.h>
static pthread_t redirect_pthread;
static pthread_mutex_t redirect_fds_lock = PTHREAD_MUTEX_INITIALIZER;
static int kq;
/* Notifications to our reader thread */
#define ASL_REDIRECT_TERMINATE ((void *)(uintptr_t)1)
#endif
typedef struct {
int level;
aslclient asl;
aslmsg msg;
/* Buffered reading */
char *buf;
char *w;
#ifdef HAVE_LIBDISPATCH
dispatch_source_t read_source;
#endif
} asl_redirect;
static asl_redirect *redirect_fds = NULL;
static int n_redirect_fds = 0;
/* Read from the FD until there is no more to read and redirect to ASL.
* Preconditions:
* 1: pthread_mutex_lock lock is held (pthreads) or called
* from the appropriate serial queue for operating on
* redirect_fds
* 2: fd corresponds to a valid entry in redirect_fds
*
* Return values:
* If the pipe is closed, EOF is returned regardless of how many bytes
* were processed. If the pipe is still open, the number of read bytes
* is returned.
*/
static inline int _read_redirect(int fd, int flush) {
int total_read = 0;
int nbytes;
asl_redirect *aslr = &redirect_fds[fd];
while((nbytes = read(fd, aslr->w, BUF_SIZE - (aslr->w - aslr->buf) - 1)) > 0) {
char *s, *p;
/* Increment our returned number read */
total_read += nbytes;
nbytes += (aslr->w - aslr->buf);
aslr->buf[nbytes] = '\0';
/* One line at a time */
for(p=aslr->buf; *p && (p - aslr->buf) < nbytes; p = s + 1) {
// Find null or \n
for(s=p; *s && *s != '\n'; s++);
if(*s == '\n') {
*s='\0';
asl_log(aslr->asl, aslr->msg, aslr->level, "%s", p);
} else if(aslr->buf != p) {
memmove(aslr->buf, p, BUF_SIZE);
aslr->w = aslr->buf + (s - p);
break;
} else if(nbytes == BUF_SIZE - 1) {
asl_log(aslr->asl, aslr->msg, aslr->level, "%s", p);
aslr->w = aslr->buf;
break;
}
}
}
/* Flush if requested or we're at EOF */
if(flush || nbytes == 0) {
if(aslr->w > aslr->buf) {
*aslr->w = '\0';
asl_log(aslr->asl, aslr->msg, aslr->level, "%s", aslr->buf);
}
}
if(nbytes == 0)
return EOF;
return total_read;
}
#ifdef HAVE_LIBDISPATCH
static void read_from_source(void *_source) {
dispatch_source_t source = (dispatch_source_t)_source;
int fd = dispatch_source_get_handle(source);
if(_read_redirect(fd, 0) == EOF) {
dispatch_source_cancel(source);
}
}
static void cancel_source(void *_source) {
dispatch_source_t source = (dispatch_source_t)_source;
int fd = dispatch_source_get_handle(source);
asl_redirect *aslr = &redirect_fds[fd];
/* Flush the buffer */
_read_redirect(fd, 1);
close(fd);
free(aslr->buf);
memset(aslr, 0, sizeof(*aslr));
dispatch_release(source);
dispatch_group_leave(read_source_group);
}
#else /* !HAVE_LIBDISPATCH */
static void *redirect_thread(void *ctx __unused) {
struct kevent ev;
int n;
while(1) {
n = kevent(kq, NULL, 0, &ev, 1, NULL);
/* Bail on errors */
if(n < 0) {
asl_log(NULL, NULL, ASL_LEVEL_ERR, "kevent failure: %s", strerror(errno));
break;
}
/* This should not happen */
if(n == 0)
continue;
switch(ev.filter) {
case EVFILT_READ:
pthread_mutex_lock(&redirect_fds_lock);
{
int fd = ev.ident;
int close_fd = 0;
asl_redirect *aslr = &redirect_fds[fd];
if(fd < 0 || fd >= n_redirect_fds || aslr->buf == NULL) {
asl_log(NULL, NULL, ASL_LEVEL_ERR, "Unexpected file descriptor: %d", fd);
goto next;
}
if(ev.flags & EV_EOF) {
close_fd = 1;
if(EOF != _read_redirect(fd, 1)) {
asl_log(NULL, NULL, ASL_LEVEL_ERR, "kevent reported EOF on %d, but read doesn't concur.", fd);
}
} else {
close_fd = (EOF == _read_redirect(fd, 0));
}
if(close_fd) {
EV_SET(&ev, fd, EVFILT_READ, EV_DELETE, 0, 0, 0);
kevent(kq, &ev, 1, NULL, 0, NULL);
close(fd);
free(aslr->buf);
memset(aslr, 0, sizeof(*aslr));
}
}
next:
pthread_mutex_unlock(&redirect_fds_lock);
case EVFILT_TIMER:
if(ev.udata == ASL_REDIRECT_TERMINATE)
return NULL;
default:
;;
}
}
return NULL;
}
#endif
static void redirect_atexit(void) {
/* stdout is linebuffered, so flush the buffer */
if(redirect_fds[STDOUT_FILENO].buf)
fflush(stdout);
#ifdef HAVE_LIBDISPATCH
{
int i;
/* Cancel all of our dispatch sources, so they flush to ASL */
for(i=0; i < n_redirect_fds; i++)
if(redirect_fds[i].read_source)
dispatch_source_cancel(redirect_fds[i].read_source);
/* Wait at least three seconds for our sources to flush to ASL */
dispatch_group_wait(read_source_group, dispatch_time(DISPATCH_TIME_NOW, 3LL * NSEC_PER_SEC));
}
#else
{
struct kevent ev;
/* Tell our reader thread it is time to pack up and go home */
EV_SET(&ev, 0, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 0, 0, ASL_REDIRECT_TERMINATE);
kevent(kq, &ev, 1, NULL, 0, NULL);
pthread_join(redirect_pthread, NULL);
}
#endif
}
#ifdef HAVE_LIBDISPATCH
static void xq_asl_init(void *ctx __unused)
#else
static void xq_asl_init(void)
#endif
{
assert((redirect_fds = calloc(16, sizeof(*redirect_fds))) != NULL);
n_redirect_fds = 16;
#ifdef HAVE_LIBDISPATCH
redirect_serial_q = dispatch_queue_create("com.apple.asl-redirect", NULL);
assert(redirect_serial_q != NULL);
read_source_group = dispatch_group_create();
assert(read_source_group != NULL);
#else
assert((kq = kqueue()) != -1);
assert(pthread_create(&redirect_pthread, NULL, redirect_thread, NULL) == 0);
#endif
atexit(redirect_atexit);
}
int xq_asl_log_fd(aslclient asl, aslmsg msg, int level, int fd) {
#ifdef HAVE_LIBDISPATCH
int err __block = 0;
static dispatch_once_t once_control;
dispatch_once_f(&once_control, NULL, xq_asl_init);
#else
int err = 0;
static pthread_once_t once_control = PTHREAD_ONCE_INIT;
assert(pthread_once(&once_control, xq_asl_init) == 0);
#endif
if(fd < 0)
return EBADF;
#ifdef HAVE_LIBDISPATCH
#define BLOCK_DONE return
dispatch_sync(redirect_serial_q, ^
#else
#define BLOCK_DONE goto done
assert(pthread_mutex_lock(&redirect_fds_lock) == 0);
#endif
{
/* Reallocate if we need more space */
if(fd >= n_redirect_fds) {
size_t new_n = 1 << (ffs(fd) + 1);
asl_redirect *new_array = realloc(redirect_fds, new_n * sizeof(*redirect_fds));
if(!new_array) {
err = errno;
BLOCK_DONE;
}
redirect_fds = new_array;
memset(redirect_fds + n_redirect_fds, 0, new_n - n_redirect_fds);
n_redirect_fds = new_n;
}
/* If we're already listening on it, return error. */
if(redirect_fds[fd].buf != NULL) {
err = EBADF;
BLOCK_DONE;
}
/* Initialize our buffer */
redirect_fds[fd].buf = (char *)malloc(BUF_SIZE);
if(redirect_fds[fd].buf == NULL) {
err = errno;
BLOCK_DONE;
}
redirect_fds[fd].w = redirect_fds[fd].buf;
/* Store our ASL settings */
redirect_fds[fd].level = level;
redirect_fds[fd].asl = asl;
redirect_fds[fd].msg = msg;
/* Don't block on reads from this fd */
fcntl(fd, F_SETFL, O_NONBLOCK);
/* Start listening */
#ifdef HAVE_LIBDISPATCH
{
dispatch_source_t read_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, fd, 0, redirect_serial_q);
redirect_fds[fd].read_source = read_source;
dispatch_set_context(read_source, read_source);
dispatch_source_set_event_handler_f(read_source, read_from_source);
dispatch_source_set_cancel_handler_f(read_source, cancel_source);
dispatch_group_enter(read_source_group);
dispatch_resume(read_source);
}
#else
{
struct kevent ev;
EV_SET(&ev, fd, EVFILT_READ, EV_ADD, 0, 0, 0);
kevent(kq, &ev, 1, NULL, 0, NULL);
}
#endif
}
#ifdef HAVE_LIBDISPATCH
);
#else
done:
assert(pthread_mutex_unlock(&redirect_fds_lock) == 0);
#endif
#undef BLOCK_DONE
return err;
}
int xq_asl_capture_fd(aslclient asl, aslmsg msg, int level, int fd) {
int pipepair[2];
/* Create pipe */
if(pipe(pipepair) == -1)
return errno;
/* Close the read fd but not the write fd on exec */
if(fcntl(pipepair[0], F_SETFD, FD_CLOEXEC) == -1)
return errno;
/* Replace the existing fd */
if(dup2(pipepair[1], fd) == -1) {
close(pipepair[0]);
close(pipepair[1]);
return errno;
}
/* If we capture STDOUT_FILENO, make sure we linebuffer stdout */
if(fd == STDOUT_FILENO)
setlinebuf(stdout);
/* Close the duplicate fds since they've been reassigned */
close(pipepair[1]);
/* Hand off the read end of our pipe to xq_asl_log_fd */
return xq_asl_log_fd(asl, msg, level, pipepair[0]);
}
#ifdef DEBUG_CONSOLE_REDIRECT
int main(int argc __unused, char **argv __unused) {
xq_asl_capture_fd(NULL, NULL, ASL_LEVEL_NOTICE, STDOUT_FILENO);
xq_asl_capture_fd(NULL, NULL, ASL_LEVEL_ERR, STDERR_FILENO);
fprintf(stderr, "TEST ERR1\n");
fprintf(stdout, "TEST OUT1\n");
fprintf(stderr, "TEST ERR2\n");
fprintf(stdout, "TEST OUT2\n");
system("/bin/echo SYST OUT");
system("/bin/echo SYST ERR >&2");
fprintf(stdout, "TEST OUT3\n");
fprintf(stdout, "TEST OUT4\n");
fprintf(stderr, "TEST ERR3\n");
fprintf(stderr, "TEST ERR4\n");
exit(0);
}
#endif

View File

@ -0,0 +1,44 @@
/* Copyright (c) 2011 Apple Inc.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT
* HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* Except as contained in this notice, the name(s) of the above
* copyright holders shall not be used in advertising or otherwise to
* promote the sale, use or other dealings in this Software without
* prior written authorization.
*/
#ifndef _XQUARTZ_CONSOLE_REDIRECT_H_
#define _XQUARTZ_CONSOLE_REDIRECT_H_
#include <asl.h>
/* The given fd is replaced with a pipe. Anything written to it will will be
* logged to ASL.
*/
int xq_asl_capture_fd(aslclient asl, aslmsg msg, int level, int fd);
/* The given fd is read from and passed along to ASL until all write ends of the
* pipe are closed. Once the last writer has closed the pipe, we close our end.
*/
int xq_asl_log_fd(aslclient asl, aslmsg msg, int level, int fd);
#endif

View File

@ -1,4 +1,5 @@
AM_CPPFLAGS = \
-I$(srcdir)/.. \
-DBUILD_DATE=\"$(BUILD_DATE)\" \
-DXSERVER_VERSION=\"$(VERSION)\" \
-DX11BINDIR=\"$(bindir)\"

View File

@ -36,6 +36,7 @@
#endif
#include <X11/Xlib.h>
#include <assert.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
@ -60,12 +61,14 @@
#include "mach_startup.h"
#include "mach_startupServer.h"
#include "launchd_fd.h"
#include "console_redirect.h"
/* From darwinEvents.c ... but don't want to pull in all the server cruft */
void DarwinListenOnOpenFD(int fd);
/* Ditto, from os/log.c */
extern void ErrorF(const char *f, ...) _X_ATTRIBUTE_PRINTF(1,2);
extern void FatalError(const char *f, ...) _X_ATTRIBUTE_PRINTF(1,2) _X_NORETURN;
extern int noPanoramiXExtension;
@ -102,6 +105,10 @@ int server_main(int argc, char **argv, char **envp);
static int execute(const char *command);
static char *command_from_prefs(const char *key, const char *default_value);
static char *pref_app_to_run;
static char *pref_login_shell;
static char *pref_startx_script;
#ifndef HAVE_LIBDISPATCH
/*** Pthread Magics ***/
static pthread_t create_thread(void *(*func)(void *), void *arg) {
@ -446,7 +453,7 @@ static int startup_trigger(int argc, char **argv, char **envp) {
/* Could open the display, start the launcher */
XCloseDisplay(display);
return execute(command_from_prefs("app_to_run", DEFAULT_CLIENT));
return execute(pref_app_to_run);
}
}
@ -457,7 +464,7 @@ static int startup_trigger(int argc, char **argv, char **envp) {
} else {
ErrorF("X11.app: Could not connect to server (DISPLAY is not set). Starting X server.\n");
}
return execute(command_from_prefs("startx_script", DEFAULT_STARTX));
return execute(pref_startx_script);
}
/** Setup the environment we want our child processes to inherit */
@ -475,6 +482,28 @@ static void ensure_path(const char *dir) {
}
}
static void setup_console_redirect(const char *bundle_id) {
char *asl_sender;
char *asl_facility;
aslclient aslc;
asprintf(&asl_sender, "%s.server", bundle_id);
assert(asl_sender);
asl_facility = strdup(bundle_id);
assert(asl_facility);
if(strcmp(asl_facility + strlen(asl_facility) - 4, ".X11") == 0)
asl_facility[strlen(asl_facility) - 4] = '\0';
assert(aslc = asl_open(asl_sender, asl_facility, ASL_OPT_NO_DELAY));
free(asl_sender);
free(asl_facility);
asl_set_filter(aslc, ASL_FILTER_MASK_UPTO(ASL_LEVEL_WARNING));
xq_asl_capture_fd(aslc, NULL, ASL_LEVEL_INFO, STDOUT_FILENO);
xq_asl_capture_fd(aslc, NULL, ASL_LEVEL_NOTICE, STDERR_FILENO);
}
static void setup_env(void) {
char *temp;
const char *pds = NULL;
@ -497,6 +526,8 @@ static void setup_env(void) {
pds = BUNDLE_ID_PREFIX".X11";
}
setup_console_redirect(pds);
server_bootstrap_name = strdup(pds);
if(!server_bootstrap_name) {
ErrorF("X11.app: Memory allocation error.\n");
@ -594,11 +625,20 @@ int main(int argc, char **argv, char **envp) {
pid_t child1, child2;
int status;
pref_app_to_run = command_from_prefs("app_to_run", DEFAULT_CLIENT);
assert(pref_app_to_run);
pref_login_shell = command_from_prefs("login_shell", DEFAULT_SHELL);
assert(pref_login_shell);
pref_startx_script = command_from_prefs("startx_script", DEFAULT_STARTX);
assert(pref_startx_script);
/* Do the fork-twice trick to avoid having to reap zombies */
child1 = fork();
switch (child1) {
case -1: /* error */
break;
FatalError("fork() failed: %s\n", strerror(errno));
case 0: /* child1 */
child2 = fork();
@ -607,7 +647,7 @@ int main(int argc, char **argv, char **envp) {
int max_files, i;
case -1: /* error */
break;
FatalError("fork() failed: %s\n", strerror(errno));
case 0: /* child2 */
/* close all open files except for standard streams */
@ -629,6 +669,10 @@ int main(int argc, char **argv, char **envp) {
default: /* parent */
waitpid(child1, &status, 0);
}
free(pref_app_to_run);
free(pref_login_shell);
free(pref_startx_script);
}
/* Main event loop */
@ -646,7 +690,7 @@ static int execute(const char *command) {
const char *newargv[4];
const char **p;
newargv[0] = command_from_prefs("login_shell", DEFAULT_SHELL);
newargv[0] = pref_login_shell;
newargv[1] = "-c";
newargv[2] = command;
newargv[3] = NULL;

View File

@ -31,41 +31,43 @@
#endif
#include <launch.h>
#include <stdio.h>
#include <asl.h>
#include <errno.h>
#include "launchd_fd.h"
extern aslclient aslc;
int launchd_display_fd(void) {
launch_data_t sockets_dict, checkin_request, checkin_response;
launch_data_t listening_fd_array, listening_fd;
/* Get launchd fd */
if ((checkin_request = launch_data_new_string(LAUNCH_KEY_CHECKIN)) == NULL) {
fprintf(stderr,"launch_data_new_string(\"" LAUNCH_KEY_CHECKIN "\") Unable to create string.\n");
asl_log(aslc, NULL, ASL_LEVEL_ERR, "launch_data_new_string(\"" LAUNCH_KEY_CHECKIN "\") Unable to create string.\n");
return ERROR_FD;
}
if ((checkin_response = launch_msg(checkin_request)) == NULL) {
fprintf(stderr,"launch_msg(\"" LAUNCH_KEY_CHECKIN "\") IPC failure: %s\n",strerror(errno));
asl_log(aslc, NULL, ASL_LEVEL_WARNING, "launch_msg(\"" LAUNCH_KEY_CHECKIN "\") IPC failure: %s\n",strerror(errno));
return ERROR_FD;
}
if (LAUNCH_DATA_ERRNO == launch_data_get_type(checkin_response)) {
// ignore EACCES, which is common if we weren't started by launchd
if (launch_data_get_errno(checkin_response) != EACCES)
fprintf(stderr,"launchd check-in failed: %s\n", strerror(launch_data_get_errno(checkin_response)));
asl_log(aslc, NULL, ASL_LEVEL_ERR, "launchd check-in failed: %s\n", strerror(launch_data_get_errno(checkin_response)));
return ERROR_FD;
}
sockets_dict = launch_data_dict_lookup(checkin_response, LAUNCH_JOBKEY_SOCKETS);
if (NULL == sockets_dict) {
fprintf(stderr,"launchd check-in: no sockets found to answer requests on!\n");
asl_log(aslc, NULL, ASL_LEVEL_ERR, "launchd check-in: no sockets found to answer requests on!\n");
return ERROR_FD;
}
if (launch_data_dict_get_count(sockets_dict) > 1) {
fprintf(stderr,"launchd check-in: some sockets will be ignored!\n");
asl_log(aslc, NULL, ASL_LEVEL_ERR, "launchd check-in: some sockets will be ignored!\n");
return ERROR_FD;
}
@ -73,13 +75,13 @@ int launchd_display_fd(void) {
if (NULL == listening_fd_array) {
listening_fd_array = launch_data_dict_lookup(sockets_dict, ":0");
if (NULL == listening_fd_array) {
fprintf(stderr,"launchd check-in: No known sockets found to answer requests on! \"%s:0\" and \":0\" failed.\n", BUNDLE_ID_PREFIX);
asl_log(aslc, NULL, ASL_LEVEL_ERR, "launchd check-in: No known sockets found to answer requests on! \"%s:0\" and \":0\" failed.\n", BUNDLE_ID_PREFIX);
return ERROR_FD;
}
}
if (launch_data_array_get_count(listening_fd_array)!=1) {
fprintf(stderr,"launchd check-in: Expected 1 socket from launchd, got %u)\n",
asl_log(aslc, NULL, ASL_LEVEL_ERR, "launchd check-in: Expected 1 socket from launchd, got %u)\n",
(unsigned)launch_data_array_get_count(listening_fd_array));
return ERROR_FD;
}

View File

@ -33,9 +33,9 @@
#endif
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <asl.h>
#include <sys/socket.h>
#include <sys/un.h>
@ -43,8 +43,6 @@
#define kX11AppBundleId BUNDLE_ID_PREFIX".X11"
#define kX11AppBundlePath "/Contents/MacOS/X11"
static char *server_bootstrap_name = kX11AppBundleId;
#include <mach/mach.h>
#include <mach/mach_error.h>
#include <servers/bootstrap.h>
@ -57,8 +55,8 @@ static char *server_bootstrap_name = kX11AppBundleId;
#include "launchd_fd.h"
static char x11_path[PATH_MAX + 1];
static pid_t x11app_pid = 0;
aslclient aslc;
static void set_x11_path(void) {
#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
@ -69,26 +67,24 @@ static void set_x11_path(void) {
switch (osstatus) {
case noErr:
if (appURL == NULL) {
fprintf(stderr, "Xquartz: Invalid response from LSFindApplicationForInfo(%s)\n",
asl_log(aslc, NULL, ASL_LEVEL_ERR, "Xquartz: Invalid response from LSFindApplicationForInfo(%s)",
kX11AppBundleId);
exit(1);
}
if (!CFURLGetFileSystemRepresentation(appURL, true, (unsigned char *)x11_path, sizeof(x11_path))) {
fprintf(stderr, "Xquartz: Error resolving URL for %s\n", kX11AppBundleId);
asl_log(aslc, NULL, ASL_LEVEL_ERR, "Xquartz: Error resolving URL for %s", kX11AppBundleId);
exit(3);
}
strlcat(x11_path, kX11AppBundlePath, sizeof(x11_path));
#ifdef DEBUG
fprintf(stderr, "Xquartz: X11.app = %s\n", x11_path);
#endif
asl_log(aslc, NULL, ASL_LEVEL_INFO, "Xquartz: X11.app = %s", x11_path);
break;
case kLSApplicationNotFoundErr:
fprintf(stderr, "Xquartz: Unable to find application for %s\n", kX11AppBundleId);
asl_log(aslc, NULL, ASL_LEVEL_ERR, "Xquartz: Unable to find application for %s", kX11AppBundleId);
exit(10);
default:
fprintf(stderr, "Xquartz: Unable to find application for %s, error code = %d\n",
asl_log(aslc, NULL, ASL_LEVEL_ERR, "Xquartz: Unable to find application for %s, error code = %d",
kX11AppBundleId, (int)osstatus);
exit(11);
}
@ -114,12 +110,12 @@ static int connect_to_socket(const char *filename) {
ret_fd = socket(PF_UNIX, SOCK_STREAM, 0);
if(ret_fd == -1) {
fprintf(stderr, "Xquartz: Failed to create socket: %s - %s\n", filename, strerror(errno));
asl_log(aslc, NULL, ASL_LEVEL_ERR, "Xquartz: Failed to create socket: %s - %s", filename, strerror(errno));
return -1;
}
if(connect(ret_fd, servaddr, servaddr_len) < 0) {
fprintf(stderr, "Xquartz: Failed to connect to socket: %s - %d - %s\n", filename, errno, strerror(errno));
asl_log(aslc, NULL, ASL_LEVEL_ERR, "Xquartz: Failed to connect to socket: %s - %d - %s", filename, errno, strerror(errno));
close(ret_fd);
return -1;
}
@ -160,14 +156,11 @@ static void send_fd_handoff(int connected_fd, int launchd_fd) {
*((int*)CMSG_DATA(cmsg)) = launchd_fd;
if(sendmsg(connected_fd, &msg, 0) < 0) {
fprintf(stderr, "Xquartz: Error sending $DISPLAY file descriptor over fd %d: %d -- %s\n", connected_fd, errno, strerror(errno));
asl_log(aslc, NULL, ASL_LEVEL_ERR, "Xquartz: Error sending $DISPLAY file descriptor over fd %d: %d -- %s", connected_fd, errno, strerror(errno));
return;
}
#ifdef DEBUG
fprintf(stderr, "Xquartz: Message sent. Closing handoff fd.\n");
#endif
asl_log(aslc, NULL, ASL_LEVEL_DEBUG, "Xquartz: Message sent. Closing handoff fd.");
close(connected_fd);
}
@ -187,10 +180,25 @@ int main(int argc, char **argv, char **envp) {
int launchd_fd;
string_t handoff_socket_filename;
sig_t handler;
char *asl_sender;
char *asl_facility;
char *server_bootstrap_name = kX11AppBundleId;
if(getenv("X11_PREFS_DOMAIN"))
server_bootstrap_name = getenv("X11_PREFS_DOMAIN");
asprintf(&asl_sender, "%s.stub", server_bootstrap_name);
assert(asl_sender);
asl_facility = strdup(server_bootstrap_name);
assert(asl_facility);
if(strcmp(asl_facility + strlen(asl_facility) - 4, ".X11") == 0)
asl_facility[strlen(asl_facility) - 4] = '\0';
assert(aslc = asl_open(asl_sender, asl_facility, ASL_OPT_NO_DELAY));
free(asl_sender);
free(asl_facility);
/* We don't have a mechanism in place to handle this interrupt driven
* server-start notification, so just send the signal now, so xinit doesn't
* time out waiting for it and will just poll for the server.
@ -211,13 +219,13 @@ int main(int argc, char **argv, char **envp) {
if(kr != KERN_SUCCESS) {
pid_t child;
fprintf(stderr, "Xquartz: Unable to locate waiting server: %s\n", server_bootstrap_name);
asl_log(aslc, NULL, ASL_LEVEL_WARNING, "Xquartz: Unable to locate waiting server: %s", server_bootstrap_name);
set_x11_path();
/* This forking is ugly and will be cleaned up later */
child = fork();
if(child == -1) {
fprintf(stderr, "Xquartz: Could not fork: %s\n", strerror(errno));
asl_log(aslc, NULL, ASL_LEVEL_ERR, "Xquartz: Could not fork: %s", strerror(errno));
return EXIT_FAILURE;
}
@ -226,7 +234,7 @@ int main(int argc, char **argv, char **envp) {
_argv[0] = x11_path;
_argv[1] = "--listenonly";
_argv[2] = NULL;
fprintf(stderr, "Xquartz: Starting X server: %s --listenonly\n", x11_path);
asl_log(aslc, NULL, ASL_LEVEL_NOTICE, "Xquartz: Starting X server: %s --listenonly", x11_path);
return execvp(x11_path, _argv);
}
@ -240,9 +248,9 @@ int main(int argc, char **argv, char **envp) {
if(kr != KERN_SUCCESS) {
#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
fprintf(stderr, "Xquartz: bootstrap_look_up(): %s\n", bootstrap_strerror(kr));
asl_log(aslc, NULL, ASL_LEVEL_ERR, "Xquartz: bootstrap_look_up(): %s", bootstrap_strerror(kr));
#else
fprintf(stderr, "Xquartz: bootstrap_look_up(): %ul\n", (unsigned long)kr);
asl_log(aslc, NULL, ASL_LEVEL_ERR, "Xquartz: bootstrap_look_up(): %ul", (unsigned long)kr);
#endif
return EXIT_FAILURE;
}
@ -258,20 +266,17 @@ int main(int argc, char **argv, char **envp) {
for(try=0, try_max=5; try < try_max; try++) {
if(request_fd_handoff_socket(mp, handoff_socket_filename) != KERN_SUCCESS) {
fprintf(stderr, "Xquartz: Failed to request a socket from the server to send the $DISPLAY fd over (try %d of %d)\n", (int)try+1, (int)try_max);
asl_log(aslc, NULL, ASL_LEVEL_INFO, "Xquartz: Failed to request a socket from the server to send the $DISPLAY fd over (try %d of %d)", (int)try+1, (int)try_max);
continue;
}
handoff_fd = connect_to_socket(handoff_socket_filename);
if(handoff_fd == -1) {
fprintf(stderr, "Xquartz: Failed to connect to socket (try %d of %d)\n", (int)try+1, (int)try_max);
asl_log(aslc, NULL, ASL_LEVEL_ERR, "Xquartz: Failed to connect to socket (try %d of %d)", (int)try+1, (int)try_max);
continue;
}
#ifdef DEBUG
fprintf(stderr, "Xquartz: Handoff connection established (try %d of %d) on fd %d, \"%s\". Sending message.\n", (int)try+1, (int)try_max, handoff_fd, handoff_socket_filename);
#endif
asl_log(aslc, NULL, ASL_LEVEL_INFO, "Xquartz: Handoff connection established (try %d of %d) on fd %d, \"%s\". Sending message.", (int)try+1, (int)try_max, handoff_fd, handoff_socket_filename);
send_fd_handoff(handoff_fd, launchd_fd);
close(handoff_fd);
break;
@ -288,7 +293,7 @@ int main(int argc, char **argv, char **envp) {
newenvp = (string_array_t)calloc((1 + envpc), sizeof(string_t));
if(!newargv || !newenvp) {
fprintf(stderr, "Xquartz: Memory allocation failure\n");
asl_log(aslc, NULL, ASL_LEVEL_ERR, "Xquartz: Memory allocation failure");
return EXIT_FAILURE;
}
@ -305,7 +310,7 @@ int main(int argc, char **argv, char **envp) {
free(newenvp);
if (kr != KERN_SUCCESS) {
fprintf(stderr, "Xquartz: start_x11_server: %s\n", mach_error_string(kr));
asl_log(aslc, NULL, ASL_LEVEL_ERR, "Xquartz: start_x11_server: %s", mach_error_string(kr));
return EXIT_FAILURE;
}
return EXIT_SUCCESS;

View File

@ -16,72 +16,72 @@ OS X handles the desktop background.
.SH CUSTOMIZATION
\fIXquartz\fP can be customized using the defaults(1) command. The available options are:
.TP 8
.B defaults write __laucnd_id_prefix__.X11 enable_fake_buttons -boolean true
.B defaults write __bundle_id_prefix__.X11 enable_fake_buttons -boolean true
Emulates a 3 button mouse using modifier keys. By default, the Command modifier
is used to emulate button 2 and Option is used for button 3. Thus, clicking the
first mouse button while holding down Command will act like clicking
button 2. Holding down Option will simulate button 3.
.TP 8
.B defaults write __laucnd_id_prefix__.X11 fake_button2 \fImodifiers\fP
.B defaults write __bundle_id_prefix__.X11 fake_button2 \fImodifiers\fP
Change the modifier keys used to emulate the second mouse button. By default,
Command is used to emulate the second button. Any combination of the following
modifier names may be used: {l,r,}shift, {l,r,}option, {l,r,}control, {l,r,}command, fn
.TP 8
.B defaults write __laucnd_id_prefix__.X11 fake_button3 \fImodifiers\fP
.B defaults write __bundle_id_prefix__.X11 fake_button3 \fImodifiers\fP
Change the modifier keys used to emulate the second mouse button. By default,
Command is used to emulate the second button. Any combination of the following
modifier names may be used: {l,r,}shift, {l,r,}option, {l,r,}control, {l,r,}command, fn
.TP 8
.B defaults write __laucnd_id_prefix__.X11 fullscreen_hotkeys -boolean true
.B defaults write __bundle_id_prefix__.X11 fullscreen_hotkeys -boolean true
Enable OSX hotkeys while in fullscreen
.TP 8
.B defaults write __laucnd_id_prefix__.X11 fullscreen_menu -boolean true
.B defaults write __bundle_id_prefix__.X11 fullscreen_menu -boolean true
Show the OSX menu while in fullscreen
.TP 8
.B defaults write __laucnd_id_prefix__.X11 no_quit_alert -boolean true
.B defaults write __bundle_id_prefix__.X11 no_quit_alert -boolean true
Disables the alert dialog displayed when attempting to quit X11.
.TP 8
.B defaults write __laucnd_id_prefix__.X11 no_auth -boolean true
.B defaults write __bundle_id_prefix__.X11 no_auth -boolean true
Stops the X server requiring that clients authenticate themselves when
connecting. See Xsecurity(__miscmansuffix__).
.TP 8
.B defaults write __laucnd_id_prefix__.X11 nolisten_tcp -boolean false
.B defaults write __bundle_id_prefix__.X11 nolisten_tcp -boolean false
This will tell the server to listen and accept TCP connections. Doing this without enabling
xauth is a possible security concern. See Xsecurity(__miscmansuffix__).
.TP 8
.B defaults write __laucnd_id_prefix__.X11 enable_system_beep -boolean false
.B defaults write __bundle_id_prefix__.X11 enable_system_beep -boolean false
Don't use the standard system beep effect for X11 alerts.
.TP 8
.B defaults write __laucnd_id_prefix__.X11 enable_key_equivalents -boolean false
.B defaults write __bundle_id_prefix__.X11 enable_key_equivalents -boolean false
Disable menu keyboard equivalents while X11 windows are focused.
.TP 8
.B defaults write __laucnd_id_prefix__.X11 depth \fIdepth\fP
.B defaults write __bundle_id_prefix__.X11 depth \fIdepth\fP
Specifies the color bit depth to use. Currently only 15, and 24 color
bits per pixel are supported. If not specified, or a value of -1 is specified,
defaults to the depth of the main display.
.TP 8
.B defaults write __laucnd_id_prefix__.X11 sync_keymap -boolean true
.B defaults write __bundle_id_prefix__.X11 sync_keymap -boolean true
Keep the X11 keymap up to date with the OSX system keymap.
.TP 8
.B defaults write __laucnd_id_prefix__.X11 option_sends_alt -boolean true
.B defaults write __bundle_id_prefix__.X11 option_sends_alt -boolean true
The Option key will send Alt_L and Alt_R instead of Mode_switch.
.TP 8
.B defaults write __laucnd_id_prefix__.X11 sync_pasteboard -boolean true
.B defaults write __bundle_id_prefix__.X11 sync_pasteboard -boolean true
Enable syncing between the OSX pasteboard and clipboard/primary selection buffers in X11. This option needs to be true for any of the other pasteboard sync options to have an effect.
.TP 8
.B defaults write __laucnd_id_prefix__.X11 sync_pasteboard_to_clipboard -boolean true
.B defaults write __bundle_id_prefix__.X11 sync_pasteboard_to_clipboard -boolean true
Update the X11 CLIPBOARD when the OSX NSPasteboard is updated.
.TP 8
.B defaults write __laucnd_id_prefix__.X11 sync_pasteboard_to_primary -boolean true
.B defaults write __bundle_id_prefix__.X11 sync_pasteboard_to_primary -boolean true
Update the the X11 PRIMARY buffer when the OSX NSPasteboard is updated.
.TP 8
.B defaults write __laucnd_id_prefix__.X11 sync_clipboard_to_pasteboard -boolean true
.B defaults write __bundle_id_prefix__.X11 sync_clipboard_to_pasteboard -boolean true
Update the the OSX NSPasteboard when the X11 CLIPBOARD is updated. Note that enabling this option causes the clipboard synchronization to act as a clipboard manager in X11. This makes it impossible to use xclipboard, klipper, or any other such clipboard managers. If you want to use any of these programs, you must disable this option.
.TP 8
.B defaults write __laucnd_id_prefix__.X11 sync_primary_on_select -boolean true
.B defaults write __bundle_id_prefix__.X11 sync_primary_on_select -boolean true
This option defaults to false and is provided only "for experts." It updates the NSPasteboard whenever a new X11 selection is made (rather than requiring you to hit cmd-c to copy the selection to the NSPasteboard). Since the X11 protocol does not require applications to send notification when they change selection, this might not work in all cases (if you run into this problem, try selecting text in another application first, then selecting the text you want).
.TP 8
.B defaults write __laucnd_id_prefix__.X11 enable_test_extensions -boolean true
.B defaults write __bundle_id_prefix__.X11 enable_test_extensions -boolean true
This option defaults to false and is only accessible through the command line. Enable this option to turn on the DEC-XTRAP, RECORD, and XTEST extensions in the server.
.SH OPTIONS
.PP
@ -102,9 +102,32 @@ Same as fake_button3 above.
.TP 8
.B "\-depth \fIdepth\fP"
Same as depth above.
.SH LOGGING
XQuartz stores a server log at ~/Library/Logs/X11.__bundle_id_prefix__.log which
is analogous to /var/log/Xorg.#.log on systems that use the XFree86 DDX such as
Linux, BSD, and Solaris.
.PP
In addition to this server log, XQuartz sends messages to syslogd(8) using
asl(3). These logs are sent to the __bundle_id_prefix__ facility, and you can
watch these logs using the following syslog(1) command:
.TP 8
.B $ syslog -w -k Facility __bundle_id_prefix__
.PP
By default, XQaurtz sets an ASL mask which prevents it from logging messages
below the ASL_LEVEL_WARNING level (meaning almost all logging is done strictly
to the file referenced above). To force XQuartz to send all log messages to
syslogd(8), you can adjust this mask using the following syslog(1) command:
.TP 8
.B $ syslog -c X11.bin -d
.PP
The stdout and stderr messages printed by any process launched by XQuartz will
be redirected to this syslog facility with a priority level of ASL_LEVEL_INFO
and ASL_LEVEL_NOTICE respectively. In order to see these messages in syslog,
you will need to adjust XQuartz's asl mask as above but using -i or -n
instead of -d.
.SH "SEE ALSO"
.PP
X(__miscmansuffix__), Xserver(1), xdm(1), xinit(1)
X(__miscmansuffix__), Xserver(1), xdm(1), xinit(1), syslog(1), syslogd(8)
.PP
http://xquartz.macosforge.org
.PP

View File

@ -56,13 +56,7 @@
#include "X11Application.h"
#ifdef NDEBUG
#undef NDEBUG
#include <assert.h>
#define NDEBUG 1
#else
#include <assert.h>
#endif
#include <pthread.h>
#include "xkbsrv.h"

View File

@ -16,7 +16,8 @@
#define BOOL OSX_BOOL
#define EventType HIT_EventType
#include <Cocoa/Cocoa.h>
#import <Cocoa/Cocoa.h>
#import <Foundation/Foundation.h>
#undef Cursor
#undef WindowPtr
@ -24,4 +25,40 @@
#undef BOOL
#undef EventType
#ifndef __has_feature
#define __has_feature(x) 0 // Compatibility with non-clang compilers.
#endif
#ifndef NS_RETURNS_RETAINED
#if __has_feature(attribute_ns_returns_retained)
#define NS_RETURNS_RETAINED __attribute__((ns_returns_retained))
#else
#define NS_RETURNS_RETAINED
#endif
#endif
#ifndef NS_RETURNS_NOT_RETAINED
#if __has_feature(attribute_ns_returns_not_retained)
#define NS_RETURNS_NOT_RETAINED __attribute__((ns_returns_not_retained))
#else
#define NS_RETURNS_NOT_RETAINED
#endif
#endif
#ifndef CF_RETURNS_RETAINED
#if __has_feature(attribute_cf_returns_retained)
#define CF_RETURNS_RETAINED __attribute__((cf_returns_retained))
#else
#define CF_RETURNS_RETAINED
#endif
#endif
#ifndef CF_RETURNS_NOT_RETAINED
#if __has_feature(attribute_cf_returns_not_retained)
#define CF_RETURNS_NOT_RETAINED __attribute__((cf_returns_not_retained))
#else
#define CF_RETURNS_NOT_RETAINED
#endif
#endif
#endif /* _XQ_SANITIZED_COCOA_H_ */

View File

@ -69,7 +69,7 @@ static x_hash_table *window_hash;
#ifdef HAVE_LIBDISPATCH
static dispatch_queue_t window_hash_serial_q;
#else
static pthread_mutex_t window_hash_mutex;
static pthread_rwlock_t window_hash_rwlock;
#endif
/* Prototypes for static functions */
@ -192,9 +192,9 @@ xprCreateFrame(RootlessWindowPtr pFrame, ScreenPtr pScreen,
x_hash_table_insert(window_hash, pFrame->wid, pFrame);
});
#else
pthread_mutex_lock(&window_hash_mutex);
pthread_rwlock_wrlock(&window_hash_rwlock);
x_hash_table_insert(window_hash, pFrame->wid, pFrame);
pthread_mutex_unlock(&window_hash_mutex);
pthread_rwlock_wrlock(&window_hash_rwlock);
#endif
xprSetNativeProperty(pFrame);
@ -216,9 +216,9 @@ xprDestroyFrame(RootlessFrameID wid)
x_hash_table_remove(window_hash, wid);
});
#else
pthread_mutex_lock(&window_hash_mutex);
pthread_rwlock_wrlock(&window_hash_rwlock);
x_hash_table_remove(window_hash, wid);
pthread_mutex_unlock(&window_hash_mutex);
pthread_rwlock_unlock(&window_hash_rwlock);
#endif
err = xp_destroy_window(x_cvt_vptr_to_uint(wid));
@ -292,9 +292,9 @@ static void xprRestackFrame(RootlessFrameID wid, RootlessFrameID nextWid) {
winRec = x_hash_table_lookup(window_hash, wid, NULL);
});
#else
pthread_mutex_lock(&window_hash_mutex);
pthread_rwlock_rdlock(&window_hash_rwlock);
winRec = x_hash_table_lookup(window_hash, wid, NULL);
pthread_mutex_unlock(&window_hash_mutex);
pthread_rwlock_unlock(&window_hash_rwlock);
#endif
if(winRec) {
@ -479,7 +479,7 @@ xprInit(ScreenPtr pScreen)
#ifdef HAVE_LIBDISPATCH
assert((window_hash_serial_q = dispatch_queue_create(BUNDLE_ID_PREFIX".X11.xpr_window_hash", NULL)));
#else
assert(0 == pthread_mutex_init(&window_hash_mutex, NULL));
assert(0 == pthread_rwlock_init(&window_hash_rwlock, NULL));
#endif
return TRUE;
@ -500,9 +500,9 @@ xprGetXWindow(xp_window_id wid)
});
#else
RootlessWindowRec *winRec;
pthread_mutex_lock(&window_hash_mutex);
pthread_rwlock_rdlock(&window_hash_rwlock);
winRec = x_hash_table_lookup(window_hash, x_cvt_uint_to_vptr(wid), NULL);
pthread_mutex_unlock(&window_hash_mutex);
pthread_rwlock_unlock(&window_hash_rwlock);
#endif
return winRec != NULL ? winRec->win : NULL;

View File

@ -24,7 +24,7 @@ MAN_SUBSTS += -e 's|__logdir__|$(logdir)|g' \
-e 's|__sysconfdir__|$(sysconfdir)|g' \
-e 's|__xconfigdir__|$(__XCONFIGDIR__)|g' \
-e 's|__xkbdir__|$(XKB_BASE_DIRECTORY)|g' \
-e 's|__laucnd_id_prefix__|$(BUNDLE_ID_PREFIX)|g' \
-e 's|__bundle_id_prefix__|$(BUNDLE_ID_PREFIX)|g' \
-e 's|__modulepath__|$(DEFAULT_MODULE_PATH)|g' \
-e 's|__default_font_path__|$(COMPILEDDEFAULTFONTPATH)|g' \
-e '\|$(COMPILEDDEFAULTFONTPATH)| s|/,|/, |g'

View File

@ -528,7 +528,12 @@ FatalError(const char *f, ...)
va_start(args, f);
#ifdef __APPLE__
(void)vsnprintf(__crashreporter_info_buff__, sizeof(__crashreporter_info_buff__), f, args);
{
va_list args2;
va_copy(args2, args);
(void)vsnprintf(__crashreporter_info_buff__, sizeof(__crashreporter_info_buff__), f, args2);
va_end(args2);
}
#endif
VErrorF(f, args);
va_end(args);