Forráskód Böngészése

services: rename UTMQemu to UTMProcess

osy 2 éve
szülő
commit
7f80bf8fa6

+ 1 - 1
QEMUHelper/QEMUHelper.m

@@ -131,7 +131,7 @@
     task.qualityOfService = NSQualityOfServiceUserInitiated;
     task.terminationHandler = ^(NSTask *task) {
         _self.childTask = nil;
-        [_self.connection.remoteObjectProxy qemuHasExited:task.terminationStatus message:nil];
+        [_self.connection.remoteObjectProxy processHasExited:task.terminationStatus message:nil];
     };
     if (![task launchAndReturnError:&err]) {
         NSLog(@"Error starting QEMU: %@", err);

+ 1 - 1
QEMUHelper/QEMUHelperDelegate.h

@@ -20,7 +20,7 @@ NS_ASSUME_NONNULL_BEGIN
 
 @protocol QEMUHelperDelegate <NSObject>
 
-- (void)qemuHasExited:(NSInteger)exitCode message:(nullable NSString *)message;
+- (void)processHasExited:(NSInteger)exitCode message:(nullable NSString *)message;
 
 @end
 

+ 1 - 1
Services/Swift-Bridging-Header.h

@@ -25,7 +25,7 @@
 #include "UTMLegacyQemuConfiguration+Sharing.h"
 #include "UTMLegacyQemuConfiguration+System.h"
 #include "UTMLegacyQemuConfigurationPortForward.h"
-#include "UTMQemu.h"
+#include "UTMProcess.h"
 #include "UTMQemuSystem.h"
 #include "UTMJailbreak.h"
 #include "UTMLogging.h"

+ 10 - 10
Services/UTMQemu.h → Services/UTMProcess.h

@@ -15,35 +15,35 @@
 //
 
 #import <Foundation/Foundation.h>
-#import "QEMUHelperProtocol.h"
-@import QEMUKitInternal;
 
-typedef void * _Nullable (* _Nonnull UTMQemuThreadEntry)(void * _Nullable args);
+@class UTMProcess;
 
 NS_ASSUME_NONNULL_BEGIN
 
-@interface UTMQemu : NSObject
+typedef int (*UTMProcessThreadEntry)(UTMProcess *self, int argc, const char * _Nonnull argv[_Nonnull], const char * _Nonnull envp[_Nonnull]);
+
+@interface UTMProcess : NSObject
 
 @property (nonatomic, readonly) BOOL hasRemoteProcess;
 @property (nonatomic, readonly) NSURL *libraryURL;
 @property (nonatomic) NSArray<NSString *> *argv;
 @property (nonatomic, nullable) NSDictionary<NSString *, NSString *> *environment;
-@property (nonatomic) dispatch_semaphore_t done;
 @property (nonatomic) NSInteger status;
 @property (nonatomic) NSInteger fatal;
-@property (nonatomic) UTMQemuThreadEntry entry;
-@property (nonatomic, nullable) QEMULogging *logging;
+@property (nonatomic) UTMProcessThreadEntry entry;
+@property (nonatomic, nullable) NSPipe *standardOutput;
+@property (nonatomic, nullable) NSPipe *standardError;
 
 - (instancetype)init;
 - (instancetype)initWithArguments:(NSArray<NSString *> *)arguments NS_DESIGNATED_INITIALIZER;
 - (void)pushArgv:(nullable NSString *)arg;
 - (void)clearArgv;
-- (void)startQemu:(nonnull NSString *)name completion:(nonnull void (^)(NSError * _Nullable))completion;
-- (void)stopQemu;
+- (void)startProcess:(nonnull NSString *)name completion:(nonnull void (^)(NSError * _Nullable))completion;
+- (void)stopProcess;
 - (void)accessDataWithBookmark:(NSData *)bookmark;
 - (void)accessDataWithBookmark:(NSData *)bookmark securityScoped:(BOOL)securityScoped completion:(void(^)(BOOL, NSData * _Nullable, NSString * _Nullable))completion;
 - (void)stopAccessingPath:(nullable NSString *)path;
-- (void)qemuHasExited:(NSInteger)exitCode message:(nullable NSString *)message;
+- (void)processHasExited:(NSInteger)exitCode message:(nullable NSString *)message;
 
 @end
 

+ 61 - 21
Services/UTMQemu.m → Services/UTMProcess.m

@@ -14,27 +14,67 @@
 // limitations under the License.
 //
 
-#import "UTMQemu.h"
+#import "UTMProcess.h"
 #import "UTMLogging.h"
 #import "QEMUHelperDelegate.h"
+#import "QEMUHelperProtocol.h"
 #import <dlfcn.h>
 #import <pthread.h>
 #import <TargetConditionals.h>
 
 extern NSString *const kUTMErrorDomain;
 
-@interface UTMQemu ()
+@interface UTMProcess ()
 
 @property (nonatomic) dispatch_queue_t completionQueue;
+@property (nonatomic) dispatch_semaphore_t done;
+@property (nonatomic, nullable) NSString *processName;
 
 @end
 
-@implementation UTMQemu {
+@implementation UTMProcess {
     NSMutableArray<NSString *> *_argv;
     NSMutableArray<NSURL *> *_urls;
     NSXPCConnection *_connection;
 }
 
+static void *startProcess(void *args) {
+    UTMProcess *self = (__bridge_transfer UTMProcess *)args;
+    NSArray<NSString *> *processArgv = self.argv;
+    NSMutableArray<NSString *> *environment = [NSMutableArray arrayWithCapacity:self.environment.count];
+    
+    /* set up environment variables */
+    [self.environment enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *value, BOOL *stop) {
+        NSString *combined = [NSString stringWithFormat:@"%@=%@", key, value];
+        [environment addObject:combined];
+        setenv(key.UTF8String, value.UTF8String, 1);
+    }];
+    NSUInteger envc = environment.count;
+    const char *envp[envc + 1];
+    for (NSUInteger i = 0; i < envc; i++) {
+        envp[i] = environment[i].UTF8String;
+    }
+    envp[envc] = NULL;
+    setenv("TMPDIR", NSFileManager.defaultManager.temporaryDirectory.path.UTF8String, 1);
+    
+    int argc = (int)processArgv.count + 1;
+    const char *argv[argc];
+    argv[0] = [self.processName cStringUsingEncoding:NSUTF8StringEncoding];
+    if (!argv[0]) {
+        argv[0] = "process";
+    }
+    for (int i = 0; i < processArgv.count; i++) {
+        argv[i+1] = [processArgv[i] UTF8String];
+    }
+    self.status = self.entry(self, argc, argv, envp);
+    dispatch_semaphore_signal(self.done);
+    return NULL;
+}
+
+static int defaultEntry(UTMProcess *self, int argc, const char *argv[], const char *envp[]) {
+    return -1;
+}
+
 #pragma mark - Properties
 
 @synthesize argv = _argv;
@@ -65,12 +105,14 @@ extern NSString *const kUTMErrorDomain;
         }
         dispatch_queue_attr_t attr = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_UTILITY, QOS_MIN_RELATIVE_PRIORITY);
         self.completionQueue = dispatch_queue_create("QEMU Completion Queue", attr);
+        self.entry = defaultEntry;
+        self.done = dispatch_semaphore_create(0);
     }
     return self;
 }
 
 - (void)dealloc {
-    [self stopQemu];
+    [self stopProcess];
 }
 
 #pragma mark - Methods
@@ -110,9 +152,7 @@ extern NSString *const kUTMErrorDomain;
             args = [args stringByAppendingFormat:@" %@", arg];
         }
     }
-    NSString *line = [[NSString alloc] initWithFormat:@"Running: %@\n", args];
-    [self.logging writeLine:line];
-    NSLog(@"%@", line);
+    UTMLog(@"Running: %@", args);
 }
 
 - (BOOL)didLoadDylib:(void *)handle {
@@ -127,7 +167,6 @@ extern NSString *const kUTMErrorDomain;
     
     NSAssert(self.entry != NULL, @"entry is NULL!");
     self.status = self.fatal = 0;
-    self.done = dispatch_semaphore_create(0);
     UTMLog(@"Loading %@", dylib);
     dlctx = dlopen([dylib UTF8String], RTLD_LOCAL);
     if (dlctx == NULL) {
@@ -151,24 +190,24 @@ extern NSString *const kUTMErrorDomain;
             pthread_exit(NULL);
         }
     }) != 0) {
-        completion([self errorWithMessage:NSLocalizedString(@"Internal error has occurred.", @"UTMQemu")]);
+        completion([self errorWithMessage:NSLocalizedString(@"Internal error has occurred.", @"UTMProcess")]);
         return;
     }
     pthread_attr_init(&qosAttribute);
     pthread_attr_set_qos_class_np(&qosAttribute, QOS_CLASS_USER_INTERACTIVE, 0);
-    pthread_create(&qemu_thread, &qosAttribute, self.entry, (__bridge_retained void *)self);
+    pthread_create(&qemu_thread, &qosAttribute, startProcess, (__bridge_retained void *)self);
     dispatch_async(self.completionQueue, ^{
         if (dispatch_semaphore_wait(self.done, DISPATCH_TIME_FOREVER)) {
             dlclose(dlctx);
-            [self qemuHasExited:-1 message:NSLocalizedString(@"Internal error has occurred.", @"UTMQemu")];
+            [self processHasExited:-1 message:NSLocalizedString(@"Internal error has occurred.", @"UTMProcess")];
         } else {
             if (dlclose(dlctx) < 0) {
                 NSString *err = [NSString stringWithUTF8String:dlerror()];
-                [self qemuHasExited:-1 message:err];
+                [self processHasExited:-1 message:err];
             } else if (self.fatal || self.status) {
-                [self qemuHasExited:-1 message:nil];
+                [self processHasExited:-1 message:nil];
             } else {
-                [self qemuHasExited:0 message:nil];
+                [self processHasExited:0 message:nil];
             }
         }
     });
@@ -186,15 +225,15 @@ extern NSString *const kUTMErrorDomain;
         return;
     }
     __weak typeof(self) _self = self;
-    NSFileHandle *standardOutput = self.logging.standardOutput.fileHandleForWriting;
-    NSFileHandle *standardError = self.logging.standardError.fileHandleForWriting;
+    NSFileHandle *standardOutput = self.standardOutput.fileHandleForWriting;
+    NSFileHandle *standardError = self.standardError.fileHandleForWriting;
     [_connection.remoteObjectProxy setEnvironment:self.environment];
     [[_connection remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) {
         if (error.domain == NSCocoaErrorDomain && error.code == NSXPCConnectionInvalid) {
             // inhibit this error since we always see it on quit
-            [_self qemuHasExited:0 message:nil];
+            [_self processHasExited:0 message:nil];
         } else {
-            [_self qemuHasExited:error.code message:error.localizedDescription];
+            [_self processHasExited:error.code message:error.localizedDescription];
         }
     }] startQemu:name standardOutput:standardOutput standardError:standardError libraryBookmark:libBookmark argv:self.argv completion:^(BOOL success, NSString *msg){
         if (!success) {
@@ -205,7 +244,7 @@ extern NSString *const kUTMErrorDomain;
     }];
 }
 
-- (void)startQemu:(nonnull NSString *)name completion:(nonnull void (^)(NSError * _Nullable))completion {
+- (void)startProcess:(nonnull NSString *)name completion:(nonnull void (^)(NSError * _Nullable))completion {
     [self printArgv];
 #if TARGET_OS_IPHONE
     NSString *base = @"";
@@ -213,6 +252,7 @@ extern NSString *const kUTMErrorDomain;
     NSString *base = @"Versions/A/";
 #endif
     NSString *dylib = [NSString stringWithFormat:@"%@.framework/%@%@", name, base, name];
+    self.processName = name;
     if (_connection) {
         [self startQemuRemote:dylib completion:completion];
     } else {
@@ -220,7 +260,7 @@ extern NSString *const kUTMErrorDomain;
     }
 }
 
-- (void)stopQemu {
+- (void)stopProcess {
     if (_connection) {
         [[_connection remoteObjectProxy] terminate];
         [_connection invalidate];
@@ -304,7 +344,7 @@ extern NSString *const kUTMErrorDomain;
     return [NSError errorWithDomain:kUTMErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey: message}];
 }
 
-- (void)qemuHasExited:(NSInteger)exitCode message:(nullable NSString *)message {
+- (void)processHasExited:(NSInteger)exitCode message:(nullable NSString *)message {
     UTMLog(@"QEMU has exited with code %ld and message %@", exitCode, message);
 }
 

+ 8 - 5
Services/UTMQemuImage.swift

@@ -17,7 +17,7 @@
 import Foundation
 import QEMUKitInternal
 
-@objc class UTMQemuImage: UTMQemu {
+@objc class UTMQemuImage: UTMProcess {
     private var logOutput: String = ""
     private var processExitContinuation: CheckedContinuation<Void, any Error>?
     
@@ -25,7 +25,7 @@ import QEMUKitInternal
         super.init(arguments: [])
     }
     
-    override func qemuHasExited(_ exitCode: Int, message: String?) {
+    override func processHasExited(_ exitCode: Int, message: String?) {
         if let processExitContinuation = processExitContinuation {
             self.processExitContinuation = nil
             if exitCode != 0 {
@@ -69,7 +69,8 @@ import QEMUKitInternal
         qemuImg.accessData(withBookmark: dstBookmark)
         qemuImg.pushArgv(dest.path)
         let logging = QEMULogging()
-        qemuImg.logging = logging
+        qemuImg.standardOutput = logging.standardOutput
+        qemuImg.standardError = logging.standardError
         try await qemuImg.start()
     }
     
@@ -125,7 +126,8 @@ import QEMUKitInternal
         qemuImg.pushArgv(url.path)
         let logging = QEMULogging()
         logging.delegate = qemuImg
-        qemuImg.logging = logging
+        qemuImg.standardOutput = logging.standardOutput
+        qemuImg.standardError = logging.standardError
         try await qemuImg.start()
 
         let decoder = JSONDecoder()
@@ -148,7 +150,8 @@ import QEMUKitInternal
         qemuImg.pushArgv(String(size))
         let logging = QEMULogging()
         logging.delegate = qemuImg
-        qemuImg.logging = logging
+        qemuImg.standardOutput = logging.standardOutput
+        qemuImg.standardError = logging.standardError
         try await qemuImg.start()
     }
 }

+ 4 - 2
Services/UTMQemuSystem.h

@@ -14,7 +14,8 @@
 // limitations under the License.
 //
 
-#import "UTMQemu.h"
+#import "UTMProcess.h"
+@import QEMUKitInternal;
 
 /// Specify the backend renderer for this VM
 typedef NS_ENUM(NSInteger, UTMQEMURendererBackend) {
@@ -34,12 +35,13 @@ typedef NS_ENUM(NSInteger, UTMQEMUSoundBackend) {
 
 NS_ASSUME_NONNULL_BEGIN
 
-@interface UTMQemuSystem : UTMQemu <QEMULauncher>
+@interface UTMQemuSystem : UTMProcess <QEMULauncher>
 
 @property (nonatomic, nullable, copy) NSArray<NSURL *> *resources;
 @property (nonatomic, nullable, weak) NSDictionary<NSURL *, NSData *> *remoteBookmarks;
 @property (nonatomic) UTMQEMURendererBackend rendererBackend;
 @property (nonatomic, weak) id<QEMULauncherDelegate> launcherDelegate;
+@property (nonatomic, nullable) QEMULogging *logging;
 
 - (instancetype)init NS_UNAVAILABLE;
 - (instancetype)initWithArguments:(NSArray<NSString *> *)arguments NS_UNAVAILABLE;

+ 29 - 36
Services/UTMQemuSystem.m

@@ -30,42 +30,15 @@
     void (*_qemu_cleanup)(void);
 }
 
-static void *start_qemu(void *args) {
-    UTMQemuSystem *self = (__bridge_transfer UTMQemuSystem *)args;
-    NSArray<NSString *> *qemuArgv = self.argv;
-    NSMutableArray<NSString *> *environment = [NSMutableArray arrayWithCapacity:self.environment.count];
-    
-    NSCAssert(self->_qemu_init != NULL, @"Started thread with invalid function.");
-    NSCAssert(self->_qemu_main_loop != NULL, @"Started thread with invalid function.");
-    NSCAssert(self->_qemu_cleanup != NULL, @"Started thread with invalid function.");
-    NSCAssert(qemuArgv, @"Started thread with invalid argv.");
-    
-    /* set up environment variables */
-    [self.environment enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *value, BOOL *stop) {
-        NSString *combined = [NSString stringWithFormat:@"%@=%@", key, value];
-        [environment addObject:combined];
-        setenv(key.UTF8String, value.UTF8String, 1);
-    }];
-    NSUInteger envc = environment.count;
-    const char *envp[envc + 1];
-    for (NSUInteger i = 0; i < envc; i++) {
-        envp[i] = environment[i].UTF8String;
+static int startQemu(UTMProcess *process, int argc, const char *argv[], const char *envp[]) {
+    UTMQemuSystem *self = (UTMQemuSystem *)process;
+    int ret = self->_qemu_init(argc, argv, envp);
+    if (ret != 0) {
+        return ret;
     }
-    envp[envc] = NULL;
-    setenv("TMPDIR", NSFileManager.defaultManager.temporaryDirectory.path.UTF8String, 1);
-    
-    int argc = (int)qemuArgv.count + 1;
-    const char *argv[argc];
-    argv[0] = "qemu-system";
-    for (int i = 0; i < qemuArgv.count; i++) {
-        argv[i+1] = [qemuArgv[i] UTF8String];
-    }
-    self->_qemu_init(argc, argv, envp);
     self->_qemu_main_loop();
     self->_qemu_cleanup();
-    self.status = 0;
-    dispatch_semaphore_signal(self.done);
-    return NULL;
+    return 0;
 }
 
 - (void)setRendererBackend:(UTMQEMURendererBackend)rendererBackend {
@@ -81,10 +54,26 @@ static void *start_qemu(void *args) {
     }
 }
 
+- (NSPipe *)standardOutput {
+    return self.logging.standardOutput;
+}
+
+- (void)setStandardOutput:(NSPipe *)standardOutput {
+    [self doesNotRecognizeSelector:_cmd];
+}
+
+- (NSPipe *)standardError {
+    return self.logging.standardError;
+}
+
+- (void)setStandardError:(NSPipe *)standardError {
+    [self doesNotRecognizeSelector:_cmd];
+}
+
 - (instancetype)initWithArguments:(NSArray<NSString *> *)arguments architecture:(nonnull NSString *)architecture {
     self = [super initWithArguments:arguments];
     if (self) {
-        self.entry = start_qemu;
+        self.entry = startQemu;
         self.architecture = architecture;
     }
     return self;
@@ -121,11 +110,15 @@ static void *start_qemu(void *args) {
     }
     dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
     NSString *name = [NSString stringWithFormat:@"qemu-%@-softmmu", self.architecture];
-    [self startQemu:name completion:completion];
+    [self startProcess:name completion:completion];
+}
+
+- (void)stopQemu {
+    [self stopProcess];
 }
 
 /// Called by superclass
-- (void)qemuHasExited:(NSInteger)exitCode message:(nullable NSString *)message {
+- (void)processHasExited:(NSInteger)exitCode message:(nullable NSString *)message {
     [self.launcherDelegate qemuLauncher:self didExitWithExitCode:exitCode message:message];
 }
 

+ 3 - 3
Services/UTMQemuVirtualMachine.swift

@@ -183,7 +183,7 @@ extension UTMQemuVirtualMachine {
             return
         }
         // if VM has not started yet, we create a temporary process
-        let system = await system ?? UTMQemu()
+        let system = await system ?? UTMProcess()
         var bookmark = await registryEntry.package.remoteBookmark
         let existing = bookmark != nil
         if !existing {
@@ -632,7 +632,7 @@ extension UTMQemuVirtualMachine {
     }
     
     private func changeMedium(_ drive: UTMQemuConfigurationDrive, with bookmark: Data, url: URL?, isSecurityScoped: Bool) async throws {
-        let system = await system ?? UTMQemu()
+        let system = await system ?? UTMProcess()
         let (success, bookmark, path) = await system.accessData(withBookmark: bookmark, securityScoped: isSecurityScoped)
         guard let bookmark = bookmark, let path = path, success else {
             throw UTMQemuVirtualMachineError.accessDriveImageFailed
@@ -715,7 +715,7 @@ extension UTMQemuVirtualMachine {
     }
     
     func changeVirtfsSharedDirectory(with bookmark: Data, isSecurityScoped: Bool) async throws {
-        let system = await system ?? UTMQemu()
+        let system = await system ?? UTMProcess()
         let (success, bookmark, path) = await system.accessData(withBookmark: bookmark, securityScoped: isSecurityScoped)
         guard let bookmark = bookmark, let _ = path, success else {
             throw UTMQemuVirtualMachineError.accessDriveImageFailed

+ 10 - 10
UTM.xcodeproj/project.pbxproj

@@ -326,7 +326,7 @@
 		CE0B6CFB24AD568400FE012D /* UTMLegacyQemuConfiguration+Networking.m in Sources */ = {isa = PBXBuildFile; fileRef = CEA02A982436C7A30087E45F /* UTMLegacyQemuConfiguration+Networking.m */; };
 		CE0B6CFC24AD568400FE012D /* UTMLegacyQemuConfigurationPortForward.m in Sources */ = {isa = PBXBuildFile; fileRef = CE54252D2436E48D00E520F7 /* UTMLegacyQemuConfigurationPortForward.m */; };
 		CE0B6CFE24AD56AE00FE012D /* UTMLogging.m in Sources */ = {isa = PBXBuildFile; fileRef = CE6EDCE1241DA0E900A719DC /* UTMLogging.m */; };
-		CE0B6D0224AD56AE00FE012D /* UTMQemu.m in Sources */ = {isa = PBXBuildFile; fileRef = CE9D197B226542FE00355E14 /* UTMQemu.m */; };
+		CE0B6D0224AD56AE00FE012D /* UTMProcess.m in Sources */ = {isa = PBXBuildFile; fileRef = CE9D197B226542FE00355E14 /* UTMProcess.m */; };
 		CE0B6D0424AD56AE00FE012D /* UTMSpiceIO.m in Sources */ = {isa = PBXBuildFile; fileRef = E2D64BC8241DB24B0034E0C6 /* UTMSpiceIO.m */; };
 		CE0B6EBB24AD677200FE012D /* libgstgio.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CE9D19622265425A00355E14 /* libgstgio.a */; };
 		CE0B6EBC24AD677200FE012D /* gstpbutils-1.0.0.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CE2D640E22653C7500FC7E63 /* gstpbutils-1.0.0.framework */; };
@@ -426,7 +426,7 @@
 		CE25125529C80CD4000790AB /* UTMScriptingCreateCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE25125429C80CD4000790AB /* UTMScriptingCreateCommand.swift */; };
 		CE2D926A24AD46670059923A /* VMDisplayMetalViewController+Pointer.h in Sources */ = {isa = PBXBuildFile; fileRef = 83FBDD53242FA71900D2C5D7 /* VMDisplayMetalViewController+Pointer.h */; };
 		CE2D927A24AD46670059923A /* UTMLegacyQemuConfiguration+System.m in Sources */ = {isa = PBXBuildFile; fileRef = CE5425332437C22A00E520F7 /* UTMLegacyQemuConfiguration+System.m */; };
-		CE2D927C24AD46670059923A /* UTMQemu.m in Sources */ = {isa = PBXBuildFile; fileRef = CE9D197B226542FE00355E14 /* UTMQemu.m */; };
+		CE2D927C24AD46670059923A /* UTMProcess.m in Sources */ = {isa = PBXBuildFile; fileRef = CE9D197B226542FE00355E14 /* UTMProcess.m */; };
 		CE2D928024AD46670059923A /* UTMLegacyQemuConfigurationPortForward.m in Sources */ = {isa = PBXBuildFile; fileRef = CE54252D2436E48D00E520F7 /* UTMLegacyQemuConfigurationPortForward.m */; };
 		CE2D928E24AD46670059923A /* UTMLegacyQemuConfiguration+Miscellaneous.m in Sources */ = {isa = PBXBuildFile; fileRef = CEE0421124418F2E0001680F /* UTMLegacyQemuConfiguration+Miscellaneous.m */; };
 		CE2D929C24AD46670059923A /* UTMLegacyViewState.m in Sources */ = {isa = PBXBuildFile; fileRef = CE6EDCDE241C4A6800A719DC /* UTMLegacyViewState.m */; };
@@ -643,7 +643,7 @@
 		CEA45E27263519B5002FA97D /* VMRemovableDrivesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE2D954524AD4F980059923A /* VMRemovableDrivesView.swift */; };
 		CEA45E37263519B5002FA97D /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE772AAB25C8B0F600E4E379 /* ContentView.swift */; };
 		CEA45E3A263519B5002FA97D /* UTMLegacyQemuConfiguration+System.m in Sources */ = {isa = PBXBuildFile; fileRef = CE5425332437C22A00E520F7 /* UTMLegacyQemuConfiguration+System.m */; };
-		CEA45E3F263519B5002FA97D /* UTMQemu.m in Sources */ = {isa = PBXBuildFile; fileRef = CE9D197B226542FE00355E14 /* UTMQemu.m */; };
+		CEA45E3F263519B5002FA97D /* UTMProcess.m in Sources */ = {isa = PBXBuildFile; fileRef = CE9D197B226542FE00355E14 /* UTMProcess.m */; };
 		CEA45E43263519B5002FA97D /* UTMLegacyQemuConfigurationPortForward.m in Sources */ = {isa = PBXBuildFile; fileRef = CE54252D2436E48D00E520F7 /* UTMLegacyQemuConfigurationPortForward.m */; };
 		CEA45E4B263519B5002FA97D /* BusyOverlay.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE7D972B24B2B17D0080CB69 /* BusyOverlay.swift */; };
 		CEA45E4E263519B5002FA97D /* VMConfigDisplayView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE2D953724AD4F980059923A /* VMConfigDisplayView.swift */; };
@@ -1588,8 +1588,8 @@
 		CE9D19632265425A00355E14 /* libgsttypefindfunctions.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libgsttypefindfunctions.a; path = "$(SYSROOT_DIR)/lib/gstreamer-1.0/libgsttypefindfunctions.a"; sourceTree = "<group>"; };
 		CE9D19642265425A00355E14 /* libgstvideotestsrc.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libgstvideotestsrc.a; path = "$(SYSROOT_DIR)/lib/gstreamer-1.0/libgstvideotestsrc.a"; sourceTree = "<group>"; };
 		CE9D19652265425A00355E14 /* libgstosxaudio.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libgstosxaudio.a; path = "$(SYSROOT_DIR)/lib/gstreamer-1.0/libgstosxaudio.a"; sourceTree = "<group>"; };
-		CE9D197A226542FE00355E14 /* UTMQemu.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = UTMQemu.h; sourceTree = "<group>"; };
-		CE9D197B226542FE00355E14 /* UTMQemu.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = UTMQemu.m; sourceTree = "<group>"; };
+		CE9D197A226542FE00355E14 /* UTMProcess.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = UTMProcess.h; sourceTree = "<group>"; };
+		CE9D197B226542FE00355E14 /* UTMProcess.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = UTMProcess.m; sourceTree = "<group>"; };
 		CEA02A972436C7A30087E45F /* UTMLegacyQemuConfiguration+Networking.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "UTMLegacyQemuConfiguration+Networking.h"; sourceTree = "<group>"; };
 		CEA02A982436C7A30087E45F /* UTMLegacyQemuConfiguration+Networking.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "UTMLegacyQemuConfiguration+Networking.m"; sourceTree = "<group>"; };
 		CEA45FB9263519B5002FA97D /* UTM SE.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "UTM SE.app"; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -2285,8 +2285,8 @@
 				CE6EDCE1241DA0E900A719DC /* UTMLogging.m */,
 				CE020BAA24AEE00000B44AB6 /* UTMLoggingSwift.swift */,
 				CEDF83F8258AE24E0030E4AC /* UTMPasteboard.swift */,
-				CE9D197A226542FE00355E14 /* UTMQemu.h */,
-				CE9D197B226542FE00355E14 /* UTMQemu.m */,
+				CE9D197A226542FE00355E14 /* UTMProcess.h */,
+				CE9D197B226542FE00355E14 /* UTMProcess.m */,
 				8453DCB3278CE5410037A0DA /* UTMQemuImage.swift */,
 				84A0A8822A47D52E0038F329 /* UTMQemuPort.swift */,
 				CE03D05424D90BE000F76B84 /* UTMQemuSystem.h */,
@@ -2817,7 +2817,7 @@
 				847BF9AA2A49C783000BD9AA /* VMData.swift in Sources */,
 				CE2D927A24AD46670059923A /* UTMLegacyQemuConfiguration+System.m in Sources */,
 				843BF8302844853E0029D60D /* UTMQemuConfigurationNetwork.swift in Sources */,
-				CE2D927C24AD46670059923A /* UTMQemu.m in Sources */,
+				CE2D927C24AD46670059923A /* UTMProcess.m in Sources */,
 				CEBE820326A4C1B5007AAB12 /* VMWizardDrivesView.swift in Sources */,
 				84018689288A44C20050AC51 /* VMWindowState.swift in Sources */,
 				84258C42288F806400C66366 /* VMToolbarUSBMenuView.swift in Sources */,
@@ -3054,7 +3054,7 @@
 				CE03D0D424DCF6DD00F76B84 /* VMMetalViewInputDelegate.swift in Sources */,
 				848F71EA277A2A4E006A0240 /* UTMSerialPort.swift in Sources */,
 				CE25124D29C55816000790AB /* UTMScriptingConfigImpl.swift in Sources */,
-				CE0B6D0224AD56AE00FE012D /* UTMQemu.m in Sources */,
+				CE0B6D0224AD56AE00FE012D /* UTMProcess.m in Sources */,
 				CEF0306026A2AFDF00667B63 /* VMWizardState.swift in Sources */,
 				CEF0300826A25A6900667B63 /* VMWizardView.swift in Sources */,
 				CE928C2A26ABE6690099F293 /* UTMAppleVirtualMachine.swift in Sources */,
@@ -3163,7 +3163,7 @@
 				841619AF28431952000034B2 /* UTMQemuConfigurationSystem.swift in Sources */,
 				8432329528C2ED9000CFBC97 /* FileBrowseField.swift in Sources */,
 				843BF82528441EAD0029D60D /* UTMQemuConfigurationDisplay.swift in Sources */,
-				CEA45E3F263519B5002FA97D /* UTMQemu.m in Sources */,
+				CEA45E3F263519B5002FA97D /* UTMProcess.m in Sources */,
 				CEA45E43263519B5002FA97D /* UTMLegacyQemuConfigurationPortForward.m in Sources */,
 				843BF841284555E70029D60D /* UTMQemuConfigurationPortForward.swift in Sources */,
 				84A0A8842A47D52E0038F329 /* UTMQemuPort.swift in Sources */,