* [PATCH iproute2] ip: return correct status from help command
@ 2026-06-21 18:03 Rose Wright
2026-06-22 15:16 ` Stephen Hemminger
0 siblings, 1 reply; 4+ messages in thread
From: Rose Wright @ 2026-06-21 18:03 UTC (permalink / raw)
To: netdev; +Cc: stephen, Rose Wright
Currently, "ip help" or "ip -help" always returns an error code because usage() is used as a fall through on "ip" and defaults to stderr with -1.
This is a minor bug that breaks "ip help | grep" and other scripts that rely on standard exit codes. The fix is to pass the status code as a parameter into usage() and change stderr to stdout when needed.
Signed-off-by: Rose Wright <rosesophiewright@gmail.com>
---
ip/ip.c | 15 ++++++++-------
1 file changed, 8 insertions(+), 7 deletions(-)
diff --git a/ip/ip.c b/ip/ip.c
index e4b71bde..ee4595e8 100644
--- a/ip/ip.c
+++ b/ip/ip.c
@@ -52,11 +52,12 @@ const char *get_ip_lib_dir(void)
return lib_dir;
}
-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: ip [ OPTIONS ] OBJECT { COMMAND | help }\n"
" ip [ -force ] -batch filename\n"
"where OBJECT := { address | addrlabel | fou | help | ila | ioam | l2tp | link |\n"
@@ -72,12 +73,12 @@ static void usage(void)
" -o[neline] | -t[imestamp] | -ts[hort] | -b[atch] [filename] |\n"
" -rc[vbuf] [size] | -n[etns] name | -N[umeric] | -a[ll] |\n"
" -c[olor]}\n");
- exit(-1);
+ exit(status);
}
static int do_help(int argc, char **argv)
{
- usage();
+ usage(0);
return 0;
}
@@ -279,7 +280,7 @@ int main(int argc, char **argv)
rcvbuf = size;
} else if (matches_color(opt, &color)) {
} else if (matches(opt, "-help") == 0) {
- usage();
+ usage(0);
} else if (matches(opt, "-netns") == 0) {
NEXT_ARG();
if (netns_switch(argv[1]))
@@ -321,5 +322,5 @@ int main(int argc, char **argv)
return do_cmd(argv[1], argc-1, argv+1, true);
rtnl_close(&rth);
- usage();
+ usage(-1);
}
--
2.54.0
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH iproute2] ip: return correct status from help command
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 ` [PATCH v2] iproute2: return correct status from help commands across all utilities Rose Wright
0 siblings, 2 replies; 4+ messages in thread
From: Stephen Hemminger @ 2026-06-22 15:16 UTC (permalink / raw)
To: Rose Wright; +Cc: netdev
On Sun, 21 Jun 2026 18:03:11 +0000
Rose Wright <rosesophiewright@gmail.com> wrote:
> Currently, "ip help" or "ip -help" always returns an error code because usage() is used as a fall through on "ip" and defaults to stderr with -1.
>
> This is a minor bug that breaks "ip help | grep" and other scripts that rely on standard exit codes. The fix is to pass the status code as a parameter into usage() and change stderr to stdout when needed.
>
> Signed-off-by: Rose Wright <rosesophiewright@gmail.com>
> ---
This is the closest of the three submissions, but there are way more commands in iproute2
than just ip. Need to address all the commands. Looks like perfect trivial job for AI
coding tools. I am looking into it now.
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH iproute2] ip: return correct status from help command
2026-06-22 15:16 ` Stephen Hemminger
@ 2026-06-22 17:18 ` Rose
2026-06-23 1:14 ` [PATCH v2] iproute2: return correct status from help commands across all utilities Rose Wright
1 sibling, 0 replies; 4+ messages in thread
From: Rose @ 2026-06-22 17:18 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: netdev
Hi Stephen,
Thanks for the feedback. I'd love to finish this up. I can apply the
same fix to the other commands in iproute2 sometime after work, around
17:30 UTC today.
Thanks again,
Rose
On Mon, Jun 22, 2026 at 10:16 AM Stephen Hemminger
<stephen@networkplumber.org> wrote:
>
> On Sun, 21 Jun 2026 18:03:11 +0000
> Rose Wright <rosesophiewright@gmail.com> wrote:
>
> > Currently, "ip help" or "ip -help" always returns an error code because usage() is used as a fall through on "ip" and defaults to stderr with -1.
> >
> > This is a minor bug that breaks "ip help | grep" and other scripts that rely on standard exit codes. The fix is to pass the status code as a parameter into usage() and change stderr to stdout when needed.
> >
> > Signed-off-by: Rose Wright <rosesophiewright@gmail.com>
> > ---
>
> This is the closest of the three submissions, but there are way more commands in iproute2
> than just ip. Need to address all the commands. Looks like perfect trivial job for AI
> coding tools. I am looking into it now.
>
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH v2] iproute2: return correct status from help commands across all utilities
2026-06-22 15:16 ` Stephen Hemminger
2026-06-22 17:18 ` Rose
@ 2026-06-23 1:14 ` Rose Wright
1 sibling, 0 replies; 4+ messages in thread
From: Rose Wright @ 2026-06-23 1:14 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: netdev, Rose Wright
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
^ permalink raw reply related [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-06-23 1:17 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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 ` [PATCH v2] iproute2: return correct status from help commands across all utilities Rose Wright
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox