From d5402b77350a3ceb522421c5c63effcabcdb8b21 Mon Sep 17 00:00:00 2001 From: user Date: Wed, 16 Apr 2025 12:16:49 +0200 Subject: [PATCH] utmctl: support booting into recovery mode --- Scripting/UTM.sdef | 3 +++ Scripting/UTMScripting.swift | 2 +- Scripting/UTMScriptingVirtualMachineImpl.swift | 14 +++++++++++++- utmctl/UTMCtl.swift | 7 +++++-- 4 files changed, 22 insertions(+), 4 deletions(-) diff --git a/Scripting/UTM.sdef b/Scripting/UTM.sdef index f40bcd1d..bd000f37 100644 --- a/Scripting/UTM.sdef +++ b/Scripting/UTM.sdef @@ -61,6 +61,9 @@ + + + diff --git a/Scripting/UTMScripting.swift b/Scripting/UTMScripting.swift index b431be75..d083d3d7 100644 --- a/Scripting/UTMScripting.swift +++ b/Scripting/UTMScripting.swift @@ -210,7 +210,7 @@ extension SBObject: UTMScriptingWindow {} @objc optional var name: String { get } // The name of the VM. @objc optional var backend: UTMScriptingBackend { get } // Emulation/virtualization engine used. @objc optional var status: UTMScriptingStatus { get } // Current running status. - @objc optional func startSaving(_ saving: Bool) // Start a virtual machine or resume a suspended virtual machine. + @objc optional func startSaving(_ saving: Bool, recovery: Bool) // Start a virtual machine or resume a suspended virtual machine. @objc optional func suspendSaving(_ saving: Bool) // Suspend a running virtual machine to memory. @objc optional func stopBy(_ by: UTMScriptingStopMethod) // Shuts down a running virtual machine. @objc optional func delete() // Delete a virtual machine. All data will be deleted, there is no confirmation! diff --git a/Scripting/UTMScriptingVirtualMachineImpl.swift b/Scripting/UTMScriptingVirtualMachineImpl.swift index d3b48634..328a6e6e 100644 --- a/Scripting/UTMScriptingVirtualMachineImpl.swift +++ b/Scripting/UTMScriptingVirtualMachineImpl.swift @@ -111,15 +111,27 @@ class UTMScriptingVirtualMachineImpl: NSObject, UTMScriptable { @objc func start(_ command: NSScriptCommand) { let shouldSaveState = command.evaluatedArguments?["saveFlag"] as? Bool ?? true + let bootRecoveryMode = command.evaluatedArguments?["bootRecoveryFlag"] as? Bool ?? false + withScriptCommand(command) { [self] in + var options: UTMVirtualMachineStartOptions = [] + if !shouldSaveState { guard type(of: vm).capabilities.supportsDisposibleMode else { throw ScriptingError.operationNotSupported } + options.insert(.bootDisposibleMode) } + if bootRecoveryMode { + guard type(of: vm).capabilities.supportsRecoveryMode else { + throw ScriptingError.operationNotSupported + } + options.insert(.bootRecovery) + } + data.run(vm: box, startImmediately: false) if vm.state == .stopped { - try await vm.start(options: shouldSaveState ? [] : .bootDisposibleMode) + try await vm.start(options: options) } else if vm.state == .paused { try await vm.resume() } else { diff --git a/utmctl/UTMCtl.swift b/utmctl/UTMCtl.swift index fa6b209c..35c4ccaf 100644 --- a/utmctl/UTMCtl.swift +++ b/utmctl/UTMCtl.swift @@ -226,10 +226,13 @@ extension UTMCtl { @Flag(help: "Run VM as a snapshot and do not save changes to disk.") var disposable: Bool = false - + + @Flag(help: "Boot a VM in recovery mode.") + var recovery: Bool = false + func run(with application: UTMScriptingApplication) throws { let vm = try virtualMachine(forIdentifier: identifer, in: application) - vm.startSaving!(!disposable) + vm.startSaving!(!disposable, recovery: recovery) if attach { print("WARNING: attach command is not implemented yet!") }