1 Reply
      Latest reply on Mar 16, 2020 1:47 PM by eskimo
      JosephDuffy Level 1 Level 1 (0 points)

        Following on my question at https://forums.swift.org/t/how-to-allow-process-to-receive-user-input-when-run-as-part-of-an-executable-e-g-to-enabled-sudo-commands/34357 I am trying to spawn an interactive process using a swift executable, specifically `sudo`.

         

        I've tried a few things but nothing is working so I think I'm missing something fundemental.

         

        I tried using `openpty` but I believe the issue is that I need to pass input to `amaster`, which I'm unsure how to do:

         

        public func runOpenpty(_ command: [String]) throws {
            var amaster: Int32 = 0
            var aslave: Int32 = 0
            if openpty(&amaster, &aslave, nil, nil, nil) == -1 {
                print("Failed to open pty")
            }
        
            let masterHandle = FileHandle(fileDescriptor: amaster, closeOnDealloc: true)
            let slaveHandle = FileHandle(fileDescriptor: aslave, closeOnDealloc: true)
        
            let process = Process()
            process.launchPath = "/usr/bin/env"
            process.arguments = command
            process.standardInput = FileHandle.standardInput
            process.standardOutput = FileHandle.standardOutput
        
            try process.run()
            process.waitUntilExit()
        }

         

        I also came across https://github.com/eonil/PseudoTeletypewriter.Swift, which uses `forkpty`, but I've been unable to get it working from a swift executable.

         

        How can I allow the user to provide input to a process that I spawn from my swift executable?

        • Re: Spawning interactive process
          eskimo Apple Staff Apple Staff (13,895 points)

          which uses forkpty, but I've been unable to get it working from a swift executable.

          The forkpty call is not safe to use from Swift.  It basically involves a fork without an exec, and it’s not safe to run Swift code in that environment (it’s the same for Objective-C).

          I believe the issue is that I need to pass input to amaster, which I'm unsure how to do:

          Not quite (-:  Before we start, a note on terminology.  While the pseudo terminal documentation is full of references to master and slave, I’m not going to use those in any text I write.  Instead I’m going to use the names of the terminal devices themselves, pty and tty respectively.

          Three things:

          • You want to pass tty to the child process, not pty.  You want to retain pty and use it to control tty.  See the pty man page for more background on this.

          • You need to pass tty to the child thrice, for standardInput, standardOutput and standardError.  I don’t think you need to do anything special here; FileHandle will do the right thing if you assign it to all three properties.

          • Once the child is running, make sure you close your copy of tty.  Otherwise things can get very confusing.


          Finally, this stuff is deep UNIX arcana and, as such, is best documented in various UNIX texts.  My go-to book for this sort of thing in Advanced Programming in the Unix Environment.  Get it, read it!

          Share and Enjoy

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