Skip to content

Instantly share code, notes, and snippets.

@dduan
Last active April 12, 2024 03:32
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save dduan/d4e967f3fc2801d3736b726cd34446bc to your computer and use it in GitHub Desktop.
Save dduan/d4e967f3fc2801d3736b726cd34446bc to your computer and use it in GitHub Desktop.
How to fork()+execv() in Swift
import Foundation
func withCStrings(_ strings: [String], scoped: ([UnsafeMutablePointer<CChar>?]) throws -> Void) rethrows {
let cStrings = strings.map { strdup($0) }
try scoped(cStrings + [nil])
cStrings.forEach { free($0) }
}
enum RunCommandError: Error {
case WaitPIDError
case POSIXSpawnError(Int32)
}
func runCommand(_ command: String, completion: ((Int32) -> Void)? = nil) throws {
var pid: pid_t = 0
let args = ["sh", "-c", command]
let envs = ProcessInfo().environment.map { k, v in "\(k)=\(v)" }
try withCStrings(args) { cArgs in
try withCStrings(envs) { cEnvs in
var status = posix_spawn(&pid, "/bin/sh", nil, nil, cArgs, cEnvs)
if status == 0 {
if (waitpid(pid, &status, 0) != -1) {
completion?(status)
} else {
throw RunCommandError.WaitPIDError
}
} else {
throw RunCommandError.POSIXSpawnError(status)
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment