| 
									
										
										
										
											2016-08-26 00:39:01 +08:00
										 |  |  | /* | 
					
						
							|  |  |  |  * Minio Cloud Storage, (C) 2016 Minio, Inc. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Licensed under the Apache License, Version 2.0 (the "License"); | 
					
						
							|  |  |  |  * you may not use this file except in compliance with the License. | 
					
						
							|  |  |  |  * You may obtain a copy of the License at | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *     http://www.apache.org/licenses/LICENSE-2.0
 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Unless required by applicable law or agreed to in writing, software | 
					
						
							|  |  |  |  * distributed under the License is distributed on an "AS IS" BASIS, | 
					
						
							|  |  |  |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
					
						
							|  |  |  |  * See the License for the specific language governing permissions and | 
					
						
							|  |  |  |  * limitations under the License. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | package cmd | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"fmt" | 
					
						
							|  |  |  | 	"os" | 
					
						
							|  |  |  | 	"path/filepath" | 
					
						
							|  |  |  | 	"runtime" | 
					
						
							|  |  |  | 	"strings" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Holds the current directory path. Used for trimming path in traceError()
 | 
					
						
							|  |  |  | var rootPath string | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Figure out the rootPath
 | 
					
						
							|  |  |  | func initError() { | 
					
						
							|  |  |  | 	// Root path is automatically determined from the calling function's source file location.
 | 
					
						
							|  |  |  | 	// Catch the calling function's source file path.
 | 
					
						
							|  |  |  | 	_, file, _, _ := runtime.Caller(1) | 
					
						
							|  |  |  | 	// Save the directory alone.
 | 
					
						
							|  |  |  | 	rootPath = filepath.Dir(file) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Represents a stack frame in the stack trace.
 | 
					
						
							|  |  |  | type traceInfo struct { | 
					
						
							|  |  |  | 	file string // File where error occurred
 | 
					
						
							|  |  |  | 	line int    // Line where error occurred
 | 
					
						
							|  |  |  | 	name string // Name of the function where error occurred
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Error - error type containing cause and the stack trace.
 | 
					
						
							|  |  |  | type Error struct { | 
					
						
							|  |  |  | 	e     error       // Holds the cause error
 | 
					
						
							|  |  |  | 	trace []traceInfo // stack trace
 | 
					
						
							|  |  |  | 	errs  []error     // Useful for XL to hold errors from all disks
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Implement error interface.
 | 
					
						
							|  |  |  | func (e Error) Error() string { | 
					
						
							|  |  |  | 	return e.e.Error() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Trace - returns stack trace.
 | 
					
						
							|  |  |  | func (e Error) Trace() []string { | 
					
						
							|  |  |  | 	var traceArr []string | 
					
						
							|  |  |  | 	for _, info := range e.trace { | 
					
						
							|  |  |  | 		traceArr = append(traceArr, fmt.Sprintf("%s:%d:%s", | 
					
						
							|  |  |  | 			info.file, info.line, info.name)) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return traceArr | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // NewStorageError - return new Error type.
 | 
					
						
							|  |  |  | func traceError(e error, errs ...error) error { | 
					
						
							|  |  |  | 	if e == nil { | 
					
						
							|  |  |  | 		return nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	err := &Error{} | 
					
						
							|  |  |  | 	err.e = e | 
					
						
							|  |  |  | 	err.errs = errs | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	stack := make([]uintptr, 40) | 
					
						
							|  |  |  | 	length := runtime.Callers(2, stack) | 
					
						
							|  |  |  | 	if length > len(stack) { | 
					
						
							|  |  |  | 		length = len(stack) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	stack = stack[:length] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for _, pc := range stack { | 
					
						
							|  |  |  | 		pc = pc - 1 | 
					
						
							|  |  |  | 		fn := runtime.FuncForPC(pc) | 
					
						
							|  |  |  | 		file, line := fn.FileLine(pc) | 
					
						
							|  |  |  | 		name := fn.Name() | 
					
						
							|  |  |  | 		if strings.HasSuffix(name, "ServeHTTP") { | 
					
						
							|  |  |  | 			break | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if strings.HasSuffix(name, "runtime.") { | 
					
						
							|  |  |  | 			break | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		file = strings.TrimPrefix(file, rootPath+string(os.PathSeparator)) | 
					
						
							|  |  |  | 		name = strings.TrimPrefix(name, "github.com/minio/minio/cmd.") | 
					
						
							|  |  |  | 		err.trace = append(err.trace, traceInfo{file, line, name}) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return err | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Returns the underlying cause error.
 | 
					
						
							|  |  |  | func errorCause(err error) error { | 
					
						
							|  |  |  | 	if e, ok := err.(*Error); ok { | 
					
						
							|  |  |  | 		err = e.e | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return err | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Returns slice of underlying cause error.
 | 
					
						
							|  |  |  | func errorsCause(errs []error) []error { | 
					
						
							| 
									
										
										
										
											2016-10-15 10:57:40 +08:00
										 |  |  | 	cerrs := make([]error, len(errs)) | 
					
						
							| 
									
										
										
										
											2016-08-26 00:39:01 +08:00
										 |  |  | 	for i, err := range errs { | 
					
						
							|  |  |  | 		if err == nil { | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-10-15 10:57:40 +08:00
										 |  |  | 		cerrs[i] = errorCause(err) | 
					
						
							| 
									
										
										
										
											2016-08-26 00:39:01 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-10-15 10:57:40 +08:00
										 |  |  | 	return cerrs | 
					
						
							| 
									
										
										
										
											2016-08-26 00:39:01 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2016-11-24 12:05:04 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-03 02:43:56 +08:00
										 |  |  | // Collection of basic errors.
 | 
					
						
							|  |  |  | var baseErrs = []error{ | 
					
						
							| 
									
										
										
										
											2016-11-24 12:05:04 +08:00
										 |  |  | 	errDiskNotFound, | 
					
						
							|  |  |  | 	errFaultyDisk, | 
					
						
							|  |  |  | 	errFaultyRemoteDisk, | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-03 02:43:56 +08:00
										 |  |  | var baseIgnoredErrs = baseErrs | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-24 12:05:04 +08:00
										 |  |  | // isErrIgnored returns whether given error is ignored or not.
 | 
					
						
							|  |  |  | func isErrIgnored(err error, ignoredErrs ...error) bool { | 
					
						
							|  |  |  | 	err = errorCause(err) | 
					
						
							|  |  |  | 	for _, ignoredErr := range ignoredErrs { | 
					
						
							|  |  |  | 		if ignoredErr == err { | 
					
						
							|  |  |  | 			return true | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return false | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2017-01-03 02:43:56 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | // isErr returns whether given error is exact error.
 | 
					
						
							|  |  |  | func isErr(err error, errs ...error) bool { | 
					
						
							|  |  |  | 	err = errorCause(err) | 
					
						
							|  |  |  | 	for _, exactErr := range errs { | 
					
						
							|  |  |  | 		if err == exactErr { | 
					
						
							|  |  |  | 			return true | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return false | 
					
						
							|  |  |  | } |