From 15f7fd91ab68a059adc3b58d4a2972582196ce36 Mon Sep 17 00:00:00 2001 From: Daniel Legt Date: Tue, 18 Aug 2026 17:03:20 +0300 Subject: [PATCH] Add background mode support to localagent and implement instance check --- lib/instance/detach.go | 49 ++++++++++++++++++++++++++++++++++++++++++ lib/instance/mutex.go | 13 +++++++++++ main.go | 18 ++++++++++++++-- 3 files changed, 78 insertions(+), 2 deletions(-) create mode 100644 lib/instance/detach.go diff --git a/lib/instance/detach.go b/lib/instance/detach.go new file mode 100644 index 0000000..64e9e43 --- /dev/null +++ b/lib/instance/detach.go @@ -0,0 +1,49 @@ +package instance + +import ( + "fmt" + "os" + "os/exec" + "strings" + "syscall" + + "golang.org/x/sys/windows" +) + +func Detach() error { + if AlreadyRunning() { + return fmt.Errorf("agent already running") + } + exe, err := os.Executable() + if err != nil { + return err + } + nul, err := os.OpenFile("NUL", os.O_RDWR, 0) + if err != nil { + return err + } + defer nul.Close() + + cmd := exec.Command(exe, stripBackground(os.Args[1:])...) + cmd.Stdin = nul + cmd.Stdout = nul + cmd.Stderr = nul + cmd.SysProcAttr = &syscall.SysProcAttr{ + HideWindow: true, + CreationFlags: windows.CREATE_NO_WINDOW | windows.CREATE_NEW_PROCESS_GROUP, + } + return cmd.Start() +} + +func stripBackground(args []string) []string { + out := make([]string, 0, len(args)) + for _, arg := range args { + name := strings.TrimLeft(arg, "-/") + lower := strings.ToLower(name) + if lower == "background" || strings.HasPrefix(lower, "background=") { + continue + } + out = append(out, arg) + } + return out +} diff --git a/lib/instance/mutex.go b/lib/instance/mutex.go index 805dd94..3b66019 100644 --- a/lib/instance/mutex.go +++ b/lib/instance/mutex.go @@ -28,6 +28,19 @@ func Acquire() (*Guard, error) { return &Guard{handle: h}, nil } +func AlreadyRunning() bool { + name, err := windows.UTF16PtrFromString(config.MutexName) + if err != nil { + return false + } + h, err := windows.OpenMutex(windows.SYNCHRONIZE, false, name) + if err != nil { + return false + } + windows.CloseHandle(h) + return true +} + func (g *Guard) Close() { if g == nil || g.handle == 0 { return diff --git a/main.go b/main.go index 67f388b..71312fe 100644 --- a/main.go +++ b/main.go @@ -4,16 +4,30 @@ // // GOOS=windows GOARCH=amd64 go build -ldflags "-s -w" -o localagent.exe . // -// The binary is a normal console application. A CMD window appears on launch -// and prints the listen address. Press Ctrl+C to stop. +// A CMD window appears on launch. Use -background to start without a window: +// +// localagent.exe -background package main import ( + "flag" + "tea.chunkbyte.com/kato/go-worm/lib/agent" "tea.chunkbyte.com/kato/go-worm/lib/helpers" + "tea.chunkbyte.com/kato/go-worm/lib/instance" ) func main() { + background := flag.Bool("background", false, "run without a console window") + flag.Parse() + + if *background { + if err := instance.Detach(); err != nil { + helpers.Log.Fatalf("%v", err) + } + return + } + a, err := agent.New() if err != nil { helpers.Log.Fatalf("%v", err)