|
7 | 7 | // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
8 | 8 | //
|
9 | 9 |
|
10 |
| -#if !os(Android) // not available |
11 | 10 | import CoreFoundation
|
12 | 11 |
|
13 | 12 | extension Process {
|
@@ -287,6 +286,8 @@ open class Process: NSObject {
|
287 | 286 | default:
|
288 | 287 | fatalError("Process: The specified working directory cannot be set.")
|
289 | 288 | }
|
| 289 | + } else { |
| 290 | + fatalError(String(describing: nserror)) |
290 | 291 | }
|
291 | 292 | } catch {
|
292 | 293 | fatalError(String(describing: error))
|
@@ -608,7 +609,7 @@ open class Process: NSObject {
|
608 | 609 | }
|
609 | 610 |
|
610 | 611 | var taskSocketPair : [Int32] = [0, 0]
|
611 |
| -#if os(macOS) || os(iOS) |
| 612 | +#if os(macOS) || os(iOS) || os(Android) |
612 | 613 | socketpair(AF_UNIX, SOCK_STREAM, 0, &taskSocketPair)
|
613 | 614 | #else
|
614 | 615 | socketpair(AF_UNIX, Int32(SOCK_STREAM.rawValue), 0, &taskSocketPair)
|
@@ -978,4 +979,133 @@ private func posix(_ code: Int32) {
|
978 | 979 | default: fatalError("POSIX command failed with error: \(code)")
|
979 | 980 | }
|
980 | 981 | }
|
| 982 | + |
| 983 | +#if os(Android) |
| 984 | +// Android doesn't provide posix_spawn APIs until recent API level, so we cannot |
| 985 | +// depend on them, but we can imitate the API, and perform the same work. |
| 986 | + |
| 987 | +private struct posix_spawn_file_actions_t { |
| 988 | + enum Action { |
| 989 | + case dup2(old: Int32, new: Int32) |
| 990 | + case close(fd: Int32) |
| 991 | + } |
| 992 | + |
| 993 | + private(set) var actions: [Action] = [] |
| 994 | + |
| 995 | + mutating func add(_ action: Action) { |
| 996 | + actions.append(action) |
| 997 | + } |
| 998 | +} |
| 999 | + |
| 1000 | +private struct posix_spawnattr_t {} |
| 1001 | + |
| 1002 | +private func posix_spawn_file_actions_init(_ actions: inout posix_spawn_file_actions_t) -> Int32 { |
| 1003 | + // NOTE: Nothing to do here, the struct initializes itself. |
| 1004 | + return 0 |
| 1005 | +} |
| 1006 | + |
| 1007 | +@discardableResult |
| 1008 | +private func posix_spawn_file_actions_destroy(_ actions: inout posix_spawn_file_actions_t) -> Int32 { |
| 1009 | + // NOTE: Nothing to do here, the struct handles its own memory. |
| 1010 | + return 0 |
| 1011 | +} |
| 1012 | + |
| 1013 | +private func posix_spawn_file_actions_adddup2(_ actions: inout posix_spawn_file_actions_t, _ old: Int32, _ new: Int32) -> Int32 { |
| 1014 | + actions.add(.dup2(old: old, new: new)) |
| 1015 | + return 0 |
| 1016 | +} |
| 1017 | + |
| 1018 | +private func posix_spawn_file_actions_addclose(_ actions: inout posix_spawn_file_actions_t, _ fd: Int32) -> Int32 { |
| 1019 | + actions.add(.close(fd: fd)) |
| 1020 | + return 0 |
| 1021 | +} |
| 1022 | + |
| 1023 | +private func posix_spawn(_ pidPtr: UnsafeMutablePointer<pid_t>?, |
| 1024 | + _ launchPath: UnsafePointer<Int8>?, |
| 1025 | + _ actions: UnsafeMutablePointer<posix_spawn_file_actions_t>?, |
| 1026 | + _ attrp: UnsafeMutablePointer<posix_spawnattr_t>?, |
| 1027 | + _ argv: UnsafeMutablePointer<UnsafeMutablePointer<Int8>?>?, |
| 1028 | + _ envp: UnsafeMutablePointer<UnsafeMutablePointer<Int8>?>?) -> Int32 { |
| 1029 | + // TODO: We completely ignore attrp, because at the moment, the only |
| 1030 | + // invocation doesn't pass a value. |
| 1031 | + |
| 1032 | + // Block signals during this fork/execv dance. |
| 1033 | + var signalSet = sigset_t() |
| 1034 | + sigfillset(&signalSet) |
| 1035 | + var oldmask = sigset_t() |
| 1036 | + guard sigprocmask(SIG_BLOCK, &signalSet, &oldmask) == 0 else { |
| 1037 | + fatalError("sigprocmask() call failed: \(errno)") |
| 1038 | + } |
| 1039 | + |
| 1040 | + let pid = fork() |
| 1041 | + guard pid == 0 else { |
| 1042 | + // This is the parent. fork call might have been successful or not. |
| 1043 | + |
| 1044 | + // Unblock signals. |
| 1045 | + guard sigprocmask(SIG_SETMASK, &oldmask, nil) == 0 else { |
| 1046 | + fatalError("sigprocmask() call failed: \(errno)") |
| 1047 | + } |
| 1048 | + |
| 1049 | + if pid < 0 { |
| 1050 | + return pid |
| 1051 | + } else { |
| 1052 | + if let pidPtr = pidPtr { |
| 1053 | + pidPtr.pointee = pid |
| 1054 | + } |
| 1055 | + return 0 |
| 1056 | + } |
| 1057 | + } |
| 1058 | + |
| 1059 | + // This is the child. |
| 1060 | + |
| 1061 | + // Clean up the parent signal handlers |
| 1062 | + for idx in 1..<(NSIG as Int32) { |
| 1063 | + // Seems that SIGKILL/SIGSTOP are sometimes silently ignored, and |
| 1064 | + // sometimes return EINVAL. Since one cannot change the handlers anyway, |
| 1065 | + // skip them. |
| 1066 | + if idx == SIGKILL || idx == SIGSTOP { |
| 1067 | + continue |
| 1068 | + } |
| 1069 | + var sigAction = sigaction() |
| 1070 | + guard sigaction(idx, nil, &sigAction) == 0 else { |
| 1071 | + exit(127) |
| 1072 | + } |
| 1073 | + |
| 1074 | + // One cannot compare @convention(c) function pointers without the |
| 1075 | + // conversion. |
| 1076 | + if unsafeBitCast(sigAction.sa_handler, to: UnsafeRawPointer?.self) |
| 1077 | + != unsafeBitCast(SIG_IGN, to: UnsafeRawPointer?.self) { |
| 1078 | + sigAction.sa_handler = SIG_DFL; |
| 1079 | + guard sigaction(idx, &sigAction, nil) == 0 else { |
| 1080 | + exit(127) |
| 1081 | + } |
| 1082 | + } |
| 1083 | + } |
| 1084 | + |
| 1085 | + // Perform the actions |
| 1086 | + if let actions = actions?.pointee { |
| 1087 | + for action in actions.actions { |
| 1088 | + switch action { |
| 1089 | + case .dup2(let old, let new): |
| 1090 | + guard dup2(old, new) >= 0 else { |
| 1091 | + exit(127) |
| 1092 | + } |
| 1093 | + case .close(let fd): |
| 1094 | + guard close(fd) == 0 else { |
| 1095 | + exit(127) |
| 1096 | + } |
| 1097 | + } |
| 1098 | + } |
| 1099 | + } |
| 1100 | + |
| 1101 | + // Unblock the signals |
| 1102 | + guard sigprocmask(SIG_SETMASK, &oldmask, nil) == 0 else { |
| 1103 | + fatalError("sigprocmask() call failed: \(errno)") |
| 1104 | + } |
| 1105 | + |
| 1106 | + // If execv fails, we will simply exit 127 as the standard says. |
| 1107 | + execve(launchPath, argv, envp ?? environ) |
| 1108 | + exit(127) |
| 1109 | + // no need for return here |
| 1110 | +} |
981 | 1111 | #endif
|
0 commit comments