github.com/endocode/docker@v1.4.2-0.20160113120958-46eb4700391e/daemon/execdriver/windows/exec.go (about) 1 // +build windows 2 3 package windows 4 5 import ( 6 "fmt" 7 8 "github.com/Sirupsen/logrus" 9 "github.com/docker/docker/daemon/execdriver" 10 "github.com/microsoft/hcsshim" 11 ) 12 13 // Exec implements the exec driver Driver interface. 14 func (d *Driver) Exec(c *execdriver.Command, processConfig *execdriver.ProcessConfig, pipes *execdriver.Pipes, hooks execdriver.Hooks) (int, error) { 15 16 var ( 17 term execdriver.Terminal 18 err error 19 exitCode int32 20 errno uint32 21 ) 22 23 active := d.activeContainers[c.ID] 24 if active == nil { 25 return -1, fmt.Errorf("Exec - No active container exists with ID %s", c.ID) 26 } 27 28 createProcessParms := hcsshim.CreateProcessParams{ 29 EmulateConsole: processConfig.Tty, // Note NOT c.ProcessConfig.Tty 30 WorkingDirectory: c.WorkingDir, 31 } 32 33 // Configure the environment for the process // Note NOT c.ProcessConfig.Env 34 createProcessParms.Environment = setupEnvironmentVariables(processConfig.Env) 35 36 // Create the commandline for the process // Note NOT c.ProcessConfig 37 createProcessParms.CommandLine, err = createCommandLine(processConfig, false) 38 39 if err != nil { 40 return -1, err 41 } 42 43 // Start the command running in the container. 44 pid, stdin, stdout, stderr, rc, err := hcsshim.CreateProcessInComputeSystem(c.ID, pipes.Stdin != nil, true, !processConfig.Tty, createProcessParms) 45 if err != nil { 46 // TODO Windows: TP4 Workaround. In Hyper-V containers, there is a limitation 47 // of one exec per container. This should be fixed post TP4. CreateProcessInComputeSystem 48 // will return a specific error which we handle here to give a good error message 49 // back to the user instead of an inactionable "An invalid argument was supplied" 50 if rc == hcsshim.Win32InvalidArgument { 51 return -1, fmt.Errorf("The limit of docker execs per Hyper-V container has been exceeded") 52 } 53 logrus.Errorf("CreateProcessInComputeSystem() failed %s", err) 54 return -1, err 55 } 56 57 // Now that the process has been launched, begin copying data to and from 58 // the named pipes for the std handles. 59 setupPipes(stdin, stdout, stderr, pipes) 60 61 // Note NOT c.ProcessConfig.Tty 62 if processConfig.Tty { 63 term = NewTtyConsole(c.ID, pid) 64 } else { 65 term = NewStdConsole() 66 } 67 processConfig.Terminal = term 68 69 // Invoke the start callback 70 if hooks.Start != nil { 71 // A closed channel for OOM is returned here as it will be 72 // non-blocking and return the correct result when read. 73 chOOM := make(chan struct{}) 74 close(chOOM) 75 hooks.Start(&c.ProcessConfig, int(pid), chOOM) 76 } 77 78 if exitCode, errno, err = hcsshim.WaitForProcessInComputeSystem(c.ID, pid, hcsshim.TimeoutInfinite); err != nil { 79 if errno == hcsshim.Win32PipeHasBeenEnded { 80 logrus.Debugf("Exiting Run() after WaitForProcessInComputeSystem failed with recognised error 0x%X", errno) 81 return hcsshim.WaitErrExecFailed, nil 82 } 83 logrus.Warnf("WaitForProcessInComputeSystem failed (container may have been killed): 0x%X %s", errno, err) 84 return -1, err 85 } 86 87 logrus.Debugln("Exiting Run()", c.ID) 88 return int(exitCode), nil 89 }