...

Source file src/pkg/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	// +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