[PATCH v2] iproute2: return correct status from help commands across all utilities
From: Rose Wright <hidden>
Date: 2026-06-23 01:17:37
Subsystem:
the rest · Maintainer:
Linus Torvalds
Currently, help commands ("help", "-h", "-help") in utilities
always return error codes.
This is a bug which breaks piping, grep operations, and scripts
that rely on standard exit codes. The fix parameterizes the usage/help
functions in these utilities to dynamically write to stdout when help
is explicitly requested.
This patch standardizes the behavior of help commands and usage errors
across all utilities: ip, bridge, tc, devlink, dcb, rdma, vdpa, dpll,
genl, tipc, and netshaper.
Netlink socket initialization is bypassed when a help command is used to prevent commands from failing in isolated
test/container environments.
Test added to confirm these changes: testsuite/tests/ip/help.t
Signed-off-by: Rose Wright <redacted>
---
bridge/bridge.c | 22 +++---
dcb/dcb.c | 38 +++++++---
devlink/devlink.c | 42 ++++++++---
dpll/dpll.c | 31 +++++---
genl/genl.c | 14 ++--
netshaper/netshaper.c | 52 ++++++++++---
rdma/rdma.c | 39 +++++++---
tc/tc.c | 14 ++--
testsuite/tests/ip/help.t | 151 ++++++++++++++++++++++++++++++++++++++
tipc/bearer.c | 142 +++++++++++++++++++----------------
tipc/bearer.h | 8 +-
tipc/cmdl.c | 9 ++-
tipc/cmdl.h | 6 +-
tipc/link.c | 108 ++++++++++++++-------------
tipc/link.h | 4 +-
tipc/media.c | 24 +++---
tipc/media.h | 4 +-
tipc/nametable.c | 8 +-
tipc/nametable.h | 4 +-
tipc/node.c | 54 ++++++++------
tipc/node.h | 4 +-
tipc/peer.c | 26 +++----
tipc/peer.h | 4 +-
tipc/socket.c | 8 +-
tipc/socket.h | 4 +-
tipc/tipc.c | 26 ++++---
vdpa/vdpa.c | 40 +++++++---
27 files changed, 598 insertions(+), 288 deletions(-)
create mode 100755 testsuite/tests/ip/help.t
diff --git a/bridge/bridge.c b/bridge/bridge.c
index d993ba19..7bc08b82 100644
--- a/bridge/bridge.c
+++ b/bridge/bridge.c@@ -29,23 +29,25 @@ int timestamp; static const char *batch_file; int force; -static void usage(void) __attribute__((noreturn)); +static void usage(int status) __attribute__((noreturn)); -static void usage(void) +static void usage(int status) { - fprintf(stderr, + FILE *out = status == 0 ? stdout : stderr; + + fprintf(out, "Usage: bridge [ OPTIONS ] OBJECT { COMMAND | help }\n" " bridge [ -force ] -batch filename\n" "where OBJECT := { link | fdb | mdb | mst | vlan | vni | monitor }\n" " OPTIONS := { -V[ersion] | -s[tatistics] | -d[etails] |\n" " -o[neline] | -t[imestamp] | -n[etns] name |\n" " -com[pressvlans] -c[olor] -p[retty] -j[son] }\n"); - exit(-1); + exit(status); } static int do_help(int argc, char **argv) { - usage(); + usage(0); }
@@ -118,7 +120,7 @@ main(int argc, char **argv) opt++; if (matches(opt, "-help") == 0) { - usage(); + usage(0); } else if (matches(opt, "-Version") == 0) { printf("bridge utility, %s\n", version); exit(0);
@@ -135,13 +137,13 @@ main(int argc, char **argv) argc--; argv++; if (argc <= 1) - usage(); + usage(-1); if (strcmp(argv[1], "inet") == 0) preferred_family = AF_INET; else if (strcmp(argv[1], "inet6") == 0) preferred_family = AF_INET6; else if (strcmp(argv[1], "help") == 0) - usage(); + usage(0); else invarg("invalid protocol family", argv[1]); } else if (strcmp(opt, "-4") == 0) {
@@ -165,7 +167,7 @@ main(int argc, char **argv) argc--; argv++; if (argc <= 1) - usage(); + usage(-1); batch_file = argv[1]; } else { fprintf(stderr,
@@ -192,5 +194,5 @@ main(int argc, char **argv) return do_cmd(argv[1], argc-1, argv+1); rtnl_close(&rth); - usage(); + usage(-1); }
diff --git a/dcb/dcb.c b/dcb/dcb.c
index fe0a0f04..131005fe 100644
--- a/dcb/dcb.c
+++ b/dcb/dcb.c@@ -465,9 +465,9 @@ int dcb_cmd_parse_dev(struct dcb *dcb, int argc, char **argv, } } -static void dcb_help(void) +static void dcb_help(FILE *out) { - fprintf(stderr, + fprintf(out, "Usage: dcb [ OPTIONS ] OBJECT { COMMAND | help }\n" " dcb [ -f | --force ] { -b | --batch } filename [ -n | --netns ] netnsname\n" "where OBJECT := { app | apptrust | buffer | dcbx | ets | maxrate | pfc | rewr }\n"
@@ -478,8 +478,11 @@ static void dcb_help(void) static int dcb_cmd(struct dcb *dcb, int argc, char **argv) { - if (!argc || matches(*argv, "help") == 0) { - dcb_help(); + if (!argc) { + dcb_help(stderr); + return -EINVAL; + } else if (matches(*argv, "help") == 0) { + dcb_help(stdout); return 0; } else if (matches(*argv, "app") == 0) { return dcb_cmd_app(dcb, argc - 1, argv + 1);
@@ -533,6 +536,7 @@ int main(int argc, char **argv) const char *batch_file = NULL; bool force = false; struct dcb *dcb; + bool need_nl = true; int opt; int err; int ret;
@@ -579,12 +583,12 @@ int main(int argc, char **argv) dcb->use_iec = true; break; case 'h': - dcb_help(); + dcb_help(stdout); ret = EXIT_SUCCESS; goto dcb_free; default: fprintf(stderr, "Unknown option.\n"); - dcb_help(); + dcb_help(stderr); ret = EXIT_FAILURE; goto dcb_free; }
@@ -593,10 +597,21 @@ int main(int argc, char **argv) argc -= optind; argv += optind; - err = dcb_init(dcb); - if (err) { - ret = EXIT_FAILURE; - goto dcb_free; + if (argc > 0 && (strcmp(argv[0], "help") == 0 || + strcmp(argv[0], "-h") == 0 || + strcmp(argv[0], "--help") == 0)) + need_nl = false; + if (argc > 1 && (strcmp(argv[1], "help") == 0 || + strcmp(argv[1], "-h") == 0 || + strcmp(argv[1], "--help") == 0)) + need_nl = false; + + if (need_nl) { + err = dcb_init(dcb); + if (err) { + ret = EXIT_FAILURE; + goto dcb_free; + } } if (batch_file)
@@ -612,7 +627,8 @@ int main(int argc, char **argv) ret = EXIT_SUCCESS; dcb_fini: - dcb_fini(dcb); + if (need_nl) + dcb_fini(dcb); dcb_free: dcb_free(dcb);
diff --git a/devlink/devlink.c b/devlink/devlink.c
index b4deba30..ad64ba1e 100644
--- a/devlink/devlink.c
+++ b/devlink/devlink.c@@ -10332,9 +10332,9 @@ static int cmd_trap(struct dl *dl) return -ENOENT; } -static void help(void) +static void help(FILE *out) { - pr_err("Usage: devlink [ OPTIONS ] OBJECT { COMMAND | help }\n" + fprintf(out, "Usage: devlink [ OPTIONS ] OBJECT { COMMAND | help }\n" " devlink [ -f[orce] ] -b[atch] filename -N[etns] netnsname\n" "where OBJECT := { dev | port | lc | sb | monitor | dpipe | resource | region | health | trap }\n" " OPTIONS := { -V[ersion] | -n[o-nice-names] | -j[son] | -p[retty] | -v[erbose] -s[tatistics] -[he]x }\n");
@@ -10345,9 +10345,12 @@ static int dl_cmd(struct dl *dl, int argc, char **argv) dl->argc = argc; dl->argv = argv; - if (dl_argv_match(dl, "help") || dl_no_arg(dl)) { - help(); + if (dl_argv_match(dl, "help")) { + help(stdout); return 0; + } else if (dl_no_arg(dl)) { + help(stderr); + return -EINVAL; } else if (dl_argv_match(dl, "dev")) { dl_arg_inc(dl); return cmd_dev(dl);
@@ -10454,6 +10457,7 @@ int main(int argc, char **argv) const char *batch_file = NULL; bool force = false; struct dl *dl; + bool need_nl = true; int opt; int err; int ret;
@@ -10464,7 +10468,7 @@ int main(int argc, char **argv) return EXIT_FAILURE; } - while ((opt = getopt_long(argc, argv, "Vfb:njpvsN:ix", + while ((opt = getopt_long(argc, argv, "Vfb:njpvsN:ixh", long_options, NULL)) >= 0) { switch (opt) {
@@ -10505,9 +10509,13 @@ int main(int argc, char **argv) case 'x': dl->hex = true; break; + case 'h': + help(stdout); + ret = EXIT_SUCCESS; + goto dl_free; default: pr_err("Unknown option.\n"); - help(); + help(stderr); ret = EXIT_FAILURE; goto dl_free; }
@@ -10516,10 +10524,21 @@ int main(int argc, char **argv) argc -= optind; argv += optind; - err = dl_init(dl); - if (err) { - ret = EXIT_FAILURE; - goto dl_free; + if (argc > 0 && (strcmp(argv[0], "help") == 0 || + strcmp(argv[0], "-h") == 0 || + strcmp(argv[0], "--help") == 0)) + need_nl = false; + if (argc > 1 && (strcmp(argv[1], "help") == 0 || + strcmp(argv[1], "-h") == 0 || + strcmp(argv[1], "--help") == 0)) + need_nl = false; + + if (need_nl) { + err = dl_init(dl); + if (err) { + ret = EXIT_FAILURE; + goto dl_free; + } } if (batch_file)
@@ -10535,7 +10554,8 @@ int main(int argc, char **argv) ret = EXIT_SUCCESS; dl_fini: - dl_fini(dl); + if (need_nl) + dl_fini(dl); dl_free: dl_free(dl);
diff --git a/dpll/dpll.c b/dpll/dpll.c
index 60404e13..e0afb4fe 100644
--- a/dpll/dpll.c
+++ b/dpll/dpll.c@@ -575,9 +575,9 @@ static void dpll_pr_freq_range(__u64 freq_min, __u64 freq_max) close_json_object(); } -static void help(void) +static void help(FILE *out) { - pr_err("Usage: dpll [ OPTIONS ] OBJECT { COMMAND | help }\n" + fprintf(out, "Usage: dpll [ OPTIONS ] OBJECT { COMMAND | help }\n" "where OBJECT := { device | pin | monitor }\n" " OPTIONS := { -V | --Version | -j | --json | -p | --pretty |\n" " -t | --timestamp | --tshort }\n");
@@ -592,9 +592,12 @@ static int dpll_cmd(struct dpll *dpll, int argc, char **argv) dpll->argc = argc; dpll->argv = argv; - if (dpll_argv_match(dpll, "help") || dpll_no_arg(dpll)) { - help(); + if (dpll_argv_match(dpll, "help")) { + help(stdout); return 0; + } else if (dpll_no_arg(dpll)) { + help(stderr); + return -EINVAL; } else if (dpll_argv_match_inc(dpll, "device")) { return cmd_device(dpll); } else if (dpll_argv_match_inc(dpll, "pin")) {
@@ -646,10 +649,12 @@ int main(int argc, char **argv) { "pretty", no_argument, NULL, 'p' }, { "timestamp", no_argument, NULL, 't' }, { "tshort", no_argument, NULL, OPT_TSHORT }, + { "help", no_argument, NULL, 'h' }, { NULL, 0, NULL, 0 } }; - const char *opt_short = "Vjpt"; + const char *opt_short = "Vjpth"; struct dpll *dpll; + bool need_nl = true; int err, opt, ret; dpll = dpll_alloc();
@@ -678,9 +683,13 @@ int main(int argc, char **argv) timestamp = 1; timestamp_short = 1; break; + case 'h': + help(stdout); + ret = EXIT_SUCCESS; + goto dpll_free; default: pr_err("Unknown option.\n"); - help(); + help(stderr); ret = EXIT_FAILURE; goto dpll_free; }
@@ -700,11 +709,13 @@ int main(int argc, char **argv) } /* Skip netlink init for help commands */ - bool need_nl = true; - - if (argc > 0 && strcmp(argv[0], "help") == 0) + if (argc > 0 && (strcmp(argv[0], "help") == 0 || + strcmp(argv[0], "-h") == 0 || + strcmp(argv[0], "--help") == 0)) need_nl = false; - if (argc > 1 && strcmp(argv[1], "help") == 0) + if (argc > 1 && (strcmp(argv[1], "help") == 0 || + strcmp(argv[1], "-h") == 0 || + strcmp(argv[1], "--help") == 0)) need_nl = false; if (need_nl) {
diff --git a/genl/genl.c b/genl/genl.c
index b497a3ad..2c304a57 100644
--- a/genl/genl.c
+++ b/genl/genl.c@@ -90,16 +90,18 @@ noexist: return f; } -static void usage(void) __attribute__((noreturn)); +static void usage(int status) __attribute__((noreturn)); -static void usage(void) +static void usage(int status) { - fprintf(stderr, + FILE *out = status == 0 ? stdout : stderr; + + fprintf(out, "Usage: genl [ OPTIONS ] OBJECT [help] }\n" "where OBJECT := { ctrl etc }\n" " OPTIONS := { -V[ersion] | -s[tatistics] | -d[etails] | -r[aw] |\n" " -j[son] | -p[retty] }\n"); - exit(-1); + exit(status); } int main(int argc, char **argv)
@@ -122,7 +124,7 @@ int main(int argc, char **argv) } else if (matches(argv[1], "-pretty") == 0) { ++pretty; } else if (matches(argv[1], "-help") == 0) { - usage(); + usage(0); } else { fprintf(stderr, "Option \"%s\" is unknown, try \"genl -help\".\n",
@@ -146,5 +148,5 @@ int main(int argc, char **argv) return ret; } - usage(); + usage(-1); }
diff --git a/netshaper/netshaper.c b/netshaper/netshaper.c
index 3b47d43d..f9aeac9b 100644
--- a/netshaper/netshaper.c
+++ b/netshaper/netshaper.c@@ -26,9 +26,11 @@ static struct rtnl_handle gen_rth = { .fd = -1 }; static int genl_family = -1; -static void usage(void) +static void usage(int status) { - fprintf(stderr, + FILE *out = status == 0 ? stdout : stderr; + + fprintf(out, "Usage: netshaper [ OPTIONS ] { COMMAND | help }\n" "OPTIONS := { -V[ersion] | -c[olor] | -help }\n" "COMMAND := { set | get | delete | group } dev DEVNAME\n"
@@ -216,6 +218,13 @@ static void print_netshaper_attrs(struct nlmsghdr *answer) static int do_cmd(int argc, char **argv, int cmd) { + if (argc > 0 && (strcmp(*argv, "help") == 0 || + strcmp(*argv, "-h") == 0 || + strcmp(*argv, "--help") == 0)) { + usage(0); + exit(0); + } + GENL_REQUEST(req, 1024, genl_family, 0, NET_SHAPER_FAMILY_VERSION, cmd, NLM_F_REQUEST | NLM_F_ACK);
@@ -243,7 +252,7 @@ static int do_cmd(int argc, char **argv, int cmd) if (strcmp(*argv, "scope") != 0) { fprintf(stderr, "What is \"%s\"\n", *argv); - usage(); + usage(-1); return -1; } NEXT_ARG();
@@ -270,7 +279,7 @@ static int do_cmd(int argc, char **argv, int cmd) NEXT_ARG(); if (strcmp(*argv, "id") != 0) { fprintf(stderr, "What is \"%s\"\n", *argv); - usage(); + usage(-1); return -1; } NEXT_ARG();
@@ -282,7 +291,7 @@ static int do_cmd(int argc, char **argv, int cmd) } } else { fprintf(stderr, "What is \"%s\"\n", *argv); - usage(); + usage(-1); return -1; } argc--;
@@ -363,7 +372,7 @@ static int parse_scope_id(const char *what, int *argcp, char ***argvp, int *scop NEXT_ARG(); if (strcmp(*argv, "id") != 0) { fprintf(stderr, "What is \"%s\"\n", *argv); - usage(); + usage(-1); return -1; } NEXT_ARG();
@@ -476,6 +485,13 @@ static int parse_leaves(int *argcp, char ***argvp, static int do_group(int argc, char **argv) { + if (argc > 0 && (strcmp(*argv, "help") == 0 || + strcmp(*argv, "-h") == 0 || + strcmp(*argv, "--help") == 0)) { + usage(0); + exit(0); + } + GENL_REQUEST(req, 4096, genl_family, 0, NET_SHAPER_FAMILY_VERSION, NET_SHAPER_CMD_GROUP, NLM_F_REQUEST | NLM_F_ACK);
@@ -517,7 +533,7 @@ static int do_group(int argc, char **argv) continue; } else { fprintf(stderr, "What is \"%s\"\n", *argv); - usage(); + usage(-1); goto free_leaves; } argc--;
@@ -599,6 +615,7 @@ free_leaves: int main(int argc, char **argv) { int color = default_color_opt(); + bool need_nl = true; while (argc > 1) { const char *opt = argv[1];
@@ -609,7 +626,7 @@ int main(int argc, char **argv) opt++; if (strcmp(opt, "-help") == 0) { - usage(); + usage(0); exit(0); } else if (strcmp(opt, "-Version") == 0 || strcmp(opt, "-V") == 0) {
@@ -627,8 +644,19 @@ int main(int argc, char **argv) check_enable_color(color, 0); - if (genl_init_handle(&gen_rth, NET_SHAPER_FAMILY_NAME, &genl_family)) - exit(1); + if (argc > 1 && (strcmp(argv[1], "help") == 0 || + strcmp(argv[1], "-h") == 0 || + strcmp(argv[1], "--help") == 0)) + need_nl = false; + if (argc > 2 && (strcmp(argv[2], "help") == 0 || + strcmp(argv[2], "-h") == 0 || + strcmp(argv[2], "--help") == 0)) + need_nl = false; + + if (need_nl) { + if (genl_init_handle(&gen_rth, NET_SHAPER_FAMILY_NAME, &genl_family)) + exit(1); + } if (argc > 1) { argc--;
@@ -643,7 +671,7 @@ int main(int argc, char **argv) if (strcmp(*argv, "group") == 0) return do_group(argc - 1, argv + 1); if (strcmp(*argv, "help") == 0) { - usage(); + usage(0); return 0; } fprintf(stderr,
@@ -651,6 +679,6 @@ int main(int argc, char **argv) *argv); exit(-1); } - usage(); + usage(-1); exit(-1); }
diff --git a/rdma/rdma.c b/rdma/rdma.c
index 253ac58b..3bdb76f0 100644
--- a/rdma/rdma.c
+++ b/rdma/rdma.c@@ -11,9 +11,9 @@ /* Global utils flags */ int json; -static void help(char *name) +static void help(FILE *out, char *name) { - pr_out("Usage: %s [ OPTIONS ] OBJECT { COMMAND | help }\n" + fprintf(out, "Usage: %s [ OPTIONS ] OBJECT { COMMAND | help }\n" " %s [ -f[orce] ] -b[atch] filename\n" "where OBJECT := { dev | link | resource | monitor | system | statistic | help }\n" " OPTIONS := { -V[ersion] | -d[etails] | -j[son] | -p[retty] | -r[aw]}\n", name, name);
@@ -21,14 +21,20 @@ static void help(char *name) static int cmd_help(struct rd *rd) { - help(rd->filename); + help(stdout, rd->filename); return 0; } +static int cmd_no_arg(struct rd *rd) +{ + help(stderr, rd->filename); + return -EINVAL; +} + static int rd_cmd(struct rd *rd, int argc, char **argv) { const struct rd_cmd cmds[] = { - { NULL, cmd_help }, + { NULL, cmd_no_arg }, { "help", cmd_help }, { "dev", cmd_dev }, { "link", cmd_link },
@@ -104,6 +110,7 @@ int main(int argc, char **argv) bool show_raw = false; bool force = false; bool oneline = false; + bool need_nl = true; struct rd rd = {}; char *filename; int opt;
@@ -142,14 +149,14 @@ int main(int argc, char **argv) batch_file = optarg; break; case 'h': - help(filename); + help(stdout, filename); return EXIT_SUCCESS; case ':': pr_err("-%c option requires an argument\n", optopt); return EXIT_FAILURE; default: pr_err("Unknown option.\n"); - help(filename); + help(stderr, filename); return EXIT_FAILURE; } }
@@ -163,9 +170,20 @@ int main(int argc, char **argv) rd.show_driver_details = show_driver_details; rd.show_raw = show_raw; - err = rd_init(&rd, filename); - if (err) - goto out; + if (argc > 0 && (strcmp(argv[0], "help") == 0 || + strcmp(argv[0], "-h") == 0 || + strcmp(argv[0], "--help") == 0)) + need_nl = false; + if (argc > 1 && (strcmp(argv[1], "help") == 0 || + strcmp(argv[1], "-h") == 0 || + strcmp(argv[1], "--help") == 0)) + need_nl = false; + + if (need_nl) { + err = rd_init(&rd, filename); + if (err) + goto out; + } if (batch_file) err = rd_batch(&rd, batch_file, force);
@@ -173,6 +191,7 @@ int main(int argc, char **argv) err = rd_cmd(&rd, argc, argv); out: /* Always cleanup */ - rd_cleanup(&rd); + if (need_nl) + rd_cleanup(&rd); return err ? EXIT_FAILURE : EXIT_SUCCESS; }
diff --git a/tc/tc.c b/tc/tc.c
index 7d69e4d5..057541d2 100644
--- a/tc/tc.c
+++ b/tc/tc.c@@ -186,9 +186,11 @@ noexist: return q; } -static void usage(void) +static void usage(int status) { - fprintf(stderr, + FILE *out = status == 0 ? stdout : stderr; + + fprintf(out, "Usage: tc [ OPTIONS ] OBJECT { COMMAND | help }\n" " tc [-force] -batch filename\n" "where OBJECT := { qdisc | class | filter | chain |\n"
@@ -217,7 +219,7 @@ static int do_cmd(int argc, char **argv) if (matches(*argv, "exec") == 0) return do_exec(argc-1, argv+1); if (matches(*argv, "help") == 0) { - usage(); + usage(0); return 0; }
@@ -282,7 +284,7 @@ int main(int argc, char **argv) } else if (matches(argv[1], "-iec") == 0) { ++use_iec; } else if (matches(argv[1], "-help") == 0) { - usage(); + usage(0); return 0; } else if (matches(argv[1], "-force") == 0) { ++force;
@@ -335,8 +337,8 @@ int main(int argc, char **argv) return batch(batch_file); if (argc <= 1) { - usage(); - return 0; + usage(-1); + return -1; } tc_core_init();
diff --git a/testsuite/tests/ip/help.t b/testsuite/tests/ip/help.t
new file mode 100755
index 00000000..141abdd6
--- /dev/null
+++ b/testsuite/tests/ip/help.t@@ -0,0 +1,151 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 + +. lib/generic.sh + +ts_log "[Testing help exit codes and output streams]" + +if [ -z "$SNAME" ]; then + SNAME="iproute2/iproute2-this" +fi + +# Define binary paths using env vars if available, else fallback to SNAME subpaths +IP="${IP:-$SNAME/ip/ip}" +BRIDGE="${BRIDGE:-$SNAME/bridge/bridge}" +TC="${TC:-$SNAME/tc/tc}" +DEVLINK="${DEVLINK:-$SNAME/devlink/devlink}" +DCB="${DCB:-$SNAME/dcb/dcb}" +RDMA="${RDMA:-$SNAME/rdma/rdma}" +VDPA="${VDPA:-$SNAME/vdpa/vdpa}" +DPLL="${DPLL:-$SNAME/dpll/dpll}" +GENL="${GENL:-$SNAME/genl/genl}" +TIPC="${TIPC:-$SNAME/tipc/tipc}" +NETSHAPER="${NETSHAPER:-$SNAME/netshaper/netshaper}" + +test_help_cmd() { + binary_path="$1" + arg="$2" + desc="$3" + + $binary_path $arg >$STD_OUT 2>$STD_ERR + status=$? + + if [ $status -ne 0 ]; then + ts_err "$0: $desc exited with $status (expected 0)" + return 1 + fi + + if [ -s $STD_ERR ]; then + ts_err "$0: $desc wrote to stderr (expected stdout only)" + ts_err "$0: stderr content:" + ts_err_cat $STD_ERR + return 1 + fi + + if [ ! -s $STD_OUT ]; then + ts_err "$0: $desc stdout was empty" + return 1 + fi + + echo "$0: $desc passed" + return 0 +} + +test_usage_error() { + binary_path="$1" + desc="$2" + + $binary_path >$STD_OUT 2>$STD_ERR + status=$? + + if [ $status -eq 0 ]; then + ts_err "$0: $desc (no args) exited with 0 (expected non-zero)" + return 1 + fi + + if [ ! -s $STD_ERR ]; then + ts_err "$0: $desc (no args) stderr was empty (expected usage info)" + return 1 + fi + + echo "$0: $desc (no args) failed as expected" + return 0 +} + +test_help_netlink_bypass() { + binary_path="$1" + arg="$2" + desc="$3" + + $binary_path $arg >$STD_OUT 2>$STD_ERR + status=$? + + if [ $status -ne 0 ]; then + ts_err "$0: $desc exited with $status (expected 0)" + return 1 + fi + + echo "$0: $desc passed" + return 0 +} + +# Run tests for each utility +# ip +test_help_cmd "$IP" "help" "ip help" +test_help_cmd "$IP" "-help" "ip -help" +test_usage_error "$IP" "ip" + +# bridge +test_help_cmd "$BRIDGE" "help" "bridge help" +test_help_cmd "$BRIDGE" "-h" "bridge -h" +test_usage_error "$BRIDGE" "bridge" + +# tc +test_help_cmd "$TC" "help" "tc help" +test_help_cmd "$TC" "-h" "tc -h" +test_usage_error "$TC" "tc" + +# devlink +test_help_cmd "$DEVLINK" "help" "devlink help" +test_help_cmd "$DEVLINK" "-h" "devlink -h" +test_help_netlink_bypass "$DEVLINK" "dev help" "devlink dev help" +test_usage_error "$DEVLINK" "devlink" + +# dcb +test_help_cmd "$DCB" "help" "dcb help" +test_help_cmd "$DCB" "-h" "dcb -h" +test_help_netlink_bypass "$DCB" "app help" "dcb app help" +test_usage_error "$DCB" "dcb" + +# rdma +test_help_cmd "$RDMA" "help" "rdma help" +test_help_cmd "$RDMA" "-h" "rdma -h" +test_help_netlink_bypass "$RDMA" "dev help" "rdma dev help" +test_usage_error "$RDMA" "rdma" + +# vdpa +test_help_cmd "$VDPA" "help" "vdpa help" +test_help_cmd "$VDPA" "-h" "vdpa -h" +test_help_netlink_bypass "$VDPA" "dev help" "vdpa dev help" +test_usage_error "$VDPA" "vdpa" + +# dpll +test_help_cmd "$DPLL" "help" "dpll help" +test_help_cmd "$DPLL" "-h" "dpll -h" +test_help_netlink_bypass "$DPLL" "device help" "dpll device help" +test_usage_error "$DPLL" "dpll" + +# genl +test_help_cmd "$GENL" "-help" "genl -help" +test_usage_error "$GENL" "genl" + +# tipc +test_help_cmd "$TIPC" "-h" "tipc -h" +test_help_cmd "$TIPC" "--help" "tipc --help" +test_usage_error "$TIPC" "tipc" + +# netshaper +test_help_cmd "$NETSHAPER" "help" "netshaper help" +test_help_cmd "$NETSHAPER" "-help" "netshaper -help" +test_help_netlink_bypass "$NETSHAPER" "group help" "netshaper group help" +test_usage_error "$NETSHAPER" "netshaper"
diff --git a/tipc/bearer.c b/tipc/bearer.c
index bb434f5f..2804631b 100644
--- a/tipc/bearer.c
+++ b/tipc/bearer.c@@ -33,9 +33,9 @@ struct cb_data { struct nlmsghdr *nlh; }; -static void _print_bearer_opts(void) +static void _print_bearer_opts(FILE *out) { - fprintf(stderr, + fprintf(out, "OPTIONS\n" " priority - Bearer link priority\n" " tolerance - Bearer link tolerance\n"
@@ -43,18 +43,18 @@ static void _print_bearer_opts(void) " mtu - Bearer link mtu\n"); } -void print_bearer_media(void) +void print_bearer_media(FILE *out) { - fprintf(stderr, + fprintf(out, "\nMEDIA\n" " udp - User Datagram Protocol\n" " ib - Infiniband\n" " eth - Ethernet\n"); } -static void cmd_bearer_enable_l2_help(struct cmdl *cmdl, char *media) +static void cmd_bearer_enable_l2_help(FILE *out, struct cmdl *cmdl, char *media) { - fprintf(stderr, + fprintf(out, "Usage: %s bearer enable media %s device DEVICE [OPTIONS]\n" "\nOPTIONS\n" " domain DOMAIN - Discovery domain\n"
@@ -62,9 +62,9 @@ static void cmd_bearer_enable_l2_help(struct cmdl *cmdl, char *media) cmdl->argv[0], media); } -static void cmd_bearer_enable_udp_help(struct cmdl *cmdl, char *media) +static void cmd_bearer_enable_udp_help(FILE *out, struct cmdl *cmdl, char *media) { - fprintf(stderr, + fprintf(out, "Usage: %s bearer enable [OPTIONS] media %s name NAME [localip IP|device DEVICE] [UDP OPTIONS]\n\n" "OPTIONS\n" " domain DOMAIN - Discovery domain\n"
@@ -230,7 +230,7 @@ static int nl_add_udp_enable_opts(struct nlmsghdr *nlh, struct opt *opts, opt = get_opt(opts, "localip"); if (!opt) { fprintf(stderr, "error, udp bearer localip/device missing\n"); - cmd_bearer_enable_udp_help(cmdl, "udp"); + cmd_bearer_enable_udp_help(help_flag ? stdout : stderr, cmdl, "udp"); return -EINVAL; } locip = opt->val;
@@ -292,7 +292,7 @@ static char *cmd_get_media_type(const struct cmd *cmd, struct cmdl *cmdl, if (!opt) { if (help_flag) - (cmd->help)(cmdl); + (cmd->help)(help_flag ? stdout : stderr, cmdl); else fprintf(stderr, "error, missing bearer media\n"); return NULL;
@@ -307,14 +307,14 @@ static int nl_add_bearer_name(struct nlmsghdr *nlh, const struct cmd *cmd, char bname[TIPC_MAX_BEARER_NAME]; int err; - if ((err = cmd_get_unique_bearer_name(cmd, cmdl, opts, bname, sup_media))) + if ((err = cmd_get_unique_bearer_name(help_flag ? stdout : stderr, cmd, cmdl, opts, bname, sup_media))) return err; mnl_attr_put_strz(nlh, TIPC_NLA_BEARER_NAME, bname); return 0; } -int cmd_get_unique_bearer_name(const struct cmd *cmd, struct cmdl *cmdl, +int cmd_get_unique_bearer_name(FILE *out, const struct cmd *cmd, struct cmdl *cmdl, struct opt *opts, char *bname, const struct tipc_sup_media *sup_media) {
@@ -332,7 +332,7 @@ int cmd_get_unique_bearer_name(const struct cmd *cmd, struct cmdl *cmdl, if (!(opt = get_opt(opts, entry->identifier))) { if (help_flag) - (entry->help)(cmdl, media); + (entry->help)(out, cmdl, media); else fprintf(stderr, "error, missing bearer %s\n", entry->identifier);
@@ -350,15 +350,15 @@ int cmd_get_unique_bearer_name(const struct cmd *cmd, struct cmdl *cmdl, return -EINVAL; } -static void cmd_bearer_add_udp_help(struct cmdl *cmdl, char *media) +static void cmd_bearer_add_udp_help(FILE *out, struct cmdl *cmdl, char *media) { - fprintf(stderr, "Usage: %s bearer add media %s name NAME remoteip REMOTEIP\n\n", + fprintf(out, "Usage: %s bearer add media %s name NAME remoteip REMOTEIP\n\n", cmdl->argv[0], media); } -static void cmd_bearer_add_help(struct cmdl *cmdl) +static void cmd_bearer_add_help(FILE *out, struct cmdl *cmdl) { - fprintf(stderr, "Usage: %s bearer add media udp name NAME remoteip REMOTEIP\n", + fprintf(out, "Usage: %s bearer add media udp name NAME remoteip REMOTEIP\n", cmdl->argv[0]); }
@@ -421,6 +421,11 @@ static int cmd_bearer_add_media(struct nlmsghdr *nlh, const struct cmd *cmd, { NULL, }, }; + if (help_flag) { + (cmd->help)(stdout, cmdl); + return 0; + } + /* Rewind optind to include media in the option list */ cmdl->optind--; if (parse_opts(opts, cmdl) < 0)
@@ -473,15 +478,15 @@ static int cmd_bearer_add(struct nlmsghdr *nlh, const struct cmd *cmd, return run_cmd(nlh, cmd, cmds, cmdl, NULL); } -static void cmd_bearer_enable_help(struct cmdl *cmdl) +static void cmd_bearer_enable_help(FILE *out, struct cmdl *cmdl) { - fprintf(stderr, + fprintf(out, "Usage: %s bearer enable [OPTIONS] media MEDIA ARGS...\n\n" "OPTIONS\n" " domain DOMAIN - Discovery domain\n" " priority PRIORITY - Bearer priority\n", cmdl->argv[0]); - print_bearer_media(); + print_bearer_media(out); } static int cmd_bearer_enable(struct nlmsghdr *nlh, const struct cmd *cmd,
@@ -509,12 +514,14 @@ static int cmd_bearer_enable(struct nlmsghdr *nlh, const struct cmd *cmd, { NULL, }, }; - if (parse_opts(opts, cmdl) < 0) { - if (help_flag) - (cmd->help)(cmdl); - return -EINVAL; + if (help_flag) { + (cmd->help)(stdout, cmdl); + return 0; } + if (parse_opts(opts, cmdl) < 0) + return -EINVAL; + nlh = msg_init(TIPC_NL_BEARER_ENABLE); if (!nlh) { fprintf(stderr, "error: message initialisation failed\n");
@@ -548,23 +555,23 @@ static int cmd_bearer_enable(struct nlmsghdr *nlh, const struct cmd *cmd, return msg_doit(nlh, NULL, NULL); } -static void cmd_bearer_disable_l2_help(struct cmdl *cmdl, char *media) +static void cmd_bearer_disable_l2_help(FILE *out, struct cmdl *cmdl, char *media) { - fprintf(stderr, "Usage: %s bearer disable media %s device DEVICE\n", + fprintf(out, "Usage: %s bearer disable media %s device DEVICE\n", cmdl->argv[0], media); } -static void cmd_bearer_disable_udp_help(struct cmdl *cmdl, char *media) +static void cmd_bearer_disable_udp_help(FILE *out, struct cmdl *cmdl, char *media) { - fprintf(stderr, "Usage: %s bearer disable media %s name NAME\n", + fprintf(out, "Usage: %s bearer disable media %s name NAME\n", cmdl->argv[0], media); } -static void cmd_bearer_disable_help(struct cmdl *cmdl) +static void cmd_bearer_disable_help(FILE *out, struct cmdl *cmdl) { - fprintf(stderr, "Usage: %s bearer disable media MEDIA ARGS...\n", + fprintf(out, "Usage: %s bearer disable media MEDIA ARGS...\n", cmdl->argv[0]); - print_bearer_media(); + print_bearer_media(out); } static int cmd_bearer_disable(struct nlmsghdr *nlh, const struct cmd *cmd,
@@ -585,12 +592,14 @@ static int cmd_bearer_disable(struct nlmsghdr *nlh, const struct cmd *cmd, { NULL, }, }; - if (parse_opts(opts, cmdl) < 0) { - if (help_flag) - (cmd->help)(cmdl); - return -EINVAL; + if (help_flag) { + (cmd->help)(stdout, cmdl); + return 0; } + if (parse_opts(opts, cmdl) < 0) + return -EINVAL; + nlh = msg_init(TIPC_NL_BEARER_DISABLE); if (!nlh) { fprintf(stderr, "error, message initialisation failed\n");
@@ -607,27 +616,27 @@ static int cmd_bearer_disable(struct nlmsghdr *nlh, const struct cmd *cmd, } -static void cmd_bearer_set_help(struct cmdl *cmdl) +static void cmd_bearer_set_help(FILE *out, struct cmdl *cmdl) { - fprintf(stderr, "Usage: %s bearer set OPTION media MEDIA ARGS...\n", + fprintf(out, "Usage: %s bearer set OPTION media MEDIA ARGS...\n", cmdl->argv[0]); - _print_bearer_opts(); - print_bearer_media(); + _print_bearer_opts(out); + print_bearer_media(out); } -static void cmd_bearer_set_udp_help(struct cmdl *cmdl, char *media) +static void cmd_bearer_set_udp_help(FILE *out, struct cmdl *cmdl, char *media) { - fprintf(stderr, "Usage: %s bearer set OPTION media %s name NAME\n\n", + fprintf(out, "Usage: %s bearer set OPTION media %s name NAME\n\n", cmdl->argv[0], media); - _print_bearer_opts(); + _print_bearer_opts(out); } -static void cmd_bearer_set_l2_help(struct cmdl *cmdl, char *media) +static void cmd_bearer_set_l2_help(FILE *out, struct cmdl *cmdl, char *media) { - fprintf(stderr, + fprintf(out, "Usage: %s bearer set [OPTION]... media %s device DEVICE\n", cmdl->argv[0], media); - _print_bearer_opts(); + _print_bearer_opts(out); } static int cmd_bearer_set_prop(struct nlmsghdr *nlh, const struct cmd *cmd,
@@ -662,6 +671,11 @@ static int cmd_bearer_set_prop(struct nlmsghdr *nlh, const struct cmd *cmd, else return -EINVAL; + if (help_flag) { + (cmd->help)(stdout, cmdl); + return 0; + } + if (cmdl->optind >= cmdl->argc) { fprintf(stderr, "error, missing value\n"); return -EINVAL;
@@ -716,33 +730,33 @@ static int cmd_bearer_set(struct nlmsghdr *nlh, const struct cmd *cmd, return run_cmd(nlh, cmd, cmds, cmdl, NULL); } -static void cmd_bearer_get_help(struct cmdl *cmdl) +static void cmd_bearer_get_help(FILE *out, struct cmdl *cmdl) { - fprintf(stderr, "Usage: %s bearer get [OPTION] media MEDIA ARGS...\n", + fprintf(out, "Usage: %s bearer get [OPTION] media MEDIA ARGS...\n", cmdl->argv[0]); - _print_bearer_opts(); - print_bearer_media(); + _print_bearer_opts(out); + print_bearer_media(out); } -static void cmd_bearer_get_udp_help(struct cmdl *cmdl, char *media) +static void cmd_bearer_get_udp_help(FILE *out, struct cmdl *cmdl, char *media) { - fprintf(stderr, "Usage: %s bearer get [OPTION] media %s name NAME [UDP OPTIONS]\n\n", + fprintf(out, "Usage: %s bearer get [OPTION] media %s name NAME [UDP OPTIONS]\n\n", cmdl->argv[0], media); - fprintf(stderr, + fprintf(out, "UDP OPTIONS\n" " remoteip - Remote ip address\n" " remoteport - Remote port\n" " localip - Local ip address\n" " localport - Local port\n\n"); - _print_bearer_opts(); + _print_bearer_opts(out); } -static void cmd_bearer_get_l2_help(struct cmdl *cmdl, char *media) +static void cmd_bearer_get_l2_help(FILE *out, struct cmdl *cmdl, char *media) { - fprintf(stderr, + fprintf(out, "Usage: %s bearer get OPTION media %s device DEVICE\n", cmdl->argv[0], media); - _print_bearer_opts(); + _print_bearer_opts(out); }
@@ -938,8 +952,8 @@ static int cmd_bearer_get_media(struct nlmsghdr *nlh, const struct cmd *cmd, media = opt->val; if (help_flag) { - cmd_bearer_get_udp_help(cmdl, media); - return -EINVAL; + cmd_bearer_get_udp_help(stdout, cmdl, media); + return 0; } if (strcmp(media, "udp") != 0) { fprintf(stderr, "error, no \"%s\" media specific options\n", media);
@@ -1004,8 +1018,8 @@ static int cmd_bearer_get_prop(struct nlmsghdr *nlh, const struct cmd *cmd, }; if (help_flag) { - (cmd->help)(cmdl); - return -EINVAL; + (cmd->help)(stdout, cmdl); + return 0; } if (strcmp(cmd->cmd, "priority") == 0)
@@ -1090,8 +1104,8 @@ static int cmd_bearer_list(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl, void *data) { if (help_flag) { - fprintf(stderr, "Usage: %s bearer list\n", cmdl->argv[0]); - return -EINVAL; + fprintf(stdout, "Usage: %s bearer list\n", cmdl->argv[0]); + return 0; } nlh = msg_init(TIPC_NL_BEARER_GET);
@@ -1103,9 +1117,9 @@ static int cmd_bearer_list(struct nlmsghdr *nlh, const struct cmd *cmd, return msg_dumpit(nlh, bearer_list_cb, NULL); } -void cmd_bearer_help(struct cmdl *cmdl) +void cmd_bearer_help(FILE *out, struct cmdl *cmdl) { - fprintf(stderr, + fprintf(out, "Usage: %s bearer COMMAND [ARGS] ...\n" "\n" "COMMANDS\n"
diff --git a/tipc/bearer.h b/tipc/bearer.h
index a9344659..2389f811 100644
--- a/tipc/bearer.h
+++ b/tipc/bearer.h@@ -12,11 +12,13 @@ extern int help_flag; +#include <stdio.h> + int cmd_bearer(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl, void *data); -void cmd_bearer_help(struct cmdl *cmdl); +void cmd_bearer_help(FILE *out, struct cmdl *cmdl); -void print_bearer_media(void); -int cmd_get_unique_bearer_name(const struct cmd *cmd, struct cmdl *cmdl, +void print_bearer_media(FILE *out); +int cmd_get_unique_bearer_name(FILE *out, const struct cmd *cmd, struct cmdl *cmdl, struct opt *opts, char *bname, const struct tipc_sup_media *sup_media); #endif
diff --git a/tipc/cmdl.c b/tipc/cmdl.c
index 152ddb51..ee9e822c 100644
--- a/tipc/cmdl.c
+++ b/tipc/cmdl.c@@ -108,7 +108,7 @@ int run_cmd(struct nlmsghdr *nlh, const struct cmd *caller, if ((cmdl->optind) >= cmdl->argc) { if (caller->help) - (caller->help)(cmdl); + (caller->help)(help_flag ? stdout : stderr, cmdl); return -EINVAL; } name = cmdl->argv[cmdl->optind];
@@ -118,7 +118,7 @@ int run_cmd(struct nlmsghdr *nlh, const struct cmd *caller, if (!cmd) { /* Show help about last command if we don't find this one */ if (help_flag && caller->help) { - (caller->help)(cmdl); + (caller->help)(stdout, cmdl); } else { fprintf(stderr, "error, invalid command \"%s\"\n", name); fprintf(stderr, "use --help for command help\n");
@@ -126,5 +126,10 @@ int run_cmd(struct nlmsghdr *nlh, const struct cmd *caller, return -EINVAL; } + if (help_flag && cmdl->optind >= cmdl->argc && cmd->help) { + (cmd->help)(stdout, cmdl); + return 0; + } + return (cmd->func)(nlh, cmd, cmdl, data); }
diff --git a/tipc/cmdl.h b/tipc/cmdl.h
index 18fe51bf..fd8f02d1 100644
--- a/tipc/cmdl.h
+++ b/tipc/cmdl.h@@ -12,6 +12,8 @@ extern int help_flag; +#include <stdio.h> + enum { OPT_KEY = (1 << 0), OPT_KEYVAL = (1 << 1),
@@ -26,14 +28,14 @@ struct cmdl { struct tipc_sup_media { char *media; char *identifier; - void (*help)(struct cmdl *cmdl, char *media); + void (*help)(FILE *out, struct cmdl *cmdl, char *media); }; struct cmd { const char *cmd; int (*func)(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl, void *data); - void (*help)(struct cmdl *cmdl); + void (*help)(FILE *out, struct cmdl *cmdl); }; struct opt {
diff --git a/tipc/link.c b/tipc/link.c
index f91c3000..48b759d3 100644
--- a/tipc/link.c
+++ b/tipc/link.c@@ -139,8 +139,8 @@ static int cmd_link_get_prop(struct nlmsghdr *nlh, const struct cmd *cmd, return -EINVAL; if (help_flag) { - (cmd->help)(cmdl); - return -EINVAL; + (cmd->help)(stdout, cmdl); + return 0; } if (parse_opts(opts, cmdl) < 0)
@@ -164,9 +164,9 @@ static int cmd_link_get_prop(struct nlmsghdr *nlh, const struct cmd *cmd, return msg_doit(nlh, link_get_cb, &prop); } -static void cmd_link_get_help(struct cmdl *cmdl) +static void cmd_link_get_help(FILE *out, struct cmdl *cmdl) { - fprintf(stderr, "Usage: %s link get PPROPERTY link LINK\n\n" + fprintf(out, "Usage: %s link get PPROPERTY link LINK\n\n" "PROPERTIES\n" " tolerance - Get link tolerance\n" " priority - Get link priority\n"
@@ -224,9 +224,9 @@ static int cmd_link_get_bcast_cb(const struct nlmsghdr *nlh, void *data) return MNL_CB_OK; } -static void cmd_link_get_bcast_help(struct cmdl *cmdl) +static void cmd_link_get_bcast_help(FILE *out, struct cmdl *cmdl) { - fprintf(stderr, "Usage: %s link get PPROPERTY\n\n" + fprintf(out, "Usage: %s link get PPROPERTY\n\n" "PROPERTIES\n" " broadcast - Get link broadcast\n", cmdl->argv[0]);
@@ -239,8 +239,8 @@ static int cmd_link_get_bcast(struct nlmsghdr *nlh, const struct cmd *cmd, struct nlattr *attrs; if (help_flag) { - (cmd->help)(cmdl); - return -EINVAL; + (cmd->help)(stdout, cmdl); + return 0; } nlh = msg_init(TIPC_NL_LINK_GET);
@@ -269,9 +269,9 @@ static int cmd_link_get(struct nlmsghdr *nlh, const struct cmd *cmd, return run_cmd(nlh, cmd, cmds, cmdl, NULL); } -static void cmd_link_stat_reset_help(struct cmdl *cmdl) +static void cmd_link_stat_reset_help(FILE *out, struct cmdl *cmdl) { - fprintf(stderr, "Usage: %s link stat reset link LINK\n\n", cmdl->argv[0]); + fprintf(out, "Usage: %s link stat reset link LINK\n\n", cmdl->argv[0]); } static int cmd_link_stat_reset(struct nlmsghdr *nlh, const struct cmd *cmd,
@@ -286,12 +286,12 @@ static int cmd_link_stat_reset(struct nlmsghdr *nlh, const struct cmd *cmd, }; if (help_flag) { - (cmd->help)(cmdl); - return -EINVAL; + (cmd->help)(stdout, cmdl); + return 0; } if (parse_opts(opts, cmdl) != 1) { - (cmd->help)(cmdl); + (cmd->help)(stdout, cmdl); return -EINVAL; }
@@ -533,9 +533,9 @@ static int link_stat_show_cb(const struct nlmsghdr *nlh, void *data) return _show_link_stat(name, attrs, prop, stats); } -static void cmd_link_stat_show_help(struct cmdl *cmdl) +static void cmd_link_stat_show_help(FILE *out, struct cmdl *cmdl) { - fprintf(stderr, "Usage: %s link stat show [ link { LINK | SUBSTRING | all } ]\n", + fprintf(out, "Usage: %s link stat show [ link { LINK | SUBSTRING | all } ]\n", cmdl->argv[0]); }
@@ -552,8 +552,8 @@ static int cmd_link_stat_show(struct nlmsghdr *nlh, const struct cmd *cmd, int err = 0; if (help_flag) { - (cmd->help)(cmdl); - return -EINVAL; + (cmd->help)(stdout, cmdl); + return 0; } nlh = msg_init(TIPC_NL_LINK_GET);
@@ -581,9 +581,9 @@ static int cmd_link_stat_show(struct nlmsghdr *nlh, const struct cmd *cmd, return err; } -static void cmd_link_stat_help(struct cmdl *cmdl) +static void cmd_link_stat_help(FILE *out, struct cmdl *cmdl) { - fprintf(stderr, "Usage: %s link stat COMMAND [ARGS]\n\n" + fprintf(out, "Usage: %s link stat COMMAND [ARGS]\n\n" "COMMANDS:\n" " reset - Reset link statistics for link\n" " show - Get link priority\n",
@@ -602,9 +602,9 @@ static int cmd_link_stat(struct nlmsghdr *nlh, const struct cmd *cmd, return run_cmd(nlh, cmd, cmds, cmdl, NULL); } -static void cmd_link_set_help(struct cmdl *cmdl) +static void cmd_link_set_help(FILE *out, struct cmdl *cmdl) { - fprintf(stderr, "Usage: %s link set PPROPERTY link LINK\n\n" + fprintf(out, "Usage: %s link set PROPERTY link LINK\n\n" "PROPERTIES\n" " tolerance TOLERANCE - Set link tolerance\n" " priority PRIORITY - Set link priority\n"
@@ -636,8 +636,8 @@ static int cmd_link_set_prop(struct nlmsghdr *nlh, const struct cmd *cmd, return -EINVAL; if (help_flag) { - (cmd->help)(cmdl); - return -EINVAL; + (cmd->help)(stdout, cmdl); + return 0; } if (cmdl->optind >= cmdl->argc) {
@@ -672,9 +672,9 @@ static int cmd_link_set_prop(struct nlmsghdr *nlh, const struct cmd *cmd, return msg_doit(nlh, link_get_cb, &prop); } -static void cmd_link_set_bcast_help(struct cmdl *cmdl) +static void cmd_link_set_bcast_help(FILE *out, struct cmdl *cmdl) { - fprintf(stderr, "Usage: %s link set broadcast PROPERTY\n\n" + fprintf(out, "Usage: %s link set broadcast PROPERTY\n\n" "PROPERTIES\n" " BROADCAST - Forces all multicast traffic to be\n" " transmitted via broadcast only,\n"
@@ -708,8 +708,8 @@ static int cmd_link_set_bcast(struct nlmsghdr *nlh, const struct cmd *cmd, int method = 0; if (help_flag) { - (cmd->help)(cmdl); - return -EINVAL; + (cmd->help)(stdout, cmdl); + return 0; } if (parse_opts(opts, cmdl) < 0)
@@ -720,7 +720,7 @@ static int cmd_link_set_bcast(struct nlmsghdr *nlh, const struct cmd *cmd, break; if (!opt || !opt->key) { - (cmd->help)(cmdl); + (cmd->help)(stdout, cmdl); return -EINVAL; }
@@ -744,7 +744,7 @@ static int cmd_link_set_bcast(struct nlmsghdr *nlh, const struct cmd *cmd, opt = get_opt(opts, "ratio"); if (!method && !opt) { - (cmd->help)(cmdl); + (cmd->help)(stdout, cmdl); return -EINVAL; }
@@ -833,8 +833,8 @@ static int cmd_link_mon_summary(struct nlmsghdr *nlh, const struct cmd *cmd, int err = 0; if (help_flag) { - fprintf(stderr, "Usage: %s monitor summary\n", cmdl->argv[0]); - return -EINVAL; + fprintf(stdout, "Usage: %s monitor summary\n", cmdl->argv[0]); + return 0; } nlh = msg_init(TIPC_NL_MON_GET);
@@ -1052,23 +1052,23 @@ static int link_mon_list_cb(const struct nlmsghdr *nlh, void *data) return MNL_CB_OK; } -static void cmd_link_mon_list_help(struct cmdl *cmdl) +static void cmd_link_mon_list_help(FILE *out, struct cmdl *cmdl) { - fprintf(stderr, "Usage: %s monitor list [ media MEDIA ARGS...]\n\n", + fprintf(out, "Usage: %s monitor list [ media MEDIA ARGS...]\n\n", cmdl->argv[0]); - print_bearer_media(); + print_bearer_media(out); } -static void cmd_link_mon_list_l2_help(struct cmdl *cmdl, char *media) +static void cmd_link_mon_list_l2_help(FILE *out, struct cmdl *cmdl, char *media) { - fprintf(stderr, + fprintf(out, "Usage: %s monitor list media %s device DEVICE [OPTIONS]\n", cmdl->argv[0], media); } -static void cmd_link_mon_list_udp_help(struct cmdl *cmdl, char *media) +static void cmd_link_mon_list_udp_help(FILE *out, struct cmdl *cmdl, char *media) { - fprintf(stderr, + fprintf(out, "Usage: %s monitor list media udp name NAME\n\n", cmdl->argv[0]); }
@@ -1096,15 +1096,15 @@ static int cmd_link_mon_list(struct nlmsghdr *nlh, const struct cmd *cmd, return -EINVAL; if (get_opt(opts, "media")) { - err = cmd_get_unique_bearer_name(cmd, cmdl, opts, bname, + err = cmd_get_unique_bearer_name(help_flag ? stdout : stderr, cmd, cmdl, opts, bname, sup_media); if (err) return err; } if (help_flag) { - cmd->help(cmdl); - return -EINVAL; + cmd->help(stdout, cmdl); + return 0; } nlh = msg_init(TIPC_NL_MON_GET);
@@ -1119,9 +1119,9 @@ static int cmd_link_mon_list(struct nlmsghdr *nlh, const struct cmd *cmd, return err; } -static void cmd_link_mon_set_help(struct cmdl *cmdl) +static void cmd_link_mon_set_help(FILE *out, struct cmdl *cmdl) { - fprintf(stderr, "Usage: %s monitor set PPROPERTY\n\n" + fprintf(out, "Usage: %s monitor set PROPERTY\n\n" "PROPERTIES\n" " threshold SIZE - Set monitor activation threshold\n", cmdl->argv[0]);
@@ -1131,16 +1131,16 @@ static int cmd_link_mon_set(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl, void *data) { const struct cmd cmds[] = { - { "threshold", cmd_link_mon_set_prop, NULL }, + { "threshold", cmd_link_mon_set_prop, cmd_link_mon_set_help }, { NULL } }; return run_cmd(nlh, cmd, cmds, cmdl, NULL); } -static void cmd_link_mon_get_help(struct cmdl *cmdl) +static void cmd_link_mon_get_help(FILE *out, struct cmdl *cmdl) { - fprintf(stderr, "Usage: %s monitor get PPROPERTY\n\n" + fprintf(out, "Usage: %s monitor get PROPERTY\n\n" "PROPERTIES\n" " threshold - Get monitor activation threshold\n", cmdl->argv[0]);
@@ -1171,6 +1171,10 @@ static int link_mon_get_cb(const struct nlmsghdr *nlh, void *data) static int cmd_link_mon_get_prop(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl, void *data) { + if (help_flag) { + (cmd->help)(stdout, cmdl); + return 0; + } nlh = msg_init(TIPC_NL_MON_GET); if (!nlh) {
@@ -1185,17 +1189,17 @@ static int cmd_link_mon_get(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl, void *data) { const struct cmd cmds[] = { - { "threshold", cmd_link_mon_get_prop, NULL}, + { "threshold", cmd_link_mon_get_prop, cmd_link_mon_get_help}, { NULL } }; return run_cmd(nlh, cmd, cmds, cmdl, NULL); } -static void cmd_link_mon_help(struct cmdl *cmdl) +static void cmd_link_mon_help(FILE *out, struct cmdl *cmdl) { - fprintf(stderr, - "Usage: %s montior COMMAND [ARGS] ...\n\n" + fprintf(out, + "Usage: %s monitor COMMAND [ARGS] ...\n\n" "COMMANDS\n" " set - Set monitor properties\n" " get - Get monitor properties\n"
@@ -1218,9 +1222,9 @@ static int cmd_link_mon(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl return run_cmd(nlh, cmd, cmds, cmdl, NULL); } -void cmd_link_help(struct cmdl *cmdl) +void cmd_link_help(FILE *out, struct cmdl *cmdl) { - fprintf(stderr, + fprintf(out, "Usage: %s link COMMAND [ARGS] ...\n" "\n" "COMMANDS\n"
diff --git a/tipc/link.h b/tipc/link.h
index a0d46035..09e47b89 100644
--- a/tipc/link.h
+++ b/tipc/link.h@@ -8,10 +8,10 @@ #ifndef _TIPC_LINK_H #define _TIPC_LINK_H -extern int help_flag; +#include <stdio.h> int cmd_link(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl, void *data); -void cmd_link_help(struct cmdl *cmdl); +void cmd_link_help(FILE *out, struct cmdl *cmdl); #endif
diff --git a/tipc/media.c b/tipc/media.c
index 5ff0c8c4..82ce5145 100644
--- a/tipc/media.c
+++ b/tipc/media.c@@ -40,8 +40,8 @@ static int cmd_media_list(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl, void *data) { if (help_flag) { - fprintf(stderr, "Usage: %s media list\n", cmdl->argv[0]); - return -EINVAL; + fprintf(stdout, "Usage: %s media list\n", cmdl->argv[0]); + return 0; } nlh = msg_init(TIPC_NL_MEDIA_GET);
@@ -101,8 +101,8 @@ static int cmd_media_get_prop(struct nlmsghdr *nlh, const struct cmd *cmd, return -EINVAL; if (help_flag) { - (cmd->help)(cmdl); - return -EINVAL; + (cmd->help)(stdout, cmdl); + return 0; } if (parse_opts(opts, cmdl) < 0)
@@ -131,9 +131,9 @@ static int cmd_media_get_prop(struct nlmsghdr *nlh, const struct cmd *cmd, return msg_doit(nlh, media_get_cb, &prop); } -static void cmd_media_get_help(struct cmdl *cmdl) +static void cmd_media_get_help(FILE *out, struct cmdl *cmdl) { - fprintf(stderr, "Usage: %s media get PPROPERTY media MEDIA\n\n" + fprintf(out, "Usage: %s media get PPROPERTY media MEDIA\n\n" "PROPERTIES\n" " tolerance - Get media tolerance\n" " priority - Get media priority\n"
@@ -156,9 +156,9 @@ static int cmd_media_get(struct nlmsghdr *nlh, const struct cmd *cmd, return run_cmd(nlh, cmd, cmds, cmdl, NULL); } -static void cmd_media_set_help(struct cmdl *cmdl) +static void cmd_media_set_help(FILE *out, struct cmdl *cmdl) { - fprintf(stderr, "Usage: %s media set PPROPERTY media MEDIA\n\n" + fprintf(out, "Usage: %s media set PPROPERTY media MEDIA\n\n" "PROPERTIES\n" " tolerance TOLERANCE - Set media tolerance\n" " priority PRIORITY - Set media priority\n"
@@ -192,8 +192,8 @@ static int cmd_media_set_prop(struct nlmsghdr *nlh, const struct cmd *cmd, return -EINVAL; if (help_flag) { - (cmd->help)(cmdl); - return -EINVAL; + (cmd->help)(stdout, cmdl); + return 0; } if (cmdl->optind >= cmdl->argc) {
@@ -247,9 +247,9 @@ static int cmd_media_set(struct nlmsghdr *nlh, const struct cmd *cmd, return run_cmd(nlh, cmd, cmds, cmdl, NULL); } -void cmd_media_help(struct cmdl *cmdl) +void cmd_media_help(FILE *out, struct cmdl *cmdl) { - fprintf(stderr, + fprintf(out, "Usage: %s media COMMAND [ARGS] ...\n" "\n" "Commands:\n"
diff --git a/tipc/media.h b/tipc/media.h
index f1b4b540..eb4374dd 100644
--- a/tipc/media.h
+++ b/tipc/media.h@@ -8,10 +8,10 @@ #ifndef _TIPC_MEDIA_H #define _TIPC_MEDIA_H -extern int help_flag; +#include <stdio.h> int cmd_media(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl, void *data); -void cmd_media_help(struct cmdl *cmdl); +void cmd_media_help(FILE *out, struct cmdl *cmdl); #endif
diff --git a/tipc/nametable.c b/tipc/nametable.c
index 5162f7fc..1ede1024 100644
--- a/tipc/nametable.c
+++ b/tipc/nametable.c@@ -80,8 +80,8 @@ static int cmd_nametable_show(struct nlmsghdr *nlh, const struct cmd *cmd, int rc = 0; if (help_flag) { - fprintf(stderr, "Usage: %s nametable show\n", cmdl->argv[0]); - return -EINVAL; + fprintf(stdout, "Usage: %s nametable show\n", cmdl->argv[0]); + return 0; } nlh = msg_init(TIPC_NL_NAME_TABLE_GET);
@@ -97,9 +97,9 @@ static int cmd_nametable_show(struct nlmsghdr *nlh, const struct cmd *cmd, return rc; } -void cmd_nametable_help(struct cmdl *cmdl) +void cmd_nametable_help(FILE *out, struct cmdl *cmdl) { - fprintf(stderr, + fprintf(out, "Usage: %s nametable COMMAND\n\n" "COMMANDS\n" " show - Show nametable\n",
diff --git a/tipc/nametable.h b/tipc/nametable.h
index c4df8d9d..e84227ed 100644
--- a/tipc/nametable.h
+++ b/tipc/nametable.h@@ -8,9 +8,9 @@ #ifndef _TIPC_NAMETABLE_H #define _TIPC_NAMETABLE_H -extern int help_flag; +#include <stdio.h> -void cmd_nametable_help(struct cmdl *cmdl); +void cmd_nametable_help(FILE *out, struct cmdl *cmdl); int cmd_nametable(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl, void *data);
diff --git a/tipc/node.c b/tipc/node.c
index b84a3fa1..77abc185 100644
--- a/tipc/node.c
+++ b/tipc/node.c@@ -48,8 +48,8 @@ static int cmd_node_list(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl, void *data) { if (help_flag) { - fprintf(stderr, "Usage: %s node list\n", cmdl->argv[0]); - return -EINVAL; + fprintf(stdout, "Usage: %s node list\n", cmdl->argv[0]); + return 0; } nlh = msg_init(TIPC_NL_NODE_GET);
@@ -68,6 +68,11 @@ static int cmd_node_set_addr(struct nlmsghdr *nlh, const struct cmd *cmd, uint32_t addr; struct nlattr *nest; + if (help_flag) { + fprintf(stdout, "Usage: %s node set address ADDRESS\n", cmdl->argv[0]); + return 0; + } + if (cmdl->argc != cmdl->optind + 1) { fprintf(stderr, "Usage: %s node set address ADDRESS\n", cmdl->argv[0]);
@@ -126,6 +131,11 @@ static int cmd_node_set_nodeid(struct nlmsghdr *nlh, const struct cmd *cmd, struct nlattr *nest; char *str; + if (help_flag) { + fprintf(stdout, "Usage: %s node set nodeid NODE_ID\n", cmdl->argv[0]); + return 0; + } + if (cmdl->argc != cmdl->optind + 1) { fprintf(stderr, "Usage: %s node set nodeid NODE_ID\n", cmdl->argv[0]);
@@ -150,9 +160,9 @@ static int cmd_node_set_nodeid(struct nlmsghdr *nlh, const struct cmd *cmd, return msg_doit(nlh, NULL, NULL); } -static void cmd_node_set_key_help(struct cmdl *cmdl) +static void cmd_node_set_key_help(FILE *out, struct cmdl *cmdl) { - fprintf(stderr, + fprintf(out, "Usage: %s node set key KEY [algname ALGNAME] [PROPERTIES]\n" " %s node set key rekeying REKEYING\n\n" "KEY\n"
@@ -201,8 +211,8 @@ static int cmd_node_set_key(struct nlmsghdr *nlh, const struct cmd *cmd, char *str; if (help_flag || cmdl->optind >= cmdl->argc) { - (cmd->help)(cmdl); - return -EINVAL; + (cmd->help)(help_flag ? stdout : stderr, cmdl); + return help_flag ? 0 : -EINVAL; } /* Check if command starts with opts i.e. "rekeying" opt without key */
@@ -285,8 +295,8 @@ static int cmd_node_flush_key(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl, void *data) { if (help_flag) { - (cmd->help)(cmdl); - return -EINVAL; + (cmd->help)(stdout, cmdl); + return 0; } /* Init & do the command */
@@ -328,8 +338,8 @@ static int cmd_node_get_nodeid(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl, void *data) { if (help_flag) { - (cmd->help)(cmdl); - return -EINVAL; + (cmd->help)(stdout, cmdl); + return 0; } nlh = msg_init(TIPC_NL_NET_GET);
@@ -364,8 +374,8 @@ static int cmd_node_get_netid(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl, void *data) { if (help_flag) { - (cmd->help)(cmdl); - return -EINVAL; + (cmd->help)(stdout, cmdl); + return 0; } nlh = msg_init(TIPC_NL_NET_GET);
@@ -384,8 +394,8 @@ static int cmd_node_set_netid(struct nlmsghdr *nlh, const struct cmd *cmd, struct nlattr *nest; if (help_flag) { - (cmd->help)(cmdl); - return -EINVAL; + (cmd->help)(stdout, cmdl); + return 0; } nlh = msg_init(TIPC_NL_NET_SET);
@@ -408,9 +418,9 @@ static int cmd_node_set_netid(struct nlmsghdr *nlh, const struct cmd *cmd, return msg_doit(nlh, NULL, NULL); } -static void cmd_node_flush_help(struct cmdl *cmdl) +static void cmd_node_flush_help(FILE *out, struct cmdl *cmdl) { - fprintf(stderr, + fprintf(out, "Usage: %s node flush PROPERTY\n\n" "PROPERTIES\n" " key - Flush all symmetric-keys\n",
@@ -428,9 +438,9 @@ static int cmd_node_flush(struct nlmsghdr *nlh, const struct cmd *cmd, return run_cmd(nlh, cmd, cmds, cmdl, NULL); } -static void cmd_node_set_help(struct cmdl *cmdl) +static void cmd_node_set_help(FILE *out, struct cmdl *cmdl) { - fprintf(stderr, + fprintf(out, "Usage: %s node set PROPERTY\n\n" "PROPERTIES\n" " identity NODEID - Set node identity\n"
@@ -454,9 +464,9 @@ static int cmd_node_set(struct nlmsghdr *nlh, const struct cmd *cmd, return run_cmd(nlh, cmd, cmds, cmdl, NULL); } -static void cmd_node_get_help(struct cmdl *cmdl) +static void cmd_node_get_help(FILE *out, struct cmdl *cmdl) { - fprintf(stderr, + fprintf(out, "Usage: %s node get PROPERTY\n\n" "PROPERTIES\n" " identity - Get node identity\n"
@@ -478,9 +488,9 @@ static int cmd_node_get(struct nlmsghdr *nlh, const struct cmd *cmd, return run_cmd(nlh, cmd, cmds, cmdl, NULL); } -void cmd_node_help(struct cmdl *cmdl) +void cmd_node_help(FILE *out, struct cmdl *cmdl) { - fprintf(stderr, + fprintf(out, "Usage: %s node COMMAND [ARGS] ...\n\n" "COMMANDS\n" " list - List remote nodes\n"
diff --git a/tipc/node.h b/tipc/node.h
index 4a986d07..7d310897 100644
--- a/tipc/node.h
+++ b/tipc/node.h@@ -8,10 +8,10 @@ #ifndef _TIPC_NODE_H #define _TIPC_NODE_H -extern int help_flag; +#include <stdio.h> int cmd_node(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl, void *data); -void cmd_node_help(struct cmdl *cmdl); +void cmd_node_help(FILE *out, struct cmdl *cmdl); #endif
diff --git a/tipc/peer.c b/tipc/peer.c
index 5a583fb9..6d12fb19 100644
--- a/tipc/peer.c
+++ b/tipc/peer.c@@ -27,9 +27,9 @@ static int cmd_peer_rm_addr(struct nlmsghdr *nlh, const struct cmd *cmd, struct nlattr *nest; if ((cmdl->argc != cmdl->optind + 1) || help_flag) { - fprintf(stderr, "Usage: %s peer remove address ADDRESS\n", + fprintf(help_flag ? stdout : stderr, "Usage: %s peer remove address ADDRESS\n", cmdl->argv[0]); - return -EINVAL; + return help_flag ? 0 : -EINVAL; } str = shift_cmdl(cmdl);
@@ -63,10 +63,10 @@ static int cmd_peer_rm_nodeid(struct nlmsghdr *nlh, const struct cmd *cmd, struct nlattr *nest; char *str; - if (cmdl->argc != cmdl->optind + 1) { - fprintf(stderr, "Usage: %s peer remove identity NODEID\n", + if ((cmdl->argc != cmdl->optind + 1) || help_flag) { + fprintf(help_flag ? stdout : stderr, "Usage: %s peer remove identity NODEID\n", cmdl->argv[0]); - return -EINVAL; + return help_flag ? 0 : -EINVAL; } str = shift_cmdl(cmdl);
@@ -89,23 +89,23 @@ static int cmd_peer_rm_nodeid(struct nlmsghdr *nlh, const struct cmd *cmd, return msg_doit(nlh, NULL, NULL); } -static void cmd_peer_rm_help(struct cmdl *cmdl) +static void cmd_peer_rm_help(FILE *out, struct cmdl *cmdl) { - fprintf(stderr, "Usage: %s peer remove PROPERTY\n\n" + fprintf(out, "Usage: %s peer remove PROPERTY\n\n" "PROPERTIES\n" " identity NODEID - Remove peer node identity\n", cmdl->argv[0]); } -static void cmd_peer_rm_addr_help(struct cmdl *cmdl) +static void cmd_peer_rm_addr_help(FILE *out, struct cmdl *cmdl) { - fprintf(stderr, "Usage: %s peer remove address ADDRESS\n", + fprintf(out, "Usage: %s peer remove address ADDRESS\n", cmdl->argv[0]); } -static void cmd_peer_rm_nodeid_help(struct cmdl *cmdl) +static void cmd_peer_rm_nodeid_help(FILE *out, struct cmdl *cmdl) { - fprintf(stderr, "Usage: %s peer remove identity NODEID\n", + fprintf(out, "Usage: %s peer remove identity NODEID\n", cmdl->argv[0]); }
@@ -121,9 +121,9 @@ static int cmd_peer_rm(struct nlmsghdr *nlh, const struct cmd *cmd, return run_cmd(nlh, cmd, cmds, cmdl, NULL); } -void cmd_peer_help(struct cmdl *cmdl) +void cmd_peer_help(FILE *out, struct cmdl *cmdl) { - fprintf(stderr, + fprintf(out, "Usage: %s peer COMMAND [ARGS] ...\n\n" "COMMANDS\n" " remove - Remove an offline peer node\n",
diff --git a/tipc/peer.h b/tipc/peer.h
index 2bd0a2a3..8a2374cf 100644
--- a/tipc/peer.h
+++ b/tipc/peer.h@@ -8,10 +8,10 @@ #ifndef _TIPC_PEER_H #define _TIPC_PEER_H -extern int help_flag; +#include <stdio.h> int cmd_peer(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl, void *data); -void cmd_peer_help(struct cmdl *cmdl); +void cmd_peer_help(FILE *out, struct cmdl *cmdl); #endif
diff --git a/tipc/socket.c b/tipc/socket.c
index 4d376e07..bf2147cb 100644
--- a/tipc/socket.c
+++ b/tipc/socket.c@@ -112,8 +112,8 @@ static int cmd_socket_list(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl, void *data) { if (help_flag) { - fprintf(stderr, "Usage: %s socket list\n", cmdl->argv[0]); - return -EINVAL; + fprintf(stdout, "Usage: %s socket list\n", cmdl->argv[0]); + return 0; } nlh = msg_init(TIPC_NL_SOCK_GET);
@@ -125,9 +125,9 @@ static int cmd_socket_list(struct nlmsghdr *nlh, const struct cmd *cmd, return msg_dumpit(nlh, sock_list_cb, NULL); } -void cmd_socket_help(struct cmdl *cmdl) +void cmd_socket_help(FILE *out, struct cmdl *cmdl) { - fprintf(stderr, + fprintf(out, "Usage: %s socket COMMAND\n\n" "Commands:\n" " list - List sockets (ports)\n",
diff --git a/tipc/socket.h b/tipc/socket.h
index c4341bb2..207b8666 100644
--- a/tipc/socket.h
+++ b/tipc/socket.h@@ -8,9 +8,9 @@ #ifndef _TIPC_SOCKET_H #define _TIPC_SOCKET_H -extern int help_flag; +#include <stdio.h> -void cmd_socket_help(struct cmdl *cmdl); +void cmd_socket_help(FILE *out, struct cmdl *cmdl); int cmd_socket(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl, void *data);
diff --git a/tipc/tipc.c b/tipc/tipc.c
index 56af052c..733acb50 100644
--- a/tipc/tipc.c
+++ b/tipc/tipc.c@@ -28,9 +28,9 @@ int help_flag; int json; struct mnlu_gen_socket tipc_nlg; -static void about(struct cmdl *cmdl) +static void about(FILE *out, struct cmdl *cmdl) { - fprintf(stderr, + fprintf(out, "Transparent Inter-Process Communication Protocol\n" "Usage: %s [OPTIONS] COMMAND [ARGS] ...\n" "\n"
@@ -111,20 +111,24 @@ int main(int argc, char *argv[]) cmdl.argc = argc; cmdl.argv = argv; - res = mnlu_gen_socket_open(&tipc_nlg, TIPC_GENL_V2_NAME, - TIPC_GENL_V2_VERSION); - if (res) { - fprintf(stderr, - "Unable to get TIPC nl family id (module loaded?)\n"); - return -1; + if (!help_flag) { + res = mnlu_gen_socket_open(&tipc_nlg, TIPC_GENL_V2_NAME, + TIPC_GENL_V2_VERSION); + if (res) { + fprintf(stderr, + "Unable to get TIPC nl family id (module loaded?)\n"); + return -1; + } } res = run_cmd(NULL, &cmd, cmds, &cmdl, &tipc_nlg); if (res != 0) { - mnlu_gen_socket_close(&tipc_nlg); - return -1; + if (!help_flag) + mnlu_gen_socket_close(&tipc_nlg); + return help_flag ? 0 : -1; } - mnlu_gen_socket_close(&tipc_nlg); + if (!help_flag) + mnlu_gen_socket_close(&tipc_nlg); return 0; }
diff --git a/vdpa/vdpa.c b/vdpa/vdpa.c
index e2b0a5b1..550443e6 100644
--- a/vdpa/vdpa.c
+++ b/vdpa/vdpa.c@@ -1051,9 +1051,9 @@ static int cmd_dev(struct vdpa *vdpa, int argc, char **argv) return -ENOENT; } -static void help(void) +static void help(FILE *out) { - fprintf(stderr, + fprintf(out, "Usage: vdpa [ OPTIONS ] OBJECT { COMMAND | help }\n" "where OBJECT := { mgmtdev | dev }\n" " OPTIONS := { -V[ersion] | -n[o-nice-names] | -j[son] | -p[retty] }\n");
@@ -1061,8 +1061,11 @@ static void help(void) static int vdpa_cmd(struct vdpa *vdpa, int argc, char **argv) { - if (!argc || matches(*argv, "help") == 0) { - help(); + if (!argc) { + help(stderr); + return -EINVAL; + } else if (matches(*argv, "help") == 0) { + help(stdout); return 0; } else if (matches(*argv, "mgmtdev") == 0) { return cmd_mgmtdev(vdpa, argc - 1, argv + 1);
@@ -1127,6 +1130,7 @@ int main(int argc, char **argv) { NULL, 0, NULL, 0 } }; struct vdpa *vdpa; + bool need_nl = true; int opt; int err; int ret;
@@ -1150,12 +1154,12 @@ int main(int argc, char **argv) pretty = true; break; case 'h': - help(); + help(stdout); ret = EXIT_SUCCESS; goto vdpa_free; default: fprintf(stderr, "Unknown option.\n"); - help(); + help(stderr); ret = EXIT_FAILURE; goto vdpa_free; }
@@ -1164,10 +1168,23 @@ int main(int argc, char **argv) argc -= optind; argv += optind; - err = vdpa_init(vdpa); - if (err) { - ret = EXIT_FAILURE; - goto vdpa_free; + if (argc > 0 && (strcmp(argv[0], "help") == 0 || + strcmp(argv[0], "-h") == 0 || + strcmp(argv[0], "--help") == 0)) + need_nl = false; + + if (argc > 1 && (strcmp(argv[1], "help") == 0 || + strcmp(argv[1], "-h") == 0 || + strcmp(argv[1], "--help") == 0)) + need_nl = false; + + + if (need_nl) { + err = vdpa_init(vdpa); + if (err) { + ret = EXIT_FAILURE; + goto vdpa_free; + } } err = vdpa_cmd(vdpa, argc, argv);
@@ -1179,7 +1196,8 @@ int main(int argc, char **argv) ret = EXIT_SUCCESS; vdpa_fini: - vdpa_fini(vdpa); + if (need_nl) + vdpa_fini(vdpa); vdpa_free: vdpa_free(vdpa); return ret;
--
2.54.0