// Copyright (c) 2014,2015,2016 Docker, Inc. // Copyright (c) 2017 Intel Corporation // // SPDX-License-Identifier: Apache-2.0 // package main import ( "context" "fmt" "strconv" "syscall" "github.com/kata-containers/runtime/pkg/katautils" vc "github.com/kata-containers/runtime/virtcontainers" "github.com/kata-containers/runtime/virtcontainers/pkg/oci" "github.com/kata-containers/runtime/virtcontainers/types" "github.com/sirupsen/logrus" "github.com/urfave/cli" ) var killCLICommand = cli.Command{ Name: "kill", Usage: "Kill sends signals to the container's init process", ArgsUsage: ` [signal] is the name for the instance of the container [signal] is the signal to be sent to the init process (default: SIGTERM) EXAMPLE: If the container id is "ubuntu01" the following will send a "KILL" signal to the init process of the "ubuntu01" container: # ` + name + ` kill ubuntu01 KILL`, Flags: []cli.Flag{ cli.BoolFlag{ Name: "all, a", Usage: "send the specified signal to all processes inside the container", }, }, Action: func(context *cli.Context) error { ctx, err := cliContextToContext(context) if err != nil { return err } args := context.Args() if !args.Present() { return fmt.Errorf("Missing container ID") } // If signal is provided, it has to be the second argument. signal := args.Get(1) if signal == "" { signal = "SIGTERM" } return kill(ctx, args.First(), signal, context.Bool("all")) }, } var signalList = map[string]syscall.Signal{ "SIGABRT": syscall.SIGABRT, "SIGALRM": syscall.SIGALRM, "SIGBUS": syscall.SIGBUS, "SIGCHLD": syscall.SIGCHLD, "SIGCLD": syscall.SIGCLD, "SIGCONT": syscall.SIGCONT, "SIGFPE": syscall.SIGFPE, "SIGHUP": syscall.SIGHUP, "SIGILL": syscall.SIGILL, "SIGINT": syscall.SIGINT, "SIGIO": syscall.SIGIO, "SIGIOT": syscall.SIGIOT, "SIGKILL": syscall.SIGKILL, "SIGPIPE": syscall.SIGPIPE, "SIGPOLL": syscall.SIGPOLL, "SIGPROF": syscall.SIGPROF, "SIGPWR": syscall.SIGPWR, "SIGQUIT": syscall.SIGQUIT, "SIGSEGV": syscall.SIGSEGV, "SIGSTKFLT": syscall.SIGSTKFLT, "SIGSTOP": syscall.SIGSTOP, "SIGSYS": syscall.SIGSYS, "SIGTERM": syscall.SIGTERM, "SIGTRAP": syscall.SIGTRAP, "SIGTSTP": syscall.SIGTSTP, "SIGTTIN": syscall.SIGTTIN, "SIGTTOU": syscall.SIGTTOU, "SIGUNUSED": syscall.SIGUNUSED, "SIGURG": syscall.SIGURG, "SIGUSR1": syscall.SIGUSR1, "SIGUSR2": syscall.SIGUSR2, "SIGVTALRM": syscall.SIGVTALRM, "SIGWINCH": syscall.SIGWINCH, "SIGXCPU": syscall.SIGXCPU, "SIGXFSZ": syscall.SIGXFSZ, } func kill(ctx context.Context, containerID, signal string, all bool) error { span, _ := katautils.Trace(ctx, "kill") defer span.Finish() kataLog = kataLog.WithField("container", containerID) setExternalLoggers(ctx, kataLog) span.SetTag("container", containerID) // Checks the MUST and MUST NOT from OCI runtime specification status, sandboxID, err := getExistingContainerInfo(ctx, containerID) if err != nil { return err } containerID = status.ID kataLog = kataLog.WithFields(logrus.Fields{ "container": containerID, "sandbox": sandboxID, }) span.SetTag("container", containerID) span.SetTag("sandbox", sandboxID) setExternalLoggers(ctx, kataLog) signum, err := processSignal(signal) if err != nil { return err } kataLog.WithField("signal", signal).WithField("container state", status.State.State).Info("kill") // container MUST be created, running or paused if status.State.State == types.StateReady || status.State.State == types.StateRunning || status.State.State == types.StatePaused { if err := vci.KillContainer(ctx, sandboxID, containerID, signum, all); err != nil { return err } } else if !all { return fmt.Errorf("container not running") } if signum != syscall.SIGKILL && signum != syscall.SIGTERM { return nil } containerType, err := oci.GetContainerType(status.Annotations) if err != nil { return err } switch containerType { case vc.PodSandbox: _, err = vci.StopSandbox(ctx, sandboxID, signum == syscall.SIGKILL) case vc.PodContainer: _, err = vci.StopContainer(ctx, sandboxID, containerID) default: return fmt.Errorf("Invalid container type found") } return err } func processSignal(signal string) (syscall.Signal, error) { signum, signalOk := signalList[signal] if signalOk { return signum, nil } // Support for short name signals (INT) signum, signalOk = signalList["SIG"+signal] if signalOk { return signum, nil } // Support for numeric signals s, err := strconv.Atoi(signal) if err != nil { return 0, fmt.Errorf("Failed to convert signal %s to int", signal) } signum = syscall.Signal(s) // Check whether signal is valid or not for _, sig := range signalList { if sig == signum { // signal is a valid signal return signum, nil } } return 0, fmt.Errorf("Signal %s is not supported", signal) }