123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188 |
- // +build linux
- package runc
- import (
- "encoding/json"
- "fmt"
- "os"
- "strconv"
- "strings"
- "github.com/codegangsta/cli"
- "github.com/opencontainers/runc/libcontainer/utils"
- "github.com/opencontainers/runtime-spec/specs-go"
- )
- var execCommand = cli.Command{
- Name: "exec",
- Usage: "execute new process inside the container",
- ArgsUsage: `<container-id> <container command>
- Where "<container-id>" is the name for the instance of the container and
- "<container command>" is the command to be executed in the container.
- For example, if the container is configured to run the linux ps command the
- following will output a list of processes running in the container:
-
- # runc exec <container-id> ps`,
- Flags: []cli.Flag{
- cli.StringFlag{
- Name: "console",
- Usage: "specify the pty slave path for use with the container",
- },
- cli.StringFlag{
- Name: "cwd",
- Usage: "current working directory in the container",
- },
- cli.StringSliceFlag{
- Name: "env, e",
- Usage: "set environment variables",
- },
- cli.BoolFlag{
- Name: "tty, t",
- Usage: "allocate a pseudo-TTY",
- },
- cli.StringFlag{
- Name: "user, u",
- Usage: "UID (format: <uid>[:<gid>])",
- },
- cli.StringFlag{
- Name: "process, p",
- Usage: "path to the process.json",
- },
- cli.BoolFlag{
- Name: "detach,d",
- Usage: "detach from the container's process",
- },
- cli.StringFlag{
- Name: "pid-file",
- Value: "",
- Usage: "specify the file to write the process id to",
- },
- cli.StringFlag{
- Name: "process-label",
- Usage: "set the asm process label for the process commonly used with selinux",
- },
- cli.StringFlag{
- Name: "apparmor",
- Usage: "set the apparmor profile for the process",
- },
- cli.BoolFlag{
- Name: "no-new-privs",
- Usage: "set the no new privileges value for the process",
- },
- cli.StringSliceFlag{
- Name: "cap, c",
- Value: &cli.StringSlice{},
- Usage: "add a capability to the bounding set for the process",
- },
- cli.BoolFlag{
- Name: "no-subreaper",
- Usage: "disable the use of the subreaper used to reap reparented processes",
- },
- },
- Action: func(context *cli.Context) {
- if os.Geteuid() != 0 {
- fatalf("runc should be run as root")
- }
- status, err := execProcess(context)
- if err != nil {
- fatalf("exec failed: %v", err)
- }
- os.Exit(status)
- },
- }
- func execProcess(context *cli.Context) (int, error) {
- container, err := getContainer(context)
- if err != nil {
- return -1, err
- }
- detach := context.Bool("detach")
- state, err := container.State()
- if err != nil {
- return -1, err
- }
- bundle := utils.SearchLabels(state.Config.Labels, "bundle")
- p, err := getProcess(context, bundle)
- if err != nil {
- return -1, err
- }
- r := &runner{
- enableSubreaper: !context.Bool("no-subreaper"),
- shouldDestroy: false,
- container: container,
- console: context.String("console"),
- detach: detach,
- pidFile: context.String("pid-file"),
- }
- return r.run(p)
- }
- func getProcess(context *cli.Context, bundle string) (*specs.Process, error) {
- if path := context.String("process"); path != "" {
- f, err := os.Open(path)
- if err != nil {
- return nil, err
- }
- defer f.Close()
- var p specs.Process
- if err := json.NewDecoder(f).Decode(&p); err != nil {
- return nil, err
- }
- return &p, validateProcessSpec(&p)
- }
- // process via cli flags
- if err := os.Chdir(bundle); err != nil {
- return nil, err
- }
- spec, err := loadSpec(specConfig)
- if err != nil {
- return nil, err
- }
- p := spec.Process
- p.Args = context.Args()[1:]
- // override the cwd, if passed
- if context.String("cwd") != "" {
- p.Cwd = context.String("cwd")
- }
- if ap := context.String("apparmor"); ap != "" {
- p.ApparmorProfile = ap
- }
- if l := context.String("process-label"); l != "" {
- p.SelinuxLabel = l
- }
- if caps := context.StringSlice("cap"); len(caps) > 0 {
- p.Capabilities = caps
- }
- // append the passed env variables
- for _, e := range context.StringSlice("env") {
- p.Env = append(p.Env, e)
- }
- // set the tty
- if context.IsSet("tty") {
- p.Terminal = context.Bool("tty")
- }
- if context.IsSet("no-new-privs") {
- p.NoNewPrivileges = context.Bool("no-new-privs")
- }
- // override the user, if passed
- if context.String("user") != "" {
- u := strings.SplitN(context.String("user"), ":", 2)
- if len(u) > 1 {
- gid, err := strconv.Atoi(u[1])
- if err != nil {
- return nil, fmt.Errorf("parsing %s as int for gid failed: %v", u[1], err)
- }
- p.User.GID = uint32(gid)
- }
- uid, err := strconv.Atoi(u[0])
- if err != nil {
- return nil, fmt.Errorf("parsing %s as int for uid failed: %v", u[0], err)
- }
- p.User.UID = uint32(uid)
- }
- return &p, nil
- }
|