diff options
Diffstat (limited to 'internal/namespace/lock_linux.go')
| -rw-r--r-- | internal/namespace/lock_linux.go | 40 |
1 files changed, 40 insertions, 0 deletions
diff --git a/internal/namespace/lock_linux.go b/internal/namespace/lock_linux.go new file mode 100644 index 0000000..8da98f6 --- /dev/null +++ b/internal/namespace/lock_linux.go @@ -0,0 +1,40 @@ +//go:build linux + +package namespace + +import ( + "fmt" + "os" + "path/filepath" + + "git.theodohertyfamily.com/tools/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() + } +} |
