123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104 |
- // Copyright 2017 The Go Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license that can be found in the LICENSE file.
- //go:build aix || openbsd
- package os
- // We query the working directory at init, to use it later to search for the
- // executable file
- // errWd will be checked later, if we need to use initWd
- var initWd, errWd = Getwd()
- func executable() (string, error) {
- var exePath string
- if len(Args) == 0 || Args[0] == "" {
- return "", ErrNotExist
- }
- if IsPathSeparator(Args[0][0]) {
- // Args[0] is an absolute path, so it is the executable.
- // Note that we only need to worry about Unix paths here.
- exePath = Args[0]
- } else {
- for i := 1; i < len(Args[0]); i++ {
- if IsPathSeparator(Args[0][i]) {
- // Args[0] is a relative path: prepend the
- // initial working directory.
- if errWd != nil {
- return "", errWd
- }
- exePath = initWd + string(PathSeparator) + Args[0]
- break
- }
- }
- }
- if exePath != "" {
- if err := isExecutable(exePath); err != nil {
- return "", err
- }
- return exePath, nil
- }
- // Search for executable in $PATH.
- for _, dir := range splitPathList(Getenv("PATH")) {
- if len(dir) == 0 {
- dir = "."
- }
- if !IsPathSeparator(dir[0]) {
- if errWd != nil {
- return "", errWd
- }
- dir = initWd + string(PathSeparator) + dir
- }
- exePath = dir + string(PathSeparator) + Args[0]
- switch isExecutable(exePath) {
- case nil:
- return exePath, nil
- case ErrPermission:
- return "", ErrPermission
- }
- }
- return "", ErrNotExist
- }
- // isExecutable returns an error if a given file is not an executable.
- func isExecutable(path string) error {
- stat, err := Stat(path)
- if err != nil {
- return err
- }
- mode := stat.Mode()
- if !mode.IsRegular() {
- return ErrPermission
- }
- if (mode & 0111) == 0 {
- return ErrPermission
- }
- return nil
- }
- // splitPathList splits a path list.
- // This is based on genSplit from strings/strings.go
- func splitPathList(pathList string) []string {
- if pathList == "" {
- return nil
- }
- n := 1
- for i := 0; i < len(pathList); i++ {
- if pathList[i] == PathListSeparator {
- n++
- }
- }
- start := 0
- a := make([]string, n)
- na := 0
- for i := 0; i+1 <= len(pathList) && na+1 < n; i++ {
- if pathList[i] == PathListSeparator {
- a[na] = pathList[start:i]
- na++
- start = i + 1
- }
- }
- a[na] = pathList[start:]
- return a[:na+1]
- }
|