func CheckPID(fname string, logger *log.Logger) error {
	if _, err := os.Stat(fname); os.IsNotExist(err) {
		return savePID(fname, os.Getpid(), logger)
	}
	content, err := ioutil.ReadFile(fname)
	if err != nil {
		logger.Error("unable to read PID file", zap.String("file", fname), zap.Error(err))
		return err
	}
	readPID, err := strconv.Atoi(string(content))
	if err != nil {
		logger.Error("invalid content inside PID file", zap.String("file", fname), zap.Error(err))
		return savePID(fname, os.Getpid(), logger)
	}
	if err = syscall.Kill(readPID, 0); err == nil {
		logger.Error("Arachne already running and different from self PID",
			zap.Int("other_PID", readPID),
			zap.Int("self_PID", os.Getpid()))
		return errors.New("Arachne already running and different from self PID")
	}
	return savePID(fname, os.Getpid(), logger)
}
CheckPID checks if another Arachne process is already running.
package util
import (
	"bufio"
	"io/ioutil"
	"os"
	"os/signal"
	"path"
	"strconv"
	"syscall"
	"time"
	"github.com/uber/arachne/internal/ip"
	"github.com/uber/arachne/internal/log"
	"github.com/uber/arachne/metrics"
	"github.com/fatih/color"
	"github.com/pkg/errors"
	"go.uber.org/zap"
)
const bannerText = `
____________________________________________________________/\\\______________________________________
 ___________________________________________________________\/\\\______________________________________
  ___________________________________________________________\/\\\______________________________________
   __/\\\\\\\\\_____/\\/\\\\\\\___/\\\\\\\\\________/\\\\\\\\_\/\\\__________/\\/\\\\\\_______/\\\\\\\\__
    _\ 
     ___/\\\\\\\\\\__\/\\\___\ 
      __/\\\ 
       _\ 
        __\ 
`
type KillChannels struct {
	Receiver   chan struct{}
	Echo       chan struct{}
	Collector  chan struct{}
	DNSRefresh chan struct{}
}
func PrintBanner() {
	color.Set(color.FgHiYellow, color.Bold)
	defer color.Unset()
	f := bufio.NewWriter(os.Stdout)
	defer f.Flush()
	f.Write([]byte(bannerText))
}
func UnixSignals(sigC chan struct{}, logger *log.Logger) {
	sigc := make(chan os.Signal, 1)
	signal.Notify(sigc, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGKILL, syscall.SIGTERM,
		syscall.SIGUSR1, syscall.SIGUSR2, syscall.SIGHUP, os.Interrupt)
	go func() {
		sigType := <-sigc
		switch sigType {
		case os.Interrupt:
		case syscall.SIGHUP:
			logger.Info("got Hangup/SIGHUP - portable number 1")
		case syscall.SIGINT:
			logger.Info("got Terminal interrupt signal/SIGINT - portable number 2")
		case syscall.SIGQUIT:
			logger.Fatal("got Terminal quit signal/SIGQUIT - portable number 3 - will core dump")
		case syscall.SIGABRT:
			logger.Fatal("got Process abort signal/SIGABRT - portable number 6 - will core dump")
		case syscall.SIGKILL:
			logger.Info("got Kill signal/SIGKILL - portable number 9")
		case syscall.SIGALRM:
			logger.Fatal("got Alarm clock signal/SIGALRM - portable number 14")
		case syscall.SIGTERM:
			logger.Info("got Termination signal/SIGTERM - portable number 15")
		case syscall.SIGUSR1:
			logger.Info("got User-defined signal 1/SIGUSR1")
		case syscall.SIGUSR2:
			logger.Info("got User-defined signal 2/SIGUSR2")
		default:
			logger.Fatal("unhandled Unix signal", zap.Any("sig_type", sigType))
		}
		sigC <- struct{}{}
		return
	}()
}