diff --git a/cmd/update.go b/cmd/update.go index ee9c41a..b5d4796 100644 --- a/cmd/update.go +++ b/cmd/update.go @@ -18,6 +18,10 @@ type Failure struct { } func Update(cmd *cobra.Command, args []string) { + lock, err := lib.AcquireLock() + if err != nil { + log.Fatalf("%v, is ublue-upd already running?", err) + } systemDriver, err := drv.GetSystemUpdateDriver() if err != nil { log.Fatalf("Failed to get system update driver") @@ -171,4 +175,5 @@ func Update(cmd *cobra.Command, args []string) { return } log.Printf("Updates Completed") + lib.ReleaseLock(lock) } diff --git a/lib/filelock.go b/lib/filelock.go index 34fe3cb..5bea876 100644 --- a/lib/filelock.go +++ b/lib/filelock.go @@ -1,11 +1,15 @@ package lib import ( + "fmt" "io" "os" "syscall" + "time" ) +const fileLockPath string = "/run/ublue-upd.lock" + func IsFileLocked(file *os.File) bool { lock := syscall.Flock_t{ Type: syscall.F_WRLCK, @@ -17,3 +21,35 @@ func IsFileLocked(file *os.File) bool { } return lock.Type != syscall.F_UNLCK } + +func AcquireLock() (*os.File, error) { + file, err := os.OpenFile(fileLockPath, os.O_RDONLY|os.O_CREATE|os.O_TRUNC, 0600) + if err != nil { + return nil, err + } + + timeout := 5.0 + startTime := time.Now() + var lockFile *os.File + + for time.Since(startTime).Seconds() < timeout { + err = syscall.Flock(int(file.Fd()), syscall.LOCK_EX|syscall.LOCK_NB) + if err == nil { + lockFile = file + break + } + + time.Sleep(1 * time.Second) + } + + if lockFile == nil { + file.Close() + return nil, fmt.Errorf("Could not acquire lock at %s", fileLockPath) + } + + return lockFile, nil +} + +func ReleaseLock(file *os.File) error { + return syscall.Close(int(file.Fd())) +}