daemon/kill.go
86528306
 package daemon
 
bc503ca8
 import (
 	"fmt"
 	"runtime"
 	"syscall"
4f2a5ba3
 	"time"
bc503ca8
 
4f2a5ba3
 	"github.com/Sirupsen/logrus"
6bb0d181
 	"github.com/docker/docker/container"
4f2a5ba3
 	derr "github.com/docker/docker/errors"
bc503ca8
 	"github.com/docker/docker/pkg/signal"
 )
86528306
 
 // ContainerKill send signal to the container
 // If no signal is given (sig 0), then Kill with SIGKILL and wait
 // for the container to exit.
 // If a signal is given, then just send it to the container and return.
b08f071e
 func (daemon *Daemon) ContainerKill(name string, sig uint64) error {
d7d512bb
 	container, err := daemon.GetContainer(name)
d25a6537
 	if err != nil {
c79b9bab
 		return err
d25a6537
 	}
 
bc503ca8
 	if sig != 0 && !signal.ValidSignalForPlatform(syscall.Signal(sig)) {
 		return fmt.Errorf("The %s daemon does not support signal %d", runtime.GOOS, sig)
 	}
 
d25a6537
 	// If no signal is passed, or SIGKILL, perform regular Kill (SIGKILL + wait())
 	if sig == 0 || syscall.Signal(sig) == syscall.SIGKILL {
fa7ec908
 		return daemon.Kill(container)
86528306
 	}
fa7ec908
 	return daemon.killWithSignal(container, int(sig))
86528306
 }
4f2a5ba3
 
 // killWithSignal sends the container the given signal. This wrapper for the
 // host specific kill command prepares the container before attempting
 // to send the signal. An error is returned if the container is paused
 // or not running, or if there is a problem returned from the
 // underlying kill command.
6bb0d181
 func (daemon *Daemon) killWithSignal(container *container.Container, sig int) error {
4f2a5ba3
 	logrus.Debugf("Sending %d to %s", sig, container.ID)
 	container.Lock()
 	defer container.Unlock()
 
 	// We could unpause the container for them rather than returning this error
 	if container.Paused {
 		return derr.ErrorCodeUnpauseContainer.WithArgs(container.ID)
 	}
 
 	if !container.Running {
 		return derr.ErrorCodeNotRunning.WithArgs(container.ID)
 	}
 
 	container.ExitOnNext()
 
 	// if the container is currently restarting we do not need to send the signal
 	// to the process.  Telling the monitor that it should exit on it's next event
 	// loop is enough
 	if container.Restarting {
 		return nil
 	}
 
 	if err := daemon.kill(container, sig); err != nil {
 		return err
 	}
 
ca5ede2d
 	daemon.LogContainerEvent(container, "kill")
4f2a5ba3
 	return nil
 }
 
 // Kill forcefully terminates a container.
6bb0d181
 func (daemon *Daemon) Kill(container *container.Container) error {
4f2a5ba3
 	if !container.IsRunning() {
 		return derr.ErrorCodeNotRunning.WithArgs(container.ID)
 	}
 
 	// 1. Send SIGKILL
 	if err := daemon.killPossiblyDeadProcess(container, int(syscall.SIGKILL)); err != nil {
 		// While normally we might "return err" here we're not going to
 		// because if we can't stop the container by this point then
 		// its probably because its already stopped. Meaning, between
 		// the time of the IsRunning() call above and now it stopped.
 		// Also, since the err return will be exec driver specific we can't
 		// look for any particular (common) error that would indicate
 		// that the process is already dead vs something else going wrong.
 		// So, instead we'll give it up to 2 more seconds to complete and if
 		// by that time the container is still running, then the error
 		// we got is probably valid and so we return it to the caller.
 
 		if container.IsRunning() {
 			container.WaitStop(2 * time.Second)
 			if container.IsRunning() {
 				return err
 			}
 		}
 	}
 
 	// 2. Wait for the process to die, in last resort, try to kill the process directly
 	if err := killProcessDirectly(container); err != nil {
 		return err
 	}
 
 	container.WaitStop(-1 * time.Second)
 	return nil
 }
 
927b334e
 // killPossibleDeadProcess is a wrapper around killSig() suppressing "no such process" error.
6bb0d181
 func (daemon *Daemon) killPossiblyDeadProcess(container *container.Container, sig int) error {
4f2a5ba3
 	err := daemon.killWithSignal(container, sig)
 	if err == syscall.ESRCH {
 		logrus.Debugf("Cannot kill process (pid=%d) with signal %d: no such process.", container.GetPID(), sig)
 		return nil
 	}
 	return err
 }