Skip to content

fix(agent): read /proc/uptime on linux instead of sysinfo(2) - #2180

Merged
henrygd merged 2 commits into
henrygd:mainfrom
alecrubin:uptime-proc-linux
Aug 18, 2026
Merged

henrygd merged 2 commits into
henrygd:mainfrom
alecrubin:uptime-proc-linux

Conversation

@alecrubin

Copy link
Copy Markdown
Contributor

Fixes #1948.

host.Uptime() is unix.Sysinfo() in gopsutil, and lxcfs can't intercept a syscall, so every LXC container reports the host's uptime. /proc/uptime is virtualized correctly, it just wasn't being read.

This reads /proc/uptime on linux and falls back to host.Uptime() if the file is missing or unparseable. Other platforms go through a stub that calls host.Uptime() exactly as before, so nothing changes off linux.

Built a small binary that calls both ways and ran it on my Proxmox 9 box (lxcfs 7.0.0-pve1), containers had been up about an hour:

=== PVE host
host.Uptime()  [sysinfo(2), current] :   268189 s
/proc/uptime   [this PR]             :   268188 s

=== inside CT 404
host.Uptime()  [sysinfo(2), current] :   268191 s
/proc/uptime   [this PR]             :     3880 s

=== inside CT 403
host.Uptime()  [sysinfo(2), current] :   268192 s
/proc/uptime   [this PR]             :     3886 s

Same on bare metal, correct in containers.

Tests cover the parse (typical, zero, no trailing newline, single field, large value) and the three fallback paths (missing file, empty file, unparseable). uptimeFilePath is a package var so the tests can point it at a fixture, same as mdraidSysfsRoot does.

Ran go build and go vet for both linux and darwin, and the tests in a golang:1.26 container.

gopsutil's host.Uptime() calls the sysinfo(2) syscall. Inside an LXC
container lxcfs virtualizes /proc/uptime but cannot intercept a
syscall, so every container reported the host's uptime.

Reads /proc/uptime on linux and falls back to host.Uptime() if the file
is missing or unparseable, so other platforms are unchanged.

Fixes henrygd#1948
@alecrubin
alecrubin requested a review from henrygd as a code owner August 3, 2026 19:25

@henrygd henrygd left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot, this looks like a good approach.

One change before merge: validate the parsed float before converting it. strconv.ParseFloat accepts NaN, infinities, and values beyond the uint64 range without returning an error, which can yield a huge bogus uptime instead of using the fallback.

seconds, err := strconv.ParseFloat(fields[0], 64)
if err != nil ||
	math.IsNaN(seconds) ||
	math.IsInf(seconds, 0) ||
	seconds < 0 ||
	seconds >= 1<<64 {
	return host.Uptime()
}
return uint64(seconds), nil

And if possible, please add tests covering NaN, +Inf, negative values, and an out-of-range value such as 1e20.

@alecrubin

Copy link
Copy Markdown
Contributor Author

Thanks a lot, this looks like a good approach.

One change before merge: validate the parsed float before converting it. strconv.ParseFloat accepts NaN, infinities, and values beyond the uint64 range without returning an error, which can yield a huge bogus uptime instead of using the fallback.

seconds, err := strconv.ParseFloat(fields[0], 64)
if err != nil ||
	math.IsNaN(seconds) ||
	math.IsInf(seconds, 0) ||
	seconds < 0 ||
	seconds >= 1<<64 {
	return host.Uptime()
}
return uint64(seconds), nil

And if possible, please add tests covering NaN, +Inf, negative values, and an out-of-range value such as 1e20.

Thanks for the review. Done in 666b6f6, took your validation as-is. Added fallback tests for NaN, +Inf, -Inf, a negative value, and 1e20. ParseFloat parses all of those without an error so each one hits its own guard instead of the err != nil path. Ran the tests in a golang:1.26 container, all passing.

@alecrubin
alecrubin requested a review from henrygd August 18, 2026 17:12

@henrygd henrygd left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perfect, thank you! Appreciate your work.

@henrygd
henrygd merged commit 68a3f89 into henrygd:main Aug 18, 2026
JuliusFreudenberger pushed a commit to JuliusFreudenberger/nix-config that referenced this pull request Sep 3, 2026
This PR contains the following updates:

| Package | Update | Change |
|---|---|---|
| [henrygd/beszel](https://github.com/henrygd/beszel) | minor | `0.18.8` → `0.19.0` |

---

> ⚠️ **Warning**
>
> Some dependencies could not be looked up. Check the [Dependency Dashboard](issues/12) for more information.

---

### Release Notes

<details>
<summary>henrygd/beszel (henrygd/beszel)</summary>

### [`v0.19.0`](https://github.com/henrygd/beszel/releases/tag/v0.19.0)

[Compare Source](henrygd/beszel@v0.18.8...v0.19.0)

:warning:  **Potential breaking change:** Agents now verify HTTPS certificates. If an agent connects to a hub using a self-signed or otherwise untrusted certificate, configure `CA_CERT_FILE` with the appropriate CA certificate or the connection will be rejected.

#### What's Changed

- Add ZFS pool and dataset monitoring ([#&#8203;2209](henrygd/beszel#2209))
- Add container health alerts with log excerpts in notifications ([#&#8203;2225](henrygd/beszel#2225))
- Add alerts for failed systemd services ([#&#8203;2173](henrygd/beszel#2173))
- Add alerts for CPU I/O wait and steal time ([#&#8203;2249](henrygd/beszel#2249))
- Add cumulative disk read and write totals to the Disk I/O sheet ([#&#8203;2179](henrygd/beszel#2179))
- Add Greek and Uzbek translations ([#&#8203;2034](henrygd/beszel#2034))
- Add custom root disk names and sort disks alphabetically ([#&#8203;2006](henrygd/beszel#2006))
- Improve alert security by enforcing system ownership and blocking additional internal notification URL ranges
- Improve ATA SMART warnings for critical attributes ([#&#8203;2275](henrygd/beszel#2275))
- Fix a hub crash caused by concurrent SSH client shutdown ([#&#8203;2277](henrygd/beszel#2277))
- Fix host CPU and memory totals when Docker runs in a VM on macOS or Windows ([#&#8203;2272](henrygd/beszel#2272))
- Fix multi-line `TOKEN_FILE` loading ([#&#8203;2276](henrygd/beszel#2276))
- Fix QNAP MD RAID arrays being incorrectly reported as failed ([#&#8203;2065](henrygd/beszel#2065))
- Fix Intel GPU power data disappearing between samples ([#&#8203;2256](henrygd/beszel#2256))
- Fix swap usage calculations to include cached swap ([#&#8203;2267](henrygd/beszel#2267))
- Fix agent payload failures caused by invalid UTF-8 in battery names ([#&#8203;2241](henrygd/beszel#2241))
- Fix uptime reporting inside Linux containers ([#&#8203;2180](henrygd/beszel#2180))
- Fix fan discovery on legacy hwmon devices ([#&#8203;2238](henrygd/beszel#2238))
- Fix CPU model detection on MIPS systems ([#&#8203;2138](henrygd/beszel#2138))
- Fix machine ID generation on FreeBSD and pfSense installations ([#&#8203;2274](henrygd/beszel#2274))
- Fix agent environment variable updates during reinstall ([#&#8203;2107](henrygd/beszel#2107))
- Fix the install script reporting the wrong listen address after upgrades ([#&#8203;2243](henrygd/beszel#2243))
- Fix load average precision on macOS, BSD, and Windows ([#&#8203;2245](henrygd/beszel#2245))
- Update the Go version and Go dependencies

#### New Contributors

- [@&#8203;IlyaMur](https://github.com/IlyaMur) made their first contribution in [#&#8203;2238](henrygd/beszel#2238)
- [@&#8203;alecrubin](https://github.com/alecrubin) made their first contribution in [#&#8203;2180](henrygd/beszel#2180)
- [@&#8203;toomore](https://github.com/toomore) made their first contribution in [#&#8203;2241](henrygd/beszel#2241)
- [@&#8203;mews-se](https://github.com/mews-se) made their first contribution in [#&#8203;2243](henrygd/beszel#2243)
- [@&#8203;justadityaraj](https://github.com/justadityaraj) made their first contribution in [#&#8203;2245](henrygd/beszel#2245)
- [@&#8203;wassupluke](https://github.com/wassupluke) made their first contribution in [#&#8203;2256](henrygd/beszel#2256)
- [@&#8203;ErkinjonYusupov](https://github.com/ErkinjonYusupov) made their first contribution in [#&#8203;2034](henrygd/beszel#2034)
- [@&#8203;snh](https://github.com/snh) made their first contribution in [#&#8203;2279](henrygd/beszel#2279)
- [@&#8203;spatiumstas](https://github.com/spatiumstas) made their first contribution in [#&#8203;2249](henrygd/beszel#2249)
- [@&#8203;martinstenrose](https://github.com/martinstenrose) made their first contribution in [#&#8203;2173](henrygd/beszel#2173)
- [@&#8203;mleczakm](https://github.com/mleczakm) made their first contribution in [#&#8203;2225](henrygd/beszel#2225)
- [@&#8203;santhiprakash](https://github.com/santhiprakash) made their first contribution in [#&#8203;2269](henrygd/beszel#2269)

**Full Changelog**: <henrygd/beszel@v0.18.8...v0.19.0>

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Mend Renovate](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4xNTAuMSIsInVwZGF0ZWRJblZlciI6IjQzLjE1MC4xIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Reviewed-on: https://git.jfreudenberger.de/JuliusFreudenberger/nix-config/pulls/43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: LXC Containers show uptime of host

2 participants