github.com/SandwichDev/go-internals@v0.0.0-20210605002614-12311ac6b2c5/execabs/execabs.go (about) 1 // Copyright 2021 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Package execabs is a drop-in replacement for os/exec 6 // that requires PATH lookups to find absolute paths. 7 // That is, execabs.Command("cmd") runs the same PATH lookup 8 // as exec.Command("cmd"), but if the result is a path 9 // which is relative, the Run and Start methods will report 10 // an error instead of running the executable. 11 package execabs 12 13 import ( 14 "context" 15 "fmt" 16 "os/exec" 17 "path/filepath" 18 "reflect" 19 "unsafe" 20 ) 21 22 var ErrNotFound = exec.ErrNotFound 23 24 type ( 25 Cmd = exec.Cmd 26 Error = exec.Error 27 ExitError = exec.ExitError 28 ) 29 30 func relError(file, path string) error { 31 return fmt.Errorf("%s resolves to executable relative to current directory (.%c%s)", file, filepath.Separator, path) 32 } 33 34 func LookPath(file string) (string, error) { 35 path, err := exec.LookPath(file) 36 if err != nil { 37 return "", err 38 } 39 if filepath.Base(file) == file && !filepath.IsAbs(path) { 40 return "", relError(file, path) 41 } 42 return path, nil 43 } 44 45 func fixCmd(name string, cmd *exec.Cmd) { 46 if filepath.Base(name) == name && !filepath.IsAbs(cmd.Path) { 47 // exec.Command was called with a bare binary name and 48 // exec.LookPath returned a path which is not absolute. 49 // Set cmd.lookPathErr and clear cmd.Path so that it 50 // cannot be run. 51 lookPathErr := (*error)(unsafe.Pointer(reflect.ValueOf(cmd).Elem().FieldByName("lookPathErr").Addr().Pointer())) 52 if *lookPathErr == nil { 53 *lookPathErr = relError(name, cmd.Path) 54 } 55 cmd.Path = "" 56 } 57 } 58 59 func CommandContext(ctx context.Context, name string, arg ...string) *exec.Cmd { 60 cmd := exec.CommandContext(ctx, name, arg...) 61 fixCmd(name, cmd) 62 return cmd 63 64 } 65 66 func Command(name string, arg ...string) *exec.Cmd { 67 cmd := exec.Command(name, arg...) 68 fixCmd(name, cmd) 69 return cmd 70 }