github.com/haraldrudell/parl@v0.4.176/punix/errno.go (about) 1 /* 2 © 2022–present Harald Rudell <harald.rudell@gmail.com> (https://haraldrudell.github.io/haraldrudell/) 3 ISC License 4 */ 5 6 // Package punix examines unix.Errno errors and identifies Unix-like platforms. 7 package punix 8 9 import ( 10 "errors" 11 "strconv" 12 "strings" 13 14 "github.com/haraldrudell/parl" 15 "golang.org/x/sys/unix" 16 ) 17 18 // IsENOENT returns true if the root cause of err is file not found. 19 // Can be used with os.Open* file not found 20 func IsENOENT(err error) (isENOENT bool) { 21 return Errno(err) == unix.ENOENT 22 } 23 24 // IsConnectionRefused searches the error chsin of err for unix.ECONNREFUSED 25 // net.Dialer errors for closed socket 26 func IsConnectionRefused(err error) (isConnectionRefused bool) { 27 return Errno(err) == unix.ECONNREFUSED 28 } 29 30 // Errno scans an error chain for a unix.Errno type. 31 // - if no errno value exists, unix.Errno 0x0 is returned 32 // - unlike most error implementations, unix.Errno type is uintptr 33 // - to check for error condition of a unix.Errno error: if errno != 0 {… 34 // - to obtain errno number: int(errno) 35 // - to print errno number: fmt.Sprintf("%d", errno) → "1" 36 // - to print errno message: fmt.Sprintf("%v", unix.EPERM) → "operation not permitted" 37 // - to obtain errno name: unix.ErrnoName(unix.EPERM) → "EPERM" 38 // - to print hexadecimal errno: 39 // 40 // Note: unix.Errno.Error has value receiver. 41 // Errno checks: 42 // 43 // Errno(nil) == 0 → true. 44 // if errno != 0 {… 45 // int(errno) // numeric value 46 // if errno == unix.ENOENT… 47 // fmt.Sprintf("%d", unix.EPERM) → "1" 48 // fmt.Printf("%v", errno) → "state not recoverable" 49 // unix.ErrnoName(unix.EPERM) → "EPERM" 50 // var i, s = int(errno), "" 51 // if i < 0 { i = -i; s = "-" } 52 // fmt.Printf("%s0x%x", s, i) → 0x68 53 func Errno(err error) (errnoValue unix.Errno) { 54 for ; err != nil; err = errors.Unwrap(err) { 55 var ok bool 56 if errnoValue, ok = err.(unix.Errno); ok { 57 return // match return 58 } 59 } 60 return // no match return 61 } 62 63 // ErrnoString returns the errno number as a string if 64 // the err error chain has a non-zero syscall.Errno error. 65 // - if label is empty string, no label is returned 66 // - if no syscall.Errno is found or it is zero, the empty string is returned 67 // - ErrnoString("errno", nil) → "" 68 // - ErrnoString("errno", unix.EPERM) → "errno: EPERM 1 0x1" 69 // - ErrnoString("errno", unix.Errno(math.MaxUint)) → "-1 -0x1" 70 func ErrnoString(label string, err error) (errnoNumericString string) { 71 var unixErrno = Errno(err) 72 if unixErrno == 0 { 73 return // no errno error return: "" 74 } 75 76 if label != "" { 77 errnoNumericString = label + ":\x20" 78 } 79 80 if name := unix.ErrnoName(unixErrno); name != "" { 81 errnoNumericString += name + "\x20" 82 } 83 84 var errno = int(unixErrno) 85 errnoNumericString += strconv.Itoa(errno) + "\x20" 86 87 var hexErrno = int64(errno) 88 var sign string 89 if hexErrno < 0 { 90 sign = "-" 91 hexErrno = -hexErrno 92 } 93 errnoNumericString += sign + "0x" + strconv.FormatInt(hexErrno, 16) 94 95 return 96 } 97 98 // ErrnoError gets the errno interpretation if the error chain does contain 99 // a unix.Errno type. 100 // if includeError is true, the error chain’s error message is prepended. 101 // if includeError is true and err is nil "OK" is returned 102 // if includeError is false or missing and no errno exists, the empty string is returned 103 func ErrnoError(err error, includeError ...bool) (errnoString string) { 104 var isInclude bool 105 if len(includeError) > 0 { 106 isInclude = includeError[0] 107 } 108 109 // handle err == nil case 110 if err == nil { 111 if isInclude { 112 return "OK" 113 } else { 114 return 115 } 116 } 117 118 // handle includeError 119 var sList []string 120 if isInclude { 121 sList = append(sList, err.Error()) 122 } 123 124 // handle errno 125 if unixErrno := Errno(err); unixErrno != 0 { 126 sList = append(sList, parl.Sprintf("errno:'%s'0x%x:temporary:%t:timeout:%t", 127 unixErrno.Error(), 128 uint(unixErrno), 129 unixErrno.Temporary(), 130 unixErrno.Timeout(), 131 )) 132 } 133 134 return strings.Join(sList, "\x20") 135 }