Summary
If a FIFO (named pipe) exists at <stats path>.tmp, the ingestor's stats writer blocks forever in os.OpenFile. Opening a FIFO for writing waits until a reader shows up. O_NOFOLLOW blocks symlinks but not FIFOs. The stats file then stops updating, and the writer goroutine never returns. This is pre-existing on master. It was found during the round-3 review of #141, outside that PR's delta.
Severity is low. Planting the FIFO needs write access to the directory that holds the stats file. In Docker that directory is private to the container.
Where
Not verified: the stop function waits on the writer goroutine (<-done), so shutdown probably hangs as well.
Proposed fix
- Open with
O_NONBLOCK added. On a FIFO without a reader this fails at once with ENXIO instead of blocking.
- After opening,
Fstat the file and refuse anything that is not a regular file, with a clear error.
- Optionally, remove a non-regular
.tmp with a log line, or just refuse and log (see the rate-limit follow-up for the owner error).
Acceptance criteria
Summary
If a FIFO (named pipe) exists at
<stats path>.tmp, the ingestor's stats writer blocks forever inos.OpenFile. Opening a FIFO for writing waits until a reader shows up.O_NOFOLLOWblocks symlinks but not FIFOs. The stats file then stops updating, and the writer goroutine never returns. This is pre-existing on master. It was found during the round-3 review of #141, outside that PR's delta.Severity is low. Planting the FIFO needs write access to the directory that holds the stats file. In Docker that directory is private to the container.
Where
727efca0:cmd/ingestor/stats_file.go:142,os.OpenFile(tmp, os.O_CREATE|os.O_WRONLY|os.O_TRUNC|oNoFollow, 0o600).3ff60504: the same call at line 143.Not verified: the stop function waits on the writer goroutine (
<-done), so shutdown probably hangs as well.Proposed fix
O_NONBLOCKadded. On a FIFO without a reader this fails at once withENXIOinstead of blocking.Fstatthe file and refuse anything that is not a regular file, with a clear error..tmpwith a log line, or just refuse and log (see the rate-limit follow-up for the owner error).Acceptance criteria
<path>.tmpand callwriteStatsAtomic. It returns an error within a short timeout instead of blocking..tmpstill works, including the owner check from fix(ingestor): assign explicit, collision-resistant MQTT client IDs #141 once that is merged.