From 904b414fce2fc5bc20ecb1964407eb17fb370e78 Mon Sep 17 00:00:00 2001 From: Hugo Santos Date: Wed, 4 Jun 2025 15:53:35 -0400 Subject: [PATCH] first windows port; no pty support. --- cmd/breakpoint/start.go | 8 +++--- pkg/execbackground/bg_unix.go | 14 ++++++++++ pkg/execbackground/bg_windows.go | 9 +++++++ pkg/sshd/pty_unix.go | 44 ++++++++++++++++++++++++++++++++ pkg/sshd/pty_windows.go | 15 +++++++++++ pkg/sshd/sshd.go | 13 +--------- pkg/sshd/winresize.go | 20 --------------- 7 files changed, 86 insertions(+), 37 deletions(-) create mode 100644 pkg/execbackground/bg_unix.go create mode 100644 pkg/execbackground/bg_windows.go create mode 100644 pkg/sshd/pty_unix.go create mode 100644 pkg/sshd/pty_windows.go delete mode 100644 pkg/sshd/winresize.go diff --git a/cmd/breakpoint/start.go b/cmd/breakpoint/start.go index 5fc321f..5287de3 100644 --- a/cmd/breakpoint/start.go +++ b/cmd/breakpoint/start.go @@ -6,13 +6,13 @@ import ( "fmt" "os" "os/exec" - "syscall" "time" "github.com/spf13/cobra" "google.golang.org/protobuf/types/known/emptypb" - "namespacelabs.dev/breakpoint/api/private/v1" + v1 "namespacelabs.dev/breakpoint/api/private/v1" "namespacelabs.dev/breakpoint/pkg/bcontrol" + "namespacelabs.dev/breakpoint/pkg/execbackground" "namespacelabs.dev/breakpoint/pkg/waiter" ) @@ -35,9 +35,7 @@ func newStartCmd() *cobra.Command { procArgs := []string{"wait", "--config", *configPath} proc := exec.Command(os.Args[0], procArgs...) - proc.SysProcAttr = &syscall.SysProcAttr{ - Setsid: true, - } + execbackground.SetCreateSession(proc) if err := proc.Start(); err != nil { return fmt.Errorf("failed to start background process: %w", err) diff --git a/pkg/execbackground/bg_unix.go b/pkg/execbackground/bg_unix.go new file mode 100644 index 0000000..beb0b37 --- /dev/null +++ b/pkg/execbackground/bg_unix.go @@ -0,0 +1,14 @@ +//go:build !windows + +package execbackground + +import ( + "os/exec" + "syscall" +) + +func SetCreateSession(cmd *exec.Cmd) { + cmd.SysProcAttr = &syscall.SysProcAttr{ + Setsid: true, + } +} diff --git a/pkg/execbackground/bg_windows.go b/pkg/execbackground/bg_windows.go new file mode 100644 index 0000000..f530448 --- /dev/null +++ b/pkg/execbackground/bg_windows.go @@ -0,0 +1,9 @@ +//go:build windows + +package execbackground + +import "os/exec" + +func SetCreateSession(cmd *exec.Cmd) { + panic("not supported") +} diff --git a/pkg/sshd/pty_unix.go b/pkg/sshd/pty_unix.go new file mode 100644 index 0000000..6ac15e4 --- /dev/null +++ b/pkg/sshd/pty_unix.go @@ -0,0 +1,44 @@ +//go:build !windows + +package sshd + +import ( + "fmt" + "io" + "os" + "os/exec" + "syscall" + "unsafe" + + "github.com/creack/pty" + "github.com/gliderlabs/ssh" +) + +func handlePty(session io.ReadWriter, ptyReq ssh.Pty, winCh <-chan ssh.Window, cmd *exec.Cmd) error { + cmd.Env = append(cmd.Env, fmt.Sprintf("TERM=%s", ptyReq.Term)) + ptyFile, err := pty.Start(cmd) + if err != nil { + return err + } + + defer ptyFile.Close() + + go syncWinSize(ptyFile, winCh) + go func() { + _, _ = io.Copy(ptyFile, session) // stdin + }() + _, _ = io.Copy(session, ptyFile) // stdout + + return nil +} + +func syncWinSize(ptyFile *os.File, winCh <-chan ssh.Window) { + for win := range winCh { + setWinsize(ptyFile, win.Width, win.Height) + } +} + +func setWinsize(f *os.File, w, h int) { + syscall.Syscall(syscall.SYS_IOCTL, f.Fd(), uintptr(syscall.TIOCSWINSZ), + uintptr(unsafe.Pointer(&struct{ h, w, x, y uint16 }{uint16(h), uint16(w), 0, 0}))) +} diff --git a/pkg/sshd/pty_windows.go b/pkg/sshd/pty_windows.go new file mode 100644 index 0000000..cedcea8 --- /dev/null +++ b/pkg/sshd/pty_windows.go @@ -0,0 +1,15 @@ +//go:build windows + +package sshd + +import ( + "errors" + "io" + "os/exec" + + "github.com/gliderlabs/ssh" +) + +func handlePty(session io.ReadWriter, ptyReq ssh.Pty, winCh <-chan ssh.Window, cmd *exec.Cmd) error { + return errors.New("pty not supported in windows") +} diff --git a/pkg/sshd/sshd.go b/pkg/sshd/sshd.go index b337385..67f72d4 100644 --- a/pkg/sshd/sshd.go +++ b/pkg/sshd/sshd.go @@ -10,7 +10,6 @@ import ( "os/exec" "time" - "github.com/creack/pty" "github.com/gliderlabs/ssh" "github.com/rs/zerolog" "go.uber.org/atomic" @@ -96,21 +95,11 @@ func MakeServer(ctx context.Context, opts SSHServerOpts) (*SSHServer, error) { opts.InteractiveMOTD(session) } - cmd.Env = append(cmd.Env, fmt.Sprintf("TERM=%s", ptyReq.Term)) - ptyFile, err := pty.Start(cmd) - if err != nil { + if err := handlePty(session, ptyReq, winCh, cmd); err != nil { sessionLog.Err(err).Msg("pty start failed") session.Exit(1) return } - - defer ptyFile.Close() - - go syncWinSize(ptyFile, winCh) - go func() { - _, _ = io.Copy(ptyFile, session) // stdin - }() - _, _ = io.Copy(session, ptyFile) // stdout } else { cmd.Stdout = session cmd.Stderr = session diff --git a/pkg/sshd/winresize.go b/pkg/sshd/winresize.go deleted file mode 100644 index 7462d2e..0000000 --- a/pkg/sshd/winresize.go +++ /dev/null @@ -1,20 +0,0 @@ -package sshd - -import ( - "os" - "syscall" - "unsafe" - - "github.com/gliderlabs/ssh" -) - -func syncWinSize(ptyFile *os.File, winCh <-chan ssh.Window) { - for win := range winCh { - setWinsize(ptyFile, win.Width, win.Height) - } -} - -func setWinsize(f *os.File, w, h int) { - syscall.Syscall(syscall.SYS_IOCTL, f.Fd(), uintptr(syscall.TIOCSWINSZ), - uintptr(unsafe.Pointer(&struct{ h, w, x, y uint16 }{uint16(h), uint16(w), 0, 0}))) -}