Files
gamertan 92a66db3df docs: publish Preview 19 dogfood evidence
Export the reviewed allowlisted snapshot from private source commit 05928cebd01b586cf9e9d4b8c8537a7605a6068c. This records the exact candidate, bounded capacity result, stateful migration scratch requirement, authenticated batch identity proof, and immediate live acceptance evidence.

AI-Assisted: OpenAI Codex
Signed-off-by: Cole Speelman <crspeelman@gmail.com>
2026-08-18 21:47:08 -04:00

78 lines
2.3 KiB
Go

// SPDX-License-Identifier: AGPL-3.0-only
package storage
import (
"errors"
"os"
"path/filepath"
"syscall"
)
type ProcessLock struct {
file *os.File
}
// AcquireProcessLock coordinates the long-running server and offline migration
// commands. Servers hold a shared lock; projection rebuilds require exclusive
// ownership and therefore cannot overlap a live server process.
func AcquireProcessLock(root string, exclusive bool) (*ProcessLock, error) {
if !filepath.IsAbs(root) || filepath.Clean(root) != root {
return nil, errors.New("process lock root must be absolute and clean")
}
if err := os.MkdirAll(root, 0o700); err != nil {
return nil, errors.New("create process lock root")
}
rootInfo, err := os.Lstat(root)
if err != nil || !rootInfo.IsDir() || rootInfo.Mode()&os.ModeSymlink != 0 || rootInfo.Mode().Perm()&0o077 != 0 {
return nil, errors.New("process lock root must be a private non-symlink directory")
}
path := filepath.Join(root, "process.lock")
fd, err := syscall.Open(path, syscall.O_RDWR|syscall.O_CREAT|syscall.O_CLOEXEC|syscall.O_NOFOLLOW, 0o600)
if err != nil {
return nil, errors.New("open process lock")
}
file := os.NewFile(uintptr(fd), path)
if file == nil {
_ = syscall.Close(fd)
return nil, errors.New("open process lock")
}
info, err := file.Stat()
if err != nil || !info.Mode().IsRegular() || info.Mode()&os.ModeSymlink != 0 {
_ = file.Close()
return nil, errors.New("process lock must be a regular non-symlink file")
}
stat, ok := info.Sys().(*syscall.Stat_t)
if !ok || stat.Nlink != 1 {
_ = file.Close()
return nil, errors.New("process lock must not have additional hard links")
}
operation := syscall.LOCK_SH | syscall.LOCK_NB
if exclusive {
operation = syscall.LOCK_EX | syscall.LOCK_NB
}
if err = syscall.Flock(fd, operation); err != nil {
_ = file.Close()
return nil, errors.New("Observatory data directory is active in another process")
}
if err = file.Chmod(0o600); err != nil {
_ = syscall.Flock(fd, syscall.LOCK_UN)
_ = file.Close()
return nil, errors.New("secure process lock")
}
return &ProcessLock{file: file}, nil
}
func (lock *ProcessLock) Close() error {
if lock == nil || lock.file == nil {
return nil
}
err := syscall.Flock(int(lock.file.Fd()), syscall.LOCK_UN)
closeErr := lock.file.Close()
lock.file = nil
if err != nil {
return err
}
return closeErr
}