-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsi.go
99 lines (84 loc) · 2.54 KB
/
si.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
package si
import (
"bytes"
"errors"
"fmt"
"golang.org/x/sys/unix"
"io/ioutil"
"os"
"path/filepath"
"strconv"
)
const ext = ".pid"
var (
// Dir is the directory where the file that registers an execution will be saved.
// If you're having problems (usually with older versions of Linux) try setting it to /var/run
Dir = "/run"
// ErrOtherInstanceRunning is the error that Register() will return if another instance
// with the same alias is running.
ErrOtherInstanceRunning = errors.New("there is another instance of the program running")
// Currently open and locked files
openFiles = make(map[string]*os.File, 10)
)
// Find looks for a running instance of a process that have the alias provided.
// It returns nil if no process with that alias was found.
func Find(alias string) (*Process, error) {
f, err := os.Open(getPath(alias))
if err != nil {
if os.IsNotExist(err) {
return nil, nil
}
return nil, fmt.Errorf("error opening pid file: %w", err)
}
defer f.Close()
if err := unix.Flock(int(f.Fd()), unix.LOCK_EX|unix.LOCK_NB); err == nil {
if err := unix.Flock(int(f.Fd()), unix.LOCK_UN); err != nil {
return nil, fmt.Errorf("error unlocking pid file: %w", err)
}
return nil, nil
} else if err != unix.EWOULDBLOCK {
return nil, fmt.Errorf("error locking pid file: %w", err)
}
data, err := ioutil.ReadAll(f)
if err != nil {
return nil, fmt.Errorf("error reading pid file: %w", err)
}
data = bytes.TrimSpace(data)
pid, err := strconv.Atoi(string(data))
if err != nil {
return nil, fmt.Errorf("error parsing pid (%s): %w", string(data), err)
}
p, err := findProcess(pid)
if err != nil {
return nil, fmt.Errorf("error finding process with pid %d: %w", pid, err)
}
return p, err
}
// Register registers the current instance of the program running under the given alias.
func Register(alias string) error {
p, err := Find(alias)
if err != nil {
return err
}
if p != nil {
return ErrOtherInstanceRunning
}
f, err := os.OpenFile(getPath(alias), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
if err != nil {
return fmt.Errorf("error creating pid file: %w", err)
}
if err := unix.Flock(int(f.Fd()), unix.LOCK_EX|unix.LOCK_NB); err != nil {
if err == unix.EWOULDBLOCK {
return ErrOtherInstanceRunning
}
return fmt.Errorf("error locking pid file: %w", err)
}
openFiles[alias] = f
if _, err := f.WriteString(strconv.Itoa(os.Getpid()) + "\n"); err != nil {
return fmt.Errorf("error writing to pid file: %w", err)
}
return nil
}
func getPath(alias string) string {
return filepath.Join(Dir, alias+ext)
}