utils.go 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. // +build !windows
  2. /*
  3. Copyright The containerd Authors.
  4. Licensed under the Apache License, Version 2.0 (the "License");
  5. you may not use this file except in compliance with the License.
  6. You may obtain a copy of the License at
  7. http://www.apache.org/licenses/LICENSE-2.0
  8. Unless required by applicable law or agreed to in writing, software
  9. distributed under the License is distributed on an "AS IS" BASIS,
  10. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11. See the License for the specific language governing permissions and
  12. limitations under the License.
  13. */
  14. package proc
  15. import (
  16. "encoding/json"
  17. "fmt"
  18. "io"
  19. "os"
  20. "path/filepath"
  21. "strings"
  22. "sync"
  23. "time"
  24. "github.com/containerd/containerd/errdefs"
  25. runc "github.com/containerd/go-runc"
  26. "github.com/pkg/errors"
  27. "golang.org/x/sys/unix"
  28. )
  29. // safePid is a thread safe wrapper for pid.
  30. type safePid struct {
  31. sync.Mutex
  32. pid int
  33. }
  34. func (s *safePid) get() int {
  35. s.Lock()
  36. defer s.Unlock()
  37. return s.pid
  38. }
  39. // TODO(mlaventure): move to runc package?
  40. func getLastRuntimeError(r *runc.Runc) (string, error) {
  41. if r.Log == "" {
  42. return "", nil
  43. }
  44. f, err := os.OpenFile(r.Log, os.O_RDONLY, 0400)
  45. if err != nil {
  46. return "", err
  47. }
  48. var (
  49. errMsg string
  50. log struct {
  51. Level string
  52. Msg string
  53. Time time.Time
  54. }
  55. )
  56. dec := json.NewDecoder(f)
  57. for err = nil; err == nil; {
  58. if err = dec.Decode(&log); err != nil && err != io.EOF {
  59. return "", err
  60. }
  61. if log.Level == "error" {
  62. errMsg = strings.TrimSpace(log.Msg)
  63. }
  64. }
  65. return errMsg, nil
  66. }
  67. // criuError returns only the first line of the error message from criu
  68. // it tries to add an invalid dump log location when returning the message
  69. func criuError(err error) string {
  70. parts := strings.Split(err.Error(), "\n")
  71. return parts[0]
  72. }
  73. func copyFile(to, from string) error {
  74. ff, err := os.Open(from)
  75. if err != nil {
  76. return err
  77. }
  78. defer ff.Close()
  79. tt, err := os.Create(to)
  80. if err != nil {
  81. return err
  82. }
  83. defer tt.Close()
  84. p := bufPool.Get().(*[]byte)
  85. defer bufPool.Put(p)
  86. _, err = io.CopyBuffer(tt, ff, *p)
  87. return err
  88. }
  89. func checkKillError(err error) error {
  90. if err == nil {
  91. return nil
  92. }
  93. if strings.Contains(err.Error(), "os: process already finished") ||
  94. strings.Contains(err.Error(), "container not running") ||
  95. err == unix.ESRCH {
  96. return errors.Wrapf(errdefs.ErrNotFound, "process already finished")
  97. }
  98. return errors.Wrapf(err, "unknown error after kill")
  99. }
  100. // InitPidFile name of the file that contains the init pid
  101. const InitPidFile = "init.pid"
  102. func newPidFile(bundle string) *pidFile {
  103. return &pidFile{
  104. path: filepath.Join(bundle, InitPidFile),
  105. }
  106. }
  107. func newExecPidFile(bundle, id string) *pidFile {
  108. return &pidFile{
  109. path: filepath.Join(bundle, fmt.Sprintf("%s.pid", id)),
  110. }
  111. }
  112. type pidFile struct {
  113. path string
  114. }
  115. func (p *pidFile) Path() string {
  116. return p.path
  117. }
  118. func (p *pidFile) Read() (int, error) {
  119. return runc.ReadPidFile(p.path)
  120. }