process_linux.go 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. // +build linux
  2. package libcontainer
  3. import (
  4. "encoding/json"
  5. "errors"
  6. "io"
  7. "os"
  8. "os/exec"
  9. "syscall"
  10. "github.com/docker/libcontainer/cgroups"
  11. "github.com/docker/libcontainer/system"
  12. )
  13. type parentProcess interface {
  14. // pid returns the pid for the running process.
  15. pid() int
  16. // start starts the process execution.
  17. start() error
  18. // send a SIGKILL to the process and wait for the exit.
  19. terminate() error
  20. // wait waits on the process returning the process state.
  21. wait() (*os.ProcessState, error)
  22. // startTime return's the process start time.
  23. startTime() (string, error)
  24. signal(os.Signal) error
  25. }
  26. type setnsProcess struct {
  27. cmd *exec.Cmd
  28. parentPipe *os.File
  29. childPipe *os.File
  30. cgroupPaths map[string]string
  31. config *initConfig
  32. }
  33. func (p *setnsProcess) startTime() (string, error) {
  34. return system.GetProcessStartTime(p.pid())
  35. }
  36. func (p *setnsProcess) signal(sig os.Signal) error {
  37. s, ok := sig.(syscall.Signal)
  38. if !ok {
  39. return errors.New("os: unsupported signal type")
  40. }
  41. return syscall.Kill(p.cmd.Process.Pid, s)
  42. }
  43. func (p *setnsProcess) start() (err error) {
  44. defer p.parentPipe.Close()
  45. if err = p.execSetns(); err != nil {
  46. return newSystemError(err)
  47. }
  48. if len(p.cgroupPaths) > 0 {
  49. if err := cgroups.EnterPid(p.cgroupPaths, p.cmd.Process.Pid); err != nil {
  50. return newSystemError(err)
  51. }
  52. }
  53. if err := json.NewEncoder(p.parentPipe).Encode(p.config); err != nil {
  54. return newSystemError(err)
  55. }
  56. if err := syscall.Shutdown(int(p.parentPipe.Fd()), syscall.SHUT_WR); err != nil {
  57. return newSystemError(err)
  58. }
  59. // wait for the child process to fully complete and receive an error message
  60. // if one was encoutered
  61. var ierr *genericError
  62. if err := json.NewDecoder(p.parentPipe).Decode(&ierr); err != nil && err != io.EOF {
  63. return newSystemError(err)
  64. }
  65. if ierr != nil {
  66. return newSystemError(ierr)
  67. }
  68. return nil
  69. }
  70. // execSetns runs the process that executes C code to perform the setns calls
  71. // because setns support requires the C process to fork off a child and perform the setns
  72. // before the go runtime boots, we wait on the process to die and receive the child's pid
  73. // over the provided pipe.
  74. func (p *setnsProcess) execSetns() error {
  75. err := p.cmd.Start()
  76. p.childPipe.Close()
  77. if err != nil {
  78. return newSystemError(err)
  79. }
  80. status, err := p.cmd.Process.Wait()
  81. if err != nil {
  82. p.cmd.Wait()
  83. return newSystemError(err)
  84. }
  85. if !status.Success() {
  86. p.cmd.Wait()
  87. return newSystemError(&exec.ExitError{ProcessState: status})
  88. }
  89. var pid *pid
  90. if err := json.NewDecoder(p.parentPipe).Decode(&pid); err != nil {
  91. p.cmd.Wait()
  92. return newSystemError(err)
  93. }
  94. process, err := os.FindProcess(pid.Pid)
  95. if err != nil {
  96. return err
  97. }
  98. p.cmd.Process = process
  99. return nil
  100. }
  101. // terminate sends a SIGKILL to the forked process for the setns routine then waits to
  102. // avoid the process becomming a zombie.
  103. func (p *setnsProcess) terminate() error {
  104. err := p.cmd.Process.Kill()
  105. if _, werr := p.wait(); err == nil {
  106. err = werr
  107. }
  108. return err
  109. }
  110. func (p *setnsProcess) wait() (*os.ProcessState, error) {
  111. err := p.cmd.Wait()
  112. if err != nil {
  113. return p.cmd.ProcessState, err
  114. }
  115. return p.cmd.ProcessState, nil
  116. }
  117. func (p *setnsProcess) pid() int {
  118. return p.cmd.Process.Pid
  119. }
  120. type initProcess struct {
  121. cmd *exec.Cmd
  122. parentPipe *os.File
  123. childPipe *os.File
  124. config *initConfig
  125. manager cgroups.Manager
  126. }
  127. func (p *initProcess) pid() int {
  128. return p.cmd.Process.Pid
  129. }
  130. func (p *initProcess) start() error {
  131. defer p.parentPipe.Close()
  132. err := p.cmd.Start()
  133. p.childPipe.Close()
  134. if err != nil {
  135. return newSystemError(err)
  136. }
  137. // Do this before syncing with child so that no children
  138. // can escape the cgroup
  139. if err := p.manager.Apply(p.pid()); err != nil {
  140. return newSystemError(err)
  141. }
  142. defer func() {
  143. if err != nil {
  144. // TODO: should not be the responsibility to call here
  145. p.manager.Destroy()
  146. }
  147. }()
  148. if err := p.createNetworkInterfaces(); err != nil {
  149. return newSystemError(err)
  150. }
  151. if err := p.sendConfig(); err != nil {
  152. return newSystemError(err)
  153. }
  154. // wait for the child process to fully complete and receive an error message
  155. // if one was encoutered
  156. var ierr *genericError
  157. if err := json.NewDecoder(p.parentPipe).Decode(&ierr); err != nil && err != io.EOF {
  158. return newSystemError(err)
  159. }
  160. if ierr != nil {
  161. return newSystemError(ierr)
  162. }
  163. return nil
  164. }
  165. func (p *initProcess) wait() (*os.ProcessState, error) {
  166. err := p.cmd.Wait()
  167. if err != nil {
  168. return p.cmd.ProcessState, err
  169. }
  170. // we should kill all processes in cgroup when init is died if we use host PID namespace
  171. if p.cmd.SysProcAttr.Cloneflags&syscall.CLONE_NEWPID == 0 {
  172. killCgroupProcesses(p.manager)
  173. }
  174. return p.cmd.ProcessState, nil
  175. }
  176. func (p *initProcess) terminate() error {
  177. if p.cmd.Process == nil {
  178. return nil
  179. }
  180. err := p.cmd.Process.Kill()
  181. if _, werr := p.wait(); err == nil {
  182. err = werr
  183. }
  184. return err
  185. }
  186. func (p *initProcess) startTime() (string, error) {
  187. return system.GetProcessStartTime(p.pid())
  188. }
  189. func (p *initProcess) sendConfig() error {
  190. // send the state to the container's init process then shutdown writes for the parent
  191. if err := json.NewEncoder(p.parentPipe).Encode(p.config); err != nil {
  192. return err
  193. }
  194. // shutdown writes for the parent side of the pipe
  195. return syscall.Shutdown(int(p.parentPipe.Fd()), syscall.SHUT_WR)
  196. }
  197. func (p *initProcess) createNetworkInterfaces() error {
  198. for _, config := range p.config.Config.Networks {
  199. strategy, err := getStrategy(config.Type)
  200. if err != nil {
  201. return err
  202. }
  203. n := &network{
  204. Network: *config,
  205. }
  206. if err := strategy.create(n, p.pid()); err != nil {
  207. return err
  208. }
  209. p.config.Networks = append(p.config.Networks, n)
  210. }
  211. return nil
  212. }
  213. func (p *initProcess) signal(sig os.Signal) error {
  214. s, ok := sig.(syscall.Signal)
  215. if !ok {
  216. return errors.New("os: unsupported signal type")
  217. }
  218. return syscall.Kill(p.cmd.Process.Pid, s)
  219. }