gpg: Print export statistics to the status-fd.
authorWerner Koch <wk@gnupg.org>
Thu, 12 Nov 2015 15:02:35 +0000 (16:02 +0100)
committerWerner Koch <wk@gnupg.org>
Thu, 12 Nov 2015 15:44:00 +0000 (16:44 +0100)
* common/status.h (STATUS_EXPORT_RES): New.
* g10/main.h (export_stats_t): New.
* g10/export.c (export_stats_s): New.
(export_new_stats, export_release_stats): New.
(export_print_stats): New.
(export_pubkeys, export_seckeys, export_secsubkeys)
(export_pubkey_buffer, do_export): Add arg "stats".
(do_export_stream): Add arg stats and update it.
* g10/gpg.c (main) <aExport, aExportSecret, aExportSecretSub>: Create,
pass, and print a stats object to the export function calls.

* g10/export.c (export_pubkeys_stream): Remove unused function.

Signed-off-by: Werner Koch <wk@gnupg.org>
common/status.h
doc/DETAILS
g10/export.c
g10/gpg.c
g10/gpgv.c
g10/keylist.c
g10/keyserver.c
g10/main.h
g10/test-stubs.c

index 76b1b30..3409167 100644 (file)
@@ -55,12 +55,15 @@ enum
     STATUS_GOODMDC,
     STATUS_BADMDC,
     STATUS_ERRMDC,
+
     STATUS_IMPORTED,
     STATUS_IMPORT_OK,
     STATUS_IMPORT_PROBLEM,
     STATUS_IMPORT_RES,
     STATUS_IMPORT_CHECK,
 
+    STATUS_EXPORT_RES,
+
     STATUS_FILE_START,
     STATUS_FILE_DONE,
     STATUS_FILE_ERROR,
index 97079b0..aa5a57b 100644 (file)
@@ -768,6 +768,16 @@ pkd:0:1024:B665B1435F4C2 .... FF26ABB:
     - <not_imported>
     - <skipped_v3_keys>
 
+*** EXPORT_RES <args>
+
+    Final statistics on export process (this is one long line). The
+    args are a list of unsigned numbers separated by white space:
+
+    - <count>
+    - <secret_count>
+    - <exported>
+
+
 ** Smartcard related
 *** CARDCTRL <what> [<serialno>]
     This is used to control smartcard operations.  Defined values for
index 2e9e61c..d84ff74 100644 (file)
@@ -46,14 +46,28 @@ struct subkey_list_s
 typedef struct subkey_list_s *subkey_list_t;
 
 
-static int do_export (ctrl_t ctrl,
-                      strlist_t users, int secret, unsigned int options );
+/* An object to track statistics for export operations.  */
+struct export_stats_s
+{
+  ulong count;            /* Number of processed keys.        */
+  ulong secret_count;     /* Number of secret keys seen.      */
+  ulong exported;         /* Number of actual exported keys.  */
+};
+
+
+/* Local prototypes.  */
+static int do_export (ctrl_t ctrl, strlist_t users, int secret,
+                      unsigned int options, export_stats_t stats);
 static int do_export_stream (ctrl_t ctrl, iobuf_t out,
                              strlist_t users, int secret,
                              kbnode_t *keyblock_out, unsigned int options,
-                            int *any);
+                            export_stats_t stats, int *any);
 
+\f
 
+
+/* Option parser for export options.  See parse_options fro
+   details.  */
 int
 parse_export_options(char *str,unsigned int *options,int noisy)
 {
@@ -85,39 +99,102 @@ parse_export_options(char *str,unsigned int *options,int noisy)
 }
 
 
-/****************
- * Export the public keys (to standard out or --output).
- * Depending on opt.armor the output is armored.
- * options are defined in main.h.
- * If USERS is NULL, the complete ring will be exported.  */
+/* Create a new export stats object initialized to zero.  On error
+   returns NULL and sets ERRNO.  */
+export_stats_t
+export_new_stats (void)
+{
+  export_stats_t stats;
+
+  return xtrycalloc (1, sizeof *stats);
+}
+
+
+/* Release an export stats object.  */
+void
+export_release_stats (export_stats_t stats)
+{
+  xfree (stats);
+}
+
+
+/* Print export statistics using the status interface.  */
+void
+export_print_stats (export_stats_t stats)
+{
+  if (!stats)
+    return;
+
+  if (is_status_enabled ())
+    {
+      char buf[15*20];
+
+      snprintf (buf, sizeof buf, "%lu %lu %lu",
+               stats->count,
+               stats->secret_count,
+               stats->exported );
+      write_status_text (STATUS_EXPORT_RES, buf);
+    }
+}
+
+
+/*
+ * Export public keys (to stdout or to --output FILE).
+ *
+ * Depending on opt.armor the output is armored.  OPTIONS are defined
+ * in main.h.  If USERS is NULL, all keys will be exported.  STATS is
+ * either an export stats object for update or NULL.
+ *
+ * This function is the core of "gpg --export".
+ */
 int
-export_pubkeys (ctrl_t ctrl, strlist_t users, unsigned int options )
+export_pubkeys (ctrl_t ctrl, strlist_t users, unsigned int options,
+                export_stats_t stats)
 {
-  return do_export (ctrl, users, 0, options );
+  return do_export (ctrl, users, 0, options, stats);
 }
 
-/****************
- * Export to an already opened stream; return -1 if no keys have
- * been exported
+
+/*
+ * Export secret keys (to stdout or to --output FILE).
+ *
+ * Depending on opt.armor the output is armored.  If USERS is NULL,
+ * all secret keys will be exported.  STATS is either an export stats
+ * object for update or NULL.
+ *
+ * This function is the core of "gpg --export-secret-keys".
  */
 int
-export_pubkeys_stream (ctrl_t ctrl, iobuf_t out, strlist_t users,
-                      kbnode_t *keyblock_out, unsigned int options )
+export_seckeys (ctrl_t ctrl, strlist_t users, export_stats_t stats)
 {
-  int any, rc;
+  return do_export (ctrl, users, 1, 0, stats);
+}
 
-  rc = do_export_stream (ctrl, out, users, 0, keyblock_out, options, &any);
-  if (!rc && !any)
-    rc = -1;
-  return rc;
+
+/*
+ * Export secret sub keys (to stdout or to --output FILE).
+ *
+ * This is the same as export_seckeys but replaces the primary key by
+ * a stub key.  Depending on opt.armor the output is armored.  If
+ * USERS is NULL, all secret subkeys will be exported.  STATS is
+ * either an export stats object for update or NULL.
+ *
+ * This function is the core of "gpg --export-secret-subkeys".
+ */
+int
+export_secsubkeys (ctrl_t ctrl, strlist_t users, export_stats_t stats)
+{
+  return do_export (ctrl, users, 2, 0, stats);
 }
 
 
 /*
- * Export a single key into a memory buffer.
+ * Export a single key into a memory buffer.  STATS is either an
+ * export stats object for update or NULL.
  */
 gpg_error_t
 export_pubkey_buffer (ctrl_t ctrl, const char *keyspec, unsigned int options,
+                      export_stats_t stats,
                       kbnode_t *r_keyblock, void **r_data, size_t *r_datalen)
 {
   gpg_error_t err;
@@ -134,7 +211,8 @@ export_pubkey_buffer (ctrl_t ctrl, const char *keyspec, unsigned int options,
     return gpg_error_from_syserror ();
 
   iobuf = iobuf_temp ();
-  err = do_export_stream (ctrl, iobuf, helplist, 0, r_keyblock, options, &any);
+  err = do_export_stream (ctrl, iobuf, helplist, 0, r_keyblock, options,
+                          stats, &any);
   if (!err && !any)
     err = gpg_error (GPG_ERR_NOT_FOUND);
   if (!err)
@@ -166,26 +244,14 @@ export_pubkey_buffer (ctrl_t ctrl, const char *keyspec, unsigned int options,
 }
 
 
-int
-export_seckeys (ctrl_t ctrl, strlist_t users )
-{
-  return do_export (ctrl, users, 1, 0);
-}
-
-int
-export_secsubkeys (ctrl_t ctrl, strlist_t users )
-{
-  return do_export (ctrl, users, 2, 0);
-}
-
-
 /* Export the keys identified by the list of strings in USERS.  If
    Secret is false public keys will be exported.  With secret true
    secret keys will be exported; in this case 1 means the entire
    secret keyblock and 2 only the subkeys.  OPTIONS are the export
    options to apply.  */
 static int
-do_export (ctrl_t ctrl, strlist_t users, int secret, unsigned int options )
+do_export (ctrl_t ctrl, strlist_t users, int secret, unsigned int options,
+           export_stats_t stats)
 {
   IOBUF out = NULL;
   int any, rc;
@@ -205,7 +271,7 @@ do_export (ctrl_t ctrl, strlist_t users, int secret, unsigned int options )
       push_armor_filter (afx, out);
     }
 
-  rc = do_export_stream (ctrl, out, users, secret, NULL, options, &any );
+  rc = do_export_stream (ctrl, out, users, secret, NULL, options, stats, &any);
 
   if ( rc || !any )
     iobuf_cancel (out);
@@ -754,7 +820,8 @@ transfer_format_to_openpgp (gcry_sexp_t s_pgp, PKT_public_key *pk)
    key has been exported true is stored at ANY. */
 static int
 do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
-                 kbnode_t *keyblock_out, unsigned int options, int *any)
+                 kbnode_t *keyblock_out, unsigned int options,
+                  export_stats_t stats, int *any)
 {
   gpg_error_t err = 0;
   PACKET pkt;
@@ -767,7 +834,10 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
   strlist_t sl;
   gcry_cipher_hd_t cipherhd = NULL;
   char *cache_nonce = NULL;
+  struct export_stats_s dummystats;
 
+  if (!stats)
+    stats = &dummystats;
   *any = 0;
   init_packet (&pkt);
   kdbhd = keydb_new ();
@@ -877,6 +947,7 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
           log_error ("public key packet not found in keyblock - skipped\n");
           continue;
         }
+      stats->count++;
       setup_main_keyids (keyblock);  /* gpg_format_keydesc needs it.  */
       pk = node->pkt->pkt.public_key;
       keyid_from_pk (pk, keyid);
@@ -906,6 +977,7 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
                         "not yet supported - skipped\n", keystr (keyid));
               continue;
             }
+          stats->secret_count++;
         }
 
       /* Always do the cleaning on the public key part if requested.
@@ -1109,6 +1181,8 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
                     }
 
                   err = build_packet (out, node->pkt);
+                  if (!err && node->pkt->pkttype == PKT_PUBLIC_KEY)
+                    stats->exported++;
                 }
               else if (!err)
                 {
@@ -1164,6 +1238,8 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
                     goto unwraperror;
 
                   err = build_packet (out, node->pkt);
+                  if (!err && node->pkt->pkttype == PKT_PUBLIC_KEY)
+                    stats->exported++;
                   goto unwraperror_leave;
 
                 unwraperror:
@@ -1201,8 +1277,11 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
           else
             {
               err = build_packet (out, node->pkt);
+              if (!err && node->pkt->pkttype == PKT_PUBLIC_KEY)
+                stats->exported++;
             }
 
+
           if (err)
             {
               log_error ("build_packet(%d) failed: %s\n",
index e47b7f5..36e6542 100644 (file)
--- a/g10/gpg.c
+++ b/g10/gpg.c
@@ -4306,7 +4306,12 @@ main (int argc, char **argv)
        else if( cmd == aRecvKeys )
             rc = keyserver_import (ctrl, sl );
        else
-            rc = export_pubkeys (ctrl, sl, opt.export_options);
+          {
+            export_stats_t stats = export_new_stats ();
+            rc = export_pubkeys (ctrl, sl, opt.export_options, stats);
+            export_print_stats (stats);
+            export_release_stats (stats);
+          }
        if(rc)
          {
            if(cmd==aSendKeys)
@@ -4372,7 +4377,12 @@ main (int argc, char **argv)
        sl = NULL;
        for( ; argc; argc--, argv++ )
            add_to_strlist2( &sl, *argv, utf8_strings );
-       export_seckeys (ctrl, sl);
+        {
+          export_stats_t stats = export_new_stats ();
+          export_seckeys (ctrl, sl, stats);
+          export_print_stats (stats);
+          export_release_stats (stats);
+        }
        free_strlist(sl);
        break;
 
@@ -4380,7 +4390,12 @@ main (int argc, char **argv)
        sl = NULL;
        for( ; argc; argc--, argv++ )
            add_to_strlist2( &sl, *argv, utf8_strings );
-       export_secsubkeys (ctrl, sl);
+        {
+          export_stats_t stats = export_new_stats ();
+          export_secsubkeys (ctrl, sl, stats);
+          export_print_stats (stats);
+          export_release_stats (stats);
+        }
        free_strlist(sl);
        break;
 
index 138f035..d39eb66 100644 (file)
@@ -606,11 +606,13 @@ gpg_dirmngr_get_pka (ctrl_t ctrl, const char *userid,
 
 gpg_error_t
 export_pubkey_buffer (ctrl_t ctrl, const char *keyspec, unsigned int options,
+                      export_stats_t stats,
                       kbnode_t *r_keyblock, void **r_data, size_t *r_datalen)
 {
   (void)ctrl;
   (void)keyspec;
   (void)options;
+  (void)stats;
 
   *r_keyblock = NULL;
   *r_data = NULL;
index cc97846..f3fd9d9 100644 (file)
@@ -906,7 +906,7 @@ list_keyblock_pka (ctrl_t ctrl, kbnode_t keyblock)
       /* We do not have an export fucntion which allows to pass a
          keyblock, thus we need to search the key again.  */
       err = export_pubkey_buffer (ctrl, hexfpr,
-                                  EXPORT_DANE_FORMAT,
+                                  EXPORT_DANE_FORMAT, NULL,
                                   &dummy_keyblock, &data, &datalen);
       release_kbnode (dummy_keyblock);
       if (!err)
index 37e62fd..72c244a 100644 (file)
@@ -1796,6 +1796,7 @@ keyserver_put (ctrl_t ctrl, strlist_t keyspecs,
 
       err = export_pubkey_buffer (ctrl, kspec->d,
                                   opt.keyserver_options.export_options,
+                                  NULL,
                                   &keyblock, &data, &datalen);
       if (err)
         log_error (_("skipped \"%s\": %s\n"), kspec->d, gpg_strerror (err));
index cdf6031..be4be29 100644 (file)
@@ -339,16 +339,25 @@ int collapse_uids( KBNODE *keyblock );
 
 
 /*-- export.c --*/
+struct export_stats_s;
+typedef struct export_stats_s *export_stats_t;
+
+export_stats_t export_new_stats (void);
+void export_release_stats (export_stats_t stats);
+void export_print_stats (export_stats_t stats);
+
 int parse_export_options(char *str,unsigned int *options,int noisy);
-int export_pubkeys (ctrl_t ctrl, strlist_t users, unsigned int options );
-int export_pubkeys_stream (ctrl_t ctrl, iobuf_t out, strlist_t users,
-                          kbnode_t *keyblock_out, unsigned int options );
+
+int export_pubkeys (ctrl_t ctrl, strlist_t users, unsigned int options,
+                    export_stats_t stats);
+int export_seckeys (ctrl_t ctrl, strlist_t users, export_stats_t stats);
+int export_secsubkeys (ctrl_t ctrl, strlist_t users, export_stats_t stats);
+
 gpg_error_t export_pubkey_buffer (ctrl_t ctrl, const char *keyspec,
                                   unsigned int options,
+                                  export_stats_t stats,
                                   kbnode_t *r_keyblock,
                                   void **r_data, size_t *r_datalen);
-int export_seckeys (ctrl_t ctrl, strlist_t users);
-int export_secsubkeys (ctrl_t ctrl, strlist_t users);
 
 /*-- dearmor.c --*/
 int dearmor_file( const char *fname );
index 0aa89b2..0e6616c 100644 (file)
@@ -418,11 +418,13 @@ gpg_dirmngr_get_pka (ctrl_t ctrl, const char *userid,
 
 gpg_error_t
 export_pubkey_buffer (ctrl_t ctrl, const char *keyspec, unsigned int options,
+                      export_stats_t stats,
                       kbnode_t *r_keyblock, void **r_data, size_t *r_datalen)
 {
   (void)ctrl;
   (void)keyspec;
   (void)options;
+  (void)stats;
 
   *r_keyblock = NULL;
   *r_data = NULL;