optionally protect against multiple starts with flock (#1873)

* optionally protect against multiple starts with flock

Fixes #1823

* use traditional .lock extension

* move config key to top level
This commit is contained in:
Shivaram Lingamneni
2022-01-01 18:56:40 -05:00
committed by GitHub
parent e112a78b9b
commit ed75533cb1
20 changed files with 1048 additions and 0 deletions

View File

@@ -616,6 +616,8 @@ type Config struct {
languageManager *languages.Manager
LockFile string `yaml:"lock-file"`
Datastore struct {
Path string
AutoUpgrade bool

24
irc/flock/flock.go Normal file
View File

@@ -0,0 +1,24 @@
//go:build !plan9
package flock
import (
"errors"
"github.com/gofrs/flock"
)
var (
CouldntAcquire = errors.New("Couldn't acquire flock (is another Ergo running?)")
)
func TryAcquireFlock(path string) (fl Flocker, err error) {
f := flock.New(path)
success, err := f.TryLock()
if err != nil {
return nil, err
} else if !success {
return nil, CouldntAcquire
}
return f, nil
}

14
irc/flock/flock_iface.go Normal file
View File

@@ -0,0 +1,14 @@
package flock
// documentation for github.com/gofrs/flock incorrectly claims that
// Flock implements sync.Locker; it does not because the Unlock method
// has a return type (err).
type Flocker interface {
Unlock() error
}
type noopFlocker struct{}
func (n *noopFlocker) Unlock() error {
return nil
}

7
irc/flock/flock_plan9.go Normal file
View File

@@ -0,0 +1,7 @@
//go:build plan9
package flock
func TryAcquireFlock(path string) (fl Flocker, err error) {
return &noopFlocker{}, nil
}

View File

@@ -25,6 +25,7 @@ import (
"github.com/ergochat/ergo/irc/caps"
"github.com/ergochat/ergo/irc/connection_limits"
"github.com/ergochat/ergo/irc/flatip"
"github.com/ergochat/ergo/irc/flock"
"github.com/ergochat/ergo/irc/history"
"github.com/ergochat/ergo/irc/logger"
"github.com/ergochat/ergo/irc/modes"
@@ -88,6 +89,7 @@ type Server struct {
whoWas WhoWasList
stats Stats
semaphores ServerSemaphores
flock flock.Flocker
defcon uint32
}
@@ -585,6 +587,19 @@ func (server *Server) applyConfig(config *Config) (err error) {
server.logger.Info("server", "Using config file", server.configFilename)
if initial {
if config.LockFile != "" {
server.flock, err = flock.TryAcquireFlock(config.LockFile)
if err != nil {
return fmt.Errorf("failed to acquire flock on %s: %w",
config.LockFile, err)
}
}
// the lock is never released until quit; we need to save a pointer
// to the (*flock.Flock) object so it doesn't get GC'ed, which would
// close the file and surrender the lock
}
// first, reload config sections for functionality implemented in subpackages:
wasLoggingRawIO := !initial && server.logger.IsLoggingRawIO()
err = server.logger.ApplyConfig(config.Logging)