2010-01-11 18:16:57 +03:00
// #include <config.h>
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <signal.h>
2010-01-11 21:26:43 +03:00
# include <errno.h>
2010-01-11 18:16:57 +03:00
# include <sys/types.h>
# include <sys/poll.h>
# include <libvirt/libvirt.h>
# include <libxml/xmlreader.h>
# define DEBUG0(fmt) printf("%s:%d :: " fmt "\n", \
__func__ , __LINE__ )
# define DEBUG(fmt, ...) printf("%s:%d: " fmt "\n", \
__func__ , __LINE__ , __VA_ARGS__ )
# define STREQ(a,b) (strcmp((a),(b)) == 0)
/* handle globals */
int h_fd = 0 ;
virEventHandleType h_event = 0 ;
virEventHandleCallback h_cb = NULL ;
virFreeCallback h_ff = NULL ;
void * h_opaque = NULL ;
/* timeout globals */
# define TIMEOUT_MS 1000
int t_active = 0 ;
int t_timeout = - 1 ;
virEventTimeoutCallback t_cb = NULL ;
virFreeCallback t_ff = NULL ;
void * t_opaque = NULL ;
/* Prototypes */
const char * eventToString ( int event ) ;
2010-01-11 21:26:43 +03:00
int myDomainEventCallback1 ( virConnectPtr conn , virDomainPtr dom ,
int event , int detail , void * opaque ) ;
int myEventAddHandleFunc ( int fd , int event ,
virEventHandleCallback cb ,
void * opaque , virFreeCallback ff ) ;
2010-01-11 18:16:57 +03:00
void myEventUpdateHandleFunc ( int watch , int event ) ;
2010-01-11 21:26:43 +03:00
int myEventRemoveHandleFunc ( int watch ) ;
2010-01-11 18:16:57 +03:00
int myEventAddTimeoutFunc ( int timeout ,
2010-01-11 21:26:43 +03:00
virEventTimeoutCallback cb ,
void * opaque , virFreeCallback ff ) ;
2010-01-11 18:16:57 +03:00
void myEventUpdateTimeoutFunc ( int timer , int timout ) ;
int myEventRemoveTimeoutFunc ( int timer ) ;
int myEventHandleTypeToPollEvent ( virEventHandleType events ) ;
virEventHandleType myPollEventToEventHandleType ( int events ) ;
void usage ( const char * pname ) ;
2010-01-11 21:26:43 +03:00
struct domain_info {
virDomainPtr dom ;
virDomainEventType event ;
} ;
2010-01-11 18:16:57 +03:00
2010-01-13 01:36:03 +03:00
2010-01-11 21:26:43 +03:00
int
myDomainEventCallback1 ( virConnectPtr conn ,
virDomainPtr dom , int event , int detail , void * opaque )
{
struct domain_info * dinfo = ( struct domain_info * ) opaque ;
if ( event = = VIR_DOMAIN_EVENT_STARTED | |
event = = VIR_DOMAIN_EVENT_STOPPED ) {
virDomainRef ( dom ) ;
dinfo - > dom = dom ;
dinfo - > event = event ;
} else {
dinfo - > event = VIR_DOMAIN_EVENT_UNDEFINED ;
}
return 0 ;
2010-01-11 18:16:57 +03:00
}
/* EventImpl Functions */
2010-01-11 21:26:43 +03:00
int
myEventHandleTypeToPollEvent ( virEventHandleType events )
2010-01-11 18:16:57 +03:00
{
2010-01-11 21:26:43 +03:00
int ret = 0 ;
if ( events & VIR_EVENT_HANDLE_READABLE )
ret | = POLLIN ;
if ( events & VIR_EVENT_HANDLE_WRITABLE )
ret | = POLLOUT ;
if ( events & VIR_EVENT_HANDLE_ERROR )
ret | = POLLERR ;
if ( events & VIR_EVENT_HANDLE_HANGUP )
ret | = POLLHUP ;
return ret ;
2010-01-11 18:16:57 +03:00
}
2010-01-11 21:26:43 +03:00
virEventHandleType
myPollEventToEventHandleType ( int events )
2010-01-11 18:16:57 +03:00
{
2010-01-11 21:26:43 +03:00
virEventHandleType ret = 0 ;
if ( events & POLLIN )
ret | = VIR_EVENT_HANDLE_READABLE ;
if ( events & POLLOUT )
ret | = VIR_EVENT_HANDLE_WRITABLE ;
if ( events & POLLERR )
ret | = VIR_EVENT_HANDLE_ERROR ;
if ( events & POLLHUP )
ret | = VIR_EVENT_HANDLE_HANGUP ;
return ret ;
2010-01-11 18:16:57 +03:00
}
2010-01-11 21:26:43 +03:00
int
myEventAddHandleFunc ( int fd , int event ,
virEventHandleCallback cb ,
void * opaque , virFreeCallback ff )
2010-01-11 18:16:57 +03:00
{
2010-01-11 21:26:43 +03:00
DEBUG ( " Add handle %d %d %p %p " , fd , event , cb , opaque ) ;
h_fd = fd ;
h_event = myEventHandleTypeToPollEvent ( event ) ;
h_cb = cb ;
h_ff = ff ;
h_opaque = opaque ;
return 0 ;
2010-01-11 18:16:57 +03:00
}
2010-01-11 21:26:43 +03:00
void
myEventUpdateHandleFunc ( int fd , int event )
2010-01-11 18:16:57 +03:00
{
2010-01-11 21:26:43 +03:00
DEBUG ( " Updated Handle %d %d " , fd , event ) ;
h_event = myEventHandleTypeToPollEvent ( event ) ;
return ;
2010-01-11 18:16:57 +03:00
}
2010-01-11 21:26:43 +03:00
int
myEventRemoveHandleFunc ( int fd )
2010-01-11 18:16:57 +03:00
{
2010-01-11 21:26:43 +03:00
DEBUG ( " Removed Handle %d " , fd ) ;
h_fd = 0 ;
if ( h_ff )
( h_ff ) ( h_opaque ) ;
return 0 ;
2010-01-11 18:16:57 +03:00
}
2010-01-11 21:26:43 +03:00
int
myEventAddTimeoutFunc ( int timeout ,
virEventTimeoutCallback cb ,
void * opaque , virFreeCallback ff )
2010-01-11 18:16:57 +03:00
{
2010-01-11 21:26:43 +03:00
DEBUG ( " Adding Timeout %d %p %p " , timeout , cb , opaque ) ;
t_active = 1 ;
t_timeout = timeout ;
t_cb = cb ;
t_ff = ff ;
t_opaque = opaque ;
return 0 ;
2010-01-11 18:16:57 +03:00
}
2010-01-11 21:26:43 +03:00
void
myEventUpdateTimeoutFunc ( int timer , int timeout )
2010-01-11 18:16:57 +03:00
{
2010-01-11 21:26:43 +03:00
/*DEBUG("Timeout updated %d %d", timer, timeout); */
t_timeout = timeout ;
2010-01-11 18:16:57 +03:00
}
2010-01-11 21:26:43 +03:00
int
myEventRemoveTimeoutFunc ( int timer )
2010-01-11 18:16:57 +03:00
{
2010-01-11 21:26:43 +03:00
DEBUG ( " Timeout removed %d " , timer ) ;
t_active = 0 ;
if ( t_ff )
( t_ff ) ( t_opaque ) ;
return 0 ;
2010-01-11 18:16:57 +03:00
}
/* main test functions */
2010-01-11 21:26:43 +03:00
void
usage ( const char * pname )
2010-01-11 18:16:57 +03:00
{
2010-01-11 21:26:43 +03:00
printf ( " %s uri \n " , pname ) ;
2010-01-11 18:16:57 +03:00
}
int run = 1 ;
2010-01-11 21:26:43 +03:00
static void
stop ( int sig )
{
printf ( " Exiting on signal %d \n " , sig ) ;
run = 0 ;
}
static int
domainStarted ( virDomainPtr mojaDomain )
2010-01-11 18:16:57 +03:00
{
2010-01-11 21:26:43 +03:00
char dom_uuid [ 42 ] ;
char * xml ;
xmlDocPtr doc ;
xmlNodePtr cur , devices , child , serial ;
xmlAttrPtr attr , attr_mode , attr_path ;
if ( ! mojaDomain )
return - 1 ;
printf ( " NAME: %s \n " , virDomainGetName ( mojaDomain ) ) ;
virDomainGetUUIDString ( mojaDomain , dom_uuid ) ;
printf ( " UUID: %s \n " , dom_uuid ) ;
xml = virDomainGetXMLDesc ( mojaDomain , 0 ) ;
// printf("%s\n", xml);
// @todo: free mojaDomain
// parseXML output
doc = xmlParseMemory ( xml , strlen ( xml ) ) ;
2010-01-12 16:35:47 +03:00
xmlFree ( xml ) ;
2010-01-11 21:26:43 +03:00
cur = xmlDocGetRootElement ( doc ) ;
if ( cur = = NULL ) {
fprintf ( stderr , " Empty doc \n " ) ;
xmlFreeDoc ( doc ) ;
return - 1 ;
}
if ( xmlStrcmp ( cur - > name , ( const xmlChar * ) " domain " ) ) {
printf ( " no domain? \n " ) ;
xmlFreeDoc ( doc ) ;
return - 1 ;
}
devices = cur - > xmlChildrenNode ;
for ( devices = cur - > xmlChildrenNode ; devices ! = NULL ;
devices = devices - > next ) {
if ( xmlStrcmp ( devices - > name , ( const xmlChar * ) " devices " ) ) {
continue ;
}
for ( child = devices - > xmlChildrenNode ; child ! = NULL ;
child = child - > next ) {
if ( xmlStrcmp ( child - > name , ( const xmlChar * ) " serial " ) ) {
continue ;
}
2010-01-13 01:36:03 +03:00
attr = xmlHasProp ( child , ( const xmlChar * ) " type " ) ;
2010-01-11 21:26:43 +03:00
if ( attr = = NULL )
continue ;
2010-01-12 16:35:47 +03:00
if ( xmlStrcmp ( attr - > children - > content ,
( const xmlChar * ) " unix " ) ) {
2010-01-11 21:26:43 +03:00
continue ;
}
for ( serial = child - > xmlChildrenNode ; serial ! = NULL ;
serial = serial - > next ) {
2010-01-12 16:35:47 +03:00
if ( xmlStrcmp ( serial - > name ,
( const xmlChar * ) " source " ) ) {
2010-01-11 21:26:43 +03:00
continue ;
}
2010-01-13 01:36:03 +03:00
attr_mode = xmlHasProp ( serial , ( const xmlChar * ) " mode " ) ;
attr_path = xmlHasProp ( serial , ( const xmlChar * ) " path " ) ;
2010-01-11 21:26:43 +03:00
if ( ( attr_path ! = NULL ) & &
( attr_mode ! = NULL ) & &
( ! xmlStrcmp ( attr_mode - > children - > content ,
( const xmlChar * ) " bind " ) ) ) {
printf ( " >> REGISTER >> %s %s \n " ,
dom_uuid ,
attr_path - > children - > content ) ;
}
}
}
}
xmlFreeDoc ( doc ) ;
return 0 ;
2010-01-11 18:16:57 +03:00
}
2010-01-11 21:26:43 +03:00
static int
registerExisting ( virConnectPtr vp )
{
int * d_ids = NULL ;
int d_count , x ;
virDomainPtr dom ;
virDomainInfo d_info ;
errno = EINVAL ;
if ( ! vp )
2010-01-13 01:36:03 +03:00
return - 1 ;
2010-01-11 21:26:43 +03:00
d_count = virConnectNumOfDomains ( vp ) ;
if ( d_count < = 0 ) {
if ( d_count = = 0 ) {
/* Successful, but no domains running */
errno = 0 ;
2010-01-13 01:36:03 +03:00
return 0 ;
2010-01-11 21:26:43 +03:00
}
goto out_fail ;
}
d_ids = malloc ( sizeof ( int ) * d_count ) ;
if ( ! d_ids )
goto out_fail ;
if ( virConnectListDomains ( vp , d_ids , d_count ) < 0 )
goto out_fail ;
/* Ok, we have the domain IDs - let's get their names and states */
for ( x = 0 ; x < d_count ; x + + ) {
dom = virDomainLookupByID ( vp , d_ids [ x ] ) ;
if ( ! dom ) {
/* XXX doom */
goto out_fail ;
}
if ( virDomainGetInfo ( dom , & d_info ) < 0 ) {
/* XXX no info for the domain?!! */
virDomainFree ( dom ) ;
goto out_fail ;
}
if ( d_info . state ! = VIR_DOMAIN_SHUTOFF & &
d_info . state ! = VIR_DOMAIN_CRASHED )
domainStarted ( dom ) ;
virDomainFree ( dom ) ;
}
out_fail :
free ( d_ids ) ;
return 0 ;
}
static int
domainStopped ( virDomainPtr mojaDomain )
{
char dom_uuid [ 42 ] ;
if ( ! mojaDomain )
return - 1 ;
printf ( " NAME: %s \n " , virDomainGetName ( mojaDomain ) ) ;
virDomainGetUUIDString ( mojaDomain , dom_uuid ) ;
printf ( " UUID: %s \n " , dom_uuid ) ;
printf ( " >> UNREGISTER >> %s \n " , dom_uuid ) ;
return 0 ;
}
2010-01-11 18:16:57 +03:00
2010-01-11 21:26:43 +03:00
int
main ( int argc , char * * argv )
2010-01-11 18:16:57 +03:00
{
2010-01-11 21:26:43 +03:00
virConnectPtr dconn = NULL ;
struct domain_info dinfo ;
struct sigaction action_stop = { . sa_handler = stop } ;
int sts ;
int callback1ret = - 1 ;
if ( argc > 1 & & STREQ ( argv [ 1 ] , " --help " ) ) {
usage ( argv [ 0 ] ) ;
return - 1 ;
}
virEventRegisterImpl ( myEventAddHandleFunc ,
myEventUpdateHandleFunc ,
myEventRemoveHandleFunc ,
myEventAddTimeoutFunc ,
myEventUpdateTimeoutFunc ,
myEventRemoveTimeoutFunc ) ;
dconn = virConnectOpen ( argv [ 1 ] ? argv [ 1 ] : NULL ) ;
if ( ! dconn ) {
printf ( " error opening \n " ) ;
return - 1 ;
}
sigaction ( SIGTERM , & action_stop , NULL ) ;
sigaction ( SIGINT , & action_stop , NULL ) ;
DEBUG0 ( " Registering domain event cbs " ) ;
registerExisting ( dconn ) ;
/* Add 2 callbacks to prove this works with more than just one */
memset ( & dinfo , 0 , sizeof ( dinfo ) ) ;
dinfo . event = VIR_DOMAIN_EVENT_UNDEFINED ;
callback1ret =
virConnectDomainEventRegister ( dconn , myDomainEventCallback1 ,
& dinfo , NULL ) ;
if ( ( callback1ret = = 0 ) ) {
while ( run ) {
struct pollfd pfd = { . fd = h_fd ,
. events = h_event ,
. revents = 0
} ;
if ( dinfo . event = = VIR_DOMAIN_EVENT_STARTED ) {
domainStarted ( dinfo . dom ) ;
virDomainFree ( dinfo . dom ) ;
dinfo . dom = NULL ;
dinfo . event = VIR_DOMAIN_EVENT_UNDEFINED ;
} else if ( dinfo . event = = VIR_DOMAIN_EVENT_STOPPED ) {
domainStopped ( dinfo . dom ) ;
virDomainFree ( dinfo . dom ) ;
dinfo . dom = NULL ;
dinfo . event = VIR_DOMAIN_EVENT_UNDEFINED ;
}
sts = poll ( & pfd , 1 , TIMEOUT_MS ) ;
/* We are assuming timeout of 0 here - so execute every time */
if ( t_cb & & t_active ) {
t_cb ( t_timeout , t_opaque ) ;
}
if ( sts = = 0 ) {
/* DEBUG0("Poll timeout"); */
continue ;
}
if ( sts < 0 ) {
DEBUG0 ( " Poll failed " ) ;
continue ;
}
if ( pfd . revents & POLLHUP ) {
DEBUG0 ( " Reset by peer " ) ;
return - 1 ;
}
if ( h_cb ) {
h_cb ( 0 ,
h_fd ,
myPollEventToEventHandleType ( pfd .
revents &
h_event ) ,
h_opaque ) ;
}
}
DEBUG0 ( " Deregistering event handlers " ) ;
virConnectDomainEventDeregister ( dconn , myDomainEventCallback1 ) ;
}
DEBUG0 ( " Closing connection " ) ;
if ( dconn & & virConnectClose ( dconn ) < 0 ) {
printf ( " error closing \n " ) ;
}
printf ( " done \n " ) ;
return 0 ;
2010-01-11 18:16:57 +03:00
}