From 3b53d7aecb2f3a729c57f2831a3d4b6e1ff1901f Mon Sep 17 00:00:00 2001 From: Jeremy Huddleston Date: Thu, 12 May 2011 20:27:55 -0700 Subject: launchd: Update console redirection to work with libdispatch Signed-off-by: Jeremy Huddleston --- launchd/Makefile.am | 2 + launchd/console_redirect.c | 469 +++++++++++++++++++++++----------- launchd/console_redirect.h | 44 ++++ launchd/privileged_startx/Makefile.am | 4 +- launchd/privileged_startx/server.c | 8 +- launchd/user_startx/Makefile.am | 6 +- launchd/user_startx/launchd_startx.c | 7 +- 7 files changed, 383 insertions(+), 157 deletions(-) create mode 100644 launchd/console_redirect.h (limited to 'launchd') diff --git a/launchd/Makefile.am b/launchd/Makefile.am index d6b5597..f8781ed 100644 --- a/launchd/Makefile.am +++ b/launchd/Makefile.am @@ -1 +1,3 @@ SUBDIRS = privileged_startx user_startx + +EXTRA_DIST = console_redirect.h diff --git a/launchd/console_redirect.c b/launchd/console_redirect.c index 07752a3..26fa097 100644 --- a/launchd/console_redirect.c +++ b/launchd/console_redirect.c @@ -27,9 +27,13 @@ */ #ifdef HAVE_CONFIG_H -# include "config.h" +#include +#else +#define DEBUG_CONSOLE_REDIRECT 1 +#define HAVE_LIBDISPATCH 1 #endif +#include #include #include #include @@ -39,189 +43,364 @@ #include #include #include + +#include "console_redirect.h" + +#define BUF_SIZE 512 + +#ifdef HAVE_LIBDISPATCH +#include + +static dispatch_queue_t redirect_serial_q; +static dispatch_group_t read_source_group; +#else #include -#define BUF_SIZE 1024 +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 { - /* Initialized values */ - int fd; int level; - aslclient aslc; - aslmsg aslm; + aslclient asl; + aslmsg msg; - /* Buffer for reading */ - char buf[BUF_SIZE]; + /* Buffered reading */ + char *buf; char *w; - int closed; -} asl_redirect; -/* Redirect stdout/stderr to asl */ -static void *redirect_thread(void *ctx) { - asl_redirect *fds = ctx; - char *p, *s; - ssize_t nbytes; - struct kevent ev[2]; - int kq, n; - - /* Setup our kqueue */ - kq = kqueue(); - EV_SET(&ev[0], fds[0].fd, EVFILT_READ, EV_ADD, 0, 0, 0); - EV_SET(&ev[1], fds[1].fd, EVFILT_READ, EV_ADD, 0, 0, 0); - kevent(kq, ev, 2, NULL, 0, NULL); - - /* Set our buffers to empty */ - fds[0].w = fds[0].buf; - fds[1].w = fds[1].buf; - - /* Start off open */ - fds[0].closed = fds[1].closed = 0; - - while(!(fds[0].closed && fds[1].closed)) { - n = kevent(kq, NULL, 0, ev, 1, NULL); - if(n < 0) { - asl_log(fds[1].aslc, fds[1].aslm, ASL_LEVEL_ERR, "read failure: %s", strerror(errno)); - break; - } +#ifdef HAVE_LIBDISPATCH + dispatch_source_t read_source; +#endif +} asl_redirect; - if(n == 1 && ev->filter == EVFILT_READ) { - int fd = ev->ident; - asl_redirect *aslr; +static asl_redirect *redirect_fds = NULL; +static int n_redirect_fds = 0; - if(fd == fds[0].fd && !fds[0].closed) { - aslr = &fds[0]; - } else if(fd == fds[1].fd && !fds[1].closed) { - aslr = &fds[1]; - } else { - asl_log(fds[1].aslc, fds[1].aslm, ASL_LEVEL_ERR, "unexpected file descriptor: %d", fd); +/* 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; } + } + } - if(ev->flags & EV_EOF) { - EV_SET(&ev[1], aslr->fd, EVFILT_READ, EV_DELETE, 0, 0, 0); - kevent(kq, &ev[1], 1, NULL, 0, NULL); - aslr->closed = 1; - } + /* 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); - nbytes = read(aslr->fd, aslr->w, BUF_SIZE - (aslr->w - aslr->buf) - 1); - if(nbytes > 0) { - 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->aslc, aslr->aslm, 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->aslc, aslr->aslm, aslr->level, "%s", p); - aslr->w = aslr->buf; - break; + 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(aslr->closed) { - close(aslr->fd); - if(aslr->w > aslr->buf) { - *aslr->w = '\0'; - asl_log(aslr->aslc, aslr->aslm, aslr->level, "%s", aslr->buf); + 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 pthread_t redirect_pthread; static void redirect_atexit(void) { /* stdout is linebuffered, so flush the buffer */ - fflush(stdout); + if(redirect_fds[STDOUT_FILENO].buf) + fflush(stdout); - /* close our pipes, causing the redirect thread to terminate */ - close(STDOUT_FILENO); - close(STDERR_FILENO); - pthread_join(redirect_pthread, NULL); -} +#ifdef HAVE_LIBDISPATCH + { + int i; -int console_redirect(aslclient aslc, aslmsg aslm, int stdout_level, int stderr_level) { - int err; - int outpair[2]; - int errpair[2]; - static asl_redirect readpair[2]; + /* 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); - /* Create pipes */ - if(pipe(outpair) == -1) { - asl_log(aslc, aslm, ASL_LEVEL_ERR, "pipe() failed: %s", strerror(errno)); - return errno; + /* 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)); } - - if(pipe(errpair) == -1) { - asl_log(aslc, aslm, ASL_LEVEL_ERR, "pipe() failed: %s", strerror(errno)); - close(outpair[0]); - close(outpair[1]); - return errno; +#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 +} - /* Close the read fd but not the write fd on exec */ - fcntl(outpair[0], F_SETFD, FD_CLOEXEC); - fcntl(errpair[0], F_SETFD, FD_CLOEXEC); - - /* Setup the context to handoff to the read thread */ - readpair[0].fd = outpair[0]; - readpair[0].level = stdout_level; - readpair[0].aslc = aslc; - readpair[0].aslm = aslm; - - readpair[1].fd = errpair[0]; - readpair[1].level = stderr_level; - readpair[1].aslc = aslc; - readpair[1].aslm = aslm; - - /* Handoff to the read thread */ - if((err = pthread_create(&redirect_pthread, NULL, redirect_thread, readpair)) != 0) { - asl_log(aslc, aslm, ASL_LEVEL_ERR, "pthread_create() failed: %s", strerror(err)); - close(outpair[0]); - close(outpair[1]); - close(errpair[0]); - close(errpair[1]); - return err; - } +#ifdef HAVE_LIBDISPATCH +static void xi_asl_init(void *ctx __unused) +#else +static void xi_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 - /* Replace our stdout fd. force stdout to be line buffered since it defaults to buffered when not a tty */ - if(dup2(outpair[1], STDOUT_FILENO) == -1) { - asl_log(aslc, aslm, ASL_LEVEL_ERR, "dup2(stdout) failed: %s", strerror(errno)); - } else if(setlinebuf(stdout) != 0) { - asl_log(aslc, aslm, ASL_LEVEL_ERR, "setlinebuf(stdout) failed, log redirection may be delayed."); - } + atexit(redirect_atexit); +} - /* Replace our stderr fd. stderr is always unbuffered */ - if(dup2(errpair[1], STDERR_FILENO) == -1) { - asl_log(aslc, aslm, ASL_LEVEL_ERR, "dup2(stderr) failed: %s", strerror(errno)); +int xi_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, xi_asl_init); +#else + int err = 0; + static pthread_once_t once_control = PTHREAD_ONCE_INIT; + assert(pthread_once(&once_control, xi_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; +} - /* Close the duplicate fds since they've been reassigned */ - close(outpair[1]); - close(errpair[1]); +int xi_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; - /* Register an atexit handler to wait for the logs to flush */ - if(atexit(redirect_atexit) != 0) { - asl_log(aslc, aslm, ASL_LEVEL_ERR, "atexit(redirect_atexit) failed: %s", strerror(errno)); + /* Replace the existing fd */ + if(dup2(pipepair[1], fd) == -1) { + close(pipepair[0]); + close(pipepair[1]); + return errno; } - return 0; + /* 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 xi_asl_log_fd */ + return xi_asl_log_fd(asl, msg, level, pipepair[0]); } #ifdef DEBUG_CONSOLE_REDIRECT -int main(int argc, char **argv) { - console_redirect(NULL, NULL, ASL_LEVEL_NOTICE, ASL_LEVEL_ERR); +int main(int argc __unused, char **argv __unused) { + xi_asl_capture_fd(NULL, NULL, ASL_LEVEL_NOTICE, STDOUT_FILENO); + xi_asl_capture_fd(NULL, NULL, ASL_LEVEL_ERR, STDERR_FILENO); fprintf(stderr, "TEST ERR1\n"); fprintf(stdout, "TEST OUT1\n"); @@ -230,9 +409,9 @@ int main(int argc, char **argv) { system("/bin/echo SYST OUT"); system("/bin/echo SYST ERR >&2"); fprintf(stdout, "TEST OUT3\n"); - fprintf(stdout, "TEST OUT4"); + fprintf(stdout, "TEST OUT4\n"); fprintf(stderr, "TEST ERR3\n"); - fprintf(stderr, "TEST ERR4"); + fprintf(stderr, "TEST ERR4\n"); exit(0); } diff --git a/launchd/console_redirect.h b/launchd/console_redirect.h new file mode 100644 index 0000000..134def6 --- /dev/null +++ b/launchd/console_redirect.h @@ -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 + +/* The given fd is replaced with a pipe. Anything written to it will will be + * logged to ASL. + */ +int xi_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 xi_asl_log_fd(aslclient asl, aslmsg msg, int level, int fd); + +#endif diff --git a/launchd/privileged_startx/Makefile.am b/launchd/privileged_startx/Makefile.am index c7cf0e8..811cbdb 100644 --- a/launchd/privileged_startx/Makefile.am +++ b/launchd/privileged_startx/Makefile.am @@ -33,7 +33,7 @@ privstartxdir = $(xinitrcdir)/privileged_startx.d xinitrc_PROGRAMS = privileged_startx privstartx_SCRIPTS = 10-tmpdirs 20-font_cache -AM_CPPFLAGS = -DXINITDIR=\"$(xinitrcdir)\" -DSCRIPTDIR=\"$(privstartxdir)\" -DBINDIR=\"$(bindir)\" +AM_CPPFLAGS = -I$(srcdir)/.. -DXINITDIR=\"$(xinitrcdir)\" -DSCRIPTDIR=\"$(privstartxdir)\" -DBINDIR=\"$(bindir)\" CPP_FILES_FLAGS = -DXINITDIR="$(xinitrcdir)" -DSCRIPTDIR="$(privstartxdir)" -DBINDIR="$(bindir)" -DBUNDLE_ID_PREFIX="$(bundleidprefix)" if TIGER_LAUNCHD @@ -41,7 +41,7 @@ CPP_FILES_FLAGS += -DTIGER_LAUNCHD endif dist_privileged_startx_SOURCES = \ - ../console_redirect.c \ + $(srcdir)/../console_redirect.c \ server.c \ client.c \ privileged_startx.c diff --git a/launchd/privileged_startx/server.c b/launchd/privileged_startx/server.c index 99e6b37..cfbb623 100644 --- a/launchd/privileged_startx/server.c +++ b/launchd/privileged_startx/server.c @@ -46,6 +46,8 @@ #include #include +#include "console_redirect.h" + #include "privileged_startx.h" #include "privileged_startxServer.h" @@ -77,9 +79,6 @@ struct idle_globals idle_globals; /* Default script dir */ const char *script_dir = SCRIPTDIR; -/* console_redirect.c */ -extern int console_redirect(aslclient aslc, aslmsg amsg, int stdout_level, int stderr_level); - #ifndef LAUNCH_JOBKEY_MACHSERVICES static mach_port_t checkin_or_register(char *bname) { kern_return_t kr; @@ -144,7 +143,8 @@ int server_main(const char *dir) { } aslc = asl_open(labelstr, BUNDLE_ID_PREFIX, ASL_OPT_NO_DELAY); - (void)console_redirect(aslc, NULL, ASL_LEVEL_INFO, ASL_LEVEL_NOTICE); + xi_asl_capture_fd(aslc, NULL, ASL_LEVEL_INFO, STDOUT_FILENO); + xi_asl_capture_fd(aslc, NULL, ASL_LEVEL_NOTICE, STDERR_FILENO); #ifdef LAUNCH_JOBKEY_MACHSERVICES launch_data_t tmv; diff --git a/launchd/user_startx/Makefile.am b/launchd/user_startx/Makefile.am index f55a474..ce00e73 100644 --- a/launchd/user_startx/Makefile.am +++ b/launchd/user_startx/Makefile.am @@ -25,11 +25,11 @@ xinitrcdir = $(XINITDIR) xinitrc_PROGRAMS = launchd_startx -AM_CPPFLAGS = -DXINITDIR=\"$(xinitrcdir)\" -DBINDIR=\"$(bindir)\" +AM_CPPFLAGS = -I$(srcdir)/.. -DXINITDIR=\"$(xinitrcdir)\" -DBINDIR=\"$(bindir)\" dist_launchd_startx_SOURCES = \ - ../console_redirect.c \ - launchd_startx.c + $(srcdir)/../console_redirect.c \ + launchd_startx.c CPP_FILES_FLAGS = \ -D__xinitrcdir__="$(xinitrcdir)" \ diff --git a/launchd/user_startx/launchd_startx.c b/launchd/user_startx/launchd_startx.c index 3d1e03e..e3fae76 100644 --- a/launchd/user_startx/launchd_startx.c +++ b/launchd/user_startx/launchd_startx.c @@ -39,8 +39,7 @@ #include #include -/* console_redirect.c */ -extern int console_redirect(aslclient aslc, aslmsg amsg, int stdout_level, int stderr_level); +#include "console_redirect.h" int main(int argc, char **argv, char **envp) { aslclient aslc; @@ -53,7 +52,9 @@ int main(int argc, char **argv, char **envp) { } aslc = asl_open(BUNDLE_ID_PREFIX".startx", BUNDLE_ID_PREFIX, ASL_OPT_NO_DELAY); - (void)console_redirect(aslc, NULL, ASL_LEVEL_INFO, ASL_LEVEL_NOTICE); + + xi_asl_capture_fd(aslc, NULL, ASL_LEVEL_INFO, STDOUT_FILENO); + xi_asl_capture_fd(aslc, NULL, ASL_LEVEL_NOTICE, STDERR_FILENO); assert(posix_spawnp(&child, argv[1], NULL, NULL, &argv[1], envp) == 0); -- cgit v1.2.3