diff --git a/defs.h b/defs.h index a942dbb..fd07f66 100755 --- a/defs.h +++ b/defs.h @@ -47,6 +47,7 @@ #include #include #include /* backtrace() */ +#include #ifndef ATTRIBUTE_UNUSED #define ATTRIBUTE_UNUSED __attribute__ ((__unused__)) @@ -977,6 +978,7 @@ extern struct machdep_table *machdep; #define FOREACH_F_FLAG (0x400000) #define FOREACH_x_FLAG (0x800000) #define FOREACH_d_FLAG (0x1000000) +#define FOREACH_REGEX (0x2000000) struct foreach_data { ulong flags; @@ -985,6 +987,7 @@ struct foreach_data { char *comm_array[MAX_FOREACH_COMMS]; ulong pid_array[MAX_FOREACH_PIDS]; ulong arg_array[MAX_FOREACH_ARGS]; + regex_t regex; char *reference; int keys; int pids; diff --git a/help.c b/help.c index f752283..d33b318 100755 --- a/help.c +++ b/help.c @@ -734,7 +734,10 @@ char *help_foreach[] = { " task_struct pointer.", " name perform the command(s) on all commands with this name. If the", " command name can be confused with a foreach command name, then", -" precede the name string with a \"\\\".", +" precede the name string with a \"\\\". If the process name is", +" enclosed within \"'\" characters, then the encompassed string is", +" a POSIX extended regular expression that will be used to match", +" thread names. Notice that 'name' can only be specified individually.", " user perform the command(s) on all user (non-kernel) threads.", " kernel perform the command(s) on all kernel threads.", " active perform the command(s) on the active thread on each CPU.\n", @@ -794,6 +797,17 @@ char *help_foreach[] = { " Display the open files for all tasks:\n", " %s> foreach files", " ...\n", +" Display the state of tasks whose name contains a match to \"event.*\":\n", +" %s> foreach 'event.*' task -R state", +" PID: 99 TASK: ffff8804750d5500 CPU: 0 COMMAND: \"events/0\"", +" state = 1,", +" ", +" PID: 100 TASK: ffff8804750d4ac0 CPU: 1 COMMAND: \"events/1\"", +" state = 1," +" ", +" PID: 101 TASK: ffff8804750d4080 CPU: 2 COMMAND: \"events/2\"", +" state = 1,", +" ...\n", NULL }; diff --git a/task.c b/task.c index fde86eb..bf0baa5 100755 --- a/task.c +++ b/task.c @@ -5021,6 +5021,9 @@ cmd_foreach(void) switch (str_to_context(args[optind], &value, &tc)) { case STR_PID: + if (fd->flags & FOREACH_REGEX) + error(FATAL, + "'name' can only be specified individually!\n"); if (p == MAX_FOREACH_PIDS) error(INFO, "too many pids specified!\n"); @@ -5033,6 +5036,9 @@ cmd_foreach(void) break; case STR_TASK: + if (fd->flags & FOREACH_REGEX) + error(FATAL, + "'name' can only be specified individually!\n"); if (t == MAX_FOREACH_TASKS) error(INFO, "too many tasks specified!\n"); @@ -5053,6 +5059,9 @@ cmd_foreach(void) * Select all kernel threads. */ if (STREQ(args[optind], "kernel")) { + if (fd->flags & FOREACH_REGEX) + error(FATAL, + "'name' can only be specified individually!\n"); if (fd->flags & FOREACH_USER) error(FATAL, "user and kernel are mutually exclusive!\n"); @@ -5065,6 +5074,9 @@ cmd_foreach(void) * Select only user threads. */ if (STREQ(args[optind], "user")) { + if (fd->flags & FOREACH_REGEX) + error(FATAL, + "'name' can only be specified individually!\n"); if (fd->flags & FOREACH_KERNEL) error(FATAL, "user and kernel are mutually exclusive!\n"); @@ -5077,6 +5089,9 @@ cmd_foreach(void) * Select only active tasks (dumpfile only) */ if (STREQ(args[optind], "active")) { + if (fd->flags & FOREACH_REGEX) + error(FATAL, + "'name' can only be specified individually!\n"); if (!DUMPFILE()) error(FATAL, "active option not allowed on live systems\n"); @@ -5086,12 +5101,34 @@ cmd_foreach(void) } /* + * Regular expression is exclosed within "'" character. + */ + if (args[optind][0] == '\'' && + args[optind][strlen(args[optind])-1] == '\'') { + if (fd->flags & FOREACH_REGEX || fd->flags & FOREACH_SPECIFIED || + fd->flags & FOREACH_KERNEL || fd->flags & FOREACH_USER || + fd->flags & FOREACH_ACTIVE) + error(FATAL, "'name' can only be specified individually!\n"); + + args[optind][strlen(args[optind])-1] = '\0'; + p1 = args[optind] + 1; + + if (regcomp(&fd->regex, p1, REG_EXTENDED|REG_NOSUB)) + error(FATAL, "invalid regular expression!\n"); + fd->flags |= FOREACH_REGEX; + optind++; + continue; + } + + /* * If it's a command name, prefixed or otherwise, take it. */ p1 = (args[optind][0] == '\\') ? &args[optind][1] : args[optind]; if (comm_exists(p1)) { + if (fd->flags & FOREACH_REGEX) + error(FATAL, "'name' can only be specified individually!\n"); if (c == MAX_FOREACH_COMMS) error(INFO, "too many commands specified!\n"); else { @@ -5335,6 +5372,10 @@ foreach(struct foreach_data *fd) if (STREQ(fd->comm_array[j], tc->comm)) doit = TRUE; } + else if (fd->flags & FOREACH_REGEX) { + if (regexec(&fd->regex, tc->comm, 0, NULL, 0) == 0) + doit = TRUE; + } else doit = TRUE;