From db6aea7d3f2053a430c440fe513e197e286c6483 Mon Sep 17 00:00:00 2001 From: Sami Kerola Date: Sun, 2 Oct 2011 13:07:35 +0200 Subject: [PATCH] ps: new usage function Signed-off-by: Sami Kerola --- ps/common.h | 12 ++++- ps/help.c | 123 +++++++++++++++++++++++++++++++++++++++------------- ps/parser.c | 32 +++++++++++--- ps/ps.1 | 12 ++++- 4 files changed, 140 insertions(+), 39 deletions(-) diff --git a/ps/common.h b/ps/common.h index d7208a7c..a3c15783 100644 --- a/ps/common.h +++ b/ps/common.h @@ -25,6 +25,16 @@ /***************** GENERAL DEFINE ********************/ +/* usage output sections */ +enum { + USAGE_DEFAULT, + USAGE_ALL, + USAGE_SELECTION, + USAGE_LIST, + USAGE_OUTPUT, + USAGE_THREADS, + USAGE_MISC +}; /* selection list */ #define SEL_RUID 1 @@ -326,7 +336,7 @@ extern int want_this_proc(proc_t *buf); extern const char *select_bits_setup(void); /* help.c */ -extern const char *help_message; +extern void __attribute__ ((__noreturn__)) usage(FILE * out, int section); /* global.c */ extern void self_info(void); diff --git a/ps/help.c b/ps/help.c index 2f39a9da..48e547c9 100644 --- a/ps/help.c +++ b/ps/help.c @@ -9,37 +9,102 @@ * GNU Library General Public License for more details. */ -/* - * The help message must not become longer, because it must fit - * on an 80x24 screen _with_ the error message and command prompt. - */ - -const char *help_message = -"********* simple selection ********* ********* selection by list *********\n" -"-A all processes -C by command name\n" -"-N negate selection -G by real group ID (supports names)\n" -"-a all w/ tty except session leaders -U by real user ID (supports names)\n" -"-d all except session leaders -g by session OR by effective group name\n" -"-e all processes -p by process ID\n" -"T all processes on this terminal -s processes in the sessions given\n" -"a all w/ tty, including other users -t by tty\n" -"g OBSOLETE -- DO NOT USE -u by effective user ID (supports names)\n" -"r only running processes U processes for specified users\n" -"x processes w/o controlling ttys t by tty\n" -"*********** output format ********** *********** long options ***********\n" -"-o,o user-defined -f full --Group --User --pid --cols --ppid\n" -"-j,j job control s signal --group --user --sid --rows --info\n" -"-O,O preloaded -o v virtual memory --cumulative --format --deselect\n" -"-l,l long u user-oriented --sort --tty --forest --version\n" -"-F extra full X registers --heading --no-heading --context\n" -" ********* misc options *********\n" -"-V,V show version L list format codes f ASCII art forest\n" -"-m,m,-L,-T,H threads S children in sum -y change -l format\n" -"-M,Z security data c true command name -c scheduling class\n" -"-w,w wide output n numeric WCHAN,UID -H process hierarchy\n" -; +#include +#include +#include +#include "common.h" +void __attribute__ ((__noreturn__)) usage(FILE * out, int section) +{ + fprintf(out, + "\nUsage: %s [options]\n", program_invocation_short_name); + if (section == USAGE_SELECTION || section == USAGE_ALL) { + fprintf(out, + "\nSimple options:\n" + " -A all processes\n" + " -N, --deselect negate selection\n" + " -a all without tty and session leader\n" + " -d all except session leader\n" + " -e all processes\n" + " T all processes on this terminal\n" + " a all without tty, including other users\n" + " g obsolete, do not use\n" + " r only running processes\n" + " x processes without controlling ttys\n"); + } + if (section == USAGE_LIST || section == USAGE_ALL) { + fprintf(out, + "\nSelection by list:\n" + " -C command name\n" + " U, -u, --user effective user id or name\n" + " -U, --User real user id or name\n" + " -G, --Group real group id or name\n" + " -g, --group session or effective group name\n" + " -p, --pid process id\n" + " --ppid select by parent process id\n" + " -s, --sid session id\n" + " t, -t, --tty terminal\n" + "\n selection take csv list e.g. `-u root,nobody'\n"); + } + if (section == USAGE_OUTPUT || section == USAGE_ALL) { + fprintf(out, + "\nOutput formats:\n" + " o, -o, --format " + " user defined format\n" + " O preloaded -o allowing sorting\n" + " -O preloaded, with default columns, allowing sorting\n" + " -j jobs format\n" + " j BSD job control format\n" + " -l long format\n" + " l BSD long format\n" + " y do not show flags, show rrs in place addr (used with -l)\n" + " -f full-format\n" + " -F extra full\n" + " s signal format\n" + " v virtual memory\n" + " u user-oriented format\n" + " X register format\n" + " Z, -M security data (for SE Linux)\n" + " f, --forest ascii art process tree\n" + " -H show process hierarchy\n" + " --context display security context (for SE Linux)\n" + " --heading repeat header lines\n" + " --no-headers do not print header at all\n" + " --cols set screen width\n" + " --rows set screen height\n"); + } + if (section == USAGE_THREADS || section == USAGE_ALL) { + fprintf(out, + "\nShow threads:\n" + " H as if they where processes\n" + " -L possibly with LWP and NLWP columns\n" + " -T possibly with SPID column\n" + " m, -m after processes\n"); + } + if (section == USAGE_MISC || section == USAGE_ALL) { + fprintf(out, + "\nMisc options:\n" + " w, -w unlimited output width\n" + " L list format codes\n" + " c true command name\n" + " n display numeric uid and wchan\n" + " -y do not show flags, show rss (only with -l)\n" + " -c show scheduling class\n" + " --sort specify sort order, can be a csv list\n" + " S, --cumulative include some dead child process data\n" + " --info print debuggin information\n" + " V,-V, --version display version information and exit\n" + " --help \n" + " display help\n"); + } + if (section == USAGE_DEFAULT) + fprintf(out, + "\n Try `%s --help '\n" + " for more information.\n", program_invocation_short_name); + fprintf(out, "\nFor more information see ps(1).\n"); + exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS); +} /* Missing: * diff --git a/ps/parser.c b/ps/parser.c index 01233b72..08d3a4f2 100644 --- a/ps/parser.c +++ b/ps/parser.c @@ -162,6 +162,23 @@ found_it: return 0; } +static int parse_usage_section(const char *opt) +{ + if (!strcmp(opt, "s") || !strcmp(opt, "selection")) + return USAGE_SELECTION; + if (!strcmp(opt, "e") || !strcmp(opt, "list")) + return USAGE_LIST; + if (!strcmp(opt, "o") || !strcmp(opt, "output")) + return USAGE_OUTPUT; + if (!strcmp(opt, "t") || !strcmp(opt, "threads")) + return USAGE_THREADS; + if (!strcmp(opt, "m") || !strcmp(opt, "misc")) + return USAGE_MISC; + if (!strcmp(opt, "a") || !strcmp(opt, "all")) + return USAGE_ALL; + return USAGE_DEFAULT; +} + /* * Used to parse lists in a generic way. (function pointers) */ @@ -786,6 +803,7 @@ static const char *parse_gnu_option(void){ char buf[16]; gnu_table_struct findme = { buf, NULL}; gnu_table_struct *found; + int usage_section; static const gnu_table_struct gnu_table[] = { {"Group", &&case_Group}, /* rgid */ {"User", &&case_User}, /* ruid */ @@ -923,10 +941,12 @@ static const char *parse_gnu_option(void){ return NULL; case_help: trace("--help\n"); - exclusive("--help"); - fwrite(help_message,1,strlen(help_message),stdout); - exit(0); - return NULL; + arg = grab_gnu_arg(); + if(!arg) + usage_section = USAGE_DEFAULT; + else + usage_section = parse_usage_section(arg); + usage(stdout, usage_section); case_info: trace("--info\n"); exclusive("--info"); @@ -1256,7 +1276,5 @@ total_failure: reset_parser(); if(personality & PER_FORCE_BSD) fprintf(stderr, "ERROR: %s\n", err2); else fprintf(stderr, "ERROR: %s\n", err); - fwrite(help_message,1,strlen(help_message),stderr); - exit(1); - /* return 1; */ /* useless */ + usage(stderr, USAGE_DEFAULT); } diff --git a/ps/ps.1 b/ps/ps.1 index b84447b4..d807aee4 100644 --- a/ps/ps.1 +++ b/ps/ps.1 @@ -633,8 +633,16 @@ Show threads, possibly with SPID column. .SH "OTHER INFORMATION" .PD 0 -.opt \-\-help -Print a help message. +.opt \-\-help \ section +Print a help message. The section argument can be +.IR selection , +.IR list , +.IR output , +.IR threads , +.IR misc +or +.IR all . +Arguments can be shorthanded to first letter. .opt \-\-info Print debugging info.