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 }