So I am trying to execute a command using sudo from Swift using the following code (as suggested here:
func doTask(_ password:String) {
let taskOne = Process()
taskOne.launchPath = "/bin/echo"
taskOne.arguments = [password]
let taskTwo = Process()
taskTwo.launchPath = "/usr/bin/sudo"
taskTwo.arguments = ["-S", "/usr/bin/xattr", "-d", "-r", "com.test.exemple", " /Desktop/file.extension"]
//taskTwo.arguments = ["-S", "/usr/bin/touch", "/tmp/foo.bar.baz"]
let pipeBetween:Pipe = Pipe()
taskOne.standardOutput = pipeBetween
taskTwo.standardInput = pipeBetween
let pipeToMe = Pipe()
taskTwo.standardOutput = pipeToMe
taskTwo.standardError = pipeToMe
taskOne.launch()
taskTwo.launch()
let data = pipeToMe.fileHandleForReading.readDataToEndOfFile()
let output : String = NSString(data: data, encoding: String.Encoding.utf8.rawValue) as! String
print(output)
}
It works just fine for passwords such as "test", "password#123" etc. But when I try a password containing an umlaut such as "ä","ü" or "ö" in doesn't work. Any ideas why?
I'm not sure why the answer to the other question piped through echo
... seems to introduce unnecessary complications and unknowns.
The following more direct approach is tested and working:
import Foundation
let password = "äëïöü"
let passwordWithNewline = password + "\n"
let sudo = Process()
sudo.launchPath = "/usr/bin/sudo"
sudo.arguments = ["-S", "/bin/ls"]
let sudoIn = Pipe()
let sudoOut = Pipe()
sudo.standardOutput = sudoOut
sudo.standardError = sudoOut
sudo.standardInput = sudoIn
sudo.launch()
// Show the output as it is produced
sudoOut.fileHandleForReading.readabilityHandler = { fileHandle in
let data = fileHandle.availableData
if (data.count == 0) { return }
print("read \(data.count)")
print("\(String(bytes: data, encoding: .utf8) ?? "<UTF8 conversion failed>")")
}
// Write the password
sudoIn.fileHandleForWriting.write(passwordWithNewline.data(using: .utf8)!)
// Close the file handle after writing the password; avoids a
// hang for incorrect password.
try? sudoIn.fileHandleForWriting.close()
// Make sure we don't disappear while output is still being produced.
sudo.waitUntilExit()
print("Process did exit")
The crux is that you must add a newline after the password. (I suppose in some ways echo
is just an overly complicated way of doing that!)