From 3c42574475a213e3e9c3b3e4a5733dfaac116e70 Mon Sep 17 00:00:00 2001 From: Michael Tremer Date: Sat, 22 Mar 2025 15:50:53 +0000 Subject: [PATCH] log streamer: Move line sanitization from PTY Signed-off-by: Michael Tremer --- src/pakfire/log_stream.c | 128 ++++++++++++++++++++++++++++++++++++++- src/pakfire/pty.c | 124 +------------------------------------ 2 files changed, 128 insertions(+), 124 deletions(-) diff --git a/src/pakfire/log_stream.c b/src/pakfire/log_stream.c index 485cd5dd..bbb8a5ad 100644 --- a/src/pakfire/log_stream.c +++ b/src/pakfire/log_stream.c @@ -19,6 +19,7 @@ #############################################################################*/ #include +#include #include #include @@ -26,6 +27,8 @@ #include #include +#define MAX_LINE_LENGTH 16384 + struct pakfire_log_stream { struct pakfire_ctx* ctx; int nrefs; @@ -111,6 +114,123 @@ struct pakfire_log_stream* pakfire_log_stream_unref(struct pakfire_log_stream* s return NULL; } + +#define pakfire_log_stream_sanitize_line(self, line, buffer, buffer_length) \ + __pakfire_log_stream_sanitize_line(self, line, sizeof(line), buffer, buffer_length) + +static int __pakfire_log_stream_sanitize_line(struct pakfire_log_stream* self, + char* line, ssize_t line_length, const char* buffer, ssize_t length) { + ssize_t i = 0; + int num; + + // The cursor position + int cursor = 0; + + while (i < length) { + switch (buffer[i]) { + // Escape + case '\x1b': + // Skip the escape character + i++; + + // CSI + if (i < length && buffer[i] == '[') { + i++; + + // Reset number + num = 0; + + // Parse the number + while (i < length) { + // Skip any ';' + if (buffer[i] == ';') { + i++; + continue; + + // Parse any digits + } else if (isdigit(buffer[i])) { + num = num * 10 + (buffer[i] - '0'); + i++; + continue; + } + + // Break on all other characters + break; + } + + // Parse the command + if (i < length) { + char command = buffer[i++]; + + switch (command) { + // Move the cursor to the left + case 'D': + cursor -= (num > 0) ? num : 1; + + // Don't go too far left + if (cursor < 0) + cursor = 0; + break; + + // Move the cursor to the right + case 'C': + cursor += (num > 0) ? num : 1; + + // Don't go too far right + if (cursor >= length) + cursor = length - 1; + break; + + // Move to a certain column + case 'G': + cursor = (num > 0) ? num - 1 : 0; + + // Don't go too far right + if (cursor >= length) + cursor = length - 1; + break; + + // Ignore any other sequences + default: + break; + } + } + } + break; + + // Backspace + case '\x08': + if (cursor > 0) { + cursor--; + + // Erase the previous character + line[cursor] = ' '; + } + i++; + break; + + // Carriage Return + case '\x0d': + // Erase everything up to the cursor + memset(line, '\0', cursor); + + cursor = 0; + i++; + break; + + // Normal characters + default: + if (cursor < line_length - 1) + line[cursor++] = buffer[i]; + i++; + break; + } + } + + // Return the length of the output + return cursor; +} + static int pakfire_log_stream_fill_buffer(struct pakfire_log_stream* stream, int fd) { ssize_t bytes_read; @@ -128,6 +248,7 @@ static int pakfire_log_stream_fill_buffer(struct pakfire_log_stream* stream, int } static int pakfire_log_stream_drain_buffer(struct pakfire_log_stream* stream) { + char line[MAX_LINE_LENGTH] = {}; const char* eol = NULL; size_t length; int r; @@ -152,8 +273,13 @@ static int pakfire_log_stream_drain_buffer(struct pakfire_log_stream* stream) { else length = stream->buffered; + // Sanitize the line + r = pakfire_log_stream_sanitize_line(stream, line, stream->buffer, length); + if (r < 0) + return r; + // Call the callback - r = stream->callback(stream, stream->buffer, length, stream->data); + r = stream->callback(stream, line, r, stream->data); if (r) return r; diff --git a/src/pakfire/pty.c b/src/pakfire/pty.c index 4f3c1ab9..9f665b32 100644 --- a/src/pakfire/pty.c +++ b/src/pakfire/pty.c @@ -400,134 +400,12 @@ static int pakfire_pty_fill_buffer(struct pakfire_pty* pty, int fd, struct pakfi return bytes_read; } -#define pakfire_pty_sanitize_line(pty, line, buffer, buffer_length) \ - __pakfire_pty_sanitize_line(pty, line, sizeof(line), buffer, buffer_length) - -static int __pakfire_pty_sanitize_line(struct pakfire_pty* self, - char* line, ssize_t line_length, const char* buffer, ssize_t length) { - ssize_t i = 0; - int num; - - // The cursor position - int cursor = 0; - - while (i < length) { - switch (buffer[i]) { - // Escape - case '\x1b': - // Skip the escape character - i++; - - // CSI - if (i < length && buffer[i] == '[') { - i++; - - // Reset number - num = 0; - - // Parse the number - while (i < length) { - // Skip any ';' - if (buffer[i] == ';') { - i++; - continue; - - // Parse any digits - } else if (isdigit(buffer[i])) { - num = num * 10 + (buffer[i] - '0'); - i++; - continue; - } - - // Break on all other characters - break; - } - - // Parse the command - if (i < length) { - char command = buffer[i++]; - - switch (command) { - // Move the cursor to the left - case 'D': - cursor -= (num > 0) ? num : 1; - - // Don't go too far left - if (cursor < 0) - cursor = 0; - break; - - // Move the cursor to the right - case 'C': - cursor += (num > 0) ? num : 1; - - // Don't go too far right - if (cursor >= length) - cursor = length - 1; - break; - - // Move to a certain column - case 'G': - cursor = (num > 0) ? num - 1 : 0; - - // Don't go too far right - if (cursor >= length) - cursor = length - 1; - break; - - // Ignore any other sequences - default: - break; - } - } - } - break; - - // Backspace - case '\x08': - if (cursor > 0) { - cursor--; - - // Erase the previous character - line[cursor] = ' '; - } - i++; - break; - - // Carriage Return - case '\x0d': - // Erase everything up to the cursor - memset(line, '\0', cursor); - - cursor = 0; - i++; - break; - - // Normal characters - default: - if (cursor < line_length - 1) - line[cursor++] = buffer[i]; - i++; - break; - } - } - - return 0; -} - static ssize_t pakfire_pty_send_line(struct pakfire_pty* self, struct pakfire_pty_stdio* stdio, const char* buffer, ssize_t length) { - char line[MAX_LINE_LENGTH] = {}; int r; - // Sanitize the line - r = pakfire_pty_sanitize_line(self, line, buffer, length); - if (r < 0) - return r; - // Call the callback - r = stdio->callbacks.stdout_callback(self->ctx, - stdio->callbacks.data, line, strlen(line)); + r = stdio->callbacks.stdout_callback(self->ctx, stdio->callbacks.data, buffer, length); if (r < 0) return r; -- 2.39.5