fix: add procfile parsing for non-seekable files (#21507)
Ilya Mashchenko committed
Dec 28, 2025 at 21:39 UTC
68079befbf3a1f77becf0ef0ed46abe4dc4365b0
2 files changed
+26
-11
src/libnetdata/procfile/procfile.c
+25
-11
@@ -330,14 +330,29 @@ procfile *procfile_readall(procfile *ff) {
330
331
ff->len += r;
332
}
333
-
334
- // netdata_log_debug(D_PROCFILE, "Rewinding file '%s'", ff->filename);
335
- if(unlikely(lseek(ff->fd, 0, SEEK_SET) == -1)) {
336
- if(unlikely(!(ff->flags & PROCFILE_FLAG_NO_ERROR_ON_FILE_IO))) collector_error(PF_PREFIX ": Cannot rewind on file '%s'.", procfile_filename(ff));
337
- else if(unlikely(ff->flags & PROCFILE_FLAG_ERROR_ON_ERROR_LOG))
338
- netdata_log_error(PF_PREFIX ": Cannot rewind on file '%s'.", procfile_filename(ff));
339
- procfile_close(ff);
340
- return NULL;
333
+
334
+ if (unlikely(ff->flags & PROCFILE_FLAG_NONSEEKABLE)) {
335
+ char *fn = procfile_filename(ff);
336
+ ff = procfile_reopen(ff, fn, NULL, ff->flags);
337
+ if (unlikely(!ff))
338
+ return NULL;
339
+ } else if (unlikely(lseek(ff->fd, 0, SEEK_SET) == -1)) {
340
+ // Some procfs files (Ubuntu HWE 24.04 / kernel 6.14) may be non-seekable.
341
+ // In that case, "rewind" by reopening.
342
+ if (errno == ESPIPE || errno == EINVAL) {
343
+ ff->flags |= PROCFILE_FLAG_NONSEEKABLE;
344
+ char *fn = procfile_filename(ff);
345
+ ff = procfile_reopen(ff, fn, NULL, ff->flags);
346
+ if (unlikely(!ff))
347
+ return NULL;
348
+ } else {
349
+ if (unlikely(!(ff->flags & PROCFILE_FLAG_NO_ERROR_ON_FILE_IO)))
350
+ collector_error(PF_PREFIX ": Cannot rewind on file '%s'.", procfile_filename(ff));
351
+ else if (unlikely(ff->flags & PROCFILE_FLAG_ERROR_ON_ERROR_LOG))
352
+ netdata_log_error(PF_PREFIX ": Cannot rewind on file '%s'.", procfile_filename(ff));
353
+ procfile_close(ff);
354
+ return NULL;
355
+ }
356
}
357
358
procfile_lines_reset(ff->lines);
@@ -498,9 +513,8 @@ procfile *procfile_reopen(procfile *ff, const char *filename, const char *separa
513
}
514
ff->stats.opens++;
515
501
- // netdata_log_info("PROCFILE: opened '%s' on fd %d", filename, ff->fd);
502
-
503
- //strncpyz(ff->filename, filename, FILENAME_MAX);
516
+ // IMPORTANT: 'filename' parameter must not be used after this point
517
+ // as it may point to ff->filename which we're about to free
518
freez(ff->filename);
519
ff->filename = NULL;
520
ff->flags = flags;
src/libnetdata/procfile/procfile.h
+1
@@ -36,6 +36,7 @@ typedef struct {
36
#define PROCFILE_FLAG_DEFAULT 0x00000000 // To store inside `collector.log`
37
#define PROCFILE_FLAG_NO_ERROR_ON_FILE_IO 0x00000001 // Do not log anything
38
#define PROCFILE_FLAG_ERROR_ON_ERROR_LOG 0x00000002 // Store inside `error.log`
39
+#define PROCFILE_FLAG_NONSEEKABLE 0x00000004 // File doesn't support lseek(), reopen instead
40
41
typedef enum __attribute__ ((__packed__)) procfile_separator {
42
PF_CHAR_IS_SEPARATOR,