Made the necessary changes. Kindly review. On Fri, Aug 12, 2011 at 2:17 AM, Mike Christie <micha...@cs.wisc.edu> wrote:
> I agree with Ulrich. > > On 08/11/2011 01:53 AM, Ulrich Windl wrote: > >>>> Vivek S <vivek...@gmail.com> schrieb am 10.08.2011 um 19:50 in > Nachricht > > <caapu5rp9mby1dednehsgrhhhygmvmnaku+dv4kjjkboe8uy...@mail.gmail.com>: > >> Hi Mike/Ulrich > >> > >> Attaching the updated patch based on your comments. > > > > Hi! > > > > Looks a lot better IMHO, but anyway a comment on style: > > > > + {"r", "Session ID to use. This is either a positive integer or a \ > > +sysfs path like /sys/devices/platform/hostH/sessionS/targetH:B:I"}, > > > > Since ANSI-C (many years now) you can concatenate strings using "string1" > "string2". In you case it may look nicer to avoid the backslash at the end > of the line and use double doublequotes instead. The other advantage is that > you can indent the continuation to align the first line quite nicely. > > > > Likewise, when printing a larger block of text that is one logical unit, > you might also use that. Consider the block starting with > > > > + printf("\nExample:\n\tTo login to a target\n"); > > + print_str("\t\t", > > + "iscsiadm -m node -T > iqn.2005-06.com.mydomain.openiscsi:test1 " > > + "-p 192.168.1.2:3260 -l"); > > > > You could use one printf() > > > > Side note: a better return value that "-1" for the error in get_cols() > might be "80", as you are not checking the error when using the return > value. > > > > + sprintf(fmt, "%s%c%c%d%c%c", tabs, '%', '.', idx, 's', > '\n'); > > + printf(fmt, str); > > > > I wonder whether this is the same as > > > > printf("%s%.*s\n", tabs, idx, str); > > > > On "find_last_space(&str[cols-1], (cols-1), 0);": > > > > "&str[cols-1]" is simply "str + cols - 1". It's also confusing that your > start_idx is larger than the end_idx in find_last_space(). Maybe using > strchr(), strrchr() or strtok(str, " \t") could help you also. > > > > For texts like: > > > > + printf("discoverydb\ndiscovery [DEPRECATED]\nnode\n" > > + "session\niface\nfw\nhost\n\n"); > > > > I'd prefer the formatting like this (if you like those newlines): > > printf("discoverydb\n" > > "discovery [DEPRECATED]\n" > > "node\n" > > "session\n" > > "iface\n" > > "fw\n" > > "host\n" > > "\n"); > > > > > > For the many > > + print_str("\t\t", > > > > I'd probably either > > #define HELP_INDENT "\t\" > > and use print_str(HELP_INDENT, > > > > or define a ``const char *help_indent = "\t\t";'' and use that. Also, it > seems your print_str() doesn't count your "tabs" correctly when considering > line breaks. A possible improvement would be to automatically scan for > leading whitespace (SPC, TAB) at the beginning of a string, and use that as > indentation if lines are wrapped. I have the impression that your > print_str() only truncates long lines, but doesn't actually wrap them. Ah, > sorry, I overlooked the recursion! > > > > For the long block starting at > > > > + printf("\nExample:\n"); > > + printf("\tTo discover a target\n"); > > + print_str("\t\t", > > + "iscsiadm -m discoverydb -t st -p 192.168.1.2:3260 -D"); > > + printf("\tTo discover and login\n"); > > + print_str("\t\t", > > + "iscsiadm -m discoverydb -t st -p 192.168.1.2:3260 -Dl"); > > + print_str("\t", > > + "To specify an interface during discovery and login"); > > + print_str("\t\t", > > + "iscsiadm -m discoverydb -t st -p 192.168.1.2:3260 -I eth0 > " > > + "-Dl"); > > > > I'd probably separate code and data like this > > > > const char *help_text[] = { > > "Example:", > > "\tTo discover a target", > > "\t\tiscsiadm -m discoverydb -t st -p 192.168.1.2:3260 -Dl", > > ..., > > NULL > > }; > > > > const char **txt; > > for (txt = help_text; *txt; ++txt) > > print_str(*txt); // new implementation! > > > > > > Regards, > > Ulrich > > > >> > >> I did not paste the patch contents as it was pretty long. > >> > >> On Tue, Aug 9, 2011 at 8:24 AM, Mike Christie <micha...@cs.wisc.edu> > wrote: > >> > >>> On 07/22/2011 12:09 PM, Vivek S wrote: > >>>> Changed the way iscsiadm displays usage help about its commands. > Rather > >>> than > >>>> simply displaying each possible mode along with its options on a > single > >>>> line, > >>>> the user can now ask help for each mode separately which describes the > >>>> various options and also provides some examples. > >>>> > >>> > >>> > >>>> + printf("\n"); > >>>> + switch (mode) > >>>> + { > >>>> + case MODE_DISCOVERYDB: > >>>> + printf("iscsiadm -m discoverydb [options...]\n\n"); > >>>> + options = CMD_LINE_OPTION_PORTAL | > CMD_LINE_OPTION_IFACE > >>> | > >>>> CMD_LINE_OPTION_OP \ > >>>> + > >>> > >>> Not sure if it is the mailer but just try to keep things around 80 > >>> columns in the code like the other code is doing unless it is a string > >>> and breaking it up makes it more difficult to read. > >>> > >>> For example if you hit 80 cols in the middle of a target name > >>> "iqn.2005-06.com.mydomain.openiscsi.test1" then I would not split that > >>> up into "iqn.2005-06.com.mydom" and "ain.openiscsi.test1" just to make > >>> it 80 cols. > >>> > >>> But, something like the above could be > >>> > >>> options = CMD_LINE_OPTION_PORTAL | CMD_LINE_OPTION_IFACE | \ > >>> CMD_LINE_OPTION_OP \ > >>> > > > > > > > > > > > > -- > You received this message because you are subscribed to the Google Groups > "open-iscsi" group. > To post to this group, send email to open-iscsi@googlegroups.com. > To unsubscribe from this group, send email to > open-iscsi+unsubscr...@googlegroups.com. > For more options, visit this group at > http://groups.google.com/group/open-iscsi?hl=en. > > -- You received this message because you are subscribed to the Google Groups "open-iscsi" group. To post to this group, send email to open-iscsi@googlegroups.com. To unsubscribe from this group, send email to open-iscsi+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/open-iscsi?hl=en.
From 2f6eb00a8fb0ba49ae01371d33c630005fd23123 Mon Sep 17 00:00:00 2001 From: Vivek Subbarao <vivek...@gmail.com> Date: Sun, 28 Aug 2011 15:12:43 +0530 Subject: [PATCH 1/1] iscsiadm help update Signed-off-by: Vivek Subbarao <vivek...@gmail.com> --- usr/Makefile | 2 +- usr/iscsiadm.c | 431 +++++++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 412 insertions(+), 21 deletions(-) diff --git a/usr/Makefile b/usr/Makefile index 3ee0cb4..43d4c54 100644 --- a/usr/Makefile +++ b/usr/Makefile @@ -59,7 +59,7 @@ iscsid: $(ISCSI_LIB_SRCS) $(INITIATOR_SRCS) $(DISCOVERY_SRCS) \ $(CC) $(CFLAGS) $^ -o $@ -L../utils/open-isns -lisns iscsiadm: $(ISCSI_LIB_SRCS) $(DISCOVERY_SRCS) iscsiadm.o session_mgmt.o - $(CC) $(CFLAGS) $^ -o $@ -L../utils/open-isns -lisns + $(CC) $(CFLAGS) $^ -o $@ -L../utils/open-isns -lisns -ltermcap iscsistart: $(ISCSI_LIB_SRCS) $(INITIATOR_SRCS) $(FW_BOOT_SRCS) \ iscsistart.o statics.o diff --git a/usr/iscsiadm.c b/usr/iscsiadm.c index 03b779e..6d805d2 100644 --- a/usr/iscsiadm.c +++ b/usr/iscsiadm.c @@ -28,6 +28,8 @@ #include <string.h> #include <signal.h> #include <sys/stat.h> +#include <sys/ioctl.h> +#include <termcap.h> #include "initiator.h" #include "discovery.h" @@ -77,6 +79,8 @@ enum iscsiadm_op { OP_APPLY_ALL = 0x40 }; +#define MAX_CMD_OPTIONS 22 + static struct option const long_options[] = { {"mode", required_argument, NULL, 'm'}, @@ -106,24 +110,411 @@ static struct option const long_options[] = }; static char *short_options = "RlDVhm:p:P:T:H:I:U:k:L:d:r:n:v:o:sSt:u"; -static void usage(int status) + +const char *generic_help[] = { + "Iscsiadm supports the following modes. " + "The user should enter atleast one of them. " + "For help about a particular mode, enter " + "'iscsiadm -m mode -h'.\n\n" + "discoverydb\n" + "discovery [DEPRECATED]\n" + "node\n" + "session\n" + "iface\n" + "fw\n" + "host\n" + "\n" + "NOTE: To kill iscsid, use 'iscsiadm -k priority' " + "with a priority of 0.\n\n" +}; + +/* + * String name for each mode. + */ +const char *mode_str[] = { + "discovery", + "discoverydb", + "node", + "session", + "host", + "iface", + "fw" +}; + +/* + * Examples for each mode. This should be in the same order + * as the modes decalred in the enum above. + */ +const char *examples[] = { + "\nExample:\n\n" + "To discover a target\n" + "iscsiadm -m discovery -t slp -p 192.168.1.1:3260 -D\n\n" + "To discover and login to a target\n" + "iscsiadm -m discovery -t slp -p 192.168.1.1:3260 -Dl\n\n" + "To specify an interface\n" + "iscsiadm -m discovery -t slp -p 192.168.1.1:3260 -I eth0\n" + , + + "\nExample:\n\n" + "To discover a target\n" + "iscsiadm -m discoverydb -t st -p 192.168.1.2:3260 -D\n\n" + "To discover and login\n" + "iscsiadm -m discoverydb -t st -p 192.168.1.2:3260 -Dl\n\n" + "To specify an interface during discovery and login\n" + "iscsiadm -m discoverydb -t st -p 192.168.1.2:3260 -I eth0 -Dl\n\n" + "To add or delete a record\n" + "iscsiadm -m discoverydb -t st -p 192.168.1.2:3260 -o new/delete\n\n" + "To update a record\n" + "iscsiadm -m discoverydb -t st -p 192.168.1.2:3260 -o " + "update -n discovery.startup -v manual\n\n" + "To display records from discovery database\n" + "iscsiadm -m discoverydb\n" + , + + "\nExample:\n\n" + "To login to a target\n" + "iscsiadm -m node -T iqn.2005-06.com.mydomain.openiscsi:test1 " + "-p 192.168.1.2:3260 -l\n\n" + "To login to all targets with node or connection startup type as " + "manual\n" + "iscsiadm -m node -L manual\n\n" + "To logout of all targets with node or connection startup type as " + "automatic\n" + "iscsiadm -m node -U automatic\n\n" + "To rescan the session passing through a target\n" + "iscsiadm -m node -T iqn.2005-06.com.mydomain.openiscsi.test1 -p" + "192.168.1.2:3260 -R\n\n" + "To display statistics about a session passing through a target\n" + "iscsiadm -m node -T iqn.2005-06.com.mydomain.openiscsi:test1 -p" + "192.168.1.2:3260 -s\n\n" + "To add a new node record\n" + "iscsiadm -m node -T iqn.2005-06.com.mydomain.openiscsi:test1 -p" + "192.168.1.2:3260 -o new\n" + , + + "\nExample:\n\n" + "To logout of a session\n" + "iscsiadm -m session -r 1 -u\n\n" + "To delete a session record\n" + "iscsiadm -m session -r 2 -o delete\n" + , + + "" + , + + "\nExample:\n\n" + "To add a iface record\n" + "iscsiadm -m iface -I eth1 -o new\n" + , + + "" + +}; + +/* + * Structure to hold all iscsiadm command line options and their description. + */ +struct option_help +{ + char *option; + const char *help_str; +}opt_help[] = { + {"p", "Portal in ip:port format. If only ip address is specified " + "then the value 3260 is assumed for the port."}, + {"T", "Iqn name of the target."}, + {"I", "Interface to use for the operation. This is the name of file " + "in /etc/iscsi/ifaces/ directory. Multiple interfaces can be " + "specified."}, + {"o", "One of the new, delete, update, show or nonpersistent " + "operations."}, + {"t", "Type of discovery. Sendtargets, slp, isns or fw."}, + {"n", "Name of the field to use in the update operation."}, + {"v", "Value to use for the specified field in the update " + "operation."}, + {"H", "SCSI host to use for the operation."}, + {"r", "Session ID to use. This is either a positive integer or a " + "sysfs path like /sys/devices/platform/hostH/sessionS/targetH:" + "B:I"}, + {"R", "Rescan all sessions if no SID is specified, else scan only " + "that session."}, + {"P", "Level of information output. 0 to display a single line and " + "1 to display detailed information in tree format."}, + {"D", "Discover targets."}, + {"l", "Login to the discovered or specified target."}, + {"L", "Login to all sessions with the specified node or connection " + "startup value or all session if all is passed."}, + {"u", "Logout of the specified node or session."}, + {"U", "Logout of all sessions with the specified node or connection " + "startup value or all sessions if all is passed."}, + {"s", "Display session statistics"}, + {"k", "Kill iscsid."}, + {"d", "Print debugging information. Valid values are 0 to 8."}, + {"S", "Show masked values during information display."}, + {"V", "Display iscsiadm version."}, + {"h", "Display this help."}, + {NULL, NULL} +}; + +/* + * Global defines for all iscsiadm command line options. + */ +#define CMD_LINE_OPTION_PORTAL 0 +#define CMD_LINE_OPTION_TGTNAME 1 +#define CMD_LINE_OPTION_IFACE 2 +#define CMD_LINE_OPTION_OP 3 +#define CMD_LINE_OPTION_TYPE 4 +#define CMD_LINE_OPTION_NAME 5 +#define CMD_LINE_OPTION_VALUE 6 +#define CMD_LINE_OPTION_HOST 7 +#define CMD_LINE_OPTION_SID 8 +#define CMD_LINE_OPTION_RESCAN 9 +#define CMD_LINE_OPTION_PRINT 10 +#define CMD_LINE_OPTION_DSCVR 11 +#define CMD_LINE_OPTION_LOGIN 12 +#define CMD_LINE_OPTION_LOGINALL 13 +#define CMD_LINE_OPTION_LOGOUT 14 +#define CMD_LINE_OPTION_LOGOUTALL 15 +#define CMD_LINE_OPTION_STATS 16 +#define CMD_LINE_OPTION_KILLISCSID 17 +#define CMD_LINE_OPTION_DEBUG 18 +#define CMD_LINE_OPTION_SHOW 19 +#define CMD_LINE_OPTION_VERSION 20 +#define CMD_LINE_OPTION_HELP 21 + + +/* + * Struture containing pointers to option_help structures describing all options + * for each mode supported by iscsiadm. + */ +struct mode_help +{ + struct option_help *op_h[MAX_CMD_OPTIONS]; +}m_help[] = { + { + { + /* + * Mode discovery + */ + &opt_help[CMD_LINE_OPTION_PORTAL], &opt_help[CMD_LINE_OPTION_IFACE], + &opt_help[CMD_LINE_OPTION_OP], &opt_help[CMD_LINE_OPTION_TYPE], + &opt_help[CMD_LINE_OPTION_PRINT], &opt_help[CMD_LINE_OPTION_DSCVR], + &opt_help[CMD_LINE_OPTION_LOGIN], &opt_help[CMD_LINE_OPTION_DEBUG], + &opt_help[CMD_LINE_OPTION_HELP], NULL + } + }, + + { + /* + * Mode discoverydb + */ + { + &opt_help[CMD_LINE_OPTION_PORTAL], &opt_help[CMD_LINE_OPTION_IFACE], + &opt_help[CMD_LINE_OPTION_OP], &opt_help[CMD_LINE_OPTION_TYPE], + &opt_help[CMD_LINE_OPTION_PRINT], &opt_help[CMD_LINE_OPTION_DSCVR], + &opt_help[CMD_LINE_OPTION_LOGIN], &opt_help[CMD_LINE_OPTION_DEBUG], + &opt_help[CMD_LINE_OPTION_HELP], &opt_help[CMD_LINE_OPTION_NAME], + &opt_help[CMD_LINE_OPTION_VALUE], NULL + } + }, + + { + /* + * Mode node + */ + { + &opt_help[CMD_LINE_OPTION_PORTAL], &opt_help[CMD_LINE_OPTION_IFACE], + &opt_help[CMD_LINE_OPTION_DEBUG], &opt_help[CMD_LINE_OPTION_LOGOUTALL], + &opt_help[CMD_LINE_OPTION_LOGIN], &opt_help[CMD_LINE_OPTION_LOGINALL], + &opt_help[CMD_LINE_OPTION_LOGOUT], &opt_help[CMD_LINE_OPTION_PRINT], + &opt_help[CMD_LINE_OPTION_TGTNAME], &opt_help[CMD_LINE_OPTION_SHOW], + &opt_help[CMD_LINE_OPTION_RESCAN], &opt_help[CMD_LINE_OPTION_STATS], + &opt_help[CMD_LINE_OPTION_HELP], &opt_help[CMD_LINE_OPTION_OP], + &opt_help[CMD_LINE_OPTION_NAME], &opt_help[CMD_LINE_OPTION_VALUE], NULL + } + }, + + { + /* + * Mode session + */ + { + &opt_help[CMD_LINE_OPTION_SID], &opt_help[CMD_LINE_OPTION_RESCAN], + &opt_help[CMD_LINE_OPTION_LOGOUT], &opt_help[CMD_LINE_OPTION_STATS], + &opt_help[CMD_LINE_OPTION_OP], &opt_help[CMD_LINE_OPTION_NAME], + &opt_help[CMD_LINE_OPTION_VALUE], &opt_help[CMD_LINE_OPTION_DEBUG], + &opt_help[CMD_LINE_OPTION_PRINT], &opt_help[CMD_LINE_OPTION_HELP], NULL + } + }, + + { + /* + * Mode host + */ + { + &opt_help[CMD_LINE_OPTION_IFACE], &opt_help[CMD_LINE_OPTION_OP], + &opt_help[CMD_LINE_OPTION_NAME], &opt_help[CMD_LINE_OPTION_VALUE], + &opt_help[CMD_LINE_OPTION_DEBUG], &opt_help[CMD_LINE_OPTION_PRINT], + &opt_help[CMD_LINE_OPTION_HELP], NULL + } + }, + + { + /* + * Mode iface + */ + { + &opt_help[CMD_LINE_OPTION_LOGIN], NULL + } + }, + + { + /* + * Mode fw + */ + { + &opt_help[CMD_LINE_OPTION_HOST], &opt_help[CMD_LINE_OPTION_PRINT], NULL + } + } +}; + + +/* + * Get terminal width or number of columns. + */ +int get_cols(void) +{ + struct winsize ws; + + if (ioctl(0,TIOCGWINSZ,&ws)!=0) + { + return 80; + } + return ws.ws_col; +} + + +/* + * Get width of the TAB character. + */ +int get_tab_width(void) +{ + char *buf = NULL; + int tab_width = 0, ret = 0; + char *term = getenv("TERM"); + + if (term == NULL) + return 8; + + ret = tgetent(buf, term); + if (ret == 0 || ret < 0) + return 8; + + tab_width = tgetnum("it"); + if (tab_width == -1) + { + /* + * Calling tgetent again frees the buffer + * allocated by it. + */ + tgetent(buf, term); + return 8; + } + + return tab_width; +} + +/* + * Print string to the terminal taking into account the terminal + * width. + */ +void print_str(const char *tabs, const char *str) +{ + int num_tabs = 0, print_len = 0; + char *temp_str = (char *)str; + char buf[1024] = {0}; + char *p = NULL, *q = NULL; + int max_cols = get_cols(); + int tab_width = get_tab_width(); + int str_len = 0, i = 0; + + /* + * End of string + */ + if (str[0] == 0) + return ; + + /* + * Find the first occurence of '\n' character in the string. + */ + p = strchr(str, '\n'); + if (p) + str_len = p - temp_str + 1; + else + str_len = strlen(str); + + /* + * Find the number of TAB characters in the string from the + * start to the occurence of the first '\n' character. + */ + for (i=0 ; i<str_len ; i++) + { + if (temp_str[i] == '\t') + num_tabs++; + } + + /* + * If the string length including the tab width in greater than + * max_cols, wrap text. + */ + if ( (str_len + (num_tabs * tab_width) - num_tabs) > max_cols ) + { + memcpy(buf, temp_str, max_cols); + q = strrchr(buf, ' '); + if (q) + print_len = q - buf + 1; + else + print_len = max_cols; + + printf("%s%.*s\n", tabs, print_len, temp_str); + } + else + { + print_len = str_len; + printf("%s%.*s", tabs, str_len, temp_str); + } + + print_str(tabs, temp_str+print_len); +} + +static void usage(int status, int mode) { - if (status != 0) - fprintf(stderr, "Try `%s --help' for more information.\n", - program_name); - else { - printf("\ -iscsiadm -m discoverydb [ -hV ] [ -d debug_level ] [-P printlevel] [ -t type -p ip:port -I ifaceN ... [ -Dl ] ] | [ [ -p ip:port -t type] \ -[ -o operation ] [ -n name ] [ -v value ] [ -lD ] ] \n\ -iscsiadm -m discovery [ -hV ] [ -d debug_level ] [-P printlevel] [ -t type -p ip:port -I ifaceN ... [ -l ] ] | [ [ -p ip:port ] [ -l | -D ] ] \n\ -iiscsiadm -m node [ -hV ] [ -d debug_level ] [ -P printlevel ] [ -L all,manual,automatic ] [ -U all,manual,automatic ] [ -S ] [ [ -T targetname -p ip:port -I ifaceN ] [ -l | -u | -R | -s] ] \ -[ [ -o operation ] [ -n name ] [ -v value ] ]\n\ -iscsiadm -m session [ -hV ] [ -d debug_level ] [ -P printlevel] [ -r sessionid | sysfsdir [ -R | -u | -s ] [ -o operation ] [ -n name ] [ -v value ] ]\n\ -iscsiadm -m iface [ -hV ] [ -d debug_level ] [ -P printlevel ] [ -I ifacename | -H hostno|MAC ] [ [ -o operation ] [ -n name ] [ -v value ] ]\n\ -iscsiadm -m fw [ -l ]\n\ -iscsiadm -m host [ -P printlevel ] [ -H hostno|MAC ]\n\ -iscsiadm -k priority\n"); + int i = 0; + + printf("\n"); + + if ((status != 0) || (mode == -1) || (mode > MODE_FW)) + { + print_str("", generic_help[0]); + } + else + { + printf( "iscsiadm -m %s [options...]\n\n" + "Options\tDescription\n" + "-------\t-----------\n", mode_str[mode]); + + for (i=0 ; m_help[mode].op_h[i] != 0 ; i++) + { + printf("%s", + m_help[mode].op_h[i]->option); + print_str("\t", + m_help[mode].op_h[i]->help_str); + printf("\n"); + } + + print_str("", examples[mode]); + printf("\nSEE MAN PAGE FOR MORE DETAILS\n\n"); } + exit(status); } @@ -377,7 +768,7 @@ logout_by_startup(char *mode) if (!mode || !(!strcmp(mode, "automatic") || !strcmp(mode, "all") || !strcmp(mode,"manual"))) { log_error("Invalid logoutall option %s.", mode); - usage(ISCSI_ERR_INVAL); + usage(ISCSI_ERR_INVAL, 0); return ISCSI_ERR_INVAL; } @@ -447,7 +838,7 @@ login_by_startup(char *mode) if (!mode || !(!strcmp(mode, "automatic") || !strcmp(mode, "all") || !strcmp(mode,"manual") || !strcmp(mode, "onboot"))) { log_error("Invalid loginall option %s.", mode); - usage(ISCSI_ERR_INVAL); + usage(ISCSI_ERR_INVAL, 0); return ISCSI_ERR_INVAL; } @@ -2223,7 +2614,7 @@ main(int argc, char **argv) ISCSI_VERSION_STR); return 0; case 'h': - usage(0); + usage(0, mode); } } @@ -2239,7 +2630,7 @@ main(int argc, char **argv) } if (mode < 0) - usage(ISCSI_ERR_INVAL); + usage(ISCSI_ERR_INVAL, 0); if (mode == MODE_FW) { if ((rc = verify_mode_params(argc, argv, "ml", 0))) { -- 1.7.4.1