gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/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  	"gvisor.dev/gvisor/runsc/cmd/util"
    26  	"gvisor.dev/gvisor/runsc/config"
    27  	"gvisor.dev/gvisor/runsc/container"
    28  	"gvisor.dev/gvisor/runsc/flag"
    29  )
    30  
    31  // Kill implements subcommands.Command for the "kill" command.
    32  type Kill struct {
    33  	all bool
    34  	pid int
    35  }
    36  
    37  // Name implements subcommands.Command.Name.
    38  func (*Kill) Name() string {
    39  	return "kill"
    40  }
    41  
    42  // Synopsis implements subcommands.Command.Synopsis.
    43  func (*Kill) Synopsis() string {
    44  	return "sends a signal to the container"
    45  }
    46  
    47  // Usage implements subcommands.Command.Usage.
    48  func (*Kill) Usage() string {
    49  	return `kill <container id> [signal]`
    50  }
    51  
    52  // SetFlags implements subcommands.Command.SetFlags.
    53  func (k *Kill) SetFlags(f *flag.FlagSet) {
    54  	f.BoolVar(&k.all, "all", false, "send the specified signal to all processes inside the container")
    55  	f.IntVar(&k.pid, "pid", 0, "send the specified signal to a specific process. pid is relative to the root PID namespace")
    56  }
    57  
    58  // Execute implements subcommands.Command.Execute.
    59  func (k *Kill) Execute(_ context.Context, f *flag.FlagSet, args ...any) subcommands.ExitStatus {
    60  	if f.NArg() == 0 || f.NArg() > 2 {
    61  		f.Usage()
    62  		return subcommands.ExitUsageError
    63  	}
    64  
    65  	id := f.Arg(0)
    66  	conf := args[0].(*config.Config)
    67  
    68  	if k.pid != 0 && k.all {
    69  		util.Fatalf("it is invalid to specify both --all and --pid")
    70  	}
    71  
    72  	c, err := container.Load(conf.RootDir, container.FullID{ContainerID: id}, container.LoadOpts{})
    73  	if err != nil {
    74  		util.Fatalf("loading container: %v", err)
    75  	}
    76  
    77  	// The OCI command-line spec says that the signal should be specified
    78  	// via a flag, but runc (and things that call runc) pass it as an
    79  	// argument.
    80  	signal := f.Arg(1)
    81  	if signal == "" {
    82  		signal = "TERM"
    83  	}
    84  
    85  	sig, err := parseSignal(signal)
    86  	if err != nil {
    87  		util.Fatalf("%v", err)
    88  	}
    89  
    90  	if k.pid != 0 {
    91  		if err := c.SignalProcess(sig, int32(k.pid)); err != nil {
    92  			util.Fatalf("failed to signal pid %d: %v", k.pid, err)
    93  		}
    94  	} else {
    95  		if err := c.SignalContainer(sig, k.all); err != nil {
    96  			util.Fatalf("%v", err)
    97  		}
    98  	}
    99  	return subcommands.ExitSuccess
   100  }
   101  
   102  func parseSignal(s string) (unix.Signal, error) {
   103  	n, err := strconv.Atoi(s)
   104  	if err == nil {
   105  		sig := unix.Signal(n)
   106  		for _, msig := range signalMap {
   107  			if sig == msig {
   108  				return sig, nil
   109  			}
   110  		}
   111  		return -1, fmt.Errorf("unknown signal %q", s)
   112  	}
   113  	if sig, ok := signalMap[strings.TrimPrefix(strings.ToUpper(s), "SIG")]; ok {
   114  		return sig, nil
   115  	}
   116  	return -1, fmt.Errorf("unknown signal %q", s)
   117  }
   118  
   119  var signalMap = map[string]unix.Signal{
   120  	"ABRT":   unix.SIGABRT,
   121  	"ALRM":   unix.SIGALRM,
   122  	"BUS":    unix.SIGBUS,
   123  	"CHLD":   unix.SIGCHLD,
   124  	"CLD":    unix.SIGCLD,
   125  	"CONT":   unix.SIGCONT,
   126  	"FPE":    unix.SIGFPE,
   127  	"HUP":    unix.SIGHUP,
   128  	"ILL":    unix.SIGILL,
   129  	"INT":    unix.SIGINT,
   130  	"IO":     unix.SIGIO,
   131  	"IOT":    unix.SIGIOT,
   132  	"KILL":   unix.SIGKILL,
   133  	"PIPE":   unix.SIGPIPE,
   134  	"POLL":   unix.SIGPOLL,
   135  	"PROF":   unix.SIGPROF,
   136  	"PWR":    unix.SIGPWR,
   137  	"QUIT":   unix.SIGQUIT,
   138  	"SEGV":   unix.SIGSEGV,
   139  	"STKFLT": unix.SIGSTKFLT,
   140  	"STOP":   unix.SIGSTOP,
   141  	"SYS":    unix.SIGSYS,
   142  	"TERM":   unix.SIGTERM,
   143  	"TRAP":   unix.SIGTRAP,
   144  	"TSTP":   unix.SIGTSTP,
   145  	"TTIN":   unix.SIGTTIN,
   146  	"TTOU":   unix.SIGTTOU,
   147  	"URG":    unix.SIGURG,
   148  	"USR1":   unix.SIGUSR1,
   149  	"USR2":   unix.SIGUSR2,
   150  	"VTALRM": unix.SIGVTALRM,
   151  	"WINCH":  unix.SIGWINCH,
   152  	"XCPU":   unix.SIGXCPU,
   153  	"XFSZ":   unix.SIGXFSZ,
   154  }