event-test.c 20.2 KB
Newer Older
1
#include <config.h>
2

3
#include <stdio.h>
4
#include <stdlib.h>
5
#include <string.h>
6
#include <signal.h>
7

8 9
#include <libvirt/libvirt.h>
#include <libvirt/virterror.h>
10

11
#define VIR_DEBUG(fmt) printf("%s:%d: " fmt "\n", __func__, __LINE__)
12
#define STREQ(a,b) (strcmp(a,b) == 0)
13

14 15 16
#ifndef ATTRIBUTE_UNUSED
# define ATTRIBUTE_UNUSED __attribute__((__unused__))
#endif
17 18 19 20

/* Prototypes */
const char *eventToString(int event);
int myEventAddHandleFunc  (int fd, int event,
21 22 23
                           virEventHandleCallback cb,
                           void *opaque,
                           virFreeCallback ff);
24 25
void myEventUpdateHandleFunc(int watch, int event);
int  myEventRemoveHandleFunc(int watch);
26

27 28 29 30
int myEventAddTimeoutFunc(int timeout,
                          virEventTimeoutCallback cb,
                          void *opaque,
                          virFreeCallback ff);
31 32 33 34 35 36 37 38 39 40 41
void myEventUpdateTimeoutFunc(int timer, int timout);
int myEventRemoveTimeoutFunc(int timer);

int myEventHandleTypeToPollEvent(virEventHandleType events);
virEventHandleType myPollEventToEventHandleType(int events);

void usage(const char *pname);

/* Callback functions */

const char *eventToString(int event) {
42
    const char *ret = "";
43
    switch ((virDomainEventType) event) {
44 45
        case VIR_DOMAIN_EVENT_DEFINED:
            ret ="Defined";
46
            break;
47 48
        case VIR_DOMAIN_EVENT_UNDEFINED:
            ret ="Undefined";
49 50 51 52 53 54 55 56 57 58 59 60 61
            break;
        case VIR_DOMAIN_EVENT_STARTED:
            ret ="Started";
            break;
        case VIR_DOMAIN_EVENT_SUSPENDED:
            ret ="Suspended";
            break;
        case VIR_DOMAIN_EVENT_RESUMED:
            ret ="Resumed";
            break;
        case VIR_DOMAIN_EVENT_STOPPED:
            ret ="Stopped";
            break;
62 63 64
        case VIR_DOMAIN_EVENT_SHUTDOWN:
            ret = "Shutdown";
            break;
65 66 67 68 69 70
    }
    return ret;
}

static const char *eventDetailToString(int event, int detail) {
    const char *ret = "";
71
    switch ((virDomainEventType) event) {
72 73 74 75 76 77 78 79 80
        case VIR_DOMAIN_EVENT_DEFINED:
            if (detail == VIR_DOMAIN_EVENT_DEFINED_ADDED)
                ret = "Added";
            else if (detail == VIR_DOMAIN_EVENT_DEFINED_UPDATED)
                ret = "Updated";
            break;
        case VIR_DOMAIN_EVENT_UNDEFINED:
            if (detail == VIR_DOMAIN_EVENT_UNDEFINED_REMOVED)
                ret = "Removed";
81
            break;
82
        case VIR_DOMAIN_EVENT_STARTED:
83
            switch ((virDomainEventStartedDetailType) detail) {
84 85 86 87 88 89 90 91 92
            case VIR_DOMAIN_EVENT_STARTED_BOOTED:
                ret = "Booted";
                break;
            case VIR_DOMAIN_EVENT_STARTED_MIGRATED:
                ret = "Migrated";
                break;
            case VIR_DOMAIN_EVENT_STARTED_RESTORED:
                ret = "Restored";
                break;
93 94 95
            case VIR_DOMAIN_EVENT_STARTED_FROM_SNAPSHOT:
                ret = "Snapshot";
                break;
96 97 98
            case VIR_DOMAIN_EVENT_STARTED_WAKEUP:
                ret = "Event wakeup";
                break;
99 100 101
            }
            break;
        case VIR_DOMAIN_EVENT_SUSPENDED:
102
            switch ((virDomainEventSuspendedDetailType) detail) {
103
            case VIR_DOMAIN_EVENT_SUSPENDED_PAUSED:
104
                ret = "Paused";
105 106
                break;
            case VIR_DOMAIN_EVENT_SUSPENDED_MIGRATED:
107
                ret = "Migrated";
108 109 110 111 112 113 114 115 116 117 118 119 120 121
                break;
            case VIR_DOMAIN_EVENT_SUSPENDED_IOERROR:
                ret = "I/O Error";
                break;
            case VIR_DOMAIN_EVENT_SUSPENDED_WATCHDOG:
                ret = "Watchdog";
                break;
            case VIR_DOMAIN_EVENT_SUSPENDED_RESTORED:
                ret = "Restored";
                break;
            case VIR_DOMAIN_EVENT_SUSPENDED_FROM_SNAPSHOT:
                ret = "Snapshot";
                break;
            }
122 123
            break;
        case VIR_DOMAIN_EVENT_RESUMED:
124
            switch ((virDomainEventResumedDetailType) detail) {
125
            case VIR_DOMAIN_EVENT_RESUMED_UNPAUSED:
126
                ret = "Unpaused";
127 128
                break;
            case VIR_DOMAIN_EVENT_RESUMED_MIGRATED:
129
                ret = "Migrated";
130 131 132 133 134
                break;
            case VIR_DOMAIN_EVENT_RESUMED_FROM_SNAPSHOT:
                ret = "Snapshot";
                break;
            }
135 136
            break;
        case VIR_DOMAIN_EVENT_STOPPED:
137
            switch ((virDomainEventStoppedDetailType) detail) {
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
            case VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN:
                ret = "Shutdown";
                break;
            case VIR_DOMAIN_EVENT_STOPPED_DESTROYED:
                ret = "Destroyed";
                break;
            case VIR_DOMAIN_EVENT_STOPPED_CRASHED:
                ret = "Crashed";
                break;
            case VIR_DOMAIN_EVENT_STOPPED_MIGRATED:
                ret = "Migrated";
                break;
            case VIR_DOMAIN_EVENT_STOPPED_SAVED:
                ret = "Failed";
                break;
            case VIR_DOMAIN_EVENT_STOPPED_FAILED:
                ret = "Failed";
                break;
156 157 158
            case VIR_DOMAIN_EVENT_STOPPED_FROM_SNAPSHOT:
                ret = "Snapshot";
                break;
159
            }
160
            break;
161 162 163 164 165 166 167
        case VIR_DOMAIN_EVENT_SHUTDOWN:
            switch ((virDomainEventShutdownDetailType) detail) {
            case VIR_DOMAIN_EVENT_SHUTDOWN_FINISHED:
                ret = "Finished";
                break;
            }
            break;
168 169 170 171
    }
    return ret;
}

172 173 174 175 176
static int myDomainEventCallback1(virConnectPtr conn ATTRIBUTE_UNUSED,
                                  virDomainPtr dom,
                                  int event,
                                  int detail,
                                  void *opaque ATTRIBUTE_UNUSED)
177
{
178
    printf("%s EVENT: Domain %s(%d) %s %s\n", __func__, virDomainGetName(dom),
179 180
           virDomainGetID(dom), eventToString(event),
           eventDetailToString(event, detail));
181 182 183
    return 0;
}

184 185 186 187 188
static int myDomainEventCallback2(virConnectPtr conn ATTRIBUTE_UNUSED,
                                  virDomainPtr dom,
                                  int event,
                                  int detail,
                                  void *opaque ATTRIBUTE_UNUSED)
189
{
190
    printf("%s EVENT: Domain %s(%d) %s %s\n", __func__, virDomainGetName(dom),
191 192
           virDomainGetID(dom), eventToString(event),
           eventDetailToString(event, detail));
193 194 195
    return 0;
}

196 197 198 199 200 201 202 203 204 205
static int myDomainEventRebootCallback(virConnectPtr conn ATTRIBUTE_UNUSED,
                                       virDomainPtr dom,
                                       void *opaque ATTRIBUTE_UNUSED)
{
    printf("%s EVENT: Domain %s(%d) rebooted\n", __func__, virDomainGetName(dom),
           virDomainGetID(dom));

    return 0;
}

206 207 208 209 210
static int myDomainEventRTCChangeCallback(virConnectPtr conn ATTRIBUTE_UNUSED,
                                          virDomainPtr dom,
                                          long long offset,
                                          void *opaque ATTRIBUTE_UNUSED)
{
211 212 213 214 215 216 217 218 219 220
    char *str = NULL;
    /* HACK: use asprintf since we have gnulib's wrapper for %lld on Win32
     * but don't have a printf() replacement with %lld */
    if (asprintf(&str, "%s EVENT: Domain %s(%d) rtc change %lld\n",
                 __func__, virDomainGetName(dom),
                 virDomainGetID(dom), offset) < 0)
        return 0;

    printf("%s", str);
    free(str);
221 222 223 224

    return 0;
}

225 226 227 228 229 230 231 232 233 234 235
static int myDomainEventWatchdogCallback(virConnectPtr conn ATTRIBUTE_UNUSED,
                                         virDomainPtr dom,
                                         int action,
                                         void *opaque ATTRIBUTE_UNUSED)
{
    printf("%s EVENT: Domain %s(%d) watchdog action=%d\n", __func__, virDomainGetName(dom),
           virDomainGetID(dom), action);

    return 0;
}

236 237 238 239 240 241 242 243 244 245 246 247 248
static int myDomainEventIOErrorCallback(virConnectPtr conn ATTRIBUTE_UNUSED,
                                        virDomainPtr dom,
                                        const char *srcPath,
                                        const char *devAlias,
                                        int action,
                                        void *opaque ATTRIBUTE_UNUSED)
{
    printf("%s EVENT: Domain %s(%d) io error path=%s alias=%s action=%d\n", __func__, virDomainGetName(dom),
           virDomainGetID(dom), srcPath, devAlias, action);

    return 0;
}

249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289
static int myDomainEventGraphicsCallback(virConnectPtr conn ATTRIBUTE_UNUSED,
                                         virDomainPtr dom,
                                         int phase,
                                         virDomainEventGraphicsAddressPtr local,
                                         virDomainEventGraphicsAddressPtr remote,
                                         const char *authScheme,
                                         virDomainEventGraphicsSubjectPtr subject,
                                         void *opaque ATTRIBUTE_UNUSED)
{
    int i;
    printf("%s EVENT: Domain %s(%d) graphics ", __func__, virDomainGetName(dom),
           virDomainGetID(dom));

    switch (phase) {
    case VIR_DOMAIN_EVENT_GRAPHICS_CONNECT:
        printf("connected ");
        break;
    case VIR_DOMAIN_EVENT_GRAPHICS_INITIALIZE:
        printf("initialized ");
        break;
    case VIR_DOMAIN_EVENT_GRAPHICS_DISCONNECT:
        printf("disconnected ");
        break;
    }

    printf("local: family=%d node=%s service=%s ",
           local->family, local->node, local->service);
    printf("remote: family=%d node=%s service=%s ",
           remote->family, remote->node, remote->service);

    printf("auth: %s ", authScheme);
    for (i = 0 ; i < subject->nidentity ; i++) {
        printf(" identity: %s=%s",
               subject->identities[i].type,
               subject->identities[i].name);
    }
    printf("\n");

    return 0;
}

290 291 292 293 294 295 296 297 298 299 300
static int myDomainEventControlErrorCallback(virConnectPtr conn ATTRIBUTE_UNUSED,
                                             virDomainPtr dom,
                                             void *opaque ATTRIBUTE_UNUSED)
{
    printf("%s EVENT: Domain %s(%d) control error\n", __func__, virDomainGetName(dom),
           virDomainGetID(dom));

    return 0;
}


301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318
const char *diskChangeReasonStrings[] = {
    "startupPolicy", /* 0 */
    /* add new reason here */
};
static int myDomainEventDiskChangeCallback(virConnectPtr conn ATTRIBUTE_UNUSED,
                                           virDomainPtr dom,
                                           const char *oldSrcPath,
                                           const char *newSrcPath,
                                           const char *devAlias,
                                           int reason,
                                           void *opaque ATTRIBUTE_UNUSED)
{
    printf("%s EVENT: Domain %s(%d) disk change oldSrcPath: %s newSrcPath: %s devAlias: %s reason: %s\n",
           __func__, virDomainGetName(dom), virDomainGetID(dom),
           oldSrcPath, newSrcPath, devAlias, diskChangeReasonStrings[reason]);
    return 0;
}

319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334
const char *trayChangeReasonStrings[] = {
    "open",
    "close",
};

static int myDomainEventTrayChangeCallback(virConnectPtr conn ATTRIBUTE_UNUSED,
                                           virDomainPtr dom,
                                           const char *devAlias,
                                           int reason,
                                           void *opaque ATTRIBUTE_UNUSED)
{
    printf("%s EVENT: Domain %s(%d) removable disk's tray change devAlias: %s reason: %s\n",
           __func__, virDomainGetName(dom), virDomainGetID(dom),
           devAlias, trayChangeReasonStrings[reason]);
    return 0;
}
335

O
Osier Yang 已提交
336 337 338 339 340 341 342 343 344 345
static int myDomainEventPMWakeupCallback(virConnectPtr conn ATTRIBUTE_UNUSED,
                                         virDomainPtr dom,
                                         int reason ATTRIBUTE_UNUSED,
                                         void *opaque ATTRIBUTE_UNUSED)
{
    printf("%s EVENT: Domain %s(%d) system pmwakeup",
           __func__, virDomainGetName(dom), virDomainGetID(dom));
    return 0;
}

O
Osier Yang 已提交
346 347 348 349 350 351 352 353 354 355
static int myDomainEventPMSuspendCallback(virConnectPtr conn ATTRIBUTE_UNUSED,
                                          virDomainPtr dom,
                                          int reason ATTRIBUTE_UNUSED,
                                          void *opaque ATTRIBUTE_UNUSED)
{
    printf("%s EVENT: Domain %s(%d) system pmsuspend",
           __func__, virDomainGetName(dom), virDomainGetID(dom));
    return 0;
}

356 357 358
static void myFreeFunc(void *opaque)
{
    char *str = opaque;
359
    printf("%s: Freeing [%s]\n", __func__, str);
360 361 362
    free(str);
}

363 364 365 366 367 368 369 370

/* main test functions */

void usage(const char *pname)
{
    printf("%s uri\n", pname);
}

371 372 373 374 375 376 377 378 379
int run = 1;

static void stop(int sig)
{
    printf("Exiting on signal %d\n", sig);
    run = 0;
}


380 381
int main(int argc, char **argv)
{
382 383
    int callback1ret = -1;
    int callback2ret = -1;
384
    int callback3ret = -1;
385
    int callback4ret = -1;
386
    int callback5ret = -1;
387
    int callback6ret = -1;
388
    int callback7ret = -1;
389
    int callback8ret = -1;
390
    int callback9ret = -1;
391
    int callback10ret = -1;
O
Osier Yang 已提交
392
    int callback11ret = -1;
O
Osier Yang 已提交
393
    int callback12ret = -1;
394
    struct sigaction action_stop;
395

396 397 398
    memset(&action_stop, 0, sizeof action_stop);

    action_stop.sa_handler = stop;
399

400
    if (argc > 1 && STREQ(argv[1], "--help")) {
401 402 403
        usage(argv[0]);
        return -1;
    }
404

405
    virEventRegisterDefaultImpl();
406 407

    virConnectPtr dconn = NULL;
408 409 410
    dconn = virConnectOpenAuth(argc > 1 ? argv[1] : NULL,
                               virConnectAuthPtrDefault,
                               VIR_CONNECT_RO);
411 412 413 414 415
    if (!dconn) {
        printf("error opening\n");
        return -1;
    }

416 417 418
    sigaction(SIGTERM, &action_stop, NULL);
    sigaction(SIGINT, &action_stop, NULL);

419
    VIR_DEBUG("Registering domain event cbs");
420 421

    /* Add 2 callbacks to prove this works with more than just one */
422 423
    callback1ret = virConnectDomainEventRegister(dconn, myDomainEventCallback1,
                                                 strdup("callback 1"), myFreeFunc);
424 425 426 427 428
    callback2ret = virConnectDomainEventRegisterAny(dconn,
                                                    NULL,
                                                    VIR_DOMAIN_EVENT_ID_LIFECYCLE,
                                                    VIR_DOMAIN_EVENT_CALLBACK(myDomainEventCallback2),
                                                    strdup("callback 2"), myFreeFunc);
429 430 431 432 433
    callback3ret = virConnectDomainEventRegisterAny(dconn,
                                                    NULL,
                                                    VIR_DOMAIN_EVENT_ID_REBOOT,
                                                    VIR_DOMAIN_EVENT_CALLBACK(myDomainEventRebootCallback),
                                                    strdup("callback reboot"), myFreeFunc);
434 435 436 437 438
    callback4ret = virConnectDomainEventRegisterAny(dconn,
                                                    NULL,
                                                    VIR_DOMAIN_EVENT_ID_RTC_CHANGE,
                                                    VIR_DOMAIN_EVENT_CALLBACK(myDomainEventRTCChangeCallback),
                                                    strdup("callback rtcchange"), myFreeFunc);
439 440 441 442 443
    callback5ret = virConnectDomainEventRegisterAny(dconn,
                                                    NULL,
                                                    VIR_DOMAIN_EVENT_ID_WATCHDOG,
                                                    VIR_DOMAIN_EVENT_CALLBACK(myDomainEventWatchdogCallback),
                                                    strdup("callback watchdog"), myFreeFunc);
444 445 446 447 448
    callback6ret = virConnectDomainEventRegisterAny(dconn,
                                                    NULL,
                                                    VIR_DOMAIN_EVENT_ID_IO_ERROR,
                                                    VIR_DOMAIN_EVENT_CALLBACK(myDomainEventIOErrorCallback),
                                                    strdup("callback io error"), myFreeFunc);
449 450 451 452 453
    callback7ret = virConnectDomainEventRegisterAny(dconn,
                                                    NULL,
                                                    VIR_DOMAIN_EVENT_ID_GRAPHICS,
                                                    VIR_DOMAIN_EVENT_CALLBACK(myDomainEventGraphicsCallback),
                                                    strdup("callback graphics"), myFreeFunc);
454 455 456 457 458
    callback8ret = virConnectDomainEventRegisterAny(dconn,
                                                    NULL,
                                                    VIR_DOMAIN_EVENT_ID_CONTROL_ERROR,
                                                    VIR_DOMAIN_EVENT_CALLBACK(myDomainEventControlErrorCallback),
                                                    strdup("callback control error"), myFreeFunc);
459 460 461 462 463
    callback9ret = virConnectDomainEventRegisterAny(dconn,
                                                    NULL,
                                                    VIR_DOMAIN_EVENT_ID_DISK_CHANGE,
                                                    VIR_DOMAIN_EVENT_CALLBACK(myDomainEventDiskChangeCallback),
                                                    strdup("disk change"), myFreeFunc);
464 465 466 467 468
    callback10ret = virConnectDomainEventRegisterAny(dconn,
                                                     NULL,
                                                     VIR_DOMAIN_EVENT_ID_TRAY_CHANGE,
                                                     VIR_DOMAIN_EVENT_CALLBACK(myDomainEventTrayChangeCallback),
                                                     strdup("tray change"), myFreeFunc);
O
Osier Yang 已提交
469 470 471 472 473
    callback11ret = virConnectDomainEventRegisterAny(dconn,
                                                     NULL,
                                                     VIR_DOMAIN_EVENT_ID_PMWAKEUP,
                                                     VIR_DOMAIN_EVENT_CALLBACK(myDomainEventPMWakeupCallback),
                                                     strdup("pmwakeup"), myFreeFunc);
O
Osier Yang 已提交
474 475 476 477 478
    callback12ret = virConnectDomainEventRegisterAny(dconn,
                                                     NULL,
                                                     VIR_DOMAIN_EVENT_ID_PMSUSPEND,
                                                     VIR_DOMAIN_EVENT_CALLBACK(myDomainEventPMSuspendCallback),
                                                     strdup("pmsuspend"), myFreeFunc);
479
    if ((callback1ret != -1) &&
480
        (callback2ret != -1) &&
481
        (callback3ret != -1) &&
482
        (callback4ret != -1) &&
483
        (callback5ret != -1) &&
484
        (callback6ret != -1) &&
485
        (callback7ret != -1) &&
486
        (callback9ret != -1) &&
O
Osier Yang 已提交
487
        (callback10ret != -1) &&
O
Osier Yang 已提交
488 489
        (callback11ret != -1) &&
        (callback12ret != -1)) {
490 491 492 493 494 495 496 497
        if (virConnectSetKeepAlive(dconn, 5, 3) < 0) {
            virErrorPtr err = virGetLastError();
            fprintf(stderr, "Failed to start keepalive protocol: %s\n",
                    err && err->message ? err->message : "Unknown error");
            run = 0;
        }

        while (run && virConnectIsAlive(dconn) == 1) {
498 499 500 501
            if (virEventRunDefaultImpl() < 0) {
                virErrorPtr err = virGetLastError();
                fprintf(stderr, "Failed to run event loop: %s\n",
                        err && err->message ? err->message : "Unknown error");
502
            }
503 504
        }

505
        VIR_DEBUG("Deregistering event handlers");
506
        virConnectDomainEventDeregister(dconn, myDomainEventCallback1);
507
        virConnectDomainEventDeregisterAny(dconn, callback2ret);
508
        virConnectDomainEventDeregisterAny(dconn, callback3ret);
509
        virConnectDomainEventDeregisterAny(dconn, callback4ret);
510
        virConnectDomainEventDeregisterAny(dconn, callback5ret);
511
        virConnectDomainEventDeregisterAny(dconn, callback6ret);
512
        virConnectDomainEventDeregisterAny(dconn, callback7ret);
513
        virConnectDomainEventDeregisterAny(dconn, callback9ret);
514
        virConnectDomainEventDeregisterAny(dconn, callback10ret);
O
Osier Yang 已提交
515
        virConnectDomainEventDeregisterAny(dconn, callback11ret);
O
Osier Yang 已提交
516
        virConnectDomainEventDeregisterAny(dconn, callback12ret);
517 518
        if (callback8ret != -1)
            virConnectDomainEventDeregisterAny(dconn, callback8ret);
519 520
    }

521
    VIR_DEBUG("Closing connection");
522
    if (dconn && virConnectClose(dconn) < 0) {
523 524
        printf("error closing\n");
    }
525

526 527 528
    printf("done\n");
    return 0;
}