mount_linux.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. package fuse
  2. import (
  3. "bytes"
  4. "fmt"
  5. "net"
  6. "os"
  7. "os/exec"
  8. "syscall"
  9. )
  10. // Begin the process of mounting at the given directory, returning a connection
  11. // to the kernel. Mounting continues in the background, and is complete when an
  12. // error is written to the supplied channel. The file system may need to
  13. // service the connection in order for mounting to complete.
  14. func mount(
  15. dir string,
  16. cfg *MountConfig,
  17. ready chan<- error) (dev *os.File, err error) {
  18. // On linux, mounting is never delayed.
  19. ready <- nil
  20. // Create a socket pair.
  21. fds, err := syscall.Socketpair(syscall.AF_FILE, syscall.SOCK_STREAM, 0)
  22. if err != nil {
  23. err = fmt.Errorf("Socketpair: %v", err)
  24. return
  25. }
  26. // Wrap the sockets into os.File objects that we will pass off to fusermount.
  27. writeFile := os.NewFile(uintptr(fds[0]), "fusermount-child-writes")
  28. defer writeFile.Close()
  29. readFile := os.NewFile(uintptr(fds[1]), "fusermount-parent-reads")
  30. defer readFile.Close()
  31. // Start fusermount, passing it a buffer in which to write stderr.
  32. var stderr bytes.Buffer
  33. cmd := exec.Command(
  34. "fusermount",
  35. "-o", cfg.toOptionsString(),
  36. "--",
  37. dir,
  38. )
  39. cmd.Env = append(os.Environ(), "_FUSE_COMMFD=3")
  40. cmd.ExtraFiles = []*os.File{writeFile}
  41. cmd.Stderr = &stderr
  42. // Run the command.
  43. err = cmd.Run()
  44. if err != nil {
  45. err = fmt.Errorf("running fusermount: %v\n\nstderr:\n%s", err, stderr.Bytes())
  46. return
  47. }
  48. // Wrap the socket file in a connection.
  49. c, err := net.FileConn(readFile)
  50. if err != nil {
  51. err = fmt.Errorf("FileConn: %v", err)
  52. return
  53. }
  54. defer c.Close()
  55. // We expect to have a Unix domain socket.
  56. uc, ok := c.(*net.UnixConn)
  57. if !ok {
  58. err = fmt.Errorf("Expected UnixConn, got %T", c)
  59. return
  60. }
  61. // Read a message.
  62. buf := make([]byte, 32) // expect 1 byte
  63. oob := make([]byte, 32) // expect 24 bytes
  64. _, oobn, _, _, err := uc.ReadMsgUnix(buf, oob)
  65. if err != nil {
  66. err = fmt.Errorf("ReadMsgUnix: %v", err)
  67. return
  68. }
  69. // Parse the message.
  70. scms, err := syscall.ParseSocketControlMessage(oob[:oobn])
  71. if err != nil {
  72. err = fmt.Errorf("ParseSocketControlMessage: %v", err)
  73. return
  74. }
  75. // We expect one message.
  76. if len(scms) != 1 {
  77. err = fmt.Errorf("expected 1 SocketControlMessage; got scms = %#v", scms)
  78. return
  79. }
  80. scm := scms[0]
  81. // Pull out the FD returned by fusermount
  82. gotFds, err := syscall.ParseUnixRights(&scm)
  83. if err != nil {
  84. err = fmt.Errorf("syscall.ParseUnixRights: %v", err)
  85. return
  86. }
  87. if len(gotFds) != 1 {
  88. err = fmt.Errorf("wanted 1 fd; got %#v", gotFds)
  89. return
  90. }
  91. // Turn the FD into an os.File.
  92. dev = os.NewFile(uintptr(gotFds[0]), "/dev/fuse")
  93. return
  94. }