diff --git a/cmd/limactl/copy.go b/cmd/limactl/copy.go index 07c7595282c..2967521fde9 100644 --- a/cmd/limactl/copy.go +++ b/cmd/limactl/copy.go @@ -36,12 +36,8 @@ func copyAction(clicontext *cli.Context) error { return err } - const useDotSSH = false - args, err := sshutil.CommonArgs(useDotSSH) - if err != nil { - return err - } - args = append(args, "-3", "--") + instDirs := make(map[string]string) + args := []string{"-3", "--"} for _, arg := range clicontext.Args().Slice() { path := strings.Split(arg, ":") switch len(path) { @@ -60,15 +56,36 @@ func copyAction(clicontext *cli.Context) error { return fmt.Errorf("instance %q is stopped, run `limactl start %s` to start the instance", instName, instName) } args = append(args, fmt.Sprintf("scp://%s@127.0.0.1:%d/%s", u.Username, inst.SSHLocalPort, path[1])) + instDirs[instName] = inst.Dir default: return fmt.Errorf("Path %q contains multiple colons", arg) } } - cmd := exec.Command(arg0, args...) + + sshArgs := []string{} + if len(instDirs) == 1 { + // Only one (instance) host is involved; we can use the instance-specific + // arguments such as ControlPath. This is preferred as we can multiplex + // sessions without re-authenticating (MaxSessions permitting). + for _, instDir := range instDirs { + sshArgs, err = sshutil.SSHArgs(instDir, false) + if err != nil { + return err + } + } + } else { + // Copying among multiple hosts; we can't pass in host-specific options. + sshArgs, err = sshutil.CommonArgs(false) + if err != nil { + return err + } + } + + cmd := exec.Command(arg0, append(sshArgs, args...)...) cmd.Stdin = os.Stdin cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr - logrus.Debugf("executing scp (may take a long)): %+v", cmd.Args) + logrus.Debugf("executing scp (may take a long time)): %+v", cmd.Args) // TODO: use syscall.Exec directly (results in losing tty?) return cmd.Run() diff --git a/pkg/sshutil/sshutil.go b/pkg/sshutil/sshutil.go index b57590aff1d..b37a4fd0a71 100644 --- a/pkg/sshutil/sshutil.go +++ b/pkg/sshutil/sshutil.go @@ -172,7 +172,7 @@ func SSHArgs(instDir string, useDotSSH bool) ([]string, error) { return nil, err } args = append(args, - "-l", u.Username, // guest and host have the same username, but we should specify the username explicitly (#85) + "-o", fmt.Sprintf("User=%s", u.Username), // guest and host have the same username, but we should specify the username explicitly (#85) "-o", "ControlMaster=auto", "-o", fmt.Sprintf("ControlPath=\"%s\"", controlSock), "-o", "ControlPersist=5m",