Improve start and shutdown controls and flow

This commit is contained in:
Daniel
2024-11-07 16:20:58 +01:00
parent 9f148f9ea3
commit c22814e6e1
7 changed files with 355 additions and 234 deletions

View File

@@ -1,7 +1,6 @@
package main
import (
"bufio"
"errors"
"flag"
"fmt"
@@ -9,44 +8,43 @@ import (
"log/slog"
"os"
"runtime/pprof"
"syscall"
"time"
"github.com/spf13/cobra"
"github.com/safing/portmaster/base/log"
"github.com/safing/portmaster/service"
"github.com/safing/portmaster/service/mgr"
"github.com/safing/portmaster/spn/conf"
)
var (
printStackOnExit bool
enableInputSignals bool
sigUSR1 = syscall.Signal(0xa) // dummy for windows
)
var printStackOnExit bool
func init() {
flag.BoolVar(&printStackOnExit, "print-stack-on-exit", false, "prints the stack before of shutting down")
flag.BoolVar(&enableInputSignals, "input-signals", false, "emulate signals using stdin")
}
type SystemService interface {
Run()
IsService() bool
RestartService() error
}
func cmdRun(cmd *cobra.Command, args []string) {
// Call platform specific checks, that will execute commands like "recover-iptables"
platformSpecificChecks()
// Run platform specific setup or switches.
runPlatformSpecifics(cmd, args)
// SETUP
svcCfg.VerifyBinaryUpdates = nil // FIXME
svcCfg.VerifyIntelUpdates = nil // FIXME
instance := createInstance()
run(instance)
}
func createInstance() *service.Instance {
// enable SPN client mode
conf.EnableClient(true)
conf.EnableIntegration(true)
// Create instance.
// Instance modules might request a cmdline execution of a function.
var execCmdLine bool
instance, err := service.New(svcCfg)
switch {
@@ -76,7 +74,56 @@ func createInstance() *service.Instance {
}
os.Exit(0)
}
return instance
// START
// Set default log level and start logging.
log.SetLogLevel(log.WarningLevel)
_ = log.Start()
// Create system service.
service := NewSystemService(instance)
// Start instance via system service manager.
go func() {
service.Run()
}()
// SHUTDOWN
// Wait for shutdown to be started.
<-instance.ShuttingDown()
// Wait for shutdown to be finished.
select {
case <-instance.ShutdownComplete():
case <-time.After(3 * time.Minute):
printStackTo(os.Stderr, "PRINTING STACK - TAKING TOO LONG FOR SHUTDOWN")
}
// Stop logging.
log.Shutdown()
// Print stack on shutdown, if enabled.
if printStackOnExit {
printStackTo(os.Stdout, "PRINTING STACK ON EXIT")
}
// Check if restart was triggered and send start service command if true.
if instance.ShouldRestart && service.IsService() {
if err := service.RestartService(); err != nil {
slog.Error("failed to restart service", "err", err)
}
}
// Give a small amount of time for everything to settle:
// - All logs written.
// - Restart command started, if needed.
// - Windows service manager notified.
time.Sleep(100 * time.Millisecond)
// Exit
os.Exit(instance.ExitCode())
}
func printStackTo(writer io.Writer, msg string) {
@@ -88,21 +135,3 @@ func printStackTo(writer io.Writer, msg string) {
slog.Error("failed to write stack trace", "err", err)
}
}
func inputSignals(signalCh chan os.Signal) {
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
switch scanner.Text() {
case "SIGHUP":
signalCh <- syscall.SIGHUP
case "SIGINT":
signalCh <- syscall.SIGINT
case "SIGQUIT":
signalCh <- syscall.SIGQUIT
case "SIGTERM":
signalCh <- syscall.SIGTERM
case "SIGUSR1":
signalCh <- sigUSR1
}
}
}