//go:build linux package host import ( "fmt" "os" "path/filepath" "syscall" "github.com/carlosframework/platform/internal/safefile" ) // The apply's two kernel-level needs, on the platform it actually runs on: // opening a path under a user-owned tree without following one symlink, and // an advisory lock that fails rather than waits when another apply holds it. // // linux, not unix: syscall.Openat is not in the stdlib syscall package on // darwin, and internal/host is linked into the CLI that people run on Macs. // The apply is a root oneshot on a Linux box and nothing else, so every // other OS gets systemapply_other.go's refusals and merely has to build. // openBeneath refuses symlinks in root and its descendants. The leaf is // pinned and checked as a single-link regular file before opening it for // I/O, so a planted device or FIFO is never opened for reading. func openBeneath(root string, parts ...string) (*os.File, error) { for _, part := range parts { if !filepath.IsLocal(part) { return nil, fmt.Errorf("open %s: path escapes directory", root) } } return safefile.OpenFile(filepath.Join(append([]string{root}, parts...)...), os.O_RDONLY, 0) } // flockExclusiveNonblock refuses when another apply holds the lock, so a // path-unit-triggered run exits quietly instead of queueing. It is the ONLY // way this package takes the apply lock: --recover wants it too, and wants // it enough to poll for half a minute, but never enough to block — see // systemApplier.waitForLock for the deadlock that buys. func flockExclusiveNonblock(f *os.File) error { return syscall.Flock(int(f.Fd()), syscall.LOCK_EX|syscall.LOCK_NB) }