utils.go 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. package docker
  2. /*
  3. #include <sys/ioctl.h>
  4. #include <linux/fs.h>
  5. #include <errno.h>
  6. // See linux.git/fs/btrfs/ioctl.h
  7. #define BTRFS_IOCTL_MAGIC 0x94
  8. #define BTRFS_IOC_CLONE _IOW(BTRFS_IOCTL_MAGIC, 9, int)
  9. int
  10. btrfs_reflink(int fd_out, int fd_in)
  11. {
  12. int res;
  13. res = ioctl(fd_out, BTRFS_IOC_CLONE, fd_in);
  14. if (res < 0)
  15. return errno;
  16. return 0;
  17. }
  18. */
  19. import "C"
  20. import (
  21. "fmt"
  22. "io"
  23. "io/ioutil"
  24. "os"
  25. "strings"
  26. "syscall"
  27. )
  28. // Compare two Config struct. Do not compare the "Image" nor "Hostname" fields
  29. // If OpenStdin is set, then it differs
  30. func CompareConfig(a, b *Config) bool {
  31. if a == nil || b == nil ||
  32. a.OpenStdin || b.OpenStdin {
  33. return false
  34. }
  35. if a.AttachStdout != b.AttachStdout ||
  36. a.AttachStderr != b.AttachStderr ||
  37. a.User != b.User ||
  38. a.Memory != b.Memory ||
  39. a.MemorySwap != b.MemorySwap ||
  40. a.CpuShares != b.CpuShares ||
  41. a.OpenStdin != b.OpenStdin ||
  42. a.Tty != b.Tty ||
  43. a.VolumesFrom != b.VolumesFrom {
  44. return false
  45. }
  46. if len(a.Cmd) != len(b.Cmd) ||
  47. len(a.Dns) != len(b.Dns) ||
  48. len(a.Env) != len(b.Env) ||
  49. len(a.PortSpecs) != len(b.PortSpecs) ||
  50. len(a.Entrypoint) != len(b.Entrypoint) ||
  51. len(a.Volumes) != len(b.Volumes) {
  52. return false
  53. }
  54. for i := 0; i < len(a.Cmd); i++ {
  55. if a.Cmd[i] != b.Cmd[i] {
  56. return false
  57. }
  58. }
  59. for i := 0; i < len(a.Dns); i++ {
  60. if a.Dns[i] != b.Dns[i] {
  61. return false
  62. }
  63. }
  64. for i := 0; i < len(a.Env); i++ {
  65. if a.Env[i] != b.Env[i] {
  66. return false
  67. }
  68. }
  69. for i := 0; i < len(a.PortSpecs); i++ {
  70. if a.PortSpecs[i] != b.PortSpecs[i] {
  71. return false
  72. }
  73. }
  74. for i := 0; i < len(a.Entrypoint); i++ {
  75. if a.Entrypoint[i] != b.Entrypoint[i] {
  76. return false
  77. }
  78. }
  79. for key := range a.Volumes {
  80. if _, exists := b.Volumes[key]; !exists {
  81. return false
  82. }
  83. }
  84. return true
  85. }
  86. func MergeConfig(userConf, imageConf *Config) {
  87. if userConf.User == "" {
  88. userConf.User = imageConf.User
  89. }
  90. if userConf.Memory == 0 {
  91. userConf.Memory = imageConf.Memory
  92. }
  93. if userConf.MemorySwap == 0 {
  94. userConf.MemorySwap = imageConf.MemorySwap
  95. }
  96. if userConf.CpuShares == 0 {
  97. userConf.CpuShares = imageConf.CpuShares
  98. }
  99. if userConf.PortSpecs == nil || len(userConf.PortSpecs) == 0 {
  100. userConf.PortSpecs = imageConf.PortSpecs
  101. } else {
  102. for _, imagePortSpec := range imageConf.PortSpecs {
  103. found := false
  104. imageNat, _ := parseNat(imagePortSpec)
  105. for _, userPortSpec := range userConf.PortSpecs {
  106. userNat, _ := parseNat(userPortSpec)
  107. if imageNat.Proto == userNat.Proto && imageNat.Backend == userNat.Backend {
  108. found = true
  109. }
  110. }
  111. if !found {
  112. userConf.PortSpecs = append(userConf.PortSpecs, imagePortSpec)
  113. }
  114. }
  115. }
  116. if !userConf.Tty {
  117. userConf.Tty = imageConf.Tty
  118. }
  119. if !userConf.OpenStdin {
  120. userConf.OpenStdin = imageConf.OpenStdin
  121. }
  122. if !userConf.StdinOnce {
  123. userConf.StdinOnce = imageConf.StdinOnce
  124. }
  125. if userConf.Env == nil || len(userConf.Env) == 0 {
  126. userConf.Env = imageConf.Env
  127. } else {
  128. for _, imageEnv := range imageConf.Env {
  129. found := false
  130. imageEnvKey := strings.Split(imageEnv, "=")[0]
  131. for _, userEnv := range userConf.Env {
  132. userEnvKey := strings.Split(userEnv, "=")[0]
  133. if imageEnvKey == userEnvKey {
  134. found = true
  135. }
  136. }
  137. if !found {
  138. userConf.Env = append(userConf.Env, imageEnv)
  139. }
  140. }
  141. }
  142. if userConf.Cmd == nil || len(userConf.Cmd) == 0 {
  143. userConf.Cmd = imageConf.Cmd
  144. }
  145. if userConf.Dns == nil || len(userConf.Dns) == 0 {
  146. userConf.Dns = imageConf.Dns
  147. } else {
  148. //duplicates aren't an issue here
  149. userConf.Dns = append(userConf.Dns, imageConf.Dns...)
  150. }
  151. if userConf.Entrypoint == nil || len(userConf.Entrypoint) == 0 {
  152. userConf.Entrypoint = imageConf.Entrypoint
  153. }
  154. if userConf.WorkingDir == "" {
  155. userConf.WorkingDir = imageConf.WorkingDir
  156. }
  157. if userConf.VolumesFrom == "" {
  158. userConf.VolumesFrom = imageConf.VolumesFrom
  159. }
  160. if userConf.Volumes == nil || len(userConf.Volumes) == 0 {
  161. userConf.Volumes = imageConf.Volumes
  162. } else {
  163. for k, v := range imageConf.Volumes {
  164. userConf.Volumes[k] = v
  165. }
  166. }
  167. }
  168. func parseLxcConfOpts(opts ListOpts) ([]KeyValuePair, error) {
  169. out := make([]KeyValuePair, len(opts))
  170. for i, o := range opts {
  171. k, v, err := parseLxcOpt(o)
  172. if err != nil {
  173. return nil, err
  174. }
  175. out[i] = KeyValuePair{Key: k, Value: v}
  176. }
  177. return out, nil
  178. }
  179. func parseLxcOpt(opt string) (string, string, error) {
  180. parts := strings.SplitN(opt, "=", 2)
  181. if len(parts) != 2 {
  182. return "", "", fmt.Errorf("Unable to parse lxc conf option: %s", opt)
  183. }
  184. return strings.TrimSpace(parts[0]), strings.TrimSpace(parts[1]), nil
  185. }
  186. func RootIsShared() bool {
  187. if data, err := ioutil.ReadFile("/proc/self/mountinfo"); err == nil {
  188. for _, line := range strings.Split(string(data), "\n") {
  189. cols := strings.Split(line, " ")
  190. if len(cols) >= 6 && cols[4] == "/" {
  191. return strings.HasPrefix(cols[6], "shared")
  192. }
  193. }
  194. }
  195. // No idea, probably safe to assume so
  196. return true
  197. }
  198. func BtrfsReflink(fd_out, fd_in uintptr) error {
  199. res := C.btrfs_reflink(C.int(fd_out), C.int(fd_in))
  200. if res != 0 {
  201. return syscall.Errno(res)
  202. }
  203. return nil
  204. }
  205. func CopyFile(dstFile, srcFile *os.File) error {
  206. err := BtrfsReflink(dstFile.Fd(), srcFile.Fd())
  207. if err == nil {
  208. return nil
  209. }
  210. // Fall back to normal copy
  211. _, err = io.Copy(dstFile, srcFile)
  212. return err
  213. }