github.com/endocode/docker@v1.4.2-0.20160113120958-46eb4700391e/utils/utils.go (about) 1 package utils 2 3 import ( 4 "crypto/sha1" 5 "encoding/hex" 6 "fmt" 7 "io" 8 "io/ioutil" 9 "os" 10 "os/exec" 11 "path/filepath" 12 "runtime" 13 "strings" 14 15 "github.com/docker/distribution/registry/api/errcode" 16 "github.com/docker/docker/dockerversion" 17 "github.com/docker/docker/pkg/archive" 18 "github.com/docker/docker/pkg/stringid" 19 ) 20 21 // SelfPath figures out the absolute path of our own binary (if it's still around). 22 func SelfPath() string { 23 path, err := exec.LookPath(os.Args[0]) 24 if err != nil { 25 if os.IsNotExist(err) { 26 return "" 27 } 28 if execErr, ok := err.(*exec.Error); ok && os.IsNotExist(execErr.Err) { 29 return "" 30 } 31 panic(err) 32 } 33 path, err = filepath.Abs(path) 34 if err != nil { 35 if os.IsNotExist(err) { 36 return "" 37 } 38 panic(err) 39 } 40 return path 41 } 42 43 func dockerInitSha1(target string) string { 44 f, err := os.Open(target) 45 if err != nil { 46 return "" 47 } 48 defer f.Close() 49 h := sha1.New() 50 _, err = io.Copy(h, f) 51 if err != nil { 52 return "" 53 } 54 return hex.EncodeToString(h.Sum(nil)) 55 } 56 57 func isValidDockerInitPath(target string, selfPath string) bool { // target and selfPath should be absolute (InitPath and SelfPath already do this) 58 if target == "" { 59 return false 60 } 61 if dockerversion.IAmStatic == "true" { 62 if selfPath == "" { 63 return false 64 } 65 if target == selfPath { 66 return true 67 } 68 targetFileInfo, err := os.Lstat(target) 69 if err != nil { 70 return false 71 } 72 selfPathFileInfo, err := os.Lstat(selfPath) 73 if err != nil { 74 return false 75 } 76 return os.SameFile(targetFileInfo, selfPathFileInfo) 77 } 78 return dockerversion.InitSHA1 != "" && dockerInitSha1(target) == dockerversion.InitSHA1 79 } 80 81 // DockerInitPath figures out the path of our dockerinit (which may be SelfPath()) 82 func DockerInitPath(localCopy string) string { 83 selfPath := SelfPath() 84 if isValidDockerInitPath(selfPath, selfPath) { 85 // if we're valid, don't bother checking anything else 86 return selfPath 87 } 88 var possibleInits = []string{ 89 localCopy, 90 dockerversion.InitPath, 91 filepath.Join(filepath.Dir(selfPath), "dockerinit"), 92 93 // FHS 3.0 Draft: "/usr/libexec includes internal binaries that are not intended to be executed directly by users or shell scripts. Applications may use a single subdirectory under /usr/libexec." 94 // https://www.linuxbase.org/betaspecs/fhs/fhs.html#usrlibexec 95 "/usr/libexec/docker/dockerinit", 96 "/usr/local/libexec/docker/dockerinit", 97 98 // FHS 2.3: "/usr/lib includes object files, libraries, and internal binaries that are not intended to be executed directly by users or shell scripts." 99 // https://refspecs.linuxfoundation.org/FHS_2.3/fhs-2.3.html#USRLIBLIBRARIESFORPROGRAMMINGANDPA 100 "/usr/lib/docker/dockerinit", 101 "/usr/local/lib/docker/dockerinit", 102 } 103 for _, dockerInit := range possibleInits { 104 if dockerInit == "" { 105 continue 106 } 107 path, err := exec.LookPath(dockerInit) 108 if err == nil { 109 path, err = filepath.Abs(path) 110 if err != nil { 111 // LookPath already validated that this file exists and is executable (following symlinks), so how could Abs fail? 112 panic(err) 113 } 114 if isValidDockerInitPath(path, selfPath) { 115 return path 116 } 117 } 118 } 119 return "" 120 } 121 122 var globalTestID string 123 124 // TestDirectory creates a new temporary directory and returns its path. 125 // The contents of directory at path `templateDir` is copied into the 126 // new directory. 127 func TestDirectory(templateDir string) (dir string, err error) { 128 if globalTestID == "" { 129 globalTestID = stringid.GenerateNonCryptoID()[:4] 130 } 131 prefix := fmt.Sprintf("docker-test%s-%s-", globalTestID, GetCallerName(2)) 132 if prefix == "" { 133 prefix = "docker-test-" 134 } 135 dir, err = ioutil.TempDir("", prefix) 136 if err = os.Remove(dir); err != nil { 137 return 138 } 139 if templateDir != "" { 140 if err = archive.CopyWithTar(templateDir, dir); err != nil { 141 return 142 } 143 } 144 return 145 } 146 147 // GetCallerName introspects the call stack and returns the name of the 148 // function `depth` levels down in the stack. 149 func GetCallerName(depth int) string { 150 // Use the caller function name as a prefix. 151 // This helps trace temp directories back to their test. 152 pc, _, _, _ := runtime.Caller(depth + 1) 153 callerLongName := runtime.FuncForPC(pc).Name() 154 parts := strings.Split(callerLongName, ".") 155 callerShortName := parts[len(parts)-1] 156 return callerShortName 157 } 158 159 // ReplaceOrAppendEnvValues returns the defaults with the overrides either 160 // replaced by env key or appended to the list 161 func ReplaceOrAppendEnvValues(defaults, overrides []string) []string { 162 cache := make(map[string]int, len(defaults)) 163 for i, e := range defaults { 164 parts := strings.SplitN(e, "=", 2) 165 cache[parts[0]] = i 166 } 167 168 for _, value := range overrides { 169 // Values w/o = means they want this env to be removed/unset. 170 if !strings.Contains(value, "=") { 171 if i, exists := cache[value]; exists { 172 defaults[i] = "" // Used to indicate it should be removed 173 } 174 continue 175 } 176 177 // Just do a normal set/update 178 parts := strings.SplitN(value, "=", 2) 179 if i, exists := cache[parts[0]]; exists { 180 defaults[i] = value 181 } else { 182 defaults = append(defaults, value) 183 } 184 } 185 186 // Now remove all entries that we want to "unset" 187 for i := 0; i < len(defaults); i++ { 188 if defaults[i] == "" { 189 defaults = append(defaults[:i], defaults[i+1:]...) 190 i-- 191 } 192 } 193 194 return defaults 195 } 196 197 // GetErrorMessage returns the human readable message associated with 198 // the passed-in error. In some cases the default Error() func returns 199 // something that is less than useful so based on its types this func 200 // will go and get a better piece of text. 201 func GetErrorMessage(err error) string { 202 switch err.(type) { 203 case errcode.Error: 204 e, _ := err.(errcode.Error) 205 return e.Message 206 207 case errcode.ErrorCode: 208 ec, _ := err.(errcode.ErrorCode) 209 return ec.Message() 210 211 default: 212 return err.Error() 213 } 214 }