backup: Wire up qemu full pull backup commands over QMP
[libvirt/ericb.git] / tools / virsh-volume.c
blob97803b21bef40cdba53662dc509a2caf0ede911d
1 /*
2 * virsh-volume.c: Commands to manage storage volume
4 * Copyright (C) 2005, 2007-2016 Red Hat, Inc.
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library. If not, see
18 * <http://www.gnu.org/licenses/>.
21 #include <config.h>
22 #include "virsh-volume.h"
23 #include "virsh-util.h"
25 #include <fcntl.h>
27 #include <libxml/parser.h>
28 #include <libxml/tree.h>
29 #include <libxml/xpath.h>
30 #include <libxml/xmlsave.h>
32 #include "internal.h"
33 #include "virbuffer.h"
34 #include "viralloc.h"
35 #include "virutil.h"
36 #include "virfile.h"
37 #include "virsh-pool.h"
38 #include "virxml.h"
39 #include "virstring.h"
40 #include "vsh-table.h"
41 #include "virenum.h"
43 #define VIRSH_COMMON_OPT_POOL_FULL \
44 VIRSH_COMMON_OPT_POOL(N_("pool name or uuid"), \
45 VIR_CONNECT_LIST_STORAGE_POOLS_ACTIVE)
47 #define VIRSH_COMMON_OPT_POOL_NAME \
48 VIRSH_COMMON_OPT_POOL(N_("pool name"), \
49 VIR_CONNECT_LIST_STORAGE_POOLS_ACTIVE)
51 #define VIRSH_COMMON_OPT_POOL_OPTIONAL \
52 {.name = "pool", \
53 .type = VSH_OT_STRING, \
54 .help = N_("pool name or uuid"), \
55 .completer = virshStoragePoolNameCompleter, \
56 .completer_flags = VIR_CONNECT_LIST_STORAGE_POOLS_ACTIVE, \
59 #define VIRSH_COMMON_OPT_VOLUME_VOL \
60 {.name = "vol", \
61 .type = VSH_OT_DATA, \
62 .flags = VSH_OFLAG_REQ, \
63 .help = N_("vol name, key or path"), \
64 .completer = virshStorageVolNameCompleter, \
67 virStorageVolPtr
68 virshCommandOptVolBy(vshControl *ctl, const vshCmd *cmd,
69 const char *optname,
70 const char *pooloptname,
71 const char **name, unsigned int flags)
73 virStorageVolPtr vol = NULL;
74 virStoragePoolPtr pool = NULL;
75 const char *n = NULL, *p = NULL;
76 virshControlPtr priv = ctl->privData;
78 virCheckFlags(VIRSH_BYUUID | VIRSH_BYNAME, NULL);
80 if (vshCommandOptStringReq(ctl, cmd, optname, &n) < 0)
81 return NULL;
83 if (pooloptname != NULL &&
84 vshCommandOptStringReq(ctl, cmd, pooloptname, &p) < 0)
85 return NULL;
87 if (p) {
88 if (!(pool = virshCommandOptPoolBy(ctl, cmd, pooloptname, name, flags)))
89 return NULL;
91 if (virStoragePoolIsActive(pool) != 1) {
92 vshError(ctl, _("pool '%s' is not active"), p);
93 virStoragePoolFree(pool);
94 return NULL;
98 vshDebug(ctl, VSH_ERR_DEBUG, "%s: found option <%s>: %s\n",
99 cmd->def->name, optname, n);
101 if (name)
102 *name = n;
104 /* try it by name */
105 if (pool && (flags & VIRSH_BYNAME)) {
106 vshDebug(ctl, VSH_ERR_DEBUG, "%s: <%s> trying as vol name\n",
107 cmd->def->name, optname);
108 vol = virStorageVolLookupByName(pool, n);
110 /* try it by key */
111 if (!vol && (flags & VIRSH_BYUUID)) {
112 vshDebug(ctl, VSH_ERR_DEBUG, "%s: <%s> trying as vol key\n",
113 cmd->def->name, optname);
114 vol = virStorageVolLookupByKey(priv->conn, n);
116 /* try it by path */
117 if (!vol && (flags & VIRSH_BYUUID)) {
118 vshDebug(ctl, VSH_ERR_DEBUG, "%s: <%s> trying as vol path\n",
119 cmd->def->name, optname);
120 vol = virStorageVolLookupByPath(priv->conn, n);
123 if (!vol) {
124 if (pool || !pooloptname)
125 vshError(ctl, _("failed to get vol '%s'"), n);
126 else
127 vshError(ctl, _("failed to get vol '%s', specifying --%s "
128 "might help"), n, pooloptname);
129 } else {
130 vshResetLibvirtError();
133 /* If the pool was specified, then make sure that the returned
134 * volume is from the given pool */
135 if (pool && vol) {
136 virStoragePoolPtr volpool = NULL;
138 if ((volpool = virStoragePoolLookupByVolume(vol))) {
139 if (STRNEQ(virStoragePoolGetName(volpool),
140 virStoragePoolGetName(pool))) {
141 vshResetLibvirtError();
142 vshError(ctl,
143 _("Requested volume '%s' is not in pool '%s'"),
144 n, virStoragePoolGetName(pool));
145 virStorageVolFree(vol);
146 vol = NULL;
148 virStoragePoolFree(volpool);
152 if (pool)
153 virStoragePoolFree(pool);
155 return vol;
159 * "vol-create-as" command
161 static const vshCmdInfo info_vol_create_as[] = {
162 {.name = "help",
163 .data = N_("create a volume from a set of args")
165 {.name = "desc",
166 .data = N_("Create a vol.")
168 {.name = NULL}
171 static const vshCmdOptDef opts_vol_create_as[] = {
172 VIRSH_COMMON_OPT_POOL_NAME,
173 {.name = "name",
174 .type = VSH_OT_DATA,
175 .flags = VSH_OFLAG_REQ,
176 .help = N_("name of the volume")
178 {.name = "capacity",
179 .type = VSH_OT_DATA,
180 .flags = VSH_OFLAG_REQ,
181 .help = N_("size of the vol, as scaled integer (default bytes)")
183 {.name = "allocation",
184 .type = VSH_OT_STRING,
185 .help = N_("initial allocation size, as scaled integer (default bytes)")
187 {.name = "format",
188 .type = VSH_OT_STRING,
189 .help = N_("file format type raw,bochs,qcow,qcow2,qed,vmdk")
191 {.name = "backing-vol",
192 .type = VSH_OT_STRING,
193 .help = N_("the backing volume if taking a snapshot")
195 {.name = "backing-vol-format",
196 .type = VSH_OT_STRING,
197 .help = N_("format of backing volume if taking a snapshot")
199 {.name = "prealloc-metadata",
200 .type = VSH_OT_BOOL,
201 .help = N_("preallocate metadata (for qcow2 instead of full allocation)")
203 {.name = "print-xml",
204 .type = VSH_OT_BOOL,
205 .help = N_("print XML document, but don't define/create")
207 {.name = NULL}
210 static int
211 virshVolSize(const char *data, unsigned long long *val)
213 char *end;
214 if (virStrToLong_ullp(data, &end, 10, val) < 0)
215 return -1;
216 return virScaleInteger(val, end, 1, ULLONG_MAX);
219 static bool
220 cmdVolCreateAs(vshControl *ctl, const vshCmd *cmd)
222 virStoragePoolPtr pool;
223 virStorageVolPtr vol = NULL;
224 char *xml = NULL;
225 bool printXML = vshCommandOptBool(cmd, "print-xml");
226 const char *name, *capacityStr = NULL, *allocationStr = NULL, *format = NULL;
227 const char *snapshotStrVol = NULL, *snapshotStrFormat = NULL;
228 unsigned long long capacity, allocation = 0;
229 virBuffer buf = VIR_BUFFER_INITIALIZER;
230 unsigned long flags = 0;
231 virshControlPtr priv = ctl->privData;
232 bool ret = false;
234 if (vshCommandOptBool(cmd, "prealloc-metadata"))
235 flags |= VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA;
237 if (!(pool = virshCommandOptPool(ctl, cmd, "pool", NULL)))
238 return false;
240 if (vshCommandOptStringReq(ctl, cmd, "name", &name) < 0)
241 goto cleanup;
243 if (vshCommandOptStringReq(ctl, cmd, "capacity", &capacityStr) < 0)
244 goto cleanup;
246 if (virshVolSize(capacityStr, &capacity) < 0) {
247 vshError(ctl, _("Malformed size %s"), capacityStr);
248 goto cleanup;
251 if (vshCommandOptStringQuiet(ctl, cmd, "allocation", &allocationStr) > 0 &&
252 virshVolSize(allocationStr, &allocation) < 0) {
253 vshError(ctl, _("Malformed size %s"), allocationStr);
254 goto cleanup;
257 if (vshCommandOptStringReq(ctl, cmd, "format", &format) < 0 ||
258 vshCommandOptStringReq(ctl, cmd, "backing-vol", &snapshotStrVol) < 0 ||
259 vshCommandOptStringReq(ctl, cmd, "backing-vol-format",
260 &snapshotStrFormat) < 0)
261 goto cleanup;
263 virBufferAddLit(&buf, "<volume>\n");
264 virBufferAdjustIndent(&buf, 2);
265 virBufferAsprintf(&buf, "<name>%s</name>\n", name);
266 virBufferAsprintf(&buf, "<capacity>%llu</capacity>\n", capacity);
267 if (allocationStr)
268 virBufferAsprintf(&buf, "<allocation>%llu</allocation>\n", allocation);
270 if (format) {
271 virBufferAddLit(&buf, "<target>\n");
272 virBufferAdjustIndent(&buf, 2);
273 virBufferAsprintf(&buf, "<format type='%s'/>\n", format);
274 virBufferAdjustIndent(&buf, -2);
275 virBufferAddLit(&buf, "</target>\n");
278 /* Convert the snapshot parameters into backingStore XML */
279 if (snapshotStrVol) {
280 /* Lookup snapshot backing volume. Try the backing-vol
281 * parameter as a name */
282 vshDebug(ctl, VSH_ERR_DEBUG,
283 "%s: Look up backing store volume '%s' as name\n",
284 cmd->def->name, snapshotStrVol);
285 virStorageVolPtr snapVol = virStorageVolLookupByName(pool, snapshotStrVol);
286 if (snapVol)
287 vshDebug(ctl, VSH_ERR_DEBUG,
288 "%s: Backing store volume found using '%s' as name\n",
289 cmd->def->name, snapshotStrVol);
291 if (snapVol == NULL) {
292 /* Snapshot backing volume not found by name. Try the
293 * backing-vol parameter as a key */
294 vshDebug(ctl, VSH_ERR_DEBUG,
295 "%s: Look up backing store volume '%s' as key\n",
296 cmd->def->name, snapshotStrVol);
297 snapVol = virStorageVolLookupByKey(priv->conn, snapshotStrVol);
298 if (snapVol)
299 vshDebug(ctl, VSH_ERR_DEBUG,
300 "%s: Backing store volume found using '%s' as key\n",
301 cmd->def->name, snapshotStrVol);
303 if (snapVol == NULL) {
304 /* Snapshot backing volume not found by key. Try the
305 * backing-vol parameter as a path */
306 vshDebug(ctl, VSH_ERR_DEBUG,
307 "%s: Look up backing store volume '%s' as path\n",
308 cmd->def->name, snapshotStrVol);
309 snapVol = virStorageVolLookupByPath(priv->conn, snapshotStrVol);
310 if (snapVol)
311 vshDebug(ctl, VSH_ERR_DEBUG,
312 "%s: Backing store volume found using '%s' as path\n",
313 cmd->def->name, snapshotStrVol);
315 if (snapVol == NULL) {
316 vshError(ctl, _("failed to get vol '%s'"), snapshotStrVol);
317 goto cleanup;
320 char *snapshotStrVolPath;
321 if ((snapshotStrVolPath = virStorageVolGetPath(snapVol)) == NULL) {
322 virStorageVolFree(snapVol);
323 goto cleanup;
326 /* Create XML for the backing store */
327 virBufferAddLit(&buf, "<backingStore>\n");
328 virBufferAdjustIndent(&buf, 2);
329 virBufferAsprintf(&buf, "<path>%s</path>\n", snapshotStrVolPath);
330 if (snapshotStrFormat)
331 virBufferAsprintf(&buf, "<format type='%s'/>\n",
332 snapshotStrFormat);
333 virBufferAdjustIndent(&buf, -2);
334 virBufferAddLit(&buf, "</backingStore>\n");
336 /* Cleanup snapshot allocations */
337 VIR_FREE(snapshotStrVolPath);
338 virStorageVolFree(snapVol);
341 virBufferAdjustIndent(&buf, -2);
342 virBufferAddLit(&buf, "</volume>\n");
344 if (virBufferError(&buf)) {
345 vshError(ctl, "%s", _("Failed to allocate XML buffer"));
346 goto cleanup;
348 xml = virBufferContentAndReset(&buf);
350 if (printXML) {
351 vshPrint(ctl, "%s", xml);
352 } else {
353 if (!(vol = virStorageVolCreateXML(pool, xml, flags))) {
354 vshError(ctl, _("Failed to create vol %s"), name);
355 goto cleanup;
357 vshPrintExtra(ctl, _("Vol %s created\n"), name);
360 ret = true;
362 cleanup:
363 virBufferFreeAndReset(&buf);
364 if (vol)
365 virStorageVolFree(vol);
366 virStoragePoolFree(pool);
367 VIR_FREE(xml);
368 return ret;
372 * "vol-create" command
374 static const vshCmdInfo info_vol_create[] = {
375 {.name = "help",
376 .data = N_("create a vol from an XML file")
378 {.name = "desc",
379 .data = N_("Create a vol.")
381 {.name = NULL}
384 static const vshCmdOptDef opts_vol_create[] = {
385 VIRSH_COMMON_OPT_POOL_NAME,
386 VIRSH_COMMON_OPT_FILE(N_("file containing an XML vol description")),
387 {.name = "prealloc-metadata",
388 .type = VSH_OT_BOOL,
389 .help = N_("preallocate metadata (for qcow2 instead of full allocation)")
391 {.name = NULL}
394 static bool
395 cmdVolCreate(vshControl *ctl, const vshCmd *cmd)
397 virStoragePoolPtr pool;
398 virStorageVolPtr vol;
399 const char *from = NULL;
400 bool ret = false;
401 unsigned int flags = 0;
402 char *buffer = NULL;
404 if (vshCommandOptBool(cmd, "prealloc-metadata"))
405 flags |= VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA;
407 if (!(pool = virshCommandOptPool(ctl, cmd, "pool", NULL)))
408 return false;
410 if (vshCommandOptStringReq(ctl, cmd, "file", &from) < 0)
411 goto cleanup;
413 if (virFileReadAll(from, VSH_MAX_XML_FILE, &buffer) < 0) {
414 vshSaveLibvirtError();
415 goto cleanup;
418 if ((vol = virStorageVolCreateXML(pool, buffer, flags))) {
419 vshPrintExtra(ctl, _("Vol %s created from %s\n"),
420 virStorageVolGetName(vol), from);
421 virStorageVolFree(vol);
422 ret = true;
423 } else {
424 vshError(ctl, _("Failed to create vol from %s"), from);
427 cleanup:
428 VIR_FREE(buffer);
429 virStoragePoolFree(pool);
430 return ret;
434 * "vol-create-from" command
436 static const vshCmdInfo info_vol_create_from[] = {
437 {.name = "help",
438 .data = N_("create a vol, using another volume as input")
440 {.name = "desc",
441 .data = N_("Create a vol from an existing volume.")
443 {.name = NULL}
446 static const vshCmdOptDef opts_vol_create_from[] = {
447 VIRSH_COMMON_OPT_POOL_FULL,
448 VIRSH_COMMON_OPT_FILE(N_("file containing an XML vol description")),
449 VIRSH_COMMON_OPT_VOLUME_VOL,
450 {.name = "inputpool",
451 .type = VSH_OT_STRING,
452 .help = N_("pool name or uuid of the input volume's pool")
454 {.name = "prealloc-metadata",
455 .type = VSH_OT_BOOL,
456 .help = N_("preallocate metadata (for qcow2 instead of full allocation)")
458 {.name = "reflink",
459 .type = VSH_OT_BOOL,
460 .help = N_("use btrfs COW lightweight copy")
462 {.name = NULL}
465 static bool
466 cmdVolCreateFrom(vshControl *ctl, const vshCmd *cmd)
468 virStoragePoolPtr pool = NULL;
469 virStorageVolPtr newvol = NULL, inputvol = NULL;
470 const char *from = NULL;
471 bool ret = false;
472 char *buffer = NULL;
473 unsigned int flags = 0;
475 if (!(pool = virshCommandOptPool(ctl, cmd, "pool", NULL)))
476 goto cleanup;
478 if (vshCommandOptBool(cmd, "prealloc-metadata"))
479 flags |= VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA;
481 if (vshCommandOptBool(cmd, "reflink"))
482 flags |= VIR_STORAGE_VOL_CREATE_REFLINK;
484 if (vshCommandOptStringReq(ctl, cmd, "file", &from) < 0)
485 goto cleanup;
487 if (!(inputvol = virshCommandOptVol(ctl, cmd, "vol", "inputpool", NULL)))
488 goto cleanup;
490 if (virFileReadAll(from, VSH_MAX_XML_FILE, &buffer) < 0) {
491 vshReportError(ctl);
492 goto cleanup;
495 newvol = virStorageVolCreateXMLFrom(pool, buffer, inputvol, flags);
497 if (newvol != NULL) {
498 vshPrintExtra(ctl, _("Vol %s created from input vol %s\n"),
499 virStorageVolGetName(newvol), virStorageVolGetName(inputvol));
500 } else {
501 vshError(ctl, _("Failed to create vol from %s"), from);
502 goto cleanup;
505 ret = true;
506 cleanup:
507 VIR_FREE(buffer);
508 if (pool)
509 virStoragePoolFree(pool);
510 if (inputvol)
511 virStorageVolFree(inputvol);
512 if (newvol)
513 virStorageVolFree(newvol);
514 return ret;
517 static xmlChar *
518 virshMakeCloneXML(const char *origxml, const char *newname)
520 xmlDocPtr doc = NULL;
521 xmlXPathContextPtr ctxt = NULL;
522 xmlXPathObjectPtr obj = NULL;
523 xmlChar *newxml = NULL;
524 int size;
526 doc = virXMLParseStringCtxt(origxml, _("(volume_definition)"), &ctxt);
527 if (!doc)
528 goto cleanup;
530 obj = xmlXPathEval(BAD_CAST "/volume/name", ctxt);
531 if (obj == NULL || obj->nodesetval == NULL ||
532 obj->nodesetval->nodeTab == NULL)
533 goto cleanup;
535 xmlNodeSetContent(obj->nodesetval->nodeTab[0], (const xmlChar *)newname);
536 xmlDocDumpMemory(doc, &newxml, &size);
538 cleanup:
539 xmlXPathFreeObject(obj);
540 xmlXPathFreeContext(ctxt);
541 xmlFreeDoc(doc);
542 return newxml;
546 * "vol-clone" command
548 static const vshCmdInfo info_vol_clone[] = {
549 {.name = "help",
550 .data = N_("clone a volume.")
552 {.name = "desc",
553 .data = N_("Clone an existing volume within the parent pool.")
555 {.name = NULL}
558 static const vshCmdOptDef opts_vol_clone[] = {
559 VIRSH_COMMON_OPT_VOLUME_VOL,
560 {.name = "newname",
561 .type = VSH_OT_DATA,
562 .flags = VSH_OFLAG_REQ,
563 .help = N_("clone name")
565 VIRSH_COMMON_OPT_POOL_OPTIONAL,
566 {.name = "prealloc-metadata",
567 .type = VSH_OT_BOOL,
568 .help = N_("preallocate metadata (for qcow2 instead of full allocation)")
570 {.name = "reflink",
571 .type = VSH_OT_BOOL,
572 .help = N_("use btrfs COW lightweight copy")
574 {.name = NULL}
577 static bool
578 cmdVolClone(vshControl *ctl, const vshCmd *cmd)
580 virStoragePoolPtr origpool = NULL;
581 virStorageVolPtr origvol = NULL, newvol = NULL;
582 const char *name = NULL;
583 char *origxml = NULL;
584 xmlChar *newxml = NULL;
585 bool ret = false;
586 unsigned int flags = 0;
588 if (!(origvol = virshCommandOptVol(ctl, cmd, "vol", "pool", NULL)))
589 goto cleanup;
591 if (vshCommandOptBool(cmd, "prealloc-metadata"))
592 flags |= VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA;
594 if (vshCommandOptBool(cmd, "reflink"))
595 flags |= VIR_STORAGE_VOL_CREATE_REFLINK;
597 origpool = virStoragePoolLookupByVolume(origvol);
598 if (!origpool) {
599 vshError(ctl, "%s", _("failed to get parent pool"));
600 goto cleanup;
603 if (vshCommandOptStringReq(ctl, cmd, "newname", &name) < 0)
604 goto cleanup;
606 origxml = virStorageVolGetXMLDesc(origvol, 0);
607 if (!origxml)
608 goto cleanup;
610 newxml = virshMakeCloneXML(origxml, name);
611 if (!newxml) {
612 vshError(ctl, "%s", _("Failed to allocate XML buffer"));
613 goto cleanup;
616 newvol = virStorageVolCreateXMLFrom(origpool, (char *) newxml, origvol, flags);
618 if (newvol != NULL) {
619 vshPrintExtra(ctl, _("Vol %s cloned from %s\n"),
620 virStorageVolGetName(newvol), virStorageVolGetName(origvol));
621 } else {
622 vshError(ctl, _("Failed to clone vol from %s"),
623 virStorageVolGetName(origvol));
624 goto cleanup;
627 ret = true;
629 cleanup:
630 VIR_FREE(origxml);
631 xmlFree(newxml);
632 if (origvol)
633 virStorageVolFree(origvol);
634 if (newvol)
635 virStorageVolFree(newvol);
636 if (origpool)
637 virStoragePoolFree(origpool);
638 return ret;
642 * "vol-upload" command
644 static const vshCmdInfo info_vol_upload[] = {
645 {.name = "help",
646 .data = N_("upload file contents to a volume")
648 {.name = "desc",
649 .data = N_("Upload file contents to a volume")
651 {.name = NULL}
654 static const vshCmdOptDef opts_vol_upload[] = {
655 VIRSH_COMMON_OPT_VOLUME_VOL,
656 VIRSH_COMMON_OPT_FILE(N_("file")),
657 VIRSH_COMMON_OPT_POOL_OPTIONAL,
658 {.name = "offset",
659 .type = VSH_OT_INT,
660 .help = N_("volume offset to upload to")
662 {.name = "length",
663 .type = VSH_OT_INT,
664 .help = N_("amount of data to upload")
666 {.name = "sparse",
667 .type = VSH_OT_BOOL,
668 .help = N_("preserve sparseness of volume")
670 {.name = NULL}
673 static bool
674 cmdVolUpload(vshControl *ctl, const vshCmd *cmd)
676 const char *file = NULL;
677 virStorageVolPtr vol = NULL;
678 bool ret = false;
679 int fd = -1;
680 virStreamPtr st = NULL;
681 const char *name = NULL;
682 unsigned long long offset = 0, length = 0;
683 virshControlPtr priv = ctl->privData;
684 unsigned int flags = 0;
685 virshStreamCallbackData cbData;
687 if (vshCommandOptULongLong(ctl, cmd, "offset", &offset) < 0)
688 return false;
690 if (vshCommandOptULongLongWrap(ctl, cmd, "length", &length) < 0)
691 return false;
693 if (!(vol = virshCommandOptVol(ctl, cmd, "vol", "pool", &name)))
694 return false;
696 if (vshCommandOptStringReq(ctl, cmd, "file", &file) < 0)
697 goto cleanup;
699 if ((fd = open(file, O_RDONLY)) < 0) {
700 vshError(ctl, _("cannot read %s"), file);
701 goto cleanup;
704 cbData.ctl = ctl;
705 cbData.fd = fd;
707 if (vshCommandOptBool(cmd, "sparse"))
708 flags |= VIR_STORAGE_VOL_UPLOAD_SPARSE_STREAM;
710 if (!(st = virStreamNew(priv->conn, 0))) {
711 vshError(ctl, _("cannot create a new stream"));
712 goto cleanup;
715 if (virStorageVolUpload(vol, st, offset, length, flags) < 0) {
716 vshError(ctl, _("cannot upload to volume %s"), name);
717 goto cleanup;
720 if (flags & VIR_STORAGE_VOL_UPLOAD_SPARSE_STREAM) {
721 if (virStreamSparseSendAll(st, virshStreamSource,
722 virshStreamInData,
723 virshStreamSourceSkip, &cbData) < 0) {
724 vshError(ctl, _("cannot send data to volume %s"), name);
725 goto cleanup;
727 } else {
728 if (virStreamSendAll(st, virshStreamSource, &cbData) < 0) {
729 vshError(ctl, _("cannot send data to volume %s"), name);
730 goto cleanup;
734 if (VIR_CLOSE(fd) < 0) {
735 vshError(ctl, _("cannot close file %s"), file);
736 virStreamAbort(st);
737 goto cleanup;
740 if (virStreamFinish(st) < 0) {
741 vshError(ctl, _("cannot close volume %s"), name);
742 goto cleanup;
745 ret = true;
747 cleanup:
748 if (vol)
749 virStorageVolFree(vol);
750 if (st)
751 virStreamFree(st);
752 VIR_FORCE_CLOSE(fd);
753 return ret;
757 * "vol-download" command
759 static const vshCmdInfo info_vol_download[] = {
760 {.name = "help",
761 .data = N_("download volume contents to a file")
763 {.name = "desc",
764 .data = N_("Download volume contents to a file")
766 {.name = NULL}
769 static const vshCmdOptDef opts_vol_download[] = {
770 VIRSH_COMMON_OPT_VOLUME_VOL,
771 VIRSH_COMMON_OPT_FILE(N_("file")),
772 VIRSH_COMMON_OPT_POOL_OPTIONAL,
773 {.name = "offset",
774 .type = VSH_OT_INT,
775 .help = N_("volume offset to download from")
777 {.name = "length",
778 .type = VSH_OT_INT,
779 .help = N_("amount of data to download")
781 {.name = "sparse",
782 .type = VSH_OT_BOOL,
783 .help = N_("preserve sparseness of volume")
785 {.name = NULL}
788 static bool
789 cmdVolDownload(vshControl *ctl, const vshCmd *cmd)
791 const char *file = NULL;
792 virStorageVolPtr vol = NULL;
793 bool ret = false;
794 int fd = -1;
795 virStreamPtr st = NULL;
796 const char *name = NULL;
797 unsigned long long offset = 0, length = 0;
798 bool created = false;
799 virshControlPtr priv = ctl->privData;
800 unsigned int flags = 0;
802 if (vshCommandOptULongLong(ctl, cmd, "offset", &offset) < 0)
803 return false;
805 if (vshCommandOptULongLongWrap(ctl, cmd, "length", &length) < 0)
806 return false;
808 if (!(vol = virshCommandOptVol(ctl, cmd, "vol", "pool", &name)))
809 return false;
811 if (vshCommandOptStringReq(ctl, cmd, "file", &file) < 0)
812 goto cleanup;
814 if (vshCommandOptBool(cmd, "sparse"))
815 flags |= VIR_STORAGE_VOL_DOWNLOAD_SPARSE_STREAM;
817 if ((fd = open(file, O_WRONLY|O_CREAT|O_EXCL, 0666)) < 0) {
818 if (errno != EEXIST ||
819 (fd = open(file, O_WRONLY|O_TRUNC, 0666)) < 0) {
820 vshError(ctl, _("cannot create %s"), file);
821 goto cleanup;
823 } else {
824 created = true;
827 if (!(st = virStreamNew(priv->conn, 0))) {
828 vshError(ctl, _("cannot create a new stream"));
829 goto cleanup;
832 if (virStorageVolDownload(vol, st, offset, length, flags) < 0) {
833 vshError(ctl, _("cannot download from volume %s"), name);
834 goto cleanup;
837 if (virStreamSparseRecvAll(st, virshStreamSink, virshStreamSkip, &fd) < 0) {
838 vshError(ctl, _("cannot receive data from volume %s"), name);
839 goto cleanup;
842 if (VIR_CLOSE(fd) < 0) {
843 vshError(ctl, _("cannot close file %s"), file);
844 virStreamAbort(st);
845 goto cleanup;
848 if (virStreamFinish(st) < 0) {
849 vshError(ctl, _("cannot close volume %s"), name);
850 goto cleanup;
853 ret = true;
855 cleanup:
856 VIR_FORCE_CLOSE(fd);
857 if (!ret && created)
858 unlink(file);
859 if (vol)
860 virStorageVolFree(vol);
861 if (st)
862 virStreamFree(st);
863 return ret;
867 * "vol-delete" command
869 static const vshCmdInfo info_vol_delete[] = {
870 {.name = "help",
871 .data = N_("delete a vol")
873 {.name = "desc",
874 .data = N_("Delete a given vol.")
876 {.name = NULL}
879 static const vshCmdOptDef opts_vol_delete[] = {
880 VIRSH_COMMON_OPT_VOLUME_VOL,
881 VIRSH_COMMON_OPT_POOL_OPTIONAL,
882 {.name = "delete-snapshots",
883 .type = VSH_OT_BOOL,
884 .help = N_("delete snapshots associated with volume (must be "
885 "supported by storage driver)")
887 {.name = NULL}
890 static bool
891 cmdVolDelete(vshControl *ctl, const vshCmd *cmd)
893 virStorageVolPtr vol;
894 bool ret = true;
895 const char *name;
896 bool delete_snapshots = vshCommandOptBool(cmd, "delete-snapshots");
897 unsigned int flags = 0;
899 if (!(vol = virshCommandOptVol(ctl, cmd, "vol", "pool", &name)))
900 return false;
902 if (delete_snapshots)
903 flags |= VIR_STORAGE_VOL_DELETE_WITH_SNAPSHOTS;
905 if (virStorageVolDelete(vol, flags) == 0) {
906 vshPrintExtra(ctl, _("Vol %s deleted\n"), name);
907 } else {
908 vshError(ctl, _("Failed to delete vol %s"), name);
909 ret = false;
912 virStorageVolFree(vol);
913 return ret;
917 * "vol-wipe" command
919 static const vshCmdInfo info_vol_wipe[] = {
920 {.name = "help",
921 .data = N_("wipe a vol")
923 {.name = "desc",
924 .data = N_("Ensure data previously on a volume is not accessible to future reads")
926 {.name = NULL}
929 static const vshCmdOptDef opts_vol_wipe[] = {
930 VIRSH_COMMON_OPT_VOLUME_VOL,
931 VIRSH_COMMON_OPT_POOL_OPTIONAL,
932 {.name = "algorithm",
933 .type = VSH_OT_STRING,
934 .help = N_("perform selected wiping algorithm")
936 {.name = NULL}
939 VIR_ENUM_DECL(virStorageVolWipeAlgorithm);
940 VIR_ENUM_IMPL(virStorageVolWipeAlgorithm,
941 VIR_STORAGE_VOL_WIPE_ALG_LAST,
942 "zero", "nnsa", "dod", "bsi", "gutmann", "schneier",
943 "pfitzner7", "pfitzner33", "random", "trim");
945 static bool
946 cmdVolWipe(vshControl *ctl, const vshCmd *cmd)
948 virStorageVolPtr vol;
949 bool ret = false;
950 const char *name;
951 const char *algorithm_str = NULL;
952 int algorithm = VIR_STORAGE_VOL_WIPE_ALG_ZERO;
953 int funcRet;
955 if (!(vol = virshCommandOptVol(ctl, cmd, "vol", "pool", &name)))
956 return false;
958 if (vshCommandOptStringReq(ctl, cmd, "algorithm", &algorithm_str) < 0)
959 goto out;
961 if (algorithm_str &&
962 (algorithm = virStorageVolWipeAlgorithmTypeFromString(algorithm_str)) < 0) {
963 vshError(ctl, _("Unsupported algorithm '%s'"), algorithm_str);
964 goto out;
967 if ((funcRet = virStorageVolWipePattern(vol, algorithm, 0)) < 0) {
968 if (last_error->code == VIR_ERR_NO_SUPPORT &&
969 algorithm == VIR_STORAGE_VOL_WIPE_ALG_ZERO)
970 funcRet = virStorageVolWipe(vol, 0);
973 if (funcRet < 0) {
974 vshError(ctl, _("Failed to wipe vol %s"), name);
975 goto out;
978 vshPrintExtra(ctl, _("Vol %s wiped\n"), name);
979 ret = true;
980 out:
981 virStorageVolFree(vol);
982 return ret;
986 VIR_ENUM_DECL(virshStorageVol);
987 VIR_ENUM_IMPL(virshStorageVol,
988 VIR_STORAGE_VOL_LAST,
989 N_("file"),
990 N_("block"),
991 N_("dir"),
992 N_("network"),
993 N_("netdir"),
994 N_("ploop"));
996 static const char *
997 virshVolumeTypeToString(int type)
999 const char *str = virshStorageVolTypeToString(type);
1000 return str ? _(str) : _("unknown");
1005 * "vol-info" command
1007 static const vshCmdInfo info_vol_info[] = {
1008 {.name = "help",
1009 .data = N_("storage vol information")
1011 {.name = "desc",
1012 .data = N_("Returns basic information about the storage vol.")
1014 {.name = NULL}
1017 static const vshCmdOptDef opts_vol_info[] = {
1018 VIRSH_COMMON_OPT_VOLUME_VOL,
1019 VIRSH_COMMON_OPT_POOL_OPTIONAL,
1020 {.name = "bytes",
1021 .type = VSH_OT_BOOL,
1022 .help = N_("sizes are represented in bytes rather than pretty units")
1024 {.name = "physical",
1025 .type = VSH_OT_BOOL,
1026 .help = N_("return the physical size of the volume in allocation field")
1028 {.name = NULL}
1031 static bool
1032 cmdVolInfo(vshControl *ctl, const vshCmd *cmd)
1034 virStorageVolInfo info;
1035 virStorageVolPtr vol;
1036 bool bytes = vshCommandOptBool(cmd, "bytes");
1037 bool physical = vshCommandOptBool(cmd, "physical");
1038 bool ret = true;
1039 int rc;
1040 unsigned int flags = 0;
1042 if (!(vol = virshCommandOptVol(ctl, cmd, "vol", "pool", NULL)))
1043 return false;
1045 vshPrint(ctl, "%-15s %s\n", _("Name:"), virStorageVolGetName(vol));
1047 if (physical)
1048 flags |= VIR_STORAGE_VOL_GET_PHYSICAL;
1050 if (flags)
1051 rc = virStorageVolGetInfoFlags(vol, &info, flags);
1052 else
1053 rc = virStorageVolGetInfo(vol, &info);
1055 if (rc == 0) {
1056 double val;
1057 const char *unit;
1059 vshPrint(ctl, "%-15s %s\n", _("Type:"),
1060 virshVolumeTypeToString(info.type));
1062 if (bytes) {
1063 vshPrint(ctl, "%-15s %llu %s\n", _("Capacity:"),
1064 info.capacity, _("bytes"));
1065 } else {
1066 val = vshPrettyCapacity(info.capacity, &unit);
1067 vshPrint(ctl, "%-15s %2.2lf %s\n", _("Capacity:"), val, unit);
1070 if (bytes) {
1071 if (physical)
1072 vshPrint(ctl, "%-15s %llu %s\n", _("Physical:"),
1073 info.allocation, _("bytes"));
1074 else
1075 vshPrint(ctl, "%-15s %llu %s\n", _("Allocation:"),
1076 info.allocation, _("bytes"));
1077 } else {
1078 val = vshPrettyCapacity(info.allocation, &unit);
1079 if (physical)
1080 vshPrint(ctl, "%-15s %2.2lf %s\n", _("Physical:"), val, unit);
1081 else
1082 vshPrint(ctl, "%-15s %2.2lf %s\n", _("Allocation:"), val, unit);
1084 } else {
1085 ret = false;
1088 virStorageVolFree(vol);
1089 return ret;
1093 * "vol-resize" command
1095 static const vshCmdInfo info_vol_resize[] = {
1096 {.name = "help",
1097 .data = N_("resize a vol")
1099 {.name = "desc",
1100 .data = N_("Resizes a storage volume. This is safe only for storage "
1101 "volumes not in use by an active guest.\n"
1102 "See blockresize for live resizing.")
1104 {.name = NULL}
1107 static const vshCmdOptDef opts_vol_resize[] = {
1108 VIRSH_COMMON_OPT_VOLUME_VOL,
1109 {.name = "capacity",
1110 .type = VSH_OT_DATA,
1111 .flags = VSH_OFLAG_REQ,
1112 .help = N_("new capacity for the vol, as scaled integer (default bytes)")
1114 VIRSH_COMMON_OPT_POOL_OPTIONAL,
1115 {.name = "allocate",
1116 .type = VSH_OT_BOOL,
1117 .help = N_("allocate the new capacity, rather than leaving it sparse")
1119 {.name = "delta",
1120 .type = VSH_OT_BOOL,
1121 .help = N_("use capacity as a delta to current size, rather than the new size")
1123 {.name = "shrink",
1124 .type = VSH_OT_BOOL,
1125 .help = N_("allow the resize to shrink the volume")
1127 {.name = NULL}
1130 static bool
1131 cmdVolResize(vshControl *ctl, const vshCmd *cmd)
1133 virStorageVolPtr vol;
1134 const char *capacityStr = NULL;
1135 unsigned long long capacity = 0;
1136 unsigned int flags = 0;
1137 bool ret = false;
1138 bool delta = vshCommandOptBool(cmd, "delta");
1140 if (vshCommandOptBool(cmd, "allocate"))
1141 flags |= VIR_STORAGE_VOL_RESIZE_ALLOCATE;
1142 if (vshCommandOptBool(cmd, "shrink"))
1143 flags |= VIR_STORAGE_VOL_RESIZE_SHRINK;
1145 if (!(vol = virshCommandOptVol(ctl, cmd, "vol", "pool", NULL)))
1146 return false;
1148 if (vshCommandOptStringReq(ctl, cmd, "capacity", &capacityStr) < 0)
1149 goto cleanup;
1150 virSkipSpaces(&capacityStr);
1151 if (*capacityStr == '-') {
1152 /* The API always requires a positive value; but we allow a
1153 * negative value for convenience. */
1154 if (vshCommandOptBool(cmd, "shrink")) {
1155 capacityStr++;
1156 delta = true;
1157 } else {
1158 vshError(ctl, "%s",
1159 _("negative size requires --shrink"));
1160 goto cleanup;
1164 if (delta)
1165 flags |= VIR_STORAGE_VOL_RESIZE_DELTA;
1167 if (virshVolSize(capacityStr, &capacity) < 0) {
1168 vshError(ctl, _("Malformed size %s"), capacityStr);
1169 goto cleanup;
1172 if (virStorageVolResize(vol, capacity, flags) == 0) {
1173 vshPrintExtra(ctl,
1174 delta ? _("Size of volume '%s' successfully changed by %s\n")
1175 : _("Size of volume '%s' successfully changed to %s\n"),
1176 virStorageVolGetName(vol), capacityStr);
1177 ret = true;
1178 } else {
1179 vshError(ctl,
1180 delta ? _("Failed to change size of volume '%s' by %s")
1181 : _("Failed to change size of volume '%s' to %s"),
1182 virStorageVolGetName(vol), capacityStr);
1183 ret = false;
1186 cleanup:
1187 virStorageVolFree(vol);
1188 return ret;
1192 * "vol-dumpxml" command
1194 static const vshCmdInfo info_vol_dumpxml[] = {
1195 {.name = "help",
1196 .data = N_("vol information in XML")
1198 {.name = "desc",
1199 .data = N_("Output the vol information as an XML dump to stdout.")
1201 {.name = NULL}
1204 static const vshCmdOptDef opts_vol_dumpxml[] = {
1205 VIRSH_COMMON_OPT_VOLUME_VOL,
1206 VIRSH_COMMON_OPT_POOL_OPTIONAL,
1207 {.name = NULL}
1210 static bool
1211 cmdVolDumpXML(vshControl *ctl, const vshCmd *cmd)
1213 virStorageVolPtr vol;
1214 bool ret = true;
1215 char *dump;
1217 if (!(vol = virshCommandOptVol(ctl, cmd, "vol", "pool", NULL)))
1218 return false;
1220 dump = virStorageVolGetXMLDesc(vol, 0);
1221 if (dump != NULL) {
1222 vshPrint(ctl, "%s", dump);
1223 VIR_FREE(dump);
1224 } else {
1225 ret = false;
1228 virStorageVolFree(vol);
1229 return ret;
1232 static int
1233 virshStorageVolSorter(const void *a, const void *b)
1235 virStorageVolPtr *va = (virStorageVolPtr *) a;
1236 virStorageVolPtr *vb = (virStorageVolPtr *) b;
1238 if (*va && !*vb)
1239 return -1;
1241 if (!*va)
1242 return *vb != NULL;
1244 return vshStrcasecmp(virStorageVolGetName(*va),
1245 virStorageVolGetName(*vb));
1248 struct virshStorageVolList {
1249 virStorageVolPtr *vols;
1250 size_t nvols;
1252 typedef struct virshStorageVolList *virshStorageVolListPtr;
1254 static void
1255 virshStorageVolListFree(virshStorageVolListPtr list)
1257 size_t i;
1259 if (list && list->vols) {
1260 for (i = 0; i < list->nvols; i++) {
1261 if (list->vols[i])
1262 virStorageVolFree(list->vols[i]);
1264 VIR_FREE(list->vols);
1266 VIR_FREE(list);
1269 static virshStorageVolListPtr
1270 virshStorageVolListCollect(vshControl *ctl,
1271 virStoragePoolPtr pool,
1272 unsigned int flags)
1274 virshStorageVolListPtr list = vshMalloc(ctl, sizeof(*list));
1275 size_t i;
1276 char **names = NULL;
1277 virStorageVolPtr vol = NULL;
1278 bool success = false;
1279 size_t deleted = 0;
1280 int nvols = 0;
1281 int ret = -1;
1283 /* try the list with flags support (0.10.2 and later) */
1284 if ((ret = virStoragePoolListAllVolumes(pool,
1285 &list->vols,
1286 flags)) >= 0) {
1287 list->nvols = ret;
1288 goto finished;
1291 /* check if the command is actually supported */
1292 if (last_error && last_error->code == VIR_ERR_NO_SUPPORT)
1293 goto fallback;
1295 /* there was an error during the call */
1296 vshError(ctl, "%s", _("Failed to list volumes"));
1297 goto cleanup;
1299 fallback:
1300 /* fall back to old method (0.10.1 and older) */
1301 vshResetLibvirtError();
1303 /* Determine the number of volumes in the pool */
1304 if ((nvols = virStoragePoolNumOfVolumes(pool)) < 0) {
1305 vshError(ctl, "%s", _("Failed to list storage volumes"));
1306 goto cleanup;
1309 if (nvols == 0)
1310 return list;
1312 /* Retrieve the list of volume names in the pool */
1313 names = vshCalloc(ctl, nvols, sizeof(*names));
1314 if ((nvols = virStoragePoolListVolumes(pool, names, nvols)) < 0) {
1315 vshError(ctl, "%s", _("Failed to list storage volumes"));
1316 goto cleanup;
1319 list->vols = vshMalloc(ctl, sizeof(virStorageVolPtr) * (nvols));
1320 list->nvols = 0;
1322 /* get the vols */
1323 for (i = 0; i < nvols; i++) {
1324 if (!(vol = virStorageVolLookupByName(pool, names[i])))
1325 continue;
1326 list->vols[list->nvols++] = vol;
1329 /* truncate the list for not found vols */
1330 deleted = nvols - list->nvols;
1332 finished:
1333 /* sort the list */
1334 if (list->vols && list->nvols)
1335 qsort(list->vols, list->nvols, sizeof(*list->vols), virshStorageVolSorter);
1337 if (deleted)
1338 VIR_SHRINK_N(list->vols, list->nvols, deleted);
1340 success = true;
1342 cleanup:
1343 if (nvols > 0)
1344 for (i = 0; i < nvols; i++)
1345 VIR_FREE(names[i]);
1346 VIR_FREE(names);
1348 if (!success) {
1349 virshStorageVolListFree(list);
1350 list = NULL;
1353 return list;
1357 * "vol-list" command
1359 static const vshCmdInfo info_vol_list[] = {
1360 {.name = "help",
1361 .data = N_("list vols")
1363 {.name = "desc",
1364 .data = N_("Returns list of vols by pool.")
1366 {.name = NULL}
1369 static const vshCmdOptDef opts_vol_list[] = {
1370 VIRSH_COMMON_OPT_POOL_FULL,
1371 {.name = "details",
1372 .type = VSH_OT_BOOL,
1373 .help = N_("display extended details for volumes")
1375 {.name = NULL}
1378 static bool
1379 cmdVolList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
1381 virStorageVolInfo volumeInfo;
1382 virStoragePoolPtr pool;
1383 const char *unit;
1384 double val;
1385 bool details = vshCommandOptBool(cmd, "details");
1386 size_t i;
1387 bool ret = false;
1388 struct volInfoText {
1389 char *allocation;
1390 char *capacity;
1391 char *path;
1392 char *type;
1394 struct volInfoText *volInfoTexts = NULL;
1395 virshStorageVolListPtr list = NULL;
1396 vshTablePtr table = NULL;
1398 /* Look up the pool information given to us by the user */
1399 if (!(pool = virshCommandOptPool(ctl, cmd, "pool", NULL)))
1400 return false;
1402 if (!(list = virshStorageVolListCollect(ctl, pool, 0)))
1403 goto cleanup;
1405 if (list->nvols > 0)
1406 volInfoTexts = vshCalloc(ctl, list->nvols, sizeof(*volInfoTexts));
1408 /* Collect the rest of the volume information for display */
1409 for (i = 0; i < list->nvols; i++) {
1410 /* Retrieve volume info */
1411 virStorageVolPtr vol = list->vols[i];
1413 /* Retrieve the volume path */
1414 if ((volInfoTexts[i].path = virStorageVolGetPath(vol)) == NULL) {
1415 /* Something went wrong retrieving a volume path, cope with it */
1416 volInfoTexts[i].path = vshStrdup(ctl, _("unknown"));
1419 /* If requested, retrieve volume type and sizing information */
1420 if (details) {
1421 if (virStorageVolGetInfo(vol, &volumeInfo) != 0) {
1422 /* Something went wrong retrieving volume info, cope with it */
1423 volInfoTexts[i].allocation = vshStrdup(ctl, _("unknown"));
1424 volInfoTexts[i].capacity = vshStrdup(ctl, _("unknown"));
1425 volInfoTexts[i].type = vshStrdup(ctl, _("unknown"));
1426 } else {
1427 /* Convert the returned volume info into output strings */
1429 /* Volume type */
1430 volInfoTexts[i].type = vshStrdup(ctl,
1431 virshVolumeTypeToString(volumeInfo.type));
1433 val = vshPrettyCapacity(volumeInfo.capacity, &unit);
1434 if (virAsprintf(&volInfoTexts[i].capacity,
1435 "%.2lf %s", val, unit) < 0)
1436 goto cleanup;
1438 val = vshPrettyCapacity(volumeInfo.allocation, &unit);
1439 if (virAsprintf(&volInfoTexts[i].allocation,
1440 "%.2lf %s", val, unit) < 0)
1441 goto cleanup;
1446 /* If the --details option wasn't selected, we output the volume
1447 * info using the fixed string format from previous versions to
1448 * maintain backward compatibility.
1451 /* Output basic info then return if --details option not selected */
1452 if (!details) {
1453 /* The old output format */
1454 table = vshTableNew(_("Name"), _("Path"), NULL);
1455 if (!table)
1456 goto cleanup;
1458 for (i = 0; i < list->nvols; i++) {
1459 if (vshTableRowAppend(table,
1460 virStorageVolGetName(list->vols[i]),
1461 volInfoTexts[i].path,
1462 NULL) < 0)
1463 goto cleanup;
1466 vshTablePrintToStdout(table, ctl);
1468 /* Cleanup and return */
1469 ret = true;
1470 goto cleanup;
1473 /* We only get here if the --details option was selected. */
1475 /* Insert the header into table */
1476 table = vshTableNew(_("Name"), _("Path"), _("Type"), _("Capacity"), _("Allocation"), NULL);
1477 if (!table)
1478 goto cleanup;
1480 /* Insert the volume info rows into table */
1481 for (i = 0; i < list->nvols; i++) {
1482 if (vshTableRowAppend(table,
1483 virStorageVolGetName(list->vols[i]),
1484 volInfoTexts[i].path,
1485 volInfoTexts[i].type,
1486 volInfoTexts[i].capacity,
1487 volInfoTexts[i].allocation,
1488 NULL) < 0)
1489 goto cleanup;
1492 vshTablePrintToStdout(table, ctl);
1494 /* Cleanup and return */
1495 ret = true;
1497 cleanup:
1498 vshTableFree(table);
1500 /* Safely free the memory allocated in this function */
1501 if (list && list->nvols) {
1502 for (i = 0; i < list->nvols; i++) {
1503 /* Cleanup the memory for one volume info structure per loop */
1504 VIR_FREE(volInfoTexts[i].path);
1505 VIR_FREE(volInfoTexts[i].type);
1506 VIR_FREE(volInfoTexts[i].capacity);
1507 VIR_FREE(volInfoTexts[i].allocation);
1511 /* Cleanup remaining memory */
1512 VIR_FREE(volInfoTexts);
1513 virStoragePoolFree(pool);
1514 virshStorageVolListFree(list);
1516 /* Return the desired value */
1517 return ret;
1521 * "vol-name" command
1523 static const vshCmdInfo info_vol_name[] = {
1524 {.name = "help",
1525 .data = N_("returns the volume name for a given volume key or path")
1527 {.name = "desc",
1528 .data = ""
1530 {.name = NULL}
1533 static const vshCmdOptDef opts_vol_name[] = {
1534 {.name = "vol",
1535 .type = VSH_OT_DATA,
1536 .flags = VSH_OFLAG_REQ,
1537 .help = N_("volume key or path")
1539 {.name = NULL}
1542 static bool
1543 cmdVolName(vshControl *ctl, const vshCmd *cmd)
1545 virStorageVolPtr vol;
1547 if (!(vol = virshCommandOptVolBy(ctl, cmd, "vol", NULL, NULL,
1548 VIRSH_BYUUID)))
1549 return false;
1551 vshPrint(ctl, "%s\n", virStorageVolGetName(vol));
1552 virStorageVolFree(vol);
1553 return true;
1557 * "vol-pool" command
1559 static const vshCmdInfo info_vol_pool[] = {
1560 {.name = "help",
1561 .data = N_("returns the storage pool for a given volume key or path")
1563 {.name = "desc",
1564 .data = ""
1566 {.name = NULL}
1569 static const vshCmdOptDef opts_vol_pool[] = {
1570 {.name = "vol",
1571 .type = VSH_OT_DATA,
1572 .flags = VSH_OFLAG_REQ,
1573 .help = N_("volume key or path")
1575 {.name = "uuid",
1576 .type = VSH_OT_BOOL,
1577 .help = N_("return the pool uuid rather than pool name")
1579 {.name = NULL}
1582 static bool
1583 cmdVolPool(vshControl *ctl, const vshCmd *cmd)
1585 virStoragePoolPtr pool;
1586 virStorageVolPtr vol;
1587 char uuid[VIR_UUID_STRING_BUFLEN];
1589 /* Use the supplied string to locate the volume */
1590 if (!(vol = virshCommandOptVolBy(ctl, cmd, "vol", NULL, NULL,
1591 VIRSH_BYUUID))) {
1592 return false;
1595 /* Look up the parent storage pool for the volume */
1596 pool = virStoragePoolLookupByVolume(vol);
1597 if (pool == NULL) {
1598 vshError(ctl, "%s", _("failed to get parent pool"));
1599 virStorageVolFree(vol);
1600 return false;
1603 /* Return the requested details of the parent storage pool */
1604 if (vshCommandOptBool(cmd, "uuid")) {
1605 /* Retrieve and return pool UUID string */
1606 if (virStoragePoolGetUUIDString(pool, &uuid[0]) == 0)
1607 vshPrint(ctl, "%s\n", uuid);
1608 } else {
1609 /* Return the storage pool name */
1610 vshPrint(ctl, "%s\n", virStoragePoolGetName(pool));
1613 /* Cleanup */
1614 virStorageVolFree(vol);
1615 virStoragePoolFree(pool);
1616 return true;
1620 * "vol-key" command
1622 static const vshCmdInfo info_vol_key[] = {
1623 {.name = "help",
1624 .data = N_("returns the volume key for a given volume name or path")
1626 {.name = "desc",
1627 .data = ""
1629 {.name = NULL}
1632 static const vshCmdOptDef opts_vol_key[] = {
1633 {.name = "vol",
1634 .type = VSH_OT_DATA,
1635 .flags = VSH_OFLAG_REQ,
1636 .help = N_("volume name or path")
1638 VIRSH_COMMON_OPT_POOL_OPTIONAL,
1639 {.name = NULL}
1642 static bool
1643 cmdVolKey(vshControl *ctl, const vshCmd *cmd)
1645 virStorageVolPtr vol;
1647 if (!(vol = virshCommandOptVol(ctl, cmd, "vol", "pool", NULL)))
1648 return false;
1650 vshPrint(ctl, "%s\n", virStorageVolGetKey(vol));
1651 virStorageVolFree(vol);
1652 return true;
1656 * "vol-path" command
1658 static const vshCmdInfo info_vol_path[] = {
1659 {.name = "help",
1660 .data = N_("returns the volume path for a given volume name or key")
1662 {.name = "desc",
1663 .data = ""
1665 {.name = NULL}
1668 static const vshCmdOptDef opts_vol_path[] = {
1669 {.name = "vol",
1670 .type = VSH_OT_DATA,
1671 .flags = VSH_OFLAG_REQ,
1672 .help = N_("volume name or key")
1674 VIRSH_COMMON_OPT_POOL_OPTIONAL,
1675 {.name = NULL}
1678 static bool
1679 cmdVolPath(vshControl *ctl, const vshCmd *cmd)
1681 virStorageVolPtr vol;
1682 char * StorageVolPath;
1684 if (!(vol = virshCommandOptVol(ctl, cmd, "vol", "pool", NULL)))
1685 return false;
1687 if ((StorageVolPath = virStorageVolGetPath(vol)) == NULL) {
1688 virStorageVolFree(vol);
1689 return false;
1692 vshPrint(ctl, "%s\n", StorageVolPath);
1693 VIR_FREE(StorageVolPath);
1694 virStorageVolFree(vol);
1695 return true;
1698 const vshCmdDef storageVolCmds[] = {
1699 {.name = "vol-clone",
1700 .handler = cmdVolClone,
1701 .opts = opts_vol_clone,
1702 .info = info_vol_clone,
1703 .flags = 0
1705 {.name = "vol-create-as",
1706 .handler = cmdVolCreateAs,
1707 .opts = opts_vol_create_as,
1708 .info = info_vol_create_as,
1709 .flags = 0
1711 {.name = "vol-create",
1712 .handler = cmdVolCreate,
1713 .opts = opts_vol_create,
1714 .info = info_vol_create,
1715 .flags = 0
1717 {.name = "vol-create-from",
1718 .handler = cmdVolCreateFrom,
1719 .opts = opts_vol_create_from,
1720 .info = info_vol_create_from,
1721 .flags = 0
1723 {.name = "vol-delete",
1724 .handler = cmdVolDelete,
1725 .opts = opts_vol_delete,
1726 .info = info_vol_delete,
1727 .flags = 0
1729 {.name = "vol-download",
1730 .handler = cmdVolDownload,
1731 .opts = opts_vol_download,
1732 .info = info_vol_download,
1733 .flags = 0
1735 {.name = "vol-dumpxml",
1736 .handler = cmdVolDumpXML,
1737 .opts = opts_vol_dumpxml,
1738 .info = info_vol_dumpxml,
1739 .flags = 0
1741 {.name = "vol-info",
1742 .handler = cmdVolInfo,
1743 .opts = opts_vol_info,
1744 .info = info_vol_info,
1745 .flags = 0
1747 {.name = "vol-key",
1748 .handler = cmdVolKey,
1749 .opts = opts_vol_key,
1750 .info = info_vol_key,
1751 .flags = 0
1753 {.name = "vol-list",
1754 .handler = cmdVolList,
1755 .opts = opts_vol_list,
1756 .info = info_vol_list,
1757 .flags = 0
1759 {.name = "vol-name",
1760 .handler = cmdVolName,
1761 .opts = opts_vol_name,
1762 .info = info_vol_name,
1763 .flags = 0
1765 {.name = "vol-path",
1766 .handler = cmdVolPath,
1767 .opts = opts_vol_path,
1768 .info = info_vol_path,
1769 .flags = 0
1771 {.name = "vol-pool",
1772 .handler = cmdVolPool,
1773 .opts = opts_vol_pool,
1774 .info = info_vol_pool,
1775 .flags = 0
1777 {.name = "vol-resize",
1778 .handler = cmdVolResize,
1779 .opts = opts_vol_resize,
1780 .info = info_vol_resize,
1781 .flags = 0
1783 {.name = "vol-upload",
1784 .handler = cmdVolUpload,
1785 .opts = opts_vol_upload,
1786 .info = info_vol_upload,
1787 .flags = 0
1789 {.name = "vol-wipe",
1790 .handler = cmdVolWipe,
1791 .opts = opts_vol_wipe,
1792 .info = info_vol_wipe,
1793 .flags = 0
1795 {.name = NULL}