diff options
author | Jon TURNEY <jon.turney@dronecode.org.uk> | 2012-04-17 19:39:03 +0100 |
---|---|---|
committer | Jon TURNEY <jon.turney@dronecode.org.uk> | 2012-04-18 12:40:45 +0100 |
commit | 474aae57c1ba62418e5194deec46f9c23961e178 (patch) | |
tree | 669bc62a8e80af93c68c4b7715bf8b7d23f94188 | |
parent | c812561a7bda569e5ca936a90245b785d1d78d81 (diff) |
Log stdout and stderr for processes started from the notification area icon
Create a separate thread to write stdout and stderr for processes started from
the notification area icon to the X server log
At the moment, this output doesn't go anywhere useful, which can make it hard
to debug problems with processes started this way.
-rw-r--r-- | hw/xwin/winprefs.c | 150 |
1 files changed, 125 insertions, 25 deletions
diff --git a/hw/xwin/winprefs.c b/hw/xwin/winprefs.c index 0209d51f5..a4904710a 100644 --- a/hw/xwin/winprefs.c +++ b/hw/xwin/winprefs.c @@ -37,6 +37,8 @@ #include <stdlib.h> #ifdef __CYGWIN__ #include <sys/resource.h> +#include <sys/wait.h> +#include <pthread.h> #endif #include "win.h" @@ -321,8 +323,120 @@ HandleCustomWM_INITMENU(unsigned long hwndIn, CheckMenuItem (hmenu, pref.menu[i].menuItem[j].commandID, dwExStyle ); } - -/* + +#ifdef __CYGWIN__ +static void +LogLineFromFd(int fd, const char *fdname, int pid) +{ +#define BUFSIZE 512 /* must be less than internal buffer size used in LogVWrite */ + char buf[BUFSIZE]; + char *bufptr = buf; + + /* read from fd until eof, newline or our buffer is full */ + while ((read(fd, bufptr, 1) > 0) && (bufptr < &(buf[BUFSIZE-1]))) + { + if (*bufptr == '\n') + break; + bufptr++; + } + + /* null terminate and log */ + *bufptr = 0; + if (strlen(buf)) + ErrorF("(pid %d %s) %s\n", pid, fdname, buf); +} + +static void * +ExecAndLogThread(void *cmd) +{ + int pid; + int stdout_filedes[2]; + int stderr_filedes[2]; + int status; + + /* Create a pair of pipes */ + pipe(stdout_filedes); + pipe(stderr_filedes); + + switch (pid = fork()) + { + case 0: /* child */ + { + struct rlimit rl; + unsigned int fd; + + /* dup write end of pipes onto stderr and stdout */ + close(STDOUT_FILENO); + close(STDERR_FILENO); + + dup2(stdout_filedes[1], STDOUT_FILENO); + dup2(stderr_filedes[1], STDERR_FILENO); + + /* Close any open descriptors except for STD* */ + getrlimit (RLIMIT_NOFILE, &rl); + for (fd = STDERR_FILENO+1; fd < rl.rlim_cur; fd++) + close(fd); + + /* Disassociate any TTYs */ + setsid(); + + execl ("/bin/sh", + "/bin/sh", + "-c", + cmd, + NULL); + perror("execl failed"); + exit(127); + } + break; + + default: /* parent */ + { + close(stdout_filedes[1]); + close(stderr_filedes[1]); + + ErrorF("executing '%s', pid %d\n", (char *)cmd, pid); + + /* read from pipes, write to log, until both are closed */ + while (TRUE) + { + fd_set readfds, errorfds; + int nfds = max(stdout_filedes[0], stderr_filedes[0])+1; + FD_ZERO(&readfds); + FD_SET(stdout_filedes[0], &readfds); + FD_SET(stderr_filedes[0], &readfds); + errorfds = readfds; + + if (select(nfds, &readfds, NULL, &errorfds, NULL) > 0) + { + if (FD_ISSET(stdout_filedes[0], &readfds)) + LogLineFromFd(stdout_filedes[0], "stdout", pid); + if (FD_ISSET(stderr_filedes[0], &readfds)) + LogLineFromFd(stderr_filedes[0], "stderr", pid); + + if (FD_ISSET(stdout_filedes[0], &errorfds) && + FD_ISSET(stderr_filedes[0], &errorfds)) + break; + } + else + { + break; + } + } + + waitpid(pid, &status, 0); + } + break; + + case -1: /* error */ + ErrorF("fork() to run command failed\n"); + } + + return (void *)status; +} +#endif + + /* * Searches for the custom WM_COMMAND command ID and performs action. * Return TRUE if command is proccessed, FALSE otherwise. */ @@ -352,29 +466,15 @@ HandleCustomWM_COMMAND (unsigned long hwndIn, { #ifdef __CYGWIN__ case CMD_EXEC: - if (fork()==0) - { - struct rlimit rl; - unsigned long i; - - /* Close any open descriptors except for STD* */ - getrlimit (RLIMIT_NOFILE, &rl); - for (i = STDERR_FILENO+1; i < rl.rlim_cur; i++) - close(i); - - /* Disassociate any TTYs */ - setsid(); - - execl ("/bin/sh", - "/bin/sh", - "-c", - m->menuItem[j].param, - NULL); - exit (0); - } - else - return TRUE; - break; + { + pthread_t t; + if (!pthread_create(&t, NULL, ExecAndLogThread, m->menuItem[j].param)) + pthread_detach(t); + else + ErrorF("Creating command output logging thread failed\n"); + } + return TRUE; + break; #else case CMD_EXEC: { |