github.com/ActiveState/cli@v0.0.0-20240508170324-6801f60cd051/internal/osutils/lockfile/pidlock_lin_mac.go (about) 1 //go:build linux || darwin 2 // +build linux darwin 3 4 package lockfile 5 6 import ( 7 "io" 8 "os" 9 "syscall" 10 11 "github.com/ActiveState/cli/internal/errs" 12 ) 13 14 // PidExists checks if a process with the given PID exists and is running 15 func PidExists(pid int) bool { 16 // this always returns a process on linux... 17 p, err := os.FindProcess(int(pid)) 18 if err != nil { 19 return false 20 } 21 // ... so we have to send it a fake signal 22 err = p.Signal(syscall.Signal(0)) 23 if err == nil { 24 // process exists on success 25 return true 26 } 27 if err.Error() == "os: process already finished" { 28 return false 29 } 30 errno, ok := err.(syscall.Errno) 31 if !ok { 32 return false 33 } 34 switch errno { 35 case syscall.ESRCH: // process does not exist if we get search failed error 36 return false 37 case syscall.EPERM: 38 return true // process exists if we do not have permissions to send signal 39 } 40 return false 41 } 42 43 // LockFile tries to acquire a read lock on the file f 44 func LockFile(f *os.File) error { 45 ft := &syscall.Flock_t{ 46 Whence: io.SeekStart, 47 Start: 0, 48 Len: 0, 49 Pid: int32(os.Getpid()), 50 Type: syscall.F_WRLCK, 51 } 52 53 err := syscall.FcntlFlock(f.Fd(), syscall.F_SETLK, ft) 54 if err != nil { 55 return errs.Wrap(err, "failed to lock file") 56 } 57 return nil 58 } 59 60 func LockRelease(f *os.File) error { 61 ft := &syscall.Flock_t{ 62 Whence: io.SeekStart, 63 Start: 0, 64 Len: 0, 65 Pid: int32(os.Getpid()), 66 Type: syscall.F_UNLCK, 67 } 68 69 return syscall.FcntlFlock(f.Fd(), syscall.F_SETLK, ft) 70 } 71 72 func (pl *PidLock) cleanLockFile(keep bool) error { 73 // On Linux we have to remove the file before removing the file lock to avoid race conditions. 74 if !keep { 75 err := os.Remove(pl.path) 76 if err != nil { 77 return errs.Wrap(err, "failed to remove lock file %s", pl.path) 78 } 79 } 80 err := LockRelease(pl.file) 81 if err != nil { 82 return errs.Wrap(err, "failed to release lock on lock file %s", pl.path) 83 } 84 err = pl.file.Close() 85 if err != nil { 86 return errs.Wrap(err, "failed to close lock file %s", pl.path) 87 } 88 return nil 89 }