From e3c48335f9c5081c6080bceafa7a04140403427a Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 12 Nov 2015 16:02:35 +0100 Subject: [PATCH] gpg: Print export statistics to the status-fd. * 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) : 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 --- common/status.h | 3 + doc/DETAILS | 10 +++ g10/export.c | 163 +++++++++++++++++++++++++++++++++++------------ g10/gpg.c | 21 +++++- g10/gpgv.c | 2 + g10/keylist.c | 2 +- g10/keyserver.c | 1 + g10/main.h | 19 ++++-- g10/test-stubs.c | 2 + 9 files changed, 172 insertions(+), 51 deletions(-) diff --git a/common/status.h b/common/status.h index 76b1b304f..340916719 100644 --- a/common/status.h +++ b/common/status.h @@ -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, diff --git a/doc/DETAILS b/doc/DETAILS index 97079b0f0..aa5a57b32 100644 --- a/doc/DETAILS +++ b/doc/DETAILS @@ -768,6 +768,16 @@ pkd:0:1024:B665B1435F4C2 .... FF26ABB: - - +*** EXPORT_RES + + Final statistics on export process (this is one long line). The + args are a list of unsigned numbers separated by white space: + + - + - + - + + ** Smartcard related *** CARDCTRL [] This is used to control smartcard operations. Defined values for diff --git a/g10/export.c b/g10/export.c index 2e9e61c69..d84ff7459 100644 --- a/g10/export.c +++ b/g10/export.c @@ -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); + + +/* 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. */ -int -export_pubkeys (ctrl_t ctrl, strlist_t users, unsigned int options ) +/* Create a new export stats object initialized to zero. On error + returns NULL and sets ERRNO. */ +export_stats_t +export_new_stats (void) { - return do_export (ctrl, users, 0, options ); + export_stats_t stats; + + return xtrycalloc (1, sizeof *stats); } -/**************** - * Export to an already opened stream; return -1 if no keys have - * been exported - */ -int -export_pubkeys_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, - kbnode_t *keyblock_out, unsigned int options ) -{ - int any, rc; - rc = do_export_stream (ctrl, out, users, 0, keyblock_out, options, &any); - if (!rc && !any) - rc = -1; - return rc; +/* 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 a single key into a memory buffer. + * 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_stats_t stats) +{ + return do_export (ctrl, users, 0, options, stats); +} + + +/* + * 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_seckeys (ctrl_t ctrl, strlist_t users, export_stats_t stats) +{ + return do_export (ctrl, users, 1, 0, stats); +} + + +/* + * 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. 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", diff --git a/g10/gpg.c b/g10/gpg.c index e47b7f5d7..36e65425b 100644 --- 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; diff --git a/g10/gpgv.c b/g10/gpgv.c index 138f03581..d39eb6622 100644 --- a/g10/gpgv.c +++ b/g10/gpgv.c @@ -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; diff --git a/g10/keylist.c b/g10/keylist.c index cc9784663..f3fd9d99a 100644 --- a/g10/keylist.c +++ b/g10/keylist.c @@ -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) diff --git a/g10/keyserver.c b/g10/keyserver.c index 37e62fd18..72c244a5d 100644 --- a/g10/keyserver.c +++ b/g10/keyserver.c @@ -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)); diff --git a/g10/main.h b/g10/main.h index cdf60315c..be4be296a 100644 --- a/g10/main.h +++ b/g10/main.h @@ -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 ); diff --git a/g10/test-stubs.c b/g10/test-stubs.c index 0aa89b2ff..0e6616cb9 100644 --- a/g10/test-stubs.c +++ b/g10/test-stubs.c @@ -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;