Merge branch 'master' of https://github.com/munki/munki into new_design

# Conflicts:
#	code/apps/Managed Software Center/Managed Software Center.xcodeproj/project.pbxproj
#	code/apps/Managed Software Center/Managed Software Center/Controllers/MainWindowController.swift
#	code/apps/Managed Software Center/Managed Software Center/Info.plist
#	code/apps/Managed Software Center/Managed Software Center/de.lproj/Localizable.strings
This commit is contained in:
Steve Küng
2020-06-09 18:43:41 +02:00
59 changed files with 1847 additions and 442 deletions
+1 -1
View File
@@ -9,7 +9,7 @@ Munki is an open source project from [Walt Disney Animation Studios](https://www
Munki is a set of tools that, used together with a webserver-based repository of packages and package metadata, can be used by macOS administrators to manage software installs (and in many cases removals) on macOS client machines.
Munki can install software packaged in the Apple package format, and also supports Adobe CS3/CS4/CS5/CS6 Enterprise Deployment "packages", and drag-and-drop disk images as installer sources.
Munki can install software packaged in the Apple package format, and also supports Adobe CS3/CS4/CS5/CS6/CC deployment packages, and drag-and-drop disk images as installer sources.
Additionally, Munki can be configured to install Apple Software Updates, either from Apple's server, or yours.
@@ -33,6 +33,7 @@
C0546BDC20FE961E003FE5A6 /* MSCPasswordAlertController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0546BDB20FE961E003FE5A6 /* MSCPasswordAlertController.swift */; };
C05F87932105587A000DB8D8 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = C05F87952105587A000DB8D8 /* Localizable.strings */; };
C0B2E4D921460E7D00FA9806 /* MSCWebView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0B2E4D821460E7D00FA9806 /* MSCWebView.swift */; };
C0BCAD7D2442A0B3001D2FDD /* appleupdates.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0BCAD7C2442A0B3001D2FDD /* appleupdates.swift */; };
C0C5DF6C20F5C27700CA0687 /* MSCStatusController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0C5DF6B20F5C27700CA0687 /* MSCStatusController.swift */; };
C0D30BEB20CA445A005E876E /* MunkiItems.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0D30BEA20CA445A005E876E /* MunkiItems.swift */; };
C0E2599E210AD8CE00C3A3D9 /* Socket.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0E2599D210AD8CD00C3A3D9 /* Socket.swift */; };
@@ -100,7 +101,7 @@
C0546BDB20FE961E003FE5A6 /* MSCPasswordAlertController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSCPasswordAlertController.swift; sourceTree = "<group>"; };
C05F878D210556C9000DB8D8 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/MainMenu.strings; sourceTree = "<group>"; };
C05F878E21055746000DB8D8 /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Base; path = Base.lproj/Info.plist; sourceTree = "<group>"; };
C05F879621055BFE000DB8D8 /* Base */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = Base; path = Base.lproj/Localizable.strings; sourceTree = "<group>"; };
C05F879621055BFE000DB8D8 /* Base */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = Base; path = Base.lproj/Localizable.strings; sourceTree = "<group>"; };
C05F879721055DAA000DB8D8 /* da */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = da; path = da.lproj/Localizable.strings; sourceTree = "<group>"; };
C05F87A221055E7F000DB8D8 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Localizable.strings; sourceTree = "<group>"; };
C05F87A321055E8F000DB8D8 /* fi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fi; path = fi.lproj/Localizable.strings; sourceTree = "<group>"; };
@@ -112,8 +113,10 @@
C05F87A921055F04000DB8D8 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = "<group>"; };
C05F87AA21055F10000DB8D8 /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/Localizable.strings; sourceTree = "<group>"; };
C0B2E4D821460E7D00FA9806 /* MSCWebView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MSCWebView.swift; sourceTree = "<group>"; };
C0BCAD7C2442A0B3001D2FDD /* appleupdates.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = appleupdates.swift; sourceTree = "<group>"; };
C0C5DF6B20F5C27700CA0687 /* MSCStatusController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MSCStatusController.swift; sourceTree = "<group>"; };
C0D30BEA20CA445A005E876E /* MunkiItems.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MunkiItems.swift; sourceTree = "<group>"; };
C0E10E58245494C4003E04F2 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
C0E2599D210AD8CD00C3A3D9 /* Socket.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Socket.swift; sourceTree = "<group>"; };
C0F8E3DF2105622F00718259 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
C0F8E3E221057A1500718259 /* da */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = da; path = da.lproj/MainMenu.strings; sourceTree = "<group>"; };
@@ -198,6 +201,7 @@
56C33E762173DC8E00D727DC /* MSCTableRowView.swift */,
C04F829C20BB5B9E00F9C57D /* MSCToolbarButton.swift */,
C04F829E20BB713B00F9C57D /* munki.swift */,
C0BCAD7C2442A0B3001D2FDD /* appleupdates.swift */,
C04F82A020BB77CF00F9C57D /* FoundationPlist.swift */,
C03107C220C8B65E007FE337 /* msclib.swift */,
C03107C420C8F220007FE337 /* msclog.swift */,
@@ -284,7 +288,7 @@
attributes = {
CLASSPREFIX = MSC;
LastSwiftUpdateCheck = 0920;
LastUpgradeCheck = 1020;
LastUpgradeCheck = 1140;
ORGANIZATIONNAME = "The Munki Project";
TargetAttributes = {
C0196316210507DB0009F51A = {
@@ -383,6 +387,7 @@
C0E2599E210AD8CE00C3A3D9 /* Socket.swift in Sources */,
C01603D120D0A7FA00DEF9E4 /* SelfService.swift in Sources */,
C04F82A120BB77CF00F9C57D /* FoundationPlist.swift in Sources */,
C0BCAD7D2442A0B3001D2FDD /* appleupdates.swift in Sources */,
C04CA61E20E6ADA100711461 /* MainWindowController.swift in Sources */,
C01603CF20CF8B6100DEF9E4 /* iconutils.swift in Sources */,
56C33E812174D7A200D727DC /* MSCTableCellView.swift in Sources */,
@@ -15,10 +15,14 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele
@IBOutlet weak var statusController: MSCStatusController!
@IBOutlet weak var passwordAlertController: MSCPasswordAlertController!
var launchedViaURL = false
var backdropOnlyMode = false
func applicationDidFinishLaunching(_ aNotification: Notification) {
// NSApplication delegate method called at launch
NSLog("%@", "Finished launching")
NSLog("Additional arguments: %@", CommandLine.arguments)
if let info_dict = Bundle.main.infoDictionary {
if let vers = info_dict["CFBundleShortVersionString"] as? String {
//print(vers)
@@ -35,6 +39,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele
// a NSUserNotificationCenterDelegate
NSLog("%@", "Launched via Notification interaction")
userNotificationCenter(NSUserNotificationCenter.default, didActivate: ourNotification)
launchedViaURL = true
}
}
// Prevent automatic relaunching at login on Lion+
@@ -49,22 +54,29 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele
// user may have launched the app manually, or it may have
// been launched by /usr/local/munki/managedsoftwareupdate
// to display available updates
var lastcheck = pref("LastCheckDate") as? Date ?? Date.distantPast
if thereAreUpdatesToBeForcedSoon(hours: 2) {
// skip the check and just display the updates
// by pretending the lastcheck is now
lastcheck = Date()
}
let max_cache_age = pref("CheckResultsCacheSeconds") as? Int ?? 0
if lastcheck.timeIntervalSinceNow * -1 > TimeInterval(max_cache_age) {
// check for updates if the last check is over the
// configured manualcheck cache age max.
mainWindowController.checkForUpdates()
} else if updateCheckNeeded() {
//check for updates if we have optional items selected for install
// or removal that have not yet been processed
mainWindowController.checkForUpdates()
// to display available updates, or via a munki: URL
if !launchedViaURL {
var lastcheck = pref("LastCheckDate") as? Date ?? Date.distantPast
if thereAreUpdatesToBeForcedSoon(hours: 2) {
// skip the check and just display the updates
// by pretending the lastcheck is now
lastcheck = Date()
}
if shouldAggressivelyNotifyAboutAppleUpdates() || shouldAggressivelyNotifyAboutMunkiUpdates() {
// skip the check and just display the updates
// by pretending the lastcheck is now
lastcheck = Date()
}
let max_cache_age = pref("CheckResultsCacheSeconds") as? Int ?? 0
if lastcheck.timeIntervalSinceNow * -1 > TimeInterval(max_cache_age) {
// check for updates if the last check is over the
// configured manualcheck cache age max.
mainWindowController.checkForUpdates()
} else if updateCheckNeeded() {
//check for updates if we have optional items selected for install
// or removal that have not yet been processed
mainWindowController.checkForUpdates()
}
}
// load the initial view only if we are not already loading something else.
// enables launching the app to a specific panel, eg. from URL handler
@@ -87,6 +99,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele
let urlDescriptor = event.paramDescriptor(forKeyword: keyword)
if let urlString = urlDescriptor?.stringValue {
msc_log("MSC", "Called by external URL: \(urlString)")
launchedViaURL = true
if let url = URL(string: urlString) {
mainWindowController.handleMunkiURL(url)
} else {
@@ -95,6 +108,19 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele
}
}
}
func applicationDidResignActive(_ notification: Notification) {
if self.mainWindowController.forceFrontmost == true {
NSApp.activate(ignoringOtherApps: true)
}
}
func applicationDidBecomeActive(_ notification: Notification) {
if self.backdropOnlyMode == true {
// (re)launch Software Update prefs pane
openSoftwareUpdatePrefsPane()
}
}
func applicationWillTerminate(_ aNotification: Notification) {
// Insert code here to tear down your application
@@ -13,6 +13,8 @@ class MSCAlertController: NSObject {
// than to move a giant bunch of ugly code out of the WindowController
var window: NSWindow? // our parent window
var timers: [Timer] = []
var quitButton: NSButton?
func handlePossibleAuthRestart() {
// Ask for and store a password for auth restart if needed/possible
@@ -115,6 +117,119 @@ class MSCAlertController: NSObject {
}
}
func alertToAppleUpdates() {
// Notify user of pending Apple updates
guard let mainWindow = window else {
msc_debug_log("Could not get main window in alertToAppleUpdates")
return
}
let alert = NSAlert()
alert.messageText = NSLocalizedString(
"Important Apple Updates", comment: "Apple Software Updates Pending title")
alert.addButton(withTitle: NSLocalizedString("Install now", comment: "Install now button title"))
alert.addButton(withTitle: NSLocalizedString(
"Skip these updates", comment: "Skip Apple updates button title"))
let su_icon_file = "/System/Library/PreferencePanes/SoftwareUpdate.prefPane/Contents/Resources/SoftwareUpdate.icns"
if let suIcon = NSImage.init(contentsOfFile: su_icon_file) {
alert.icon = suIcon
}
if !userIsAdmin() && userMustBeAdminToInstallAppleUpdates() {
// tell user they cannot install the updates
msc_log("user", "apple_updates_user_cannot_install")
alert.informativeText = NSLocalizedString(
"There are one or more pending Apple Software Updates that require a restart.\n\nYour administrator has restricted installation of these updates. Contact your administrator for assistance.",
comment: "Apple Software Updates Unable detail")
// disable insstall now button
alert.buttons[0].isEnabled = false
} else {
// prompt user to install using System Preferences
msc_log("user", "apple_updates_pending")
alert.informativeText = NSLocalizedString(
"There are one or more pending Apple Software Updates that require a restart.\n\nYou must install these updates using Software Update in System Preferences.",
comment: "Apple Software Updates Pending detail")
if shouldAggressivelyNotifyAboutAppleUpdates() {
// disable the skip button
alert.buttons[1].isEnabled = false
}
}
alert.beginSheetModal(for: mainWindow, completionHandler: { (modalResponse) -> Void in
self.appleUpdateAlertEnded(for: alert, withResponse: modalResponse)
})
}
func appleUpdateAlertEnded(for alert: NSAlert, withResponse modalResponse: NSApplication.ModalResponse) {
// Called when Apple update alert ends
if modalResponse == .alertFirstButtonReturn {
msc_log("user", "agreed_apple_updates")
// make sure this alert panel is gone before we proceed
alert.window.orderOut(self)
let appDelegate = NSApp.delegate! as! AppDelegate
appDelegate.mainWindowController.forceFrontmost = false
appDelegate.backdropOnlyMode = true
if let mainWindow = window {
mainWindow.level = .normal
}
let timer1 = Timer.scheduledTimer(timeInterval: 0.1,
target: self,
selector: #selector(self.openSoftwareUpdate),
userInfo: nil,
repeats: false)
timers.append(timer1)
let timer2 = Timer.scheduledTimer(timeInterval: 1.5,
target: self,
selector: #selector(self.closeMainWindow),
userInfo: nil,
repeats: false)
timers.append(timer2)
let timer3 = Timer.scheduledTimer(timeInterval: 9.5,
target: self,
selector: #selector(self.fadeOutBackdropWindows),
userInfo: nil,
repeats: false)
timers.append(timer3)
// wait 10 seconds, then quit
let timer4 = Timer.scheduledTimer(timeInterval: 10.0,
target: NSApp,
selector: #selector(NSApp.terminate),
userInfo: self,
repeats: false)
timers.append(timer4)
} else {
// cancelled
msc_log("user", "deferred_apple_updates")
alert.window.orderOut(self)
clearMunkiItemsCache()
if let mainWindowController = (NSApp.delegate! as! AppDelegate).mainWindowController {
mainWindowController.load_page("updates.html")
mainWindowController.displayUpdateCount()
if shouldAggressivelyNotifyAboutMunkiUpdates() {
mainWindowController._alertedUserToOutstandingUpdates = false
}
}
}
}
@objc func openSoftwareUpdate() {
// object method to call openSoftwareUpdatePrefsPane function
openSoftwareUpdatePrefsPane()
}
@objc func closeMainWindow() {
// closes the main window, duh
if let mainWindow = window {
mainWindow.orderOut(self)
}
}
@objc func fadeOutBackdropWindows() {
// fades out the windows that block access to other apps
let backdropWindows = (NSApp.delegate! as! AppDelegate).mainWindowController.backdropWindows
for window in backdropWindows {
window.animator().alphaValue = 0.0
}
}
func alertToExtraUpdates() {
// Notify user of additional pending updates
msc_log("user", "extra_updates_pending")
@@ -416,4 +531,90 @@ class MSCAlertController: NSObject {
}
return false
}
func alertToPendingUpdates(_ mwc: MainWindowController) {
// Alert user to pending updates before quitting the application
mwc._alertedUserToOutstandingUpdates = true
// show the updates
mwc.loadUpdatesPage(self)
var alertTitle = ""
var alertDetail = ""
if thereAreUpdatesToBeForcedSoon() {
alertTitle = NSLocalizedString("Mandatory Updates Pending",
comment: "Mandatory Updates Pending text")
if let deadline = earliestForceInstallDate() {
let time_til_logout = deadline.timeIntervalSinceNow
if time_til_logout > 0 {
let deadline_str = stringFromDate(deadline)
let formatString = NSLocalizedString(
("One or more updates must be installed by %@. A logout " +
"may be forced if you wait too long to update."),
comment: "Mandatory Updates Pending detail")
alertDetail = String(format: formatString, deadline_str)
} else {
alertDetail = NSLocalizedString(
("One or more mandatory updates are overdue for " +
"installation. A logout will be forced soon."),
comment: "Mandatory Updates Imminent detail")
}
}
} else {
alertTitle = NSLocalizedString(
"Pending updates", comment: "Pending Updates alert title")
alertDetail = NSLocalizedString(
"There are pending updates for this computer.",
comment: "Pending Updates alert detail text")
}
let alert = NSAlert()
alert.messageText = alertTitle
alert.informativeText = alertDetail
var quitButton = NSApplication.ModalResponse.alertFirstButtonReturn
var updateButton = NSApplication.ModalResponse.alertSecondButtonReturn
if !shouldAggressivelyNotifyAboutMunkiUpdates() && !thereAreUpdatesToBeForcedSoon() {
alert.addButton(withTitle: NSLocalizedString("Quit", comment: "Quit button title"))
alert.addButton(withTitle: NSLocalizedString("Update now", comment: "Update Now button title"))
} else {
// add the buttons in the opposite order so "Update now" is the default/primary
alert.addButton(withTitle: NSLocalizedString("Update now", comment: "Update Now button title"))
alert.addButton(withTitle: NSLocalizedString("Quit", comment: "Quit button title"))
// initially disable the Quit button
self.quitButton = alert.buttons[1]
alert.buttons[1].isEnabled = false
let timer1 = Timer.scheduledTimer(timeInterval: 5.0,
target: self,
selector: #selector(self.activateQuitButton),
userInfo: nil,
repeats: false)
timers.append(timer1)
updateButton = NSApplication.ModalResponse.alertFirstButtonReturn
quitButton = NSApplication.ModalResponse.alertSecondButtonReturn
}
alert.beginSheetModal(for: self.window!, completionHandler: { (modalResponse) -> Void in
if modalResponse == quitButton {
msc_log("user", "quit")
NSApp.terminate(self)
} else if modalResponse == updateButton {
msc_log("user", "install_now_clicked")
// make sure this alert panel is gone before we proceed
// which might involve opening another alert sheet
alert.window.orderOut(self)
// invalidate any timers
for timer in self.timers {
timer.invalidate()
}
// initiate the updates
mwc.updateNow()
mwc.loadUpdatesPage(self)
}
})
}
@objc func activateQuitButton() {
if let button = self.quitButton {
button.isEnabled = true
} else {
NSLog("%@", "could not get the alert button reference")
}
}
}
@@ -174,6 +174,7 @@ class MSCStatusController: NSObject {
// Initialize the main window for update status
statusWindowController._update_in_progress = true
if statusWindowController.currentPageIsUpdatesPage() {
statusWindowController.makeUsUnobnoxious()
statusWindowController.load_page("updates.html")
statusWindowController.displayUpdateCount()
}
@@ -29,6 +29,10 @@ class MainWindowController: NSWindowController, NSWindowDelegate, WKNavigationDe
var _status_title = ""
var stop_requested = false
var user_warned_about_extra_updates = false
var should_filter_apple_updates = false
var forceFrontmost = false
var backdropWindows: [NSWindow] = []
// Cocoa UI binding properties
@@ -74,18 +78,34 @@ class MainWindowController: NSWindowController, NSWindowDelegate, WKNavigationDe
// no pending updates
return .terminateNow
}
if (currentPageIsUpdatesPage() && !thereAreUpdatesToBeForcedSoon()) {
// We're already at the updates view, so user is aware of the
// pending updates, so OK to just terminate
// (unless there are some updates to be forced soon)
return .terminateNow
if !should_filter_apple_updates && appleUpdatesRequireRestartOnMojaveAndUp() {
if shouldAggressivelyNotifyAboutAppleUpdates(days: 2) {
if !currentPageIsUpdatesPage() {
loadUpdatesPage(self)
}
alert_controller.alertToAppleUpdates()
should_filter_apple_updates = true
return .terminateCancel
}
}
if (currentPageIsUpdatesPage() && _alertedUserToOutstandingUpdates) {
return .terminateNow
if currentPageIsUpdatesPage() {
if (!thereAreUpdatesToBeForcedSoon() && !shouldAggressivelyNotifyAboutMunkiUpdates()) {
// We're already at the updates view, so user is aware of the
// pending updates, so OK to just terminate
// (unless there are some updates to be forced soon)
return .terminateNow
}
if _alertedUserToOutstandingUpdates {
if (thereAreUpdatesToBeForcedSoon() || shouldAggressivelyNotifyAboutMunkiUpdates()) {
// user keeps avoiding; let's try at next logout or restart
writeInstallAtStartupFlagFile(skipAppleUpdates: false)
}
return .terminateNow
}
}
// we have pending updates and we have not yet warned the user
// about them
alertToPendingUpdates()
alert_controller.alertToPendingUpdates(self)
return .terminateCancel
}
@@ -93,59 +113,105 @@ class MainWindowController: NSWindowController, NSWindowDelegate, WKNavigationDe
// return true if current tab selected is Updates
return sidebar.selectedRow == 3
}
func newTranslucentWindow(screen: NSScreen) -> NSWindow {
// makes a translucent masking window we use to prevent interaction with
// other apps
var windowRect = screen.frame
windowRect.origin = NSMakePoint(0.0, 0.0)
let thisWindow = NSWindow(
contentRect: windowRect,
styleMask: .borderless,
backing: .buffered,
defer: false,
screen: screen
)
thisWindow.level = .normal
thisWindow.backgroundColor = NSColor.black.withAlphaComponent(0.50)
thisWindow.isOpaque = false
thisWindow.ignoresMouseEvents = false
thisWindow.alphaValue = 0.0
thisWindow.orderFrontRegardless()
thisWindow.animator().alphaValue = 1.0
return thisWindow
}
func alertToPendingUpdates() {
// Alert user to pending updates before quitting the application
_alertedUserToOutstandingUpdates = true
// show the updates
loadUpdatesPage(self)
var alertTitle = ""
var alertDetail = ""
if thereAreUpdatesToBeForcedSoon() {
alertTitle = NSLocalizedString("Mandatory Updates Pending",
comment: "Mandatory Updates Pending text")
if let deadline = earliestForceInstallDate() {
let time_til_logout = deadline.timeIntervalSinceNow
if time_til_logout > 0 {
let deadline_str = stringFromDate(deadline)
let formatString = NSLocalizedString(
("One or more updates must be installed by %@. A logout " +
"may be forced if you wait too long to update."),
comment: "Mandatory Updates Pending detail")
alertDetail = String(format: formatString, deadline_str)
} else {
alertDetail = NSLocalizedString(
("One or more mandatory updates are overdue for " +
"installation. A logout will be forced soon."),
comment: "Mandatory Updates Imminent detail")
}
}
} else {
alertTitle = NSLocalizedString(
"Pending updates", comment: "Pending Updates alert title")
alertDetail = NSLocalizedString(
"There are pending updates for this computer.",
comment: "Pending Updates alert detail text")
func displayBackdropWindows() {
for screen in NSScreen.screens {
let newWindow = newTranslucentWindow(screen: screen)
// add to our backdropWindows array so a reference stays around
backdropWindows.append(newWindow)
}
let alert = NSAlert()
alert.messageText = alertTitle
alert.informativeText = alertDetail
alert.addButton(withTitle: NSLocalizedString("Quit", comment: "Quit button title"))
alert.addButton(withTitle: NSLocalizedString("Update now", comment: "Update Now button title"))
alert.beginSheetModal(for: self.window!, completionHandler: { (modalResponse) -> Void in
if modalResponse == .alertFirstButtonReturn {
msc_log("user", "quit")
NSApp.terminate(self)
} else if modalResponse == .alertSecondButtonReturn {
msc_log("user", "install_now_clicked")
// make sure this alert panel is gone before we proceed
// which might involve opening another alert sheet
alert.window.orderOut(self)
// initiate the updates
self.updateNow()
self.loadUpdatesPage(self)
}
func makeUsUnobnoxious() {
// reverse all the obnoxious changes
msc_log("msc", "end_obnoxious_mode")
let options = NSApplication.PresentationOptions([])
NSApp.presentationOptions = options
for window in self.backdropWindows {
window.orderOut(self)
}
if let window = self.window {
window.collectionBehavior = .fullScreenPrimary
window.styleMask = [.titled, .closable, .miniaturizable, .resizable]
window.level = .normal
}
self.forceFrontmost = false
// enable/disable controls as needed
enableOrDisableSoftwareViewControls()
}
func makeUsObnoxious() {
// makes this app and window impossible(?)/difficult to ignore
msc_log("msc", "start_obnoxious_mode")
// make it very difficult to switch away from this app
let options = NSApplication.PresentationOptions([.hideDock, .disableHideApplication, .disableProcessSwitching, .disableForceQuit])
NSApp.presentationOptions = options
// alter some window properties to make the window harder to ignore
if let window = self.window {
window.center()
window.collectionBehavior = .fullScreenNone
window.styleMask = [.titled, .closable]
window.level = .floating
}
// disable all of the other controls
softwareToolbarItem.isEnabled = false
categoriesToolbarItem.isEnabled = false
myItemsToolbarItem.isEnabled = false
searchField.isEnabled = false
findMenuItem.isEnabled = false
softwareMenuItem.isEnabled = false
categoriesMenuItem.isEnabled = false
myItemsMenuItem.isEnabled = false
// set flag to cause us to always be brought to front
self.forceFrontmost = true
// create translucent windows to mask all other apps
displayBackdropWindows()
}
func weShouldBeObnoxious() -> Bool {
// returns a Bool to let us know if we should enter obnoxiousMode
if thereAreUpdatesToBeForcedSoon() {
return true
}
if shouldAggressivelyNotifyAboutMunkiUpdates() {
return true
}
if shouldAggressivelyNotifyAboutAppleUpdates() {
if userIsAdmin() || !userMustBeAdminToInstallAppleUpdates() {
// only be obnoxious if the user can actually _do_ something
return true
}
})
}
return false
}
func loadInitialView() {
@@ -203,6 +269,11 @@ class MainWindowController: NSWindowController, NSWindowDelegate, WKNavigationDe
// The managedsoftwareupdate run will have changed state preferences
// in ManagedInstalls.plist. Load the new values.
reloadPrefs()
if tasktype == "" {
// probably a background session, but not one initiated by the user here
resetAndReload()
return
}
let lastCheckResult = pref("LastCheckResult") as? Int ?? 0
if sessionResult != 0 || lastCheckResult < 0 {
var alertMessageText = NSLocalizedString(
@@ -251,7 +322,13 @@ class MainWindowController: NSWindowController, NSWindowDelegate, WKNavigationDe
detailText = "\(detailText)\n\n\(errorMessage)"
}
// show the alert sheet
self.window!.makeKeyAndOrderFront(self)
if let thisWindow = self.window {
thisWindow.makeKeyAndOrderFront(self)
if let attachedSheet = thisWindow.attachedSheet {
// there's an existing sheet open; close it first
thisWindow.endSheet(attachedSheet)
}
}
let alert = NSAlert()
alert.messageText = alertMessageText
alert.informativeText = detailText
@@ -312,7 +389,9 @@ class MainWindowController: NSWindowController, NSWindowDelegate, WKNavigationDe
case "updates":
// updates page; just rebuild and reload it
load_page("updates.html")
_alertedUserToOutstandingUpdates = true
if !shouldAggressivelyNotifyAboutMunkiUpdates() {
_alertedUserToOutstandingUpdates = true
}
default:
// should never get here
msc_debug_log("Unexpected value for page name: \(filename)")
@@ -490,6 +569,7 @@ class MainWindowController: NSWindowController, NSWindowDelegate, WKNavigationDe
return
}
_update_in_progress = true
should_filter_apple_updates = false
displayUpdateCount()
managedsoftwareupdate_task = "manualcheck"
if let status_controller = (NSApp.delegate as? AppDelegate)?.statusController {
@@ -653,7 +733,11 @@ class MainWindowController: NSWindowController, NSWindowDelegate, WKNavigationDe
} else {
msc_debug_log("updateCheck not needed")
_alertedUserToOutstandingUpdates = false
_status_title = NSLocalizedString(
"Update in progress.",
comment: "Update In Progress primary text") + ".."
kickOffInstallSession()
makeUsUnobnoxious()
}
}
@@ -662,7 +746,7 @@ class MainWindowController: NSWindowController, NSWindowDelegate, WKNavigationDe
if _update_in_progress {
return 0
}
return getEffectiveUpdateList().count
return getEffectiveUpdateList(should_filter_apple_updates).count
}
func displayUpdateCount() {
@@ -748,6 +832,10 @@ class MainWindowController: NSWindowController, NSWindowDelegate, WKNavigationDe
if url_fragment == "updates.html" {
// clear all earlier update notifications
NSUserNotificationCenter.default.removeAllDeliveredNotifications()
// record that the user has been presented pending updates
if !_update_in_progress && !shouldAggressivelyNotifyAboutMunkiUpdates() && !thereAreUpdatesToBeForcedSoon() {
_alertedUserToOutstandingUpdates = true
}
}
}
@@ -766,8 +854,31 @@ class MainWindowController: NSWindowController, NSWindowDelegate, WKNavigationDe
if !(filename.hasSuffix(".html")) {
filename += ".html"
}
// if the user has minimized the main window, deminiaturize it
if let window = self.window {
if window.isMiniaturized {
window.deminiaturize(self)
}
}
// try to build and load the page
load_page(filename)
if filename == "notify.html" {
//resetAndReload()
load_page("updates.html")
if !_update_in_progress && getUpdateCount() > 0 {
// we're notifying about pending updates. We might need to be obnoxious about it
if let window = self.window {
// don't let people move the window mostly off-screen so
// they can ignore it
window.center()
}
if weShouldBeObnoxious() {
NSLog("%@", "Entering obnoxious mode")
makeUsObnoxious()
}
}
} else {
load_page(filename)
}
}
func setNoPageCache() {
@@ -784,10 +895,17 @@ class MainWindowController: NSWindowController, NSWindowDelegate, WKNavigationDe
}
func clearCache() {
if #available(OSX 10.11, *) {
let cacheDataTypes = Set([WKWebsiteDataTypeDiskCache, WKWebsiteDataTypeMemoryCache])
var osMinorVers = 9
if #available(OSX 10.10, *) {
osMinorVers = ProcessInfo().operatingSystemVersion.minorVersion
}
if osMinorVers >= 11 {
if #available(OSX 10.11, *) {
let cacheDataTypes = Set([WKWebsiteDataTypeDiskCache, WKWebsiteDataTypeMemoryCache])
let dateFrom = Date.init(timeIntervalSince1970: 0)
WKWebsiteDataStore.default().removeData(ofTypes: cacheDataTypes, modifiedSince: dateFrom, completionHandler: {})
}
} else {
// Fallback on earlier versions
URLCache.shared.removeAllCachedResponses()
@@ -966,7 +1084,14 @@ class MainWindowController: NSWindowController, NSWindowDelegate, WKNavigationDe
// we're on the Updates page, so users can see all the pending/
// outstanding updates
_alertedUserToOutstandingUpdates = true
updateNow()
if !should_filter_apple_updates && appleUpdatesRequireRestartOnMojaveAndUp() {
// if there are pending Apple updates, alert the user to
// install via System Preferences
alert_controller.alertToAppleUpdates()
should_filter_apple_updates = true
} else {
updateNow()
}
}
}
@@ -1088,9 +1213,9 @@ class MainWindowController: NSWindowController, NSWindowDelegate, WKNavigationDe
"Please contact your administrator for more details",
comment: "Pre Install Uninstall Upgrade Alert Detail")
let defaultOKLabel = NSLocalizedString(
"OK", comment: "Pre Install Uninstall Upgrade OK Label")
"OK", comment: "OK button title")
let defaultCancelLabel = NSLocalizedString(
"Cancel", comment: "Pre Install Uninstall Upgrade Cancel Label")
"Cancel", comment: "Cancel button title/short action text")
let alertTitle = alert["alert_title"] as? String ?? defaultAlertTitle
let alertDetail = alert["alert_detail"] as? String ?? defaultAlertDetail
@@ -1227,7 +1352,7 @@ class MainWindowController: NSWindowController, NSWindowDelegate, WKNavigationDe
// update the updates-to-install header to reflect the new list of
// updates to install
setInnerText(updateCountMessage(getUpdateCount()), elementID: "update-count-string")
setInnerText(getWarningText(), elementID: "update-warning-text")
setInnerText(getWarningText(should_filter_apple_updates), elementID: "update-warning-text")
// update text of Install All button
setInnerText(getInstallAllButtonTextForCount(getUpdateCount()), elementID: "install-all-button-text")
@@ -1340,7 +1465,6 @@ class MainWindowController: NSWindowController, NSWindowDelegate, WKNavigationDe
@IBAction func loadUpdatesPage(_ sender: Any) {
// Called by Navigate menu item'''
load_page("updates.html")
_alertedUserToOutstandingUpdates = true
}
@IBAction func softwareToolbarItemClicked(_ sender: Any) {
@@ -19,7 +19,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$(MARKETING_VERSION)</string>
<string>5.2.0</string>
<key>CFBundleURLTypes</key>
<array>
<dict>
@@ -243,6 +243,12 @@ class GenericItem: BaseItem {
}
}
}
// if it's an Apple Software Update, use the Software Update icon
if let apple_update = my["apple_update"] as? Bool {
if apple_update {
return "static/SoftwareUpdate.png"
}
}
// use the Generic package icon
return "static/Generic.png"
}
@@ -326,7 +332,7 @@ class GenericItem: BaseItem {
comment: "Update Will Be Installed status text"),
"update-available":
NSLocalizedString("Update available",
comment: "Update Available status text"),
comment: "Update available text"),
"unavailable":
NSLocalizedString("Unavailable",
comment: "Unavailable status text")
@@ -564,7 +570,7 @@ class GenericItem: BaseItem {
let note = my["note"] as? String ?? ""
if is_update {
return NSLocalizedString("Update available",
comment: "Update available display text")
comment: "Update available text")
} else if note.hasPrefix("Insufficient disk space to download and install") {
return NSLocalizedString("Not enough disk space",
comment: "Not Enough Disk Space display text")
@@ -921,7 +927,8 @@ class UpdateItem: GenericItem {
comment: "Managed Update type")
}
my["hide_cancel_button"] = "hidden"
my ["dependent_items"] = dependentItems(name)
my["dependent_items"] = dependentItems(name)
my["days_available"] = getDaysPending(name)
}
override func description() -> String {
@@ -966,6 +973,15 @@ class UpdateItem: GenericItem {
}
start_text += "<span class=\"warning\">\(filtered_html(warning_text))</span><br/><br/>"
}
} else if let days_available = my["days_available"] as? Int {
if days_available > 2 {
let format_str = NSLocalizedString(
"This update has been pending for %@ days.",
comment: "Pending days message")
let formatted_str = NSString(format: format_str as NSString,
String(days_available) as NSString)
start_text += "<span class=\"warning\">\(formatted_str)</span><br><br>"
}
}
if !((my["dependent_items"] as? [String] ?? []).isEmpty) {
start_text += dependency_description()
@@ -982,6 +998,94 @@ func cachedInstallInfo() -> [String : Any] {
return Cache.shared["InstallInfo"] as? [String : Any] ?? [String : Any]()
}
func updateTrackingInfo() -> [String : Any] {
if !Cache.shared.keys.contains("UpdateNotificationTrackingInfo") {
Cache.shared["UpdateNotificationTrackingInfo"] = getUpdateNotificationTracking()
}
return Cache.shared["UpdateNotificationTrackingInfo"] as? [String : Any] ?? [String : Any]()
}
func getDateFirstAvailable(_ itemname: String) -> Date? {
// Uses UpdateNotificationTracking.plist data to determine when an item was first
// "discovered"/presented as available
let trackingInfo = updateTrackingInfo()
for category in trackingInfo.keys {
if let items = (trackingInfo[category] as? [String : Any]) {
for name in items.keys {
if name == itemname {
return (items[name] as? Date)
}
}
}
}
return nil
}
func getDaysPending(_ itemname: String) -> Int {
// Returns the number of days an item has been pending
if let dateAvailable = getDateFirstAvailable(itemname) {
let secondsInDay = 60 * 60 * 24
let timeAvailable = dateAvailable.timeIntervalSinceNow * -1
let daysAvailable = Int(timeAvailable as Double)/secondsInDay
return daysAvailable
}
return 0
}
func shouldAggressivelyNotifyAboutMunkiUpdates(days: Int = -1) -> Bool {
// Do we have any Munki updates that have been pending a long time?
var maxPendingDays = 0
if let trackingInfo = updateTrackingInfo()["managed_installs"] as? [String: Any?] {
for name in trackingInfo.keys {
if let dateAvailable = trackingInfo[name] as? Date {
let secondsInDay = 60 * 60 * 24
let timeAvailable = dateAvailable.timeIntervalSinceNow * -1
let daysAvailable = Int(timeAvailable as Double)/secondsInDay
if daysAvailable > maxPendingDays {
maxPendingDays = daysAvailable
}
}
}
}
if days == -1 {
let aggressiveNotificationDays = pref("AggressiveUpdateNotificationDays") as? Int ?? 14
if aggressiveNotificationDays == 0 {
// never get aggressive
return false
}
return maxPendingDays > aggressiveNotificationDays
} else {
return maxPendingDays > days
}
}
func shouldAggressivelyNotifyAboutAppleUpdates(days: Int = -1) -> Bool {
// Do we have any Apple updates that require a restart that have been pending
// a long time?
var maxPendingDays = 0
let requiresRestartItems = getAppleUpdates().filter(
{ ($0["RestartAction"] as? String ?? "").hasSuffix("Restart") }
)
for item in requiresRestartItems {
if let itemname = item["name"] as? String {
let thisItemDaysPending = getDaysPending(itemname)
if thisItemDaysPending > maxPendingDays {
maxPendingDays = thisItemDaysPending
}
}
}
if days == -1 {
let aggressiveNotificationDays = pref("AggressiveUpdateNotificationDays") as? Int ?? 14
if aggressiveNotificationDays == 0 {
// never get aggressive
return false
}
return maxPendingDays > aggressiveNotificationDays
} else {
return maxPendingDays > days
}
}
func optionalInstallsExist() -> Bool {
let optional_items = cachedInstallInfo()["optional_installs"] as? [[String : Any]] ?? [[String : Any]]()
return optional_items.count > 0
@@ -994,7 +1098,7 @@ func getOptionalInstallItems() -> [OptionalItem] {
}
if !Cache.shared.keys.contains("optional_install_items") {
let optional_items = cachedInstallInfo()["optional_installs"] as? [[String : Any]] ?? [[String : Any]]()
var optional_install_items = optional_items.map({ OptionalItem($0) })
let optional_install_items = optional_items.map({ OptionalItem($0) })
let featured_items = cachedInstallInfo()["featured_items"] as? [String] ?? [String]()
for index in 0..<optional_install_items.count {
if let name = optional_install_items[index]["name"] as? String {
@@ -1067,9 +1171,9 @@ func display_name(_ item_name: String) -> String {
return item_name
}
func getUpdateList() -> [UpdateItem] {
func getUpdateList(_ filterAppleUpdates: Bool = false) -> [UpdateItem] {
if !Cache.shared.keys.contains("update_list") {
Cache.shared["update_list"] = _build_update_list()
Cache.shared["update_list"] = _build_update_list(filterAppleUpdates)
}
return Cache.shared["update_list"] as? [UpdateItem] ?? [UpdateItem]()
}
@@ -1096,15 +1200,20 @@ func update_list_sort(_ lh: UpdateItem, _ rh: UpdateItem) -> Bool {
}
}
func _build_update_list() -> [UpdateItem] {
func _build_update_list(_ filterAppleUpdates: Bool = false) -> [UpdateItem] {
var update_items = [[String: Any]]()
if !munkiUpdatesContainAppleItems() {
if let apple_update_items = getAppleUpdates()["AppleUpdates"] as? [[String: Any]] {
for var item in apple_update_items {
item["developer"] = "Apple"
item["status"] = "will-be-installed"
update_items.append(item)
for var item in getAppleUpdates() {
if (filterAppleUpdates &&
((item["RestartAction"] as? String ?? "").hasSuffix("Restart"))) {
// skip this update because it requires a restart and we've been
// directed to filter these out
continue
}
item["developer"] = "Apple"
item["status"] = "will-be-installed"
item["apple_update"] = true
update_items.append(item)
}
}
let install_info = cachedInstallInfo()
@@ -1144,6 +1253,21 @@ func updatesRequireRestart() -> Bool {
return requiresRestart
}
func appleUpdatesRequireRestartOnMojaveAndUp() -> Bool {
// Return true if any item in the apple update list requires a restart
var osMinorVers = 9
if #available(OSX 10.10, *) {
osMinorVers = ProcessInfo().operatingSystemVersion.minorVersion
}
if osMinorVers >= 14 {
let requiresRestart = getAppleUpdates().filter(
{ ($0["RestartAction"] as? String ?? "").hasSuffix("Restart") }
).count > 0
return requiresRestart
}
return false
}
func updatesContainNonUserSelectedItems() -> Bool {
// Does the list of updates contain items not selected by the user?
if !munkiUpdatesContainAppleItems() && getAppleUpdates().count > 0 {
@@ -1168,7 +1292,7 @@ func updatesContainNonUserSelectedItems() -> Bool {
return false
}
func getEffectiveUpdateList() -> [GenericItem] {
func getEffectiveUpdateList(_ filterAppleUpdates: Bool = false) -> [GenericItem] {
// Combine the updates Munki has found with any optional choices to
// make the effective list of updates
let optional_installs = getOptionalWillBeInstalledItems() as [GenericItem]
@@ -1178,7 +1302,7 @@ func getEffectiveUpdateList() -> [GenericItem] {
)
// filter out pending optional items from the list of all pending updates
// so we can add in the items with additional optional detail
let mandatory_updates = getUpdateList().filter(
let mandatory_updates = getUpdateList(filterAppleUpdates).filter(
{ !optional_item_names.contains($0["name"] as? String ?? "") }
) as [GenericItem]
return mandatory_updates + optional_installs + optional_removals
Binary file not shown.

After

Width:  |  Height:  |  Size: 314 KiB

@@ -45,13 +45,8 @@ class UNIXDomainSocketClient {
} else {
return nil
}
// make a CFData reference to the sockaddr struct
let sockaddr_un_ptr = UnsafeMutableRawPointer(
&socketAdr).bindMemory(to: UInt8.self,
capacity: MemoryLayout<sockaddr_un>.size)
return CFDataCreate(kCFAllocatorDefault,
sockaddr_un_ptr,
MemoryLayout<sockaddr_un>.size)
return NSData(bytes: &socketAdr,
length: MemoryLayout.size(ofValue: socketAdr)) as CFData
}
func connect(to path: String) {
@@ -108,7 +103,7 @@ class UNIXDomainSocketClient {
}
private func fdSet(_ fd: Int32, set: inout fd_set) {
/// Replacement for FD_SET macro
// Replacement for FD_SET macro
let intOffset = Int(fd / 32)
let bitOffset = fd % 32
let mask = Int32(1 << bitOffset)
@@ -182,18 +177,16 @@ class UNIXDomainSocketClient {
return ""
}
// allocate some space for the return message.
let buffer = Array<CChar>(repeating: CChar(0), count: maxsize)
let buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: maxsize)
defer { buffer.deallocate() }
// read from socket
let msg_len = recv(CFSocketGetNative(socket),
UnsafeMutableRawPointer(mutating: buffer),
maxsize,
0)
if msg_len > 0 {
if let text = String(utf8String: buffer) {
return text
}
let msg_len = recv(CFSocketGetNative(socket), buffer, maxsize, 0)
if let msg = NSString(bytes: buffer,
length: msg_len,
encoding: String.Encoding.utf8.rawValue) as String? {
return msg
}
errCode = .writeError
errCode = .readError
return ""
}
}
@@ -0,0 +1,121 @@
//
// appleupdates.swift
// Managed Software Center
//
// Created by Greg Neagle on 4/11/20.
// Copyright © 2020 The Munki Project. All rights reserved.
//
import AppKit
import Foundation
import OpenDirectory
let INSTALLATSTARTUPFILE = "/Users/Shared/.com.googlecode.munki.installatstartup"
func writeInstallAtStartupFlagFile(skipAppleUpdates: Bool = true) {
// writes out a file to trigger Munki to install Munki updates at next restart
let plist = ["SkipAppleUpdates": skipAppleUpdates]
do {
try writePlist(plist, toFile: INSTALLATSTARTUPFILE)
} catch {
// unfortunate, but not fatal.
msc_log("MSC", "cant_write_file", msg: "Couldn't write \(INSTALLATSTARTUPFILE) -- \(error)")
}
}
func killSystemPreferencesApp() {
// force quits System Preferences if it's open
let runningApps = NSRunningApplication.runningApplications(withBundleIdentifier: "com.apple.systempreferences")
for app in runningApps {
_ = app.forceTerminate()
}
}
func openSoftwareUpdatePrefsPane() {
// kill it first in case it is open with a dialog/sheet
//killSystemPreferencesApp() // nope, it reopens to previous pane
writeInstallAtStartupFlagFile()
if let softwareUpdatePrefsPane = URL(string: "x-apple.systempreferences:com.apple.preferences.softwareupdate") {
NSWorkspace.shared.open(softwareUpdatePrefsPane)
}
}
func userMustBeAdminToInstallAppleUpdates() -> Bool {
// returns a boolean telling if the user must be an admin to install Apple Updates
let suMustBeAdmin = CFPreferencesCopyAppValue(
"restrict-software-update-require-admin-to-install" as CFString,
"com.apple.SoftwareUpdate" as CFString) as? Bool ?? false
let suMustBeAdminIsForced = CFPreferencesAppValueIsForced(
"restrict-software-update-require-admin-to-install" as CFString,
"com.apple.SoftwareUpdate" as CFString)
let appStoreMustBeAdmin = CFPreferencesCopyAppValue(
"restrict-store-require-admin-to-install" as CFString,
"com.apple.appstore" as CFString ) as? Bool ?? false
let appStoreMustBeAdminIsForced = CFPreferencesAppValueIsForced(
"restrict-store-require-admin-to-install" as CFString,
"com.apple.appstore" as CFString)
return (suMustBeAdmin && suMustBeAdminIsForced) || (appStoreMustBeAdmin && appStoreMustBeAdminIsForced)
}
func findODgroupRecords(groupname: String, nodename: String = "/Search") throws -> [ODRecord] {
// Uses OpenDirectory methods to find user records for username
let searchNode = try ODNode(session: ODSession.default(), name: nodename)
let query = try ODQuery(node: searchNode,
forRecordTypes: kODRecordTypeGroups,
attribute: kODAttributeTypeRecordName,
matchType: ODMatchType(kODMatchEqualTo),
queryValues: groupname,
returnAttributes: kODAttributeTypeAllAttributes,
maximumResults: 0)
return (try query.resultsAllowingPartial(false) as! [ODRecord])
}
func findODgroupRecord(groupname: String, nodename: String = "/Search") -> ODRecord? {
// Returns first record found for groupname, or nil if not found
do {
let records = try findODgroupRecords(groupname: groupname)
if records.isEmpty {
return nil
}
return records[0]
} catch {
return nil
}
}
func userIsAdmin() -> Bool {
let username = NSUserName()
if let userRecord = findODuserRecord(username: username) {
if let adminGroupRecord = findODgroupRecord(groupname: "admin", nodename: "/Local/Default") {
do {
try adminGroupRecord.isMemberRecord(userRecord)
return true
} catch {
return false
}
}
}
return false
}
func su_pref(_ prefName: String) -> Any? {
// Return a com.apple.SoftwareUpdate preference.
return CFPreferencesCopyValue(prefName as CFString,
"com.apple.SoftwareUpdate" as CFString,
kCFPreferencesAnyUser,
kCFPreferencesCurrentHost)
}
func suRecommendedUpdateIDs() -> [String] {
// returns a list of productids for the SoftwareUpdate recommended ids
var ids = [String]()
if let recommendedUpdates = su_pref("RecommendedUpdates") as? [[String: Any]] {
for update in recommendedUpdates {
if let productKey = update["Product Key"] as? String {
ids.append(productKey)
}
}
}
return ids
}
@@ -52,6 +52,9 @@
/* Other Users Blocking Apps Running title */
"Applications in use by others" = "Programmer i brug af andre";
/* Pre Install Uninstall Upgrade Alert Title */
"Attention" = "Vær opmærksom";
/* Cancel button title/short action text */
"Cancel" = "Annuller";
@@ -151,18 +154,24 @@
/* No help alert detail */
"Help isn't available for Managed Software Center." = "Hjælp er ikke tilgængelig for Managed Software Center.";
/* Apple Software Updates Pending title */
"Important Apple Updates" = "Vigtige opdateringer fra Apple";
/* Sidebar Information label */
"Information" = "Information";
/* Install action text */
"Install" = "Installer";
/* Install Required action text */
"Install Required" = "Installering krævet";
/* Install now button title */
"Install now" = "Installer nu";
/* Install Requested status text */
"Install requested" = "Installering ønsket";
/* Install Required action text */
"Install Required" = "Installering krævet";
/* Install Session Failed title */
"Install session failed" = "Installeringen mislykkedes";
@@ -187,6 +196,9 @@
/* Logout Required title */
"Logout Required" = "Log ud krævet";
/* macOS update required text */
"macOS update required" = "Kræver macOS-opdatering";
/* Failed Preflight Check detail */
"Managed Software Center cannot check for updates now.\nTry again later. If this situation continues, contact your systems administrator." = "Managed Software Center kan ikke søge efter opdateringer.\nPrøv igen senere. Hvis problemet består, skal du kontakte systemadministratoren.";
@@ -220,15 +232,15 @@
/* No Updates message */
"No pending updates" = "Ingen ventende opdateringer";
/* Item Not Found title */
"Not Found" = "Findes ikke";
/* Not Currently Available display text */
"Not currently available" = "Ikke tilgængeligt i øjeblikket";
/* Not Enough Disk Space display text */
"Not enough disk space" = "Ikke nok plads på disken";
/* Item Not Found title */
"Not Found" = "Findes ikke";
/* Not Installed status text */
"Not installed" = "Ikke installeret";
@@ -238,6 +250,9 @@
/* OK button title */
"OK" = "OK";
/* Pending Apple Updates warning */
"One or more important Apple updates must be installed" = "Én eller flere vigtige opdateringer fra Apple skal installeres";
/* Forced Install Date summary */
"One or more items must be installed by %@" = "Et eller flere emner skal installeres senest %@";
@@ -274,6 +289,9 @@
/* Preparing Removal status text */
"Preparing removal" = "Forbereder fjernelse";
/* managedsoftwareupdate message */
"Preparing to run macOS Installer..." = "Forbereder start af macOS-installation...";
/* Problem Updates label */
"Problem updates" = "Problematiske opdateringer";
@@ -322,6 +340,9 @@
/* Sidebar Size label */
"Size:" = "Str.:";
/* Skip Apple updates button title */
"Skip these updates" = "Spring over";
/* Software label */
"Software" = "Software";
@@ -331,9 +352,15 @@
/* Restart Required alert detail */
"Software installed or removed requires a restart. You will have a chance to save open documents." = "Den software, der blev installeret eller fjernet, kræver en genstart. Du får mulighed for at gemme alle åbne dokumenter.";
/* Pre Install Uninstall Upgrade Alert Detail */
"Some conditions apply to this software. Please contact your administrator for more details" = "Denne software kræver opmærksomhed. Kontakt administratoren for mere information";
/* managedsoftwareupdate message */
"Starting Adobe installer..." = "Starter Adobe installer...";
/* managedsoftwareupdate message */
"Starting macOS upgrade..." = "Starter macOS-opgradering...";
/* managedsoftwareupdate message */
"Starting..." = "Starter...";
@@ -343,6 +370,9 @@
/* System configuration problem alert title */
"System configuration problem" = "Problem med systemkonfigurationen";
/* managedsoftwareupdate message */
"System will restart and begin upgrade of macOS." = "Systemet vil genstarte og begynde installering af macOS.";
/* managedsoftwareupdate message */
"The software was successfully installed." = "Installation af software er gennemført.";
@@ -358,6 +388,12 @@
/* No Category Results primary text */
"There are no items in this category." = "Der er ingen emner i kategorien.";
/* Apple Software Updates Pending detail */
"There are one or more pending Apple Software Updates that require a restart.\n\nYou must install these updates using Software Update in System Preferences." = "Der er én eller flere Apple-softwareopdateringer, der kræver en genstart.\n\nDu skal installere opdateringerne fra Softwareopdatering i Systemindstillinger.";
/* Apple Software Updates Unable detail */
"There are one or more pending Apple Software Updates that require a restart.\n\nYour administrator has restricted installation of these updates. Contact your administrator for assistance." = "Der er én eller flere Apple-softwareopdateringer, der kræver en genstart.\n\nAdministratoren har begrænset installationen af disse opdateringer. Kontakt din administrator for mere information.";
/* Other Users Logged In detail */
"There are other users logged into this computer.\nUpdating now could cause other users to lose their work.\n\nPlease try again later after the other users have logged out." = "Der er andre brugere logget ind på computeren.\nHvis du opdaterer nu, risikerer du, at de mister deres åbne dokumenter.\n\nPrøv igen senere når de andre brugere er logget ud.";
@@ -382,6 +418,9 @@
/* Forced Date warning */
"This item must be installed by %@" = "Dette emne skal installeres senest %@";
/* Pending days message */
"This update has been pending for %@ days." = "Denne opdatering har afventet i %@ dage.";
/* Password explanation */
"To allow this, enter your login password." = "For at tillade dette, skal du skrive din log ind-adgangskode.";
@@ -398,7 +437,7 @@
"Try selecting another developer." = "Prøv at vælge en anden udvikler.";
/* Sidebar Type label */
"Type:" = "Type:";
"Type" = "Type";
/* Unavailable status text */
"Unavailable" = "Ikke tilgængelig";
@@ -412,9 +451,6 @@
/* Update All button title */
"Update All" = "Opdater alle";
/* Update Required long action text */
"Update Required" = "Opdatering kræves";
/* No comment provided by engineer. */
"Update available" = "Kan opdateres";
@@ -427,6 +463,9 @@
/* Update Now button title */
"Update now" = "Opdater nu";
/* Update Required long action text */
"Update Required" = "Opdatering kræves";
/* Update Will Be Installed status text */
"Update will be installed" = "Opdatering bliver installeret";
@@ -471,6 +510,3 @@
/* No Pending Updates primary text */
"Your software is up to date." = "Softwaren er opdateret.";
/* macOS update required text */
"macOS update required" = "Kræver macOS-opdatering";
Binary file not shown.
@@ -1,5 +1,14 @@
/* Failed Preflight Check detail */
/* System configuration problem alert detail */
"A systems configuration issue is preventing Managed Software Center from operating correctly. The reported issue is: " = "A systems configuration issue is preventing Managed Software Centre from operating correctly. The reported issue is: ";
/* No help alert detail */
"Help isn't available for Managed Software Center." = "Help isn't available for Managed Software Centre.";
/* Failed Preflight Check detail */
"Managed Software Center cannot check for updates now.\nTry again later. If this situation continues, contact your systems administrator." = "Managed Software Centre cannot check for updates now.\nTry again later. If this situation continues, contact your systems administrator.";
/* Cannot Contact Server detail */
"Managed Software Center cannot contact the update server at this time.\nTry again later. If this situation continues, contact your systems administrator." = "Managed Software Centre cannot contact the update server at this time.\nTry again later. If this situation continues, contact your systems administrator.";
/* Password prompt title */
"Managed Software Center wants to unlock the startup disk after restarting to complete all pending updates." = "Managed Software Centre wants to unlock the startup disk after restarting to complete all pending updates.";
@@ -1,5 +1,14 @@
/* Failed Preflight Check detail */
/* System configuration problem alert detail */
"A systems configuration issue is preventing Managed Software Center from operating correctly. The reported issue is: " = "A systems configuration issue is preventing Managed Software Centre from operating correctly. The reported issue is: ";
/* No help alert detail */
"Help isn't available for Managed Software Center." = "Help isn't available for Managed Software Centre.";
/* Failed Preflight Check detail */
"Managed Software Center cannot check for updates now.\nTry again later. If this situation continues, contact your systems administrator." = "Managed Software Centre cannot check for updates now.\nTry again later. If this situation continues, contact your systems administrator.";
/* Cannot Contact Server detail */
"Managed Software Center cannot contact the update server at this time.\nTry again later. If this situation continues, contact your systems administrator." = "Managed Software Centre cannot contact the update server at this time.\nTry again later. If this situation continues, contact your systems administrator.";
/* Password prompt title */
"Managed Software Center wants to unlock the startup disk after restarting to complete all pending updates." = "Managed Software Centre wants to unlock the startup disk after restarting to complete all pending updates.";
@@ -1,5 +1,14 @@
/* Failed Preflight Check detail */
/* System configuration problem alert detail */
"A systems configuration issue is preventing Managed Software Center from operating correctly. The reported issue is: " = "A systems configuration issue is preventing Managed Software Centre from operating correctly. The reported issue is: ";
/* No help alert detail */
"Help isn't available for Managed Software Center." = "Help isn't available for Managed Software Centre.";
/* Failed Preflight Check detail */
"Managed Software Center cannot check for updates now.\nTry again later. If this situation continues, contact your systems administrator." = "Managed Software Centre cannot check for updates now.\nTry again later. If this situation continues, contact your systems administrator.";
/* Cannot Contact Server detail */
"Managed Software Center cannot contact the update server at this time.\nTry again later. If this situation continues, contact your systems administrator." = "Managed Software Centre cannot contact the update server at this time.\nTry again later. If this situation continues, contact your systems administrator.";
/* Password prompt title */
"Managed Software Center wants to unlock the startup disk after restarting to complete all pending updates." = "Managed Software Centre wants to unlock the startup disk after restarting to complete all pending updates.";
@@ -1,32 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIconFile</key>
<string></string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>5.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSMinimumSystemVersion</key>
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2019-2020 The Munki Project. All rights reserved.</string>
<key>NSMainNibFile</key>
<string>MainMenu</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
</dict>
</plist>
@@ -1,4 +1,3 @@
/* Class = "NSMenuItem"; title = "Navigate"; ObjectID = "1Dc-SU-RKH"; */
"1Dc-SU-RKH.title" = "Navigate";
@@ -52,6 +52,9 @@
/* Other Users Blocking Apps Running title */
"Applications in use by others" = "Applicaciones en uso por otros";
/* Pre Install Uninstall Upgrade Alert Title */
"Attention" = "Atención";
/* Cancel button title/short action text */
"Cancel" = "Cancelar";
@@ -151,18 +154,24 @@
/* No help alert detail */
"Help isn't available for Managed Software Center." = "No hay ayuda disponible para el Centro de aplicaciones.";
/* Apple Software Updates Pending title */
"Important Apple Updates" = "Actualizaciones importantes de Apple";
/* Sidebar Information label */
"Information" = "Información";
/* Install action text */
"Install" = "Instalar";
/* Install Required action text */
"Install Required" = "Instalación requerida";
/* Install now button title */
"Install now" = "Install ahora";
/* Install Requested status text */
"Install requested" = "Instalación solicitada";
/* Install Required action text */
"Install Required" = "Instalación requerida";
/* Install Session Failed title */
"Install session failed" = "Error en la sesión de instalación";
@@ -187,6 +196,9 @@
/* Logout Required title */
"Logout Required" = "Es necesario cerrar sesión";
/* macOS update required text */
"macOS update required" = "Actualización de macOS requerida";
/* Failed Preflight Check detail */
"Managed Software Center cannot check for updates now.\nTry again later. If this situation continues, contact your systems administrator." = "Centro de aplicaciones no puede comprobar las actualizaciones.\nPrueba más tarde. Si esta situación continua, contacta con el administrador de sistemas.";
@@ -220,15 +232,15 @@
/* No Updates message */
"No pending updates" = "No hay actualizaciones pendientes";
/* Item Not Found title */
"Not Found" = "No encontrado";
/* Not Currently Available display text */
"Not currently available" = "Actualmente no disponible";
/* Not Enough Disk Space display text */
"Not enough disk space" = "No hay suficiente espacion en el disco";
/* Item Not Found title */
"Not Found" = "No encontrado";
/* Not Installed status text */
"Not installed" = "No instalado";
@@ -238,6 +250,9 @@
/* OK button title */
"OK" = "Aceptar";
/* Pending Apple Updates warning */
"One or more important Apple updates must be installed" = "Una o más actualizaciones importates de Apple deben ser instaladas";
/* Forced Install Date summary */
"One or more items must be installed by %@" = "Uno o mas ítems tienen que ser instalados para el %@";
@@ -274,6 +289,9 @@
/* Preparing Removal status text */
"Preparing removal" = "Preparando desinstalación";
/* managedsoftwareupdate message */
"Preparing to run macOS Installer..." = "Preparando para ejecutar el instalador de macOS";
/* Problem Updates label */
"Problem updates" = "Actualización problematica";
@@ -322,6 +340,9 @@
/* Sidebar Size label */
"Size:" = "Tamaño:";
/* Skip Apple updates button title */
"Skip these updates" = "Saltar actualizaciones de Apple";
/* Software label */
"Software" = "Aplicaciones";
@@ -331,9 +352,15 @@
/* Restart Required alert detail */
"Software installed or removed requires a restart. You will have a chance to save open documents." = "El software instalado necesita reiniciar el equipo. Tendrás oportunidad de guardar tus documentos";
/* Pre Install Uninstall Upgrade Alert Detail */
"Some conditions apply to this software. Please contact your administrator for more details" = "Este software esta sujeto a algunas condiciones. Por favor contacta con tu administrador de sistemas para obtener más información";
/* managedsoftwareupdate message */
"Starting Adobe installer..." = "Empezando el instalador de Adobe...";
/* managedsoftwareupdate message */
"Starting macOS upgrade..." = "Empezando actualización completa de macOS";
/* managedsoftwareupdate message */
"Starting..." = "Empezando...";
@@ -343,6 +370,9 @@
/* System configuration problem alert title */
"System configuration problem" = "Problema en la configuración del sistema";
/* managedsoftwareupdate message */
"System will restart and begin upgrade of macOS." = "El sistema se reiniciará y comenzará la intalación completa de macOS";
/* managedsoftwareupdate message */
"The software was successfully installed." = "El software se instaló correctamente.";
@@ -358,6 +388,12 @@
/* No Category Results primary text */
"There are no items in this category." = "No hay ítems en esta categoria.";
/* Apple Software Updates Pending detail */
"There are one or more pending Apple Software Updates that require a restart.\n\nYou must install these updates using Software Update in System Preferences." = "Hay una o mas actualizaciones de software de Apple que requieren un reinicio.\n\nDebes instalar estas actualizaciones usando Actualización de software en Preferencias del Sistema";
/* Apple Software Updates Unable detail */
"There are one or more pending Apple Software Updates that require a restart.\n\nYour administrator has restricted installation of these updates. Contact your administrator for assistance." = "Hay una o mas actualizaciones de software de Apple que requieren un reinicio.\n\nTu administrador de sistemas ha restringido la instalación de estas actualizaciones. Contacta con tu administrador para recibir asistencia.";
/* Other Users Logged In detail */
"There are other users logged into this computer.\nUpdating now could cause other users to lose their work.\n\nPlease try again later after the other users have logged out." = "Hay otros usuarios con sesiones abiertas en este equipo.\nActualizar ahora puede causar perdidas en su trabajo.\n\nPor favor prueba más tarde cuando los otros usuarios hayan cerrado sus sesiones.";
@@ -382,6 +418,9 @@
/* Forced Date warning */
"This item must be installed by %@" = "Tiene que estar instalado para el %@";
/* Pending days message */
"This update has been pending for %@ days." = "Esta actualización ha estado pendiente durante %@ days.";
/* Password explanation */
"To allow this, enter your login password." = "Para permitir esto, introduzca su contraseña de usuario.";
@@ -398,7 +437,7 @@
"Try selecting another developer." = "Intentar seleccionar otro desarollador.";
/* Sidebar Type label */
"Type:" = "Tipo:";
"Type" = "Tipo";
/* Unavailable status text */
"Unavailable" = "No disponible";
@@ -412,9 +451,6 @@
/* Update All button title */
"Update All" = "Actualizar todo";
/* Update Required long action text */
"Update Required" = "Requiere una actualización";
/* No comment provided by engineer. */
"Update available" = "Actualización disponible";
@@ -427,6 +463,9 @@
/* Update Now button title */
"Update now" = "Actualizar ahora";
/* Update Required long action text */
"Update Required" = "Requiere una actualización";
/* Update Will Be Installed status text */
"Update will be installed" = "Se instalará la actualización";
@@ -471,6 +510,3 @@
/* No Pending Updates primary text */
"Your software is up to date." = "Tus aplicaciones están actualizadas.";
/* macOS update required text */
"macOS update required" = "Actualización de macOS requerida";
@@ -52,6 +52,9 @@
/* Other Users Blocking Apps Running title */
"Applications in use by others" = "Muiden käyttäjien käytössä olevat ohjelmat";
/* Pre Install Uninstall Upgrade Alert Title */
"Attention" = "Huomio";
/* Cancel button title/short action text */
"Cancel" = "Kumoa";
@@ -151,18 +154,24 @@
/* No help alert detail */
"Help isn't available for Managed Software Center." = "Managed Software Center -ohjelmalle ei ole ohjetta.";
/* Apple Software Updates Pending title */
"Important Apple Updates" = "Tärkeitä Applen päivityksiä";
/* Sidebar Information label */
"Information" = "Tietoja";
/* Install action text */
"Install" = "Asenna";
/* Install Required action text */
"Install Required" = "Pakollinen asennus";
/* Install now button title */
"Install now" = "Asenna nyt";
/* Install Requested status text */
"Install requested" = "Asennusta pyydetty";
/* Install Required action text */
"Install Required" = "Pakollinen asennus";
/* Install Session Failed title */
"Install session failed" = "Asennus epäonnistui";
@@ -187,6 +196,9 @@
/* Logout Required title */
"Logout Required" = "Vaatii uloskirjautumisen";
/* macOS update required text */
"macOS update required" = "macOS-päivitys vaaditaan";
/* Failed Preflight Check detail */
"Managed Software Center cannot check for updates now.\nTry again later. If this situation continues, contact your systems administrator." = "Managed Software Center ei voi tarkistaa päivityksiä juuri nyt. Yritä myöhemmin uudelleen. Jos ongelma jatkuu, ota yhteyttä järjestelmän ylläpitäjään.";
@@ -220,15 +232,15 @@
/* No Updates message */
"No pending updates" = "Ei päivityksiä";
/* Item Not Found title */
"Not Found" = "Ei tuloksia";
/* Not Currently Available display text */
"Not currently available" = "Ei saatavilla tällä hetkellä";
/* Not Enough Disk Space display text */
"Not enough disk space" = "Kovalevyllä ei ole tarpeeksi tilaa";
/* Item Not Found title */
"Not Found" = "Ei tuloksia";
/* Not Installed status text */
"Not installed" = "Ei asennettu";
@@ -238,6 +250,9 @@
/* OK button title */
"OK" = "OK";
/* Pending Apple Updates warning */
"One or more important Apple updates must be installed" = "Yksi tai useampi tärkeä Applen päivitys täytyy asentaa";
/* Forced Install Date summary */
"One or more items must be installed by %@" = "Yksi tai useampi kohde täytyy asentaa ennen %@";
@@ -274,6 +289,9 @@
/* Preparing Removal status text */
"Preparing removal" = "Valmistellaan poistoa";
/* managedsoftwareupdate message */
"Preparing to run macOS Installer..." = "Valmistellaan macOS-asentajan käynnistämistä...";
/* Problem Updates label */
"Problem updates" = "Epäonnistuneet päivitykset";
@@ -322,6 +340,9 @@
/* Sidebar Size label */
"Size:" = "Koko:";
/* Skip Apple updates button title */
"Skip these updates" = "Ohita nämä päivitykset";
/* Software label */
"Software" = "Ohjelmistot";
@@ -331,9 +352,15 @@
/* Restart Required alert detail */
"Software installed or removed requires a restart. You will have a chance to save open documents." = "Asennettu ohjelmisto tai poisto vaatii tietokoneen uudelleenkäynnistyksen. Avoinna olevien dokumenttien tallentaminen on mahdollista.";
/* Pre Install Uninstall Upgrade Alert Detail */
"Some conditions apply to this software. Please contact your administrator for more details" = "Tähän päivitykseen liittyy ehtoja. Ota yhteys ylläpitäjään";
/* managedsoftwareupdate message */
"Starting Adobe installer..." = "Käynnistetään Adobe-asentajaa...";
/* managedsoftwareupdate message */
"Starting macOS upgrade..." = "Aloitetaan macOS-päivitys...";
/* managedsoftwareupdate message */
"Starting..." = "Aloitetaan...";
@@ -343,6 +370,9 @@
/* System configuration problem alert title */
"System configuration problem" = "Järjestelmän määritysvirhe";
/* managedsoftwareupdate message */
"System will restart and begin upgrade of macOS." = "Järjestelmä käynnistyy uudelleen ja aloittaa macOS-päivityksen.";
/* managedsoftwareupdate message */
"The software was successfully installed." = "Ohjelmiston asennus onnistui.";
@@ -358,6 +388,12 @@
/* No Category Results primary text */
"There are no items in this category." = "Ei kohteita tässä kategoriassa.";
/* Apple Software Updates Pending detail */
"There are one or more pending Apple Software Updates that require a restart.\n\nYou must install these updates using Software Update in System Preferences." = "Yksi tai useampi saatavilla oleva Applen päivitys vaatii uudelleenkäynnistyksen.\n\nPäivitykset täytyy asentaa avaamalla Järjestelmäasetukset ja valitsemalla Ohjelmiston päivitys.";
/* Apple Software Updates Unable detail */
"There are one or more pending Apple Software Updates that require a restart.\n\nYour administrator has restricted installation of these updates. Contact your administrator for assistance." = "Yksi tai useampi saatavilla oleva Applen päivitys vaatii uudelleenkäynnistyksen.\n\nYlläpitäjä on rajoittanut näiden päivitysten asentamista. Ota yhteyttä ylläpitäjään.";
/* Other Users Logged In detail */
"There are other users logged into this computer.\nUpdating now could cause other users to lose their work.\n\nPlease try again later after the other users have logged out." = "Tietokoneelle on kirjautuneena muita käyttäjiä.\nMuut käyttäjät saattavat menettää tallentamattomia muutoksia jos päivitys tehdään nyt.\n\nYritä uudelleen kun muut käyttäjät ovat kirjautuneet ulos.";
@@ -382,6 +418,9 @@
/* Forced Date warning */
"This item must be installed by %@" = "Asennettava ennen %@";
/* Pending days message */
"This update has been pending for %@ days." = "Päivitys on ollut saatavilla %@ päivää.";
/* Password explanation */
"To allow this, enter your login password." = "Salli lukituksen avaaminen syöttämällä salasana.";
@@ -398,7 +437,7 @@
"Try selecting another developer." = "Valitse toinen kehittäjä.";
/* Sidebar Type label */
"Type:" = "Tyyppi:";
"Type" = "Tyyppi";
/* Unavailable status text */
"Unavailable" = "Ei saatavilla";
@@ -412,9 +451,6 @@
/* Update All button title */
"Update All" = "Päivitä kaikki";
/* Update Required long action text */
"Update Required" = "Pakollinen päivitys";
/* No comment provided by engineer. */
"Update available" = "Päivitys saatavilla";
@@ -427,6 +463,9 @@
/* Update Now button title */
"Update now" = "Päivitä nyt";
/* Update Required long action text */
"Update Required" = "Pakollinen päivitys";
/* Update Will Be Installed status text */
"Update will be installed" = "Päivitys asennetaan";
@@ -471,6 +510,3 @@
/* No Pending Updates primary text */
"Your software is up to date." = "Ohjelmisto on ajan tasalla.";
/* macOS update required text */
"macOS update required" = "macOS-päivitys vaaditaan";
@@ -47,12 +47,14 @@
"An older version is currently installed. There is not enough disk space to download and install this update." = "Une ancienne version est actuellement installée. Il n'y a pas assez d'espace disque pour télécharger et installer cette mise à jour.";
/* Long update requires a higher OS version text */
"An older version is currently installed. You must upgrade to macOS version %@ or higher to be able to install this update." = "Une ancienne version est actuellement installée. Vous devez mettre à jour vers une version macOS
%@ ou plus pour pouvoir installer cette mise à jour.";
"An older version is currently installed. You must upgrade to macOS version %@ or higher to be able to install this update." = "Une version antérieure est actuellement installée. Vous devez mettre à jour macOS à la version %@ ou plus récente pour pouvoir installer cette mise à jour.";
/* Other Users Blocking Apps Running title */
"Applications in use by others" = "Application utilisée par d'autres";
/* Pre Install Uninstall Upgrade Alert Title */
"Attention" = "Attention";
/* Cancel button title/short action text */
"Cancel" = "Annuler";
@@ -152,18 +154,24 @@
/* No help alert detail */
"Help isn't available for Managed Software Center." = "L'aide n'est pas disponible pour le Centre de gestion des logiciels.";
/* Apple Software Updates Pending title */
"Important Apple Updates" = "Mises à jour Apple importantes";
/* Sidebar Information label */
"Information" = "Information";
/* Install action text */
"Install" = "Installer";
/* Install Required action text */
"Install Required" = "Installation obligatoire";
/* Install now button title */
"Install now" = "Installer maintenant";
/* Install Requested status text */
"Install requested" = "Installation demandée";
/* Install Required action text */
"Install Required" = "Installation obligatoire";
/* Install Session Failed title */
"Install session failed" = "Échec de l'installation";
@@ -188,6 +196,9 @@
/* Logout Required title */
"Logout Required" = "Fermeture de session obligatoire";
/* macOS update required text */
"macOS update required" = "Mise à jour MacOS requise";
/* Failed Preflight Check detail */
"Managed Software Center cannot check for updates now.\nTry again later. If this situation continues, contact your systems administrator." = "Le Centre de gestion des logiciels ne peut vérifier les mises à jour maintenant.\nEssayez plus tard. Si cette situation perdure, contactez votre administrateur système.";
@@ -221,15 +232,15 @@
/* No Updates message */
"No pending updates" = "Aucune mise à jour en attente";
/* Item Not Found title */
"Not Found" = "Aucune correspondance";
/* Not Currently Available display text */
"Not currently available" = "Non disponible actuellement";
/* Not Enough Disk Space display text */
"Not enough disk space" = "Pas assez d'espace disque";
/* Item Not Found title */
"Not Found" = "Aucune correspondance";
/* Not Installed status text */
"Not installed" = "Non installé";
@@ -239,6 +250,9 @@
/* OK button title */
"OK" = "OK";
/* Pending Apple Updates warning */
"One or more important Apple updates must be installed" = "Une ou plusieurs mises à jour Apple importantes doivent être installées";
/* Forced Install Date summary */
"One or more items must be installed by %@" = "Un article doit être installé avant le %@";
@@ -275,6 +289,9 @@
/* Preparing Removal status text */
"Preparing removal" = "Préparation de la suppression";
/* managedsoftwareupdate message */
"Preparing to run macOS Installer..." = "Préparation du lancement de l'installeur macOS";
/* Problem Updates label */
"Problem updates" = "Mises à jour problématiques";
@@ -323,6 +340,9 @@
/* Sidebar Size label */
"Size:" = "Taille:";
/* Skip Apple updates button title */
"Skip these updates" = "Ignorer ces mises à jour";
/* Software label */
"Software" = "Logiciel";
@@ -332,9 +352,15 @@
/* Restart Required alert detail */
"Software installed or removed requires a restart. You will have a chance to save open documents." = "Les logiciels installés ou supprimés nécessitent un redémarrage. Vous aurez la possibilité de sauvegarder les documents ouverts.";
/* Pre Install Uninstall Upgrade Alert Detail */
"Some conditions apply to this software. Please contact your administrator for more details" = "Des conditions d'utilisation sont applicables à ce logiciel. Merci de contacter votre administrateur pour plus d'informations";
/* managedsoftwareupdate message */
"Starting Adobe installer..." = "Démarrage du programme d'installation d'Adobe...";
/* managedsoftwareupdate message */
"Starting macOS upgrade..." = "Démarrage de la mise à jour de macOS...";
/* managedsoftwareupdate message */
"Starting..." = "Démarrage...";
@@ -344,6 +370,9 @@
/* System configuration problem alert title */
"System configuration problem" = "Problème de configuration du système";
/* managedsoftwareupdate message */
"System will restart and begin upgrade of macOS." = "Le système va redémarrer et lancer la mise à jour de macOS.";
/* managedsoftwareupdate message */
"The software was successfully installed." = "Le logiciel a été installé avec succès.";
@@ -359,6 +388,12 @@
/* No Category Results primary text */
"There are no items in this category." = "Il n'y a pas d'articles dans cette catégorie.";
/* Apple Software Updates Pending detail */
"There are one or more pending Apple Software Updates that require a restart.\n\nYou must install these updates using Software Update in System Preferences." = "Une ou plusieurs mises à jour logicielles Apple importantes nécessitent un redémarrage.\n\nVous devez les installer en utilisant Mise à jour de logiciels dans les Préférences Système.";
/* Apple Software Updates Unable detail */
"There are one or more pending Apple Software Updates that require a restart.\n\nYour administrator has restricted installation of these updates. Contact your administrator for assistance." = "Une ou plusieurs mises à jour logicielles Apple importantes nécessitent un redémarrage.\n\nVotre administrateur a restreint l'installation de ces mises à jour. Contactez votre administrateur pour de l'assistance.";
/* Other Users Logged In detail */
"There are other users logged into this computer.\nUpdating now could cause other users to lose their work.\n\nPlease try again later after the other users have logged out." = "Il y a d'autres utilisateurs connectés sur l'ordinateur.\nMettre à jour peut entrainer la perte du travail des autres utilisateurs.\n\nMerci d'essayer plus tard après que les autres utilisateurs aient quitté leur session.";
@@ -383,6 +418,9 @@
/* Forced Date warning */
"This item must be installed by %@" = "Cet article doit être installé avant le %@";
/* Pending days message */
"This update has been pending for %@ days." = "Cette mise à jour est en attente depuis %@ jours.";
/* Password explanation */
"To allow this, enter your login password." = "Pour autoriser cette opération, veuillez entrer votre mot de passe.";
@@ -399,7 +437,7 @@
"Try selecting another developer." = "Essayez de sélectionner un autre développeur.";
/* Sidebar Type label */
"Type:" = "Type:";
"Type" = "Type";
/* Unavailable status text */
"Unavailable" = "Non disponible";
@@ -413,9 +451,6 @@
/* Update All button title */
"Update All" = "Tout mettre à jour";
/* Update Required long action text */
"Update Required" = "Mise à jour obligatoire";
/* No comment provided by engineer. */
"Update available" = "Mise à jour disponible";
@@ -428,6 +463,9 @@
/* Update Now button title */
"Update now" = "Mettre à jour maintenant";
/* Update Required long action text */
"Update Required" = "Mise à jour obligatoire";
/* Update Will Be Installed status text */
"Update will be installed" = "La mise à jour sera installée";
@@ -472,6 +510,3 @@
/* No Pending Updates primary text */
"Your software is up to date." = "Votre logiciel est à jour.";
/* macOS update required text */
"macOS update required" = "Mise à jour MacOS requise";
@@ -52,6 +52,9 @@
/* Other Users Blocking Apps Running title */
"Applications in use by others" = "Applicazioni in uso da altri";
/* Pre Install Uninstall Upgrade Alert Title */
"Attention" = "Attenzione";
/* Cancel button title/short action text */
"Cancel" = "Cancella";
@@ -110,7 +113,7 @@
"Determining which filesystem items to remove" = "Determino elementi del filesystem da rimuovere";
/* Sidebar Developer label */
"Developer:" = "Developer:";
"Developer:" = "Sviluppatore:";
/* managedsoftwareupdate message */
"Done." = "Fatto.";
@@ -151,18 +154,24 @@
/* No help alert detail */
"Help isn't available for Managed Software Center." = "Aiuto non è disponibile per Centro Gestione Applicazioni.";
/* Apple Software Updates Pending title */
"Important Apple Updates" = "Aggiornamenti importanti da Apple";
/* Sidebar Information label */
"Information" = "Informazioni";
/* Install action text */
"Install" = "Installazione";
/* Install Required action text */
"Install Required" = "Installazione Necessaria";
/* Install now button title */
"Install now" = "Installa adesso";
/* Install Requested status text */
"Install requested" = "Installazione richiesta";
/* Install Required action text */
"Install Required" = "Installazione Necessaria";
/* Install Session Failed title */
"Install session failed" = "Sessione di installazione fallita";
@@ -187,6 +196,9 @@
/* Logout Required title */
"Logout Required" = "Logout Necessario";
/* macOS update required text */
"macOS update required" = "È richiesto un aggiornamento di Mac OS";
/* Failed Preflight Check detail */
"Managed Software Center cannot check for updates now.\nTry again later. If this situation continues, contact your systems administrator." = "In questo momento il Centro Gestione Applicazioni non riesce a controllare gli aggiornamenti.\nRiprovare più tardi. Se questa situazione persiste, contattare l'amministratore di sistema.";
@@ -220,15 +232,15 @@
/* No Updates message */
"No pending updates" = "Nessun aggiornamento in sospeso";
/* Item Not Found title */
"Not Found" = "Non Trovato";
/* Not Currently Available display text */
"Not currently available" = "Attualmente non disponibile";
/* Not Enough Disk Space display text */
"Not enough disk space" = "Non c'è abbastanza spazio su disco";
/* Item Not Found title */
"Not Found" = "Non Trovato";
/* Not Installed status text */
"Not installed" = "Non Installato";
@@ -238,6 +250,9 @@
/* OK button title */
"OK" = "OK";
/* Pending Apple Updates warning */
"One or more important Apple updates must be installed" = "Uno o più aggiornamenti software importanti di Apple devono essere installati";
/* Forced Install Date summary */
"One or more items must be installed by %@" = "Uno o più elementi devono essere installati da %@";
@@ -274,6 +289,9 @@
/* Preparing Removal status text */
"Preparing removal" = "Rimozione in preparazione";
/* managedsoftwareupdate message */
"Preparing to run macOS Installer..." = "Preparo l'installazione di macOS...";
/* Problem Updates label */
"Problem updates" = "Aggiornamenti che richiedono attenzione";
@@ -322,6 +340,9 @@
/* Sidebar Size label */
"Size:" = "Dimensione:";
/* Skip Apple updates button title */
"Skip these updates" = "Ignora questi aggiornamenti";
/* Software label */
"Software" = "Applicazione";
@@ -331,18 +352,27 @@
/* Restart Required alert detail */
"Software installed or removed requires a restart. You will have a chance to save open documents." = "L'applicazione installata o rimossa richiede il riavvio. Avrai la possibilità di salvare i documenti aperti.";
/* Pre Install Uninstall Upgrade Alert Detail */
"Some conditions apply to this software. Please contact your administrator for more details" = "Delle condizioni specifiche si applicano a questo software. Contatta il tuo amministratore di sistema per maggiori informazioni";
/* managedsoftwareupdate message */
"Starting Adobe installer..." = "Avvio Adobe installer...";
/* managedsoftwareupdate message */
"Starting macOS upgrade..." = "Inizio dell'aggiornamento di macOS...";
/* managedsoftwareupdate message */
"Starting..." = "Avvio...";
/* Sidebar Status label */
"Status:" = "Status:";
"Status:" = "Stato:";
/* System configuration problem alert title */
"System configuration problem" = "Problema di configurazione di sistema";
/* managedsoftwareupdate message */
"System will restart and begin upgrade of macOS." = "Il sistema si riavvierà e inizierà l'aggiornamento di macOS";
/* managedsoftwareupdate message */
"The software was successfully installed." = "L'applicazione è stata installata con successo.";
@@ -358,6 +388,12 @@
/* No Category Results primary text */
"There are no items in this category." = "Non ci sono elementi in questa categoria.";
/* Apple Software Updates Pending detail */
"There are one or more pending Apple Software Updates that require a restart.\n\nYou must install these updates using Software Update in System Preferences." = "Ci sono uno o più aggiornamenti in sospeso che richiedono il riavvio del sistema.\n\nInstalla questi aggiornamenti usando Aggiornamento Software nelle Preferenze di Sistema.";
/* Apple Software Updates Unable detail */
"There are one or more pending Apple Software Updates that require a restart.\n\nYour administrator has restricted installation of these updates. Contact your administrator for assistance." = "Ci sono uno o più aggiornamenti in sospeso che richiedono il riavvio del sistema.\n\nL'amministratore di sistema controlla l'installazione di questi aggiornamenti. Contatta l'amministratore di sistema per richiedere assistenza.";
/* Other Users Logged In detail */
"There are other users logged into this computer.\nUpdating now could cause other users to lose their work.\n\nPlease try again later after the other users have logged out." = "Ci sono altri utenti collegati a questo computer.\nAggiornare ora può causare la perdita dei loro dati.\n\nRiprovare quando tutti gli utenti saranno scollegati.";
@@ -382,6 +418,9 @@
/* Forced Date warning */
"This item must be installed by %@" = "Questo elemento deve essere installato da %@";
/* Pending days message */
"This update has been pending for %@ days." = "Questo aggiornamento è in sospeso da %@ giorni.";
/* Password explanation */
"To allow this, enter your login password." = "Per permettere questo, inserire la password di login.";
@@ -398,7 +437,7 @@
"Try selecting another developer." = "Prova selezionando un altro developer.";
/* Sidebar Type label */
"Type:" = "Tipo:";
"Type" = "Tipo";
/* Unavailable status text */
"Unavailable" = "Non disponibile";
@@ -412,9 +451,6 @@
/* Update All button title */
"Update All" = "Aggiorna Tutto";
/* Update Required long action text */
"Update Required" = "Aggiornamento richiesto";
/* No comment provided by engineer. */
"Update available" = "Aggiornamento disponibile";
@@ -427,6 +463,9 @@
/* Update Now button title */
"Update now" = "Aggiorna adesso";
/* Update Required long action text */
"Update Required" = "Aggiornamento richiesto";
/* Update Will Be Installed status text */
"Update will be installed" = "L'aggiornamento verrà installato";
@@ -471,6 +510,3 @@
/* No Pending Updates primary text */
"Your software is up to date." = "Le applicazioni sono aggiornate.";
/* macOS update required text */
"macOS update required" = "È richiesto un aggiornamento di Mac OS";
@@ -52,6 +52,9 @@
/* Other Users Blocking Apps Running title */
"Applications in use by others" = "他のユーザーが使用しているアプリケーションです";
/* Pre Install Uninstall Upgrade Alert Title */
"Attention" = "注意";
/* Cancel button title/short action text */
"Cancel" = "キャンセル";
@@ -151,18 +154,24 @@
/* No help alert detail */
"Help isn't available for Managed Software Center." = "Managed Software Centerにヘルプは付属していません";
/* Apple Software Updates Pending title */
"Important Apple Updates" = "重要な Apple ソフトウェアアップデート";
/* Sidebar Information label */
"Information" = "情報";
/* Install action text */
"Install" = "インストール";
/* Install Required action text */
"Install Required" = "要請されたインストール";
/* Install now button title */
"Install now" = "今すぐインストール";
/* Install Requested status text */
"Install requested" = "要請されたインストール";
/* Install Required action text */
"Install Required" = "要請されたインストール";
/* Install Session Failed title */
"Install session failed" = "インストールセッションに失敗しました";
@@ -187,6 +196,9 @@
/* Logout Required title */
"Logout Required" = "ログアウトが必要です";
/* macOS update required text */
"macOS update required" = "macOSアップデートが必要";
/* Failed Preflight Check detail */
"Managed Software Center cannot check for updates now.\nTry again later. If this situation continues, contact your systems administrator." = "Managed Software Centerは現在アップーデートのチェックができません。\n後でもう一度実行してください。もしこの状況が改善されない場合は、システム管理者に連絡してください。";
@@ -220,15 +232,15 @@
/* No Updates message */
"No pending updates" = "保留中のアップデートはありません";
/* Item Not Found title */
"Not Found" = "見つかりません";
/* Not Currently Available display text */
"Not currently available" = "現在使用ができません";
/* Not Enough Disk Space display text */
"Not enough disk space" = "ディスクの空きが足りません";
/* Item Not Found title */
"Not Found" = "見つかりません";
/* Not Installed status text */
"Not installed" = "インストールされていません";
@@ -238,6 +250,9 @@
/* OK button title */
"OK" = "OK";
/* Pending Apple Updates warning */
"One or more important Apple updates must be installed" = "重要な Apple ソフトウェアアップデートをインストールする必要があります";
/* Forced Install Date summary */
"One or more items must be installed by %@" = "%@までに、1つまたそれ以上のアイテムのインストールが必要です";
@@ -274,6 +289,9 @@
/* Preparing Removal status text */
"Preparing removal" = "削除準備中です";
/* managedsoftwareupdate message */
"Preparing to run macOS Installer..." = "macOS インストーラを実行する準備をしています...";
/* Problem Updates label */
"Problem updates" = "問題のアップデート";
@@ -322,6 +340,9 @@
/* Sidebar Size label */
"Size:" = "サイズ:";
/* Skip Apple updates button title */
"Skip these updates" = "ソフトウェアアップデートをスキップ";
/* Software label */
"Software" = "ソフトウェア";
@@ -331,9 +352,15 @@
/* Restart Required alert detail */
"Software installed or removed requires a restart. You will have a chance to save open documents." = "インストールまた削除したソフトウェアがあるため再起動が必要です。現在使用中のドキュメントの保存ができます。";
/* Pre Install Uninstall Upgrade Alert Detail */
"Some conditions apply to this software. Please contact your administrator for more details" = "このソフトウェアには、いくつかの条件が適用されます。詳しくは管理者にお問い合わせください";
/* managedsoftwareupdate message */
"Starting Adobe installer..." = "Adobeインストーラーを開始…";
/* managedsoftwareupdate message */
"Starting macOS upgrade..." = "macOS のアップグレードを開始しています...";
/* managedsoftwareupdate message */
"Starting..." = "開始…";
@@ -343,6 +370,9 @@
/* System configuration problem alert title */
"System configuration problem" = "システムコンフィギュレーションに問題があります";
/* managedsoftwareupdate message */
"System will restart and begin upgrade of macOS." = "システムが再起動し、macOS のアップグレードが始まります。";
/* managedsoftwareupdate message */
"The software was successfully installed." = "ソフトウェアのインストールが完了しました";
@@ -358,6 +388,12 @@
/* No Category Results primary text */
"There are no items in this category." = "このカテゴリにアイテムはありません";
/* Apple Software Updates Pending detail */
"There are one or more pending Apple Software Updates that require a restart.\n\nYou must install these updates using Software Update in System Preferences." = "再起動が必要となる Apple ソフトウェアアップデートが保留中となっています。\n\nこのアップデートは、「システム環境設定」の「ソフトウェアアップデート」を使用してインストールする必要があります。";
/* Apple Software Updates Unable detail */
"There are one or more pending Apple Software Updates that require a restart.\n\nYour administrator has restricted installation of these updates. Contact your administrator for assistance." = "再起動が必要となる Apple ソフトウェアアップデートが保留中となっています。\n\nこのアップデートのインストールは制限されています。システム管理者にお問い合わせください。";
/* Other Users Logged In detail */
"There are other users logged into this computer.\nUpdating now could cause other users to lose their work.\n\nPlease try again later after the other users have logged out." = "他のユーザーがこのコンピューターにログインしています。\n今アップデートを実行すると、他のユーザーのワークが失われる原因になります。\n\n他のユーザーがログアウトしたのち、もう一度アップデートを実行してください。";
@@ -382,6 +418,9 @@
/* Forced Date warning */
"This item must be installed by %@" = "このアイテムは%@までにインストールしなければいけません";
/* Pending days message */
"This update has been pending for %@ days." = "この更新は、%@ 日間保留となっています。";
/* Password explanation */
"To allow this, enter your login password." = "これを許可する為、ログインパスワードを入力して下さい。";
@@ -398,7 +437,7 @@
"Try selecting another developer." = "ほかのディベロッパを選択してしてください";
/* Sidebar Type label */
"Type:" = "種類:";
"Type" = "種類";
/* Unavailable status text */
"Unavailable" = "入手できません";
@@ -412,9 +451,6 @@
/* Update All button title */
"Update All" = "すべてをアップデート";
/* Update Required long action text */
"Update Required" = "アップデートが必要です";
/* No comment provided by engineer. */
"Update available" = "アップデートがあります";
@@ -427,6 +463,9 @@
/* Update Now button title */
"Update now" = "今すぐアップデート";
/* Update Required long action text */
"Update Required" = "アップデートが必要です";
/* Update Will Be Installed status text */
"Update will be installed" = "アップデートをインストールします";
@@ -471,6 +510,3 @@
/* No Pending Updates primary text */
"Your software is up to date." = "ソフトウェアは最新です";
/* macOS update required text */
"macOS update required" = "macOSアップデートが必要";
@@ -613,7 +613,8 @@ func buildUpdatesPage() throws {
try buildUpdateStatusPage()
return
}
let item_list = getEffectiveUpdateList()
let filterAppleUpdates = (NSApp.delegate! as! AppDelegate).mainWindowController.should_filter_apple_updates
let item_list = getEffectiveUpdateList(filterAppleUpdates)
let problem_updates = getProblemItems()
for item in problem_updates {
item["hide_cancel_button"] = "hidden"
@@ -672,7 +673,7 @@ func buildUpdatesPage() throws {
// in Python was count = len([item for item in item_list if item['status'] != 'problem-item'])
page["update_count"] = updateCountMessage(count)
page["install_btn_label"] = getInstallAllButtonTextForCount(count)
page["warning_text"] = getWarningText()
page["warning_text"] = getWarningText(filterAppleUpdates)
// build problem updates table
page["problem_updates_header_message"] = NSLocalizedString(
@@ -795,7 +796,7 @@ func getRestartActionForUpdateList(_ update_list: [GenericItem]) -> String {
return ""
}
func getWarningText() -> String {
func getWarningText(_ filterAppleUpdates: Bool) -> String {
// Return localized text warning about forced installs and/or
// logouts and/or restarts
let item_list = getEffectiveUpdateList()
@@ -807,6 +808,11 @@ func getWarningText() -> String {
"One or more items must be installed by %@",
comment: "Forced Install Date summary")
warning_text = NSString(format: forced_date_text as NSString, date_str) as String
} else if !filterAppleUpdates && shouldAggressivelyNotifyAboutAppleUpdates() {
warning_text = NSLocalizedString(
"One or more important Apple updates must be installed",
comment: "Pending Apple Updates warning"
)
}
let restart_text = getRestartActionForUpdateList(item_list)
if !restart_text.isEmpty {
@@ -24,11 +24,17 @@ func is_safe_to_use(_ pathname: String) -> Bool {
return false
}
}
let fref = open(UnsafePointer(pathname), O_RDWR | O_CREAT | O_NOFOLLOW, 0x0600)
if fref != -1 {
var st = stat()
if fstat(fref, UnsafeMutablePointer<stat>(&st)) == 0 {
safe = ((st.st_mode & S_IFREG) != 0) && (st.st_uid == getuid())
pathname.withCString(){
let fref = open($0, O_RDWR | O_CREAT | O_NOFOLLOW, 0x0600)
if fref != 1 {
var st = stat()
var fstat_result : Int32 = 0
withUnsafeMutablePointer(to: &st){
fstat_result = fstat(fref, $0)
}
if fstat_result == 0 {
safe = ((st.st_mode & S_IFREG) != 0) && (st.st_uid == getuid())
}
}
close(fref)
}
@@ -6,6 +6,7 @@
// Copyright © 2018-2020 The Munki Project. All rights reserved.
//
import AppKit
import Foundation
import SystemConfiguration
import IOKit
@@ -17,7 +18,7 @@ let UPDATECHECKLAUNCHFILE = "/private/tmp/.com.googlecode.munki.updatecheck.laun
let INSTALLWITHOUTLOGOUTFILE = "/private/tmp/.com.googlecode.munki.managedinstall.launchd"
let BUNDLE_ID = "ManagedInstalls" as CFString
let DEFAULT_GUI_CACHE_AGE_SECS = 600
let DEFAULT_GUI_CACHE_AGE_SECS = 3600
let WRITEABLE_SELF_SERVICE_MANIFEST_PATH = "/Users/Shared/.SelfServeManifest"
func exec(_ command: String, args: [String] = []) -> String {
@@ -207,7 +208,7 @@ func getInstallInfo() -> PlistDict {
return readPlistAsNSDictionary(installinfo_path)
}
func getAppleUpdates() -> PlistDict {
func getAppleUpdates() -> [PlistDict] {
// Returns any available Apple update info
let installAppleSoftwareUpdates = pythonishBool(pref("InstallAppleSoftwareUpdates"))
let appleSoftwareUpdatesOnly = pythonishBool(pref("AppleSoftwareUpdatesOnly"))
@@ -215,12 +216,36 @@ func getAppleUpdates() -> PlistDict {
let managedinstallbase = pref("ManagedInstallDir") as! String
let appleupdates_path = NSString.path(
withComponents: [managedinstallbase, "AppleUpdates.plist"])
return readPlistAsNSDictionary(appleupdates_path)
let plistData = readPlistAsNSDictionary(appleupdates_path)
let rawAppleUpdates = plistData["AppleUpdates"] as? [PlistDict] ?? []
if pythonishBool(plistData["AppleUpdatesTesting"]) {
// this lets us test MSC behavior with fake data
return rawAppleUpdates
}
// since it's possible SoftwareUpdate has run since managedsoftwareupdate last
// ran, we should filter these against the RecommendedUpdates in com.apple.SoftwareUpdate
var filteredAppleUpdates = [PlistDict]()
for item in rawAppleUpdates {
if let productKey = item["productKey"] as? String {
if suRecommendedUpdateIDs().contains(productKey) {
filteredAppleUpdates.append(item)
}
}
}
return filteredAppleUpdates
} else {
return PlistDict()
return [PlistDict]()
}
}
func getUpdateNotificationTracking() -> PlistDict {
// Returns a dictionary describing when items were first made available
let managedinstallbase = pref("ManagedInstallDir") as! String
let updatetracking_path = NSString.path(
withComponents: [managedinstallbase, "UpdateNotificationTracking.plist"])
return readPlistAsNSDictionary(updatetracking_path)
}
func munkiUpdatesContainAppleItems() -> Bool {
// Return true if there are any Apple items in the list of updates
let installinfo = getInstallInfo()
@@ -251,9 +276,7 @@ func thereAreUpdatesToBeForcedSoon(hours: Int = 72) -> Bool {
// Return True if any updates need to be installed within the next
// X hours, false otherwise
var installinfo = getInstallInfo()["managed_installs"] as? [PlistDict] ?? [PlistDict]()
let appleupdates = getAppleUpdates()["AppleUpdates"] as? [PlistDict] ?? [PlistDict]()
installinfo = installinfo + appleupdates
installinfo = installinfo + getAppleUpdates()
let now_xhours = Date(timeIntervalSinceNow: TimeInterval(hours * 3600))
for item in installinfo {
if var force_install_after_date = item["force_install_after_date"] as? Date {
@@ -273,8 +296,7 @@ func earliestForceInstallDate(_ installinfo: [PlistDict]? = nil) -> Date? {
var earliest_date: Date? = nil
if installinfo == nil {
let managed_installs = getInstallInfo()["managed_installs"] as? [PlistDict] ?? [PlistDict]()
let appleupdates = getAppleUpdates()["AppleUpdates"] as? [PlistDict] ?? [PlistDict]()
installinfo = managed_installs + appleupdates
installinfo = managed_installs + getAppleUpdates()
}
for install in installinfo! {
if var this_force_install_date = install["force_install_after_date"] as? Date {
@@ -375,8 +397,9 @@ func startUpdateCheck(_ suppress_apple_update_check: Bool = false) throws {
do {
try writePlist(plist, toFile: UPDATECHECKLAUNCHFILE)
} catch {
throw ProcessStartError.error(
description: "Could not create file \(UPDATECHECKLAUNCHFILE) -- \(error)")
let message = "Could not create file \(UPDATECHECKLAUNCHFILE) -- \(error)"
msc_log("MSC", "cant_write_file", msg: message)
throw ProcessStartError.error(description: message)
}
}
}
@@ -52,6 +52,9 @@
/* Other Users Blocking Apps Running title */
"Applications in use by others" = "Programmer som er i bruk av andre";
/* Pre Install Uninstall Upgrade Alert Title */
"Attention" = "Merk følgende";
/* Cancel button title/short action text */
"Cancel" = "Avbryt";
@@ -151,18 +154,24 @@
/* No help alert detail */
"Help isn't available for Managed Software Center." = "Hjelp er ikke tilgjengelig for Managed Software Center.";
/* Apple Software Updates Pending title */
"Important Apple Updates" = "Viktige Apple oppdateringer";
/* Sidebar Information label */
"Information" = "Informasjon";
/* Install action text */
"Install" = "Installer";
/* Install Required action text */
"Install Required" = "Installasjon påkrevd";
/* Install now button title */
"Install now" = "Installer nå";
/* Install Requested status text */
"Install requested" = "Installasjon forespurt";
/* Install Required action text */
"Install Required" = "Installasjon påkrevd";
/* Install Session Failed title */
"Install session failed" = "Installasjonen feilet";
@@ -187,6 +196,9 @@
/* Logout Required title */
"Logout Required" = "Utlogging påkrevd";
/* macOS update required text */
"macOS update required" = "macOS-oppdatering nødvendig";
/* Failed Preflight Check detail */
"Managed Software Center cannot check for updates now.\nTry again later. If this situation continues, contact your systems administrator." = "Managed Software Center kan ikke søke etter oppdateringer.\nPrøv igjen senere. Hvis problemet fortsetter, kontakt din systemadministrator.";
@@ -220,15 +232,15 @@
/* No Updates message */
"No pending updates" = "Ingen ventende oppdateringer";
/* Item Not Found title */
"Not Found" = "Ikke funnet";
/* Not Currently Available display text */
"Not currently available" = "Ikke tilgjengelig for øyeblikket";
/* Not Enough Disk Space display text */
"Not enough disk space" = "Ikke nok plass på disken";
/* Item Not Found title */
"Not Found" = "Ikke funnet";
/* Not Installed status text */
"Not installed" = "Ikke installert";
@@ -238,6 +250,9 @@
/* OK button title */
"OK" = "OK";
/* Pending Apple Updates warning */
"One or more important Apple updates must be installed" = "En eller flere viktige Apple oppdateringer må installeres";
/* Forced Install Date summary */
"One or more items must be installed by %@" = "Et eller flere objekter må installeres senest %@";
@@ -274,6 +289,9 @@
/* Preparing Removal status text */
"Preparing removal" = "Forbereder avinstallasjon";
/* managedsoftwareupdate message */
"Preparing to run macOS Installer..." = "Forbereder å kjøre macOS Installer...";
/* Problem Updates label */
"Problem updates" = "Problematiske oppdateringer";
@@ -322,6 +340,9 @@
/* Sidebar Size label */
"Size:" = "Størrelse:";
/* Skip Apple updates button title */
"Skip these updates" = "Hopp over";
/* Software label */
"Software" = "Programvare";
@@ -331,9 +352,15 @@
/* Restart Required alert detail */
"Software installed or removed requires a restart. You will have a chance to save open documents." = "Programvaren som er blitt installert eller fjernet krever en omstart. Du får muligheten til å lagre åpne dokumenter.";
/* Pre Install Uninstall Upgrade Alert Detail */
"Some conditions apply to this software. Please contact your administrator for more details" = "Noen betingelser gjelder for denne programvaren. Kontakt administratoren din for mer informasjon";
/* managedsoftwareupdate message */
"Starting Adobe installer..." = "Starter Adobe installer...";
/* managedsoftwareupdate message */
"Starting macOS upgrade..." = "Starter oppgradering av macOS...";
/* managedsoftwareupdate message */
"Starting..." = "Starter...";
@@ -343,6 +370,9 @@
/* System configuration problem alert title */
"System configuration problem" = "Problem med systemkonfigurasjon";
/* managedsoftwareupdate message */
"System will restart and begin upgrade of macOS." = "Systemet vil starte på nytt og begynne å oppgradere macOS.";
/* managedsoftwareupdate message */
"The software was successfully installed." = "Installasjon av programvaren er fullført.";
@@ -358,6 +388,12 @@
/* No Category Results primary text */
"There are no items in this category." = "Det finnes ingen objekter i kategorien.";
/* Apple Software Updates Pending detail */
"There are one or more pending Apple Software Updates that require a restart.\n\nYou must install these updates using Software Update in System Preferences." = "En eller flere ventende Apple-programvareoppdateringer krever en omstart.\n\nDu må installere disse fra Programvareoppdatering-valgpanelet i Systemvalg.";
/* Apple Software Updates Unable detail */
"There are one or more pending Apple Software Updates that require a restart.\n\nYour administrator has restricted installation of these updates. Contact your administrator for assistance." = "En eller flere ventende Apple-programvareoppdateringer krever en omstart.\n\nAdministratoren har blokkert installasjon av disse oppdateringene. Kontakt administratoren for å få hjelp.";
/* Other Users Logged In detail */
"There are other users logged into this computer.\nUpdating now could cause other users to lose their work.\n\nPlease try again later after the other users have logged out." = "Det er andre påloggede brukere på datamaskinen.\nHvis du oppdaterer nå, risikerer du at de mister deres ulagrede arbeid.\n\nPrøv igjen senere når de andre brukerne har logget ut.";
@@ -382,6 +418,9 @@
/* Forced Date warning */
"This item must be installed by %@" = "Dette objektet må installeres senest %@";
/* Pending days message */
"This update has been pending for %@ days." = "Denne oppdateringen har ventet i %@ dager.";
/* Password explanation */
"To allow this, enter your login password." = "For å tillate dette, må du skrive inn ditt påloggingspassord.";
@@ -398,7 +437,7 @@
"Try selecting another developer." = "Prøv å velge en annen utvikler.";
/* Sidebar Type label */
"Type:" = "Type:";
"Type" = "Type";
/* Unavailable status text */
"Unavailable" = "Ikke tilgjengelig";
@@ -412,9 +451,6 @@
/* Update All button title */
"Update All" = "Oppdater alle";
/* Update Required long action text */
"Update Required" = "Oppdatering påkrevd";
/* No comment provided by engineer. */
"Update available" = "Kan oppdateres";
@@ -427,6 +463,9 @@
/* Update Now button title */
"Update now" = "Oppdater nu";
/* Update Required long action text */
"Update Required" = "Oppdatering påkrevd";
/* Update Will Be Installed status text */
"Update will be installed" = "Oppdatering vil bli installert";
@@ -471,6 +510,3 @@
/* No Pending Updates primary text */
"Your software is up to date." = "Din programvare er oppdateret.";
/* macOS update required text */
"macOS update required" = "macOS-oppdatering nødvendig";
@@ -52,6 +52,9 @@
/* Other Users Blocking Apps Running title */
"Applications in use by others" = "Applicaties in gebruik door anderen";
/* Pre Install Uninstall Upgrade Alert Title */
"Attention" = "Attentie";
/* Cancel button title/short action text */
"Cancel" = "Annuleren";
@@ -151,18 +154,24 @@
/* No help alert detail */
"Help isn't available for Managed Software Center." = "Help is niet beschikbaar voor Managed Software Center.";
/* Apple Software Updates Pending title */
"Important Apple Updates" = "Belangrijke Apple Updates";
/* Sidebar Information label */
"Information" = "Informatie";
/* Install action text */
"Install" = "Installeer";
/* Install Required action text */
"Install Required" = "Installatie Benodigd";
/* Install now button title */
"Install now" = "Installeer nu";
/* Install Requested status text */
"Install requested" = "Installatie Verzocht";
/* Install Required action text */
"Install Required" = "Installatie Benodigd";
/* Install Session Failed title */
"Install session failed" = "Installatie-sessie niet succesvol";
@@ -187,6 +196,9 @@
/* Logout Required title */
"Logout Required" = "Uitloggen Benodigd";
/* macOS update required text */
"macOS update required" = "macOS update vereist";
/* Failed Preflight Check detail */
"Managed Software Center cannot check for updates now.\nTry again later. If this situation continues, contact your systems administrator." = "Managed Software Center kan geen updates checken.\nProbeer later nog eens. Als deze situatie niet verandert, neem contact op met uw systeembeheerder.";
@@ -220,15 +232,15 @@
/* No Updates message */
"No pending updates" = "Geen updates";
/* Item Not Found title */
"Not Found" = "Niet Gevonden";
/* Not Currently Available display text */
"Not currently available" = "Op dit moment niet beschikbaar";
/* Not Enough Disk Space display text */
"Not enough disk space" = "Onvoldoende ruimte op de harde schijf";
/* Item Not Found title */
"Not Found" = "Niet Gevonden";
/* Not Installed status text */
"Not installed" = "Niet geïnstalleerd";
@@ -238,6 +250,9 @@
/* OK button title */
"OK" = "OK";
/* Pending Apple Updates warning */
"One or more important Apple updates must be installed" = "Een of meerdere belangrijke Apple updates dienen geïnstalleerd worden";
/* Forced Install Date summary */
"One or more items must be installed by %@" = "Eén of meer items moeten voor %@ worden geïnstalleerd";
@@ -274,6 +289,9 @@
/* Preparing Removal status text */
"Preparing removal" = "Verwijderen voorbereiden";
/* managedsoftwareupdate message */
"Preparing to run macOS Installer..." = "macOS installatie voorbereiden...";
/* Problem Updates label */
"Problem updates" = "Problematische updates";
@@ -322,6 +340,9 @@
/* Sidebar Size label */
"Size:" = "Grootte:";
/* Skip Apple updates button title */
"Skip these updates" = "Sla Apple updates over";
/* Software label */
"Software" = "Software";
@@ -331,9 +352,15 @@
/* Restart Required alert detail */
"Software installed or removed requires a restart. You will have a chance to save open documents." = "Geïnstalleerde of verwijderde software maakt een herstart nodig. U krijgt de kans om geopende documenten op te slaan.";
/* Pre Install Uninstall Upgrade Alert Detail */
"Some conditions apply to this software. Please contact your administrator for more details" = "Op deze software zijn enkele voorwaarden van toepassing. Neem contact op met uw beheerder voor meer informatie";
/* managedsoftwareupdate message */
"Starting Adobe installer..." = "Adobe installer opstarten...";
/* managedsoftwareupdate message */
"Starting macOS upgrade..." = "Starten met de macOS upgrade...";
/* managedsoftwareupdate message */
"Starting..." = "Beginnen...";
@@ -343,6 +370,9 @@
/* System configuration problem alert title */
"System configuration problem" = "Probleem met de systeemconfiguratie";
/* managedsoftwareupdate message */
"System will restart and begin upgrade of macOS." = "De Mac zal opnieuw opstarten en de upgrade van macOS starten.";
/* managedsoftwareupdate message */
"The software was successfully installed." = "De software is succesvol geïnstalleerd.";
@@ -358,6 +388,12 @@
/* No Category Results primary text */
"There are no items in this category." = "Er zijn geen items in deze categorie.";
/* Apple Software Updates Pending detail */
"There are one or more pending Apple Software Updates that require a restart.\n\nYou must install these updates using Software Update in System Preferences." = "Er zijn een of meerdere Apple Software Updates die een herstart nodig hebben.\n\nInstalleer deze updates door gebruik te maken Software-update in Systeemvoorkeuren.";
/* Apple Software Updates Unable detail */
"There are one or more pending Apple Software Updates that require a restart.\n\nYour administrator has restricted installation of these updates. Contact your administrator for assistance." = "Er zijn een of meerdere Apple Software Updates die een herstart nodig hebben.\n\nDe beheerder van deze machine staat de installatie van deze updates niet toe. Neem contact op met de beheerder voor assistentie.";
/* Other Users Logged In detail */
"There are other users logged into this computer.\nUpdating now could cause other users to lose their work.\n\nPlease try again later after the other users have logged out." = "Er zijn andere gebruikers ingelogd op deze computer.\nAls U nu bijwerkt kunnen de andere gebruikers hun werk verliezen.\n\nProbeer opnieuw nadat de andere gebruikers zijn uitgelogd.";
@@ -382,6 +418,9 @@
/* Forced Date warning */
"This item must be installed by %@" = "Dit item moet geïnstalleerd zijn voor %@";
/* Pending days message */
"This update has been pending for %@ days." = "Deze update wacht al %@ dagen.";
/* Password explanation */
"To allow this, enter your login password." = "Om dit toe te staan, vul je loginwachtwoord in.";
@@ -398,7 +437,7 @@
"Try selecting another developer." = "Selecteer een andere ontwikkelaar.";
/* Sidebar Type label */
"Type:" = "Type:";
"Type" = "Type";
/* Unavailable status text */
"Unavailable" = "Niet beschikbaar";
@@ -412,9 +451,6 @@
/* Update All button title */
"Update All" = "Update Alles";
/* Update Required long action text */
"Update Required" = "Update benodigd";
/* No comment provided by engineer. */
"Update available" = "Update beschikbaar";
@@ -427,6 +463,9 @@
/* Update Now button title */
"Update now" = "Update nu";
/* Update Required long action text */
"Update Required" = "Update benodigd";
/* Update Will Be Installed status text */
"Update will be installed" = "Update wordt geïnstalleerd";
@@ -471,6 +510,3 @@
/* No Pending Updates primary text */
"Your software is up to date." = "Uw software is up to date.";
/* macOS update required text */
"macOS update required" = "macOS update vereist";
@@ -52,6 +52,9 @@
/* Other Users Blocking Apps Running title */
"Applications in use by others" = "Приложения, которые используются другими";
/* Pre Install Uninstall Upgrade Alert Title */
"Attention" = "Внимание";
/* Cancel button title/short action text */
"Cancel" = "Отменить";
@@ -151,18 +154,24 @@
/* No help alert detail */
"Help isn't available for Managed Software Center." = "Помощь недоступна для Центра Управления ПО.";
/* Apple Software Updates Pending title */
"Important Apple Updates" = "Важные обновления Apple";
/* Sidebar Information label */
"Information" = "Информация";
/* Install action text */
"Install" = "Установить";
/* Install Required action text */
"Install Required" = "Установить Обязательные";
/* Install now button title */
"Install now" = "Установить сейчас";
/* Install Requested status text */
"Install requested" = "Установить Требуемые";
/* Install Required action text */
"Install Required" = "Установить Обязательные";
/* Install Session Failed title */
"Install session failed" = "Сбой процесса установки";
@@ -187,6 +196,9 @@
/* Logout Required title */
"Logout Required" = "Необходимо выйти из системы";
/* macOS update required text */
"macOS update required" = "требуется обновление macOS";
/* Failed Preflight Check detail */
"Managed Software Center cannot check for updates now.\nTry again later. If this situation continues, contact your systems administrator." = "Центр Управления ПО не может проверить наличие обновлений в данный момент.\nПопробуйте еще раз позже. Если эта ситуация продолжится, обратитесь к системному администратору.";
@@ -220,15 +232,15 @@
/* No Updates message */
"No pending updates" = "Нет отложенных обновлений";
/* Item Not Found title */
"Not Found" = "Не найдено";
/* Not Currently Available display text */
"Not currently available" = "В настоящее время не доступно";
/* Not Enough Disk Space display text */
"Not enough disk space" = "Недостаточно места на диске";
/* Item Not Found title */
"Not Found" = "Не найдено";
/* Not Installed status text */
"Not installed" = "Не установлено";
@@ -238,6 +250,9 @@
/* OK button title */
"OK" = "OK";
/* Pending Apple Updates warning */
"One or more important Apple updates must be installed" = "Необходимо установить одно или более обновлений Apple";
/* Forced Install Date summary */
"One or more items must be installed by %@" = "Один или несколько элементов должны быть установлены до %@";
@@ -274,6 +289,9 @@
/* Preparing Removal status text */
"Preparing removal" = "Подготовка удаления";
/* managedsoftwareupdate message */
"Preparing to run macOS Installer..." = "Подготовка к запуску Установщика macOS...";
/* Problem Updates label */
"Problem updates" = "проблемные обновления";
@@ -322,6 +340,9 @@
/* Sidebar Size label */
"Size:" = "Размер:";
/* Skip Apple updates button title */
"Skip these updates" = "Пропустить эти обновления";
/* Software label */
"Software" = "Программы";
@@ -331,9 +352,15 @@
/* Restart Required alert detail */
"Software installed or removed requires a restart. You will have a chance to save open documents." = "Установленное или удаленное ПО требует перезагрузки. У Вас будет возможность сохранить открытые документы.";
/* Pre Install Uninstall Upgrade Alert Detail */
"Some conditions apply to this software. Please contact your administrator for more details" = "К этому ПО применяются некоторые условия. Обратитесь к администратору системы за подробной информацией";
/* managedsoftwareupdate message */
"Starting Adobe installer..." = "Запуск Adobe installer...";
/* managedsoftwareupdate message */
"Starting macOS upgrade..." = "Начало обновления macOS...";
/* managedsoftwareupdate message */
"Starting..." = "Запуск...";
@@ -343,6 +370,9 @@
/* System configuration problem alert title */
"System configuration problem" = "Проблема с конфигурацией системы";
/* managedsoftwareupdate message */
"System will restart and begin upgrade of macOS." = "Система перезагрузится, и начнётся обновление macOS";
/* managedsoftwareupdate message */
"The software was successfully installed." = "Программное обеспечение было успешно установлено.";
@@ -358,6 +388,12 @@
/* No Category Results primary text */
"There are no items in this category." = "Нет элементов в этой категории.";
/* Apple Software Updates Pending detail */
"There are one or more pending Apple Software Updates that require a restart.\n\nYou must install these updates using Software Update in System Preferences." = "Одно или более обновлений ПО Apple требуют перезагрузки.\n\nВам необходимо установить их через раздел «Обновление ПО» в Системных настройках.";
/* Apple Software Updates Unable detail */
"There are one or more pending Apple Software Updates that require a restart.\n\nYour administrator has restricted installation of these updates. Contact your administrator for assistance." = "Одно или более обновлений ПО Apple требуют перезагрузки.\n\nАдминистратор запретил установку этих обновлений. Обратитесь за помощью к администратору.";
/* Other Users Logged In detail */
"There are other users logged into this computer.\nUpdating now could cause other users to lose their work.\n\nPlease try again later after the other users have logged out." = "Другие пользователи сейчас в системе.\nОбновление может привести к потере их несохраненных документов.\n\nПовторите попытку после выхода других пользователей из системы.";
@@ -382,6 +418,9 @@
/* Forced Date warning */
"This item must be installed by %@" = "Этот элемент должен быть установлен до %@";
/* Pending days message */
"This update has been pending for %@ days." = "Это обновление доступно в течение %@ дн.";
/* Password explanation */
"To allow this, enter your login password." = "Для разрешения введите свой пароль для входа в систему.";
@@ -398,7 +437,7 @@
"Try selecting another developer." = "Попробуйте выбрать другой разработчика.";
/* Sidebar Type label */
"Type:" = "Тип:";
"Type" = "Тип";
/* Unavailable status text */
"Unavailable" = "Недоступно";
@@ -412,9 +451,6 @@
/* Update All button title */
"Update All" = "Обновить Все";
/* Update Required long action text */
"Update Required" = "Обновить Обязательное";
/* No comment provided by engineer. */
"Update available" = "Доступно обновление";
@@ -427,6 +463,9 @@
/* Update Now button title */
"Update now" = "Обновить сейчас";
/* Update Required long action text */
"Update Required" = "Обновить Обязательное";
/* Update Will Be Installed status text */
"Update will be installed" = "Обновление будет установлено";
@@ -471,6 +510,3 @@
/* No Pending Updates primary text */
"Your software is up to date." = "У Вас самое новое ПО.";
/* macOS update required text */
"macOS update required" = "требуется обновление macOS";
@@ -44,14 +44,17 @@
"An installation attempt failed. Installation will be attempted again.\nIf this situation continues, contact your systems administrator." = "Installationen misslyckades. Ytterligare installationsförsök kommer att göras.\nKontakta din datoradministratör om problemet återkommer.";
/* Long Not Enough Disk Space For Update display text */
"An older version is currently installed. There is not enough disk space to download and install this update." = "An older version is currently installed. There is not enough disk space to download and install this update.";
"An older version is currently installed. There is not enough disk space to download and install this update." = "En äldre version är installerad. Det finns inte tillräckligt med utrymme för att ladda ner och installera uppdateringen.";
/* Long update requires a higher OS version text */
"An older version is currently installed. You must upgrade to macOS version %@ or higher to be able to install this update." = "An older version is currently installed. You must upgrade to macOS version %@ or higher to be able to install this update.";
"An older version is currently installed. You must upgrade to macOS version %@ or higher to be able to install this update." = "En äldre version är installerad. Du behöver uppgradera till macOS version %@ eller nyare för att kunna installera uppdateringen.";
/* Other Users Blocking Apps Running title */
"Applications in use by others" = "Andra användare på datorn har programmet öppet";
/* Pre Install Uninstall Upgrade Alert Title */
"Attention" = "Observera";
/* Cancel button title/short action text */
"Cancel" = "Avbryt";
@@ -151,18 +154,24 @@
/* No help alert detail */
"Help isn't available for Managed Software Center." = "Det finns ingen hjälp för Managed Software Center.";
/* Apple Software Updates Pending title */
"Important Apple Updates" = "Viktiga Apple-uppdateringar";
/* Sidebar Information label */
"Information" = "Information";
/* Install action text */
"Install" = "Installera";
/* Install Required action text */
"Install Required" = "Installation krävs";
/* Install now button title */
"Install now" = "Installera nu";
/* Install Requested status text */
"Install requested" = "Installation begärd";
/* Install Required action text */
"Install Required" = "Installation krävs";
/* Install Session Failed title */
"Install session failed" = "Installationen misslyckades";
@@ -187,6 +196,9 @@
/* Logout Required title */
"Logout Required" = "Utloggning krävs";
/* macOS update required text */
"macOS update required" = "macOS-uppdatering krävs";
/* Failed Preflight Check detail */
"Managed Software Center cannot check for updates now.\nTry again later. If this situation continues, contact your systems administrator." = "Managed Software Center kan inte leta efter uppdateringar nu.\nFörsök igen senare. Kontakta din datoradministratör om problemet återkommer.";
@@ -220,15 +232,15 @@
/* No Updates message */
"No pending updates" = "Inga uppdateringar väntar.";
/* Item Not Found title */
"Not Found" = "Kunde inte hittas";
/* Not Currently Available display text */
"Not currently available" = "Inte tillgänglig just nu";
/* Not Enough Disk Space display text */
"Not enough disk space" = "Inte tillräckligt med utrymme på skivan";
/* Item Not Found title */
"Not Found" = "Kunde inte hittas";
/* Not Installed status text */
"Not installed" = "Ej installerat";
@@ -238,6 +250,9 @@
/* OK button title */
"OK" = "OK";
/* Pending Apple Updates warning */
"One or more important Apple updates must be installed" = "En eller flera viktiga Apple-uppdateringar måste installeras";
/* Forced Install Date summary */
"One or more items must be installed by %@" = "Ett eller flera objekt måste installeras senast %@";
@@ -274,8 +289,11 @@
/* Preparing Removal status text */
"Preparing removal" = "Förbereder borttagning";
/* managedsoftwareupdate message */
"Preparing to run macOS Installer..." = "Förbereder installation av macOS...";
/* Problem Updates label */
"Problem updates" = "Problem updates";
"Problem updates" = "Problemuppdateringar";
/* Quit button title */
"Quit" = "Avsluta";
@@ -296,7 +314,7 @@
"Removing receipt info" = "Tar bort kvittot";
/* Install Required action text */
"Required" = "Required";
"Required" = "Krävs";
/* Restart button title */
"Restart" = "Omstart";
@@ -322,6 +340,9 @@
/* Sidebar Size label */
"Size:" = "Storlek:";
/* Skip Apple updates button title */
"Skip these updates" = "Hoppa över";
/* Software label */
"Software" = "Programvara";
@@ -331,9 +352,15 @@
/* Restart Required alert detail */
"Software installed or removed requires a restart. You will have a chance to save open documents." = "Program som lades till eller togs bort kräver en omstart. Du kommer att få möjlighet att spara ditt arbete.";
/* Pre Install Uninstall Upgrade Alert Detail */
"Some conditions apply to this software. Please contact your administrator for more details" = "Vissa villkor gäller för den här mjukvaran. Kontakta din administratör för mer information.";
/* managedsoftwareupdate message */
"Starting Adobe installer..." = "Startar Adobe installer...";
/* managedsoftwareupdate message */
"Starting macOS upgrade..." = "Startar uppgradering av macOS...";
/* managedsoftwareupdate message */
"Starting..." = "Startar...";
@@ -343,6 +370,9 @@
/* System configuration problem alert title */
"System configuration problem" = "Problem med systemkonfiguration";
/* managedsoftwareupdate message */
"System will restart and begin upgrade of macOS." = "Systemet kommer att starta om och påbörja uppgraderingen av macOS";
/* managedsoftwareupdate message */
"The software was successfully installed." = "Programvaran installerades.";
@@ -358,6 +388,12 @@
/* No Category Results primary text */
"There are no items in this category." = "Det finns inget i den här kategorin.";
/* Apple Software Updates Pending detail */
"There are one or more pending Apple Software Updates that require a restart.\n\nYou must install these updates using Software Update in System Preferences." = "Det finns en eller flera väntande Apple-uppdateringar som kräver att datorn startas om.\n\nDu måste installera uppdateringarna med inställningspanelen Programuppdatering i Systeminställningar.";
/* Apple Software Updates Unable detail */
"There are one or more pending Apple Software Updates that require a restart.\n\nYour administrator has restricted installation of these updates. Contact your administrator for assistance." = "Det finns en eller flera väntande Apple-uppdateringar som kräver att datorn startas om.\n\nAdminstratören har begränsat möjligheten att installera uppdateringar. Kontakta din adminstratör för hjälp.";
/* Other Users Logged In detail */
"There are other users logged into this computer.\nUpdating now could cause other users to lose their work.\n\nPlease try again later after the other users have logged out." = "Det finns andra användare inloggade på datorn.\nOm du uppdaterar nu riskerar dom att förlora ej sparat arbete.\n\nProva igen när de andra användarna har loggat ut.";
@@ -374,7 +410,7 @@
"There is no new software for your computer at this time." = "Det finns inga uppdateringar för närvarande.";
/* Long Not Enough Disk Space display text */
"There is not enough disk space to download and install this item." = "There is not enough disk space to download and install this item.";
"There is not enough disk space to download and install this item." = "Det finns inte tillräckligt med utrymme för att ladda ner och installera.";
/* Dependency List prologue text */
"This item is required by:" = "Krävs av:";
@@ -382,6 +418,9 @@
/* Forced Date warning */
"This item must be installed by %@" = "Måste installeras senast %@";
/* Pending days message */
"This update has been pending for %@ days." = "Den här uppdateringen har väntat i %@ dagar.";
/* Password explanation */
"To allow this, enter your login password." = "Ange ditt inloggningslösenord för att tillåta detta.";
@@ -398,7 +437,7 @@
"Try selecting another developer." = "Försök med en annan utvecklare.";
/* Sidebar Type label */
"Type:" = "Typ:";
"Type" = "Typ";
/* Unavailable status text */
"Unavailable" = "Ej tillgänglig";
@@ -412,9 +451,6 @@
/* Update All button title */
"Update All" = "Uppdatera alla";
/* Update Required long action text */
"Update Required" = "Uppdatering krävs";
/* No comment provided by engineer. */
"Update available" = "Uppdatering tillgänglig";
@@ -427,6 +463,9 @@
/* Update Now button title */
"Update now" = "Uppdatera nu";
/* Update Required long action text */
"Update Required" = "Uppdatering krävs";
/* Update Will Be Installed status text */
"Update will be installed" = "Uppdateringen kommer att installeras";
@@ -461,7 +500,7 @@
"You must quit the following applications before proceeding with installation or removal:\n\n%@" = "Du måste avsluta följande program innan installationen eller avinstallationen kan fortsätta:\n\n%@";
/* Long item requires a higher OS version text */
"You must upgrade to macOS version %@ to be able to install this item." = "You must upgrade to macOS version %@ to be able to install this item.";
"You must upgrade to macOS version %@ to be able to install this item." = "Du behöver uppgradera till macOS version %@ för att kunna installera.";
/* No Power Source Warning text */
"Your computer is not connected to a power source." = "Datorn är inte ansluten till en strömkälla.";
@@ -471,6 +510,3 @@
/* No Pending Updates primary text */
"Your software is up to date." = "Programvaran är uppdaterad.";
/* macOS update required text */
"macOS update required" = "macOS update required";
@@ -152,7 +152,7 @@
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0920;
LastUpgradeCheck = 1020;
LastUpgradeCheck = 1140;
ORGANIZATIONNAME = "The Munki Project";
TargetAttributes = {
C0544D4720AF0EDA00DC86F6 = {
@@ -12,7 +12,7 @@
NSString * const ManagedSoftwareCenterBundleID = @"com.googlecode.munki.ManagedSoftwareCenter";
NSString * const NotificationCenterUIBundleID = @"com.apple.notificationcenterui";
NSString * const MunkiUpdatesURL = @"munki://updates";
NSString * const MunkiNotificationURL = @"munki://notify";
long const DefaultUseNotificationCenterDays = 3;
@@ -132,7 +132,7 @@ InstallFakeBundleIdentifierHook()
// to launch MSC.app
[[NSUserNotificationCenter defaultUserNotificationCenter] removeAllDeliveredNotifications];
}
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString: MunkiUpdatesURL]];
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString: MunkiNotificationURL]];
[NSApp terminate: self];
return;
}
@@ -169,7 +169,7 @@ InstallFakeBundleIdentifierHook()
// Create options (userInfo) dictionary
NSMutableDictionary *options = [NSMutableDictionary dictionary];
options[@"action"] = @"open_url";
options[@"value"] = MunkiUpdatesURL;
options[@"value"] = MunkiNotificationURL;
// deliver the notification
[self deliverNotificationWithTitle:title
@@ -239,7 +239,7 @@ InstallFakeBundleIdentifierHook()
if ([action isEqualToString:@"open_url"]){
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:value]];
} else {
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString: MunkiUpdatesURL]];
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString: MunkiNotificationURL]];
}
[NSApp terminate: self];
+2
View File
@@ -95,6 +95,8 @@ class AppUsageClient(object):
try:
self.connect()
result = self.send_request(request)
except AppUsageClientError as err:
return "ERROR:%s" % err
finally:
self.disconnect()
return result
+21 -10
View File
@@ -50,6 +50,13 @@ APPNAME = 'appusaged'
VERSION = '0.1'
def print_error_and_exit(errmsg):
'''Prints an error message to stderr, sleeps, and exits'''
print(errmsg, file=sys.stderr)
time.sleep(10)
return 1
class AppUsageHandlerError(Exception):
'''Exception to raise if there is any error in AppUsageHandler'''
pass
@@ -161,7 +168,14 @@ class RunHandler(SocketServer.StreamRequestHandler):
self.log.debug('Handling request')
# Get uid and primary gid of connecting peer.
uid, gids = self.getpeerid()
try:
uid, gids = self.getpeerid()
except OSError as err:
self.log.error(u'Peerid failure: %s' % unicode_or_str(err))
self.request.send(
(u'ERROR:Internal peerid error\n').encode('UTF-8'))
return
gid = gids[0]
self.log.debug(
'Got request from uid %d gid %d' % (uid, gid))
@@ -206,7 +220,6 @@ class RunHandler(SocketServer.StreamRequestHandler):
self.log.error(u'Caught exception: %s' % repr(err))
self.request.send(
(u'ERROR:Caught exception: %s' % repr(err)).encode('UTF-8'))
return
class AppUsageDaemonError(Exception):
'''Exception to raise for AppUsageDaemon errors'''
@@ -274,10 +287,7 @@ def main():
'''Start our daemon, connect to socket and process events'''
# Make sure we're launched as root
if os.geteuid() != 0:
print('%s must be run as root.' % APPNAME, file=sys.stderr)
# Sleep to avoid respawn.
time.sleep(10)
return 1
print_error_and_exit('%s must be run as root.' % APPNAME)
# Make sure that the executable and all containing directories are owned
# by root:wheel or root:admin, and not writeable by other users.
@@ -314,13 +324,14 @@ def main():
# Get socket file descriptors from launchd.
socket_fd = launchd.get_socket_fd(APPNAME.encode('UTF-8'))
if not socket_fd:
print('No socket provided to us by launchd', file=sys.stderr)
time.sleep(10)
return 1
print_error_and_exit('No socket provided to us by launchd')
# Create the daemon object.
daemon = AppUsageDaemon(socket_fd, RunHandler)
daemon.setup_logging()
try:
daemon.setup_logging()
except AppUsageDaemonError as err:
print_error_and_exit('%s' % err)
daemon.log.debug('%s v%s starting', APPNAME, VERSION)
+18
View File
@@ -101,6 +101,24 @@ class FDEUtil(object):
self.log.info('Restart request denied')
raise FDEUtilError('Restart may only be triggered by root')
if self.request['task'] == 'delayed_authrestart':
# set up a delayed authrestart. Defaults to waiting indefinitely,
# so the next "normal" restart becomes an authrestart.
self.log.info('Delayed restart request from uid %s', self.uid)
if self.uid == 0:
self.log.info('Stored username for authrestart: %s',
self.server.stored_username)
delayminutes = self.request.get('delayminutes', -1)
authrestart.perform_auth_restart(
password=self.server.stored_password,
username=self.server.stored_username,
delayminutes=delayminutes)
return 'DONE'
else:
self.log.info('Delayed restart request denied')
raise FDEUtilError(
'Delayed restart may only be triggered by root')
if self.request['task'] == 'store_password':
# store a password for later fdesetup authrestart
self.log.info('Store password request')
+64 -13
View File
@@ -273,7 +273,9 @@ def doInstallTasks(do_apple_updates, only_unattended=False):
'Restart not initiated by startosinstall; will initiate '
'restart ourselves')
if not authrestartd.restart():
authrestart.do_authorized_or_normal_restart()
authrestart.do_authorized_or_normal_restart(
shutdown=osutils.bridgeos_update_staged()
)
if do_apple_updates:
# install Apple updates
@@ -408,7 +410,6 @@ def munkiUpdatesContainStartOSInstallItem():
return False
def munkiUpdatesContainAppleItems():
"""Return True if there are any Apple items in the list of updates"""
install_info = os.path.join(
@@ -711,11 +712,13 @@ def main():
# triggered the update before logging out, or we triggered it before
# restarting.
user_triggered = False
flagfiles = [constants.CHECKANDINSTALLATSTARTUPFLAG,
flagfiles = (constants.CHECKANDINSTALLATSTARTUPFLAG,
constants.INSTALLATSTARTUPFLAG,
constants.INSTALLATLOGOUTFLAG]
constants.INSTALLATLOGOUTFLAG)
for filename in flagfiles:
if os.path.exists(filename):
munkilog.log(
"managedsoftwareupdate run triggered by %s" % filename)
user_triggered = True
if filename == constants.CHECKANDINSTALLATSTARTUPFLAG:
runtype = 'checkandinstallatstartup'
@@ -729,9 +732,32 @@ def main():
if networkUp():
break
time.sleep(1)
else:
# delete triggerfile if _not_ checkandinstallatstartup
os.unlink(filename)
break
elif filename == constants.INSTALLATSTARTUPFLAG:
runtype = 'installatstartup'
# check to see if we should do some special handling;
# we might have installed Apple updates right before a
# restart
try:
launch_options = FoundationPlist.readPlist(filename)
if launch_options.get("SkipAppleUpdates"):
munkilog.log("SkipAppleUpdates is True")
appleupdates.clearAppleUpdateInfo()
options.munkipkgsonly = True
except FoundationPlist.FoundationPlistException as err:
pass
break
# delete any triggerfile that isn't checkandinstallatstartup
# so it's not hanging around at the next logout or restart
for triggerfile in (constants.INSTALLATSTARTUPFLAG,
constants.INSTALLATLOGOUTFLAG):
if os.path.exists(triggerfile):
try:
os.unlink(triggerfile)
except (OSError, IOError):
pass
if not user_triggered:
# no trigger file was found -- how'd we get launched?
osutils.cleanUpTmpDir()
@@ -743,6 +769,10 @@ def main():
launchdtriggerfile = \
'/private/tmp/.com.googlecode.munki.managedinstall.launchd'
if os.path.exists(launchdtriggerfile):
munkilog.log(
"managedsoftwareupdate run triggered by %s"
% launchdtriggerfile
)
# remove it so we aren't automatically relaunched
os.unlink(launchdtriggerfile)
runtype = 'installwithnologout'
@@ -756,6 +786,10 @@ def main():
launchdtriggerfile = \
'/private/tmp/.com.googlecode.munki.updatecheck.launchd'
if os.path.exists(launchdtriggerfile):
munkilog.log(
"managedsoftwareupdate run triggered by %s"
% launchdtriggerfile
)
try:
launch_options = FoundationPlist.readPlist(launchdtriggerfile)
options.munkipkgsonly = launch_options.get(
@@ -890,12 +924,7 @@ def main():
# we need to delete AppleUpdates.plist so that other code doesn't
# mistakenly alert for forced installs it isn't actually going to
# install.
appleupdates_plist = os.path.join(
prefs.pref('ManagedInstallDir'), 'AppleUpdates.plist')
try:
os.unlink(appleupdates_plist)
except OSError:
pass
appleupdates.clearAppleUpdateInfo()
else:
# check the normal preferences
should_do_apple_updates = prefs.pref('InstallAppleSoftwareUpdates')
@@ -954,6 +983,28 @@ def main():
mustlogout = False
notify_user = False
force_action = None
if runtype == 'installatstartup':
# turn off options.installonly; we need options.auto behavior from here
# on out because if FileVault is active we may actually be logged in
# at this point!
options.installonly = False
options.auto = True
if runtype == 'checkandinstallatstartup':
# we're in bootstrap mode
if not updatesavailable and appleupdatesavailable:
# there are only Apple updates, but we might not be able to install
# some
if not appleupdates.installableUpdates():
# there are no Apple updates we can actually install without
# user assistance, so clear bootstrapping mode so we don't loop
# endlessly
try:
bootstrapping.clear_bootstrap_mode()
except bootstrapping.SetupError as err:
display.display_error(err)
if updatesavailable or appleupdatesavailable:
if options.installonly or options.logoutinstall:
# just install
+79 -33
View File
@@ -494,41 +494,52 @@ class AppleUpdates(object):
display.display_info(' *Logout required')
reports.report['LogoutRequired'] = True
def installable_updates(self):
"""Returns a list of installable Apple updates.
This may filter out updates that require a restart."""
try:
pl_dict = FoundationPlist.readPlist(self.apple_updates_plist)
except FoundationPlist.FoundationPlistException:
# can't read it or it doesn't exist, therefore no installable
# updates
return []
apple_updates = pl_dict.get('AppleUpdates', [])
os_version_tuple = osutils.getOsVersion(as_tuple=True)
if os_version_tuple >= (10, 14):
# in Mojave and Catalina (and perhaps beyond), it's too risky to
# install OS or Security updates because softwareupdate is just
# not reliable at this any longer. So filter out updates that
# require a restart
filtered_apple_updates = [
item for item in apple_updates
if item.get('RestartAction', 'None') == 'None'
]
return filtered_apple_updates
return apple_updates
def install_apple_updates(self, only_unattended=False):
"""Uses softwareupdate to install previously downloaded updates.
Returns:
Boolean. True if a restart is needed after install, False otherwise.
restart_action -- an integer indicating the action to take later:
none, logout, restart, shutdown
"""
# disable Stop button if we are presenting GUI status
if display.munkistatusoutput:
munkistatus.hideStopButton()
self.shutdown_instead_of_restart = False
# Get list of unattended_installs
if only_unattended:
msg = 'Installing unattended Apple Software Updates...'
unattended_install_items, unattended_install_product_ids = \
self.get_unattended_installs()
# ensure that we don't restart for unattended installations
restart_action = POSTACTION_NONE
if not unattended_install_items:
return False # didn't find any unattended installs
else:
msg = 'Installing available Apple Software Updates...'
restart_action = self.restart_action_for_updates()
display.display_status_major(msg)
os_version_tuple = osutils.getOsVersion(as_tuple=True)
installlist = self.software_update_info()
remaining_apple_updates = []
installresults = {'installed': [], 'download': []}
su_options = ['-i']
if only_unattended:
# Append list of unattended_install items
su_options.extend(unattended_install_items)
msg = 'Installing unattended Apple Software Updates...'
restart_action = POSTACTION_NONE
unattended_install_product_ids = self.get_unattended_installs()
# Filter installlist to only include items
# which we're attempting to install
filtered_installlist = [item for item in installlist
@@ -537,17 +548,51 @@ class AppleUpdates(object):
# record items we aren't planning to attempt to install
remaining_apple_updates = [item for item in installlist
if item not in filtered_installlist]
# set the list of items to install to our newly-filted list
installlist = filtered_installlist
elif os_version_tuple >= (10, 14):
msg = ('Installing Apple Software Updates that do not require '
'restart...')
restart_action = POSTACTION_NONE
# in Mojave and Catalina (and perhaps beyond), it's too risky to
# install OS or Security updates because softwareupdate is just
# not reliable at this any longer. So skip any updates that require
# a restart -- users will need to install these using Apple's GUI
# tools. We can still install other updates that don't require a
# restart (for now)
filtered_installlist = [
item for item in installlist
if item.get('RestartAction', 'None') == 'None'
]
# record items we aren't planning to attempt to install
remaining_apple_updates = [item for item in installlist
if item not in filtered_installlist]
for item in remaining_apple_updates:
display.display_debug1(
"Skipping install of %s-%s because it requires a restart.",
item['name'], item['version_to_install']
)
# set the list of items to install to our newly-filtered list
installlist = filtered_installlist
else:
# We're installing all available updates; add all their names
for item in installlist:
su_options.append(
item['name'] + '-' + item['version_to_install'])
msg = 'Installing available Apple Software Updates...'
restart_action = self.restart_action_for_updates()
if not installlist:
return POSTACTION_NONE # our list of items to install is empty
display.display_status_major(msg)
# Add the current (possibly filtered) installlist items to the
# softwareupdate install options
for item in installlist:
su_options.append(
item['name'] + '-' + item['version_to_install'])
# new in 10.11: '--no-scan' flag to tell softwareupdate to just install
# and not rescan for available updates.
os_version_tuple = osutils.getOsVersion(as_tuple=True)
if os_version_tuple >= (10, 11):
try:
# attempt to fetch the apple catalog to confirm connectivity
@@ -578,8 +623,10 @@ class AppleUpdates(object):
su_start_date = NSDate.new()
installresults = su_tool.run(su_options, catalog_url=catalog_url)
retcode = installresults.get('exit_code', 0)
self.shutdown_instead_of_restart = installresults.get(
'post_action') == POSTACTION_SHUTDOWN
self.shutdown_instead_of_restart = (
installresults.get('post_action') == POSTACTION_SHUTDOWN or
osutils.bridgeos_update_staged()
)
su_end_date = NSDate.new()
# get the items that were just installed from InstallHistory.plist
@@ -741,9 +788,12 @@ class AppleUpdates(object):
metadata_to_copy = ['blocking_applications',
'description',
'display_name',
'force_install_after_date',
'unattended_install',
'RestartAction']
# we support force_install_after_date only on macOS earlier than Mojave
os_version_tuple = osutils.getOsVersion(as_tuple=True)
if os_version_tuple < (10, 14):
metadata_to_copy.append('force_install_after_date')
# Mapping of supported restart_actions to
# equal or greater auxiliary actions
@@ -797,17 +847,15 @@ class AppleUpdates(object):
def get_unattended_installs(self):
"""Processes AppleUpdates.plist to return a list
of NAME-VERSION formatted items and a list of product_ids
which are eligible for unattended installation.
of product_ids which are eligible for unattended installation.
"""
item_list = []
product_ids = []
try:
pl_dict = FoundationPlist.readPlist(self.apple_updates_plist)
except FoundationPlist.FoundationPlistException:
display.display_error(
'Error reading: %s', self.apple_updates_plist)
return item_list, product_ids
return product_ids
apple_updates = pl_dict.get('AppleUpdates', [])
for item in apple_updates:
if (item.get('unattended_install') or
@@ -819,14 +867,12 @@ class AppleUpdates(object):
'blocking application(s) running.'
% item['display_name'])
continue
install_item = item['name'] + '-' + item['version_to_install']
item_list.append(install_item)
product_ids.append(item['productKey'])
else:
display.display_detail(
'Skipping install of %s because it\'s not unattended.'
% item['display_name'])
return item_list, product_ids
return product_ids
if __name__ == '__main__':
@@ -74,6 +74,12 @@ def appleSoftwareUpdatesAvailable(forcecheck=False, suppresscheck=False,
force_check=forcecheck, suppress_check=suppresscheck)
def installableUpdates():
"""Returns the list of installable updates, which might not include updates
that require a restart"""
return getAppleUpdatesInstance().installable_updates()
def displayAppleUpdateInfo():
"""Method for drop-in appleupdates replacement; see primary method docs."""
getAppleUpdatesInstance().display_apple_update_info()
+14 -5
View File
@@ -148,7 +148,7 @@ def can_attempt_auth_restart(have_password=False):
(get_auth_restart_key(quiet=True) != '' or have_password))
def perform_auth_restart(username=None, password=None):
def perform_auth_restart(username=None, password=None, delayminutes=0):
"""When called this will perform an authorized restart. Before trying
to perform an authorized restart it checks to see if the machine supports
the feature. If supported it will look for the defined plist containing
@@ -169,14 +169,23 @@ def perform_auth_restart(username=None, password=None):
if username:
keys['Username'] = username
inputplist = FoundationPlist.writePlistToString(keys)
display.display_info('Attempting an Authorized Restart now...')
if delayminutes == 0:
display.display_info('Attempting an Authorized Restart now...')
else:
display.display_info('Configuring a delayed Authorized Restart...')
os_version_tuple = osutils.getOsVersion(as_tuple=True)
if os_version_tuple >= (10, 12):
cmd = ['/usr/bin/fdesetup', 'authrestart',
'-delayminutes', str(delayminutes), '-inputplist']
else:
cmd = ['/usr/bin/fdesetup', 'authrestart', '-inputplist']
proc = subprocess.Popen(
['/usr/bin/fdesetup', 'authrestart', '-inputplist'],
cmd,
stdout=subprocess.PIPE,
stdin=subprocess.PIPE,
stderr=subprocess.PIPE)
stderr=subprocess.PIPE
)
err = proc.communicate(input=inputplist)[1].decode('UTF-8')
os_version_tuple = osutils.getOsVersion(as_tuple=True)
if os_version_tuple >= (10, 12) and 'System is being restarted' in err:
return True
if err:
@@ -27,6 +27,7 @@ import os
import select
import socket
from .. import prefs
from ..wrappers import writePlistToString
AUTHRESTARTD_SOCKET = "/var/run/authrestartd"
@@ -115,6 +116,13 @@ class AuthRestartClient(object):
if not result.startswith('OK'):
raise AuthRestartClientError(result)
def setup_delayed_authrestart(self, delayminutes=-1):
'''Sets up a delayed auth restart'''
request = {'task': 'delayed_authrestart', 'delayminutes': delayminutes}
result = self.process(request)
if not result.startswith('OK'):
raise AuthRestartClientError(result)
# Higher-level wrapper functions that swallow AuthRestartClientErrors
def fv_is_active():
@@ -172,15 +180,29 @@ def restart():
return False
def setup_delayed_authrestart():
'''Sets up a delayed authrestart.
Returns boolean to indicate success/failure'''
try:
AuthRestartClient().setup_delayed_authrestart()
return True
except AuthRestartClientError:
return False
def test():
'''A function for doing some basic testing'''
import getpass
import pwd
from ..wrappers import get_input
print('PerformAuthRestarts preference is: %s'
% prefs.pref('PerformAuthRestarts'))
print('FileVault is active: %s' % fv_is_active())
print('Recovery key is present: %s' % verify_recovery_key_present())
username = pwd.getpwuid(os.getuid()).pw_name
if username == 'root':
username = get_input('Enter name of FV-enabled user: ')
print('%s is FV user: %s' % (username, verify_user(username)))
password = getpass.getpass('Enter password: ')
if password:
@@ -191,6 +213,10 @@ def test():
else:
print('store_password failed')
print('Can attempt auth restart: %s' % verify_can_attempt_auth_restart())
answer = get_input('Test setup of delayed auth restart (y/n)? ')
if answer.lower().startswith('y'):
print('Successfully set up delayed authrestart: %s'
% setup_delayed_authrestart())
answer = get_input('Test auth restart (y/n)? ')
if answer.lower().startswith('y'):
print('Attempting auth restart...')
+3 -1
View File
@@ -177,7 +177,7 @@ def mount_points_for_disk_image(dmgpath):
def mountdmg(dmgpath, use_shadow=False, use_existing_mounts=False,
random_mountpoint=True):
random_mountpoint=True, skip_verification=False):
"""
Attempts to mount the dmg at dmgpath
and returns a list of mountpoints
@@ -205,6 +205,8 @@ def mountdmg(dmgpath, use_shadow=False, use_existing_mounts=False,
cmd.extend(['-mountRandom', '/tmp'])
if use_shadow:
cmd.append('-shadow')
if skip_verification:
cmd.append('-noverify')
proc = subprocess.Popen(cmd,
bufsize=-1, stdout=subprocess.PIPE,
stderr=subprocess.PIPE, stdin=subprocess.PIPE)
+3
View File
@@ -70,6 +70,9 @@ def convertIconToPNG(icon_path, destination_path,
try:
properties = CGImageSourceCopyPropertiesAtIndex(
image_source, index, None)
# perform not empty check for properties to prevent crash as CGImageSourceCopyPropertiesAtIndex sometimes fails in 10.15.4 and above
if not properties:
return False
dpi = int(properties.get(kCGImagePropertyDPIHeight, 0))
height = int(properties.get(kCGImagePropertyPixelHeight, 0))
if (not candidate or
+19 -7
View File
@@ -56,7 +56,7 @@ try:
_ = xrange # pylint: disable=xrange-builtin
except NameError:
# no xrange in Python 3
xrange = range
xrange = range # pylint: disable=redefined-builtin,invalid-name
# Always ignore these directories when discovering applications.
APP_DISCOVERY_EXCLUSION_DIRS = set([
@@ -548,9 +548,9 @@ def get_version():
return vers
def get_hardware_info():
'''Uses system profiler to get hardware info for this machine'''
cmd = ['/usr/sbin/system_profiler', 'SPHardwareDataType', '-xml']
def get_sp_data(data_type):
'''Uses system profiler to get info of data_type for this machine'''
cmd = ['/usr/sbin/system_profiler', data_type, '-xml']
proc = subprocess.Popen(cmd, shell=False, bufsize=-1,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
@@ -560,12 +560,22 @@ def get_hardware_info():
# system_profiler xml is an array
sp_dict = plist[0]
items = sp_dict['_items']
sp_hardware_dict = items[0]
return sp_hardware_dict
sp_items_dict = items[0]
return sp_items_dict
except BaseException:
return {}
def get_hardware_info():
'''Uses system profiler to get hardware info for this machine'''
return get_sp_data('SPHardwareDataType')
def get_ibridge_info():
'''Uses system profiler to get iBridge info for this machine'''
return get_sp_data('SPiBridgeDataType')
def get_ip_addresses(kind):
'''Uses system profiler to get active IP addresses for this machine
kind must be one of 'IPv4' or 'IPv6' '''
@@ -655,7 +665,9 @@ def getMachineFacts():
machine['ipv4_address'] = get_ip_addresses('IPv4')
machine['ipv6_address'] = get_ip_addresses('IPv6')
machine['serial_number'] = hardware_info.get('serial_number', 'UNKNOWN')
ibridge_info = get_ibridge_info()
machine['ibridge_model_name'] = ibridge_info.get(
'ibridge_model_name', 'NO IBRIDGE CHIP')
if machine['arch'] == 'x86_64':
machine['x86_64_capable'] = True
elif machine['arch'] == 'i386':
+2 -1
View File
@@ -167,7 +167,8 @@ def handle_apple_package_install(item, itempath):
mount_with_shadow = suppress_bundle_relocation
# we need to mount the diskimage as read/write to be able to
# modify the package to suppress bundle relocation
mountpoints = dmgutils.mountdmg(itempath, use_shadow=mount_with_shadow)
mountpoints = dmgutils.mountdmg(
itempath, use_shadow=mount_with_shadow, skip_verification=True)
if mountpoints == []:
display.display_error(
"No filesystems mounted from %s", item["installer_item"])
+50 -4
View File
@@ -106,7 +106,8 @@ def create_missing_dirs(destpath):
def remove_quarantine_from_item(some_path):
'''Removes com.apple.quarantine from some_path'''
try:
if "com.apple.quarantine" in xattr.xattr(some_path).list():
if ("com.apple.quarantine" in
xattr.xattr(some_path).list(options=xattr.XATTR_NOFOLLOW)):
xattr.xattr(some_path).remove("com.apple.quarantine",
options=xattr.XATTR_NOFOLLOW)
except BaseException as err:
@@ -167,6 +168,50 @@ def validate_source_and_destination(mountpoint, item):
return (0, source_itempath, full_destpath)
def get_size(pathname):
'''Recursively gets size of pathname in bytes'''
if os.path.isdir(pathname):
total_size = 0
for dirpath, _, filenames in os.walk(pathname):
for filename in filenames:
filepath = os.path.join(dirpath, filename)
# skip if it is symbolic link
if not os.path.islink(filepath):
total_size += os.path.getsize(filepath)
return total_size
elif os.path.isfile(pathname):
return os.path.getsize(pathname)
return 0
def ditto_with_progress(source_path, dest_path):
'''Uses ditto to copy an item and provides progress output'''
source_size = get_size(source_path)
total_bytes_copied = 0
cmd = ["/usr/bin/ditto", "-V", "--noqtn", source_path, dest_path]
proc = subprocess.Popen(cmd, shell=False, bufsize=-1,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
while True:
output = proc.stdout.readline().decode('UTF-8')
if not output and (proc.poll() != None):
break
words = output.rstrip('\n').split()
if len(words) > 1 and words[1] == "bytes":
try:
bytes_copied = int(words[0])
except TypeError:
pass
else:
total_bytes_copied += bytes_copied
display.display_percent_done(total_bytes_copied, source_size)
return proc.returncode
def copy_items_from_mountpoint(mountpoint, itemlist):
'''copies items from the mountpoint to the startup disk
Returns 0 if no issues; some error code otherwise.
@@ -191,8 +236,9 @@ def copy_items_from_mountpoint(mountpoint, itemlist):
temp_destination_dir, os.path.basename(destination_path))
# copy the file or directory, removing the quarantine xattr and
# preserving HFS+ compression
retcode = subprocess.call(["/usr/bin/ditto", "--noqtn",
source_path, temp_destination_path])
#retcode = subprocess.call(["/usr/bin/ditto", "--noqtn",
# source_path, temp_destination_path])
retcode = ditto_with_progress(source_path, temp_destination_path)
if retcode:
display.display_error(
"Error copying %s to %s", source_path, temp_destination_path)
@@ -277,7 +323,7 @@ def copy_from_dmg(dmgpath, itemlist):
display.display_status_minor(
'Mounting disk image %s', os.path.basename(dmgpath))
mountpoints = dmgutils.mountdmg(dmgpath)
mountpoints = dmgutils.mountdmg(dmgpath, skip_verification=True)
if mountpoints:
mountpoint = mountpoints[0]
retcode = copy_items_from_mountpoint(mountpoint, itemlist)
+3 -2
View File
@@ -198,7 +198,7 @@ def _run_installer(cmd, env_vars, packagename):
retcode = job.returncode()
if retcode != 0:
# append stdout to our installer output
installeroutput.extend(job.stderr.read().splitlines())
installeroutput.extend(job.stderr.read().decode("UTF-8").splitlines())
display.display_status_minor(
"Install of %s failed with return code %s" % (packagename, retcode))
display.display_error("-"*78)
@@ -277,7 +277,8 @@ def installall(dirpath, options=None):
itempath = os.path.join(dirpath, item)
if pkgutils.hasValidDiskImageExt(item):
display.display_info("Mounting disk image %s" % item)
mountpoints = dmgutils.mountdmg(itempath, use_shadow=True)
mountpoints = dmgutils.mountdmg(
itempath, use_shadow=True, skip_verification=True)
if mountpoints == []:
display.display_error("No filesystems mounted from %s", item)
return (retcode, restartflag)
+6 -5
View File
@@ -43,7 +43,7 @@ try:
_ = xrange # pylint: disable=xrange-builtin
except NameError:
# no xrange in Python 3
xrange = range
xrange = range # pylint: disable=redefined-builtin,invalid-name
# This many hours before a force install deadline, start notifying the user.
@@ -239,10 +239,11 @@ def force_install_package_check():
managed_install_dir = prefs.pref('ManagedInstallDir')
installinfo_types = {
'InstallInfo.plist' : 'managed_installs',
'AppleUpdates.plist': 'AppleUpdates'
}
installinfo_types = {'InstallInfo.plist': 'managed_installs'}
if (prefs.pref('InstallAppleSoftwareUpdates') or
prefs.pref('AppleSoftwareUpdatesOnly')):
# only consider Apple updates if the prefs say it's OK
installinfo_types['AppleUpdates.plist'] = 'AppleUpdates'
now = NSDate.date()
now_xhours = NSDate.dateWithTimeIntervalSinceNow_(
+9 -1
View File
@@ -29,6 +29,7 @@ from __future__ import absolute_import, print_function
import os
import subprocess
import tempfile
import time
import uuid
@@ -139,7 +140,13 @@ class Job(object):
def __init__(self, cmd, environment_vars=None,
job_label=None, cleanup_at_exit=True):
'''Initialize our launchd job'''
tmpdir = osutils.tmpdir()
if cleanup_at_exit:
# safe to use the same tmpdir as the calling tool
# (usually managedsoftwareupdate) so it will get cleaned up
tmpdir = osutils.tmpdir()
else:
# need to create our own tmpdir; may not be cleaned up
tmpdir = tempfile.mkdtemp(prefix='munki.launchd-', dir='/tmp')
# label this job
self.label = job_label or 'com.googlecode.munki.' + str(uuid.uuid1())
@@ -174,6 +181,7 @@ class Job(object):
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
err = proc.communicate()[1].decode('UTF-8')
if proc.returncode:
raise LaunchdJobException(err)
+76 -36
View File
@@ -110,6 +110,48 @@ def get_os_version(app_path):
return ''
def setup_authrestart_if_applicable():
'''Sets up the ability to do an authrestart if applicable'''
# ask authrestartd if we can do an auth restart, or look for a recovery
# key (via munkilib.authrestart methods)
if (authrestartd.verify_can_attempt_auth_restart() or
authrestart.can_attempt_auth_restart()):
display.display_info(
'FileVault is active and we can do an authrestart')
#os_version_tuple = osutils.getOsVersion(as_tuple=True)
if False: # was: os_version_tuple >= (10, 12):
# setup delayed auth restart so that when startosinstall does a
# restart, it completes without user credentials
display.display_info('Setting up delayed authrestart...')
authrestartd.setup_delayed_authrestart()
# make sure the special secret InstallAssistant preference is not
# set
CFPreferencesSetValue(
'IAQuitInsteadOfReboot', None, '.GlobalPreferences',
kCFPreferencesAnyUser, kCFPreferencesCurrentHost)
else:
#
# set an undocumented preference to tell the osinstaller
# process to exit instead of restart
# this is the equivalent of:
# `defaults write /Library/Preferences/.GlobalPreferences
# IAQuitInsteadOfReboot -bool YES`
#
# This preference is referred to in a framework inside the
# Install macOS.app:
# Contents/Frameworks/OSInstallerSetup.framework/Versions/A/
# Frameworks/OSInstallerSetupInternal.framework/Versions/A/
# OSInstallerSetupInternal
#
# It might go away in future versions of the macOS installer.
#
display.display_info(
'Configuring startosinstall to quit instead of restart...')
CFPreferencesSetValue(
'IAQuitInsteadOfReboot', True, '.GlobalPreferences',
kCFPreferencesAnyUser, kCFPreferencesCurrentHost)
class StartOSInstallError(Exception):
'''Exception to raise if starting the macOS install fails'''
pass
@@ -130,13 +172,9 @@ class StartOSInstallRunner(object):
done setting up the macOS install and is ready and waiting to reboot'''
display.display_debug1('Got SIGUSR1 from startosinstall')
self.got_sigusr1 = True
# do cleanup, record-keeping, notifications
if self.installinfo and 'postinstall_script' in self.installinfo:
# run the postinstall_script
dummy_retcode = scriptutils.run_embedded_script(
'postinstall_script', self.installinfo)
if self.finishing_tasks:
self.finishing_tasks()
setup_authrestart_if_applicable()
# set Munki to run at boot after the OS upgrade is complete
try:
bootstrapping.set_bootstrap_mode()
@@ -144,34 +182,22 @@ class StartOSInstallRunner(object):
display.display_error(
'Could not set up Munki to run after OS upgrade is complete: '
'%s', err)
# do cleanup, record-keeping, notifications
if self.installinfo and 'postinstall_script' in self.installinfo:
# run the postinstall_script
dummy_retcode = scriptutils.run_embedded_script(
'postinstall_script', self.installinfo)
if self.finishing_tasks:
self.finishing_tasks()
if pkgutils.hasValidDiskImageExt(self.installer):
# remove the diskimage to free up more space for the actual install
try:
os.unlink(self.installer)
except (IOError, OSError):
pass
# ask authrestartd if we can do an auth restart, or look for a recovery
# key (via munkilib.authrestart methods)
if (authrestartd.verify_can_attempt_auth_restart() or
authrestart.can_attempt_auth_restart()):
#
# set a secret preference to tell the osinstaller process to exit
# instead of restart
# this is the equivalent of:
# `defaults write /Library/Preferences/.GlobalPreferences
# IAQuitInsteadOfReboot -bool YES`
#
# This preference is referred to in a framework inside the
# Install macOS.app:
# Contents/Frameworks/OSInstallerSetup.framework/Versions/A/
# Frameworks/OSInstallerSetupInternal.framework/Versions/A/
# OSInstallerSetupInternal
#
# It might go away in future versions of the macOS installer.
#
CFPreferencesSetValue(
'IAQuitInsteadOfReboot', True, '.GlobalPreferences',
kCFPreferencesAnyUser, kCFPreferencesCurrentHost)
# now tell startosinstall it's OK to proceed
subprocess.call(['/usr/bin/killall', '-SIGUSR1', 'startosinstall'])
@@ -217,7 +243,7 @@ class StartOSInstallRunner(object):
'middle of a CoreStorage conversion.')
if self.installinfo and 'preinstall_script' in self.installinfo:
# run the postinstall_script
# run the preinstall_script
retcode = scriptutils.run_embedded_script(
'preinstall_script', self.installinfo)
if retcode:
@@ -339,13 +365,14 @@ class StartOSInstallRunner(object):
startosinstall_output.append(info_output)
# parse output for useful progress info
msg = info_output.rstrip('\n')
msg = info_output.strip()
if msg.startswith('Preparing to '):
display.display_status_minor(msg)
elif msg.startswith('Preparing '):
elif msg.startswith(('Preparing ', 'Preparing: ')):
# percent-complete messages
percent_str = msg.split()[-1].rstrip('%.')
try:
percent = int(float(msg[10:].rstrip().rstrip('.')))
percent = int(float(percent_str))
except ValueError:
percent = -1
display.display_percent_done(percent, 100)
@@ -410,9 +437,10 @@ class StartOSInstallRunner(object):
CFPreferencesSetValue(
'IAQuitInsteadOfReboot', None, '.GlobalPreferences',
kCFPreferencesAnyUser, kCFPreferencesCurrentHost)
# attempt to do an auth restart, or regular restart
# attempt to do an auth restart, or regular restart, or shutdown
if not authrestartd.restart():
authrestart.do_authorized_or_normal_restart()
authrestart.do_authorized_or_normal_restart(
shutdown=osutils.bridgeos_update_staged())
else:
raise StartOSInstallError(
'startosinstall did not complete successfully. '
@@ -439,9 +467,21 @@ def get_catalog_info(mounted_dmgpath):
# "14.3GB of available storage to perform upgrade"
# http://www.apple.com/macos/how-to-upgrade/
installed_size = int(14.3 * 1024 * 1024)
elif vers.startswith('10.14'):
# Mojave:
# "12.5GB of available storage space, or up to 18.5GB of
# storage space when upgrading from OS X Yosemite or earlier."
# https://support.apple.com/en-us/HT210190
installed_size = int(18.5 * 1024 * 1024)
elif vers.startswith('10.15'):
# Catalina:
# "12.5GB of available storage space, or up to 18.5GB of
# storage space when upgrading from OS X Yosemite or earlier."
# https://support.apple.com/en-us/HT201475
installed_size = int(18.5 * 1024 * 1024)
else:
# will need to modify for future macOS releases
installed_size = int(14.3 * 1024 * 1024)
installed_size = int(18.5 * 1024 * 1024)
return {'RestartAction': 'RequireRestart',
'apple_item': True,
'description': description,
+42
View File
@@ -28,6 +28,8 @@ import shutil
import subprocess
import sys
import tempfile
import time
# PyLint cannot properly find names inside Cocoa libraries, so issues bogus
# No name 'Foo' in module 'Bar' warnings. Disable them.
@@ -36,6 +38,7 @@ from SystemConfiguration import SCDynamicStoreCopyConsoleUser
# pylint: enable=E0611
from . import display
from . import munkilog
# we use lots of camelCase-style names. Deal with it.
# pylint: disable=C0103
@@ -184,5 +187,44 @@ def osascript(osastring):
return u''
def bridgeos_update_staged():
'''Checks an undocumented nvram variable to see if a bridgeOS update
has been staged. If so, we should shut down instead of restart.
Returns a boolean.'''
cmd = ["/usr/sbin/nvram", "BOSUpdateStarted"]
proc = subprocess.Popen(cmd,
shell=False,
bufsize=-1,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
output = proc.communicate()[0].decode('UTF-8')
if proc.returncode == 0:
munkilog.log("nvram output: %s" % output)
lines = output.splitlines()
parts = lines[0].split()
try:
timestamp = int(parts[1].split(',')[0])
now = int(time.time())
seconds_ago = now - timestamp
if seconds_ago < 60 * 60:
munkilog.log(
"bridgeOS update staged %s seconds ago; shutdown required"
% seconds_ago)
return True
#else
munkilog.log(
"bridgeOS update %s seconds ago; too long ago to trust"
% seconds_ago)
return False
except (IndexError, ValueError):
munkilog.log(
"unexpected nvram output, can't detect bridgeos update")
return False
#else
munkilog.log("No bridgeOS update staged")
return False
if __name__ == '__main__':
print('This is a library of support tools for the Munki Suite.')
+1
View File
@@ -49,6 +49,7 @@ DEFAULT_INSECURE_REPO_URL = 'http://munki/repo'
DEFAULT_PREFS = {
'AdditionalHttpHeaders': None,
'AggressiveUpdateNotificationDays': 14,
'AppleSoftwareUpdatesOnly': False,
'CatalogURL': None,
'ClientCertificatePath': None,
+1 -1
View File
@@ -3,6 +3,6 @@
<plist version="1.0">
<dict>
<key>CFBundleShortVersionString</key>
<string>4.1.0</string>
<string>5.0.0</string>
</dict>
</plist>
+46 -2
View File
@@ -68,6 +68,8 @@ class RepoCleaner(object):
self.manifest_items = set()
self.manifest_items_with_versions = set()
self.pkginfodb = {}
self.referenced_pkgs = set()
self.orphaned_pkgs = []
self.required_items = set()
self.pkginfo_count = 0
self.items_to_delete = []
@@ -103,7 +105,7 @@ class RepoCleaner(object):
return str(size_in_bytes) + " bytes"
return str(round(size_in_bytes/float(limit/2**10), 1)) + suffix
count = 0
count = len(self.orphaned_pkgs)
pkginfo_total_size = 0
pkg_total_size = 0
for item in self.items_to_delete:
@@ -196,6 +198,11 @@ class RepoCleaner(object):
uninstallpkgpath = pkginfo.get('uninstaller_item_location', '')
uninstallpkgsize = pkginfo.get('uninstaller_item_size', 0) * 1024
if pkgpath:
self.referenced_pkgs.add(pkgpath)
if uninstallpkgpath:
self.referenced_pkgs.add(uninstallpkgpath)
# track required items; if these are in "Foo-1.0" format, we need
# to note these so we don't delete the specific referenced version
if 'requires' in pkginfo:
@@ -261,6 +268,20 @@ class RepoCleaner(object):
})
self.pkginfo_count += 1
def find_orphaned_pkgs(self):
'''Finds installer items that are not referred to by any pkginfo file'''
print('Analyzing installer items...')
try:
pkgs_list = self.repo.itemlist('pkgs')
except munkirepo.RepoError as err:
self.errors.append(
"Repo error getting list of pkgs: %s"
% unicode_or_str(err))
pkgs_list = []
for pkg in pkgs_list:
if pkg not in self.referenced_pkgs:
self.orphaned_pkgs.append(pkg)
def find_cleanup_items(self):
'''Using the info on manifests and pkgsinfo, find items to clean up.
Populates self.items_to_delete: a list of pkginfo items to remove,
@@ -325,6 +346,14 @@ class RepoCleaner(object):
print("(%s)" % item['resource_identifier'])
if print_this:
print()
if self.orphaned_pkgs:
print('The following pkgs are not referred to by any pkginfo '
'item:')
for pkg in self.orphaned_pkgs:
print("\t%s" % pkg)
if print_this:
print()
print("Total pkginfo items: %s" % self.pkginfo_count)
print("Item variants: %s" % len(list(self.pkginfodb.keys())))
@@ -333,6 +362,10 @@ class RepoCleaner(object):
print("pkgs to delete: %s" % pkg_count)
print("pkginfo space savings: %s" % pkginfo_size)
print("pkg space savings: %s" % pkg_size)
if len(self.orphaned_pkgs):
print(" "
"(Unknown additional pkg space savings from %s orphaned pkgs)"
% len(self.orphaned_pkgs))
if self.errors:
print("\nErrors encountered when processing repo:\n",
@@ -342,6 +375,7 @@ class RepoCleaner(object):
def delete_items(self):
'''Deletes items from the repo'''
# remove old pkginfo and referenced pkgs
for item in self.items_to_delete:
if 'resource_identifier' in item:
print('Removing %s' % item['resource_identifier'],
@@ -366,6 +400,15 @@ class RepoCleaner(object):
self.repo.delete(pkg_to_remove)
except munkirepo.RepoError as err:
print(unicode_or_str(err), file=sys.stderr)
# remove orphaned pkgs
for pkg in self.orphaned_pkgs:
pkg_to_remove = os.path.join('pkgs', pkg)
print('Removing %s' % pkg_to_remove)
try:
self.repo.delete(pkg_to_remove)
except munkirepo.RepoError as err:
print(unicode_or_str(err), file=sys.stderr)
def make_catalogs(self):
"""Calls makecatalogs to rebuild our catalogs"""
@@ -405,8 +448,9 @@ class RepoCleaner(object):
'''Clean our repo!'''
self.analyze_manifests()
self.analyze_pkgsinfo()
self.find_orphaned_pkgs()
self.find_cleanup_items()
if self.items_to_delete:
if self.items_to_delete or self.orphaned_pkgs:
print()
if not self.options.auto:
answer = get_input(
+37
View File
@@ -0,0 +1,37 @@
#!/bin/sh
export PATH=/usr/bin:/bin:/usr/sbin:/sbin
# relaunch MSC.app if it was running before we upgraded it
MSC_APP="/Applications/Managed Software Center.app"
if [ "$3" == "/" ]; then
if [ -e /tmp/com.googlecode.munki.relaunch_msc_app ] ; then
FRONTMOST=$(cat /tmp/com.googlecode.munki.relaunch_msc_app)
rm /tmp/com.googlecode.munki.relaunch_msc_app
if [ "$FRONTMOST" == "frontmost" ] ; then
OPENCMD="open -a"
else
OPENCMD="open -g -a"
fi
CONSOLEUSER=$(who | grep console | cut -d" " -f1)
if [ "$CONSOLEUSER" == "" ] ; then
exit 0
fi
CONSOLE_UID=$(id -u "$CONSOLEUSER")
os_major_version=$(sw_vers -productVersion | cut -d. -f2)
for pid_uid in $(ps -axo pid,uid,args | grep -i "[l]oginwindow.app" | awk '{print $1 "," $2}'); do
pid=$(echo $pid_uid | cut -d, -f1)
uid=$(echo $pid_uid | cut -d, -f2)
if [ "$uid" == "$CONSOLE_UID" ] ; then
if [[ $os_major_version -lt 10 ]] ; then
launchctl bsexec "$pid" chroot -u "$uid" / $OPENCMD "$MSC_APP"
exit 0
else
launchctl asuser "$uid" $OPENCMD "$MSC_APP"
exit 0
fi
fi
done
fi
fi
+23 -8
View File
@@ -1,13 +1,28 @@
#!/bin/sh
# remove any Managed Software Update.app bundle since the installer
# won't replace a bundle with a symlink, leading to yucky stuff like
# "/Applications/Utilities/Managed Software Update.app 1"
export PATH=/usr/bin:/bin:/usr/sbin:/sbin
if [ -d "$3/Applications/Utilities/Managed Software Update.app" ] ; then
/bin/rm -r "$3/Applications/Utilities/Managed Software Update.app"
fi
MSC_APP_NAME="Managed Software Center"
if [ -d "$3/Applications/Utilities/Managed Software Update.app 1" ] ; then
/bin/rm -r "$3/Applications/Utilities/Managed Software Update.app 1"
# installing on the current boot volume? kill MSC.app if it's running
if [ "$3" == "/" ]; then
CONSOLEUSER=$(who | grep console | cut -d" " -f1)
if [ "$CONSOLEUSER" != "" ] ; then
# is the console user running MSC.app and is it in front?
FRONT_APPID=$(lsappinfo info -only bundleid $(lsappinfo front) | cut -d= -f2 | cut -d\" -f2)
if [ "$FRONT_APPID" == "com.googlecode.munki.ManagedSoftwareCenter" ] ; then
# leave a flag that tells us to relaunch and bring to front
echo "frontmost" >> /tmp/com.googlecode.munki.relaunch_msc_app
else
# is the console user running MSC.app at all?
killall -s -u "$CONSOLEUSER" "$MSC_APP_NAME" &>/dev/null
if [ $? -eq 0 ] ; then
# leave a flag that tells us to relaunch and not bring to front
echo "not frontmost" >> /tmp/com.googlecode.munki.relaunch_msc_app
fi
fi
fi
# kill all instances of Managed Software Center.app
killall "$MSC_APP_NAME" &>/dev/null
exit 0
fi
+1 -1
View File
@@ -406,7 +406,7 @@ mkdir -p "$ADMINROOT/usr/local/munki"
chmod -R 755 "$ADMINROOT/usr"
# Copy command line admin utilities.
# edit this if list of tools changes!
for TOOL in makecatalogs makepkginfo manifestutil munkiimport iconimporter
for TOOL in makecatalogs makepkginfo manifestutil munkiimport iconimporter repoclean
do
cp -X "$MUNKIROOT/code/client/$TOOL" "$ADMINROOT/usr/local/munki/" 2>&1
done
+1 -1
View File
@@ -418,7 +418,7 @@ mkdir -p "$ADMINROOT/usr/local/munki"
chmod -R 755 "$ADMINROOT/usr"
# Copy command line admin utilities.
# edit this if list of tools changes!
for TOOL in makecatalogs makepkginfo manifestutil munkiimport iconimporter
for TOOL in makecatalogs makepkginfo manifestutil munkiimport iconimporter repoclean
do
cp -X "$MUNKIROOT/code/client/$TOOL" "$ADMINROOT/usr/local/munki/" 2>&1
done