Skip to content

Commit 6ef40ed

Browse files
committed
Do tilde-expansion only once in FillDefaults()
We need to do the expansion before we copy the Location over as the default MountPoint because we can't do tilde expansion for guest filenames (the existing call in cidata.go was an error). Signed-off-by: Jan Dubois <[email protected]>
1 parent d82d125 commit 6ef40ed

File tree

8 files changed

+46
-67
lines changed

8 files changed

+46
-67
lines changed

pkg/cidata/cidata.go

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -200,14 +200,6 @@ func templateArgs(bootScripts bool, instDir, name string, instConfig *limayaml.L
200200
}
201201
for i, f := range instConfig.Mounts {
202202
tag := fmt.Sprintf("mount%d", i)
203-
location, err := localpathutil.Expand(f.Location)
204-
if err != nil {
205-
return nil, err
206-
}
207-
mountPoint, err := localpathutil.Expand(*f.MountPoint)
208-
if err != nil {
209-
return nil, err
210-
}
211203
options := "defaults"
212204
switch fstype {
213205
case "9p", "virtiofs":
@@ -220,17 +212,17 @@ func templateArgs(bootScripts bool, instDir, name string, instConfig *limayaml.L
220212
options += fmt.Sprintf(",version=%s", *f.NineP.ProtocolVersion)
221213
msize, err := units.RAMInBytes(*f.NineP.Msize)
222214
if err != nil {
223-
return nil, fmt.Errorf("failed to parse msize for %q: %w", location, err)
215+
return nil, fmt.Errorf("failed to parse msize for %q: %w", f.Location, err)
224216
}
225217
options += fmt.Sprintf(",msize=%d", msize)
226218
options += fmt.Sprintf(",cache=%s", *f.NineP.Cache)
227219
}
228220
// don't fail the boot, if virtfs is not available
229221
options += ",nofail"
230222
}
231-
args.Mounts = append(args.Mounts, Mount{Tag: tag, MountPoint: mountPoint, Type: fstype, Options: options})
232-
if location == hostHome {
233-
args.HostHomeMountPoint = mountPoint
223+
args.Mounts = append(args.Mounts, Mount{Tag: tag, MountPoint: *f.MountPoint, Type: fstype, Options: options})
224+
if f.Location == hostHome {
225+
args.HostHomeMountPoint = *f.MountPoint
234226
}
235227
}
236228

pkg/hostagent/inotify.go

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import (
1111
"strings"
1212

1313
guestagentapi "github.com/lima-vm/lima/pkg/guestagent/api"
14-
"github.com/lima-vm/lima/pkg/localpathutil"
1514
"github.com/rjeczalik/notify"
1615
"github.com/sirupsen/logrus"
1716
"google.golang.org/protobuf/types/known/timestamppb"
@@ -74,20 +73,16 @@ func (a *HostAgent) setupWatchers(events chan notify.EventInfo) error {
7473
if !*m.Writable {
7574
continue
7675
}
77-
location, err := localpathutil.Expand(m.Location)
76+
symlink, err := filepath.EvalSymlinks(m.Location)
7877
if err != nil {
7978
return err
8079
}
81-
symlink, err := filepath.EvalSymlinks(location)
82-
if err != nil {
83-
return err
84-
}
85-
if location != symlink {
86-
mountSymlinks[symlink] = location
80+
if m.Location != symlink {
81+
mountSymlinks[symlink] = m.Location
8782
}
8883

89-
logrus.Infof("enable inotify for writable mount: %s", location)
90-
err = notify.Watch(path.Join(location, "..."), events, GetNotifyEvent())
84+
logrus.Infof("enable inotify for writable mount: %s", m.Location)
85+
err = notify.Watch(path.Join(m.Location, "..."), events, GetNotifyEvent())
9186
if err != nil {
9287
return err
9388
}

pkg/hostagent/mount.go

Lines changed: 10 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import (
99
"os"
1010

1111
"github.com/lima-vm/lima/pkg/limayaml"
12-
"github.com/lima-vm/lima/pkg/localpathutil"
1312
"github.com/lima-vm/sshocker/pkg/reversesshfs"
1413
"github.com/sirupsen/logrus"
1514
)
@@ -35,16 +34,7 @@ func (a *HostAgent) setupMounts() ([]*mount, error) {
3534
}
3635

3736
func (a *HostAgent) setupMount(m limayaml.Mount) (*mount, error) {
38-
location, err := localpathutil.Expand(m.Location)
39-
if err != nil {
40-
return nil, err
41-
}
42-
43-
mountPoint, err := localpathutil.Expand(*m.MountPoint)
44-
if err != nil {
45-
return nil, err
46-
}
47-
if err := os.MkdirAll(location, 0o755); err != nil {
37+
if err := os.MkdirAll(m.Location, 0o755); err != nil {
4838
return nil, err
4939
}
5040
// NOTE: allow_other requires "user_allow_other" in /etc/fuse.conf
@@ -55,35 +45,35 @@ func (a *HostAgent) setupMount(m limayaml.Mount) (*mount, error) {
5545
if *m.SSHFS.FollowSymlinks {
5646
sshfsOptions += ",follow_symlinks"
5747
}
58-
logrus.Infof("Mounting %q on %q", location, mountPoint)
48+
logrus.Infof("Mounting %q on %q", m.Location, *m.MountPoint)
5949

6050
rsf := &reversesshfs.ReverseSSHFS{
6151
Driver: *m.SSHFS.SFTPDriver,
6252
SSHConfig: a.sshConfig,
63-
LocalPath: location,
53+
LocalPath: m.Location,
6454
Host: "127.0.0.1",
6555
Port: a.sshLocalPort,
66-
RemotePath: mountPoint,
56+
RemotePath: *m.MountPoint,
6757
Readonly: !(*m.Writable),
6858
SSHFSAdditionalArgs: []string{"-o", sshfsOptions},
6959
}
7060
if err := rsf.Prepare(); err != nil {
71-
return nil, fmt.Errorf("failed to prepare reverse sshfs for %q on %q: %w", location, mountPoint, err)
61+
return nil, fmt.Errorf("failed to prepare reverse sshfs for %q on %q: %w", m.Location, *m.MountPoint, err)
7262
}
7363
if err := rsf.Start(); err != nil {
74-
logrus.WithError(err).Warnf("failed to mount reverse sshfs for %q on %q, retrying with `-o nonempty`", location, mountPoint)
64+
logrus.WithError(err).Warnf("failed to mount reverse sshfs for %q on %q, retrying with `-o nonempty`", m.Location, *m.MountPoint)
7565
// NOTE: nonempty is not supported for libfuse3: https://github.com/canonical/multipass/issues/1381
7666
rsf.SSHFSAdditionalArgs = []string{"-o", "nonempty"}
7767
if err := rsf.Start(); err != nil {
78-
return nil, fmt.Errorf("failed to mount reverse sshfs for %q on %q: %w", location, mountPoint, err)
68+
return nil, fmt.Errorf("failed to mount reverse sshfs for %q on %q: %w", m.Location, *m.MountPoint, err)
7969
}
8070
}
8171

8272
res := &mount{
8373
close: func() error {
84-
logrus.Infof("Unmounting %q", location)
85-
if closeErr := rsf.Close(); closeErr != nil {
86-
return fmt.Errorf("failed to unmount reverse sshfs for %q on %q: %w", location, mountPoint, err)
74+
logrus.Infof("Unmounting %q", m.Location)
75+
if err := rsf.Close(); err != nil {
76+
return fmt.Errorf("failed to unmount reverse sshfs for %q on %q: %w", m.Location, *m.MountPoint, err)
8777
}
8878
return nil
8979
},

pkg/limayaml/defaults.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import (
2929
"golang.org/x/sys/cpu"
3030

3131
"github.com/lima-vm/lima/pkg/identifierutil"
32+
"github.com/lima-vm/lima/pkg/localpathutil"
3233
. "github.com/lima-vm/lima/pkg/must"
3334
"github.com/lima-vm/lima/pkg/networks"
3435
"github.com/lima-vm/lima/pkg/osutil"
@@ -785,8 +786,13 @@ func FillDefault(y, d, o *LimaYAML, filePath string, warn bool) {
785786
mounts[i].NineP.Cache = ptr.Of(Default9pCacheForRO)
786787
}
787788
}
789+
if location, err := localpathutil.Expand(mount.Location); err == nil {
790+
mounts[i].Location = location
791+
} else {
792+
logrus.WithError(err).Warnf("Couldn't expand location %q", mount.Location)
793+
}
788794
if mount.MountPoint == nil {
789-
mounts[i].MountPoint = ptr.Of(mount.Location)
795+
mounts[i].MountPoint = ptr.Of(mounts[i].Location)
790796
}
791797
}
792798

pkg/limayaml/defaults_test.go

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,9 @@ func TestFillDefault(t *testing.T) {
146146
},
147147
},
148148
Mounts: []Mount{
149-
{Location: "/tmp"},
149+
// Location will be passed through localpathutil.Expand() which will normalize the name
150+
// (add a drive letter). So we must start with a valid local path to match it again later.
151+
{Location: filepath.Clean(os.TempDir())},
150152
{Location: "{{.Dir}}/{{.Param.ONE}}", MountPoint: ptr.Of("/mnt/{{.Param.ONE}}")},
151153
},
152154
MountType: ptr.Of(NINEP),
@@ -231,7 +233,7 @@ func TestFillDefault(t *testing.T) {
231233
expect.Mounts[0].NineP.Cache = ptr.Of(Default9pCacheForRO)
232234
expect.Mounts[0].Virtiofs.QueueSize = nil
233235
// Only missing Mounts field is Writable, and the default value is also the null value: false
234-
expect.Mounts[1].Location = fmt.Sprintf("%s/%s", instDir, y.Param["ONE"])
236+
expect.Mounts[1].Location = filepath.Join(instDir, y.Param["ONE"])
235237
expect.Mounts[1].MountPoint = ptr.Of(fmt.Sprintf("/mnt/%s", y.Param["ONE"]))
236238
expect.Mounts[1].Writable = ptr.Of(false)
237239
expect.Mounts[1].SSHFS.Cache = ptr.Of(true)
@@ -321,6 +323,9 @@ func TestFillDefault(t *testing.T) {
321323
// User-provided defaults should override any builtin defaults
322324

323325
// Choose values that are different from the "builtin" defaults
326+
327+
// Calling filepath.Abs() to add a drive letter on Windows
328+
varLog, _ := filepath.Abs("/var/log")
324329
d = LimaYAML{
325330
VMType: ptr.Of("vz"),
326331
OS: ptr.Of("unknown"),
@@ -385,7 +390,7 @@ func TestFillDefault(t *testing.T) {
385390

386391
Mounts: []Mount{
387392
{
388-
Location: "/var/log",
393+
Location: varLog,
389394
Writable: ptr.Of(false),
390395
},
391396
},
@@ -593,7 +598,7 @@ func TestFillDefault(t *testing.T) {
593598

594599
Mounts: []Mount{
595600
{
596-
Location: "/var/log",
601+
Location: varLog,
597602
Writable: ptr.Of(true),
598603
SSHFS: SSHFS{
599604
Cache: ptr.Of(false),

pkg/limayaml/validate.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ func Validate(y *LimaYAML, warn bool) error {
154154
return fmt.Errorf("field `mounts[%d].location` must be an absolute path, got %q",
155155
i, f.Location)
156156
}
157+
// f.Location has already been expanded in FillDefaults(), but that function cannot return errors.
157158
loc, err := localpathutil.Expand(f.Location)
158159
if err != nil {
159160
return fmt.Errorf("field `mounts[%d].location` refers to an unexpandable path: %q: %w", i, f.Location, err)
@@ -174,6 +175,10 @@ func Validate(y *LimaYAML, warn bool) error {
174175
case *y.User.Home:
175176
return fmt.Errorf("field `mounts[%d].mountPoint` is the reserved internal home directory %q", i, *y.User.Home)
176177
}
178+
// There is no tilde-expansion for guest filenames
179+
if strings.HasPrefix(*f.MountPoint, "~") {
180+
return fmt.Errorf("field `mounts[%d].mountPoint` must not start with \"~\"", i)
181+
}
177182

178183
if _, err := units.RAMInBytes(*f.NineP.Msize); err != nil {
179184
return fmt.Errorf("field `msize` has an invalid value: %w", err)

pkg/qemu/qemu.go

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ import (
3131
"github.com/lima-vm/lima/pkg/fileutils"
3232
"github.com/lima-vm/lima/pkg/iso9660util"
3333
"github.com/lima-vm/lima/pkg/limayaml"
34-
"github.com/lima-vm/lima/pkg/localpathutil"
3534
"github.com/lima-vm/lima/pkg/networks"
3635
"github.com/lima-vm/lima/pkg/qemu/imgutil"
3736
"github.com/lima-vm/lima/pkg/store"
@@ -935,19 +934,15 @@ func Cmdline(ctx context.Context, cfg Config) (exe string, args []string, err er
935934
if *y.MountType == limayaml.NINEP || *y.MountType == limayaml.VIRTIOFS {
936935
for i, f := range y.Mounts {
937936
tag := fmt.Sprintf("mount%d", i)
938-
location, err := localpathutil.Expand(f.Location)
939-
if err != nil {
940-
return "", nil, err
941-
}
942-
if err := os.MkdirAll(location, 0o755); err != nil {
937+
if err := os.MkdirAll(f.Location, 0o755); err != nil {
943938
return "", nil, err
944939
}
945940

946941
switch *y.MountType {
947942
case limayaml.NINEP:
948943
options := "local"
949944
options += fmt.Sprintf(",mount_tag=%s", tag)
950-
options += fmt.Sprintf(",path=%s", location)
945+
options += fmt.Sprintf(",path=%s", f.Location)
951946
options += fmt.Sprintf(",security_model=%s", *f.NineP.SecurityModel)
952947
if !*f.Writable {
953948
options += ",readonly"
@@ -1067,10 +1062,6 @@ func FindVirtiofsd(qemuExe string) (string, error) {
10671062

10681063
func VirtiofsdCmdline(cfg Config, mountIndex int) ([]string, error) {
10691064
mount := cfg.LimaYAML.Mounts[mountIndex]
1070-
location, err := localpathutil.Expand(mount.Location)
1071-
if err != nil {
1072-
return nil, err
1073-
}
10741065

10751066
vhostSock := filepath.Join(cfg.InstanceDir, fmt.Sprintf(filenames.VhostSock, mountIndex))
10761067
// qemu_driver has to wait for the socket to appear, so make sure any old ones are removed here.
@@ -1080,7 +1071,7 @@ func VirtiofsdCmdline(cfg Config, mountIndex int) ([]string, error) {
10801071

10811072
return []string{
10821073
"--socket-path", vhostSock,
1083-
"--shared-dir", location,
1074+
"--shared-dir", mount.Location,
10841075
}, nil
10851076
}
10861077

pkg/vz/vm_darwin.go

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ import (
2525
"github.com/lima-vm/lima/pkg/driver"
2626
"github.com/lima-vm/lima/pkg/iso9660util"
2727
"github.com/lima-vm/lima/pkg/limayaml"
28-
"github.com/lima-vm/lima/pkg/localpathutil"
2928
"github.com/lima-vm/lima/pkg/nativeimgutil"
3029
"github.com/lima-vm/lima/pkg/networks"
3130
"github.com/lima-vm/lima/pkg/networks/usernet"
@@ -548,18 +547,14 @@ func attachFolderMounts(driver *driver.BaseDriver, vmConfig *vz.VirtualMachineCo
548547
var mounts []vz.DirectorySharingDeviceConfiguration
549548
if *driver.Instance.Config.MountType == limayaml.VIRTIOFS {
550549
for i, mount := range driver.Instance.Config.Mounts {
551-
expandedPath, err := localpathutil.Expand(mount.Location)
552-
if err != nil {
553-
return err
554-
}
555-
if _, err := os.Stat(expandedPath); errors.Is(err, os.ErrNotExist) {
556-
err := os.MkdirAll(expandedPath, 0o750)
550+
if _, err := os.Stat(mount.Location); errors.Is(err, os.ErrNotExist) {
551+
err := os.MkdirAll(mount.Location, 0o750)
557552
if err != nil {
558553
return err
559554
}
560555
}
561556

562-
directory, err := vz.NewSharedDirectory(expandedPath, !*mount.Writable)
557+
directory, err := vz.NewSharedDirectory(mount.Location, !*mount.Writable)
563558
if err != nil {
564559
return err
565560
}

0 commit comments

Comments
 (0)