123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144 |
- // +build !windows
- /*
- Copyright The containerd Authors.
- 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 proc
- import (
- "encoding/json"
- "fmt"
- "io"
- "os"
- "path/filepath"
- "strings"
- "sync"
- "time"
- "github.com/containerd/containerd/errdefs"
- runc "github.com/containerd/go-runc"
- "github.com/pkg/errors"
- "golang.org/x/sys/unix"
- )
- // safePid is a thread safe wrapper for pid.
- type safePid struct {
- sync.Mutex
- pid int
- }
- func (s *safePid) get() int {
- s.Lock()
- defer s.Unlock()
- return s.pid
- }
- // TODO(mlaventure): move to runc package?
- func getLastRuntimeError(r *runc.Runc) (string, error) {
- if r.Log == "" {
- return "", nil
- }
- f, err := os.OpenFile(r.Log, os.O_RDONLY, 0400)
- if err != nil {
- return "", err
- }
- var (
- errMsg string
- log struct {
- Level string
- Msg string
- Time time.Time
- }
- )
- dec := json.NewDecoder(f)
- for err = nil; err == nil; {
- if err = dec.Decode(&log); err != nil && err != io.EOF {
- return "", err
- }
- if log.Level == "error" {
- errMsg = strings.TrimSpace(log.Msg)
- }
- }
- return errMsg, nil
- }
- // criuError returns only the first line of the error message from criu
- // it tries to add an invalid dump log location when returning the message
- func criuError(err error) string {
- parts := strings.Split(err.Error(), "\n")
- return parts[0]
- }
- func copyFile(to, from string) error {
- ff, err := os.Open(from)
- if err != nil {
- return err
- }
- defer ff.Close()
- tt, err := os.Create(to)
- if err != nil {
- return err
- }
- defer tt.Close()
- p := bufPool.Get().(*[]byte)
- defer bufPool.Put(p)
- _, err = io.CopyBuffer(tt, ff, *p)
- return err
- }
- func checkKillError(err error) error {
- if err == nil {
- return nil
- }
- if strings.Contains(err.Error(), "os: process already finished") ||
- strings.Contains(err.Error(), "container not running") ||
- err == unix.ESRCH {
- return errors.Wrapf(errdefs.ErrNotFound, "process already finished")
- }
- return errors.Wrapf(err, "unknown error after kill")
- }
- // InitPidFile name of the file that contains the init pid
- const InitPidFile = "init.pid"
- func newPidFile(bundle string) *pidFile {
- return &pidFile{
- path: filepath.Join(bundle, InitPidFile),
- }
- }
- func newExecPidFile(bundle, id string) *pidFile {
- return &pidFile{
- path: filepath.Join(bundle, fmt.Sprintf("%s.pid", id)),
- }
- }
- type pidFile struct {
- path string
- }
- func (p *pidFile) Path() string {
- return p.path
- }
- func (p *pidFile) Read() (int, error) {
- return runc.ReadPidFile(p.path)
- }
|