summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard W.M. Jones <rjones@redhat.com>2010-11-03 12:53:00 +0000
committerRichard W.M. Jones <rjones@redhat.com>2010-11-03 17:44:30 +0000
commitd859c283c469b9d9124d90d0ac32024671372ed5 (patch)
tree8d8cfd99b88d86b618d1877829ad2c0ae3610d5a
parent2be1648632e5e8dca06d84349314ab5e84f29e5c (diff)
downloadlibguestfs-d859c283c469b9d9124d90d0ac32024671372ed5.tar.gz
libguestfs-d859c283c469b9d9124d90d0ac32024671372ed5.tar.xz
libguestfs-d859c283c469b9d9124d90d0ac32024671372ed5.zip
daemon: Send back the errno as a string.
This changes the protocol again so that if the errno is available, it is converted to a string (like "EIO") and sent back over the protocol to the library. In this commit the library just discards the string.
-rw-r--r--.gitignore4
-rw-r--r--daemon/Makefile.am13
-rw-r--r--daemon/proto.c7
-rw-r--r--generator/.depend12
-rw-r--r--generator/Makefile.am1
-rw-r--r--generator/generator_c.ml1
-rw-r--r--generator/generator_errnostring.ml273
-rw-r--r--generator/generator_main.ml3
-rw-r--r--generator/generator_xdr.ml5
-rw-r--r--po/POTFILES.in2
-rw-r--r--src/guestfs.pod3
11 files changed, 316 insertions, 8 deletions
diff --git a/.gitignore b/.gitignore
index 72288285..e5c9ffa5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -46,6 +46,8 @@ configure
cscope.out
csharp/
daemon/actions.h
+daemon/errnostring.c
+daemon/errnostring.h
daemon/guestfsd
daemon/guestfsd.exe
daemon/guestfs_protocol.c
@@ -250,6 +252,8 @@ ruby/ext/guestfs/mkmf.log
ruby/Rakefile
src/actions.c
src/bindtests.c
+src/errnostring.c
+src/errnostring.h
src/guestfs-actions.h
src/guestfs-internal-actions.h
src/guestfs_protocol.c
diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index 0e2ac6ef..2b585c27 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -36,7 +36,9 @@ $(generatorsrcdir)/stamp-generator: force
BUILT_SOURCES = \
$(generator_built) \
guestfs_protocol.c \
- guestfs_protocol.h
+ guestfs_protocol.h \
+ errnostring.c \
+ errnostring.h
EXTRA_DIST = $(BUILT_SOURCES) \
.gitignore
@@ -60,6 +62,13 @@ $(libsrcdir)/guestfs_protocol.c: force
$(libsrcdir)/guestfs_protocol.h: force
$(MAKE) -C $(libsrcdir) guestfs_protocol.h
+errnostring.c: $(libsrcdir)/errnostring.c
+ rm -f $@
+ ln $< $@
+errnostring.h: $(libsrcdir)/errnostring.h
+ rm -f $@
+ ln $< $@
+
noinst_PROGRAMS = guestfsd
guestfsd_SOURCES = \
actions.h \
@@ -82,6 +91,8 @@ guestfsd_SOURCES = \
dropcaches.c \
du.c \
echo_daemon.c \
+ errnostring.h \
+ errnostring.c \
ext2.c \
fallocate.c \
file.c \
diff --git a/daemon/proto.c b/daemon/proto.c
index f3b1fc0e..63d1cc99 100644
--- a/daemon/proto.c
+++ b/daemon/proto.c
@@ -39,6 +39,7 @@
#include "daemon.h"
#include "guestfs_protocol.h"
+#include "errnostring.h"
/* The message currently being processed. */
int proc_nr;
@@ -247,7 +248,11 @@ send_error (int errnum, const char *msg)
exit (EXIT_FAILURE);
}
- err.linux_errno = errnum;
+ /* These strings are not going to be freed. We just cast them
+ * to (char *) because they are defined that way in the XDR structs.
+ */
+ err.errno_string =
+ (char *) (errnum > 0 ? guestfs___errno_to_string (errnum) : "");
err.error_message = (char *) msg;
if (!xdr_guestfs_message_error (&xdr, &err)) {
diff --git a/generator/.depend b/generator/.depend
index ff9263ee..c9d1a519 100644
--- a/generator/.depend
+++ b/generator/.depend
@@ -115,15 +115,19 @@ generator_bindtests.cmo: generator_utils.cmi generator_types.cmo \
generator_bindtests.cmx: generator_utils.cmx generator_types.cmx \
generator_structs.cmx generator_pr.cmx generator_optgroups.cmx \
generator_docstrings.cmx generator_c.cmx generator_actions.cmx
+generator_errnostring.cmo: generator_utils.cmi generator_types.cmo \
+ generator_pr.cmi generator_docstrings.cmo
+generator_errnostring.cmx: generator_utils.cmx generator_types.cmx \
+ generator_pr.cmx generator_docstrings.cmx
generator_main.cmo: generator_xdr.cmo generator_structs.cmi \
generator_ruby.cmo generator_python.cmo generator_pr.cmi \
generator_php.cmo generator_perl.cmo generator_ocaml.cmo \
generator_java.cmo generator_haskell.cmo generator_fish.cmo \
- generator_daemon.cmo generator_csharp.cmo generator_capitests.cmo \
- generator_c.cmo generator_bindtests.cmo
+ generator_errnostring.cmo generator_daemon.cmo generator_csharp.cmo \
+ generator_capitests.cmo generator_c.cmo generator_bindtests.cmo
generator_main.cmx: generator_xdr.cmx generator_structs.cmx \
generator_ruby.cmx generator_python.cmx generator_pr.cmx \
generator_php.cmx generator_perl.cmx generator_ocaml.cmx \
generator_java.cmx generator_haskell.cmx generator_fish.cmx \
- generator_daemon.cmx generator_csharp.cmx generator_capitests.cmx \
- generator_c.cmx generator_bindtests.cmx
+ generator_errnostring.cmx generator_daemon.cmx generator_csharp.cmx \
+ generator_capitests.cmx generator_c.cmx generator_bindtests.cmx
diff --git a/generator/Makefile.am b/generator/Makefile.am
index f6dfd6b7..469265b6 100644
--- a/generator/Makefile.am
+++ b/generator/Makefile.am
@@ -44,6 +44,7 @@ SOURCES = \
generator_csharp.ml \
generator_php.ml \
generator_bindtests.ml \
+ generator_errnostring.ml \
generator_main.ml
SOURCES_ML = $(filter %.ml,$(SOURCES))
diff --git a/generator/generator_c.ml b/generator/generator_c.ml
index dad3ac30..513bc1da 100644
--- a/generator/generator_c.ml
+++ b/generator/generator_c.ml
@@ -804,6 +804,7 @@ check_state (guestfs_h *g, const char *caller)
pr " if (hdr.status == GUESTFS_STATUS_ERROR) {\n";
pr " error (g, \"%%s: %%s\", \"%s\", err.error_message);\n" shortname;
pr " free (err.error_message);\n";
+ pr " free (err.errno_string);\n";
pr " guestfs___end_busy (g);\n";
pr " return %s;\n" error_code;
pr " }\n";
diff --git a/generator/generator_errnostring.ml b/generator/generator_errnostring.ml
new file mode 100644
index 00000000..d0a5734f
--- /dev/null
+++ b/generator/generator_errnostring.ml
@@ -0,0 +1,273 @@
+(* libguestfs
+ * Copyright (C) 2010 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *)
+
+(* Please read generator/README first. *)
+
+open Printf
+
+open Generator_types
+open Generator_utils
+open Generator_pr
+open Generator_docstrings
+
+(* Generate the functions errno_to_string and string_to_errno which
+ * convert errno (eg. EINVAL) into string ("EINVAL") and back again,
+ * allowing us to portably pass error values over the protocol between
+ * different versions of Un*x.
+ *)
+
+(* Errors found in POSIX plus additional errors found in the Linux
+ * header files. NOTE keep this sorted and avoid duplicates.
+ *)
+let errnos = [
+ "E2BIG";
+ "EACCES";
+ "EADDRINUSE";
+ "EADDRNOTAVAIL";
+ "EADV";
+ "EAFNOSUPPORT";
+ "EAGAIN";
+ "EALREADY";
+ "EBADE";
+ "EBADF";
+ "EBADFD";
+ "EBADMSG";
+ "EBADR";
+ "EBADRQC";
+ "EBADSLT";
+ "EBFONT";
+ "EBUSY";
+ "ECANCELED";
+ "ECHILD";
+ "ECHRNG";
+ "ECOMM";
+ "ECONNABORTED";
+ "ECONNREFUSED";
+ "ECONNRESET";
+ (*"EDEADLK"; - same as EDEADLOCK*)
+ "EDEADLOCK";
+ "EDESTADDRREQ";
+ "EDOM";
+ "EDOTDOT";
+ "EDQUOT";
+ "EEXIST";
+ "EFAULT";
+ "EFBIG";
+ "EHOSTDOWN";
+ "EHOSTUNREACH";
+ "EIDRM";
+ "EILSEQ";
+ "EINPROGRESS";
+ "EINTR";
+ "EINVAL";
+ "EIO";
+ "EISCONN";
+ "EISDIR";
+ "EISNAM";
+ "EKEYEXPIRED";
+ "EKEYREJECTED";
+ "EKEYREVOKED";
+ "EL2HLT";
+ "EL2NSYNC";
+ "EL3HLT";
+ "EL3RST";
+ "ELIBACC";
+ "ELIBBAD";
+ "ELIBEXEC";
+ "ELIBMAX";
+ "ELIBSCN";
+ "ELNRNG";
+ "ELOOP";
+ "EMEDIUMTYPE";
+ "EMFILE";
+ "EMLINK";
+ "EMSGSIZE";
+ "EMULTIHOP";
+ "ENAMETOOLONG";
+ "ENAVAIL";
+ "ENETDOWN";
+ "ENETRESET";
+ "ENETUNREACH";
+ "ENFILE";
+ "ENOANO";
+ "ENOBUFS";
+ "ENOCSI";
+ "ENODATA";
+ "ENODEV";
+ "ENOENT";
+ "ENOEXEC";
+ "ENOKEY";
+ "ENOLCK";
+ "ENOLINK";
+ "ENOMEDIUM";
+ "ENOMEM";
+ "ENOMSG";
+ "ENONET";
+ "ENOPKG";
+ "ENOPROTOOPT";
+ "ENOSPC";
+ "ENOSR";
+ "ENOSTR";
+ "ENOSYS";
+ "ENOTBLK";
+ "ENOTCONN";
+ "ENOTDIR";
+ "ENOTEMPTY";
+ "ENOTNAM";
+ "ENOTRECOVERABLE";
+ "ENOTSOCK";
+ "ENOTSUP";
+ "ENOTTY";
+ "ENOTUNIQ";
+ "ENXIO";
+ (*"EOPNOTSUPP"; - duplicates another error, and we don't care because
+ it's a network error *)
+ "EOVERFLOW";
+ "EOWNERDEAD";
+ "EPERM";
+ "EPFNOSUPPORT";
+ "EPIPE";
+ "EPROTO";
+ "EPROTONOSUPPORT";
+ "EPROTOTYPE";
+ "ERANGE";
+ "EREMCHG";
+ "EREMOTE";
+ "EREMOTEIO";
+ "ERESTART";
+ "ERFKILL";
+ "EROFS";
+ "ESHUTDOWN";
+ "ESOCKTNOSUPPORT";
+ "ESPIPE";
+ "ESRCH";
+ "ESRMNT";
+ "ESTALE";
+ "ESTRPIPE";
+ "ETIME";
+ "ETIMEDOUT";
+ "ETOOMANYREFS";
+ "ETXTBSY";
+ "EUCLEAN";
+ "EUNATCH";
+ "EUSERS";
+ (*"EWOULDBLOCK"; - same as EAGAIN*)
+ "EXDEV";
+ "EXFULL";
+
+ (* This is a non-existent errno which is simply used to test that
+ * the generated code can handle such cases on future platforms
+ * where one of the above error codes might not exist.
+ *)
+ "EZZZ";
+]
+
+let () =
+ (* Check list is sorted and no duplicates. *)
+ let file = "generator/generator_errnostring.ml" in
+ let check str =
+ let len = String.length str in
+ if len == 0 || len > 32 then
+ failwithf "%s: errno empty or length > 32 (%s)" file str;
+ if str.[0] <> 'E' then
+ failwithf "%s: errno string does not begin with letter 'E' (%s)" file str;
+ for i = 0 to len-1 do
+ let c = str.[i] in
+ if Char.uppercase c <> c then
+ failwithf "%s: errno string is not all uppercase (%s)" file str
+ done
+ in
+ let rec loop = function
+ | [] -> ()
+ | x :: y :: xs when x = y ->
+ failwithf "%s: errnos list contains duplicates (%s)" file x
+ | x :: y :: xs when x > y ->
+ failwithf "%s: errnos list is not sorted (%s > %s)" file x y
+ | x :: xs -> check x; loop xs
+ in
+ loop errnos
+
+let generate_errnostring_h () =
+ generate_header CStyle LGPLv2plus;
+
+ pr "
+#ifndef GUESTFS_ERRNOSTRING_H_
+#define GUESTFS_ERRNOSTRING_H_
+
+/* Convert errno (eg. EIO) to its string representation (\"EIO\").
+ * This only works for a set of errors that are listed in the generator
+ * AND are supported on the local operating system. For other errors
+ * the string (\"EINVAL\") is returned.
+ *
+ * NOTE: It is an error to call this function with errnum == 0.
+ */
+extern const char *guestfs___errno_to_string (int errnum);
+
+/* Convert string representation of an error (eg. \"EIO\") to the errno
+ * value (EIO). As for the function above, this only works for a
+ * subset of errors. For errors not supported by the local operating
+ * system, EINVAL is returned (all POSIX-conforming systems must
+ * support EINVAL).
+ */
+//extern int guestfs___string_to_errno (const char *errnostr);
+
+#endif /* GUESTFS_ERRNOSTRING_H_ */
+"
+
+let generate_errnostring_c () =
+ generate_header CStyle LGPLv2plus;
+
+ pr "\
+#include <config.h>
+
+#include <stdlib.h>
+#include <errno.h>
+
+#include \"errnostring.h\"
+
+static const char *errno_to_string[] = {
+";
+
+ List.iter (
+ fun e ->
+ pr "#ifdef %s\n" e;
+ pr " [%s] = \"%s\",\n" e e;
+ pr "#endif\n"
+ ) errnos;
+
+ pr "\
+};
+
+#define ERRNO_TO_STRING_SIZE \\
+ (sizeof errno_to_string / sizeof errno_to_string[0])
+
+const char *
+guestfs___errno_to_string (int errnum)
+{
+ /* See function documentation. */
+ if (errnum == 0)
+ abort ();
+
+ if (errnum < 0 || (size_t) errnum >= ERRNO_TO_STRING_SIZE ||
+ errno_to_string[errnum] == NULL)
+ return \"EINVAL\";
+ else
+ return errno_to_string[errnum];
+}
+
+"
diff --git a/generator/generator_main.ml b/generator/generator_main.ml
index 401ae605..1aa15d0f 100644
--- a/generator/generator_main.ml
+++ b/generator/generator_main.ml
@@ -38,6 +38,7 @@ open Generator_haskell
open Generator_csharp
open Generator_php
open Generator_bindtests
+open Generator_errnostring
let perror msg = function
| Unix_error (err, _, _) ->
@@ -80,6 +81,8 @@ Run it from the top source directory using the command
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.c" generate_errnostring_c;
+ output_to "src/errnostring.h" generate_errnostring_h;
output_to "src/MAX_PROC_NR" generate_max_proc_nr;
output_to "src/libguestfs.syms" generate_linker_script;
output_to "daemon/actions.h" generate_daemon_actions_h;
diff --git a/generator/generator_xdr.ml b/generator/generator_xdr.ml
index 49421499..b44e2ef1 100644
--- a/generator/generator_xdr.ml
+++ b/generator/generator_xdr.ml
@@ -157,7 +157,7 @@ let generate_xdr () =
*/
const GUESTFS_PROGRAM = 0x2000F5F5;
-const GUESTFS_PROTOCOL_VERSION = 2;
+const GUESTFS_PROTOCOL_VERSION = 3;
/* These constants must be larger than any possible message length. */
const GUESTFS_LAUNCH_FLAG = 0xf5f55ff5;
@@ -181,7 +181,8 @@ enum guestfs_message_status {
pr "\
struct guestfs_message_error {
- int linux_errno; /* Linux errno if available. */
+ string errno_string<32>; /* errno eg. \"EINVAL\", empty string
+ if errno not available */
string error_message<GUESTFS_ERROR_LEN>;
};
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 699e90bc..17b98b45 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -16,6 +16,7 @@ daemon/dmesg.c
daemon/dropcaches.c
daemon/du.c
daemon/echo_daemon.c
+daemon/errnostring.c
daemon/ext2.c
daemon/fallocate.c
daemon/file.c
@@ -118,6 +119,7 @@ ruby/ext/guestfs/_guestfs.c
src/actions.c
src/appliance.c
src/bindtests.c
+src/errnostring.c
src/guestfs.c
src/inspect.c
src/launch.c
diff --git a/src/guestfs.pod b/src/guestfs.pod
index 50e9f50b..603fe209 100644
--- a/src/guestfs.pod
+++ b/src/guestfs.pod
@@ -781,6 +781,9 @@ 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