Skip to content

Commit 7373473

Browse files
committed
9p: initial version
1 parent abbafa2 commit 7373473

File tree

5 files changed

+119
-1
lines changed

5 files changed

+119
-1
lines changed

cmd/crc/cmd/daemon.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"os"
1212
"os/signal"
1313
"regexp"
14+
"runtime"
1415
"syscall"
1516
"time"
1617

@@ -24,6 +25,7 @@ import (
2425
"github.com/crc-org/crc/v2/pkg/crc/constants"
2526
"github.com/crc-org/crc/v2/pkg/crc/daemonclient"
2627
"github.com/crc-org/crc/v2/pkg/crc/logging"
28+
"github.com/crc-org/crc/v2/pkg/fileserver/fs9p"
2729
"github.com/crc-org/machine/libmachine/drivers"
2830
"github.com/docker/go-units"
2931
"github.com/gorilla/handlers"
@@ -248,6 +250,21 @@ func run(configuration *types.Configuration) error {
248250
}
249251
}()
250252

253+
// 9p home directory sharing
254+
if runtime.GOOS == "windows" {
255+
listener9p, err := vn.Listen("tcp", net.JoinHostPort(configuration.GatewayIP, fmt.Sprintf("%d", constants.Plan9TcpPort)))
256+
if err != nil {
257+
return err
258+
}
259+
server9p, err := fs9p.New9pServer(listener9p, constants.GetHomeDir())
260+
if err != nil {
261+
return err
262+
}
263+
if err := server9p.Start(); err != nil {
264+
return err
265+
}
266+
}
267+
251268
startupDone()
252269

253270
if logging.IsDebug() {

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ require (
3131
github.com/klauspost/compress v1.18.0
3232
github.com/klauspost/cpuid/v2 v2.3.0
3333
github.com/kofalt/go-memoize v0.0.0-20220914132407-0b5d6a304579
34-
github.com/linuxkit/virtsock v0.0.0-20220523201153-1a23e78aa7a2
3534
github.com/mattn/go-colorable v0.1.14
3635
github.com/mdlayher/vsock v1.2.1
3736
github.com/onsi/ginkgo/v2 v2.25.3
@@ -132,6 +131,7 @@ require (
132131
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
133132
github.com/klauspost/pgzip v1.2.6 // indirect
134133
github.com/letsencrypt/boulder v0.0.0-20240620165639-de9c06129bec // indirect
134+
github.com/linuxkit/virtsock v0.0.0-20220523201153-1a23e78aa7a2 // indirect
135135
github.com/lufia/plan9stats v0.0.0-20240909124753-873cd0166683 // indirect
136136
github.com/mailru/easyjson v0.7.7 // indirect
137137
github.com/mattn/go-isatty v0.0.20 // indirect

pkg/crc/constants/constants.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ const (
5555
OpenShiftIngressHTTPSPort = 443
5656

5757
BackgroundLauncherExecutable = "crc-background-launcher.exe"
58+
59+
Plan9Msize = 1024 * 1024
60+
Plan9TcpPort = 564
5861
)
5962

6063
var adminHelperExecutableForOs = map[string]string{

pkg/crc/machine/start.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,7 @@ func configureSharedDirs(vm *virtualMachine, sshRunner *crcssh.Runner) error {
248248
if _, _, err := sshRunner.RunPrivileged(fmt.Sprintf("Mounting %s", mount.Target), "mount", "-o", "context=\"system_u:object_r:container_file_t:s0\"", "-t", mount.Type, mount.Tag, mount.Target); err != nil {
249249
return err
250250
}
251+
251252
case "cifs":
252253
smbUncPath := fmt.Sprintf("//%s/%s", hostVirtualIP, mount.Tag)
253254
if _, _, err := sshRunner.RunPrivate("sudo", "mount", "-o", fmt.Sprintf("rw,uid=core,gid=core,username='%s',password='%s'", mount.Username, mount.Password), "-t", mount.Type, smbUncPath, mount.Target); err != nil {
@@ -257,6 +258,16 @@ func configureSharedDirs(vm *virtualMachine, sshRunner *crcssh.Runner) error {
257258
}
258259
return fmt.Errorf("Failed to mount CIFS/SMB share '%s' please make sure configured password is correct: %w", mount.Tag, err)
259260
}
261+
262+
case "9p":
263+
// change owner to core user to allow mounting to it as a non-root user
264+
if _, _, err := sshRunner.RunPrivileged("Changing owner of mount directory", "chown core:core", mount.Target); err != nil {
265+
return err
266+
}
267+
if _, _, err := sshRunner.Run("9pfs 192.168.127.1", mount.Target); err != nil {
268+
return err
269+
}
270+
260271
default:
261272
return fmt.Errorf("Unknown Shared dir type requested: %s", mount.Type)
262273
}

pkg/fileserver/fs9p/server.go

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
package fs9p
2+
3+
import (
4+
"fmt"
5+
"net"
6+
"os"
7+
"path/filepath"
8+
9+
"github.com/DeedleFake/p9"
10+
"github.com/DeedleFake/p9/proto"
11+
"github.com/crc-org/crc/v2/pkg/crc/constants"
12+
"github.com/sirupsen/logrus"
13+
)
14+
15+
type Server struct {
16+
// Listener this server is bound to
17+
Listener net.Listener
18+
// Plan9 Filesystem type that holds the exposed directory
19+
Filesystem p9.FileSystem
20+
// Directory this server exposes
21+
ExposedDir string
22+
// Errors from the server being started will come out here
23+
ErrChan chan error
24+
}
25+
26+
// New9pServer exposes a single directory (and all children) via the given net.Listener
27+
// and returns the server struct.
28+
// Directory given must be an absolute path and must exist.
29+
func New9pServer(listener net.Listener, exposeDir string) (*Server, error) {
30+
// Verify that exposeDir makes sense.
31+
if !filepath.IsAbs(exposeDir) {
32+
return nil, fmt.Errorf("path to expose to machine must be absolute: %s", exposeDir)
33+
}
34+
stat, err := os.Stat(exposeDir)
35+
if err != nil {
36+
return nil, fmt.Errorf("cannot stat path to expose to machine: %w", err)
37+
}
38+
if !stat.IsDir() {
39+
return nil, fmt.Errorf("path to expose to machine must be a directory: %s", exposeDir)
40+
}
41+
42+
fs := p9.FileSystem(p9.Dir(exposeDir))
43+
errChan := make(chan error)
44+
45+
toReturn := new(Server)
46+
toReturn.Listener = listener
47+
toReturn.Filesystem = fs
48+
toReturn.ExposedDir = exposeDir
49+
toReturn.ErrChan = errChan
50+
51+
return toReturn, nil
52+
}
53+
54+
// Start a server created by New9pServer.
55+
func (s *Server) Start() error {
56+
go func() {
57+
s.ErrChan <- proto.Serve(s.Listener, p9.Proto(), p9.FSConnHandler(s.Filesystem, constants.Plan9Msize))
58+
close(s.ErrChan)
59+
}()
60+
61+
// Just before returning, check to see if we got an error off server startup.
62+
select {
63+
case err := <-s.ErrChan:
64+
return fmt.Errorf("starting 9p server: %w", err)
65+
default:
66+
logrus.Infof("Successfully started 9p server on %s for directory %s", s.Listener.Addr().String(), s.ExposedDir)
67+
return nil
68+
}
69+
}
70+
71+
// Stop a running server.
72+
// Please note that this does *BAD THINGS* to clients if they are still running
73+
// when the server stops. Processes get stuck in I/O deep sleep and zombify, and
74+
// nothing I do other than restarting the VM can remove the zombies.
75+
func (s *Server) Stop() error {
76+
if err := s.Listener.Close(); err != nil {
77+
return err
78+
}
79+
logrus.Infof("Successfully stopped 9p server for directory %s", s.ExposedDir)
80+
return nil
81+
}
82+
83+
// WaitForError from a running server.
84+
func (s *Server) WaitForError() error {
85+
err := <-s.ErrChan
86+
return err
87+
}

0 commit comments

Comments
 (0)