[PATCH 5/6] virsh/virt-admin: Add possibility to probe for new arguments

Peter Krempa via Devel posted 6 patches 7 hours ago
[PATCH 5/6] virsh/virt-admin: Add possibility to probe for new arguments
Posted by Peter Krempa via Devel 7 hours ago
From: Peter Krempa <pkrempa@redhat.com>

Add users possibility to discover presence of arguments safely.

The new global argument '--probe-arguments' which runs the argument
parser but doesn't run the actual function and returning success if it
gets to the point of actually trying to runt he parser.

This will allow users to probe for new arguments (which were added after
this patch:

 - virsh prior to this patch:

   $ virsh --probe-arguments blockresize cd vda 1 --extend ; echo $?
   error: unsupported option '--probe-arguments'. See --help.
   1

 - virsh with this patch but checking for something that doesn't yet exist:

   $ virsh --probe-arguments blockresize cd vda 1 --allow-shrink ; echo $?
   error: command 'blockresize' doesn't support option --allow-shrink
   1

 - virsh with this patch with the argument present:

   $ virsh --probe-arguments blockresize cd vda 1 --allow-shrink ; echo $?
   0

Signed-off-by: Peter Krempa <pkrempa@redhat.com>
---
 docs/manpages/virsh.rst | 17 ++++++++++++++++-
 tools/virsh.c           |  4 ++++
 tools/virt-admin.c      |  9 +++++++++
 tools/vsh.c             |  3 +++
 tools/vsh.h             |  1 +
 5 files changed, 33 insertions(+), 1 deletion(-)

diff --git a/docs/manpages/virsh.rst b/docs/manpages/virsh.rst
index 80b0ea14a8..9ede859aaf 100644
--- a/docs/manpages/virsh.rst
+++ b/docs/manpages/virsh.rst
@@ -161,7 +161,22 @@ Ignore all other arguments, and prints the version of the libvirt library
 virsh is coming from and which options and driver are compiled in.


-
+- ``--probe-arguments``
+
+Parse all incomming commands and their arguments. Return without actually
+executing the command. This gives the caller the possibility to probe if given
+command or argument exists in this version of virsh without executing the
+command. Mandatory arguments need to be provided albeit with dummy values if
+checking existence of optional features.
+(Introduced in libvirt-12.3.0)
+
+Example::
+
+ if virsh --probe-arguments blockresize --domain dummy --path dummy --size 1 --allow-shrink 2>/dev/null; then
+    echo "supported"
+ else
+    echo "unsupported"
+ fi

 NOTES
 =====
diff --git a/tools/virsh.c b/tools/virsh.c
index fdce3220b3..57e2b9c1a9 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -646,6 +646,7 @@ virshParseArgv(vshControl *ctl, int argc, char **argv)
         { "timing", no_argument, NULL, 't' },
         { "no-pkttyagent", no_argument, NULL, 0 },
         { "version", optional_argument, NULL, 'v' },
+        { "probe-arguments", no_argument, NULL, 0 },
         { NULL, 0, NULL, 0 },
     };

@@ -746,6 +747,9 @@ virshParseArgv(vshControl *ctl, int argc, char **argv)
             if (STREQ(opt[longindex].name, "no-pkttyagent")) {
                 ctl->no_pkttyagent = true;
                 break;
+            } else if (STREQ(opt[longindex].name, "probe-arguments")) {
+                ctl->probe_arguments = true;
+                break;
             } else {
                 vshError(ctl, "%s", _("unknown option"));
                 exit(EXIT_FAILURE);
diff --git a/tools/virt-admin.c b/tools/virt-admin.c
index ac8f3202b6..ff6f3856aa 100644
--- a/tools/virt-admin.c
+++ b/tools/virt-admin.c
@@ -1292,6 +1292,7 @@ vshAdmParseArgv(vshControl *ctl, int argc, char **argv)
         { "log", required_argument, NULL, 'l' },
         { "quiet", no_argument, NULL, 'q' },
         { "version", optional_argument, NULL, 'v' },
+        { "probe-arguments", no_argument, NULL, 0 },
         { NULL, 0, NULL, 0 },
     };

@@ -1337,6 +1338,14 @@ vshAdmParseArgv(vshControl *ctl, int argc, char **argv)
         case 'V':
             vshAdmShowVersion(ctl);
             exit(EXIT_SUCCESS);
+        case 0:
+            if (STREQ(opt[longindex].name, "probe-arguments")) {
+                ctl->probe_arguments = true;
+                break;
+            } else {
+                vshError(ctl, "%s", _("unknown option"));
+                exit(EXIT_FAILURE);
+            }
         case ':':
             for (i = 0; opt[i].name != NULL; i++) {
                 if (opt[i].val == optopt)
diff --git a/tools/vsh.c b/tools/vsh.c
index 74016c0043..e85d8b5001 100644
--- a/tools/vsh.c
+++ b/tools/vsh.c
@@ -1366,6 +1366,9 @@ vshCommandRun(vshControl *ctl,
     const vshClientHooks *hooks = ctl->hooks;
     int ret = EXIT_SUCCESS;

+    if (ctl->probe_arguments)
+        return EXIT_SUCCESS;
+
     while (cmd) {
         gint64 before, after;
         bool enable_timing = ctl->timing;
diff --git a/tools/vsh.h b/tools/vsh.h
index bd2494e899..18fa7ad594 100644
--- a/tools/vsh.h
+++ b/tools/vsh.h
@@ -203,6 +203,7 @@ struct _vshControl {
     bool timing;                /* print timing info? */
     bool no_pkttyagent;         /* suppress registration of pkttyagent? */
     int debug;                  /* print debug messages? */
+    bool probe_arguments;       /* process arguments but don't run command */
     char *logfile;              /* log file name */
     int log_fd;                 /* log file descriptor */
     char *historydir;           /* readline history directory name */
-- 
2.53.0
Re: [PATCH 5/6] virsh/virt-admin: Add possibility to probe for new arguments
Posted by Pavel Hrdina via Devel 6 hours ago
On Wed, Apr 01, 2026 at 03:27:16PM +0200, Peter Krempa via Devel wrote:
> From: Peter Krempa <pkrempa@redhat.com>
> 
> Add users possibility to discover presence of arguments safely.
> 
> The new global argument '--probe-arguments' which runs the argument
> parser but doesn't run the actual function and returning success if it
> gets to the point of actually trying to runt he parser.

s/runt he/run the/

> 
> This will allow users to probe for new arguments (which were added after
> this patch:
> 
>  - virsh prior to this patch:
> 
>    $ virsh --probe-arguments blockresize cd vda 1 --extend ; echo $?
>    error: unsupported option '--probe-arguments'. See --help.
>    1
> 
>  - virsh with this patch but checking for something that doesn't yet exist:
> 
>    $ virsh --probe-arguments blockresize cd vda 1 --allow-shrink ; echo $?
>    error: command 'blockresize' doesn't support option --allow-shrink
>    1

Same here as for the API, do we want to print error in this case? I would say
this will be mainly used in scripts and it would help callers as they
would most likely discard the error message in case the script is
probing virsh if something is supported or not.

I wanted to suggest that the script can run `virsh help | grep --probe-arguments`
to figure out if it should even try using it but at the same time it can
run `virsh CMD --help | grep --some-argument` so now I'm not sure if we
even need this in virsh.

Pavel

> 
>  - virsh with this patch with the argument present:
> 
>    $ virsh --probe-arguments blockresize cd vda 1 --allow-shrink ; echo $?
>    0
> 
> Signed-off-by: Peter Krempa <pkrempa@redhat.com>
> ---
>  docs/manpages/virsh.rst | 17 ++++++++++++++++-
>  tools/virsh.c           |  4 ++++
>  tools/virt-admin.c      |  9 +++++++++
>  tools/vsh.c             |  3 +++
>  tools/vsh.h             |  1 +
>  5 files changed, 33 insertions(+), 1 deletion(-)
> 
> diff --git a/docs/manpages/virsh.rst b/docs/manpages/virsh.rst
> index 80b0ea14a8..9ede859aaf 100644
> --- a/docs/manpages/virsh.rst
> +++ b/docs/manpages/virsh.rst
> @@ -161,7 +161,22 @@ Ignore all other arguments, and prints the version of the libvirt library
>  virsh is coming from and which options and driver are compiled in.
> 
> 
> -
> +- ``--probe-arguments``
> +
> +Parse all incomming commands and their arguments. Return without actually
> +executing the command. This gives the caller the possibility to probe if given
> +command or argument exists in this version of virsh without executing the
> +command. Mandatory arguments need to be provided albeit with dummy values if
> +checking existence of optional features.
> +(Introduced in libvirt-12.3.0)
> +
> +Example::
> +
> + if virsh --probe-arguments blockresize --domain dummy --path dummy --size 1 --allow-shrink 2>/dev/null; then
> +    echo "supported"
> + else
> +    echo "unsupported"
> + fi
> 
>  NOTES
>  =====
> diff --git a/tools/virsh.c b/tools/virsh.c
> index fdce3220b3..57e2b9c1a9 100644
> --- a/tools/virsh.c
> +++ b/tools/virsh.c
> @@ -646,6 +646,7 @@ virshParseArgv(vshControl *ctl, int argc, char **argv)
>          { "timing", no_argument, NULL, 't' },
>          { "no-pkttyagent", no_argument, NULL, 0 },
>          { "version", optional_argument, NULL, 'v' },
> +        { "probe-arguments", no_argument, NULL, 0 },
>          { NULL, 0, NULL, 0 },
>      };
> 
> @@ -746,6 +747,9 @@ virshParseArgv(vshControl *ctl, int argc, char **argv)
>              if (STREQ(opt[longindex].name, "no-pkttyagent")) {
>                  ctl->no_pkttyagent = true;
>                  break;
> +            } else if (STREQ(opt[longindex].name, "probe-arguments")) {
> +                ctl->probe_arguments = true;
> +                break;
>              } else {
>                  vshError(ctl, "%s", _("unknown option"));
>                  exit(EXIT_FAILURE);
> diff --git a/tools/virt-admin.c b/tools/virt-admin.c
> index ac8f3202b6..ff6f3856aa 100644
> --- a/tools/virt-admin.c
> +++ b/tools/virt-admin.c
> @@ -1292,6 +1292,7 @@ vshAdmParseArgv(vshControl *ctl, int argc, char **argv)
>          { "log", required_argument, NULL, 'l' },
>          { "quiet", no_argument, NULL, 'q' },
>          { "version", optional_argument, NULL, 'v' },
> +        { "probe-arguments", no_argument, NULL, 0 },
>          { NULL, 0, NULL, 0 },
>      };
> 
> @@ -1337,6 +1338,14 @@ vshAdmParseArgv(vshControl *ctl, int argc, char **argv)
>          case 'V':
>              vshAdmShowVersion(ctl);
>              exit(EXIT_SUCCESS);
> +        case 0:
> +            if (STREQ(opt[longindex].name, "probe-arguments")) {
> +                ctl->probe_arguments = true;
> +                break;
> +            } else {
> +                vshError(ctl, "%s", _("unknown option"));
> +                exit(EXIT_FAILURE);
> +            }
>          case ':':
>              for (i = 0; opt[i].name != NULL; i++) {
>                  if (opt[i].val == optopt)
> diff --git a/tools/vsh.c b/tools/vsh.c
> index 74016c0043..e85d8b5001 100644
> --- a/tools/vsh.c
> +++ b/tools/vsh.c
> @@ -1366,6 +1366,9 @@ vshCommandRun(vshControl *ctl,
>      const vshClientHooks *hooks = ctl->hooks;
>      int ret = EXIT_SUCCESS;
> 
> +    if (ctl->probe_arguments)
> +        return EXIT_SUCCESS;
> +
>      while (cmd) {
>          gint64 before, after;
>          bool enable_timing = ctl->timing;
> diff --git a/tools/vsh.h b/tools/vsh.h
> index bd2494e899..18fa7ad594 100644
> --- a/tools/vsh.h
> +++ b/tools/vsh.h
> @@ -203,6 +203,7 @@ struct _vshControl {
>      bool timing;                /* print timing info? */
>      bool no_pkttyagent;         /* suppress registration of pkttyagent? */
>      int debug;                  /* print debug messages? */
> +    bool probe_arguments;       /* process arguments but don't run command */
>      char *logfile;              /* log file name */
>      int log_fd;                 /* log file descriptor */
>      char *historydir;           /* readline history directory name */
> -- 
> 2.53.0
>