github.com/sagernet/gvisor@v0.0.0-20240428053021-e691de28565f/pkg/errors/linuxerr/internal.go (about) 1 // Copyright 2021 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"),; 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package linuxerr 16 17 import ( 18 "github.com/sagernet/gvisor/pkg/abi/linux/errno" 19 "github.com/sagernet/gvisor/pkg/errors" 20 ) 21 22 var ( 23 // ErrWouldBlock is an internal error used to indicate that an operation 24 // cannot be satisfied immediately, and should be retried at a later 25 // time, possibly when the caller has received a notification that the 26 // operation may be able to complete. It is used by implementations of 27 // the kio.File interface. 28 ErrWouldBlock = errors.New(errno.EWOULDBLOCK, "request would block") 29 30 // ErrInterrupted is returned if a request is interrupted before it can 31 // complete. 32 ErrInterrupted = errors.New(errno.EINTR, "request was interrupted") 33 34 // ErrExceedsFileSizeLimit is returned if a request would exceed the 35 // file's size limit. 36 ErrExceedsFileSizeLimit = errors.New(errno.E2BIG, "exceeds file size limit") 37 ) 38 39 var errorMap = map[error]*errors.Error{ 40 ErrWouldBlock: EWOULDBLOCK, 41 ErrInterrupted: EINTR, 42 ErrExceedsFileSizeLimit: EFBIG, 43 } 44 45 // errorUnwrappers is an array of unwrap functions to extract typed errors. 46 var errorUnwrappers = []func(error) (*errors.Error, bool){} 47 48 // AddErrorUnwrapper registers an unwrap method that can extract a concrete error 49 // from a typed, but not initialized, error. 50 func AddErrorUnwrapper(unwrap func(e error) (*errors.Error, bool)) { 51 errorUnwrappers = append(errorUnwrappers, unwrap) 52 } 53 54 // TranslateError translates errors to errnos, it will return false if 55 // the error was not registered. 56 func TranslateError(from error) (*errors.Error, bool) { 57 if err, ok := errorMap[from]; ok { 58 return err, true 59 } 60 // Try to unwrap the error if we couldn't match an error 61 // exactly. This might mean that a package has its own 62 // error type. 63 for _, unwrap := range errorUnwrappers { 64 if err, ok := unwrap(from); ok { 65 return err, true 66 } 67 } 68 return nil, false 69 } 70 71 // These errors are significant because ptrace syscall exit tracing can 72 // observe them. 73 // 74 // For all of the following errors, if the syscall is not interrupted by a 75 // signal delivered to a user handler, the syscall is restarted. 76 var ( 77 // ERESTARTSYS is returned by an interrupted syscall to indicate that it 78 // should be converted to EINTR if interrupted by a signal delivered to a 79 // user handler without SA_RESTART set, and restarted otherwise. 80 ERESTARTSYS = errors.New(errno.ERESTARTSYS, "to be restarted if SA_RESTART is set") 81 82 // ERESTARTNOINTR is returned by an interrupted syscall to indicate that it 83 // should always be restarted. 84 ERESTARTNOINTR = errors.New(errno.ERESTARTNOINTR, "to be restarted") 85 86 // ERESTARTNOHAND is returned by an interrupted syscall to indicate that it 87 // should be converted to EINTR if interrupted by a signal delivered to a 88 // user handler, and restarted otherwise. 89 ERESTARTNOHAND = errors.New(errno.ERESTARTNOHAND, "to be restarted if no handler") 90 91 // ERESTART_RESTARTBLOCK is returned by an interrupted syscall to indicate 92 // that it should be restarted using a custom function. The interrupted 93 // syscall must register a custom restart function by calling 94 // Task.SetRestartSyscallFn. 95 ERESTART_RESTARTBLOCK = errors.New(errno.ERESTART_RESTARTBLOCK, "interrupted by signal") 96 ) 97 98 var restartMap = map[int]*errors.Error{ 99 -int(errno.ERESTARTSYS): ERESTARTSYS, 100 -int(errno.ERESTARTNOINTR): ERESTARTNOINTR, 101 -int(errno.ERESTARTNOHAND): ERESTARTNOHAND, 102 -int(errno.ERESTART_RESTARTBLOCK): ERESTART_RESTARTBLOCK, 103 } 104 105 // IsRestartError checks if a given error is a restart error. 106 func IsRestartError(err error) bool { 107 switch err { 108 case ERESTARTSYS, ERESTARTNOINTR, ERESTARTNOHAND, ERESTART_RESTARTBLOCK: 109 return true 110 default: 111 return false 112 } 113 } 114 115 // SyscallRestartErrorFromReturn returns the SyscallRestartErrno represented by 116 // rv, the value in a syscall return register. 117 func SyscallRestartErrorFromReturn(rv uintptr) (*errors.Error, bool) { 118 err, ok := restartMap[int(rv)] 119 return err, ok 120 } 121 122 // ConvertIntr converts the provided error code (err) to another one (intr) if 123 // the first error corresponds to an interrupted operation. 124 func ConvertIntr(err, intr error) error { 125 if err == ErrInterrupted { 126 return intr 127 } 128 return err 129 }