Bug reports from users have shown diagnosing problems with the remote
driver are quite tricky, so I've been looking at improving its error
messages where possible. There's a number of places where we simply
pass in strerror(errno) as the only data in virRaiseError. This doesn't
let us narrow down just which call failed - we just get a generic message
"Permission denied" or "Connection refused" with no clue what was
being
tried.
This patch adds descriptive error messages whereever possible, fixes a
place where we'd report an error to connect to IPv4 even if IPv6
succeeded, and adds some missing translations
Before
$ virsh --connect qemu:///system
libvir: Remote error : Permission denied
$ virsh --connect qemu+tcp:///system
libvir: Remote error : Connection refused
$ virsh --connect qemu+tcp://wibble/system
libvir: Remote error : invalid argument in Name or service not known
After
$ ./src/virsh --connect qemu:///system
libvir: Remote error : unable to connect to '/var/run/libvirt/libvirt-sock':
Permission denied
$ ./src/virsh --connect qemu+tcp:///system
libvir: Remote error : unable to connect to 'localhost': Connection refused
$ ./src/virsh --connect qemu+tcp://wibble/system
libvir: Remote error : unable to resolve hostname 'wibble': Name or service not
known
Daniel
Index: src/remote_internal.c
===================================================================
RCS file: /data/cvs/libvirt/src/remote_internal.c,v
retrieving revision 1.80
diff -u -r1.80 remote_internal.c
--- src/remote_internal.c 26 Jun 2008 09:37:51 -0000 1.80
+++ src/remote_internal.c 19 Aug 2008 10:36:32 -0000
@@ -371,13 +371,12 @@
priv->hostname = strdup (uri->server ? uri->server :
"localhost");
- if (!priv->hostname) {
- error (NULL, VIR_ERR_NO_MEMORY, _("allocating priv->hostname"));
- goto failed;
- }
+ if (!priv->hostname)
+ goto out_of_memory;
if (uri->user) {
username = strdup (uri->user);
- if (!username) goto out_of_memory;
+ if (!username)
+ goto out_of_memory;
}
/* Get the variables from the query string.
@@ -491,12 +490,15 @@
//
http://people.redhat.com/drepper/userapi-ipv6.html
struct addrinfo *res, *r;
struct addrinfo hints;
+ int saved_errno = EINVAL;
memset (&hints, 0, sizeof hints);
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_ADDRCONFIG;
int e = getaddrinfo (priv->hostname, port, &hints, &res);
if (e != 0) {
- error (conn, VIR_ERR_INVALID_ARG, gai_strerror (e));
+ errorf (conn, VIR_ERR_SYSTEM_ERROR,
+ _("unable to resolve hostname '%s': %s"),
+ priv->hostname, gai_strerror (e));
goto failed;
}
@@ -516,7 +518,7 @@
priv->sock = socket (r->ai_family, SOCK_STREAM, 0);
if (priv->sock == -1) {
- error (conn, VIR_ERR_SYSTEM_ERROR, strerror (socket_errno ()));
+ saved_errno = socket_errno();
continue;
}
@@ -526,7 +528,7 @@
sizeof no_slow_start);
if (connect (priv->sock, r->ai_addr, r->ai_addrlen) == -1) {
- error (conn, VIR_ERR_SYSTEM_ERROR, strerror (socket_errno ()));
+ saved_errno = socket_errno();
close (priv->sock);
continue;
}
@@ -545,6 +547,9 @@
}
freeaddrinfo (res);
+ errorf (conn, VIR_ERR_SYSTEM_ERROR,
+ _("unable to connect to '%s': %s"),
+ priv->hostname, strerror (saved_errno));
goto failed;
tcp_connected:
@@ -563,23 +568,23 @@
uid_t uid = getuid();
if (!(pw = getpwuid(uid))) {
- error (conn, VIR_ERR_SYSTEM_ERROR, strerror (errno));
+ errorf (conn, VIR_ERR_SYSTEM_ERROR,
+ _("unable to lookup user '%d': %s"),
+ uid, strerror (errno));
goto failed;
}
if (asprintf (&sockname, "@%s" LIBVIRTD_USER_UNIX_SOCKET,
pw->pw_dir) < 0) {
- error (conn, VIR_ERR_SYSTEM_ERROR, strerror (errno));
- goto failed;
+ sockname = NULL;
+ goto out_of_memory;
}
} else {
if (flags & VIR_DRV_OPEN_REMOTE_RO)
sockname = strdup (LIBVIRTD_PRIV_UNIX_SOCKET_RO);
else
sockname = strdup (LIBVIRTD_PRIV_UNIX_SOCKET);
- if (sockname == NULL) {
- error (conn, VIR_ERR_SYSTEM_ERROR, strerror (errno));
- goto failed;
- }
+ if (sockname == NULL)
+ goto out_of_memory;
}
}
@@ -598,7 +603,9 @@
autostart_retry:
priv->sock = socket (AF_UNIX, SOCK_STREAM, 0);
if (priv->sock == -1) {
- error (conn, VIR_ERR_SYSTEM_ERROR, strerror (errno));
+ errorf (conn, VIR_ERR_SYSTEM_ERROR,
+ _("unable to create socket %s"),
+ strerror (errno));
goto failed;
}
if (connect (priv->sock, (struct sockaddr *) &addr, sizeof addr) == -1) {
@@ -620,7 +627,9 @@
goto autostart_retry;
}
}
- error (conn, VIR_ERR_SYSTEM_ERROR, strerror (errno));
+ errorf (conn, VIR_ERR_SYSTEM_ERROR,
+ _("unable to connect to '%s': %s"),
+ sockname, strerror (errno));
goto failed;
}
@@ -634,17 +643,13 @@
if (no_tty) nr_args += 5; /* For -T -o BatchMode=yes -e none */
command = command ? : strdup ("ssh");
- if (command == NULL) {
- error (conn, VIR_ERR_SYSTEM_ERROR, strerror (errno));
- goto failed;
- }
+ if (command == NULL)
+ goto out_of_memory;
// Generate the final command argv[] array.
// ssh -p $port [-l $username] $hostname $netcat -U $sockname [NULL]
- if (VIR_ALLOC_N(cmd_argv, nr_args) < 0) {
- error (conn, VIR_ERR_SYSTEM_ERROR, strerror (errno));
- goto failed;
- }
+ if (VIR_ALLOC_N(cmd_argv, nr_args) < 0)
+ goto out_of_memory;
j = 0;
cmd_argv[j++] = strdup (command);
@@ -667,12 +672,9 @@
cmd_argv[j++] = strdup (sockname ? sockname : LIBVIRTD_PRIV_UNIX_SOCKET);
cmd_argv[j++] = 0;
assert (j == nr_args);
- for (j = 0; j < (nr_args-1); j++) {
- if (cmd_argv[j] == NULL) {
- error (conn, VIR_ERR_SYSTEM_ERROR, strerror (ENOMEM));
- goto failed;
- }
- }
+ for (j = 0; j < (nr_args-1); j++)
+ if (cmd_argv[j] == NULL)
+ goto out_of_memory;
}
/*FALLTHROUGH*/
@@ -685,28 +687,38 @@
* to faff around with two file descriptors (a la 'pipe(2)').
*/
if (socketpair (PF_UNIX, SOCK_STREAM, 0, sv) == -1) {
- error (conn, VIR_ERR_SYSTEM_ERROR, strerror (errno));
+ errorf (conn, VIR_ERR_SYSTEM_ERROR,
+ _("unable to create socket pair %s"),
+ strerror (errno));
goto failed;
}
pid = fork ();
if (pid == -1) {
- error (conn, VIR_ERR_SYSTEM_ERROR, strerror (errno));
+ errorf (conn, VIR_ERR_SYSTEM_ERROR,
+ _("unable to fork external network transport: %s"),
+ strerror (errno));
goto failed;
} else if (pid == 0) { /* Child. */
close (sv[0]);
// Connect socket (sv[1]) to stdin/stdout.
close (0);
- if (dup (sv[1]) == -1) perror ("dup");
+ if (dup (sv[1]) == -1) {
+ perror ("dup");
+ _exit(1);
+ }
close (1);
- if (dup (sv[1]) == -1) perror ("dup");
+ if (dup (sv[1]) == -1) {
+ perror ("dup");
+ _exit(1);
+ }
close (sv[1]);
// Run the external process.
if (!cmd_argv) {
if (VIR_ALLOC_N(cmd_argv, 2) < 0) {
- error (conn, VIR_ERR_SYSTEM_ERROR, strerror (errno));
- goto failed;
+ perror("malloc");
+ _exit(1);
}
cmd_argv[0] = command;
cmd_argv[1] = 0;
@@ -770,7 +782,7 @@
return retcode;
out_of_memory:
- error (NULL, VIR_ERR_NO_MEMORY, _("uri params"));
+ error (conn, VIR_ERR_NO_MEMORY, NULL);
failed:
/* Close the socket if we failed. */
@@ -882,10 +894,9 @@
{
struct stat sb;
if (stat(file, &sb) < 0) {
- __virRaiseError (conn, NULL, NULL, VIR_FROM_REMOTE, VIR_ERR_RPC,
- VIR_ERR_ERROR, LIBVIRT_CACERT, NULL, NULL, 0, 0,
- _("Cannot access %s '%s': %s (%d)"),
- type, file, strerror(errno), errno);
+ errorf(conn, VIR_ERR_RPC,
+ _("Cannot access %s '%s': %s (%d)"),
+ type, file, strerror(errno), errno);
return -1;
}
return 0;
@@ -905,7 +916,9 @@
/* X509 stuff */
err = gnutls_certificate_allocate_credentials (&x509_cred);
if (err) {
- error (conn, VIR_ERR_GNUTLS_ERROR, gnutls_strerror (err));
+ errorf (conn, VIR_ERR_GNUTLS_ERROR,
+ _("unable to allocate TLS credentials: %s"),
+ gnutls_strerror (err));
return -1;
}
@@ -923,7 +936,9 @@
gnutls_certificate_set_x509_trust_file (x509_cred, LIBVIRT_CACERT,
GNUTLS_X509_FMT_PEM);
if (err < 0) {
- error (conn, VIR_ERR_GNUTLS_ERROR, gnutls_strerror (err));
+ errorf (conn, VIR_ERR_GNUTLS_ERROR,
+ _("unable to load CA certificate: %s"),
+ gnutls_strerror (err));
return -1;
}
@@ -936,7 +951,9 @@
LIBVIRT_CLIENTKEY,
GNUTLS_X509_FMT_PEM);
if (err < 0) {
- error (conn, VIR_ERR_GNUTLS_ERROR, gnutls_strerror (err));
+ errorf (conn, VIR_ERR_GNUTLS_ERROR,
+ _("unable to load private key/certificate: %s"),
+ gnutls_strerror (err));
return -1;
}
@@ -963,21 +980,27 @@
*/
err = gnutls_init (&session, GNUTLS_CLIENT);
if (err) {
- error (conn, VIR_ERR_GNUTLS_ERROR, gnutls_strerror (err));
+ errorf (conn, VIR_ERR_GNUTLS_ERROR,
+ _("unable to initialize TLS client: %s"),
+ gnutls_strerror (err));
return NULL;
}
/* Use default priorities */
err = gnutls_set_default_priority (session);
if (err) {
- error (conn, VIR_ERR_GNUTLS_ERROR, gnutls_strerror (err));
+ errorf (conn, VIR_ERR_GNUTLS_ERROR,
+ _("unable to set TLS algorithm priority: %s"),
+ gnutls_strerror (err));
return NULL;
}
err =
gnutls_certificate_type_set_priority (session,
cert_type_priority);
if (err) {
- error (conn, VIR_ERR_GNUTLS_ERROR, gnutls_strerror (err));
+ errorf (conn, VIR_ERR_GNUTLS_ERROR,
+ _("unable to set certificate priority: %s"),
+ gnutls_strerror (err));
return NULL;
}
@@ -985,7 +1008,9 @@
*/
err = gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, x509_cred);
if (err) {
- error (conn, VIR_ERR_GNUTLS_ERROR, gnutls_strerror (err));
+ errorf (conn, VIR_ERR_GNUTLS_ERROR,
+ _("unable to set session credentials: %s"),
+ gnutls_strerror (err));
return NULL;
}
@@ -998,7 +1023,9 @@
if (err < 0) {
if (err == GNUTLS_E_AGAIN || err == GNUTLS_E_INTERRUPTED)
goto again;
- error (conn, VIR_ERR_GNUTLS_ERROR, gnutls_strerror (err));
+ errorf (conn, VIR_ERR_GNUTLS_ERROR,
+ _("unable to complete TLS handshake: %s"),
+ gnutls_strerror (err));
return NULL;
}
@@ -1018,12 +1045,14 @@
if (len < 0 && len != GNUTLS_E_UNEXPECTED_PACKET_LENGTH) {
if (len == GNUTLS_E_AGAIN || len == GNUTLS_E_INTERRUPTED)
goto again_2;
- error (conn, VIR_ERR_GNUTLS_ERROR, gnutls_strerror (len));
+ errorf (conn, VIR_ERR_GNUTLS_ERROR,
+ _("unable to complete TLS initialization: %s"),
+ gnutls_strerror (len));
return NULL;
}
if (len != 1 || buf[0] != '\1') {
error (conn, VIR_ERR_RPC,
- _("server verification (of our certificate or IP address)
failed\n"));
+ _("server verification (of our certificate or IP address)
failed\n"));
return NULL;
}
@@ -1047,33 +1076,39 @@
time_t now;
if ((ret = gnutls_certificate_verify_peers2 (session, &status)) < 0) {
- error (conn, VIR_ERR_GNUTLS_ERROR, gnutls_strerror (ret));
+ errorf (conn, VIR_ERR_GNUTLS_ERROR,
+ _("unable to verify server certificate: %s"),
+ gnutls_strerror (ret));
return -1;
}
if ((now = time(NULL)) == ((time_t)-1)) {
- error (conn, VIR_ERR_SYSTEM_ERROR, strerror (errno));
+ errorf (conn, VIR_ERR_SYSTEM_ERROR,
+ _("cannot get current time: %s"),
+ strerror (errno));
return -1;
}
if (status != 0) {
- const char *reason = "Invalid certificate";
+ const char *reason = _("Invalid certificate");
if (status & GNUTLS_CERT_INVALID)
- reason = "The certificate is not trusted.";
+ reason = _("The certificate is not trusted.");
if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
- reason = "The certificate hasn't got a known issuer.";
+ reason = _("The certificate hasn't got a known issuer.");
if (status & GNUTLS_CERT_REVOKED)
- reason = "The certificate has been revoked.";
+ reason = _("The certificate has been revoked.");
#ifndef GNUTLS_1_0_COMPAT
if (status & GNUTLS_CERT_INSECURE_ALGORITHM)
- reason = "The certificate uses an insecure algorithm";
+ reason = _("The certificate uses an insecure algorithm");
#endif
- error (conn, VIR_ERR_RPC, reason);
+ errorf (conn, VIR_ERR_RPC,
+ _("server certificate failed validation: %s"),
+ reason);
return -1;
}
@@ -1092,13 +1127,17 @@
ret = gnutls_x509_crt_init (&cert);
if (ret < 0) {
- error (conn, VIR_ERR_GNUTLS_ERROR, gnutls_strerror (ret));
+ errorf (conn, VIR_ERR_GNUTLS_ERROR,
+ _("unable to initialize certificate: %s"),
+ gnutls_strerror (ret));
return -1;
}
ret = gnutls_x509_crt_import (cert, &certs[i], GNUTLS_X509_FMT_DER);
if (ret < 0) {
- error (conn, VIR_ERR_GNUTLS_ERROR, gnutls_strerror (ret));
+ errorf (conn, VIR_ERR_GNUTLS_ERROR,
+ _("unable to import certificate: %s"),
+ gnutls_strerror (ret));
gnutls_x509_crt_deinit (cert);
return -1;
}
@@ -1117,13 +1156,9 @@
if (i == 0) {
if (!gnutls_x509_crt_check_hostname (cert, priv->hostname)) {
- __virRaiseError
- (conn, NULL, NULL,
- VIR_FROM_REMOTE, VIR_ERR_RPC,
- VIR_ERR_ERROR, priv->hostname, NULL, NULL,
- 0, 0,
- _("Certificate's owner does not match the hostname
(%s)"),
- priv->hostname);
+ errorf(conn, VIR_ERR_RPC,
+ _("Certificate's owner does not match the hostname
(%s)"),
+ priv->hostname);
gnutls_x509_crt_deinit (cert);
return -1;
}
@@ -4721,8 +4756,9 @@
errmsg = __virErrorMsg (code, errorMessage);
__virRaiseError (conn, NULL, NULL, VIR_FROM_REMOTE,
- code, VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0,
- "%s", errmsg);
+ code, VIR_ERR_ERROR,
+ errmsg, errorMessage, NULL, -1, -1,
+ errmsg, errorMessage);
}
/* For errors generated on the server side and sent back to us. */
--
|: Red Hat, Engineering, London -o-
http://people.redhat.com/berrange/ :|
|:
http://libvirt.org -o-
http://virt-manager.org -o-
http://ovirt.org :|
|:
http://autobuild.org -o-
http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|