[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