common: Add a status callback to gnupg_exec_tool_stream.
authorWerner Koch <wk@gnupg.org>
Fri, 27 May 2016 22:07:09 +0000 (00:07 +0200)
committerWerner Koch <wk@gnupg.org>
Fri, 27 May 2016 22:07:09 +0000 (00:07 +0200)
* common/exectool.h (exec_tool_status_cb_t): New.
* common/exectool.c: Include missing exectool.h.
(read_and_log_buffer_t): Replace array by pointer.
(gnupg_exec_tool_stream): Add args 'status_cb' and 'status_cb_value'.
Change all callers to pass NULL for them.  Malloc buffer for
FDERRSTATE.
(read_and_log_stderr): Implement status_fd feature.

Signed-off-by: Werner Koch <wk@gnupg.org>
common/exectool.c
common/exectool.h
tools/gpgtar-create.c
tools/gpgtar-extract.c
tools/gpgtar-list.c

index 953c34a..897450e 100644 (file)
 #include "exechelp.h"
 #include "sysutils.h"
 #include "util.h"
 #include "exechelp.h"
 #include "sysutils.h"
 #include "util.h"
+#include "exectool.h"
 
 typedef struct
 {
   const char *pgmname;
 
 typedef struct
 {
   const char *pgmname;
+  exec_tool_status_cb_t status_cb;
+  void *status_cb_value;
   int cont;
   int cont;
-  int used;
-  char buffer[256];
+  size_t used;
+  size_t buffer_size;
+  char *buffer;
 } read_and_log_buffer_t;
 
 
 } read_and_log_buffer_t;
 
 
@@ -83,14 +87,37 @@ read_and_log_stderr (read_and_log_buffer_t *state, es_poll_t *fderr)
             pname++;
           else
             pname = state->pgmname;
             pname++;
           else
             pname = state->pgmname;
-          /* If our pgmname plus colon is identical to the start of
-             the output, print only the output.  */
           len = strlen (pname);
           len = strlen (pname);
-          if (!state->cont
+
+          if (state->status_cb
+              && !strncmp (state->buffer, "[GNUPG:] ", 9)
+              && state->buffer[9] >= 'A' && state->buffer[9] <= 'Z')
+            {
+              char *rest;
+
+              rest = strchr (state->buffer + 9, ' ');
+              if (!rest)
+                {
+                  /* Set REST to an empty string.  */
+                  rest = state->buffer + strlen (state->buffer);
+                }
+              else
+                {
+                  *rest++ = 0;
+                  trim_spaces (rest);
+                }
+              state->status_cb (state->status_cb_value,
+                                state->buffer + 9, rest);
+            }
+          else if (!state->cont
               && !strncmp (state->buffer, pname, len)
               && strlen (state->buffer) > strlen (pname)
               && state->buffer[len] == ':' )
               && !strncmp (state->buffer, pname, len)
               && strlen (state->buffer) > strlen (pname)
               && state->buffer[len] == ':' )
-            log_info ("%s\n", state->buffer);
+            {
+              /* PGMNAME plus colon is identical to the start of
+                 the output: print only the output.  */
+              log_info ("%s\n", state->buffer);
+            }
           else
             log_info ("%s%c %s\n",
                       pname, state->cont? '+':':', state->buffer);
           else
             log_info ("%s%c %s\n",
                       pname, state->cont? '+':':', state->buffer);
@@ -123,10 +150,39 @@ read_and_log_stderr (read_and_log_buffer_t *state, es_poll_t *fderr)
         }
       else
         {
         }
       else
         {
-          if (state->used >= sizeof state->buffer - 1)
+          if (state->used >= state->buffer_size - 1)
             {
             {
-              read_and_log_stderr (state, NULL);
-              state->cont = 1;
+              if (state->status_cb)
+                {
+                  /* A status callback requires that we have a full
+                   * line.  Thus we need to enlarget the buffer in
+                   * this case.  */
+                  char *newbuffer;
+                  size_t newsize = state->buffer_size + 256;
+
+                  newbuffer = xtrymalloc (newsize);
+                  if (!newbuffer)
+                    {
+                      log_error ("error allocating memory for status cb: %s\n",
+                                 gpg_strerror (my_error_from_syserror ()));
+                      /* We better disable the status CB in this case.  */
+                      state->status_cb = NULL;
+                      read_and_log_stderr (state, NULL);
+                      state->cont = 1;
+                    }
+                  else
+                    {
+                      memcpy (newbuffer, state->buffer, state->used);
+                      xfree (state->buffer);
+                      state->buffer = newbuffer;
+                      state->buffer_size = newsize;
+                    }
+                }
+              else
+                {
+                  read_and_log_stderr (state, NULL);
+                  state->cont = 1;
+                }
             }
           state->buffer[state->used++] = c;
         }
             }
           state->buffer[state->used++] = c;
         }
@@ -242,7 +298,9 @@ copy_buffer_flush (struct copy_buffer *c, estream_t sink)
 gpg_error_t
 gnupg_exec_tool_stream (const char *pgmname, const char *argv[],
                         estream_t input, estream_t inextra,
 gpg_error_t
 gnupg_exec_tool_stream (const char *pgmname, const char *argv[],
                         estream_t input, estream_t inextra,
-                        estream_t output)
+                        estream_t output,
+                        exec_tool_status_cb_t status_cb,
+                        void *status_cb_value)
 {
   gpg_error_t err;
   pid_t pid;
 {
   gpg_error_t err;
   pid_t pid;
@@ -265,6 +323,14 @@ gnupg_exec_tool_stream (const char *pgmname, const char *argv[],
   copy_buffer_init (&cpbuf_out);
   copy_buffer_init (&cpbuf_extra);
 
   copy_buffer_init (&cpbuf_out);
   copy_buffer_init (&cpbuf_extra);
 
+  fderrstate.pgmname = pgmname;
+  fderrstate.status_cb = status_cb;
+  fderrstate.status_cb_value = status_cb_value;
+  fderrstate.buffer_size = 256;
+  fderrstate.buffer = xtrymalloc (fderrstate.buffer_size);
+  if (!fderrstate.buffer)
+    return my_error_from_syserror ();
+
   if (inextra)
     {
       err = gnupg_create_outbound_pipe (extrapipe, &extrafp, 1);
   if (inextra)
     {
       err = gnupg_create_outbound_pipe (extrapipe, &extrafp, 1);
@@ -272,6 +338,7 @@ gnupg_exec_tool_stream (const char *pgmname, const char *argv[],
         {
           log_error ("error running outbound pipe for extra fp: %s\n",
                      gpg_strerror (err));
         {
           log_error ("error running outbound pipe for extra fp: %s\n",
                      gpg_strerror (err));
+          xfree (fderrstate.buffer);
           return err;
         }
       exceptclose[0] = extrapipe[0]; /* Do not close in child. */
           return err;
         }
       exceptclose[0] = extrapipe[0]; /* Do not close in child. */
@@ -303,11 +370,10 @@ gnupg_exec_tool_stream (const char *pgmname, const char *argv[],
     {
       log_error ("error running '%s': %s\n", pgmname, gpg_strerror (err));
       es_fclose (extrafp);
     {
       log_error ("error running '%s': %s\n", pgmname, gpg_strerror (err));
       es_fclose (extrafp);
+      xfree (fderrstate.buffer);
       return err;
     }
 
       return err;
     }
 
-  fderrstate.pgmname = pgmname;
-
   fds[0].stream = infp;
   fds[0].want_write = 1;
   if (!input)
   fds[0].stream = infp;
   fds[0].want_write = 1;
   if (!input)
@@ -438,6 +504,7 @@ gnupg_exec_tool_stream (const char *pgmname, const char *argv[],
   copy_buffer_shred (&cpbuf_out);
   if (inextra)
     copy_buffer_shred (&cpbuf_extra);
   copy_buffer_shred (&cpbuf_out);
   if (inextra)
     copy_buffer_shred (&cpbuf_extra);
+  xfree (fderrstate.buffer);
   return err;
 }
 
   return err;
 }
 
@@ -488,7 +555,7 @@ gnupg_exec_tool (const char *pgmname, const char *argv[],
       goto leave;
     }
 
       goto leave;
     }
 
-  err = gnupg_exec_tool_stream (pgmname, argv, input, NULL, output);
+  err = gnupg_exec_tool_stream (pgmname, argv, input, NULL, output, NULL, NULL);
   if (err)
     goto leave;
 
   if (err)
     goto leave;
 
index 21bc177..94091fd 100644 (file)
 
 #include <gpg-error.h>
 
 
 #include <gpg-error.h>
 
+/* This callback can be used to process --status-fd outputs of GnuPG
+ * tools.  OPAQUE can be used to communicate between the caller of the
+ * function and the callback.  KEYWORD is the status keyword (see
+ * doc/DETAILS); it is never NULL.  ARGS are the arguments of the
+ * status line and will also never be NULL; the caller may modify this
+ * string.  */
+typedef void (*exec_tool_status_cb_t) (void *opaque,
+                                       const char *keyword,
+                                       char *args);
+
+
 /* Run the program PGMNAME with the command line arguments given in
    the NULL terminates array ARGV.  If INPUT_STRING is not NULL it
    will be fed to stdin of the process.  stderr is logged using
 /* Run the program PGMNAME with the command line arguments given in
    the NULL terminates array ARGV.  If INPUT_STRING is not NULL it
    will be fed to stdin of the process.  stderr is logged using
@@ -51,6 +62,8 @@ gpg_error_t gnupg_exec_tool (const char *pgmname, const char *argv[],
    printed, and an error code returned.  INEXTRA is reserved. */
 gpg_error_t gnupg_exec_tool_stream (const char *pgmname, const char *argv[],
                                     estream_t input, estream_t inextra,
    printed, and an error code returned.  INEXTRA is reserved. */
 gpg_error_t gnupg_exec_tool_stream (const char *pgmname, const char *argv[],
                                     estream_t input, estream_t inextra,
-                                    estream_t output);
+                                    estream_t output,
+                                    exec_tool_status_cb_t status_cb,
+                                    void *status_cb_value);
 
 #endif /* GNUPG_COMMON_EXECTOOL_H */
 
 #endif /* GNUPG_COMMON_EXECTOOL_H */
index d615fd3..6adc1f5 100644 (file)
@@ -932,7 +932,7 @@ gpgtar_create (char **inpattern, int encrypt, int sign)
         }
 
       err = gnupg_exec_tool_stream (opt.gpg_program, argv,
         }
 
       err = gnupg_exec_tool_stream (opt.gpg_program, argv,
-                                    outstream, NULL, cipher_stream);
+                                    outstream, NULL, cipher_stream, NULL, NULL);
       xfree (argv);
       if (err)
         goto leave;
       xfree (argv);
       if (err)
         goto leave;
index c4bf440..866215b 100644 (file)
@@ -327,7 +327,7 @@ gpgtar_extract (const char *filename, int decrypt)
         }
 
       err = gnupg_exec_tool_stream (opt.gpg_program, argv,
         }
 
       err = gnupg_exec_tool_stream (opt.gpg_program, argv,
-                                    cipher_stream, NULL, stream);
+                                    cipher_stream, NULL, stream, NULL, NULL);
       xfree (argv);
       if (err)
         goto leave;
       xfree (argv);
       if (err)
         goto leave;
index a3f85ac..1d59d9c 100644 (file)
@@ -327,7 +327,7 @@ gpgtar_list (const char *filename, int decrypt)
         }
 
       err = gnupg_exec_tool_stream (opt.gpg_program, argv,
         }
 
       err = gnupg_exec_tool_stream (opt.gpg_program, argv,
-                                    cipher_stream, NULL, stream);
+                                    cipher_stream, NULL, stream, NULL, NULL);
       xfree (argv);
       if (err)
         goto leave;
       xfree (argv);
       if (err)
         goto leave;