diff --git a/headers/private/kernel/debug.h b/headers/private/kernel/debug.h index 2250c94e33..8885ceb485 100644 --- a/headers/private/kernel/debug.h +++ b/headers/private/kernel/debug.h @@ -48,7 +48,8 @@ #endif // command return value -#define B_KDEBUG_ERROR 4 +#define B_KDEBUG_ERROR 4 +#define B_KDEBUG_RESTART_PIPE 5 // command flags #define B_KDEBUG_DONT_PARSE_ARGUMENTS (0x01) diff --git a/src/system/kernel/debug/debug_builtin_commands.cpp b/src/system/kernel/debug/debug_builtin_commands.cpp index 04d615c90a..4d36b8650a 100644 --- a/src/system/kernel/debug/debug_builtin_commands.cpp +++ b/src/system/kernel/debug/debug_builtin_commands.cpp @@ -148,6 +148,59 @@ cmd_head(int argc, char** argv) } +static int +cmd_tail(int argc, char** argv) +{ + debugger_command_pipe_segment* segment + = get_current_debugger_command_pipe_segment(); + if (segment == NULL) { + kprintf_unfiltered("%s can only be run as part of a pipe!\n", argv[0]); + return B_KDEBUG_ERROR; + } + + struct user_data { + uint64 max_lines; + int64 line_count; + bool restarted; + }; + user_data* userData = (user_data*)segment->user_data; + + if (segment->invocations == 0) { + if (argc > 3) { + print_debugger_command_usage(argv[0]); + return B_KDEBUG_ERROR; + } + + userData->max_lines = 10; + if (argc > 2 && !evaluate_debug_expression(argv[1], + &userData->max_lines, false)) { + return B_KDEBUG_ERROR; + } + + userData->line_count = 1; + userData->restarted = false; + } else if (!userData->restarted) { + if (argv[argc - 1] == NULL) { + userData->restarted = true; + userData->line_count -= userData->max_lines; + return B_KDEBUG_RESTART_PIPE; + } + + ++userData->line_count; + } else { + if (argv[argc - 1] == NULL) + return 0; + + if (--userData->line_count < 0) { + kputs(argv[argc - 1]); + kputs("\n"); + } + } + + return 0; +} + + static int cmd_grep(int argc, char** argv) { @@ -300,6 +353,13 @@ debug_builtin_commands_init() "Should be used in a command pipe. It prints only the first\n" " lines of output from the previous command in the pipe and\n" "silently discards the rest of the output.\n", 0); + add_debugger_command_etc("tail", &cmd_tail, + "Prints only the last lines of output from another command", + "[ ]\n" + "Should be used in a command pipe. It prints only the last\n" + " (default 10) lines of output from the previous command in\n" + "the pipe and silently discards the rest of the output.\n", + B_KDEBUG_PIPE_FINAL_RERUN); add_debugger_command_etc("grep", &cmd_grep, "Filters output from another command", "[ -i ] [ -v ] \n" diff --git a/src/system/kernel/debug/debug_commands.cpp b/src/system/kernel/debug/debug_commands.cpp index 469f5f6199..b8778a53ed 100644 --- a/src/system/kernel/debug/debug_commands.cpp +++ b/src/system/kernel/debug/debug_commands.cpp @@ -351,13 +351,25 @@ invoke_debugger_command_pipe(debugger_command_pipe* pipe) sOutputBuffers[i], kOutputBufferSize); } - int result = invoke_pipe_segment(pipe, 0, NULL); + int result; + while (true) { + result = invoke_pipe_segment(pipe, 0, NULL); - // perform final rerun for all commands that want it - for (int32 i = 1; result != B_KDEBUG_ERROR && i < segments; i++) { - debugger_command_pipe_segment& segment = pipe->segments[i]; - if ((segment.command->flags & B_KDEBUG_PIPE_FINAL_RERUN) != 0) - result = invoke_pipe_segment(pipe, i, NULL); + // perform final rerun for all commands that want it + for (int32 i = 1; result != B_KDEBUG_ERROR && i < segments; i++) { + debugger_command_pipe_segment& segment = pipe->segments[i]; + if ((segment.command->flags & B_KDEBUG_PIPE_FINAL_RERUN) != 0) { + result = invoke_pipe_segment(pipe, i, NULL); + if (result == B_KDEBUG_RESTART_PIPE) { + for (int32 j = 0; j < i; j++) + pipe->segments[j].invocations = 0; + break; + } + } + } + + if (result != B_KDEBUG_RESTART_PIPE) + break; } sCurrentPipe = oldPipe;