Skip to content

Commit 3dfcddc

Browse files
authored
Merge pull request #6977 from naveenrajm7/script-sandbox-path
scripting : add vm registry suite
2 parents 51bc96d + f57fe2e commit 3dfcddc

File tree

7 files changed

+128
-2
lines changed

7 files changed

+128
-2
lines changed

Scripting/UTM.sdef

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -564,6 +564,10 @@
564564
<record-type name="qemu argument" code="QeAr" description="QEMU argument configuration.">
565565
<property name="argument string" code="ArSt" type="text"
566566
description="The QEMU argument as a string."/>
567+
<property name="file urls" code="FlUr"
568+
description="Optional URLs associated with this argument.">
569+
<type type="file" list="yes"/>
570+
</property>
567571
</record-type>
568572

569573
<record-type name="apple configuration" code="ApCf" description="Apple virtual machine configuration.">
@@ -714,4 +718,27 @@
714718
<direct-parameter description="The USB device to disconnect." type="usb device"/>
715719
</command>
716720
</suite>
721+
722+
<suite name="UTM Registry Suite" code="UTMr" description="UTM virtual machine registry suite. Use this to update virtual machine registry.">
723+
<access-group identifier="com.utmapp.UTM.vm-access" />
724+
725+
<class-extension extends="virtual machine" description="Virtual machine registry.">
726+
<property name="registry" code="ReGs" access="r"
727+
description="The registry of the virtual machine.">
728+
<type type="file" list="yes"/>
729+
</property>
730+
731+
<responds-to command="update registry">
732+
<cocoa method="updateRegistry:"/>
733+
</responds-to>
734+
</class-extension>
735+
736+
<command name="update registry" code="UTMrUpDt" description="Update the registry of the virtual machine.">
737+
<direct-parameter description="Virtual machine to update." type="virtual machine"/>
738+
<parameter name="with" code="UpRg" description="The registry to update the virtual machine. Currently you can only change the shared directory with this!">
739+
<cocoa key="newRegistry"/>
740+
<type type="file" list="yes"/>
741+
</parameter>
742+
</command>
743+
</suite>
717744
</dictionary>

Scripting/UTMScriptingConfigImpl.swift

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,10 @@ extension UTMScriptingConfigImpl {
194194
var serializedArgument: [AnyHashable: Any] = [
195195
"argumentString": argument.string
196196
]
197+
// Only add fileUrls if it is not nil and contains URLs
198+
if let fileUrls = argument.fileUrls, !fileUrls.isEmpty {
199+
serializedArgument["fileUrls"] = fileUrls.map({ $0 as AnyHashable })
200+
}
197201

198202
return serializedArgument
199203
}
@@ -526,7 +530,10 @@ extension UTMScriptingConfigImpl {
526530
let additionalArguments = records.compactMap { record -> QEMUArgument? in
527531
guard let argumentString = record["argumentString"] as? String else { return nil }
528532
var argument = QEMUArgument(argumentString)
529-
533+
// fileUrls are used as required resources by QEMU.
534+
if let fileUrls = record["fileUrls"] as? [URL] {
535+
argument.fileUrls = fileUrls
536+
}
530537
return argument
531538
}
532539
// Update entire additional arguments with new one.
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
//
2+
// Copyright © 2025 naveenrajm7. All rights reserved.
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS,
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
//
16+
17+
import Foundation
18+
19+
@objc extension UTMScriptingVirtualMachineImpl {
20+
@objc var registry: [URL] {
21+
let wrapper = UTMScriptingRegistryEntryImpl(vm.registryEntry)
22+
return wrapper.serializeRegistry()
23+
}
24+
25+
@objc func updateRegistry(_ command: NSScriptCommand) {
26+
let newRegistry = command.evaluatedArguments?["newRegistry"] as? [URL]
27+
withScriptCommand(command) { [self] in
28+
guard let newRegistry = newRegistry else {
29+
throw ScriptingError.invalidParameter
30+
}
31+
let wrapper = UTMScriptingRegistryEntryImpl(vm.registryEntry)
32+
try await wrapper.updateRegistry(from: newRegistry, qemuProcess)
33+
}
34+
}
35+
}
36+
37+
@MainActor
38+
class UTMScriptingRegistryEntryImpl {
39+
private(set) var registry: UTMRegistryEntry
40+
41+
init(_ registry: UTMRegistryEntry) {
42+
self.registry = registry
43+
}
44+
45+
func serializeRegistry() -> [URL] {
46+
return registry.sharedDirectories.compactMap { $0.url }
47+
}
48+
49+
func updateRegistry(from fileUrls: [URL], _ system: UTMQemuSystem?) async throws {
50+
// Clear all shared directories, we add all directories here
51+
registry.removeAllSharedDirectories()
52+
53+
// Add urls to the registry
54+
for url in fileUrls {
55+
// Start scoped access
56+
let isScopedAccess = url.startAccessingSecurityScopedResource()
57+
defer {
58+
if isScopedAccess {
59+
url.stopAccessingSecurityScopedResource()
60+
}
61+
}
62+
63+
// Get bookmark from UTM process
64+
let standardBookmark = try url.bookmarkData()
65+
let system = system ?? UTMProcess()
66+
let (success, bookmark, path) = await system.accessData(withBookmark: standardBookmark, securityScoped: false)
67+
guard let bookmark = bookmark, let _ = path, success else {
68+
throw UTMQemuVirtualMachineError.accessDriveImageFailed
69+
}
70+
71+
// Store bookmark in registry
72+
let file = UTMRegistryEntry.File(dummyFromPath: url.path, remoteBookmark: bookmark)
73+
registry.appendSharedDirectory(file)
74+
}
75+
76+
}
77+
}

Scripting/UTMScriptingVirtualMachineImpl.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,12 @@ class UTMScriptingVirtualMachineImpl: NSObject, UTMScriptable {
9090
}
9191
}
9292

93+
var qemuProcess: UTMQemuSystem? {
94+
get async {
95+
await (vm as? UTMQemuVirtualMachine)?.system
96+
}
97+
}
98+
9399
override var objectSpecifier: NSScriptObjectSpecifier? {
94100
let appDescription = NSApplication.classDescription() as! NSScriptClassDescription
95101
return NSUniqueIDSpecifier(containerClassDescription: appDescription,

Services/UTMQemuVirtualMachine.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,8 @@ final class UTMQemuVirtualMachine: UTMSpiceVirtualMachine {
129129

130130
private let qemuVM = QEMUVirtualMachine()
131131

132-
private var system: UTMQemuSystem? {
132+
/// QEMU Process interface
133+
var system: UTMQemuSystem? {
133134
get async {
134135
await qemuVM.launcher as? UTMQemuSystem
135136
}

Services/UTMRegistryEntry.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,10 @@ extension UTMRegistryEntry: UTMRegistryEntryDecodable {}
260260
}
261261
}
262262

263+
func appendSharedDirectory(_ file: File) {
264+
sharedDirectories.append(file)
265+
}
266+
263267
func removeAllSharedDirectories() {
264268
sharedDirectories = []
265269
}

UTM.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,7 @@
272272
B3DDF57226E9BBA300CE47F0 /* AltKit in Frameworks */ = {isa = PBXBuildFile; productRef = B3DDF57126E9BBA300CE47F0 /* AltKit */; };
273273
CD77BE422CAB51B40074ADD2 /* UTMScriptingExportCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD77BE412CAB519F0074ADD2 /* UTMScriptingExportCommand.swift */; };
274274
CD77BE442CB38F060074ADD2 /* UTMScriptingImportCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD77BE432CB38F060074ADD2 /* UTMScriptingImportCommand.swift */; };
275+
CD84C2092D3B446D00829850 /* UTMScriptingRegistryEntryImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD84C2082D3B446D00829850 /* UTMScriptingRegistryEntryImpl.swift */; };
275276
CE020BA324AEDC7C00B44AB6 /* UTMData.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE020BA224AEDC7C00B44AB6 /* UTMData.swift */; };
276277
CE020BA424AEDC7C00B44AB6 /* UTMData.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE020BA224AEDC7C00B44AB6 /* UTMData.swift */; };
277278
CE020BA724AEDEF000B44AB6 /* Logging in Frameworks */ = {isa = PBXBuildFile; productRef = CE020BA624AEDEF000B44AB6 /* Logging */; };
@@ -1779,6 +1780,7 @@
17791780
C8958B6D243634DA002D86B4 /* ko */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ko; path = ko.lproj/Localizable.strings; sourceTree = "<group>"; };
17801781
CD77BE412CAB519F0074ADD2 /* UTMScriptingExportCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UTMScriptingExportCommand.swift; sourceTree = "<group>"; };
17811782
CD77BE432CB38F060074ADD2 /* UTMScriptingImportCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UTMScriptingImportCommand.swift; sourceTree = "<group>"; };
1783+
CD84C2082D3B446D00829850 /* UTMScriptingRegistryEntryImpl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UTMScriptingRegistryEntryImpl.swift; sourceTree = "<group>"; };
17821784
CE020BA224AEDC7C00B44AB6 /* UTMData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UTMData.swift; sourceTree = "<group>"; };
17831785
CE020BAA24AEE00000B44AB6 /* UTMLoggingSwift.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UTMLoggingSwift.swift; sourceTree = "<group>"; };
17841786
CE020BB524B14F8400B44AB6 /* UTMVirtualMachine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UTMVirtualMachine.swift; sourceTree = "<group>"; };
@@ -3027,6 +3029,7 @@
30273029
CEC794B9294924E300121A9F /* UTMScriptingSerialPortImpl.swift */,
30283030
CE25124829BFDBA6000790AB /* UTMScriptingGuestFileImpl.swift */,
30293031
CE25124629BFDB87000790AB /* UTMScriptingGuestProcessImpl.swift */,
3032+
CD84C2082D3B446D00829850 /* UTMScriptingRegistryEntryImpl.swift */,
30303033
CE25124C29C55816000790AB /* UTMScriptingConfigImpl.swift */,
30313034
CE25125429C80CD4000790AB /* UTMScriptingCreateCommand.swift */,
30323035
CD77BE432CB38F060074ADD2 /* UTMScriptingImportCommand.swift */,
@@ -3724,6 +3727,7 @@
37243727
CEBE820D26A4C8E0007AAB12 /* VMWizardSummaryView.swift in Sources */,
37253728
8401FDB2269E602000265F0D /* VMConfigAppleDriveDetailsView.swift in Sources */,
37263729
841619B428431DA5000034B2 /* UTMQemuConfigurationQEMU.swift in Sources */,
3730+
CD84C2092D3B446D00829850 /* UTMScriptingRegistryEntryImpl.swift in Sources */,
37273731
CEF0307626A2B40B00667B63 /* VMWizardHardwareView.swift in Sources */,
37283732
CED234EE254796E500ED0A57 /* NumberTextField.swift in Sources */,
37293733
841619B028431952000034B2 /* UTMQemuConfigurationSystem.swift in Sources */,

0 commit comments

Comments
 (0)