]> git.ipfire.org Git - pakfire.git/commitdiff
log stream: Remove FILE handle
authorMichael Tremer <michael.tremer@ipfire.org>
Sat, 12 Oct 2024 16:12:29 +0000 (16:12 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Sat, 12 Oct 2024 16:12:29 +0000 (16:12 +0000)
This is being replaced by our own loop that splits the input by line.

Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/libpakfire/log_stream.c

index a8f20a675e6d6878a4c1d3928c8acfd74a954a06..760dcc1670326f267f8895b7415f7ac0cb9ca1b3 100644 (file)
@@ -33,8 +33,9 @@ struct pakfire_log_stream {
        // Pipe
        int pipe[2];
 
-       // FILE Handle
-       FILE* f;
+       // Buffer
+       char buffer[64 * 1024];
+       size_t buffered;
 
        // Event Source
        sd_event_source* event;
@@ -46,9 +47,7 @@ struct pakfire_log_stream {
 
 static void pakfire_log_stream_free(struct pakfire_log_stream* stream) {
        if (stream->event)
-               sd_event_source_unref(stream->event);
-       if (stream->f)
-               fclose(stream->f);
+               stream->event = sd_event_source_unref(stream->event);
 
        // Close the pipe
        if (stream->pipe[0] >= 0)
@@ -115,39 +114,83 @@ struct pakfire_log_stream* pakfire_log_stream_unref(struct pakfire_log_stream* s
        return NULL;
 }
 
+static int pakfire_log_stream_fill_buffer(struct pakfire_log_stream* stream, int fd) {
+       ssize_t bytes_read;
+
+       // Read into the buffer
+       bytes_read = read(fd, stream->buffer + stream->buffered, sizeof(stream->buffer) - stream->buffered);
+       if (bytes_read < 0)
+               return bytes_read;
+
+       stream->buffered += bytes_read;
+
+       return 0;
+}
+
+static int pakfire_log_stream_drain_buffer(struct pakfire_log_stream* stream) {
+       const char* eol = NULL;
+       size_t length;
+       int r;
+
+       // Log a message if we don't have a callback
+       if (!stream->callback) {
+               CTX_ERROR(stream->ctx, "Log stream has no callback set\n");
+               return -EINVAL;
+       }
+
+       for (;;) {
+               // Find the next line
+               eol = memchr(stream->buffer, '\n', stream->buffered);
+               if (!eol)
+                       return 0;
+
+               // Determine the length of the line
+               length = eol - stream->buffer + 1;
+
+               // Call the callback
+               r = stream->callback(stream, stream->buffer, length, stream->data);
+               if (r)
+                       return r;
+
+               memmove(stream->buffer, stream->buffer + length, stream->buffered - length);
+               stream->buffered -= length;
+       }
+}
+
 static int __pakfire_log_stream(sd_event_source* s, int fd, uint32_t events, void* data) {
        struct pakfire_log_stream* stream = data;
-
-       char* line = NULL;
-       size_t l = 0;
        int r = -EINVAL;
 
-       ssize_t bytes_read = 0;
-
-       // Read as many lines as possible
        if (events & EPOLLIN) {
                for (;;) {
-                       bytes_read = getline(&line, &l, stream->f);
-                       if (bytes_read < 0)
-                               break;
-
-                       // Log a message if we don't have a callback
-                       if (!stream->callback) {
-                               CTX_ERROR(stream->ctx, "Log stream has no callback set\n");
-                               continue;
+                       // Fill the buffer
+                       r = pakfire_log_stream_fill_buffer(stream, fd);
+                       if (r < 0) {
+                               switch (-r) {
+                                       case EAGAIN:
+                                               return 0;
+
+                                       default:
+                                               return r;
+                               }
                        }
 
-                       // Call the callback
-                       r = stream->callback(stream, line, bytes_read, stream->data);
-                       if (r)
+                       // Drain the buffer
+                       r = pakfire_log_stream_drain_buffer(stream);
+                       if (r < 0)
                                return r;
                }
        }
 
        // Handle if the child process has closed the file descriptor
        if (events & EPOLLHUP) {
-               close(stream->pipe[0]);
-               stream->pipe[0] = -1;
+               if (stream->event)
+                       stream->event = sd_event_source_unref(stream->event);
+
+               if (stream->pipe[0] >= 0) {
+                       close(stream->pipe[0]);
+                       stream->pipe[0] = -1;
+               }
        }
 
        return r;
@@ -173,13 +216,6 @@ int pakfire_log_stream_in_parent(struct pakfire_log_stream* stream, sd_event* lo
                return r;
        }
 
-       // Create a file handle for easy line buffering
-       stream->f = fdopen(stream->pipe[0], "r");
-       if (!stream->f) {
-               CTX_ERROR(stream->ctx, "Could not open a file handle: %m\n");
-               return -errno;
-       }
-
        return 0;
 }