Skip to content

Commit

Permalink
all: fix build on plan9
Browse files Browse the repository at this point in the history
It turns out that the syscall package is not only a problem for
unix vs windows, but also for unix vs plan9.

Thankfully, I forgot that os/exec.ExitError.ExitCode exists,
so at least we can still extract exit status codes on all platforms.
  • Loading branch information
mvdan committed Nov 29, 2024
1 parent 18ab714 commit 0ac9498
Show file tree
Hide file tree
Showing 6 changed files with 39 additions and 15 deletions.
5 changes: 1 addition & 4 deletions expand/expand.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import (
"runtime"
"strconv"
"strings"
"syscall"

"mvdan.cc/sh/v3/pattern"
"mvdan.cc/sh/v3/syntax"
Expand Down Expand Up @@ -890,9 +889,7 @@ func (cfg *Config) glob(base, pat string) ([]string, error) {
// which can be wasteful if we only want to see if it exists,
// but at least it's correct in all scenarios.
if _, err := cfg.ReadDir2(match); err != nil {
const errPathNotFound = syscall.Errno(3) // from syscall/types_windows.go, to avoid a build tag
var pathErr *os.PathError
if runtime.GOOS == "windows" && errors.As(err, &pathErr) && pathErr.Err == errPathNotFound {
if isWindowsErrPathNotFound(err) {
// Unfortunately, os.File.Readdir on a regular file on
// Windows returns an error that satisfies ErrNotExist.
// Luckily, it returns a special "path not found" rather
Expand Down
8 changes: 8 additions & 0 deletions expand/expand_nonwindows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// Copyright (c) 2017, Daniel Martí <[email protected]>
// See LICENSE for licensing information

//go:build !windows

package expand

func isWindowsErrPathNotFound(error) bool { return false }
15 changes: 15 additions & 0 deletions expand/expand_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Copyright (c) 2017, Daniel Martí <[email protected]>
// See LICENSE for licensing information

package expand

import (
"errors"
"os"
"syscall"
)

func isWindowsErrPathNotFound(err error) bool {
var pathErr *os.PathError
return errors.As(err, &pathErr) && pathErr.Err == syscall.ERROR_PATH_NOT_FOUND
}
18 changes: 7 additions & 11 deletions interp/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import (
"path/filepath"
"runtime"
"strings"
"syscall"
"time"

"mvdan.cc/sh/v3/expand"
Expand Down Expand Up @@ -135,18 +134,15 @@ func DefaultExecHandler(killTimeout time.Duration) ExecHandlerFunc {

switch err := err.(type) {
case *exec.ExitError:
// started, but errored - default to 1 if OS
// doesn't have exit statuses
if status, ok := err.Sys().(syscall.WaitStatus); ok {
if status.Signaled() {
if ctx.Err() != nil {
return ctx.Err()
}
return NewExitStatus(uint8(128 + status.Signal()))
// Windows and Plan9 do not have support for syscall.WaitStatus
// with methods like Signaled and Signal, so for those, waitStatus is a no-op.
if status, ok := err.Sys().(waitStatus); ok && status.Signaled() {
if ctx.Err() != nil {
return ctx.Err()
}
return NewExitStatus(uint8(status.ExitStatus()))
return NewExitStatus(uint8(128 + status.Signal()))
}
return NewExitStatus(1)
return NewExitStatus(uint8(err.ExitCode()))
case *exec.Error:
// did not start
fmt.Fprintf(hc.Stderr, "%v\n", err)
Expand Down
6 changes: 6 additions & 0 deletions interp/os_notunix.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,9 @@ func hasPermissionToDir(string) bool {
func (r *Runner) unTestOwnOrGrp(ctx context.Context, op syntax.UnTestOperator, x string) bool {
panic(fmt.Sprintf("unhandled unary test op: %v", op))
}

// waitStatus is a no-op on plan9 and windows.
type waitStatus struct{}

func (waitStatus) Signaled() bool { return false }
func (waitStatus) Signal() int { return 0 }
2 changes: 2 additions & 0 deletions interp/os_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,5 @@ func (r *Runner) unTestOwnOrGrp(ctx context.Context, op syntax.UnTestOperator, x
gid, _ := strconv.Atoi(u.Gid)
return uint32(gid) == info.Sys().(*syscall.Stat_t).Gid
}

type waitStatus = syscall.WaitStatus

0 comments on commit 0ac9498

Please sign in to comment.