[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

Re: [libvirt] [PATCH] error: avoid API breakage with vmware



On 12/21/10 - 03:12:43PM, Eric Blake wrote:
> Fix glitch in commit cddd2a06 (thankfully post-0.8.6, so no
> released version has the glitch).
> 
> Document and try to workaround glitch in commit 46e9b0f (in 0.8.0,
> which invalidated 6 virErrorNumber dating back to 0.7.1).
> 
> Thankfully, my audit did not find any other glitches until pre-0.1.0
> days.  I'm not sure how to add a syntax-check off the top of my
> head, but hopefully the explicit numbering will make people think
> twice about renumbering in the future.
> 
> * include/libvirt/virterror.h (virErrorDomain): Avoid inserting
> new values in the middle, and add explicit numbering to help avoid
> this in the future.
> (virErrorNumber): Add explicit numbering, and document the snafu.
> * src/remote/remote_driver.c (remoteIO): Compensate for the snafu.

Thanks for looking at this, Eric.

> ---
>  include/libvirt/virterror.h |  266 ++++++++++++++++++++++++------------------
>  src/remote/remote_driver.c  |   30 +++++-
>  2 files changed, 181 insertions(+), 115 deletions(-)
> 
> diff --git a/include/libvirt/virterror.h b/include/libvirt/virterror.h
> index a1f88f4..0e59c0e 100644
> --- a/include/libvirt/virterror.h
> +++ b/include/libvirt/virterror.h
> @@ -4,7 +4,7 @@
>   * Description: Provides the interfaces of the libvirt library to handle
>   *              errors raised while using the library.
>   *
> - * Copy:  Copyright (C) 2006 Red Hat, Inc.
> + * Copy:  Copyright (C) 2006, 2010 Red Hat, Inc.
>   *
>   * See COPYING.LIB for the License of this software
>   *
> @@ -34,49 +34,51 @@ typedef enum {
>  /**
>   * virErrorDomain:
>   *
> - * Indicates where an error may have come from
> + * Indicates where an error may have come from.  This should remain
> + * stable, with all additions placed at the end since libvirt 0.1.0.
>   */
>  typedef enum {
>      VIR_FROM_NONE = 0,
> -    VIR_FROM_XEN,	/* Error at Xen hypervisor layer */
> -    VIR_FROM_XEND,	/* Error at connection with xend daemon */
> -    VIR_FROM_XENSTORE,	/* Error at connection with xen store */
> -    VIR_FROM_SEXPR,	/* Error in the S-Expression code */
> -    VIR_FROM_XML,	/* Error in the XML code */
> -    VIR_FROM_DOM,	/* Error when operating on a domain */
> -    VIR_FROM_RPC,	/* Error in the XML-RPC code */
> -    VIR_FROM_PROXY,	/* Error in the proxy code */ /* unused since 0.8.6 */
> -    VIR_FROM_CONF,	/* Error in the configuration file handling */
> -    VIR_FROM_QEMU,      /* Error at the QEMU daemon */
> -    VIR_FROM_NET,       /* Error when operating on a network */
> -    VIR_FROM_TEST,	/* Error from test driver */
> -    VIR_FROM_REMOTE,	/* Error from remote driver */
> -    VIR_FROM_OPENVZ,    /* Error from OpenVZ driver */
> -    VIR_FROM_VMWARE,    /* Error from VMware driver */
> -    VIR_FROM_XENXM,	/* Error at Xen XM layer */
> -    VIR_FROM_STATS_LINUX,/* Error in the Linux Stats code */
> -    VIR_FROM_LXC,       /* Error from Linux Container driver */
> -    VIR_FROM_STORAGE,   /* Error from storage driver */
> -    VIR_FROM_NETWORK,   /* Error from network config */
> -    VIR_FROM_DOMAIN,    /* Error from domain config */
> -    VIR_FROM_UML,       /* Error at the UML driver */
> -    VIR_FROM_NODEDEV,   /* Error from node device monitor */
> -    VIR_FROM_XEN_INOTIFY,/* Error from xen inotify layer */
> -    VIR_FROM_SECURITY,  /* Error from security framework */
> -    VIR_FROM_VBOX,      /* Error from VirtualBox driver */
> -    VIR_FROM_INTERFACE, /* Error when operating on an interface */
> -    VIR_FROM_ONE,       /* Error from OpenNebula driver */
> -    VIR_FROM_ESX,       /* Error from ESX driver */
> -    VIR_FROM_PHYP,      /* Error from IBM power hypervisor */
> -    VIR_FROM_SECRET,    /* Error from secret storage */
> -    VIR_FROM_CPU,       /* Error from CPU driver */
> -    VIR_FROM_XENAPI,    /* Error from XenAPI */
> -    VIR_FROM_NWFILTER,  /* Error from network filter driver */
> -    VIR_FROM_HOOK,      /* Error from Synchronous hooks */
> -    VIR_FROM_DOMAIN_SNAPSHOT, /* Error from domain snapshot */
> -    VIR_FROM_AUDIT,     /* Error from auditing subsystem */
> -    VIR_FROM_SYSINFO,   /* Error from sysinfo/SMBIOS */
> -    VIR_FROM_STREAMS,   /* Error from I/O streams */
> +    VIR_FROM_XEN = 1,		/* Error at Xen hypervisor layer */
> +    VIR_FROM_XEND = 2,		/* Error at connection with xend daemon */
> +    VIR_FROM_XENSTORE = 3,	/* Error at connection with xen store */
> +    VIR_FROM_SEXPR = 4,		/* Error in the S-Expression code */
> +    VIR_FROM_XML = 5,		/* Error in the XML code */
> +    VIR_FROM_DOM = 6,		/* Error when operating on a domain */
> +    VIR_FROM_RPC = 7,		/* Error in the XML-RPC code */
> +    VIR_FROM_PROXY = 8,		/* Error in the proxy code; unused since
> +                                   0.8.6 */
> +    VIR_FROM_CONF = 9,		/* Error in the configuration file handling */
> +    VIR_FROM_QEMU = 10,		/* Error at the QEMU daemon */
> +    VIR_FROM_NET = 11,		/* Error when operating on a network */
> +    VIR_FROM_TEST = 12,		/* Error from test driver */
> +    VIR_FROM_REMOTE = 13,	/* Error from remote driver */
> +    VIR_FROM_OPENVZ = 14,	/* Error from OpenVZ driver */
> +    VIR_FROM_XENXM = 15,	/* Error at Xen XM layer */
> +    VIR_FROM_STATS_LINUX = 16,	/* Error in the Linux Stats code */
> +    VIR_FROM_LXC = 17,		/* Error from Linux Container driver */
> +    VIR_FROM_STORAGE = 18,	/* Error from storage driver */
> +    VIR_FROM_NETWORK = 19,	/* Error from network config */
> +    VIR_FROM_DOMAIN = 20,	/* Error from domain config */
> +    VIR_FROM_UML = 21,		/* Error at the UML driver */
> +    VIR_FROM_NODEDEV = 22,	/* Error from node device monitor */
> +    VIR_FROM_XEN_INOTIFY = 23,	/* Error from xen inotify layer */
> +    VIR_FROM_SECURITY = 24,	/* Error from security framework */
> +    VIR_FROM_VBOX = 25,		/* Error from VirtualBox driver */
> +    VIR_FROM_INTERFACE = 26,	/* Error when operating on an interface */
> +    VIR_FROM_ONE = 27,		/* Error from OpenNebula driver */
> +    VIR_FROM_ESX = 28,		/* Error from ESX driver */
> +    VIR_FROM_PHYP = 29,		/* Error from IBM power hypervisor */
> +    VIR_FROM_SECRET = 30,	/* Error from secret storage */
> +    VIR_FROM_CPU = 31,		/* Error from CPU driver */
> +    VIR_FROM_XENAPI = 32,	/* Error from XenAPI */
> +    VIR_FROM_NWFILTER = 33,	/* Error from network filter driver */
> +    VIR_FROM_HOOK = 34,		/* Error from Synchronous hooks */
> +    VIR_FROM_DOMAIN_SNAPSHOT = 35,/* Error from domain snapshot */
> +    VIR_FROM_AUDIT = 36,	/* Error from auditing subsystem */
> +    VIR_FROM_SYSINFO = 37,	/* Error from sysinfo/SMBIOS */
> +    VIR_FROM_STREAMS = 38,	/* Error from I/O streams */
> +    VIR_FROM_VMWARE = 39,	/* Error from VMware driver */
>  } virErrorDomain;
> 
> 
> @@ -114,82 +116,118 @@ struct _virError {
>   * virErrorNumber:
>   *
>   * The full list of errors the library can generate
> + *
> + * This list should remain stable, with all additions placed at the
> + * end since libvirt 0.1.0.  There is one exception: values added
> + * between libvirt 0.7.1 and libvirt 0.7.7 (VIR_WAR_NO_SECRET through
> + * VIR_ERROR_MIGRATE_PERSIST_FAILED) were inadvertently relocated by
> + * four positions in 0.8.0.  If you suspect version mismatch between a
> + * server and client, then you can decipher values as follows:
> + *
> + * switch (err.code) {
> + * case 60:
> + *     // no way to tell VIR_WAR_NO_SECRET apart from VIR_WAR_NO_NWFILTER,
> + *     // but both are very similar warnings
> + *     break;
> + * case 61: case 62: case 63:
> + *     if (err.domain != VIR_FROM_NWFILTER)
> + *         err.code += 4;
> + *     break;
> + * case 64:
> + *     if (err.domain == VIR_FROM_QEMU)
> + *         err.code += 4;
> + *     break;
> + * case 65:
> + *     if (err.domain == VIR_FROM_XEN)
> + *         err.code += 4;
> + *     break;
> + * default:
> + * }
>   */
>  typedef enum {
>      VIR_ERR_OK = 0,
> -    VIR_ERR_INTERNAL_ERROR, /* internal error */
> -    VIR_ERR_NO_MEMORY,  /* memory allocation failure */
> -    VIR_ERR_NO_SUPPORT, /* no support for this function */
> -    VIR_ERR_UNKNOWN_HOST,/* could not resolve hostname */
> -    VIR_ERR_NO_CONNECT, /* can't connect to hypervisor */
> -    VIR_ERR_INVALID_CONN,/* invalid connection object */
> -    VIR_ERR_INVALID_DOMAIN,/* invalid domain object */
> -    VIR_ERR_INVALID_ARG,/* invalid function argument */
> -    VIR_ERR_OPERATION_FAILED,/* a command to hypervisor failed */
> -    VIR_ERR_GET_FAILED,/* a HTTP GET command to failed */
> -    VIR_ERR_POST_FAILED,/* a HTTP POST command to failed */
> -    VIR_ERR_HTTP_ERROR,/* unexpected HTTP error code */
> -    VIR_ERR_SEXPR_SERIAL,/* failure to serialize an S-Expr */
> -    VIR_ERR_NO_XEN,/* could not open Xen hypervisor control */
> -    VIR_ERR_XEN_CALL,/* failure doing an hypervisor call */
> -    VIR_ERR_OS_TYPE, /* unknown OS type */
> -    VIR_ERR_NO_KERNEL, /* missing kernel information */
> -    VIR_ERR_NO_ROOT, /* missing root device information */
> -    VIR_ERR_NO_SOURCE, /* missing source device information */
> -    VIR_ERR_NO_TARGET, /* missing target device information */
> -    VIR_ERR_NO_NAME, /* missing domain name information */
> -    VIR_ERR_NO_OS, /* missing domain OS information */
> -    VIR_ERR_NO_DEVICE, /* missing domain devices information */
> -    VIR_ERR_NO_XENSTORE,/* could not open Xen Store control */
> -    VIR_ERR_DRIVER_FULL, /* too many drivers registered */
> -    VIR_ERR_CALL_FAILED, /* not supported by the drivers (DEPRECATED) */
> -    VIR_ERR_XML_ERROR, /* an XML description is not well formed or broken */
> -    VIR_ERR_DOM_EXIST,/* the domain already exist */
> -    VIR_ERR_OPERATION_DENIED, /* operation forbidden on read-only connections */
> -    VIR_ERR_OPEN_FAILED, /* failed to open a conf file */
> -    VIR_ERR_READ_FAILED, /* failed to read a conf file */
> -    VIR_ERR_PARSE_FAILED, /* failed to parse a conf file */
> -    VIR_ERR_CONF_SYNTAX, /* failed to parse the syntax of a conf file */
> -    VIR_ERR_WRITE_FAILED, /* failed to write a conf file */
> -    VIR_ERR_XML_DETAIL, /* detail of an XML error */
> -    VIR_ERR_INVALID_NETWORK, /* invalid network object */
> -    VIR_ERR_NETWORK_EXIST, /* the network already exist */
> -    VIR_ERR_SYSTEM_ERROR, /* general system call failure */
> -    VIR_ERR_RPC, /* some sort of RPC error */
> -    VIR_ERR_GNUTLS_ERROR, /* error from a GNUTLS call */
> -    VIR_WAR_NO_NETWORK, /* failed to start network */
> -    VIR_ERR_NO_DOMAIN, /* domain not found or unexpectedly disappeared */
> -    VIR_ERR_NO_NETWORK, /* network not found */
> -    VIR_ERR_INVALID_MAC, /* invalid MAC address */
> -    VIR_ERR_AUTH_FAILED, /* authentication failed */
> -    VIR_ERR_INVALID_STORAGE_POOL, /* invalid storage pool object */
> -    VIR_ERR_INVALID_STORAGE_VOL, /* invalid storage vol object */
> -    VIR_WAR_NO_STORAGE, /* failed to start storage */
> -    VIR_ERR_NO_STORAGE_POOL, /* storage pool not found */
> -    VIR_ERR_NO_STORAGE_VOL, /* storage pool not found */
> -    VIR_WAR_NO_NODE, /* failed to start node driver */
> -    VIR_ERR_INVALID_NODE_DEVICE,/* invalid node device object */
> -    VIR_ERR_NO_NODE_DEVICE,/* node device not found */
> -    VIR_ERR_NO_SECURITY_MODEL, /* security model not found */
> -    VIR_ERR_OPERATION_INVALID, /* operation is not applicable at this time */
> -    VIR_WAR_NO_INTERFACE, /* failed to start interface driver */
> -    VIR_ERR_NO_INTERFACE, /* interface driver not running */
> -    VIR_ERR_INVALID_INTERFACE, /* invalid interface object */
> -    VIR_ERR_MULTIPLE_INTERFACES, /* more than one matching interface found */
> -    VIR_WAR_NO_NWFILTER, /* failed to start nwfilter driver */
> -    VIR_ERR_INVALID_NWFILTER, /* invalid nwfilter object */
> -    VIR_ERR_NO_NWFILTER, /* nw filter pool not found */
> -    VIR_ERR_BUILD_FIREWALL, /* nw filter pool not found */
> -    VIR_WAR_NO_SECRET, /* failed to start secret storage */
> -    VIR_ERR_INVALID_SECRET, /* invalid secret */
> -    VIR_ERR_NO_SECRET, /* secret not found */
> -    VIR_ERR_CONFIG_UNSUPPORTED, /* unsupported configuration construct */
> -    VIR_ERR_OPERATION_TIMEOUT, /* timeout occurred during operation */
> -    VIR_ERR_MIGRATE_PERSIST_FAILED, /* a migration worked, but making the
> -                                       VM persist on the dest host failed */
> -    VIR_ERR_HOOK_SCRIPT_FAILED, /* a synchronous hook script failed */
> -    VIR_ERR_INVALID_DOMAIN_SNAPSHOT, /* invalid domain snapshot */
> -    VIR_ERR_NO_DOMAIN_SNAPSHOT, /* domain snapshot not found */
> +    VIR_ERR_INTERNAL_ERROR = 1,		/* internal error */
> +    VIR_ERR_NO_MEMORY = 2,		/* memory allocation failure */
> +    VIR_ERR_NO_SUPPORT = 3,		/* no support for this function */
> +    VIR_ERR_UNKNOWN_HOST = 4,		/* could not resolve hostname */
> +    VIR_ERR_NO_CONNECT = 5,		/* can't connect to hypervisor */
> +    VIR_ERR_INVALID_CONN = 6,		/* invalid connection object */
> +    VIR_ERR_INVALID_DOMAIN = 7,		/* invalid domain object */
> +    VIR_ERR_INVALID_ARG = 8,		/* invalid function argument */
> +    VIR_ERR_OPERATION_FAILED = 9,	/* a command to hypervisor failed */
> +    VIR_ERR_GET_FAILED = 10,		/* a HTTP GET command to failed */
> +    VIR_ERR_POST_FAILED = 11,		/* a HTTP POST command to failed */
> +    VIR_ERR_HTTP_ERROR = 12,		/* unexpected HTTP error code */
> +    VIR_ERR_SEXPR_SERIAL = 13,		/* failure to serialize an S-Expr */
> +    VIR_ERR_NO_XEN = 14,		/* could not open Xen hypervisor
> +                                           control */
> +    VIR_ERR_XEN_CALL = 15,		/* failure doing an hypervisor call */
> +    VIR_ERR_OS_TYPE = 16,		/* unknown OS type */
> +    VIR_ERR_NO_KERNEL = 17,		/* missing kernel information */
> +    VIR_ERR_NO_ROOT = 18,		/* missing root device information */
> +    VIR_ERR_NO_SOURCE = 19,		/* missing source device information */
> +    VIR_ERR_NO_TARGET = 20,		/* missing target device information */
> +    VIR_ERR_NO_NAME = 21,		/* missing domain name information */
> +    VIR_ERR_NO_OS = 22,			/* missing domain OS information */
> +    VIR_ERR_NO_DEVICE = 23,		/* missing domain devices information */
> +    VIR_ERR_NO_XENSTORE = 24,		/* could not open Xen Store control */
> +    VIR_ERR_DRIVER_FULL = 25,		/* too many drivers registered */
> +    VIR_ERR_CALL_FAILED = 26,		/* not supported by the drivers
> +                                           (DEPRECATED) */
> +    VIR_ERR_XML_ERROR = 27,		/* an XML description is not well
> +                                           formed or broken */
> +    VIR_ERR_DOM_EXIST = 28,		/* the domain already exist */
> +    VIR_ERR_OPERATION_DENIED = 29,	/* operation forbidden on read-only
> +                                           connections */
> +    VIR_ERR_OPEN_FAILED = 30,		/* failed to open a conf file */
> +    VIR_ERR_READ_FAILED = 31,		/* failed to read a conf file */
> +    VIR_ERR_PARSE_FAILED = 32,		/* failed to parse a conf file */
> +    VIR_ERR_CONF_SYNTAX = 33,		/* failed to parse the syntax of a
> +                                           conf file */
> +    VIR_ERR_WRITE_FAILED = 34,		/* failed to write a conf file */
> +    VIR_ERR_XML_DETAIL = 35,		/* detail of an XML error */
> +    VIR_ERR_INVALID_NETWORK = 36,	/* invalid network object */
> +    VIR_ERR_NETWORK_EXIST = 37,		/* the network already exist */
> +    VIR_ERR_SYSTEM_ERROR = 38,		/* general system call failure */
> +    VIR_ERR_RPC = 39,			/* some sort of RPC error */
> +    VIR_ERR_GNUTLS_ERROR = 40,		/* error from a GNUTLS call */
> +    VIR_WAR_NO_NETWORK = 41,		/* failed to start network */
> +    VIR_ERR_NO_DOMAIN = 42,		/* domain not found or unexpectedly
> +                                           disappeared */
> +    VIR_ERR_NO_NETWORK = 43,		/* network not found */
> +    VIR_ERR_INVALID_MAC = 44,		/* invalid MAC address */
> +    VIR_ERR_AUTH_FAILED = 45,		/* authentication failed */
> +    VIR_ERR_INVALID_STORAGE_POOL = 46,	/* invalid storage pool object */
> +    VIR_ERR_INVALID_STORAGE_VOL = 47,	/* invalid storage vol object */
> +    VIR_WAR_NO_STORAGE = 48,		/* failed to start storage */
> +    VIR_ERR_NO_STORAGE_POOL = 49,	/* storage pool not found */
> +    VIR_ERR_NO_STORAGE_VOL = 50,	/* storage pool not found */
> +    VIR_WAR_NO_NODE = 51,		/* failed to start node driver */
> +    VIR_ERR_INVALID_NODE_DEVICE = 52,	/* invalid node device object */
> +    VIR_ERR_NO_NODE_DEVICE = 53,	/* node device not found */
> +    VIR_ERR_NO_SECURITY_MODEL = 54,	/* security model not found */
> +    VIR_ERR_OPERATION_INVALID = 55,	/* operation is not applicable at this
> +                                           time */
> +    VIR_WAR_NO_INTERFACE = 56,		/* failed to start interface driver */
> +    VIR_ERR_NO_INTERFACE = 57,		/* interface driver not running */
> +    VIR_ERR_INVALID_INTERFACE = 58,	/* invalid interface object */
> +    VIR_ERR_MULTIPLE_INTERFACES = 59,	/* more than one matching interface
> +                                           found */
> +    VIR_WAR_NO_NWFILTER = 60,		/* failed to start nwfilter driver */
> +    VIR_ERR_INVALID_NWFILTER = 61,	/* invalid nwfilter object */
> +    VIR_ERR_NO_NWFILTER = 62,		/* nw filter pool not found */
> +    VIR_ERR_BUILD_FIREWALL = 63,	/* nw filter pool not found */
> +    VIR_WAR_NO_SECRET = 64,		/* failed to start secret storage */
> +    VIR_ERR_INVALID_SECRET = 65,	/* invalid secret */
> +    VIR_ERR_NO_SECRET = 66,		/* secret not found */
> +    VIR_ERR_CONFIG_UNSUPPORTED = 67,	/* unsupported configuration
> +                                           construct */
> +    VIR_ERR_OPERATION_TIMEOUT = 68,	/* timeout occurred during operation */
> +    VIR_ERR_MIGRATE_PERSIST_FAILED = 69,/* a migration worked, but making the
> +                                           VM persist on the dest host failed */
> +    VIR_ERR_HOOK_SCRIPT_FAILED = 70,	/* a synchronous hook script failed */
> +    VIR_ERR_INVALID_DOMAIN_SNAPSHOT = 71,/* invalid domain snapshot */
> +    VIR_ERR_NO_DOMAIN_SNAPSHOT = 72,	/* domain snapshot not found */
>  } virErrorNumber;

Definitely ACK to these two parts; moving VIR_FROM_VMWARE to the end and
explicitly numbering everything.  See below.

> 
>  /**
> diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c
> index fae191c..66d3852 100644
> --- a/src/remote/remote_driver.c
> +++ b/src/remote/remote_driver.c
> @@ -10371,8 +10371,36 @@ remoteIO(virConnectPtr conn,
>          return -1;
> 
>  cleanup:
> -    DEBUG("All done with our call %d %p %p", thiscall->proc_nr, priv->waitDispatch, thiscall);
> +    DEBUG("All done with our call %d %p %p", thiscall->proc_nr,
> +          priv->waitDispatch, thiscall);
>      if (thiscall->mode == REMOTE_MODE_ERROR) {
> +        /* Interop for virErrorNumber glitch in 0.8.0, if server is
> +         * 0.7.1 through 0.7.7 */
> +        switch (thiscall->err.code) {
> +        case VIR_WAR_NO_NWFILTER:
> +            /* no way to tell old VIR_WAR_NO_SECRET apart from
> +             * VIR_WAR_NO_NWFILTER, but both are very similar
> +             * warnings, so ignore the difference */
> +            break;
> +        case VIR_ERR_INVALID_NWFILTER:
> +        case VIR_ERR_NO_NWFILTER:
> +        case VIR_ERR_BUILD_FIREWALL:
> +            if (thiscall->err.domain != VIR_FROM_NWFILTER)
> +                thiscall->err.code += 4;
> +            break;
> +        case VIR_WAR_NO_SECRET:
> +            if (thiscall->err.domain == VIR_FROM_QEMU)
> +                thiscall->err.code = VIR_ERR_OPERATION_TIMEOUT;
> +            break;
> +        case VIR_ERR_INVALID_SECRET:
> +            if (thiscall->err.domain == VIR_FROM_XEN)
> +                thiscall->err.code = VIR_ERR_MIGRATE_PERSIST_FAILED;
> +            break;
> +        default:
> +            /* Nothing to alter. */
> +            break;
> +        }
> +
>          /* See if caller asked us to keep quiet about missing RPCs
>           * eg for interop with older servers */
>          if (flags & REMOTE_CALL_QUIET_MISSING_RPC &&

Clever.  Make sure it is of the right "domain", and if not, you know you are
talking to an older server.  At first I thought it was confusing, but this
will do the right thing in *almost* all situations, so I like it.

ACK to this; as DV says, maybe we can make a "make check" or
"make syntax-check" to automatically catch it in the future, but this at least
fixes the current breakage.

-- 
Chris Lalancette


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]