diff --git a/cmd/flags.go b/cmd/flags.go
new file mode 100644
index 0000000..3767f91
--- /dev/null
+++ b/cmd/flags.go
@@ -0,0 +1,74 @@
+// Linsk - A utility to access Linux-native file systems on non-Linux operating systems.
+// Copyright (c) 2023 The Linsk Authors.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+package cmd
+
+import (
+ "log/slog"
+ "os"
+
+ "github.com/spf13/pflag"
+)
+
+const defaultVMMountDevName = "vdb"
+
+func getLUKSContainerDevice() string {
+ var luksContainerDevice string
+
+ if vmRuntimeLUKSContainerFlag != "" {
+ if vmRuntimeLUKSContainerEntireDriveFlag {
+ slog.Error("--luks-container and --luks-container-entire-drive (-c) cannot be both specified at once")
+ os.Exit(1)
+ }
+
+ luksContainerDevice = vmRuntimeLUKSContainerFlag
+ } else if vmRuntimeLUKSContainerEntireDriveFlag {
+ luksContainerDevice = defaultVMMountDevName
+ }
+
+ return luksContainerDevice
+}
+
+var (
+ vmRuntimeLUKSContainerFlag string
+ vmRuntimeLUKSContainerEntireDriveFlag bool
+
+ // These are for internal use by the initVMRuntimeFlags and configureVMRuntimeFlags functions.
+ vmRuntimeInternalAllowLUKSLowMemoryFlag bool
+
+ // These are to be initialized (set) by the initVMRuntimeFlags function.
+ vmRuntimeLUKSContainerDevice string
+)
+
+func initVMRuntimeFlags(flags *pflag.FlagSet) {
+ flags.StringVar(&vmRuntimeLUKSContainerFlag, "luks-container", "", `Specifies a device path (without "dev/" prefix) to preopen as a LUKS container (password will be prompted). Useful for accessing LVM partitions behind LUKS.`)
+ flags.BoolVarP(&vmRuntimeLUKSContainerEntireDriveFlag, "luks-container-entire-drive", "c", false, `Similar to --luks-container, but this assumes that the entire passed-through volume is a LUKS container (password will be prompted).`)
+ flags.BoolVar(&vmRuntimeInternalAllowLUKSLowMemoryFlag, "allow-luks-low-memory", false, "Allow VM memory allocation lower than 2048 MiB when LUKS is enabled.")
+}
+
+func configureVMRuntimeFlags() {
+ vmRuntimeLUKSContainerDevice = getLUKSContainerDevice()
+
+ if (luksFlag || vmRuntimeLUKSContainerDevice != "") && !vmRuntimeInternalAllowLUKSLowMemoryFlag {
+ if vmMemAllocFlag < defaultMemAllocLUKS {
+ if vmMemAllocFlag != defaultMemAlloc {
+ slog.Warn("Enforcing minimum LUKS memory allocation. Please add --allow-luks-low-memory to disable this.", "min", vmMemAllocFlag, "specified", vmMemAllocFlag)
+ }
+
+ vmMemAllocFlag = defaultMemAllocLUKS
+ }
+ }
+}
diff --git a/cmd/ls.go b/cmd/ls.go
index a50ab8a..4ea1f66 100644
--- a/cmd/ls.go
+++ b/cmd/ls.go
@@ -32,7 +32,17 @@ var lsCmd = &cobra.Command{
Short: "Start a VM and list all user drives within the VM. Uses lsblk command under the hood.",
Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) {
+ configureVMRuntimeFlags()
+
os.Exit(runVM(args[0], func(ctx context.Context, i *vm.VM, fm *vm.FileManager, trc *share.NetTapRuntimeContext) int {
+ if vmRuntimeLUKSContainerDevice != "" {
+ err := fm.PreopenLUKSContainer(vmRuntimeLUKSContainerDevice)
+ if err != nil {
+ slog.Error("Failed to preopen LUKS container", "error", err.Error())
+ return 1
+ }
+ }
+
lsblkOut, err := fm.Lsblk()
if err != nil {
slog.Error("Failed to list block devices in the VM", "error", err.Error())
@@ -49,3 +59,7 @@ var lsCmd = &cobra.Command{
}, nil, false, false))
},
}
+
+func init() {
+ initVMRuntimeFlags(lsCmd.Flags())
+}
diff --git a/cmd/run.go b/cmd/run.go
index 419fe46..7fac91e 100644
--- a/cmd/run.go
+++ b/cmd/run.go
@@ -35,24 +35,13 @@ var runCmd = &cobra.Command{
Short: "Start a VM and expose an FTP file share.",
Args: cobra.RangeArgs(1, 3),
Run: func(cmd *cobra.Command, args []string) {
- var luksContainerDevice string
+ configureVMRuntimeFlags()
- vmMountDevName := "vdb"
-
- if luksContainerFlag != "" {
- if luksContainerEntireDriveFlag {
- slog.Error("--luks-container and --luks-container-entire-drive (-c) cannot be both specified at once")
- os.Exit(1)
- }
-
- luksContainerDevice = luksContainerFlag
- } else if luksContainerEntireDriveFlag {
- luksContainerDevice = vmMountDevName
- }
+ vmMountDevName := defaultVMMountDevName
if len(args) > 1 {
vmMountDevName = args[1]
- } else if luksContainerDevice != "" {
+ } else if vmRuntimeLUKSContainerDevice != "" {
slog.Error("Cannot use the default (entire) device with a LUKS container. Please specify the in-VM device name to mount as a second positional argument.")
}
@@ -84,16 +73,6 @@ var runCmd = &cobra.Command{
os.Exit(1)
}
- if (luksFlag || luksContainerDevice != "") && !allowLUKSLowMemoryFlag {
- if vmMemAllocFlag < defaultMemAllocLUKS {
- if vmMemAllocFlag != defaultMemAlloc {
- slog.Warn("Enforcing minimum LUKS memory allocation. Please add --allow-luks-low-memory to disable this.", "min", vmMemAllocFlag, "specified", vmMemAllocFlag)
- }
-
- vmMemAllocFlag = defaultMemAllocLUKS
- }
- }
-
os.Exit(runVM(args[0], func(ctx context.Context, i *vm.VM, fm *vm.FileManager, tapCtx *share.NetTapRuntimeContext) int {
fsToLog := ""
if fsTypeOverride != "" {
@@ -103,7 +82,7 @@ var runCmd = &cobra.Command{
slog.Info("Mounting the device", "dev", vmMountDevName, "fs", fsToLog, "luks", luksFlag)
err := fm.Mount(vmMountDevName, vm.MountOptions{
- LUKSContainerPreopen: luksContainerDevice,
+ LUKSContainerPreopen: vmRuntimeLUKSContainerDevice,
FSTypeOverride: fsTypeOverride,
LUKS: luksFlag,
@@ -157,24 +136,20 @@ var runCmd = &cobra.Command{
}
var (
- luksFlag bool
- luksContainerFlag string
- luksContainerEntireDriveFlag bool
- allowLUKSLowMemoryFlag bool
- shareListenIPFlag string
- ftpExtIPFlag string
- shareBackendFlag string
- smbUseExternAddrFlag bool
- debugShellFlag bool
+ luksFlag bool
+ shareListenIPFlag string
+ ftpExtIPFlag string
+ shareBackendFlag string
+ smbUseExternAddrFlag bool
+ debugShellFlag bool
)
func init() {
runCmd.Flags().BoolVarP(&luksFlag, "luks", "l", false, "Use cryptsetup to open a LUKS volume (password will be prompted).")
- runCmd.Flags().StringVar(&luksContainerFlag, "luks-container", "", `Specifies a device path (without "dev/" prefix) to preopen as a LUKS container (password will be prompted). Useful for accessing LVM partitions behind LUKS.`)
- runCmd.Flags().BoolVarP(&luksContainerEntireDriveFlag, "luks-container-entire-drive", "c", false, `Similar to --luks-container, but this assumes that the entire passed-through volume is a LUKS container (password will be prompted).`)
- runCmd.Flags().BoolVar(&allowLUKSLowMemoryFlag, "allow-luks-low-memory", false, "Allow VM memory allocation lower than 2048 MiB when LUKS is enabled.")
runCmd.Flags().BoolVar(&debugShellFlag, "debug-shell", false, "Start a VM shell when the network file share is active.")
+ initVMRuntimeFlags(runCmd.Flags())
+
var defaultShareType string
switch {
case osspecifics.IsMacOS():
diff --git a/vm/filemanager.go b/vm/filemanager.go
index 61882d0..5d06780 100644
--- a/vm/filemanager.go
+++ b/vm/filemanager.go
@@ -169,6 +169,39 @@ func (fm *FileManager) luksOpen(sc *ssh.Client, fullDevPath string, luksDMName s
})
}
+func (fm *FileManager) PreopenLUKSContainer(containerDevPath string) error {
+ sc, err := fm.vm.DialSSH()
+ if err != nil {
+ return errors.Wrap(err, "dial vm ssh")
+ }
+
+ defer func() { _ = sc.Close() }()
+
+ return fm.preopenLUKSContainerWithSSH(sc, containerDevPath)
+}
+
+func (fm *FileManager) preopenLUKSContainerWithSSH(sc *ssh.Client, containerDevPath string) error {
+ if !utils.ValidateDevName(containerDevPath) {
+ return fmt.Errorf("bad luks container device name")
+ }
+
+ fullContainerDevPath := "/dev/" + containerDevPath
+
+ fm.logger.Info("Preopening a LUKS container", "container", fullContainerDevPath)
+
+ err := fm.luksOpen(sc, fullContainerDevPath, "cryptcontainer")
+ if err != nil {
+ return errors.Wrap(err, "luks (pre)open container")
+ }
+
+ err = fm.InitLVM()
+ if err != nil {
+ return errors.Wrap(err, "reinit lvm")
+ }
+
+ return nil
+}
+
func (fm *FileManager) Mount(devName string, mo MountOptions) error {
if devName == "" {
return fmt.Errorf("device name is empty")
@@ -204,22 +237,9 @@ func (fm *FileManager) Mount(devName string, mo MountOptions) error {
defer func() { _ = sc.Close() }()
if mo.LUKSContainerPreopen != "" {
- if !utils.ValidateDevName(mo.LUKSContainerPreopen) {
- return fmt.Errorf("bad luks container device name")
- }
-
- fullContainerDevPath := "/dev/" + mo.LUKSContainerPreopen
-
- fm.logger.Info("Preopening a LUKS container", "container", fullContainerDevPath)
-
- err := fm.luksOpen(sc, fullContainerDevPath, "cryptcontainer")
+ err := fm.preopenLUKSContainerWithSSH(sc, mo.LUKSContainerPreopen)
if err != nil {
- return errors.Wrap(err, "luks (pre)open container")
- }
-
- err = fm.InitLVM()
- if err != nil {
- return errors.Wrap(err, "reinit lvm")
+ return errors.Wrap(err, "preopen luks container")
}
}