mirror of
https://github.com/opencontainers/runc.git
synced 2026-07-11 06:03:57 +08:00
*: console rewrite
This implements {createTTY, detach} and all of the combinations and
negations of the two that were previously implemented. There are some
valid questions about out-of-OCI-scope topics like !createTTY and how
things should be handled (why do we dup the current stdio to the
process, and how is that not a security issue). However, these will be
dealt with in a separate patchset.
In order to allow for late console setup, split setupRootfs into the
"preparation" section where all of the mounts are created and the
"finalize" section where we pivot_root and set things as ro. In between
the two we can set up all of the console mountpoints and symlinks we
need.
We use two-stage synchronisation to ensures that when the syscalls are
reordered in a suboptimal way, an out-of-place read() on the parentPipe
will not gobble the ancilliary information.
This patch is part of the console rewrite patchset.
Signed-off-by: Aleksa Sarai <asarai@suse.de>
This commit is contained in:
+31
-35
@@ -94,22 +94,6 @@ func newProcess(p specs.Process) (*libcontainer.Process, error) {
|
||||
return lp, nil
|
||||
}
|
||||
|
||||
func dupStdio(process *libcontainer.Process, rootuid, rootgid int) error {
|
||||
process.Stdin = os.Stdin
|
||||
process.Stdout = os.Stdout
|
||||
process.Stderr = os.Stderr
|
||||
for _, fd := range []uintptr{
|
||||
os.Stdin.Fd(),
|
||||
os.Stdout.Fd(),
|
||||
os.Stderr.Fd(),
|
||||
} {
|
||||
if err := syscall.Fchown(int(fd), rootuid, rootgid); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// If systemd is supporting sd_notify protocol, this function will add support
|
||||
// for sd_notify protocol from within the container.
|
||||
func setupSdNotify(spec *specs.Spec, notifySocket string) {
|
||||
@@ -123,23 +107,27 @@ func destroy(container libcontainer.Container) {
|
||||
}
|
||||
}
|
||||
|
||||
// setupIO sets the proper IO on the process depending on the configuration
|
||||
// If there is a nil error then there must be a non nil tty returned
|
||||
func setupIO(process *libcontainer.Process, rootuid, rootgid int, console string, createTTY, detach bool) (*tty, error) {
|
||||
// detach and createTty will not work unless a console path is passed
|
||||
// so error out here before changing any terminal settings
|
||||
if createTTY && detach && console == "" {
|
||||
return nil, fmt.Errorf("cannot allocate tty if runc will detach")
|
||||
}
|
||||
// setupIO modifies the given process config according to the options.
|
||||
func setupIO(process *libcontainer.Process, rootuid, rootgid int, createTTY, detach bool) (*tty, error) {
|
||||
// This is entirely handled by recvtty.
|
||||
if createTTY {
|
||||
return createTty(process, rootuid, rootgid, console)
|
||||
process.Stdin = nil
|
||||
process.Stdout = nil
|
||||
process.Stderr = nil
|
||||
return &tty{}, nil
|
||||
}
|
||||
|
||||
// When we detach, we just dup over stdio and call it a day. There's no
|
||||
// requirement that we set up anything nice for our caller or the
|
||||
// container.
|
||||
if detach {
|
||||
// TODO: Actually set rootuid, rootgid.
|
||||
if err := dupStdio(process, rootuid, rootgid); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &tty{}, nil
|
||||
}
|
||||
|
||||
return createStdioPipes(process, rootuid, rootgid)
|
||||
}
|
||||
|
||||
@@ -192,7 +180,6 @@ type runner struct {
|
||||
detach bool
|
||||
listenFDs []*os.File
|
||||
pidFile string
|
||||
console string
|
||||
container libcontainer.Container
|
||||
create bool
|
||||
}
|
||||
@@ -217,21 +204,31 @@ func (r *runner) run(config *specs.Process) (int, error) {
|
||||
r.destroy()
|
||||
return -1, err
|
||||
}
|
||||
tty, err := setupIO(process, rootuid, rootgid, r.console, config.Terminal, r.detach || r.create)
|
||||
if err != nil {
|
||||
r.destroy()
|
||||
return -1, err
|
||||
}
|
||||
handler := newSignalHandler(tty, r.enableSubreaper)
|
||||
startFn := r.container.Start
|
||||
if !r.create {
|
||||
startFn = r.container.Run
|
||||
}
|
||||
defer tty.Close()
|
||||
// Setting up IO is a two stage process. We need to modify process to deal
|
||||
// with detaching containers, and then we get a tty after the container has
|
||||
// started.
|
||||
handler := newSignalHandler(r.enableSubreaper)
|
||||
tty, err := setupIO(process, rootuid, rootgid, config.Terminal, r.detach || r.create)
|
||||
if err != nil {
|
||||
r.destroy()
|
||||
return -1, err
|
||||
}
|
||||
if err := startFn(process); err != nil {
|
||||
r.destroy()
|
||||
return -1, err
|
||||
}
|
||||
if config.Terminal {
|
||||
if err := tty.recvtty(process, r.detach || r.create); err != nil {
|
||||
r.terminate(process)
|
||||
r.destroy()
|
||||
return -1, err
|
||||
}
|
||||
}
|
||||
defer tty.Close()
|
||||
if err := tty.ClosePostStart(); err != nil {
|
||||
r.terminate(process)
|
||||
r.destroy()
|
||||
@@ -247,7 +244,7 @@ func (r *runner) run(config *specs.Process) (int, error) {
|
||||
if r.detach || r.create {
|
||||
return 0, nil
|
||||
}
|
||||
status, err := handler.forward(process)
|
||||
status, err := handler.forward(process, tty)
|
||||
if err != nil {
|
||||
r.terminate(process)
|
||||
}
|
||||
@@ -298,7 +295,6 @@ func startContainer(context *cli.Context, spec *specs.Spec, create bool) (int, e
|
||||
shouldDestroy: true,
|
||||
container: container,
|
||||
listenFDs: listenFDs,
|
||||
console: context.String("console"),
|
||||
detach: context.Bool("detach"),
|
||||
pidFile: context.String("pid-file"),
|
||||
create: create,
|
||||
|
||||
Reference in New Issue
Block a user