git: 99f2177b0905 - stable/14 - ifconfig: Support variable-argument commands

From: Lexi Winter <ivy_at_FreeBSD.org>
Date: Sat, 23 Aug 2025 00:11:26 UTC
The branch stable/14 has been updated by ivy:

URL: https://cgit.FreeBSD.org/src/commit/?id=99f2177b0905b9567ee35fd060b0db931e87b542

commit 99f2177b0905b9567ee35fd060b0db931e87b542
Author:     Lexi Winter <ivy@FreeBSD.org>
AuthorDate: 2025-07-31 15:54:53 +0000
Commit:     Lexi Winter <ivy@FreeBSD.org>
CommitDate: 2025-08-23 00:10:15 +0000

    ifconfig: Support variable-argument commands
    
    Add a new type of command, DEF_CMD_VARG, which takes an (argc, argv)
    pair instead of a fixed number of arguments.  This allows commands
    to do their own argument parsing and accept a variable number of
    arguments.
    
    Reviewed by:            kevans
    Differential Revision:  https://reviews.freebsd.org/D51243
    
    (cherry picked from commit 7d4a177efc653bc60a496ba0adf5cb4e0560fa07)
---
 sbin/ifconfig/ifconfig.c |  7 +++++++
 sbin/ifconfig/ifconfig.h | 10 ++++++++++
 2 files changed, 17 insertions(+)

diff --git a/sbin/ifconfig/ifconfig.c b/sbin/ifconfig/ifconfig.c
index c1e3e0af83c2..9d7a40b9049a 100644
--- a/sbin/ifconfig/ifconfig.c
+++ b/sbin/ifconfig/ifconfig.c
@@ -1218,6 +1218,13 @@ top:
 			argc -= 2, argv += 2;
 		} else if (p->c_parameter == SPARAM && p->c_u.c_func3) {
 			p->c_u.c_func3(ctx, *argv, p->c_sparameter);
+		} else if (p->c_parameter == ARGVECTOR && p->c_u.c_funcv) {
+			int argsdone;
+
+			argsdone = p->c_u.c_funcv(ctx, argc - 1,
+			    (const char *const *)argv + 1);
+			argc -= argsdone;
+			argv += argsdone;
 		} else if (p->c_u.c_func)
 			p->c_u.c_func(ctx, *argv, p->c_parameter);
 		argc--, argv++;
diff --git a/sbin/ifconfig/ifconfig.h b/sbin/ifconfig/ifconfig.h
index 0ae317aca409..be333d0ae02f 100644
--- a/sbin/ifconfig/ifconfig.h
+++ b/sbin/ifconfig/ifconfig.h
@@ -66,6 +66,7 @@ typedef struct ifconfig_context if_ctx;
 typedef	void c_func(if_ctx *ctx, const char *cmd, int arg);
 typedef	void c_func2(if_ctx *ctx, const char *arg1, const char *arg2);
 typedef	void c_func3(if_ctx *ctx, const char *cmd, const char *arg);
+typedef	int  c_funcv(if_ctx *ctx, int argc, const char *const *argv);
 
 struct cmd {
 	const char *c_name;
@@ -74,11 +75,13 @@ struct cmd {
 #define	NEXTARG2	0xfffffe	/* has 2 following args */
 #define	OPTARG		0xfffffd	/* has optional following arg */
 #define	SPARAM		0xfffffc	/* parameter is string c_sparameter */
+#define	ARGVECTOR	0xfffffb	/* takes argument vector */
 	const char *c_sparameter;
 	union {
 		c_func	*c_func;
 		c_func2	*c_func2;
 		c_func3	*c_func3;
+		c_funcv	*c_funcv;
 	} c_u;
 	int	c_iscloneop;
 	struct cmd *c_next;
@@ -120,6 +123,13 @@ void	callback_register(callback_func *, void *);
     .c_iscloneop = 0,				\
     .c_next = NULL,				\
 }
+#define	DEF_CMD_VARG(name, func) {		\
+    .c_name = (name),				\
+    .c_parameter = ARGVECTOR,			\
+    .c_u = { .c_funcv = (func) },		\
+    .c_iscloneop = 0,				\
+    .c_next = NULL,				\
+}
 #define	DEF_CMD_SARG(name, sparam, func) {	\
     .c_name = (name),				\
     .c_parameter = SPARAM,			\