]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
test-ndisc-send: convert to the new option parser
authorZbigniew Jędrzejewski-Szmek <zbyszek@amutable.com>
Thu, 16 Apr 2026 08:27:43 +0000 (10:27 +0200)
committerZbigniew Jędrzejewski-Szmek <zbyszek@amutable.com>
Wed, 22 Apr 2026 12:19:01 +0000 (14:19 +0200)
Co-developed-by: Claude Opus 4.6 <noreply@anthropic.com>
src/libsystemd-network/test-ndisc-send.c

index 247cc0ec16cfb31c86db416026945d4863e4b592..e0bbcfe6c243aab9161be816108886e914e4c8b5 100644 (file)
@@ -1,6 +1,5 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 
-#include <getopt.h>
 #include <netinet/icmp6.h>
 
 #include "sd-ndisc-protocol.h"
@@ -17,6 +16,7 @@
 #include "ndisc-option.h"
 #include "netlink-util.h"
 #include "network-common.h"
+#include "options.h"
 #include "parse-util.h"
 #include "set.h"
 #include "string-util.h"
@@ -72,197 +72,158 @@ static int parse_preference(const char *str) {
 }
 
 static int parse_argv(int argc, char *argv[]) {
-        enum {
-                ARG_VERSION = 0x100,
-                ARG_RA_HOP_LIMIT,
-                ARG_RA_MANAGED,
-                ARG_RA_OTHER,
-                ARG_RA_HOME_AGENT,
-                ARG_RA_PREFERENCE,
-                ARG_RA_LIFETIME,
-                ARG_RA_REACHABLE,
-                ARG_RA_RETRANSMIT,
-                ARG_NA_ROUTER,
-                ARG_NA_SOLICITED,
-                ARG_NA_OVERRIDE,
-                ARG_TARGET_ADDRESS,
-                ARG_REDIRECT_DESTINATION,
-                ARG_OPTION_SOURCE_LL,
-                ARG_OPTION_TARGET_LL,
-                ARG_OPTION_REDIRECTED_HEADER,
-                ARG_OPTION_MTU,
-        };
-
-        static const struct option options[] = {
-                { "version",              no_argument,       NULL, ARG_VERSION                  },
-                { "interface",            required_argument, NULL, 'i'                          },
-                { "type",                 required_argument, NULL, 't'                          },
-                { "dest",                 required_argument, NULL, 'd'                          },
-                /* For Router Advertisement */
-                { "hop-limit",            required_argument, NULL, ARG_RA_HOP_LIMIT             },
-                { "managed",              required_argument, NULL, ARG_RA_MANAGED               },
-                { "other",                required_argument, NULL, ARG_RA_OTHER                 },
-                { "home-agent",           required_argument, NULL, ARG_RA_HOME_AGENT            },
-                { "preference",           required_argument, NULL, ARG_RA_PREFERENCE            },
-                { "lifetime",             required_argument, NULL, ARG_RA_LIFETIME              },
-                { "reachable-time",       required_argument, NULL, ARG_RA_REACHABLE             },
-                { "retransmit-timer",     required_argument, NULL, ARG_RA_RETRANSMIT            },
-                /* For Neighbor Advertisement */
-                { "is-router",            required_argument, NULL, ARG_NA_ROUTER                },
-                { "is-solicited",         required_argument, NULL, ARG_NA_SOLICITED             },
-                { "is-override",          required_argument, NULL, ARG_NA_OVERRIDE              },
-                /* For Neighbor Solicit, Neighbor Advertisement, and Redirect */
-                { "target-address",       required_argument, NULL, ARG_TARGET_ADDRESS           },
-                /* For Redirect */
-                { "redirect-destination", required_argument, NULL, ARG_REDIRECT_DESTINATION     },
-                /* Options */
-                { "source-ll-address",    required_argument, NULL, ARG_OPTION_SOURCE_LL         },
-                { "target-ll-address",    required_argument, NULL, ARG_OPTION_TARGET_LL         },
-                { "redirected-header",    required_argument, NULL, ARG_OPTION_REDIRECTED_HEADER },
-                { "mtu",                  required_argument, NULL, ARG_OPTION_MTU               },
-                {}
-        };
-
         _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
-        int c, r;
+        int r;
 
         assert(argc >= 0);
         assert(argv);
 
-        while ((c = getopt_long(argc, argv, "i:t:d:", options, NULL)) >= 0) {
+        OptionParser state = { argc, argv };
+        const char *arg;
 
+        FOREACH_OPTION(&state, c, &arg, /* on_error= */ return c)
                 switch (c) {
 
-                case ARG_VERSION:
+                OPTION_COMMON_VERSION:
                         return version();
 
-                case 'i':
-                        r = rtnl_resolve_interface_or_warn(&rtnl, optarg);
+                OPTION('i', "interface", "INTERFACE", "Network interface"):
+                        r = rtnl_resolve_interface_or_warn(&rtnl, arg);
                         if (r < 0)
                                 return r;
                         arg_ifindex = r;
                         break;
 
-                case 't':
-                        r = parse_icmp6_type(optarg);
+                OPTION('t', "type", "TYPE", "ICMPv6 message type"):
+                        r = parse_icmp6_type(arg);
                         if (r < 0)
                                 return log_error_errno(r, "Failed to parse message type: %m");
                         arg_icmp6_type = r;
                         break;
 
-                case 'd':
-                        r = in_addr_from_string(AF_INET6, optarg, &arg_dest);
+                OPTION('d', "dest", "ADDRESS", "Destination address"):
+                        r = in_addr_from_string(AF_INET6, arg, &arg_dest);
                         if (r < 0)
                                 return log_error_errno(r, "Failed to parse destination address: %m");
                         if (!in6_addr_is_link_local(&arg_dest.in6))
                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                                       "The destination address %s is not a link-local address.", optarg);
+                                                       "The destination address %s is not a link-local address.", arg);
                         break;
 
-                case ARG_RA_HOP_LIMIT:
-                        r = safe_atou8(optarg, &arg_hop_limit);
+                OPTION_GROUP("Router Advertisement"): {}
+
+                OPTION_LONG("hop-limit", "LIMIT", "Hop limit"):
+                        r = safe_atou8(arg, &arg_hop_limit);
                         if (r < 0)
                                 return log_error_errno(r, "Failed to parse hop limit: %m");
                         break;
 
-                case ARG_RA_MANAGED:
-                        r = parse_boolean(optarg);
+                OPTION_LONG("managed", "BOOL", "Managed flag"):
+                        r = parse_boolean(arg);
                         if (r < 0)
                                 return log_error_errno(r, "Failed to parse managed flag: %m");
                         SET_FLAG(arg_ra_flags, ND_RA_FLAG_MANAGED, r);
                         break;
 
-                case ARG_RA_OTHER:
-                        r = parse_boolean(optarg);
+                OPTION_LONG("other", "BOOL", "Other flag"):
+                        r = parse_boolean(arg);
                         if (r < 0)
                                 return log_error_errno(r, "Failed to parse other flag: %m");
                         SET_FLAG(arg_ra_flags, ND_RA_FLAG_OTHER, r);
                         break;
 
-                case ARG_RA_HOME_AGENT:
-                        r = parse_boolean(optarg);
+                OPTION_LONG("home-agent", "BOOL", "Home-agent flag"):
+                        r = parse_boolean(arg);
                         if (r < 0)
                                 return log_error_errno(r, "Failed to parse home-agent flag: %m");
                         SET_FLAG(arg_ra_flags, ND_RA_FLAG_HOME_AGENT, r);
                         break;
 
-                case ARG_RA_PREFERENCE:
-                        r = parse_preference(optarg);
+                OPTION_LONG("preference", "PREF", "Preference"):
+                        r = parse_preference(arg);
                         if (r < 0)
                                 return log_error_errno(r, "Failed to parse preference: %m");
                         arg_preference = r;
                         break;
 
-                case ARG_RA_LIFETIME:
-                        r = parse_sec(optarg, &arg_lifetime);
+                OPTION_LONG("lifetime", "SECS", "Lifetime"):
+                        r = parse_sec(arg, &arg_lifetime);
                         if (r < 0)
                                 return log_error_errno(r, "Failed to parse lifetime: %m");
                         break;
 
-                case ARG_RA_REACHABLE:
-                        r = parse_sec(optarg, &arg_reachable);
+                OPTION_LONG("reachable-time", "SECS", "Reachable time"):
+                        r = parse_sec(arg, &arg_reachable);
                         if (r < 0)
                                 return log_error_errno(r, "Failed to parse reachable time: %m");
                         break;
 
-                case ARG_RA_RETRANSMIT:
-                        r = parse_sec(optarg, &arg_retransmit);
+                OPTION_LONG("retransmit-timer", "SECS", "Retransmit timer"):
+                        r = parse_sec(arg, &arg_retransmit);
                         if (r < 0)
                                 return log_error_errno(r, "Failed to parse retransmit timer: %m");
                         break;
 
-                case ARG_NA_ROUTER:
-                        r = parse_boolean(optarg);
+                OPTION_GROUP("Neighbor Advertisement"): {}
+
+                OPTION_LONG("is-router", "BOOL", "Router flag"):
+                        r = parse_boolean(arg);
                         if (r < 0)
                                 return log_error_errno(r, "Failed to parse is-router flag: %m");
                         SET_FLAG(arg_na_flags, ND_NA_FLAG_ROUTER, r);
                         break;
 
-                case ARG_NA_SOLICITED:
-                        r = parse_boolean(optarg);
+                OPTION_LONG("is-solicited", "BOOL", "Solicited flag"):
+                        r = parse_boolean(arg);
                         if (r < 0)
                                 return log_error_errno(r, "Failed to parse is-solicited flag: %m");
                         SET_FLAG(arg_na_flags, ND_NA_FLAG_SOLICITED, r);
                         break;
 
-                case ARG_NA_OVERRIDE:
-                        r = parse_boolean(optarg);
+                OPTION_LONG("is-override", "BOOL", "Override flag"):
+                        r = parse_boolean(arg);
                         if (r < 0)
                                 return log_error_errno(r, "Failed to parse is-override flag: %m");
                         SET_FLAG(arg_na_flags, ND_NA_FLAG_OVERRIDE, r);
                         break;
 
-                case ARG_TARGET_ADDRESS:
-                        r = in_addr_from_string(AF_INET6, optarg, &arg_target_address);
+                OPTION_GROUP("Neighbor Solicit/Advertisement and Redirect"): {}
+
+                OPTION_LONG("target-address", "ADDRESS", "Target address"):
+                        r = in_addr_from_string(AF_INET6, arg, &arg_target_address);
                         if (r < 0)
                                 return log_error_errno(r, "Failed to parse target address: %m");
                         break;
 
-                case ARG_REDIRECT_DESTINATION:
-                        r = in_addr_from_string(AF_INET6, optarg, &arg_redirect_destination);
+                OPTION_GROUP("Redirect"): {}
+
+                OPTION_LONG("redirect-destination", "ADDRESS", "Redirect destination address"):
+                        r = in_addr_from_string(AF_INET6, arg, &arg_redirect_destination);
                         if (r < 0)
                                 return log_error_errno(r, "Failed to parse destination address: %m");
                         break;
 
-                case ARG_OPTION_SOURCE_LL:
-                        r = parse_boolean(optarg);
+                OPTION_GROUP("NDisc Options"): {}
+
+                OPTION_LONG("source-ll-address", "BOOL", "Include source link-layer address"):
+                        r = parse_boolean(arg);
                         if (r < 0)
                                 return log_error_errno(r, "Failed to parse source LL address option: %m");
                         arg_set_source_mac = r;
                         break;
 
-                case ARG_OPTION_TARGET_LL:
-                        r = parse_ether_addr(optarg, &arg_target_mac);
+                OPTION_LONG("target-ll-address", "ADDRESS", "Target link-layer address"):
+                        r = parse_ether_addr(arg, &arg_target_mac);
                         if (r < 0)
                                 return log_error_errno(r, "Failed to parse target LL address option: %m");
                         arg_set_target_mac = true;
                         break;
 
-                case ARG_OPTION_REDIRECTED_HEADER: {
+                OPTION_LONG("redirected-header", "BASE64", "Redirected header (base64)"): {
                         _cleanup_free_ void *p = NULL;
                         size_t len;
 
-                        r = unbase64mem(optarg, &p, &len);
+                        r = unbase64mem(arg, &p, &len);
                         if (r < 0)
                                 return log_error_errno(r, "Failed to parse redirected header: %m");
 
@@ -272,20 +233,14 @@ static int parse_argv(int argc, char *argv[]) {
                         arg_redirected_header = TAKE_PTR(p);
                         break;
                 }
-                case ARG_OPTION_MTU:
-                        r = safe_atou32(optarg, &arg_mtu);
+
+                OPTION_LONG("mtu", "MTU", "MTU"):
+                        r = safe_atou32(arg, &arg_mtu);
                         if (r < 0)
                                 return log_error_errno(r, "Failed to parse MTU: %m");
                         arg_set_mtu = true;
                         break;
-
-                case '?':
-                        return -EINVAL;
-
-                default:
-                        assert_not_reached();
                 }
-        }
 
         if (arg_ifindex <= 0)
                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "--interface/-i option is mandatory.");