Black Lives Matter. Support the Equal Justice Initiative.

Source file src/os/executable_path.go

Documentation: os

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

View as plain text