sync.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. package libcontainer
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "io"
  6. "github.com/opencontainers/runc/libcontainer/utils"
  7. )
  8. type syncType string
  9. // Constants that are used for synchronisation between the parent and child
  10. // during container setup. They come in pairs (with procError being a generic
  11. // response which is followed by a &genericError).
  12. //
  13. // [ child ] <-> [ parent ]
  14. //
  15. // procHooks --> [run hooks]
  16. // <-- procResume
  17. //
  18. // procConsole -->
  19. // <-- procConsoleReq
  20. // [send(fd)] --> [recv(fd)]
  21. // <-- procConsoleAck
  22. //
  23. // procReady --> [final setup]
  24. // <-- procRun
  25. const (
  26. procError syncType = "procError"
  27. procReady syncType = "procReady"
  28. procRun syncType = "procRun"
  29. procHooks syncType = "procHooks"
  30. procResume syncType = "procResume"
  31. )
  32. type syncT struct {
  33. Type syncType `json:"type"`
  34. }
  35. // writeSync is used to write to a synchronisation pipe. An error is returned
  36. // if there was a problem writing the payload.
  37. func writeSync(pipe io.Writer, sync syncType) error {
  38. return utils.WriteJSON(pipe, syncT{sync})
  39. }
  40. // readSync is used to read from a synchronisation pipe. An error is returned
  41. // if we got a genericError, the pipe was closed, or we got an unexpected flag.
  42. func readSync(pipe io.Reader, expected syncType) error {
  43. var procSync syncT
  44. if err := json.NewDecoder(pipe).Decode(&procSync); err != nil {
  45. if err == io.EOF {
  46. return fmt.Errorf("parent closed synchronisation channel")
  47. }
  48. if procSync.Type == procError {
  49. var ierr genericError
  50. if err := json.NewDecoder(pipe).Decode(&ierr); err != nil {
  51. return fmt.Errorf("failed reading error from parent: %v", err)
  52. }
  53. return &ierr
  54. }
  55. if procSync.Type != expected {
  56. return fmt.Errorf("invalid synchronisation flag from parent")
  57. }
  58. }
  59. return nil
  60. }
  61. // parseSync runs the given callback function on each syncT received from the
  62. // child. It will return once io.EOF is returned from the given pipe.
  63. func parseSync(pipe io.Reader, fn func(*syncT) error) error {
  64. dec := json.NewDecoder(pipe)
  65. for {
  66. var sync syncT
  67. if err := dec.Decode(&sync); err != nil {
  68. if err == io.EOF {
  69. break
  70. }
  71. return err
  72. }
  73. // We handle this case outside fn for cleanliness reasons.
  74. var ierr *genericError
  75. if sync.Type == procError {
  76. if err := dec.Decode(&ierr); err != nil && err != io.EOF {
  77. return newSystemErrorWithCause(err, "decoding proc error from init")
  78. }
  79. if ierr != nil {
  80. return ierr
  81. }
  82. // Programmer error.
  83. panic("No error following JSON procError payload.")
  84. }
  85. if err := fn(&sync); err != nil {
  86. return err
  87. }
  88. }
  89. return nil
  90. }