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 <[email protected]> --- 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 _______________________________________________ general mailing list [email protected] http://lists.openfabrics.org/cgi-bin/mailman/listinfo/general To unsubscribe, please visit http://openib.org/mailman/listinfo/openib-general
