6 Replies
      Latest reply on Jan 11, 2020 1:18 PM by SlaunchaMan
      SlaunchaMan Level 1 Level 1 (0 points)

        I’m trying to write a utility to help automate some things with simctl. My thought was to write a quick command-line application in Swift, using the Task API to launch things, but it appears that due to App Sandboxing (I’m on 10.15) I can’t actually launch an executable in /usr/bin:

         

        Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'launch path not accessible'

         

        I tried creating an Entitlements file to disable the sandbox, but this didn’t work:

         

        <?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>
          <false/>
        </dict>
        </plist>
        

         

        What I’m trying to write is a developer tool with no plans of distribution. Is there a way to write a Swift app that launches software like this locally, or has this been completely locked down with this iteration of macOS?

        • Re: Launching Unix tools from command-line apps
          john daniel Level 4 Level 4 (530 points)

          Maybe post code that described how you are launching this task. I do this hundreds of times from my sandboxed app.

          • Re: Launching Unix tools from command-line apps
            eskimo Apple Staff Apple Staff (12,715 points)

            I’m trying to write a utility to help automate some things with simctl …  I can’t actually launch an executable in /usr/bin

            simctl isn’t in /usr/bin:

            % which simctl
            simctl not found

            I suspect you’re using xcrun:

            % which xcrun
            /usr/bin/xcrun

            This is a trampoline that bounces to the default Xcode (selected using xcode-select).

            How you should proceed here depends on your deploy strategy:

            • If you’re just building this for yourself, disable App Sandbox and move on.

              Note Setting com.apple.security.app-sandbox to false is not the right way to disable the App Sandbox.  If you’re using Xcode, remove the App Sandbox slice from the Signing & Capabilities editor.  If you’re not using Xcode, remove the com.apple.security.app-sandbox entitlement entirely.

            • If you’re deploying to the Mac App Store, I don’t think you’ll be able to make this work.  For a start, the user can place the default Xcode anywhere on disk.  Second, simctl uses IPC to the simulator infrastructure to do its job, and it’s likely that’ll be blocked by the sandbox.

            • If you’re deploying to a wide range of users outside of the Mac App Store, you can choose to enable the sandbox or not.  If you do enable the sandbox, it’s likely that you can add enough temporary exceptions to get things working, but I suspect that your solution is going to end up being very brittle.

            Share and Enjoy

            Quinn “The Eskimo!”
            Apple Developer Relations, Developer Technical Support, Core OS/Hardware
            let myEmail = "eskimo" + "1" + "@apple.com"

              • Re: Launching Unix tools from command-line apps
                SlaunchaMan Level 1 Level 1 (0 points)

                Thanks for the reply. You’re right, I’m using xcrun to launch simctl. Here’s a simple example of how I’m trying to launch the process, from a Swift command-line utility. The app sandbox is not in the Signing & Capabilities section of Xcode, and there are no entitlements:

                 

                import Foundation
                
                let process = Process()
                process.arguments = ["/bin/echo", "Hello, World!"]
                
                process.launch()
                
                process.waitUntilExit()

                 

                This generates the above error about reading from that location.

                  • Re: Launching Unix tools from command-line apps
                    SlaunchaMan Level 1 Level 1 (0 points)

                    I’ve also tried using NSUserUnixTask, but this seems to quit immediately:

                     

                    let url = URL(fileURLWithPath: "/bin/echo")
                    
                    do {
                        let task = try NSUserUnixTask(url: url)
                        
                        task.standardOutput = FileHandle(forWritingAtPath: "/Users/jeff/Desktop/test")
                        
                        task.execute(withArguments: ["test"]) { error in
                            if let error = error {
                                fatalError(error.localizedDescription)
                            }
                            
                            print("Hello")
                        }
                    }
                    catch {
                        fatalError(error.localizedDescription)
                    }
                    
                    

                     

                    My print statement never prints, and the file is not written. If I create the file, it does not receive any contents.

                      • Re: Launching Unix tools from command-line apps
                        SlaunchaMan Level 1 Level 1 (0 points)

                        OK, more progress. This works—apparently I just wasn’t letting the task live long enough:

                         

                        let url = URL(fileURLWithPath: "/bin/echo")
                        
                        do {
                            let task = try NSUserUnixTask(url: url)
                            
                            task.standardOutput = FileHandle(forWritingAtPath: "/Users/jeff/Desktop/test")
                            
                            task.execute(withArguments: ["test"]) { error in
                                if let error = error {
                                    fatalError(error.localizedDescription)
                                }
                                
                                print("Hello")
                                
                                exit(0)
                            }
                        }
                        catch {
                            fatalError(error.localizedDescription)
                        }
                        
                        dispatchMain()