Source file src/os/executable_path.go

     1  // Copyright 2017 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  //go:build aix || openbsd
     6  
     7  package os
     8  
     9  // We query the working directory at init, to use it later to search for the
    10  // executable file
    11  // errWd will be checked later, if we need to use initWd
    12  var initWd, errWd = Getwd()
    13  
    14  func executable() (string, error) {
    15  	var exePath string
    16  	if len(Args) == 0 || Args[0] == "" {
    17  		return "", ErrNotExist
    18  	}
    19  	if IsPathSeparator(Args[0][0]) {
    20  		// Args[0] is an absolute path, so it is the executable.
    21  		// Note that we only need to worry about Unix paths here.
    22  		exePath = Args[0]
    23  	} else {
    24  		for i := 1; i < len(Args[0]); i++ {
    25  			if IsPathSeparator(Args[0][i]) {
    26  				// Args[0] is a relative path: prepend the
    27  				// initial working directory.
    28  				if errWd != nil {
    29  					return "", errWd
    30  				}
    31  				exePath = initWd + string(PathSeparator) + Args[0]
    32  				break
    33  			}
    34  		}
    35  	}
    36  	if exePath != "" {
    37  		if err := isExecutable(exePath); err != nil {
    38  			return "", err
    39  		}
    40  		return exePath, nil
    41  	}
    42  	// Search for executable in $PATH.
    43  	for _, dir := range splitPathList(Getenv("PATH")) {
    44  		if len(dir) == 0 {
    45  			dir = "."
    46  		}
    47  		if !IsPathSeparator(dir[0]) {
    48  			if errWd != nil {
    49  				return "", errWd
    50  			}
    51  			dir = initWd + string(PathSeparator) + dir
    52  		}
    53  		exePath = dir + string(PathSeparator) + Args[0]
    54  		switch isExecutable(exePath) {
    55  		case nil:
    56  			return exePath, nil
    57  		case ErrPermission:
    58  			return "", ErrPermission
    59  		}
    60  	}
    61  	return "", ErrNotExist
    62  }
    63  
    64  // isExecutable returns an error if a given file is not an executable.
    65  func isExecutable(path string) error {
    66  	stat, err := Stat(path)
    67  	if err != nil {
    68  		return err
    69  	}
    70  	mode := stat.Mode()
    71  	if !mode.IsRegular() {
    72  		return ErrPermission
    73  	}
    74  	if (mode & 0111) == 0 {
    75  		return ErrPermission
    76  	}
    77  	return nil
    78  }
    79  
    80  // splitPathList splits a path list.
    81  // This is based on genSplit from strings/strings.go
    82  func splitPathList(pathList string) []string {
    83  	if pathList == "" {
    84  		return nil
    85  	}
    86  	n := 1
    87  	for i := 0; i < len(pathList); i++ {
    88  		if pathList[i] == PathListSeparator {
    89  			n++
    90  		}
    91  	}
    92  	start := 0
    93  	a := make([]string, n)
    94  	na := 0
    95  	for i := 0; i+1 <= len(pathList) && na+1 < n; i++ {
    96  		if pathList[i] == PathListSeparator {
    97  			a[na] = pathList[start:i]
    98  			na++
    99  			start = i + 1
   100  		}
   101  	}
   102  	a[na] = pathList[start:]
   103  	return a[:na+1]
   104  }
   105  

View as plain text