Add vault locking and a cross-platform build script

Commands that change the vault hold an exclusive lock on DIR/.lock and
readers hold a shared one, taken after the passphrase prompt. A blocked
process says it is waiting. Unix uses fcntl locks and Windows uses
LockFileEx, both released by the OS if the process dies. Plan 9 and
WebAssembly fall back to an exclusive lock file.

build.sh cross-compiles static binaries for every Go target that builds
without cgo (43 today, armv6 and armv7 for 32-bit ARM Linux) and writes
SHA256SUMS.
This commit is contained in:
Andy Dixon
2026-09-26 14:36:44 +01:00
parent be09659f8f
commit 5aa60d7bc7
10 changed files with 273 additions and 8 deletions
+37
View File
@@ -0,0 +1,37 @@
// Copyright 2026 The vault Authors.
// SPDX-License-Identifier: GPL-3.0-or-later
//go:build !unix && !windows
package main
import (
"errors"
"fmt"
"io/fs"
"os"
"time"
)
// acquireLock falls back to an exclusive lock file where the OS offers no
// file locks. Every lock is exclusive here.
// ponytail: a crash leaves the lock file behind; the error names it for manual removal.
func acquireLock(path string, _ bool, waiting func()) (func(), error) {
for i := 0; ; i++ {
f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0o600)
if err == nil {
f.Close()
return func() { os.Remove(path) }, nil
}
if !errors.Is(err, fs.ErrExist) {
return nil, err
}
if i == 0 {
waiting()
}
if i == 600 {
return nil, fmt.Errorf("vault still locked after a minute; if no other vault process is running, remove %s", path)
}
time.Sleep(100 * time.Millisecond)
}
}