[ofa-general] [PATCH] infiniband-diags: command line option processing framework
Sasha Khapyorsky
sashak at voltaire.com
Sun Jan 25 03:51:36 PST 2009
The main motivation of this is to unify infiniband-diags command line
options and tools usage. Also it simplifies programming and can remove
a lot of duplications. The usage message is also unified over all tools
and looks like:
Usage: ibaddr [options] [<lid|dr_path|guid>]
Options:
--gid_show, -g show gid address only
--lid_show, -l show lid range only
--Lid_show, -L show lid range (in decimal) only
--Ca, -C <ca> Ca name to use
--Port, -P <port> Ca port number to use
--Direct, -D use Direct address argument
--Guid, -G use GUID address argument
--timeout, -t <ms> timeout in ms
--sm_port, -s <lid> SM port lid
--errors, -e show send and receive errors
--verbose, -v increase verbosity level
--debug, -d raise debug level
--usage, -u usage message
--help, -h help message
--version, -V show version
Examples:
ibaddr # local port's address
ibaddr 32 # show lid range and gid of lid 32
ibaddr -G 0x8f1040023 # same but using guid address
ibaddr -l 32 # show lid range only
ibaddr -L 32 # show decimal lid range only
ibaddr -g 32 # show gid address only
Custom (per tool) option processing is also supported.
Signed-off-by: Sasha Khapyorsky <sashak at voltaire.com>
---
infiniband-diags/include/ibdiag_common.h | 28 +++-
infiniband-diags/src/ibdiag_common.c | 248 ++++++++++++++++++++++++++++++
2 files changed, 274 insertions(+), 2 deletions(-)
diff --git a/infiniband-diags/include/ibdiag_common.h b/infiniband-diags/include/ibdiag_common.h
index 0518579..4304826 100644
--- a/infiniband-diags/include/ibdiag_common.h
+++ b/infiniband-diags/include/ibdiag_common.h
@@ -35,18 +35,42 @@
#ifndef _IBDIAG_COMMON_H_
#define _IBDIAG_COMMON_H_
+#include <infiniband/mad.h>
+
extern int ibdebug;
+extern int ibverbose;
+extern char *ibd_ca;
+extern int ibd_ca_port;
+extern int ibd_dest_type;
+extern ib_portid_t *ibd_sm_id;
+extern int ibd_timeout;
/*========================================================*/
/* External interface */
/*========================================================*/
#undef DEBUG
-#define DEBUG if (ibdebug || verbose) IBWARN
-#define VERBOSE if (ibdebug || verbose > 1) IBWARN
+#define DEBUG if (ibdebug || ibverbose) IBWARN
+#define VERBOSE if (ibdebug || ibverbose > 1) IBWARN
#define IBERROR(fmt, args...) iberror(__FUNCTION__, fmt, ## args)
extern void iberror(const char *fn, char *msg, ...);
extern const char *get_build_version(void);
+struct ibdiag_opt {
+ const char *name;
+ char letter;
+ unsigned has_arg;
+ const char *arg_tmpl;
+ const char *description;
+};
+
+extern int ibdiag_process_opts(int argc, char * const argv[], void *context,
+ const char *exclude_common_str,
+ const struct ibdiag_opt custom_opts[],
+ int (*custom_handler)(void *cxt, int val, char *optarg),
+ const char *usage_args,
+ const char *usage_examples[]);
+extern void ibdiag_show_usage();
+
#endif /* _IBDIAG_COMMON_H_ */
diff --git a/infiniband-diags/src/ibdiag_common.c b/infiniband-diags/src/ibdiag_common.c
index 3a9d5c2..8dcec5e 100644
--- a/infiniband-diags/src/ibdiag_common.c
+++ b/infiniband-diags/src/ibdiag_common.c
@@ -46,11 +46,259 @@
#include <unistd.h>
#include <ctype.h>
#include <config.h>
+#include <getopt.h>
+#include <infiniband/umad.h>
+#include <infiniband/mad.h>
#include <ibdiag_common.h>
#include <ibdiag_version.h>
int ibdebug;
+int ibverbose;
+char *ibd_ca;
+int ibd_ca_port;
+int ibd_dest_type = IB_DEST_LID;
+ib_portid_t *ibd_sm_id;
+int ibd_timeout;
+
+static ib_portid_t sm_portid = {0};
+
+static const char *prog_name;
+static const char *prog_args;
+static const char **prog_examples;
+static struct option *long_opts;
+static const struct ibdiag_opt *opts_map[256];
+
+static void pretty_print(int start, int width, const char *str)
+{
+ int len = width - start;
+ const char *p, *e;
+
+ while (1) {
+ while(isspace(*str))
+ str++;
+ p = str;
+ do {
+ e = p + 1;
+ p = strchr(e, ' ');
+ } while (p && p - str < len);
+ if (!p) {
+ fprintf(stderr, "%s", str);
+ break;
+ }
+ if (e - str == 1)
+ e = p;
+ fprintf(stderr, "%.*s\n%*s", e - str, str, start, "");
+ str = e;
+ }
+}
+
+void ibdiag_show_usage()
+{
+ struct option *o = long_opts;
+ int n;
+
+ fprintf(stderr, "\nUsage: %s [options] %s\n\n", prog_name,
+ prog_args ? prog_args : "");
+
+ if (long_opts[0].name)
+ fprintf(stderr, "Options:\n");
+ for (o = long_opts; o->name; o++) {
+ const struct ibdiag_opt *io = opts_map[o->val];
+ n = fprintf(stderr, " --%s", io->name);
+ if (isprint(io->letter))
+ n += fprintf(stderr, ", -%c", io->letter);
+ if (io->has_arg)
+ n += fprintf(stderr, " %s",
+ io->arg_tmpl ? io->arg_tmpl : "<val>");
+ if (io->description && *io->description) {
+ n += fprintf(stderr, "%*s ", 24 - n > 0 ? 24 - n : 0, "");
+ pretty_print(n, 74, io->description);
+ }
+ fprintf(stderr, "\n");
+ }
+
+ if (prog_examples) {
+ const char **p;
+ fprintf(stderr, "\nExamples:\n");
+ for (p = prog_examples; *p && **p; p++)
+ fprintf(stderr, " %s %s\n", prog_name, *p);
+ }
+
+ fprintf(stderr, "\n");
+
+ exit(2);
+}
+
+static int process_opt(int ch, char *optarg)
+{
+ int val;
+
+ switch (ch) {
+ case 'h':
+ case 'u':
+ ibdiag_show_usage();
+ break;
+ case 'V':
+ fprintf(stderr, "%s %s\n", prog_name, get_build_version());
+ exit(2);
+ case 'e':
+ madrpc_show_errors(1);
+ break;
+ case 'v':
+ ibverbose++;
+ break;
+ case 'd':
+ ibdebug++;
+ madrpc_show_errors(1);
+ umad_debug(ibdebug - 1);
+ break;
+ case 'C':
+ ibd_ca = optarg;
+ break;
+ case 'P':
+ ibd_ca_port = strtoul(optarg, 0, 0);
+ break;
+ case 'D':
+ ibd_dest_type = IB_DEST_DRPATH;
+ break;
+ case 'L':
+ ibd_dest_type = IB_DEST_LID;
+ break;
+ case 'G':
+ ibd_dest_type = IB_DEST_GUID;
+ break;
+ case 't':
+ val = strtoul(optarg, 0, 0);
+ madrpc_set_timeout(val);
+ ibd_timeout = val;
+ break;
+ case 's':
+ if (ib_resolve_portid_str(&sm_portid, optarg, IB_DEST_LID, 0) < 0)
+ IBERROR("cannot resolve SM destination port %s", optarg);
+ ibd_sm_id = &sm_portid;
+ break;
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+static const struct ibdiag_opt common_opts[] = {
+ { "Ca", 'C', 1, "<ca>", "Ca name to use"},
+ { "Port", 'P', 1, "<port>", "Ca port number to use"},
+ { "Direct", 'D', 0, NULL, "use Direct address argument"},
+ { "Lid", 'L', 0, NULL, "use LID address argument"},
+ { "Guid", 'G', 0, NULL, "use GUID address argument"},
+ { "timeout", 't', 1, "<ms>", "timeout in ms"},
+ { "sm_port", 's', 1, "<lid>", "SM port lid" },
+ { "errors", 'e', 0, NULL, "show send and receive errors" },
+ { "verbose", 'v', 0, NULL, "increase verbosity level" },
+ { "debug", 'd', 0, NULL, "raise debug level" },
+ { "usage", 'u', 0, NULL, "usage message" },
+ { "help", 'h', 0, NULL, "help message" },
+ { "version", 'V', 0, NULL, "show version" },
+ {}
+};
+
+static void make_opt(struct option *l, const struct ibdiag_opt *o,
+ const struct ibdiag_opt *map[])
+{
+ l->name = o->name;
+ l->has_arg = o->has_arg;
+ l->flag = NULL;
+ l->val = o->letter;
+ if (!map[l->val])
+ map[l->val] = o;
+}
+
+static struct option *make_long_opts(const char *exclude_str,
+ const struct ibdiag_opt *custom_opts,
+ const struct ibdiag_opt *map[])
+{
+ struct option *long_opts, *l;
+ const struct ibdiag_opt *o;
+ unsigned n = 0;
+
+ if (custom_opts)
+ for (o = custom_opts; o->name; o++)
+ n++;
+
+ long_opts = malloc((sizeof(common_opts)/sizeof(common_opts[0]) + n) *
+ sizeof(*long_opts));
+ if (!long_opts)
+ return NULL;
+
+ l = long_opts;
+
+ if (custom_opts)
+ for (o = custom_opts; o->name; o++)
+ make_opt(l++, o, map);
+
+ for (o = common_opts; o->name; o++) {
+ if (exclude_str && strchr(exclude_str, o->letter))
+ continue;
+ make_opt(l++, o, map);
+ }
+
+ memset(l, 0, sizeof(*l));
+
+ return long_opts;
+}
+
+static void make_str_opts(const struct option *o, char *p, unsigned size)
+{
+ int i, n = 0;
+
+ for (n = 0; o->name && n + 2 + o->has_arg < size; o++) {
+ p[n++] = o->val;
+ for (i = 0; i < o->has_arg; i++)
+ p[n++] = ':';
+ }
+ p[n] = '\0';
+}
+
+int ibdiag_process_opts(int argc, char * const argv[], void *cxt,
+ const char *exclude_common_str,
+ const struct ibdiag_opt custom_opts[],
+ int (*custom_handler)(void *cxt, int val, char *optarg),
+ const char *usage_args, const char *usage_examples[])
+{
+ char str_opts[1024];
+ const struct ibdiag_opt *o;
+
+ memset(opts_map, 0, sizeof(opts_map));
+
+ prog_name = argv[0];
+ prog_args = usage_args;
+ prog_examples = usage_examples;
+
+ long_opts = make_long_opts(exclude_common_str, custom_opts, opts_map);
+ if (!long_opts)
+ return -1;
+
+ make_str_opts(long_opts, str_opts, sizeof(str_opts));
+
+ while (1) {
+ int ch = getopt_long(argc, argv, str_opts, long_opts, NULL);
+ if ( ch == -1 )
+ break;
+ o = opts_map[ch];
+ if (!o)
+ ibdiag_show_usage();
+ if (custom_handler) {
+ if (custom_handler(cxt, ch, optarg) &&
+ process_opt(ch, optarg))
+ ibdiag_show_usage();
+ } else if (process_opt(ch, optarg))
+ ibdiag_show_usage();
+ }
+
+ free(long_opts);
+
+ return 0;
+}
extern char *argv0;
--
1.6.0.4.766.g6fc4a
More information about the general
mailing list