|
5 | 5 | // Copyright © 2016 mas-cli. All rights reserved.
|
6 | 6 | //
|
7 | 7 |
|
| 8 | +private import AppKit |
8 | 9 | internal import ArgumentParser
|
9 | 10 | private import CommerceKit
|
10 | 11 |
|
@@ -32,37 +33,56 @@ extension MAS {
|
32 | 33 | /// As `storeagent` no longer exists, terminates all processes known to be
|
33 | 34 | /// associated with the Mac App Store.
|
34 | 35 | func run(printer: Printer) {
|
35 |
| - let killall = Process() |
36 |
| - killall.launchPath = "/usr/bin/killall" |
37 |
| - killall.arguments = [ |
38 |
| - "ContextStoreAgent", |
39 |
| - "Dock", |
40 |
| - "SetStoreUpdateService", |
41 |
| - "appstoreagent", |
42 |
| - "appstorecomponentsd", |
43 |
| - "storeaccountd", |
44 |
| - "storeassetd", |
45 |
| - "storedownloadd", |
46 |
| - "storeinstalld", |
47 |
| - "storekitagent", |
48 |
| - "storelegacy", |
49 |
| - "storeuid", |
50 |
| - ] |
51 |
| - let stderr = Pipe() |
52 |
| - killall.standardError = stderr |
53 |
| - killall.standardOutput = Pipe() |
| 36 | + for bundleID in ["com.apple.dock", "com.apple.storeuid"] { |
| 37 | + for app in NSRunningApplication.runningApplications(withBundleIdentifier: bundleID) where !app.terminate() { |
| 38 | + printer.warning("Failed to terminate app with bundle ID:", bundleID) |
| 39 | + if !app.forceTerminate() { |
| 40 | + printer.error("Failed to force terminate app with bundle ID:", bundleID) |
| 41 | + } |
| 42 | + } |
| 43 | + } |
| 44 | + |
| 45 | + let executablePathSet = Set([ |
| 46 | + "/System/Library/Frameworks/StoreKit.framework/Support/storekitagent", |
| 47 | + "/System/Library/PrivateFrameworks/AppStoreComponents.framework/Support/appstorecomponentsd", |
| 48 | + "/System/Library/PrivateFrameworks/AppStoreDaemon.framework/Support/appstoreagent", |
| 49 | + """ |
| 50 | + /System/Library/PrivateFrameworks/CascadeSets.framework/Versions/A/XPCServices/SetStoreUpdateService.xpc/Contents/MacOS/SetStoreUpdateService |
| 51 | + """, |
| 52 | + "/System/Library/PrivateFrameworks/CommerceKit.framework/Versions/A/Resources/storeaccountd", |
| 53 | + "/System/Library/PrivateFrameworks/CommerceKit.framework/Versions/A/Resources/storeassetd", |
| 54 | + "/System/Library/PrivateFrameworks/CommerceKit.framework/Versions/A/Resources/storedownloadd", |
| 55 | + "/System/Library/PrivateFrameworks/CommerceKit.framework/Versions/A/Resources/storeinstalld", |
| 56 | + "/System/Library/PrivateFrameworks/CommerceKit.framework/Versions/A/Resources/storelegacy", |
| 57 | + ]) |
| 58 | + |
| 59 | + var processListMIB = [CTL_KERN, KERN_PROC, KERN_PROC_ALL] |
| 60 | + var length = 0 |
| 61 | + guard sysctl(&processListMIB, u_int(processListMIB.count), nil, &length, nil, 0) == 0 else { |
| 62 | + printer.error("Failed to get process list length") |
| 63 | + return |
| 64 | + } |
| 65 | + |
| 66 | + var kinfoProcs = [kinfo_proc](repeating: kinfo_proc(), count: length / MemoryLayout<kinfo_proc>.stride) |
| 67 | + guard sysctl(&processListMIB, u_int(processListMIB.count), &kinfoProcs, &length, nil, 0) == 0 else { |
| 68 | + printer.error("Failed to get process list") |
| 69 | + return |
| 70 | + } |
| 71 | + |
| 72 | + var executablePathBuffer = [CChar](repeating: 0, count: Int(PATH_MAX)) |
| 73 | + for pid in kinfoProcs.map(\.kp_proc.p_pid) { |
| 74 | + guard |
| 75 | + proc_pidpath(pid, &executablePathBuffer, UInt32(executablePathBuffer.count)) > 0, |
| 76 | + let executablePath = String(cString: executablePathBuffer, encoding: .utf8), |
| 77 | + executablePathSet.contains(executablePath) |
| 78 | + else { |
| 79 | + continue |
| 80 | + } |
54 | 81 |
|
55 |
| - killall.launch() |
56 |
| - killall.waitUntilExit() |
57 |
| - if killall.terminationStatus != 0 { |
58 |
| - let output = stderr.fileHandleForReading.readDataToEndOfFile() |
59 |
| - printer.error( |
60 |
| - "killall failed with exit status ", |
61 |
| - killall.terminationStatus, |
62 |
| - ":\n", |
63 |
| - String(data: output, encoding: .utf8) ?? "Error info not available", |
64 |
| - separator: "" |
65 |
| - ) |
| 82 | + let exitStatus = kill(pid, SIGTERM) |
| 83 | + if exitStatus != 0 { |
| 84 | + printer.error("Failed to terminate", executablePath, "getting exit status", exitStatus, "for pid", pid) |
| 85 | + } |
66 | 86 | }
|
67 | 87 |
|
68 | 88 | let folder = CKDownloadDirectory(nil)
|
|
0 commit comments