[libvirt] [PATCH 00/13 v2] Split virsh

There are conflicts after splitting 2/11 and 3/11, so post the whole set again. v1 - v2: * split 2/11, and 3/11 for the patches were too big. However, the new 3/13 is still quite big. I will send it individualy after compression. This splits virsh.c by the command groups, except 'virsh itself' group, each group will have a separate .c, filled with the its commands, a few helpers, and command group definition moved from virsh.c. and virsh.c simply include those new .c files. It still could be optimized, but this set could set up the skelton, and further optimization could be later patches. Osier Yang (13): virsh: Move definition of cmds and cmd groups right at the top of main virsh: Split cmds for domain monitoring from virsh.c virsh: Split cmds of domain group from virsh.c virsh: Split cmds of storage volume group from virsh.c virsh: Split cmds of storage pool group from virsh.c virsh: Split cmds to manage network from virsh.c virsh: Split cmds to manage host interface from virsh.c virsh: Split cmds to manage network filter from virsh.c virsh: Split cmds to manage secret from virsh.c virsh: Split cmds to manage domain snapshot from virsh.c virsh: Split cmds in host group from virsh.c virsh: Split cmds in node device group from virsh.c virsh: Move command group definition into its own file tools/virsh-domain-monitor.c | 1701 ++++ tools/virsh-domain.c | 8139 +++++++++++++++++++ tools/virsh-host.c | 839 ++ tools/virsh-interface.c | 1032 +++ tools/virsh-network.c | 710 ++ tools/virsh-nodedev.c | 402 + tools/virsh-nwfilter.c | 324 + tools/virsh-pool.c | 1442 ++++ tools/virsh-secret.c | 373 + tools/virsh-snapshot.c | 1628 ++++ tools/virsh-volume.c | 1462 ++++ tools/virsh.c |18474 +----------------------------------------- 12 files changed, 18361 insertions(+), 18165 deletions(-) create mode 100644 tools/virsh-domain-monitor.c create mode 100644 tools/virsh-domain.c create mode 100644 tools/virsh-host.c create mode 100644 tools/virsh-interface.c create mode 100644 tools/virsh-network.c create mode 100644 tools/virsh-nodedev.c create mode 100644 tools/virsh-nwfilter.c create mode 100644 tools/virsh-pool.c create mode 100644 tools/virsh-secret.c create mode 100644 tools/virsh-snapshot.c create mode 100644 tools/virsh-volume.c Regards, Osier

This will avoid many conflicts if moving the codes for each command group into separate files in later patches. --- tools/virsh.c | 967 ++++++++++++++++++++++++++++----------------------------- 1 files changed, 483 insertions(+), 484 deletions(-) diff --git a/tools/virsh.c b/tools/virsh.c index 6bb0fc8..81976a0 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -18183,371 +18183,38 @@ cleanup: return ret; } -static const vshCmdDef domManagementCmds[] = { - {"attach-device", cmdAttachDevice, opts_attach_device, - info_attach_device, 0}, - {"attach-disk", cmdAttachDisk, opts_attach_disk, - info_attach_disk, 0}, - {"attach-interface", cmdAttachInterface, opts_attach_interface, - info_attach_interface, 0}, - {"autostart", cmdAutostart, opts_autostart, info_autostart, 0}, - {"blkdeviotune", cmdBlkdeviotune, opts_blkdeviotune, info_blkdeviotune, 0}, - {"blkiotune", cmdBlkiotune, opts_blkiotune, info_blkiotune, 0}, - {"blockcopy", cmdBlockCopy, opts_block_copy, info_block_copy, 0}, - {"blockjob", cmdBlockJob, opts_block_job, info_block_job, 0}, - {"blockpull", cmdBlockPull, opts_block_pull, info_block_pull, 0}, - {"blockresize", cmdBlockResize, opts_block_resize, info_block_resize, 0}, - {"change-media", cmdChangeMedia, opts_change_media, info_change_media, 0}, -#ifndef WIN32 - {"console", cmdConsole, opts_console, info_console, 0}, -#endif - {"cpu-baseline", cmdCPUBaseline, opts_cpu_baseline, info_cpu_baseline, 0}, - {"cpu-compare", cmdCPUCompare, opts_cpu_compare, info_cpu_compare, 0}, - {"cpu-stats", cmdCPUStats, opts_cpu_stats, info_cpu_stats, 0}, - {"create", cmdCreate, opts_create, info_create, 0}, - {"define", cmdDefine, opts_define, info_define, 0}, - {"desc", cmdDesc, opts_desc, info_desc, 0}, - {"destroy", cmdDestroy, opts_destroy, info_destroy, 0}, - {"detach-device", cmdDetachDevice, opts_detach_device, - info_detach_device, 0}, - {"detach-disk", cmdDetachDisk, opts_detach_disk, info_detach_disk, 0}, - {"detach-interface", cmdDetachInterface, opts_detach_interface, - info_detach_interface, 0}, - {"domdisplay", cmdDomDisplay, opts_domdisplay, info_domdisplay, 0}, - {"domhostname", cmdDomHostname, opts_domhostname, info_domhostname, 0}, - {"domid", cmdDomid, opts_domid, info_domid, 0}, - {"domif-setlink", cmdDomIfSetLink, opts_domif_setlink, info_domif_setlink, 0}, - {"domiftune", cmdDomIftune, opts_domiftune, info_domiftune, 0}, - {"domjobabort", cmdDomjobabort, opts_domjobabort, info_domjobabort, 0}, - {"domjobinfo", cmdDomjobinfo, opts_domjobinfo, info_domjobinfo, 0}, - {"domname", cmdDomname, opts_domname, info_domname, 0}, - {"dompmsuspend", cmdDomPMSuspend, - opts_dom_pm_suspend, info_dom_pm_suspend, 0}, - {"dompmwakeup", cmdDomPMWakeup, - opts_dom_pm_wakeup, info_dom_pm_wakeup, 0}, - {"domuuid", cmdDomuuid, opts_domuuid, info_domuuid, 0}, - {"domxml-from-native", cmdDomXMLFromNative, opts_domxmlfromnative, - info_domxmlfromnative, 0}, - {"domxml-to-native", cmdDomXMLToNative, opts_domxmltonative, - info_domxmltonative, 0}, - {"dump", cmdDump, opts_dump, info_dump, 0}, - {"dumpxml", cmdDumpXML, opts_dumpxml, info_dumpxml, 0}, - {"edit", cmdEdit, opts_edit, info_edit, 0}, - {"inject-nmi", cmdInjectNMI, opts_inject_nmi, info_inject_nmi, 0}, - {"send-key", cmdSendKey, opts_send_key, info_send_key, 0}, - {"managedsave", cmdManagedSave, opts_managedsave, info_managedsave, 0}, - {"managedsave-remove", cmdManagedSaveRemove, opts_managedsaveremove, - info_managedsaveremove, 0}, - {"maxvcpus", cmdMaxvcpus, opts_maxvcpus, info_maxvcpus, 0}, - {"memtune", cmdMemtune, opts_memtune, info_memtune, 0}, - {"migrate", cmdMigrate, opts_migrate, info_migrate, 0}, - {"migrate-setmaxdowntime", cmdMigrateSetMaxDowntime, - opts_migrate_setmaxdowntime, info_migrate_setmaxdowntime, 0}, - {"migrate-setspeed", cmdMigrateSetMaxSpeed, - opts_migrate_setspeed, info_migrate_setspeed, 0}, - {"migrate-getspeed", cmdMigrateGetMaxSpeed, - opts_migrate_getspeed, info_migrate_getspeed, 0}, - {"numatune", cmdNumatune, opts_numatune, info_numatune, 0}, - {"reboot", cmdReboot, opts_reboot, info_reboot, 0}, - {"reset", cmdReset, opts_reset, info_reset, 0}, - {"restore", cmdRestore, opts_restore, info_restore, 0}, - {"resume", cmdResume, opts_resume, info_resume, 0}, - {"save", cmdSave, opts_save, info_save, 0}, - {"save-image-define", cmdSaveImageDefine, opts_save_image_define, - info_save_image_define, 0}, - {"save-image-dumpxml", cmdSaveImageDumpxml, opts_save_image_dumpxml, - info_save_image_dumpxml, 0}, - {"save-image-edit", cmdSaveImageEdit, opts_save_image_edit, - info_save_image_edit, 0}, - {"schedinfo", cmdSchedinfo, opts_schedinfo, info_schedinfo, 0}, - {"screenshot", cmdScreenshot, opts_screenshot, info_screenshot, 0}, - {"setmaxmem", cmdSetmaxmem, opts_setmaxmem, info_setmaxmem, 0}, - {"setmem", cmdSetmem, opts_setmem, info_setmem, 0}, - {"setvcpus", cmdSetvcpus, opts_setvcpus, info_setvcpus, 0}, - {"shutdown", cmdShutdown, opts_shutdown, info_shutdown, 0}, - {"start", cmdStart, opts_start, info_start, 0}, - {"suspend", cmdSuspend, opts_suspend, info_suspend, 0}, - {"ttyconsole", cmdTTYConsole, opts_ttyconsole, info_ttyconsole, 0}, - {"undefine", cmdUndefine, opts_undefine, info_undefine, 0}, - {"update-device", cmdUpdateDevice, opts_update_device, - info_update_device, 0}, - {"vcpucount", cmdVcpucount, opts_vcpucount, info_vcpucount, 0}, - {"vcpuinfo", cmdVcpuinfo, opts_vcpuinfo, info_vcpuinfo, 0}, - {"vcpupin", cmdVcpuPin, opts_vcpupin, info_vcpupin, 0}, - {"vncdisplay", cmdVNCDisplay, opts_vncdisplay, info_vncdisplay, 0}, - {NULL, NULL, NULL, NULL, 0} -}; - -static const vshCmdDef domMonitoringCmds[] = { - {"domblkerror", cmdDomBlkError, opts_domblkerror, info_domblkerror, 0}, - {"domblkinfo", cmdDomblkinfo, opts_domblkinfo, info_domblkinfo, 0}, - {"domblklist", cmdDomblklist, opts_domblklist, info_domblklist, 0}, - {"domblkstat", cmdDomblkstat, opts_domblkstat, info_domblkstat, 0}, - {"domcontrol", cmdDomControl, opts_domcontrol, info_domcontrol, 0}, - {"domif-getlink", cmdDomIfGetLink, opts_domif_getlink, info_domif_getlink, 0}, - {"domiflist", cmdDomiflist, opts_domiflist, info_domiflist, 0}, - {"domifstat", cmdDomIfstat, opts_domifstat, info_domifstat, 0}, - {"dominfo", cmdDominfo, opts_dominfo, info_dominfo, 0}, - {"dommemstat", cmdDomMemStat, opts_dommemstat, info_dommemstat, 0}, - {"domstate", cmdDomstate, opts_domstate, info_domstate, 0}, - {"list", cmdList, opts_list, info_list, 0}, - {NULL, NULL, NULL, NULL, 0} -}; +/* --------------- + * Utils for work with command definition + * --------------- + */ +static const char * +vshCmddefGetInfo(const vshCmdDef * cmd, const char *name) +{ + const vshCmdInfo *info; -static const vshCmdDef storagePoolCmds[] = { - {"find-storage-pool-sources-as", cmdPoolDiscoverSourcesAs, - opts_find_storage_pool_sources_as, info_find_storage_pool_sources_as, 0}, - {"find-storage-pool-sources", cmdPoolDiscoverSources, - opts_find_storage_pool_sources, info_find_storage_pool_sources, 0}, - {"pool-autostart", cmdPoolAutostart, opts_pool_autostart, - info_pool_autostart, 0}, - {"pool-build", cmdPoolBuild, opts_pool_build, info_pool_build, 0}, - {"pool-create-as", cmdPoolCreateAs, opts_pool_X_as, info_pool_create_as, 0}, - {"pool-create", cmdPoolCreate, opts_pool_create, info_pool_create, 0}, - {"pool-define-as", cmdPoolDefineAs, opts_pool_X_as, info_pool_define_as, 0}, - {"pool-define", cmdPoolDefine, opts_pool_define, info_pool_define, 0}, - {"pool-delete", cmdPoolDelete, opts_pool_delete, info_pool_delete, 0}, - {"pool-destroy", cmdPoolDestroy, opts_pool_destroy, info_pool_destroy, 0}, - {"pool-dumpxml", cmdPoolDumpXML, opts_pool_dumpxml, info_pool_dumpxml, 0}, - {"pool-edit", cmdPoolEdit, opts_pool_edit, info_pool_edit, 0}, - {"pool-info", cmdPoolInfo, opts_pool_info, info_pool_info, 0}, - {"pool-list", cmdPoolList, opts_pool_list, info_pool_list, 0}, - {"pool-name", cmdPoolName, opts_pool_name, info_pool_name, 0}, - {"pool-refresh", cmdPoolRefresh, opts_pool_refresh, info_pool_refresh, 0}, - {"pool-start", cmdPoolStart, opts_pool_start, info_pool_start, 0}, - {"pool-undefine", cmdPoolUndefine, opts_pool_undefine, - info_pool_undefine, 0}, - {"pool-uuid", cmdPoolUuid, opts_pool_uuid, info_pool_uuid, 0}, - {NULL, NULL, NULL, NULL, 0} -}; + for (info = cmd->info; info && info->name; info++) { + if (STREQ(info->name, name)) + return info->data; + } + return NULL; +} -static const vshCmdDef storageVolCmds[] = { - {"vol-clone", cmdVolClone, opts_vol_clone, info_vol_clone, 0}, - {"vol-create-as", cmdVolCreateAs, opts_vol_create_as, - info_vol_create_as, 0}, - {"vol-create", cmdVolCreate, opts_vol_create, info_vol_create, 0}, - {"vol-create-from", cmdVolCreateFrom, opts_vol_create_from, - info_vol_create_from, 0}, - {"vol-delete", cmdVolDelete, opts_vol_delete, info_vol_delete, 0}, - {"vol-download", cmdVolDownload, opts_vol_download, info_vol_download, 0}, - {"vol-dumpxml", cmdVolDumpXML, opts_vol_dumpxml, info_vol_dumpxml, 0}, - {"vol-info", cmdVolInfo, opts_vol_info, info_vol_info, 0}, - {"vol-key", cmdVolKey, opts_vol_key, info_vol_key, 0}, - {"vol-list", cmdVolList, opts_vol_list, info_vol_list, 0}, - {"vol-name", cmdVolName, opts_vol_name, info_vol_name, 0}, - {"vol-path", cmdVolPath, opts_vol_path, info_vol_path, 0}, - {"vol-pool", cmdVolPool, opts_vol_pool, info_vol_pool, 0}, - {"vol-resize", cmdVolResize, opts_vol_resize, info_vol_resize, 0}, - {"vol-upload", cmdVolUpload, opts_vol_upload, info_vol_upload, 0}, - {"vol-wipe", cmdVolWipe, opts_vol_wipe, info_vol_wipe, 0}, - {NULL, NULL, NULL, NULL, 0} -}; +/* Validate that the options associated with cmd can be parsed. */ +static int +vshCmddefOptParse(const vshCmdDef *cmd, uint32_t *opts_need_arg, + uint32_t *opts_required) +{ + int i; + bool optional = false; -static const vshCmdDef networkCmds[] = { - {"net-autostart", cmdNetworkAutostart, opts_network_autostart, - info_network_autostart, 0}, - {"net-create", cmdNetworkCreate, opts_network_create, - info_network_create, 0}, - {"net-define", cmdNetworkDefine, opts_network_define, - info_network_define, 0}, - {"net-destroy", cmdNetworkDestroy, opts_network_destroy, - info_network_destroy, 0}, - {"net-dumpxml", cmdNetworkDumpXML, opts_network_dumpxml, - info_network_dumpxml, 0}, - {"net-edit", cmdNetworkEdit, opts_network_edit, info_network_edit, 0}, - {"net-info", cmdNetworkInfo, opts_network_info, info_network_info, 0}, - {"net-list", cmdNetworkList, opts_network_list, info_network_list, 0}, - {"net-name", cmdNetworkName, opts_network_name, info_network_name, 0}, - {"net-start", cmdNetworkStart, opts_network_start, info_network_start, 0}, - {"net-undefine", cmdNetworkUndefine, opts_network_undefine, - info_network_undefine, 0}, - {"net-uuid", cmdNetworkUuid, opts_network_uuid, info_network_uuid, 0}, - {NULL, NULL, NULL, NULL, 0} -}; + *opts_need_arg = 0; + *opts_required = 0; -static const vshCmdDef nodedevCmds[] = { - {"nodedev-create", cmdNodeDeviceCreate, opts_node_device_create, - info_node_device_create, 0}, - {"nodedev-destroy", cmdNodeDeviceDestroy, opts_node_device_destroy, - info_node_device_destroy, 0}, - {"nodedev-detach", cmdNodeDeviceDetach, opts_node_device_detach, - info_node_device_detach, 0}, - {"nodedev-dettach", cmdNodeDeviceDetach, opts_node_device_detach, - info_node_device_detach, VSH_CMD_FLAG_ALIAS}, - {"nodedev-dumpxml", cmdNodeDeviceDumpXML, opts_node_device_dumpxml, - info_node_device_dumpxml, 0}, - {"nodedev-list", cmdNodeListDevices, opts_node_list_devices, - info_node_list_devices, 0}, - {"nodedev-reattach", cmdNodeDeviceReAttach, opts_node_device_reattach, - info_node_device_reattach, 0}, - {"nodedev-reset", cmdNodeDeviceReset, opts_node_device_reset, - info_node_device_reset, 0}, - {NULL, NULL, NULL, NULL, 0} -}; + if (!cmd->opts) + return 0; -static const vshCmdDef ifaceCmds[] = { - {"iface-begin", cmdInterfaceBegin, opts_interface_begin, - info_interface_begin, 0}, - {"iface-bridge", cmdInterfaceBridge, opts_interface_bridge, - info_interface_bridge, 0}, - {"iface-commit", cmdInterfaceCommit, opts_interface_commit, - info_interface_commit, 0}, - {"iface-define", cmdInterfaceDefine, opts_interface_define, - info_interface_define, 0}, - {"iface-destroy", cmdInterfaceDestroy, opts_interface_destroy, - info_interface_destroy, 0}, - {"iface-dumpxml", cmdInterfaceDumpXML, opts_interface_dumpxml, - info_interface_dumpxml, 0}, - {"iface-edit", cmdInterfaceEdit, opts_interface_edit, - info_interface_edit, 0}, - {"iface-list", cmdInterfaceList, opts_interface_list, - info_interface_list, 0}, - {"iface-mac", cmdInterfaceMAC, opts_interface_mac, - info_interface_mac, 0}, - {"iface-name", cmdInterfaceName, opts_interface_name, - info_interface_name, 0}, - {"iface-rollback", cmdInterfaceRollback, opts_interface_rollback, - info_interface_rollback, 0}, - {"iface-start", cmdInterfaceStart, opts_interface_start, - info_interface_start, 0}, - {"iface-unbridge", cmdInterfaceUnbridge, opts_interface_unbridge, - info_interface_unbridge, 0}, - {"iface-undefine", cmdInterfaceUndefine, opts_interface_undefine, - info_interface_undefine, 0}, - {NULL, NULL, NULL, NULL, 0} -}; - -static const vshCmdDef nwfilterCmds[] = { - {"nwfilter-define", cmdNWFilterDefine, opts_nwfilter_define, - info_nwfilter_define, 0}, - {"nwfilter-dumpxml", cmdNWFilterDumpXML, opts_nwfilter_dumpxml, - info_nwfilter_dumpxml, 0}, - {"nwfilter-edit", cmdNWFilterEdit, opts_nwfilter_edit, - info_nwfilter_edit, 0}, - {"nwfilter-list", cmdNWFilterList, opts_nwfilter_list, - info_nwfilter_list, 0}, - {"nwfilter-undefine", cmdNWFilterUndefine, opts_nwfilter_undefine, - info_nwfilter_undefine, 0}, - {NULL, NULL, NULL, NULL, 0} -}; - -static const vshCmdDef secretCmds[] = { - {"secret-define", cmdSecretDefine, opts_secret_define, - info_secret_define, 0}, - {"secret-dumpxml", cmdSecretDumpXML, opts_secret_dumpxml, - info_secret_dumpxml, 0}, - {"secret-get-value", cmdSecretGetValue, opts_secret_get_value, - info_secret_get_value, 0}, - {"secret-list", cmdSecretList, NULL, info_secret_list, 0}, - {"secret-set-value", cmdSecretSetValue, opts_secret_set_value, - info_secret_set_value, 0}, - {"secret-undefine", cmdSecretUndefine, opts_secret_undefine, - info_secret_undefine, 0}, - {NULL, NULL, NULL, NULL, 0} -}; - -static const vshCmdDef virshCmds[] = { - {"cd", cmdCd, opts_cd, info_cd, VSH_CMD_FLAG_NOCONNECT}, - {"echo", cmdEcho, opts_echo, info_echo, VSH_CMD_FLAG_NOCONNECT}, - {"exit", cmdQuit, NULL, info_quit, VSH_CMD_FLAG_NOCONNECT}, - {"help", cmdHelp, opts_help, info_help, VSH_CMD_FLAG_NOCONNECT}, - {"pwd", cmdPwd, NULL, info_pwd, VSH_CMD_FLAG_NOCONNECT}, - {"quit", cmdQuit, NULL, info_quit, VSH_CMD_FLAG_NOCONNECT}, - {NULL, NULL, NULL, NULL, 0} -}; - -static const vshCmdDef snapshotCmds[] = { - {"snapshot-create", cmdSnapshotCreate, opts_snapshot_create, - info_snapshot_create, 0}, - {"snapshot-create-as", cmdSnapshotCreateAs, opts_snapshot_create_as, - info_snapshot_create_as, 0}, - {"snapshot-current", cmdSnapshotCurrent, opts_snapshot_current, - info_snapshot_current, 0}, - {"snapshot-delete", cmdSnapshotDelete, opts_snapshot_delete, - info_snapshot_delete, 0}, - {"snapshot-dumpxml", cmdSnapshotDumpXML, opts_snapshot_dumpxml, - info_snapshot_dumpxml, 0}, - {"snapshot-edit", cmdSnapshotEdit, opts_snapshot_edit, - info_snapshot_edit, 0}, - {"snapshot-info", cmdSnapshotInfo, opts_snapshot_info, - info_snapshot_info, 0}, - {"snapshot-list", cmdSnapshotList, opts_snapshot_list, - info_snapshot_list, 0}, - {"snapshot-parent", cmdSnapshotParent, opts_snapshot_parent, - info_snapshot_parent, 0}, - {"snapshot-revert", cmdDomainSnapshotRevert, opts_snapshot_revert, - info_snapshot_revert, 0}, - {NULL, NULL, NULL, NULL, 0} -}; - -static const vshCmdDef hostAndHypervisorCmds[] = { - {"capabilities", cmdCapabilities, NULL, info_capabilities, 0}, - {"connect", cmdConnect, opts_connect, info_connect, - VSH_CMD_FLAG_NOCONNECT}, - {"freecell", cmdFreecell, opts_freecell, info_freecell, 0}, - {"hostname", cmdHostname, NULL, info_hostname, 0}, - {"nodecpustats", cmdNodeCpuStats, opts_node_cpustats, info_nodecpustats, 0}, - {"nodeinfo", cmdNodeinfo, NULL, info_nodeinfo, 0}, - {"nodememstats", cmdNodeMemStats, opts_node_memstats, info_nodememstats, 0}, - {"nodesuspend", cmdNodeSuspend, opts_node_suspend, info_nodesuspend, 0}, - {"qemu-attach", cmdQemuAttach, opts_qemu_attach, info_qemu_attach, 0}, - {"qemu-monitor-command", cmdQemuMonitorCommand, opts_qemu_monitor_command, - info_qemu_monitor_command, 0}, - {"sysinfo", cmdSysinfo, NULL, info_sysinfo, 0}, - {"uri", cmdURI, NULL, info_uri, 0}, - {"version", cmdVersion, opts_version, info_version, 0}, - {NULL, NULL, NULL, NULL, 0} -}; - -static const vshCmdGrp cmdGroups[] = { - {VSH_CMD_GRP_DOM_MANAGEMENT, "domain", domManagementCmds}, - {VSH_CMD_GRP_DOM_MONITORING, "monitor", domMonitoringCmds}, - {VSH_CMD_GRP_HOST_AND_HV, "host", hostAndHypervisorCmds}, - {VSH_CMD_GRP_IFACE, "interface", ifaceCmds}, - {VSH_CMD_GRP_NWFILTER, "filter", nwfilterCmds}, - {VSH_CMD_GRP_NETWORK, "network", networkCmds}, - {VSH_CMD_GRP_NODEDEV, "nodedev", nodedevCmds}, - {VSH_CMD_GRP_SECRET, "secret", secretCmds}, - {VSH_CMD_GRP_SNAPSHOT, "snapshot", snapshotCmds}, - {VSH_CMD_GRP_STORAGE_POOL, "pool", storagePoolCmds}, - {VSH_CMD_GRP_STORAGE_VOL, "volume", storageVolCmds}, - {VSH_CMD_GRP_VIRSH, "virsh", virshCmds}, - {NULL, NULL, NULL} -}; - - -/* --------------- - * Utils for work with command definition - * --------------- - */ -static const char * -vshCmddefGetInfo(const vshCmdDef * cmd, const char *name) -{ - const vshCmdInfo *info; - - for (info = cmd->info; info && info->name; info++) { - if (STREQ(info->name, name)) - return info->data; - } - return NULL; -} - -/* Validate that the options associated with cmd can be parsed. */ -static int -vshCmddefOptParse(const vshCmdDef *cmd, uint32_t *opts_need_arg, - uint32_t *opts_required) -{ - int i; - bool optional = false; - - *opts_need_arg = 0; - *opts_required = 0; - - if (!cmd->opts) - return 0; - - for (i = 0; cmd->opts[i].name; i++) { - const vshCmdOptDef *opt = &cmd->opts[i]; + for (i = 0; cmd->opts[i].name; i++) { + const vshCmdOptDef *opt = &cmd->opts[i]; if (i > 31) return -1; /* too many options */ @@ -20923,135 +20590,467 @@ vshShowVersion(vshControl *ctl ATTRIBUTE_UNUSED) #endif vshPrint(ctl, "\n"); - vshPrint(ctl, "%s", _(" Miscellaneous:")); -#ifdef WITH_NODE_DEVICES - vshPrint(ctl, " Nodedev"); -#endif -#ifdef WITH_SECDRIVER_APPARMOR - vshPrint(ctl, " AppArmor"); -#endif -#ifdef WITH_SECDRIVER_SELINUX - vshPrint(ctl, " SELinux"); -#endif -#ifdef WITH_SECRETS - vshPrint(ctl, " Secrets"); -#endif -#ifdef ENABLE_DEBUG - vshPrint(ctl, " Debug"); -#endif -#ifdef WITH_DTRACE_PROBES - vshPrint(ctl, " DTrace"); -#endif -#ifdef USE_READLINE - vshPrint(ctl, " Readline"); -#endif -#ifdef WITH_DRIVER_MODULES - vshPrint(ctl, " Modular"); -#endif - vshPrint(ctl, "\n"); -} + vshPrint(ctl, "%s", _(" Miscellaneous:")); +#ifdef WITH_NODE_DEVICES + vshPrint(ctl, " Nodedev"); +#endif +#ifdef WITH_SECDRIVER_APPARMOR + vshPrint(ctl, " AppArmor"); +#endif +#ifdef WITH_SECDRIVER_SELINUX + vshPrint(ctl, " SELinux"); +#endif +#ifdef WITH_SECRETS + vshPrint(ctl, " Secrets"); +#endif +#ifdef ENABLE_DEBUG + vshPrint(ctl, " Debug"); +#endif +#ifdef WITH_DTRACE_PROBES + vshPrint(ctl, " DTrace"); +#endif +#ifdef USE_READLINE + vshPrint(ctl, " Readline"); +#endif +#ifdef WITH_DRIVER_MODULES + vshPrint(ctl, " Modular"); +#endif + vshPrint(ctl, "\n"); +} + +static bool +vshAllowedEscapeChar(char c) +{ + /* Allowed escape characters: + * a-z A-Z @ [ \ ] ^ _ + */ + return ('a' <= c && c <= 'z') || + ('@' <= c && c <= '_'); +} + +/* + * argv[]: virsh [options] [command] + * + */ +static bool +vshParseArgv(vshControl *ctl, int argc, char **argv) +{ + int arg, len; + struct option opt[] = { + {"debug", required_argument, NULL, 'd'}, + {"help", no_argument, NULL, 'h'}, + {"quiet", no_argument, NULL, 'q'}, + {"timing", no_argument, NULL, 't'}, + {"version", optional_argument, NULL, 'v'}, + {"connect", required_argument, NULL, 'c'}, + {"readonly", no_argument, NULL, 'r'}, + {"log", required_argument, NULL, 'l'}, + {"escape", required_argument, NULL, 'e'}, + {NULL, 0, NULL, 0} + }; + + /* Standard (non-command) options. The leading + ensures that no + * argument reordering takes place, so that command options are + * not confused with top-level virsh options. */ + while ((arg = getopt_long(argc, argv, "+d:hqtc:vVrl:e:", opt, NULL)) != -1) { + switch (arg) { + case 'd': + if (virStrToLong_i(optarg, NULL, 10, &ctl->debug) < 0) { + vshError(ctl, "%s", _("option -d takes a numeric argument")); + exit(EXIT_FAILURE); + } + break; + case 'h': + vshUsage(); + exit(EXIT_SUCCESS); + break; + case 'q': + ctl->quiet = true; + break; + case 't': + ctl->timing = true; + break; + case 'c': + ctl->name = vshStrdup(ctl, optarg); + break; + case 'v': + if (STRNEQ_NULLABLE(optarg, "long")) { + puts(VERSION); + exit(EXIT_SUCCESS); + } + /* fall through */ + case 'V': + vshShowVersion(ctl); + exit(EXIT_SUCCESS); + case 'r': + ctl->readonly = true; + break; + case 'l': + ctl->logfile = vshStrdup(ctl, optarg); + break; + case 'e': + len = strlen(optarg); + + if ((len == 2 && *optarg == '^' && + vshAllowedEscapeChar(optarg[1])) || + (len == 1 && *optarg != '^')) { + ctl->escapeChar = optarg; + } else { + vshError(ctl, _("Invalid string '%s' for escape sequence"), + optarg); + exit(EXIT_FAILURE); + } + break; + default: + vshError(ctl, _("unsupported option '-%c'. See --help."), arg); + exit(EXIT_FAILURE); + } + } + + if (argc > optind) { + /* parse command */ + ctl->imode = false; + if (argc - optind == 1) { + vshDebug(ctl, VSH_ERR_INFO, "commands: \"%s\"\n", argv[optind]); + return vshCommandStringParse(ctl, argv[optind]); + } else { + return vshCommandArgvParse(ctl, argc - optind, argv + optind); + } + } + return true; +} + +static const vshCmdDef domManagementCmds[] = { + {"attach-device", cmdAttachDevice, opts_attach_device, + info_attach_device, 0}, + {"attach-disk", cmdAttachDisk, opts_attach_disk, + info_attach_disk, 0}, + {"attach-interface", cmdAttachInterface, opts_attach_interface, + info_attach_interface, 0}, + {"autostart", cmdAutostart, opts_autostart, info_autostart, 0}, + {"blkdeviotune", cmdBlkdeviotune, opts_blkdeviotune, info_blkdeviotune, 0}, + {"blkiotune", cmdBlkiotune, opts_blkiotune, info_blkiotune, 0}, + {"blockcopy", cmdBlockCopy, opts_block_copy, info_block_copy, 0}, + {"blockjob", cmdBlockJob, opts_block_job, info_block_job, 0}, + {"blockpull", cmdBlockPull, opts_block_pull, info_block_pull, 0}, + {"blockresize", cmdBlockResize, opts_block_resize, info_block_resize, 0}, + {"change-media", cmdChangeMedia, opts_change_media, info_change_media, 0}, +#ifndef WIN32 + {"console", cmdConsole, opts_console, info_console, 0}, +#endif + {"cpu-baseline", cmdCPUBaseline, opts_cpu_baseline, info_cpu_baseline, 0}, + {"cpu-compare", cmdCPUCompare, opts_cpu_compare, info_cpu_compare, 0}, + {"cpu-stats", cmdCPUStats, opts_cpu_stats, info_cpu_stats, 0}, + {"create", cmdCreate, opts_create, info_create, 0}, + {"define", cmdDefine, opts_define, info_define, 0}, + {"desc", cmdDesc, opts_desc, info_desc, 0}, + {"destroy", cmdDestroy, opts_destroy, info_destroy, 0}, + {"detach-device", cmdDetachDevice, opts_detach_device, + info_detach_device, 0}, + {"detach-disk", cmdDetachDisk, opts_detach_disk, info_detach_disk, 0}, + {"detach-interface", cmdDetachInterface, opts_detach_interface, + info_detach_interface, 0}, + {"domdisplay", cmdDomDisplay, opts_domdisplay, info_domdisplay, 0}, + {"domhostname", cmdDomHostname, opts_domhostname, info_domhostname, 0}, + {"domid", cmdDomid, opts_domid, info_domid, 0}, + {"domif-setlink", cmdDomIfSetLink, opts_domif_setlink, info_domif_setlink, 0}, + {"domiftune", cmdDomIftune, opts_domiftune, info_domiftune, 0}, + {"domjobabort", cmdDomjobabort, opts_domjobabort, info_domjobabort, 0}, + {"domjobinfo", cmdDomjobinfo, opts_domjobinfo, info_domjobinfo, 0}, + {"domname", cmdDomname, opts_domname, info_domname, 0}, + {"dompmsuspend", cmdDomPMSuspend, + opts_dom_pm_suspend, info_dom_pm_suspend, 0}, + {"dompmwakeup", cmdDomPMWakeup, + opts_dom_pm_wakeup, info_dom_pm_wakeup, 0}, + {"domuuid", cmdDomuuid, opts_domuuid, info_domuuid, 0}, + {"domxml-from-native", cmdDomXMLFromNative, opts_domxmlfromnative, + info_domxmlfromnative, 0}, + {"domxml-to-native", cmdDomXMLToNative, opts_domxmltonative, + info_domxmltonative, 0}, + {"dump", cmdDump, opts_dump, info_dump, 0}, + {"dumpxml", cmdDumpXML, opts_dumpxml, info_dumpxml, 0}, + {"edit", cmdEdit, opts_edit, info_edit, 0}, + {"inject-nmi", cmdInjectNMI, opts_inject_nmi, info_inject_nmi, 0}, + {"send-key", cmdSendKey, opts_send_key, info_send_key, 0}, + {"managedsave", cmdManagedSave, opts_managedsave, info_managedsave, 0}, + {"managedsave-remove", cmdManagedSaveRemove, opts_managedsaveremove, + info_managedsaveremove, 0}, + {"maxvcpus", cmdMaxvcpus, opts_maxvcpus, info_maxvcpus, 0}, + {"memtune", cmdMemtune, opts_memtune, info_memtune, 0}, + {"migrate", cmdMigrate, opts_migrate, info_migrate, 0}, + {"migrate-setmaxdowntime", cmdMigrateSetMaxDowntime, + opts_migrate_setmaxdowntime, info_migrate_setmaxdowntime, 0}, + {"migrate-setspeed", cmdMigrateSetMaxSpeed, + opts_migrate_setspeed, info_migrate_setspeed, 0}, + {"migrate-getspeed", cmdMigrateGetMaxSpeed, + opts_migrate_getspeed, info_migrate_getspeed, 0}, + {"numatune", cmdNumatune, opts_numatune, info_numatune, 0}, + {"reboot", cmdReboot, opts_reboot, info_reboot, 0}, + {"reset", cmdReset, opts_reset, info_reset, 0}, + {"restore", cmdRestore, opts_restore, info_restore, 0}, + {"resume", cmdResume, opts_resume, info_resume, 0}, + {"save", cmdSave, opts_save, info_save, 0}, + {"save-image-define", cmdSaveImageDefine, opts_save_image_define, + info_save_image_define, 0}, + {"save-image-dumpxml", cmdSaveImageDumpxml, opts_save_image_dumpxml, + info_save_image_dumpxml, 0}, + {"save-image-edit", cmdSaveImageEdit, opts_save_image_edit, + info_save_image_edit, 0}, + {"schedinfo", cmdSchedinfo, opts_schedinfo, info_schedinfo, 0}, + {"screenshot", cmdScreenshot, opts_screenshot, info_screenshot, 0}, + {"setmaxmem", cmdSetmaxmem, opts_setmaxmem, info_setmaxmem, 0}, + {"setmem", cmdSetmem, opts_setmem, info_setmem, 0}, + {"setvcpus", cmdSetvcpus, opts_setvcpus, info_setvcpus, 0}, + {"shutdown", cmdShutdown, opts_shutdown, info_shutdown, 0}, + {"start", cmdStart, opts_start, info_start, 0}, + {"suspend", cmdSuspend, opts_suspend, info_suspend, 0}, + {"ttyconsole", cmdTTYConsole, opts_ttyconsole, info_ttyconsole, 0}, + {"undefine", cmdUndefine, opts_undefine, info_undefine, 0}, + {"update-device", cmdUpdateDevice, opts_update_device, + info_update_device, 0}, + {"vcpucount", cmdVcpucount, opts_vcpucount, info_vcpucount, 0}, + {"vcpuinfo", cmdVcpuinfo, opts_vcpuinfo, info_vcpuinfo, 0}, + {"vcpupin", cmdVcpuPin, opts_vcpupin, info_vcpupin, 0}, + {"vncdisplay", cmdVNCDisplay, opts_vncdisplay, info_vncdisplay, 0}, + {NULL, NULL, NULL, NULL, 0} +}; + +static const vshCmdDef domMonitoringCmds[] = { + {"domblkerror", cmdDomBlkError, opts_domblkerror, info_domblkerror, 0}, + {"domblkinfo", cmdDomblkinfo, opts_domblkinfo, info_domblkinfo, 0}, + {"domblklist", cmdDomblklist, opts_domblklist, info_domblklist, 0}, + {"domblkstat", cmdDomblkstat, opts_domblkstat, info_domblkstat, 0}, + {"domcontrol", cmdDomControl, opts_domcontrol, info_domcontrol, 0}, + {"domif-getlink", cmdDomIfGetLink, opts_domif_getlink, info_domif_getlink, 0}, + {"domiflist", cmdDomiflist, opts_domiflist, info_domiflist, 0}, + {"domifstat", cmdDomIfstat, opts_domifstat, info_domifstat, 0}, + {"dominfo", cmdDominfo, opts_dominfo, info_dominfo, 0}, + {"dommemstat", cmdDomMemStat, opts_dommemstat, info_dommemstat, 0}, + {"domstate", cmdDomstate, opts_domstate, info_domstate, 0}, + {"list", cmdList, opts_list, info_list, 0}, + {NULL, NULL, NULL, NULL, 0} +}; + +static const vshCmdDef storagePoolCmds[] = { + {"find-storage-pool-sources-as", cmdPoolDiscoverSourcesAs, + opts_find_storage_pool_sources_as, info_find_storage_pool_sources_as, 0}, + {"find-storage-pool-sources", cmdPoolDiscoverSources, + opts_find_storage_pool_sources, info_find_storage_pool_sources, 0}, + {"pool-autostart", cmdPoolAutostart, opts_pool_autostart, + info_pool_autostart, 0}, + {"pool-build", cmdPoolBuild, opts_pool_build, info_pool_build, 0}, + {"pool-create-as", cmdPoolCreateAs, opts_pool_X_as, info_pool_create_as, 0}, + {"pool-create", cmdPoolCreate, opts_pool_create, info_pool_create, 0}, + {"pool-define-as", cmdPoolDefineAs, opts_pool_X_as, info_pool_define_as, 0}, + {"pool-define", cmdPoolDefine, opts_pool_define, info_pool_define, 0}, + {"pool-delete", cmdPoolDelete, opts_pool_delete, info_pool_delete, 0}, + {"pool-destroy", cmdPoolDestroy, opts_pool_destroy, info_pool_destroy, 0}, + {"pool-dumpxml", cmdPoolDumpXML, opts_pool_dumpxml, info_pool_dumpxml, 0}, + {"pool-edit", cmdPoolEdit, opts_pool_edit, info_pool_edit, 0}, + {"pool-info", cmdPoolInfo, opts_pool_info, info_pool_info, 0}, + {"pool-list", cmdPoolList, opts_pool_list, info_pool_list, 0}, + {"pool-name", cmdPoolName, opts_pool_name, info_pool_name, 0}, + {"pool-refresh", cmdPoolRefresh, opts_pool_refresh, info_pool_refresh, 0}, + {"pool-start", cmdPoolStart, opts_pool_start, info_pool_start, 0}, + {"pool-undefine", cmdPoolUndefine, opts_pool_undefine, + info_pool_undefine, 0}, + {"pool-uuid", cmdPoolUuid, opts_pool_uuid, info_pool_uuid, 0}, + {NULL, NULL, NULL, NULL, 0} +}; + +static const vshCmdDef storageVolCmds[] = { + {"vol-clone", cmdVolClone, opts_vol_clone, info_vol_clone, 0}, + {"vol-create-as", cmdVolCreateAs, opts_vol_create_as, + info_vol_create_as, 0}, + {"vol-create", cmdVolCreate, opts_vol_create, info_vol_create, 0}, + {"vol-create-from", cmdVolCreateFrom, opts_vol_create_from, + info_vol_create_from, 0}, + {"vol-delete", cmdVolDelete, opts_vol_delete, info_vol_delete, 0}, + {"vol-download", cmdVolDownload, opts_vol_download, info_vol_download, 0}, + {"vol-dumpxml", cmdVolDumpXML, opts_vol_dumpxml, info_vol_dumpxml, 0}, + {"vol-info", cmdVolInfo, opts_vol_info, info_vol_info, 0}, + {"vol-key", cmdVolKey, opts_vol_key, info_vol_key, 0}, + {"vol-list", cmdVolList, opts_vol_list, info_vol_list, 0}, + {"vol-name", cmdVolName, opts_vol_name, info_vol_name, 0}, + {"vol-path", cmdVolPath, opts_vol_path, info_vol_path, 0}, + {"vol-pool", cmdVolPool, opts_vol_pool, info_vol_pool, 0}, + {"vol-resize", cmdVolResize, opts_vol_resize, info_vol_resize, 0}, + {"vol-upload", cmdVolUpload, opts_vol_upload, info_vol_upload, 0}, + {"vol-wipe", cmdVolWipe, opts_vol_wipe, info_vol_wipe, 0}, + {NULL, NULL, NULL, NULL, 0} +}; + +static const vshCmdDef networkCmds[] = { + {"net-autostart", cmdNetworkAutostart, opts_network_autostart, + info_network_autostart, 0}, + {"net-create", cmdNetworkCreate, opts_network_create, + info_network_create, 0}, + {"net-define", cmdNetworkDefine, opts_network_define, + info_network_define, 0}, + {"net-destroy", cmdNetworkDestroy, opts_network_destroy, + info_network_destroy, 0}, + {"net-dumpxml", cmdNetworkDumpXML, opts_network_dumpxml, + info_network_dumpxml, 0}, + {"net-edit", cmdNetworkEdit, opts_network_edit, info_network_edit, 0}, + {"net-info", cmdNetworkInfo, opts_network_info, info_network_info, 0}, + {"net-list", cmdNetworkList, opts_network_list, info_network_list, 0}, + {"net-name", cmdNetworkName, opts_network_name, info_network_name, 0}, + {"net-start", cmdNetworkStart, opts_network_start, info_network_start, 0}, + {"net-undefine", cmdNetworkUndefine, opts_network_undefine, + info_network_undefine, 0}, + {"net-uuid", cmdNetworkUuid, opts_network_uuid, info_network_uuid, 0}, + {NULL, NULL, NULL, NULL, 0} +}; + +static const vshCmdDef nodedevCmds[] = { + {"nodedev-create", cmdNodeDeviceCreate, opts_node_device_create, + info_node_device_create, 0}, + {"nodedev-destroy", cmdNodeDeviceDestroy, opts_node_device_destroy, + info_node_device_destroy, 0}, + {"nodedev-detach", cmdNodeDeviceDetach, opts_node_device_detach, + info_node_device_detach, 0}, + {"nodedev-dettach", cmdNodeDeviceDetach, opts_node_device_detach, + info_node_device_detach, VSH_CMD_FLAG_ALIAS}, + {"nodedev-dumpxml", cmdNodeDeviceDumpXML, opts_node_device_dumpxml, + info_node_device_dumpxml, 0}, + {"nodedev-list", cmdNodeListDevices, opts_node_list_devices, + info_node_list_devices, 0}, + {"nodedev-reattach", cmdNodeDeviceReAttach, opts_node_device_reattach, + info_node_device_reattach, 0}, + {"nodedev-reset", cmdNodeDeviceReset, opts_node_device_reset, + info_node_device_reset, 0}, + {NULL, NULL, NULL, NULL, 0} +}; + +static const vshCmdDef ifaceCmds[] = { + {"iface-begin", cmdInterfaceBegin, opts_interface_begin, + info_interface_begin, 0}, + {"iface-bridge", cmdInterfaceBridge, opts_interface_bridge, + info_interface_bridge, 0}, + {"iface-commit", cmdInterfaceCommit, opts_interface_commit, + info_interface_commit, 0}, + {"iface-define", cmdInterfaceDefine, opts_interface_define, + info_interface_define, 0}, + {"iface-destroy", cmdInterfaceDestroy, opts_interface_destroy, + info_interface_destroy, 0}, + {"iface-dumpxml", cmdInterfaceDumpXML, opts_interface_dumpxml, + info_interface_dumpxml, 0}, + {"iface-edit", cmdInterfaceEdit, opts_interface_edit, + info_interface_edit, 0}, + {"iface-list", cmdInterfaceList, opts_interface_list, + info_interface_list, 0}, + {"iface-mac", cmdInterfaceMAC, opts_interface_mac, + info_interface_mac, 0}, + {"iface-name", cmdInterfaceName, opts_interface_name, + info_interface_name, 0}, + {"iface-rollback", cmdInterfaceRollback, opts_interface_rollback, + info_interface_rollback, 0}, + {"iface-start", cmdInterfaceStart, opts_interface_start, + info_interface_start, 0}, + {"iface-unbridge", cmdInterfaceUnbridge, opts_interface_unbridge, + info_interface_unbridge, 0}, + {"iface-undefine", cmdInterfaceUndefine, opts_interface_undefine, + info_interface_undefine, 0}, + {NULL, NULL, NULL, NULL, 0} +}; -static bool -vshAllowedEscapeChar(char c) -{ - /* Allowed escape characters: - * a-z A-Z @ [ \ ] ^ _ - */ - return ('a' <= c && c <= 'z') || - ('@' <= c && c <= '_'); -} +static const vshCmdDef nwfilterCmds[] = { + {"nwfilter-define", cmdNWFilterDefine, opts_nwfilter_define, + info_nwfilter_define, 0}, + {"nwfilter-dumpxml", cmdNWFilterDumpXML, opts_nwfilter_dumpxml, + info_nwfilter_dumpxml, 0}, + {"nwfilter-edit", cmdNWFilterEdit, opts_nwfilter_edit, + info_nwfilter_edit, 0}, + {"nwfilter-list", cmdNWFilterList, opts_nwfilter_list, + info_nwfilter_list, 0}, + {"nwfilter-undefine", cmdNWFilterUndefine, opts_nwfilter_undefine, + info_nwfilter_undefine, 0}, + {NULL, NULL, NULL, NULL, 0} +}; -/* - * argv[]: virsh [options] [command] - * - */ -static bool -vshParseArgv(vshControl *ctl, int argc, char **argv) -{ - int arg, len; - struct option opt[] = { - {"debug", required_argument, NULL, 'd'}, - {"help", no_argument, NULL, 'h'}, - {"quiet", no_argument, NULL, 'q'}, - {"timing", no_argument, NULL, 't'}, - {"version", optional_argument, NULL, 'v'}, - {"connect", required_argument, NULL, 'c'}, - {"readonly", no_argument, NULL, 'r'}, - {"log", required_argument, NULL, 'l'}, - {"escape", required_argument, NULL, 'e'}, - {NULL, 0, NULL, 0} - }; +static const vshCmdDef secretCmds[] = { + {"secret-define", cmdSecretDefine, opts_secret_define, + info_secret_define, 0}, + {"secret-dumpxml", cmdSecretDumpXML, opts_secret_dumpxml, + info_secret_dumpxml, 0}, + {"secret-get-value", cmdSecretGetValue, opts_secret_get_value, + info_secret_get_value, 0}, + {"secret-list", cmdSecretList, NULL, info_secret_list, 0}, + {"secret-set-value", cmdSecretSetValue, opts_secret_set_value, + info_secret_set_value, 0}, + {"secret-undefine", cmdSecretUndefine, opts_secret_undefine, + info_secret_undefine, 0}, + {NULL, NULL, NULL, NULL, 0} +}; - /* Standard (non-command) options. The leading + ensures that no - * argument reordering takes place, so that command options are - * not confused with top-level virsh options. */ - while ((arg = getopt_long(argc, argv, "+d:hqtc:vVrl:e:", opt, NULL)) != -1) { - switch (arg) { - case 'd': - if (virStrToLong_i(optarg, NULL, 10, &ctl->debug) < 0) { - vshError(ctl, "%s", _("option -d takes a numeric argument")); - exit(EXIT_FAILURE); - } - break; - case 'h': - vshUsage(); - exit(EXIT_SUCCESS); - break; - case 'q': - ctl->quiet = true; - break; - case 't': - ctl->timing = true; - break; - case 'c': - ctl->name = vshStrdup(ctl, optarg); - break; - case 'v': - if (STRNEQ_NULLABLE(optarg, "long")) { - puts(VERSION); - exit(EXIT_SUCCESS); - } - /* fall through */ - case 'V': - vshShowVersion(ctl); - exit(EXIT_SUCCESS); - case 'r': - ctl->readonly = true; - break; - case 'l': - ctl->logfile = vshStrdup(ctl, optarg); - break; - case 'e': - len = strlen(optarg); +static const vshCmdDef virshCmds[] = { + {"cd", cmdCd, opts_cd, info_cd, VSH_CMD_FLAG_NOCONNECT}, + {"echo", cmdEcho, opts_echo, info_echo, VSH_CMD_FLAG_NOCONNECT}, + {"exit", cmdQuit, NULL, info_quit, VSH_CMD_FLAG_NOCONNECT}, + {"help", cmdHelp, opts_help, info_help, VSH_CMD_FLAG_NOCONNECT}, + {"pwd", cmdPwd, NULL, info_pwd, VSH_CMD_FLAG_NOCONNECT}, + {"quit", cmdQuit, NULL, info_quit, VSH_CMD_FLAG_NOCONNECT}, + {NULL, NULL, NULL, NULL, 0} +}; - if ((len == 2 && *optarg == '^' && - vshAllowedEscapeChar(optarg[1])) || - (len == 1 && *optarg != '^')) { - ctl->escapeChar = optarg; - } else { - vshError(ctl, _("Invalid string '%s' for escape sequence"), - optarg); - exit(EXIT_FAILURE); - } - break; - default: - vshError(ctl, _("unsupported option '-%c'. See --help."), arg); - exit(EXIT_FAILURE); - } - } +static const vshCmdDef snapshotCmds[] = { + {"snapshot-create", cmdSnapshotCreate, opts_snapshot_create, + info_snapshot_create, 0}, + {"snapshot-create-as", cmdSnapshotCreateAs, opts_snapshot_create_as, + info_snapshot_create_as, 0}, + {"snapshot-current", cmdSnapshotCurrent, opts_snapshot_current, + info_snapshot_current, 0}, + {"snapshot-delete", cmdSnapshotDelete, opts_snapshot_delete, + info_snapshot_delete, 0}, + {"snapshot-dumpxml", cmdSnapshotDumpXML, opts_snapshot_dumpxml, + info_snapshot_dumpxml, 0}, + {"snapshot-edit", cmdSnapshotEdit, opts_snapshot_edit, + info_snapshot_edit, 0}, + {"snapshot-info", cmdSnapshotInfo, opts_snapshot_info, + info_snapshot_info, 0}, + {"snapshot-list", cmdSnapshotList, opts_snapshot_list, + info_snapshot_list, 0}, + {"snapshot-parent", cmdSnapshotParent, opts_snapshot_parent, + info_snapshot_parent, 0}, + {"snapshot-revert", cmdDomainSnapshotRevert, opts_snapshot_revert, + info_snapshot_revert, 0}, + {NULL, NULL, NULL, NULL, 0} +}; - if (argc > optind) { - /* parse command */ - ctl->imode = false; - if (argc - optind == 1) { - vshDebug(ctl, VSH_ERR_INFO, "commands: \"%s\"\n", argv[optind]); - return vshCommandStringParse(ctl, argv[optind]); - } else { - return vshCommandArgvParse(ctl, argc - optind, argv + optind); - } - } - return true; -} +static const vshCmdDef hostAndHypervisorCmds[] = { + {"capabilities", cmdCapabilities, NULL, info_capabilities, 0}, + {"connect", cmdConnect, opts_connect, info_connect, + VSH_CMD_FLAG_NOCONNECT}, + {"freecell", cmdFreecell, opts_freecell, info_freecell, 0}, + {"hostname", cmdHostname, NULL, info_hostname, 0}, + {"nodecpustats", cmdNodeCpuStats, opts_node_cpustats, info_nodecpustats, 0}, + {"nodeinfo", cmdNodeinfo, NULL, info_nodeinfo, 0}, + {"nodememstats", cmdNodeMemStats, opts_node_memstats, info_nodememstats, 0}, + {"nodesuspend", cmdNodeSuspend, opts_node_suspend, info_nodesuspend, 0}, + {"qemu-attach", cmdQemuAttach, opts_qemu_attach, info_qemu_attach, 0}, + {"qemu-monitor-command", cmdQemuMonitorCommand, opts_qemu_monitor_command, + info_qemu_monitor_command, 0}, + {"sysinfo", cmdSysinfo, NULL, info_sysinfo, 0}, + {"uri", cmdURI, NULL, info_uri, 0}, + {"version", cmdVersion, opts_version, info_version, 0}, + {NULL, NULL, NULL, NULL, 0} +}; + +static const vshCmdGrp cmdGroups[] = { + {VSH_CMD_GRP_DOM_MANAGEMENT, "domain", domManagementCmds}, + {VSH_CMD_GRP_DOM_MONITORING, "monitor", domMonitoringCmds}, + {VSH_CMD_GRP_HOST_AND_HV, "host", hostAndHypervisorCmds}, + {VSH_CMD_GRP_IFACE, "interface", ifaceCmds}, + {VSH_CMD_GRP_NWFILTER, "filter", nwfilterCmds}, + {VSH_CMD_GRP_NETWORK, "network", networkCmds}, + {VSH_CMD_GRP_NODEDEV, "nodedev", nodedevCmds}, + {VSH_CMD_GRP_SECRET, "secret", secretCmds}, + {VSH_CMD_GRP_SNAPSHOT, "snapshot", snapshotCmds}, + {VSH_CMD_GRP_STORAGE_POOL, "pool", storagePoolCmds}, + {VSH_CMD_GRP_STORAGE_VOL, "volume", storageVolCmds}, + {VSH_CMD_GRP_VIRSH, "virsh", virshCmds}, + {NULL, NULL, NULL} +}; int main(int argc, char **argv) -- 1.7.7.3

On 07/24/2012 11:18 AM, Osier Yang wrote:
This will avoid many conflicts if moving the codes for each command group into separate files in later patches. --- tools/virsh.c | 967 ++++++++++++++++++++++++++++----------------------------- 1 files changed, 483 insertions(+), 484 deletions(-)
diff --git a/tools/virsh.c b/tools/virsh.c index 6bb0fc8..81976a0 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -18183,371 +18183,38 @@ cleanup: return ret; }
-static const vshCmdDef domManagementCmds[] = { - {"attach-device", cmdAttachDevice, opts_attach_device, - info_attach_device, 0}, - {"attach-disk", cmdAttachDisk, opts_attach_disk, - info_attach_disk, 0}, - {"attach-interface", cmdAttachInterface, opts_attach_interface, - info_attach_interface, 0}, - {"autostart", cmdAutostart, opts_autostart, info_autostart, 0}, - {"blkdeviotune", cmdBlkdeviotune, opts_blkdeviotune, info_blkdeviotune, 0}, - {"blkiotune", cmdBlkiotune, opts_blkiotune, info_blkiotune, 0}, - {"blockcopy", cmdBlockCopy, opts_block_copy, info_block_copy, 0}, - {"blockjob", cmdBlockJob, opts_block_job, info_block_job, 0}, - {"blockpull", cmdBlockPull, opts_block_pull, info_block_pull, 0}, - {"blockresize", cmdBlockResize, opts_block_resize, info_block_resize, 0}, - {"change-media", cmdChangeMedia, opts_change_media, info_change_media, 0}, -#ifndef WIN32 - {"console", cmdConsole, opts_console, info_console, 0}, -#endif - {"cpu-baseline", cmdCPUBaseline, opts_cpu_baseline, info_cpu_baseline, 0}, - {"cpu-compare", cmdCPUCompare, opts_cpu_compare, info_cpu_compare, 0}, - {"cpu-stats", cmdCPUStats, opts_cpu_stats, info_cpu_stats, 0}, - {"create", cmdCreate, opts_create, info_create, 0}, - {"define", cmdDefine, opts_define, info_define, 0}, - {"desc", cmdDesc, opts_desc, info_desc, 0}, - {"destroy", cmdDestroy, opts_destroy, info_destroy, 0}, - {"detach-device", cmdDetachDevice, opts_detach_device, - info_detach_device, 0}, - {"detach-disk", cmdDetachDisk, opts_detach_disk, info_detach_disk, 0}, - {"detach-interface", cmdDetachInterface, opts_detach_interface, - info_detach_interface, 0}, - {"domdisplay", cmdDomDisplay, opts_domdisplay, info_domdisplay, 0}, - {"domhostname", cmdDomHostname, opts_domhostname, info_domhostname, 0}, - {"domid", cmdDomid, opts_domid, info_domid, 0}, - {"domif-setlink", cmdDomIfSetLink, opts_domif_setlink, info_domif_setlink, 0}, - {"domiftune", cmdDomIftune, opts_domiftune, info_domiftune, 0}, - {"domjobabort", cmdDomjobabort, opts_domjobabort, info_domjobabort, 0}, - {"domjobinfo", cmdDomjobinfo, opts_domjobinfo, info_domjobinfo, 0}, - {"domname", cmdDomname, opts_domname, info_domname, 0}, - {"dompmsuspend", cmdDomPMSuspend, - opts_dom_pm_suspend, info_dom_pm_suspend, 0}, - {"dompmwakeup", cmdDomPMWakeup, - opts_dom_pm_wakeup, info_dom_pm_wakeup, 0}, - {"domuuid", cmdDomuuid, opts_domuuid, info_domuuid, 0}, - {"domxml-from-native", cmdDomXMLFromNative, opts_domxmlfromnative, - info_domxmlfromnative, 0}, - {"domxml-to-native", cmdDomXMLToNative, opts_domxmltonative, - info_domxmltonative, 0}, - {"dump", cmdDump, opts_dump, info_dump, 0}, - {"dumpxml", cmdDumpXML, opts_dumpxml, info_dumpxml, 0}, - {"edit", cmdEdit, opts_edit, info_edit, 0}, - {"inject-nmi", cmdInjectNMI, opts_inject_nmi, info_inject_nmi, 0}, - {"send-key", cmdSendKey, opts_send_key, info_send_key, 0}, - {"managedsave", cmdManagedSave, opts_managedsave, info_managedsave, 0}, - {"managedsave-remove", cmdManagedSaveRemove, opts_managedsaveremove, - info_managedsaveremove, 0}, - {"maxvcpus", cmdMaxvcpus, opts_maxvcpus, info_maxvcpus, 0}, - {"memtune", cmdMemtune, opts_memtune, info_memtune, 0}, - {"migrate", cmdMigrate, opts_migrate, info_migrate, 0}, - {"migrate-setmaxdowntime", cmdMigrateSetMaxDowntime, - opts_migrate_setmaxdowntime, info_migrate_setmaxdowntime, 0}, - {"migrate-setspeed", cmdMigrateSetMaxSpeed, - opts_migrate_setspeed, info_migrate_setspeed, 0}, - {"migrate-getspeed", cmdMigrateGetMaxSpeed, - opts_migrate_getspeed, info_migrate_getspeed, 0}, - {"numatune", cmdNumatune, opts_numatune, info_numatune, 0}, - {"reboot", cmdReboot, opts_reboot, info_reboot, 0}, - {"reset", cmdReset, opts_reset, info_reset, 0}, - {"restore", cmdRestore, opts_restore, info_restore, 0}, - {"resume", cmdResume, opts_resume, info_resume, 0}, - {"save", cmdSave, opts_save, info_save, 0}, - {"save-image-define", cmdSaveImageDefine, opts_save_image_define, - info_save_image_define, 0}, - {"save-image-dumpxml", cmdSaveImageDumpxml, opts_save_image_dumpxml, - info_save_image_dumpxml, 0}, - {"save-image-edit", cmdSaveImageEdit, opts_save_image_edit, - info_save_image_edit, 0}, - {"schedinfo", cmdSchedinfo, opts_schedinfo, info_schedinfo, 0}, - {"screenshot", cmdScreenshot, opts_screenshot, info_screenshot, 0}, - {"setmaxmem", cmdSetmaxmem, opts_setmaxmem, info_setmaxmem, 0}, - {"setmem", cmdSetmem, opts_setmem, info_setmem, 0}, - {"setvcpus", cmdSetvcpus, opts_setvcpus, info_setvcpus, 0}, - {"shutdown", cmdShutdown, opts_shutdown, info_shutdown, 0}, - {"start", cmdStart, opts_start, info_start, 0}, - {"suspend", cmdSuspend, opts_suspend, info_suspend, 0}, - {"ttyconsole", cmdTTYConsole, opts_ttyconsole, info_ttyconsole, 0}, - {"undefine", cmdUndefine, opts_undefine, info_undefine, 0}, - {"update-device", cmdUpdateDevice, opts_update_device, - info_update_device, 0}, - {"vcpucount", cmdVcpucount, opts_vcpucount, info_vcpucount, 0}, - {"vcpuinfo", cmdVcpuinfo, opts_vcpuinfo, info_vcpuinfo, 0}, - {"vcpupin", cmdVcpuPin, opts_vcpupin, info_vcpupin, 0}, - {"vncdisplay", cmdVNCDisplay, opts_vncdisplay, info_vncdisplay, 0}, - {NULL, NULL, NULL, NULL, 0} -}; - -static const vshCmdDef domMonitoringCmds[] = { - {"domblkerror", cmdDomBlkError, opts_domblkerror, info_domblkerror, 0}, - {"domblkinfo", cmdDomblkinfo, opts_domblkinfo, info_domblkinfo, 0}, - {"domblklist", cmdDomblklist, opts_domblklist, info_domblklist, 0}, - {"domblkstat", cmdDomblkstat, opts_domblkstat, info_domblkstat, 0}, - {"domcontrol", cmdDomControl, opts_domcontrol, info_domcontrol, 0}, - {"domif-getlink", cmdDomIfGetLink, opts_domif_getlink, info_domif_getlink, 0}, - {"domiflist", cmdDomiflist, opts_domiflist, info_domiflist, 0}, - {"domifstat", cmdDomIfstat, opts_domifstat, info_domifstat, 0}, - {"dominfo", cmdDominfo, opts_dominfo, info_dominfo, 0}, - {"dommemstat", cmdDomMemStat, opts_dommemstat, info_dommemstat, 0}, - {"domstate", cmdDomstate, opts_domstate, info_domstate, 0}, - {"list", cmdList, opts_list, info_list, 0}, - {NULL, NULL, NULL, NULL, 0} -}; +/* --------------- + * Utils for work with command definition + * --------------- + */ +static const char * +vshCmddefGetInfo(const vshCmdDef * cmd, const char *name) +{ + const vshCmdInfo *info;
-static const vshCmdDef storagePoolCmds[] = { - {"find-storage-pool-sources-as", cmdPoolDiscoverSourcesAs, - opts_find_storage_pool_sources_as, info_find_storage_pool_sources_as, 0}, - {"find-storage-pool-sources", cmdPoolDiscoverSources, - opts_find_storage_pool_sources, info_find_storage_pool_sources, 0}, - {"pool-autostart", cmdPoolAutostart, opts_pool_autostart, - info_pool_autostart, 0}, - {"pool-build", cmdPoolBuild, opts_pool_build, info_pool_build, 0}, - {"pool-create-as", cmdPoolCreateAs, opts_pool_X_as, info_pool_create_as, 0}, - {"pool-create", cmdPoolCreate, opts_pool_create, info_pool_create, 0}, - {"pool-define-as", cmdPoolDefineAs, opts_pool_X_as, info_pool_define_as, 0}, - {"pool-define", cmdPoolDefine, opts_pool_define, info_pool_define, 0}, - {"pool-delete", cmdPoolDelete, opts_pool_delete, info_pool_delete, 0}, - {"pool-destroy", cmdPoolDestroy, opts_pool_destroy, info_pool_destroy, 0}, - {"pool-dumpxml", cmdPoolDumpXML, opts_pool_dumpxml, info_pool_dumpxml, 0}, - {"pool-edit", cmdPoolEdit, opts_pool_edit, info_pool_edit, 0}, - {"pool-info", cmdPoolInfo, opts_pool_info, info_pool_info, 0}, - {"pool-list", cmdPoolList, opts_pool_list, info_pool_list, 0}, - {"pool-name", cmdPoolName, opts_pool_name, info_pool_name, 0}, - {"pool-refresh", cmdPoolRefresh, opts_pool_refresh, info_pool_refresh, 0}, - {"pool-start", cmdPoolStart, opts_pool_start, info_pool_start, 0}, - {"pool-undefine", cmdPoolUndefine, opts_pool_undefine, - info_pool_undefine, 0}, - {"pool-uuid", cmdPoolUuid, opts_pool_uuid, info_pool_uuid, 0}, - {NULL, NULL, NULL, NULL, 0} -}; + for (info = cmd->info; info && info->name; info++) { + if (STREQ(info->name, name)) + return info->data; + } + return NULL; +}
-static const vshCmdDef storageVolCmds[] = { - {"vol-clone", cmdVolClone, opts_vol_clone, info_vol_clone, 0}, - {"vol-create-as", cmdVolCreateAs, opts_vol_create_as, - info_vol_create_as, 0}, - {"vol-create", cmdVolCreate, opts_vol_create, info_vol_create, 0}, - {"vol-create-from", cmdVolCreateFrom, opts_vol_create_from, - info_vol_create_from, 0}, - {"vol-delete", cmdVolDelete, opts_vol_delete, info_vol_delete, 0}, - {"vol-download", cmdVolDownload, opts_vol_download, info_vol_download, 0}, - {"vol-dumpxml", cmdVolDumpXML, opts_vol_dumpxml, info_vol_dumpxml, 0}, - {"vol-info", cmdVolInfo, opts_vol_info, info_vol_info, 0}, - {"vol-key", cmdVolKey, opts_vol_key, info_vol_key, 0}, - {"vol-list", cmdVolList, opts_vol_list, info_vol_list, 0}, - {"vol-name", cmdVolName, opts_vol_name, info_vol_name, 0}, - {"vol-path", cmdVolPath, opts_vol_path, info_vol_path, 0}, - {"vol-pool", cmdVolPool, opts_vol_pool, info_vol_pool, 0}, - {"vol-resize", cmdVolResize, opts_vol_resize, info_vol_resize, 0}, - {"vol-upload", cmdVolUpload, opts_vol_upload, info_vol_upload, 0}, - {"vol-wipe", cmdVolWipe, opts_vol_wipe, info_vol_wipe, 0}, - {NULL, NULL, NULL, NULL, 0} -}; +/* Validate that the options associated with cmd can be parsed. */ +static int +vshCmddefOptParse(const vshCmdDef *cmd, uint32_t *opts_need_arg, + uint32_t *opts_required) +{ + int i; + bool optional = false;
-static const vshCmdDef networkCmds[] = { - {"net-autostart", cmdNetworkAutostart, opts_network_autostart, - info_network_autostart, 0}, - {"net-create", cmdNetworkCreate, opts_network_create, - info_network_create, 0}, - {"net-define", cmdNetworkDefine, opts_network_define, - info_network_define, 0}, - {"net-destroy", cmdNetworkDestroy, opts_network_destroy, - info_network_destroy, 0}, - {"net-dumpxml", cmdNetworkDumpXML, opts_network_dumpxml, - info_network_dumpxml, 0}, - {"net-edit", cmdNetworkEdit, opts_network_edit, info_network_edit, 0}, - {"net-info", cmdNetworkInfo, opts_network_info, info_network_info, 0}, - {"net-list", cmdNetworkList, opts_network_list, info_network_list, 0}, - {"net-name", cmdNetworkName, opts_network_name, info_network_name, 0}, - {"net-start", cmdNetworkStart, opts_network_start, info_network_start, 0}, - {"net-undefine", cmdNetworkUndefine, opts_network_undefine, - info_network_undefine, 0}, - {"net-uuid", cmdNetworkUuid, opts_network_uuid, info_network_uuid, 0}, - {NULL, NULL, NULL, NULL, 0} -}; + *opts_need_arg = 0; + *opts_required = 0;
-static const vshCmdDef nodedevCmds[] = { - {"nodedev-create", cmdNodeDeviceCreate, opts_node_device_create, - info_node_device_create, 0}, - {"nodedev-destroy", cmdNodeDeviceDestroy, opts_node_device_destroy, - info_node_device_destroy, 0}, - {"nodedev-detach", cmdNodeDeviceDetach, opts_node_device_detach, - info_node_device_detach, 0}, - {"nodedev-dettach", cmdNodeDeviceDetach, opts_node_device_detach, - info_node_device_detach, VSH_CMD_FLAG_ALIAS}, - {"nodedev-dumpxml", cmdNodeDeviceDumpXML, opts_node_device_dumpxml, - info_node_device_dumpxml, 0}, - {"nodedev-list", cmdNodeListDevices, opts_node_list_devices, - info_node_list_devices, 0}, - {"nodedev-reattach", cmdNodeDeviceReAttach, opts_node_device_reattach, - info_node_device_reattach, 0}, - {"nodedev-reset", cmdNodeDeviceReset, opts_node_device_reset, - info_node_device_reset, 0}, - {NULL, NULL, NULL, NULL, 0} -}; + if (!cmd->opts) + return 0;
-static const vshCmdDef ifaceCmds[] = { - {"iface-begin", cmdInterfaceBegin, opts_interface_begin, - info_interface_begin, 0}, - {"iface-bridge", cmdInterfaceBridge, opts_interface_bridge, - info_interface_bridge, 0}, - {"iface-commit", cmdInterfaceCommit, opts_interface_commit, - info_interface_commit, 0}, - {"iface-define", cmdInterfaceDefine, opts_interface_define, - info_interface_define, 0}, - {"iface-destroy", cmdInterfaceDestroy, opts_interface_destroy, - info_interface_destroy, 0}, - {"iface-dumpxml", cmdInterfaceDumpXML, opts_interface_dumpxml, - info_interface_dumpxml, 0}, - {"iface-edit", cmdInterfaceEdit, opts_interface_edit, - info_interface_edit, 0}, - {"iface-list", cmdInterfaceList, opts_interface_list, - info_interface_list, 0}, - {"iface-mac", cmdInterfaceMAC, opts_interface_mac, - info_interface_mac, 0}, - {"iface-name", cmdInterfaceName, opts_interface_name, - info_interface_name, 0}, - {"iface-rollback", cmdInterfaceRollback, opts_interface_rollback, - info_interface_rollback, 0}, - {"iface-start", cmdInterfaceStart, opts_interface_start, - info_interface_start, 0}, - {"iface-unbridge", cmdInterfaceUnbridge, opts_interface_unbridge, - info_interface_unbridge, 0}, - {"iface-undefine", cmdInterfaceUndefine, opts_interface_undefine, - info_interface_undefine, 0}, - {NULL, NULL, NULL, NULL, 0} -}; - -static const vshCmdDef nwfilterCmds[] = { - {"nwfilter-define", cmdNWFilterDefine, opts_nwfilter_define, - info_nwfilter_define, 0}, - {"nwfilter-dumpxml", cmdNWFilterDumpXML, opts_nwfilter_dumpxml, - info_nwfilter_dumpxml, 0}, - {"nwfilter-edit", cmdNWFilterEdit, opts_nwfilter_edit, - info_nwfilter_edit, 0}, - {"nwfilter-list", cmdNWFilterList, opts_nwfilter_list, - info_nwfilter_list, 0}, - {"nwfilter-undefine", cmdNWFilterUndefine, opts_nwfilter_undefine, - info_nwfilter_undefine, 0}, - {NULL, NULL, NULL, NULL, 0} -}; - -static const vshCmdDef secretCmds[] = { - {"secret-define", cmdSecretDefine, opts_secret_define, - info_secret_define, 0}, - {"secret-dumpxml", cmdSecretDumpXML, opts_secret_dumpxml, - info_secret_dumpxml, 0}, - {"secret-get-value", cmdSecretGetValue, opts_secret_get_value, - info_secret_get_value, 0}, - {"secret-list", cmdSecretList, NULL, info_secret_list, 0}, - {"secret-set-value", cmdSecretSetValue, opts_secret_set_value, - info_secret_set_value, 0}, - {"secret-undefine", cmdSecretUndefine, opts_secret_undefine, - info_secret_undefine, 0}, - {NULL, NULL, NULL, NULL, 0} -}; - -static const vshCmdDef virshCmds[] = { - {"cd", cmdCd, opts_cd, info_cd, VSH_CMD_FLAG_NOCONNECT}, - {"echo", cmdEcho, opts_echo, info_echo, VSH_CMD_FLAG_NOCONNECT}, - {"exit", cmdQuit, NULL, info_quit, VSH_CMD_FLAG_NOCONNECT}, - {"help", cmdHelp, opts_help, info_help, VSH_CMD_FLAG_NOCONNECT}, - {"pwd", cmdPwd, NULL, info_pwd, VSH_CMD_FLAG_NOCONNECT}, - {"quit", cmdQuit, NULL, info_quit, VSH_CMD_FLAG_NOCONNECT}, - {NULL, NULL, NULL, NULL, 0} -}; - -static const vshCmdDef snapshotCmds[] = { - {"snapshot-create", cmdSnapshotCreate, opts_snapshot_create, - info_snapshot_create, 0}, - {"snapshot-create-as", cmdSnapshotCreateAs, opts_snapshot_create_as, - info_snapshot_create_as, 0}, - {"snapshot-current", cmdSnapshotCurrent, opts_snapshot_current, - info_snapshot_current, 0}, - {"snapshot-delete", cmdSnapshotDelete, opts_snapshot_delete, - info_snapshot_delete, 0}, - {"snapshot-dumpxml", cmdSnapshotDumpXML, opts_snapshot_dumpxml, - info_snapshot_dumpxml, 0}, - {"snapshot-edit", cmdSnapshotEdit, opts_snapshot_edit, - info_snapshot_edit, 0}, - {"snapshot-info", cmdSnapshotInfo, opts_snapshot_info, - info_snapshot_info, 0}, - {"snapshot-list", cmdSnapshotList, opts_snapshot_list, - info_snapshot_list, 0}, - {"snapshot-parent", cmdSnapshotParent, opts_snapshot_parent, - info_snapshot_parent, 0}, - {"snapshot-revert", cmdDomainSnapshotRevert, opts_snapshot_revert, - info_snapshot_revert, 0}, - {NULL, NULL, NULL, NULL, 0} -}; - -static const vshCmdDef hostAndHypervisorCmds[] = { - {"capabilities", cmdCapabilities, NULL, info_capabilities, 0}, - {"connect", cmdConnect, opts_connect, info_connect, - VSH_CMD_FLAG_NOCONNECT}, - {"freecell", cmdFreecell, opts_freecell, info_freecell, 0}, - {"hostname", cmdHostname, NULL, info_hostname, 0}, - {"nodecpustats", cmdNodeCpuStats, opts_node_cpustats, info_nodecpustats, 0}, - {"nodeinfo", cmdNodeinfo, NULL, info_nodeinfo, 0}, - {"nodememstats", cmdNodeMemStats, opts_node_memstats, info_nodememstats, 0}, - {"nodesuspend", cmdNodeSuspend, opts_node_suspend, info_nodesuspend, 0}, - {"qemu-attach", cmdQemuAttach, opts_qemu_attach, info_qemu_attach, 0}, - {"qemu-monitor-command", cmdQemuMonitorCommand, opts_qemu_monitor_command, - info_qemu_monitor_command, 0}, - {"sysinfo", cmdSysinfo, NULL, info_sysinfo, 0}, - {"uri", cmdURI, NULL, info_uri, 0}, - {"version", cmdVersion, opts_version, info_version, 0}, - {NULL, NULL, NULL, NULL, 0} -}; - -static const vshCmdGrp cmdGroups[] = { - {VSH_CMD_GRP_DOM_MANAGEMENT, "domain", domManagementCmds}, - {VSH_CMD_GRP_DOM_MONITORING, "monitor", domMonitoringCmds}, - {VSH_CMD_GRP_HOST_AND_HV, "host", hostAndHypervisorCmds}, - {VSH_CMD_GRP_IFACE, "interface", ifaceCmds}, - {VSH_CMD_GRP_NWFILTER, "filter", nwfilterCmds}, - {VSH_CMD_GRP_NETWORK, "network", networkCmds}, - {VSH_CMD_GRP_NODEDEV, "nodedev", nodedevCmds}, - {VSH_CMD_GRP_SECRET, "secret", secretCmds}, - {VSH_CMD_GRP_SNAPSHOT, "snapshot", snapshotCmds}, - {VSH_CMD_GRP_STORAGE_POOL, "pool", storagePoolCmds}, - {VSH_CMD_GRP_STORAGE_VOL, "volume", storageVolCmds}, - {VSH_CMD_GRP_VIRSH, "virsh", virshCmds}, - {NULL, NULL, NULL} -}; - - -/* --------------- - * Utils for work with command definition - * --------------- - */ -static const char * -vshCmddefGetInfo(const vshCmdDef * cmd, const char *name) -{ - const vshCmdInfo *info; - - for (info = cmd->info; info && info->name; info++) { - if (STREQ(info->name, name)) - return info->data; - } - return NULL; -} - -/* Validate that the options associated with cmd can be parsed. */ -static int -vshCmddefOptParse(const vshCmdDef *cmd, uint32_t *opts_need_arg, - uint32_t *opts_required) -{ - int i; - bool optional = false; - - *opts_need_arg = 0; - *opts_required = 0; - - if (!cmd->opts) - return 0; - - for (i = 0; cmd->opts[i].name; i++) { - const vshCmdOptDef *opt = &cmd->opts[i]; + for (i = 0; cmd->opts[i].name; i++) { + const vshCmdOptDef *opt = &cmd->opts[i];
if (i > 31) return -1; /* too many options */ @@ -20923,135 +20590,467 @@ vshShowVersion(vshControl *ctl ATTRIBUTE_UNUSED) #endif vshPrint(ctl, "\n");
- vshPrint(ctl, "%s", _(" Miscellaneous:")); -#ifdef WITH_NODE_DEVICES - vshPrint(ctl, " Nodedev"); -#endif -#ifdef WITH_SECDRIVER_APPARMOR - vshPrint(ctl, " AppArmor"); -#endif -#ifdef WITH_SECDRIVER_SELINUX - vshPrint(ctl, " SELinux"); -#endif -#ifdef WITH_SECRETS - vshPrint(ctl, " Secrets"); -#endif -#ifdef ENABLE_DEBUG - vshPrint(ctl, " Debug"); -#endif -#ifdef WITH_DTRACE_PROBES - vshPrint(ctl, " DTrace"); -#endif -#ifdef USE_READLINE - vshPrint(ctl, " Readline"); -#endif -#ifdef WITH_DRIVER_MODULES - vshPrint(ctl, " Modular"); -#endif - vshPrint(ctl, "\n"); -} + vshPrint(ctl, "%s", _(" Miscellaneous:")); +#ifdef WITH_NODE_DEVICES + vshPrint(ctl, " Nodedev"); +#endif +#ifdef WITH_SECDRIVER_APPARMOR + vshPrint(ctl, " AppArmor"); +#endif +#ifdef WITH_SECDRIVER_SELINUX + vshPrint(ctl, " SELinux"); +#endif +#ifdef WITH_SECRETS + vshPrint(ctl, " Secrets"); +#endif +#ifdef ENABLE_DEBUG + vshPrint(ctl, " Debug"); +#endif +#ifdef WITH_DTRACE_PROBES + vshPrint(ctl, " DTrace"); +#endif +#ifdef USE_READLINE + vshPrint(ctl, " Readline"); +#endif +#ifdef WITH_DRIVER_MODULES + vshPrint(ctl, " Modular"); +#endif + vshPrint(ctl, "\n"); +} + +static bool +vshAllowedEscapeChar(char c) +{ + /* Allowed escape characters: + * a-z A-Z @ [ \ ] ^ _ + */ + return ('a' <= c && c <= 'z') || + ('@' <= c && c <= '_'); +} + +/* + * argv[]: virsh [options] [command] + * + */ +static bool +vshParseArgv(vshControl *ctl, int argc, char **argv) +{ + int arg, len; + struct option opt[] = { + {"debug", required_argument, NULL, 'd'}, + {"help", no_argument, NULL, 'h'}, + {"quiet", no_argument, NULL, 'q'}, + {"timing", no_argument, NULL, 't'}, + {"version", optional_argument, NULL, 'v'}, + {"connect", required_argument, NULL, 'c'}, + {"readonly", no_argument, NULL, 'r'}, + {"log", required_argument, NULL, 'l'}, + {"escape", required_argument, NULL, 'e'}, + {NULL, 0, NULL, 0} + }; + + /* Standard (non-command) options. The leading + ensures that no + * argument reordering takes place, so that command options are + * not confused with top-level virsh options. */ + while ((arg = getopt_long(argc, argv, "+d:hqtc:vVrl:e:", opt, NULL)) != -1) { + switch (arg) { + case 'd': + if (virStrToLong_i(optarg, NULL, 10, &ctl->debug) < 0) { + vshError(ctl, "%s", _("option -d takes a numeric argument")); + exit(EXIT_FAILURE); + } + break; + case 'h': + vshUsage(); + exit(EXIT_SUCCESS); + break; + case 'q': + ctl->quiet = true; + break; + case 't': + ctl->timing = true; + break; + case 'c': + ctl->name = vshStrdup(ctl, optarg); + break; + case 'v': + if (STRNEQ_NULLABLE(optarg, "long")) { + puts(VERSION); + exit(EXIT_SUCCESS); + } + /* fall through */ + case 'V': + vshShowVersion(ctl); + exit(EXIT_SUCCESS); + case 'r': + ctl->readonly = true; + break; + case 'l': + ctl->logfile = vshStrdup(ctl, optarg); + break; + case 'e': + len = strlen(optarg); + + if ((len == 2 && *optarg == '^' && + vshAllowedEscapeChar(optarg[1])) || + (len == 1 && *optarg != '^')) { + ctl->escapeChar = optarg; + } else { + vshError(ctl, _("Invalid string '%s' for escape sequence"), + optarg); + exit(EXIT_FAILURE); + } + break; + default: + vshError(ctl, _("unsupported option '-%c'. See --help."), arg); + exit(EXIT_FAILURE); + } + } + + if (argc > optind) { + /* parse command */ + ctl->imode = false; + if (argc - optind == 1) { + vshDebug(ctl, VSH_ERR_INFO, "commands: \"%s\"\n", argv[optind]); + return vshCommandStringParse(ctl, argv[optind]); + } else { + return vshCommandArgvParse(ctl, argc - optind, argv + optind); + } + } + return true; +} + +static const vshCmdDef domManagementCmds[] = { + {"attach-device", cmdAttachDevice, opts_attach_device, + info_attach_device, 0}, + {"attach-disk", cmdAttachDisk, opts_attach_disk, + info_attach_disk, 0}, + {"attach-interface", cmdAttachInterface, opts_attach_interface, + info_attach_interface, 0}, + {"autostart", cmdAutostart, opts_autostart, info_autostart, 0}, + {"blkdeviotune", cmdBlkdeviotune, opts_blkdeviotune, info_blkdeviotune, 0}, + {"blkiotune", cmdBlkiotune, opts_blkiotune, info_blkiotune, 0}, + {"blockcopy", cmdBlockCopy, opts_block_copy, info_block_copy, 0}, + {"blockjob", cmdBlockJob, opts_block_job, info_block_job, 0}, + {"blockpull", cmdBlockPull, opts_block_pull, info_block_pull, 0}, + {"blockresize", cmdBlockResize, opts_block_resize, info_block_resize, 0}, + {"change-media", cmdChangeMedia, opts_change_media, info_change_media, 0}, +#ifndef WIN32 + {"console", cmdConsole, opts_console, info_console, 0}, +#endif + {"cpu-baseline", cmdCPUBaseline, opts_cpu_baseline, info_cpu_baseline, 0}, + {"cpu-compare", cmdCPUCompare, opts_cpu_compare, info_cpu_compare, 0}, + {"cpu-stats", cmdCPUStats, opts_cpu_stats, info_cpu_stats, 0}, + {"create", cmdCreate, opts_create, info_create, 0}, + {"define", cmdDefine, opts_define, info_define, 0}, + {"desc", cmdDesc, opts_desc, info_desc, 0}, + {"destroy", cmdDestroy, opts_destroy, info_destroy, 0}, + {"detach-device", cmdDetachDevice, opts_detach_device, + info_detach_device, 0}, + {"detach-disk", cmdDetachDisk, opts_detach_disk, info_detach_disk, 0}, + {"detach-interface", cmdDetachInterface, opts_detach_interface, + info_detach_interface, 0}, + {"domdisplay", cmdDomDisplay, opts_domdisplay, info_domdisplay, 0}, + {"domhostname", cmdDomHostname, opts_domhostname, info_domhostname, 0}, + {"domid", cmdDomid, opts_domid, info_domid, 0}, + {"domif-setlink", cmdDomIfSetLink, opts_domif_setlink, info_domif_setlink, 0}, + {"domiftune", cmdDomIftune, opts_domiftune, info_domiftune, 0}, + {"domjobabort", cmdDomjobabort, opts_domjobabort, info_domjobabort, 0}, + {"domjobinfo", cmdDomjobinfo, opts_domjobinfo, info_domjobinfo, 0}, + {"domname", cmdDomname, opts_domname, info_domname, 0}, + {"dompmsuspend", cmdDomPMSuspend, + opts_dom_pm_suspend, info_dom_pm_suspend, 0}, + {"dompmwakeup", cmdDomPMWakeup, + opts_dom_pm_wakeup, info_dom_pm_wakeup, 0}, + {"domuuid", cmdDomuuid, opts_domuuid, info_domuuid, 0}, + {"domxml-from-native", cmdDomXMLFromNative, opts_domxmlfromnative, + info_domxmlfromnative, 0}, + {"domxml-to-native", cmdDomXMLToNative, opts_domxmltonative, + info_domxmltonative, 0}, + {"dump", cmdDump, opts_dump, info_dump, 0}, + {"dumpxml", cmdDumpXML, opts_dumpxml, info_dumpxml, 0}, + {"edit", cmdEdit, opts_edit, info_edit, 0}, + {"inject-nmi", cmdInjectNMI, opts_inject_nmi, info_inject_nmi, 0}, + {"send-key", cmdSendKey, opts_send_key, info_send_key, 0}, + {"managedsave", cmdManagedSave, opts_managedsave, info_managedsave, 0}, + {"managedsave-remove", cmdManagedSaveRemove, opts_managedsaveremove, + info_managedsaveremove, 0}, + {"maxvcpus", cmdMaxvcpus, opts_maxvcpus, info_maxvcpus, 0}, + {"memtune", cmdMemtune, opts_memtune, info_memtune, 0}, + {"migrate", cmdMigrate, opts_migrate, info_migrate, 0}, + {"migrate-setmaxdowntime", cmdMigrateSetMaxDowntime, + opts_migrate_setmaxdowntime, info_migrate_setmaxdowntime, 0}, + {"migrate-setspeed", cmdMigrateSetMaxSpeed, + opts_migrate_setspeed, info_migrate_setspeed, 0}, + {"migrate-getspeed", cmdMigrateGetMaxSpeed, + opts_migrate_getspeed, info_migrate_getspeed, 0}, + {"numatune", cmdNumatune, opts_numatune, info_numatune, 0}, + {"reboot", cmdReboot, opts_reboot, info_reboot, 0}, + {"reset", cmdReset, opts_reset, info_reset, 0}, + {"restore", cmdRestore, opts_restore, info_restore, 0}, + {"resume", cmdResume, opts_resume, info_resume, 0}, + {"save", cmdSave, opts_save, info_save, 0}, + {"save-image-define", cmdSaveImageDefine, opts_save_image_define, + info_save_image_define, 0}, + {"save-image-dumpxml", cmdSaveImageDumpxml, opts_save_image_dumpxml, + info_save_image_dumpxml, 0}, + {"save-image-edit", cmdSaveImageEdit, opts_save_image_edit, + info_save_image_edit, 0}, + {"schedinfo", cmdSchedinfo, opts_schedinfo, info_schedinfo, 0}, + {"screenshot", cmdScreenshot, opts_screenshot, info_screenshot, 0}, + {"setmaxmem", cmdSetmaxmem, opts_setmaxmem, info_setmaxmem, 0}, + {"setmem", cmdSetmem, opts_setmem, info_setmem, 0}, + {"setvcpus", cmdSetvcpus, opts_setvcpus, info_setvcpus, 0}, + {"shutdown", cmdShutdown, opts_shutdown, info_shutdown, 0}, + {"start", cmdStart, opts_start, info_start, 0}, + {"suspend", cmdSuspend, opts_suspend, info_suspend, 0}, + {"ttyconsole", cmdTTYConsole, opts_ttyconsole, info_ttyconsole, 0}, + {"undefine", cmdUndefine, opts_undefine, info_undefine, 0}, + {"update-device", cmdUpdateDevice, opts_update_device, + info_update_device, 0}, + {"vcpucount", cmdVcpucount, opts_vcpucount, info_vcpucount, 0}, + {"vcpuinfo", cmdVcpuinfo, opts_vcpuinfo, info_vcpuinfo, 0}, + {"vcpupin", cmdVcpuPin, opts_vcpupin, info_vcpupin, 0}, + {"vncdisplay", cmdVNCDisplay, opts_vncdisplay, info_vncdisplay, 0}, + {NULL, NULL, NULL, NULL, 0} +}; + +static const vshCmdDef domMonitoringCmds[] = { + {"domblkerror", cmdDomBlkError, opts_domblkerror, info_domblkerror, 0}, + {"domblkinfo", cmdDomblkinfo, opts_domblkinfo, info_domblkinfo, 0}, + {"domblklist", cmdDomblklist, opts_domblklist, info_domblklist, 0}, + {"domblkstat", cmdDomblkstat, opts_domblkstat, info_domblkstat, 0}, + {"domcontrol", cmdDomControl, opts_domcontrol, info_domcontrol, 0}, + {"domif-getlink", cmdDomIfGetLink, opts_domif_getlink, info_domif_getlink, 0}, + {"domiflist", cmdDomiflist, opts_domiflist, info_domiflist, 0}, + {"domifstat", cmdDomIfstat, opts_domifstat, info_domifstat, 0}, + {"dominfo", cmdDominfo, opts_dominfo, info_dominfo, 0}, + {"dommemstat", cmdDomMemStat, opts_dommemstat, info_dommemstat, 0}, + {"domstate", cmdDomstate, opts_domstate, info_domstate, 0}, + {"list", cmdList, opts_list, info_list, 0}, + {NULL, NULL, NULL, NULL, 0} +}; + +static const vshCmdDef storagePoolCmds[] = { + {"find-storage-pool-sources-as", cmdPoolDiscoverSourcesAs, + opts_find_storage_pool_sources_as, info_find_storage_pool_sources_as, 0}, + {"find-storage-pool-sources", cmdPoolDiscoverSources, + opts_find_storage_pool_sources, info_find_storage_pool_sources, 0}, + {"pool-autostart", cmdPoolAutostart, opts_pool_autostart, + info_pool_autostart, 0}, + {"pool-build", cmdPoolBuild, opts_pool_build, info_pool_build, 0}, + {"pool-create-as", cmdPoolCreateAs, opts_pool_X_as, info_pool_create_as, 0}, + {"pool-create", cmdPoolCreate, opts_pool_create, info_pool_create, 0}, + {"pool-define-as", cmdPoolDefineAs, opts_pool_X_as, info_pool_define_as, 0}, + {"pool-define", cmdPoolDefine, opts_pool_define, info_pool_define, 0}, + {"pool-delete", cmdPoolDelete, opts_pool_delete, info_pool_delete, 0}, + {"pool-destroy", cmdPoolDestroy, opts_pool_destroy, info_pool_destroy, 0}, + {"pool-dumpxml", cmdPoolDumpXML, opts_pool_dumpxml, info_pool_dumpxml, 0}, + {"pool-edit", cmdPoolEdit, opts_pool_edit, info_pool_edit, 0}, + {"pool-info", cmdPoolInfo, opts_pool_info, info_pool_info, 0}, + {"pool-list", cmdPoolList, opts_pool_list, info_pool_list, 0}, + {"pool-name", cmdPoolName, opts_pool_name, info_pool_name, 0}, + {"pool-refresh", cmdPoolRefresh, opts_pool_refresh, info_pool_refresh, 0}, + {"pool-start", cmdPoolStart, opts_pool_start, info_pool_start, 0}, + {"pool-undefine", cmdPoolUndefine, opts_pool_undefine, + info_pool_undefine, 0}, + {"pool-uuid", cmdPoolUuid, opts_pool_uuid, info_pool_uuid, 0}, + {NULL, NULL, NULL, NULL, 0} +}; + +static const vshCmdDef storageVolCmds[] = { + {"vol-clone", cmdVolClone, opts_vol_clone, info_vol_clone, 0}, + {"vol-create-as", cmdVolCreateAs, opts_vol_create_as, + info_vol_create_as, 0}, + {"vol-create", cmdVolCreate, opts_vol_create, info_vol_create, 0}, + {"vol-create-from", cmdVolCreateFrom, opts_vol_create_from, + info_vol_create_from, 0}, + {"vol-delete", cmdVolDelete, opts_vol_delete, info_vol_delete, 0}, + {"vol-download", cmdVolDownload, opts_vol_download, info_vol_download, 0}, + {"vol-dumpxml", cmdVolDumpXML, opts_vol_dumpxml, info_vol_dumpxml, 0}, + {"vol-info", cmdVolInfo, opts_vol_info, info_vol_info, 0}, + {"vol-key", cmdVolKey, opts_vol_key, info_vol_key, 0}, + {"vol-list", cmdVolList, opts_vol_list, info_vol_list, 0}, + {"vol-name", cmdVolName, opts_vol_name, info_vol_name, 0}, + {"vol-path", cmdVolPath, opts_vol_path, info_vol_path, 0}, + {"vol-pool", cmdVolPool, opts_vol_pool, info_vol_pool, 0}, + {"vol-resize", cmdVolResize, opts_vol_resize, info_vol_resize, 0}, + {"vol-upload", cmdVolUpload, opts_vol_upload, info_vol_upload, 0}, + {"vol-wipe", cmdVolWipe, opts_vol_wipe, info_vol_wipe, 0}, + {NULL, NULL, NULL, NULL, 0} +}; + +static const vshCmdDef networkCmds[] = { + {"net-autostart", cmdNetworkAutostart, opts_network_autostart, + info_network_autostart, 0}, + {"net-create", cmdNetworkCreate, opts_network_create, + info_network_create, 0}, + {"net-define", cmdNetworkDefine, opts_network_define, + info_network_define, 0}, + {"net-destroy", cmdNetworkDestroy, opts_network_destroy, + info_network_destroy, 0}, + {"net-dumpxml", cmdNetworkDumpXML, opts_network_dumpxml, + info_network_dumpxml, 0}, + {"net-edit", cmdNetworkEdit, opts_network_edit, info_network_edit, 0}, + {"net-info", cmdNetworkInfo, opts_network_info, info_network_info, 0}, + {"net-list", cmdNetworkList, opts_network_list, info_network_list, 0}, + {"net-name", cmdNetworkName, opts_network_name, info_network_name, 0}, + {"net-start", cmdNetworkStart, opts_network_start, info_network_start, 0}, + {"net-undefine", cmdNetworkUndefine, opts_network_undefine, + info_network_undefine, 0}, + {"net-uuid", cmdNetworkUuid, opts_network_uuid, info_network_uuid, 0}, + {NULL, NULL, NULL, NULL, 0} +}; + +static const vshCmdDef nodedevCmds[] = { + {"nodedev-create", cmdNodeDeviceCreate, opts_node_device_create, + info_node_device_create, 0}, + {"nodedev-destroy", cmdNodeDeviceDestroy, opts_node_device_destroy, + info_node_device_destroy, 0}, + {"nodedev-detach", cmdNodeDeviceDetach, opts_node_device_detach, + info_node_device_detach, 0}, + {"nodedev-dettach", cmdNodeDeviceDetach, opts_node_device_detach, + info_node_device_detach, VSH_CMD_FLAG_ALIAS}, + {"nodedev-dumpxml", cmdNodeDeviceDumpXML, opts_node_device_dumpxml, + info_node_device_dumpxml, 0}, + {"nodedev-list", cmdNodeListDevices, opts_node_list_devices, + info_node_list_devices, 0}, + {"nodedev-reattach", cmdNodeDeviceReAttach, opts_node_device_reattach, + info_node_device_reattach, 0}, + {"nodedev-reset", cmdNodeDeviceReset, opts_node_device_reset, + info_node_device_reset, 0}, + {NULL, NULL, NULL, NULL, 0} +}; + +static const vshCmdDef ifaceCmds[] = { + {"iface-begin", cmdInterfaceBegin, opts_interface_begin, + info_interface_begin, 0}, + {"iface-bridge", cmdInterfaceBridge, opts_interface_bridge, + info_interface_bridge, 0}, + {"iface-commit", cmdInterfaceCommit, opts_interface_commit, + info_interface_commit, 0}, + {"iface-define", cmdInterfaceDefine, opts_interface_define, + info_interface_define, 0}, + {"iface-destroy", cmdInterfaceDestroy, opts_interface_destroy, + info_interface_destroy, 0}, + {"iface-dumpxml", cmdInterfaceDumpXML, opts_interface_dumpxml, + info_interface_dumpxml, 0}, + {"iface-edit", cmdInterfaceEdit, opts_interface_edit, + info_interface_edit, 0}, + {"iface-list", cmdInterfaceList, opts_interface_list, + info_interface_list, 0}, + {"iface-mac", cmdInterfaceMAC, opts_interface_mac, + info_interface_mac, 0}, + {"iface-name", cmdInterfaceName, opts_interface_name, + info_interface_name, 0}, + {"iface-rollback", cmdInterfaceRollback, opts_interface_rollback, + info_interface_rollback, 0}, + {"iface-start", cmdInterfaceStart, opts_interface_start, + info_interface_start, 0}, + {"iface-unbridge", cmdInterfaceUnbridge, opts_interface_unbridge, + info_interface_unbridge, 0}, + {"iface-undefine", cmdInterfaceUndefine, opts_interface_undefine, + info_interface_undefine, 0}, + {NULL, NULL, NULL, NULL, 0} +};
-static bool -vshAllowedEscapeChar(char c) -{ - /* Allowed escape characters: - * a-z A-Z @ [ \ ] ^ _ - */ - return ('a' <= c && c <= 'z') || - ('@' <= c && c <= '_'); -} +static const vshCmdDef nwfilterCmds[] = { + {"nwfilter-define", cmdNWFilterDefine, opts_nwfilter_define, + info_nwfilter_define, 0}, + {"nwfilter-dumpxml", cmdNWFilterDumpXML, opts_nwfilter_dumpxml, + info_nwfilter_dumpxml, 0}, + {"nwfilter-edit", cmdNWFilterEdit, opts_nwfilter_edit, + info_nwfilter_edit, 0}, + {"nwfilter-list", cmdNWFilterList, opts_nwfilter_list, + info_nwfilter_list, 0}, + {"nwfilter-undefine", cmdNWFilterUndefine, opts_nwfilter_undefine, + info_nwfilter_undefine, 0}, + {NULL, NULL, NULL, NULL, 0} +};
-/* - * argv[]: virsh [options] [command] - * - */ -static bool -vshParseArgv(vshControl *ctl, int argc, char **argv) -{ - int arg, len; - struct option opt[] = { - {"debug", required_argument, NULL, 'd'}, - {"help", no_argument, NULL, 'h'}, - {"quiet", no_argument, NULL, 'q'}, - {"timing", no_argument, NULL, 't'}, - {"version", optional_argument, NULL, 'v'}, - {"connect", required_argument, NULL, 'c'}, - {"readonly", no_argument, NULL, 'r'}, - {"log", required_argument, NULL, 'l'}, - {"escape", required_argument, NULL, 'e'}, - {NULL, 0, NULL, 0} - }; +static const vshCmdDef secretCmds[] = { + {"secret-define", cmdSecretDefine, opts_secret_define, + info_secret_define, 0}, + {"secret-dumpxml", cmdSecretDumpXML, opts_secret_dumpxml, + info_secret_dumpxml, 0}, + {"secret-get-value", cmdSecretGetValue, opts_secret_get_value, + info_secret_get_value, 0}, + {"secret-list", cmdSecretList, NULL, info_secret_list, 0}, + {"secret-set-value", cmdSecretSetValue, opts_secret_set_value, + info_secret_set_value, 0}, + {"secret-undefine", cmdSecretUndefine, opts_secret_undefine, + info_secret_undefine, 0}, + {NULL, NULL, NULL, NULL, 0} +};
- /* Standard (non-command) options. The leading + ensures that no - * argument reordering takes place, so that command options are - * not confused with top-level virsh options. */ - while ((arg = getopt_long(argc, argv, "+d:hqtc:vVrl:e:", opt, NULL)) != -1) { - switch (arg) { - case 'd': - if (virStrToLong_i(optarg, NULL, 10, &ctl->debug) < 0) { - vshError(ctl, "%s", _("option -d takes a numeric argument")); - exit(EXIT_FAILURE); - } - break; - case 'h': - vshUsage(); - exit(EXIT_SUCCESS); - break; - case 'q': - ctl->quiet = true; - break; - case 't': - ctl->timing = true; - break; - case 'c': - ctl->name = vshStrdup(ctl, optarg); - break; - case 'v': - if (STRNEQ_NULLABLE(optarg, "long")) { - puts(VERSION); - exit(EXIT_SUCCESS); - } - /* fall through */ - case 'V': - vshShowVersion(ctl); - exit(EXIT_SUCCESS); - case 'r': - ctl->readonly = true; - break; - case 'l': - ctl->logfile = vshStrdup(ctl, optarg); - break; - case 'e': - len = strlen(optarg); +static const vshCmdDef virshCmds[] = { + {"cd", cmdCd, opts_cd, info_cd, VSH_CMD_FLAG_NOCONNECT}, + {"echo", cmdEcho, opts_echo, info_echo, VSH_CMD_FLAG_NOCONNECT}, + {"exit", cmdQuit, NULL, info_quit, VSH_CMD_FLAG_NOCONNECT}, + {"help", cmdHelp, opts_help, info_help, VSH_CMD_FLAG_NOCONNECT}, + {"pwd", cmdPwd, NULL, info_pwd, VSH_CMD_FLAG_NOCONNECT}, + {"quit", cmdQuit, NULL, info_quit, VSH_CMD_FLAG_NOCONNECT}, + {NULL, NULL, NULL, NULL, 0} +};
- if ((len == 2 && *optarg == '^' && - vshAllowedEscapeChar(optarg[1])) || - (len == 1 && *optarg != '^')) { - ctl->escapeChar = optarg; - } else { - vshError(ctl, _("Invalid string '%s' for escape sequence"), - optarg); - exit(EXIT_FAILURE); - } - break; - default: - vshError(ctl, _("unsupported option '-%c'. See --help."), arg); - exit(EXIT_FAILURE); - } - } +static const vshCmdDef snapshotCmds[] = { + {"snapshot-create", cmdSnapshotCreate, opts_snapshot_create, + info_snapshot_create, 0}, + {"snapshot-create-as", cmdSnapshotCreateAs, opts_snapshot_create_as, + info_snapshot_create_as, 0}, + {"snapshot-current", cmdSnapshotCurrent, opts_snapshot_current, + info_snapshot_current, 0}, + {"snapshot-delete", cmdSnapshotDelete, opts_snapshot_delete, + info_snapshot_delete, 0}, + {"snapshot-dumpxml", cmdSnapshotDumpXML, opts_snapshot_dumpxml, + info_snapshot_dumpxml, 0}, + {"snapshot-edit", cmdSnapshotEdit, opts_snapshot_edit, + info_snapshot_edit, 0}, + {"snapshot-info", cmdSnapshotInfo, opts_snapshot_info, + info_snapshot_info, 0}, + {"snapshot-list", cmdSnapshotList, opts_snapshot_list, + info_snapshot_list, 0}, + {"snapshot-parent", cmdSnapshotParent, opts_snapshot_parent, + info_snapshot_parent, 0}, + {"snapshot-revert", cmdDomainSnapshotRevert, opts_snapshot_revert, + info_snapshot_revert, 0}, + {NULL, NULL, NULL, NULL, 0} +};
- if (argc > optind) { - /* parse command */ - ctl->imode = false; - if (argc - optind == 1) { - vshDebug(ctl, VSH_ERR_INFO, "commands: \"%s\"\n", argv[optind]); - return vshCommandStringParse(ctl, argv[optind]); - } else { - return vshCommandArgvParse(ctl, argc - optind, argv + optind); - } - } - return true; -} +static const vshCmdDef hostAndHypervisorCmds[] = { + {"capabilities", cmdCapabilities, NULL, info_capabilities, 0}, + {"connect", cmdConnect, opts_connect, info_connect, + VSH_CMD_FLAG_NOCONNECT}, + {"freecell", cmdFreecell, opts_freecell, info_freecell, 0}, + {"hostname", cmdHostname, NULL, info_hostname, 0}, + {"nodecpustats", cmdNodeCpuStats, opts_node_cpustats, info_nodecpustats, 0}, + {"nodeinfo", cmdNodeinfo, NULL, info_nodeinfo, 0}, + {"nodememstats", cmdNodeMemStats, opts_node_memstats, info_nodememstats, 0}, + {"nodesuspend", cmdNodeSuspend, opts_node_suspend, info_nodesuspend, 0}, + {"qemu-attach", cmdQemuAttach, opts_qemu_attach, info_qemu_attach, 0}, + {"qemu-monitor-command", cmdQemuMonitorCommand, opts_qemu_monitor_command, + info_qemu_monitor_command, 0}, + {"sysinfo", cmdSysinfo, NULL, info_sysinfo, 0}, + {"uri", cmdURI, NULL, info_uri, 0}, + {"version", cmdVersion, opts_version, info_version, 0}, + {NULL, NULL, NULL, NULL, 0} +}; + +static const vshCmdGrp cmdGroups[] = { + {VSH_CMD_GRP_DOM_MANAGEMENT, "domain", domManagementCmds}, + {VSH_CMD_GRP_DOM_MONITORING, "monitor", domMonitoringCmds}, + {VSH_CMD_GRP_HOST_AND_HV, "host", hostAndHypervisorCmds}, + {VSH_CMD_GRP_IFACE, "interface", ifaceCmds}, + {VSH_CMD_GRP_NWFILTER, "filter", nwfilterCmds}, + {VSH_CMD_GRP_NETWORK, "network", networkCmds}, + {VSH_CMD_GRP_NODEDEV, "nodedev", nodedevCmds}, + {VSH_CMD_GRP_SECRET, "secret", secretCmds}, + {VSH_CMD_GRP_SNAPSHOT, "snapshot", snapshotCmds}, + {VSH_CMD_GRP_STORAGE_POOL, "pool", storagePoolCmds}, + {VSH_CMD_GRP_STORAGE_VOL, "volume", storageVolCmds}, + {VSH_CMD_GRP_VIRSH, "virsh", virshCmds}, + {NULL, NULL, NULL} +};
int main(int argc, char **argv)
Looks clean and should not make any problems, ACK. Martin

This splits commands commands to monitor domain status into virsh-domain-monitor.c. The helpers not for common use are moved too. Standard copyright is added. * tools/virsh.c: Remove commands for domain monitoring group and a few helpers ( vshDomainIOErrorToString, vshGetDomainDescription, vshDomainControlStateToString, vshDomainStateToString) not for common use. * tools/virsh-domain-monitor.c: New file, filled with commands of domain monitor group. --- tools/virsh-domain-monitor.c | 1685 +++++++++++++++++++++++++++++++++++++ tools/virsh.c | 1904 +++--------------------------------------- 2 files changed, 1807 insertions(+), 1782 deletions(-) create mode 100644 tools/virsh-domain-monitor.c diff --git a/tools/virsh-domain-monitor.c b/tools/virsh-domain-monitor.c new file mode 100644 index 0000000..1a61f62 --- /dev/null +++ b/tools/virsh-domain-monitor.c @@ -0,0 +1,1685 @@ +/* + * virsh-domain.c: Commands to monitor domain status + * + * Copyright (C) 2005, 2007-2012 Red Hat, Inc + * + * 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 + * License along with this library; If not, see + * <http://www.gnu.org/licenses/>. + * + * Daniel Veillard <veillard@redhat.com> + * Karel Zak <kzak@redhat.com> + * Daniel P. Berrange <berrange@redhat.com> + * + */ + +static const char * +vshDomainIOErrorToString(int error) +{ + switch ((virDomainDiskErrorCode) error) { + case VIR_DOMAIN_DISK_ERROR_NONE: + return _("no error"); + case VIR_DOMAIN_DISK_ERROR_UNSPEC: + return _("unspecified error"); + case VIR_DOMAIN_DISK_ERROR_NO_SPACE: + return _("no space"); + case VIR_DOMAIN_DISK_ERROR_LAST: + ; + } + + return _("unknown error"); +} + +/* extract description or title from domain xml */ +static char * +vshGetDomainDescription(vshControl *ctl, virDomainPtr dom, bool title, + unsigned int flags) +{ + char *desc = NULL; + char *domxml = NULL; + virErrorPtr err = NULL; + xmlDocPtr doc = NULL; + xmlXPathContextPtr ctxt = NULL; + int type; + + if (title) + type = VIR_DOMAIN_METADATA_TITLE; + else + type = VIR_DOMAIN_METADATA_DESCRIPTION; + + if ((desc = virDomainGetMetadata(dom, type, NULL, flags))) { + return desc; + } else { + err = virGetLastError(); + + if (err && err->code == VIR_ERR_NO_DOMAIN_METADATA) { + desc = vshStrdup(ctl, ""); + virResetLastError(); + return desc; + } + + if (err && err->code != VIR_ERR_NO_SUPPORT) + return desc; + } + + /* fall back to xml */ + /* get domain's xml description and extract the title/description */ + if (!(domxml = virDomainGetXMLDesc(dom, flags))) { + vshError(ctl, "%s", _("Failed to retrieve domain XML")); + goto cleanup; + } + doc = virXMLParseStringCtxt(domxml, _("(domain_definition)"), &ctxt); + if (!doc) { + vshError(ctl, "%s", _("Couldn't parse domain XML")); + goto cleanup; + } + if (title) + desc = virXPathString("string(./title[1])", ctxt); + else + desc = virXPathString("string(./description[1])", ctxt); + + if (!desc) + desc = vshStrdup(ctl, ""); + +cleanup: + VIR_FREE(domxml); + xmlXPathFreeContext(ctxt); + xmlFreeDoc(doc); + + return desc; +} +static const char * +vshDomainControlStateToString(int state) +{ + switch ((virDomainControlState) state) { + case VIR_DOMAIN_CONTROL_OK: + return N_("ok"); + case VIR_DOMAIN_CONTROL_JOB: + return N_("background job"); + case VIR_DOMAIN_CONTROL_OCCUPIED: + return N_("occupied"); + case VIR_DOMAIN_CONTROL_ERROR: + return N_("error"); + default: + ; + } + + return N_("unknown"); +} + +static const char * +vshDomainStateToString(int state) +{ + /* Can't use virDomainStateTypeToString, because we want to mark + * * strings for translation. */ + switch ((virDomainState) state) { + case VIR_DOMAIN_RUNNING: + return N_("running"); + case VIR_DOMAIN_BLOCKED: + return N_("idle"); + case VIR_DOMAIN_PAUSED: + return N_("paused"); + case VIR_DOMAIN_SHUTDOWN: + return N_("in shutdown"); + case VIR_DOMAIN_SHUTOFF: + return N_("shut off"); + case VIR_DOMAIN_CRASHED: + return N_("crashed"); + case VIR_DOMAIN_PMSUSPENDED: + return N_("pmsuspended"); + case VIR_DOMAIN_NOSTATE: + default: + ;/*FALLTHROUGH*/ + } + return N_("no state"); /* = dom0 state */ +} + +static const char * +vshDomainStateReasonToString(int state, int reason) +{ + switch ((virDomainState) state) { + case VIR_DOMAIN_NOSTATE: + switch ((virDomainNostateReason) reason) { + case VIR_DOMAIN_NOSTATE_UNKNOWN: + case VIR_DOMAIN_NOSTATE_LAST: + ; + } + break; + + case VIR_DOMAIN_RUNNING: + switch ((virDomainRunningReason) reason) { + case VIR_DOMAIN_RUNNING_BOOTED: + return N_("booted"); + case VIR_DOMAIN_RUNNING_MIGRATED: + return N_("migrated"); + case VIR_DOMAIN_RUNNING_RESTORED: + return N_("restored"); + case VIR_DOMAIN_RUNNING_FROM_SNAPSHOT: + return N_("from snapshot"); + case VIR_DOMAIN_RUNNING_UNPAUSED: + return N_("unpaused"); + case VIR_DOMAIN_RUNNING_MIGRATION_CANCELED: + return N_("migration canceled"); + case VIR_DOMAIN_RUNNING_SAVE_CANCELED: + return N_("save canceled"); + case VIR_DOMAIN_RUNNING_WAKEUP: + return N_("event wakeup"); + case VIR_DOMAIN_RUNNING_UNKNOWN: + case VIR_DOMAIN_RUNNING_LAST: + ; + } + break; + + case VIR_DOMAIN_BLOCKED: + switch ((virDomainBlockedReason) reason) { + case VIR_DOMAIN_BLOCKED_UNKNOWN: + case VIR_DOMAIN_BLOCKED_LAST: + ; + } + break; + + case VIR_DOMAIN_PAUSED: + switch ((virDomainPausedReason) reason) { + case VIR_DOMAIN_PAUSED_USER: + return N_("user"); + case VIR_DOMAIN_PAUSED_MIGRATION: + return N_("migrating"); + case VIR_DOMAIN_PAUSED_SAVE: + return N_("saving"); + case VIR_DOMAIN_PAUSED_DUMP: + return N_("dumping"); + case VIR_DOMAIN_PAUSED_IOERROR: + return N_("I/O error"); + case VIR_DOMAIN_PAUSED_WATCHDOG: + return N_("watchdog"); + case VIR_DOMAIN_PAUSED_FROM_SNAPSHOT: + return N_("from snapshot"); + case VIR_DOMAIN_PAUSED_SHUTTING_DOWN: + return N_("shutting down"); + case VIR_DOMAIN_PAUSED_UNKNOWN: + case VIR_DOMAIN_PAUSED_LAST: + ; + } + break; + + case VIR_DOMAIN_SHUTDOWN: + switch ((virDomainShutdownReason) reason) { + case VIR_DOMAIN_SHUTDOWN_USER: + return N_("user"); + case VIR_DOMAIN_SHUTDOWN_UNKNOWN: + case VIR_DOMAIN_SHUTDOWN_LAST: + ; + } + break; + + case VIR_DOMAIN_SHUTOFF: + switch ((virDomainShutoffReason) reason) { + case VIR_DOMAIN_SHUTOFF_SHUTDOWN: + return N_("shutdown"); + case VIR_DOMAIN_SHUTOFF_DESTROYED: + return N_("destroyed"); + case VIR_DOMAIN_SHUTOFF_CRASHED: + return N_("crashed"); + case VIR_DOMAIN_SHUTOFF_MIGRATED: + return N_("migrated"); + case VIR_DOMAIN_SHUTOFF_SAVED: + return N_("saved"); + case VIR_DOMAIN_SHUTOFF_FAILED: + return N_("failed"); + case VIR_DOMAIN_SHUTOFF_FROM_SNAPSHOT: + return N_("from snapshot"); + case VIR_DOMAIN_SHUTOFF_UNKNOWN: + case VIR_DOMAIN_SHUTOFF_LAST: + ; + } + break; + + case VIR_DOMAIN_CRASHED: + switch ((virDomainCrashedReason) reason) { + case VIR_DOMAIN_CRASHED_UNKNOWN: + case VIR_DOMAIN_CRASHED_LAST: + ; + } + break; + + case VIR_DOMAIN_PMSUSPENDED: + switch ((virDomainPMSuspendedReason) reason) { + case VIR_DOMAIN_PMSUSPENDED_UNKNOWN: + case VIR_DOMAIN_PMSUSPENDED_LAST: + ; + } + break; + + case VIR_DOMAIN_LAST: + ; + } + + return N_("unknown"); +} + +/* + * "dommemstats" command + */ +static const vshCmdInfo info_dommemstat[] = { + {"help", N_("get memory statistics for a domain")}, + {"desc", N_("Get memory statistics for a running domain.")}, + {NULL,NULL} +}; + +static const vshCmdOptDef opts_dommemstat[] = { + {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdDomMemStat(vshControl *ctl, const vshCmd *cmd) +{ + virDomainPtr dom; + const char *name; + struct _virDomainMemoryStat stats[VIR_DOMAIN_MEMORY_STAT_NR]; + unsigned int nr_stats, i; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(dom = vshCommandOptDomain(ctl, cmd, &name))) + return false; + + nr_stats = virDomainMemoryStats(dom, stats, VIR_DOMAIN_MEMORY_STAT_NR, 0); + if (nr_stats == -1) { + vshError(ctl, _("Failed to get memory statistics for domain %s"), name); + virDomainFree(dom); + return false; + } + + for (i = 0; i < nr_stats; i++) { + if (stats[i].tag == VIR_DOMAIN_MEMORY_STAT_SWAP_IN) + vshPrint(ctl, "swap_in %llu\n", stats[i].val); + if (stats[i].tag == VIR_DOMAIN_MEMORY_STAT_SWAP_OUT) + vshPrint(ctl, "swap_out %llu\n", stats[i].val); + if (stats[i].tag == VIR_DOMAIN_MEMORY_STAT_MAJOR_FAULT) + vshPrint(ctl, "major_fault %llu\n", stats[i].val); + if (stats[i].tag == VIR_DOMAIN_MEMORY_STAT_MINOR_FAULT) + vshPrint(ctl, "minor_fault %llu\n", stats[i].val); + if (stats[i].tag == VIR_DOMAIN_MEMORY_STAT_UNUSED) + vshPrint(ctl, "unused %llu\n", stats[i].val); + if (stats[i].tag == VIR_DOMAIN_MEMORY_STAT_AVAILABLE) + vshPrint(ctl, "available %llu\n", stats[i].val); + if (stats[i].tag == VIR_DOMAIN_MEMORY_STAT_ACTUAL_BALLOON) + vshPrint(ctl, "actual %llu\n", stats[i].val); + if (stats[i].tag == VIR_DOMAIN_MEMORY_STAT_RSS) + vshPrint(ctl, "rss %llu\n", stats[i].val); + } + + virDomainFree(dom); + return true; +} + +/* + * "domblkinfo" command + */ +static const vshCmdInfo info_domblkinfo[] = { + {"help", N_("domain block device size information")}, + {"desc", N_("Get block device size info for a domain.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_domblkinfo[] = { + {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, + {"device", VSH_OT_DATA, VSH_OFLAG_REQ, N_("block device")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdDomblkinfo(vshControl *ctl, const vshCmd *cmd) +{ + virDomainBlockInfo info; + virDomainPtr dom; + bool ret = true; + const char *device = NULL; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(dom = vshCommandOptDomain(ctl, cmd, NULL))) + return false; + + if (vshCommandOptString(cmd, "device", &device) <= 0) { + virDomainFree(dom); + return false; + } + + if (virDomainGetBlockInfo(dom, device, &info, 0) < 0) { + virDomainFree(dom); + return false; + } + + vshPrint(ctl, "%-15s %llu\n", _("Capacity:"), info.capacity); + vshPrint(ctl, "%-15s %llu\n", _("Allocation:"), info.allocation); + vshPrint(ctl, "%-15s %llu\n", _("Physical:"), info.physical); + + virDomainFree(dom); + return ret; +} + +/* + * "domblklist" command + */ +static const vshCmdInfo info_domblklist[] = { + {"help", N_("list all domain blocks")}, + {"desc", N_("Get the summary of block devices for a domain.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_domblklist[] = { + {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, + {"inactive", VSH_OT_BOOL, 0, + N_("get inactive rather than running configuration")}, + {"details", VSH_OT_BOOL, 0, + N_("additionally display the type and device value")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdDomblklist(vshControl *ctl, const vshCmd *cmd) +{ + virDomainPtr dom; + bool ret = false; + unsigned int flags = 0; + char *xml = NULL; + xmlDocPtr xmldoc = NULL; + xmlXPathContextPtr ctxt = NULL; + int ndisks; + xmlNodePtr *disks = NULL; + int i; + bool details = false; + + if (vshCommandOptBool(cmd, "inactive")) + flags |= VIR_DOMAIN_XML_INACTIVE; + + details = vshCommandOptBool(cmd, "details"); + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(dom = vshCommandOptDomain(ctl, cmd, NULL))) + return false; + + xml = virDomainGetXMLDesc(dom, flags); + if (!xml) + goto cleanup; + + xmldoc = virXMLParseStringCtxt(xml, _("(domain_definition)"), &ctxt); + if (!xmldoc) + goto cleanup; + + ndisks = virXPathNodeSet("./devices/disk", ctxt, &disks); + if (ndisks < 0) + goto cleanup; + + if (details) + vshPrint(ctl, "%-10s %-10s %-10s %s\n", _("Type"), + _("Device"), _("Target"), _("Source")); + else + vshPrint(ctl, "%-10s %s\n", _("Target"), _("Source")); + + vshPrint(ctl, "------------------------------------------------\n"); + + for (i = 0; i < ndisks; i++) { + char *type; + char *device; + char *target; + char *source; + + ctxt->node = disks[i]; + + if (details) { + type = virXPathString("string(./@type)", ctxt); + device = virXPathString("string(./@device)", ctxt); + } + + target = virXPathString("string(./target/@dev)", ctxt); + if (!target) { + vshError(ctl, "unable to query block list"); + goto cleanup; + } + source = virXPathString("string(./source/@file" + "|./source/@dev" + "|./source/@dir" + "|./source/@name)", ctxt); + if (details) { + vshPrint(ctl, "%-10s %-10s %-10s %s\n", type, device, + target, source ? source : "-"); + VIR_FREE(type); + VIR_FREE(device); + } else { + vshPrint(ctl, "%-10s %s\n", target, source ? source : "-"); + } + + VIR_FREE(target); + VIR_FREE(source); + } + + ret = true; + +cleanup: + VIR_FREE(disks); + virDomainFree(dom); + VIR_FREE(xml); + xmlFreeDoc(xmldoc); + xmlXPathFreeContext(ctxt); + return ret; +} + +/* + * "domiflist" command + */ +static const vshCmdInfo info_domiflist[] = { + {"help", N_("list all domain virtual interfaces")}, + {"desc", N_("Get the summary of virtual interfaces for a domain.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_domiflist[] = { + {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, + {"inactive", VSH_OT_BOOL, 0, + N_("get inactive rather than running configuration")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdDomiflist(vshControl *ctl, const vshCmd *cmd) +{ + virDomainPtr dom; + bool ret = false; + unsigned int flags = 0; + char *xml = NULL; + xmlDocPtr xmldoc = NULL; + xmlXPathContextPtr ctxt = NULL; + int ninterfaces; + xmlNodePtr *interfaces = NULL; + int i; + + if (vshCommandOptBool(cmd, "inactive")) + flags |= VIR_DOMAIN_XML_INACTIVE; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(dom = vshCommandOptDomain(ctl, cmd, NULL))) + return false; + + xml = virDomainGetXMLDesc(dom, flags); + if (!xml) + goto cleanup; + + xmldoc = virXMLParseStringCtxt(xml, _("(domain_definition)"), &ctxt); + if (!xmldoc) + goto cleanup; + + ninterfaces = virXPathNodeSet("./devices/interface", ctxt, &interfaces); + if (ninterfaces < 0) + goto cleanup; + + vshPrint(ctl, "%-10s %-10s %-10s %-11s %s\n", _("Interface"), _("Type"), + _("Source"), _("Model"), _("MAC")); + vshPrint(ctl, "-------------------------------------------------------\n"); + + for (i = 0; i < ninterfaces; i++) { + char *type = NULL; + char *source = NULL; + char *target = NULL; + char *model = NULL; + char *mac = NULL; + + ctxt->node = interfaces[i]; + type = virXPathString("string(./@type)", ctxt); + + source = virXPathString("string(./source/@bridge" + "|./source/@dev" + "|./source/@network" + "|./source/@name)", ctxt); + + target = virXPathString("string(./target/@dev)", ctxt); + model = virXPathString("string(./model/@type)", ctxt); + mac = virXPathString("string(./mac/@address)", ctxt); + + vshPrint(ctl, "%-10s %-10s %-10s %-11s %-10s\n", + target ? target : "-", + type, + source ? source : "-", + model ? model : "-", + mac ? mac : "-"); + + VIR_FREE(type); + VIR_FREE(source); + VIR_FREE(target); + VIR_FREE(model); + VIR_FREE(mac); + } + + ret = true; + +cleanup: + VIR_FREE(interfaces); + virDomainFree(dom); + VIR_FREE(xml); + xmlFreeDoc(xmldoc); + xmlXPathFreeContext(ctxt); + return ret; +} + +/* + * "domif-getlink" command + */ +static const vshCmdInfo info_domif_getlink[] = { + {"help", N_("get link state of a virtual interface")}, + {"desc", N_("Get link state of a domain's virtual interface.")}, + {NULL,NULL} +}; + +static const vshCmdOptDef opts_domif_getlink[] = { + {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, + {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, N_("interface device (MAC Address)")}, + {"persistent", VSH_OT_ALIAS, 0, "config"}, + {"config", VSH_OT_BOOL, 0, N_("Get persistent interface state")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdDomIfGetLink(vshControl *ctl, const vshCmd *cmd) +{ + virDomainPtr dom; + const char *iface = NULL; + int flags = 0; + char *state = NULL; + char *value = NULL; + virMacAddr macaddr; + const char *element; + const char *attr; + bool ret = false; + int i; + char *desc; + xmlDocPtr xml = NULL; + xmlXPathContextPtr ctxt = NULL; + xmlNodePtr cur = NULL; + xmlXPathObjectPtr obj = NULL; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(dom = vshCommandOptDomain(ctl, cmd, NULL))) + return false; + + if (vshCommandOptString(cmd, "interface", &iface) <= 0) { + virDomainFree(dom); + return false; + } + + if (vshCommandOptBool(cmd, "config")) + flags = VIR_DOMAIN_XML_INACTIVE; + + desc = virDomainGetXMLDesc(dom, flags); + if (desc == NULL) { + vshError(ctl, _("Failed to get domain description xml")); + goto cleanup; + } + + xml = virXMLParseStringCtxt(desc, _("(domain_definition)"), &ctxt); + VIR_FREE(desc); + if (!xml) { + vshError(ctl, _("Failed to parse domain description xml")); + goto cleanup; + } + + obj = xmlXPathEval(BAD_CAST "/domain/devices/interface", ctxt); + if (obj == NULL || obj->type != XPATH_NODESET || + obj->nodesetval == NULL || obj->nodesetval->nodeNr == 0) { + vshError(ctl, _("Failed to extract interface information or no interfaces found")); + goto cleanup; + } + + if (virMacAddrParse(iface, &macaddr) == 0) { + element = "mac"; + attr = "address"; + } else { + element = "target"; + attr = "dev"; + } + + /* find interface with matching mac addr */ + for (i = 0; i < obj->nodesetval->nodeNr; i++) { + cur = obj->nodesetval->nodeTab[i]->children; + + while (cur) { + if (cur->type == XML_ELEMENT_NODE && + xmlStrEqual(cur->name, BAD_CAST element)) { + + value = virXMLPropString(cur, attr); + + if (STRCASEEQ(value, iface)) { + VIR_FREE(value); + goto hit; + } + VIR_FREE(value); + } + cur = cur->next; + } + } + + vshError(ctl, _("Interface (%s: %s) not found."), element, iface); + goto cleanup; + +hit: + cur = obj->nodesetval->nodeTab[i]->children; + while (cur) { + if (cur->type == XML_ELEMENT_NODE && + xmlStrEqual(cur->name, BAD_CAST "link")) { + + state = virXMLPropString(cur, "state"); + vshPrint(ctl, "%s %s", iface, state); + VIR_FREE(state); + + goto cleanup; + } + cur = cur->next; + } + + /* attribute not found */ + vshPrint(ctl, "%s default", iface); + + ret = true; +cleanup: + xmlXPathFreeObject(obj); + xmlXPathFreeContext(ctxt); + xmlFreeDoc(xml); + if (dom) + virDomainFree(dom); + + return ret; +} + +/* + * "domcontrol" command + */ +static const vshCmdInfo info_domcontrol[] = { + {"help", N_("domain control interface state")}, + {"desc", N_("Returns state of a control interface to the domain.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_domcontrol[] = { + {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdDomControl(vshControl *ctl, const vshCmd *cmd) +{ + virDomainPtr dom; + bool ret = true; + virDomainControlInfo info; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(dom = vshCommandOptDomain(ctl, cmd, NULL))) + return false; + + if (virDomainGetControlInfo(dom, &info, 0) < 0) { + ret = false; + goto cleanup; + } + + if (info.state != VIR_DOMAIN_CONTROL_OK && + info.state != VIR_DOMAIN_CONTROL_ERROR) { + vshPrint(ctl, "%s (%0.3fs)\n", + _(vshDomainControlStateToString(info.state)), + info.stateTime / 1000.0); + } else { + vshPrint(ctl, "%s\n", + _(vshDomainControlStateToString(info.state))); + } + +cleanup: + virDomainFree(dom); + return ret; +} + +/* + * "domblkstat" command + */ +static const vshCmdInfo info_domblkstat[] = { + {"help", N_("get device block stats for a domain")}, + {"desc", N_("Get device block stats for a running domain. See man page or " + "use --human for explanation of fields")}, + {NULL,NULL} +}; + +static const vshCmdOptDef opts_domblkstat[] = { + {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, + {"device", VSH_OT_DATA, VSH_OFLAG_REQ, N_("block device")}, + {"human", VSH_OT_BOOL, 0, N_("print a more human readable output")}, + {NULL, 0, 0, NULL} +}; + +struct _domblkstat_sequence { + const char *field; /* field name */ + const char *legacy; /* legacy name from previous releases */ + const char *human; /* human-friendly explanation */ +}; + +/* sequence of values for output to honor legacy format from previous + * versions */ +static const struct _domblkstat_sequence domblkstat_output[] = { + { VIR_DOMAIN_BLOCK_STATS_READ_REQ, "rd_req", + N_("number of read operations:") }, /* 0 */ + { VIR_DOMAIN_BLOCK_STATS_READ_BYTES, "rd_bytes", + N_("number of bytes read:") }, /* 1 */ + { VIR_DOMAIN_BLOCK_STATS_WRITE_REQ, "wr_req", + N_("number of write operations:") }, /* 2 */ + { VIR_DOMAIN_BLOCK_STATS_WRITE_BYTES, "wr_bytes", + N_("number of bytes written:") }, /* 3 */ + { VIR_DOMAIN_BLOCK_STATS_ERRS, "errs", + N_("error count:") }, /* 4 */ + { VIR_DOMAIN_BLOCK_STATS_FLUSH_REQ, NULL, + N_("number of flush operations:") }, /* 5 */ + { VIR_DOMAIN_BLOCK_STATS_READ_TOTAL_TIMES, NULL, + N_("total duration of reads (ns):") }, /* 6 */ + { VIR_DOMAIN_BLOCK_STATS_WRITE_TOTAL_TIMES, NULL, + N_("total duration of writes (ns):") }, /* 7 */ + { VIR_DOMAIN_BLOCK_STATS_FLUSH_TOTAL_TIMES, NULL, + N_("total duration of flushes (ns):") }, /* 8 */ + { NULL, NULL, NULL } +}; + +#define DOMBLKSTAT_LEGACY_PRINT(ID, VALUE) \ + if (VALUE >= 0) \ + vshPrint(ctl, "%s %-*s %lld\n", device, \ + human ? 31 : 0, \ + human ? _(domblkstat_output[ID].human) \ + : domblkstat_output[ID].legacy, \ + VALUE); + +static bool +cmdDomblkstat(vshControl *ctl, const vshCmd *cmd) +{ + virDomainPtr dom; + const char *name = NULL, *device = NULL; + struct _virDomainBlockStats stats; + virTypedParameterPtr params = NULL; + virTypedParameterPtr par = NULL; + char *value = NULL; + const char *field = NULL; + int rc, nparams = 0; + int i = 0; + bool ret = false; + bool human = vshCommandOptBool(cmd, "human"); /* human readable output */ + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(dom = vshCommandOptDomain(ctl, cmd, &name))) + return false; + + if (vshCommandOptString(cmd, "device", &device) <= 0) + goto cleanup; + + rc = virDomainBlockStatsFlags(dom, device, NULL, &nparams, 0); + + /* It might fail when virDomainBlockStatsFlags is not + * supported on older libvirt, fallback to use virDomainBlockStats + * then. + */ + if (rc < 0) { + /* try older API if newer is not supported */ + if (last_error->code != VIR_ERR_NO_SUPPORT) + goto cleanup; + + virFreeError(last_error); + last_error = NULL; + + if (virDomainBlockStats(dom, device, &stats, + sizeof(stats)) == -1) { + vshError(ctl, _("Failed to get block stats %s %s"), + name, device); + goto cleanup; + } + + /* human friendly output */ + if (human) { + vshPrint(ctl, N_("Device: %s\n"), device); + device = ""; + } + + DOMBLKSTAT_LEGACY_PRINT(0, stats.rd_req); + DOMBLKSTAT_LEGACY_PRINT(1, stats.rd_bytes); + DOMBLKSTAT_LEGACY_PRINT(2, stats.wr_req); + DOMBLKSTAT_LEGACY_PRINT(3, stats.wr_bytes); + DOMBLKSTAT_LEGACY_PRINT(4, stats.errs); + } else { + params = vshCalloc(ctl, nparams, sizeof(*params)); + + if (virDomainBlockStatsFlags(dom, device, params, &nparams, 0) < 0) { + vshError(ctl, _("Failed to get block stats %s %s"), name, device); + goto cleanup; + } + + /* set for prettier output */ + if (human) { + vshPrint(ctl, N_("Device: %s\n"), device); + device = ""; + } + + /* at first print all known values in desired order */ + for (i = 0; domblkstat_output[i].field != NULL; i++) { + if (!(par = vshFindTypedParamByName(domblkstat_output[i].field, + params, + nparams))) + continue; + + value = vshGetTypedParamValue(ctl, par); + + /* to print other not supported fields, mark the already printed */ + par->field[0] = '\0'; /* set the name to empty string */ + + /* translate into human readable or legacy spelling */ + field = NULL; + if (human) + field = _(domblkstat_output[i].human); + else + field = domblkstat_output[i].legacy; + + /* use the provided spelling if no translation is available */ + if (!field) + field = domblkstat_output[i].field; + + vshPrint(ctl, "%s %-*s %s\n", device, + human ? 31 : 0, field, value); + + VIR_FREE(value); + } + + /* go through the fields again, for remaining fields */ + for (i = 0; i < nparams; i++) { + if (!*params[i].field) + continue; + + value = vshGetTypedParamValue(ctl, params+i); + vshPrint(ctl, "%s %s %s\n", device, params[i].field, value); + VIR_FREE(value); + } + } + + ret = true; + +cleanup: + VIR_FREE(params); + virDomainFree(dom); + return ret; +} +#undef DOMBLKSTAT_LEGACY_PRINT + +/* + * "domifstat" command + */ +static const vshCmdInfo info_domifstat[] = { + {"help", N_("get network interface stats for a domain")}, + {"desc", N_("Get network interface stats for a running domain.")}, + {NULL,NULL} +}; + +static const vshCmdOptDef opts_domifstat[] = { + {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, + {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, N_("interface device")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdDomIfstat(vshControl *ctl, const vshCmd *cmd) +{ + virDomainPtr dom; + const char *name = NULL, *device = NULL; + struct _virDomainInterfaceStats stats; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(dom = vshCommandOptDomain(ctl, cmd, &name))) + return false; + + if (vshCommandOptString(cmd, "interface", &device) <= 0) { + virDomainFree(dom); + return false; + } + + if (virDomainInterfaceStats(dom, device, &stats, sizeof(stats)) == -1) { + vshError(ctl, _("Failed to get interface stats %s %s"), name, device); + virDomainFree(dom); + return false; + } + + if (stats.rx_bytes >= 0) + vshPrint(ctl, "%s rx_bytes %lld\n", device, stats.rx_bytes); + + if (stats.rx_packets >= 0) + vshPrint(ctl, "%s rx_packets %lld\n", device, stats.rx_packets); + + if (stats.rx_errs >= 0) + vshPrint(ctl, "%s rx_errs %lld\n", device, stats.rx_errs); + + if (stats.rx_drop >= 0) + vshPrint(ctl, "%s rx_drop %lld\n", device, stats.rx_drop); + + if (stats.tx_bytes >= 0) + vshPrint(ctl, "%s tx_bytes %lld\n", device, stats.tx_bytes); + + if (stats.tx_packets >= 0) + vshPrint(ctl, "%s tx_packets %lld\n", device, stats.tx_packets); + + if (stats.tx_errs >= 0) + vshPrint(ctl, "%s tx_errs %lld\n", device, stats.tx_errs); + + if (stats.tx_drop >= 0) + vshPrint(ctl, "%s tx_drop %lld\n", device, stats.tx_drop); + + virDomainFree(dom); + return true; +} + +/* + * "domblkerror" command + */ +static const vshCmdInfo info_domblkerror[] = { + {"help", N_("Show errors on block devices")}, + {"desc", N_("Show block device errors")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_domblkerror[] = { + {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id, or uuid")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdDomBlkError(vshControl *ctl, const vshCmd *cmd) +{ + virDomainPtr dom; + virDomainDiskErrorPtr disks = NULL; + unsigned int ndisks; + int i; + int count; + bool ret = false; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(dom = vshCommandOptDomain(ctl, cmd, NULL))) + return false; + + if ((count = virDomainGetDiskErrors(dom, NULL, 0, 0)) < 0) + goto cleanup; + ndisks = count; + + if (ndisks) { + if (VIR_ALLOC_N(disks, ndisks) < 0) + goto cleanup; + + if ((count = virDomainGetDiskErrors(dom, disks, ndisks, 0)) == -1) + goto cleanup; + } + + if (count == 0) { + vshPrint(ctl, _("No errors found\n")); + } else { + for (i = 0; i < count; i++) { + vshPrint(ctl, "%s: %s\n", + disks[i].disk, + vshDomainIOErrorToString(disks[i].error)); + } + } + + ret = true; + +cleanup: + VIR_FREE(disks); + virDomainFree(dom); + return ret; +} + +/* + * "dominfo" command + */ +static const vshCmdInfo info_dominfo[] = { + {"help", N_("domain information")}, + {"desc", N_("Returns basic information about the domain.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_dominfo[] = { + {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdDominfo(vshControl *ctl, const vshCmd *cmd) +{ + virDomainInfo info; + virDomainPtr dom; + virSecurityModel secmodel; + virSecurityLabelPtr seclabel; + int persistent = 0; + bool ret = true; + int autostart; + unsigned int id; + char *str, uuid[VIR_UUID_STRING_BUFLEN]; + int has_managed_save = 0; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(dom = vshCommandOptDomain(ctl, cmd, NULL))) + return false; + + id = virDomainGetID(dom); + if (id == ((unsigned int)-1)) + vshPrint(ctl, "%-15s %s\n", _("Id:"), "-"); + else + vshPrint(ctl, "%-15s %d\n", _("Id:"), id); + vshPrint(ctl, "%-15s %s\n", _("Name:"), virDomainGetName(dom)); + + if (virDomainGetUUIDString(dom, &uuid[0])==0) + vshPrint(ctl, "%-15s %s\n", _("UUID:"), uuid); + + if ((str = virDomainGetOSType(dom))) { + vshPrint(ctl, "%-15s %s\n", _("OS Type:"), str); + VIR_FREE(str); + } + + if (virDomainGetInfo(dom, &info) == 0) { + vshPrint(ctl, "%-15s %s\n", _("State:"), + _(vshDomainStateToString(info.state))); + + vshPrint(ctl, "%-15s %d\n", _("CPU(s):"), info.nrVirtCpu); + + if (info.cpuTime != 0) { + double cpuUsed = info.cpuTime; + + cpuUsed /= 1000000000.0; + + vshPrint(ctl, "%-15s %.1lfs\n", _("CPU time:"), cpuUsed); + } + + if (info.maxMem != UINT_MAX) + vshPrint(ctl, "%-15s %lu KiB\n", _("Max memory:"), + info.maxMem); + else + vshPrint(ctl, "%-15s %s\n", _("Max memory:"), + _("no limit")); + + vshPrint(ctl, "%-15s %lu KiB\n", _("Used memory:"), + info.memory); + + } else { + ret = false; + } + + /* Check and display whether the domain is persistent or not */ + persistent = virDomainIsPersistent(dom); + vshDebug(ctl, VSH_ERR_DEBUG, "Domain persistent flag value: %d\n", + persistent); + if (persistent < 0) + vshPrint(ctl, "%-15s %s\n", _("Persistent:"), _("unknown")); + else + vshPrint(ctl, "%-15s %s\n", _("Persistent:"), persistent ? _("yes") : _("no")); + + /* Check and display whether the domain autostarts or not */ + if (!virDomainGetAutostart(dom, &autostart)) { + vshPrint(ctl, "%-15s %s\n", _("Autostart:"), + autostart ? _("enable") : _("disable") ); + } + + has_managed_save = virDomainHasManagedSaveImage(dom, 0); + if (has_managed_save < 0) + vshPrint(ctl, "%-15s %s\n", _("Managed save:"), _("unknown")); + else + vshPrint(ctl, "%-15s %s\n", _("Managed save:"), + has_managed_save ? _("yes") : _("no")); + + /* Security model and label information */ + memset(&secmodel, 0, sizeof(secmodel)); + if (virNodeGetSecurityModel(ctl->conn, &secmodel) == -1) { + if (last_error->code != VIR_ERR_NO_SUPPORT) { + virDomainFree(dom); + return false; + } else { + virFreeError(last_error); + last_error = NULL; + } + } else { + /* Only print something if a security model is active */ + if (secmodel.model[0] != '\0') { + vshPrint(ctl, "%-15s %s\n", _("Security model:"), secmodel.model); + vshPrint(ctl, "%-15s %s\n", _("Security DOI:"), secmodel.doi); + + /* Security labels are only valid for active domains */ + if (VIR_ALLOC(seclabel) < 0) { + virDomainFree(dom); + return false; + } + + if (virDomainGetSecurityLabel(dom, seclabel) == -1) { + virDomainFree(dom); + VIR_FREE(seclabel); + return false; + } else { + if (seclabel->label[0] != '\0') + vshPrint(ctl, "%-15s %s (%s)\n", _("Security label:"), + seclabel->label, seclabel->enforcing ? "enforcing" : "permissive"); + } + + VIR_FREE(seclabel); + } + } + virDomainFree(dom); + return ret; +} + +/* + * "domstate" command + */ +static const vshCmdInfo info_domstate[] = { + {"help", N_("domain state")}, + {"desc", N_("Returns state about a domain.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_domstate[] = { + {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, + {"reason", VSH_OT_BOOL, 0, N_("also print reason for the state")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdDomstate(vshControl *ctl, const vshCmd *cmd) +{ + virDomainPtr dom; + bool ret = true; + bool showReason = vshCommandOptBool(cmd, "reason"); + int state, reason; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(dom = vshCommandOptDomain(ctl, cmd, NULL))) + return false; + + if ((state = vshDomainState(ctl, dom, &reason)) < 0) { + ret = false; + goto cleanup; + } + + if (showReason) { + vshPrint(ctl, "%s (%s)\n", + _(vshDomainStateToString(state)), + vshDomainStateReasonToString(state, reason)); + } else { + vshPrint(ctl, "%s\n", + _(vshDomainStateToString(state))); + } + +cleanup: + virDomainFree(dom); + return ret; +} + +/* + * "list" command + */ +static const vshCmdInfo info_list[] = { + {"help", N_("list domains")}, + {"desc", N_("Returns list of domains.")}, + {NULL, NULL} +}; + +/* compare domains, pack NULLed ones at the end*/ +static int +vshDomainSorter(const void *a, const void *b) +{ + virDomainPtr *da = (virDomainPtr *) a; + virDomainPtr *db = (virDomainPtr *) b; + unsigned int ida; + unsigned int idb; + unsigned int inactive = (unsigned int) -1; + + if (*da && !*db) + return -1; + + if (!*da) + return *db != NULL; + + ida = virDomainGetID(*da); + idb = virDomainGetID(*db); + + if (ida == inactive && idb == inactive) + return strcasecmp(virDomainGetName(*da), virDomainGetName(*db)); + + if (ida != inactive && idb != inactive) { + if (ida > idb) + return 1; + else if (ida < idb) + return -1; + } + + if (ida != inactive) + return -1; + else + return 1; +} + +struct vshDomainList { + virDomainPtr *domains; + size_t ndomains; +}; +typedef struct vshDomainList *vshDomainListPtr; + +static void +vshDomainListFree(vshDomainListPtr domlist) +{ + int i; + + if (domlist && domlist->domains) { + for (i = 0; i < domlist->ndomains; i++) { + if (domlist->domains[i]) + virDomainFree(domlist->domains[i]); + } + VIR_FREE(domlist->domains); + } + VIR_FREE(domlist); +} + +#define MATCH(FLAG) (flags & (FLAG)) +static vshDomainListPtr +vshDomainListCollect(vshControl *ctl, unsigned int flags) +{ + vshDomainListPtr list = vshMalloc(ctl, sizeof(*list)); + int i; + int ret; + int *ids = NULL; + int nids = 0; + char **names = NULL; + int nnames = 0; + virDomainPtr dom; + bool success = false; + size_t deleted = 0; + int persistent; + int autostart; + int state; + int nsnap; + int mansave; + + /* try the list with flags support (0.9.13 and later) */ + if ((ret = virConnectListAllDomains(ctl->conn, &list->domains, + flags)) >= 0) { + list->ndomains = ret; + goto finished; + } + + /* check if the command is actually supported */ + if (last_error && last_error->code == VIR_ERR_NO_SUPPORT) { + virFreeError(last_error); + last_error = NULL; + goto fallback; + } + + if (last_error && last_error->code == VIR_ERR_INVALID_ARG) { + /* try the new API again but mask non-guaranteed flags */ + unsigned int newflags = flags & (VIR_CONNECT_LIST_DOMAINS_ACTIVE | + VIR_CONNECT_LIST_DOMAINS_INACTIVE); + + virFreeError(last_error); + last_error = NULL; + if ((ret = virConnectListAllDomains(ctl->conn, &list->domains, + newflags)) >= 0) { + list->ndomains = ret; + goto filter; + } + } + + /* there was an error during the first or second call */ + vshError(ctl, "%s", _("Failed to list domains")); + goto cleanup; + + +fallback: + /* fall back to old method (0.9.12 and older) */ + virResetLastError(); + + /* list active domains, if necessary */ + if (!MATCH(VIR_CONNECT_LIST_FILTERS_ACTIVE) || + MATCH(VIR_CONNECT_LIST_DOMAINS_ACTIVE)) { + if ((nids = virConnectNumOfDomains(ctl->conn)) < 0) { + vshError(ctl, "%s", _("Failed to list active domains")); + goto cleanup; + } + + if (nids) { + ids = vshMalloc(ctl, sizeof(int) * nids); + + if ((nids = virConnectListDomains(ctl->conn, ids, nids)) < 0) { + vshError(ctl, "%s", _("Failed to list active domains")); + goto cleanup; + } + } + } + + if (!MATCH(VIR_CONNECT_LIST_FILTERS_ACTIVE) || + MATCH(VIR_CONNECT_LIST_DOMAINS_INACTIVE)) { + if ((nnames = virConnectNumOfDefinedDomains(ctl->conn)) < 0) { + vshError(ctl, "%s", _("Failed to list inactive domains")); + goto cleanup; + } + + if (nnames) { + names = vshMalloc(ctl, sizeof(char *) * nnames); + + if ((nnames = virConnectListDefinedDomains(ctl->conn, names, + nnames)) < 0) { + vshError(ctl, "%s", _("Failed to list inactive domains")); + goto cleanup; + } + } + } + + list->domains = vshMalloc(ctl, sizeof(virDomainPtr) * (nids + nnames)); + list->ndomains = 0; + + /* get active domains */ + for (i = 0; i < nids; i++) { + if (!(dom = virDomainLookupByID(ctl->conn, ids[i]))) + continue; + list->domains[list->ndomains++] = dom; + } + + /* get inactive domains */ + for (i = 0; i < nnames; i++) { + if (!(dom = virDomainLookupByName(ctl->conn, names[i]))) + continue; + list->domains[list->ndomains++] = dom; + } + + /* truncate domains that weren't found */ + deleted = (nids + nnames) - list->ndomains; + +filter: + /* filter list the list if the list was acquired by fallback means */ + for (i = 0; i < list->ndomains; i++) { + dom = list->domains[i]; + + /* persistence filter */ + if (MATCH(VIR_CONNECT_LIST_FILTERS_PERSISTENT)) { + if ((persistent = virDomainIsPersistent(dom)) < 0) { + vshError(ctl, "%s", _("Failed to get domain persistence info")); + goto cleanup; + } + + if (!((MATCH(VIR_CONNECT_LIST_DOMAINS_PERSISTENT) && persistent) || + (MATCH(VIR_CONNECT_LIST_DOMAINS_TRANSIENT) && !persistent))) + goto remove_entry; + } + + /* domain state filter */ + if (MATCH(VIR_CONNECT_LIST_FILTERS_STATE)) { + if (virDomainGetState(dom, &state, NULL, 0) < 0) { + vshError(ctl, "%s", _("Failed to get domain state")); + goto cleanup; + } + + if (!((MATCH(VIR_CONNECT_LIST_DOMAINS_RUNNING) && + state == VIR_DOMAIN_RUNNING) || + (MATCH(VIR_CONNECT_LIST_DOMAINS_PAUSED) && + state == VIR_DOMAIN_PAUSED) || + (MATCH(VIR_CONNECT_LIST_DOMAINS_SHUTOFF) && + state == VIR_DOMAIN_SHUTOFF) || + (MATCH(VIR_CONNECT_LIST_DOMAINS_OTHER) && + (state != VIR_DOMAIN_RUNNING && + state != VIR_DOMAIN_PAUSED && + state != VIR_DOMAIN_SHUTOFF)))) + goto remove_entry; + } + + /* autostart filter */ + if (MATCH(VIR_CONNECT_LIST_FILTERS_AUTOSTART)) { + if (virDomainGetAutostart(dom, &autostart) < 0) { + vshError(ctl, "%s", _("Failed to get domain autostart state")); + goto cleanup; + } + + if (!((MATCH(VIR_CONNECT_LIST_DOMAINS_AUTOSTART) && autostart) || + (MATCH(VIR_CONNECT_LIST_DOMAINS_NO_AUTOSTART) && !autostart))) + goto remove_entry; + } + + /* managed save filter */ + if (MATCH(VIR_CONNECT_LIST_FILTERS_MANAGEDSAVE)) { + if ((mansave = virDomainHasManagedSaveImage(dom, 0)) < 0) { + vshError(ctl, "%s", + _("Failed to check for managed save image")); + goto cleanup; + } + + if (!((MATCH(VIR_CONNECT_LIST_DOMAINS_MANAGEDSAVE) && mansave) || + (MATCH(VIR_CONNECT_LIST_DOMAINS_NO_MANAGEDSAVE) && !mansave))) + goto remove_entry; + } + + /* snapshot filter */ + if (MATCH(VIR_CONNECT_LIST_FILTERS_SNAPSHOT)) { + if ((nsnap = virDomainSnapshotNum(dom, 0)) < 0) { + vshError(ctl, "%s", _("Failed to get snapshot count")); + goto cleanup; + } + if (!((MATCH(VIR_CONNECT_LIST_DOMAINS_HAS_SNAPSHOT) && nsnap > 0) || + (MATCH(VIR_CONNECT_LIST_DOMAINS_NO_SNAPSHOT) && nsnap == 0))) + goto remove_entry; + } + + /* the domain matched all filters, it may stay */ + continue; + +remove_entry: + /* the domain has to be removed as it failed one of the filters */ + virDomainFree(list->domains[i]); + list->domains[i] = NULL; + deleted++; + } + +finished: + /* sort the list */ + if (list->domains && list->ndomains) + qsort(list->domains, list->ndomains, sizeof(*list->domains), + vshDomainSorter); + + /* truncate the list if filter simulation deleted entries */ + if (deleted) + VIR_SHRINK_N(list->domains, list->ndomains, deleted); + + success = true; + +cleanup: + for (i = 0; i < nnames; i++) + VIR_FREE(names[i]); + + if (!success) { + vshDomainListFree(list); + list = NULL; + } + + VIR_FREE(names); + VIR_FREE(ids); + return list; +} +#undef MATCH + +static const vshCmdOptDef opts_list[] = { + {"inactive", VSH_OT_BOOL, 0, N_("list inactive domains")}, + {"all", VSH_OT_BOOL, 0, N_("list inactive & active domains")}, + {"transient", VSH_OT_BOOL, 0, N_("list transient domains")}, + {"persistent", VSH_OT_BOOL, 0, N_("list persistent domains")}, + {"with-snapshot", VSH_OT_BOOL, 0, + N_("list domains with existing snapshot")}, + {"without-snapshot", VSH_OT_BOOL, 0, + N_("list domains without a snapshot")}, + {"state-running", VSH_OT_BOOL, 0, N_("list domains in running state")}, + {"state-paused", VSH_OT_BOOL, 0, N_("list domains in paused state")}, + {"state-shutoff", VSH_OT_BOOL, 0, N_("list domains in shutoff state")}, + {"state-other", VSH_OT_BOOL, 0, N_("list domains in other states")}, + {"autostart", VSH_OT_BOOL, 0, N_("list domains with autostart enabled")}, + {"no-autostart", VSH_OT_BOOL, 0, + N_("list domains with autostart disabled")}, + {"with-managed-save", VSH_OT_BOOL, 0, + N_("list domains with managed save state")}, + {"without-managed-save", VSH_OT_BOOL, 0, + N_("list domains without managed save")}, + {"uuid", VSH_OT_BOOL, 0, N_("list uuid's only")}, + {"name", VSH_OT_BOOL, 0, N_("list domain names only")}, + {"table", VSH_OT_BOOL, 0, N_("list table (default)")}, + {"managed-save", VSH_OT_BOOL, 0, + N_("mark inactive domains with managed save state")}, + {"title", VSH_OT_BOOL, 0, N_("show short domain description")}, + {NULL, 0, 0, NULL} +}; + +#define FILTER(NAME, FLAG) \ + if (vshCommandOptBool(cmd, NAME)) \ + flags |= (FLAG) +static bool +cmdList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) +{ + bool managed = vshCommandOptBool(cmd, "managed-save"); + bool optTitle = vshCommandOptBool(cmd, "title"); + bool optTable = vshCommandOptBool(cmd, "table"); + bool optUUID = vshCommandOptBool(cmd, "uuid"); + bool optName = vshCommandOptBool(cmd, "name"); + int i; + char *title; + char uuid[VIR_UUID_STRING_BUFLEN]; + int state; + bool ret = false; + vshDomainListPtr list = NULL; + virDomainPtr dom; + char id_buf[INT_BUFSIZE_BOUND(unsigned int)]; + unsigned int id; + unsigned int flags = VIR_CONNECT_LIST_DOMAINS_ACTIVE; + + /* construct filter flags */ + if (vshCommandOptBool(cmd, "inactive")) + flags = VIR_CONNECT_LIST_DOMAINS_INACTIVE; + + if (vshCommandOptBool(cmd, "all")) + flags = VIR_CONNECT_LIST_DOMAINS_INACTIVE | + VIR_CONNECT_LIST_DOMAINS_ACTIVE; + + FILTER("persistent", VIR_CONNECT_LIST_DOMAINS_PERSISTENT); + FILTER("transient", VIR_CONNECT_LIST_DOMAINS_TRANSIENT); + + FILTER("with-managed-save", VIR_CONNECT_LIST_DOMAINS_MANAGEDSAVE); + FILTER("without-managed-save", VIR_CONNECT_LIST_DOMAINS_NO_MANAGEDSAVE); + + FILTER("autostart", VIR_CONNECT_LIST_DOMAINS_AUTOSTART); + FILTER("no-autostart", VIR_CONNECT_LIST_DOMAINS_NO_AUTOSTART); + + FILTER("with-snapshot", VIR_CONNECT_LIST_DOMAINS_HAS_SNAPSHOT); + FILTER("without-snapshot", VIR_CONNECT_LIST_DOMAINS_NO_SNAPSHOT); + + FILTER("state-running", VIR_CONNECT_LIST_DOMAINS_RUNNING); + FILTER("state-paused", VIR_CONNECT_LIST_DOMAINS_PAUSED); + FILTER("state-shutoff", VIR_CONNECT_LIST_DOMAINS_SHUTOFF); + FILTER("state-other", VIR_CONNECT_LIST_DOMAINS_OTHER); + + if (optTable + optName + optUUID > 1) { + vshError(ctl, "%s", + _("Only one argument from --table, --name and --uuid " + "may be specified.")); + return false; + } + + if (!optUUID && !optName) + optTable = true; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(list = vshDomainListCollect(ctl, flags))) + goto cleanup; + + /* print table header in legacy mode */ + if (optTable) { + if (optTitle) + vshPrintExtra(ctl, " %-5s %-30s %-10s %-20s\n%s\n", + _("Id"), _("Name"), _("State"), _("Title"), + "-----------------------------------------" + "-----------------------------------------"); + else + vshPrintExtra(ctl, " %-5s %-30s %s\n%s\n", + _("Id"), _("Name"), _("State"), + "-----------------------------------------" + "-----------"); + } + + for (i = 0; i < list->ndomains; i++) { + dom = list->domains[i]; + id = virDomainGetID(dom); + if (id != (unsigned int) -1) + snprintf(id_buf, sizeof(id_buf), "%d", id); + else + ignore_value(virStrcpyStatic(id_buf, "-")); + + state = vshDomainState(ctl, dom, NULL); + if (optTable && managed && state == VIR_DOMAIN_SHUTOFF && + virDomainHasManagedSaveImage(dom, 0) > 0) + state = -2; + + if (optTable) { + if (optTitle) { + if (!(title = vshGetDomainDescription(ctl, dom, true, 0))) + goto cleanup; + + vshPrint(ctl, " %-5s %-30s %-10s %-20s\n", id_buf, + virDomainGetName(dom), + state == -2 ? _("saved") : _(vshDomainStateToString(state)), + title); + + VIR_FREE(title); + } else { + vshPrint(ctl, " %-5s %-30s %s\n", id_buf, + virDomainGetName(dom), + state == -2 ? _("saved") : _(vshDomainStateToString(state))); + } + } else if (optUUID) { + if (virDomainGetUUIDString(dom, uuid) < 0) { + vshError(ctl, "%s", _("Failed to get domain's UUID")); + goto cleanup; + } + vshPrint(ctl, "%s\n", uuid); + } else if (optName) { + vshPrint(ctl, "%s\n", virDomainGetName(dom)); + } + } + + ret = true; +cleanup: + vshDomainListFree(list); + return ret; +} +#undef FILTER diff --git a/tools/virsh.c b/tools/virsh.c index 81976a0..85c171b 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -976,450 +976,6 @@ cleanup: #endif /* WIN32 */ - -/* - * "list" command - */ -static const vshCmdInfo info_list[] = { - {"help", N_("list domains")}, - {"desc", N_("Returns list of domains.")}, - {NULL, NULL} -}; - -/* compare domains, pack NULLed ones at the end*/ -static int -vshDomainSorter(const void *a, const void *b) -{ - virDomainPtr *da = (virDomainPtr *) a; - virDomainPtr *db = (virDomainPtr *) b; - unsigned int ida; - unsigned int idb; - unsigned int inactive = (unsigned int) -1; - - if (*da && !*db) - return -1; - - if (!*da) - return *db != NULL; - - ida = virDomainGetID(*da); - idb = virDomainGetID(*db); - - if (ida == inactive && idb == inactive) - return strcasecmp(virDomainGetName(*da), virDomainGetName(*db)); - - if (ida != inactive && idb != inactive) { - if (ida > idb) - return 1; - else if (ida < idb) - return -1; - } - - if (ida != inactive) - return -1; - else - return 1; -} - -struct vshDomainList { - virDomainPtr *domains; - size_t ndomains; -}; -typedef struct vshDomainList *vshDomainListPtr; - -static void -vshDomainListFree(vshDomainListPtr domlist) -{ - int i; - - if (domlist && domlist->domains) { - for (i = 0; i < domlist->ndomains; i++) { - if (domlist->domains[i]) - virDomainFree(domlist->domains[i]); - } - VIR_FREE(domlist->domains); - } - VIR_FREE(domlist); -} - -#define MATCH(FLAG) (flags & (FLAG)) -static vshDomainListPtr -vshDomainListCollect(vshControl *ctl, unsigned int flags) -{ - vshDomainListPtr list = vshMalloc(ctl, sizeof(*list)); - int i; - int ret; - int *ids = NULL; - int nids = 0; - char **names = NULL; - int nnames = 0; - virDomainPtr dom; - bool success = false; - size_t deleted = 0; - int persistent; - int autostart; - int state; - int nsnap; - int mansave; - - /* try the list with flags support (0.9.13 and later) */ - if ((ret = virConnectListAllDomains(ctl->conn, &list->domains, - flags)) >= 0) { - list->ndomains = ret; - goto finished; - } - - /* check if the command is actually supported */ - if (last_error && last_error->code == VIR_ERR_NO_SUPPORT) { - virFreeError(last_error); - last_error = NULL; - goto fallback; - } - - if (last_error && last_error->code == VIR_ERR_INVALID_ARG) { - /* try the new API again but mask non-guaranteed flags */ - unsigned int newflags = flags & (VIR_CONNECT_LIST_DOMAINS_ACTIVE | - VIR_CONNECT_LIST_DOMAINS_INACTIVE); - - virFreeError(last_error); - last_error = NULL; - if ((ret = virConnectListAllDomains(ctl->conn, &list->domains, - newflags)) >= 0) { - list->ndomains = ret; - goto filter; - } - } - - /* there was an error during the first or second call */ - vshError(ctl, "%s", _("Failed to list domains")); - goto cleanup; - - -fallback: - /* fall back to old method (0.9.12 and older) */ - virResetLastError(); - - /* list active domains, if necessary */ - if (!MATCH(VIR_CONNECT_LIST_FILTERS_ACTIVE) || - MATCH(VIR_CONNECT_LIST_DOMAINS_ACTIVE)) { - if ((nids = virConnectNumOfDomains(ctl->conn)) < 0) { - vshError(ctl, "%s", _("Failed to list active domains")); - goto cleanup; - } - - if (nids) { - ids = vshMalloc(ctl, sizeof(int) * nids); - - if ((nids = virConnectListDomains(ctl->conn, ids, nids)) < 0) { - vshError(ctl, "%s", _("Failed to list active domains")); - goto cleanup; - } - } - } - - if (!MATCH(VIR_CONNECT_LIST_FILTERS_ACTIVE) || - MATCH(VIR_CONNECT_LIST_DOMAINS_INACTIVE)) { - if ((nnames = virConnectNumOfDefinedDomains(ctl->conn)) < 0) { - vshError(ctl, "%s", _("Failed to list inactive domains")); - goto cleanup; - } - - if (nnames) { - names = vshMalloc(ctl, sizeof(char *) * nnames); - - if ((nnames = virConnectListDefinedDomains(ctl->conn, names, - nnames)) < 0) { - vshError(ctl, "%s", _("Failed to list inactive domains")); - goto cleanup; - } - } - } - - list->domains = vshMalloc(ctl, sizeof(virDomainPtr) * (nids + nnames)); - list->ndomains = 0; - - /* get active domains */ - for (i = 0; i < nids; i++) { - if (!(dom = virDomainLookupByID(ctl->conn, ids[i]))) - continue; - list->domains[list->ndomains++] = dom; - } - - /* get inactive domains */ - for (i = 0; i < nnames; i++) { - if (!(dom = virDomainLookupByName(ctl->conn, names[i]))) - continue; - list->domains[list->ndomains++] = dom; - } - - /* truncate domains that weren't found */ - deleted = (nids + nnames) - list->ndomains; - -filter: - /* filter list the list if the list was acquired by fallback means */ - for (i = 0; i < list->ndomains; i++) { - dom = list->domains[i]; - - /* persistence filter */ - if (MATCH(VIR_CONNECT_LIST_FILTERS_PERSISTENT)) { - if ((persistent = virDomainIsPersistent(dom)) < 0) { - vshError(ctl, "%s", _("Failed to get domain persistence info")); - goto cleanup; - } - - if (!((MATCH(VIR_CONNECT_LIST_DOMAINS_PERSISTENT) && persistent) || - (MATCH(VIR_CONNECT_LIST_DOMAINS_TRANSIENT) && !persistent))) - goto remove_entry; - } - - /* domain state filter */ - if (MATCH(VIR_CONNECT_LIST_FILTERS_STATE)) { - if (virDomainGetState(dom, &state, NULL, 0) < 0) { - vshError(ctl, "%s", _("Failed to get domain state")); - goto cleanup; - } - - if (!((MATCH(VIR_CONNECT_LIST_DOMAINS_RUNNING) && - state == VIR_DOMAIN_RUNNING) || - (MATCH(VIR_CONNECT_LIST_DOMAINS_PAUSED) && - state == VIR_DOMAIN_PAUSED) || - (MATCH(VIR_CONNECT_LIST_DOMAINS_SHUTOFF) && - state == VIR_DOMAIN_SHUTOFF) || - (MATCH(VIR_CONNECT_LIST_DOMAINS_OTHER) && - (state != VIR_DOMAIN_RUNNING && - state != VIR_DOMAIN_PAUSED && - state != VIR_DOMAIN_SHUTOFF)))) - goto remove_entry; - } - - /* autostart filter */ - if (MATCH(VIR_CONNECT_LIST_FILTERS_AUTOSTART)) { - if (virDomainGetAutostart(dom, &autostart) < 0) { - vshError(ctl, "%s", _("Failed to get domain autostart state")); - goto cleanup; - } - - if (!((MATCH(VIR_CONNECT_LIST_DOMAINS_AUTOSTART) && autostart) || - (MATCH(VIR_CONNECT_LIST_DOMAINS_NO_AUTOSTART) && !autostart))) - goto remove_entry; - } - - /* managed save filter */ - if (MATCH(VIR_CONNECT_LIST_FILTERS_MANAGEDSAVE)) { - if ((mansave = virDomainHasManagedSaveImage(dom, 0)) < 0) { - vshError(ctl, "%s", - _("Failed to check for managed save image")); - goto cleanup; - } - - if (!((MATCH(VIR_CONNECT_LIST_DOMAINS_MANAGEDSAVE) && mansave) || - (MATCH(VIR_CONNECT_LIST_DOMAINS_NO_MANAGEDSAVE) && !mansave))) - goto remove_entry; - } - - /* snapshot filter */ - if (MATCH(VIR_CONNECT_LIST_FILTERS_SNAPSHOT)) { - if ((nsnap = virDomainSnapshotNum(dom, 0)) < 0) { - vshError(ctl, "%s", _("Failed to get snapshot count")); - goto cleanup; - } - if (!((MATCH(VIR_CONNECT_LIST_DOMAINS_HAS_SNAPSHOT) && nsnap > 0) || - (MATCH(VIR_CONNECT_LIST_DOMAINS_NO_SNAPSHOT) && nsnap == 0))) - goto remove_entry; - } - - /* the domain matched all filters, it may stay */ - continue; - -remove_entry: - /* the domain has to be removed as it failed one of the filters */ - virDomainFree(list->domains[i]); - list->domains[i] = NULL; - deleted++; - } - -finished: - /* sort the list */ - if (list->domains && list->ndomains) - qsort(list->domains, list->ndomains, sizeof(*list->domains), - vshDomainSorter); - - /* truncate the list if filter simulation deleted entries */ - if (deleted) - VIR_SHRINK_N(list->domains, list->ndomains, deleted); - - success = true; - -cleanup: - for (i = 0; i < nnames; i++) - VIR_FREE(names[i]); - - if (!success) { - vshDomainListFree(list); - list = NULL; - } - - VIR_FREE(names); - VIR_FREE(ids); - return list; -} -#undef MATCH - - -static const vshCmdOptDef opts_list[] = { - {"inactive", VSH_OT_BOOL, 0, N_("list inactive domains")}, - {"all", VSH_OT_BOOL, 0, N_("list inactive & active domains")}, - {"transient", VSH_OT_BOOL, 0, N_("list transient domains")}, - {"persistent", VSH_OT_BOOL, 0, N_("list persistent domains")}, - {"with-snapshot", VSH_OT_BOOL, 0, - N_("list domains with existing snapshot")}, - {"without-snapshot", VSH_OT_BOOL, 0, - N_("list domains without a snapshot")}, - {"state-running", VSH_OT_BOOL, 0, N_("list domains in running state")}, - {"state-paused", VSH_OT_BOOL, 0, N_("list domains in paused state")}, - {"state-shutoff", VSH_OT_BOOL, 0, N_("list domains in shutoff state")}, - {"state-other", VSH_OT_BOOL, 0, N_("list domains in other states")}, - {"autostart", VSH_OT_BOOL, 0, N_("list domains with autostart enabled")}, - {"no-autostart", VSH_OT_BOOL, 0, - N_("list domains with autostart disabled")}, - {"with-managed-save", VSH_OT_BOOL, 0, - N_("list domains with managed save state")}, - {"without-managed-save", VSH_OT_BOOL, 0, - N_("list domains without managed save")}, - {"uuid", VSH_OT_BOOL, 0, N_("list uuid's only")}, - {"name", VSH_OT_BOOL, 0, N_("list domain names only")}, - {"table", VSH_OT_BOOL, 0, N_("list table (default)")}, - {"managed-save", VSH_OT_BOOL, 0, - N_("mark inactive domains with managed save state")}, - {"title", VSH_OT_BOOL, 0, N_("show short domain description")}, - {NULL, 0, 0, NULL} -}; - - -#define FILTER(NAME, FLAG) \ - if (vshCommandOptBool(cmd, NAME)) \ - flags |= (FLAG) -static bool -cmdList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) -{ - bool managed = vshCommandOptBool(cmd, "managed-save"); - bool optTitle = vshCommandOptBool(cmd, "title"); - bool optTable = vshCommandOptBool(cmd, "table"); - bool optUUID = vshCommandOptBool(cmd, "uuid"); - bool optName = vshCommandOptBool(cmd, "name"); - int i; - char *title; - char uuid[VIR_UUID_STRING_BUFLEN]; - int state; - bool ret = false; - vshDomainListPtr list = NULL; - virDomainPtr dom; - char id_buf[INT_BUFSIZE_BOUND(unsigned int)]; - unsigned int id; - unsigned int flags = VIR_CONNECT_LIST_DOMAINS_ACTIVE; - - /* construct filter flags */ - if (vshCommandOptBool(cmd, "inactive")) - flags = VIR_CONNECT_LIST_DOMAINS_INACTIVE; - - if (vshCommandOptBool(cmd, "all")) - flags = VIR_CONNECT_LIST_DOMAINS_INACTIVE | - VIR_CONNECT_LIST_DOMAINS_ACTIVE; - - FILTER("persistent", VIR_CONNECT_LIST_DOMAINS_PERSISTENT); - FILTER("transient", VIR_CONNECT_LIST_DOMAINS_TRANSIENT); - - FILTER("with-managed-save", VIR_CONNECT_LIST_DOMAINS_MANAGEDSAVE); - FILTER("without-managed-save", VIR_CONNECT_LIST_DOMAINS_NO_MANAGEDSAVE); - - FILTER("autostart", VIR_CONNECT_LIST_DOMAINS_AUTOSTART); - FILTER("no-autostart", VIR_CONNECT_LIST_DOMAINS_NO_AUTOSTART); - - FILTER("with-snapshot", VIR_CONNECT_LIST_DOMAINS_HAS_SNAPSHOT); - FILTER("without-snapshot", VIR_CONNECT_LIST_DOMAINS_NO_SNAPSHOT); - - FILTER("state-running", VIR_CONNECT_LIST_DOMAINS_RUNNING); - FILTER("state-paused", VIR_CONNECT_LIST_DOMAINS_PAUSED); - FILTER("state-shutoff", VIR_CONNECT_LIST_DOMAINS_SHUTOFF); - FILTER("state-other", VIR_CONNECT_LIST_DOMAINS_OTHER); - - if (optTable + optName + optUUID > 1) { - vshError(ctl, "%s", - _("Only one argument from --table, --name and --uuid " - "may be specified.")); - return false; - } - - if (!optUUID && !optName) - optTable = true; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (!(list = vshDomainListCollect(ctl, flags))) - goto cleanup; - - /* print table header in legacy mode */ - if (optTable) { - if (optTitle) - vshPrintExtra(ctl, " %-5s %-30s %-10s %-20s\n%s\n", - _("Id"), _("Name"), _("State"), _("Title"), - "-----------------------------------------" - "-----------------------------------------"); - else - vshPrintExtra(ctl, " %-5s %-30s %s\n%s\n", - _("Id"), _("Name"), _("State"), - "-----------------------------------------" - "-----------"); - } - - for (i = 0; i < list->ndomains; i++) { - dom = list->domains[i]; - id = virDomainGetID(dom); - if (id != (unsigned int) -1) - snprintf(id_buf, sizeof(id_buf), "%d", id); - else - ignore_value(virStrcpyStatic(id_buf, "-")); - - state = vshDomainState(ctl, dom, NULL); - if (optTable && managed && state == VIR_DOMAIN_SHUTOFF && - virDomainHasManagedSaveImage(dom, 0) > 0) - state = -2; - - if (optTable) { - if (optTitle) { - if (!(title = vshGetDomainDescription(ctl, dom, true, 0))) - goto cleanup; - - vshPrint(ctl, " %-5s %-30s %-10s %-20s\n", id_buf, - virDomainGetName(dom), - state == -2 ? _("saved") : _(vshDomainStateToString(state)), - title); - - VIR_FREE(title); - } else { - vshPrint(ctl, " %-5s %-30s %s\n", id_buf, - virDomainGetName(dom), - state == -2 ? _("saved") : _(vshDomainStateToString(state))); - } - } else if (optUUID) { - if (virDomainGetUUIDString(dom, uuid) < 0) { - vshError(ctl, "%s", _("Failed to get domain's UUID")); - goto cleanup; - } - vshPrint(ctl, "%s\n", uuid); - } else if (optName) { - vshPrint(ctl, "%s\n", virDomainGetName(dom)); - } - } - - ret = true; -cleanup: - vshDomainListFree(list); - return ret; -} -#undef FILTER - /* * "desc" command for managing domain description and title */ @@ -1576,28 +1132,43 @@ cleanup: return ret; } -/* - * "domstate" command +/* "domif-setlink" command */ -static const vshCmdInfo info_domstate[] = { - {"help", N_("domain state")}, - {"desc", N_("Returns state about a domain.")}, - {NULL, NULL} +static const vshCmdInfo info_domif_setlink[] = { + {"help", N_("set link state of a virtual interface")}, + {"desc", N_("Set link state of a domain's virtual interface. This command wraps usage of update-device command.")}, + {NULL,NULL} }; -static const vshCmdOptDef opts_domstate[] = { +static const vshCmdOptDef opts_domif_setlink[] = { {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, - {"reason", VSH_OT_BOOL, 0, N_("also print reason for the state")}, + {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, N_("interface device (MAC Address)")}, + {"state", VSH_OT_DATA, VSH_OFLAG_REQ, N_("new state of the device")}, + {"persistent", VSH_OT_ALIAS, 0, "config"}, + {"config", VSH_OT_BOOL, 0, N_("affect next boot")}, {NULL, 0, 0, NULL} }; static bool -cmdDomstate(vshControl *ctl, const vshCmd *cmd) +cmdDomIfSetLink(vshControl *ctl, const vshCmd *cmd) { virDomainPtr dom; - bool ret = true; - bool showReason = vshCommandOptBool(cmd, "reason"); - int state, reason; + const char *iface; + const char *state; + const char *value; + const char *desc; + virMacAddr macaddr; + const char *element; + const char *attr; + bool config; + bool ret = false; + unsigned int flags = 0; + int i; + xmlDocPtr xml = NULL; + xmlXPathContextPtr ctxt = NULL; + xmlXPathObjectPtr obj = NULL; + xmlNodePtr cur = NULL; + xmlBufferPtr xml_buf = NULL; if (!vshConnectionUsability(ctl, ctl->conn)) return false; @@ -1605,382 +1176,33 @@ cmdDomstate(vshControl *ctl, const vshCmd *cmd) if (!(dom = vshCommandOptDomain(ctl, cmd, NULL))) return false; - if ((state = vshDomainState(ctl, dom, &reason)) < 0) { - ret = false; + if (vshCommandOptString(cmd, "interface", &iface) <= 0) goto cleanup; - } - - if (showReason) { - vshPrint(ctl, "%s (%s)\n", - _(vshDomainStateToString(state)), - vshDomainStateReasonToString(state, reason)); - } else { - vshPrint(ctl, "%s\n", - _(vshDomainStateToString(state))); - } - -cleanup: - virDomainFree(dom); - return ret; -} - -/* - * "domcontrol" command - */ -static const vshCmdInfo info_domcontrol[] = { - {"help", N_("domain control interface state")}, - {"desc", N_("Returns state of a control interface to the domain.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_domcontrol[] = { - {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdDomControl(vshControl *ctl, const vshCmd *cmd) -{ - virDomainPtr dom; - bool ret = true; - virDomainControlInfo info; - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; + if (vshCommandOptString(cmd, "state", &state) <= 0) + goto cleanup; - if (!(dom = vshCommandOptDomain(ctl, cmd, NULL))) - return false; + config = vshCommandOptBool(cmd, "config"); - if (virDomainGetControlInfo(dom, &info, 0) < 0) { - ret = false; + if (STRNEQ(state, "up") && STRNEQ(state, "down")) { + vshError(ctl, _("invalid link state '%s'"), state); goto cleanup; } - if (info.state != VIR_DOMAIN_CONTROL_OK && - info.state != VIR_DOMAIN_CONTROL_ERROR) { - vshPrint(ctl, "%s (%0.3fs)\n", - _(vshDomainControlStateToString(info.state)), - info.stateTime / 1000.0); - } else { - vshPrint(ctl, "%s\n", - _(vshDomainControlStateToString(info.state))); + /* get persistent or live description of network device */ + desc = virDomainGetXMLDesc(dom, config ? VIR_DOMAIN_XML_INACTIVE : 0); + if (desc == NULL) { + vshError(ctl, _("Failed to get domain description xml")); + goto cleanup; } -cleanup: - virDomainFree(dom); - return ret; -} + if (config) + flags = VIR_DOMAIN_AFFECT_CONFIG; + else + flags = VIR_DOMAIN_AFFECT_LIVE; -/* "domblkstat" command - */ -static const vshCmdInfo info_domblkstat[] = { - {"help", N_("get device block stats for a domain")}, - {"desc", N_("Get device block stats for a running domain. See man page or " - "use --human for explanation of fields")}, - {NULL,NULL} -}; - -static const vshCmdOptDef opts_domblkstat[] = { - {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, - {"device", VSH_OT_DATA, VSH_OFLAG_REQ, N_("block device")}, - {"human", VSH_OT_BOOL, 0, N_("print a more human readable output")}, - {NULL, 0, 0, NULL} -}; - -struct _domblkstat_sequence { - const char *field; /* field name */ - const char *legacy; /* legacy name from previous releases */ - const char *human; /* human-friendly explanation */ -}; - -/* sequence of values for output to honor legacy format from previous - * versions */ -static const struct _domblkstat_sequence domblkstat_output[] = { - { VIR_DOMAIN_BLOCK_STATS_READ_REQ, "rd_req", - N_("number of read operations:") }, /* 0 */ - { VIR_DOMAIN_BLOCK_STATS_READ_BYTES, "rd_bytes", - N_("number of bytes read:") }, /* 1 */ - { VIR_DOMAIN_BLOCK_STATS_WRITE_REQ, "wr_req", - N_("number of write operations:") }, /* 2 */ - { VIR_DOMAIN_BLOCK_STATS_WRITE_BYTES, "wr_bytes", - N_("number of bytes written:") }, /* 3 */ - { VIR_DOMAIN_BLOCK_STATS_ERRS, "errs", - N_("error count:") }, /* 4 */ - { VIR_DOMAIN_BLOCK_STATS_FLUSH_REQ, NULL, - N_("number of flush operations:") }, /* 5 */ - { VIR_DOMAIN_BLOCK_STATS_READ_TOTAL_TIMES, NULL, - N_("total duration of reads (ns):") }, /* 6 */ - { VIR_DOMAIN_BLOCK_STATS_WRITE_TOTAL_TIMES, NULL, - N_("total duration of writes (ns):") }, /* 7 */ - { VIR_DOMAIN_BLOCK_STATS_FLUSH_TOTAL_TIMES, NULL, - N_("total duration of flushes (ns):") }, /* 8 */ - { NULL, NULL, NULL } -}; - -#define DOMBLKSTAT_LEGACY_PRINT(ID, VALUE) \ - if (VALUE >= 0) \ - vshPrint(ctl, "%s %-*s %lld\n", device, \ - human ? 31 : 0, \ - human ? _(domblkstat_output[ID].human) \ - : domblkstat_output[ID].legacy, \ - VALUE); - -static bool -cmdDomblkstat(vshControl *ctl, const vshCmd *cmd) -{ - virDomainPtr dom; - const char *name = NULL, *device = NULL; - struct _virDomainBlockStats stats; - virTypedParameterPtr params = NULL; - virTypedParameterPtr par = NULL; - char *value = NULL; - const char *field = NULL; - int rc, nparams = 0; - int i = 0; - bool ret = false; - bool human = vshCommandOptBool(cmd, "human"); /* human readable output */ - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (!(dom = vshCommandOptDomain(ctl, cmd, &name))) - return false; - - if (vshCommandOptString(cmd, "device", &device) <= 0) - goto cleanup; - - rc = virDomainBlockStatsFlags(dom, device, NULL, &nparams, 0); - - /* It might fail when virDomainBlockStatsFlags is not - * supported on older libvirt, fallback to use virDomainBlockStats - * then. - */ - if (rc < 0) { - /* try older API if newer is not supported */ - if (last_error->code != VIR_ERR_NO_SUPPORT) - goto cleanup; - - virFreeError(last_error); - last_error = NULL; - - if (virDomainBlockStats(dom, device, &stats, - sizeof(stats)) == -1) { - vshError(ctl, _("Failed to get block stats %s %s"), - name, device); - goto cleanup; - } - - /* human friendly output */ - if (human) { - vshPrint(ctl, N_("Device: %s\n"), device); - device = ""; - } - - DOMBLKSTAT_LEGACY_PRINT(0, stats.rd_req); - DOMBLKSTAT_LEGACY_PRINT(1, stats.rd_bytes); - DOMBLKSTAT_LEGACY_PRINT(2, stats.wr_req); - DOMBLKSTAT_LEGACY_PRINT(3, stats.wr_bytes); - DOMBLKSTAT_LEGACY_PRINT(4, stats.errs); - } else { - params = vshCalloc(ctl, nparams, sizeof(*params)); - - if (virDomainBlockStatsFlags(dom, device, params, &nparams, 0) < 0) { - vshError(ctl, _("Failed to get block stats %s %s"), name, device); - goto cleanup; - } - - /* set for prettier output */ - if (human) { - vshPrint(ctl, N_("Device: %s\n"), device); - device = ""; - } - - /* at first print all known values in desired order */ - for (i = 0; domblkstat_output[i].field != NULL; i++) { - if (!(par = vshFindTypedParamByName(domblkstat_output[i].field, - params, - nparams))) - continue; - - value = vshGetTypedParamValue(ctl, par); - - /* to print other not supported fields, mark the already printed */ - par->field[0] = '\0'; /* set the name to empty string */ - - /* translate into human readable or legacy spelling */ - field = NULL; - if (human) - field = _(domblkstat_output[i].human); - else - field = domblkstat_output[i].legacy; - - /* use the provided spelling if no translation is available */ - if (!field) - field = domblkstat_output[i].field; - - vshPrint(ctl, "%s %-*s %s\n", device, - human ? 31 : 0, field, value); - - VIR_FREE(value); - } - - /* go through the fields again, for remaining fields */ - for (i = 0; i < nparams; i++) { - if (!*params[i].field) - continue; - - value = vshGetTypedParamValue(ctl, params+i); - vshPrint(ctl, "%s %s %s\n", device, params[i].field, value); - VIR_FREE(value); - } - } - - ret = true; - -cleanup: - VIR_FREE(params); - virDomainFree(dom); - return ret; -} -#undef DOMBLKSTAT_LEGACY_PRINT - -/* "domifstat" command - */ -static const vshCmdInfo info_domifstat[] = { - {"help", N_("get network interface stats for a domain")}, - {"desc", N_("Get network interface stats for a running domain.")}, - {NULL,NULL} -}; - -static const vshCmdOptDef opts_domifstat[] = { - {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, - {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, N_("interface device")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdDomIfstat(vshControl *ctl, const vshCmd *cmd) -{ - virDomainPtr dom; - const char *name = NULL, *device = NULL; - struct _virDomainInterfaceStats stats; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (!(dom = vshCommandOptDomain(ctl, cmd, &name))) - return false; - - if (vshCommandOptString(cmd, "interface", &device) <= 0) { - virDomainFree(dom); - return false; - } - - if (virDomainInterfaceStats(dom, device, &stats, sizeof(stats)) == -1) { - vshError(ctl, _("Failed to get interface stats %s %s"), name, device); - virDomainFree(dom); - return false; - } - - if (stats.rx_bytes >= 0) - vshPrint(ctl, "%s rx_bytes %lld\n", device, stats.rx_bytes); - - if (stats.rx_packets >= 0) - vshPrint(ctl, "%s rx_packets %lld\n", device, stats.rx_packets); - - if (stats.rx_errs >= 0) - vshPrint(ctl, "%s rx_errs %lld\n", device, stats.rx_errs); - - if (stats.rx_drop >= 0) - vshPrint(ctl, "%s rx_drop %lld\n", device, stats.rx_drop); - - if (stats.tx_bytes >= 0) - vshPrint(ctl, "%s tx_bytes %lld\n", device, stats.tx_bytes); - - if (stats.tx_packets >= 0) - vshPrint(ctl, "%s tx_packets %lld\n", device, stats.tx_packets); - - if (stats.tx_errs >= 0) - vshPrint(ctl, "%s tx_errs %lld\n", device, stats.tx_errs); - - if (stats.tx_drop >= 0) - vshPrint(ctl, "%s tx_drop %lld\n", device, stats.tx_drop); - - virDomainFree(dom); - return true; -} - -/* "domif-setlink" command - */ -static const vshCmdInfo info_domif_setlink[] = { - {"help", N_("set link state of a virtual interface")}, - {"desc", N_("Set link state of a domain's virtual interface. This command wraps usage of update-device command.")}, - {NULL,NULL} -}; - -static const vshCmdOptDef opts_domif_setlink[] = { - {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, - {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, N_("interface device (MAC Address)")}, - {"state", VSH_OT_DATA, VSH_OFLAG_REQ, N_("new state of the device")}, - {"persistent", VSH_OT_ALIAS, 0, "config"}, - {"config", VSH_OT_BOOL, 0, N_("affect next boot")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdDomIfSetLink(vshControl *ctl, const vshCmd *cmd) -{ - virDomainPtr dom; - const char *iface; - const char *state; - const char *value; - const char *desc; - virMacAddr macaddr; - const char *element; - const char *attr; - bool config; - bool ret = false; - unsigned int flags = 0; - int i; - xmlDocPtr xml = NULL; - xmlXPathContextPtr ctxt = NULL; - xmlXPathObjectPtr obj = NULL; - xmlNodePtr cur = NULL; - xmlBufferPtr xml_buf = NULL; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (!(dom = vshCommandOptDomain(ctl, cmd, NULL))) - return false; - - if (vshCommandOptString(cmd, "interface", &iface) <= 0) - goto cleanup; - - if (vshCommandOptString(cmd, "state", &state) <= 0) - goto cleanup; - - config = vshCommandOptBool(cmd, "config"); - - if (STRNEQ(state, "up") && STRNEQ(state, "down")) { - vshError(ctl, _("invalid link state '%s'"), state); - goto cleanup; - } - - /* get persistent or live description of network device */ - desc = virDomainGetXMLDesc(dom, config ? VIR_DOMAIN_XML_INACTIVE : 0); - if (desc == NULL) { - vshError(ctl, _("Failed to get domain description xml")); - goto cleanup; - } - - if (config) - flags = VIR_DOMAIN_AFFECT_CONFIG; - else - flags = VIR_DOMAIN_AFFECT_LIVE; - - if (virDomainIsActive(dom) == 0) - flags = VIR_DOMAIN_AFFECT_CONFIG; + if (virDomainIsActive(dom) == 0) + flags = VIR_DOMAIN_AFFECT_CONFIG; /* extract current network device description */ xml = virXMLParseStringCtxt(desc, _("(domain_definition)"), &ctxt); @@ -2050,166 +1272,37 @@ hit: BAD_CAST "link", NULL); if (!cur) - goto cleanup; - - if (xmlNewProp(cur, BAD_CAST "state", BAD_CAST state) == NULL) - goto cleanup; - } - - xml_buf = xmlBufferCreate(); - if (!xml_buf) { - vshError(ctl, _("Failed to allocate memory")); - goto cleanup; - } - - if (xmlNodeDump(xml_buf, xml, obj->nodesetval->nodeTab[i], 0, 0) < 0 ) { - vshError(ctl, _("Failed to create XML")); - goto cleanup; - } - - if (virDomainUpdateDeviceFlags(dom, (char *)xmlBufferContent(xml_buf), flags) < 0) { - vshError(ctl, _("Failed to update interface link state")); - goto cleanup; - } else { - vshPrint(ctl, "%s", _("Device updated successfully\n")); - ret = true; - } - -cleanup: - xmlXPathFreeObject(obj); - xmlXPathFreeContext(ctxt); - xmlFreeDoc(xml); - xmlBufferFree(xml_buf); - - if (dom) - virDomainFree(dom); - - return ret; -} - -/* "domif-getlink" command - */ -static const vshCmdInfo info_domif_getlink[] = { - {"help", N_("get link state of a virtual interface")}, - {"desc", N_("Get link state of a domain's virtual interface.")}, - {NULL,NULL} -}; - -static const vshCmdOptDef opts_domif_getlink[] = { - {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, - {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, N_("interface device (MAC Address)")}, - {"persistent", VSH_OT_ALIAS, 0, "config"}, - {"config", VSH_OT_BOOL, 0, N_("Get persistent interface state")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdDomIfGetLink(vshControl *ctl, const vshCmd *cmd) -{ - virDomainPtr dom; - const char *iface = NULL; - int flags = 0; - char *state = NULL; - char *value = NULL; - virMacAddr macaddr; - const char *element; - const char *attr; - bool ret = false; - int i; - char *desc; - xmlDocPtr xml = NULL; - xmlXPathContextPtr ctxt = NULL; - xmlNodePtr cur = NULL; - xmlXPathObjectPtr obj = NULL; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (!(dom = vshCommandOptDomain(ctl, cmd, NULL))) - return false; - - if (vshCommandOptString(cmd, "interface", &iface) <= 0) { - virDomainFree(dom); - return false; - } - - if (vshCommandOptBool(cmd, "config")) - flags = VIR_DOMAIN_XML_INACTIVE; - - desc = virDomainGetXMLDesc(dom, flags); - if (desc == NULL) { - vshError(ctl, _("Failed to get domain description xml")); - goto cleanup; - } - - xml = virXMLParseStringCtxt(desc, _("(domain_definition)"), &ctxt); - VIR_FREE(desc); - if (!xml) { - vshError(ctl, _("Failed to parse domain description xml")); - goto cleanup; - } - - obj = xmlXPathEval(BAD_CAST "/domain/devices/interface", ctxt); - if (obj == NULL || obj->type != XPATH_NODESET || - obj->nodesetval == NULL || obj->nodesetval->nodeNr == 0) { - vshError(ctl, _("Failed to extract interface information or no interfaces found")); - goto cleanup; - } - - if (virMacAddrParse(iface, &macaddr) == 0) { - element = "mac"; - attr = "address"; - } else { - element = "target"; - attr = "dev"; - } - - /* find interface with matching mac addr */ - for (i = 0; i < obj->nodesetval->nodeNr; i++) { - cur = obj->nodesetval->nodeTab[i]->children; - - while (cur) { - if (cur->type == XML_ELEMENT_NODE && - xmlStrEqual(cur->name, BAD_CAST element)) { - - value = virXMLPropString(cur, attr); - - if (STRCASEEQ(value, iface)) { - VIR_FREE(value); - goto hit; - } - VIR_FREE(value); - } - cur = cur->next; - } - } - - vshError(ctl, _("Interface (%s: %s) not found."), element, iface); - goto cleanup; - -hit: - cur = obj->nodesetval->nodeTab[i]->children; - while (cur) { - if (cur->type == XML_ELEMENT_NODE && - xmlStrEqual(cur->name, BAD_CAST "link")) { - - state = virXMLPropString(cur, "state"); - vshPrint(ctl, "%s %s", iface, state); - VIR_FREE(state); + goto cleanup; + if (xmlNewProp(cur, BAD_CAST "state", BAD_CAST state) == NULL) goto cleanup; - } - cur = cur->next; } - /* attribute not found */ - vshPrint(ctl, "%s default", iface); + xml_buf = xmlBufferCreate(); + if (!xml_buf) { + vshError(ctl, _("Failed to allocate memory")); + goto cleanup; + } + + if (xmlNodeDump(xml_buf, xml, obj->nodesetval->nodeTab[i], 0, 0) < 0 ) { + vshError(ctl, _("Failed to create XML")); + goto cleanup; + } + + if (virDomainUpdateDeviceFlags(dom, (char *)xmlBufferContent(xml_buf), flags) < 0) { + vshError(ctl, _("Failed to update interface link state")); + goto cleanup; + } else { + vshPrint(ctl, "%s", _("Device updated successfully\n")); + ret = true; + } - ret = true; cleanup: xmlXPathFreeObject(obj); xmlXPathFreeContext(ctxt); xmlFreeDoc(xml); + xmlBufferFree(xml_buf); + if (dom) virDomainFree(dom); @@ -2345,381 +1438,69 @@ cmdDomIftune(vshControl *ctl, const vshCmd *cmd) /* set the interface parameters */ params = vshCalloc(ctl, nparams, sizeof(*params)); if (!params) { - virReportOOMError(); - goto cleanup; - } - - for (i = 0; i < nparams; i++) - params[i].type = VIR_TYPED_PARAM_UINT; - - i = 0; - if (inbound.average && i < nparams) { - if (!virStrcpy(params[i].field, VIR_DOMAIN_BANDWIDTH_IN_AVERAGE, - sizeof(params[i].field))) - goto cleanup; - params[i].value.ui = inbound.average; - i++; - } - if (inbound.peak && i < nparams) { - if (!virStrcpy(params[i].field, VIR_DOMAIN_BANDWIDTH_IN_PEAK, - sizeof(params[i].field))) - goto cleanup; - params[i].value.ui = inbound.peak; - i++; - } - if (inbound.burst && i < nparams) { - if (!virStrcpy(params[i].field, VIR_DOMAIN_BANDWIDTH_IN_BURST, - sizeof(params[i].field))) - goto cleanup; - params[i].value.ui = inbound.burst; - i++; - } - if (outbound.average && i < nparams) { - if (!virStrcpy(params[i].field, VIR_DOMAIN_BANDWIDTH_OUT_AVERAGE, - sizeof(params[i].field))) - goto cleanup; - params[i].value.ui = outbound.average; - i++; - } - if (outbound.peak && i < nparams) { - if (!virStrcpy(params[i].field, VIR_DOMAIN_BANDWIDTH_OUT_PEAK, - sizeof(params[i].field))) - goto cleanup; - params[i].value.ui = outbound.peak; - i++; - } - if (outbound.burst && i < nparams) { - if (!virStrcpy(params[i].field, VIR_DOMAIN_BANDWIDTH_OUT_BURST, - sizeof(params[i].field))) - goto cleanup; - params[i].value.ui = outbound.burst; - i++; - } - - if (virDomainSetInterfaceParameters(dom, device, params, nparams, flags) != 0) { - vshError(ctl, "%s", _("Unable to set interface parameters")); - goto cleanup; - } - } - - ret = true; - -cleanup: - virTypedParameterArrayClear(params, nparams); - VIR_FREE(params); - virDomainFree(dom); - return ret; -} - -/* - * "dommemstats" command - */ -static const vshCmdInfo info_dommemstat[] = { - {"help", N_("get memory statistics for a domain")}, - {"desc", N_("Get memory statistics for a running domain.")}, - {NULL,NULL} -}; - -static const vshCmdOptDef opts_dommemstat[] = { - {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdDomMemStat(vshControl *ctl, const vshCmd *cmd) -{ - virDomainPtr dom; - const char *name; - struct _virDomainMemoryStat stats[VIR_DOMAIN_MEMORY_STAT_NR]; - unsigned int nr_stats, i; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (!(dom = vshCommandOptDomain(ctl, cmd, &name))) - return false; - - nr_stats = virDomainMemoryStats(dom, stats, VIR_DOMAIN_MEMORY_STAT_NR, 0); - if (nr_stats == -1) { - vshError(ctl, _("Failed to get memory statistics for domain %s"), name); - virDomainFree(dom); - return false; - } - - for (i = 0; i < nr_stats; i++) { - if (stats[i].tag == VIR_DOMAIN_MEMORY_STAT_SWAP_IN) - vshPrint(ctl, "swap_in %llu\n", stats[i].val); - if (stats[i].tag == VIR_DOMAIN_MEMORY_STAT_SWAP_OUT) - vshPrint(ctl, "swap_out %llu\n", stats[i].val); - if (stats[i].tag == VIR_DOMAIN_MEMORY_STAT_MAJOR_FAULT) - vshPrint(ctl, "major_fault %llu\n", stats[i].val); - if (stats[i].tag == VIR_DOMAIN_MEMORY_STAT_MINOR_FAULT) - vshPrint(ctl, "minor_fault %llu\n", stats[i].val); - if (stats[i].tag == VIR_DOMAIN_MEMORY_STAT_UNUSED) - vshPrint(ctl, "unused %llu\n", stats[i].val); - if (stats[i].tag == VIR_DOMAIN_MEMORY_STAT_AVAILABLE) - vshPrint(ctl, "available %llu\n", stats[i].val); - if (stats[i].tag == VIR_DOMAIN_MEMORY_STAT_ACTUAL_BALLOON) - vshPrint(ctl, "actual %llu\n", stats[i].val); - if (stats[i].tag == VIR_DOMAIN_MEMORY_STAT_RSS) - vshPrint(ctl, "rss %llu\n", stats[i].val); - } - - virDomainFree(dom); - return true; -} - -/* - * "domblkinfo" command - */ -static const vshCmdInfo info_domblkinfo[] = { - {"help", N_("domain block device size information")}, - {"desc", N_("Get block device size info for a domain.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_domblkinfo[] = { - {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, - {"device", VSH_OT_DATA, VSH_OFLAG_REQ, N_("block device")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdDomblkinfo(vshControl *ctl, const vshCmd *cmd) -{ - virDomainBlockInfo info; - virDomainPtr dom; - bool ret = true; - const char *device = NULL; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (!(dom = vshCommandOptDomain(ctl, cmd, NULL))) - return false; - - if (vshCommandOptString(cmd, "device", &device) <= 0) { - virDomainFree(dom); - return false; - } - - if (virDomainGetBlockInfo(dom, device, &info, 0) < 0) { - virDomainFree(dom); - return false; - } - - vshPrint(ctl, "%-15s %llu\n", _("Capacity:"), info.capacity); - vshPrint(ctl, "%-15s %llu\n", _("Allocation:"), info.allocation); - vshPrint(ctl, "%-15s %llu\n", _("Physical:"), info.physical); - - virDomainFree(dom); - return ret; -} - -/* - * "domblklist" command - */ -static const vshCmdInfo info_domblklist[] = { - {"help", N_("list all domain blocks")}, - {"desc", N_("Get the summary of block devices for a domain.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_domblklist[] = { - {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, - {"inactive", VSH_OT_BOOL, 0, - N_("get inactive rather than running configuration")}, - {"details", VSH_OT_BOOL, 0, - N_("additionally display the type and device value")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdDomblklist(vshControl *ctl, const vshCmd *cmd) -{ - virDomainPtr dom; - bool ret = false; - unsigned int flags = 0; - char *xml = NULL; - xmlDocPtr xmldoc = NULL; - xmlXPathContextPtr ctxt = NULL; - int ndisks; - xmlNodePtr *disks = NULL; - int i; - bool details = false; - - if (vshCommandOptBool(cmd, "inactive")) - flags |= VIR_DOMAIN_XML_INACTIVE; - - details = vshCommandOptBool(cmd, "details"); - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (!(dom = vshCommandOptDomain(ctl, cmd, NULL))) - return false; - - xml = virDomainGetXMLDesc(dom, flags); - if (!xml) - goto cleanup; - - xmldoc = virXMLParseStringCtxt(xml, _("(domain_definition)"), &ctxt); - if (!xmldoc) - goto cleanup; - - ndisks = virXPathNodeSet("./devices/disk", ctxt, &disks); - if (ndisks < 0) - goto cleanup; - - if (details) - vshPrint(ctl, "%-10s %-10s %-10s %s\n", _("Type"), - _("Device"), _("Target"), _("Source")); - else - vshPrint(ctl, "%-10s %s\n", _("Target"), _("Source")); - - vshPrint(ctl, "------------------------------------------------\n"); - - for (i = 0; i < ndisks; i++) { - char *type; - char *device; - char *target; - char *source; - - ctxt->node = disks[i]; - - if (details) { - type = virXPathString("string(./@type)", ctxt); - device = virXPathString("string(./@device)", ctxt); - } - - target = virXPathString("string(./target/@dev)", ctxt); - if (!target) { - vshError(ctl, "unable to query block list"); - goto cleanup; - } - source = virXPathString("string(./source/@file" - "|./source/@dev" - "|./source/@dir" - "|./source/@name)", ctxt); - if (details) { - vshPrint(ctl, "%-10s %-10s %-10s %s\n", type, device, - target, source ? source : "-"); - VIR_FREE(type); - VIR_FREE(device); - } else { - vshPrint(ctl, "%-10s %s\n", target, source ? source : "-"); - } - - VIR_FREE(target); - VIR_FREE(source); - } - - ret = true; - -cleanup: - VIR_FREE(disks); - virDomainFree(dom); - VIR_FREE(xml); - xmlFreeDoc(xmldoc); - xmlXPathFreeContext(ctxt); - return ret; -} - -/* - * "domiflist" command - */ -static const vshCmdInfo info_domiflist[] = { - {"help", N_("list all domain virtual interfaces")}, - {"desc", N_("Get the summary of virtual interfaces for a domain.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_domiflist[] = { - {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, - {"inactive", VSH_OT_BOOL, 0, - N_("get inactive rather than running configuration")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdDomiflist(vshControl *ctl, const vshCmd *cmd) -{ - virDomainPtr dom; - bool ret = false; - unsigned int flags = 0; - char *xml = NULL; - xmlDocPtr xmldoc = NULL; - xmlXPathContextPtr ctxt = NULL; - int ninterfaces; - xmlNodePtr *interfaces = NULL; - int i; - - if (vshCommandOptBool(cmd, "inactive")) - flags |= VIR_DOMAIN_XML_INACTIVE; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (!(dom = vshCommandOptDomain(ctl, cmd, NULL))) - return false; - - xml = virDomainGetXMLDesc(dom, flags); - if (!xml) - goto cleanup; - - xmldoc = virXMLParseStringCtxt(xml, _("(domain_definition)"), &ctxt); - if (!xmldoc) - goto cleanup; - - ninterfaces = virXPathNodeSet("./devices/interface", ctxt, &interfaces); - if (ninterfaces < 0) - goto cleanup; - - vshPrint(ctl, "%-10s %-10s %-10s %-11s %s\n", _("Interface"), _("Type"), - _("Source"), _("Model"), _("MAC")); - vshPrint(ctl, "-------------------------------------------------------\n"); - - for (i = 0; i < ninterfaces; i++) { - char *type = NULL; - char *source = NULL; - char *target = NULL; - char *model = NULL; - char *mac = NULL; - - ctxt->node = interfaces[i]; - type = virXPathString("string(./@type)", ctxt); - - source = virXPathString("string(./source/@bridge" - "|./source/@dev" - "|./source/@network" - "|./source/@name)", ctxt); + virReportOOMError(); + goto cleanup; + } - target = virXPathString("string(./target/@dev)", ctxt); - model = virXPathString("string(./model/@type)", ctxt); - mac = virXPathString("string(./mac/@address)", ctxt); + for (i = 0; i < nparams; i++) + params[i].type = VIR_TYPED_PARAM_UINT; - vshPrint(ctl, "%-10s %-10s %-10s %-11s %-10s\n", - target ? target : "-", - type, - source ? source : "-", - model ? model : "-", - mac ? mac : "-"); + i = 0; + if (inbound.average && i < nparams) { + if (!virStrcpy(params[i].field, VIR_DOMAIN_BANDWIDTH_IN_AVERAGE, + sizeof(params[i].field))) + goto cleanup; + params[i].value.ui = inbound.average; + i++; + } + if (inbound.peak && i < nparams) { + if (!virStrcpy(params[i].field, VIR_DOMAIN_BANDWIDTH_IN_PEAK, + sizeof(params[i].field))) + goto cleanup; + params[i].value.ui = inbound.peak; + i++; + } + if (inbound.burst && i < nparams) { + if (!virStrcpy(params[i].field, VIR_DOMAIN_BANDWIDTH_IN_BURST, + sizeof(params[i].field))) + goto cleanup; + params[i].value.ui = inbound.burst; + i++; + } + if (outbound.average && i < nparams) { + if (!virStrcpy(params[i].field, VIR_DOMAIN_BANDWIDTH_OUT_AVERAGE, + sizeof(params[i].field))) + goto cleanup; + params[i].value.ui = outbound.average; + i++; + } + if (outbound.peak && i < nparams) { + if (!virStrcpy(params[i].field, VIR_DOMAIN_BANDWIDTH_OUT_PEAK, + sizeof(params[i].field))) + goto cleanup; + params[i].value.ui = outbound.peak; + i++; + } + if (outbound.burst && i < nparams) { + if (!virStrcpy(params[i].field, VIR_DOMAIN_BANDWIDTH_OUT_BURST, + sizeof(params[i].field))) + goto cleanup; + params[i].value.ui = outbound.burst; + i++; + } - VIR_FREE(type); - VIR_FREE(source); - VIR_FREE(target); - VIR_FREE(model); - VIR_FREE(mac); + if (virDomainSetInterfaceParameters(dom, device, params, nparams, flags) != 0) { + vshError(ctl, "%s", _("Unable to set interface parameters")); + goto cleanup; + } } ret = true; cleanup: - VIR_FREE(interfaces); + virTypedParameterArrayClear(params, nparams); + VIR_FREE(params); virDomainFree(dom); - VIR_FREE(xml); - xmlFreeDoc(xmldoc); - xmlXPathFreeContext(ctxt); return ret; } @@ -4731,144 +3512,6 @@ cmdDestroy(vshControl *ctl, const vshCmd *cmd) } /* - * "dominfo" command - */ -static const vshCmdInfo info_dominfo[] = { - {"help", N_("domain information")}, - {"desc", N_("Returns basic information about the domain.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_dominfo[] = { - {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdDominfo(vshControl *ctl, const vshCmd *cmd) -{ - virDomainInfo info; - virDomainPtr dom; - virSecurityModel secmodel; - virSecurityLabelPtr seclabel; - int persistent = 0; - bool ret = true; - int autostart; - unsigned int id; - char *str, uuid[VIR_UUID_STRING_BUFLEN]; - int has_managed_save = 0; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (!(dom = vshCommandOptDomain(ctl, cmd, NULL))) - return false; - - id = virDomainGetID(dom); - if (id == ((unsigned int)-1)) - vshPrint(ctl, "%-15s %s\n", _("Id:"), "-"); - else - vshPrint(ctl, "%-15s %d\n", _("Id:"), id); - vshPrint(ctl, "%-15s %s\n", _("Name:"), virDomainGetName(dom)); - - if (virDomainGetUUIDString(dom, &uuid[0])==0) - vshPrint(ctl, "%-15s %s\n", _("UUID:"), uuid); - - if ((str = virDomainGetOSType(dom))) { - vshPrint(ctl, "%-15s %s\n", _("OS Type:"), str); - VIR_FREE(str); - } - - if (virDomainGetInfo(dom, &info) == 0) { - vshPrint(ctl, "%-15s %s\n", _("State:"), - _(vshDomainStateToString(info.state))); - - vshPrint(ctl, "%-15s %d\n", _("CPU(s):"), info.nrVirtCpu); - - if (info.cpuTime != 0) { - double cpuUsed = info.cpuTime; - - cpuUsed /= 1000000000.0; - - vshPrint(ctl, "%-15s %.1lfs\n", _("CPU time:"), cpuUsed); - } - - if (info.maxMem != UINT_MAX) - vshPrint(ctl, "%-15s %lu KiB\n", _("Max memory:"), - info.maxMem); - else - vshPrint(ctl, "%-15s %s\n", _("Max memory:"), - _("no limit")); - - vshPrint(ctl, "%-15s %lu KiB\n", _("Used memory:"), - info.memory); - - } else { - ret = false; - } - - /* Check and display whether the domain is persistent or not */ - persistent = virDomainIsPersistent(dom); - vshDebug(ctl, VSH_ERR_DEBUG, "Domain persistent flag value: %d\n", - persistent); - if (persistent < 0) - vshPrint(ctl, "%-15s %s\n", _("Persistent:"), _("unknown")); - else - vshPrint(ctl, "%-15s %s\n", _("Persistent:"), persistent ? _("yes") : _("no")); - - /* Check and display whether the domain autostarts or not */ - if (!virDomainGetAutostart(dom, &autostart)) { - vshPrint(ctl, "%-15s %s\n", _("Autostart:"), - autostart ? _("enable") : _("disable") ); - } - - has_managed_save = virDomainHasManagedSaveImage(dom, 0); - if (has_managed_save < 0) - vshPrint(ctl, "%-15s %s\n", _("Managed save:"), _("unknown")); - else - vshPrint(ctl, "%-15s %s\n", _("Managed save:"), - has_managed_save ? _("yes") : _("no")); - - /* Security model and label information */ - memset(&secmodel, 0, sizeof(secmodel)); - if (virNodeGetSecurityModel(ctl->conn, &secmodel) == -1) { - if (last_error->code != VIR_ERR_NO_SUPPORT) { - virDomainFree(dom); - return false; - } else { - virFreeError(last_error); - last_error = NULL; - } - } else { - /* Only print something if a security model is active */ - if (secmodel.model[0] != '\0') { - vshPrint(ctl, "%-15s %s\n", _("Security model:"), secmodel.model); - vshPrint(ctl, "%-15s %s\n", _("Security DOI:"), secmodel.doi); - - /* Security labels are only valid for active domains */ - if (VIR_ALLOC(seclabel) < 0) { - virDomainFree(dom); - return false; - } - - if (virDomainGetSecurityLabel(dom, seclabel) == -1) { - virDomainFree(dom); - VIR_FREE(seclabel); - return false; - } else { - if (seclabel->label[0] != '\0') - vshPrint(ctl, "%-15s %s (%s)\n", _("Security label:"), - seclabel->label, seclabel->enforcing ? "enforcing" : "permissive"); - } - - VIR_FREE(seclabel); - } - } - virDomainFree(dom); - return ret; -} - -/* * "domjobinfo" command */ static const vshCmdInfo info_domjobinfo[] = { @@ -17995,83 +16638,6 @@ cleanup: } /* - * "domblkerror" command - */ -static const char * -vshDomainIOErrorToString(int error) -{ - switch ((virDomainDiskErrorCode) error) { - case VIR_DOMAIN_DISK_ERROR_NONE: - return _("no error"); - case VIR_DOMAIN_DISK_ERROR_UNSPEC: - return _("unspecified error"); - case VIR_DOMAIN_DISK_ERROR_NO_SPACE: - return _("no space"); - case VIR_DOMAIN_DISK_ERROR_LAST: - ; - } - - return _("unknown error"); -} - -static const vshCmdInfo info_domblkerror[] = { - {"help", N_("Show errors on block devices")}, - {"desc", N_("Show block device errors")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_domblkerror[] = { - {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id, or uuid")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdDomBlkError(vshControl *ctl, const vshCmd *cmd) -{ - virDomainPtr dom; - virDomainDiskErrorPtr disks = NULL; - unsigned int ndisks; - int i; - int count; - bool ret = false; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (!(dom = vshCommandOptDomain(ctl, cmd, NULL))) - return false; - - if ((count = virDomainGetDiskErrors(dom, NULL, 0, 0)) < 0) - goto cleanup; - ndisks = count; - - if (ndisks) { - if (VIR_ALLOC_N(disks, ndisks) < 0) - goto cleanup; - - if ((count = virDomainGetDiskErrors(dom, disks, ndisks, 0)) == -1) - goto cleanup; - } - - if (count == 0) { - vshPrint(ctl, _("No errors found\n")); - } else { - for (i = 0; i < count; i++) { - vshPrint(ctl, "%s: %s\n", - disks[i].disk, - vshDomainIOErrorToString(disks[i].error)); - } - } - - ret = true; - -cleanup: - VIR_FREE(disks); - virDomainFree(dom); - return ret; -} - -/* * "qemu-monitor-command" command */ static const vshCmdInfo info_qemu_monitor_command[] = { @@ -19536,215 +18102,6 @@ vshDomainState(vshControl *ctl, virDomainPtr dom, int *reason) return info.state; } -static const char * -vshDomainStateToString(int state) -{ - /* Can't use virDomainStateTypeToString, because we want to mark - * strings for translation. */ - switch ((virDomainState) state) { - case VIR_DOMAIN_RUNNING: - return N_("running"); - case VIR_DOMAIN_BLOCKED: - return N_("idle"); - case VIR_DOMAIN_PAUSED: - return N_("paused"); - case VIR_DOMAIN_SHUTDOWN: - return N_("in shutdown"); - case VIR_DOMAIN_SHUTOFF: - return N_("shut off"); - case VIR_DOMAIN_CRASHED: - return N_("crashed"); - case VIR_DOMAIN_PMSUSPENDED: - return N_("pmsuspended"); - case VIR_DOMAIN_NOSTATE: - default: - ;/*FALLTHROUGH*/ - } - return N_("no state"); /* = dom0 state */ -} - -static const char * -vshDomainStateReasonToString(int state, int reason) -{ - switch ((virDomainState) state) { - case VIR_DOMAIN_NOSTATE: - switch ((virDomainNostateReason) reason) { - case VIR_DOMAIN_NOSTATE_UNKNOWN: - case VIR_DOMAIN_NOSTATE_LAST: - ; - } - break; - - case VIR_DOMAIN_RUNNING: - switch ((virDomainRunningReason) reason) { - case VIR_DOMAIN_RUNNING_BOOTED: - return N_("booted"); - case VIR_DOMAIN_RUNNING_MIGRATED: - return N_("migrated"); - case VIR_DOMAIN_RUNNING_RESTORED: - return N_("restored"); - case VIR_DOMAIN_RUNNING_FROM_SNAPSHOT: - return N_("from snapshot"); - case VIR_DOMAIN_RUNNING_UNPAUSED: - return N_("unpaused"); - case VIR_DOMAIN_RUNNING_MIGRATION_CANCELED: - return N_("migration canceled"); - case VIR_DOMAIN_RUNNING_SAVE_CANCELED: - return N_("save canceled"); - case VIR_DOMAIN_RUNNING_WAKEUP: - return N_("event wakeup"); - case VIR_DOMAIN_RUNNING_UNKNOWN: - case VIR_DOMAIN_RUNNING_LAST: - ; - } - break; - - case VIR_DOMAIN_BLOCKED: - switch ((virDomainBlockedReason) reason) { - case VIR_DOMAIN_BLOCKED_UNKNOWN: - case VIR_DOMAIN_BLOCKED_LAST: - ; - } - break; - - case VIR_DOMAIN_PAUSED: - switch ((virDomainPausedReason) reason) { - case VIR_DOMAIN_PAUSED_USER: - return N_("user"); - case VIR_DOMAIN_PAUSED_MIGRATION: - return N_("migrating"); - case VIR_DOMAIN_PAUSED_SAVE: - return N_("saving"); - case VIR_DOMAIN_PAUSED_DUMP: - return N_("dumping"); - case VIR_DOMAIN_PAUSED_IOERROR: - return N_("I/O error"); - case VIR_DOMAIN_PAUSED_WATCHDOG: - return N_("watchdog"); - case VIR_DOMAIN_PAUSED_FROM_SNAPSHOT: - return N_("from snapshot"); - case VIR_DOMAIN_PAUSED_SHUTTING_DOWN: - return N_("shutting down"); - case VIR_DOMAIN_PAUSED_UNKNOWN: - case VIR_DOMAIN_PAUSED_LAST: - ; - } - break; - - case VIR_DOMAIN_SHUTDOWN: - switch ((virDomainShutdownReason) reason) { - case VIR_DOMAIN_SHUTDOWN_USER: - return N_("user"); - case VIR_DOMAIN_SHUTDOWN_UNKNOWN: - case VIR_DOMAIN_SHUTDOWN_LAST: - ; - } - break; - - case VIR_DOMAIN_SHUTOFF: - switch ((virDomainShutoffReason) reason) { - case VIR_DOMAIN_SHUTOFF_SHUTDOWN: - return N_("shutdown"); - case VIR_DOMAIN_SHUTOFF_DESTROYED: - return N_("destroyed"); - case VIR_DOMAIN_SHUTOFF_CRASHED: - return N_("crashed"); - case VIR_DOMAIN_SHUTOFF_MIGRATED: - return N_("migrated"); - case VIR_DOMAIN_SHUTOFF_SAVED: - return N_("saved"); - case VIR_DOMAIN_SHUTOFF_FAILED: - return N_("failed"); - case VIR_DOMAIN_SHUTOFF_FROM_SNAPSHOT: - return N_("from snapshot"); - case VIR_DOMAIN_SHUTOFF_UNKNOWN: - case VIR_DOMAIN_SHUTOFF_LAST: - ; - } - break; - - case VIR_DOMAIN_CRASHED: - switch ((virDomainCrashedReason) reason) { - case VIR_DOMAIN_CRASHED_UNKNOWN: - case VIR_DOMAIN_CRASHED_LAST: - ; - } - break; - - case VIR_DOMAIN_PMSUSPENDED: - switch ((virDomainPMSuspendedReason) reason) { - case VIR_DOMAIN_PMSUSPENDED_UNKNOWN: - case VIR_DOMAIN_PMSUSPENDED_LAST: - ; - } - break; - - case VIR_DOMAIN_LAST: - ; - } - - return N_("unknown"); -} - -/* extract description or title from domain xml */ -static char * -vshGetDomainDescription(vshControl *ctl, virDomainPtr dom, bool title, - unsigned int flags) -{ - char *desc = NULL; - char *domxml = NULL; - virErrorPtr err = NULL; - xmlDocPtr doc = NULL; - xmlXPathContextPtr ctxt = NULL; - int type; - - if (title) - type = VIR_DOMAIN_METADATA_TITLE; - else - type = VIR_DOMAIN_METADATA_DESCRIPTION; - - if ((desc = virDomainGetMetadata(dom, type, NULL, flags))) { - return desc; - } else { - err = virGetLastError(); - - if (err && err->code == VIR_ERR_NO_DOMAIN_METADATA) { - desc = vshStrdup(ctl, ""); - virResetLastError(); - return desc; - } - - if (err && err->code != VIR_ERR_NO_SUPPORT) - return desc; - } - - /* fall back to xml */ - /* get domain's xml description and extract the title/description */ - if (!(domxml = virDomainGetXMLDesc(dom, flags))) { - vshError(ctl, "%s", _("Failed to retrieve domain XML")); - goto cleanup; - } - doc = virXMLParseStringCtxt(domxml, _("(domain_definition)"), &ctxt); - if (!doc) { - vshError(ctl, "%s", _("Couldn't parse domain XML")); - goto cleanup; - } - if (title) - desc = virXPathString("string(./title[1])", ctxt); - else - desc = virXPathString("string(./description[1])", ctxt); - - if (!desc) - desc = vshStrdup(ctl, ""); - -cleanup: - VIR_FREE(domxml); - xmlXPathFreeContext(ctxt); - xmlFreeDoc(doc); - - return desc; -} - /* Return a non-NULL string representation of a typed parameter; exit * if we are out of memory. */ static char * @@ -19814,25 +18171,6 @@ vshFindTypedParamByName(const char *name, virTypedParameterPtr list, int count) } static const char * -vshDomainControlStateToString(int state) -{ - switch ((virDomainControlState) state) { - case VIR_DOMAIN_CONTROL_OK: - return N_("ok"); - case VIR_DOMAIN_CONTROL_JOB: - return N_("background job"); - case VIR_DOMAIN_CONTROL_OCCUPIED: - return N_("occupied"); - case VIR_DOMAIN_CONTROL_ERROR: - return N_("error"); - default: - ; - } - - return N_("unknown"); -} - -static const char * vshDomainVcpuStateToString(int state) { switch (state) { @@ -20815,6 +19153,8 @@ static const vshCmdDef domManagementCmds[] = { {NULL, NULL, NULL, NULL, 0} }; +#include "virsh-domain-monitor.c" + static const vshCmdDef domMonitoringCmds[] = { {"domblkerror", cmdDomBlkError, opts_domblkerror, info_domblkerror, 0}, {"domblkinfo", cmdDomblkinfo, opts_domblkinfo, info_domblkinfo, 0}, -- 1.7.7.3

On 07/24/2012 11:18 AM, Osier Yang wrote:
This splits commands commands to monitor domain status into virsh-domain-monitor.c. The helpers not for common use are moved too. Standard copyright is added.
* tools/virsh.c: Remove commands for domain monitoring group and a few helpers ( vshDomainIOErrorToString, vshGetDomainDescription, vshDomainControlStateToString, vshDomainStateToString) not for common use.
* tools/virsh-domain-monitor.c: New file, filled with commands of domain monitor group. --- tools/virsh-domain-monitor.c | 1685 +++++++++++++++++++++++++++++++++++++ tools/virsh.c | 1904 +++--------------------------------------- 2 files changed, 1807 insertions(+), 1782 deletions(-) create mode 100644 tools/virsh-domain-monitor.c
diff --git a/tools/virsh-domain-monitor.c b/tools/virsh-domain-monitor.c new file mode 100644 index 0000000..1a61f62 --- /dev/null +++ b/tools/virsh-domain-monitor.c @@ -0,0 +1,1685 @@ +/* + * virsh-domain.c: Commands to monitor domain status
Wrong filename in the header, should be virsh-domain-monitor.c
+ * + * Copyright (C) 2005, 2007-2012 Red Hat, Inc [...] +cleanup: + VIR_FREE(domxml); + xmlXPathFreeContext(ctxt); + xmlFreeDoc(doc); + + return desc; +}
I'd add a empty line here for the sake of beauty.
+static const char * +vshDomainControlStateToString(int state) [...] +static const char * +vshDomainStateToString(int state) +{ + /* Can't use virDomainStateTypeToString, because we want to mark + * * strings for translation. */
This comment has weirdly shifted asterisk.
+ switch ((virDomainState) state) { [...] + +/* + * "dommemstats" command
Should be 'dommemstat' Also the order of the commands doesn't make much sense to me (it could be in the same order as the domMonitoringCmds struct). Apart from the tiny beauty nits (I'd give ACK with that), there is a problem with 'cfg.mk'. It specifies 'virsh.c' as one of the files with exception for strcasecmp() and this function gets copied into 'virsh-domain-monitor.c'. If this is done because of this particular occurrence, the file should be added to 'exclude_file_name_regexp--sc_avoid_strcase' in 'cfg.mk', otherwise make syntax-check will fail. Everything else is clean copy-paste, looks good, so ACK with at least the 'sytax-check' problem fixed. Martin

On 2012年07月25日 21:20, Martin Kletzander wrote:
On 07/24/2012 11:18 AM, Osier Yang wrote:
This splits commands commands to monitor domain status into virsh-domain-monitor.c. The helpers not for common use are moved too. Standard copyright is added.
* tools/virsh.c: Remove commands for domain monitoring group and a few helpers ( vshDomainIOErrorToString, vshGetDomainDescription, vshDomainControlStateToString, vshDomainStateToString) not for common use.
* tools/virsh-domain-monitor.c: New file, filled with commands of domain monitor group. --- tools/virsh-domain-monitor.c | 1685 +++++++++++++++++++++++++++++++++++++ tools/virsh.c | 1904 +++--------------------------------------- 2 files changed, 1807 insertions(+), 1782 deletions(-) create mode 100644 tools/virsh-domain-monitor.c
diff --git a/tools/virsh-domain-monitor.c b/tools/virsh-domain-monitor.c new file mode 100644 index 0000000..1a61f62 --- /dev/null +++ b/tools/virsh-domain-monitor.c @@ -0,0 +1,1685 @@ +/* + * virsh-domain.c: Commands to monitor domain status
Wrong filename in the header, should be virsh-domain-monitor.c
+ * + * Copyright (C) 2005, 2007-2012 Red Hat, Inc [...] +cleanup: + VIR_FREE(domxml); + xmlXPathFreeContext(ctxt); + xmlFreeDoc(doc); + + return desc; +}
I'd add a empty line here for the sake of beauty.
+static const char * +vshDomainControlStateToString(int state) [...] +static const char * +vshDomainStateToString(int state) +{ + /* Can't use virDomainStateTypeToString, because we want to mark + * * strings for translation. */
This comment has weirdly shifted asterisk.
+ switch ((virDomainState) state) { [...] + +/* + * "dommemstats" command
Should be 'dommemstat'
Also the order of the commands doesn't make much sense to me (it could be in the same order as the domMonitoringCmds struct).
Actually I tried to sort that. But I gave up quickly for it will take too much time. And honestly, it's boring.
Apart from the tiny beauty nits (I'd give ACK with that), there is a problem with 'cfg.mk'. It specifies 'virsh.c' as one of the files with exception for strcasecmp() and this function gets copied into 'virsh-domain-monitor.c'. If this is done because of this particular occurrence, the file should be added to 'exclude_file_name_regexp--sc_avoid_strcase' in 'cfg.mk', otherwise make syntax-check will fail.
Good catch, I did 'syntax-check', but not sure why I missed it.
Everything else is clean copy-paste, looks good, so ACK with at least the 'sytax-check' problem fixed.
Will fix those nits and the syntax-check failure when pushing ( after the whole set is acked). Thanks for the reviewing. Regards, Osier

This splits commands of storage volume group into virsh-volume.c, The helpers not for common use are moved too. Standard copyright is added for the new file. * tools/virsh.c: Remove commands for storage storage volume and a few helpers. (vshCommandOptVol, vshCommandOptVolBy). * tools/virsh-volume.c: New file, filled with commands of storage volume group and its helpers. --- tools/virsh-volume.c | 1440 +++++++++++++++++++++++++++++++++++++++++ tools/virsh.c | 1746 +++++--------------------------------------------- 2 files changed, 1595 insertions(+), 1591 deletions(-) create mode 100644 tools/virsh-volume.c diff --git a/tools/virsh-volume.c b/tools/virsh-volume.c new file mode 100644 index 0000000..6fb721e --- /dev/null +++ b/tools/virsh-volume.c @@ -0,0 +1,1440 @@ +/* + * virsh-volume.c: Commands to manage storage volume + * + * Copyright (C) 2005, 2007-2012 Red Hat, Inc + * + * 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 + * License along with this library; If not, see + * <http://www.gnu.org/licenses/>. + * + * Daniel Veillard <veillard@redhat.com> + * Karel Zak <kzak@redhat.com> + * Daniel P. Berrange <berrange@redhat.com> + * + */ + +/* default is lookup by Name and UUID */ +#define vshCommandOptVol(_ctl, _cmd, _optname, _pooloptname, _name) \ + vshCommandOptVolBy(_ctl, _cmd, _optname, _pooloptname, _name, \ + VSH_BYUUID|VSH_BYNAME) + +static virStorageVolPtr +vshCommandOptVolBy(vshControl *ctl, const vshCmd *cmd, + const char *optname, + const char *pooloptname, + const char **name, int flag) +{ + virStorageVolPtr vol = NULL; + virStoragePoolPtr pool = NULL; + const char *n = NULL, *p = NULL; + + if (vshCommandOptString(cmd, optname, &n) <= 0) + return NULL; + + if (pooloptname != NULL && vshCommandOptString(cmd, pooloptname, &p) < 0) { + vshError(ctl, "%s", _("missing option")); + return NULL; + } + + if (p) + pool = vshCommandOptPoolBy(ctl, cmd, pooloptname, name, flag); + + vshDebug(ctl, VSH_ERR_DEBUG, "%s: found option <%s>: %s\n", + cmd->def->name, optname, n); + + if (name) + *name = n; + + /* try it by name */ + if (pool && (flag & VSH_BYNAME)) { + vshDebug(ctl, VSH_ERR_DEBUG, "%s: <%s> trying as vol name\n", + cmd->def->name, optname); + vol = virStorageVolLookupByName(pool, n); + } + /* try it by key */ + if (vol == NULL && (flag & VSH_BYUUID)) { + vshDebug(ctl, VSH_ERR_DEBUG, "%s: <%s> trying as vol key\n", + cmd->def->name, optname); + vol = virStorageVolLookupByKey(ctl->conn, n); + } + /* try it by path */ + if (vol == NULL && (flag & VSH_BYUUID)) { + vshDebug(ctl, VSH_ERR_DEBUG, "%s: <%s> trying as vol path\n", + cmd->def->name, optname); + vol = virStorageVolLookupByPath(ctl->conn, n); + } + + if (!vol) { + if (pool) + vshError(ctl, _("failed to get vol '%s'"), n); + else + vshError(ctl, _("failed to get vol '%s', specifying --%s " + "might help"), n, pooloptname); + } + + if (pool) + virStoragePoolFree(pool); + + return vol; +} + +/* + * "vol-create-as" command + */ +static const vshCmdInfo info_vol_create_as[] = { + {"help", N_("create a volume from a set of args")}, + {"desc", N_("Create a vol.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_vol_create_as[] = { + {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name")}, + {"name", VSH_OT_DATA, VSH_OFLAG_REQ, N_("name of the volume")}, + {"capacity", VSH_OT_DATA, VSH_OFLAG_REQ, + N_("size of the vol, as scaled integer (default bytes)")}, + {"allocation", VSH_OT_STRING, 0, + N_("initial allocation size, as scaled integer (default bytes)")}, + {"format", VSH_OT_STRING, 0, + N_("file format type raw,bochs,qcow,qcow2,qed,vmdk")}, + {"backing-vol", VSH_OT_STRING, 0, + N_("the backing volume if taking a snapshot")}, + {"backing-vol-format", VSH_OT_STRING, 0, + N_("format of backing volume if taking a snapshot")}, + {NULL, 0, 0, NULL} +}; + +static int +vshVolSize(const char *data, unsigned long long *val) +{ + char *end; + if (virStrToLong_ull(data, &end, 10, val) < 0) + return -1; + return virScaleInteger(val, end, 1, ULLONG_MAX); +} + +static bool +cmdVolCreateAs(vshControl *ctl, const vshCmd *cmd) +{ + virStoragePoolPtr pool; + virStorageVolPtr vol; + char *xml; + const char *name, *capacityStr = NULL, *allocationStr = NULL, *format = NULL; + const char *snapshotStrVol = NULL, *snapshotStrFormat = NULL; + unsigned long long capacity, allocation = 0; + virBuffer buf = VIR_BUFFER_INITIALIZER; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(pool = vshCommandOptPoolBy(ctl, cmd, "pool", NULL, + VSH_BYNAME))) + return false; + + if (vshCommandOptString(cmd, "name", &name) <= 0) + goto cleanup; + + if (vshCommandOptString(cmd, "capacity", &capacityStr) <= 0) + goto cleanup; + + if (vshVolSize(capacityStr, &capacity) < 0) { + vshError(ctl, _("Malformed size %s"), capacityStr); + goto cleanup; + } + + if (vshCommandOptString(cmd, "allocation", &allocationStr) > 0 && + vshVolSize(allocationStr, &allocation) < 0) { + vshError(ctl, _("Malformed size %s"), allocationStr); + goto cleanup; + } + + if (vshCommandOptString(cmd, "format", &format) < 0 || + vshCommandOptString(cmd, "backing-vol", &snapshotStrVol) < 0 || + vshCommandOptString(cmd, "backing-vol-format", + &snapshotStrFormat) < 0) { + vshError(ctl, "%s", _("missing argument")); + goto cleanup; + } + + + virBufferAddLit(&buf, "<volume>\n"); + virBufferAsprintf(&buf, " <name>%s</name>\n", name); + virBufferAsprintf(&buf, " <capacity>%llu</capacity>\n", capacity); + if (allocationStr) + virBufferAsprintf(&buf, " <allocation>%llu</allocation>\n", allocation); + + if (format) { + virBufferAddLit(&buf, " <target>\n"); + virBufferAsprintf(&buf, " <format type='%s'/>\n",format); + virBufferAddLit(&buf, " </target>\n"); + } + + /* Convert the snapshot parameters into backingStore XML */ + if (snapshotStrVol) { + /* Lookup snapshot backing volume. Try the backing-vol + * parameter as a name */ + vshDebug(ctl, VSH_ERR_DEBUG, + "%s: Look up backing store volume '%s' as name\n", + cmd->def->name, snapshotStrVol); + virStorageVolPtr snapVol = virStorageVolLookupByName(pool, snapshotStrVol); + if (snapVol) + vshDebug(ctl, VSH_ERR_DEBUG, + "%s: Backing store volume found using '%s' as name\n", + cmd->def->name, snapshotStrVol); + + if (snapVol == NULL) { + /* Snapshot backing volume not found by name. Try the + * backing-vol parameter as a key */ + vshDebug(ctl, VSH_ERR_DEBUG, + "%s: Look up backing store volume '%s' as key\n", + cmd->def->name, snapshotStrVol); + snapVol = virStorageVolLookupByKey(ctl->conn, snapshotStrVol); + if (snapVol) + vshDebug(ctl, VSH_ERR_DEBUG, + "%s: Backing store volume found using '%s' as key\n", + cmd->def->name, snapshotStrVol); + } + if (snapVol == NULL) { + /* Snapshot backing volume not found by key. Try the + * backing-vol parameter as a path */ + vshDebug(ctl, VSH_ERR_DEBUG, + "%s: Look up backing store volume '%s' as path\n", + cmd->def->name, snapshotStrVol); + snapVol = virStorageVolLookupByPath(ctl->conn, snapshotStrVol); + if (snapVol) + vshDebug(ctl, VSH_ERR_DEBUG, + "%s: Backing store volume found using '%s' as path\n", + cmd->def->name, snapshotStrVol); + } + if (snapVol == NULL) { + vshError(ctl, _("failed to get vol '%s'"), snapshotStrVol); + goto cleanup; + } + + char *snapshotStrVolPath; + if ((snapshotStrVolPath = virStorageVolGetPath(snapVol)) == NULL) { + virStorageVolFree(snapVol); + goto cleanup; + } + + /* Create XML for the backing store */ + virBufferAddLit(&buf, " <backingStore>\n"); + virBufferAsprintf(&buf, " <path>%s</path>\n",snapshotStrVolPath); + if (snapshotStrFormat) + virBufferAsprintf(&buf, " <format type='%s'/>\n",snapshotStrFormat); + virBufferAddLit(&buf, " </backingStore>\n"); + + /* Cleanup snapshot allocations */ + VIR_FREE(snapshotStrVolPath); + virStorageVolFree(snapVol); + } + + virBufferAddLit(&buf, "</volume>\n"); + + if (virBufferError(&buf)) { + vshPrint(ctl, "%s", _("Failed to allocate XML buffer")); + goto cleanup; + } + xml = virBufferContentAndReset(&buf); + vol = virStorageVolCreateXML(pool, xml, 0); + VIR_FREE(xml); + virStoragePoolFree(pool); + + if (vol != NULL) { + vshPrint(ctl, _("Vol %s created\n"), name); + virStorageVolFree(vol); + return true; + } else { + vshError(ctl, _("Failed to create vol %s"), name); + return false; + } + + cleanup: + virBufferFreeAndReset(&buf); + virStoragePoolFree(pool); + return false; +} + +/* + * "vol-create" command + */ +static const vshCmdInfo info_vol_create[] = { + {"help", N_("create a vol from an XML file")}, + {"desc", N_("Create a vol.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_vol_create[] = { + {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name")}, + {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containing an XML vol description")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdVolCreate(vshControl *ctl, const vshCmd *cmd) +{ + virStoragePoolPtr pool; + virStorageVolPtr vol; + const char *from = NULL; + bool ret = true; + char *buffer; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(pool = vshCommandOptPoolBy(ctl, cmd, "pool", NULL, + VSH_BYNAME))) + return false; + + if (vshCommandOptString(cmd, "file", &from) <= 0) { + virStoragePoolFree(pool); + return false; + } + + if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0) { + virshReportError(ctl); + virStoragePoolFree(pool); + return false; + } + + vol = virStorageVolCreateXML(pool, buffer, 0); + VIR_FREE(buffer); + virStoragePoolFree(pool); + + if (vol != NULL) { + vshPrint(ctl, _("Vol %s created from %s\n"), + virStorageVolGetName(vol), from); + virStorageVolFree(vol); + } else { + vshError(ctl, _("Failed to create vol from %s"), from); + ret = false; + } + return ret; +} + +/* + * "vol-create-from" command + */ +static const vshCmdInfo info_vol_create_from[] = { + {"help", N_("create a vol, using another volume as input")}, + {"desc", N_("Create a vol from an existing volume.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_vol_create_from[] = { + {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")}, + {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containing an XML vol description")}, + {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("input vol name or key")}, + {"inputpool", VSH_OT_STRING, 0, N_("pool name or uuid of the input volume's pool")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdVolCreateFrom(vshControl *ctl, const vshCmd *cmd) +{ + virStoragePoolPtr pool = NULL; + virStorageVolPtr newvol = NULL, inputvol = NULL; + const char *from = NULL; + bool ret = false; + char *buffer = NULL; + + if (!vshConnectionUsability(ctl, ctl->conn)) + goto cleanup; + + if (!(pool = vshCommandOptPool(ctl, cmd, "pool", NULL))) + goto cleanup; + + if (vshCommandOptString(cmd, "file", &from) <= 0) { + goto cleanup; + } + + if (!(inputvol = vshCommandOptVol(ctl, cmd, "vol", "inputpool", NULL))) + goto cleanup; + + if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0) { + virshReportError(ctl); + goto cleanup; + } + + newvol = virStorageVolCreateXMLFrom(pool, buffer, inputvol, 0); + + if (newvol != NULL) { + vshPrint(ctl, _("Vol %s created from input vol %s\n"), + virStorageVolGetName(newvol), virStorageVolGetName(inputvol)); + } else { + vshError(ctl, _("Failed to create vol from %s"), from); + goto cleanup; + } + + ret = true; +cleanup: + VIR_FREE(buffer); + if (pool) + virStoragePoolFree(pool); + if (inputvol) + virStorageVolFree(inputvol); + if (newvol) + virStorageVolFree(newvol); + return ret; +} + +static xmlChar * +makeCloneXML(const char *origxml, const char *newname) +{ + + xmlDocPtr doc = NULL; + xmlXPathContextPtr ctxt = NULL; + xmlXPathObjectPtr obj = NULL; + xmlChar *newxml = NULL; + int size; + + doc = virXMLParseStringCtxt(origxml, _("(volume_definition)"), &ctxt); + if (!doc) + goto cleanup; + + obj = xmlXPathEval(BAD_CAST "/volume/name", ctxt); + if (obj == NULL || obj->nodesetval == NULL || + obj->nodesetval->nodeTab == NULL) + goto cleanup; + + xmlNodeSetContent(obj->nodesetval->nodeTab[0], (const xmlChar *)newname); + xmlDocDumpMemory(doc, &newxml, &size); + +cleanup: + xmlXPathFreeObject(obj); + xmlXPathFreeContext(ctxt); + xmlFreeDoc(doc); + return newxml; +} + +/* + * "vol-clone" command + */ +static const vshCmdInfo info_vol_clone[] = { + {"help", N_("clone a volume.")}, + {"desc", N_("Clone an existing volume.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_vol_clone[] = { + {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("orig vol name or key")}, + {"newname", VSH_OT_DATA, VSH_OFLAG_REQ, N_("clone name")}, + {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdVolClone(vshControl *ctl, const vshCmd *cmd) +{ + virStoragePoolPtr origpool = NULL; + virStorageVolPtr origvol = NULL, newvol = NULL; + const char *name = NULL; + char *origxml = NULL; + xmlChar *newxml = NULL; + bool ret = false; + + if (!vshConnectionUsability(ctl, ctl->conn)) + goto cleanup; + + if (!(origvol = vshCommandOptVol(ctl, cmd, "vol", "pool", NULL))) + goto cleanup; + + origpool = virStoragePoolLookupByVolume(origvol); + if (!origpool) { + vshError(ctl, "%s", _("failed to get parent pool")); + goto cleanup; + } + + if (vshCommandOptString(cmd, "newname", &name) <= 0) + goto cleanup; + + origxml = virStorageVolGetXMLDesc(origvol, 0); + if (!origxml) + goto cleanup; + + newxml = makeCloneXML(origxml, name); + if (!newxml) { + vshPrint(ctl, "%s", _("Failed to allocate XML buffer")); + goto cleanup; + } + + newvol = virStorageVolCreateXMLFrom(origpool, (char *) newxml, origvol, 0); + + if (newvol != NULL) { + vshPrint(ctl, _("Vol %s cloned from %s\n"), + virStorageVolGetName(newvol), virStorageVolGetName(origvol)); + } else { + vshError(ctl, _("Failed to clone vol from %s"), + virStorageVolGetName(origvol)); + goto cleanup; + } + + ret = true; + +cleanup: + VIR_FREE(origxml); + xmlFree(newxml); + if (origvol) + virStorageVolFree(origvol); + if (newvol) + virStorageVolFree(newvol); + if (origpool) + virStoragePoolFree(origpool); + return ret; +} + +/* + * "vol-upload" command + */ +static const vshCmdInfo info_vol_upload[] = { + {"help", N_("upload a file into a volume")}, + {"desc", N_("Upload a file into a volume")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_vol_upload[] = { + {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("vol name, key or path")}, + {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file")}, + {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")}, + {"offset", VSH_OT_INT, 0, N_("volume offset to upload to") }, + {"length", VSH_OT_INT, 0, N_("amount of data to upload") }, + {NULL, 0, 0, NULL} +}; + +static int +cmdVolUploadSource(virStreamPtr st ATTRIBUTE_UNUSED, + char *bytes, size_t nbytes, void *opaque) +{ + int *fd = opaque; + + return saferead(*fd, bytes, nbytes); +} + +static bool +cmdVolUpload(vshControl *ctl, const vshCmd *cmd) +{ + const char *file = NULL; + virStorageVolPtr vol = NULL; + bool ret = false; + int fd = -1; + virStreamPtr st = NULL; + const char *name = NULL; + unsigned long long offset = 0, length = 0; + + if (!vshConnectionUsability(ctl, ctl->conn)) + goto cleanup; + + if (vshCommandOptULongLong(cmd, "offset", &offset) < 0) { + vshError(ctl, _("Unable to parse integer")); + return false; + } + + if (vshCommandOptULongLong(cmd, "length", &length) < 0) { + vshError(ctl, _("Unable to parse integer")); + return false; + } + + if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", &name))) { + return false; + } + + if (vshCommandOptString(cmd, "file", &file) < 0) { + vshError(ctl, _("file must not be empty")); + goto cleanup; + } + + if ((fd = open(file, O_RDONLY)) < 0) { + vshError(ctl, _("cannot read %s"), file); + goto cleanup; + } + + st = virStreamNew(ctl->conn, 0); + if (virStorageVolUpload(vol, st, offset, length, 0) < 0) { + vshError(ctl, _("cannot upload to volume %s"), name); + goto cleanup; + } + + if (virStreamSendAll(st, cmdVolUploadSource, &fd) < 0) { + vshError(ctl, _("cannot send data to volume %s"), name); + goto cleanup; + } + + if (VIR_CLOSE(fd) < 0) { + vshError(ctl, _("cannot close file %s"), file); + virStreamAbort(st); + goto cleanup; + } + + if (virStreamFinish(st) < 0) { + vshError(ctl, _("cannot close volume %s"), name); + goto cleanup; + } + + ret = true; + +cleanup: + if (vol) + virStorageVolFree(vol); + if (st) + virStreamFree(st); + VIR_FORCE_CLOSE(fd); + return ret; +} + +/* + * "vol-download" command + */ +static const vshCmdInfo info_vol_download[] = { + {"help", N_("Download a volume to a file")}, + {"desc", N_("Download a volume to a file")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_vol_download[] = { + {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("vol name, key or path")}, + {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file")}, + {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")}, + {"offset", VSH_OT_INT, 0, N_("volume offset to download from") }, + {"length", VSH_OT_INT, 0, N_("amount of data to download") }, + {NULL, 0, 0, NULL} +}; + +static bool +cmdVolDownload(vshControl *ctl, const vshCmd *cmd) +{ + const char *file = NULL; + virStorageVolPtr vol = NULL; + bool ret = false; + int fd = -1; + virStreamPtr st = NULL; + const char *name = NULL; + unsigned long long offset = 0, length = 0; + bool created = false; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (vshCommandOptULongLong(cmd, "offset", &offset) < 0) { + vshError(ctl, _("Unable to parse integer")); + return false; + } + + if (vshCommandOptULongLong(cmd, "length", &length) < 0) { + vshError(ctl, _("Unable to parse integer")); + return false; + } + + if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", &name))) + return false; + + if (vshCommandOptString(cmd, "file", &file) < 0) { + vshError(ctl, _("file must not be empty")); + goto cleanup; + } + + if ((fd = open(file, O_WRONLY|O_CREAT|O_EXCL, 0666)) < 0) { + if (errno != EEXIST || + (fd = open(file, O_WRONLY|O_TRUNC, 0666)) < 0) { + vshError(ctl, _("cannot create %s"), file); + goto cleanup; + } + } else { + created = true; + } + + st = virStreamNew(ctl->conn, 0); + if (virStorageVolDownload(vol, st, offset, length, 0) < 0) { + vshError(ctl, _("cannot download from volume %s"), name); + goto cleanup; + } + + if (virStreamRecvAll(st, vshStreamSink, &fd) < 0) { + vshError(ctl, _("cannot receive data from volume %s"), name); + goto cleanup; + } + + if (VIR_CLOSE(fd) < 0) { + vshError(ctl, _("cannot close file %s"), file); + virStreamAbort(st); + goto cleanup; + } + + if (virStreamFinish(st) < 0) { + vshError(ctl, _("cannot close volume %s"), name); + goto cleanup; + } + + ret = true; + +cleanup: + VIR_FORCE_CLOSE(fd); + if (!ret && created) + unlink(file); + if (vol) + virStorageVolFree(vol); + if (st) + virStreamFree(st); + return ret; +} + +/* + * "vol-delete" command + */ +static const vshCmdInfo info_vol_delete[] = { + {"help", N_("delete a vol")}, + {"desc", N_("Delete a given vol.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_vol_delete[] = { + {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("vol name, key or path")}, + {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdVolDelete(vshControl *ctl, const vshCmd *cmd) +{ + virStorageVolPtr vol; + bool ret = true; + const char *name; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", &name))) { + return false; + } + + if (virStorageVolDelete(vol, 0) == 0) { + vshPrint(ctl, _("Vol %s deleted\n"), name); + } else { + vshError(ctl, _("Failed to delete vol %s"), name); + ret = false; + } + + virStorageVolFree(vol); + return ret; +} + +/* + * "vol-wipe" command + */ +static const vshCmdInfo info_vol_wipe[] = { + {"help", N_("wipe a vol")}, + {"desc", N_("Ensure data previously on a volume is not accessible to future reads")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_vol_wipe[] = { + {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("vol name, key or path")}, + {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")}, + {"algorithm", VSH_OT_STRING, 0, N_("perform selected wiping algorithm")}, + {NULL, 0, 0, NULL} +}; + +VIR_ENUM_DECL(virStorageVolWipeAlgorithm) +VIR_ENUM_IMPL(virStorageVolWipeAlgorithm, VIR_STORAGE_VOL_WIPE_ALG_LAST, + "zero", "nnsa", "dod", "bsi", "gutmann", "schneier", + "pfitzner7", "pfitzner33", "random"); + +static bool +cmdVolWipe(vshControl *ctl, const vshCmd *cmd) +{ + virStorageVolPtr vol; + bool ret = false; + const char *name; + const char *algorithm_str = NULL; + int algorithm = VIR_STORAGE_VOL_WIPE_ALG_ZERO; + int funcRet; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", &name))) { + return false; + } + + if (vshCommandOptString(cmd, "algorithm", &algorithm_str) < 0) { + vshError(ctl, "%s", _("missing argument")); + goto out; + } + + if (algorithm_str && + (algorithm = virStorageVolWipeAlgorithmTypeFromString(algorithm_str)) < 0) { + vshError(ctl, _("Unsupported algorithm '%s'"), algorithm_str); + goto out; + } + + if ((funcRet = virStorageVolWipePattern(vol, algorithm, 0)) < 0) { + if (last_error->code == VIR_ERR_NO_SUPPORT && + algorithm == VIR_STORAGE_VOL_WIPE_ALG_ZERO) + funcRet = virStorageVolWipe(vol, 0); + } + + if (funcRet < 0) { + vshError(ctl, _("Failed to wipe vol %s"), name); + goto out; + } + + vshPrint(ctl, _("Vol %s wiped\n"), name); + ret = true; +out: + virStorageVolFree(vol); + return ret; +} + +/* + * "vol-info" command + */ +static const vshCmdInfo info_vol_info[] = { + {"help", N_("storage vol information")}, + {"desc", N_("Returns basic information about the storage vol.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_vol_info[] = { + {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("vol name, key or path")}, + {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdVolInfo(vshControl *ctl, const vshCmd *cmd) +{ + virStorageVolInfo info; + virStorageVolPtr vol; + bool ret = true; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", NULL))) + return false; + + vshPrint(ctl, "%-15s %s\n", _("Name:"), virStorageVolGetName(vol)); + + if (virStorageVolGetInfo(vol, &info) == 0) { + double val; + const char *unit; + switch(info.type) { + case VIR_STORAGE_VOL_FILE: + vshPrint(ctl, "%-15s %s\n", _("Type:"), _("file")); + break; + + case VIR_STORAGE_VOL_BLOCK: + vshPrint(ctl, "%-15s %s\n", _("Type:"), _("block")); + break; + + case VIR_STORAGE_VOL_DIR: + vshPrint(ctl, "%-15s %s\n", _("Type:"), _("dir")); + break; + + case VIR_STORAGE_VOL_NETWORK: + vshPrint(ctl, "%-15s %s\n", _("Type:"), _("network")); + break; + + default: + vshPrint(ctl, "%-15s %s\n", _("Type:"), _("unknown")); + } + + val = prettyCapacity(info.capacity, &unit); + vshPrint(ctl, "%-15s %2.2lf %s\n", _("Capacity:"), val, unit); + + val = prettyCapacity(info.allocation, &unit); + vshPrint(ctl, "%-15s %2.2lf %s\n", _("Allocation:"), val, unit); + } else { + ret = false; + } + + virStorageVolFree(vol); + return ret; +} + +/* + * "vol-resize" command + */ +static const vshCmdInfo info_vol_resize[] = { + {"help", N_("resize a vol")}, + {"desc", N_("Resizes a storage volume.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_vol_resize[] = { + {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("vol name, key or path")}, + {"capacity", VSH_OT_DATA, VSH_OFLAG_REQ, + N_("new capacity for the vol, as scaled integer (default bytes)")}, + {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")}, + {"allocate", VSH_OT_BOOL, 0, + N_("allocate the new capacity, rather than leaving it sparse")}, + {"delta", VSH_OT_BOOL, 0, + N_("use capacity as a delta to current size, rather than the new size")}, + {"shrink", VSH_OT_BOOL, 0, N_("allow the resize to shrink the volume")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdVolResize(vshControl *ctl, const vshCmd *cmd) +{ + virStorageVolPtr vol; + const char *capacityStr = NULL; + unsigned long long capacity = 0; + unsigned int flags = 0; + bool ret = false; + bool delta = false; + + if (vshCommandOptBool(cmd, "allocate")) + flags |= VIR_STORAGE_VOL_RESIZE_ALLOCATE; + if (vshCommandOptBool(cmd, "delta")) { + delta = true; + flags |= VIR_STORAGE_VOL_RESIZE_DELTA; + } + if (vshCommandOptBool(cmd, "shrink")) + flags |= VIR_STORAGE_VOL_RESIZE_SHRINK; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", NULL))) + return false; + + if (vshCommandOptString(cmd, "capacity", &capacityStr) <= 0) + goto cleanup; + virSkipSpaces(&capacityStr); + if (*capacityStr == '-') { + /* The API always requires a positive value; but we allow a + * negative value for convenience. */ + if (delta && vshCommandOptBool(cmd, "shrink")){ + capacityStr++; + } else { + vshError(ctl, "%s", + _("negative size requires --delta and --shrink")); + goto cleanup; + } + } + if (vshVolSize(capacityStr, &capacity) < 0) { + vshError(ctl, _("Malformed size %s"), capacityStr); + goto cleanup; + } + + if (virStorageVolResize(vol, capacity, flags) == 0) { + vshPrint(ctl, + delta ? _("Size of volume '%s' successfully changed by %s\n") + : _("Size of volume '%s' successfully changed to %s\n"), + virStorageVolGetName(vol), capacityStr); + ret = true; + } else { + vshError(ctl, + delta ? _("Failed to change size of volume '%s' by %s\n") + : _("Failed to change size of volume '%s' to %s\n"), + virStorageVolGetName(vol), capacityStr); + ret = false; + } + +cleanup: + virStorageVolFree(vol); + return ret; +} + +/* + * "vol-dumpxml" command + */ +static const vshCmdInfo info_vol_dumpxml[] = { + {"help", N_("vol information in XML")}, + {"desc", N_("Output the vol information as an XML dump to stdout.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_vol_dumpxml[] = { + {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("vol name, key or path")}, + {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdVolDumpXML(vshControl *ctl, const vshCmd *cmd) +{ + virStorageVolPtr vol; + bool ret = true; + char *dump; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", NULL))) + return false; + + dump = virStorageVolGetXMLDesc(vol, 0); + if (dump != NULL) { + vshPrint(ctl, "%s", dump); + VIR_FREE(dump); + } else { + ret = false; + } + + virStorageVolFree(vol); + return ret; +} + +/* + * "vol-list" command + */ +static const vshCmdInfo info_vol_list[] = { + {"help", N_("list vols")}, + {"desc", N_("Returns list of vols by pool.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_vol_list[] = { + {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")}, + {"details", VSH_OT_BOOL, 0, N_("display extended details for volumes")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdVolList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) +{ + virStorageVolInfo volumeInfo; + virStoragePoolPtr pool; + char **activeNames = NULL; + char *outputStr = NULL; + const char *unit; + double val; + bool details = vshCommandOptBool(cmd, "details"); + int numVolumes = 0, i; + int ret; + bool functionReturn; + int stringLength = 0; + size_t allocStrLength = 0, capStrLength = 0; + size_t nameStrLength = 0, pathStrLength = 0; + size_t typeStrLength = 0; + struct volInfoText { + char *allocation; + char *capacity; + char *path; + char *type; + }; + struct volInfoText *volInfoTexts = NULL; + + /* Check the connection to libvirtd daemon is still working */ + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + /* Look up the pool information given to us by the user */ + if (!(pool = vshCommandOptPool(ctl, cmd, "pool", NULL))) + return false; + + /* Determine the number of volumes in the pool */ + numVolumes = virStoragePoolNumOfVolumes(pool); + + if (numVolumes < 0) { + vshError(ctl, "%s", _("Failed to list storage volumes")); + virStoragePoolFree(pool); + return false; + } + + /* Retrieve the list of volume names in the pool */ + if (numVolumes > 0) { + activeNames = vshCalloc(ctl, numVolumes, sizeof(*activeNames)); + if ((numVolumes = virStoragePoolListVolumes(pool, activeNames, + numVolumes)) < 0) { + vshError(ctl, "%s", _("Failed to list active vols")); + VIR_FREE(activeNames); + virStoragePoolFree(pool); + return false; + } + + /* Sort the volume names */ + qsort(&activeNames[0], numVolumes, sizeof(*activeNames), vshNameSorter); + + /* Set aside memory for volume information pointers */ + volInfoTexts = vshCalloc(ctl, numVolumes, sizeof(*volInfoTexts)); + } + + /* Collect the rest of the volume information for display */ + for (i = 0; i < numVolumes; i++) { + /* Retrieve volume info */ + virStorageVolPtr vol = virStorageVolLookupByName(pool, + activeNames[i]); + + /* Retrieve the volume path */ + if ((volInfoTexts[i].path = virStorageVolGetPath(vol)) == NULL) { + /* Something went wrong retrieving a volume path, cope with it */ + volInfoTexts[i].path = vshStrdup(ctl, _("unknown")); + } + + /* If requested, retrieve volume type and sizing information */ + if (details) { + if (virStorageVolGetInfo(vol, &volumeInfo) != 0) { + /* Something went wrong retrieving volume info, cope with it */ + volInfoTexts[i].allocation = vshStrdup(ctl, _("unknown")); + volInfoTexts[i].capacity = vshStrdup(ctl, _("unknown")); + volInfoTexts[i].type = vshStrdup(ctl, _("unknown")); + } else { + /* Convert the returned volume info into output strings */ + + /* Volume type */ + switch (volumeInfo.type) { + case VIR_STORAGE_VOL_FILE: + volInfoTexts[i].type = vshStrdup(ctl, _("file")); + break; + case VIR_STORAGE_VOL_BLOCK: + volInfoTexts[i].type = vshStrdup(ctl, _("block")); + break; + case VIR_STORAGE_VOL_DIR: + volInfoTexts[i].type = vshStrdup(ctl, _("dir")); + break; + default: + volInfoTexts[i].type = vshStrdup(ctl, _("unknown")); + } + + /* Create the capacity output string */ + val = prettyCapacity(volumeInfo.capacity, &unit); + ret = virAsprintf(&volInfoTexts[i].capacity, + "%.2lf %s", val, unit); + if (ret < 0) { + /* An error occurred creating the string, return */ + goto asprintf_failure; + } + + /* Create the allocation output string */ + val = prettyCapacity(volumeInfo.allocation, &unit); + ret = virAsprintf(&volInfoTexts[i].allocation, + "%.2lf %s", val, unit); + if (ret < 0) { + /* An error occurred creating the string, return */ + goto asprintf_failure; + } + } + + /* Remember the largest length for each output string. + * This lets us displaying header and volume information rows + * using a single, properly sized, printf style output string. + */ + + /* Keep the length of name string if longest so far */ + stringLength = strlen(activeNames[i]); + if (stringLength > nameStrLength) + nameStrLength = stringLength; + + /* Keep the length of path string if longest so far */ + stringLength = strlen(volInfoTexts[i].path); + if (stringLength > pathStrLength) + pathStrLength = stringLength; + + /* Keep the length of type string if longest so far */ + stringLength = strlen(volInfoTexts[i].type); + if (stringLength > typeStrLength) + typeStrLength = stringLength; + + /* Keep the length of capacity string if longest so far */ + stringLength = strlen(volInfoTexts[i].capacity); + if (stringLength > capStrLength) + capStrLength = stringLength; + + /* Keep the length of allocation string if longest so far */ + stringLength = strlen(volInfoTexts[i].allocation); + if (stringLength > allocStrLength) + allocStrLength = stringLength; + } + + /* Cleanup memory allocation */ + virStorageVolFree(vol); + } + + /* If the --details option wasn't selected, we output the volume + * info using the fixed string format from previous versions to + * maintain backward compatibility. + */ + + /* Output basic info then return if --details option not selected */ + if (!details) { + /* The old output format */ + vshPrintExtra(ctl, "%-20s %-40s\n", _("Name"), _("Path")); + vshPrintExtra(ctl, "-----------------------------------------\n"); + for (i = 0; i < numVolumes; i++) { + vshPrint(ctl, "%-20s %-40s\n", activeNames[i], + volInfoTexts[i].path); + } + + /* Cleanup and return */ + functionReturn = true; + goto cleanup; + } + + /* We only get here if the --details option was selected. */ + + /* Use the length of name header string if it's longest */ + stringLength = strlen(_("Name")); + if (stringLength > nameStrLength) + nameStrLength = stringLength; + + /* Use the length of path header string if it's longest */ + stringLength = strlen(_("Path")); + if (stringLength > pathStrLength) + pathStrLength = stringLength; + + /* Use the length of type header string if it's longest */ + stringLength = strlen(_("Type")); + if (stringLength > typeStrLength) + typeStrLength = stringLength; + + /* Use the length of capacity header string if it's longest */ + stringLength = strlen(_("Capacity")); + if (stringLength > capStrLength) + capStrLength = stringLength; + + /* Use the length of allocation header string if it's longest */ + stringLength = strlen(_("Allocation")); + if (stringLength > allocStrLength) + allocStrLength = stringLength; + + /* Display the string lengths for debugging */ + vshDebug(ctl, VSH_ERR_DEBUG, + "Longest name string = %zu chars\n", nameStrLength); + vshDebug(ctl, VSH_ERR_DEBUG, + "Longest path string = %zu chars\n", pathStrLength); + vshDebug(ctl, VSH_ERR_DEBUG, + "Longest type string = %zu chars\n", typeStrLength); + vshDebug(ctl, VSH_ERR_DEBUG, + "Longest capacity string = %zu chars\n", capStrLength); + vshDebug(ctl, VSH_ERR_DEBUG, + "Longest allocation string = %zu chars\n", allocStrLength); + + /* Create the output template */ + ret = virAsprintf(&outputStr, + "%%-%lus %%-%lus %%-%lus %%%lus %%%lus\n", + (unsigned long) nameStrLength, + (unsigned long) pathStrLength, + (unsigned long) typeStrLength, + (unsigned long) capStrLength, + (unsigned long) allocStrLength); + if (ret < 0) { + /* An error occurred creating the string, return */ + goto asprintf_failure; + } + + /* Display the header */ + vshPrint(ctl, outputStr, _("Name"), _("Path"), _("Type"), + ("Capacity"), _("Allocation")); + for (i = nameStrLength + pathStrLength + typeStrLength + + capStrLength + allocStrLength + + 8; i > 0; i--) + vshPrintExtra(ctl, "-"); + vshPrintExtra(ctl, "\n"); + + /* Display the volume info rows */ + for (i = 0; i < numVolumes; i++) { + vshPrint(ctl, outputStr, + activeNames[i], + volInfoTexts[i].path, + volInfoTexts[i].type, + volInfoTexts[i].capacity, + volInfoTexts[i].allocation); + } + + /* Cleanup and return */ + functionReturn = true; + goto cleanup; + +asprintf_failure: + + /* Display an appropriate error message then cleanup and return */ + switch (errno) { + case ENOMEM: + /* Couldn't allocate memory */ + vshError(ctl, "%s", _("Out of memory")); + break; + default: + /* Some other error */ + vshError(ctl, _("virAsprintf failed (errno %d)"), errno); + } + functionReturn = false; + +cleanup: + + /* Safely free the memory allocated in this function */ + for (i = 0; i < numVolumes; i++) { + /* Cleanup the memory for one volume info structure per loop */ + VIR_FREE(volInfoTexts[i].path); + VIR_FREE(volInfoTexts[i].type); + VIR_FREE(volInfoTexts[i].capacity); + VIR_FREE(volInfoTexts[i].allocation); + VIR_FREE(activeNames[i]); + } + + /* Cleanup remaining memory */ + VIR_FREE(outputStr); + VIR_FREE(volInfoTexts); + VIR_FREE(activeNames); + virStoragePoolFree(pool); + + /* Return the desired value */ + return functionReturn; +} + +/* + * "vol-name" command + */ +static const vshCmdInfo info_vol_name[] = { + {"help", N_("returns the volume name for a given volume key or path")}, + {"desc", ""}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_vol_name[] = { + {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("volume key or path")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdVolName(vshControl *ctl, const vshCmd *cmd) +{ + virStorageVolPtr vol; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(vol = vshCommandOptVolBy(ctl, cmd, "vol", NULL, NULL, + VSH_BYUUID))) + return false; + + vshPrint(ctl, "%s\n", virStorageVolGetName(vol)); + virStorageVolFree(vol); + return true; +} + +/* + * "vol-pool" command + */ +static const vshCmdInfo info_vol_pool[] = { + {"help", N_("returns the storage pool for a given volume key or path")}, + {"desc", ""}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_vol_pool[] = { + {"uuid", VSH_OT_BOOL, 0, N_("return the pool uuid rather than pool name")}, + {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("volume key or path")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdVolPool(vshControl *ctl, const vshCmd *cmd) +{ + virStoragePoolPtr pool; + virStorageVolPtr vol; + char uuid[VIR_UUID_STRING_BUFLEN]; + + /* Check the connection to libvirtd daemon is still working */ + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + /* Use the supplied string to locate the volume */ + if (!(vol = vshCommandOptVolBy(ctl, cmd, "vol", NULL, NULL, + VSH_BYUUID))) { + return false; + } + + /* Look up the parent storage pool for the volume */ + pool = virStoragePoolLookupByVolume(vol); + if (pool == NULL) { + vshError(ctl, "%s", _("failed to get parent pool")); + virStorageVolFree(vol); + return false; + } + + /* Return the requested details of the parent storage pool */ + if (vshCommandOptBool(cmd, "uuid")) { + /* Retrieve and return pool UUID string */ + if (virStoragePoolGetUUIDString(pool, &uuid[0]) == 0) + vshPrint(ctl, "%s\n", uuid); + } else { + /* Return the storage pool name */ + vshPrint(ctl, "%s\n", virStoragePoolGetName(pool)); + } + + /* Cleanup */ + virStorageVolFree(vol); + virStoragePoolFree(pool); + return true; +} + +/* + * "vol-key" command + */ +static const vshCmdInfo info_vol_key[] = { + {"help", N_("returns the volume key for a given volume name or path")}, + {"desc", ""}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_vol_key[] = { + {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("volume name or path")}, + {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdVolKey(vshControl *ctl, const vshCmd *cmd) +{ + virStorageVolPtr vol; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", NULL))) + return false; + + vshPrint(ctl, "%s\n", virStorageVolGetKey(vol)); + virStorageVolFree(vol); + return true; +} + +/* + * "vol-path" command + */ +static const vshCmdInfo info_vol_path[] = { + {"help", N_("returns the volume path for a given volume name or key")}, + {"desc", ""}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_vol_path[] = { + {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("volume name or key")}, + {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdVolPath(vshControl *ctl, const vshCmd *cmd) +{ + virStorageVolPtr vol; + char * StorageVolPath; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", NULL))) { + return false; + } + + if ((StorageVolPath = virStorageVolGetPath(vol)) == NULL) { + virStorageVolFree(vol); + return false; + } + + vshPrint(ctl, "%s\n", StorageVolPath); + VIR_FREE(StorageVolPath); + virStorageVolFree(vol); + return true; +} diff --git a/tools/virsh.c b/tools/virsh.c index e3ecd54..ac8ad09 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -372,16 +372,6 @@ static virStoragePoolPtr vshCommandOptPoolBy(vshControl *ctl, const vshCmd *cmd, vshCommandOptPoolBy(_ctl, _cmd, _optname, _name, \ VSH_BYUUID|VSH_BYNAME) -static virStorageVolPtr vshCommandOptVolBy(vshControl *ctl, const vshCmd *cmd, - const char *optname, - const char *pooloptname, - const char **name, int flag); - -/* default is lookup by Name and UUID */ -#define vshCommandOptVol(_ctl, _cmd, _optname, _pooloptname, _name) \ - vshCommandOptVolBy(_ctl, _cmd, _optname, _pooloptname, _name, \ - VSH_BYUUID|VSH_BYNAME) - static virSecretPtr vshCommandOptSecret(vshControl *ctl, const vshCmd *cmd, const char **name); @@ -4159,1632 +4149,264 @@ cmdPoolDiscoverSources(vshControl * ctl, const vshCmd * cmd ATTRIBUTE_UNUSED) return false; if (srcSpecFile && virFileReadAll(srcSpecFile, VIRSH_MAX_XML_FILE, &srcSpec) < 0) - return false; - - srcList = virConnectFindStoragePoolSources(ctl->conn, type, srcSpec, 0); - VIR_FREE(srcSpec); - if (srcList == NULL) { - vshError(ctl, _("Failed to find any %s pool sources"), type); - return false; - } - vshPrint(ctl, "%s", srcList); - VIR_FREE(srcList); - - return true; -} - - -/* - * "pool-info" command - */ -static const vshCmdInfo info_pool_info[] = { - {"help", N_("storage pool information")}, - {"desc", N_("Returns basic information about the storage pool.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_pool_info[] = { - {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdPoolInfo(vshControl *ctl, const vshCmd *cmd) -{ - virStoragePoolInfo info; - virStoragePoolPtr pool; - int autostart = 0; - int persistent = 0; - bool ret = true; - char uuid[VIR_UUID_STRING_BUFLEN]; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (!(pool = vshCommandOptPool(ctl, cmd, "pool", NULL))) - return false; - - vshPrint(ctl, "%-15s %s\n", _("Name:"), virStoragePoolGetName(pool)); - - if (virStoragePoolGetUUIDString(pool, &uuid[0])==0) - vshPrint(ctl, "%-15s %s\n", _("UUID:"), uuid); - - if (virStoragePoolGetInfo(pool, &info) == 0) { - double val; - const char *unit; - switch (info.state) { - case VIR_STORAGE_POOL_INACTIVE: - vshPrint(ctl, "%-15s %s\n", _("State:"), - _("inactive")); - break; - case VIR_STORAGE_POOL_BUILDING: - vshPrint(ctl, "%-15s %s\n", _("State:"), - _("building")); - break; - case VIR_STORAGE_POOL_RUNNING: - vshPrint(ctl, "%-15s %s\n", _("State:"), - _("running")); - break; - case VIR_STORAGE_POOL_DEGRADED: - vshPrint(ctl, "%-15s %s\n", _("State:"), - _("degraded")); - break; - case VIR_STORAGE_POOL_INACCESSIBLE: - vshPrint(ctl, "%-15s %s\n", _("State:"), - _("inaccessible")); - break; - } - - /* Check and display whether the pool is persistent or not */ - persistent = virStoragePoolIsPersistent(pool); - vshDebug(ctl, VSH_ERR_DEBUG, "Pool persistent flag value: %d\n", - persistent); - if (persistent < 0) - vshPrint(ctl, "%-15s %s\n", _("Persistent:"), _("unknown")); - else - vshPrint(ctl, "%-15s %s\n", _("Persistent:"), persistent ? _("yes") : _("no")); - - /* Check and display whether the pool is autostarted or not */ - virStoragePoolGetAutostart(pool, &autostart); - vshDebug(ctl, VSH_ERR_DEBUG, "Pool autostart flag value: %d\n", - autostart); - if (autostart < 0) - vshPrint(ctl, "%-15s %s\n", _("Autostart:"), _("no autostart")); - else - vshPrint(ctl, "%-15s %s\n", _("Autostart:"), autostart ? _("yes") : _("no")); - - if (info.state == VIR_STORAGE_POOL_RUNNING || - info.state == VIR_STORAGE_POOL_DEGRADED) { - val = prettyCapacity(info.capacity, &unit); - vshPrint(ctl, "%-15s %2.2lf %s\n", _("Capacity:"), val, unit); - - val = prettyCapacity(info.allocation, &unit); - vshPrint(ctl, "%-15s %2.2lf %s\n", _("Allocation:"), val, unit); - - val = prettyCapacity(info.available, &unit); - vshPrint(ctl, "%-15s %2.2lf %s\n", _("Available:"), val, unit); - } - } else { - ret = false; - } - - virStoragePoolFree(pool); - return ret; -} - - -/* - * "pool-name" command - */ -static const vshCmdInfo info_pool_name[] = { - {"help", N_("convert a pool UUID to pool name")}, - {"desc", ""}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_pool_name[] = { - {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool uuid")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdPoolName(vshControl *ctl, const vshCmd *cmd) -{ - virStoragePoolPtr pool; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - if (!(pool = vshCommandOptPoolBy(ctl, cmd, "pool", NULL, - VSH_BYUUID))) - return false; - - vshPrint(ctl, "%s\n", virStoragePoolGetName(pool)); - virStoragePoolFree(pool); - return true; -} - - -/* - * "pool-start" command - */ -static const vshCmdInfo info_pool_start[] = { - {"help", N_("start a (previously defined) inactive pool")}, - {"desc", N_("Start a pool.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_pool_start[] = { - {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("name or uuid of the inactive pool")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdPoolStart(vshControl *ctl, const vshCmd *cmd) -{ - virStoragePoolPtr pool; - bool ret = true; - const char *name = NULL; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (!(pool = vshCommandOptPool(ctl, cmd, "pool", &name))) - return false; - - if (virStoragePoolCreate(pool, 0) == 0) { - vshPrint(ctl, _("Pool %s started\n"), name); - } else { - vshError(ctl, _("Failed to start pool %s"), name); - ret = false; - } - - virStoragePoolFree(pool); - return ret; -} - - -/* - * "vol-create-as" command - */ -static const vshCmdInfo info_vol_create_as[] = { - {"help", N_("create a volume from a set of args")}, - {"desc", N_("Create a vol.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_vol_create_as[] = { - {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name")}, - {"name", VSH_OT_DATA, VSH_OFLAG_REQ, N_("name of the volume")}, - {"capacity", VSH_OT_DATA, VSH_OFLAG_REQ, - N_("size of the vol, as scaled integer (default bytes)")}, - {"allocation", VSH_OT_STRING, 0, - N_("initial allocation size, as scaled integer (default bytes)")}, - {"format", VSH_OT_STRING, 0, - N_("file format type raw,bochs,qcow,qcow2,qed,vmdk")}, - {"backing-vol", VSH_OT_STRING, 0, - N_("the backing volume if taking a snapshot")}, - {"backing-vol-format", VSH_OT_STRING, 0, - N_("format of backing volume if taking a snapshot")}, - {NULL, 0, 0, NULL} -}; - -static int -vshVolSize(const char *data, unsigned long long *val) -{ - char *end; - if (virStrToLong_ull(data, &end, 10, val) < 0) - return -1; - return virScaleInteger(val, end, 1, ULLONG_MAX); -} - -static bool -cmdVolCreateAs(vshControl *ctl, const vshCmd *cmd) -{ - virStoragePoolPtr pool; - virStorageVolPtr vol; - char *xml; - const char *name, *capacityStr = NULL, *allocationStr = NULL, *format = NULL; - const char *snapshotStrVol = NULL, *snapshotStrFormat = NULL; - unsigned long long capacity, allocation = 0; - virBuffer buf = VIR_BUFFER_INITIALIZER; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (!(pool = vshCommandOptPoolBy(ctl, cmd, "pool", NULL, - VSH_BYNAME))) - return false; - - if (vshCommandOptString(cmd, "name", &name) <= 0) - goto cleanup; - - if (vshCommandOptString(cmd, "capacity", &capacityStr) <= 0) - goto cleanup; - - if (vshVolSize(capacityStr, &capacity) < 0) { - vshError(ctl, _("Malformed size %s"), capacityStr); - goto cleanup; - } - - if (vshCommandOptString(cmd, "allocation", &allocationStr) > 0 && - vshVolSize(allocationStr, &allocation) < 0) { - vshError(ctl, _("Malformed size %s"), allocationStr); - goto cleanup; - } - - if (vshCommandOptString(cmd, "format", &format) < 0 || - vshCommandOptString(cmd, "backing-vol", &snapshotStrVol) < 0 || - vshCommandOptString(cmd, "backing-vol-format", - &snapshotStrFormat) < 0) { - vshError(ctl, "%s", _("missing argument")); - goto cleanup; - } - - - virBufferAddLit(&buf, "<volume>\n"); - virBufferAsprintf(&buf, " <name>%s</name>\n", name); - virBufferAsprintf(&buf, " <capacity>%llu</capacity>\n", capacity); - if (allocationStr) - virBufferAsprintf(&buf, " <allocation>%llu</allocation>\n", allocation); - - if (format) { - virBufferAddLit(&buf, " <target>\n"); - virBufferAsprintf(&buf, " <format type='%s'/>\n",format); - virBufferAddLit(&buf, " </target>\n"); - } - - /* Convert the snapshot parameters into backingStore XML */ - if (snapshotStrVol) { - /* Lookup snapshot backing volume. Try the backing-vol - * parameter as a name */ - vshDebug(ctl, VSH_ERR_DEBUG, - "%s: Look up backing store volume '%s' as name\n", - cmd->def->name, snapshotStrVol); - virStorageVolPtr snapVol = virStorageVolLookupByName(pool, snapshotStrVol); - if (snapVol) - vshDebug(ctl, VSH_ERR_DEBUG, - "%s: Backing store volume found using '%s' as name\n", - cmd->def->name, snapshotStrVol); - - if (snapVol == NULL) { - /* Snapshot backing volume not found by name. Try the - * backing-vol parameter as a key */ - vshDebug(ctl, VSH_ERR_DEBUG, - "%s: Look up backing store volume '%s' as key\n", - cmd->def->name, snapshotStrVol); - snapVol = virStorageVolLookupByKey(ctl->conn, snapshotStrVol); - if (snapVol) - vshDebug(ctl, VSH_ERR_DEBUG, - "%s: Backing store volume found using '%s' as key\n", - cmd->def->name, snapshotStrVol); - } - if (snapVol == NULL) { - /* Snapshot backing volume not found by key. Try the - * backing-vol parameter as a path */ - vshDebug(ctl, VSH_ERR_DEBUG, - "%s: Look up backing store volume '%s' as path\n", - cmd->def->name, snapshotStrVol); - snapVol = virStorageVolLookupByPath(ctl->conn, snapshotStrVol); - if (snapVol) - vshDebug(ctl, VSH_ERR_DEBUG, - "%s: Backing store volume found using '%s' as path\n", - cmd->def->name, snapshotStrVol); - } - if (snapVol == NULL) { - vshError(ctl, _("failed to get vol '%s'"), snapshotStrVol); - goto cleanup; - } - - char *snapshotStrVolPath; - if ((snapshotStrVolPath = virStorageVolGetPath(snapVol)) == NULL) { - virStorageVolFree(snapVol); - goto cleanup; - } - - /* Create XML for the backing store */ - virBufferAddLit(&buf, " <backingStore>\n"); - virBufferAsprintf(&buf, " <path>%s</path>\n",snapshotStrVolPath); - if (snapshotStrFormat) - virBufferAsprintf(&buf, " <format type='%s'/>\n",snapshotStrFormat); - virBufferAddLit(&buf, " </backingStore>\n"); - - /* Cleanup snapshot allocations */ - VIR_FREE(snapshotStrVolPath); - virStorageVolFree(snapVol); - } - - virBufferAddLit(&buf, "</volume>\n"); - - if (virBufferError(&buf)) { - vshPrint(ctl, "%s", _("Failed to allocate XML buffer")); - goto cleanup; - } - xml = virBufferContentAndReset(&buf); - vol = virStorageVolCreateXML(pool, xml, 0); - VIR_FREE(xml); - virStoragePoolFree(pool); - - if (vol != NULL) { - vshPrint(ctl, _("Vol %s created\n"), name); - virStorageVolFree(vol); - return true; - } else { - vshError(ctl, _("Failed to create vol %s"), name); - return false; - } - - cleanup: - virBufferFreeAndReset(&buf); - virStoragePoolFree(pool); - return false; -} - - -/* - * "pool-undefine" command - */ -static const vshCmdInfo info_pool_undefine[] = { - {"help", N_("undefine an inactive pool")}, - {"desc", N_("Undefine the configuration for an inactive pool.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_pool_undefine[] = { - {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdPoolUndefine(vshControl *ctl, const vshCmd *cmd) -{ - virStoragePoolPtr pool; - bool ret = true; - const char *name; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (!(pool = vshCommandOptPool(ctl, cmd, "pool", &name))) - return false; - - if (virStoragePoolUndefine(pool) == 0) { - vshPrint(ctl, _("Pool %s has been undefined\n"), name); - } else { - vshError(ctl, _("Failed to undefine pool %s"), name); - ret = false; - } - - virStoragePoolFree(pool); - return ret; -} - - -/* - * "pool-uuid" command - */ -static const vshCmdInfo info_pool_uuid[] = { - {"help", N_("convert a pool name to pool UUID")}, - {"desc", ""}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_pool_uuid[] = { - {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdPoolUuid(vshControl *ctl, const vshCmd *cmd) -{ - virStoragePoolPtr pool; - char uuid[VIR_UUID_STRING_BUFLEN]; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (!(pool = vshCommandOptPoolBy(ctl, cmd, "pool", NULL, - VSH_BYNAME))) - return false; - - if (virStoragePoolGetUUIDString(pool, uuid) != -1) - vshPrint(ctl, "%s\n", uuid); - else - vshError(ctl, "%s", _("failed to get pool UUID")); - - virStoragePoolFree(pool); - return true; -} - - -/* - * "vol-create" command - */ -static const vshCmdInfo info_vol_create[] = { - {"help", N_("create a vol from an XML file")}, - {"desc", N_("Create a vol.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_vol_create[] = { - {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name")}, - {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containing an XML vol description")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdVolCreate(vshControl *ctl, const vshCmd *cmd) -{ - virStoragePoolPtr pool; - virStorageVolPtr vol; - const char *from = NULL; - bool ret = true; - char *buffer; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (!(pool = vshCommandOptPoolBy(ctl, cmd, "pool", NULL, - VSH_BYNAME))) - return false; - - if (vshCommandOptString(cmd, "file", &from) <= 0) { - virStoragePoolFree(pool); - return false; - } - - if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0) { - virshReportError(ctl); - virStoragePoolFree(pool); - return false; - } - - vol = virStorageVolCreateXML(pool, buffer, 0); - VIR_FREE(buffer); - virStoragePoolFree(pool); - - if (vol != NULL) { - vshPrint(ctl, _("Vol %s created from %s\n"), - virStorageVolGetName(vol), from); - virStorageVolFree(vol); - } else { - vshError(ctl, _("Failed to create vol from %s"), from); - ret = false; - } - return ret; -} - -/* - * "vol-create-from" command - */ -static const vshCmdInfo info_vol_create_from[] = { - {"help", N_("create a vol, using another volume as input")}, - {"desc", N_("Create a vol from an existing volume.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_vol_create_from[] = { - {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")}, - {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containing an XML vol description")}, - {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("input vol name or key")}, - {"inputpool", VSH_OT_STRING, 0, N_("pool name or uuid of the input volume's pool")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdVolCreateFrom(vshControl *ctl, const vshCmd *cmd) -{ - virStoragePoolPtr pool = NULL; - virStorageVolPtr newvol = NULL, inputvol = NULL; - const char *from = NULL; - bool ret = false; - char *buffer = NULL; - - if (!vshConnectionUsability(ctl, ctl->conn)) - goto cleanup; - - if (!(pool = vshCommandOptPool(ctl, cmd, "pool", NULL))) - goto cleanup; - - if (vshCommandOptString(cmd, "file", &from) <= 0) { - goto cleanup; - } - - if (!(inputvol = vshCommandOptVol(ctl, cmd, "vol", "inputpool", NULL))) - goto cleanup; - - if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0) { - virshReportError(ctl); - goto cleanup; - } - - newvol = virStorageVolCreateXMLFrom(pool, buffer, inputvol, 0); - - if (newvol != NULL) { - vshPrint(ctl, _("Vol %s created from input vol %s\n"), - virStorageVolGetName(newvol), virStorageVolGetName(inputvol)); - } else { - vshError(ctl, _("Failed to create vol from %s"), from); - goto cleanup; - } - - ret = true; -cleanup: - VIR_FREE(buffer); - if (pool) - virStoragePoolFree(pool); - if (inputvol) - virStorageVolFree(inputvol); - if (newvol) - virStorageVolFree(newvol); - return ret; -} - -static xmlChar * -makeCloneXML(const char *origxml, const char *newname) -{ - - xmlDocPtr doc = NULL; - xmlXPathContextPtr ctxt = NULL; - xmlXPathObjectPtr obj = NULL; - xmlChar *newxml = NULL; - int size; - - doc = virXMLParseStringCtxt(origxml, _("(volume_definition)"), &ctxt); - if (!doc) - goto cleanup; - - obj = xmlXPathEval(BAD_CAST "/volume/name", ctxt); - if (obj == NULL || obj->nodesetval == NULL || - obj->nodesetval->nodeTab == NULL) - goto cleanup; - - xmlNodeSetContent(obj->nodesetval->nodeTab[0], (const xmlChar *)newname); - xmlDocDumpMemory(doc, &newxml, &size); - -cleanup: - xmlXPathFreeObject(obj); - xmlXPathFreeContext(ctxt); - xmlFreeDoc(doc); - return newxml; -} - -/* - * "vol-clone" command - */ -static const vshCmdInfo info_vol_clone[] = { - {"help", N_("clone a volume.")}, - {"desc", N_("Clone an existing volume.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_vol_clone[] = { - {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("orig vol name or key")}, - {"newname", VSH_OT_DATA, VSH_OFLAG_REQ, N_("clone name")}, - {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdVolClone(vshControl *ctl, const vshCmd *cmd) -{ - virStoragePoolPtr origpool = NULL; - virStorageVolPtr origvol = NULL, newvol = NULL; - const char *name = NULL; - char *origxml = NULL; - xmlChar *newxml = NULL; - bool ret = false; - - if (!vshConnectionUsability(ctl, ctl->conn)) - goto cleanup; - - if (!(origvol = vshCommandOptVol(ctl, cmd, "vol", "pool", NULL))) - goto cleanup; - - origpool = virStoragePoolLookupByVolume(origvol); - if (!origpool) { - vshError(ctl, "%s", _("failed to get parent pool")); - goto cleanup; - } - - if (vshCommandOptString(cmd, "newname", &name) <= 0) - goto cleanup; - - origxml = virStorageVolGetXMLDesc(origvol, 0); - if (!origxml) - goto cleanup; - - newxml = makeCloneXML(origxml, name); - if (!newxml) { - vshPrint(ctl, "%s", _("Failed to allocate XML buffer")); - goto cleanup; - } - - newvol = virStorageVolCreateXMLFrom(origpool, (char *) newxml, origvol, 0); - - if (newvol != NULL) { - vshPrint(ctl, _("Vol %s cloned from %s\n"), - virStorageVolGetName(newvol), virStorageVolGetName(origvol)); - } else { - vshError(ctl, _("Failed to clone vol from %s"), - virStorageVolGetName(origvol)); - goto cleanup; - } - - ret = true; - -cleanup: - VIR_FREE(origxml); - xmlFree(newxml); - if (origvol) - virStorageVolFree(origvol); - if (newvol) - virStorageVolFree(newvol); - if (origpool) - virStoragePoolFree(origpool); - return ret; -} - - -/* - * "vol-upload" command - */ -static const vshCmdInfo info_vol_upload[] = { - {"help", N_("upload a file into a volume")}, - {"desc", N_("Upload a file into a volume")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_vol_upload[] = { - {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("vol name, key or path")}, - {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file")}, - {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")}, - {"offset", VSH_OT_INT, 0, N_("volume offset to upload to") }, - {"length", VSH_OT_INT, 0, N_("amount of data to upload") }, - {NULL, 0, 0, NULL} -}; - -static int -cmdVolUploadSource(virStreamPtr st ATTRIBUTE_UNUSED, - char *bytes, size_t nbytes, void *opaque) -{ - int *fd = opaque; - - return saferead(*fd, bytes, nbytes); -} - -static bool -cmdVolUpload(vshControl *ctl, const vshCmd *cmd) -{ - const char *file = NULL; - virStorageVolPtr vol = NULL; - bool ret = false; - int fd = -1; - virStreamPtr st = NULL; - const char *name = NULL; - unsigned long long offset = 0, length = 0; - - if (!vshConnectionUsability(ctl, ctl->conn)) - goto cleanup; - - if (vshCommandOptULongLong(cmd, "offset", &offset) < 0) { - vshError(ctl, _("Unable to parse integer")); - return false; - } - - if (vshCommandOptULongLong(cmd, "length", &length) < 0) { - vshError(ctl, _("Unable to parse integer")); - return false; - } - - if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", &name))) { - return false; - } - - if (vshCommandOptString(cmd, "file", &file) < 0) { - vshError(ctl, _("file must not be empty")); - goto cleanup; - } - - if ((fd = open(file, O_RDONLY)) < 0) { - vshError(ctl, _("cannot read %s"), file); - goto cleanup; - } - - st = virStreamNew(ctl->conn, 0); - if (virStorageVolUpload(vol, st, offset, length, 0) < 0) { - vshError(ctl, _("cannot upload to volume %s"), name); - goto cleanup; - } - - if (virStreamSendAll(st, cmdVolUploadSource, &fd) < 0) { - vshError(ctl, _("cannot send data to volume %s"), name); - goto cleanup; - } - - if (VIR_CLOSE(fd) < 0) { - vshError(ctl, _("cannot close file %s"), file); - virStreamAbort(st); - goto cleanup; - } - - if (virStreamFinish(st) < 0) { - vshError(ctl, _("cannot close volume %s"), name); - goto cleanup; - } - - ret = true; - -cleanup: - if (vol) - virStorageVolFree(vol); - if (st) - virStreamFree(st); - VIR_FORCE_CLOSE(fd); - return ret; -} - - - -/* - * "vol-download" command - */ -static const vshCmdInfo info_vol_download[] = { - {"help", N_("Download a volume to a file")}, - {"desc", N_("Download a volume to a file")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_vol_download[] = { - {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("vol name, key or path")}, - {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file")}, - {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")}, - {"offset", VSH_OT_INT, 0, N_("volume offset to download from") }, - {"length", VSH_OT_INT, 0, N_("amount of data to download") }, - {NULL, 0, 0, NULL} -}; - -static bool -cmdVolDownload(vshControl *ctl, const vshCmd *cmd) -{ - const char *file = NULL; - virStorageVolPtr vol = NULL; - bool ret = false; - int fd = -1; - virStreamPtr st = NULL; - const char *name = NULL; - unsigned long long offset = 0, length = 0; - bool created = false; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (vshCommandOptULongLong(cmd, "offset", &offset) < 0) { - vshError(ctl, _("Unable to parse integer")); - return false; - } - - if (vshCommandOptULongLong(cmd, "length", &length) < 0) { - vshError(ctl, _("Unable to parse integer")); - return false; - } - - if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", &name))) - return false; - - if (vshCommandOptString(cmd, "file", &file) < 0) { - vshError(ctl, _("file must not be empty")); - goto cleanup; - } - - if ((fd = open(file, O_WRONLY|O_CREAT|O_EXCL, 0666)) < 0) { - if (errno != EEXIST || - (fd = open(file, O_WRONLY|O_TRUNC, 0666)) < 0) { - vshError(ctl, _("cannot create %s"), file); - goto cleanup; - } - } else { - created = true; - } - - st = virStreamNew(ctl->conn, 0); - if (virStorageVolDownload(vol, st, offset, length, 0) < 0) { - vshError(ctl, _("cannot download from volume %s"), name); - goto cleanup; - } - - if (virStreamRecvAll(st, vshStreamSink, &fd) < 0) { - vshError(ctl, _("cannot receive data from volume %s"), name); - goto cleanup; - } - - if (VIR_CLOSE(fd) < 0) { - vshError(ctl, _("cannot close file %s"), file); - virStreamAbort(st); - goto cleanup; - } - - if (virStreamFinish(st) < 0) { - vshError(ctl, _("cannot close volume %s"), name); - goto cleanup; - } - - ret = true; - -cleanup: - VIR_FORCE_CLOSE(fd); - if (!ret && created) - unlink(file); - if (vol) - virStorageVolFree(vol); - if (st) - virStreamFree(st); - return ret; -} - - -/* - * "vol-delete" command - */ -static const vshCmdInfo info_vol_delete[] = { - {"help", N_("delete a vol")}, - {"desc", N_("Delete a given vol.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_vol_delete[] = { - {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("vol name, key or path")}, - {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdVolDelete(vshControl *ctl, const vshCmd *cmd) -{ - virStorageVolPtr vol; - bool ret = true; - const char *name; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", &name))) { - return false; - } - - if (virStorageVolDelete(vol, 0) == 0) { - vshPrint(ctl, _("Vol %s deleted\n"), name); - } else { - vshError(ctl, _("Failed to delete vol %s"), name); - ret = false; - } - - virStorageVolFree(vol); - return ret; -} - - -/* - * "vol-wipe" command - */ -static const vshCmdInfo info_vol_wipe[] = { - {"help", N_("wipe a vol")}, - {"desc", N_("Ensure data previously on a volume is not accessible to future reads")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_vol_wipe[] = { - {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("vol name, key or path")}, - {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")}, - {"algorithm", VSH_OT_STRING, 0, N_("perform selected wiping algorithm")}, - {NULL, 0, 0, NULL} -}; - -VIR_ENUM_DECL(virStorageVolWipeAlgorithm) -VIR_ENUM_IMPL(virStorageVolWipeAlgorithm, VIR_STORAGE_VOL_WIPE_ALG_LAST, - "zero", "nnsa", "dod", "bsi", "gutmann", "schneier", - "pfitzner7", "pfitzner33", "random"); - -static bool -cmdVolWipe(vshControl *ctl, const vshCmd *cmd) -{ - virStorageVolPtr vol; - bool ret = false; - const char *name; - const char *algorithm_str = NULL; - int algorithm = VIR_STORAGE_VOL_WIPE_ALG_ZERO; - int funcRet; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", &name))) { - return false; - } - - if (vshCommandOptString(cmd, "algorithm", &algorithm_str) < 0) { - vshError(ctl, "%s", _("missing argument")); - goto out; - } - - if (algorithm_str && - (algorithm = virStorageVolWipeAlgorithmTypeFromString(algorithm_str)) < 0) { - vshError(ctl, _("Unsupported algorithm '%s'"), algorithm_str); - goto out; - } - - if ((funcRet = virStorageVolWipePattern(vol, algorithm, 0)) < 0) { - if (last_error->code == VIR_ERR_NO_SUPPORT && - algorithm == VIR_STORAGE_VOL_WIPE_ALG_ZERO) - funcRet = virStorageVolWipe(vol, 0); - } - - if (funcRet < 0) { - vshError(ctl, _("Failed to wipe vol %s"), name); - goto out; - } - - vshPrint(ctl, _("Vol %s wiped\n"), name); - ret = true; -out: - virStorageVolFree(vol); - return ret; -} - - -/* - * "vol-info" command - */ -static const vshCmdInfo info_vol_info[] = { - {"help", N_("storage vol information")}, - {"desc", N_("Returns basic information about the storage vol.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_vol_info[] = { - {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("vol name, key or path")}, - {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdVolInfo(vshControl *ctl, const vshCmd *cmd) -{ - virStorageVolInfo info; - virStorageVolPtr vol; - bool ret = true; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", NULL))) - return false; - - vshPrint(ctl, "%-15s %s\n", _("Name:"), virStorageVolGetName(vol)); - - if (virStorageVolGetInfo(vol, &info) == 0) { - double val; - const char *unit; - switch(info.type) { - case VIR_STORAGE_VOL_FILE: - vshPrint(ctl, "%-15s %s\n", _("Type:"), _("file")); - break; - - case VIR_STORAGE_VOL_BLOCK: - vshPrint(ctl, "%-15s %s\n", _("Type:"), _("block")); - break; - - case VIR_STORAGE_VOL_DIR: - vshPrint(ctl, "%-15s %s\n", _("Type:"), _("dir")); - break; - - case VIR_STORAGE_VOL_NETWORK: - vshPrint(ctl, "%-15s %s\n", _("Type:"), _("network")); - break; - - default: - vshPrint(ctl, "%-15s %s\n", _("Type:"), _("unknown")); - } - - val = prettyCapacity(info.capacity, &unit); - vshPrint(ctl, "%-15s %2.2lf %s\n", _("Capacity:"), val, unit); - - val = prettyCapacity(info.allocation, &unit); - vshPrint(ctl, "%-15s %2.2lf %s\n", _("Allocation:"), val, unit); - } else { - ret = false; - } - - virStorageVolFree(vol); - return ret; -} - -/* - * "vol-resize" command - */ -static const vshCmdInfo info_vol_resize[] = { - {"help", N_("resize a vol")}, - {"desc", N_("Resizes a storage volume.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_vol_resize[] = { - {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("vol name, key or path")}, - {"capacity", VSH_OT_DATA, VSH_OFLAG_REQ, - N_("new capacity for the vol, as scaled integer (default bytes)")}, - {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")}, - {"allocate", VSH_OT_BOOL, 0, - N_("allocate the new capacity, rather than leaving it sparse")}, - {"delta", VSH_OT_BOOL, 0, - N_("use capacity as a delta to current size, rather than the new size")}, - {"shrink", VSH_OT_BOOL, 0, N_("allow the resize to shrink the volume")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdVolResize(vshControl *ctl, const vshCmd *cmd) -{ - virStorageVolPtr vol; - const char *capacityStr = NULL; - unsigned long long capacity = 0; - unsigned int flags = 0; - bool ret = false; - bool delta = false; - - if (vshCommandOptBool(cmd, "allocate")) - flags |= VIR_STORAGE_VOL_RESIZE_ALLOCATE; - if (vshCommandOptBool(cmd, "delta")) { - delta = true; - flags |= VIR_STORAGE_VOL_RESIZE_DELTA; - } - if (vshCommandOptBool(cmd, "shrink")) - flags |= VIR_STORAGE_VOL_RESIZE_SHRINK; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", NULL))) - return false; - - if (vshCommandOptString(cmd, "capacity", &capacityStr) <= 0) - goto cleanup; - virSkipSpaces(&capacityStr); - if (*capacityStr == '-') { - /* The API always requires a positive value; but we allow a - * negative value for convenience. */ - if (delta && vshCommandOptBool(cmd, "shrink")){ - capacityStr++; - } else { - vshError(ctl, "%s", - _("negative size requires --delta and --shrink")); - goto cleanup; - } - } - if (vshVolSize(capacityStr, &capacity) < 0) { - vshError(ctl, _("Malformed size %s"), capacityStr); - goto cleanup; - } - - if (virStorageVolResize(vol, capacity, flags) == 0) { - vshPrint(ctl, - delta ? _("Size of volume '%s' successfully changed by %s\n") - : _("Size of volume '%s' successfully changed to %s\n"), - virStorageVolGetName(vol), capacityStr); - ret = true; - } else { - vshError(ctl, - delta ? _("Failed to change size of volume '%s' by %s\n") - : _("Failed to change size of volume '%s' to %s\n"), - virStorageVolGetName(vol), capacityStr); - ret = false; - } - -cleanup: - virStorageVolFree(vol); - return ret; -} - - -/* - * "vol-dumpxml" command - */ -static const vshCmdInfo info_vol_dumpxml[] = { - {"help", N_("vol information in XML")}, - {"desc", N_("Output the vol information as an XML dump to stdout.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_vol_dumpxml[] = { - {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("vol name, key or path")}, - {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdVolDumpXML(vshControl *ctl, const vshCmd *cmd) -{ - virStorageVolPtr vol; - bool ret = true; - char *dump; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", NULL))) - return false; - - dump = virStorageVolGetXMLDesc(vol, 0); - if (dump != NULL) { - vshPrint(ctl, "%s", dump); - VIR_FREE(dump); - } else { - ret = false; - } - - virStorageVolFree(vol); - return ret; -} - - -/* - * "vol-list" command - */ -static const vshCmdInfo info_vol_list[] = { - {"help", N_("list vols")}, - {"desc", N_("Returns list of vols by pool.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_vol_list[] = { - {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")}, - {"details", VSH_OT_BOOL, 0, N_("display extended details for volumes")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdVolList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) -{ - virStorageVolInfo volumeInfo; - virStoragePoolPtr pool; - char **activeNames = NULL; - char *outputStr = NULL; - const char *unit; - double val; - bool details = vshCommandOptBool(cmd, "details"); - int numVolumes = 0, i; - int ret; - bool functionReturn; - int stringLength = 0; - size_t allocStrLength = 0, capStrLength = 0; - size_t nameStrLength = 0, pathStrLength = 0; - size_t typeStrLength = 0; - struct volInfoText { - char *allocation; - char *capacity; - char *path; - char *type; - }; - struct volInfoText *volInfoTexts = NULL; - - /* Check the connection to libvirtd daemon is still working */ - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - /* Look up the pool information given to us by the user */ - if (!(pool = vshCommandOptPool(ctl, cmd, "pool", NULL))) - return false; - - /* Determine the number of volumes in the pool */ - numVolumes = virStoragePoolNumOfVolumes(pool); - - if (numVolumes < 0) { - vshError(ctl, "%s", _("Failed to list storage volumes")); - virStoragePoolFree(pool); - return false; - } - - /* Retrieve the list of volume names in the pool */ - if (numVolumes > 0) { - activeNames = vshCalloc(ctl, numVolumes, sizeof(*activeNames)); - if ((numVolumes = virStoragePoolListVolumes(pool, activeNames, - numVolumes)) < 0) { - vshError(ctl, "%s", _("Failed to list active vols")); - VIR_FREE(activeNames); - virStoragePoolFree(pool); - return false; - } - - /* Sort the volume names */ - qsort(&activeNames[0], numVolumes, sizeof(*activeNames), vshNameSorter); - - /* Set aside memory for volume information pointers */ - volInfoTexts = vshCalloc(ctl, numVolumes, sizeof(*volInfoTexts)); - } - - /* Collect the rest of the volume information for display */ - for (i = 0; i < numVolumes; i++) { - /* Retrieve volume info */ - virStorageVolPtr vol = virStorageVolLookupByName(pool, - activeNames[i]); - - /* Retrieve the volume path */ - if ((volInfoTexts[i].path = virStorageVolGetPath(vol)) == NULL) { - /* Something went wrong retrieving a volume path, cope with it */ - volInfoTexts[i].path = vshStrdup(ctl, _("unknown")); - } - - /* If requested, retrieve volume type and sizing information */ - if (details) { - if (virStorageVolGetInfo(vol, &volumeInfo) != 0) { - /* Something went wrong retrieving volume info, cope with it */ - volInfoTexts[i].allocation = vshStrdup(ctl, _("unknown")); - volInfoTexts[i].capacity = vshStrdup(ctl, _("unknown")); - volInfoTexts[i].type = vshStrdup(ctl, _("unknown")); - } else { - /* Convert the returned volume info into output strings */ - - /* Volume type */ - switch (volumeInfo.type) { - case VIR_STORAGE_VOL_FILE: - volInfoTexts[i].type = vshStrdup(ctl, _("file")); - break; - case VIR_STORAGE_VOL_BLOCK: - volInfoTexts[i].type = vshStrdup(ctl, _("block")); - break; - case VIR_STORAGE_VOL_DIR: - volInfoTexts[i].type = vshStrdup(ctl, _("dir")); - break; - default: - volInfoTexts[i].type = vshStrdup(ctl, _("unknown")); - } - - /* Create the capacity output string */ - val = prettyCapacity(volumeInfo.capacity, &unit); - ret = virAsprintf(&volInfoTexts[i].capacity, - "%.2lf %s", val, unit); - if (ret < 0) { - /* An error occurred creating the string, return */ - goto asprintf_failure; - } - - /* Create the allocation output string */ - val = prettyCapacity(volumeInfo.allocation, &unit); - ret = virAsprintf(&volInfoTexts[i].allocation, - "%.2lf %s", val, unit); - if (ret < 0) { - /* An error occurred creating the string, return */ - goto asprintf_failure; - } - } - - /* Remember the largest length for each output string. - * This lets us displaying header and volume information rows - * using a single, properly sized, printf style output string. - */ - - /* Keep the length of name string if longest so far */ - stringLength = strlen(activeNames[i]); - if (stringLength > nameStrLength) - nameStrLength = stringLength; - - /* Keep the length of path string if longest so far */ - stringLength = strlen(volInfoTexts[i].path); - if (stringLength > pathStrLength) - pathStrLength = stringLength; - - /* Keep the length of type string if longest so far */ - stringLength = strlen(volInfoTexts[i].type); - if (stringLength > typeStrLength) - typeStrLength = stringLength; - - /* Keep the length of capacity string if longest so far */ - stringLength = strlen(volInfoTexts[i].capacity); - if (stringLength > capStrLength) - capStrLength = stringLength; - - /* Keep the length of allocation string if longest so far */ - stringLength = strlen(volInfoTexts[i].allocation); - if (stringLength > allocStrLength) - allocStrLength = stringLength; - } - - /* Cleanup memory allocation */ - virStorageVolFree(vol); - } - - /* If the --details option wasn't selected, we output the volume - * info using the fixed string format from previous versions to - * maintain backward compatibility. - */ - - /* Output basic info then return if --details option not selected */ - if (!details) { - /* The old output format */ - vshPrintExtra(ctl, "%-20s %-40s\n", _("Name"), _("Path")); - vshPrintExtra(ctl, "-----------------------------------------\n"); - for (i = 0; i < numVolumes; i++) { - vshPrint(ctl, "%-20s %-40s\n", activeNames[i], - volInfoTexts[i].path); - } + return false; - /* Cleanup and return */ - functionReturn = true; - goto cleanup; + srcList = virConnectFindStoragePoolSources(ctl->conn, type, srcSpec, 0); + VIR_FREE(srcSpec); + if (srcList == NULL) { + vshError(ctl, _("Failed to find any %s pool sources"), type); + return false; } + vshPrint(ctl, "%s", srcList); + VIR_FREE(srcList); - /* We only get here if the --details option was selected. */ + return true; +} - /* Use the length of name header string if it's longest */ - stringLength = strlen(_("Name")); - if (stringLength > nameStrLength) - nameStrLength = stringLength; - /* Use the length of path header string if it's longest */ - stringLength = strlen(_("Path")); - if (stringLength > pathStrLength) - pathStrLength = stringLength; +/* + * "pool-info" command + */ +static const vshCmdInfo info_pool_info[] = { + {"help", N_("storage pool information")}, + {"desc", N_("Returns basic information about the storage pool.")}, + {NULL, NULL} +}; - /* Use the length of type header string if it's longest */ - stringLength = strlen(_("Type")); - if (stringLength > typeStrLength) - typeStrLength = stringLength; +static const vshCmdOptDef opts_pool_info[] = { + {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")}, + {NULL, 0, 0, NULL} +}; - /* Use the length of capacity header string if it's longest */ - stringLength = strlen(_("Capacity")); - if (stringLength > capStrLength) - capStrLength = stringLength; +static bool +cmdPoolInfo(vshControl *ctl, const vshCmd *cmd) +{ + virStoragePoolInfo info; + virStoragePoolPtr pool; + int autostart = 0; + int persistent = 0; + bool ret = true; + char uuid[VIR_UUID_STRING_BUFLEN]; - /* Use the length of allocation header string if it's longest */ - stringLength = strlen(_("Allocation")); - if (stringLength > allocStrLength) - allocStrLength = stringLength; + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; - /* Display the string lengths for debugging */ - vshDebug(ctl, VSH_ERR_DEBUG, - "Longest name string = %zu chars\n", nameStrLength); - vshDebug(ctl, VSH_ERR_DEBUG, - "Longest path string = %zu chars\n", pathStrLength); - vshDebug(ctl, VSH_ERR_DEBUG, - "Longest type string = %zu chars\n", typeStrLength); - vshDebug(ctl, VSH_ERR_DEBUG, - "Longest capacity string = %zu chars\n", capStrLength); - vshDebug(ctl, VSH_ERR_DEBUG, - "Longest allocation string = %zu chars\n", allocStrLength); + if (!(pool = vshCommandOptPool(ctl, cmd, "pool", NULL))) + return false; - /* Create the output template */ - ret = virAsprintf(&outputStr, - "%%-%lus %%-%lus %%-%lus %%%lus %%%lus\n", - (unsigned long) nameStrLength, - (unsigned long) pathStrLength, - (unsigned long) typeStrLength, - (unsigned long) capStrLength, - (unsigned long) allocStrLength); - if (ret < 0) { - /* An error occurred creating the string, return */ - goto asprintf_failure; - } + vshPrint(ctl, "%-15s %s\n", _("Name:"), virStoragePoolGetName(pool)); - /* Display the header */ - vshPrint(ctl, outputStr, _("Name"), _("Path"), _("Type"), - ("Capacity"), _("Allocation")); - for (i = nameStrLength + pathStrLength + typeStrLength - + capStrLength + allocStrLength - + 8; i > 0; i--) - vshPrintExtra(ctl, "-"); - vshPrintExtra(ctl, "\n"); + if (virStoragePoolGetUUIDString(pool, &uuid[0])==0) + vshPrint(ctl, "%-15s %s\n", _("UUID:"), uuid); - /* Display the volume info rows */ - for (i = 0; i < numVolumes; i++) { - vshPrint(ctl, outputStr, - activeNames[i], - volInfoTexts[i].path, - volInfoTexts[i].type, - volInfoTexts[i].capacity, - volInfoTexts[i].allocation); - } + if (virStoragePoolGetInfo(pool, &info) == 0) { + double val; + const char *unit; + switch (info.state) { + case VIR_STORAGE_POOL_INACTIVE: + vshPrint(ctl, "%-15s %s\n", _("State:"), + _("inactive")); + break; + case VIR_STORAGE_POOL_BUILDING: + vshPrint(ctl, "%-15s %s\n", _("State:"), + _("building")); + break; + case VIR_STORAGE_POOL_RUNNING: + vshPrint(ctl, "%-15s %s\n", _("State:"), + _("running")); + break; + case VIR_STORAGE_POOL_DEGRADED: + vshPrint(ctl, "%-15s %s\n", _("State:"), + _("degraded")); + break; + case VIR_STORAGE_POOL_INACCESSIBLE: + vshPrint(ctl, "%-15s %s\n", _("State:"), + _("inaccessible")); + break; + } - /* Cleanup and return */ - functionReturn = true; - goto cleanup; + /* Check and display whether the pool is persistent or not */ + persistent = virStoragePoolIsPersistent(pool); + vshDebug(ctl, VSH_ERR_DEBUG, "Pool persistent flag value: %d\n", + persistent); + if (persistent < 0) + vshPrint(ctl, "%-15s %s\n", _("Persistent:"), _("unknown")); + else + vshPrint(ctl, "%-15s %s\n", _("Persistent:"), persistent ? _("yes") : _("no")); -asprintf_failure: + /* Check and display whether the pool is autostarted or not */ + virStoragePoolGetAutostart(pool, &autostart); + vshDebug(ctl, VSH_ERR_DEBUG, "Pool autostart flag value: %d\n", + autostart); + if (autostart < 0) + vshPrint(ctl, "%-15s %s\n", _("Autostart:"), _("no autostart")); + else + vshPrint(ctl, "%-15s %s\n", _("Autostart:"), autostart ? _("yes") : _("no")); - /* Display an appropriate error message then cleanup and return */ - switch (errno) { - case ENOMEM: - /* Couldn't allocate memory */ - vshError(ctl, "%s", _("Out of memory")); - break; - default: - /* Some other error */ - vshError(ctl, _("virAsprintf failed (errno %d)"), errno); - } - functionReturn = false; + if (info.state == VIR_STORAGE_POOL_RUNNING || + info.state == VIR_STORAGE_POOL_DEGRADED) { + val = prettyCapacity(info.capacity, &unit); + vshPrint(ctl, "%-15s %2.2lf %s\n", _("Capacity:"), val, unit); -cleanup: + val = prettyCapacity(info.allocation, &unit); + vshPrint(ctl, "%-15s %2.2lf %s\n", _("Allocation:"), val, unit); - /* Safely free the memory allocated in this function */ - for (i = 0; i < numVolumes; i++) { - /* Cleanup the memory for one volume info structure per loop */ - VIR_FREE(volInfoTexts[i].path); - VIR_FREE(volInfoTexts[i].type); - VIR_FREE(volInfoTexts[i].capacity); - VIR_FREE(volInfoTexts[i].allocation); - VIR_FREE(activeNames[i]); + val = prettyCapacity(info.available, &unit); + vshPrint(ctl, "%-15s %2.2lf %s\n", _("Available:"), val, unit); + } + } else { + ret = false; } - /* Cleanup remaining memory */ - VIR_FREE(outputStr); - VIR_FREE(volInfoTexts); - VIR_FREE(activeNames); virStoragePoolFree(pool); - - /* Return the desired value */ - return functionReturn; + return ret; } /* - * "vol-name" command + * "pool-name" command */ -static const vshCmdInfo info_vol_name[] = { - {"help", N_("returns the volume name for a given volume key or path")}, +static const vshCmdInfo info_pool_name[] = { + {"help", N_("convert a pool UUID to pool name")}, {"desc", ""}, {NULL, NULL} }; -static const vshCmdOptDef opts_vol_name[] = { - {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("volume key or path")}, +static const vshCmdOptDef opts_pool_name[] = { + {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool uuid")}, {NULL, 0, 0, NULL} }; static bool -cmdVolName(vshControl *ctl, const vshCmd *cmd) +cmdPoolName(vshControl *ctl, const vshCmd *cmd) { - virStorageVolPtr vol; + virStoragePoolPtr pool; if (!vshConnectionUsability(ctl, ctl->conn)) return false; - - if (!(vol = vshCommandOptVolBy(ctl, cmd, "vol", NULL, NULL, - VSH_BYUUID))) + if (!(pool = vshCommandOptPoolBy(ctl, cmd, "pool", NULL, + VSH_BYUUID))) return false; - vshPrint(ctl, "%s\n", virStorageVolGetName(vol)); - virStorageVolFree(vol); + vshPrint(ctl, "%s\n", virStoragePoolGetName(pool)); + virStoragePoolFree(pool); return true; } /* - * "vol-pool" command + * "pool-start" command */ -static const vshCmdInfo info_vol_pool[] = { - {"help", N_("returns the storage pool for a given volume key or path")}, - {"desc", ""}, +static const vshCmdInfo info_pool_start[] = { + {"help", N_("start a (previously defined) inactive pool")}, + {"desc", N_("Start a pool.")}, {NULL, NULL} }; -static const vshCmdOptDef opts_vol_pool[] = { - {"uuid", VSH_OT_BOOL, 0, N_("return the pool uuid rather than pool name")}, - {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("volume key or path")}, +static const vshCmdOptDef opts_pool_start[] = { + {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("name or uuid of the inactive pool")}, {NULL, 0, 0, NULL} }; static bool -cmdVolPool(vshControl *ctl, const vshCmd *cmd) +cmdPoolStart(vshControl *ctl, const vshCmd *cmd) { virStoragePoolPtr pool; - virStorageVolPtr vol; - char uuid[VIR_UUID_STRING_BUFLEN]; + bool ret = true; + const char *name = NULL; - /* Check the connection to libvirtd daemon is still working */ if (!vshConnectionUsability(ctl, ctl->conn)) return false; - /* Use the supplied string to locate the volume */ - if (!(vol = vshCommandOptVolBy(ctl, cmd, "vol", NULL, NULL, - VSH_BYUUID))) { - return false; - } - - /* Look up the parent storage pool for the volume */ - pool = virStoragePoolLookupByVolume(vol); - if (pool == NULL) { - vshError(ctl, "%s", _("failed to get parent pool")); - virStorageVolFree(vol); - return false; - } + if (!(pool = vshCommandOptPool(ctl, cmd, "pool", &name))) + return false; - /* Return the requested details of the parent storage pool */ - if (vshCommandOptBool(cmd, "uuid")) { - /* Retrieve and return pool UUID string */ - if (virStoragePoolGetUUIDString(pool, &uuid[0]) == 0) - vshPrint(ctl, "%s\n", uuid); + if (virStoragePoolCreate(pool, 0) == 0) { + vshPrint(ctl, _("Pool %s started\n"), name); } else { - /* Return the storage pool name */ - vshPrint(ctl, "%s\n", virStoragePoolGetName(pool)); + vshError(ctl, _("Failed to start pool %s"), name); + ret = false; } - /* Cleanup */ - virStorageVolFree(vol); virStoragePoolFree(pool); - return true; + return ret; } - /* - * "vol-key" command + * "pool-undefine" command */ -static const vshCmdInfo info_vol_key[] = { - {"help", N_("returns the volume key for a given volume name or path")}, - {"desc", ""}, +static const vshCmdInfo info_pool_undefine[] = { + {"help", N_("undefine an inactive pool")}, + {"desc", N_("Undefine the configuration for an inactive pool.")}, {NULL, NULL} }; -static const vshCmdOptDef opts_vol_key[] = { - {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("volume name or path")}, - {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")}, +static const vshCmdOptDef opts_pool_undefine[] = { + {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")}, {NULL, 0, 0, NULL} }; static bool -cmdVolKey(vshControl *ctl, const vshCmd *cmd) +cmdPoolUndefine(vshControl *ctl, const vshCmd *cmd) { - virStorageVolPtr vol; + virStoragePoolPtr pool; + bool ret = true; + const char *name; if (!vshConnectionUsability(ctl, ctl->conn)) return false; - if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", NULL))) + if (!(pool = vshCommandOptPool(ctl, cmd, "pool", &name))) return false; - vshPrint(ctl, "%s\n", virStorageVolGetKey(vol)); - virStorageVolFree(vol); - return true; -} + if (virStoragePoolUndefine(pool) == 0) { + vshPrint(ctl, _("Pool %s has been undefined\n"), name); + } else { + vshError(ctl, _("Failed to undefine pool %s"), name); + ret = false; + } + virStoragePoolFree(pool); + return ret; +} /* - * "vol-path" command + * "pool-uuid" command */ -static const vshCmdInfo info_vol_path[] = { - {"help", N_("returns the volume path for a given volume name or key")}, +static const vshCmdInfo info_pool_uuid[] = { + {"help", N_("convert a pool name to pool UUID")}, {"desc", ""}, {NULL, NULL} }; -static const vshCmdOptDef opts_vol_path[] = { - {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("volume name or key")}, - {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")}, +static const vshCmdOptDef opts_pool_uuid[] = { + {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name")}, {NULL, 0, 0, NULL} }; static bool -cmdVolPath(vshControl *ctl, const vshCmd *cmd) +cmdPoolUuid(vshControl *ctl, const vshCmd *cmd) { - virStorageVolPtr vol; - char * StorageVolPath; + virStoragePoolPtr pool; + char uuid[VIR_UUID_STRING_BUFLEN]; if (!vshConnectionUsability(ctl, ctl->conn)) return false; - if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", NULL))) { + if (!(pool = vshCommandOptPoolBy(ctl, cmd, "pool", NULL, + VSH_BYNAME))) return false; - } - if ((StorageVolPath = virStorageVolGetPath(vol)) == NULL) { - virStorageVolFree(vol); - return false; - } + if (virStoragePoolGetUUIDString(pool, uuid) != -1) + vshPrint(ctl, "%s\n", uuid); + else + vshError(ctl, "%s", _("failed to get pool UUID")); - vshPrint(ctl, "%s\n", StorageVolPath); - VIR_FREE(StorageVolPath); - virStorageVolFree(vol); + virStoragePoolFree(pool); return true; } - /* * "secret-define" command */ @@ -9618,66 +8240,6 @@ vshCommandOptPoolBy(vshControl *ctl, const vshCmd *cmd, const char *optname, return pool; } -static virStorageVolPtr -vshCommandOptVolBy(vshControl *ctl, const vshCmd *cmd, - const char *optname, - const char *pooloptname, - const char **name, int flag) -{ - virStorageVolPtr vol = NULL; - virStoragePoolPtr pool = NULL; - const char *n = NULL, *p = NULL; - - if (vshCommandOptString(cmd, optname, &n) <= 0) - return NULL; - - if (pooloptname != NULL && vshCommandOptString(cmd, pooloptname, &p) < 0) { - vshError(ctl, "%s", _("missing option")); - return NULL; - } - - if (p) - pool = vshCommandOptPoolBy(ctl, cmd, pooloptname, name, flag); - - vshDebug(ctl, VSH_ERR_DEBUG, "%s: found option <%s>: %s\n", - cmd->def->name, optname, n); - - if (name) - *name = n; - - /* try it by name */ - if (pool && (flag & VSH_BYNAME)) { - vshDebug(ctl, VSH_ERR_DEBUG, "%s: <%s> trying as vol name\n", - cmd->def->name, optname); - vol = virStorageVolLookupByName(pool, n); - } - /* try it by key */ - if (vol == NULL && (flag & VSH_BYUUID)) { - vshDebug(ctl, VSH_ERR_DEBUG, "%s: <%s> trying as vol key\n", - cmd->def->name, optname); - vol = virStorageVolLookupByKey(ctl->conn, n); - } - /* try it by path */ - if (vol == NULL && (flag & VSH_BYUUID)) { - vshDebug(ctl, VSH_ERR_DEBUG, "%s: <%s> trying as vol path\n", - cmd->def->name, optname); - vol = virStorageVolLookupByPath(ctl->conn, n); - } - - if (!vol) { - if (pool) - vshError(ctl, _("failed to get vol '%s'"), n); - else - vshError(ctl, _("failed to get vol '%s', specifying --%s " - "might help"), n, pooloptname); - } - - if (pool) - virStoragePoolFree(pool); - - return vol; -} - static virSecretPtr vshCommandOptSecret(vshControl *ctl, const vshCmd *cmd, const char **name) { @@ -11171,6 +9733,8 @@ static const vshCmdDef storagePoolCmds[] = { {NULL, NULL, NULL, NULL, 0} }; +#include "virsh-volume.c" + static const vshCmdDef storageVolCmds[] = { {"vol-clone", cmdVolClone, opts_vol_clone, info_vol_clone, 0}, {"vol-create-as", cmdVolCreateAs, opts_vol_create_as, -- 1.7.7.3

On 07/24/2012 11:18 AM, Osier Yang wrote:
This splits commands of storage volume group into virsh-volume.c, The helpers not for common use are moved too. Standard copyright is added for the new file.
* tools/virsh.c: Remove commands for storage storage volume and a few helpers. (vshCommandOptVol, vshCommandOptVolBy).
* tools/virsh-volume.c: New file, filled with commands of storage volume group and its helpers. --- tools/virsh-volume.c | 1440 +++++++++++++++++++++++++++++++++++++++++ tools/virsh.c | 1746 +++++--------------------------------------------- 2 files changed, 1595 insertions(+), 1591 deletions(-) create mode 100644 tools/virsh-volume.c
diff --git a/tools/virsh-volume.c b/tools/virsh-volume.c new file mode 100644 index 0000000..6fb721e --- /dev/null +++ b/tools/virsh-volume.c @@ -0,0 +1,1440 @@ +/* + * virsh-volume.c: Commands to manage storage volume + * + * Copyright (C) 2005, 2007-2012 Red Hat, Inc + * + * 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 + * License along with this library; If not, see + * <http://www.gnu.org/licenses/>. + * + * Daniel Veillard <veillard@redhat.com> + * Karel Zak <kzak@redhat.com> + * Daniel P. Berrange <berrange@redhat.com> + * + */ + +/* default is lookup by Name and UUID */ +#define vshCommandOptVol(_ctl, _cmd, _optname, _pooloptname, _name) \ + vshCommandOptVolBy(_ctl, _cmd, _optname, _pooloptname, _name, \ + VSH_BYUUID|VSH_BYNAME) + +static virStorageVolPtr +vshCommandOptVolBy(vshControl *ctl, const vshCmd *cmd, + const char *optname, + const char *pooloptname, + const char **name, int flag) +{ + virStorageVolPtr vol = NULL; + virStoragePoolPtr pool = NULL; + const char *n = NULL, *p = NULL; + + if (vshCommandOptString(cmd, optname, &n) <= 0) + return NULL; + + if (pooloptname != NULL && vshCommandOptString(cmd, pooloptname, &p) < 0) { + vshError(ctl, "%s", _("missing option")); + return NULL; + } + + if (p) + pool = vshCommandOptPoolBy(ctl, cmd, pooloptname, name, flag); + + vshDebug(ctl, VSH_ERR_DEBUG, "%s: found option <%s>: %s\n", + cmd->def->name, optname, n); + + if (name) + *name = n; + + /* try it by name */ + if (pool && (flag & VSH_BYNAME)) { + vshDebug(ctl, VSH_ERR_DEBUG, "%s: <%s> trying as vol name\n", + cmd->def->name, optname); + vol = virStorageVolLookupByName(pool, n); + } + /* try it by key */ + if (vol == NULL && (flag & VSH_BYUUID)) { + vshDebug(ctl, VSH_ERR_DEBUG, "%s: <%s> trying as vol key\n", + cmd->def->name, optname); + vol = virStorageVolLookupByKey(ctl->conn, n); + } + /* try it by path */ + if (vol == NULL && (flag & VSH_BYUUID)) { + vshDebug(ctl, VSH_ERR_DEBUG, "%s: <%s> trying as vol path\n", + cmd->def->name, optname); + vol = virStorageVolLookupByPath(ctl->conn, n); + } + + if (!vol) { + if (pool) + vshError(ctl, _("failed to get vol '%s'"), n); + else + vshError(ctl, _("failed to get vol '%s', specifying --%s " + "might help"), n, pooloptname); + } + + if (pool) + virStoragePoolFree(pool); + + return vol; +} + +/* + * "vol-create-as" command + */ +static const vshCmdInfo info_vol_create_as[] = { + {"help", N_("create a volume from a set of args")}, + {"desc", N_("Create a vol.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_vol_create_as[] = { + {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name")}, + {"name", VSH_OT_DATA, VSH_OFLAG_REQ, N_("name of the volume")}, + {"capacity", VSH_OT_DATA, VSH_OFLAG_REQ, + N_("size of the vol, as scaled integer (default bytes)")}, + {"allocation", VSH_OT_STRING, 0, + N_("initial allocation size, as scaled integer (default bytes)")}, + {"format", VSH_OT_STRING, 0, + N_("file format type raw,bochs,qcow,qcow2,qed,vmdk")}, + {"backing-vol", VSH_OT_STRING, 0, + N_("the backing volume if taking a snapshot")}, + {"backing-vol-format", VSH_OT_STRING, 0, + N_("format of backing volume if taking a snapshot")}, + {NULL, 0, 0, NULL} +}; + +static int +vshVolSize(const char *data, unsigned long long *val) +{ + char *end; + if (virStrToLong_ull(data, &end, 10, val) < 0) + return -1; + return virScaleInteger(val, end, 1, ULLONG_MAX); +} + +static bool +cmdVolCreateAs(vshControl *ctl, const vshCmd *cmd) +{ + virStoragePoolPtr pool; + virStorageVolPtr vol; + char *xml; + const char *name, *capacityStr = NULL, *allocationStr = NULL, *format = NULL; + const char *snapshotStrVol = NULL, *snapshotStrFormat = NULL; + unsigned long long capacity, allocation = 0; + virBuffer buf = VIR_BUFFER_INITIALIZER; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(pool = vshCommandOptPoolBy(ctl, cmd, "pool", NULL, + VSH_BYNAME))) + return false; + + if (vshCommandOptString(cmd, "name", &name) <= 0) + goto cleanup; + + if (vshCommandOptString(cmd, "capacity", &capacityStr) <= 0) + goto cleanup; + + if (vshVolSize(capacityStr, &capacity) < 0) { + vshError(ctl, _("Malformed size %s"), capacityStr); + goto cleanup; + } + + if (vshCommandOptString(cmd, "allocation", &allocationStr) > 0 && + vshVolSize(allocationStr, &allocation) < 0) { + vshError(ctl, _("Malformed size %s"), allocationStr); + goto cleanup; + } + + if (vshCommandOptString(cmd, "format", &format) < 0 || + vshCommandOptString(cmd, "backing-vol", &snapshotStrVol) < 0 || + vshCommandOptString(cmd, "backing-vol-format", + &snapshotStrFormat) < 0) { + vshError(ctl, "%s", _("missing argument")); + goto cleanup; + } + + + virBufferAddLit(&buf, "<volume>\n"); + virBufferAsprintf(&buf, " <name>%s</name>\n", name); + virBufferAsprintf(&buf, " <capacity>%llu</capacity>\n", capacity); + if (allocationStr) + virBufferAsprintf(&buf, " <allocation>%llu</allocation>\n", allocation); + + if (format) { + virBufferAddLit(&buf, " <target>\n"); + virBufferAsprintf(&buf, " <format type='%s'/>\n",format); + virBufferAddLit(&buf, " </target>\n"); + } + + /* Convert the snapshot parameters into backingStore XML */ + if (snapshotStrVol) { + /* Lookup snapshot backing volume. Try the backing-vol + * parameter as a name */ + vshDebug(ctl, VSH_ERR_DEBUG, + "%s: Look up backing store volume '%s' as name\n", + cmd->def->name, snapshotStrVol); + virStorageVolPtr snapVol = virStorageVolLookupByName(pool, snapshotStrVol); + if (snapVol) + vshDebug(ctl, VSH_ERR_DEBUG, + "%s: Backing store volume found using '%s' as name\n", + cmd->def->name, snapshotStrVol); + + if (snapVol == NULL) { + /* Snapshot backing volume not found by name. Try the + * backing-vol parameter as a key */ + vshDebug(ctl, VSH_ERR_DEBUG, + "%s: Look up backing store volume '%s' as key\n", + cmd->def->name, snapshotStrVol); + snapVol = virStorageVolLookupByKey(ctl->conn, snapshotStrVol); + if (snapVol) + vshDebug(ctl, VSH_ERR_DEBUG, + "%s: Backing store volume found using '%s' as key\n", + cmd->def->name, snapshotStrVol); + } + if (snapVol == NULL) { + /* Snapshot backing volume not found by key. Try the + * backing-vol parameter as a path */ + vshDebug(ctl, VSH_ERR_DEBUG, + "%s: Look up backing store volume '%s' as path\n", + cmd->def->name, snapshotStrVol); + snapVol = virStorageVolLookupByPath(ctl->conn, snapshotStrVol); + if (snapVol) + vshDebug(ctl, VSH_ERR_DEBUG, + "%s: Backing store volume found using '%s' as path\n", + cmd->def->name, snapshotStrVol); + } + if (snapVol == NULL) { + vshError(ctl, _("failed to get vol '%s'"), snapshotStrVol); + goto cleanup; + } + + char *snapshotStrVolPath; + if ((snapshotStrVolPath = virStorageVolGetPath(snapVol)) == NULL) { + virStorageVolFree(snapVol); + goto cleanup; + } + + /* Create XML for the backing store */ + virBufferAddLit(&buf, " <backingStore>\n"); + virBufferAsprintf(&buf, " <path>%s</path>\n",snapshotStrVolPath); + if (snapshotStrFormat) + virBufferAsprintf(&buf, " <format type='%s'/>\n",snapshotStrFormat); + virBufferAddLit(&buf, " </backingStore>\n"); + + /* Cleanup snapshot allocations */ + VIR_FREE(snapshotStrVolPath); + virStorageVolFree(snapVol); + } + + virBufferAddLit(&buf, "</volume>\n"); + + if (virBufferError(&buf)) { + vshPrint(ctl, "%s", _("Failed to allocate XML buffer")); + goto cleanup; + } + xml = virBufferContentAndReset(&buf); + vol = virStorageVolCreateXML(pool, xml, 0); + VIR_FREE(xml); + virStoragePoolFree(pool); + + if (vol != NULL) { + vshPrint(ctl, _("Vol %s created\n"), name); + virStorageVolFree(vol); + return true; + } else { + vshError(ctl, _("Failed to create vol %s"), name); + return false; + } + + cleanup: + virBufferFreeAndReset(&buf); + virStoragePoolFree(pool); + return false; +} + +/* + * "vol-create" command + */ +static const vshCmdInfo info_vol_create[] = { + {"help", N_("create a vol from an XML file")}, + {"desc", N_("Create a vol.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_vol_create[] = { + {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name")}, + {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containing an XML vol description")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdVolCreate(vshControl *ctl, const vshCmd *cmd) +{ + virStoragePoolPtr pool; + virStorageVolPtr vol; + const char *from = NULL; + bool ret = true; + char *buffer; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(pool = vshCommandOptPoolBy(ctl, cmd, "pool", NULL, + VSH_BYNAME))) + return false; + + if (vshCommandOptString(cmd, "file", &from) <= 0) { + virStoragePoolFree(pool); + return false; + } + + if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0) { + virshReportError(ctl); + virStoragePoolFree(pool); + return false; + } + + vol = virStorageVolCreateXML(pool, buffer, 0); + VIR_FREE(buffer); + virStoragePoolFree(pool); + + if (vol != NULL) { + vshPrint(ctl, _("Vol %s created from %s\n"), + virStorageVolGetName(vol), from); + virStorageVolFree(vol); + } else { + vshError(ctl, _("Failed to create vol from %s"), from); + ret = false; + } + return ret; +} + +/* + * "vol-create-from" command + */ +static const vshCmdInfo info_vol_create_from[] = { + {"help", N_("create a vol, using another volume as input")}, + {"desc", N_("Create a vol from an existing volume.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_vol_create_from[] = { + {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")}, + {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containing an XML vol description")}, + {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("input vol name or key")}, + {"inputpool", VSH_OT_STRING, 0, N_("pool name or uuid of the input volume's pool")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdVolCreateFrom(vshControl *ctl, const vshCmd *cmd) +{ + virStoragePoolPtr pool = NULL; + virStorageVolPtr newvol = NULL, inputvol = NULL; + const char *from = NULL; + bool ret = false; + char *buffer = NULL; + + if (!vshConnectionUsability(ctl, ctl->conn)) + goto cleanup; + + if (!(pool = vshCommandOptPool(ctl, cmd, "pool", NULL))) + goto cleanup; + + if (vshCommandOptString(cmd, "file", &from) <= 0) { + goto cleanup; + } + + if (!(inputvol = vshCommandOptVol(ctl, cmd, "vol", "inputpool", NULL))) + goto cleanup; + + if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0) { + virshReportError(ctl); + goto cleanup; + } + + newvol = virStorageVolCreateXMLFrom(pool, buffer, inputvol, 0); + + if (newvol != NULL) { + vshPrint(ctl, _("Vol %s created from input vol %s\n"), + virStorageVolGetName(newvol), virStorageVolGetName(inputvol)); + } else { + vshError(ctl, _("Failed to create vol from %s"), from); + goto cleanup; + } + + ret = true; +cleanup: + VIR_FREE(buffer); + if (pool) + virStoragePoolFree(pool); + if (inputvol) + virStorageVolFree(inputvol); + if (newvol) + virStorageVolFree(newvol); + return ret; +} + +static xmlChar * +makeCloneXML(const char *origxml, const char *newname) +{ + + xmlDocPtr doc = NULL; + xmlXPathContextPtr ctxt = NULL; + xmlXPathObjectPtr obj = NULL; + xmlChar *newxml = NULL; + int size; + + doc = virXMLParseStringCtxt(origxml, _("(volume_definition)"), &ctxt); + if (!doc) + goto cleanup; + + obj = xmlXPathEval(BAD_CAST "/volume/name", ctxt); + if (obj == NULL || obj->nodesetval == NULL || + obj->nodesetval->nodeTab == NULL) + goto cleanup; + + xmlNodeSetContent(obj->nodesetval->nodeTab[0], (const xmlChar *)newname); + xmlDocDumpMemory(doc, &newxml, &size); + +cleanup: + xmlXPathFreeObject(obj); + xmlXPathFreeContext(ctxt); + xmlFreeDoc(doc); + return newxml; +} + +/* + * "vol-clone" command + */ +static const vshCmdInfo info_vol_clone[] = { + {"help", N_("clone a volume.")}, + {"desc", N_("Clone an existing volume.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_vol_clone[] = { + {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("orig vol name or key")}, + {"newname", VSH_OT_DATA, VSH_OFLAG_REQ, N_("clone name")}, + {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdVolClone(vshControl *ctl, const vshCmd *cmd) +{ + virStoragePoolPtr origpool = NULL; + virStorageVolPtr origvol = NULL, newvol = NULL; + const char *name = NULL; + char *origxml = NULL; + xmlChar *newxml = NULL; + bool ret = false; + + if (!vshConnectionUsability(ctl, ctl->conn)) + goto cleanup; + + if (!(origvol = vshCommandOptVol(ctl, cmd, "vol", "pool", NULL))) + goto cleanup; + + origpool = virStoragePoolLookupByVolume(origvol); + if (!origpool) { + vshError(ctl, "%s", _("failed to get parent pool")); + goto cleanup; + } + + if (vshCommandOptString(cmd, "newname", &name) <= 0) + goto cleanup; + + origxml = virStorageVolGetXMLDesc(origvol, 0); + if (!origxml) + goto cleanup; + + newxml = makeCloneXML(origxml, name); + if (!newxml) { + vshPrint(ctl, "%s", _("Failed to allocate XML buffer")); + goto cleanup; + } + + newvol = virStorageVolCreateXMLFrom(origpool, (char *) newxml, origvol, 0); + + if (newvol != NULL) { + vshPrint(ctl, _("Vol %s cloned from %s\n"), + virStorageVolGetName(newvol), virStorageVolGetName(origvol)); + } else { + vshError(ctl, _("Failed to clone vol from %s"), + virStorageVolGetName(origvol)); + goto cleanup; + } + + ret = true; + +cleanup: + VIR_FREE(origxml); + xmlFree(newxml); + if (origvol) + virStorageVolFree(origvol); + if (newvol) + virStorageVolFree(newvol); + if (origpool) + virStoragePoolFree(origpool); + return ret; +} + +/* + * "vol-upload" command + */ +static const vshCmdInfo info_vol_upload[] = { + {"help", N_("upload a file into a volume")}, + {"desc", N_("Upload a file into a volume")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_vol_upload[] = { + {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("vol name, key or path")}, + {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file")}, + {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")}, + {"offset", VSH_OT_INT, 0, N_("volume offset to upload to") }, + {"length", VSH_OT_INT, 0, N_("amount of data to upload") }, + {NULL, 0, 0, NULL} +}; + +static int +cmdVolUploadSource(virStreamPtr st ATTRIBUTE_UNUSED, + char *bytes, size_t nbytes, void *opaque) +{ + int *fd = opaque; + + return saferead(*fd, bytes, nbytes); +} + +static bool +cmdVolUpload(vshControl *ctl, const vshCmd *cmd) +{ + const char *file = NULL; + virStorageVolPtr vol = NULL; + bool ret = false; + int fd = -1; + virStreamPtr st = NULL; + const char *name = NULL; + unsigned long long offset = 0, length = 0; + + if (!vshConnectionUsability(ctl, ctl->conn)) + goto cleanup; + + if (vshCommandOptULongLong(cmd, "offset", &offset) < 0) { + vshError(ctl, _("Unable to parse integer")); + return false; + } + + if (vshCommandOptULongLong(cmd, "length", &length) < 0) { + vshError(ctl, _("Unable to parse integer")); + return false; + } + + if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", &name))) { + return false; + } + + if (vshCommandOptString(cmd, "file", &file) < 0) { + vshError(ctl, _("file must not be empty")); + goto cleanup; + } + + if ((fd = open(file, O_RDONLY)) < 0) { + vshError(ctl, _("cannot read %s"), file); + goto cleanup; + } + + st = virStreamNew(ctl->conn, 0); + if (virStorageVolUpload(vol, st, offset, length, 0) < 0) { + vshError(ctl, _("cannot upload to volume %s"), name); + goto cleanup; + } + + if (virStreamSendAll(st, cmdVolUploadSource, &fd) < 0) { + vshError(ctl, _("cannot send data to volume %s"), name); + goto cleanup; + } + + if (VIR_CLOSE(fd) < 0) { + vshError(ctl, _("cannot close file %s"), file); + virStreamAbort(st); + goto cleanup; + } + + if (virStreamFinish(st) < 0) { + vshError(ctl, _("cannot close volume %s"), name); + goto cleanup; + } + + ret = true; + +cleanup: + if (vol) + virStorageVolFree(vol); + if (st) + virStreamFree(st); + VIR_FORCE_CLOSE(fd); + return ret; +} + +/* + * "vol-download" command + */ +static const vshCmdInfo info_vol_download[] = { + {"help", N_("Download a volume to a file")}, + {"desc", N_("Download a volume to a file")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_vol_download[] = { + {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("vol name, key or path")}, + {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file")}, + {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")}, + {"offset", VSH_OT_INT, 0, N_("volume offset to download from") }, + {"length", VSH_OT_INT, 0, N_("amount of data to download") }, + {NULL, 0, 0, NULL} +}; + +static bool +cmdVolDownload(vshControl *ctl, const vshCmd *cmd) +{ + const char *file = NULL; + virStorageVolPtr vol = NULL; + bool ret = false; + int fd = -1; + virStreamPtr st = NULL; + const char *name = NULL; + unsigned long long offset = 0, length = 0; + bool created = false; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (vshCommandOptULongLong(cmd, "offset", &offset) < 0) { + vshError(ctl, _("Unable to parse integer")); + return false; + } + + if (vshCommandOptULongLong(cmd, "length", &length) < 0) { + vshError(ctl, _("Unable to parse integer")); + return false; + } + + if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", &name))) + return false; + + if (vshCommandOptString(cmd, "file", &file) < 0) { + vshError(ctl, _("file must not be empty")); + goto cleanup; + } + + if ((fd = open(file, O_WRONLY|O_CREAT|O_EXCL, 0666)) < 0) { + if (errno != EEXIST || + (fd = open(file, O_WRONLY|O_TRUNC, 0666)) < 0) { + vshError(ctl, _("cannot create %s"), file); + goto cleanup; + } + } else { + created = true; + } + + st = virStreamNew(ctl->conn, 0); + if (virStorageVolDownload(vol, st, offset, length, 0) < 0) { + vshError(ctl, _("cannot download from volume %s"), name); + goto cleanup; + } + + if (virStreamRecvAll(st, vshStreamSink, &fd) < 0) { + vshError(ctl, _("cannot receive data from volume %s"), name); + goto cleanup; + } + + if (VIR_CLOSE(fd) < 0) { + vshError(ctl, _("cannot close file %s"), file); + virStreamAbort(st); + goto cleanup; + } + + if (virStreamFinish(st) < 0) { + vshError(ctl, _("cannot close volume %s"), name); + goto cleanup; + } + + ret = true; + +cleanup: + VIR_FORCE_CLOSE(fd); + if (!ret && created) + unlink(file); + if (vol) + virStorageVolFree(vol); + if (st) + virStreamFree(st); + return ret; +} + +/* + * "vol-delete" command + */ +static const vshCmdInfo info_vol_delete[] = { + {"help", N_("delete a vol")}, + {"desc", N_("Delete a given vol.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_vol_delete[] = { + {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("vol name, key or path")}, + {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdVolDelete(vshControl *ctl, const vshCmd *cmd) +{ + virStorageVolPtr vol; + bool ret = true; + const char *name; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", &name))) { + return false; + } + + if (virStorageVolDelete(vol, 0) == 0) { + vshPrint(ctl, _("Vol %s deleted\n"), name); + } else { + vshError(ctl, _("Failed to delete vol %s"), name); + ret = false; + } + + virStorageVolFree(vol); + return ret; +} + +/* + * "vol-wipe" command + */ +static const vshCmdInfo info_vol_wipe[] = { + {"help", N_("wipe a vol")}, + {"desc", N_("Ensure data previously on a volume is not accessible to future reads")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_vol_wipe[] = { + {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("vol name, key or path")}, + {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")}, + {"algorithm", VSH_OT_STRING, 0, N_("perform selected wiping algorithm")}, + {NULL, 0, 0, NULL} +}; + +VIR_ENUM_DECL(virStorageVolWipeAlgorithm) +VIR_ENUM_IMPL(virStorageVolWipeAlgorithm, VIR_STORAGE_VOL_WIPE_ALG_LAST, + "zero", "nnsa", "dod", "bsi", "gutmann", "schneier", + "pfitzner7", "pfitzner33", "random"); + +static bool +cmdVolWipe(vshControl *ctl, const vshCmd *cmd) +{ + virStorageVolPtr vol; + bool ret = false; + const char *name; + const char *algorithm_str = NULL; + int algorithm = VIR_STORAGE_VOL_WIPE_ALG_ZERO; + int funcRet; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", &name))) { + return false; + } + + if (vshCommandOptString(cmd, "algorithm", &algorithm_str) < 0) { + vshError(ctl, "%s", _("missing argument")); + goto out; + } + + if (algorithm_str && + (algorithm = virStorageVolWipeAlgorithmTypeFromString(algorithm_str)) < 0) { + vshError(ctl, _("Unsupported algorithm '%s'"), algorithm_str); + goto out; + } + + if ((funcRet = virStorageVolWipePattern(vol, algorithm, 0)) < 0) { + if (last_error->code == VIR_ERR_NO_SUPPORT && + algorithm == VIR_STORAGE_VOL_WIPE_ALG_ZERO) + funcRet = virStorageVolWipe(vol, 0); + } + + if (funcRet < 0) { + vshError(ctl, _("Failed to wipe vol %s"), name); + goto out; + } + + vshPrint(ctl, _("Vol %s wiped\n"), name); + ret = true; +out: + virStorageVolFree(vol); + return ret; +} + +/* + * "vol-info" command + */ +static const vshCmdInfo info_vol_info[] = { + {"help", N_("storage vol information")}, + {"desc", N_("Returns basic information about the storage vol.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_vol_info[] = { + {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("vol name, key or path")}, + {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdVolInfo(vshControl *ctl, const vshCmd *cmd) +{ + virStorageVolInfo info; + virStorageVolPtr vol; + bool ret = true; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", NULL))) + return false; + + vshPrint(ctl, "%-15s %s\n", _("Name:"), virStorageVolGetName(vol)); + + if (virStorageVolGetInfo(vol, &info) == 0) { + double val; + const char *unit; + switch(info.type) { + case VIR_STORAGE_VOL_FILE: + vshPrint(ctl, "%-15s %s\n", _("Type:"), _("file")); + break; + + case VIR_STORAGE_VOL_BLOCK: + vshPrint(ctl, "%-15s %s\n", _("Type:"), _("block")); + break; + + case VIR_STORAGE_VOL_DIR: + vshPrint(ctl, "%-15s %s\n", _("Type:"), _("dir")); + break; + + case VIR_STORAGE_VOL_NETWORK: + vshPrint(ctl, "%-15s %s\n", _("Type:"), _("network")); + break; + + default: + vshPrint(ctl, "%-15s %s\n", _("Type:"), _("unknown")); + } + + val = prettyCapacity(info.capacity, &unit); + vshPrint(ctl, "%-15s %2.2lf %s\n", _("Capacity:"), val, unit); + + val = prettyCapacity(info.allocation, &unit); + vshPrint(ctl, "%-15s %2.2lf %s\n", _("Allocation:"), val, unit); + } else { + ret = false; + } + + virStorageVolFree(vol); + return ret; +} + +/* + * "vol-resize" command + */ +static const vshCmdInfo info_vol_resize[] = { + {"help", N_("resize a vol")}, + {"desc", N_("Resizes a storage volume.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_vol_resize[] = { + {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("vol name, key or path")}, + {"capacity", VSH_OT_DATA, VSH_OFLAG_REQ, + N_("new capacity for the vol, as scaled integer (default bytes)")}, + {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")}, + {"allocate", VSH_OT_BOOL, 0, + N_("allocate the new capacity, rather than leaving it sparse")}, + {"delta", VSH_OT_BOOL, 0, + N_("use capacity as a delta to current size, rather than the new size")}, + {"shrink", VSH_OT_BOOL, 0, N_("allow the resize to shrink the volume")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdVolResize(vshControl *ctl, const vshCmd *cmd) +{ + virStorageVolPtr vol; + const char *capacityStr = NULL; + unsigned long long capacity = 0; + unsigned int flags = 0; + bool ret = false; + bool delta = false; + + if (vshCommandOptBool(cmd, "allocate")) + flags |= VIR_STORAGE_VOL_RESIZE_ALLOCATE; + if (vshCommandOptBool(cmd, "delta")) { + delta = true; + flags |= VIR_STORAGE_VOL_RESIZE_DELTA; + } + if (vshCommandOptBool(cmd, "shrink")) + flags |= VIR_STORAGE_VOL_RESIZE_SHRINK; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", NULL))) + return false; + + if (vshCommandOptString(cmd, "capacity", &capacityStr) <= 0) + goto cleanup; + virSkipSpaces(&capacityStr); + if (*capacityStr == '-') { + /* The API always requires a positive value; but we allow a + * negative value for convenience. */ + if (delta && vshCommandOptBool(cmd, "shrink")){ + capacityStr++; + } else { + vshError(ctl, "%s", + _("negative size requires --delta and --shrink")); + goto cleanup; + } + } + if (vshVolSize(capacityStr, &capacity) < 0) { + vshError(ctl, _("Malformed size %s"), capacityStr); + goto cleanup; + } + + if (virStorageVolResize(vol, capacity, flags) == 0) { + vshPrint(ctl, + delta ? _("Size of volume '%s' successfully changed by %s\n") + : _("Size of volume '%s' successfully changed to %s\n"), + virStorageVolGetName(vol), capacityStr); + ret = true; + } else { + vshError(ctl, + delta ? _("Failed to change size of volume '%s' by %s\n") + : _("Failed to change size of volume '%s' to %s\n"), + virStorageVolGetName(vol), capacityStr); + ret = false; + } + +cleanup: + virStorageVolFree(vol); + return ret; +} + +/* + * "vol-dumpxml" command + */ +static const vshCmdInfo info_vol_dumpxml[] = { + {"help", N_("vol information in XML")}, + {"desc", N_("Output the vol information as an XML dump to stdout.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_vol_dumpxml[] = { + {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("vol name, key or path")}, + {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdVolDumpXML(vshControl *ctl, const vshCmd *cmd) +{ + virStorageVolPtr vol; + bool ret = true; + char *dump; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", NULL))) + return false; + + dump = virStorageVolGetXMLDesc(vol, 0); + if (dump != NULL) { + vshPrint(ctl, "%s", dump); + VIR_FREE(dump); + } else { + ret = false; + } + + virStorageVolFree(vol); + return ret; +} + +/* + * "vol-list" command + */ +static const vshCmdInfo info_vol_list[] = { + {"help", N_("list vols")}, + {"desc", N_("Returns list of vols by pool.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_vol_list[] = { + {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")}, + {"details", VSH_OT_BOOL, 0, N_("display extended details for volumes")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdVolList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) +{ + virStorageVolInfo volumeInfo; + virStoragePoolPtr pool; + char **activeNames = NULL; + char *outputStr = NULL; + const char *unit; + double val; + bool details = vshCommandOptBool(cmd, "details"); + int numVolumes = 0, i; + int ret; + bool functionReturn; + int stringLength = 0; + size_t allocStrLength = 0, capStrLength = 0; + size_t nameStrLength = 0, pathStrLength = 0; + size_t typeStrLength = 0; + struct volInfoText { + char *allocation; + char *capacity; + char *path; + char *type; + }; + struct volInfoText *volInfoTexts = NULL; + + /* Check the connection to libvirtd daemon is still working */ + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + /* Look up the pool information given to us by the user */ + if (!(pool = vshCommandOptPool(ctl, cmd, "pool", NULL))) + return false; + + /* Determine the number of volumes in the pool */ + numVolumes = virStoragePoolNumOfVolumes(pool); + + if (numVolumes < 0) { + vshError(ctl, "%s", _("Failed to list storage volumes")); + virStoragePoolFree(pool); + return false; + } + + /* Retrieve the list of volume names in the pool */ + if (numVolumes > 0) { + activeNames = vshCalloc(ctl, numVolumes, sizeof(*activeNames)); + if ((numVolumes = virStoragePoolListVolumes(pool, activeNames, + numVolumes)) < 0) { + vshError(ctl, "%s", _("Failed to list active vols")); + VIR_FREE(activeNames); + virStoragePoolFree(pool); + return false; + } + + /* Sort the volume names */ + qsort(&activeNames[0], numVolumes, sizeof(*activeNames), vshNameSorter); + + /* Set aside memory for volume information pointers */ + volInfoTexts = vshCalloc(ctl, numVolumes, sizeof(*volInfoTexts)); + } + + /* Collect the rest of the volume information for display */ + for (i = 0; i < numVolumes; i++) { + /* Retrieve volume info */ + virStorageVolPtr vol = virStorageVolLookupByName(pool, + activeNames[i]); + + /* Retrieve the volume path */ + if ((volInfoTexts[i].path = virStorageVolGetPath(vol)) == NULL) { + /* Something went wrong retrieving a volume path, cope with it */ + volInfoTexts[i].path = vshStrdup(ctl, _("unknown")); + } + + /* If requested, retrieve volume type and sizing information */ + if (details) { + if (virStorageVolGetInfo(vol, &volumeInfo) != 0) { + /* Something went wrong retrieving volume info, cope with it */ + volInfoTexts[i].allocation = vshStrdup(ctl, _("unknown")); + volInfoTexts[i].capacity = vshStrdup(ctl, _("unknown")); + volInfoTexts[i].type = vshStrdup(ctl, _("unknown")); + } else { + /* Convert the returned volume info into output strings */ + + /* Volume type */ + switch (volumeInfo.type) { + case VIR_STORAGE_VOL_FILE: + volInfoTexts[i].type = vshStrdup(ctl, _("file")); + break; + case VIR_STORAGE_VOL_BLOCK: + volInfoTexts[i].type = vshStrdup(ctl, _("block")); + break; + case VIR_STORAGE_VOL_DIR: + volInfoTexts[i].type = vshStrdup(ctl, _("dir")); + break; + default: + volInfoTexts[i].type = vshStrdup(ctl, _("unknown")); + } + + /* Create the capacity output string */ + val = prettyCapacity(volumeInfo.capacity, &unit); + ret = virAsprintf(&volInfoTexts[i].capacity, + "%.2lf %s", val, unit); + if (ret < 0) { + /* An error occurred creating the string, return */ + goto asprintf_failure; + } + + /* Create the allocation output string */ + val = prettyCapacity(volumeInfo.allocation, &unit); + ret = virAsprintf(&volInfoTexts[i].allocation, + "%.2lf %s", val, unit); + if (ret < 0) { + /* An error occurred creating the string, return */ + goto asprintf_failure; + } + } + + /* Remember the largest length for each output string. + * This lets us displaying header and volume information rows + * using a single, properly sized, printf style output string. + */ + + /* Keep the length of name string if longest so far */ + stringLength = strlen(activeNames[i]); + if (stringLength > nameStrLength) + nameStrLength = stringLength; + + /* Keep the length of path string if longest so far */ + stringLength = strlen(volInfoTexts[i].path); + if (stringLength > pathStrLength) + pathStrLength = stringLength; + + /* Keep the length of type string if longest so far */ + stringLength = strlen(volInfoTexts[i].type); + if (stringLength > typeStrLength) + typeStrLength = stringLength; + + /* Keep the length of capacity string if longest so far */ + stringLength = strlen(volInfoTexts[i].capacity); + if (stringLength > capStrLength) + capStrLength = stringLength; + + /* Keep the length of allocation string if longest so far */ + stringLength = strlen(volInfoTexts[i].allocation); + if (stringLength > allocStrLength) + allocStrLength = stringLength; + } + + /* Cleanup memory allocation */ + virStorageVolFree(vol); + } + + /* If the --details option wasn't selected, we output the volume + * info using the fixed string format from previous versions to + * maintain backward compatibility. + */ + + /* Output basic info then return if --details option not selected */ + if (!details) { + /* The old output format */ + vshPrintExtra(ctl, "%-20s %-40s\n", _("Name"), _("Path")); + vshPrintExtra(ctl, "-----------------------------------------\n"); + for (i = 0; i < numVolumes; i++) { + vshPrint(ctl, "%-20s %-40s\n", activeNames[i], + volInfoTexts[i].path); + } + + /* Cleanup and return */ + functionReturn = true; + goto cleanup; + } + + /* We only get here if the --details option was selected. */ + + /* Use the length of name header string if it's longest */ + stringLength = strlen(_("Name")); + if (stringLength > nameStrLength) + nameStrLength = stringLength; + + /* Use the length of path header string if it's longest */ + stringLength = strlen(_("Path")); + if (stringLength > pathStrLength) + pathStrLength = stringLength; + + /* Use the length of type header string if it's longest */ + stringLength = strlen(_("Type")); + if (stringLength > typeStrLength) + typeStrLength = stringLength; + + /* Use the length of capacity header string if it's longest */ + stringLength = strlen(_("Capacity")); + if (stringLength > capStrLength) + capStrLength = stringLength; + + /* Use the length of allocation header string if it's longest */ + stringLength = strlen(_("Allocation")); + if (stringLength > allocStrLength) + allocStrLength = stringLength; + + /* Display the string lengths for debugging */ + vshDebug(ctl, VSH_ERR_DEBUG, + "Longest name string = %zu chars\n", nameStrLength); + vshDebug(ctl, VSH_ERR_DEBUG, + "Longest path string = %zu chars\n", pathStrLength); + vshDebug(ctl, VSH_ERR_DEBUG, + "Longest type string = %zu chars\n", typeStrLength); + vshDebug(ctl, VSH_ERR_DEBUG, + "Longest capacity string = %zu chars\n", capStrLength); + vshDebug(ctl, VSH_ERR_DEBUG, + "Longest allocation string = %zu chars\n", allocStrLength); + + /* Create the output template */ + ret = virAsprintf(&outputStr, + "%%-%lus %%-%lus %%-%lus %%%lus %%%lus\n", + (unsigned long) nameStrLength, + (unsigned long) pathStrLength, + (unsigned long) typeStrLength, + (unsigned long) capStrLength, + (unsigned long) allocStrLength); + if (ret < 0) { + /* An error occurred creating the string, return */ + goto asprintf_failure; + } + + /* Display the header */ + vshPrint(ctl, outputStr, _("Name"), _("Path"), _("Type"), + ("Capacity"), _("Allocation")); + for (i = nameStrLength + pathStrLength + typeStrLength + + capStrLength + allocStrLength + + 8; i > 0; i--) + vshPrintExtra(ctl, "-"); + vshPrintExtra(ctl, "\n"); + + /* Display the volume info rows */ + for (i = 0; i < numVolumes; i++) { + vshPrint(ctl, outputStr, + activeNames[i], + volInfoTexts[i].path, + volInfoTexts[i].type, + volInfoTexts[i].capacity, + volInfoTexts[i].allocation); + } + + /* Cleanup and return */ + functionReturn = true; + goto cleanup; + +asprintf_failure: + + /* Display an appropriate error message then cleanup and return */ + switch (errno) { + case ENOMEM: + /* Couldn't allocate memory */ + vshError(ctl, "%s", _("Out of memory")); + break; + default: + /* Some other error */ + vshError(ctl, _("virAsprintf failed (errno %d)"), errno); + } + functionReturn = false; + +cleanup: + + /* Safely free the memory allocated in this function */ + for (i = 0; i < numVolumes; i++) { + /* Cleanup the memory for one volume info structure per loop */ + VIR_FREE(volInfoTexts[i].path); + VIR_FREE(volInfoTexts[i].type); + VIR_FREE(volInfoTexts[i].capacity); + VIR_FREE(volInfoTexts[i].allocation); + VIR_FREE(activeNames[i]); + } + + /* Cleanup remaining memory */ + VIR_FREE(outputStr); + VIR_FREE(volInfoTexts); + VIR_FREE(activeNames); + virStoragePoolFree(pool); + + /* Return the desired value */ + return functionReturn; +} + +/* + * "vol-name" command + */ +static const vshCmdInfo info_vol_name[] = { + {"help", N_("returns the volume name for a given volume key or path")}, + {"desc", ""}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_vol_name[] = { + {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("volume key or path")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdVolName(vshControl *ctl, const vshCmd *cmd) +{ + virStorageVolPtr vol; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(vol = vshCommandOptVolBy(ctl, cmd, "vol", NULL, NULL, + VSH_BYUUID))) + return false; + + vshPrint(ctl, "%s\n", virStorageVolGetName(vol)); + virStorageVolFree(vol); + return true; +} + +/* + * "vol-pool" command + */ +static const vshCmdInfo info_vol_pool[] = { + {"help", N_("returns the storage pool for a given volume key or path")}, + {"desc", ""}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_vol_pool[] = { + {"uuid", VSH_OT_BOOL, 0, N_("return the pool uuid rather than pool name")}, + {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("volume key or path")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdVolPool(vshControl *ctl, const vshCmd *cmd) +{ + virStoragePoolPtr pool; + virStorageVolPtr vol; + char uuid[VIR_UUID_STRING_BUFLEN]; + + /* Check the connection to libvirtd daemon is still working */ + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + /* Use the supplied string to locate the volume */ + if (!(vol = vshCommandOptVolBy(ctl, cmd, "vol", NULL, NULL, + VSH_BYUUID))) { + return false; + } + + /* Look up the parent storage pool for the volume */ + pool = virStoragePoolLookupByVolume(vol); + if (pool == NULL) { + vshError(ctl, "%s", _("failed to get parent pool")); + virStorageVolFree(vol); + return false; + } + + /* Return the requested details of the parent storage pool */ + if (vshCommandOptBool(cmd, "uuid")) { + /* Retrieve and return pool UUID string */ + if (virStoragePoolGetUUIDString(pool, &uuid[0]) == 0) + vshPrint(ctl, "%s\n", uuid); + } else { + /* Return the storage pool name */ + vshPrint(ctl, "%s\n", virStoragePoolGetName(pool)); + } + + /* Cleanup */ + virStorageVolFree(vol); + virStoragePoolFree(pool); + return true; +} + +/* + * "vol-key" command + */ +static const vshCmdInfo info_vol_key[] = { + {"help", N_("returns the volume key for a given volume name or path")}, + {"desc", ""}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_vol_key[] = { + {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("volume name or path")}, + {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdVolKey(vshControl *ctl, const vshCmd *cmd) +{ + virStorageVolPtr vol; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", NULL))) + return false; + + vshPrint(ctl, "%s\n", virStorageVolGetKey(vol)); + virStorageVolFree(vol); + return true; +} + +/* + * "vol-path" command + */ +static const vshCmdInfo info_vol_path[] = { + {"help", N_("returns the volume path for a given volume name or key")}, + {"desc", ""}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_vol_path[] = { + {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("volume name or key")}, + {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdVolPath(vshControl *ctl, const vshCmd *cmd) +{ + virStorageVolPtr vol; + char * StorageVolPath; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", NULL))) { + return false; + } + + if ((StorageVolPath = virStorageVolGetPath(vol)) == NULL) { + virStorageVolFree(vol); + return false; + } + + vshPrint(ctl, "%s\n", StorageVolPath); + VIR_FREE(StorageVolPath); + virStorageVolFree(vol); + return true; +} diff --git a/tools/virsh.c b/tools/virsh.c index e3ecd54..ac8ad09 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -372,16 +372,6 @@ static virStoragePoolPtr vshCommandOptPoolBy(vshControl *ctl, const vshCmd *cmd, vshCommandOptPoolBy(_ctl, _cmd, _optname, _name, \ VSH_BYUUID|VSH_BYNAME)
-static virStorageVolPtr vshCommandOptVolBy(vshControl *ctl, const vshCmd *cmd, - const char *optname, - const char *pooloptname, - const char **name, int flag); - -/* default is lookup by Name and UUID */ -#define vshCommandOptVol(_ctl, _cmd, _optname, _pooloptname, _name) \ - vshCommandOptVolBy(_ctl, _cmd, _optname, _pooloptname, _name, \ - VSH_BYUUID|VSH_BYNAME) - static virSecretPtr vshCommandOptSecret(vshControl *ctl, const vshCmd *cmd, const char **name);
@@ -4159,1632 +4149,264 @@ cmdPoolDiscoverSources(vshControl * ctl, const vshCmd * cmd ATTRIBUTE_UNUSED) return false;
if (srcSpecFile && virFileReadAll(srcSpecFile, VIRSH_MAX_XML_FILE, &srcSpec) < 0) - return false; - - srcList = virConnectFindStoragePoolSources(ctl->conn, type, srcSpec, 0); - VIR_FREE(srcSpec); - if (srcList == NULL) { - vshError(ctl, _("Failed to find any %s pool sources"), type); - return false; - } - vshPrint(ctl, "%s", srcList); - VIR_FREE(srcList); - - return true; -} - - -/* - * "pool-info" command - */ -static const vshCmdInfo info_pool_info[] = { - {"help", N_("storage pool information")}, - {"desc", N_("Returns basic information about the storage pool.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_pool_info[] = { - {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdPoolInfo(vshControl *ctl, const vshCmd *cmd) -{ - virStoragePoolInfo info; - virStoragePoolPtr pool; - int autostart = 0; - int persistent = 0; - bool ret = true; - char uuid[VIR_UUID_STRING_BUFLEN]; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (!(pool = vshCommandOptPool(ctl, cmd, "pool", NULL))) - return false; - - vshPrint(ctl, "%-15s %s\n", _("Name:"), virStoragePoolGetName(pool)); - - if (virStoragePoolGetUUIDString(pool, &uuid[0])==0) - vshPrint(ctl, "%-15s %s\n", _("UUID:"), uuid); - - if (virStoragePoolGetInfo(pool, &info) == 0) { - double val; - const char *unit; - switch (info.state) { - case VIR_STORAGE_POOL_INACTIVE: - vshPrint(ctl, "%-15s %s\n", _("State:"), - _("inactive")); - break; - case VIR_STORAGE_POOL_BUILDING: - vshPrint(ctl, "%-15s %s\n", _("State:"), - _("building")); - break; - case VIR_STORAGE_POOL_RUNNING: - vshPrint(ctl, "%-15s %s\n", _("State:"), - _("running")); - break; - case VIR_STORAGE_POOL_DEGRADED: - vshPrint(ctl, "%-15s %s\n", _("State:"), - _("degraded")); - break; - case VIR_STORAGE_POOL_INACCESSIBLE: - vshPrint(ctl, "%-15s %s\n", _("State:"), - _("inaccessible")); - break; - } - - /* Check and display whether the pool is persistent or not */ - persistent = virStoragePoolIsPersistent(pool); - vshDebug(ctl, VSH_ERR_DEBUG, "Pool persistent flag value: %d\n", - persistent); - if (persistent < 0) - vshPrint(ctl, "%-15s %s\n", _("Persistent:"), _("unknown")); - else - vshPrint(ctl, "%-15s %s\n", _("Persistent:"), persistent ? _("yes") : _("no")); - - /* Check and display whether the pool is autostarted or not */ - virStoragePoolGetAutostart(pool, &autostart); - vshDebug(ctl, VSH_ERR_DEBUG, "Pool autostart flag value: %d\n", - autostart); - if (autostart < 0) - vshPrint(ctl, "%-15s %s\n", _("Autostart:"), _("no autostart")); - else - vshPrint(ctl, "%-15s %s\n", _("Autostart:"), autostart ? _("yes") : _("no")); - - if (info.state == VIR_STORAGE_POOL_RUNNING || - info.state == VIR_STORAGE_POOL_DEGRADED) { - val = prettyCapacity(info.capacity, &unit); - vshPrint(ctl, "%-15s %2.2lf %s\n", _("Capacity:"), val, unit); - - val = prettyCapacity(info.allocation, &unit); - vshPrint(ctl, "%-15s %2.2lf %s\n", _("Allocation:"), val, unit); - - val = prettyCapacity(info.available, &unit); - vshPrint(ctl, "%-15s %2.2lf %s\n", _("Available:"), val, unit); - } - } else { - ret = false; - } - - virStoragePoolFree(pool); - return ret; -} - - -/* - * "pool-name" command - */ -static const vshCmdInfo info_pool_name[] = { - {"help", N_("convert a pool UUID to pool name")}, - {"desc", ""}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_pool_name[] = { - {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool uuid")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdPoolName(vshControl *ctl, const vshCmd *cmd) -{ - virStoragePoolPtr pool; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - if (!(pool = vshCommandOptPoolBy(ctl, cmd, "pool", NULL, - VSH_BYUUID))) - return false; - - vshPrint(ctl, "%s\n", virStoragePoolGetName(pool)); - virStoragePoolFree(pool); - return true; -} - - -/* - * "pool-start" command - */ -static const vshCmdInfo info_pool_start[] = { - {"help", N_("start a (previously defined) inactive pool")}, - {"desc", N_("Start a pool.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_pool_start[] = { - {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("name or uuid of the inactive pool")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdPoolStart(vshControl *ctl, const vshCmd *cmd) -{ - virStoragePoolPtr pool; - bool ret = true; - const char *name = NULL; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (!(pool = vshCommandOptPool(ctl, cmd, "pool", &name))) - return false; - - if (virStoragePoolCreate(pool, 0) == 0) { - vshPrint(ctl, _("Pool %s started\n"), name); - } else { - vshError(ctl, _("Failed to start pool %s"), name); - ret = false; - } - - virStoragePoolFree(pool); - return ret; -} - - -/* - * "vol-create-as" command - */ -static const vshCmdInfo info_vol_create_as[] = { - {"help", N_("create a volume from a set of args")}, - {"desc", N_("Create a vol.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_vol_create_as[] = { - {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name")}, - {"name", VSH_OT_DATA, VSH_OFLAG_REQ, N_("name of the volume")}, - {"capacity", VSH_OT_DATA, VSH_OFLAG_REQ, - N_("size of the vol, as scaled integer (default bytes)")}, - {"allocation", VSH_OT_STRING, 0, - N_("initial allocation size, as scaled integer (default bytes)")}, - {"format", VSH_OT_STRING, 0, - N_("file format type raw,bochs,qcow,qcow2,qed,vmdk")}, - {"backing-vol", VSH_OT_STRING, 0, - N_("the backing volume if taking a snapshot")}, - {"backing-vol-format", VSH_OT_STRING, 0, - N_("format of backing volume if taking a snapshot")}, - {NULL, 0, 0, NULL} -}; - -static int -vshVolSize(const char *data, unsigned long long *val) -{ - char *end; - if (virStrToLong_ull(data, &end, 10, val) < 0) - return -1; - return virScaleInteger(val, end, 1, ULLONG_MAX); -} - -static bool -cmdVolCreateAs(vshControl *ctl, const vshCmd *cmd) -{ - virStoragePoolPtr pool; - virStorageVolPtr vol; - char *xml; - const char *name, *capacityStr = NULL, *allocationStr = NULL, *format = NULL; - const char *snapshotStrVol = NULL, *snapshotStrFormat = NULL; - unsigned long long capacity, allocation = 0; - virBuffer buf = VIR_BUFFER_INITIALIZER; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (!(pool = vshCommandOptPoolBy(ctl, cmd, "pool", NULL, - VSH_BYNAME))) - return false; - - if (vshCommandOptString(cmd, "name", &name) <= 0) - goto cleanup; - - if (vshCommandOptString(cmd, "capacity", &capacityStr) <= 0) - goto cleanup; - - if (vshVolSize(capacityStr, &capacity) < 0) { - vshError(ctl, _("Malformed size %s"), capacityStr); - goto cleanup; - } - - if (vshCommandOptString(cmd, "allocation", &allocationStr) > 0 && - vshVolSize(allocationStr, &allocation) < 0) { - vshError(ctl, _("Malformed size %s"), allocationStr); - goto cleanup; - } - - if (vshCommandOptString(cmd, "format", &format) < 0 || - vshCommandOptString(cmd, "backing-vol", &snapshotStrVol) < 0 || - vshCommandOptString(cmd, "backing-vol-format", - &snapshotStrFormat) < 0) { - vshError(ctl, "%s", _("missing argument")); - goto cleanup; - } - - - virBufferAddLit(&buf, "<volume>\n"); - virBufferAsprintf(&buf, " <name>%s</name>\n", name); - virBufferAsprintf(&buf, " <capacity>%llu</capacity>\n", capacity); - if (allocationStr) - virBufferAsprintf(&buf, " <allocation>%llu</allocation>\n", allocation); - - if (format) { - virBufferAddLit(&buf, " <target>\n"); - virBufferAsprintf(&buf, " <format type='%s'/>\n",format); - virBufferAddLit(&buf, " </target>\n"); - } - - /* Convert the snapshot parameters into backingStore XML */ - if (snapshotStrVol) { - /* Lookup snapshot backing volume. Try the backing-vol - * parameter as a name */ - vshDebug(ctl, VSH_ERR_DEBUG, - "%s: Look up backing store volume '%s' as name\n", - cmd->def->name, snapshotStrVol); - virStorageVolPtr snapVol = virStorageVolLookupByName(pool, snapshotStrVol); - if (snapVol) - vshDebug(ctl, VSH_ERR_DEBUG, - "%s: Backing store volume found using '%s' as name\n", - cmd->def->name, snapshotStrVol); - - if (snapVol == NULL) { - /* Snapshot backing volume not found by name. Try the - * backing-vol parameter as a key */ - vshDebug(ctl, VSH_ERR_DEBUG, - "%s: Look up backing store volume '%s' as key\n", - cmd->def->name, snapshotStrVol); - snapVol = virStorageVolLookupByKey(ctl->conn, snapshotStrVol); - if (snapVol) - vshDebug(ctl, VSH_ERR_DEBUG, - "%s: Backing store volume found using '%s' as key\n", - cmd->def->name, snapshotStrVol); - } - if (snapVol == NULL) { - /* Snapshot backing volume not found by key. Try the - * backing-vol parameter as a path */ - vshDebug(ctl, VSH_ERR_DEBUG, - "%s: Look up backing store volume '%s' as path\n", - cmd->def->name, snapshotStrVol); - snapVol = virStorageVolLookupByPath(ctl->conn, snapshotStrVol); - if (snapVol) - vshDebug(ctl, VSH_ERR_DEBUG, - "%s: Backing store volume found using '%s' as path\n", - cmd->def->name, snapshotStrVol); - } - if (snapVol == NULL) { - vshError(ctl, _("failed to get vol '%s'"), snapshotStrVol); - goto cleanup; - } - - char *snapshotStrVolPath; - if ((snapshotStrVolPath = virStorageVolGetPath(snapVol)) == NULL) { - virStorageVolFree(snapVol); - goto cleanup; - } - - /* Create XML for the backing store */ - virBufferAddLit(&buf, " <backingStore>\n"); - virBufferAsprintf(&buf, " <path>%s</path>\n",snapshotStrVolPath); - if (snapshotStrFormat) - virBufferAsprintf(&buf, " <format type='%s'/>\n",snapshotStrFormat); - virBufferAddLit(&buf, " </backingStore>\n"); - - /* Cleanup snapshot allocations */ - VIR_FREE(snapshotStrVolPath); - virStorageVolFree(snapVol); - } - - virBufferAddLit(&buf, "</volume>\n"); - - if (virBufferError(&buf)) { - vshPrint(ctl, "%s", _("Failed to allocate XML buffer")); - goto cleanup; - } - xml = virBufferContentAndReset(&buf); - vol = virStorageVolCreateXML(pool, xml, 0); - VIR_FREE(xml); - virStoragePoolFree(pool); - - if (vol != NULL) { - vshPrint(ctl, _("Vol %s created\n"), name); - virStorageVolFree(vol); - return true; - } else { - vshError(ctl, _("Failed to create vol %s"), name); - return false; - } - - cleanup: - virBufferFreeAndReset(&buf); - virStoragePoolFree(pool); - return false; -} - - -/* - * "pool-undefine" command - */ -static const vshCmdInfo info_pool_undefine[] = { - {"help", N_("undefine an inactive pool")}, - {"desc", N_("Undefine the configuration for an inactive pool.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_pool_undefine[] = { - {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdPoolUndefine(vshControl *ctl, const vshCmd *cmd) -{ - virStoragePoolPtr pool; - bool ret = true; - const char *name; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (!(pool = vshCommandOptPool(ctl, cmd, "pool", &name))) - return false; - - if (virStoragePoolUndefine(pool) == 0) { - vshPrint(ctl, _("Pool %s has been undefined\n"), name); - } else { - vshError(ctl, _("Failed to undefine pool %s"), name); - ret = false; - } - - virStoragePoolFree(pool); - return ret; -} - - -/* - * "pool-uuid" command - */ -static const vshCmdInfo info_pool_uuid[] = { - {"help", N_("convert a pool name to pool UUID")}, - {"desc", ""}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_pool_uuid[] = { - {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdPoolUuid(vshControl *ctl, const vshCmd *cmd) -{ - virStoragePoolPtr pool; - char uuid[VIR_UUID_STRING_BUFLEN]; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (!(pool = vshCommandOptPoolBy(ctl, cmd, "pool", NULL, - VSH_BYNAME))) - return false; - - if (virStoragePoolGetUUIDString(pool, uuid) != -1) - vshPrint(ctl, "%s\n", uuid); - else - vshError(ctl, "%s", _("failed to get pool UUID")); - - virStoragePoolFree(pool); - return true; -} - - -/* - * "vol-create" command - */ -static const vshCmdInfo info_vol_create[] = { - {"help", N_("create a vol from an XML file")}, - {"desc", N_("Create a vol.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_vol_create[] = { - {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name")}, - {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containing an XML vol description")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdVolCreate(vshControl *ctl, const vshCmd *cmd) -{ - virStoragePoolPtr pool; - virStorageVolPtr vol; - const char *from = NULL; - bool ret = true; - char *buffer; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (!(pool = vshCommandOptPoolBy(ctl, cmd, "pool", NULL, - VSH_BYNAME))) - return false; - - if (vshCommandOptString(cmd, "file", &from) <= 0) { - virStoragePoolFree(pool); - return false; - } - - if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0) { - virshReportError(ctl); - virStoragePoolFree(pool); - return false; - } - - vol = virStorageVolCreateXML(pool, buffer, 0); - VIR_FREE(buffer); - virStoragePoolFree(pool); - - if (vol != NULL) { - vshPrint(ctl, _("Vol %s created from %s\n"), - virStorageVolGetName(vol), from); - virStorageVolFree(vol); - } else { - vshError(ctl, _("Failed to create vol from %s"), from); - ret = false; - } - return ret; -} - -/* - * "vol-create-from" command - */ -static const vshCmdInfo info_vol_create_from[] = { - {"help", N_("create a vol, using another volume as input")}, - {"desc", N_("Create a vol from an existing volume.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_vol_create_from[] = { - {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")}, - {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containing an XML vol description")}, - {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("input vol name or key")}, - {"inputpool", VSH_OT_STRING, 0, N_("pool name or uuid of the input volume's pool")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdVolCreateFrom(vshControl *ctl, const vshCmd *cmd) -{ - virStoragePoolPtr pool = NULL; - virStorageVolPtr newvol = NULL, inputvol = NULL; - const char *from = NULL; - bool ret = false; - char *buffer = NULL; - - if (!vshConnectionUsability(ctl, ctl->conn)) - goto cleanup; - - if (!(pool = vshCommandOptPool(ctl, cmd, "pool", NULL))) - goto cleanup; - - if (vshCommandOptString(cmd, "file", &from) <= 0) { - goto cleanup; - } - - if (!(inputvol = vshCommandOptVol(ctl, cmd, "vol", "inputpool", NULL))) - goto cleanup; - - if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0) { - virshReportError(ctl); - goto cleanup; - } - - newvol = virStorageVolCreateXMLFrom(pool, buffer, inputvol, 0); - - if (newvol != NULL) { - vshPrint(ctl, _("Vol %s created from input vol %s\n"), - virStorageVolGetName(newvol), virStorageVolGetName(inputvol)); - } else { - vshError(ctl, _("Failed to create vol from %s"), from); - goto cleanup; - } - - ret = true; -cleanup: - VIR_FREE(buffer); - if (pool) - virStoragePoolFree(pool); - if (inputvol) - virStorageVolFree(inputvol); - if (newvol) - virStorageVolFree(newvol); - return ret; -} - -static xmlChar * -makeCloneXML(const char *origxml, const char *newname) -{ - - xmlDocPtr doc = NULL; - xmlXPathContextPtr ctxt = NULL; - xmlXPathObjectPtr obj = NULL; - xmlChar *newxml = NULL; - int size; - - doc = virXMLParseStringCtxt(origxml, _("(volume_definition)"), &ctxt); - if (!doc) - goto cleanup; - - obj = xmlXPathEval(BAD_CAST "/volume/name", ctxt); - if (obj == NULL || obj->nodesetval == NULL || - obj->nodesetval->nodeTab == NULL) - goto cleanup; - - xmlNodeSetContent(obj->nodesetval->nodeTab[0], (const xmlChar *)newname); - xmlDocDumpMemory(doc, &newxml, &size); - -cleanup: - xmlXPathFreeObject(obj); - xmlXPathFreeContext(ctxt); - xmlFreeDoc(doc); - return newxml; -} - -/* - * "vol-clone" command - */ -static const vshCmdInfo info_vol_clone[] = { - {"help", N_("clone a volume.")}, - {"desc", N_("Clone an existing volume.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_vol_clone[] = { - {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("orig vol name or key")}, - {"newname", VSH_OT_DATA, VSH_OFLAG_REQ, N_("clone name")}, - {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdVolClone(vshControl *ctl, const vshCmd *cmd) -{ - virStoragePoolPtr origpool = NULL; - virStorageVolPtr origvol = NULL, newvol = NULL; - const char *name = NULL; - char *origxml = NULL; - xmlChar *newxml = NULL; - bool ret = false; - - if (!vshConnectionUsability(ctl, ctl->conn)) - goto cleanup; - - if (!(origvol = vshCommandOptVol(ctl, cmd, "vol", "pool", NULL))) - goto cleanup; - - origpool = virStoragePoolLookupByVolume(origvol); - if (!origpool) { - vshError(ctl, "%s", _("failed to get parent pool")); - goto cleanup; - } - - if (vshCommandOptString(cmd, "newname", &name) <= 0) - goto cleanup; - - origxml = virStorageVolGetXMLDesc(origvol, 0); - if (!origxml) - goto cleanup; - - newxml = makeCloneXML(origxml, name); - if (!newxml) { - vshPrint(ctl, "%s", _("Failed to allocate XML buffer")); - goto cleanup; - } - - newvol = virStorageVolCreateXMLFrom(origpool, (char *) newxml, origvol, 0); - - if (newvol != NULL) { - vshPrint(ctl, _("Vol %s cloned from %s\n"), - virStorageVolGetName(newvol), virStorageVolGetName(origvol)); - } else { - vshError(ctl, _("Failed to clone vol from %s"), - virStorageVolGetName(origvol)); - goto cleanup; - } - - ret = true; - -cleanup: - VIR_FREE(origxml); - xmlFree(newxml); - if (origvol) - virStorageVolFree(origvol); - if (newvol) - virStorageVolFree(newvol); - if (origpool) - virStoragePoolFree(origpool); - return ret; -} - - -/* - * "vol-upload" command - */ -static const vshCmdInfo info_vol_upload[] = { - {"help", N_("upload a file into a volume")}, - {"desc", N_("Upload a file into a volume")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_vol_upload[] = { - {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("vol name, key or path")}, - {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file")}, - {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")}, - {"offset", VSH_OT_INT, 0, N_("volume offset to upload to") }, - {"length", VSH_OT_INT, 0, N_("amount of data to upload") }, - {NULL, 0, 0, NULL} -}; - -static int -cmdVolUploadSource(virStreamPtr st ATTRIBUTE_UNUSED, - char *bytes, size_t nbytes, void *opaque) -{ - int *fd = opaque; - - return saferead(*fd, bytes, nbytes); -} - -static bool -cmdVolUpload(vshControl *ctl, const vshCmd *cmd) -{ - const char *file = NULL; - virStorageVolPtr vol = NULL; - bool ret = false; - int fd = -1; - virStreamPtr st = NULL; - const char *name = NULL; - unsigned long long offset = 0, length = 0; - - if (!vshConnectionUsability(ctl, ctl->conn)) - goto cleanup; - - if (vshCommandOptULongLong(cmd, "offset", &offset) < 0) { - vshError(ctl, _("Unable to parse integer")); - return false; - } - - if (vshCommandOptULongLong(cmd, "length", &length) < 0) { - vshError(ctl, _("Unable to parse integer")); - return false; - } - - if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", &name))) { - return false; - } - - if (vshCommandOptString(cmd, "file", &file) < 0) { - vshError(ctl, _("file must not be empty")); - goto cleanup; - } - - if ((fd = open(file, O_RDONLY)) < 0) { - vshError(ctl, _("cannot read %s"), file); - goto cleanup; - } - - st = virStreamNew(ctl->conn, 0); - if (virStorageVolUpload(vol, st, offset, length, 0) < 0) { - vshError(ctl, _("cannot upload to volume %s"), name); - goto cleanup; - } - - if (virStreamSendAll(st, cmdVolUploadSource, &fd) < 0) { - vshError(ctl, _("cannot send data to volume %s"), name); - goto cleanup; - } - - if (VIR_CLOSE(fd) < 0) { - vshError(ctl, _("cannot close file %s"), file); - virStreamAbort(st); - goto cleanup; - } - - if (virStreamFinish(st) < 0) { - vshError(ctl, _("cannot close volume %s"), name); - goto cleanup; - } - - ret = true; - -cleanup: - if (vol) - virStorageVolFree(vol); - if (st) - virStreamFree(st); - VIR_FORCE_CLOSE(fd); - return ret; -} - - - -/* - * "vol-download" command - */ -static const vshCmdInfo info_vol_download[] = { - {"help", N_("Download a volume to a file")}, - {"desc", N_("Download a volume to a file")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_vol_download[] = { - {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("vol name, key or path")}, - {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file")}, - {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")}, - {"offset", VSH_OT_INT, 0, N_("volume offset to download from") }, - {"length", VSH_OT_INT, 0, N_("amount of data to download") }, - {NULL, 0, 0, NULL} -}; - -static bool -cmdVolDownload(vshControl *ctl, const vshCmd *cmd) -{ - const char *file = NULL; - virStorageVolPtr vol = NULL; - bool ret = false; - int fd = -1; - virStreamPtr st = NULL; - const char *name = NULL; - unsigned long long offset = 0, length = 0; - bool created = false; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (vshCommandOptULongLong(cmd, "offset", &offset) < 0) { - vshError(ctl, _("Unable to parse integer")); - return false; - } - - if (vshCommandOptULongLong(cmd, "length", &length) < 0) { - vshError(ctl, _("Unable to parse integer")); - return false; - } - - if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", &name))) - return false; - - if (vshCommandOptString(cmd, "file", &file) < 0) { - vshError(ctl, _("file must not be empty")); - goto cleanup; - } - - if ((fd = open(file, O_WRONLY|O_CREAT|O_EXCL, 0666)) < 0) { - if (errno != EEXIST || - (fd = open(file, O_WRONLY|O_TRUNC, 0666)) < 0) { - vshError(ctl, _("cannot create %s"), file); - goto cleanup; - } - } else { - created = true; - } - - st = virStreamNew(ctl->conn, 0); - if (virStorageVolDownload(vol, st, offset, length, 0) < 0) { - vshError(ctl, _("cannot download from volume %s"), name); - goto cleanup; - } - - if (virStreamRecvAll(st, vshStreamSink, &fd) < 0) { - vshError(ctl, _("cannot receive data from volume %s"), name); - goto cleanup; - } - - if (VIR_CLOSE(fd) < 0) { - vshError(ctl, _("cannot close file %s"), file); - virStreamAbort(st); - goto cleanup; - } - - if (virStreamFinish(st) < 0) { - vshError(ctl, _("cannot close volume %s"), name); - goto cleanup; - } - - ret = true; - -cleanup: - VIR_FORCE_CLOSE(fd); - if (!ret && created) - unlink(file); - if (vol) - virStorageVolFree(vol); - if (st) - virStreamFree(st); - return ret; -} - - -/* - * "vol-delete" command - */ -static const vshCmdInfo info_vol_delete[] = { - {"help", N_("delete a vol")}, - {"desc", N_("Delete a given vol.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_vol_delete[] = { - {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("vol name, key or path")}, - {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdVolDelete(vshControl *ctl, const vshCmd *cmd) -{ - virStorageVolPtr vol; - bool ret = true; - const char *name; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", &name))) { - return false; - } - - if (virStorageVolDelete(vol, 0) == 0) { - vshPrint(ctl, _("Vol %s deleted\n"), name); - } else { - vshError(ctl, _("Failed to delete vol %s"), name); - ret = false; - } - - virStorageVolFree(vol); - return ret; -} - - -/* - * "vol-wipe" command - */ -static const vshCmdInfo info_vol_wipe[] = { - {"help", N_("wipe a vol")}, - {"desc", N_("Ensure data previously on a volume is not accessible to future reads")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_vol_wipe[] = { - {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("vol name, key or path")}, - {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")}, - {"algorithm", VSH_OT_STRING, 0, N_("perform selected wiping algorithm")}, - {NULL, 0, 0, NULL} -}; - -VIR_ENUM_DECL(virStorageVolWipeAlgorithm) -VIR_ENUM_IMPL(virStorageVolWipeAlgorithm, VIR_STORAGE_VOL_WIPE_ALG_LAST, - "zero", "nnsa", "dod", "bsi", "gutmann", "schneier", - "pfitzner7", "pfitzner33", "random"); - -static bool -cmdVolWipe(vshControl *ctl, const vshCmd *cmd) -{ - virStorageVolPtr vol; - bool ret = false; - const char *name; - const char *algorithm_str = NULL; - int algorithm = VIR_STORAGE_VOL_WIPE_ALG_ZERO; - int funcRet; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", &name))) { - return false; - } - - if (vshCommandOptString(cmd, "algorithm", &algorithm_str) < 0) { - vshError(ctl, "%s", _("missing argument")); - goto out; - } - - if (algorithm_str && - (algorithm = virStorageVolWipeAlgorithmTypeFromString(algorithm_str)) < 0) { - vshError(ctl, _("Unsupported algorithm '%s'"), algorithm_str); - goto out; - } - - if ((funcRet = virStorageVolWipePattern(vol, algorithm, 0)) < 0) { - if (last_error->code == VIR_ERR_NO_SUPPORT && - algorithm == VIR_STORAGE_VOL_WIPE_ALG_ZERO) - funcRet = virStorageVolWipe(vol, 0); - } - - if (funcRet < 0) { - vshError(ctl, _("Failed to wipe vol %s"), name); - goto out; - } - - vshPrint(ctl, _("Vol %s wiped\n"), name); - ret = true; -out: - virStorageVolFree(vol); - return ret; -} - - -/* - * "vol-info" command - */ -static const vshCmdInfo info_vol_info[] = { - {"help", N_("storage vol information")}, - {"desc", N_("Returns basic information about the storage vol.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_vol_info[] = { - {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("vol name, key or path")}, - {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdVolInfo(vshControl *ctl, const vshCmd *cmd) -{ - virStorageVolInfo info; - virStorageVolPtr vol; - bool ret = true; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", NULL))) - return false; - - vshPrint(ctl, "%-15s %s\n", _("Name:"), virStorageVolGetName(vol)); - - if (virStorageVolGetInfo(vol, &info) == 0) { - double val; - const char *unit; - switch(info.type) { - case VIR_STORAGE_VOL_FILE: - vshPrint(ctl, "%-15s %s\n", _("Type:"), _("file")); - break; - - case VIR_STORAGE_VOL_BLOCK: - vshPrint(ctl, "%-15s %s\n", _("Type:"), _("block")); - break; - - case VIR_STORAGE_VOL_DIR: - vshPrint(ctl, "%-15s %s\n", _("Type:"), _("dir")); - break; - - case VIR_STORAGE_VOL_NETWORK: - vshPrint(ctl, "%-15s %s\n", _("Type:"), _("network")); - break; - - default: - vshPrint(ctl, "%-15s %s\n", _("Type:"), _("unknown")); - } - - val = prettyCapacity(info.capacity, &unit); - vshPrint(ctl, "%-15s %2.2lf %s\n", _("Capacity:"), val, unit); - - val = prettyCapacity(info.allocation, &unit); - vshPrint(ctl, "%-15s %2.2lf %s\n", _("Allocation:"), val, unit); - } else { - ret = false; - } - - virStorageVolFree(vol); - return ret; -} - -/* - * "vol-resize" command - */ -static const vshCmdInfo info_vol_resize[] = { - {"help", N_("resize a vol")}, - {"desc", N_("Resizes a storage volume.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_vol_resize[] = { - {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("vol name, key or path")}, - {"capacity", VSH_OT_DATA, VSH_OFLAG_REQ, - N_("new capacity for the vol, as scaled integer (default bytes)")}, - {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")}, - {"allocate", VSH_OT_BOOL, 0, - N_("allocate the new capacity, rather than leaving it sparse")}, - {"delta", VSH_OT_BOOL, 0, - N_("use capacity as a delta to current size, rather than the new size")}, - {"shrink", VSH_OT_BOOL, 0, N_("allow the resize to shrink the volume")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdVolResize(vshControl *ctl, const vshCmd *cmd) -{ - virStorageVolPtr vol; - const char *capacityStr = NULL; - unsigned long long capacity = 0; - unsigned int flags = 0; - bool ret = false; - bool delta = false; - - if (vshCommandOptBool(cmd, "allocate")) - flags |= VIR_STORAGE_VOL_RESIZE_ALLOCATE; - if (vshCommandOptBool(cmd, "delta")) { - delta = true; - flags |= VIR_STORAGE_VOL_RESIZE_DELTA; - } - if (vshCommandOptBool(cmd, "shrink")) - flags |= VIR_STORAGE_VOL_RESIZE_SHRINK; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", NULL))) - return false; - - if (vshCommandOptString(cmd, "capacity", &capacityStr) <= 0) - goto cleanup; - virSkipSpaces(&capacityStr); - if (*capacityStr == '-') { - /* The API always requires a positive value; but we allow a - * negative value for convenience. */ - if (delta && vshCommandOptBool(cmd, "shrink")){ - capacityStr++; - } else { - vshError(ctl, "%s", - _("negative size requires --delta and --shrink")); - goto cleanup; - } - } - if (vshVolSize(capacityStr, &capacity) < 0) { - vshError(ctl, _("Malformed size %s"), capacityStr); - goto cleanup; - } - - if (virStorageVolResize(vol, capacity, flags) == 0) { - vshPrint(ctl, - delta ? _("Size of volume '%s' successfully changed by %s\n") - : _("Size of volume '%s' successfully changed to %s\n"), - virStorageVolGetName(vol), capacityStr); - ret = true; - } else { - vshError(ctl, - delta ? _("Failed to change size of volume '%s' by %s\n") - : _("Failed to change size of volume '%s' to %s\n"), - virStorageVolGetName(vol), capacityStr); - ret = false; - } - -cleanup: - virStorageVolFree(vol); - return ret; -} - - -/* - * "vol-dumpxml" command - */ -static const vshCmdInfo info_vol_dumpxml[] = { - {"help", N_("vol information in XML")}, - {"desc", N_("Output the vol information as an XML dump to stdout.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_vol_dumpxml[] = { - {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("vol name, key or path")}, - {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdVolDumpXML(vshControl *ctl, const vshCmd *cmd) -{ - virStorageVolPtr vol; - bool ret = true; - char *dump; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", NULL))) - return false; - - dump = virStorageVolGetXMLDesc(vol, 0); - if (dump != NULL) { - vshPrint(ctl, "%s", dump); - VIR_FREE(dump); - } else { - ret = false; - } - - virStorageVolFree(vol); - return ret; -} - - -/* - * "vol-list" command - */ -static const vshCmdInfo info_vol_list[] = { - {"help", N_("list vols")}, - {"desc", N_("Returns list of vols by pool.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_vol_list[] = { - {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")}, - {"details", VSH_OT_BOOL, 0, N_("display extended details for volumes")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdVolList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) -{ - virStorageVolInfo volumeInfo; - virStoragePoolPtr pool; - char **activeNames = NULL; - char *outputStr = NULL; - const char *unit; - double val; - bool details = vshCommandOptBool(cmd, "details"); - int numVolumes = 0, i; - int ret; - bool functionReturn; - int stringLength = 0; - size_t allocStrLength = 0, capStrLength = 0; - size_t nameStrLength = 0, pathStrLength = 0; - size_t typeStrLength = 0; - struct volInfoText { - char *allocation; - char *capacity; - char *path; - char *type; - }; - struct volInfoText *volInfoTexts = NULL; - - /* Check the connection to libvirtd daemon is still working */ - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - /* Look up the pool information given to us by the user */ - if (!(pool = vshCommandOptPool(ctl, cmd, "pool", NULL))) - return false; - - /* Determine the number of volumes in the pool */ - numVolumes = virStoragePoolNumOfVolumes(pool); - - if (numVolumes < 0) { - vshError(ctl, "%s", _("Failed to list storage volumes")); - virStoragePoolFree(pool); - return false; - } - - /* Retrieve the list of volume names in the pool */ - if (numVolumes > 0) { - activeNames = vshCalloc(ctl, numVolumes, sizeof(*activeNames)); - if ((numVolumes = virStoragePoolListVolumes(pool, activeNames, - numVolumes)) < 0) { - vshError(ctl, "%s", _("Failed to list active vols")); - VIR_FREE(activeNames); - virStoragePoolFree(pool); - return false; - } - - /* Sort the volume names */ - qsort(&activeNames[0], numVolumes, sizeof(*activeNames), vshNameSorter); - - /* Set aside memory for volume information pointers */ - volInfoTexts = vshCalloc(ctl, numVolumes, sizeof(*volInfoTexts)); - } - - /* Collect the rest of the volume information for display */ - for (i = 0; i < numVolumes; i++) { - /* Retrieve volume info */ - virStorageVolPtr vol = virStorageVolLookupByName(pool, - activeNames[i]); - - /* Retrieve the volume path */ - if ((volInfoTexts[i].path = virStorageVolGetPath(vol)) == NULL) { - /* Something went wrong retrieving a volume path, cope with it */ - volInfoTexts[i].path = vshStrdup(ctl, _("unknown")); - } - - /* If requested, retrieve volume type and sizing information */ - if (details) { - if (virStorageVolGetInfo(vol, &volumeInfo) != 0) { - /* Something went wrong retrieving volume info, cope with it */ - volInfoTexts[i].allocation = vshStrdup(ctl, _("unknown")); - volInfoTexts[i].capacity = vshStrdup(ctl, _("unknown")); - volInfoTexts[i].type = vshStrdup(ctl, _("unknown")); - } else { - /* Convert the returned volume info into output strings */ - - /* Volume type */ - switch (volumeInfo.type) { - case VIR_STORAGE_VOL_FILE: - volInfoTexts[i].type = vshStrdup(ctl, _("file")); - break; - case VIR_STORAGE_VOL_BLOCK: - volInfoTexts[i].type = vshStrdup(ctl, _("block")); - break; - case VIR_STORAGE_VOL_DIR: - volInfoTexts[i].type = vshStrdup(ctl, _("dir")); - break; - default: - volInfoTexts[i].type = vshStrdup(ctl, _("unknown")); - } - - /* Create the capacity output string */ - val = prettyCapacity(volumeInfo.capacity, &unit); - ret = virAsprintf(&volInfoTexts[i].capacity, - "%.2lf %s", val, unit); - if (ret < 0) { - /* An error occurred creating the string, return */ - goto asprintf_failure; - } - - /* Create the allocation output string */ - val = prettyCapacity(volumeInfo.allocation, &unit); - ret = virAsprintf(&volInfoTexts[i].allocation, - "%.2lf %s", val, unit); - if (ret < 0) { - /* An error occurred creating the string, return */ - goto asprintf_failure; - } - } - - /* Remember the largest length for each output string. - * This lets us displaying header and volume information rows - * using a single, properly sized, printf style output string. - */ - - /* Keep the length of name string if longest so far */ - stringLength = strlen(activeNames[i]); - if (stringLength > nameStrLength) - nameStrLength = stringLength; - - /* Keep the length of path string if longest so far */ - stringLength = strlen(volInfoTexts[i].path); - if (stringLength > pathStrLength) - pathStrLength = stringLength; - - /* Keep the length of type string if longest so far */ - stringLength = strlen(volInfoTexts[i].type); - if (stringLength > typeStrLength) - typeStrLength = stringLength; - - /* Keep the length of capacity string if longest so far */ - stringLength = strlen(volInfoTexts[i].capacity); - if (stringLength > capStrLength) - capStrLength = stringLength; - - /* Keep the length of allocation string if longest so far */ - stringLength = strlen(volInfoTexts[i].allocation); - if (stringLength > allocStrLength) - allocStrLength = stringLength; - } - - /* Cleanup memory allocation */ - virStorageVolFree(vol); - } - - /* If the --details option wasn't selected, we output the volume - * info using the fixed string format from previous versions to - * maintain backward compatibility. - */ - - /* Output basic info then return if --details option not selected */ - if (!details) { - /* The old output format */ - vshPrintExtra(ctl, "%-20s %-40s\n", _("Name"), _("Path")); - vshPrintExtra(ctl, "-----------------------------------------\n"); - for (i = 0; i < numVolumes; i++) { - vshPrint(ctl, "%-20s %-40s\n", activeNames[i], - volInfoTexts[i].path); - } + return false;
- /* Cleanup and return */ - functionReturn = true; - goto cleanup; + srcList = virConnectFindStoragePoolSources(ctl->conn, type, srcSpec, 0); + VIR_FREE(srcSpec); + if (srcList == NULL) { + vshError(ctl, _("Failed to find any %s pool sources"), type); + return false; } + vshPrint(ctl, "%s", srcList); + VIR_FREE(srcList);
- /* We only get here if the --details option was selected. */ + return true; +}
- /* Use the length of name header string if it's longest */ - stringLength = strlen(_("Name")); - if (stringLength > nameStrLength) - nameStrLength = stringLength;
- /* Use the length of path header string if it's longest */ - stringLength = strlen(_("Path")); - if (stringLength > pathStrLength) - pathStrLength = stringLength; +/* + * "pool-info" command + */ +static const vshCmdInfo info_pool_info[] = { + {"help", N_("storage pool information")}, + {"desc", N_("Returns basic information about the storage pool.")}, + {NULL, NULL} +};
- /* Use the length of type header string if it's longest */ - stringLength = strlen(_("Type")); - if (stringLength > typeStrLength) - typeStrLength = stringLength; +static const vshCmdOptDef opts_pool_info[] = { + {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")}, + {NULL, 0, 0, NULL} +};
- /* Use the length of capacity header string if it's longest */ - stringLength = strlen(_("Capacity")); - if (stringLength > capStrLength) - capStrLength = stringLength; +static bool +cmdPoolInfo(vshControl *ctl, const vshCmd *cmd) +{ + virStoragePoolInfo info; + virStoragePoolPtr pool; + int autostart = 0; + int persistent = 0; + bool ret = true; + char uuid[VIR_UUID_STRING_BUFLEN];
- /* Use the length of allocation header string if it's longest */ - stringLength = strlen(_("Allocation")); - if (stringLength > allocStrLength) - allocStrLength = stringLength; + if (!vshConnectionUsability(ctl, ctl->conn)) + return false;
- /* Display the string lengths for debugging */ - vshDebug(ctl, VSH_ERR_DEBUG, - "Longest name string = %zu chars\n", nameStrLength); - vshDebug(ctl, VSH_ERR_DEBUG, - "Longest path string = %zu chars\n", pathStrLength); - vshDebug(ctl, VSH_ERR_DEBUG, - "Longest type string = %zu chars\n", typeStrLength); - vshDebug(ctl, VSH_ERR_DEBUG, - "Longest capacity string = %zu chars\n", capStrLength); - vshDebug(ctl, VSH_ERR_DEBUG, - "Longest allocation string = %zu chars\n", allocStrLength); + if (!(pool = vshCommandOptPool(ctl, cmd, "pool", NULL))) + return false;
- /* Create the output template */ - ret = virAsprintf(&outputStr, - "%%-%lus %%-%lus %%-%lus %%%lus %%%lus\n", - (unsigned long) nameStrLength, - (unsigned long) pathStrLength, - (unsigned long) typeStrLength, - (unsigned long) capStrLength, - (unsigned long) allocStrLength); - if (ret < 0) { - /* An error occurred creating the string, return */ - goto asprintf_failure; - } + vshPrint(ctl, "%-15s %s\n", _("Name:"), virStoragePoolGetName(pool));
- /* Display the header */ - vshPrint(ctl, outputStr, _("Name"), _("Path"), _("Type"), - ("Capacity"), _("Allocation")); - for (i = nameStrLength + pathStrLength + typeStrLength - + capStrLength + allocStrLength - + 8; i > 0; i--) - vshPrintExtra(ctl, "-"); - vshPrintExtra(ctl, "\n"); + if (virStoragePoolGetUUIDString(pool, &uuid[0])==0) + vshPrint(ctl, "%-15s %s\n", _("UUID:"), uuid);
- /* Display the volume info rows */ - for (i = 0; i < numVolumes; i++) { - vshPrint(ctl, outputStr, - activeNames[i], - volInfoTexts[i].path, - volInfoTexts[i].type, - volInfoTexts[i].capacity, - volInfoTexts[i].allocation); - } + if (virStoragePoolGetInfo(pool, &info) == 0) { + double val; + const char *unit; + switch (info.state) { + case VIR_STORAGE_POOL_INACTIVE: + vshPrint(ctl, "%-15s %s\n", _("State:"), + _("inactive")); + break; + case VIR_STORAGE_POOL_BUILDING: + vshPrint(ctl, "%-15s %s\n", _("State:"), + _("building")); + break; + case VIR_STORAGE_POOL_RUNNING: + vshPrint(ctl, "%-15s %s\n", _("State:"), + _("running")); + break; + case VIR_STORAGE_POOL_DEGRADED: + vshPrint(ctl, "%-15s %s\n", _("State:"), + _("degraded")); + break; + case VIR_STORAGE_POOL_INACCESSIBLE: + vshPrint(ctl, "%-15s %s\n", _("State:"), + _("inaccessible")); + break; + }
- /* Cleanup and return */ - functionReturn = true; - goto cleanup; + /* Check and display whether the pool is persistent or not */ + persistent = virStoragePoolIsPersistent(pool); + vshDebug(ctl, VSH_ERR_DEBUG, "Pool persistent flag value: %d\n", + persistent); + if (persistent < 0) + vshPrint(ctl, "%-15s %s\n", _("Persistent:"), _("unknown")); + else + vshPrint(ctl, "%-15s %s\n", _("Persistent:"), persistent ? _("yes") : _("no"));
-asprintf_failure: + /* Check and display whether the pool is autostarted or not */ + virStoragePoolGetAutostart(pool, &autostart); + vshDebug(ctl, VSH_ERR_DEBUG, "Pool autostart flag value: %d\n", + autostart); + if (autostart < 0) + vshPrint(ctl, "%-15s %s\n", _("Autostart:"), _("no autostart")); + else + vshPrint(ctl, "%-15s %s\n", _("Autostart:"), autostart ? _("yes") : _("no"));
- /* Display an appropriate error message then cleanup and return */ - switch (errno) { - case ENOMEM: - /* Couldn't allocate memory */ - vshError(ctl, "%s", _("Out of memory")); - break; - default: - /* Some other error */ - vshError(ctl, _("virAsprintf failed (errno %d)"), errno); - } - functionReturn = false; + if (info.state == VIR_STORAGE_POOL_RUNNING || + info.state == VIR_STORAGE_POOL_DEGRADED) { + val = prettyCapacity(info.capacity, &unit); + vshPrint(ctl, "%-15s %2.2lf %s\n", _("Capacity:"), val, unit);
-cleanup: + val = prettyCapacity(info.allocation, &unit); + vshPrint(ctl, "%-15s %2.2lf %s\n", _("Allocation:"), val, unit);
- /* Safely free the memory allocated in this function */ - for (i = 0; i < numVolumes; i++) { - /* Cleanup the memory for one volume info structure per loop */ - VIR_FREE(volInfoTexts[i].path); - VIR_FREE(volInfoTexts[i].type); - VIR_FREE(volInfoTexts[i].capacity); - VIR_FREE(volInfoTexts[i].allocation); - VIR_FREE(activeNames[i]); + val = prettyCapacity(info.available, &unit); + vshPrint(ctl, "%-15s %2.2lf %s\n", _("Available:"), val, unit); + } + } else { + ret = false; }
- /* Cleanup remaining memory */ - VIR_FREE(outputStr); - VIR_FREE(volInfoTexts); - VIR_FREE(activeNames); virStoragePoolFree(pool); - - /* Return the desired value */ - return functionReturn; + return ret; }
/* - * "vol-name" command + * "pool-name" command */ -static const vshCmdInfo info_vol_name[] = { - {"help", N_("returns the volume name for a given volume key or path")}, +static const vshCmdInfo info_pool_name[] = { + {"help", N_("convert a pool UUID to pool name")}, {"desc", ""}, {NULL, NULL} };
-static const vshCmdOptDef opts_vol_name[] = { - {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("volume key or path")}, +static const vshCmdOptDef opts_pool_name[] = { + {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool uuid")}, {NULL, 0, 0, NULL} };
static bool -cmdVolName(vshControl *ctl, const vshCmd *cmd) +cmdPoolName(vshControl *ctl, const vshCmd *cmd) { - virStorageVolPtr vol; + virStoragePoolPtr pool;
if (!vshConnectionUsability(ctl, ctl->conn)) return false; - - if (!(vol = vshCommandOptVolBy(ctl, cmd, "vol", NULL, NULL, - VSH_BYUUID))) + if (!(pool = vshCommandOptPoolBy(ctl, cmd, "pool", NULL, + VSH_BYUUID))) return false;
- vshPrint(ctl, "%s\n", virStorageVolGetName(vol)); - virStorageVolFree(vol); + vshPrint(ctl, "%s\n", virStoragePoolGetName(pool)); + virStoragePoolFree(pool); return true; }
/* - * "vol-pool" command + * "pool-start" command */ -static const vshCmdInfo info_vol_pool[] = { - {"help", N_("returns the storage pool for a given volume key or path")}, - {"desc", ""}, +static const vshCmdInfo info_pool_start[] = { + {"help", N_("start a (previously defined) inactive pool")}, + {"desc", N_("Start a pool.")}, {NULL, NULL} };
-static const vshCmdOptDef opts_vol_pool[] = { - {"uuid", VSH_OT_BOOL, 0, N_("return the pool uuid rather than pool name")}, - {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("volume key or path")}, +static const vshCmdOptDef opts_pool_start[] = { + {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("name or uuid of the inactive pool")}, {NULL, 0, 0, NULL} };
static bool -cmdVolPool(vshControl *ctl, const vshCmd *cmd) +cmdPoolStart(vshControl *ctl, const vshCmd *cmd) { virStoragePoolPtr pool; - virStorageVolPtr vol; - char uuid[VIR_UUID_STRING_BUFLEN]; + bool ret = true; + const char *name = NULL;
- /* Check the connection to libvirtd daemon is still working */ if (!vshConnectionUsability(ctl, ctl->conn)) return false;
- /* Use the supplied string to locate the volume */ - if (!(vol = vshCommandOptVolBy(ctl, cmd, "vol", NULL, NULL, - VSH_BYUUID))) { - return false; - } - - /* Look up the parent storage pool for the volume */ - pool = virStoragePoolLookupByVolume(vol); - if (pool == NULL) { - vshError(ctl, "%s", _("failed to get parent pool")); - virStorageVolFree(vol); - return false; - } + if (!(pool = vshCommandOptPool(ctl, cmd, "pool", &name))) + return false;
- /* Return the requested details of the parent storage pool */ - if (vshCommandOptBool(cmd, "uuid")) { - /* Retrieve and return pool UUID string */ - if (virStoragePoolGetUUIDString(pool, &uuid[0]) == 0) - vshPrint(ctl, "%s\n", uuid); + if (virStoragePoolCreate(pool, 0) == 0) { + vshPrint(ctl, _("Pool %s started\n"), name); } else { - /* Return the storage pool name */ - vshPrint(ctl, "%s\n", virStoragePoolGetName(pool)); + vshError(ctl, _("Failed to start pool %s"), name); + ret = false; }
- /* Cleanup */ - virStorageVolFree(vol); virStoragePoolFree(pool); - return true; + return ret; }
- /* - * "vol-key" command + * "pool-undefine" command */ -static const vshCmdInfo info_vol_key[] = { - {"help", N_("returns the volume key for a given volume name or path")}, - {"desc", ""}, +static const vshCmdInfo info_pool_undefine[] = { + {"help", N_("undefine an inactive pool")}, + {"desc", N_("Undefine the configuration for an inactive pool.")}, {NULL, NULL} };
-static const vshCmdOptDef opts_vol_key[] = { - {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("volume name or path")}, - {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")}, +static const vshCmdOptDef opts_pool_undefine[] = { + {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")}, {NULL, 0, 0, NULL} };
static bool -cmdVolKey(vshControl *ctl, const vshCmd *cmd) +cmdPoolUndefine(vshControl *ctl, const vshCmd *cmd) { - virStorageVolPtr vol; + virStoragePoolPtr pool; + bool ret = true; + const char *name;
if (!vshConnectionUsability(ctl, ctl->conn)) return false;
- if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", NULL))) + if (!(pool = vshCommandOptPool(ctl, cmd, "pool", &name))) return false;
- vshPrint(ctl, "%s\n", virStorageVolGetKey(vol)); - virStorageVolFree(vol); - return true; -} + if (virStoragePoolUndefine(pool) == 0) { + vshPrint(ctl, _("Pool %s has been undefined\n"), name); + } else { + vshError(ctl, _("Failed to undefine pool %s"), name); + ret = false; + }
+ virStoragePoolFree(pool); + return ret; +}
/* - * "vol-path" command + * "pool-uuid" command */ -static const vshCmdInfo info_vol_path[] = { - {"help", N_("returns the volume path for a given volume name or key")}, +static const vshCmdInfo info_pool_uuid[] = { + {"help", N_("convert a pool name to pool UUID")}, {"desc", ""}, {NULL, NULL} };
-static const vshCmdOptDef opts_vol_path[] = { - {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("volume name or key")}, - {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")}, +static const vshCmdOptDef opts_pool_uuid[] = { + {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name")}, {NULL, 0, 0, NULL} };
static bool -cmdVolPath(vshControl *ctl, const vshCmd *cmd) +cmdPoolUuid(vshControl *ctl, const vshCmd *cmd) { - virStorageVolPtr vol; - char * StorageVolPath; + virStoragePoolPtr pool; + char uuid[VIR_UUID_STRING_BUFLEN];
if (!vshConnectionUsability(ctl, ctl->conn)) return false;
- if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", NULL))) { + if (!(pool = vshCommandOptPoolBy(ctl, cmd, "pool", NULL, + VSH_BYNAME))) return false; - }
- if ((StorageVolPath = virStorageVolGetPath(vol)) == NULL) { - virStorageVolFree(vol); - return false; - } + if (virStoragePoolGetUUIDString(pool, uuid) != -1) + vshPrint(ctl, "%s\n", uuid); + else + vshError(ctl, "%s", _("failed to get pool UUID"));
- vshPrint(ctl, "%s\n", StorageVolPath); - VIR_FREE(StorageVolPath); - virStorageVolFree(vol); + virStoragePoolFree(pool); return true; }
- /* * "secret-define" command */ @@ -9618,66 +8240,6 @@ vshCommandOptPoolBy(vshControl *ctl, const vshCmd *cmd, const char *optname, return pool; }
-static virStorageVolPtr -vshCommandOptVolBy(vshControl *ctl, const vshCmd *cmd, - const char *optname, - const char *pooloptname, - const char **name, int flag) -{ - virStorageVolPtr vol = NULL; - virStoragePoolPtr pool = NULL; - const char *n = NULL, *p = NULL; - - if (vshCommandOptString(cmd, optname, &n) <= 0) - return NULL; - - if (pooloptname != NULL && vshCommandOptString(cmd, pooloptname, &p) < 0) { - vshError(ctl, "%s", _("missing option")); - return NULL; - } - - if (p) - pool = vshCommandOptPoolBy(ctl, cmd, pooloptname, name, flag); - - vshDebug(ctl, VSH_ERR_DEBUG, "%s: found option <%s>: %s\n", - cmd->def->name, optname, n); - - if (name) - *name = n; - - /* try it by name */ - if (pool && (flag & VSH_BYNAME)) { - vshDebug(ctl, VSH_ERR_DEBUG, "%s: <%s> trying as vol name\n", - cmd->def->name, optname); - vol = virStorageVolLookupByName(pool, n); - } - /* try it by key */ - if (vol == NULL && (flag & VSH_BYUUID)) { - vshDebug(ctl, VSH_ERR_DEBUG, "%s: <%s> trying as vol key\n", - cmd->def->name, optname); - vol = virStorageVolLookupByKey(ctl->conn, n); - } - /* try it by path */ - if (vol == NULL && (flag & VSH_BYUUID)) { - vshDebug(ctl, VSH_ERR_DEBUG, "%s: <%s> trying as vol path\n", - cmd->def->name, optname); - vol = virStorageVolLookupByPath(ctl->conn, n); - } - - if (!vol) { - if (pool) - vshError(ctl, _("failed to get vol '%s'"), n); - else - vshError(ctl, _("failed to get vol '%s', specifying --%s " - "might help"), n, pooloptname); - } - - if (pool) - virStoragePoolFree(pool); - - return vol; -} - static virSecretPtr vshCommandOptSecret(vshControl *ctl, const vshCmd *cmd, const char **name) { @@ -11171,6 +9733,8 @@ static const vshCmdDef storagePoolCmds[] = { {NULL, NULL, NULL, NULL, 0} };
+#include "virsh-volume.c" + static const vshCmdDef storageVolCmds[] = { {"vol-clone", cmdVolClone, opts_vol_clone, info_vol_clone, 0}, {"vol-create-as", cmdVolCreateAs, opts_vol_create_as,
I noticed just a removal of the function prototype for vshCommandOptVolBy that is obviously not needed, so ACK. Martin

This splits commands of storage pool group into virsh-pool.c, The helpers not for common use are moved too. Standard copyright is added for the new file. * tools/virsh.c: Remove commands for storage storage pool and a few helpers. (vshCommandOptVol, vshCommandOptVolBy). * tools/virsh-pool.c: New file, filled with commands of storage pool group and its helpers. --- tools/virsh-pool.c | 1415 +++++++++++++++++++++++++++++++++++++++++++ tools/virsh.c | 1690 +++++----------------------------------------------- 2 files changed, 1556 insertions(+), 1549 deletions(-) create mode 100644 tools/virsh-pool.c diff --git a/tools/virsh-pool.c b/tools/virsh-pool.c new file mode 100644 index 0000000..6a1208f --- /dev/null +++ b/tools/virsh-pool.c @@ -0,0 +1,1415 @@ +/* + * virsh-pool.c: Commands to manage storage pool + * + * Copyright (C) 2005, 2007-2012 Red Hat, Inc + * + * 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 + * License along with this library; If not, see + * <http://www.gnu.org/licenses/>. + * + * Daniel Veillard <veillard@redhat.com> + * Karel Zak <kzak@redhat.com> + * Daniel P. Berrange <berrange@redhat.com> + * + */ + +/* default is lookup by Name and UUID */ +#define vshCommandOptPool(_ctl, _cmd, _optname, _name) \ + vshCommandOptPoolBy(_ctl, _cmd, _optname, _name, \ + VSH_BYUUID|VSH_BYNAME) + +static virStoragePoolPtr +vshCommandOptPoolBy(vshControl *ctl, const vshCmd *cmd, const char *optname, + const char **name, int flag) +{ + virStoragePoolPtr pool = NULL; + const char *n = NULL; + + if (vshCommandOptString(cmd, optname, &n) <= 0) + return NULL; + + vshDebug(ctl, VSH_ERR_INFO, "%s: found option <%s>: %s\n", + cmd->def->name, optname, n); + + if (name) + *name = n; + + /* try it by UUID */ + if ((flag & VSH_BYUUID) && strlen(n) == VIR_UUID_STRING_BUFLEN-1) { + vshDebug(ctl, VSH_ERR_DEBUG, "%s: <%s> trying as pool UUID\n", + cmd->def->name, optname); + pool = virStoragePoolLookupByUUIDString(ctl->conn, n); + } + /* try it by NAME */ + if (pool == NULL && (flag & VSH_BYNAME)) { + vshDebug(ctl, VSH_ERR_DEBUG, "%s: <%s> trying as pool NAME\n", + cmd->def->name, optname); + pool = virStoragePoolLookupByName(ctl->conn, n); + } + + if (!pool) + vshError(ctl, _("failed to get pool '%s'"), n); + + return pool; +} + +/* + * "pool-autostart" command + */ +static const vshCmdInfo info_pool_autostart[] = { + {"help", N_("autostart a pool")}, + {"desc", + N_("Configure a pool to be automatically started at boot.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_pool_autostart[] = { + {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")}, + {"disable", VSH_OT_BOOL, 0, N_("disable autostarting")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdPoolAutostart(vshControl *ctl, const vshCmd *cmd) +{ + virStoragePoolPtr pool; + const char *name; + int autostart; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(pool = vshCommandOptPool(ctl, cmd, "pool", &name))) + return false; + + autostart = !vshCommandOptBool(cmd, "disable"); + + if (virStoragePoolSetAutostart(pool, autostart) < 0) { + if (autostart) + vshError(ctl, _("failed to mark pool %s as autostarted"), name); + else + vshError(ctl, _("failed to unmark pool %s as autostarted"), name); + virStoragePoolFree(pool); + return false; + } + + if (autostart) + vshPrint(ctl, _("Pool %s marked as autostarted\n"), name); + else + vshPrint(ctl, _("Pool %s unmarked as autostarted\n"), name); + + virStoragePoolFree(pool); + return true; +} + +/* + * "pool-create" command + */ +static const vshCmdInfo info_pool_create[] = { + {"help", N_("create a pool from an XML file")}, + {"desc", N_("Create a pool.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_pool_create[] = { + {"file", VSH_OT_DATA, VSH_OFLAG_REQ, + N_("file containing an XML pool description")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdPoolCreate(vshControl *ctl, const vshCmd *cmd) +{ + virStoragePoolPtr pool; + const char *from = NULL; + bool ret = true; + char *buffer; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (vshCommandOptString(cmd, "file", &from) <= 0) + return false; + + if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0) + return false; + + pool = virStoragePoolCreateXML(ctl->conn, buffer, 0); + VIR_FREE(buffer); + + if (pool != NULL) { + vshPrint(ctl, _("Pool %s created from %s\n"), + virStoragePoolGetName(pool), from); + virStoragePoolFree(pool); + } else { + vshError(ctl, _("Failed to create pool from %s"), from); + ret = false; + } + return ret; +} + +/* + * XML Building helper for pool-define-as and pool-create-as + */ +static const vshCmdOptDef opts_pool_X_as[] = { + {"name", VSH_OT_DATA, VSH_OFLAG_REQ, N_("name of the pool")}, + {"print-xml", VSH_OT_BOOL, 0, N_("print XML document, but don't define/create")}, + {"type", VSH_OT_DATA, VSH_OFLAG_REQ, N_("type of the pool")}, + {"source-host", VSH_OT_DATA, 0, N_("source-host for underlying storage")}, + {"source-path", VSH_OT_DATA, 0, N_("source path for underlying storage")}, + {"source-dev", VSH_OT_DATA, 0, N_("source device for underlying storage")}, + {"source-name", VSH_OT_DATA, 0, N_("source name for underlying storage")}, + {"target", VSH_OT_DATA, 0, N_("target for underlying storage")}, + {"source-format", VSH_OT_STRING, 0, N_("format for underlying storage")}, + {NULL, 0, 0, NULL} +}; + +static int buildPoolXML(const vshCmd *cmd, const char **retname, char **xml) { + + const char *name = NULL, *type = NULL, *srcHost = NULL, *srcPath = NULL, + *srcDev = NULL, *srcName = NULL, *srcFormat = NULL, *target = NULL; + virBuffer buf = VIR_BUFFER_INITIALIZER; + + if (vshCommandOptString(cmd, "name", &name) <= 0) + goto cleanup; + if (vshCommandOptString(cmd, "type", &type) <= 0) + goto cleanup; + + if (vshCommandOptString(cmd, "source-host", &srcHost) < 0 || + vshCommandOptString(cmd, "source-path", &srcPath) < 0 || + vshCommandOptString(cmd, "source-dev", &srcDev) < 0 || + vshCommandOptString(cmd, "source-name", &srcName) < 0 || + vshCommandOptString(cmd, "source-format", &srcFormat) < 0 || + vshCommandOptString(cmd, "target", &target) < 0) { + vshError(NULL, "%s", _("missing argument")); + goto cleanup; + } + + virBufferAsprintf(&buf, "<pool type='%s'>\n", type); + virBufferAsprintf(&buf, " <name>%s</name>\n", name); + if (srcHost || srcPath || srcDev || srcFormat || srcName) { + virBufferAddLit(&buf, " <source>\n"); + + if (srcHost) + virBufferAsprintf(&buf, " <host name='%s'/>\n", srcHost); + if (srcPath) + virBufferAsprintf(&buf, " <dir path='%s'/>\n", srcPath); + if (srcDev) + virBufferAsprintf(&buf, " <device path='%s'/>\n", srcDev); + if (srcFormat) + virBufferAsprintf(&buf, " <format type='%s'/>\n", srcFormat); + if (srcName) + virBufferAsprintf(&buf, " <name>%s</name>\n", srcName); + + virBufferAddLit(&buf, " </source>\n"); + } + if (target) { + virBufferAddLit(&buf, " <target>\n"); + virBufferAsprintf(&buf, " <path>%s</path>\n", target); + virBufferAddLit(&buf, " </target>\n"); + } + virBufferAddLit(&buf, "</pool>\n"); + + if (virBufferError(&buf)) { + vshPrint(ctl, "%s", _("Failed to allocate XML buffer")); + return false; + } + + *xml = virBufferContentAndReset(&buf); + *retname = name; + return true; + +cleanup: + virBufferFreeAndReset(&buf); + return false; +} + +/* + * "pool-create-as" command + */ +static const vshCmdInfo info_pool_create_as[] = { + {"help", N_("create a pool from a set of args")}, + {"desc", N_("Create a pool.")}, + {NULL, NULL} +}; + +static bool +cmdPoolCreateAs(vshControl *ctl, const vshCmd *cmd) +{ + virStoragePoolPtr pool; + const char *name; + char *xml; + bool printXML = vshCommandOptBool(cmd, "print-xml"); + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!buildPoolXML(cmd, &name, &xml)) + return false; + + if (printXML) { + vshPrint(ctl, "%s", xml); + VIR_FREE(xml); + } else { + pool = virStoragePoolCreateXML(ctl->conn, xml, 0); + VIR_FREE(xml); + + if (pool != NULL) { + vshPrint(ctl, _("Pool %s created\n"), name); + virStoragePoolFree(pool); + } else { + vshError(ctl, _("Failed to create pool %s"), name); + return false; + } + } + return true; +} + +/* + * "pool-define" command + */ +static const vshCmdInfo info_pool_define[] = { + {"help", N_("define (but don't start) a pool from an XML file")}, + {"desc", N_("Define a pool.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_pool_define[] = { + {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containing an XML pool description")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdPoolDefine(vshControl *ctl, const vshCmd *cmd) +{ + virStoragePoolPtr pool; + const char *from = NULL; + bool ret = true; + char *buffer; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (vshCommandOptString(cmd, "file", &from) <= 0) + return false; + + if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0) + return false; + + pool = virStoragePoolDefineXML(ctl->conn, buffer, 0); + VIR_FREE(buffer); + + if (pool != NULL) { + vshPrint(ctl, _("Pool %s defined from %s\n"), + virStoragePoolGetName(pool), from); + virStoragePoolFree(pool); + } else { + vshError(ctl, _("Failed to define pool from %s"), from); + ret = false; + } + return ret; +} + +/* + * "pool-define-as" command + */ +static const vshCmdInfo info_pool_define_as[] = { + {"help", N_("define a pool from a set of args")}, + {"desc", N_("Define a pool.")}, + {NULL, NULL} +}; + +static bool +cmdPoolDefineAs(vshControl *ctl, const vshCmd *cmd) +{ + virStoragePoolPtr pool; + const char *name; + char *xml; + bool printXML = vshCommandOptBool(cmd, "print-xml"); + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!buildPoolXML(cmd, &name, &xml)) + return false; + + if (printXML) { + vshPrint(ctl, "%s", xml); + VIR_FREE(xml); + } else { + pool = virStoragePoolDefineXML(ctl->conn, xml, 0); + VIR_FREE(xml); + + if (pool != NULL) { + vshPrint(ctl, _("Pool %s defined\n"), name); + virStoragePoolFree(pool); + } else { + vshError(ctl, _("Failed to define pool %s"), name); + return false; + } + } + return true; +} + +/* + * "pool-build" command + */ +static const vshCmdInfo info_pool_build[] = { + {"help", N_("build a pool")}, + {"desc", N_("Build a given pool.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_pool_build[] = { + {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")}, + {"no-overwrite", VSH_OT_BOOL, 0, N_("do not overwrite an existing pool of this type")}, + {"overwrite", VSH_OT_BOOL, 0, N_("overwrite any existing data")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdPoolBuild(vshControl *ctl, const vshCmd *cmd) +{ + virStoragePoolPtr pool; + bool ret = true; + const char *name; + unsigned int flags = 0; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(pool = vshCommandOptPool(ctl, cmd, "pool", &name))) + return false; + + if (vshCommandOptBool(cmd, "no-overwrite")) { + flags |= VIR_STORAGE_POOL_BUILD_NO_OVERWRITE; + } + + if (vshCommandOptBool(cmd, "overwrite")) { + flags |= VIR_STORAGE_POOL_BUILD_OVERWRITE; + } + + if (virStoragePoolBuild(pool, flags) == 0) { + vshPrint(ctl, _("Pool %s built\n"), name); + } else { + vshError(ctl, _("Failed to build pool %s"), name); + ret = false; + } + + virStoragePoolFree(pool); + + return ret; +} + +/* + * "pool-destroy" command + */ +static const vshCmdInfo info_pool_destroy[] = { + {"help", N_("destroy (stop) a pool")}, + {"desc", + N_("Forcefully stop a given pool. Raw data in the pool is untouched")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_pool_destroy[] = { + {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdPoolDestroy(vshControl *ctl, const vshCmd *cmd) +{ + virStoragePoolPtr pool; + bool ret = true; + const char *name; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(pool = vshCommandOptPool(ctl, cmd, "pool", &name))) + return false; + + if (virStoragePoolDestroy(pool) == 0) { + vshPrint(ctl, _("Pool %s destroyed\n"), name); + } else { + vshError(ctl, _("Failed to destroy pool %s"), name); + ret = false; + } + + virStoragePoolFree(pool); + return ret; +} + +/* + * "pool-delete" command + */ +static const vshCmdInfo info_pool_delete[] = { + {"help", N_("delete a pool")}, + {"desc", N_("Delete a given pool.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_pool_delete[] = { + {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdPoolDelete(vshControl *ctl, const vshCmd *cmd) +{ + virStoragePoolPtr pool; + bool ret = true; + const char *name; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(pool = vshCommandOptPool(ctl, cmd, "pool", &name))) + return false; + + if (virStoragePoolDelete(pool, 0) == 0) { + vshPrint(ctl, _("Pool %s deleted\n"), name); + } else { + vshError(ctl, _("Failed to delete pool %s"), name); + ret = false; + } + + virStoragePoolFree(pool); + return ret; +} + +/* + * "pool-refresh" command + */ +static const vshCmdInfo info_pool_refresh[] = { + {"help", N_("refresh a pool")}, + {"desc", N_("Refresh a given pool.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_pool_refresh[] = { + {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdPoolRefresh(vshControl *ctl, const vshCmd *cmd) +{ + virStoragePoolPtr pool; + bool ret = true; + const char *name; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(pool = vshCommandOptPool(ctl, cmd, "pool", &name))) + return false; + + if (virStoragePoolRefresh(pool, 0) == 0) { + vshPrint(ctl, _("Pool %s refreshed\n"), name); + } else { + vshError(ctl, _("Failed to refresh pool %s"), name); + ret = false; + } + virStoragePoolFree(pool); + + return ret; +} + +/* + * "pool-dumpxml" command + */ +static const vshCmdInfo info_pool_dumpxml[] = { + {"help", N_("pool information in XML")}, + {"desc", N_("Output the pool information as an XML dump to stdout.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_pool_dumpxml[] = { + {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")}, + {"inactive", VSH_OT_BOOL, 0, N_("show inactive defined XML")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdPoolDumpXML(vshControl *ctl, const vshCmd *cmd) +{ + virStoragePoolPtr pool; + bool ret = true; + bool inactive = vshCommandOptBool(cmd, "inactive"); + unsigned int flags = 0; + char *dump; + + if (inactive) + flags |= VIR_STORAGE_XML_INACTIVE; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(pool = vshCommandOptPool(ctl, cmd, "pool", NULL))) + return false; + + dump = virStoragePoolGetXMLDesc(pool, flags); + if (dump != NULL) { + vshPrint(ctl, "%s", dump); + VIR_FREE(dump); + } else { + ret = false; + } + + virStoragePoolFree(pool); + return ret; +} + +/* + * "pool-list" command + */ +static const vshCmdInfo info_pool_list[] = { + {"help", N_("list pools")}, + {"desc", N_("Returns list of pools.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_pool_list[] = { + {"inactive", VSH_OT_BOOL, 0, N_("list inactive pools")}, + {"all", VSH_OT_BOOL, 0, N_("list inactive & active pools")}, + {"details", VSH_OT_BOOL, 0, N_("display extended details for pools")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdPoolList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) +{ + virStoragePoolInfo info; + char **poolNames = NULL; + int i, ret; + bool functionReturn; + int numActivePools = 0, numInactivePools = 0, numAllPools = 0; + size_t stringLength = 0, nameStrLength = 0; + size_t autostartStrLength = 0, persistStrLength = 0; + size_t stateStrLength = 0, capStrLength = 0; + size_t allocStrLength = 0, availStrLength = 0; + struct poolInfoText { + char *state; + char *autostart; + char *persistent; + char *capacity; + char *allocation; + char *available; + }; + struct poolInfoText *poolInfoTexts = NULL; + + /* Determine the options passed by the user */ + bool all = vshCommandOptBool(cmd, "all"); + bool details = vshCommandOptBool(cmd, "details"); + bool inactive = vshCommandOptBool(cmd, "inactive"); + bool active = !inactive || all; + inactive |= all; + + /* Check the connection to libvirtd daemon is still working */ + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + /* Retrieve the number of active storage pools */ + if (active) { + numActivePools = virConnectNumOfStoragePools(ctl->conn); + if (numActivePools < 0) { + vshError(ctl, "%s", _("Failed to list active pools")); + return false; + } + } + + /* Retrieve the number of inactive storage pools */ + if (inactive) { + numInactivePools = virConnectNumOfDefinedStoragePools(ctl->conn); + if (numInactivePools < 0) { + vshError(ctl, "%s", _("Failed to list inactive pools")); + return false; + } + } + + /* Determine the total number of pools to list */ + numAllPools = numActivePools + numInactivePools; + + /* Allocate memory for arrays of storage pool names and info */ + poolNames = vshCalloc(ctl, numAllPools, sizeof(*poolNames)); + poolInfoTexts = + vshCalloc(ctl, numAllPools, sizeof(*poolInfoTexts)); + + /* Retrieve a list of active storage pool names */ + if (active) { + if (virConnectListStoragePools(ctl->conn, + poolNames, numActivePools) < 0) { + vshError(ctl, "%s", _("Failed to list active pools")); + VIR_FREE(poolInfoTexts); + VIR_FREE(poolNames); + return false; + } + } + + /* Add the inactive storage pools to the end of the name list */ + if (inactive) { + if (virConnectListDefinedStoragePools(ctl->conn, + &poolNames[numActivePools], + numInactivePools) < 0) { + vshError(ctl, "%s", _("Failed to list inactive pools")); + VIR_FREE(poolInfoTexts); + VIR_FREE(poolNames); + return false; + } + } + + /* Sort the storage pool names */ + qsort(poolNames, numAllPools, sizeof(*poolNames), vshNameSorter); + + /* Collect the storage pool information for display */ + for (i = 0; i < numAllPools; i++) { + int autostart = 0, persistent = 0; + + /* Retrieve a pool object, looking it up by name */ + virStoragePoolPtr pool = virStoragePoolLookupByName(ctl->conn, + poolNames[i]); + if (!pool) { + VIR_FREE(poolNames[i]); + continue; + } + + /* Retrieve the autostart status of the pool */ + if (virStoragePoolGetAutostart(pool, &autostart) < 0) + poolInfoTexts[i].autostart = vshStrdup(ctl, _("no autostart")); + else + poolInfoTexts[i].autostart = vshStrdup(ctl, autostart ? + _("yes") : _("no")); + + /* Retrieve the persistence status of the pool */ + if (details) { + persistent = virStoragePoolIsPersistent(pool); + vshDebug(ctl, VSH_ERR_DEBUG, "Persistent flag value: %d\n", + persistent); + if (persistent < 0) + poolInfoTexts[i].persistent = vshStrdup(ctl, _("unknown")); + else + poolInfoTexts[i].persistent = vshStrdup(ctl, persistent ? + _("yes") : _("no")); + + /* Keep the length of persistent string if longest so far */ + stringLength = strlen(poolInfoTexts[i].persistent); + if (stringLength > persistStrLength) + persistStrLength = stringLength; + } + + /* Collect further extended information about the pool */ + if (virStoragePoolGetInfo(pool, &info) != 0) { + /* Something went wrong retrieving pool info, cope with it */ + vshError(ctl, "%s", _("Could not retrieve pool information")); + poolInfoTexts[i].state = vshStrdup(ctl, _("unknown")); + if (details) { + poolInfoTexts[i].capacity = vshStrdup(ctl, _("unknown")); + poolInfoTexts[i].allocation = vshStrdup(ctl, _("unknown")); + poolInfoTexts[i].available = vshStrdup(ctl, _("unknown")); + } + } else { + /* Decide which state string to display */ + if (details) { + /* --details option was specified, we're using detailed state + * strings */ + switch (info.state) { + case VIR_STORAGE_POOL_INACTIVE: + poolInfoTexts[i].state = vshStrdup(ctl, _("inactive")); + break; + case VIR_STORAGE_POOL_BUILDING: + poolInfoTexts[i].state = vshStrdup(ctl, _("building")); + break; + case VIR_STORAGE_POOL_RUNNING: + poolInfoTexts[i].state = vshStrdup(ctl, _("running")); + break; + case VIR_STORAGE_POOL_DEGRADED: + poolInfoTexts[i].state = vshStrdup(ctl, _("degraded")); + break; + case VIR_STORAGE_POOL_INACCESSIBLE: + poolInfoTexts[i].state = vshStrdup(ctl, _("inaccessible")); + break; + } + + /* Create the pool size related strings */ + if (info.state == VIR_STORAGE_POOL_RUNNING || + info.state == VIR_STORAGE_POOL_DEGRADED) { + double val; + const char *unit; + + /* Create the capacity output string */ + val = prettyCapacity(info.capacity, &unit); + ret = virAsprintf(&poolInfoTexts[i].capacity, + "%.2lf %s", val, unit); + if (ret < 0) { + /* An error occurred creating the string, return */ + goto asprintf_failure; + } + + /* Create the allocation output string */ + val = prettyCapacity(info.allocation, &unit); + ret = virAsprintf(&poolInfoTexts[i].allocation, + "%.2lf %s", val, unit); + if (ret < 0) { + /* An error occurred creating the string, return */ + goto asprintf_failure; + } + + /* Create the available space output string */ + val = prettyCapacity(info.available, &unit); + ret = virAsprintf(&poolInfoTexts[i].available, + "%.2lf %s", val, unit); + if (ret < 0) { + /* An error occurred creating the string, return */ + goto asprintf_failure; + } + } else { + /* Capacity related information isn't available */ + poolInfoTexts[i].capacity = vshStrdup(ctl, _("-")); + poolInfoTexts[i].allocation = vshStrdup(ctl, _("-")); + poolInfoTexts[i].available = vshStrdup(ctl, _("-")); + } + + /* Keep the length of capacity string if longest so far */ + stringLength = strlen(poolInfoTexts[i].capacity); + if (stringLength > capStrLength) + capStrLength = stringLength; + + /* Keep the length of allocation string if longest so far */ + stringLength = strlen(poolInfoTexts[i].allocation); + if (stringLength > allocStrLength) + allocStrLength = stringLength; + + /* Keep the length of available string if longest so far */ + stringLength = strlen(poolInfoTexts[i].available); + if (stringLength > availStrLength) + availStrLength = stringLength; + } else { + /* --details option was not specified, only active/inactive + * state strings are used */ + if (info.state == VIR_STORAGE_POOL_INACTIVE) + poolInfoTexts[i].state = vshStrdup(ctl, _("inactive")); + else + poolInfoTexts[i].state = vshStrdup(ctl, _("active")); + } + } + + /* Keep the length of name string if longest so far */ + stringLength = strlen(poolNames[i]); + if (stringLength > nameStrLength) + nameStrLength = stringLength; + + /* Keep the length of state string if longest so far */ + stringLength = strlen(poolInfoTexts[i].state); + if (stringLength > stateStrLength) + stateStrLength = stringLength; + + /* Keep the length of autostart string if longest so far */ + stringLength = strlen(poolInfoTexts[i].autostart); + if (stringLength > autostartStrLength) + autostartStrLength = stringLength; + + /* Free the pool object */ + virStoragePoolFree(pool); + } + + /* If the --details option wasn't selected, we output the pool + * info using the fixed string format from previous versions to + * maintain backward compatibility. + */ + + /* Output basic info then return if --details option not selected */ + if (!details) { + /* Output old style header */ + vshPrintExtra(ctl, "%-20s %-10s %-10s\n", _("Name"), _("State"), + _("Autostart")); + vshPrintExtra(ctl, "-----------------------------------------\n"); + + /* Output old style pool info */ + for (i = 0; i < numAllPools; i++) { + vshPrint(ctl, "%-20s %-10s %-10s\n", + poolNames[i], + poolInfoTexts[i].state, + poolInfoTexts[i].autostart); + } + + /* Cleanup and return */ + functionReturn = true; + goto cleanup; + } + + /* We only get here if the --details option was selected. */ + + /* Use the length of name header string if it's longest */ + stringLength = strlen(_("Name")); + if (stringLength > nameStrLength) + nameStrLength = stringLength; + + /* Use the length of state header string if it's longest */ + stringLength = strlen(_("State")); + if (stringLength > stateStrLength) + stateStrLength = stringLength; + + /* Use the length of autostart header string if it's longest */ + stringLength = strlen(_("Autostart")); + if (stringLength > autostartStrLength) + autostartStrLength = stringLength; + + /* Use the length of persistent header string if it's longest */ + stringLength = strlen(_("Persistent")); + if (stringLength > persistStrLength) + persistStrLength = stringLength; + + /* Use the length of capacity header string if it's longest */ + stringLength = strlen(_("Capacity")); + if (stringLength > capStrLength) + capStrLength = stringLength; + + /* Use the length of allocation header string if it's longest */ + stringLength = strlen(_("Allocation")); + if (stringLength > allocStrLength) + allocStrLength = stringLength; + + /* Use the length of available header string if it's longest */ + stringLength = strlen(_("Available")); + if (stringLength > availStrLength) + availStrLength = stringLength; + + /* Display the string lengths for debugging. */ + vshDebug(ctl, VSH_ERR_DEBUG, "Longest name string = %lu chars\n", + (unsigned long) nameStrLength); + vshDebug(ctl, VSH_ERR_DEBUG, "Longest state string = %lu chars\n", + (unsigned long) stateStrLength); + vshDebug(ctl, VSH_ERR_DEBUG, "Longest autostart string = %lu chars\n", + (unsigned long) autostartStrLength); + vshDebug(ctl, VSH_ERR_DEBUG, "Longest persistent string = %lu chars\n", + (unsigned long) persistStrLength); + vshDebug(ctl, VSH_ERR_DEBUG, "Longest capacity string = %lu chars\n", + (unsigned long) capStrLength); + vshDebug(ctl, VSH_ERR_DEBUG, "Longest allocation string = %lu chars\n", + (unsigned long) allocStrLength); + vshDebug(ctl, VSH_ERR_DEBUG, "Longest available string = %lu chars\n", + (unsigned long) availStrLength); + + /* Create the output template. Each column is sized according to + * the longest string. + */ + char *outputStr; + ret = virAsprintf(&outputStr, + "%%-%lus %%-%lus %%-%lus %%-%lus %%%lus %%%lus %%%lus\n", + (unsigned long) nameStrLength, + (unsigned long) stateStrLength, + (unsigned long) autostartStrLength, + (unsigned long) persistStrLength, + (unsigned long) capStrLength, + (unsigned long) allocStrLength, + (unsigned long) availStrLength); + if (ret < 0) { + /* An error occurred creating the string, return */ + goto asprintf_failure; + } + + /* Display the header */ + vshPrint(ctl, outputStr, _("Name"), _("State"), _("Autostart"), + _("Persistent"), _("Capacity"), _("Allocation"), _("Available")); + for (i = nameStrLength + stateStrLength + autostartStrLength + + persistStrLength + capStrLength + + allocStrLength + availStrLength + + 12; i > 0; i--) + vshPrintExtra(ctl, "-"); + vshPrintExtra(ctl, "\n"); + + /* Display the pool info rows */ + for (i = 0; i < numAllPools; i++) { + vshPrint(ctl, outputStr, + poolNames[i], + poolInfoTexts[i].state, + poolInfoTexts[i].autostart, + poolInfoTexts[i].persistent, + poolInfoTexts[i].capacity, + poolInfoTexts[i].allocation, + poolInfoTexts[i].available); + } + + /* Cleanup and return */ + functionReturn = true; + goto cleanup; + +asprintf_failure: + + /* Display an appropriate error message then cleanup and return */ + switch (errno) { + case ENOMEM: + /* Couldn't allocate memory */ + vshError(ctl, "%s", _("Out of memory")); + break; + default: + /* Some other error */ + vshError(ctl, _("virAsprintf failed (errno %d)"), errno); + } + functionReturn = false; + +cleanup: + + /* Safely free the memory allocated in this function */ + for (i = 0; i < numAllPools; i++) { + /* Cleanup the memory for one pool info structure */ + VIR_FREE(poolInfoTexts[i].state); + VIR_FREE(poolInfoTexts[i].autostart); + VIR_FREE(poolInfoTexts[i].persistent); + VIR_FREE(poolInfoTexts[i].capacity); + VIR_FREE(poolInfoTexts[i].allocation); + VIR_FREE(poolInfoTexts[i].available); + VIR_FREE(poolNames[i]); + } + + /* Cleanup the memory for the initial arrays*/ + VIR_FREE(poolInfoTexts); + VIR_FREE(poolNames); + + /* Return the desired value */ + return functionReturn; +} + +/* + * "find-storage-pool-sources-as" command + */ +static const vshCmdInfo info_find_storage_pool_sources_as[] = { + {"help", N_("find potential storage pool sources")}, + {"desc", N_("Returns XML <sources> document.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_find_storage_pool_sources_as[] = { + {"type", VSH_OT_DATA, VSH_OFLAG_REQ, + N_("type of storage pool sources to find")}, + {"host", VSH_OT_DATA, VSH_OFLAG_NONE, N_("optional host to query")}, + {"port", VSH_OT_DATA, VSH_OFLAG_NONE, N_("optional port to query")}, + {"initiator", VSH_OT_DATA, VSH_OFLAG_NONE, N_("optional initiator IQN to use for query")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdPoolDiscoverSourcesAs(vshControl * ctl, const vshCmd * cmd ATTRIBUTE_UNUSED) +{ + const char *type = NULL, *host = NULL; + char *srcSpec = NULL; + char *srcList; + const char *initiator = NULL; + + if (vshCommandOptString(cmd, "type", &type) <= 0 || + vshCommandOptString(cmd, "host", &host) < 0 || + vshCommandOptString(cmd, "initiator", &initiator) < 0) { + vshError(ctl,"%s", _("missing argument")); + return false; + } + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (host) { + const char *port = NULL; + virBuffer buf = VIR_BUFFER_INITIALIZER; + + if (vshCommandOptString(cmd, "port", &port) < 0) { + vshError(ctl, "%s", _("missing argument")); + virBufferFreeAndReset(&buf); + return false; + } + virBufferAddLit(&buf, "<source>\n"); + virBufferAsprintf(&buf, " <host name='%s'", host); + if (port) + virBufferAsprintf(&buf, " port='%s'", port); + virBufferAddLit(&buf, "/>\n"); + if (initiator) { + virBufferAddLit(&buf, " <initiator>\n"); + virBufferAsprintf(&buf, " <iqn name='%s'/>\n", initiator); + virBufferAddLit(&buf, " </initiator>\n"); + } + virBufferAddLit(&buf, "</source>\n"); + if (virBufferError(&buf)) { + vshError(ctl, "%s", _("Out of memory")); + return false; + } + srcSpec = virBufferContentAndReset(&buf); + } + + srcList = virConnectFindStoragePoolSources(ctl->conn, type, srcSpec, 0); + VIR_FREE(srcSpec); + if (srcList == NULL) { + vshError(ctl, _("Failed to find any %s pool sources"), type); + return false; + } + vshPrint(ctl, "%s", srcList); + VIR_FREE(srcList); + + return true; +} + +/* + * "find-storage-pool-sources" command + */ +static const vshCmdInfo info_find_storage_pool_sources[] = { + {"help", N_("discover potential storage pool sources")}, + {"desc", N_("Returns XML <sources> document.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_find_storage_pool_sources[] = { + {"type", VSH_OT_DATA, VSH_OFLAG_REQ, + N_("type of storage pool sources to discover")}, + {"srcSpec", VSH_OT_DATA, VSH_OFLAG_NONE, + N_("optional file of source xml to query for pools")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdPoolDiscoverSources(vshControl * ctl, const vshCmd * cmd ATTRIBUTE_UNUSED) +{ + const char *type = NULL, *srcSpecFile = NULL; + char *srcSpec = NULL, *srcList; + + if (vshCommandOptString(cmd, "type", &type) <= 0) + return false; + + if (vshCommandOptString(cmd, "srcSpec", &srcSpecFile) < 0) { + vshError(ctl, "%s", _("missing option")); + return false; + } + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (srcSpecFile && virFileReadAll(srcSpecFile, VIRSH_MAX_XML_FILE, &srcSpec) < 0) + return false; + + srcList = virConnectFindStoragePoolSources(ctl->conn, type, srcSpec, 0); + VIR_FREE(srcSpec); + if (srcList == NULL) { + vshError(ctl, _("Failed to find any %s pool sources"), type); + return false; + } + vshPrint(ctl, "%s", srcList); + VIR_FREE(srcList); + + return true; +} + +/* + * "pool-info" command + */ +static const vshCmdInfo info_pool_info[] = { + {"help", N_("storage pool information")}, + {"desc", N_("Returns basic information about the storage pool.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_pool_info[] = { + {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdPoolInfo(vshControl *ctl, const vshCmd *cmd) +{ + virStoragePoolInfo info; + virStoragePoolPtr pool; + int autostart = 0; + int persistent = 0; + bool ret = true; + char uuid[VIR_UUID_STRING_BUFLEN]; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(pool = vshCommandOptPool(ctl, cmd, "pool", NULL))) + return false; + + vshPrint(ctl, "%-15s %s\n", _("Name:"), virStoragePoolGetName(pool)); + + if (virStoragePoolGetUUIDString(pool, &uuid[0])==0) + vshPrint(ctl, "%-15s %s\n", _("UUID:"), uuid); + + if (virStoragePoolGetInfo(pool, &info) == 0) { + double val; + const char *unit; + switch (info.state) { + case VIR_STORAGE_POOL_INACTIVE: + vshPrint(ctl, "%-15s %s\n", _("State:"), + _("inactive")); + break; + case VIR_STORAGE_POOL_BUILDING: + vshPrint(ctl, "%-15s %s\n", _("State:"), + _("building")); + break; + case VIR_STORAGE_POOL_RUNNING: + vshPrint(ctl, "%-15s %s\n", _("State:"), + _("running")); + break; + case VIR_STORAGE_POOL_DEGRADED: + vshPrint(ctl, "%-15s %s\n", _("State:"), + _("degraded")); + break; + case VIR_STORAGE_POOL_INACCESSIBLE: + vshPrint(ctl, "%-15s %s\n", _("State:"), + _("inaccessible")); + break; + } + + /* Check and display whether the pool is persistent or not */ + persistent = virStoragePoolIsPersistent(pool); + vshDebug(ctl, VSH_ERR_DEBUG, "Pool persistent flag value: %d\n", + persistent); + if (persistent < 0) + vshPrint(ctl, "%-15s %s\n", _("Persistent:"), _("unknown")); + else + vshPrint(ctl, "%-15s %s\n", _("Persistent:"), persistent ? _("yes") : _("no")); + + /* Check and display whether the pool is autostarted or not */ + virStoragePoolGetAutostart(pool, &autostart); + vshDebug(ctl, VSH_ERR_DEBUG, "Pool autostart flag value: %d\n", + autostart); + if (autostart < 0) + vshPrint(ctl, "%-15s %s\n", _("Autostart:"), _("no autostart")); + else + vshPrint(ctl, "%-15s %s\n", _("Autostart:"), autostart ? _("yes") : _("no")); + + if (info.state == VIR_STORAGE_POOL_RUNNING || + info.state == VIR_STORAGE_POOL_DEGRADED) { + val = prettyCapacity(info.capacity, &unit); + vshPrint(ctl, "%-15s %2.2lf %s\n", _("Capacity:"), val, unit); + + val = prettyCapacity(info.allocation, &unit); + vshPrint(ctl, "%-15s %2.2lf %s\n", _("Allocation:"), val, unit); + + val = prettyCapacity(info.available, &unit); + vshPrint(ctl, "%-15s %2.2lf %s\n", _("Available:"), val, unit); + } + } else { + ret = false; + } + + virStoragePoolFree(pool); + return ret; +} + +/* + * "pool-name" command + */ +static const vshCmdInfo info_pool_name[] = { + {"help", N_("convert a pool UUID to pool name")}, + {"desc", ""}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_pool_name[] = { + {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool uuid")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdPoolName(vshControl *ctl, const vshCmd *cmd) +{ + virStoragePoolPtr pool; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + if (!(pool = vshCommandOptPoolBy(ctl, cmd, "pool", NULL, + VSH_BYUUID))) + return false; + + vshPrint(ctl, "%s\n", virStoragePoolGetName(pool)); + virStoragePoolFree(pool); + return true; +} + +/* + * "pool-start" command + */ +static const vshCmdInfo info_pool_start[] = { + {"help", N_("start a (previously defined) inactive pool")}, + {"desc", N_("Start a pool.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_pool_start[] = { + {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("name or uuid of the inactive pool")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdPoolStart(vshControl *ctl, const vshCmd *cmd) +{ + virStoragePoolPtr pool; + bool ret = true; + const char *name = NULL; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(pool = vshCommandOptPool(ctl, cmd, "pool", &name))) + return false; + + if (virStoragePoolCreate(pool, 0) == 0) { + vshPrint(ctl, _("Pool %s started\n"), name); + } else { + vshError(ctl, _("Failed to start pool %s"), name); + ret = false; + } + + virStoragePoolFree(pool); + return ret; +} + +/* + * "pool-undefine" command + */ +static const vshCmdInfo info_pool_undefine[] = { + {"help", N_("undefine an inactive pool")}, + {"desc", N_("Undefine the configuration for an inactive pool.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_pool_undefine[] = { + {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdPoolUndefine(vshControl *ctl, const vshCmd *cmd) +{ + virStoragePoolPtr pool; + bool ret = true; + const char *name; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(pool = vshCommandOptPool(ctl, cmd, "pool", &name))) + return false; + + if (virStoragePoolUndefine(pool) == 0) { + vshPrint(ctl, _("Pool %s has been undefined\n"), name); + } else { + vshError(ctl, _("Failed to undefine pool %s"), name); + ret = false; + } + + virStoragePoolFree(pool); + return ret; +} + +/* + * "pool-uuid" command + */ +static const vshCmdInfo info_pool_uuid[] = { + {"help", N_("convert a pool name to pool UUID")}, + {"desc", ""}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_pool_uuid[] = { + {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdPoolUuid(vshControl *ctl, const vshCmd *cmd) +{ + virStoragePoolPtr pool; + char uuid[VIR_UUID_STRING_BUFLEN]; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(pool = vshCommandOptPoolBy(ctl, cmd, "pool", NULL, + VSH_BYNAME))) + return false; + + if (virStoragePoolGetUUIDString(pool, uuid) != -1) + vshPrint(ctl, "%s\n", uuid); + else + vshError(ctl, "%s", _("failed to get pool UUID")); + + virStoragePoolFree(pool); + return true; +} + +/* + * "pool-edit" command + */ +static const vshCmdInfo info_pool_edit[] = { + {"help", N_("edit XML configuration for a storage pool")}, + {"desc", N_("Edit the XML configuration for a storage pool.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_pool_edit[] = { + {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdPoolEdit(vshControl *ctl, const vshCmd *cmd) +{ + bool ret = false; + virStoragePoolPtr pool = NULL; + virStoragePoolPtr pool_edited = NULL; + unsigned int flags = VIR_STORAGE_XML_INACTIVE; + char *tmp_desc = NULL; + + if (!vshConnectionUsability(ctl, ctl->conn)) + goto cleanup; + + pool = vshCommandOptPool(ctl, cmd, "pool", NULL); + if (pool == NULL) + goto cleanup; + + /* Some old daemons don't support _INACTIVE flag */ + if (!(tmp_desc = virStoragePoolGetXMLDesc(pool, flags))) { + if (last_error->code == VIR_ERR_INVALID_ARG) { + flags &= ~VIR_STORAGE_XML_INACTIVE; + virFreeError(last_error); + last_error = NULL; + } else { + goto cleanup; + } + } else { + VIR_FREE(tmp_desc); + } + +#define EDIT_GET_XML virStoragePoolGetXMLDesc(pool, flags) +#define EDIT_NOT_CHANGED \ + vshPrint(ctl, _("Pool %s XML configuration not changed.\n"), \ + virStoragePoolGetName(pool)); \ + ret = true; goto edit_cleanup; +#define EDIT_DEFINE \ + (pool_edited = virStoragePoolDefineXML(ctl->conn, doc_edited, 0)) +#define EDIT_FREE \ + if (pool_edited) \ + virStoragePoolFree(pool_edited); +#include "virsh-edit.c" + + vshPrint(ctl, _("Pool %s XML configuration edited.\n"), + virStoragePoolGetName(pool_edited)); + + ret = true; + + cleanup: + if (pool) + virStoragePoolFree(pool); + if (pool_edited) + virStoragePoolFree(pool_edited); + + return ret; +} diff --git a/tools/virsh.c b/tools/virsh.c index ac8ad09..7a30871 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -364,14 +364,6 @@ static virInterfacePtr vshCommandOptInterfaceBy(vshControl *ctl, const vshCmd *c vshCommandOptInterfaceBy(_ctl, _cmd, NULL, _name, \ VSH_BYMAC|VSH_BYNAME) -static virStoragePoolPtr vshCommandOptPoolBy(vshControl *ctl, const vshCmd *cmd, - const char *optname, const char **name, int flag); - -/* default is lookup by Name and UUID */ -#define vshCommandOptPool(_ctl, _cmd, _optname, _name) \ - vshCommandOptPoolBy(_ctl, _cmd, _optname, _name, \ - VSH_BYUUID|VSH_BYNAME) - static virSecretPtr vshCommandOptSecret(vshControl *ctl, const vshCmd *cmd, const char **name); @@ -2863,1548 +2855,250 @@ static const vshCmdInfo info_nwfilter_dumpxml[] = { {NULL, NULL} }; -static const vshCmdOptDef opts_nwfilter_dumpxml[] = { - {"nwfilter", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network filter name or uuid")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdNWFilterDumpXML(vshControl *ctl, const vshCmd *cmd) -{ - virNWFilterPtr nwfilter; - bool ret = true; - char *dump; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (!(nwfilter = vshCommandOptNWFilter(ctl, cmd, NULL))) - return false; - - dump = virNWFilterGetXMLDesc(nwfilter, 0); - if (dump != NULL) { - vshPrint(ctl, "%s", dump); - VIR_FREE(dump); - } else { - ret = false; - } - - virNWFilterFree(nwfilter); - return ret; -} - -/* - * "nwfilter-list" command - */ -static const vshCmdInfo info_nwfilter_list[] = { - {"help", N_("list network filters")}, - {"desc", N_("Returns list of network filters.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_nwfilter_list[] = { - {NULL, 0, 0, NULL} -}; - -static bool -cmdNWFilterList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) -{ - int numfilters, i; - char **names; - char uuid[VIR_UUID_STRING_BUFLEN]; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - numfilters = virConnectNumOfNWFilters(ctl->conn); - if (numfilters < 0) { - vshError(ctl, "%s", _("Failed to list network filters")); - return false; - } - - names = vshMalloc(ctl, sizeof(char *) * numfilters); - - if ((numfilters = virConnectListNWFilters(ctl->conn, names, - numfilters)) < 0) { - vshError(ctl, "%s", _("Failed to list network filters")); - VIR_FREE(names); - return false; - } - - qsort(&names[0], numfilters, sizeof(char *), vshNameSorter); - - vshPrintExtra(ctl, "%-36s %-20s \n", _("UUID"), _("Name")); - vshPrintExtra(ctl, - "----------------------------------------------------------------\n"); - - for (i = 0; i < numfilters; i++) { - virNWFilterPtr nwfilter = - virNWFilterLookupByName(ctl->conn, names[i]); - - /* this kind of work with networks is not atomic operation */ - if (!nwfilter) { - VIR_FREE(names[i]); - continue; - } - - virNWFilterGetUUIDString(nwfilter, uuid); - vshPrint(ctl, "%-36s %-20s\n", - uuid, - virNWFilterGetName(nwfilter)); - virNWFilterFree(nwfilter); - VIR_FREE(names[i]); - } - - VIR_FREE(names); - return true; -} - - -/* - * "nwfilter-edit" command - */ -static const vshCmdInfo info_nwfilter_edit[] = { - {"help", N_("edit XML configuration for a network filter")}, - {"desc", N_("Edit the XML configuration for a network filter.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_nwfilter_edit[] = { - {"nwfilter", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network filter name or uuid")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdNWFilterEdit(vshControl *ctl, const vshCmd *cmd) -{ - bool ret = false; - virNWFilterPtr nwfilter = NULL; - virNWFilterPtr nwfilter_edited = NULL; - - if (!vshConnectionUsability(ctl, ctl->conn)) - goto cleanup; - - nwfilter = vshCommandOptNWFilter(ctl, cmd, NULL); - if (nwfilter == NULL) - goto cleanup; - -#define EDIT_GET_XML virNWFilterGetXMLDesc(nwfilter, 0) -#define EDIT_NOT_CHANGED \ - vshPrint(ctl, _("Network filter %s XML " \ - "configuration not changed.\n"), \ - virNWFilterGetName(nwfilter)); \ - ret = true; goto edit_cleanup; -#define EDIT_DEFINE \ - (nwfilter_edited = virNWFilterDefineXML(ctl->conn, doc_edited)) -#define EDIT_FREE \ - if (nwfilter_edited) \ - virNWFilterFree(nwfilter); -#include "virsh-edit.c" - - vshPrint(ctl, _("Network filter %s XML configuration edited.\n"), - virNWFilterGetName(nwfilter_edited)); - - ret = true; - -cleanup: - if (nwfilter) - virNWFilterFree(nwfilter); - if (nwfilter_edited) - virNWFilterFree(nwfilter_edited); - - return ret; -} - - -/**************************************************************************/ -/* - * "pool-autostart" command - */ -static const vshCmdInfo info_pool_autostart[] = { - {"help", N_("autostart a pool")}, - {"desc", - N_("Configure a pool to be automatically started at boot.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_pool_autostart[] = { - {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")}, - {"disable", VSH_OT_BOOL, 0, N_("disable autostarting")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdPoolAutostart(vshControl *ctl, const vshCmd *cmd) -{ - virStoragePoolPtr pool; - const char *name; - int autostart; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (!(pool = vshCommandOptPool(ctl, cmd, "pool", &name))) - return false; - - autostart = !vshCommandOptBool(cmd, "disable"); - - if (virStoragePoolSetAutostart(pool, autostart) < 0) { - if (autostart) - vshError(ctl, _("failed to mark pool %s as autostarted"), name); - else - vshError(ctl, _("failed to unmark pool %s as autostarted"), name); - virStoragePoolFree(pool); - return false; - } - - if (autostart) - vshPrint(ctl, _("Pool %s marked as autostarted\n"), name); - else - vshPrint(ctl, _("Pool %s unmarked as autostarted\n"), name); - - virStoragePoolFree(pool); - return true; -} - -/* - * "pool-create" command - */ -static const vshCmdInfo info_pool_create[] = { - {"help", N_("create a pool from an XML file")}, - {"desc", N_("Create a pool.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_pool_create[] = { - {"file", VSH_OT_DATA, VSH_OFLAG_REQ, - N_("file containing an XML pool description")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdPoolCreate(vshControl *ctl, const vshCmd *cmd) -{ - virStoragePoolPtr pool; - const char *from = NULL; - bool ret = true; - char *buffer; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (vshCommandOptString(cmd, "file", &from) <= 0) - return false; - - if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0) - return false; - - pool = virStoragePoolCreateXML(ctl->conn, buffer, 0); - VIR_FREE(buffer); - - if (pool != NULL) { - vshPrint(ctl, _("Pool %s created from %s\n"), - virStoragePoolGetName(pool), from); - virStoragePoolFree(pool); - } else { - vshError(ctl, _("Failed to create pool from %s"), from); - ret = false; - } - return ret; -} - - -/* - * "nodedev-create" command - */ -static const vshCmdInfo info_node_device_create[] = { - {"help", N_("create a device defined " - "by an XML file on the node")}, - {"desc", N_("Create a device on the node. Note that this " - "command creates devices on the physical host " - "that can then be assigned to a virtual machine.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_node_device_create[] = { - {"file", VSH_OT_DATA, VSH_OFLAG_REQ, - N_("file containing an XML description of the device")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdNodeDeviceCreate(vshControl *ctl, const vshCmd *cmd) -{ - virNodeDevicePtr dev = NULL; - const char *from = NULL; - bool ret = true; - char *buffer; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (vshCommandOptString(cmd, "file", &from) <= 0) - return false; - - if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0) - return false; - - dev = virNodeDeviceCreateXML(ctl->conn, buffer, 0); - VIR_FREE(buffer); - - if (dev != NULL) { - vshPrint(ctl, _("Node device %s created from %s\n"), - virNodeDeviceGetName(dev), from); - virNodeDeviceFree(dev); - } else { - vshError(ctl, _("Failed to create node device from %s"), from); - ret = false; - } - - return ret; -} - - -/* - * "nodedev-destroy" command - */ -static const vshCmdInfo info_node_device_destroy[] = { - {"help", N_("destroy (stop) a device on the node")}, - {"desc", N_("Destroy a device on the node. Note that this " - "command destroys devices on the physical host")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_node_device_destroy[] = { - {"name", VSH_OT_DATA, VSH_OFLAG_REQ, - N_("name of the device to be destroyed")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdNodeDeviceDestroy(vshControl *ctl, const vshCmd *cmd) -{ - virNodeDevicePtr dev = NULL; - bool ret = true; - const char *name = NULL; - - if (!vshConnectionUsability(ctl, ctl->conn)) { - return false; - } - - if (vshCommandOptString(cmd, "name", &name) <= 0) - return false; - - dev = virNodeDeviceLookupByName(ctl->conn, name); - - if (virNodeDeviceDestroy(dev) == 0) { - vshPrint(ctl, _("Destroyed node device '%s'\n"), name); - } else { - vshError(ctl, _("Failed to destroy node device '%s'"), name); - ret = false; - } - - virNodeDeviceFree(dev); - return ret; -} - - -/* - * XML Building helper for pool-define-as and pool-create-as - */ -static const vshCmdOptDef opts_pool_X_as[] = { - {"name", VSH_OT_DATA, VSH_OFLAG_REQ, N_("name of the pool")}, - {"print-xml", VSH_OT_BOOL, 0, N_("print XML document, but don't define/create")}, - {"type", VSH_OT_DATA, VSH_OFLAG_REQ, N_("type of the pool")}, - {"source-host", VSH_OT_DATA, 0, N_("source-host for underlying storage")}, - {"source-path", VSH_OT_DATA, 0, N_("source path for underlying storage")}, - {"source-dev", VSH_OT_DATA, 0, N_("source device for underlying storage")}, - {"source-name", VSH_OT_DATA, 0, N_("source name for underlying storage")}, - {"target", VSH_OT_DATA, 0, N_("target for underlying storage")}, - {"source-format", VSH_OT_STRING, 0, N_("format for underlying storage")}, - {NULL, 0, 0, NULL} -}; - -static int buildPoolXML(const vshCmd *cmd, const char **retname, char **xml) { - - const char *name = NULL, *type = NULL, *srcHost = NULL, *srcPath = NULL, - *srcDev = NULL, *srcName = NULL, *srcFormat = NULL, *target = NULL; - virBuffer buf = VIR_BUFFER_INITIALIZER; - - if (vshCommandOptString(cmd, "name", &name) <= 0) - goto cleanup; - if (vshCommandOptString(cmd, "type", &type) <= 0) - goto cleanup; - - if (vshCommandOptString(cmd, "source-host", &srcHost) < 0 || - vshCommandOptString(cmd, "source-path", &srcPath) < 0 || - vshCommandOptString(cmd, "source-dev", &srcDev) < 0 || - vshCommandOptString(cmd, "source-name", &srcName) < 0 || - vshCommandOptString(cmd, "source-format", &srcFormat) < 0 || - vshCommandOptString(cmd, "target", &target) < 0) { - vshError(NULL, "%s", _("missing argument")); - goto cleanup; - } - - virBufferAsprintf(&buf, "<pool type='%s'>\n", type); - virBufferAsprintf(&buf, " <name>%s</name>\n", name); - if (srcHost || srcPath || srcDev || srcFormat || srcName) { - virBufferAddLit(&buf, " <source>\n"); - - if (srcHost) - virBufferAsprintf(&buf, " <host name='%s'/>\n", srcHost); - if (srcPath) - virBufferAsprintf(&buf, " <dir path='%s'/>\n", srcPath); - if (srcDev) - virBufferAsprintf(&buf, " <device path='%s'/>\n", srcDev); - if (srcFormat) - virBufferAsprintf(&buf, " <format type='%s'/>\n", srcFormat); - if (srcName) - virBufferAsprintf(&buf, " <name>%s</name>\n", srcName); - - virBufferAddLit(&buf, " </source>\n"); - } - if (target) { - virBufferAddLit(&buf, " <target>\n"); - virBufferAsprintf(&buf, " <path>%s</path>\n", target); - virBufferAddLit(&buf, " </target>\n"); - } - virBufferAddLit(&buf, "</pool>\n"); - - if (virBufferError(&buf)) { - vshPrint(ctl, "%s", _("Failed to allocate XML buffer")); - return false; - } - - *xml = virBufferContentAndReset(&buf); - *retname = name; - return true; - -cleanup: - virBufferFreeAndReset(&buf); - return false; -} - -/* - * "pool-create-as" command - */ -static const vshCmdInfo info_pool_create_as[] = { - {"help", N_("create a pool from a set of args")}, - {"desc", N_("Create a pool.")}, - {NULL, NULL} -}; - -static bool -cmdPoolCreateAs(vshControl *ctl, const vshCmd *cmd) -{ - virStoragePoolPtr pool; - const char *name; - char *xml; - bool printXML = vshCommandOptBool(cmd, "print-xml"); - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (!buildPoolXML(cmd, &name, &xml)) - return false; - - if (printXML) { - vshPrint(ctl, "%s", xml); - VIR_FREE(xml); - } else { - pool = virStoragePoolCreateXML(ctl->conn, xml, 0); - VIR_FREE(xml); - - if (pool != NULL) { - vshPrint(ctl, _("Pool %s created\n"), name); - virStoragePoolFree(pool); - } else { - vshError(ctl, _("Failed to create pool %s"), name); - return false; - } - } - return true; -} - - -/* - * "pool-define" command - */ -static const vshCmdInfo info_pool_define[] = { - {"help", N_("define (but don't start) a pool from an XML file")}, - {"desc", N_("Define a pool.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_pool_define[] = { - {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containing an XML pool description")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdPoolDefine(vshControl *ctl, const vshCmd *cmd) -{ - virStoragePoolPtr pool; - const char *from = NULL; - bool ret = true; - char *buffer; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (vshCommandOptString(cmd, "file", &from) <= 0) - return false; - - if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0) - return false; - - pool = virStoragePoolDefineXML(ctl->conn, buffer, 0); - VIR_FREE(buffer); - - if (pool != NULL) { - vshPrint(ctl, _("Pool %s defined from %s\n"), - virStoragePoolGetName(pool), from); - virStoragePoolFree(pool); - } else { - vshError(ctl, _("Failed to define pool from %s"), from); - ret = false; - } - return ret; -} - - -/* - * "pool-define-as" command - */ -static const vshCmdInfo info_pool_define_as[] = { - {"help", N_("define a pool from a set of args")}, - {"desc", N_("Define a pool.")}, - {NULL, NULL} -}; - -static bool -cmdPoolDefineAs(vshControl *ctl, const vshCmd *cmd) -{ - virStoragePoolPtr pool; - const char *name; - char *xml; - bool printXML = vshCommandOptBool(cmd, "print-xml"); - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (!buildPoolXML(cmd, &name, &xml)) - return false; - - if (printXML) { - vshPrint(ctl, "%s", xml); - VIR_FREE(xml); - } else { - pool = virStoragePoolDefineXML(ctl->conn, xml, 0); - VIR_FREE(xml); - - if (pool != NULL) { - vshPrint(ctl, _("Pool %s defined\n"), name); - virStoragePoolFree(pool); - } else { - vshError(ctl, _("Failed to define pool %s"), name); - return false; - } - } - return true; -} - - -/* - * "pool-build" command - */ -static const vshCmdInfo info_pool_build[] = { - {"help", N_("build a pool")}, - {"desc", N_("Build a given pool.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_pool_build[] = { - {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")}, - {"no-overwrite", VSH_OT_BOOL, 0, N_("do not overwrite an existing pool of this type")}, - {"overwrite", VSH_OT_BOOL, 0, N_("overwrite any existing data")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdPoolBuild(vshControl *ctl, const vshCmd *cmd) -{ - virStoragePoolPtr pool; - bool ret = true; - const char *name; - unsigned int flags = 0; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (!(pool = vshCommandOptPool(ctl, cmd, "pool", &name))) - return false; - - if (vshCommandOptBool(cmd, "no-overwrite")) { - flags |= VIR_STORAGE_POOL_BUILD_NO_OVERWRITE; - } - - if (vshCommandOptBool(cmd, "overwrite")) { - flags |= VIR_STORAGE_POOL_BUILD_OVERWRITE; - } - - if (virStoragePoolBuild(pool, flags) == 0) { - vshPrint(ctl, _("Pool %s built\n"), name); - } else { - vshError(ctl, _("Failed to build pool %s"), name); - ret = false; - } - - virStoragePoolFree(pool); - - return ret; -} - -/* - * "pool-destroy" command - */ -static const vshCmdInfo info_pool_destroy[] = { - {"help", N_("destroy (stop) a pool")}, - {"desc", - N_("Forcefully stop a given pool. Raw data in the pool is untouched")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_pool_destroy[] = { - {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdPoolDestroy(vshControl *ctl, const vshCmd *cmd) -{ - virStoragePoolPtr pool; - bool ret = true; - const char *name; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (!(pool = vshCommandOptPool(ctl, cmd, "pool", &name))) - return false; - - if (virStoragePoolDestroy(pool) == 0) { - vshPrint(ctl, _("Pool %s destroyed\n"), name); - } else { - vshError(ctl, _("Failed to destroy pool %s"), name); - ret = false; - } - - virStoragePoolFree(pool); - return ret; -} - - -/* - * "pool-delete" command - */ -static const vshCmdInfo info_pool_delete[] = { - {"help", N_("delete a pool")}, - {"desc", N_("Delete a given pool.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_pool_delete[] = { - {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdPoolDelete(vshControl *ctl, const vshCmd *cmd) -{ - virStoragePoolPtr pool; - bool ret = true; - const char *name; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (!(pool = vshCommandOptPool(ctl, cmd, "pool", &name))) - return false; - - if (virStoragePoolDelete(pool, 0) == 0) { - vshPrint(ctl, _("Pool %s deleted\n"), name); - } else { - vshError(ctl, _("Failed to delete pool %s"), name); - ret = false; - } - - virStoragePoolFree(pool); - return ret; -} - - -/* - * "pool-refresh" command - */ -static const vshCmdInfo info_pool_refresh[] = { - {"help", N_("refresh a pool")}, - {"desc", N_("Refresh a given pool.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_pool_refresh[] = { - {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdPoolRefresh(vshControl *ctl, const vshCmd *cmd) -{ - virStoragePoolPtr pool; - bool ret = true; - const char *name; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (!(pool = vshCommandOptPool(ctl, cmd, "pool", &name))) - return false; - - if (virStoragePoolRefresh(pool, 0) == 0) { - vshPrint(ctl, _("Pool %s refreshed\n"), name); - } else { - vshError(ctl, _("Failed to refresh pool %s"), name); - ret = false; - } - virStoragePoolFree(pool); - - return ret; -} - - -/* - * "pool-dumpxml" command - */ -static const vshCmdInfo info_pool_dumpxml[] = { - {"help", N_("pool information in XML")}, - {"desc", N_("Output the pool information as an XML dump to stdout.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_pool_dumpxml[] = { - {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")}, - {"inactive", VSH_OT_BOOL, 0, N_("show inactive defined XML")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdPoolDumpXML(vshControl *ctl, const vshCmd *cmd) -{ - virStoragePoolPtr pool; - bool ret = true; - bool inactive = vshCommandOptBool(cmd, "inactive"); - unsigned int flags = 0; - char *dump; - - if (inactive) - flags |= VIR_STORAGE_XML_INACTIVE; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (!(pool = vshCommandOptPool(ctl, cmd, "pool", NULL))) - return false; - - dump = virStoragePoolGetXMLDesc(pool, flags); - if (dump != NULL) { - vshPrint(ctl, "%s", dump); - VIR_FREE(dump); - } else { - ret = false; - } - - virStoragePoolFree(pool); - return ret; -} - - -/* - * "pool-list" command - */ -static const vshCmdInfo info_pool_list[] = { - {"help", N_("list pools")}, - {"desc", N_("Returns list of pools.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_pool_list[] = { - {"inactive", VSH_OT_BOOL, 0, N_("list inactive pools")}, - {"all", VSH_OT_BOOL, 0, N_("list inactive & active pools")}, - {"details", VSH_OT_BOOL, 0, N_("display extended details for pools")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdPoolList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) -{ - virStoragePoolInfo info; - char **poolNames = NULL; - int i, ret; - bool functionReturn; - int numActivePools = 0, numInactivePools = 0, numAllPools = 0; - size_t stringLength = 0, nameStrLength = 0; - size_t autostartStrLength = 0, persistStrLength = 0; - size_t stateStrLength = 0, capStrLength = 0; - size_t allocStrLength = 0, availStrLength = 0; - struct poolInfoText { - char *state; - char *autostart; - char *persistent; - char *capacity; - char *allocation; - char *available; - }; - struct poolInfoText *poolInfoTexts = NULL; - - /* Determine the options passed by the user */ - bool all = vshCommandOptBool(cmd, "all"); - bool details = vshCommandOptBool(cmd, "details"); - bool inactive = vshCommandOptBool(cmd, "inactive"); - bool active = !inactive || all; - inactive |= all; - - /* Check the connection to libvirtd daemon is still working */ - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - /* Retrieve the number of active storage pools */ - if (active) { - numActivePools = virConnectNumOfStoragePools(ctl->conn); - if (numActivePools < 0) { - vshError(ctl, "%s", _("Failed to list active pools")); - return false; - } - } - - /* Retrieve the number of inactive storage pools */ - if (inactive) { - numInactivePools = virConnectNumOfDefinedStoragePools(ctl->conn); - if (numInactivePools < 0) { - vshError(ctl, "%s", _("Failed to list inactive pools")); - return false; - } - } - - /* Determine the total number of pools to list */ - numAllPools = numActivePools + numInactivePools; - - /* Allocate memory for arrays of storage pool names and info */ - poolNames = vshCalloc(ctl, numAllPools, sizeof(*poolNames)); - poolInfoTexts = - vshCalloc(ctl, numAllPools, sizeof(*poolInfoTexts)); - - /* Retrieve a list of active storage pool names */ - if (active) { - if (virConnectListStoragePools(ctl->conn, - poolNames, numActivePools) < 0) { - vshError(ctl, "%s", _("Failed to list active pools")); - VIR_FREE(poolInfoTexts); - VIR_FREE(poolNames); - return false; - } - } - - /* Add the inactive storage pools to the end of the name list */ - if (inactive) { - if (virConnectListDefinedStoragePools(ctl->conn, - &poolNames[numActivePools], - numInactivePools) < 0) { - vshError(ctl, "%s", _("Failed to list inactive pools")); - VIR_FREE(poolInfoTexts); - VIR_FREE(poolNames); - return false; - } - } - - /* Sort the storage pool names */ - qsort(poolNames, numAllPools, sizeof(*poolNames), vshNameSorter); - - /* Collect the storage pool information for display */ - for (i = 0; i < numAllPools; i++) { - int autostart = 0, persistent = 0; - - /* Retrieve a pool object, looking it up by name */ - virStoragePoolPtr pool = virStoragePoolLookupByName(ctl->conn, - poolNames[i]); - if (!pool) { - VIR_FREE(poolNames[i]); - continue; - } - - /* Retrieve the autostart status of the pool */ - if (virStoragePoolGetAutostart(pool, &autostart) < 0) - poolInfoTexts[i].autostart = vshStrdup(ctl, _("no autostart")); - else - poolInfoTexts[i].autostart = vshStrdup(ctl, autostart ? - _("yes") : _("no")); - - /* Retrieve the persistence status of the pool */ - if (details) { - persistent = virStoragePoolIsPersistent(pool); - vshDebug(ctl, VSH_ERR_DEBUG, "Persistent flag value: %d\n", - persistent); - if (persistent < 0) - poolInfoTexts[i].persistent = vshStrdup(ctl, _("unknown")); - else - poolInfoTexts[i].persistent = vshStrdup(ctl, persistent ? - _("yes") : _("no")); - - /* Keep the length of persistent string if longest so far */ - stringLength = strlen(poolInfoTexts[i].persistent); - if (stringLength > persistStrLength) - persistStrLength = stringLength; - } - - /* Collect further extended information about the pool */ - if (virStoragePoolGetInfo(pool, &info) != 0) { - /* Something went wrong retrieving pool info, cope with it */ - vshError(ctl, "%s", _("Could not retrieve pool information")); - poolInfoTexts[i].state = vshStrdup(ctl, _("unknown")); - if (details) { - poolInfoTexts[i].capacity = vshStrdup(ctl, _("unknown")); - poolInfoTexts[i].allocation = vshStrdup(ctl, _("unknown")); - poolInfoTexts[i].available = vshStrdup(ctl, _("unknown")); - } - } else { - /* Decide which state string to display */ - if (details) { - /* --details option was specified, we're using detailed state - * strings */ - switch (info.state) { - case VIR_STORAGE_POOL_INACTIVE: - poolInfoTexts[i].state = vshStrdup(ctl, _("inactive")); - break; - case VIR_STORAGE_POOL_BUILDING: - poolInfoTexts[i].state = vshStrdup(ctl, _("building")); - break; - case VIR_STORAGE_POOL_RUNNING: - poolInfoTexts[i].state = vshStrdup(ctl, _("running")); - break; - case VIR_STORAGE_POOL_DEGRADED: - poolInfoTexts[i].state = vshStrdup(ctl, _("degraded")); - break; - case VIR_STORAGE_POOL_INACCESSIBLE: - poolInfoTexts[i].state = vshStrdup(ctl, _("inaccessible")); - break; - } - - /* Create the pool size related strings */ - if (info.state == VIR_STORAGE_POOL_RUNNING || - info.state == VIR_STORAGE_POOL_DEGRADED) { - double val; - const char *unit; - - /* Create the capacity output string */ - val = prettyCapacity(info.capacity, &unit); - ret = virAsprintf(&poolInfoTexts[i].capacity, - "%.2lf %s", val, unit); - if (ret < 0) { - /* An error occurred creating the string, return */ - goto asprintf_failure; - } - - /* Create the allocation output string */ - val = prettyCapacity(info.allocation, &unit); - ret = virAsprintf(&poolInfoTexts[i].allocation, - "%.2lf %s", val, unit); - if (ret < 0) { - /* An error occurred creating the string, return */ - goto asprintf_failure; - } - - /* Create the available space output string */ - val = prettyCapacity(info.available, &unit); - ret = virAsprintf(&poolInfoTexts[i].available, - "%.2lf %s", val, unit); - if (ret < 0) { - /* An error occurred creating the string, return */ - goto asprintf_failure; - } - } else { - /* Capacity related information isn't available */ - poolInfoTexts[i].capacity = vshStrdup(ctl, _("-")); - poolInfoTexts[i].allocation = vshStrdup(ctl, _("-")); - poolInfoTexts[i].available = vshStrdup(ctl, _("-")); - } - - /* Keep the length of capacity string if longest so far */ - stringLength = strlen(poolInfoTexts[i].capacity); - if (stringLength > capStrLength) - capStrLength = stringLength; - - /* Keep the length of allocation string if longest so far */ - stringLength = strlen(poolInfoTexts[i].allocation); - if (stringLength > allocStrLength) - allocStrLength = stringLength; - - /* Keep the length of available string if longest so far */ - stringLength = strlen(poolInfoTexts[i].available); - if (stringLength > availStrLength) - availStrLength = stringLength; - } else { - /* --details option was not specified, only active/inactive - * state strings are used */ - if (info.state == VIR_STORAGE_POOL_INACTIVE) - poolInfoTexts[i].state = vshStrdup(ctl, _("inactive")); - else - poolInfoTexts[i].state = vshStrdup(ctl, _("active")); - } - } - - /* Keep the length of name string if longest so far */ - stringLength = strlen(poolNames[i]); - if (stringLength > nameStrLength) - nameStrLength = stringLength; - - /* Keep the length of state string if longest so far */ - stringLength = strlen(poolInfoTexts[i].state); - if (stringLength > stateStrLength) - stateStrLength = stringLength; - - /* Keep the length of autostart string if longest so far */ - stringLength = strlen(poolInfoTexts[i].autostart); - if (stringLength > autostartStrLength) - autostartStrLength = stringLength; - - /* Free the pool object */ - virStoragePoolFree(pool); - } - - /* If the --details option wasn't selected, we output the pool - * info using the fixed string format from previous versions to - * maintain backward compatibility. - */ - - /* Output basic info then return if --details option not selected */ - if (!details) { - /* Output old style header */ - vshPrintExtra(ctl, "%-20s %-10s %-10s\n", _("Name"), _("State"), - _("Autostart")); - vshPrintExtra(ctl, "-----------------------------------------\n"); - - /* Output old style pool info */ - for (i = 0; i < numAllPools; i++) { - vshPrint(ctl, "%-20s %-10s %-10s\n", - poolNames[i], - poolInfoTexts[i].state, - poolInfoTexts[i].autostart); - } - - /* Cleanup and return */ - functionReturn = true; - goto cleanup; - } - - /* We only get here if the --details option was selected. */ - - /* Use the length of name header string if it's longest */ - stringLength = strlen(_("Name")); - if (stringLength > nameStrLength) - nameStrLength = stringLength; - - /* Use the length of state header string if it's longest */ - stringLength = strlen(_("State")); - if (stringLength > stateStrLength) - stateStrLength = stringLength; - - /* Use the length of autostart header string if it's longest */ - stringLength = strlen(_("Autostart")); - if (stringLength > autostartStrLength) - autostartStrLength = stringLength; - - /* Use the length of persistent header string if it's longest */ - stringLength = strlen(_("Persistent")); - if (stringLength > persistStrLength) - persistStrLength = stringLength; - - /* Use the length of capacity header string if it's longest */ - stringLength = strlen(_("Capacity")); - if (stringLength > capStrLength) - capStrLength = stringLength; - - /* Use the length of allocation header string if it's longest */ - stringLength = strlen(_("Allocation")); - if (stringLength > allocStrLength) - allocStrLength = stringLength; - - /* Use the length of available header string if it's longest */ - stringLength = strlen(_("Available")); - if (stringLength > availStrLength) - availStrLength = stringLength; - - /* Display the string lengths for debugging. */ - vshDebug(ctl, VSH_ERR_DEBUG, "Longest name string = %lu chars\n", - (unsigned long) nameStrLength); - vshDebug(ctl, VSH_ERR_DEBUG, "Longest state string = %lu chars\n", - (unsigned long) stateStrLength); - vshDebug(ctl, VSH_ERR_DEBUG, "Longest autostart string = %lu chars\n", - (unsigned long) autostartStrLength); - vshDebug(ctl, VSH_ERR_DEBUG, "Longest persistent string = %lu chars\n", - (unsigned long) persistStrLength); - vshDebug(ctl, VSH_ERR_DEBUG, "Longest capacity string = %lu chars\n", - (unsigned long) capStrLength); - vshDebug(ctl, VSH_ERR_DEBUG, "Longest allocation string = %lu chars\n", - (unsigned long) allocStrLength); - vshDebug(ctl, VSH_ERR_DEBUG, "Longest available string = %lu chars\n", - (unsigned long) availStrLength); - - /* Create the output template. Each column is sized according to - * the longest string. - */ - char *outputStr; - ret = virAsprintf(&outputStr, - "%%-%lus %%-%lus %%-%lus %%-%lus %%%lus %%%lus %%%lus\n", - (unsigned long) nameStrLength, - (unsigned long) stateStrLength, - (unsigned long) autostartStrLength, - (unsigned long) persistStrLength, - (unsigned long) capStrLength, - (unsigned long) allocStrLength, - (unsigned long) availStrLength); - if (ret < 0) { - /* An error occurred creating the string, return */ - goto asprintf_failure; - } - - /* Display the header */ - vshPrint(ctl, outputStr, _("Name"), _("State"), _("Autostart"), - _("Persistent"), _("Capacity"), _("Allocation"), _("Available")); - for (i = nameStrLength + stateStrLength + autostartStrLength - + persistStrLength + capStrLength - + allocStrLength + availStrLength - + 12; i > 0; i--) - vshPrintExtra(ctl, "-"); - vshPrintExtra(ctl, "\n"); - - /* Display the pool info rows */ - for (i = 0; i < numAllPools; i++) { - vshPrint(ctl, outputStr, - poolNames[i], - poolInfoTexts[i].state, - poolInfoTexts[i].autostart, - poolInfoTexts[i].persistent, - poolInfoTexts[i].capacity, - poolInfoTexts[i].allocation, - poolInfoTexts[i].available); - } - - /* Cleanup and return */ - functionReturn = true; - goto cleanup; - -asprintf_failure: - - /* Display an appropriate error message then cleanup and return */ - switch (errno) { - case ENOMEM: - /* Couldn't allocate memory */ - vshError(ctl, "%s", _("Out of memory")); - break; - default: - /* Some other error */ - vshError(ctl, _("virAsprintf failed (errno %d)"), errno); - } - functionReturn = false; - -cleanup: - - /* Safely free the memory allocated in this function */ - for (i = 0; i < numAllPools; i++) { - /* Cleanup the memory for one pool info structure */ - VIR_FREE(poolInfoTexts[i].state); - VIR_FREE(poolInfoTexts[i].autostart); - VIR_FREE(poolInfoTexts[i].persistent); - VIR_FREE(poolInfoTexts[i].capacity); - VIR_FREE(poolInfoTexts[i].allocation); - VIR_FREE(poolInfoTexts[i].available); - VIR_FREE(poolNames[i]); - } - - /* Cleanup the memory for the initial arrays*/ - VIR_FREE(poolInfoTexts); - VIR_FREE(poolNames); - - /* Return the desired value */ - return functionReturn; -} - -/* - * "find-storage-pool-sources-as" command - */ -static const vshCmdInfo info_find_storage_pool_sources_as[] = { - {"help", N_("find potential storage pool sources")}, - {"desc", N_("Returns XML <sources> document.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_find_storage_pool_sources_as[] = { - {"type", VSH_OT_DATA, VSH_OFLAG_REQ, - N_("type of storage pool sources to find")}, - {"host", VSH_OT_DATA, VSH_OFLAG_NONE, N_("optional host to query")}, - {"port", VSH_OT_DATA, VSH_OFLAG_NONE, N_("optional port to query")}, - {"initiator", VSH_OT_DATA, VSH_OFLAG_NONE, N_("optional initiator IQN to use for query")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdPoolDiscoverSourcesAs(vshControl * ctl, const vshCmd * cmd ATTRIBUTE_UNUSED) -{ - const char *type = NULL, *host = NULL; - char *srcSpec = NULL; - char *srcList; - const char *initiator = NULL; - - if (vshCommandOptString(cmd, "type", &type) <= 0 || - vshCommandOptString(cmd, "host", &host) < 0 || - vshCommandOptString(cmd, "initiator", &initiator) < 0) { - vshError(ctl,"%s", _("missing argument")); - return false; - } - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (host) { - const char *port = NULL; - virBuffer buf = VIR_BUFFER_INITIALIZER; - - if (vshCommandOptString(cmd, "port", &port) < 0) { - vshError(ctl, "%s", _("missing argument")); - virBufferFreeAndReset(&buf); - return false; - } - virBufferAddLit(&buf, "<source>\n"); - virBufferAsprintf(&buf, " <host name='%s'", host); - if (port) - virBufferAsprintf(&buf, " port='%s'", port); - virBufferAddLit(&buf, "/>\n"); - if (initiator) { - virBufferAddLit(&buf, " <initiator>\n"); - virBufferAsprintf(&buf, " <iqn name='%s'/>\n", initiator); - virBufferAddLit(&buf, " </initiator>\n"); - } - virBufferAddLit(&buf, "</source>\n"); - if (virBufferError(&buf)) { - vshError(ctl, "%s", _("Out of memory")); - return false; - } - srcSpec = virBufferContentAndReset(&buf); - } - - srcList = virConnectFindStoragePoolSources(ctl->conn, type, srcSpec, 0); - VIR_FREE(srcSpec); - if (srcList == NULL) { - vshError(ctl, _("Failed to find any %s pool sources"), type); - return false; - } - vshPrint(ctl, "%s", srcList); - VIR_FREE(srcList); - - return true; -} - - -/* - * "find-storage-pool-sources" command - */ -static const vshCmdInfo info_find_storage_pool_sources[] = { - {"help", N_("discover potential storage pool sources")}, - {"desc", N_("Returns XML <sources> document.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_find_storage_pool_sources[] = { - {"type", VSH_OT_DATA, VSH_OFLAG_REQ, - N_("type of storage pool sources to discover")}, - {"srcSpec", VSH_OT_DATA, VSH_OFLAG_NONE, - N_("optional file of source xml to query for pools")}, +static const vshCmdOptDef opts_nwfilter_dumpxml[] = { + {"nwfilter", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network filter name or uuid")}, {NULL, 0, 0, NULL} }; static bool -cmdPoolDiscoverSources(vshControl * ctl, const vshCmd * cmd ATTRIBUTE_UNUSED) +cmdNWFilterDumpXML(vshControl *ctl, const vshCmd *cmd) { - const char *type = NULL, *srcSpecFile = NULL; - char *srcSpec = NULL, *srcList; - - if (vshCommandOptString(cmd, "type", &type) <= 0) - return false; - - if (vshCommandOptString(cmd, "srcSpec", &srcSpecFile) < 0) { - vshError(ctl, "%s", _("missing option")); - return false; - } + virNWFilterPtr nwfilter; + bool ret = true; + char *dump; if (!vshConnectionUsability(ctl, ctl->conn)) return false; - if (srcSpecFile && virFileReadAll(srcSpecFile, VIRSH_MAX_XML_FILE, &srcSpec) < 0) + if (!(nwfilter = vshCommandOptNWFilter(ctl, cmd, NULL))) return false; - srcList = virConnectFindStoragePoolSources(ctl->conn, type, srcSpec, 0); - VIR_FREE(srcSpec); - if (srcList == NULL) { - vshError(ctl, _("Failed to find any %s pool sources"), type); - return false; + dump = virNWFilterGetXMLDesc(nwfilter, 0); + if (dump != NULL) { + vshPrint(ctl, "%s", dump); + VIR_FREE(dump); + } else { + ret = false; } - vshPrint(ctl, "%s", srcList); - VIR_FREE(srcList); - return true; + virNWFilterFree(nwfilter); + return ret; } - /* - * "pool-info" command + * "nwfilter-list" command */ -static const vshCmdInfo info_pool_info[] = { - {"help", N_("storage pool information")}, - {"desc", N_("Returns basic information about the storage pool.")}, +static const vshCmdInfo info_nwfilter_list[] = { + {"help", N_("list network filters")}, + {"desc", N_("Returns list of network filters.")}, {NULL, NULL} }; -static const vshCmdOptDef opts_pool_info[] = { - {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")}, +static const vshCmdOptDef opts_nwfilter_list[] = { {NULL, 0, 0, NULL} }; static bool -cmdPoolInfo(vshControl *ctl, const vshCmd *cmd) +cmdNWFilterList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) { - virStoragePoolInfo info; - virStoragePoolPtr pool; - int autostart = 0; - int persistent = 0; - bool ret = true; + int numfilters, i; + char **names; char uuid[VIR_UUID_STRING_BUFLEN]; if (!vshConnectionUsability(ctl, ctl->conn)) return false; - if (!(pool = vshCommandOptPool(ctl, cmd, "pool", NULL))) + numfilters = virConnectNumOfNWFilters(ctl->conn); + if (numfilters < 0) { + vshError(ctl, "%s", _("Failed to list network filters")); return false; + } - vshPrint(ctl, "%-15s %s\n", _("Name:"), virStoragePoolGetName(pool)); - - if (virStoragePoolGetUUIDString(pool, &uuid[0])==0) - vshPrint(ctl, "%-15s %s\n", _("UUID:"), uuid); + names = vshMalloc(ctl, sizeof(char *) * numfilters); - if (virStoragePoolGetInfo(pool, &info) == 0) { - double val; - const char *unit; - switch (info.state) { - case VIR_STORAGE_POOL_INACTIVE: - vshPrint(ctl, "%-15s %s\n", _("State:"), - _("inactive")); - break; - case VIR_STORAGE_POOL_BUILDING: - vshPrint(ctl, "%-15s %s\n", _("State:"), - _("building")); - break; - case VIR_STORAGE_POOL_RUNNING: - vshPrint(ctl, "%-15s %s\n", _("State:"), - _("running")); - break; - case VIR_STORAGE_POOL_DEGRADED: - vshPrint(ctl, "%-15s %s\n", _("State:"), - _("degraded")); - break; - case VIR_STORAGE_POOL_INACCESSIBLE: - vshPrint(ctl, "%-15s %s\n", _("State:"), - _("inaccessible")); - break; - } + if ((numfilters = virConnectListNWFilters(ctl->conn, names, + numfilters)) < 0) { + vshError(ctl, "%s", _("Failed to list network filters")); + VIR_FREE(names); + return false; + } - /* Check and display whether the pool is persistent or not */ - persistent = virStoragePoolIsPersistent(pool); - vshDebug(ctl, VSH_ERR_DEBUG, "Pool persistent flag value: %d\n", - persistent); - if (persistent < 0) - vshPrint(ctl, "%-15s %s\n", _("Persistent:"), _("unknown")); - else - vshPrint(ctl, "%-15s %s\n", _("Persistent:"), persistent ? _("yes") : _("no")); - - /* Check and display whether the pool is autostarted or not */ - virStoragePoolGetAutostart(pool, &autostart); - vshDebug(ctl, VSH_ERR_DEBUG, "Pool autostart flag value: %d\n", - autostart); - if (autostart < 0) - vshPrint(ctl, "%-15s %s\n", _("Autostart:"), _("no autostart")); - else - vshPrint(ctl, "%-15s %s\n", _("Autostart:"), autostart ? _("yes") : _("no")); + qsort(&names[0], numfilters, sizeof(char *), vshNameSorter); - if (info.state == VIR_STORAGE_POOL_RUNNING || - info.state == VIR_STORAGE_POOL_DEGRADED) { - val = prettyCapacity(info.capacity, &unit); - vshPrint(ctl, "%-15s %2.2lf %s\n", _("Capacity:"), val, unit); + vshPrintExtra(ctl, "%-36s %-20s \n", _("UUID"), _("Name")); + vshPrintExtra(ctl, + "----------------------------------------------------------------\n"); - val = prettyCapacity(info.allocation, &unit); - vshPrint(ctl, "%-15s %2.2lf %s\n", _("Allocation:"), val, unit); + for (i = 0; i < numfilters; i++) { + virNWFilterPtr nwfilter = + virNWFilterLookupByName(ctl->conn, names[i]); - val = prettyCapacity(info.available, &unit); - vshPrint(ctl, "%-15s %2.2lf %s\n", _("Available:"), val, unit); + /* this kind of work with networks is not atomic operation */ + if (!nwfilter) { + VIR_FREE(names[i]); + continue; } - } else { - ret = false; + + virNWFilterGetUUIDString(nwfilter, uuid); + vshPrint(ctl, "%-36s %-20s\n", + uuid, + virNWFilterGetName(nwfilter)); + virNWFilterFree(nwfilter); + VIR_FREE(names[i]); } - virStoragePoolFree(pool); - return ret; + VIR_FREE(names); + return true; } /* - * "pool-name" command + * "nwfilter-edit" command */ -static const vshCmdInfo info_pool_name[] = { - {"help", N_("convert a pool UUID to pool name")}, - {"desc", ""}, +static const vshCmdInfo info_nwfilter_edit[] = { + {"help", N_("edit XML configuration for a network filter")}, + {"desc", N_("Edit the XML configuration for a network filter.")}, {NULL, NULL} }; -static const vshCmdOptDef opts_pool_name[] = { - {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool uuid")}, +static const vshCmdOptDef opts_nwfilter_edit[] = { + {"nwfilter", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network filter name or uuid")}, {NULL, 0, 0, NULL} }; static bool -cmdPoolName(vshControl *ctl, const vshCmd *cmd) +cmdNWFilterEdit(vshControl *ctl, const vshCmd *cmd) { - virStoragePoolPtr pool; + bool ret = false; + virNWFilterPtr nwfilter = NULL; + virNWFilterPtr nwfilter_edited = NULL; if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - if (!(pool = vshCommandOptPoolBy(ctl, cmd, "pool", NULL, - VSH_BYUUID))) - return false; - - vshPrint(ctl, "%s\n", virStoragePoolGetName(pool)); - virStoragePoolFree(pool); - return true; -} - - -/* - * "pool-start" command - */ -static const vshCmdInfo info_pool_start[] = { - {"help", N_("start a (previously defined) inactive pool")}, - {"desc", N_("Start a pool.")}, - {NULL, NULL} -}; + goto cleanup; -static const vshCmdOptDef opts_pool_start[] = { - {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("name or uuid of the inactive pool")}, - {NULL, 0, 0, NULL} -}; + nwfilter = vshCommandOptNWFilter(ctl, cmd, NULL); + if (nwfilter == NULL) + goto cleanup; -static bool -cmdPoolStart(vshControl *ctl, const vshCmd *cmd) -{ - virStoragePoolPtr pool; - bool ret = true; - const char *name = NULL; +#define EDIT_GET_XML virNWFilterGetXMLDesc(nwfilter, 0) +#define EDIT_NOT_CHANGED \ + vshPrint(ctl, _("Network filter %s XML " \ + "configuration not changed.\n"), \ + virNWFilterGetName(nwfilter)); \ + ret = true; goto edit_cleanup; +#define EDIT_DEFINE \ + (nwfilter_edited = virNWFilterDefineXML(ctl->conn, doc_edited)) +#define EDIT_FREE \ + if (nwfilter_edited) \ + virNWFilterFree(nwfilter); +#include "virsh-edit.c" - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; + vshPrint(ctl, _("Network filter %s XML configuration edited.\n"), + virNWFilterGetName(nwfilter_edited)); - if (!(pool = vshCommandOptPool(ctl, cmd, "pool", &name))) - return false; + ret = true; - if (virStoragePoolCreate(pool, 0) == 0) { - vshPrint(ctl, _("Pool %s started\n"), name); - } else { - vshError(ctl, _("Failed to start pool %s"), name); - ret = false; - } +cleanup: + if (nwfilter) + virNWFilterFree(nwfilter); + if (nwfilter_edited) + virNWFilterFree(nwfilter_edited); - virStoragePoolFree(pool); return ret; } /* - * "pool-undefine" command + * "nodedev-create" command */ -static const vshCmdInfo info_pool_undefine[] = { - {"help", N_("undefine an inactive pool")}, - {"desc", N_("Undefine the configuration for an inactive pool.")}, +static const vshCmdInfo info_node_device_create[] = { + {"help", N_("create a device defined " + "by an XML file on the node")}, + {"desc", N_("Create a device on the node. Note that this " + "command creates devices on the physical host " + "that can then be assigned to a virtual machine.")}, {NULL, NULL} }; -static const vshCmdOptDef opts_pool_undefine[] = { - {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")}, +static const vshCmdOptDef opts_node_device_create[] = { + {"file", VSH_OT_DATA, VSH_OFLAG_REQ, + N_("file containing an XML description of the device")}, {NULL, 0, 0, NULL} }; static bool -cmdPoolUndefine(vshControl *ctl, const vshCmd *cmd) +cmdNodeDeviceCreate(vshControl *ctl, const vshCmd *cmd) { - virStoragePoolPtr pool; + virNodeDevicePtr dev = NULL; + const char *from = NULL; bool ret = true; - const char *name; + char *buffer; if (!vshConnectionUsability(ctl, ctl->conn)) return false; - if (!(pool = vshCommandOptPool(ctl, cmd, "pool", &name))) + if (vshCommandOptString(cmd, "file", &from) <= 0) + return false; + + if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0) return false; - if (virStoragePoolUndefine(pool) == 0) { - vshPrint(ctl, _("Pool %s has been undefined\n"), name); + dev = virNodeDeviceCreateXML(ctl->conn, buffer, 0); + VIR_FREE(buffer); + + if (dev != NULL) { + vshPrint(ctl, _("Node device %s created from %s\n"), + virNodeDeviceGetName(dev), from); + virNodeDeviceFree(dev); } else { - vshError(ctl, _("Failed to undefine pool %s"), name); + vshError(ctl, _("Failed to create node device from %s"), from); ret = false; } - virStoragePoolFree(pool); return ret; } /* - * "pool-uuid" command + * "nodedev-destroy" command */ -static const vshCmdInfo info_pool_uuid[] = { - {"help", N_("convert a pool name to pool UUID")}, - {"desc", ""}, +static const vshCmdInfo info_node_device_destroy[] = { + {"help", N_("destroy (stop) a device on the node")}, + {"desc", N_("Destroy a device on the node. Note that this " + "command destroys devices on the physical host")}, {NULL, NULL} }; -static const vshCmdOptDef opts_pool_uuid[] = { - {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name")}, +static const vshCmdOptDef opts_node_device_destroy[] = { + {"name", VSH_OT_DATA, VSH_OFLAG_REQ, + N_("name of the device to be destroyed")}, {NULL, 0, 0, NULL} }; static bool -cmdPoolUuid(vshControl *ctl, const vshCmd *cmd) +cmdNodeDeviceDestroy(vshControl *ctl, const vshCmd *cmd) { - virStoragePoolPtr pool; - char uuid[VIR_UUID_STRING_BUFLEN]; + virNodeDevicePtr dev = NULL; + bool ret = true; + const char *name = NULL; - if (!vshConnectionUsability(ctl, ctl->conn)) + if (!vshConnectionUsability(ctl, ctl->conn)) { return false; + } - if (!(pool = vshCommandOptPoolBy(ctl, cmd, "pool", NULL, - VSH_BYNAME))) + if (vshCommandOptString(cmd, "name", &name) <= 0) return false; - if (virStoragePoolGetUUIDString(pool, uuid) != -1) - vshPrint(ctl, "%s\n", uuid); - else - vshError(ctl, "%s", _("failed to get pool UUID")); + dev = virNodeDeviceLookupByName(ctl->conn, name); - virStoragePoolFree(pool); - return true; + if (virNodeDeviceDestroy(dev) == 0) { + vshPrint(ctl, _("Destroyed node device '%s'\n"), name); + } else { + vshError(ctl, _("Failed to destroy node device '%s'"), name); + ret = false; + } + + virNodeDeviceFree(dev); + return ret; } /* @@ -5582,75 +4276,6 @@ cmdNetworkEdit(vshControl *ctl, const vshCmd *cmd) } /* - * "pool-edit" command - */ -static const vshCmdInfo info_pool_edit[] = { - {"help", N_("edit XML configuration for a storage pool")}, - {"desc", N_("Edit the XML configuration for a storage pool.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_pool_edit[] = { - {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdPoolEdit(vshControl *ctl, const vshCmd *cmd) -{ - bool ret = false; - virStoragePoolPtr pool = NULL; - virStoragePoolPtr pool_edited = NULL; - unsigned int flags = VIR_STORAGE_XML_INACTIVE; - char *tmp_desc = NULL; - - if (!vshConnectionUsability(ctl, ctl->conn)) - goto cleanup; - - pool = vshCommandOptPool(ctl, cmd, "pool", NULL); - if (pool == NULL) - goto cleanup; - - /* Some old daemons don't support _INACTIVE flag */ - if (!(tmp_desc = virStoragePoolGetXMLDesc(pool, flags))) { - if (last_error->code == VIR_ERR_INVALID_ARG) { - flags &= ~VIR_STORAGE_XML_INACTIVE; - virFreeError(last_error); - last_error = NULL; - } else { - goto cleanup; - } - } else { - VIR_FREE(tmp_desc); - } - -#define EDIT_GET_XML virStoragePoolGetXMLDesc(pool, flags) -#define EDIT_NOT_CHANGED \ - vshPrint(ctl, _("Pool %s XML configuration not changed.\n"), \ - virStoragePoolGetName(pool)); \ - ret = true; goto edit_cleanup; -#define EDIT_DEFINE \ - (pool_edited = virStoragePoolDefineXML(ctl->conn, doc_edited, 0)) -#define EDIT_FREE \ - if (pool_edited) \ - virStoragePoolFree(pool_edited); -#include "virsh-edit.c" - - vshPrint(ctl, _("Pool %s XML configuration edited.\n"), - virStoragePoolGetName(pool_edited)); - - ret = true; - - cleanup: - if (pool) - virStoragePoolFree(pool); - if (pool_edited) - virStoragePoolFree(pool_edited); - - return ret; -} - -/* * "quit" command */ static const vshCmdInfo info_quit[] = { @@ -8205,41 +6830,6 @@ vshCommandOptInterfaceBy(vshControl *ctl, const vshCmd *cmd, return iface; } -static virStoragePoolPtr -vshCommandOptPoolBy(vshControl *ctl, const vshCmd *cmd, const char *optname, - const char **name, int flag) -{ - virStoragePoolPtr pool = NULL; - const char *n = NULL; - - if (vshCommandOptString(cmd, optname, &n) <= 0) - return NULL; - - vshDebug(ctl, VSH_ERR_INFO, "%s: found option <%s>: %s\n", - cmd->def->name, optname, n); - - if (name) - *name = n; - - /* try it by UUID */ - if ((flag & VSH_BYUUID) && strlen(n) == VIR_UUID_STRING_BUFLEN-1) { - vshDebug(ctl, VSH_ERR_DEBUG, "%s: <%s> trying as pool UUID\n", - cmd->def->name, optname); - pool = virStoragePoolLookupByUUIDString(ctl->conn, n); - } - /* try it by NAME */ - if (pool == NULL && (flag & VSH_BYNAME)) { - vshDebug(ctl, VSH_ERR_DEBUG, "%s: <%s> trying as pool NAME\n", - cmd->def->name, optname); - pool = virStoragePoolLookupByName(ctl->conn, n); - } - - if (!pool) - vshError(ctl, _("failed to get pool '%s'"), n); - - return pool; -} - static virSecretPtr vshCommandOptSecret(vshControl *ctl, const vshCmd *cmd, const char **name) { @@ -9706,6 +8296,8 @@ static const vshCmdDef domMonitoringCmds[] = { {NULL, NULL, NULL, NULL, 0} }; +#include "virsh-pool.c" + static const vshCmdDef storagePoolCmds[] = { {"find-storage-pool-sources-as", cmdPoolDiscoverSourcesAs, opts_find_storage_pool_sources_as, info_find_storage_pool_sources_as, 0}, -- 1.7.7.3

On 07/24/12 11:18, Osier Yang wrote:
This splits commands of storage pool group into virsh-pool.c, The helpers not for common use are moved too. Standard copyright is added for the new file.
* tools/virsh.c: Remove commands for storage storage pool and a few helpers. (vshCommandOptVol, vshCommandOptVolBy).
* tools/virsh-pool.c: New file, filled with commands of storage pool group and its helpers. --- tools/virsh-pool.c | 1415 +++++++++++++++++++++++++++++++++++++++++++ tools/virsh.c | 1690 +++++----------------------------------------------- 2 files changed, 1556 insertions(+), 1549 deletions(-) create mode 100644 tools/virsh-pool.c
Again, I checked that additions match removals and that aditions are not modified. Also this file has some functions that would deserve to be in a utils file. As this is a first step into splitting virsh I'm fine with this. ACK Peter

Commands to manage network are moved from virsh.c to virsh-network.c, with a few helpers for network command use. * virsh.c: Remove network commands and a few helpers. * virsh-network.c: New file, filled with network commands its helpers. --- tools/virsh-network.c | 688 +++++++++++++++++++++++++++++++++++++++++++++++++ tools/virsh.c | 678 +------------------------------------------------ 2 files changed, 690 insertions(+), 676 deletions(-) create mode 100644 tools/virsh-network.c diff --git a/tools/virsh-network.c b/tools/virsh-network.c new file mode 100644 index 0000000..459ccfe --- /dev/null +++ b/tools/virsh-network.c @@ -0,0 +1,688 @@ +/* + * virsh-network.c: Commands to manage network + * + * Copyright (C) 2005, 2007-2012 Red Hat, Inc + * + * 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 + * License along with this library; If not, see + * <http://www.gnu.org/licenses/>. + * + * Daniel Veillard <veillard@redhat.com> + * Karel Zak <kzak@redhat.com> + * Daniel P. Berrange <berrange@redhat.com> + * + */ + +/* default is lookup by Name and UUID */ +#define vshCommandOptNetwork(_ctl, _cmd, _name) \ + vshCommandOptNetworkBy(_ctl, _cmd, _name, \ + VSH_BYUUID|VSH_BYNAME) + +static virNetworkPtr +vshCommandOptNetworkBy(vshControl *ctl, const vshCmd *cmd, + const char **name, int flag) +{ + virNetworkPtr network = NULL; + const char *n = NULL; + const char *optname = "network"; + if (!cmd_has_option(ctl, cmd, optname)) + return NULL; + + if (vshCommandOptString(cmd, optname, &n) <= 0) + return NULL; + + vshDebug(ctl, VSH_ERR_INFO, "%s: found option <%s>: %s\n", + cmd->def->name, optname, n); + + if (name) + *name = n; + + /* try it by UUID */ + if ((flag & VSH_BYUUID) && strlen(n) == VIR_UUID_STRING_BUFLEN-1) { + vshDebug(ctl, VSH_ERR_DEBUG, "%s: <%s> trying as network UUID\n", + cmd->def->name, optname); + network = virNetworkLookupByUUIDString(ctl->conn, n); + } + /* try it by NAME */ + if (network==NULL && (flag & VSH_BYNAME)) { + vshDebug(ctl, VSH_ERR_DEBUG, "%s: <%s> trying as network NAME\n", + cmd->def->name, optname); + network = virNetworkLookupByName(ctl->conn, n); + } + + if (!network) + vshError(ctl, _("failed to get network '%s'"), n); + + return network; +} + +/* + * "net-autostart" command + */ +static const vshCmdInfo info_network_autostart[] = { + {"help", N_("autostart a network")}, + {"desc", + N_("Configure a network to be automatically started at boot.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_network_autostart[] = { + {"network", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network name or uuid")}, + {"disable", VSH_OT_BOOL, 0, N_("disable autostarting")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdNetworkAutostart(vshControl *ctl, const vshCmd *cmd) +{ + virNetworkPtr network; + const char *name; + int autostart; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(network = vshCommandOptNetwork(ctl, cmd, &name))) + return false; + + autostart = !vshCommandOptBool(cmd, "disable"); + + if (virNetworkSetAutostart(network, autostart) < 0) { + if (autostart) + vshError(ctl, _("failed to mark network %s as autostarted"), name); + else + vshError(ctl, _("failed to unmark network %s as autostarted"), name); + virNetworkFree(network); + return false; + } + + if (autostart) + vshPrint(ctl, _("Network %s marked as autostarted\n"), name); + else + vshPrint(ctl, _("Network %s unmarked as autostarted\n"), name); + + virNetworkFree(network); + return true; +} + +/* + * "net-create" command + */ +static const vshCmdInfo info_network_create[] = { + {"help", N_("create a network from an XML file")}, + {"desc", N_("Create a network.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_network_create[] = { + {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containing an XML network description")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdNetworkCreate(vshControl *ctl, const vshCmd *cmd) +{ + virNetworkPtr network; + const char *from = NULL; + bool ret = true; + char *buffer; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (vshCommandOptString(cmd, "file", &from) <= 0) + return false; + + if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0) + return false; + + network = virNetworkCreateXML(ctl->conn, buffer); + VIR_FREE(buffer); + + if (network != NULL) { + vshPrint(ctl, _("Network %s created from %s\n"), + virNetworkGetName(network), from); + virNetworkFree(network); + } else { + vshError(ctl, _("Failed to create network from %s"), from); + ret = false; + } + return ret; +} + +/* + * "net-define" command + */ +static const vshCmdInfo info_network_define[] = { + {"help", N_("define (but don't start) a network from an XML file")}, + {"desc", N_("Define a network.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_network_define[] = { + {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containing an XML network description")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdNetworkDefine(vshControl *ctl, const vshCmd *cmd) +{ + virNetworkPtr network; + const char *from = NULL; + bool ret = true; + char *buffer; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (vshCommandOptString(cmd, "file", &from) <= 0) + return false; + + if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0) + return false; + + network = virNetworkDefineXML(ctl->conn, buffer); + VIR_FREE(buffer); + + if (network != NULL) { + vshPrint(ctl, _("Network %s defined from %s\n"), + virNetworkGetName(network), from); + virNetworkFree(network); + } else { + vshError(ctl, _("Failed to define network from %s"), from); + ret = false; + } + return ret; +} + +/* + * "net-destroy" command + */ +static const vshCmdInfo info_network_destroy[] = { + {"help", N_("destroy (stop) a network")}, + {"desc", N_("Forcefully stop a given network.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_network_destroy[] = { + {"network", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network name or uuid")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdNetworkDestroy(vshControl *ctl, const vshCmd *cmd) +{ + virNetworkPtr network; + bool ret = true; + const char *name; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(network = vshCommandOptNetwork(ctl, cmd, &name))) + return false; + + if (virNetworkDestroy(network) == 0) { + vshPrint(ctl, _("Network %s destroyed\n"), name); + } else { + vshError(ctl, _("Failed to destroy network %s"), name); + ret = false; + } + + virNetworkFree(network); + return ret; +} + +/* + * "net-dumpxml" command + */ +static const vshCmdInfo info_network_dumpxml[] = { + {"help", N_("network information in XML")}, + {"desc", N_("Output the network information as an XML dump to stdout.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_network_dumpxml[] = { + {"network", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network name or uuid")}, + {"inactive", VSH_OT_BOOL, VSH_OFLAG_NONE, N_("network information of an inactive domain")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdNetworkDumpXML(vshControl *ctl, const vshCmd *cmd) +{ + virNetworkPtr network; + bool ret = true; + char *dump; + unsigned int flags = 0; + int inactive; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(network = vshCommandOptNetwork(ctl, cmd, NULL))) + return false; + + inactive = vshCommandOptBool(cmd, "inactive"); + if (inactive) + flags |= VIR_NETWORK_XML_INACTIVE; + + dump = virNetworkGetXMLDesc(network, flags); + + if (dump != NULL) { + vshPrint(ctl, "%s", dump); + VIR_FREE(dump); + } else { + ret = false; + } + + virNetworkFree(network); + return ret; +} + +/* + * "net-info" command + */ +static const vshCmdInfo info_network_info[] = { + {"help", N_("network information")}, + {"desc", N_("Returns basic information about the network")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_network_info[] = { + {"network", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network name or uuid")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdNetworkInfo(vshControl *ctl, const vshCmd *cmd) +{ + virNetworkPtr network; + char uuid[VIR_UUID_STRING_BUFLEN]; + int autostart; + int persistent = -1; + int active = -1; + char *bridge = NULL; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(network = vshCommandOptNetwork(ctl, cmd, NULL))) + return false; + + vshPrint(ctl, "%-15s %s\n", _("Name"), virNetworkGetName(network)); + + if (virNetworkGetUUIDString(network, uuid) == 0) + vshPrint(ctl, "%-15s %s\n", _("UUID"), uuid); + + active = virNetworkIsActive(network); + if (active >= 0) + vshPrint(ctl, "%-15s %s\n", _("Active:"), active? _("yes") : _("no")); + + persistent = virNetworkIsPersistent(network); + if (persistent < 0) + vshPrint(ctl, "%-15s %s\n", _("Persistent:"), _("unknown")); + else + vshPrint(ctl, "%-15s %s\n", _("Persistent:"), persistent ? _("yes") : _("no")); + + if (virNetworkGetAutostart(network, &autostart) < 0) + vshPrint(ctl, "%-15s %s\n", _("Autostart:"), _("no autostart")); + else + vshPrint(ctl, "%-15s %s\n", _("Autostart:"), autostart ? _("yes") : _("no")); + + bridge = virNetworkGetBridgeName(network); + if (bridge) + vshPrint(ctl, "%-15s %s\n", _("Bridge:"), bridge); + + VIR_FREE(bridge); + virNetworkFree(network); + return true; +} + +/* + * "net-list" command + */ +static const vshCmdInfo info_network_list[] = { + {"help", N_("list networks")}, + {"desc", N_("Returns list of networks.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_network_list[] = { + {"inactive", VSH_OT_BOOL, 0, N_("list inactive networks")}, + {"all", VSH_OT_BOOL, 0, N_("list inactive & active networks")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdNetworkList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) +{ + bool inactive = vshCommandOptBool(cmd, "inactive"); + bool all = vshCommandOptBool(cmd, "all"); + bool active = !inactive || all; + int maxactive = 0, maxinactive = 0, i; + char **activeNames = NULL, **inactiveNames = NULL; + inactive |= all; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (active) { + maxactive = virConnectNumOfNetworks(ctl->conn); + if (maxactive < 0) { + vshError(ctl, "%s", _("Failed to list active networks")); + return false; + } + if (maxactive) { + activeNames = vshMalloc(ctl, sizeof(char *) * maxactive); + + if ((maxactive = virConnectListNetworks(ctl->conn, activeNames, + maxactive)) < 0) { + vshError(ctl, "%s", _("Failed to list active networks")); + VIR_FREE(activeNames); + return false; + } + + qsort(&activeNames[0], maxactive, sizeof(char *), vshNameSorter); + } + } + if (inactive) { + maxinactive = virConnectNumOfDefinedNetworks(ctl->conn); + if (maxinactive < 0) { + vshError(ctl, "%s", _("Failed to list inactive networks")); + VIR_FREE(activeNames); + return false; + } + if (maxinactive) { + inactiveNames = vshMalloc(ctl, sizeof(char *) * maxinactive); + + if ((maxinactive = + virConnectListDefinedNetworks(ctl->conn, inactiveNames, + maxinactive)) < 0) { + vshError(ctl, "%s", _("Failed to list inactive networks")); + VIR_FREE(activeNames); + VIR_FREE(inactiveNames); + return false; + } + + qsort(&inactiveNames[0], maxinactive, sizeof(char*), vshNameSorter); + } + } + vshPrintExtra(ctl, "%-20s %-10s %s\n", _("Name"), _("State"), + _("Autostart")); + vshPrintExtra(ctl, "-----------------------------------------\n"); + + for (i = 0; i < maxactive; i++) { + virNetworkPtr network = + virNetworkLookupByName(ctl->conn, activeNames[i]); + const char *autostartStr; + int autostart = 0; + + /* this kind of work with networks is not atomic operation */ + if (!network) { + VIR_FREE(activeNames[i]); + continue; + } + + if (virNetworkGetAutostart(network, &autostart) < 0) + autostartStr = _("no autostart"); + else + autostartStr = autostart ? _("yes") : _("no"); + + vshPrint(ctl, "%-20s %-10s %-10s\n", + virNetworkGetName(network), + _("active"), + autostartStr); + virNetworkFree(network); + VIR_FREE(activeNames[i]); + } + for (i = 0; i < maxinactive; i++) { + virNetworkPtr network = virNetworkLookupByName(ctl->conn, inactiveNames[i]); + const char *autostartStr; + int autostart = 0; + + /* this kind of work with networks is not atomic operation */ + if (!network) { + VIR_FREE(inactiveNames[i]); + continue; + } + + if (virNetworkGetAutostart(network, &autostart) < 0) + autostartStr = _("no autostart"); + else + autostartStr = autostart ? _("yes") : _("no"); + + vshPrint(ctl, "%-20s %-10s %-10s\n", + inactiveNames[i], + _("inactive"), + autostartStr); + + virNetworkFree(network); + VIR_FREE(inactiveNames[i]); + } + VIR_FREE(activeNames); + VIR_FREE(inactiveNames); + return true; +} + +/* + * "net-name" command + */ +static const vshCmdInfo info_network_name[] = { + {"help", N_("convert a network UUID to network name")}, + {"desc", ""}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_network_name[] = { + {"network", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network uuid")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdNetworkName(vshControl *ctl, const vshCmd *cmd) +{ + virNetworkPtr network; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + if (!(network = vshCommandOptNetworkBy(ctl, cmd, NULL, + VSH_BYUUID))) + return false; + + vshPrint(ctl, "%s\n", virNetworkGetName(network)); + virNetworkFree(network); + return true; +} + +/* + * "net-start" command + */ +static const vshCmdInfo info_network_start[] = { + {"help", N_("start a (previously defined) inactive network")}, + {"desc", N_("Start a network.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_network_start[] = { + {"network", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network name or uuid")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdNetworkStart(vshControl *ctl, const vshCmd *cmd) +{ + virNetworkPtr network; + bool ret = true; + const char *name = NULL; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(network = vshCommandOptNetwork(ctl, cmd, &name))) + return false; + + if (virNetworkCreate(network) == 0) { + vshPrint(ctl, _("Network %s started\n"), name); + } else { + vshError(ctl, _("Failed to start network %s"), name); + ret = false; + } + virNetworkFree(network); + return ret; +} + +/* + * "net-undefine" command + */ +static const vshCmdInfo info_network_undefine[] = { + {"help", N_("undefine an inactive network")}, + {"desc", N_("Undefine the configuration for an inactive network.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_network_undefine[] = { + {"network", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network name or uuid")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdNetworkUndefine(vshControl *ctl, const vshCmd *cmd) +{ + virNetworkPtr network; + bool ret = true; + const char *name; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(network = vshCommandOptNetwork(ctl, cmd, &name))) + return false; + + if (virNetworkUndefine(network) == 0) { + vshPrint(ctl, _("Network %s has been undefined\n"), name); + } else { + vshError(ctl, _("Failed to undefine network %s"), name); + ret = false; + } + + virNetworkFree(network); + return ret; +} + +/* + * "net-uuid" command + */ +static const vshCmdInfo info_network_uuid[] = { + {"help", N_("convert a network name to network UUID")}, + {"desc", ""}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_network_uuid[] = { + {"network", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network name")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdNetworkUuid(vshControl *ctl, const vshCmd *cmd) +{ + virNetworkPtr network; + char uuid[VIR_UUID_STRING_BUFLEN]; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(network = vshCommandOptNetworkBy(ctl, cmd, NULL, + VSH_BYNAME))) + return false; + + if (virNetworkGetUUIDString(network, uuid) != -1) + vshPrint(ctl, "%s\n", uuid); + else + vshError(ctl, "%s", _("failed to get network UUID")); + + virNetworkFree(network); + return true; +} + +/* + * "net-edit" command + */ +static const vshCmdInfo info_network_edit[] = { + {"help", N_("edit XML configuration for a network")}, + {"desc", N_("Edit the XML configuration for a network.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_network_edit[] = { + {"network", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network name or uuid")}, + {NULL, 0, 0, NULL} +}; + +static char *vshNetworkGetXMLDesc(virNetworkPtr network) +{ + unsigned int flags = VIR_NETWORK_XML_INACTIVE; + char *doc = virNetworkGetXMLDesc(network, flags); + + if (!doc && last_error->code == VIR_ERR_INVALID_ARG) { + /* The server side libvirt doesn't support + * VIR_NETWORK_XML_INACTIVE, so retry without it. + */ + virFreeError(last_error); + last_error = NULL; + flags &= ~VIR_NETWORK_XML_INACTIVE; + doc = virNetworkGetXMLDesc(network, flags); + } + return doc; +} + +static bool +cmdNetworkEdit(vshControl *ctl, const vshCmd *cmd) +{ + bool ret = false; + virNetworkPtr network = NULL; + virNetworkPtr network_edited = NULL; + + if (!vshConnectionUsability(ctl, ctl->conn)) + goto cleanup; + + network = vshCommandOptNetwork(ctl, cmd, NULL); + if (network == NULL) + goto cleanup; + +#define EDIT_GET_XML vshNetworkGetXMLDesc(network) +#define EDIT_NOT_CHANGED \ + vshPrint(ctl, _("Network %s XML configuration not changed.\n"), \ + virNetworkGetName(network)); \ + ret = true; goto edit_cleanup; +#define EDIT_DEFINE \ + (network_edited = virNetworkDefineXML(ctl->conn, doc_edited)) +#define EDIT_FREE \ + if (network_edited) \ + virNetworkFree(network_edited); +#include "virsh-edit.c" + + vshPrint(ctl, _("Network %s XML configuration edited.\n"), + virNetworkGetName(network_edited)); + + ret = true; + + cleanup: + if (network) + virNetworkFree(network); + if (network_edited) + virNetworkFree(network_edited); + + return ret; +} diff --git a/tools/virsh.c b/tools/virsh.c index 7a30871..220aa1d 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -339,14 +339,6 @@ static virDomainPtr vshCommandOptDomainBy(vshControl *ctl, const vshCmd *cmd, #define vshCommandOptDomain(_ctl, _cmd, _name) \ vshCommandOptDomainBy(_ctl, _cmd, _name, VSH_BYID|VSH_BYUUID|VSH_BYNAME) -static virNetworkPtr vshCommandOptNetworkBy(vshControl *ctl, const vshCmd *cmd, - const char **name, int flag); - -/* default is lookup by Name and UUID */ -#define vshCommandOptNetwork(_ctl, _cmd, _name) \ - vshCommandOptNetworkBy(_ctl, _cmd, _name, \ - VSH_BYUUID|VSH_BYNAME) - static virNWFilterPtr vshCommandOptNWFilterBy(vshControl *ctl, const vshCmd *cmd, const char **name, int flag); @@ -1273,292 +1265,6 @@ cmdCapabilities(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) } /* - * "net-autostart" command - */ -static const vshCmdInfo info_network_autostart[] = { - {"help", N_("autostart a network")}, - {"desc", - N_("Configure a network to be automatically started at boot.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_network_autostart[] = { - {"network", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network name or uuid")}, - {"disable", VSH_OT_BOOL, 0, N_("disable autostarting")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdNetworkAutostart(vshControl *ctl, const vshCmd *cmd) -{ - virNetworkPtr network; - const char *name; - int autostart; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (!(network = vshCommandOptNetwork(ctl, cmd, &name))) - return false; - - autostart = !vshCommandOptBool(cmd, "disable"); - - if (virNetworkSetAutostart(network, autostart) < 0) { - if (autostart) - vshError(ctl, _("failed to mark network %s as autostarted"), name); - else - vshError(ctl, _("failed to unmark network %s as autostarted"), name); - virNetworkFree(network); - return false; - } - - if (autostart) - vshPrint(ctl, _("Network %s marked as autostarted\n"), name); - else - vshPrint(ctl, _("Network %s unmarked as autostarted\n"), name); - - virNetworkFree(network); - return true; -} - -/* - * "net-create" command - */ -static const vshCmdInfo info_network_create[] = { - {"help", N_("create a network from an XML file")}, - {"desc", N_("Create a network.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_network_create[] = { - {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containing an XML network description")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdNetworkCreate(vshControl *ctl, const vshCmd *cmd) -{ - virNetworkPtr network; - const char *from = NULL; - bool ret = true; - char *buffer; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (vshCommandOptString(cmd, "file", &from) <= 0) - return false; - - if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0) - return false; - - network = virNetworkCreateXML(ctl->conn, buffer); - VIR_FREE(buffer); - - if (network != NULL) { - vshPrint(ctl, _("Network %s created from %s\n"), - virNetworkGetName(network), from); - virNetworkFree(network); - } else { - vshError(ctl, _("Failed to create network from %s"), from); - ret = false; - } - return ret; -} - - -/* - * "net-define" command - */ -static const vshCmdInfo info_network_define[] = { - {"help", N_("define (but don't start) a network from an XML file")}, - {"desc", N_("Define a network.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_network_define[] = { - {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containing an XML network description")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdNetworkDefine(vshControl *ctl, const vshCmd *cmd) -{ - virNetworkPtr network; - const char *from = NULL; - bool ret = true; - char *buffer; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (vshCommandOptString(cmd, "file", &from) <= 0) - return false; - - if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0) - return false; - - network = virNetworkDefineXML(ctl->conn, buffer); - VIR_FREE(buffer); - - if (network != NULL) { - vshPrint(ctl, _("Network %s defined from %s\n"), - virNetworkGetName(network), from); - virNetworkFree(network); - } else { - vshError(ctl, _("Failed to define network from %s"), from); - ret = false; - } - return ret; -} - - -/* - * "net-destroy" command - */ -static const vshCmdInfo info_network_destroy[] = { - {"help", N_("destroy (stop) a network")}, - {"desc", N_("Forcefully stop a given network.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_network_destroy[] = { - {"network", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network name or uuid")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdNetworkDestroy(vshControl *ctl, const vshCmd *cmd) -{ - virNetworkPtr network; - bool ret = true; - const char *name; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (!(network = vshCommandOptNetwork(ctl, cmd, &name))) - return false; - - if (virNetworkDestroy(network) == 0) { - vshPrint(ctl, _("Network %s destroyed\n"), name); - } else { - vshError(ctl, _("Failed to destroy network %s"), name); - ret = false; - } - - virNetworkFree(network); - return ret; -} - - -/* - * "net-dumpxml" command - */ -static const vshCmdInfo info_network_dumpxml[] = { - {"help", N_("network information in XML")}, - {"desc", N_("Output the network information as an XML dump to stdout.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_network_dumpxml[] = { - {"network", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network name or uuid")}, - {"inactive", VSH_OT_BOOL, VSH_OFLAG_NONE, N_("network information of an inactive domain")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdNetworkDumpXML(vshControl *ctl, const vshCmd *cmd) -{ - virNetworkPtr network; - bool ret = true; - char *dump; - unsigned int flags = 0; - int inactive; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (!(network = vshCommandOptNetwork(ctl, cmd, NULL))) - return false; - - inactive = vshCommandOptBool(cmd, "inactive"); - if (inactive) - flags |= VIR_NETWORK_XML_INACTIVE; - - dump = virNetworkGetXMLDesc(network, flags); - - if (dump != NULL) { - vshPrint(ctl, "%s", dump); - VIR_FREE(dump); - } else { - ret = false; - } - - virNetworkFree(network); - return ret; -} - -/* - * "net-info" command - */ -static const vshCmdInfo info_network_info[] = { - {"help", N_("network information")}, - {"desc", N_("Returns basic information about the network")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_network_info[] = { - {"network", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network name or uuid")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdNetworkInfo(vshControl *ctl, const vshCmd *cmd) -{ - virNetworkPtr network; - char uuid[VIR_UUID_STRING_BUFLEN]; - int autostart; - int persistent = -1; - int active = -1; - char *bridge = NULL; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (!(network = vshCommandOptNetwork(ctl, cmd, NULL))) - return false; - - vshPrint(ctl, "%-15s %s\n", _("Name"), virNetworkGetName(network)); - - if (virNetworkGetUUIDString(network, uuid) == 0) - vshPrint(ctl, "%-15s %s\n", _("UUID"), uuid); - - active = virNetworkIsActive(network); - if (active >= 0) - vshPrint(ctl, "%-15s %s\n", _("Active:"), active? _("yes") : _("no")); - - persistent = virNetworkIsPersistent(network); - if (persistent < 0) - vshPrint(ctl, "%-15s %s\n", _("Persistent:"), _("unknown")); - else - vshPrint(ctl, "%-15s %s\n", _("Persistent:"), persistent ? _("yes") : _("no")); - - if (virNetworkGetAutostart(network, &autostart) < 0) - vshPrint(ctl, "%-15s %s\n", _("Autostart:"), _("no autostart")); - else - vshPrint(ctl, "%-15s %s\n", _("Autostart:"), autostart ? _("yes") : _("no")); - - bridge = virNetworkGetBridgeName(network); - if (bridge) - vshPrint(ctl, "%-15s %s\n", _("Bridge:"), bridge); - - VIR_FREE(bridge); - virNetworkFree(network); - return true; -} - -/* * "iface-edit" command */ static const vshCmdInfo info_interface_edit[] = { @@ -1613,278 +1319,6 @@ cleanup: return ret; } -/* - * "net-list" command - */ -static const vshCmdInfo info_network_list[] = { - {"help", N_("list networks")}, - {"desc", N_("Returns list of networks.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_network_list[] = { - {"inactive", VSH_OT_BOOL, 0, N_("list inactive networks")}, - {"all", VSH_OT_BOOL, 0, N_("list inactive & active networks")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdNetworkList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) -{ - bool inactive = vshCommandOptBool(cmd, "inactive"); - bool all = vshCommandOptBool(cmd, "all"); - bool active = !inactive || all; - int maxactive = 0, maxinactive = 0, i; - char **activeNames = NULL, **inactiveNames = NULL; - inactive |= all; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (active) { - maxactive = virConnectNumOfNetworks(ctl->conn); - if (maxactive < 0) { - vshError(ctl, "%s", _("Failed to list active networks")); - return false; - } - if (maxactive) { - activeNames = vshMalloc(ctl, sizeof(char *) * maxactive); - - if ((maxactive = virConnectListNetworks(ctl->conn, activeNames, - maxactive)) < 0) { - vshError(ctl, "%s", _("Failed to list active networks")); - VIR_FREE(activeNames); - return false; - } - - qsort(&activeNames[0], maxactive, sizeof(char *), vshNameSorter); - } - } - if (inactive) { - maxinactive = virConnectNumOfDefinedNetworks(ctl->conn); - if (maxinactive < 0) { - vshError(ctl, "%s", _("Failed to list inactive networks")); - VIR_FREE(activeNames); - return false; - } - if (maxinactive) { - inactiveNames = vshMalloc(ctl, sizeof(char *) * maxinactive); - - if ((maxinactive = - virConnectListDefinedNetworks(ctl->conn, inactiveNames, - maxinactive)) < 0) { - vshError(ctl, "%s", _("Failed to list inactive networks")); - VIR_FREE(activeNames); - VIR_FREE(inactiveNames); - return false; - } - - qsort(&inactiveNames[0], maxinactive, sizeof(char*), vshNameSorter); - } - } - vshPrintExtra(ctl, "%-20s %-10s %s\n", _("Name"), _("State"), - _("Autostart")); - vshPrintExtra(ctl, "-----------------------------------------\n"); - - for (i = 0; i < maxactive; i++) { - virNetworkPtr network = - virNetworkLookupByName(ctl->conn, activeNames[i]); - const char *autostartStr; - int autostart = 0; - - /* this kind of work with networks is not atomic operation */ - if (!network) { - VIR_FREE(activeNames[i]); - continue; - } - - if (virNetworkGetAutostart(network, &autostart) < 0) - autostartStr = _("no autostart"); - else - autostartStr = autostart ? _("yes") : _("no"); - - vshPrint(ctl, "%-20s %-10s %-10s\n", - virNetworkGetName(network), - _("active"), - autostartStr); - virNetworkFree(network); - VIR_FREE(activeNames[i]); - } - for (i = 0; i < maxinactive; i++) { - virNetworkPtr network = virNetworkLookupByName(ctl->conn, inactiveNames[i]); - const char *autostartStr; - int autostart = 0; - - /* this kind of work with networks is not atomic operation */ - if (!network) { - VIR_FREE(inactiveNames[i]); - continue; - } - - if (virNetworkGetAutostart(network, &autostart) < 0) - autostartStr = _("no autostart"); - else - autostartStr = autostart ? _("yes") : _("no"); - - vshPrint(ctl, "%-20s %-10s %-10s\n", - inactiveNames[i], - _("inactive"), - autostartStr); - - virNetworkFree(network); - VIR_FREE(inactiveNames[i]); - } - VIR_FREE(activeNames); - VIR_FREE(inactiveNames); - return true; -} - - -/* - * "net-name" command - */ -static const vshCmdInfo info_network_name[] = { - {"help", N_("convert a network UUID to network name")}, - {"desc", ""}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_network_name[] = { - {"network", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network uuid")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdNetworkName(vshControl *ctl, const vshCmd *cmd) -{ - virNetworkPtr network; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - if (!(network = vshCommandOptNetworkBy(ctl, cmd, NULL, - VSH_BYUUID))) - return false; - - vshPrint(ctl, "%s\n", virNetworkGetName(network)); - virNetworkFree(network); - return true; -} - - -/* - * "net-start" command - */ -static const vshCmdInfo info_network_start[] = { - {"help", N_("start a (previously defined) inactive network")}, - {"desc", N_("Start a network.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_network_start[] = { - {"network", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network name or uuid")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdNetworkStart(vshControl *ctl, const vshCmd *cmd) -{ - virNetworkPtr network; - bool ret = true; - const char *name = NULL; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (!(network = vshCommandOptNetwork(ctl, cmd, &name))) - return false; - - if (virNetworkCreate(network) == 0) { - vshPrint(ctl, _("Network %s started\n"), name); - } else { - vshError(ctl, _("Failed to start network %s"), name); - ret = false; - } - virNetworkFree(network); - return ret; -} - - -/* - * "net-undefine" command - */ -static const vshCmdInfo info_network_undefine[] = { - {"help", N_("undefine an inactive network")}, - {"desc", N_("Undefine the configuration for an inactive network.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_network_undefine[] = { - {"network", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network name or uuid")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdNetworkUndefine(vshControl *ctl, const vshCmd *cmd) -{ - virNetworkPtr network; - bool ret = true; - const char *name; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (!(network = vshCommandOptNetwork(ctl, cmd, &name))) - return false; - - if (virNetworkUndefine(network) == 0) { - vshPrint(ctl, _("Network %s has been undefined\n"), name); - } else { - vshError(ctl, _("Failed to undefine network %s"), name); - ret = false; - } - - virNetworkFree(network); - return ret; -} - - -/* - * "net-uuid" command - */ -static const vshCmdInfo info_network_uuid[] = { - {"help", N_("convert a network name to network UUID")}, - {"desc", ""}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_network_uuid[] = { - {"network", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network name")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdNetworkUuid(vshControl *ctl, const vshCmd *cmd) -{ - virNetworkPtr network; - char uuid[VIR_UUID_STRING_BUFLEN]; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (!(network = vshCommandOptNetworkBy(ctl, cmd, NULL, - VSH_BYNAME))) - return false; - - if (virNetworkGetUUIDString(network, uuid) != -1) - vshPrint(ctl, "%s\n", uuid); - else - vshError(ctl, "%s", _("failed to get network UUID")); - - virNetworkFree(network); - return true; -} - - /**************************************************************************/ /* * "iface-list" command @@ -4205,77 +3639,6 @@ cmdEcho(vshControl *ctl, const vshCmd *cmd) } /* - * "net-edit" command - */ -static const vshCmdInfo info_network_edit[] = { - {"help", N_("edit XML configuration for a network")}, - {"desc", N_("Edit the XML configuration for a network.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_network_edit[] = { - {"network", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network name or uuid")}, - {NULL, 0, 0, NULL} -}; - -static char *vshNetworkGetXMLDesc(virNetworkPtr network) -{ - unsigned int flags = VIR_NETWORK_XML_INACTIVE; - char *doc = virNetworkGetXMLDesc(network, flags); - - if (!doc && last_error->code == VIR_ERR_INVALID_ARG) { - /* The server side libvirt doesn't support - * VIR_NETWORK_XML_INACTIVE, so retry without it. - */ - virFreeError(last_error); - last_error = NULL; - flags &= ~VIR_NETWORK_XML_INACTIVE; - doc = virNetworkGetXMLDesc(network, flags); - } - return doc; -} - -static bool -cmdNetworkEdit(vshControl *ctl, const vshCmd *cmd) -{ - bool ret = false; - virNetworkPtr network = NULL; - virNetworkPtr network_edited = NULL; - - if (!vshConnectionUsability(ctl, ctl->conn)) - goto cleanup; - - network = vshCommandOptNetwork(ctl, cmd, NULL); - if (network == NULL) - goto cleanup; - -#define EDIT_GET_XML vshNetworkGetXMLDesc(network) -#define EDIT_NOT_CHANGED \ - vshPrint(ctl, _("Network %s XML configuration not changed.\n"), \ - virNetworkGetName(network)); \ - ret = true; goto edit_cleanup; -#define EDIT_DEFINE \ - (network_edited = virNetworkDefineXML(ctl->conn, doc_edited)) -#define EDIT_FREE \ - if (network_edited) \ - virNetworkFree(network_edited); -#include "virsh-edit.c" - - vshPrint(ctl, _("Network %s XML configuration edited.\n"), - virNetworkGetName(network_edited)); - - ret = true; - - cleanup: - if (network) - virNetworkFree(network); - if (network_edited) - virNetworkFree(network_edited); - - return ret; -} - -/* * "quit" command */ static const vshCmdInfo info_quit[] = { @@ -6712,45 +6075,6 @@ vshCommandOptDomainBy(vshControl *ctl, const vshCmd *cmd, return dom; } -static virNetworkPtr -vshCommandOptNetworkBy(vshControl *ctl, const vshCmd *cmd, - const char **name, int flag) -{ - virNetworkPtr network = NULL; - const char *n = NULL; - const char *optname = "network"; - if (!cmd_has_option(ctl, cmd, optname)) - return NULL; - - if (vshCommandOptString(cmd, optname, &n) <= 0) - return NULL; - - vshDebug(ctl, VSH_ERR_INFO, "%s: found option <%s>: %s\n", - cmd->def->name, optname, n); - - if (name) - *name = n; - - /* try it by UUID */ - if ((flag & VSH_BYUUID) && strlen(n) == VIR_UUID_STRING_BUFLEN-1) { - vshDebug(ctl, VSH_ERR_DEBUG, "%s: <%s> trying as network UUID\n", - cmd->def->name, optname); - network = virNetworkLookupByUUIDString(ctl->conn, n); - } - /* try it by NAME */ - if (network==NULL && (flag & VSH_BYNAME)) { - vshDebug(ctl, VSH_ERR_DEBUG, "%s: <%s> trying as network NAME\n", - cmd->def->name, optname); - network = virNetworkLookupByName(ctl->conn, n); - } - - if (!network) - vshError(ctl, _("failed to get network '%s'"), n); - - return network; -} - - static virNWFilterPtr vshCommandOptNWFilterBy(vshControl *ctl, const vshCmd *cmd, const char **name, int flag) @@ -8349,6 +7673,8 @@ static const vshCmdDef storageVolCmds[] = { {NULL, NULL, NULL, NULL, 0} }; +#include "virsh-network.c" + static const vshCmdDef networkCmds[] = { {"net-autostart", cmdNetworkAutostart, opts_network_autostart, info_network_autostart, 0}, -- 1.7.7.3

On 07/24/2012 11:18 AM, Osier Yang wrote:
Commands to manage network are moved from virsh.c to virsh-network.c, with a few helpers for network command use.
* virsh.c: Remove network commands and a few helpers. * virsh-network.c: New file, filled with network commands its helpers.
s/its/and its/ =) ACK, Martin

Commands to manage host interface are moved from virsh.c to virsh-interface.c, with a few helpers for interface command use. * virsh.c: Remove interface commands and a few helpers. (vshCommandOptInterface, vshCommandOptInterfaceBy) * virsh-interface.c: New file, filled with interface commands its helpers. --- tools/virsh-interface.c | 1000 +++++++++++++++++++++++++++++++++++ tools/virsh.c | 1333 +++++++---------------------------------------- 2 files changed, 1177 insertions(+), 1156 deletions(-) create mode 100644 tools/virsh-interface.c diff --git a/tools/virsh-interface.c b/tools/virsh-interface.c new file mode 100644 index 0000000..6a43bb1 --- /dev/null +++ b/tools/virsh-interface.c @@ -0,0 +1,1000 @@ +/* + * virsh-interface.c: Commands to manage host interface + * + * Copyright (C) 2005, 2007-2012 Red Hat, Inc + * + * 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 + * License along with this library; If not, see + * <http://www.gnu.org/licenses/>. + * + * Daniel Veillard <veillard@redhat.com> + * Karel Zak <kzak@redhat.com> + * Daniel P. Berrange <berrange@redhat.com> + * + */ + +/* default is lookup by Name and MAC */ +#define vshCommandOptInterface(_ctl, _cmd, _name) \ + vshCommandOptInterfaceBy(_ctl, _cmd, NULL, _name, \ + VSH_BYMAC|VSH_BYNAME) + +static virInterfacePtr +vshCommandOptInterfaceBy(vshControl *ctl, const vshCmd *cmd, + const char *optname, + const char **name, int flag) +{ + virInterfacePtr iface = NULL; + const char *n = NULL; + + if (!optname) + optname = "interface"; + if (!cmd_has_option(ctl, cmd, optname)) + return NULL; + + if (vshCommandOptString(cmd, optname, &n) <= 0) + return NULL; + + vshDebug(ctl, VSH_ERR_INFO, "%s: found option <%s>: %s\n", + cmd->def->name, optname, n); + + if (name) + *name = n; + + /* try it by NAME */ + if (flag & VSH_BYNAME) { + vshDebug(ctl, VSH_ERR_DEBUG, "%s: <%s> trying as interface NAME\n", + cmd->def->name, optname); + iface = virInterfaceLookupByName(ctl->conn, n); + } + /* try it by MAC */ + if (iface == NULL && (flag & VSH_BYMAC)) { + vshDebug(ctl, VSH_ERR_DEBUG, "%s: <%s> trying as interface MAC\n", + cmd->def->name, optname); + iface = virInterfaceLookupByMACString(ctl->conn, n); + } + + if (!iface) + vshError(ctl, _("failed to get interface '%s'"), n); + + return iface; +} + +/* + * "iface-edit" command + */ +static const vshCmdInfo info_interface_edit[] = { + {"help", N_("edit XML configuration for a physical host interface")}, + {"desc", N_("Edit the XML configuration for a physical host interface.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_interface_edit[] = { + {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, N_("interface name or MAC address")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdInterfaceEdit(vshControl *ctl, const vshCmd *cmd) +{ + bool ret = false; + virInterfacePtr iface = NULL; + virInterfacePtr iface_edited = NULL; + unsigned int flags = VIR_INTERFACE_XML_INACTIVE; + + if (!vshConnectionUsability(ctl, ctl->conn)) + goto cleanup; + + iface = vshCommandOptInterface(ctl, cmd, NULL); + if (iface == NULL) + goto cleanup; + +#define EDIT_GET_XML virInterfaceGetXMLDesc(iface, flags) +#define EDIT_NOT_CHANGED \ + vshPrint(ctl, _("Interface %s XML configuration not changed.\n"), \ + virInterfaceGetName(iface)); \ + ret = true; goto edit_cleanup; +#define EDIT_DEFINE \ + (iface_edited = virInterfaceDefineXML(ctl->conn, doc_edited, 0)) +#define EDIT_FREE \ + if (iface_edited) \ + virInterfaceFree(iface_edited); +#include "virsh-edit.c" + + vshPrint(ctl, _("Interface %s XML configuration edited.\n"), + virInterfaceGetName(iface_edited)); + + ret = true; + +cleanup: + if (iface) + virInterfaceFree(iface); + if (iface_edited) + virInterfaceFree(iface_edited); + + return ret; +} + +/* + * "iface-list" command + */ +static const vshCmdInfo info_interface_list[] = { + {"help", N_("list physical host interfaces")}, + {"desc", N_("Returns list of physical host interfaces.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_interface_list[] = { + {"inactive", VSH_OT_BOOL, 0, N_("list inactive interfaces")}, + {"all", VSH_OT_BOOL, 0, N_("list inactive & active interfaces")}, + {NULL, 0, 0, NULL} +}; +static bool +cmdInterfaceList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) +{ + bool inactive = vshCommandOptBool(cmd, "inactive"); + bool all = vshCommandOptBool(cmd, "all"); + bool active = !inactive || all; + int maxactive = 0, maxinactive = 0, i; + char **activeNames = NULL, **inactiveNames = NULL; + inactive |= all; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (active) { + maxactive = virConnectNumOfInterfaces(ctl->conn); + if (maxactive < 0) { + vshError(ctl, "%s", _("Failed to list active interfaces")); + return false; + } + if (maxactive) { + activeNames = vshMalloc(ctl, sizeof(char *) * maxactive); + + if ((maxactive = virConnectListInterfaces(ctl->conn, activeNames, + maxactive)) < 0) { + vshError(ctl, "%s", _("Failed to list active interfaces")); + VIR_FREE(activeNames); + return false; + } + + qsort(&activeNames[0], maxactive, sizeof(char *), vshNameSorter); + } + } + if (inactive) { + maxinactive = virConnectNumOfDefinedInterfaces(ctl->conn); + if (maxinactive < 0) { + vshError(ctl, "%s", _("Failed to list inactive interfaces")); + VIR_FREE(activeNames); + return false; + } + if (maxinactive) { + inactiveNames = vshMalloc(ctl, sizeof(char *) * maxinactive); + + if ((maxinactive = + virConnectListDefinedInterfaces(ctl->conn, inactiveNames, + maxinactive)) < 0) { + vshError(ctl, "%s", _("Failed to list inactive interfaces")); + VIR_FREE(activeNames); + VIR_FREE(inactiveNames); + return false; + } + + qsort(&inactiveNames[0], maxinactive, sizeof(char*), vshNameSorter); + } + } + vshPrintExtra(ctl, "%-20s %-10s %s\n", _("Name"), _("State"), + _("MAC Address")); + vshPrintExtra(ctl, "--------------------------------------------\n"); + + for (i = 0; i < maxactive; i++) { + virInterfacePtr iface = + virInterfaceLookupByName(ctl->conn, activeNames[i]); + + /* this kind of work with interfaces is not atomic */ + if (!iface) { + VIR_FREE(activeNames[i]); + continue; + } + + vshPrint(ctl, "%-20s %-10s %s\n", + virInterfaceGetName(iface), + _("active"), + virInterfaceGetMACString(iface)); + virInterfaceFree(iface); + VIR_FREE(activeNames[i]); + } + for (i = 0; i < maxinactive; i++) { + virInterfacePtr iface = + virInterfaceLookupByName(ctl->conn, inactiveNames[i]); + + /* this kind of work with interfaces is not atomic */ + if (!iface) { + VIR_FREE(inactiveNames[i]); + continue; + } + + vshPrint(ctl, "%-20s %-10s %s\n", + virInterfaceGetName(iface), + _("inactive"), + virInterfaceGetMACString(iface)); + virInterfaceFree(iface); + VIR_FREE(inactiveNames[i]); + } + VIR_FREE(activeNames); + VIR_FREE(inactiveNames); + return true; + +} + +/* + * "iface-name" command + */ +static const vshCmdInfo info_interface_name[] = { + {"help", N_("convert an interface MAC address to interface name")}, + {"desc", ""}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_interface_name[] = { + {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, N_("interface mac")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdInterfaceName(vshControl *ctl, const vshCmd *cmd) +{ + virInterfacePtr iface; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + if (!(iface = vshCommandOptInterfaceBy(ctl, cmd, NULL, NULL, + VSH_BYMAC))) + return false; + + vshPrint(ctl, "%s\n", virInterfaceGetName(iface)); + virInterfaceFree(iface); + return true; +} + +/* + * "iface-mac" command + */ +static const vshCmdInfo info_interface_mac[] = { + {"help", N_("convert an interface name to interface MAC address")}, + {"desc", ""}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_interface_mac[] = { + {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, N_("interface name")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdInterfaceMAC(vshControl *ctl, const vshCmd *cmd) +{ + virInterfacePtr iface; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + if (!(iface = vshCommandOptInterfaceBy(ctl, cmd, NULL, NULL, + VSH_BYNAME))) + return false; + + vshPrint(ctl, "%s\n", virInterfaceGetMACString(iface)); + virInterfaceFree(iface); + return true; +} + +/* + * "iface-dumpxml" command + */ +static const vshCmdInfo info_interface_dumpxml[] = { + {"help", N_("interface information in XML")}, + {"desc", N_("Output the physical host interface information as an XML dump to stdout.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_interface_dumpxml[] = { + {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, N_("interface name or MAC address")}, + {"inactive", VSH_OT_BOOL, 0, N_("show inactive defined XML")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdInterfaceDumpXML(vshControl *ctl, const vshCmd *cmd) +{ + virInterfacePtr iface; + bool ret = true; + char *dump; + unsigned int flags = 0; + bool inactive = vshCommandOptBool(cmd, "inactive"); + + if (inactive) + flags |= VIR_INTERFACE_XML_INACTIVE; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(iface = vshCommandOptInterface(ctl, cmd, NULL))) + return false; + + dump = virInterfaceGetXMLDesc(iface, flags); + if (dump != NULL) { + vshPrint(ctl, "%s", dump); + VIR_FREE(dump); + } else { + ret = false; + } + + virInterfaceFree(iface); + return ret; +} + +/* + * "iface-define" command + */ +static const vshCmdInfo info_interface_define[] = { + {"help", N_("define (but don't start) a physical host interface from an XML file")}, + {"desc", N_("Define a physical host interface.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_interface_define[] = { + {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containing an XML interface description")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdInterfaceDefine(vshControl *ctl, const vshCmd *cmd) +{ + virInterfacePtr iface; + const char *from = NULL; + bool ret = true; + char *buffer; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (vshCommandOptString(cmd, "file", &from) <= 0) + return false; + + if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0) + return false; + + iface = virInterfaceDefineXML(ctl->conn, buffer, 0); + VIR_FREE(buffer); + + if (iface != NULL) { + vshPrint(ctl, _("Interface %s defined from %s\n"), + virInterfaceGetName(iface), from); + virInterfaceFree(iface); + } else { + vshError(ctl, _("Failed to define interface from %s"), from); + ret = false; + } + return ret; +} + +/* + * "iface-undefine" command + */ +static const vshCmdInfo info_interface_undefine[] = { + {"help", N_("undefine a physical host interface (remove it from configuration)")}, + {"desc", N_("undefine an interface.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_interface_undefine[] = { + {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, N_("interface name or MAC address")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdInterfaceUndefine(vshControl *ctl, const vshCmd *cmd) +{ + virInterfacePtr iface; + bool ret = true; + const char *name; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(iface = vshCommandOptInterface(ctl, cmd, &name))) + return false; + + if (virInterfaceUndefine(iface) == 0) { + vshPrint(ctl, _("Interface %s undefined\n"), name); + } else { + vshError(ctl, _("Failed to undefine interface %s"), name); + ret = false; + } + + virInterfaceFree(iface); + return ret; +} + +/* + * "iface-start" command + */ +static const vshCmdInfo info_interface_start[] = { + {"help", N_("start a physical host interface (enable it / \"if-up\")")}, + {"desc", N_("start a physical host interface.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_interface_start[] = { + {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, N_("interface name or MAC address")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdInterfaceStart(vshControl *ctl, const vshCmd *cmd) +{ + virInterfacePtr iface; + bool ret = true; + const char *name; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(iface = vshCommandOptInterface(ctl, cmd, &name))) + return false; + + if (virInterfaceCreate(iface, 0) == 0) { + vshPrint(ctl, _("Interface %s started\n"), name); + } else { + vshError(ctl, _("Failed to start interface %s"), name); + ret = false; + } + + virInterfaceFree(iface); + return ret; +} + +/* + * "iface-destroy" command + */ +static const vshCmdInfo info_interface_destroy[] = { + {"help", N_("destroy a physical host interface (disable it / \"if-down\")")}, + {"desc", N_("forcefully stop a physical host interface.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_interface_destroy[] = { + {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, N_("interface name or MAC address")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdInterfaceDestroy(vshControl *ctl, const vshCmd *cmd) +{ + virInterfacePtr iface; + bool ret = true; + const char *name; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(iface = vshCommandOptInterface(ctl, cmd, &name))) + return false; + + if (virInterfaceDestroy(iface, 0) == 0) { + vshPrint(ctl, _("Interface %s destroyed\n"), name); + } else { + vshError(ctl, _("Failed to destroy interface %s"), name); + ret = false; + } + + virInterfaceFree(iface); + return ret; +} + +/* + * "iface-begin" command + */ +static const vshCmdInfo info_interface_begin[] = { + {"help", N_("create a snapshot of current interfaces settings, " + "which can be later committed (iface-commit) or " + "restored (iface-rollback)")}, + {"desc", N_("Create a restore point for interfaces settings")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_interface_begin[] = { + {NULL, 0, 0, NULL} +}; + +static bool +cmdInterfaceBegin(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) +{ + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (virInterfaceChangeBegin(ctl->conn, 0) < 0) { + vshError(ctl, "%s", _("Failed to begin network config change transaction")); + return false; + } + + vshPrint(ctl, "%s", _("Network config change transaction started\n")); + return true; +} + +/* + * "iface-commit" command + */ +static const vshCmdInfo info_interface_commit[] = { + {"help", N_("commit changes made since iface-begin and free restore point")}, + {"desc", N_("commit changes and free restore point")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_interface_commit[] = { + {NULL, 0, 0, NULL} +}; + +static bool +cmdInterfaceCommit(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) +{ + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (virInterfaceChangeCommit(ctl->conn, 0) < 0) { + vshError(ctl, "%s", _("Failed to commit network config change transaction")); + return false; + } + + vshPrint(ctl, "%s", _("Network config change transaction committed\n")); + return true; +} + +/* + * "iface-rollback" command + */ +static const vshCmdInfo info_interface_rollback[] = { + {"help", N_("rollback to previous saved configuration created via iface-begin")}, + {"desc", N_("rollback to previous restore point")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_interface_rollback[] = { + {NULL, 0, 0, NULL} +}; + +static bool +cmdInterfaceRollback(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) +{ + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (virInterfaceChangeRollback(ctl->conn, 0) < 0) { + vshError(ctl, "%s", _("Failed to rollback network config change transaction")); + return false; + } + + vshPrint(ctl, "%s", _("Network config change transaction rolled back\n")); + return true; +} + +/* + * "iface-bridge" command + */ +static const vshCmdInfo info_interface_bridge[] = { + {"help", N_("create a bridge device and attach an existing network device to it")}, + {"desc", N_("bridge an existing network device")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_interface_bridge[] = { + {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, N_("existing interface name")}, + {"bridge", VSH_OT_DATA, VSH_OFLAG_REQ, N_("new bridge device name")}, + {"no-stp", VSH_OT_BOOL, 0, N_("do not enable STP for this bridge")}, + {"delay", VSH_OT_INT, 0, + N_("number of seconds to squelch traffic on newly connected ports")}, + {"no-start", VSH_OT_BOOL, 0, N_("don't start the bridge immediately")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdInterfaceBridge(vshControl *ctl, const vshCmd *cmd) +{ + bool ret = false; + virInterfacePtr if_handle = NULL, br_handle = NULL; + const char *if_name, *br_name; + char *if_type = NULL, *if2_name = NULL, *delay_str = NULL; + bool stp = false, nostart = false; + unsigned int delay = 0; + char *if_xml = NULL; + xmlChar *br_xml = NULL; + int br_xml_size; + xmlDocPtr xml_doc = NULL; + xmlXPathContextPtr ctxt = NULL; + xmlNodePtr top_node, br_node, if_node, cur; + + if (!vshConnectionUsability(ctl, ctl->conn)) + goto cleanup; + + /* Get a handle to the original device */ + if (!(if_handle = vshCommandOptInterfaceBy(ctl, cmd, "interface", + &if_name, VSH_BYNAME))) { + goto cleanup; + } + + /* Name for new bridge device */ + if (vshCommandOptString(cmd, "bridge", &br_name) <= 0) { + vshError(ctl, "%s", _("Missing bridge device name in command")); + goto cleanup; + } + + /* make sure "new" device doesn't already exist */ + if ((br_handle = virInterfaceLookupByName(ctl->conn, br_name))) { + vshError(ctl, _("Network device %s already exists"), br_name); + goto cleanup; + } + + /* use "no-stp" because we want "stp" to default true */ + stp = !vshCommandOptBool(cmd, "no-stp"); + + if (vshCommandOptUInt(cmd, "delay", &delay) < 0) { + vshError(ctl, "%s", _("Unable to parse delay parameter")); + goto cleanup; + } + + nostart = vshCommandOptBool(cmd, "no-start"); + + /* Get the original interface into an xmlDoc */ + if (!(if_xml = virInterfaceGetXMLDesc(if_handle, VIR_INTERFACE_XML_INACTIVE))) + goto cleanup; + if (!(xml_doc = virXMLParseStringCtxt(if_xml, + _("(interface definition)"), &ctxt))) { + vshError(ctl, _("Failed to parse configuration of %s"), if_name); + goto cleanup; + } + top_node = ctxt->node; + + /* Verify that the original device isn't already a bridge. */ + if (!(if_type = virXMLPropString(top_node, "type"))) { + vshError(ctl, _("Existing device %s has no type"), if_name); + goto cleanup; + } + + if (STREQ(if_type, "bridge")) { + vshError(ctl, _("Existing device %s is already a bridge"), if_name); + goto cleanup; + } + + /* verify the name in the XML matches the device name */ + if (!(if2_name = virXMLPropString(top_node, "name")) || + STRNEQ(if2_name, if_name)) { + vshError(ctl, _("Interface name from config %s doesn't match given supplied name %s"), + if2_name, if_name); + goto cleanup; + } + + /* Create a <bridge> node under <interface>. */ + if (!(br_node = xmlNewChild(top_node, NULL, BAD_CAST "bridge", NULL))) { + vshError(ctl, "%s", _("Failed to create bridge node in xml document")); + goto cleanup; + } + + /* Set stp and delay attributes in <bridge> according to the + * commandline options. + */ + if (!xmlSetProp(br_node, BAD_CAST "stp", BAD_CAST (stp ? "on" : "off"))) { + vshError(ctl, "%s", _("Failed to set stp attribute in xml document")); + goto cleanup; + } + + if ((delay || stp) && + ((virAsprintf(&delay_str, "%d", delay) < 0) || + !xmlSetProp(br_node, BAD_CAST "delay", BAD_CAST delay_str))) { + vshError(ctl, _("Failed to set bridge delay %d in xml document"), delay); + goto cleanup; + } + + /* Change the type of the outer/master interface to "bridge" and the + * name to the provided bridge name. + */ + if (!xmlSetProp(top_node, BAD_CAST "type", BAD_CAST "bridge")) { + vshError(ctl, "%s", _("Failed to set bridge interface type to 'bridge' in xml document")); + goto cleanup; + } + + if (!xmlSetProp(top_node, BAD_CAST "name", BAD_CAST br_name)) { + vshError(ctl, _("Failed to set master bridge interface name to '%s' in xml document"), + br_name); + goto cleanup; + } + + /* Create an <interface> node under <bridge> that uses the + * original interface's type and name. + */ + if (!(if_node = xmlNewChild(br_node, NULL, BAD_CAST "interface", NULL))) { + vshError(ctl, "%s", _("Failed to create interface node under bridge node in xml document")); + goto cleanup; + } + + /* set the type of the inner/slave interface to the original + * if_type, and the name to the original if_name. + */ + if (!xmlSetProp(if_node, BAD_CAST "type", BAD_CAST if_type)) { + vshError(ctl, _("Failed to set new slave interface type to '%s' in xml document"), + if_name); + goto cleanup; + } + + if (!xmlSetProp(if_node, BAD_CAST "name", BAD_CAST if_name)) { + vshError(ctl, _("Failed to set new slave interface name to '%s' in xml document"), + br_name); + goto cleanup; + } + + /* Cycle through all the nodes under the original <interface>, + * moving all <mac>, <bond> and <vlan> nodes down into the new + * lower level <interface>. + */ + cur = top_node->children; + while (cur) { + xmlNodePtr old = cur; + + cur = cur->next; + if ((old->type == XML_ELEMENT_NODE) && + (xmlStrEqual(old->name, BAD_CAST "mac") || /* ethernet stuff to move down */ + xmlStrEqual(old->name, BAD_CAST "bond") || /* bond stuff to move down */ + xmlStrEqual(old->name, BAD_CAST "vlan"))) { /* vlan stuff to move down */ + xmlUnlinkNode(old); + if (!xmlAddChild(if_node, old)) { + vshError(ctl, _("Failed to move '%s' element in xml document"), old->name); + xmlFreeNode(old); + goto cleanup; + } + } + } + + /* The document should now be fully converted; write it out to a string. */ + xmlDocDumpMemory(xml_doc, &br_xml, &br_xml_size); + + if (!br_xml || br_xml_size <= 0) { + vshError(ctl, _("Failed to format new xml document for bridge %s"), br_name); + goto cleanup; + } + + + /* br_xml is the new interface to define. It will automatically undefine the + * independent original interface. + */ + if (!(br_handle = virInterfaceDefineXML(ctl->conn, (char *) br_xml, 0))) { + vshError(ctl, _("Failed to define new bridge interface %s"), + br_name); + goto cleanup; + } + + vshPrint(ctl, _("Created bridge %s with attached device %s\n"), + br_name, if_name); + + /* start it up unless requested not to */ + if (!nostart) { + if (virInterfaceCreate(br_handle, 0) < 0) { + vshError(ctl, _("Failed to start bridge interface %s"), br_name); + goto cleanup; + } + vshPrint(ctl, _("Bridge interface %s started\n"), br_name); + } + + ret = true; + cleanup: + if (if_handle) + virInterfaceFree(if_handle); + if (br_handle) + virInterfaceFree(br_handle); + VIR_FREE(if_xml); + VIR_FREE(br_xml); + VIR_FREE(if_type); + VIR_FREE(if2_name); + VIR_FREE(delay_str); + xmlXPathFreeContext(ctxt); + xmlFreeDoc(xml_doc); + return ret; +} + +/* + * "iface-unbridge" command + */ +static const vshCmdInfo info_interface_unbridge[] = { + {"help", N_("undefine a bridge device after detaching its slave device")}, + {"desc", N_("unbridge a network device")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_interface_unbridge[] = { + {"bridge", VSH_OT_DATA, VSH_OFLAG_REQ, N_("current bridge device name")}, + {"no-start", VSH_OT_BOOL, 0, + N_("don't start the un-slaved interface immediately (not recommended)")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdInterfaceUnbridge(vshControl *ctl, const vshCmd *cmd) +{ + bool ret = false; + virInterfacePtr if_handle = NULL, br_handle = NULL; + const char *br_name; + char *if_type = NULL, *if_name = NULL; + bool nostart = false; + char *br_xml = NULL; + xmlChar *if_xml = NULL; + int if_xml_size; + xmlDocPtr xml_doc = NULL; + xmlXPathContextPtr ctxt = NULL; + xmlNodePtr top_node, br_node, if_node, cur; + + if (!vshConnectionUsability(ctl, ctl->conn)) + goto cleanup; + + /* Get a handle to the original device */ + if (!(br_handle = vshCommandOptInterfaceBy(ctl, cmd, "bridge", + &br_name, VSH_BYNAME))) { + goto cleanup; + } + + nostart = vshCommandOptBool(cmd, "no-start"); + + /* Get the bridge xml into an xmlDoc */ + if (!(br_xml = virInterfaceGetXMLDesc(br_handle, VIR_INTERFACE_XML_INACTIVE))) + goto cleanup; + if (!(xml_doc = virXMLParseStringCtxt(br_xml, + _("(bridge interface definition)"), + &ctxt))) { + vshError(ctl, _("Failed to parse configuration of %s"), br_name); + goto cleanup; + } + top_node = ctxt->node; + + /* Verify that the device really is a bridge. */ + if (!(if_type = virXMLPropString(top_node, "type"))) { + vshError(ctl, _("Existing device %s has no type"), br_name); + goto cleanup; + } + + if (STRNEQ(if_type, "bridge")) { + vshError(ctl, _("Device %s is not a bridge"), br_name); + goto cleanup; + } + VIR_FREE(if_type); + + /* verify the name in the XML matches the device name */ + if (!(if_name = virXMLPropString(top_node, "name")) || + STRNEQ(if_name, br_name)) { + vshError(ctl, _("Interface name from config %s doesn't match given supplied name %s"), + if_name, br_name); + goto cleanup; + } + VIR_FREE(if_name); + + /* Find the <bridge> node under <interface>. */ + if (!(br_node = virXPathNode("./bridge", ctxt))) { + vshError(ctl, "%s", _("No bridge node in xml document")); + goto cleanup; + } + + if ((if_node = virXPathNode("./bridge/interface[2]", ctxt))) { + vshError(ctl, "%s", _("Multiple interfaces attached to bridge")); + goto cleanup; + } + + if (!(if_node = virXPathNode("./bridge/interface", ctxt))) { + vshError(ctl, "%s", _("No interface attached to bridge")); + goto cleanup; + } + + /* Change the type and name of the outer/master interface to + * the type/name of the attached slave interface. + */ + if (!(if_name = virXMLPropString(if_node, "name"))) { + vshError(ctl, _("Device attached to bridge %s has no name"), br_name); + goto cleanup; + } + + if (!(if_type = virXMLPropString(if_node, "type"))) { + vshError(ctl, _("Attached device %s has no type"), if_name); + goto cleanup; + } + + if (!xmlSetProp(top_node, BAD_CAST "type", BAD_CAST if_type)) { + vshError(ctl, _("Failed to set interface type to '%s' in xml document"), + if_type); + goto cleanup; + } + + if (!xmlSetProp(top_node, BAD_CAST "name", BAD_CAST if_name)) { + vshError(ctl, _("Failed to set interface name to '%s' in xml document"), + if_name); + goto cleanup; + } + + /* Cycle through all the nodes under the attached <interface>, + * moving all <mac>, <bond> and <vlan> nodes up into the toplevel + * <interface>. + */ + cur = if_node->children; + while (cur) { + xmlNodePtr old = cur; + + cur = cur->next; + if ((old->type == XML_ELEMENT_NODE) && + (xmlStrEqual(old->name, BAD_CAST "mac") || /* ethernet stuff to move down */ + xmlStrEqual(old->name, BAD_CAST "bond") || /* bond stuff to move down */ + xmlStrEqual(old->name, BAD_CAST "vlan"))) { /* vlan stuff to move down */ + xmlUnlinkNode(old); + if (!xmlAddChild(top_node, old)) { + vshError(ctl, _("Failed to move '%s' element in xml document"), old->name); + xmlFreeNode(old); + goto cleanup; + } + } + } + + /* The document should now be fully converted; write it out to a string. */ + xmlDocDumpMemory(xml_doc, &if_xml, &if_xml_size); + + if (!if_xml || if_xml_size <= 0) { + vshError(ctl, _("Failed to format new xml document for un-enslaved interface %s"), + if_name); + goto cleanup; + } + + /* Destroy and Undefine the bridge device, since we otherwise + * can't safely define the unattached device. + */ + if (virInterfaceDestroy(br_handle, 0) < 0) { + vshError(ctl, _("Failed to destroy bridge interface %s"), br_name); + goto cleanup; + } + if (virInterfaceUndefine(br_handle) < 0) { + vshError(ctl, _("Failed to undefine bridge interface %s"), br_name); + goto cleanup; + } + + /* if_xml is the new interface to define. + */ + if (!(if_handle = virInterfaceDefineXML(ctl->conn, (char *) if_xml, 0))) { + vshError(ctl, _("Failed to define new interface %s"), if_name); + goto cleanup; + } + + vshPrint(ctl, _("Device %s un-attached from bridge %s\n"), + if_name, br_name); + + /* unless requested otherwise, undefine the bridge device */ + if (!nostart) { + if (virInterfaceCreate(if_handle, 0) < 0) { + vshError(ctl, _("Failed to start interface %s"), if_name); + goto cleanup; + } + vshPrint(ctl, _("Interface %s started\n"), if_name); + } + + ret = true; + cleanup: + if (if_handle) + virInterfaceFree(if_handle); + if (br_handle) + virInterfaceFree(br_handle); + VIR_FREE(if_xml); + VIR_FREE(br_xml); + VIR_FREE(if_type); + VIR_FREE(if_name); + xmlXPathFreeContext(ctxt); + xmlFreeDoc(xml_doc); + return ret; +} diff --git a/tools/virsh.c b/tools/virsh.c index 220aa1d..23b2ec9 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -347,15 +347,6 @@ static virNWFilterPtr vshCommandOptNWFilterBy(vshControl *ctl, const vshCmd *cmd vshCommandOptNWFilterBy(_ctl, _cmd, _name, \ VSH_BYUUID|VSH_BYNAME) -static virInterfacePtr vshCommandOptInterfaceBy(vshControl *ctl, const vshCmd *cmd, - const char *optname, - const char **name, int flag); - -/* default is lookup by Name and MAC */ -#define vshCommandOptInterface(_ctl, _cmd, _name) \ - vshCommandOptInterfaceBy(_ctl, _cmd, NULL, _name, \ - VSH_BYMAC|VSH_BYNAME) - static virSecretPtr vshCommandOptSecret(vshControl *ctl, const vshCmd *cmd, const char **name); @@ -1019,1180 +1010,249 @@ cmdNodeCpuStats(vshControl *ctl, const vshCmd *cmd) if (vshCommandOptInt(cmd, "cpu", &cpuNum) < 0) { vshError(ctl, "%s", _("Invalid value of cpuNum")); - return false; - } - - if (virNodeGetCPUStats(ctl->conn, cpuNum, NULL, &nparams, 0) != 0) { - vshError(ctl, "%s", - _("Unable to get number of cpu stats")); - return false; - } - if (nparams == 0) { - /* nothing to output */ - return true; - } - - memset(cpu_stats, 0, sizeof(cpu_stats)); - params = vshCalloc(ctl, nparams, sizeof(*params)); - - for (i = 0; i < 2; i++) { - if (i > 0) - sleep(1); - - if (virNodeGetCPUStats(ctl->conn, cpuNum, params, &nparams, 0) != 0) { - vshError(ctl, "%s", _("Unable to get node cpu stats")); - goto cleanup; - } - - for (j = 0; j < nparams; j++) { - unsigned long long value = params[j].value; - - if (STREQ(params[j].field, VIR_NODE_CPU_STATS_KERNEL)) { - cpu_stats[i].sys = value; - } else if (STREQ(params[j].field, VIR_NODE_CPU_STATS_USER)) { - cpu_stats[i].user = value; - } else if (STREQ(params[j].field, VIR_NODE_CPU_STATS_IDLE)) { - cpu_stats[i].idle = value; - } else if (STREQ(params[j].field, VIR_NODE_CPU_STATS_IOWAIT)) { - cpu_stats[i].iowait = value; - } else if (STREQ(params[j].field, VIR_NODE_CPU_STATS_UTILIZATION)) { - cpu_stats[i].util = value; - flag_utilization = true; - } - } - - if (flag_utilization || !flag_percent) - break; - } - - if (!flag_percent) { - if (!flag_utilization) { - vshPrint(ctl, "%-15s %20llu\n", _("user:"), cpu_stats[0].user); - vshPrint(ctl, "%-15s %20llu\n", _("system:"), cpu_stats[0].sys); - vshPrint(ctl, "%-15s %20llu\n", _("idle:"), cpu_stats[0].idle); - vshPrint(ctl, "%-15s %20llu\n", _("iowait:"), cpu_stats[0].iowait); - } - } else { - if (flag_utilization) { - usage = cpu_stats[0].util; - - vshPrint(ctl, "%-15s %5.1lf%%\n", _("usage:"), usage); - vshPrint(ctl, "%-15s %5.1lf%%\n", _("idle:"), 100 - usage); - } else { - user_time = cpu_stats[1].user - cpu_stats[0].user; - sys_time = cpu_stats[1].sys - cpu_stats[0].sys; - idle_time = cpu_stats[1].idle - cpu_stats[0].idle; - iowait_time = cpu_stats[1].iowait - cpu_stats[0].iowait; - total_time = user_time + sys_time + idle_time + iowait_time; - - usage = (user_time + sys_time) / total_time * 100; - - vshPrint(ctl, "%-15s %5.1lf%%\n", - _("usage:"), usage); - vshPrint(ctl, "%-15s %5.1lf%%\n", - _("user:"), user_time / total_time * 100); - vshPrint(ctl, "%-15s %5.1lf%%\n", - _("system:"), sys_time / total_time * 100); - vshPrint(ctl, "%-15s %5.1lf%%\n", - _("idle:"), idle_time / total_time * 100); - vshPrint(ctl, "%-15s %5.1lf%%\n", - _("iowait:"), iowait_time / total_time * 100); - } - } - - ret = true; - - cleanup: - VIR_FREE(params); - return ret; -} - -/* - * "nodememstats" command - */ -static const vshCmdInfo info_nodememstats[] = { - {"help", N_("Prints memory stats of the node.")}, - {"desc", N_("Returns memory stats of the node, in kilobytes.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_node_memstats[] = { - {"cell", VSH_OT_INT, 0, N_("prints specified cell statistics only.")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdNodeMemStats(vshControl *ctl, const vshCmd *cmd) -{ - int nparams = 0; - unsigned int i = 0; - int cellNum = VIR_NODE_MEMORY_STATS_ALL_CELLS; - virNodeMemoryStatsPtr params = NULL; - bool ret = false; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (vshCommandOptInt(cmd, "cell", &cellNum) < 0) { - vshError(ctl, "%s", _("Invalid value of cellNum")); - return false; - } - - /* get the number of memory parameters */ - if (virNodeGetMemoryStats(ctl->conn, cellNum, NULL, &nparams, 0) != 0) { - vshError(ctl, "%s", - _("Unable to get number of memory stats")); - goto cleanup; - } - - if (nparams == 0) { - /* nothing to output */ - ret = true; - goto cleanup; - } - - /* now go get all the memory parameters */ - params = vshCalloc(ctl, nparams, sizeof(*params)); - if (virNodeGetMemoryStats(ctl->conn, cellNum, params, &nparams, 0) != 0) { - vshError(ctl, "%s", _("Unable to get memory stats")); - goto cleanup; - } - - for (i = 0; i < nparams; i++) - vshPrint(ctl, "%-7s: %20llu KiB\n", params[i].field, params[i].value); - - ret = true; - - cleanup: - VIR_FREE(params); - return ret; -} - -/* - * "nodesuspend" command - */ -static const vshCmdInfo info_nodesuspend[] = { - {"help", N_("suspend the host node for a given time duration")}, - {"desc", N_("Suspend the host node for a given time duration " - "and attempt to resume thereafter.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_node_suspend[] = { - {"target", VSH_OT_DATA, VSH_OFLAG_REQ, N_("mem(Suspend-to-RAM), " - "disk(Suspend-to-Disk), hybrid(Hybrid-Suspend)")}, - {"duration", VSH_OT_INT, VSH_OFLAG_REQ, N_("Suspend duration in seconds")}, - {"flags", VSH_OT_INT, VSH_OFLAG_NONE, N_("Suspend flags, 0 for default")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdNodeSuspend(vshControl *ctl, const vshCmd *cmd) -{ - const char *target = NULL; - unsigned int suspendTarget; - long long duration; - unsigned int flags = 0; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (vshCommandOptString(cmd, "target", &target) < 0) { - vshError(ctl, _("Invalid target argument")); - return false; - } - - if (vshCommandOptLongLong(cmd, "duration", &duration) < 0) { - vshError(ctl, _("Invalid duration argument")); - return false; - } - - if (vshCommandOptUInt(cmd, "flags", &flags) < 0) { - vshError(ctl, _("Invalid flags argument")); - return false; - } - - if (STREQ(target, "mem")) - suspendTarget = VIR_NODE_SUSPEND_TARGET_MEM; - else if (STREQ(target, "disk")) - suspendTarget = VIR_NODE_SUSPEND_TARGET_DISK; - else if (STREQ(target, "hybrid")) - suspendTarget = VIR_NODE_SUSPEND_TARGET_HYBRID; - else { - vshError(ctl, "%s", _("Invalid target")); - return false; - } - - if (duration <= 0) { - vshError(ctl, "%s", _("Invalid duration")); - return false; - } - - if (virNodeSuspendForDuration(ctl->conn, suspendTarget, duration, - flags) < 0) { - vshError(ctl, "%s", _("The host was not suspended")); - return false; - } - return true; -} - - -/* - * "capabilities" command - */ -static const vshCmdInfo info_capabilities[] = { - {"help", N_("capabilities")}, - {"desc", N_("Returns capabilities of hypervisor/driver.")}, - {NULL, NULL} -}; - -static bool -cmdCapabilities(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) -{ - char *caps; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if ((caps = virConnectGetCapabilities(ctl->conn)) == NULL) { - vshError(ctl, "%s", _("failed to get capabilities")); - return false; - } - vshPrint(ctl, "%s\n", caps); - VIR_FREE(caps); - - return true; -} - -/* - * "iface-edit" command - */ -static const vshCmdInfo info_interface_edit[] = { - {"help", N_("edit XML configuration for a physical host interface")}, - {"desc", N_("Edit the XML configuration for a physical host interface.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_interface_edit[] = { - {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, N_("interface name or MAC address")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdInterfaceEdit(vshControl *ctl, const vshCmd *cmd) -{ - bool ret = false; - virInterfacePtr iface = NULL; - virInterfacePtr iface_edited = NULL; - unsigned int flags = VIR_INTERFACE_XML_INACTIVE; - - if (!vshConnectionUsability(ctl, ctl->conn)) - goto cleanup; - - iface = vshCommandOptInterface(ctl, cmd, NULL); - if (iface == NULL) - goto cleanup; - -#define EDIT_GET_XML virInterfaceGetXMLDesc(iface, flags) -#define EDIT_NOT_CHANGED \ - vshPrint(ctl, _("Interface %s XML configuration not changed.\n"), \ - virInterfaceGetName(iface)); \ - ret = true; goto edit_cleanup; -#define EDIT_DEFINE \ - (iface_edited = virInterfaceDefineXML(ctl->conn, doc_edited, 0)) -#define EDIT_FREE \ - if (iface_edited) \ - virInterfaceFree(iface_edited); -#include "virsh-edit.c" - - vshPrint(ctl, _("Interface %s XML configuration edited.\n"), - virInterfaceGetName(iface_edited)); - - ret = true; - -cleanup: - if (iface) - virInterfaceFree(iface); - if (iface_edited) - virInterfaceFree(iface_edited); - - return ret; -} - -/**************************************************************************/ -/* - * "iface-list" command - */ -static const vshCmdInfo info_interface_list[] = { - {"help", N_("list physical host interfaces")}, - {"desc", N_("Returns list of physical host interfaces.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_interface_list[] = { - {"inactive", VSH_OT_BOOL, 0, N_("list inactive interfaces")}, - {"all", VSH_OT_BOOL, 0, N_("list inactive & active interfaces")}, - {NULL, 0, 0, NULL} -}; -static bool -cmdInterfaceList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) -{ - bool inactive = vshCommandOptBool(cmd, "inactive"); - bool all = vshCommandOptBool(cmd, "all"); - bool active = !inactive || all; - int maxactive = 0, maxinactive = 0, i; - char **activeNames = NULL, **inactiveNames = NULL; - inactive |= all; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (active) { - maxactive = virConnectNumOfInterfaces(ctl->conn); - if (maxactive < 0) { - vshError(ctl, "%s", _("Failed to list active interfaces")); - return false; - } - if (maxactive) { - activeNames = vshMalloc(ctl, sizeof(char *) * maxactive); - - if ((maxactive = virConnectListInterfaces(ctl->conn, activeNames, - maxactive)) < 0) { - vshError(ctl, "%s", _("Failed to list active interfaces")); - VIR_FREE(activeNames); - return false; - } - - qsort(&activeNames[0], maxactive, sizeof(char *), vshNameSorter); - } - } - if (inactive) { - maxinactive = virConnectNumOfDefinedInterfaces(ctl->conn); - if (maxinactive < 0) { - vshError(ctl, "%s", _("Failed to list inactive interfaces")); - VIR_FREE(activeNames); - return false; - } - if (maxinactive) { - inactiveNames = vshMalloc(ctl, sizeof(char *) * maxinactive); - - if ((maxinactive = - virConnectListDefinedInterfaces(ctl->conn, inactiveNames, - maxinactive)) < 0) { - vshError(ctl, "%s", _("Failed to list inactive interfaces")); - VIR_FREE(activeNames); - VIR_FREE(inactiveNames); - return false; - } - - qsort(&inactiveNames[0], maxinactive, sizeof(char*), vshNameSorter); - } - } - vshPrintExtra(ctl, "%-20s %-10s %s\n", _("Name"), _("State"), - _("MAC Address")); - vshPrintExtra(ctl, "--------------------------------------------\n"); - - for (i = 0; i < maxactive; i++) { - virInterfacePtr iface = - virInterfaceLookupByName(ctl->conn, activeNames[i]); - - /* this kind of work with interfaces is not atomic */ - if (!iface) { - VIR_FREE(activeNames[i]); - continue; - } - - vshPrint(ctl, "%-20s %-10s %s\n", - virInterfaceGetName(iface), - _("active"), - virInterfaceGetMACString(iface)); - virInterfaceFree(iface); - VIR_FREE(activeNames[i]); - } - for (i = 0; i < maxinactive; i++) { - virInterfacePtr iface = - virInterfaceLookupByName(ctl->conn, inactiveNames[i]); - - /* this kind of work with interfaces is not atomic */ - if (!iface) { - VIR_FREE(inactiveNames[i]); - continue; - } - - vshPrint(ctl, "%-20s %-10s %s\n", - virInterfaceGetName(iface), - _("inactive"), - virInterfaceGetMACString(iface)); - virInterfaceFree(iface); - VIR_FREE(inactiveNames[i]); - } - VIR_FREE(activeNames); - VIR_FREE(inactiveNames); - return true; - -} - -/* - * "iface-name" command - */ -static const vshCmdInfo info_interface_name[] = { - {"help", N_("convert an interface MAC address to interface name")}, - {"desc", ""}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_interface_name[] = { - {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, N_("interface mac")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdInterfaceName(vshControl *ctl, const vshCmd *cmd) -{ - virInterfacePtr iface; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - if (!(iface = vshCommandOptInterfaceBy(ctl, cmd, NULL, NULL, - VSH_BYMAC))) - return false; - - vshPrint(ctl, "%s\n", virInterfaceGetName(iface)); - virInterfaceFree(iface); - return true; -} - -/* - * "iface-mac" command - */ -static const vshCmdInfo info_interface_mac[] = { - {"help", N_("convert an interface name to interface MAC address")}, - {"desc", ""}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_interface_mac[] = { - {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, N_("interface name")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdInterfaceMAC(vshControl *ctl, const vshCmd *cmd) -{ - virInterfacePtr iface; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - if (!(iface = vshCommandOptInterfaceBy(ctl, cmd, NULL, NULL, - VSH_BYNAME))) - return false; - - vshPrint(ctl, "%s\n", virInterfaceGetMACString(iface)); - virInterfaceFree(iface); - return true; -} - -/* - * "iface-dumpxml" command - */ -static const vshCmdInfo info_interface_dumpxml[] = { - {"help", N_("interface information in XML")}, - {"desc", N_("Output the physical host interface information as an XML dump to stdout.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_interface_dumpxml[] = { - {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, N_("interface name or MAC address")}, - {"inactive", VSH_OT_BOOL, 0, N_("show inactive defined XML")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdInterfaceDumpXML(vshControl *ctl, const vshCmd *cmd) -{ - virInterfacePtr iface; - bool ret = true; - char *dump; - unsigned int flags = 0; - bool inactive = vshCommandOptBool(cmd, "inactive"); - - if (inactive) - flags |= VIR_INTERFACE_XML_INACTIVE; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (!(iface = vshCommandOptInterface(ctl, cmd, NULL))) - return false; - - dump = virInterfaceGetXMLDesc(iface, flags); - if (dump != NULL) { - vshPrint(ctl, "%s", dump); - VIR_FREE(dump); - } else { - ret = false; - } - - virInterfaceFree(iface); - return ret; -} - -/* - * "iface-define" command - */ -static const vshCmdInfo info_interface_define[] = { - {"help", N_("define (but don't start) a physical host interface from an XML file")}, - {"desc", N_("Define a physical host interface.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_interface_define[] = { - {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containing an XML interface description")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdInterfaceDefine(vshControl *ctl, const vshCmd *cmd) -{ - virInterfacePtr iface; - const char *from = NULL; - bool ret = true; - char *buffer; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (vshCommandOptString(cmd, "file", &from) <= 0) - return false; - - if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0) - return false; - - iface = virInterfaceDefineXML(ctl->conn, buffer, 0); - VIR_FREE(buffer); - - if (iface != NULL) { - vshPrint(ctl, _("Interface %s defined from %s\n"), - virInterfaceGetName(iface), from); - virInterfaceFree(iface); - } else { - vshError(ctl, _("Failed to define interface from %s"), from); - ret = false; - } - return ret; -} - -/* - * "iface-undefine" command - */ -static const vshCmdInfo info_interface_undefine[] = { - {"help", N_("undefine a physical host interface (remove it from configuration)")}, - {"desc", N_("undefine an interface.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_interface_undefine[] = { - {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, N_("interface name or MAC address")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdInterfaceUndefine(vshControl *ctl, const vshCmd *cmd) -{ - virInterfacePtr iface; - bool ret = true; - const char *name; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (!(iface = vshCommandOptInterface(ctl, cmd, &name))) - return false; - - if (virInterfaceUndefine(iface) == 0) { - vshPrint(ctl, _("Interface %s undefined\n"), name); - } else { - vshError(ctl, _("Failed to undefine interface %s"), name); - ret = false; - } - - virInterfaceFree(iface); - return ret; -} - -/* - * "iface-start" command - */ -static const vshCmdInfo info_interface_start[] = { - {"help", N_("start a physical host interface (enable it / \"if-up\")")}, - {"desc", N_("start a physical host interface.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_interface_start[] = { - {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, N_("interface name or MAC address")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdInterfaceStart(vshControl *ctl, const vshCmd *cmd) -{ - virInterfacePtr iface; - bool ret = true; - const char *name; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (!(iface = vshCommandOptInterface(ctl, cmd, &name))) - return false; - - if (virInterfaceCreate(iface, 0) == 0) { - vshPrint(ctl, _("Interface %s started\n"), name); - } else { - vshError(ctl, _("Failed to start interface %s"), name); - ret = false; - } - - virInterfaceFree(iface); - return ret; -} - -/* - * "iface-destroy" command - */ -static const vshCmdInfo info_interface_destroy[] = { - {"help", N_("destroy a physical host interface (disable it / \"if-down\")")}, - {"desc", N_("forcefully stop a physical host interface.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_interface_destroy[] = { - {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, N_("interface name or MAC address")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdInterfaceDestroy(vshControl *ctl, const vshCmd *cmd) -{ - virInterfacePtr iface; - bool ret = true; - const char *name; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (!(iface = vshCommandOptInterface(ctl, cmd, &name))) - return false; - - if (virInterfaceDestroy(iface, 0) == 0) { - vshPrint(ctl, _("Interface %s destroyed\n"), name); - } else { - vshError(ctl, _("Failed to destroy interface %s"), name); - ret = false; - } - - virInterfaceFree(iface); - return ret; -} - -/* - * "iface-begin" command - */ -static const vshCmdInfo info_interface_begin[] = { - {"help", N_("create a snapshot of current interfaces settings, " - "which can be later committed (iface-commit) or " - "restored (iface-rollback)")}, - {"desc", N_("Create a restore point for interfaces settings")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_interface_begin[] = { - {NULL, 0, 0, NULL} -}; - -static bool -cmdInterfaceBegin(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) -{ - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (virInterfaceChangeBegin(ctl->conn, 0) < 0) { - vshError(ctl, "%s", _("Failed to begin network config change transaction")); - return false; - } - - vshPrint(ctl, "%s", _("Network config change transaction started\n")); - return true; -} - -/* - * "iface-commit" command - */ -static const vshCmdInfo info_interface_commit[] = { - {"help", N_("commit changes made since iface-begin and free restore point")}, - {"desc", N_("commit changes and free restore point")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_interface_commit[] = { - {NULL, 0, 0, NULL} -}; - -static bool -cmdInterfaceCommit(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) -{ - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (virInterfaceChangeCommit(ctl->conn, 0) < 0) { - vshError(ctl, "%s", _("Failed to commit network config change transaction")); - return false; - } - - vshPrint(ctl, "%s", _("Network config change transaction committed\n")); - return true; -} - -/* - * "iface-rollback" command - */ -static const vshCmdInfo info_interface_rollback[] = { - {"help", N_("rollback to previous saved configuration created via iface-begin")}, - {"desc", N_("rollback to previous restore point")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_interface_rollback[] = { - {NULL, 0, 0, NULL} -}; - -static bool -cmdInterfaceRollback(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) -{ - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (virInterfaceChangeRollback(ctl->conn, 0) < 0) { - vshError(ctl, "%s", _("Failed to rollback network config change transaction")); - return false; - } - - vshPrint(ctl, "%s", _("Network config change transaction rolled back\n")); - return true; -} - -/* - * "iface-bridge" command - */ -static const vshCmdInfo info_interface_bridge[] = { - {"help", N_("create a bridge device and attach an existing network device to it")}, - {"desc", N_("bridge an existing network device")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_interface_bridge[] = { - {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, N_("existing interface name")}, - {"bridge", VSH_OT_DATA, VSH_OFLAG_REQ, N_("new bridge device name")}, - {"no-stp", VSH_OT_BOOL, 0, N_("do not enable STP for this bridge")}, - {"delay", VSH_OT_INT, 0, - N_("number of seconds to squelch traffic on newly connected ports")}, - {"no-start", VSH_OT_BOOL, 0, N_("don't start the bridge immediately")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdInterfaceBridge(vshControl *ctl, const vshCmd *cmd) -{ - bool ret = false; - virInterfacePtr if_handle = NULL, br_handle = NULL; - const char *if_name, *br_name; - char *if_type = NULL, *if2_name = NULL, *delay_str = NULL; - bool stp = false, nostart = false; - unsigned int delay = 0; - char *if_xml = NULL; - xmlChar *br_xml = NULL; - int br_xml_size; - xmlDocPtr xml_doc = NULL; - xmlXPathContextPtr ctxt = NULL; - xmlNodePtr top_node, br_node, if_node, cur; - - if (!vshConnectionUsability(ctl, ctl->conn)) - goto cleanup; - - /* Get a handle to the original device */ - if (!(if_handle = vshCommandOptInterfaceBy(ctl, cmd, "interface", - &if_name, VSH_BYNAME))) { - goto cleanup; - } - - /* Name for new bridge device */ - if (vshCommandOptString(cmd, "bridge", &br_name) <= 0) { - vshError(ctl, "%s", _("Missing bridge device name in command")); - goto cleanup; - } - - /* make sure "new" device doesn't already exist */ - if ((br_handle = virInterfaceLookupByName(ctl->conn, br_name))) { - vshError(ctl, _("Network device %s already exists"), br_name); - goto cleanup; - } - - /* use "no-stp" because we want "stp" to default true */ - stp = !vshCommandOptBool(cmd, "no-stp"); - - if (vshCommandOptUInt(cmd, "delay", &delay) < 0) { - vshError(ctl, "%s", _("Unable to parse delay parameter")); - goto cleanup; - } - - nostart = vshCommandOptBool(cmd, "no-start"); - - /* Get the original interface into an xmlDoc */ - if (!(if_xml = virInterfaceGetXMLDesc(if_handle, VIR_INTERFACE_XML_INACTIVE))) - goto cleanup; - if (!(xml_doc = virXMLParseStringCtxt(if_xml, - _("(interface definition)"), &ctxt))) { - vshError(ctl, _("Failed to parse configuration of %s"), if_name); - goto cleanup; - } - top_node = ctxt->node; - - /* Verify that the original device isn't already a bridge. */ - if (!(if_type = virXMLPropString(top_node, "type"))) { - vshError(ctl, _("Existing device %s has no type"), if_name); - goto cleanup; - } - - if (STREQ(if_type, "bridge")) { - vshError(ctl, _("Existing device %s is already a bridge"), if_name); - goto cleanup; - } - - /* verify the name in the XML matches the device name */ - if (!(if2_name = virXMLPropString(top_node, "name")) || - STRNEQ(if2_name, if_name)) { - vshError(ctl, _("Interface name from config %s doesn't match given supplied name %s"), - if2_name, if_name); - goto cleanup; - } - - /* Create a <bridge> node under <interface>. */ - if (!(br_node = xmlNewChild(top_node, NULL, BAD_CAST "bridge", NULL))) { - vshError(ctl, "%s", _("Failed to create bridge node in xml document")); - goto cleanup; - } - - /* Set stp and delay attributes in <bridge> according to the - * commandline options. - */ - if (!xmlSetProp(br_node, BAD_CAST "stp", BAD_CAST (stp ? "on" : "off"))) { - vshError(ctl, "%s", _("Failed to set stp attribute in xml document")); - goto cleanup; - } - - if ((delay || stp) && - ((virAsprintf(&delay_str, "%d", delay) < 0) || - !xmlSetProp(br_node, BAD_CAST "delay", BAD_CAST delay_str))) { - vshError(ctl, _("Failed to set bridge delay %d in xml document"), delay); - goto cleanup; - } - - /* Change the type of the outer/master interface to "bridge" and the - * name to the provided bridge name. - */ - if (!xmlSetProp(top_node, BAD_CAST "type", BAD_CAST "bridge")) { - vshError(ctl, "%s", _("Failed to set bridge interface type to 'bridge' in xml document")); - goto cleanup; + return false; } - if (!xmlSetProp(top_node, BAD_CAST "name", BAD_CAST br_name)) { - vshError(ctl, _("Failed to set master bridge interface name to '%s' in xml document"), - br_name); - goto cleanup; + if (virNodeGetCPUStats(ctl->conn, cpuNum, NULL, &nparams, 0) != 0) { + vshError(ctl, "%s", + _("Unable to get number of cpu stats")); + return false; } - - /* Create an <interface> node under <bridge> that uses the - * original interface's type and name. - */ - if (!(if_node = xmlNewChild(br_node, NULL, BAD_CAST "interface", NULL))) { - vshError(ctl, "%s", _("Failed to create interface node under bridge node in xml document")); - goto cleanup; + if (nparams == 0) { + /* nothing to output */ + return true; } - /* set the type of the inner/slave interface to the original - * if_type, and the name to the original if_name. - */ - if (!xmlSetProp(if_node, BAD_CAST "type", BAD_CAST if_type)) { - vshError(ctl, _("Failed to set new slave interface type to '%s' in xml document"), - if_name); - goto cleanup; - } + memset(cpu_stats, 0, sizeof(cpu_stats)); + params = vshCalloc(ctl, nparams, sizeof(*params)); - if (!xmlSetProp(if_node, BAD_CAST "name", BAD_CAST if_name)) { - vshError(ctl, _("Failed to set new slave interface name to '%s' in xml document"), - br_name); - goto cleanup; - } + for (i = 0; i < 2; i++) { + if (i > 0) + sleep(1); - /* Cycle through all the nodes under the original <interface>, - * moving all <mac>, <bond> and <vlan> nodes down into the new - * lower level <interface>. - */ - cur = top_node->children; - while (cur) { - xmlNodePtr old = cur; - - cur = cur->next; - if ((old->type == XML_ELEMENT_NODE) && - (xmlStrEqual(old->name, BAD_CAST "mac") || /* ethernet stuff to move down */ - xmlStrEqual(old->name, BAD_CAST "bond") || /* bond stuff to move down */ - xmlStrEqual(old->name, BAD_CAST "vlan"))) { /* vlan stuff to move down */ - xmlUnlinkNode(old); - if (!xmlAddChild(if_node, old)) { - vshError(ctl, _("Failed to move '%s' element in xml document"), old->name); - xmlFreeNode(old); - goto cleanup; - } + if (virNodeGetCPUStats(ctl->conn, cpuNum, params, &nparams, 0) != 0) { + vshError(ctl, "%s", _("Unable to get node cpu stats")); + goto cleanup; } - } - /* The document should now be fully converted; write it out to a string. */ - xmlDocDumpMemory(xml_doc, &br_xml, &br_xml_size); + for (j = 0; j < nparams; j++) { + unsigned long long value = params[j].value; - if (!br_xml || br_xml_size <= 0) { - vshError(ctl, _("Failed to format new xml document for bridge %s"), br_name); - goto cleanup; + if (STREQ(params[j].field, VIR_NODE_CPU_STATS_KERNEL)) { + cpu_stats[i].sys = value; + } else if (STREQ(params[j].field, VIR_NODE_CPU_STATS_USER)) { + cpu_stats[i].user = value; + } else if (STREQ(params[j].field, VIR_NODE_CPU_STATS_IDLE)) { + cpu_stats[i].idle = value; + } else if (STREQ(params[j].field, VIR_NODE_CPU_STATS_IOWAIT)) { + cpu_stats[i].iowait = value; + } else if (STREQ(params[j].field, VIR_NODE_CPU_STATS_UTILIZATION)) { + cpu_stats[i].util = value; + flag_utilization = true; + } + } + + if (flag_utilization || !flag_percent) + break; } + if (!flag_percent) { + if (!flag_utilization) { + vshPrint(ctl, "%-15s %20llu\n", _("user:"), cpu_stats[0].user); + vshPrint(ctl, "%-15s %20llu\n", _("system:"), cpu_stats[0].sys); + vshPrint(ctl, "%-15s %20llu\n", _("idle:"), cpu_stats[0].idle); + vshPrint(ctl, "%-15s %20llu\n", _("iowait:"), cpu_stats[0].iowait); + } + } else { + if (flag_utilization) { + usage = cpu_stats[0].util; - /* br_xml is the new interface to define. It will automatically undefine the - * independent original interface. - */ - if (!(br_handle = virInterfaceDefineXML(ctl->conn, (char *) br_xml, 0))) { - vshError(ctl, _("Failed to define new bridge interface %s"), - br_name); - goto cleanup; - } + vshPrint(ctl, "%-15s %5.1lf%%\n", _("usage:"), usage); + vshPrint(ctl, "%-15s %5.1lf%%\n", _("idle:"), 100 - usage); + } else { + user_time = cpu_stats[1].user - cpu_stats[0].user; + sys_time = cpu_stats[1].sys - cpu_stats[0].sys; + idle_time = cpu_stats[1].idle - cpu_stats[0].idle; + iowait_time = cpu_stats[1].iowait - cpu_stats[0].iowait; + total_time = user_time + sys_time + idle_time + iowait_time; - vshPrint(ctl, _("Created bridge %s with attached device %s\n"), - br_name, if_name); + usage = (user_time + sys_time) / total_time * 100; - /* start it up unless requested not to */ - if (!nostart) { - if (virInterfaceCreate(br_handle, 0) < 0) { - vshError(ctl, _("Failed to start bridge interface %s"), br_name); - goto cleanup; + vshPrint(ctl, "%-15s %5.1lf%%\n", + _("usage:"), usage); + vshPrint(ctl, "%-15s %5.1lf%%\n", + _("user:"), user_time / total_time * 100); + vshPrint(ctl, "%-15s %5.1lf%%\n", + _("system:"), sys_time / total_time * 100); + vshPrint(ctl, "%-15s %5.1lf%%\n", + _("idle:"), idle_time / total_time * 100); + vshPrint(ctl, "%-15s %5.1lf%%\n", + _("iowait:"), iowait_time / total_time * 100); } - vshPrint(ctl, _("Bridge interface %s started\n"), br_name); } ret = true; - cleanup: - if (if_handle) - virInterfaceFree(if_handle); - if (br_handle) - virInterfaceFree(br_handle); - VIR_FREE(if_xml); - VIR_FREE(br_xml); - VIR_FREE(if_type); - VIR_FREE(if2_name); - VIR_FREE(delay_str); - xmlXPathFreeContext(ctxt); - xmlFreeDoc(xml_doc); + + cleanup: + VIR_FREE(params); return ret; } /* - * "iface-unbridge" command + * "nodememstats" command */ -static const vshCmdInfo info_interface_unbridge[] = { - {"help", N_("undefine a bridge device after detaching its slave device")}, - {"desc", N_("unbridge a network device")}, +static const vshCmdInfo info_nodememstats[] = { + {"help", N_("Prints memory stats of the node.")}, + {"desc", N_("Returns memory stats of the node, in kilobytes.")}, {NULL, NULL} }; -static const vshCmdOptDef opts_interface_unbridge[] = { - {"bridge", VSH_OT_DATA, VSH_OFLAG_REQ, N_("current bridge device name")}, - {"no-start", VSH_OT_BOOL, 0, - N_("don't start the un-slaved interface immediately (not recommended)")}, +static const vshCmdOptDef opts_node_memstats[] = { + {"cell", VSH_OT_INT, 0, N_("prints specified cell statistics only.")}, {NULL, 0, 0, NULL} }; static bool -cmdInterfaceUnbridge(vshControl *ctl, const vshCmd *cmd) +cmdNodeMemStats(vshControl *ctl, const vshCmd *cmd) { + int nparams = 0; + unsigned int i = 0; + int cellNum = VIR_NODE_MEMORY_STATS_ALL_CELLS; + virNodeMemoryStatsPtr params = NULL; bool ret = false; - virInterfacePtr if_handle = NULL, br_handle = NULL; - const char *br_name; - char *if_type = NULL, *if_name = NULL; - bool nostart = false; - char *br_xml = NULL; - xmlChar *if_xml = NULL; - int if_xml_size; - xmlDocPtr xml_doc = NULL; - xmlXPathContextPtr ctxt = NULL; - xmlNodePtr top_node, br_node, if_node, cur; if (!vshConnectionUsability(ctl, ctl->conn)) - goto cleanup; + return false; - /* Get a handle to the original device */ - if (!(br_handle = vshCommandOptInterfaceBy(ctl, cmd, "bridge", - &br_name, VSH_BYNAME))) { - goto cleanup; + if (vshCommandOptInt(cmd, "cell", &cellNum) < 0) { + vshError(ctl, "%s", _("Invalid value of cellNum")); + return false; } - nostart = vshCommandOptBool(cmd, "no-start"); - - /* Get the bridge xml into an xmlDoc */ - if (!(br_xml = virInterfaceGetXMLDesc(br_handle, VIR_INTERFACE_XML_INACTIVE))) - goto cleanup; - if (!(xml_doc = virXMLParseStringCtxt(br_xml, - _("(bridge interface definition)"), - &ctxt))) { - vshError(ctl, _("Failed to parse configuration of %s"), br_name); + /* get the number of memory parameters */ + if (virNodeGetMemoryStats(ctl->conn, cellNum, NULL, &nparams, 0) != 0) { + vshError(ctl, "%s", + _("Unable to get number of memory stats")); goto cleanup; } - top_node = ctxt->node; - /* Verify that the device really is a bridge. */ - if (!(if_type = virXMLPropString(top_node, "type"))) { - vshError(ctl, _("Existing device %s has no type"), br_name); + if (nparams == 0) { + /* nothing to output */ + ret = true; goto cleanup; } - if (STRNEQ(if_type, "bridge")) { - vshError(ctl, _("Device %s is not a bridge"), br_name); + /* now go get all the memory parameters */ + params = vshCalloc(ctl, nparams, sizeof(*params)); + if (virNodeGetMemoryStats(ctl->conn, cellNum, params, &nparams, 0) != 0) { + vshError(ctl, "%s", _("Unable to get memory stats")); goto cleanup; } - VIR_FREE(if_type); - /* verify the name in the XML matches the device name */ - if (!(if_name = virXMLPropString(top_node, "name")) || - STRNEQ(if_name, br_name)) { - vshError(ctl, _("Interface name from config %s doesn't match given supplied name %s"), - if_name, br_name); - goto cleanup; - } - VIR_FREE(if_name); + for (i = 0; i < nparams; i++) + vshPrint(ctl, "%-7s: %20llu KiB\n", params[i].field, params[i].value); - /* Find the <bridge> node under <interface>. */ - if (!(br_node = virXPathNode("./bridge", ctxt))) { - vshError(ctl, "%s", _("No bridge node in xml document")); - goto cleanup; - } + ret = true; - if ((if_node = virXPathNode("./bridge/interface[2]", ctxt))) { - vshError(ctl, "%s", _("Multiple interfaces attached to bridge")); - goto cleanup; - } + cleanup: + VIR_FREE(params); + return ret; +} - if (!(if_node = virXPathNode("./bridge/interface", ctxt))) { - vshError(ctl, "%s", _("No interface attached to bridge")); - goto cleanup; - } +/* + * "nodesuspend" command + */ +static const vshCmdInfo info_nodesuspend[] = { + {"help", N_("suspend the host node for a given time duration")}, + {"desc", N_("Suspend the host node for a given time duration " + "and attempt to resume thereafter.")}, + {NULL, NULL} +}; - /* Change the type and name of the outer/master interface to - * the type/name of the attached slave interface. - */ - if (!(if_name = virXMLPropString(if_node, "name"))) { - vshError(ctl, _("Device attached to bridge %s has no name"), br_name); - goto cleanup; - } +static const vshCmdOptDef opts_node_suspend[] = { + {"target", VSH_OT_DATA, VSH_OFLAG_REQ, N_("mem(Suspend-to-RAM), " + "disk(Suspend-to-Disk), hybrid(Hybrid-Suspend)")}, + {"duration", VSH_OT_INT, VSH_OFLAG_REQ, N_("Suspend duration in seconds")}, + {"flags", VSH_OT_INT, VSH_OFLAG_NONE, N_("Suspend flags, 0 for default")}, + {NULL, 0, 0, NULL} +}; - if (!(if_type = virXMLPropString(if_node, "type"))) { - vshError(ctl, _("Attached device %s has no type"), if_name); - goto cleanup; - } +static bool +cmdNodeSuspend(vshControl *ctl, const vshCmd *cmd) +{ + const char *target = NULL; + unsigned int suspendTarget; + long long duration; + unsigned int flags = 0; - if (!xmlSetProp(top_node, BAD_CAST "type", BAD_CAST if_type)) { - vshError(ctl, _("Failed to set interface type to '%s' in xml document"), - if_type); - goto cleanup; - } + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; - if (!xmlSetProp(top_node, BAD_CAST "name", BAD_CAST if_name)) { - vshError(ctl, _("Failed to set interface name to '%s' in xml document"), - if_name); - goto cleanup; + if (vshCommandOptString(cmd, "target", &target) < 0) { + vshError(ctl, _("Invalid target argument")); + return false; } - /* Cycle through all the nodes under the attached <interface>, - * moving all <mac>, <bond> and <vlan> nodes up into the toplevel - * <interface>. - */ - cur = if_node->children; - while (cur) { - xmlNodePtr old = cur; - - cur = cur->next; - if ((old->type == XML_ELEMENT_NODE) && - (xmlStrEqual(old->name, BAD_CAST "mac") || /* ethernet stuff to move down */ - xmlStrEqual(old->name, BAD_CAST "bond") || /* bond stuff to move down */ - xmlStrEqual(old->name, BAD_CAST "vlan"))) { /* vlan stuff to move down */ - xmlUnlinkNode(old); - if (!xmlAddChild(top_node, old)) { - vshError(ctl, _("Failed to move '%s' element in xml document"), old->name); - xmlFreeNode(old); - goto cleanup; - } - } + if (vshCommandOptLongLong(cmd, "duration", &duration) < 0) { + vshError(ctl, _("Invalid duration argument")); + return false; } - /* The document should now be fully converted; write it out to a string. */ - xmlDocDumpMemory(xml_doc, &if_xml, &if_xml_size); - - if (!if_xml || if_xml_size <= 0) { - vshError(ctl, _("Failed to format new xml document for un-enslaved interface %s"), - if_name); - goto cleanup; + if (vshCommandOptUInt(cmd, "flags", &flags) < 0) { + vshError(ctl, _("Invalid flags argument")); + return false; } - /* Destroy and Undefine the bridge device, since we otherwise - * can't safely define the unattached device. - */ - if (virInterfaceDestroy(br_handle, 0) < 0) { - vshError(ctl, _("Failed to destroy bridge interface %s"), br_name); - goto cleanup; + if (STREQ(target, "mem")) + suspendTarget = VIR_NODE_SUSPEND_TARGET_MEM; + else if (STREQ(target, "disk")) + suspendTarget = VIR_NODE_SUSPEND_TARGET_DISK; + else if (STREQ(target, "hybrid")) + suspendTarget = VIR_NODE_SUSPEND_TARGET_HYBRID; + else { + vshError(ctl, "%s", _("Invalid target")); + return false; } - if (virInterfaceUndefine(br_handle) < 0) { - vshError(ctl, _("Failed to undefine bridge interface %s"), br_name); - goto cleanup; + + if (duration <= 0) { + vshError(ctl, "%s", _("Invalid duration")); + return false; } - /* if_xml is the new interface to define. - */ - if (!(if_handle = virInterfaceDefineXML(ctl->conn, (char *) if_xml, 0))) { - vshError(ctl, _("Failed to define new interface %s"), if_name); - goto cleanup; + if (virNodeSuspendForDuration(ctl->conn, suspendTarget, duration, + flags) < 0) { + vshError(ctl, "%s", _("The host was not suspended")); + return false; } + return true; +} - vshPrint(ctl, _("Device %s un-attached from bridge %s\n"), - if_name, br_name); - /* unless requested otherwise, undefine the bridge device */ - if (!nostart) { - if (virInterfaceCreate(if_handle, 0) < 0) { - vshError(ctl, _("Failed to start interface %s"), if_name); - goto cleanup; - } - vshPrint(ctl, _("Interface %s started\n"), if_name); +/* + * "capabilities" command + */ +static const vshCmdInfo info_capabilities[] = { + {"help", N_("capabilities")}, + {"desc", N_("Returns capabilities of hypervisor/driver.")}, + {NULL, NULL} +}; + +static bool +cmdCapabilities(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) +{ + char *caps; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if ((caps = virConnectGetCapabilities(ctl->conn)) == NULL) { + vshError(ctl, "%s", _("failed to get capabilities")); + return false; } + vshPrint(ctl, "%s\n", caps); + VIR_FREE(caps); - ret = true; - cleanup: - if (if_handle) - virInterfaceFree(if_handle); - if (br_handle) - virInterfaceFree(br_handle); - VIR_FREE(if_xml); - VIR_FREE(br_xml); - VIR_FREE(if_type); - VIR_FREE(if_name); - xmlXPathFreeContext(ctxt); - xmlFreeDoc(xml_doc); - return ret; + return true; } /* @@ -6113,47 +5173,6 @@ vshCommandOptNWFilterBy(vshControl *ctl, const vshCmd *cmd, return nwfilter; } -static virInterfacePtr -vshCommandOptInterfaceBy(vshControl *ctl, const vshCmd *cmd, - const char *optname, - const char **name, int flag) -{ - virInterfacePtr iface = NULL; - const char *n = NULL; - - if (!optname) - optname = "interface"; - if (!cmd_has_option(ctl, cmd, optname)) - return NULL; - - if (vshCommandOptString(cmd, optname, &n) <= 0) - return NULL; - - vshDebug(ctl, VSH_ERR_INFO, "%s: found option <%s>: %s\n", - cmd->def->name, optname, n); - - if (name) - *name = n; - - /* try it by NAME */ - if (flag & VSH_BYNAME) { - vshDebug(ctl, VSH_ERR_DEBUG, "%s: <%s> trying as interface NAME\n", - cmd->def->name, optname); - iface = virInterfaceLookupByName(ctl->conn, n); - } - /* try it by MAC */ - if (iface == NULL && (flag & VSH_BYMAC)) { - vshDebug(ctl, VSH_ERR_DEBUG, "%s: <%s> trying as interface MAC\n", - cmd->def->name, optname); - iface = virInterfaceLookupByMACString(ctl->conn, n); - } - - if (!iface) - vshError(ctl, _("failed to get interface '%s'"), n); - - return iface; -} - static virSecretPtr vshCommandOptSecret(vshControl *ctl, const vshCmd *cmd, const char **name) { @@ -7717,6 +6736,8 @@ static const vshCmdDef nodedevCmds[] = { {NULL, NULL, NULL, NULL, 0} }; +#include "virsh-interface.c" + static const vshCmdDef ifaceCmds[] = { {"iface-begin", cmdInterfaceBegin, opts_interface_begin, info_interface_begin, 0}, -- 1.7.7.3

On 07/24/12 11:18, Osier Yang wrote:
Commands to manage host interface are moved from virsh.c to virsh-interface.c, with a few helpers for interface command use.
* virsh.c: Remove interface commands and a few helpers. (vshCommandOptInterface, vshCommandOptInterfaceBy) * virsh-interface.c: New file, filled with interface commands its helpers. --- tools/virsh-interface.c | 1000 +++++++++++++++++++++++++++++++++++ tools/virsh.c | 1333 +++++++---------------------------------------- 2 files changed, 1177 insertions(+), 1156 deletions(-) create mode 100644 tools/virsh-interface.c
ACK, Peter.

Commands to manage network filter are moved from virsh.c to virsh-nwfilter.c, with a few helpers for network filter command use. * virsh.c: Remove network filter commands and a few helpers. (vshCommandOptNWFilter, and vshCommandOptNWFilterBy) * virsh-nwfilter.c: New file, filled with network filter commands and its helpers. --- tools/virsh-nwfilter.c | 310 ++++++++++++++++++++++++++++++++++++++++++++++++ tools/virsh.c | 294 +--------------------------------------------- 2 files changed, 312 insertions(+), 292 deletions(-) create mode 100644 tools/virsh-nwfilter.c diff --git a/tools/virsh-nwfilter.c b/tools/virsh-nwfilter.c new file mode 100644 index 0000000..4b4996a --- /dev/null +++ b/tools/virsh-nwfilter.c @@ -0,0 +1,310 @@ +/* + * virsh-domain.c: Commands to manage network filters + * + * Copyright (C) 2005, 2007-2012 Red Hat, Inc + * + * 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 + * License along with this library; If not, see + * <http://www.gnu.org/licenses/>. + * + * Daniel Veillard <veillard@redhat.com> + * Karel Zak <kzak@redhat.com> + * Daniel P. Berrange <berrange@redhat.com> + * + */ + +/* default is lookup by Name and UUID */ +#define vshCommandOptNWFilter(_ctl, _cmd, _name) \ + vshCommandOptNWFilterBy(_ctl, _cmd, _name, \ + VSH_BYUUID|VSH_BYNAME) + +static virNWFilterPtr +vshCommandOptNWFilterBy(vshControl *ctl, const vshCmd *cmd, + const char **name, int flag) +{ + virNWFilterPtr nwfilter = NULL; + const char *n = NULL; + const char *optname = "nwfilter"; + if (!cmd_has_option(ctl, cmd, optname)) + return NULL; + + if (vshCommandOptString(cmd, optname, &n) <= 0) + return NULL; + + vshDebug(ctl, VSH_ERR_INFO, "%s: found option <%s>: %s\n", + cmd->def->name, optname, n); + + if (name) + *name = n; + + /* try it by UUID */ + if ((flag & VSH_BYUUID) && strlen(n) == VIR_UUID_STRING_BUFLEN-1) { + vshDebug(ctl, VSH_ERR_DEBUG, "%s: <%s> trying as nwfilter UUID\n", + cmd->def->name, optname); + nwfilter = virNWFilterLookupByUUIDString(ctl->conn, n); + } + /* try it by NAME */ + if (nwfilter == NULL && (flag & VSH_BYNAME)) { + vshDebug(ctl, VSH_ERR_DEBUG, "%s: <%s> trying as nwfilter NAME\n", + cmd->def->name, optname); + nwfilter = virNWFilterLookupByName(ctl->conn, n); + } + + if (!nwfilter) + vshError(ctl, _("failed to get nwfilter '%s'"), n); + + return nwfilter; +} + +/* + * "nwfilter-define" command + */ +static const vshCmdInfo info_nwfilter_define[] = { + {"help", N_("define or update a network filter from an XML file")}, + {"desc", N_("Define a new network filter or update an existing one.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_nwfilter_define[] = { + {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containing an XML network filter description")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdNWFilterDefine(vshControl *ctl, const vshCmd *cmd) +{ + virNWFilterPtr nwfilter; + const char *from = NULL; + bool ret = true; + char *buffer; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (vshCommandOptString(cmd, "file", &from) <= 0) + return false; + + if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0) + return false; + + nwfilter = virNWFilterDefineXML(ctl->conn, buffer); + VIR_FREE(buffer); + + if (nwfilter != NULL) { + vshPrint(ctl, _("Network filter %s defined from %s\n"), + virNWFilterGetName(nwfilter), from); + virNWFilterFree(nwfilter); + } else { + vshError(ctl, _("Failed to define network filter from %s"), from); + ret = false; + } + return ret; +} + +/* + * "nwfilter-undefine" command + */ +static const vshCmdInfo info_nwfilter_undefine[] = { + {"help", N_("undefine a network filter")}, + {"desc", N_("Undefine a given network filter.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_nwfilter_undefine[] = { + {"nwfilter", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network filter name or uuid")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdNWFilterUndefine(vshControl *ctl, const vshCmd *cmd) +{ + virNWFilterPtr nwfilter; + bool ret = true; + const char *name; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(nwfilter = vshCommandOptNWFilter(ctl, cmd, &name))) + return false; + + if (virNWFilterUndefine(nwfilter) == 0) { + vshPrint(ctl, _("Network filter %s undefined\n"), name); + } else { + vshError(ctl, _("Failed to undefine network filter %s"), name); + ret = false; + } + + virNWFilterFree(nwfilter); + return ret; +} + +/* + * "nwfilter-dumpxml" command + */ +static const vshCmdInfo info_nwfilter_dumpxml[] = { + {"help", N_("network filter information in XML")}, + {"desc", N_("Output the network filter information as an XML dump to stdout.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_nwfilter_dumpxml[] = { + {"nwfilter", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network filter name or uuid")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdNWFilterDumpXML(vshControl *ctl, const vshCmd *cmd) +{ + virNWFilterPtr nwfilter; + bool ret = true; + char *dump; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(nwfilter = vshCommandOptNWFilter(ctl, cmd, NULL))) + return false; + + dump = virNWFilterGetXMLDesc(nwfilter, 0); + if (dump != NULL) { + vshPrint(ctl, "%s", dump); + VIR_FREE(dump); + } else { + ret = false; + } + + virNWFilterFree(nwfilter); + return ret; +} + +/* + * "nwfilter-list" command + */ +static const vshCmdInfo info_nwfilter_list[] = { + {"help", N_("list network filters")}, + {"desc", N_("Returns list of network filters.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_nwfilter_list[] = { + {NULL, 0, 0, NULL} +}; + +static bool +cmdNWFilterList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) +{ + int numfilters, i; + char **names; + char uuid[VIR_UUID_STRING_BUFLEN]; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + numfilters = virConnectNumOfNWFilters(ctl->conn); + if (numfilters < 0) { + vshError(ctl, "%s", _("Failed to list network filters")); + return false; + } + + names = vshMalloc(ctl, sizeof(char *) * numfilters); + + if ((numfilters = virConnectListNWFilters(ctl->conn, names, + numfilters)) < 0) { + vshError(ctl, "%s", _("Failed to list network filters")); + VIR_FREE(names); + return false; + } + + qsort(&names[0], numfilters, sizeof(char *), vshNameSorter); + + vshPrintExtra(ctl, "%-36s %-20s \n", _("UUID"), _("Name")); + vshPrintExtra(ctl, + "----------------------------------------------------------------\n"); + + for (i = 0; i < numfilters; i++) { + virNWFilterPtr nwfilter = + virNWFilterLookupByName(ctl->conn, names[i]); + + /* this kind of work with networks is not atomic operation */ + if (!nwfilter) { + VIR_FREE(names[i]); + continue; + } + + virNWFilterGetUUIDString(nwfilter, uuid); + vshPrint(ctl, "%-36s %-20s\n", + uuid, + virNWFilterGetName(nwfilter)); + virNWFilterFree(nwfilter); + VIR_FREE(names[i]); + } + + VIR_FREE(names); + return true; +} + +/* + * "nwfilter-edit" command + */ +static const vshCmdInfo info_nwfilter_edit[] = { + {"help", N_("edit XML configuration for a network filter")}, + {"desc", N_("Edit the XML configuration for a network filter.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_nwfilter_edit[] = { + {"nwfilter", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network filter name or uuid")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdNWFilterEdit(vshControl *ctl, const vshCmd *cmd) +{ + bool ret = false; + virNWFilterPtr nwfilter = NULL; + virNWFilterPtr nwfilter_edited = NULL; + + if (!vshConnectionUsability(ctl, ctl->conn)) + goto cleanup; + + nwfilter = vshCommandOptNWFilter(ctl, cmd, NULL); + if (nwfilter == NULL) + goto cleanup; + +#define EDIT_GET_XML virNWFilterGetXMLDesc(nwfilter, 0) +#define EDIT_NOT_CHANGED \ + vshPrint(ctl, _("Network filter %s XML " \ + "configuration not changed.\n"), \ + virNWFilterGetName(nwfilter)); \ + ret = true; goto edit_cleanup; +#define EDIT_DEFINE \ + (nwfilter_edited = virNWFilterDefineXML(ctl->conn, doc_edited)) +#define EDIT_FREE \ + if (nwfilter_edited) \ + virNWFilterFree(nwfilter); +#include "virsh-edit.c" + + vshPrint(ctl, _("Network filter %s XML configuration edited.\n"), + virNWFilterGetName(nwfilter_edited)); + + ret = true; + +cleanup: + if (nwfilter) + virNWFilterFree(nwfilter); + if (nwfilter_edited) + virNWFilterFree(nwfilter_edited); + + return ret; +} diff --git a/tools/virsh.c b/tools/virsh.c index 23b2ec9..4844e31 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -339,14 +339,6 @@ static virDomainPtr vshCommandOptDomainBy(vshControl *ctl, const vshCmd *cmd, #define vshCommandOptDomain(_ctl, _cmd, _name) \ vshCommandOptDomainBy(_ctl, _cmd, _name, VSH_BYID|VSH_BYUUID|VSH_BYNAME) -static virNWFilterPtr vshCommandOptNWFilterBy(vshControl *ctl, const vshCmd *cmd, - const char **name, int flag); - -/* default is lookup by Name and UUID */ -#define vshCommandOptNWFilter(_ctl, _cmd, _name) \ - vshCommandOptNWFilterBy(_ctl, _cmd, _name, \ - VSH_BYUUID|VSH_BYNAME) - static virSecretPtr vshCommandOptSecret(vshControl *ctl, const vshCmd *cmd, const char **name); @@ -1256,252 +1248,6 @@ cmdCapabilities(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) } /* - * "nwfilter-define" command - */ -static const vshCmdInfo info_nwfilter_define[] = { - {"help", N_("define or update a network filter from an XML file")}, - {"desc", N_("Define a new network filter or update an existing one.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_nwfilter_define[] = { - {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containing an XML network filter description")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdNWFilterDefine(vshControl *ctl, const vshCmd *cmd) -{ - virNWFilterPtr nwfilter; - const char *from = NULL; - bool ret = true; - char *buffer; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (vshCommandOptString(cmd, "file", &from) <= 0) - return false; - - if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0) - return false; - - nwfilter = virNWFilterDefineXML(ctl->conn, buffer); - VIR_FREE(buffer); - - if (nwfilter != NULL) { - vshPrint(ctl, _("Network filter %s defined from %s\n"), - virNWFilterGetName(nwfilter), from); - virNWFilterFree(nwfilter); - } else { - vshError(ctl, _("Failed to define network filter from %s"), from); - ret = false; - } - return ret; -} - - -/* - * "nwfilter-undefine" command - */ -static const vshCmdInfo info_nwfilter_undefine[] = { - {"help", N_("undefine a network filter")}, - {"desc", N_("Undefine a given network filter.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_nwfilter_undefine[] = { - {"nwfilter", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network filter name or uuid")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdNWFilterUndefine(vshControl *ctl, const vshCmd *cmd) -{ - virNWFilterPtr nwfilter; - bool ret = true; - const char *name; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (!(nwfilter = vshCommandOptNWFilter(ctl, cmd, &name))) - return false; - - if (virNWFilterUndefine(nwfilter) == 0) { - vshPrint(ctl, _("Network filter %s undefined\n"), name); - } else { - vshError(ctl, _("Failed to undefine network filter %s"), name); - ret = false; - } - - virNWFilterFree(nwfilter); - return ret; -} - - -/* - * "nwfilter-dumpxml" command - */ -static const vshCmdInfo info_nwfilter_dumpxml[] = { - {"help", N_("network filter information in XML")}, - {"desc", N_("Output the network filter information as an XML dump to stdout.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_nwfilter_dumpxml[] = { - {"nwfilter", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network filter name or uuid")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdNWFilterDumpXML(vshControl *ctl, const vshCmd *cmd) -{ - virNWFilterPtr nwfilter; - bool ret = true; - char *dump; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (!(nwfilter = vshCommandOptNWFilter(ctl, cmd, NULL))) - return false; - - dump = virNWFilterGetXMLDesc(nwfilter, 0); - if (dump != NULL) { - vshPrint(ctl, "%s", dump); - VIR_FREE(dump); - } else { - ret = false; - } - - virNWFilterFree(nwfilter); - return ret; -} - -/* - * "nwfilter-list" command - */ -static const vshCmdInfo info_nwfilter_list[] = { - {"help", N_("list network filters")}, - {"desc", N_("Returns list of network filters.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_nwfilter_list[] = { - {NULL, 0, 0, NULL} -}; - -static bool -cmdNWFilterList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) -{ - int numfilters, i; - char **names; - char uuid[VIR_UUID_STRING_BUFLEN]; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - numfilters = virConnectNumOfNWFilters(ctl->conn); - if (numfilters < 0) { - vshError(ctl, "%s", _("Failed to list network filters")); - return false; - } - - names = vshMalloc(ctl, sizeof(char *) * numfilters); - - if ((numfilters = virConnectListNWFilters(ctl->conn, names, - numfilters)) < 0) { - vshError(ctl, "%s", _("Failed to list network filters")); - VIR_FREE(names); - return false; - } - - qsort(&names[0], numfilters, sizeof(char *), vshNameSorter); - - vshPrintExtra(ctl, "%-36s %-20s \n", _("UUID"), _("Name")); - vshPrintExtra(ctl, - "----------------------------------------------------------------\n"); - - for (i = 0; i < numfilters; i++) { - virNWFilterPtr nwfilter = - virNWFilterLookupByName(ctl->conn, names[i]); - - /* this kind of work with networks is not atomic operation */ - if (!nwfilter) { - VIR_FREE(names[i]); - continue; - } - - virNWFilterGetUUIDString(nwfilter, uuid); - vshPrint(ctl, "%-36s %-20s\n", - uuid, - virNWFilterGetName(nwfilter)); - virNWFilterFree(nwfilter); - VIR_FREE(names[i]); - } - - VIR_FREE(names); - return true; -} - - -/* - * "nwfilter-edit" command - */ -static const vshCmdInfo info_nwfilter_edit[] = { - {"help", N_("edit XML configuration for a network filter")}, - {"desc", N_("Edit the XML configuration for a network filter.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_nwfilter_edit[] = { - {"nwfilter", VSH_OT_DATA, VSH_OFLAG_REQ, N_("network filter name or uuid")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdNWFilterEdit(vshControl *ctl, const vshCmd *cmd) -{ - bool ret = false; - virNWFilterPtr nwfilter = NULL; - virNWFilterPtr nwfilter_edited = NULL; - - if (!vshConnectionUsability(ctl, ctl->conn)) - goto cleanup; - - nwfilter = vshCommandOptNWFilter(ctl, cmd, NULL); - if (nwfilter == NULL) - goto cleanup; - -#define EDIT_GET_XML virNWFilterGetXMLDesc(nwfilter, 0) -#define EDIT_NOT_CHANGED \ - vshPrint(ctl, _("Network filter %s XML " \ - "configuration not changed.\n"), \ - virNWFilterGetName(nwfilter)); \ - ret = true; goto edit_cleanup; -#define EDIT_DEFINE \ - (nwfilter_edited = virNWFilterDefineXML(ctl->conn, doc_edited)) -#define EDIT_FREE \ - if (nwfilter_edited) \ - virNWFilterFree(nwfilter); -#include "virsh-edit.c" - - vshPrint(ctl, _("Network filter %s XML configuration edited.\n"), - virNWFilterGetName(nwfilter_edited)); - - ret = true; - -cleanup: - if (nwfilter) - virNWFilterFree(nwfilter); - if (nwfilter_edited) - virNWFilterFree(nwfilter_edited); - - return ret; -} - -/* * "nodedev-create" command */ static const vshCmdInfo info_node_device_create[] = { @@ -5135,44 +4881,6 @@ vshCommandOptDomainBy(vshControl *ctl, const vshCmd *cmd, return dom; } -static virNWFilterPtr -vshCommandOptNWFilterBy(vshControl *ctl, const vshCmd *cmd, - const char **name, int flag) -{ - virNWFilterPtr nwfilter = NULL; - const char *n = NULL; - const char *optname = "nwfilter"; - if (!cmd_has_option(ctl, cmd, optname)) - return NULL; - - if (vshCommandOptString(cmd, optname, &n) <= 0) - return NULL; - - vshDebug(ctl, VSH_ERR_INFO, "%s: found option <%s>: %s\n", - cmd->def->name, optname, n); - - if (name) - *name = n; - - /* try it by UUID */ - if ((flag & VSH_BYUUID) && strlen(n) == VIR_UUID_STRING_BUFLEN-1) { - vshDebug(ctl, VSH_ERR_DEBUG, "%s: <%s> trying as nwfilter UUID\n", - cmd->def->name, optname); - nwfilter = virNWFilterLookupByUUIDString(ctl->conn, n); - } - /* try it by NAME */ - if (nwfilter == NULL && (flag & VSH_BYNAME)) { - vshDebug(ctl, VSH_ERR_DEBUG, "%s: <%s> trying as nwfilter NAME\n", - cmd->def->name, optname); - nwfilter = virNWFilterLookupByName(ctl->conn, n); - } - - if (!nwfilter) - vshError(ctl, _("failed to get nwfilter '%s'"), n); - - return nwfilter; -} - static virSecretPtr vshCommandOptSecret(vshControl *ctl, const vshCmd *cmd, const char **name) { @@ -6770,6 +6478,8 @@ static const vshCmdDef ifaceCmds[] = { {NULL, NULL, NULL, NULL, 0} }; +#include "virsh-nwfilter.c" + static const vshCmdDef nwfilterCmds[] = { {"nwfilter-define", cmdNWFilterDefine, opts_nwfilter_define, info_nwfilter_define, 0}, -- 1.7.7.3

On 07/24/2012 11:18 AM, Osier Yang wrote:
Commands to manage network filter are moved from virsh.c to virsh-nwfilter.c, with a few helpers for network filter command use.
* virsh.c: Remove network filter commands and a few helpers. (vshCommandOptNWFilter, and vshCommandOptNWFilterBy) * virsh-nwfilter.c: New file, filled with network filter commands and its helpers. --- tools/virsh-nwfilter.c | 310 ++++++++++++++++++++++++++++++++++++++++++++++++ tools/virsh.c | 294 +--------------------------------------------- 2 files changed, 312 insertions(+), 292 deletions(-) create mode 100644 tools/virsh-nwfilter.c
diff --git a/tools/virsh-nwfilter.c b/tools/virsh-nwfilter.c new file mode 100644 index 0000000..4b4996a --- /dev/null +++ b/tools/virsh-nwfilter.c @@ -0,0 +1,310 @@ +/* + * virsh-domain.c: Commands to manage network filters
s/domain/nwfilter/ ACK with the filename fixed. Martin

Commands to manage secret are moved from virsh.c to virsh-secret.c, with a few helpers for secret command use. * virsh.c: Remove secret commands and helper (vshCommandOptSecret). * virsh-secret.c: New file, filled with secret commands and its helper. --- tools/virsh-secret.c | 358 ++++++++++++++++++++++++++++++++++++++++++++++++++ tools/virsh.c | 340 +----------------------------------------------- 2 files changed, 360 insertions(+), 338 deletions(-) create mode 100644 tools/virsh-secret.c diff --git a/tools/virsh-secret.c b/tools/virsh-secret.c new file mode 100644 index 0000000..9ec3186 --- /dev/null +++ b/tools/virsh-secret.c @@ -0,0 +1,358 @@ +/* + * virsh-domain.c: Commands to manage secret + * + * Copyright (C) 2005, 2007-2012 Red Hat, Inc + * + * 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 + * License along with this library; If not, see + * <http://www.gnu.org/licenses/>. + * + * Daniel Veillard <veillard@redhat.com> + * Karel Zak <kzak@redhat.com> + * Daniel P. Berrange <berrange@redhat.com> + * + */ + +static virSecretPtr +vshCommandOptSecret(vshControl *ctl, const vshCmd *cmd, const char **name) +{ + virSecretPtr secret = NULL; + const char *n = NULL; + const char *optname = "secret"; + + if (!cmd_has_option(ctl, cmd, optname)) + return NULL; + + if (vshCommandOptString(cmd, optname, &n) <= 0) + return NULL; + + vshDebug(ctl, VSH_ERR_DEBUG, + "%s: found option <%s>: %s\n", cmd->def->name, optname, n); + + if (name != NULL) + *name = n; + + secret = virSecretLookupByUUIDString(ctl->conn, n); + + if (secret == NULL) + vshError(ctl, _("failed to get secret '%s'"), n); + + return secret; +} + +/* + * "secret-define" command + */ +static const vshCmdInfo info_secret_define[] = { + {"help", N_("define or modify a secret from an XML file")}, + {"desc", N_("Define or modify a secret.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_secret_define[] = { + {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containing secret attributes in XML")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdSecretDefine(vshControl *ctl, const vshCmd *cmd) +{ + const char *from = NULL; + char *buffer; + virSecretPtr res; + char uuid[VIR_UUID_STRING_BUFLEN]; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (vshCommandOptString(cmd, "file", &from) <= 0) + return false; + + if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0) + return false; + + res = virSecretDefineXML(ctl->conn, buffer, 0); + VIR_FREE(buffer); + + if (res == NULL) { + vshError(ctl, _("Failed to set attributes from %s"), from); + return false; + } + if (virSecretGetUUIDString(res, &(uuid[0])) < 0) { + vshError(ctl, "%s", _("Failed to get UUID of created secret")); + virSecretFree(res); + return false; + } + vshPrint(ctl, _("Secret %s created\n"), uuid); + virSecretFree(res); + return true; +} + +/* + * "secret-dumpxml" command + */ +static const vshCmdInfo info_secret_dumpxml[] = { + {"help", N_("secret attributes in XML")}, + {"desc", N_("Output attributes of a secret as an XML dump to stdout.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_secret_dumpxml[] = { + {"secret", VSH_OT_DATA, VSH_OFLAG_REQ, N_("secret UUID")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdSecretDumpXML(vshControl *ctl, const vshCmd *cmd) +{ + virSecretPtr secret; + bool ret = false; + char *xml; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + secret = vshCommandOptSecret(ctl, cmd, NULL); + if (secret == NULL) + return false; + + xml = virSecretGetXMLDesc(secret, 0); + if (xml == NULL) + goto cleanup; + vshPrint(ctl, "%s", xml); + VIR_FREE(xml); + ret = true; + +cleanup: + virSecretFree(secret); + return ret; +} + +/* + * "secret-set-value" command + */ +static const vshCmdInfo info_secret_set_value[] = { + {"help", N_("set a secret value")}, + {"desc", N_("Set a secret value.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_secret_set_value[] = { + {"secret", VSH_OT_DATA, VSH_OFLAG_REQ, N_("secret UUID")}, + {"base64", VSH_OT_DATA, VSH_OFLAG_REQ, N_("base64-encoded secret value")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdSecretSetValue(vshControl *ctl, const vshCmd *cmd) +{ + virSecretPtr secret; + size_t value_size; + const char *base64 = NULL; + char *value; + int res; + bool ret = false; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + secret = vshCommandOptSecret(ctl, cmd, NULL); + if (secret == NULL) + return false; + + if (vshCommandOptString(cmd, "base64", &base64) <= 0) + goto cleanup; + + if (!base64_decode_alloc(base64, strlen(base64), &value, &value_size)) { + vshError(ctl, "%s", _("Invalid base64 data")); + goto cleanup; + } + if (value == NULL) { + vshError(ctl, "%s", _("Failed to allocate memory")); + return false; + } + + res = virSecretSetValue(secret, (unsigned char *)value, value_size, 0); + memset(value, 0, value_size); + VIR_FREE(value); + + if (res != 0) { + vshError(ctl, "%s", _("Failed to set secret value")); + goto cleanup; + } + vshPrint(ctl, "%s", _("Secret value set\n")); + ret = true; + +cleanup: + virSecretFree(secret); + return ret; +} + +/* + * "secret-get-value" command + */ +static const vshCmdInfo info_secret_get_value[] = { + {"help", N_("Output a secret value")}, + {"desc", N_("Output a secret value to stdout.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_secret_get_value[] = { + {"secret", VSH_OT_DATA, VSH_OFLAG_REQ, N_("secret UUID")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdSecretGetValue(vshControl *ctl, const vshCmd *cmd) +{ + virSecretPtr secret; + char *base64; + unsigned char *value; + size_t value_size; + bool ret = false; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + secret = vshCommandOptSecret(ctl, cmd, NULL); + if (secret == NULL) + return false; + + value = virSecretGetValue(secret, &value_size, 0); + if (value == NULL) + goto cleanup; + + base64_encode_alloc((char *)value, value_size, &base64); + memset(value, 0, value_size); + VIR_FREE(value); + + if (base64 == NULL) { + vshError(ctl, "%s", _("Failed to allocate memory")); + goto cleanup; + } + vshPrint(ctl, "%s", base64); + memset(base64, 0, strlen(base64)); + VIR_FREE(base64); + ret = true; + +cleanup: + virSecretFree(secret); + return ret; +} + +/* + * "secret-undefine" command + */ +static const vshCmdInfo info_secret_undefine[] = { + {"help", N_("undefine a secret")}, + {"desc", N_("Undefine a secret.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_secret_undefine[] = { + {"secret", VSH_OT_DATA, VSH_OFLAG_REQ, N_("secret UUID")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdSecretUndefine(vshControl *ctl, const vshCmd *cmd) +{ + virSecretPtr secret; + bool ret = false; + const char *uuid; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + secret = vshCommandOptSecret(ctl, cmd, &uuid); + if (secret == NULL) + return false; + + if (virSecretUndefine(secret) < 0) { + vshError(ctl, _("Failed to delete secret %s"), uuid); + goto cleanup; + } + vshPrint(ctl, _("Secret %s deleted\n"), uuid); + ret = true; + +cleanup: + virSecretFree(secret); + return ret; +} + +/* + * "secret-list" command + */ +static const vshCmdInfo info_secret_list[] = { + {"help", N_("list secrets")}, + {"desc", N_("Returns a list of secrets")}, + {NULL, NULL} +}; + +static bool +cmdSecretList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) +{ + int maxuuids = 0, i; + char **uuids = NULL; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + maxuuids = virConnectNumOfSecrets(ctl->conn); + if (maxuuids < 0) { + vshError(ctl, "%s", _("Failed to list secrets")); + return false; + } + uuids = vshMalloc(ctl, sizeof(*uuids) * maxuuids); + + maxuuids = virConnectListSecrets(ctl->conn, uuids, maxuuids); + if (maxuuids < 0) { + vshError(ctl, "%s", _("Failed to list secrets")); + VIR_FREE(uuids); + return false; + } + + qsort(uuids, maxuuids, sizeof(char *), vshNameSorter); + + vshPrintExtra(ctl, "%-36s %s\n", _("UUID"), _("Usage")); + vshPrintExtra(ctl, "-----------------------------------------------------------\n"); + + for (i = 0; i < maxuuids; i++) { + virSecretPtr sec = virSecretLookupByUUIDString(ctl->conn, uuids[i]); + const char *usageType = NULL; + + if (!sec) { + VIR_FREE(uuids[i]); + continue; + } + + switch (virSecretGetUsageType(sec)) { + case VIR_SECRET_USAGE_TYPE_VOLUME: + usageType = _("Volume"); + break; + } + + if (usageType) { + vshPrint(ctl, "%-36s %s %s\n", + uuids[i], usageType, + virSecretGetUsageID(sec)); + } else { + vshPrint(ctl, "%-36s %s\n", + uuids[i], _("Unused")); + } + virSecretFree(sec); + VIR_FREE(uuids[i]); + } + VIR_FREE(uuids); + return true; +} diff --git a/tools/virsh.c b/tools/virsh.c index 4844e31..cddb6e3 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -339,9 +339,6 @@ static virDomainPtr vshCommandOptDomainBy(vshControl *ctl, const vshCmd *cmd, #define vshCommandOptDomain(_ctl, _cmd, _name) \ vshCommandOptDomainBy(_ctl, _cmd, _name, VSH_BYID|VSH_BYUUID|VSH_BYNAME) -static virSecretPtr vshCommandOptSecret(vshControl *ctl, const vshCmd *cmd, - const char **name); - static void vshPrintExtra(vshControl *ctl, const char *format, ...) ATTRIBUTE_FMT_PRINTF(2, 3); static void vshDebug(vshControl *ctl, int level, const char *format, ...) @@ -1342,314 +1339,6 @@ cmdNodeDeviceDestroy(vshControl *ctl, const vshCmd *cmd) } /* - * "secret-define" command - */ -static const vshCmdInfo info_secret_define[] = { - {"help", N_("define or modify a secret from an XML file")}, - {"desc", N_("Define or modify a secret.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_secret_define[] = { - {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containing secret attributes in XML")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdSecretDefine(vshControl *ctl, const vshCmd *cmd) -{ - const char *from = NULL; - char *buffer; - virSecretPtr res; - char uuid[VIR_UUID_STRING_BUFLEN]; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (vshCommandOptString(cmd, "file", &from) <= 0) - return false; - - if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0) - return false; - - res = virSecretDefineXML(ctl->conn, buffer, 0); - VIR_FREE(buffer); - - if (res == NULL) { - vshError(ctl, _("Failed to set attributes from %s"), from); - return false; - } - if (virSecretGetUUIDString(res, &(uuid[0])) < 0) { - vshError(ctl, "%s", _("Failed to get UUID of created secret")); - virSecretFree(res); - return false; - } - vshPrint(ctl, _("Secret %s created\n"), uuid); - virSecretFree(res); - return true; -} - -/* - * "secret-dumpxml" command - */ -static const vshCmdInfo info_secret_dumpxml[] = { - {"help", N_("secret attributes in XML")}, - {"desc", N_("Output attributes of a secret as an XML dump to stdout.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_secret_dumpxml[] = { - {"secret", VSH_OT_DATA, VSH_OFLAG_REQ, N_("secret UUID")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdSecretDumpXML(vshControl *ctl, const vshCmd *cmd) -{ - virSecretPtr secret; - bool ret = false; - char *xml; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - secret = vshCommandOptSecret(ctl, cmd, NULL); - if (secret == NULL) - return false; - - xml = virSecretGetXMLDesc(secret, 0); - if (xml == NULL) - goto cleanup; - vshPrint(ctl, "%s", xml); - VIR_FREE(xml); - ret = true; - -cleanup: - virSecretFree(secret); - return ret; -} - -/* - * "secret-set-value" command - */ -static const vshCmdInfo info_secret_set_value[] = { - {"help", N_("set a secret value")}, - {"desc", N_("Set a secret value.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_secret_set_value[] = { - {"secret", VSH_OT_DATA, VSH_OFLAG_REQ, N_("secret UUID")}, - {"base64", VSH_OT_DATA, VSH_OFLAG_REQ, N_("base64-encoded secret value")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdSecretSetValue(vshControl *ctl, const vshCmd *cmd) -{ - virSecretPtr secret; - size_t value_size; - const char *base64 = NULL; - char *value; - int res; - bool ret = false; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - secret = vshCommandOptSecret(ctl, cmd, NULL); - if (secret == NULL) - return false; - - if (vshCommandOptString(cmd, "base64", &base64) <= 0) - goto cleanup; - - if (!base64_decode_alloc(base64, strlen(base64), &value, &value_size)) { - vshError(ctl, "%s", _("Invalid base64 data")); - goto cleanup; - } - if (value == NULL) { - vshError(ctl, "%s", _("Failed to allocate memory")); - return false; - } - - res = virSecretSetValue(secret, (unsigned char *)value, value_size, 0); - memset(value, 0, value_size); - VIR_FREE(value); - - if (res != 0) { - vshError(ctl, "%s", _("Failed to set secret value")); - goto cleanup; - } - vshPrint(ctl, "%s", _("Secret value set\n")); - ret = true; - -cleanup: - virSecretFree(secret); - return ret; -} - -/* - * "secret-get-value" command - */ -static const vshCmdInfo info_secret_get_value[] = { - {"help", N_("Output a secret value")}, - {"desc", N_("Output a secret value to stdout.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_secret_get_value[] = { - {"secret", VSH_OT_DATA, VSH_OFLAG_REQ, N_("secret UUID")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdSecretGetValue(vshControl *ctl, const vshCmd *cmd) -{ - virSecretPtr secret; - char *base64; - unsigned char *value; - size_t value_size; - bool ret = false; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - secret = vshCommandOptSecret(ctl, cmd, NULL); - if (secret == NULL) - return false; - - value = virSecretGetValue(secret, &value_size, 0); - if (value == NULL) - goto cleanup; - - base64_encode_alloc((char *)value, value_size, &base64); - memset(value, 0, value_size); - VIR_FREE(value); - - if (base64 == NULL) { - vshError(ctl, "%s", _("Failed to allocate memory")); - goto cleanup; - } - vshPrint(ctl, "%s", base64); - memset(base64, 0, strlen(base64)); - VIR_FREE(base64); - ret = true; - -cleanup: - virSecretFree(secret); - return ret; -} - -/* - * "secret-undefine" command - */ -static const vshCmdInfo info_secret_undefine[] = { - {"help", N_("undefine a secret")}, - {"desc", N_("Undefine a secret.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_secret_undefine[] = { - {"secret", VSH_OT_DATA, VSH_OFLAG_REQ, N_("secret UUID")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdSecretUndefine(vshControl *ctl, const vshCmd *cmd) -{ - virSecretPtr secret; - bool ret = false; - const char *uuid; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - secret = vshCommandOptSecret(ctl, cmd, &uuid); - if (secret == NULL) - return false; - - if (virSecretUndefine(secret) < 0) { - vshError(ctl, _("Failed to delete secret %s"), uuid); - goto cleanup; - } - vshPrint(ctl, _("Secret %s deleted\n"), uuid); - ret = true; - -cleanup: - virSecretFree(secret); - return ret; -} - -/* - * "secret-list" command - */ -static const vshCmdInfo info_secret_list[] = { - {"help", N_("list secrets")}, - {"desc", N_("Returns a list of secrets")}, - {NULL, NULL} -}; - -static bool -cmdSecretList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) -{ - int maxuuids = 0, i; - char **uuids = NULL; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - maxuuids = virConnectNumOfSecrets(ctl->conn); - if (maxuuids < 0) { - vshError(ctl, "%s", _("Failed to list secrets")); - return false; - } - uuids = vshMalloc(ctl, sizeof(*uuids) * maxuuids); - - maxuuids = virConnectListSecrets(ctl->conn, uuids, maxuuids); - if (maxuuids < 0) { - vshError(ctl, "%s", _("Failed to list secrets")); - VIR_FREE(uuids); - return false; - } - - qsort(uuids, maxuuids, sizeof(char *), vshNameSorter); - - vshPrintExtra(ctl, "%-36s %s\n", _("UUID"), _("Usage")); - vshPrintExtra(ctl, "-----------------------------------------------------------\n"); - - for (i = 0; i < maxuuids; i++) { - virSecretPtr sec = virSecretLookupByUUIDString(ctl->conn, uuids[i]); - const char *usageType = NULL; - - if (!sec) { - VIR_FREE(uuids[i]); - continue; - } - - switch (virSecretGetUsageType(sec)) { - case VIR_SECRET_USAGE_TYPE_VOLUME: - usageType = _("Volume"); - break; - } - - if (usageType) { - vshPrint(ctl, "%-36s %s %s\n", - uuids[i], usageType, - virSecretGetUsageID(sec)); - } else { - vshPrint(ctl, "%-36s %s\n", - uuids[i], _("Unused")); - } - virSecretFree(sec); - VIR_FREE(uuids[i]); - } - VIR_FREE(uuids); - return true; -} - - -/* * "version" command */ static const vshCmdInfo info_version[] = { @@ -4881,33 +4570,6 @@ vshCommandOptDomainBy(vshControl *ctl, const vshCmd *cmd, return dom; } -static virSecretPtr -vshCommandOptSecret(vshControl *ctl, const vshCmd *cmd, const char **name) -{ - virSecretPtr secret = NULL; - const char *n = NULL; - const char *optname = "secret"; - - if (!cmd_has_option(ctl, cmd, optname)) - return NULL; - - if (vshCommandOptString(cmd, optname, &n) <= 0) - return NULL; - - vshDebug(ctl, VSH_ERR_DEBUG, - "%s: found option <%s>: %s\n", cmd->def->name, optname, n); - - if (name != NULL) - *name = n; - - secret = virSecretLookupByUUIDString(ctl->conn, n); - - if (secret == NULL) - vshError(ctl, _("failed to get secret '%s'"), n); - - return secret; -} - /* * Executes command(s) and returns return code from last command */ @@ -6494,6 +6156,8 @@ static const vshCmdDef nwfilterCmds[] = { {NULL, NULL, NULL, NULL, 0} }; +#include "virsh-secret.c" + static const vshCmdDef secretCmds[] = { {"secret-define", cmdSecretDefine, opts_secret_define, info_secret_define, 0}, -- 1.7.7.3

On 07/24/2012 11:18 AM, Osier Yang wrote:
Commands to manage secret are moved from virsh.c to virsh-secret.c, with a few helpers for secret command use.
* virsh.c: Remove secret commands and helper (vshCommandOptSecret). * virsh-secret.c: New file, filled with secret commands and its helper. --- tools/virsh-secret.c | 358 ++++++++++++++++++++++++++++++++++++++++++++++++++ tools/virsh.c | 340 +----------------------------------------------- 2 files changed, 360 insertions(+), 338 deletions(-) create mode 100644 tools/virsh-secret.c
diff --git a/tools/virsh-secret.c b/tools/virsh-secret.c new file mode 100644 index 0000000..9ec3186 --- /dev/null +++ b/tools/virsh-secret.c @@ -0,0 +1,358 @@ +/* + * virsh-domain.c: Commands to manage secret
s/domain/secret/ ACK with the filename fixed, Martin

Commands to manage domain snapshot are moved from virsh.c to virsh-snapshot.c. * virsh.c: Remove domain snapshot commands. * virsh-snapshot.c: New file, filled with domain snapshot commands. --- tools/virsh-snapshot.c | 1604 ++++++++++++++++++++++++++++++++++++++++++++++++ tools/virsh.c | 1582 +----------------------------------------------- 2 files changed, 1606 insertions(+), 1580 deletions(-) create mode 100644 tools/virsh-snapshot.c diff --git a/tools/virsh-snapshot.c b/tools/virsh-snapshot.c new file mode 100644 index 0000000..c0a2d9d --- /dev/null +++ b/tools/virsh-snapshot.c @@ -0,0 +1,1604 @@ +/* + * virsh-domain.c: Commands to manage domain snapshot + * + * Copyright (C) 2005, 2007-2012 Red Hat, Inc + * + * 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 + * License along with this library; If not, see + * <http://www.gnu.org/licenses/>. + * + * Daniel Veillard <veillard@redhat.com> + * Karel Zak <kzak@redhat.com> + * Daniel P. Berrange <berrange@redhat.com> + * + */ + +/* Helper for snapshot-create and snapshot-create-as */ +static bool +vshSnapshotCreate(vshControl *ctl, virDomainPtr dom, const char *buffer, + unsigned int flags, const char *from) +{ + bool ret = false; + virDomainSnapshotPtr snapshot; + bool halt = false; + char *doc = NULL; + xmlDocPtr xml = NULL; + xmlXPathContextPtr ctxt = NULL; + const char *name = NULL; + + snapshot = virDomainSnapshotCreateXML(dom, buffer, flags); + + /* Emulate --halt on older servers. */ + if (!snapshot && last_error->code == VIR_ERR_INVALID_ARG && + (flags & VIR_DOMAIN_SNAPSHOT_CREATE_HALT)) { + int persistent; + + virFreeError(last_error); + last_error = NULL; + persistent = virDomainIsPersistent(dom); + if (persistent < 0) { + virshReportError(ctl); + goto cleanup; + } + if (!persistent) { + vshError(ctl, "%s", + _("cannot halt after snapshot of transient domain")); + goto cleanup; + } + if (virDomainIsActive(dom) == 1) + halt = true; + flags &= ~VIR_DOMAIN_SNAPSHOT_CREATE_HALT; + snapshot = virDomainSnapshotCreateXML(dom, buffer, flags); + } + + if (snapshot == NULL) + goto cleanup; + + if (halt && virDomainDestroy(dom) < 0) { + virshReportError(ctl); + goto cleanup; + } + + name = virDomainSnapshotGetName(snapshot); + if (!name) { + vshError(ctl, "%s", _("Could not get snapshot name")); + goto cleanup; + } + + if (from) + vshPrint(ctl, _("Domain snapshot %s created from '%s'"), name, from); + else + vshPrint(ctl, _("Domain snapshot %s created"), name); + + ret = true; + +cleanup: + xmlXPathFreeContext(ctxt); + xmlFreeDoc(xml); + if (snapshot) + virDomainSnapshotFree(snapshot); + VIR_FREE(doc); + return ret; +} + +/* + * "snapshot-create" command + */ +static const vshCmdInfo info_snapshot_create[] = { + {"help", N_("Create a snapshot from XML")}, + {"desc", N_("Create a snapshot (disk and RAM) from XML")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_snapshot_create[] = { + {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, + {"xmlfile", VSH_OT_DATA, 0, N_("domain snapshot XML")}, + {"redefine", VSH_OT_BOOL, 0, N_("redefine metadata for existing snapshot")}, + {"current", VSH_OT_BOOL, 0, N_("with redefine, set current snapshot")}, + {"no-metadata", VSH_OT_BOOL, 0, N_("take snapshot but create no metadata")}, + {"halt", VSH_OT_BOOL, 0, N_("halt domain after snapshot is created")}, + {"disk-only", VSH_OT_BOOL, 0, N_("capture disk state but not vm state")}, + {"reuse-external", VSH_OT_BOOL, 0, N_("reuse any existing external files")}, + {"quiesce", VSH_OT_BOOL, 0, N_("quiesce guest's file systems")}, + {"atomic", VSH_OT_BOOL, 0, N_("require atomic operation")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdSnapshotCreate(vshControl *ctl, const vshCmd *cmd) +{ + virDomainPtr dom = NULL; + bool ret = false; + const char *from = NULL; + char *buffer = NULL; + unsigned int flags = 0; + + if (vshCommandOptBool(cmd, "redefine")) + flags |= VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE; + if (vshCommandOptBool(cmd, "current")) + flags |= VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT; + if (vshCommandOptBool(cmd, "no-metadata")) + flags |= VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA; + if (vshCommandOptBool(cmd, "halt")) + flags |= VIR_DOMAIN_SNAPSHOT_CREATE_HALT; + if (vshCommandOptBool(cmd, "disk-only")) + flags |= VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY; + if (vshCommandOptBool(cmd, "reuse-external")) + flags |= VIR_DOMAIN_SNAPSHOT_CREATE_REUSE_EXT; + if (vshCommandOptBool(cmd, "quiesce")) + flags |= VIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE; + if (vshCommandOptBool(cmd, "atomic")) + flags |= VIR_DOMAIN_SNAPSHOT_CREATE_ATOMIC; + + if (!vshConnectionUsability(ctl, ctl->conn)) + goto cleanup; + + dom = vshCommandOptDomain(ctl, cmd, NULL); + if (dom == NULL) + goto cleanup; + + if (vshCommandOptString(cmd, "xmlfile", &from) <= 0) + buffer = vshStrdup(ctl, "<domainsnapshot/>"); + else { + if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0) { + /* we have to report the error here because during cleanup + * we'll run through virDomainFree(), which loses the + * last error + */ + virshReportError(ctl); + goto cleanup; + } + } + if (buffer == NULL) { + vshError(ctl, "%s", _("Out of memory")); + goto cleanup; + } + + ret = vshSnapshotCreate(ctl, dom, buffer, flags, from); + +cleanup: + VIR_FREE(buffer); + if (dom) + virDomainFree(dom); + + return ret; +} + +/* + * "snapshot-create-as" command + */ +static int +vshParseSnapshotDiskspec(vshControl *ctl, virBufferPtr buf, const char *str) +{ + int ret = -1; + char *name = NULL; + char *snapshot = NULL; + char *driver = NULL; + char *file = NULL; + char *spec = vshStrdup(ctl, str); + char *tmp = spec; + size_t len = strlen(str); + + if (*str == ',') + goto cleanup; + name = tmp; + while ((tmp = strchr(tmp, ','))) { + if (tmp[1] == ',') { + /* Recognize ,, as an escape for a literal comma */ + memmove(&tmp[1], &tmp[2], len - (tmp - spec) - 2 + 1); + len--; + tmp++; + continue; + } + /* Terminate previous string, look for next recognized one */ + *tmp++ = '\0'; + if (!snapshot && STRPREFIX(tmp, "snapshot=")) + snapshot = tmp + strlen("snapshot="); + else if (!driver && STRPREFIX(tmp, "driver=")) + driver = tmp + strlen("driver="); + else if (!file && STRPREFIX(tmp, "file=")) + file = tmp + strlen("file="); + else + goto cleanup; + } + + virBufferEscapeString(buf, " <disk name='%s'", name); + if (snapshot) + virBufferAsprintf(buf, " snapshot='%s'", snapshot); + if (driver || file) { + virBufferAddLit(buf, ">\n"); + if (driver) + virBufferAsprintf(buf, " <driver type='%s'/>\n", driver); + if (file) + virBufferEscapeString(buf, " <source file='%s'/>\n", file); + virBufferAddLit(buf, " </disk>\n"); + } else { + virBufferAddLit(buf, "/>\n"); + } + ret = 0; +cleanup: + if (ret < 0) + vshError(ctl, _("unable to parse diskspec: %s"), str); + VIR_FREE(spec); + return ret; +} + +static const vshCmdInfo info_snapshot_create_as[] = { + {"help", N_("Create a snapshot from a set of args")}, + {"desc", N_("Create a snapshot (disk and RAM) from arguments")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_snapshot_create_as[] = { + {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, + {"name", VSH_OT_DATA, 0, N_("name of snapshot")}, + {"description", VSH_OT_DATA, 0, N_("description of snapshot")}, + {"print-xml", VSH_OT_BOOL, 0, N_("print XML document rather than create")}, + {"no-metadata", VSH_OT_BOOL, 0, N_("take snapshot but create no metadata")}, + {"halt", VSH_OT_BOOL, 0, N_("halt domain after snapshot is created")}, + {"disk-only", VSH_OT_BOOL, 0, N_("capture disk state but not vm state")}, + {"reuse-external", VSH_OT_BOOL, 0, N_("reuse any existing external files")}, + {"quiesce", VSH_OT_BOOL, 0, N_("quiesce guest's file systems")}, + {"atomic", VSH_OT_BOOL, 0, N_("require atomic operation")}, + {"diskspec", VSH_OT_ARGV, 0, + N_("disk attributes: disk[,snapshot=type][,driver=type][,file=name]")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdSnapshotCreateAs(vshControl *ctl, const vshCmd *cmd) +{ + virDomainPtr dom = NULL; + bool ret = false; + char *buffer = NULL; + const char *name = NULL; + const char *desc = NULL; + virBuffer buf = VIR_BUFFER_INITIALIZER; + unsigned int flags = 0; + const vshCmdOpt *opt = NULL; + + if (vshCommandOptBool(cmd, "no-metadata")) + flags |= VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA; + if (vshCommandOptBool(cmd, "halt")) + flags |= VIR_DOMAIN_SNAPSHOT_CREATE_HALT; + if (vshCommandOptBool(cmd, "disk-only")) + flags |= VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY; + if (vshCommandOptBool(cmd, "reuse-external")) + flags |= VIR_DOMAIN_SNAPSHOT_CREATE_REUSE_EXT; + if (vshCommandOptBool(cmd, "quiesce")) + flags |= VIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE; + if (vshCommandOptBool(cmd, "atomic")) + flags |= VIR_DOMAIN_SNAPSHOT_CREATE_ATOMIC; + + if (!vshConnectionUsability(ctl, ctl->conn)) + goto cleanup; + + dom = vshCommandOptDomain(ctl, cmd, NULL); + if (dom == NULL) + goto cleanup; + + if (vshCommandOptString(cmd, "name", &name) < 0 || + vshCommandOptString(cmd, "description", &desc) < 0) { + vshError(ctl, _("argument must not be empty")); + goto cleanup; + } + + virBufferAddLit(&buf, "<domainsnapshot>\n"); + if (name) + virBufferEscapeString(&buf, " <name>%s</name>\n", name); + if (desc) + virBufferEscapeString(&buf, " <description>%s</description>\n", desc); + if (vshCommandOptBool(cmd, "diskspec")) { + virBufferAddLit(&buf, " <disks>\n"); + while ((opt = vshCommandOptArgv(cmd, opt))) { + if (vshParseSnapshotDiskspec(ctl, &buf, opt->data) < 0) { + virBufferFreeAndReset(&buf); + goto cleanup; + } + } + virBufferAddLit(&buf, " </disks>\n"); + } + virBufferAddLit(&buf, "</domainsnapshot>\n"); + + buffer = virBufferContentAndReset(&buf); + if (buffer == NULL) { + vshError(ctl, "%s", _("Out of memory")); + goto cleanup; + } + + if (vshCommandOptBool(cmd, "print-xml")) { + vshPrint(ctl, "%s\n", buffer); + ret = true; + goto cleanup; + } + + ret = vshSnapshotCreate(ctl, dom, buffer, flags, NULL); + +cleanup: + VIR_FREE(buffer); + if (dom) + virDomainFree(dom); + + return ret; +} + +/* Helper for resolving {--current | --ARG name} into a snapshot + * belonging to DOM. If EXCLUSIVE, fail if both --current and arg are + * present. On success, populate *SNAP and *NAME, before returning 0. + * On failure, return -1 after issuing an error message. */ +static int +vshLookupSnapshot(vshControl *ctl, const vshCmd *cmd, + const char *arg, bool exclusive, virDomainPtr dom, + virDomainSnapshotPtr *snap, const char **name) +{ + bool current = vshCommandOptBool(cmd, "current"); + const char *snapname = NULL; + + if (vshCommandOptString(cmd, arg, &snapname) < 0) { + vshError(ctl, _("invalid argument for --%s"), arg); + return -1; + } + + if (exclusive && current && snapname) { + vshError(ctl, _("--%s and --current are mutually exclusive"), arg); + return -1; + } + + if (snapname) { + *snap = virDomainSnapshotLookupByName(dom, snapname, 0); + } else if (current) { + *snap = virDomainSnapshotCurrent(dom, 0); + } else { + vshError(ctl, _("--%s or --current is required"), arg); + return -1; + } + if (!*snap) { + virshReportError(ctl); + return -1; + } + + *name = virDomainSnapshotGetName(*snap); + return 0; +} + +/* + * "snapshot-edit" command + */ +static const vshCmdInfo info_snapshot_edit[] = { + {"help", N_("edit XML for a snapshot")}, + {"desc", N_("Edit the domain snapshot XML for a named snapshot")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_snapshot_edit[] = { + {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, + {"snapshotname", VSH_OT_DATA, 0, N_("snapshot name")}, + {"current", VSH_OT_BOOL, 0, N_("also set edited snapshot as current")}, + {"rename", VSH_OT_BOOL, 0, N_("allow renaming an existing snapshot")}, + {"clone", VSH_OT_BOOL, 0, N_("allow cloning to new name")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdSnapshotEdit(vshControl *ctl, const vshCmd *cmd) +{ + virDomainPtr dom = NULL; + virDomainSnapshotPtr snapshot = NULL; + virDomainSnapshotPtr edited = NULL; + const char *name; + const char *edited_name; + bool ret = false; + unsigned int getxml_flags = VIR_DOMAIN_XML_SECURE; + unsigned int define_flags = VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE; + bool rename_okay = vshCommandOptBool(cmd, "rename"); + bool clone_okay = vshCommandOptBool(cmd, "clone"); + + if (rename_okay && clone_okay) { + vshError(ctl, "%s", + _("--rename and --clone are mutually exclusive")); + return false; + } + + if (vshCommandOptBool(cmd, "current") && + vshCommandOptBool(cmd, "snapshotname")) + define_flags |= VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + dom = vshCommandOptDomain(ctl, cmd, NULL); + if (dom == NULL) + goto cleanup; + + if (vshLookupSnapshot(ctl, cmd, "snapshotname", false, dom, + &snapshot, &name) < 0) + goto cleanup; + +#define EDIT_GET_XML \ + virDomainSnapshotGetXMLDesc(snapshot, getxml_flags) +#define EDIT_NOT_CHANGED \ + /* Depending on flags, we re-edit even if XML is unchanged. */ \ + if (!(define_flags & VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT)) { \ + vshPrint(ctl, \ + _("Snapshot %s XML configuration not changed.\n"), \ + name); \ + ret = true; \ + goto cleanup; \ + } +#define EDIT_DEFINE \ + (strstr(doc, "<state>disk-snapshot</state>") ? \ + define_flags |= VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY : 0), \ + edited = virDomainSnapshotCreateXML(dom, doc_edited, define_flags) +#define EDIT_FREE \ + if (edited) \ + virDomainSnapshotFree(edited); +#include "virsh-edit.c" + + edited_name = virDomainSnapshotGetName(edited); + if (STREQ(name, edited_name)) { + vshPrint(ctl, _("Snapshot %s edited.\n"), name); + } else if (clone_okay) { + vshPrint(ctl, _("Snapshot %s cloned to %s.\n"), name, + edited_name); + } else { + unsigned int delete_flags; + + delete_flags = VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY; + if (virDomainSnapshotDelete(rename_okay ? snapshot : edited, + delete_flags) < 0) { + virshReportError(ctl); + vshError(ctl, _("Failed to clean up %s"), + rename_okay ? name : edited_name); + goto cleanup; + } + if (!rename_okay) { + vshError(ctl, _("Must use --rename or --clone to change %s to %s"), + name, edited_name); + goto cleanup; + } + } + + ret = true; + +cleanup: + if (edited) + virDomainSnapshotFree(edited); + else + vshError(ctl, _("Failed to update %s"), name); + if (snapshot) + virDomainSnapshotFree(snapshot); + if (dom) + virDomainFree(dom); + return ret; +} + +/* + * "snapshot-current" command + */ +static const vshCmdInfo info_snapshot_current[] = { + {"help", N_("Get or set the current snapshot")}, + {"desc", N_("Get or set the current snapshot")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_snapshot_current[] = { + {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, + {"name", VSH_OT_BOOL, 0, N_("list the name, rather than the full xml")}, + {"security-info", VSH_OT_BOOL, 0, + N_("include security sensitive information in XML dump")}, + {"snapshotname", VSH_OT_DATA, 0, + N_("name of existing snapshot to make current")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdSnapshotCurrent(vshControl *ctl, const vshCmd *cmd) +{ + virDomainPtr dom = NULL; + bool ret = false; + int current; + virDomainSnapshotPtr snapshot = NULL; + char *xml = NULL; + const char *snapshotname = NULL; + unsigned int flags = 0; + const char *domname; + + if (vshCommandOptBool(cmd, "security-info")) + flags |= VIR_DOMAIN_XML_SECURE; + + if (!vshConnectionUsability(ctl, ctl->conn)) + goto cleanup; + + dom = vshCommandOptDomain(ctl, cmd, &domname); + if (dom == NULL) + goto cleanup; + + if (vshCommandOptString(cmd, "snapshotname", &snapshotname) < 0) { + vshError(ctl, _("invalid snapshotname argument '%s'"), snapshotname); + goto cleanup; + } + if (snapshotname) { + virDomainSnapshotPtr snapshot2 = NULL; + flags = (VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE | + VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT); + + if (vshCommandOptBool(cmd, "name")) { + vshError(ctl, "%s", + _("--name and snapshotname are mutually exclusive")); + goto cleanup; + } + snapshot = virDomainSnapshotLookupByName(dom, snapshotname, 0); + if (snapshot == NULL) + goto cleanup; + xml = virDomainSnapshotGetXMLDesc(snapshot, VIR_DOMAIN_XML_SECURE); + if (!xml) + goto cleanup; + /* strstr is safe here, since xml came from libvirt API and not user */ + if (strstr(xml, "<state>disk-snapshot</state>")) + flags |= VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY; + snapshot2 = virDomainSnapshotCreateXML(dom, xml, flags); + if (snapshot2 == NULL) + goto cleanup; + virDomainSnapshotFree(snapshot2); + vshPrint(ctl, _("Snapshot %s set as current"), snapshotname); + ret = true; + goto cleanup; + } + + current = virDomainHasCurrentSnapshot(dom, 0); + if (current < 0) { + goto cleanup; + } else if (!current) { + vshError(ctl, _("domain '%s' has no current snapshot"), domname); + goto cleanup; + } else { + const char *name = NULL; + + if (!(snapshot = virDomainSnapshotCurrent(dom, 0))) + goto cleanup; + + if (vshCommandOptBool(cmd, "name")) { + name = virDomainSnapshotGetName(snapshot); + if (!name) + goto cleanup; + } else { + xml = virDomainSnapshotGetXMLDesc(snapshot, flags); + if (!xml) + goto cleanup; + } + + vshPrint(ctl, "%s", name ? name : xml); + } + + ret = true; + +cleanup: + if (!ret) + virshReportError(ctl); + VIR_FREE(xml); + if (snapshot) + virDomainSnapshotFree(snapshot); + if (dom) + virDomainFree(dom); + + return ret; +} + +/* Helper function to get the name of a snapshot's parent. Caller + * must free the result. Returns 0 on success (including when it was + * proven no parent exists), and -1 on failure with error reported + * (such as no snapshot support or domain deleted in meantime). */ +static int +vshGetSnapshotParent(vshControl *ctl, virDomainSnapshotPtr snapshot, + char **parent_name) +{ + virDomainSnapshotPtr parent = NULL; + char *xml = NULL; + xmlDocPtr xmldoc = NULL; + xmlXPathContextPtr ctxt = NULL; + int ret = -1; + + *parent_name = NULL; + + /* Try new API, since it is faster. */ + if (!ctl->useSnapshotOld) { + parent = virDomainSnapshotGetParent(snapshot, 0); + if (parent) { + /* API works, and virDomainSnapshotGetName will succeed */ + *parent_name = vshStrdup(ctl, virDomainSnapshotGetName(parent)); + ret = 0; + goto cleanup; + } + if (last_error->code == VIR_ERR_NO_DOMAIN_SNAPSHOT) { + /* API works, and we found a root with no parent */ + ret = 0; + goto cleanup; + } + /* API didn't work, fall back to XML scraping. */ + ctl->useSnapshotOld = true; + } + + xml = virDomainSnapshotGetXMLDesc(snapshot, 0); + if (!xml) + goto cleanup; + + xmldoc = virXMLParseStringCtxt(xml, _("(domain_snapshot)"), &ctxt); + if (!xmldoc) + goto cleanup; + + *parent_name = virXPathString("string(/domainsnapshot/parent/name)", ctxt); + ret = 0; + +cleanup: + if (ret < 0) { + virshReportError(ctl); + vshError(ctl, "%s", _("unable to determine if snapshot has parent")); + } else { + virFreeError(last_error); + last_error = NULL; + } + if (parent) + virDomainSnapshotFree(parent); + xmlXPathFreeContext(ctxt); + xmlFreeDoc(xmldoc); + VIR_FREE(xml); + return ret; +} + +/* + * "snapshot-info" command + */ +static const vshCmdInfo info_snapshot_info[] = { + {"help", N_("snapshot information")}, + {"desc", N_("Returns basic information about a snapshot.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_snapshot_info[] = { + {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, + {"snapshotname", VSH_OT_DATA, 0, N_("snapshot name")}, + {"current", VSH_OT_BOOL, 0, N_("info on current snapshot")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdSnapshotInfo(vshControl *ctl, const vshCmd *cmd) +{ + virDomainPtr dom; + virDomainSnapshotPtr snapshot = NULL; + const char *name; + char *doc = NULL; + char *tmp; + char *parent = NULL; + bool ret = false; + int count; + unsigned int flags; + int current; + int metadata; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + dom = vshCommandOptDomain(ctl, cmd, NULL); + if (dom == NULL) + return false; + + if (vshLookupSnapshot(ctl, cmd, "snapshotname", true, dom, + &snapshot, &name) < 0) + goto cleanup; + + vshPrint(ctl, "%-15s %s\n", _("Name:"), name); + vshPrint(ctl, "%-15s %s\n", _("Domain:"), virDomainGetName(dom)); + + /* Determine if snapshot is current; this is useful enough that we + * attempt a fallback. */ + current = virDomainSnapshotIsCurrent(snapshot, 0); + if (current < 0) { + virDomainSnapshotPtr other = virDomainSnapshotCurrent(dom, 0); + + virResetLastError(); + current = 0; + if (other) { + if (STREQ(name, virDomainSnapshotGetName(other))) + current = 1; + virDomainSnapshotFree(other); + } + } + vshPrint(ctl, "%-15s %s\n", _("Current:"), + current > 0 ? _("yes") : _("no")); + + /* Get the XML configuration of the snapshot to determine the + * state of the machine at the time of the snapshot. */ + doc = virDomainSnapshotGetXMLDesc(snapshot, 0); + if (!doc) + goto cleanup; + + tmp = strstr(doc, "<state>"); + if (!tmp) { + vshError(ctl, "%s", + _("unexpected problem reading snapshot xml")); + goto cleanup; + } + tmp += strlen("<state>"); + vshPrint(ctl, "%-15s %.*s\n", _("State:"), + (int) (strchr(tmp, '<') - tmp), tmp); + + if (vshGetSnapshotParent(ctl, snapshot, &parent) < 0) + goto cleanup; + vshPrint(ctl, "%-15s %s\n", _("Parent:"), parent ? parent : "-"); + + /* Children, Descendants. After this point, the fallback to + * compute children is too expensive, so we gracefully quit if the + * APIs don't exist. */ + if (ctl->useSnapshotOld) { + ret = true; + goto cleanup; + } + flags = 0; + count = virDomainSnapshotNumChildren(snapshot, flags); + if (count < 0) + goto cleanup; + vshPrint(ctl, "%-15s %d\n", _("Children:"), count); + flags = VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS; + count = virDomainSnapshotNumChildren(snapshot, flags); + if (count < 0) + goto cleanup; + vshPrint(ctl, "%-15s %d\n", _("Descendants:"), count); + + /* Metadata; the fallback here relies on the fact that metadata + * used to have an all-or-nothing effect on snapshot count. */ + metadata = virDomainSnapshotHasMetadata(snapshot, 0); + if (metadata < 0) { + metadata = virDomainSnapshotNum(dom, + VIR_DOMAIN_SNAPSHOT_LIST_METADATA); + virResetLastError(); + } + if (metadata >= 0) + vshPrint(ctl, "%-15s %s\n", _("Metadata:"), + metadata ? _("yes") : _("no")); + + ret = true; + +cleanup: + VIR_FREE(doc); + VIR_FREE(parent); + if (snapshot) + virDomainSnapshotFree(snapshot); + virDomainFree(dom); + return ret; +} + +/* Helpers for collecting a list of snapshots. */ +struct vshSnap { + virDomainSnapshotPtr snap; + char *parent; +}; +struct vshSnapshotList { + struct vshSnap *snaps; + int nsnaps; +}; +typedef struct vshSnapshotList *vshSnapshotListPtr; + +static void +vshSnapshotListFree(vshSnapshotListPtr snaplist) +{ + int i; + + if (!snaplist) + return; + if (snaplist->snaps) { + for (i = 0; i < snaplist->nsnaps; i++) { + if (snaplist->snaps[i].snap) + virDomainSnapshotFree(snaplist->snaps[i].snap); + VIR_FREE(snaplist->snaps[i].parent); + } + VIR_FREE(snaplist->snaps); + } + VIR_FREE(snaplist); +} + +static int +vshSnapSorter(const void *a, const void *b) +{ + const struct vshSnap *sa = a; + const struct vshSnap *sb = b; + + if (sa->snap && !sb->snap) + return -1; + if (!sa->snap) + return sb->snap != NULL; + + /* User visible sort, so we want locale-specific case comparison. */ + return strcasecmp(virDomainSnapshotGetName(sa->snap), + virDomainSnapshotGetName(sb->snap)); +} + +/* Compute a list of snapshots from DOM. If FROM is provided, the + * list is limited to descendants of the given snapshot. If FLAGS is + * given, the list is filtered. If TREE is specified, then all but + * FROM or the roots will also have parent information. */ +static vshSnapshotListPtr +vshSnapshotListCollect(vshControl *ctl, virDomainPtr dom, + virDomainSnapshotPtr from, + unsigned int flags, bool tree) +{ + int i; + char **names = NULL; + int count = -1; + bool descendants = false; + bool roots = false; + virDomainSnapshotPtr *snaps; + vshSnapshotListPtr snaplist = vshMalloc(ctl, sizeof(*snaplist)); + vshSnapshotListPtr ret = NULL; + const char *fromname = NULL; + int start_index = -1; + int deleted = 0; + + /* Try the interface available in 0.9.13 and newer. */ + if (!ctl->useSnapshotOld) { + if (from) + count = virDomainSnapshotListAllChildren(from, &snaps, flags); + else + count = virDomainListAllSnapshots(dom, &snaps, flags); + } + if (count >= 0) { + /* When mixing --from and --tree, we also want a copy of from + * in the list, but with no parent for that one entry. */ + snaplist->snaps = vshCalloc(ctl, count + (tree && from), + sizeof(*snaplist->snaps)); + snaplist->nsnaps = count; + for (i = 0; i < count; i++) + snaplist->snaps[i].snap = snaps[i]; + VIR_FREE(snaps); + if (tree) { + for (i = 0; i < count; i++) { + if (vshGetSnapshotParent(ctl, snaplist->snaps[i].snap, + &snaplist->snaps[i].parent) < 0) + goto cleanup; + } + if (from) { + snaps[snaplist->nsnaps++] = from; + virDomainSnapshotRef(from); + } + } + goto success; + } + + /* Assume that if we got this far, then the --no-leaves and + * --no-metadata flags were not supported. Disable groups that + * have no impact. */ + /* XXX should we emulate --no-leaves? */ + if (flags & VIR_DOMAIN_SNAPSHOT_LIST_NO_LEAVES && + flags & VIR_DOMAIN_SNAPSHOT_LIST_LEAVES) + flags &= ~(VIR_DOMAIN_SNAPSHOT_LIST_NO_LEAVES | + VIR_DOMAIN_SNAPSHOT_LIST_LEAVES); + if (flags & VIR_DOMAIN_SNAPSHOT_LIST_NO_METADATA && + flags & VIR_DOMAIN_SNAPSHOT_LIST_METADATA) + flags &= ~(VIR_DOMAIN_SNAPSHOT_LIST_NO_METADATA | + VIR_DOMAIN_SNAPSHOT_LIST_METADATA); + if (flags & VIR_DOMAIN_SNAPSHOT_LIST_NO_METADATA) { + /* We can emulate --no-metadata if --metadata was supported, + * since it was an all-or-none attribute on old servers. */ + count = virDomainSnapshotNum(dom, + VIR_DOMAIN_SNAPSHOT_LIST_METADATA); + if (count < 0) + goto cleanup; + if (count > 0) + return snaplist; + flags &= ~VIR_DOMAIN_SNAPSHOT_LIST_NO_METADATA; + } + + /* This uses the interfaces available in 0.8.0-0.9.6 + * (virDomainSnapshotListNames, global list only) and in + * 0.9.7-0.9.12 (addition of virDomainSnapshotListChildrenNames + * for child listing, and new flags), as follows, with [*] by the + * combinations that need parent info (either for filtering + * purposes or for the resulting tree listing): + * old new + * list global as-is global as-is + * list --roots *global + filter global + flags + * list --from *global + filter child as-is + * list --from --descendants *global + filter child + flags + * list --tree *global as-is *global as-is + * list --tree --from *global + filter *child + flags + * + * Additionally, when --tree and --from are both used, from is + * added to the final list as the only element without a parent. + * Otherwise, --from does not appear in the final list. + */ + if (from) { + fromname = virDomainSnapshotGetName(from); + if (!fromname) { + vshError(ctl, "%s", _("Could not get snapshot name")); + goto cleanup; + } + descendants = (flags & VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS) || tree; + if (tree) + flags |= VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS; + + /* Determine if we can use the new child listing API. */ + if (ctl->useSnapshotOld || + ((count = virDomainSnapshotNumChildren(from, flags)) < 0 && + last_error->code == VIR_ERR_NO_SUPPORT)) { + /* We can emulate --from. */ + /* XXX can we also emulate --leaves? */ + virFreeError(last_error); + last_error = NULL; + ctl->useSnapshotOld = true; + flags &= ~VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS; + goto global; + } + if (tree && count >= 0) + count++; + } else { + global: + /* Global listing (including fallback when --from failed with + * child listing). */ + count = virDomainSnapshotNum(dom, flags); + + /* Fall back to simulation if --roots was unsupported. */ + /* XXX can we also emulate --leaves? */ + if (!from && count < 0 && last_error->code == VIR_ERR_INVALID_ARG && + (flags & VIR_DOMAIN_SNAPSHOT_LIST_ROOTS)) { + virFreeError(last_error); + last_error = NULL; + roots = true; + flags &= ~VIR_DOMAIN_SNAPSHOT_LIST_ROOTS; + count = virDomainSnapshotNum(dom, flags); + } + } + + if (count < 0) { + if (!last_error) + vshError(ctl, _("failed to collect snapshot list")); + goto cleanup; + } + + if (!count) + goto success; + + names = vshCalloc(ctl, sizeof(*names), count); + + /* Now that we have a count, collect the list. */ + if (from && !ctl->useSnapshotOld) { + if (tree) { + if (count) + count = virDomainSnapshotListChildrenNames(from, names + 1, + count - 1, flags); + if (count >= 0) { + count++; + names[0] = vshStrdup(ctl, fromname); + } + } else { + count = virDomainSnapshotListChildrenNames(from, names, + count, flags); + } + } else { + count = virDomainSnapshotListNames(dom, names, count, flags); + } + if (count < 0) + goto cleanup; + + snaplist->snaps = vshCalloc(ctl, sizeof(*snaplist->snaps), count); + snaplist->nsnaps = count; + for (i = 0; i < count; i++) { + snaplist->snaps[i].snap = virDomainSnapshotLookupByName(dom, + names[i], 0); + if (!snaplist->snaps[i].snap) + goto cleanup; + } + + /* Collect parents when needed. With the new API, --tree and + * --from together put from as the first element without a parent; + * with the old API we still need to do a post-process filtering + * based on all parent information. */ + if (tree || (from && ctl->useSnapshotOld) || roots) { + for (i = (from && !ctl->useSnapshotOld); i < count; i++) { + if (from && ctl->useSnapshotOld && STREQ(names[i], fromname)) { + start_index = i; + if (tree) + continue; + } + if (vshGetSnapshotParent(ctl, snaplist->snaps[i].snap, + &snaplist->snaps[i].parent) < 0) + goto cleanup; + if ((from && ((tree && !snaplist->snaps[i].parent) || + (!descendants && + STRNEQ_NULLABLE(fromname, + snaplist->snaps[i].parent)))) || + (roots && snaplist->snaps[i].parent)) { + virDomainSnapshotFree(snaplist->snaps[i].snap); + snaplist->snaps[i].snap = NULL; + VIR_FREE(snaplist->snaps[i].parent); + deleted++; + } + } + } + if (tree) + goto success; + + if (ctl->useSnapshotOld && descendants) { + bool changed = false; + bool remaining = false; + + /* Make multiple passes over the list - first pass finds + * direct children and NULLs out all roots and from, remaining + * passes NULL out any undecided entry whose parent is not + * still in list. We mark known descendants by clearing + * snaps[i].parents. Sorry, this is O(n^3) - hope your + * hierarchy isn't huge. XXX Is it worth making O(n^2 log n) + * by using qsort and bsearch? */ + if (start_index < 0) { + vshError(ctl, _("snapshot %s disappeared from list"), fromname); + goto cleanup; + } + for (i = 0; i < count; i++) { + if (i == start_index || !snaplist->snaps[i].parent) { + VIR_FREE(names[i]); + virDomainSnapshotFree(snaplist->snaps[i].snap); + snaplist->snaps[i].snap = NULL; + VIR_FREE(snaplist->snaps[i].parent); + deleted++; + } else if (STREQ(snaplist->snaps[i].parent, fromname)) { + VIR_FREE(snaplist->snaps[i].parent); + changed = true; + } else { + remaining = true; + } + } + if (!changed) { + ret = vshMalloc(ctl, sizeof(*snaplist)); + goto cleanup; + } + while (changed && remaining) { + changed = remaining = false; + for (i = 0; i < count; i++) { + bool found_parent = false; + int j; + + if (!names[i] || !snaplist->snaps[i].parent) + continue; + for (j = 0; j < count; j++) { + if (!names[j] || i == j) + continue; + if (STREQ(snaplist->snaps[i].parent, names[j])) { + found_parent = true; + if (!snaplist->snaps[j].parent) + VIR_FREE(snaplist->snaps[i].parent); + else + remaining = true; + break; + } + } + if (!found_parent) { + changed = true; + VIR_FREE(names[i]); + virDomainSnapshotFree(snaplist->snaps[i].snap); + snaplist->snaps[i].snap = NULL; + VIR_FREE(snaplist->snaps[i].parent); + deleted++; + } + } + } + } + +success: + qsort(snaplist->snaps, snaplist->nsnaps, sizeof(*snaplist->snaps), + vshSnapSorter); + snaplist->nsnaps -= deleted; + + ret = snaplist; + snaplist = NULL; + +cleanup: + vshSnapshotListFree(snaplist); + if (names) + for (i = 0; i < count; i++) + VIR_FREE(names[i]); + VIR_FREE(names); + return ret; +} + +static const char * +vshSnapshotListLookup(int id, bool parent, void *opaque) +{ + vshSnapshotListPtr snaplist = opaque; + if (parent) + return snaplist->snaps[id].parent; + return virDomainSnapshotGetName(snaplist->snaps[id].snap); +} + +/* + * "snapshot-list" command + */ +static const vshCmdInfo info_snapshot_list[] = { + {"help", N_("List snapshots for a domain")}, + {"desc", N_("Snapshot List")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_snapshot_list[] = { + {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, + {"parent", VSH_OT_BOOL, 0, N_("add a column showing parent snapshot")}, + {"roots", VSH_OT_BOOL, 0, N_("list only snapshots without parents")}, + {"leaves", VSH_OT_BOOL, 0, N_("list only snapshots without children")}, + {"no-leaves", VSH_OT_BOOL, 0, + N_("list only snapshots that are not leaves (with children)")}, + {"metadata", VSH_OT_BOOL, 0, + N_("list only snapshots that have metadata that would prevent undefine")}, + {"no-metadata", VSH_OT_BOOL, 0, + N_("list only snapshots that have no metadata managed by libvirt")}, + {"tree", VSH_OT_BOOL, 0, N_("list snapshots in a tree")}, + {"from", VSH_OT_DATA, 0, N_("limit list to children of given snapshot")}, + {"current", VSH_OT_BOOL, 0, + N_("limit list to children of current snapshot")}, + {"descendants", VSH_OT_BOOL, 0, N_("with --from, list all descendants")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdSnapshotList(vshControl *ctl, const vshCmd *cmd) +{ + virDomainPtr dom = NULL; + bool ret = false; + unsigned int flags = 0; + bool show_parent = false; + int i; + xmlDocPtr xml = NULL; + xmlXPathContextPtr ctxt = NULL; + char *doc = NULL; + virDomainSnapshotPtr snapshot = NULL; + char *state = NULL; + char *parent = NULL; + long long creation_longlong; + time_t creation_time_t; + char timestr[100]; + struct tm time_info; + bool tree = vshCommandOptBool(cmd, "tree"); + bool leaves = vshCommandOptBool(cmd, "leaves"); + bool no_leaves = vshCommandOptBool(cmd, "no-leaves"); + const char *from = NULL; + virDomainSnapshotPtr start = NULL; + vshSnapshotListPtr snaplist = NULL; + + if (!vshConnectionUsability(ctl, ctl->conn)) + goto cleanup; + + dom = vshCommandOptDomain(ctl, cmd, NULL); + if (dom == NULL) + goto cleanup; + + if ((vshCommandOptBool(cmd, "from") || + vshCommandOptBool(cmd, "current")) && + vshLookupSnapshot(ctl, cmd, "from", true, dom, &start, &from) < 0) + goto cleanup; + + if (vshCommandOptBool(cmd, "parent")) { + if (vshCommandOptBool(cmd, "roots")) { + vshError(ctl, "%s", + _("--parent and --roots are mutually exclusive")); + goto cleanup; + } + if (tree) { + vshError(ctl, "%s", + _("--parent and --tree are mutually exclusive")); + goto cleanup; + } + show_parent = true; + } else if (vshCommandOptBool(cmd, "roots")) { + if (tree) { + vshError(ctl, "%s", + _("--roots and --tree are mutually exclusive")); + goto cleanup; + } + if (from) { + vshError(ctl, "%s", + _("--roots and --from are mutually exclusive")); + goto cleanup; + } + flags |= VIR_DOMAIN_SNAPSHOT_LIST_ROOTS; + } + if (leaves) { + if (tree) { + vshError(ctl, "%s", + _("--leaves and --tree are mutually exclusive")); + goto cleanup; + } + flags |= VIR_DOMAIN_SNAPSHOT_LIST_LEAVES; + } + if (no_leaves) { + if (tree) { + vshError(ctl, "%s", + _("--no-leaves and --tree are mutually exclusive")); + goto cleanup; + } + flags |= VIR_DOMAIN_SNAPSHOT_LIST_NO_LEAVES; + } + + if (vshCommandOptBool(cmd, "metadata")) { + flags |= VIR_DOMAIN_SNAPSHOT_LIST_METADATA; + } + if (vshCommandOptBool(cmd, "no-metadata")) { + flags |= VIR_DOMAIN_SNAPSHOT_LIST_NO_METADATA; + } + + if (vshCommandOptBool(cmd, "descendants")) { + if (!from) { + vshError(ctl, "%s", + _("--descendants requires either --from or --current")); + goto cleanup; + } + flags |= VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS; + } + + if ((snaplist = vshSnapshotListCollect(ctl, dom, start, flags, + tree)) == NULL) + goto cleanup; + + if (!tree) { + if (show_parent) + vshPrintExtra(ctl, " %-20s %-25s %-15s %s", + _("Name"), _("Creation Time"), _("State"), + _("Parent")); + else + vshPrintExtra(ctl, " %-20s %-25s %s", + _("Name"), _("Creation Time"), _("State")); + vshPrintExtra(ctl, "\n" +"------------------------------------------------------------\n"); + } + + if (!snaplist->nsnaps) { + ret = true; + goto cleanup; + } + + if (tree) { + for (i = 0; i < snaplist->nsnaps; i++) { + if (!snaplist->snaps[i].parent && + vshTreePrint(ctl, vshSnapshotListLookup, snaplist, + snaplist->nsnaps, i) < 0) + goto cleanup; + } + ret = true; + goto cleanup; + } + + for (i = 0; i < snaplist->nsnaps; i++) { + const char *name; + + /* free up memory from previous iterations of the loop */ + VIR_FREE(parent); + VIR_FREE(state); + xmlXPathFreeContext(ctxt); + xmlFreeDoc(xml); + VIR_FREE(doc); + + snapshot = snaplist->snaps[i].snap; + name = virDomainSnapshotGetName(snapshot); + assert(name); + + doc = virDomainSnapshotGetXMLDesc(snapshot, 0); + if (!doc) + continue; + + xml = virXMLParseStringCtxt(doc, _("(domain_snapshot)"), &ctxt); + if (!xml) + continue; + + if (show_parent) + parent = virXPathString("string(/domainsnapshot/parent/name)", + ctxt); + + state = virXPathString("string(/domainsnapshot/state)", ctxt); + if (state == NULL) + continue; + if (virXPathLongLong("string(/domainsnapshot/creationTime)", ctxt, + &creation_longlong) < 0) + continue; + creation_time_t = creation_longlong; + if (creation_time_t != creation_longlong) { + vshError(ctl, "%s", _("time_t overflow")); + continue; + } + localtime_r(&creation_time_t, &time_info); + strftime(timestr, sizeof(timestr), "%Y-%m-%d %H:%M:%S %z", + &time_info); + + if (parent) + vshPrint(ctl, " %-20s %-25s %-15s %s\n", + name, timestr, state, parent); + else + vshPrint(ctl, " %-20s %-25s %s\n", name, timestr, state); + } + + ret = true; + +cleanup: + /* this frees up memory from the last iteration of the loop */ + vshSnapshotListFree(snaplist); + VIR_FREE(parent); + VIR_FREE(state); + if (start) + virDomainSnapshotFree(start); + xmlXPathFreeContext(ctxt); + xmlFreeDoc(xml); + VIR_FREE(doc); + if (dom) + virDomainFree(dom); + + return ret; +} + +/* + * "snapshot-dumpxml" command + */ +static const vshCmdInfo info_snapshot_dumpxml[] = { + {"help", N_("Dump XML for a domain snapshot")}, + {"desc", N_("Snapshot Dump XML")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_snapshot_dumpxml[] = { + {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, + {"snapshotname", VSH_OT_DATA, VSH_OFLAG_REQ, N_("snapshot name")}, + {"security-info", VSH_OT_BOOL, 0, + N_("include security sensitive information in XML dump")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdSnapshotDumpXML(vshControl *ctl, const vshCmd *cmd) +{ + virDomainPtr dom = NULL; + bool ret = false; + const char *name = NULL; + virDomainSnapshotPtr snapshot = NULL; + char *xml = NULL; + unsigned int flags = 0; + + if (vshCommandOptBool(cmd, "security-info")) + flags |= VIR_DOMAIN_XML_SECURE; + + if (!vshConnectionUsability(ctl, ctl->conn)) + goto cleanup; + + dom = vshCommandOptDomain(ctl, cmd, NULL); + if (dom == NULL) + goto cleanup; + + if (vshCommandOptString(cmd, "snapshotname", &name) <= 0) + goto cleanup; + + snapshot = virDomainSnapshotLookupByName(dom, name, 0); + if (snapshot == NULL) + goto cleanup; + + xml = virDomainSnapshotGetXMLDesc(snapshot, flags); + if (!xml) + goto cleanup; + + vshPrint(ctl, "%s", xml); + + ret = true; + +cleanup: + VIR_FREE(xml); + if (snapshot) + virDomainSnapshotFree(snapshot); + if (dom) + virDomainFree(dom); + + return ret; +} + +/* + * "snapshot-parent" command + */ +static const vshCmdInfo info_snapshot_parent[] = { + {"help", N_("Get the name of the parent of a snapshot")}, + {"desc", N_("Extract the snapshot's parent, if any")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_snapshot_parent[] = { + {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, + {"snapshotname", VSH_OT_DATA, 0, N_("find parent of snapshot name")}, + {"current", VSH_OT_BOOL, 0, N_("find parent of current snapshot")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdSnapshotParent(vshControl *ctl, const vshCmd *cmd) +{ + virDomainPtr dom = NULL; + bool ret = false; + const char *name = NULL; + virDomainSnapshotPtr snapshot = NULL; + char *parent = NULL; + + if (!vshConnectionUsability(ctl, ctl->conn)) + goto cleanup; + + dom = vshCommandOptDomain(ctl, cmd, NULL); + if (dom == NULL) + goto cleanup; + + if (vshLookupSnapshot(ctl, cmd, "snapshotname", true, dom, + &snapshot, &name) < 0) + goto cleanup; + + if (vshGetSnapshotParent(ctl, snapshot, &parent) < 0) + goto cleanup; + if (!parent) { + vshError(ctl, _("snapshot '%s' has no parent"), name); + goto cleanup; + } + + vshPrint(ctl, "%s", parent); + + ret = true; + +cleanup: + VIR_FREE(parent); + if (snapshot) + virDomainSnapshotFree(snapshot); + if (dom) + virDomainFree(dom); + + return ret; +} + +/* + * "snapshot-revert" command + */ +static const vshCmdInfo info_snapshot_revert[] = { + {"help", N_("Revert a domain to a snapshot")}, + {"desc", N_("Revert domain to snapshot")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_snapshot_revert[] = { + {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, + {"snapshotname", VSH_OT_DATA, 0, N_("snapshot name")}, + {"current", VSH_OT_BOOL, 0, N_("revert to current snapshot")}, + {"running", VSH_OT_BOOL, 0, N_("after reverting, change state to running")}, + {"paused", VSH_OT_BOOL, 0, N_("after reverting, change state to paused")}, + {"force", VSH_OT_BOOL, 0, N_("try harder on risky reverts")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdDomainSnapshotRevert(vshControl *ctl, const vshCmd *cmd) +{ + virDomainPtr dom = NULL; + bool ret = false; + const char *name = NULL; + virDomainSnapshotPtr snapshot = NULL; + unsigned int flags = 0; + bool force = false; + int result; + + if (vshCommandOptBool(cmd, "running")) + flags |= VIR_DOMAIN_SNAPSHOT_REVERT_RUNNING; + if (vshCommandOptBool(cmd, "paused")) + flags |= VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED; + /* We want virsh snapshot-revert --force to work even when talking + * to older servers that did the unsafe revert by default but + * reject the flag, so we probe without the flag, and only use it + * when the error says it will make a difference. */ + if (vshCommandOptBool(cmd, "force")) + force = true; + + if (!vshConnectionUsability(ctl, ctl->conn)) + goto cleanup; + + dom = vshCommandOptDomain(ctl, cmd, NULL); + if (dom == NULL) + goto cleanup; + + if (vshLookupSnapshot(ctl, cmd, "snapshotname", true, dom, + &snapshot, &name) < 0) + goto cleanup; + + result = virDomainRevertToSnapshot(snapshot, flags); + if (result < 0 && force && + last_error->code == VIR_ERR_SNAPSHOT_REVERT_RISKY) { + flags |= VIR_DOMAIN_SNAPSHOT_REVERT_FORCE; + virFreeError(last_error); + last_error = NULL; + result = virDomainRevertToSnapshot(snapshot, flags); + } + if (result < 0) + goto cleanup; + + ret = true; + +cleanup: + if (snapshot) + virDomainSnapshotFree(snapshot); + if (dom) + virDomainFree(dom); + + return ret; +} + +/* + * "snapshot-delete" command + */ +static const vshCmdInfo info_snapshot_delete[] = { + {"help", N_("Delete a domain snapshot")}, + {"desc", N_("Snapshot Delete")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_snapshot_delete[] = { + {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, + {"snapshotname", VSH_OT_DATA, 0, N_("snapshot name")}, + {"current", VSH_OT_BOOL, 0, N_("delete current snapshot")}, + {"children", VSH_OT_BOOL, 0, N_("delete snapshot and all children")}, + {"children-only", VSH_OT_BOOL, 0, N_("delete children but not snapshot")}, + {"metadata", VSH_OT_BOOL, 0, + N_("delete only libvirt metadata, leaving snapshot contents behind")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdSnapshotDelete(vshControl *ctl, const vshCmd *cmd) +{ + virDomainPtr dom = NULL; + bool ret = false; + const char *name = NULL; + virDomainSnapshotPtr snapshot = NULL; + unsigned int flags = 0; + + if (!vshConnectionUsability(ctl, ctl->conn)) + goto cleanup; + + dom = vshCommandOptDomain(ctl, cmd, NULL); + if (dom == NULL) + goto cleanup; + + if (vshLookupSnapshot(ctl, cmd, "snapshotname", true, dom, + &snapshot, &name) < 0) + goto cleanup; + + if (vshCommandOptBool(cmd, "children")) + flags |= VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN; + if (vshCommandOptBool(cmd, "children-only")) + flags |= VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY; + if (vshCommandOptBool(cmd, "metadata")) + flags |= VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY; + + /* XXX If we wanted, we could emulate DELETE_CHILDREN_ONLY even on + * older servers that reject the flag, by manually computing the + * list of descendants. But that's a lot of code to maintain. */ + if (virDomainSnapshotDelete(snapshot, flags) == 0) { + if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY) + vshPrint(ctl, _("Domain snapshot %s children deleted\n"), name); + else + vshPrint(ctl, _("Domain snapshot %s deleted\n"), name); + } else { + vshError(ctl, _("Failed to delete snapshot %s"), name); + goto cleanup; + } + + ret = true; + +cleanup: + if (snapshot) + virDomainSnapshotFree(snapshot); + if (dom) + virDomainFree(dom); + + return ret; +} diff --git a/tools/virsh.c b/tools/virsh.c index cddb6e3..96e9b34 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -2149,1586 +2149,6 @@ cmdQuit(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) return true; } -/* Helper for snapshot-create and snapshot-create-as */ -static bool -vshSnapshotCreate(vshControl *ctl, virDomainPtr dom, const char *buffer, - unsigned int flags, const char *from) -{ - bool ret = false; - virDomainSnapshotPtr snapshot; - bool halt = false; - char *doc = NULL; - xmlDocPtr xml = NULL; - xmlXPathContextPtr ctxt = NULL; - const char *name = NULL; - - snapshot = virDomainSnapshotCreateXML(dom, buffer, flags); - - /* Emulate --halt on older servers. */ - if (!snapshot && last_error->code == VIR_ERR_INVALID_ARG && - (flags & VIR_DOMAIN_SNAPSHOT_CREATE_HALT)) { - int persistent; - - virFreeError(last_error); - last_error = NULL; - persistent = virDomainIsPersistent(dom); - if (persistent < 0) { - virshReportError(ctl); - goto cleanup; - } - if (!persistent) { - vshError(ctl, "%s", - _("cannot halt after snapshot of transient domain")); - goto cleanup; - } - if (virDomainIsActive(dom) == 1) - halt = true; - flags &= ~VIR_DOMAIN_SNAPSHOT_CREATE_HALT; - snapshot = virDomainSnapshotCreateXML(dom, buffer, flags); - } - - if (snapshot == NULL) - goto cleanup; - - if (halt && virDomainDestroy(dom) < 0) { - virshReportError(ctl); - goto cleanup; - } - - name = virDomainSnapshotGetName(snapshot); - if (!name) { - vshError(ctl, "%s", _("Could not get snapshot name")); - goto cleanup; - } - - if (from) - vshPrint(ctl, _("Domain snapshot %s created from '%s'"), name, from); - else - vshPrint(ctl, _("Domain snapshot %s created"), name); - - ret = true; - -cleanup: - xmlXPathFreeContext(ctxt); - xmlFreeDoc(xml); - if (snapshot) - virDomainSnapshotFree(snapshot); - VIR_FREE(doc); - return ret; -} - -/* - * "snapshot-create" command - */ -static const vshCmdInfo info_snapshot_create[] = { - {"help", N_("Create a snapshot from XML")}, - {"desc", N_("Create a snapshot (disk and RAM) from XML")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_snapshot_create[] = { - {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, - {"xmlfile", VSH_OT_DATA, 0, N_("domain snapshot XML")}, - {"redefine", VSH_OT_BOOL, 0, N_("redefine metadata for existing snapshot")}, - {"current", VSH_OT_BOOL, 0, N_("with redefine, set current snapshot")}, - {"no-metadata", VSH_OT_BOOL, 0, N_("take snapshot but create no metadata")}, - {"halt", VSH_OT_BOOL, 0, N_("halt domain after snapshot is created")}, - {"disk-only", VSH_OT_BOOL, 0, N_("capture disk state but not vm state")}, - {"reuse-external", VSH_OT_BOOL, 0, N_("reuse any existing external files")}, - {"quiesce", VSH_OT_BOOL, 0, N_("quiesce guest's file systems")}, - {"atomic", VSH_OT_BOOL, 0, N_("require atomic operation")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdSnapshotCreate(vshControl *ctl, const vshCmd *cmd) -{ - virDomainPtr dom = NULL; - bool ret = false; - const char *from = NULL; - char *buffer = NULL; - unsigned int flags = 0; - - if (vshCommandOptBool(cmd, "redefine")) - flags |= VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE; - if (vshCommandOptBool(cmd, "current")) - flags |= VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT; - if (vshCommandOptBool(cmd, "no-metadata")) - flags |= VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA; - if (vshCommandOptBool(cmd, "halt")) - flags |= VIR_DOMAIN_SNAPSHOT_CREATE_HALT; - if (vshCommandOptBool(cmd, "disk-only")) - flags |= VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY; - if (vshCommandOptBool(cmd, "reuse-external")) - flags |= VIR_DOMAIN_SNAPSHOT_CREATE_REUSE_EXT; - if (vshCommandOptBool(cmd, "quiesce")) - flags |= VIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE; - if (vshCommandOptBool(cmd, "atomic")) - flags |= VIR_DOMAIN_SNAPSHOT_CREATE_ATOMIC; - - if (!vshConnectionUsability(ctl, ctl->conn)) - goto cleanup; - - dom = vshCommandOptDomain(ctl, cmd, NULL); - if (dom == NULL) - goto cleanup; - - if (vshCommandOptString(cmd, "xmlfile", &from) <= 0) - buffer = vshStrdup(ctl, "<domainsnapshot/>"); - else { - if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0) { - /* we have to report the error here because during cleanup - * we'll run through virDomainFree(), which loses the - * last error - */ - virshReportError(ctl); - goto cleanup; - } - } - if (buffer == NULL) { - vshError(ctl, "%s", _("Out of memory")); - goto cleanup; - } - - ret = vshSnapshotCreate(ctl, dom, buffer, flags, from); - -cleanup: - VIR_FREE(buffer); - if (dom) - virDomainFree(dom); - - return ret; -} - -/* - * "snapshot-create-as" command - */ -static int -vshParseSnapshotDiskspec(vshControl *ctl, virBufferPtr buf, const char *str) -{ - int ret = -1; - char *name = NULL; - char *snapshot = NULL; - char *driver = NULL; - char *file = NULL; - char *spec = vshStrdup(ctl, str); - char *tmp = spec; - size_t len = strlen(str); - - if (*str == ',') - goto cleanup; - name = tmp; - while ((tmp = strchr(tmp, ','))) { - if (tmp[1] == ',') { - /* Recognize ,, as an escape for a literal comma */ - memmove(&tmp[1], &tmp[2], len - (tmp - spec) - 2 + 1); - len--; - tmp++; - continue; - } - /* Terminate previous string, look for next recognized one */ - *tmp++ = '\0'; - if (!snapshot && STRPREFIX(tmp, "snapshot=")) - snapshot = tmp + strlen("snapshot="); - else if (!driver && STRPREFIX(tmp, "driver=")) - driver = tmp + strlen("driver="); - else if (!file && STRPREFIX(tmp, "file=")) - file = tmp + strlen("file="); - else - goto cleanup; - } - - virBufferEscapeString(buf, " <disk name='%s'", name); - if (snapshot) - virBufferAsprintf(buf, " snapshot='%s'", snapshot); - if (driver || file) { - virBufferAddLit(buf, ">\n"); - if (driver) - virBufferAsprintf(buf, " <driver type='%s'/>\n", driver); - if (file) - virBufferEscapeString(buf, " <source file='%s'/>\n", file); - virBufferAddLit(buf, " </disk>\n"); - } else { - virBufferAddLit(buf, "/>\n"); - } - ret = 0; -cleanup: - if (ret < 0) - vshError(ctl, _("unable to parse diskspec: %s"), str); - VIR_FREE(spec); - return ret; -} - -static const vshCmdInfo info_snapshot_create_as[] = { - {"help", N_("Create a snapshot from a set of args")}, - {"desc", N_("Create a snapshot (disk and RAM) from arguments")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_snapshot_create_as[] = { - {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, - {"name", VSH_OT_DATA, 0, N_("name of snapshot")}, - {"description", VSH_OT_DATA, 0, N_("description of snapshot")}, - {"print-xml", VSH_OT_BOOL, 0, N_("print XML document rather than create")}, - {"no-metadata", VSH_OT_BOOL, 0, N_("take snapshot but create no metadata")}, - {"halt", VSH_OT_BOOL, 0, N_("halt domain after snapshot is created")}, - {"disk-only", VSH_OT_BOOL, 0, N_("capture disk state but not vm state")}, - {"reuse-external", VSH_OT_BOOL, 0, N_("reuse any existing external files")}, - {"quiesce", VSH_OT_BOOL, 0, N_("quiesce guest's file systems")}, - {"atomic", VSH_OT_BOOL, 0, N_("require atomic operation")}, - {"diskspec", VSH_OT_ARGV, 0, - N_("disk attributes: disk[,snapshot=type][,driver=type][,file=name]")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdSnapshotCreateAs(vshControl *ctl, const vshCmd *cmd) -{ - virDomainPtr dom = NULL; - bool ret = false; - char *buffer = NULL; - const char *name = NULL; - const char *desc = NULL; - virBuffer buf = VIR_BUFFER_INITIALIZER; - unsigned int flags = 0; - const vshCmdOpt *opt = NULL; - - if (vshCommandOptBool(cmd, "no-metadata")) - flags |= VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA; - if (vshCommandOptBool(cmd, "halt")) - flags |= VIR_DOMAIN_SNAPSHOT_CREATE_HALT; - if (vshCommandOptBool(cmd, "disk-only")) - flags |= VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY; - if (vshCommandOptBool(cmd, "reuse-external")) - flags |= VIR_DOMAIN_SNAPSHOT_CREATE_REUSE_EXT; - if (vshCommandOptBool(cmd, "quiesce")) - flags |= VIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE; - if (vshCommandOptBool(cmd, "atomic")) - flags |= VIR_DOMAIN_SNAPSHOT_CREATE_ATOMIC; - - if (!vshConnectionUsability(ctl, ctl->conn)) - goto cleanup; - - dom = vshCommandOptDomain(ctl, cmd, NULL); - if (dom == NULL) - goto cleanup; - - if (vshCommandOptString(cmd, "name", &name) < 0 || - vshCommandOptString(cmd, "description", &desc) < 0) { - vshError(ctl, _("argument must not be empty")); - goto cleanup; - } - - virBufferAddLit(&buf, "<domainsnapshot>\n"); - if (name) - virBufferEscapeString(&buf, " <name>%s</name>\n", name); - if (desc) - virBufferEscapeString(&buf, " <description>%s</description>\n", desc); - if (vshCommandOptBool(cmd, "diskspec")) { - virBufferAddLit(&buf, " <disks>\n"); - while ((opt = vshCommandOptArgv(cmd, opt))) { - if (vshParseSnapshotDiskspec(ctl, &buf, opt->data) < 0) { - virBufferFreeAndReset(&buf); - goto cleanup; - } - } - virBufferAddLit(&buf, " </disks>\n"); - } - virBufferAddLit(&buf, "</domainsnapshot>\n"); - - buffer = virBufferContentAndReset(&buf); - if (buffer == NULL) { - vshError(ctl, "%s", _("Out of memory")); - goto cleanup; - } - - if (vshCommandOptBool(cmd, "print-xml")) { - vshPrint(ctl, "%s\n", buffer); - ret = true; - goto cleanup; - } - - ret = vshSnapshotCreate(ctl, dom, buffer, flags, NULL); - -cleanup: - VIR_FREE(buffer); - if (dom) - virDomainFree(dom); - - return ret; -} - -/* Helper for resolving {--current | --ARG name} into a snapshot - * belonging to DOM. If EXCLUSIVE, fail if both --current and arg are - * present. On success, populate *SNAP and *NAME, before returning 0. - * On failure, return -1 after issuing an error message. */ -static int -vshLookupSnapshot(vshControl *ctl, const vshCmd *cmd, - const char *arg, bool exclusive, virDomainPtr dom, - virDomainSnapshotPtr *snap, const char **name) -{ - bool current = vshCommandOptBool(cmd, "current"); - const char *snapname = NULL; - - if (vshCommandOptString(cmd, arg, &snapname) < 0) { - vshError(ctl, _("invalid argument for --%s"), arg); - return -1; - } - - if (exclusive && current && snapname) { - vshError(ctl, _("--%s and --current are mutually exclusive"), arg); - return -1; - } - - if (snapname) { - *snap = virDomainSnapshotLookupByName(dom, snapname, 0); - } else if (current) { - *snap = virDomainSnapshotCurrent(dom, 0); - } else { - vshError(ctl, _("--%s or --current is required"), arg); - return -1; - } - if (!*snap) { - virshReportError(ctl); - return -1; - } - - *name = virDomainSnapshotGetName(*snap); - return 0; -} - -/* - * "snapshot-edit" command - */ -static const vshCmdInfo info_snapshot_edit[] = { - {"help", N_("edit XML for a snapshot")}, - {"desc", N_("Edit the domain snapshot XML for a named snapshot")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_snapshot_edit[] = { - {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, - {"snapshotname", VSH_OT_DATA, 0, N_("snapshot name")}, - {"current", VSH_OT_BOOL, 0, N_("also set edited snapshot as current")}, - {"rename", VSH_OT_BOOL, 0, N_("allow renaming an existing snapshot")}, - {"clone", VSH_OT_BOOL, 0, N_("allow cloning to new name")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdSnapshotEdit(vshControl *ctl, const vshCmd *cmd) -{ - virDomainPtr dom = NULL; - virDomainSnapshotPtr snapshot = NULL; - virDomainSnapshotPtr edited = NULL; - const char *name; - const char *edited_name; - bool ret = false; - unsigned int getxml_flags = VIR_DOMAIN_XML_SECURE; - unsigned int define_flags = VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE; - bool rename_okay = vshCommandOptBool(cmd, "rename"); - bool clone_okay = vshCommandOptBool(cmd, "clone"); - - if (rename_okay && clone_okay) { - vshError(ctl, "%s", - _("--rename and --clone are mutually exclusive")); - return false; - } - - if (vshCommandOptBool(cmd, "current") && - vshCommandOptBool(cmd, "snapshotname")) - define_flags |= VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - dom = vshCommandOptDomain(ctl, cmd, NULL); - if (dom == NULL) - goto cleanup; - - if (vshLookupSnapshot(ctl, cmd, "snapshotname", false, dom, - &snapshot, &name) < 0) - goto cleanup; - -#define EDIT_GET_XML \ - virDomainSnapshotGetXMLDesc(snapshot, getxml_flags) -#define EDIT_NOT_CHANGED \ - /* Depending on flags, we re-edit even if XML is unchanged. */ \ - if (!(define_flags & VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT)) { \ - vshPrint(ctl, \ - _("Snapshot %s XML configuration not changed.\n"), \ - name); \ - ret = true; \ - goto cleanup; \ - } -#define EDIT_DEFINE \ - (strstr(doc, "<state>disk-snapshot</state>") ? \ - define_flags |= VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY : 0), \ - edited = virDomainSnapshotCreateXML(dom, doc_edited, define_flags) -#define EDIT_FREE \ - if (edited) \ - virDomainSnapshotFree(edited); -#include "virsh-edit.c" - - edited_name = virDomainSnapshotGetName(edited); - if (STREQ(name, edited_name)) { - vshPrint(ctl, _("Snapshot %s edited.\n"), name); - } else if (clone_okay) { - vshPrint(ctl, _("Snapshot %s cloned to %s.\n"), name, - edited_name); - } else { - unsigned int delete_flags; - - delete_flags = VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY; - if (virDomainSnapshotDelete(rename_okay ? snapshot : edited, - delete_flags) < 0) { - virshReportError(ctl); - vshError(ctl, _("Failed to clean up %s"), - rename_okay ? name : edited_name); - goto cleanup; - } - if (!rename_okay) { - vshError(ctl, _("Must use --rename or --clone to change %s to %s"), - name, edited_name); - goto cleanup; - } - } - - ret = true; - -cleanup: - if (edited) - virDomainSnapshotFree(edited); - else - vshError(ctl, _("Failed to update %s"), name); - if (snapshot) - virDomainSnapshotFree(snapshot); - if (dom) - virDomainFree(dom); - return ret; -} - -/* - * "snapshot-current" command - */ -static const vshCmdInfo info_snapshot_current[] = { - {"help", N_("Get or set the current snapshot")}, - {"desc", N_("Get or set the current snapshot")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_snapshot_current[] = { - {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, - {"name", VSH_OT_BOOL, 0, N_("list the name, rather than the full xml")}, - {"security-info", VSH_OT_BOOL, 0, - N_("include security sensitive information in XML dump")}, - {"snapshotname", VSH_OT_DATA, 0, - N_("name of existing snapshot to make current")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdSnapshotCurrent(vshControl *ctl, const vshCmd *cmd) -{ - virDomainPtr dom = NULL; - bool ret = false; - int current; - virDomainSnapshotPtr snapshot = NULL; - char *xml = NULL; - const char *snapshotname = NULL; - unsigned int flags = 0; - const char *domname; - - if (vshCommandOptBool(cmd, "security-info")) - flags |= VIR_DOMAIN_XML_SECURE; - - if (!vshConnectionUsability(ctl, ctl->conn)) - goto cleanup; - - dom = vshCommandOptDomain(ctl, cmd, &domname); - if (dom == NULL) - goto cleanup; - - if (vshCommandOptString(cmd, "snapshotname", &snapshotname) < 0) { - vshError(ctl, _("invalid snapshotname argument '%s'"), snapshotname); - goto cleanup; - } - if (snapshotname) { - virDomainSnapshotPtr snapshot2 = NULL; - flags = (VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE | - VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT); - - if (vshCommandOptBool(cmd, "name")) { - vshError(ctl, "%s", - _("--name and snapshotname are mutually exclusive")); - goto cleanup; - } - snapshot = virDomainSnapshotLookupByName(dom, snapshotname, 0); - if (snapshot == NULL) - goto cleanup; - xml = virDomainSnapshotGetXMLDesc(snapshot, VIR_DOMAIN_XML_SECURE); - if (!xml) - goto cleanup; - /* strstr is safe here, since xml came from libvirt API and not user */ - if (strstr(xml, "<state>disk-snapshot</state>")) - flags |= VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY; - snapshot2 = virDomainSnapshotCreateXML(dom, xml, flags); - if (snapshot2 == NULL) - goto cleanup; - virDomainSnapshotFree(snapshot2); - vshPrint(ctl, _("Snapshot %s set as current"), snapshotname); - ret = true; - goto cleanup; - } - - current = virDomainHasCurrentSnapshot(dom, 0); - if (current < 0) { - goto cleanup; - } else if (!current) { - vshError(ctl, _("domain '%s' has no current snapshot"), domname); - goto cleanup; - } else { - const char *name = NULL; - - if (!(snapshot = virDomainSnapshotCurrent(dom, 0))) - goto cleanup; - - if (vshCommandOptBool(cmd, "name")) { - name = virDomainSnapshotGetName(snapshot); - if (!name) - goto cleanup; - } else { - xml = virDomainSnapshotGetXMLDesc(snapshot, flags); - if (!xml) - goto cleanup; - } - - vshPrint(ctl, "%s", name ? name : xml); - } - - ret = true; - -cleanup: - if (!ret) - virshReportError(ctl); - VIR_FREE(xml); - if (snapshot) - virDomainSnapshotFree(snapshot); - if (dom) - virDomainFree(dom); - - return ret; -} - -/* Helper function to get the name of a snapshot's parent. Caller - * must free the result. Returns 0 on success (including when it was - * proven no parent exists), and -1 on failure with error reported - * (such as no snapshot support or domain deleted in meantime). */ -static int -vshGetSnapshotParent(vshControl *ctl, virDomainSnapshotPtr snapshot, - char **parent_name) -{ - virDomainSnapshotPtr parent = NULL; - char *xml = NULL; - xmlDocPtr xmldoc = NULL; - xmlXPathContextPtr ctxt = NULL; - int ret = -1; - - *parent_name = NULL; - - /* Try new API, since it is faster. */ - if (!ctl->useSnapshotOld) { - parent = virDomainSnapshotGetParent(snapshot, 0); - if (parent) { - /* API works, and virDomainSnapshotGetName will succeed */ - *parent_name = vshStrdup(ctl, virDomainSnapshotGetName(parent)); - ret = 0; - goto cleanup; - } - if (last_error->code == VIR_ERR_NO_DOMAIN_SNAPSHOT) { - /* API works, and we found a root with no parent */ - ret = 0; - goto cleanup; - } - /* API didn't work, fall back to XML scraping. */ - ctl->useSnapshotOld = true; - } - - xml = virDomainSnapshotGetXMLDesc(snapshot, 0); - if (!xml) - goto cleanup; - - xmldoc = virXMLParseStringCtxt(xml, _("(domain_snapshot)"), &ctxt); - if (!xmldoc) - goto cleanup; - - *parent_name = virXPathString("string(/domainsnapshot/parent/name)", ctxt); - ret = 0; - -cleanup: - if (ret < 0) { - virshReportError(ctl); - vshError(ctl, "%s", _("unable to determine if snapshot has parent")); - } else { - virFreeError(last_error); - last_error = NULL; - } - if (parent) - virDomainSnapshotFree(parent); - xmlXPathFreeContext(ctxt); - xmlFreeDoc(xmldoc); - VIR_FREE(xml); - return ret; -} - -/* - * "snapshot-info" command - */ -static const vshCmdInfo info_snapshot_info[] = { - {"help", N_("snapshot information")}, - {"desc", N_("Returns basic information about a snapshot.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_snapshot_info[] = { - {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, - {"snapshotname", VSH_OT_DATA, 0, N_("snapshot name")}, - {"current", VSH_OT_BOOL, 0, N_("info on current snapshot")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdSnapshotInfo(vshControl *ctl, const vshCmd *cmd) -{ - virDomainPtr dom; - virDomainSnapshotPtr snapshot = NULL; - const char *name; - char *doc = NULL; - char *tmp; - char *parent = NULL; - bool ret = false; - int count; - unsigned int flags; - int current; - int metadata; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - dom = vshCommandOptDomain(ctl, cmd, NULL); - if (dom == NULL) - return false; - - if (vshLookupSnapshot(ctl, cmd, "snapshotname", true, dom, - &snapshot, &name) < 0) - goto cleanup; - - vshPrint(ctl, "%-15s %s\n", _("Name:"), name); - vshPrint(ctl, "%-15s %s\n", _("Domain:"), virDomainGetName(dom)); - - /* Determine if snapshot is current; this is useful enough that we - * attempt a fallback. */ - current = virDomainSnapshotIsCurrent(snapshot, 0); - if (current < 0) { - virDomainSnapshotPtr other = virDomainSnapshotCurrent(dom, 0); - - virResetLastError(); - current = 0; - if (other) { - if (STREQ(name, virDomainSnapshotGetName(other))) - current = 1; - virDomainSnapshotFree(other); - } - } - vshPrint(ctl, "%-15s %s\n", _("Current:"), - current > 0 ? _("yes") : _("no")); - - /* Get the XML configuration of the snapshot to determine the - * state of the machine at the time of the snapshot. */ - doc = virDomainSnapshotGetXMLDesc(snapshot, 0); - if (!doc) - goto cleanup; - - tmp = strstr(doc, "<state>"); - if (!tmp) { - vshError(ctl, "%s", - _("unexpected problem reading snapshot xml")); - goto cleanup; - } - tmp += strlen("<state>"); - vshPrint(ctl, "%-15s %.*s\n", _("State:"), - (int) (strchr(tmp, '<') - tmp), tmp); - - if (vshGetSnapshotParent(ctl, snapshot, &parent) < 0) - goto cleanup; - vshPrint(ctl, "%-15s %s\n", _("Parent:"), parent ? parent : "-"); - - /* Children, Descendants. After this point, the fallback to - * compute children is too expensive, so we gracefully quit if the - * APIs don't exist. */ - if (ctl->useSnapshotOld) { - ret = true; - goto cleanup; - } - flags = 0; - count = virDomainSnapshotNumChildren(snapshot, flags); - if (count < 0) - goto cleanup; - vshPrint(ctl, "%-15s %d\n", _("Children:"), count); - flags = VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS; - count = virDomainSnapshotNumChildren(snapshot, flags); - if (count < 0) - goto cleanup; - vshPrint(ctl, "%-15s %d\n", _("Descendants:"), count); - - /* Metadata; the fallback here relies on the fact that metadata - * used to have an all-or-nothing effect on snapshot count. */ - metadata = virDomainSnapshotHasMetadata(snapshot, 0); - if (metadata < 0) { - metadata = virDomainSnapshotNum(dom, - VIR_DOMAIN_SNAPSHOT_LIST_METADATA); - virResetLastError(); - } - if (metadata >= 0) - vshPrint(ctl, "%-15s %s\n", _("Metadata:"), - metadata ? _("yes") : _("no")); - - ret = true; - -cleanup: - VIR_FREE(doc); - VIR_FREE(parent); - if (snapshot) - virDomainSnapshotFree(snapshot); - virDomainFree(dom); - return ret; -} - -/* Helpers for collecting a list of snapshots. */ -struct vshSnap { - virDomainSnapshotPtr snap; - char *parent; -}; -struct vshSnapshotList { - struct vshSnap *snaps; - int nsnaps; -}; -typedef struct vshSnapshotList *vshSnapshotListPtr; - -static void -vshSnapshotListFree(vshSnapshotListPtr snaplist) -{ - int i; - - if (!snaplist) - return; - if (snaplist->snaps) { - for (i = 0; i < snaplist->nsnaps; i++) { - if (snaplist->snaps[i].snap) - virDomainSnapshotFree(snaplist->snaps[i].snap); - VIR_FREE(snaplist->snaps[i].parent); - } - VIR_FREE(snaplist->snaps); - } - VIR_FREE(snaplist); -} - -static int -vshSnapSorter(const void *a, const void *b) -{ - const struct vshSnap *sa = a; - const struct vshSnap *sb = b; - - if (sa->snap && !sb->snap) - return -1; - if (!sa->snap) - return sb->snap != NULL; - - /* User visible sort, so we want locale-specific case comparison. */ - return strcasecmp(virDomainSnapshotGetName(sa->snap), - virDomainSnapshotGetName(sb->snap)); -} - -/* Compute a list of snapshots from DOM. If FROM is provided, the - * list is limited to descendants of the given snapshot. If FLAGS is - * given, the list is filtered. If TREE is specified, then all but - * FROM or the roots will also have parent information. */ -static vshSnapshotListPtr -vshSnapshotListCollect(vshControl *ctl, virDomainPtr dom, - virDomainSnapshotPtr from, - unsigned int flags, bool tree) -{ - int i; - char **names = NULL; - int count = -1; - bool descendants = false; - bool roots = false; - virDomainSnapshotPtr *snaps; - vshSnapshotListPtr snaplist = vshMalloc(ctl, sizeof(*snaplist)); - vshSnapshotListPtr ret = NULL; - const char *fromname = NULL; - int start_index = -1; - int deleted = 0; - - /* Try the interface available in 0.9.13 and newer. */ - if (!ctl->useSnapshotOld) { - if (from) - count = virDomainSnapshotListAllChildren(from, &snaps, flags); - else - count = virDomainListAllSnapshots(dom, &snaps, flags); - } - if (count >= 0) { - /* When mixing --from and --tree, we also want a copy of from - * in the list, but with no parent for that one entry. */ - snaplist->snaps = vshCalloc(ctl, count + (tree && from), - sizeof(*snaplist->snaps)); - snaplist->nsnaps = count; - for (i = 0; i < count; i++) - snaplist->snaps[i].snap = snaps[i]; - VIR_FREE(snaps); - if (tree) { - for (i = 0; i < count; i++) { - if (vshGetSnapshotParent(ctl, snaplist->snaps[i].snap, - &snaplist->snaps[i].parent) < 0) - goto cleanup; - } - if (from) { - snaps[snaplist->nsnaps++] = from; - virDomainSnapshotRef(from); - } - } - goto success; - } - - /* Assume that if we got this far, then the --no-leaves and - * --no-metadata flags were not supported. Disable groups that - * have no impact. */ - /* XXX should we emulate --no-leaves? */ - if (flags & VIR_DOMAIN_SNAPSHOT_LIST_NO_LEAVES && - flags & VIR_DOMAIN_SNAPSHOT_LIST_LEAVES) - flags &= ~(VIR_DOMAIN_SNAPSHOT_LIST_NO_LEAVES | - VIR_DOMAIN_SNAPSHOT_LIST_LEAVES); - if (flags & VIR_DOMAIN_SNAPSHOT_LIST_NO_METADATA && - flags & VIR_DOMAIN_SNAPSHOT_LIST_METADATA) - flags &= ~(VIR_DOMAIN_SNAPSHOT_LIST_NO_METADATA | - VIR_DOMAIN_SNAPSHOT_LIST_METADATA); - if (flags & VIR_DOMAIN_SNAPSHOT_LIST_NO_METADATA) { - /* We can emulate --no-metadata if --metadata was supported, - * since it was an all-or-none attribute on old servers. */ - count = virDomainSnapshotNum(dom, - VIR_DOMAIN_SNAPSHOT_LIST_METADATA); - if (count < 0) - goto cleanup; - if (count > 0) - return snaplist; - flags &= ~VIR_DOMAIN_SNAPSHOT_LIST_NO_METADATA; - } - - /* This uses the interfaces available in 0.8.0-0.9.6 - * (virDomainSnapshotListNames, global list only) and in - * 0.9.7-0.9.12 (addition of virDomainSnapshotListChildrenNames - * for child listing, and new flags), as follows, with [*] by the - * combinations that need parent info (either for filtering - * purposes or for the resulting tree listing): - * old new - * list global as-is global as-is - * list --roots *global + filter global + flags - * list --from *global + filter child as-is - * list --from --descendants *global + filter child + flags - * list --tree *global as-is *global as-is - * list --tree --from *global + filter *child + flags - * - * Additionally, when --tree and --from are both used, from is - * added to the final list as the only element without a parent. - * Otherwise, --from does not appear in the final list. - */ - if (from) { - fromname = virDomainSnapshotGetName(from); - if (!fromname) { - vshError(ctl, "%s", _("Could not get snapshot name")); - goto cleanup; - } - descendants = (flags & VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS) || tree; - if (tree) - flags |= VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS; - - /* Determine if we can use the new child listing API. */ - if (ctl->useSnapshotOld || - ((count = virDomainSnapshotNumChildren(from, flags)) < 0 && - last_error->code == VIR_ERR_NO_SUPPORT)) { - /* We can emulate --from. */ - /* XXX can we also emulate --leaves? */ - virFreeError(last_error); - last_error = NULL; - ctl->useSnapshotOld = true; - flags &= ~VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS; - goto global; - } - if (tree && count >= 0) - count++; - } else { - global: - /* Global listing (including fallback when --from failed with - * child listing). */ - count = virDomainSnapshotNum(dom, flags); - - /* Fall back to simulation if --roots was unsupported. */ - /* XXX can we also emulate --leaves? */ - if (!from && count < 0 && last_error->code == VIR_ERR_INVALID_ARG && - (flags & VIR_DOMAIN_SNAPSHOT_LIST_ROOTS)) { - virFreeError(last_error); - last_error = NULL; - roots = true; - flags &= ~VIR_DOMAIN_SNAPSHOT_LIST_ROOTS; - count = virDomainSnapshotNum(dom, flags); - } - } - - if (count < 0) { - if (!last_error) - vshError(ctl, _("failed to collect snapshot list")); - goto cleanup; - } - - if (!count) - goto success; - - names = vshCalloc(ctl, sizeof(*names), count); - - /* Now that we have a count, collect the list. */ - if (from && !ctl->useSnapshotOld) { - if (tree) { - if (count) - count = virDomainSnapshotListChildrenNames(from, names + 1, - count - 1, flags); - if (count >= 0) { - count++; - names[0] = vshStrdup(ctl, fromname); - } - } else { - count = virDomainSnapshotListChildrenNames(from, names, - count, flags); - } - } else { - count = virDomainSnapshotListNames(dom, names, count, flags); - } - if (count < 0) - goto cleanup; - - snaplist->snaps = vshCalloc(ctl, sizeof(*snaplist->snaps), count); - snaplist->nsnaps = count; - for (i = 0; i < count; i++) { - snaplist->snaps[i].snap = virDomainSnapshotLookupByName(dom, - names[i], 0); - if (!snaplist->snaps[i].snap) - goto cleanup; - } - - /* Collect parents when needed. With the new API, --tree and - * --from together put from as the first element without a parent; - * with the old API we still need to do a post-process filtering - * based on all parent information. */ - if (tree || (from && ctl->useSnapshotOld) || roots) { - for (i = (from && !ctl->useSnapshotOld); i < count; i++) { - if (from && ctl->useSnapshotOld && STREQ(names[i], fromname)) { - start_index = i; - if (tree) - continue; - } - if (vshGetSnapshotParent(ctl, snaplist->snaps[i].snap, - &snaplist->snaps[i].parent) < 0) - goto cleanup; - if ((from && ((tree && !snaplist->snaps[i].parent) || - (!descendants && - STRNEQ_NULLABLE(fromname, - snaplist->snaps[i].parent)))) || - (roots && snaplist->snaps[i].parent)) { - virDomainSnapshotFree(snaplist->snaps[i].snap); - snaplist->snaps[i].snap = NULL; - VIR_FREE(snaplist->snaps[i].parent); - deleted++; - } - } - } - if (tree) - goto success; - - if (ctl->useSnapshotOld && descendants) { - bool changed = false; - bool remaining = false; - - /* Make multiple passes over the list - first pass finds - * direct children and NULLs out all roots and from, remaining - * passes NULL out any undecided entry whose parent is not - * still in list. We mark known descendants by clearing - * snaps[i].parents. Sorry, this is O(n^3) - hope your - * hierarchy isn't huge. XXX Is it worth making O(n^2 log n) - * by using qsort and bsearch? */ - if (start_index < 0) { - vshError(ctl, _("snapshot %s disappeared from list"), fromname); - goto cleanup; - } - for (i = 0; i < count; i++) { - if (i == start_index || !snaplist->snaps[i].parent) { - VIR_FREE(names[i]); - virDomainSnapshotFree(snaplist->snaps[i].snap); - snaplist->snaps[i].snap = NULL; - VIR_FREE(snaplist->snaps[i].parent); - deleted++; - } else if (STREQ(snaplist->snaps[i].parent, fromname)) { - VIR_FREE(snaplist->snaps[i].parent); - changed = true; - } else { - remaining = true; - } - } - if (!changed) { - ret = vshMalloc(ctl, sizeof(*snaplist)); - goto cleanup; - } - while (changed && remaining) { - changed = remaining = false; - for (i = 0; i < count; i++) { - bool found_parent = false; - int j; - - if (!names[i] || !snaplist->snaps[i].parent) - continue; - for (j = 0; j < count; j++) { - if (!names[j] || i == j) - continue; - if (STREQ(snaplist->snaps[i].parent, names[j])) { - found_parent = true; - if (!snaplist->snaps[j].parent) - VIR_FREE(snaplist->snaps[i].parent); - else - remaining = true; - break; - } - } - if (!found_parent) { - changed = true; - VIR_FREE(names[i]); - virDomainSnapshotFree(snaplist->snaps[i].snap); - snaplist->snaps[i].snap = NULL; - VIR_FREE(snaplist->snaps[i].parent); - deleted++; - } - } - } - } - -success: - qsort(snaplist->snaps, snaplist->nsnaps, sizeof(*snaplist->snaps), - vshSnapSorter); - snaplist->nsnaps -= deleted; - - ret = snaplist; - snaplist = NULL; - -cleanup: - vshSnapshotListFree(snaplist); - if (names) - for (i = 0; i < count; i++) - VIR_FREE(names[i]); - VIR_FREE(names); - return ret; -} - -static const char * -vshSnapshotListLookup(int id, bool parent, void *opaque) -{ - vshSnapshotListPtr snaplist = opaque; - if (parent) - return snaplist->snaps[id].parent; - return virDomainSnapshotGetName(snaplist->snaps[id].snap); -} - -/* - * "snapshot-list" command - */ -static const vshCmdInfo info_snapshot_list[] = { - {"help", N_("List snapshots for a domain")}, - {"desc", N_("Snapshot List")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_snapshot_list[] = { - {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, - {"parent", VSH_OT_BOOL, 0, N_("add a column showing parent snapshot")}, - {"roots", VSH_OT_BOOL, 0, N_("list only snapshots without parents")}, - {"leaves", VSH_OT_BOOL, 0, N_("list only snapshots without children")}, - {"no-leaves", VSH_OT_BOOL, 0, - N_("list only snapshots that are not leaves (with children)")}, - {"metadata", VSH_OT_BOOL, 0, - N_("list only snapshots that have metadata that would prevent undefine")}, - {"no-metadata", VSH_OT_BOOL, 0, - N_("list only snapshots that have no metadata managed by libvirt")}, - {"tree", VSH_OT_BOOL, 0, N_("list snapshots in a tree")}, - {"from", VSH_OT_DATA, 0, N_("limit list to children of given snapshot")}, - {"current", VSH_OT_BOOL, 0, - N_("limit list to children of current snapshot")}, - {"descendants", VSH_OT_BOOL, 0, N_("with --from, list all descendants")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdSnapshotList(vshControl *ctl, const vshCmd *cmd) -{ - virDomainPtr dom = NULL; - bool ret = false; - unsigned int flags = 0; - bool show_parent = false; - int i; - xmlDocPtr xml = NULL; - xmlXPathContextPtr ctxt = NULL; - char *doc = NULL; - virDomainSnapshotPtr snapshot = NULL; - char *state = NULL; - char *parent = NULL; - long long creation_longlong; - time_t creation_time_t; - char timestr[100]; - struct tm time_info; - bool tree = vshCommandOptBool(cmd, "tree"); - bool leaves = vshCommandOptBool(cmd, "leaves"); - bool no_leaves = vshCommandOptBool(cmd, "no-leaves"); - const char *from = NULL; - virDomainSnapshotPtr start = NULL; - vshSnapshotListPtr snaplist = NULL; - - if (!vshConnectionUsability(ctl, ctl->conn)) - goto cleanup; - - dom = vshCommandOptDomain(ctl, cmd, NULL); - if (dom == NULL) - goto cleanup; - - if ((vshCommandOptBool(cmd, "from") || - vshCommandOptBool(cmd, "current")) && - vshLookupSnapshot(ctl, cmd, "from", true, dom, &start, &from) < 0) - goto cleanup; - - if (vshCommandOptBool(cmd, "parent")) { - if (vshCommandOptBool(cmd, "roots")) { - vshError(ctl, "%s", - _("--parent and --roots are mutually exclusive")); - goto cleanup; - } - if (tree) { - vshError(ctl, "%s", - _("--parent and --tree are mutually exclusive")); - goto cleanup; - } - show_parent = true; - } else if (vshCommandOptBool(cmd, "roots")) { - if (tree) { - vshError(ctl, "%s", - _("--roots and --tree are mutually exclusive")); - goto cleanup; - } - if (from) { - vshError(ctl, "%s", - _("--roots and --from are mutually exclusive")); - goto cleanup; - } - flags |= VIR_DOMAIN_SNAPSHOT_LIST_ROOTS; - } - if (leaves) { - if (tree) { - vshError(ctl, "%s", - _("--leaves and --tree are mutually exclusive")); - goto cleanup; - } - flags |= VIR_DOMAIN_SNAPSHOT_LIST_LEAVES; - } - if (no_leaves) { - if (tree) { - vshError(ctl, "%s", - _("--no-leaves and --tree are mutually exclusive")); - goto cleanup; - } - flags |= VIR_DOMAIN_SNAPSHOT_LIST_NO_LEAVES; - } - - if (vshCommandOptBool(cmd, "metadata")) { - flags |= VIR_DOMAIN_SNAPSHOT_LIST_METADATA; - } - if (vshCommandOptBool(cmd, "no-metadata")) { - flags |= VIR_DOMAIN_SNAPSHOT_LIST_NO_METADATA; - } - - if (vshCommandOptBool(cmd, "descendants")) { - if (!from) { - vshError(ctl, "%s", - _("--descendants requires either --from or --current")); - goto cleanup; - } - flags |= VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS; - } - - if ((snaplist = vshSnapshotListCollect(ctl, dom, start, flags, - tree)) == NULL) - goto cleanup; - - if (!tree) { - if (show_parent) - vshPrintExtra(ctl, " %-20s %-25s %-15s %s", - _("Name"), _("Creation Time"), _("State"), - _("Parent")); - else - vshPrintExtra(ctl, " %-20s %-25s %s", - _("Name"), _("Creation Time"), _("State")); - vshPrintExtra(ctl, "\n" -"------------------------------------------------------------\n"); - } - - if (!snaplist->nsnaps) { - ret = true; - goto cleanup; - } - - if (tree) { - for (i = 0; i < snaplist->nsnaps; i++) { - if (!snaplist->snaps[i].parent && - vshTreePrint(ctl, vshSnapshotListLookup, snaplist, - snaplist->nsnaps, i) < 0) - goto cleanup; - } - ret = true; - goto cleanup; - } - - for (i = 0; i < snaplist->nsnaps; i++) { - const char *name; - - /* free up memory from previous iterations of the loop */ - VIR_FREE(parent); - VIR_FREE(state); - xmlXPathFreeContext(ctxt); - xmlFreeDoc(xml); - VIR_FREE(doc); - - snapshot = snaplist->snaps[i].snap; - name = virDomainSnapshotGetName(snapshot); - assert(name); - - doc = virDomainSnapshotGetXMLDesc(snapshot, 0); - if (!doc) - continue; - - xml = virXMLParseStringCtxt(doc, _("(domain_snapshot)"), &ctxt); - if (!xml) - continue; - - if (show_parent) - parent = virXPathString("string(/domainsnapshot/parent/name)", - ctxt); - - state = virXPathString("string(/domainsnapshot/state)", ctxt); - if (state == NULL) - continue; - if (virXPathLongLong("string(/domainsnapshot/creationTime)", ctxt, - &creation_longlong) < 0) - continue; - creation_time_t = creation_longlong; - if (creation_time_t != creation_longlong) { - vshError(ctl, "%s", _("time_t overflow")); - continue; - } - localtime_r(&creation_time_t, &time_info); - strftime(timestr, sizeof(timestr), "%Y-%m-%d %H:%M:%S %z", - &time_info); - - if (parent) - vshPrint(ctl, " %-20s %-25s %-15s %s\n", - name, timestr, state, parent); - else - vshPrint(ctl, " %-20s %-25s %s\n", name, timestr, state); - } - - ret = true; - -cleanup: - /* this frees up memory from the last iteration of the loop */ - vshSnapshotListFree(snaplist); - VIR_FREE(parent); - VIR_FREE(state); - if (start) - virDomainSnapshotFree(start); - xmlXPathFreeContext(ctxt); - xmlFreeDoc(xml); - VIR_FREE(doc); - if (dom) - virDomainFree(dom); - - return ret; -} - -/* - * "snapshot-dumpxml" command - */ -static const vshCmdInfo info_snapshot_dumpxml[] = { - {"help", N_("Dump XML for a domain snapshot")}, - {"desc", N_("Snapshot Dump XML")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_snapshot_dumpxml[] = { - {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, - {"snapshotname", VSH_OT_DATA, VSH_OFLAG_REQ, N_("snapshot name")}, - {"security-info", VSH_OT_BOOL, 0, - N_("include security sensitive information in XML dump")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdSnapshotDumpXML(vshControl *ctl, const vshCmd *cmd) -{ - virDomainPtr dom = NULL; - bool ret = false; - const char *name = NULL; - virDomainSnapshotPtr snapshot = NULL; - char *xml = NULL; - unsigned int flags = 0; - - if (vshCommandOptBool(cmd, "security-info")) - flags |= VIR_DOMAIN_XML_SECURE; - - if (!vshConnectionUsability(ctl, ctl->conn)) - goto cleanup; - - dom = vshCommandOptDomain(ctl, cmd, NULL); - if (dom == NULL) - goto cleanup; - - if (vshCommandOptString(cmd, "snapshotname", &name) <= 0) - goto cleanup; - - snapshot = virDomainSnapshotLookupByName(dom, name, 0); - if (snapshot == NULL) - goto cleanup; - - xml = virDomainSnapshotGetXMLDesc(snapshot, flags); - if (!xml) - goto cleanup; - - vshPrint(ctl, "%s", xml); - - ret = true; - -cleanup: - VIR_FREE(xml); - if (snapshot) - virDomainSnapshotFree(snapshot); - if (dom) - virDomainFree(dom); - - return ret; -} - -/* - * "snapshot-parent" command - */ -static const vshCmdInfo info_snapshot_parent[] = { - {"help", N_("Get the name of the parent of a snapshot")}, - {"desc", N_("Extract the snapshot's parent, if any")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_snapshot_parent[] = { - {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, - {"snapshotname", VSH_OT_DATA, 0, N_("find parent of snapshot name")}, - {"current", VSH_OT_BOOL, 0, N_("find parent of current snapshot")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdSnapshotParent(vshControl *ctl, const vshCmd *cmd) -{ - virDomainPtr dom = NULL; - bool ret = false; - const char *name = NULL; - virDomainSnapshotPtr snapshot = NULL; - char *parent = NULL; - - if (!vshConnectionUsability(ctl, ctl->conn)) - goto cleanup; - - dom = vshCommandOptDomain(ctl, cmd, NULL); - if (dom == NULL) - goto cleanup; - - if (vshLookupSnapshot(ctl, cmd, "snapshotname", true, dom, - &snapshot, &name) < 0) - goto cleanup; - - if (vshGetSnapshotParent(ctl, snapshot, &parent) < 0) - goto cleanup; - if (!parent) { - vshError(ctl, _("snapshot '%s' has no parent"), name); - goto cleanup; - } - - vshPrint(ctl, "%s", parent); - - ret = true; - -cleanup: - VIR_FREE(parent); - if (snapshot) - virDomainSnapshotFree(snapshot); - if (dom) - virDomainFree(dom); - - return ret; -} - -/* - * "snapshot-revert" command - */ -static const vshCmdInfo info_snapshot_revert[] = { - {"help", N_("Revert a domain to a snapshot")}, - {"desc", N_("Revert domain to snapshot")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_snapshot_revert[] = { - {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, - {"snapshotname", VSH_OT_DATA, 0, N_("snapshot name")}, - {"current", VSH_OT_BOOL, 0, N_("revert to current snapshot")}, - {"running", VSH_OT_BOOL, 0, N_("after reverting, change state to running")}, - {"paused", VSH_OT_BOOL, 0, N_("after reverting, change state to paused")}, - {"force", VSH_OT_BOOL, 0, N_("try harder on risky reverts")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdDomainSnapshotRevert(vshControl *ctl, const vshCmd *cmd) -{ - virDomainPtr dom = NULL; - bool ret = false; - const char *name = NULL; - virDomainSnapshotPtr snapshot = NULL; - unsigned int flags = 0; - bool force = false; - int result; - - if (vshCommandOptBool(cmd, "running")) - flags |= VIR_DOMAIN_SNAPSHOT_REVERT_RUNNING; - if (vshCommandOptBool(cmd, "paused")) - flags |= VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED; - /* We want virsh snapshot-revert --force to work even when talking - * to older servers that did the unsafe revert by default but - * reject the flag, so we probe without the flag, and only use it - * when the error says it will make a difference. */ - if (vshCommandOptBool(cmd, "force")) - force = true; - - if (!vshConnectionUsability(ctl, ctl->conn)) - goto cleanup; - - dom = vshCommandOptDomain(ctl, cmd, NULL); - if (dom == NULL) - goto cleanup; - - if (vshLookupSnapshot(ctl, cmd, "snapshotname", true, dom, - &snapshot, &name) < 0) - goto cleanup; - - result = virDomainRevertToSnapshot(snapshot, flags); - if (result < 0 && force && - last_error->code == VIR_ERR_SNAPSHOT_REVERT_RISKY) { - flags |= VIR_DOMAIN_SNAPSHOT_REVERT_FORCE; - virFreeError(last_error); - last_error = NULL; - result = virDomainRevertToSnapshot(snapshot, flags); - } - if (result < 0) - goto cleanup; - - ret = true; - -cleanup: - if (snapshot) - virDomainSnapshotFree(snapshot); - if (dom) - virDomainFree(dom); - - return ret; -} - -/* - * "snapshot-delete" command - */ -static const vshCmdInfo info_snapshot_delete[] = { - {"help", N_("Delete a domain snapshot")}, - {"desc", N_("Snapshot Delete")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_snapshot_delete[] = { - {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, - {"snapshotname", VSH_OT_DATA, 0, N_("snapshot name")}, - {"current", VSH_OT_BOOL, 0, N_("delete current snapshot")}, - {"children", VSH_OT_BOOL, 0, N_("delete snapshot and all children")}, - {"children-only", VSH_OT_BOOL, 0, N_("delete children but not snapshot")}, - {"metadata", VSH_OT_BOOL, 0, - N_("delete only libvirt metadata, leaving snapshot contents behind")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdSnapshotDelete(vshControl *ctl, const vshCmd *cmd) -{ - virDomainPtr dom = NULL; - bool ret = false; - const char *name = NULL; - virDomainSnapshotPtr snapshot = NULL; - unsigned int flags = 0; - - if (!vshConnectionUsability(ctl, ctl->conn)) - goto cleanup; - - dom = vshCommandOptDomain(ctl, cmd, NULL); - if (dom == NULL) - goto cleanup; - - if (vshLookupSnapshot(ctl, cmd, "snapshotname", true, dom, - &snapshot, &name) < 0) - goto cleanup; - - if (vshCommandOptBool(cmd, "children")) - flags |= VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN; - if (vshCommandOptBool(cmd, "children-only")) - flags |= VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY; - if (vshCommandOptBool(cmd, "metadata")) - flags |= VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY; - - /* XXX If we wanted, we could emulate DELETE_CHILDREN_ONLY even on - * older servers that reject the flag, by manually computing the - * list of descendants. But that's a lot of code to maintain. */ - if (virDomainSnapshotDelete(snapshot, flags) == 0) { - if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY) - vshPrint(ctl, _("Domain snapshot %s children deleted\n"), name); - else - vshPrint(ctl, _("Domain snapshot %s deleted\n"), name); - } else { - vshError(ctl, _("Failed to delete snapshot %s"), name); - goto cleanup; - } - - ret = true; - -cleanup: - if (snapshot) - virDomainSnapshotFree(snapshot); - if (dom) - virDomainFree(dom); - - return ret; -} - /* * "qemu-monitor-command" command */ @@ -6183,6 +4603,8 @@ static const vshCmdDef virshCmds[] = { {NULL, NULL, NULL, NULL, 0} }; +#include "virsh-snapshot.c" + static const vshCmdDef snapshotCmds[] = { {"snapshot-create", cmdSnapshotCreate, opts_snapshot_create, info_snapshot_create, 0}, -- 1.7.7.3

On 07/24/12 11:18, Osier Yang wrote:
Commands to manage domain snapshot are moved from virsh.c to virsh-snapshot.c.
* virsh.c: Remove domain snapshot commands. * virsh-snapshot.c: New file, filled with domain snapshot commands. --- tools/virsh-snapshot.c | 1604 ++++++++++++++++++++++++++++++++++++++++++++++++ tools/virsh.c | 1582 +----------------------------------------------- 2 files changed, 1606 insertions(+), 1580 deletions(-) create mode 100644 tools/virsh-snapshot.c
ACK. Peter

Commands in host group moved from virsh.c to virsh-host.c, * virsh.c: Remove commands in host group. * virsh-host.c: New file, filled with commands in host group --- tools/virsh-host.c | 820 ++++++++++++++++++++++++++++++++++++++++++++++++++++ tools/virsh.c | 799 +-------------------------------------------------- 2 files changed, 822 insertions(+), 797 deletions(-) create mode 100644 tools/virsh-host.c diff --git a/tools/virsh-host.c b/tools/virsh-host.c new file mode 100644 index 0000000..c6296d3 --- /dev/null +++ b/tools/virsh-host.c @@ -0,0 +1,820 @@ +/* + * virsh-host.c: Commands in "Host and Hypervisor" group. + * + * Copyright (C) 2005, 2007-2012 Red Hat, Inc + * + * 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 + * License along with this library; If not, see + * <http://www.gnu.org/licenses/>. + * + * Daniel Veillard <veillard@redhat.com> + * Karel Zak <kzak@redhat.com> + * Daniel P. Berrange <berrange@redhat.com> + * + */ + +/* + * "capabilities" command + */ +static const vshCmdInfo info_capabilities[] = { + {"help", N_("capabilities")}, + {"desc", N_("Returns capabilities of hypervisor/driver.")}, + {NULL, NULL} +}; + +static bool +cmdCapabilities(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) +{ + char *caps; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if ((caps = virConnectGetCapabilities(ctl->conn)) == NULL) { + vshError(ctl, "%s", _("failed to get capabilities")); + return false; + } + vshPrint(ctl, "%s\n", caps); + VIR_FREE(caps); + + return true; +} + +/* + * "connect" command + */ +static const vshCmdInfo info_connect[] = { + {"help", N_("(re)connect to hypervisor")}, + {"desc", + N_("Connect to local hypervisor. This is built-in command after shell start up.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_connect[] = { + {"name", VSH_OT_DATA, VSH_OFLAG_EMPTY_OK, + N_("hypervisor connection URI")}, + {"readonly", VSH_OT_BOOL, 0, N_("read-only connection")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdConnect(vshControl *ctl, const vshCmd *cmd) +{ + bool ro = vshCommandOptBool(cmd, "readonly"); + const char *name = NULL; + + if (ctl->conn) { + int ret; + if ((ret = virConnectClose(ctl->conn)) != 0) { + vshError(ctl, _("Failed to disconnect from the hypervisor, %d leaked reference(s)"), ret); + return false; + } + ctl->conn = NULL; + } + + VIR_FREE(ctl->name); + if (vshCommandOptString(cmd, "name", &name) < 0) { + vshError(ctl, "%s", _("Please specify valid connection URI")); + return false; + } + ctl->name = vshStrdup(ctl, name); + + ctl->useGetInfo = false; + ctl->useSnapshotOld = false; + ctl->readonly = ro; + + ctl->conn = virConnectOpenAuth(ctl->name, virConnectAuthPtrDefault, + ctl->readonly ? VIR_CONNECT_RO : 0); + + if (!ctl->conn) + vshError(ctl, "%s", _("Failed to connect to the hypervisor")); + + return !!ctl->conn; +} + +/* + * "freecell" command + */ +static const vshCmdInfo info_freecell[] = { + {"help", N_("NUMA free memory")}, + {"desc", N_("display available free memory for the NUMA cell.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_freecell[] = { + {"cellno", VSH_OT_INT, 0, N_("NUMA cell number")}, + {"all", VSH_OT_BOOL, 0, N_("show free memory for all NUMA cells")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdFreecell(vshControl *ctl, const vshCmd *cmd) +{ + bool func_ret = false; + int ret; + int cell = -1, cell_given; + unsigned long long memory; + xmlNodePtr *nodes = NULL; + unsigned long nodes_cnt; + unsigned long *nodes_id = NULL; + unsigned long long *nodes_free = NULL; + int all_given; + int i; + char *cap_xml = NULL; + xmlDocPtr xml = NULL; + xmlXPathContextPtr ctxt = NULL; + + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if ( (cell_given = vshCommandOptInt(cmd, "cellno", &cell)) < 0) { + vshError(ctl, "%s", _("cell number has to be a number")); + goto cleanup; + } + all_given = vshCommandOptBool(cmd, "all"); + + if (all_given && cell_given) { + vshError(ctl, "%s", _("--cellno and --all are mutually exclusive. " + "Please choose only one.")); + goto cleanup; + } + + if (all_given) { + cap_xml = virConnectGetCapabilities(ctl->conn); + if (!cap_xml) { + vshError(ctl, "%s", _("unable to get node capabilities")); + goto cleanup; + } + + xml = virXMLParseStringCtxt(cap_xml, _("(capabilities)"), &ctxt); + if (!xml) { + vshError(ctl, "%s", _("unable to get node capabilities")); + goto cleanup; + } + nodes_cnt = virXPathNodeSet("/capabilities/host/topology/cells/cell", + ctxt, &nodes); + + if (nodes_cnt == -1) { + vshError(ctl, "%s", _("could not get information about " + "NUMA topology")); + goto cleanup; + } + + nodes_free = vshCalloc(ctl, nodes_cnt, sizeof(*nodes_free)); + nodes_id = vshCalloc(ctl, nodes_cnt, sizeof(*nodes_id)); + + for (i = 0; i < nodes_cnt; i++) { + unsigned long id; + char *val = virXMLPropString(nodes[i], "id"); + if (virStrToLong_ul(val, NULL, 10, &id)) { + vshError(ctl, "%s", _("conversion from string failed")); + VIR_FREE(val); + goto cleanup; + } + VIR_FREE(val); + nodes_id[i]=id; + ret = virNodeGetCellsFreeMemory(ctl->conn, &(nodes_free[i]), id, 1); + if (ret != 1) { + vshError(ctl, _("failed to get free memory for NUMA node " + "number: %lu"), id); + goto cleanup; + } + } + + memory = 0; + for (cell = 0; cell < nodes_cnt; cell++) { + vshPrint(ctl, "%5lu: %10llu KiB\n", nodes_id[cell], + (nodes_free[cell]/1024)); + memory += nodes_free[cell]; + } + + vshPrintExtra(ctl, "--------------------\n"); + vshPrintExtra(ctl, "%5s: %10llu KiB\n", _("Total"), memory/1024); + } else { + if (!cell_given) { + memory = virNodeGetFreeMemory(ctl->conn); + if (memory == 0) + goto cleanup; + } else { + ret = virNodeGetCellsFreeMemory(ctl->conn, &memory, cell, 1); + if (ret != 1) + goto cleanup; + } + + if (cell == -1) + vshPrint(ctl, "%s: %llu KiB\n", _("Total"), (memory/1024)); + else + vshPrint(ctl, "%d: %llu KiB\n", cell, (memory/1024)); + } + + func_ret = true; + +cleanup: + xmlXPathFreeContext(ctxt); + xmlFreeDoc(xml); + VIR_FREE(nodes); + VIR_FREE(nodes_free); + VIR_FREE(nodes_id); + VIR_FREE(cap_xml); + return func_ret; +} + +/* + * "nodeinfo" command + */ +static const vshCmdInfo info_nodeinfo[] = { + {"help", N_("node information")}, + {"desc", N_("Returns basic information about the node.")}, + {NULL, NULL} +}; + +static bool +cmdNodeinfo(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) +{ + virNodeInfo info; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (virNodeGetInfo(ctl->conn, &info) < 0) { + vshError(ctl, "%s", _("failed to get node information")); + return false; + } + vshPrint(ctl, "%-20s %s\n", _("CPU model:"), info.model); + vshPrint(ctl, "%-20s %d\n", _("CPU(s):"), info.cpus); + vshPrint(ctl, "%-20s %d MHz\n", _("CPU frequency:"), info.mhz); + vshPrint(ctl, "%-20s %d\n", _("CPU socket(s):"), info.sockets); + vshPrint(ctl, "%-20s %d\n", _("Core(s) per socket:"), info.cores); + vshPrint(ctl, "%-20s %d\n", _("Thread(s) per core:"), info.threads); + vshPrint(ctl, "%-20s %d\n", _("NUMA cell(s):"), info.nodes); + vshPrint(ctl, "%-20s %lu KiB\n", _("Memory size:"), info.memory); + + return true; +} + +/* + * "nodecpustats" command + */ +static const vshCmdInfo info_nodecpustats[] = { + {"help", N_("Prints cpu stats of the node.")}, + {"desc", N_("Returns cpu stats of the node, in nanoseconds.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_node_cpustats[] = { + {"cpu", VSH_OT_INT, 0, N_("prints specified cpu statistics only.")}, + {"percent", VSH_OT_BOOL, 0, N_("prints by percentage during 1 second.")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdNodeCpuStats(vshControl *ctl, const vshCmd *cmd) +{ + int i, j; + bool flag_utilization = false; + bool flag_percent = vshCommandOptBool(cmd, "percent"); + int cpuNum = VIR_NODE_CPU_STATS_ALL_CPUS; + virNodeCPUStatsPtr params; + int nparams = 0; + bool ret = false; + struct cpu_stats { + unsigned long long user; + unsigned long long sys; + unsigned long long idle; + unsigned long long iowait; + unsigned long long util; + } cpu_stats[2]; + double user_time, sys_time, idle_time, iowait_time, total_time; + double usage; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (vshCommandOptInt(cmd, "cpu", &cpuNum) < 0) { + vshError(ctl, "%s", _("Invalid value of cpuNum")); + return false; + } + + if (virNodeGetCPUStats(ctl->conn, cpuNum, NULL, &nparams, 0) != 0) { + vshError(ctl, "%s", + _("Unable to get number of cpu stats")); + return false; + } + if (nparams == 0) { + /* nothing to output */ + return true; + } + + memset(cpu_stats, 0, sizeof(cpu_stats)); + params = vshCalloc(ctl, nparams, sizeof(*params)); + + for (i = 0; i < 2; i++) { + if (i > 0) + sleep(1); + + if (virNodeGetCPUStats(ctl->conn, cpuNum, params, &nparams, 0) != 0) { + vshError(ctl, "%s", _("Unable to get node cpu stats")); + goto cleanup; + } + + for (j = 0; j < nparams; j++) { + unsigned long long value = params[j].value; + + if (STREQ(params[j].field, VIR_NODE_CPU_STATS_KERNEL)) { + cpu_stats[i].sys = value; + } else if (STREQ(params[j].field, VIR_NODE_CPU_STATS_USER)) { + cpu_stats[i].user = value; + } else if (STREQ(params[j].field, VIR_NODE_CPU_STATS_IDLE)) { + cpu_stats[i].idle = value; + } else if (STREQ(params[j].field, VIR_NODE_CPU_STATS_IOWAIT)) { + cpu_stats[i].iowait = value; + } else if (STREQ(params[j].field, VIR_NODE_CPU_STATS_UTILIZATION)) { + cpu_stats[i].util = value; + flag_utilization = true; + } + } + + if (flag_utilization || !flag_percent) + break; + } + + if (!flag_percent) { + if (!flag_utilization) { + vshPrint(ctl, "%-15s %20llu\n", _("user:"), cpu_stats[0].user); + vshPrint(ctl, "%-15s %20llu\n", _("system:"), cpu_stats[0].sys); + vshPrint(ctl, "%-15s %20llu\n", _("idle:"), cpu_stats[0].idle); + vshPrint(ctl, "%-15s %20llu\n", _("iowait:"), cpu_stats[0].iowait); + } + } else { + if (flag_utilization) { + usage = cpu_stats[0].util; + + vshPrint(ctl, "%-15s %5.1lf%%\n", _("usage:"), usage); + vshPrint(ctl, "%-15s %5.1lf%%\n", _("idle:"), 100 - usage); + } else { + user_time = cpu_stats[1].user - cpu_stats[0].user; + sys_time = cpu_stats[1].sys - cpu_stats[0].sys; + idle_time = cpu_stats[1].idle - cpu_stats[0].idle; + iowait_time = cpu_stats[1].iowait - cpu_stats[0].iowait; + total_time = user_time + sys_time + idle_time + iowait_time; + + usage = (user_time + sys_time) / total_time * 100; + + vshPrint(ctl, "%-15s %5.1lf%%\n", + _("usage:"), usage); + vshPrint(ctl, "%-15s %5.1lf%%\n", + _("user:"), user_time / total_time * 100); + vshPrint(ctl, "%-15s %5.1lf%%\n", + _("system:"), sys_time / total_time * 100); + vshPrint(ctl, "%-15s %5.1lf%%\n", + _("idle:"), idle_time / total_time * 100); + vshPrint(ctl, "%-15s %5.1lf%%\n", + _("iowait:"), iowait_time / total_time * 100); + } + } + + ret = true; + + cleanup: + VIR_FREE(params); + return ret; +} + +/* + * "nodememstats" command + */ +static const vshCmdInfo info_nodememstats[] = { + {"help", N_("Prints memory stats of the node.")}, + {"desc", N_("Returns memory stats of the node, in kilobytes.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_node_memstats[] = { + {"cell", VSH_OT_INT, 0, N_("prints specified cell statistics only.")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdNodeMemStats(vshControl *ctl, const vshCmd *cmd) +{ + int nparams = 0; + unsigned int i = 0; + int cellNum = VIR_NODE_MEMORY_STATS_ALL_CELLS; + virNodeMemoryStatsPtr params = NULL; + bool ret = false; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (vshCommandOptInt(cmd, "cell", &cellNum) < 0) { + vshError(ctl, "%s", _("Invalid value of cellNum")); + return false; + } + + /* get the number of memory parameters */ + if (virNodeGetMemoryStats(ctl->conn, cellNum, NULL, &nparams, 0) != 0) { + vshError(ctl, "%s", + _("Unable to get number of memory stats")); + goto cleanup; + } + + if (nparams == 0) { + /* nothing to output */ + ret = true; + goto cleanup; + } + + /* now go get all the memory parameters */ + params = vshCalloc(ctl, nparams, sizeof(*params)); + if (virNodeGetMemoryStats(ctl->conn, cellNum, params, &nparams, 0) != 0) { + vshError(ctl, "%s", _("Unable to get memory stats")); + goto cleanup; + } + + for (i = 0; i < nparams; i++) + vshPrint(ctl, "%-7s: %20llu KiB\n", params[i].field, params[i].value); + + ret = true; + + cleanup: + VIR_FREE(params); + return ret; +} + +/* + * "nodesuspend" command + */ +static const vshCmdInfo info_nodesuspend[] = { + {"help", N_("suspend the host node for a given time duration")}, + {"desc", N_("Suspend the host node for a given time duration " + "and attempt to resume thereafter.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_node_suspend[] = { + {"target", VSH_OT_DATA, VSH_OFLAG_REQ, N_("mem(Suspend-to-RAM), " + "disk(Suspend-to-Disk), hybrid(Hybrid-Suspend)")}, + {"duration", VSH_OT_INT, VSH_OFLAG_REQ, N_("Suspend duration in seconds")}, + {"flags", VSH_OT_INT, VSH_OFLAG_NONE, N_("Suspend flags, 0 for default")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdNodeSuspend(vshControl *ctl, const vshCmd *cmd) +{ + const char *target = NULL; + unsigned int suspendTarget; + long long duration; + unsigned int flags = 0; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (vshCommandOptString(cmd, "target", &target) < 0) { + vshError(ctl, _("Invalid target argument")); + return false; + } + + if (vshCommandOptLongLong(cmd, "duration", &duration) < 0) { + vshError(ctl, _("Invalid duration argument")); + return false; + } + + if (vshCommandOptUInt(cmd, "flags", &flags) < 0) { + vshError(ctl, _("Invalid flags argument")); + return false; + } + + if (STREQ(target, "mem")) + suspendTarget = VIR_NODE_SUSPEND_TARGET_MEM; + else if (STREQ(target, "disk")) + suspendTarget = VIR_NODE_SUSPEND_TARGET_DISK; + else if (STREQ(target, "hybrid")) + suspendTarget = VIR_NODE_SUSPEND_TARGET_HYBRID; + else { + vshError(ctl, "%s", _("Invalid target")); + return false; + } + + if (duration <= 0) { + vshError(ctl, "%s", _("Invalid duration")); + return false; + } + + if (virNodeSuspendForDuration(ctl->conn, suspendTarget, duration, + flags) < 0) { + vshError(ctl, "%s", _("The host was not suspended")); + return false; + } + return true; +} + +/* + * "qemu-monitor-command" command + */ +static const vshCmdInfo info_qemu_monitor_command[] = { + {"help", N_("QEMU Monitor Command")}, + {"desc", N_("QEMU Monitor Command")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_qemu_monitor_command[] = { + {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, + {"hmp", VSH_OT_BOOL, 0, N_("command is in human monitor protocol")}, + {"cmd", VSH_OT_ARGV, VSH_OFLAG_REQ, N_("command")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdQemuMonitorCommand(vshControl *ctl, const vshCmd *cmd) +{ + virDomainPtr dom = NULL; + bool ret = false; + char *monitor_cmd = NULL; + char *result = NULL; + unsigned int flags = 0; + const vshCmdOpt *opt = NULL; + virBuffer buf = VIR_BUFFER_INITIALIZER; + bool pad = false; + + if (!vshConnectionUsability(ctl, ctl->conn)) + goto cleanup; + + dom = vshCommandOptDomain(ctl, cmd, NULL); + if (dom == NULL) + goto cleanup; + + while ((opt = vshCommandOptArgv(cmd, opt))) { + if (pad) + virBufferAddChar(&buf, ' '); + pad = true; + virBufferAdd(&buf, opt->data, -1); + } + if (virBufferError(&buf)) { + vshPrint(ctl, "%s", _("Failed to collect command")); + goto cleanup; + } + monitor_cmd = virBufferContentAndReset(&buf); + + if (vshCommandOptBool(cmd, "hmp")) + flags |= VIR_DOMAIN_QEMU_MONITOR_COMMAND_HMP; + + if (virDomainQemuMonitorCommand(dom, monitor_cmd, &result, flags) < 0) + goto cleanup; + + printf("%s\n", result); + + ret = true; + +cleanup: + VIR_FREE(result); + VIR_FREE(monitor_cmd); + if (dom) + virDomainFree(dom); + + return ret; +} + +/* + * "qemu-attach" command + */ +static const vshCmdInfo info_qemu_attach[] = { + {"help", N_("QEMU Attach")}, + {"desc", N_("QEMU Attach")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_qemu_attach[] = { + {"pid", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pid")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdQemuAttach(vshControl *ctl, const vshCmd *cmd) +{ + virDomainPtr dom = NULL; + bool ret = false; + unsigned int flags = 0; + unsigned int pid_value; /* API uses unsigned int, not pid_t */ + + if (!vshConnectionUsability(ctl, ctl->conn)) + goto cleanup; + + if (vshCommandOptUInt(cmd, "pid", &pid_value) <= 0) { + vshError(ctl, "%s", _("missing pid value")); + goto cleanup; + } + + if (!(dom = virDomainQemuAttach(ctl->conn, pid_value, flags))) + goto cleanup; + + if (dom != NULL) { + vshPrint(ctl, _("Domain %s attached to pid %u\n"), + virDomainGetName(dom), pid_value); + virDomainFree(dom); + ret = true; + } else { + vshError(ctl, _("Failed to attach to pid %u"), pid_value); + } + +cleanup: + return ret; +} + +/* + * "sysinfo" command + */ +static const vshCmdInfo info_sysinfo[] = { + {"help", N_("print the hypervisor sysinfo")}, + {"desc", + N_("output an XML string for the hypervisor sysinfo, if available")}, + {NULL, NULL} +}; + +static bool +cmdSysinfo(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) +{ + char *sysinfo; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + sysinfo = virConnectGetSysinfo(ctl->conn, 0); + if (sysinfo == NULL) { + vshError(ctl, "%s", _("failed to get sysinfo")); + return false; + } + + vshPrint(ctl, "%s", sysinfo); + VIR_FREE(sysinfo); + + return true; +} + +/* + * "hostname" command + */ +static const vshCmdInfo info_hostname[] = { + {"help", N_("print the hypervisor hostname")}, + {"desc", ""}, + {NULL, NULL} +}; + +static bool +cmdHostname(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) +{ + char *hostname; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + hostname = virConnectGetHostname(ctl->conn); + if (hostname == NULL) { + vshError(ctl, "%s", _("failed to get hostname")); + return false; + } + + vshPrint (ctl, "%s\n", hostname); + VIR_FREE(hostname); + + return true; +} + +/* + * "uri" command + */ +static const vshCmdInfo info_uri[] = { + {"help", N_("print the hypervisor canonical URI")}, + {"desc", ""}, + {NULL, NULL} +}; + +static bool +cmdURI(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) +{ + char *uri; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + uri = virConnectGetURI(ctl->conn); + if (uri == NULL) { + vshError(ctl, "%s", _("failed to get URI")); + return false; + } + + vshPrint(ctl, "%s\n", uri); + VIR_FREE(uri); + + return true; +} + +/* + * "version" command + */ +static const vshCmdInfo info_version[] = { + {"help", N_("show version")}, + {"desc", N_("Display the system version information.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_version[] = { + {"daemon", VSH_OT_BOOL, VSH_OFLAG_NONE, N_("report daemon version too")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdVersion(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) +{ + unsigned long hvVersion; + const char *hvType; + unsigned long libVersion; + unsigned long includeVersion; + unsigned long apiVersion; + unsigned long daemonVersion; + int ret; + unsigned int major; + unsigned int minor; + unsigned int rel; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + hvType = virConnectGetType(ctl->conn); + if (hvType == NULL) { + vshError(ctl, "%s", _("failed to get hypervisor type")); + return false; + } + + includeVersion = LIBVIR_VERSION_NUMBER; + major = includeVersion / 1000000; + includeVersion %= 1000000; + minor = includeVersion / 1000; + rel = includeVersion % 1000; + vshPrint(ctl, _("Compiled against library: libvir %d.%d.%d\n"), + major, minor, rel); + + ret = virGetVersion(&libVersion, hvType, &apiVersion); + if (ret < 0) { + vshError(ctl, "%s", _("failed to get the library version")); + return false; + } + major = libVersion / 1000000; + libVersion %= 1000000; + minor = libVersion / 1000; + rel = libVersion % 1000; + vshPrint(ctl, _("Using library: libvir %d.%d.%d\n"), + major, minor, rel); + + major = apiVersion / 1000000; + apiVersion %= 1000000; + minor = apiVersion / 1000; + rel = apiVersion % 1000; + vshPrint(ctl, _("Using API: %s %d.%d.%d\n"), hvType, + major, minor, rel); + + ret = virConnectGetVersion(ctl->conn, &hvVersion); + if (ret < 0) { + vshError(ctl, "%s", _("failed to get the hypervisor version")); + return false; + } + if (hvVersion == 0) { + vshPrint(ctl, + _("Cannot extract running %s hypervisor version\n"), hvType); + } else { + major = hvVersion / 1000000; + hvVersion %= 1000000; + minor = hvVersion / 1000; + rel = hvVersion % 1000; + + vshPrint(ctl, _("Running hypervisor: %s %d.%d.%d\n"), + hvType, major, minor, rel); + } + + if (vshCommandOptBool(cmd, "daemon")) { + ret = virConnectGetLibVersion(ctl->conn, &daemonVersion); + if (ret < 0) { + vshError(ctl, "%s", _("failed to get the daemon version")); + } else { + major = daemonVersion / 1000000; + daemonVersion %= 1000000; + minor = daemonVersion / 1000; + rel = daemonVersion % 1000; + vshPrint(ctl, _("Running against daemon: %d.%d.%d\n"), + major, minor, rel); + } + } + + return true; +} diff --git a/tools/virsh.c b/tools/virsh.c index 96e9b34..1d878b9 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -747,504 +747,6 @@ cmdHelp(vshControl *ctl, const vshCmd *cmd) } /* - * "connect" command - */ -static const vshCmdInfo info_connect[] = { - {"help", N_("(re)connect to hypervisor")}, - {"desc", - N_("Connect to local hypervisor. This is built-in command after shell start up.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_connect[] = { - {"name", VSH_OT_DATA, VSH_OFLAG_EMPTY_OK, - N_("hypervisor connection URI")}, - {"readonly", VSH_OT_BOOL, 0, N_("read-only connection")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdConnect(vshControl *ctl, const vshCmd *cmd) -{ - bool ro = vshCommandOptBool(cmd, "readonly"); - const char *name = NULL; - - if (ctl->conn) { - int ret; - if ((ret = virConnectClose(ctl->conn)) != 0) { - vshError(ctl, _("Failed to disconnect from the hypervisor, %d leaked reference(s)"), ret); - return false; - } - ctl->conn = NULL; - } - - VIR_FREE(ctl->name); - if (vshCommandOptString(cmd, "name", &name) < 0) { - vshError(ctl, "%s", _("Please specify valid connection URI")); - return false; - } - ctl->name = vshStrdup(ctl, name); - - ctl->useGetInfo = false; - ctl->useSnapshotOld = false; - ctl->readonly = ro; - - ctl->conn = virConnectOpenAuth(ctl->name, virConnectAuthPtrDefault, - ctl->readonly ? VIR_CONNECT_RO : 0); - - if (!ctl->conn) - vshError(ctl, "%s", _("Failed to connect to the hypervisor")); - - return !!ctl->conn; -} - -/* - * "freecell" command - */ -static const vshCmdInfo info_freecell[] = { - {"help", N_("NUMA free memory")}, - {"desc", N_("display available free memory for the NUMA cell.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_freecell[] = { - {"cellno", VSH_OT_INT, 0, N_("NUMA cell number")}, - {"all", VSH_OT_BOOL, 0, N_("show free memory for all NUMA cells")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdFreecell(vshControl *ctl, const vshCmd *cmd) -{ - bool func_ret = false; - int ret; - int cell = -1, cell_given; - unsigned long long memory; - xmlNodePtr *nodes = NULL; - unsigned long nodes_cnt; - unsigned long *nodes_id = NULL; - unsigned long long *nodes_free = NULL; - int all_given; - int i; - char *cap_xml = NULL; - xmlDocPtr xml = NULL; - xmlXPathContextPtr ctxt = NULL; - - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if ( (cell_given = vshCommandOptInt(cmd, "cellno", &cell)) < 0) { - vshError(ctl, "%s", _("cell number has to be a number")); - goto cleanup; - } - all_given = vshCommandOptBool(cmd, "all"); - - if (all_given && cell_given) { - vshError(ctl, "%s", _("--cellno and --all are mutually exclusive. " - "Please choose only one.")); - goto cleanup; - } - - if (all_given) { - cap_xml = virConnectGetCapabilities(ctl->conn); - if (!cap_xml) { - vshError(ctl, "%s", _("unable to get node capabilities")); - goto cleanup; - } - - xml = virXMLParseStringCtxt(cap_xml, _("(capabilities)"), &ctxt); - if (!xml) { - vshError(ctl, "%s", _("unable to get node capabilities")); - goto cleanup; - } - nodes_cnt = virXPathNodeSet("/capabilities/host/topology/cells/cell", - ctxt, &nodes); - - if (nodes_cnt == -1) { - vshError(ctl, "%s", _("could not get information about " - "NUMA topology")); - goto cleanup; - } - - nodes_free = vshCalloc(ctl, nodes_cnt, sizeof(*nodes_free)); - nodes_id = vshCalloc(ctl, nodes_cnt, sizeof(*nodes_id)); - - for (i = 0; i < nodes_cnt; i++) { - unsigned long id; - char *val = virXMLPropString(nodes[i], "id"); - if (virStrToLong_ul(val, NULL, 10, &id)) { - vshError(ctl, "%s", _("conversion from string failed")); - VIR_FREE(val); - goto cleanup; - } - VIR_FREE(val); - nodes_id[i]=id; - ret = virNodeGetCellsFreeMemory(ctl->conn, &(nodes_free[i]), id, 1); - if (ret != 1) { - vshError(ctl, _("failed to get free memory for NUMA node " - "number: %lu"), id); - goto cleanup; - } - } - - memory = 0; - for (cell = 0; cell < nodes_cnt; cell++) { - vshPrint(ctl, "%5lu: %10llu KiB\n", nodes_id[cell], - (nodes_free[cell]/1024)); - memory += nodes_free[cell]; - } - - vshPrintExtra(ctl, "--------------------\n"); - vshPrintExtra(ctl, "%5s: %10llu KiB\n", _("Total"), memory/1024); - } else { - if (!cell_given) { - memory = virNodeGetFreeMemory(ctl->conn); - if (memory == 0) - goto cleanup; - } else { - ret = virNodeGetCellsFreeMemory(ctl->conn, &memory, cell, 1); - if (ret != 1) - goto cleanup; - } - - if (cell == -1) - vshPrint(ctl, "%s: %llu KiB\n", _("Total"), (memory/1024)); - else - vshPrint(ctl, "%d: %llu KiB\n", cell, (memory/1024)); - } - - func_ret = true; - -cleanup: - xmlXPathFreeContext(ctxt); - xmlFreeDoc(xml); - VIR_FREE(nodes); - VIR_FREE(nodes_free); - VIR_FREE(nodes_id); - VIR_FREE(cap_xml); - return func_ret; -} - -/* - * "nodeinfo" command - */ -static const vshCmdInfo info_nodeinfo[] = { - {"help", N_("node information")}, - {"desc", N_("Returns basic information about the node.")}, - {NULL, NULL} -}; - -static bool -cmdNodeinfo(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) -{ - virNodeInfo info; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (virNodeGetInfo(ctl->conn, &info) < 0) { - vshError(ctl, "%s", _("failed to get node information")); - return false; - } - vshPrint(ctl, "%-20s %s\n", _("CPU model:"), info.model); - vshPrint(ctl, "%-20s %d\n", _("CPU(s):"), info.cpus); - vshPrint(ctl, "%-20s %d MHz\n", _("CPU frequency:"), info.mhz); - vshPrint(ctl, "%-20s %d\n", _("CPU socket(s):"), info.sockets); - vshPrint(ctl, "%-20s %d\n", _("Core(s) per socket:"), info.cores); - vshPrint(ctl, "%-20s %d\n", _("Thread(s) per core:"), info.threads); - vshPrint(ctl, "%-20s %d\n", _("NUMA cell(s):"), info.nodes); - vshPrint(ctl, "%-20s %lu KiB\n", _("Memory size:"), info.memory); - - return true; -} - -/* - * "nodecpustats" command - */ -static const vshCmdInfo info_nodecpustats[] = { - {"help", N_("Prints cpu stats of the node.")}, - {"desc", N_("Returns cpu stats of the node, in nanoseconds.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_node_cpustats[] = { - {"cpu", VSH_OT_INT, 0, N_("prints specified cpu statistics only.")}, - {"percent", VSH_OT_BOOL, 0, N_("prints by percentage during 1 second.")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdNodeCpuStats(vshControl *ctl, const vshCmd *cmd) -{ - int i, j; - bool flag_utilization = false; - bool flag_percent = vshCommandOptBool(cmd, "percent"); - int cpuNum = VIR_NODE_CPU_STATS_ALL_CPUS; - virNodeCPUStatsPtr params; - int nparams = 0; - bool ret = false; - struct cpu_stats { - unsigned long long user; - unsigned long long sys; - unsigned long long idle; - unsigned long long iowait; - unsigned long long util; - } cpu_stats[2]; - double user_time, sys_time, idle_time, iowait_time, total_time; - double usage; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (vshCommandOptInt(cmd, "cpu", &cpuNum) < 0) { - vshError(ctl, "%s", _("Invalid value of cpuNum")); - return false; - } - - if (virNodeGetCPUStats(ctl->conn, cpuNum, NULL, &nparams, 0) != 0) { - vshError(ctl, "%s", - _("Unable to get number of cpu stats")); - return false; - } - if (nparams == 0) { - /* nothing to output */ - return true; - } - - memset(cpu_stats, 0, sizeof(cpu_stats)); - params = vshCalloc(ctl, nparams, sizeof(*params)); - - for (i = 0; i < 2; i++) { - if (i > 0) - sleep(1); - - if (virNodeGetCPUStats(ctl->conn, cpuNum, params, &nparams, 0) != 0) { - vshError(ctl, "%s", _("Unable to get node cpu stats")); - goto cleanup; - } - - for (j = 0; j < nparams; j++) { - unsigned long long value = params[j].value; - - if (STREQ(params[j].field, VIR_NODE_CPU_STATS_KERNEL)) { - cpu_stats[i].sys = value; - } else if (STREQ(params[j].field, VIR_NODE_CPU_STATS_USER)) { - cpu_stats[i].user = value; - } else if (STREQ(params[j].field, VIR_NODE_CPU_STATS_IDLE)) { - cpu_stats[i].idle = value; - } else if (STREQ(params[j].field, VIR_NODE_CPU_STATS_IOWAIT)) { - cpu_stats[i].iowait = value; - } else if (STREQ(params[j].field, VIR_NODE_CPU_STATS_UTILIZATION)) { - cpu_stats[i].util = value; - flag_utilization = true; - } - } - - if (flag_utilization || !flag_percent) - break; - } - - if (!flag_percent) { - if (!flag_utilization) { - vshPrint(ctl, "%-15s %20llu\n", _("user:"), cpu_stats[0].user); - vshPrint(ctl, "%-15s %20llu\n", _("system:"), cpu_stats[0].sys); - vshPrint(ctl, "%-15s %20llu\n", _("idle:"), cpu_stats[0].idle); - vshPrint(ctl, "%-15s %20llu\n", _("iowait:"), cpu_stats[0].iowait); - } - } else { - if (flag_utilization) { - usage = cpu_stats[0].util; - - vshPrint(ctl, "%-15s %5.1lf%%\n", _("usage:"), usage); - vshPrint(ctl, "%-15s %5.1lf%%\n", _("idle:"), 100 - usage); - } else { - user_time = cpu_stats[1].user - cpu_stats[0].user; - sys_time = cpu_stats[1].sys - cpu_stats[0].sys; - idle_time = cpu_stats[1].idle - cpu_stats[0].idle; - iowait_time = cpu_stats[1].iowait - cpu_stats[0].iowait; - total_time = user_time + sys_time + idle_time + iowait_time; - - usage = (user_time + sys_time) / total_time * 100; - - vshPrint(ctl, "%-15s %5.1lf%%\n", - _("usage:"), usage); - vshPrint(ctl, "%-15s %5.1lf%%\n", - _("user:"), user_time / total_time * 100); - vshPrint(ctl, "%-15s %5.1lf%%\n", - _("system:"), sys_time / total_time * 100); - vshPrint(ctl, "%-15s %5.1lf%%\n", - _("idle:"), idle_time / total_time * 100); - vshPrint(ctl, "%-15s %5.1lf%%\n", - _("iowait:"), iowait_time / total_time * 100); - } - } - - ret = true; - - cleanup: - VIR_FREE(params); - return ret; -} - -/* - * "nodememstats" command - */ -static const vshCmdInfo info_nodememstats[] = { - {"help", N_("Prints memory stats of the node.")}, - {"desc", N_("Returns memory stats of the node, in kilobytes.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_node_memstats[] = { - {"cell", VSH_OT_INT, 0, N_("prints specified cell statistics only.")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdNodeMemStats(vshControl *ctl, const vshCmd *cmd) -{ - int nparams = 0; - unsigned int i = 0; - int cellNum = VIR_NODE_MEMORY_STATS_ALL_CELLS; - virNodeMemoryStatsPtr params = NULL; - bool ret = false; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (vshCommandOptInt(cmd, "cell", &cellNum) < 0) { - vshError(ctl, "%s", _("Invalid value of cellNum")); - return false; - } - - /* get the number of memory parameters */ - if (virNodeGetMemoryStats(ctl->conn, cellNum, NULL, &nparams, 0) != 0) { - vshError(ctl, "%s", - _("Unable to get number of memory stats")); - goto cleanup; - } - - if (nparams == 0) { - /* nothing to output */ - ret = true; - goto cleanup; - } - - /* now go get all the memory parameters */ - params = vshCalloc(ctl, nparams, sizeof(*params)); - if (virNodeGetMemoryStats(ctl->conn, cellNum, params, &nparams, 0) != 0) { - vshError(ctl, "%s", _("Unable to get memory stats")); - goto cleanup; - } - - for (i = 0; i < nparams; i++) - vshPrint(ctl, "%-7s: %20llu KiB\n", params[i].field, params[i].value); - - ret = true; - - cleanup: - VIR_FREE(params); - return ret; -} - -/* - * "nodesuspend" command - */ -static const vshCmdInfo info_nodesuspend[] = { - {"help", N_("suspend the host node for a given time duration")}, - {"desc", N_("Suspend the host node for a given time duration " - "and attempt to resume thereafter.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_node_suspend[] = { - {"target", VSH_OT_DATA, VSH_OFLAG_REQ, N_("mem(Suspend-to-RAM), " - "disk(Suspend-to-Disk), hybrid(Hybrid-Suspend)")}, - {"duration", VSH_OT_INT, VSH_OFLAG_REQ, N_("Suspend duration in seconds")}, - {"flags", VSH_OT_INT, VSH_OFLAG_NONE, N_("Suspend flags, 0 for default")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdNodeSuspend(vshControl *ctl, const vshCmd *cmd) -{ - const char *target = NULL; - unsigned int suspendTarget; - long long duration; - unsigned int flags = 0; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (vshCommandOptString(cmd, "target", &target) < 0) { - vshError(ctl, _("Invalid target argument")); - return false; - } - - if (vshCommandOptLongLong(cmd, "duration", &duration) < 0) { - vshError(ctl, _("Invalid duration argument")); - return false; - } - - if (vshCommandOptUInt(cmd, "flags", &flags) < 0) { - vshError(ctl, _("Invalid flags argument")); - return false; - } - - if (STREQ(target, "mem")) - suspendTarget = VIR_NODE_SUSPEND_TARGET_MEM; - else if (STREQ(target, "disk")) - suspendTarget = VIR_NODE_SUSPEND_TARGET_DISK; - else if (STREQ(target, "hybrid")) - suspendTarget = VIR_NODE_SUSPEND_TARGET_HYBRID; - else { - vshError(ctl, "%s", _("Invalid target")); - return false; - } - - if (duration <= 0) { - vshError(ctl, "%s", _("Invalid duration")); - return false; - } - - if (virNodeSuspendForDuration(ctl->conn, suspendTarget, duration, - flags) < 0) { - vshError(ctl, "%s", _("The host was not suspended")); - return false; - } - return true; -} - - -/* - * "capabilities" command - */ -static const vshCmdInfo info_capabilities[] = { - {"help", N_("capabilities")}, - {"desc", N_("Returns capabilities of hypervisor/driver.")}, - {NULL, NULL} -}; - -static bool -cmdCapabilities(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) -{ - char *caps; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if ((caps = virConnectGetCapabilities(ctl->conn)) == NULL) { - vshError(ctl, "%s", _("failed to get capabilities")); - return false; - } - vshPrint(ctl, "%s\n", caps); - VIR_FREE(caps); - - return true; -} - -/* * "nodedev-create" command */ static const vshCmdInfo info_node_device_create[] = { @@ -1338,105 +840,6 @@ cmdNodeDeviceDestroy(vshControl *ctl, const vshCmd *cmd) return ret; } -/* - * "version" command - */ -static const vshCmdInfo info_version[] = { - {"help", N_("show version")}, - {"desc", N_("Display the system version information.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_version[] = { - {"daemon", VSH_OT_BOOL, VSH_OFLAG_NONE, N_("report daemon version too")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdVersion(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) -{ - unsigned long hvVersion; - const char *hvType; - unsigned long libVersion; - unsigned long includeVersion; - unsigned long apiVersion; - unsigned long daemonVersion; - int ret; - unsigned int major; - unsigned int minor; - unsigned int rel; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - hvType = virConnectGetType(ctl->conn); - if (hvType == NULL) { - vshError(ctl, "%s", _("failed to get hypervisor type")); - return false; - } - - includeVersion = LIBVIR_VERSION_NUMBER; - major = includeVersion / 1000000; - includeVersion %= 1000000; - minor = includeVersion / 1000; - rel = includeVersion % 1000; - vshPrint(ctl, _("Compiled against library: libvir %d.%d.%d\n"), - major, minor, rel); - - ret = virGetVersion(&libVersion, hvType, &apiVersion); - if (ret < 0) { - vshError(ctl, "%s", _("failed to get the library version")); - return false; - } - major = libVersion / 1000000; - libVersion %= 1000000; - minor = libVersion / 1000; - rel = libVersion % 1000; - vshPrint(ctl, _("Using library: libvir %d.%d.%d\n"), - major, minor, rel); - - major = apiVersion / 1000000; - apiVersion %= 1000000; - minor = apiVersion / 1000; - rel = apiVersion % 1000; - vshPrint(ctl, _("Using API: %s %d.%d.%d\n"), hvType, - major, minor, rel); - - ret = virConnectGetVersion(ctl->conn, &hvVersion); - if (ret < 0) { - vshError(ctl, "%s", _("failed to get the hypervisor version")); - return false; - } - if (hvVersion == 0) { - vshPrint(ctl, - _("Cannot extract running %s hypervisor version\n"), hvType); - } else { - major = hvVersion / 1000000; - hvVersion %= 1000000; - minor = hvVersion / 1000; - rel = hvVersion % 1000; - - vshPrint(ctl, _("Running hypervisor: %s %d.%d.%d\n"), - hvType, major, minor, rel); - } - - if (vshCommandOptBool(cmd, "daemon")) { - ret = virConnectGetLibVersion(ctl->conn, &daemonVersion); - if (ret < 0) { - vshError(ctl, "%s", _("failed to get the daemon version")); - } else { - major = daemonVersion / 1000000; - daemonVersion %= 1000000; - minor = daemonVersion / 1000; - rel = daemonVersion % 1000; - vshPrint(ctl, _("Running against daemon: %d.%d.%d\n"), - major, minor, rel); - } - } - - return true; -} - /* Tree listing helpers. */ /* Given an index, return either the name of that device (non-NULL) or @@ -1789,94 +1192,6 @@ cmdNodeDeviceReset(vshControl *ctl, const vshCmd *cmd) return ret; } -/* - * "hostname" command - */ -static const vshCmdInfo info_hostname[] = { - {"help", N_("print the hypervisor hostname")}, - {"desc", ""}, - {NULL, NULL} -}; - -static bool -cmdHostname(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) -{ - char *hostname; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - hostname = virConnectGetHostname(ctl->conn); - if (hostname == NULL) { - vshError(ctl, "%s", _("failed to get hostname")); - return false; - } - - vshPrint (ctl, "%s\n", hostname); - VIR_FREE(hostname); - - return true; -} - -/* - * "uri" command - */ -static const vshCmdInfo info_uri[] = { - {"help", N_("print the hypervisor canonical URI")}, - {"desc", ""}, - {NULL, NULL} -}; - -static bool -cmdURI(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) -{ - char *uri; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - uri = virConnectGetURI(ctl->conn); - if (uri == NULL) { - vshError(ctl, "%s", _("failed to get URI")); - return false; - } - - vshPrint(ctl, "%s\n", uri); - VIR_FREE(uri); - - return true; -} - -/* - * "sysinfo" command - */ -static const vshCmdInfo info_sysinfo[] = { - {"help", N_("print the hypervisor sysinfo")}, - {"desc", - N_("output an XML string for the hypervisor sysinfo, if available")}, - {NULL, NULL} -}; - -static bool -cmdSysinfo(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) -{ - char *sysinfo; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - sysinfo = virConnectGetSysinfo(ctl->conn, 0); - if (sysinfo == NULL) { - vshError(ctl, "%s", _("failed to get sysinfo")); - return false; - } - - vshPrint(ctl, "%s", sysinfo); - VIR_FREE(sysinfo); - - return true; -} - /* Common code for the edit / net-edit / pool-edit functions which follow. */ static char * editWriteToTempFile(vshControl *ctl, const char *doc) @@ -2149,118 +1464,6 @@ cmdQuit(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) return true; } -/* - * "qemu-monitor-command" command - */ -static const vshCmdInfo info_qemu_monitor_command[] = { - {"help", N_("QEMU Monitor Command")}, - {"desc", N_("QEMU Monitor Command")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_qemu_monitor_command[] = { - {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, - {"hmp", VSH_OT_BOOL, 0, N_("command is in human monitor protocol")}, - {"cmd", VSH_OT_ARGV, VSH_OFLAG_REQ, N_("command")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdQemuMonitorCommand(vshControl *ctl, const vshCmd *cmd) -{ - virDomainPtr dom = NULL; - bool ret = false; - char *monitor_cmd = NULL; - char *result = NULL; - unsigned int flags = 0; - const vshCmdOpt *opt = NULL; - virBuffer buf = VIR_BUFFER_INITIALIZER; - bool pad = false; - - if (!vshConnectionUsability(ctl, ctl->conn)) - goto cleanup; - - dom = vshCommandOptDomain(ctl, cmd, NULL); - if (dom == NULL) - goto cleanup; - - while ((opt = vshCommandOptArgv(cmd, opt))) { - if (pad) - virBufferAddChar(&buf, ' '); - pad = true; - virBufferAdd(&buf, opt->data, -1); - } - if (virBufferError(&buf)) { - vshPrint(ctl, "%s", _("Failed to collect command")); - goto cleanup; - } - monitor_cmd = virBufferContentAndReset(&buf); - - if (vshCommandOptBool(cmd, "hmp")) - flags |= VIR_DOMAIN_QEMU_MONITOR_COMMAND_HMP; - - if (virDomainQemuMonitorCommand(dom, monitor_cmd, &result, flags) < 0) - goto cleanup; - - printf("%s\n", result); - - ret = true; - -cleanup: - VIR_FREE(result); - VIR_FREE(monitor_cmd); - if (dom) - virDomainFree(dom); - - return ret; -} - -/* - * "qemu-attach" command - */ -static const vshCmdInfo info_qemu_attach[] = { - {"help", N_("QEMU Attach")}, - {"desc", N_("QEMU Attach")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_qemu_attach[] = { - {"pid", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pid")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdQemuAttach(vshControl *ctl, const vshCmd *cmd) -{ - virDomainPtr dom = NULL; - bool ret = false; - unsigned int flags = 0; - unsigned int pid_value; /* API uses unsigned int, not pid_t */ - - if (!vshConnectionUsability(ctl, ctl->conn)) - goto cleanup; - - if (vshCommandOptUInt(cmd, "pid", &pid_value) <= 0) { - vshError(ctl, "%s", _("missing pid value")); - goto cleanup; - } - - if (!(dom = virDomainQemuAttach(ctl->conn, pid_value, flags))) - goto cleanup; - - if (dom != NULL) { - vshPrint(ctl, _("Domain %s attached to pid %u\n"), - virDomainGetName(dom), pid_value); - virDomainFree(dom); - ret = true; - } else { - vshError(ctl, _("Failed to attach to pid %u"), pid_value); - } - -cleanup: - return ret; -} - /* --------------- * Utils for work with command definition * --------------- @@ -4629,6 +3832,8 @@ static const vshCmdDef snapshotCmds[] = { {NULL, NULL, NULL, NULL, 0} }; +#include "virsh-host.c" + static const vshCmdDef hostAndHypervisorCmds[] = { {"capabilities", cmdCapabilities, NULL, info_capabilities, 0}, {"connect", cmdConnect, opts_connect, info_connect, -- 1.7.7.3

On 07/24/12 11:18, Osier Yang wrote:
Commands in host group moved from virsh.c to virsh-host.c,
* virsh.c: Remove commands in host group. * virsh-host.c: New file, filled with commands in host group --- tools/virsh-host.c | 820 ++++++++++++++++++++++++++++++++++++++++++++++++++++ tools/virsh.c | 799 +-------------------------------------------------- 2 files changed, 822 insertions(+), 797 deletions(-) create mode 100644 tools/virsh-host.c
ACK. Peter

Commands in node device group moved from virsh.c to virsh-nodedev.c, * virsh.c: Remove commands in node device group. * virsh-nodedev.c: New file, filled with commands in node device group --- tools/virsh-nodedev.c | 383 +++++++++++++++++++++++++++++++++++++++++++++++++ tools/virsh.c | 360 +--------------------------------------------- 2 files changed, 385 insertions(+), 358 deletions(-) create mode 100644 tools/virsh-nodedev.c diff --git a/tools/virsh-nodedev.c b/tools/virsh-nodedev.c new file mode 100644 index 0000000..ee9a6fd --- /dev/null +++ b/tools/virsh-nodedev.c @@ -0,0 +1,383 @@ +/* + * virsh-nodedev.c: Commands in node device group + * + * Copyright (C) 2005, 2007-2012 Red Hat, Inc + * + * 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 + * License along with this library; If not, see + * <http://www.gnu.org/licenses/>. + * + * Daniel Veillard <veillard@redhat.com> + * Karel Zak <kzak@redhat.com> + * Daniel P. Berrange <berrange@redhat.com> + * + */ + +/* + * "nodedev-create" command + */ +static const vshCmdInfo info_node_device_create[] = { + {"help", N_("create a device defined " + "by an XML file on the node")}, + {"desc", N_("Create a device on the node. Note that this " + "command creates devices on the physical host " + "that can then be assigned to a virtual machine.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_node_device_create[] = { + {"file", VSH_OT_DATA, VSH_OFLAG_REQ, + N_("file containing an XML description of the device")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdNodeDeviceCreate(vshControl *ctl, const vshCmd *cmd) +{ + virNodeDevicePtr dev = NULL; + const char *from = NULL; + bool ret = true; + char *buffer; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (vshCommandOptString(cmd, "file", &from) <= 0) + return false; + + if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0) + return false; + + dev = virNodeDeviceCreateXML(ctl->conn, buffer, 0); + VIR_FREE(buffer); + + if (dev != NULL) { + vshPrint(ctl, _("Node device %s created from %s\n"), + virNodeDeviceGetName(dev), from); + virNodeDeviceFree(dev); + } else { + vshError(ctl, _("Failed to create node device from %s"), from); + ret = false; + } + + return ret; +} + + +/* + * "nodedev-destroy" command + */ +static const vshCmdInfo info_node_device_destroy[] = { + {"help", N_("destroy (stop) a device on the node")}, + {"desc", N_("Destroy a device on the node. Note that this " + "command destroys devices on the physical host")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_node_device_destroy[] = { + {"name", VSH_OT_DATA, VSH_OFLAG_REQ, + N_("name of the device to be destroyed")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdNodeDeviceDestroy(vshControl *ctl, const vshCmd *cmd) +{ + virNodeDevicePtr dev = NULL; + bool ret = true; + const char *name = NULL; + + if (!vshConnectionUsability(ctl, ctl->conn)) { + return false; + } + + if (vshCommandOptString(cmd, "name", &name) <= 0) + return false; + + dev = virNodeDeviceLookupByName(ctl->conn, name); + + if (virNodeDeviceDestroy(dev) == 0) { + vshPrint(ctl, _("Destroyed node device '%s'\n"), name); + } else { + vshError(ctl, _("Failed to destroy node device '%s'"), name); + ret = false; + } + + virNodeDeviceFree(dev); + return ret; +} + +struct vshNodeList { + char **names; + char **parents; +}; + +static const char * +vshNodeListLookup(int devid, bool parent, void *opaque) +{ + struct vshNodeList *arrays = opaque; + if (parent) + return arrays->parents[devid]; + return arrays->names[devid]; +} + +/* + * "nodedev-list" command + */ +static const vshCmdInfo info_node_list_devices[] = { + {"help", N_("enumerate devices on this host")}, + {"desc", ""}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_node_list_devices[] = { + {"tree", VSH_OT_BOOL, 0, N_("list devices in a tree")}, + {"cap", VSH_OT_STRING, VSH_OFLAG_NONE, N_("capability name")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdNodeListDevices(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) +{ + const char *cap = NULL; + char **devices; + int num_devices, i; + bool tree = vshCommandOptBool(cmd, "tree"); + bool ret = true; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (vshCommandOptString(cmd, "cap", &cap) <= 0) + cap = NULL; + + num_devices = virNodeNumOfDevices(ctl->conn, cap, 0); + if (num_devices < 0) { + vshError(ctl, "%s", _("Failed to count node devices")); + return false; + } else if (num_devices == 0) { + return true; + } + + devices = vshMalloc(ctl, sizeof(char *) * num_devices); + num_devices = + virNodeListDevices(ctl->conn, cap, devices, num_devices, 0); + if (num_devices < 0) { + vshError(ctl, "%s", _("Failed to list node devices")); + VIR_FREE(devices); + return false; + } + qsort(&devices[0], num_devices, sizeof(char*), vshNameSorter); + if (tree) { + char **parents = vshMalloc(ctl, sizeof(char *) * num_devices); + struct vshNodeList arrays = { devices, parents }; + + for (i = 0; i < num_devices; i++) { + virNodeDevicePtr dev = virNodeDeviceLookupByName(ctl->conn, devices[i]); + if (dev && STRNEQ(devices[i], "computer")) { + const char *parent = virNodeDeviceGetParent(dev); + parents[i] = parent ? vshStrdup(ctl, parent) : NULL; + } else { + parents[i] = NULL; + } + virNodeDeviceFree(dev); + } + for (i = 0 ; i < num_devices ; i++) { + if (parents[i] == NULL && + vshTreePrint(ctl, vshNodeListLookup, &arrays, num_devices, + i) < 0) + ret = false; + } + for (i = 0 ; i < num_devices ; i++) { + VIR_FREE(devices[i]); + VIR_FREE(parents[i]); + } + VIR_FREE(parents); + } else { + for (i = 0; i < num_devices; i++) { + vshPrint(ctl, "%s\n", devices[i]); + VIR_FREE(devices[i]); + } + } + VIR_FREE(devices); + return ret; +} + +/* + * "nodedev-dumpxml" command + */ +static const vshCmdInfo info_node_device_dumpxml[] = { + {"help", N_("node device details in XML")}, + {"desc", N_("Output the node device details as an XML dump to stdout.")}, + {NULL, NULL} +}; + + +static const vshCmdOptDef opts_node_device_dumpxml[] = { + {"device", VSH_OT_DATA, VSH_OFLAG_REQ, N_("device key")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdNodeDeviceDumpXML(vshControl *ctl, const vshCmd *cmd) +{ + const char *name = NULL; + virNodeDevicePtr device; + char *xml; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + if (vshCommandOptString(cmd, "device", &name) <= 0) + return false; + if (!(device = virNodeDeviceLookupByName(ctl->conn, name))) { + vshError(ctl, "%s '%s'", _("Could not find matching device"), name); + return false; + } + + xml = virNodeDeviceGetXMLDesc(device, 0); + if (!xml) { + virNodeDeviceFree(device); + return false; + } + + vshPrint(ctl, "%s\n", xml); + VIR_FREE(xml); + virNodeDeviceFree(device); + return true; +} + +/* + * "nodedev-detach" command + */ +static const vshCmdInfo info_node_device_detach[] = { + {"help", N_("detach node device from its device driver")}, + {"desc", N_("Detach node device from its device driver before assigning to a domain.")}, + {NULL, NULL} +}; + + +static const vshCmdOptDef opts_node_device_detach[] = { + {"device", VSH_OT_DATA, VSH_OFLAG_REQ, N_("device key")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdNodeDeviceDetach(vshControl *ctl, const vshCmd *cmd) +{ + const char *name = NULL; + virNodeDevicePtr device; + bool ret = true; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + if (vshCommandOptString(cmd, "device", &name) <= 0) + return false; + if (!(device = virNodeDeviceLookupByName(ctl->conn, name))) { + vshError(ctl, "%s '%s'", _("Could not find matching device"), name); + return false; + } + + /* Yes, our public API is misspelled. At least virsh can accept + * either spelling. */ + if (virNodeDeviceDettach(device) == 0) { + vshPrint(ctl, _("Device %s detached\n"), name); + } else { + vshError(ctl, _("Failed to detach device %s"), name); + ret = false; + } + virNodeDeviceFree(device); + return ret; +} + +/* + * "nodedev-reattach" command + */ +static const vshCmdInfo info_node_device_reattach[] = { + {"help", N_("reattach node device to its device driver")}, + {"desc", N_("Reattach node device to its device driver once released by the domain.")}, + {NULL, NULL} +}; + + +static const vshCmdOptDef opts_node_device_reattach[] = { + {"device", VSH_OT_DATA, VSH_OFLAG_REQ, N_("device key")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdNodeDeviceReAttach(vshControl *ctl, const vshCmd *cmd) +{ + const char *name = NULL; + virNodeDevicePtr device; + bool ret = true; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + if (vshCommandOptString(cmd, "device", &name) <= 0) + return false; + if (!(device = virNodeDeviceLookupByName(ctl->conn, name))) { + vshError(ctl, "%s '%s'", _("Could not find matching device"), name); + return false; + } + + if (virNodeDeviceReAttach(device) == 0) { + vshPrint(ctl, _("Device %s re-attached\n"), name); + } else { + vshError(ctl, _("Failed to re-attach device %s"), name); + ret = false; + } + virNodeDeviceFree(device); + return ret; +} + +/* + * "nodedev-reset" command + */ +static const vshCmdInfo info_node_device_reset[] = { + {"help", N_("reset node device")}, + {"desc", N_("Reset node device before or after assigning to a domain.")}, + {NULL, NULL} +}; + + +static const vshCmdOptDef opts_node_device_reset[] = { + {"device", VSH_OT_DATA, VSH_OFLAG_REQ, N_("device key")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdNodeDeviceReset(vshControl *ctl, const vshCmd *cmd) +{ + const char *name = NULL; + virNodeDevicePtr device; + bool ret = true; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + if (vshCommandOptString(cmd, "device", &name) <= 0) + return false; + if (!(device = virNodeDeviceLookupByName(ctl->conn, name))) { + vshError(ctl, "%s '%s'", _("Could not find matching device"), name); + return false; + } + + if (virNodeDeviceReset(device) == 0) { + vshPrint(ctl, _("Device %s reset\n"), name); + } else { + vshError(ctl, _("Failed to reset device %s"), name); + ret = false; + } + virNodeDeviceFree(device); + return ret; +} + diff --git a/tools/virsh.c b/tools/virsh.c index 1d878b9..e461410 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -746,100 +746,6 @@ cmdHelp(vshControl *ctl, const vshCmd *cmd) } } -/* - * "nodedev-create" command - */ -static const vshCmdInfo info_node_device_create[] = { - {"help", N_("create a device defined " - "by an XML file on the node")}, - {"desc", N_("Create a device on the node. Note that this " - "command creates devices on the physical host " - "that can then be assigned to a virtual machine.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_node_device_create[] = { - {"file", VSH_OT_DATA, VSH_OFLAG_REQ, - N_("file containing an XML description of the device")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdNodeDeviceCreate(vshControl *ctl, const vshCmd *cmd) -{ - virNodeDevicePtr dev = NULL; - const char *from = NULL; - bool ret = true; - char *buffer; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (vshCommandOptString(cmd, "file", &from) <= 0) - return false; - - if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0) - return false; - - dev = virNodeDeviceCreateXML(ctl->conn, buffer, 0); - VIR_FREE(buffer); - - if (dev != NULL) { - vshPrint(ctl, _("Node device %s created from %s\n"), - virNodeDeviceGetName(dev), from); - virNodeDeviceFree(dev); - } else { - vshError(ctl, _("Failed to create node device from %s"), from); - ret = false; - } - - return ret; -} - - -/* - * "nodedev-destroy" command - */ -static const vshCmdInfo info_node_device_destroy[] = { - {"help", N_("destroy (stop) a device on the node")}, - {"desc", N_("Destroy a device on the node. Note that this " - "command destroys devices on the physical host")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_node_device_destroy[] = { - {"name", VSH_OT_DATA, VSH_OFLAG_REQ, - N_("name of the device to be destroyed")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdNodeDeviceDestroy(vshControl *ctl, const vshCmd *cmd) -{ - virNodeDevicePtr dev = NULL; - bool ret = true; - const char *name = NULL; - - if (!vshConnectionUsability(ctl, ctl->conn)) { - return false; - } - - if (vshCommandOptString(cmd, "name", &name) <= 0) - return false; - - dev = virNodeDeviceLookupByName(ctl->conn, name); - - if (virNodeDeviceDestroy(dev) == 0) { - vshPrint(ctl, _("Destroyed node device '%s'\n"), name); - } else { - vshError(ctl, _("Failed to destroy node device '%s'"), name); - ret = false; - } - - virNodeDeviceFree(dev); - return ret; -} - /* Tree listing helpers. */ /* Given an index, return either the name of that device (non-NULL) or @@ -928,270 +834,6 @@ vshTreePrint(vshControl *ctl, vshTreeLookup lookup, void *opaque, return ret; } -struct vshNodeList { - char **names; - char **parents; -}; - -static const char * -vshNodeListLookup(int devid, bool parent, void *opaque) -{ - struct vshNodeList *arrays = opaque; - if (parent) - return arrays->parents[devid]; - return arrays->names[devid]; -} - -/* - * "nodedev-list" command - */ -static const vshCmdInfo info_node_list_devices[] = { - {"help", N_("enumerate devices on this host")}, - {"desc", ""}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_node_list_devices[] = { - {"tree", VSH_OT_BOOL, 0, N_("list devices in a tree")}, - {"cap", VSH_OT_STRING, VSH_OFLAG_NONE, N_("capability name")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdNodeListDevices(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) -{ - const char *cap = NULL; - char **devices; - int num_devices, i; - bool tree = vshCommandOptBool(cmd, "tree"); - bool ret = true; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (vshCommandOptString(cmd, "cap", &cap) <= 0) - cap = NULL; - - num_devices = virNodeNumOfDevices(ctl->conn, cap, 0); - if (num_devices < 0) { - vshError(ctl, "%s", _("Failed to count node devices")); - return false; - } else if (num_devices == 0) { - return true; - } - - devices = vshMalloc(ctl, sizeof(char *) * num_devices); - num_devices = - virNodeListDevices(ctl->conn, cap, devices, num_devices, 0); - if (num_devices < 0) { - vshError(ctl, "%s", _("Failed to list node devices")); - VIR_FREE(devices); - return false; - } - qsort(&devices[0], num_devices, sizeof(char*), vshNameSorter); - if (tree) { - char **parents = vshMalloc(ctl, sizeof(char *) * num_devices); - struct vshNodeList arrays = { devices, parents }; - - for (i = 0; i < num_devices; i++) { - virNodeDevicePtr dev = virNodeDeviceLookupByName(ctl->conn, devices[i]); - if (dev && STRNEQ(devices[i], "computer")) { - const char *parent = virNodeDeviceGetParent(dev); - parents[i] = parent ? vshStrdup(ctl, parent) : NULL; - } else { - parents[i] = NULL; - } - virNodeDeviceFree(dev); - } - for (i = 0 ; i < num_devices ; i++) { - if (parents[i] == NULL && - vshTreePrint(ctl, vshNodeListLookup, &arrays, num_devices, - i) < 0) - ret = false; - } - for (i = 0 ; i < num_devices ; i++) { - VIR_FREE(devices[i]); - VIR_FREE(parents[i]); - } - VIR_FREE(parents); - } else { - for (i = 0; i < num_devices; i++) { - vshPrint(ctl, "%s\n", devices[i]); - VIR_FREE(devices[i]); - } - } - VIR_FREE(devices); - return ret; -} - -/* - * "nodedev-dumpxml" command - */ -static const vshCmdInfo info_node_device_dumpxml[] = { - {"help", N_("node device details in XML")}, - {"desc", N_("Output the node device details as an XML dump to stdout.")}, - {NULL, NULL} -}; - - -static const vshCmdOptDef opts_node_device_dumpxml[] = { - {"device", VSH_OT_DATA, VSH_OFLAG_REQ, N_("device key")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdNodeDeviceDumpXML(vshControl *ctl, const vshCmd *cmd) -{ - const char *name = NULL; - virNodeDevicePtr device; - char *xml; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - if (vshCommandOptString(cmd, "device", &name) <= 0) - return false; - if (!(device = virNodeDeviceLookupByName(ctl->conn, name))) { - vshError(ctl, "%s '%s'", _("Could not find matching device"), name); - return false; - } - - xml = virNodeDeviceGetXMLDesc(device, 0); - if (!xml) { - virNodeDeviceFree(device); - return false; - } - - vshPrint(ctl, "%s\n", xml); - VIR_FREE(xml); - virNodeDeviceFree(device); - return true; -} - -/* - * "nodedev-detach" command - */ -static const vshCmdInfo info_node_device_detach[] = { - {"help", N_("detach node device from its device driver")}, - {"desc", N_("Detach node device from its device driver before assigning to a domain.")}, - {NULL, NULL} -}; - - -static const vshCmdOptDef opts_node_device_detach[] = { - {"device", VSH_OT_DATA, VSH_OFLAG_REQ, N_("device key")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdNodeDeviceDetach(vshControl *ctl, const vshCmd *cmd) -{ - const char *name = NULL; - virNodeDevicePtr device; - bool ret = true; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - if (vshCommandOptString(cmd, "device", &name) <= 0) - return false; - if (!(device = virNodeDeviceLookupByName(ctl->conn, name))) { - vshError(ctl, "%s '%s'", _("Could not find matching device"), name); - return false; - } - - /* Yes, our public API is misspelled. At least virsh can accept - * either spelling. */ - if (virNodeDeviceDettach(device) == 0) { - vshPrint(ctl, _("Device %s detached\n"), name); - } else { - vshError(ctl, _("Failed to detach device %s"), name); - ret = false; - } - virNodeDeviceFree(device); - return ret; -} - -/* - * "nodedev-reattach" command - */ -static const vshCmdInfo info_node_device_reattach[] = { - {"help", N_("reattach node device to its device driver")}, - {"desc", N_("Reattach node device to its device driver once released by the domain.")}, - {NULL, NULL} -}; - - -static const vshCmdOptDef opts_node_device_reattach[] = { - {"device", VSH_OT_DATA, VSH_OFLAG_REQ, N_("device key")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdNodeDeviceReAttach(vshControl *ctl, const vshCmd *cmd) -{ - const char *name = NULL; - virNodeDevicePtr device; - bool ret = true; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - if (vshCommandOptString(cmd, "device", &name) <= 0) - return false; - if (!(device = virNodeDeviceLookupByName(ctl->conn, name))) { - vshError(ctl, "%s '%s'", _("Could not find matching device"), name); - return false; - } - - if (virNodeDeviceReAttach(device) == 0) { - vshPrint(ctl, _("Device %s re-attached\n"), name); - } else { - vshError(ctl, _("Failed to re-attach device %s"), name); - ret = false; - } - virNodeDeviceFree(device); - return ret; -} - -/* - * "nodedev-reset" command - */ -static const vshCmdInfo info_node_device_reset[] = { - {"help", N_("reset node device")}, - {"desc", N_("Reset node device before or after assigning to a domain.")}, - {NULL, NULL} -}; - - -static const vshCmdOptDef opts_node_device_reset[] = { - {"device", VSH_OT_DATA, VSH_OFLAG_REQ, N_("device key")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdNodeDeviceReset(vshControl *ctl, const vshCmd *cmd) -{ - const char *name = NULL; - virNodeDevicePtr device; - bool ret = true; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - if (vshCommandOptString(cmd, "device", &name) <= 0) - return false; - if (!(device = virNodeDeviceLookupByName(ctl->conn, name))) { - vshError(ctl, "%s '%s'", _("Could not find matching device"), name); - return false; - } - - if (virNodeDeviceReset(device) == 0) { - vshPrint(ctl, _("Device %s reset\n"), name); - } else { - vshError(ctl, _("Failed to reset device %s"), name); - ret = false; - } - virNodeDeviceFree(device); - return ret; -} - /* Common code for the edit / net-edit / pool-edit functions which follow. */ static char * editWriteToTempFile(vshControl *ctl, const char *doc) @@ -3709,6 +3351,8 @@ static const vshCmdDef networkCmds[] = { {NULL, NULL, NULL, NULL, 0} }; +#include "virsh-nodedev.c" + static const vshCmdDef nodedevCmds[] = { {"nodedev-create", cmdNodeDeviceCreate, opts_node_device_create, info_node_device_create, 0}, -- 1.7.7.3

On 07/24/12 11:18, Osier Yang wrote:
Commands in node device group moved from virsh.c to virsh-nodedev.c,
* virsh.c: Remove commands in node device group. * virsh-nodedev.c: New file, filled with commands in node device group --- tools/virsh-nodedev.c | 383 +++++++++++++++++++++++++++++++++++++++++++++++++ tools/virsh.c | 360 +--------------------------------------------- 2 files changed, 385 insertions(+), 358 deletions(-) create mode 100644 tools/virsh-nodedev.c
There's an extra newline at the end of virsh-nodedev.c. ACK with that removed. Peter

* virsh-domain-monitor.c: Add domMonitoringCmds * virsh-domain.c: Add domManagementCmds * virsh-host.c: Add hostAndHypervisorCmds * virsh-interface.c: Add ifaceCmds * virsh-network.c: Add networkCmds * virsh-nodedev.c: Add nodedevCmds * virsh-nwfilter.c: Add nwfilterCmds * virsh-pool.c: Add storagePoolCmds * virsh-secret.c: Add secretCmds * virsh-snapshot.c: Add snapshotCmds * virsh-volume.c: Add storageVolCmds * virsh.c: Remove all the above *Cmds. --- tools/virsh-domain-monitor.c | 16 ++ tools/virsh-domain.c | 95 +++++++++++++ tools/virsh-host.c | 19 +++ tools/virsh-interface.c | 32 ++++ tools/virsh-network.c | 22 +++ tools/virsh-nodedev.c | 19 +++ tools/virsh-nwfilter.c | 14 ++ tools/virsh-pool.c | 27 ++++ tools/virsh-secret.c | 15 ++ tools/virsh-snapshot.c | 24 +++ tools/virsh-volume.c | 22 +++ tools/virsh.c | 320 +----------------------------------------- 12 files changed, 307 insertions(+), 318 deletions(-) diff --git a/tools/virsh-domain-monitor.c b/tools/virsh-domain-monitor.c index 1a61f62..249ff13 100644 --- a/tools/virsh-domain-monitor.c +++ b/tools/virsh-domain-monitor.c @@ -1683,3 +1683,19 @@ cleanup: return ret; } #undef FILTER + +static const vshCmdDef domMonitoringCmds[] = { + {"domblkerror", cmdDomBlkError, opts_domblkerror, info_domblkerror, 0}, + {"domblkinfo", cmdDomblkinfo, opts_domblkinfo, info_domblkinfo, 0}, + {"domblklist", cmdDomblklist, opts_domblklist, info_domblklist, 0}, + {"domblkstat", cmdDomblkstat, opts_domblkstat, info_domblkstat, 0}, + {"domcontrol", cmdDomControl, opts_domcontrol, info_domcontrol, 0}, + {"domif-getlink", cmdDomIfGetLink, opts_domif_getlink, info_domif_getlink, 0}, + {"domiflist", cmdDomiflist, opts_domiflist, info_domiflist, 0}, + {"domifstat", cmdDomIfstat, opts_domifstat, info_domifstat, 0}, + {"dominfo", cmdDominfo, opts_dominfo, info_dominfo, 0}, + {"dommemstat", cmdDomMemStat, opts_dommemstat, info_dommemstat, 0}, + {"domstate", cmdDomstate, opts_domstate, info_domstate, 0}, + {"list", cmdList, opts_list, info_list, 0}, + {NULL, NULL, NULL, NULL, 0} +}; diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c index 22d002c..6da4f46 100644 --- a/tools/virsh-domain.c +++ b/tools/virsh-domain.c @@ -8042,3 +8042,98 @@ cleanup: virDomainFree(dom); return ret; } + +static const vshCmdDef domManagementCmds[] = { + {"attach-device", cmdAttachDevice, opts_attach_device, + info_attach_device, 0}, + {"attach-disk", cmdAttachDisk, opts_attach_disk, + info_attach_disk, 0}, + {"attach-interface", cmdAttachInterface, opts_attach_interface, + info_attach_interface, 0}, + {"autostart", cmdAutostart, opts_autostart, info_autostart, 0}, + {"blkdeviotune", cmdBlkdeviotune, opts_blkdeviotune, info_blkdeviotune, 0}, + {"blkiotune", cmdBlkiotune, opts_blkiotune, info_blkiotune, 0}, + {"blockcopy", cmdBlockCopy, opts_block_copy, info_block_copy, 0}, + {"blockjob", cmdBlockJob, opts_block_job, info_block_job, 0}, + {"blockpull", cmdBlockPull, opts_block_pull, info_block_pull, 0}, + {"blockresize", cmdBlockResize, opts_block_resize, info_block_resize, 0}, + {"change-media", cmdChangeMedia, opts_change_media, info_change_media, 0}, +#ifndef WIN32 + {"console", cmdConsole, opts_console, info_console, 0}, +#endif + {"cpu-baseline", cmdCPUBaseline, opts_cpu_baseline, info_cpu_baseline, 0}, + {"cpu-compare", cmdCPUCompare, opts_cpu_compare, info_cpu_compare, 0}, + {"cpu-stats", cmdCPUStats, opts_cpu_stats, info_cpu_stats, 0}, + {"create", cmdCreate, opts_create, info_create, 0}, + {"define", cmdDefine, opts_define, info_define, 0}, + {"desc", cmdDesc, opts_desc, info_desc, 0}, + {"destroy", cmdDestroy, opts_destroy, info_destroy, 0}, + {"detach-device", cmdDetachDevice, opts_detach_device, + info_detach_device, 0}, + {"detach-disk", cmdDetachDisk, opts_detach_disk, info_detach_disk, 0}, + {"detach-interface", cmdDetachInterface, opts_detach_interface, + info_detach_interface, 0}, + {"domdisplay", cmdDomDisplay, opts_domdisplay, info_domdisplay, 0}, + {"domhostname", cmdDomHostname, opts_domhostname, info_domhostname, 0}, + {"domid", cmdDomid, opts_domid, info_domid, 0}, + {"domif-setlink", cmdDomIfSetLink, opts_domif_setlink, info_domif_setlink, 0}, + {"domiftune", cmdDomIftune, opts_domiftune, info_domiftune, 0}, + {"domjobabort", cmdDomjobabort, opts_domjobabort, info_domjobabort, 0}, + {"domjobinfo", cmdDomjobinfo, opts_domjobinfo, info_domjobinfo, 0}, + {"domname", cmdDomname, opts_domname, info_domname, 0}, + {"dompmsuspend", cmdDomPMSuspend, + opts_dom_pm_suspend, info_dom_pm_suspend, 0}, + {"dompmwakeup", cmdDomPMWakeup, + opts_dom_pm_wakeup, info_dom_pm_wakeup, 0}, + {"domuuid", cmdDomuuid, opts_domuuid, info_domuuid, 0}, + {"domxml-from-native", cmdDomXMLFromNative, opts_domxmlfromnative, + info_domxmlfromnative, 0}, + {"domxml-to-native", cmdDomXMLToNative, opts_domxmltonative, + info_domxmltonative, 0}, + {"dump", cmdDump, opts_dump, info_dump, 0}, + {"dumpxml", cmdDumpXML, opts_dumpxml, info_dumpxml, 0}, + {"edit", cmdEdit, opts_edit, info_edit, 0}, + {"inject-nmi", cmdInjectNMI, opts_inject_nmi, info_inject_nmi, 0}, + {"send-key", cmdSendKey, opts_send_key, info_send_key, 0}, + {"managedsave", cmdManagedSave, opts_managedsave, info_managedsave, 0}, + {"managedsave-remove", cmdManagedSaveRemove, opts_managedsaveremove, + info_managedsaveremove, 0}, + {"maxvcpus", cmdMaxvcpus, opts_maxvcpus, info_maxvcpus, 0}, + {"memtune", cmdMemtune, opts_memtune, info_memtune, 0}, + {"migrate", cmdMigrate, opts_migrate, info_migrate, 0}, + {"migrate-setmaxdowntime", cmdMigrateSetMaxDowntime, + opts_migrate_setmaxdowntime, info_migrate_setmaxdowntime, 0}, + {"migrate-setspeed", cmdMigrateSetMaxSpeed, + opts_migrate_setspeed, info_migrate_setspeed, 0}, + {"migrate-getspeed", cmdMigrateGetMaxSpeed, + opts_migrate_getspeed, info_migrate_getspeed, 0}, + {"numatune", cmdNumatune, opts_numatune, info_numatune, 0}, + {"reboot", cmdReboot, opts_reboot, info_reboot, 0}, + {"reset", cmdReset, opts_reset, info_reset, 0}, + {"restore", cmdRestore, opts_restore, info_restore, 0}, + {"resume", cmdResume, opts_resume, info_resume, 0}, + {"save", cmdSave, opts_save, info_save, 0}, + {"save-image-define", cmdSaveImageDefine, opts_save_image_define, + info_save_image_define, 0}, + {"save-image-dumpxml", cmdSaveImageDumpxml, opts_save_image_dumpxml, + info_save_image_dumpxml, 0}, + {"save-image-edit", cmdSaveImageEdit, opts_save_image_edit, + info_save_image_edit, 0}, + {"schedinfo", cmdSchedinfo, opts_schedinfo, info_schedinfo, 0}, + {"screenshot", cmdScreenshot, opts_screenshot, info_screenshot, 0}, + {"setmaxmem", cmdSetmaxmem, opts_setmaxmem, info_setmaxmem, 0}, + {"setmem", cmdSetmem, opts_setmem, info_setmem, 0}, + {"setvcpus", cmdSetvcpus, opts_setvcpus, info_setvcpus, 0}, + {"shutdown", cmdShutdown, opts_shutdown, info_shutdown, 0}, + {"start", cmdStart, opts_start, info_start, 0}, + {"suspend", cmdSuspend, opts_suspend, info_suspend, 0}, + {"ttyconsole", cmdTTYConsole, opts_ttyconsole, info_ttyconsole, 0}, + {"undefine", cmdUndefine, opts_undefine, info_undefine, 0}, + {"update-device", cmdUpdateDevice, opts_update_device, + info_update_device, 0}, + {"vcpucount", cmdVcpucount, opts_vcpucount, info_vcpucount, 0}, + {"vcpuinfo", cmdVcpuinfo, opts_vcpuinfo, info_vcpuinfo, 0}, + {"vcpupin", cmdVcpuPin, opts_vcpupin, info_vcpupin, 0}, + {"vncdisplay", cmdVNCDisplay, opts_vncdisplay, info_vncdisplay, 0}, + {NULL, NULL, NULL, NULL, 0} +}; diff --git a/tools/virsh-host.c b/tools/virsh-host.c index c6296d3..298fb2a 100644 --- a/tools/virsh-host.c +++ b/tools/virsh-host.c @@ -818,3 +818,22 @@ cmdVersion(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) return true; } + +static const vshCmdDef hostAndHypervisorCmds[] = { + {"capabilities", cmdCapabilities, NULL, info_capabilities, 0}, + {"connect", cmdConnect, opts_connect, info_connect, + VSH_CMD_FLAG_NOCONNECT}, + {"freecell", cmdFreecell, opts_freecell, info_freecell, 0}, + {"hostname", cmdHostname, NULL, info_hostname, 0}, + {"nodecpustats", cmdNodeCpuStats, opts_node_cpustats, info_nodecpustats, 0}, + {"nodeinfo", cmdNodeinfo, NULL, info_nodeinfo, 0}, + {"nodememstats", cmdNodeMemStats, opts_node_memstats, info_nodememstats, 0}, + {"nodesuspend", cmdNodeSuspend, opts_node_suspend, info_nodesuspend, 0}, + {"qemu-attach", cmdQemuAttach, opts_qemu_attach, info_qemu_attach, 0}, + {"qemu-monitor-command", cmdQemuMonitorCommand, opts_qemu_monitor_command, + info_qemu_monitor_command, 0}, + {"sysinfo", cmdSysinfo, NULL, info_sysinfo, 0}, + {"uri", cmdURI, NULL, info_uri, 0}, + {"version", cmdVersion, opts_version, info_version, 0}, + {NULL, NULL, NULL, NULL, 0} +}; diff --git a/tools/virsh-interface.c b/tools/virsh-interface.c index 6a43bb1..8c116c8 100644 --- a/tools/virsh-interface.c +++ b/tools/virsh-interface.c @@ -998,3 +998,35 @@ cmdInterfaceUnbridge(vshControl *ctl, const vshCmd *cmd) xmlFreeDoc(xml_doc); return ret; } + +static const vshCmdDef ifaceCmds[] = { + {"iface-begin", cmdInterfaceBegin, opts_interface_begin, + info_interface_begin, 0}, + {"iface-bridge", cmdInterfaceBridge, opts_interface_bridge, + info_interface_bridge, 0}, + {"iface-commit", cmdInterfaceCommit, opts_interface_commit, + info_interface_commit, 0}, + {"iface-define", cmdInterfaceDefine, opts_interface_define, + info_interface_define, 0}, + {"iface-destroy", cmdInterfaceDestroy, opts_interface_destroy, + info_interface_destroy, 0}, + {"iface-dumpxml", cmdInterfaceDumpXML, opts_interface_dumpxml, + info_interface_dumpxml, 0}, + {"iface-edit", cmdInterfaceEdit, opts_interface_edit, + info_interface_edit, 0}, + {"iface-list", cmdInterfaceList, opts_interface_list, + info_interface_list, 0}, + {"iface-mac", cmdInterfaceMAC, opts_interface_mac, + info_interface_mac, 0}, + {"iface-name", cmdInterfaceName, opts_interface_name, + info_interface_name, 0}, + {"iface-rollback", cmdInterfaceRollback, opts_interface_rollback, + info_interface_rollback, 0}, + {"iface-start", cmdInterfaceStart, opts_interface_start, + info_interface_start, 0}, + {"iface-unbridge", cmdInterfaceUnbridge, opts_interface_unbridge, + info_interface_unbridge, 0}, + {"iface-undefine", cmdInterfaceUndefine, opts_interface_undefine, + info_interface_undefine, 0}, + {NULL, NULL, NULL, NULL, 0} +}; diff --git a/tools/virsh-network.c b/tools/virsh-network.c index 459ccfe..f5df891 100644 --- a/tools/virsh-network.c +++ b/tools/virsh-network.c @@ -686,3 +686,25 @@ cmdNetworkEdit(vshControl *ctl, const vshCmd *cmd) return ret; } + +static const vshCmdDef networkCmds[] = { + {"net-autostart", cmdNetworkAutostart, opts_network_autostart, + info_network_autostart, 0}, + {"net-create", cmdNetworkCreate, opts_network_create, + info_network_create, 0}, + {"net-define", cmdNetworkDefine, opts_network_define, + info_network_define, 0}, + {"net-destroy", cmdNetworkDestroy, opts_network_destroy, + info_network_destroy, 0}, + {"net-dumpxml", cmdNetworkDumpXML, opts_network_dumpxml, + info_network_dumpxml, 0}, + {"net-edit", cmdNetworkEdit, opts_network_edit, info_network_edit, 0}, + {"net-info", cmdNetworkInfo, opts_network_info, info_network_info, 0}, + {"net-list", cmdNetworkList, opts_network_list, info_network_list, 0}, + {"net-name", cmdNetworkName, opts_network_name, info_network_name, 0}, + {"net-start", cmdNetworkStart, opts_network_start, info_network_start, 0}, + {"net-undefine", cmdNetworkUndefine, opts_network_undefine, + info_network_undefine, 0}, + {"net-uuid", cmdNetworkUuid, opts_network_uuid, info_network_uuid, 0}, + {NULL, NULL, NULL, NULL, 0} +}; diff --git a/tools/virsh-nodedev.c b/tools/virsh-nodedev.c index ee9a6fd..ecff0d7 100644 --- a/tools/virsh-nodedev.c +++ b/tools/virsh-nodedev.c @@ -381,3 +381,22 @@ cmdNodeDeviceReset(vshControl *ctl, const vshCmd *cmd) return ret; } +static const vshCmdDef nodedevCmds[] = { + {"nodedev-create", cmdNodeDeviceCreate, opts_node_device_create, + info_node_device_create, 0}, + {"nodedev-destroy", cmdNodeDeviceDestroy, opts_node_device_destroy, + info_node_device_destroy, 0}, + {"nodedev-detach", cmdNodeDeviceDetach, opts_node_device_detach, + info_node_device_detach, 0}, + {"nodedev-dettach", cmdNodeDeviceDetach, opts_node_device_detach, + info_node_device_detach, VSH_CMD_FLAG_ALIAS}, + {"nodedev-dumpxml", cmdNodeDeviceDumpXML, opts_node_device_dumpxml, + info_node_device_dumpxml, 0}, + {"nodedev-list", cmdNodeListDevices, opts_node_list_devices, + info_node_list_devices, 0}, + {"nodedev-reattach", cmdNodeDeviceReAttach, opts_node_device_reattach, + info_node_device_reattach, 0}, + {"nodedev-reset", cmdNodeDeviceReset, opts_node_device_reset, + info_node_device_reset, 0}, + {NULL, NULL, NULL, NULL, 0} +}; diff --git a/tools/virsh-nwfilter.c b/tools/virsh-nwfilter.c index 4b4996a..1fbe253 100644 --- a/tools/virsh-nwfilter.c +++ b/tools/virsh-nwfilter.c @@ -308,3 +308,17 @@ cleanup: return ret; } + +static const vshCmdDef nwfilterCmds[] = { + {"nwfilter-define", cmdNWFilterDefine, opts_nwfilter_define, + info_nwfilter_define, 0}, + {"nwfilter-dumpxml", cmdNWFilterDumpXML, opts_nwfilter_dumpxml, + info_nwfilter_dumpxml, 0}, + {"nwfilter-edit", cmdNWFilterEdit, opts_nwfilter_edit, + info_nwfilter_edit, 0}, + {"nwfilter-list", cmdNWFilterList, opts_nwfilter_list, + info_nwfilter_list, 0}, + {"nwfilter-undefine", cmdNWFilterUndefine, opts_nwfilter_undefine, + info_nwfilter_undefine, 0}, + {NULL, NULL, NULL, NULL, 0} +}; diff --git a/tools/virsh-pool.c b/tools/virsh-pool.c index 6a1208f..6c8e0a3 100644 --- a/tools/virsh-pool.c +++ b/tools/virsh-pool.c @@ -1413,3 +1413,30 @@ cmdPoolEdit(vshControl *ctl, const vshCmd *cmd) return ret; } + +static const vshCmdDef storagePoolCmds[] = { + {"find-storage-pool-sources-as", cmdPoolDiscoverSourcesAs, + opts_find_storage_pool_sources_as, info_find_storage_pool_sources_as, 0}, + {"find-storage-pool-sources", cmdPoolDiscoverSources, + opts_find_storage_pool_sources, info_find_storage_pool_sources, 0}, + {"pool-autostart", cmdPoolAutostart, opts_pool_autostart, + info_pool_autostart, 0}, + {"pool-build", cmdPoolBuild, opts_pool_build, info_pool_build, 0}, + {"pool-create-as", cmdPoolCreateAs, opts_pool_X_as, info_pool_create_as, 0}, + {"pool-create", cmdPoolCreate, opts_pool_create, info_pool_create, 0}, + {"pool-define-as", cmdPoolDefineAs, opts_pool_X_as, info_pool_define_as, 0}, + {"pool-define", cmdPoolDefine, opts_pool_define, info_pool_define, 0}, + {"pool-delete", cmdPoolDelete, opts_pool_delete, info_pool_delete, 0}, + {"pool-destroy", cmdPoolDestroy, opts_pool_destroy, info_pool_destroy, 0}, + {"pool-dumpxml", cmdPoolDumpXML, opts_pool_dumpxml, info_pool_dumpxml, 0}, + {"pool-edit", cmdPoolEdit, opts_pool_edit, info_pool_edit, 0}, + {"pool-info", cmdPoolInfo, opts_pool_info, info_pool_info, 0}, + {"pool-list", cmdPoolList, opts_pool_list, info_pool_list, 0}, + {"pool-name", cmdPoolName, opts_pool_name, info_pool_name, 0}, + {"pool-refresh", cmdPoolRefresh, opts_pool_refresh, info_pool_refresh, 0}, + {"pool-start", cmdPoolStart, opts_pool_start, info_pool_start, 0}, + {"pool-undefine", cmdPoolUndefine, opts_pool_undefine, + info_pool_undefine, 0}, + {"pool-uuid", cmdPoolUuid, opts_pool_uuid, info_pool_uuid, 0}, + {NULL, NULL, NULL, NULL, 0} +}; diff --git a/tools/virsh-secret.c b/tools/virsh-secret.c index 9ec3186..6cbc635 100644 --- a/tools/virsh-secret.c +++ b/tools/virsh-secret.c @@ -356,3 +356,18 @@ cmdSecretList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) VIR_FREE(uuids); return true; } + +static const vshCmdDef secretCmds[] = { + {"secret-define", cmdSecretDefine, opts_secret_define, + info_secret_define, 0}, + {"secret-dumpxml", cmdSecretDumpXML, opts_secret_dumpxml, + info_secret_dumpxml, 0}, + {"secret-get-value", cmdSecretGetValue, opts_secret_get_value, + info_secret_get_value, 0}, + {"secret-list", cmdSecretList, NULL, info_secret_list, 0}, + {"secret-set-value", cmdSecretSetValue, opts_secret_set_value, + info_secret_set_value, 0}, + {"secret-undefine", cmdSecretUndefine, opts_secret_undefine, + info_secret_undefine, 0}, + {NULL, NULL, NULL, NULL, 0} +}; diff --git a/tools/virsh-snapshot.c b/tools/virsh-snapshot.c index c0a2d9d..819e7b3 100644 --- a/tools/virsh-snapshot.c +++ b/tools/virsh-snapshot.c @@ -1602,3 +1602,27 @@ cleanup: return ret; } + +static const vshCmdDef snapshotCmds[] = { + {"snapshot-create", cmdSnapshotCreate, opts_snapshot_create, + info_snapshot_create, 0}, + {"snapshot-create-as", cmdSnapshotCreateAs, opts_snapshot_create_as, + info_snapshot_create_as, 0}, + {"snapshot-current", cmdSnapshotCurrent, opts_snapshot_current, + info_snapshot_current, 0}, + {"snapshot-delete", cmdSnapshotDelete, opts_snapshot_delete, + info_snapshot_delete, 0}, + {"snapshot-dumpxml", cmdSnapshotDumpXML, opts_snapshot_dumpxml, + info_snapshot_dumpxml, 0}, + {"snapshot-edit", cmdSnapshotEdit, opts_snapshot_edit, + info_snapshot_edit, 0}, + {"snapshot-info", cmdSnapshotInfo, opts_snapshot_info, + info_snapshot_info, 0}, + {"snapshot-list", cmdSnapshotList, opts_snapshot_list, + info_snapshot_list, 0}, + {"snapshot-parent", cmdSnapshotParent, opts_snapshot_parent, + info_snapshot_parent, 0}, + {"snapshot-revert", cmdDomainSnapshotRevert, opts_snapshot_revert, + info_snapshot_revert, 0}, + {NULL, NULL, NULL, NULL, 0} +}; diff --git a/tools/virsh-volume.c b/tools/virsh-volume.c index 6fb721e..39ba59a 100644 --- a/tools/virsh-volume.c +++ b/tools/virsh-volume.c @@ -1438,3 +1438,25 @@ cmdVolPath(vshControl *ctl, const vshCmd *cmd) virStorageVolFree(vol); return true; } + +static const vshCmdDef storageVolCmds[] = { + {"vol-clone", cmdVolClone, opts_vol_clone, info_vol_clone, 0}, + {"vol-create-as", cmdVolCreateAs, opts_vol_create_as, + info_vol_create_as, 0}, + {"vol-create", cmdVolCreate, opts_vol_create, info_vol_create, 0}, + {"vol-create-from", cmdVolCreateFrom, opts_vol_create_from, + info_vol_create_from, 0}, + {"vol-delete", cmdVolDelete, opts_vol_delete, info_vol_delete, 0}, + {"vol-download", cmdVolDownload, opts_vol_download, info_vol_download, 0}, + {"vol-dumpxml", cmdVolDumpXML, opts_vol_dumpxml, info_vol_dumpxml, 0}, + {"vol-info", cmdVolInfo, opts_vol_info, info_vol_info, 0}, + {"vol-key", cmdVolKey, opts_vol_key, info_vol_key, 0}, + {"vol-list", cmdVolList, opts_vol_list, info_vol_list, 0}, + {"vol-name", cmdVolName, opts_vol_name, info_vol_name, 0}, + {"vol-path", cmdVolPath, opts_vol_path, info_vol_path, 0}, + {"vol-pool", cmdVolPool, opts_vol_pool, info_vol_pool, 0}, + {"vol-resize", cmdVolResize, opts_vol_resize, info_vol_resize, 0}, + {"vol-upload", cmdVolUpload, opts_vol_upload, info_vol_upload, 0}, + {"vol-wipe", cmdVolWipe, opts_vol_wipe, info_vol_wipe, 0}, + {NULL, NULL, NULL, NULL, 0} +}; diff --git a/tools/virsh.c b/tools/virsh.c index e461410..8840460 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -3160,285 +3160,16 @@ vshParseArgv(vshControl *ctl, int argc, char **argv) } #include "virsh-domain.c" - -static const vshCmdDef domManagementCmds[] = { - {"attach-device", cmdAttachDevice, opts_attach_device, - info_attach_device, 0}, - {"attach-disk", cmdAttachDisk, opts_attach_disk, - info_attach_disk, 0}, - {"attach-interface", cmdAttachInterface, opts_attach_interface, - info_attach_interface, 0}, - {"autostart", cmdAutostart, opts_autostart, info_autostart, 0}, - {"blkdeviotune", cmdBlkdeviotune, opts_blkdeviotune, info_blkdeviotune, 0}, - {"blkiotune", cmdBlkiotune, opts_blkiotune, info_blkiotune, 0}, - {"blockcopy", cmdBlockCopy, opts_block_copy, info_block_copy, 0}, - {"blockjob", cmdBlockJob, opts_block_job, info_block_job, 0}, - {"blockpull", cmdBlockPull, opts_block_pull, info_block_pull, 0}, - {"blockresize", cmdBlockResize, opts_block_resize, info_block_resize, 0}, - {"change-media", cmdChangeMedia, opts_change_media, info_change_media, 0}, -#ifndef WIN32 - {"console", cmdConsole, opts_console, info_console, 0}, -#endif - {"cpu-baseline", cmdCPUBaseline, opts_cpu_baseline, info_cpu_baseline, 0}, - {"cpu-compare", cmdCPUCompare, opts_cpu_compare, info_cpu_compare, 0}, - {"cpu-stats", cmdCPUStats, opts_cpu_stats, info_cpu_stats, 0}, - {"create", cmdCreate, opts_create, info_create, 0}, - {"define", cmdDefine, opts_define, info_define, 0}, - {"desc", cmdDesc, opts_desc, info_desc, 0}, - {"destroy", cmdDestroy, opts_destroy, info_destroy, 0}, - {"detach-device", cmdDetachDevice, opts_detach_device, - info_detach_device, 0}, - {"detach-disk", cmdDetachDisk, opts_detach_disk, info_detach_disk, 0}, - {"detach-interface", cmdDetachInterface, opts_detach_interface, - info_detach_interface, 0}, - {"domdisplay", cmdDomDisplay, opts_domdisplay, info_domdisplay, 0}, - {"domhostname", cmdDomHostname, opts_domhostname, info_domhostname, 0}, - {"domid", cmdDomid, opts_domid, info_domid, 0}, - {"domif-setlink", cmdDomIfSetLink, opts_domif_setlink, info_domif_setlink, 0}, - {"domiftune", cmdDomIftune, opts_domiftune, info_domiftune, 0}, - {"domjobabort", cmdDomjobabort, opts_domjobabort, info_domjobabort, 0}, - {"domjobinfo", cmdDomjobinfo, opts_domjobinfo, info_domjobinfo, 0}, - {"domname", cmdDomname, opts_domname, info_domname, 0}, - {"dompmsuspend", cmdDomPMSuspend, - opts_dom_pm_suspend, info_dom_pm_suspend, 0}, - {"dompmwakeup", cmdDomPMWakeup, - opts_dom_pm_wakeup, info_dom_pm_wakeup, 0}, - {"domuuid", cmdDomuuid, opts_domuuid, info_domuuid, 0}, - {"domxml-from-native", cmdDomXMLFromNative, opts_domxmlfromnative, - info_domxmlfromnative, 0}, - {"domxml-to-native", cmdDomXMLToNative, opts_domxmltonative, - info_domxmltonative, 0}, - {"dump", cmdDump, opts_dump, info_dump, 0}, - {"dumpxml", cmdDumpXML, opts_dumpxml, info_dumpxml, 0}, - {"edit", cmdEdit, opts_edit, info_edit, 0}, - {"inject-nmi", cmdInjectNMI, opts_inject_nmi, info_inject_nmi, 0}, - {"send-key", cmdSendKey, opts_send_key, info_send_key, 0}, - {"managedsave", cmdManagedSave, opts_managedsave, info_managedsave, 0}, - {"managedsave-remove", cmdManagedSaveRemove, opts_managedsaveremove, - info_managedsaveremove, 0}, - {"maxvcpus", cmdMaxvcpus, opts_maxvcpus, info_maxvcpus, 0}, - {"memtune", cmdMemtune, opts_memtune, info_memtune, 0}, - {"migrate", cmdMigrate, opts_migrate, info_migrate, 0}, - {"migrate-setmaxdowntime", cmdMigrateSetMaxDowntime, - opts_migrate_setmaxdowntime, info_migrate_setmaxdowntime, 0}, - {"migrate-setspeed", cmdMigrateSetMaxSpeed, - opts_migrate_setspeed, info_migrate_setspeed, 0}, - {"migrate-getspeed", cmdMigrateGetMaxSpeed, - opts_migrate_getspeed, info_migrate_getspeed, 0}, - {"numatune", cmdNumatune, opts_numatune, info_numatune, 0}, - {"reboot", cmdReboot, opts_reboot, info_reboot, 0}, - {"reset", cmdReset, opts_reset, info_reset, 0}, - {"restore", cmdRestore, opts_restore, info_restore, 0}, - {"resume", cmdResume, opts_resume, info_resume, 0}, - {"save", cmdSave, opts_save, info_save, 0}, - {"save-image-define", cmdSaveImageDefine, opts_save_image_define, - info_save_image_define, 0}, - {"save-image-dumpxml", cmdSaveImageDumpxml, opts_save_image_dumpxml, - info_save_image_dumpxml, 0}, - {"save-image-edit", cmdSaveImageEdit, opts_save_image_edit, - info_save_image_edit, 0}, - {"schedinfo", cmdSchedinfo, opts_schedinfo, info_schedinfo, 0}, - {"screenshot", cmdScreenshot, opts_screenshot, info_screenshot, 0}, - {"setmaxmem", cmdSetmaxmem, opts_setmaxmem, info_setmaxmem, 0}, - {"setmem", cmdSetmem, opts_setmem, info_setmem, 0}, - {"setvcpus", cmdSetvcpus, opts_setvcpus, info_setvcpus, 0}, - {"shutdown", cmdShutdown, opts_shutdown, info_shutdown, 0}, - {"start", cmdStart, opts_start, info_start, 0}, - {"suspend", cmdSuspend, opts_suspend, info_suspend, 0}, - {"ttyconsole", cmdTTYConsole, opts_ttyconsole, info_ttyconsole, 0}, - {"undefine", cmdUndefine, opts_undefine, info_undefine, 0}, - {"update-device", cmdUpdateDevice, opts_update_device, - info_update_device, 0}, - {"vcpucount", cmdVcpucount, opts_vcpucount, info_vcpucount, 0}, - {"vcpuinfo", cmdVcpuinfo, opts_vcpuinfo, info_vcpuinfo, 0}, - {"vcpupin", cmdVcpuPin, opts_vcpupin, info_vcpupin, 0}, - {"vncdisplay", cmdVNCDisplay, opts_vncdisplay, info_vncdisplay, 0}, - {NULL, NULL, NULL, NULL, 0} -}; - #include "virsh-domain-monitor.c" - -static const vshCmdDef domMonitoringCmds[] = { - {"domblkerror", cmdDomBlkError, opts_domblkerror, info_domblkerror, 0}, - {"domblkinfo", cmdDomblkinfo, opts_domblkinfo, info_domblkinfo, 0}, - {"domblklist", cmdDomblklist, opts_domblklist, info_domblklist, 0}, - {"domblkstat", cmdDomblkstat, opts_domblkstat, info_domblkstat, 0}, - {"domcontrol", cmdDomControl, opts_domcontrol, info_domcontrol, 0}, - {"domif-getlink", cmdDomIfGetLink, opts_domif_getlink, info_domif_getlink, 0}, - {"domiflist", cmdDomiflist, opts_domiflist, info_domiflist, 0}, - {"domifstat", cmdDomIfstat, opts_domifstat, info_domifstat, 0}, - {"dominfo", cmdDominfo, opts_dominfo, info_dominfo, 0}, - {"dommemstat", cmdDomMemStat, opts_dommemstat, info_dommemstat, 0}, - {"domstate", cmdDomstate, opts_domstate, info_domstate, 0}, - {"list", cmdList, opts_list, info_list, 0}, - {NULL, NULL, NULL, NULL, 0} -}; - #include "virsh-pool.c" - -static const vshCmdDef storagePoolCmds[] = { - {"find-storage-pool-sources-as", cmdPoolDiscoverSourcesAs, - opts_find_storage_pool_sources_as, info_find_storage_pool_sources_as, 0}, - {"find-storage-pool-sources", cmdPoolDiscoverSources, - opts_find_storage_pool_sources, info_find_storage_pool_sources, 0}, - {"pool-autostart", cmdPoolAutostart, opts_pool_autostart, - info_pool_autostart, 0}, - {"pool-build", cmdPoolBuild, opts_pool_build, info_pool_build, 0}, - {"pool-create-as", cmdPoolCreateAs, opts_pool_X_as, info_pool_create_as, 0}, - {"pool-create", cmdPoolCreate, opts_pool_create, info_pool_create, 0}, - {"pool-define-as", cmdPoolDefineAs, opts_pool_X_as, info_pool_define_as, 0}, - {"pool-define", cmdPoolDefine, opts_pool_define, info_pool_define, 0}, - {"pool-delete", cmdPoolDelete, opts_pool_delete, info_pool_delete, 0}, - {"pool-destroy", cmdPoolDestroy, opts_pool_destroy, info_pool_destroy, 0}, - {"pool-dumpxml", cmdPoolDumpXML, opts_pool_dumpxml, info_pool_dumpxml, 0}, - {"pool-edit", cmdPoolEdit, opts_pool_edit, info_pool_edit, 0}, - {"pool-info", cmdPoolInfo, opts_pool_info, info_pool_info, 0}, - {"pool-list", cmdPoolList, opts_pool_list, info_pool_list, 0}, - {"pool-name", cmdPoolName, opts_pool_name, info_pool_name, 0}, - {"pool-refresh", cmdPoolRefresh, opts_pool_refresh, info_pool_refresh, 0}, - {"pool-start", cmdPoolStart, opts_pool_start, info_pool_start, 0}, - {"pool-undefine", cmdPoolUndefine, opts_pool_undefine, - info_pool_undefine, 0}, - {"pool-uuid", cmdPoolUuid, opts_pool_uuid, info_pool_uuid, 0}, - {NULL, NULL, NULL, NULL, 0} -}; - #include "virsh-volume.c" - -static const vshCmdDef storageVolCmds[] = { - {"vol-clone", cmdVolClone, opts_vol_clone, info_vol_clone, 0}, - {"vol-create-as", cmdVolCreateAs, opts_vol_create_as, - info_vol_create_as, 0}, - {"vol-create", cmdVolCreate, opts_vol_create, info_vol_create, 0}, - {"vol-create-from", cmdVolCreateFrom, opts_vol_create_from, - info_vol_create_from, 0}, - {"vol-delete", cmdVolDelete, opts_vol_delete, info_vol_delete, 0}, - {"vol-download", cmdVolDownload, opts_vol_download, info_vol_download, 0}, - {"vol-dumpxml", cmdVolDumpXML, opts_vol_dumpxml, info_vol_dumpxml, 0}, - {"vol-info", cmdVolInfo, opts_vol_info, info_vol_info, 0}, - {"vol-key", cmdVolKey, opts_vol_key, info_vol_key, 0}, - {"vol-list", cmdVolList, opts_vol_list, info_vol_list, 0}, - {"vol-name", cmdVolName, opts_vol_name, info_vol_name, 0}, - {"vol-path", cmdVolPath, opts_vol_path, info_vol_path, 0}, - {"vol-pool", cmdVolPool, opts_vol_pool, info_vol_pool, 0}, - {"vol-resize", cmdVolResize, opts_vol_resize, info_vol_resize, 0}, - {"vol-upload", cmdVolUpload, opts_vol_upload, info_vol_upload, 0}, - {"vol-wipe", cmdVolWipe, opts_vol_wipe, info_vol_wipe, 0}, - {NULL, NULL, NULL, NULL, 0} -}; - #include "virsh-network.c" - -static const vshCmdDef networkCmds[] = { - {"net-autostart", cmdNetworkAutostart, opts_network_autostart, - info_network_autostart, 0}, - {"net-create", cmdNetworkCreate, opts_network_create, - info_network_create, 0}, - {"net-define", cmdNetworkDefine, opts_network_define, - info_network_define, 0}, - {"net-destroy", cmdNetworkDestroy, opts_network_destroy, - info_network_destroy, 0}, - {"net-dumpxml", cmdNetworkDumpXML, opts_network_dumpxml, - info_network_dumpxml, 0}, - {"net-edit", cmdNetworkEdit, opts_network_edit, info_network_edit, 0}, - {"net-info", cmdNetworkInfo, opts_network_info, info_network_info, 0}, - {"net-list", cmdNetworkList, opts_network_list, info_network_list, 0}, - {"net-name", cmdNetworkName, opts_network_name, info_network_name, 0}, - {"net-start", cmdNetworkStart, opts_network_start, info_network_start, 0}, - {"net-undefine", cmdNetworkUndefine, opts_network_undefine, - info_network_undefine, 0}, - {"net-uuid", cmdNetworkUuid, opts_network_uuid, info_network_uuid, 0}, - {NULL, NULL, NULL, NULL, 0} -}; - #include "virsh-nodedev.c" - -static const vshCmdDef nodedevCmds[] = { - {"nodedev-create", cmdNodeDeviceCreate, opts_node_device_create, - info_node_device_create, 0}, - {"nodedev-destroy", cmdNodeDeviceDestroy, opts_node_device_destroy, - info_node_device_destroy, 0}, - {"nodedev-detach", cmdNodeDeviceDetach, opts_node_device_detach, - info_node_device_detach, 0}, - {"nodedev-dettach", cmdNodeDeviceDetach, opts_node_device_detach, - info_node_device_detach, VSH_CMD_FLAG_ALIAS}, - {"nodedev-dumpxml", cmdNodeDeviceDumpXML, opts_node_device_dumpxml, - info_node_device_dumpxml, 0}, - {"nodedev-list", cmdNodeListDevices, opts_node_list_devices, - info_node_list_devices, 0}, - {"nodedev-reattach", cmdNodeDeviceReAttach, opts_node_device_reattach, - info_node_device_reattach, 0}, - {"nodedev-reset", cmdNodeDeviceReset, opts_node_device_reset, - info_node_device_reset, 0}, - {NULL, NULL, NULL, NULL, 0} -}; - #include "virsh-interface.c" - -static const vshCmdDef ifaceCmds[] = { - {"iface-begin", cmdInterfaceBegin, opts_interface_begin, - info_interface_begin, 0}, - {"iface-bridge", cmdInterfaceBridge, opts_interface_bridge, - info_interface_bridge, 0}, - {"iface-commit", cmdInterfaceCommit, opts_interface_commit, - info_interface_commit, 0}, - {"iface-define", cmdInterfaceDefine, opts_interface_define, - info_interface_define, 0}, - {"iface-destroy", cmdInterfaceDestroy, opts_interface_destroy, - info_interface_destroy, 0}, - {"iface-dumpxml", cmdInterfaceDumpXML, opts_interface_dumpxml, - info_interface_dumpxml, 0}, - {"iface-edit", cmdInterfaceEdit, opts_interface_edit, - info_interface_edit, 0}, - {"iface-list", cmdInterfaceList, opts_interface_list, - info_interface_list, 0}, - {"iface-mac", cmdInterfaceMAC, opts_interface_mac, - info_interface_mac, 0}, - {"iface-name", cmdInterfaceName, opts_interface_name, - info_interface_name, 0}, - {"iface-rollback", cmdInterfaceRollback, opts_interface_rollback, - info_interface_rollback, 0}, - {"iface-start", cmdInterfaceStart, opts_interface_start, - info_interface_start, 0}, - {"iface-unbridge", cmdInterfaceUnbridge, opts_interface_unbridge, - info_interface_unbridge, 0}, - {"iface-undefine", cmdInterfaceUndefine, opts_interface_undefine, - info_interface_undefine, 0}, - {NULL, NULL, NULL, NULL, 0} -}; - #include "virsh-nwfilter.c" - -static const vshCmdDef nwfilterCmds[] = { - {"nwfilter-define", cmdNWFilterDefine, opts_nwfilter_define, - info_nwfilter_define, 0}, - {"nwfilter-dumpxml", cmdNWFilterDumpXML, opts_nwfilter_dumpxml, - info_nwfilter_dumpxml, 0}, - {"nwfilter-edit", cmdNWFilterEdit, opts_nwfilter_edit, - info_nwfilter_edit, 0}, - {"nwfilter-list", cmdNWFilterList, opts_nwfilter_list, - info_nwfilter_list, 0}, - {"nwfilter-undefine", cmdNWFilterUndefine, opts_nwfilter_undefine, - info_nwfilter_undefine, 0}, - {NULL, NULL, NULL, NULL, 0} -}; - #include "virsh-secret.c" - -static const vshCmdDef secretCmds[] = { - {"secret-define", cmdSecretDefine, opts_secret_define, - info_secret_define, 0}, - {"secret-dumpxml", cmdSecretDumpXML, opts_secret_dumpxml, - info_secret_dumpxml, 0}, - {"secret-get-value", cmdSecretGetValue, opts_secret_get_value, - info_secret_get_value, 0}, - {"secret-list", cmdSecretList, NULL, info_secret_list, 0}, - {"secret-set-value", cmdSecretSetValue, opts_secret_set_value, - info_secret_set_value, 0}, - {"secret-undefine", cmdSecretUndefine, opts_secret_undefine, - info_secret_undefine, 0}, - {NULL, NULL, NULL, NULL, 0} -}; +#include "virsh-snapshot.c" +#include "virsh-host.c" static const vshCmdDef virshCmds[] = { {"cd", cmdCd, opts_cd, info_cd, VSH_CMD_FLAG_NOCONNECT}, @@ -3450,53 +3181,6 @@ static const vshCmdDef virshCmds[] = { {NULL, NULL, NULL, NULL, 0} }; -#include "virsh-snapshot.c" - -static const vshCmdDef snapshotCmds[] = { - {"snapshot-create", cmdSnapshotCreate, opts_snapshot_create, - info_snapshot_create, 0}, - {"snapshot-create-as", cmdSnapshotCreateAs, opts_snapshot_create_as, - info_snapshot_create_as, 0}, - {"snapshot-current", cmdSnapshotCurrent, opts_snapshot_current, - info_snapshot_current, 0}, - {"snapshot-delete", cmdSnapshotDelete, opts_snapshot_delete, - info_snapshot_delete, 0}, - {"snapshot-dumpxml", cmdSnapshotDumpXML, opts_snapshot_dumpxml, - info_snapshot_dumpxml, 0}, - {"snapshot-edit", cmdSnapshotEdit, opts_snapshot_edit, - info_snapshot_edit, 0}, - {"snapshot-info", cmdSnapshotInfo, opts_snapshot_info, - info_snapshot_info, 0}, - {"snapshot-list", cmdSnapshotList, opts_snapshot_list, - info_snapshot_list, 0}, - {"snapshot-parent", cmdSnapshotParent, opts_snapshot_parent, - info_snapshot_parent, 0}, - {"snapshot-revert", cmdDomainSnapshotRevert, opts_snapshot_revert, - info_snapshot_revert, 0}, - {NULL, NULL, NULL, NULL, 0} -}; - -#include "virsh-host.c" - -static const vshCmdDef hostAndHypervisorCmds[] = { - {"capabilities", cmdCapabilities, NULL, info_capabilities, 0}, - {"connect", cmdConnect, opts_connect, info_connect, - VSH_CMD_FLAG_NOCONNECT}, - {"freecell", cmdFreecell, opts_freecell, info_freecell, 0}, - {"hostname", cmdHostname, NULL, info_hostname, 0}, - {"nodecpustats", cmdNodeCpuStats, opts_node_cpustats, info_nodecpustats, 0}, - {"nodeinfo", cmdNodeinfo, NULL, info_nodeinfo, 0}, - {"nodememstats", cmdNodeMemStats, opts_node_memstats, info_nodememstats, 0}, - {"nodesuspend", cmdNodeSuspend, opts_node_suspend, info_nodesuspend, 0}, - {"qemu-attach", cmdQemuAttach, opts_qemu_attach, info_qemu_attach, 0}, - {"qemu-monitor-command", cmdQemuMonitorCommand, opts_qemu_monitor_command, - info_qemu_monitor_command, 0}, - {"sysinfo", cmdSysinfo, NULL, info_sysinfo, 0}, - {"uri", cmdURI, NULL, info_uri, 0}, - {"version", cmdVersion, opts_version, info_version, 0}, - {NULL, NULL, NULL, NULL, 0} -}; - static const vshCmdGrp cmdGroups[] = { {VSH_CMD_GRP_DOM_MANAGEMENT, "domain", domManagementCmds}, {VSH_CMD_GRP_DOM_MONITORING, "monitor", domMonitoringCmds}, -- 1.7.7.3

On 07/24/2012 11:18 AM, Osier Yang wrote:
* virsh-domain-monitor.c: Add domMonitoringCmds * virsh-domain.c: Add domManagementCmds * virsh-host.c: Add hostAndHypervisorCmds * virsh-interface.c: Add ifaceCmds * virsh-network.c: Add networkCmds * virsh-nodedev.c: Add nodedevCmds * virsh-nwfilter.c: Add nwfilterCmds * virsh-pool.c: Add storagePoolCmds * virsh-secret.c: Add secretCmds * virsh-snapshot.c: Add snapshotCmds * virsh-volume.c: Add storageVolCmds * virsh.c: Remove all the above *Cmds. --- tools/virsh-domain-monitor.c | 16 ++ tools/virsh-domain.c | 95 +++++++++++++ tools/virsh-host.c | 19 +++ tools/virsh-interface.c | 32 ++++ tools/virsh-network.c | 22 +++ tools/virsh-nodedev.c | 19 +++ tools/virsh-nwfilter.c | 14 ++ tools/virsh-pool.c | 27 ++++ tools/virsh-secret.c | 15 ++ tools/virsh-snapshot.c | 24 +++ tools/virsh-volume.c | 22 +++ tools/virsh.c | 320 +----------------------------------------- 12 files changed, 307 insertions(+), 318 deletions(-)
This patch is ok, but for the whole series together there are few more things I've found out (thanks to syntax-check, mostly): - 'virsh-snapshot.c' file should be listed under the same exception as 'virsh-domain-monitor.c' in 'cfg.mk' - All new files are missing a dot after 'Inc' in the copyright - All new files need to be added to 'po/POTFILES.in' - All new files should be added in the exception for 'require_config_h' and 'require_config_h_first' - tools/virsh.c should not have 'intprops.h' included, but 'virsh-domain-monitor.c' should (we really need to refactor this in the future =) ) I attached a trivial patch that fixes all of that in case you want to use that (maybe 'rebase -i' with 'add -p' would ease the pain). ACK with the changes from the attached fixup implemented. Martin

On 2012年07月26日 00:06, Martin Kletzander wrote:
On 07/24/2012 11:18 AM, Osier Yang wrote:
* virsh-domain-monitor.c: Add domMonitoringCmds * virsh-domain.c: Add domManagementCmds * virsh-host.c: Add hostAndHypervisorCmds * virsh-interface.c: Add ifaceCmds * virsh-network.c: Add networkCmds * virsh-nodedev.c: Add nodedevCmds * virsh-nwfilter.c: Add nwfilterCmds * virsh-pool.c: Add storagePoolCmds * virsh-secret.c: Add secretCmds * virsh-snapshot.c: Add snapshotCmds * virsh-volume.c: Add storageVolCmds * virsh.c: Remove all the above *Cmds. --- tools/virsh-domain-monitor.c | 16 ++ tools/virsh-domain.c | 95 +++++++++++++ tools/virsh-host.c | 19 +++ tools/virsh-interface.c | 32 ++++ tools/virsh-network.c | 22 +++ tools/virsh-nodedev.c | 19 +++ tools/virsh-nwfilter.c | 14 ++ tools/virsh-pool.c | 27 ++++ tools/virsh-secret.c | 15 ++ tools/virsh-snapshot.c | 24 +++ tools/virsh-volume.c | 22 +++ tools/virsh.c | 320 +----------------------------------------- 12 files changed, 307 insertions(+), 318 deletions(-)
This patch is ok, but for the whole series together there are few more things I've found out (thanks to syntax-check, mostly): - 'virsh-snapshot.c' file should be listed under the same exception as 'virsh-domain-monitor.c' in 'cfg.mk' - All new files are missing a dot after 'Inc' in the copyright - All new files need to be added to 'po/POTFILES.in' - All new files should be added in the exception for 'require_config_h' and 'require_config_h_first' - tools/virsh.c should not have 'intprops.h' included, but 'virsh-domain-monitor.c' should (we really need to refactor this in the future =) )
Thanks. These was fixed on my local branch. Regards, Osier

Attach 3/13 after compression. Thank goodness, 134K is lower than 150K. Regards, Osier

On 07/24/12 11:29, Osier Yang wrote:
Attach 3/13 after compression. Thank goodness, 134K is lower than 150K.
Regards, Osier
Yep, but still hell of a patch to review. I verified that all aditions match the removed parts of code (but not otherwise) by optical means. I'd split out some of the function in a special helper file (specialy functions that start vsh*). I'm confident enough to ACK this patch. Peter

On 2012年07月25日 21:34, Peter Krempa wrote:
On 07/24/12 11:29, Osier Yang wrote:
Attach 3/13 after compression. Thank goodness, 134K is lower than 150K.
Regards, Osier
Yep, but still hell of a patch to review. I verified that all aditions match the removed parts of code (but not otherwise) by optical means. I'd split out some of the function in a special helper file (specialy functions that start vsh*)
Yeah, I believe there are still many optimization space left. but that could be later patches. For the special helper file, perhaps in virsh.c is fine if it's small enough. Regards, Osier

There were patches on virsh committed since this set created. I run out of time today to resolve the conflicts to push the set. Please wait a while if you have any changes on virsh (to avoid I could destroy your changes with the flood when rebasing, and as a trade, I would save a bit time, :-) I will push the set tomorrow morning. After get an ACK on 13/13. Regards, Osier On 2012年07月24日 17:18, Osier Yang wrote:
There are conflicts after splitting 2/11 and 3/11, so post the whole set again.
v1 - v2: * split 2/11, and 3/11 for the patches were too big. However, the new 3/13 is still quite big. I will send it individualy after compression.
This splits virsh.c by the command groups, except 'virsh itself' group, each group will have a separate .c, filled with the its commands, a few helpers, and command group definition moved from virsh.c. and virsh.c simply include those new .c files.
It still could be optimized, but this set could set up the skelton, and further optimization could be later patches.
Osier Yang (13): virsh: Move definition of cmds and cmd groups right at the top of main virsh: Split cmds for domain monitoring from virsh.c virsh: Split cmds of domain group from virsh.c virsh: Split cmds of storage volume group from virsh.c virsh: Split cmds of storage pool group from virsh.c virsh: Split cmds to manage network from virsh.c virsh: Split cmds to manage host interface from virsh.c virsh: Split cmds to manage network filter from virsh.c virsh: Split cmds to manage secret from virsh.c virsh: Split cmds to manage domain snapshot from virsh.c virsh: Split cmds in host group from virsh.c virsh: Split cmds in node device group from virsh.c virsh: Move command group definition into its own file
tools/virsh-domain-monitor.c | 1701 ++++ tools/virsh-domain.c | 8139 +++++++++++++++++++ tools/virsh-host.c | 839 ++ tools/virsh-interface.c | 1032 +++ tools/virsh-network.c | 710 ++ tools/virsh-nodedev.c | 402 + tools/virsh-nwfilter.c | 324 + tools/virsh-pool.c | 1442 ++++ tools/virsh-secret.c | 373 + tools/virsh-snapshot.c | 1628 ++++ tools/virsh-volume.c | 1462 ++++ tools/virsh.c |18474 +----------------------------------------- 12 files changed, 18361 insertions(+), 18165 deletions(-) create mode 100644 tools/virsh-domain-monitor.c create mode 100644 tools/virsh-domain.c create mode 100644 tools/virsh-host.c create mode 100644 tools/virsh-interface.c create mode 100644 tools/virsh-network.c create mode 100644 tools/virsh-nodedev.c create mode 100644 tools/virsh-nwfilter.c create mode 100644 tools/virsh-pool.c create mode 100644 tools/virsh-secret.c create mode 100644 tools/virsh-snapshot.c create mode 100644 tools/virsh-volume.c
Regards, Osier
-- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list

On 2012年07月26日 00:02, Osier Yang wrote:
There were patches on virsh committed since this set created. I run out of time today to resolve the conflicts to push the set. Please wait a while if you have any changes on virsh (to avoid I could destroy your changes with the flood when rebasing, and as a trade, I would save a bit time, :-)
Pushed the set with various nits fixed. Regards, Osier

On 07/25/2012 10:04 PM, Osier Yang wrote:
On 2012年07月26日 00:02, Osier Yang wrote:
There were patches on virsh committed since this set created. I run out of time today to resolve the conflicts to push the set. Please wait a while if you have any changes on virsh (to avoid I could destroy your changes with the flood when rebasing, and as a trade, I would save a bit time, :-)
Pushed the set with various nits fixed.
I didn't notice this beforehand, but why do we have virsh.c but virt-helper.c? Should all the files be named virsh-helper.c? -- Eric Blake eblake@redhat.com +1-919-301-3266 Libvirt virtualization library http://libvirt.org

On 07/26/2012 08:58 AM, Eric Blake wrote:
On 07/25/2012 10:04 PM, Osier Yang wrote:
On 2012年07月26日 00:02, Osier Yang wrote:
There were patches on virsh committed since this set created. I run out of time today to resolve the conflicts to push the set. Please wait a while if you have any changes on virsh (to avoid I could destroy your changes with the flood when rebasing, and as a trade, I would save a bit time, :-)
Pushed the set with various nits fixed.
I didn't notice this beforehand, but why do we have virsh.c but virt-helper.c? Should all the files be named virsh-helper.c?
My apologies - I'm confusing the source files for virt-host-validate with the files for virsh. I guess that means I'm now wondering if we should refactor tools into having subdirectories, one per tool? -- Eric Blake eblake@redhat.com +1-919-301-3266 Libvirt virtualization library http://libvirt.org

On 07/26/2012 11:00 AM, Eric Blake wrote:
My apologies - I'm confusing the source files for virt-host-validate with the files for virsh. I guess that means I'm now wondering if we should refactor tools into having subdirectories, one per tool?
Now that one of the tools has multiple .c files, that would probably eliminate some confusion.

On 2012年07月27日 12:42, Laine Stump wrote:
On 07/26/2012 11:00 AM, Eric Blake wrote:
My apologies - I'm confusing the source files for virt-host-validate with the files for virsh. I guess that means I'm now wondering if we should refactor tools into having subdirectories, one per tool?
Now that one of the tools has multiple .c files, that would probably eliminate some confusion.
Agreed. I'm going to refactor the tools/ tree soon. Regards, Osier
participants (5)
-
Eric Blake
-
Laine Stump
-
Martin Kletzander
-
Osier Yang
-
Peter Krempa