cscope.out
csharp/
daemon/actions.h
+daemon/errnostring_gperf.c
+daemon/errnostring_gperf.gperf
daemon/errnostring.c
daemon/errnostring.h
daemon/guestfsd
ruby/Rakefile
src/actions.c
src/bindtests.c
+src/errnostring_gperf.c
+src/errnostring_gperf.gperf
src/errnostring.c
src/errnostring.h
src/guestfs-actions.h
- libxml2
+- gperf
+
- Augeas (http://augeas.net/)
- squashfs-tools (mksquashfs only)
test "x$CPIO" = "xno" &&
AC_MSG_ERROR([cpio must be installed])
+dnl Check for gperf.
+AC_CHECK_PROG([GPERF],[gperf],[gperf],[no])
+test "x$GPERF" = "xno" &&
+ AC_MSG_ERROR([gperf must be installed])
+
dnl Check for pod2man and pod2text.
AC_CHECK_PROG([POD2MAN],[pod2man],[pod2man],[no])
test "x$POD2MAN" = "xno" &&
$(generator_built) \
guestfs_protocol.c \
guestfs_protocol.h \
+ errnostring_gperf.c \
+ errnostring_gperf.gperf \
errnostring.c \
errnostring.h
$(libsrcdir)/guestfs_protocol.h: force
$(MAKE) -C $(libsrcdir) guestfs_protocol.h
+# Build the errnostring perfect hash code. The generated code has lots
+# of warnings so we must compile it in a separate mini-library.
+noinst_LIBRARIES += liberrnostring.a
+liberrnostring_a_SOURCES = \
+ errnostring_gperf.c \
+ errnostring.h \
+ errnostring.c
+liberrnostring_a_CFLAGS =
+
+errnostring_gperf.c: errnostring_gperf.gperf
+ rm -f $@
+ $(GPERF) -t $< > $@-t
+ mv $@-t $@
+errnostring_gperf.gperf: $(libsrcdir)/errnostring_gperf.gperf
+ rm -f $@
+ ln $< $@
errnostring.c: $(libsrcdir)/errnostring.c
rm -f $@
ln $< $@
dropcaches.c \
du.c \
echo_daemon.c \
- errnostring.h \
- errnostring.c \
ext2.c \
fallocate.c \
file.c \
zero.c \
zerofree.c
guestfsd_LDADD = \
+ liberrnostring.a \
libprotocol.a \
lib/libgnu.a \
$(GETADDRINFO_LIB) \
AC_CHECK_MEMBER([struct stat.st_blksize],[
AC_DEFINE([HAVE_STRUCT_STAT_ST_BLKSIZE],[1],[Define to 1 if 'st_blksize' is a member of 'struct stat'])])
+dnl Check for gperf.
+AC_CHECK_PROG([GPERF],[gperf],[gperf],[no])
+test "x$GPERF" = "xno" &&
+ AC_MSG_ERROR([gperf must be installed])
+
dnl Check for Augeas (now optional).
AC_CHECK_LIB([augeas],[aug_match],[
LIBS="-laugeas $LIBS"
#include \"guestfs-internal.h\"
#include \"guestfs-internal-actions.h\"
#include \"guestfs_protocol.h\"
+#include \"errnostring.h\"
/* Check the return message from a call for validity. */
static int
pr "\n";
pr " if (hdr.status == GUESTFS_STATUS_ERROR) {\n";
- pr " error (g, \"%%s: %%s\", \"%s\", err.error_message);\n" shortname;
+ pr " int errnum = 0;\n";
+ pr " if (err.errno_string[0] != '\\0')\n";
+ pr " errnum = guestfs___string_to_errno (err.errno_string);\n";
+ pr " if (errnum <= 0)\n";
+ pr " error (g, \"%%s: %%s\", \"%s\", err.error_message);\n"
+ shortname;
+ pr " else\n";
+ pr " guestfs_error_errno (g, errnum, \"%%s: %%s\", \"%s\",\n"
+ shortname;
+ pr " err.error_message);\n";
pr " free (err.error_message);\n";
pr " free (err.errno_string);\n";
pr " guestfs___end_busy (g);\n";
"guestfs_get_error_handler";
"guestfs_get_out_of_memory_handler";
"guestfs_get_private";
+ "guestfs_last_errno";
"guestfs_last_error";
"guestfs_set_close_callback";
"guestfs_set_error_handler";
* system, EINVAL is returned (all POSIX-conforming systems must
* support EINVAL).
*/
-//extern int guestfs___string_to_errno (const char *errnostr);
+extern int guestfs___string_to_errno (const char *errnostr);
+
+/* Private structure and function used by the perfect hash implementation. */
+struct errnostring_entry { char *name; int errnum; };
+extern const struct errnostring_entry *guestfs___string_to_errno_lookup (register const char *str, register unsigned int len);
#endif /* GUESTFS_ERRNOSTRING_H_ */
"
#include <config.h>
#include <stdlib.h>
+#include <string.h>
#include <errno.h>
#include \"errnostring.h\"
return errno_to_string[errnum];
}
+int
+guestfs___string_to_errno (const char *errnostr)
+{
+ const struct errnostring_entry *v =
+ guestfs___string_to_errno_lookup (errnostr, strlen (errnostr));
+ if (v /* not necessary to check v->name != NULL here */)
+ return v->errnum;
+ else
+ return EINVAL;
+}
"
+
+let generate_errnostring_gperf () =
+ generate_header CStyle LGPLv2plus;
+
+ pr "\
+%%language=ANSI-C
+%%define lookup-function-name guestfs___string_to_errno_lookup
+%%readonly-tables
+%%null-strings
+
+%%{
+
+#include <config.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include \"errnostring.h\"
+
+";
+
+ (* Some of these errnos might not exist on the target platform, but
+ * we are going to include E_ macros directly in the C output of
+ * gperf. To avoid this causing errors, we include macros to define
+ * unknown errors as EINVAL (see specification of
+ * guestfs___string_to_errno above). Note this only affects the
+ * single output file containing gperf-generated code.
+ *)
+ List.iter (
+ fun e ->
+ pr "#ifndef %s\n" e;
+ pr "#define %s EINVAL\n" e;
+ pr "#endif\n";
+ ) errnos;
+
+ pr "\
+
+%%}
+
+struct errnostring_entry;
+
+%%%%
+";
+
+ List.iter (
+ fun e ->
+ pr "%s, %s\n" e e
+ ) errnos
output_to "src/guestfs-structs.pod" generate_structs_pod;
output_to "src/guestfs-actions.pod" generate_actions_pod;
output_to "src/guestfs-availability.pod" generate_availability_pod;
+ output_to "src/errnostring_gperf.gperf" generate_errnostring_gperf;
output_to "src/errnostring.c" generate_errnostring_c;
output_to "src/errnostring.h" generate_errnostring_h;
output_to "src/MAX_PROC_NR" generate_max_proc_nr;
daemon/du.c
daemon/echo_daemon.c
daemon/errnostring.c
+daemon/errnostring_gperf.c
daemon/ext2.c
daemon/fallocate.c
daemon/file.c
src/appliance.c
src/bindtests.c
src/errnostring.c
+src/errnostring_gperf.c
src/guestfs.c
src/inspect.c
src/launch.c
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) \
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.
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"' \
int selinux; /* selinux enabled? */
char *last_error;
+ int last_errnum; /* errno, or 0 if there was no errno */
/* Callbacks. */
guestfs_abort_cb abort_cb;
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);
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
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
}
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;
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);
}
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);
}
/*--- 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__));
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
=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>.
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,
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.