forked from JuliaLang/julia
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
When a julia executable is found, if it's not in a framework then there is no way to know what version it is. To determine the version, run a simple julia expression to print the version. Of course, running any random executable named 'Julia' isn't smart so the executable is instead run inside an App Sandbox with mostly restricted permissions. The only special permission granted to the sandbox is the read/exec '/' permission to allow the executable to be read and executed.
- Loading branch information
1 parent
57367d5
commit bb9310d
Showing
10 changed files
with
538 additions
and
28 deletions.
There are no files selected for viewing
12 changes: 12 additions & 0 deletions
12
contrib/mac/frameworkapp/ExecSandbox/ExecSandbox.entitlements
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | ||
<plist version="1.0"> | ||
<dict> | ||
<key>com.apple.security.app-sandbox</key> | ||
<true/> | ||
<key>com.apple.security.temporary-exception.files.absolute-path.read-only</key> | ||
<array> | ||
<string>/</string> | ||
</array> | ||
</dict> | ||
</plist> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
// This file is a part of Julia. License is MIT: https://julialang.org/license | ||
|
||
@import Foundation; | ||
#import "ExecSandboxProtocol.h" | ||
|
||
@interface ExecSandbox : NSObject <ExecSandboxProtocol> | ||
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
// This file is a part of Julia. License is MIT: https://julialang.org/license | ||
|
||
#import "ExecSandbox.h" | ||
|
||
@class JuliaTask; | ||
|
||
@interface ExecSandbox () { | ||
NSMutableArray<JuliaTask *> *_Nonnull _tasks; | ||
} | ||
- (void)taskTerminated:(JuliaTask *_Nonnull)jt; | ||
@end | ||
|
||
@interface JuliaTask : NSObject <TaskProtocol> { | ||
ExecSandbox *__weak _delegate; | ||
dispatch_block_t _Nullable _onCleanup; | ||
NSTask *_Nonnull _task; | ||
} | ||
@end | ||
|
||
@implementation JuliaTask | ||
|
||
- (instancetype)initWithTask:(NSTask *_Nonnull)task | ||
delegate:(ExecSandbox *)d | ||
cleanup:(dispatch_block_t)onCleanup { | ||
self = [super init]; | ||
if (self == nil) { | ||
return nil; | ||
} | ||
_delegate = d; | ||
_onCleanup = onCleanup; | ||
_task = task; | ||
return self; | ||
} | ||
|
||
- (void)launch:(void (^_Nullable)(int status))onTermination { | ||
dispatch_block_t onCleanup = _onCleanup; | ||
JuliaTask __weak *weakSelf = self; | ||
_task.terminationHandler = ^(NSTask *_Nonnull t) { | ||
if (onTermination != nil) { | ||
onTermination(t.terminationStatus); | ||
} | ||
if (onCleanup != nil) { | ||
onCleanup(); | ||
} | ||
JuliaTask *strongSelf = weakSelf; | ||
if (strongSelf) { | ||
[strongSelf->_delegate taskTerminated:strongSelf]; | ||
} | ||
}; | ||
@try { | ||
[_task launch]; | ||
} @catch (NSException *exception) { | ||
NSLog(@"NSTask launch exception: %@", exception); | ||
} | ||
} | ||
|
||
- (void)terminate { | ||
@try { | ||
[_task terminate]; | ||
} @catch (NSException *exception) { | ||
NSLog(@"NSTask terminate exception: %@", exception); | ||
} | ||
} | ||
|
||
@end | ||
|
||
@implementation ExecSandbox | ||
|
||
- (instancetype)init { | ||
self = [super init]; | ||
if (self == nil) { | ||
return nil; | ||
} | ||
_tasks = [[NSMutableArray alloc] init]; | ||
return self; | ||
} | ||
|
||
- (void)eval:(NSString *)p | ||
withJulia:(NSData *)executableBookmark | ||
arguments:(NSArray<NSString *> *)baseArgs | ||
task:(void (^)(id<TaskProtocol> task, NSFileHandle *stdIn, | ||
NSFileHandle *stdOut, NSFileHandle *stdErr))reply { | ||
|
||
NSURL *executableURL = | ||
[NSURL URLByResolvingBookmarkData:executableBookmark | ||
options:NSURLBookmarkResolutionWithoutUI | ||
relativeToURL:nil | ||
bookmarkDataIsStale:nil | ||
error:nil]; | ||
if (executableURL == nil) { | ||
reply(nil, nil, nil, nil); | ||
return; | ||
} | ||
|
||
for (NSString *arg in baseArgs) { | ||
if ([arg isEqual:@"--"]) { | ||
reply(nil, nil, nil, nil); | ||
return; | ||
} | ||
} | ||
|
||
NSURL *temporaryDirectoryURL = [NSURL fileURLWithPath:NSTemporaryDirectory() | ||
isDirectory:YES]; | ||
NSString *temporaryFilename = | ||
[[NSProcessInfo processInfo] globallyUniqueString]; | ||
NSURL *temporaryFileURL = | ||
[temporaryDirectoryURL URLByAppendingPathComponent:temporaryFilename | ||
isDirectory:false]; | ||
|
||
[[p dataUsingEncoding:NSUTF8StringEncoding] writeToURL:temporaryFileURL | ||
atomically:false]; | ||
|
||
NSMutableArray<NSString *> *args = [[NSMutableArray alloc] init]; | ||
[args addObjectsFromArray:baseArgs]; | ||
[args addObjectsFromArray:@[ @"--", temporaryFileURL.path ]]; | ||
|
||
NSPipe *stdIn = [NSPipe pipe], *stdOut = [NSPipe pipe], | ||
*stdErr = [NSPipe pipe]; | ||
|
||
NSTask *t = [[NSTask alloc] init]; | ||
if (@available(macOS 10.13, *)) { | ||
t.executableURL = executableURL; | ||
} else { | ||
t.launchPath = executableURL.path; | ||
} | ||
t.arguments = args; | ||
t.standardInput = stdIn; | ||
t.standardOutput = stdOut; | ||
t.standardError = stdErr; | ||
|
||
JuliaTask *jt = | ||
[[JuliaTask alloc] initWithTask:t | ||
delegate:self | ||
cleanup:^() { | ||
[[NSFileManager defaultManager] | ||
removeItemAtURL:temporaryDirectoryURL | ||
error:nil]; | ||
}]; | ||
[_tasks addObject:jt]; | ||
|
||
reply(jt, stdIn.fileHandleForWriting, stdOut.fileHandleForReading, | ||
stdErr.fileHandleForReading); | ||
} | ||
|
||
- (void)taskTerminated:(JuliaTask *_Nonnull)jt { | ||
[_tasks removeObject:jt]; | ||
} | ||
|
||
@end |
31 changes: 31 additions & 0 deletions
31
contrib/mac/frameworkapp/ExecSandbox/ExecSandboxProtocol.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
// This file is a part of Julia. License is MIT: https://julialang.org/license | ||
|
||
@import Foundation; | ||
|
||
@protocol TaskProtocol | ||
/// Launch the task and upon termination receive the exit status. | ||
- (void)launch:(void (^_Nullable)(int status))onTermination; | ||
/// Terminate (SIGTERM) the task. | ||
- (void)terminate; | ||
@end | ||
|
||
@protocol ExecSandboxProtocol | ||
/** | ||
Evaluate a Julia program with a Julia executable. | ||
@param juliaProgram Julia source code to be evaluated. | ||
@param executableBookmark NSURL file bookmark for the julia executable to run. | ||
@param args Arguments to pass to julia. | ||
@param reply Async result with task and standard in, out, and error. An error | ||
occured if task is nil. | ||
*/ | ||
- (void)eval:(NSString *_Nonnull)juliaProgram | ||
withJulia:(NSData *_Nonnull)executableBookmark | ||
arguments:(NSArray<NSString *> *_Nullable)args | ||
task:(void (^_Nonnull)(id<TaskProtocol> _Nullable task, | ||
NSFileHandle *_Nullable stdIn, | ||
NSFileHandle *_Nullable stdOut, | ||
NSFileHandle *_Nullable stdErr))reply; | ||
@end | ||
|
||
NSXPCInterface *_Nonnull CreateExecSandboxXPCInterface(void); |
14 changes: 14 additions & 0 deletions
14
contrib/mac/frameworkapp/ExecSandbox/ExecSandboxProtocol.m
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
// This file is a part of Julia. License is MIT: https://julialang.org/license | ||
|
||
#import "ExecSandboxProtocol.h" | ||
|
||
NSXPCInterface *CreateExecSandboxXPCInterface(void) { | ||
NSXPCInterface *i = | ||
[NSXPCInterface interfaceWithProtocol:@protocol(ExecSandboxProtocol)]; | ||
/// Reply sends a task proxy: | ||
[i setInterface:[NSXPCInterface interfaceWithProtocol:@protocol(TaskProtocol)] | ||
forSelector:@selector(eval:withJulia:arguments:task:) | ||
argumentIndex:0 | ||
ofReply:true]; | ||
return i; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | ||
<plist version="1.0"> | ||
<dict> | ||
<key>CFBundleDevelopmentRegion</key> | ||
<string>$(DEVELOPMENT_LANGUAGE)</string> | ||
<key>CFBundleDisplayName</key> | ||
<string>ExecSandbox</string> | ||
<key>CFBundleExecutable</key> | ||
<string>$(EXECUTABLE_NAME)</string> | ||
<key>CFBundleIdentifier</key> | ||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> | ||
<key>CFBundleInfoDictionaryVersion</key> | ||
<string>6.0</string> | ||
<key>CFBundleName</key> | ||
<string>$(PRODUCT_NAME)</string> | ||
<key>CFBundlePackageType</key> | ||
<string>XPC!</string> | ||
<key>CFBundleShortVersionString</key> | ||
<string>$(APP_SHORT_VERSION_STRING)</string> | ||
<key>CFBundleVersion</key> | ||
<string>$(APP_VERSION)</string> | ||
<key>XPCService</key> | ||
<dict> | ||
<key>RunLoopType</key> | ||
<string>NSRunLoop</string> | ||
<key>ServiceType</key> | ||
<string>Application</string> | ||
</dict> | ||
</dict> | ||
</plist> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
// This file is a part of Julia. License is MIT: https://julialang.org/license | ||
|
||
@import Foundation; | ||
#import "ExecSandbox.h" | ||
|
||
@interface ServiceDelegate : NSObject <NSXPCListenerDelegate> | ||
@end | ||
|
||
@implementation ServiceDelegate | ||
|
||
- (BOOL)listener:(NSXPCListener *)listener | ||
shouldAcceptNewConnection:(NSXPCConnection *)newConnection { | ||
newConnection.exportedInterface = CreateExecSandboxXPCInterface(); | ||
ExecSandbox *exportedObject = [[ExecSandbox alloc] init]; | ||
newConnection.exportedObject = exportedObject; | ||
[newConnection resume]; | ||
return YES; | ||
} | ||
|
||
@end | ||
|
||
int main(int argc, const char *argv[]) { | ||
ServiceDelegate *delegate = [[ServiceDelegate alloc] init]; | ||
NSXPCListener *listener = [NSXPCListener serviceListener]; | ||
listener.delegate = delegate; | ||
[listener resume]; | ||
return 0; | ||
} |
Oops, something went wrong.