38 lines
1.3 KiB
Go
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
|
|
}
|