diff options
author | Richard W.M. Jones <rjones@redhat.com> | 2010-11-03 15:49:36 +0000 |
---|---|---|
committer | Richard W.M. Jones <rjones@redhat.com> | 2010-11-03 18:48:56 +0000 |
commit | 2066805a5d93b62beaf6653324715f0b62b06a05 (patch) | |
tree | 393ec11feb514069cf5cfb102b24a4d3a75d7e40 /src | |
parent | d859c283c469b9d9124d90d0ac32024671372ed5 (diff) | |
download | libguestfs-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.am | 29 | ||||
-rw-r--r-- | src/guestfs-internal.h | 5 | ||||
-rw-r--r-- | src/guestfs.c | 21 | ||||
-rw-r--r-- | src/guestfs.h | 2 | ||||
-rw-r--r-- | src/guestfs.pod | 69 |
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. |