From: Rose Wright <rosesophiewright@gmail.com>
To: Stephen Hemminger <stephen@networkplumber.org>
Cc: netdev@vger.kernel.org, Rose Wright <rosesophiewright@gmail.com>
Subject: [PATCH v2] iproute2: return correct status from help commands across all utilities
Date: Tue, 23 Jun 2026 01:14:54 +0000 [thread overview]
Message-ID: <20260623011454.214244-1-rosesophiewright@gmail.com> (raw)
In-Reply-To: <20260622081637.172a6bb8@phoenix.local>
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 <rosesophiewright@gmail.com>
---
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
prev parent reply other threads:[~2026-06-23 1:17 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-21 18:03 [PATCH iproute2] ip: return correct status from help command Rose Wright
2026-06-22 15:16 ` Stephen Hemminger
2026-06-22 17:18 ` Rose
2026-06-23 1:14 ` Rose Wright [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260623011454.214244-1-rosesophiewright@gmail.com \
--to=rosesophiewright@gmail.com \
--cc=netdev@vger.kernel.org \
--cc=stephen@networkplumber.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox