// Copyright 2014 The go-ethereum Authors // This file is part of go-ethereum. // // go-ethereum is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // go-ethereum is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with go-ethereum. If not, see . // Package utils contains internal helper functions for go-ethereum commands. package utils import ( "context" "fmt" "io" "os" "os/signal" "runtime" "syscall" "github.com/spf13/cobra" "github.com/urfave/cli" "github.com/ledgerwatch/erigon/internal/debug" "github.com/ledgerwatch/erigon/log" "github.com/ledgerwatch/erigon/node" ) // Fatalf formats a message to standard error and exits the program. // The message is also printed to standard output if standard error // is redirected to a different file. func Fatalf(format string, args ...interface{}) { w := io.MultiWriter(os.Stdout, os.Stderr) if runtime.GOOS == "windows" { // The SameFile check below doesn't work on Windows. // stdout is unlikely to get redirected though, so just print there. w = os.Stdout } else { outf, _ := os.Stdout.Stat() errf, _ := os.Stderr.Stat() if outf != nil && errf != nil && os.SameFile(outf, errf) { w = os.Stderr } } fmt.Fprintf(w, "Fatal: "+format+"\n", args...) os.Exit(1) } func StartNode(stack *node.Node) { if err := stack.Start(); err != nil { Fatalf("Error starting protocol stack: %v", err) } go func() { sigc := make(chan os.Signal, 1) signal.Notify(sigc, syscall.SIGINT, syscall.SIGTERM) defer signal.Stop(sigc) <-sigc log.Info("Got interrupt, shutting down...") go stack.Close() for i := 10; i > 0; i-- { <-sigc if i > 1 { log.Warn("Already shutting down, interrupt more to panic.", "times", i-1) } } debug.Exit() // ensure trace and CPU profile data is flushed. debug.LoudPanic("boom") }() } func SetupCobra(cmd *cobra.Command) error { return debug.SetupCobra(cmd) } func StopDebug() { debug.Exit() } func SetupUrfave(ctx *cli.Context) error { return debug.Setup(ctx) } func RootContext() (context.Context, context.CancelFunc) { ctx, cancel := context.WithCancel(context.Background()) go func() { defer cancel() ch := make(chan os.Signal, 1) defer close(ch) signal.Notify(ch, os.Interrupt, syscall.SIGTERM) defer signal.Stop(ch) select { case sig := <-ch: log.Info("Got interrupt, shutting down...", "sig", sig) case <-ctx.Done(): } }() return ctx, cancel }