//go:build linux package namespace import ( "fmt" "os" "path/filepath" "git.theodohertyfamily.com/wg-wrap/internal/paths" "golang.org/x/sys/unix" ) // AcquireProfileLock locks the profile to prevent concurrent startup races. func AcquireProfileLock(pm *paths.PathManager, profile string) (*os.File, error) { lockPath := filepath.Join(pm.RuntimeBaseDir(), "profiles", profile+".lock") if err := os.MkdirAll(filepath.Dir(lockPath), 0755); err != nil { return nil, fmt.Errorf("failed to create lock directory: %w", err) } file, err := os.OpenFile(lockPath, os.O_CREATE|os.O_RDWR, 0600) if err != nil { return nil, fmt.Errorf("failed to open lock file: %w", err) } if err := unix.Flock(int(file.Fd()), unix.LOCK_EX); err != nil { _ = file.Close() return nil, fmt.Errorf("failed to lock profile: %w", err) } return file, nil } // ReleaseProfileLock unlocks the profile. func ReleaseProfileLock(file *os.File) { if file != nil { _ = unix.Flock(int(file.Fd()), unix.LOCK_UN) _ = file.Close() } }