diff --git a/sm/gpgsm.c b/sm/gpgsm.c index 26b05773c..bea0184e3 100644 --- a/sm/gpgsm.c +++ b/sm/gpgsm.c @@ -1803,6 +1803,10 @@ main ( int argc, char **argv) gnupg_inhibit_set_foregound_window (1); } + /* Better make sure that we have a statusfp so that a failure status + * in gpgsm_exit can work even w/o any preeding status messages. */ + gpgsm_init_statusfp (&ctrl); + /* Add default keybox. */ if (!nrings && default_keyring && !opt.use_keyboxd) { @@ -2356,6 +2360,12 @@ gpgsm_exit (int rc) else if (opt.assert_signer_list && !assert_signer_true) rc = 1; + /* If we had an error but not printed an error message, do it now. + * Note that the function will never print a second failure status + * line. */ + if (rc) + gpgsm_exit_failure_status (); + gcry_control (GCRYCTL_UPDATE_RANDOM_SEED_FILE); if (opt.debug & DBG_MEMSTAT_VALUE) { diff --git a/sm/gpgsm.h b/sm/gpgsm.h index 916d0235c..cd45ec101 100644 --- a/sm/gpgsm.h +++ b/sm/gpgsm.h @@ -355,12 +355,14 @@ int gpgsm_parse_validation_model (const char *model); /*-- server.c --*/ void gpgsm_server (certlist_t default_recplist); +void gpgsm_init_statusfp (ctrl_t ctrl); gpg_error_t gpgsm_status (ctrl_t ctrl, int no, const char *text); gpg_error_t gpgsm_status2 (ctrl_t ctrl, int no, ...) GPGRT_ATTR_SENTINEL(0); gpg_error_t gpgsm_status_with_err_code (ctrl_t ctrl, int no, const char *text, gpg_err_code_t ec); gpg_error_t gpgsm_status_with_error (ctrl_t ctrl, int no, const char *text, gpg_error_t err); +void gpgsm_exit_failure_status (void); gpg_error_t gpgsm_progress_cb (ctrl_t ctrl, uint64_t current, uint64_t total); gpg_error_t gpgsm_proxy_pinentry_notify (ctrl_t ctrl, const unsigned char *line); diff --git a/sm/keylist.c b/sm/keylist.c index a29c7d792..41e7ca309 100644 --- a/sm/keylist.c +++ b/sm/keylist.c @@ -1663,6 +1663,7 @@ list_internal_keys (ctrl_t ctrl, strlist_t names, estream_t fp, resname = keydb_get_resource_name (hd); + es_clearerr (fp); if (lastresname != resname ) { int i; @@ -1716,6 +1717,20 @@ list_internal_keys (ctrl_t ctrl, strlist_t names, estream_t fp, ksba_cert_release (lastcert); lastcert = cert; cert = NULL; + + if (es_ferror (fp)) + rc = gpg_error_from_syserror (); + + /* For faster key listings we flush the output after each cert + * only if we list secret keys. */ + if ((mode & 2) && es_fflush (fp) && !rc) + rc = gpg_error_from_syserror (); + + if (rc) + { + log_error (_("error writing to output: %s\n"), gpg_strerror (rc)); + goto leave; + } } if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND) rc = 0; diff --git a/sm/server.c b/sm/server.c index cb3fae24d..345c3167b 100644 --- a/sm/server.c +++ b/sm/server.c @@ -37,6 +37,11 @@ #define set_error(e,t) assuan_set_error (ctx, gpg_error (e), (t)) +/* Used to track whether we printed any FAILURE status in non-server + * mode. */ +static int any_failure_printed; + + /* The filepointer for status message used in non-server mode */ static FILE *statusfp; @@ -1515,6 +1520,24 @@ gpgsm_server (certlist_t default_recplist) } +void +gpgsm_init_statusfp (ctrl_t ctrl) +{ + if (statusfp || ctrl->status_fd == -1) + return; + + if (ctrl->status_fd == 1) + statusfp = stdout; + else if (ctrl->status_fd == 2) + statusfp = stderr; + else + statusfp = fdopen (ctrl->status_fd, "w"); + + if (!statusfp) + log_fatal ("can't open fd %d for status output: %s\n", + ctrl->status_fd, strerror(errno)); +} + gpg_error_t gpgsm_status2 (ctrl_t ctrl, int no, ...) @@ -1527,23 +1550,11 @@ gpgsm_status2 (ctrl_t ctrl, int no, ...) if (ctrl->no_server && ctrl->status_fd == -1) ; /* No status wanted. */ + else if (ctrl->no_server && no == STATUS_FAILURE && any_failure_printed) + ; /* Don't emit FAILURE a second time. */ else if (ctrl->no_server) { - if (!statusfp) - { - if (ctrl->status_fd == 1) - statusfp = stdout; - else if (ctrl->status_fd == 2) - statusfp = stderr; - else - statusfp = fdopen (ctrl->status_fd, "w"); - - if (!statusfp) - { - log_fatal ("can't open fd %d for status output: %s\n", - ctrl->status_fd, strerror(errno)); - } - } + gpgsm_init_statusfp (ctrl); fputs ("[GNUPG:] ", statusfp); fputs (get_status_string (no), statusfp); @@ -1562,6 +1573,10 @@ gpgsm_status2 (ctrl_t ctrl, int no, ...) } } putc ('\n', statusfp); + + if (no == STATUS_FAILURE) + any_failure_printed = 1; + if (ferror (statusfp)) err = gpg_error_from_syserror (); else @@ -1614,6 +1629,23 @@ gpgsm_status_with_error (ctrl_t ctrl, int no, const char *text, } +/* Function to print a FAILURE status line on exit. */ +void +gpgsm_exit_failure_status (void) +{ + /* stderr is used as a last but possible wrong resort if no status + * has yet been printed. */ + FILE *fp = statusfp? statusfp : stderr; + + if (any_failure_printed) + return; + + fputs ("[GNUPG:] ", fp); + fputs (get_status_string (STATUS_FAILURE), fp); + fputs (" gpgsm-exit 50331649\n", fp); +} + + /* This callback is used to emit progress status lines. */ gpg_error_t gpgsm_progress_cb (ctrl_t ctrl, uint64_t current, uint64_t total)