~serge-hallyn/ubuntu/raring/libvirt/libvirt-hugepages

« back to all changes in this revision

Viewing changes to src/node_device_hal.c

  • Committer: James Westby
  • Author(s): Jamie Strandboge
  • Date: 2009-12-02 14:22:21 UTC
  • mfrom: (1.2.3 upstream) (3.4.9 squeeze)
  • Revision ID: james.westby@canonical.com-20091202142221-ltkr0to6h52mla1y
Tags: 0.7.2-4ubuntu1
* Merge from debian testing. Remaining changes:
  - debian/control:
    + Don't build-depend on QEmu
    + Bump bridge-utils, dnsmasq-base, netcat-openbsd, and iptables
      to Depends of libvirt-bin
    + Recommends qemu-kvm (>= 0.11.0-0ubuntu6)
    + Add versioned Conflicts/Replaces to libvirt0 for libvirt0-dbg,
      since we used to ship them as such
    + We call libxen-dev libxen3-dev, so change all references
    + Build-Depends on libxml2-utils
    + Build-Depends on open-iscsi-utils instead of open-iscsi due to
      LP: #414986
  - debian/postinst:
    + rename the libvirt group to libvirtd
    + add each admin user to the libvirtd group
  - debian/libvirt-bin.postrm: rename the libvirt group to libvirtd
  - debian/rules: add DEB_MAKE_CHECK_TARGET := check
  - debian/patches/900[0-7]: updated/refreshed for new paths in 0.7.2
  - debian/patches/series: don't apply 0002-qemu-disable-network.diff.patch
  - AppArmor integration:
    + debian/control: Build-Depends on libapparmor-dev and Suggests
      apparmor (>= 2.3+1289-0ubuntu14)
    + debian/libvirt-bin.dirs: add /etc/apparmor.d/abstractions,
      /etc/apparmor.d/force-complain, /etc/apparmor.d/libvirt,
      /etc/cron.daily and /usr/share/apport/package-hooks
    + add debian/libvirt-bin.cron.daily (LP: #438165)
    + add debian/libvirt-bin.apport
    + debian/libvirt-bin.install: install apparmor profiles, abstractions
      and apport hook
    + debian/postinst: reload apparmor profiles
    + debian/libvirt-bin.postrm: remove apparmor symlinks on purge
    + debian/libvirt-bin.preinst: added to force complain on certain
      upgrades
    + debian/README.Debian: add AppArmor section based on the upstream
      documentation
    + debian/rules: use --with-apparmor and copy apparmor and apport hook to
      debian/tmp
  - Dropped the following patches now included upstream:
    + 0005-Close-logfile-fd-after-spawning-qemu.patch
    + 9090-reenable-nonfile-labels.patch
    + 9091-apparmor.patch
    + 9092-apparmor-autoreconf.patch
* AppArmor integration updates:
  - debian/apparmor/usr.sbin.libvirtd: allow libvirtd access to
    /usr/lib/libvirt/* (LP: #480478)
  - debian/apparmor/libvirt-qemu: allow guests access to
    /etc/pki/libvirt-vnc/** (LP: #484562)
  - debian/libvirt-bin.postinst: 0.7.2 moved /usr/bin/virt-aa-helper to
    /usr/lib/libvirt, so the profile changed from usr.bin.virt-aa-helper
    to usr.lib.libvirt.virt-aa-helper and needs to be migrated. If the user
    made no changes to the old profile, remove it, otherwise, update the
    paths, preserving the shipped usr.lib.libvirt.virt-aa-helper
  - update to 0.7.4 version of the sVirt AppArmor driver (can be dropped in
    0.7.4):
    + debian/patches/9008-apparmor-caps-mockup.patch
    + debian/patches/9009-apparmor-lp453335.patch
    + debian/patches/9010-apparmor-lp460271.patch
    + debian/patches/9011-apparmor-code-cleanups.patch
  - add virt-aa-helper-test and examples/apparmor that were omitted from the
    upstream tarball (can be dropped in 0.7.5):
    + debian/patches/9012-apparmor-add-virt-aa-helper-test.patch
    + debian/patches/9013-apparmor-examples.patch
    + debian/rules: add post-patches target to make virt-aa-helper-test
      executable
* debian/patches/0005-Fix-SELinux-linking-issues.patch: updated to work
  when both apparmor and selinux are available. This patch should be
  dropped in 0.7.4.
* debian/patches/9007-default-config-test-case.patch: updated to not fail
  if building in a deep directory
* debian/patches/9014-event-fuzz.patch: add a little fuzz to not be quite
  so precise with expected expiry time. Fixes FTBFS with HZ=100 kernels.
  Can be dropped in 0.7.5.
* debian/patches/9015-hal-startup-failure-is-nonfatal.patch: disable hal
  driver if hald is not running instead of dying. Can be dropped in
  0.7.4.
* debian/control: temporarily remove Build-Depends on libcap-ng-dev, which
  isn't available in Ubuntu main yet
* revert change to new source format 3.0 (quilt) since Launchpad can't
  handle it yet (see LP: #293106)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * node_device_hal.c: node device enumeration - HAL-based implementation
3
 
 *
4
 
 * Copyright (C) 2008 Virtual Iron Software, Inc.
5
 
 * Copyright (C) 2008 David F. Lively
6
 
 *
7
 
 * This library is free software; you can redistribute it and/or
8
 
 * modify it under the terms of the GNU Lesser General Public
9
 
 * License as published by the Free Software Foundation; either
10
 
 * version 2.1 of the License, or (at your option) any later version.
11
 
 *
12
 
 * This library is distributed in the hope that it will be useful,
13
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
 
 * Lesser General Public License for more details.
16
 
 *
17
 
 * You should have received a copy of the GNU Lesser General Public
18
 
 * License along with this library; if not, write to the Free Software
19
 
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
20
 
 *
21
 
 * Author: David F. Lively <dlively@virtualiron.com>
22
 
 */
23
 
 
24
 
#include <config.h>
25
 
 
26
 
#include <stdio.h>
27
 
#include <stdlib.h>
28
 
#include <libhal.h>
29
 
 
30
 
#include "node_device_conf.h"
31
 
#include "node_device_hal.h"
32
 
#include "virterror_internal.h"
33
 
#include "driver.h"
34
 
#include "datatypes.h"
35
 
#include "event.h"
36
 
#include "memory.h"
37
 
#include "uuid.h"
38
 
#include "logging.h"
39
 
#include "node_device.h"
40
 
 
41
 
#define VIR_FROM_THIS VIR_FROM_NODEDEV
42
 
 
43
 
/*
44
 
 * Host device enumeration (HAL implementation)
45
 
 */
46
 
 
47
 
static virDeviceMonitorStatePtr driverState;
48
 
 
49
 
#define CONN_DRV_STATE(conn) \
50
 
        ((virDeviceMonitorStatePtr)((conn)->devMonPrivateData))
51
 
#define DRV_STATE_HAL_CTX(ds) ((LibHalContext *)((ds)->privateData))
52
 
#define CONN_HAL_CTX(conn) DRV_STATE_HAL_CTX(CONN_DRV_STATE(conn))
53
 
 
54
 
#define NODE_DEV_UDI(obj) ((const char *)((obj)->privateData)
55
 
 
56
 
 
57
 
static const char *hal_name(const char *udi)
58
 
{
59
 
    const char *name = strrchr(udi, '/');
60
 
    if (name)
61
 
        return name+1;
62
 
    return udi;
63
 
}
64
 
 
65
 
 
66
 
static int get_str_prop(LibHalContext *ctxt, const char *udi,
67
 
                        const char *prop, char **val_p)
68
 
{
69
 
    char *val = libhal_device_get_property_string(ctxt, udi, prop, NULL);
70
 
 
71
 
    if (val) {
72
 
        if (*val) {
73
 
            *val_p = val;
74
 
            return 0;
75
 
        } else {
76
 
            /* Treat empty strings as NULL values */
77
 
            VIR_FREE(val);
78
 
        }
79
 
    }
80
 
 
81
 
    return -1;
82
 
}
83
 
 
84
 
static int get_int_prop(LibHalContext *ctxt, const char *udi,
85
 
                        const char *prop, int *val_p)
86
 
{
87
 
    DBusError err;
88
 
    int val;
89
 
    int rv;
90
 
 
91
 
    dbus_error_init(&err);
92
 
    val = libhal_device_get_property_int(ctxt, udi, prop, &err);
93
 
    rv = dbus_error_is_set(&err);
94
 
    dbus_error_free(&err);
95
 
    if (rv == 0)
96
 
        *val_p = val;
97
 
 
98
 
    return rv;
99
 
}
100
 
 
101
 
static int get_bool_prop(LibHalContext *ctxt, const char *udi,
102
 
                         const char *prop, int *val_p)
103
 
{
104
 
    DBusError err;
105
 
    int val;
106
 
    int rv;
107
 
 
108
 
    dbus_error_init(&err);
109
 
    val = libhal_device_get_property_bool(ctxt, udi, prop, &err);
110
 
    rv = dbus_error_is_set(&err);
111
 
    dbus_error_free(&err);
112
 
    if (rv == 0)
113
 
        *val_p = val;
114
 
 
115
 
    return rv;
116
 
}
117
 
 
118
 
static int get_uint64_prop(LibHalContext *ctxt, const char *udi,
119
 
                           const char *prop, unsigned long long *val_p)
120
 
{
121
 
    DBusError err;
122
 
    unsigned long long val;
123
 
    int rv;
124
 
 
125
 
    dbus_error_init(&err);
126
 
    val = libhal_device_get_property_uint64(ctxt, udi, prop, &err);
127
 
    rv = dbus_error_is_set(&err);
128
 
    dbus_error_free(&err);
129
 
    if (rv == 0)
130
 
        *val_p = val;
131
 
 
132
 
    return rv;
133
 
}
134
 
 
135
 
static int gather_pci_cap(LibHalContext *ctx, const char *udi,
136
 
                          union _virNodeDevCapData *d)
137
 
{
138
 
    char *sysfs_path;
139
 
 
140
 
    if (get_str_prop(ctx, udi, "pci.linux.sysfs_path", &sysfs_path) == 0) {
141
 
        char *p = strrchr(sysfs_path, '/');
142
 
        if (p) {
143
 
            (void)virStrToLong_ui(p+1, &p, 16, &d->pci_dev.domain);
144
 
            (void)virStrToLong_ui(p+1, &p, 16, &d->pci_dev.bus);
145
 
            (void)virStrToLong_ui(p+1, &p, 16, &d->pci_dev.slot);
146
 
            (void)virStrToLong_ui(p+1, &p, 16, &d->pci_dev.function);
147
 
        }
148
 
        VIR_FREE(sysfs_path);
149
 
    }
150
 
    (void)get_int_prop(ctx, udi, "pci.vendor_id", (int *)&d->pci_dev.vendor);
151
 
    if (get_str_prop(ctx, udi, "pci.vendor", &d->pci_dev.vendor_name) != 0)
152
 
        (void)get_str_prop(ctx, udi, "info.vendor", &d->pci_dev.vendor_name);
153
 
    (void)get_int_prop(ctx, udi, "pci.product_id", (int *)&d->pci_dev.product);
154
 
    if (get_str_prop(ctx, udi, "pci.product", &d->pci_dev.product_name) != 0)
155
 
        (void)get_str_prop(ctx, udi, "info.product", &d->pci_dev.product_name);
156
 
    return 0;
157
 
}
158
 
 
159
 
 
160
 
static int gather_usb_cap(LibHalContext *ctx, const char *udi,
161
 
                          union _virNodeDevCapData *d)
162
 
{
163
 
    (void)get_int_prop(ctx, udi, "usb.interface.number",
164
 
                       (int *)&d->usb_if.number);
165
 
    (void)get_int_prop(ctx, udi, "usb.interface.class",
166
 
                       (int *)&d->usb_if._class);
167
 
    (void)get_int_prop(ctx, udi, "usb.interface.subclass",
168
 
                       (int *)&d->usb_if.subclass);
169
 
    (void)get_int_prop(ctx, udi, "usb.interface.protocol",
170
 
                       (int *)&d->usb_if.protocol);
171
 
    (void)get_str_prop(ctx, udi, "usb.interface.description",
172
 
                       &d->usb_if.description);
173
 
    return 0;
174
 
}
175
 
 
176
 
 
177
 
static int gather_usb_device_cap(LibHalContext *ctx, const char *udi,
178
 
                          union _virNodeDevCapData *d)
179
 
{
180
 
    (void)get_int_prop(ctx, udi, "usb_device.bus_number",
181
 
                       (int *)&d->usb_dev.bus);
182
 
    (void)get_int_prop(ctx, udi, "usb_device.linux.device_number",
183
 
                       (int *)&d->usb_dev.device);
184
 
    (void)get_int_prop(ctx, udi, "usb_device.vendor_id",
185
 
                       (int *)&d->usb_dev.vendor);
186
 
    if (get_str_prop(ctx, udi, "usb_device.vendor",
187
 
                     &d->usb_dev.vendor_name) != 0)
188
 
        (void)get_str_prop(ctx, udi, "info.vendor", &d->usb_dev.vendor_name);
189
 
    (void)get_int_prop(ctx, udi, "usb_device.product_id",
190
 
                       (int *)&d->usb_dev.product);
191
 
    if (get_str_prop(ctx, udi, "usb_device.product",
192
 
                     &d->usb_dev.product_name) != 0)
193
 
        (void)get_str_prop(ctx, udi, "info.product", &d->usb_dev.product_name);
194
 
    return 0;
195
 
}
196
 
 
197
 
 
198
 
static int gather_net_cap(LibHalContext *ctx, const char *udi,
199
 
                          union _virNodeDevCapData *d)
200
 
{
201
 
    unsigned long long dummy;
202
 
    (void)get_str_prop(ctx, udi, "net.interface", &d->net.ifname);
203
 
    (void)get_str_prop(ctx, udi, "net.address", &d->net.address);
204
 
    if (get_uint64_prop(ctx, udi, "net.80203.mac_address",
205
 
                        &dummy) == 0)
206
 
        d->net.subtype = VIR_NODE_DEV_CAP_NET_80203;
207
 
    else if (get_uint64_prop(ctx, udi, "net.80211.mac_address",
208
 
                             &dummy) == 0)
209
 
        d->net.subtype = VIR_NODE_DEV_CAP_NET_80211;
210
 
    else
211
 
        d->net.subtype = VIR_NODE_DEV_CAP_NET_LAST;
212
 
 
213
 
    return 0;
214
 
}
215
 
 
216
 
 
217
 
static int gather_scsi_host_cap(LibHalContext *ctx, const char *udi,
218
 
                                union _virNodeDevCapData *d)
219
 
{
220
 
    int retval = 0;
221
 
 
222
 
    (void)get_int_prop(ctx, udi, "scsi_host.host", (int *)&d->scsi_host.host);
223
 
 
224
 
    retval = check_fc_host(d);
225
 
 
226
 
    if (retval == -1) {
227
 
        goto out;
228
 
    }
229
 
 
230
 
    retval = check_vport_capable(d);
231
 
 
232
 
out:
233
 
    return retval;
234
 
}
235
 
 
236
 
 
237
 
static int gather_scsi_cap(LibHalContext *ctx, const char *udi,
238
 
                           union _virNodeDevCapData *d)
239
 
{
240
 
    (void)get_int_prop(ctx, udi, "scsi.host", (int *)&d->scsi.host);
241
 
    (void)get_int_prop(ctx, udi, "scsi.bus", (int *)&d->scsi.bus);
242
 
    (void)get_int_prop(ctx, udi, "scsi.target", (int *)&d->scsi.target);
243
 
    (void)get_int_prop(ctx, udi, "scsi.lun", (int *)&d->scsi.lun);
244
 
    (void)get_str_prop(ctx, udi, "scsi.type", &d->scsi.type);
245
 
    return 0;
246
 
}
247
 
 
248
 
 
249
 
static int gather_storage_cap(LibHalContext *ctx, const char *udi,
250
 
                              union _virNodeDevCapData *d)
251
 
{
252
 
    int val;
253
 
    (void)get_str_prop(ctx, udi, "block.device", &d->storage.block);
254
 
    (void)get_str_prop(ctx, udi, "storage.bus", &d->storage.bus);
255
 
    (void)get_str_prop(ctx, udi, "storage.drive_type", &d->storage.drive_type);
256
 
    (void)get_str_prop(ctx, udi, "storage.model", &d->storage.model);
257
 
    (void)get_str_prop(ctx, udi, "storage.vendor", &d->storage.vendor);
258
 
    (void)get_str_prop(ctx, udi, "storage.serial", &d->storage.serial);
259
 
    if (get_bool_prop(ctx, udi, "storage.removable", &val) == 0 && val) {
260
 
        d->storage.flags |= VIR_NODE_DEV_CAP_STORAGE_REMOVABLE;
261
 
        if (get_bool_prop(ctx, udi, "storage.removable.media_available",
262
 
                          &val) == 0 && val) {
263
 
            d->storage.flags |=
264
 
                VIR_NODE_DEV_CAP_STORAGE_REMOVABLE_MEDIA_AVAILABLE;
265
 
            (void)get_uint64_prop(ctx, udi, "storage.removable.media_size",
266
 
                                  &d->storage.removable_media_size);
267
 
        }
268
 
    } else {
269
 
        (void)get_uint64_prop(ctx, udi, "storage.size", &d->storage.size);
270
 
    }
271
 
    if (get_bool_prop(ctx, udi, "storage.hotpluggable", &val) == 0 && val)
272
 
        d->storage.flags |= VIR_NODE_DEV_CAP_STORAGE_HOTPLUGGABLE;
273
 
    return 0;
274
 
}
275
 
 
276
 
 
277
 
static int gather_system_cap(LibHalContext *ctx, const char *udi,
278
 
                             union _virNodeDevCapData *d)
279
 
{
280
 
    char *uuidstr;
281
 
 
282
 
    (void)get_str_prop(ctx, udi, "system.product", &d->system.product_name);
283
 
    (void)get_str_prop(ctx, udi, "system.hardware.vendor",
284
 
                       &d->system.hardware.vendor_name);
285
 
    (void)get_str_prop(ctx, udi, "system.hardware.version",
286
 
                       &d->system.hardware.version);
287
 
    (void)get_str_prop(ctx, udi, "system.hardware.serial",
288
 
                       &d->system.hardware.serial);
289
 
    if (get_str_prop(ctx, udi, "system.hardware.uuid", &uuidstr) == 0) {
290
 
        (void)virUUIDParse(uuidstr, d->system.hardware.uuid);
291
 
        VIR_FREE(uuidstr);
292
 
    }
293
 
    (void)get_str_prop(ctx, udi, "system.firmware.vendor",
294
 
                       &d->system.firmware.vendor_name);
295
 
    (void)get_str_prop(ctx, udi, "system.firmware.version",
296
 
                       &d->system.firmware.version);
297
 
    (void)get_str_prop(ctx, udi, "system.firmware.release_date",
298
 
                       &d->system.firmware.release_date);
299
 
    return 0;
300
 
}
301
 
 
302
 
 
303
 
struct _caps_tbl_entry {
304
 
    const char *cap_name;
305
 
    enum virNodeDevCapType type;
306
 
    int (*gather_fn)(LibHalContext *ctx,
307
 
                     const char *udi,
308
 
                     union _virNodeDevCapData *data);
309
 
};
310
 
 
311
 
typedef struct _caps_tbl_entry caps_tbl_entry;
312
 
 
313
 
static caps_tbl_entry caps_tbl[] = {
314
 
    { "system",     VIR_NODE_DEV_CAP_SYSTEM,        gather_system_cap },
315
 
    { "pci",        VIR_NODE_DEV_CAP_PCI_DEV,       gather_pci_cap },
316
 
    { "usb",        VIR_NODE_DEV_CAP_USB_INTERFACE, gather_usb_cap },
317
 
    { "usb_device", VIR_NODE_DEV_CAP_USB_DEV,       gather_usb_device_cap },
318
 
    { "net",        VIR_NODE_DEV_CAP_NET,           gather_net_cap },
319
 
    { "scsi_host",  VIR_NODE_DEV_CAP_SCSI_HOST,     gather_scsi_host_cap },
320
 
    { "scsi",       VIR_NODE_DEV_CAP_SCSI,          gather_scsi_cap },
321
 
    { "storage",    VIR_NODE_DEV_CAP_STORAGE,       gather_storage_cap },
322
 
};
323
 
 
324
 
 
325
 
/* qsort/bsearch string comparator */
326
 
static int cmpstringp(const void *p1, const void *p2)
327
 
{
328
 
    /* from man 3 qsort */
329
 
    return strcmp(* (char * const *) p1, * (char * const *) p2);
330
 
}
331
 
 
332
 
 
333
 
static int gather_capability(LibHalContext *ctx, const char *udi,
334
 
                             const char *cap_name,
335
 
                             virNodeDevCapsDefPtr *caps_p)
336
 
{
337
 
    caps_tbl_entry *entry;
338
 
 
339
 
    entry = bsearch(&cap_name, caps_tbl, ARRAY_CARDINALITY(caps_tbl),
340
 
                    sizeof(caps_tbl[0]), cmpstringp);
341
 
 
342
 
    if (entry) {
343
 
        virNodeDevCapsDefPtr caps;
344
 
        if (VIR_ALLOC(caps) < 0)
345
 
            return ENOMEM;
346
 
        caps->type = entry->type;
347
 
        if (entry->gather_fn) {
348
 
            int rv = (*entry->gather_fn)(ctx, udi, &caps->data);
349
 
            if (rv != 0) {
350
 
                virNodeDevCapsDefFree(caps);
351
 
                return rv;
352
 
            }
353
 
        }
354
 
        caps->next = *caps_p;
355
 
        *caps_p = caps;
356
 
    }
357
 
 
358
 
    return 0;
359
 
}
360
 
 
361
 
 
362
 
static int gather_capabilities(LibHalContext *ctx, const char *udi,
363
 
                               virNodeDevCapsDefPtr *caps_p)
364
 
{
365
 
    char *bus_name = NULL;
366
 
    virNodeDevCapsDefPtr caps = NULL;
367
 
    char **hal_cap_names;
368
 
    int rv, i;
369
 
 
370
 
    if (STREQ(udi, "/org/freedesktop/Hal/devices/computer")) {
371
 
        rv = gather_capability(ctx, udi, "system", &caps);
372
 
        if (rv != 0)
373
 
            goto failure;
374
 
    }
375
 
 
376
 
    if (get_str_prop(ctx, udi, "info.subsystem", &bus_name) == 0 ||
377
 
        get_str_prop(ctx, udi, "linux.subsystem", &bus_name) == 0) {
378
 
        rv = gather_capability(ctx, udi, bus_name, &caps);
379
 
        if (rv != 0)
380
 
            goto failure;
381
 
    }
382
 
 
383
 
    hal_cap_names = libhal_device_get_property_strlist(ctx, udi,
384
 
                                                       "info.capabilities",
385
 
                                                       NULL);
386
 
    if (hal_cap_names) {
387
 
        for (i = 0; hal_cap_names[i]; i++) {
388
 
            if (! (bus_name && STREQ(hal_cap_names[i], bus_name))) {
389
 
                rv = gather_capability(ctx, udi, hal_cap_names[i], &caps);
390
 
                if (rv != 0)
391
 
                    goto failure;
392
 
            }
393
 
        }
394
 
        for (i = 0; hal_cap_names[i]; i++)
395
 
            VIR_FREE(hal_cap_names[i]);
396
 
        VIR_FREE(hal_cap_names);
397
 
    }
398
 
    VIR_FREE(bus_name);
399
 
 
400
 
    *caps_p = caps;
401
 
    return 0;
402
 
 
403
 
 failure:
404
 
    VIR_FREE(bus_name);
405
 
    if (hal_cap_names) {
406
 
        for (i = 0; hal_cap_names[i]; i++)
407
 
            VIR_FREE(hal_cap_names[i]);
408
 
        VIR_FREE(hal_cap_names);
409
 
    }
410
 
    while (caps) {
411
 
        virNodeDevCapsDefPtr next = caps->next;
412
 
        virNodeDevCapsDefFree(caps);
413
 
        caps = next;
414
 
    }
415
 
    return rv;
416
 
}
417
 
 
418
 
static void free_udi(void *udi)
419
 
{
420
 
    VIR_FREE(udi);
421
 
}
422
 
 
423
 
static void dev_create(const char *udi)
424
 
{
425
 
    LibHalContext *ctx;
426
 
    char *parent_key = NULL;
427
 
    virNodeDeviceObjPtr dev = NULL;
428
 
    virNodeDeviceDefPtr def = NULL;
429
 
    const char *name = hal_name(udi);
430
 
    int rv;
431
 
    char *privData = strdup(udi);
432
 
    char *devicePath = NULL;
433
 
 
434
 
    if (!privData)
435
 
        return;
436
 
 
437
 
    nodeDeviceLock(driverState);
438
 
    ctx = DRV_STATE_HAL_CTX(driverState);
439
 
 
440
 
    if (VIR_ALLOC(def) < 0)
441
 
        goto failure;
442
 
 
443
 
    if ((def->name = strdup(name)) == NULL)
444
 
        goto failure;
445
 
 
446
 
    if (get_str_prop(ctx, udi, "info.parent", &parent_key) == 0) {
447
 
        def->parent = strdup(hal_name(parent_key));
448
 
        VIR_FREE(parent_key);
449
 
        if (def->parent == NULL)
450
 
            goto failure;
451
 
    }
452
 
 
453
 
    rv = gather_capabilities(ctx, udi, &def->caps);
454
 
    if (rv != 0) goto failure;
455
 
 
456
 
    if (def->caps == NULL)
457
 
        goto cleanup;
458
 
 
459
 
    /* Some devices don't have a path in sysfs, so ignore failure */
460
 
    get_str_prop(ctx, udi, "linux.sysfs_path", &devicePath);
461
 
 
462
 
    dev = virNodeDeviceAssignDef(NULL,
463
 
                                 &driverState->devs,
464
 
                                 def);
465
 
 
466
 
    if (!dev) {
467
 
        VIR_FREE(devicePath);
468
 
        goto failure;
469
 
    }
470
 
 
471
 
    dev->privateData = privData;
472
 
    dev->privateFree = free_udi;
473
 
    dev->devicePath = devicePath;
474
 
 
475
 
    virNodeDeviceObjUnlock(dev);
476
 
 
477
 
    nodeDeviceUnlock(driverState);
478
 
    return;
479
 
 
480
 
 failure:
481
 
    DEBUG("FAILED TO ADD dev %s", name);
482
 
cleanup:
483
 
    VIR_FREE(privData);
484
 
    if (def)
485
 
        virNodeDeviceDefFree(def);
486
 
    nodeDeviceUnlock(driverState);
487
 
}
488
 
 
489
 
static void dev_refresh(const char *udi)
490
 
{
491
 
    const char *name = hal_name(udi);
492
 
    virNodeDeviceObjPtr dev;
493
 
 
494
 
    nodeDeviceLock(driverState);
495
 
    dev = virNodeDeviceFindByName(&driverState->devs, name);
496
 
    if (dev) {
497
 
        /* Simply "rediscover" device -- incrementally handling changes
498
 
         * to sub-capabilities (like net.80203) is nasty ... so avoid it.
499
 
         */
500
 
        virNodeDeviceObjRemove(&driverState->devs, dev);
501
 
    } else
502
 
        DEBUG("no device named %s", name);
503
 
    nodeDeviceUnlock(driverState);
504
 
 
505
 
    if (dev) {
506
 
        dev_create(udi);
507
 
    }
508
 
}
509
 
 
510
 
static void device_added(LibHalContext *ctx ATTRIBUTE_UNUSED,
511
 
                         const char *udi)
512
 
{
513
 
    DEBUG0(hal_name(udi));
514
 
    dev_create(udi);
515
 
}
516
 
 
517
 
 
518
 
static void device_removed(LibHalContext *ctx ATTRIBUTE_UNUSED,
519
 
                           const char *udi)
520
 
{
521
 
    const char *name = hal_name(udi);
522
 
    virNodeDeviceObjPtr dev;
523
 
 
524
 
    nodeDeviceLock(driverState);
525
 
    dev = virNodeDeviceFindByName(&driverState->devs,name);
526
 
    DEBUG0(name);
527
 
    if (dev)
528
 
        virNodeDeviceObjRemove(&driverState->devs, dev);
529
 
    else
530
 
        DEBUG("no device named %s", name);
531
 
    nodeDeviceUnlock(driverState);
532
 
}
533
 
 
534
 
 
535
 
static void device_cap_added(LibHalContext *ctx,
536
 
                             const char *udi, const char *cap)
537
 
{
538
 
    const char *name = hal_name(udi);
539
 
    virNodeDeviceObjPtr dev;
540
 
 
541
 
    nodeDeviceLock(driverState);
542
 
    dev = virNodeDeviceFindByName(&driverState->devs,name);
543
 
    nodeDeviceUnlock(driverState);
544
 
    DEBUG("%s %s", cap, name);
545
 
    if (dev) {
546
 
        (void)gather_capability(ctx, udi, cap, &dev->def->caps);
547
 
        virNodeDeviceObjUnlock(dev);
548
 
    } else {
549
 
        DEBUG("no device named %s", name);
550
 
    }
551
 
}
552
 
 
553
 
 
554
 
static void device_cap_lost(LibHalContext *ctx ATTRIBUTE_UNUSED,
555
 
                            const char *udi,
556
 
                            const char *cap)
557
 
{
558
 
    const char *name = hal_name(udi);
559
 
    DEBUG("%s %s", cap, name);
560
 
 
561
 
    dev_refresh(udi);
562
 
}
563
 
 
564
 
 
565
 
static void device_prop_modified(LibHalContext *ctx ATTRIBUTE_UNUSED,
566
 
                                 const char *udi,
567
 
                                 const char *key,
568
 
                                 dbus_bool_t is_removed ATTRIBUTE_UNUSED,
569
 
                                 dbus_bool_t is_added ATTRIBUTE_UNUSED)
570
 
{
571
 
    const char *name = hal_name(udi);
572
 
    DEBUG("%s %s", name, key);
573
 
 
574
 
    dev_refresh(udi);
575
 
}
576
 
 
577
 
 
578
 
static void dbus_watch_callback(int fdatch ATTRIBUTE_UNUSED,
579
 
                                int fd ATTRIBUTE_UNUSED,
580
 
                                int events, void *opaque)
581
 
{
582
 
    DBusWatch *watch = opaque;
583
 
    LibHalContext *hal_ctx;
584
 
    DBusConnection *dbus_conn;
585
 
    int dbus_flags = 0;
586
 
 
587
 
    if (events & VIR_EVENT_HANDLE_READABLE)
588
 
        dbus_flags |= DBUS_WATCH_READABLE;
589
 
    if (events & VIR_EVENT_HANDLE_WRITABLE)
590
 
        dbus_flags |= DBUS_WATCH_WRITABLE;
591
 
    if (events & VIR_EVENT_HANDLE_ERROR)
592
 
        dbus_flags |= DBUS_WATCH_ERROR;
593
 
    if (events & VIR_EVENT_HANDLE_HANGUP)
594
 
        dbus_flags |= DBUS_WATCH_HANGUP;
595
 
 
596
 
    (void)dbus_watch_handle(watch, dbus_flags);
597
 
 
598
 
    nodeDeviceLock(driverState);
599
 
    hal_ctx = DRV_STATE_HAL_CTX(driverState);
600
 
    dbus_conn = libhal_ctx_get_dbus_connection(hal_ctx);
601
 
    nodeDeviceUnlock(driverState);
602
 
    while (dbus_connection_dispatch(dbus_conn) == DBUS_DISPATCH_DATA_REMAINS)
603
 
        /* keep dispatching while data remains */;
604
 
}
605
 
 
606
 
 
607
 
static int xlate_dbus_watch_flags(int dbus_flags)
608
 
{
609
 
    unsigned int flags = 0;
610
 
    if (dbus_flags & DBUS_WATCH_READABLE)
611
 
        flags |= VIR_EVENT_HANDLE_READABLE;
612
 
    if (dbus_flags & DBUS_WATCH_WRITABLE)
613
 
        flags |= VIR_EVENT_HANDLE_WRITABLE;
614
 
    if (dbus_flags & DBUS_WATCH_ERROR)
615
 
        flags |= VIR_EVENT_HANDLE_ERROR;
616
 
    if (dbus_flags & DBUS_WATCH_HANGUP)
617
 
        flags |= VIR_EVENT_HANDLE_HANGUP;
618
 
    return flags;
619
 
}
620
 
 
621
 
 
622
 
struct nodeDeviceWatchInfo
623
 
{
624
 
    int watch;
625
 
};
626
 
 
627
 
static void nodeDeviceWatchFree(void *data) {
628
 
    struct nodeDeviceWatchInfo *info = data;
629
 
    VIR_FREE(info);
630
 
}
631
 
 
632
 
static dbus_bool_t add_dbus_watch(DBusWatch *watch,
633
 
                                  void *data ATTRIBUTE_UNUSED)
634
 
{
635
 
    int flags = 0;
636
 
    int fd;
637
 
    struct nodeDeviceWatchInfo *info;
638
 
 
639
 
    if (VIR_ALLOC(info) < 0)
640
 
        return 0;
641
 
 
642
 
    if (dbus_watch_get_enabled(watch))
643
 
        flags = xlate_dbus_watch_flags(dbus_watch_get_flags(watch));
644
 
 
645
 
#if HAVE_DBUS_WATCH_GET_UNIX_FD
646
 
    fd = dbus_watch_get_unix_fd(watch);
647
 
#else
648
 
    fd = dbus_watch_get_fd(watch);
649
 
#endif
650
 
    info->watch = virEventAddHandle(fd, flags, dbus_watch_callback,
651
 
                                    watch, NULL);
652
 
    if (info->watch < 0) {
653
 
        VIR_FREE(info);
654
 
        return 0;
655
 
    }
656
 
    dbus_watch_set_data(watch, info, nodeDeviceWatchFree);
657
 
 
658
 
    return 1;
659
 
}
660
 
 
661
 
 
662
 
static void remove_dbus_watch(DBusWatch *watch,
663
 
                              void *data ATTRIBUTE_UNUSED)
664
 
{
665
 
    struct nodeDeviceWatchInfo *info;
666
 
 
667
 
    info = dbus_watch_get_data(watch);
668
 
 
669
 
    (void)virEventRemoveHandle(info->watch);
670
 
}
671
 
 
672
 
 
673
 
static void toggle_dbus_watch(DBusWatch *watch,
674
 
                              void *data ATTRIBUTE_UNUSED)
675
 
{
676
 
    int flags = 0;
677
 
    struct nodeDeviceWatchInfo *info;
678
 
 
679
 
    if (dbus_watch_get_enabled(watch))
680
 
        flags = xlate_dbus_watch_flags(dbus_watch_get_flags(watch));
681
 
 
682
 
    info = dbus_watch_get_data(watch);
683
 
 
684
 
    (void)virEventUpdateHandle(info->watch, flags);
685
 
}
686
 
 
687
 
 
688
 
static int halDeviceMonitorStartup(int privileged ATTRIBUTE_UNUSED)
689
 
{
690
 
    LibHalContext *hal_ctx = NULL;
691
 
    DBusConnection *dbus_conn = NULL;
692
 
    DBusError err;
693
 
    char **udi = NULL;
694
 
    int num_devs, i;
695
 
 
696
 
    /* Ensure caps_tbl is sorted by capability name */
697
 
    qsort(caps_tbl, ARRAY_CARDINALITY(caps_tbl), sizeof(caps_tbl[0]),
698
 
          cmpstringp);
699
 
 
700
 
    if (VIR_ALLOC(driverState) < 0)
701
 
        return -1;
702
 
 
703
 
    if (virMutexInit(&driverState->lock) < 0) {
704
 
        VIR_FREE(driverState);
705
 
        return -1;
706
 
    }
707
 
    nodeDeviceLock(driverState);
708
 
 
709
 
    /* Allocate and initialize a new HAL context */
710
 
    dbus_connection_set_change_sigpipe(FALSE);
711
 
    dbus_threads_init_default();
712
 
 
713
 
    dbus_error_init(&err);
714
 
    hal_ctx = libhal_ctx_new();
715
 
    if (hal_ctx == NULL) {
716
 
        VIR_ERROR0("libhal_ctx_new returned NULL\n");
717
 
        goto failure;
718
 
    }
719
 
    dbus_conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
720
 
    if (dbus_conn == NULL) {
721
 
        VIR_ERROR0("dbus_bus_get failed\n");
722
 
        goto failure;
723
 
    }
724
 
    dbus_connection_set_exit_on_disconnect(dbus_conn, FALSE);
725
 
 
726
 
    if (!libhal_ctx_set_dbus_connection(hal_ctx, dbus_conn)) {
727
 
        VIR_ERROR0("libhal_ctx_set_dbus_connection failed\n");
728
 
        goto failure;
729
 
    }
730
 
    if (!libhal_ctx_init(hal_ctx, &err)) {
731
 
        VIR_ERROR0("libhal_ctx_init failed\n");
732
 
        goto failure;
733
 
    }
734
 
 
735
 
    /* Register dbus watch callbacks */
736
 
    if (!dbus_connection_set_watch_functions(dbus_conn,
737
 
                                             add_dbus_watch,
738
 
                                             remove_dbus_watch,
739
 
                                             toggle_dbus_watch,
740
 
                                             NULL, NULL)) {
741
 
        VIR_ERROR0("dbus_connection_set_watch_functions failed\n");
742
 
        goto failure;
743
 
    }
744
 
 
745
 
    /* Register HAL event callbacks */
746
 
    if (!libhal_ctx_set_device_added(hal_ctx, device_added) ||
747
 
        !libhal_ctx_set_device_removed(hal_ctx, device_removed) ||
748
 
        !libhal_ctx_set_device_new_capability(hal_ctx, device_cap_added) ||
749
 
        !libhal_ctx_set_device_lost_capability(hal_ctx, device_cap_lost) ||
750
 
        !libhal_ctx_set_device_property_modified(hal_ctx, device_prop_modified) ||
751
 
        !libhal_device_property_watch_all(hal_ctx, &err)) {
752
 
        VIR_ERROR0("setting up HAL callbacks failed\n");
753
 
        goto failure;
754
 
    }
755
 
 
756
 
    /* Populate with known devices */
757
 
    driverState->privateData = hal_ctx;
758
 
 
759
 
    nodeDeviceUnlock(driverState);
760
 
    udi = libhal_get_all_devices(hal_ctx, &num_devs, &err);
761
 
    if (udi == NULL) {
762
 
        VIR_ERROR0("libhal_get_all_devices failed\n");
763
 
        goto failure;
764
 
    }
765
 
    for (i = 0; i < num_devs; i++) {
766
 
        dev_create(udi[i]);
767
 
        VIR_FREE(udi[i]);
768
 
    }
769
 
    VIR_FREE(udi);
770
 
 
771
 
    return 0;
772
 
 
773
 
 failure:
774
 
    if (dbus_error_is_set(&err)) {
775
 
        VIR_ERROR("%s: %s\n", err.name, err.message);
776
 
        dbus_error_free(&err);
777
 
    }
778
 
    virNodeDeviceObjListFree(&driverState->devs);
779
 
    if (hal_ctx)
780
 
        (void)libhal_ctx_free(hal_ctx);
781
 
    if (udi) {
782
 
        for (i = 0; i < num_devs; i++)
783
 
            VIR_FREE(udi[i]);
784
 
        VIR_FREE(udi);
785
 
    }
786
 
    nodeDeviceUnlock(driverState);
787
 
    VIR_FREE(driverState);
788
 
 
789
 
    return -1;
790
 
}
791
 
 
792
 
 
793
 
static int halDeviceMonitorShutdown(void)
794
 
{
795
 
    if (driverState) {
796
 
        nodeDeviceLock(driverState);
797
 
        LibHalContext *hal_ctx = DRV_STATE_HAL_CTX(driverState);
798
 
        virNodeDeviceObjListFree(&driverState->devs);
799
 
        (void)libhal_ctx_shutdown(hal_ctx, NULL);
800
 
        (void)libhal_ctx_free(hal_ctx);
801
 
        nodeDeviceUnlock(driverState);
802
 
        virMutexDestroy(&driverState->lock);
803
 
        VIR_FREE(driverState);
804
 
        return 0;
805
 
    }
806
 
    return -1;
807
 
}
808
 
 
809
 
 
810
 
static int halDeviceMonitorReload(void)
811
 
{
812
 
    DBusError err;
813
 
    char **udi = NULL;
814
 
    int num_devs, i;
815
 
    LibHalContext *hal_ctx;
816
 
 
817
 
    VIR_INFO0("Reloading HAL device state");
818
 
    nodeDeviceLock(driverState);
819
 
    VIR_INFO0("Removing existing objects");
820
 
    virNodeDeviceObjListFree(&driverState->devs);
821
 
    nodeDeviceUnlock(driverState);
822
 
 
823
 
    hal_ctx = DRV_STATE_HAL_CTX(driverState);
824
 
    VIR_INFO0("Creating new objects");
825
 
    dbus_error_init(&err);
826
 
    udi = libhal_get_all_devices(hal_ctx, &num_devs, &err);
827
 
    if (udi == NULL) {
828
 
        fprintf(stderr, "%s: libhal_get_all_devices failed\n", __FUNCTION__);
829
 
        return -1;
830
 
    }
831
 
    for (i = 0; i < num_devs; i++) {
832
 
        dev_create(udi[i]);
833
 
        VIR_FREE(udi[i]);
834
 
    }
835
 
    VIR_FREE(udi);
836
 
    VIR_INFO0("HAL device reload complete");
837
 
 
838
 
    return 0;
839
 
}
840
 
 
841
 
 
842
 
static int halDeviceMonitorActive(void)
843
 
{
844
 
    /* Always ready to deal with a shutdown */
845
 
    return 0;
846
 
}
847
 
 
848
 
 
849
 
static virDrvOpenStatus halNodeDrvOpen(virConnectPtr conn,
850
 
                                       virConnectAuthPtr auth ATTRIBUTE_UNUSED,
851
 
                                       int flags ATTRIBUTE_UNUSED)
852
 
{
853
 
    if (driverState == NULL)
854
 
        return VIR_DRV_OPEN_DECLINED;
855
 
 
856
 
    conn->devMonPrivateData = driverState;
857
 
 
858
 
    return VIR_DRV_OPEN_SUCCESS;
859
 
}
860
 
 
861
 
static int halNodeDrvClose(virConnectPtr conn ATTRIBUTE_UNUSED)
862
 
{
863
 
    conn->devMonPrivateData = NULL;
864
 
    return 0;
865
 
}
866
 
 
867
 
 
868
 
static virDeviceMonitor halDeviceMonitor = {
869
 
    .name = "halDeviceMonitor",
870
 
    .open = halNodeDrvOpen,
871
 
    .close = halNodeDrvClose,
872
 
};
873
 
 
874
 
 
875
 
static virStateDriver halStateDriver = {
876
 
    .initialize = halDeviceMonitorStartup,
877
 
    .cleanup = halDeviceMonitorShutdown,
878
 
    .reload = halDeviceMonitorReload,
879
 
    .active = halDeviceMonitorActive,
880
 
};
881
 
 
882
 
int halNodeRegister(void)
883
 
{
884
 
    registerCommonNodeFuncs(&halDeviceMonitor);
885
 
    if (virRegisterDeviceMonitor(&halDeviceMonitor) < 0)
886
 
        return -1;
887
 
    return virRegisterStateDriver(&halStateDriver);
888
 
}