From ad350c468698a3d89eb92aefe59d08a02e6625a0 Mon Sep 17 00:00:00 2001
From: mh17 <mh17>
Date: Fri, 4 Dec 2009 16:01:39 +0000
Subject: [PATCH] script args implemented and STDERR reported to user

---
 src/zmapServer/pipe/pipeServer.c   | 111 ++++++++++++++++++++++++-----
 src/zmapServer/pipe/pipeServer_P.h |  12 ++--
 2 files changed, 103 insertions(+), 20 deletions(-)

diff --git a/src/zmapServer/pipe/pipeServer.c b/src/zmapServer/pipe/pipeServer.c
index 81307a24c..71c0aed90 100755
--- a/src/zmapServer/pipe/pipeServer.c
+++ b/src/zmapServer/pipe/pipeServer.c
@@ -34,7 +34,7 @@
  * HISTORY:
  * Last edited: Nov 30 09:18 2009 (edgrif)
  * Created: 2009-11-26 12:02:40 (mh17)
- * CVS info:   $Id: pipeServer.c,v 1.4 2009-12-03 15:03:08 mh17 Exp $
+ * CVS info:   $Id: pipeServer.c,v 1.5 2009-12-04 16:01:39 mh17 Exp $
  *-------------------------------------------------------------------
  */
 
@@ -212,6 +212,8 @@ static gboolean createConnection(void **server_out,
   }
 
   server->query = url->query;
+  server->zmap_start = 0;
+  server->zmap_end = 0; // default to all of it
 
   return result ;
 }
@@ -222,39 +224,92 @@ static gboolean createConnection(void **server_out,
 /* 
  * fork and exec the script and read teh output via a pipe
  * no data sent to STDIN and STDERR ignored
- * in case of errors or hangups eevntually we will time out and an error popped up.
- * downside is limited to not having the data, whcih is what happens anyway
+ * in case of errors or hangups eventually we will time out and an error popped up.
+ * downside is limited to not having the data, which is what happens anyway
  */
 static gboolean pipe_server_spawn(PipeServer server,GError **error)
 {
   gboolean result = FALSE;
-  gchar **argv;
+  gchar **argv, **q_args, *z_start,*z_end;
   gint pipe_fd;
-  GError *pipe_error = NULL;;
-
-  argv = (gchar **) g_malloc (sizeof(gchar *) * (PIPE_MAX_ARGS + 4));
-    /* initially we have one arg which is the query string
-     * but implement flexible arg handling anyway
-     */
+  GError *pipe_error = NULL;
+  int i;
+  gint err_fd;
 
+  q_args = g_strsplit(server->query,"&",0);
+  argv = (gchar **) g_malloc (sizeof(gchar *) * (PIPE_MAX_ARGS + g_strv_length(q_args)));
   argv[0] = server->script_path; // scripts can get exec'd, as long as they start w/ #!
-  argv[1] = server->query;       // may be NULL
-  argv[2]= NULL;
+  for(i = 1;q_args[i-1];i++)
+      argv[i] = q_args[i-1];
+
+      // now add on zmap args such as start and end
+  if(server->zmap_start || server->zmap_end)
+  {
+      argv[i++] = z_start = g_strdup_printf("%s=%d",PIPE_ARG_ZMAP_START,server->zmap_start);
+      argv[i++] = z_end = g_strdup_printf("%s=%d",PIPE_ARG_ZMAP_END,server->zmap_end);
+  }
+
+  argv[i]= NULL;
 
-  result = g_spawn_async_with_pipes(server->script_dir,argv,NULL,G_SPAWN_STDERR_TO_DEV_NULL,
-                                    NULL,NULL,&server->child_pid,NULL,&pipe_fd,NULL,&pipe_error);
+  result = g_spawn_async_with_pipes(server->script_dir,argv,NULL,G_SPAWN_CHILD_INHERITS_STDIN, // can't not give a flag!
+                                    NULL,NULL,&server->child_pid,NULL,&pipe_fd,&err_fd,&pipe_error);
   if(result)
   {
     server->gff_pipe = g_io_channel_unix_new(pipe_fd);
+    server->gff_error = g_io_channel_unix_new(err_fd);
+  }
+
+  g_free(argv);   // strings allocated and freed seperately
+  g_strfreev(q_args);
+  if(server->zmap_start || server->zmap_end)
+  {
+      g_free(z_start);
+      g_free(z_end);
   }
 
-  g_free(argv);
   if(error)
     *error = pipe_error;
   return(result);
 }
 
 
+/*
+ * read stderr from the external source and if non empty display and log some messages 
+ * use non-blocking i/o so we don't hang ???
+ * gets called by setErrMsg() - if the server fails we read STDERR and possibly report why
+ * if no failures we ignore STDERR
+ * the last message is the one that gets popped up to the user
+ * We log all messages except the last as that generally appears twice in the log anyway
+ */
+gchar *pipe_server_get_stderr(PipeServer server)
+{
+  GIOStatus status ;
+  gsize terminator_pos = 0;
+  GError *gff_pipe_err = NULL;
+  gchar * msg = NULL;
+  GString *line;
+
+  line = g_string_sized_new(2000) ;      /* Probably not many lines will be > 2k chars. */
+
+  while (1)
+    {
+      status = g_io_channel_read_line_string(server->gff_error, line,
+            &terminator_pos,&gff_pipe_err);
+      if(status != G_IO_STATUS_NORMAL)
+        break;
+
+      if(msg)
+            ZMAPPIPESERVER_LOG(Warning, PIPE_PROTOCOL_STR, server->script_path,server->query,"%s", msg) ;
+
+      *(line->str + terminator_pos) = '\0' ; /* Remove terminating newline. */
+      msg = g_strdup(line->str);
+    }
+    
+    g_string_free(line,TRUE);
+    return(msg);
+}
+
+
 static ZMapServerResponseType openConnection(void *server_in)
 {
   ZMapServerResponseType result = ZMAP_SERVERRESPONSE_REQFAIL ;
@@ -746,10 +801,24 @@ static ZMapServerResponseType closeConnection(void *server_in)
     {
       /* this seems to be required to destroy the GIOChannel.... */
       g_io_channel_unref(server->gff_pipe) ;
-
       server->gff_pipe = NULL ;
     }
 
+  if (server->gff_error && g_io_channel_shutdown(server->gff_error, FALSE, &gff_pipe_err) != G_IO_STATUS_NORMAL)
+    {
+      zMapLogCritical("Could not close error pipe \"%s\"", server->script_path) ;
+
+      setLastErrorMsg(server, &gff_pipe_err) ;
+
+      result = ZMAP_SERVERRESPONSE_REQFAIL ;
+    }
+  else
+    {
+      /* this seems to be required to destroy the GIOChannel.... */
+      g_io_channel_unref(server->gff_error) ;
+      server->gff_error = NULL ;
+    }
+
   return result ;
 }
 
@@ -972,8 +1041,18 @@ static gboolean getServerInfo(PipeServer server, ZMapServerInfo info)
 
 
 /* It's possible for us to have reported an error and then another error to come along. */
+/* mgh: if we get an error such as pipe broken then let's look at stderr and if there's a message there report it */
 static void setErrMsg(PipeServer server, char *new_msg)
 {
+  gchar *errmsg;
+
+  errmsg = pipe_server_get_stderr(server);
+  if(errmsg)
+  { 
+      g_free(new_msg);
+      new_msg = errmsg;       // explain the cause of the error not the symptom
+  }
+
   if (server->last_err_msg)
     g_free(server->last_err_msg) ;
 
diff --git a/src/zmapServer/pipe/pipeServer_P.h b/src/zmapServer/pipe/pipeServer_P.h
index 9360665f6..60f5c2ae2 100755
--- a/src/zmapServer/pipe/pipeServer_P.h
+++ b/src/zmapServer/pipe/pipeServer_P.h
@@ -28,7 +28,7 @@
  *              
  * HISTORY:
  * Created: Thu Nov 26 10:30:21 2009 (mh17)
- * CVS info:   $Id: pipeServer_P.h,v 1.2 2009-12-03 15:03:08 mh17 Exp $
+ * CVS info:   $Id: pipeServer_P.h,v 1.3 2009-12-04 16:01:39 mh17 Exp $
  *-------------------------------------------------------------------
  */
 #ifndef PIPE_SERVER_P_H
@@ -37,20 +37,24 @@
 
 #define PIPE_PROTOCOL_STR "GFF Pipe"			    /* For error messages. */
 
-#define PIPE_MAX_ARGS	2	// extra args we add on to the query
+#define PIPE_MAX_ARGS	4	// extra args we add on to the query, including the program and terminating NULL
 #define PIPE_ARG_ZMAP_START	"zmap_start"
 #define PIPE_ARG_ZMAP_END	"zmap_end"
 
 
 
+
 /* Holds all the state we need to create and access the script output. */
 typedef struct _PipeServerStruct
 {
   gchar *script_dir;		// default location for relative paths
-  gchar *script_path ;	// where our configured script is, includign script-dir
+  gchar *script_path ;	      // where our configured script is, includign script-dir
   gchar *query;		    	// from query string
-  GIOChannel *gff_pipe ;// the pipe we read the script's output from
+  GIOChannel *gff_pipe ;      // the pipe we read the script's output from
+  GIOChannel *gff_error ;     // the pipe we read the script's error output from
   GPid child_pid;
+  gint zmap_start,zmap_end;   // display coordinates of interesting region
+  gint wait;                  // delay before gettign data, mainly for testing
 
   char *styles_file ;
 
-- 
GitLab