Ensure only a single instance of after-lock runs at a time
This commit is contained in:
		@@ -2,19 +2,50 @@ package main
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"after-lock/afterlock"
 | 
						"after-lock/afterlock"
 | 
				
			||||||
 | 
						"after-lock/lockfile"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"runtime/debug"
 | 
				
			||||||
 | 
						"os"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
	initialDelay = 3
 | 
						initialDelay = 3
 | 
				
			||||||
	loopDelay = 6
 | 
						loopDelay = 6
 | 
				
			||||||
	keyboardDeviceNode = "/dev/input/by-id/usb-Dell_Dell_USB_Entry_Keyboard-event-kbd"
 | 
						keyboardDeviceNode = "/dev/input/by-id/usb-Dell_Dell_USB_Entry_Keyboard-event-kbd"
 | 
				
			||||||
 | 
						lockfilePath = "/tmp/after-lock.lock"
 | 
				
			||||||
 | 
						printStackTraces = false
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func main() {
 | 
					func main() {
 | 
				
			||||||
 | 
						defer handleErrors()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						lock := grabExclusiveProcessLock()
 | 
				
			||||||
 | 
						defer lock.Unlock()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	al := afterlock.New(keyboardDeviceNode)
 | 
						al := afterlock.New(keyboardDeviceNode)
 | 
				
			||||||
	al.InitialDelay = initialDelay
 | 
						al.InitialDelay = initialDelay
 | 
				
			||||||
	al.LoopDelay = loopDelay
 | 
						al.LoopDelay = loopDelay
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	al.Start()
 | 
						al.Start()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func handleErrors() {
 | 
				
			||||||
 | 
						if err := recover(); err != nil {
 | 
				
			||||||
 | 
							fmt.Printf("Crashed with unexpected error: %v!\n", err)
 | 
				
			||||||
 | 
							if printStackTraces {
 | 
				
			||||||
 | 
								fmt.Printf("Stack trace:\n\n")
 | 
				
			||||||
 | 
								debug.PrintStack()
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							os.Exit(1)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func grabExclusiveProcessLock() *lockfile.Lockfile {
 | 
				
			||||||
 | 
						lf := lockfile.New(lockfilePath)
 | 
				
			||||||
 | 
						err := lf.Lock()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							panic(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return lf
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										49
									
								
								lockfile/lockfile.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								lockfile/lockfile.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,49 @@
 | 
				
			|||||||
 | 
					package lockfile
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
 | 
						"os"
 | 
				
			||||||
 | 
						"syscall"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Lockfile struct {
 | 
				
			||||||
 | 
						path string
 | 
				
			||||||
 | 
						fd int
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func New(path string) *Lockfile {
 | 
				
			||||||
 | 
						return &Lockfile{path: path}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (lf *Lockfile) Lock() error {
 | 
				
			||||||
 | 
						fd, err := syscall.Open(lf.path, syscall.O_CREAT | syscall.O_RDWR, 0600)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						lf.fd = fd
 | 
				
			||||||
 | 
						err = syscall.Flock(lf.fd, syscall.LOCK_EX | syscall.LOCK_NB)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (lf *Lockfile) Unlock() error {
 | 
				
			||||||
 | 
						if lf.fd == 0 {
 | 
				
			||||||
 | 
							panic(errors.New("Lockfile was not locked"))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						err := syscall.Flock(lf.fd, syscall.LOCK_UN)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						err = syscall.Close(lf.fd)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						os.Remove(lf.path)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										71
									
								
								lockfile/lockfile_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								lockfile/lockfile_test.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,71 @@
 | 
				
			|||||||
 | 
					package lockfile_test
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"io/ioutil"
 | 
				
			||||||
 | 
						"os"
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"after-lock/lockfile"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func tmpFile() string {
 | 
				
			||||||
 | 
						tf, err := ioutil.TempFile("", "lockfile_test*")
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							panic(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return tf.Name()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestNotLockedUnlockPanics(t *testing.T) {
 | 
				
			||||||
 | 
						defer func() {
 | 
				
			||||||
 | 
					        if r := recover(); r == nil {
 | 
				
			||||||
 | 
					            t.Errorf("Unlock() did not panic")
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tf := tmpFile()
 | 
				
			||||||
 | 
						defer os.Remove(tf)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err := lockfile.New(tf).Unlock()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							panic(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestSecondLockFails(t *testing.T) {
 | 
				
			||||||
 | 
						tf := tmpFile()
 | 
				
			||||||
 | 
						defer os.Remove(tf)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						fl1 := lockfile.New(tf)
 | 
				
			||||||
 | 
						err := fl1.Lock()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							panic(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						defer fl1.Unlock()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						fl2 := lockfile.New(tf)
 | 
				
			||||||
 | 
						err = fl2.Lock()
 | 
				
			||||||
 | 
						if err == nil {
 | 
				
			||||||
 | 
							t.Errorf("Second Lock() did not fail")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestLockUnlock(t *testing.T) {
 | 
				
			||||||
 | 
						tf := tmpFile()
 | 
				
			||||||
 | 
						defer os.Remove(tf)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						fl := lockfile.New(tf)
 | 
				
			||||||
 | 
						err := fl.Lock()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							panic(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						err = fl.Unlock()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							panic(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if _, err := os.Stat(tf); !os.IsNotExist(err) {
 | 
				
			||||||
 | 
							t.Errorf("Lockfile %s still exists", tf)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user