summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/ktrace.h3
-rw-r--r--src/create.c38
-rw-r--r--src/enable.c44
-rw-r--r--src/help.c179
4 files changed, 180 insertions, 84 deletions
diff --git a/include/ktrace.h b/include/ktrace.h
index cb0d537..3319423 100644
--- a/include/ktrace.h
+++ b/include/ktrace.h
@@ -16,8 +16,11 @@ struct ktrace_commands {
const char *command;
const char *usage;
const char *help;
+ struct ktrace_commands *link;
};
+int ktrace_help(struct ccli *ccli, const char *arg1, const char *arg2);
+
int help_completion(struct ccli *ccli, const char *command,
const char *line, int word,
char *match, char ***list, void *data);
diff --git a/src/create.c b/src/create.c
index 1cd1236..7b11e8a 100644
--- a/src/create.c
+++ b/src/create.c
@@ -4,13 +4,6 @@
*/
#include "ktrace.h"
-
-static void create_usage(struct ccli *ccli)
-{
- ccli_printf(ccli, "usage: create <type> <type-command>\n"
- " <type> : kprobe, eprobe, synthetic_event\n");
-}
-
static int add_type_offset(struct ccli *ccli, char *p, char **pvar, char *line)
{
long long offset;
@@ -135,7 +128,7 @@ static int create_kprobe(struct ccli *ccli, void *data,
int i;
if (argc < 3) {
- ccli_printf(ccli, "# usage: create kprobe name function/address fields\n");
+ ktrace_help(ccli, "create", "kprobe");
return 0;
}
@@ -223,10 +216,8 @@ static int create_eprobe(struct ccli *ccli, void *data,
int ret;
int i;
- if (argc < 3) {
- ccli_printf(ccli, "# usage: create eprobe name system/event fields\n");
- return 0;
- }
+ if (argc < 3)
+ return ktrace_help(ccli, "create", "eprobe");
name = argv[0];
@@ -264,21 +255,6 @@ static int create_eprobe(struct ccli *ccli, void *data,
return 0;
}
-static int usage_synthetic(struct ccli *ccli)
-{
- ccli_printf(ccli, "# usage: create synthetic name system/event.field1[,field2,..] system2/event2.field1[,field2,..] field1=systemX/eventX.field[ field2=systemX/eventX.field ...]\n"
- "# Where the synthetic event is created when the fields of system/event\n"
- "# match system/event2 fields. Then add the fields of the synthetic event\n"
- "# on how they will map to the other fields.\n#\n"
- "# A synthetic event field may also equal timestamps:\n"
- "# start=system/event.TIMESTAMP\n"
- "# start=system/event.TIMESTAMP_USECS\n#\n"
- "# Or even a delta:\n"
- "# delta=system/event.TIMESTAMP-system2/event2.TIMESTAMP\n"
- );
- return 0;
-}
-
static char *check_ts(char *val)
{
if (strcmp(val, "TIMESTAMP") == 0)
@@ -425,7 +401,7 @@ static int create_synthetic(struct ccli *ccli, void *data,
int i;
if (argc < 4)
- return usage_synthetic(ccli);
+ return ktrace_help(ccli, "create", "synthetic");
name = argv[0];
@@ -523,10 +499,8 @@ free_fields:
int cmd_create(struct ccli *ccli, const char *command, const char *line,
void *data, int argc, char **argv)
{
- if (argc < 2) {
- create_usage(ccli);
- return 0;
- }
+ if (argc < 2)
+ return ktrace_help(ccli, "create", NULL);
if (strcmp(argv[1], "kprobe") == 0)
return create_kprobe(ccli, data, argc - 2, argv + 2);
diff --git a/src/enable.c b/src/enable.c
index f588f1a..d978bc4 100644
--- a/src/enable.c
+++ b/src/enable.c
@@ -4,18 +4,6 @@
*/
#include "ktrace.h"
-static void enable_usage(struct ccli *ccli)
-{
- ccli_printf(ccli, "usage: enable <type> <type-command>\n"
- " <type> : tracing, event\n");
-}
-
-static void disable_usage(struct ccli *ccli)
-{
- ccli_printf(ccli, "usage: disable <type> <type-command>\n"
- " <type> : tracing, event\n");
-}
-
static int enable_tracing(struct ccli *ccli, void *data,
int argc, char **argv)
{
@@ -79,10 +67,8 @@ static int enable_event(struct ccli *ccli, void *data,
{
char *file;
- if (argc < 1) {
- ccli_printf(ccli, "usage: enable event system/event\n");
- return 0;
- }
+ if (argc < 1)
+ return ktrace_help(ccli, "enable", "event");
file = get_event(ccli, data, argv[0]);
if (file)
@@ -96,10 +82,8 @@ static int disable_event(struct ccli *ccli, void *data,
{
char *file;
- if (argc < 1) {
- ccli_printf(ccli, "usage: enable event system/event\n");
- return 0;
- }
+ if (argc < 1)
+ return ktrace_help(ccli, "disable", "event");
file = get_event(ccli, data, argv[0]);
if (file)
@@ -111,10 +95,8 @@ static int disable_event(struct ccli *ccli, void *data,
int cmd_enable(struct ccli *ccli, const char *command, const char *line,
void *data, int argc, char **argv)
{
- if (argc < 2) {
- enable_usage(ccli);
- return 0;
- }
+ if (argc < 2)
+ return ktrace_help(ccli, "enable", NULL);
if (strcmp(argv[1], "tracing") == 0)
return enable_tracing(ccli, data, argc - 2, argv + 2);
@@ -122,18 +104,14 @@ int cmd_enable(struct ccli *ccli, const char *command, const char *line,
if (strcmp(argv[1], "event") == 0)
return enable_event(ccli, data, argc - 2, argv + 2);
- enable_usage(ccli);
-
- return 0;
+ return ktrace_help(ccli, "enable", NULL);
}
int cmd_disable(struct ccli *ccli, const char *command, const char *line,
void *data, int argc, char **argv)
{
- if (argc < 2) {
- disable_usage(ccli);
- return 0;
- }
+ if (argc < 2)
+ return ktrace_help(ccli, "disable", NULL);
if (strcmp(argv[1], "tracing") == 0)
return disable_tracing(ccli, data, argc - 2, argv + 2);
@@ -141,9 +119,7 @@ int cmd_disable(struct ccli *ccli, const char *command, const char *line,
if (strcmp(argv[1], "event") == 0)
return disable_event(ccli, data, argc - 2, argv + 2);
- enable_usage(ccli);
-
- return 0;
+ return ktrace_help(ccli, "disable", NULL);
}
static int disenable_event_completion(struct ccli *ccli, void *data,
diff --git a/src/help.c b/src/help.c
index 05ce439..0798088 100644
--- a/src/help.c
+++ b/src/help.c
@@ -4,6 +4,79 @@
*/
#include "ktrace.h"
+static struct ktrace_commands create_cmds[] =
+{
+ {
+ "kprobe",
+ "create kprobe name function/address fields",
+ "# Create a kprobe with 'name' at a function or an address given.\n"
+ "# followed by a set of fields."
+ },
+ {
+ "eprobe",
+ "create eprobe name system/event fields",
+ "# Create an event on top of another event.\n"
+ "# Where 'name' is the new event.\n"
+ "# 'system/event' is the event to attach to.\n"
+ "# Followed by the fields to display",
+ },
+ {
+ "synthetic",
+ "create synthetic name system/event.field1[,field2,..] system2/event2.field1[,field2,..] field1=systemX/eventX.field[ field2=systemX/eventX.field ...]",
+ "# Where the synthetic event is created when the fields of system/event\n"
+ "# match system/event2 fields. Then add the fields of the synthetic event\n"
+ "# on how they will map to the other fields.\n#\n"
+ "# A synthetic event field may also equal timestamps:\n"
+ "# start=system/event.TIMESTAMP\n"
+ "# start=system/event.TIMESTAMP_USECS\n#\n"
+ "# Or even a delta:\n"
+ "# delta=system/event.TIMESTAMP-system2/event2.TIMESTAMP"
+ },
+ {
+ NULL
+ }
+};
+
+static struct ktrace_commands enable_cmds[] =
+{
+ {
+ "tracing",
+ "enable tracing",
+ " Makes the ring buffer writable"
+ },
+ {
+ "event",
+ "enable event (all|system|system/event)",
+ " Enable an event.\n"
+ " Key word 'all' will enable all events\n"
+ " Specify just a system to enable all events within that system.\n"
+ " Specify system/event, with '/' to separate the two, to enable just one event."
+ },
+ {
+ NULL
+ }
+};
+
+static struct ktrace_commands disable_cmds[] =
+{
+ {
+ "tracing",
+ "disable tracing",
+ " Disable writing to the ring buffer"
+ },
+ {
+ "event",
+ "disable event (all|system|system/event)",
+ " Disable an event.\n"
+ " Key word 'all' will disable all events\n"
+ " Specify just a system to disable all events within that system.\n"
+ " Specify system/event, with '/' to separate the two, to disable just one event."
+ },
+ {
+ NULL
+ }
+};
+
static struct ktrace_commands ktrace_cmds[] =
{
{
@@ -12,29 +85,53 @@ static struct ktrace_commands ktrace_cmds[] =
" kprobe - to create a kernel probe event.\n"
" eprobe - to create an event on top of another event.\n"
" synthetic - to create a synthetic event",
+ .link = create_cmds
},
{
"enable",
"enable (tracing|event)",
" tracing - to enable tracing if it is stopped.\n"
- " event - to enable an event"
+ " event - to enable an event",
+ .link = enable_cmds
},
{
"disable",
"disable (tracing|event)",
" tracing - to disable tracing, just stops writing to the ring buffer.\n"
- " event - stop an event."
+ " event - stop an event.",
+ .link = disable_cmds
+ },
+ {
+ NULL
}
};
-int cmd_help(struct ccli *ccli, const char *command, const char *line,
- void *data, int argc, char **argv)
+static int help_cmd(struct ccli *ccli, const char *arg,
+ struct ktrace_commands *commands)
{
int l = 1;
int i;
- if (argc < 2) {
- for (i = 0; l > 0 && i < ARRAY_SIZE(ktrace_cmds); i++) {
+ for (i = 0; l > 0 && commands[i].command; i++) {
+ if (strcmp(arg, commands[i].command) == 0) {
+ l = ccli_page(ccli, l, "usage: %s\n",
+ commands[i].usage);
+ l = ccli_page(ccli, l, "%s\n",
+ commands[i].help);
+ return 0;
+ }
+ }
+ ccli_printf(ccli, "Command %s not found\n", arg);
+ return 0;
+}
+
+int ktrace_help(struct ccli *ccli, const char *arg1, const char *arg2)
+{
+ int l = 1;
+ int i;
+
+ if (!arg1) {
+ for (i = 0; l > 0 && ktrace_cmds[i].command; i++) {
if (i)
l = ccli_page(ccli, l, "\n");
l = ccli_page(ccli, l, "command: %s\n",
@@ -47,32 +144,78 @@ int cmd_help(struct ccli *ccli, const char *command, const char *line,
return 0;
}
- for (i = 0; l > 0 && i < ARRAY_SIZE(ktrace_cmds); i++) {
- if (strcmp(argv[1], ktrace_cmds[i].command) == 0) {
+ if (!arg2)
+ return help_cmd(ccli, arg1, ktrace_cmds);
+
+ for (i = 0; l > 0 && ktrace_cmds[i].command; i++) {
+ if (strcmp(arg1, ktrace_cmds[i].command) == 0) {
+ if (ktrace_cmds[i].link)
+ return help_cmd(ccli, arg2, ktrace_cmds[i].link);
l = ccli_page(ccli, l, "usage: %s\n",
- ktrace_cmds[i].usage);
+ ktrace_cmds[i].usage);
l = ccli_page(ccli, l, "%s\n",
- ktrace_cmds[i].help);
+ ktrace_cmds[i].help);
return 0;
}
+ ccli_printf(ccli, "Command %s not found\n", arg1);
}
+
return 0;
}
+int cmd_help(struct ccli *ccli, const char *command, const char *line,
+ void *data, int argc, char **argv)
+{
+ if (argc < 2)
+ return ktrace_help(ccli, NULL, NULL);
+
+ if (argc < 3)
+ return ktrace_help(ccli, argv[1], NULL);
+
+ return ktrace_help(ccli, argv[1], argv[2]);
+}
+
+static int help_complete(struct ccli *ccli, char ***list,
+ struct ktrace_commands *commands)
+{
+ int cnt = 0;
+ int ret = 0;
+ int i;
+
+ for (i = 0; ret >= 0 && commands[i].command; i++)
+ ret = ccli_list_add(ccli, list, &cnt, commands[i].command);
+
+ return ret;
+}
+
int help_completion(struct ccli *ccli, const char *command,
const char *line, int word,
char *match, char ***list, void *data)
{
- int cnt = 0;
+ char **argv;
int ret = 0;
+ int argc;
int i;
- if (word == 1) {
- for (i = 0; ret >= 0 && i < ARRAY_SIZE(ktrace_cmds); i++)
- ret = ccli_list_add(ccli, list, &cnt,
- ktrace_cmds[i].command);
- return ret;
+ if (word > 2)
+ return 0;
+
+ if (word == 1)
+ return help_complete(ccli, list, ktrace_cmds);
+
+ argc = ccli_line_parse(line, &argv);
+ if (argc < 1)
+ return 0;
+
+ ret = 0;
+ for (i = 0; argc > 1 && ktrace_cmds[i].command; i++) {
+ if (strcmp(argv[1], ktrace_cmds[i].command) == 0) {
+ if (!ktrace_cmds[i].link)
+ break;
+ ret = help_complete(ccli, list, ktrace_cmds[i].link);
+ break;
+ }
}
- return 0;
+ ccli_argv_free(argv);
+ return ret;
}
-