Update Red Hat Copyright Notices
[nbdkit.git] / plugins / libvirt / libvirt-plugin.c
blob1aee70d7147857bcc2cb4b840f8c613f153381ec
1 /* nbdkit
2 * Copyright Red Hat
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * * Neither the name of Red Hat nor the names of its contributors may be
16 * used to endorse or promote products derived from this software without
17 * specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
22 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
26 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
27 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
29 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
33 /* libvirt-plugin:
35 * This uses the libvirt virDomainBlockPeek API to access the disks of
36 * libvirt guests, even remotely. This only works read-only (since
37 * libvirt does not have an equivalent write API).
39 * http://libvirt.org/html/libvirt-libvirt.html#virDomainBlockPeek
41 * Note to compile this, ./configure must be able to find libvirt.
42 * To unconditionally disable this plugin, use ./configure --without-libvirt
45 #include <config.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <stdint.h>
50 #include <string.h>
51 #include <errno.h>
53 #include <libvirt/libvirt.h>
55 #include <nbdkit-plugin.h>
57 /* Configuration. */
58 static const char *libvirt_uri = NULL;
59 static const char *domain = NULL;
60 static const char *disk = NULL;
62 static int
63 virt_config (const char *key, const char *value)
65 if (strcmp (key, "connect") == 0) {
66 libvirt_uri = value;
68 else if (strcmp (key, "domain") == 0) {
69 domain = value;
71 else if (strcmp (key, "disk") == 0) {
72 disk = value;
74 else {
75 nbdkit_error ("unknown parameter '%s'", key);
76 return -1;
79 return 0;
82 static int
83 virt_config_complete (void)
85 if (domain == NULL) {
86 nbdkit_error ("the 'domain' parameter is required");
87 return -1;
89 if (disk == NULL) {
90 nbdkit_error ("the 'disk' parameter is required");
91 return -1;
93 return 0;
96 #define virt_config_help \
97 "connect=<URI> (optional) libvirt connection URI\n" \
98 "domain=<DOMAIN> (required) libvirt domain name\n" \
99 "disk=<DISK> (required) guest disk name"
101 /* The per-connection handle. */
102 struct virt_handle {
103 virConnectPtr conn;
104 virDomainPtr dom;
105 uint64_t exportsize;
108 /* Create the per-connection handle. */
109 static void *
110 virt_open (int readonly)
112 struct virt_handle *h;
113 virDomainBlockInfo info;
115 h = malloc (sizeof *h);
116 if (h == NULL) {
117 nbdkit_error ("malloc: %m");
118 return NULL;
121 /* Connect to libvirt. */
122 h->conn = virConnectOpen (libvirt_uri);
123 if (!h->conn) {
124 nbdkit_error ("virConnectOpen failed, see earlier error messages");
125 goto err1;
128 /* Open the domain. */
129 h->dom = virDomainLookupByName (h->conn, domain);
130 if (!h->dom) {
131 nbdkit_error ("virDomainLookupByName: "
132 "cannot open domain '%s'", domain);
133 goto err2;
136 if (virDomainGetBlockInfo (h->dom, disk, &info, 0) == -1) {
137 nbdkit_error ("virDomainGetBlockInfo: "
138 "cannot read information about disk '%s' from domain '%s'",
139 disk, domain);
140 goto err3;
142 h->exportsize = info.physical;
144 return h;
146 err3:
147 virDomainFree (h->dom);
148 err2:
149 virConnectClose (h->conn);
150 err1:
151 free (h);
152 return NULL;
155 /* Free up the per-connection handle. */
156 static void
157 virt_close (void *handle)
159 struct virt_handle *h = handle;
161 virDomainFree (h->dom);
162 virConnectClose (h->conn);
163 free (h);
166 #define THREAD_MODEL NBDKIT_THREAD_MODEL_SERIALIZE_REQUESTS
168 /* Get the file size. */
169 static int64_t
170 virt_get_size (void *handle)
172 struct virt_handle *h = handle;
174 return h->exportsize;
177 /* Read data from the file. */
178 static int
179 virt_pread (void *handle, void *buf, uint32_t count, uint64_t offset)
181 struct virt_handle *h = handle;
182 uint32_t c;
184 while (count > 0) {
185 /* Limit requests to 1MB, which was the limit in 0.9.13 (it has since
186 * been raised).
188 c = count;
189 if (c > 1024*1024)
190 c = 1024*1024;
192 if (virDomainBlockPeek (h->dom, disk, offset, c, buf, 0) == -1) {
193 nbdkit_error ("virDomainBlockPeek: cannot read block from disk '%s'",
194 disk);
195 errno = EIO;
196 return -1;
199 buf += c;
200 count -= c;
201 offset += c;
204 return 0;
207 static struct nbdkit_plugin plugin = {
208 .name = "libvirt",
209 .longname = "nbdkit libvirt plugin",
210 .version = PACKAGE_VERSION,
211 .config = virt_config,
212 .config_complete = virt_config_complete,
213 .config_help = virt_config_help,
214 .open = virt_open,
215 .close = virt_close,
216 .get_size = virt_get_size,
217 .pread = virt_pread,
220 NBDKIT_REGISTER_PLUGIN (plugin)