Skip to content
Snippets Groups Projects
pid.go 1.61 KiB
Newer Older
  • Learn to ignore specific revisions
  • package main
    
    import (
    	"fmt"
    	"io/ioutil"
    
    	"os"
    	"path/filepath"
    
    	"runtime"
    
    	"strconv"
    	"syscall"
    
    	"0xacab.org/leap/bitmask-systray/bitmask"
    )
    
    var pidFile = filepath.Join(bitmask.ConfigPath, "systray.pid")
    
    func acquirePID() error {
    	pid := syscall.Getpid()
    	current, err := getPID()
    	if err != nil {
    		return err
    	}
    
    
    	if current != pid && pidRunning(current) {
    		return fmt.Errorf("Another systray is running with pid: %d", current)
    
    	}
    
    	return setPID(pid)
    }
    
    func releasePID() error {
    	pid := syscall.Getpid()
    	current, err := getPID()
    	if err != nil {
    		return err
    	}
    	if current != 0 && current != pid {
    		return fmt.Errorf("Can't release pid file, is not own by this process")
    	}
    
    	if current == pid {
    		return os.Remove(pidFile)
    	}
    	return nil
    }
    
    func getPID() (int, error) {
    	_, err := os.Stat(pidFile)
    	if os.IsNotExist(err) {
    		return 0, nil
    	}
    	if err != nil {
    		return 0, err
    	}
    
    	file, err := os.Open(pidFile)
    	if err != nil {
    		return 0, err
    	}
    	defer file.Close()
    
    	b, err := ioutil.ReadAll(file)
    	if err != nil {
    		return 0, err
    	}
    	if len(b) == 0 {
    		return 0, nil
    	}
    	return strconv.Atoi(string(b))
    }
    
    func setPID(pid int) error {
    	file, err := os.Create(pidFile)
    	if err != nil {
    		return err
    	}
    	defer file.Close()
    
    	_, err = file.WriteString(fmt.Sprintf("%d", pid))
    	return err
    }
    
    
    func pidRunning(pid int) bool {
    	if pid == 0 {
    		return false
    	}
    
    	proc, err := os.FindProcess(pid)
    	if runtime.GOOS == "windows" {
    		return err == nil
    	}
    
    	if err != nil {
    		log.Printf("An error ocurred finding process: %v", err)
    		return false
    	}
    	err = proc.Signal(syscall.Signal(0))
    	if err == nil {
    		return true
    	}
    	return false
    }