[Libguestfs] [PATCH 2/2] Use 'error' function for fprintf followed by exit.

Richard W.M. Jones rjones at redhat.com
Mon Apr 4 12:28:51 UTC 2016


Like with the previous commit, this replaces instances of:

  if (something_bad) {
    fprintf (stderr, "%s: error message\n", guestfs_int_program_name);
    exit (EXIT_FAILURE);
  }

with:

  if (something_bad)
    error (EXIT_FAILURE, 0, "error message");

(except in a few cases were errno was incorrectly being ignored, in
which case I have fixed that).

It's slightly more complex than the previous commit because we must be
careful to:

 - Remove the program name (since error(3) prints it).

 - Remove any trailing \n character from the message.

Candidates for replacement were found using:

  pcregrep --buffer-size 10M -M '\bfprintf\b.*\n.*\bexit\b' `git ls-files`
---
 align/scan.c                               |   7 +-
 cat/cat.c                                  |  16 ++--
 cat/filesystems.c                          |  24 +++---
 cat/log.c                                  |  17 ++--
 cat/ls.c                                   |  31 +++----
 daemon/lvm-filter.c                        |   8 +-
 daemon/mount.c                             |  26 +++---
 daemon/proto.c                             |  80 ++++++------------
 df/main.c                                  |  34 +++-----
 diff/diff.c                                |  36 +++------
 edit/edit.c                                |  30 +++----
 fish/fish.c                                |  73 ++++++-----------
 format/format.c                            |  55 +++++--------
 fuse/guestmount.c                          |  75 ++++++-----------
 inspector/inspector.c                      |  96 +++++++---------------
 make-fs/make-fs.c                          |  17 ++--
 p2v/gui.c                                  |  12 +--
 p2v/kernel.c                               |  58 ++++++-------
 p2v/ssh.c                                  |   6 +-
 rescue/rescue.c                            |  57 +++++--------
 src/libvirt-is-version.c                   |  12 +--
 test-tool/Makefile.am                      |   5 +-
 test-tool/test-tool.c                      | 125 +++++++++--------------------
 tests/c-api/test-add-drive-opts.c          |   8 +-
 tests/c-api/test-add-libvirt-dom.c         |  32 +++-----
 tests/c-api/test-backend-settings.c        |  13 ++-
 tests/c-api/test-command.c                 |  13 ++-
 tests/c-api/test-config.c                  |  20 ++---
 tests/c-api/test-create-handle.c           |   8 +-
 tests/c-api/test-debug-to-file.c           |   6 +-
 tests/c-api/test-dlopen.c                  |  34 +++-----
 tests/c-api/test-last-errno.c              |  55 +++++--------
 tests/c-api/test-private-data.c            |   8 +-
 tests/c-api/test-user-cancel.c             |  42 ++++------
 tests/c-api/tests-main.c                   |  32 +++-----
 tests/events/test-libvirt-auth-callbacks.c |  49 +++++------
 tests/qemu/qemu-boot.c                     |  46 ++++-------
 tests/regressions/rhbz790721.c             |  12 +--
 38 files changed, 457 insertions(+), 821 deletions(-)

diff --git a/align/scan.c b/align/scan.c
index 1185293..db6eb19 100644
--- a/align/scan.c
+++ b/align/scan.c
@@ -26,6 +26,7 @@
 #include <unistd.h>
 #include <getopt.h>
 #include <errno.h>
+#include <error.h>
 #include <locale.h>
 #include <assert.h>
 #include <libintl.h>
@@ -130,10 +131,8 @@ main (int argc, char *argv[])
   int r;
 
   g = guestfs_create ();
-  if (g == NULL) {
-    fprintf (stderr, _("guestfs_create: failed to create handle\n"));
-    exit (EXIT_FAILURE);
-  }
+  if (g == NULL)
+    error (EXIT_FAILURE, errno, "guestfs_create");
 
   for (;;) {
     c = getopt_long (argc, argv, options, long_options, &option_index);
diff --git a/cat/cat.c b/cat/cat.c
index c90fc06..0370fbd 100644
--- a/cat/cat.c
+++ b/cat/cat.c
@@ -116,10 +116,8 @@ main (int argc, char *argv[])
   int option_index;
 
   g = guestfs_create ();
-  if (g == NULL) {
-    fprintf (stderr, _("guestfs_create: failed to create handle\n"));
-    exit (EXIT_FAILURE);
-  }
+  if (g == NULL)
+    error (EXIT_FAILURE, errno, "guestfs_create");
 
   for (;;) {
     c = getopt_long (argc, argv, options, long_options, &option_index);
@@ -137,12 +135,10 @@ main (int argc, char *argv[])
         echo_keys = 1;
       } else if (STREQ (long_options[option_index].name, "format")) {
         OPTION_format;
-      } else {
-        fprintf (stderr, _("%s: unknown long option: %s (%d)\n"),
-                 guestfs_int_program_name,
-                 long_options[option_index].name, option_index);
-        exit (EXIT_FAILURE);
-      }
+      } else
+        error (EXIT_FAILURE, 0,
+               _("unknown long option: %s (%d)"),
+               long_options[option_index].name, option_index);
       break;
 
     case 'a':
diff --git a/cat/filesystems.c b/cat/filesystems.c
index 6f083d3..3f9d931 100644
--- a/cat/filesystems.c
+++ b/cat/filesystems.c
@@ -185,10 +185,8 @@ main (int argc, char *argv[])
   int title;
 
   g = guestfs_create ();
-  if (g == NULL) {
-    fprintf (stderr, _("guestfs_create: failed to create handle\n"));
-    exit (EXIT_FAILURE);
-  }
+  if (g == NULL)
+    error (EXIT_FAILURE, errno, "guestfs_create");
 
   for (;;) {
     c = getopt_long (argc, argv, options, long_options, &option_index);
@@ -238,12 +236,10 @@ main (int argc, char *argv[])
                  STREQ (long_options[option_index].name, "volgroups") ||
                  STREQ (long_options[option_index].name, "volume-groups")) {
         output |= OUTPUT_VGS;
-      } else {
-        fprintf (stderr, _("%s: unknown long option: %s (%d)\n"),
-                 guestfs_int_program_name,
-                 long_options[option_index].name, option_index);
-        exit (EXIT_FAILURE);
-      }
+      } else
+        error (EXIT_FAILURE, 0,
+               _("unknown long option: %s (%d)"),
+               long_options[option_index].name, option_index);
       break;
 
     case 'a':
@@ -303,11 +299,9 @@ main (int argc, char *argv[])
   /* -h and --csv doesn't make sense.  Spreadsheets will corrupt these
    * fields.  (RHBZ#600977).
    */
-  if (human && csv) {
-    fprintf (stderr, _("%s: you cannot use -h and --csv options together.\n"),
-             guestfs_int_program_name);
-    exit (EXIT_FAILURE);
-  }
+  if (human && csv)
+    error (EXIT_FAILURE, 0,
+           _("you cannot use -h and --csv options together."));
 
   /* Nothing selected for output, means --filesystems is implied. */
   if (output == 0)
diff --git a/cat/log.c b/cat/log.c
index 79761a0..daefda7 100644
--- a/cat/log.c
+++ b/cat/log.c
@@ -26,6 +26,7 @@
 #include <unistd.h>
 #include <getopt.h>
 #include <errno.h>
+#include <error.h>
 #include <locale.h>
 #include <assert.h>
 #include <libintl.h>
@@ -117,10 +118,8 @@ main (int argc, char *argv[])
   int option_index;
 
   g = guestfs_create ();
-  if (g == NULL) {
-    fprintf (stderr, _("guestfs_create: failed to create handle\n"));
-    exit (EXIT_FAILURE);
-  }
+  if (g == NULL)
+    error (EXIT_FAILURE, errno, "guestfs_create");
 
   for (;;) {
     c = getopt_long (argc, argv, options, long_options, &option_index);
@@ -138,12 +137,10 @@ main (int argc, char *argv[])
         echo_keys = 1;
       } else if (STREQ (long_options[option_index].name, "format")) {
         OPTION_format;
-      } else {
-        fprintf (stderr, _("%s: unknown long option: %s (%d)\n"),
-                 guestfs_int_program_name,
-                 long_options[option_index].name, option_index);
-        exit (EXIT_FAILURE);
-      }
+      } else
+        error (EXIT_FAILURE, 0,
+               _("unknown long option: %s (%d)"),
+               long_options[option_index].name, option_index);
       break;
 
     case 'a':
diff --git a/cat/ls.c b/cat/ls.c
index f92bda1..91f2125 100644
--- a/cat/ls.c
+++ b/cat/ls.c
@@ -178,10 +178,8 @@ main (int argc, char *argv[])
   int mode = 0;
 
   g = guestfs_create ();
-  if (g == NULL) {
-    fprintf (stderr, _("guestfs_create: failed to create handle\n"));
-    exit (EXIT_FAILURE);
-  }
+  if (g == NULL)
+    error (EXIT_FAILURE, errno, "guestfs_create");
 
   for (;;) {
     c = getopt_long (argc, argv, options, long_options, &option_index);
@@ -227,11 +225,10 @@ main (int argc, char *argv[])
       } else if (STREQ (long_options[option_index].name, "uid") ||
                  STREQ (long_options[option_index].name, "uids")) {
         enable_uids = 1;
-      } else {
-        fprintf (stderr, _("%s: unknown long option: %s (%d)\n"),
-                 guestfs_int_program_name, long_options[option_index].name, option_index);
-        exit (EXIT_FAILURE);
-      }
+      } else
+        error (EXIT_FAILURE, 0,
+               _("unknown long option: %s (%d)"),
+               long_options[option_index].name, option_index);
       break;
 
     case 'a':
@@ -327,20 +324,16 @@ main (int argc, char *argv[])
   /* Many flags only apply to -lR mode. */
   if (mode != MODE_LS_LR &&
       (csv || human || enable_uids || enable_times || enable_extra_stats ||
-       checksum)) {
-    fprintf (stderr, _("%s: used a flag which can only be combined with -lR mode\nFor more information, read the virt-ls(1) man page.\n"),
-             guestfs_int_program_name);
-    exit (EXIT_FAILURE);
-  }
+       checksum))
+    error (EXIT_FAILURE, 0,
+           _("used a flag which can only be combined with -lR mode\nFor more information, read the virt-ls(1) man page."));
 
   /* CSV && human is unsafe because spreadsheets fail to parse these
    * fields correctly.  (RHBZ#600977).
    */
-  if (human && csv) {
-    fprintf (stderr, _("%s: you cannot use -h and --csv options together.\n"),
-             guestfs_int_program_name);
-    exit (EXIT_FAILURE);
-  }
+  if (human && csv)
+    error (EXIT_FAILURE, 0,
+           _("you cannot use -h and --csv options together."));
 
   /* User must specify at least one directory name on the command line. */
   if (optind >= argc || argc - optind < 1)
diff --git a/daemon/lvm-filter.c b/daemon/lvm-filter.c
index 12c4ca7..eadc472 100644
--- a/daemon/lvm-filter.c
+++ b/daemon/lvm-filter.c
@@ -23,6 +23,8 @@
 #include <inttypes.h>
 #include <string.h>
 #include <unistd.h>
+#include <errno.h>
+#include <error.h>
 #include <sys/stat.h>
 #include <sys/wait.h>
 
@@ -72,10 +74,8 @@ copy_lvm (void)
     return;
   }
 
-  if (mkdtemp (lvm_system_dir) == NULL) {
-    fprintf (stderr, "mkdtemp: %s: %m\n", lvm_system_dir);
-    exit (EXIT_FAILURE);
-  }
+  if (mkdtemp (lvm_system_dir) == NULL)
+    error (EXIT_FAILURE, errno, "mkdtemp: %s", lvm_system_dir);
 
   /* Copy the entire directory */
   snprintf (cmd, sizeof cmd, "%s -a /etc/lvm/ %s", str_cp, lvm_system_dir);
diff --git a/daemon/mount.c b/daemon/mount.c
index 5dd7da2..ef51d48 100644
--- a/daemon/mount.c
+++ b/daemon/mount.c
@@ -22,6 +22,8 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <errno.h>
+#include <error.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <mntent.h>
@@ -49,10 +51,8 @@ is_root_mounted (void)
    * that requires custom parsing code.
    */
   fp = setmntent ("/proc/mounts", "r");
-  if (fp == NULL) {
-    fprintf (stderr, "setmntent: %s: %m\n", "/proc/mounts");
-    exit (EXIT_FAILURE);
-  }
+  if (fp == NULL)
+    error (EXIT_FAILURE, errno, "setmntent: %s", "/proc/mounts");
 
   while ((m = getmntent (fp)) != NULL) {
     /* Allow a mount directory like "/sysroot". */
@@ -91,10 +91,8 @@ is_device_mounted (const char *device)
    * that requires custom parsing code.
    */
   fp = setmntent ("/proc/mounts", "r");
-  if (fp == NULL) {
-    fprintf (stderr, "setmntent: %s: %m\n", "/proc/mounts");
-    exit (EXIT_FAILURE);
-  }
+  if (fp == NULL)
+    error (EXIT_FAILURE, errno, "setmntent: %s", "/proc/mounts");
 
   while ((m = getmntent (fp)) != NULL) {
     if ((sysroot_len > 0 && STREQ (m->mnt_dir, sysroot)) ||
@@ -274,10 +272,8 @@ mounts_or_mountpoints (int mp)
    * that requires custom parsing code.
    */
   fp = setmntent ("/proc/mounts", "r");
-  if (fp == NULL) {
-    fprintf (stderr, "setmntent: %s: %m\n", "/proc/mounts");
-    exit (EXIT_FAILURE);
-  }
+  if (fp == NULL)
+    error (EXIT_FAILURE, errno, "setmntent: %s", "/proc/mounts");
 
   while ((m = getmntent (fp)) != NULL) {
     /* Allow a mount directory like "/sysroot". */
@@ -383,10 +379,8 @@ do_umount_all (void)
    * that requires custom parsing code.
    */
   fp = setmntent ("/proc/mounts", "r");
-  if (fp == NULL) {
-    fprintf (stderr, "setmntent: %s: %m\n", "/proc/mounts");
-    exit (EXIT_FAILURE);
-  }
+  if (fp == NULL)
+    error (EXIT_FAILURE, errno, "setmntent: %s", "/proc/mounts");
 
   while ((m = getmntent (fp)) != NULL) {
     if (verbose) {
diff --git a/daemon/proto.c b/daemon/proto.c
index c3972f1..654dd3a 100644
--- a/daemon/proto.c
+++ b/daemon/proto.c
@@ -107,11 +107,8 @@ main_loop (int _sock)
     if (len == GUESTFS_CANCEL_FLAG)
       continue;
 
-    if (len > GUESTFS_MESSAGE_MAX) {
-      fprintf (stderr, "guestfsd: incoming message is too long (%u bytes)\n",
-               len);
-      exit (EXIT_FAILURE);
-    }
+    if (len > GUESTFS_MESSAGE_MAX)
+      error (EXIT_FAILURE, 0, "incoming message is too long (%u bytes)", len);
 
     buf = malloc (len);
     if (!buf) {
@@ -151,10 +148,8 @@ main_loop (int _sock)
 
     /* Decode the message header. */
     xdrmem_create (&xdr, buf, len, XDR_DECODE);
-    if (!xdr_guestfs_message_header (&xdr, &hdr)) {
-      fprintf (stderr, "guestfsd: could not decode message header\n");
-      exit (EXIT_FAILURE);
-    }
+    if (!xdr_guestfs_message_header (&xdr, &hdr))
+      error (EXIT_FAILURE, 0, "could not decode message header");
 
     /* Check the version etc. */
     if (hdr.prog != GUESTFS_PROGRAM) {
@@ -296,10 +291,8 @@ send_error (int errnum, char *msg)
   hdr.proc = proc_nr;
   hdr.serial = serial;
 
-  if (!xdr_guestfs_message_header (&xdr, &hdr)) {
-    fprintf (stderr, "guestfsd: failed to encode error message header\n");
-    exit (EXIT_FAILURE);
-  }
+  if (!xdr_guestfs_message_header (&xdr, &hdr))
+    error (EXIT_FAILURE, 0, "failed to encode error message header");
 
   /* These strings are not going to be freed.  We just cast them
    * to (char *) because they are defined that way in the XDR structs.
@@ -308,10 +301,8 @@ send_error (int errnum, char *msg)
     (char *) (errnum > 0 ? guestfs_int_errno_to_string (errnum) : "");
   err.error_message = (char *) msg;
 
-  if (!xdr_guestfs_message_error (&xdr, &err)) {
-    fprintf (stderr, "guestfsd: failed to encode error message body\n");
-    exit (EXIT_FAILURE);
-  }
+  if (!xdr_guestfs_message_error (&xdr, &err))
+    error (EXIT_FAILURE, 0, "failed to encode error message body");
 
   len = xdr_getpos (&xdr);
   xdr_destroy (&xdr);
@@ -320,14 +311,10 @@ send_error (int errnum, char *msg)
   xdr_u_int (&xdr, &len);
   xdr_destroy (&xdr);
 
-  if (xwrite (sock, lenbuf, 4) == -1) {
-    fprintf (stderr, "guestfsd: xwrite failed\n");
-    exit (EXIT_FAILURE);
-  }
-  if (xwrite (sock, buf, len) == -1) {
-    fprintf (stderr, "guestfsd: xwrite failed\n");
-    exit (EXIT_FAILURE);
-  }
+  if (xwrite (sock, lenbuf, 4) == -1)
+    error (EXIT_FAILURE, 0, "xwrite failed");
+  if (xwrite (sock, buf, len) == -1)
+    error (EXIT_FAILURE, 0, "xwrite failed");
 }
 
 void
@@ -352,10 +339,8 @@ reply (xdrproc_t xdrp, char *ret)
   hdr.proc = proc_nr;
   hdr.serial = serial;
 
-  if (!xdr_guestfs_message_header (&xdr, &hdr)) {
-    fprintf (stderr, "guestfsd: failed to encode reply header\n");
-    exit (EXIT_FAILURE);
-  }
+  if (!xdr_guestfs_message_header (&xdr, &hdr))
+    error (EXIT_FAILURE, 0, "failed to encode reply header");
 
   if (xdrp) {
     /* This can fail if the reply body is too large, for example
@@ -376,14 +361,10 @@ reply (xdrproc_t xdrp, char *ret)
   xdr_u_int (&xdr, &len);
   xdr_destroy (&xdr);
 
-  if (xwrite (sock, lenbuf, 4) == -1) {
-    fprintf (stderr, "guestfsd: xwrite failed\n");
-    exit (EXIT_FAILURE);
-  }
-  if (xwrite (sock, buf, (size_t) len) == -1) {
-    fprintf (stderr, "guestfsd: xwrite failed\n");
-    exit (EXIT_FAILURE);
-  }
+  if (xwrite (sock, lenbuf, 4) == -1)
+    error (EXIT_FAILURE, 0, "xwrite failed");
+  if (xwrite (sock, buf, (size_t) len) == -1)
+    error (EXIT_FAILURE, 0, "xwrite failed");
 }
 
 /* Receive file chunks, repeatedly calling 'cb'. */
@@ -413,11 +394,8 @@ receive_file (receive_cb cb, void *opaque)
     if (len == GUESTFS_CANCEL_FLAG)
       continue;			/* Just ignore it. */
 
-    if (len > GUESTFS_MESSAGE_MAX) {
-      fprintf (stderr, "guestfsd: incoming message is too long (%u bytes)\n",
-               len);
-      exit (EXIT_FAILURE);
-    }
+    if (len > GUESTFS_MESSAGE_MAX)
+      error (EXIT_FAILURE, 0, "incoming message is too long (%u bytes)", len);
 
     buf = malloc (len);
     if (!buf) {
@@ -617,10 +595,8 @@ send_chunk (const guestfs_chunk *chunk)
 
   int err = (xwrite (sock, lenbuf, 4) == 0
              && xwrite (sock, buf, len) == 0 ? 0 : -1);
-  if (err) {
-    fprintf (stderr, "guestfsd: send_chunk: write failed\n");
-    exit (EXIT_FAILURE);
-  }
+  if (err)
+    error (EXIT_FAILURE, 0, "send_chunk: write failed");
 
   return err;
 }
@@ -684,10 +660,8 @@ notify_progress_no_ratelimit (uint64_t position, uint64_t total,
   xdr_u_int (&xdr, &i);
   xdr_destroy (&xdr);
 
-  if (xwrite (sock, buf, 4) == -1) {
-    fprintf (stderr, "guestfsd: xwrite failed\n");
-    exit (EXIT_FAILURE);
-  }
+  if (xwrite (sock, buf, 4) == -1)
+    error (EXIT_FAILURE, 0, "xwrite failed");
 
   message.proc = proc_nr;
   message.serial = serial;
@@ -703,10 +677,8 @@ notify_progress_no_ratelimit (uint64_t position, uint64_t total,
   len = xdr_getpos (&xdr);
   xdr_destroy (&xdr);
 
-  if (xwrite (sock, buf, len) == -1) {
-    fprintf (stderr, "guestfsd: xwrite failed\n");
-    exit (EXIT_FAILURE);
-  }
+  if (xwrite (sock, buf, len) == -1)
+    error (EXIT_FAILURE, 0, "xwrite failed");
 }
 
 /* "Pulse mode" progress messages. */
diff --git a/df/main.c b/df/main.c
index 8866151..e04b14e 100644
--- a/df/main.c
+++ b/df/main.c
@@ -131,10 +131,8 @@ main (int argc, char *argv[])
   int err;
 
   g = guestfs_create ();
-  if (g == NULL) {
-    fprintf (stderr, _("guestfs_create: failed to create handle\n"));
-    exit (EXIT_FAILURE);
-  }
+  if (g == NULL)
+    error (EXIT_FAILURE, errno, "guestfs_create");
 
   for (;;) {
     c = getopt_long (argc, argv, options, long_options, &option_index);
@@ -154,11 +152,10 @@ main (int argc, char *argv[])
         /* nothing - left for backwards compatibility */
       } else if (STREQ (long_options[option_index].name, "uuid")) {
         uuid = 1;
-      } else {
-        fprintf (stderr, _("%s: unknown long option: %s (%d)\n"),
-                 guestfs_int_program_name, long_options[option_index].name, option_index);
-        exit (EXIT_FAILURE);
-      }
+      } else
+        error (EXIT_FAILURE, 0,
+               _("unknown long option: %s (%d)"),
+               long_options[option_index].name, option_index);
       break;
 
     case 'a':
@@ -182,11 +179,8 @@ main (int argc, char *argv[])
       break;
 
     case 'P':
-      if (sscanf (optarg, "%zu", &max_threads) != 1) {
-        fprintf (stderr, _("%s: -P option is not numeric\n"),
-                 guestfs_int_program_name);
-        exit (EXIT_FAILURE);
-      }
+      if (sscanf (optarg, "%zu", &max_threads) != 1)
+        error (EXIT_FAILURE, 0, _("-P option is not numeric"));
       break;
 
     case 'v':
@@ -256,11 +250,8 @@ main (int argc, char *argv[])
   /* -h and --csv doesn't make sense.  Spreadsheets will corrupt these
    * fields.  (RHBZ#600977).
    */
-  if (human && csv) {
-    fprintf (stderr, _("%s: you cannot use -h and --csv options together.\n"),
-             guestfs_int_program_name);
-    exit (EXIT_FAILURE);
-  }
+  if (human && csv)
+    error (EXIT_FAILURE, 0, _("you cannot use -h and --csv options together."));
 
   /* virt-df has two modes.  If the user didn't specify any drives,
    * then we do the df on every libvirt guest.  That's the if-clause
@@ -274,9 +265,8 @@ main (int argc, char *argv[])
     err = start_threads (max_threads, g, df_work);
     free_domains ();
 #else
-    fprintf (stderr, _("%s: compiled without support for libvirt.\n"),
-             guestfs_int_program_name);
-    exit (EXIT_FAILURE);
+    error (EXIT_FAILURE, 0,
+           _("compiled without support for libvirt."));
 #endif
   }
   else {                        /* Single guest. */
diff --git a/diff/diff.c b/diff/diff.c
index 2e099db..d7542fc 100644
--- a/diff/diff.c
+++ b/diff/diff.c
@@ -190,16 +190,12 @@ main (int argc, char *argv[])
   struct tree *tree1, *tree2;
 
   g = guestfs_create ();
-  if (g == NULL) {
-    fprintf (stderr, _("guestfs_create: failed to create handle\n"));
-    exit (EXIT_FAILURE);
-  }
+  if (g == NULL)
+    error (EXIT_FAILURE, errno, "guestfs_create");
 
   g2 = guestfs_create ();
-  if (g2 == NULL) {
-    fprintf (stderr, _("guestfs_create: failed to create handle\n"));
-    exit (EXIT_FAILURE);
-  }
+  if (g2 == NULL)
+    error (EXIT_FAILURE, errno, "guestfs_create");
 
   for (;;) {
     c = getopt_long (argc, argv, options, long_options, &option_index);
@@ -260,12 +256,10 @@ main (int argc, char *argv[])
       } else if (STREQ (long_options[option_index].name, "xattr") ||
                  STREQ (long_options[option_index].name, "xattrs")) {
         enable_xattrs = 1;
-      } else {
-        fprintf (stderr, _("%s: unknown long option: %s (%d)\n"),
-                 guestfs_int_program_name,
-                 long_options[option_index].name, option_index);
-        exit (EXIT_FAILURE);
-      }
+      } else
+        error (EXIT_FAILURE, 0,
+               _("unknown long option: %s (%d)"),
+               long_options[option_index].name, option_index);
       break;
 
     case 'a':
@@ -327,17 +321,11 @@ main (int argc, char *argv[])
   /* CSV && human is unsafe because spreadsheets fail to parse these
    * fields correctly.  (RHBZ#600977).
    */
-  if (human && csv) {
-    fprintf (stderr, _("%s: you cannot use -h and --csv options together.\n"),
-             guestfs_int_program_name);
-    exit (EXIT_FAILURE);
-  }
+  if (human && csv)
+    error (EXIT_FAILURE, 0, _("you cannot use -h and --csv options together."));
 
-  if (optind != argc) {
-    fprintf (stderr, _("%s: extra arguments on the command line\n"),
-             guestfs_int_program_name);
-    usage (EXIT_FAILURE);
-  }
+  if (optind != argc)
+    error (EXIT_FAILURE, 0, _("extra arguments on the command line"));
 
   /* These are really constants, but they have to be variables for the
    * options parsing code.  Assert here that they have known-good
diff --git a/edit/edit.c b/edit/edit.c
index 38af8a5..6e7aee4 100644
--- a/edit/edit.c
+++ b/edit/edit.c
@@ -133,10 +133,8 @@ main (int argc, char *argv[])
   int option_index;
 
   g = guestfs_create ();
-  if (g == NULL) {
-    fprintf (stderr, _("guestfs_create: failed to create handle\n"));
-    exit (EXIT_FAILURE);
-  }
+  if (g == NULL)
+    error (EXIT_FAILURE, errno, "guestfs_create");
 
   for (;;) {
     c = getopt_long (argc, argv, options, long_options, &option_index);
@@ -154,12 +152,10 @@ main (int argc, char *argv[])
         echo_keys = 1;
       } else if (STREQ (long_options[option_index].name, "format")) {
         OPTION_format;
-      } else {
-        fprintf (stderr, _("%s: unknown long option: %s (%d)\n"),
-                 guestfs_int_program_name,
-                 long_options[option_index].name, option_index);
-        exit (EXIT_FAILURE);
-      }
+      } else
+        error (EXIT_FAILURE, 0,
+               _("unknown long option: %s (%d)"),
+               long_options[option_index].name, option_index);
       break;
 
     case 'a':
@@ -167,11 +163,8 @@ main (int argc, char *argv[])
       break;
 
     case 'b':
-      if (backup_extension) {
-        fprintf (stderr, _("%s: -b option given multiple times\n"),
-                 guestfs_int_program_name);
-        exit (EXIT_FAILURE);
-      }
+      if (backup_extension)
+        error (EXIT_FAILURE, 0, _("-b option given multiple times"));
       backup_extension = optarg;
       break;
 
@@ -184,11 +177,8 @@ main (int argc, char *argv[])
       break;
 
     case 'e':
-      if (perl_expr) {
-        fprintf (stderr, _("%s: -e option given multiple times\n"),
-                 guestfs_int_program_name);
-        exit (EXIT_FAILURE);
-      }
+      if (perl_expr)
+        error (EXIT_FAILURE, 0, _("-e option given multiple times"));
       perl_expr = optarg;
       break;
 
diff --git a/fish/fish.c b/fish/fish.c
index 6f9c784..bfb4f82 100644
--- a/fish/fish.c
+++ b/fish/fish.c
@@ -234,10 +234,8 @@ main (int argc, char *argv[])
    * it's OK to do it early here.
    */
   g = guestfs_create ();
-  if (g == NULL) {
-    fprintf (stderr, _("guestfs_create: failed to create handle\n"));
-    exit (EXIT_FAILURE);
-  }
+  if (g == NULL)
+    error (EXIT_FAILURE, errno, "guestfs_create");
 
   for (;;) {
     c = getopt_long (argc, argv, options, long_options, &option_index);
@@ -253,19 +251,15 @@ main (int argc, char *argv[])
         remote_control_listen = 1;
       else if (STREQ (long_options[option_index].name, "remote")) {
         if (optarg) {
-          if (sscanf (optarg, "%d", &remote_control) != 1) {
-            fprintf (stderr, _("%s: --listen=PID: PID was not a number: %s\n"),
-                     guestfs_int_program_name, optarg);
-            exit (EXIT_FAILURE);
-          }
+          if (sscanf (optarg, "%d", &remote_control) != 1)
+            error (EXIT_FAILURE, 0,
+                   _("--listen=PID: PID was not a number: %s"), optarg);
         } else {
           p = getenv ("GUESTFISH_PID");
-          if (!p || sscanf (p, "%d", &remote_control) != 1) {
-            fprintf (stderr, _("%s: remote: $GUESTFISH_PID must be set"
-                               " to the PID of the remote process\n"),
-                     guestfs_int_program_name);
-            exit (EXIT_FAILURE);
-          }
+          if (!p || sscanf (p, "%d", &remote_control) != 1)
+            error (EXIT_FAILURE, 0,
+                   _("remote: $GUESTFISH_PID must be set"
+                     " to the PID of the remote process"));
         }
       } else if (STREQ (long_options[option_index].name, "selinux")) {
         if (guestfs_set_selinux (g, 1) == -1)
@@ -291,11 +285,10 @@ main (int argc, char *argv[])
           exit (EXIT_FAILURE);
       } else if (STREQ (long_options[option_index].name, "no-dest-paths")) {
         complete_dest_paths = 0;
-      } else {
-        fprintf (stderr, _("%s: unknown long option: %s (%d)\n"),
-                 guestfs_int_program_name, long_options[option_index].name, option_index);
-        exit (EXIT_FAILURE);
-      }
+      } else
+        error (EXIT_FAILURE, 0,
+               _("unknown long option: %s (%d)"),
+               long_options[option_index].name, option_index);
       break;
 
     case 'a':
@@ -317,11 +310,8 @@ main (int argc, char *argv[])
       break;
 
     case 'f':
-      if (file) {
-        fprintf (stderr, _("%s: only one -f parameter can be given\n"),
-                 guestfs_int_program_name);
-        exit (EXIT_FAILURE);
-      }
+      if (file)
+        error (EXIT_FAILURE, 0, _("only one -f parameter can be given"));
       file = optarg;
       break;
 
@@ -501,26 +491,17 @@ main (int argc, char *argv[])
   free_mps (mps);
 
   /* Remote control? */
-  if (remote_control_listen && remote_control) {
-    fprintf (stderr,
-             _("%s: cannot use --listen and --remote options at the same time\n"),
-             guestfs_int_program_name);
-    exit (EXIT_FAILURE);
-  }
+  if (remote_control_listen && remote_control)
+    error (EXIT_FAILURE, 0,
+           _("cannot use --listen and --remote options at the same time"));
 
   if (remote_control_listen) {
-    if (optind < argc) {
-      fprintf (stderr,
-               _("%s: extra parameters on the command line with --listen flag\n"),
-               guestfs_int_program_name);
-      exit (EXIT_FAILURE);
-    }
-    if (file) {
-      fprintf (stderr,
-               _("%s: cannot use --listen and --file options at the same time\n"),
-               guestfs_int_program_name);
-      exit (EXIT_FAILURE);
-    }
+    if (optind < argc)
+      error (EXIT_FAILURE, 0,
+             _("extra parameters on the command line with --listen flag"));
+    if (file)
+      error (EXIT_FAILURE, 0,
+             _("cannot use --listen and --file options at the same time"));
     rc_listen ();
     goto out_after_handle_close;
   }
@@ -1055,10 +1036,8 @@ cmdline (char *argv[], size_t optind, size_t argc)
   if (optind >= argc) return;
 
   cmd = argv[optind++];
-  if (STREQ (cmd, ":")) {
-    fprintf (stderr, _("%s: empty command on command line\n"), guestfs_int_program_name);
-    exit (EXIT_FAILURE);
-  }
+  if (STREQ (cmd, ":"))
+    error (EXIT_FAILURE, 0, _("empty command on command line"));
 
   /* Allow -cmd on the command line to mean (temporarily) override
    * the normal exit on error (RHBZ#578407).
diff --git a/format/format.c b/format/format.c
index 781423f..4aa31de 100644
--- a/format/format.c
+++ b/format/format.c
@@ -128,10 +128,8 @@ main (int argc, char *argv[])
   int retry, retries;
 
   g = guestfs_create ();
-  if (g == NULL) {
-    fprintf (stderr, _("guestfs_create: failed to create handle\n"));
-    exit (EXIT_FAILURE);
-  }
+  if (g == NULL)
+    error (EXIT_FAILURE, errno, "guestfs_create");
 
   for (;;) {
     c = getopt_long (argc, argv, options, long_options, &option_index);
@@ -148,19 +146,14 @@ main (int argc, char *argv[])
       } else if (STREQ (long_options[option_index].name, "filesystem")) {
         if (STREQ (optarg, "none"))
           filesystem = NULL;
-        else if (optarg[0] == '-') { /* eg: --filesystem --lvm */
-          fprintf (stderr, _("%s: no filesystem was specified\n"),
-                   guestfs_int_program_name);
-          exit (EXIT_FAILURE);
-        } else
+        else if (optarg[0] == '-') /* eg: --filesystem --lvm */
+          error (EXIT_FAILURE, 0, _("no filesystem was specified"));
+        else
           filesystem = optarg;
       } else if (STREQ (long_options[option_index].name, "lvm")) {
-        if (vg || lv) {
-          fprintf (stderr,
-                   _("%s: --lvm option cannot be given multiple times\n"),
-                   guestfs_int_program_name);
-          exit (EXIT_FAILURE);
-        }
+        if (vg || lv)
+          error (EXIT_FAILURE, 0,
+                 _("--lvm option cannot be given multiple times"));
         if (optarg == NULL) {
           vg = strdup ("VG");
           lv = strdup ("LV");
@@ -182,12 +175,10 @@ main (int argc, char *argv[])
         wipe = 1;
       } else if (STREQ (long_options[option_index].name, "label")) {
         label = optarg;
-      } else {
-        fprintf (stderr, _("%s: unknown long option: %s (%d)\n"),
-                 guestfs_int_program_name,
-                 long_options[option_index].name, option_index);
-        exit (EXIT_FAILURE);
-      }
+      } else
+        error (EXIT_FAILURE, 0,
+               _("unknown long option: %s (%d)"),
+               long_options[option_index].name, option_index);
       break;
 
     case 'a':
@@ -271,16 +262,13 @@ main (int argc, char *argv[])
       guestfs_close (g);
       g = g2;
     }
-    else {
+    else
       /* Failed. */
-      fprintf (stderr,
-               _("%s: failed to rescan the disks after two attempts.  This\n"
-                 "may mean there is some sort of partition table or disk\n"
-                 "data which we are unable to remove.  If you think this\n"
-                 "is a bug, please file a bug at http://libguestfs.org/\n"),
-               guestfs_int_program_name);
-      exit (EXIT_FAILURE);
-    }
+      error (EXIT_FAILURE, 0,
+             _("failed to rescan the disks after two attempts.  This\n"
+               "may mean there is some sort of partition table or disk\n"
+               "data which we are unable to remove.  If you think this\n"
+               "is a bug, please file a bug at http://libguestfs.org/\n"));
   }
 
   /* Free up data structures. */
@@ -311,12 +299,9 @@ parse_vg_lv (const char *lvm)
 
     if (!vg || !lv)
       error (EXIT_FAILURE, errno, "strdup");
-  } else {
+  } else
   cannot_parse:
-    fprintf (stderr, _("%s: cannot parse --lvm option (%s)\n"),
-             guestfs_int_program_name, lvm);
-    exit (EXIT_FAILURE);
-  }
+    error (EXIT_FAILURE, 0, _("cannot parse --lvm option (%s)"), lvm);
 
   if (strchr (vg, '/') || strchr (lv, '/'))
     goto cannot_parse;
diff --git a/fuse/guestmount.c b/fuse/guestmount.c
index 6ab654a..fc03a9c 100644
--- a/fuse/guestmount.c
+++ b/fuse/guestmount.c
@@ -207,10 +207,8 @@ main (int argc, char *argv[])
   sigaction (SIGPIPE, &sa, NULL);
 
   g = guestfs_create ();
-  if (g == NULL) {
-    fprintf (stderr, _("guestfs_create: failed to create handle\n"));
-    exit (EXIT_FAILURE);
-  }
+  if (g == NULL)
+    error (EXIT_FAILURE, errno, "guestfs_create");
 
   for (;;) {
     c = getopt_long (argc, argv, options, long_options, &option_index);
@@ -242,17 +240,13 @@ main (int argc, char *argv[])
       } else if (STREQ (long_options[option_index].name, "no-fork")) {
         do_fork = 0;
       } else if (STREQ (long_options[option_index].name, "fd")) {
-        if (sscanf (optarg, "%d", &pipe_fd) != 1 || pipe_fd < 0) {
-          fprintf (stderr, _("%s: unable to parse --fd option value: %s\n"),
-                   guestfs_int_program_name, optarg);
-          exit (EXIT_FAILURE);
-        }
-      } else {
-        fprintf (stderr, _("%s: unknown long option: %s (%d)\n"),
-                 guestfs_int_program_name,
-                 long_options[option_index].name, option_index);
-        exit (EXIT_FAILURE);
-      }
+        if (sscanf (optarg, "%d", &pipe_fd) != 1 || pipe_fd < 0)
+          error (EXIT_FAILURE, 0,
+                 _("unable to parse --fd option value: %s"), optarg);
+      } else
+        error (EXIT_FAILURE, 0,
+               _("unknown long option: %s (%d)"),
+               long_options[option_index].name, option_index);
       break;
 
     case 'a':
@@ -317,29 +311,18 @@ main (int argc, char *argv[])
 
   /* Check we have the right options. */
   if (!live) {
-    if (!drvs || !(mps || inspector)) {
-      fprintf (stderr,
-               _("%s: must have at least one -a/-d and at least one -m/-i option\n"),
-               guestfs_int_program_name);
-      exit (EXIT_FAILURE);
-    }
+    if (!drvs || !(mps || inspector))
+      error (EXIT_FAILURE, 0,
+             _("must have at least one -a/-d and at least one -m/-i option"));
   } else {
     size_t count_d = 0, count_other = 0;
     struct drv *drv;
 
-    if (read_only) {
-      fprintf (stderr,
-               _("%s: --live is not compatible with --ro option\n"),
-               guestfs_int_program_name);
-      exit (EXIT_FAILURE);
-    }
+    if (read_only)
+      error (EXIT_FAILURE, 0, _("--live is not compatible with --ro option"));
 
-    if (inspector) {
-      fprintf (stderr,
-               _("%s: --live is not compatible with -i option\n"),
-               guestfs_int_program_name);
-      exit (EXIT_FAILURE);
-    }
+    if (inspector)
+      error (EXIT_FAILURE, 0, _("--live is not compatible with -i option"));
 
     /* --live: make sure there was one -d option and no -a options */
     for (drv = drvs; drv; drv = drv->next) {
@@ -349,28 +332,18 @@ main (int argc, char *argv[])
         count_other++;
     }
 
-    if (count_d != 1) {
-      fprintf (stderr,
-               _("%s: with --live, you must use exactly one -d option\n"),
-               guestfs_int_program_name);
-      exit (EXIT_FAILURE);
-    }
+    if (count_d != 1)
+      error (EXIT_FAILURE, 0,
+             _("with --live, you must use exactly one -d option"));
 
-    if (count_other != 0) {
-      fprintf (stderr,
-               _("%s: --live is not compatible with -a option\n"),
-               guestfs_int_program_name);
-      exit (EXIT_FAILURE);
-    }
+    if (count_other != 0)
+      error (EXIT_FAILURE, 0, _("--live is not compatible with -a option"));
   }
 
   /* We'd better have a mountpoint. */
-  if (optind+1 != argc) {
-    fprintf (stderr,
-             _("%s: you must specify a mountpoint in the host filesystem\n"),
-             guestfs_int_program_name);
-    exit (EXIT_FAILURE);
-  }
+  if (optind+1 != argc)
+    error (EXIT_FAILURE, 0,
+           _("you must specify a mountpoint in the host filesystem"));
 
   /* If we're forking, we can't use the recovery process. */
   if (guestfs_set_recovery_proc (g, !do_fork) == -1)
diff --git a/inspector/inspector.c b/inspector/inspector.c
index 2e54924..2519816 100644
--- a/inspector/inspector.c
+++ b/inspector/inspector.c
@@ -131,10 +131,8 @@ main (int argc, char *argv[])
   int option_index;
 
   g = guestfs_create ();
-  if (g == NULL) {
-    fprintf (stderr, _("guestfs_create: failed to create handle\n"));
-    exit (EXIT_FAILURE);
-  }
+  if (g == NULL)
+    error (EXIT_FAILURE, errno, "guestfs_create");
 
   for (;;) {
     c = getopt_long (argc, argv, options, long_options, &option_index);
@@ -246,11 +244,9 @@ main (int argc, char *argv[])
    * one extra parameter on the command line.
    */
   if (xpath) {
-    if (drvs != NULL) {
-      fprintf (stderr, _("%s: cannot use --xpath together with other options.\n"),
-               guestfs_int_program_name);
-      exit (EXIT_FAILURE);
-    }
+    if (drvs != NULL)
+      error (EXIT_FAILURE, 0,
+             _("cannot use --xpath together with other options."));
 
     do_xpath (xpath);
 
@@ -280,11 +276,9 @@ main (int argc, char *argv[])
 
   {
     CLEANUP_FREE_STRING_LIST char **roots = guestfs_inspect_os (g);
-    if (roots == NULL) {
-      fprintf (stderr, _("%s: no operating system could be detected inside this disk image.\n\nThis may be because the file is not a disk image, or is not a virtual machine\nimage, or because the OS type is not understood by libguestfs.\n\nNOTE for Red Hat Enterprise Linux 6 users: for Windows guest support you must\ninstall the separate libguestfs-winsupport package.\n\nIf you feel this is an error, please file a bug report including as much\ninformation about the disk image as possible.\n"),
-               guestfs_int_program_name);
-      exit (EXIT_FAILURE);
-    }
+    if (roots == NULL)
+      error (EXIT_FAILURE, 0,
+             _("no operating system could be detected inside this disk image.\n\nThis may be because the file is not a disk image, or is not a virtual machine\nimage, or because the OS type is not understood by libguestfs.\n\nNOTE for Red Hat Enterprise Linux 6 users: for Windows guest support you must\ninstall the separate libguestfs-winsupport package.\n\nIf you feel this is an error, please file a bug report including as much\ninformation about the disk image as possible.\n"));
 
     output (roots);
   }
@@ -295,32 +289,23 @@ main (int argc, char *argv[])
 }
 
 #define XMLERROR(code,e) do {                                           \
-    if ((e) == (code)) {                                                \
-      fprintf (stderr, _("%s: XML write error at \"%s\": %m\n"),        \
-               #e, guestfs_int_program_name);				\
-      exit (EXIT_FAILURE);                                              \
-    }                                                                   \
+    if ((e) == (code))                                                  \
+      error (EXIT_FAILURE, errno, _("XML write error at \"%s\""), #e);	\
   } while (0)
 
 static void
 output (char **roots)
 {
   xmlOutputBufferPtr ob = xmlOutputBufferCreateFd (1, NULL);
-  if (ob == NULL) {
-    fprintf (stderr,
-             _("%s: xmlOutputBufferCreateFd: failed to open stdout\n"),
-             guestfs_int_program_name);
-    exit (EXIT_FAILURE);
-  }
+  if (ob == NULL)
+    error (EXIT_FAILURE, 0,
+           _("xmlOutputBufferCreateFd: failed to open stdout"));
 
   /* 'ob' is freed when 'xo' is freed.. */
   CLEANUP_XMLFREETEXTWRITER xmlTextWriterPtr xo = xmlNewTextWriter (ob);
-  if (xo == NULL) {
-    fprintf (stderr,
-             _("%s: xmlNewTextWriter: failed to create libxml2 writer\n"),
-             guestfs_int_program_name);
-    exit (EXIT_FAILURE);
-  }
+  if (xo == NULL)
+    error (EXIT_FAILURE, 0,
+           _("xmlNewTextWriter: failed to create libxml2 writer"));
 
   /* Pretty-print the output. */
   XMLERROR (-1, xmlTextWriterSetIndent (xo, 1));
@@ -780,25 +765,16 @@ do_xpath (const char *query)
   xmlNodePtr wrnode;
 
   doc = xmlReadFd (STDIN_FILENO, NULL, "utf8", XML_PARSE_NOBLANKS);
-  if (doc == NULL) {
-    fprintf (stderr, _("%s: unable to parse XML from stdin\n"),
-             guestfs_int_program_name);
-    exit (EXIT_FAILURE);
-  }
+  if (doc == NULL)
+    error (EXIT_FAILURE, 0, _("unable to parse XML from stdin"));
 
   xpathCtx = xmlXPathNewContext (doc);
-  if (xpathCtx == NULL) {
-    fprintf (stderr, _("%s: unable to create new XPath context\n"),
-             guestfs_int_program_name);
-    exit (EXIT_FAILURE);
-  }
+  if (xpathCtx == NULL)
+    error (EXIT_FAILURE, 0, _("unable to create new XPath context"));
 
   xpathObj = xmlXPathEvalExpression (BAD_CAST query, xpathCtx);
-  if (xpathObj == NULL) {
-    fprintf (stderr, _("%s: unable to evaluate XPath expression\n"),
-             guestfs_int_program_name);
-    exit (EXIT_FAILURE);
-  }
+  if (xpathObj == NULL)
+    error (EXIT_FAILURE, 0, _("unable to evaluate XPath expression"));
 
   switch (xpathObj->type) {
   case XPATH_NODESET:
@@ -808,33 +784,21 @@ do_xpath (const char *query)
 
     saveCtx = xmlSaveToFd (STDOUT_FILENO, NULL,
                            XML_SAVE_NO_DECL | XML_SAVE_FORMAT);
-    if (saveCtx == NULL) {
-      fprintf (stderr, _("%s: xmlSaveToFd failed\n"),
-               guestfs_int_program_name);
-      exit (EXIT_FAILURE);
-    }
+    if (saveCtx == NULL)
+      error (EXIT_FAILURE, 0, _("xmlSaveToFd failed"));
 
     for (i = 0; i < (size_t) nodes->nodeNr; ++i) {
       CLEANUP_XMLFREEDOC xmlDocPtr wrdoc = xmlNewDoc (BAD_CAST "1.0");
-      if (wrdoc == NULL) {
-        fprintf (stderr, _("%s: xmlNewDoc failed\n"),
-                 guestfs_int_program_name);
-        exit (EXIT_FAILURE);
-      }
+      if (wrdoc == NULL)
+        error (EXIT_FAILURE, 0, _("xmlNewDoc failed"));
       wrnode = xmlDocCopyNode (nodes->nodeTab[i], wrdoc, 1);
-      if (wrnode == NULL) {
-        fprintf (stderr, _("%s: xmlCopyNode failed\n"),
-                 guestfs_int_program_name);
-        exit (EXIT_FAILURE);
-      }
+      if (wrnode == NULL)
+        error (EXIT_FAILURE, 0, _("xmlCopyNode failed"));
 
       xmlDocSetRootElement (wrdoc, wrnode);
 
-      if (xmlSaveDoc (saveCtx, wrdoc) == -1) {
-        fprintf (stderr, _("%s: xmlSaveDoc failed\n"),
-                 guestfs_int_program_name);
-        exit (EXIT_FAILURE);
-      }
+      if (xmlSaveDoc (saveCtx, wrdoc) == -1)
+        error (EXIT_FAILURE, 0, _("xmlSaveDoc failed"));
     }
 
     xmlSaveClose (saveCtx);
diff --git a/make-fs/make-fs.c b/make-fs/make-fs.c
index 2778772..42e7e82 100644
--- a/make-fs/make-fs.c
+++ b/make-fs/make-fs.c
@@ -26,6 +26,7 @@
 #include <getopt.h>
 #include <fcntl.h>
 #include <errno.h>
+#include <error.h>
 #include <locale.h>
 #include <assert.h>
 #include <libintl.h>
@@ -112,10 +113,8 @@ main (int argc, char *argv[])
   textdomain (PACKAGE);
 
   g = guestfs_create ();
-  if (g == NULL) {
-    fprintf (stderr, _("guestfs_create: failed to create handle\n"));
-    exit (EXIT_FAILURE);
-  }
+  if (g == NULL)
+    error (EXIT_FAILURE, errno, "guestfs_create");
 
   for (;;) {
     c = getopt_long (argc, argv, options, long_options, &option_index);
@@ -142,12 +141,10 @@ main (int argc, char *argv[])
           partition = "mbr";
         else
           partition = optarg;
-      } else {
-        fprintf (stderr, _("%s: unknown long option: %s (%d)\n"),
-                 guestfs_int_program_name,
-                 long_options[option_index].name, option_index);
-        exit (EXIT_FAILURE);
-      }
+      } else
+        error (EXIT_FAILURE, 0,
+               _("unknown long option: %s (%d)"),
+               long_options[option_index].name, option_index);
       break;
 
     case 'F':
diff --git a/p2v/gui.c b/p2v/gui.c
index c5fbc99..625c6eb 100644
--- a/p2v/gui.c
+++ b/p2v/gui.c
@@ -322,10 +322,8 @@ test_connection_clicked (GtkWidget *w, gpointer data)
   pthread_attr_init (&attr);
   pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
   err = pthread_create (&tid, &attr, test_connection_thread, copy);
-  if (err != 0) {
-    fprintf (stderr, "pthread_create: %s\n", strerror (err));
-    exit (EXIT_FAILURE);
-  }
+  if (err != 0)
+    error (EXIT_FAILURE, err, "pthread_create");
   pthread_attr_destroy (&attr);
 }
 
@@ -1557,10 +1555,8 @@ start_conversion_clicked (GtkWidget *w, gpointer data)
   pthread_attr_init (&attr);
   pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
   err = pthread_create (&tid, &attr, start_conversion_thread, copy);
-  if (err != 0) {
-    fprintf (stderr, "pthread_create: %s\n", strerror (err));
-    exit (EXIT_FAILURE);
-  }
+  if (err != 0)
+    error (EXIT_FAILURE, err, "pthread_create");
   pthread_attr_destroy (&attr);
 }
 
diff --git a/p2v/kernel.c b/p2v/kernel.c
index 61fbecd..fb52785 100644
--- a/p2v/kernel.c
+++ b/p2v/kernel.c
@@ -54,11 +54,9 @@ kernel_configuration (struct config *config, char **cmdline, int cmdline_source)
 
   p = get_cmdline_key (cmdline, "p2v.port");
   if (p) {
-    if (sscanf (p, "%d", &config->port) != 1) {
-      fprintf (stderr, "%s: cannot parse p2v.port from kernel command line",
-               guestfs_int_program_name);
-      exit (EXIT_FAILURE);
-    }
+    if (sscanf (p, "%d", &config->port) != 1)
+      error (EXIT_FAILURE, 0,
+             "cannot parse p2v.port from kernel command line");
   }
 
   p = get_cmdline_key (cmdline, "p2v.username");
@@ -93,9 +91,9 @@ kernel_configuration (struct config *config, char **cmdline, int cmdline_source)
     if (test_connection (config) == -1) {
       const char *err = get_ssh_error ();
 
-      fprintf (stderr, "%s: error opening control connection to %s:%d: %s\n",
-               guestfs_int_program_name, config->server, config->port, err);
-      exit (EXIT_FAILURE);
+      error (EXIT_FAILURE, 0,
+             "error opening control connection to %s:%d: %s",
+             config->server, config->port, err);
     }
   }
 
@@ -107,22 +105,18 @@ kernel_configuration (struct config *config, char **cmdline, int cmdline_source)
 
   p = get_cmdline_key (cmdline, "p2v.vcpus");
   if (p) {
-    if (sscanf (p, "%d", &config->vcpus) != 1) {
-      fprintf (stderr, "%s: cannot parse p2v.vcpus from kernel command line\n",
-               guestfs_int_program_name);
-      exit (EXIT_FAILURE);
-    }
+    if (sscanf (p, "%d", &config->vcpus) != 1)
+      error (EXIT_FAILURE, 0,
+             "cannot parse p2v.vcpus from kernel command line");
   }
 
   p = get_cmdline_key (cmdline, "p2v.memory");
   if (p) {
     char mem_code;
 
-    if (sscanf (p, "%" SCNu64 "%c", &config->memory, &mem_code) != 2) {
-      fprintf (stderr, "%s: cannot parse p2v.memory from kernel command line\n",
-               guestfs_int_program_name);
-      exit (EXIT_FAILURE);
-    }
+    if (sscanf (p, "%" SCNu64 "%c", &config->memory, &mem_code) != 2)
+      error (EXIT_FAILURE, 0,
+             "cannot parse p2v.memory from kernel command line");
     config->memory *= 1024;
     if (mem_code == 'M' || mem_code == 'm'
         || mem_code == 'G' || mem_code == 'g')
@@ -130,11 +124,9 @@ kernel_configuration (struct config *config, char **cmdline, int cmdline_source)
     if (mem_code == 'G' || mem_code == 'g')
       config->memory *= 1024;
     if (mem_code != 'M' && mem_code != 'm'
-        && mem_code != 'G' && mem_code != 'g') {
-      fprintf (stderr, "%s: p2v.memory on kernel command line must be followed by 'G' or 'M'\n",
-               guestfs_int_program_name);
-      exit (EXIT_FAILURE);
-    }
+        && mem_code != 'G' && mem_code != 'g')
+      error (EXIT_FAILURE, 0,
+             "p2v.memory on kernel command line must be followed by 'G' or 'M'");
   }
 
   p = get_cmdline_key (cmdline, "p2v.disks");
@@ -216,13 +208,11 @@ kernel_configuration (struct config *config, char **cmdline, int cmdline_source)
   }
 
   /* Some disks must have been specified for conversion. */
-  if (config->disks == NULL || guestfs_int_count_strings (config->disks) == 0) {
-    fprintf (stderr, "%s: error: no non-removable disks were discovered on this machine.\n",
-             guestfs_int_program_name);
-    fprintf (stderr, "virt-p2v looked in /sys/block and in p2v.disks on the kernel command line.\n");
-    fprintf (stderr, "This is a fatal error and virt-p2v cannot continue.\n");
-    exit (EXIT_FAILURE);
-  }
+  if (config->disks == NULL || guestfs_int_count_strings (config->disks) == 0)
+    error (EXIT_FAILURE, 0,
+           "no non-removable disks were discovered on this machine.\n"
+           "virt-p2v looked in /sys/block and in p2v.disks on the kernel command line.\n"
+           "This is a fatal error and virt-p2v cannot continue.");
 
   /* Perform the conversion in text mode. */
   if (start_conversion (config, notify_ui_callback) == -1) {
@@ -285,9 +275,7 @@ run_command (int verbose, const char *stage, const char *command)
   r = system (command);
   if (r == -1)
     error (EXIT_FAILURE, errno, "system: %s", command);
-  if ((WIFEXITED (r) && WEXITSTATUS (r) != 0) || !WIFEXITED (r)) {
-    fprintf (stderr, "%s: %s: unexpected failure of external command\n",
-             guestfs_int_program_name, stage);
-    exit (EXIT_FAILURE);
-  }
+  if ((WIFEXITED (r) && WEXITSTATUS (r) != 0) || !WIFEXITED (r))
+    error (EXIT_FAILURE, 0,
+           "%s: unexpected failure of external command", stage);
 }
diff --git a/p2v/ssh.c b/p2v/ssh.c
index 6ddfcb2..7158e70 100644
--- a/p2v/ssh.c
+++ b/p2v/ssh.c
@@ -415,10 +415,8 @@ start_ssh (struct config *config, char **extra_args, int wait_prompt)
        */
       r = pcre_get_substring (h->buffer, ovector,
                               mexp_get_pcre_error (h), 1, &matched);
-      if (r < 0) {
-        fprintf (stderr, "error: PCRE error reading substring (%d)\n", r);
-        exit (EXIT_FAILURE);
-      }
+      if (r < 0)
+        error (EXIT_FAILURE, 0, "PCRE error reading substring (%d)", r);
       r = STREQ (magic, matched);
       pcre_free_substring (matched);
       if (!r)
diff --git a/rescue/rescue.c b/rescue/rescue.c
index 37a0c3f..c46c775 100644
--- a/rescue/rescue.c
+++ b/rescue/rescue.c
@@ -133,10 +133,8 @@ main (int argc, char *argv[])
   int suggest = 0;
 
   g = guestfs_create ();
-  if (g == NULL) {
-    fprintf (stderr, _("guestfs_create: failed to create handle\n"));
-    exit (EXIT_FAILURE);
-  }
+  if (g == NULL)
+    error (EXIT_FAILURE, errno, "guestfs_create");
 
   for (;;) {
     c = getopt_long (argc, argv, options, long_options, &option_index);
@@ -158,16 +156,12 @@ main (int argc, char *argv[])
       } else if (STREQ (long_options[option_index].name, "format")) {
         OPTION_format;
       } else if (STREQ (long_options[option_index].name, "smp")) {
-        if (sscanf (optarg, "%d", &smp) != 1) {
-          fprintf (stderr, _("%s: could not parse --smp parameter '%s'\n"),
-                   guestfs_int_program_name, optarg);
-          exit (EXIT_FAILURE);
-        }
-        if (smp < 1) {
-          fprintf (stderr, _("%s: --smp parameter '%s' should be >= 1\n"),
-                   guestfs_int_program_name, optarg);
-          exit (EXIT_FAILURE);
-        }
+        if (sscanf (optarg, "%d", &smp) != 1)
+          error (EXIT_FAILURE, 0,
+                 _("could not parse --smp parameter '%s'"), optarg);
+        if (smp < 1)
+          error (EXIT_FAILURE, 0,
+                 _("--smp parameter '%s' should be >= 1"), optarg);
       } else if (STREQ (long_options[option_index].name, "suggest")) {
         suggest = 1;
       } else if (STREQ (long_options[option_index].name, "scratch")) {
@@ -175,25 +169,18 @@ main (int argc, char *argv[])
           add_scratch_disks (1, &drvs);
         else {
           int n;
-          if (sscanf (optarg, "%d", &n) != 1) {
-            fprintf (stderr,
-                     _("%s: could not parse --scratch parameter '%s'\n"),
-                     guestfs_int_program_name, optarg);
-            exit (EXIT_FAILURE);
-          }
-          if (n < 1) {
-            fprintf (stderr,
-                     _("%s: --scratch parameter '%s' should be >= 1\n"),
-                     guestfs_int_program_name, optarg);
-            exit (EXIT_FAILURE);
-          }
+          if (sscanf (optarg, "%d", &n) != 1)
+            error (EXIT_FAILURE, 0,
+                   _("could not parse --scratch parameter '%s'"), optarg);
+          if (n < 1)
+            error (EXIT_FAILURE, 0,
+                   _("--scratch parameter '%s' should be >= 1"), optarg);
           add_scratch_disks (n, &drvs);
         }
-      } else {
-        fprintf (stderr, _("%s: unknown long option: %s (%d)\n"),
-                 guestfs_int_program_name, long_options[option_index].name, option_index);
-        exit (EXIT_FAILURE);
-      }
+      } else
+        error (EXIT_FAILURE, 0,
+               _("unknown long option: %s (%d)"),
+               long_options[option_index].name, option_index);
       break;
 
     case 'a':
@@ -209,11 +196,9 @@ main (int argc, char *argv[])
       break;
 
     case 'm':
-      if (sscanf (optarg, "%d", &memsize) != 1) {
-        fprintf (stderr, _("%s: could not parse memory size '%s'\n"),
-                 guestfs_int_program_name, optarg);
-        exit (EXIT_FAILURE);
-      }
+      if (sscanf (optarg, "%d", &memsize) != 1)
+        error (EXIT_FAILURE, 0,
+               _("could not parse memory size '%s'"), optarg);
       break;
 
     case 'r':
diff --git a/src/libvirt-is-version.c b/src/libvirt-is-version.c
index 212368a..e350c4d 100644
--- a/src/libvirt-is-version.c
+++ b/src/libvirt-is-version.c
@@ -23,6 +23,7 @@
 #include <string.h>
 #include <unistd.h>
 #include <errno.h>
+#include <error.h>
 #include <locale.h>
 #include <libintl.h>
 
@@ -51,10 +52,7 @@ main (int argc, char *argv[])
     major = argtoint (argv[0], argv[1]);
     break;
   case 1:
-    fprintf (stderr, "%s: not enough arguments: MAJOR [MINOR [PATCH]]\n",
-             argv[0]);
-    exit (EXIT_FAILURE);
-    break;
+    error (EXIT_FAILURE, 0, "not enough arguments: MAJOR [MINOR [PATCH]]");
   }
 
   virInitialize ();
@@ -74,10 +72,8 @@ argtoint (const char *prog, const char *arg)
 
   errno = 0;
   res = strtol (arg, &endptr, 10);
-  if (errno || *endptr) {
-    fprintf (stderr, "%s: cannot parse integer argument '%s'.\n", prog, arg);
-    exit (EXIT_FAILURE);
-  }
+  if (errno || *endptr)
+    error (EXIT_FAILURE, 0, "cannot parse integer argument '%s'", arg);
 
   return (unsigned int) res;
 }
diff --git a/test-tool/Makefile.am b/test-tool/Makefile.am
index f7d1c7f..5177942 100644
--- a/test-tool/Makefile.am
+++ b/test-tool/Makefile.am
@@ -33,10 +33,13 @@ libguestfs_test_tool_CPPFLAGS = \
 	-DLOCALEBASEDIR=\""$(datadir)/locale"\"
 
 libguestfs_test_tool_CFLAGS = \
-	$(WARN_CFLAGS) $(WERROR_CFLAGS)
+	$(WARN_CFLAGS) $(WERROR_CFLAGS) \
+	$(LIBXML2_CFLAGS)
 
 libguestfs_test_tool_LDADD = \
 	$(top_builddir)/src/libguestfs.la \
+	$(top_builddir)/src/libutils.la \
+	$(LIBXML2_LIBS) \
 	$(LTLIBINTL) \
 	$(top_builddir)/gnulib/lib/libgnu.la
 
diff --git a/test-tool/test-tool.c b/test-tool/test-tool.c
index 1aa9bc4..c632440 100644
--- a/test-tool/test-tool.c
+++ b/test-tool/test-tool.c
@@ -35,7 +35,7 @@
 #include <limits.h>
 #include <libintl.h>
 
-#include <guestfs.h>
+#include "guestfs.h"
 #include "guestfs-internal-frontend.h"
 
 #include "ignore-value.h"
@@ -111,35 +111,24 @@ main (int argc, char *argv[])
         qemu = optarg;
         qemu_use_wrapper = 1;
       }
-      else {
-        fprintf (stderr,
-                 _("libguestfs-test-tool: unknown long option: %s (%d)\n"),
-                 long_options[option_index].name, option_index);
-        exit (EXIT_FAILURE);
-      }
+      else
+        error (EXIT_FAILURE, 0,
+               _("unknown long option: %s (%d)"),
+               long_options[option_index].name, option_index);
       break;
 
     case 't':
-      if (sscanf (optarg, "%d", &timeout) != 1 || timeout < 0) {
-        fprintf (stderr,
-                 _("libguestfs-test-tool: invalid timeout: %s\n"),
-                 optarg);
-        exit (EXIT_FAILURE);
-      }
+      if (sscanf (optarg, "%d", &timeout) != 1 || timeout < 0)
+        error (EXIT_FAILURE, 0, _("invalid timeout: %s"), optarg);
       break;
 
     case 'V':
       g = guestfs_create ();
-      if (g == NULL) {
-        fprintf (stderr,
-                 _("libguestfs-test-tool: failed to create libguestfs handle\n"));
-        exit (EXIT_FAILURE);
-      }
+      if (g == NULL)
+        error (EXIT_FAILURE, errno, "guestfs_create");
       vers = guestfs_version (g);
-      if (vers == NULL) {
-        fprintf (stderr, _("libguestfs-test-tool: guestfs_version failed\n"));
+      if (vers == NULL)
         exit (EXIT_FAILURE);
-      }
       printf ("%s %"PRIi64".%"PRIi64".%"PRIi64"%s\n",
               "libguestfs-test-tool",
               vers->major, vers->minor, vers->release, vers->extra);
@@ -152,17 +141,12 @@ main (int argc, char *argv[])
       exit (EXIT_SUCCESS);
 
     default:
-      fprintf (stderr,
-               _("libguestfs-test-tool: unexpected command line option %d\n"),
-               c);
-      exit (EXIT_FAILURE);
+      error (EXIT_FAILURE, 0, _("unexpected command line option %d"), c);
     }
   }
 
-  if (optind < argc) {
-    fprintf (stderr, _("libguestfs-test-tool: extra arguments on the command line\n"));
-    exit (EXIT_FAILURE);
-  }
+  if (optind < argc)
+    error (EXIT_FAILURE, 0, _("extra arguments on the command line"));
 
   /* Everyone ignores the documentation, so ... */
   printf ("     ************************************************************\n"
@@ -177,17 +161,12 @@ main (int argc, char *argv[])
 
   /* Create the handle. */
   g = guestfs_create_flags (GUESTFS_CREATE_NO_ENVIRONMENT);
-  if (g == NULL) {
-    fprintf (stderr,
-             _("libguestfs-test-tool: failed to create libguestfs handle\n"));
-    exit (EXIT_FAILURE);
-  }
-  if (guestfs_parse_environment (g) == -1) {
-    fprintf (stderr,
-             _("libguestfs-test-tool: failed parsing environment variables.\n"
-               "Check earlier messages, and the output of the 'printenv' command.\n"));
-    exit (EXIT_FAILURE);
-  }
+  if (g == NULL)
+    error (EXIT_FAILURE, errno, "guestfs_create_flags");
+  if (guestfs_parse_environment (g) == -1)
+    error (EXIT_FAILURE, 0,
+           _("failed parsing environment variables.\n"
+             "Check earlier messages, and the output of the 'printenv' command."));
   guestfs_set_verbose (g, 1);
 
   if (qemu)
@@ -224,11 +203,8 @@ main (int argc, char *argv[])
   ignore_value (system ("getenforce"));
 
   /* Configure the handle. */
-  if (guestfs_add_drive_scratch (g, 100*1024*1024, -1) == -1) {
-    fprintf (stderr,
-             _("libguestfs-test-tool: failed to add scratch drive\n"));
+  if (guestfs_add_drive_scratch (g, 100*1024*1024, -1) == -1)
     exit (EXIT_FAILURE);
-  }
 
   printf ("guestfs_get_append: %s\n", guestfs_get_append (g) ? : "(null)");
   printf ("guestfs_get_autosync: %d\n", guestfs_get_autosync (g));
@@ -277,11 +253,8 @@ main (int argc, char *argv[])
 
   alarm (timeout);
 
-  if (guestfs_launch (g) == -1) {
-    fprintf (stderr,
-             _("libguestfs-test-tool: failed to launch appliance\n"));
+  if (guestfs_launch (g) == -1)
     exit (EXIT_FAILURE);
-  }
 
   alarm (0);
 
@@ -289,36 +262,22 @@ main (int argc, char *argv[])
   fflush (stdout);
 
   /* Create the filesystem and mount everything. */
-  if (guestfs_part_disk (g, "/dev/sda", "mbr") == -1) {
-    fprintf (stderr,
-             _("libguestfs-test-tool: failed to run part-disk\n"));
+  if (guestfs_part_disk (g, "/dev/sda", "mbr") == -1)
     exit (EXIT_FAILURE);
-  }
 
-  if (guestfs_mkfs (g, "ext2", "/dev/sda1") == -1) {
-    fprintf (stderr,
-             _("libguestfs-test-tool: failed to mkfs.ext2\n"));
+  if (guestfs_mkfs (g, "ext2", "/dev/sda1") == -1)
     exit (EXIT_FAILURE);
-  }
 
-  if (guestfs_mount (g, "/dev/sda1", "/") == -1) {
-    fprintf (stderr,
-             _("libguestfs-test-tool: failed to mount /dev/sda1 on /\n"));
+  if (guestfs_mount (g, "/dev/sda1", "/") == -1)
     exit (EXIT_FAILURE);
-  }
 
   /* Touch a file. */
-  if (guestfs_touch (g, "/hello") == -1) {
-    fprintf (stderr,
-             _("libguestfs-test-tool: failed to touch file\n"));
+  if (guestfs_touch (g, "/hello") == -1)
     exit (EXIT_FAILURE);
-  }
 
   /* Close the handle. */
-  if (guestfs_shutdown (g) == -1) {
-    fprintf (stderr, _("libguestfs-test-tool: shutdown failed\n"));
+  if (guestfs_shutdown (g) == -1)
     exit (EXIT_FAILURE);
-  }
 
   guestfs_close (g);
 
@@ -342,26 +301,21 @@ cleanup_wrapper (void)
 static void
 set_qemu (guestfs_h *g, const char *path, int use_wrapper)
 {
-  char *buffer;
+  CLEANUP_FREE char *buffer = NULL;
   struct stat statbuf;
   int fd;
   FILE *fp;
 
   if (getenv ("LIBGUESTFS_QEMU") != NULL ||
-      getenv ("LIBGUESTFS_HV") != NULL) {
-    fprintf (stderr,
-	     _("LIBGUESTFS_HV/LIBGUESTFS_QEMU environment variable is already set, so\n"
-	       "--qemu/--qemudir options cannot be used.\n"));
-    exit (EXIT_FAILURE);
-  }
+      getenv ("LIBGUESTFS_HV") != NULL)
+    error (EXIT_FAILURE, 0,
+           _("LIBGUESTFS_HV/LIBGUESTFS_QEMU environment variable is already set, so\n"
+             "--qemu/--qemudir options cannot be used."));
 
   if (!use_wrapper) {
-    if (access (path, X_OK) == -1) {
-      fprintf (stderr,
-               _("Binary '%s' does not exist or is not executable\n"),
-               path);
-      exit (EXIT_FAILURE);
-    }
+    if (access (path, X_OK) == -1)
+      error (EXIT_FAILURE, errno,
+             _("binary '%s' does not exist or is not executable"), path);
 
     guestfs_set_hv (g, path);
     return;
@@ -371,14 +325,9 @@ set_qemu (guestfs_h *g, const char *path, int use_wrapper)
   if (asprintf (&buffer, "%s/pc-bios", path) == -1)
     error (EXIT_FAILURE, errno, "asprintf");
   if (stat (buffer, &statbuf) == -1 ||
-      !S_ISDIR (statbuf.st_mode)) {
-    fprintf (stderr,
-             _("%s: does not look like a qemu source directory\n"),
-             path);
-    free (buffer);
-    exit (EXIT_FAILURE);
-  }
-  free (buffer);
+      !S_ISDIR (statbuf.st_mode))
+    error (EXIT_FAILURE, errno,
+           _("path does not look like a qemu source directory: %s"), path);
 
   /* Make a wrapper script. */
   fd = mkstemp (qemuwrapper);
diff --git a/tests/c-api/test-add-drive-opts.c b/tests/c-api/test-add-drive-opts.c
index 7f6bd4a..4f39e26 100644
--- a/tests/c-api/test-add-drive-opts.c
+++ b/tests/c-api/test-add-drive-opts.c
@@ -22,6 +22,8 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <errno.h>
+#include <error.h>
 
 #include "guestfs.h"
 #include "guestfs-internal-frontend.h"
@@ -33,10 +35,8 @@ main (int argc, char *argv[])
   int r;
 
   g = guestfs_create ();
-  if (g == NULL) {
-    fprintf (stderr, "failed to create handle\n");
-    exit (EXIT_FAILURE);
-  }
+  if (g == NULL)
+    error (EXIT_FAILURE, errno, "guestfs_create");
 
   r = guestfs_add_drive_opts (g, "/dev/null", -1);
   if (r == -1)
diff --git a/tests/c-api/test-add-libvirt-dom.c b/tests/c-api/test-add-libvirt-dom.c
index 566a3de..612b86e 100644
--- a/tests/c-api/test-add-libvirt-dom.c
+++ b/tests/c-api/test-add-libvirt-dom.c
@@ -84,17 +84,13 @@ main (int argc, char *argv[])
 
   /* Create the guestfs handle. */
   g = guestfs_create ();
-  if (g == NULL) {
-    fprintf (stderr, "failed to create handle\n");
-    exit (EXIT_FAILURE);
-  }
+  if (g == NULL)
+    error (EXIT_FAILURE, errno, "guestfs_create");
 
   backend = guestfs_get_backend (g);
   if (STREQ (backend, "uml")) {
-    printf ("%s: test skipped because UML backend does not support qcow2\n",
-            argv[0]);
     free (backend);
-    exit (77);
+    error (77, 0, "test skipped because UML backend does not support qcow2");
   }
   free (backend);
 
@@ -125,19 +121,16 @@ main (int argc, char *argv[])
   conn = virConnectOpenReadOnly (libvirt_uri);
   if (!conn) {
     err = virGetLastError ();
-    fprintf (stderr,
-             "%s: could not connect to libvirt (code %d, domain %d): %s\n",
-             argv[0], err->code, err->domain, err->message);
-    exit (EXIT_FAILURE);
+    error (EXIT_FAILURE, 0,
+           "could not connect to libvirt (code %d, domain %d): %s",
+           err->code, err->domain, err->message);
   }
 
   dom = virDomainLookupByName (conn, "guest");
   if (!dom) {
     err = virGetLastError ();
-    fprintf (stderr,
-             "%s: no libvirt domain called '%s': %s\n",
-             argv[0], "guest", err->message);
-    exit (EXIT_FAILURE);
+    error (EXIT_FAILURE, 0,
+           "no libvirt domain called '%s': %s", "guest", err->message);
   }
 
   r = guestfs_add_libvirt_dom (g, dom,
@@ -146,12 +139,9 @@ main (int argc, char *argv[])
   if (r == -1)
     exit (EXIT_FAILURE);
 
-  if (r != 3) {
-    fprintf (stderr,
-             "%s: incorrect number of disks added (%d, expected 3)\n",
-             argv[0], r);
-    exit (EXIT_FAILURE);
-  }
+  if (r != 3)
+    error (EXIT_FAILURE, 0,
+           "incorrect number of disks added (%d, expected 3)", r);
 
   guestfs_close (g);
 
diff --git a/tests/c-api/test-backend-settings.c b/tests/c-api/test-backend-settings.c
index ce1854f..371a247 100644
--- a/tests/c-api/test-backend-settings.c
+++ b/tests/c-api/test-backend-settings.c
@@ -25,6 +25,7 @@
 #include <string.h>
 #include <unistd.h>
 #include <errno.h>
+#include <error.h>
 #include <assert.h>
 
 #include "guestfs.h"
@@ -44,10 +45,8 @@ main (int argc, char *argv[])
   unsetenv ("LIBGUESTFS_BACKEND_SETTINGS");
 
   g = guestfs_create ();
-  if (g == NULL) {
-    fprintf (stderr, "failed to create handle\n");
-    exit (EXIT_FAILURE);
-  }
+  if (g == NULL)
+    error (EXIT_FAILURE, errno, "guestfs_create");
 
   /* There should be no backend settings initially. */
   strs = guestfs_get_backend_settings (g);
@@ -82,10 +81,8 @@ main (int argc, char *argv[])
 
       setenv ("LIBGUESTFS_BACKEND_SETTINGS", initial_settings, 1);
       g = guestfs_create ();
-      if (g == NULL) {
-        fprintf (stderr, "failed to create handle\n");
-        exit (EXIT_FAILURE);
-      }
+      if (g == NULL)
+        error (EXIT_FAILURE, errno, "guestfs_create");
     }
 
     /* Check the settings are correct. */
diff --git a/tests/c-api/test-command.c b/tests/c-api/test-command.c
index c23b7d1..b14f0f1 100644
--- a/tests/c-api/test-command.c
+++ b/tests/c-api/test-command.c
@@ -25,6 +25,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <error.h>
 
 #define STREQ(a,b) (strcmp((a),(b)) == 0)
 
@@ -54,14 +55,10 @@ main (int argc, char *argv[])
       printf ("Result10-1\nResult10-2\n");
     } else if (STREQ (argv[1], "11")) {
       printf ("Result11-1\nResult11-2");
-    } else {
-      fprintf (stderr, "unknown parameter: %s\n", argv[1]);
-      exit (EXIT_FAILURE);
-    }
-  } else {
-    fprintf (stderr, "missing parameter\n");
-    exit (EXIT_FAILURE);
-  }
+    } else
+      error (EXIT_FAILURE, 0, "unknown parameter: %s", argv[1]);
+  } else
+    error (EXIT_FAILURE, 0, "missing parameter");
 
   exit (EXIT_SUCCESS);
 }
diff --git a/tests/c-api/test-config.c b/tests/c-api/test-config.c
index feaeadc..fef6c64 100644
--- a/tests/c-api/test-config.c
+++ b/tests/c-api/test-config.c
@@ -22,6 +22,8 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <errno.h>
+#include <error.h>
 
 #include "guestfs.h"
 #include "guestfs-internal-frontend.h"
@@ -33,10 +35,8 @@ main (int argc, char *argv[])
   int r;
 
   g = guestfs_create ();
-  if (g == NULL) {
-    fprintf (stderr, "failed to create handle\n");
-    exit (EXIT_FAILURE);
-  }
+  if (g == NULL)
+    error (EXIT_FAILURE, errno, "guestfs_create");
 
   /* If these fail, the default error handler will print an error
    * message to stderr, so we don't need to print anything.  This code
@@ -49,19 +49,15 @@ main (int argc, char *argv[])
   r = guestfs_get_verbose (g);
   if (r == -1)
     exit (EXIT_FAILURE);
-  if (!r) {
-    fprintf (stderr, "set_verbose not true\n");
-    exit (EXIT_FAILURE);
-  }
+  if (!r)
+    error (EXIT_FAILURE, 0, "set_verbose not true");
   if (guestfs_set_verbose (g, 0) == -1)
     exit (EXIT_FAILURE);
   r = guestfs_get_verbose (g);
   if (r == -1)
     exit (EXIT_FAILURE);
-  if (r) {
-    fprintf (stderr, "set_verbose not false\n");
-    exit (EXIT_FAILURE);
-  }
+  if (r)
+    error (EXIT_FAILURE, 0, "set_verbose not false");
 
   guestfs_close (g);
 
diff --git a/tests/c-api/test-create-handle.c b/tests/c-api/test-create-handle.c
index d2bfbbf..1706499 100644
--- a/tests/c-api/test-create-handle.c
+++ b/tests/c-api/test-create-handle.c
@@ -22,6 +22,8 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <errno.h>
+#include <error.h>
 
 #include "guestfs.h"
 #include "guestfs-internal-frontend.h"
@@ -32,10 +34,8 @@ main (int argc, char *argv[])
   guestfs_h *g;
 
   g = guestfs_create ();
-  if (g == NULL) {
-    fprintf (stderr, "failed to create handle\n");
-    exit (EXIT_FAILURE);
-  }
+  if (g == NULL)
+    error (EXIT_FAILURE, errno, "guestfs_create");
 
   guestfs_close (g);
 
diff --git a/tests/c-api/test-debug-to-file.c b/tests/c-api/test-debug-to-file.c
index c36ae14..10e36c6 100644
--- a/tests/c-api/test-debug-to-file.c
+++ b/tests/c-api/test-debug-to-file.c
@@ -60,10 +60,8 @@ main (int argc, char *argv[])
     error (EXIT_FAILURE, errno, "fopen: %s", filename);
 
   g = guestfs_create ();
-  if (g == NULL) {
-    fprintf (stderr, "failed to create handle\n");
-    exit (EXIT_FAILURE);
-  }
+  if (g == NULL)
+    error (EXIT_FAILURE, errno, "guestfs_create");
 
   if (guestfs_set_event_callback
       (g, debug_to_file,
diff --git a/tests/c-api/test-dlopen.c b/tests/c-api/test-dlopen.c
index 3efd847..8a4174c 100644
--- a/tests/c-api/test-dlopen.c
+++ b/tests/c-api/test-dlopen.c
@@ -24,6 +24,8 @@
 #include <stdlib.h>
 #include <unistd.h>
 #include <dlfcn.h>
+#include <errno.h>
+#include <error.h>
 
 /* We don't need the <guestfs.h> header file here. */
 typedef struct guestfs_h guestfs_h;
@@ -44,10 +46,9 @@ read_symbol (void *lib, const char *symbol)
 
   dlerror (); /* Clear error indicator. */
   symval = dlsym (lib, symbol);
-  if ((err = dlerror ()) != NULL) {
-    fprintf (stderr, "could not read symbol: %s: %s\n", symbol, err);
-    exit (EXIT_FAILURE);
-  }
+  if ((err = dlerror ()) != NULL)
+    error (EXIT_FAILURE, 0,
+           "could not read symbol: %s: %s", symbol, err);
   return symval;
 }
 
@@ -60,35 +61,26 @@ main (int argc, char *argv[])
   guestfs_close_t guestfs_close;
   guestfs_h *g;
 
-  if (access (LIBRARY, X_OK) == -1) {
-    fprintf (stderr, "test skipped because %s cannot be accessed: %m\n",
-             LIBRARY);
-    exit (77);
-  }
+  if (access (LIBRARY, X_OK) == -1)
+    error (77, errno, "test skipped because %s cannot be accessed", LIBRARY);
 
   lib = dlopen (LIBRARY, RTLD_LAZY);
-  if (lib == NULL) {
-    fprintf (stderr, "could not open %s: %s\n", LIBRARY, dlerror ());
-    exit (EXIT_FAILURE);
-  }
+  if (lib == NULL)
+    error (EXIT_FAILURE, 0, "could not open %s: %s", LIBRARY, dlerror ());
 
   guestfs_create = read_symbol (lib, "guestfs_create");
   guestfs_get_program = read_symbol (lib, "guestfs_get_program");
   guestfs_close = read_symbol (lib, "guestfs_close");
 
   g = guestfs_create ();
-  if (g == NULL) {
-    fprintf (stderr, "failed to create handle\n");
-    exit (EXIT_FAILURE);
-  }
+  if (g == NULL)
+    error (EXIT_FAILURE, errno, "guestfs_create");
   printf ("program = %s\n", guestfs_get_program (g));
 
   guestfs_close (g);
 
-  if (dlclose (lib) != 0) {
-    fprintf (stderr, "could not close %s: %s\n", LIBRARY, dlerror ());
-    exit (EXIT_FAILURE);
-  }
+  if (dlclose (lib) != 0)
+    error (EXIT_FAILURE, 0, "could not close %s: %s", LIBRARY, dlerror ());
 
   exit (EXIT_SUCCESS);
 }
diff --git a/tests/c-api/test-last-errno.c b/tests/c-api/test-last-errno.c
index 135d672..acd5cd9 100644
--- a/tests/c-api/test-last-errno.c
+++ b/tests/c-api/test-last-errno.c
@@ -28,6 +28,7 @@
 #include <unistd.h>
 #include <fcntl.h>
 #include <errno.h>
+#include <error.h>
 
 #include "guestfs.h"
 #include "guestfs-internal-frontend.h"
@@ -40,10 +41,8 @@ main (int argc, char *argv[])
   struct guestfs_stat *stat;
 
   g = guestfs_create ();
-  if (g == NULL) {
-    fprintf (stderr, "failed to create handle\n");
-    exit (EXIT_FAILURE);
-  }
+  if (g == NULL)
+    error (EXIT_FAILURE, errno, "guestfs_create");
 
   if (guestfs_add_drive_scratch (g, 524288000, -1) == -1)
     exit (EXIT_FAILURE);
@@ -64,18 +63,14 @@ main (int argc, char *argv[])
     exit (EXIT_FAILURE);
 
   r = guestfs_touch (g, "/test");
-  if (r != -1) {
-    fprintf (stderr,
-             "guestfs_touch: expected error for read-only filesystem\n");
-    exit (EXIT_FAILURE);
-  }
+  if (r != -1)
+    error (EXIT_FAILURE, 0,
+           "guestfs_touch: expected error for read-only filesystem");
 
   err = guestfs_last_errno (g);
-  if (err != EROFS) {
-    fprintf (stderr,
-             "guestfs_touch: expected errno == EROFS, but got %d\n", err);
-    exit (EXIT_FAILURE);
-  }
+  if (err != EROFS)
+    error (EXIT_FAILURE, 0,
+           "guestfs_touch: expected errno == EROFS, but got %d", err);
 
   if (guestfs_umount (g, "/") == -1)
     exit (EXIT_FAILURE);
@@ -85,35 +80,27 @@ main (int argc, char *argv[])
     exit (EXIT_FAILURE);
 
   stat = guestfs_lstat (g, "/nosuchfile");
-  if (stat != NULL) {
-    fprintf (stderr,
-             "guestfs_lstat: expected error for missing file\n");
-    exit (EXIT_FAILURE);
-  }
+  if (stat != NULL)
+    error (EXIT_FAILURE, 0,
+           "guestfs_lstat: expected error for missing file");
 
   err = guestfs_last_errno (g);
-  if (err != ENOENT) {
-    fprintf (stderr,
-             "guestfs_lstat: expected errno == ENOENT, but got %d\n", err);
-    exit (EXIT_FAILURE);
-  }
+  if (err != ENOENT)
+    error (EXIT_FAILURE, 0,
+           "guestfs_lstat: expected errno == ENOENT, but got %d", err);
 
   if (guestfs_touch (g, "/test") == -1)
     exit (EXIT_FAILURE);
 
   r = guestfs_mkdir (g, "/test");
-  if (r != -1) {
-    fprintf (stderr,
-             "guestfs_mkdir: expected error for file which exists\n");
-    exit (EXIT_FAILURE);
-  }
+  if (r != -1)
+    error (EXIT_FAILURE, 0,
+           "guestfs_mkdir: expected error for file which exists");
 
   err = guestfs_last_errno (g);
-  if (err != EEXIST) {
-    fprintf (stderr,
-             "guestfs_mkdir: expected errno == EEXIST, but got %d\n", err);
-    exit (EXIT_FAILURE);
-  }
+  if (err != EEXIST)
+    error (EXIT_FAILURE, 0,
+           "guestfs_mkdir: expected errno == EEXIST, but got %d", err);
 
   guestfs_close (g);
 
diff --git a/tests/c-api/test-private-data.c b/tests/c-api/test-private-data.c
index 349d959..9ebe7a8 100644
--- a/tests/c-api/test-private-data.c
+++ b/tests/c-api/test-private-data.c
@@ -25,6 +25,8 @@
 #include <string.h>
 #include <unistd.h>
 #include <assert.h>
+#include <errno.h>
+#include <error.h>
 
 #include "guestfs.h"
 #include "guestfs-internal-frontend.h"
@@ -68,10 +70,8 @@ main (int argc, char *argv[])
   size_t count;
 
   g = guestfs_create ();
-  if (g == NULL) {
-    fprintf (stderr, "failed to create handle\n");
-    exit (EXIT_FAILURE);
-  }
+  if (g == NULL)
+    error (EXIT_FAILURE, errno, "guestfs_create");
 
   if (guestfs_set_event_callback (g, close_callback, GUESTFS_EVENT_CLOSE,
                                   0, NULL) == -1)
diff --git a/tests/c-api/test-user-cancel.c b/tests/c-api/test-user-cancel.c
index 029c405..3823682 100644
--- a/tests/c-api/test-user-cancel.c
+++ b/tests/c-api/test-user-cancel.c
@@ -75,10 +75,8 @@ main (int argc, char *argv[])
   srand48 (time (NULL));
 
   g = guestfs_create ();
-  if (g == NULL) {
-    fprintf (stderr, "failed to create handle\n");
-    exit (EXIT_FAILURE);
-  }
+  if (g == NULL)
+    error (EXIT_FAILURE, errno, "guestfs_create");
 
   if (guestfs_add_drive_scratch (g, filesize, -1) == -1)
     exit (EXIT_FAILURE);
@@ -115,10 +113,8 @@ main (int argc, char *argv[])
 
   /* Create the test thread. */
   r = pthread_create (&test_thread, NULL, start_test_thread, &data);
-  if (r != 0) {
-    fprintf (stderr, "pthread_create: %s\n", strerror (r));
-    exit (EXIT_FAILURE);
-  }
+  if (r != 0)
+    error (EXIT_FAILURE, r, "pthread_create");
 
   /* Do the upload. */
   op_error = guestfs_upload (g, dev_fd, "/upload");
@@ -126,15 +122,11 @@ main (int argc, char *argv[])
 
   /* Kill the test thread and clean up. */
   r = pthread_cancel (test_thread);
-  if (r != 0) {
-    fprintf (stderr, "pthread_cancel: %s\n", strerror (r));
-    exit (EXIT_FAILURE);
-  }
+  if (r != 0)
+    error (EXIT_FAILURE, r, "pthread_cancel");
   r = pthread_join (test_thread, NULL);
-  if (r != 0) {
-    fprintf (stderr, "pthread_join: %s\n", strerror (r));
-    exit (EXIT_FAILURE);
-  }
+  if (r != 0)
+    error (EXIT_FAILURE, r, "pthread_join");
 
   close (fds[0]);
   close (fds[1]);
@@ -179,10 +171,8 @@ main (int argc, char *argv[])
 
   /* Create the test thread. */
   r = pthread_create (&test_thread, NULL, start_test_thread, &data);
-  if (r != 0) {
-    fprintf (stderr, "pthread_create: %s\n", strerror (r));
-    exit (EXIT_FAILURE);
-  }
+  if (r != 0)
+    error (EXIT_FAILURE, r, "pthread_create");
 
   /* Do the download. */
   op_error = guestfs_download (g, "/download", dev_fd);
@@ -190,15 +180,11 @@ main (int argc, char *argv[])
 
   /* Kill the test thread and clean up. */
   r = pthread_cancel (test_thread);
-  if (r != 0) {
-    fprintf (stderr, "pthread_cancel: %s\n", strerror (r));
-    exit (EXIT_FAILURE);
-  }
+  if (r != 0)
+    error (EXIT_FAILURE, r, "pthread_cancel");
   r = pthread_join (test_thread, NULL);
-  if (r != 0) {
-    fprintf (stderr, "pthread_join: %s\n", strerror (r));
-    exit (EXIT_FAILURE);
-  }
+  if (r != 0)
+    error (EXIT_FAILURE, r, "pthread_join");
 
   close (fds[0]);
   close (fds[1]);
diff --git a/tests/c-api/tests-main.c b/tests/c-api/tests-main.c
index dd5c2b6..e3af651 100644
--- a/tests/c-api/tests-main.c
+++ b/tests/c-api/tests-main.c
@@ -345,11 +345,9 @@ match_re (const char *str, const char *pattern)
   int vec[30], r;
 
   re = pcre_compile (pattern, 0, &err, &offset, NULL);
-  if (re == NULL) {
-    fprintf (stderr, "tests: cannot compile regular expression '%s': %s\n",
-             pattern, err);
-    exit (EXIT_FAILURE);
-  }
+  if (re == NULL)
+    error (EXIT_FAILURE, 0,
+           "cannot compile regular expression '%s': %s", pattern, err);
   r = pcre_exec (re, NULL, str, len, 0, 0, vec, sizeof vec / sizeof vec[0]);
   pcre_free (re);
 
@@ -370,13 +368,12 @@ substitute_srcdir (const char *path)
     const char *srcdir;
 
     srcdir = getenv ("srcdir");
-    if (!srcdir) {
-      fprintf (stderr, "tests: environment variable $srcdir is not defined.\n"
-               "Normally it is defined by automake.  If you are running the\n"
-               "tests directly, set $srcdir to point to the source tests/c-api\n"
-               "directory.\n");
-      exit (EXIT_FAILURE);
-    }
+    if (!srcdir)
+      error (EXIT_FAILURE, 0,
+             "environment variable $srcdir is not defined.\n"
+             "Normally it is defined by automake.  If you are running the\n"
+             "tests directly, set $srcdir to point to the source tests/c-api\n"
+             "directory.");
 
     if (asprintf (&ret, "%s%s", srcdir, path + 7) == -1)
       error (EXIT_FAILURE, errno, "asprintf");
@@ -485,17 +482,12 @@ check_cross_appliance (guestfs_h *g)
   struct guestfs_utsname host_utsname;
 
   r = uname (&host);
-  if (r == -1) {
-    fprintf (stderr, "call to uname failed\n");
-    exit (EXIT_FAILURE);
-  }
+  if (r == -1)
+    error (EXIT_FAILURE, errno, "uname");
 
   appliance = guestfs_utsname (g);
-  if (appliance == NULL) {
-    fprintf (stderr, "call to guestfs_utsname failed: %d, %s\n",
-             guestfs_last_errno (g), guestfs_last_error (g));
+  if (appliance == NULL)
     exit (EXIT_FAILURE);
-  }
 
   host_utsname.uts_sysname = host.sysname;
   host_utsname.uts_release = host.release;
diff --git a/tests/events/test-libvirt-auth-callbacks.c b/tests/events/test-libvirt-auth-callbacks.c
index 86e26f8..a18ab24 100644
--- a/tests/events/test-libvirt-auth-callbacks.c
+++ b/tests/events/test-libvirt-auth-callbacks.c
@@ -55,22 +55,17 @@ main (int argc, char *argv[])
    * supports the new test-driver auth feature.
    */
   virGetVersion (&ver, NULL, NULL);
-  if (ver < 1002001) {
-    fprintf (stderr, "%s: test skipped because libvirt is too old (%lu)\n",
-             argv[0], ver);
-    exit (77);
-  }
+  if (ver < 1002001)
+    error (77, 0, "test skipped because libvirt is too old (%lu)", ver);
 
   /* $srcdir must have been passed (by automake). */
   srcdir = getenv ("srcdir");
-  if (!srcdir) {
-    fprintf (stderr,
-             "%s: environment variable $srcdir is not defined.\n"
-             "Normally it is defined by automake.  If you are running the\n"
-             "tests directly, set $srcdir to point to the source tests/events\n"
-             "directory.\n", argv[0]);
-    exit (EXIT_FAILURE);
-  }
+  if (!srcdir)
+    error (EXIT_FAILURE, 0,
+           "environment variable $srcdir is not defined.\n"
+           "Normally it is defined by automake.  If you are running the\n"
+           "tests directly, set $srcdir to point to the source tests/events\n"
+           "directory.");
 
   cwd = getcwd (NULL, 0);
   if (cwd == NULL)
@@ -107,7 +102,7 @@ do_test (const char *prog, const char *libvirt_uri,
 
   g = guestfs_create ();
   if (!g)
-    exit (EXIT_FAILURE);
+    error (EXIT_FAILURE, errno, "guestfs_create");
 
   r = guestfs_set_libvirt_supported_credentials (g, (char **) creds);
   if (r == -1)
@@ -123,13 +118,11 @@ do_test (const char *prog, const char *libvirt_uri,
                           GUESTFS_ADD_DOMAIN_LIBVIRTURI, libvirt_uri,
                           GUESTFS_ADD_DOMAIN_READONLY, 1,
                           -1);
-  if (r != expected) {
-    fprintf (stderr,
-             "%s: test failed: u=%s p=%s: got %d expected %d\n",
-             prog, auth_data->username, auth_data->password ? : "(none)",
-             r, expected);
-    exit (EXIT_FAILURE);
-  }
+  if (r != expected)
+    error (EXIT_FAILURE, 0,
+           "test failed: u=%s p=%s: got %d expected %d",
+           auth_data->username, auth_data->password ? : "(none)",
+           r, expected);
 
   guestfs_close (g);
 }
@@ -161,18 +154,18 @@ auth_callback (guestfs_h *g, void *opaque,
     }
     else if (STREQ (creds[i], "passphrase") ||
              STREQ (creds[i], "noechoprompt")) {
-      if (!auth_data->password) {
-        fprintf (stderr, "test failed: libvirt asked for a password, but auth_data->password == NULL\n");
-        exit (EXIT_FAILURE);
-      }
+      if (!auth_data->password)
+        error (EXIT_FAILURE, 0,
+               "test failed: libvirt asked for a password, but auth_data->password == NULL");
 
       reply = auth_data->password;
       len = strlen (reply);
     }
     else {
-      fprintf (stderr, "test failed: libvirt asked for '%s' which is not in creds list\n(This is probably a libvirt bug)\n",
-               creds[i]);
-      exit (EXIT_FAILURE);
+      error (EXIT_FAILURE, 0,
+             "test failed: libvirt asked for '%s' which is not in creds list\n(This is probably a libvirt bug)",
+             creds[i]);
+      abort (); /* keeps GCC happy since error(3) is not marked noreturn */
     }
 
     r = guestfs_set_libvirt_requested_credential (g, i,
diff --git a/tests/qemu/qemu-boot.c b/tests/qemu/qemu-boot.c
index fe7ce95..61d2ff0 100644
--- a/tests/qemu/qemu-boot.c
+++ b/tests/qemu/qemu-boot.c
@@ -122,11 +122,10 @@ main (int argc, char *argv[])
             log_file_size += 64;
         }
       }
-      else {
-        fprintf (stderr, "%s: unknown long option: %s (%d)\n",
-                 guestfs_int_program_name, long_options[option_index].name, option_index);
-        exit (EXIT_FAILURE);
-      }
+      else
+        error (EXIT_FAILURE, 0,
+               "unknown long option: %s (%d)",
+               long_options[option_index].name, option_index);
       break;
 
     case 'i':
@@ -134,18 +133,13 @@ main (int argc, char *argv[])
       break;
 
     case 'n':
-      if (sscanf (optarg, "%zu", &n) != 1 || n == 0) {
-        fprintf (stderr, "%s: -n option not numeric and greater than 0\n",
-                 guestfs_int_program_name);
-        exit (EXIT_FAILURE);
-      }
+      if (sscanf (optarg, "%zu", &n) != 1 || n == 0)
+        error (EXIT_FAILURE, 0, "-n option not numeric and greater than 0");
       break;
 
     case 'P':
-      if (sscanf (optarg, "%zu", &P) != 1) {
-        fprintf (stderr, "%s: -P option not numeric\n", guestfs_int_program_name);
-        exit (EXIT_FAILURE);
-      }
+      if (sscanf (optarg, "%zu", &P) != 1)
+        error (EXIT_FAILURE, 0, "-P option not numeric");
       break;
 
     case 'v':
@@ -164,18 +158,13 @@ main (int argc, char *argv[])
     }
   }
 
-  if (n == 0) {
-    fprintf (stderr,
-             "%s: must specify number of processes to run (-n option)\n",
-             guestfs_int_program_name);
-    exit (EXIT_FAILURE);
-  }
+  if (n == 0)
+    error (EXIT_FAILURE, 0,
+           "must specify number of processes to run (-n option)");
 
-  if (optind != argc) {
-    fprintf (stderr, "%s: extra arguments found on the command line\n",
-             guestfs_int_program_name);
-    exit (EXIT_FAILURE);
-  }
+  if (optind != argc)
+    error (EXIT_FAILURE, 0,
+           "extra arguments found on the command line");
 
   /* Calculate the number of threads to use. */
   if (P > 0)
@@ -205,11 +194,8 @@ run_test (size_t P)
   for (i = 0; i < P; ++i) {
     thread_data[i].thread_num = i;
     err = pthread_create (&threads[i], NULL, start_thread, &thread_data[i]);
-    if (err != 0) {
-      fprintf (stderr, "%s: pthread_create[%zu]: %s\n",
-               guestfs_int_program_name, i, strerror (err));
-      exit (EXIT_FAILURE);
-    }
+    if (err != 0)
+      error (EXIT_FAILURE, err, "pthread_create[%zu]\n", i);
   }
 
   /* Wait for the threads to exit. */
diff --git a/tests/regressions/rhbz790721.c b/tests/regressions/rhbz790721.c
index ae44e68..e2178e5 100644
--- a/tests/regressions/rhbz790721.c
+++ b/tests/regressions/rhbz790721.c
@@ -90,10 +90,8 @@ main (int argc, char *argv[])
   for (i = 0; i < NR_THREADS; ++i) {
     data[i] = i;
     r = pthread_create (&thread[i], NULL, start_thread, &data[i]);
-    if (r != 0) {
-      fprintf (stderr, "pthread_create: %s\n", strerror (r));
-      exit (EXIT_FAILURE);
-    }
+    if (r != 0)
+      error (EXIT_FAILURE, r, "pthread_create");
   }
 
   /* Wait for the threads to exit. */
@@ -103,10 +101,8 @@ main (int argc, char *argv[])
     int *ret;
 
     r = pthread_join (thread[i], (void **) &ret);
-    if (r != 0) {
-      fprintf (stderr, "pthread_join: %s\n", strerror (r));
-      exit (EXIT_FAILURE);
-    }
+    if (r != 0)
+      error (EXIT_FAILURE, r, "pthread_join");
     if (*ret == -1)
       errors++;
   }
-- 
2.7.4




More information about the Libguestfs mailing list