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.
This commit is contained in:
Richard W.M. Jones
2010-11-03 12:53:00 +00:00
parent 2be1648632
commit d859c283c4
11 changed files with 316 additions and 8 deletions

4
.gitignore vendored
View File

@@ -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

View File

@@ -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 \

View File

@@ -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)) {

View File

@@ -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

View File

@@ -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))

View File

@@ -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";

View File

@@ -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];
}
"

View File

@@ -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;

View File

@@ -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>;
};

View File

@@ -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

View File

@@ -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