diff --git a/code/apps/Managed Software Center/Managed Software Center/Controllers/MainWindowController.swift b/code/apps/Managed Software Center/Managed Software Center/Controllers/MainWindowController.swift
index 02fbe456..a6cb55cc 100755
--- a/code/apps/Managed Software Center/Managed Software Center/Controllers/MainWindowController.swift
+++ b/code/apps/Managed Software Center/Managed Software Center/Controllers/MainWindowController.swift
@@ -961,8 +961,8 @@ class MainWindowController: NSWindowController, NSWindowDelegate, WKNavigationDe
// we can't remove them directly since we didn't actually post them
// so we can't use
// NSUserNotificationCenter.default.removeAllDeliveredNotifications()
- let munkiNotifierPath = Bundle.main.path(forResource: "munki-notifier", ofType: "app")
- if let munkiNotifierPath = munkiNotifierPath {
+ let munkiNotifierPath = Bundle.main.bundlePath + "/Contents/Helpers/munki-notifier.app"
+ if FileManager.default.fileExists(atPath: munkiNotifierPath) {
NSLog("munki-notifier path: %@", munkiNotifierPath as String)
// now make sure it's not already running
let executablePath = munkiNotifierPath + "/Contents/MacOS/munki-notifier"
diff --git a/code/client/installhelper b/code/client/installhelper
new file mode 100755
index 00000000..9996fd4c
--- /dev/null
+++ b/code/client/installhelper
@@ -0,0 +1,484 @@
+#!/usr/local/munki/munki-python
+# encoding: utf-8
+#
+# Copyright 2011-2024 Greg Neagle.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""
+installhelper
+
+Created 2024-02-28.
+
+A helper tool for handling launchd items when installing Munki
+
+"""
+from __future__ import absolute_import
+
+# standard libs
+import glob
+import os
+import logging
+import logging.handlers
+import re
+import subprocess
+import time
+import sys
+from pathlib import Path
+
+# Append munki's path, to load our libs when not running under munki
+# pylint: disable = C0413
+sys.path.append('/usr/local/munki')
+
+# our libs
+from munkilib import osutils
+from munkilib import prefs
+from munkilib import FoundationPlist
+
+# globals
+LAUNCHD_PREFIX = 'com.googlecode.munki.'
+APPUSAGE_AGENT = LAUNCHD_PREFIX + 'app_usage_monitor'
+APPUSAGE_DAEMON = LAUNCHD_PREFIX + 'appusaged'
+INSTALL_HELPER = LAUNCHD_PREFIX + 'installhelper'
+PROG_NAME = 'managedsoftwareupdate'
+APP_NAME = 'installhelper'
+APP_VERSION = '0.1'
+
+
+def main():
+ '''Main function'''
+
+ # If INSTALLHELPER_RUN_TYPE isn't set
+ if not os.environ.get('INSTALLHELPER_RUN_TYPE'):
+ # Set launchd_group to the first value passed
+ launchd_group = sys.argv[1].lower()
+ # If INSTALLHELPER_RUN_TYPE is set and we have a valid value passed
+ elif (os.environ.get('INSTALLHELPER_RUN_TYPE') == 'appusage' or
+ os.environ.get('INSTALLHELPER_RUN_TYPE') == 'launchd'):
+ # Set launchd_group to the value of INSTALLHELPER_RUN_TYPE
+ launchd_group = os.environ.get('INSTALLHELPER_RUN_TYPE')
+ # If we've got here, something isn't right
+ else:
+ # Error message
+ logging.info("ERROR: Cannot ascertain correct value for passed argument")
+ # Exit
+ sys.exit(1)
+
+ # Setup logging
+ setup_logging()
+
+ # If not launched via launchd
+ if not os.environ.get('INSTALLHELPER_RUN_TYPE'):
+ # Launched manually
+ logging.info("Launched manually - arg: %s", launchd_group)
+ create_launch_daemon(launchd_group)
+ # If launched via launchd
+ else:
+ # Launched via launchd
+ logging.info("Launched via launchd - arg: %s", launchd_group)
+ process_munki_launchd(launchd_group)
+
+
+def create_launch_daemon(launchd_group):
+ '''Creates and loads the launch daemon'''
+
+ # Set name and path based on the value of launchd_group
+ launch_daemon_name = 'com.googlecode.munki.installhelper-' + launchd_group
+ launch_daemon_path = '/Library/LaunchDaemons/' + launch_daemon_name + '.plist'
+
+ # Progress notification
+ logging.info("Creating launch daemon")
+
+ # Retrieve all running launch daemons
+ cmd = ['/bin/launchctl', 'list']
+ cmd_out = subprocess.run(cmd, capture_output = True, check = False)
+ launchd_labels = split_launchctl_list(cmd_out)
+
+ # Check to see if launch_daemon_name is already loaded, and stop if so
+ if launch_daemon_name in launchd_labels:
+ # Stop the launch daemon at the login window
+ cmd = ['/bin/launchctl', 'bootout', 'system/' + launch_daemon_name]
+ subprocess.call(cmd)
+
+ # Populate launch deamon dict
+ launch_daemon = {}
+ launch_daemon['EnvironmentVariables'] = {'INSTALLHELPER_RUN_TYPE': launchd_group}
+ launch_daemon['Label'] = launch_daemon_name
+ launch_daemon['ProgramArguments'] = ['/usr/local/munki/installhelper']
+ launch_daemon['RunAtLoad'] = True
+
+ # Create the launch daemon
+ FoundationPlist.writePlist(launch_daemon, launch_daemon_path)
+
+ # Set the launch daemons owner and perms
+ os.chown(launch_daemon_path, 0, 0)
+ os.chmod(launch_daemon_path, int('644', 8))
+
+ # Load the launch daemon
+ logging.info("Starting: %s", launch_daemon_path)
+ cmd = ['/bin/launchctl', 'bootstrap', 'system', launch_daemon_path]
+ subprocess.call(cmd)
+
+
+def get_logged_in_users():
+ '''Returns a dict containing any logged in users uid and username'''
+
+ # Var declaration
+ user_details = {}
+
+ # Retrieve details of all running processes
+ cmd = ['/bin/ps', '-axo', 'uid,login,args']
+ cmd_out = subprocess.run(cmd, capture_output = True, check = False)
+ # Split out the above output
+ for some_process in cmd_out.stdout.decode().splitlines():
+ # Retrieve details for users that are running loginwindow.app, excluding root
+ if "loginwindow.app" in some_process.lower() and some_process.split()[0] != "0":
+ # Capture the userid and username for all users running the loginwindow
+ user_details[some_process.split()[0]] = some_process.split()[1]
+
+ # Returns either an empty dict, or a dict with userid and usernames
+ return user_details
+
+
+def is_managedsoftwareupdate_running():
+ '''If managedsoftwareupdate is running, check again in x seconds'''
+
+ # Check to see if managedsoftwareupdate is running
+ managedsoftwareupdate_pid = osutils.pythonScriptRunning(PROG_NAME)
+
+ # An instance of managedsoftwareupdate is running, so we need to try again later
+ while managedsoftwareupdate_pid:
+ logging.info("*" * 60)
+ logging.info("%s is running as pid %s.", managedsoftwareupdate_pid, os.getpid())
+ logging.info("checking again in 10 seconds")
+ logging.info("*" * 60)
+ time.sleep(10)
+
+ # If managedsoftwareupdate is not running.. return from function to proceed
+ logging.info("%s is not running, proceeding...", (PROG_NAME))
+
+
+def process_launch_daemons(launch_daemons, launchd_group, loginwindow_launchds):
+ '''Processes Munki's Launch Daemons'''
+
+ # Progress notification
+ logging.info("Processing Launch Daemons")
+
+ # Var declaration
+ matched_labels = []
+
+ # Retrieve all running launch daemons
+ cmd = ['/bin/launchctl', 'list']
+ cmd_out = subprocess.run(cmd, capture_output = True, check = False)
+ launchd_labels = split_launchctl_list(cmd_out)
+
+ # For each plist in /Library/LaunchDaemons/ prefixed with LAUNCHD_PREFIX
+ for launch_daemon in launch_daemons:
+ try:
+ # Make sure content is valid, before proceeding to reload
+ daemon_content = FoundationPlist.readPlist(launch_daemon)
+ except FoundationPlist.NSPropertyListSerializationException:
+ break
+ # Get the Label
+ daemon_label = daemon_content.get('Label')
+ # If we have a label and it's not an INSTALL_HELPER launchd item
+ if daemon_label and not INSTALL_HELPER in daemon_label:
+ # Check to see if the launch daemon is loaded, before stopping
+ if daemon_label in launchd_labels:
+ # Stop the launch daemon
+ logging.info("Stopping: %s", launch_daemon)
+ cmd = ['/bin/launchctl', 'bootout', 'system/' + daemon_label]
+ subprocess.call(cmd)
+ # Load the launch daemon
+ logging.info("Starting: %s", launch_daemon)
+ cmd = ['/bin/launchctl', 'bootstrap', 'system', launch_daemon]
+ subprocess.call(cmd)
+ # Append the launchd items label to matched_labels
+ matched_labels.append(daemon_label)
+
+ # If we're to interact with all non-appusage launchd items
+ if launchd_group == 'launchd':
+ # For each label in launchd_labels
+ for launchd_label in launchd_labels:
+ # If we have a label, it's not in matched_labels or loginwindow_launchds,
+ # and it's not an APPUSAGE_DAEMON or a INSTALL_HELPER launchd item
+ if (launchd_label not in matched_labels + loginwindow_launchds + [APPUSAGE_DAEMON]
+ and not launchd_label.startswith(INSTALL_HELPER)):
+ # Stop the launch daemon
+ logging.info("Stopping: %s", launchd_label)
+ cmd = ['/bin/launchctl', 'bootout', 'system/' + launchd_label]
+ subprocess.call(cmd)
+
+
+def process_loginwindow_launch_agents(launch_agents):
+ '''Processes Munki's LoginWindow Launch Agents'''
+
+ # Progress notification
+ logging.info("Processing LoginWindow Launch Agents")
+
+ # Var declaration
+ loginwindow_launchds = []
+
+ # Get the labels for any launchd running at the LoginWindow, this will only list LoginWindow
+ # launch agents when ran at the LoginWindow
+ cmd = ['/bin/launchctl', 'dumpstate']
+ cmd_out = subprocess.run(cmd, capture_output = True, check = False)
+ launchd_labels = re.findall("loginwindow/.*/(" + LAUNCHD_PREFIX + ".*) =",
+ cmd_out.stdout.decode())
+
+ # For each plist in /Library/LaunchAgents/ prefixed with LAUNCHD_PREFIX
+ for launch_agent in launch_agents:
+ try:
+ # Make sure content is valid, before proceeding to reload
+ agent_content = FoundationPlist.readPlist(launch_agent)
+ except FoundationPlist.NSPropertyListSerializationException:
+ break
+ # If we're to limit loading
+ if agent_content.get('LimitLoadToSessionType'):
+ # If the launch agent includes LimitLoadToSessionType, and it contains LoginWindow
+ if 'LoginWindow' in agent_content.get('LimitLoadToSessionType'):
+ # If the launch agent is to be loaded at the login window, get the Label
+ agent_label = agent_content.get('Label')
+ # If we have a label and it's not an INSTALL_HELPER launchd item
+ if agent_label and not INSTALL_HELPER in agent_label:
+ # Check to see if the launch agent is loaded, before stopping
+ if agent_label in launchd_labels:
+ # Stop the launch agent at the login window
+ logging.info("Stopping: %s", launch_agent)
+ cmd = ['/bin/launchctl', 'unload', '-S', 'LoginWindow', launch_agent]
+ subprocess.call(cmd)
+ # Load the launch agent at the login window
+ logging.info("Starting: %s", launch_agent)
+ cmd = ['/bin/launchctl', 'load', '-S', 'LoginWindow', launch_agent]
+ subprocess.call(cmd)
+ # Append the launchd items label to loginwindow_launchds
+ loginwindow_launchds.append(agent_label)
+
+ # For each label in launchd_labels
+ for launchd_label in launchd_labels:
+ # If we have a label, it's not in loginwindow_launchds and it's not an INSTALL_HELPER
+ # launchd item
+ if (launchd_label not in loginwindow_launchds
+ and not launchd_label.startswith(INSTALL_HELPER)):
+ # Stop the launch agent
+ logging.info("Stopping: %s", launchd_label)
+ cmd = ['/bin/launchctl', 'bootout', 'loginwindow/' + launchd_label]
+ subprocess.call(cmd)
+
+ # Returns loginwindow_launchds
+ return loginwindow_launchds
+
+
+def process_munki_launchd(launchd_group):
+ '''Reload Munki's launchd'''
+
+ # If we're to interact only with the appusage launchd items
+ if launchd_group == 'appusage':
+ # returns a list containing just the path to the app_usage_monitor launch agent
+ launch_agents = ['/Library/LaunchAgents/' + APPUSAGE_AGENT+ '.plist']
+ # returns a list containing just the path to the appusaged launch daemon
+ launch_daemons = ['/Library/LaunchDaemons/' + APPUSAGE_DAEMON + '.plist']
+
+ # If we're to interact with all non-appusage launchd items
+ if launchd_group == 'launchd':
+ # Returns a list of Munki's launch agents, excluding the APPUSAGE_AGENT agent
+ launch_agents = [launch_agent for launch_agent in
+ glob.glob('/Library/LaunchAgents/' + LAUNCHD_PREFIX + '*') if not
+ APPUSAGE_AGENT in launch_agent]
+ # Returns a list of Munki's launch daemons, excluding the APPUSAGE_DAEMON and
+ # INSTALL_HELPER launchd items
+ launch_daemons = [launch_daemon for launch_daemon in
+ glob.glob('/Library/LaunchDaemons/' + LAUNCHD_PREFIX + '*') if not
+ (APPUSAGE_DAEMON or INSTALL_HELPER) in launch_daemon]
+
+ # Only proceed if PROG_NAME isn't running, looping until it's not running
+ is_managedsoftwareupdate_running()
+
+ # Get the userid and username of any logged in users
+ user_details = get_logged_in_users()
+
+ # If users are logged in
+ if user_details:
+ # If users are logged in, reload the required launch agents as them
+ process_user_launch_agents(launch_agents, launchd_group, user_details)
+
+ # If we're not only looking to reload the appusage launchd's
+ if launchd_group != 'appusage':
+ # reload munki's loginwindow launch agents, returning a list of labels
+ loginwindow_launchds = process_loginwindow_launch_agents(launch_agents)
+ # If we're just looking to reload the appusage launchd's
+ else:
+ # Set to an empty list
+ loginwindow_launchds = []
+
+ # Reload launch daemons as needed
+ process_launch_daemons(launch_daemons, launchd_group, loginwindow_launchds)
+
+ # Set name and path based on the value of launchd_group
+ launch_daemon_name = INSTALL_HELPER + '-' + launchd_group
+ launch_daemon_path = '/Library/LaunchDaemons/' + launch_daemon_name + '.plist'
+
+ # If the launch daemon exists
+ if os.path.isfile(launch_daemon_path):
+ # Progress notification
+ logging.info("Completed tasks, tidying up")
+ # Delete the launch daemon
+ logging.info("Deleting: %s", launch_daemon_path)
+ os.unlink(launch_daemon_path)
+ # Unload the launch daemon
+ logging.info("Unloading: %s", launch_daemon_name)
+ cmd = ['/bin/launchctl', 'bootout', 'system/' + launch_daemon_name]
+ subprocess.call(cmd)
+
+
+def process_user_launch_agents(launch_agents, launchd_group, user_details):
+ '''Processes Munki's user Launch Agents'''
+
+ # For each logged in user
+ for userid, username in user_details.items():
+ # Var declaration
+ matched_labels = []
+ # Log who we're reloading the Launch Agents as
+ logging.info("Processing Launch Agents for: %s", username)
+ # Retrieve all running launch agents for the user
+ cmd = ['/bin/launchctl', 'asuser', str(userid), '/bin/launchctl', 'list']
+ cmd_out = subprocess.run(cmd, capture_output = True, check = False)
+ launchd_labels = split_launchctl_list(cmd_out)
+ # For each plist in /Library/LaunchAgents/ prefixed with LAUNCHD_PREFIX
+ for launch_agent in launch_agents:
+ try:
+ # Make sure content is valid, before proceeding to reload
+ agent_content = FoundationPlist.readPlist(launch_agent)
+ except FoundationPlist.NSPropertyListSerializationException:
+ break
+ # If the launch agent doesn't contain LimitLoadToSessionType or
+ # LimitLoadToSessionType exists and it contains Aqua
+ if (not agent_content.get('LimitLoadToSessionType') or 'Aqua' in
+ agent_content.get('LimitLoadToSessionType')):
+ # If the launch agent is to be loaded at the login window, get the Label
+ agent_label = agent_content.get('Label')
+ # If we have a label and it's not an INSTALL_HELPER launchd item
+ if agent_label and not agent_label.startswith(INSTALL_HELPER):
+ # Check to see if the launch agent is loaded, before stopping
+ if agent_label in launchd_labels:
+ # Stop the launch agent
+ logging.info("Stopping: %s", launch_agent)
+ cmd = ['/bin/launchctl', 'asuser', str(userid), '/bin/launchctl', 'bootout',
+ 'gui/' + str(userid) + '/' + agent_label]
+ subprocess.call(cmd)
+ # Load the launch agent
+ logging.info("Starting: %s", launch_agent)
+ cmd = ['/bin/launchctl', 'asuser', str(userid), '/bin/launchctl', 'bootstrap',
+ 'gui/' + str(userid), launch_agent]
+ subprocess.call(cmd)
+ # Append the launchd items label to matched_labels
+ matched_labels.append(agent_label)
+
+ # If we're to interact with all non-appusage launchd items
+ if launchd_group == 'launchd':
+ # For each label in launchd_labels
+ for launchd_label in launchd_labels:
+ # If we have a label, it's not in matched_labels and it's not an INSTALL_HELPER
+ # launchd item
+ if (launchd_label not in matched_labels + [APPUSAGE_AGENT]
+ and not launchd_label.startswith(INSTALL_HELPER)):
+ # Stop the launch agent
+ logging.info("Stopping: %s", launchd_label)
+ cmd = ['/bin/launchctl', 'asuser', str(userid), '/bin/launchctl', 'bootout',
+ 'gui/' + str(userid) + '/' + launchd_label]
+ subprocess.call(cmd)
+
+
+def setup_logging():
+ '''Configure logging'''
+
+ # Creates the logging dir if doesn't exist
+ Path(os.path.dirname(prefs.pref('LogFile'))).mkdir(parents=True, exist_ok=True)
+
+ # Store the log in the same directory as ManagedSoftwareUpdate.log
+ log_path = os.path.join(os.path.dirname(prefs.pref('LogFile')), APP_NAME + '.log')
+
+ # Generic settings
+ log_level = logging.getLevelName('INFO')
+
+ # Log format
+ log_format = logging.Formatter('%(asctime)s %(levelname)s %(message)s', '%b %d %Y %H:%M:%S %z')
+
+ # Change root logger level from WARNING to NOTSET in order for all messages to be delegated.
+ # https://stackoverflow.com/a/59431653
+ logging.getLogger('').setLevel(logging.NOTSET)
+
+ # Create a rotating log file handler, rotate at 10MB, keeping 9 backups
+ file_logger = logging.handlers.RotatingFileHandler(log_path, 'a', 100000, 9, 'utf-8')
+ # Set file logging level
+ file_logger.setLevel(log_level)
+ # Set file log format
+ file_logger.setFormatter(log_format)
+ # Add to logger
+ logging.getLogger('').addHandler(file_logger)
+
+ # Add console handler to logging object
+ console_logger = logging.StreamHandler()
+ # Set console logging level
+ console_logger.setLevel(log_level)
+ # Set console logging format
+ console_logger.setFormatter(log_format)
+ # Add to logger
+ logging.getLogger('').addHandler(console_logger)
+
+ # Start log
+ logging.info("Starting %s - %s", APP_NAME, APP_VERSION)
+
+
+def split_launchctl_list(cmd_out):
+ '''Takes launchctl list output and returns a list with just the labels'''
+
+ # Var declaration
+ launchd_labels = []
+
+ # Strip cmd_out to just the labels of the running launch agents
+ for launchd_item in cmd_out.stdout.decode().splitlines():
+ # If the launchd_item starts with LAUNCHD_PREFIX
+ if launchd_item.split('\t')[2].startswith(LAUNCHD_PREFIX):
+ # Add the label to launchd_labels
+ launchd_labels.append(launchd_item.split('\t')[2])
+
+ # Returns a list of launchd labels
+ return launchd_labels
+
+
+if __name__ == '__main__':
+
+ # Check to see if we're root
+ if os.geteuid() != 0:
+ print("ERROR: You must run this as root!", file=sys.stderr)
+ sys.exit(1)
+
+ # If INSTALLHELPER_RUN_TYPE isn't set
+ if not os.environ.get('INSTALLHELPER_RUN_TYPE'):
+ # If we have no arguments passed or the arguments passed are not expected.. exit
+ if len(sys.argv) == 1 or not (sys.argv[1].lower() == 'appusage' or
+ sys.argv[1].lower() == 'launchd'):
+ print("ERROR: Requires either \'appusage\' or \'launchd\' arguments to be passed.")
+ sys.exit(1)
+ # If INSTALLHELPER_RUN_TYPE is set
+ else:
+ # Else if we have INSTALLHELPER_RUN_TYPE defined, and it's not what's expected.. exit
+ if not (os.environ.get('INSTALLHELPER_RUN_TYPE') != 'appusage' or
+ os.environ.get('INSTALLHELPER_RUN_TYPE') != 'launchd'):
+ # Set launchd_group to the value of INSTALLHELPER_RUN_TYPE
+ print("ERROR: Requires INSTALLHELPER_RUN_TYPE to be set to either \'appusage\' or "
+ "\'launchd\'")
+ sys.exit(1)
+
+ # Proceed to run main
+ main()
diff --git a/code/tools/make_munki_mpkg.sh b/code/tools/make_munki_mpkg.sh
index 99717a90..83e20fdf 100755
--- a/code/tools/make_munki_mpkg.sh
+++ b/code/tools/make_munki_mpkg.sh
@@ -508,7 +508,7 @@ mkdir -m 755 "$ADMINROOT/usr/local"
mkdir -m 755 "$ADMINROOT/usr/local/munki"
# Copy command line admin utilities.
# edit this if list of tools changes!
-for TOOL in makecatalogs makepkginfo manifestutil munkiimport iconimporter repoclean
+for TOOL in makecatalogs makepkginfo manifestutil munkiimport iconimporter repoclean installhelper
do
cp -X "$MUNKIROOT/code/client/$TOOL" "$ADMINROOT/usr/local/munki/" 2>&1
done
@@ -544,10 +544,12 @@ mkdir -m 1775 "$APPROOT"
mkdir -m 775 "$APPROOT/Applications"
# Copy Managed Software Center application.
cp -R "$MSCAPP" "$APPROOT/Applications/"
+# Create Helper directory
+mkdir -m 775 "$APPROOT/Applications/Managed Software Center.app/Contents/Helpers/"
# Copy MunkiStatus helper app
-cp -R "$MSAPP" "$APPROOT/Applications/Managed Software Center.app/Contents/Resources/"
+cp -R "$MSAPP" "$APPROOT/Applications/Managed Software Center.app/Contents/Helpers/"
# Copy notifier helper app
-cp -R "$NOTIFIERAPP" "$APPROOT/Applications/Managed Software Center.app/Contents/Resources/"
+cp -R "$NOTIFIERAPP" "$APPROOT/Applications/Managed Software Center.app/Contents/Helpers/"
# make sure not writeable by group or other
chmod -R go-w "$APPROOT/Applications/Managed Software Center.app"
@@ -556,7 +558,7 @@ if [ "$APPSIGNINGCERT" != "" ]; then
echo "Signing Managed Software Center.app Bundles..."
/usr/bin/codesign -f -s "$APPSIGNINGCERT" --options runtime --timestamp --verbose \
"$APPROOT/Applications/Managed Software Center.app/Contents/PlugIns/MSCDockTilePlugin.docktileplugin" \
- "$APPROOT/Applications/Managed Software Center.app/Contents/Resources/munki-notifier.app"
+ "$APPROOT/Applications/Managed Software Center.app/Contents/Helpers/munki-notifier.app"
SIGNING_RESULT="$?"
if [ "$SIGNING_RESULT" -ne 0 ]; then
echo "Error signing Managed Software Center.app: $SIGNING_RESULT"
@@ -564,7 +566,7 @@ if [ "$APPSIGNINGCERT" != "" ]; then
fi
echo "Signing MunkiStatus.app Frameworks..."
- /usr/bin/find "$APPROOT/Applications/Managed Software Center.app/Contents/Resources/MunkiStatus.app/Contents/Frameworks" -type f -perm -u=x -exec /usr/bin/codesign -f -s "$APPSIGNINGCERT" --options runtime --timestamp --verbose {} \;
+ /usr/bin/find "$APPROOT/Applications/Managed Software Center.app/Contents/Helpers/MunkiStatus.app/Contents/Frameworks" -type f -perm -u=x -exec /usr/bin/codesign -f -s "$APPSIGNINGCERT" --options runtime --timestamp --verbose {} \;
SIGNING_RESULT="$?"
if [ "$SIGNING_RESULT" -ne 0 ]; then
echo "Error signing MunkiStatus.app Frameworks: $SIGNING_RESULT"
@@ -580,7 +582,7 @@ if [ "$APPSIGNINGCERT" != "" ]; then
echo "Signing Managed Software Center.app..."
/usr/bin/codesign -f -s "$APPSIGNINGCERT" --options runtime --timestamp --verbose \
- "$APPROOT/Applications/Managed Software Center.app/Contents/Resources/MunkiStatus.app" \
+ "$APPROOT/Applications/Managed Software Center.app/Contents/Helpers/MunkiStatus.app" \
"$APPROOT/Applications/Managed Software Center.app"
SIGNING_RESULT="$?"
if [ "$SIGNING_RESULT" -ne 0 ]; then
@@ -914,18 +916,6 @@ cat > "$DISTFILE" <
-
@@ -951,7 +941,7 @@ cat > "$DISTFILE" <
-
+
@@ -968,9 +958,9 @@ cat > "$DISTFILE" <${PKGPREFIX}munkitools_core.pkg
${PKGPREFIX}munkitools_admin.pkg
${PKGPREFIX}munkitools_app.pkg
- ${PKGPREFIX}munkitools_launchd.pkg
- ${PKGPREFIX}munkitools_app_usage.pkg
${PKGPREFIX}munkitools_python.pkg
+ ${PKGPREFIX}munkitools_launchd.pkg
+ ${PKGPREFIX}munkitools_app_usage.pkg
$BOOTSTRAPREF
$CONFREF
$CLIENTCERTREF
diff --git a/code/tools/pkgresources/Scripts_app_usage/postinstall b/code/tools/pkgresources/Scripts_app_usage/postinstall
index 46dd0482..bcaf188b 100755
--- a/code/tools/pkgresources/Scripts_app_usage/postinstall
+++ b/code/tools/pkgresources/Scripts_app_usage/postinstall
@@ -1,22 +1,19 @@
#!/bin/sh
-# Lovingly adapted from Per Olofsson
-# https://github.com/MagerValp/Scripted-Mac-Package-Creation/blob/master/scripts/postinstall
+#
+# this postinstall should run installhelper in the background, with it then waiting until
+# managedsoftwareupdate isn't running and then (re)load Munki's appusage launchditems items as needed
+#
-export PATH=/usr/bin:/bin:/usr/sbin:/sbin
-
-# Execute postinstall actions if we're installing on a live system.
-# This is useful for loading launch daemons and agents.
-if [ "$3" = "/" ]; then
-
- # Run postinstall actions for root.
- launchctl bootstrap system/ /Library/LaunchDaemons/com.googlecode.munki.appusaged.plist
-
- # Run postinstall actions for all logged in users.
- for uid in $(ps -axo uid,args | grep "/[F]inder.app/" | awk '{print $1}'); do
- launchctl bootstrap gui/"$uid"/ /Library/LaunchAgents/com.googlecode.munki.app_usage_monitor.plist
- done
-
-fi
-
-exit 0
\ No newline at end of file
+# Only execute postinstall actions if we're installing on a live system.
+if [ "$3" = "/" ]
+then
+ installHelper='/usr/local/munki/installhelper'
+ if [ -f "${installHelper}" ]
+ then
+ /bin/echo "Loading ${installHelper}..."
+ "${installHelper}" appusage &
+ else
+ /bin/echo "Cannot locate: ${installHelper}..."
+ fi
+fi
\ No newline at end of file
diff --git a/code/tools/pkgresources/Scripts_app_usage/preinstall b/code/tools/pkgresources/Scripts_app_usage/preinstall
deleted file mode 100755
index c7063690..00000000
--- a/code/tools/pkgresources/Scripts_app_usage/preinstall
+++ /dev/null
@@ -1,29 +0,0 @@
-#!/bin/sh
-
-# Lovingly adapted from Per Olofsson
-# https://github.com/MagerValp/Scripted-Mac-Package-Creation/blob/master/scripts/postinstall
-
-export PATH=/usr/bin:/bin:/usr/sbin:/sbin
-
-# Execute preinstall actions if we're installing on a live system.
-# This is useful for unloading launch daemons and agents.
-if [ "$3" = "/" ]; then
-
- # Run preinstall actions for root.
- if launchctl print system/munki.app_usage_monitor > /dev/null 2>&1 ; then
- launchctl bootout system/munki.app_usage_monitor
- fi
- if launchctl print system/com.googlecode.munki.appusaged. > /dev/null 2>&1 ; then
- launchctl bootout system/com.googlecode.munki.appusaged
- fi
-
- # Run preinstall actions for all logged in users.
- for uid in $(ps -axo uid,args | grep "/[F]inder.app/" | awk '{print $1}'); do
- if launchctl print gui/"$uid"/com.googlecode.munki.app_usage_monitor > /dev/null 2>&1 ; then
- launchctl bootout gui/"$uid"/com.googlecode.munki.app_usage_monitor
- fi
- done
-
-fi
-
-exit 0
\ No newline at end of file
diff --git a/code/tools/pkgresources/Scripts_launchd/postinstall b/code/tools/pkgresources/Scripts_launchd/postinstall
index 4e430267..9a0534d5 100755
--- a/code/tools/pkgresources/Scripts_launchd/postinstall
+++ b/code/tools/pkgresources/Scripts_launchd/postinstall
@@ -1,51 +1,19 @@
#!/bin/sh
-# Lovingly lifted from Per Olofsson
-# https://github.com/MagerValp/Scripted-Mac-Package-Creation/blob/master/scripts/postinstall
-
-# this is intended for a new install of the Munki tools -- the tools will be
-# installed and the launchagents/daemons will be activated without the need for
-# a restart
#
-# This should not be used for "upgrade" installs of the munkitools, or by
-# installs handled by Munki itself.
+# this postinstall should run installhelper in the background, with it then waiting until
+# managedsoftwareupdate isn't running and then (re)load Munki's launchd items as needed
+#
-export PATH=/usr/bin:/bin:/usr/sbin:/sbin
-
-# Execute postinstall actions if we're installing on a live system.
-# This is useful for loading launch daemons and agents.
-if [ "$3" = "/" ]; then
-
- # is a Munki launchd job already loaded? if so, exit now
- for JOB in logouthelper managedsoftwareupdate-check managedsoftwareupdate-install managedsoftwareupdate-manualcheck
- do
- if launchctl list com.googlecode.munki.${JOB} >/dev/null 2>&1 ; then
- echo "com.googlecode.munki.${JOB} is loaded: exiting postflight"
- exit 0
- fi
- done
-
- # Load all launch daemons.
- launchctl bootstrap system/ /Library/LaunchDaemons/com.googlecode.munki.authrestartd.plist
- launchctl bootstrap system/ /Library/LaunchDaemons/com.googlecode.munki.logouthelper.plist
- launchctl bootstrap system/ /Library/LaunchDaemons/com.googlecode.munki.managedsoftwareupdate-check.plist
- launchctl bootstrap system/ /Library/LaunchDaemons/com.googlecode.munki.managedsoftwareupdate-install.plist
- launchctl bootstrap system/ /Library/LaunchDaemons/com.googlecode.munki.managedsoftwareupdate-manualcheck.plist
-
- loggedInUser=$( echo "show State:/Users/ConsoleUser" | scutil | awk '/Name :/ && ! /loginwindow/ { print $3 }' )
- if [ "$loggedInUser" = "" ] ; then
- # no-one is logged in; I.E. we're at the loginwindow.
- # Load the loginwindow launchagents
- launchctl load -S LoginWindow /Library/LaunchAgents/com.googlecode.munki.managedsoftwareupdate-loginwindow.plist
- launchctl load -S LoginWindow /Library/LaunchAgents/com.googlecode.munki.MunkiStatus.plist
+# Only execute postinstall actions if we're installing on a live system.
+if [ "$3" = "/" ]
+then
+ installHelper='/usr/local/munki/installhelper'
+ if [ -f "${installHelper}" ]
+ then
+ /bin/echo "Loading ${installHelper}..."
+ "${installHelper}" launchd &
+ else
+ /bin/echo "Cannot locate: ${installHelper}..."
fi
-
- # Load launch agents for all currently logged in users.
- for uid in $(ps -axo uid,args | grep "/[F]inder.app/" | awk '{print $1}'); do
- launchctl bootstrap gui/"$uid"/ /Library/LaunchAgents/com.googlecode.munki.ManagedSoftwareCenter.plist
- launchctl bootstrap gui/"$uid"/ /Library/LaunchAgents/com.googlecode.munki.munki-notifier.plist
- done
-
-fi
-
-exit 0
+fi
\ No newline at end of file
diff --git a/launchd/LaunchAgents/com.googlecode.munki.MunkiStatus.plist b/launchd/LaunchAgents/com.googlecode.munki.MunkiStatus.plist
index abdbdb42..063139f7 100644
--- a/launchd/LaunchAgents/com.googlecode.munki.MunkiStatus.plist
+++ b/launchd/LaunchAgents/com.googlecode.munki.MunkiStatus.plist
@@ -24,7 +24,7 @@
ProgramArguments
- /Applications/Managed Software Center.app/Contents/Resources/MunkiStatus.app/Contents/MacOS/MunkiStatus
+ /Applications/Managed Software Center.app/Contents/Helpers/MunkiStatus.app/Contents/MacOS/MunkiStatus
diff --git a/launchd/LaunchAgents/com.googlecode.munki.munki-notifier.plist b/launchd/LaunchAgents/com.googlecode.munki.munki-notifier.plist
index 40e24bc0..a81a6536 100644
--- a/launchd/LaunchAgents/com.googlecode.munki.munki-notifier.plist
+++ b/launchd/LaunchAgents/com.googlecode.munki.munki-notifier.plist
@@ -20,7 +20,7 @@
/usr/local/munki/launchapp
-a
- /Applications/Managed Software Center.app/Contents/Resources/munki-notifier.app
+ /Applications/Managed Software Center.app/Contents/Helpers/munki-notifier.app