summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJon TURNEY <jon.turney@dronecode.org.uk>2012-04-17 19:39:03 +0100
committerJon TURNEY <jon.turney@dronecode.org.uk>2012-04-18 12:40:45 +0100
commit474aae57c1ba62418e5194deec46f9c23961e178 (patch)
tree669bc62a8e80af93c68c4b7715bf8b7d23f94188
parentc812561a7bda569e5ca936a90245b785d1d78d81 (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.c150
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:
{