github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/runsc/cmd/kill.go (about)

     1  // Copyright 2018 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package cmd
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  	"strconv"
    21  	"strings"
    22  
    23  	"github.com/google/subcommands"
    24  	"golang.org/x/sys/unix"
    25  	"github.com/SagerNet/gvisor/runsc/config"
    26  	"github.com/SagerNet/gvisor/runsc/container"
    27  	"github.com/SagerNet/gvisor/runsc/flag"
    28  )
    29  
    30  // Kill implements subcommands.Command for the "kill" command.
    31  type Kill struct {
    32  	all bool
    33  	pid int
    34  }
    35  
    36  // Name implements subcommands.Command.Name.
    37  func (*Kill) Name() string {
    38  	return "kill"
    39  }
    40  
    41  // Synopsis implements subcommands.Command.Synopsis.
    42  func (*Kill) Synopsis() string {
    43  	return "sends a signal to the container"
    44  }
    45  
    46  // Usage implements subcommands.Command.Usage.
    47  func (*Kill) Usage() string {
    48  	return `kill <container id> [signal]`
    49  }
    50  
    51  // SetFlags implements subcommands.Command.SetFlags.
    52  func (k *Kill) SetFlags(f *flag.FlagSet) {
    53  	f.BoolVar(&k.all, "all", false, "send the specified signal to all processes inside the container")
    54  	f.IntVar(&k.pid, "pid", 0, "send the specified signal to a specific process. pid is relative to the root PID namespace")
    55  }
    56  
    57  // Execute implements subcommands.Command.Execute.
    58  func (k *Kill) Execute(_ context.Context, f *flag.FlagSet, args ...interface{}) subcommands.ExitStatus {
    59  	if f.NArg() == 0 || f.NArg() > 2 {
    60  		f.Usage()
    61  		return subcommands.ExitUsageError
    62  	}
    63  
    64  	id := f.Arg(0)
    65  	conf := args[0].(*config.Config)
    66  
    67  	if k.pid != 0 && k.all {
    68  		Fatalf("it is invalid to specify both --all and --pid")
    69  	}
    70  
    71  	c, err := container.Load(conf.RootDir, container.FullID{ContainerID: id}, container.LoadOpts{})
    72  	if err != nil {
    73  		Fatalf("loading container: %v", err)
    74  	}
    75  
    76  	// The OCI command-line spec says that the signal should be specified
    77  	// via a flag, but runc (and things that call runc) pass it as an
    78  	// argument.
    79  	signal := f.Arg(1)
    80  	if signal == "" {
    81  		signal = "TERM"
    82  	}
    83  
    84  	sig, err := parseSignal(signal)
    85  	if err != nil {
    86  		Fatalf("%v", err)
    87  	}
    88  
    89  	if k.pid != 0 {
    90  		if err := c.SignalProcess(sig, int32(k.pid)); err != nil {
    91  			Fatalf("failed to signal pid %d: %v", k.pid, err)
    92  		}
    93  	} else {
    94  		if err := c.SignalContainer(sig, k.all); err != nil {
    95  			Fatalf("%v", err)
    96  		}
    97  	}
    98  	return subcommands.ExitSuccess
    99  }
   100  
   101  func parseSignal(s string) (unix.Signal, error) {
   102  	n, err := strconv.Atoi(s)
   103  	if err == nil {
   104  		sig := unix.Signal(n)
   105  		for _, msig := range signalMap {
   106  			if sig == msig {
   107  				return sig, nil
   108  			}
   109  		}
   110  		return -1, fmt.Errorf("unknown signal %q", s)
   111  	}
   112  	if sig, ok := signalMap[strings.TrimPrefix(strings.ToUpper(s), "SIG")]; ok {
   113  		return sig, nil
   114  	}
   115  	return -1, fmt.Errorf("unknown signal %q", s)
   116  }
   117  
   118  var signalMap = map[string]unix.Signal{
   119  	"ABRT":   unix.SIGABRT,
   120  	"ALRM":   unix.SIGALRM,
   121  	"BUS":    unix.SIGBUS,
   122  	"CHLD":   unix.SIGCHLD,
   123  	"CLD":    unix.SIGCLD,
   124  	"CONT":   unix.SIGCONT,
   125  	"FPE":    unix.SIGFPE,
   126  	"HUP":    unix.SIGHUP,
   127  	"ILL":    unix.SIGILL,
   128  	"INT":    unix.SIGINT,
   129  	"IO":     unix.SIGIO,
   130  	"IOT":    unix.SIGIOT,
   131  	"KILL":   unix.SIGKILL,
   132  	"PIPE":   unix.SIGPIPE,
   133  	"POLL":   unix.SIGPOLL,
   134  	"PROF":   unix.SIGPROF,
   135  	"PWR":    unix.SIGPWR,
   136  	"QUIT":   unix.SIGQUIT,
   137  	"SEGV":   unix.SIGSEGV,
   138  	"STKFLT": unix.SIGSTKFLT,
   139  	"STOP":   unix.SIGSTOP,
   140  	"SYS":    unix.SIGSYS,
   141  	"TERM":   unix.SIGTERM,
   142  	"TRAP":   unix.SIGTRAP,
   143  	"TSTP":   unix.SIGTSTP,
   144  	"TTIN":   unix.SIGTTIN,
   145  	"TTOU":   unix.SIGTTOU,
   146  	"URG":    unix.SIGURG,
   147  	"USR1":   unix.SIGUSR1,
   148  	"USR2":   unix.SIGUSR2,
   149  	"VTALRM": unix.SIGVTALRM,
   150  	"WINCH":  unix.SIGWINCH,
   151  	"XCPU":   unix.SIGXCPU,
   152  	"XFSZ":   unix.SIGXFSZ,
   153  }