2007-02-14 01:40:09 +00:00
/*
2009-09-16 12:37:26 +01:00
* libvirtd.c: daemon start of day, guest process & i/o management
2007-02-14 01:40:09 +00:00
*
2010-02-02 11:27:25 +01:00
* Copyright (C) 2006-2010 Red Hat, Inc.
2007-02-14 01:40:09 +00: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 18:15:54 +00:00
#include <config.h>
2007-02-14 15:42:55 +00:00
2007-02-14 01:40:09 +00: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 12:04:54 +00:00
#include <netinet/tcp.h>
2007-02-14 01:40:09 +00:00
#include <netdb.h>
#include <stdlib.h>
#include <pwd.h>
#include <stdio.h>
2007-02-16 18:30:55 +00:00
#include <stdarg.h>
#include <syslog.h>
2007-02-14 01:40:09 +00:00
#include <string.h>
#include <errno.h>
#include <getopt.h>
2007-06-11 12:04:54 +00:00
#include <fnmatch.h>
2007-09-19 02:28:01 +00:00
#include <grp.h>
2008-01-23 14:54:41 +00:00
#include <signal.h>
2008-10-28 17:46:00 +00:00
#include <netdb.h>
2007-04-10 23:17:46 +00:00
2008-11-04 23:22:06 +00:00
#include "libvirt_internal.h"
2009-02-05 16:28:30 +00:00
#include "virterror_internal.h"
2008-05-23 08:24:41 +00:00
2009-02-09 17:52:38 +00:00
#define VIR_FROM_THIS VIR_FROM_QEMU
2009-09-16 12:37:26 +01:00
#include "libvirtd.h"
2009-07-10 12:20:03 +01:00
#include "dispatch.h"
2008-05-23 08:24:41 +00:00
#include "util.h"
2010-05-25 15:33:51 +01:00
#include "uuid.h"
2009-09-16 16:55:16 +01:00
#include "remote_driver.h"
2008-05-23 08:24:41 +00:00
#include "conf.h"
2007-06-26 19:11:00 +00:00
#include "event.h"
2008-06-06 10:52:01 +00:00
#include "memory.h"
2009-07-10 13:06:36 +01:00
#include "stream.h"
2010-03-26 15:53:32 +01:00
#include "hooks.h"
2007-09-19 01:56:55 +00:00
#ifdef HAVE_AVAHI
2010-03-09 19:22:22 +01:00
# include "mdns.h"
2007-09-19 01:56:55 +00:00
#endif
2007-02-14 01:40:09 +00:00
2008-11-21 12:16:08 +00:00
#ifdef WITH_DRIVER_MODULES
2010-03-09 19:22:22 +01:00
# include "driver.h"
2008-11-21 12:16:08 +00:00
#else
2010-03-09 19:22:22 +01:00
# ifdef WITH_QEMU
# include "qemu/qemu_driver.h"
# endif
# ifdef WITH_LXC
# include "lxc/lxc_driver.h"
# endif
# ifdef WITH_UML
# include "uml/uml_driver.h"
# endif
# ifdef WITH_ONE
# include "opennebula/one_driver.h"
# endif
# ifdef WITH_NETWORK
# include "network/bridge_driver.h"
# endif
# ifdef WITH_NETCF
# include "interface/netcf_driver.h"
# endif
# ifdef WITH_STORAGE_DIR
# include "storage/storage_driver.h"
# endif
# ifdef WITH_NODE_DEVICES
# include "node_device/node_device_driver.h"
# endif
# ifdef WITH_SECRETS
# include "secret/secret_driver.h"
# endif
2010-03-25 13:46:09 -04:00
# ifdef WITH_NWFILTER
# include "nwfilter/nwfilter_driver.h"
# endif
2009-12-22 14:50:50 +01:00
#endif
2008-11-17 12:18:18 +00:00
2009-01-22 17:49:41 +00:00
#ifdef __sun
2010-03-09 19:22:22 +01:00
# include <ucred.h>
# include <priv.h>
2009-01-22 17:49:41 +00:00
2010-03-09 19:22:22 +01:00
# ifndef PRIV_VIRT_MANAGE
# define PRIV_VIRT_MANAGE ((const char *)"virt_manage")
# endif
2009-01-22 17:49:41 +00:00
2010-03-09 19:22:22 +01:00
# ifndef PRIV_XVM_CONTROL
# define PRIV_XVM_CONTROL ((const char *)"xvm_control")
# endif
2009-01-22 17:49:41 +00:00
2010-03-09 19:22:22 +01:00
# define PU_RESETGROUPS 0x0001 /* Remove supplemental groups */
# define PU_CLEARLIMITSET 0x0008 /* L=0 */
2009-01-22 17:49:41 +00:00
extern int __init_daemon_priv ( int , uid_t , gid_t , ...);
2010-03-09 19:22:22 +01:00
# define SYSTEM_UID 60
2009-01-22 17:49:41 +00:00
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 12:04:54 +00:00
static int godaemon = 0 ; /* -d: Be a daemon */
static int verbose = 0 ; /* -v: Verbose mode */
2007-06-26 23:48:46 +00:00
static int timeout = - 1 ; /* -t: Shutdown timeout */
2007-06-11 12:04:54 +00:00
static int sigwrite = - 1 ; /* Signal handler pipe */
2007-06-26 23:48:46 +00:00
static int ipsock = 0 ; /* -l Listen for TCP/IP */
2007-06-11 12:04:54 +00:00
2007-06-26 23:48:46 +00:00
/* Defaults for configuration file elements */
2007-06-11 12:04:54 +00:00
static int listen_tls = 1 ;
static int listen_tcp = 0 ;
2008-05-14 20:57:20 +00:00
static char * listen_addr = ( char * ) LIBVIRTD_LISTEN_ADDR ;
2007-11-30 15:43:42 +00:00
static char * tls_port = ( char * ) LIBVIRTD_TLS_PORT ;
static char * tcp_port = ( char * ) LIBVIRTD_TCP_PORT ;
2007-06-11 12:04:54 +00:00
2009-02-09 17:52:38 +00:00
static char * unix_sock_dir = NULL ;
2007-12-05 18:21:27 +00:00
#if HAVE_POLKIT
static int auth_unix_rw = REMOTE_AUTH_POLKIT ;
static int auth_unix_ro = REMOTE_AUTH_POLKIT ;
#else
2007-12-05 15:34:05 +00:00
static int auth_unix_rw = REMOTE_AUTH_NONE ;
static int auth_unix_ro = REMOTE_AUTH_NONE ;
2007-12-05 18:21:27 +00:00
#endif /* HAVE_POLKIT */
2007-12-05 15:34:05 +00: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 01:56:55 +00:00
static int mdns_adv = 1 ;
2007-11-30 15:43:42 +00:00
static char * mdns_name = NULL ;
2007-09-19 01:56:55 +00:00
2007-06-11 12:04:54 +00:00
static int tls_no_verify_certificate = 0 ;
2007-11-30 15:43:42 +00:00
static char ** tls_allowed_dn_list = NULL ;
2007-06-11 12:04:54 +00:00
2007-11-30 15:43:42 +00: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 12:04:54 +00:00
static gnutls_certificate_credentials_t x509_cred ;
static gnutls_dh_params_t dh_params ;
2008-12-04 22:18:44 +00:00
static int min_workers = 5 ;
static int max_workers = 20 ;
static int max_clients = 20 ;
2009-01-20 19:25:15 +00: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 12:04:54 +00:00
#define DH_BITS 1024
2007-02-16 18:28:17 +00:00
2007-03-27 10:28:45 +00:00
static sig_atomic_t sig_errors = 0 ;
static int sig_lasterrno = 0 ;
2010-05-20 21:40:54 +02:00
static const char * argv0 ;
2007-03-27 10:28:45 +00:00
2009-10-16 12:14:54 +01: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 ,
2010-03-26 15:53:32 +01:00
VIR_DAEMON_ERR_HOOKS ,
2009-10-16 12:14:54 +01:00
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" ,
2010-03-26 15:53:32 +01:00
"Unable to load configuration file" ,
"Unable to look for hook scripts" )
2009-10-16 12:14:54 +01:00
2008-05-13 06:30:58 +00:00
static void sig_handler ( int sig , siginfo_t * siginfo ,
void * context ATTRIBUTE_UNUSED ) {
2007-02-16 18:28:17 +00:00
int origerrno ;
2007-03-27 10:28:45 +00:00
int r ;
2007-02-16 18:28:17 +00:00
2008-05-13 06:30:58 +00:00
/* set the sig num in the struct */
siginfo -> si_signo = sig ;
2007-02-16 18:28:17 +00:00
origerrno = errno ;
2008-05-13 06:30:58 +00:00
r = safewrite ( sigwrite , siginfo , sizeof ( * siginfo ));
2007-03-27 10:28:45 +00:00
if ( r == - 1 ) {
sig_errors ++ ;
sig_lasterrno = errno ;
}
2007-02-16 18:28:17 +00:00
errno = origerrno ;
2007-02-14 01:40:09 +00:00
}
2007-02-16 18:28:17 +00:00
2008-11-19 16:19:36 +00: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 19:27:11 +00:00
static int qemudStartWorker ( struct qemud_server * server , struct qemud_worker * worker );
2009-01-20 19:25:15 +00: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 12:20:03 +01:00
struct qemud_client_message *
2009-01-20 19:25:15 +00: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 19:11:00 +00:00
2007-07-12 14:54:45 +00:00
static int
remoteCheckCertFile ( const char * type , const char * file )
{
struct stat sb ;
if ( stat ( file , & sb ) < 0 ) {
2009-02-05 16:28:03 +00:00
char ebuf [ 1024 ];
VIR_ERROR ( _ ( "Cannot access %s '%s': %s" ),
type , file , virStrerror ( errno , ebuf , sizeof ebuf ));
2007-07-12 14:54:45 +00:00
return - 1 ;
}
return 0 ;
}
2007-06-11 12:04:54 +00:00
static int
remoteInitializeGnuTLS ( void )
{
int err ;
/* Initialise GnuTLS. */
gnutls_global_init ();
err = gnutls_certificate_allocate_credentials ( & x509_cred );
if ( err ) {
2009-01-06 18:32:03 +00:00
VIR_ERROR ( _ ( "gnutls_certificate_allocate_credentials: %s" ),
2007-06-11 12:04:54 +00:00
gnutls_strerror ( err ));
return - 1 ;
}
if ( ca_file && ca_file [ 0 ] != '\0' ) {
2007-07-12 14:54:45 +00:00
if ( remoteCheckCertFile ( "CA certificate" , ca_file ) < 0 )
return - 1 ;
2007-06-11 12:04:54 +00: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 18:32:03 +00:00
VIR_ERROR ( _ ( "gnutls_certificate_set_x509_trust_file: %s" ),
2007-06-11 12:04:54 +00:00
gnutls_strerror ( err ));
return - 1 ;
}
}
if ( crl_file && crl_file [ 0 ] != '\0' ) {
2007-11-21 23:16:11 +00:00
if ( remoteCheckCertFile ( "CA revocation list" , crl_file ) < 0 )
2007-07-12 14:54:45 +00:00
return - 1 ;
2008-12-22 12:53:26 +00:00
DEBUG ( "loading CRL from %s" , crl_file );
2007-06-11 12:04:54 +00:00
err = gnutls_certificate_set_x509_crl_file ( x509_cred , crl_file ,
GNUTLS_X509_FMT_PEM );
if ( err < 0 ) {
2009-01-06 18:32:03 +00:00
VIR_ERROR ( _ ( "gnutls_certificate_set_x509_crl_file: %s" ),
2007-06-11 12:04:54 +00:00
gnutls_strerror ( err ));
return - 1 ;
}
}
if ( cert_file && cert_file [ 0 ] != '\0' && key_file && key_file [ 0 ] != '\0' ) {
2007-07-12 14:54:45 +00:00
if ( remoteCheckCertFile ( "server certificate" , cert_file ) < 0 )
return - 1 ;
if ( remoteCheckCertFile ( "server key" , key_file ) < 0 )
return - 1 ;
2008-12-22 12:53:26 +00:00
DEBUG ( "loading cert and key from %s and %s" , cert_file , key_file );
2007-06-11 12:04:54 +00:00
err =
gnutls_certificate_set_x509_key_file ( x509_cred ,
cert_file , key_file ,
GNUTLS_X509_FMT_PEM );
if ( err < 0 ) {
2009-01-06 18:32:03 +00:00
VIR_ERROR ( _ ( "gnutls_certificate_set_x509_key_file: %s" ),
2007-06-11 12:04:54 +00: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 18:32:03 +00:00
VIR_ERROR ( _ ( "gnutls_dh_params_init: %s" ), gnutls_strerror ( err ));
2007-06-11 12:04:54 +00:00
return - 1 ;
}
err = gnutls_dh_params_generate2 ( dh_params , DH_BITS );
if ( err < 0 ) {
2009-01-06 18:32:03 +00:00
VIR_ERROR ( _ ( "gnutls_dh_params_generate2: %s" ), gnutls_strerror ( err ));
2007-06-11 12:04:54 +00:00
return - 1 ;
}
gnutls_certificate_set_dh_params ( x509_cred , dh_params );
return 0 ;
}
2008-10-23 13:18:18 +00:00
static void
2008-11-19 16:19:36 +00:00
qemudDispatchSignalEvent ( int watch ATTRIBUTE_UNUSED ,
int fd ATTRIBUTE_UNUSED ,
2008-10-23 13:18:18 +00:00
int events ATTRIBUTE_UNUSED ,
void * opaque ) {
2007-06-26 19:11:00 +00:00
struct qemud_server * server = ( struct qemud_server * ) opaque ;
2008-05-13 06:30:58 +00:00
siginfo_t siginfo ;
2007-02-16 18:28:17 +00:00
2009-01-15 19:56:05 +00:00
virMutexLock ( & server -> lock );
2008-12-04 22:16:40 +00:00
2008-05-13 06:30:58 +00:00
if ( saferead ( server -> sigread , & siginfo , sizeof ( siginfo )) != sizeof ( siginfo )) {
2009-02-05 16:28:03 +00:00
char ebuf [ 1024 ];
VIR_ERROR ( _ ( "Failed to read from signal pipe: %s" ),
virStrerror ( errno , ebuf , sizeof ebuf ));
2009-01-15 19:56:05 +00:00
virMutexUnlock ( & server -> lock );
2007-06-26 19:11:00 +00:00
return ;
2007-02-16 18:30:55 +00:00
}
2008-05-13 06:30:58 +00:00
switch ( siginfo . si_signo ) {
2007-02-16 18:28:17 +00:00
case SIGHUP :
2009-01-06 18:32:03 +00:00
VIR_INFO0 ( _ ( "Reloading configuration on SIGHUP" ));
2010-03-26 15:53:32 +01:00
virHookCall ( VIR_HOOK_DRIVER_DAEMON , "-" ,
VIR_HOOK_DAEMON_OP_RELOAD , SIGHUP , "SIGHUP" , NULL );
2007-06-26 22:56:14 +00:00
if ( virStateReload () < 0 )
2010-05-19 12:00:18 +02:00
VIR_WARN0 ( "Error while reloading drivers" );
2010-03-26 15:53:32 +01:00
2007-02-16 18:28:17 +00:00
break ;
case SIGINT :
2007-02-19 16:59:15 +00:00
case SIGQUIT :
2007-02-16 18:28:17 +00:00
case SIGTERM :
2010-05-19 12:00:18 +02:00
VIR_WARN ( "Shutting down on signal %d" , siginfo . si_signo );
2009-10-16 16:34:37 +01:00
server -> quitEventThread = 1 ;
2007-02-16 18:28:17 +00:00
break ;
default :
2009-01-06 18:32:03 +00:00
VIR_INFO ( _ ( "Received unexpected signal %d" ), siginfo . si_signo );
2007-02-16 18:28:17 +00:00
break ;
}
2009-01-15 19:56:05 +00:00
virMutexUnlock ( & server -> lock );
2007-02-16 18:28:17 +00:00
}
2007-02-16 18:30:55 +00:00
2009-10-16 12:14:54 +01:00
static int daemonForkIntoBackground ( void ) {
int statuspipe [ 2 ];
if ( pipe ( statuspipe ) < 0 )
return - 1 ;
2007-02-14 01:40:09 +00:00
int pid = fork ();
switch ( pid ) {
case 0 :
{
int stdinfd = - 1 ;
int stdoutfd = - 1 ;
2007-02-16 18:26:18 +00:00
int nextpid ;
2007-02-14 01:40:09 +00:00
2009-10-16 12:14:54 +01:00
close ( statuspipe [ 0 ]);
2008-12-17 18:04:55 +00:00
if (( stdinfd = open ( "/dev/null" , O_RDONLY )) < 0 )
2007-02-14 01:40:09 +00:00
goto cleanup ;
2008-12-17 18:04:55 +00:00
if (( stdoutfd = open ( "/dev/null" , O_WRONLY )) < 0 )
2007-02-14 01:40:09 +00: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 12:14:54 +01:00
return statuspipe [ 1 ];
2007-02-14 01:40:09 +00:00
case - 1 :
return - 1 ;
default :
2008-03-11 14:22:12 +00:00
_exit ( 0 );
2007-02-14 01:40:09 +00:00
}
cleanup :
if ( stdoutfd != - 1 )
close ( stdoutfd );
if ( stdinfd != - 1 )
close ( stdinfd );
return - 1 ;
}
case - 1 :
return - 1 ;
default :
{
2009-10-16 12:14:54 +01: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 01:40:09 +00:00
got != pid ||
2009-10-16 12:14:54 +01:00
exitstatus != 0 ) {
2007-02-14 01:40:09 +00:00
return - 1 ;
}
2009-10-16 12:14:54 +01: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 11:29:35 -05:00
fprintf ( stderr ,
2010-05-20 21:40:54 +02:00
_ ( "%s: error: %s. Check /var/log/messages or run without "
"--daemon for more info. \n " ), argv0 ,
2010-02-24 11:29:35 -05:00
virDaemonErrTypeToString ( status ));
2009-10-16 12:14:54 +01:00
}
_exit ( ret == 1 && status == 0 ? 0 : 1 );
2007-02-14 01:40:09 +00:00
}
}
}
2007-02-23 12:48:36 +00:00
static int qemudWritePidFile ( const char * pidFile ) {
int fd ;
FILE * fh ;
2009-02-05 16:28:03 +00:00
char ebuf [ 1024 ];
2007-02-23 12:48:36 +00:00
if ( pidFile [ 0 ] == '\0' )
return 0 ;
if (( fd = open ( pidFile , O_WRONLY | O_CREAT | O_EXCL , 0644 )) < 0 ) {
2009-01-06 18:32:03 +00:00
VIR_ERROR ( _ ( "Failed to open pid file '%s' : %s" ),
2009-02-05 16:28:03 +00:00
pidFile , virStrerror ( errno , ebuf , sizeof ebuf ));
2007-02-23 12:48:36 +00:00
return - 1 ;
}
if ( ! ( fh = fdopen ( fd , "w" ))) {
2009-01-06 18:32:03 +00:00
VIR_ERROR ( _ ( "Failed to fdopen pid file '%s' : %s" ),
2009-02-05 16:28:03 +00:00
pidFile , virStrerror ( errno , ebuf , sizeof ebuf ));
2007-02-23 12:48:36 +00:00
close ( fd );
return - 1 ;
}
if ( fprintf ( fh , "%lu \n " , ( unsigned long ) getpid ()) < 0 ) {
2010-05-20 21:40:54 +02:00
VIR_ERROR ( _ ( "%s: Failed to write to pid file '%s' : %s" ),
argv0 , pidFile , virStrerror ( errno , ebuf , sizeof ebuf ));
2009-03-16 10:41:37 +00:00
fclose ( fh );
2007-02-23 12:48:36 +00:00
return - 1 ;
}
if ( fclose ( fh ) == EOF ) {
2010-05-20 21:40:54 +02:00
VIR_ERROR ( _ ( "%s: Failed to close pid file '%s' : %s" ),
argv0 , pidFile , virStrerror ( errno , ebuf , sizeof ebuf ));
2007-02-23 12:48:36 +00:00
return - 1 ;
}
return 0 ;
}
2007-02-14 01:40:09 +00:00
static int qemudListenUnix ( struct qemud_server * server ,
2010-06-03 14:36:34 +01:00
char * path , int readonly , int auth ) {
2008-06-06 10:52:01 +00:00
struct qemud_socket * sock ;
2007-02-14 01:40:09 +00:00
struct sockaddr_un addr ;
mode_t oldmask ;
2007-09-19 02:28:01 +00:00
gid_t oldgrp ;
2009-02-05 16:28:03 +00:00
char ebuf [ 1024 ];
2007-02-14 01:40:09 +00:00
2008-06-06 10:52:01 +00:00
if ( VIR_ALLOC ( sock ) < 0 ) {
2010-05-20 08:10:38 +02:00
VIR_ERROR0 ( _ ( "Failed to allocate memory for struct qemud_socket" ));
2007-02-14 01:40:09 +00:00
return - 1 ;
2007-02-16 18:30:55 +00:00
}
2007-02-14 01:40:09 +00:00
sock -> readonly = readonly ;
2007-09-19 01:56:55 +00:00
sock -> port = - 1 ;
2007-12-05 15:27:08 +00:00
sock -> type = QEMUD_SOCK_TYPE_UNIX ;
2007-12-05 15:34:05 +00:00
sock -> auth = auth ;
2010-06-03 14:36:34 +01:00
sock -> path = path ;
2007-02-14 01:40:09 +00:00
2007-02-16 18:30:55 +00:00
if (( sock -> fd = socket ( PF_UNIX , SOCK_STREAM , 0 )) < 0 ) {
2009-01-06 18:32:03 +00:00
VIR_ERROR ( _ ( "Failed to create socket: %s" ),
2009-02-05 16:28:03 +00:00
virStrerror ( errno , ebuf , sizeof ebuf ));
2007-06-26 19:11:00 +00:00
goto cleanup ;
2007-02-16 18:30:55 +00:00
}
2007-02-14 01:40:09 +00:00
2009-05-12 15:43:07 +00:00
if ( virSetCloseExec ( sock -> fd ) < 0 ||
virSetNonBlock ( sock -> fd ) < 0 )
2007-06-26 19:11:00 +00:00
goto cleanup ;
2007-02-14 01:40:09 +00:00
memset ( & addr , 0 , sizeof ( addr ));
addr . sun_family = AF_UNIX ;
2009-08-03 14:37:44 +02:00
if ( virStrcpyStatic ( addr . sun_path , path ) == NULL ) {
VIR_ERROR ( _ ( "Path %s too long for unix socket" ), path );
goto cleanup ;
}
2007-02-14 01:40:09 +00:00
if ( addr . sun_path [ 0 ] == '@' )
addr . sun_path [ 0 ] = '\0' ;
2007-09-19 02:28:01 +00:00
oldgrp = getgid ();
2007-11-30 15:43:42 +00:00
oldmask = umask ( readonly ? ~ unix_sock_ro_mask : ~ unix_sock_rw_mask );
2010-02-26 10:42:14 +01:00
if ( server -> privileged && setgid ( unix_sock_gid )) {
VIR_ERROR ( _ ( "Failed to set group ID to %d" ), unix_sock_gid );
goto cleanup ;
}
2007-09-19 02:28:01 +00:00
2007-02-16 18:30:55 +00:00
if ( bind ( sock -> fd , ( struct sockaddr * ) & addr , sizeof ( addr )) < 0 ) {
2009-01-06 18:32:03 +00:00
VIR_ERROR ( _ ( "Failed to bind socket to '%s': %s" ),
2009-02-05 16:28:03 +00:00
path , virStrerror ( errno , ebuf , sizeof ebuf ));
2007-06-26 19:11:00 +00:00
goto cleanup ;
2007-02-16 18:30:55 +00:00
}
2007-02-14 01:40:09 +00:00
umask ( oldmask );
2010-02-26 10:42:14 +01:00
if ( server -> privileged && setgid ( oldgrp )) {
VIR_ERROR ( _ ( "Failed to restore group ID to %d" ), oldgrp );
goto cleanup ;
}
2007-02-14 01:40:09 +00:00
2007-02-16 18:30:55 +00:00
if ( listen ( sock -> fd , 30 ) < 0 ) {
2009-01-06 18:32:03 +00:00
VIR_ERROR ( _ ( "Failed to listen for connections on '%s': %s" ),
2009-02-05 16:28:03 +00:00
path , virStrerror ( errno , ebuf , sizeof ebuf ));
2007-06-26 19:11:00 +00:00
goto cleanup ;
}
sock -> next = server -> sockets ;
server -> sockets = sock ;
server -> nsockets ++ ;
2007-02-14 01:40:09 +00:00
return 0 ;
2007-06-26 19:11:00 +00:00
cleanup :
2010-02-02 11:27:25 +01:00
if ( sock -> fd >= 0 )
2007-06-26 19:11:00 +00:00
close ( sock -> fd );
2009-12-10 00:00:50 +01:00
VIR_FREE ( sock );
2007-06-26 19:11:00 +00:00
return - 1 ;
2007-02-14 01:40:09 +00:00
}
2007-06-11 12:04:54 +00:00
// See: http://people.redhat.com/drepper/userapi-ipv6.html
static int
2008-05-14 20:57:20 +00:00
remoteMakeSockets ( int * fds , int max_fds , int * nfds_r , const char * node , const char * service )
2007-06-11 12:04:54 +00: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-14 20:57:20 +00:00
int e = getaddrinfo ( node , service , & hints , & ai );
2007-06-11 12:04:54 +00:00
if ( e != 0 ) {
2010-01-19 14:17:20 +01:00
VIR_ERROR ( _ ( "getaddrinfo: %s" ), gai_strerror ( e ));
2007-06-11 12:04:54 +00:00
return - 1 ;
}
struct addrinfo * runp = ai ;
while ( runp && * nfds_r < max_fds ) {
2009-02-05 16:28:03 +00:00
char ebuf [ 1024 ];
2007-06-11 12:04:54 +00:00
fds [ * nfds_r ] = socket ( runp -> ai_family , runp -> ai_socktype ,
runp -> ai_protocol );
if ( fds [ * nfds_r ] == - 1 ) {
2009-02-05 16:28:03 +00:00
VIR_ERROR ( _ ( "socket: %s" ), virStrerror ( errno , ebuf , sizeof ebuf ));
2007-06-11 12:04:54 +00:00
return - 1 ;
}
int opt = 1 ;
setsockopt ( fds [ * nfds_r ], SOL_SOCKET , SO_REUSEADDR , & opt , sizeof opt );
2009-11-11 15:19:50 +00: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 12:04:54 +00:00
if ( bind ( fds [ * nfds_r ], runp -> ai_addr , runp -> ai_addrlen ) == - 1 ) {
if ( errno != EADDRINUSE ) {
2009-02-05 16:28:03 +00:00
VIR_ERROR ( _ ( "bind: %s" ), virStrerror ( errno , ebuf , sizeof ebuf ));
2007-06-11 12:04:54 +00:00
return - 1 ;
}
close ( fds [ * nfds_r ]);
2009-10-16 11:24:01 +01:00
} else {
2007-06-11 12:04:54 +00:00
++* nfds_r ;
}
runp = runp -> ai_next ;
}
2007-02-23 09:10:28 +00:00
2007-06-11 12:04:54 +00: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-14 21:23:02 +00:00
const char * addr ,
2007-06-11 12:04:54 +00:00
const char * port ,
2007-12-05 15:27:08 +00:00
int type ,
2007-12-05 15:24:15 +00:00
int auth )
2007-06-11 12:04:54 +00:00
{
int fds [ 2 ];
int nfds = 0 ;
2007-02-23 09:10:28 +00:00
int i ;
2007-06-11 12:04:54 +00:00
struct qemud_socket * sock ;
2008-05-14 20:57:20 +00:00
if ( remoteMakeSockets ( fds , 2 , & nfds , addr , port ) == - 1 )
2007-06-11 12:04:54 +00:00
return - 1 ;
for ( i = 0 ; i < nfds ; ++ i ) {
2009-02-13 19:10:55 +00: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 16:28:03 +00:00
char ebuf [ 1024 ];
2009-02-13 19:10:55 +00:00
socklen_t salen = sizeof ( s );
2007-09-19 01:56:55 +00:00
2008-06-06 10:52:01 +00:00
if ( VIR_ALLOC ( sock ) < 0 ) {
2009-02-05 16:28:03 +00:00
VIR_ERROR ( _ ( "remoteListenTCP: calloc: %s" ),
virStrerror ( errno , ebuf , sizeof ebuf ));
2008-06-06 10:52:01 +00:00
goto cleanup ;
2007-06-11 12:04:54 +00:00
}
sock -> readonly = 0 ;
sock -> next = server -> sockets ;
server -> sockets = sock ;
server -> nsockets ++ ;
sock -> fd = fds [ i ];
2007-12-05 15:27:08 +00:00
sock -> type = type ;
2007-12-05 15:24:15 +00:00
sock -> auth = auth ;
2007-02-14 01:40:09 +00:00
2009-02-13 19:10:55 +00:00
if ( getsockname ( sock -> fd , & s . sa , & salen ) < 0 )
2008-06-06 10:52:01 +00:00
goto cleanup ;
2007-09-19 01:56:55 +00:00
2009-02-13 19:10:55 +00:00
if ( s . sa . sa_family == AF_INET ) {
sock -> port = htons ( s . sa_in . sin_port );
2007-11-26 11:56:41 +00:00
#ifdef AF_INET6
2009-02-13 19:10:55 +00:00
} else if ( s . sa . sa_family == AF_INET6 )
sock -> port = htons ( s . sa_in6 . sin6_port );
2007-11-26 11:56:41 +00:00
#endif
2007-09-19 01:56:55 +00:00
else
sock -> port = - 1 ;
2009-05-12 15:43:07 +00:00
if ( virSetCloseExec ( sock -> fd ) < 0 ||
virSetNonBlock ( sock -> fd ) < 0 )
2008-06-06 10:52:01 +00:00
goto cleanup ;
2007-06-11 12:04:54 +00:00
if ( listen ( sock -> fd , 30 ) < 0 ) {
2009-02-05 16:28:03 +00:00
VIR_ERROR ( _ ( "remoteListenTCP: listen: %s" ),
virStrerror ( errno , ebuf , sizeof ebuf ));
2008-06-06 10:52:01 +00:00
goto cleanup ;
2007-02-20 09:04:27 +00:00
}
2007-06-11 12:04:54 +00:00
}
return 0 ;
2008-06-06 10:52:01 +00:00
cleanup :
for ( i = 0 ; i < nfds ; ++ i )
2009-02-17 14:40:24 +00:00
close ( fds [ i ]);
2008-06-06 10:52:01 +00:00
return - 1 ;
2007-06-11 12:04:54 +00:00
}
static int qemudInitPaths ( struct qemud_server * server ,
2010-06-03 14:36:34 +01:00
char ** sockname ,
char ** roSockname )
2009-01-22 17:49:41 +00:00
{
2010-06-03 14:36:34 +01:00
char * base_dir_prefix = NULL ;
2009-02-09 17:52:38 +00:00
char * sock_dir_prefix = NULL ;
2010-06-03 14:36:34 +01:00
int ret = - 1 ;
/* The base_dir_prefix is the base under which all libvirtd
* files live */
if ( server -> privileged ) {
if ( ! ( base_dir_prefix = strdup ( LOCAL_STATE_DIR )))
goto no_memory ;
} else {
uid_t uid = geteuid ();
if ( ! ( base_dir_prefix = virGetUserDirectory ( uid )))
goto cleanup ;
}
2009-02-09 17:52:38 +00:00
2010-06-03 14:36:34 +01:00
/* The unix_sock_dir is the location under which all
* unix domain sockets live */
2009-10-16 11:29:01 +01:00
if ( unix_sock_dir ) {
2010-06-03 14:36:34 +01:00
if ( ! ( sock_dir_prefix = strdup ( unix_sock_dir )))
goto no_memory ;
2009-10-16 11:29:01 +01: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-06-12 13:20:13 +00:00
if ( server -> privileged ) {
2010-06-03 14:36:34 +01:00
if ( virAsprintf ( & sock_dir_prefix , "%s/run/libvirt" ,
base_dir_prefix ) < 0 )
goto no_memory ;
2009-02-09 17:52:38 +00:00
} else {
2010-06-03 14:36:34 +01:00
if ( virAsprintf ( & sock_dir_prefix , "%s/.libvirt" ,
base_dir_prefix ) < 0 )
goto no_memory ;
2009-02-09 17:52:38 +00:00
}
}
2007-02-16 18:30:55 +00:00
2009-06-12 13:20:13 +00:00
if ( server -> privileged ) {
2010-06-03 14:36:34 +01:00
if ( virAsprintf ( sockname , "%s/libvirt-sock" ,
sock_dir_prefix ) < 0 )
goto no_memory ;
if ( virAsprintf ( roSockname , "%s/libvirt-sock-ro" ,
sock_dir_prefix ) < 0 )
goto no_memory ;
unlink ( * sockname );
unlink ( * roSockname );
2007-02-14 01:40:09 +00:00
} else {
2010-06-03 14:36:34 +01:00
if ( virAsprintf ( sockname , "@%s/libvirt-sock" ,
sock_dir_prefix ) < 0 )
goto no_memory ;
/* There is no RO socket in unprivileged mode,
* since the user always has full RW access
* to their private instance */
2009-02-09 17:52:38 +00:00
}
2007-06-11 12:04:54 +00:00
2009-10-16 11:09:13 +01:00
if ( server -> privileged ) {
2010-06-03 14:36:34 +01:00
if ( virAsprintf ( & server -> logDir , "%s/log/libvirt" ,
base_dir_prefix ) < 0 )
goto no_memory ;
2009-10-16 11:09:13 +01:00
} else {
2010-06-03 14:36:34 +01:00
if ( virAsprintf ( & server -> logDir , "%s/.libvirt/log" ,
base_dir_prefix ) < 0 )
goto no_memory ;
2009-10-16 11:09:13 +01:00
}
2007-06-11 12:04:54 +00:00
2009-02-09 17:52:38 +00:00
ret = 0 ;
2007-02-16 18:30:55 +00:00
2010-06-03 14:36:34 +01:00
no_memory :
if ( ret != 0 )
virReportOOMError ();
2009-02-09 17:52:38 +00:00
cleanup :
2010-06-03 14:36:34 +01:00
VIR_FREE ( base_dir_prefix );
2009-12-10 00:00:50 +01:00
VIR_FREE ( sock_dir_prefix );
2009-02-09 17:52:38 +00:00
return ret ;
2007-02-14 01:40:09 +00:00
}
2009-10-19 18:28:28 +01: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 11:48:50 +01:00
static struct qemud_server * qemudInitialize ( void ) {
2007-02-14 01:40:09 +00:00
struct qemud_server * server ;
2008-06-06 10:52:01 +00:00
if ( VIR_ALLOC ( server ) < 0 ) {
2009-01-06 18:32:03 +00:00
VIR_ERROR0 ( _ ( "Failed to allocate struct qemud_server" ));
2007-02-14 01:40:09 +00:00
return NULL ;
2007-02-16 18:30:55 +00:00
}
2007-02-14 01:40:09 +00:00
2009-10-16 11:48:50 +01:00
server -> privileged = geteuid () == 0 ? 1 : 0 ;
server -> sigread = server -> sigwrite = - 1 ;
2009-01-15 19:56:05 +00:00
if ( virMutexInit ( & server -> lock ) < 0 ) {
2010-05-20 08:10:38 +02:00
VIR_ERROR0 ( _ ( "cannot initialize mutex" ));
2009-01-15 19:56:05 +00:00
VIR_FREE ( server );
2009-10-16 11:48:50 +01:00
return NULL ;
2009-01-15 19:56:05 +00:00
}
if ( virCondInit ( & server -> job ) < 0 ) {
2010-05-20 08:10:38 +02:00
VIR_ERROR0 ( _ ( "cannot initialize condition variable" ));
2009-01-15 19:56:05 +00:00
virMutexDestroy ( & server -> lock );
2008-12-04 22:16:40 +00:00
VIR_FREE ( server );
2009-10-16 11:48:50 +01:00
return NULL ;
2008-12-04 22:16:40 +00:00
}
2008-12-04 22:14:15 +00:00
if ( virEventInit () < 0 ) {
2009-01-06 18:32:03 +00:00
VIR_ERROR0 ( _ ( "Failed to initialize event system" ));
2009-10-16 11:48:50 +01:00
virMutexDestroy ( & server -> lock );
if ( virCondDestroy ( & server -> job ) < 0 )
{}
2008-12-04 22:14:15 +00:00
VIR_FREE ( server );
return NULL ;
}
2008-12-02 11:37:55 +00: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 12:16:08 +00: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 00:02:46 +01:00
* If they try to open a connection for a module that
2008-11-21 12:16:08 +00:00
* is not loaded they'll get a suitable error at that point
*/
virDriverLoadModule ( "network" );
virDriverLoadModule ( "storage" );
2008-11-21 12:27:11 +00:00
virDriverLoadModule ( "nodedev" );
2009-08-14 21:48:55 +02:00
virDriverLoadModule ( "secret" );
2008-12-02 11:37:55 +00:00
virDriverLoadModule ( "qemu" );
virDriverLoadModule ( "lxc" );
virDriverLoadModule ( "uml" );
2009-05-25 11:56:00 +00:00
virDriverLoadModule ( "one" );
2010-03-25 13:46:09 -04:00
virDriverLoadModule ( "nwfilter" );
2008-11-21 12:16:08 +00:00
#else
2010-03-09 19:22:22 +01:00
# ifdef WITH_NETWORK
2008-11-17 12:18:18 +00:00
networkRegister ();
2010-03-09 19:22:22 +01:00
# endif
# ifdef WITH_NETCF
2009-07-21 16:02:16 +02:00
interfaceRegister ();
2010-03-09 19:22:22 +01:00
# endif
# ifdef WITH_STORAGE_DIR
2008-11-17 12:18:18 +00:00
storageRegister ();
2010-03-09 19:22:22 +01:00
# endif
# if defined(WITH_NODE_DEVICES)
2008-11-21 12:27:11 +00:00
nodedevRegister ();
2010-03-09 19:22:22 +01:00
# endif
# ifdef WITH_SECRETS
2009-08-14 21:48:55 +02:00
secretRegister ();
2010-03-09 19:22:22 +01:00
# endif
2010-03-25 13:46:09 -04:00
# ifdef WITH_NWFILTER
nwfilterRegister ();
# endif
2010-03-09 19:22:22 +01:00
# ifdef WITH_QEMU
2008-12-02 11:37:55 +00:00
qemuRegister ();
2010-03-09 19:22:22 +01:00
# endif
# ifdef WITH_LXC
2008-12-02 11:37:55 +00:00
lxcRegister ();
2010-03-09 19:22:22 +01:00
# endif
# ifdef WITH_UML
2008-12-02 11:37:55 +00:00
umlRegister ();
2010-03-09 19:22:22 +01:00
# endif
# ifdef WITH_ONE
2009-05-25 11:56:00 +00:00
oneRegister ();
2010-03-09 19:22:22 +01:00
# endif
2008-11-17 12:18:18 +00:00
#endif
2008-10-23 13:18:18 +00:00
virEventRegisterImpl ( virEventAddHandleImpl ,
virEventUpdateHandleImpl ,
virEventRemoveHandleImpl ,
virEventAddTimeoutImpl ,
virEventUpdateTimeoutImpl ,
virEventRemoveTimeoutImpl );
2007-06-26 23:48:46 +00:00
2007-12-05 15:34:05 +00:00
return server ;
}
2009-10-16 11:24:01 +01:00
static int qemudNetworkInit ( struct qemud_server * server ) {
2010-06-03 14:36:34 +01:00
char * sockname = NULL ;
char * roSockname = NULL ;
2007-12-05 15:24:15 +00:00
#if HAVE_SASL
2007-12-05 15:34:05 +00:00
int err ;
#endif /* HAVE_SASL */
2010-06-03 14:36:34 +01:00
if ( qemudInitPaths ( server , & sockname , & roSockname ) < 0 )
2007-12-05 15:34:05 +00:00
goto cleanup ;
if ( qemudListenUnix ( server , sockname , 0 , auth_unix_rw ) < 0 )
2007-12-05 15:24:15 +00:00
goto cleanup ;
2010-06-03 14:36:34 +01:00
sockname = NULL ;
2007-12-05 15:34:05 +00:00
2010-06-03 14:36:34 +01:00
if ( roSockname != NULL && qemudListenUnix ( server , roSockname , 1 , auth_unix_ro ) < 0 )
2007-12-05 15:34:05 +00:00
goto cleanup ;
2010-06-03 14:36:34 +01:00
roSockname = NULL ;
2007-12-05 15:34:05 +00:00
#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 18:32:03 +00:00
VIR_ERROR ( _ ( "Failed to initialize SASL authentication %s" ),
sasl_errstring ( err , NULL , NULL ));
2007-12-05 15:34:05 +00:00
goto cleanup ;
}
2007-12-05 15:24:15 +00:00
}
#endif
2009-08-06 13:54:08 +01:00
#if HAVE_POLKIT0
2007-12-05 18:21:27 +00:00
if ( auth_unix_rw == REMOTE_AUTH_POLKIT ||
auth_unix_ro == REMOTE_AUTH_POLKIT ) {
DBusError derr ;
2009-03-02 11:13:37 +00:00
dbus_connection_set_change_sigpipe ( FALSE );
dbus_threads_init_default ();
2007-12-05 18:21:27 +00:00
dbus_error_init ( & derr );
server -> sysbus = dbus_bus_get ( DBUS_BUS_SYSTEM , & derr );
if ( ! ( server -> sysbus )) {
2009-01-06 18:32:03 +00:00
VIR_ERROR ( _ ( "Failed to connect to system bus for PolicyKit auth: %s" ),
derr . message );
2007-12-05 18:21:27 +00:00
dbus_error_free ( & derr );
goto cleanup ;
}
2009-03-02 11:13:37 +00:00
dbus_connection_set_exit_on_disconnect ( server -> sysbus , FALSE );
2007-12-05 18:21:27 +00:00
}
#endif
2007-06-26 23:48:46 +00:00
if ( ipsock ) {
2008-05-14 20:57:20 +00:00
if ( listen_tcp && remoteListenTCP ( server , listen_addr , tcp_port , QEMUD_SOCK_TYPE_TCP , auth_tcp ) < 0 )
2007-06-11 12:04:54 +00:00
goto cleanup ;
if ( listen_tls ) {
if ( remoteInitializeGnuTLS () < 0 )
goto cleanup ;
2008-05-14 20:57:20 +00:00
if ( remoteListenTCP ( server , listen_addr , tls_port , QEMUD_SOCK_TYPE_TLS , auth_tls ) < 0 )
2007-06-11 12:04:54 +00:00
goto cleanup ;
}
2007-02-14 01:40:09 +00:00
}
2007-09-19 01:56:55 +00:00
#ifdef HAVE_AVAHI
2009-06-12 13:20:13 +00:00
if ( server -> privileged && mdns_adv ) {
2007-09-19 01:56:55 +00:00
struct libvirtd_mdns_group * group ;
2009-10-16 11:24:01 +01:00
struct qemud_socket * sock ;
2007-09-19 01:56:55 +00:00
int port = 0 ;
2010-03-23 09:01:37 -04:00
int ret ;
2007-09-19 01:56:55 +00:00
server -> mdns = libvirtd_mdns_new ();
if ( ! mdns_name ) {
2010-03-23 09:01:37 -04:00
char * groupname , * localhost , * tmp ;
2009-10-23 13:01:22 -04:00
localhost = virGetHostname ( NULL );
if ( localhost == NULL )
2010-03-23 09:01:37 -04:00
/* we couldn't resolve the hostname; assume that we are
* running in disconnected operation, and report a less
* useful Avahi string
*/
ret = virAsprintf ( & groupname , "Virtualization Host" );
else {
/* Extract the host part of the potentially FQDN */
if (( tmp = strchr ( localhost , '.' )))
* tmp = '\0' ;
ret = virAsprintf ( & groupname , "Virtualization Host %s" ,
localhost );
}
VIR_FREE ( localhost );
if ( ret < 0 ) {
virReportOOMError ();
2009-10-23 12:05:01 +02:00
goto cleanup ;
2010-03-23 09:01:37 -04:00
}
2007-09-19 01:56:55 +00:00
group = libvirtd_mdns_add_group ( server -> mdns , groupname );
2010-03-23 09:01:37 -04:00
VIR_FREE ( groupname );
2007-09-19 01:56:55 +00:00
} else {
group = libvirtd_mdns_add_group ( server -> mdns , mdns_name );
}
2007-11-30 15:43:42 +00:00
/*
2007-09-19 01:56:55 +00: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 15:27:08 +00:00
if ( sock -> port != - 1 && sock -> type == QEMUD_SOCK_TYPE_TLS ) {
2007-09-19 01:56:55 +00:00
port = sock -> port ;
break ;
}
sock = sock -> next ;
}
2007-11-30 15:43:42 +00:00
2007-09-19 01:56:55 +00: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 11:24:01 +01:00
return 0 ;
2007-02-14 01:40:09 +00:00
cleanup :
2010-06-03 14:36:34 +01:00
VIR_FREE ( sockname );
VIR_FREE ( roSockname );
2009-10-16 11:24:01 +01:00
return - 1 ;
2007-02-14 01:40:09 +00:00
}
2009-10-16 16:34:37 +01: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 11:24:01 +01:00
2010-06-03 14:36:34 +01:00
2007-06-11 12:04:54 +00: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 18:32:03 +00:00
VIR_ERROR ( _ ( "remoteInitializeTLSSession: %s" ),
2007-06-11 12:04:54 +00: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 ;
2007-11-30 15:43:42 +00:00
char ** wildcards ;
2007-06-11 12:04:54 +00:00
int err ;
err = gnutls_x509_crt_get_dn ( cert , name , & namesize );
if ( err != 0 ) {
2009-01-06 18:32:03 +00:00
VIR_ERROR ( _ ( "remoteCheckDN: gnutls_x509_cert_get_dn: %s" ),
2007-06-11 12:04:54 +00: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 12:53:26 +00:00
DEBUG ( _ ( "remoteCheckDN: failed: client DN is %s" ), name );
2007-06-11 12:04:54 +00: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 18:32:03 +00:00
VIR_ERROR ( _ ( "remoteCheckCertificate: verify failed: %s" ),
2007-06-11 12:04:54 +00:00
gnutls_strerror ( ret ));
return - 1 ;
}
if ( status != 0 ) {
if ( status & GNUTLS_CERT_INVALID )
2009-01-06 18:32:03 +00:00
VIR_ERROR0 ( _ ( "remoteCheckCertificate: "
"the client certificate is not trusted." ));
2007-06-11 12:04:54 +00:00
if ( status & GNUTLS_CERT_SIGNER_NOT_FOUND )
2009-01-06 18:32:03 +00:00
VIR_ERROR0 ( _ ( "remoteCheckCertificate: the client "
"certificate has unknown issuer." ));
2007-06-11 12:04:54 +00:00
if ( status & GNUTLS_CERT_REVOKED )
2009-01-06 18:32:03 +00:00
VIR_ERROR0 ( _ ( "remoteCheckCertificate: "
"the client certificate has been revoked." ));
2007-06-11 12:04:54 +00:00
2007-08-07 13:02:35 +00:00
#ifndef GNUTLS_1_0_COMPAT
2007-06-11 12:04:54 +00:00
if ( status & GNUTLS_CERT_INSECURE_ALGORITHM )
2009-01-06 18:32:03 +00:00
VIR_ERROR0 ( _ ( "remoteCheckCertificate: the client certificate"
" uses an insecure algorithm." ));
2007-08-07 13:02:35 +00:00
#endif
2007-06-11 12:04:54 +00:00
return - 1 ;
}
if ( gnutls_certificate_type_get ( session ) != GNUTLS_CRT_X509 ) {
2009-01-06 18:32:03 +00:00
VIR_ERROR0 ( _ ( "remoteCheckCertificate: certificate is not X.509" ));
2007-06-11 12:04:54 +00:00
return - 1 ;
}
if ( ! ( certs = gnutls_certificate_get_peers ( session , & nCerts ))) {
2009-01-06 18:32:03 +00:00
VIR_ERROR0 ( _ ( "remoteCheckCertificate: no peers" ));
2007-06-11 12:04:54 +00: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 18:32:03 +00:00
VIR_ERROR0 ( _ ( "remoteCheckCertificate: gnutls_x509_crt_init failed" ));
2007-06-11 12:04:54 +00:00
return - 1 ;
}
if ( gnutls_x509_crt_import ( cert , & certs [ i ], GNUTLS_X509_FMT_DER ) < 0 ) {
gnutls_x509_crt_deinit ( cert );
return - 1 ;
}
2007-11-30 15:43:42 +00:00
2007-06-11 12:04:54 +00:00
if ( gnutls_x509_crt_get_expiration_time ( cert ) < now ) {
2009-01-06 18:32:03 +00:00
VIR_ERROR0 ( _ ( "remoteCheckCertificate: "
"the client certificate has expired" ));
2007-06-11 12:04:54 +00:00
gnutls_x509_crt_deinit ( cert );
return - 1 ;
}
2007-11-30 15:43:42 +00:00
2007-06-11 12:04:54 +00:00
if ( gnutls_x509_crt_get_activation_time ( cert ) > now ) {
2009-01-06 18:32:03 +00:00
VIR_ERROR0 ( _ ( "remoteCheckCertificate: the client "
"certificate is not yet activated" ));
2007-06-11 12:04:54 +00: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 18:32:03 +00: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 12:04:54 +00: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 19:25:15 +00:00
struct qemud_client_message * confirm ;
2007-06-11 12:04:54 +00:00
/* Verify client certificate. */
2007-12-05 15:27:08 +00:00
if ( remoteCheckCertificate ( client -> tlssession ) == - 1 ) {
2009-01-06 18:32:03 +00:00
VIR_ERROR0 ( _ ( "remoteCheckCertificate: "
"failed to verify client's certificate" ));
2007-06-11 12:04:54 +00:00
if ( ! tls_no_verify_certificate ) return - 1 ;
2009-01-06 18:32:03 +00:00
else VIR_INFO0 ( _ ( "remoteCheckCertificate: tls_no_verify_certificate "
"is set so the bad certificate is ignored" ));
2007-06-11 12:04:54 +00:00
}
2009-01-20 19:25:15 +00: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 12:04:54 +00: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 19:25:15 +00:00
confirm -> async = 1 ;
confirm -> bufferLength = 1 ;
confirm -> bufferOffset = 0 ;
confirm -> buffer [ 0 ] = '\1' ;
client -> tx = confirm ;
2007-06-11 12:04:54 +00:00
return 0 ;
}
2007-02-14 01:40:09 +00:00
2008-04-04 15:09:19 +00:00
#if HAVE_POLKIT
int qemudGetSocketIdentity ( int fd , uid_t * uid , pid_t * pid ) {
2010-03-09 19:22:22 +01:00
# ifdef SO_PEERCRED
2008-04-04 15:09:19 +00:00
struct ucred cr ;
unsigned int cr_len = sizeof ( cr );
if ( getsockopt ( fd , SOL_SOCKET , SO_PEERCRED , & cr , & cr_len ) < 0 ) {
2009-02-05 16:28:03 +00:00
char ebuf [ 1024 ];
2009-01-06 18:32:03 +00:00
VIR_ERROR ( _ ( "Failed to verify client credentials: %s" ),
2009-02-05 16:28:03 +00:00
virStrerror ( errno , ebuf , sizeof ebuf ));
2008-04-04 15:09:19 +00:00
return - 1 ;
}
* pid = cr . pid ;
* uid = cr . uid ;
2010-03-09 19:22:22 +01:00
# else
2008-04-04 15:09:19 +00:00
/* XXX Many more OS support UNIX socket credentials we could port to. See dbus ....*/
2010-03-09 19:22:22 +01:00
# error "UNIX socket credentials not supported/implemented on this platform yet..."
# endif
2008-04-04 15:09:19 +00:00
return 0 ;
}
#endif
2009-01-20 19:25:15 +00:00
2007-02-14 01:40:09 +00:00
static int qemudDispatchServer ( struct qemud_server * server , struct qemud_socket * sock ) {
int fd ;
struct sockaddr_storage addr ;
2007-06-11 12:04:54 +00:00
socklen_t addrlen = ( socklen_t ) ( sizeof addr );
2007-02-14 01:40:09 +00:00
struct qemud_client * client ;
2007-06-11 12:04:54 +00:00
int no_slow_start = 1 ;
2010-03-18 14:56:56 +00:00
int i ;
2007-02-14 01:40:09 +00:00
if (( fd = accept ( sock -> fd , ( struct sockaddr * ) & addr , & addrlen )) < 0 ) {
2009-02-05 16:28:03 +00:00
char ebuf [ 1024 ];
2007-02-14 01:40:09 +00:00
if ( errno == EAGAIN )
return 0 ;
2009-02-05 16:28:03 +00:00
VIR_ERROR ( _ ( "Failed to accept connection: %s" ),
virStrerror ( errno , ebuf , sizeof ebuf ));
2007-02-14 01:40:09 +00:00
return - 1 ;
}
2008-12-04 22:18:44 +00:00
if ( server -> nclients >= max_clients ) {
2009-01-20 19:25:15 +00:00
VIR_ERROR ( _ ( "Too many active clients (%d), dropping connection" ), max_clients );
2008-12-04 22:18:44 +00:00
close ( fd );
return - 1 ;
}
2008-12-04 22:09:35 +00:00
if ( VIR_REALLOC_N ( server -> clients , server -> nclients + 1 ) < 0 ) {
2009-01-06 18:32:03 +00:00
VIR_ERROR0 ( _ ( "Out of memory allocating clients" ));
2008-12-04 22:09:35 +00:00
close ( fd );
return - 1 ;
}
2009-01-22 17:49:41 +00: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 12:04:54 +00: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 15:43:07 +00:00
if ( virSetCloseExec ( fd ) < 0 ||
virSetNonBlock ( fd ) < 0 ) {
2007-02-14 01:40:09 +00:00
close ( fd );
return - 1 ;
}
2008-06-06 10:52:01 +00:00
if ( VIR_ALLOC ( client ) < 0 )
2007-11-30 15:43:42 +00:00
goto cleanup ;
2009-01-15 19:56:05 +00:00
if ( virMutexInit ( & client -> lock ) < 0 ) {
2010-05-20 08:10:38 +02:00
VIR_ERROR0 ( _ ( "cannot initialize mutex" ));
2009-01-15 19:56:05 +00:00
VIR_FREE ( client );
2008-12-04 22:16:40 +00:00
goto cleanup ;
2009-01-15 19:56:05 +00:00
}
2008-12-04 22:16:40 +00:00
2007-06-11 12:04:54 +00:00
client -> magic = QEMUD_CLIENT_MAGIC ;
2007-02-14 01:40:09 +00:00
client -> fd = fd ;
client -> readonly = sock -> readonly ;
2007-12-05 15:27:08 +00:00
client -> type = sock -> type ;
2007-12-05 15:24:15 +00:00
client -> auth = sock -> auth ;
2007-06-11 12:04:54 +00:00
memcpy ( & client -> addr , & addr , sizeof addr );
client -> addrlen = addrlen ;
2010-03-18 14:56:56 +00:00
for ( i = 0 ; i < VIR_DOMAIN_EVENT_ID_LAST ; i ++ ) {
client -> domainEventCallbackID [ i ] = - 1 ;
}
2009-01-20 19:25:15 +00: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 15:09:19 +00: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 06:12:32 +00:00
/* Client is running as root, so disable auth */
2008-04-04 15:09:19 +00:00
if ( uid == 0 ) {
2009-01-06 18:32:03 +00:00
VIR_INFO ( _ ( "Turn off polkit auth for privileged client %d" ), pid );
2008-04-04 15:09:19 +00:00
client -> auth = REMOTE_AUTH_NONE ;
}
}
#endif
2007-12-05 15:27:08 +00:00
if ( client -> type != QEMUD_SOCK_TYPE_TLS ) {
2009-01-20 19:25:15 +00:00
/* Plain socket, so prepare to read first message */
2009-07-10 12:48:50 +01:00
if ( qemudRegisterClientEvent ( server , client ) < 0 )
2007-06-26 19:11:00 +00:00
goto cleanup ;
2007-06-11 12:04:54 +00:00
} else {
int ret ;
2007-12-05 15:27:08 +00:00
client -> tlssession = remoteInitializeTLSSession ();
if ( client -> tlssession == NULL )
2007-06-26 19:11:00 +00:00
goto cleanup ;
2007-06-11 12:04:54 +00:00
2007-12-05 15:27:08 +00:00
gnutls_transport_set_ptr ( client -> tlssession ,
2007-06-11 12:04:54 +00:00
( gnutls_transport_ptr_t ) ( long ) fd );
/* Begin the TLS handshake. */
2007-12-05 15:27:08 +00:00
ret = gnutls_handshake ( client -> tlssession );
2007-06-11 12:04:54 +00:00
if ( ret == 0 ) {
2009-03-03 08:25:50 +00:00
client -> handshake = 0 ;
2007-06-11 12:04:54 +00:00
/* Unlikely, but ... Next step is to check the certificate. */
if ( remoteCheckAccess ( client ) == - 1 )
2007-06-26 19:11:00 +00:00
goto cleanup ;
2009-01-20 19:25:15 +00:00
/* Handshake & cert check OK, so prepare to read first message */
2009-07-10 12:48:50 +01:00
if ( qemudRegisterClientEvent ( server , client ) < 0 )
2007-06-26 19:11:00 +00:00
goto cleanup ;
2007-06-11 12:04:54 +00:00
} else if ( ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN ) {
2009-01-20 19:25:15 +00:00
/* Most likely, need to do more handshake data */
client -> handshake = 1 ;
2007-06-26 19:11:00 +00:00
2009-07-10 12:48:50 +01:00
if ( qemudRegisterClientEvent ( server , client ) < 0 )
2007-06-26 19:11:00 +00:00
goto cleanup ;
2007-06-11 12:04:54 +00:00
} else {
2009-01-06 18:32:03 +00:00
VIR_ERROR ( _ ( "TLS handshake failed: %s" ),
2007-06-11 12:04:54 +00:00
gnutls_strerror ( ret ));
2007-06-26 19:11:00 +00:00
goto cleanup ;
2007-06-11 12:04:54 +00:00
}
}
2007-02-14 01:40:09 +00:00
2008-12-04 22:09:35 +00:00
server -> clients [ server -> nclients ++ ] = client ;
2007-02-14 01:40:09 +00:00
2009-01-20 19:27:11 +00:00
if ( server -> nclients > server -> nactiveworkers &&
server -> nactiveworkers < server -> nworkers ) {
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 01:40:09 +00:00
return 0 ;
2007-06-11 12:04:54 +00:00
2007-06-26 19:11:00 +00:00
cleanup :
2008-12-04 22:16:40 +00:00
if ( client &&
client -> tlssession ) gnutls_deinit ( client -> tlssession );
2007-06-11 12:04:54 +00:00
close ( fd );
2009-12-14 16:45:11 +01:00
if ( client )
VIR_FREE ( client -> rx );
2009-01-20 19:25:15 +00:00
VIR_FREE ( client );
2007-06-11 12:04:54 +00:00
return - 1 ;
2007-02-14 01:40:09 +00:00
}
2008-12-04 22:16:40 +00: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 19:25:15 +00:00
void qemudDispatchClientFailure ( struct qemud_client * client ) {
2009-05-29 14:34:35 +00:00
if ( client -> watch != - 1 ) {
virEventRemoveHandleImpl ( client -> watch );
client -> watch = - 1 ;
}
2007-06-26 19:11:00 +00:00
2008-10-23 13:18:18 +00:00
/* Deregister event delivery callback */
2010-03-18 14:56:56 +00:00
if ( client -> conn ) {
int i ;
for ( i = 0 ; i < VIR_DOMAIN_EVENT_ID_LAST ; i ++ ) {
if ( client -> domainEventCallbackID [ i ] != - 1 ) {
DEBUG ( "Deregistering to relay remote events %d" , i );
virConnectDomainEventDeregisterAny ( client -> conn ,
client -> domainEventCallbackID [ i ]);
}
client -> domainEventCallbackID [ i ] = - 1 ;
}
2008-10-23 13:18:18 +00:00
}
2007-12-05 15:24:15 +00:00
#if HAVE_SASL
2009-05-29 14:34:35 +00:00
if ( client -> saslconn ) {
sasl_dispose ( & client -> saslconn );
client -> saslconn = NULL ;
}
2009-12-10 00:00:50 +01:00
VIR_FREE ( client -> saslUsername );
2007-12-05 15:24:15 +00:00
#endif
2009-05-29 14:34:35 +00:00
if ( client -> tlssession ) {
gnutls_deinit ( client -> tlssession );
client -> tlssession = NULL ;
}
if ( client -> fd != - 1 ) {
close ( client -> fd );
client -> fd = - 1 ;
}
2008-12-04 22:16:40 +00: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 19:56:05 +00:00
virMutexLock ( & server -> clients [ i ] -> lock );
2009-01-20 19:25:15 +00:00
if ( server -> clients [ i ] -> dx ) {
2008-12-04 22:16:40 +00:00
/* Delibrately don't unlock client - caller wants the lock */
return server -> clients [ i ];
}
2009-01-15 19:56:05 +00:00
virMutexUnlock ( & server -> clients [ i ] -> lock );
2008-12-04 22:16:40 +00:00
}
return NULL ;
2007-02-14 01:40:09 +00:00
}
2008-12-04 22:16:40 +00:00
static void * qemudWorker ( void * data )
{
2009-01-20 19:27:11 +00:00
struct qemud_worker * worker = data ;
struct qemud_server * server = worker -> server ;
2008-12-04 22:16:40 +00:00
while ( 1 ) {
2009-01-20 19:25:15 +00:00
struct qemud_client * client = NULL ;
2009-07-10 12:45:37 +01:00
struct qemud_client_message * msg ;
2009-01-20 19:25:15 +00:00
2009-01-15 19:56:05 +00:00
virMutexLock ( & server -> lock );
2010-03-01 11:59:43 -07:00
while (( client = qemudPendingJob ( server )) == NULL ) {
if ( worker -> quitRequest ||
virCondWait ( & server -> job , & server -> lock ) < 0 ) {
2009-01-15 19:56:05 +00:00
virMutexUnlock ( & server -> lock );
return NULL ;
}
}
2009-01-20 19:27:11 +00:00
if ( worker -> quitRequest ) {
2010-03-01 11:59:43 -07:00
virMutexUnlock ( & client -> lock );
2009-01-20 19:27:11 +00:00
virMutexUnlock ( & server -> lock );
return NULL ;
}
worker -> processingCall = 1 ;
2009-01-15 19:56:05 +00:00
virMutexUnlock ( & server -> lock );
2008-12-04 22:16:40 +00:00
/* We own a locked client now... */
client -> refs ++ ;
2009-01-20 19:25:15 +00:00
/* Remove our message from dispatch queue while we use it */
2009-07-10 12:45:37 +01:00
msg = qemudClientMessageQueueServe ( & client -> dx );
2009-01-20 19:25:15 +00:00
/* This function drops the lock during dispatch,
* and re-acquires it before returning */
2009-07-10 12:58:22 +01:00
if ( remoteDispatchClientRequest ( server , client , msg ) < 0 ) {
2009-07-10 12:45:37 +01:00
VIR_FREE ( msg );
2009-01-20 19:25:15 +00:00
qemudDispatchClientFailure ( client );
client -> refs -- ;
virMutexUnlock ( & client -> lock );
continue ;
}
2008-12-04 22:16:40 +00:00
client -> refs -- ;
2009-01-15 19:56:05 +00:00
virMutexUnlock ( & client -> lock );
2009-01-20 19:27:11 +00:00
virMutexLock ( & server -> lock );
worker -> processingCall = 0 ;
virMutexUnlock ( & server -> lock );
2008-12-04 22:16:40 +00:00
}
}
2007-02-14 01:40:09 +00:00
2009-01-20 19:27:11 +00: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 01:40:09 +00:00
2009-01-20 19:25:15 +00: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 11:31:39 +00:00
VIR_ERROR ( _ ( "unexpected negative length request %lld" ),
( long long int ) len );
2009-01-20 19:25:15 +00:00
qemudDispatchClientFailure ( client );
return - 1 ;
}
2007-06-11 12:04:54 +00:00
/*qemudDebug ("qemudClientRead: len = %d", len);*/
2007-12-05 15:27:08 +00:00
if ( ! client -> tlssession ) {
2009-02-05 16:28:03 +00:00
char ebuf [ 1024 ];
2009-01-20 19:25:15 +00: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 16:28:03 +00:00
VIR_ERROR ( _ ( "read: %s" ),
virStrerror ( errno , ebuf , sizeof ebuf ));
2009-01-20 19:25:15 +00:00
qemudDispatchClientFailure ( client );
2007-06-11 12:04:54 +00:00
return - 1 ;
}
} else {
2007-12-05 15:27:08 +00:00
ret = gnutls_record_recv ( client -> tlssession , data , len );
2009-01-20 19:25:15 +00: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 12:04:54 +00:00
return - 1 ;
}
2007-02-14 01:40:09 +00:00
}
2007-06-11 12:04:54 +00:00
2007-12-05 15:27:08 +00:00
return ret ;
}
2009-01-20 19:25:15 +00: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 01:40:09 +00:00
}
2007-12-05 15:27:08 +00:00
#if HAVE_SASL
2009-01-20 19:25:15 +00: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 15:27:08 +00: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 19:25:15 +00:00
int ret ;
2007-12-05 15:27:08 +00:00
char encoded [ 8192 ];
2009-01-20 19:25:15 +00: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 15:27:08 +00:00
return - 1 ;
2009-01-20 19:25:15 +00:00
}
2007-12-05 15:27:08 +00:00
client -> saslDecodedOffset = 0 ;
}
/* Some buffered decoded data to return now */
got = client -> saslDecodedLength - client -> saslDecodedOffset ;
2009-01-20 19:25:15 +00:00
want = client -> rx -> bufferLength - client -> rx -> bufferOffset ;
2007-12-05 15:27:08 +00:00
if ( want > got )
want = got ;
2009-01-20 19:25:15 +00:00
memcpy ( client -> rx -> buffer + client -> rx -> bufferOffset ,
2007-12-05 15:27:08 +00:00
client -> saslDecoded + client -> saslDecodedOffset , want );
client -> saslDecodedOffset += want ;
2009-01-20 19:25:15 +00:00
client -> rx -> bufferOffset += want ;
2007-12-05 15:27:08 +00:00
if ( client -> saslDecodedOffset == client -> saslDecodedLength ) {
client -> saslDecoded = NULL ;
client -> saslDecodedOffset = client -> saslDecodedLength = 0 ;
}
2009-01-20 19:25:15 +00:00
return want ;
2007-12-05 15:27:08 +00:00
}
#endif
2009-01-20 19:25:15 +00: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 15:27:08 +00:00
#if HAVE_SASL
if ( client -> saslSSF & QEMUD_SASL_SSF_READ )
2009-01-20 19:25:15 +00:00
return qemudClientReadSASL ( client );
2007-12-05 15:27:08 +00:00
else
#endif
2009-01-20 19:25:15 +00:00
return qemudClientReadPlain ( client );
2007-12-05 15:27:08 +00:00
}
2009-01-20 19:25:15 +00: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 12:04:54 +00:00
/*qemudDebug ("qemudDispatchClientRead: mode = %d", client->mode);*/
2007-02-14 01:40:09 +00:00
2009-01-20 19:25:15 +00:00
readmore :
if ( qemudClientRead ( client ) < 0 )
return ; /* Error */
2007-06-11 12:04:54 +00:00
2009-01-20 19:25:15 +00:00
if ( client -> rx -> bufferOffset < client -> rx -> bufferLength )
return ; /* Still not read enough */
2007-06-11 12:04:54 +00:00
2009-01-20 19:25:15 +00:00
/* Either done with length word header */
if ( client -> rx -> bufferLength == REMOTE_MESSAGE_HEADER_XDR_LEN ) {
unsigned int len ;
XDR x ;
2007-06-11 12:04:54 +00:00
2009-01-20 19:25:15 +00:00
xdrmem_create ( & x , client -> rx -> buffer , client -> rx -> bufferLength , XDR_DECODE );
2007-06-11 12:04:54 +00:00
2007-11-17 11:17:48 +00:00
if ( ! xdr_u_int ( & x , & len )) {
xdr_destroy ( & x );
2008-12-22 12:53:26 +00:00
DEBUG0 ( "Failed to decode packet length" );
2009-01-20 19:25:15 +00:00
qemudDispatchClientFailure ( client );
2007-02-14 01:40:09 +00:00
return ;
}
2007-11-17 11:17:48 +00:00
xdr_destroy ( & x );
2007-06-11 12:04:54 +00:00
2009-01-20 19:25:15 +00:00
if ( len < REMOTE_MESSAGE_HEADER_XDR_LEN ) {
DEBUG ( "Packet length %u too small" , len );
qemudDispatchClientFailure ( client );
2007-06-11 12:04:54 +00:00
return ;
2007-02-14 01:40:09 +00:00
}
2007-06-11 12:04:54 +00:00
2009-01-20 19:25:15 +00: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 12:04:54 +00:00
return ;
}
2009-01-20 19:25:15 +00:00
/* Prepare to read rest of message */
client -> rx -> bufferLength += len ;
2007-06-11 12:04:54 +00:00
2009-07-10 12:48:50 +01:00
qemudUpdateClientEvent ( client );
2007-06-26 19:11:00 +00:00
2009-01-20 19:25:15 +00: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 12:58:22 +01: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 13:06:36 +01:00
int ret ;
ret = ( filter -> query )( client , msg , filter -> opaque );
if ( ret == 1 ) {
2009-07-10 12:58:22 +01:00
msg = NULL ;
break ;
2009-07-10 13:06:36 +01:00
} else if ( ret == - 1 ) {
VIR_FREE ( msg );
qemudDispatchClientFailure ( client );
return ;
2009-07-10 12:58:22 +01:00
}
filter = filter -> next ;
}
2009-01-20 19:25:15 +00:00
/* Move completed message to the end of the dispatch queue */
2009-07-10 12:58:22 +01:00
if ( msg )
qemudClientMessageQueuePush ( & client -> dx , msg );
2009-01-20 19:25:15 +00: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 19:11:00 +00:00
} else {
2009-01-20 19:25:15 +00:00
if ( client -> rx )
client -> rx -> bufferLength = REMOTE_MESSAGE_HEADER_XDR_LEN ;
2009-07-10 12:48:50 +01:00
qemudUpdateClientEvent ( client );
/* Tell one of the workers to get on with it... */
virCondSignal ( & server -> job );
2007-06-26 19:11:00 +00:00
}
2007-02-14 01:40:09 +00:00
}
}
2009-01-20 19:25:15 +00: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 11:31:39 +00:00
VIR_ERROR ( _ ( "unexpected negative length request %lld" ),
( long long int ) len );
2009-01-20 19:25:15 +00:00
qemudDispatchClientFailure ( client );
return - 1 ;
}
2007-12-05 15:27:08 +00:00
if ( ! client -> tlssession ) {
2009-02-05 16:28:03 +00:00
char ebuf [ 1024 ];
2009-01-20 19:25:15 +00:00
if (( ret = write ( client -> fd , data , len )) == - 1 ) {
if ( errno == EAGAIN || errno == EINTR )
return 0 ;
2009-02-05 16:28:03 +00:00
VIR_ERROR ( _ ( "write: %s" ), virStrerror ( errno , ebuf , sizeof ebuf ));
2009-01-20 19:25:15 +00:00
qemudDispatchClientFailure ( client );
2007-06-11 12:04:54 +00:00
return - 1 ;
}
} else {
2007-12-05 15:27:08 +00:00
ret = gnutls_record_send ( client -> tlssession , data , len );
2009-01-20 19:25:15 +00: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 12:04:54 +00:00
return - 1 ;
}
2007-02-14 01:40:09 +00:00
}
2007-12-05 15:27:08 +00:00
return ret ;
}
2007-06-11 12:04:54 +00:00
2007-12-05 15:27:08 +00:00
2009-01-20 19:25:15 +00: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 01:40:09 +00:00
}
2007-12-05 15:27:08 +00:00
#if HAVE_SASL
2009-01-20 19:25:15 +00: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 15:27:08 +00:00
int ret ;
/* Not got any pending encoded data, so we need to encode raw stuff */
if ( client -> saslEncoded == NULL ) {
2009-01-20 19:25:15 +00:00
ret = sasl_encode ( client -> saslconn ,
client -> tx -> buffer + client -> tx -> bufferOffset ,
client -> tx -> bufferLength - client -> tx -> bufferOffset ,
2007-12-05 15:27:08 +00:00
& client -> saslEncoded ,
& client -> saslEncodedLength );
2009-01-20 19:25:15 +00: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 15:27:08 +00:00
client -> saslEncodedOffset = 0 ;
}
/* Send some of the encoded stuff out on the wire */
2009-01-20 19:25:15 +00:00
ret = qemudClientWriteBuf ( client ,
2007-12-05 15:27:08 +00:00
client -> saslEncoded + client -> saslEncodedOffset ,
client -> saslEncodedLength - client -> saslEncodedOffset );
2009-01-20 19:25:15 +00:00
if ( ret <= 0 )
return ret ; /* -1 error, 0 == egain */
2007-12-05 15:27:08 +00: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 19:25:15 +00:00
/* Mark as complete, so caller detects completion */
client -> tx -> bufferOffset = client -> tx -> bufferLength ;
2007-12-05 15:27:08 +00:00
}
2009-01-20 19:25:15 +00:00
return ret ;
2007-12-05 15:27:08 +00:00
}
#endif
2009-01-20 19:25:15 +00: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 15:27:08 +00:00
#if HAVE_SASL
if ( client -> saslSSF & QEMUD_SASL_SSF_WRITE )
2009-01-20 19:25:15 +00:00
return qemudClientWriteSASL ( client );
2007-12-05 15:27:08 +00:00
else
#endif
2009-01-20 19:25:15 +00:00
return qemudClientWritePlain ( client );
2007-12-05 15:27:08 +00:00
}
2009-07-10 13:06:36 +01:00
void
qemudClientMessageRelease ( struct qemud_client * client ,
struct qemud_client_message * msg )
{
2009-08-24 20:57:16 +01:00
if ( msg -> streamTX ) {
remoteStreamMessageFinished ( client , msg );
} else if ( ! msg -> async )
2009-07-10 13:06:36 +01: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 19:25:15 +00:00
/*
* Process all queued client->tx messages until
* we would block on I/O
*/
static void
2009-07-10 12:48:50 +01:00
qemudDispatchClientWrite ( struct qemud_client * client ) {
2009-01-20 19:25:15 +00:00
while ( client -> tx ) {
ssize_t ret ;
2007-06-11 12:04:54 +00:00
2009-01-20 19:25:15 +00: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 13:06:36 +01:00
qemudClientMessageRelease ( client , reply );
2007-06-11 12:04:54 +00:00
2009-07-10 12:48:50 +01:00
if ( client -> closing )
qemudDispatchClientFailure ( client );
2009-01-20 19:25:15 +00:00
}
2007-06-11 12:04:54 +00:00
}
2009-01-20 19:25:15 +00:00
}
2007-06-11 12:04:54 +00:00
2009-01-20 19:25:15 +00:00
static void
2009-07-10 12:48:50 +01:00
qemudDispatchClientHandshake ( struct qemud_client * client ) {
2009-01-20 19:25:15 +00:00
int ret ;
/* Continue the handshake. */
ret = gnutls_handshake ( client -> tlssession );
if ( ret == 0 ) {
2009-03-03 08:25:50 +00:00
client -> handshake = 0 ;
2009-01-20 19:25:15 +00:00
/* Finished. Next step is to check the certificate. */
if ( remoteCheckAccess ( client ) == - 1 )
qemudDispatchClientFailure ( client );
2009-07-10 12:48:50 +01:00
else
qemudUpdateClientEvent ( client );
2009-01-20 19:25:15 +00: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 12:48:50 +01:00
qemudUpdateClientEvent ( client );
2009-01-20 19:25:15 +00:00
} else {
/* Fatal error in handshake */
VIR_ERROR ( _ ( "TLS handshake failed: %s" ),
gnutls_strerror ( ret ));
qemudDispatchClientFailure ( client );
2007-02-14 01:40:09 +00:00
}
}
2008-10-23 13:18:18 +00:00
static void
2008-11-19 16:19:36 +00:00
qemudDispatchClientEvent ( int watch , int fd , int events , void * opaque ) {
2007-06-26 19:11:00 +00:00
struct qemud_server * server = ( struct qemud_server * ) opaque ;
2008-12-04 22:09:35 +00:00
struct qemud_client * client = NULL ;
int i ;
2007-02-23 08:39:49 +00:00
2009-01-15 19:56:05 +00:00
virMutexLock ( & server -> lock );
2008-12-04 22:16:40 +00:00
2008-12-04 22:09:35 +00:00
for ( i = 0 ; i < server -> nclients ; i ++ ) {
2009-01-20 19:25:15 +00:00
virMutexLock ( & server -> clients [ i ] -> lock );
2008-12-04 22:09:35 +00:00
if ( server -> clients [ i ] -> watch == watch ) {
client = server -> clients [ i ];
2007-06-26 19:11:00 +00:00
break ;
2008-12-04 22:09:35 +00:00
}
2009-01-20 19:25:15 +00:00
virMutexUnlock ( & server -> clients [ i ] -> lock );
2007-06-26 19:11:00 +00:00
}
2007-06-11 12:04:54 +00:00
2009-01-20 19:25:15 +00:00
virMutexUnlock ( & server -> lock );
2008-12-04 22:16:40 +00:00
if ( ! client ) {
2007-06-26 19:11:00 +00:00
return ;
2008-12-04 22:16:40 +00:00
}
2009-01-20 19:25:15 +00:00
if ( client -> fd != fd ) {
virMutexUnlock ( & client -> lock );
2008-11-19 16:19:36 +00:00
return ;
2009-01-20 19:25:15 +00:00
}
if ( events & ( VIR_EVENT_HANDLE_WRITABLE |
VIR_EVENT_HANDLE_READABLE )) {
if ( client -> handshake ) {
2009-07-10 12:48:50 +01:00
qemudDispatchClientHandshake ( client );
2009-01-20 19:25:15 +00:00
} else {
if ( events & VIR_EVENT_HANDLE_WRITABLE )
2009-07-10 12:48:50 +01:00
qemudDispatchClientWrite ( client );
2009-01-20 19:25:15 +00: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 16:19:36 +00:00
2009-01-15 19:56:05 +00:00
virMutexUnlock ( & client -> lock );
2007-06-26 19:11:00 +00:00
}
2009-07-10 12:48:50 +01:00
/*
* @client: a locked client object
*/
static int
qemudCalculateHandleMode ( struct qemud_client * client ) {
2009-01-20 19:25:15 +00:00
int mode = 0 ;
if ( client -> handshake ) {
2007-12-05 15:27:08 +00:00
if ( gnutls_record_get_direction ( client -> tlssession ) == 0 )
2009-01-20 19:25:15 +00:00
mode |= VIR_EVENT_HANDLE_READABLE ;
2007-12-05 15:27:08 +00:00
else
2009-01-20 19:25:15 +00: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-04 22:16:40 +00:00
2009-01-20 19:25:15 +00: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 15:27:08 +00:00
}
2009-07-10 12:48:50 +01: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 19:11:00 +00:00
return 0 ;
}
2009-07-10 12:48:50 +01:00
/*
* @client: a locked client object
*/
void qemudUpdateClientEvent ( struct qemud_client * client ) {
int mode ;
mode = qemudCalculateHandleMode ( client );
virEventUpdateHandleImpl ( client -> watch , mode );
}
2008-10-23 13:18:18 +00:00
static void
2008-11-19 16:19:36 +00:00
qemudDispatchServerEvent ( int watch , int fd , int events , void * opaque ) {
2007-06-26 19:11:00 +00:00
struct qemud_server * server = ( struct qemud_server * ) opaque ;
2008-12-04 22:16:40 +00:00
struct qemud_socket * sock ;
2009-01-15 19:56:05 +00:00
virMutexLock ( & server -> lock );
2008-12-04 22:16:40 +00:00
sock = server -> sockets ;
2007-06-26 19:11:00 +00:00
2007-03-05 17:15:20 +00:00
while ( sock ) {
2008-11-19 16:19:36 +00:00
if ( sock -> watch == watch )
2007-06-26 19:11:00 +00:00
break ;
sock = sock -> next ;
2007-03-05 17:15:20 +00:00
}
2007-02-14 01:40:09 +00:00
2008-12-04 22:16:40 +00:00
if ( sock && sock -> fd == fd && events )
2007-06-26 19:11:00 +00:00
qemudDispatchServer ( server , sock );
2008-12-04 22:16:40 +00:00
2009-01-15 19:56:05 +00:00
virMutexUnlock ( & server -> lock );
2007-06-26 19:11:00 +00:00
}
2007-06-26 20:51:00 +00:00
static int qemudOneLoop ( void ) {
2007-03-27 10:28:45 +00:00
sig_atomic_t errors ;
2007-02-14 01:40:09 +00:00
2007-06-26 19:11:00 +00:00
if ( virEventRunOnce () < 0 )
2007-02-14 01:40:09 +00:00
return - 1 ;
2007-03-27 10:28:45 +00:00
/* Check for any signal handling errors and log them. */
errors = sig_errors ;
if ( errors ) {
2009-02-05 16:28:03 +00:00
char ebuf [ 1024 ];
2007-03-27 10:28:45 +00:00
sig_errors -= errors ;
2009-01-06 18:32:03 +00:00
VIR_ERROR ( _ ( "Signal handler reported %d errors: last error: %s" ),
2009-02-05 16:28:03 +00:00
errors , virStrerror ( sig_lasterrno , ebuf , sizeof ebuf ));
2007-03-27 10:28:45 +00:00
return - 1 ;
}
2007-02-14 01:40:09 +00:00
return 0 ;
}
2009-02-06 14:43:52 +00:00
static void qemudInactiveTimer ( int timerid , void * data ) {
2007-06-26 22:56:14 +00:00
struct qemud_server * server = ( struct qemud_server * ) data ;
2009-02-06 14:43:52 +00: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 16:34:37 +01:00
server -> quitEventThread = 1 ;
2007-06-26 22:56:14 +00:00
}
}
2009-01-20 19:25:15 +00: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 13:06:36 +01:00
while ( client -> streams )
remoteRemoveClientStream ( client , client -> streams );
2009-01-20 19:25:15 +00:00
if ( client -> conn )
virConnectClose ( client -> conn );
virMutexDestroy ( & client -> lock );
VIR_FREE ( client );
}
2009-10-16 16:34:37 +01:00
static void * qemudRunLoop ( void * opaque ) {
struct qemud_server * server = opaque ;
2007-06-26 22:56:14 +00:00
int timerid = - 1 ;
2009-10-16 16:34:37 +01:00
int i ;
2009-02-06 14:43:52 +00:00
int timerActive = 0 ;
2008-12-04 22:16:40 +00:00
2009-01-15 19:56:05 +00:00
virMutexLock ( & server -> lock );
2008-12-04 22:16:40 +00:00
2009-02-06 14:43:52 +00:00
if ( timeout > 0 &&
( timerid = virEventAddTimeoutImpl ( - 1 ,
qemudInactiveTimer ,
server , NULL )) < 0 ) {
VIR_ERROR0 ( _ ( "Failed to register shutdown timeout" ));
2009-10-16 16:34:37 +01:00
return NULL ;
2009-02-06 14:43:52 +00:00
}
2009-01-20 19:27:11 +00:00
if ( min_workers > max_workers )
max_workers = min_workers ;
server -> nworkers = max_workers ;
2008-12-04 22:16:40 +00:00
if ( VIR_ALLOC_N ( server -> workers , server -> nworkers ) < 0 ) {
2009-01-06 18:32:03 +00:00
VIR_ERROR0 ( _ ( "Failed to allocate workers" ));
2009-10-16 16:34:37 +01:00
return NULL ;
2008-12-04 22:16:40 +00:00
}
2009-01-20 19:27:11 +00:00
for ( i = 0 ; i < min_workers ; i ++ ) {
if ( qemudStartWorker ( server , & server -> workers [ i ]) < 0 )
goto cleanup ;
server -> nactiveworkers ++ ;
2008-12-04 22:16:40 +00:00
}
2007-06-26 22:56:14 +00:00
2009-10-16 16:34:37 +01:00
for (; ! server -> quitEventThread ;) {
2007-06-26 22:56:14 +00:00
/* A shutdown timeout is specified, so check
* if any drivers have active state, if not
* shutdown after timeout seconds
*/
2009-02-06 14:43:52 +00: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-26 22:56:14 +00:00
}
2009-01-15 19:56:05 +00:00
virMutexUnlock ( & server -> lock );
2009-01-20 19:25:15 +00:00
if ( qemudOneLoop () < 0 ) {
virMutexLock ( & server -> lock );
2010-04-02 21:44:04 +02:00
DEBUG0 ( "Loop iteration error, exiting" );
2007-06-26 22:56:14 +00:00
break ;
2009-01-20 19:25:15 +00:00
}
2009-01-15 19:56:05 +00:00
virMutexLock ( & server -> lock );
2008-12-04 22:16:40 +00:00
reprocess :
for ( i = 0 ; i < server -> nclients ; i ++ ) {
int inactive ;
2009-01-15 19:56:05 +00:00
virMutexLock ( & server -> clients [ i ] -> lock );
2008-12-04 22:16:40 +00:00
inactive = server -> clients [ i ] -> fd == - 1
&& server -> clients [ i ] -> refs == 0 ;
2009-01-15 19:56:05 +00:00
virMutexUnlock ( & server -> clients [ i ] -> lock );
2008-12-04 22:16:40 +00:00
if ( inactive ) {
2009-01-20 19:25:15 +00:00
qemudFreeClient ( server -> clients [ i ]);
2008-12-04 22:16:40 +00:00
server -> nclients -- ;
2009-01-20 19:25:15 +00:00
if ( i < server -> nclients )
2008-12-04 22:16:40 +00:00
memmove ( server -> clients + i ,
server -> clients + i + 1 ,
2009-01-20 19:25:15 +00:00
sizeof ( * server -> clients ) * ( server -> nclients - i ));
if ( VIR_REALLOC_N ( server -> clients ,
server -> nclients ) < 0 ) {
; /* ignore */
2008-12-04 22:16:40 +00:00
}
2009-01-20 19:25:15 +00:00
goto reprocess ;
2008-12-04 22:16:40 +00:00
}
}
2007-02-14 01:40:09 +00:00
2009-01-20 19:27:11 +00: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-26 22:56:14 +00:00
}
2009-01-20 19:27:11 +00:00
cleanup :
2008-12-04 22:16:40 +00:00
for ( i = 0 ; i < server -> nworkers ; i ++ ) {
2009-01-20 19:27:11 +00:00
if ( ! server -> workers [ i ]. hasThread )
continue ;
server -> workers [ i ]. quitRequest = 1 ;
virCondBroadcast ( & server -> job );
2009-01-15 19:56:05 +00:00
virMutexUnlock ( & server -> lock );
2009-01-20 19:27:11 +00:00
pthread_join ( server -> workers [ i ]. thread , NULL );
2009-01-15 19:56:05 +00:00
virMutexLock ( & server -> lock );
2009-01-20 19:27:11 +00:00
server -> workers [ i ]. hasThread = 0 ;
2008-12-04 22:16:40 +00:00
}
2009-01-20 19:25:15 +00:00
VIR_FREE ( server -> workers );
2008-12-04 22:16:40 +00:00
2009-01-15 19:56:05 +00:00
virMutexUnlock ( & server -> lock );
2009-10-16 16:34:37 +01:00
return NULL ;
2007-02-14 01:40:09 +00:00
}
2009-10-16 16:34:37 +01: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 01:40:09 +00:00
static void qemudCleanup ( struct qemud_server * server ) {
2007-02-20 17:51:41 +00:00
struct qemud_socket * sock ;
2009-10-16 11:48:50 +01:00
if ( server -> sigread != - 1 )
close ( server -> sigread );
if ( server -> sigwrite != - 1 )
close ( server -> sigwrite );
2007-02-20 17:51:41 +00:00
sock = server -> sockets ;
2007-02-14 01:40:09 +00:00
while ( sock ) {
2007-02-20 17:51:41 +00:00
struct qemud_socket * next = sock -> next ;
2009-10-16 11:24:01 +01:00
if ( sock -> watch )
virEventRemoveHandleImpl ( sock -> watch );
2007-02-14 01:40:09 +00:00
close ( sock -> fd );
2010-06-03 14:36:34 +01:00
/* Unlink unix domain sockets which are not in
* the abstract namespace */
if ( sock -> path &&
sock -> path [ 0 ] != '@' )
unlink ( sock -> path );
VIR_FREE ( sock -> path );
2009-12-10 00:00:50 +01:00
VIR_FREE ( sock );
2007-02-20 17:51:41 +00:00
sock = next ;
2007-02-14 01:40:09 +00:00
}
2009-12-10 00:00:50 +01:00
VIR_FREE ( server -> logDir );
2007-02-20 17:51:41 +00:00
2007-12-05 19:25:44 +00:00
#ifdef HAVE_SASL
2007-12-05 15:34:05 +00:00
if ( server -> saslUsernameWhitelist ) {
char ** list = server -> saslUsernameWhitelist ;
while ( * list ) {
2009-12-10 00:00:50 +01:00
VIR_FREE ( * list );
2007-12-05 15:34:05 +00:00
list ++ ;
}
2009-12-10 00:00:50 +01:00
VIR_FREE ( server -> saslUsernameWhitelist );
2007-12-05 15:34:05 +00:00
}
2007-12-05 19:25:44 +00:00
#endif
2007-02-20 17:51:41 +00:00
2009-10-16 11:24:01 +01:00
#if HAVE_POLKIT0
if ( server -> sysbus )
dbus_connection_unref ( server -> sysbus );
#endif
2007-06-26 22:56:14 +00:00
virStateCleanup ();
2007-06-11 12:04:54 +00:00
2009-01-15 19:56:05 +00:00
if ( virCondDestroy ( & server -> job ) < 0 ) {
;
}
virMutexDestroy ( & server -> lock );
VIR_FREE ( server );
2007-02-14 01:40:09 +00:00
}
2007-11-30 15:43:42 +00: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 10:52:01 +00:00
if ( VIR_ALLOC_N ( list , 2 ) < 0 ) {
2009-01-06 18:32:03 +00:00
VIR_ERROR ( _ ( "failed to allocate memory for %s config list" ), key );
2007-11-30 15:43:42 +00:00
return - 1 ;
}
list [ 0 ] = strdup ( p -> str );
list [ 1 ] = NULL ;
if ( list [ 0 ] == NULL ) {
2009-01-06 18:32:03 +00:00
VIR_ERROR ( _ ( "failed to allocate memory for %s config list value" ),
2007-11-30 15:43:42 +00:00
key );
2008-06-06 10:52:01 +00:00
VIR_FREE ( list );
2007-11-30 15:43:42 +00: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 10:52:01 +00:00
if ( VIR_ALLOC_N ( list , 1 + len ) < 0 ) {
2009-01-06 18:32:03 +00:00
VIR_ERROR ( _ ( "failed to allocate memory for %s config list" ), key );
2007-11-30 15:43:42 +00:00
return - 1 ;
}
for ( i = 0 , pp = p -> list ; pp ; ++ i , pp = pp -> next ) {
if ( pp -> type != VIR_CONF_STRING ) {
2009-01-06 18:32:03 +00:00
VIR_ERROR ( _ ( "remoteReadConfigFile: %s: %s:"
2010-04-02 21:44:04 +02:00
" must be a string or list of strings" ),
2007-11-30 15:43:42 +00:00
filename , key );
2008-06-06 10:52:01 +00:00
VIR_FREE ( list );
2007-11-30 15:43:42 +00:00
return - 1 ;
}
list [ i ] = strdup ( pp -> str );
if ( list [ i ] == NULL ) {
int j ;
for ( j = 0 ; j < i ; j ++ )
2008-06-06 10:52:01 +00:00
VIR_FREE ( list [ j ]);
VIR_FREE ( list );
2009-01-06 18:32:03 +00:00
VIR_ERROR ( _ ( "failed to allocate memory for %s config list value" ),
key );
2007-11-30 15:43:42 +00:00
return - 1 ;
}
}
list [ i ] = NULL ;
break ;
}
default :
2009-01-06 18:32:03 +00:00
VIR_ERROR ( _ ( "remoteReadConfigFile: %s: %s:"
2010-04-02 21:44:04 +02:00
" must be a string or list of strings" ),
2007-11-30 15:43:42 +00: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 18:32:03 +00:00
VIR_ERROR ( _ ( "remoteReadConfigFile: %s: %s: invalid type:"
2010-04-02 21:44:04 +02:00
" got %s; expected %s" ), filename , key ,
2007-11-30 15:43:42 +00: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 16:28:30 +00:00
char ebuf[1024]; \
2010-01-19 14:17:20 +01:00
VIR_ERROR(_("remoteReadConfigFile: %s"), \
2009-02-05 16:28:30 +00:00
virStrerror(errno, ebuf, sizeof ebuf)); \
2007-11-30 15:43:42 +00: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 15:34:05 +00: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-11 21:20:13 +00:00
if ( checkType ( p , filename , key , VIR_CONF_STRING ) < 0 )
2007-12-05 15:34:05 +00: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 18:21:27 +00:00
#endif
#if HAVE_POLKIT
} else if ( STREQ ( p -> str , "polkit" )) {
* auth = REMOTE_AUTH_POLKIT ;
2007-12-05 15:34:05 +00:00
#endif
} else {
2010-01-19 14:17:20 +01:00
VIR_ERROR ( _ ( "remoteReadConfigFile: %s: %s: unsupported auth %s" ),
2008-02-07 16:50:17 +00:00
filename , key , p -> str );
2007-12-05 15:34:05 +00:00
return - 1 ;
}
return 0 ;
}
2007-12-05 19:25:44 +00: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 12:53:26 +00: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 16:16:10 +00:00
static int
2009-10-23 08:56:21 +02:00
qemudSetLogging ( virConfPtr conf , const char * filename )
{
int log_level = 0 ;
2009-08-06 15:45:50 +02:00
char * log_filters = NULL ;
char * log_outputs = NULL ;
2008-12-22 16:16:10 +00:00
int ret = - 1 ;
2008-12-22 12:53:26 +00:00
virLogReset ();
2008-12-22 16:16:10 +00:00
/*
2009-08-06 15:55:07 +02: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 16:16:10 +00:00
*/
2008-12-22 12:53:26 +00:00
GET_CONF_INT ( conf , filename , log_level );
2009-08-06 15:45:50 +02:00
if ( log_level != 0 )
virLogSetDefaultPriority ( log_level );
2009-08-06 15:55:07 +02:00
virLogSetFromEnv ();
2009-08-06 15:45:50 +02:00
if ( virLogGetNbFilters () == 0 ) {
GET_CONF_STR ( conf , filename , log_filters );
virLogParseFilters ( log_filters );
2008-12-22 16:16:10 +00:00
}
2008-12-22 12:53:26 +00:00
2009-08-06 15:45:50 +02:00
if ( virLogGetNbOutputs () == 0 ) {
GET_CONF_STR ( conf , filename , log_outputs );
virLogParseOutputs ( log_outputs );
2009-06-03 10:36:17 +00:00
}
2008-12-22 12:53:26 +00:00
/*
2009-08-06 15:45:50 +02:00
* If no defined outputs, then direct to syslog when running
* as daemon. Otherwise the default output is stderr.
2008-12-22 12:53:26 +00:00
*/
2009-08-06 15:45:50 +02:00
if ( virLogGetNbOutputs () == 0 ) {
2009-07-01 11:21:15 +00:00
char * tmp = NULL ;
2009-01-20 21:50:31 +00:00
if ( godaemon ) {
2009-08-06 15:45:50 +02:00
if ( virAsprintf ( & tmp , "%d:syslog:libvirtd" ,
virLogGetDefaultPriority ()) < 0 )
2009-01-20 21:50:31 +00:00
goto free_and_fail ;
} else {
2009-08-06 15:45:50 +02:00
if ( virAsprintf ( & tmp , "%d:stderr" ,
virLogGetDefaultPriority ()) < 0 )
2009-07-01 11:21:15 +00:00
goto free_and_fail ;
2009-01-20 21:50:31 +00:00
}
2009-07-01 11:21:15 +00:00
virLogParseOutputs ( tmp );
VIR_FREE ( tmp );
2009-06-03 10:36:17 +00:00
}
2009-08-06 15:55:07 +02:00
/*
* Command line override for --verbose
*/
if (( verbose ) && ( virLogGetDefaultPriority () > VIR_LOG_INFO ))
virLogSetDefaultPriority ( VIR_LOG_INFO );
2008-12-22 16:16:10 +00:00
ret = 0 ;
2008-12-22 12:53:26 +00:00
free_and_fail :
VIR_FREE ( log_filters );
VIR_FREE ( log_outputs );
2008-12-22 16:16:10 +00:00
return ( ret );
2008-12-22 12:53:26 +00:00
}
2007-12-05 19:25:44 +00:00
2007-06-11 12:04:54 +00:00
/* Read the config file if it exists.
* Only used in the remote case, hence the name.
*/
static int
2007-12-05 15:34:05 +00:00
remoteReadConfigFile ( struct qemud_server * server , const char * filename )
2007-06-11 12:04:54 +00:00
{
virConfPtr conf ;
2007-11-30 15:43:42 +00: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 14:53:19 +00:00
char * buf = NULL ;
2010-05-25 15:33:51 +01:00
char * host_uuid = NULL ;
2007-11-30 15:43:42 +00:00
2008-07-30 08:47:10 +00:00
#if HAVE_POLKIT
/* Change the default back to no auth for non-root */
2009-06-12 13:20:13 +00:00
if ( ! server -> privileged && auth_unix_rw == REMOTE_AUTH_POLKIT )
2008-07-30 08:47:10 +00:00
auth_unix_rw = REMOTE_AUTH_NONE ;
2009-06-12 13:20:13 +00:00
if ( ! server -> privileged && auth_unix_ro == REMOTE_AUTH_POLKIT )
2008-07-30 08:47:10 +00:00
auth_unix_ro = REMOTE_AUTH_NONE ;
#endif
2009-06-19 12:34:30 +00:00
conf = virConfReadFile ( filename , 0 );
2009-01-12 18:22:32 +00:00
if ( ! conf ) return - 1 ;
2007-06-11 12:04:54 +00:00
2008-12-22 12:53:26 +00:00
/*
* First get all the logging settings and activate them
*/
2008-12-22 16:16:10 +00:00
if ( qemudSetLogging ( conf , filename ) < 0 )
goto free_and_fail ;
2008-12-22 12:53:26 +00:00
2007-12-05 18:56:27 +00:00
GET_CONF_INT ( conf , filename , listen_tcp );
GET_CONF_INT ( conf , filename , listen_tls );
2007-11-30 15:43:42 +00:00
GET_CONF_STR ( conf , filename , tls_port );
GET_CONF_STR ( conf , filename , tcp_port );
2008-05-14 20:57:20 +00:00
GET_CONF_STR ( conf , filename , listen_addr );
2008-05-14 21:22:04 +00:00
2007-12-05 15:34:05 +00:00
if ( remoteConfigGetAuth ( conf , "auth_unix_rw" , & auth_unix_rw , filename ) < 0 )
2008-03-03 13:15:57 +00:00
goto free_and_fail ;
2007-12-05 18:21:27 +00: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 15:34:05 +00:00
if ( remoteConfigGetAuth ( conf , "auth_unix_ro" , & auth_unix_ro , filename ) < 0 )
2008-03-03 13:15:57 +00:00
goto free_and_fail ;
2007-12-05 15:34:05 +00:00
if ( remoteConfigGetAuth ( conf , "auth_tcp" , & auth_tcp , filename ) < 0 )
2008-03-03 13:15:57 +00:00
goto free_and_fail ;
2007-12-05 15:34:05 +00:00
if ( remoteConfigGetAuth ( conf , "auth_tls" , & auth_tls , filename ) < 0 )
2008-03-03 13:15:57 +00:00
goto free_and_fail ;
2007-12-05 15:34:05 +00:00
2007-11-30 15:43:42 +00:00
GET_CONF_STR ( conf , filename , unix_sock_group );
if ( unix_sock_group ) {
2009-06-12 13:20:13 +00:00
if ( ! server -> privileged ) {
2010-05-19 12:00:18 +02:00
VIR_WARN0 ( "Cannot set group when not running as root" );
2007-09-19 02:28:01 +00:00
} else {
2009-04-16 14:53:19 +00:00
int ret ;
2009-01-22 19:41:48 +00:00
struct group grpdata , * grp ;
2009-04-16 14:53:19 +00:00
size_t maxbuf = sysconf ( _SC_GETGR_R_SIZE_MAX );
if ( maxbuf == - 1 )
maxbuf = 1024 ;
if ( VIR_ALLOC_N ( buf , maxbuf ) < 0 ) {
2010-05-20 08:10:38 +02:00
VIR_ERROR0 ( _ ( "Failed to allocate memory for buffer" ));
2009-04-16 14:53:19 +00:00
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 ) {
2010-05-20 08:10:38 +02:00
VIR_ERROR0 ( _ ( "Failed to reallocate enough memory for buffer" ));
2009-04-16 14:53:19 +00:00
goto free_and_fail ;
}
}
if ( ret != 0 || ! grp ) {
2009-01-06 18:32:03 +00:00
VIR_ERROR ( _ ( "Failed to lookup group '%s'" ), unix_sock_group );
2007-11-30 15:43:42 +00:00
goto free_and_fail ;
2007-09-19 02:28:01 +00:00
}
unix_sock_gid = grp -> gr_gid ;
2009-12-10 00:00:50 +01:00
VIR_FREE ( buf );
2007-09-19 02:28:01 +00:00
}
2009-12-10 00:00:50 +01:00
VIR_FREE ( unix_sock_group );
2007-09-19 02:28:01 +00:00
}
2007-11-30 15:43:42 +00:00
GET_CONF_STR ( conf , filename , unix_sock_ro_perms );
if ( unix_sock_ro_perms ) {
2008-02-08 09:15:16 +00:00
if ( virStrToLong_i ( unix_sock_ro_perms , NULL , 8 , & unix_sock_ro_mask ) != 0 ) {
2009-01-06 18:32:03 +00:00
VIR_ERROR ( _ ( "Failed to parse mode '%s'" ), unix_sock_ro_perms );
2007-11-30 15:43:42 +00:00
goto free_and_fail ;
2007-09-19 02:28:01 +00:00
}
2009-12-10 00:00:50 +01:00
VIR_FREE ( unix_sock_ro_perms );
2007-09-19 02:28:01 +00:00
}
2007-11-30 15:43:42 +00:00
GET_CONF_STR ( conf , filename , unix_sock_rw_perms );
if ( unix_sock_rw_perms ) {
2008-02-08 09:15:16 +00:00
if ( virStrToLong_i ( unix_sock_rw_perms , NULL , 8 , & unix_sock_rw_mask ) != 0 ) {
2009-01-06 18:32:03 +00:00
VIR_ERROR ( _ ( "Failed to parse mode '%s'" ), unix_sock_rw_perms );
2007-11-30 15:43:42 +00:00
goto free_and_fail ;
2007-09-19 02:28:01 +00:00
}
2009-12-10 00:00:50 +01:00
VIR_FREE ( unix_sock_rw_perms );
2007-09-19 02:28:01 +00:00
}
2009-02-09 17:52:38 +00:00
GET_CONF_STR ( conf , filename , unix_sock_dir );
2007-11-30 15:43:42 +00:00
GET_CONF_INT ( conf , filename , mdns_adv );
GET_CONF_STR ( conf , filename , mdns_name );
2007-09-19 01:56:55 +00:00
2007-11-30 15:43:42 +00:00
GET_CONF_INT ( conf , filename , tls_no_verify_certificate );
2007-06-11 12:04:54 +00:00
2007-11-30 15:43:42 +00: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 12:04:54 +00:00
2007-11-30 15:43:42 +00:00
if ( remoteConfigGetStringList ( conf , "tls_allowed_dn_list" ,
& tls_allowed_dn_list , filename ) < 0 )
goto free_and_fail ;
2007-06-11 12:04:54 +00:00
2007-12-05 19:25:44 +00:00
if ( remoteReadSaslAllowedUsernameList ( conf , server , filename ) < 0 )
2007-11-30 15:43:42 +00:00
goto free_and_fail ;
2007-06-11 12:04:54 +00:00
2008-12-04 22:18:44 +00: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 19:25:15 +00:00
GET_CONF_INT ( conf , filename , max_requests );
GET_CONF_INT ( conf , filename , max_client_requests );
2010-05-25 15:33:51 +01:00
GET_CONF_STR ( conf , filename , host_uuid );
2010-05-25 21:12:01 +02:00
if ( virSetHostUUIDStr ( host_uuid )) {
VIR_ERROR ( _ ( "invalid host UUID: %s" ), host_uuid );
2010-05-25 15:33:51 +01:00
goto free_and_fail ;
2010-05-25 21:12:01 +02:00
}
2010-05-25 15:33:51 +01:00
VIR_FREE ( host_uuid );
2007-11-30 15:43:42 +00:00
virConfFree ( conf );
return 0 ;
2007-06-11 12:04:54 +00:00
2007-11-30 15:43:42 +00:00
free_and_fail :
virConfFree ( conf );
2010-05-25 15:33:51 +01:00
VIR_FREE ( host_uuid );
2009-12-10 00:00:50 +01: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 );
2007-11-30 15:43:42 +00:00
2008-05-14 20:57:20 +00: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
2007-11-30 15:43:42 +00: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 00:00:50 +01:00
VIR_FREE ( tls_allowed_dn_list [ i ]);
VIR_FREE ( tls_allowed_dn_list );
2007-11-30 15:43:42 +00:00
}
return - 1 ;
2007-06-11 12:04:54 +00:00
}
2008-12-12 07:56:50 +00:00
/* Display version information. */
static void
2010-05-20 21:40:54 +02:00
version ( void )
2008-12-12 07:56:50 +00:00
{
printf ( "%s (%s) %s \n " , argv0 , PACKAGE_NAME , PACKAGE_VERSION );
}
2009-01-22 17:49:41 +00: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 14:17:20 +01:00
VIR_ERROR0 ( _ ( "additional privileges are required" ));
2009-01-22 17:49:41 +00: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 14:17:20 +01:00
VIR_ERROR0 ( _ ( "failed to set reduced privileges" ));
2009-01-22 17:49:41 +00:00
return - 1 ;
}
return 0 ;
}
#else
2010-03-09 19:22:22 +01:00
# define qemudSetupPrivs() 0
2009-01-22 17:49:41 +00:00
#endif
2009-10-16 11:48:50 +01: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 09:32:00 +00:00
/* Print command-line usage. */
static void
2010-05-20 21:40:54 +02:00
usage ( void )
2007-04-04 09:32:00 +00:00
{
fprintf ( stderr ,
2010-05-20 10:01:32 +02:00
_ ( " \n \
2007-06-11 12:04:54 +00:00
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-26 23:48:46 +00:00
-l | --listen Listen for TCP/IP connections. \n \
-t | --timeout <secs> Exit after timeout period. \n \
2007-08-07 13:24:22 +00:00
-f | --config <file> Configuration file. \n \
2008-12-12 07:56:50 +00:00
| --version Display version information. \n \
2007-06-11 12:04:54 +00:00
-p | --pid-file <file> Change name of PID file. \n \
\n \
2007-06-26 23:48:46 +00:00
libvirt management daemon: \n \
2007-06-11 12:04:54 +00:00
\n \
Default paths: \n \
\n \
2009-11-10 15:53:20 +01:00
Configuration file (unless overridden by -f): \n \
2010-05-20 10:01:32 +02:00
%s/libvirt/libvirtd.conf \n \
2007-06-11 12:04:54 +00:00
\n \
2007-06-26 23:48:46 +00:00
Sockets (as root): \n \
2010-05-20 10:01:32 +02:00
%s/run/libvirt/libvirt-sock \n \
%s/run/libvirt/libvirt-sock-ro \n \
2007-06-26 23:48:46 +00:00
\n \
Sockets (as non-root): \n \
$HOME/.libvirt/libvirt-sock (in UNIX abstract namespace) \n \
2007-06-11 12:04:54 +00:00
\n \
TLS: \n \
2010-05-20 10:01:32 +02:00
CA certificate: %s \n \
Server certificate: %s \n \
Server private key: %s \n \
2007-06-11 12:04:54 +00:00
\n \
PID file (unless overridden by --pid-file): \n \
%s \n \
2010-05-20 10:01:32 +02:00
\n " ),
argv0 ,
SYSCONF_DIR ,
LOCAL_STATE_DIR ,
LOCAL_STATE_DIR ,
LIBVIRT_CACERT ,
LIBVIRT_SERVERCERT ,
LIBVIRT_SERVERKEY ,
( REMOTE_PID_FILE [ 0 ] != '\0'
? REMOTE_PID_FILE
: _ ( "(disabled in ./configure)" )));
2007-04-04 09:32:00 +00:00
}
2008-12-12 07:56:50 +00:00
enum {
OPT_VERSION = 129
};
2007-02-14 01:40:09 +00:00
#define MAX_LISTEN 5
int main ( int argc , char ** argv ) {
2008-03-03 18:10:19 +00:00
struct qemud_server * server = NULL ;
2007-06-11 12:04:54 +00:00
const char * pid_file = NULL ;
2009-01-12 18:22:32 +00:00
const char * remote_config_file = NULL ;
2009-10-16 12:14:54 +01:00
int statuswrite = - 1 ;
2007-02-23 12:48:36 +00:00
int ret = 1 ;
2010-05-20 21:40:54 +02:00
argv0 = argv [ 0 ];
2007-02-14 01:40:09 +00:00
struct option opts [] = {
{ "verbose" , no_argument , & verbose , 1 },
{ "daemon" , no_argument , & godaemon , 1 },
2007-06-26 23:48:46 +00:00
{ "listen" , no_argument , & ipsock , 1 },
2007-08-07 13:24:22 +00:00
{ "config" , required_argument , NULL , 'f' },
2007-04-04 09:32:00 +00:00
{ "timeout" , required_argument , NULL , 't' },
{ "pid-file" , required_argument , NULL , 'p' },
2008-12-12 07:56:50 +00:00
{ "version" , no_argument , NULL , OPT_VERSION },
2007-04-04 09:32:00 +00:00
{ "help" , no_argument , NULL , '?' },
2007-02-14 01:40:09 +00:00
{ 0 , 0 , 0 , 0 }
};
2010-05-20 09:52:20 +02:00
if ( virInitialize () < 0 ) {
2010-05-20 21:40:54 +02:00
fprintf ( stderr , _ ( "%s: initialization failed \n " ), argv0 );
2010-05-20 09:52:20 +02:00
exit ( EXIT_FAILURE );
}
2009-10-16 11:29:01 +01:00
2007-02-14 01:40:09 +00:00
while ( 1 ) {
int optidx = 0 ;
int c ;
char * tmp ;
2007-08-07 13:24:22 +00:00
c = getopt_long ( argc , argv , "ldf:p:t:v" , opts , & optidx );
2007-02-14 01:40:09 +00: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-26 23:48:46 +00:00
case 'l' :
ipsock = 1 ;
2007-02-14 01:40:09 +00:00
break ;
case 't' :
2008-02-08 09:15:16 +00:00
if ( virStrToLong_i ( optarg , & tmp , 10 , & timeout ) != 0
2007-11-14 10:53:05 +00:00
|| timeout <= 0
/* Ensure that we can multiply by 1000 without overflowing. */
|| timeout > INT_MAX / 1000 )
2007-02-14 01:40:09 +00:00
timeout = - 1 ;
break ;
2007-02-23 12:48:36 +00:00
case 'p' :
2007-06-11 12:04:54 +00:00
pid_file = optarg ;
break ;
case 'f' :
remote_config_file = optarg ;
2007-02-23 12:48:36 +00:00
break ;
2008-12-12 07:56:50 +00:00
case OPT_VERSION :
2010-05-20 21:40:54 +02:00
version ();
2008-12-12 07:56:50 +00:00
return 0 ;
2007-02-14 01:40:09 +00:00
case '?' :
2010-05-20 21:40:54 +02:00
usage ();
2007-02-14 01:40:09 +00:00
return 2 ;
default :
2010-05-20 21:40:54 +02:00
fprintf ( stderr , _ ( "%s: internal error: unknown flag: %c \n " ),
argv0 , c );
2009-12-15 09:43:29 +01:00
exit ( EXIT_FAILURE );
2007-02-14 01:40:09 +00:00
}
}
2009-01-12 18:22:32 +00:00
if ( remote_config_file == NULL ) {
static const char * default_config_file
= SYSCONF_DIR "/libvirt/libvirtd.conf" ;
remote_config_file =
2009-01-13 12:22:24 +00:00
( access ( default_config_file , R_OK ) == 0
2009-01-12 18:22:32 +00:00
? default_config_file
: "/dev/null" );
}
2008-05-20 16:17:36 +00:00
if ( godaemon ) {
2009-02-05 16:28:03 +00:00
char ebuf [ 1024 ];
2009-10-16 12:14:54 +01:00
if (( statuswrite = daemonForkIntoBackground ()) < 0 ) {
2009-02-05 16:28:03 +00:00
VIR_ERROR ( _ ( "Failed to fork as daemon: %s" ),
virStrerror ( errno , ebuf , sizeof ebuf ));
2009-10-16 11:48:50 +01:00
goto error ;
2008-05-20 16:17:36 +00:00
}
}
/* If running as root and no PID file is set, use the default */
if ( pid_file == NULL &&
2009-06-12 13:20:13 +00:00
geteuid () == 0 &&
2008-05-20 16:17:36 +00: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 12:14:54 +01:00
qemudWritePidFile ( pid_file ) < 0 ) {
pid_file = NULL ; /* Prevent unlinking of someone else's pid ! */
ret = VIR_DAEMON_ERR_PIDFILE ;
2009-10-16 11:48:50 +01:00
goto error ;
2009-10-16 12:14:54 +01:00
}
2008-05-20 16:17:36 +00:00
2009-01-22 17:49:41 +00:00
/* Ensure the rundir exists (on tmpfs on some systems) */
2009-06-12 13:20:13 +00:00
if ( geteuid () == 0 ) {
2009-01-22 17:49:41 +00:00
const char * rundir = LOCAL_STATE_DIR "/run/libvirt" ;
if ( mkdir ( rundir , 0755 )) {
if ( errno != EEXIST ) {
2009-09-23 12:38:21 +02:00
char ebuf [ 1024 ];
VIR_ERROR ( _ ( "unable to create rundir %s: %s" ), rundir ,
virStrerror ( errno , ebuf , sizeof ( ebuf )));
2009-10-16 12:14:54 +01:00
ret = VIR_DAEMON_ERR_RUNDIR ;
goto error ;
2009-01-22 17:49:41 +00:00
}
}
}
2009-06-12 13:20:13 +00: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 12:14:54 +01:00
if ( qemudSetupPrivs () < 0 ) {
ret = VIR_DAEMON_ERR_PRIVS ;
2009-10-16 11:48:50 +01:00
goto error ;
2009-10-16 12:14:54 +01:00
}
2009-01-22 17:49:41 +00:00
2009-10-16 11:48:50 +01:00
if ( ! ( server = qemudInitialize ())) {
2009-10-16 12:14:54 +01:00
ret = VIR_DAEMON_ERR_INIT ;
2009-10-16 11:48:50 +01:00
goto error ;
2007-12-05 15:34:05 +00:00
}
2007-02-16 18:28:17 +00:00
2009-10-16 12:14:54 +01:00
if (( daemonSetupSignals ( server )) < 0 ) {
ret = VIR_DAEMON_ERR_SIGNAL ;
2009-10-16 11:48:50 +01:00
goto error ;
2009-10-16 12:14:54 +01:00
}
2009-10-16 11:48:50 +01:00
2007-12-05 15:34:05 +00:00
/* Read the config file (if it exists). */
2009-10-16 12:14:54 +01:00
if ( remoteReadConfigFile ( server , remote_config_file ) < 0 ) {
ret = VIR_DAEMON_ERR_CONFIG ;
2009-10-16 11:48:50 +01:00
goto error ;
2009-10-16 12:14:54 +01:00
}
2007-02-14 01:40:09 +00:00
2010-03-26 15:53:32 +01:00
/* setup the hooks if any */
2010-03-30 15:06:13 +02:00
if ( virHookInitialize () < 0 ) {
2010-03-26 15:53:32 +01:00
ret = VIR_DAEMON_ERR_HOOKS ;
goto error ;
}
2009-10-19 18:28:28 +01:00
/* Disable error func, now logging is setup */
virSetErrorFunc ( NULL , virshErrorHandler );
2010-03-26 15:53:32 +01:00
/*
* Call the daemon startup hook
* TODO: should we abort the daemon startup if the script returned
* an error ?
*/
virHookCall ( VIR_HOOK_DRIVER_DAEMON , "-" , VIR_HOOK_DAEMON_OP_START ,
0 , "start" , NULL );
2009-10-16 11:24:01 +01:00
if ( qemudNetworkInit ( server ) < 0 ) {
2009-10-16 12:14:54 +01:00
ret = VIR_DAEMON_ERR_NETWORK ;
2009-10-16 11:48:50 +01:00
goto error ;
2007-12-05 15:34:05 +00:00
}
2009-10-16 12:14:54 +01: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 16:34:37 +01:00
/* Start the event loop in a background thread, since
* state initialization needs events to be being processed */
if ( qemudStartEventLoop ( server ) < 0 ) {
2010-05-20 08:14:50 +02:00
VIR_ERROR0 ( _ ( "Event thread startup failed" ));
2009-10-16 16:34:37 +01:00
goto error ;
}
2009-10-16 12:14:54 +01: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 ) {
2010-05-20 08:14:50 +02:00
VIR_ERROR0 ( _ ( "Driver state initialization failed" ));
2009-11-13 10:34:47 +00:00
goto shutdown ;
2009-10-16 12:14:54 +01:00
}
2007-02-14 01:40:09 +00:00
2009-10-16 16:34:37 +01:00
/* Start accepting new clients from network */
virMutexLock ( & server -> lock );
if ( qemudNetworkEnable ( server ) < 0 ) {
2010-05-20 08:14:50 +02:00
VIR_ERROR0 ( _ ( "Network event loop enablement failed" ));
2009-10-16 16:34:37 +01:00
goto shutdown ;
}
virMutexUnlock ( & server -> lock );
2007-02-23 12:48:36 +00:00
ret = 0 ;
2009-10-16 16:34:37 +01: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 );
2010-03-26 15:53:32 +01:00
virHookCall ( VIR_HOOK_DRIVER_DAEMON , "-" , VIR_HOOK_DAEMON_OP_SHUTDOWN ,
0 , "shutdown" , NULL );
2009-10-16 11:48:50 +01:00
error :
2009-10-16 12:14:54 +01: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 18:10:19 +00:00
if ( server )
qemudCleanup ( server );
2008-05-20 16:17:36 +00:00
if ( pid_file )
unlink ( pid_file );
2008-12-22 12:53:26 +00:00
virLogShutdown ();
2007-02-23 12:48:36 +00:00
return ret ;
2007-02-14 01:40:09 +00:00
}