summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorRichard W.M. Jones <rjones@redhat.com>2010-11-03 15:49:36 +0000
committerRichard W.M. Jones <rjones@redhat.com>2010-11-03 18:48:56 +0000
commit2066805a5d93b62beaf6653324715f0b62b06a05 (patch)
tree393ec11feb514069cf5cfb102b24a4d3a75d7e40 /src
parentd859c283c469b9d9124d90d0ac32024671372ed5 (diff)
downloadlibguestfs-2066805a5d93b62beaf6653324715f0b62b06a05.tar.gz
libguestfs-2066805a5d93b62beaf6653324715f0b62b06a05.tar.xz
libguestfs-2066805a5d93b62beaf6653324715f0b62b06a05.zip
lib: Expose errno through new API guestfs_last_errno.
If either the daemon sends back an errno, or a system call fails in the library, save the errno in the handle and then make it available to callers through the guestfs_last_errno function.
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am29
-rw-r--r--src/guestfs-internal.h5
-rw-r--r--src/guestfs.c21
-rw-r--r--src/guestfs.h2
-rw-r--r--src/guestfs.pod69
5 files changed, 98 insertions, 28 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 4c5468bc..4bcf7e9e 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -24,15 +24,19 @@ generator_built = \
guestfs-internal-actions.h \
actions.c \
bindtests.c \
+ errnostring_gperf.gperf \
+ errnostring.c \
+ errnostring.h
guestfs-actions.pod \
guestfs-availability.pod \
guestfs-structs.pod \
libguestfs.syms
BUILT_SOURCES = \
- $(generator_built) \
- guestfs_protocol.c \
- guestfs_protocol.h
+ $(generator_built) \
+ guestfs_protocol.c \
+ guestfs_protocol.h \
+ errnostring_gperf.c
EXTRA_DIST = \
$(BUILT_SOURCES) \
@@ -52,6 +56,19 @@ libprotocol_la_SOURCES = \
libprotocol_la_CFLAGS =
+# Build the errnostring perfect hash code. The generated code has lots
+# of warnings so we must compile it in a separate mini-library.
+liberrnostring_la_SOURCES = \
+ errnostring_gperf.c \
+ errnostring.h \
+ errnostring.c
+liberrnostring_la_CFLAGS =
+
+errnostring_gperf.c: errnostring_gperf.gperf
+ rm -f $@
+ $(GPERF) -t $< > $@-t
+ mv $@-t $@
+
# From the libtool info file, with comments:
#
# | 1. Start with version information of `0:0:0' for each libtool library.
@@ -115,9 +132,9 @@ libguestfs_la_SOURCES = \
libguestfs_la_LIBADD = $(HIVEX_LIBS) $(AUGEAS_LIBS) $(LIBPCRE) $(LIBMAGIC) $(LTLIBTHREAD) ../gnulib/lib/libgnu.la
-# Make libguestfs include the convenience library.
-noinst_LTLIBRARIES = libprotocol.la
-libguestfs_la_LIBADD += libprotocol.la
+# Make libguestfs include the convenience libraries.
+noinst_LTLIBRARIES = liberrnostring.la libprotocol.la
+libguestfs_la_LIBADD += liberrnostring.la libprotocol.la
libguestfs_la_CFLAGS = \
-DGUESTFS_DEFAULT_PATH='"$(libdir)/guestfs"' \
diff --git a/src/guestfs-internal.h b/src/guestfs-internal.h
index ffd8cf15..9c7c96cc 100644
--- a/src/guestfs-internal.h
+++ b/src/guestfs-internal.h
@@ -114,6 +114,7 @@ struct guestfs_h
int selinux; /* selinux enabled? */
char *last_error;
+ int last_errnum; /* errno, or 0 if there was no errno */
/* Callbacks. */
guestfs_abort_cb abort_cb;
@@ -200,6 +201,8 @@ struct guestfs_message_error;
extern void guestfs_error (guestfs_h *g, const char *fs, ...)
__attribute__((format (printf,2,3)));
+extern void guestfs_error_errno (guestfs_h *g, int errnum, const char *fs, ...)
+ __attribute__((format (printf,3,4)));
extern void guestfs_perrorf (guestfs_h *g, const char *fs, ...)
__attribute__((format (printf,2,3)));
extern void *guestfs_safe_realloc (guestfs_h *g, void *ptr, int nbytes);
@@ -221,7 +224,7 @@ extern int guestfs___accept_from_daemon (guestfs_h *g);
extern int guestfs___build_appliance (guestfs_h *g, char **kernel, char **initrd, char **appliance);
extern void guestfs___print_BufferIn (FILE *out, const char *buf, size_t buf_size);
-#define error guestfs_error
+#define error(g,...) guestfs_error_errno((g),0,__VA_ARGS__)
#define perrorf guestfs_perrorf
#define safe_calloc guestfs_safe_calloc
#define safe_malloc guestfs_safe_malloc
diff --git a/src/guestfs.c b/src/guestfs.c
index df13d517..e4f74e0e 100644
--- a/src/guestfs.c
+++ b/src/guestfs.c
@@ -270,11 +270,18 @@ guestfs_last_error (guestfs_h *g)
return g->last_error;
}
+int
+guestfs_last_errno (guestfs_h *g)
+{
+ return g->last_errnum;
+}
+
static void
-set_last_error (guestfs_h *g, const char *msg)
+set_last_error (guestfs_h *g, int errnum, const char *msg)
{
free (g->last_error);
g->last_error = strdup (msg);
+ g->last_errnum = errnum;
}
static void
@@ -284,7 +291,7 @@ default_error_cb (guestfs_h *g, void *data, const char *msg)
}
void
-guestfs_error (guestfs_h *g, const char *fs, ...)
+guestfs_error_errno (guestfs_h *g, int errnum, const char *fs, ...)
{
va_list args;
char *msg;
@@ -295,8 +302,11 @@ guestfs_error (guestfs_h *g, const char *fs, ...)
if (err < 0) return;
+ /* set_last_error first so that the callback can access the error
+ * message and errno through the handle if it wishes.
+ */
+ set_last_error (g, errnum, msg);
if (g->error_cb) g->error_cb (g, g->error_cb_data, msg);
- set_last_error (g, msg);
free (msg);
}
@@ -327,8 +337,11 @@ guestfs_perrorf (guestfs_h *g, const char *fs, ...)
strcat (msg, ": ");
strcat (msg, buf);
+ /* set_last_error first so that the callback can access the error
+ * message and errno through the handle if it wishes.
+ */
+ set_last_error (g, errnum, msg);
if (g->error_cb) g->error_cb (g, g->error_cb_data, msg);
- set_last_error (g, msg);
free (msg);
}
diff --git a/src/guestfs.h b/src/guestfs.h
index 911e9565..977b4c59 100644
--- a/src/guestfs.h
+++ b/src/guestfs.h
@@ -44,6 +44,8 @@ extern void guestfs_close (guestfs_h *g);
/*--- Error handling ---*/
extern const char *guestfs_last_error (guestfs_h *g);
+#define LIBGUESTFS_HAVE_LAST_ERRNO 1
+extern int guestfs_last_errno (guestfs_h *g);
typedef void (*guestfs_error_handler_cb) (guestfs_h *g, void *opaque, const char *msg);
typedef void (*guestfs_abort_cb) (void) __attribute__((__noreturn__));
diff --git a/src/guestfs.pod b/src/guestfs.pod
index 603fe209..da031286 100644
--- a/src/guestfs.pod
+++ b/src/guestfs.pod
@@ -770,20 +770,6 @@ The error message you get from this is also a little obscure.
This could be fixed in the generator by specially marking parameters
and return values which take bytes or other units.
-=item Library should return errno with error messages.
-
-It would be a nice-to-have to be able to get the original value of
-'errno' from inside the appliance along error paths (where set).
-Currently L<guestmount(1)> goes through hoops to try to reverse the
-error message string into an errno, see the function error() in
-fuse/guestmount.c.
-
-In libguestfs 1.5.4, the protocol was changed so that the
-Linux errno is sent back from the daemon.
-
-In libguestfs 1.7.1, the protocol was changed again to send the
-errno back as a string (for portability between differing Un*xes).
-
=item Ambiguity between devices and paths
There is a subtle ambiguity in the API between a device name
@@ -892,9 +878,16 @@ This closes the connection handle and frees up all resources used.
=head1 ERROR HANDLING
The convention in all functions that return C<int> is that they return
-C<-1> to indicate an error. You can get additional information on
-errors by calling L</guestfs_last_error> and/or by setting up an error
-handler with L</guestfs_set_error_handler>.
+C<-1> to indicate an error.
+
+Additional information is available for errors: an error message
+string and optionally an error number (errno) if the thing that failed
+was a system call.
+
+You can get at the additional information about the last error on the
+handle by calling L</guestfs_last_error>, L</guestfs_last_errno>,
+and/or by setting up an error handler with
+L</guestfs_set_error_handler>.
The default error handler prints the information string to C<stderr>.
@@ -917,6 +910,45 @@ The error string is not localized (ie. is always in English), because
this makes searching for error messages in search engines give the
largest number of results.
+=head2 guestfs_last_errno
+
+ int guestfs_last_errno (guestfs_h *g);
+
+This returns the last error number (errno) that happened on C<g>.
+
+If successful, an errno integer not equal to zero is returned.
+
+If no error, this returns 0. This call can return 0 in three
+situations:
+
+=over 4
+
+=item 1.
+
+There has not been any error on the handle.
+
+=item 2.
+
+There has been an error but the errno was meaningless. This
+corresponds to the case where the error did not come from a
+failed system call, but for some other reason.
+
+=item 3.
+
+There was an error from a failed system call, but for some
+reason the errno was not captured and returned. This usually
+indicates a bug in libguestfs.
+
+=back
+
+Libguestfs tries to convert the errno from inside the applicance into
+a corresponding errno for the caller (not entirely trivial: the
+appliance might be running a completely different operating system
+from the library and error numbers are not standardized across
+Un*xen). If this could not be done, then the error is translated to
+C<EINVAL>. In practice this should only happen in very rare
+circumstances.
+
=head2 guestfs_set_error_handler
typedef void (*guestfs_error_handler_cb) (guestfs_h *g,
@@ -930,6 +962,9 @@ The callback C<cb> will be called if there is an error. The
parameters passed to the callback are an opaque data pointer and the
error message string.
+C<errno> is not passed to the callback. To get that the callback must
+call L</guestfs_last_errno>.
+
Note that the message string C<msg> is freed as soon as the callback
function returns, so if you want to stash it somewhere you must make
your own copy.