github.com/zhuohuang-hust/src-cbuild@v0.0.0-20230105071821-c7aab3e7c840/mergeCode/runc/exec.go (about)

     1  // +build linux
     2  
     3  package main
     4  
     5  import (
     6  	"encoding/json"
     7  	"fmt"
     8  	"os"
     9  	"strconv"
    10  	"strings"
    11  
    12  	"github.com/opencontainers/runc/libcontainer"
    13  	"github.com/opencontainers/runc/libcontainer/utils"
    14  	"github.com/opencontainers/runtime-spec/specs-go"
    15  	"github.com/urfave/cli"
    16  )
    17  
    18  var execCommand = cli.Command{
    19  	Name:  "exec",
    20  	Usage: "execute new process inside the container",
    21  	ArgsUsage: `<container-id> <container command> [command options]
    22  
    23  Where "<container-id>" is the name for the instance of the container and
    24  "<container command>" is the command to be executed in the container.
    25  
    26  EXAMPLE:
    27  For example, if the container is configured to run the linux ps command the
    28  following will output a list of processes running in the container:
    29  	 
    30         # runc exec <container-id> ps`,
    31  	Flags: []cli.Flag{
    32  		cli.StringFlag{
    33  			Name:  "console",
    34  			Usage: "specify the pty slave path for use with the container",
    35  		},
    36  		cli.StringFlag{
    37  			Name:  "cwd",
    38  			Usage: "current working directory in the container",
    39  		},
    40  		cli.StringSliceFlag{
    41  			Name:  "env, e",
    42  			Usage: "set environment variables",
    43  		},
    44  		cli.BoolFlag{
    45  			Name:  "tty, t",
    46  			Usage: "allocate a pseudo-TTY",
    47  		},
    48  		cli.StringFlag{
    49  			Name:  "user, u",
    50  			Usage: "UID (format: <uid>[:<gid>])",
    51  		},
    52  		cli.StringFlag{
    53  			Name:  "process, p",
    54  			Usage: "path to the process.json",
    55  		},
    56  		cli.BoolFlag{
    57  			Name:  "detach,d",
    58  			Usage: "detach from the container's process",
    59  		},
    60  		cli.StringFlag{
    61  			Name:  "pid-file",
    62  			Value: "",
    63  			Usage: "specify the file to write the process id to",
    64  		},
    65  		cli.StringFlag{
    66  			Name:  "process-label",
    67  			Usage: "set the asm process label for the process commonly used with selinux",
    68  		},
    69  		cli.StringFlag{
    70  			Name:  "apparmor",
    71  			Usage: "set the apparmor profile for the process",
    72  		},
    73  		cli.BoolFlag{
    74  			Name:  "no-new-privs",
    75  			Usage: "set the no new privileges value for the process",
    76  		},
    77  		cli.StringSliceFlag{
    78  			Name:  "cap, c",
    79  			Value: &cli.StringSlice{},
    80  			Usage: "add a capability to the bounding set for the process",
    81  		},
    82  		cli.BoolFlag{
    83  			Name:   "no-subreaper",
    84  			Usage:  "disable the use of the subreaper used to reap reparented processes",
    85  			Hidden: true,
    86  		},
    87  	},
    88  	Action: func(context *cli.Context) error {
    89  		if os.Geteuid() != 0 {
    90  			return fmt.Errorf("runc should be run as root")
    91  		}
    92  		status, err := execProcess(context)
    93  		if err == nil {
    94  			os.Exit(status)
    95  		}
    96  		return fmt.Errorf("exec failed: %v", err)
    97  	},
    98  	SkipArgReorder: true,
    99  }
   100  
   101  func execProcess(context *cli.Context) (int, error) {
   102  	container, err := getContainer(context)
   103  	if err != nil {
   104  		return -1, err
   105  	}
   106  	status, err := container.Status()
   107  	if err != nil {
   108  		return -1, err
   109  	}
   110  	if status == libcontainer.Stopped {
   111  		return -1, fmt.Errorf("cannot exec a container that has run and stopped")
   112  	}
   113  	path := context.String("process")
   114  	if path == "" && len(context.Args()) == 1 {
   115  		return -1, fmt.Errorf("process args cannot be empty")
   116  	}
   117  	detach := context.Bool("detach")
   118  	state, err := container.State()
   119  	if err != nil {
   120  		return -1, err
   121  	}
   122  	bundle := utils.SearchLabels(state.Config.Labels, "bundle")
   123  	p, err := getProcess(context, bundle)
   124  	if err != nil {
   125  		return -1, err
   126  	}
   127  	r := &runner{
   128  		enableSubreaper: false,
   129  		shouldDestroy:   false,
   130  		container:       container,
   131  		console:         context.String("console"),
   132  		detach:          detach,
   133  		pidFile:         context.String("pid-file"),
   134  	}
   135  	return r.run(p)
   136  }
   137  
   138  func getProcess(context *cli.Context, bundle string) (*specs.Process, error) {
   139  	if path := context.String("process"); path != "" {
   140  		f, err := os.Open(path)
   141  		if err != nil {
   142  			return nil, err
   143  		}
   144  		defer f.Close()
   145  		var p specs.Process
   146  		if err := json.NewDecoder(f).Decode(&p); err != nil {
   147  			return nil, err
   148  		}
   149  		return &p, validateProcessSpec(&p)
   150  	}
   151  	// process via cli flags
   152  	if err := os.Chdir(bundle); err != nil {
   153  		return nil, err
   154  	}
   155  	spec, err := loadSpec(specConfig)
   156  	if err != nil {
   157  		return nil, err
   158  	}
   159  	p := spec.Process
   160  	p.Args = context.Args()[1:]
   161  	// override the cwd, if passed
   162  	if context.String("cwd") != "" {
   163  		p.Cwd = context.String("cwd")
   164  	}
   165  	if ap := context.String("apparmor"); ap != "" {
   166  		p.ApparmorProfile = ap
   167  	}
   168  	if l := context.String("process-label"); l != "" {
   169  		p.SelinuxLabel = l
   170  	}
   171  	if caps := context.StringSlice("cap"); len(caps) > 0 {
   172  		p.Capabilities = caps
   173  	}
   174  	// append the passed env variables
   175  	for _, e := range context.StringSlice("env") {
   176  		p.Env = append(p.Env, e)
   177  	}
   178  	// set the tty
   179  	if context.IsSet("tty") {
   180  		p.Terminal = context.Bool("tty")
   181  	}
   182  	if context.IsSet("no-new-privs") {
   183  		p.NoNewPrivileges = context.Bool("no-new-privs")
   184  	}
   185  	// override the user, if passed
   186  	if context.String("user") != "" {
   187  		u := strings.SplitN(context.String("user"), ":", 2)
   188  		if len(u) > 1 {
   189  			gid, err := strconv.Atoi(u[1])
   190  			if err != nil {
   191  				return nil, fmt.Errorf("parsing %s as int for gid failed: %v", u[1], err)
   192  			}
   193  			p.User.GID = uint32(gid)
   194  		}
   195  		uid, err := strconv.Atoi(u[0])
   196  		if err != nil {
   197  			return nil, fmt.Errorf("parsing %s as int for uid failed: %v", u[0], err)
   198  		}
   199  		p.User.UID = uint32(uid)
   200  	}
   201  	return &p, nil
   202  }