Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions Sources/removemacai/SelfTest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,12 @@ func selfTest() -> Bool {
program: "/Library/PrivilegedHelperTools/dev.orbstack.OrbStack.privhelper", system: true)
check(script.owner == "sync.sh" && helper.owner == "OrbStack", "background items are named after what they run")

let ranAll = Shell.run("/bin/sh", ["-c", Shell.adminScript(["false", "echo second"])])
check(!ranAll.ok && ranAll.output.contains("second"), "one failed administrator step doesn't skip the rest")
let exited = Shell.run("/bin/sh", ["-c", Shell.adminScript(["exit 3", "echo after-exit"])])
check(!exited.ok && exited.output.contains("after-exit"), "a step that exits doesn't stop the rest")
check(Shell.run("/bin/sh", ["-c", Shell.adminScript(["true", "true"])]).ok, "administrator steps succeed together")

print(failed == 0 ? Term.green("all checks passed") : Term.red("\(failed) failed"))
return failed == 0
}
9 changes: 7 additions & 2 deletions Sources/removemacai/Shell.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,11 @@ enum Shell {
static func quote(_ s: String) -> String { "'" + s.replacingOccurrences(of: "'", with: "'\\''") + "'" }

/// Runs shell commands as root after one macOS password prompt. From a
/// terminal, sudo asks instead.
/// terminal, sudo asks instead. Every command runs even when an earlier one
/// fails; the result fails if any of them did.
static func admin(_ commands: [String], prompt: String) -> Result {
guard !commands.isEmpty else { return Result(status: 0, output: "") }
let script = commands.joined(separator: " && ")
let script = adminScript(commands)
if getuid() == 0 { return run("/bin/sh", ["-c", script]) }
if isatty(STDIN_FILENO) == 1 && !Shell.inApp {
return run("/usr/bin/sudo", ["/bin/sh", "-c", script])
Expand All @@ -41,6 +42,10 @@ enum Shell {
])
}

static func adminScript(_ commands: [String]) -> String {
(["rc=0"] + commands.map { "( \($0) ) || rc=1" } + ["exit $rc"]).joined(separator: "; ")
}

/// A readable reason for a failed administrator step. osascript prefixes
/// "0:390: execution error:" and appends the error number.
static func adminError(_ result: Result) -> String {
Expand Down