AdGuardHome/internal/next/cmd/signal.go
Eugene Burkov e77de2e67d Pull request 2294: AGDNS-2455 Windows permissions
Closes #7314.

Squashed commit of the following:

commit f8b6ffeec2f0f96c947cf896c75d05efaca77caf
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Tue Oct 29 14:14:41 2024 +0300

    all: fix chlog

commit 9417b7dc51
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Mon Oct 28 19:41:30 2024 +0300

    aghos: imp doc

commit b91f0e72a7
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Mon Oct 28 19:26:15 2024 +0300

    all: rm bin

commit 9008ee93b1
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Mon Oct 28 18:23:54 2024 +0300

    all: revert permcheck

commit bcc85d50f5
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Mon Oct 28 17:48:55 2024 +0300

    all: use aghos more

commit 993e351712
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Mon Oct 28 16:24:56 2024 +0300

    all: fix more bugs

commit a22b0d265e
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Fri Oct 25 18:30:52 2024 +0300

    all: fix bugs

commit a2309f812a
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Fri Oct 25 17:05:08 2024 +0300

    all: fix chlog, imp api

commit 42c3f8e91c
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Fri Oct 25 16:04:47 2024 +0300

    scripts: fix docs

commit 9e781ff18d
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Fri Oct 25 16:03:19 2024 +0300

    scripts: imp docs

commit 1dbc784982
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Fri Oct 25 15:55:16 2024 +0300

    all: use new functions, add tests

commit dcbabaf4e3
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Fri Oct 25 13:23:50 2024 +0300

    aghos: add stat

commit 72d7c0f881
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Thu Oct 24 17:10:30 2024 +0300

    aghos: add windows functions
2024-10-29 14:28:59 +03:00

168 lines
3.7 KiB
Go

package cmd
import (
"os"
"strconv"
"github.com/AdguardTeam/AdGuardHome/internal/aghos"
"github.com/AdguardTeam/AdGuardHome/internal/next/agh"
"github.com/AdguardTeam/AdGuardHome/internal/next/configmgr"
"github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/osutil"
)
// signalHandler processes incoming signals and shuts services down.
type signalHandler struct {
// confMgrConf contains the configuration parameters for the configuration
// manager.
confMgrConf *configmgr.Config
// signal is the channel to which OS signals are sent.
signal chan os.Signal
// pidFile is the path to the file where to store the PID, if any.
pidFile string
// services are the services that are shut down before application exiting.
services []agh.Service
}
// handle processes OS signals.
func (h *signalHandler) handle() {
defer log.OnPanic("signalHandler.handle")
h.writePID()
for sig := range h.signal {
log.Info("sighdlr: received signal %q", sig)
if aghos.IsReconfigureSignal(sig) {
h.reconfigure()
} else if osutil.IsShutdownSignal(sig) {
status := h.shutdown()
h.removePID()
log.Info("sighdlr: exiting with status %d", status)
os.Exit(status)
}
}
}
// reconfigure rereads the configuration file and updates and restarts services.
func (h *signalHandler) reconfigure() {
log.Info("sighdlr: reconfiguring adguard home")
status := h.shutdown()
if status != statusSuccess {
log.Info("sighdlr: reconfiguring: exiting with status %d", status)
os.Exit(status)
}
// TODO(a.garipov): This is a very rough way to do it. Some services can be
// reconfigured without the full shutdown, and the error handling is
// currently not the best.
confMgr, err := newConfigMgr(h.confMgrConf)
check(err)
web := confMgr.Web()
err = web.Start()
check(err)
dns := confMgr.DNS()
err = dns.Start()
check(err)
h.services = []agh.Service{
dns,
web,
}
log.Info("sighdlr: successfully reconfigured adguard home")
}
// Exit status constants.
const (
statusSuccess = 0
statusError = 1
statusArgumentError = 2
)
// shutdown gracefully shuts down all services.
func (h *signalHandler) shutdown() (status int) {
ctx, cancel := ctxWithDefaultTimeout()
defer cancel()
status = statusSuccess
log.Info("sighdlr: shutting down services")
for i, service := range h.services {
err := service.Shutdown(ctx)
if err != nil {
log.Error("sighdlr: shutting down service at index %d: %s", i, err)
status = statusError
}
}
return status
}
// newSignalHandler returns a new signalHandler that shuts down svcs.
func newSignalHandler(
confMgrConf *configmgr.Config,
pidFile string,
svcs ...agh.Service,
) (h *signalHandler) {
h = &signalHandler{
confMgrConf: confMgrConf,
signal: make(chan os.Signal, 1),
pidFile: pidFile,
services: svcs,
}
notifier := osutil.DefaultSignalNotifier{}
osutil.NotifyShutdownSignal(notifier, h.signal)
aghos.NotifyReconfigureSignal(h.signal)
return h
}
// writePID writes the PID to the file, if needed. Any errors are reported to
// log.
func (h *signalHandler) writePID() {
if h.pidFile == "" {
return
}
// Use 8, since most PIDs will fit.
data := make([]byte, 0, 8)
data = strconv.AppendInt(data, int64(os.Getpid()), 10)
data = append(data, '\n')
err := aghos.WriteFile(h.pidFile, data, 0o644)
if err != nil {
log.Error("sighdlr: writing pidfile: %s", err)
return
}
log.Debug("sighdlr: wrote pid to %q", h.pidFile)
}
// removePID removes the PID file, if any.
func (h *signalHandler) removePID() {
if h.pidFile == "" {
return
}
err := os.Remove(h.pidFile)
if err != nil {
log.Error("sighdlr: removing pidfile: %s", err)
return
}
log.Debug("sighdlr: removed pid at %q", h.pidFile)
}