node_device_hal.c 23.6 KB
Newer Older
1 2 3
/*
 * node_device_hal.c: node device enumeration - HAL-based implementation
 *
4
 * Copyright (C) 2011, 2013 Red Hat, Inc.
5 6 7 8 9 10 11 12 13 14 15 16 17 18
 * Copyright (C) 2008 Virtual Iron Software, Inc.
 * Copyright (C) 2008 David F. Lively
 *
 * 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
19
 * License along with this library.  If not, see
O
Osier Yang 已提交
20
 * <http://www.gnu.org/licenses/>.
21 22 23 24
 *
 * Author: David F. Lively <dlively@virtualiron.com>
 */

25 26
#include <config.h>

27 28 29 30 31
#include <stdio.h>
#include <stdlib.h>
#include <libhal.h>

#include "node_device_conf.h"
32
#include "node_device_hal.h"
33
#include "virerror.h"
34 35
#include "driver.h"
#include "datatypes.h"
36
#include "viralloc.h"
37
#include "viruuid.h"
38
#include "virpci.h"
39
#include "virlog.h"
40
#include "node_device_driver.h"
41
#include "virdbus.h"
42
#include "virstring.h"
43

44 45
#define VIR_FROM_THIS VIR_FROM_NODEDEV

46 47 48 49
/*
 * Host device enumeration (HAL implementation)
 */

50
static virNodeDeviceDriverStatePtr driverState;
51 52

#define CONN_DRV_STATE(conn) \
53
        ((virNodeDeviceDriverStatePtr)((conn)->nodeDevicePrivateData))
54 55 56 57 58 59
#define DRV_STATE_HAL_CTX(ds) ((LibHalContext *)((ds)->privateData))
#define CONN_HAL_CTX(conn) DRV_STATE_HAL_CTX(CONN_DRV_STATE(conn))

#define NODE_DEV_UDI(obj) ((const char *)((obj)->privateData)


60 61
static const char *
hal_name(const char *udi)
62 63 64
{
    const char *name = strrchr(udi, '/');
    if (name)
65
        return name + 1;
66 67 68 69
    return udi;
}


70 71 72
static int
get_str_prop(LibHalContext *ctxt, const char *udi,
             const char *prop, char **val_p)
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
{
    char *val = libhal_device_get_property_string(ctxt, udi, prop, NULL);

    if (val) {
        if (*val) {
            *val_p = val;
            return 0;
        } else {
            /* Treat empty strings as NULL values */
            VIR_FREE(val);
        }
    }

    return -1;
}

89 90 91
static int
get_int_prop(LibHalContext *ctxt, const char *udi,
             const char *prop, int *val_p)
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
{
    DBusError err;
    int val;
    int rv;

    dbus_error_init(&err);
    val = libhal_device_get_property_int(ctxt, udi, prop, &err);
    rv = dbus_error_is_set(&err);
    dbus_error_free(&err);
    if (rv == 0)
        *val_p = val;

    return rv;
}

107 108 109
static int
get_bool_prop(LibHalContext *ctxt, const char *udi,
              const char *prop, int *val_p)
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
{
    DBusError err;
    int val;
    int rv;

    dbus_error_init(&err);
    val = libhal_device_get_property_bool(ctxt, udi, prop, &err);
    rv = dbus_error_is_set(&err);
    dbus_error_free(&err);
    if (rv == 0)
        *val_p = val;

    return rv;
}

125 126 127
static int
get_uint64_prop(LibHalContext *ctxt, const char *udi,
                const char *prop, unsigned long long *val_p)
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
{
    DBusError err;
    unsigned long long val;
    int rv;

    dbus_error_init(&err);
    val = libhal_device_get_property_uint64(ctxt, udi, prop, &err);
    rv = dbus_error_is_set(&err);
    dbus_error_free(&err);
    if (rv == 0)
        *val_p = val;

    return rv;
}

143 144 145
static int
gather_pci_cap(LibHalContext *ctx, const char *udi,
               union _virNodeDevCapData *d)
146 147 148 149 150 151 152 153 154 155 156
{
    char *sysfs_path;

    if (get_str_prop(ctx, udi, "pci.linux.sysfs_path", &sysfs_path) == 0) {
        char *p = strrchr(sysfs_path, '/');
        if (p) {
            (void)virStrToLong_ui(p+1, &p, 16, &d->pci_dev.domain);
            (void)virStrToLong_ui(p+1, &p, 16, &d->pci_dev.bus);
            (void)virStrToLong_ui(p+1, &p, 16, &d->pci_dev.slot);
            (void)virStrToLong_ui(p+1, &p, 16, &d->pci_dev.function);
        }
157

158 159
        if (!virPCIGetPhysicalFunction(sysfs_path,
                                       &d->pci_dev.physical_function))
160 161
            d->pci_dev.flags |= VIR_NODE_DEV_CAP_FLAG_PCI_PHYSICAL_FUNCTION;

162 163 164 165 166 167 168
        int ret = virPCIGetVirtualFunctions(sysfs_path,
                                            &d->pci_dev.virtual_functions,
                                            &d->pci_dev.num_virtual_functions);
        if (ret < 0) {
            VIR_FREE(sysfs_path);
            return -1;
        }
169

170 171
        if (d->pci_dev.num_virtual_functions > 0)
            d->pci_dev.flags |= VIR_NODE_DEV_CAP_FLAG_PCI_VIRTUAL_FUNCTION;
172 173
        VIR_FREE(sysfs_path);
    }
174

175 176 177 178 179 180
    (void)get_int_prop(ctx, udi, "pci.vendor_id", (int *)&d->pci_dev.vendor);
    if (get_str_prop(ctx, udi, "pci.vendor", &d->pci_dev.vendor_name) != 0)
        (void)get_str_prop(ctx, udi, "info.vendor", &d->pci_dev.vendor_name);
    (void)get_int_prop(ctx, udi, "pci.product_id", (int *)&d->pci_dev.product);
    if (get_str_prop(ctx, udi, "pci.product", &d->pci_dev.product_name) != 0)
        (void)get_str_prop(ctx, udi, "info.product", &d->pci_dev.product_name);
181

182 183 184 185
    return 0;
}


186 187 188
static int
gather_usb_cap(LibHalContext *ctx, const char *udi,
               union _virNodeDevCapData *d)
189 190 191 192 193 194 195 196 197 198 199 200 201 202 203
{
    (void)get_int_prop(ctx, udi, "usb.interface.number",
                       (int *)&d->usb_if.number);
    (void)get_int_prop(ctx, udi, "usb.interface.class",
                       (int *)&d->usb_if._class);
    (void)get_int_prop(ctx, udi, "usb.interface.subclass",
                       (int *)&d->usb_if.subclass);
    (void)get_int_prop(ctx, udi, "usb.interface.protocol",
                       (int *)&d->usb_if.protocol);
    (void)get_str_prop(ctx, udi, "usb.interface.description",
                       &d->usb_if.description);
    return 0;
}


204 205 206
static int
gather_usb_device_cap(LibHalContext *ctx, const char *udi,
                      union _virNodeDevCapData *d)
207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225
{
    (void)get_int_prop(ctx, udi, "usb_device.bus_number",
                       (int *)&d->usb_dev.bus);
    (void)get_int_prop(ctx, udi, "usb_device.linux.device_number",
                       (int *)&d->usb_dev.device);
    (void)get_int_prop(ctx, udi, "usb_device.vendor_id",
                       (int *)&d->usb_dev.vendor);
    if (get_str_prop(ctx, udi, "usb_device.vendor",
                     &d->usb_dev.vendor_name) != 0)
        (void)get_str_prop(ctx, udi, "info.vendor", &d->usb_dev.vendor_name);
    (void)get_int_prop(ctx, udi, "usb_device.product_id",
                       (int *)&d->usb_dev.product);
    if (get_str_prop(ctx, udi, "usb_device.product",
                     &d->usb_dev.product_name) != 0)
        (void)get_str_prop(ctx, udi, "info.product", &d->usb_dev.product_name);
    return 0;
}


226 227 228
static int
gather_net_cap(LibHalContext *ctx, const char *udi,
               union _virNodeDevCapData *d)
229 230
{
    unsigned long long dummy;
231
    (void)get_str_prop(ctx, udi, "net.interface", &d->net.ifname);
232 233 234 235 236 237 238 239 240 241 242 243 244 245
    (void)get_str_prop(ctx, udi, "net.address", &d->net.address);
    if (get_uint64_prop(ctx, udi, "net.80203.mac_address",
                        &dummy) == 0)
        d->net.subtype = VIR_NODE_DEV_CAP_NET_80203;
    else if (get_uint64_prop(ctx, udi, "net.80211.mac_address",
                             &dummy) == 0)
        d->net.subtype = VIR_NODE_DEV_CAP_NET_80211;
    else
        d->net.subtype = VIR_NODE_DEV_CAP_NET_LAST;

    return 0;
}


246 247 248
static int
gather_scsi_host_cap(LibHalContext *ctx, const char *udi,
                     union _virNodeDevCapData *d)
249
{
250 251
    int retval = 0;

252
    (void)get_int_prop(ctx, udi, "scsi_host.host", (int *)&d->scsi_host.host);
253

O
Osier Yang 已提交
254
    retval = detect_scsi_host_caps(d);
255 256 257 258 259 260 261

    if (retval == -1) {
        goto out;
    }

out:
    return retval;
262 263 264
}


265 266 267
static int
gather_scsi_cap(LibHalContext *ctx, const char *udi,
                union _virNodeDevCapData *d)
268 269 270 271 272 273 274 275 276 277
{
    (void)get_int_prop(ctx, udi, "scsi.host", (int *)&d->scsi.host);
    (void)get_int_prop(ctx, udi, "scsi.bus", (int *)&d->scsi.bus);
    (void)get_int_prop(ctx, udi, "scsi.target", (int *)&d->scsi.target);
    (void)get_int_prop(ctx, udi, "scsi.lun", (int *)&d->scsi.lun);
    (void)get_str_prop(ctx, udi, "scsi.type", &d->scsi.type);
    return 0;
}


278 279 280
static int
gather_storage_cap(LibHalContext *ctx, const char *udi,
                   union _virNodeDevCapData *d)
281 282
{
    int val;
283
    (void)get_str_prop(ctx, udi, "block.device", &d->storage.block);
284 285 286 287
    (void)get_str_prop(ctx, udi, "storage.bus", &d->storage.bus);
    (void)get_str_prop(ctx, udi, "storage.drive_type", &d->storage.drive_type);
    (void)get_str_prop(ctx, udi, "storage.model", &d->storage.model);
    (void)get_str_prop(ctx, udi, "storage.vendor", &d->storage.vendor);
288
    (void)get_str_prop(ctx, udi, "storage.serial", &d->storage.serial);
289 290
    if (get_bool_prop(ctx, udi, "storage.removable", &val) == 0 && val) {
        d->storage.flags |= VIR_NODE_DEV_CAP_STORAGE_REMOVABLE;
291 292
        if (get_bool_prop(ctx, udi, "storage.removable.media_available",
                          &val) == 0 && val) {
293 294 295 296 297 298 299 300 301 302 303 304 305 306
            d->storage.flags |=
                VIR_NODE_DEV_CAP_STORAGE_REMOVABLE_MEDIA_AVAILABLE;
            (void)get_uint64_prop(ctx, udi, "storage.removable.media_size",
                                  &d->storage.removable_media_size);
        }
    } else {
        (void)get_uint64_prop(ctx, udi, "storage.size", &d->storage.size);
    }
    if (get_bool_prop(ctx, udi, "storage.hotpluggable", &val) == 0 && val)
        d->storage.flags |= VIR_NODE_DEV_CAP_STORAGE_HOTPLUGGABLE;
    return 0;
}


307 308 309
static int
gather_system_cap(LibHalContext *ctx, const char *udi,
                  union _virNodeDevCapData *d)
310 311 312 313 314 315 316 317 318 319 320
{
    char *uuidstr;

    (void)get_str_prop(ctx, udi, "system.product", &d->system.product_name);
    (void)get_str_prop(ctx, udi, "system.hardware.vendor",
                       &d->system.hardware.vendor_name);
    (void)get_str_prop(ctx, udi, "system.hardware.version",
                       &d->system.hardware.version);
    (void)get_str_prop(ctx, udi, "system.hardware.serial",
                       &d->system.hardware.serial);
    if (get_str_prop(ctx, udi, "system.hardware.uuid", &uuidstr) == 0) {
321
        ignore_value(virUUIDParse(uuidstr, d->system.hardware.uuid));
322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356
        VIR_FREE(uuidstr);
    }
    (void)get_str_prop(ctx, udi, "system.firmware.vendor",
                       &d->system.firmware.vendor_name);
    (void)get_str_prop(ctx, udi, "system.firmware.version",
                       &d->system.firmware.version);
    (void)get_str_prop(ctx, udi, "system.firmware.release_date",
                       &d->system.firmware.release_date);
    return 0;
}


struct _caps_tbl_entry {
    const char *cap_name;
    enum virNodeDevCapType type;
    int (*gather_fn)(LibHalContext *ctx,
                     const char *udi,
                     union _virNodeDevCapData *data);
};

typedef struct _caps_tbl_entry caps_tbl_entry;

static caps_tbl_entry caps_tbl[] = {
    { "system",     VIR_NODE_DEV_CAP_SYSTEM,        gather_system_cap },
    { "pci",        VIR_NODE_DEV_CAP_PCI_DEV,       gather_pci_cap },
    { "usb",        VIR_NODE_DEV_CAP_USB_INTERFACE, gather_usb_cap },
    { "usb_device", VIR_NODE_DEV_CAP_USB_DEV,       gather_usb_device_cap },
    { "net",        VIR_NODE_DEV_CAP_NET,           gather_net_cap },
    { "scsi_host",  VIR_NODE_DEV_CAP_SCSI_HOST,     gather_scsi_host_cap },
    { "scsi",       VIR_NODE_DEV_CAP_SCSI,          gather_scsi_cap },
    { "storage",    VIR_NODE_DEV_CAP_STORAGE,       gather_storage_cap },
};


/* qsort/bsearch string comparator */
357 358
static int
cmpstringp(const void *p1, const void *p2)
359 360 361 362 363 364
{
    /* from man 3 qsort */
    return strcmp(* (char * const *) p1, * (char * const *) p2);
}


365 366 367 368
static int
gather_capability(LibHalContext *ctx, const char *udi,
                  const char *cap_name,
                  virNodeDevCapsDefPtr *caps_p)
369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394
{
    caps_tbl_entry *entry;

    entry = bsearch(&cap_name, caps_tbl, ARRAY_CARDINALITY(caps_tbl),
                    sizeof(caps_tbl[0]), cmpstringp);

    if (entry) {
        virNodeDevCapsDefPtr caps;
        if (VIR_ALLOC(caps) < 0)
            return ENOMEM;
        caps->type = entry->type;
        if (entry->gather_fn) {
            int rv = (*entry->gather_fn)(ctx, udi, &caps->data);
            if (rv != 0) {
                virNodeDevCapsDefFree(caps);
                return rv;
            }
        }
        caps->next = *caps_p;
        *caps_p = caps;
    }

    return 0;
}


395 396 397
static int
gather_capabilities(LibHalContext *ctx, const char *udi,
                    virNodeDevCapsDefPtr *caps_p)
398 399 400
{
    char *bus_name = NULL;
    virNodeDevCapsDefPtr caps = NULL;
401
    char **hal_cap_names = NULL;
402 403 404 405 406 407 408 409
    int rv, i;

    if (STREQ(udi, "/org/freedesktop/Hal/devices/computer")) {
        rv = gather_capability(ctx, udi, "system", &caps);
        if (rv != 0)
            goto failure;
    }

410 411
    if (get_str_prop(ctx, udi, "info.subsystem", &bus_name) == 0 ||
        get_str_prop(ctx, udi, "linux.subsystem", &bus_name) == 0) {
412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451
        rv = gather_capability(ctx, udi, bus_name, &caps);
        if (rv != 0)
            goto failure;
    }

    hal_cap_names = libhal_device_get_property_strlist(ctx, udi,
                                                       "info.capabilities",
                                                       NULL);
    if (hal_cap_names) {
        for (i = 0; hal_cap_names[i]; i++) {
            if (! (bus_name && STREQ(hal_cap_names[i], bus_name))) {
                rv = gather_capability(ctx, udi, hal_cap_names[i], &caps);
                if (rv != 0)
                    goto failure;
            }
        }
        for (i = 0; hal_cap_names[i]; i++)
            VIR_FREE(hal_cap_names[i]);
        VIR_FREE(hal_cap_names);
    }
    VIR_FREE(bus_name);

    *caps_p = caps;
    return 0;

 failure:
    VIR_FREE(bus_name);
    if (hal_cap_names) {
        for (i = 0; hal_cap_names[i]; i++)
            VIR_FREE(hal_cap_names[i]);
        VIR_FREE(hal_cap_names);
    }
    while (caps) {
        virNodeDevCapsDefPtr next = caps->next;
        virNodeDevCapsDefFree(caps);
        caps = next;
    }
    return rv;
}

452 453
static void
free_udi(void *udi)
454 455 456 457
{
    VIR_FREE(udi);
}

458 459
static void
dev_create(const char *udi)
460
{
461
    LibHalContext *ctx;
462
    char *parent_key = NULL;
463 464
    virNodeDeviceObjPtr dev = NULL;
    virNodeDeviceDefPtr def = NULL;
465 466
    const char *name = hal_name(udi);
    int rv;
467
    char *privData;
468
    char *devicePath = NULL;
469

470
    if (VIR_STRDUP(privData, udi) < 0)
471
        return;
472

473 474 475 476 477
    nodeDeviceLock(driverState);
    ctx = DRV_STATE_HAL_CTX(driverState);

    if (VIR_ALLOC(def) < 0)
        goto failure;
478

479
    if (VIR_STRDUP(def->name, name) < 0)
480 481 482
        goto failure;

    if (get_str_prop(ctx, udi, "info.parent", &parent_key) == 0) {
483 484
        if (VIR_STRDUP(def->parent, hal_name(parent_key)) < 0) {
            VIR_FREE(parent_key);
485
            goto failure;
486 487
        }
        VIR_FREE(parent_key);
488 489
    }

490
    rv = gather_capabilities(ctx, udi, &def->caps);
491 492
    if (rv != 0) goto failure;

493 494
    if (def->caps == NULL)
        goto cleanup;
495

496
    /* Some devices don't have a path in sysfs, so ignore failure */
497
    (void)get_str_prop(ctx, udi, "linux.sysfs_path", &devicePath);
498

499
    dev = virNodeDeviceAssignDef(&driverState->devs,
500 501
                                 def);

502 503
    if (!dev) {
        VIR_FREE(devicePath);
504
        goto failure;
505
    }
506

507 508
    dev->privateData = privData;
    dev->privateFree = free_udi;
509
    dev->def->sysfs_path = devicePath;
510

511
    virNodeDeviceObjUnlock(dev);
512

513
    nodeDeviceUnlock(driverState);
514 515 516
    return;

 failure:
517
    VIR_DEBUG("FAILED TO ADD dev %s", name);
518 519
cleanup:
    VIR_FREE(privData);
520
    virNodeDeviceDefFree(def);
521
    nodeDeviceUnlock(driverState);
522 523
}

524 525
static void
dev_refresh(const char *udi)
526 527 528 529 530 531 532 533 534 535 536 537
{
    const char *name = hal_name(udi);
    virNodeDeviceObjPtr dev;

    nodeDeviceLock(driverState);
    dev = virNodeDeviceFindByName(&driverState->devs, name);
    if (dev) {
        /* Simply "rediscover" device -- incrementally handling changes
         * to sub-capabilities (like net.80203) is nasty ... so avoid it.
         */
        virNodeDeviceObjRemove(&driverState->devs, dev);
    } else
538
        VIR_DEBUG("no device named %s", name);
539 540 541 542 543 544
    nodeDeviceUnlock(driverState);

    if (dev) {
        dev_create(udi);
    }
}
545

546 547 548
static void
device_added(LibHalContext *ctx ATTRIBUTE_UNUSED,
             const char *udi)
549
{
550
    VIR_DEBUG("%s", hal_name(udi));
551
    dev_create(udi);
552 553 554
}


555 556 557
static void
device_removed(LibHalContext *ctx ATTRIBUTE_UNUSED,
               const char *udi)
558 559
{
    const char *name = hal_name(udi);
560 561 562 563
    virNodeDeviceObjPtr dev;

    nodeDeviceLock(driverState);
    dev = virNodeDeviceFindByName(&driverState->devs,name);
564
    VIR_DEBUG("%s", name);
565 566 567
    if (dev)
        virNodeDeviceObjRemove(&driverState->devs, dev);
    else
568
        VIR_DEBUG("no device named %s", name);
569
    nodeDeviceUnlock(driverState);
570 571 572
}


573 574 575
static void
device_cap_added(LibHalContext *ctx,
                 const char *udi, const char *cap)
576 577
{
    const char *name = hal_name(udi);
578 579 580 581 582
    virNodeDeviceObjPtr dev;

    nodeDeviceLock(driverState);
    dev = virNodeDeviceFindByName(&driverState->devs,name);
    nodeDeviceUnlock(driverState);
583
    VIR_DEBUG("%s %s", cap, name);
584
    if (dev) {
585
        (void)gather_capability(ctx, udi, cap, &dev->def->caps);
586 587
        virNodeDeviceObjUnlock(dev);
    } else {
588
        VIR_DEBUG("no device named %s", name);
589
    }
590 591 592
}


593 594 595 596
static void
device_cap_lost(LibHalContext *ctx ATTRIBUTE_UNUSED,
                const char *udi,
                const char *cap)
597 598
{
    const char *name = hal_name(udi);
599
    VIR_DEBUG("%s %s", cap, name);
600 601

    dev_refresh(udi);
602 603 604
}


605 606 607 608 609 610
static void
device_prop_modified(LibHalContext *ctx ATTRIBUTE_UNUSED,
                     const char *udi,
                     const char *key,
                     dbus_bool_t is_removed ATTRIBUTE_UNUSED,
                     dbus_bool_t is_added ATTRIBUTE_UNUSED)
611 612
{
    const char *name = hal_name(udi);
613
    VIR_DEBUG("%s %s", name, key);
614

615
    dev_refresh(udi);
616 617 618
}


619 620 621 622
static int
nodeStateInitialize(bool privileged ATTRIBUTE_UNUSED,
                    virStateInhibitCallback callback ATTRIBUTE_UNUSED,
                    void *opaque ATTRIBUTE_UNUSED)
623 624 625 626
{
    LibHalContext *hal_ctx = NULL;
    char **udi = NULL;
    int num_devs, i;
627
    int ret = -1;
628 629
    DBusConnection *sysbus;
    DBusError err;
630 631 632 633 634 635 636 637

    /* Ensure caps_tbl is sorted by capability name */
    qsort(caps_tbl, ARRAY_CARDINALITY(caps_tbl), sizeof(caps_tbl[0]),
          cmpstringp);

    if (VIR_ALLOC(driverState) < 0)
        return -1;

638 639 640 641
    if (virMutexInit(&driverState->lock) < 0) {
        VIR_FREE(driverState);
        return -1;
    }
642 643
    nodeDeviceLock(driverState);

644 645 646 647 648 649 650
    if (!(sysbus = virDBusGetSystemBus())) {
        virErrorPtr verr = virGetLastError();
        VIR_ERROR(_("DBus not available, disabling HAL driver: %s"),
                    verr->message);
        ret = 0;
        goto failure;
    }
651

652 653 654
    dbus_error_init(&err);
    hal_ctx = libhal_ctx_new();
    if (hal_ctx == NULL) {
655
        VIR_ERROR(_("libhal_ctx_new returned NULL"));
656 657
        goto failure;
    }
658

659
    if (!libhal_ctx_set_dbus_connection(hal_ctx, sysbus)) {
660
        VIR_ERROR(_("libhal_ctx_set_dbus_connection failed"));
661 662 663
        goto failure;
    }
    if (!libhal_ctx_init(hal_ctx, &err)) {
664
        VIR_ERROR(_("libhal_ctx_init failed, haldaemon is probably not running"));
665 666 667 668
        /* We don't want to show a fatal error here,
           otherwise entire libvirtd shuts down when
           hald isn't running */
        ret = 0;
669 670 671
        goto failure;
    }

672 673 674 675 676 677 678 679 680 681
    /* Populate with known devices */
    driverState->privateData = hal_ctx;

    /* We need to unlock state now, since setting these callbacks cause
     * a dbus RPC call, and while this call is waiting for the reply,
     * a signal may already arrive, triggering the callback and thus
     * requiring the lock !
     */
    nodeDeviceUnlock(driverState);

682 683 684 685 686
    /* Register HAL event callbacks */
    if (!libhal_ctx_set_device_added(hal_ctx, device_added) ||
        !libhal_ctx_set_device_removed(hal_ctx, device_removed) ||
        !libhal_ctx_set_device_new_capability(hal_ctx, device_cap_added) ||
        !libhal_ctx_set_device_lost_capability(hal_ctx, device_cap_lost) ||
687
        !libhal_ctx_set_device_property_modified(hal_ctx, device_prop_modified) ||
688
        !libhal_device_property_watch_all(hal_ctx, &err)) {
689
        VIR_ERROR(_("setting up HAL callbacks failed"));
690 691 692 693 694
        goto failure;
    }

    udi = libhal_get_all_devices(hal_ctx, &num_devs, &err);
    if (udi == NULL) {
695
        VIR_ERROR(_("libhal_get_all_devices failed"));
696 697
        goto failure;
    }
698
    for (i = 0; i < num_devs; i++) {
699
        dev_create(udi[i]);
700 701 702
        VIR_FREE(udi[i]);
    }
    VIR_FREE(udi);
703 704 705 706 707

    return 0;

 failure:
    if (dbus_error_is_set(&err)) {
708
        VIR_ERROR(_("%s: %s"), err.name, err.message);
709 710 711 712 713
        dbus_error_free(&err);
    }
    virNodeDeviceObjListFree(&driverState->devs);
    if (hal_ctx)
        (void)libhal_ctx_free(hal_ctx);
714
    nodeDeviceUnlock(driverState);
715 716
    VIR_FREE(driverState);

717
    return ret;
718 719 720
}


721 722
static int
nodeStateCleanup(void)
723 724
{
    if (driverState) {
725
        nodeDeviceLock(driverState);
726 727 728 729
        LibHalContext *hal_ctx = DRV_STATE_HAL_CTX(driverState);
        virNodeDeviceObjListFree(&driverState->devs);
        (void)libhal_ctx_shutdown(hal_ctx, NULL);
        (void)libhal_ctx_free(hal_ctx);
730
        nodeDeviceUnlock(driverState);
731
        virMutexDestroy(&driverState->lock);
732 733 734 735 736 737 738
        VIR_FREE(driverState);
        return 0;
    }
    return -1;
}


739 740
static int
nodeStateReload(void)
741
{
742 743 744 745 746
    DBusError err;
    char **udi = NULL;
    int num_devs, i;
    LibHalContext *hal_ctx;

747
    VIR_INFO("Reloading HAL device state");
748
    nodeDeviceLock(driverState);
749
    VIR_INFO("Removing existing objects");
750 751 752 753
    virNodeDeviceObjListFree(&driverState->devs);
    nodeDeviceUnlock(driverState);

    hal_ctx = DRV_STATE_HAL_CTX(driverState);
754
    VIR_INFO("Creating new objects");
755 756 757
    dbus_error_init(&err);
    udi = libhal_get_all_devices(hal_ctx, &num_devs, &err);
    if (udi == NULL) {
758
        VIR_ERROR(_("libhal_get_all_devices failed"));
759 760 761 762 763 764 765
        return -1;
    }
    for (i = 0; i < num_devs; i++) {
        dev_create(udi[i]);
        VIR_FREE(udi[i]);
    }
    VIR_FREE(udi);
766
    VIR_INFO("HAL device reload complete");
767 768

    return 0;
769 770 771
}


772 773 774 775
static virDrvOpenStatus
nodeDeviceOpen(virConnectPtr conn,
               virConnectAuthPtr auth ATTRIBUTE_UNUSED,
               unsigned int flags)
776
{
E
Eric Blake 已提交
777 778
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

779 780 781
    if (driverState == NULL)
        return VIR_DRV_OPEN_DECLINED;

782
    conn->nodeDevicePrivateData = driverState;
783 784 785 786

    return VIR_DRV_OPEN_SUCCESS;
}

787 788
static int
nodeDeviceClose(virConnectPtr conn ATTRIBUTE_UNUSED)
789
{
790
    conn->nodeDevicePrivateData = NULL;
791 792 793 794
    return 0;
}


795 796
static virNodeDeviceDriver halNodeDeviceDriver = {
    .name = "halNodeDeviceDriver",
797
    .nodeDeviceOpen = nodeDeviceOpen, /* 0.5.0 */
798
    .nodeDeviceClose = nodeDeviceClose, /* 0.5.0 */
799 800
    .nodeNumOfDevices = nodeNumOfDevices, /* 0.5.0 */
    .nodeListDevices = nodeListDevices, /* 0.5.0 */
801
    .connectListAllNodeDevices = nodeConnectListAllNodeDevices, /* 0.10.2 */
802 803 804 805 806 807 808 809
    .nodeDeviceLookupByName = nodeDeviceLookupByName, /* 0.5.0 */
    .nodeDeviceLookupSCSIHostByWWN = nodeDeviceLookupSCSIHostByWWN, /* 1.0.2 */
    .nodeDeviceGetXMLDesc = nodeDeviceGetXMLDesc, /* 0.5.0 */
    .nodeDeviceGetParent = nodeDeviceGetParent, /* 0.5.0 */
    .nodeDeviceNumOfCaps = nodeDeviceNumOfCaps, /* 0.5.0 */
    .nodeDeviceListCaps = nodeDeviceListCaps, /* 0.5.0 */
    .nodeDeviceCreateXML = nodeDeviceCreateXML, /* 0.6.5 */
    .nodeDeviceDestroy = nodeDeviceDestroy, /* 0.6.5 */
810 811 812 813
};


static virStateDriver halStateDriver = {
814
    .name = "HAL",
815 816 817
    .stateInitialize = nodeStateInitialize, /* 0.5.0 */
    .stateCleanup = nodeStateCleanup, /* 0.5.0 */
    .stateReload = nodeStateReload, /* 0.5.0 */
818 819
};

820 821
int
halNodeRegister(void)
822
{
823
    if (virRegisterNodeDeviceDriver(&halNodeDeviceDriver) < 0)
824 825 826
        return -1;
    return virRegisterStateDriver(&halStateDriver);
}