From ac150162fd6287a0a79f335b75e7ca2e11d2dfb5 Mon Sep 17 00:00:00 2001 From: Peter Krempa Date: Tue, 5 Mar 2024 15:07:47 +0100 Subject: [PATCH] vsh: Annotate 'required' and 'positional' arguments explicitly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add 'positional' and 'required' fields to vshCmdOptDef, which will explicitly track the two properties of arguments. To ensure that we have proper coverage, add checks to vshCmddefCheckInternals validating the state of the above flags by infering it from existing data. This conversion will allow us: - remove VSH_OT_DATA in favor of VSH_OT_STRING - use VSH_OT_INT when required both as positional and non-positional - properly annotate which VSH_OT_ARGV are positional and which are not (currently inferred by whether an previous positional option exists) Signed-off-by: Peter Krempa Reviewed-by: Ján Tomko --- tools/virsh-domain-monitor.c | 5 ++ tools/virsh-domain.c | 118 +++++++++++++++++++++++++++++++++++ tools/virsh-host.c | 10 +++ tools/virsh-interface.c | 12 ++++ tools/virsh-network.c | 14 +++++ tools/virsh-nodedev.c | 20 ++++++ tools/virsh-nwfilter.c | 10 +++ tools/virsh-pool.c | 8 +++ tools/virsh-secret.c | 8 +++ tools/virsh-snapshot.c | 2 + tools/virsh-volume.c | 12 ++++ tools/virsh.h | 12 +++- tools/virt-admin.c | 22 +++++++ tools/vsh.c | 32 +++++++++- tools/vsh.h | 2 + 15 files changed, 283 insertions(+), 4 deletions(-) diff --git a/tools/virsh-domain-monitor.c b/tools/virsh-domain-monitor.c index 7a25318bbd..573451c678 100644 --- a/tools/virsh-domain-monitor.c +++ b/tools/virsh-domain-monitor.c @@ -738,6 +738,8 @@ static const vshCmdOptDef opts_domif_getlink[] = { VIRSH_COMMON_OPT_DOMAIN_FULL(0), {.name = "interface", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .completer = virshDomainInterfaceCompleter, .help = N_("interface device (MAC Address)") @@ -1038,6 +1040,8 @@ static const vshCmdOptDef opts_domifstat[] = { VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_ACTIVE), {.name = "interface", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .completer = virshDomainInterfaceCompleter, .help = N_("interface device specified by name or MAC Address") @@ -2050,6 +2054,7 @@ static const vshCmdOptDef opts_domstats[] = { }, {.name = "domain", .type = VSH_OT_ARGV, + .positional = true, .help = N_("list of domains to get stats for"), .completer = virshDomainNameCompleter, }, diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c index bbad264053..063a514521 100644 --- a/tools/virsh-domain.c +++ b/tools/virsh-domain.c @@ -420,11 +420,15 @@ static const vshCmdOptDef opts_attach_disk[] = { VIRSH_COMMON_OPT_DOMAIN_FULL(0), {.name = "source", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ | VSH_OFLAG_EMPTY_OK, .help = N_("source of disk device or name of network disk") }, {.name = "target", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .completer = virshCompleteEmpty, .help = N_("target of disk device") @@ -812,11 +816,15 @@ static const vshCmdOptDef opts_attach_interface[] = { VIRSH_COMMON_OPT_DOMAIN_FULL(0), {.name = "type", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .help = N_("network interface type") }, {.name = "source", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .help = N_("source of network interface") }, @@ -1188,6 +1196,8 @@ static const vshCmdOptDef opts_blkdeviotune[] = { VIRSH_COMMON_OPT_DOMAIN_FULL(0), {.name = "device", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .completer = virshDomainDiskTargetCompleter, .help = N_("block device") @@ -1981,6 +1991,8 @@ static const vshCmdOptDef opts_blockcommit[] = { VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_ACTIVE), {.name = "path", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .completer = virshDomainDiskTargetCompleter, .help = N_("fully-qualified path of disk") @@ -2200,6 +2212,8 @@ static const vshCmdOptDef opts_blockcopy[] = { VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_ACTIVE), {.name = "path", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .completer = virshDomainDiskTargetCompleter, .help = N_("fully-qualified path of source disk") @@ -2532,6 +2546,8 @@ static const vshCmdOptDef opts_blockjob[] = { VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_ACTIVE), {.name = "path", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .completer = virshDomainDiskTargetCompleter, .help = N_("fully-qualified path of disk") @@ -2743,6 +2759,8 @@ static const vshCmdOptDef opts_blockpull[] = { VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_ACTIVE), {.name = "path", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .completer = virshDomainDiskTargetCompleter, .help = N_("fully-qualified path of disk") @@ -2885,6 +2903,8 @@ static const vshCmdOptDef opts_blockresize[] = { VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_ACTIVE), {.name = "path", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .completer = virshDomainDiskTargetCompleter, .help = N_("Fully-qualified path of block device") @@ -3042,12 +3062,16 @@ static const vshCmdOptDef opts_domif_setlink[] = { VIRSH_COMMON_OPT_DOMAIN_FULL(0), {.name = "interface", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .completer = virshDomainInterfaceCompleter, .help = N_("interface device (MAC Address)") }, {.name = "state", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .completer = virshDomainInterfaceStateCompleter, .help = N_("new state of the device") @@ -3188,6 +3212,8 @@ static const vshCmdOptDef opts_domiftune[] = { VIRSH_COMMON_OPT_DOMAIN_FULL(0), {.name = "interface", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .completer = virshDomainInterfaceCompleter, .help = N_("interface device (MAC Address)") @@ -3413,6 +3439,8 @@ static const vshCmdOptDef opts_dom_pm_suspend[] = { VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_RUNNING), {.name = "target", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .completer = virshNodeSuspendTargetCompleter, .help = N_("mem(Suspend-to-RAM), " @@ -4096,6 +4124,8 @@ static const vshCmdOptDef opts_save[] = { VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_ACTIVE), {.name = "file", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .help = N_("where to save the data") }, @@ -4445,6 +4475,8 @@ static const vshCmdInfo info_save_image_dumpxml = { static const vshCmdOptDef opts_save_image_dumpxml[] = { {.name = "file", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .help = N_("saved state file to read") }, @@ -4502,11 +4534,15 @@ static const vshCmdInfo info_save_image_define = { static const vshCmdOptDef opts_save_image_define[] = { {.name = "file", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .help = N_("saved state file to modify") }, {.name = "xml", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .completer = virshCompletePathLocalExisting, .help = N_("filename containing updated XML for the target") @@ -4565,6 +4601,8 @@ static const vshCmdInfo info_save_image_edit = { static const vshCmdOptDef opts_save_image_edit[] = { {.name = "file", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .help = N_("saved state file to edit") }, @@ -4904,6 +4942,8 @@ static const vshCmdOptDef opts_managed_save_define[] = { VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_MANAGEDSAVE), {.name = "xml", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .completer = virshCompletePathLocalExisting, .help = N_("filename containing updated XML for the target") @@ -5180,6 +5220,8 @@ static const vshCmdInfo info_restore = { static const vshCmdOptDef opts_restore[] = { {.name = "file", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .help = N_("the state to restore") }, @@ -5263,6 +5305,8 @@ static const vshCmdOptDef opts_dump[] = { VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_ACTIVE), {.name = "file", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .help = N_("where to dump the core") }, @@ -5562,12 +5606,16 @@ static const vshCmdOptDef opts_setLifecycleAction[] = { VIRSH_COMMON_OPT_DOMAIN_FULL(0), {.name = "type", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .completer = virshDomainLifecycleCompleter, .help = N_("lifecycle type to modify") }, {.name = "action", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .completer = virshDomainLifecycleActionCompleter, .help = N_("lifecycle action to set") @@ -5654,11 +5702,15 @@ static const vshCmdOptDef opts_set_user_password[] = { VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_ACTIVE), {.name = "user", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .help = N_("the username") }, {.name = "password", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .completer = virshCompleteEmpty, .help = N_("the new password") @@ -7074,6 +7126,8 @@ static const vshCmdOptDef opts_setvcpus[] = { VIRSH_COMMON_OPT_DOMAIN_FULL(0), {.name = "count", .type = VSH_OT_INT, + .required = true, + .positional = true, .flags = VSH_OFLAG_REQ, .help = N_("number of virtual CPUs") }, @@ -7240,6 +7294,8 @@ static const vshCmdOptDef opts_setvcpu[] = { VIRSH_COMMON_OPT_DOMAIN_FULL(0), {.name = "vcpulist", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .completer = virshDomainVcpulistCompleter, .help = N_("ids of vcpus to manipulate") @@ -7314,12 +7370,16 @@ static const vshCmdOptDef opts_domblkthreshold[] = { VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_ACTIVE), {.name = "dev", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .completer = virshDomainDiskTargetCompleter, .help = N_("device to set threshold for") }, {.name = "threshold", .type = VSH_OT_INT, + .required = true, + .positional = true, .flags = VSH_OFLAG_REQ, .help = N_("threshold as a scaled number (by default bytes)") }, @@ -7442,12 +7502,16 @@ static const vshCmdOptDef opts_iothreadpin[] = { VIRSH_COMMON_OPT_DOMAIN_FULL(0), {.name = "iothread", .type = VSH_OT_INT, + .required = true, + .positional = true, .flags = VSH_OFLAG_REQ, .completer = virshDomainIOThreadIdCompleter, .help = N_("IOThread ID number") }, {.name = "cpulist", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .completer = virshDomainCpulistCompleter, .help = N_("host cpu number(s) to set") @@ -7515,6 +7579,8 @@ static const vshCmdOptDef opts_iothreadadd[] = { VIRSH_COMMON_OPT_DOMAIN_FULL(0), {.name = "id", .type = VSH_OT_INT, + .required = true, + .positional = true, .flags = VSH_OFLAG_REQ, .help = N_("iothread for the new IOThread") }, @@ -7571,6 +7637,8 @@ static const vshCmdOptDef opts_iothreadset[] = { VIRSH_COMMON_OPT_DOMAIN_FULL(0), {.name = "id", .type = VSH_OT_INT, + .required = true, + .positional = true, .flags = VSH_OFLAG_REQ, .completer = virshDomainIOThreadIdCompleter, .help = N_("iothread id of existing IOThread") @@ -7687,6 +7755,8 @@ static const vshCmdOptDef opts_iothreaddel[] = { VIRSH_COMMON_OPT_DOMAIN_FULL(0), {.name = "id", .type = VSH_OT_INT, + .required = true, + .positional = true, .flags = VSH_OFLAG_REQ, .completer = virshDomainIOThreadIdCompleter, .help = N_("iothread_id for the IOThread to delete") @@ -8277,6 +8347,8 @@ static const vshCmdOptDef opts_metadata[] = { VIRSH_COMMON_OPT_DOMAIN_FULL(0), {.name = "uri", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .help = N_("URI of the namespace") }, @@ -8455,6 +8527,7 @@ static const vshCmdOptDef opts_send_key[] = { }, {.name = "keycode", .type = VSH_OT_ARGV, + .required = true, .flags = VSH_OFLAG_REQ, .completer = virshKeycodeNameCompleter, .help = N_("the key code") @@ -8539,12 +8612,16 @@ static const vshCmdOptDef opts_send_process_signal[] = { VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_ACTIVE), {.name = "pid", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .completer = virshCompleteEmpty, .help = N_("the process ID") }, {.name = "signame", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .completer = virshDomainSignalCompleter, .help = N_("the signal number or name") @@ -8633,6 +8710,8 @@ static const vshCmdOptDef opts_setmem[] = { }, {.name = "size", .type = VSH_OT_INT, + .required = true, + .positional = true, .flags = VSH_OFLAG_REQ, .help = N_("new memory size, as scaled integer (default KiB)") }, @@ -8702,6 +8781,8 @@ static const vshCmdOptDef opts_setmaxmem[] = { }, {.name = "size", .type = VSH_OT_INT, + .required = true, + .positional = true, .flags = VSH_OFLAG_REQ, .help = N_("new maximum memory size, as scaled integer (default KiB)") }, @@ -9475,12 +9556,16 @@ static const vshCmdOptDef opts_dom_fd_associate[] = { VIRSH_COMMON_OPT_DOMAIN_FULL(0), {.name = "name", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .completer = virshCompleteEmpty, .help = N_("name of the FD group") }, {.name = "pass-fds", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .completer = virshCompleteEmpty, .help = N_("file descriptors N,M,... to associate") @@ -9557,6 +9642,7 @@ static const vshCmdOptDef opts_qemu_monitor_command[] = { }, {.name = "cmd", .type = VSH_OT_ARGV, + .required = true, .flags = VSH_OFLAG_REQ, .help = N_("command") }, @@ -9892,6 +9978,8 @@ static const vshCmdInfo info_qemu_attach = { static const vshCmdOptDef opts_qemu_attach[] = { {.name = "pid", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .completer = virshCompleteEmpty, .help = N_("pid") @@ -9949,6 +10037,7 @@ static const vshCmdOptDef opts_qemu_agent_command[] = { }, {.name = "cmd", .type = VSH_OT_ARGV, + .required = true, .flags = VSH_OFLAG_REQ, .help = N_("command") }, @@ -10045,6 +10134,7 @@ static const vshCmdOptDef opts_lxc_enter_namespace[] = { }, {.name = "cmd", .type = VSH_OT_ARGV, + .required = true, .flags = VSH_OFLAG_REQ, .help = N_("command to run") }, @@ -10224,11 +10314,15 @@ static const vshCmdInfo info_domxmlfromnative = { static const vshCmdOptDef opts_domxmlfromnative[] = { {.name = "format", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .help = N_("source config data format") }, {.name = "config", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .completer = virshCompletePathLocalExisting, .help = N_("config data file to import from") @@ -10272,6 +10366,8 @@ static const vshCmdInfo info_domxmltonative = { static const vshCmdOptDef opts_domxmltonative[] = { {.name = "format", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .help = N_("target config data type format") }, @@ -10339,6 +10435,8 @@ static const vshCmdInfo info_domname = { static const vshCmdOptDef opts_domname[] = { {.name = "domain", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .completer = virshDomainUUIDCompleter, .help = N_("domain id or uuid") @@ -10372,6 +10470,8 @@ static const vshCmdOptDef opts_domrename[] = { VIR_CONNECT_LIST_DOMAINS_INACTIVE), {.name = "new-name", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .completer = virshCompleteEmpty, .help = N_("new domain name") @@ -10474,6 +10574,8 @@ static const vshCmdOptDef opts_migrate[] = { VIRSH_COMMON_OPT_DOMAIN_FULL(0), {.name = "desturi", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .completer = virshCompleteEmpty, .help = N_("connection URI of the destination host as seen from the client(normal migration) or source(p2p migration)") @@ -11171,6 +11273,8 @@ static const vshCmdOptDef opts_migrate_setmaxdowntime[] = { VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_ACTIVE), {.name = "downtime", .type = VSH_OT_INT, + .required = true, + .positional = true, .flags = VSH_OFLAG_REQ, .help = N_("maximum tolerable downtime (in milliseconds) for migration") }, @@ -11289,6 +11393,8 @@ static const vshCmdOptDef opts_migrate_setspeed[] = { VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_ACTIVE), {.name = "bandwidth", .type = VSH_OT_INT, + .required = true, + .positional = true, .flags = VSH_OFLAG_REQ, .help = N_("migration bandwidth limit in MiB/s") }, @@ -11878,6 +11984,8 @@ static const vshCmdOptDef opts_detach_device_alias[] = { VIRSH_COMMON_OPT_DOMAIN_FULL(0), {.name = "alias", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .completer = virshDomainDeviceAliasCompleter, .help = N_("device alias") @@ -12006,6 +12114,8 @@ static const vshCmdOptDef opts_detach_interface[] = { VIRSH_COMMON_OPT_DOMAIN_FULL(0), {.name = "type", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .help = N_("network interface type") }, @@ -12378,6 +12488,8 @@ static const vshCmdOptDef opts_detach_disk[] = { VIRSH_COMMON_OPT_DOMAIN_FULL(0), {.name = "target", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .completer = virshDomainDiskTargetCompleter, .help = N_("target of disk device") @@ -12538,6 +12650,8 @@ static const vshCmdOptDef opts_change_media[] = { VIRSH_COMMON_OPT_DOMAIN_FULL(0), {.name = "path", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .completer = virshDomainDiskTargetCompleter, .help = N_("Fully-qualified path or target of disk device") @@ -13012,6 +13126,8 @@ static const vshCmdOptDef opts_get_user_sshkeys[] = { VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_ACTIVE), {.name = "user", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .help = N_("user to list authorized keys for"), }, @@ -13059,6 +13175,8 @@ static const vshCmdOptDef opts_set_user_sshkeys[] = { VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_ACTIVE), {.name = "user", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .help = N_("user to set authorized keys for"), }, diff --git a/tools/virsh-host.c b/tools/virsh-host.c index 1a97f4926b..368e656550 100644 --- a/tools/virsh-host.c +++ b/tools/virsh-host.c @@ -468,12 +468,16 @@ static const vshCmdInfo info_allocpages = { static const vshCmdOptDef opts_allocpages[] = { {.name = "pagesize", .type = VSH_OT_INT, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .completer = virshAllocpagesPagesizeCompleter, .help = N_("page size (in kibibytes)") }, {.name = "pagecount", .type = VSH_OT_INT, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .help = N_("page count") }, @@ -943,6 +947,8 @@ static const vshCmdInfo info_nodesuspend = { static const vshCmdOptDef opts_node_suspend[] = { {.name = "target", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .completer = virshNodeSuspendTargetCompleter, .help = N_("mem(Suspend-to-RAM), disk(Suspend-to-Disk), " @@ -950,6 +956,8 @@ static const vshCmdOptDef opts_node_suspend[] = { }, {.name = "duration", .type = VSH_OT_INT, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .help = N_("Suspend duration in seconds, at least 60") }, @@ -1270,6 +1278,8 @@ static const vshCmdInfo info_cpu_models = { static const vshCmdOptDef opts_cpu_models[] = { {.name = "arch", .type = VSH_OT_DATA, + .positional = true, + .required = true, .completer = virshArchCompleter, .flags = VSH_OFLAG_REQ, .help = N_("architecture") diff --git a/tools/virsh-interface.c b/tools/virsh-interface.c index 5dde4f9d46..52dce97462 100644 --- a/tools/virsh-interface.c +++ b/tools/virsh-interface.c @@ -21,6 +21,8 @@ #define VIRSH_COMMON_OPT_INTERFACE(cflags) \ {.name = "interface", \ .type = VSH_OT_DATA, \ + .positional = true, \ + .required = true, \ .flags = VSH_OFLAG_REQ, \ .help = N_("interface name or MAC address"), \ .completer = virshInterfaceNameCompleter, \ @@ -383,6 +385,8 @@ static const vshCmdInfo info_interface_name = { static const vshCmdOptDef opts_interface_name[] = { {.name = "interface", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .completer = virshInterfaceMacCompleter, .help = N_("interface mac") @@ -414,6 +418,8 @@ static const vshCmdInfo info_interface_mac = { static const vshCmdOptDef opts_interface_mac[] = { {.name = "interface", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .completer = virshInterfaceNameCompleter, .help = N_("interface name") @@ -716,12 +722,16 @@ static const vshCmdInfo info_interface_bridge = { static const vshCmdOptDef opts_interface_bridge[] = { {.name = "interface", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .completer = virshInterfaceNameCompleter, .help = N_("existing interface name") }, {.name = "bridge", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .help = N_("new bridge device name") }, @@ -943,6 +953,8 @@ static const vshCmdInfo info_interface_unbridge = { static const vshCmdOptDef opts_interface_unbridge[] = { {.name = "bridge", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .help = N_("current bridge device name") }, diff --git a/tools/virsh-network.c b/tools/virsh-network.c index 8eca6e866c..b12efdce36 100644 --- a/tools/virsh-network.c +++ b/tools/virsh-network.c @@ -33,6 +33,8 @@ #define VIRSH_COMMON_OPT_NETWORK(_helpstr, cflags) \ {.name = "network", \ .type = VSH_OT_DATA, \ + .positional = true, \ + .required = true, \ .flags = VSH_OFLAG_REQ, \ .help = _helpstr, \ .completer = virshNetworkNameCompleter, \ @@ -56,6 +58,8 @@ #define VIRSH_COMMON_OPT_NETWORK_PORT(cflags) \ {.name = "port", \ .type = VSH_OT_DATA, \ + .positional = true, \ + .required = true, \ .flags = VSH_OFLAG_REQ, \ .help = N_("port UUID"), \ .completer = virshNetworkPortUUIDCompleter, \ @@ -502,6 +506,8 @@ static const vshCmdOptDef opts_network_metadata[] = { VIRSH_COMMON_OPT_NETWORK_FULL(0), {.name = "uri", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .help = N_("URI of the namespace") }, @@ -1127,6 +1133,8 @@ static const vshCmdInfo info_network_name = { static const vshCmdOptDef opts_network_name[] = { {.name = "network", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .completer = virshNetworkUUIDCompleter, .help = N_("network uuid") @@ -1224,18 +1232,24 @@ static const vshCmdOptDef opts_network_update[] = { VIRSH_COMMON_OPT_NETWORK_FULL(0), {.name = "command", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .completer = virshNetworkUpdateCommandCompleter, .help = N_("type of update (add-first, add-last (add), delete, or modify)") }, {.name = "section", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .completer = virshNetworkUpdateSectionCompleter, .help = N_("which section of network configuration to update") }, {.name = "xml", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .completer = virshCompletePathLocalExisting, .help = N_("name of file containing xml (or, if it starts with '<', the complete " diff --git a/tools/virsh-nodedev.c b/tools/virsh-nodedev.c index c0fb319fa7..0081e3cbb7 100644 --- a/tools/virsh-nodedev.c +++ b/tools/virsh-nodedev.c @@ -97,6 +97,8 @@ static const vshCmdOptDef opts_node_device_destroy[] = { }, {.name = "device", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .help = N_("device name or wwn pair in 'wwnn,wwpn' format"), .completer = virshNodeDeviceNameCompleter, @@ -571,6 +573,8 @@ static const vshCmdInfo info_node_device_dumpxml = { static const vshCmdOptDef opts_node_device_dumpxml[] = { {.name = "device", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .help = N_("device name or wwn pair in 'wwnn,wwpn' format"), .completer = virshNodeDeviceNameCompleter, @@ -634,6 +638,8 @@ static const vshCmdInfo info_node_device_detach = { static const vshCmdOptDef opts_node_device_detach[] = { {.name = "device", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .help = N_("device key"), .completer = virshNodeDeviceNameCompleter, @@ -696,6 +702,8 @@ static const vshCmdInfo info_node_device_reattach = { static const vshCmdOptDef opts_node_device_reattach[] = { {.name = "device", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .help = N_("device key"), .completer = virshNodeDeviceNameCompleter, @@ -741,6 +749,8 @@ static const vshCmdInfo info_node_device_reset = { static const vshCmdOptDef opts_node_device_reset[] = { {.name = "device", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .help = N_("device key"), .completer = virshNodeDeviceNameCompleter, @@ -1002,6 +1012,8 @@ static const vshCmdInfo info_node_device_undefine = { static const vshCmdOptDef opts_node_device_undefine[] = { {.name = "device", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .help = N_("device name or wwn pair in 'wwnn,wwpn' format"), .completer = virshNodeDeviceNameCompleter, @@ -1093,6 +1105,8 @@ static const vshCmdInfo info_node_device_start = { static const vshCmdOptDef opts_node_device_start[] = { {.name = "device", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .help = N_("device name"), .completer = virshNodeDeviceNameCompleter, @@ -1138,6 +1152,8 @@ static const vshCmdInfo info_node_device_autostart = { static const vshCmdOptDef opts_node_device_autostart[] = { {.name = "device", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .help = N_("device name or wwn pair in 'wwnn,wwpn' format"), .completer = virshNodeDeviceNameCompleter, @@ -1195,6 +1211,8 @@ static const vshCmdInfo info_node_device_info = { static const vshCmdOptDef opts_node_device_info[] = { {.name = "device", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .help = N_("device name or wwn pair in 'wwnn,wwpn' format"), .completer = virshNodeDeviceNameCompleter, @@ -1245,6 +1263,8 @@ static const vshCmdInfo info_node_device_update = { static const vshCmdOptDef opts_node_device_update[] = { {.name = "device", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .help = N_("device name or wwn pair in 'wwnn,wwpn' format"), .completer = virshNodeDeviceNameCompleter, diff --git a/tools/virsh-nwfilter.c b/tools/virsh-nwfilter.c index 7a578f3f7c..993539d368 100644 --- a/tools/virsh-nwfilter.c +++ b/tools/virsh-nwfilter.c @@ -129,6 +129,8 @@ static const vshCmdInfo info_nwfilter_undefine = { static const vshCmdOptDef opts_nwfilter_undefine[] = { {.name = "nwfilter", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .help = N_("network filter name or uuid"), .completer = virshNWFilterNameCompleter, @@ -167,6 +169,8 @@ static const vshCmdInfo info_nwfilter_dumpxml = { static const vshCmdOptDef opts_nwfilter_dumpxml[] = { {.name = "nwfilter", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .help = N_("network filter name or uuid"), .completer = virshNWFilterNameCompleter, @@ -391,6 +395,8 @@ static const vshCmdInfo info_nwfilter_edit = { static const vshCmdOptDef opts_nwfilter_edit[] = { {.name = "nwfilter", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .help = N_("network filter name or uuid"), .completer = virshNWFilterNameCompleter, @@ -526,6 +532,8 @@ static const vshCmdInfo info_nwfilter_binding_delete = { static const vshCmdOptDef opts_nwfilter_binding_delete[] = { {.name = "binding", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .help = N_("network filter binding port dev"), .completer = virshNWFilterBindingNameCompleter, @@ -566,6 +574,8 @@ static const vshCmdInfo info_nwfilter_binding_dumpxml = { static const vshCmdOptDef opts_nwfilter_binding_dumpxml[] = { {.name = "binding", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .help = N_("network filter binding portdev"), .completer = virshNWFilterBindingNameCompleter, diff --git a/tools/virsh-pool.c b/tools/virsh-pool.c index a7b82de9be..4606990836 100644 --- a/tools/virsh-pool.c +++ b/tools/virsh-pool.c @@ -58,12 +58,16 @@ #define VIRSH_COMMON_OPT_POOL_X_AS \ {.name = "name", \ .type = VSH_OT_DATA, \ + .positional = true, \ + .required = true, \ .flags = VSH_OFLAG_REQ, \ .completer = virshCompleteEmpty, \ .help = N_("name of the pool") \ }, \ {.name = "type", \ .type = VSH_OT_DATA, \ + .positional = true, \ + .required = true, \ .flags = VSH_OFLAG_REQ, \ .completer = virshPoolTypeCompleter, \ .help = N_("type of the pool") \ @@ -1354,6 +1358,8 @@ static const vshCmdInfo info_find_storage_pool_sources_as = { static const vshCmdOptDef opts_find_storage_pool_sources_as[] = { {.name = "type", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .completer = virshPoolTypeCompleter, .help = N_("type of storage pool sources to find") @@ -1437,6 +1443,8 @@ static const vshCmdInfo info_find_storage_pool_sources = { static const vshCmdOptDef opts_find_storage_pool_sources[] = { {.name = "type", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .completer = virshPoolTypeCompleter, .help = N_("type of storage pool sources to discover") diff --git a/tools/virsh-secret.c b/tools/virsh-secret.c index a88980ef9e..d7e60de4ca 100644 --- a/tools/virsh-secret.c +++ b/tools/virsh-secret.c @@ -124,6 +124,8 @@ static const vshCmdInfo info_secret_dumpxml = { static const vshCmdOptDef opts_secret_dumpxml[] = { {.name = "secret", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .help = N_("secret UUID"), .completer = virshSecretUUIDCompleter, @@ -179,6 +181,8 @@ static const vshCmdInfo info_secret_set_value = { static const vshCmdOptDef opts_secret_set_value[] = { {.name = "secret", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .help = N_("secret UUID"), .completer = virshSecretUUIDCompleter, @@ -290,6 +294,8 @@ static const vshCmdInfo info_secret_get_value = { static const vshCmdOptDef opts_secret_get_value[] = { {.name = "secret", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .help = N_("secret UUID"), .completer = virshSecretUUIDCompleter, @@ -343,6 +349,8 @@ static const vshCmdInfo info_secret_undefine = { static const vshCmdOptDef opts_secret_undefine[] = { {.name = "secret", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .help = N_("secret UUID"), .completer = virshSecretUUIDCompleter, diff --git a/tools/virsh-snapshot.c b/tools/virsh-snapshot.c index 31ab27b112..9ad33c4252 100644 --- a/tools/virsh-snapshot.c +++ b/tools/virsh-snapshot.c @@ -1568,6 +1568,8 @@ static const vshCmdOptDef opts_snapshot_dumpxml[] = { VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_HAS_SNAPSHOT), {.name = "snapshotname", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .help = N_("snapshot name"), .completer = virshSnapshotNameCompleter, diff --git a/tools/virsh-volume.c b/tools/virsh-volume.c index 0cb7262b67..ecf89345c3 100644 --- a/tools/virsh-volume.c +++ b/tools/virsh-volume.c @@ -57,6 +57,8 @@ #define VIRSH_COMMON_OPT_VOL_NAME(_helpstr) \ {.name = "vol", \ .type = VSH_OT_DATA, \ + .positional = true, \ + .required = true, \ .flags = VSH_OFLAG_REQ, \ .help = _helpstr, \ .completer = virshStorageVolNameCompleter, \ @@ -65,6 +67,8 @@ #define VIRSH_COMMON_OPT_VOL_KEY(_helpstr) \ {.name = "vol", \ .type = VSH_OT_DATA, \ + .positional = true, \ + .required = true, \ .flags = VSH_OFLAG_REQ, \ .help = _helpstr, \ .completer = virshStorageVolKeyCompleter, \ @@ -173,12 +177,16 @@ static const vshCmdOptDef opts_vol_create_as[] = { VIRSH_COMMON_OPT_POOL_NAME, {.name = "name", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .completer = virshCompleteEmpty, .help = N_("name of the volume") }, {.name = "capacity", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .completer = virshCompleteEmpty, .help = N_("size of the vol, as scaled integer (default bytes)") @@ -520,6 +528,8 @@ static const vshCmdOptDef opts_vol_clone[] = { VIRSH_COMMON_OPT_VOL_FULL, {.name = "newname", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .completer = virshCompleteEmpty, .help = N_("clone name") @@ -1024,6 +1034,8 @@ static const vshCmdOptDef opts_vol_resize[] = { VIRSH_COMMON_OPT_VOL_FULL, {.name = "capacity", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .completer = virshCompleteEmpty, .help = N_("new capacity for the vol, as scaled integer (default bytes)") diff --git a/tools/virsh.h b/tools/virsh.h index 877b290e3a..451683769d 100644 --- a/tools/virsh.h +++ b/tools/virsh.h @@ -58,6 +58,8 @@ #define VIRSH_COMMON_OPT_POOL(_helpstr, cflags) \ {.name = "pool", \ .type = VSH_OT_DATA, \ + .positional = true, \ + .required = true, \ .flags = VSH_OFLAG_REQ, \ .help = _helpstr, \ .completer = virshStoragePoolNameCompleter, \ @@ -67,6 +69,8 @@ #define VIRSH_COMMON_OPT_DOMAIN(_helpstr, cflags) \ {.name = "domain", \ .type = VSH_OT_DATA, \ + .positional = true, \ + .required = true, \ .flags = VSH_OFLAG_REQ, \ .help = _helpstr, \ .completer = virshDomainNameCompleter, \ @@ -98,10 +102,12 @@ #define VIRSH_COMMON_OPT_FILE(_helpstr) \ VIRSH_COMMON_OPT_FILE_FULL(_helpstr, true) -#define VIRSH_COMMON_OPT_FILE_FULL(_helpstr, required) \ +#define VIRSH_COMMON_OPT_FILE_FULL(_helpstr, required_) \ {.name = "file", \ - .type = required ? VSH_OT_DATA : VSH_OT_STRING, \ - .flags = required ? VSH_OFLAG_REQ : VSH_OFLAG_NONE, \ + .type = required_ ? VSH_OT_DATA : VSH_OT_STRING, \ + .required = required_, \ + .positional = required_, \ + .flags = required_ ? VSH_OFLAG_REQ : VSH_OFLAG_NONE, \ .completer = virshCompletePathLocalExisting, \ .help = _helpstr \ } diff --git a/tools/virt-admin.c b/tools/virt-admin.c index 114ec2e8e7..d266d824cb 100644 --- a/tools/virt-admin.c +++ b/tools/virt-admin.c @@ -359,6 +359,8 @@ static const vshCmdInfo info_srv_threadpool_info = { static const vshCmdOptDef opts_srv_threadpool_info[] = { {.name = "server", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .completer = vshAdmServerCompleter, .help = N_("Server to retrieve threadpool attributes from."), @@ -416,6 +418,8 @@ static const vshCmdInfo info_srv_threadpool_set = { static const vshCmdOptDef opts_srv_threadpool_set[] = { {.name = "server", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .completer = vshAdmServerCompleter, .help = N_("Server to alter threadpool attributes on."), @@ -517,6 +521,8 @@ static const vshCmdInfo info_srv_clients_list = { static const vshCmdOptDef opts_srv_clients_list[] = { {.name = "server", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .completer = vshAdmServerCompleter, .help = N_("server which to list connected clients from"), @@ -599,12 +605,16 @@ static const vshCmdInfo info_client_info = { static const vshCmdOptDef opts_client_info[] = { {.name = "server", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .completer = vshAdmServerCompleter, .help = N_("server to which is connected to"), }, {.name = "client", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .help = N_("client which to retrieve identity information for"), }, @@ -681,12 +691,16 @@ static const vshCmdInfo info_client_disconnect = { static const vshCmdOptDef opts_client_disconnect[] = { {.name = "server", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .completer = vshAdmServerCompleter, .help = N_("server which the client is currently connected to"), }, {.name = "client", .type = VSH_OT_INT, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .help = N_("client which to disconnect, specified by ID"), }, @@ -742,6 +756,8 @@ static const vshCmdInfo info_srv_clients_info = { static const vshCmdOptDef opts_srv_clients_info[] = { {.name = "server", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .completer = vshAdmServerCompleter, .help = N_("Server to retrieve the client limits from."), @@ -796,6 +812,8 @@ static const vshCmdInfo info_srv_clients_set = { static const vshCmdOptDef opts_srv_clients_set[] = { {.name = "server", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .completer = vshAdmServerCompleter, .help = N_("Server to alter the client-related configuration limits on."), @@ -893,6 +911,8 @@ static const vshCmdInfo info_srv_update_tls_file = { static const vshCmdOptDef opts_srv_update_tls_file[] = { {.name = "server", .type = VSH_OT_DATA, + .positional = true, + .required = true, .flags = VSH_OFLAG_REQ, .help = N_("Available servers on a daemon. " "Currently only supports 'libvirtd' or 'virtproxyd'.") @@ -991,6 +1011,8 @@ static const vshCmdInfo info_daemon_log_outputs = { static const vshCmdOptDef opts_daemon_timeout[] = { {.name = "timeout", .type = VSH_OT_INT, + .positional = true, + .required = true, .help = N_("number of seconds the daemon will run without any active connection"), .flags = VSH_OFLAG_REQ | VSH_OFLAG_REQ_OPT }, diff --git a/tools/vsh.c b/tools/vsh.c index c4099bb725..f059434b1a 100644 --- a/tools/vsh.c +++ b/tools/vsh.c @@ -248,6 +248,7 @@ vshCmddefCheckInternals(vshControl *ctl, { size_t i; bool seenOptionalOption = false; + bool seenPositionalOption = false; g_auto(virBuffer) complbuf = VIR_BUFFER_INITIALIZER; /* in order to perform the validation resolve the alias first */ @@ -301,6 +302,8 @@ vshCmddefCheckInternals(vshControl *ctl, for (i = 0; cmd->opts[i].name; i++) { const vshCmdOptDef *opt = &cmd->opts[i]; + bool isPositional = false; + bool isRequired = false; if (i > 63) { vshError(ctl, "command '%s' has too many options", cmd->name); @@ -385,12 +388,17 @@ vshCmddefCheckInternals(vshControl *ctl, } } break; + case VSH_OT_ARGV: if (cmd->opts[i + 1].name) { vshError(ctl, "parameter '%s' of command '%s' must be listed last", opt->name, cmd->name); return -1; } + + isRequired = opt->flags & VSH_OFLAG_REQ; + /* ARGV argument is positional if there are no positional options */ + isPositional = !seenPositionalOption; break; case VSH_OT_DATA: @@ -400,6 +408,10 @@ vshCmddefCheckInternals(vshControl *ctl, return -1; } + isRequired = true; + isPositional = true; + seenPositionalOption = true; + if (seenOptionalOption) { vshError(ctl, "parameter '%s' of command '%s' must be listed before optional parameters", opt->name, cmd->name); @@ -414,12 +426,28 @@ vshCmddefCheckInternals(vshControl *ctl, opt->name, cmd->name); return -1; } + seenPositionalOption = true; + isPositional = true; + isRequired = true; } else { - seenOptionalOption = true; + isPositional = false; + isRequired = false; } break; } + + if (opt->required != isRequired) { + vshError(ctl, "parameter '%s' of command '%s' 'required' state mismatch", + opt->name, cmd->name); + return -1; + } + + if (opt->positional != isPositional) { + vshError(ctl, "parameter '%s' of command '%s' 'positional' state mismatch", + opt->name, cmd->name); + return -1; + } } virBufferTrim(&complbuf, ", "); @@ -3241,6 +3269,7 @@ const vshCmdOptDef opts_echo[] = { }, {.name = "string", .type = VSH_OT_ARGV, + .positional = true, .help = N_("arguments to echo") }, {.name = NULL} @@ -3379,6 +3408,7 @@ cmdSelfTest(vshControl *ctl, const vshCmd *cmd) const vshCmdOptDef opts_complete[] = { {.name = "string", .type = VSH_OT_ARGV, + .positional = true, .flags = VSH_OFLAG_EMPTY_OK, .help = N_("partial string to autocomplete") }, diff --git a/tools/vsh.h b/tools/vsh.h index 6007df2b7e..53384dbb55 100644 --- a/tools/vsh.h +++ b/tools/vsh.h @@ -133,6 +133,8 @@ struct _vshCmdInfo { struct _vshCmdOptDef { const char *name; /* the name of option, or NULL for list end */ vshCmdOptType type; /* option type */ + bool required; /* option is required */ + bool positional; /* option is a positional option (not requiring '--optionname') */ unsigned int flags; /* flags */ const char *help; /* non-NULL help string; or for VSH_OT_ALIAS * the name of a later public option */