Files
Privatae e4c9b69b46
ci / personal-data (push) Successful in 5s
ci / test (push) Successful in 3m4s
ci / fuzz (push) Successful in 3m45s
bastion 0.53.2
2026-10-20 04:42:14 +00:00

38 lines
1.3 KiB
Go

//go:build linux
package main
import (
"os"
"syscall"
"golang.org/x/sys/unix"
)
// stdinIsTerminal distinguishes a person at a shell from the service. It decides
// which way the machine lock waits: a human who typed `run` wants "already
// running" immediately, while the unit must BLOCK so a restart queues behind the
// dying primary instead of exiting and being restarted every two seconds — the
// crash-loop the lock exists to end.
//
// It is a real isatty (TCGETS), not a character-device test. os.ModeCharDevice —
// which the first draft used — is TRUE for /dev/null, and every installed daemon
// has stdin on /dev/null: the installed unit sets no StandardInput, so systemd's
// default (null) applies. The daemon therefore took the fail-fast branch in the
// only deployment shape that exists, and the blocking standby the design asks
// for was unreachable. Measured on 18 of 18 reachable boxes in one deployment.
func stdinIsTerminal() bool {
_, err := unix.IoctlGetTermios(int(os.Stdin.Fd()), unix.TCGETS)
return err == nil
}
// ownerUID reports the owning uid of a stat result. Used to refuse locking inside
// a runtime directory root does not own.
func ownerUID(fi os.FileInfo) (uint32, bool) {
st, ok := fi.Sys().(*syscall.Stat_t)
if !ok {
return 0, false
}
return st.Uid, true
}