2007-02-14 04:40:09 +03:00
/*
2009-09-16 15:37:26 +04:00
* libvirtd . c : daemon start of day , guest process & i / o management
2007-02-14 04:40:09 +03:00
*
2010-02-02 13:27:25 +03:00
* Copyright ( C ) 2006 - 2010 Red Hat , Inc .
2007-02-14 04:40:09 +03:00
* Copyright ( C ) 2006 Daniel P . Berrange
*
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation ; either
* version 2.1 of the License , or ( at your option ) any later version .
*
* This library 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
* Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*
* Author : Daniel P . Berrange < berrange @ redhat . com >
*/
2008-01-29 21:15:54 +03:00
# include <config.h>
2007-02-14 18:42:55 +03:00
2007-02-14 04:40:09 +03:00
# include <sys/types.h>
# include <sys/wait.h>
# include <sys/stat.h>
# include <unistd.h>
# include <fcntl.h>
# include <limits.h>
# include <sys/socket.h>
# include <sys/un.h>
# include <sys/poll.h>
# include <netinet/in.h>
2007-06-11 16:04:54 +04:00
# include <netinet/tcp.h>
2007-02-14 04:40:09 +03:00
# include <netdb.h>
# include <stdlib.h>
# include <pwd.h>
# include <stdio.h>
2007-02-16 21:30:55 +03:00
# include <stdarg.h>
# include <syslog.h>
2007-02-14 04:40:09 +03:00
# include <string.h>
# include <errno.h>
# include <getopt.h>
2007-06-11 16:04:54 +04:00
# include <fnmatch.h>
2007-09-19 06:28:01 +04:00
# include <grp.h>
2008-01-23 17:54:41 +03:00
# include <signal.h>
2008-10-28 20:46:00 +03:00
# include <netdb.h>
2007-04-11 03:17:46 +04:00
2008-11-05 02:22:06 +03:00
# include "libvirt_internal.h"
2009-02-05 19:28:30 +03:00
# include "virterror_internal.h"
Standardize use of header files, making internal.h primary.
* qemud/internal.h, qemud/qemud.h: Rename this file so it
doesn't conflict with src/internal.h.
* HACKING: Document how header files should be used.
* qemud/Makefile.am: Add src/ directory to includes.
* qemud/event.c, qemud/mdns.c, qemud/qemud.c, qemud/remote.c,
qemud/remote_protocol.c, qemud/remote_protocol.h,
qemud/remote_protocol.x, src/buf.c, src/libvirt.c,
src/nodeinfo.c, src/qemu_conf.c, src/qemu_driver.c,
src/stats_linux.c, src/storage_backend.c, src/storage_backend_fs.c,
src/storage_backend_iscsi.c, src/storage_backend_logical.c,
src/storage_conf.c, src/storage_driver.c, src/util.c,
src/util.h, src/virsh.c, src/virterror.c, src/xend_internal.c,
src/xml.c, tests/reconnect.c, tests/xmlrpctest.c,
tests/qparamtest.c: Standardize use of header files.
* docs/*, po/*: Rebuild docs.
2008-05-23 12:24:41 +04:00
2009-02-09 20:52:38 +03:00
# define VIR_FROM_THIS VIR_FROM_QEMU
2009-09-16 15:37:26 +04:00
# include "libvirtd.h"
2009-07-10 15:20:03 +04:00
# include "dispatch.h"
Standardize use of header files, making internal.h primary.
* qemud/internal.h, qemud/qemud.h: Rename this file so it
doesn't conflict with src/internal.h.
* HACKING: Document how header files should be used.
* qemud/Makefile.am: Add src/ directory to includes.
* qemud/event.c, qemud/mdns.c, qemud/qemud.c, qemud/remote.c,
qemud/remote_protocol.c, qemud/remote_protocol.h,
qemud/remote_protocol.x, src/buf.c, src/libvirt.c,
src/nodeinfo.c, src/qemu_conf.c, src/qemu_driver.c,
src/stats_linux.c, src/storage_backend.c, src/storage_backend_fs.c,
src/storage_backend_iscsi.c, src/storage_backend_logical.c,
src/storage_conf.c, src/storage_driver.c, src/util.c,
src/util.h, src/virsh.c, src/virterror.c, src/xend_internal.c,
src/xml.c, tests/reconnect.c, tests/xmlrpctest.c,
tests/qparamtest.c: Standardize use of header files.
* docs/*, po/*: Rebuild docs.
2008-05-23 12:24:41 +04:00
# include "util.h"
2009-09-16 19:55:16 +04:00
# include "remote_driver.h"
Standardize use of header files, making internal.h primary.
* qemud/internal.h, qemud/qemud.h: Rename this file so it
doesn't conflict with src/internal.h.
* HACKING: Document how header files should be used.
* qemud/Makefile.am: Add src/ directory to includes.
* qemud/event.c, qemud/mdns.c, qemud/qemud.c, qemud/remote.c,
qemud/remote_protocol.c, qemud/remote_protocol.h,
qemud/remote_protocol.x, src/buf.c, src/libvirt.c,
src/nodeinfo.c, src/qemu_conf.c, src/qemu_driver.c,
src/stats_linux.c, src/storage_backend.c, src/storage_backend_fs.c,
src/storage_backend_iscsi.c, src/storage_backend_logical.c,
src/storage_conf.c, src/storage_driver.c, src/util.c,
src/util.h, src/virsh.c, src/virterror.c, src/xend_internal.c,
src/xml.c, tests/reconnect.c, tests/xmlrpctest.c,
tests/qparamtest.c: Standardize use of header files.
* docs/*, po/*: Rebuild docs.
2008-05-23 12:24:41 +04:00
# include "conf.h"
2007-06-26 23:11:00 +04:00
# include "event.h"
2008-06-06 14:52:01 +04:00
# include "memory.h"
2009-07-10 16:06:36 +04:00
# include "stream.h"
2007-09-19 05:56:55 +04:00
# ifdef HAVE_AVAHI
# include "mdns.h"
# endif
2007-02-14 04:40:09 +03:00
2008-11-21 15:16:08 +03:00
# ifdef WITH_DRIVER_MODULES
# include "driver.h"
# else
2008-11-17 15:18:18 +03:00
# ifdef WITH_QEMU
2009-09-15 20:14:43 +04:00
# include "qemu/qemu_driver.h"
2008-11-17 15:18:18 +03:00
# endif
# ifdef WITH_LXC
2009-09-15 20:03:01 +04:00
# include "lxc/lxc_driver.h"
2008-11-17 15:18:18 +03:00
# endif
2008-11-19 19:58:23 +03:00
# ifdef WITH_UML
2009-09-15 20:25:30 +04:00
# include "uml/uml_driver.h"
2008-11-19 19:58:23 +03:00
# endif
2009-05-25 15:56:00 +04:00
# ifdef WITH_ONE
# include "opennebula/one_driver.h"
# endif
2008-11-17 15:18:18 +03:00
# ifdef WITH_NETWORK
2009-09-15 21:52:58 +04:00
# include "network/bridge_driver.h"
2008-11-17 15:18:18 +03:00
# endif
2009-07-21 18:02:16 +04:00
# ifdef WITH_NETCF
2009-09-15 21:55:16 +04:00
# include "interface/netcf_driver.h"
2009-07-21 18:02:16 +04:00
# endif
2008-11-17 15:18:18 +03:00
# ifdef WITH_STORAGE_DIR
2009-09-15 20:55:05 +04:00
# include "storage/storage_driver.h"
2008-11-17 15:18:18 +03:00
# endif
2008-11-21 15:27:11 +03:00
# ifdef WITH_NODE_DEVICES
2009-09-15 21:30:17 +04:00
# include "node_device/node_device_driver.h"
2008-11-21 15:27:11 +03:00
# endif
2009-12-22 16:50:50 +03:00
# ifdef WITH_SECRETS
2009-09-15 21:59:58 +04:00
# include "secret/secret_driver.h"
2008-11-21 15:16:08 +03:00
# endif
2009-12-22 16:50:50 +03:00
# endif
2008-11-17 15:18:18 +03:00
2009-01-22 20:49:41 +03:00
# ifdef __sun
# include <ucred.h>
# include <priv.h>
# ifndef PRIV_VIRT_MANAGE
# define PRIV_VIRT_MANAGE ((const char *)"virt_manage")
# endif
# ifndef PRIV_XVM_CONTROL
# define PRIV_XVM_CONTROL ((const char *)"xvm_control")
# endif
# define PU_RESETGROUPS 0x0001 /* Remove supplemental groups */
# define PU_CLEARLIMITSET 0x0008 /* L=0 */
extern int __init_daemon_priv ( int , uid_t , gid_t , . . . ) ;
# define SYSTEM_UID 60
static gid_t unix_sock_gid = 60 ; /* Not used */
static int unix_sock_rw_mask = 0666 ;
static int unix_sock_ro_mask = 0666 ;
# else
static gid_t unix_sock_gid = 0 ; /* Only root by default */
static int unix_sock_rw_mask = 0700 ; /* Allow user only */
static int unix_sock_ro_mask = 0777 ; /* Allow world */
# endif /* __sun */
2007-06-11 16:04:54 +04:00
static int godaemon = 0 ; /* -d: Be a daemon */
static int verbose = 0 ; /* -v: Verbose mode */
2007-06-27 03:48:46 +04:00
static int timeout = - 1 ; /* -t: Shutdown timeout */
2007-06-11 16:04:54 +04:00
static int sigwrite = - 1 ; /* Signal handler pipe */
2007-06-27 03:48:46 +04:00
static int ipsock = 0 ; /* -l Listen for TCP/IP */
2007-06-11 16:04:54 +04:00
2007-06-27 03:48:46 +04:00
/* Defaults for configuration file elements */
2007-06-11 16:04:54 +04:00
static int listen_tls = 1 ;
static int listen_tcp = 0 ;
2008-05-15 00:57:20 +04:00
static char * listen_addr = ( char * ) LIBVIRTD_LISTEN_ADDR ;
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 18:43:42 +03:00
static char * tls_port = ( char * ) LIBVIRTD_TLS_PORT ;
static char * tcp_port = ( char * ) LIBVIRTD_TCP_PORT ;
2007-06-11 16:04:54 +04:00
2009-02-09 20:52:38 +03:00
static char * unix_sock_dir = NULL ;
2007-12-05 21:21:27 +03:00
# if HAVE_POLKIT
static int auth_unix_rw = REMOTE_AUTH_POLKIT ;
static int auth_unix_ro = REMOTE_AUTH_POLKIT ;
# else
2007-12-05 18:34:05 +03:00
static int auth_unix_rw = REMOTE_AUTH_NONE ;
static int auth_unix_ro = REMOTE_AUTH_NONE ;
2007-12-05 21:21:27 +03:00
# endif /* HAVE_POLKIT */
2007-12-05 18:34:05 +03:00
# if HAVE_SASL
static int auth_tcp = REMOTE_AUTH_SASL ;
# else
static int auth_tcp = REMOTE_AUTH_NONE ;
# endif
static int auth_tls = REMOTE_AUTH_NONE ;
2007-09-19 05:56:55 +04:00
static int mdns_adv = 1 ;
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 18:43:42 +03:00
static char * mdns_name = NULL ;
2007-09-19 05:56:55 +04:00
2007-06-11 16:04:54 +04:00
static int tls_no_verify_certificate = 0 ;
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 18:43:42 +03:00
static char * * tls_allowed_dn_list = NULL ;
2007-06-11 16:04:54 +04:00
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 18:43:42 +03:00
static char * key_file = ( char * ) LIBVIRT_SERVERKEY ;
static char * cert_file = ( char * ) LIBVIRT_SERVERCERT ;
static char * ca_file = ( char * ) LIBVIRT_CACERT ;
static char * crl_file = ( char * ) " " ;
2007-06-11 16:04:54 +04:00
static gnutls_certificate_credentials_t x509_cred ;
static gnutls_dh_params_t dh_params ;
2008-12-05 01:18:44 +03:00
static int min_workers = 5 ;
static int max_workers = 20 ;
static int max_clients = 20 ;
2009-01-20 22:25:15 +03:00
/* Total number of 'in-process' RPC calls allowed across all clients */
static int max_requests = 20 ;
/* Total number of 'in-process' RPC calls allowed by a single client*/
static int max_client_requests = 5 ;
2007-06-11 16:04:54 +04:00
# define DH_BITS 1024
2007-02-16 21:28:17 +03:00
2007-03-27 14:28:45 +04:00
static sig_atomic_t sig_errors = 0 ;
static int sig_lasterrno = 0 ;
2009-10-16 15:14:54 +04:00
enum {
VIR_DAEMON_ERR_NONE = 0 ,
VIR_DAEMON_ERR_PIDFILE ,
VIR_DAEMON_ERR_RUNDIR ,
VIR_DAEMON_ERR_INIT ,
VIR_DAEMON_ERR_SIGNAL ,
VIR_DAEMON_ERR_PRIVS ,
VIR_DAEMON_ERR_NETWORK ,
VIR_DAEMON_ERR_CONFIG ,
VIR_DAEMON_ERR_LAST
} ;
VIR_ENUM_DECL ( virDaemonErr )
VIR_ENUM_IMPL ( virDaemonErr , VIR_DAEMON_ERR_LAST ,
" Initialization successful " ,
" Unable to obtain pidfile " ,
" Unable to create rundir " ,
" Unable to initialize libvirt " ,
" Unable to setup signal handlers " ,
" Unable to drop privileges " ,
" Unable to initialize network sockets " ,
" Unable to load configuration file " )
2008-05-13 10:30:58 +04:00
static void sig_handler ( int sig , siginfo_t * siginfo ,
void * context ATTRIBUTE_UNUSED ) {
2007-02-16 21:28:17 +03:00
int origerrno ;
2007-03-27 14:28:45 +04:00
int r ;
2007-02-16 21:28:17 +03:00
2008-05-13 10:30:58 +04:00
/* set the sig num in the struct */
siginfo - > si_signo = sig ;
2007-02-16 21:28:17 +03:00
origerrno = errno ;
2008-05-13 10:30:58 +04:00
r = safewrite ( sigwrite , siginfo , sizeof ( * siginfo ) ) ;
2007-03-27 14:28:45 +04:00
if ( r = = - 1 ) {
sig_errors + + ;
sig_lasterrno = errno ;
}
2007-02-16 21:28:17 +03:00
errno = origerrno ;
2007-02-14 04:40:09 +03:00
}
2007-02-16 21:28:17 +03:00
2008-11-19 19:19:36 +03:00
static void qemudDispatchClientEvent ( int watch , int fd , int events , void * opaque ) ;
static void qemudDispatchServerEvent ( int watch , int fd , int events , void * opaque ) ;
2009-01-20 22:27:11 +03:00
static int qemudStartWorker ( struct qemud_server * server , struct qemud_worker * worker ) ;
2009-01-20 22:25:15 +03:00
void
qemudClientMessageQueuePush ( struct qemud_client_message * * queue ,
struct qemud_client_message * msg )
{
struct qemud_client_message * tmp = * queue ;
if ( tmp ) {
while ( tmp - > next )
tmp = tmp - > next ;
tmp - > next = msg ;
} else {
* queue = msg ;
}
}
2009-07-10 15:20:03 +04:00
struct qemud_client_message *
2009-01-20 22:25:15 +03:00
qemudClientMessageQueueServe ( struct qemud_client_message * * queue )
{
struct qemud_client_message * tmp = * queue ;
if ( tmp ) {
* queue = tmp - > next ;
tmp - > next = NULL ;
}
return tmp ;
}
2007-06-26 23:11:00 +04:00
2007-07-12 18:54:45 +04:00
static int
remoteCheckCertFile ( const char * type , const char * file )
{
struct stat sb ;
if ( stat ( file , & sb ) < 0 ) {
2009-02-05 19:28:03 +03:00
char ebuf [ 1024 ] ;
VIR_ERROR ( _ ( " Cannot access %s '%s': %s " ) ,
type , file , virStrerror ( errno , ebuf , sizeof ebuf ) ) ;
2007-07-12 18:54:45 +04:00
return - 1 ;
}
return 0 ;
}
2007-06-11 16:04:54 +04:00
static int
remoteInitializeGnuTLS ( void )
{
int err ;
/* Initialise GnuTLS. */
gnutls_global_init ( ) ;
err = gnutls_certificate_allocate_credentials ( & x509_cred ) ;
if ( err ) {
2009-01-06 21:32:03 +03:00
VIR_ERROR ( _ ( " gnutls_certificate_allocate_credentials: %s " ) ,
2007-06-11 16:04:54 +04:00
gnutls_strerror ( err ) ) ;
return - 1 ;
}
if ( ca_file & & ca_file [ 0 ] ! = ' \0 ' ) {
2007-07-12 18:54:45 +04:00
if ( remoteCheckCertFile ( " CA certificate " , ca_file ) < 0 )
return - 1 ;
2007-06-11 16:04:54 +04:00
qemudDebug ( " loading CA cert from %s " , ca_file ) ;
err = gnutls_certificate_set_x509_trust_file ( x509_cred , ca_file ,
GNUTLS_X509_FMT_PEM ) ;
if ( err < 0 ) {
2009-01-06 21:32:03 +03:00
VIR_ERROR ( _ ( " gnutls_certificate_set_x509_trust_file: %s " ) ,
2007-06-11 16:04:54 +04:00
gnutls_strerror ( err ) ) ;
return - 1 ;
}
}
if ( crl_file & & crl_file [ 0 ] ! = ' \0 ' ) {
2007-11-22 02:16:11 +03:00
if ( remoteCheckCertFile ( " CA revocation list " , crl_file ) < 0 )
2007-07-12 18:54:45 +04:00
return - 1 ;
2008-12-22 15:53:26 +03:00
DEBUG ( " loading CRL from %s " , crl_file ) ;
2007-06-11 16:04:54 +04:00
err = gnutls_certificate_set_x509_crl_file ( x509_cred , crl_file ,
GNUTLS_X509_FMT_PEM ) ;
if ( err < 0 ) {
2009-01-06 21:32:03 +03:00
VIR_ERROR ( _ ( " gnutls_certificate_set_x509_crl_file: %s " ) ,
2007-06-11 16:04:54 +04:00
gnutls_strerror ( err ) ) ;
return - 1 ;
}
}
if ( cert_file & & cert_file [ 0 ] ! = ' \0 ' & & key_file & & key_file [ 0 ] ! = ' \0 ' ) {
2007-07-12 18:54:45 +04:00
if ( remoteCheckCertFile ( " server certificate " , cert_file ) < 0 )
return - 1 ;
if ( remoteCheckCertFile ( " server key " , key_file ) < 0 )
return - 1 ;
2008-12-22 15:53:26 +03:00
DEBUG ( " loading cert and key from %s and %s " , cert_file , key_file ) ;
2007-06-11 16:04:54 +04:00
err =
gnutls_certificate_set_x509_key_file ( x509_cred ,
cert_file , key_file ,
GNUTLS_X509_FMT_PEM ) ;
if ( err < 0 ) {
2009-01-06 21:32:03 +03:00
VIR_ERROR ( _ ( " gnutls_certificate_set_x509_key_file: %s " ) ,
2007-06-11 16:04:54 +04:00
gnutls_strerror ( err ) ) ;
return - 1 ;
}
}
/* Generate Diffie Hellman parameters - for use with DHE
* kx algorithms . These should be discarded and regenerated
* once a day , once a week or once a month . Depending on the
* security requirements .
*/
err = gnutls_dh_params_init ( & dh_params ) ;
if ( err < 0 ) {
2009-01-06 21:32:03 +03:00
VIR_ERROR ( _ ( " gnutls_dh_params_init: %s " ) , gnutls_strerror ( err ) ) ;
2007-06-11 16:04:54 +04:00
return - 1 ;
}
err = gnutls_dh_params_generate2 ( dh_params , DH_BITS ) ;
if ( err < 0 ) {
2009-01-06 21:32:03 +03:00
VIR_ERROR ( _ ( " gnutls_dh_params_generate2: %s " ) , gnutls_strerror ( err ) ) ;
2007-06-11 16:04:54 +04:00
return - 1 ;
}
gnutls_certificate_set_dh_params ( x509_cred , dh_params ) ;
return 0 ;
}
2008-10-23 17:18:18 +04:00
static void
2008-11-19 19:19:36 +03:00
qemudDispatchSignalEvent ( int watch ATTRIBUTE_UNUSED ,
int fd ATTRIBUTE_UNUSED ,
2008-10-23 17:18:18 +04:00
int events ATTRIBUTE_UNUSED ,
void * opaque ) {
2007-06-26 23:11:00 +04:00
struct qemud_server * server = ( struct qemud_server * ) opaque ;
2008-05-13 10:30:58 +04:00
siginfo_t siginfo ;
2007-02-16 21:28:17 +03:00
2009-01-15 22:56:05 +03:00
virMutexLock ( & server - > lock ) ;
2008-12-05 01:16:40 +03:00
2008-05-13 10:30:58 +04:00
if ( saferead ( server - > sigread , & siginfo , sizeof ( siginfo ) ) ! = sizeof ( siginfo ) ) {
2009-02-05 19:28:03 +03:00
char ebuf [ 1024 ] ;
VIR_ERROR ( _ ( " Failed to read from signal pipe: %s " ) ,
virStrerror ( errno , ebuf , sizeof ebuf ) ) ;
2009-01-15 22:56:05 +03:00
virMutexUnlock ( & server - > lock ) ;
2007-06-26 23:11:00 +04:00
return ;
2007-02-16 21:30:55 +03:00
}
2008-05-13 10:30:58 +04:00
switch ( siginfo . si_signo ) {
2007-02-16 21:28:17 +03:00
case SIGHUP :
2009-01-06 21:32:03 +03:00
VIR_INFO0 ( _ ( " Reloading configuration on SIGHUP " ) ) ;
2007-06-27 02:56:14 +04:00
if ( virStateReload ( ) < 0 )
2009-01-06 21:32:03 +03:00
VIR_WARN0 ( _ ( " Error while reloading drivers " ) ) ;
2007-02-16 21:28:17 +03:00
break ;
case SIGINT :
2007-02-19 19:59:15 +03:00
case SIGQUIT :
2007-02-16 21:28:17 +03:00
case SIGTERM :
2009-01-06 21:32:03 +03:00
VIR_WARN ( _ ( " Shutting down on signal %d " ) , siginfo . si_signo ) ;
2009-10-16 19:34:37 +04:00
server - > quitEventThread = 1 ;
2007-02-16 21:28:17 +03:00
break ;
default :
2009-01-06 21:32:03 +03:00
VIR_INFO ( _ ( " Received unexpected signal %d " ) , siginfo . si_signo ) ;
2007-02-16 21:28:17 +03:00
break ;
}
2009-01-15 22:56:05 +03:00
virMutexUnlock ( & server - > lock ) ;
2007-02-16 21:28:17 +03:00
}
2007-02-16 21:30:55 +03:00
2009-10-16 15:14:54 +04:00
static int daemonForkIntoBackground ( void ) {
int statuspipe [ 2 ] ;
if ( pipe ( statuspipe ) < 0 )
return - 1 ;
2007-02-14 04:40:09 +03:00
int pid = fork ( ) ;
switch ( pid ) {
case 0 :
{
int stdinfd = - 1 ;
int stdoutfd = - 1 ;
2007-02-16 21:26:18 +03:00
int nextpid ;
2007-02-14 04:40:09 +03:00
2009-10-16 15:14:54 +04:00
close ( statuspipe [ 0 ] ) ;
2008-12-17 21:04:55 +03:00
if ( ( stdinfd = open ( " /dev/null " , O_RDONLY ) ) < 0 )
2007-02-14 04:40:09 +03:00
goto cleanup ;
2008-12-17 21:04:55 +03:00
if ( ( stdoutfd = open ( " /dev/null " , O_WRONLY ) ) < 0 )
2007-02-14 04:40:09 +03:00
goto cleanup ;
if ( dup2 ( stdinfd , STDIN_FILENO ) ! = STDIN_FILENO )
goto cleanup ;
if ( dup2 ( stdoutfd , STDOUT_FILENO ) ! = STDOUT_FILENO )
goto cleanup ;
if ( dup2 ( stdoutfd , STDERR_FILENO ) ! = STDERR_FILENO )
goto cleanup ;
if ( close ( stdinfd ) < 0 )
goto cleanup ;
stdinfd = - 1 ;
if ( close ( stdoutfd ) < 0 )
goto cleanup ;
stdoutfd = - 1 ;
if ( setsid ( ) < 0 )
goto cleanup ;
nextpid = fork ( ) ;
switch ( nextpid ) {
case 0 :
2009-10-16 15:14:54 +04:00
return statuspipe [ 1 ] ;
2007-02-14 04:40:09 +03:00
case - 1 :
return - 1 ;
default :
2008-03-11 17:22:12 +03:00
_exit ( 0 ) ;
2007-02-14 04:40:09 +03:00
}
cleanup :
if ( stdoutfd ! = - 1 )
close ( stdoutfd ) ;
if ( stdinfd ! = - 1 )
close ( stdinfd ) ;
return - 1 ;
}
case - 1 :
return - 1 ;
default :
{
2009-10-16 15:14:54 +04:00
int got , exitstatus = 0 ;
int ret ;
char status ;
close ( statuspipe [ 1 ] ) ;
/* We wait to make sure the first child forked successfully */
if ( ( got = waitpid ( pid , & exitstatus , 0 ) ) < 0 | |
2007-02-14 04:40:09 +03:00
got ! = pid | |
2009-10-16 15:14:54 +04:00
exitstatus ! = 0 ) {
2007-02-14 04:40:09 +03:00
return - 1 ;
}
2009-10-16 15:14:54 +04:00
/* Now block until the second child initializes successfully */
again :
ret = read ( statuspipe [ 0 ] , & status , 1 ) ;
if ( ret = = - 1 & & errno = = EINTR )
goto again ;
if ( ret = = 1 & & status ! = 0 ) {
2010-02-24 19:29:35 +03:00
fprintf ( stderr ,
" error: %s. Check /var/log/messages or run without "
" --daemon for more info. \n " ,
virDaemonErrTypeToString ( status ) ) ;
2009-10-16 15:14:54 +04:00
}
_exit ( ret = = 1 & & status = = 0 ? 0 : 1 ) ;
2007-02-14 04:40:09 +03:00
}
}
}
2007-02-23 15:48:36 +03:00
static int qemudWritePidFile ( const char * pidFile ) {
int fd ;
FILE * fh ;
2009-02-05 19:28:03 +03:00
char ebuf [ 1024 ] ;
2007-02-23 15:48:36 +03:00
if ( pidFile [ 0 ] = = ' \0 ' )
return 0 ;
if ( ( fd = open ( pidFile , O_WRONLY | O_CREAT | O_EXCL , 0644 ) ) < 0 ) {
2009-01-06 21:32:03 +03:00
VIR_ERROR ( _ ( " Failed to open pid file '%s' : %s " ) ,
2009-02-05 19:28:03 +03:00
pidFile , virStrerror ( errno , ebuf , sizeof ebuf ) ) ;
2007-02-23 15:48:36 +03:00
return - 1 ;
}
if ( ! ( fh = fdopen ( fd , " w " ) ) ) {
2009-01-06 21:32:03 +03:00
VIR_ERROR ( _ ( " Failed to fdopen pid file '%s' : %s " ) ,
2009-02-05 19:28:03 +03:00
pidFile , virStrerror ( errno , ebuf , sizeof ebuf ) ) ;
2007-02-23 15:48:36 +03:00
close ( fd ) ;
return - 1 ;
}
if ( fprintf ( fh , " %lu \n " , ( unsigned long ) getpid ( ) ) < 0 ) {
2009-01-06 21:32:03 +03:00
VIR_ERROR ( _ ( " Failed to write to pid file '%s' : %s " ) ,
2009-02-05 19:28:03 +03:00
pidFile , virStrerror ( errno , ebuf , sizeof ebuf ) ) ;
2009-03-16 13:41:37 +03:00
fclose ( fh ) ;
2007-02-23 15:48:36 +03:00
return - 1 ;
}
if ( fclose ( fh ) = = EOF ) {
2009-01-06 21:32:03 +03:00
VIR_ERROR ( _ ( " Failed to close pid file '%s' : %s " ) ,
2009-02-05 19:28:03 +03:00
pidFile , virStrerror ( errno , ebuf , sizeof ebuf ) ) ;
2007-02-23 15:48:36 +03:00
return - 1 ;
}
return 0 ;
}
2007-02-14 04:40:09 +03:00
static int qemudListenUnix ( struct qemud_server * server ,
2007-12-05 18:34:05 +03:00
const char * path , int readonly , int auth ) {
2008-06-06 14:52:01 +04:00
struct qemud_socket * sock ;
2007-02-14 04:40:09 +03:00
struct sockaddr_un addr ;
mode_t oldmask ;
2007-09-19 06:28:01 +04:00
gid_t oldgrp ;
2009-02-05 19:28:03 +03:00
char ebuf [ 1024 ] ;
2007-02-14 04:40:09 +03:00
2008-06-06 14:52:01 +04:00
if ( VIR_ALLOC ( sock ) < 0 ) {
2009-01-06 21:32:03 +03:00
VIR_ERROR ( " %s " , _ ( " Failed to allocate memory for struct qemud_socket " ) ) ;
2007-02-14 04:40:09 +03:00
return - 1 ;
2007-02-16 21:30:55 +03:00
}
2007-02-14 04:40:09 +03:00
sock - > readonly = readonly ;
2007-09-19 05:56:55 +04:00
sock - > port = - 1 ;
2007-12-05 18:27:08 +03:00
sock - > type = QEMUD_SOCK_TYPE_UNIX ;
2007-12-05 18:34:05 +03:00
sock - > auth = auth ;
2007-02-14 04:40:09 +03:00
2007-02-16 21:30:55 +03:00
if ( ( sock - > fd = socket ( PF_UNIX , SOCK_STREAM , 0 ) ) < 0 ) {
2009-01-06 21:32:03 +03:00
VIR_ERROR ( _ ( " Failed to create socket: %s " ) ,
2009-02-05 19:28:03 +03:00
virStrerror ( errno , ebuf , sizeof ebuf ) ) ;
2007-06-26 23:11:00 +04:00
goto cleanup ;
2007-02-16 21:30:55 +03:00
}
2007-02-14 04:40:09 +03:00
2009-05-12 19:43:07 +04:00
if ( virSetCloseExec ( sock - > fd ) < 0 | |
virSetNonBlock ( sock - > fd ) < 0 )
2007-06-26 23:11:00 +04:00
goto cleanup ;
2007-02-14 04:40:09 +03:00
memset ( & addr , 0 , sizeof ( addr ) ) ;
addr . sun_family = AF_UNIX ;
2009-08-03 16:37:44 +04:00
if ( virStrcpyStatic ( addr . sun_path , path ) = = NULL ) {
VIR_ERROR ( _ ( " Path %s too long for unix socket " ) , path ) ;
goto cleanup ;
}
2007-02-14 04:40:09 +03:00
if ( addr . sun_path [ 0 ] = = ' @ ' )
addr . sun_path [ 0 ] = ' \0 ' ;
2007-09-19 06:28:01 +04:00
oldgrp = getgid ( ) ;
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 18:43:42 +03:00
oldmask = umask ( readonly ? ~ unix_sock_ro_mask : ~ unix_sock_rw_mask ) ;
2009-06-12 17:20:13 +04:00
if ( server - > privileged )
2007-09-19 06:28:01 +04:00
setgid ( unix_sock_gid ) ;
2007-02-16 21:30:55 +03:00
if ( bind ( sock - > fd , ( struct sockaddr * ) & addr , sizeof ( addr ) ) < 0 ) {
2009-01-06 21:32:03 +03:00
VIR_ERROR ( _ ( " Failed to bind socket to '%s': %s " ) ,
2009-02-05 19:28:03 +03:00
path , virStrerror ( errno , ebuf , sizeof ebuf ) ) ;
2007-06-26 23:11:00 +04:00
goto cleanup ;
2007-02-16 21:30:55 +03:00
}
2007-02-14 04:40:09 +03:00
umask ( oldmask ) ;
2009-06-12 17:20:13 +04:00
if ( server - > privileged )
2007-09-19 06:28:01 +04:00
setgid ( oldgrp ) ;
2007-02-14 04:40:09 +03:00
2007-02-16 21:30:55 +03:00
if ( listen ( sock - > fd , 30 ) < 0 ) {
2009-01-06 21:32:03 +03:00
VIR_ERROR ( _ ( " Failed to listen for connections on '%s': %s " ) ,
2009-02-05 19:28:03 +03:00
path , virStrerror ( errno , ebuf , sizeof ebuf ) ) ;
2007-06-26 23:11:00 +04:00
goto cleanup ;
}
sock - > next = server - > sockets ;
server - > sockets = sock ;
server - > nsockets + + ;
2007-02-14 04:40:09 +03:00
return 0 ;
2007-06-26 23:11:00 +04:00
cleanup :
2010-02-02 13:27:25 +03:00
if ( sock - > fd > = 0 )
2007-06-26 23:11:00 +04:00
close ( sock - > fd ) ;
2009-12-10 02:00:50 +03:00
VIR_FREE ( sock ) ;
2007-06-26 23:11:00 +04:00
return - 1 ;
2007-02-14 04:40:09 +03:00
}
2007-06-11 16:04:54 +04:00
// See: http://people.redhat.com/drepper/userapi-ipv6.html
static int
2008-05-15 00:57:20 +04:00
remoteMakeSockets ( int * fds , int max_fds , int * nfds_r , const char * node , const char * service )
2007-06-11 16:04:54 +04:00
{
struct addrinfo * ai ;
struct addrinfo hints ;
memset ( & hints , 0 , sizeof hints ) ;
hints . ai_flags = AI_PASSIVE | AI_ADDRCONFIG ;
hints . ai_socktype = SOCK_STREAM ;
2008-05-15 00:57:20 +04:00
int e = getaddrinfo ( node , service , & hints , & ai ) ;
2007-06-11 16:04:54 +04:00
if ( e ! = 0 ) {
2010-01-19 16:17:20 +03:00
VIR_ERROR ( _ ( " getaddrinfo: %s " ) , gai_strerror ( e ) ) ;
2007-06-11 16:04:54 +04:00
return - 1 ;
}
struct addrinfo * runp = ai ;
while ( runp & & * nfds_r < max_fds ) {
2009-02-05 19:28:03 +03:00
char ebuf [ 1024 ] ;
2007-06-11 16:04:54 +04:00
fds [ * nfds_r ] = socket ( runp - > ai_family , runp - > ai_socktype ,
runp - > ai_protocol ) ;
if ( fds [ * nfds_r ] = = - 1 ) {
2009-02-05 19:28:03 +03:00
VIR_ERROR ( _ ( " socket: %s " ) , virStrerror ( errno , ebuf , sizeof ebuf ) ) ;
2007-06-11 16:04:54 +04:00
return - 1 ;
}
int opt = 1 ;
setsockopt ( fds [ * nfds_r ] , SOL_SOCKET , SO_REUSEADDR , & opt , sizeof opt ) ;
2009-11-11 18:19:50 +03:00
# ifdef IPV6_V6ONLY
if ( runp - > ai_family = = PF_INET6 ) {
int on = 1 ;
/*
* Normally on Linux an INET6 socket will bind to the INET4
* address too . If getaddrinfo returns results with INET4
* first though , this will result in INET6 binding failing .
* We can trivially cope with multiple server sockets , so
* we force it to only listen on IPv6
*/
setsockopt ( fds [ * nfds_r ] , IPPROTO_IPV6 , IPV6_V6ONLY ,
( void * ) & on , sizeof on ) ;
}
# endif
2007-06-11 16:04:54 +04:00
if ( bind ( fds [ * nfds_r ] , runp - > ai_addr , runp - > ai_addrlen ) = = - 1 ) {
if ( errno ! = EADDRINUSE ) {
2009-02-05 19:28:03 +03:00
VIR_ERROR ( _ ( " bind: %s " ) , virStrerror ( errno , ebuf , sizeof ebuf ) ) ;
2007-06-11 16:04:54 +04:00
return - 1 ;
}
close ( fds [ * nfds_r ] ) ;
2009-10-16 14:24:01 +04:00
} else {
2007-06-11 16:04:54 +04:00
+ + * nfds_r ;
}
runp = runp - > ai_next ;
}
2007-02-23 12:10:28 +03:00
2007-06-11 16:04:54 +04:00
freeaddrinfo ( ai ) ;
return 0 ;
}
/* Listen on the named/numbered TCP port. On a machine with IPv4 and
* IPv6 interfaces this may generate several sockets .
*/
static int
remoteListenTCP ( struct qemud_server * server ,
2008-05-15 01:23:02 +04:00
const char * addr ,
2007-06-11 16:04:54 +04:00
const char * port ,
2007-12-05 18:27:08 +03:00
int type ,
2007-12-05 18:24:15 +03:00
int auth )
2007-06-11 16:04:54 +04:00
{
int fds [ 2 ] ;
int nfds = 0 ;
2007-02-23 12:10:28 +03:00
int i ;
2007-06-11 16:04:54 +04:00
struct qemud_socket * sock ;
2008-05-15 00:57:20 +04:00
if ( remoteMakeSockets ( fds , 2 , & nfds , addr , port ) = = - 1 )
2007-06-11 16:04:54 +04:00
return - 1 ;
for ( i = 0 ; i < nfds ; + + i ) {
2009-02-13 22:10:55 +03:00
union {
struct sockaddr_storage sa_stor ;
struct sockaddr sa ;
struct sockaddr_in sa_in ;
# ifdef AF_INET6
struct sockaddr_in6 sa_in6 ;
# endif
} s ;
2009-02-05 19:28:03 +03:00
char ebuf [ 1024 ] ;
2009-02-13 22:10:55 +03:00
socklen_t salen = sizeof ( s ) ;
2007-09-19 05:56:55 +04:00
2008-06-06 14:52:01 +04:00
if ( VIR_ALLOC ( sock ) < 0 ) {
2009-02-05 19:28:03 +03:00
VIR_ERROR ( _ ( " remoteListenTCP: calloc: %s " ) ,
virStrerror ( errno , ebuf , sizeof ebuf ) ) ;
2008-06-06 14:52:01 +04:00
goto cleanup ;
2007-06-11 16:04:54 +04:00
}
sock - > readonly = 0 ;
sock - > next = server - > sockets ;
server - > sockets = sock ;
server - > nsockets + + ;
sock - > fd = fds [ i ] ;
2007-12-05 18:27:08 +03:00
sock - > type = type ;
2007-12-05 18:24:15 +03:00
sock - > auth = auth ;
2007-02-14 04:40:09 +03:00
2009-02-13 22:10:55 +03:00
if ( getsockname ( sock - > fd , & s . sa , & salen ) < 0 )
2008-06-06 14:52:01 +04:00
goto cleanup ;
2007-09-19 05:56:55 +04:00
2009-02-13 22:10:55 +03:00
if ( s . sa . sa_family = = AF_INET ) {
sock - > port = htons ( s . sa_in . sin_port ) ;
2007-11-26 14:56:41 +03:00
# ifdef AF_INET6
2009-02-13 22:10:55 +03:00
} else if ( s . sa . sa_family = = AF_INET6 )
sock - > port = htons ( s . sa_in6 . sin6_port ) ;
2007-11-26 14:56:41 +03:00
# endif
2007-09-19 05:56:55 +04:00
else
sock - > port = - 1 ;
2009-05-12 19:43:07 +04:00
if ( virSetCloseExec ( sock - > fd ) < 0 | |
virSetNonBlock ( sock - > fd ) < 0 )
2008-06-06 14:52:01 +04:00
goto cleanup ;
2007-06-11 16:04:54 +04:00
if ( listen ( sock - > fd , 30 ) < 0 ) {
2009-02-05 19:28:03 +03:00
VIR_ERROR ( _ ( " remoteListenTCP: listen: %s " ) ,
virStrerror ( errno , ebuf , sizeof ebuf ) ) ;
2008-06-06 14:52:01 +04:00
goto cleanup ;
2007-02-20 12:04:27 +03:00
}
2007-06-11 16:04:54 +04:00
}
return 0 ;
2008-06-06 14:52:01 +04:00
cleanup :
for ( i = 0 ; i < nfds ; + + i )
2009-02-17 17:40:24 +03:00
close ( fds [ i ] ) ;
2008-06-06 14:52:01 +04:00
return - 1 ;
2007-06-11 16:04:54 +04:00
}
static int qemudInitPaths ( struct qemud_server * server ,
char * sockname ,
char * roSockname ,
2009-01-22 20:49:41 +03:00
int maxlen )
{
2009-02-09 20:52:38 +03:00
char * sock_dir ;
char * dir_prefix = NULL ;
int ret = - 1 ;
char * sock_dir_prefix = NULL ;
2009-10-16 14:29:01 +04:00
if ( unix_sock_dir ) {
2009-02-09 20:52:38 +03:00
sock_dir = unix_sock_dir ;
2009-10-16 14:29:01 +04:00
/* Change the group ownership of /var/run/libvirt to unix_sock_gid */
if ( server - > privileged ) {
if ( chown ( unix_sock_dir , - 1 , unix_sock_gid ) < 0 )
VIR_ERROR ( _ ( " Failed to change group ownership of %s " ) ,
unix_sock_dir ) ;
}
} else {
2009-02-09 20:52:38 +03:00
sock_dir = sockname ;
2009-06-12 17:20:13 +04:00
if ( server - > privileged ) {
2009-02-09 20:52:38 +03:00
dir_prefix = strdup ( LOCAL_STATE_DIR ) ;
if ( dir_prefix = = NULL ) {
2010-02-04 21:19:08 +03:00
virReportOOMError ( ) ;
2009-02-09 20:52:38 +03:00
goto cleanup ;
}
if ( snprintf ( sock_dir , maxlen , " %s/run/libvirt " ,
dir_prefix ) > = maxlen )
goto snprintf_error ;
} else {
2009-06-12 17:20:13 +04:00
uid_t uid = geteuid ( ) ;
2010-02-05 01:41:52 +03:00
dir_prefix = virGetUserDirectory ( uid ) ;
2009-02-09 20:52:38 +03:00
if ( dir_prefix = = NULL ) {
/* Do not diagnose here; virGetUserDirectory does that. */
goto snprintf_error ;
}
2007-06-11 16:04:54 +04:00
2009-02-09 20:52:38 +03:00
if ( snprintf ( sock_dir , maxlen , " %s/.libvirt " , dir_prefix ) > = maxlen )
goto snprintf_error ;
}
}
2007-02-16 21:30:55 +03:00
2009-02-09 20:52:38 +03:00
sock_dir_prefix = strdup ( sock_dir ) ;
if ( ! sock_dir_prefix ) {
2010-02-04 21:19:08 +03:00
virReportOOMError ( ) ;
2009-02-09 20:52:38 +03:00
goto cleanup ;
}
2007-02-14 04:40:09 +03:00
2009-06-12 17:20:13 +04:00
if ( server - > privileged ) {
2009-02-09 20:52:38 +03:00
if ( snprintf ( sockname , maxlen , " %s/libvirt-sock " ,
sock_dir_prefix ) > = maxlen
| | ( snprintf ( roSockname , maxlen , " %s/libvirt-sock-ro " ,
sock_dir_prefix ) > = maxlen ) )
2007-02-16 21:30:55 +03:00
goto snprintf_error ;
2009-02-09 20:52:38 +03:00
unlink ( sockname ) ;
2007-03-06 19:51:48 +03:00
unlink ( roSockname ) ;
2007-02-14 04:40:09 +03:00
} else {
2009-02-09 20:52:38 +03:00
if ( snprintf ( sockname , maxlen , " @%s/libvirt-sock " ,
sock_dir_prefix ) > = maxlen )
2007-06-27 03:48:46 +04:00
goto snprintf_error ;
2009-02-09 20:52:38 +03:00
}
2007-06-11 16:04:54 +04:00
2009-10-16 14:09:13 +04:00
if ( server - > privileged ) {
if ( ! ( server - > logDir = strdup ( LOCAL_STATE_DIR " /log/libvirt " ) ) )
2010-02-04 21:19:08 +03:00
virReportOOMError ( ) ;
2009-10-16 14:09:13 +04:00
} else {
if ( virAsprintf ( & server - > logDir , " %s/.libvirt/log " , dir_prefix ) < 0 )
2010-02-04 21:19:08 +03:00
virReportOOMError ( ) ;
2009-10-16 14:09:13 +04:00
}
2007-06-11 16:04:54 +04:00
2009-02-09 20:52:38 +03:00
if ( server - > logDir = = NULL )
2009-10-16 14:09:13 +04:00
goto cleanup ;
2009-02-09 20:52:38 +03:00
ret = 0 ;
2007-02-16 21:30:55 +03:00
snprintf_error :
2009-02-09 20:52:38 +03:00
if ( ret )
VIR_ERROR ( " %s " ,
_ ( " Resulting path too long for buffer in qemudInitPaths() " ) ) ;
cleanup :
2009-12-10 02:00:50 +03:00
VIR_FREE ( dir_prefix ) ;
VIR_FREE ( sock_dir_prefix ) ;
2009-02-09 20:52:38 +03:00
return ret ;
2007-02-14 04:40:09 +03:00
}
2009-10-19 21:28:28 +04:00
static void virshErrorHandler ( void * opaque ATTRIBUTE_UNUSED , virErrorPtr err ATTRIBUTE_UNUSED )
{
/* Don't do anything, since logging infrastructure already
* took care of reporting the error */
}
2009-10-16 14:48:50 +04:00
static struct qemud_server * qemudInitialize ( void ) {
2007-02-14 04:40:09 +03:00
struct qemud_server * server ;
2008-06-06 14:52:01 +04:00
if ( VIR_ALLOC ( server ) < 0 ) {
2009-01-06 21:32:03 +03:00
VIR_ERROR0 ( _ ( " Failed to allocate struct qemud_server " ) ) ;
2007-02-14 04:40:09 +03:00
return NULL ;
2007-02-16 21:30:55 +03:00
}
2007-02-14 04:40:09 +03:00
2009-10-16 14:48:50 +04:00
server - > privileged = geteuid ( ) = = 0 ? 1 : 0 ;
server - > sigread = server - > sigwrite = - 1 ;
2009-01-15 22:56:05 +03:00
if ( virMutexInit ( & server - > lock ) < 0 ) {
VIR_ERROR ( " %s " , _ ( " cannot initialize mutex " ) ) ;
VIR_FREE ( server ) ;
2009-10-16 14:48:50 +04:00
return NULL ;
2009-01-15 22:56:05 +03:00
}
if ( virCondInit ( & server - > job ) < 0 ) {
VIR_ERROR ( " %s " , _ ( " cannot initialize condition variable " ) ) ;
virMutexDestroy ( & server - > lock ) ;
2008-12-05 01:16:40 +03:00
VIR_FREE ( server ) ;
2009-10-16 14:48:50 +04:00
return NULL ;
2008-12-05 01:16:40 +03:00
}
2008-12-05 01:14:15 +03:00
if ( virEventInit ( ) < 0 ) {
2009-01-06 21:32:03 +03:00
VIR_ERROR0 ( _ ( " Failed to initialize event system " ) ) ;
2009-10-16 14:48:50 +04:00
virMutexDestroy ( & server - > lock ) ;
if ( virCondDestroy ( & server - > job ) < 0 )
{ }
2008-12-05 01:14:15 +03:00
VIR_FREE ( server ) ;
return NULL ;
}
2008-12-02 14:37:55 +03:00
/*
* Note that the order is important : the first ones have a higher
* priority when calling virStateInitialize . We must register
* the network , storage and nodedev drivers before any domain
* drivers , since their resources must be auto - started before
* any domains can be auto - started .
*/
2008-11-21 15:16:08 +03:00
# ifdef WITH_DRIVER_MODULES
/* We don't care if any of these fail, because the whole point
* is to allow users to only install modules they want to use .
2009-10-27 02:02:46 +03:00
* If they try to open a connection for a module that
2008-11-21 15:16:08 +03:00
* is not loaded they ' ll get a suitable error at that point
*/
virDriverLoadModule ( " network " ) ;
virDriverLoadModule ( " storage " ) ;
2008-11-21 15:27:11 +03:00
virDriverLoadModule ( " nodedev " ) ;
2009-08-14 23:48:55 +04:00
virDriverLoadModule ( " secret " ) ;
2008-12-02 14:37:55 +03:00
virDriverLoadModule ( " qemu " ) ;
virDriverLoadModule ( " lxc " ) ;
virDriverLoadModule ( " uml " ) ;
2009-05-25 15:56:00 +04:00
virDriverLoadModule ( " one " ) ;
2008-11-21 15:16:08 +03:00
# else
2008-11-17 15:18:18 +03:00
# ifdef WITH_NETWORK
networkRegister ( ) ;
# endif
2009-07-21 18:02:16 +04:00
# ifdef WITH_NETCF
interfaceRegister ( ) ;
# endif
2008-11-17 15:18:18 +03:00
# ifdef WITH_STORAGE_DIR
storageRegister ( ) ;
2008-11-21 15:16:08 +03:00
# endif
2009-11-13 00:48:24 +03:00
# if defined(WITH_NODE_DEVICES)
2008-11-21 15:27:11 +03:00
nodedevRegister ( ) ;
# endif
2009-12-22 16:50:50 +03:00
# ifdef WITH_SECRETS
2009-08-14 23:48:55 +04:00
secretRegister ( ) ;
2009-12-22 16:50:50 +03:00
# endif
2008-12-02 14:37:55 +03:00
# ifdef WITH_QEMU
qemuRegister ( ) ;
# endif
# ifdef WITH_LXC
lxcRegister ( ) ;
# endif
# ifdef WITH_UML
umlRegister ( ) ;
# endif
2009-05-25 15:56:00 +04:00
# ifdef WITH_ONE
oneRegister ( ) ;
# endif
2008-11-17 15:18:18 +03:00
# endif
2008-10-23 17:18:18 +04:00
virEventRegisterImpl ( virEventAddHandleImpl ,
virEventUpdateHandleImpl ,
virEventRemoveHandleImpl ,
virEventAddTimeoutImpl ,
virEventUpdateTimeoutImpl ,
virEventRemoveTimeoutImpl ) ;
2007-06-27 03:48:46 +04:00
2007-12-05 18:34:05 +03:00
return server ;
}
2009-10-16 14:24:01 +04:00
static int qemudNetworkInit ( struct qemud_server * server ) {
2007-12-05 18:34:05 +03:00
char sockname [ PATH_MAX ] ;
char roSockname [ PATH_MAX ] ;
2007-12-05 18:24:15 +03:00
# if HAVE_SASL
2007-12-05 18:34:05 +03:00
int err ;
# endif /* HAVE_SASL */
roSockname [ 0 ] = ' \0 ' ;
if ( qemudInitPaths ( server , sockname , roSockname , PATH_MAX ) < 0 )
goto cleanup ;
if ( qemudListenUnix ( server , sockname , 0 , auth_unix_rw ) < 0 )
2007-12-05 18:24:15 +03:00
goto cleanup ;
2007-12-05 18:34:05 +03:00
if ( roSockname [ 0 ] ! = ' \0 ' & & qemudListenUnix ( server , roSockname , 1 , auth_unix_ro ) < 0 )
goto cleanup ;
# if HAVE_SASL
if ( auth_unix_rw = = REMOTE_AUTH_SASL | |
auth_unix_ro = = REMOTE_AUTH_SASL | |
auth_tcp = = REMOTE_AUTH_SASL | |
auth_tls = = REMOTE_AUTH_SASL ) {
if ( ( err = sasl_server_init ( NULL , " libvirt " ) ) ! = SASL_OK ) {
2009-01-06 21:32:03 +03:00
VIR_ERROR ( _ ( " Failed to initialize SASL authentication %s " ) ,
sasl_errstring ( err , NULL , NULL ) ) ;
2007-12-05 18:34:05 +03:00
goto cleanup ;
}
2007-12-05 18:24:15 +03:00
}
# endif
2009-08-06 16:54:08 +04:00
# if HAVE_POLKIT0
2007-12-05 21:21:27 +03:00
if ( auth_unix_rw = = REMOTE_AUTH_POLKIT | |
auth_unix_ro = = REMOTE_AUTH_POLKIT ) {
DBusError derr ;
2009-03-02 14:13:37 +03:00
dbus_connection_set_change_sigpipe ( FALSE ) ;
dbus_threads_init_default ( ) ;
2007-12-05 21:21:27 +03:00
dbus_error_init ( & derr ) ;
server - > sysbus = dbus_bus_get ( DBUS_BUS_SYSTEM , & derr ) ;
if ( ! ( server - > sysbus ) ) {
2009-01-06 21:32:03 +03:00
VIR_ERROR ( _ ( " Failed to connect to system bus for PolicyKit auth: %s " ) ,
derr . message ) ;
2007-12-05 21:21:27 +03:00
dbus_error_free ( & derr ) ;
goto cleanup ;
}
2009-03-02 14:13:37 +03:00
dbus_connection_set_exit_on_disconnect ( server - > sysbus , FALSE ) ;
2007-12-05 21:21:27 +03:00
}
# endif
2007-06-27 03:48:46 +04:00
if ( ipsock ) {
2008-05-15 00:57:20 +04:00
if ( listen_tcp & & remoteListenTCP ( server , listen_addr , tcp_port , QEMUD_SOCK_TYPE_TCP , auth_tcp ) < 0 )
2007-06-11 16:04:54 +04:00
goto cleanup ;
if ( listen_tls ) {
if ( remoteInitializeGnuTLS ( ) < 0 )
goto cleanup ;
2008-05-15 00:57:20 +04:00
if ( remoteListenTCP ( server , listen_addr , tls_port , QEMUD_SOCK_TYPE_TLS , auth_tls ) < 0 )
2007-06-11 16:04:54 +04:00
goto cleanup ;
}
2007-02-14 04:40:09 +03:00
}
2007-09-19 05:56:55 +04:00
# ifdef HAVE_AVAHI
2009-06-12 17:20:13 +04:00
if ( server - > privileged & & mdns_adv ) {
2007-09-19 05:56:55 +04:00
struct libvirtd_mdns_group * group ;
2009-10-16 14:24:01 +04:00
struct qemud_socket * sock ;
2007-09-19 05:56:55 +04:00
int port = 0 ;
server - > mdns = libvirtd_mdns_new ( ) ;
if ( ! mdns_name ) {
2009-10-23 14:05:01 +04:00
char groupname [ 64 ] , * localhost , * tmp ;
2007-09-19 05:56:55 +04:00
/* Extract the host part of the potentially FQDN */
2009-10-23 21:01:22 +04:00
localhost = virGetHostname ( NULL ) ;
if ( localhost = = NULL )
2009-10-23 14:05:01 +04:00
goto cleanup ;
2009-10-23 21:01:22 +04:00
2007-09-19 05:56:55 +04:00
if ( ( tmp = strchr ( localhost , ' . ' ) ) )
* tmp = ' \0 ' ;
snprintf ( groupname , sizeof ( groupname ) - 1 , " Virtualization Host %s " , localhost ) ;
groupname [ sizeof ( groupname ) - 1 ] = ' \0 ' ;
group = libvirtd_mdns_add_group ( server - > mdns , groupname ) ;
2009-10-23 14:05:01 +04:00
VIR_FREE ( localhost ) ;
2007-09-19 05:56:55 +04:00
} else {
group = libvirtd_mdns_add_group ( server - > mdns , mdns_name ) ;
}
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 18:43:42 +03:00
/*
2007-09-19 05:56:55 +04:00
* See if there ' s a TLS enabled port we can advertise . Cowardly
* don ' t bother to advertise TCP since we don ' t want people using
* them for real world apps
*/
sock = server - > sockets ;
while ( sock ) {
2007-12-05 18:27:08 +03:00
if ( sock - > port ! = - 1 & & sock - > type = = QEMUD_SOCK_TYPE_TLS ) {
2007-09-19 05:56:55 +04:00
port = sock - > port ;
break ;
}
sock = sock - > next ;
}
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 18:43:42 +03:00
2007-09-19 05:56:55 +04:00
/*
* Add the primary entry - we choose SSH because its most likely to always
* be available
*/
libvirtd_mdns_add_entry ( group , " _libvirt._tcp " , port ) ;
libvirtd_mdns_start ( server - > mdns ) ;
}
# endif
2009-10-16 14:24:01 +04:00
return 0 ;
2007-02-14 04:40:09 +03:00
cleanup :
2009-10-16 14:24:01 +04:00
return - 1 ;
2007-02-14 04:40:09 +03:00
}
2009-10-16 19:34:37 +04:00
static int qemudNetworkEnable ( struct qemud_server * server ) {
struct qemud_socket * sock ;
sock = server - > sockets ;
while ( sock ) {
if ( ( sock - > watch = virEventAddHandleImpl ( sock - > fd ,
VIR_EVENT_HANDLE_READABLE |
VIR_EVENT_HANDLE_ERROR |
VIR_EVENT_HANDLE_HANGUP ,
qemudDispatchServerEvent ,
server , NULL ) ) < 0 ) {
VIR_ERROR0 ( _ ( " Failed to add server event callback " ) ) ;
return - 1 ;
}
sock = sock - > next ;
}
return 0 ;
}
2009-10-16 14:24:01 +04:00
2007-06-11 16:04:54 +04:00
static gnutls_session_t
remoteInitializeTLSSession ( void )
{
gnutls_session_t session ;
int err ;
err = gnutls_init ( & session , GNUTLS_SERVER ) ;
if ( err ! = 0 ) goto failed ;
/* avoid calling all the priority functions, since the defaults
* are adequate .
*/
err = gnutls_set_default_priority ( session ) ;
if ( err ! = 0 ) goto failed ;
err = gnutls_credentials_set ( session , GNUTLS_CRD_CERTIFICATE , x509_cred ) ;
if ( err ! = 0 ) goto failed ;
/* request client certificate if any.
*/
gnutls_certificate_server_set_request ( session , GNUTLS_CERT_REQUEST ) ;
gnutls_dh_set_prime_bits ( session , DH_BITS ) ;
return session ;
failed :
2009-01-06 21:32:03 +03:00
VIR_ERROR ( _ ( " remoteInitializeTLSSession: %s " ) ,
2007-06-11 16:04:54 +04:00
gnutls_strerror ( err ) ) ;
return NULL ;
}
/* Check DN is on tls_allowed_dn_list. */
static int
remoteCheckDN ( gnutls_x509_crt_t cert )
{
char name [ 256 ] ;
size_t namesize = sizeof name ;
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 18:43:42 +03:00
char * * wildcards ;
2007-06-11 16:04:54 +04:00
int err ;
err = gnutls_x509_crt_get_dn ( cert , name , & namesize ) ;
if ( err ! = 0 ) {
2009-01-06 21:32:03 +03:00
VIR_ERROR ( _ ( " remoteCheckDN: gnutls_x509_cert_get_dn: %s " ) ,
2007-06-11 16:04:54 +04:00
gnutls_strerror ( err ) ) ;
return 0 ;
}
/* If the list is not set, allow any DN. */
wildcards = tls_allowed_dn_list ;
if ( ! wildcards )
return 1 ;
while ( * wildcards ) {
if ( fnmatch ( * wildcards , name , 0 ) = = 0 )
return 1 ;
wildcards + + ;
}
/* Print the client's DN. */
2008-12-22 15:53:26 +03:00
DEBUG ( _ ( " remoteCheckDN: failed: client DN is %s " ) , name ) ;
2007-06-11 16:04:54 +04:00
return 0 ; // Not found.
}
static int
remoteCheckCertificate ( gnutls_session_t session )
{
int ret ;
unsigned int status ;
const gnutls_datum_t * certs ;
unsigned int nCerts , i ;
time_t now ;
if ( ( ret = gnutls_certificate_verify_peers2 ( session , & status ) ) < 0 ) {
2009-01-06 21:32:03 +03:00
VIR_ERROR ( _ ( " remoteCheckCertificate: verify failed: %s " ) ,
2007-06-11 16:04:54 +04:00
gnutls_strerror ( ret ) ) ;
return - 1 ;
}
if ( status ! = 0 ) {
if ( status & GNUTLS_CERT_INVALID )
2009-01-06 21:32:03 +03:00
VIR_ERROR0 ( _ ( " remoteCheckCertificate: "
" the client certificate is not trusted. " ) ) ;
2007-06-11 16:04:54 +04:00
if ( status & GNUTLS_CERT_SIGNER_NOT_FOUND )
2009-01-06 21:32:03 +03:00
VIR_ERROR0 ( _ ( " remoteCheckCertificate: the client "
" certificate has unknown issuer. " ) ) ;
2007-06-11 16:04:54 +04:00
if ( status & GNUTLS_CERT_REVOKED )
2009-01-06 21:32:03 +03:00
VIR_ERROR0 ( _ ( " remoteCheckCertificate: "
" the client certificate has been revoked. " ) ) ;
2007-06-11 16:04:54 +04:00
2007-08-07 17:02:35 +04:00
# ifndef GNUTLS_1_0_COMPAT
2007-06-11 16:04:54 +04:00
if ( status & GNUTLS_CERT_INSECURE_ALGORITHM )
2009-01-06 21:32:03 +03:00
VIR_ERROR0 ( _ ( " remoteCheckCertificate: the client certificate "
" uses an insecure algorithm. " ) ) ;
2007-08-07 17:02:35 +04:00
# endif
2007-06-11 16:04:54 +04:00
return - 1 ;
}
if ( gnutls_certificate_type_get ( session ) ! = GNUTLS_CRT_X509 ) {
2009-01-06 21:32:03 +03:00
VIR_ERROR0 ( _ ( " remoteCheckCertificate: certificate is not X.509 " ) ) ;
2007-06-11 16:04:54 +04:00
return - 1 ;
}
if ( ! ( certs = gnutls_certificate_get_peers ( session , & nCerts ) ) ) {
2009-01-06 21:32:03 +03:00
VIR_ERROR0 ( _ ( " remoteCheckCertificate: no peers " ) ) ;
2007-06-11 16:04:54 +04:00
return - 1 ;
}
now = time ( NULL ) ;
for ( i = 0 ; i < nCerts ; i + + ) {
gnutls_x509_crt_t cert ;
if ( gnutls_x509_crt_init ( & cert ) < 0 ) {
2009-01-06 21:32:03 +03:00
VIR_ERROR0 ( _ ( " remoteCheckCertificate: gnutls_x509_crt_init failed " ) ) ;
2007-06-11 16:04:54 +04:00
return - 1 ;
}
if ( gnutls_x509_crt_import ( cert , & certs [ i ] , GNUTLS_X509_FMT_DER ) < 0 ) {
gnutls_x509_crt_deinit ( cert ) ;
return - 1 ;
}
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 18:43:42 +03:00
2007-06-11 16:04:54 +04:00
if ( gnutls_x509_crt_get_expiration_time ( cert ) < now ) {
2009-01-06 21:32:03 +03:00
VIR_ERROR0 ( _ ( " remoteCheckCertificate: "
" the client certificate has expired " ) ) ;
2007-06-11 16:04:54 +04:00
gnutls_x509_crt_deinit ( cert ) ;
return - 1 ;
}
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 18:43:42 +03:00
2007-06-11 16:04:54 +04:00
if ( gnutls_x509_crt_get_activation_time ( cert ) > now ) {
2009-01-06 21:32:03 +03:00
VIR_ERROR0 ( _ ( " remoteCheckCertificate: the client "
" certificate is not yet activated " ) ) ;
2007-06-11 16:04:54 +04:00
gnutls_x509_crt_deinit ( cert ) ;
return - 1 ;
}
if ( i = = 0 ) {
if ( ! remoteCheckDN ( cert ) ) {
/* This is the most common error: make it informative. */
2009-01-06 21:32:03 +03:00
VIR_ERROR0 ( _ ( " remoteCheckCertificate: client's Distinguished Name is not on the list of allowed clients (tls_allowed_dn_list). Use 'openssl x509 -in clientcert.pem -text' to view the Distinguished Name field in the client certificate, or run this daemon with --verbose option. " ) ) ;
2007-06-11 16:04:54 +04:00
gnutls_x509_crt_deinit ( cert ) ;
return - 1 ;
}
}
}
return 0 ;
}
/* Check the client's access. */
static int
remoteCheckAccess ( struct qemud_client * client )
{
2009-01-20 22:25:15 +03:00
struct qemud_client_message * confirm ;
2007-06-11 16:04:54 +04:00
/* Verify client certificate. */
2007-12-05 18:27:08 +03:00
if ( remoteCheckCertificate ( client - > tlssession ) = = - 1 ) {
2009-01-06 21:32:03 +03:00
VIR_ERROR0 ( _ ( " remoteCheckCertificate: "
" failed to verify client's certificate " ) ) ;
2007-06-11 16:04:54 +04:00
if ( ! tls_no_verify_certificate ) return - 1 ;
2009-01-06 21:32:03 +03:00
else VIR_INFO0 ( _ ( " remoteCheckCertificate: tls_no_verify_certificate "
" is set so the bad certificate is ignored " ) ) ;
2007-06-11 16:04:54 +04:00
}
2009-01-20 22:25:15 +03:00
if ( client - > tx ) {
VIR_INFO ( " %s " ,
_ ( " client had unexpected data pending tx after access check " ) ) ;
return - 1 ;
}
if ( VIR_ALLOC ( confirm ) < 0 )
return - 1 ;
2007-06-11 16:04:54 +04:00
/* Checks have succeeded. Write a '\1' byte back to the client to
* indicate this ( otherwise the socket is abruptly closed ) .
* ( NB . The ' \1 ' byte is sent in an encrypted record ) .
*/
2009-01-20 22:25:15 +03:00
confirm - > async = 1 ;
confirm - > bufferLength = 1 ;
confirm - > bufferOffset = 0 ;
confirm - > buffer [ 0 ] = ' \1 ' ;
client - > tx = confirm ;
2007-06-11 16:04:54 +04:00
return 0 ;
}
2007-02-14 04:40:09 +03:00
2008-04-04 19:09:19 +04:00
# if HAVE_POLKIT
int qemudGetSocketIdentity ( int fd , uid_t * uid , pid_t * pid ) {
# ifdef SO_PEERCRED
struct ucred cr ;
unsigned int cr_len = sizeof ( cr ) ;
if ( getsockopt ( fd , SOL_SOCKET , SO_PEERCRED , & cr , & cr_len ) < 0 ) {
2009-02-05 19:28:03 +03:00
char ebuf [ 1024 ] ;
2009-01-06 21:32:03 +03:00
VIR_ERROR ( _ ( " Failed to verify client credentials: %s " ) ,
2009-02-05 19:28:03 +03:00
virStrerror ( errno , ebuf , sizeof ebuf ) ) ;
2008-04-04 19:09:19 +04:00
return - 1 ;
}
* pid = cr . pid ;
* uid = cr . uid ;
# else
/* XXX Many more OS support UNIX socket credentials we could port to. See dbus ....*/
# error "UNIX socket credentials not supported / implemented on this platform yet..."
# endif
return 0 ;
}
# endif
2009-01-20 22:25:15 +03:00
2007-02-14 04:40:09 +03:00
static int qemudDispatchServer ( struct qemud_server * server , struct qemud_socket * sock ) {
int fd ;
struct sockaddr_storage addr ;
2007-06-11 16:04:54 +04:00
socklen_t addrlen = ( socklen_t ) ( sizeof addr ) ;
2007-02-14 04:40:09 +03:00
struct qemud_client * client ;
2007-06-11 16:04:54 +04:00
int no_slow_start = 1 ;
2007-02-14 04:40:09 +03:00
if ( ( fd = accept ( sock - > fd , ( struct sockaddr * ) & addr , & addrlen ) ) < 0 ) {
2009-02-05 19:28:03 +03:00
char ebuf [ 1024 ] ;
2007-02-14 04:40:09 +03:00
if ( errno = = EAGAIN )
return 0 ;
2009-02-05 19:28:03 +03:00
VIR_ERROR ( _ ( " Failed to accept connection: %s " ) ,
virStrerror ( errno , ebuf , sizeof ebuf ) ) ;
2007-02-14 04:40:09 +03:00
return - 1 ;
}
2008-12-05 01:18:44 +03:00
if ( server - > nclients > = max_clients ) {
2009-01-20 22:25:15 +03:00
VIR_ERROR ( _ ( " Too many active clients (%d), dropping connection " ) , max_clients ) ;
2008-12-05 01:18:44 +03:00
close ( fd ) ;
return - 1 ;
}
2008-12-05 01:09:35 +03:00
if ( VIR_REALLOC_N ( server - > clients , server - > nclients + 1 ) < 0 ) {
2009-01-06 21:32:03 +03:00
VIR_ERROR0 ( _ ( " Out of memory allocating clients " ) ) ;
2008-12-05 01:09:35 +03:00
close ( fd ) ;
return - 1 ;
}
2009-01-22 20:49:41 +03:00
# ifdef __sun
{
ucred_t * ucred = NULL ;
const priv_set_t * privs ;
if ( getpeerucred ( fd , & ucred ) = = - 1 | |
( privs = ucred_getprivset ( ucred , PRIV_EFFECTIVE ) ) = = NULL ) {
if ( ucred ! = NULL )
ucred_free ( ucred ) ;
close ( fd ) ;
return - 1 ;
}
if ( ! priv_ismember ( privs , PRIV_VIRT_MANAGE ) ) {
ucred_free ( ucred ) ;
close ( fd ) ;
return - 1 ;
}
ucred_free ( ucred ) ;
}
# endif /* __sun */
2007-06-11 16:04:54 +04:00
/* Disable Nagle. Unix sockets will ignore this. */
setsockopt ( fd , IPPROTO_TCP , TCP_NODELAY , ( void * ) & no_slow_start ,
sizeof no_slow_start ) ;
2009-05-12 19:43:07 +04:00
if ( virSetCloseExec ( fd ) < 0 | |
virSetNonBlock ( fd ) < 0 ) {
2007-02-14 04:40:09 +03:00
close ( fd ) ;
return - 1 ;
}
2008-06-06 14:52:01 +04:00
if ( VIR_ALLOC ( client ) < 0 )
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 18:43:42 +03:00
goto cleanup ;
2009-01-15 22:56:05 +03:00
if ( virMutexInit ( & client - > lock ) < 0 ) {
VIR_ERROR ( " %s " , _ ( " cannot initialize mutex " ) ) ;
VIR_FREE ( client ) ;
2008-12-05 01:16:40 +03:00
goto cleanup ;
2009-01-15 22:56:05 +03:00
}
2008-12-05 01:16:40 +03:00
2007-06-11 16:04:54 +04:00
client - > magic = QEMUD_CLIENT_MAGIC ;
2007-02-14 04:40:09 +03:00
client - > fd = fd ;
client - > readonly = sock - > readonly ;
2007-12-05 18:27:08 +03:00
client - > type = sock - > type ;
2007-12-05 18:24:15 +03:00
client - > auth = sock - > auth ;
2007-06-11 16:04:54 +04:00
memcpy ( & client - > addr , & addr , sizeof addr ) ;
client - > addrlen = addrlen ;
2009-01-20 22:25:15 +03:00
/* Prepare one for packet receive */
if ( VIR_ALLOC ( client - > rx ) < 0 )
goto cleanup ;
client - > rx - > bufferLength = REMOTE_MESSAGE_HEADER_XDR_LEN ;
2008-04-04 19:09:19 +04:00
# if HAVE_POLKIT
/* Only do policy checks for non-root - allow root user
through with no checks , as a fail - safe - root can easily
change policykit policy anyway , so its pointless trying
to restrict root */
if ( client - > auth = = REMOTE_AUTH_POLKIT ) {
uid_t uid ;
pid_t pid ;
if ( qemudGetSocketIdentity ( client - > fd , & uid , & pid ) < 0 )
goto cleanup ;
2008-05-15 10:12:32 +04:00
/* Client is running as root, so disable auth */
2008-04-04 19:09:19 +04:00
if ( uid = = 0 ) {
2009-01-06 21:32:03 +03:00
VIR_INFO ( _ ( " Turn off polkit auth for privileged client %d " ) , pid ) ;
2008-04-04 19:09:19 +04:00
client - > auth = REMOTE_AUTH_NONE ;
}
}
# endif
2007-12-05 18:27:08 +03:00
if ( client - > type ! = QEMUD_SOCK_TYPE_TLS ) {
2009-01-20 22:25:15 +03:00
/* Plain socket, so prepare to read first message */
2009-07-10 15:48:50 +04:00
if ( qemudRegisterClientEvent ( server , client ) < 0 )
2007-06-26 23:11:00 +04:00
goto cleanup ;
2007-06-11 16:04:54 +04:00
} else {
int ret ;
2007-12-05 18:27:08 +03:00
client - > tlssession = remoteInitializeTLSSession ( ) ;
if ( client - > tlssession = = NULL )
2007-06-26 23:11:00 +04:00
goto cleanup ;
2007-06-11 16:04:54 +04:00
2007-12-05 18:27:08 +03:00
gnutls_transport_set_ptr ( client - > tlssession ,
2007-06-11 16:04:54 +04:00
( gnutls_transport_ptr_t ) ( long ) fd ) ;
/* Begin the TLS handshake. */
2007-12-05 18:27:08 +03:00
ret = gnutls_handshake ( client - > tlssession ) ;
2007-06-11 16:04:54 +04:00
if ( ret = = 0 ) {
2009-03-03 11:25:50 +03:00
client - > handshake = 0 ;
2007-06-11 16:04:54 +04:00
/* Unlikely, but ... Next step is to check the certificate. */
if ( remoteCheckAccess ( client ) = = - 1 )
2007-06-26 23:11:00 +04:00
goto cleanup ;
2009-01-20 22:25:15 +03:00
/* Handshake & cert check OK, so prepare to read first message */
2009-07-10 15:48:50 +04:00
if ( qemudRegisterClientEvent ( server , client ) < 0 )
2007-06-26 23:11:00 +04:00
goto cleanup ;
2007-06-11 16:04:54 +04:00
} else if ( ret = = GNUTLS_E_INTERRUPTED | | ret = = GNUTLS_E_AGAIN ) {
2009-01-20 22:25:15 +03:00
/* Most likely, need to do more handshake data */
client - > handshake = 1 ;
2007-06-26 23:11:00 +04:00
2009-07-10 15:48:50 +04:00
if ( qemudRegisterClientEvent ( server , client ) < 0 )
2007-06-26 23:11:00 +04:00
goto cleanup ;
2007-06-11 16:04:54 +04:00
} else {
2009-01-06 21:32:03 +03:00
VIR_ERROR ( _ ( " TLS handshake failed: %s " ) ,
2007-06-11 16:04:54 +04:00
gnutls_strerror ( ret ) ) ;
2007-06-26 23:11:00 +04:00
goto cleanup ;
2007-06-11 16:04:54 +04:00
}
}
2007-02-14 04:40:09 +03:00
2008-12-05 01:09:35 +03:00
server - > clients [ server - > nclients + + ] = client ;
2007-02-14 04:40:09 +03:00
2009-01-20 22:27:11 +03:00
if ( server - > nclients > server - > nactiveworkers & &
server - > nactiveworkers < server - > nworkers ) {
int i ;
for ( i = 0 ; i < server - > nworkers ; i + + ) {
if ( ! server - > workers [ i ] . hasThread ) {
if ( qemudStartWorker ( server , & server - > workers [ i ] ) < 0 )
return - 1 ;
server - > nactiveworkers + + ;
break ;
}
}
}
2007-02-14 04:40:09 +03:00
return 0 ;
2007-06-11 16:04:54 +04:00
2007-06-26 23:11:00 +04:00
cleanup :
2008-12-05 01:16:40 +03:00
if ( client & &
client - > tlssession ) gnutls_deinit ( client - > tlssession ) ;
2007-06-11 16:04:54 +04:00
close ( fd ) ;
2009-12-14 18:45:11 +03:00
if ( client )
VIR_FREE ( client - > rx ) ;
2009-01-20 22:25:15 +03:00
VIR_FREE ( client ) ;
2007-06-11 16:04:54 +04:00
return - 1 ;
2007-02-14 04:40:09 +03:00
}
2008-12-05 01:16:40 +03:00
/*
* You must hold lock for at least the client
* We don ' t free stuff here , merely disconnect the client ' s
* network socket & resources .
* We keep the libvirt connection open until any async
* jobs have finished , then clean it up elsehwere
*/
2009-01-20 22:25:15 +03:00
void qemudDispatchClientFailure ( struct qemud_client * client ) {
2009-05-29 18:34:35 +04:00
if ( client - > watch ! = - 1 ) {
virEventRemoveHandleImpl ( client - > watch ) ;
client - > watch = - 1 ;
}
2007-06-26 23:11:00 +04:00
2008-10-23 17:18:18 +04:00
/* Deregister event delivery callback */
2010-01-13 21:21:30 +03:00
if ( client - > conn & & client - > domain_events_registered ) {
2008-12-22 15:53:26 +03:00
DEBUG0 ( " Deregistering to relay remote events " ) ;
2008-10-23 17:18:18 +04:00
virConnectDomainEventDeregister ( client - > conn , remoteRelayDomainEvent ) ;
}
2007-12-05 18:24:15 +03:00
# if HAVE_SASL
2009-05-29 18:34:35 +04:00
if ( client - > saslconn ) {
sasl_dispose ( & client - > saslconn ) ;
client - > saslconn = NULL ;
}
2009-12-10 02:00:50 +03:00
VIR_FREE ( client - > saslUsername ) ;
2007-12-05 18:24:15 +03:00
# endif
2009-05-29 18:34:35 +04:00
if ( client - > tlssession ) {
gnutls_deinit ( client - > tlssession ) ;
client - > tlssession = NULL ;
}
if ( client - > fd ! = - 1 ) {
close ( client - > fd ) ;
client - > fd = - 1 ;
}
2008-12-05 01:16:40 +03:00
}
/* Caller must hold server lock */
static struct qemud_client * qemudPendingJob ( struct qemud_server * server )
{
int i ;
for ( i = 0 ; i < server - > nclients ; i + + ) {
2009-01-15 22:56:05 +03:00
virMutexLock ( & server - > clients [ i ] - > lock ) ;
2009-01-20 22:25:15 +03:00
if ( server - > clients [ i ] - > dx ) {
2008-12-05 01:16:40 +03:00
/* Delibrately don't unlock client - caller wants the lock */
return server - > clients [ i ] ;
}
2009-01-15 22:56:05 +03:00
virMutexUnlock ( & server - > clients [ i ] - > lock ) ;
2008-12-05 01:16:40 +03:00
}
return NULL ;
2007-02-14 04:40:09 +03:00
}
2008-12-05 01:16:40 +03:00
static void * qemudWorker ( void * data )
{
2009-01-20 22:27:11 +03:00
struct qemud_worker * worker = data ;
struct qemud_server * server = worker - > server ;
2008-12-05 01:16:40 +03:00
while ( 1 ) {
2009-01-20 22:25:15 +03:00
struct qemud_client * client = NULL ;
2009-07-10 15:45:37 +04:00
struct qemud_client_message * msg ;
2009-01-20 22:25:15 +03:00
2009-01-15 22:56:05 +03:00
virMutexLock ( & server - > lock ) ;
2009-01-20 22:27:11 +03:00
while ( ( ( client = qemudPendingJob ( server ) ) = = NULL ) & &
! worker - > quitRequest ) {
2009-01-15 22:56:05 +03:00
if ( virCondWait ( & server - > job , & server - > lock ) < 0 ) {
virMutexUnlock ( & server - > lock ) ;
return NULL ;
}
}
2009-01-20 22:27:11 +03:00
if ( worker - > quitRequest ) {
if ( client )
virMutexUnlock ( & client - > lock ) ;
virMutexUnlock ( & server - > lock ) ;
return NULL ;
}
worker - > processingCall = 1 ;
2009-01-15 22:56:05 +03:00
virMutexUnlock ( & server - > lock ) ;
2008-12-05 01:16:40 +03:00
/* We own a locked client now... */
client - > refs + + ;
2009-01-20 22:25:15 +03:00
/* Remove our message from dispatch queue while we use it */
2009-07-10 15:45:37 +04:00
msg = qemudClientMessageQueueServe ( & client - > dx ) ;
2009-01-20 22:25:15 +03:00
/* This function drops the lock during dispatch,
* and re - acquires it before returning */
2009-07-10 15:58:22 +04:00
if ( remoteDispatchClientRequest ( server , client , msg ) < 0 ) {
2009-07-10 15:45:37 +04:00
VIR_FREE ( msg ) ;
2009-01-20 22:25:15 +03:00
qemudDispatchClientFailure ( client ) ;
client - > refs - - ;
virMutexUnlock ( & client - > lock ) ;
continue ;
}
2008-12-05 01:16:40 +03:00
client - > refs - - ;
2009-01-15 22:56:05 +03:00
virMutexUnlock ( & client - > lock ) ;
2009-01-20 22:27:11 +03:00
virMutexLock ( & server - > lock ) ;
worker - > processingCall = 0 ;
virMutexUnlock ( & server - > lock ) ;
2008-12-05 01:16:40 +03:00
}
}
2007-02-14 04:40:09 +03:00
2009-01-20 22:27:11 +03:00
static int qemudStartWorker ( struct qemud_server * server ,
struct qemud_worker * worker ) {
pthread_attr_t attr ;
pthread_attr_init ( & attr ) ;
/* We want to join workers, so don't detach them */
/*pthread_attr_setdetachstate(&attr, 1);*/
if ( worker - > hasThread )
return - 1 ;
worker - > server = server ;
worker - > hasThread = 1 ;
worker - > quitRequest = 0 ;
worker - > processingCall = 0 ;
if ( pthread_create ( & worker - > thread ,
& attr ,
qemudWorker ,
worker ) ! = 0 ) {
worker - > hasThread = 0 ;
worker - > server = NULL ;
return - 1 ;
}
return 0 ;
}
2007-02-14 04:40:09 +03:00
2009-01-20 22:25:15 +03:00
/*
* Read data into buffer using wire decoding ( plain or TLS )
*
* Returns :
* - 1 on error or EOF
* 0 on EAGAIN
* n number of bytes
*/
static ssize_t qemudClientReadBuf ( struct qemud_client * client ,
char * data , ssize_t len ) {
ssize_t ret ;
if ( len < 0 ) {
2009-01-28 14:31:39 +03:00
VIR_ERROR ( _ ( " unexpected negative length request %lld " ) ,
( long long int ) len ) ;
2009-01-20 22:25:15 +03:00
qemudDispatchClientFailure ( client ) ;
return - 1 ;
}
2007-06-11 16:04:54 +04:00
/*qemudDebug ("qemudClientRead: len = %d", len);*/
2007-12-05 18:27:08 +03:00
if ( ! client - > tlssession ) {
2009-02-05 19:28:03 +03:00
char ebuf [ 1024 ] ;
2009-01-20 22:25:15 +03:00
ret = read ( client - > fd , data , len ) ;
if ( ret = = - 1 & & ( errno = = EAGAIN | |
errno = = EINTR ) )
return 0 ;
if ( ret < = 0 ) {
if ( ret ! = 0 )
2009-02-05 19:28:03 +03:00
VIR_ERROR ( _ ( " read: %s " ) ,
virStrerror ( errno , ebuf , sizeof ebuf ) ) ;
2009-01-20 22:25:15 +03:00
qemudDispatchClientFailure ( client ) ;
2007-06-11 16:04:54 +04:00
return - 1 ;
}
} else {
2007-12-05 18:27:08 +03:00
ret = gnutls_record_recv ( client - > tlssession , data , len ) ;
2009-01-20 22:25:15 +03:00
if ( ret < 0 & & ( ret = = GNUTLS_E_AGAIN | |
ret = = GNUTLS_E_INTERRUPTED ) )
return 0 ;
if ( ret < = 0 ) {
if ( ret ! = 0 )
VIR_ERROR ( _ ( " gnutls_record_recv: %s " ) ,
gnutls_strerror ( ret ) ) ;
qemudDispatchClientFailure ( client ) ;
2007-06-11 16:04:54 +04:00
return - 1 ;
}
2007-02-14 04:40:09 +03:00
}
2007-06-11 16:04:54 +04:00
2007-12-05 18:27:08 +03:00
return ret ;
}
2009-01-20 22:25:15 +03:00
/*
* Read data into buffer without decoding
*
* Returns :
* - 1 on error or EOF
* 0 on EAGAIN
* n number of bytes
*/
static ssize_t qemudClientReadPlain ( struct qemud_client * client ) {
ssize_t ret ;
ret = qemudClientReadBuf ( client ,
client - > rx - > buffer + client - > rx - > bufferOffset ,
client - > rx - > bufferLength - client - > rx - > bufferOffset ) ;
if ( ret < = 0 )
return ret ; /* -1 error, 0 eagain */
client - > rx - > bufferOffset + = ret ;
return ret ;
2007-02-14 04:40:09 +03:00
}
2007-12-05 18:27:08 +03:00
# if HAVE_SASL
2009-01-20 22:25:15 +03:00
/*
* Read data into buffer decoding with SASL
*
* Returns :
* - 1 on error or EOF
* 0 on EAGAIN
* n number of bytes
*/
static ssize_t qemudClientReadSASL ( struct qemud_client * client ) {
ssize_t got , want ;
2007-12-05 18:27:08 +03:00
/* We're doing a SSF data read, so now its times to ensure
* future writes are under SSF too .
*
* cf remoteSASLCheckSSF in remote . c
*/
client - > saslSSF | = QEMUD_SASL_SSF_WRITE ;
/* Need to read some more data off the wire */
if ( client - > saslDecoded = = NULL ) {
2009-01-20 22:25:15 +03:00
int ret ;
2007-12-05 18:27:08 +03:00
char encoded [ 8192 ] ;
2009-01-20 22:25:15 +03:00
ssize_t encodedLen = sizeof ( encoded ) ;
encodedLen = qemudClientReadBuf ( client , encoded , encodedLen ) ;
if ( encodedLen < = 0 )
return encodedLen ;
ret = sasl_decode ( client - > saslconn , encoded , encodedLen ,
& client - > saslDecoded , & client - > saslDecodedLength ) ;
if ( ret ! = SASL_OK ) {
VIR_ERROR ( _ ( " failed to decode SASL data %s " ) ,
sasl_errstring ( ret , NULL , NULL ) ) ;
qemudDispatchClientFailure ( client ) ;
2007-12-05 18:27:08 +03:00
return - 1 ;
2009-01-20 22:25:15 +03:00
}
2007-12-05 18:27:08 +03:00
client - > saslDecodedOffset = 0 ;
}
/* Some buffered decoded data to return now */
got = client - > saslDecodedLength - client - > saslDecodedOffset ;
2009-01-20 22:25:15 +03:00
want = client - > rx - > bufferLength - client - > rx - > bufferOffset ;
2007-12-05 18:27:08 +03:00
if ( want > got )
want = got ;
2009-01-20 22:25:15 +03:00
memcpy ( client - > rx - > buffer + client - > rx - > bufferOffset ,
2007-12-05 18:27:08 +03:00
client - > saslDecoded + client - > saslDecodedOffset , want ) ;
client - > saslDecodedOffset + = want ;
2009-01-20 22:25:15 +03:00
client - > rx - > bufferOffset + = want ;
2007-12-05 18:27:08 +03:00
if ( client - > saslDecodedOffset = = client - > saslDecodedLength ) {
client - > saslDecoded = NULL ;
client - > saslDecodedOffset = client - > saslDecodedLength = 0 ;
}
2009-01-20 22:25:15 +03:00
return want ;
2007-12-05 18:27:08 +03:00
}
# endif
2009-01-20 22:25:15 +03:00
/*
* Read as much data off wire as possible till we fill our
* buffer , or would block on I / O
*/
static ssize_t qemudClientRead ( struct qemud_client * client ) {
2007-12-05 18:27:08 +03:00
# if HAVE_SASL
if ( client - > saslSSF & QEMUD_SASL_SSF_READ )
2009-01-20 22:25:15 +03:00
return qemudClientReadSASL ( client ) ;
2007-12-05 18:27:08 +03:00
else
# endif
2009-01-20 22:25:15 +03:00
return qemudClientReadPlain ( client ) ;
2007-12-05 18:27:08 +03:00
}
2009-01-20 22:25:15 +03:00
/*
* Read data until we get a complete message to process
*/
static void qemudDispatchClientRead ( struct qemud_server * server ,
struct qemud_client * client ) {
2007-06-11 16:04:54 +04:00
/*qemudDebug ("qemudDispatchClientRead: mode = %d", client->mode);*/
2007-02-14 04:40:09 +03:00
2009-01-20 22:25:15 +03:00
readmore :
if ( qemudClientRead ( client ) < 0 )
return ; /* Error */
2007-06-11 16:04:54 +04:00
2009-01-20 22:25:15 +03:00
if ( client - > rx - > bufferOffset < client - > rx - > bufferLength )
return ; /* Still not read enough */
2007-06-11 16:04:54 +04:00
2009-01-20 22:25:15 +03:00
/* Either done with length word header */
if ( client - > rx - > bufferLength = = REMOTE_MESSAGE_HEADER_XDR_LEN ) {
unsigned int len ;
XDR x ;
2007-06-11 16:04:54 +04:00
2009-01-20 22:25:15 +03:00
xdrmem_create ( & x , client - > rx - > buffer , client - > rx - > bufferLength , XDR_DECODE ) ;
2007-06-11 16:04:54 +04:00
2007-11-17 14:17:48 +03:00
if ( ! xdr_u_int ( & x , & len ) ) {
xdr_destroy ( & x ) ;
2008-12-22 15:53:26 +03:00
DEBUG0 ( " Failed to decode packet length " ) ;
2009-01-20 22:25:15 +03:00
qemudDispatchClientFailure ( client ) ;
2007-02-14 04:40:09 +03:00
return ;
}
2007-11-17 14:17:48 +03:00
xdr_destroy ( & x ) ;
2007-06-11 16:04:54 +04:00
2009-01-20 22:25:15 +03:00
if ( len < REMOTE_MESSAGE_HEADER_XDR_LEN ) {
DEBUG ( " Packet length %u too small " , len ) ;
qemudDispatchClientFailure ( client ) ;
2007-06-11 16:04:54 +04:00
return ;
2007-02-14 04:40:09 +03:00
}
2007-06-11 16:04:54 +04:00
2009-01-20 22:25:15 +03:00
/* Length includes the size of the length word itself */
len - = REMOTE_MESSAGE_HEADER_XDR_LEN ;
if ( len > REMOTE_MESSAGE_MAX ) {
DEBUG ( " Packet length %u too large " , len ) ;
qemudDispatchClientFailure ( client ) ;
2007-06-11 16:04:54 +04:00
return ;
}
2009-01-20 22:25:15 +03:00
/* Prepare to read rest of message */
client - > rx - > bufferLength + = len ;
2007-06-11 16:04:54 +04:00
2009-07-10 15:48:50 +04:00
qemudUpdateClientEvent ( client ) ;
2007-06-26 23:11:00 +04:00
2009-01-20 22:25:15 +03:00
/* Try and read payload immediately instead of going back
into poll ( ) because chances are the data is already
waiting for us */
goto readmore ;
} else {
2009-07-10 15:58:22 +04:00
/* Grab the completed message */
struct qemud_client_message * msg = qemudClientMessageQueueServe ( & client - > rx ) ;
struct qemud_client_filter * filter ;
/* Decode the header so we can use it for routing decisions */
if ( remoteDecodeClientMessageHeader ( msg ) < 0 ) {
VIR_FREE ( msg ) ;
qemudDispatchClientFailure ( client ) ;
}
/* Check if any filters match this message */
filter = client - > filters ;
while ( filter ) {
2009-07-10 16:06:36 +04:00
int ret ;
ret = ( filter - > query ) ( client , msg , filter - > opaque ) ;
if ( ret = = 1 ) {
2009-07-10 15:58:22 +04:00
msg = NULL ;
break ;
2009-07-10 16:06:36 +04:00
} else if ( ret = = - 1 ) {
VIR_FREE ( msg ) ;
qemudDispatchClientFailure ( client ) ;
return ;
2009-07-10 15:58:22 +04:00
}
filter = filter - > next ;
}
2009-01-20 22:25:15 +03:00
/* Move completed message to the end of the dispatch queue */
2009-07-10 15:58:22 +04:00
if ( msg )
qemudClientMessageQueuePush ( & client - > dx , msg ) ;
2009-01-20 22:25:15 +03:00
client - > nrequests + + ;
/* Possibly need to create another receive buffer */
if ( ( client - > nrequests < max_client_requests & &
VIR_ALLOC ( client - > rx ) < 0 ) ) {
qemudDispatchClientFailure ( client ) ;
2007-06-26 23:11:00 +04:00
} else {
2009-01-20 22:25:15 +03:00
if ( client - > rx )
client - > rx - > bufferLength = REMOTE_MESSAGE_HEADER_XDR_LEN ;
2009-07-10 15:48:50 +04:00
qemudUpdateClientEvent ( client ) ;
/* Tell one of the workers to get on with it... */
virCondSignal ( & server - > job ) ;
2007-06-26 23:11:00 +04:00
}
2007-02-14 04:40:09 +03:00
}
}
2009-01-20 22:25:15 +03:00
/*
* Send a chunk of data using wire encoding ( plain or TLS )
*
* Returns :
* - 1 on error
* 0 on EAGAIN
* n number of bytes
*/
static ssize_t qemudClientWriteBuf ( struct qemud_client * client ,
const char * data , ssize_t len ) {
ssize_t ret ;
if ( len < 0 ) {
2009-01-28 14:31:39 +03:00
VIR_ERROR ( _ ( " unexpected negative length request %lld " ) ,
( long long int ) len ) ;
2009-01-20 22:25:15 +03:00
qemudDispatchClientFailure ( client ) ;
return - 1 ;
}
2007-12-05 18:27:08 +03:00
if ( ! client - > tlssession ) {
2009-02-05 19:28:03 +03:00
char ebuf [ 1024 ] ;
2009-01-20 22:25:15 +03:00
if ( ( ret = write ( client - > fd , data , len ) ) = = - 1 ) {
if ( errno = = EAGAIN | | errno = = EINTR )
return 0 ;
2009-02-05 19:28:03 +03:00
VIR_ERROR ( _ ( " write: %s " ) , virStrerror ( errno , ebuf , sizeof ebuf ) ) ;
2009-01-20 22:25:15 +03:00
qemudDispatchClientFailure ( client ) ;
2007-06-11 16:04:54 +04:00
return - 1 ;
}
} else {
2007-12-05 18:27:08 +03:00
ret = gnutls_record_send ( client - > tlssession , data , len ) ;
2009-01-20 22:25:15 +03:00
if ( ret < 0 ) {
if ( ret = = GNUTLS_E_INTERRUPTED | |
ret = = GNUTLS_E_AGAIN )
return 0 ;
VIR_ERROR ( _ ( " gnutls_record_send: %s " ) , gnutls_strerror ( ret ) ) ;
qemudDispatchClientFailure ( client ) ;
2007-06-11 16:04:54 +04:00
return - 1 ;
}
2007-02-14 04:40:09 +03:00
}
2007-12-05 18:27:08 +03:00
return ret ;
}
2007-06-11 16:04:54 +04:00
2007-12-05 18:27:08 +03:00
2009-01-20 22:25:15 +03:00
/*
* Send client - > tx using no encoding
*
* Returns :
* - 1 on error or EOF
* 0 on EAGAIN
* n number of bytes
*/
static int qemudClientWritePlain ( struct qemud_client * client ) {
int ret = qemudClientWriteBuf ( client ,
client - > tx - > buffer + client - > tx - > bufferOffset ,
client - > tx - > bufferLength - client - > tx - > bufferOffset ) ;
if ( ret < = 0 )
return ret ; /* -1 error, 0 = egain */
client - > tx - > bufferOffset + = ret ;
return ret ;
2007-02-14 04:40:09 +03:00
}
2007-12-05 18:27:08 +03:00
# if HAVE_SASL
2009-01-20 22:25:15 +03:00
/*
* Send client - > tx using SASL encoding
*
* Returns :
* - 1 on error
* 0 on EAGAIN
* n number of bytes
*/
static int qemudClientWriteSASL ( struct qemud_client * client ) {
2007-12-05 18:27:08 +03:00
int ret ;
/* Not got any pending encoded data, so we need to encode raw stuff */
if ( client - > saslEncoded = = NULL ) {
2009-01-20 22:25:15 +03:00
ret = sasl_encode ( client - > saslconn ,
client - > tx - > buffer + client - > tx - > bufferOffset ,
client - > tx - > bufferLength - client - > tx - > bufferOffset ,
2007-12-05 18:27:08 +03:00
& client - > saslEncoded ,
& client - > saslEncodedLength ) ;
2009-01-20 22:25:15 +03:00
if ( ret ! = SASL_OK ) {
VIR_ERROR ( _ ( " failed to encode SASL data %s " ) ,
sasl_errstring ( ret , NULL , NULL ) ) ;
qemudDispatchClientFailure ( client ) ;
return - 1 ;
}
2007-12-05 18:27:08 +03:00
client - > saslEncodedOffset = 0 ;
}
/* Send some of the encoded stuff out on the wire */
2009-01-20 22:25:15 +03:00
ret = qemudClientWriteBuf ( client ,
2007-12-05 18:27:08 +03:00
client - > saslEncoded + client - > saslEncodedOffset ,
client - > saslEncodedLength - client - > saslEncodedOffset ) ;
2009-01-20 22:25:15 +03:00
if ( ret < = 0 )
return ret ; /* -1 error, 0 == egain */
2007-12-05 18:27:08 +03:00
/* Note how much we sent */
client - > saslEncodedOffset + = ret ;
/* Sent all encoded, so update raw buffer to indicate completion */
if ( client - > saslEncodedOffset = = client - > saslEncodedLength ) {
client - > saslEncoded = NULL ;
client - > saslEncodedOffset = client - > saslEncodedLength = 0 ;
2009-01-20 22:25:15 +03:00
/* Mark as complete, so caller detects completion */
client - > tx - > bufferOffset = client - > tx - > bufferLength ;
2007-12-05 18:27:08 +03:00
}
2009-01-20 22:25:15 +03:00
return ret ;
2007-12-05 18:27:08 +03:00
}
# endif
2009-01-20 22:25:15 +03:00
/*
* Send as much data in the client - > tx as possible
*
* Returns :
* - 1 on error or EOF
* 0 on EAGAIN
* n number of bytes
*/
static ssize_t qemudClientWrite ( struct qemud_client * client ) {
2007-12-05 18:27:08 +03:00
# if HAVE_SASL
if ( client - > saslSSF & QEMUD_SASL_SSF_WRITE )
2009-01-20 22:25:15 +03:00
return qemudClientWriteSASL ( client ) ;
2007-12-05 18:27:08 +03:00
else
# endif
2009-01-20 22:25:15 +03:00
return qemudClientWritePlain ( client ) ;
2007-12-05 18:27:08 +03:00
}
2009-07-10 16:06:36 +04:00
void
qemudClientMessageRelease ( struct qemud_client * client ,
struct qemud_client_message * msg )
{
2009-08-24 23:57:16 +04:00
if ( msg - > streamTX ) {
remoteStreamMessageFinished ( client , msg ) ;
} else if ( ! msg - > async )
2009-07-10 16:06:36 +04:00
client - > nrequests - - ;
/* See if the recv queue is currently throttled */
if ( ! client - > rx & &
client - > nrequests < max_client_requests ) {
/* Reset message record for next RX attempt */
memset ( msg , 0 , sizeof ( * msg ) ) ;
client - > rx = msg ;
/* Get ready to receive next message */
client - > rx - > bufferLength = REMOTE_MESSAGE_HEADER_XDR_LEN ;
} else {
VIR_FREE ( msg ) ;
}
qemudUpdateClientEvent ( client ) ;
}
2009-01-20 22:25:15 +03:00
/*
* Process all queued client - > tx messages until
* we would block on I / O
*/
static void
2009-07-10 15:48:50 +04:00
qemudDispatchClientWrite ( struct qemud_client * client ) {
2009-01-20 22:25:15 +03:00
while ( client - > tx ) {
ssize_t ret ;
2007-06-11 16:04:54 +04:00
2009-01-20 22:25:15 +03:00
ret = qemudClientWrite ( client ) ;
if ( ret < 0 ) {
qemudDispatchClientFailure ( client ) ;
return ;
}
if ( ret = = 0 )
return ; /* Would block on write EAGAIN */
if ( client - > tx - > bufferOffset = = client - > tx - > bufferLength ) {
struct qemud_client_message * reply ;
/* Get finished reply from head of tx queue */
reply = qemudClientMessageQueueServe ( & client - > tx ) ;
2009-07-10 16:06:36 +04:00
qemudClientMessageRelease ( client , reply ) ;
2007-06-11 16:04:54 +04:00
2009-07-10 15:48:50 +04:00
if ( client - > closing )
qemudDispatchClientFailure ( client ) ;
2009-01-20 22:25:15 +03:00
}
2007-06-11 16:04:54 +04:00
}
2009-01-20 22:25:15 +03:00
}
2007-06-11 16:04:54 +04:00
2009-01-20 22:25:15 +03:00
static void
2009-07-10 15:48:50 +04:00
qemudDispatchClientHandshake ( struct qemud_client * client ) {
2009-01-20 22:25:15 +03:00
int ret ;
/* Continue the handshake. */
ret = gnutls_handshake ( client - > tlssession ) ;
if ( ret = = 0 ) {
2009-03-03 11:25:50 +03:00
client - > handshake = 0 ;
2009-01-20 22:25:15 +03:00
/* Finished. Next step is to check the certificate. */
if ( remoteCheckAccess ( client ) = = - 1 )
qemudDispatchClientFailure ( client ) ;
2009-07-10 15:48:50 +04:00
else
qemudUpdateClientEvent ( client ) ;
2009-01-20 22:25:15 +03:00
} else if ( ret = = GNUTLS_E_AGAIN | |
ret = = GNUTLS_E_INTERRUPTED ) {
/* Carry on waiting for more handshake. Update
the events just in case handshake data flow
direction has changed */
2009-07-10 15:48:50 +04:00
qemudUpdateClientEvent ( client ) ;
2009-01-20 22:25:15 +03:00
} else {
/* Fatal error in handshake */
VIR_ERROR ( _ ( " TLS handshake failed: %s " ) ,
gnutls_strerror ( ret ) ) ;
qemudDispatchClientFailure ( client ) ;
2007-02-14 04:40:09 +03:00
}
}
2008-10-23 17:18:18 +04:00
static void
2008-11-19 19:19:36 +03:00
qemudDispatchClientEvent ( int watch , int fd , int events , void * opaque ) {
2007-06-26 23:11:00 +04:00
struct qemud_server * server = ( struct qemud_server * ) opaque ;
2008-12-05 01:09:35 +03:00
struct qemud_client * client = NULL ;
int i ;
2007-02-23 11:39:49 +03:00
2009-01-15 22:56:05 +03:00
virMutexLock ( & server - > lock ) ;
2008-12-05 01:16:40 +03:00
2008-12-05 01:09:35 +03:00
for ( i = 0 ; i < server - > nclients ; i + + ) {
2009-01-20 22:25:15 +03:00
virMutexLock ( & server - > clients [ i ] - > lock ) ;
2008-12-05 01:09:35 +03:00
if ( server - > clients [ i ] - > watch = = watch ) {
client = server - > clients [ i ] ;
2007-06-26 23:11:00 +04:00
break ;
2008-12-05 01:09:35 +03:00
}
2009-01-20 22:25:15 +03:00
virMutexUnlock ( & server - > clients [ i ] - > lock ) ;
2007-06-26 23:11:00 +04:00
}
2007-06-11 16:04:54 +04:00
2009-01-20 22:25:15 +03:00
virMutexUnlock ( & server - > lock ) ;
2008-12-05 01:16:40 +03:00
if ( ! client ) {
2007-06-26 23:11:00 +04:00
return ;
2008-12-05 01:16:40 +03:00
}
2009-01-20 22:25:15 +03:00
if ( client - > fd ! = fd ) {
virMutexUnlock ( & client - > lock ) ;
2008-11-19 19:19:36 +03:00
return ;
2009-01-20 22:25:15 +03:00
}
if ( events & ( VIR_EVENT_HANDLE_WRITABLE |
VIR_EVENT_HANDLE_READABLE ) ) {
if ( client - > handshake ) {
2009-07-10 15:48:50 +04:00
qemudDispatchClientHandshake ( client ) ;
2009-01-20 22:25:15 +03:00
} else {
if ( events & VIR_EVENT_HANDLE_WRITABLE )
2009-07-10 15:48:50 +04:00
qemudDispatchClientWrite ( client ) ;
2009-01-20 22:25:15 +03:00
if ( events & VIR_EVENT_HANDLE_READABLE )
qemudDispatchClientRead ( server , client ) ;
}
}
/* NB, will get HANGUP + READABLE at same time upon
* disconnect */
if ( events & ( VIR_EVENT_HANDLE_ERROR |
VIR_EVENT_HANDLE_HANGUP ) )
qemudDispatchClientFailure ( client ) ;
2008-11-19 19:19:36 +03:00
2009-01-15 22:56:05 +03:00
virMutexUnlock ( & client - > lock ) ;
2007-06-26 23:11:00 +04:00
}
2009-07-10 15:48:50 +04:00
/*
* @ client : a locked client object
*/
static int
qemudCalculateHandleMode ( struct qemud_client * client ) {
2009-01-20 22:25:15 +03:00
int mode = 0 ;
if ( client - > handshake ) {
2007-12-05 18:27:08 +03:00
if ( gnutls_record_get_direction ( client - > tlssession ) = = 0 )
2009-01-20 22:25:15 +03:00
mode | = VIR_EVENT_HANDLE_READABLE ;
2007-12-05 18:27:08 +03:00
else
2009-01-20 22:25:15 +03:00
mode | = VIR_EVENT_HANDLE_WRITABLE ;
} else {
/* If there is a message on the rx queue then
* we ' re wanting more input */
if ( client - > rx )
mode | = VIR_EVENT_HANDLE_READABLE ;
2008-12-05 01:16:40 +03:00
2009-01-20 22:25:15 +03:00
/* If there are one or more messages to send back to client,
then monitor for writability on socket */
if ( client - > tx )
mode | = VIR_EVENT_HANDLE_WRITABLE ;
2007-12-05 18:27:08 +03:00
}
2009-07-10 15:48:50 +04:00
return mode ;
}
/*
* @ server : a locked or unlocked server object
* @ client : a locked client object
*/
int qemudRegisterClientEvent ( struct qemud_server * server ,
struct qemud_client * client ) {
int mode ;
mode = qemudCalculateHandleMode ( client ) ;
if ( ( client - > watch = virEventAddHandleImpl ( client - > fd ,
mode ,
qemudDispatchClientEvent ,
server , NULL ) ) < 0 )
return - 1 ;
2007-06-26 23:11:00 +04:00
return 0 ;
}
2009-07-10 15:48:50 +04:00
/*
* @ client : a locked client object
*/
void qemudUpdateClientEvent ( struct qemud_client * client ) {
int mode ;
mode = qemudCalculateHandleMode ( client ) ;
virEventUpdateHandleImpl ( client - > watch , mode ) ;
}
2008-10-23 17:18:18 +04:00
static void
2008-11-19 19:19:36 +03:00
qemudDispatchServerEvent ( int watch , int fd , int events , void * opaque ) {
2007-06-26 23:11:00 +04:00
struct qemud_server * server = ( struct qemud_server * ) opaque ;
2008-12-05 01:16:40 +03:00
struct qemud_socket * sock ;
2009-01-15 22:56:05 +03:00
virMutexLock ( & server - > lock ) ;
2008-12-05 01:16:40 +03:00
sock = server - > sockets ;
2007-06-26 23:11:00 +04:00
2007-03-05 20:15:20 +03:00
while ( sock ) {
2008-11-19 19:19:36 +03:00
if ( sock - > watch = = watch )
2007-06-26 23:11:00 +04:00
break ;
sock = sock - > next ;
2007-03-05 20:15:20 +03:00
}
2007-02-14 04:40:09 +03:00
2008-12-05 01:16:40 +03:00
if ( sock & & sock - > fd = = fd & & events )
2007-06-26 23:11:00 +04:00
qemudDispatchServer ( server , sock ) ;
2008-12-05 01:16:40 +03:00
2009-01-15 22:56:05 +03:00
virMutexUnlock ( & server - > lock ) ;
2007-06-26 23:11:00 +04:00
}
2007-06-27 00:51:00 +04:00
static int qemudOneLoop ( void ) {
2007-03-27 14:28:45 +04:00
sig_atomic_t errors ;
2007-02-14 04:40:09 +03:00
2007-06-26 23:11:00 +04:00
if ( virEventRunOnce ( ) < 0 )
2007-02-14 04:40:09 +03:00
return - 1 ;
2007-03-27 14:28:45 +04:00
/* Check for any signal handling errors and log them. */
errors = sig_errors ;
if ( errors ) {
2009-02-05 19:28:03 +03:00
char ebuf [ 1024 ] ;
2007-03-27 14:28:45 +04:00
sig_errors - = errors ;
2009-01-06 21:32:03 +03:00
VIR_ERROR ( _ ( " Signal handler reported %d errors: last error: %s " ) ,
2009-02-05 19:28:03 +03:00
errors , virStrerror ( sig_lasterrno , ebuf , sizeof ebuf ) ) ;
2007-03-27 14:28:45 +04:00
return - 1 ;
}
2007-02-14 04:40:09 +03:00
return 0 ;
}
2009-02-06 17:43:52 +03:00
static void qemudInactiveTimer ( int timerid , void * data ) {
2007-06-27 02:56:14 +04:00
struct qemud_server * server = ( struct qemud_server * ) data ;
2009-02-06 17:43:52 +03:00
if ( virStateActive ( ) | |
server - > clients ) {
DEBUG0 ( " Timer expired but still active, not shutting down " ) ;
virEventUpdateTimeoutImpl ( timerid , - 1 ) ;
} else {
DEBUG0 ( " Timer expired and inactive, shutting down " ) ;
2009-10-16 19:34:37 +04:00
server - > quitEventThread = 1 ;
2007-06-27 02:56:14 +04:00
}
}
2009-01-20 22:25:15 +03:00
static void qemudFreeClient ( struct qemud_client * client ) {
while ( client - > rx ) {
struct qemud_client_message * msg
= qemudClientMessageQueueServe ( & client - > rx ) ;
VIR_FREE ( msg ) ;
}
while ( client - > dx ) {
struct qemud_client_message * msg
= qemudClientMessageQueueServe ( & client - > dx ) ;
VIR_FREE ( msg ) ;
}
while ( client - > tx ) {
struct qemud_client_message * msg
= qemudClientMessageQueueServe ( & client - > tx ) ;
VIR_FREE ( msg ) ;
}
2009-07-10 16:06:36 +04:00
while ( client - > streams )
remoteRemoveClientStream ( client , client - > streams ) ;
2009-01-20 22:25:15 +03:00
if ( client - > conn )
virConnectClose ( client - > conn ) ;
virMutexDestroy ( & client - > lock ) ;
VIR_FREE ( client ) ;
}
2009-10-16 19:34:37 +04:00
static void * qemudRunLoop ( void * opaque ) {
struct qemud_server * server = opaque ;
2007-06-27 02:56:14 +04:00
int timerid = - 1 ;
2009-10-16 19:34:37 +04:00
int i ;
2009-02-06 17:43:52 +03:00
int timerActive = 0 ;
2008-12-05 01:16:40 +03:00
2009-01-15 22:56:05 +03:00
virMutexLock ( & server - > lock ) ;
2008-12-05 01:16:40 +03:00
2009-02-06 17:43:52 +03:00
if ( timeout > 0 & &
( timerid = virEventAddTimeoutImpl ( - 1 ,
qemudInactiveTimer ,
server , NULL ) ) < 0 ) {
VIR_ERROR0 ( _ ( " Failed to register shutdown timeout " ) ) ;
2009-10-16 19:34:37 +04:00
return NULL ;
2009-02-06 17:43:52 +03:00
}
2009-01-20 22:27:11 +03:00
if ( min_workers > max_workers )
max_workers = min_workers ;
server - > nworkers = max_workers ;
2008-12-05 01:16:40 +03:00
if ( VIR_ALLOC_N ( server - > workers , server - > nworkers ) < 0 ) {
2009-01-06 21:32:03 +03:00
VIR_ERROR0 ( _ ( " Failed to allocate workers " ) ) ;
2009-10-16 19:34:37 +04:00
return NULL ;
2008-12-05 01:16:40 +03:00
}
2009-01-20 22:27:11 +03:00
for ( i = 0 ; i < min_workers ; i + + ) {
if ( qemudStartWorker ( server , & server - > workers [ i ] ) < 0 )
goto cleanup ;
server - > nactiveworkers + + ;
2008-12-05 01:16:40 +03:00
}
2007-06-27 02:56:14 +04:00
2009-10-16 19:34:37 +04:00
for ( ; ! server - > quitEventThread ; ) {
2007-06-27 02:56:14 +04:00
/* A shutdown timeout is specified, so check
* if any drivers have active state , if not
* shutdown after timeout seconds
*/
2009-02-06 17:43:52 +03:00
if ( timeout > 0 ) {
if ( timerActive ) {
if ( server - > clients ) {
DEBUG ( " Deactivating shutdown timer %d " , timerid ) ;
virEventUpdateTimeoutImpl ( timerid , - 1 ) ;
timerActive = 0 ;
}
} else {
if ( ! virStateActive ( ) & &
! server - > clients ) {
DEBUG ( " Activating shutdown timer %d " , timerid ) ;
virEventUpdateTimeoutImpl ( timerid , timeout * 1000 ) ;
timerActive = 1 ;
}
}
2007-06-27 02:56:14 +04:00
}
2009-01-15 22:56:05 +03:00
virMutexUnlock ( & server - > lock ) ;
2009-01-20 22:25:15 +03:00
if ( qemudOneLoop ( ) < 0 ) {
virMutexLock ( & server - > lock ) ;
DEBUG0 ( " Loop iteration error, exiting \n " ) ;
2007-06-27 02:56:14 +04:00
break ;
2009-01-20 22:25:15 +03:00
}
2009-01-15 22:56:05 +03:00
virMutexLock ( & server - > lock ) ;
2008-12-05 01:16:40 +03:00
reprocess :
for ( i = 0 ; i < server - > nclients ; i + + ) {
int inactive ;
2009-01-15 22:56:05 +03:00
virMutexLock ( & server - > clients [ i ] - > lock ) ;
2008-12-05 01:16:40 +03:00
inactive = server - > clients [ i ] - > fd = = - 1
& & server - > clients [ i ] - > refs = = 0 ;
2009-01-15 22:56:05 +03:00
virMutexUnlock ( & server - > clients [ i ] - > lock ) ;
2008-12-05 01:16:40 +03:00
if ( inactive ) {
2009-01-20 22:25:15 +03:00
qemudFreeClient ( server - > clients [ i ] ) ;
2008-12-05 01:16:40 +03:00
server - > nclients - - ;
2009-01-20 22:25:15 +03:00
if ( i < server - > nclients )
2008-12-05 01:16:40 +03:00
memmove ( server - > clients + i ,
server - > clients + i + 1 ,
2009-01-20 22:25:15 +03:00
sizeof ( * server - > clients ) * ( server - > nclients - i ) ) ;
if ( VIR_REALLOC_N ( server - > clients ,
server - > nclients ) < 0 ) {
; /* ignore */
2008-12-05 01:16:40 +03:00
}
2009-01-20 22:25:15 +03:00
goto reprocess ;
2008-12-05 01:16:40 +03:00
}
}
2007-02-14 04:40:09 +03:00
2009-01-20 22:27:11 +03:00
/* If number of active workers exceeds both the min_workers
* threshold and the number of clients , then kill some
* off */
for ( i = 0 ; ( i < server - > nworkers & &
server - > nactiveworkers > server - > nclients & &
server - > nactiveworkers > min_workers ) ; i + + ) {
if ( server - > workers [ i ] . hasThread & &
! server - > workers [ i ] . processingCall ) {
server - > workers [ i ] . quitRequest = 1 ;
virCondBroadcast ( & server - > job ) ;
virMutexUnlock ( & server - > lock ) ;
pthread_join ( server - > workers [ i ] . thread , NULL ) ;
virMutexLock ( & server - > lock ) ;
server - > workers [ i ] . hasThread = 0 ;
server - > nactiveworkers - - ;
}
}
2007-06-27 02:56:14 +04:00
}
2009-01-20 22:27:11 +03:00
cleanup :
2008-12-05 01:16:40 +03:00
for ( i = 0 ; i < server - > nworkers ; i + + ) {
2009-01-20 22:27:11 +03:00
if ( ! server - > workers [ i ] . hasThread )
continue ;
server - > workers [ i ] . quitRequest = 1 ;
virCondBroadcast ( & server - > job ) ;
2009-01-15 22:56:05 +03:00
virMutexUnlock ( & server - > lock ) ;
2009-01-20 22:27:11 +03:00
pthread_join ( server - > workers [ i ] . thread , NULL ) ;
2009-01-15 22:56:05 +03:00
virMutexLock ( & server - > lock ) ;
2009-01-20 22:27:11 +03:00
server - > workers [ i ] . hasThread = 0 ;
2008-12-05 01:16:40 +03:00
}
2009-01-20 22:25:15 +03:00
VIR_FREE ( server - > workers ) ;
2008-12-05 01:16:40 +03:00
2009-01-15 22:56:05 +03:00
virMutexUnlock ( & server - > lock ) ;
2009-10-16 19:34:37 +04:00
return NULL ;
2007-02-14 04:40:09 +03:00
}
2009-10-16 19:34:37 +04:00
static int qemudStartEventLoop ( struct qemud_server * server ) {
pthread_attr_t attr ;
pthread_attr_init ( & attr ) ;
/* We want to join the eventloop, so don't detach it */
/*pthread_attr_setdetachstate(&attr, 1);*/
if ( pthread_create ( & server - > eventThread ,
& attr ,
qemudRunLoop ,
server ) ! = 0 )
return - 1 ;
server - > hasEventThread = 1 ;
return 0 ;
}
2007-02-14 04:40:09 +03:00
static void qemudCleanup ( struct qemud_server * server ) {
2007-02-20 20:51:41 +03:00
struct qemud_socket * sock ;
2009-10-16 14:48:50 +04:00
if ( server - > sigread ! = - 1 )
close ( server - > sigread ) ;
if ( server - > sigwrite ! = - 1 )
close ( server - > sigwrite ) ;
2007-02-20 20:51:41 +03:00
sock = server - > sockets ;
2007-02-14 04:40:09 +03:00
while ( sock ) {
2007-02-20 20:51:41 +03:00
struct qemud_socket * next = sock - > next ;
2009-10-16 14:24:01 +04:00
if ( sock - > watch )
virEventRemoveHandleImpl ( sock - > watch ) ;
2007-02-14 04:40:09 +03:00
close ( sock - > fd ) ;
2009-12-10 02:00:50 +03:00
VIR_FREE ( sock ) ;
2007-02-20 20:51:41 +03:00
sock = next ;
2007-02-14 04:40:09 +03:00
}
2009-12-10 02:00:50 +03:00
VIR_FREE ( server - > logDir ) ;
2007-02-20 20:51:41 +03:00
2007-12-05 22:25:44 +03:00
# ifdef HAVE_SASL
2007-12-05 18:34:05 +03:00
if ( server - > saslUsernameWhitelist ) {
char * * list = server - > saslUsernameWhitelist ;
while ( * list ) {
2009-12-10 02:00:50 +03:00
VIR_FREE ( * list ) ;
2007-12-05 18:34:05 +03:00
list + + ;
}
2009-12-10 02:00:50 +03:00
VIR_FREE ( server - > saslUsernameWhitelist ) ;
2007-12-05 18:34:05 +03:00
}
2007-12-05 22:25:44 +03:00
# endif
2007-02-20 20:51:41 +03:00
2009-10-16 14:24:01 +04:00
# if HAVE_POLKIT0
if ( server - > sysbus )
dbus_connection_unref ( server - > sysbus ) ;
# endif
2007-06-27 02:56:14 +04:00
virStateCleanup ( ) ;
2007-06-11 16:04:54 +04:00
2009-01-15 22:56:05 +03:00
if ( virCondDestroy ( & server - > job ) < 0 ) {
;
}
virMutexDestroy ( & server - > lock ) ;
VIR_FREE ( server ) ;
2007-02-14 04:40:09 +03:00
}
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 18:43:42 +03:00
/* Allocate an array of malloc'd strings from the config file, filename
* ( used only in diagnostics ) , using handle " conf " . Upon error , return - 1
* and free any allocated memory . Otherwise , save the array in * list_arg
* and return 0.
*/
static int
remoteConfigGetStringList ( virConfPtr conf , const char * key , char * * * list_arg ,
const char * filename )
{
char * * list ;
virConfValuePtr p = virConfGetValue ( conf , key ) ;
if ( ! p )
return 0 ;
switch ( p - > type ) {
case VIR_CONF_STRING :
2008-06-06 14:52:01 +04:00
if ( VIR_ALLOC_N ( list , 2 ) < 0 ) {
2009-01-06 21:32:03 +03:00
VIR_ERROR ( _ ( " failed to allocate memory for %s config list " ) , key ) ;
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 18:43:42 +03:00
return - 1 ;
}
list [ 0 ] = strdup ( p - > str ) ;
list [ 1 ] = NULL ;
if ( list [ 0 ] = = NULL ) {
2009-01-06 21:32:03 +03:00
VIR_ERROR ( _ ( " failed to allocate memory for %s config list value " ) ,
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 18:43:42 +03:00
key ) ;
2008-06-06 14:52:01 +04:00
VIR_FREE ( list ) ;
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 18:43:42 +03:00
return - 1 ;
}
break ;
case VIR_CONF_LIST : {
int i , len = 0 ;
virConfValuePtr pp ;
for ( pp = p - > list ; pp ; pp = pp - > next )
len + + ;
2008-06-06 14:52:01 +04:00
if ( VIR_ALLOC_N ( list , 1 + len ) < 0 ) {
2009-01-06 21:32:03 +03:00
VIR_ERROR ( _ ( " failed to allocate memory for %s config list " ) , key ) ;
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 18:43:42 +03:00
return - 1 ;
}
for ( i = 0 , pp = p - > list ; pp ; + + i , pp = pp - > next ) {
if ( pp - > type ! = VIR_CONF_STRING ) {
2009-01-06 21:32:03 +03:00
VIR_ERROR ( _ ( " remoteReadConfigFile: %s: %s: "
" must be a string or list of strings \n " ) ,
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 18:43:42 +03:00
filename , key ) ;
2008-06-06 14:52:01 +04:00
VIR_FREE ( list ) ;
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 18:43:42 +03:00
return - 1 ;
}
list [ i ] = strdup ( pp - > str ) ;
if ( list [ i ] = = NULL ) {
int j ;
for ( j = 0 ; j < i ; j + + )
2008-06-06 14:52:01 +04:00
VIR_FREE ( list [ j ] ) ;
VIR_FREE ( list ) ;
2009-01-06 21:32:03 +03:00
VIR_ERROR ( _ ( " failed to allocate memory for %s config list value " ) ,
key ) ;
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 18:43:42 +03:00
return - 1 ;
}
}
list [ i ] = NULL ;
break ;
}
default :
2009-01-06 21:32:03 +03:00
VIR_ERROR ( _ ( " remoteReadConfigFile: %s: %s: "
" must be a string or list of strings \n " ) ,
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 18:43:42 +03:00
filename , key ) ;
return - 1 ;
}
* list_arg = list ;
return 0 ;
}
/* A helper function used by each of the following macros. */
static int
checkType ( virConfValuePtr p , const char * filename ,
const char * key , virConfType required_type )
{
if ( p - > type ! = required_type ) {
2009-01-06 21:32:03 +03:00
VIR_ERROR ( _ ( " remoteReadConfigFile: %s: %s: invalid type: "
Mark all qemudLog diagnostics for translation.
* po/POTFILES.in: Add names of many new files.
* Makefile.maint (err_func_re): Add qemudLog.
Mark diagnostics with _(...). Split some long lines.
* qemud/qemud.c (remoteCheckCertFile, remoteInitializeGnuTLS):
(qemudDispatchSignalEvent, qemudSetCloseExec, qemudSetNonBlock):
(qemudWritePidFile, qemudListenUnix, remoteMakeSockets):
(remoteListenTCP, qemudInitPaths, qemudInitialize):
(qemudNetworkInit, remoteInitializeTLSSession, remoteCheckDN):
(remoteCheckCertificate, remoteCheckAccess, qemudDispatchServer):
(qemudClientReadBuf, qemudDispatchClientRead):
(qemudClientWriteBuf, qemudDispatchClientWrite, qemudOneLoop):
(remoteConfigGetStringList, checkType, GET_CONF_STR):
(remoteConfigGetAuth, remoteReadConfigFile, main):
* qemud/remote.c (remoteDispatchAuthSaslInit, remoteSASLCheckSSF):
(remoteSASLCheckAccess, remoteDispatchAuthSaslStart):
(remoteDispatchAuthSaslStep, remoteDispatchAuthSaslInit):
(remoteDispatchAuthSaslStart, remoteDispatchAuthSaslStep):
(qemudGetSocketIdentity, remoteDispatchAuthPolkit):
* src/iptables.c (notifyRulesUpdated, MAX_FILE_LEN, iptRulesSave):
(iptRulesReload):
* src/qemu_conf.c (qemudExtractVersionInfo, qemudLoadConfig):
(qemudLoadNetworkConfig, qemudScanConfigDir):
* src/qemu_driver.c (qemudSetCloseExec, qemudSetNonBlock):
(qemudAutostartConfigs, qemudStartup, qemudReload):
(qemudWaitForMonitor, qemudStartVMDaemon, qemudVMData):
(qemudShutdownVMDaemon, qemudStartNetworkDaemon):
(qemudShutdownNetworkDaemon, qemudMonitorCommand):
(qemudDomainUndefine, qemudNetworkUndefine):
* src/uuid.c (virUUIDGenerate):
* src/xm_internal.c (xenXMAttachInterface):
2008-02-07 19:50:17 +03:00
" got %s; expected %s \n " ) , filename , key ,
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 18:43:42 +03:00
virConfTypeName ( p - > type ) ,
virConfTypeName ( required_type ) ) ;
return - 1 ;
}
return 0 ;
}
/* If there is no config data for the key, #var_name, then do nothing.
If there is valid data of type VIR_CONF_STRING , and strdup succeeds ,
store the result in var_name . Otherwise , ( i . e . invalid type , or strdup
failure ) , give a diagnostic and " goto " the cleanup - and - fail label . */
# define GET_CONF_STR(conf, filename, var_name) \
do { \
virConfValuePtr p = virConfGetValue ( conf , # var_name ) ; \
if ( p ) { \
if ( checkType ( p , filename , # var_name , VIR_CONF_STRING ) < 0 ) \
goto free_and_fail ; \
( var_name ) = strdup ( p - > str ) ; \
if ( ( var_name ) = = NULL ) { \
2009-02-05 19:28:30 +03:00
char ebuf [ 1024 ] ; \
2010-01-19 16:17:20 +03:00
VIR_ERROR ( _ ( " remoteReadConfigFile: %s " ) , \
2009-02-05 19:28:30 +03:00
virStrerror ( errno , ebuf , sizeof ebuf ) ) ; \
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 18:43:42 +03:00
goto free_and_fail ; \
} \
} \
} while ( 0 )
/* Like GET_CONF_STR, but for integral values. */
# define GET_CONF_INT(conf, filename, var_name) \
do { \
virConfValuePtr p = virConfGetValue ( conf , # var_name ) ; \
if ( p ) { \
if ( checkType ( p , filename , # var_name , VIR_CONF_LONG ) < 0 ) \
goto free_and_fail ; \
( var_name ) = p - > l ; \
} \
} while ( 0 )
2007-12-05 18:34:05 +03:00
static int remoteConfigGetAuth ( virConfPtr conf , const char * key , int * auth , const char * filename ) {
virConfValuePtr p ;
p = virConfGetValue ( conf , key ) ;
if ( ! p )
return 0 ;
2007-12-12 00:20:13 +03:00
if ( checkType ( p , filename , key , VIR_CONF_STRING ) < 0 )
2007-12-05 18:34:05 +03:00
return - 1 ;
if ( ! p - > str )
return 0 ;
if ( STREQ ( p - > str , " none " ) ) {
* auth = REMOTE_AUTH_NONE ;
# if HAVE_SASL
} else if ( STREQ ( p - > str , " sasl " ) ) {
* auth = REMOTE_AUTH_SASL ;
2007-12-05 21:21:27 +03:00
# endif
# if HAVE_POLKIT
} else if ( STREQ ( p - > str , " polkit " ) ) {
* auth = REMOTE_AUTH_POLKIT ;
2007-12-05 18:34:05 +03:00
# endif
} else {
2010-01-19 16:17:20 +03:00
VIR_ERROR ( _ ( " remoteReadConfigFile: %s: %s: unsupported auth %s " ) ,
Mark all qemudLog diagnostics for translation.
* po/POTFILES.in: Add names of many new files.
* Makefile.maint (err_func_re): Add qemudLog.
Mark diagnostics with _(...). Split some long lines.
* qemud/qemud.c (remoteCheckCertFile, remoteInitializeGnuTLS):
(qemudDispatchSignalEvent, qemudSetCloseExec, qemudSetNonBlock):
(qemudWritePidFile, qemudListenUnix, remoteMakeSockets):
(remoteListenTCP, qemudInitPaths, qemudInitialize):
(qemudNetworkInit, remoteInitializeTLSSession, remoteCheckDN):
(remoteCheckCertificate, remoteCheckAccess, qemudDispatchServer):
(qemudClientReadBuf, qemudDispatchClientRead):
(qemudClientWriteBuf, qemudDispatchClientWrite, qemudOneLoop):
(remoteConfigGetStringList, checkType, GET_CONF_STR):
(remoteConfigGetAuth, remoteReadConfigFile, main):
* qemud/remote.c (remoteDispatchAuthSaslInit, remoteSASLCheckSSF):
(remoteSASLCheckAccess, remoteDispatchAuthSaslStart):
(remoteDispatchAuthSaslStep, remoteDispatchAuthSaslInit):
(remoteDispatchAuthSaslStart, remoteDispatchAuthSaslStep):
(qemudGetSocketIdentity, remoteDispatchAuthPolkit):
* src/iptables.c (notifyRulesUpdated, MAX_FILE_LEN, iptRulesSave):
(iptRulesReload):
* src/qemu_conf.c (qemudExtractVersionInfo, qemudLoadConfig):
(qemudLoadNetworkConfig, qemudScanConfigDir):
* src/qemu_driver.c (qemudSetCloseExec, qemudSetNonBlock):
(qemudAutostartConfigs, qemudStartup, qemudReload):
(qemudWaitForMonitor, qemudStartVMDaemon, qemudVMData):
(qemudShutdownVMDaemon, qemudStartNetworkDaemon):
(qemudShutdownNetworkDaemon, qemudMonitorCommand):
(qemudDomainUndefine, qemudNetworkUndefine):
* src/uuid.c (virUUIDGenerate):
* src/xm_internal.c (xenXMAttachInterface):
2008-02-07 19:50:17 +03:00
filename , key , p - > str ) ;
2007-12-05 18:34:05 +03:00
return - 1 ;
}
return 0 ;
}
2007-12-05 22:25:44 +03:00
# ifdef HAVE_SASL
static inline int
remoteReadSaslAllowedUsernameList ( virConfPtr conf ,
struct qemud_server * server ,
const char * filename )
{
return
remoteConfigGetStringList ( conf , " sasl_allowed_username_list " ,
& server - > saslUsernameWhitelist , filename ) ;
}
# else
static inline int
remoteReadSaslAllowedUsernameList ( virConfPtr conf ATTRIBUTE_UNUSED ,
struct qemud_server * server ATTRIBUTE_UNUSED ,
const char * filename ATTRIBUTE_UNUSED )
{
return 0 ;
}
# endif
2008-12-22 15:53:26 +03:00
/*
* Set up the logging environment
* By default if daemonized all errors go to syslog and the logging
* is also saved onto the logfile libvird . log , but if verbose or error
* debugging is asked for then output informations or debug .
*/
2008-12-22 19:16:10 +03:00
static int
2009-10-23 10:56:21 +04:00
qemudSetLogging ( virConfPtr conf , const char * filename )
{
int log_level = 0 ;
2009-08-06 17:45:50 +04:00
char * log_filters = NULL ;
char * log_outputs = NULL ;
2008-12-22 19:16:10 +03:00
int ret = - 1 ;
2008-12-22 15:53:26 +03:00
virLogReset ( ) ;
2008-12-22 19:16:10 +03:00
/*
2009-08-06 17:55:07 +04:00
* Libvirtd ' s order of precedence is :
* cmdline > environment > config
*
* In order to achieve this , we must process configuration in
* different order for the log level versus the filters and
* outputs . Because filters and outputs append , we have to look at
* the environment first and then only check the config file if
* there was no result from the environment . The default output is
* then applied only if there was no setting from either of the
* first two . Because we don ' t have a way to determine if the log
* level has been set , we must process variables in the opposite
* order , each one overriding the previous .
2008-12-22 19:16:10 +03:00
*/
2008-12-22 15:53:26 +03:00
GET_CONF_INT ( conf , filename , log_level ) ;
2009-08-06 17:45:50 +04:00
if ( log_level ! = 0 )
virLogSetDefaultPriority ( log_level ) ;
2009-08-06 17:55:07 +04:00
virLogSetFromEnv ( ) ;
2009-08-06 17:45:50 +04:00
if ( virLogGetNbFilters ( ) = = 0 ) {
GET_CONF_STR ( conf , filename , log_filters ) ;
virLogParseFilters ( log_filters ) ;
2008-12-22 19:16:10 +03:00
}
2008-12-22 15:53:26 +03:00
2009-08-06 17:45:50 +04:00
if ( virLogGetNbOutputs ( ) = = 0 ) {
GET_CONF_STR ( conf , filename , log_outputs ) ;
virLogParseOutputs ( log_outputs ) ;
2009-06-03 14:36:17 +04:00
}
2008-12-22 15:53:26 +03:00
/*
2009-08-06 17:45:50 +04:00
* If no defined outputs , then direct to syslog when running
* as daemon . Otherwise the default output is stderr .
2008-12-22 15:53:26 +03:00
*/
2009-08-06 17:45:50 +04:00
if ( virLogGetNbOutputs ( ) = = 0 ) {
2009-07-01 15:21:15 +04:00
char * tmp = NULL ;
2009-01-21 00:50:31 +03:00
if ( godaemon ) {
2009-08-06 17:45:50 +04:00
if ( virAsprintf ( & tmp , " %d:syslog:libvirtd " ,
virLogGetDefaultPriority ( ) ) < 0 )
2009-01-21 00:50:31 +03:00
goto free_and_fail ;
} else {
2009-08-06 17:45:50 +04:00
if ( virAsprintf ( & tmp , " %d:stderr " ,
virLogGetDefaultPriority ( ) ) < 0 )
2009-07-01 15:21:15 +04:00
goto free_and_fail ;
2009-01-21 00:50:31 +03:00
}
2009-07-01 15:21:15 +04:00
virLogParseOutputs ( tmp ) ;
VIR_FREE ( tmp ) ;
2009-06-03 14:36:17 +04:00
}
2009-08-06 17:55:07 +04:00
/*
* Command line override for - - verbose
*/
if ( ( verbose ) & & ( virLogGetDefaultPriority ( ) > VIR_LOG_INFO ) )
virLogSetDefaultPriority ( VIR_LOG_INFO ) ;
2008-12-22 19:16:10 +03:00
ret = 0 ;
2008-12-22 15:53:26 +03:00
free_and_fail :
VIR_FREE ( log_filters ) ;
VIR_FREE ( log_outputs ) ;
2008-12-22 19:16:10 +03:00
return ( ret ) ;
2008-12-22 15:53:26 +03:00
}
2007-12-05 22:25:44 +03:00
2007-06-11 16:04:54 +04:00
/* Read the config file if it exists.
* Only used in the remote case , hence the name .
*/
static int
2007-12-05 18:34:05 +03:00
remoteReadConfigFile ( struct qemud_server * server , const char * filename )
2007-06-11 16:04:54 +04:00
{
virConfPtr conf ;
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 18:43:42 +03:00
/* The following variable names must match the corresponding
configuration strings . */
char * unix_sock_ro_perms = NULL ;
char * unix_sock_rw_perms = NULL ;
char * unix_sock_group = NULL ;
2009-04-16 18:53:19 +04:00
char * buf = NULL ;
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 18:43:42 +03:00
2008-07-30 12:47:10 +04:00
# if HAVE_POLKIT
/* Change the default back to no auth for non-root */
2009-06-12 17:20:13 +04:00
if ( ! server - > privileged & & auth_unix_rw = = REMOTE_AUTH_POLKIT )
2008-07-30 12:47:10 +04:00
auth_unix_rw = REMOTE_AUTH_NONE ;
2009-06-12 17:20:13 +04:00
if ( ! server - > privileged & & auth_unix_ro = = REMOTE_AUTH_POLKIT )
2008-07-30 12:47:10 +04:00
auth_unix_ro = REMOTE_AUTH_NONE ;
# endif
2009-06-19 16:34:30 +04:00
conf = virConfReadFile ( filename , 0 ) ;
2009-01-12 21:22:32 +03:00
if ( ! conf ) return - 1 ;
2007-06-11 16:04:54 +04:00
2008-12-22 15:53:26 +03:00
/*
* First get all the logging settings and activate them
*/
2008-12-22 19:16:10 +03:00
if ( qemudSetLogging ( conf , filename ) < 0 )
goto free_and_fail ;
2008-12-22 15:53:26 +03:00
2007-12-05 21:56:27 +03:00
GET_CONF_INT ( conf , filename , listen_tcp ) ;
GET_CONF_INT ( conf , filename , listen_tls ) ;
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 18:43:42 +03:00
GET_CONF_STR ( conf , filename , tls_port ) ;
GET_CONF_STR ( conf , filename , tcp_port ) ;
2008-05-15 00:57:20 +04:00
GET_CONF_STR ( conf , filename , listen_addr ) ;
2008-05-15 01:22:04 +04:00
2007-12-05 18:34:05 +03:00
if ( remoteConfigGetAuth ( conf , " auth_unix_rw " , & auth_unix_rw , filename ) < 0 )
2008-03-03 16:15:57 +03:00
goto free_and_fail ;
2007-12-05 21:21:27 +03:00
# if HAVE_POLKIT
/* Change default perms to be wide-open if PolicyKit is enabled.
* Admin can always override in config file
*/
if ( auth_unix_rw = = REMOTE_AUTH_POLKIT )
unix_sock_rw_mask = 0777 ;
# endif
2007-12-05 18:34:05 +03:00
if ( remoteConfigGetAuth ( conf , " auth_unix_ro " , & auth_unix_ro , filename ) < 0 )
2008-03-03 16:15:57 +03:00
goto free_and_fail ;
2007-12-05 18:34:05 +03:00
if ( remoteConfigGetAuth ( conf , " auth_tcp " , & auth_tcp , filename ) < 0 )
2008-03-03 16:15:57 +03:00
goto free_and_fail ;
2007-12-05 18:34:05 +03:00
if ( remoteConfigGetAuth ( conf , " auth_tls " , & auth_tls , filename ) < 0 )
2008-03-03 16:15:57 +03:00
goto free_and_fail ;
2007-12-05 18:34:05 +03:00
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 18:43:42 +03:00
GET_CONF_STR ( conf , filename , unix_sock_group ) ;
if ( unix_sock_group ) {
2009-06-12 17:20:13 +04:00
if ( ! server - > privileged ) {
2009-01-06 21:32:03 +03:00
VIR_WARN0 ( _ ( " Cannot set group when not running as root " ) ) ;
2007-09-19 06:28:01 +04:00
} else {
2009-04-16 18:53:19 +04:00
int ret ;
2009-01-22 22:41:48 +03:00
struct group grpdata , * grp ;
2009-04-16 18:53:19 +04:00
size_t maxbuf = sysconf ( _SC_GETGR_R_SIZE_MAX ) ;
if ( maxbuf = = - 1 )
maxbuf = 1024 ;
if ( VIR_ALLOC_N ( buf , maxbuf ) < 0 ) {
VIR_ERROR ( " %s " , _ ( " Failed to allocate memory for buffer " ) ) ;
goto free_and_fail ;
}
while ( ( ret = getgrnam_r ( unix_sock_group , & grpdata ,
buf , maxbuf ,
& grp ) ) = = ERANGE ) {
maxbuf * = 2 ;
if ( maxbuf > 65536 | | VIR_REALLOC_N ( buf , maxbuf ) < 0 ) {
VIR_ERROR ( " %s " , _ ( " Failed to reallocate enough memory for buffer " ) ) ;
goto free_and_fail ;
}
}
if ( ret ! = 0 | | ! grp ) {
2009-01-06 21:32:03 +03:00
VIR_ERROR ( _ ( " Failed to lookup group '%s' " ) , unix_sock_group ) ;
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 18:43:42 +03:00
goto free_and_fail ;
2007-09-19 06:28:01 +04:00
}
unix_sock_gid = grp - > gr_gid ;
2009-12-10 02:00:50 +03:00
VIR_FREE ( buf ) ;
2007-09-19 06:28:01 +04:00
}
2009-12-10 02:00:50 +03:00
VIR_FREE ( unix_sock_group ) ;
2007-09-19 06:28:01 +04:00
}
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 18:43:42 +03:00
GET_CONF_STR ( conf , filename , unix_sock_ro_perms ) ;
if ( unix_sock_ro_perms ) {
2008-02-08 12:15:16 +03:00
if ( virStrToLong_i ( unix_sock_ro_perms , NULL , 8 , & unix_sock_ro_mask ) ! = 0 ) {
2009-01-06 21:32:03 +03:00
VIR_ERROR ( _ ( " Failed to parse mode '%s' " ) , unix_sock_ro_perms ) ;
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 18:43:42 +03:00
goto free_and_fail ;
2007-09-19 06:28:01 +04:00
}
2009-12-10 02:00:50 +03:00
VIR_FREE ( unix_sock_ro_perms ) ;
2007-09-19 06:28:01 +04:00
}
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 18:43:42 +03:00
GET_CONF_STR ( conf , filename , unix_sock_rw_perms ) ;
if ( unix_sock_rw_perms ) {
2008-02-08 12:15:16 +03:00
if ( virStrToLong_i ( unix_sock_rw_perms , NULL , 8 , & unix_sock_rw_mask ) ! = 0 ) {
2009-01-06 21:32:03 +03:00
VIR_ERROR ( _ ( " Failed to parse mode '%s' " ) , unix_sock_rw_perms ) ;
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 18:43:42 +03:00
goto free_and_fail ;
2007-09-19 06:28:01 +04:00
}
2009-12-10 02:00:50 +03:00
VIR_FREE ( unix_sock_rw_perms ) ;
2007-09-19 06:28:01 +04:00
}
2009-02-09 20:52:38 +03:00
GET_CONF_STR ( conf , filename , unix_sock_dir ) ;
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 18:43:42 +03:00
GET_CONF_INT ( conf , filename , mdns_adv ) ;
GET_CONF_STR ( conf , filename , mdns_name ) ;
2007-09-19 05:56:55 +04:00
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 18:43:42 +03:00
GET_CONF_INT ( conf , filename , tls_no_verify_certificate ) ;
2007-06-11 16:04:54 +04:00
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 18:43:42 +03:00
GET_CONF_STR ( conf , filename , key_file ) ;
GET_CONF_STR ( conf , filename , cert_file ) ;
GET_CONF_STR ( conf , filename , ca_file ) ;
GET_CONF_STR ( conf , filename , crl_file ) ;
2007-06-11 16:04:54 +04:00
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 18:43:42 +03:00
if ( remoteConfigGetStringList ( conf , " tls_allowed_dn_list " ,
& tls_allowed_dn_list , filename ) < 0 )
goto free_and_fail ;
2007-06-11 16:04:54 +04:00
2007-12-05 22:25:44 +03:00
if ( remoteReadSaslAllowedUsernameList ( conf , server , filename ) < 0 )
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 18:43:42 +03:00
goto free_and_fail ;
2007-06-11 16:04:54 +04:00
2008-12-05 01:18:44 +03:00
GET_CONF_INT ( conf , filename , min_workers ) ;
GET_CONF_INT ( conf , filename , max_workers ) ;
GET_CONF_INT ( conf , filename , max_clients ) ;
2009-01-20 22:25:15 +03:00
GET_CONF_INT ( conf , filename , max_requests ) ;
GET_CONF_INT ( conf , filename , max_client_requests ) ;
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 18:43:42 +03:00
virConfFree ( conf ) ;
return 0 ;
2007-06-11 16:04:54 +04:00
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 18:43:42 +03:00
free_and_fail :
virConfFree ( conf ) ;
2009-12-10 02:00:50 +03:00
VIR_FREE ( mdns_name ) ;
VIR_FREE ( unix_sock_ro_perms ) ;
VIR_FREE ( unix_sock_rw_perms ) ;
VIR_FREE ( unix_sock_group ) ;
VIR_FREE ( buf ) ;
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 18:43:42 +03:00
2008-05-15 00:57:20 +04:00
/* Don't bother trying to free listen_addr, tcp_port, tls_port, key_file,
cert_file , ca_file , or crl_file , since they are initialized to
non - malloc ' d strings . Besides , these are static variables , and callers
are unlikely to call this function more than once , so there wouldn ' t
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 18:43:42 +03:00
even be a real leak . */
if ( tls_allowed_dn_list ) {
int i ;
for ( i = 0 ; tls_allowed_dn_list [ i ] ; i + + )
2009-12-10 02:00:50 +03:00
VIR_FREE ( tls_allowed_dn_list [ i ] ) ;
VIR_FREE ( tls_allowed_dn_list ) ;
Detect heap allocation failure; factor out some duplication.
* qemud/qemud.c (tls_port, tcp_port, mdns_name, tls_allowed_ip_list):
(tls_allowed_dn_list): Remove "const", now that we free these.
(unix_sock_rw_mask): Rename from unix_sock_rw_perms, so that
the latter name can be used as a local string variable, so that the
variable name matches the config attribute name.
(unix_sock_ro_mask): Rename from unix_sock_ro_perms, likewise.
(remoteCheckDN, remoteCheckAccess): Adapt to const removal.
(qemudDispatchServer): Check for heap allocation failure.
(remoteConfigGetStringList): New function, based on code from Dan Berrangé.
(CHECK_TYPE): Remove macro.
(checkType): New function.
(GET_CONF_INT, GET_CONF_STR): New macros.
(remoteReadConfigFile): Use new macros to avoid duplication and to
check for allocation failure.
* src/conf.h (virConfTypeName): New static inline function.
2007-11-30 18:43:42 +03:00
}
return - 1 ;
2007-06-11 16:04:54 +04:00
}
2008-12-12 10:56:50 +03:00
/* Display version information. */
static void
version ( const char * argv0 )
{
printf ( " %s (%s) %s \n " , argv0 , PACKAGE_NAME , PACKAGE_VERSION ) ;
}
2009-01-22 20:49:41 +03:00
# ifdef __sun
static int
qemudSetupPrivs ( void )
{
chown ( " /var/run/libvirt " , SYSTEM_UID , SYSTEM_UID ) ;
if ( __init_daemon_priv ( PU_RESETGROUPS | PU_CLEARLIMITSET ,
SYSTEM_UID , SYSTEM_UID , PRIV_XVM_CONTROL , NULL ) ) {
2010-01-19 16:17:20 +03:00
VIR_ERROR0 ( _ ( " additional privileges are required " ) ) ;
2009-01-22 20:49:41 +03:00
return - 1 ;
}
if ( priv_set ( PRIV_OFF , PRIV_ALLSETS , PRIV_FILE_LINK_ANY , PRIV_PROC_INFO ,
PRIV_PROC_SESSION , PRIV_PROC_EXEC , PRIV_PROC_FORK , NULL ) ) {
2010-01-19 16:17:20 +03:00
VIR_ERROR0 ( _ ( " failed to set reduced privileges " ) ) ;
2009-01-22 20:49:41 +03:00
return - 1 ;
}
return 0 ;
}
# else
# define qemudSetupPrivs() 0
# endif
2009-10-16 14:48:50 +04:00
/*
* Doing anything non - trivial in signal handlers is pretty dangerous ,
* since there are very few async - signal safe POSIX funtions . To
* deal with this we setup a very simple signal handler . It simply
* writes the signal number to a pipe . The main event loop then sees
* the signal on the pipe and can safely do the processing from
* event loop context
*/
static int
daemonSetupSignals ( struct qemud_server * server )
{
struct sigaction sig_action ;
int sigpipe [ 2 ] ;
if ( pipe ( sigpipe ) < 0 )
return - 1 ;
if ( virSetNonBlock ( sigpipe [ 0 ] ) < 0 | |
virSetNonBlock ( sigpipe [ 1 ] ) < 0 | |
virSetCloseExec ( sigpipe [ 0 ] ) < 0 | |
virSetCloseExec ( sigpipe [ 1 ] ) < 0 ) {
char ebuf [ 1024 ] ;
VIR_ERROR ( _ ( " Failed to create pipe: %s " ) ,
virStrerror ( errno , ebuf , sizeof ebuf ) ) ;
goto error ;
}
sig_action . sa_sigaction = sig_handler ;
sig_action . sa_flags = SA_SIGINFO ;
sigemptyset ( & sig_action . sa_mask ) ;
sigaction ( SIGHUP , & sig_action , NULL ) ;
sigaction ( SIGINT , & sig_action , NULL ) ;
sigaction ( SIGQUIT , & sig_action , NULL ) ;
sigaction ( SIGTERM , & sig_action , NULL ) ;
sigaction ( SIGCHLD , & sig_action , NULL ) ;
sig_action . sa_handler = SIG_IGN ;
sigaction ( SIGPIPE , & sig_action , NULL ) ;
if ( virEventAddHandleImpl ( sigpipe [ 0 ] ,
VIR_EVENT_HANDLE_READABLE ,
qemudDispatchSignalEvent ,
server , NULL ) < 0 ) {
VIR_ERROR0 ( _ ( " Failed to register callback for signal pipe " ) ) ;
goto error ;
}
server - > sigread = sigpipe [ 0 ] ;
server - > sigwrite = sigpipe [ 1 ] ;
sigwrite = sigpipe [ 1 ] ;
return 0 ;
error :
close ( sigpipe [ 0 ] ) ;
close ( sigpipe [ 1 ] ) ;
return - 1 ;
}
2007-04-04 13:32:00 +04:00
/* Print command-line usage. */
static void
usage ( const char * argv0 )
{
fprintf ( stderr ,
2007-06-11 16:04:54 +04:00
" \n \
Usage : \ n \
% s [ options ] \ n \
\ n \
Options : \ n \
- v | - - verbose Verbose messages . \ n \
- d | - - daemon Run as a daemon & write PID file . \ n \
2007-06-27 03:48:46 +04:00
- l | - - listen Listen for TCP / IP connections . \ n \
- t | - - timeout < secs > Exit after timeout period . \ n \
2007-08-07 17:24:22 +04:00
- f | - - config < file > Configuration file . \ n \
2008-12-12 10:56:50 +03:00
| - - version Display version information . \ n \
2007-06-11 16:04:54 +04:00
- p | - - pid - file < file > Change name of PID file . \ n \
\ n \
2007-06-27 03:48:46 +04:00
libvirt management daemon : \ n \
2007-06-11 16:04:54 +04:00
\ n \
Default paths : \ n \
\ n \
2009-11-10 17:53:20 +03:00
Configuration file ( unless overridden by - f ) : \ n \
2007-06-11 16:04:54 +04:00
" SYSCONF_DIR " / libvirt / libvirtd . conf \ n \
\ n \
2007-06-27 03:48:46 +04:00
Sockets ( as root ) : \ n \
2007-06-11 16:04:54 +04:00
" LOCAL_STATE_DIR " / run / libvirt / libvirt - sock \ n \
" LOCAL_STATE_DIR " / run / libvirt / libvirt - sock - ro \ n \
2007-06-27 03:48:46 +04:00
\ n \
Sockets ( as non - root ) : \ n \
$ HOME / . libvirt / libvirt - sock ( in UNIX abstract namespace ) \ n \
2007-06-11 16:04:54 +04:00
\ n \
TLS : \ n \
CA certificate : " LIBVIRT_CACERT " \ n \
Server certificate : " LIBVIRT_SERVERCERT " \ n \
Server private key : " LIBVIRT_SERVERKEY " \ n \
\ n \
PID file ( unless overridden by - - pid - file ) : \ n \
% s \ n \
\ n " ,
argv0 ,
REMOTE_PID_FILE [ 0 ] ! = ' \0 '
? REMOTE_PID_FILE
: " (disabled in ./configure) " ) ;
2007-04-04 13:32:00 +04:00
}
2008-12-12 10:56:50 +03:00
enum {
OPT_VERSION = 129
} ;
2007-02-14 04:40:09 +03:00
# define MAX_LISTEN 5
int main ( int argc , char * * argv ) {
2008-03-03 21:10:19 +03:00
struct qemud_server * server = NULL ;
2007-06-11 16:04:54 +04:00
const char * pid_file = NULL ;
2009-01-12 21:22:32 +03:00
const char * remote_config_file = NULL ;
2009-10-16 15:14:54 +04:00
int statuswrite = - 1 ;
2007-02-23 15:48:36 +03:00
int ret = 1 ;
2007-02-14 04:40:09 +03:00
struct option opts [ ] = {
{ " verbose " , no_argument , & verbose , 1 } ,
{ " daemon " , no_argument , & godaemon , 1 } ,
2007-06-27 03:48:46 +04:00
{ " listen " , no_argument , & ipsock , 1 } ,
2007-08-07 17:24:22 +04:00
{ " config " , required_argument , NULL , ' f ' } ,
2007-04-04 13:32:00 +04:00
{ " timeout " , required_argument , NULL , ' t ' } ,
{ " pid-file " , required_argument , NULL , ' p ' } ,
2008-12-12 10:56:50 +03:00
{ " version " , no_argument , NULL , OPT_VERSION } ,
2007-04-04 13:32:00 +04:00
{ " help " , no_argument , NULL , ' ? ' } ,
2007-02-14 04:40:09 +03:00
{ 0 , 0 , 0 , 0 }
} ;
2009-10-16 14:29:01 +04:00
virInitialize ( ) ;
2007-02-14 04:40:09 +03:00
while ( 1 ) {
int optidx = 0 ;
int c ;
char * tmp ;
2007-08-07 17:24:22 +04:00
c = getopt_long ( argc , argv , " ldf:p:t:v " , opts , & optidx ) ;
2007-02-14 04:40:09 +03:00
if ( c = = - 1 ) {
break ;
}
switch ( c ) {
case 0 :
/* Got one of the flags */
break ;
case ' v ' :
verbose = 1 ;
break ;
case ' d ' :
godaemon = 1 ;
break ;
2007-06-27 03:48:46 +04:00
case ' l ' :
ipsock = 1 ;
2007-02-14 04:40:09 +03:00
break ;
case ' t ' :
2008-02-08 12:15:16 +03:00
if ( virStrToLong_i ( optarg , & tmp , 10 , & timeout ) ! = 0
2007-11-14 13:53:05 +03:00
| | timeout < = 0
/* Ensure that we can multiply by 1000 without overflowing. */
| | timeout > INT_MAX / 1000 )
2007-02-14 04:40:09 +03:00
timeout = - 1 ;
break ;
2007-02-23 15:48:36 +03:00
case ' p ' :
2007-06-11 16:04:54 +04:00
pid_file = optarg ;
break ;
case ' f ' :
remote_config_file = optarg ;
2007-02-23 15:48:36 +03:00
break ;
2008-12-12 10:56:50 +03:00
case OPT_VERSION :
version ( argv [ 0 ] ) ;
return 0 ;
2007-02-14 04:40:09 +03:00
case ' ? ' :
2007-04-04 13:32:00 +04:00
usage ( argv [ 0 ] ) ;
2007-02-14 04:40:09 +03:00
return 2 ;
default :
2007-08-07 17:24:22 +04:00
fprintf ( stderr , " libvirtd: internal error: unknown flag: %c \n " ,
c ) ;
2009-12-15 11:43:29 +03:00
exit ( EXIT_FAILURE ) ;
2007-02-14 04:40:09 +03:00
}
}
2009-01-12 21:22:32 +03:00
if ( remote_config_file = = NULL ) {
static const char * default_config_file
= SYSCONF_DIR " /libvirt/libvirtd.conf " ;
remote_config_file =
2009-01-13 15:22:24 +03:00
( access ( default_config_file , R_OK ) = = 0
2009-01-12 21:22:32 +03:00
? default_config_file
: " /dev/null " ) ;
}
2008-05-20 20:17:36 +04:00
if ( godaemon ) {
2009-02-05 19:28:03 +03:00
char ebuf [ 1024 ] ;
2009-10-16 15:14:54 +04:00
if ( ( statuswrite = daemonForkIntoBackground ( ) ) < 0 ) {
2009-02-05 19:28:03 +03:00
VIR_ERROR ( _ ( " Failed to fork as daemon: %s " ) ,
virStrerror ( errno , ebuf , sizeof ebuf ) ) ;
2009-10-16 14:48:50 +04:00
goto error ;
2008-05-20 20:17:36 +04:00
}
}
/* If running as root and no PID file is set, use the default */
if ( pid_file = = NULL & &
2009-06-12 17:20:13 +04:00
geteuid ( ) = = 0 & &
2008-05-20 20:17:36 +04:00
REMOTE_PID_FILE [ 0 ] ! = ' \0 ' )
pid_file = REMOTE_PID_FILE ;
/* If we have a pidfile set, claim it now, exiting if already taken */
if ( pid_file ! = NULL & &
2009-10-16 15:14:54 +04:00
qemudWritePidFile ( pid_file ) < 0 ) {
pid_file = NULL ; /* Prevent unlinking of someone else's pid ! */
ret = VIR_DAEMON_ERR_PIDFILE ;
2009-10-16 14:48:50 +04:00
goto error ;
2009-10-16 15:14:54 +04:00
}
2008-05-20 20:17:36 +04:00
2009-01-22 20:49:41 +03:00
/* Ensure the rundir exists (on tmpfs on some systems) */
2009-06-12 17:20:13 +04:00
if ( geteuid ( ) = = 0 ) {
2009-01-22 20:49:41 +03:00
const char * rundir = LOCAL_STATE_DIR " /run/libvirt " ;
if ( mkdir ( rundir , 0755 ) ) {
if ( errno ! = EEXIST ) {
2009-09-23 14:38:21 +04:00
char ebuf [ 1024 ] ;
VIR_ERROR ( _ ( " unable to create rundir %s: %s " ) , rundir ,
virStrerror ( errno , ebuf , sizeof ( ebuf ) ) ) ;
2009-10-16 15:14:54 +04:00
ret = VIR_DAEMON_ERR_RUNDIR ;
goto error ;
2009-01-22 20:49:41 +03:00
}
}
}
2009-06-12 17:20:13 +04:00
/* Beyond this point, nothing should rely on using
* getuid / geteuid ( ) = = 0 , for privilege level checks .
* It must all use the flag ' server - > privileged '
* which is also passed into all libvirt stateful
* drivers
*/
2009-10-16 15:14:54 +04:00
if ( qemudSetupPrivs ( ) < 0 ) {
ret = VIR_DAEMON_ERR_PRIVS ;
2009-10-16 14:48:50 +04:00
goto error ;
2009-10-16 15:14:54 +04:00
}
2009-01-22 20:49:41 +03:00
2009-10-16 14:48:50 +04:00
if ( ! ( server = qemudInitialize ( ) ) ) {
2009-10-16 15:14:54 +04:00
ret = VIR_DAEMON_ERR_INIT ;
2009-10-16 14:48:50 +04:00
goto error ;
2007-12-05 18:34:05 +03:00
}
2007-02-16 21:28:17 +03:00
2009-10-16 15:14:54 +04:00
if ( ( daemonSetupSignals ( server ) ) < 0 ) {
ret = VIR_DAEMON_ERR_SIGNAL ;
2009-10-16 14:48:50 +04:00
goto error ;
2009-10-16 15:14:54 +04:00
}
2009-10-16 14:48:50 +04:00
2007-12-05 18:34:05 +03:00
/* Read the config file (if it exists). */
2009-10-16 15:14:54 +04:00
if ( remoteReadConfigFile ( server , remote_config_file ) < 0 ) {
ret = VIR_DAEMON_ERR_CONFIG ;
2009-10-16 14:48:50 +04:00
goto error ;
2009-10-16 15:14:54 +04:00
}
2007-02-14 04:40:09 +03:00
2009-10-19 21:28:28 +04:00
/* Disable error func, now logging is setup */
virSetErrorFunc ( NULL , virshErrorHandler ) ;
2009-10-16 14:24:01 +04:00
if ( qemudNetworkInit ( server ) < 0 ) {
2009-10-16 15:14:54 +04:00
ret = VIR_DAEMON_ERR_NETWORK ;
2009-10-16 14:48:50 +04:00
goto error ;
2007-12-05 18:34:05 +03:00
}
2009-10-16 15:14:54 +04:00
/* Tell parent of daemon that basic initialization is complete
* In particular we ' re ready to accept net connections & have
* written the pidfile
*/
if ( statuswrite ! = - 1 ) {
char status = 0 ;
while ( write ( statuswrite , & status , 1 ) = = - 1 & &
errno = = EINTR )
;
close ( statuswrite ) ;
statuswrite = - 1 ;
}
2009-10-16 19:34:37 +04:00
/* Start the event loop in a background thread, since
* state initialization needs events to be being processed */
if ( qemudStartEventLoop ( server ) < 0 ) {
VIR_ERROR0 ( " Event thread startup failed " ) ;
goto error ;
}
2009-10-16 15:14:54 +04:00
/* Start the stateful HV drivers
* This is delibrately done after telling the parent process
* we ' re ready , since it can take a long time and this will
* seriously delay OS bootup process */
if ( virStateInitialize ( server - > privileged ) < 0 ) {
VIR_ERROR0 ( " Driver state initialization failed " ) ;
2009-11-13 13:34:47 +03:00
goto shutdown ;
2009-10-16 15:14:54 +04:00
}
2007-02-14 04:40:09 +03:00
2009-10-16 19:34:37 +04:00
/* Start accepting new clients from network */
virMutexLock ( & server - > lock ) ;
if ( qemudNetworkEnable ( server ) < 0 ) {
VIR_ERROR0 ( " Network event loop enablement failed " ) ;
goto shutdown ;
}
virMutexUnlock ( & server - > lock ) ;
2007-02-23 15:48:36 +03:00
ret = 0 ;
2009-10-16 19:34:37 +04:00
shutdown :
/* In a non-0 shutdown scenario we need to tell event loop
* to quit immediately . Otherwise in normal case we just
* sit in the thread join forever . Sure this means the
* main thread doesn ' t do anything useful ever , but that ' s
* not too much of drain on resources
*/
if ( ret ! = 0 ) {
virMutexLock ( & server - > lock ) ;
if ( server - > hasEventThread )
/* This SIGQUIT triggers the shutdown process */
kill ( getpid ( ) , SIGQUIT ) ;
virMutexUnlock ( & server - > lock ) ;
}
pthread_join ( server - > eventThread , NULL ) ;
2009-10-16 14:48:50 +04:00
error :
2009-10-16 15:14:54 +04:00
if ( statuswrite ! = - 1 ) {
if ( ret ! = 0 ) {
/* Tell parent of daemon what failed */
char status = ret ;
while ( write ( statuswrite , & status , 1 ) = = - 1 & &
errno = = EINTR )
;
}
close ( statuswrite ) ;
}
2008-03-03 21:10:19 +03:00
if ( server )
qemudCleanup ( server ) ;
2008-05-20 20:17:36 +04:00
if ( pid_file )
unlink ( pid_file ) ;
2008-12-22 15:53:26 +03:00
virLogShutdown ( ) ;
2007-02-23 15:48:36 +03:00
return ret ;
2007-02-14 04:40:09 +03:00
}