Files
podman/pkg/machine/hyperv/volumes.go
Mario Loriedo 8e6ecb97c9 Fix running machines with volumes containing spaces
Machines configured to mount local paths containing
spaces failed to start on Hyper-V and silently failed
to mount the folder on macOS/Linux.

On Windows/hyperv, where local paths are mounted
running a 9p client inside the VM, the local host
path needs to be surrounding with quotation marks
before using in a `podman machine ssh ...` command.

A similar behavior happened on Linux/QEMU where the
path was used in a SSH command to mount the folder
using virtiofs. Quoting the path when buidling the
command arguments fixed the problem.

On macOS/libkit,applehv the path was written as is
in a systemd unit name to instruct how to mount it.
Escaping space chars so that they are are parsed
successfully fixed this:
```diff
-- enable path with spaces.mount
++ enable path\x20with\x20spaces.mount
```

Fixes https://github.com/containers/podman/issues/25500

Signed-off-by: Mario Loriedo <mario.loriedo@gmail.com>
2025-04-30 08:54:42 +02:00

85 lines
2.4 KiB
Go

//go:build windows
package hyperv
import (
"errors"
"fmt"
"path"
"strconv"
"strings"
"github.com/containers/podman/v5/pkg/machine"
"github.com/containers/podman/v5/pkg/machine/hyperv/vsock"
"github.com/containers/podman/v5/pkg/machine/vmconfigs"
"github.com/sirupsen/logrus"
)
func removeShares(mc *vmconfigs.MachineConfig) error {
var removalErr error
for _, mount := range mc.Mounts {
if mount.VSockNumber == nil {
// nothing to do if the vsock number was never defined
continue
}
vsockReg, err := vsock.LoadHVSockRegistryEntry(*mount.VSockNumber)
if err != nil {
logrus.Debugf("Vsock %d for mountpoint %s does not have a valid registry entry, skipping removal", *mount.VSockNumber, mount.Target)
continue
}
if err := vsockReg.Remove(); err != nil {
if removalErr != nil {
logrus.Errorf("Error removing vsock: %v", removalErr)
}
removalErr = fmt.Errorf("removing vsock %d for mountpoint %s: %w", *mount.VSockNumber, mount.Target, err)
}
}
return removalErr
}
func startShares(mc *vmconfigs.MachineConfig) error {
for _, mount := range mc.Mounts {
var args []string
cleanTarget := path.Clean(mount.Target)
requiresChattr := !strings.HasPrefix(cleanTarget, "/home") && !strings.HasPrefix(cleanTarget, "/mnt")
if requiresChattr {
args = append(args, "sudo", "chattr", "-i", "/", "; ")
}
args = append(args, "sudo", "mkdir", "-p", strconv.Quote(cleanTarget), "; ")
if requiresChattr {
args = append(args, "sudo", "chattr", "+i", "/", "; ")
}
args = append(args, "sudo", "podman")
if logrus.IsLevelEnabled(logrus.DebugLevel) {
args = append(args, "--log-level=debug")
}
// just being protective here; in a perfect world, this cannot happen
if mount.VSockNumber == nil {
return errors.New("cannot start 9p shares with undefined vsock number")
}
args = append(args, "machine", "client9p", fmt.Sprintf("%d", *mount.VSockNumber), strconv.Quote(mount.Target))
if err := machine.CommonSSH(mc.SSH.RemoteUsername, mc.SSH.IdentityPath, mc.Name, mc.SSH.Port, args); err != nil {
return err
}
}
return nil
}
func createShares(mc *vmconfigs.MachineConfig) (err error) {
for _, mount := range mc.Mounts {
testVsock, err := vsock.NewHVSockRegistryEntry(mc.Name, vsock.Fileserver)
if err != nil {
return err
}
mount.VSockNumber = &testVsock.Port
logrus.Debugf("Going to share directory %s via 9p on vsock %d", mount.Source, testVsock.Port)
}
return nil
}